1
Fork 0
turbonss/src/libnss.zig

115 lines
3.1 KiB
Zig

const std = @import("std");
const os = std.os;
const fmt = std.fmt;
const log = std.log;
const mem = std.mem;
const process = std.process;
const once = std.once;
const DB = @import("DB.zig");
const File = @import("File.zig");
const ErrCtx = @import("ErrCtx.zig");
const CGroup = @import("Group.zig").CGroup;
const PackedGroup = @import("PackedGroup.zig");
const CUser = @import("User.zig").CUser;
const PackedUser = @import("PackedUser.zig");
const c = @cImport({
@cInclude("nss.h");
});
const ENV_DB = "TURBONSS_DB";
const ENV_VERBOSE = "TURBONSS__VERBOSE";
const ENV_OMIT_MEMBERS = "TURBONSS_OMIT_MEMBERS";
export const turbonss_default_path: [:0]const u8 = "/etc/turbonss/db.turbo";
pub var log_level: std.log.Level = .err;
// State is a type of the global variable holding the process state:
// the DB handle and all the iterators.
const State = struct {
file: ?File,
getpwent_iterator: ?PackedUser.Iterator = null,
getgrent_iterator: ?PackedGroup.Iterator = null,
omit_members: bool,
};
// global_state is initialized on first call to an nss function
var global_state: State = undefined;
var global_start = once(init);
// assigns State from environment variables et al
fn init() void {
if (os.getenvZ(ENV_VERBOSE)) |env|
log_level = if (mem.eql(u8, mem.sliceTo(env, 0), "1"))
.debug
else
.err;
const fname = os.getenvZ(ENV_DB) orelse turbonss_default_path[0..];
log.debug("opening {s}", .{fname});
const env_omit_members = os.getenvZ(ENV_OMIT_MEMBERS) orelse "auto";
const omit_members = shouldOmitMembers(env_omit_members, os.argv);
log.debug("omitting members from getgr* calls: {any}\n", .{omit_members});
const file = File.open(fname) catch |err| {
log.warn("open '{s}': {s}", .{ fname, @errorName(err) });
return;
};
log.debug("turbonss database opened", .{});
global_state = State{
.file = file,
.omit_members = omit_members,
};
}
fn shouldOmitMembers(envvar: []const u8, argv: [][*:0]u8) bool {
if (mem.eql(u8, envvar, "1")) return true;
if (mem.eql(u8, envvar, "0")) return false;
if (argv.len == 0) return false;
return mem.eql(u8, mem.sliceTo(argv[0], 0), "id");
}
export fn _nss_turbo_getpwuid_r(
uid: c_uint,
res: *CUser,
buf: [*]u8,
len: usize,
errnop: *c_int,
) c.enum_nss_status {
global_start.call();
if (global_state.file == null) {
errnop.* = @enumToInt(os.E.AGAIN);
return c.NSS_STATUS_UNAVAIL;
}
const db = global_state.file.?.db;
const cuser = db.getpwuid(uid, buf[0..len]) catch |err| switch (err) {
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 errc = ErrCtx{};
var tf = try File.TestDB.init(testing.allocator, &errc);
defer tf.deinit();
}