usermod --gid regroups every file under an account's home, and accounts were made with / as home: they now have /nonexistent, and an older account's home is moved there (without its files) before its group changes. A sub-path asked for later that holds data not in the group waits for the operator as the root would. The take act gives the group to hardlinked files an account owns (the *arr apps' downloads) and leaves root's; a file's setuid or setgid bit the regroup takes is never put back, so no setgid file hands out the library's group; each is counted. An apply no longer waits for a running take walk.
74 lines
2.9 KiB
Go
74 lines
2.9 KiB
Go
package system
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
// busybox has no usermod (novox/hq ADR 0328 §4): an account the mesh made is given its added groups with addgroup
|
|
// and delgroup, and a change of its primary group is refused, saying why.
|
|
func TestBusyboxGivesAnAccountItsAddedGroupsAndRefusesAnotherPrimary(t *testing.T) {
|
|
var ran []string
|
|
run := func(_ context.Context, name string, args ...string) (string, error) {
|
|
ran = append(ran, name+" "+strings.Join(args, " "))
|
|
switch {
|
|
case name == "getent" && args[0] == "passwd":
|
|
return "mesh-radarr:x:61001:62000::/:/sbin/nologin\n", nil
|
|
case name == "getent" && args[0] == "group":
|
|
return "mesh-media:x:62000:\n", nil
|
|
case name == "id":
|
|
return "mesh-media mesh-old\n", nil
|
|
}
|
|
return "", nil
|
|
}
|
|
if err := (alpine{}).ModifyAccount(context.Background(), run, "mesh-radarr", 62000, []string{"mesh-books"}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
got := strings.Join(ran, "\n")
|
|
if !strings.Contains(got, "addgroup mesh-radarr mesh-books") || !strings.Contains(got, "delgroup mesh-radarr mesh-old") ||
|
|
strings.Contains(got, "delgroup mesh-radarr mesh-media") {
|
|
t.Fatalf("not given exactly its added groups:\n%s", got)
|
|
}
|
|
err := (alpine{}).ModifyAccount(context.Background(), run, "mesh-radarr", 62005, nil)
|
|
if !errors.Is(err, ErrUnsupported) || !strings.Contains(err.Error(), "primary group") {
|
|
t.Fatalf("a change of primary group was not refused saying why: %v", err)
|
|
}
|
|
}
|
|
|
|
// An account is made with no home, and a change of its groups moves an old home of `/` away first: `usermod --gid`
|
|
// regroups every file under the home the account owns, and under `/` that is the whole machine.
|
|
func TestAnAccountsGroupsChangeOnlyWithNoHome(t *testing.T) {
|
|
var ran []string
|
|
home := "/"
|
|
run := func(_ context.Context, name string, args ...string) (string, error) {
|
|
line := name + " " + strings.Join(args, " ")
|
|
ran = append(ran, line)
|
|
if name == "getent" {
|
|
return "mesh-radarr:x:61001:61001::" + home + ":/usr/bin/nologin\n", nil
|
|
}
|
|
if name == "usermod" && args[0] == "--home" {
|
|
home = args[1]
|
|
}
|
|
if name == "usermod" && args[0] == "--gid" && home != NoHome {
|
|
t.Fatalf("usermod --gid ran with the home %s: every file there would be regrouped", home)
|
|
}
|
|
return "", nil
|
|
}
|
|
if err := (arch{}).CreateSystemAccount(context.Background(), run, "mesh-radarr", 61001, 61001, nil); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if !strings.Contains(ran[0], "--no-create-home --home-dir "+NoHome+" ") {
|
|
t.Fatalf("an account is made with a home: %s", ran[0])
|
|
}
|
|
if err := (arch{}).ModifyAccount(context.Background(), run, "mesh-radarr", 62000, nil); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
got := strings.Join(ran, "\n")
|
|
if !strings.Contains(got, "usermod --home "+NoHome+" mesh-radarr") || strings.Contains(got, " -m") ||
|
|
strings.Contains(got, "--move-home") {
|
|
t.Fatalf("the home was not moved away first, without moving files:\n%s", got)
|
|
}
|
|
}
|