std.os.ChildProcess: ability to set both uid and gid
parent
cba4a9ad4a
commit
fd2d502e41
|
@ -40,6 +40,9 @@ pub const ChildProcess = struct {
|
|||
/// Set to change the user id when spawning the child process.
|
||||
pub uid: ?u32,
|
||||
|
||||
/// Set to change the group id when spawning the child process.
|
||||
pub gid: ?u32,
|
||||
|
||||
/// Set to change the current working directory when spawning the child process.
|
||||
pub cwd: ?[]const u8,
|
||||
|
||||
|
@ -77,6 +80,7 @@ pub const ChildProcess = struct {
|
|||
.env_map = null,
|
||||
.cwd = null,
|
||||
.uid = null,
|
||||
.gid = null,
|
||||
.stdin = null,
|
||||
.stdout = null,
|
||||
.stderr = null,
|
||||
|
@ -89,7 +93,9 @@ pub const ChildProcess = struct {
|
|||
}
|
||||
|
||||
pub fn setUserName(self: &ChildProcess, name: []const u8) -> %void {
|
||||
self.uid = %return os.getUserId(name);
|
||||
const user_info = %return os.getUserInfo(name);
|
||||
self.uid = user_info.uid;
|
||||
self.gid = user_info.gid;
|
||||
}
|
||||
|
||||
/// onTerm can be called before `spawn` returns.
|
||||
|
@ -294,7 +300,11 @@ pub const ChildProcess = struct {
|
|||
}
|
||||
|
||||
if (self.uid) |uid| {
|
||||
os.posix_setuid(uid) %% |err| forkChildErrReport(err_pipe[1], err);
|
||||
os.posix_setreuid(uid, uid) %% |err| forkChildErrReport(err_pipe[1], err);
|
||||
}
|
||||
|
||||
if (self.gid) |gid| {
|
||||
os.posix_setregid(gid, gid) %% |err| forkChildErrReport(err_pipe[1], err);
|
||||
}
|
||||
|
||||
os.posixExecve(self.argv, env_map, self.allocator) %%
|
||||
|
|
|
@ -3,10 +3,15 @@ const Os = builtin.Os;
|
|||
const os = @import("index.zig");
|
||||
const io = @import("../io.zig");
|
||||
|
||||
pub const UserInfo = struct {
|
||||
uid: u32,
|
||||
gid: u32,
|
||||
};
|
||||
|
||||
/// POSIX function which gets a uid from username.
|
||||
pub fn getUserId(name: []const u8) -> %u32 {
|
||||
pub fn getUserInfo(name: []const u8) -> %UserInfo {
|
||||
return switch (builtin.os) {
|
||||
Os.linux, Os.darwin, Os.macosx, Os.ios => posixGetUserId(name),
|
||||
Os.linux, Os.darwin, Os.macosx, Os.ios => posixGetUserInfo(name),
|
||||
else => @compileError("Unsupported OS"),
|
||||
};
|
||||
}
|
||||
|
@ -15,13 +20,17 @@ const State = enum {
|
|||
Start,
|
||||
WaitForNextLine,
|
||||
SkipPassword,
|
||||
ReadId,
|
||||
ReadUserId,
|
||||
ReadGroupId,
|
||||
};
|
||||
|
||||
error UserNotFound;
|
||||
error CorruptPasswordFile;
|
||||
|
||||
pub fn posixGetUserId(name: []const u8) -> %u32 {
|
||||
// TODO this reads /etc/passwd. But sometimes the user/id mapping is in something else
|
||||
// like NIS, AD, etc. See `man nss` or look at an strace for `id myuser`.
|
||||
|
||||
pub fn posixGetUserInfo(name: []const u8) -> %UserInfo {
|
||||
var in_stream = %return io.InStream.open("/etc/passwd", null);
|
||||
defer in_stream.close();
|
||||
|
||||
|
@ -29,6 +38,7 @@ pub fn posixGetUserId(name: []const u8) -> %u32 {
|
|||
var name_index: usize = 0;
|
||||
var state = State.Start;
|
||||
var uid: u32 = 0;
|
||||
var gid: u32 = 0;
|
||||
|
||||
while (true) {
|
||||
const amt_read = %return in_stream.read(buf[0..]);
|
||||
|
@ -56,12 +66,15 @@ pub fn posixGetUserId(name: []const u8) -> %u32 {
|
|||
State.SkipPassword => switch (byte) {
|
||||
'\n' => return error.CorruptPasswordFile,
|
||||
':' => {
|
||||
state = State.ReadId;
|
||||
state = State.ReadUserId;
|
||||
},
|
||||
else => continue,
|
||||
},
|
||||
State.ReadId => switch (byte) {
|
||||
'\n', ':' => return uid,
|
||||
State.ReadUserId => switch (byte) {
|
||||
':' => {
|
||||
state = State.ReadGroupId;
|
||||
},
|
||||
'\n' => return error.CorruptPasswordFile,
|
||||
else => {
|
||||
const digit = switch (byte) {
|
||||
'0' ... '9' => byte - '0',
|
||||
|
@ -71,6 +84,22 @@ pub fn posixGetUserId(name: []const u8) -> %u32 {
|
|||
if (@addWithOverflow(u32, uid, digit, &uid)) return error.CorruptPasswordFile;
|
||||
},
|
||||
},
|
||||
State.ReadGroupId => switch (byte) {
|
||||
'\n', ':' => {
|
||||
return UserInfo {
|
||||
.uid = uid,
|
||||
.gid = gid,
|
||||
};
|
||||
},
|
||||
else => {
|
||||
const digit = switch (byte) {
|
||||
'0' ... '9' => byte - '0',
|
||||
else => return error.CorruptPasswordFile,
|
||||
};
|
||||
if (@mulWithOverflow(u32, gid, 10, &gid)) return error.CorruptPasswordFile;
|
||||
if (@addWithOverflow(u32, gid, digit, &gid)) return error.CorruptPasswordFile;
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
if (amt_read < buf.len) return error.UserNotFound;
|
||||
|
|
|
@ -20,7 +20,8 @@ pub const line_sep = switch (builtin.os) {
|
|||
|
||||
pub const page_size = 4 * 1024;
|
||||
|
||||
pub const getUserId = @import("get_user_id.zig").getUserId;
|
||||
pub const UserInfo = @import("get_user_id.zig").UserInfo;
|
||||
pub const getUserInfo = @import("get_user_id.zig").getUserInfo;
|
||||
|
||||
const debug = @import("../debug.zig");
|
||||
const assert = debug.assert;
|
||||
|
@ -999,3 +1000,36 @@ pub fn posix_setuid(uid: u32) -> %void {
|
|||
else => error.Unexpected,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn posix_setreuid(ruid: u32, euid: u32) -> %void {
|
||||
const err = posix.getErrno(posix.setreuid(ruid, euid));
|
||||
if (err == 0) return;
|
||||
return switch (err) {
|
||||
posix.EAGAIN => error.ResourceLimitReached,
|
||||
posix.EINVAL => error.InvalidUserId,
|
||||
posix.EPERM => error.PermissionDenied,
|
||||
else => error.Unexpected,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn posix_setgid(gid: u32) -> %void {
|
||||
const err = posix.getErrno(posix.setgid(gid));
|
||||
if (err == 0) return;
|
||||
return switch (err) {
|
||||
posix.EAGAIN => error.ResourceLimitReached,
|
||||
posix.EINVAL => error.InvalidUserId,
|
||||
posix.EPERM => error.PermissionDenied,
|
||||
else => error.Unexpected,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn posix_setregid(rgid: u32, egid: u32) -> %void {
|
||||
const err = posix.getErrno(posix.setregid(rgid, egid));
|
||||
if (err == 0) return;
|
||||
return switch (err) {
|
||||
posix.EAGAIN => error.ResourceLimitReached,
|
||||
posix.EINVAL => error.InvalidUserId,
|
||||
posix.EPERM => error.PermissionDenied,
|
||||
else => error.Unexpected,
|
||||
};
|
||||
}
|
||||
|
|
|
@ -484,6 +484,18 @@ pub fn setuid(uid: u32) -> usize {
|
|||
arch.syscall1(arch.SYS_setuid, uid)
|
||||
}
|
||||
|
||||
pub fn setgid(gid: u32) -> usize {
|
||||
arch.syscall1(arch.SYS_setgid, gid)
|
||||
}
|
||||
|
||||
pub fn setreuid(ruid: u32, euid: u32) -> usize {
|
||||
arch.syscall2(arch.SYS_setreuid, ruid, euid)
|
||||
}
|
||||
|
||||
pub fn setregid(rgid: u32, egid: u32) -> usize {
|
||||
arch.syscall2(arch.SYS_setregid, rgid, egid)
|
||||
}
|
||||
|
||||
pub fn sigprocmask(flags: u32, noalias set: &const sigset_t, noalias oldset: ?&sigset_t) -> usize {
|
||||
arch.syscall4(arch.SYS_rt_sigprocmask, flags, @ptrToInt(set), @ptrToInt(oldset), NSIG/8)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue