Skip to content

Simplify sudo check on unix #2183

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jan 5, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 21 additions & 50 deletions src/cli/self_update.rs
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,7 @@ pub fn install(no_prompt: bool, verbose: bool, quiet: bool, mut opts: InstallOpt
do_pre_install_sanity_checks()?;
do_pre_install_options_sanity_checks(&opts)?;
check_existence_of_rustc_or_cargo_in_path(no_prompt)?;
#[cfg(unix)]
do_anti_sudo_check(no_prompt)?;

let mut term = term2::stdout();
Expand Down Expand Up @@ -467,63 +468,33 @@ fn do_pre_install_options_sanity_checks(opts: &InstallOpts) -> Result<()> {
// If the user is trying to install with sudo, on some systems this will
// result in writing root-owned files to the user's home directory, because
// sudo is configured not to change $HOME. Don't let that bogosity happen.
#[allow(dead_code)]
#[cfg(unix)]
fn do_anti_sudo_check(no_prompt: bool) -> Result<()> {
use std::ffi::OsString;

#[cfg(unix)]
pub fn home_mismatch() -> (bool, OsString, String) {
use std::ffi::CStr;
use std::mem::MaybeUninit;
use std::ptr;

pub fn home_mismatch() -> (bool, PathBuf, PathBuf) {
let fallback = || (false, PathBuf::new(), PathBuf::new());
// test runner should set this, nothing else
if let Ok(true) = env::var("RUSTUP_INIT_SKIP_SUDO_CHECK").map(|s| s == "yes") {
return (false, OsString::new(), String::new());
}
let mut buf = [0u8; 1024];
let mut pwd = MaybeUninit::<libc::passwd>::uninit();
let mut pwdp: *mut libc::passwd = ptr::null_mut();
let rv = unsafe {
libc::getpwuid_r(
libc::geteuid(),
pwd.as_mut_ptr(),
buf.as_mut_ptr().cast::<libc::c_char>(),
buf.len(),
(&mut pwdp) as *mut *mut libc::passwd,
)
};
if rv != 0 || pwdp.is_null() {
warn!("getpwuid_r: couldn't get user data");
return (false, OsString::new(), String::new());
if env::var_os("RUSTUP_INIT_SKIP_SUDO_CHECK").map_or(false, |s| s == "yes") {
return fallback();
}
let pwd = unsafe { pwd.assume_init() };
let pw_dir = unsafe { CStr::from_ptr(pwd.pw_dir) }.to_str().ok();
let env_home = env::var_os("HOME");
match (env_home, pw_dir) {
(None, _) | (_, None) => (false, OsString::new(), String::new()),
(Some(eh), Some(pd)) => (eh != pd, eh, String::from(pd)),
}
}

#[cfg(not(unix))]
pub fn home_mismatch() -> (bool, OsString, String) {
(false, OsString::new(), String::new())
match (utils::home_dir_from_passwd(), env::var_os("HOME")) {
(Some(pw), Some(eh)) if eh != pw => return (true, PathBuf::from(eh), pw),
(None, _) => warn!("getpwuid_r: couldn't get user data"),
_ => {}
}
fallback()
}

match (home_mismatch(), no_prompt) {
((false, _, _), _) => (),
((true, env_home, euid_home), false) => {
match home_mismatch() {
(false, _, _) => {}
(true, env_home, euid_home) => {
err!("$HOME differs from euid-obtained home directory: you may be using sudo");
err!("$HOME directory: {:?}", env_home);
err!("euid-obtained home directory: {}", euid_home);
err!("if this is what you want, restart the installation with `-y'");
process::exit(1);
}
((true, env_home, euid_home), true) => {
warn!("$HOME differs from euid-obtained home directory: you may be using sudo");
warn!("$HOME directory: {:?}", env_home);
warn!("euid-obtained home directory: {}", euid_home);
err!("$HOME directory: {}", env_home.display());
err!("euid-obtained home directory: {}", euid_home.display());
if !no_prompt {
err!("if this is what you want, restart the installation with `-y'");
process::exit(1);
}
}
}

Expand Down
33 changes: 33 additions & 0 deletions src/utils/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -670,6 +670,39 @@ impl<'a> io::Read for FileReaderWithProgress<'a> {
}
}

// search user database to get home dir of euid user
#[cfg(unix)]
pub fn home_dir_from_passwd() -> Option<PathBuf> {
use std::ffi::CStr;
use std::mem::MaybeUninit;
use std::os::unix::ffi::OsStringExt;
use std::ptr;
unsafe {
let init_size = match libc::sysconf(libc::_SC_GETPW_R_SIZE_MAX) {
-1 => 1024,
n => n as usize,
};
let mut buf = Vec::with_capacity(init_size);
let mut pwd: MaybeUninit<libc::passwd> = MaybeUninit::uninit();
let mut pwdp = ptr::null_mut();
match libc::getpwuid_r(
libc::geteuid(),
pwd.as_mut_ptr(),
buf.as_mut_ptr(),
buf.capacity(),
&mut pwdp,
) {
0 if !pwdp.is_null() => {
let pwd = pwd.assume_init();
let bytes = CStr::from_ptr(pwd.pw_dir).to_bytes().to_vec();
let pw_dir = OsString::from_vec(bytes);
Some(PathBuf::from(pw_dir))
}
_ => None,
}
}
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down