From c93cbd1cb2c635174a4ff8d76146d918d4060be5 Mon Sep 17 00:00:00 2001 From: Itxaka Date: Thu, 17 Oct 2024 15:35:30 +0200 Subject: [PATCH 1/6] Try harder to get existing user ID Signed-off-by: Itxaka --- pkg/plugins/user.go | 37 +++++++++++++++++----------------- pkg/plugins/user_test.go | 1 - pkg/schema/loader_cloudinit.go | 1 - pkg/schema/schema.go | 1 - 4 files changed, 19 insertions(+), 21 deletions(-) diff --git a/pkg/plugins/user.go b/pkg/plugins/user.go index 6f5fdd0a..c69145eb 100644 --- a/pkg/plugins/user.go +++ b/pkg/plugins/user.go @@ -6,6 +6,7 @@ import ( osuser "os/user" "sort" "strconv" + "syscall" "github.com/mauromorales/xpasswd/pkg/users" "github.com/pkg/errors" @@ -101,26 +102,30 @@ func createUser(fs vfs.FS, u schema.User, console Console) error { } } + if u.Homedir == "" { + u.Homedir = fmt.Sprintf("%s/%s", usrDefaults["HOME"], u.Name) + } + uid := -1 - if u.UID != "" { - // User defined-uid - uid, err = strconv.Atoi(u.UID) + list := users.NewUserList() + list.SetPath(etcpasswd) + list.Load() + user := list.Get(u.Name) + + if user != nil { + uid, err = user.UID() if err != nil { - return errors.Wrap(err, "invalid uid defined") + return errors.Wrap(err, "could not get user id") } } else { - list := users.NewUserList() - list.SetPath(etcpasswd) - list.Load() - - user := list.Get(u.Name) - - if user != nil { - uid, err = user.UID() - if err != nil { - return errors.Wrap(err, "could not get user id") + // Try to see if the user is in the system already with a given UID + userDir, err := os.Stat(u.Homedir) + if err == nil { + if stat, ok := userDir.Sys().(*syscall.Stat_t); ok { + uid = int(stat.Uid) } } else { + // Now generate one if we havent been able to pick the existing one // https://systemd.io/UIDS-GIDS/#special-distribution-uid-ranges uid, err = list.GenerateUIDInRange(entities.HumanIDMin, entities.HumanIDMax) if err != nil { @@ -132,10 +137,6 @@ func createUser(fs vfs.FS, u schema.User, console Console) error { return errors.New("could not set uid for user") } - if u.Homedir == "" { - u.Homedir = fmt.Sprintf("%s/%s", usrDefaults["HOME"], u.Name) - } - if u.Shell == "" { u.Shell = usrDefaults["SHELL"] } diff --git a/pkg/plugins/user_test.go b/pkg/plugins/user_test.go index 47250822..2c3d6881 100644 --- a/pkg/plugins/user_test.go +++ b/pkg/plugins/user_test.go @@ -183,7 +183,6 @@ last:x:999:999:Test user for uid:/:/usr/bin/nologin Users: map[string]schema.User{"foo": { PasswordHash: `$fkekofe`, LockPasswd: true, - UID: "5000", Homedir: "/run/foo", Shell: "/bin/bash", }}, diff --git a/pkg/schema/loader_cloudinit.go b/pkg/schema/loader_cloudinit.go index 3f9230c2..ac55a022 100644 --- a/pkg/schema/loader_cloudinit.go +++ b/pkg/schema/loader_cloudinit.go @@ -54,7 +54,6 @@ func (cloudInit) Load(source string, s []byte, fs vfs.FS) (*YipConfig, error) { System: u.System, NoLogInit: u.NoLogInit, Shell: u.Shell, - UID: u.UID, LockPasswd: u.LockPasswd, } sshKeys[u.Name] = u.SSHAuthorizedKeys diff --git a/pkg/schema/schema.go b/pkg/schema/schema.go index 763b58da..ef451eac 100644 --- a/pkg/schema/schema.go +++ b/pkg/schema/schema.go @@ -98,7 +98,6 @@ type User struct { NoLogInit bool `yaml:"no_log_init,omitempty"` Shell string `yaml:"shell,omitempty"` LockPasswd bool `yaml:"lock_passwd,omitempty"` - UID string `yaml:"uid,omitempty"` } func (u User) Exists() bool { From 7821e8e624bd8456eb62adc7af7e807f09109a97 Mon Sep 17 00:00:00 2001 From: Itxaka Date: Fri, 18 Oct 2024 09:50:06 +0200 Subject: [PATCH 2/6] Update pkg/plugins/user.go Co-authored-by: Dimitris Karakasilis --- pkg/plugins/user.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/plugins/user.go b/pkg/plugins/user.go index c69145eb..684587e5 100644 --- a/pkg/plugins/user.go +++ b/pkg/plugins/user.go @@ -118,7 +118,7 @@ func createUser(fs vfs.FS, u schema.User, console Console) error { return errors.Wrap(err, "could not get user id") } } else { - // Try to see if the user is in the system already with a given UID + // Try to see if the user was created previously with a given UID by checking for an existing home dir userDir, err := os.Stat(u.Homedir) if err == nil { if stat, ok := userDir.Sys().(*syscall.Stat_t); ok { From c765897abe11c7fcaf28b790019677040f023776 Mon Sep 17 00:00:00 2001 From: Itxaka Date: Fri, 18 Oct 2024 09:53:55 +0200 Subject: [PATCH 3/6] Fix tests Signed-off-by: Itxaka --- pkg/plugins/user_test.go | 3 +-- pkg/schema/schema_test.go | 2 -- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/pkg/plugins/user_test.go b/pkg/plugins/user_test.go index 2c3d6881..34ee978b 100644 --- a/pkg/plugins/user_test.go +++ b/pkg/plugins/user_test.go @@ -212,8 +212,7 @@ last:x:999:999:Test user for uid:/:/usr/bin/nologin Expect(foo.HomeDir()).To(Equal("/run/foo")) Expect(foo.Shell()).To(Equal("/bin/bash")) Expect(foo.Password()).To(Equal("x")) - // we specifically set this UID() - Expect(foo.UID()).To(Equal(5000)) + Expect(foo.UID()).To(Equal(1000)) }) diff --git a/pkg/schema/schema_test.go b/pkg/schema/schema_test.go index b17c3891..439e81d9 100644 --- a/pkg/schema/schema_test.go +++ b/pkg/schema/schema_test.go @@ -94,7 +94,6 @@ stages: users: - name: "bar" passwd: "foo" - uid: "1002" lock_passwd: true groups: - sudo @@ -113,7 +112,6 @@ write_files: owner: "bar" `) Expect(len(yipConfig.Stages)).To(Equal(3)) - Expect(yipConfig.Stages["boot"][0].Users["bar"].UID).To(Equal("1002")) Expect(yipConfig.Stages["boot"][0].Users["bar"].PasswordHash).To(Equal("foo")) Expect(yipConfig.Stages["boot"][0].SSHKeys).To(Equal(map[string][]string{"bar": {"faaapploo", "asdd"}})) Expect(yipConfig.Stages["boot"][0].Files[0].Path).To(Equal("/foo/bar")) From 39b577e6f5706eea5b158a2fc27a2c082d272853 Mon Sep 17 00:00:00 2001 From: Itxaka Date: Mon, 21 Oct 2024 10:15:34 +0200 Subject: [PATCH 4/6] Restore UID in user. Signed-off-by: Itxaka --- pkg/plugins/user.go | 47 ++++++++++++++++++++++----------------- pkg/plugins/user_test.go | 3 ++- pkg/schema/schema.go | 1 + pkg/schema/schema_test.go | 2 ++ 4 files changed, 32 insertions(+), 21 deletions(-) diff --git a/pkg/plugins/user.go b/pkg/plugins/user.go index 684587e5..ddcf295b 100644 --- a/pkg/plugins/user.go +++ b/pkg/plugins/user.go @@ -107,32 +107,39 @@ func createUser(fs vfs.FS, u schema.User, console Console) error { } uid := -1 - list := users.NewUserList() - list.SetPath(etcpasswd) - list.Load() - user := list.Get(u.Name) - - if user != nil { - uid, err = user.UID() - if err != nil { - return errors.Wrap(err, "could not get user id") - } + + // If UID is specified just put it there. No matter whats in the system or the collisions. Good luck. + if u.UID != "" { + uid, err = strconv.Atoi(u.UID) } else { - // Try to see if the user was created previously with a given UID by checking for an existing home dir - userDir, err := os.Stat(u.Homedir) - if err == nil { - if stat, ok := userDir.Sys().(*syscall.Stat_t); ok { - uid = int(stat.Uid) + // Try to get the existing UID in the system + list := users.NewUserList() + list.SetPath(etcpasswd) + list.Load() + user := list.Get(u.Name) + if user != nil { + uid, err = user.UID() + if err != nil { + return errors.Wrap(err, "could not get user id") } } else { - // Now generate one if we havent been able to pick the existing one - // https://systemd.io/UIDS-GIDS/#special-distribution-uid-ranges - uid, err = list.GenerateUIDInRange(entities.HumanIDMin, entities.HumanIDMax) - if err != nil { - return errors.Wrap(err, "no available uid") + // Try to see if the user was created previously with a given UID by checking for an existing home dir + userDir, err := os.Stat(u.Homedir) + if err == nil { + if stat, ok := userDir.Sys().(*syscall.Stat_t); ok { + uid = int(stat.Uid) + } + } else { + // Now generate one if we havent been able to pick the existing one + // https://systemd.io/UIDS-GIDS/#special-distribution-uid-ranges + uid, err = list.GenerateUIDInRange(entities.HumanIDMin, entities.HumanIDMax) + if err != nil { + return errors.Wrap(err, "no available uid") + } } } } + if uid == -1 { return errors.New("could not set uid for user") } diff --git a/pkg/plugins/user_test.go b/pkg/plugins/user_test.go index 34ee978b..2081fc15 100644 --- a/pkg/plugins/user_test.go +++ b/pkg/plugins/user_test.go @@ -183,6 +183,7 @@ last:x:999:999:Test user for uid:/:/usr/bin/nologin Users: map[string]schema.User{"foo": { PasswordHash: `$fkekofe`, LockPasswd: true, + UID: "5000", Homedir: "/run/foo", Shell: "/bin/bash", }}, @@ -212,7 +213,7 @@ last:x:999:999:Test user for uid:/:/usr/bin/nologin Expect(foo.HomeDir()).To(Equal("/run/foo")) Expect(foo.Shell()).To(Equal("/bin/bash")) Expect(foo.Password()).To(Equal("x")) - Expect(foo.UID()).To(Equal(1000)) + Expect(foo.UID()).To(Equal(5000)) }) diff --git a/pkg/schema/schema.go b/pkg/schema/schema.go index ef451eac..763b58da 100644 --- a/pkg/schema/schema.go +++ b/pkg/schema/schema.go @@ -98,6 +98,7 @@ type User struct { NoLogInit bool `yaml:"no_log_init,omitempty"` Shell string `yaml:"shell,omitempty"` LockPasswd bool `yaml:"lock_passwd,omitempty"` + UID string `yaml:"uid,omitempty"` } func (u User) Exists() bool { diff --git a/pkg/schema/schema_test.go b/pkg/schema/schema_test.go index 439e81d9..5d1ea0e2 100644 --- a/pkg/schema/schema_test.go +++ b/pkg/schema/schema_test.go @@ -94,6 +94,7 @@ stages: users: - name: "bar" passwd: "foo" + uid: "1002" lock_passwd: true groups: - sudo @@ -113,6 +114,7 @@ write_files: `) Expect(len(yipConfig.Stages)).To(Equal(3)) Expect(yipConfig.Stages["boot"][0].Users["bar"].PasswordHash).To(Equal("foo")) + Expect(yipConfig.Stages["boot"][0].Users["bar"].UID).To(Equal("1002")) Expect(yipConfig.Stages["boot"][0].SSHKeys).To(Equal(map[string][]string{"bar": {"faaapploo", "asdd"}})) Expect(yipConfig.Stages["boot"][0].Files[0].Path).To(Equal("/foo/bar")) Expect(yipConfig.Stages["boot"][0].Files[0].Permissions).To(Equal(uint32(0644))) From a4f179419f402fa4a3e03809fd6354cbe1472014 Mon Sep 17 00:00:00 2001 From: Itxaka Date: Mon, 21 Oct 2024 10:22:23 +0200 Subject: [PATCH 5/6] Fix restore of UID Signed-off-by: Itxaka --- pkg/plugins/user_test.go | 1 + pkg/schema/loader_cloudinit.go | 1 + pkg/schema/schema_test.go | 2 +- 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/pkg/plugins/user_test.go b/pkg/plugins/user_test.go index 2081fc15..47250822 100644 --- a/pkg/plugins/user_test.go +++ b/pkg/plugins/user_test.go @@ -213,6 +213,7 @@ last:x:999:999:Test user for uid:/:/usr/bin/nologin Expect(foo.HomeDir()).To(Equal("/run/foo")) Expect(foo.Shell()).To(Equal("/bin/bash")) Expect(foo.Password()).To(Equal("x")) + // we specifically set this UID() Expect(foo.UID()).To(Equal(5000)) }) diff --git a/pkg/schema/loader_cloudinit.go b/pkg/schema/loader_cloudinit.go index ac55a022..3f9230c2 100644 --- a/pkg/schema/loader_cloudinit.go +++ b/pkg/schema/loader_cloudinit.go @@ -54,6 +54,7 @@ func (cloudInit) Load(source string, s []byte, fs vfs.FS) (*YipConfig, error) { System: u.System, NoLogInit: u.NoLogInit, Shell: u.Shell, + UID: u.UID, LockPasswd: u.LockPasswd, } sshKeys[u.Name] = u.SSHAuthorizedKeys diff --git a/pkg/schema/schema_test.go b/pkg/schema/schema_test.go index 5d1ea0e2..b17c3891 100644 --- a/pkg/schema/schema_test.go +++ b/pkg/schema/schema_test.go @@ -113,8 +113,8 @@ write_files: owner: "bar" `) Expect(len(yipConfig.Stages)).To(Equal(3)) - Expect(yipConfig.Stages["boot"][0].Users["bar"].PasswordHash).To(Equal("foo")) Expect(yipConfig.Stages["boot"][0].Users["bar"].UID).To(Equal("1002")) + Expect(yipConfig.Stages["boot"][0].Users["bar"].PasswordHash).To(Equal("foo")) Expect(yipConfig.Stages["boot"][0].SSHKeys).To(Equal(map[string][]string{"bar": {"faaapploo", "asdd"}})) Expect(yipConfig.Stages["boot"][0].Files[0].Path).To(Equal("/foo/bar")) Expect(yipConfig.Stages["boot"][0].Files[0].Permissions).To(Equal(uint32(0644))) From 31daf3d010fcab58e7e6a7cefefba85063a2ae24 Mon Sep 17 00:00:00 2001 From: Itxaka Date: Mon, 21 Oct 2024 10:23:04 +0200 Subject: [PATCH 6/6] Return error if we cannot convert specified uid Signed-off-by: Itxaka --- pkg/plugins/user.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/pkg/plugins/user.go b/pkg/plugins/user.go index ddcf295b..5efab05c 100644 --- a/pkg/plugins/user.go +++ b/pkg/plugins/user.go @@ -107,10 +107,14 @@ func createUser(fs vfs.FS, u schema.User, console Console) error { } uid := -1 - + // If UID is specified just put it there. No matter whats in the system or the collisions. Good luck. if u.UID != "" { + // User defined-uid uid, err = strconv.Atoi(u.UID) + if err != nil { + return errors.Wrap(err, "invalid uid defined") + } } else { // Try to get the existing UID in the system list := users.NewUserList()