You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

76 lines
2.1 KiB

// vim: set expandtab: set tabstop=4
const std = @import("std");
const mem = std.mem;
const crypto = std.crypto;
const heap = std.heap;
const process = std.process;
const cstr = std.cstr;
const os = std.os;
const io = std.io;
const assert = std.debug.assert;
const ArrayList = std.ArrayList;
const c = @cImport({
@cInclude("pwd.h");
@cInclude("shadow.h");
@cInclude("unistd.h");
@cInclude("grp.h");
@cInclude("crypt.h");
});
fn getGroups(alloc: mem.Allocator, passwd: c.passwd) ![]c.gid_t {
var ngr: c_int = 0;
_ = c.getgrouplist(passwd.pw_name, passwd.pw_gid, null, &ngr);
const groups = try alloc.alloc(c.gid_t, @intCast(usize, ngr));
_ = c.getgrouplist(passwd.pw_name, passwd.pw_gid, groups.ptr, &ngr);
return groups;
}
pub fn main() !u8 {
const stderr = io.getStdErr().writer();
if (os.argv.len <= 1) {
try stderr.print("Not enough arguments\n", .{});
return 1;
}
const passwd = c.getpwuid(c.getuid()).*;
const shadowEntry = c.getspnam(passwd.pw_name);
if (shadowEntry == null) {
try stderr.print("Missing setuid on binary {s}\n", .{os.argv[0]});
return 1;
}
const shadow = shadowEntry.*;
const wheel = c.getgrnam("wheel").*;
var allocator = heap.ArenaAllocator.init(std.heap.page_allocator);
defer allocator.deinit();
const gpa = allocator.allocator();
for (try getGroups(gpa, passwd)) |gr_id| {
const gr = c.getgrgid(gr_id).*;
if (gr.gr_gid == wheel.gr_gid) {
const pass = mem.span(c.getpass("#: "));
if (cstr.cmp(shadow.sp_pwdp, c.crypt(pass, shadow.sp_pwdp)) == 0) {
crypto.utils.secureZero(u8, pass);
_ = c.setuid(0);
_ = c.setgid(0);
var argl = ArrayList([]const u8).init(gpa);
for (os.argv[1..]) |arg| {
try argl.append(mem.span(arg));
}
return process.execv(gpa, try argl.toOwnedSlice());
} else {
try stderr.print("Wrong Password\n", .{});
return 1;
}
break;
}
}
return 0;
}