From 5fa4a71ddf3d64e9d4197d6d6ae54465f37210a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Motiejus=20Jak=C5=A1tys?= Date: Fri, 8 Jul 2022 08:40:24 +0300 Subject: [PATCH] use omit_members sometimes --- src/DB.zig | 65 ++++++++++++++++++++++++++++++++++++++++++-------- src/libnss.zig | 31 ++++++++++++++++-------- 2 files changed, 76 insertions(+), 20 deletions(-) diff --git a/src/DB.zig b/src/DB.zig index 6f639ca..e25a44a 100644 --- a/src/DB.zig +++ b/src/DB.zig @@ -279,6 +279,28 @@ pub fn fromBytes(buf: []align(8) const u8) InvalidHeader!DB { return result; } +pub fn packCGroupNoMembers(group: PackedGroup, buf: []u8) error{BufferTooSmall}!CGroup { + // first word in buf will be a pointer to null. that probably can be + // simplified by writing (0)**word_size to the buffer, but let's pretend + // type safety for a moment. + const name_start = @sizeOf(?[*:0]const u8); + if (name_start > buf.len) return error.BufferTooSmall; + var member_ptrs = mem.bytesAsSlice(?[*:0]const u8, buf[0..name_start]); + member_ptrs[0] = null; + + // write name + const name = group.name(); + if (name_start + name.len + 1 > buf.len) return error.BufferTooSmall; + mem.copy(u8, buf[name_start..], name); + buf[name_start + name.len] = 0; + + return CGroup{ + .gid = group.gid(), + .name = buf[name_start .. name_start + name.len :0].ptr, + .members = member_ptrs.ptr, + }; +} + // dumps PackedGroup to []u8 and returns a CGroup. pub fn packCGroup(self: *const DB, group: PackedGroup, buf: []u8) error{BufferTooSmall}!CGroup { const members_slice = self.groupmembers[group.members_offset..]; @@ -321,25 +343,41 @@ pub fn packCGroup(self: *const DB, group: PackedGroup, buf: []u8) error{BufferTo } // get a CGroup entry by name. -pub fn getgrnam(self: *const DB, name: []const u8, buf: []u8) error{BufferTooSmall}!?CGroup { +pub fn getgrnam( + self: *const DB, + name: []const u8, + buf: []u8, + omit_members: bool, +) error{BufferTooSmall}!?CGroup { const idx = bdz.search(self.bdz_groupname, name); if (idx >= self.header.num_groups) return null; const offset = self.idx_groupname2group[idx]; 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.packCGroup(group, buf); + return if (omit_members) + try packCGroupNoMembers(group, buf) + else + try self.packCGroup(group, buf); } // get a CGroup entry by it's gid. -pub fn getgrgid(self: *const DB, gid: u32, buf: []u8) error{BufferTooSmall}!?CGroup { +pub fn getgrgid( + self: *const DB, + gid: u32, + buf: []u8, + omit_members: bool, +) error{BufferTooSmall}!?CGroup { const idx = bdz.search_u32(self.bdz_gid, gid); if (idx >= self.header.num_groups) return null; const offset = self.idx_gid2group[idx]; const nbits = PackedGroup.alignment_bits; const group = PackedGroup.fromBytes(self.groups[offset << nbits ..]).group; if (gid != group.gid()) return null; - return try self.packCGroup(group, buf); + return if (omit_members) + try packCGroupNoMembers(group, buf) + else + try self.packCGroup(group, buf); } fn pushStr(str: []const u8, buf: []u8, offset: *usize) [*:0]const u8 { @@ -708,8 +746,8 @@ test "getgrnam/getgrgid" { defer testing.allocator.free(buf); { - try testing.expectEqual(try db.getgrnam("doesnotexist", buf), null); - const all = (try db.getgrnam("all", buf)).?; + try testing.expectEqual(try db.getgrnam("doesnotexist", buf, false), null); + const all = (try db.getgrnam("all", buf, false)).?; try testing.expectEqual(all.gid, 9999); try testing.expectEqualStrings(all.name[0..4], "all\x00"); const members = all.members; @@ -721,16 +759,23 @@ test "getgrnam/getgrgid" { } { - try testing.expectEqual(try db.getgrgid(42, buf), null); - const all = (try db.getgrgid(9999, buf)).?; + const all = (try db.getgrnam("all", buf, true)).?; + try testing.expectEqual(all.gid, 9999); + try testing.expectEqualStrings(all.name[0..4], "all\x00"); + try testing.expectEqual(all.members[0], null); + } + + { + try testing.expectEqual(try db.getgrgid(42, buf, false), null); + const all = (try db.getgrgid(9999, buf, false)).?; try testing.expectEqual(all.gid, 9999); try testing.expectEqualStrings(all.name[0..3], "all"); } try testing.expectEqualStrings("", errc.unwrap().constSlice()); - _ = try db.getgrnam("all", buf); + _ = try db.getgrnam("all", buf, false); buf.len -= 1; - try testing.expectError(error.BufferTooSmall, db.getgrnam("all", buf)); + try testing.expectError(error.BufferTooSmall, db.getgrnam("all", buf, false)); } test "getpwnam/getpwuid" { diff --git a/src/libnss.zig b/src/libnss.zig index 4a6214f..e39213d 100644 --- a/src/libnss.zig +++ b/src/libnss.zig @@ -160,8 +160,12 @@ export fn _nss_turbo_getgrgid_r( buflen: usize, errnop: *c_int, ) c.enum_nss_status { - const db = getDBErrno(errnop) orelse return c.NSS_STATUS_UNAVAIL; - var cgroup = db.getgrgid(gid, buffer[0..buflen]) catch |err| switch (err) { + const state = getStateErrno(errnop) orelse return c.NSS_STATUS_UNAVAIL; + const db = state.file.db; + const omit_members = state.omit_members; + + var buf = buffer[0..buflen]; + var cgroup = db.getgrgid(gid, buf, omit_members) catch |err| switch (err) { error.BufferTooSmall => { errnop.* = @enumToInt(os.E.RANGE); return c.NSS_STATUS_TRYAGAIN; @@ -184,10 +188,13 @@ export fn _nss_turbo_getgrnam_r( buflen: usize, errnop: *c_int, ) c.enum_nss_status { - const db = getDBErrno(errnop) orelse return c.NSS_STATUS_UNAVAIL; + const state = getStateErrno(errnop) orelse return c.NSS_STATUS_UNAVAIL; + const db = state.file.db; + const omit_members = state.omit_members; + const nameSlice = mem.sliceTo(name, 0); var buf = buffer[0..buflen]; - var cgroup = db.getgrnam(nameSlice, buf) catch |err| switch (err) { + var cgroup = db.getgrnam(nameSlice, buf, omit_members) catch |err| switch (err) { error.BufferTooSmall => { errnop.* = @enumToInt(os.E.RANGE); return c.NSS_STATUS_TRYAGAIN; @@ -267,16 +274,20 @@ export fn _nss_turbo_getgrent_r( return c.NSS_STATUS_NOTFOUND; }; - const buf = buffer[0..buflen]; - const cgroup = state.file.db.packCGroup(group, buf) catch |err| switch (err) { + const cgroup1 = if (state.omit_members) + DB.packCGroupNoMembers(group, buffer[0..buflen]) + else + state.file.db.packCGroup(group, buffer[0..buflen]); + + if (cgroup1) |cgroup| { + result.* = cgroup; + return c.NSS_STATUS_SUCCESS; + } else |err| switch (err) { error.BufferTooSmall => { errnop.* = @enumToInt(os.E.RANGE); return c.NSS_STATUS_TRYAGAIN; }, - }; - - result.* = cgroup; - return c.NSS_STATUS_SUCCESS; + } } export fn _nss_turbo_getpwent_r(