aboutsummaryrefslogtreecommitdiffhomepage
path: root/cmd/hsu/parse.go
diff options
context:
space:
mode:
Diffstat (limited to 'cmd/hsu/parse.go')
-rw-r--r--cmd/hsu/parse.go104
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
+ }
}