tests for initgroups_dyn
This commit is contained in:
parent
5fa4a71ddf
commit
f327fb24ba
@ -260,10 +260,18 @@ pub fn testCorpus(allocator: Allocator) !Corpus {
|
||||
|
||||
var group0 = try Group.init(allocator, 0, "root", &[_][]const u8{"root"});
|
||||
var group1 = try Group.init(allocator, 128, "vidmantas", &[_][]const u8{"vidmantas"});
|
||||
const members2 = &[_][]const u8{ "svc-bar", "Name" ** 8, "vidmantas", "root" };
|
||||
var group2 = try Group.init(allocator, 9999, "all", members2);
|
||||
const members3 = &[_][]const u8{ "svc-bar", "vidmantas" };
|
||||
var group3 = try Group.init(allocator, 100000, "service-account", members3);
|
||||
var group2 = try Group.init(
|
||||
allocator,
|
||||
9999,
|
||||
"all",
|
||||
&[_][]const u8{ "svc-bar", "Name" ** 8, "vidmantas", "root" },
|
||||
);
|
||||
var group3 = try Group.init(
|
||||
allocator,
|
||||
100000,
|
||||
"service-account",
|
||||
&[_][]const u8{ "svc-bar", "vidmantas" },
|
||||
);
|
||||
defer group0.deinit(allocator);
|
||||
defer group1.deinit(allocator);
|
||||
defer group2.deinit(allocator);
|
||||
|
@ -313,7 +313,7 @@ pub fn packCGroup(self: *const DB, group: PackedGroup, buf: []u8) error{BufferTo
|
||||
member_ptrs[member_ptrs.len - 1] = null;
|
||||
var buf_offset: usize = ptr_end;
|
||||
|
||||
var it = compress.DeltaDecompressionIterator(&vit);
|
||||
var it = compress.deltaDecompressionIterator(&vit);
|
||||
var i: usize = 0;
|
||||
while (it.nextMust()) |member_offset| : (i += 1) {
|
||||
const entry = PackedUser.fromBytes(self.users[member_offset << 3 ..]);
|
||||
@ -647,6 +647,11 @@ fn groupsSection(
|
||||
};
|
||||
}
|
||||
|
||||
pub fn userGids(self: *const DB, offset: u64) compress.DeltaDecompressionIterator {
|
||||
var vit = compress.VarintSliceIteratorMust(self.additional_gids[offset..]);
|
||||
return compress.deltaDecompressionIterator(&vit);
|
||||
}
|
||||
|
||||
// creates a bdz index using packed_mphf.
|
||||
// hash = bdz_search(packed_mphf, keys[i]);
|
||||
// result[hash] = idx2offset[i];
|
||||
@ -830,7 +835,7 @@ test "additionalGids" {
|
||||
continue;
|
||||
}
|
||||
var vit = try compress.VarintSliceIterator(additional_gids.blob[offset..]);
|
||||
var it = compress.DeltaDecompressionIterator(&vit);
|
||||
var it = compress.deltaDecompressionIterator(&vit);
|
||||
try testing.expectEqual(it.remaining(), groups.len);
|
||||
var i: u64 = 0;
|
||||
const corpusGids = corpus.groups.items(.gid);
|
||||
|
@ -145,12 +145,12 @@ pub fn VarintSliceIteratorMust(arr: []const u8) varintSliceIterator {
|
||||
};
|
||||
}
|
||||
|
||||
const deltaDecompressionIterator = struct {
|
||||
pub const DeltaDecompressionIterator = struct {
|
||||
vit: *varintSliceIterator,
|
||||
prev: u64,
|
||||
add_to_prev: u1,
|
||||
|
||||
pub fn next(self: *deltaDecompressionIterator) error{Overflow}!?u64 {
|
||||
pub fn next(self: *DeltaDecompressionIterator) error{Overflow}!?u64 {
|
||||
const current = try self.vit.next();
|
||||
if (current == null) return null;
|
||||
|
||||
@ -163,19 +163,19 @@ const deltaDecompressionIterator = struct {
|
||||
|
||||
// returns the number of remaining items. If called before the first
|
||||
// next(), returns the length of the slice.
|
||||
pub fn remaining(self: *const deltaDecompressionIterator) usize {
|
||||
pub fn remaining(self: *const DeltaDecompressionIterator) usize {
|
||||
return self.vit.remaining;
|
||||
}
|
||||
|
||||
pub fn nextMust(self: *deltaDecompressionIterator) ?u64 {
|
||||
pub fn nextMust(self: *DeltaDecompressionIterator) ?u64 {
|
||||
return self.next() catch |err| switch (err) {
|
||||
error.Overflow => unreachable,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
pub fn DeltaDecompressionIterator(vit: *varintSliceIterator) deltaDecompressionIterator {
|
||||
return deltaDecompressionIterator{
|
||||
pub fn deltaDecompressionIterator(vit: *varintSliceIterator) DeltaDecompressionIterator {
|
||||
return DeltaDecompressionIterator{
|
||||
.vit = vit,
|
||||
.prev = 0,
|
||||
.add_to_prev = 0,
|
||||
@ -304,7 +304,7 @@ test "delta decompression with an iterator" {
|
||||
try appendUvarint(&buf, x);
|
||||
|
||||
var vit = try VarintSliceIterator(buf.items);
|
||||
var it = DeltaDecompressionIterator(&vit);
|
||||
var it = deltaDecompressionIterator(&vit);
|
||||
var i: usize = 0;
|
||||
try testing.expectEqual(it.remaining(), uvarint_tests.len);
|
||||
while (try it.next()) |got| : (i += 1) {
|
||||
|
@ -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));
|
||||
|
Loading…
Reference in New Issue
Block a user