passwd fields now have sentinels

This commit is contained in:
Motiejus Jakštys 2022-07-06 16:54:43 +03:00
parent 4a3d43561f
commit a63c60cc6f
4 changed files with 61 additions and 23 deletions

View File

@ -280,13 +280,13 @@ pub fn fromBytes(buf: []align(8) const u8) InvalidHeader!DB {
} }
// dumps PackedGroup to []u8 and returns a CGroup. // dumps PackedGroup to []u8 and returns a CGroup.
fn getGroup(self: *const DB, group: PackedGroup, buf: []u8) error{OutOfMemory}!CGroup { fn getGroup(self: *const DB, group: PackedGroup, buf: []u8) error{BufferTooSmall}!CGroup {
const members_slice = self.groupmembers[group.members_offset..]; const members_slice = self.groupmembers[group.members_offset..];
var vit = compress.VarintSliceIteratorMust(members_slice); var vit = compress.VarintSliceIteratorMust(members_slice);
const num_members = vit.remaining; const num_members = vit.remaining;
const ptr_end = @sizeOf(?[*:0]const u8) * (num_members + 1); const ptr_end = @sizeOf(?[*:0]const u8) * (num_members + 1);
if (ptr_end > buf.len) return error.OutOfMemory; if (ptr_end > buf.len) return error.BufferTooSmall;
var member_ptrs = mem.bytesAsSlice(?[*:0]const u8, buf[0..ptr_end]); var member_ptrs = mem.bytesAsSlice(?[*:0]const u8, buf[0..ptr_end]);
member_ptrs[member_ptrs.len - 1] = null; member_ptrs[member_ptrs.len - 1] = null;
var buf_offset: usize = ptr_end; var buf_offset: usize = ptr_end;
@ -297,7 +297,7 @@ fn getGroup(self: *const DB, group: PackedGroup, buf: []u8) error{OutOfMemory}!C
const entry = PackedUser.fromBytes(self.users[member_offset << 3 ..]); const entry = PackedUser.fromBytes(self.users[member_offset << 3 ..]);
const start = buf_offset; const start = buf_offset;
const name = entry.user.name(); const name = entry.user.name();
if (buf_offset + name.len + 1 > buf.len) return error.OutOfMemory; if (buf_offset + name.len + 1 > buf.len) return error.BufferTooSmall;
mem.copy(u8, buf[buf_offset..], name); mem.copy(u8, buf[buf_offset..], name);
buf_offset += name.len; buf_offset += name.len;
buf[buf_offset] = 0; buf[buf_offset] = 0;
@ -309,7 +309,7 @@ fn getGroup(self: *const DB, group: PackedGroup, buf: []u8) error{OutOfMemory}!C
} }
const name = group.name(); const name = group.name();
if (buf_offset + name.len + 1 > buf.len) return error.OutOfMemory; if (buf_offset + name.len + 1 > buf.len) return error.BufferTooSmall;
mem.copy(u8, buf[buf_offset..], name); mem.copy(u8, buf[buf_offset..], name);
buf[buf_offset + name.len] = 0; buf[buf_offset + name.len] = 0;
@ -321,7 +321,7 @@ fn getGroup(self: *const DB, group: PackedGroup, buf: []u8) error{OutOfMemory}!C
} }
// get a CGroup entry by name. // get a CGroup entry by name.
fn getgrnam(self: *const DB, name: []const u8, buf: []u8) error{OutOfMemory}!?CGroup { fn getgrnam(self: *const DB, name: []const u8, buf: []u8) error{BufferTooSmall}!?CGroup {
const idx = bdz.search(self.bdz_groupname, name); const idx = bdz.search(self.bdz_groupname, name);
if (idx >= self.header.num_groups) return null; if (idx >= self.header.num_groups) return null;
const offset = self.idx_groupname2group[idx]; const offset = self.idx_groupname2group[idx];
@ -332,7 +332,7 @@ fn getgrnam(self: *const DB, name: []const u8, buf: []u8) error{OutOfMemory}!?CG
} }
// get a CGroup entry by it's gid. // get a CGroup entry by it's gid.
fn getgrgid(self: *const DB, gid: u32, buf: []u8) error{OutOfMemory}!?CGroup { fn getgrgid(self: *const DB, gid: u32, buf: []u8) error{BufferTooSmall}!?CGroup {
const idx = bdz.search_u32(self.bdz_gid, gid); const idx = bdz.search_u32(self.bdz_gid, gid);
if (idx >= self.header.num_groups) return null; if (idx >= self.header.num_groups) return null;
const offset = self.idx_gid2group[idx]; const offset = self.idx_gid2group[idx];
@ -342,12 +342,12 @@ fn getgrgid(self: *const DB, gid: u32, buf: []u8) error{OutOfMemory}!?CGroup {
return try self.getGroup(group, buf); return try self.getGroup(group, buf);
} }
fn pushStr(str: []const u8, buf: []u8, offset: *usize) [*]const u8 { fn pushStr(str: []const u8, buf: []u8, offset: *usize) [*:0]const u8 {
const start = offset.*; const start = offset.*;
mem.copy(u8, buf[offset.*..], str); mem.copy(u8, buf[offset.*..], str);
buf[offset.* + str.len] = 0; buf[offset.* + str.len] = 0;
offset.* += str.len + 1; offset.* += str.len + 1;
return @ptrCast([*]const u8, &buf[start]); return @ptrCast([*:0]const u8, &buf[start]);
} }
fn getUser(self: *const DB, user: PackedUser, buf: []u8) error{BufferTooSmall}!CUser { fn getUser(self: *const DB, user: PackedUser, buf: []u8) error{BufferTooSmall}!CUser {
@ -725,7 +725,7 @@ test "getgrnam/getgrgid" {
_ = try db.getgrnam("all", buf); _ = try db.getgrnam("all", buf);
buf.len -= 1; buf.len -= 1;
try testing.expectError(error.OutOfMemory, db.getgrnam("all", buf)); try testing.expectError(error.BufferTooSmall, db.getgrnam("all", buf));
} }
test "getpwnam/getpwuid" { test "getpwnam/getpwuid" {

View File

@ -43,11 +43,12 @@ pub const TestDB = struct {
dir: testing.TmpDir, dir: testing.TmpDir,
path: [:0]const u8, path: [:0]const u8,
pub fn init(allocator: Allocator, errc: *ErrCtx) !TestDB { pub fn init(allocator: Allocator) !TestDB {
var errc = ErrCtx{};
var corpus = try Corpus.testCorpus(allocator); var corpus = try Corpus.testCorpus(allocator);
defer corpus.deinit(); defer corpus.deinit();
var db = try DB.fromCorpus(allocator, &corpus, errc); var db = try DB.fromCorpus(allocator, &corpus, &errc);
defer db.deinit(allocator); defer db.deinit(allocator);
var tmp = testing.tmpDir(.{}); var tmp = testing.tmpDir(.{});

View File

@ -145,13 +145,13 @@ pub fn fromReader(allocator: Allocator, err: *ErrCtx, reader: anytype) ![]User {
} }
pub const CUser = extern struct { pub const CUser = extern struct {
pw_name: [*]const u8, pw_name: [*:0]const u8,
pw_passwd: [*]const u8 = pw_passwd, pw_passwd: [*:0]const u8 = pw_passwd,
pw_uid: u32, pw_uid: u32,
pw_gid: u32, pw_gid: u32,
pw_gecos: [*]const u8, pw_gecos: [*:0]const u8,
pw_dir: [*]const u8, pw_dir: [*:0]const u8,
pw_shell: [*]const u8, pw_shell: [*:0]const u8,
}; };
const testing = std.testing; const testing = std.testing;

View File

@ -127,7 +127,7 @@ export fn _nss_turbo_getpwuid_r(
} }
export fn _nss_turbo_getpwnam_r( export fn _nss_turbo_getpwnam_r(
name: [*:0]u8, name: [*:0]const u8,
passwd: *CUser, passwd: *CUser,
buffer: [*]u8, buffer: [*]u8,
buflen: usize, buflen: usize,
@ -164,17 +164,54 @@ fn get_db(errnop: *c_int) ?DB {
const testing = std.testing; const testing = std.testing;
test "nss_turbo_getpwuid_r" { test "getpwuid_r and getpwnam_r" {
var errc = ErrCtx{}; var tf = try File.TestDB.init(testing.allocator);
var tf = try File.TestDB.init(testing.allocator, &errc);
defer tf.deinit(); defer tf.deinit();
const turbonss_db_path_old = turbonss_db_path;
turbonss_db_path = tf.path; turbonss_db_path = tf.path;
defer {
turbonss_db_path = turbonss_db_path_old;
}
var passwd: CUser = undefined;
var buffer: [1024]u8 = undefined; var buffer: [1024]u8 = undefined;
var errno: c_int = 0; var errno: c_int = 0;
const status = _nss_turbo_getpwuid_r(0, &passwd, &buffer, buffer.len, &errno); var passwd: CUser = undefined;
try testing.expectEqual(
c.NSS_STATUS_SUCCESS,
_nss_turbo_getpwuid_r(128, &passwd, &buffer, buffer.len, &errno),
);
try testing.expectEqual(@as(c_int, 0), errno); try testing.expectEqual(@as(c_int, 0), errno);
try testing.expectEqual(c.NSS_STATUS_SUCCESS, status); try testVidmantas(passwd);
passwd = undefined;
try testing.expectEqual(
c.NSS_STATUS_SUCCESS,
_nss_turbo_getpwnam_r("vidmantas", &passwd, &buffer, buffer.len, &errno),
);
try testing.expectEqual(@as(c_int, 0), errno);
try testVidmantas(passwd);
passwd = undefined;
try testing.expectEqual(
c.NSS_STATUS_NOTFOUND,
_nss_turbo_getpwnam_r("does not exist", &passwd, &buffer, buffer.len, &errno),
);
try testing.expectEqual(@enumToInt(os.E.NOENT), @intCast(u16, errno));
passwd = undefined;
var small_buffer: [1]u8 = undefined;
try testing.expectEqual(
c.NSS_STATUS_TRYAGAIN,
_nss_turbo_getpwuid_r(0, &passwd, &small_buffer, small_buffer.len, &errno),
);
try testing.expectEqual(@enumToInt(os.E.RANGE), @intCast(u16, errno));
}
fn testVidmantas(u: CUser) !void {
try testing.expectEqualStrings("vidmantas", mem.sliceTo(u.pw_name, 0));
try testing.expectEqual(@as(u32, 128), u.pw_uid);
try testing.expectEqual(@as(u32, 128), u.pw_gid);
try testing.expectEqualStrings("Vidmantas Kaminskas", mem.sliceTo(u.pw_gecos, 0));
try testing.expectEqualStrings("/bin/bash", mem.sliceTo(u.pw_shell, 0));
} }