static void vjs_waive(enum jail_gen_e jge) { priv_set_t *effective, *inheritable, *permitted, *limited; if (!(effective = priv_allocset()) || !(inheritable = priv_allocset()) || !(permitted = priv_allocset()) || !(limited = priv_allocset())) { MGT_complain(C_SECURITY, "Solaris Jail warning: " " vjs_waive - priv_allocset failed: errno=%d (%s)", errno, strerror(errno)); return; } /* * inheritable and effective are distinct sets * effective is a subset of permitted * limit is the union of all */ priv_emptyset(inheritable); vjs_add_inheritable(inheritable, jge); priv_emptyset(effective); vjs_add_effective(effective, jge); priv_copyset(effective, permitted); vjs_add_permitted(permitted, jge); priv_copyset(inheritable, limited); priv_union(permitted, limited); /* * invert the sets and clear privileges such that setppriv will always * succeed */ priv_inverse(limited); priv_inverse(permitted); priv_inverse(effective); priv_inverse(inheritable); AZ(setppriv(PRIV_OFF, PRIV_LIMIT, limited)); AZ(setppriv(PRIV_OFF, PRIV_PERMITTED, permitted)); AZ(setppriv(PRIV_OFF, PRIV_EFFECTIVE, effective)); AZ(setppriv(PRIV_OFF, PRIV_INHERITABLE, inheritable)); priv_freeset(limited); priv_freeset(permitted); priv_freeset(effective); priv_freeset(inheritable); }
static void mgt_sandbox_solaris_waive(enum sandbox_e who) { priv_set_t *effective, *inheritable, *permitted; if (!(effective = priv_allocset()) || !(inheritable = priv_allocset()) || !(permitted = priv_allocset())) { REPORT(LOG_ERR, "Sandbox warning: " " mgt_sandbox_waive - priv_allocset failed: errno=%d (%s)", errno, strerror(errno)); return; } /* * simple scheme: * (inheritable subset-of effective) subset-of permitted */ priv_emptyset(inheritable); mgt_sandbox_solaris_add_inheritable(inheritable, who); priv_copyset(inheritable, effective); mgt_sandbox_solaris_add_effective(effective, who); priv_copyset(effective, permitted); mgt_sandbox_solaris_add_permitted(permitted, who); /* * invert the sets and clear privileges such that setppriv will always * succeed */ priv_inverse(inheritable); priv_inverse(effective); priv_inverse(permitted); AZ(setppriv(PRIV_OFF, PRIV_LIMIT, permitted)); AZ(setppriv(PRIV_OFF, PRIV_PERMITTED, permitted)); AZ(setppriv(PRIV_OFF, PRIV_EFFECTIVE, effective)); AZ(setppriv(PRIV_OFF, PRIV_INHERITABLE, inheritable)); priv_freeset(inheritable); priv_freeset(effective); priv_freeset(permitted); }
void mgt_sandbox_solaris_fini(void) { priv_set_t *effective, *inheritable, *permitted; if (!(effective = priv_allocset()) || !(inheritable = priv_allocset()) || !(permitted = priv_allocset())) { REPORT(LOG_ERR, "Child start warning: mgt_sandbox_waive - priv_allocset failed: errno=%d (%s)", errno, strerror(errno)); return; } priv_emptyset(inheritable); priv_emptyset(effective); mgt_sandbox_solaris_add_effective(effective); priv_copyset(effective, permitted); mgt_sandbox_solaris_add_permitted(permitted); /* * invert the sets and clear privileges such that setppriv will always * succeed */ priv_inverse(inheritable); priv_inverse(effective); priv_inverse(permitted); #define SETPPRIV(which, set) \ if (setppriv(PRIV_OFF, which, set)) \ REPORT(LOG_ERR, \ "Child start warning: Waiving privileges failed on %s: errno=%d (%s)", \ #which, errno, strerror(errno)); SETPPRIV(PRIV_INHERITABLE, inheritable); SETPPRIV(PRIV_EFFECTIVE, effective); SETPPRIV(PRIV_PERMITTED, permitted); SETPPRIV(PRIV_LIMIT, permitted); #undef SETPPRIV priv_freeset(inheritable); priv_freeset(effective); }
static void setup_privs() { priv_set_t *privset; if (seteuid(getuid()) == -1 || setegid(getgid()) == -1) die(gettext("seteuid()/setegid() failed")); /* * Add our privileges and remove unneeded 'basic' privileges from the * permitted set. */ if ((privset = priv_str_to_set("basic", ",", NULL)) == NULL) die(gettext("cannot setup privileges")); (void) priv_addset(privset, PRIV_SYS_ACCT); (void) priv_addset(privset, PRIV_FILE_DAC_WRITE); (void) priv_addset(privset, PRIV_SYS_DL_CONFIG); (void) priv_delset(privset, PRIV_FILE_LINK_ANY); (void) priv_delset(privset, PRIV_PROC_EXEC); (void) priv_delset(privset, PRIV_PROC_FORK); (void) priv_delset(privset, PRIV_PROC_INFO); (void) priv_delset(privset, PRIV_PROC_SESSION); priv_inverse(privset); if (setppriv(PRIV_OFF, PRIV_PERMITTED, privset) == -1) die(gettext("cannot setup privileges")); priv_freeset(privset); /* * Clear the Inheritable and Limit sets. */ if ((privset = priv_allocset()) == NULL) die(gettext("cannot setup privileges")); priv_emptyset(privset); if (setppriv(PRIV_SET, PRIV_INHERITABLE, privset) == -1 || setppriv(PRIV_SET, PRIV_LIMIT, privset) == -1) die(gettext("cannot setup privileges")); /* * Turn off the sys_acct, file_dac_write and dl_config privileges * until needed. */ (void) priv_set(PRIV_OFF, PRIV_EFFECTIVE, PRIV_FILE_DAC_WRITE, PRIV_SYS_ACCT, PRIV_SYS_DL_CONFIG, NULL); }
/* * Most privileges, except the ones that are required for smbd, are turn off * in the effective set. They will be turn on when needed for command * execution during share connection/disconnection. */ static void smbd_daemonize_fini(int fd, int exit_status) { priv_set_t *pset; /* * Now that we're running, if a pipe fd was specified, write an exit * status to it to indicate that our parent process can safely detach. * Then proceed to loading the remaining non-built-in modules. */ if (fd >= 0) (void) write(fd, &exit_status, sizeof (exit_status)); (void) close(fd); pset = priv_allocset(); if (pset == NULL) return; priv_basicset(pset); /* list of privileges for smbd */ (void) priv_addset(pset, PRIV_NET_MAC_AWARE); (void) priv_addset(pset, PRIV_NET_PRIVADDR); (void) priv_addset(pset, PRIV_PROC_AUDIT); (void) priv_addset(pset, PRIV_SYS_DEVICES); (void) priv_addset(pset, PRIV_SYS_SMB); (void) priv_addset(pset, PRIV_SYS_MOUNT); priv_inverse(pset); /* turn off unneeded privileges */ (void) setppriv(PRIV_OFF, PRIV_EFFECTIVE, pset); priv_freeset(pset); /* reenable core dumps */ __fini_daemon_priv(NULL); }
void checkAsRoot() { #ifndef __CYGWIN__ #ifdef SOLAR_PRIV priv_set_t *privset; char *p; /* Get the basic set */ privset = priv_str_to_set("basic", ",", NULL); if (privset == NULL) { die("ERROR: Could not get basic privset from priv_str_to_set()."); } else { p = priv_set_to_str(privset, ',', 0); SPINE_LOG_DEBUG(("DEBUG: Basic privset is: '%s'.", p != NULL ? p : "Unknown")); } /* Add priviledge to send/receive ICMP packets */ if (priv_addset(privset, PRIV_NET_ICMPACCESS) < 0 ) { SPINE_LOG_DEBUG(("Warning: Addition of PRIV_NET_ICMPACCESS to privset failed: '%s'.", strerror(errno))); } /* Compute the set of privileges that are never needed */ priv_inverse(privset); /* Remove the set of unneeded privs from Permitted (and by * implication from Effective) */ if (setppriv(PRIV_OFF, PRIV_PERMITTED, privset) < 0) { SPINE_LOG_DEBUG(("Warning: Dropping privileges from PRIV_PERMITTED failed: '%s'.", strerror(errno))); } /* Remove unneeded priv set from Limit to be safe */ if (setppriv(PRIV_OFF, PRIV_LIMIT, privset) < 0) { SPINE_LOG_DEBUG(("Warning: Dropping privileges from PRIV_LIMIT failed: '%s'.", strerror(errno))); } boolean_t pe = priv_ineffect(PRIV_NET_ICMPACCESS); SPINE_LOG_DEBUG(("DEBUG: Privilege PRIV_NET_ICMPACCESS is: '%s'.", pe != 0 ? "Enabled" : "Disabled")); set.icmp_avail = pe; /* Free the privset */ priv_freeset(privset); free(p); #else if (hasCaps() != TRUE) { seteuid(0); if (geteuid() != 0) { SPINE_LOG_DEBUG(("WARNING: Spine NOT running asroot. This is required if using ICMP. Please run \"chmod +s;chown root:root spine\" to resolve.")); set.icmp_avail = FALSE; }else{ SPINE_LOG_DEBUG(("DEBUG: Spine is running asroot.")); set.icmp_avail = TRUE; seteuid(getuid()); } } else { SPINE_LOG_DEBUG(("DEBUG: Spine has cap_net_raw capability.")); set.icmp_avail = TRUE; } #endif #endif }
/* * setppriv (priv_op_t, priv_ptype_t, priv_set_t) */ static int setppriv(priv_op_t op, priv_ptype_t type, priv_set_t *in_pset) { priv_set_t pset, *target; cred_t *cr, *pcr; proc_t *p; boolean_t donocd = B_FALSE; if (!PRIV_VALIDSET(type) || !PRIV_VALIDOP(op)) return (set_errno(EINVAL)); if (copyin(in_pset, &pset, sizeof (priv_set_t))) return (set_errno(EFAULT)); p = ttoproc(curthread); cr = cralloc(); mutex_enter(&p->p_crlock); retry: pcr = p->p_cred; if (AU_AUDITING()) audit_setppriv(op, type, &pset, pcr); /* * Filter out unallowed request (bad op and bad type) */ switch (op) { case PRIV_ON: case PRIV_SET: /* * Turning on privileges; the limit set cannot grow, * other sets can but only as long as they remain subsets * of P. Only immediately after exec holds that P <= L. */ if (type == PRIV_LIMIT && !priv_issubset(&pset, &CR_LPRIV(pcr))) { mutex_exit(&p->p_crlock); crfree(cr); return (set_errno(EPERM)); } if (!priv_issubset(&pset, &CR_OPPRIV(pcr)) && !priv_issubset(&pset, priv_getset(pcr, type))) { mutex_exit(&p->p_crlock); /* Policy override should not grow beyond L either */ if (type != PRIV_INHERITABLE || !priv_issubset(&pset, &CR_LPRIV(pcr)) || secpolicy_require_privs(CRED(), &pset) != 0) { crfree(cr); return (set_errno(EPERM)); } mutex_enter(&p->p_crlock); if (pcr != p->p_cred) goto retry; donocd = B_TRUE; } break; case PRIV_OFF: /* PRIV_OFF is always allowed */ break; } /* * OK! everything is cool. * Do cred COW. */ crcopy_to(pcr, cr); /* * If we change the effective, permitted or limit set, we attain * "privilege awareness". */ if (type != PRIV_INHERITABLE) priv_set_PA(cr); target = &(CR_PRIVS(cr)->crprivs[type]); switch (op) { case PRIV_ON: priv_union(&pset, target); break; case PRIV_OFF: priv_inverse(&pset); priv_intersect(target, &pset); /* * Fall-thru to set target and change other process * privilege sets. */ /*FALLTHRU*/ case PRIV_SET: *target = pset; /* * Take privileges no longer permitted out * of other effective sets as well. * Limit set is enforced at exec() time. */ if (type == PRIV_PERMITTED) priv_intersect(&pset, &CR_EPRIV(cr)); break; } /* * When we give up privileges not in the inheritable set, * set SNOCD if not already set; first we compute the * privileges removed from P using Diff = (~P') & P * and then we check whether the removed privileges are * a subset of I. If we retain uid 0, all privileges * are required anyway so don't set SNOCD. */ if (type == PRIV_PERMITTED && (p->p_flag & SNOCD) == 0 && cr->cr_uid != 0 && cr->cr_ruid != 0 && cr->cr_suid != 0) { priv_set_t diff = CR_OPPRIV(cr); priv_inverse(&diff); priv_intersect(&CR_OPPRIV(pcr), &diff); donocd = !priv_issubset(&diff, &CR_IPRIV(cr)); } p->p_cred = cr; mutex_exit(&p->p_crlock); if (donocd) { mutex_enter(&p->p_lock); p->p_flag |= SNOCD; mutex_exit(&p->p_lock); } /* * The basic_test privilege should not be removed from E; * if that has happened, then some programmer typically set the E/P to * empty. That is not portable. */ if ((type == PRIV_EFFECTIVE || type == PRIV_PERMITTED) && priv_basic_test >= 0 && !PRIV_ISASSERT(target, priv_basic_test)) { proc_t *p = curproc; pid_t pid = p->p_pid; char *fn = PTOU(p)->u_comm; cmn_err(CE_WARN, "%s[%d]: setppriv: basic_test privilege " "removed from E/P", fn, pid); } crset(p, cr); /* broadcast to process threads */ return (0); }
static int parsespec(const char *spec) { char *p; const char *q; int count; priv_set_t ***toupd; priv_set_t *upd; int i; boolean_t freeupd = B_TRUE; if (pri == NULL) loadprivinfo(); p = strpbrk(spec, "+-="); if (p == NULL || p - spec > pri->priv_nsets) badspec(spec); if (p[1] == '\0' || (upd = priv_str_to_set(p + 1, ",", NULL)) == NULL) badspec(p + 1); count = p - spec; switch (*p) { case '+': toupd = &add; break; case '-': toupd = &rem; priv_inverse(upd); break; case '=': toupd = &assign; break; } /* Update all sets? */ if (count == 0 || *spec == 'a' || *spec == 'A') { count = pri->priv_nsets; q = sets; } else q = spec; for (i = 0; i < count; i++) { int ind = strindex(q[i], sets); if (ind == -1) badspec(spec); /* Assign is mutually exclusive with add/remove and itself */ if (((toupd == &rem || toupd == &add) && assign[ind] != NULL) || (toupd == &assign && (assign[ind] != NULL || rem[ind] != NULL || add[ind] != NULL))) { (void) fprintf(stderr, "%s: conflicting spec: %s\n", command, spec); exit(1); } if ((*toupd)[ind] != NULL) { if (*p == '-') priv_intersect(upd, (*toupd)[ind]); else priv_union(upd, (*toupd)[ind]); } else { (*toupd)[ind] = upd; freeupd = B_FALSE; } } if (freeupd) priv_freeset(upd); return (0); }