From eaf26765c12efe5519fb2af72557dc0ee8286bcd Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Fri, 7 Oct 2016 10:42:00 -0600 Subject: [PATCH] Add su --- Cargo.toml | 4 +++ src/bin/login.rs | 4 --- src/bin/su.rs | 84 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 88 insertions(+), 4 deletions(-) create mode 100644 src/bin/su.rs diff --git a/Cargo.toml b/Cargo.toml index 9287729090..fbbef1a662 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,6 +14,10 @@ path = "src/bin/id.rs" name = "login" path = "src/bin/login.rs" +[[bin]] +name = "su" +path = "src/bin/su.rs" + [[bin]] name = "sudo" path = "src/bin/sudo.rs" diff --git a/src/bin/login.rs b/src/bin/login.rs index 9806a14de1..ba2e9d1d7d 100644 --- a/src/bin/login.rs +++ b/src/bin/login.rs @@ -52,10 +52,6 @@ pub fn main() { let password_hash = Passwd::encode(&password); - if let Ok(mut debug) = File::open("debug:") { - let _ = write!(debug, "{};{}\n", user, password_hash); - } - for line in passwd_string.lines() { if let Ok(passwd) = Passwd::parse(line) { if user == passwd.user && password_hash == passwd.hash { diff --git a/src/bin/su.rs b/src/bin/su.rs new file mode 100644 index 0000000000..7c57000d00 --- /dev/null +++ b/src/bin/su.rs @@ -0,0 +1,84 @@ +#![feature(question_mark)] + +extern crate syscall; +extern crate termion; +extern crate userutils; + +use std::env; +use std::fs::File; +use std::io::{self, Read, Write}; +use std::os::unix::process::CommandExt; +use std::process::Command; +use std::str; + +use termion::input::TermRead; +use userutils::Passwd; + +pub fn main() { + let stdin = io::stdin(); + let mut stdin = stdin.lock(); + let stdout = io::stdout(); + let mut stdout = stdout.lock(); + + let mut user = env::args().nth(1).unwrap_or(String::new()); + if user.is_empty() { + user = String::from("root"); + } + + let uid = syscall::getuid().unwrap(); + + let mut passwd_string = String::new(); + File::open("file:etc/passwd").unwrap().read_to_string(&mut passwd_string).unwrap(); + + let mut passwd_option = None; + for line in passwd_string.lines() { + if let Ok(passwd) = Passwd::parse(line) { + if user == passwd.user && ("" == passwd.hash || uid == 0) { + passwd_option = Some(passwd); + break; + } + } + } + + if passwd_option.is_none() { + stdout.write_all(b"password: ").unwrap(); + let _ = stdout.flush(); + + if let Some(password) = stdin.read_passwd(&mut stdout).unwrap() { + stdout.write(b"\n").unwrap(); + let _ = stdout.flush(); + + let password_hash = Passwd::encode(&password); + + for line in passwd_string.lines() { + if let Ok(passwd) = Passwd::parse(line) { + if user == passwd.user && password_hash == passwd.hash { + passwd_option = Some(passwd); + break; + } + } + } + } + } + + if let Some(passwd) = passwd_option { + let mut command = Command::new(passwd.shell); + + command.uid(passwd.uid); + command.gid(passwd.gid); + + command.env("USER", &user); + command.env("HOME", passwd.home); + + match command.spawn() { + Ok(mut child) => match child.wait() { + Ok(_status) => (), //println!("login: waited for {}: {:?}", sh, status.code()), + Err(err) => panic!("su: failed to wait for '{}': {}", passwd.shell, err) + }, + Err(err) => panic!("su: failed to execute '{}': {}", passwd.shell, err) + } + } else { + stdout.write(b"su: authentication failed\n").unwrap(); + let _ = stdout.flush(); + } +}