Beispiel #1
0
/*
 * 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);
}
Beispiel #3
0
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);
}