fixes for libnss.zig
- global state is a pointer; avoid copying - fix getgr* tests
This commit is contained in:
parent
abf7edf14c
commit
43015f4d1d
179
src/libnss.zig
179
src/libnss.zig
@ -1,7 +1,6 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const os = std.os;
|
const os = std.os;
|
||||||
const fmt = std.fmt;
|
const fmt = std.fmt;
|
||||||
const log = std.log;
|
|
||||||
const mem = std.mem;
|
const mem = std.mem;
|
||||||
const math = std.math;
|
const math = std.math;
|
||||||
const heap = std.heap;
|
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";
|
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:
|
// State is a type of the global variable holding the process state:
|
||||||
// the DB handle and all the iterators.
|
// the DB handle and all the iterators.
|
||||||
const State = struct {
|
const State = struct {
|
||||||
file: File,
|
file: File,
|
||||||
omit_members: bool,
|
omit_members: bool,
|
||||||
|
v: bool = false,
|
||||||
|
|
||||||
getpwent_iterator_mu: Mutex = Mutex{},
|
getpwent_iterator_mu: Mutex = Mutex{},
|
||||||
getpwent_iterator: ?PackedUser.Iterator = null,
|
getpwent_iterator: ?PackedUser.Iterator = null,
|
||||||
@ -52,56 +50,65 @@ var global_init = once(init);
|
|||||||
|
|
||||||
// assigns State from environment variables et al
|
// assigns State from environment variables et al
|
||||||
fn init() void {
|
fn init() void {
|
||||||
//if (os.getenvZ(ENV_LOGLEVEL)) |env| {
|
//const verbose = blk: {
|
||||||
// const got = mem.sliceTo(env, 0);
|
// if (os.getenvZ(ENV_LOGLEVEL)) |env| {
|
||||||
// if (mem.eql(u8, got, "0")) {
|
// const got = mem.sliceTo(env, 0);
|
||||||
// log_level = .err;
|
// if (mem.eql(u8, got, "0")) {
|
||||||
// } else if (mem.eql(u8, got, "1")) {
|
// break :blk false;
|
||||||
// log_level = .warn;
|
// } else if (mem.eql(u8, got, "1")) {
|
||||||
// } else if (mem.eql(u8, got, "2")) {
|
// break :blk true;
|
||||||
// log_level = .info;
|
// } else {
|
||||||
// } else if (mem.eql(u8, got, "3")) {
|
// std.debug.print(
|
||||||
// log_level = .debug;
|
// "warning: unrecognized {s}={s}. Expected between 0 or 1\n",
|
||||||
// } else {
|
// .{ ENV_LOGLEVEL, got },
|
||||||
// std.debug.print(
|
// );
|
||||||
// "warning: unrecognized {s}={s}. Expected between 0 and 3\n",
|
// }
|
||||||
// .{ ENV_LOGLEVEL, got },
|
|
||||||
// );
|
|
||||||
// }
|
// }
|
||||||
//}
|
// break :blk false;
|
||||||
|
//};
|
||||||
|
|
||||||
const omit_members = blk: {
|
//const omit_members = blk: {
|
||||||
if (os.getenvZ(ENV_OMIT_MEMBERS)) |env| {
|
// if (os.getenvZ(ENV_OMIT_MEMBERS)) |env| {
|
||||||
const got = mem.sliceTo(env, 0);
|
// const got = mem.sliceTo(env, 0);
|
||||||
if (mem.eql(u8, got, "1")) {
|
// if (mem.eql(u8, got, "1")) {
|
||||||
break :blk true;
|
// break :blk true;
|
||||||
} else if (mem.eql(u8, got, "0")) {
|
// } else if (mem.eql(u8, got, "0")) {
|
||||||
break :blk false;
|
// break :blk false;
|
||||||
} else if (mem.eql(u8, got, "auto")) {
|
// } else if (mem.eql(u8, got, "auto")) {
|
||||||
// not set, do autodiscover
|
// // not set, do autodiscover
|
||||||
} else {
|
// } else {
|
||||||
std.debug.print(
|
// std.debug.print(
|
||||||
"warning: unrecognized {s}={s}. Expected 0, 1 or auto\n",
|
// "warning: unrecognized {s}={s}. Expected 0, 1 or auto\n",
|
||||||
.{ ENV_OMIT_MEMBERS, got },
|
// .{ ENV_OMIT_MEMBERS, got },
|
||||||
);
|
// );
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
if (os.argv.len == 0) break :blk false;
|
// if (os.argv.len == 0) break :blk false;
|
||||||
break :blk mem.eql(u8, mem.sliceTo(os.argv[0], 0), "id");
|
// break :blk mem.eql(u8, mem.sliceTo(os.argv[0], 0), "id");
|
||||||
};
|
//};
|
||||||
log.debug("omitting members from getgr* calls: {any}\n", .{omit_members});
|
|
||||||
|
|
||||||
const fname = os.getenvZ(ENV_DB) orelse turbonss_db_path;
|
//if (verbose)
|
||||||
log.debug("opening '{s}'", .{fname});
|
// 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| {
|
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;
|
return;
|
||||||
};
|
};
|
||||||
log.debug("turbonss database opened", .{});
|
|
||||||
|
if (verbose)
|
||||||
|
std.debug.print("turbonss database opened\n", .{});
|
||||||
|
|
||||||
global_state = State{
|
global_state = State{
|
||||||
.file = file,
|
.file = file,
|
||||||
|
.v = verbose,
|
||||||
.omit_members = omit_members,
|
.omit_members = omit_members,
|
||||||
.initgroups_dyn_allocator = heap.raw_c_allocator,
|
.initgroups_dyn_allocator = heap.raw_c_allocator,
|
||||||
};
|
};
|
||||||
@ -115,7 +122,7 @@ export fn _nss_turbo_getpwuid_r(
|
|||||||
errnop: *c_int,
|
errnop: *c_int,
|
||||||
) c.enum_nss_status {
|
) c.enum_nss_status {
|
||||||
const db = getDBErrno(errnop) orelse return c.NSS_STATUS_UNAVAIL;
|
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(
|
fn getpwuid_r(
|
||||||
@ -150,7 +157,7 @@ export fn _nss_turbo_getpwnam_r(
|
|||||||
errnop: *c_int,
|
errnop: *c_int,
|
||||||
) c.enum_nss_status {
|
) c.enum_nss_status {
|
||||||
const db = getDBErrno(errnop) orelse return c.NSS_STATUS_UNAVAIL;
|
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(
|
fn getpwnam_r(
|
||||||
@ -188,7 +195,7 @@ export fn _nss_turbo_getgrgid_r(
|
|||||||
errnop: *c_int,
|
errnop: *c_int,
|
||||||
) c.enum_nss_status {
|
) c.enum_nss_status {
|
||||||
const state = getStateErrno(errnop) orelse return c.NSS_STATUS_UNAVAIL;
|
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(
|
fn getgrgid_r(
|
||||||
@ -227,7 +234,7 @@ export fn _nss_turbo_getgrnam_r(
|
|||||||
errnop: *c_int,
|
errnop: *c_int,
|
||||||
) c.enum_nss_status {
|
) c.enum_nss_status {
|
||||||
const state = getStateErrno(errnop) orelse return c.NSS_STATUS_UNAVAIL;
|
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(
|
fn getgrnam_r(
|
||||||
@ -256,13 +263,13 @@ fn getgrnam_r(
|
|||||||
return c.NSS_STATUS_SUCCESS;
|
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();
|
global_init.call();
|
||||||
var state = global_state orelse return;
|
var state = global_state orelse return c.NSS_STATUS_UNAVAIL;
|
||||||
setpwent(&state);
|
return setpwent(&state);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn setpwent(state: *State) void {
|
fn setpwent(state: *State) c.enum_nss_status {
|
||||||
state.getpwent_iterator_mu.lock();
|
state.getpwent_iterator_mu.lock();
|
||||||
defer state.getpwent_iterator_mu.unlock();
|
defer state.getpwent_iterator_mu.unlock();
|
||||||
|
|
||||||
@ -272,43 +279,51 @@ fn setpwent(state: *State) void {
|
|||||||
db.header.num_users,
|
db.header.num_users,
|
||||||
db.shellReader(),
|
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();
|
global_init.call();
|
||||||
var state = global_state orelse return;
|
var state = global_state orelse return c.NSS_STATUS_UNAVAIL;
|
||||||
endpwent(&state);
|
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_mu.lock();
|
||||||
state.getpwent_iterator = null;
|
state.getpwent_iterator = null;
|
||||||
state.getpwent_iterator_mu.unlock();
|
state.getpwent_iterator_mu.unlock();
|
||||||
|
return c.NSS_STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
export fn _nss_turbo_setgrent(_: c_int) void {
|
export fn _nss_turbo_setgrent(_: c_int) c.enum_nss_status {
|
||||||
var state = getState() orelse return;
|
var state = getState() orelse return c.NSS_STATUS_UNAVAIL;
|
||||||
setgrent(&state);
|
return setgrent(&state);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn setgrent(state: *State) void {
|
fn setgrent(state: *State) c.enum_nss_status {
|
||||||
state.getgrent_iterator_mu.lock();
|
state.getgrent_iterator_mu.lock();
|
||||||
defer state.getgrent_iterator_mu.unlock();
|
defer state.getgrent_iterator_mu.unlock();
|
||||||
state.getgrent_iterator = PackedGroup.iterator(
|
state.getgrent_iterator = PackedGroup.iterator(
|
||||||
state.file.db.groups,
|
state.file.db.groups,
|
||||||
state.file.db.header.num_groups,
|
state.file.db.header.num_groups,
|
||||||
);
|
);
|
||||||
|
return c.NSS_STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
export fn _nss_turbo_endgrent() void {
|
export fn _nss_turbo_endgrent() c.enum_nss_status {
|
||||||
var state = getState() orelse return;
|
var state = getState() orelse return c.NSS_STATUS_UNAVAIL;
|
||||||
endgrent(&state);
|
return endgrent(&state);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn endgrent(state: *State) void {
|
fn endgrent(state: *State) c.enum_nss_status {
|
||||||
state.getgrent_iterator_mu.lock();
|
state.getgrent_iterator_mu.lock();
|
||||||
state.getgrent_iterator = null;
|
state.getgrent_iterator = null;
|
||||||
state.getgrent_iterator_mu.unlock();
|
state.getgrent_iterator_mu.unlock();
|
||||||
|
return c.NSS_STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
export fn _nss_turbo_getgrent_r(
|
export fn _nss_turbo_getgrent_r(
|
||||||
@ -318,7 +333,7 @@ export fn _nss_turbo_getgrent_r(
|
|||||||
errnop: *c_int,
|
errnop: *c_int,
|
||||||
) c.enum_nss_status {
|
) c.enum_nss_status {
|
||||||
var state = getStateErrno(errnop) orelse return c.NSS_STATUS_UNAVAIL;
|
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(
|
fn getgrent_r(
|
||||||
@ -338,7 +353,7 @@ fn getgrent_r(
|
|||||||
};
|
};
|
||||||
|
|
||||||
const group = it.next() orelse {
|
const group = it.next() orelse {
|
||||||
errnop.* = @enumToInt(os.E.NOENT);
|
errnop.* = 0;
|
||||||
return c.NSS_STATUS_NOTFOUND;
|
return c.NSS_STATUS_NOTFOUND;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -365,7 +380,7 @@ export fn _nss_turbo_getpwent_r(
|
|||||||
errnop: *c_int,
|
errnop: *c_int,
|
||||||
) c.enum_nss_status {
|
) c.enum_nss_status {
|
||||||
var state = getStateErrno(errnop) orelse return c.NSS_STATUS_UNAVAIL;
|
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(
|
fn getpwent_r(
|
||||||
@ -378,14 +393,17 @@ fn getpwent_r(
|
|||||||
state.getpwent_iterator_mu.lock();
|
state.getpwent_iterator_mu.lock();
|
||||||
defer state.getpwent_iterator_mu.unlock();
|
defer state.getpwent_iterator_mu.unlock();
|
||||||
|
|
||||||
|
std.debug.print("starting getpwent_r\n", .{});
|
||||||
var it = state.getpwent_iterator orelse {
|
var it = state.getpwent_iterator orelse {
|
||||||
// logic from _nss_systemd_getgrent_r
|
// logic from _nss_systemd_getgrent_r
|
||||||
|
std.debug.print("no iterator, bailing\n", .{});
|
||||||
errnop.* = @enumToInt(os.E.HOSTDOWN);
|
errnop.* = @enumToInt(os.E.HOSTDOWN);
|
||||||
return c.NSS_STATUS_UNAVAIL;
|
return c.NSS_STATUS_UNAVAIL;
|
||||||
};
|
};
|
||||||
|
|
||||||
const user = it.next() orelse {
|
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;
|
return c.NSS_STATUS_NOTFOUND;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -411,7 +429,7 @@ export fn _nss_turbo_initgroups_dyn(
|
|||||||
errnop: *c_int,
|
errnop: *c_int,
|
||||||
) c.enum_nss_status {
|
) c.enum_nss_status {
|
||||||
const state = getStateErrno(errnop) orelse return c.NSS_STATUS_UNAVAIL;
|
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(
|
fn initgroups_dyn(
|
||||||
@ -475,9 +493,9 @@ fn getState() ?State {
|
|||||||
return global_state;
|
return global_state;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn getStateErrno(errnop: *c_int) ?State {
|
fn getStateErrno(errnop: *c_int) ?*State {
|
||||||
global_init.call();
|
global_init.call();
|
||||||
if (global_state) |state| {
|
if (global_state) |*state| {
|
||||||
return state;
|
return state;
|
||||||
} else {
|
} else {
|
||||||
errnop.* = @enumToInt(os.E.AGAIN);
|
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| {
|
if (getStateErrno(errnop)) |state| {
|
||||||
return state.file.db;
|
return &state.file.db;
|
||||||
} else return null;
|
} else return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -548,18 +566,19 @@ fn testVidmantas(u: CUser) !void {
|
|||||||
test "libnss getgrgid_r and getgrnam_r" {
|
test "libnss getgrgid_r and getgrnam_r" {
|
||||||
var tf = try File.TestDB.init(testing.allocator);
|
var tf = try File.TestDB.init(testing.allocator);
|
||||||
defer tf.deinit();
|
defer tf.deinit();
|
||||||
const turbonss_db_path_old = turbonss_db_path;
|
|
||||||
turbonss_db_path = tf.path;
|
const state = State{
|
||||||
defer {
|
.file = tf.file,
|
||||||
turbonss_db_path = turbonss_db_path_old;
|
.omit_members = false,
|
||||||
}
|
.initgroups_dyn_allocator = testing.failing_allocator,
|
||||||
|
};
|
||||||
|
|
||||||
var buf: [1024]u8 = undefined;
|
var buf: [1024]u8 = undefined;
|
||||||
var errno: c_int = 0;
|
var errno: c_int = 0;
|
||||||
var group: CGroup = undefined;
|
var group: CGroup = undefined;
|
||||||
try testing.expectEqual(
|
try testing.expectEqual(
|
||||||
c.NSS_STATUS_SUCCESS,
|
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 testing.expectEqual(@as(c_int, 0), errno);
|
||||||
try testSvcGroup(group);
|
try testSvcGroup(group);
|
||||||
@ -567,7 +586,7 @@ test "libnss getgrgid_r and getgrnam_r" {
|
|||||||
group = undefined;
|
group = undefined;
|
||||||
try testing.expectEqual(
|
try testing.expectEqual(
|
||||||
c.NSS_STATUS_SUCCESS,
|
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 testing.expectEqual(@as(c_int, 0), errno);
|
||||||
try testSvcGroup(group);
|
try testSvcGroup(group);
|
||||||
@ -575,7 +594,7 @@ test "libnss getgrgid_r and getgrnam_r" {
|
|||||||
group = undefined;
|
group = undefined;
|
||||||
try testing.expectEqual(
|
try testing.expectEqual(
|
||||||
c.NSS_STATUS_NOTFOUND,
|
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));
|
try testing.expectEqual(@enumToInt(os.E.NOENT), @intCast(u16, errno));
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user