Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

passwd: Add a way to delete users/groups #1014

Merged
merged 5 commits into from
Aug 6, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions build_blackbox_tests
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ set -eu
# system
GLDFLAGS="-X github.com/coreos/ignition/v2/internal/distro.useraddCmd=useradd-stub "
GLDFLAGS+="-X github.com/coreos/ignition/v2/internal/distro.usermodCmd=usermod-stub "
GLDFLAGS+="-X github.com/coreos/ignition/v2/internal/distro.userdelCmd=userdel-stub "
GLDFLAGS+="-X github.com/coreos/ignition/v2/internal/distro.groupdelCmd=groupdel-stub "
GLDFLAGS+="-X github.com/coreos/ignition/v2/internal/distro.blackboxTesting=true "

. ./build
Expand Down
6 changes: 6 additions & 0 deletions config/v3_2_experimental/schema/ignition.json
Original file line number Diff line number Diff line change
Expand Up @@ -577,6 +577,9 @@
},
"shell": {
"type": ["string", "null"]
},
"shouldExist": {
sohankunkerkar marked this conversation as resolved.
Show resolved Hide resolved
"type": ["boolean", "null"]
}
},
"required": [
Expand All @@ -597,6 +600,9 @@
},
"system": {
"type": ["boolean", "null"]
},
"shouldExist": {
"type": ["boolean", "null"]
}
},
"required": [
Expand Down
29 changes: 29 additions & 0 deletions config/v3_2_experimental/translate/translate.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,39 @@ func translateStorage(old old_types.Storage) (ret types.Storage) {
return
}

func translatePasswdUser(old old_types.PasswdUser) (ret types.PasswdUser) {
sohankunkerkar marked this conversation as resolved.
Show resolved Hide resolved
tr := translate.NewTranslator()
tr.Translate(&old.Gecos, &ret.Gecos)
tr.Translate(&old.Groups, &ret.Groups)
tr.Translate(&old.HomeDir, &ret.HomeDir)
tr.Translate(&old.Name, &ret.Name)
tr.Translate(&old.NoCreateHome, &ret.NoCreateHome)
tr.Translate(&old.NoLogInit, &ret.NoLogInit)
tr.Translate(&old.NoUserGroup, &ret.NoUserGroup)
tr.Translate(&old.PasswordHash, &ret.PasswordHash)
tr.Translate(&old.PrimaryGroup, &ret.PrimaryGroup)
tr.Translate(&old.SSHAuthorizedKeys, &ret.SSHAuthorizedKeys)
tr.Translate(&old.Shell, &ret.Shell)
tr.Translate(&old.System, &ret.System)
tr.Translate(&old.UID, &ret.UID)
return
}

func translatePasswdGroup(old old_types.PasswdGroup) (ret types.PasswdGroup) {
tr := translate.NewTranslator()
tr.Translate(&old.Gid, &ret.Gid)
tr.Translate(&old.Name, &ret.Name)
tr.Translate(&old.PasswordHash, &ret.PasswordHash)
tr.Translate(&old.System, &ret.System)
return
}

func Translate(old old_types.Config) (ret types.Config) {
tr := translate.NewTranslator()
tr.AddCustomTranslator(translateIgnition)
tr.AddCustomTranslator(translateStorage)
tr.AddCustomTranslator(translatePasswdUser)
tr.AddCustomTranslator(translatePasswdGroup)
tr.Translate(&old, &ret)
return
}
2 changes: 2 additions & 0 deletions config/v3_2_experimental/types/schema.go
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ type PasswdGroup struct {
Gid *int `json:"gid,omitempty"`
Name string `json:"name"`
PasswordHash *string `json:"passwordHash,omitempty"`
ShouldExist *bool `json:"shouldExist,omitempty"`
System *bool `json:"system,omitempty"`
}

Expand All @@ -160,6 +161,7 @@ type PasswdUser struct {
PasswordHash *string `json:"passwordHash,omitempty"`
PrimaryGroup *string `json:"primaryGroup,omitempty"`
SSHAuthorizedKeys []SSHAuthorizedKey `json:"sshAuthorizedKeys,omitempty"`
ShouldExist *bool `json:"shouldExist,omitempty"`
Shell *string `json:"shell,omitempty"`
System *bool `json:"system,omitempty"`
UID *int `json:"uid,omitempty"`
Expand Down
2 changes: 2 additions & 0 deletions dracut/30ignition/module-setup.sh
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,15 @@ install() {
# present
inst_multiple -o \
groupadd \
groupdel \
mkfs.btrfs \
mkfs.ext4 \
mkfs.vfat \
mkfs.xfs \
mkswap \
sgdisk \
useradd \
userdel \
usermod \
wipefs

Expand Down
4 changes: 4 additions & 0 deletions internal/distro/distro.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,15 @@ var (

// Helper programs
groupaddCmd = "groupadd"
groupdelCmd = "groupdel"
mdadmCmd = "mdadm"
mountCmd = "mount"
sgdiskCmd = "sgdisk"
modprobeCmd = "modprobe"
udevadmCmd = "udevadm"
usermodCmd = "usermod"
useraddCmd = "useradd"
userdelCmd = "userdel"
setfilesCmd = "setfiles"
wipefsCmd = "wipefs"

Expand Down Expand Up @@ -81,13 +83,15 @@ func KernelCmdlinePath() string { return kernelCmdlinePath }
func SystemConfigDir() string { return fromEnv("SYSTEM_CONFIG_DIR", systemConfigDir) }

func GroupaddCmd() string { return groupaddCmd }
func GroupdelCmd() string { return groupdelCmd }
func MdadmCmd() string { return mdadmCmd }
func MountCmd() string { return mountCmd }
func SgdiskCmd() string { return sgdiskCmd }
func ModprobeCmd() string { return modprobeCmd }
func UdevadmCmd() string { return udevadmCmd }
func UsermodCmd() string { return usermodCmd }
func UseraddCmd() string { return useraddCmd }
func UserdelCmd() string { return userdelCmd }
func SetfilesCmd() string { return setfilesCmd }
func WipefsCmd() string { return wipefsCmd }

Expand Down
33 changes: 21 additions & 12 deletions internal/exec/stages/files/passwd.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,12 @@ func (s *stage) expandGlobList(globs ...string) ([]string, error) {

// createPasswd creates the users and groups as described in config.Passwd.
func (s *stage) createPasswd(config types.Config) error {
if err := s.createGroups(config); err != nil {
return fmt.Errorf("failed to create groups: %v", err)
if err := s.ensureGroups(config); err != nil {
return fmt.Errorf("failed to configure groups: %v", err)
}

if err := s.createUsers(config); err != nil {
return fmt.Errorf("failed to create users: %v", err)
if err := s.ensureUsers(config); err != nil {
return fmt.Errorf("failed to configure users: %v", err)
}

// to be safe, just blanket mark all passwd-related files rather than
Expand All @@ -68,7 +68,10 @@ func (s *stage) createPasswd(config types.Config) error {
s.relabel(deglobbed...)
s.relabel("/etc/.pwd.lock")
for _, user := range config.Passwd.Users {
if user.NoCreateHome != nil && *user.NoCreateHome == true {
if user.NoCreateHome != nil && *user.NoCreateHome {
continue
}
if user.ShouldExist != nil && !*user.ShouldExist {
continue
}
homedir, err := s.GetUserHomeDir(user)
Expand All @@ -94,12 +97,13 @@ func (s *stage) createPasswd(config types.Config) error {
return nil
}

// createUsers creates the users as described in config.Passwd.Users.
func (s stage) createUsers(config types.Config) error {
// ensureUsers ensures that users match the state described
// in config.Passwd.Users.
func (s stage) ensureUsers(config types.Config) error {
if len(config.Passwd.Users) == 0 {
return nil
}
s.Logger.PushPrefix("createUsers")
s.Logger.PushPrefix("ensureUsers")
defer s.Logger.PopPrefix()

for _, u := range config.Passwd.Users {
Expand All @@ -108,6 +112,10 @@ func (s stage) createUsers(config types.Config) error {
u.Name, err)
}

if u.ShouldExist != nil && !*u.ShouldExist {
continue
}

if err := s.SetPasswordHash(u); err != nil {
return fmt.Errorf("failed to set password for %q: %v",
u.Name, err)
Expand All @@ -122,16 +130,17 @@ func (s stage) createUsers(config types.Config) error {
return nil
}

// createGroups creates the users as described in config.Passwd.Groups.
func (s stage) createGroups(config types.Config) error {
// ensureGroups ensures that groups match the state described
// in config.Passwd.Groups.
func (s stage) ensureGroups(config types.Config) error {
if len(config.Passwd.Groups) == 0 {
return nil
}
s.Logger.PushPrefix("createGroups")
s.Logger.PushPrefix("ensureGroups")
defer s.Logger.PopPrefix()

for _, g := range config.Passwd.Groups {
if err := s.CreateGroup(g); err != nil {
if err := s.EnsureGroup(g); err != nil {
return fmt.Errorf("failed to create group %q: %v",
g.Name, err)
}
Expand Down
57 changes: 52 additions & 5 deletions internal/exec/util/passwd.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,13 +50,28 @@ func appendIfStringSet(args []string, arg string, str *string) []string {
}

// EnsureUser ensures that the user exists as described. If the user does not
// yet exist, they will be created, otherwise the existing user will be
// modified.
// yet exist, they will be created, otherwise the existing user will be modified.
// If the `shouldExist` field is set to false and the user already exists, then
// they will be deleted.
func (u Util) EnsureUser(c types.PasswdUser) error {
sohankunkerkar marked this conversation as resolved.
Show resolved Hide resolved
shouldExist := c.ShouldExist == nil || *c.ShouldExist
exists, err := u.CheckIfUserExists(c)
if err != nil {
return err
}
if !shouldExist {
if exists {
args := []string{"--remove", "--root", u.DestDir, c.Name}
_, err := u.LogCmd(exec.Command(distro.UserdelCmd(), args...),
"deleting user %q", c.Name)
if err != nil {
return fmt.Errorf("failed to delete user %q: %v",
c.Name, err)
}
}
return nil
}
sohankunkerkar marked this conversation as resolved.
Show resolved Hide resolved
sohankunkerkar marked this conversation as resolved.
Show resolved Hide resolved

args := []string{"--root", u.DestDir}

var cmd string
Expand Down Expand Up @@ -244,8 +259,28 @@ func (u Util) SetPasswordHash(c types.PasswdUser) error {
return err
}

// CreateGroup creates the group as described.
func (u Util) CreateGroup(g types.PasswdGroup) error {
// EnsureGroup ensures that the group exists as described. If the
// `shouldExist` field is set to false and the group already exists,
// then it will be deleted.
func (u Util) EnsureGroup(g types.PasswdGroup) error {
shouldExist := g.ShouldExist == nil || *g.ShouldExist
exists, err := u.CheckIfGroupExists(g)
if err != nil {
return err
}
if !shouldExist {
sohankunkerkar marked this conversation as resolved.
Show resolved Hide resolved
if exists {
args := []string{"--root", u.DestDir, g.Name}
_, err := u.LogCmd(exec.Command(distro.GroupdelCmd(), args...),
"deleting group %q", g.Name)
if err != nil {
return fmt.Errorf("failed to delete group %q: %v",
g.Name, err)
}
}
return nil
}

args := []string{"--root", u.DestDir}

if g.Gid != nil {
Expand All @@ -263,7 +298,19 @@ func (u Util) CreateGroup(g types.PasswdGroup) error {

args = append(args, g.Name)

_, err := u.LogCmd(exec.Command(distro.GroupaddCmd(), args...),
_, err = u.LogCmd(exec.Command(distro.GroupaddCmd(), args...),
"adding group %q", g.Name)
return err
}

// CheckIfGroupExists will return Info log when group is empty
func (u Util) CheckIfGroupExists(g types.PasswdGroup) (bool, error) {
_, err := u.groupLookup(g.Name)
if _, ok := err.(user.UnknownGroupError); ok {
return false, nil
}
if err != nil {
return false, err
}
return true, nil
}
Loading