Migrated wrench command

This commit is contained in:
Sasha Koshka 2023-05-30 03:43:09 -04:00
parent 17a816e360
commit 6f876b2a17

230
cmd/wrench/main.go Normal file
View File

@ -0,0 +1,230 @@
package main
import "os"
import "fmt"
import "flag"
import "strconv"
import "os/exec"
import "os/user"
import "path/filepath"
import "golang.org/x/crypto/bcrypt"
func printErr (format string, values ...any) {
fmt.Fprintf(os.Stderr, os.Args[0] + ": " + format, values...)
}
func serviceUser (service string) string {
return "hn-" + service
}
func tryCommand (cmd *exec.Cmd, failReason string) {
output, err := cmd.CombinedOutput()
if err != nil {
printErr("%s: %s", failReason, string(output))
os.Exit(1)
}
}
func ownOne (path string, uid, gid int) {
file, err := os.Stat(path)
if err != nil {
printErr("could not stat %s: %v", path, err)
return
}
err = os.Chown(path, uid, gid)
if err != nil {
printErr("could not change ownership of %s: %v", path, err)
return
}
if file.IsDir() {
err = os.Chmod(path, 0770)
} else {
err = os.Chmod(path, 0660)
}
if err != nil {
printErr("could not change mode of %s: %v", path, err)
return
}
}
func main () {
user, err := user.Current()
if err != nil {
printErr("could not get username %v", err)
os.Exit(1)
}
// define commands
hashCommand := flag.NewFlagSet("hash", flag.ExitOnError)
hashCost := hashCommand.Uint("cost", uint(bcrypt.DefaultCost), "Cost of the hash")
hashText := hashCommand.String("k", "", "Text content of the key")
addUserCommand := flag.NewFlagSet("adduser", flag.ExitOnError)
addUserService := addUserCommand.String ("s", "router",
"Service to add a user for")
delUserCommand := flag.NewFlagSet("deluser", flag.ExitOnError)
delUserService := delUserCommand.String ("s", "router",
"Service to delete the user for")
authCommand := flag.NewFlagSet("auth", flag.ExitOnError)
authService := authCommand.String ("s", "router",
"Service to authorize the user to access")
authUser := authCommand.String ("u", user.Username,
"User to be given access")
ownCommand := flag.NewFlagSet("own", flag.ExitOnError)
ownService := ownCommand.String ("s", "router",
"Service to give ownership of the file to")
ownFile := ownCommand.String ("f", ".",
"File to take ownership of")
ownRecursive := ownCommand.Bool ("r", false,
"Whether or not to recurse into sub-directories")
// execute correct command
switch os.Args[1] {
case "hash":
execHash(int(*hashCost), *hashText)
case "adduser":
execAdduser(*addUserService)
case "deluser":
execDeluser(*delUserService)
case "auth":
execAuth(*authService, *authUser)
case "own":
execOwn(*ownService, *ownFile, *ownRecursive)
}
}
func execHash (cost int, key string) {
if cost < bcrypt.MinCost {
printErr("cost is too low, must be at least %v", bcrypt.MinCost)
os.Exit(1)
}
if cost > bcrypt.MaxCost {
printErr("cost is too hight, can be at most %v", bcrypt.MaxCost)
os.Exit(1)
}
hash, err := bcrypt.GenerateFromPassword([]byte(key), cost)
if err != nil {
printErr("could not hash key: %v", err)
os.Exit(1)
}
fmt.Println(string(hash))
}
func execAdduser (service string) {
fullName := serviceUser(service)
// BUSYBOX
adduser, err := exec.LookPath("adduser")
if err == nil {
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 {
tryCommand (exec.Command (
useradd, fullName, "-rUM",
"--shell", "/sbin/nologin"), "could not add user")
return
}
printErr("could not add user: no command adduser or useradd")
os.Exit(1)
}
func execDeluser (service string) {
fullName := serviceUser(service)
// BUSYBOX
deluser, err := exec.LookPath("deluser")
if err == nil {
tryCommand (exec.Command(deluser, fullName, "--remove-home"),
"could not delete user")
return
}
// GNU
userdel, err := exec.LookPath("userdel")
if err == nil {
tryCommand (exec.Command(userdel, fullName, "-r"),
"could not delete user")
groupdel, _ := exec.LookPath("groupdel")
tryCommand (exec.Command(groupdel, fullName),
"could not delete group")
return
}
printErr("could not delete user: no command deluser or userdel")
os.Exit(1)
}
func execAuth (service, user string) {
fullName := serviceUser(service)
adduser, err := exec.LookPath("adduser")
if err == nil {
tryCommand (exec.Command(adduser, user, fullName),
"could not add user to group " + fullName)
return
}
// GNU
useradd, err := exec.LookPath("usermod")
if err == nil {
tryCommand (exec.Command(useradd, "-a", "-g", fullName, user),
"could not add user to group " + fullName)
return
}
printErr("could not auth user: no command adduser or usermod")
os.Exit(1)
}
func execOwn (service, file string, recurse bool) {
fullName := serviceUser(service)
userInfo, err := user.Lookup(fullName)
uid, _ := strconv.Atoi(userInfo.Uid)
gid, _ := strconv.Atoi(userInfo.Gid)
if err != nil {
printErr("could not get user info: %v", err)
os.Exit(1)
}
if !recurse {
ownOne(file, uid, gid)
return
}
err = filepath.Walk(file, func(
filePath string,
file os.FileInfo,
err error,
) error {
if err != nil {
printErr("could not traverse filesystem: %v", err)
return nil
}
ownOne(filePath, uid, gid)
return nil
})
if err != nil {
printErr("could not traverse filesystem: %v", err)
os.Exit(1)
}
}