From a63c60cc6f6ece26c1ad180d9ff44d630c132e44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Motiejus=20Jak=C5=A1tys?= Date: Wed, 6 Jul 2022 16:54:43 +0300 Subject: [PATCH] passwd fields now have sentinels --- src/DB.zig | 18 +++++++++--------- src/File.zig | 5 +++-- src/User.zig | 10 +++++----- src/libnss.zig | 51 +++++++++++++++++++++++++++++++++++++++++++------- 4 files changed, 61 insertions(+), 23 deletions(-) diff --git a/src/DB.zig b/src/DB.zig index 82b445b..54e130f 100644 --- a/src/DB.zig +++ b/src/DB.zig @@ -280,13 +280,13 @@ pub fn fromBytes(buf: []align(8) const u8) InvalidHeader!DB { } // 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{BufferTooSmall}!CGroup { const members_slice = self.groupmembers[group.members_offset..]; var vit = compress.VarintSliceIteratorMust(members_slice); const num_members = vit.remaining; const ptr_end = @sizeOf(?[*:0]const u8) * (num_members + 1); - if (ptr_end > buf.len) return error.OutOfMemory; + if (ptr_end > buf.len) return error.BufferTooSmall; var member_ptrs = mem.bytesAsSlice(?[*:0]const u8, buf[0..ptr_end]); member_ptrs[member_ptrs.len - 1] = null; var buf_offset: usize = ptr_end; @@ -297,7 +297,7 @@ fn getGroup(self: *const DB, group: PackedGroup, buf: []u8) error{OutOfMemory}!C const entry = PackedUser.fromBytes(self.users[member_offset << 3 ..]); const start = buf_offset; const name = entry.user.name(); - if (buf_offset + name.len + 1 > buf.len) return error.OutOfMemory; + if (buf_offset + name.len + 1 > buf.len) return error.BufferTooSmall; mem.copy(u8, buf[buf_offset..], name); buf_offset += name.len; buf[buf_offset] = 0; @@ -309,7 +309,7 @@ fn getGroup(self: *const DB, group: PackedGroup, buf: []u8) error{OutOfMemory}!C } const name = group.name(); - if (buf_offset + name.len + 1 > buf.len) return error.OutOfMemory; + if (buf_offset + name.len + 1 > buf.len) return error.BufferTooSmall; mem.copy(u8, buf[buf_offset..], name); buf[buf_offset + name.len] = 0; @@ -321,7 +321,7 @@ fn getGroup(self: *const DB, group: PackedGroup, buf: []u8) error{OutOfMemory}!C } // get a CGroup entry by name. -fn getgrnam(self: *const DB, name: []const u8, buf: []u8) error{OutOfMemory}!?CGroup { +fn getgrnam(self: *const DB, name: []const u8, buf: []u8) 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]; @@ -332,7 +332,7 @@ fn getgrnam(self: *const DB, name: []const u8, buf: []u8) error{OutOfMemory}!?CG } // get a CGroup entry by it's gid. -fn getgrgid(self: *const DB, gid: u32, buf: []u8) error{OutOfMemory}!?CGroup { +fn getgrgid(self: *const DB, gid: u32, buf: []u8) 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]; @@ -342,12 +342,12 @@ fn getgrgid(self: *const DB, gid: u32, buf: []u8) error{OutOfMemory}!?CGroup { return try self.getGroup(group, buf); } -fn pushStr(str: []const u8, buf: []u8, offset: *usize) [*]const u8 { +fn pushStr(str: []const u8, buf: []u8, offset: *usize) [*:0]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]); + return @ptrCast([*:0]const u8, &buf[start]); } fn getUser(self: *const DB, user: PackedUser, buf: []u8) error{BufferTooSmall}!CUser { @@ -725,7 +725,7 @@ test "getgrnam/getgrgid" { _ = try db.getgrnam("all", buf); buf.len -= 1; - try testing.expectError(error.OutOfMemory, db.getgrnam("all", buf)); + try testing.expectError(error.BufferTooSmall, db.getgrnam("all", buf)); } test "getpwnam/getpwuid" { diff --git a/src/File.zig b/src/File.zig index c72214d..dcd432f 100644 --- a/src/File.zig +++ b/src/File.zig @@ -43,11 +43,12 @@ pub const TestDB = struct { dir: testing.TmpDir, path: [:0]const u8, - pub fn init(allocator: Allocator, errc: *ErrCtx) !TestDB { + pub fn init(allocator: Allocator) !TestDB { + var errc = ErrCtx{}; var corpus = try Corpus.testCorpus(allocator); defer corpus.deinit(); - var db = try DB.fromCorpus(allocator, &corpus, errc); + var db = try DB.fromCorpus(allocator, &corpus, &errc); defer db.deinit(allocator); var tmp = testing.tmpDir(.{}); diff --git a/src/User.zig b/src/User.zig index f0c3efc..5457bfc 100644 --- a/src/User.zig +++ b/src/User.zig @@ -145,13 +145,13 @@ pub fn fromReader(allocator: Allocator, err: *ErrCtx, reader: anytype) ![]User { } pub const CUser = extern struct { - pw_name: [*]const u8, - pw_passwd: [*]const u8 = pw_passwd, + pw_name: [*:0]const u8, + pw_passwd: [*:0]const u8 = pw_passwd, pw_uid: u32, pw_gid: u32, - pw_gecos: [*]const u8, - pw_dir: [*]const u8, - pw_shell: [*]const u8, + pw_gecos: [*:0]const u8, + pw_dir: [*:0]const u8, + pw_shell: [*:0]const u8, }; const testing = std.testing; diff --git a/src/libnss.zig b/src/libnss.zig index cf01153..a9fb77a 100644 --- a/src/libnss.zig +++ b/src/libnss.zig @@ -127,7 +127,7 @@ export fn _nss_turbo_getpwuid_r( } export fn _nss_turbo_getpwnam_r( - name: [*:0]u8, + name: [*:0]const u8, passwd: *CUser, buffer: [*]u8, buflen: usize, @@ -164,17 +164,54 @@ fn get_db(errnop: *c_int) ?DB { const testing = std.testing; -test "nss_turbo_getpwuid_r" { - var errc = ErrCtx{}; - var tf = try File.TestDB.init(testing.allocator, &errc); +test "getpwuid_r and getpwnam_r" { + var tf = try File.TestDB.init(testing.allocator); defer tf.deinit(); + const turbonss_db_path_old = turbonss_db_path; turbonss_db_path = tf.path; + defer { + turbonss_db_path = turbonss_db_path_old; + } - var passwd: CUser = undefined; var buffer: [1024]u8 = undefined; var errno: c_int = 0; - const status = _nss_turbo_getpwuid_r(0, &passwd, &buffer, buffer.len, &errno); + var passwd: CUser = undefined; + try testing.expectEqual( + c.NSS_STATUS_SUCCESS, + _nss_turbo_getpwuid_r(128, &passwd, &buffer, buffer.len, &errno), + ); try testing.expectEqual(@as(c_int, 0), errno); - try testing.expectEqual(c.NSS_STATUS_SUCCESS, status); + try testVidmantas(passwd); + + passwd = undefined; + try testing.expectEqual( + c.NSS_STATUS_SUCCESS, + _nss_turbo_getpwnam_r("vidmantas", &passwd, &buffer, buffer.len, &errno), + ); + try testing.expectEqual(@as(c_int, 0), errno); + try testVidmantas(passwd); + + passwd = undefined; + try testing.expectEqual( + c.NSS_STATUS_NOTFOUND, + _nss_turbo_getpwnam_r("does not exist", &passwd, &buffer, buffer.len, &errno), + ); + try testing.expectEqual(@enumToInt(os.E.NOENT), @intCast(u16, errno)); + + passwd = undefined; + var small_buffer: [1]u8 = undefined; + try testing.expectEqual( + c.NSS_STATUS_TRYAGAIN, + _nss_turbo_getpwuid_r(0, &passwd, &small_buffer, small_buffer.len, &errno), + ); + try testing.expectEqual(@enumToInt(os.E.RANGE), @intCast(u16, errno)); +} + +fn testVidmantas(u: CUser) !void { + try testing.expectEqualStrings("vidmantas", mem.sliceTo(u.pw_name, 0)); + try testing.expectEqual(@as(u32, 128), u.pw_uid); + try testing.expectEqual(@as(u32, 128), u.pw_gid); + try testing.expectEqualStrings("Vidmantas Kaminskas", mem.sliceTo(u.pw_gecos, 0)); + try testing.expectEqualStrings("/bin/bash", mem.sliceTo(u.pw_shell, 0)); }