tests for initgroups_dyn
This commit is contained in:
@@ -3,9 +3,11 @@ const os = std.os;
|
||||
const fmt = std.fmt;
|
||||
const log = std.log;
|
||||
const mem = std.mem;
|
||||
const process = std.process;
|
||||
const math = std.math;
|
||||
const heap = std.heap;
|
||||
const once = std.once;
|
||||
const Mutex = std.Thread.Mutex;
|
||||
const Allocator = mem.Allocator;
|
||||
|
||||
const DB = @import("DB.zig");
|
||||
const File = @import("File.zig");
|
||||
@@ -39,6 +41,9 @@ const State = struct {
|
||||
|
||||
getgrent_iterator_mu: Mutex = Mutex{},
|
||||
getgrent_iterator: ?PackedGroup.Iterator = null,
|
||||
|
||||
// allocator for
|
||||
initgroups_dyn_allocator: Allocator,
|
||||
};
|
||||
|
||||
// global_state is initialized on first call to an nss function
|
||||
@@ -98,6 +103,7 @@ fn init() void {
|
||||
global_state = State{
|
||||
.file = file,
|
||||
.omit_members = omit_members,
|
||||
.initgroups_dyn_allocator = heap.raw_c_allocator,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -329,24 +335,56 @@ export fn _nss_turbo_initgroups_dyn(
|
||||
_: u32,
|
||||
start: *c_long,
|
||||
size: *c_long,
|
||||
groups: [*]u32,
|
||||
groupsp: *[*]u32,
|
||||
limit: c_long,
|
||||
errnop: *c_int,
|
||||
) c.enum_nss_status {
|
||||
const db = getDBErrno(errnop) orelse return c.NSS_STATUS_UNAVAIL;
|
||||
const state = getStateErrno(errnop) orelse return c.NSS_STATUS_UNAVAIL;
|
||||
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;
|
||||
};
|
||||
|
||||
_ = user;
|
||||
_ = start;
|
||||
_ = size;
|
||||
_ = groups;
|
||||
_ = limit;
|
||||
var gids = db.userGids(user.additional_gids_offset);
|
||||
if (size.* < gids.remaining()) {
|
||||
const oldsize = @intCast(usize, size.*);
|
||||
const newsize = if (limit <= 0)
|
||||
oldsize + gids.remaining()
|
||||
else
|
||||
math.min(@intCast(usize, limit), oldsize + gids.remaining());
|
||||
|
||||
return c.NSS_STATUS_SUCCESS;
|
||||
var buf = groupsp.*[0..oldsize];
|
||||
const new_groups = state.initgroups_dyn_allocator.realloc(buf, newsize);
|
||||
if (new_groups) |newgroups| {
|
||||
groupsp.* = newgroups.ptr;
|
||||
size.* = @intCast(c_long, newsize);
|
||||
} else |err| switch (err) {
|
||||
error.OutOfMemory => {
|
||||
errnop.* = @enumToInt(os.E.NOMEM);
|
||||
return c.NSS_STATUS_TRYAGAIN;
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// I was not able to understand the expected behavior of limit. In glibc
|
||||
// compat-initgroups.c limit is used to malloc the buffer. Something like
|
||||
// this is all over the place:
|
||||
// if (limit > 0 && *size == limit) /* We reached the maximum. */
|
||||
// return;
|
||||
// Our implementation will thus limit the number of *added* entries.
|
||||
|
||||
var added: usize = 0;
|
||||
while (gids.nextMust()) |gid| {
|
||||
if (limit > 0 and added == limit) break;
|
||||
|
||||
added += 1;
|
||||
groupsp.*[@intCast(usize, start.*)] = @intCast(u32, gid);
|
||||
start.* += 1;
|
||||
}
|
||||
|
||||
return if (added > 0) c.NSS_STATUS_SUCCESS else c.NSS_STATUS_NOTFOUND;
|
||||
}
|
||||
|
||||
fn getState() ?State {
|
||||
@@ -459,6 +497,39 @@ test "getgrgid_r and getgrnam_r" {
|
||||
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 size: c_long = 3; // size of the gids array is this
|
||||
var groups = try allocator.alloc(u32, @intCast(usize, size)); // buffer too small
|
||||
defer allocator.free(groups);
|
||||
var errno: c_int = 42; // canary
|
||||
groups[0] = 42; // canary
|
||||
var start: c_long = 1; // canary is there
|
||||
|
||||
const status = _nss_turbo_initgroups_dyn(
|
||||
"vidmantas",
|
||||
0, // gid, ignored
|
||||
&start,
|
||||
&size,
|
||||
&groups.ptr,
|
||||
3, // limit: besides canary accept 2 groups
|
||||
&errno,
|
||||
);
|
||||
try testing.expectEqual(c.NSS_STATUS_SUCCESS, status);
|
||||
try testing.expectEqual(@as(c_int, 42), errno);
|
||||
try testing.expectEqual(@as(u32, 42), groups[0]);
|
||||
try testing.expectEqual(@as(u32, 128), groups[1]);
|
||||
}
|
||||
|
||||
fn testVidmantasGroup(g: CGroup) !void {
|
||||
try testing.expectEqual(@as(u32, 128), g.gid);
|
||||
try testing.expectEqualStrings("vidmantas", mem.sliceTo(g.name, 0));
|
||||
|
||||
Reference in New Issue
Block a user