wip _nss_turbo_getpwuid_r
This commit is contained in:
parent
ee603c47ca
commit
4f2c8707f4
17
lib/DB.zig
17
lib/DB.zig
@ -9,7 +9,6 @@ const Allocator = std.mem.Allocator;
|
|||||||
const ArrayList = std.ArrayList;
|
const ArrayList = std.ArrayList;
|
||||||
const AutoHashMap = std.AutoHashMap;
|
const AutoHashMap = std.AutoHashMap;
|
||||||
const BoundedArray = std.BoundedArray;
|
const BoundedArray = std.BoundedArray;
|
||||||
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");
|
||||||
@ -149,6 +148,14 @@ pub fn fromCorpus(
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn getgrBufsize(self: *const DB) usize {
|
||||||
|
return self.header.getgr_bufsize;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn getpwBufsize(self: *const DB) usize {
|
||||||
|
return self.header.getpw_bufsize;
|
||||||
|
}
|
||||||
|
|
||||||
pub fn deinit(self: *DB, allocator: Allocator) void {
|
pub fn deinit(self: *DB, allocator: Allocator) void {
|
||||||
allocator.destroy(self.header);
|
allocator.destroy(self.header);
|
||||||
allocator.free(self.bdz_gid);
|
allocator.free(self.bdz_gid);
|
||||||
@ -336,7 +343,7 @@ fn getUser(self: *const DB, user: PackedUser, buf: *[]u8) error{OutOfMemory}!CUs
|
|||||||
}
|
}
|
||||||
|
|
||||||
// get a CUser entry by name.
|
// get a CUser entry by name.
|
||||||
fn getpwnam(self: *const DB, name: []const u8, buf: *[]u8) error{OutOfMemory}!?CUser {
|
pub fn getpwnam(self: *const DB, name: []const u8, buf: *[]u8) error{OutOfMemory}!?CUser {
|
||||||
const idx = bdz.search(self.bdz_username, name);
|
const idx = bdz.search(self.bdz_username, name);
|
||||||
// bdz may return a hash that's bigger than the number of users
|
// bdz may return a hash that's bigger than the number of users
|
||||||
if (idx >= self.header.num_users) return null;
|
if (idx >= self.header.num_users) return null;
|
||||||
@ -348,7 +355,7 @@ fn getpwnam(self: *const DB, name: []const u8, buf: *[]u8) error{OutOfMemory}!?C
|
|||||||
}
|
}
|
||||||
|
|
||||||
// get a CUser entry by uid.
|
// get a CUser entry by uid.
|
||||||
fn getpwuid(self: *const DB, uid: u32, buf: *[]u8) error{OutOfMemory}!?CUser {
|
pub fn getpwuid(self: *const DB, uid: u32, buf: *[]u8) error{OutOfMemory}!?CUser {
|
||||||
const idx = bdz.search_u32(self.bdz_uid, uid);
|
const idx = bdz.search_u32(self.bdz_uid, uid);
|
||||||
if (idx >= self.header.num_users) return null;
|
if (idx >= self.header.num_users) return null;
|
||||||
const offset = self.idx_uid2user[idx];
|
const offset = self.idx_uid2user[idx];
|
||||||
@ -644,7 +651,7 @@ test "getgrnam/getgrgid" {
|
|||||||
defer corpus.deinit();
|
defer corpus.deinit();
|
||||||
var db = try DB.fromCorpus(testing.allocator, &corpus);
|
var db = try DB.fromCorpus(testing.allocator, &corpus);
|
||||||
defer db.deinit(testing.allocator);
|
defer db.deinit(testing.allocator);
|
||||||
var buf = try testing.allocator.alloc(u8, db.header.getgr_bufsize);
|
var buf = try testing.allocator.alloc(u8, db.getgrBufsize());
|
||||||
defer testing.allocator.free(buf);
|
defer testing.allocator.free(buf);
|
||||||
|
|
||||||
{
|
{
|
||||||
@ -677,7 +684,7 @@ test "getpwnam/getpwuid" {
|
|||||||
defer corpus.deinit();
|
defer corpus.deinit();
|
||||||
var db = try DB.fromCorpus(testing.allocator, &corpus);
|
var db = try DB.fromCorpus(testing.allocator, &corpus);
|
||||||
defer db.deinit(testing.allocator);
|
defer db.deinit(testing.allocator);
|
||||||
var buf = try testing.allocator.alloc(u8, db.header.getpw_bufsize);
|
var buf = try testing.allocator.alloc(u8, db.getpwBufsize());
|
||||||
defer testing.allocator.free(buf);
|
defer testing.allocator.free(buf);
|
||||||
|
|
||||||
{
|
{
|
||||||
|
44
lib/File.zig
44
lib/File.zig
@ -1,6 +1,9 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const os = std.os;
|
const os = std.os;
|
||||||
|
const fs = std.fs;
|
||||||
|
const Allocator = std.mem.Allocator;
|
||||||
|
|
||||||
|
const Corpus = @import("Corpus.zig");
|
||||||
const DB = @import("DB.zig");
|
const DB = @import("DB.zig");
|
||||||
const InvalidHeader = @import("header.zig").Invalid;
|
const InvalidHeader = @import("header.zig").Invalid;
|
||||||
|
|
||||||
@ -13,12 +16,10 @@ pub const Error = os.OpenError || os.FStatError || os.MMapError || InvalidHeader
|
|||||||
pub fn open(fname: []const u8) Error!File {
|
pub fn open(fname: []const u8) Error!File {
|
||||||
const fd = try os.open(fname, os.O.RDONLY, 0);
|
const fd = try os.open(fname, os.O.RDONLY, 0);
|
||||||
var fd_open = true;
|
var fd_open = true;
|
||||||
errdefer {
|
errdefer if (fd_open) os.close(fd);
|
||||||
if (fd_open) os.close(fd);
|
|
||||||
}
|
|
||||||
|
|
||||||
const st = try os.fstat(fd);
|
const st = try os.fstat(fd);
|
||||||
const size = @intCast(u64, st.size);
|
const size = @intCast(usize, st.size);
|
||||||
const ptr = try os.mmap(null, size, os.PROT.READ, os.MAP.SHARED, fd, 0);
|
const ptr = try os.mmap(null, size, os.PROT.READ, os.MAP.SHARED, fd, 0);
|
||||||
errdefer os.munmap(ptr);
|
errdefer os.munmap(ptr);
|
||||||
|
|
||||||
@ -33,3 +34,38 @@ pub fn close(self: *File) void {
|
|||||||
os.munmap(self.ptr);
|
os.munmap(self.ptr);
|
||||||
self.* = undefined;
|
self.* = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const testing = std.testing;
|
||||||
|
|
||||||
|
pub const TestFile = struct {
|
||||||
|
dir: testing.TmpDir,
|
||||||
|
path: [:0]const u8,
|
||||||
|
|
||||||
|
pub fn init(allocator: Allocator) !TestFile {
|
||||||
|
var corpus = try Corpus.testCorpus(allocator);
|
||||||
|
defer corpus.deinit();
|
||||||
|
|
||||||
|
var db = try DB.fromCorpus(allocator, &corpus);
|
||||||
|
defer db.deinit(allocator);
|
||||||
|
|
||||||
|
var tmp = testing.tmpDir(.{});
|
||||||
|
errdefer tmp.cleanup();
|
||||||
|
|
||||||
|
const mode = os.O.RDWR | os.O.CREAT | os.O.EXCL;
|
||||||
|
const fd = try os.openat(tmp.dir.fd, "db.turbo", mode, 0o666);
|
||||||
|
defer os.close(fd);
|
||||||
|
|
||||||
|
_ = try os.writev(fd, db.iov().constSlice());
|
||||||
|
const dir_path = try tmp.getFullPath(allocator);
|
||||||
|
defer allocator.free(dir_path);
|
||||||
|
|
||||||
|
const full = &[_][]const u8{ dir_path, "db.turbo\x00" };
|
||||||
|
var result = try fs.path.join(allocator, full);
|
||||||
|
return TestFile{ .dir = tmp, .path = result[0 .. result.len - 1 :0] };
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deinit(self: *TestFile, allocator: Allocator) void {
|
||||||
|
self.dir.cleanup();
|
||||||
|
allocator.free(self.path);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
@ -2,6 +2,7 @@ const std = @import("std");
|
|||||||
const os = std.os;
|
const os = std.os;
|
||||||
const fmt = std.fmt;
|
const fmt = std.fmt;
|
||||||
const mem = std.mem;
|
const mem = std.mem;
|
||||||
|
const process = std.process;
|
||||||
|
|
||||||
const DB = @import("DB.zig");
|
const DB = @import("DB.zig");
|
||||||
const File = @import("File.zig");
|
const File = @import("File.zig");
|
||||||
@ -11,10 +12,16 @@ const CUser = @import("User.zig").CUser;
|
|||||||
const PackedUser = @import("PackedUser.zig");
|
const PackedUser = @import("PackedUser.zig");
|
||||||
|
|
||||||
const c = @cImport({
|
const c = @cImport({
|
||||||
@cInclude("stdlib.h");
|
|
||||||
@cInclude("nss.h");
|
@cInclude("nss.h");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const TURBONSS_DB = "DB";
|
||||||
|
const TURBONSS_VERBOSE = "TURBONSS_VERBOSE";
|
||||||
|
const TURBONSS_OMIT_MEMBERS = "TURBONSS_OMIT_MEMBERS";
|
||||||
|
|
||||||
|
extern fn putenv(name: [*:0]const u8, value: [*:0]const u8, overwrite: c_int) c_int;
|
||||||
|
extern fn getenv(name: [*:0]const u8) ?[*:0]const u8;
|
||||||
|
|
||||||
export const turbonss_default_path: [:0]const u8 = "/etc/turbonss/db.turbo";
|
export const turbonss_default_path: [:0]const u8 = "/etc/turbonss/db.turbo";
|
||||||
|
|
||||||
// State is a type of the global variable holding the process state:
|
// State is a type of the global variable holding the process state:
|
||||||
@ -24,7 +31,29 @@ const State = struct {
|
|||||||
getpwent_iterator: ?PackedUser.Iterator,
|
getpwent_iterator: ?PackedUser.Iterator,
|
||||||
getgrent_iterator: ?PackedGroup.Iterator,
|
getgrent_iterator: ?PackedGroup.Iterator,
|
||||||
omit_members: bool,
|
omit_members: bool,
|
||||||
err_msg: [1024]u8,
|
verbose: bool = false,
|
||||||
|
|
||||||
|
fn debug(self: *const State, comptime format: []const u8, args: anytype) void {
|
||||||
|
self.log(.debug, format, args);
|
||||||
|
}
|
||||||
|
fn info(self: *const State, comptime format: []const u8, args: anytype) void {
|
||||||
|
self.log(.info, format, args);
|
||||||
|
}
|
||||||
|
fn err(self: *const State, comptime format: []const u8, args: anytype) void {
|
||||||
|
self.log(.err, format, args);
|
||||||
|
}
|
||||||
|
fn log(
|
||||||
|
self: *const State,
|
||||||
|
comptime level: std.log.Level,
|
||||||
|
comptime format: []const u8,
|
||||||
|
args: anytype,
|
||||||
|
) void {
|
||||||
|
if (!self.verbose) return;
|
||||||
|
const stderr = std.io.getStdErr().writer();
|
||||||
|
std.debug.getStderrMutex().lock();
|
||||||
|
defer std.debug.getStderrMutex().unlock();
|
||||||
|
stderr.print("[" ++ level.asText() ++ "] " ++ format ++ "\n", args) catch return;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// state is initialized on library startup.
|
// state is initialized on library startup.
|
||||||
@ -32,14 +61,29 @@ var state: State = undefined;
|
|||||||
|
|
||||||
// constructor
|
// constructor
|
||||||
export fn _turbo_init() void {
|
export fn _turbo_init() void {
|
||||||
const fname = os.getenvZ("TURBONSS_DB") orelse turbonss_default_path[0..];
|
//if (os.getenvZ(TURBONSS_VERBOSE)) |env|
|
||||||
|
// state.verbose = mem.eql(u8, env, "1");
|
||||||
|
|
||||||
|
if (getenv(TURBONSS_VERBOSE)) |env| {
|
||||||
|
const envZ = mem.sliceTo(env, 0);
|
||||||
|
state.verbose = mem.eql(u8, envZ, "1");
|
||||||
|
}
|
||||||
|
|
||||||
|
//std.debug.print("TURBONSS_VERBOSE: {s}\n", .{os.getenv(TURBONSS_VERBOSE)});
|
||||||
|
std.debug.print("TURBONSS_VERBOSE: {s}\n", .{getenv(TURBONSS_VERBOSE)});
|
||||||
|
std.debug.print("verbose: {any}\n", .{state.verbose});
|
||||||
|
|
||||||
|
const fname = os.getenvZ(TURBONSS_DB) orelse turbonss_default_path[0..];
|
||||||
|
state.debug("opening {s}", .{fname});
|
||||||
state.file = File.open(fname) catch |err| {
|
state.file = File.open(fname) catch |err| {
|
||||||
_ = fmt.bufPrint(&state.err_msg, "open {s}: {s}", .{ fname, @errorName(err) }) catch return;
|
state.err("open {s}: {s}", .{ fname, @errorName(err) });
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
state.debug("turbonss database opened", .{});
|
||||||
|
|
||||||
const omit_members_env = os.getenvZ("TURBONSS_OMIT_MEMBERS") orelse "auto";
|
const omit_members_env = os.getenvZ(TURBONSS_OMIT_MEMBERS) orelse "auto";
|
||||||
state.omit_members = shouldOmitMembers(omit_members_env, os.argv);
|
state.omit_members = shouldOmitMembers(omit_members_env, os.argv);
|
||||||
|
state.debug("omitting members from getgr* calls: {any}\n", .{state.omit_members});
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -65,10 +109,43 @@ export fn _nss_turbo_getpwuid_r(
|
|||||||
len: usize,
|
len: usize,
|
||||||
errnop: *c_int,
|
errnop: *c_int,
|
||||||
) c.enum_nss_status {
|
) c.enum_nss_status {
|
||||||
_ = uid;
|
if (state.file == null) {
|
||||||
_ = res;
|
errnop.* = @enumToInt(os.E.AGAIN);
|
||||||
_ = buf;
|
return c.NSS_STATUS_UNAVAIL;
|
||||||
_ = len;
|
}
|
||||||
_ = errnop;
|
const cuser = state.file.?.db.getpwuid(uid, &buf[0..len]) catch |err| switch (err) {
|
||||||
return 0;
|
error.OutOfMemory => {
|
||||||
|
errnop.* = @enumToInt(os.E.RANGE);
|
||||||
|
return c.NSS_STATUS_TRYAGAIN;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
if (cuser == null) {
|
||||||
|
errnop.* = @enumToInt(os.E.NOENT);
|
||||||
|
return c.NSS_STATUS_NOTFOUND;
|
||||||
|
}
|
||||||
|
res.* = cuser.?;
|
||||||
|
|
||||||
|
return c.NSS_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
const testing = std.testing;
|
||||||
|
|
||||||
|
test "nss_turbo_getpwuid_r" {
|
||||||
|
var tf = try File.TestFile.init(testing.allocator);
|
||||||
|
defer tf.deinit(testing.allocator);
|
||||||
|
|
||||||
|
var env = try process.getEnvMap(testing.allocator);
|
||||||
|
defer env.deinit();
|
||||||
|
|
||||||
|
try testing.expectEqual(putenv(TURBONSS_VERBOSE, "1", 1), 0);
|
||||||
|
try testing.expectEqual(putenv(TURBONSS_DB, tf.path, 1), 0);
|
||||||
|
_turbo_init();
|
||||||
|
try testing.expect(state.file != null);
|
||||||
|
|
||||||
|
var buf = try testing.allocator.alloc(u8, state.file.?.db.getpwBufsize());
|
||||||
|
var user: CUser = undefined;
|
||||||
|
var errno: c_int = undefined;
|
||||||
|
const ret = _nss_turbo_getpwuid_r(128, &user, buf.ptr, buf.len, &errno);
|
||||||
|
try testing.expectEqual(ret, c.NSS_STATUS_SUCCESS);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user