diff --git a/Cargo.lock b/Cargo.lock index caae5577c5..9d74eb02e0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -182,7 +182,7 @@ dependencies = [ [[package]] name = "redox_users" version = "0.1.0" -source = "git+https://github.com/redox-os/users.git#0c56faee77dd86d0b48460b6e588e2c96a8a0d99" +source = "git+https://github.com/redox-os/users.git#820ab8f1ea19816175ac400ddc1d1be6c0b8d992" dependencies = [ "argon2rs 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "extra 0.1.0 (git+https://github.com/redox-os/libextra.git)", diff --git a/src/bin/groupadd.rs b/src/bin/groupadd.rs index 8eda178e38..f7e787081c 100644 --- a/src/bin/groupadd.rs +++ b/src/bin/groupadd.rs @@ -47,7 +47,7 @@ fn main() { (about: "Add groups based on the system's redox_users backend") (@arg GROUP: +required "Add group GROUP") (@arg FORCE: -f --force "Force the status of the program to be 0 even if the group exists") - (@arg GID: -g --gid "Group id. Positive integer and must not be in use") + (@arg GID: -g --gid +takes_value "Group id. Positive integer and must not be in use") ).get_matches(); let mut sys_groups = AllGroups::new().unwrap_or_exit(1); diff --git a/src/bin/groupmod.rs b/src/bin/groupmod.rs index fb983bf020..f3de52f6f9 100644 --- a/src/bin/groupmod.rs +++ b/src/bin/groupmod.rs @@ -8,7 +8,7 @@ extern crate redox_users; use std::process::exit; use extra::option::OptionalExt; -use redox_users::AllGroups; +use redox_users::{AllGroups, AllUsers}; const _MAN_PAGE: &'static str = /* @MANSTART{groupmod} */ r#" NAME @@ -33,7 +33,7 @@ OPTIONS Files with GROUP's old gid will not be updated. User's who use the old gid as their primary gid will - also not be updated. This is a TODO and will change. + be updated. -n, --name NAME The name of the group will be set to NAME @@ -62,9 +62,16 @@ fn main() { exit(1); }); - //TODO: Update user's primary GID, if gid is used as such if let Some(gid) = args.value_of("GID") { let gid = gid.parse::().unwrap_or_exit(1); + // Update users + let mut sys_users = AllUsers::new().unwrap_or_exit(1); + for user in sys_users.iter_mut() { + if user.gid == group.gid { + user.gid = gid; + } + } + sys_users.save().unwrap_or_exit(1); group.gid = gid; } diff --git a/src/bin/useradd.rs b/src/bin/useradd.rs index c029576378..915b4b66e1 100644 --- a/src/bin/useradd.rs +++ b/src/bin/useradd.rs @@ -181,6 +181,7 @@ fn main() { .value_of("HOME_DIR") .unwrap_or_else(|| { if args.is_present("CREATE_HOME") { + sys_homes.push_str("/"); sys_homes.push_str(&login); sys_homes.as_str() } else { diff --git a/src/bin/userdel.rs b/src/bin/userdel.rs index 187cd9a18d..d5d4a3ca1a 100644 --- a/src/bin/userdel.rs +++ b/src/bin/userdel.rs @@ -4,12 +4,14 @@ extern crate clap; extern crate extra; extern crate redox_users; +extern crate userutils; use std::fs::remove_dir; use std::process::exit; use extra::option::OptionalExt; -use redox_users::AllUsers; +use redox_users::{AllGroups, AllUsers}; +use userutils::AllGroupsExt; const _MAN_PAGE: &'static str = /* @MANSTART{userdel} */ r#" NAME @@ -21,12 +23,10 @@ SYNOPSYS DESCRIPTION userdel removes users from whatever backend is employed by - the system's redox_users. + the system's redox_users. The utility removes the user from + all groups of which they are a member. It can also be used to manage removal of home directories. - - This utility does not remove the user from any groups! This is - a planned feature and will be implemented at some point. OPTIONS -h, --help @@ -51,18 +51,21 @@ fn main() { let login = args.value_of("LOGIN").unwrap(); let mut sys_users = AllUsers::new().unwrap_or_exit(1); + let mut sys_groups = AllGroups::new().unwrap_or_exit(1); { - let user = sys_users.get_by_name(login).unwrap_or_else(|| { - eprintln!("userdel: user does not exist: {}", login); - exit(1); - }); + sys_groups.remove_user_from_all_groups(login); if args.is_present("REMOVE") { + let user = sys_users.get_by_name(login).unwrap_or_else(|| { + eprintln!("userdel: user does not exist: {}", login); + exit(1); + }); remove_dir(&user.home).unwrap_or_exit(1); } } sys_users.remove_by_name(login.to_string()).unwrap_or_exit(1); + sys_groups.save().unwrap_or_exit(1); sys_users.save().unwrap_or_exit(1); } diff --git a/src/bin/usermod.rs b/src/bin/usermod.rs index 60f80282ad..c2ed5d83bc 100644 --- a/src/bin/usermod.rs +++ b/src/bin/usermod.rs @@ -11,7 +11,7 @@ use std::process::exit; use extra::option::OptionalExt; use redox_users::{AllGroups, AllUsers}; -use userutils::create_user_dir; +use userutils::{create_user_dir, AllGroupsExt}; const _MAN_PAGE: &'static str = /* @MANSTART{usermod} */ r#" NAME @@ -123,24 +123,16 @@ fn main() { let mut sys_users = AllUsers::new().unwrap_or_exit(1); let mut sys_groups; - //Requires iteration over system groups, which requires additions to redox_users - if let Some(_new_groups) = args.value_of("SET_GROUPS") { - unimplemented!(); + if let Some(new_groups) = args.value_of("SET_GROUPS") { + sys_groups = AllGroups::new().unwrap_or_exit(1); + sys_groups.remove_user_from_all_groups(login); + sys_groups.add_user_to_groups(login, new_groups.split(',').collect()).unwrap_or_exit(1); + sys_groups.save().unwrap_or_exit(1); } if let Some(new_groups) = args.value_of("APPEND_GROUPS") { sys_groups = AllGroups::new().unwrap_or_exit(1); - - let new_groups = new_groups.split(','); - - for groupname in new_groups { - let group = sys_groups.get_mut_by_name(groupname).unwrap_or_else(|| { - eprintln!("usermod: no group found: {}", groupname); - exit(1); - }); - group.users.push(login.to_string()); - } - + sys_groups.add_user_to_groups(login, new_groups.split(',').collect()).unwrap_or_exit(1); sys_groups.save().unwrap_or_exit(1); } diff --git a/src/lib.rs b/src/lib.rs index c7a7dd86fa..344b723a17 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -19,15 +19,47 @@ extern crate redox_users; extern crate syscall; -use std::io::Result; +use std::io::Result as IoResult; -use redox_users::User; +use redox_users::{AllGroups, Result, User, UsersError}; use syscall::call::{open, fchmod, fchown}; use syscall::error::Result as SysResult; use syscall::flag::{O_CREAT, O_DIRECTORY, O_CLOEXEC}; const DEFAULT_MODE: u16 = 0o700; +// Not the prettiest thing in the world, but some functionality here makes +// some of the utils much less gross +pub trait AllGroupsExt { + fn add_user_to_groups(&mut self, login: &str, groups: Vec<&str>) -> Result<()>; + fn remove_user_from_all_groups(&mut self, login: &str); +} + +impl AllGroupsExt for AllGroups { + // new_groups is a comma separated list of groupnames + fn add_user_to_groups(&mut self, login: &str, new_groups: Vec<&str>) -> Result<()> { + for groupname in new_groups { + let group = match self.get_mut_by_name(groupname) { + Some(group) => group, + None => return Err(UsersError::NotFound.into()) + }; + group.users.push(login.to_string()); + } + Ok(()) + } + + /// Remove a user from all groups of which they are a member + fn remove_user_from_all_groups(&mut self, login: &str) { + for group in self.iter_mut() { + let op_pos = group.users.iter() + .position(|username| username == login ); + if let Some(indx) = op_pos { + group.users.remove(indx); + } + } + } +} + /// Spawns a shell for the given `User`. /// /// This function wraps the shell_cmd function of the User struct @@ -43,7 +75,7 @@ const DEFAULT_MODE: u16 = 0o700; /// let user = sys_users.get_by_name("goyox86"); /// spawn_shell(user).unwrap(); /// ``` -pub fn spawn_shell(user: &User) -> Result { +pub fn spawn_shell(user: &User) -> IoResult { let mut command = user.shell_cmd(); let mut child = command.spawn()?; @@ -53,7 +85,7 @@ pub fn spawn_shell(user: &User) -> Result { } } - +/// Creates a directory with 700 user:user permissions pub fn create_user_dir(user: &User, dir: T) -> SysResult<()> where T: AsRef + std::convert::AsRef<[u8]> {