authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-09-26 02:42:06-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-09-26 02:42:06-04:00
logfd2d502e411c45828ebdf1008c5060db8749ef31
treea116b0e692198f52396e426393a9311c8652c221
parentcba4a9ad4a149766c650e3f3d71435cef14867a3

std.os.ChildProcess: ability to set both uid and gid


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,
4242
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,
4548
...@@ -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 }
9094
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 }
94100
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 }
295301
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 }
299309
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;
3const os = @import("index.zig");3const os = @import("index.zig");
4const io = @import("../io.zig");4const io = @import("../io.zig");
55
6pub 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.
7pub fn getUserId(name: []const u8) -> %u32 {12pub 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};
2026
21error UserNotFound;27error UserNotFound;
22error CorruptPasswordFile;28error CorruptPasswordFile;
2329
24pub 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
33pub 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();
2736
...@@ -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;
3242
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) {
2020
21pub const page_size = 4 * 1024;21pub const page_size = 4 * 1024;
2222
23pub const getUserId = @import("get_user_id.zig").getUserId;23pub const UserInfo = @import("get_user_id.zig").UserInfo;
24pub const getUserInfo = @import("get_user_id.zig").getUserInfo;
2425
25const debug = @import("../debug.zig");26const debug = @import("../debug.zig");
26const assert = debug.assert;27const 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
1004pub 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
1015pub 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
1026pub 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}
486486
487pub fn setgid(gid: u32) -> usize {
488 arch.syscall1(arch.SYS_setgid, gid)
489}
490
491pub fn setreuid(ruid: u32, euid: u32) -> usize {
492 arch.syscall2(arch.SYS_setreuid, ruid, euid)
493}
494
495pub fn setregid(rgid: u32, egid: u32) -> usize {
496 arch.syscall2(arch.SYS_setregid, rgid, egid)
497}
498
487pub fn sigprocmask(flags: u32, noalias set: &const sigset_t, noalias oldset: ?&sigset_t) -> usize {499pub 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}