wip getpwnam

This commit is contained in:
Motiejus Jakštys 2022-04-19 13:17:23 +03:00 committed by Motiejus Jakštys
parent 9e80d6676b
commit 4469d174ea
4 changed files with 100 additions and 13 deletions

View File

@ -14,12 +14,13 @@ const ArenaAllocator = std.heap.ArenaAllocator;
const Corpus = @import("Corpus.zig"); const Corpus = @import("Corpus.zig");
const pad = @import("padding.zig"); const pad = @import("padding.zig");
const compress = @import("compress.zig"); const compress = @import("compress.zig");
const PackedUser = @import("PackedUser.zig");
const User = @import("User.zig");
const Group = @import("Group.zig"); const Group = @import("Group.zig");
const CGroup = Group.CGroup; const CGroup = Group.CGroup;
const PackedGroup = @import("PackedGroup.zig"); const PackedGroup = @import("PackedGroup.zig");
const GroupStored = PackedGroup.GroupStored; const GroupStored = PackedGroup.GroupStored;
const User = @import("User.zig");
const CUser = User.CUser;
const PackedUser = @import("PackedUser.zig");
const ShellSections = @import("shell.zig").ShellWriter.ShellSections; const ShellSections = @import("shell.zig").ShellWriter.ShellSections;
const ShellReader = @import("shell.zig").ShellReader; const ShellReader = @import("shell.zig").ShellReader;
const ShellWriter = @import("shell.zig").ShellWriter; const ShellWriter = @import("shell.zig").ShellWriter;
@ -123,6 +124,8 @@ pub fn fromCorpus(
.getpw_bufsize = corpus.getpw_bufsize, .getpw_bufsize = corpus.getpw_bufsize,
}; };
std.debug.print("fromCorpus shell.index: {any}\n", .{shell.index.constSlice()});
return DB{ return DB{
.header = header, .header = header,
.bdz_gid = bdz_gid, .bdz_gid = bdz_gid,
@ -169,6 +172,8 @@ pub fn iov(self: *const DB) BoundedArray(os.iovec_const, DB_fields.len * 2) {
*const Header => mem.asBytes(value), *const Header => mem.asBytes(value),
else => mem.sliceAsBytes(value), else => mem.sliceAsBytes(value),
}; };
if (mem.eql(u8, field.name, "shell_index"))
std.debug.print("shell_index original: {any}\n", .{value});
result.appendAssumeCapacity(os.iovec_const{ result.appendAssumeCapacity(os.iovec_const{
.iov_base = bytes.ptr, .iov_base = bytes.ptr,
.iov_len = bytes.len, .iov_len = bytes.len,
@ -219,15 +224,13 @@ pub fn fromBytes(buf: []align(8) const u8) InvalidHeader!DB {
offset += lengths[i]; offset += lengths[i];
} }
std.debug.print("GOT shell_index: {any}\n", .{result.shell_index});
return result; return result;
} }
// dumps PackedGroup to []u8 and returns a CGroup. // dumps PackedGroup to []u8 and returns a CGroup.
fn getGroup( fn getGroup(self: *const DB, group: PackedGroup, buf: *[]u8) error{OutOfMemory}!CGroup {
self: *const DB,
group: PackedGroup,
buf: *[]u8,
) error{OutOfMemory}!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;
@ -271,7 +274,8 @@ fn getGroup(
fn getgrnam(self: *const DB, name: []const u8, buf: *[]u8) error{OutOfMemory}!?CGroup { fn getgrnam(self: *const DB, name: []const u8, buf: *[]u8) error{OutOfMemory}!?CGroup {
const idx = bdz.search(self.bdz_groupname, name); const idx = bdz.search(self.bdz_groupname, name);
const offset = self.idx_groupname2group[idx]; const offset = self.idx_groupname2group[idx];
const group = PackedGroup.fromBytes(self.groups[offset << 3 ..]).group; const nbits = PackedGroup.alignment_bits;
const group = PackedGroup.fromBytes(self.groups[offset << nbits ..]).group;
if (!mem.eql(u8, name, group.name())) return null; if (!mem.eql(u8, name, group.name())) return null;
return try self.getGroup(group, buf); return try self.getGroup(group, buf);
} }
@ -280,16 +284,69 @@ fn getgrnam(self: *const DB, name: []const u8, buf: *[]u8) error{OutOfMemory}!?C
fn getgrgid(self: *const DB, gid: u32, buf: *[]u8) error{OutOfMemory}!?CGroup { fn getgrgid(self: *const DB, gid: u32, buf: *[]u8) error{OutOfMemory}!?CGroup {
const idx = bdz.search_u32(self.bdz_gid, gid); const idx = bdz.search_u32(self.bdz_gid, gid);
const offset = self.idx_gid2group[idx]; const offset = self.idx_gid2group[idx];
const group = PackedGroup.fromBytes(self.groups[offset << 3 ..]).group; const nbits = PackedGroup.alignment_bits;
const group = PackedGroup.fromBytes(self.groups[offset << nbits ..]).group;
if (gid != group.gid()) return null; if (gid != group.gid()) return null;
return try self.getGroup(group, buf); return try self.getGroup(group, buf);
} }
fn pushStr(str: []const u8, buf: *[]u8, offset: *usize) [*]const u8 {
const start = offset.*;
mem.copy(u8, buf.*[offset.*..], str);
buf.*[offset.* + str.len] = 0;
offset.* += str.len + 1;
return @ptrCast([*]const u8, &buf.*[start]);
}
fn getUser(self: *const DB, user: PackedUser, buf: *[]u8) error{OutOfMemory}!CUser {
const shell_reader = ShellReader{
.index = self.shell_index,
.blob = self.shell_blob,
};
const name = user.name();
const gecos = user.gecos();
const home = user.home();
const shell = user.shell(shell_reader);
const strlen =
name.len + 1 +
gecos.len + 1 +
home.len + 1 +
shell.len + 1;
if (strlen > buf.len) return error.OutOfMemory;
var offset: usize = 0;
const pw_name = pushStr(name, buf, &offset);
const pw_gecos = pushStr(gecos, buf, &offset);
const pw_dir = pushStr(home, buf, &offset);
const pw_shell = pushStr(shell, buf, &offset);
return CUser{
.pw_name = pw_name,
.pw_uid = user.uid(),
.pw_gid = user.gid(),
.pw_gecos = pw_gecos,
.pw_dir = pw_dir,
.pw_shell = pw_shell,
};
}
// get a CUser entry by name.
fn getpwnam(self: *const DB, name: []const u8, buf: *[]u8) error{OutOfMemory}!?CUser {
const idx = bdz.search(self.bdz_username, name);
const offset = self.idx_name2user[idx];
const nbits = PackedUser.alignment_bits;
const user = PackedUser.fromBytes(self.users[offset << nbits ..]).user;
if (!mem.eql(u8, name, user.name())) return null;
return try self.getUser(user, buf);
}
fn shellSections( fn shellSections(
allocator: Allocator, allocator: Allocator,
corpus: *const Corpus, corpus: *const Corpus,
) error{OutOfMemory}!ShellSections { ) error{OutOfMemory}!ShellSections {
var popcon = ShellWriter.init(allocator); var popcon = ShellWriter.init(allocator);
errdefer popcon.deinit();
for (corpus.users.items(.shell)) |shell| for (corpus.users.items(.shell)) |shell|
try popcon.put(shell); try popcon.put(shell);
return popcon.toOwnedSections(max_shells); return popcon.toOwnedSections(max_shells);
@ -609,6 +666,22 @@ test "getgr_bufsize" {
try testing.expectError(error.OutOfMemory, db.getgrnam("all", &buf)); try testing.expectError(error.OutOfMemory, db.getgrnam("all", &buf));
} }
test "getpwnam" {
var arena = ArenaAllocator.init(testing.allocator);
defer arena.deinit();
var corpus = try Corpus.testCorpus(arena.allocator());
var db = try DB.fromCorpus(arena.allocator(), &corpus);
std.debug.print("db.shell.index: {any}\n", .{db.shell_index});
var buf = try arena.allocator().alloc(u8, db.header.getpw_bufsize);
const vidmantas = (try db.getpwnam("vidmantas", &buf)).?;
try testing.expectEqual(vidmantas.pw_uid, 128);
try testing.expectEqual(vidmantas.pw_gid, 128);
try testing.expectEqualStrings(vidmantas.pw_name[0..9], "vidmantas");
try testing.expectEqualStrings(vidmantas.pw_gecos[0..10], "Vidmantas Kaminskas");
try testing.expectEqualStrings(vidmantas.pw_dir[0..10], "/home/vidmantas");
}
test "additionalGids" { test "additionalGids" {
const allocator = testing.allocator; const allocator = testing.allocator;
var corpus = try Corpus.testCorpus(allocator); var corpus = try Corpus.testCorpus(allocator);

View File

@ -209,7 +209,8 @@ pub fn shell(self: PackedUser, shell_reader: shellImport.ShellReader) []const u8
return shell_reader.get(self.inner.shell_len_or_idx); return shell_reader.get(self.inner.shell_len_or_idx);
} }
pub const max_str_len = math.maxInt(fieldInfo(Inner, .shell_len_or_idx).field_type) + 1 + pub const max_str_len =
math.maxInt(fieldInfo(Inner, .shell_len_or_idx).field_type) + 1 +
math.maxInt(fieldInfo(Inner, .home_len).field_type) + 1 + math.maxInt(fieldInfo(Inner, .home_len).field_type) + 1 +
math.maxInt(fieldInfo(Inner, .name_len).field_type) + 1 + math.maxInt(fieldInfo(Inner, .name_len).field_type) + 1 +
math.maxInt(fieldInfo(Inner, .gecos_len).field_type); math.maxInt(fieldInfo(Inner, .gecos_len).field_type);

View File

@ -6,6 +6,8 @@ const Allocator = mem.Allocator;
const ArrayList = std.ArrayList; const ArrayList = std.ArrayList;
const BoundedArray = std.BoundedArray; const BoundedArray = std.BoundedArray;
const pw_passwd = "x\x00";
const User = @This(); const User = @This();
const PackedUser = @import("PackedUser.zig"); const PackedUser = @import("PackedUser.zig");
const validate = @import("validate.zig"); const validate = @import("validate.zig");
@ -126,6 +128,16 @@ pub fn fromReader(allocator: Allocator, reader: anytype) ![]User {
_ = users; _ = users;
} }
pub const CUser = extern struct {
pw_name: [*]const u8,
pw_passwd: [*]const u8 = pw_passwd,
pw_uid: u32,
pw_gid: u32,
pw_gecos: [*]const u8,
pw_dir: [*]const u8,
pw_shell: [*]const u8,
};
const testing = std.testing; const testing = std.testing;
pub const max_user = User{ pub const max_user = User{

View File

@ -22,6 +22,8 @@ pub const ShellReader = struct {
// get returns a shell at the given index. // get returns a shell at the given index.
pub fn get(self: *const ShellReader, idx: u8) []const u8 { pub fn get(self: *const ShellReader, idx: u8) []const u8 {
std.debug.print("\nrequested shell at index {d}; ", .{idx});
std.debug.print("start:{d} end:{d}\n", .{ self.index[idx], self.index[idx + 1] });
return self.blob[self.index[idx]..self.index[idx + 1]]; return self.blob[self.index[idx]..self.index[idx + 1]];
} }
}; };
@ -73,6 +75,7 @@ pub const ShellWriter = struct {
self.index.set(idx8, offset); self.index.set(idx8, offset);
} }
self.index.appendAssumeCapacity(@intCast(u8, self.blob.len)); self.index.appendAssumeCapacity(@intCast(u8, self.blob.len));
std.debug.print("\nGEN shell_index: {any}\n", .{self.index.constSlice()});
return self; return self;
} }
@ -141,9 +144,7 @@ pub const ShellWriter = struct {
} }
const total = std.math.min(deque.count(), limit); const total = std.math.min(deque.count(), limit);
var topShells = BoundedArray([]const u8, max_shells).init(total) catch |err| switch (err) { var topShells = BoundedArray([]const u8, max_shells).init(total) catch unreachable;
error.Overflow => unreachable,
};
var i: u32 = 0; var i: u32 = 0;
while (i < total) : (i += 1) while (i < total) : (i += 1)