libnss: pass state explicitly

This commit is contained in:
Motiejus Jakštys 2022-07-09 16:50:49 +03:00
parent f327fb24ba
commit 78ac541e49
2 changed files with 119 additions and 32 deletions

View File

@ -39,9 +39,10 @@ pub fn close(self: *File) void {
const testing = std.testing; const testing = std.testing;
pub const TestDB = struct { pub const TestDB = struct {
allocator: Allocator, file: File,
dir: testing.TmpDir, dir: testing.TmpDir,
path: [:0]const u8, path: [:0]const u8,
allocator: Allocator,
pub fn init(allocator: Allocator) !TestDB { pub fn init(allocator: Allocator) !TestDB {
var errc = ErrCtx{}; var errc = ErrCtx{};
@ -65,9 +66,9 @@ pub const TestDB = struct {
break :blk real_path; 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, base_path,
"db.turbo\x00", "db.turbo",
}); });
allocator.free(base_path); allocator.free(base_path);
@ -78,8 +79,9 @@ pub const TestDB = struct {
_ = try os.writev(fd, db.iov().constSlice()); _ = try os.writev(fd, db.iov().constSlice());
return TestDB{ return TestDB{
.file = try open(full_path),
.dir = tmp, .dir = tmp,
.path = full_path[0 .. full_path.len - 1 :0], .path = full_path,
.allocator = allocator, .allocator = allocator,
}; };
} }

View File

@ -115,7 +115,17 @@ 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);
}
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) { var cuser = db.getpwuid(uid, buffer[0..buflen]) catch |err| switch (err) {
error.BufferTooSmall => { error.BufferTooSmall => {
errnop.* = @enumToInt(os.E.RANGE); errnop.* = @enumToInt(os.E.RANGE);
@ -140,6 +150,17 @@ 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);
}
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); const nameSlice = mem.sliceTo(name, 0);
var buf = buffer[0..buflen]; var buf = buffer[0..buflen];
@ -167,6 +188,17 @@ 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);
}
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 db = state.file.db;
const omit_members = state.omit_members; const omit_members = state.omit_members;
@ -195,9 +227,19 @@ 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);
}
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 db = state.file.db;
const omit_members = state.omit_members; const omit_members = state.omit_members;
const nameSlice = mem.sliceTo(name, 0); const nameSlice = mem.sliceTo(name, 0);
var buf = buffer[0..buflen]; var buf = buffer[0..buflen];
var cgroup = db.getgrnam(nameSlice, buf, omit_members) catch |err| switch (err) { 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; return c.NSS_STATUS_TRYAGAIN;
}, },
}; };
const got_cgroup = cgroup orelse { const got_cgroup = cgroup orelse {
errnop.* = @enumToInt(os.E.NOENT); errnop.* = @enumToInt(os.E.NOENT);
return c.NSS_STATUS_NOTFOUND; return c.NSS_STATUS_NOTFOUND;
}; };
group.* = got_cgroup; group.* = got_cgroup;
return c.NSS_STATUS_SUCCESS; return c.NSS_STATUS_SUCCESS;
} }
@ -219,7 +259,10 @@ export fn _nss_turbo_getgrnam_r(
export fn _nss_turbo_setpwent(_: c_int) void { export fn _nss_turbo_setpwent(_: c_int) void {
global_init.call(); global_init.call();
var state = global_state orelse return; var state = global_state orelse return;
setpwent(&state);
}
fn setpwent(state: *State) void {
state.getpwent_iterator_mu.lock(); state.getpwent_iterator_mu.lock();
defer state.getpwent_iterator_mu.unlock(); defer state.getpwent_iterator_mu.unlock();
@ -235,7 +278,10 @@ export fn _nss_turbo_setpwent(_: c_int) void {
export fn _nss_turbo_endpwent() void { export fn _nss_turbo_endpwent() void {
global_init.call(); global_init.call();
var state = global_state orelse return; var state = global_state orelse return;
endpwent(&state);
}
fn endpwent(state: *State) void {
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();
@ -243,6 +289,10 @@ export fn _nss_turbo_endpwent() void {
export fn _nss_turbo_setgrent(_: c_int) void { export fn _nss_turbo_setgrent(_: c_int) void {
var state = getState() orelse return; var state = getState() orelse return;
setgrent(&state);
}
fn setgrent(state: *State) void {
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(
@ -252,7 +302,10 @@ export fn _nss_turbo_setgrent(_: c_int) void {
export fn _nss_turbo_endgrent() void { export fn _nss_turbo_endgrent() void {
var state = getState() orelse return; var state = getState() orelse return;
endgrent(&state);
}
fn endgrent(state: *State) void {
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();
@ -265,7 +318,16 @@ 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);
}
fn getgrent_r(
state: *State,
result: *CGroup,
buffer: [*]u8,
buflen: usize,
errnop: *c_int,
) 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();
@ -303,7 +365,16 @@ 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);
}
fn getpwent_r(
state: *State,
result: *CUser,
buffer: [*]u8,
buflen: usize,
errnop: *c_int,
) 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();
@ -332,7 +403,7 @@ export fn _nss_turbo_getpwent_r(
export fn _nss_turbo_initgroups_dyn( export fn _nss_turbo_initgroups_dyn(
user_name: [*:0]const u8, user_name: [*:0]const u8,
_: u32, gid: u32,
start: *c_long, start: *c_long,
size: *c_long, size: *c_long,
groupsp: *[*]u32, groupsp: *[*]u32,
@ -340,8 +411,20 @@ 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;
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 { const user = db.getUser(mem.sliceTo(user_name, 0)) orelse {
errnop.* = @enumToInt(os.E.NOENT); errnop.* = @enumToInt(os.E.NOENT);
return c.NSS_STATUS_NOTFOUND; return c.NSS_STATUS_NOTFOUND;
@ -413,19 +496,19 @@ const testing = std.testing;
test "getpwuid_r and getpwnam_r" { test "getpwuid_r and getpwnam_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; const state = State{
turbonss_db_path = tf.path; .file = tf.file,
defer { .omit_members = false,
turbonss_db_path = turbonss_db_path_old; .initgroups_dyn_allocator = testing.failing_allocator,
} };
var buffer: [1024]u8 = undefined; var buf: [1024]u8 = undefined;
var errno: c_int = 0; var errno: c_int = 0;
var passwd: CUser = undefined; var passwd: CUser = undefined;
try testing.expectEqual( try testing.expectEqual(
c.NSS_STATUS_SUCCESS, 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 testing.expectEqual(@as(c_int, 0), errno);
try testVidmantas(passwd); try testVidmantas(passwd);
@ -433,7 +516,7 @@ test "getpwuid_r and getpwnam_r" {
passwd = undefined; passwd = undefined;
try testing.expectEqual( try testing.expectEqual(
c.NSS_STATUS_SUCCESS, 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 testing.expectEqual(@as(c_int, 0), errno);
try testVidmantas(passwd); try testVidmantas(passwd);
@ -441,7 +524,7 @@ test "getpwuid_r and getpwnam_r" {
passwd = undefined; passwd = undefined;
try testing.expectEqual( try testing.expectEqual(
c.NSS_STATUS_NOTFOUND, 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)); 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; var small_buffer: [1]u8 = undefined;
try testing.expectEqual( try testing.expectEqual(
c.NSS_STATUS_TRYAGAIN, 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)); 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; turbonss_db_path = turbonss_db_path_old;
} }
var buffer: [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(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 testing.expectEqual(@as(c_int, 0), errno);
try testVidmantasGroup(group); try testVidmantasGroup(group);
@ -484,7 +567,7 @@ test "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("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 testing.expectEqual(@as(c_int, 0), errno);
try testVidmantasGroup(group); try testVidmantasGroup(group);
@ -492,21 +575,21 @@ test "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, &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)); try testing.expectEqual(@enumToInt(os.E.NOENT), @intCast(u16, errno));
} }
test "initgroups_dyn" { 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; 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 size: c_long = 3; // size of the gids array is this
var groups = try allocator.alloc(u32, @intCast(usize, size)); // buffer too small var groups = try allocator.alloc(u32, @intCast(usize, size)); // buffer too small
@ -515,7 +598,8 @@ test "initgroups_dyn" {
groups[0] = 42; // canary groups[0] = 42; // canary
var start: c_long = 1; // canary is there var start: c_long = 1; // canary is there
const status = _nss_turbo_initgroups_dyn( const status = initgroups_dyn(
&state,
"vidmantas", "vidmantas",
0, // gid, ignored 0, // gid, ignored
&start, &start,
@ -528,6 +612,7 @@ test "initgroups_dyn" {
try testing.expectEqual(@as(c_int, 42), errno); try testing.expectEqual(@as(c_int, 42), errno);
try testing.expectEqual(@as(u32, 42), groups[0]); try testing.expectEqual(@as(u32, 42), groups[0]);
try testing.expectEqual(@as(u32, 128), groups[1]); try testing.expectEqual(@as(u32, 128), groups[1]);
try testing.expectEqual(@as(u32, 9999), groups[2]);
} }
fn testVidmantasGroup(g: CGroup) !void { fn testVidmantasGroup(g: CGroup) !void {