create user needs sudo
This commit is contained in:
@@ -24,6 +24,7 @@ The program:
|
|||||||
- Prompts to add, edit, or delete a share.
|
- Prompts to add, edit, or delete a share.
|
||||||
- Checks `valid users` entries against local accounts.
|
- Checks `valid users` entries against local accounts.
|
||||||
- Offers to create missing local accounts with `useradd -M -s /usr/sbin/nologin <user>`.
|
- Offers to create missing local accounts with `useradd -M -s /usr/sbin/nologin <user>`.
|
||||||
|
- If user creation fails because admin rights are needed, explains the issue and offers to retry with `sudo`.
|
||||||
- Writes a timestamped backup before saving changes.
|
- Writes a timestamped backup before saving changes.
|
||||||
|
|
||||||
If you create a local account for a Samba-authenticated share, you may still need to add the Samba password separately:
|
If you create a local account for a Samba-authenticated share, you may still need to add the Samba password separately:
|
||||||
|
|||||||
57
app.go
57
app.go
@@ -17,7 +17,6 @@ var ErrCancelled = errors.New("cancelled")
|
|||||||
|
|
||||||
type UserManager interface {
|
type UserManager interface {
|
||||||
UserExists(name string) bool
|
UserExists(name string) bool
|
||||||
CreateUser(name string) error
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type CommandRunner interface {
|
type CommandRunner interface {
|
||||||
@@ -33,11 +32,6 @@ func (RealUserManager) UserExists(name string) bool {
|
|||||||
return err == nil
|
return err == nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (RealUserManager) CreateUser(name string) error {
|
|
||||||
runner := OSCommandRunner{}
|
|
||||||
return runner.Run("useradd", "-M", "-s", "/usr/sbin/nologin", name)
|
|
||||||
}
|
|
||||||
|
|
||||||
type OSCommandRunner struct{}
|
type OSCommandRunner struct{}
|
||||||
|
|
||||||
func (OSCommandRunner) Run(name string, args ...string) error {
|
func (OSCommandRunner) Run(name string, args ...string) error {
|
||||||
@@ -348,8 +342,8 @@ func (a *App) ensureUsers(users []string) error {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := a.users.CreateUser(name); err != nil {
|
if err := a.createUser(name); err != nil {
|
||||||
return fmt.Errorf("create user %s: %w", name, err)
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
a.printf("Created local user %s\n", name)
|
a.printf("Created local user %s\n", name)
|
||||||
@@ -359,6 +353,42 @@ func (a *App) ensureUsers(users []string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *App) createUser(name string) error {
|
||||||
|
args := []string{"-M", "-s", "/usr/sbin/nologin", name}
|
||||||
|
if err := a.runner.Run("useradd", args...); err == nil {
|
||||||
|
return nil
|
||||||
|
} else if shouldOfferSudoRetry(err) {
|
||||||
|
a.println("")
|
||||||
|
a.println("Creating a Linux user usually needs administrator permission.")
|
||||||
|
a.println("I can try again using sudo so you can enter your admin password.")
|
||||||
|
a.flush()
|
||||||
|
|
||||||
|
canUseSudo := false
|
||||||
|
if a.lookPath != nil {
|
||||||
|
_, sudoErr := a.lookPath("sudo")
|
||||||
|
canUseSudo = sudoErr == nil
|
||||||
|
}
|
||||||
|
if !canUseSudo {
|
||||||
|
return fmt.Errorf("create user %s: %w", name, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
retry, promptErr := a.confirm("Retry user creation with sudo", true)
|
||||||
|
if promptErr != nil {
|
||||||
|
return promptErr
|
||||||
|
}
|
||||||
|
if !retry {
|
||||||
|
return fmt.Errorf("create user %s: %w", name, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if sudoErr := a.runner.Run("sudo", append([]string{"useradd"}, args...)...); sudoErr != nil {
|
||||||
|
return fmt.Errorf("create user %s with sudo: %w", name, sudoErr)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
} else {
|
||||||
|
return fmt.Errorf("create user %s: %w", name, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (a *App) prompt(label string) (string, error) {
|
func (a *App) prompt(label string) (string, error) {
|
||||||
a.printf("%s: ", label)
|
a.printf("%s: ", label)
|
||||||
a.flush()
|
a.flush()
|
||||||
@@ -437,3 +467,14 @@ func copyFile(src, dst string) error {
|
|||||||
}
|
}
|
||||||
return os.WriteFile(dst, data, 0o644)
|
return os.WriteFile(dst, data, 0o644)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func shouldOfferSudoRetry(err error) bool {
|
||||||
|
if os.Geteuid() == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
text := strings.ToLower(err.Error())
|
||||||
|
return strings.Contains(text, "permission denied") ||
|
||||||
|
strings.Contains(text, "operation not permitted") ||
|
||||||
|
strings.Contains(text, "exit status")
|
||||||
|
}
|
||||||
|
|||||||
BIN
samba-configer
BIN
samba-configer
Binary file not shown.
Reference in New Issue
Block a user