| 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,6 +40,9 @@ pub const ChildProcess = struct { |
| 40 | /// Set to change the user id when spawning the child process. | 40 | /// Set to change the user id when spawning the child process. |
| 41 | pub uid: ?u32, | 41 | pub uid: ?u32, |
| 42 | 42 | ||
| 43 | /// Set to change the group id when spawning the child process. | ||
| 44 | pub gid: ?u32, | ||
| 45 | |||
| 43 | /// Set to change the current working directory when spawning the child process. | 46 | /// Set to change the current working directory when spawning the child process. |
| 44 | pub cwd: ?[]const u8, | 47 | pub cwd: ?[]const u8, |
| 45 | 48 | ||
| ... | @@ -77,6 +80,7 @@ pub const ChildProcess = struct { | ... | @@ -77,6 +80,7 @@ pub const ChildProcess = struct { |
| 77 | .env_map = null, | 80 | .env_map = null, |
| 78 | .cwd = null, | 81 | .cwd = null, |
| 79 | .uid = null, | 82 | .uid = null, |
| 83 | .gid = null, | ||
| 80 | .stdin = null, | 84 | .stdin = null, |
| 81 | .stdout = null, | 85 | .stdout = null, |
| 82 | .stderr = null, | 86 | .stderr = null, |
| ... | @@ -89,7 +93,9 @@ pub const ChildProcess = struct { | ... | @@ -89,7 +93,9 @@ pub const ChildProcess = struct { |
| 89 | } | 93 | } |
| 90 | 94 | ||
| 91 | pub fn setUserName(self: &ChildProcess, name: []const u8) -> %void { | 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 | /// onTerm can be called before `spawn` returns. | 101 | /// onTerm can be called before `spawn` returns. |
| ... | @@ -294,7 +300,11 @@ pub const ChildProcess = struct { | ... | @@ -294,7 +300,11 @@ pub const ChildProcess = struct { |
| 294 | } | 300 | } |
| 295 | 301 | ||
| 296 | if (self.uid) |uid| { | 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 | os.posixExecve(self.argv, env_map, self.allocator) %% | 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,10 +3,15 @@ const Os = builtin.Os; |
| 3 | const os = @import("index.zig"); | 3 | const os = @import("index.zig"); |
| 4 | const io = @import("../io.zig"); | 4 | const io = @import("../io.zig"); |
| 5 | 5 | ||
| 6 | pub const UserInfo = struct { | ||
| 7 | uid: u32, | ||
| 8 | gid: u32, | ||
| 9 | }; | ||
| 10 | |||
| 6 | /// POSIX function which gets a uid from username. | 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 | return switch (builtin.os) { | 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 | else => @compileError("Unsupported OS"), | 15 | else => @compileError("Unsupported OS"), |
| 11 | }; | 16 | }; |
| 12 | } | 17 | } |
| ... | @@ -15,13 +20,17 @@ const State = enum { | ... | @@ -15,13 +20,17 @@ const State = enum { |
| 15 | Start, | 20 | Start, |
| 16 | WaitForNextLine, | 21 | WaitForNextLine, |
| 17 | SkipPassword, | 22 | SkipPassword, |
| 18 | ReadId, | 23 | ReadUserId, |
| 24 | ReadGroupId, | ||
| 19 | }; | 25 | }; |
| 20 | 26 | ||
| 21 | error UserNotFound; | 27 | error UserNotFound; |
| 22 | error CorruptPasswordFile; | 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 | var in_stream = %return io.InStream.open("/etc/passwd", null); | 34 | var in_stream = %return io.InStream.open("/etc/passwd", null); |
| 26 | defer in_stream.close(); | 35 | defer in_stream.close(); |
| 27 | 36 | ||
| ... | @@ -29,6 +38,7 @@ pub fn posixGetUserId(name: []const u8) -> %u32 { | ... | @@ -29,6 +38,7 @@ pub fn posixGetUserId(name: []const u8) -> %u32 { |
| 29 | var name_index: usize = 0; | 38 | var name_index: usize = 0; |
| 30 | var state = State.Start; | 39 | var state = State.Start; |
| 31 | var uid: u32 = 0; | 40 | var uid: u32 = 0; |
| 41 | var gid: u32 = 0; | ||
| 32 | 42 | ||
| 33 | while (true) { | 43 | while (true) { |
| 34 | const amt_read = %return in_stream.read(buf[0..]); | 44 | const amt_read = %return in_stream.read(buf[0..]); |
| ... | @@ -56,12 +66,15 @@ pub fn posixGetUserId(name: []const u8) -> %u32 { | ... | @@ -56,12 +66,15 @@ pub fn posixGetUserId(name: []const u8) -> %u32 { |
| 56 | State.SkipPassword => switch (byte) { | 66 | State.SkipPassword => switch (byte) { |
| 57 | '\n' => return error.CorruptPasswordFile, | 67 | '\n' => return error.CorruptPasswordFile, |
| 58 | ':' => { | 68 | ':' => { |
| 59 | state = State.ReadId; | 69 | state = State.ReadUserId; |
| 60 | }, | 70 | }, |
| 61 | else => continue, | 71 | else => continue, |
| 62 | }, | 72 | }, |
| 63 | State.ReadId => switch (byte) { | 73 | State.ReadUserId => switch (byte) { |
| 64 | '\n', ':' => return uid, | 74 | ':' => { |
| 75 | state = State.ReadGroupId; | ||
| 76 | }, | ||
| 77 | '\n' => return error.CorruptPasswordFile, | ||
| 65 | else => { | 78 | else => { |
| 66 | const digit = switch (byte) { | 79 | const digit = switch (byte) { |
| 67 | '0' ... '9' => byte - '0', | 80 | '0' ... '9' => byte - '0', |
| ... | @@ -71,6 +84,22 @@ pub fn posixGetUserId(name: []const u8) -> %u32 { | ... | @@ -71,6 +84,22 @@ pub fn posixGetUserId(name: []const u8) -> %u32 { |
| 71 | if (@addWithOverflow(u32, uid, digit, &uid)) return error.CorruptPasswordFile; | 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 | if (amt_read < buf.len) return error.UserNotFound; | 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,7 +20,8 @@ pub const line_sep = switch (builtin.os) { |
| 20 | 20 | ||
| 21 | pub const page_size = 4 * 1024; | 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 | const debug = @import("../debug.zig"); | 26 | const debug = @import("../debug.zig"); |
| 26 | const assert = debug.assert; | 27 | const assert = debug.assert; |
| ... | @@ -999,3 +1000,36 @@ pub fn posix_setuid(uid: u32) -> %void { | ... | @@ -999,3 +1000,36 @@ pub fn posix_setuid(uid: u32) -> %void { |
| 999 | else => error.Unexpected, | 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,6 +484,18 @@ pub fn setuid(uid: u32) -> usize { |
| 484 | arch.syscall1(arch.SYS_setuid, uid) | 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 | pub fn sigprocmask(flags: u32, noalias set: &const sigset_t, noalias oldset: ?&sigset_t) -> usize { | 499 | pub fn sigprocmask(flags: u32, noalias set: &const sigset_t, noalias oldset: ?&sigset_t) -> usize { |
| 488 | arch.syscall4(arch.SYS_rt_sigprocmask, flags, @ptrToInt(set), @ptrToInt(oldset), NSIG/8) | 500 | arch.syscall4(arch.SYS_rt_sigprocmask, flags, @ptrToInt(set), @ptrToInt(oldset), NSIG/8) |
| 489 | } | 501 | } |