diff --git a/src/bin/su.rs b/src/bin/su.rs index e757b81174..57ae650ad8 100644 --- a/src/bin/su.rs +++ b/src/bin/su.rs @@ -67,22 +67,34 @@ pub fn main() { let user = get_user_by_name(&target_user).unwrap_or_exit(1); - if uid > 0 || user.hash != "" { + // If we are root and the new user account has no password + if uid == 0 && user.hash == "" { + stdout.write(b"\n").try(&mut stderr); + stdout.flush().try(&mut stderr); + + // Spawn a shell as the new user + exit(spawn_shell(user).code().unwrap_or(1)); + } else { + // Ask for the new user account's password stdout.write_all(b"password: ").try(&mut stderr); stdout.flush().try(&mut stderr); - if let Some(password) = stdin.read_passwd(&mut stdout).try(&mut stderr) { + // Read the password, reading an empty string if CTRL-d is specified + let password = stdin.read_passwd(&mut stdout).try(&mut stderr).unwrap_or(String::new()); - if user.verify_passwd(&password) { - spawn_shell(user); - exit(0); - } else { - stdout.write(b"su: authentication failed\n").try(&mut stderr); - stdout.flush().try(&mut stderr); - exit(1); - } + // Write a newline + stdout.write(b"\n").try(&mut stderr); + stdout.flush().try(&mut stderr); + + // If the password is correct + if user.verify_passwd(&password) { + // Spawn a shell as the new user + exit(spawn_shell(user).code().unwrap_or(1)); } } - spawn_shell(user); + // All other conditions will return an error + stderr.write(b"su: authentication failed\n").try(&mut stderr); + stderr.flush().try(&mut stderr); + exit(1); } diff --git a/src/lib.rs b/src/lib.rs index dcb18c0f55..b29b2ac7d2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -18,7 +18,7 @@ extern crate redox_users; -use std::process::Command; +use std::process::{Command, ExitStatus}; use std::os::unix::process::CommandExt; use redox_users::User; @@ -49,7 +49,7 @@ use redox_users::User; /// This function can panic under two scenarios. The first, when an error occurs while /// spawning the new process containig the shell and the second, when after a succesful /// spawn, an error happens while trying to wait for the newly created process. -pub fn spawn_shell(user: User) { +pub fn spawn_shell(user: User) -> ExitStatus { let mut command = Command::new(&user.shell); command.uid(user.uid); @@ -65,7 +65,7 @@ pub fn spawn_shell(user: User) { match command.spawn() { Ok(mut child) => match child.wait() { - Ok(_status) => (), + Ok(status) => status, Err(err) => panic!("userutils: failed to wait for '{}': {}", user.shell, err) }, Err(err) => panic!("userutils: failed to execute '{}': {}", user.shell, err)