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
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
use errors::*;
use libc;
use nix::unistd;
use std::path::{Path, PathBuf};
#[derive(Default)]
pub struct PrivDrop {
chroot: Option<PathBuf>,
user: Option<String>,
group: Option<String>,
}
impl PrivDrop {
pub fn chroot<T: AsRef<Path>>(mut self, path: T) -> Self {
self.chroot = Some(path.as_ref().to_owned());
self
}
pub fn user<T: AsRef<str>>(mut self, user: T) -> Self {
self.user = Some(user.as_ref().to_owned());
self
}
pub fn group<T: AsRef<str>>(mut self, group: T) -> Self {
self.group = Some(group.as_ref().to_owned());
self
}
pub fn apply(self) -> Result<(), PrivDropError> {
try!(self.do_preload());
try!(self.do_chroot());
try!(self.do_userchange());
Ok(())
}
fn do_preload(&self) -> Result<(), PrivDropError> {
unsafe {
libc::strerror(1);
libc::setlocale(libc::LC_CTYPE, "C".as_ptr() as *const i8);
libc::setlocale(libc::LC_COLLATE, "C".as_ptr() as *const i8);
let mut now: libc::time_t = 0;
libc::time(&mut now);
libc::localtime(&now);
}
Ok(())
}
fn do_chroot(&self) -> Result<(), PrivDropError> {
if let Some(ref chroot) = self.chroot {
try!(unistd::chdir(chroot));
try!(unistd::chroot(chroot));
try!(unistd::chdir("/"))
}
Ok(())
}
fn do_userchange(&self) -> Result<(), PrivDropError> {
if let Some(ref user) = self.user {
let pwent = unsafe { libc::getpwnam(user.as_ptr() as *const i8) };
if pwent.is_null() {
return Err(PrivDropError::from((ErrorKind::SysError, "User not found")));
}
let (uid, gid) = (unsafe { *pwent }.pw_uid, unsafe { *pwent }.pw_gid);
let gid = if let Some(ref group) = self.group {
let grent = unsafe { libc::getgrnam(group.as_ptr() as *const i8) };
if grent.is_null() {
return Err(PrivDropError::from((ErrorKind::SysError, "Group not found")));
}
unsafe { *grent }.gr_gid
} else {
gid
};
if unsafe { libc::setgroups(1, &gid) } != 0 {
return Err(PrivDropError::from((ErrorKind::SysError,
"Unable to revoke supplementary groups")));
}
try!(unistd::setgid(gid));
try!(unistd::setuid(uid));
}
Ok(())
}
}