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
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
|
use std::{
ffi::{OsStr, OsString},
fs::File,
io::{self, BufRead, Result},
os::unix::ffi::*,
path::Path,
process,
};
use nix::unistd;
// use crate::prepared_command::PreparedCommand;
use crate::util::Checkable;
#[derive(Debug, Eq, Ord, PartialEq, PartialOrd)]
struct SubIDRange {
start: libc::uid_t,
count: libc::uid_t,
}
fn parse_uid(s: &OsStr) -> Option<libc::uid_t> {
s.to_str().and_then(|s| s.parse().ok())
}
fn parse_id_range(line: Vec<u8>, uid: &OsStr, username: Option<&OsStr>) -> Option<SubIDRange> {
let parts: Vec<_> = line.split(|c| *c == b':').map(OsStr::from_bytes).collect();
if parts.len() != 3 {
return None;
}
if parts[0] != uid && Some(parts[0]) != username {
return None;
}
let start = parse_uid(parts[1])?;
let count = parse_uid(parts[2])?;
Some(SubIDRange { start, count })
}
fn read_id_ranges(filename: &Path) -> Result<Vec<SubIDRange>> {
let uid = users::get_effective_uid();
let username = users::get_user_by_uid(uid).map(|user| user.name().to_os_string());
let uidstr = OsString::from(uid.to_string());
let usernamestr = username.as_ref().map(OsString::as_os_str);
let file = File::open(filename)?;
let lines = io::BufReader::new(file).split(b'\n');
lines
.map(|line| Ok(parse_id_range(line?, &uidstr, usernamestr)))
.filter_map(Result::transpose)
.collect()
}
#[derive(Debug)]
struct SubIDMap {
lower: libc::uid_t,
upper: libc::uid_t,
count: libc::uid_t,
}
fn generate_idmap(id: libc::uid_t, mut ranges: Vec<SubIDRange>) -> Vec<SubIDMap> {
let mut map = Vec::new();
map.push(SubIDMap {
lower: 0,
upper: id,
count: 1,
});
let mut lower = 1;
ranges.sort();
for range in &ranges {
map.push(SubIDMap {
lower,
upper: range.start,
count: range.count,
});
lower += range.count;
}
map
}
fn get_uid_map() -> Result<Vec<SubIDMap>> {
let uid = users::get_effective_uid();
let uid_ranges = read_id_ranges(Path::new("/etc/subuid"))?;
Ok(generate_idmap(uid, uid_ranges))
}
fn get_gid_map() -> Result<Vec<SubIDMap>> {
let gid = users::get_effective_gid();
let gid_ranges = read_id_ranges(Path::new("/etc/subgid"))?;
Ok(generate_idmap(gid, gid_ranges))
}
fn run_idmap_cmd(cmd: &str, pid: &str, map: &Vec<SubIDMap>) -> Result<()> {
let mut builder = process::Command::new(cmd);
builder.arg(pid);
for uids in map {
builder.arg(uids.lower.to_string());
builder.arg(uids.upper.to_string());
builder.arg(uids.count.to_string());
}
builder.status().and_then(|status| status.check())
}
pub fn idmap(pid: unistd::Pid) -> Result<()> {
let pid_string = pid.to_string();
run_idmap_cmd("newuidmap", pid_string.as_str(), &get_uid_map()?)?;
run_idmap_cmd("newgidmap", pid_string.as_str(), &get_gid_map()?)?;
Ok(())
}
|