diff options
| author | Andrew Kelley <superjoe30@gmail.com> | 2017-09-26 02:42:06 -0400 |
|---|---|---|
| committer | Andrew Kelley <superjoe30@gmail.com> | 2017-09-26 02:42:06 -0400 |
| commit | fd2d502e411c45828ebdf1008c5060db8749ef31 (patch) | |
| tree | a116b0e692198f52396e426393a9311c8652c221 /std | |
| parent | cba4a9ad4a149766c650e3f3d71435cef14867a3 (diff) | |
| download | zig-fd2d502e411c45828ebdf1008c5060db8749ef31.tar.gz zig-fd2d502e411c45828ebdf1008c5060db8749ef31.zip | |
std.os.ChildProcess: ability to set both uid and gid
Diffstat (limited to 'std')
| -rw-r--r-- | std/os/child_process.zig | 14 | ||||
| -rw-r--r-- | std/os/get_user_id.zig | 43 | ||||
| -rw-r--r-- | std/os/index.zig | 36 | ||||
| -rw-r--r-- | std/os/linux.zig | 12 |
4 files changed, 95 insertions, 10 deletions
diff --git a/std/os/child_process.zig b/std/os/child_process.zig index 73bf8463eb..7a4b508cfc 100644 --- a/std/os/child_process.zig +++ b/std/os/child_process.zig @@ -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) %% diff --git a/std/os/get_user_id.zig b/std/os/get_user_id.zig index a5a9fe8308..07974fbe09 100644 --- a/std/os/get_user_id.zig +++ b/std/os/get_user_id.zig @@ -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; diff --git a/std/os/index.zig b/std/os/index.zig index 5b47becf54..ccd7527975 100644 --- a/std/os/index.zig +++ b/std/os/index.zig @@ -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, + }; +} diff --git a/std/os/linux.zig b/std/os/linux.zig index 16a368ffbe..dea89be1fd 100644 --- a/std/os/linux.zig +++ b/std/os/linux.zig @@ -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) } |
