diff options
Diffstat (limited to 'cmd/hsu/parse.go')
| -rw-r--r-- | cmd/hsu/parse.go | 104 |
1 files changed, 85 insertions, 19 deletions
diff --git a/cmd/hsu/parse.go b/cmd/hsu/parse.go index 35704c61..6003f6cf 100644 --- a/cmd/hsu/parse.go +++ b/cmd/hsu/parse.go @@ -6,62 +6,128 @@ import ( "fmt" "io" "log" + "math" + "os" "strings" ) -func parseUint32Fast(s string) (int, error) { +const ( + // useridStart is the first userid. + useridStart = 0 + // useridEnd is the last userid. + useridEnd = useridStart + rangeSize - 1 +) + +// parseUint32Fast parses a string representation of an unsigned 32-bit integer value +// using the fast path only. This limits the range of values it is defined in. +func parseUint32Fast(s string) (uint32, error) { sLen := len(s) if sLen < 1 { - return -1, errors.New("zero length string") + return 0, errors.New("zero length string") } if sLen > 10 { - return -1, errors.New("string too long") + return 0, errors.New("string too long") } - n := 0 + var n uint32 for i, ch := range []byte(s) { ch -= '0' if ch > 9 { - return -1, fmt.Errorf("invalid character '%s' at index %d", string(ch+'0'), i) + return 0, fmt.Errorf("invalid character '%s' at index %d", string(ch+'0'), i) } - n = n*10 + int(ch) + n = n*10 + uint32(ch) } return n, nil } -func parseConfig(r io.Reader, puid int) (fid int, ok bool, err error) { +// parseConfig reads a list of allowed users from r until it encounters puid or [io.EOF]. +// +// Each line of the file specifies a hakurei userid to kernel uid mapping. A line consists +// of the string representation of the uid of the user wishing to start hakurei containers, +// followed by a space, followed by the string representation of its userid. Duplicate uid +// entries are ignored, with the first occurrence taking effect. +// +// All string representations are parsed by calling parseUint32Fast. +func parseConfig(r io.Reader, puid uint32) (userid uint32, ok bool, err error) { s := bufio.NewScanner(r) - var line, puid0 int + var ( + line uintptr + puid0 uint32 + ) for s.Scan() { line++ - // <puid> <fid> + // <puid> <userid> lf := strings.SplitN(s.Text(), " ", 2) if len(lf) != 2 { - return -1, false, fmt.Errorf("invalid entry on line %d", line) + return useridEnd + 1, false, fmt.Errorf("invalid entry on line %d", line) } puid0, err = parseUint32Fast(lf[0]) if err != nil || puid0 < 1 { - return -1, false, fmt.Errorf("invalid parent uid on line %d", line) + return useridEnd + 1, false, fmt.Errorf("invalid parent uid on line %d", line) } ok = puid0 == puid if ok { - // allowed fid range 0 to 99 - if fid, err = parseUint32Fast(lf[1]); err != nil || fid < 0 || fid > 99 { - return -1, false, fmt.Errorf("invalid identity on line %d", line) + // userid bound to a range, uint32 size allows this to be increased if needed + if userid, err = parseUint32Fast(lf[1]); err != nil || + userid < useridStart || userid > useridEnd { + return useridEnd + 1, false, fmt.Errorf("invalid userid on line %d", line) } return } } - return -1, false, s.Err() + return useridEnd + 1, false, s.Err() } -func mustParseConfig(r io.Reader, puid int) (int, bool) { - fid, ok, err := parseConfig(r, puid) - if err != nil { +// hsuConfPath is an absolute pathname to the hsu configuration file. +// Its contents are interpreted by parseConfig. +const hsuConfPath = "/etc/hsurc" + +// mustParseConfig calls parseConfig to interpret the contents of hsuConfPath, +// terminating the program if an error is encountered, the syntax is incorrect, +// or the current user is not authorised to use hsu because its uid is missing. +// +// Therefore, code after this function call can assume an authenticated state. +// +// mustParseConfig returns the userid value of the current user. +func mustParseConfig(puid int) (userid uint32) { + if puid > math.MaxUint32 { + log.Fatalf("got impossible uid %d", puid) + } + + var ok bool + if f, err := os.Open(hsuConfPath); err != nil { + log.Fatal(err) + } else if userid, ok, err = parseConfig(f, uint32(puid)); err != nil { + log.Fatal(err) + } else if err = f.Close(); err != nil { log.Fatal(err) } - return fid, ok + if !ok { + log.Fatalf("uid %d is not in the hsurc file", puid) + } + + return +} + +// envIdentity is the name of the environment variable holding a +// string representation of the current application identity. +var envIdentity = "HAKUREI_IDENTITY" + +// mustReadIdentity calls parseUint32Fast to interpret the value stored in envIdentity, +// terminating the program if the value is not set, malformed, or out of bounds. +func mustReadIdentity() uint32 { + // ranges defined in hst and copied to this package to avoid importing hst + if as, ok := os.LookupEnv(envIdentity); !ok { + log.Fatal("HAKUREI_IDENTITY not set") + panic("unreachable") + } else if identity, err := parseUint32Fast(as); err != nil || + identity < identityStart || identity > identityEnd { + log.Fatal("invalid identity") + panic("unreachable") + } else { + return identity + } } |
