Carry a bundle's seat traffic under its own name and kind, and start a module as its own account (hq ADR 0259)
This commit is contained in:
@@ -0,0 +1,68 @@
|
||||
package launch
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os/exec"
|
||||
"os/user"
|
||||
"strconv"
|
||||
"strings"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// RunAs is the word in a bundle's environment naming the account it runs as (novox/hq ADR 0259 §8), and
|
||||
// OperatorAccount the word naming the operator's account on this machine, which the runtime is given.
|
||||
const (
|
||||
RunAs = "MESH_RUN_AS"
|
||||
OperatorAccount = "MESH_OPERATOR_ACCOUNT"
|
||||
)
|
||||
|
||||
// lookupUser is user.Lookup, a variable so a test can name accounts this machine does not have.
|
||||
var lookupUser = user.Lookup
|
||||
|
||||
func word(env []string, name string) string {
|
||||
for _, kv := range env {
|
||||
if k, v, ok := strings.Cut(kv, "="); ok && k == name {
|
||||
return v
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// runAs starts cmd as the account its environment names, with that account's home, or leaves it as the
|
||||
// runtime's own when none is named. It refuses root and the operator's account: a module asks for an
|
||||
// account of its own to keep what it holds from the agents, and every agent runs as the operator.
|
||||
func runAs(cmd *exec.Cmd, env []string) error {
|
||||
name := word(env, RunAs)
|
||||
if name == "" {
|
||||
return nil
|
||||
}
|
||||
if operator := word(env, OperatorAccount); operator != "" && name == operator {
|
||||
return fmt.Errorf("%s names the operator's account %s; a module runs as an account of its own, never "+
|
||||
"the one every agent runs as (novox/hq ADR 0259)", RunAs, name)
|
||||
}
|
||||
u, err := lookupUser(name)
|
||||
if err != nil {
|
||||
return fmt.Errorf("%s names the account %s, which this machine does not have: the module makes it with "+
|
||||
"a user resource (novox/hq ADR 0259): %w", RunAs, name, err)
|
||||
}
|
||||
uid, err := strconv.ParseUint(u.Uid, 10, 32)
|
||||
if err != nil {
|
||||
return fmt.Errorf("the account %s has no usable uid %q", name, u.Uid)
|
||||
}
|
||||
gid, err := strconv.ParseUint(u.Gid, 10, 32)
|
||||
if err != nil {
|
||||
return fmt.Errorf("the account %s has no usable gid %q", name, u.Gid)
|
||||
}
|
||||
if uid == 0 || name == "root" {
|
||||
return fmt.Errorf("%s names root; a module that asks for an account of its own is not given root", RunAs)
|
||||
}
|
||||
cmd.SysProcAttr = &syscall.SysProcAttr{Credential: &syscall.Credential{Uid: uint32(uid), Gid: uint32(gid)}}
|
||||
var kept []string
|
||||
for _, kv := range cmd.Env {
|
||||
if !strings.HasPrefix(kv, "HOME=") && !strings.HasPrefix(kv, "USER=") && !strings.HasPrefix(kv, "LOGNAME=") {
|
||||
kept = append(kept, kv)
|
||||
}
|
||||
}
|
||||
cmd.Env = append(kept, "HOME="+u.HomeDir, "USER="+name, "LOGNAME="+name)
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user