/* * 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)); }
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 _zexec(const char *a_zoneName, const char *a_path, char *a_argv[]) { zoneid_t zoneid; zone_state_t st; char **new_env = { NULL }; priv_set_t *privset; /* entry assertions */ assert(a_zoneName != NULL); assert(*a_zoneName != '\0'); assert(a_path != NULL); assert(*a_path != '\0'); /* establish locale settings */ (void) setlocale(LC_ALL, ""); (void) textdomain(TEXT_DOMAIN); /* can only be invoked from within the global zone */ if (getzoneid() != GLOBAL_ZONEID) { _z_program_error(ERR_ZEXEC_NOT_IN_GZ, a_zoneName); return (-1); } if (strcmp(a_zoneName, GLOBAL_ZONENAME) == 0) { _z_program_error(ERR_ZEXEC_GZUSED, a_zoneName); return (-1); } /* get the state of the specified zone */ if (zone_get_state((char *)a_zoneName, &st) != Z_OK) { _z_program_error(ERR_ZEXEC_BADZONE, a_zoneName); return (-1); } if (st < ZONE_STATE_INSTALLED) { _z_program_error(ERR_ZEXEC_BADSTATE, a_zoneName, zone_state_str(st)); return (-1); } if (st != ZONE_STATE_RUNNING && st != ZONE_STATE_MOUNTED) { _z_program_error(ERR_ZEXEC_NOTRUNNING, a_zoneName, zone_state_str(st)); return (-1); } /* * In both console and non-console cases, we require all privs. * In the console case, because we may need to startup zoneadmd. * In the non-console case in order to do zone_enter(2), zonept() * and other tasks. * * Future work: this solution is temporary. Ultimately, we need to * move to a flexible system which allows the global admin to * designate that a particular user can zlogin (and probably zlogin * -C) to a particular zone. This all-root business we have now is * quite sketchy. */ if ((privset = priv_allocset()) == NULL) { _z_program_error(ERR_ZEXEC_PRIV_ALLOCSET, a_zoneName, strerror(errno)); return (-1); } if (getppriv(PRIV_EFFECTIVE, privset) != 0) { _z_program_error(ERR_ZEXEC_GETPPRIV, a_zoneName, strerror(errno)); priv_freeset(privset); return (-1); } if (priv_isfullset(privset) == B_FALSE) { _z_program_error(ERR_ZEXEC_PRIVS, a_zoneName); priv_freeset(privset); return (-1); } priv_freeset(privset); if ((zoneid = getzoneidbyname(a_zoneName)) == -1) { _z_program_error(ERR_ZEXEC_NOZONEID, a_zoneName, strerror(errno)); return (-1); } if ((new_env = _zexec_prep_env()) == NULL) { _z_program_error(ERR_ZEXEC_ASSEMBLE, a_zoneName); return (-1); } /* * In case any of stdin, stdout or stderr are streams, * anchor them to prevent malicious I_POPs. * * Future work: use pipes to entirely eliminate FD leakage * into the zone. */ (void) ioctl(STDIN_FILENO, I_ANCHOR); (void) ioctl(STDOUT_FILENO, I_ANCHOR); (void) ioctl(STDERR_FILENO, I_ANCHOR); if (zone_enter(zoneid) == -1) { int lerrno = errno; _z_program_error(ERR_ZEXEC_ZONEENTER, a_zoneName, strerror(errno)); if (lerrno == EFAULT) { _z_program_error(ERR_ZEXEC_EFAULT, a_zoneName); } free(new_env); return (-1); } (void) execve(a_path, &a_argv[0], new_env); _z_program_error(ERR_ZEXEC_EXECFAILURE, a_zoneName, strerror(errno)); return (-1); }