aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorOphestra <cat@gensokyo.uk>2025-09-24 21:10:13 +0900
committerOphestra <cat@gensokyo.uk>2025-09-24 21:10:13 +0900
commitafa7a0800da2bb44fd9daaea1180c046ea111db8 (patch)
tree16625a815e17c3d587513f54554a965860db4a47
parent773253fdf5388dd77d817be98024cc975d207104 (diff)
cmd/hsu: return hsurc id
The uid format is stable, this value is what caller has to obtain through hsu. Closes #14. Signed-off-by: Ophestra <cat@gensokyo.uk>
-rw-r--r--cmd/hsu/main.go37
-rw-r--r--internal/app/process.go2
-rw-r--r--internal/sys/hsu.go87
3 files changed, 55 insertions, 71 deletions
diff --git a/cmd/hsu/main.go b/cmd/hsu/main.go
index 28571b9b..cb82c204 100644
--- a/cmd/hsu/main.go
+++ b/cmd/hsu/main.go
@@ -15,7 +15,7 @@ import (
const (
hsuConfFile = "/etc/hsurc"
envShim = "HAKUREI_SHIM"
- envAID = "HAKUREI_APP_ID"
+ envIdentity = "HAKUREI_IDENTITY"
envGroups = "HAKUREI_GROUPS"
PR_SET_NO_NEW_PRIVS = 0x26
@@ -48,8 +48,8 @@ func main() {
}
// uid = 1000000 +
- // fid * 10000 +
- // aid
+ // id * 10000 +
+ // identity
uid := 1000000
// refuse to run if hsurc is not protected correctly
@@ -62,29 +62,25 @@ func main() {
}
// authenticate before accepting user input
+ var id int
if f, err := os.Open(hsuConfFile); err != nil {
log.Fatal(err)
- } else if fid, ok := mustParseConfig(f, puid); !ok {
+ } else if v, ok := mustParseConfig(f, puid); !ok {
log.Fatalf("uid %d is not in the hsurc file", puid)
} else {
- uid += fid * 10000
- }
+ id = v
+ if err = f.Close(); err != nil {
+ log.Fatal(err)
+ }
- // allowed aid range 0 to 9999
- if as, ok := os.LookupEnv(envAID); !ok {
- log.Fatal("HAKUREI_APP_ID not set")
- } else if aid, err := parseUint32Fast(as); err != nil || aid < 0 || aid > 9999 {
- log.Fatal("invalid aid")
- } else {
- uid += aid
+ uid += id * 10000
}
// pass through setup fd to shim
var shimSetupFd string
if s, ok := os.LookupEnv(envShim); !ok {
- // hakurei requests target uid
- // print resolved uid and exit
- fmt.Print(uid)
+ // hakurei requests hsurc user id
+ fmt.Print(id)
os.Exit(0)
} else if len(s) != 1 || s[0] > '9' || s[0] < '3' {
log.Fatal("HAKUREI_SHIM holds an invalid value")
@@ -92,6 +88,15 @@ func main() {
shimSetupFd = s
}
+ // allowed identity range 0 to 9999
+ if as, ok := os.LookupEnv(envIdentity); !ok {
+ log.Fatal("HAKUREI_IDENTITY not set")
+ } else if identity, err := parseUint32Fast(as); err != nil || identity < 0 || identity > 9999 {
+ log.Fatal("invalid identity")
+ } else {
+ uid += identity
+ }
+
// supplementary groups
var suppGroups, suppCurrent []int
diff --git a/internal/app/process.go b/internal/app/process.go
index a182fa6c..368b655f 100644
--- a/internal/app/process.go
+++ b/internal/app/process.go
@@ -255,7 +255,7 @@ func (seal *outcome) main() {
// passed through to shim by hsu
shimEnv + "=" + strconv.Itoa(fd),
// interpreted by hsu
- "HAKUREI_APP_ID=" + seal.user.identity.String(),
+ "HAKUREI_IDENTITY=" + seal.user.identity.String(),
}
}
diff --git a/internal/sys/hsu.go b/internal/sys/hsu.go
index 2be12d1e..39fb4f18 100644
--- a/internal/sys/hsu.go
+++ b/internal/sys/hsu.go
@@ -17,69 +17,48 @@ import (
// Hsu caches responses from cmd/hsu.
type Hsu struct {
- uidOnce sync.Once
- uidCopy map[int]struct {
- uid int
- err error
- }
- uidMu sync.RWMutex
+ idOnce sync.Once
+ idErr error
+ id int
}
var ErrHsuAccess = errors.New("current user is not in the hsurc file")
func (h *Hsu) Uid(identity int) (int, error) {
- h.uidOnce.Do(func() {
- h.uidCopy = make(map[int]struct {
- uid int
- err error
- })
- })
-
- {
- h.uidMu.RLock()
- u, ok := h.uidCopy[identity]
- h.uidMu.RUnlock()
- if ok {
- return u.uid, u.err
- }
- }
+ h.idOnce.Do(func() {
+ h.id = -1
+ hsuPath := internal.MustHsuPath()
- h.uidMu.Lock()
- defer h.uidMu.Unlock()
+ cmd := exec.Command(hsuPath)
+ cmd.Path = hsuPath
+ cmd.Stderr = os.Stderr // pass through fatal messages
+ cmd.Env = make([]string, 0)
+ cmd.Dir = container.FHSRoot
+ var (
+ p []byte
+ exitError *exec.ExitError
+ )
- u := struct {
- uid int
- err error
- }{}
- defer func() { h.uidCopy[identity] = u }()
-
- u.uid = -1
- hsuPath := internal.MustHsuPath()
-
- cmd := exec.Command(hsuPath)
- cmd.Path = hsuPath
- cmd.Stderr = os.Stderr // pass through fatal messages
- cmd.Env = []string{"HAKUREI_APP_ID=" + strconv.Itoa(identity)}
- cmd.Dir = container.FHSRoot
- var (
- p []byte
- exitError *exec.ExitError
- )
-
- const step = "obtain uid from hsu"
- if p, u.err = cmd.Output(); u.err == nil {
- u.uid, u.err = strconv.Atoi(string(p))
- if u.err != nil {
- u.err = &hst.AppError{Step: step, Err: u.err, Msg: "invalid uid string from hsu"}
+ const step = "obtain uid from hsu"
+ if p, h.idErr = cmd.Output(); h.idErr == nil {
+ h.id, h.idErr = strconv.Atoi(string(p))
+ if h.idErr != nil {
+ h.idErr = &hst.AppError{Step: step, Err: h.idErr, Msg: "invalid uid string from hsu"}
+ }
+ } else if errors.As(h.idErr, &exitError) && exitError != nil && exitError.ExitCode() == 1 {
+ // hsu prints an error message in this case
+ h.idErr = &hst.AppError{Step: step, Err: ErrHsuAccess}
+ } else if os.IsNotExist(h.idErr) {
+ h.idErr = &hst.AppError{Step: step, Err: os.ErrNotExist,
+ Msg: fmt.Sprintf("the setuid helper is missing: %s", hsuPath)}
}
- } else if errors.As(u.err, &exitError) && exitError != nil && exitError.ExitCode() == 1 {
- // hsu prints an error message in this case
- u.err = &hst.AppError{Step: step, Err: ErrHsuAccess}
- } else if os.IsNotExist(u.err) {
- u.err = &hst.AppError{Step: step, Err: os.ErrNotExist,
- Msg: fmt.Sprintf("the setuid helper is missing: %s", hsuPath)}
+ })
+
+ uid := -1
+ if h.id >= 0 {
+ uid = 1000000 + h.id*10000 + identity
}
- return u.uid, u.err
+ return uid, h.idErr
}
// MustUid calls [State.Uid] and terminates on error.