xref: /onnv-gate/usr/src/lib/libc/port/gen/privlib.c (revision 12273:63678502e95e)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
51059Scasper  * Common Development and Distribution License (the "License").
61059Scasper  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
213864Sraf 
220Sstevel@tonic-gate /*
23*12273SCasper.Dik@Sun.COM  * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
266812Sraf #pragma weak _getprivimplinfo	= getprivimplinfo
276812Sraf #pragma weak _priv_addset	= priv_addset
286812Sraf #pragma weak _priv_allocset	= priv_allocset
296812Sraf #pragma weak _priv_copyset	= priv_copyset
306812Sraf #pragma weak _priv_delset	= priv_delset
316812Sraf #pragma weak _priv_emptyset	= priv_emptyset
3211537SCasper.Dik@Sun.COM #pragma weak _priv_basicset	= priv_basicset
336812Sraf #pragma weak _priv_fillset	= priv_fillset
346812Sraf #pragma weak _priv_freeset	= priv_freeset
356812Sraf #pragma weak _priv_getbyname	= priv_getbyname
366812Sraf #pragma weak _priv_getbynum	= priv_getbynum
376812Sraf #pragma weak _priv_getsetbyname	= priv_getsetbyname
386812Sraf #pragma weak _priv_getsetbynum	= priv_getsetbynum
396812Sraf #pragma weak _priv_ineffect	= priv_ineffect
406812Sraf #pragma weak _priv_intersect	= priv_intersect
416812Sraf #pragma weak _priv_inverse	= priv_inverse
426812Sraf #pragma weak _priv_isemptyset	= priv_isemptyset
436812Sraf #pragma weak _priv_isequalset	= priv_isequalset
446812Sraf #pragma weak _priv_isfullset	= priv_isfullset
456812Sraf #pragma weak _priv_ismember	= priv_ismember
466812Sraf #pragma weak _priv_issubset	= priv_issubset
476812Sraf #pragma weak _priv_set		= priv_set
486812Sraf #pragma weak _priv_union	= priv_union
490Sstevel@tonic-gate 
506812Sraf #include "lint.h"
510Sstevel@tonic-gate 
520Sstevel@tonic-gate #define	_STRUCTURED_PROC	1
530Sstevel@tonic-gate 
540Sstevel@tonic-gate #include "priv_private.h"
550Sstevel@tonic-gate #include "mtlib.h"
560Sstevel@tonic-gate #include "libc.h"
570Sstevel@tonic-gate #include <errno.h>
580Sstevel@tonic-gate #include <stdarg.h>
590Sstevel@tonic-gate #include <stdlib.h>
600Sstevel@tonic-gate #include <unistd.h>
610Sstevel@tonic-gate #include <strings.h>
620Sstevel@tonic-gate #include <synch.h>
630Sstevel@tonic-gate #include <alloca.h>
643864Sraf #include <atomic.h>
650Sstevel@tonic-gate #include <sys/ucred.h>
660Sstevel@tonic-gate #include <sys/procfs.h>
670Sstevel@tonic-gate #include <sys/param.h>
680Sstevel@tonic-gate #include <sys/corectl.h>
690Sstevel@tonic-gate #include <priv_utils.h>
700Sstevel@tonic-gate #include <zone.h>
710Sstevel@tonic-gate 
720Sstevel@tonic-gate /* Include each string only once - until the compiler/linker are fixed */
730Sstevel@tonic-gate static const char *permitted	= PRIV_PERMITTED;
740Sstevel@tonic-gate static const char *effective	= PRIV_EFFECTIVE;
750Sstevel@tonic-gate static const char *limit	= PRIV_LIMIT;
760Sstevel@tonic-gate static const char *inheritable	= PRIV_INHERITABLE;
770Sstevel@tonic-gate /*
780Sstevel@tonic-gate  * Data independent privilege set operations.
790Sstevel@tonic-gate  *
800Sstevel@tonic-gate  * Only a few functions are provided that do not default to
810Sstevel@tonic-gate  * the system implementation of privileges.  A limited set of
820Sstevel@tonic-gate  * interfaces is provided that accepts a priv_data_t *
830Sstevel@tonic-gate  * argument; this set of interfaces is a private interface between libc
840Sstevel@tonic-gate  * and libproc.  It is delivered in order to interpret privilege sets
850Sstevel@tonic-gate  * in debuggers in a implementation independent way.  As such, we
860Sstevel@tonic-gate  * don't need to provide the bulk of the interfaces, only a few
870Sstevel@tonic-gate  * boolean tests (isfull, isempty) the name<->num mappings and
880Sstevel@tonic-gate  * set pretty print functions.   The boolean tests are only needed for
890Sstevel@tonic-gate  * the latter, so those aren't provided externally.
900Sstevel@tonic-gate  *
910Sstevel@tonic-gate  * Additionally, we provide the function that maps the kernel implementation
920Sstevel@tonic-gate  * structure into a libc private data structure.
930Sstevel@tonic-gate  */
940Sstevel@tonic-gate 
950Sstevel@tonic-gate priv_data_t *privdata;
960Sstevel@tonic-gate 
970Sstevel@tonic-gate static mutex_t pd_lock = DEFAULTMUTEX;
980Sstevel@tonic-gate 
990Sstevel@tonic-gate static int
parseninfo(priv_info_names_t * na,char *** buf,int * cp)1000Sstevel@tonic-gate parseninfo(priv_info_names_t *na, char ***buf, int *cp)
1010Sstevel@tonic-gate {
1020Sstevel@tonic-gate 	char *q;
1030Sstevel@tonic-gate 	int i;
1040Sstevel@tonic-gate 
1050Sstevel@tonic-gate 	*buf = libc_malloc(sizeof (char *) * na->cnt);
1060Sstevel@tonic-gate 
1070Sstevel@tonic-gate 	if (*buf == NULL)
1080Sstevel@tonic-gate 		return (-1);
1090Sstevel@tonic-gate 
1100Sstevel@tonic-gate 	q = na->names;
1110Sstevel@tonic-gate 
1120Sstevel@tonic-gate 	for (i = 0; i < na->cnt; i++) {
1130Sstevel@tonic-gate 		int l = strlen(q);
1140Sstevel@tonic-gate 
1150Sstevel@tonic-gate 		(*buf)[i] = q;
1160Sstevel@tonic-gate 		q += l + 1;
1170Sstevel@tonic-gate 	}
1180Sstevel@tonic-gate 	*cp = na->cnt;
1190Sstevel@tonic-gate 	return (0);
1200Sstevel@tonic-gate }
1210Sstevel@tonic-gate 
1220Sstevel@tonic-gate struct strint {
1230Sstevel@tonic-gate 	char *name;
1240Sstevel@tonic-gate 	int rank;
1250Sstevel@tonic-gate };
1260Sstevel@tonic-gate 
1270Sstevel@tonic-gate static int
strintcmp(const void * a,const void * b)1280Sstevel@tonic-gate strintcmp(const void *a, const void *b)
1290Sstevel@tonic-gate {
1300Sstevel@tonic-gate 	const struct strint *ap = a;
1310Sstevel@tonic-gate 	const struct strint *bp = b;
1320Sstevel@tonic-gate 
1330Sstevel@tonic-gate 	return (strcasecmp(ap->name, bp->name));
1340Sstevel@tonic-gate }
1350Sstevel@tonic-gate 
1360Sstevel@tonic-gate priv_data_t *
__priv_parse_info(priv_impl_info_t * ip)1370Sstevel@tonic-gate __priv_parse_info(priv_impl_info_t *ip)
1380Sstevel@tonic-gate {
1390Sstevel@tonic-gate 	priv_data_t *tmp;
1400Sstevel@tonic-gate 	char *x;
1410Sstevel@tonic-gate 	size_t size = PRIV_IMPL_INFO_SIZE(ip);
1420Sstevel@tonic-gate 	int i;
1430Sstevel@tonic-gate 
1440Sstevel@tonic-gate 	tmp = libc_malloc(sizeof (*tmp));
1450Sstevel@tonic-gate 
1460Sstevel@tonic-gate 	if (tmp == NULL)
1470Sstevel@tonic-gate 		return (NULL);
1480Sstevel@tonic-gate 
1490Sstevel@tonic-gate 	(void) memset(tmp, 0, sizeof (*tmp));
1500Sstevel@tonic-gate 
1510Sstevel@tonic-gate 	tmp->pd_pinfo = ip;
1520Sstevel@tonic-gate 	tmp->pd_setsize = sizeof (priv_chunk_t) * ip->priv_setsize;
1530Sstevel@tonic-gate 	tmp->pd_ucredsize = UCRED_SIZE(ip);
1540Sstevel@tonic-gate 
1550Sstevel@tonic-gate 	x = (char *)ip;
1560Sstevel@tonic-gate 	x += ip->priv_headersize;
1570Sstevel@tonic-gate 
1580Sstevel@tonic-gate 	while (x < ((char *)ip) + size) {
1590Sstevel@tonic-gate 		/* LINTED: alignment */
1600Sstevel@tonic-gate 		priv_info_names_t *na = (priv_info_names_t *)x;
1610Sstevel@tonic-gate 		/* LINTED: alignment */
1620Sstevel@tonic-gate 		priv_info_set_t *st = (priv_info_set_t *)x;
1630Sstevel@tonic-gate 		struct strint *tmparr;
1640Sstevel@tonic-gate 
1650Sstevel@tonic-gate 		switch (na->info.priv_info_type) {
1660Sstevel@tonic-gate 		case PRIV_INFO_SETNAMES:
1670Sstevel@tonic-gate 			if (parseninfo(na, &tmp->pd_setnames, &tmp->pd_nsets))
1680Sstevel@tonic-gate 				goto out;
1690Sstevel@tonic-gate 			break;
1700Sstevel@tonic-gate 		case PRIV_INFO_PRIVNAMES:
1710Sstevel@tonic-gate 			if (parseninfo(na, &tmp->pd_privnames, &tmp->pd_nprivs))
1720Sstevel@tonic-gate 				goto out;
1730Sstevel@tonic-gate 			/*
1740Sstevel@tonic-gate 			 * We compute a sorted index which allows us
1750Sstevel@tonic-gate 			 * to present a sorted list of privileges
1760Sstevel@tonic-gate 			 * without actually having to sort it each time.
1770Sstevel@tonic-gate 			 */
1780Sstevel@tonic-gate 			tmp->pd_setsort = libc_malloc(tmp->pd_nprivs *
1790Sstevel@tonic-gate 			    sizeof (int));
1800Sstevel@tonic-gate 			if (tmp->pd_setsort == NULL)
1810Sstevel@tonic-gate 				goto out;
1820Sstevel@tonic-gate 
1830Sstevel@tonic-gate 			tmparr = libc_malloc(tmp->pd_nprivs *
1840Sstevel@tonic-gate 			    sizeof (struct strint));
1850Sstevel@tonic-gate 
1860Sstevel@tonic-gate 			if (tmparr == NULL)
1870Sstevel@tonic-gate 				goto out;
1880Sstevel@tonic-gate 
1890Sstevel@tonic-gate 			for (i = 0; i < tmp->pd_nprivs; i++) {
1900Sstevel@tonic-gate 				tmparr[i].rank = i;
1910Sstevel@tonic-gate 				tmparr[i].name = tmp->pd_privnames[i];
1920Sstevel@tonic-gate 			}
1930Sstevel@tonic-gate 			qsort(tmparr, tmp->pd_nprivs, sizeof (struct strint),
1946812Sraf 			    strintcmp);
1950Sstevel@tonic-gate 			for (i = 0; i < tmp->pd_nprivs; i++)
1960Sstevel@tonic-gate 				tmp->pd_setsort[i] = tmparr[i].rank;
1970Sstevel@tonic-gate 			libc_free(tmparr);
1980Sstevel@tonic-gate 			break;
1990Sstevel@tonic-gate 		case PRIV_INFO_BASICPRIVS:
2000Sstevel@tonic-gate 			tmp->pd_basicset = (priv_set_t *)&st->set[0];
2010Sstevel@tonic-gate 			break;
2020Sstevel@tonic-gate 		default:
2030Sstevel@tonic-gate 			/* unknown, ignore */
2040Sstevel@tonic-gate 			break;
2050Sstevel@tonic-gate 		}
2060Sstevel@tonic-gate 		x += na->info.priv_info_size;
2070Sstevel@tonic-gate 	}
2080Sstevel@tonic-gate 	return (tmp);
2090Sstevel@tonic-gate out:
2100Sstevel@tonic-gate 	libc_free(tmp->pd_setnames);
2110Sstevel@tonic-gate 	libc_free(tmp->pd_privnames);
2120Sstevel@tonic-gate 	libc_free(tmp->pd_setsort);
2130Sstevel@tonic-gate 	libc_free(tmp);
2140Sstevel@tonic-gate 	return (NULL);
2150Sstevel@tonic-gate }
2160Sstevel@tonic-gate 
2170Sstevel@tonic-gate /*
2180Sstevel@tonic-gate  * Caller must have allocated d->pd_pinfo and should free it,
2190Sstevel@tonic-gate  * if necessary.
2200Sstevel@tonic-gate  */
2210Sstevel@tonic-gate void
__priv_free_info(priv_data_t * d)2220Sstevel@tonic-gate __priv_free_info(priv_data_t *d)
2230Sstevel@tonic-gate {
2240Sstevel@tonic-gate 	libc_free(d->pd_setnames);
2250Sstevel@tonic-gate 	libc_free(d->pd_privnames);
2260Sstevel@tonic-gate 	libc_free(d->pd_setsort);
2270Sstevel@tonic-gate 	libc_free(d);
2280Sstevel@tonic-gate }
2290Sstevel@tonic-gate 
2300Sstevel@tonic-gate /*
2311059Scasper  * Return with the pd_lock held and data loaded or indicate failure.
2320Sstevel@tonic-gate  */
2331059Scasper int
lock_data(void)2340Sstevel@tonic-gate lock_data(void)
2350Sstevel@tonic-gate {
2363864Sraf 	if (__priv_getdata() == NULL)
2371059Scasper 		return (-1);
2381059Scasper 
2390Sstevel@tonic-gate 	lmutex_lock(&pd_lock);
2401059Scasper 	return (0);
2410Sstevel@tonic-gate }
2420Sstevel@tonic-gate 
2430Sstevel@tonic-gate boolean_t
refresh_data(void)2440Sstevel@tonic-gate refresh_data(void)
2450Sstevel@tonic-gate {
2460Sstevel@tonic-gate 	priv_impl_info_t *ip, ii;
2470Sstevel@tonic-gate 	priv_data_t *tmp;
2480Sstevel@tonic-gate 	char *p0, *q0;
2490Sstevel@tonic-gate 	int oldn, newn;
2500Sstevel@tonic-gate 	int i;
2510Sstevel@tonic-gate 
2520Sstevel@tonic-gate 	if (getprivinfo(&ii, sizeof (ii)) != 0 ||
2530Sstevel@tonic-gate 	    ii.priv_max == privdata->pd_nprivs)
2540Sstevel@tonic-gate 		return (B_FALSE);
2550Sstevel@tonic-gate 
2560Sstevel@tonic-gate 	ip = alloca(PRIV_IMPL_INFO_SIZE(&ii));
2570Sstevel@tonic-gate 
2580Sstevel@tonic-gate 	(void) getprivinfo(ip, PRIV_IMPL_INFO_SIZE(&ii));
2590Sstevel@tonic-gate 
2600Sstevel@tonic-gate 	/* Parse the info; then copy the additional bits */
2610Sstevel@tonic-gate 	tmp = __priv_parse_info(ip);
2620Sstevel@tonic-gate 	if (tmp == NULL)
2630Sstevel@tonic-gate 		return (B_FALSE);
2640Sstevel@tonic-gate 
2650Sstevel@tonic-gate 	oldn = privdata->pd_nprivs;
2660Sstevel@tonic-gate 	p0 = privdata->pd_privnames[0];
2670Sstevel@tonic-gate 
2680Sstevel@tonic-gate 	newn = tmp->pd_nprivs;
2690Sstevel@tonic-gate 	q0 = tmp->pd_privnames[0];
2700Sstevel@tonic-gate 
2710Sstevel@tonic-gate 	/* copy the extra information to the old datastructure */
2720Sstevel@tonic-gate 	(void) memcpy((char *)privdata->pd_pinfo + sizeof (priv_impl_info_t),
2736812Sraf 	    (char *)ip + sizeof (priv_impl_info_t),
2746812Sraf 	    PRIV_IMPL_INFO_SIZE(ip) - sizeof (priv_impl_info_t));
2750Sstevel@tonic-gate 
2760Sstevel@tonic-gate 	/* Copy the first oldn pointers */
2770Sstevel@tonic-gate 	(void) memcpy(tmp->pd_privnames, privdata->pd_privnames,
2780Sstevel@tonic-gate 	    oldn * sizeof (char *));
2790Sstevel@tonic-gate 
2800Sstevel@tonic-gate 	/* Adjust the rest */
2810Sstevel@tonic-gate 	for (i = oldn; i < newn; i++)
2820Sstevel@tonic-gate 		tmp->pd_privnames[i] += p0 - q0;
2830Sstevel@tonic-gate 
2840Sstevel@tonic-gate 	/* Install the larger arrays */
2850Sstevel@tonic-gate 	libc_free(privdata->pd_privnames);
2860Sstevel@tonic-gate 	privdata->pd_privnames = tmp->pd_privnames;
2870Sstevel@tonic-gate 	tmp->pd_privnames = NULL;
2880Sstevel@tonic-gate 
2890Sstevel@tonic-gate 	libc_free(privdata->pd_setsort);
2900Sstevel@tonic-gate 	privdata->pd_setsort = tmp->pd_setsort;
2910Sstevel@tonic-gate 	tmp->pd_setsort = NULL;
2920Sstevel@tonic-gate 
2930Sstevel@tonic-gate 	/* Copy the rest of the data */
2940Sstevel@tonic-gate 	*privdata->pd_pinfo = *ip;
2950Sstevel@tonic-gate 
2960Sstevel@tonic-gate 	privdata->pd_nprivs = newn;
2970Sstevel@tonic-gate 
2980Sstevel@tonic-gate 	__priv_free_info(tmp);
2990Sstevel@tonic-gate 	return (B_TRUE);
3000Sstevel@tonic-gate }
3010Sstevel@tonic-gate 
3020Sstevel@tonic-gate void
unlock_data(void)3030Sstevel@tonic-gate unlock_data(void)
3040Sstevel@tonic-gate {
3050Sstevel@tonic-gate 	lmutex_unlock(&pd_lock);
3060Sstevel@tonic-gate }
3070Sstevel@tonic-gate 
3080Sstevel@tonic-gate static priv_set_t *__priv_allocset(priv_data_t *);
3090Sstevel@tonic-gate 
3100Sstevel@tonic-gate priv_data_t *
__priv_getdata(void)3110Sstevel@tonic-gate __priv_getdata(void)
3120Sstevel@tonic-gate {
3130Sstevel@tonic-gate 	if (privdata == NULL) {
3143864Sraf 		lmutex_lock(&pd_lock);
3153864Sraf 		if (privdata == NULL) {
3163864Sraf 			priv_data_t *tmp;
3173864Sraf 			priv_impl_info_t *ip;
3183864Sraf 			size_t size = sizeof (priv_impl_info_t) + 2048;
3193864Sraf 			size_t realsize;
3203864Sraf 			priv_impl_info_t *aip = alloca(size);
3210Sstevel@tonic-gate 
3223864Sraf 			if (getprivinfo(aip, size) != 0)
3233864Sraf 				goto out;
3243864Sraf 
3253864Sraf 			realsize = PRIV_IMPL_INFO_SIZE(aip);
3263864Sraf 
3273864Sraf 			ip = libc_malloc(realsize);
3283864Sraf 
3293864Sraf 			if (ip == NULL)
3303864Sraf 				goto out;
3310Sstevel@tonic-gate 
3323864Sraf 			if (realsize <= size) {
3333864Sraf 				(void) memcpy(ip, aip, realsize);
3343864Sraf 			} else if (getprivinfo(ip, realsize) != 0) {
3353864Sraf 				libc_free(ip);
3363864Sraf 				goto out;
3373864Sraf 			}
3380Sstevel@tonic-gate 
3393864Sraf 			if ((tmp = __priv_parse_info(ip)) == NULL) {
3403864Sraf 				libc_free(ip);
3413864Sraf 				goto out;
3423864Sraf 			}
3430Sstevel@tonic-gate 
3443864Sraf 			/* Allocate the zoneset just once, here */
3453864Sraf 			tmp->pd_zoneset = __priv_allocset(tmp);
3463864Sraf 			if (tmp->pd_zoneset == NULL)
3473864Sraf 				goto clean;
3480Sstevel@tonic-gate 
3493864Sraf 			if (zone_getattr(getzoneid(), ZONE_ATTR_PRIVSET,
3503864Sraf 			    tmp->pd_zoneset, tmp->pd_setsize)
3513864Sraf 			    == tmp->pd_setsize) {
3523864Sraf 				membar_producer();
3533864Sraf 				privdata = tmp;
3543864Sraf 				goto out;
3553864Sraf 			}
3563864Sraf 
3573864Sraf 			priv_freeset(tmp->pd_zoneset);
3583864Sraf clean:
3593864Sraf 			__priv_free_info(tmp);
3600Sstevel@tonic-gate 			libc_free(ip);
3610Sstevel@tonic-gate 		}
3623864Sraf out:
3633864Sraf 		lmutex_unlock(&pd_lock);
3640Sstevel@tonic-gate 	}
3653864Sraf 	membar_consumer();
3660Sstevel@tonic-gate 	return (privdata);
3670Sstevel@tonic-gate }
3680Sstevel@tonic-gate 
3690Sstevel@tonic-gate const priv_impl_info_t *
getprivimplinfo(void)3706812Sraf getprivimplinfo(void)
3710Sstevel@tonic-gate {
3720Sstevel@tonic-gate 	priv_data_t *d;
3730Sstevel@tonic-gate 
3740Sstevel@tonic-gate 	LOADPRIVDATA(d);
3750Sstevel@tonic-gate 
3760Sstevel@tonic-gate 	return (d->pd_pinfo);
3770Sstevel@tonic-gate }
3780Sstevel@tonic-gate 
3790Sstevel@tonic-gate static priv_set_t *
priv_vlist(va_list ap)3800Sstevel@tonic-gate priv_vlist(va_list ap)
3810Sstevel@tonic-gate {
3820Sstevel@tonic-gate 	priv_set_t *pset = priv_allocset();
3830Sstevel@tonic-gate 	const char *priv;
3840Sstevel@tonic-gate 
3850Sstevel@tonic-gate 	if (pset == NULL)
3860Sstevel@tonic-gate 		return (NULL);
3870Sstevel@tonic-gate 
3880Sstevel@tonic-gate 	priv_emptyset(pset);
3890Sstevel@tonic-gate 
3900Sstevel@tonic-gate 	while ((priv = va_arg(ap, const char *)) != NULL) {
3910Sstevel@tonic-gate 		if (priv_addset(pset, priv) < 0) {
3920Sstevel@tonic-gate 			priv_freeset(pset);
3930Sstevel@tonic-gate 			return (NULL);
3940Sstevel@tonic-gate 		}
3950Sstevel@tonic-gate 	}
3960Sstevel@tonic-gate 	return (pset);
3970Sstevel@tonic-gate }
3980Sstevel@tonic-gate 
3990Sstevel@tonic-gate /*
4000Sstevel@tonic-gate  * priv_set(op, set, priv_id1, priv_id2, ..., NULL)
4010Sstevel@tonic-gate  *
4020Sstevel@tonic-gate  * Library routine to enable a user process to set a specific
4030Sstevel@tonic-gate  * privilege set appropriately using a single call.  User is
4040Sstevel@tonic-gate  * required to terminate the list of privileges with NULL.
4050Sstevel@tonic-gate  */
4060Sstevel@tonic-gate int
priv_set(priv_op_t op,priv_ptype_t setname,...)4070Sstevel@tonic-gate priv_set(priv_op_t op, priv_ptype_t setname, ...)
4080Sstevel@tonic-gate {
4090Sstevel@tonic-gate 	va_list ap;
4100Sstevel@tonic-gate 	priv_set_t *pset;
4110Sstevel@tonic-gate 	int ret;
4120Sstevel@tonic-gate 
4130Sstevel@tonic-gate 	va_start(ap, setname);
4140Sstevel@tonic-gate 
4150Sstevel@tonic-gate 	pset = priv_vlist(ap);
4160Sstevel@tonic-gate 
4170Sstevel@tonic-gate 	va_end(ap);
4180Sstevel@tonic-gate 
4190Sstevel@tonic-gate 	if (pset == NULL)
4200Sstevel@tonic-gate 		return (-1);
4210Sstevel@tonic-gate 
4220Sstevel@tonic-gate 	/* All sets */
4230Sstevel@tonic-gate 	if (setname == NULL) {
4240Sstevel@tonic-gate 		priv_data_t *d;
4250Sstevel@tonic-gate 		int set;
4260Sstevel@tonic-gate 
4270Sstevel@tonic-gate 		LOADPRIVDATA(d);
4280Sstevel@tonic-gate 
4290Sstevel@tonic-gate 		for (set = 0; set < d->pd_nsets; set++)
4300Sstevel@tonic-gate 			if ((ret = syscall(SYS_privsys, PRIVSYS_SETPPRIV, op,
4316812Sraf 			    set, (void *)pset, d->pd_setsize)) != 0)
4320Sstevel@tonic-gate 				break;
4330Sstevel@tonic-gate 	} else {
4340Sstevel@tonic-gate 		ret = setppriv(op, setname, pset);
4350Sstevel@tonic-gate 	}
4360Sstevel@tonic-gate 
4370Sstevel@tonic-gate 	priv_freeset(pset);
4380Sstevel@tonic-gate 	return (ret);
4390Sstevel@tonic-gate }
4400Sstevel@tonic-gate 
4410Sstevel@tonic-gate /*
4420Sstevel@tonic-gate  * priv_ineffect(privilege).
4435331Samw  * tests the existence of a privilege against the effective set.
4440Sstevel@tonic-gate  */
4450Sstevel@tonic-gate boolean_t
priv_ineffect(const char * priv)4460Sstevel@tonic-gate priv_ineffect(const char *priv)
4470Sstevel@tonic-gate {
4480Sstevel@tonic-gate 	priv_set_t *curset;
4490Sstevel@tonic-gate 	boolean_t res;
4500Sstevel@tonic-gate 
4510Sstevel@tonic-gate 	curset = priv_allocset();
4520Sstevel@tonic-gate 
4530Sstevel@tonic-gate 	if (curset == NULL)
4540Sstevel@tonic-gate 		return (B_FALSE);
4550Sstevel@tonic-gate 
4560Sstevel@tonic-gate 	if (getppriv(effective, curset) != 0 ||
4570Sstevel@tonic-gate 	    !priv_ismember(curset, priv))
4580Sstevel@tonic-gate 		res = B_FALSE;
4590Sstevel@tonic-gate 	else
4600Sstevel@tonic-gate 		res = B_TRUE;
4610Sstevel@tonic-gate 
4620Sstevel@tonic-gate 	priv_freeset(curset);
4630Sstevel@tonic-gate 
4640Sstevel@tonic-gate 	return (res);
4650Sstevel@tonic-gate }
4660Sstevel@tonic-gate 
4670Sstevel@tonic-gate /*
4680Sstevel@tonic-gate  * The routine __init_daemon_priv() is private to Solaris and is
4690Sstevel@tonic-gate  * used by daemons to limit the privileges they can use and
4700Sstevel@tonic-gate  * to set the uid they run under.
4710Sstevel@tonic-gate  */
4720Sstevel@tonic-gate 
4730Sstevel@tonic-gate static const char root_cp[] = "/core.%f.%t";
4740Sstevel@tonic-gate static const char daemon_cp[] = "/var/tmp/core.%f.%t";
4750Sstevel@tonic-gate 
4760Sstevel@tonic-gate int
__init_daemon_priv(int flags,uid_t uid,gid_t gid,...)4770Sstevel@tonic-gate __init_daemon_priv(int flags, uid_t uid, gid_t gid, ...)
4780Sstevel@tonic-gate {
4790Sstevel@tonic-gate 	priv_set_t *nset;
4800Sstevel@tonic-gate 	priv_set_t *perm = NULL;
4810Sstevel@tonic-gate 	va_list pa;
4820Sstevel@tonic-gate 	priv_data_t *d;
4830Sstevel@tonic-gate 	int ret = -1;
4840Sstevel@tonic-gate 	char buf[1024];
4850Sstevel@tonic-gate 
4860Sstevel@tonic-gate 	LOADPRIVDATA(d);
4870Sstevel@tonic-gate 
4880Sstevel@tonic-gate 	va_start(pa, gid);
4890Sstevel@tonic-gate 
4900Sstevel@tonic-gate 	nset = priv_vlist(pa);
4910Sstevel@tonic-gate 
4920Sstevel@tonic-gate 	va_end(pa);
4930Sstevel@tonic-gate 
4940Sstevel@tonic-gate 	if (nset == NULL)
4950Sstevel@tonic-gate 		return (-1);
4960Sstevel@tonic-gate 
4970Sstevel@tonic-gate 	/* Always add the basic set */
4980Sstevel@tonic-gate 	if (d->pd_basicset != NULL)
4990Sstevel@tonic-gate 		priv_union(d->pd_basicset, nset);
5000Sstevel@tonic-gate 
5010Sstevel@tonic-gate 	/*
5020Sstevel@tonic-gate 	 * This is not a significant failure: it allows us to start programs
5030Sstevel@tonic-gate 	 * with sufficient privileges and with the proper uid.   We don't
5040Sstevel@tonic-gate 	 * care enough about the extra groups in that case.
5050Sstevel@tonic-gate 	 */
5060Sstevel@tonic-gate 	if (flags & PU_RESETGROUPS)
5070Sstevel@tonic-gate 		(void) setgroups(0, NULL);
5080Sstevel@tonic-gate 
5094321Scasper 	if (gid != (gid_t)-1 && setgid(gid) != 0)
5100Sstevel@tonic-gate 		goto end;
5110Sstevel@tonic-gate 
5120Sstevel@tonic-gate 	perm = priv_allocset();
5130Sstevel@tonic-gate 	if (perm == NULL)
5140Sstevel@tonic-gate 		goto end;
5150Sstevel@tonic-gate 
5160Sstevel@tonic-gate 	/* E = P */
5170Sstevel@tonic-gate 	(void) getppriv(permitted, perm);
5180Sstevel@tonic-gate 	(void) setppriv(PRIV_SET, effective, perm);
5190Sstevel@tonic-gate 
5200Sstevel@tonic-gate 	/* Now reset suid and euid */
5214321Scasper 	if (uid != (uid_t)-1 && setreuid(uid, uid) != 0)
5220Sstevel@tonic-gate 		goto end;
5230Sstevel@tonic-gate 
5240Sstevel@tonic-gate 	/* Check for the limit privs */
5250Sstevel@tonic-gate 	if ((flags & PU_LIMITPRIVS) &&
5260Sstevel@tonic-gate 	    setppriv(PRIV_SET, limit, nset) != 0)
5270Sstevel@tonic-gate 		goto end;
5280Sstevel@tonic-gate 
5290Sstevel@tonic-gate 	if (flags & PU_CLEARLIMITSET) {
5300Sstevel@tonic-gate 		priv_emptyset(perm);
5310Sstevel@tonic-gate 		if (setppriv(PRIV_SET, limit, perm) != 0)
5320Sstevel@tonic-gate 			goto end;
5330Sstevel@tonic-gate 	}
5340Sstevel@tonic-gate 
5350Sstevel@tonic-gate 	/* Remove the privileges from all the other sets */
5360Sstevel@tonic-gate 	if (setppriv(PRIV_SET, permitted, nset) != 0)
5370Sstevel@tonic-gate 		goto end;
5380Sstevel@tonic-gate 
5390Sstevel@tonic-gate 	if (!(flags & PU_INHERITPRIVS))
5400Sstevel@tonic-gate 		priv_emptyset(nset);
5410Sstevel@tonic-gate 
5420Sstevel@tonic-gate 	ret = setppriv(PRIV_SET, inheritable, nset);
5430Sstevel@tonic-gate end:
5440Sstevel@tonic-gate 	priv_freeset(nset);
5450Sstevel@tonic-gate 	priv_freeset(perm);
5460Sstevel@tonic-gate 
5470Sstevel@tonic-gate 	if (core_get_process_path(buf, sizeof (buf), getpid()) == 0 &&
5480Sstevel@tonic-gate 	    strcmp(buf, "core") == 0) {
5490Sstevel@tonic-gate 
5504321Scasper 		if ((uid == (uid_t)-1 ? geteuid() : uid) == 0) {
5510Sstevel@tonic-gate 			(void) core_set_process_path(root_cp, sizeof (root_cp),
5520Sstevel@tonic-gate 			    getpid());
5530Sstevel@tonic-gate 		} else {
5540Sstevel@tonic-gate 			(void) core_set_process_path(daemon_cp,
5550Sstevel@tonic-gate 			    sizeof (daemon_cp), getpid());
5560Sstevel@tonic-gate 		}
5570Sstevel@tonic-gate 	}
5580Sstevel@tonic-gate 	(void) setpflags(__PROC_PROTECT, 0);
5590Sstevel@tonic-gate 
5600Sstevel@tonic-gate 	return (ret);
5610Sstevel@tonic-gate }
5620Sstevel@tonic-gate 
5630Sstevel@tonic-gate /*
5640Sstevel@tonic-gate  * The routine __fini_daemon_priv() is private to Solaris and is
5650Sstevel@tonic-gate  * used by daemons to clear remaining unwanted privileges and
5660Sstevel@tonic-gate  * reenable core dumps.
5670Sstevel@tonic-gate  */
5680Sstevel@tonic-gate void
__fini_daemon_priv(const char * priv,...)5690Sstevel@tonic-gate __fini_daemon_priv(const char *priv, ...)
5700Sstevel@tonic-gate {
5710Sstevel@tonic-gate 	priv_set_t *nset;
5720Sstevel@tonic-gate 	va_list pa;
5730Sstevel@tonic-gate 
5740Sstevel@tonic-gate 	va_start(pa, priv);
5750Sstevel@tonic-gate 
5760Sstevel@tonic-gate 	if (priv != NULL) {
5770Sstevel@tonic-gate 		nset = priv_vlist(pa);
5780Sstevel@tonic-gate 		if (nset == NULL)
5790Sstevel@tonic-gate 			return;
5800Sstevel@tonic-gate 
5810Sstevel@tonic-gate 		(void) priv_addset(nset, priv);
5820Sstevel@tonic-gate 		(void) setppriv(PRIV_OFF, permitted, nset);
5830Sstevel@tonic-gate 		priv_freeset(nset);
5840Sstevel@tonic-gate 	}
5850Sstevel@tonic-gate 
5860Sstevel@tonic-gate 	va_end(pa);
5870Sstevel@tonic-gate 
5880Sstevel@tonic-gate 	(void) setpflags(__PROC_PROTECT, 0);
5890Sstevel@tonic-gate }
5900Sstevel@tonic-gate 
5910Sstevel@tonic-gate /*
5920Sstevel@tonic-gate  * The routine __init_suid_priv() is private to Solaris and is
5930Sstevel@tonic-gate  * used by set-uid root programs to limit the privileges acquired
5940Sstevel@tonic-gate  * to those actually needed.
5950Sstevel@tonic-gate  */
5960Sstevel@tonic-gate 
5970Sstevel@tonic-gate static priv_set_t *bracketpriv;
5980Sstevel@tonic-gate 
5990Sstevel@tonic-gate int
__init_suid_priv(int flags,...)6000Sstevel@tonic-gate __init_suid_priv(int flags, ...)
6010Sstevel@tonic-gate {
6020Sstevel@tonic-gate 	priv_set_t *nset = NULL;
6030Sstevel@tonic-gate 	priv_set_t *tmpset = NULL;
6040Sstevel@tonic-gate 	va_list pa;
6050Sstevel@tonic-gate 	int r = -1;
6060Sstevel@tonic-gate 	uid_t ruid, euid;
6070Sstevel@tonic-gate 
6080Sstevel@tonic-gate 	euid = geteuid();
6090Sstevel@tonic-gate 
6100Sstevel@tonic-gate 	/* If we're not set-uid root, don't reset the uid */
6110Sstevel@tonic-gate 	if (euid == 0) {
6120Sstevel@tonic-gate 		ruid = getuid();
6130Sstevel@tonic-gate 		/* If we're running as root, keep everything */
6140Sstevel@tonic-gate 		if (ruid == 0)
6150Sstevel@tonic-gate 			return (0);
6160Sstevel@tonic-gate 	}
6170Sstevel@tonic-gate 
6180Sstevel@tonic-gate 	/* Can call this only once */
6190Sstevel@tonic-gate 	if (bracketpriv != NULL)
6200Sstevel@tonic-gate 		return (-1);
6210Sstevel@tonic-gate 
6220Sstevel@tonic-gate 	va_start(pa, flags);
6230Sstevel@tonic-gate 
6240Sstevel@tonic-gate 	nset = priv_vlist(pa);
6250Sstevel@tonic-gate 
6260Sstevel@tonic-gate 	va_end(pa);
6270Sstevel@tonic-gate 
6280Sstevel@tonic-gate 	if (nset == NULL)
6290Sstevel@tonic-gate 		goto end;
6300Sstevel@tonic-gate 
6310Sstevel@tonic-gate 	tmpset = priv_allocset();
6320Sstevel@tonic-gate 
6330Sstevel@tonic-gate 	if (tmpset == NULL)
6340Sstevel@tonic-gate 		goto end;
6350Sstevel@tonic-gate 
6360Sstevel@tonic-gate 	/* We cannot grow our privileges beyond P, so start there */
6370Sstevel@tonic-gate 	(void) getppriv(permitted, tmpset);
6380Sstevel@tonic-gate 
6390Sstevel@tonic-gate 	/* Is the privilege we need even in P? */
6400Sstevel@tonic-gate 	if (!priv_issubset(nset, tmpset))
6410Sstevel@tonic-gate 		goto end;
6420Sstevel@tonic-gate 
6430Sstevel@tonic-gate 	bracketpriv = priv_allocset();
6440Sstevel@tonic-gate 	if (bracketpriv == NULL)
6450Sstevel@tonic-gate 		goto end;
6460Sstevel@tonic-gate 
6470Sstevel@tonic-gate 	priv_copyset(nset, bracketpriv);
6480Sstevel@tonic-gate 
6490Sstevel@tonic-gate 	/* Always add the basic set */
6500Sstevel@tonic-gate 	priv_union(priv_basic(), nset);
6510Sstevel@tonic-gate 
6520Sstevel@tonic-gate 	/* But don't add what we don't have */
6530Sstevel@tonic-gate 	priv_intersect(tmpset, nset);
6540Sstevel@tonic-gate 
6550Sstevel@tonic-gate 	(void) getppriv(inheritable, tmpset);
6560Sstevel@tonic-gate 
6570Sstevel@tonic-gate 	/* And stir in the inheritable privileges */
6580Sstevel@tonic-gate 	priv_union(tmpset, nset);
6590Sstevel@tonic-gate 
6600Sstevel@tonic-gate 	if ((r = setppriv(PRIV_SET, effective, tmpset)) != 0)
6610Sstevel@tonic-gate 		goto end;
6620Sstevel@tonic-gate 
6630Sstevel@tonic-gate 	if ((r = setppriv(PRIV_SET, permitted, nset)) != 0)
6640Sstevel@tonic-gate 		goto end;
6650Sstevel@tonic-gate 
6660Sstevel@tonic-gate 	if (flags & PU_CLEARLIMITSET)
6670Sstevel@tonic-gate 		priv_emptyset(nset);
6680Sstevel@tonic-gate 
6690Sstevel@tonic-gate 	if ((flags & (PU_LIMITPRIVS|PU_CLEARLIMITSET)) != 0 &&
6700Sstevel@tonic-gate 	    (r = setppriv(PRIV_SET, limit, nset)) != 0)
6710Sstevel@tonic-gate 		goto end;
6720Sstevel@tonic-gate 
6730Sstevel@tonic-gate 	if (euid == 0)
6740Sstevel@tonic-gate 		r = setreuid(ruid, ruid);
6750Sstevel@tonic-gate 
6760Sstevel@tonic-gate end:
6770Sstevel@tonic-gate 	priv_freeset(tmpset);
6780Sstevel@tonic-gate 	priv_freeset(nset);
6790Sstevel@tonic-gate 	if (r != 0) {
6800Sstevel@tonic-gate 		/* Fail without leaving uid 0 around */
6810Sstevel@tonic-gate 		if (euid == 0)
6820Sstevel@tonic-gate 			(void) setreuid(ruid, ruid);
6830Sstevel@tonic-gate 		priv_freeset(bracketpriv);
6840Sstevel@tonic-gate 		bracketpriv = NULL;
6850Sstevel@tonic-gate 	}
6860Sstevel@tonic-gate 
6870Sstevel@tonic-gate 	return (r);
6880Sstevel@tonic-gate }
6890Sstevel@tonic-gate 
6900Sstevel@tonic-gate /*
6910Sstevel@tonic-gate  * Toggle privileges on/off in the effective set.
6920Sstevel@tonic-gate  */
6930Sstevel@tonic-gate int
__priv_bracket(priv_op_t op)6940Sstevel@tonic-gate __priv_bracket(priv_op_t op)
6950Sstevel@tonic-gate {
6960Sstevel@tonic-gate 	/* We're running fully privileged or didn't check errors first time */
6970Sstevel@tonic-gate 	if (bracketpriv == NULL)
6980Sstevel@tonic-gate 		return (0);
6990Sstevel@tonic-gate 
7000Sstevel@tonic-gate 	/* Only PRIV_ON and PRIV_OFF are valid */
7010Sstevel@tonic-gate 	if (op == PRIV_SET)
7020Sstevel@tonic-gate 		return (-1);
7030Sstevel@tonic-gate 
7040Sstevel@tonic-gate 	return (setppriv(op, effective, bracketpriv));
7050Sstevel@tonic-gate }
7060Sstevel@tonic-gate 
7070Sstevel@tonic-gate /*
7080Sstevel@tonic-gate  * Remove privileges from E & P.
7090Sstevel@tonic-gate  */
7100Sstevel@tonic-gate void
__priv_relinquish(void)7110Sstevel@tonic-gate __priv_relinquish(void)
7120Sstevel@tonic-gate {
7130Sstevel@tonic-gate 	if (bracketpriv != NULL) {
7140Sstevel@tonic-gate 		(void) setppriv(PRIV_OFF, permitted, bracketpriv);
7150Sstevel@tonic-gate 		priv_freeset(bracketpriv);
7160Sstevel@tonic-gate 		bracketpriv = NULL;
7170Sstevel@tonic-gate 	}
7180Sstevel@tonic-gate }
7190Sstevel@tonic-gate 
7200Sstevel@tonic-gate /*
7210Sstevel@tonic-gate  * Use binary search on the ordered list.
7220Sstevel@tonic-gate  */
7230Sstevel@tonic-gate int
__priv_getbyname(const priv_data_t * d,const char * name)7240Sstevel@tonic-gate __priv_getbyname(const priv_data_t *d, const char *name)
7250Sstevel@tonic-gate {
7261059Scasper 	char *const *list;
7271059Scasper 	const int *order;
7280Sstevel@tonic-gate 	int lo = 0;
7291059Scasper 	int hi;
7301059Scasper 
7311059Scasper 	if (d == NULL)
7321059Scasper 		return (-1);
7331059Scasper 
7341059Scasper 	list = d->pd_privnames;
7351059Scasper 	order = d->pd_setsort;
7361059Scasper 	hi = d->pd_nprivs - 1;
7370Sstevel@tonic-gate 
7380Sstevel@tonic-gate 	if (strncasecmp(name, "priv_", 5) == 0)
7390Sstevel@tonic-gate 		name += 5;
7400Sstevel@tonic-gate 
7410Sstevel@tonic-gate 	do {
7420Sstevel@tonic-gate 		int mid = (lo + hi) / 2;
7430Sstevel@tonic-gate 		int res = strcasecmp(name, list[order[mid]]);
7440Sstevel@tonic-gate 
7450Sstevel@tonic-gate 		if (res == 0)
7460Sstevel@tonic-gate 			return (order[mid]);
7470Sstevel@tonic-gate 		else if (res < 0)
7480Sstevel@tonic-gate 			hi = mid - 1;
7490Sstevel@tonic-gate 		else
7500Sstevel@tonic-gate 			lo = mid + 1;
7510Sstevel@tonic-gate 	} while (lo <= hi);
7520Sstevel@tonic-gate 
7530Sstevel@tonic-gate 	errno = EINVAL;
7540Sstevel@tonic-gate 	return (-1);
7550Sstevel@tonic-gate }
7560Sstevel@tonic-gate 
7570Sstevel@tonic-gate int
priv_getbyname(const char * name)7580Sstevel@tonic-gate priv_getbyname(const char *name)
7590Sstevel@tonic-gate {
7600Sstevel@tonic-gate 	WITHPRIVLOCKED(int, -1, __priv_getbyname(GETPRIVDATA(), name));
7610Sstevel@tonic-gate }
7620Sstevel@tonic-gate 
7630Sstevel@tonic-gate int
__priv_getsetbyname(const priv_data_t * d,const char * name)7640Sstevel@tonic-gate __priv_getsetbyname(const priv_data_t *d, const char *name)
7650Sstevel@tonic-gate {
7660Sstevel@tonic-gate 	int i;
7670Sstevel@tonic-gate 	int n = d->pd_nsets;
7680Sstevel@tonic-gate 	char *const *list = d->pd_setnames;
7690Sstevel@tonic-gate 
7700Sstevel@tonic-gate 	if (strncasecmp(name, "priv_", 5) == 0)
7710Sstevel@tonic-gate 		name += 5;
7720Sstevel@tonic-gate 
7730Sstevel@tonic-gate 	for (i = 0; i < n; i++) {
7740Sstevel@tonic-gate 		if (strcasecmp(list[i], name) == 0)
7750Sstevel@tonic-gate 			return (i);
7760Sstevel@tonic-gate 	}
7770Sstevel@tonic-gate 
7780Sstevel@tonic-gate 	errno = EINVAL;
7790Sstevel@tonic-gate 	return (-1);
7800Sstevel@tonic-gate }
7810Sstevel@tonic-gate 
7820Sstevel@tonic-gate int
priv_getsetbyname(const char * name)7830Sstevel@tonic-gate priv_getsetbyname(const char *name)
7840Sstevel@tonic-gate {
7850Sstevel@tonic-gate 	/* Not locked: sets don't change */
7860Sstevel@tonic-gate 	return (__priv_getsetbyname(GETPRIVDATA(), name));
7870Sstevel@tonic-gate }
7880Sstevel@tonic-gate 
7890Sstevel@tonic-gate static const char *
priv_bynum(int i,int n,char ** list)7900Sstevel@tonic-gate priv_bynum(int i, int n, char **list)
7910Sstevel@tonic-gate {
7920Sstevel@tonic-gate 	if (i < 0 || i >= n)
7930Sstevel@tonic-gate 		return (NULL);
7940Sstevel@tonic-gate 
7950Sstevel@tonic-gate 	return (list[i]);
7960Sstevel@tonic-gate }
7970Sstevel@tonic-gate 
7980Sstevel@tonic-gate const char *
__priv_getbynum(const priv_data_t * d,int num)7990Sstevel@tonic-gate __priv_getbynum(const priv_data_t *d, int num)
8000Sstevel@tonic-gate {
8011059Scasper 	if (d == NULL)
8021059Scasper 		return (NULL);
8030Sstevel@tonic-gate 	return (priv_bynum(num, d->pd_nprivs, d->pd_privnames));
8040Sstevel@tonic-gate }
8050Sstevel@tonic-gate 
8060Sstevel@tonic-gate const char *
priv_getbynum(int num)8070Sstevel@tonic-gate priv_getbynum(int num)
8080Sstevel@tonic-gate {
8090Sstevel@tonic-gate 	WITHPRIVLOCKED(const char *, NULL, __priv_getbynum(GETPRIVDATA(), num));
8100Sstevel@tonic-gate }
8110Sstevel@tonic-gate 
8120Sstevel@tonic-gate const char *
__priv_getsetbynum(const priv_data_t * d,int num)8130Sstevel@tonic-gate __priv_getsetbynum(const priv_data_t *d, int num)
8140Sstevel@tonic-gate {
8151059Scasper 	if (d == NULL)
8161059Scasper 		return (NULL);
8170Sstevel@tonic-gate 	return (priv_bynum(num, d->pd_nsets, d->pd_setnames));
8180Sstevel@tonic-gate }
8190Sstevel@tonic-gate 
8200Sstevel@tonic-gate const char *
priv_getsetbynum(int num)8210Sstevel@tonic-gate priv_getsetbynum(int num)
8220Sstevel@tonic-gate {
8230Sstevel@tonic-gate 	return (__priv_getsetbynum(GETPRIVDATA(), num));
8240Sstevel@tonic-gate }
8250Sstevel@tonic-gate 
8260Sstevel@tonic-gate 
8270Sstevel@tonic-gate /*
8280Sstevel@tonic-gate  * Privilege manipulation functions
8290Sstevel@tonic-gate  *
8300Sstevel@tonic-gate  * Without knowing the details of the privilege set implementation,
8310Sstevel@tonic-gate  * opaque pointers can be used to manipulate sets at will.
8320Sstevel@tonic-gate  */
8330Sstevel@tonic-gate 
8340Sstevel@tonic-gate static priv_set_t *
__priv_allocset(priv_data_t * d)8350Sstevel@tonic-gate __priv_allocset(priv_data_t *d)
8360Sstevel@tonic-gate {
8371059Scasper 	if (d == NULL)
8381059Scasper 		return (NULL);
8391059Scasper 
8400Sstevel@tonic-gate 	return (libc_malloc(d->pd_setsize));
8410Sstevel@tonic-gate }
8420Sstevel@tonic-gate 
8430Sstevel@tonic-gate priv_set_t *
priv_allocset(void)8440Sstevel@tonic-gate priv_allocset(void)
8450Sstevel@tonic-gate {
8460Sstevel@tonic-gate 	return (__priv_allocset(GETPRIVDATA()));
8470Sstevel@tonic-gate }
8480Sstevel@tonic-gate 
8490Sstevel@tonic-gate void
priv_freeset(priv_set_t * p)8500Sstevel@tonic-gate priv_freeset(priv_set_t *p)
8510Sstevel@tonic-gate {
8520Sstevel@tonic-gate 	int er = errno;
8530Sstevel@tonic-gate 
8540Sstevel@tonic-gate 	libc_free(p);
8550Sstevel@tonic-gate 	errno = er;
8560Sstevel@tonic-gate }
8570Sstevel@tonic-gate 
8580Sstevel@tonic-gate void
__priv_emptyset(priv_data_t * d,priv_set_t * set)8590Sstevel@tonic-gate __priv_emptyset(priv_data_t *d, priv_set_t *set)
8600Sstevel@tonic-gate {
8610Sstevel@tonic-gate 	(void) memset(set, 0, d->pd_setsize);
8620Sstevel@tonic-gate }
8630Sstevel@tonic-gate 
8640Sstevel@tonic-gate void
priv_emptyset(priv_set_t * set)8650Sstevel@tonic-gate priv_emptyset(priv_set_t *set)
8660Sstevel@tonic-gate {
8670Sstevel@tonic-gate 	__priv_emptyset(GETPRIVDATA(), set);
8680Sstevel@tonic-gate }
8690Sstevel@tonic-gate 
8700Sstevel@tonic-gate void
priv_basicset(priv_set_t * set)87111537SCasper.Dik@Sun.COM priv_basicset(priv_set_t *set)
87211537SCasper.Dik@Sun.COM {
873*12273SCasper.Dik@Sun.COM 	priv_copyset(priv_basic(), set);
87411537SCasper.Dik@Sun.COM }
87511537SCasper.Dik@Sun.COM 
87611537SCasper.Dik@Sun.COM void
__priv_fillset(priv_data_t * d,priv_set_t * set)8770Sstevel@tonic-gate __priv_fillset(priv_data_t *d, priv_set_t *set)
8780Sstevel@tonic-gate {
8790Sstevel@tonic-gate 	(void) memset(set, ~0, d->pd_setsize);
8800Sstevel@tonic-gate }
8810Sstevel@tonic-gate 
8820Sstevel@tonic-gate void
priv_fillset(priv_set_t * set)8830Sstevel@tonic-gate priv_fillset(priv_set_t *set)
8840Sstevel@tonic-gate {
8850Sstevel@tonic-gate 	__priv_fillset(GETPRIVDATA(), set);
8860Sstevel@tonic-gate }
8870Sstevel@tonic-gate 
8880Sstevel@tonic-gate 
8890Sstevel@tonic-gate #define	PRIV_TEST_BODY_D(d, test) \
8900Sstevel@tonic-gate 	int i; \
8910Sstevel@tonic-gate \
8920Sstevel@tonic-gate 	for (i = d->pd_pinfo->priv_setsize; i-- > 0; ) \
8930Sstevel@tonic-gate 		if (!(test)) \
8940Sstevel@tonic-gate 			return (B_FALSE); \
8950Sstevel@tonic-gate \
8960Sstevel@tonic-gate 	return (B_TRUE)
8970Sstevel@tonic-gate 
8980Sstevel@tonic-gate boolean_t
priv_isequalset(const priv_set_t * a,const priv_set_t * b)8990Sstevel@tonic-gate priv_isequalset(const priv_set_t *a, const priv_set_t *b)
9000Sstevel@tonic-gate {
9010Sstevel@tonic-gate 	priv_data_t *d;
9020Sstevel@tonic-gate 
9030Sstevel@tonic-gate 	LOADPRIVDATA(d);
9040Sstevel@tonic-gate 
9050Sstevel@tonic-gate 	return ((boolean_t)(memcmp(a, b, d->pd_setsize) == 0));
9060Sstevel@tonic-gate }
9070Sstevel@tonic-gate 
9080Sstevel@tonic-gate boolean_t
__priv_isemptyset(priv_data_t * d,const priv_set_t * set)9090Sstevel@tonic-gate __priv_isemptyset(priv_data_t *d, const priv_set_t *set)
9100Sstevel@tonic-gate {
9110Sstevel@tonic-gate 	PRIV_TEST_BODY_D(d, ((priv_chunk_t *)set)[i] == 0);
9120Sstevel@tonic-gate }
9130Sstevel@tonic-gate 
9140Sstevel@tonic-gate boolean_t
priv_isemptyset(const priv_set_t * set)9150Sstevel@tonic-gate priv_isemptyset(const priv_set_t *set)
9160Sstevel@tonic-gate {
9170Sstevel@tonic-gate 	return (__priv_isemptyset(GETPRIVDATA(), set));
9180Sstevel@tonic-gate }
9190Sstevel@tonic-gate 
9200Sstevel@tonic-gate boolean_t
__priv_isfullset(priv_data_t * d,const priv_set_t * set)9210Sstevel@tonic-gate __priv_isfullset(priv_data_t *d, const priv_set_t *set)
9220Sstevel@tonic-gate {
9230Sstevel@tonic-gate 	PRIV_TEST_BODY_D(d, ((priv_chunk_t *)set)[i] == ~(priv_chunk_t)0);
9240Sstevel@tonic-gate }
9250Sstevel@tonic-gate 
9260Sstevel@tonic-gate boolean_t
priv_isfullset(const priv_set_t * set)9270Sstevel@tonic-gate priv_isfullset(const priv_set_t *set)
9280Sstevel@tonic-gate {
9290Sstevel@tonic-gate 	return (__priv_isfullset(GETPRIVDATA(), set));
9300Sstevel@tonic-gate }
9310Sstevel@tonic-gate 
9320Sstevel@tonic-gate /*
9330Sstevel@tonic-gate  * Return true if a is a subset of b
9340Sstevel@tonic-gate  */
9350Sstevel@tonic-gate boolean_t
__priv_issubset(priv_data_t * d,const priv_set_t * a,const priv_set_t * b)9360Sstevel@tonic-gate __priv_issubset(priv_data_t *d, const priv_set_t *a, const priv_set_t *b)
9370Sstevel@tonic-gate {
9380Sstevel@tonic-gate 	PRIV_TEST_BODY_D(d, (((priv_chunk_t *)a)[i] | ((priv_chunk_t *)b)[i]) ==
9396812Sraf 	    ((priv_chunk_t *)b)[i]);
9400Sstevel@tonic-gate }
9410Sstevel@tonic-gate 
9420Sstevel@tonic-gate boolean_t
priv_issubset(const priv_set_t * a,const priv_set_t * b)9430Sstevel@tonic-gate priv_issubset(const priv_set_t *a, const priv_set_t *b)
9440Sstevel@tonic-gate {
9450Sstevel@tonic-gate 	return (__priv_issubset(GETPRIVDATA(), a, b));
9460Sstevel@tonic-gate }
9470Sstevel@tonic-gate 
9480Sstevel@tonic-gate #define	PRIV_CHANGE_BODY(a, op, b) \
9490Sstevel@tonic-gate 	int i; \
9500Sstevel@tonic-gate 	priv_data_t *d; \
9510Sstevel@tonic-gate \
9520Sstevel@tonic-gate 	LOADPRIVDATA(d); \
9530Sstevel@tonic-gate \
9540Sstevel@tonic-gate 	for (i = 0; i < d->pd_pinfo->priv_setsize; i++) \
9550Sstevel@tonic-gate 		((priv_chunk_t *)a)[i] op \
9560Sstevel@tonic-gate 			((priv_chunk_t *)b)[i]
9570Sstevel@tonic-gate 
9580Sstevel@tonic-gate /* B = A ^ B */
9590Sstevel@tonic-gate void
priv_intersect(const priv_set_t * a,priv_set_t * b)9600Sstevel@tonic-gate priv_intersect(const priv_set_t *a, priv_set_t *b)
9610Sstevel@tonic-gate {
9620Sstevel@tonic-gate 	/* CSTYLED */
9630Sstevel@tonic-gate 	PRIV_CHANGE_BODY(b, &=, a);
9640Sstevel@tonic-gate }
9650Sstevel@tonic-gate 
9660Sstevel@tonic-gate /* B = A */
9670Sstevel@tonic-gate void
priv_copyset(const priv_set_t * a,priv_set_t * b)9680Sstevel@tonic-gate priv_copyset(const priv_set_t *a, priv_set_t *b)
9690Sstevel@tonic-gate {
9700Sstevel@tonic-gate 	/* CSTYLED */
9710Sstevel@tonic-gate 	PRIV_CHANGE_BODY(b, =, a);
9720Sstevel@tonic-gate }
9730Sstevel@tonic-gate 
9740Sstevel@tonic-gate /* B = A v B */
9750Sstevel@tonic-gate void
priv_union(const priv_set_t * a,priv_set_t * b)9760Sstevel@tonic-gate priv_union(const priv_set_t *a, priv_set_t *b)
9770Sstevel@tonic-gate {
9780Sstevel@tonic-gate 	/* CSTYLED */
9790Sstevel@tonic-gate 	PRIV_CHANGE_BODY(b, |=, a);
9800Sstevel@tonic-gate }
9810Sstevel@tonic-gate 
9820Sstevel@tonic-gate /* A = ! A */
9830Sstevel@tonic-gate void
priv_inverse(priv_set_t * a)9840Sstevel@tonic-gate priv_inverse(priv_set_t *a)
9850Sstevel@tonic-gate {
9860Sstevel@tonic-gate 	PRIV_CHANGE_BODY(a, = ~, a);
9870Sstevel@tonic-gate }
9880Sstevel@tonic-gate 
9890Sstevel@tonic-gate /*
9900Sstevel@tonic-gate  * Manipulating single privileges.
9910Sstevel@tonic-gate  */
9920Sstevel@tonic-gate 
9930Sstevel@tonic-gate int
priv_addset(priv_set_t * a,const char * p)9940Sstevel@tonic-gate priv_addset(priv_set_t *a, const char *p)
9950Sstevel@tonic-gate {
9960Sstevel@tonic-gate 	int priv = priv_getbyname(p);
9970Sstevel@tonic-gate 
9980Sstevel@tonic-gate 	if (priv < 0)
9990Sstevel@tonic-gate 		return (-1);
10000Sstevel@tonic-gate 
10010Sstevel@tonic-gate 	PRIV_ADDSET(a, priv);
10020Sstevel@tonic-gate 
10030Sstevel@tonic-gate 	return (0);
10040Sstevel@tonic-gate }
10050Sstevel@tonic-gate 
10060Sstevel@tonic-gate int
priv_delset(priv_set_t * a,const char * p)10070Sstevel@tonic-gate priv_delset(priv_set_t *a, const char *p)
10080Sstevel@tonic-gate {
10090Sstevel@tonic-gate 	int priv = priv_getbyname(p);
10100Sstevel@tonic-gate 
10110Sstevel@tonic-gate 	if (priv < 0)
10120Sstevel@tonic-gate 		return (-1);
10130Sstevel@tonic-gate 
10140Sstevel@tonic-gate 	PRIV_DELSET(a, priv);
10150Sstevel@tonic-gate 	return (0);
10160Sstevel@tonic-gate }
10170Sstevel@tonic-gate 
10180Sstevel@tonic-gate boolean_t
priv_ismember(const priv_set_t * a,const char * p)10190Sstevel@tonic-gate priv_ismember(const priv_set_t *a, const char *p)
10200Sstevel@tonic-gate {
10210Sstevel@tonic-gate 	int priv = priv_getbyname(p);
10220Sstevel@tonic-gate 
10230Sstevel@tonic-gate 	if (priv < 0)
10240Sstevel@tonic-gate 		return (B_FALSE);
10250Sstevel@tonic-gate 
10260Sstevel@tonic-gate 	return ((boolean_t)PRIV_ISMEMBER(a, priv));
10270Sstevel@tonic-gate }
1028