From 43015f4d1d802a0efb8da121371895f8449eb976 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Motiejus=20Jak=C5=A1tys?= Date: Thu, 14 Jul 2022 17:59:21 +0300 Subject: [PATCH] fixes for libnss.zig - global state is a pointer; avoid copying - fix getgr* tests --- src/libnss.zig | 179 +++++++++++++++++++++++++++---------------------- 1 file changed, 99 insertions(+), 80 deletions(-) diff --git a/src/libnss.zig b/src/libnss.zig index 53b3dae..5513bbb 100644 --- a/src/libnss.zig +++ b/src/libnss.zig @@ -1,7 +1,6 @@ const std = @import("std"); const os = std.os; const fmt = std.fmt; -const log = std.log; const mem = std.mem; const math = std.math; const heap = std.heap; @@ -28,13 +27,12 @@ const ENV_OMIT_MEMBERS = "TURBONSS_OMIT_MEMBERS"; export var turbonss_db_path: [:0]const u8 = "/etc/turbonss/db.turbo"; -pub const log_level: std.log.Level = .debug; - // State is a type of the global variable holding the process state: // the DB handle and all the iterators. const State = struct { file: File, omit_members: bool, + v: bool = false, getpwent_iterator_mu: Mutex = Mutex{}, getpwent_iterator: ?PackedUser.Iterator = null, @@ -52,56 +50,65 @@ var global_init = once(init); // assigns State from environment variables et al fn init() void { - //if (os.getenvZ(ENV_LOGLEVEL)) |env| { - // const got = mem.sliceTo(env, 0); - // if (mem.eql(u8, got, "0")) { - // log_level = .err; - // } else if (mem.eql(u8, got, "1")) { - // log_level = .warn; - // } else if (mem.eql(u8, got, "2")) { - // log_level = .info; - // } else if (mem.eql(u8, got, "3")) { - // log_level = .debug; - // } else { - // std.debug.print( - // "warning: unrecognized {s}={s}. Expected between 0 and 3\n", - // .{ ENV_LOGLEVEL, got }, - // ); + //const verbose = blk: { + // if (os.getenvZ(ENV_LOGLEVEL)) |env| { + // const got = mem.sliceTo(env, 0); + // if (mem.eql(u8, got, "0")) { + // break :blk false; + // } else if (mem.eql(u8, got, "1")) { + // break :blk true; + // } else { + // std.debug.print( + // "warning: unrecognized {s}={s}. Expected between 0 or 1\n", + // .{ ENV_LOGLEVEL, got }, + // ); + // } // } - //} + // break :blk false; + //}; - const omit_members = blk: { - if (os.getenvZ(ENV_OMIT_MEMBERS)) |env| { - const got = mem.sliceTo(env, 0); - if (mem.eql(u8, got, "1")) { - break :blk true; - } else if (mem.eql(u8, got, "0")) { - break :blk false; - } else if (mem.eql(u8, got, "auto")) { - // not set, do autodiscover - } else { - std.debug.print( - "warning: unrecognized {s}={s}. Expected 0, 1 or auto\n", - .{ ENV_OMIT_MEMBERS, got }, - ); - } - } - if (os.argv.len == 0) break :blk false; - break :blk mem.eql(u8, mem.sliceTo(os.argv[0], 0), "id"); - }; - log.debug("omitting members from getgr* calls: {any}\n", .{omit_members}); + //const omit_members = blk: { + // if (os.getenvZ(ENV_OMIT_MEMBERS)) |env| { + // const got = mem.sliceTo(env, 0); + // if (mem.eql(u8, got, "1")) { + // break :blk true; + // } else if (mem.eql(u8, got, "0")) { + // break :blk false; + // } else if (mem.eql(u8, got, "auto")) { + // // not set, do autodiscover + // } else { + // std.debug.print( + // "warning: unrecognized {s}={s}. Expected 0, 1 or auto\n", + // .{ ENV_OMIT_MEMBERS, got }, + // ); + // } + // } + // if (os.argv.len == 0) break :blk false; + // break :blk mem.eql(u8, mem.sliceTo(os.argv[0], 0), "id"); + //}; - const fname = os.getenvZ(ENV_DB) orelse turbonss_db_path; - log.debug("opening '{s}'", .{fname}); + //if (verbose) + // std.debug.print("omitting members from getgr* calls: {any}\n", .{omit_members}); + + //const fname = os.getenvZ(ENV_DB) orelse turbonss_db_path; + //if (verbose) + // std.debug.print("opening '{s}'\n", .{fname}); + const fname = turbonss_db_path; + const verbose = true; + const omit_members = true; const file = File.open(fname) catch |err| { - log.warn("open '{s}': {s}", .{ fname, @errorName(err) }); + if (verbose) + std.debug.print("open '{s}': {s}\n", .{ fname, @errorName(err) }); return; }; - log.debug("turbonss database opened", .{}); + + if (verbose) + std.debug.print("turbonss database opened\n", .{}); global_state = State{ .file = file, + .v = verbose, .omit_members = omit_members, .initgroups_dyn_allocator = heap.raw_c_allocator, }; @@ -115,7 +122,7 @@ 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); + return getpwuid_r(db, uid, passwd, buffer, buflen, errnop); } fn getpwuid_r( @@ -150,7 +157,7 @@ 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); + return getpwnam_r(db, name, passwd, buffer, buflen, errnop); } fn getpwnam_r( @@ -188,7 +195,7 @@ 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); + return getgrgid_r(state, gid, gr, buffer, buflen, errnop); } fn getgrgid_r( @@ -227,7 +234,7 @@ 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); + return getgrnam_r(state, name, group, buffer, buflen, errnop); } fn getgrnam_r( @@ -256,13 +263,13 @@ fn getgrnam_r( return c.NSS_STATUS_SUCCESS; } -export fn _nss_turbo_setpwent(_: c_int) void { +export fn _nss_turbo_setpwent(_: c_int) c.enum_nss_status { global_init.call(); - var state = global_state orelse return; - setpwent(&state); + var state = global_state orelse return c.NSS_STATUS_UNAVAIL; + return setpwent(&state); } -fn setpwent(state: *State) void { +fn setpwent(state: *State) c.enum_nss_status { state.getpwent_iterator_mu.lock(); defer state.getpwent_iterator_mu.unlock(); @@ -272,43 +279,51 @@ fn setpwent(state: *State) void { db.header.num_users, db.shellReader(), ); + std.debug.print("state.getpwent_iterator: {*}\n", .{ + &state.getpwent_iterator.?, + }); + return c.NSS_STATUS_SUCCESS; } -export fn _nss_turbo_endpwent() void { +export fn _nss_turbo_endpwent() c.enum_nss_status { global_init.call(); - var state = global_state orelse return; - endpwent(&state); + var state = global_state orelse return c.NSS_STATUS_UNAVAIL; + return endpwent(&state); } -fn endpwent(state: *State) void { +fn endpwent(state: *State) c.enum_nss_status { + std.debug.print("endpwent\n", .{}); state.getpwent_iterator_mu.lock(); state.getpwent_iterator = null; state.getpwent_iterator_mu.unlock(); + return c.NSS_STATUS_SUCCESS; } -export fn _nss_turbo_setgrent(_: c_int) void { - var state = getState() orelse return; - setgrent(&state); +export fn _nss_turbo_setgrent(_: c_int) c.enum_nss_status { + var state = getState() orelse return c.NSS_STATUS_UNAVAIL; + return setgrent(&state); } -fn setgrent(state: *State) void { +fn setgrent(state: *State) c.enum_nss_status { state.getgrent_iterator_mu.lock(); defer state.getgrent_iterator_mu.unlock(); state.getgrent_iterator = PackedGroup.iterator( state.file.db.groups, state.file.db.header.num_groups, ); + return c.NSS_STATUS_SUCCESS; } -export fn _nss_turbo_endgrent() void { - var state = getState() orelse return; - endgrent(&state); +export fn _nss_turbo_endgrent() c.enum_nss_status { + var state = getState() orelse return c.NSS_STATUS_UNAVAIL; + return endgrent(&state); } -fn endgrent(state: *State) void { +fn endgrent(state: *State) c.enum_nss_status { state.getgrent_iterator_mu.lock(); state.getgrent_iterator = null; state.getgrent_iterator_mu.unlock(); + return c.NSS_STATUS_SUCCESS; } export fn _nss_turbo_getgrent_r( @@ -318,7 +333,7 @@ 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); + return getgrent_r(state, result, buffer, buflen, errnop); } fn getgrent_r( @@ -338,7 +353,7 @@ fn getgrent_r( }; const group = it.next() orelse { - errnop.* = @enumToInt(os.E.NOENT); + errnop.* = 0; return c.NSS_STATUS_NOTFOUND; }; @@ -365,7 +380,7 @@ 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); + return getpwent_r(state, result, buffer, buflen, errnop); } fn getpwent_r( @@ -378,14 +393,17 @@ fn getpwent_r( state.getpwent_iterator_mu.lock(); defer state.getpwent_iterator_mu.unlock(); + std.debug.print("starting getpwent_r\n", .{}); var it = state.getpwent_iterator orelse { // logic from _nss_systemd_getgrent_r + std.debug.print("no iterator, bailing\n", .{}); errnop.* = @enumToInt(os.E.HOSTDOWN); return c.NSS_STATUS_UNAVAIL; }; const user = it.next() orelse { - errnop.* = @enumToInt(os.E.NOENT); + std.debug.print("end of iteration, returning 0\n", .{}); + errnop.* = 0; return c.NSS_STATUS_NOTFOUND; }; @@ -411,7 +429,7 @@ export fn _nss_turbo_initgroups_dyn( errnop: *c_int, ) c.enum_nss_status { const state = getStateErrno(errnop) orelse return c.NSS_STATUS_UNAVAIL; - return initgroups_dyn(&state, user_name, gid, start, size, groupsp, limit, errnop); + return initgroups_dyn(state, user_name, gid, start, size, groupsp, limit, errnop); } fn initgroups_dyn( @@ -475,9 +493,9 @@ fn getState() ?State { return global_state; } -fn getStateErrno(errnop: *c_int) ?State { +fn getStateErrno(errnop: *c_int) ?*State { global_init.call(); - if (global_state) |state| { + if (global_state) |*state| { return state; } else { errnop.* = @enumToInt(os.E.AGAIN); @@ -485,9 +503,9 @@ fn getStateErrno(errnop: *c_int) ?State { } } -fn getDBErrno(errnop: *c_int) ?DB { +fn getDBErrno(errnop: *c_int) ?*const DB { if (getStateErrno(errnop)) |state| { - return state.file.db; + return &state.file.db; } else return null; } @@ -548,18 +566,19 @@ fn testVidmantas(u: CUser) !void { test "libnss getgrgid_r and getgrnam_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 buf: [1024]u8 = undefined; var errno: c_int = 0; var group: CGroup = undefined; try testing.expectEqual( c.NSS_STATUS_SUCCESS, - _nss_turbo_getgrgid_r(100000, &group, &buf, buf.len, &errno), + getgrgid_r(&state, 100000, &group, &buf, buf.len, &errno), ); try testing.expectEqual(@as(c_int, 0), errno); try testSvcGroup(group); @@ -567,7 +586,7 @@ test "libnss getgrgid_r and getgrnam_r" { group = undefined; try testing.expectEqual( c.NSS_STATUS_SUCCESS, - _nss_turbo_getgrnam_r("service-group", &group, &buf, buf.len, &errno), + getgrnam_r(&state, "service-group", &group, &buf, buf.len, &errno), ); try testing.expectEqual(@as(c_int, 0), errno); try testSvcGroup(group); @@ -575,7 +594,7 @@ test "libnss getgrgid_r and getgrnam_r" { group = undefined; try testing.expectEqual( c.NSS_STATUS_NOTFOUND, - _nss_turbo_getgrnam_r("does not exist", &group, &buf, buf.len, &errno), + getgrnam_r(&state, "does not exist", &group, &buf, buf.len, &errno), ); try testing.expectEqual(@enumToInt(os.E.NOENT), @intCast(u16, errno)); }