go-runas: call RPCs to yourself as a child dropping root
If you have a Go server running as root and want to run some of your code as adifferent user, it turns out that Go’s standard rpc package works wonderfully for this.
Here’s a fun hack of a library that makes this easy: go-runas
Usage, from example.go in that repo:
// ....
func main() {
runas.Server.Register(&DemoService{})
runas.MaybeRunChildServer()
for _, user := range []string{"nobody", "daemon", "man", "syslog"} {
var res WhoAmIResult
client, err := runas.User(user)
if err != nil {
log.Printf("failed to get client for user %s: %v", user, err)
continue
}
client.Call("DemoService.WhoAmI", true, &res)
log.Printf("user %s: %v", user, res)
}
}
// This code runs as a different user, not root.
func (s *DemoService) WhoAmI(unused *bool, res *WhoAmIResult) os.Error {
res.Uid = syscall.Getuid()
res.Gid = syscall.Getgid()
return nil
}And the result:
$ 6g example.go && 6l -o example example.6 && sudo ./example
2011/04/22 12:14:57 user nobody: {65534 65534}
2011/04/22 12:14:57 user daemon: {1 1}
2011/04/22 12:14:57 user man: {6 12}
2011/04/22 12:14:57 user syslog: {101 103}