blob: 1cd78e28db9e92c5a34eded9308c8a1a92453ea2 [file] [log] [blame] [raw]
#include "common.h"
#include <sys/types.h>
#include <sys/mac.h>
#include <sys/priv.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
static struct privilege_description {
char *name, *desc;
} privileges[] = {
#define PRIVILEGE(N,D) [PRIV_##N] = { #N, D }
PRIVILEGE(ACCT, "Manage process accounting"),
PRIVILEGE(MAXFILES, "Exceed system open files limit"),
PRIVILEGE(MAXPROC, "Exceed system processes limit"),
PRIVILEGE(KTRACE, "Set/clear KTRFAC_ROOT on ktrace"),
PRIVILEGE(SETDUMPER, "Configure dump device"),
PRIVILEGE(REBOOT, "Can reboot system"),
PRIVILEGE(SWAPON, "Can swapon()"),
PRIVILEGE(SWAPOFF, "Can swapoff()"),
PRIVILEGE(MSGBUF, "Can read kernel message buffer"),
PRIVILEGE(IO, "Can perform low-level I/O"),
PRIVILEGE(KEYBOARD, "Reprogram keyboard"),
PRIVILEGE(DRIVER, "Low-level driver privilege"),
PRIVILEGE(ADJTIME, "Set time adjustment"),
PRIVILEGE(NTP_ADJTIME, "Set NTP time adjustment"),
PRIVILEGE(CLOCK_SETTIME, "Can call clock_settime"),
PRIVILEGE(SETTIMEOFDAY, "Can call settimeofday"),
PRIVILEGE(AUDIT_CONTROL, "Can configure audit"),
PRIVILEGE(AUDIT_FAILSTOP, "Can run during audit fail stop"),
PRIVILEGE(AUDIT_GETAUDIT, "Can get proc audit properties"),
PRIVILEGE(AUDIT_SETAUDIT, "Can set proc audit properties"),
PRIVILEGE(AUDIT_SUBMIT, "Can submit an audit record"),
PRIVILEGE(CRED_SETUID, "setuid"),
PRIVILEGE(CRED_SETEUID, "seteuid to !ruid and !svuid"),
PRIVILEGE(CRED_SETGID, "setgid"),
PRIVILEGE(CRED_SETEGID, "setgid to !rgid and !svgid"),
PRIVILEGE(CRED_SETGROUPS, "Set process additional groups"),
PRIVILEGE(CRED_SETREUID, "setreuid"),
PRIVILEGE(CRED_SETREGID, "setregid"),
PRIVILEGE(CRED_SETRESUID, "setresuid"),
PRIVILEGE(CRED_SETRESGID, "setresgid"),
PRIVILEGE(SEEOTHERGIDS, "Exempt bsd.seeothergids"),
PRIVILEGE(SEEOTHERUIDS, "Exempt bsd.seeotheruids"),
PRIVILEGE(DEBUG_DIFFCRED, "Exempt debugging other users"),
PRIVILEGE(DEBUG_SUGID, "Exempt debugging setuid proc"),
PRIVILEGE(DEBUG_UNPRIV, "Exempt unprivileged debug limit"),
PRIVILEGE(DEBUG_DENIED, "Exempt P2_NOTRACE"),
PRIVILEGE(DTRACE_KERNEL, "Allow use of DTrace on the kernel"),
PRIVILEGE(DTRACE_PROC, "Allow attaching DTrace to process"),
PRIVILEGE(DTRACE_USER, "Process may submit DTrace events"),
PRIVILEGE(FIRMWARE_LOAD, "Can load firmware"),
PRIVILEGE(JAIL_ATTACH, "Attach to a jail"),
PRIVILEGE(JAIL_SET, "Set jail parameters"),
PRIVILEGE(JAIL_REMOVE, "Remove a jail"),
PRIVILEGE(KENV_SET, "Set kernel env. variables"),
PRIVILEGE(KENV_UNSET, "Unset kernel env. variables"),
PRIVILEGE(KLD_LOAD, "Load a kernel module"),
PRIVILEGE(KLD_UNLOAD, "Unload a kernel module"),
PRIVILEGE(MAC_PARTITION, "Privilege in mac_partition policy"),
PRIVILEGE(MAC_PRIVS, "Privilege in the mac_privs policy"),
PRIVILEGE(PROC_LIMIT, "Exceed user process limit"),
PRIVILEGE(PROC_SETLOGIN, "Can call setlogin"),
PRIVILEGE(PROC_SETRLIMIT, "Can raise resources limits"),
PRIVILEGE(PROC_SETLOGINCLASS, "Can call setloginclass(2)"),
PRIVILEGE(IPC_READ, "Can override IPC read perm"),
PRIVILEGE(IPC_WRITE, "Can override IPC write perm"),
PRIVILEGE(IPC_ADMIN, "Can override IPC owner-only perm"),
PRIVILEGE(IPC_MSGSIZE, "Exempt IPC message queue limit"),
PRIVILEGE(MQ_ADMIN, "Can override msgq owner-only perm"),
PRIVILEGE(PMC_MANAGE, "Can administer PMC"),
PRIVILEGE(PMC_SYSTEM, "Can allocate a system-wide PMC"),
PRIVILEGE(SCHED_DIFFCRED, "Exempt scheduling other users"),
PRIVILEGE(SCHED_SETPRIORITY, "Can set lower nice value for proc"),
PRIVILEGE(SCHED_RTPRIO, "Can set real time scheduling"),
PRIVILEGE(SCHED_SETPOLICY, "Can set scheduler policy"),
PRIVILEGE(SCHED_SET, "Can set thread scheduler"),
PRIVILEGE(SCHED_SETPARAM, "Can set thread scheduler params"),
PRIVILEGE(SCHED_CPUSET, "Can manipulate cpusets"),
PRIVILEGE(SCHED_CPUSET_INTR, "Can adjust IRQ to CPU binding"),
PRIVILEGE(SEM_WRITE, "Can override sem write perm"),
PRIVILEGE(SIGNAL_DIFFCRED, "Exempt signalling other users"),
PRIVILEGE(SIGNAL_SUGID, "Non-conserv signal setuid proc"),
PRIVILEGE(SYSCTL_DEBUG, "Can invoke sysctl.debug"),
PRIVILEGE(SYSCTL_WRITE, "Can write sysctls"),
PRIVILEGE(SYSCTL_WRITEJAIL, "Can write sysctls, jail permitted"),
PRIVILEGE(TTY_CONSOLE, "Set console to tty"),
PRIVILEGE(TTY_DRAINWAIT, "Set tty drain wait time"),
PRIVILEGE(TTY_DTRWAIT, "Set DTR wait on tty"),
PRIVILEGE(TTY_EXCLUSIVE, "Override tty exclusive flag"),
PRIVILEGE(TTY_STI, "Simulate input on another tty"),
PRIVILEGE(TTY_SETA, "Set tty termios structure"),
PRIVILEGE(UFS_EXTATTRCTL, "Can configure EAs on UFS1"),
PRIVILEGE(UFS_QUOTAOFF, "quotaoff()"),
PRIVILEGE(UFS_QUOTAON, "quotaon()"),
PRIVILEGE(UFS_SETUSE, "setuse()"),
PRIVILEGE(ZFS_POOL_CONFIG, "Can configure ZFS pools"),
PRIVILEGE(ZFS_INJECT, "Can inject faults in the ZFS fault injection framework"),
PRIVILEGE(ZFS_JAIL, "Can attach/detach ZFS to/from jails"),
PRIVILEGE(NFS_DAEMON, "Can become the NFS daemon"),
PRIVILEGE(NFS_LOCKD, "Can become NFS lock daemon"),
PRIVILEGE(VFS_READ, "Override vnode DAC read perm"),
PRIVILEGE(VFS_WRITE, "Override vnode DAC write perm"),
PRIVILEGE(VFS_ADMIN, "Override vnode DAC admin perm"),
PRIVILEGE(VFS_EXEC, "Override vnode DAC exec perm"),
PRIVILEGE(VFS_LOOKUP, "Override vnode DAC lookup perm"),
PRIVILEGE(VFS_BLOCKRESERVE, "Can use free block reserve"),
PRIVILEGE(VFS_CHFLAGS_DEV, "Can chflags() a device node"),
PRIVILEGE(VFS_CHOWN, "Can set user; group to non-member"),
PRIVILEGE(VFS_CHROOT, "chroot()"),
PRIVILEGE(VFS_RETAINSUGID, "Can retain sugid bits on change"),
PRIVILEGE(VFS_EXCEEDQUOTA, "Exempt from quota restrictions"),
PRIVILEGE(VFS_EXTATTR_SYSTEM, "Operate on system EA namespace"),
PRIVILEGE(VFS_FCHROOT, "fchroot()"),
PRIVILEGE(VFS_FHOPEN, "Can fhopen()"),
PRIVILEGE(VFS_FHSTAT, "Can fhstat()"),
PRIVILEGE(VFS_FHSTATFS, "Can fhstatfs()"),
PRIVILEGE(VFS_GENERATION, "stat() returns generation number"),
PRIVILEGE(VFS_GETFH, "Can retrieve file handles"),
PRIVILEGE(VFS_GETQUOTA, "getquota()"),
PRIVILEGE(VFS_LINK, "bsd.hardlink_check_uid"),
PRIVILEGE(VFS_MKNOD_BAD, "Can mknod() to mark bad inodes"),
PRIVILEGE(VFS_MKNOD_DEV, "Can mknod() to create dev nodes"),
PRIVILEGE(VFS_MKNOD_WHT, "Can mknod() to create whiteout"),
PRIVILEGE(VFS_MOUNT, "Can mount()"),
PRIVILEGE(VFS_MOUNT_OWNER, "Can manage other users' file systems"),
PRIVILEGE(VFS_MOUNT_EXPORTED, "Can set MNT_EXPORTED on mount"),
PRIVILEGE(VFS_MOUNT_PERM, "Override dev node perms at mount"),
PRIVILEGE(VFS_MOUNT_SUIDDIR, "Can set MNT_SUIDDIR on mount"),
PRIVILEGE(VFS_MOUNT_NONUSER, "Can perform a non-user mount"),
PRIVILEGE(VFS_SETGID, "Can setgid if not in group"),
PRIVILEGE(VFS_SETQUOTA, "setquota()"),
PRIVILEGE(VFS_STICKYFILE, "Can set sticky bit on file"),
PRIVILEGE(VFS_SYSFLAGS, "Can modify system flags"),
PRIVILEGE(VFS_UNMOUNT, "Can unmount()"),
PRIVILEGE(VFS_STAT, "Override vnode MAC stat perm"),
PRIVILEGE(VM_MADV_PROTECT, "Can set MADV_PROTECT"),
PRIVILEGE(VM_MLOCK, "Can mlock(), mlockall()"),
PRIVILEGE(VM_MUNLOCK, "Can munlock(), munlockall()"),
PRIVILEGE(VM_SWAP_NOQUOTA, "Can override the global swap reservation limits"),
PRIVILEGE(VM_SWAP_NORLIMIT, "Can override the per-uid swap reservation limits"),
PRIVILEGE(DEVFS_RULE, "Can manage devfs rules"),
PRIVILEGE(DEVFS_SYMLINK, "Can create symlinks in devfs"),
PRIVILEGE(RANDOM_RESEED, "Closing /dev/random reseeds"),
PRIVILEGE(NET_BRIDGE, "Administer bridge"),
PRIVILEGE(NET_GRE, "Administer GRE"),
#ifdef PRIV_NET_PPP
PRIVILEGE(NET_PPP, "Administer PPP interface"),
#endif
PRIVILEGE(NET_BPF, "Monitor BPF"),
PRIVILEGE(NET_RAW, "Open raw socket"),
PRIVILEGE(NET_ROUTE, "Administer routing"),
PRIVILEGE(NET_TAP, "Can open tap device"),
PRIVILEGE(NET_SETIFMTU, "Set interface MTU"),
PRIVILEGE(NET_SETIFFLAGS, "Set interface flags"),
PRIVILEGE(NET_SETIFCAP, "Set interface capabilities"),
PRIVILEGE(NET_SETIFNAME, "Set interface name"),
PRIVILEGE(NET_SETIFMETRIC, "Set interface metrics"),
PRIVILEGE(NET_SETIFPHYS, "Set interface physical layer prop"),
PRIVILEGE(NET_SETIFMAC, "Set interface MAC label"),
PRIVILEGE(NET_ADDMULTI, "Add multicast addr. to ifnet"),
PRIVILEGE(NET_DELMULTI, "Delete multicast addr. from ifnet"),
PRIVILEGE(NET_HWIOCTL, "Issue hardware ioctl on ifnet"),
PRIVILEGE(NET_SETLLADDR, "Set interface link-level address"),
PRIVILEGE(NET_ADDIFGROUP, "Add new interface group"),
PRIVILEGE(NET_DELIFGROUP, "Delete interface group"),
PRIVILEGE(NET_IFCREATE, "Create cloned interface"),
PRIVILEGE(NET_IFDESTROY, "Destroy cloned interface"),
PRIVILEGE(NET_ADDIFADDR, "Add protocol addr to interface"),
PRIVILEGE(NET_DELIFADDR, "Delete protocol addr on interface"),
PRIVILEGE(NET_LAGG, "Administer lagg interface"),
PRIVILEGE(NET_GIF, "Administer gif interface"),
PRIVILEGE(NET_SETIFVNET, "Move interface to vnet"),
PRIVILEGE(NET_SETIFDESCR, "Set interface description"),
PRIVILEGE(NET_SETIFFIB, "Set interface fib"),
PRIVILEGE(NET_VXLAN, "Administer vxlan"),
#ifdef PRIV_NET_SETVLANPCP
PRIVILEGE(NET_SETVLANPCP, "Set VLAN priority"),
#endif
PRIVILEGE(NET80211_GETKEY, "Query 802.11 keys"),
PRIVILEGE(NET80211_MANAGE, "Administer 802.11"),
PRIVILEGE(NETATALK_RESERVEDPORT, "Bind low port number"),
PRIVILEGE(NETATM_CFG, ""),
PRIVILEGE(NETATM_ADD, ""),
PRIVILEGE(NETATM_DEL, ""),
PRIVILEGE(NETATM_SET, ""),
PRIVILEGE(NETBLUETOOTH_RAW, "Open raw bluetooth socket"),
PRIVILEGE(NETGRAPH_CONTROL, "Open netgraph control socket"),
PRIVILEGE(NETGRAPH_TTY, "Configure tty for netgraph"),
PRIVILEGE(NETINET_RESERVEDPORT, "Bind low port number"),
PRIVILEGE(NETINET_IPFW, "Administer IPFW firewall"),
PRIVILEGE(NETINET_DIVERT, "Open IP divert socket"),
PRIVILEGE(NETINET_PF, "Administer pf firewall"),
PRIVILEGE(NETINET_DUMMYNET, "Administer DUMMYNET"),
PRIVILEGE(NETINET_CARP, "Administer CARP"),
PRIVILEGE(NETINET_MROUTE, "Administer multicast routing"),
PRIVILEGE(NETINET_RAW, "Open netinet raw socket"),
PRIVILEGE(NETINET_GETCRED, "Query netinet pcb credentials"),
PRIVILEGE(NETINET_ADDRCTRL6, "Administer IPv6 address scopes"),
PRIVILEGE(NETINET_ND6, "Administer IPv6 neighbor disc"),
PRIVILEGE(NETINET_SCOPE6, "Administer IPv6 address scopes"),
PRIVILEGE(NETINET_ALIFETIME6, "Administer IPv6 address lifetimes"),
PRIVILEGE(NETINET_IPSEC, "Administer IPSEC"),
PRIVILEGE(NETINET_REUSEPORT, "Allow [rapid] port/address reuse"),
PRIVILEGE(NETINET_SETHDROPTS, "Set certain IPv4/6 header options"),
PRIVILEGE(NETINET_BINDANY, "Allow bind to any address"),
#ifdef PRIV_NETINET_HASHKEY
PRIVILEGE(NETINET_HASHKEY, "Get and set hash keys for IPv4/6"),
#endif
PRIVILEGE(NETIPX_RESERVEDPORT, "Bind low port number"),
PRIVILEGE(NETIPX_RAW, "Open netipx raw socket"),
PRIVILEGE(NETNCP, "Use another user's connection"),
PRIVILEGE(NETSMB, "Use another user's connection"),
PRIVILEGE(VM86_INTCALL, "Allow invoking vm86 int handlers"),
PRIVILEGE(MODULE0, ""),
PRIVILEGE(MODULE1, ""),
PRIVILEGE(MODULE2, ""),
PRIVILEGE(MODULE3, ""),
PRIVILEGE(MODULE4, ""),
PRIVILEGE(MODULE5, ""),
PRIVILEGE(MODULE6, ""),
PRIVILEGE(MODULE7, ""),
PRIVILEGE(MODULE8, ""),
PRIVILEGE(MODULE9, ""),
PRIVILEGE(MODULE10, ""),
PRIVILEGE(MODULE11, ""),
PRIVILEGE(MODULE12, ""),
PRIVILEGE(MODULE13, ""),
PRIVILEGE(MODULE14, ""),
PRIVILEGE(MODULE15, ""),
PRIVILEGE(DDB_CAPTURE, "Allow reading of DDB capture log"),
PRIVILEGE(NNPFS_DEBUG, "Perforn ARLA_VIOC_NNPFSDEBUG"),
PRIVILEGE(CPUCTL_WRMSR, "Write model-specific register"),
PRIVILEGE(CPUCTL_UPDATE, "Update cpu microcode"),
PRIVILEGE(C4B_RESET_CTLR, "Load firmware, reset controller"),
PRIVILEGE(C4B_TRACE, "Unrestricted CAPI message tracing"),
PRIVILEGE(AFS_ADMIN, "Can change AFS client settings"),
PRIVILEGE(AFS_DAEMON, "Can become the AFS daemon"),
PRIVILEGE(RCTL_GET_RACCT, ""),
PRIVILEGE(RCTL_GET_RULES, ""),
PRIVILEGE(RCTL_GET_LIMITS, ""),
PRIVILEGE(RCTL_ADD_RULE, ""),
PRIVILEGE(RCTL_REMOVE_RULE, ""),
PRIVILEGE(KMEM_READ, "Open mem/kmem for reading"),
PRIVILEGE(KMEM_WRITE, "Open mem/kmem for writing"),
#undef PRIVILEGE
};
static int get_privilege_by_name(const char *name) {
unsigned int i = _PRIV_LOWEST;
do {
const char *s = privileges[i].name;
if(s && strcasecmp(s, name) == 0) return i;
} while(++i < _PRIV_HIGHEST);
return -1;
}
static char *get_priv_label_text() {
if(!mac_is_present("priv")) {
fputs("MAC/Privilege not available\n", stderr);
return NULL;
}
mac_t mac;
if(mac_prepare(&mac, "priv") < 0) {
perror("mac_prepare");
return NULL;
}
if(mac_get_proc(mac) < 0) {
perror("mac_get_proc");
mac_free(mac);
return NULL;
}
char *label_text;
if(mac_to_text(mac, &label_text) < 0) {
perror("mac_to_text");
label_text = NULL;
}
mac_free(mac);
return label_text;
}
int get_privileges(char ***names, char ***descriptions, unsigned int *count) {
int r = -1;
char *label_text = get_priv_label_text();
if(!label_text) return -1;
char *p = strchr(label_text, '/');
if(!p) {
fprintf(stderr, "Malformed MAC label string '%s'\n", label_text);
goto cleanup;
}
p++;
char *end_p;
if(names) *names = NULL;
if(descriptions) *descriptions = NULL;
*count = 0;
size_t current_size = 0;
while(*p) {
int n = strtol(p, &end_p, 0);
if(*end_p && *end_p != '/') {
end_p = strchr(p, '/');
if(end_p) *end_p = 0;
n = get_privilege_by_name(p);
} else if(end_p == p) {
fputs("Failed to parse privilege set\n", stderr);
goto failed;
} else if(*end_p) {
*end_p = 0;
} else {
end_p = NULL;
}
if((names || descriptions) && (*count + 1) * sizeof(char *) > current_size) {
current_size += 2 * sizeof(char *);
if(names) {
char **new_p = realloc(*names, current_size);
if(!new_p) {
fputs("Out of memory\n", stderr);
goto failed;
}
*names = new_p;
}
if(descriptions) {
char **new_p = realloc(*descriptions, current_size);
if(!new_p) {
fputs("Out of memory\n", stderr);
goto failed;
}
*descriptions = new_p;
}
}
if(names) {
(*names)[*count] = strdup(n < 0 ? p : privileges[n].name);
if(!(*names)[*count]) {
fputs("Out of memory\n", stderr);
goto failed;
}
}
if(descriptions) {
(*descriptions)[*count] = strdup(n < 0 ? "Unknown" : privileges[n].desc);
if(!(*descriptions)[*count]) {
fputs("Out of memory\n", stderr);
if(names) free((*names)[*count]);
goto failed;
}
}
(*count)++;
if(!end_p) break;
p = end_p + 1;
}
r = 0;
cleanup:
free(label_text);
return r;
failed:
r = -1;
if(names && *names) {
unsigned int i = 0;
while(i < *count) free((*names)[i++]);
free(*names);
}
if(descriptions && *descriptions) {
unsigned int i = 0;
while(i < *count) free((*descriptions)[i++]);
free(*descriptions);
}
goto cleanup;
}
int get_all_privileges(char ***names, char **grants, char ***descriptions, unsigned int *count) {
int r = -1;
char *label_text = get_priv_label_text();
if(!label_text) return -1;
char *next_p = strchr(label_text, '/');
if(!next_p) {
fprintf(stderr, "Malformed MAC label string '%s'\n", label_text);
goto cleanup;
}
char *p = NULL, *end_p;
long int n;
if(names) *names = NULL;
if(grants) *grants = NULL;
if(descriptions) *descriptions = NULL;
*count = 0;
unsigned int current_count = 0;
unsigned int i = _PRIV_LOWEST;
do {
if(!p && next_p) {
p = next_p + 1;
next_p = strchr(p, '/');
if(next_p) *next_p = 0;
n = strtol(p, &end_p, 0);
if(*end_p) n = -1;
}
if((names || grants || descriptions) && (*count + 1) > current_count) {
current_count += 2;
if(names) {
char **new_p = realloc(*names, current_count * sizeof(char *));
if(!new_p) {
fputs("Out of memory\n", stderr);
goto failed;
}
*names = new_p;
}
if(grants) {
char *new_p = realloc(*grants, current_count);
if(!new_p) {
fputs("Out of memory\n", stderr);
goto failed;
}
*grants = new_p;
}
if(descriptions) {
char **new_p = realloc(*descriptions, current_count * sizeof(char *));
if(!new_p) {
fputs("Out of memory\n", stderr);
goto failed;
}
*descriptions = new_p;
}
}
const struct privilege_description *priv = privileges + i;
if(priv->name) {
if(names) (*names)[*count] = strdup(priv->name);
int is_granted = p && strcmp(priv->name, p) == 0;
if(grants) (*grants)[*count] = is_granted;
if(descriptions) (*descriptions)[*count] = strdup(priv->desc);
if(is_granted) p = NULL;
} else if(p && n >= _PRIV_LOWEST && n <= i) {
if(names) (*names)[*count] = strdup(p);
if(grants) (*grants)[*count] = 1;
if(descriptions) (*descriptions)[*count] = strdup("Unknown");
p = NULL;
} else continue;
if(names && !(*names)[*count]) {
fputs("Out of memory\n", stderr);
goto failed;
}
if(descriptions && !(*descriptions)[*count]) {
fputs("Out of memory\n", stderr);
if(names) free((*names)[*count]);
goto failed;
}
(*count)++;
} while(++i < _PRIV_HIGHEST);
r = 0;
cleanup:
free(label_text);
return r;
failed:
r = -1;
if(names && *names) {
unsigned int i = 0;
while(i < *count) free((*names)[i++]);
free(*names);
}
if(grants) free(*grants);
if(descriptions && *descriptions) {
unsigned int i = 0;
while(i < *count) free((*descriptions)[i++]);
free(*descriptions);
}
goto cleanup;
}
int set_privileges(const struct word_list *priv_list, int how) {
if(!mac_is_present("priv")) return -1;
return 0;
}