priv_set_t *priv_str_to_set (const char *buf, const char *sep, const char **endptr) { /* Take a copy of the string since strtok_r will modify it. */ char *str = strdup (buf); if (!str) return NULL; priv_set_t *set = priv_allocset (); if (!set) { free (str); return NULL; } priv_emptyset (set); const priv_data_t *data = __priv_parse_data_cached (); if (!data) return NULL; priv_set_t *basic = data->pd_basicprivs; char *saveptr; char *priv = strtok_r (str, sep, &saveptr); if (!priv) return set; do { if (strcmp (priv, "basic") == 0 && basic) priv_union (basic, set); else if (strcmp (priv, "all") == 0) priv_fillset (set); else if (strcmp (priv, "none") == 0) priv_emptyset (set); else if (strcmp (priv, "zone") == 0) { priv_set_t *zone = priv_allocset (); if (!zone) goto inval; if (zone_getattr (getzoneid (), ZONE_ATTR_PRIVSET, zone, __PRIVSETSIZE) == 0) priv_union (zone, set); priv_freeset (zone); } else { int negate = *str == '-' || *str == '!'; if (negate) str++; int res; if (negate) res = priv_delset (set, str); else res = priv_addset (set, str); if (res == -1) goto inval; } } while ((priv = strtok_r (NULL, sep, &saveptr))) ; free (str); return set; inval: priv_freeset (set); free (str); __set_errno (EINVAL); return NULL; }
/* Specify what privileges an suid root binary needs. */ int __init_suid_priv (int flags, ...) { int res = 0; priv_set_t *permit = NULL, *inherit = NULL, *scratch = NULL; /* Check flags. */ if (flags != PU_LIMITPRIVS && flags != PU_CLEARLIMITSET) return -1; /* We can only initialize once. */ if (__suidset) return -1; /* Do nothing if we are running as root but not setuid root. */ uid_t uid = getuid (); uid_t euid = geteuid (); if (uid == 0 && euid == 0) return 0; /* Allocate a scratch set. */ scratch = priv_allocset (); if (!scratch) goto error; /* Get the basic set. */ const priv_data_t *pd = __priv_parse_data_cached (); if (!pd) goto error; priv_set_t *basic = pd->pd_basicprivs; /* Get the inherited set. */ inherit = priv_allocset (); if (!inherit) goto error; if (getppriv (PRIV_INHERITABLE, inherit) != 0) goto error; /* Get the permitted set. */ permit = priv_allocset (); if (!permit) goto error; if (getppriv (PRIV_PERMITTED, permit) != 0) goto error; /* Get passed privileges. */ __suidset = priv_allocset (); if (!__suidset) goto error; priv_emptyset (__suidset); va_list ap; va_start (ap, flags); const char *priv; while ((priv = va_arg (ap, const char *))) if (priv_addset (__suidset, priv) != 0) goto error; /* Make sure that the passed privileges are a subset of the current permitted privileges. */ if (priv_issubset (__suidset, permit) != _B_TRUE) goto error; /* Set the effective privileges to the inherited ones. */ if (setppriv (PRIV_SET, PRIV_EFFECTIVE, inherit) != 0) goto error; /* Set the permitted privileges to those currently permitted privileges in set of the ones passed in, the inherited ones, and the basic set. */ priv_copyset (__suidset, scratch); priv_union (inherit, scratch); if (basic) priv_union (basic, scratch); priv_intersect (permit, scratch); if (setppriv (PRIV_SET, PRIV_PERMITTED, scratch) != 0) goto error; /* Check if we need to set the limit set. */ if (flags & PU_CLEARLIMITSET) { priv_emptyset (scratch); if (setppriv (PRIV_SET, PRIV_LIMIT, scratch) != 0) goto error; } else if (flags & PU_LIMITPRIVS) { if (setppriv (PRIV_SET, PRIV_LIMIT, scratch) != 0) goto error; } /* Change the uid to the caller's uid if we're setuid root. */ if (euid == 0 && setreuid (uid, uid) != 0) goto error; goto out; error: res = -1; if (__suidset) { priv_freeset (__suidset); __suidset = NULL; } if (euid == 0) setreuid (uid, uid); out: priv_freeset (permit); priv_freeset (inherit); priv_freeset (scratch); return res; }