213 lines
6.8 KiB
Rust
213 lines
6.8 KiB
Rust
#[macro_use]
|
|
extern crate clap;
|
|
extern crate extra;
|
|
extern crate syscall;
|
|
extern crate redox_users;
|
|
extern crate userutils;
|
|
|
|
use std::process::exit;
|
|
|
|
use extra::option::OptionalExt;
|
|
use redox_users::{All, AllGroups, AllUsers, Config};
|
|
use userutils::create_user_dir;
|
|
|
|
const _MAN_PAGE: &'static str = /* @MANSTART{useradd} */ r#"
|
|
NAME
|
|
useradd - add a new user
|
|
|
|
SYNOPSYS
|
|
useradd [ options ] LOGIN
|
|
useradd [ -h | --help ]
|
|
|
|
DESCRIPTION
|
|
The useradd utility creates a new user based on
|
|
system defaults and values passed on the command line.
|
|
|
|
Useradd creates a new group for the user by default and
|
|
can also be instructed to create the user's home directory.
|
|
|
|
Note that useradd creates a new user with the password
|
|
unset (no login). This is better documented with the
|
|
redox_users crate.
|
|
|
|
OPTIONS
|
|
-h, --help
|
|
Display this help and exit.
|
|
|
|
-c, --comment
|
|
Any text string, usually used as the user's full name.
|
|
Historically known as the GECOS field
|
|
|
|
-d, --home-dir HOME_DIR
|
|
The new user will be created with HOME_DIR as their home
|
|
directory. The default value is LOGIN prepended with "/home/".
|
|
This flag DOES NOT create the home directory. See --create-home
|
|
|
|
-g, --gid GID
|
|
The group id to use when creating the default login group. This value
|
|
must not be in use and must be non-negative. The default is to pick the
|
|
smallest available group id between values defined in redox_users.
|
|
|
|
-m, --create-home
|
|
Creates the user's home directory if it does not already exist.
|
|
|
|
This option is not enabled by default. This option must be specified
|
|
for a home directory to be created. If not set, the user's home dir is
|
|
set to "/"
|
|
|
|
-N, --no-user-group
|
|
Do not attempt to create the user's user group. Instead, the groupid
|
|
is set to 99 ("nobody"). -N and -g are mutually exclusive.
|
|
|
|
-s, --shell SHELL
|
|
The path to the user's default login shell. If not specified, the
|
|
default shell is set as "/bin/ion"
|
|
|
|
-u, --uid UID
|
|
The user id to use. This value must not be in use and must be
|
|
non-negative. The default is to pick the smallest available
|
|
user id between the defaults defined in redox_users
|
|
|
|
AUTHORS
|
|
Written by Wesley Hershberger.
|
|
"#; /* @MANEND */
|
|
const DEFAULT_SHELL: &'static str = "file:/bin/ion";
|
|
const DEFAULT_HOME: &'static str = "file:/home";
|
|
const DEFAULT_NO_GROUP: &'static str = "nobody";
|
|
|
|
fn main() {
|
|
let args = clap_app!(useradd =>
|
|
(author: "Wesley Hershberger")
|
|
(about: "Add users based on the system's redox_users backend")
|
|
(@arg LOGIN:
|
|
+required
|
|
"Add user LOGIN")
|
|
(@arg COMMENT:
|
|
-c --comment
|
|
+takes_value
|
|
"Set user description (GECOS field)")
|
|
(@arg HOME_DIR:
|
|
-d --("home-dir")
|
|
+takes_value
|
|
"Set LOGIN's home dir to HOME_DIR (does not create directory)")
|
|
(@arg CREATE_HOME:
|
|
-m --("create-home")
|
|
"Create the user's home directory")
|
|
(@arg SHELL:
|
|
-s --shell
|
|
+takes_value
|
|
"Set user's default login shell")
|
|
(@arg GID:
|
|
-g --gid
|
|
+takes_value
|
|
"Set LOGIN's primary group id. Positive integer and must not be in use.")
|
|
(@arg NO_USER_GROUP:
|
|
-N --("no-user-group")
|
|
conflicts_with[GID]
|
|
"Do not create primary user group (set gid to 99, \"nobody\")")
|
|
(@arg UID:
|
|
-u --uid
|
|
+takes_value
|
|
"Set LOGIN's user id. Positive ineger and must not be in use.")
|
|
).get_matches();
|
|
|
|
// unwrap is safe because of "+required". clap-rs is cool...
|
|
let login = args.value_of("LOGIN").unwrap();
|
|
|
|
let mut sys_users = AllUsers::new(Config::with_auth()).unwrap_or_exit(1);
|
|
let mut sys_groups = AllGroups::new(Config::default()).unwrap_or_exit(1);
|
|
|
|
let uid = match args.value_of("UID") {
|
|
Some(uid) => {
|
|
let id = uid.parse::<usize>().unwrap_or_exit(1);
|
|
if let Some(_user) = sys_users.get_by_id(id) {
|
|
eprintln!("useradd: userid already in use: {}", id);
|
|
exit(1);
|
|
}
|
|
id
|
|
},
|
|
None => sys_users
|
|
.get_unique_id()
|
|
.unwrap_or_else(|| {
|
|
eprintln!("useradd: no available uid");
|
|
exit(1);
|
|
})
|
|
};
|
|
|
|
let gid = if args.is_present("NO_USER_GROUP") {
|
|
let nobody = sys_groups
|
|
.get_mut_by_name(DEFAULT_NO_GROUP)
|
|
.unwrap_or_else(|| {
|
|
eprintln!("useradd: group not found: {}", DEFAULT_NO_GROUP);
|
|
exit(1)
|
|
});
|
|
nobody.users.push(login.to_string());
|
|
99
|
|
} else {
|
|
let id = match args.value_of("GID") {
|
|
Some(id) => {
|
|
let id = id.parse::<usize>().unwrap_or_exit(1);
|
|
if let Some(_group) = sys_groups.get_by_id(id) {
|
|
eprintln!("useradd: group already exists with gid: {}", id);
|
|
exit(1);
|
|
}
|
|
id
|
|
},
|
|
None => sys_groups
|
|
.get_unique_id()
|
|
.unwrap_or_else(|| {
|
|
eprintln!("useradd: no available gid");
|
|
exit(1);
|
|
})
|
|
};
|
|
sys_groups
|
|
.add_group(login, id, &[login])
|
|
.unwrap_or_else(|err| {
|
|
eprintln!("useradd: {}: {}", err, login);
|
|
exit(1);
|
|
});
|
|
id
|
|
};
|
|
|
|
let gecos = args
|
|
.value_of("COMMENT")
|
|
.unwrap_or(login);
|
|
|
|
//Ugly way to satisfy the borrow checker...
|
|
let mut sys_homes = String::from(DEFAULT_HOME);
|
|
let userhome = args
|
|
.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 {
|
|
"/"
|
|
}
|
|
});
|
|
|
|
let shell = args
|
|
.value_of("SHELL")
|
|
.unwrap_or(DEFAULT_SHELL);
|
|
|
|
sys_users
|
|
.add_user(login, uid, gid, gecos, userhome, shell)
|
|
.unwrap_or_else(|err| {
|
|
eprintln!("useradd: {}: {}", err, login);
|
|
exit(1);
|
|
});
|
|
|
|
// Make sure to try and create the user/groups before we create
|
|
// their home, that way we get a permissions error that makes
|
|
// more sense
|
|
sys_groups.save().unwrap_or_exit(1);
|
|
sys_users.save().unwrap_or_exit(1);
|
|
|
|
if args.is_present("CREATE_HOME") {
|
|
//Shouldn't ever error...
|
|
let user = sys_users.get_by_id(uid).unwrap_or_exit(1);
|
|
create_user_dir(user, userhome).unwrap_or_exit(1);
|
|
}
|
|
}
|