1use deno_core::OpState;
4use deno_core::op2;
5use deno_core::v8;
6use deno_permissions::PermissionCheckError;
7use deno_permissions::PermissionsContainer;
8#[cfg(unix)]
9use nix::unistd::Gid;
10#[cfg(unix)]
11use nix::unistd::Group;
12#[cfg(unix)]
13use nix::unistd::Uid;
14#[cfg(unix)]
15use nix::unistd::User;
16
17#[derive(Debug, thiserror::Error, deno_error::JsError)]
18pub enum ProcessError {
19 #[class(inherit)]
20 #[error(transparent)]
21 Permission(
22 #[from]
23 #[inherit]
24 PermissionCheckError,
25 ),
26 #[class(generic)]
27 #[error("{0} identifier does not exist: {1}")]
28 #[property("code" = "ERR_UNKNOWN_CREDENTIAL")]
29 UnknownCredential(String, String),
30 #[class(inherit)]
31 #[error(transparent)]
32 Io(#[from] std::io::Error),
33 #[class(generic)]
34 #[error("Operation not supported on this platform")]
35 NotSupported,
36 #[class(type)]
37 #[error("Invalid {0} parameter")]
38 InvalidParam(String),
39}
40
41#[cfg(unix)]
42impl From<nix::Error> for ProcessError {
43 fn from(err: nix::Error) -> Self {
44 ProcessError::Io(std::io::Error::from_raw_os_error(err as i32))
45 }
46}
47
48#[cfg(unix)]
49fn kill(pid: i32, sig: i32) -> i32 {
50 if unsafe { libc::kill(pid, sig) } < 0 {
52 std::io::Error::last_os_error().raw_os_error().unwrap()
53 } else {
54 0
55 }
56}
57
58#[cfg(not(unix))]
59fn kill(pid: i32, _sig: i32) -> i32 {
60 match deno_subprocess_windows::process_kill(pid, _sig) {
61 Ok(_) => 0,
62 Err(e) => e.as_uv_error(),
63 }
64}
65
66#[op2(fast, stack_trace)]
67pub fn op_node_process_kill(
68 state: &mut OpState,
69 #[smi] pid: i32,
70 #[smi] sig: i32,
71) -> Result<i32, deno_permissions::PermissionCheckError> {
72 state
73 .borrow_mut::<PermissionsContainer>()
74 .check_run_all("process.kill")?;
75 Ok(kill(pid, sig))
76}
77
78#[op2(fast)]
79pub fn op_process_abort() {
80 std::process::abort();
81}
82
83#[cfg(not(any(target_os = "android", target_os = "windows")))]
84enum Id {
85 Number(u32),
86 Name(String),
87}
88
89#[cfg(not(any(target_os = "android", target_os = "windows")))]
90fn get_group_id(name: &str) -> Result<Gid, ProcessError> {
91 let group = Group::from_name(name)?;
92
93 if let Some(group) = group {
94 Ok(group.gid)
95 } else {
96 Err(ProcessError::UnknownCredential(
97 "Group".to_string(),
98 name.to_string(),
99 ))
100 }
101}
102
103#[cfg(not(any(target_os = "android", target_os = "windows")))]
104fn serialize_id<'a>(
105 scope: &mut v8::PinScope<'a, '_>,
106 value: v8::Local<'a, v8::Value>,
107) -> Result<Id, ProcessError> {
108 if value.is_number() {
109 let num = value.uint32_value(scope).unwrap();
110 return Ok(Id::Number(num));
111 }
112
113 if value.is_string() {
114 let name = value.to_string(scope).unwrap();
115 return Ok(Id::Name(name.to_rust_string_lossy(scope)));
116 }
117
118 Err(ProcessError::InvalidParam("id".to_string()))
119}
120
121#[cfg(not(any(target_os = "android", target_os = "windows")))]
122#[op2(fast, stack_trace)]
123pub fn op_node_process_setegid<'a>(
124 scope: &mut v8::PinScope<'a, '_>,
125 state: &mut OpState,
126 id: v8::Local<'a, v8::Value>,
127) -> Result<(), ProcessError> {
128 {
129 let permissions = state.borrow_mut::<PermissionsContainer>();
130 permissions.check_sys("setegid", "node:process.setegid")?;
131 }
132
133 let gid = match serialize_id(scope, id)? {
134 Id::Number(number) => Gid::from_raw(number),
135 Id::Name(name) => get_group_id(&name)?,
136 };
137
138 nix::unistd::setegid(gid)?;
139
140 Ok(())
141}
142
143#[cfg(any(target_os = "android", target_os = "windows"))]
144#[op2(fast, stack_trace)]
145pub fn op_node_process_setegid(
146 _scope: &mut v8::PinScope<'_, '_>,
147 _state: &mut OpState,
148 _id: v8::Local<'_, v8::Value>,
149) -> Result<(), ProcessError> {
150 Err(ProcessError::NotSupported)
151}
152
153#[cfg(not(any(target_os = "android", target_os = "windows")))]
154fn get_user_id(name: &str) -> Result<Uid, ProcessError> {
155 let user = User::from_name(name)?;
156
157 if let Some(user) = user {
158 Ok(user.uid)
159 } else {
160 Err(ProcessError::UnknownCredential(
161 "User".to_string(),
162 name.to_string(),
163 ))
164 }
165}
166
167#[cfg(not(any(target_os = "android", target_os = "windows")))]
168#[op2(fast, stack_trace)]
169pub fn op_node_process_seteuid<'a>(
170 scope: &mut v8::PinScope<'a, '_>,
171 state: &mut OpState,
172 id: v8::Local<'a, v8::Value>,
173) -> Result<(), ProcessError> {
174 {
175 let permissions = state.borrow_mut::<PermissionsContainer>();
176 permissions.check_sys("seteuid", "node:process.seteuid")?;
177 }
178
179 let uid = match serialize_id(scope, id)? {
180 Id::Number(number) => Uid::from_raw(number),
181 Id::Name(name) => get_user_id(&name)?,
182 };
183
184 nix::unistd::seteuid(uid)?;
185
186 Ok(())
187}
188
189#[cfg(any(target_os = "android", target_os = "windows"))]
190#[op2(fast, stack_trace)]
191pub fn op_node_process_seteuid(
192 _scope: &mut v8::PinScope<'_, '_>,
193 _state: &mut OpState,
194 _id: v8::Local<'_, v8::Value>,
195) -> Result<(), ProcessError> {
196 Err(ProcessError::NotSupported)
197}
198
199#[cfg(not(any(target_os = "android", target_os = "windows")))]
200#[op2(fast, stack_trace)]
201pub fn op_node_process_setgid<'a>(
202 scope: &mut v8::PinScope<'a, '_>,
203 state: &mut OpState,
204 id: v8::Local<'a, v8::Value>,
205) -> Result<(), ProcessError> {
206 {
207 let permissions = state.borrow_mut::<PermissionsContainer>();
208 permissions.check_sys("setgid", "node:process.setgid")?;
209 }
210
211 let gid = match serialize_id(scope, id)? {
212 Id::Number(number) => Gid::from_raw(number),
213 Id::Name(name) => get_group_id(&name)?,
214 };
215
216 nix::unistd::setgid(gid)?;
217
218 Ok(())
219}
220
221#[cfg(any(target_os = "android", target_os = "windows"))]
222#[op2(fast, stack_trace)]
223pub fn op_node_process_setgid(
224 _scope: &mut v8::PinScope<'_, '_>,
225 _state: &mut OpState,
226 _id: v8::Local<'_, v8::Value>,
227) -> Result<(), ProcessError> {
228 Err(ProcessError::NotSupported)
229}
230
231#[cfg(not(any(target_os = "android", target_os = "windows")))]
232#[op2(fast, stack_trace)]
233pub fn op_node_process_setuid<'a>(
234 scope: &mut v8::PinScope<'a, '_>,
235 state: &mut OpState,
236 id: v8::Local<'a, v8::Value>,
237) -> Result<(), ProcessError> {
238 {
239 let permissions = state.borrow_mut::<PermissionsContainer>();
240 permissions.check_sys("setuid", "node:process.setuid")?;
241 }
242
243 let uid = match serialize_id(scope, id)? {
244 Id::Number(number) => Uid::from_raw(number),
245 Id::Name(name) => get_user_id(&name)?,
246 };
247
248 nix::unistd::setuid(uid)?;
249
250 Ok(())
251}
252
253#[cfg(any(target_os = "android", target_os = "windows"))]
254#[op2(fast, stack_trace)]
255pub fn op_node_process_setuid(
256 _scope: &mut v8::PinScope<'_, '_>,
257 _state: &mut OpState,
258 _id: v8::Local<'_, v8::Value>,
259) -> Result<(), ProcessError> {
260 Err(ProcessError::NotSupported)
261}