package main import ( "bytes" "errors" "flag" "fmt" "os" "path" "strconv" "git.gensokyo.uk/security/fortify/internal/fmsg" ) func main() { fmsg.SetPrefix("fuserdb") const varEmpty = "/var/empty" out := flag.String("o", "userdb", "output directory") homeDir := flag.String("d", varEmpty, "parent of home directories") shell := flag.String("s", "/sbin/nologin", "absolute path to subordinate user shell") flag.Parse() type user struct { name string fid int } users := make([]user, len(flag.Args())) for i, s := range flag.Args() { f := bytes.SplitN([]byte(s), []byte{':'}, 2) if len(f) != 2 { fmsg.Fatalf("invalid entry at index %d", i) } users[i].name = string(f[0]) if fid, err := strconv.Atoi(string(f[1])); err != nil { fmsg.Fatal(err.Error()) } else { users[i].fid = fid } } if err := os.MkdirAll(*out, 0755); err != nil && !errors.Is(err, os.ErrExist) { fmsg.Fatalf("cannot create output: %v", err) } for _, u := range users { fidString := strconv.Itoa(u.fid) for aid := 0; aid < 10000; aid++ { userName := fmt.Sprintf("u%d_a%d", u.fid, aid) uid := 1000000 + u.fid*10000 + aid us := strconv.Itoa(uid) realName := fmt.Sprintf("Fortify subordinate user %d (%s)", aid, u.name) var homeDirectory string if *homeDir != varEmpty { homeDirectory = path.Join(*homeDir, "u"+fidString, "a"+strconv.Itoa(aid)) } else { homeDirectory = varEmpty } writeUser(userName, uid, us, realName, homeDirectory, *shell, *out) writeGroup(userName, uid, us, nil, *out) } } fmsg.Printf("created %d entries", len(users)*2*10000) fmsg.Exit(0) }