~goorzhel/radm

ref: d1c1a9803da1394d729503da1063f3495dd25854 radm/src/system.rs -rw-r--r-- 2.4 KiB
d1c1a980 — Antonio Gurgel Replace macro_use with uses 4 months ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
//! Low-level interfaces.
//!
//! These functions aren't associated with [User](crate::user::User), to emphasize that they
//! run while `rstdm` still has root privileges.

use std::{
    env::{set_var, var, VarError},
    ffi::{CString, OsStr},
    fmt::Display,
    fs::{create_dir_all, set_permissions, Permissions},
    os::unix::prelude::PermissionsExt,
    path::{Path, PathBuf},
};

use anyhow::{Context, Result};
use log::{debug, warn};
use nix::unistd::{chdir, chown, getgrouplist, setgid, setgroups, setuid};

use crate::user::User;

/// Sets `rstdm`'s privileges and working directory to those of the authenticated user.
pub fn drop_privileges(user: &User) -> Result<()> {
    let username = CString::new(user.name.clone())?;
    let uid = user.uid;
    let gid = user.gid;

    let gids = getgrouplist(&username, gid).context("Couldn't getgroups()")?;
    setgroups(&gids).context("Couldn't setgroups()")?;
    setgid(gid).context("Couldn't setgid()")?;
    setuid(uid).context("Couldn't setuid()")?;
    chdir(Path::new(&user.dir)).context("Couldn't chdir() to homedir")?;
    Ok(())
}

/// Reads environment variable `$XDG_RUNTIME_DIR` and ensures a directory with
/// the correct perms exists at the path.
///
/// Requires root.
pub fn prepare_xdg_runtime(user: &User) -> Result<()> {
    let uid = user.uid;
    let gid = user.gid;

    let path: PathBuf = var("XDG_RUNTIME_DIR").unwrap().into();
    // unwrap: $XDG_RUNTIME_DIR should already be set by User::load_environment.
    create_dir_all(&path).context("Couldn't create XDG_RUNTIME_DIR")?;
    chown(&path, Some(uid), Some(gid)).context("Couldn't chown XDG_RUNTIME_DIR")?;
    set_permissions(&path, Permissions::from_mode(0o700))
        .context("Couldn't chmod XDG_RUNTIME_DIR")?;
    Ok(())
}

/// Reads an environment variable; if unset, sets it to the given default.
pub fn env_var_or_set_default<K: AsRef<OsStr> + Display, D: AsRef<OsStr> + Display>(
    key: K,
    default: D,
) -> String {
    match var(&key) {
        Ok(v) => v,
        Err(e) => {
            match e {
                VarError::NotPresent => debug!("Defaulting {} to {}", &key, default),
                VarError::NotUnicode(_) => warn!(
                    "Found value for {} but it wasn't valid Unicode; defaulting to {}",
                    &key, default
                ),
            }
            set_var(key, &default);
            default.to_string()
        }
    }
}