| author | |
| committer | |
| log | fd2d502e411c45828ebdf1008c5060db8749ef31 |
| tree | a116b0e692198f52396e426393a9311c8652c221 |
| parent | cba4a9ad4a149766c650e3f3d71435cef14867a3 |
4 files changed, 95 insertions(+), 10 deletions(-)
std/os/child_process.zig+12-2| ... | ... | @@ -40,6 +40,9 @@ pub const ChildProcess = struct { |
| 40 | 40 | /// Set to change the user id when spawning the child process. |
| 41 | 41 | pub uid: ?u32, |
| 42 | 42 | |
| 43 | /// Set to change the group id when spawning the child process. | |
| 44 | pub gid: ?u32, | |
| 45 | ||
| 43 | 46 | /// Set to change the current working directory when spawning the child process. |
| 44 | 47 | pub cwd: ?[]const u8, |
| 45 | 48 | |
| ... | ... | @@ -77,6 +80,7 @@ pub const ChildProcess = struct { |
| 77 | 80 | .env_map = null, |
| 78 | 81 | .cwd = null, |
| 79 | 82 | .uid = null, |
| 83 | .gid = null, | |
| 80 | 84 | .stdin = null, |
| 81 | 85 | .stdout = null, |
| 82 | 86 | .stderr = null, |
| ... | ... | @@ -89,7 +93,9 @@ pub const ChildProcess = struct { |
| 89 | 93 | } |
| 90 | 94 | |
| 91 | 95 | pub fn setUserName(self: &ChildProcess, name: []const u8) -> %void { |
| 92 | self.uid = %return os.getUserId(name); | |
| 96 | const user_info = %return os.getUserInfo(name); | |
| 97 | self.uid = user_info.uid; | |
| 98 | self.gid = user_info.gid; | |
| 93 | 99 | } |
| 94 | 100 | |
| 95 | 101 | /// onTerm can be called before `spawn` returns. |
| ... | ... | @@ -294,7 +300,11 @@ pub const ChildProcess = struct { |
| 294 | 300 | } |
| 295 | 301 | |
| 296 | 302 | if (self.uid) |uid| { |
| 297 | os.posix_setuid(uid) %% |err| forkChildErrReport(err_pipe[1], err); | |
| 303 | os.posix_setreuid(uid, uid) %% |err| forkChildErrReport(err_pipe[1], err); | |
| 304 | } | |
| 305 | ||
| 306 | if (self.gid) |gid| { | |
| 307 | os.posix_setregid(gid, gid) %% |err| forkChildErrReport(err_pipe[1], err); | |
| 298 | 308 | } |
| 299 | 309 | |
| 300 | 310 | os.posixExecve(self.argv, env_map, self.allocator) %% |
std/os/get_user_id.zig+36-7| ... | ... | @@ -3,10 +3,15 @@ const Os = builtin.Os; |
| 3 | 3 | const os = @import("index.zig"); |
| 4 | 4 | const io = @import("../io.zig"); |
| 5 | 5 | |
| 6 | pub const UserInfo = struct { | |
| 7 | uid: u32, | |
| 8 | gid: u32, | |
| 9 | }; | |
| 10 | ||
| 6 | 11 | /// POSIX function which gets a uid from username. |
| 7 | pub fn getUserId(name: []const u8) -> %u32 { | |
| 12 | pub fn getUserInfo(name: []const u8) -> %UserInfo { | |
| 8 | 13 | return switch (builtin.os) { |
| 9 | Os.linux, Os.darwin, Os.macosx, Os.ios => posixGetUserId(name), | |
| 14 | Os.linux, Os.darwin, Os.macosx, Os.ios => posixGetUserInfo(name), | |
| 10 | 15 | else => @compileError("Unsupported OS"), |
| 11 | 16 | }; |
| 12 | 17 | } |
| ... | ... | @@ -15,13 +20,17 @@ const State = enum { |
| 15 | 20 | Start, |
| 16 | 21 | WaitForNextLine, |
| 17 | 22 | SkipPassword, |
| 18 | ReadId, | |
| 23 | ReadUserId, | |
| 24 | ReadGroupId, | |
| 19 | 25 | }; |
| 20 | 26 | |
| 21 | 27 | error UserNotFound; |
| 22 | 28 | error CorruptPasswordFile; |
| 23 | 29 | |
| 24 | pub fn posixGetUserId(name: []const u8) -> %u32 { | |
| 30 | // TODO this reads /etc/passwd. But sometimes the user/id mapping is in something else | |
| 31 | // like NIS, AD, etc. See `man nss` or look at an strace for `id myuser`. | |
| 32 | ||
| 33 | pub fn posixGetUserInfo(name: []const u8) -> %UserInfo { | |
| 25 | 34 | var in_stream = %return io.InStream.open("/etc/passwd", null); |
| 26 | 35 | defer in_stream.close(); |
| 27 | 36 | |
| ... | ... | @@ -29,6 +38,7 @@ pub fn posixGetUserId(name: []const u8) -> %u32 { |
| 29 | 38 | var name_index: usize = 0; |
| 30 | 39 | var state = State.Start; |
| 31 | 40 | var uid: u32 = 0; |
| 41 | var gid: u32 = 0; | |
| 32 | 42 | |
| 33 | 43 | while (true) { |
| 34 | 44 | const amt_read = %return in_stream.read(buf[0..]); |
| ... | ... | @@ -56,12 +66,15 @@ pub fn posixGetUserId(name: []const u8) -> %u32 { |
| 56 | 66 | State.SkipPassword => switch (byte) { |
| 57 | 67 | '\n' => return error.CorruptPasswordFile, |
| 58 | 68 | ':' => { |
| 59 | state = State.ReadId; | |
| 69 | state = State.ReadUserId; | |
| 60 | 70 | }, |
| 61 | 71 | else => continue, |
| 62 | 72 | }, |
| 63 | State.ReadId => switch (byte) { | |
| 64 | '\n', ':' => return uid, | |
| 73 | State.ReadUserId => switch (byte) { | |
| 74 | ':' => { | |
| 75 | state = State.ReadGroupId; | |
| 76 | }, | |
| 77 | '\n' => return error.CorruptPasswordFile, | |
| 65 | 78 | else => { |
| 66 | 79 | const digit = switch (byte) { |
| 67 | 80 | '0' ... '9' => byte - '0', |
| ... | ... | @@ -71,6 +84,22 @@ pub fn posixGetUserId(name: []const u8) -> %u32 { |
| 71 | 84 | if (@addWithOverflow(u32, uid, digit, &uid)) return error.CorruptPasswordFile; |
| 72 | 85 | }, |
| 73 | 86 | }, |
| 87 | State.ReadGroupId => switch (byte) { | |
| 88 | '\n', ':' => { | |
| 89 | return UserInfo { | |
| 90 | .uid = uid, | |
| 91 | .gid = gid, | |
| 92 | }; | |
| 93 | }, | |
| 94 | else => { | |
| 95 | const digit = switch (byte) { | |
| 96 | '0' ... '9' => byte - '0', | |
| 97 | else => return error.CorruptPasswordFile, | |
| 98 | }; | |
| 99 | if (@mulWithOverflow(u32, gid, 10, &gid)) return error.CorruptPasswordFile; | |
| 100 | if (@addWithOverflow(u32, gid, digit, &gid)) return error.CorruptPasswordFile; | |
| 101 | }, | |
| 102 | }, | |
| 74 | 103 | } |
| 75 | 104 | } |
| 76 | 105 | if (amt_read < buf.len) return error.UserNotFound; |
std/os/index.zig+35-1| ... | ... | @@ -20,7 +20,8 @@ pub const line_sep = switch (builtin.os) { |
| 20 | 20 | |
| 21 | 21 | pub const page_size = 4 * 1024; |
| 22 | 22 | |
| 23 | pub const getUserId = @import("get_user_id.zig").getUserId; | |
| 23 | pub const UserInfo = @import("get_user_id.zig").UserInfo; | |
| 24 | pub const getUserInfo = @import("get_user_id.zig").getUserInfo; | |
| 24 | 25 | |
| 25 | 26 | const debug = @import("../debug.zig"); |
| 26 | 27 | const assert = debug.assert; |
| ... | ... | @@ -999,3 +1000,36 @@ pub fn posix_setuid(uid: u32) -> %void { |
| 999 | 1000 | else => error.Unexpected, |
| 1000 | 1001 | }; |
| 1001 | 1002 | } |
| 1003 | ||
| 1004 | pub fn posix_setreuid(ruid: u32, euid: u32) -> %void { | |
| 1005 | const err = posix.getErrno(posix.setreuid(ruid, euid)); | |
| 1006 | if (err == 0) return; | |
| 1007 | return switch (err) { | |
| 1008 | posix.EAGAIN => error.ResourceLimitReached, | |
| 1009 | posix.EINVAL => error.InvalidUserId, | |
| 1010 | posix.EPERM => error.PermissionDenied, | |
| 1011 | else => error.Unexpected, | |
| 1012 | }; | |
| 1013 | } | |
| 1014 | ||
| 1015 | pub fn posix_setgid(gid: u32) -> %void { | |
| 1016 | const err = posix.getErrno(posix.setgid(gid)); | |
| 1017 | if (err == 0) return; | |
| 1018 | return switch (err) { | |
| 1019 | posix.EAGAIN => error.ResourceLimitReached, | |
| 1020 | posix.EINVAL => error.InvalidUserId, | |
| 1021 | posix.EPERM => error.PermissionDenied, | |
| 1022 | else => error.Unexpected, | |
| 1023 | }; | |
| 1024 | } | |
| 1025 | ||
| 1026 | pub fn posix_setregid(rgid: u32, egid: u32) -> %void { | |
| 1027 | const err = posix.getErrno(posix.setregid(rgid, egid)); | |
| 1028 | if (err == 0) return; | |
| 1029 | return switch (err) { | |
| 1030 | posix.EAGAIN => error.ResourceLimitReached, | |
| 1031 | posix.EINVAL => error.InvalidUserId, | |
| 1032 | posix.EPERM => error.PermissionDenied, | |
| 1033 | else => error.Unexpected, | |
| 1034 | }; | |
| 1035 | } |
std/os/linux.zig+12| ... | ... | @@ -484,6 +484,18 @@ pub fn setuid(uid: u32) -> usize { |
| 484 | 484 | arch.syscall1(arch.SYS_setuid, uid) |
| 485 | 485 | } |
| 486 | 486 | |
| 487 | pub fn setgid(gid: u32) -> usize { | |
| 488 | arch.syscall1(arch.SYS_setgid, gid) | |
| 489 | } | |
| 490 | ||
| 491 | pub fn setreuid(ruid: u32, euid: u32) -> usize { | |
| 492 | arch.syscall2(arch.SYS_setreuid, ruid, euid) | |
| 493 | } | |
| 494 | ||
| 495 | pub fn setregid(rgid: u32, egid: u32) -> usize { | |
| 496 | arch.syscall2(arch.SYS_setregid, rgid, egid) | |
| 497 | } | |
| 498 | ||
| 487 | 499 | pub fn sigprocmask(flags: u32, noalias set: &const sigset_t, noalias oldset: ?&sigset_t) -> usize { |
| 488 | 500 | arch.syscall4(arch.SYS_rt_sigprocmask, flags, @ptrToInt(set), @ptrToInt(oldset), NSIG/8) |
| 489 | 501 | } |