From 80e085e7f0027cc7b8e68a5e797f33f0efd03b29 Mon Sep 17 00:00:00 2001 From: Jose Narvaez Date: Mon, 24 Jul 2017 22:49:07 +0100 Subject: [PATCH] Revisiting `passwd` - Replaced all `unwrap()` calls by `try()`. - Replaced all `panic()` calls by `fail()`. - Argument parsing is now all done by `ArgParser`. - Used `Passwd::parse_file` where possible. - This actually does not change the password, will be the next job. --- src/bin/passwd.rs | 107 ++++++++++++++++++++++++---------------------- 1 file changed, 57 insertions(+), 50 deletions(-) diff --git a/src/bin/passwd.rs b/src/bin/passwd.rs index 18c7a03b65..3300205b92 100644 --- a/src/bin/passwd.rs +++ b/src/bin/passwd.rs @@ -1,4 +1,7 @@ +#![deny(warnings)] + extern crate arg_parser; +extern crate extra; extern crate rand; extern crate syscall; extern crate termion; @@ -8,18 +11,20 @@ use rand::{Rng, OsRng}; use std::{env, io}; use std::fs::File; use std::io::{Read, Write}; -use std::process; +use std::process::exit; use arg_parser::ArgParser; use termion::input::TermRead; use userutils::Passwd; +use extra::option::OptionalExt; +use extra::io::fail; const MAN_PAGE: &'static str = /* @MANSTART{passwd} */ r#" NAME passwd - modify a user's password SYNOPSIS - passwd + passwd [ user ] passwd [ -h | --help ] DESCRIPTION @@ -36,12 +41,14 @@ OPTIONS AUTHOR Written by Jeremy Soller. "#; +const PASSWD_FILE: &'static str = "/etc/passwd"; fn main() { let stdin = io::stdin(); let mut stdin = stdin.lock(); let stdout = io::stdout(); let mut stdout = stdout.lock(); + let mut stderr = io::stderr(); let mut parser = ArgParser::new(1) .add_flag(&["h", "help"]); @@ -49,62 +56,57 @@ fn main() { // Shows the help if parser.found("help") { - let _ = stdout.write_all(MAN_PAGE.as_bytes()); - let _ = stdout.flush(); - process::exit(0); + stdout.write_all(MAN_PAGE.as_bytes()).try(&mut stderr); + stdout.flush().try(&mut stderr); + exit(0); } - let uid = syscall::getuid().unwrap() as u32; + let uid = userutils::get_uid(&mut stderr) as u32; let mut passwd_string = String::new(); - File::open("/etc/passwd").unwrap().read_to_string(&mut passwd_string).unwrap(); + let mut passwd_file = File::open(PASSWD_FILE).try(&mut stderr); + passwd_file.read_to_string(&mut passwd_string).try(&mut stderr); + let passwd_file_entries = match Passwd::parse_file(&passwd_string) { + Ok(entries) => entries, + Err(_) => fail("passwd: error parsing passwd file", &mut stderr) + }; + + let passwd = if parser.args.is_empty() { + let passwd_option = passwd_file_entries.iter() + .find(|passwd| passwd.uid == uid); - let passwd = if let Some(user) = env::args().nth(1) { - let mut passwd_option = None; - for line in passwd_string.lines() { - if let Ok(passwd) = Passwd::parse(line) { - if passwd.user == user { - passwd_option = Some(passwd); - break; - } - } - } if let Some(passwd) = passwd_option { passwd } else { - panic!("passwd: user '{}' does not exist", user); + fail(&format!("passwd: current user id {} does not exist", uid), &mut stderr); } } else { - let mut passwd_option = None; - for line in passwd_string.lines() { - if let Ok(passwd) = Passwd::parse(line) { - if passwd.uid == uid { - passwd_option = Some(passwd); - break; - } - } - } + let user = &parser.args[0]; + let passwd_option = passwd_file_entries.iter() + .find(|passwd| passwd.user == user); + if let Some(passwd) = passwd_option { passwd } else { - panic!("passwd: current user id {} does not exist", uid); + fail(&format!("passwd: user '{}' does not exist", user), &mut stderr); } }; if passwd.uid == uid || uid == 0 { - writeln!(stdout, "changing password for '{}'", passwd.user).unwrap(); - let _ = stdout.flush(); + let msg = format!("changing password for '{}' \n", passwd.user); + stdout.write_all(&msg.as_bytes()).try(&mut stderr); + stdout.flush().try(&mut stderr); let mut verified = false; if passwd.hash == "" { verified = true; } else if passwd.uid == uid || uid != 0 { - stdout.write_all(b"current password: ").unwrap(); - let _ = stdout.flush(); + stdout.write_all(b"current password: ").try(&mut stderr); + stdout.flush().try(&mut stderr); - if let Some(password) = stdin.read_passwd(&mut stdout).unwrap() { - stdout.write(b"\n").unwrap(); - let _ = stdout.flush(); + if let Some(password) = stdin.read_passwd(&mut stdout).try(&mut stderr) { + stdout.write(b"\n").try(&mut stderr); + stdout.flush().try(&mut stderr); if passwd.verify(&password) { verified = true; @@ -115,33 +117,38 @@ fn main() { } if verified { - stdout.write_all(b"new password: ").unwrap(); - let _ = stdout.flush(); + stdout.write_all(b"new password: ").try(&mut stderr);; + stdout.flush().try(&mut stderr);; - if let Some(new_password) = stdin.read_passwd(&mut stdout).unwrap() { - stdout.write(b"\nconfirm password: ").unwrap(); - let _ = stdout.flush(); + if let Some(new_password) = stdin.read_passwd(&mut stdout).try(&mut stderr) { + stdout.write(b"\nconfirm password: ").try(&mut stderr); + stdout.flush().try(&mut stderr); - if let Some(confirm_password) = stdin.read_passwd(&mut stdout).unwrap() { - stdout.write(b"\n").unwrap(); - let _ = stdout.flush(); + if let Some(confirm_password) = stdin.read_passwd(&mut stdout).try(&mut stderr) { + stdout.write(b"\n").try(&mut stderr); + stdout.flush().try(&mut stderr);; if new_password == confirm_password { - let salt = format!("{:X}", OsRng::new().unwrap().next_u64()); - writeln!(stdout, "{}", userutils::Passwd::encode(&new_password, &salt)).unwrap(); + let salt = format!("{:X}", OsRng::new().try(&mut stderr).next_u64()); + let encoded_passwd = userutils::Passwd::encode(&new_password, &salt); + //TODO: Actually persist the new password to PASSWD_FILE + let msg = format!("{}\n", encoded_passwd); + stdout.write_all(&msg.as_bytes()).try(&mut stderr); + stdout.flush().try(&mut stderr); } else { - panic!("passwd: new password does not match confirm password"); + fail("passwd: new password does not match confirm password", &mut stderr); } } else { - panic!("passwd: no confirm password provided"); + fail("passwd: no confirm password provided", &mut stderr); } } else { - panic!("passwd: no new password provided"); + fail("passwd: no new password provided", &mut stderr); } } else { - panic!("passwd: incorrect current password"); + fail("passwd: incorrect current password", &mut stderr); } } else { - panic!("passwd: you do not have permission to set the password of '{}'", passwd.user); + let msg = &format!("passwd: you do not have permission to set the password of '{}'", passwd.user); + fail(msg, &mut stderr); } }