diff --git a/src/bash.zig b/src/bash.zig index 25f40b5..56971b1 100644 --- a/src/bash.zig +++ b/src/bash.zig @@ -8,7 +8,7 @@ const lib = @import("lib.zig"); pub fn main(init: std.process.Init) !void { const arena: std.mem.Allocator = init.arena.allocator(); - const io = init.io; + // const io = init.io; var environ_map = try lib.fixupEnvironMap(arena, init.environ_map, .user); defer environ_map.deinit(); @@ -16,7 +16,7 @@ pub fn main(init: std.process.Init) !void { var argv: std.ArrayList([]const u8) = .empty; defer argv.deinit(arena); - try argv.append(arena, options.bash); + try argv.append(arena, "bash"); var it = try init.minimal.args.iterateAllocator(arena); defer it.deinit(); @@ -28,10 +28,12 @@ pub fn main(init: std.process.Init) !void { try lib.switchToUser(); - const err = std.process.replace(io, .{ - .argv = argv.items, - .environ_map = &environ_map, - }); + try lib.exec(init.gpa, options.bash, argv, &environ_map); - std.debug.print("unable to execute: {t}\n", .{err}); + // const err = std.process.replace(io, .{ + // .argv = argv.items, + // .environ_map = &environ_map, + // }); + + // std.debug.print("unable to execute: {t}\n", .{err}); } diff --git a/src/lib.zig b/src/lib.zig index a9cee89..9f1daa0 100644 --- a/src/lib.zig +++ b/src/lib.zig @@ -3,10 +3,12 @@ const std = @import("std"); +pub const exec = @import("lib/process.zig").exec; pub const fixupEnvironMap = @import("lib/env.zig").fixupEnvironMap; pub const switchToUser = @import("lib/switchtouser.zig").switchToUser; test { _ = @import("lib/env.zig"); + _ = @import("lib/process.zig"); _ = @import("lib/switchtouser.zig"); } diff --git a/src/lib/passwd.zig b/src/lib/passwd.zig new file mode 100644 index 0000000..9bdfaf5 --- /dev/null +++ b/src/lib/passwd.zig @@ -0,0 +1,58 @@ +// SPDX-FileCopyrightText: © 2023 Jeffrey C. Ollie +// SPDX-License-Identifier: MIT + +const std = @import("std"); +const options = @import("options"); + +pub fn getUserUid( + io: std.Io, + name: []const u8, +) !?u32 { + var passwd_file = try std.Io.Dir.openFileAbsolute(io, "/etc/passwd", .{ .mode = .read_only }); + defer passwd_file.close(io); + + // room for 2 paths (home directory and shell) plus a generous amount for the rest + var passwd_buf: [1024 + std.fs.max_path_bytes * 2]u8 = undefined; + var passwd_file_reader = passwd_file.reader(io, &passwd_buf); + const reader = &passwd_file_reader.interface; + + while (true) { + const line = reader.takeDelimiter('\n') catch |err| switch (err) { + error.ReadFailed => return error.ReadFailed, + error.StreamTooLong => return error.StreamTooLong, + } orelse return null; + var it = std.mem.splitScalar(u8, line, ':'); + const username = it.next() orelse continue; + if (!std.mem.eql(u8, username, name)) continue; + _ = it.next(); // skip password field + const uid_str = it.next() orelse return error.MissingUID; + return try std.fmt.parseUnsigned(u32, uid_str, 10); + } +} + +pub fn getUserGid( + io: std.Io, + name: []const u8, +) !?u32 { + var passwd_file = try std.Io.Dir.openFileAbsolute(io, "/etc/passwd", .{ .mode = .read_only }); + defer passwd_file.close(io); + + // room for 2 paths (home directory and shell) plus a generous amount for the rest + var passwd_buf: [1024 + std.fs.max_path_bytes * 2]u8 = undefined; + var passwd_file_reader = passwd_file.reader(io, &passwd_buf); + const reader = &passwd_file_reader.interface; + + while (true) { + const line = reader.takeDelimiter('\n') catch |err| switch (err) { + error.ReadFailed => return error.ReadFailed, + error.StreamTooLong => return error.StreamTooLong, + } orelse return null; + var it = std.mem.splitScalar(u8, line, ':'); + const username = it.next() orelse continue; + if (!std.mem.eql(u8, username, name)) continue; + _ = it.next(); // skip password field + _ = it.next(); // skip uid field + const gid_str = it.next() orelse return error.MissingGID; + return try std.fmt.parseUnsigned(u32, gid_str, 10); + } +} diff --git a/src/lib/process.zig b/src/lib/process.zig new file mode 100644 index 0000000..5dc461c --- /dev/null +++ b/src/lib/process.zig @@ -0,0 +1,26 @@ +// SPDX-FileCopyrightText: © 2023 Jeffrey C. Ollie +// SPDX-License-Identifier: MIT + +const std = @import("std"); +const options = @import("options"); + +pub fn exec(gpa: std.mem.Allocator, path: []const u8, argv: []const []const u8, map: *const std.process.Environ.Map) !void { + var arena: std.heap.ArenaAllocator = .init(gpa); + defer arena.deinit(); + const alloc = arena.allocator(); + + const path0 = try alloc.dupeZ(u8, path); + + const argv0 = try alloc.allocSentinel(?[*:0]const u8, argv.len, null); + for (argv, 0..) |arg, i| argv0[i] = (try alloc.dupeZ(u8, arg)).ptr; + + const block = try map.createPosixBlock(alloc, .{ .zig_progress_fd = -1 }); + + const rc = std.os.linux.execve( + path0.ptr, + argv0.ptr, + block, + ); + + return std.posix.unexpectedErrno(rc); +}