From 4469d174eaa5d3b128ae1c20a91ab680966dea98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Motiejus=20Jak=C5=A1tys?= Date: Tue, 19 Apr 2022 13:17:23 +0300 Subject: [PATCH] wip getpwnam --- lib/DB.zig | 91 +++++++++++++++++++++++++++++++++++++++++----- lib/PackedUser.zig | 3 +- lib/User.zig | 12 ++++++ lib/shell.zig | 7 ++-- 4 files changed, 100 insertions(+), 13 deletions(-) diff --git a/lib/DB.zig b/lib/DB.zig index 31f86ca..3a30c21 100644 --- a/lib/DB.zig +++ b/lib/DB.zig @@ -14,12 +14,13 @@ const ArenaAllocator = std.heap.ArenaAllocator; const Corpus = @import("Corpus.zig"); const pad = @import("padding.zig"); const compress = @import("compress.zig"); -const PackedUser = @import("PackedUser.zig"); -const User = @import("User.zig"); const Group = @import("Group.zig"); const CGroup = Group.CGroup; const PackedGroup = @import("PackedGroup.zig"); const GroupStored = PackedGroup.GroupStored; +const User = @import("User.zig"); +const CUser = User.CUser; +const PackedUser = @import("PackedUser.zig"); const ShellSections = @import("shell.zig").ShellWriter.ShellSections; const ShellReader = @import("shell.zig").ShellReader; const ShellWriter = @import("shell.zig").ShellWriter; @@ -123,6 +124,8 @@ pub fn fromCorpus( .getpw_bufsize = corpus.getpw_bufsize, }; + std.debug.print("fromCorpus shell.index: {any}\n", .{shell.index.constSlice()}); + return DB{ .header = header, .bdz_gid = bdz_gid, @@ -169,6 +172,8 @@ pub fn iov(self: *const DB) BoundedArray(os.iovec_const, DB_fields.len * 2) { *const Header => mem.asBytes(value), else => mem.sliceAsBytes(value), }; + if (mem.eql(u8, field.name, "shell_index")) + std.debug.print("shell_index original: {any}\n", .{value}); result.appendAssumeCapacity(os.iovec_const{ .iov_base = bytes.ptr, .iov_len = bytes.len, @@ -219,15 +224,13 @@ pub fn fromBytes(buf: []align(8) const u8) InvalidHeader!DB { offset += lengths[i]; } + std.debug.print("GOT shell_index: {any}\n", .{result.shell_index}); + return result; } // dumps PackedGroup to []u8 and returns a CGroup. -fn getGroup( - self: *const DB, - group: PackedGroup, - buf: *[]u8, -) error{OutOfMemory}!CGroup { +fn getGroup(self: *const DB, group: PackedGroup, buf: *[]u8) error{OutOfMemory}!CGroup { const members_slice = self.groupmembers[group.members_offset..]; var vit = compress.VarintSliceIteratorMust(members_slice); const num_members = vit.remaining; @@ -271,7 +274,8 @@ fn getGroup( fn getgrnam(self: *const DB, name: []const u8, buf: *[]u8) error{OutOfMemory}!?CGroup { const idx = bdz.search(self.bdz_groupname, name); const offset = self.idx_groupname2group[idx]; - const group = PackedGroup.fromBytes(self.groups[offset << 3 ..]).group; + const nbits = PackedGroup.alignment_bits; + const group = PackedGroup.fromBytes(self.groups[offset << nbits ..]).group; if (!mem.eql(u8, name, group.name())) return null; return try self.getGroup(group, buf); } @@ -280,16 +284,69 @@ fn getgrnam(self: *const DB, name: []const u8, buf: *[]u8) error{OutOfMemory}!?C fn getgrgid(self: *const DB, gid: u32, buf: *[]u8) error{OutOfMemory}!?CGroup { const idx = bdz.search_u32(self.bdz_gid, gid); const offset = self.idx_gid2group[idx]; - const group = PackedGroup.fromBytes(self.groups[offset << 3 ..]).group; + const nbits = PackedGroup.alignment_bits; + const group = PackedGroup.fromBytes(self.groups[offset << nbits ..]).group; if (gid != group.gid()) return null; return try self.getGroup(group, buf); } +fn pushStr(str: []const u8, buf: *[]u8, offset: *usize) [*]const u8 { + const start = offset.*; + mem.copy(u8, buf.*[offset.*..], str); + buf.*[offset.* + str.len] = 0; + offset.* += str.len + 1; + return @ptrCast([*]const u8, &buf.*[start]); +} + +fn getUser(self: *const DB, user: PackedUser, buf: *[]u8) error{OutOfMemory}!CUser { + const shell_reader = ShellReader{ + .index = self.shell_index, + .blob = self.shell_blob, + }; + const name = user.name(); + const gecos = user.gecos(); + const home = user.home(); + const shell = user.shell(shell_reader); + + const strlen = + name.len + 1 + + gecos.len + 1 + + home.len + 1 + + shell.len + 1; + if (strlen > buf.len) return error.OutOfMemory; + + var offset: usize = 0; + const pw_name = pushStr(name, buf, &offset); + const pw_gecos = pushStr(gecos, buf, &offset); + const pw_dir = pushStr(home, buf, &offset); + const pw_shell = pushStr(shell, buf, &offset); + + return CUser{ + .pw_name = pw_name, + .pw_uid = user.uid(), + .pw_gid = user.gid(), + .pw_gecos = pw_gecos, + .pw_dir = pw_dir, + .pw_shell = pw_shell, + }; +} + +// get a CUser entry by name. +fn getpwnam(self: *const DB, name: []const u8, buf: *[]u8) error{OutOfMemory}!?CUser { + const idx = bdz.search(self.bdz_username, name); + const offset = self.idx_name2user[idx]; + const nbits = PackedUser.alignment_bits; + const user = PackedUser.fromBytes(self.users[offset << nbits ..]).user; + if (!mem.eql(u8, name, user.name())) return null; + return try self.getUser(user, buf); +} + fn shellSections( allocator: Allocator, corpus: *const Corpus, ) error{OutOfMemory}!ShellSections { var popcon = ShellWriter.init(allocator); + errdefer popcon.deinit(); for (corpus.users.items(.shell)) |shell| try popcon.put(shell); return popcon.toOwnedSections(max_shells); @@ -609,6 +666,22 @@ test "getgr_bufsize" { try testing.expectError(error.OutOfMemory, db.getgrnam("all", &buf)); } +test "getpwnam" { + var arena = ArenaAllocator.init(testing.allocator); + defer arena.deinit(); + var corpus = try Corpus.testCorpus(arena.allocator()); + var db = try DB.fromCorpus(arena.allocator(), &corpus); + std.debug.print("db.shell.index: {any}\n", .{db.shell_index}); + var buf = try arena.allocator().alloc(u8, db.header.getpw_bufsize); + + const vidmantas = (try db.getpwnam("vidmantas", &buf)).?; + try testing.expectEqual(vidmantas.pw_uid, 128); + try testing.expectEqual(vidmantas.pw_gid, 128); + try testing.expectEqualStrings(vidmantas.pw_name[0..9], "vidmantas"); + try testing.expectEqualStrings(vidmantas.pw_gecos[0..10], "Vidmantas Kaminskas"); + try testing.expectEqualStrings(vidmantas.pw_dir[0..10], "/home/vidmantas"); +} + test "additionalGids" { const allocator = testing.allocator; var corpus = try Corpus.testCorpus(allocator); diff --git a/lib/PackedUser.zig b/lib/PackedUser.zig index 4d9fbbe..8d41762 100644 --- a/lib/PackedUser.zig +++ b/lib/PackedUser.zig @@ -209,7 +209,8 @@ pub fn shell(self: PackedUser, shell_reader: shellImport.ShellReader) []const u8 return shell_reader.get(self.inner.shell_len_or_idx); } -pub const max_str_len = math.maxInt(fieldInfo(Inner, .shell_len_or_idx).field_type) + 1 + +pub const max_str_len = + math.maxInt(fieldInfo(Inner, .shell_len_or_idx).field_type) + 1 + math.maxInt(fieldInfo(Inner, .home_len).field_type) + 1 + math.maxInt(fieldInfo(Inner, .name_len).field_type) + 1 + math.maxInt(fieldInfo(Inner, .gecos_len).field_type); diff --git a/lib/User.zig b/lib/User.zig index db099ae..f5a7ceb 100644 --- a/lib/User.zig +++ b/lib/User.zig @@ -6,6 +6,8 @@ const Allocator = mem.Allocator; const ArrayList = std.ArrayList; const BoundedArray = std.BoundedArray; +const pw_passwd = "x\x00"; + const User = @This(); const PackedUser = @import("PackedUser.zig"); const validate = @import("validate.zig"); @@ -126,6 +128,16 @@ pub fn fromReader(allocator: Allocator, reader: anytype) ![]User { _ = users; } +pub const CUser = extern struct { + pw_name: [*]const u8, + pw_passwd: [*]const u8 = pw_passwd, + pw_uid: u32, + pw_gid: u32, + pw_gecos: [*]const u8, + pw_dir: [*]const u8, + pw_shell: [*]const u8, +}; + const testing = std.testing; pub const max_user = User{ diff --git a/lib/shell.zig b/lib/shell.zig index 6f33f23..8374a8d 100644 --- a/lib/shell.zig +++ b/lib/shell.zig @@ -22,6 +22,8 @@ pub const ShellReader = struct { // get returns a shell at the given index. pub fn get(self: *const ShellReader, idx: u8) []const u8 { + std.debug.print("\nrequested shell at index {d}; ", .{idx}); + std.debug.print("start:{d} end:{d}\n", .{ self.index[idx], self.index[idx + 1] }); return self.blob[self.index[idx]..self.index[idx + 1]]; } }; @@ -73,6 +75,7 @@ pub const ShellWriter = struct { self.index.set(idx8, offset); } self.index.appendAssumeCapacity(@intCast(u8, self.blob.len)); + std.debug.print("\nGEN shell_index: {any}\n", .{self.index.constSlice()}); return self; } @@ -141,9 +144,7 @@ pub const ShellWriter = struct { } const total = std.math.min(deque.count(), limit); - var topShells = BoundedArray([]const u8, max_shells).init(total) catch |err| switch (err) { - error.Overflow => unreachable, - }; + var topShells = BoundedArray([]const u8, max_shells).init(total) catch unreachable; var i: u32 = 0; while (i < total) : (i += 1)