diff --git a/cli/cli.go b/cli/cli.go index 9574237..49d900d 100644 --- a/cli/cli.go +++ b/cli/cli.go @@ -5,7 +5,10 @@ package cli import "os" import "fmt" import "flag" +import "os/user" import "strings" +import "strconv" +import "path/filepath" // Sayf is like Printf, but prints the program name before the message. This is // used for printing messages and errors. @@ -25,6 +28,16 @@ func ServiceUser (service string) string { return "hn-" + strings.ToLower(service) } +// DataDir returns the standard Hnakra data directory. +func DataDir () string { + return "/var/hnakra" +} + +// ServiceDir returns the standard data directory of a service. +func ServiceDir (service string) string { + return filepath.Join(DataDir(), "services", ServiceUser(service)) +} + // NeedRoot halts the program and displays an error if it is not being run as // root. This should be called whenever an operation takes place that requires // root privelages. @@ -35,3 +48,34 @@ func NeedRoot() { os.Exit(1) } } + +// MkdirFor makes a directory makes the specified directory (if it doesnt +// already exist) and gives ownership of it to the specified uid and gid. +func MkdirFor (directory string, uid, gid int) error { + err := os.MkdirAll(directory, 0755) + if err != nil { return err } + err = os.Chmod(directory, 0770) + if err != nil { return err } + err = os.Chown(directory, uid, gid) + if err != nil { return err } + + return nil +} + +// LookupUID returns the uid and gid of the given username, if it exists. +func LookupUID (name string) (uid, gid uint32, err error) { + user, err := user.Lookup(name) + if err != nil { + return 0, 0, err + } + + puid, err := strconv.Atoi(user.Uid) + if err != nil { + return 0, 0, err + } + pgid, err := strconv.Atoi(user.Gid) + if err != nil { + return 0, 0, err + } + return uint32(puid), uint32(pgid), nil +} diff --git a/cmd/hnctl/main.go b/cmd/hnctl/main.go index 231290b..7be0f1f 100644 --- a/cmd/hnctl/main.go +++ b/cmd/hnctl/main.go @@ -64,7 +64,7 @@ func execStart (service string) { return } - uid, gid, err := spawn.LookupUID(fullName) + uid, gid, err := cli.LookupUID(fullName) if err != nil { cli.Sayf("cannot start service: %v\n", err) os.Exit(1) @@ -78,7 +78,7 @@ func execStart (service string) { logDir := filepath.Join("/var/log/", fullName) env := append(os.Environ(), "HNAKRA_LOG_DIR=" + logDir) - err = ensureLogDir(logDir, int(uid), int(gid)) + err = cli.MkdirFor(logDir, int(uid), int(gid)) if err != nil { cli.Sayf("cannot start service: %v\n", err) os.Exit(1) @@ -125,17 +125,6 @@ func execStop (service string) { } } -func ensureLogDir (directory string, uid, gid int) error { - err := os.MkdirAll(directory, 0755) - if err != nil { return err } - err = os.Chmod(directory, 0770) - if err != nil { return err } - err = os.Chown(directory, uid, gid) - if err != nil { return err } - - return nil -} - func ensurePidFile (file string, uid, gid int) error { pidFile, err := os.Create(file) if err != nil { return err } diff --git a/cmd/hnctl/spawn/spawn.go b/cmd/hnctl/spawn/spawn.go index 558351e..2c30abc 100644 --- a/cmd/hnctl/spawn/spawn.go +++ b/cmd/hnctl/spawn/spawn.go @@ -6,7 +6,6 @@ import "fmt" import "time" import "errors" import "syscall" -import "os/user" import "strconv" import "path/filepath" @@ -45,24 +44,6 @@ func Spawn (path string, uid, gid uint32, env []string, args ...string) (pid int return process.Pid, process.Release() } -// LookupUID returns the uid and gid of the given username, if it exists. -func LookupUID (name string) (uid, gid uint32, err error) { - user, err := user.Lookup(name) - if err != nil { - return 0, 0, err - } - - puid, err := strconv.Atoi(user.Uid) - if err != nil { - return 0, 0, err - } - pgid, err := strconv.Atoi(user.Gid) - if err != nil { - return 0, 0, err - } - return uint32(puid), uint32(pgid), nil -} - // PidFile returns the path of a pidfile under the specified name. More // specifically, it returns `/run/.pid`. func PidFile (name string) string { diff --git a/cmd/wrench/main.go b/cmd/wrench/main.go index 1486d78..09ca964 100644 --- a/cmd/wrench/main.go +++ b/cmd/wrench/main.go @@ -76,6 +76,8 @@ func main () { delUserCommand := flag.NewFlagSet("deluser", flag.ExitOnError) delUserService := delUserCommand.String ("s", "router", "Service to delete the user for") + delUserRmData := delUserCommand.Bool ("rmd", false, + "Whether to remove the service's data directory") authCommand := flag.NewFlagSet("auth", flag.ExitOnError) authService := authCommand.String ("s", "router", @@ -108,7 +110,7 @@ func main () { execAdduser(*addUserService) case "deluser": delUserCommand.Parse(subCommandArgs) - execDeluser(*delUserService) + execDeluser(*delUserService, *delUserRmData) case "auth": authCommand.Parse(subCommandArgs) execAuth(*authService, *authUser) @@ -144,55 +146,66 @@ func execHash (cost int, key string) { func execAdduser (service string) { fullName := cli.ServiceUser(service) + dataDir := cli.ServiceDir(service) - // BUSYBOX - adduser, err := exec.LookPath("adduser") - if err == nil { + if adduser, err := exec.LookPath("adduser"); err == nil { + // BUSYBOX addgroup, _ := exec.LookPath("addgroup") tryCommand (exec.Command(addgroup, fullName, "-S"), "could not add group") tryCommand (exec.Command(adduser, fullName, "-SHDG", fullName), "could not add user") - return - } - - // GNU - useradd, err := exec.LookPath("useradd") - if err == nil { + } else if useradd, err := exec.LookPath("useradd"); err == nil { + // GNU tryCommand (exec.Command ( useradd, fullName, "-rUM", "--shell", "/sbin/nologin"), "could not add user") - return + } else { + cli.Sayf("could not add user: no command adduser or useradd\n") + os.Exit(1) } - cli.Sayf("could not add user: no command adduser or useradd\n") - os.Exit(1) + // create data directory + uid, gid, err := cli.LookupUID(fullName) + if err != nil { + cli.Sayf("could not create data dir: %v\n", err) + os.Exit(1) + } + err = cli.MkdirFor(dataDir, int(uid), int(gid)) + if err != nil { + cli.Sayf("could not create data dir: %v\n", err) + os.Exit(1) + } } -func execDeluser (service string) { +func execDeluser (service string, rmData bool) { fullName := cli.ServiceUser(service) + dataDir := cli.ServiceDir(service) - // BUSYBOX - deluser, err := exec.LookPath("deluser") - if err == nil { + if deluser, err := exec.LookPath("deluser"); err == nil { + // BUSYBOX tryCommand (exec.Command(deluser, fullName, "--remove-home"), "could not delete user") - return - } - - // GNU - userdel, err := exec.LookPath("userdel") - if err == nil { + } else if userdel, err := exec.LookPath("userdel"); err == nil { + // GNU tryCommand (exec.Command(userdel, fullName, "-r"), "could not delete user") groupdel, _ := exec.LookPath("groupdel") tryCommand (exec.Command(groupdel, fullName), "could not delete group") - return + } else { + cli.Sayf("could not delete user: no command deluser or userdel\n") + os.Exit(1) } - cli.Sayf("could not delete user: no command deluser or userdel\n") - os.Exit(1) + // delete data directory + if rmData { + err := os.RemoveAll(dataDir) + if err != nil { + cli.Sayf("could not delete data dir: %v\n", err) + os.Exit(1) + } + } } func execAuth (service, user string) {