Skip to content

Commit 5d04be9

Browse files
Allow sudo passwordless
1 parent 60dac98 commit 5d04be9

File tree

1 file changed

+50
-0
lines changed

1 file changed

+50
-0
lines changed

authdaemon/host_linux.go

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,10 +158,51 @@ func createUser(username string, meta ConnectionMetadata) error {
158158
} else {
159159
logger.Info("auth-daemon: added %s to %s", username, group)
160160
}
161+
if err := configurePasswordlessSudo(username); err != nil {
162+
logger.Warn("auth-daemon: configure passwordless sudo for %s: %v", username, err)
163+
}
164+
}
165+
return nil
166+
}
167+
168+
// configurePasswordlessSudo creates a sudoers.d file to allow passwordless sudo for the user
169+
func configurePasswordlessSudo(username string) error {
170+
sudoersFile := filepath.Join("/etc/sudoers.d", fmt.Sprintf("90-pangolin-%s", username))
171+
content := fmt.Sprintf("# Created by newt auth-daemon\n%s ALL=(ALL) NOPASSWD:ALL\n", username)
172+
173+
// Write to temp file first
174+
tmpFile := sudoersFile + ".tmp"
175+
if err := os.WriteFile(tmpFile, []byte(content), 0440); err != nil {
176+
return fmt.Errorf("write temp sudoers file: %w", err)
177+
}
178+
179+
// Validate with visudo
180+
cmd := exec.Command("visudo", "-c", "-f", tmpFile)
181+
if out, err := cmd.CombinedOutput(); err != nil {
182+
os.Remove(tmpFile)
183+
return fmt.Errorf("visudo validation failed: %w (output: %s)", err, string(out))
184+
}
185+
186+
// Move to final location
187+
if err := os.Rename(tmpFile, sudoersFile); err != nil {
188+
os.Remove(tmpFile)
189+
return fmt.Errorf("move sudoers file: %w", err)
161190
}
191+
192+
logger.Info("auth-daemon: configured passwordless sudo for %s", username)
162193
return nil
163194
}
164195

196+
// removePasswordlessSudo removes the sudoers.d file for the user
197+
func removePasswordlessSudo(username string) {
198+
sudoersFile := filepath.Join("/etc/sudoers.d", fmt.Sprintf("90-newt-%s", username))
199+
if err := os.Remove(sudoersFile); err != nil && !os.IsNotExist(err) {
200+
logger.Warn("auth-daemon: remove passwordless sudo for %s: %v", username, err)
201+
} else if err == nil {
202+
logger.Info("auth-daemon: removed passwordless sudo for %s", username)
203+
}
204+
}
205+
165206
func mustAtoi(s string) int {
166207
n, _ := strconv.Atoi(s)
167208
return n
@@ -189,6 +230,15 @@ func reconcileUser(u *user.User, meta ConnectionMetadata) error {
189230
logger.Info("auth-daemon: removed %s from %s", u.Username, group)
190231
}
191232
}
233+
234+
// Configure passwordless sudo
235+
if meta.Sudo {
236+
if err := configurePasswordlessSudo(u.Username); err != nil {
237+
logger.Warn("auth-daemon: configure passwordless sudo for %s: %v", u.Username, err)
238+
}
239+
} else {
240+
removePasswordlessSudo(u.Username)
241+
}
192242
if meta.Homedir && u.HomeDir != "" {
193243
if st, err := os.Stat(u.HomeDir); err != nil || !st.IsDir() {
194244
if err := os.MkdirAll(u.HomeDir, 0755); err != nil {

0 commit comments

Comments
 (0)