-
Notifications
You must be signed in to change notification settings - Fork 1.3k
/
Copy pathsys.rs
149 lines (130 loc) · 4.83 KB
/
sys.rs
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
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
//! System related APIs
/// Some systems set an artificially low soft limit on open file count, for compatibility
/// with code that uses select and its hard-coded maximum file descriptor
/// (limited by the size of fd_set).
///
/// Tokio (Mio) doesn't use select.
///
/// http://0pointer.net/blog/file-descriptor-limits.html
/// https://github.com/golang/go/issues/46279
#[cfg(all(unix, not(target_os = "android")))]
pub fn adjust_nofile() {
use log::{debug, trace};
use std::{io::Error, mem};
unsafe {
let mut lim: libc::rlimit = mem::zeroed();
let ret = libc::getrlimit(libc::RLIMIT_NOFILE, &mut lim);
if ret < 0 {
debug!("getrlimit NOFILE failed, {}", Error::last_os_error());
return;
}
if lim.rlim_cur != lim.rlim_max {
trace!("rlimit NOFILE {:?} require adjustion", lim);
lim.rlim_cur = lim.rlim_max;
// On older macOS, setrlimit with rlim_cur = infinity will fail.
#[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos", target_os = "tvos"))]
{
use std::ptr;
unsafe extern "C" {
fn sysctlbyname(
name: *const libc::c_char,
oldp: *mut libc::c_void,
oldlenp: *mut libc::size_t,
newp: *mut libc::c_void,
newlen: libc::size_t,
) -> libc::c_int;
}
// CTL_KERN
//
// Name Type Changeable
// kern.maxfiles int32_t yes
// kern.maxfilesperproc int32_t yes
let name = b"kern.maxfilesperproc\0";
let mut nfile: i32 = 0;
let mut nfile_len: libc::size_t = mem::size_of_val(&nfile);
let ret = sysctlbyname(
name.as_ptr() as *const _,
&mut nfile as *mut _ as *mut _,
&mut nfile_len,
ptr::null_mut(),
0,
);
if ret < 0 {
debug!("sysctlbyname kern.maxfilesperproc failed, {}", Error::last_os_error());
} else {
lim.rlim_cur = nfile as libc::rlim_t;
}
}
let ret = libc::setrlimit(libc::RLIMIT_NOFILE, &lim);
if ret < 0 {
debug!("setrlimit NOFILE {:?} failed, {}", lim, Error::last_os_error());
} else {
debug!("rlimit NOFILE adjusted {:?}", lim);
}
}
}
}
/// setuid(), setgid() for a specific user or uid
#[cfg(unix)]
pub fn run_as_user(uname: &str) -> std::io::Result<()> {
use log::error;
use std::{
ffi::{CStr, CString},
io::{Error, ErrorKind},
};
unsafe {
let pwd = match uname.parse::<libc::uid_t>() {
Ok(uid) => {
let mut pwd = libc::getpwuid(uid);
if pwd.is_null() {
let uname = CString::new(uname).expect("username");
pwd = libc::getpwnam(uname.as_ptr())
}
pwd
}
Err(..) => {
let uname = CString::new(uname).expect("username");
libc::getpwnam(uname.as_ptr())
}
};
if pwd.is_null() {
return Err(Error::new(ErrorKind::InvalidInput, format!("user {} not found", uname)));
}
let pwd = &*pwd;
// setgid first, because we may not allowed to do it anymore after setuid
if libc::setgid(pwd.pw_gid as libc::gid_t) != 0 {
let err = Error::last_os_error();
error!(
"could not change group id to user {:?}'s gid: {}, uid: {}, error: {}",
CStr::from_ptr(pwd.pw_name),
pwd.pw_gid,
pwd.pw_uid,
err
);
return Err(err);
}
if libc::initgroups(pwd.pw_name, pwd.pw_gid as _) != 0 {
let err = Error::last_os_error();
error!(
"could not change supplementary groups to user {:?}'s gid: {}, uid: {}, error: {}",
CStr::from_ptr(pwd.pw_name),
pwd.pw_gid,
pwd.pw_uid,
err
);
return Err(err);
}
if libc::setuid(pwd.pw_uid) != 0 {
let err = Error::last_os_error();
error!(
"could not change user id to user {:?}'s gid: {}, uid: {}, error: {}",
CStr::from_ptr(pwd.pw_name),
pwd.pw_gid,
pwd.pw_uid,
err
);
return Err(err);
}
}
Ok(())
}