static int dumppriv(char **argv) { int rc = 0; const char *pname; int i; if (argv[0] == NULL) { for (i = 0; ((pname = priv_getbynum(i++)) != NULL); ) rc += dopriv(pname); } else { for (; *argv; argv++) { priv_set_t *pset = priv_str_to_set(*argv, ",", NULL); if (pset == NULL) { (void) fprintf(stderr, "%s: %s: bad privilege" " list\n", command, *argv); rc++; continue; } for (i = 0; ((pname = priv_getbynum(i++)) != NULL); ) if (priv_ismember(pset, pname)) rc += dopriv(pname); } } return (rc); }
/* Try to remove priv from the effective set. Returns 0 if priv was removed. Returns -1 on error with errno set appropriately. */ int priv_set_remove (const char *priv) { if (! initialized && priv_set_initialize () != 0) return -1; if (priv_ismember (eff_set, priv)) { /* priv_addset/priv_delset can only fail if priv is invalid, which is checked above by the priv_ismember call. */ priv_delset (eff_set, priv); if (setppriv (PRIV_SET, PRIV_EFFECTIVE, eff_set) != 0) { priv_addset (eff_set, priv); return -1; } priv_addset (rem_set, priv); } else { errno = EINVAL; return -1; } return 0; }
int main (void) { #if HAVE_GETPPRIV && HAVE_PRIV_H priv_set_t *set; ASSERT (set = priv_allocset ()); ASSERT (getppriv (PRIV_EFFECTIVE, set) == 0); ASSERT (priv_ismember (set, PRIV_PROC_EXEC) == 1); /* Do a series of removes and restores making sure that the results are consistent with our ismember function and solaris' priv_ismember. */ ASSERT (priv_set_ismember (PRIV_PROC_EXEC) == 1); ASSERT (getppriv (PRIV_EFFECTIVE, set) == 0); ASSERT (priv_ismember (set, PRIV_PROC_EXEC) == 1); ASSERT (priv_set_restore (PRIV_PROC_EXEC) == -1); ASSERT (errno == EINVAL); ASSERT (priv_set_ismember (PRIV_PROC_EXEC) == 1); ASSERT (getppriv (PRIV_EFFECTIVE, set) == 0); ASSERT (priv_ismember (set, PRIV_PROC_EXEC) == 1); ASSERT (priv_set_remove (PRIV_PROC_EXEC) == 0); ASSERT (priv_set_ismember (PRIV_PROC_EXEC) == 0); ASSERT (getppriv (PRIV_EFFECTIVE, set) == 0); ASSERT (priv_ismember (set, PRIV_PROC_EXEC) == 0); ASSERT (priv_set_remove (PRIV_PROC_EXEC) == -1); ASSERT (errno == EINVAL); ASSERT (priv_set_ismember (PRIV_PROC_EXEC) == 0); ASSERT (getppriv (PRIV_EFFECTIVE, set) == 0); ASSERT (priv_ismember (set, PRIV_PROC_EXEC) == 0); ASSERT (priv_set_restore (PRIV_PROC_EXEC) == 0); ASSERT (priv_set_ismember (PRIV_PROC_EXEC) == 1); ASSERT (getppriv (PRIV_EFFECTIVE, set) == 0); ASSERT (priv_ismember (set, PRIV_PROC_EXEC) == 1); ASSERT (priv_set_restore (PRIV_PROC_EXEC) == -1); ASSERT (errno == EINVAL); ASSERT (priv_set_ismember (PRIV_PROC_EXEC) == 1); ASSERT (getppriv (PRIV_EFFECTIVE, set) == 0); ASSERT (priv_ismember (set, PRIV_PROC_EXEC) == 1); /* Test the priv_set_linkdir wrappers. */ ASSERT (getppriv (PRIV_EFFECTIVE, set) == 0); if (priv_ismember (set, PRIV_SYS_LINKDIR)) { ASSERT (priv_set_restore_linkdir () == -1); ASSERT (errno == EINVAL); ASSERT (priv_set_remove_linkdir () == 0); ASSERT (priv_set_remove_linkdir () == -1); ASSERT (errno == EINVAL); ASSERT (priv_set_restore_linkdir () == 0); } #else ASSERT (priv_set_restore_linkdir () == -1); ASSERT (priv_set_remove_linkdir () == -1); #endif return 0; }
/* Check if priv is in the effective set. Returns 1 if priv is a member and 0 if not. Returns -1 on error with errno set appropriately. */ int priv_set_ismember (const char *priv) { if (! initialized && priv_set_initialize () != 0) return -1; return priv_ismember (eff_set, priv); }
static void N2N_check_priv( void *buf, char *dc_str) { nss_pheader_t *phdr = (nss_pheader_t *)buf; ucred_t *uc = NULL; const priv_set_t *eset; zoneid_t zoneid; int errnum; char *me = "N2N_check_priv"; if (door_ucred(&uc) != 0) { errnum = errno; _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG) (me, "door_ucred: %s\n", strerror(errno)); NSCD_RETURN_STATUS(phdr, NSS_ERROR, errnum); } eset = ucred_getprivset(uc, PRIV_EFFECTIVE); zoneid = ucred_getzoneid(uc); if ((zoneid != GLOBAL_ZONEID && zoneid != getzoneid()) || eset != NULL ? !priv_ismember(eset, PRIV_SYS_ADMIN) : ucred_geteuid(uc) != 0) { _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ALERT) (me, "%s call failed(cred): caller pid %d, uid %d, " "euid %d, zoneid %d\n", dc_str, ucred_getpid(uc), ucred_getruid(uc), ucred_geteuid(uc), zoneid); ucred_free(uc); NSCD_RETURN_STATUS(phdr, NSS_ERROR, EACCES); } _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG) (me, "nscd received %s cmd from pid %d, uid %d, " "euid %d, zoneid %d\n", dc_str, ucred_getpid(uc), ucred_getruid(uc), ucred_geteuid(uc), zoneid); ucred_free(uc); NSCD_RETURN_STATUS_SUCCESS(phdr); }
/* * Check to see if the door client's euid is 0 or if it has required_priv * privilege. Return 0 if yes, -1 otherwise. * Supported values for required_priv are: * - NSCD_ALL_PRIV: for all zones privileges * - NSCD_READ_PRIV: for PRIV_FILE_DAC_READ privilege */ int _nscd_check_client_priv(int required_priv) { int rc = 0; ucred_t *uc = NULL; const priv_set_t *eset; char *me = "_nscd_check_client_read_priv"; priv_set_t *zs; /* zone */ if (door_ucred(&uc) != 0) { _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR) (me, "door_ucred: %s\n", strerror(errno)); return (-1); } if (ucred_geteuid(uc) == 0) { ucred_free(uc); return (0); } eset = ucred_getprivset(uc, PRIV_EFFECTIVE); switch (required_priv) { case NSCD_ALL_PRIV: zs = priv_str_to_set("zone", ",", NULL); if (!priv_isequalset(eset, zs)) { _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR) (me, "missing all zones privileges\n"); rc = -1; } priv_freeset(zs); break; case NSCD_READ_PRIV: if (!priv_ismember(eset, PRIV_FILE_DAC_READ)) rc = -1; break; default: _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR) (me, "unknown required_priv: %d\n", required_priv); rc = -1; break; } ucred_free(uc); return (rc); }
void dump_privs(void) { const char *pname; int i; priv_set_t *pset = priv_str_to_set("zone", ",", NULL); if (pset == NULL) { (void) fprintf(stderr, "unable to create priv_set for 'zone'\n"); return; } (void) puts("== Zone privileges =="); for (i = 0; ((pname = priv_getbynum(i++)) != NULL); ) { if (priv_ismember(pset, pname)) { (void) puts(pname); } } }
/* * Utillity function to fetch the XPRT's ucred and determine if we should deny * the request. For now, we implement a simple policy of rejecting any caller * who does not have the PRIV_SYS_CONFIG bit in their Effective privilege set, * unless the caller is loading a module, which requires all privileges. */ int fmd_rpc_deny(struct svc_req *rqp) { ucred_t *ucp = alloca(ucred_size()); const priv_set_t *psp; if (svc_getcallerucred(rqp->rq_xprt, &ucp) != 0 || (psp = ucred_getprivset(ucp, PRIV_EFFECTIVE)) == NULL) return (1); /* deny access if we can't get credentials */ #ifndef DEBUG /* * For convenience of testing, we only require all privileges for a * module load when running a non-DEBUG fault management daemon. */ if (rqp->rq_proc == FMD_ADM_MODLOAD) return (!priv_isfullset(psp)); #endif return (!priv_ismember(psp, PRIV_SYS_CONFIG)); }
/* * remove_zfs -- unshare a ZVOL from the target */ static char * remove_zfs(tgt_node_t *x, ucred_t *cred) { char *prop; char *msg = NULL; tgt_node_t *targ = NULL; libzfs_handle_t *zh = NULL; const priv_set_t *eset; if (tgt_find_value_str(x, XML_ELEMENT_NAME, &prop) == False) { xml_rtn_msg(&msg, ERR_SYNTAX_MISSING_NAME); return (msg); } if ((zh = libzfs_init()) == NULL) { xml_rtn_msg(&msg, ERR_INTERNAL_ERROR); free(prop); return (msg); } eset = ucred_getprivset(cred, PRIV_EFFECTIVE); if (eset != NULL ? !priv_ismember(eset, PRIV_SYS_CONFIG) : ucred_geteuid(cred) != 0) { /* * See if user has ZFS dataset permissions to do operation */ if (zfs_iscsi_perm_check(zh, prop, cred) != 0) { xml_rtn_msg(&msg, ERR_NO_PERMISSION); free(prop); libzfs_fini(zh); return (msg); } } libzfs_fini(zh); while ((targ = tgt_node_next(targets_config, XML_ELEMENT_TARG, targ)) != NULL) { if (strcmp(targ->x_value, prop) == 0) break; } free(prop); if (targ == NULL) { /* * We're unsharing a target. If we don't have a reference * then there's no problem. */ xml_rtn_msg(&msg, ERR_SUCCESS); return (msg); } if (tgt_find_value_str(targ, XML_ELEMENT_INAME, &prop) == False) { xml_rtn_msg(&msg, ERR_TARGCFG_MISSING_INAME); return (msg); } tgt_node_remove(targets_config, targ, MatchBoth); /* * Wait until here to issue a logout to any initiators that * might be logged into the target. Certain initiators are * sneaky in that if asked to logout they will, but turn right * around and log back into the target. By waiting until here * to issue the logout we'll have removed reference to the target * such that this can't happen. */ if (isns_enabled() == True) { if (isns_dereg(prop) != 0) syslog(LOG_INFO, "ISNS dereg failed\n"); } logout_targ(prop); free(prop); xml_rtn_msg(&msg, ERR_SUCCESS); return (msg); }
token_t * au_to_privset( const char *set, const priv_set_t *pset, char data_header, int success) { token_t *token, *m; adr_t adr; int priv; const char *pname; char sf = (char)success; char *buf, *q; short sz; boolean_t full; token = au_getclr(); adr_start(&adr, memtod(token, char *)); adr_char(&adr, &data_header, 1); /* * set is not used for AUT_UPRIV and sf (== success) is not * used for AUT_PRIV */ if (data_header == AUT_UPRIV) { adr_char(&adr, &sf, 1); } else { sz = strlen(set) + 1; adr_short(&adr, &sz, 1); token->len = (uchar_t)adr_count(&adr); m = au_getclr(); (void) au_append_buf(set, sz, m); (void) au_append_rec(token, m, AU_PACK); adr.adr_now += sz; } full = priv_isfullset(pset); if (full) { buf = "ALL"; sz = strlen(buf) + 1; } else { q = buf = kmem_alloc(maxprivbytes, KM_SLEEP); *buf = '\0'; for (priv = 0; (pname = priv_getbynum(priv)) != NULL; priv++) { if (priv_ismember(pset, priv)) { if (q != buf) *q++ = ','; (void) strcpy(q, pname); q += strlen(q); } } sz = (q - buf) + 1; } adr_short(&adr, &sz, 1); token->len = (uchar_t)adr_count(&adr); m = au_getclr(); (void) au_append_buf(buf, sz, m); (void) au_append_rec(token, m, AU_PACK); if (!full) kmem_free(buf, maxprivbytes); return (token); }
int main(int argc, char **argv) { #if !defined(__APPLE__) ucred_t *ucp; #endif int err; int opt_C = 0, opt_H = 0, opt_p = 0, opt_v = 0; char c, *p, *end; struct sigaction act; int done = 0; g_pname = basename(argv[0]); argv[0] = g_pname; /* rewrite argv[0] for getopt errors */ /* * Make sure we have the required dtrace_proc privilege. */ #if !defined(__APPLE__) if ((ucp = ucred_get(getpid())) != NULL) { const priv_set_t *psp; if ((psp = ucred_getprivset(ucp, PRIV_EFFECTIVE)) != NULL && !priv_ismember(psp, PRIV_DTRACE_PROC)) { fatal("dtrace_proc privilege required\n"); } ucred_free(ucp); } #endif while ((c = getopt(argc, argv, PLOCKSTAT_OPTSTR)) != EOF) { switch (c) { case 'n': errno = 0; g_nent = strtoul(optarg, &end, 10); if (*end != '\0' || errno != 0) { (void) fprintf(stderr, "%s: invalid count " "'%s'\n", g_pname, optarg); usage(); } break; case 'p': opt_p = 1; break; case 'v': opt_v = 1; break; case 'A': opt_C = opt_H = 1; break; case 'C': opt_C = 1; break; case 'H': opt_H = 1; break; case 'V': g_opt_V = 1; break; default: if (strchr(PLOCKSTAT_OPTSTR, c) == NULL) usage(); } } /* * We need a command or at least one pid. */ if (argc == optind) usage(); if (opt_C == 0 && opt_H == 0) opt_C = 1; if ((g_dtp = dtrace_open(DTRACE_VERSION, 0, &err)) == NULL) fatal("failed to initialize dtrace: %s\n", dtrace_errmsg(NULL, err)); /* * The longest string we trace is 23 bytes long -- so 32 is plenty. */ if (dtrace_setopt(g_dtp, "strsize", "32") == -1) dfatal("failed to set 'strsize'"); /* * 1k should be more than enough for all trace() and printa() actions. */ if (dtrace_setopt(g_dtp, "bufsize", "1k") == -1) dfatal("failed to set 'bufsize'"); /* * The table we produce has the hottest locks at the top. */ if (dtrace_setopt(g_dtp, "aggsortrev", NULL) == -1) dfatal("failed to set 'aggsortrev'"); /* * These are two reasonable defaults which should suffice. */ if (dtrace_setopt(g_dtp, "aggsize", "256k") == -1) dfatal("failed to set 'aggsize'"); if (dtrace_setopt(g_dtp, "aggrate", "1sec") == -1) dfatal("failed to set 'aggrate'"); /* * Take a second pass through to look for options that set options now * that we have an open dtrace handle. */ optind = 1; while ((c = getopt(argc, argv, PLOCKSTAT_OPTSTR)) != EOF) { switch (c) { case 's': g_opt_s = 1; if (dtrace_setopt(g_dtp, "ustackframes", optarg) == -1) dfatal("failed to set 'ustackframes'"); break; case 'x': if ((p = strchr(optarg, '=')) != NULL) *p++ = '\0'; if (dtrace_setopt(g_dtp, optarg, p) != 0) dfatal("failed to set -x %s", optarg); break; case 'e': errno = 0; (void) strtoul(optarg, &end, 10); if (*optarg == '-' || *end != '\0' || errno != 0) { (void) fprintf(stderr, "%s: invalid timeout " "'%s'\n", g_pname, optarg); usage(); } /* * Construct a DTrace enabling that will exit after * the specified number of seconds. */ dprog_add("BEGIN\n{\n\tend = timestamp + "); dprog_add(optarg); dprog_add(" * 1000000000;\n}\n"); dprog_add("tick-10hz\n/timestamp >= end/\n"); dprog_add("{\n\texit(0);\n}\n"); break; } } argc -= optind; argv += optind; if (opt_H) { dprog_add(g_hold_init); if (g_opt_s == NULL) dprog_add(g_hold_times); else dprog_add(g_hold_histogram); } if (opt_C) { dprog_add(g_ctnd_init); if (g_opt_s == NULL) dprog_add(g_ctnd_times); else dprog_add(g_ctnd_histogram); } if (opt_p) { ulong_t pid; if (argc > 1) { (void) fprintf(stderr, "%s: only one pid is allowed\n", g_pname); usage(); } errno = 0; pid = strtoul(argv[0], &end, 10); if (*end != '\0' || errno != 0 || (pid_t)pid != pid) { (void) fprintf(stderr, "%s: invalid pid '%s'\n", g_pname, argv[0]); usage(); } if ((g_pr = dtrace_proc_grab(g_dtp, (pid_t)pid, 0)) == NULL) dfatal(NULL); } else { if ((g_pr = dtrace_proc_create(g_dtp, argv[0], argv)) == NULL) dfatal(NULL); } dprog_compile(); if (dtrace_handle_proc(g_dtp, &prochandler, NULL) == -1) dfatal("failed to establish proc handler"); (void) sigemptyset(&act.sa_mask); act.sa_flags = 0; act.sa_handler = intr; (void) sigaction(SIGINT, &act, NULL); (void) sigaction(SIGTERM, &act, NULL); if (dtrace_go(g_dtp) != 0) dfatal("dtrace_go()"); if (dtrace_getopt(g_dtp, "ustackframes", &g_nframes) != 0) dfatal("failed to get 'ustackframes'"); dtrace_proc_continue(g_dtp, g_pr); if (opt_v) (void) printf("%s: tracing enabled for pid %d\n", g_pname, (int)Pstatus(g_pr)->pr_pid); do { if (!g_intr && !done) dtrace_sleep(g_dtp); if (done || g_intr || g_exited) { done = 1; if (dtrace_stop(g_dtp) == -1) dfatal("couldn't stop tracing"); } switch (dtrace_work(g_dtp, stdout, NULL, chewrec, NULL)) { case DTRACE_WORKSTATUS_DONE: done = 1; break; case DTRACE_WORKSTATUS_OKAY: break; default: dfatal("processing aborted"); } } while (!done); dtrace_close(g_dtp); return (0); }