From 78ac541e498a9f01dc0b456cd898cdf5491a443c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Motiejus=20Jak=C5=A1tys?= Date: Sat, 9 Jul 2022 16:50:49 +0300 Subject: [PATCH] libnss: pass state explicitly --- src/File.zig | 10 ++-- src/libnss.zig | 141 +++++++++++++++++++++++++++++++++++++++---------- 2 files changed, 119 insertions(+), 32 deletions(-) diff --git a/src/File.zig b/src/File.zig index dcd432f..e67e0bf 100644 --- a/src/File.zig +++ b/src/File.zig @@ -39,9 +39,10 @@ pub fn close(self: *File) void { const testing = std.testing; pub const TestDB = struct { - allocator: Allocator, + file: File, dir: testing.TmpDir, path: [:0]const u8, + allocator: Allocator, pub fn init(allocator: Allocator) !TestDB { var errc = ErrCtx{}; @@ -65,9 +66,9 @@ pub const TestDB = struct { break :blk real_path; }; - const full_path = try fs.path.join(allocator, &[_][]const u8{ + const full_path = try fs.path.joinZ(allocator, &[_][]const u8{ base_path, - "db.turbo\x00", + "db.turbo", }); allocator.free(base_path); @@ -78,8 +79,9 @@ pub const TestDB = struct { _ = try os.writev(fd, db.iov().constSlice()); return TestDB{ + .file = try open(full_path), .dir = tmp, - .path = full_path[0 .. full_path.len - 1 :0], + .path = full_path, .allocator = allocator, }; } diff --git a/src/libnss.zig b/src/libnss.zig index 3cb4344..77aa448 100644 --- a/src/libnss.zig +++ b/src/libnss.zig @@ -115,7 +115,17 @@ export fn _nss_turbo_getpwuid_r( errnop: *c_int, ) c.enum_nss_status { const db = getDBErrno(errnop) orelse return c.NSS_STATUS_UNAVAIL; + return getpwuid_r(&db, uid, passwd, buffer, buflen, errnop); +} +fn getpwuid_r( + db: *const DB, + uid: c_uint, + passwd: *CUser, + buffer: [*]u8, + buflen: usize, + errnop: *c_int, +) c.enum_nss_status { var cuser = db.getpwuid(uid, buffer[0..buflen]) catch |err| switch (err) { error.BufferTooSmall => { errnop.* = @enumToInt(os.E.RANGE); @@ -140,6 +150,17 @@ export fn _nss_turbo_getpwnam_r( errnop: *c_int, ) c.enum_nss_status { const db = getDBErrno(errnop) orelse return c.NSS_STATUS_UNAVAIL; + return getpwnam_r(&db, name, passwd, buffer, buflen, errnop); +} + +fn getpwnam_r( + db: *const DB, + name: [*:0]const u8, + passwd: *CUser, + buffer: [*]u8, + buflen: usize, + errnop: *c_int, +) c.enum_nss_status { const nameSlice = mem.sliceTo(name, 0); var buf = buffer[0..buflen]; @@ -167,6 +188,17 @@ export fn _nss_turbo_getgrgid_r( errnop: *c_int, ) c.enum_nss_status { const state = getStateErrno(errnop) orelse return c.NSS_STATUS_UNAVAIL; + return getgrgid_r(&state, gid, gr, buffer, buflen, errnop); +} + +fn getgrgid_r( + state: *const State, + gid: c_uint, + gr: *CGroup, + buffer: [*]u8, + buflen: usize, + errnop: *c_int, +) c.enum_nss_status { const db = state.file.db; const omit_members = state.omit_members; @@ -195,9 +227,19 @@ export fn _nss_turbo_getgrnam_r( errnop: *c_int, ) c.enum_nss_status { const state = getStateErrno(errnop) orelse return c.NSS_STATUS_UNAVAIL; + return getgrnam_r(&state, name, group, buffer, buflen, errnop); +} + +fn getgrnam_r( + state: *const State, + name: [*:0]const u8, + group: *CGroup, + buffer: [*]u8, + buflen: usize, + errnop: *c_int, +) c.enum_nss_status { 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, omit_members) catch |err| switch (err) { @@ -206,12 +248,10 @@ export fn _nss_turbo_getgrnam_r( return c.NSS_STATUS_TRYAGAIN; }, }; - const got_cgroup = cgroup orelse { errnop.* = @enumToInt(os.E.NOENT); return c.NSS_STATUS_NOTFOUND; }; - group.* = got_cgroup; return c.NSS_STATUS_SUCCESS; } @@ -219,7 +259,10 @@ export fn _nss_turbo_getgrnam_r( export fn _nss_turbo_setpwent(_: c_int) void { global_init.call(); var state = global_state orelse return; + setpwent(&state); +} +fn setpwent(state: *State) void { state.getpwent_iterator_mu.lock(); defer state.getpwent_iterator_mu.unlock(); @@ -235,7 +278,10 @@ export fn _nss_turbo_setpwent(_: c_int) void { export fn _nss_turbo_endpwent() void { global_init.call(); var state = global_state orelse return; + endpwent(&state); +} +fn endpwent(state: *State) void { state.getpwent_iterator_mu.lock(); state.getpwent_iterator = null; state.getpwent_iterator_mu.unlock(); @@ -243,6 +289,10 @@ export fn _nss_turbo_endpwent() void { export fn _nss_turbo_setgrent(_: c_int) void { var state = getState() orelse return; + setgrent(&state); +} + +fn setgrent(state: *State) void { state.getgrent_iterator_mu.lock(); defer state.getgrent_iterator_mu.unlock(); state.getgrent_iterator = PackedGroup.iterator( @@ -252,7 +302,10 @@ export fn _nss_turbo_setgrent(_: c_int) void { export fn _nss_turbo_endgrent() void { var state = getState() orelse return; + endgrent(&state); +} +fn endgrent(state: *State) void { state.getgrent_iterator_mu.lock(); state.getgrent_iterator = null; state.getgrent_iterator_mu.unlock(); @@ -265,7 +318,16 @@ export fn _nss_turbo_getgrent_r( errnop: *c_int, ) c.enum_nss_status { var state = getStateErrno(errnop) orelse return c.NSS_STATUS_UNAVAIL; + return getgrent_r(&state, result, buffer, buflen, errnop); +} +fn getgrent_r( + state: *State, + result: *CGroup, + buffer: [*]u8, + buflen: usize, + errnop: *c_int, +) c.enum_nss_status { state.getgrent_iterator_mu.lock(); defer state.getgrent_iterator_mu.unlock(); @@ -303,7 +365,16 @@ export fn _nss_turbo_getpwent_r( errnop: *c_int, ) c.enum_nss_status { var state = getStateErrno(errnop) orelse return c.NSS_STATUS_UNAVAIL; + return getpwent_r(&state, result, buffer, buflen, errnop); +} +fn getpwent_r( + state: *State, + result: *CUser, + buffer: [*]u8, + buflen: usize, + errnop: *c_int, +) c.enum_nss_status { state.getpwent_iterator_mu.lock(); defer state.getpwent_iterator_mu.unlock(); @@ -332,7 +403,7 @@ export fn _nss_turbo_getpwent_r( export fn _nss_turbo_initgroups_dyn( user_name: [*:0]const u8, - _: u32, + gid: u32, start: *c_long, size: *c_long, groupsp: *[*]u32, @@ -340,8 +411,20 @@ export fn _nss_turbo_initgroups_dyn( errnop: *c_int, ) c.enum_nss_status { const state = getStateErrno(errnop) orelse return c.NSS_STATUS_UNAVAIL; - const db = state.file.db; + return initgroups_dyn(&state, user_name, gid, start, size, groupsp, limit, errnop); +} +fn initgroups_dyn( + state: *const State, + user_name: [*:0]const u8, + _: u32, + start: *c_long, + size: *c_long, + groupsp: *[*]u32, + limit: c_long, + errnop: *c_int, +) c.enum_nss_status { + const db = state.file.db; const user = db.getUser(mem.sliceTo(user_name, 0)) orelse { errnop.* = @enumToInt(os.E.NOENT); return c.NSS_STATUS_NOTFOUND; @@ -413,19 +496,19 @@ const testing = std.testing; 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; - } + const state = State{ + .file = tf.file, + .omit_members = false, + .initgroups_dyn_allocator = testing.failing_allocator, + }; - var buffer: [1024]u8 = undefined; + var buf: [1024]u8 = undefined; var errno: c_int = 0; var passwd: CUser = undefined; try testing.expectEqual( c.NSS_STATUS_SUCCESS, - _nss_turbo_getpwuid_r(128, &passwd, &buffer, buffer.len, &errno), + getpwuid_r(&state.file.db, 128, &passwd, &buf, buf.len, &errno), ); try testing.expectEqual(@as(c_int, 0), errno); try testVidmantas(passwd); @@ -433,7 +516,7 @@ test "getpwuid_r and getpwnam_r" { passwd = undefined; try testing.expectEqual( c.NSS_STATUS_SUCCESS, - _nss_turbo_getpwnam_r("vidmantas", &passwd, &buffer, buffer.len, &errno), + getpwnam_r(&state.file.db, "vidmantas", &passwd, &buf, buf.len, &errno), ); try testing.expectEqual(@as(c_int, 0), errno); try testVidmantas(passwd); @@ -441,7 +524,7 @@ test "getpwuid_r and getpwnam_r" { passwd = undefined; try testing.expectEqual( c.NSS_STATUS_NOTFOUND, - _nss_turbo_getpwnam_r("does not exist", &passwd, &buffer, buffer.len, &errno), + getpwnam_r(&state.file.db, "does not exist", &passwd, &buf, buf.len, &errno), ); try testing.expectEqual(@enumToInt(os.E.NOENT), @intCast(u16, errno)); @@ -449,7 +532,7 @@ test "getpwuid_r and getpwnam_r" { 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), + getpwuid_r(&state.file.db, 0, &passwd, &small_buffer, small_buffer.len, &errno), ); try testing.expectEqual(@enumToInt(os.E.RANGE), @intCast(u16, errno)); } @@ -471,12 +554,12 @@ test "getgrgid_r and getgrnam_r" { turbonss_db_path = turbonss_db_path_old; } - var buffer: [1024]u8 = undefined; + var buf: [1024]u8 = undefined; var errno: c_int = 0; var group: CGroup = undefined; try testing.expectEqual( c.NSS_STATUS_SUCCESS, - _nss_turbo_getgrgid_r(128, &group, &buffer, buffer.len, &errno), + _nss_turbo_getgrgid_r(128, &group, &buf, buf.len, &errno), ); try testing.expectEqual(@as(c_int, 0), errno); try testVidmantasGroup(group); @@ -484,7 +567,7 @@ test "getgrgid_r and getgrnam_r" { group = undefined; try testing.expectEqual( c.NSS_STATUS_SUCCESS, - _nss_turbo_getgrnam_r("vidmantas", &group, &buffer, buffer.len, &errno), + _nss_turbo_getgrnam_r("vidmantas", &group, &buf, buf.len, &errno), ); try testing.expectEqual(@as(c_int, 0), errno); try testVidmantasGroup(group); @@ -492,21 +575,21 @@ test "getgrgid_r and getgrnam_r" { group = undefined; try testing.expectEqual( c.NSS_STATUS_NOTFOUND, - _nss_turbo_getgrnam_r("does not exist", &group, &buffer, buffer.len, &errno), + _nss_turbo_getgrnam_r("does not exist", &group, &buf, buf.len, &errno), ); try testing.expectEqual(@enumToInt(os.E.NOENT), @intCast(u16, errno)); } test "initgroups_dyn" { - 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; - } const allocator = testing.allocator; - global_state.?.initgroups_dyn_allocator = allocator; + + var tf = try File.TestDB.init(allocator); + defer tf.deinit(); + var state = State{ + .file = tf.file, + .omit_members = false, + .initgroups_dyn_allocator = allocator, + }; var size: c_long = 3; // size of the gids array is this var groups = try allocator.alloc(u32, @intCast(usize, size)); // buffer too small @@ -515,7 +598,8 @@ test "initgroups_dyn" { groups[0] = 42; // canary var start: c_long = 1; // canary is there - const status = _nss_turbo_initgroups_dyn( + const status = initgroups_dyn( + &state, "vidmantas", 0, // gid, ignored &start, @@ -528,6 +612,7 @@ test "initgroups_dyn" { try testing.expectEqual(@as(c_int, 42), errno); try testing.expectEqual(@as(u32, 42), groups[0]); try testing.expectEqual(@as(u32, 128), groups[1]); + try testing.expectEqual(@as(u32, 9999), groups[2]); } fn testVidmantasGroup(g: CGroup) !void {