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
51544Seschrock * Common Development and Distribution License (the "License").
61544Seschrock * 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 */
210Sstevel@tonic-gate /*
2212273SCasper.Dik@Sun.COM * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
230Sstevel@tonic-gate */
240Sstevel@tonic-gate
250Sstevel@tonic-gate #include <sys/types.h>
260Sstevel@tonic-gate #include <sys/sysmacros.h>
270Sstevel@tonic-gate #include <sys/param.h>
280Sstevel@tonic-gate #include <sys/systm.h>
290Sstevel@tonic-gate #include <sys/cred_impl.h>
300Sstevel@tonic-gate #include <sys/vnode.h>
310Sstevel@tonic-gate #include <sys/vfs.h>
320Sstevel@tonic-gate #include <sys/stat.h>
330Sstevel@tonic-gate #include <sys/errno.h>
340Sstevel@tonic-gate #include <sys/kmem.h>
350Sstevel@tonic-gate #include <sys/user.h>
360Sstevel@tonic-gate #include <sys/proc.h>
370Sstevel@tonic-gate #include <sys/acct.h>
380Sstevel@tonic-gate #include <sys/ipc_impl.h>
390Sstevel@tonic-gate #include <sys/cmn_err.h>
400Sstevel@tonic-gate #include <sys/debug.h>
410Sstevel@tonic-gate #include <sys/policy.h>
420Sstevel@tonic-gate #include <sys/kobj.h>
430Sstevel@tonic-gate #include <sys/msg.h>
440Sstevel@tonic-gate #include <sys/devpolicy.h>
450Sstevel@tonic-gate #include <c2/audit.h>
460Sstevel@tonic-gate #include <sys/varargs.h>
476134Scasper #include <sys/klpd.h>
480Sstevel@tonic-gate #include <sys/modctl.h>
490Sstevel@tonic-gate #include <sys/disp.h>
500Sstevel@tonic-gate #include <sys/zone.h>
510Sstevel@tonic-gate #include <inet/optcom.h>
520Sstevel@tonic-gate #include <sys/sdt.h>
530Sstevel@tonic-gate #include <sys/vfs.h>
540Sstevel@tonic-gate #include <sys/mntent.h>
550Sstevel@tonic-gate #include <sys/contract_impl.h>
568275SEric Cheng #include <sys/dld_ioc.h>
570Sstevel@tonic-gate
580Sstevel@tonic-gate /*
590Sstevel@tonic-gate * There are two possible layers of privilege routines and two possible
600Sstevel@tonic-gate * levels of secpolicy. Plus one other we may not be interested in, so
610Sstevel@tonic-gate * we may need as many as 6 but no more.
620Sstevel@tonic-gate */
630Sstevel@tonic-gate #define MAXPRIVSTACK 6
640Sstevel@tonic-gate
650Sstevel@tonic-gate int priv_debug = 0;
6611537SCasper.Dik@Sun.COM int priv_basic_test = -1;
670Sstevel@tonic-gate
680Sstevel@tonic-gate /*
690Sstevel@tonic-gate * This file contains the majority of the policy routines.
700Sstevel@tonic-gate * Since the policy routines are defined by function and not
710Sstevel@tonic-gate * by privilege, there is quite a bit of duplication of
720Sstevel@tonic-gate * functions.
730Sstevel@tonic-gate *
745331Samw * The secpolicy functions must not make assumptions about
750Sstevel@tonic-gate * locks held or not held as any lock can be held while they're
760Sstevel@tonic-gate * being called.
770Sstevel@tonic-gate *
780Sstevel@tonic-gate * Credentials are read-only so no special precautions need to
790Sstevel@tonic-gate * be taken while locking them.
800Sstevel@tonic-gate *
810Sstevel@tonic-gate * When a new policy check needs to be added to the system the
820Sstevel@tonic-gate * following procedure should be followed:
830Sstevel@tonic-gate *
840Sstevel@tonic-gate * Pick an appropriate secpolicy_*() function
850Sstevel@tonic-gate * -> done if one exists.
860Sstevel@tonic-gate * Create a new secpolicy function, preferably with
870Sstevel@tonic-gate * a descriptive name using the standard template.
880Sstevel@tonic-gate * Pick an appropriate privilege for the policy.
890Sstevel@tonic-gate * If no appropraite privilege exists, define new one
900Sstevel@tonic-gate * (this should be done with extreme care; in most cases
910Sstevel@tonic-gate * little is gained by adding another privilege)
920Sstevel@tonic-gate *
930Sstevel@tonic-gate * WHY ROOT IS STILL SPECIAL.
940Sstevel@tonic-gate *
950Sstevel@tonic-gate * In a number of the policy functions, there are still explicit
960Sstevel@tonic-gate * checks for uid 0. The rationale behind these is that many root
970Sstevel@tonic-gate * owned files/objects hold configuration information which can give full
980Sstevel@tonic-gate * privileges to the user once written to. To prevent escalation
990Sstevel@tonic-gate * of privilege by allowing just a single privilege to modify root owned
1000Sstevel@tonic-gate * objects, we've added these root specific checks where we considered
1010Sstevel@tonic-gate * them necessary: modifying root owned files, changing uids to 0, etc.
1020Sstevel@tonic-gate *
1030Sstevel@tonic-gate * PRIVILEGE ESCALATION AND ZONES.
1040Sstevel@tonic-gate *
1050Sstevel@tonic-gate * A number of operations potentially allow the caller to achieve
1060Sstevel@tonic-gate * privileges beyond the ones normally required to perform the operation.
1070Sstevel@tonic-gate * For example, if allowed to create a setuid 0 executable, a process can
1080Sstevel@tonic-gate * gain privileges beyond PRIV_FILE_SETID. Zones, however, place
1090Sstevel@tonic-gate * restrictions on the ability to gain privileges beyond those available
1100Sstevel@tonic-gate * within the zone through file and process manipulation. Hence, such
1110Sstevel@tonic-gate * operations require that the caller have an effective set that includes
1120Sstevel@tonic-gate * all privileges available within the current zone, or all privileges
1130Sstevel@tonic-gate * if executing in the global zone.
1140Sstevel@tonic-gate *
1150Sstevel@tonic-gate * This is indicated in the priv_policy* policy checking functions
1160Sstevel@tonic-gate * through a combination of parameters. The "priv" parameter indicates
1170Sstevel@tonic-gate * the privilege that is required, and the "allzone" parameter indicates
1180Sstevel@tonic-gate * whether or not all privileges in the zone are required. In addition,
1190Sstevel@tonic-gate * priv can be set to PRIV_ALL to indicate that all privileges are
1200Sstevel@tonic-gate * required (regardless of zone). There are three scenarios of interest:
1210Sstevel@tonic-gate * (1) operation requires a specific privilege
1220Sstevel@tonic-gate * (2) operation requires a specific privilege, and requires all
1230Sstevel@tonic-gate * privileges available within the zone (or all privileges if in
1240Sstevel@tonic-gate * the global zone)
1250Sstevel@tonic-gate * (3) operation requires all privileges, regardless of zone
1260Sstevel@tonic-gate *
1270Sstevel@tonic-gate * For (1), priv should be set to the specific privilege, and allzone
1280Sstevel@tonic-gate * should be set to B_FALSE.
1290Sstevel@tonic-gate * For (2), priv should be set to the specific privilege, and allzone
1300Sstevel@tonic-gate * should be set to B_TRUE.
1310Sstevel@tonic-gate * For (3), priv should be set to PRIV_ALL, and allzone should be set
1320Sstevel@tonic-gate * to B_FALSE.
1330Sstevel@tonic-gate *
1340Sstevel@tonic-gate */
1350Sstevel@tonic-gate
1360Sstevel@tonic-gate /*
1370Sstevel@tonic-gate * The privileges are checked against the Effective set for
1380Sstevel@tonic-gate * ordinary processes and checked against the Limit set
1390Sstevel@tonic-gate * for euid 0 processes that haven't manipulated their privilege
1400Sstevel@tonic-gate * sets.
1410Sstevel@tonic-gate */
1420Sstevel@tonic-gate #define HAS_ALLPRIVS(cr) priv_isfullset(&CR_OEPRIV(cr))
1430Sstevel@tonic-gate #define ZONEPRIVS(cr) ((cr)->cr_zone->zone_privset)
1440Sstevel@tonic-gate #define HAS_ALLZONEPRIVS(cr) priv_issubset(ZONEPRIVS(cr), &CR_OEPRIV(cr))
1450Sstevel@tonic-gate #define HAS_PRIVILEGE(cr, pr) ((pr) == PRIV_ALL ? \
1460Sstevel@tonic-gate HAS_ALLPRIVS(cr) : \
1470Sstevel@tonic-gate PRIV_ISASSERT(&CR_OEPRIV(cr), pr))
1480Sstevel@tonic-gate
14912273SCasper.Dik@Sun.COM #define FAST_BASIC_CHECK(cr, priv) \
15012273SCasper.Dik@Sun.COM if (PRIV_ISASSERT(&CR_OEPRIV(cr), priv)) { \
15112273SCasper.Dik@Sun.COM DTRACE_PROBE2(priv__ok, int, priv, boolean_t, B_FALSE); \
15212273SCasper.Dik@Sun.COM return (0); \
15312273SCasper.Dik@Sun.COM }
15412273SCasper.Dik@Sun.COM
1550Sstevel@tonic-gate /*
1566134Scasper * Policy checking functions.
1570Sstevel@tonic-gate *
1586134Scasper * All of the system's policy should be implemented here.
1590Sstevel@tonic-gate */
1600Sstevel@tonic-gate
1610Sstevel@tonic-gate /*
1626134Scasper * Private functions which take an additional va_list argument to
1636134Scasper * implement an object specific policy override.
1646134Scasper */
1656134Scasper static int priv_policy_ap(const cred_t *, int, boolean_t, int,
1666134Scasper const char *, va_list);
1676134Scasper static int priv_policy_va(const cred_t *, int, boolean_t, int,
1686134Scasper const char *, ...);
1696134Scasper
1706134Scasper /*
1710Sstevel@tonic-gate * Generic policy calls
1720Sstevel@tonic-gate *
1730Sstevel@tonic-gate * The "bottom" functions of policy control
1740Sstevel@tonic-gate */
1750Sstevel@tonic-gate static char *
mprintf(const char * fmt,...)1760Sstevel@tonic-gate mprintf(const char *fmt, ...)
1770Sstevel@tonic-gate {
1780Sstevel@tonic-gate va_list args;
1790Sstevel@tonic-gate char *buf;
1800Sstevel@tonic-gate size_t len;
1810Sstevel@tonic-gate
1820Sstevel@tonic-gate va_start(args, fmt);
1830Sstevel@tonic-gate len = vsnprintf(NULL, 0, fmt, args) + 1;
1840Sstevel@tonic-gate va_end(args);
1850Sstevel@tonic-gate
1860Sstevel@tonic-gate buf = kmem_alloc(len, KM_NOSLEEP);
1870Sstevel@tonic-gate
1880Sstevel@tonic-gate if (buf == NULL)
1890Sstevel@tonic-gate return (NULL);
1900Sstevel@tonic-gate
1910Sstevel@tonic-gate va_start(args, fmt);
1920Sstevel@tonic-gate (void) vsnprintf(buf, len, fmt, args);
1930Sstevel@tonic-gate va_end(args);
1940Sstevel@tonic-gate
1950Sstevel@tonic-gate return (buf);
1960Sstevel@tonic-gate }
1970Sstevel@tonic-gate
1980Sstevel@tonic-gate /*
1990Sstevel@tonic-gate * priv_policy_errmsg()
2000Sstevel@tonic-gate *
2010Sstevel@tonic-gate * Generate an error message if privilege debugging is enabled system wide
2020Sstevel@tonic-gate * or for this particular process.
2030Sstevel@tonic-gate */
2040Sstevel@tonic-gate
2050Sstevel@tonic-gate #define FMTHDR "%s[%d]: missing privilege \"%s\" (euid = %d, syscall = %d)"
2060Sstevel@tonic-gate #define FMTMSG " for \"%s\""
2070Sstevel@tonic-gate #define FMTFUN " needed at %s+0x%lx"
2080Sstevel@tonic-gate
2090Sstevel@tonic-gate /* The maximum size privilege format: the concatenation of the above */
2100Sstevel@tonic-gate #define FMTMAX FMTHDR FMTMSG FMTFUN "\n"
2110Sstevel@tonic-gate
2120Sstevel@tonic-gate static void
priv_policy_errmsg(const cred_t * cr,int priv,const char * msg)2130Sstevel@tonic-gate priv_policy_errmsg(const cred_t *cr, int priv, const char *msg)
2140Sstevel@tonic-gate {
2150Sstevel@tonic-gate struct proc *me;
2160Sstevel@tonic-gate pc_t stack[MAXPRIVSTACK];
2170Sstevel@tonic-gate int depth;
2180Sstevel@tonic-gate int i;
2190Sstevel@tonic-gate char *sym;
2200Sstevel@tonic-gate ulong_t off;
2210Sstevel@tonic-gate const char *pname;
2220Sstevel@tonic-gate
2230Sstevel@tonic-gate char *cmd;
2240Sstevel@tonic-gate char fmt[sizeof (FMTMAX)];
2250Sstevel@tonic-gate
2260Sstevel@tonic-gate if ((me = curproc) == &p0)
2270Sstevel@tonic-gate return;
2280Sstevel@tonic-gate
2290Sstevel@tonic-gate /* Privileges must be defined */
2300Sstevel@tonic-gate ASSERT(priv == PRIV_ALL || priv == PRIV_MULTIPLE ||
2310Sstevel@tonic-gate priv == PRIV_ALLZONE || priv == PRIV_GLOBAL ||
2320Sstevel@tonic-gate priv_getbynum(priv) != NULL);
2330Sstevel@tonic-gate
2340Sstevel@tonic-gate if (priv == PRIV_ALLZONE && INGLOBALZONE(me))
2350Sstevel@tonic-gate priv = PRIV_ALL;
2360Sstevel@tonic-gate
2370Sstevel@tonic-gate if (curthread->t_pre_sys)
2380Sstevel@tonic-gate ttolwp(curthread)->lwp_badpriv = (short)priv;
2390Sstevel@tonic-gate
2400Sstevel@tonic-gate if (priv_debug == 0 && (CR_FLAGS(cr) & PRIV_DEBUG) == 0)
2410Sstevel@tonic-gate return;
2420Sstevel@tonic-gate
2430Sstevel@tonic-gate (void) strcpy(fmt, FMTHDR);
2440Sstevel@tonic-gate
2450Sstevel@tonic-gate if (me->p_user.u_comm[0])
2460Sstevel@tonic-gate cmd = &me->p_user.u_comm[0];
2470Sstevel@tonic-gate else
2480Sstevel@tonic-gate cmd = "priv_policy";
2490Sstevel@tonic-gate
2500Sstevel@tonic-gate if (msg != NULL && *msg != '\0') {
2510Sstevel@tonic-gate (void) strcat(fmt, FMTMSG);
2520Sstevel@tonic-gate } else {
2530Sstevel@tonic-gate (void) strcat(fmt, "%s");
2540Sstevel@tonic-gate msg = "";
2550Sstevel@tonic-gate }
2560Sstevel@tonic-gate
2570Sstevel@tonic-gate sym = NULL;
2580Sstevel@tonic-gate
2590Sstevel@tonic-gate depth = getpcstack(stack, MAXPRIVSTACK);
2600Sstevel@tonic-gate
2610Sstevel@tonic-gate /*
2620Sstevel@tonic-gate * Try to find the first interesting function on the stack.
2630Sstevel@tonic-gate * priv_policy* that's us, so completely uninteresting.
2640Sstevel@tonic-gate * suser(), drv_priv(), secpolicy_* are also called from
2650Sstevel@tonic-gate * too many locations to convey useful information.
2660Sstevel@tonic-gate */
2670Sstevel@tonic-gate for (i = 0; i < depth; i++) {
2680Sstevel@tonic-gate sym = kobj_getsymname((uintptr_t)stack[i], &off);
2690Sstevel@tonic-gate if (sym != NULL &&
2700Sstevel@tonic-gate strstr(sym, "hasprocperm") == 0 &&
2710Sstevel@tonic-gate strcmp("suser", sym) != 0 &&
2720Sstevel@tonic-gate strcmp("ipcaccess", sym) != 0 &&
2730Sstevel@tonic-gate strcmp("drv_priv", sym) != 0 &&
2740Sstevel@tonic-gate strncmp("secpolicy_", sym, 10) != 0 &&
2750Sstevel@tonic-gate strncmp("priv_policy", sym, 11) != 0)
2760Sstevel@tonic-gate break;
2770Sstevel@tonic-gate }
2780Sstevel@tonic-gate
2790Sstevel@tonic-gate if (sym != NULL)
2800Sstevel@tonic-gate (void) strcat(fmt, FMTFUN);
2810Sstevel@tonic-gate
2820Sstevel@tonic-gate (void) strcat(fmt, "\n");
2830Sstevel@tonic-gate
2840Sstevel@tonic-gate switch (priv) {
2850Sstevel@tonic-gate case PRIV_ALL:
2860Sstevel@tonic-gate pname = "ALL";
2870Sstevel@tonic-gate break;
2880Sstevel@tonic-gate case PRIV_MULTIPLE:
2890Sstevel@tonic-gate pname = "MULTIPLE";
2900Sstevel@tonic-gate break;
2910Sstevel@tonic-gate case PRIV_ALLZONE:
2920Sstevel@tonic-gate pname = "ZONE";
2930Sstevel@tonic-gate break;
2940Sstevel@tonic-gate case PRIV_GLOBAL:
2950Sstevel@tonic-gate pname = "GLOBAL";
2960Sstevel@tonic-gate break;
2970Sstevel@tonic-gate default:
2980Sstevel@tonic-gate pname = priv_getbynum(priv);
2990Sstevel@tonic-gate break;
3000Sstevel@tonic-gate }
3010Sstevel@tonic-gate
3020Sstevel@tonic-gate if (CR_FLAGS(cr) & PRIV_DEBUG) {
3030Sstevel@tonic-gate /* Remember last message, just like lwp_badpriv. */
3040Sstevel@tonic-gate if (curthread->t_pdmsg != NULL) {
3050Sstevel@tonic-gate kmem_free(curthread->t_pdmsg,
3060Sstevel@tonic-gate strlen(curthread->t_pdmsg) + 1);
3070Sstevel@tonic-gate }
3080Sstevel@tonic-gate
3090Sstevel@tonic-gate curthread->t_pdmsg = mprintf(fmt, cmd, me->p_pid, pname,
3104543Smarks cr->cr_uid, curthread->t_sysnum, msg, sym, off);
3110Sstevel@tonic-gate
3120Sstevel@tonic-gate curthread->t_post_sys = 1;
3136134Scasper }
3146134Scasper if (priv_debug) {
3150Sstevel@tonic-gate cmn_err(CE_NOTE, fmt, cmd, me->p_pid, pname, cr->cr_uid,
3160Sstevel@tonic-gate curthread->t_sysnum, msg, sym, off);
3170Sstevel@tonic-gate }
3180Sstevel@tonic-gate }
3190Sstevel@tonic-gate
3200Sstevel@tonic-gate /*
3216134Scasper * Override the policy, if appropriate. Return 0 if the external
3226134Scasper * policy engine approves.
3236134Scasper */
3246134Scasper static int
priv_policy_override(const cred_t * cr,int priv,boolean_t allzone,va_list ap)3256134Scasper priv_policy_override(const cred_t *cr, int priv, boolean_t allzone, va_list ap)
3266134Scasper {
3276134Scasper priv_set_t set;
3286134Scasper int ret;
3296134Scasper
3306134Scasper if (!(CR_FLAGS(cr) & PRIV_XPOLICY))
3316134Scasper return (-1);
3326134Scasper
3336134Scasper if (priv == PRIV_ALL) {
3346134Scasper priv_fillset(&set);
3356134Scasper } else if (allzone) {
3366134Scasper set = *ZONEPRIVS(cr);
3376134Scasper } else {
3386134Scasper priv_emptyset(&set);
3396134Scasper priv_addset(&set, priv);
3406134Scasper }
3416134Scasper ret = klpd_call(cr, &set, ap);
3426134Scasper return (ret);
3436134Scasper }
3446134Scasper
3456134Scasper static int
priv_policy_override_set(const cred_t * cr,const priv_set_t * req,va_list ap)34612273SCasper.Dik@Sun.COM priv_policy_override_set(const cred_t *cr, const priv_set_t *req, va_list ap)
3476134Scasper {
34812273SCasper.Dik@Sun.COM if (CR_FLAGS(cr) & PRIV_PFEXEC)
34912273SCasper.Dik@Sun.COM return (check_user_privs(cr, req));
3506134Scasper if (CR_FLAGS(cr) & PRIV_XPOLICY) {
3516134Scasper return (klpd_call(cr, req, ap));
3526134Scasper }
3536134Scasper return (-1);
3546134Scasper }
3556134Scasper
35612273SCasper.Dik@Sun.COM static int
priv_policy_override_set_va(const cred_t * cr,const priv_set_t * req,...)35712273SCasper.Dik@Sun.COM priv_policy_override_set_va(const cred_t *cr, const priv_set_t *req, ...)
35812273SCasper.Dik@Sun.COM {
35912273SCasper.Dik@Sun.COM va_list ap;
36012273SCasper.Dik@Sun.COM int ret;
36112273SCasper.Dik@Sun.COM
36212273SCasper.Dik@Sun.COM va_start(ap, req);
36312273SCasper.Dik@Sun.COM ret = priv_policy_override_set(cr, req, ap);
36412273SCasper.Dik@Sun.COM va_end(ap);
36512273SCasper.Dik@Sun.COM return (ret);
36612273SCasper.Dik@Sun.COM }
36712273SCasper.Dik@Sun.COM
3686134Scasper /*
3690Sstevel@tonic-gate * Audit failure, log error message.
3700Sstevel@tonic-gate */
3710Sstevel@tonic-gate static void
priv_policy_err(const cred_t * cr,int priv,boolean_t allzone,const char * msg)3720Sstevel@tonic-gate priv_policy_err(const cred_t *cr, int priv, boolean_t allzone, const char *msg)
3730Sstevel@tonic-gate {
3740Sstevel@tonic-gate
37511861SMarek.Pospisil@Sun.COM if (AU_AUDITING())
3760Sstevel@tonic-gate audit_priv(priv, allzone ? ZONEPRIVS(cr) : NULL, 0);
3770Sstevel@tonic-gate DTRACE_PROBE2(priv__err, int, priv, boolean_t, allzone);
3780Sstevel@tonic-gate
3790Sstevel@tonic-gate if (priv_debug || (CR_FLAGS(cr) & PRIV_DEBUG) ||
3800Sstevel@tonic-gate curthread->t_pre_sys) {
3810Sstevel@tonic-gate if (allzone && !HAS_ALLZONEPRIVS(cr)) {
3820Sstevel@tonic-gate priv_policy_errmsg(cr, PRIV_ALLZONE, msg);
3830Sstevel@tonic-gate } else {
3840Sstevel@tonic-gate ASSERT(!HAS_PRIVILEGE(cr, priv));
3850Sstevel@tonic-gate priv_policy_errmsg(cr, priv, msg);
3860Sstevel@tonic-gate }
3870Sstevel@tonic-gate }
3880Sstevel@tonic-gate }
3890Sstevel@tonic-gate
3900Sstevel@tonic-gate /*
3916134Scasper * priv_policy_ap()
3920Sstevel@tonic-gate * return 0 or error.
3930Sstevel@tonic-gate * See block comment above for a description of "priv" and "allzone" usage.
3940Sstevel@tonic-gate */
3956134Scasper static int
priv_policy_ap(const cred_t * cr,int priv,boolean_t allzone,int err,const char * msg,va_list ap)3966134Scasper priv_policy_ap(const cred_t *cr, int priv, boolean_t allzone, int err,
3976134Scasper const char *msg, va_list ap)
3980Sstevel@tonic-gate {
3996134Scasper if ((HAS_PRIVILEGE(cr, priv) && (!allzone || HAS_ALLZONEPRIVS(cr))) ||
4006134Scasper (!servicing_interrupt() &&
4016134Scasper priv_policy_override(cr, priv, allzone, ap) == 0)) {
4020Sstevel@tonic-gate if ((allzone || priv == PRIV_ALL ||
4030Sstevel@tonic-gate !PRIV_ISASSERT(priv_basic, priv)) &&
4040Sstevel@tonic-gate !servicing_interrupt()) {
4053446Smrj PTOU(curproc)->u_acflag |= ASU; /* Needed for SVVS */
40611861SMarek.Pospisil@Sun.COM if (AU_AUDITING())
4070Sstevel@tonic-gate audit_priv(priv,
4080Sstevel@tonic-gate allzone ? ZONEPRIVS(cr) : NULL, 1);
4090Sstevel@tonic-gate }
4100Sstevel@tonic-gate err = 0;
4110Sstevel@tonic-gate DTRACE_PROBE2(priv__ok, int, priv, boolean_t, allzone);
4120Sstevel@tonic-gate } else if (!servicing_interrupt()) {
4130Sstevel@tonic-gate /* Failure audited in this procedure */
4140Sstevel@tonic-gate priv_policy_err(cr, priv, allzone, msg);
4150Sstevel@tonic-gate }
4166134Scasper return (err);
4176134Scasper }
4180Sstevel@tonic-gate
4196134Scasper int
priv_policy_va(const cred_t * cr,int priv,boolean_t allzone,int err,const char * msg,...)4206134Scasper priv_policy_va(const cred_t *cr, int priv, boolean_t allzone, int err,
4216134Scasper const char *msg, ...)
4226134Scasper {
4236134Scasper int ret;
4246134Scasper va_list ap;
4256134Scasper
4266134Scasper va_start(ap, msg);
4276134Scasper ret = priv_policy_ap(cr, priv, allzone, err, msg, ap);
4286134Scasper va_end(ap);
4296134Scasper
4306134Scasper return (ret);
4316134Scasper }
4326134Scasper
4336134Scasper int
priv_policy(const cred_t * cr,int priv,boolean_t allzone,int err,const char * msg)4346134Scasper priv_policy(const cred_t *cr, int priv, boolean_t allzone, int err,
4356134Scasper const char *msg)
4366134Scasper {
43712273SCasper.Dik@Sun.COM return (priv_policy_va(cr, priv, allzone, err, msg, KLPDARG_NONE));
4380Sstevel@tonic-gate }
4390Sstevel@tonic-gate
4400Sstevel@tonic-gate /*
4410Sstevel@tonic-gate * Return B_TRUE for sufficient privileges, B_FALSE for insufficient privileges.
4420Sstevel@tonic-gate */
4430Sstevel@tonic-gate boolean_t
priv_policy_choice(const cred_t * cr,int priv,boolean_t allzone)4440Sstevel@tonic-gate priv_policy_choice(const cred_t *cr, int priv, boolean_t allzone)
4450Sstevel@tonic-gate {
4460Sstevel@tonic-gate boolean_t res = HAS_PRIVILEGE(cr, priv) &&
4470Sstevel@tonic-gate (!allzone || HAS_ALLZONEPRIVS(cr));
4480Sstevel@tonic-gate
4490Sstevel@tonic-gate /* Audit success only */
45011861SMarek.Pospisil@Sun.COM if (res && AU_AUDITING() &&
4510Sstevel@tonic-gate (allzone || priv == PRIV_ALL || !PRIV_ISASSERT(priv_basic, priv)) &&
4520Sstevel@tonic-gate !servicing_interrupt()) {
4530Sstevel@tonic-gate audit_priv(priv, allzone ? ZONEPRIVS(cr) : NULL, 1);
4540Sstevel@tonic-gate }
4550Sstevel@tonic-gate if (res) {
4560Sstevel@tonic-gate DTRACE_PROBE2(priv__ok, int, priv, boolean_t, allzone);
4570Sstevel@tonic-gate } else {
4580Sstevel@tonic-gate DTRACE_PROBE2(priv__err, int, priv, boolean_t, allzone);
4590Sstevel@tonic-gate }
4600Sstevel@tonic-gate return (res);
4610Sstevel@tonic-gate }
4620Sstevel@tonic-gate
4630Sstevel@tonic-gate /*
4640Sstevel@tonic-gate * Non-auditing variant of priv_policy_choice().
4650Sstevel@tonic-gate */
4660Sstevel@tonic-gate boolean_t
priv_policy_only(const cred_t * cr,int priv,boolean_t allzone)4670Sstevel@tonic-gate priv_policy_only(const cred_t *cr, int priv, boolean_t allzone)
4680Sstevel@tonic-gate {
4690Sstevel@tonic-gate boolean_t res = HAS_PRIVILEGE(cr, priv) &&
4700Sstevel@tonic-gate (!allzone || HAS_ALLZONEPRIVS(cr));
4710Sstevel@tonic-gate
4720Sstevel@tonic-gate if (res) {
4730Sstevel@tonic-gate DTRACE_PROBE2(priv__ok, int, priv, boolean_t, allzone);
4740Sstevel@tonic-gate } else {
4750Sstevel@tonic-gate DTRACE_PROBE2(priv__err, int, priv, boolean_t, allzone);
4760Sstevel@tonic-gate }
4770Sstevel@tonic-gate return (res);
4780Sstevel@tonic-gate }
4790Sstevel@tonic-gate
4800Sstevel@tonic-gate /*
4810Sstevel@tonic-gate * Check whether all privileges in the required set are present.
4820Sstevel@tonic-gate */
4830Sstevel@tonic-gate static int
secpolicy_require_set(const cred_t * cr,const priv_set_t * req,const char * msg,...)48412273SCasper.Dik@Sun.COM secpolicy_require_set(const cred_t *cr, const priv_set_t *req,
48512273SCasper.Dik@Sun.COM const char *msg, ...)
4860Sstevel@tonic-gate {
4870Sstevel@tonic-gate int priv;
4880Sstevel@tonic-gate int pfound = -1;
4890Sstevel@tonic-gate priv_set_t pset;
49012273SCasper.Dik@Sun.COM va_list ap;
49112273SCasper.Dik@Sun.COM int ret;
4920Sstevel@tonic-gate
4930Sstevel@tonic-gate if (req == PRIV_FULLSET ? HAS_ALLPRIVS(cr) : priv_issubset(req,
4944543Smarks &CR_OEPRIV(cr))) {
4950Sstevel@tonic-gate return (0);
4960Sstevel@tonic-gate }
4970Sstevel@tonic-gate
49812273SCasper.Dik@Sun.COM va_start(ap, msg);
49912273SCasper.Dik@Sun.COM ret = priv_policy_override_set(cr, req, ap);
50012273SCasper.Dik@Sun.COM va_end(ap);
50112273SCasper.Dik@Sun.COM if (ret == 0)
5026134Scasper return (0);
5036134Scasper
5040Sstevel@tonic-gate if (req == PRIV_FULLSET || priv_isfullset(req)) {
5050Sstevel@tonic-gate priv_policy_err(cr, PRIV_ALL, B_FALSE, msg);
5060Sstevel@tonic-gate return (EACCES);
5070Sstevel@tonic-gate }
5080Sstevel@tonic-gate
5090Sstevel@tonic-gate pset = CR_OEPRIV(cr); /* present privileges */
5100Sstevel@tonic-gate priv_inverse(&pset); /* all non present privileges */
5110Sstevel@tonic-gate priv_intersect(req, &pset); /* the actual missing privs */
5120Sstevel@tonic-gate
51311861SMarek.Pospisil@Sun.COM if (AU_AUDITING())
5140Sstevel@tonic-gate audit_priv(PRIV_NONE, &pset, 0);
5150Sstevel@tonic-gate /*
5160Sstevel@tonic-gate * Privilege debugging; special case "one privilege in set".
5170Sstevel@tonic-gate */
5180Sstevel@tonic-gate if (priv_debug || (CR_FLAGS(cr) & PRIV_DEBUG) || curthread->t_pre_sys) {
5190Sstevel@tonic-gate for (priv = 0; priv < nprivs; priv++) {
5200Sstevel@tonic-gate if (priv_ismember(&pset, priv)) {
5210Sstevel@tonic-gate if (pfound != -1) {
5220Sstevel@tonic-gate /* Multiple missing privs */
5230Sstevel@tonic-gate priv_policy_errmsg(cr, PRIV_MULTIPLE,
5244543Smarks msg);
5250Sstevel@tonic-gate return (EACCES);
5260Sstevel@tonic-gate }
5270Sstevel@tonic-gate pfound = priv;
5280Sstevel@tonic-gate }
5290Sstevel@tonic-gate }
5300Sstevel@tonic-gate ASSERT(pfound != -1);
5310Sstevel@tonic-gate /* Just the one missing privilege */
5320Sstevel@tonic-gate priv_policy_errmsg(cr, pfound, msg);
5330Sstevel@tonic-gate }
5340Sstevel@tonic-gate
5350Sstevel@tonic-gate return (EACCES);
5360Sstevel@tonic-gate }
5370Sstevel@tonic-gate
5380Sstevel@tonic-gate /*
5390Sstevel@tonic-gate * Called when an operation requires that the caller be in the
5400Sstevel@tonic-gate * global zone, regardless of privilege.
5410Sstevel@tonic-gate */
5420Sstevel@tonic-gate static int
priv_policy_global(const cred_t * cr)5430Sstevel@tonic-gate priv_policy_global(const cred_t *cr)
5440Sstevel@tonic-gate {
5450Sstevel@tonic-gate if (crgetzoneid(cr) == GLOBAL_ZONEID)
5460Sstevel@tonic-gate return (0); /* success */
5470Sstevel@tonic-gate
5480Sstevel@tonic-gate if (priv_debug || (CR_FLAGS(cr) & PRIV_DEBUG) ||
5490Sstevel@tonic-gate curthread->t_pre_sys) {
5500Sstevel@tonic-gate priv_policy_errmsg(cr, PRIV_GLOBAL, NULL);
5510Sstevel@tonic-gate }
5520Sstevel@tonic-gate return (EPERM);
5530Sstevel@tonic-gate }
5540Sstevel@tonic-gate
5550Sstevel@tonic-gate /*
5560Sstevel@tonic-gate * Changing process priority
5570Sstevel@tonic-gate */
5580Sstevel@tonic-gate int
secpolicy_setpriority(const cred_t * cr)5590Sstevel@tonic-gate secpolicy_setpriority(const cred_t *cr)
5600Sstevel@tonic-gate {
5610Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_PROC_PRIOCNTL, B_FALSE, EPERM, NULL));
5620Sstevel@tonic-gate }
5630Sstevel@tonic-gate
5640Sstevel@tonic-gate /*
5650Sstevel@tonic-gate * Binding to a privileged port, port must be specified in host byte
5660Sstevel@tonic-gate * order.
56712273SCasper.Dik@Sun.COM * When adding a new privilege which allows binding to currently privileged
56812273SCasper.Dik@Sun.COM * ports, then you MUST also allow processes with PRIV_NET_PRIVADDR bind
56912273SCasper.Dik@Sun.COM * to these ports because of backward compatibility.
5700Sstevel@tonic-gate */
5710Sstevel@tonic-gate int
secpolicy_net_privaddr(const cred_t * cr,in_port_t port,int proto)5726134Scasper secpolicy_net_privaddr(const cred_t *cr, in_port_t port, int proto)
5730Sstevel@tonic-gate {
5745331Samw char *reason;
5755331Samw int priv;
5765331Samw
5775331Samw switch (port) {
5785331Samw case 137:
5795331Samw case 138:
5805331Samw case 139:
5815331Samw case 445:
5825331Samw /*
58312273SCasper.Dik@Sun.COM * NBT and SMB ports, these are normal privileged ports,
58412273SCasper.Dik@Sun.COM * allow bind only if the SYS_SMB or NET_PRIVADDR privilege
58512273SCasper.Dik@Sun.COM * is present.
58612273SCasper.Dik@Sun.COM * Try both, if neither is present return an error for
58712273SCasper.Dik@Sun.COM * priv SYS_SMB.
5885331Samw */
58912273SCasper.Dik@Sun.COM if (PRIV_POLICY_ONLY(cr, PRIV_NET_PRIVADDR, B_FALSE))
59012273SCasper.Dik@Sun.COM priv = PRIV_NET_PRIVADDR;
59112273SCasper.Dik@Sun.COM else
59212273SCasper.Dik@Sun.COM priv = PRIV_SYS_SMB;
5935331Samw reason = "NBT or SMB port";
5945331Samw break;
5955331Samw
5965331Samw case 2049:
5975331Samw case 4045:
5985331Samw /*
5995331Samw * NFS ports, these are extra privileged ports, allow bind
6005331Samw * only if the SYS_NFS privilege is present.
6015331Samw */
6025331Samw priv = PRIV_SYS_NFS;
6035331Samw reason = "NFS port";
6045331Samw break;
6055331Samw
6065331Samw default:
6075331Samw priv = PRIV_NET_PRIVADDR;
6085331Samw reason = NULL;
6095331Samw break;
6105331Samw
6115331Samw }
6125331Samw
6136134Scasper return (priv_policy_va(cr, priv, B_FALSE, EACCES, reason,
6146134Scasper KLPDARG_PORT, (int)proto, (int)port, KLPDARG_NOMORE));
6150Sstevel@tonic-gate }
6160Sstevel@tonic-gate
6170Sstevel@tonic-gate /*
6181676Sjpk * Binding to a multilevel port on a trusted (labeled) system.
6191676Sjpk */
6201676Sjpk int
secpolicy_net_bindmlp(const cred_t * cr)6211676Sjpk secpolicy_net_bindmlp(const cred_t *cr)
6221676Sjpk {
6236134Scasper return (PRIV_POLICY(cr, PRIV_NET_BINDMLP, B_FALSE, EACCES, NULL));
6241676Sjpk }
6251676Sjpk
6261676Sjpk /*
6271676Sjpk * Allow a communication between a zone and an unlabeled host when their
6281676Sjpk * labels don't match.
6291676Sjpk */
6301676Sjpk int
secpolicy_net_mac_aware(const cred_t * cr)6311676Sjpk secpolicy_net_mac_aware(const cred_t *cr)
6321676Sjpk {
6336134Scasper return (PRIV_POLICY(cr, PRIV_NET_MAC_AWARE, B_FALSE, EACCES, NULL));
6341676Sjpk }
6351676Sjpk
6361676Sjpk /*
63710934Ssommerfeld@sun.com * Allow a privileged process to transmit traffic without explicit labels
63810934Ssommerfeld@sun.com */
63910934Ssommerfeld@sun.com int
secpolicy_net_mac_implicit(const cred_t * cr)64010934Ssommerfeld@sun.com secpolicy_net_mac_implicit(const cred_t *cr)
64110934Ssommerfeld@sun.com {
64210934Ssommerfeld@sun.com return (PRIV_POLICY(cr, PRIV_NET_MAC_IMPLICIT, B_FALSE, EACCES, NULL));
64310934Ssommerfeld@sun.com }
64410934Ssommerfeld@sun.com
64510934Ssommerfeld@sun.com /*
6460Sstevel@tonic-gate * Common routine which determines whether a given credential can
6470Sstevel@tonic-gate * act on a given mount.
6480Sstevel@tonic-gate * When called through mount, the parameter needoptcheck is a pointer
6490Sstevel@tonic-gate * to a boolean variable which will be set to either true or false,
6500Sstevel@tonic-gate * depending on whether the mount policy should change the mount options.
6510Sstevel@tonic-gate * In all other cases, needoptcheck should be a NULL pointer.
6520Sstevel@tonic-gate */
6530Sstevel@tonic-gate static int
secpolicy_fs_common(cred_t * cr,vnode_t * mvp,const vfs_t * vfsp,boolean_t * needoptcheck)6540Sstevel@tonic-gate secpolicy_fs_common(cred_t *cr, vnode_t *mvp, const vfs_t *vfsp,
6550Sstevel@tonic-gate boolean_t *needoptcheck)
6560Sstevel@tonic-gate {
6570Sstevel@tonic-gate boolean_t allzone = B_FALSE;
6580Sstevel@tonic-gate boolean_t mounting = needoptcheck != NULL;
6590Sstevel@tonic-gate
6600Sstevel@tonic-gate /*
6610Sstevel@tonic-gate * Short circuit the following cases:
6620Sstevel@tonic-gate * vfsp == NULL or mvp == NULL (pure privilege check)
6630Sstevel@tonic-gate * have all privileges - no further checks required
6640Sstevel@tonic-gate * and no mount options need to be set.
6650Sstevel@tonic-gate */
6660Sstevel@tonic-gate if (vfsp == NULL || mvp == NULL || HAS_ALLPRIVS(cr)) {
6670Sstevel@tonic-gate if (mounting)
6680Sstevel@tonic-gate *needoptcheck = B_FALSE;
6690Sstevel@tonic-gate
6706134Scasper return (priv_policy_va(cr, PRIV_SYS_MOUNT, allzone, EPERM,
6716134Scasper NULL, KLPDARG_VNODE, mvp, (char *)NULL, KLPDARG_NOMORE));
6720Sstevel@tonic-gate }
6730Sstevel@tonic-gate
6740Sstevel@tonic-gate /*
6750Sstevel@tonic-gate * When operating on an existing mount (either we're not mounting
6760Sstevel@tonic-gate * or we're doing a remount and VFS_REMOUNT will be set), zones
6770Sstevel@tonic-gate * can operate only on mounts established by the zone itself.
6780Sstevel@tonic-gate */
6790Sstevel@tonic-gate if (!mounting || (vfsp->vfs_flag & VFS_REMOUNT) != 0) {
6800Sstevel@tonic-gate zoneid_t zoneid = crgetzoneid(cr);
6810Sstevel@tonic-gate
6820Sstevel@tonic-gate if (zoneid != GLOBAL_ZONEID &&
6830Sstevel@tonic-gate vfsp->vfs_zone->zone_id != zoneid) {
6840Sstevel@tonic-gate return (EPERM);
6850Sstevel@tonic-gate }
6860Sstevel@tonic-gate }
6870Sstevel@tonic-gate
6880Sstevel@tonic-gate if (mounting)
6890Sstevel@tonic-gate *needoptcheck = B_TRUE;
6900Sstevel@tonic-gate
6910Sstevel@tonic-gate /*
6920Sstevel@tonic-gate * Overlay mounts may hide important stuff; if you can't write to a
6930Sstevel@tonic-gate * mount point but would be able to mount on top of it, you can
6940Sstevel@tonic-gate * escalate your privileges.
6950Sstevel@tonic-gate * So we go about asking the same questions namefs does when it
6960Sstevel@tonic-gate * decides whether you can mount over a file or not but with the
6970Sstevel@tonic-gate * added restriction that you can only mount on top of a regular
6980Sstevel@tonic-gate * file or directory.
6990Sstevel@tonic-gate * If we have all the zone's privileges, we skip all other checks,
7000Sstevel@tonic-gate * or else we may actually get in trouble inside the automounter.
7010Sstevel@tonic-gate */
7020Sstevel@tonic-gate if ((mvp->v_flag & VROOT) != 0 ||
7030Sstevel@tonic-gate (mvp->v_type != VDIR && mvp->v_type != VREG) ||
7040Sstevel@tonic-gate HAS_ALLZONEPRIVS(cr)) {
7050Sstevel@tonic-gate allzone = B_TRUE;
7060Sstevel@tonic-gate } else {
7070Sstevel@tonic-gate vattr_t va;
7080Sstevel@tonic-gate int err;
7090Sstevel@tonic-gate
7100Sstevel@tonic-gate va.va_mask = AT_UID|AT_MODE;
7115331Samw err = VOP_GETATTR(mvp, &va, 0, cr, NULL);
7120Sstevel@tonic-gate if (err != 0)
7130Sstevel@tonic-gate return (err);
7140Sstevel@tonic-gate
7150Sstevel@tonic-gate if ((err = secpolicy_vnode_owner(cr, va.va_uid)) != 0)
7160Sstevel@tonic-gate return (err);
7170Sstevel@tonic-gate
71812273SCasper.Dik@Sun.COM if (secpolicy_vnode_access2(cr, mvp, va.va_uid, va.va_mode,
71912273SCasper.Dik@Sun.COM VWRITE) != 0) {
7200Sstevel@tonic-gate return (EACCES);
7210Sstevel@tonic-gate }
7220Sstevel@tonic-gate }
7236134Scasper return (priv_policy_va(cr, PRIV_SYS_MOUNT, allzone, EPERM,
7246134Scasper NULL, KLPDARG_VNODE, mvp, (char *)NULL, KLPDARG_NOMORE));
7250Sstevel@tonic-gate }
7260Sstevel@tonic-gate
7274543Smarks void
secpolicy_fs_mount_clearopts(cred_t * cr,struct vfs * vfsp)7284543Smarks secpolicy_fs_mount_clearopts(cred_t *cr, struct vfs *vfsp)
7294543Smarks {
7304543Smarks boolean_t amsuper = HAS_ALLZONEPRIVS(cr);
7314543Smarks
7324543Smarks /*
7334543Smarks * check; if we don't have either "nosuid" or
7344543Smarks * both "nosetuid" and "nodevices", then we add
7354543Smarks * "nosuid"; this depends on how the current
7364543Smarks * implementation works (it first checks nosuid). In a
7374543Smarks * zone, a user with all zone privileges can mount with
7384543Smarks * "setuid" but never with "devices".
7394543Smarks */
7404543Smarks if (!vfs_optionisset(vfsp, MNTOPT_NOSUID, NULL) &&
7414543Smarks (!vfs_optionisset(vfsp, MNTOPT_NODEVICES, NULL) ||
7424543Smarks !vfs_optionisset(vfsp, MNTOPT_NOSETUID, NULL))) {
7434543Smarks if (crgetzoneid(cr) == GLOBAL_ZONEID || !amsuper)
7444543Smarks vfs_setmntopt(vfsp, MNTOPT_NOSUID, NULL, 0);
7454543Smarks else
7464543Smarks vfs_setmntopt(vfsp, MNTOPT_NODEVICES, NULL, 0);
7474543Smarks }
7484543Smarks /*
7494543Smarks * If we're not the local super user, we set the "restrict"
7504543Smarks * option to indicate to automountd that this mount should
7514543Smarks * be handled with care.
7524543Smarks */
7534543Smarks if (!amsuper)
7544543Smarks vfs_setmntopt(vfsp, MNTOPT_RESTRICT, NULL, 0);
7554543Smarks
7564543Smarks }
7574543Smarks
75812633Sjohn.levon@sun.com int
secpolicy_fs_allowed_mount(const char * fsname)75912633Sjohn.levon@sun.com secpolicy_fs_allowed_mount(const char *fsname)
76012633Sjohn.levon@sun.com {
76112633Sjohn.levon@sun.com struct vfssw *vswp;
76212633Sjohn.levon@sun.com const char *p;
76312633Sjohn.levon@sun.com size_t len;
76412633Sjohn.levon@sun.com
76512633Sjohn.levon@sun.com ASSERT(fsname != NULL);
76612633Sjohn.levon@sun.com ASSERT(fsname[0] != '\0');
76712633Sjohn.levon@sun.com
76812633Sjohn.levon@sun.com if (INGLOBALZONE(curproc))
76912633Sjohn.levon@sun.com return (0);
77012633Sjohn.levon@sun.com
77112633Sjohn.levon@sun.com vswp = vfs_getvfssw(fsname);
77212633Sjohn.levon@sun.com if (vswp == NULL)
77312633Sjohn.levon@sun.com return (ENOENT);
77412633Sjohn.levon@sun.com
77512633Sjohn.levon@sun.com if ((vswp->vsw_flag & VSW_ZMOUNT) != 0) {
77612633Sjohn.levon@sun.com vfs_unrefvfssw(vswp);
77712633Sjohn.levon@sun.com return (0);
77812633Sjohn.levon@sun.com }
77912633Sjohn.levon@sun.com
78012633Sjohn.levon@sun.com vfs_unrefvfssw(vswp);
78112633Sjohn.levon@sun.com
78212633Sjohn.levon@sun.com p = curzone->zone_fs_allowed;
78312633Sjohn.levon@sun.com len = strlen(fsname);
78412633Sjohn.levon@sun.com
78512633Sjohn.levon@sun.com while (p != NULL && *p != '\0') {
78612633Sjohn.levon@sun.com if (strncmp(p, fsname, len) == 0) {
78712633Sjohn.levon@sun.com char c = *(p + len);
78812633Sjohn.levon@sun.com if (c == '\0' || c == ',')
78912633Sjohn.levon@sun.com return (0);
79012633Sjohn.levon@sun.com }
79112633Sjohn.levon@sun.com
79212633Sjohn.levon@sun.com /* skip to beyond the next comma */
79312633Sjohn.levon@sun.com if ((p = strchr(p, ',')) != NULL)
79412633Sjohn.levon@sun.com p++;
79512633Sjohn.levon@sun.com }
79612633Sjohn.levon@sun.com
79712633Sjohn.levon@sun.com return (EPERM);
79812633Sjohn.levon@sun.com }
79912633Sjohn.levon@sun.com
800148Scasper extern vnode_t *rootvp;
801148Scasper extern vfs_t *rootvfs;
802148Scasper
8030Sstevel@tonic-gate int
secpolicy_fs_mount(cred_t * cr,vnode_t * mvp,struct vfs * vfsp)8040Sstevel@tonic-gate secpolicy_fs_mount(cred_t *cr, vnode_t *mvp, struct vfs *vfsp)
8050Sstevel@tonic-gate {
8060Sstevel@tonic-gate boolean_t needoptchk;
8070Sstevel@tonic-gate int error;
8080Sstevel@tonic-gate
809148Scasper /*
810148Scasper * If it's a remount, get the underlying mount point,
811148Scasper * except for the root where we use the rootvp.
812148Scasper */
813148Scasper if ((vfsp->vfs_flag & VFS_REMOUNT) != 0) {
814148Scasper if (vfsp == rootvfs)
815148Scasper mvp = rootvp;
816148Scasper else
817148Scasper mvp = vfsp->vfs_vnodecovered;
818148Scasper }
819148Scasper
8200Sstevel@tonic-gate error = secpolicy_fs_common(cr, mvp, vfsp, &needoptchk);
8210Sstevel@tonic-gate
8220Sstevel@tonic-gate if (error == 0 && needoptchk) {
8234543Smarks secpolicy_fs_mount_clearopts(cr, vfsp);
8244543Smarks }
8250Sstevel@tonic-gate
8260Sstevel@tonic-gate return (error);
8270Sstevel@tonic-gate }
8280Sstevel@tonic-gate
8290Sstevel@tonic-gate /*
8300Sstevel@tonic-gate * Does the policy computations for "ownership" of a mount;
8310Sstevel@tonic-gate * here ownership is defined as the ability to "mount"
8320Sstevel@tonic-gate * the filesystem originally. The rootvfs doesn't cover any
8330Sstevel@tonic-gate * vnodes; we attribute its ownership to the rootvp.
8340Sstevel@tonic-gate */
8350Sstevel@tonic-gate static int
secpolicy_fs_owner(cred_t * cr,const struct vfs * vfsp)8360Sstevel@tonic-gate secpolicy_fs_owner(cred_t *cr, const struct vfs *vfsp)
8370Sstevel@tonic-gate {
8380Sstevel@tonic-gate vnode_t *mvp;
8390Sstevel@tonic-gate
8400Sstevel@tonic-gate if (vfsp == NULL)
8410Sstevel@tonic-gate mvp = NULL;
8420Sstevel@tonic-gate else if (vfsp == rootvfs)
8430Sstevel@tonic-gate mvp = rootvp;
8440Sstevel@tonic-gate else
8450Sstevel@tonic-gate mvp = vfsp->vfs_vnodecovered;
8460Sstevel@tonic-gate
8470Sstevel@tonic-gate return (secpolicy_fs_common(cr, mvp, vfsp, NULL));
8480Sstevel@tonic-gate }
8490Sstevel@tonic-gate
8500Sstevel@tonic-gate int
secpolicy_fs_unmount(cred_t * cr,struct vfs * vfsp)8510Sstevel@tonic-gate secpolicy_fs_unmount(cred_t *cr, struct vfs *vfsp)
8520Sstevel@tonic-gate {
8530Sstevel@tonic-gate return (secpolicy_fs_owner(cr, vfsp));
8540Sstevel@tonic-gate }
8550Sstevel@tonic-gate
8560Sstevel@tonic-gate /*
8570Sstevel@tonic-gate * Quotas are a resource, but if one has the ability to mount a filesystem, he
8580Sstevel@tonic-gate * should be able to modify quotas on it.
8590Sstevel@tonic-gate */
8600Sstevel@tonic-gate int
secpolicy_fs_quota(const cred_t * cr,const vfs_t * vfsp)8610Sstevel@tonic-gate secpolicy_fs_quota(const cred_t *cr, const vfs_t *vfsp)
8620Sstevel@tonic-gate {
8630Sstevel@tonic-gate return (secpolicy_fs_owner((cred_t *)cr, vfsp));
8640Sstevel@tonic-gate }
8650Sstevel@tonic-gate
8660Sstevel@tonic-gate /*
8670Sstevel@tonic-gate * Exceeding minfree: also a per-mount resource constraint.
8680Sstevel@tonic-gate */
8690Sstevel@tonic-gate int
secpolicy_fs_minfree(const cred_t * cr,const vfs_t * vfsp)8700Sstevel@tonic-gate secpolicy_fs_minfree(const cred_t *cr, const vfs_t *vfsp)
8710Sstevel@tonic-gate {
8720Sstevel@tonic-gate return (secpolicy_fs_owner((cred_t *)cr, vfsp));
8730Sstevel@tonic-gate }
8740Sstevel@tonic-gate
8750Sstevel@tonic-gate int
secpolicy_fs_config(const cred_t * cr,const vfs_t * vfsp)8760Sstevel@tonic-gate secpolicy_fs_config(const cred_t *cr, const vfs_t *vfsp)
8770Sstevel@tonic-gate {
8780Sstevel@tonic-gate return (secpolicy_fs_owner((cred_t *)cr, vfsp));
8790Sstevel@tonic-gate }
8800Sstevel@tonic-gate
8810Sstevel@tonic-gate /* ARGSUSED */
8820Sstevel@tonic-gate int
secpolicy_fs_linkdir(const cred_t * cr,const vfs_t * vfsp)8830Sstevel@tonic-gate secpolicy_fs_linkdir(const cred_t *cr, const vfs_t *vfsp)
8840Sstevel@tonic-gate {
8850Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_LINKDIR, B_FALSE, EPERM, NULL));
8860Sstevel@tonic-gate }
8870Sstevel@tonic-gate
8880Sstevel@tonic-gate /*
8890Sstevel@tonic-gate * Name: secpolicy_vnode_access()
8900Sstevel@tonic-gate *
8910Sstevel@tonic-gate * Parameters: Process credential
8920Sstevel@tonic-gate * vnode
8930Sstevel@tonic-gate * uid of owner of vnode
8940Sstevel@tonic-gate * permission bits not granted to the caller when examining
8950Sstevel@tonic-gate * file mode bits (i.e., when a process wants to open a
8960Sstevel@tonic-gate * mode 444 file for VREAD|VWRITE, this function should be
8970Sstevel@tonic-gate * called only with a VWRITE argument).
8980Sstevel@tonic-gate *
8990Sstevel@tonic-gate * Normal: Verifies that cred has the appropriate privileges to
9000Sstevel@tonic-gate * override the mode bits that were denied.
9010Sstevel@tonic-gate *
9020Sstevel@tonic-gate * Override: file_dac_execute - if VEXEC bit was denied and vnode is
9030Sstevel@tonic-gate * not a directory.
9040Sstevel@tonic-gate * file_dac_read - if VREAD bit was denied.
9050Sstevel@tonic-gate * file_dac_search - if VEXEC bit was denied and vnode is
9060Sstevel@tonic-gate * a directory.
9070Sstevel@tonic-gate * file_dac_write - if VWRITE bit was denied.
9080Sstevel@tonic-gate *
9090Sstevel@tonic-gate * Root owned files are special cased to protect system
9100Sstevel@tonic-gate * configuration files and such.
9110Sstevel@tonic-gate *
9120Sstevel@tonic-gate * Output: EACCES - if privilege check fails.
9130Sstevel@tonic-gate */
9140Sstevel@tonic-gate
9150Sstevel@tonic-gate int
secpolicy_vnode_access(const cred_t * cr,vnode_t * vp,uid_t owner,mode_t mode)9160Sstevel@tonic-gate secpolicy_vnode_access(const cred_t *cr, vnode_t *vp, uid_t owner, mode_t mode)
9170Sstevel@tonic-gate {
9186134Scasper if ((mode & VREAD) && priv_policy_va(cr, PRIV_FILE_DAC_READ, B_FALSE,
9196134Scasper EACCES, NULL, KLPDARG_VNODE, vp, (char *)NULL,
9206134Scasper KLPDARG_NOMORE) != 0) {
9210Sstevel@tonic-gate return (EACCES);
9226134Scasper }
9230Sstevel@tonic-gate
9240Sstevel@tonic-gate if (mode & VWRITE) {
9250Sstevel@tonic-gate boolean_t allzone;
9260Sstevel@tonic-gate
9270Sstevel@tonic-gate if (owner == 0 && cr->cr_uid != 0)
9280Sstevel@tonic-gate allzone = B_TRUE;
9290Sstevel@tonic-gate else
9300Sstevel@tonic-gate allzone = B_FALSE;
9316134Scasper if (priv_policy_va(cr, PRIV_FILE_DAC_WRITE, allzone, EACCES,
9326134Scasper NULL, KLPDARG_VNODE, vp, (char *)NULL,
9336134Scasper KLPDARG_NOMORE) != 0) {
9340Sstevel@tonic-gate return (EACCES);
9356134Scasper }
9360Sstevel@tonic-gate }
9370Sstevel@tonic-gate
9380Sstevel@tonic-gate if (mode & VEXEC) {
9390Sstevel@tonic-gate /*
9400Sstevel@tonic-gate * Directories use file_dac_search to override the execute bit.
9410Sstevel@tonic-gate */
9426134Scasper int p = vp->v_type == VDIR ? PRIV_FILE_DAC_SEARCH :
9436134Scasper PRIV_FILE_DAC_EXECUTE;
9440Sstevel@tonic-gate
9456134Scasper return (priv_policy_va(cr, p, B_FALSE, EACCES, NULL,
9466134Scasper KLPDARG_VNODE, vp, (char *)NULL, KLPDARG_NOMORE));
9470Sstevel@tonic-gate }
9480Sstevel@tonic-gate return (0);
9490Sstevel@tonic-gate }
9500Sstevel@tonic-gate
9510Sstevel@tonic-gate /*
95212273SCasper.Dik@Sun.COM * Like secpolicy_vnode_access() but we get the actual wanted mode and the
95312273SCasper.Dik@Sun.COM * current mode of the file, not the missing bits.
95412273SCasper.Dik@Sun.COM */
95512273SCasper.Dik@Sun.COM int
secpolicy_vnode_access2(const cred_t * cr,vnode_t * vp,uid_t owner,mode_t curmode,mode_t wantmode)95612273SCasper.Dik@Sun.COM secpolicy_vnode_access2(const cred_t *cr, vnode_t *vp, uid_t owner,
95712273SCasper.Dik@Sun.COM mode_t curmode, mode_t wantmode)
95812273SCasper.Dik@Sun.COM {
95912273SCasper.Dik@Sun.COM mode_t mode;
96012273SCasper.Dik@Sun.COM
96112273SCasper.Dik@Sun.COM /* Inline the basic privileges tests. */
96212273SCasper.Dik@Sun.COM if ((wantmode & VREAD) &&
96312273SCasper.Dik@Sun.COM !PRIV_ISASSERT(&CR_OEPRIV(cr), PRIV_FILE_READ) &&
96412273SCasper.Dik@Sun.COM priv_policy_va(cr, PRIV_FILE_READ, B_FALSE, EACCES, NULL,
96512273SCasper.Dik@Sun.COM KLPDARG_VNODE, vp, (char *)NULL, KLPDARG_NOMORE) != 0) {
96612273SCasper.Dik@Sun.COM return (EACCES);
96712273SCasper.Dik@Sun.COM }
96812273SCasper.Dik@Sun.COM
96912273SCasper.Dik@Sun.COM if ((wantmode & VWRITE) &&
97012273SCasper.Dik@Sun.COM !PRIV_ISASSERT(&CR_OEPRIV(cr), PRIV_FILE_WRITE) &&
97112273SCasper.Dik@Sun.COM priv_policy_va(cr, PRIV_FILE_WRITE, B_FALSE, EACCES, NULL,
97212273SCasper.Dik@Sun.COM KLPDARG_VNODE, vp, (char *)NULL, KLPDARG_NOMORE) != 0) {
97312273SCasper.Dik@Sun.COM return (EACCES);
97412273SCasper.Dik@Sun.COM }
97512273SCasper.Dik@Sun.COM
97612273SCasper.Dik@Sun.COM mode = ~curmode & wantmode;
97712273SCasper.Dik@Sun.COM
97812273SCasper.Dik@Sun.COM if (mode == 0)
97912273SCasper.Dik@Sun.COM return (0);
98012273SCasper.Dik@Sun.COM
98112273SCasper.Dik@Sun.COM if ((mode & VREAD) && priv_policy_va(cr, PRIV_FILE_DAC_READ, B_FALSE,
98212273SCasper.Dik@Sun.COM EACCES, NULL, KLPDARG_VNODE, vp, (char *)NULL,
98312273SCasper.Dik@Sun.COM KLPDARG_NOMORE) != 0) {
98412273SCasper.Dik@Sun.COM return (EACCES);
98512273SCasper.Dik@Sun.COM }
98612273SCasper.Dik@Sun.COM
98712273SCasper.Dik@Sun.COM if (mode & VWRITE) {
98812273SCasper.Dik@Sun.COM boolean_t allzone;
98912273SCasper.Dik@Sun.COM
99012273SCasper.Dik@Sun.COM if (owner == 0 && cr->cr_uid != 0)
99112273SCasper.Dik@Sun.COM allzone = B_TRUE;
99212273SCasper.Dik@Sun.COM else
99312273SCasper.Dik@Sun.COM allzone = B_FALSE;
99412273SCasper.Dik@Sun.COM if (priv_policy_va(cr, PRIV_FILE_DAC_WRITE, allzone, EACCES,
99512273SCasper.Dik@Sun.COM NULL, KLPDARG_VNODE, vp, (char *)NULL,
99612273SCasper.Dik@Sun.COM KLPDARG_NOMORE) != 0) {
99712273SCasper.Dik@Sun.COM return (EACCES);
99812273SCasper.Dik@Sun.COM }
99912273SCasper.Dik@Sun.COM }
100012273SCasper.Dik@Sun.COM
100112273SCasper.Dik@Sun.COM if (mode & VEXEC) {
100212273SCasper.Dik@Sun.COM /*
100312273SCasper.Dik@Sun.COM * Directories use file_dac_search to override the execute bit.
100412273SCasper.Dik@Sun.COM */
100512273SCasper.Dik@Sun.COM int p = vp->v_type == VDIR ? PRIV_FILE_DAC_SEARCH :
100612273SCasper.Dik@Sun.COM PRIV_FILE_DAC_EXECUTE;
100712273SCasper.Dik@Sun.COM
100812273SCasper.Dik@Sun.COM return (priv_policy_va(cr, p, B_FALSE, EACCES, NULL,
100912273SCasper.Dik@Sun.COM KLPDARG_VNODE, vp, (char *)NULL, KLPDARG_NOMORE));
101012273SCasper.Dik@Sun.COM }
101112273SCasper.Dik@Sun.COM return (0);
101212273SCasper.Dik@Sun.COM }
101312273SCasper.Dik@Sun.COM
101412273SCasper.Dik@Sun.COM /*
101512273SCasper.Dik@Sun.COM * This is a special routine for ZFS; it is used to determine whether
101612273SCasper.Dik@Sun.COM * any of the privileges in effect allow any form of access to the
101712273SCasper.Dik@Sun.COM * file. There's no reason to audit this or any reason to record
101812273SCasper.Dik@Sun.COM * this. More work is needed to do the "KPLD" stuff.
101912273SCasper.Dik@Sun.COM */
102012273SCasper.Dik@Sun.COM int
secpolicy_vnode_any_access(const cred_t * cr,vnode_t * vp,uid_t owner)102112273SCasper.Dik@Sun.COM secpolicy_vnode_any_access(const cred_t *cr, vnode_t *vp, uid_t owner)
102212273SCasper.Dik@Sun.COM {
102312273SCasper.Dik@Sun.COM static int privs[] = {
102412273SCasper.Dik@Sun.COM PRIV_FILE_OWNER,
102512484SCasper.Dik@Sun.COM PRIV_FILE_CHOWN,
102612273SCasper.Dik@Sun.COM PRIV_FILE_DAC_READ,
102712273SCasper.Dik@Sun.COM PRIV_FILE_DAC_WRITE,
102812273SCasper.Dik@Sun.COM PRIV_FILE_DAC_EXECUTE,
102912273SCasper.Dik@Sun.COM PRIV_FILE_DAC_SEARCH,
103012273SCasper.Dik@Sun.COM };
103112273SCasper.Dik@Sun.COM int i;
103212273SCasper.Dik@Sun.COM
103312273SCasper.Dik@Sun.COM /* Same as secpolicy_vnode_setdac */
103412273SCasper.Dik@Sun.COM if (owner == cr->cr_uid)
103512273SCasper.Dik@Sun.COM return (0);
103612273SCasper.Dik@Sun.COM
103712273SCasper.Dik@Sun.COM for (i = 0; i < sizeof (privs)/sizeof (int); i++) {
103812273SCasper.Dik@Sun.COM boolean_t allzone = B_FALSE;
103912273SCasper.Dik@Sun.COM int priv;
104012273SCasper.Dik@Sun.COM
104112273SCasper.Dik@Sun.COM switch (priv = privs[i]) {
104212273SCasper.Dik@Sun.COM case PRIV_FILE_DAC_EXECUTE:
104312273SCasper.Dik@Sun.COM if (vp->v_type == VDIR)
104412273SCasper.Dik@Sun.COM continue;
104512273SCasper.Dik@Sun.COM break;
104612273SCasper.Dik@Sun.COM case PRIV_FILE_DAC_SEARCH:
104712273SCasper.Dik@Sun.COM if (vp->v_type != VDIR)
104812273SCasper.Dik@Sun.COM continue;
104912273SCasper.Dik@Sun.COM break;
105012273SCasper.Dik@Sun.COM case PRIV_FILE_DAC_WRITE:
105112273SCasper.Dik@Sun.COM case PRIV_FILE_OWNER:
105212484SCasper.Dik@Sun.COM case PRIV_FILE_CHOWN:
105312273SCasper.Dik@Sun.COM /* We know here that if owner == 0, that cr_uid != 0 */
105412273SCasper.Dik@Sun.COM allzone = owner == 0;
105512273SCasper.Dik@Sun.COM break;
105612273SCasper.Dik@Sun.COM }
105712273SCasper.Dik@Sun.COM if (PRIV_POLICY_CHOICE(cr, priv, allzone))
105812273SCasper.Dik@Sun.COM return (0);
105912273SCasper.Dik@Sun.COM }
106012273SCasper.Dik@Sun.COM return (EPERM);
106112273SCasper.Dik@Sun.COM }
106212273SCasper.Dik@Sun.COM
106312273SCasper.Dik@Sun.COM /*
10640Sstevel@tonic-gate * Name: secpolicy_vnode_setid_modify()
10650Sstevel@tonic-gate *
10660Sstevel@tonic-gate * Normal: verify that subject can set the file setid flags.
10670Sstevel@tonic-gate *
10680Sstevel@tonic-gate * Output: EPERM - if not privileged.
10690Sstevel@tonic-gate */
10700Sstevel@tonic-gate
10710Sstevel@tonic-gate static int
secpolicy_vnode_setid_modify(const cred_t * cr,uid_t owner)10720Sstevel@tonic-gate secpolicy_vnode_setid_modify(const cred_t *cr, uid_t owner)
10730Sstevel@tonic-gate {
10740Sstevel@tonic-gate /* If changing to suid root, must have all zone privs */
10750Sstevel@tonic-gate boolean_t allzone = B_TRUE;
10760Sstevel@tonic-gate
10770Sstevel@tonic-gate if (owner != 0) {
10780Sstevel@tonic-gate if (owner == cr->cr_uid)
10790Sstevel@tonic-gate return (0);
10800Sstevel@tonic-gate allzone = B_FALSE;
10810Sstevel@tonic-gate }
10820Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_FILE_SETID, allzone, EPERM, NULL));
10830Sstevel@tonic-gate }
10840Sstevel@tonic-gate
10850Sstevel@tonic-gate /*
10860Sstevel@tonic-gate * Are we allowed to retain the set-uid/set-gid bits when
10870Sstevel@tonic-gate * changing ownership or when writing to a file?
10880Sstevel@tonic-gate * "issuid" should be true when set-uid; only in that case
10890Sstevel@tonic-gate * root ownership is checked (setgid is assumed).
10900Sstevel@tonic-gate */
10910Sstevel@tonic-gate int
secpolicy_vnode_setid_retain(const cred_t * cred,boolean_t issuidroot)10920Sstevel@tonic-gate secpolicy_vnode_setid_retain(const cred_t *cred, boolean_t issuidroot)
10930Sstevel@tonic-gate {
10940Sstevel@tonic-gate if (issuidroot && !HAS_ALLZONEPRIVS(cred))
10950Sstevel@tonic-gate return (EPERM);
10960Sstevel@tonic-gate
10970Sstevel@tonic-gate return (!PRIV_POLICY_CHOICE(cred, PRIV_FILE_SETID, B_FALSE));
10980Sstevel@tonic-gate }
10990Sstevel@tonic-gate
11000Sstevel@tonic-gate /*
11010Sstevel@tonic-gate * Name: secpolicy_vnode_setids_setgids()
11020Sstevel@tonic-gate *
11030Sstevel@tonic-gate * Normal: verify that subject can set the file setgid flag.
11040Sstevel@tonic-gate *
11050Sstevel@tonic-gate * Output: EPERM - if not privileged
11060Sstevel@tonic-gate */
11070Sstevel@tonic-gate
11080Sstevel@tonic-gate int
secpolicy_vnode_setids_setgids(const cred_t * cred,gid_t gid)11090Sstevel@tonic-gate secpolicy_vnode_setids_setgids(const cred_t *cred, gid_t gid)
11100Sstevel@tonic-gate {
11110Sstevel@tonic-gate if (!groupmember(gid, cred))
11120Sstevel@tonic-gate return (PRIV_POLICY(cred, PRIV_FILE_SETID, B_FALSE, EPERM,
11130Sstevel@tonic-gate NULL));
11140Sstevel@tonic-gate return (0);
11150Sstevel@tonic-gate }
11160Sstevel@tonic-gate
11170Sstevel@tonic-gate /*
11187624SMark.Shellenbaum@Sun.COM * Name: secpolicy_vnode_chown
11197624SMark.Shellenbaum@Sun.COM *
11207624SMark.Shellenbaum@Sun.COM * Normal: Determine if subject can chown owner of a file.
11217624SMark.Shellenbaum@Sun.COM *
11227624SMark.Shellenbaum@Sun.COM * Output: EPERM - if access denied
11237624SMark.Shellenbaum@Sun.COM */
11247624SMark.Shellenbaum@Sun.COM
11257624SMark.Shellenbaum@Sun.COM int
secpolicy_vnode_chown(const cred_t * cred,uid_t owner)11269866SMark.Shellenbaum@Sun.COM secpolicy_vnode_chown(const cred_t *cred, uid_t owner)
11277624SMark.Shellenbaum@Sun.COM {
11289866SMark.Shellenbaum@Sun.COM boolean_t is_owner = (owner == crgetuid(cred));
11299866SMark.Shellenbaum@Sun.COM boolean_t allzone = B_FALSE;
11309866SMark.Shellenbaum@Sun.COM int priv;
11319866SMark.Shellenbaum@Sun.COM
11329866SMark.Shellenbaum@Sun.COM if (!is_owner) {
11339866SMark.Shellenbaum@Sun.COM allzone = (owner == 0);
11349866SMark.Shellenbaum@Sun.COM priv = PRIV_FILE_CHOWN;
11359866SMark.Shellenbaum@Sun.COM } else {
11369866SMark.Shellenbaum@Sun.COM priv = HAS_PRIVILEGE(cred, PRIV_FILE_CHOWN) ?
11379866SMark.Shellenbaum@Sun.COM PRIV_FILE_CHOWN : PRIV_FILE_CHOWN_SELF;
11389866SMark.Shellenbaum@Sun.COM }
11399866SMark.Shellenbaum@Sun.COM
11409866SMark.Shellenbaum@Sun.COM return (PRIV_POLICY(cred, priv, allzone, EPERM, NULL));
11417624SMark.Shellenbaum@Sun.COM }
11427624SMark.Shellenbaum@Sun.COM
11437624SMark.Shellenbaum@Sun.COM /*
11447624SMark.Shellenbaum@Sun.COM * Name: secpolicy_vnode_create_gid
11457624SMark.Shellenbaum@Sun.COM *
11467624SMark.Shellenbaum@Sun.COM * Normal: Determine if subject can change group ownership of a file.
11477624SMark.Shellenbaum@Sun.COM *
11487624SMark.Shellenbaum@Sun.COM * Output: EPERM - if access denied
11490Sstevel@tonic-gate */
11500Sstevel@tonic-gate int
secpolicy_vnode_create_gid(const cred_t * cred)11510Sstevel@tonic-gate secpolicy_vnode_create_gid(const cred_t *cred)
11520Sstevel@tonic-gate {
11539866SMark.Shellenbaum@Sun.COM if (HAS_PRIVILEGE(cred, PRIV_FILE_CHOWN))
11549866SMark.Shellenbaum@Sun.COM return (PRIV_POLICY(cred, PRIV_FILE_CHOWN, B_FALSE, EPERM,
11559866SMark.Shellenbaum@Sun.COM NULL));
11569866SMark.Shellenbaum@Sun.COM else
11579866SMark.Shellenbaum@Sun.COM return (PRIV_POLICY(cred, PRIV_FILE_CHOWN_SELF, B_FALSE, EPERM,
11589866SMark.Shellenbaum@Sun.COM NULL));
11590Sstevel@tonic-gate }
11600Sstevel@tonic-gate
11610Sstevel@tonic-gate /*
11620Sstevel@tonic-gate * Name: secpolicy_vnode_utime_modify()
11630Sstevel@tonic-gate *
11640Sstevel@tonic-gate * Normal: verify that subject can modify the utime on a file.
11650Sstevel@tonic-gate *
11660Sstevel@tonic-gate * Output: EPERM - if access denied.
11670Sstevel@tonic-gate */
11680Sstevel@tonic-gate
11690Sstevel@tonic-gate static int
secpolicy_vnode_utime_modify(const cred_t * cred)11700Sstevel@tonic-gate secpolicy_vnode_utime_modify(const cred_t *cred)
11710Sstevel@tonic-gate {
11720Sstevel@tonic-gate return (PRIV_POLICY(cred, PRIV_FILE_OWNER, B_FALSE, EPERM,
11730Sstevel@tonic-gate "modify file times"));
11740Sstevel@tonic-gate }
11750Sstevel@tonic-gate
11760Sstevel@tonic-gate
11770Sstevel@tonic-gate /*
11780Sstevel@tonic-gate * Name: secpolicy_vnode_setdac()
11790Sstevel@tonic-gate *
11800Sstevel@tonic-gate * Normal: verify that subject can modify the mode of a file.
11810Sstevel@tonic-gate * allzone privilege needed when modifying root owned object.
11820Sstevel@tonic-gate *
11830Sstevel@tonic-gate * Output: EPERM - if access denied.
11840Sstevel@tonic-gate */
11850Sstevel@tonic-gate
11860Sstevel@tonic-gate int
secpolicy_vnode_setdac(const cred_t * cred,uid_t owner)11870Sstevel@tonic-gate secpolicy_vnode_setdac(const cred_t *cred, uid_t owner)
11880Sstevel@tonic-gate {
11890Sstevel@tonic-gate if (owner == cred->cr_uid)
11900Sstevel@tonic-gate return (0);
11910Sstevel@tonic-gate
11920Sstevel@tonic-gate return (PRIV_POLICY(cred, PRIV_FILE_OWNER, owner == 0, EPERM, NULL));
11930Sstevel@tonic-gate }
11940Sstevel@tonic-gate /*
11950Sstevel@tonic-gate * Name: secpolicy_vnode_stky_modify()
11960Sstevel@tonic-gate *
11970Sstevel@tonic-gate * Normal: verify that subject can make a file a "sticky".
11980Sstevel@tonic-gate *
11990Sstevel@tonic-gate * Output: EPERM - if access denied.
12000Sstevel@tonic-gate */
12010Sstevel@tonic-gate
12020Sstevel@tonic-gate int
secpolicy_vnode_stky_modify(const cred_t * cred)12030Sstevel@tonic-gate secpolicy_vnode_stky_modify(const cred_t *cred)
12040Sstevel@tonic-gate {
12050Sstevel@tonic-gate return (PRIV_POLICY(cred, PRIV_SYS_CONFIG, B_FALSE, EPERM,
12060Sstevel@tonic-gate "set file sticky"));
12070Sstevel@tonic-gate }
12080Sstevel@tonic-gate
12090Sstevel@tonic-gate /*
12100Sstevel@tonic-gate * Policy determines whether we can remove an entry from a directory,
12110Sstevel@tonic-gate * regardless of permission bits.
12120Sstevel@tonic-gate */
12130Sstevel@tonic-gate int
secpolicy_vnode_remove(const cred_t * cr)12140Sstevel@tonic-gate secpolicy_vnode_remove(const cred_t *cr)
12150Sstevel@tonic-gate {
12160Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_FILE_OWNER, B_FALSE, EACCES,
12170Sstevel@tonic-gate "sticky directory"));
12180Sstevel@tonic-gate }
12190Sstevel@tonic-gate
12200Sstevel@tonic-gate int
secpolicy_vnode_owner(const cred_t * cr,uid_t owner)12210Sstevel@tonic-gate secpolicy_vnode_owner(const cred_t *cr, uid_t owner)
12220Sstevel@tonic-gate {
12230Sstevel@tonic-gate boolean_t allzone = (owner == 0);
12240Sstevel@tonic-gate
12250Sstevel@tonic-gate if (owner == cr->cr_uid)
12260Sstevel@tonic-gate return (0);
12270Sstevel@tonic-gate
12280Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_FILE_OWNER, allzone, EPERM, NULL));
12290Sstevel@tonic-gate }
12300Sstevel@tonic-gate
12311115Smarks void
secpolicy_setid_clear(vattr_t * vap,cred_t * cr)12321115Smarks secpolicy_setid_clear(vattr_t *vap, cred_t *cr)
12331115Smarks {
12341115Smarks if ((vap->va_mode & (S_ISUID | S_ISGID)) != 0 &&
12351115Smarks secpolicy_vnode_setid_retain(cr,
12361115Smarks (vap->va_mode & S_ISUID) != 0 &&
12371115Smarks (vap->va_mask & AT_UID) != 0 && vap->va_uid == 0) != 0) {
12381115Smarks vap->va_mask |= AT_MODE;
12391115Smarks vap->va_mode &= ~(S_ISUID|S_ISGID);
12401115Smarks }
12411115Smarks }
12421115Smarks
12432796Smarks int
secpolicy_setid_setsticky_clear(vnode_t * vp,vattr_t * vap,const vattr_t * ovap,cred_t * cr)12442796Smarks secpolicy_setid_setsticky_clear(vnode_t *vp, vattr_t *vap, const vattr_t *ovap,
12452796Smarks cred_t *cr)
12462796Smarks {
12472796Smarks int error;
12482796Smarks
12492796Smarks if ((vap->va_mode & S_ISUID) != 0 &&
12502796Smarks (error = secpolicy_vnode_setid_modify(cr,
12512796Smarks ovap->va_uid)) != 0) {
12522796Smarks return (error);
12532796Smarks }
12542796Smarks
12552796Smarks /*
12562796Smarks * Check privilege if attempting to set the
12572796Smarks * sticky bit on a non-directory.
12582796Smarks */
12592796Smarks if (vp->v_type != VDIR && (vap->va_mode & S_ISVTX) != 0 &&
12602796Smarks secpolicy_vnode_stky_modify(cr) != 0) {
12614543Smarks vap->va_mode &= ~S_ISVTX;
12622796Smarks }
12632796Smarks
12642796Smarks /*
12652796Smarks * Check for privilege if attempting to set the
12662796Smarks * group-id bit.
12672796Smarks */
12682796Smarks if ((vap->va_mode & S_ISGID) != 0 &&
12692796Smarks secpolicy_vnode_setids_setgids(cr, ovap->va_gid) != 0) {
12704543Smarks vap->va_mode &= ~S_ISGID;
12712796Smarks }
12722796Smarks
12732796Smarks return (0);
12742796Smarks }
12752796Smarks
12765331Samw #define ATTR_FLAG_PRIV(attr, value, cr) \
12775331Samw PRIV_POLICY(cr, value ? PRIV_FILE_FLAG_SET : PRIV_ALL, \
12785331Samw B_FALSE, EPERM, NULL)
12795331Samw
12805331Samw /*
12815331Samw * Check privileges for setting xvattr attributes
12825331Samw */
12835331Samw int
secpolicy_xvattr(xvattr_t * xvap,uid_t owner,cred_t * cr,vtype_t vtype)12845331Samw secpolicy_xvattr(xvattr_t *xvap, uid_t owner, cred_t *cr, vtype_t vtype)
12855331Samw {
12865331Samw xoptattr_t *xoap;
12875331Samw int error = 0;
12885331Samw
12895331Samw if ((xoap = xva_getxoptattr(xvap)) == NULL)
12905331Samw return (EINVAL);
12915331Samw
12925331Samw /*
12935331Samw * First process the DOS bits
12945331Samw */
12955331Samw if (XVA_ISSET_REQ(xvap, XAT_ARCHIVE) ||
12965331Samw XVA_ISSET_REQ(xvap, XAT_HIDDEN) ||
12975331Samw XVA_ISSET_REQ(xvap, XAT_READONLY) ||
12985331Samw XVA_ISSET_REQ(xvap, XAT_SYSTEM) ||
1299*13082SJoyce.McIntosh@Sun.COM XVA_ISSET_REQ(xvap, XAT_CREATETIME) ||
1300*13082SJoyce.McIntosh@Sun.COM XVA_ISSET_REQ(xvap, XAT_OFFLINE) ||
1301*13082SJoyce.McIntosh@Sun.COM XVA_ISSET_REQ(xvap, XAT_SPARSE)) {
13025331Samw if ((error = secpolicy_vnode_owner(cr, owner)) != 0)
13035331Samw return (error);
13045331Samw }
13055331Samw
13065331Samw /*
13075331Samw * Now handle special attributes
13085331Samw */
13095331Samw
13105331Samw if (XVA_ISSET_REQ(xvap, XAT_IMMUTABLE))
13115331Samw error = ATTR_FLAG_PRIV(XAT_IMMUTABLE,
13125331Samw xoap->xoa_immutable, cr);
13135331Samw if (error == 0 && XVA_ISSET_REQ(xvap, XAT_NOUNLINK))
13145331Samw error = ATTR_FLAG_PRIV(XAT_NOUNLINK,
13155331Samw xoap->xoa_nounlink, cr);
13165331Samw if (error == 0 && XVA_ISSET_REQ(xvap, XAT_APPENDONLY))
13175331Samw error = ATTR_FLAG_PRIV(XAT_APPENDONLY,
13185331Samw xoap->xoa_appendonly, cr);
13195331Samw if (error == 0 && XVA_ISSET_REQ(xvap, XAT_NODUMP))
13205331Samw error = ATTR_FLAG_PRIV(XAT_NODUMP,
13215331Samw xoap->xoa_nodump, cr);
13225331Samw if (error == 0 && XVA_ISSET_REQ(xvap, XAT_OPAQUE))
13235331Samw error = EPERM;
13245331Samw if (error == 0 && XVA_ISSET_REQ(xvap, XAT_AV_QUARANTINED)) {
13255331Samw error = ATTR_FLAG_PRIV(XAT_AV_QUARANTINED,
13265331Samw xoap->xoa_av_quarantined, cr);
13275545Smarks if (error == 0 && vtype != VREG && xoap->xoa_av_quarantined)
13285331Samw error = EINVAL;
13295331Samw }
13305331Samw if (error == 0 && XVA_ISSET_REQ(xvap, XAT_AV_MODIFIED))
13315331Samw error = ATTR_FLAG_PRIV(XAT_AV_MODIFIED,
13325331Samw xoap->xoa_av_modified, cr);
13335331Samw if (error == 0 && XVA_ISSET_REQ(xvap, XAT_AV_SCANSTAMP)) {
13345331Samw error = ATTR_FLAG_PRIV(XAT_AV_SCANSTAMP,
13355331Samw xoap->xoa_av_scanstamp, cr);
13365331Samw if (error == 0 && vtype != VREG)
13375331Samw error = EINVAL;
13385331Samw }
13395331Samw return (error);
13405331Samw }
13415331Samw
13420Sstevel@tonic-gate /*
13430Sstevel@tonic-gate * This function checks the policy decisions surrounding the
13440Sstevel@tonic-gate * vop setattr call.
13450Sstevel@tonic-gate *
13460Sstevel@tonic-gate * It should be called after sufficient locks have been established
13470Sstevel@tonic-gate * on the underlying data structures. No concurrent modifications
13480Sstevel@tonic-gate * should be allowed.
13490Sstevel@tonic-gate *
13500Sstevel@tonic-gate * The caller must pass in unlocked version of its vaccess function
13510Sstevel@tonic-gate * this is required because vop_access function should lock the
13520Sstevel@tonic-gate * node for reading. A three argument function should be defined
13530Sstevel@tonic-gate * which accepts the following argument:
13540Sstevel@tonic-gate * A pointer to the internal "node" type (inode *)
13550Sstevel@tonic-gate * vnode access bits (VREAD|VWRITE|VEXEC)
13560Sstevel@tonic-gate * a pointer to the credential
13570Sstevel@tonic-gate *
13580Sstevel@tonic-gate * This function makes the following policy decisions:
13590Sstevel@tonic-gate *
13600Sstevel@tonic-gate * - change permissions
13610Sstevel@tonic-gate * - permission to change file mode if not owner
13620Sstevel@tonic-gate * - permission to add sticky bit to non-directory
13630Sstevel@tonic-gate * - permission to add set-gid bit
13640Sstevel@tonic-gate *
13650Sstevel@tonic-gate * The ovap argument should include AT_MODE|AT_UID|AT_GID.
13660Sstevel@tonic-gate *
13670Sstevel@tonic-gate * If the vap argument does not include AT_MODE, the mode will be copied from
13680Sstevel@tonic-gate * ovap. In certain situations set-uid/set-gid bits need to be removed;
13690Sstevel@tonic-gate * this is done by marking vap->va_mask to include AT_MODE and va_mode
13700Sstevel@tonic-gate * is updated to the newly computed mode.
13710Sstevel@tonic-gate */
13720Sstevel@tonic-gate
13730Sstevel@tonic-gate int
secpolicy_vnode_setattr(cred_t * cr,struct vnode * vp,struct vattr * vap,const struct vattr * ovap,int flags,int unlocked_access (void *,int,cred_t *),void * node)13740Sstevel@tonic-gate secpolicy_vnode_setattr(cred_t *cr, struct vnode *vp, struct vattr *vap,
13750Sstevel@tonic-gate const struct vattr *ovap, int flags,
13760Sstevel@tonic-gate int unlocked_access(void *, int, cred_t *),
13770Sstevel@tonic-gate void *node)
13780Sstevel@tonic-gate {
13790Sstevel@tonic-gate int mask = vap->va_mask;
13800Sstevel@tonic-gate int error = 0;
13815331Samw boolean_t skipaclchk = (flags & ATTR_NOACLCHECK) ? B_TRUE : B_FALSE;
13820Sstevel@tonic-gate
13830Sstevel@tonic-gate if (mask & AT_SIZE) {
13840Sstevel@tonic-gate if (vp->v_type == VDIR) {
13850Sstevel@tonic-gate error = EISDIR;
13860Sstevel@tonic-gate goto out;
13870Sstevel@tonic-gate }
13885331Samw
13895331Samw /*
13905331Samw * If ATTR_NOACLCHECK is set in the flags, then we don't
13915331Samw * perform the secondary unlocked_access() call since the
13925331Samw * ACL (if any) is being checked there.
13935331Samw */
13945331Samw if (skipaclchk == B_FALSE) {
13955331Samw error = unlocked_access(node, VWRITE, cr);
13965331Samw if (error)
13975331Samw goto out;
13985331Samw }
13990Sstevel@tonic-gate }
14000Sstevel@tonic-gate if (mask & AT_MODE) {
14010Sstevel@tonic-gate /*
14020Sstevel@tonic-gate * If not the owner of the file then check privilege
14030Sstevel@tonic-gate * for two things: the privilege to set the mode at all
14040Sstevel@tonic-gate * and, if we're setting setuid, we also need permissions
14050Sstevel@tonic-gate * to add the set-uid bit, if we're not the owner.
14060Sstevel@tonic-gate * In the specific case of creating a set-uid root
14070Sstevel@tonic-gate * file, we need even more permissions.
14080Sstevel@tonic-gate */
14090Sstevel@tonic-gate if ((error = secpolicy_vnode_setdac(cr, ovap->va_uid)) != 0)
14100Sstevel@tonic-gate goto out;
14110Sstevel@tonic-gate
14122796Smarks if ((error = secpolicy_setid_setsticky_clear(vp, vap,
14132796Smarks ovap, cr)) != 0)
14140Sstevel@tonic-gate goto out;
14150Sstevel@tonic-gate } else
14160Sstevel@tonic-gate vap->va_mode = ovap->va_mode;
14170Sstevel@tonic-gate
14180Sstevel@tonic-gate if (mask & (AT_UID|AT_GID)) {
14190Sstevel@tonic-gate boolean_t checkpriv = B_FALSE;
14200Sstevel@tonic-gate
14210Sstevel@tonic-gate /*
14220Sstevel@tonic-gate * Chowning files.
14230Sstevel@tonic-gate *
14240Sstevel@tonic-gate * If you are the file owner:
14250Sstevel@tonic-gate * chown to other uid FILE_CHOWN_SELF
14260Sstevel@tonic-gate * chown to gid (non-member) FILE_CHOWN_SELF
14270Sstevel@tonic-gate * chown to gid (member) <none>
14280Sstevel@tonic-gate *
14290Sstevel@tonic-gate * Instead of PRIV_FILE_CHOWN_SELF, FILE_CHOWN is also
14300Sstevel@tonic-gate * acceptable but the first one is reported when debugging.
14310Sstevel@tonic-gate *
14320Sstevel@tonic-gate * If you are not the file owner:
14330Sstevel@tonic-gate * chown from root PRIV_FILE_CHOWN + zone
14340Sstevel@tonic-gate * chown from other to any PRIV_FILE_CHOWN
14350Sstevel@tonic-gate *
14360Sstevel@tonic-gate */
14370Sstevel@tonic-gate if (cr->cr_uid != ovap->va_uid) {
14380Sstevel@tonic-gate checkpriv = B_TRUE;
14390Sstevel@tonic-gate } else {
14400Sstevel@tonic-gate if (((mask & AT_UID) && vap->va_uid != ovap->va_uid) ||
14410Sstevel@tonic-gate ((mask & AT_GID) && vap->va_gid != ovap->va_gid &&
14420Sstevel@tonic-gate !groupmember(vap->va_gid, cr))) {
14430Sstevel@tonic-gate checkpriv = B_TRUE;
14440Sstevel@tonic-gate }
14450Sstevel@tonic-gate }
14460Sstevel@tonic-gate /*
14470Sstevel@tonic-gate * If necessary, check privilege to see if update can be done.
14480Sstevel@tonic-gate */
14490Sstevel@tonic-gate if (checkpriv &&
14509866SMark.Shellenbaum@Sun.COM (error = secpolicy_vnode_chown(cr, ovap->va_uid)) != 0) {
14510Sstevel@tonic-gate goto out;
14520Sstevel@tonic-gate }
14530Sstevel@tonic-gate
14540Sstevel@tonic-gate /*
14550Sstevel@tonic-gate * If the file has either the set UID or set GID bits
14560Sstevel@tonic-gate * set and the caller can set the bits, then leave them.
14570Sstevel@tonic-gate */
14581115Smarks secpolicy_setid_clear(vap, cr);
14590Sstevel@tonic-gate }
14600Sstevel@tonic-gate if (mask & (AT_ATIME|AT_MTIME)) {
14610Sstevel@tonic-gate /*
14620Sstevel@tonic-gate * If not the file owner and not otherwise privileged,
14630Sstevel@tonic-gate * always return an error when setting the
14640Sstevel@tonic-gate * time other than the current (ATTR_UTIME flag set).
14650Sstevel@tonic-gate * If setting the current time (ATTR_UTIME not set) then
14660Sstevel@tonic-gate * unlocked_access will check permissions according to policy.
14670Sstevel@tonic-gate */
14680Sstevel@tonic-gate if (cr->cr_uid != ovap->va_uid) {
14690Sstevel@tonic-gate if (flags & ATTR_UTIME)
14700Sstevel@tonic-gate error = secpolicy_vnode_utime_modify(cr);
14715331Samw else if (skipaclchk == B_FALSE) {
14720Sstevel@tonic-gate error = unlocked_access(node, VWRITE, cr);
14730Sstevel@tonic-gate if (error == EACCES &&
14740Sstevel@tonic-gate secpolicy_vnode_utime_modify(cr) == 0)
14750Sstevel@tonic-gate error = 0;
14760Sstevel@tonic-gate }
14770Sstevel@tonic-gate if (error)
14780Sstevel@tonic-gate goto out;
14790Sstevel@tonic-gate }
14800Sstevel@tonic-gate }
14815331Samw
14825331Samw /*
14835331Samw * Check for optional attributes here by checking the following:
14845331Samw */
14855331Samw if (mask & AT_XVATTR)
14865331Samw error = secpolicy_xvattr((xvattr_t *)vap, ovap->va_uid, cr,
14875331Samw vp->v_type);
14880Sstevel@tonic-gate out:
14890Sstevel@tonic-gate return (error);
14900Sstevel@tonic-gate }
14910Sstevel@tonic-gate
14920Sstevel@tonic-gate /*
14930Sstevel@tonic-gate * Name: secpolicy_pcfs_modify_bootpartition()
14940Sstevel@tonic-gate *
14950Sstevel@tonic-gate * Normal: verify that subject can modify a pcfs boot partition.
14960Sstevel@tonic-gate *
14970Sstevel@tonic-gate * Output: EACCES - if privilege check failed.
14980Sstevel@tonic-gate */
14990Sstevel@tonic-gate /*ARGSUSED*/
15000Sstevel@tonic-gate int
secpolicy_pcfs_modify_bootpartition(const cred_t * cred)15010Sstevel@tonic-gate secpolicy_pcfs_modify_bootpartition(const cred_t *cred)
15020Sstevel@tonic-gate {
15030Sstevel@tonic-gate return (PRIV_POLICY(cred, PRIV_ALL, B_FALSE, EACCES,
15040Sstevel@tonic-gate "modify pcfs boot partition"));
15050Sstevel@tonic-gate }
15060Sstevel@tonic-gate
15070Sstevel@tonic-gate /*
15080Sstevel@tonic-gate * System V IPC routines
15090Sstevel@tonic-gate */
15100Sstevel@tonic-gate int
secpolicy_ipc_owner(const cred_t * cr,const struct kipc_perm * ip)15110Sstevel@tonic-gate secpolicy_ipc_owner(const cred_t *cr, const struct kipc_perm *ip)
15120Sstevel@tonic-gate {
15130Sstevel@tonic-gate if (crgetzoneid(cr) != ip->ipc_zoneid ||
15140Sstevel@tonic-gate (cr->cr_uid != ip->ipc_uid && cr->cr_uid != ip->ipc_cuid)) {
15150Sstevel@tonic-gate boolean_t allzone = B_FALSE;
15160Sstevel@tonic-gate if (ip->ipc_uid == 0 || ip->ipc_cuid == 0)
15170Sstevel@tonic-gate allzone = B_TRUE;
15180Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_IPC_OWNER, allzone, EPERM, NULL));
15190Sstevel@tonic-gate }
15200Sstevel@tonic-gate return (0);
15210Sstevel@tonic-gate }
15220Sstevel@tonic-gate
15230Sstevel@tonic-gate int
secpolicy_ipc_config(const cred_t * cr)15240Sstevel@tonic-gate secpolicy_ipc_config(const cred_t *cr)
15250Sstevel@tonic-gate {
15260Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_IPC_CONFIG, B_FALSE, EPERM, NULL));
15270Sstevel@tonic-gate }
15280Sstevel@tonic-gate
15290Sstevel@tonic-gate int
secpolicy_ipc_access(const cred_t * cr,const struct kipc_perm * ip,mode_t mode)15300Sstevel@tonic-gate secpolicy_ipc_access(const cred_t *cr, const struct kipc_perm *ip, mode_t mode)
15310Sstevel@tonic-gate {
15320Sstevel@tonic-gate
15330Sstevel@tonic-gate boolean_t allzone = B_FALSE;
15340Sstevel@tonic-gate
15350Sstevel@tonic-gate ASSERT((mode & (MSG_R|MSG_W)) != 0);
15360Sstevel@tonic-gate
15370Sstevel@tonic-gate if ((mode & MSG_R) &&
15380Sstevel@tonic-gate PRIV_POLICY(cr, PRIV_IPC_DAC_READ, allzone, EACCES, NULL) != 0)
15390Sstevel@tonic-gate return (EACCES);
15400Sstevel@tonic-gate
15410Sstevel@tonic-gate if (mode & MSG_W) {
15420Sstevel@tonic-gate if (cr->cr_uid != 0 && (ip->ipc_uid == 0 || ip->ipc_cuid == 0))
15430Sstevel@tonic-gate allzone = B_TRUE;
15440Sstevel@tonic-gate
15450Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_IPC_DAC_WRITE, allzone, EACCES,
15460Sstevel@tonic-gate NULL));
15470Sstevel@tonic-gate }
15480Sstevel@tonic-gate return (0);
15490Sstevel@tonic-gate }
15500Sstevel@tonic-gate
15510Sstevel@tonic-gate int
secpolicy_rsm_access(const cred_t * cr,uid_t owner,mode_t mode)15520Sstevel@tonic-gate secpolicy_rsm_access(const cred_t *cr, uid_t owner, mode_t mode)
15530Sstevel@tonic-gate {
15540Sstevel@tonic-gate boolean_t allzone = B_FALSE;
15550Sstevel@tonic-gate
15560Sstevel@tonic-gate ASSERT((mode & (MSG_R|MSG_W)) != 0);
15570Sstevel@tonic-gate
15580Sstevel@tonic-gate if ((mode & MSG_R) &&
15590Sstevel@tonic-gate PRIV_POLICY(cr, PRIV_IPC_DAC_READ, allzone, EACCES, NULL) != 0)
15600Sstevel@tonic-gate return (EACCES);
15610Sstevel@tonic-gate
15620Sstevel@tonic-gate if (mode & MSG_W) {
15630Sstevel@tonic-gate if (cr->cr_uid != 0 && owner == 0)
15640Sstevel@tonic-gate allzone = B_TRUE;
15650Sstevel@tonic-gate
15660Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_IPC_DAC_WRITE, allzone, EACCES,
15670Sstevel@tonic-gate NULL));
15680Sstevel@tonic-gate }
15690Sstevel@tonic-gate return (0);
15700Sstevel@tonic-gate }
15710Sstevel@tonic-gate
15720Sstevel@tonic-gate /*
15730Sstevel@tonic-gate * Audit configuration.
15740Sstevel@tonic-gate */
15750Sstevel@tonic-gate int
secpolicy_audit_config(const cred_t * cr)15760Sstevel@tonic-gate secpolicy_audit_config(const cred_t *cr)
15770Sstevel@tonic-gate {
15780Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_AUDIT, B_FALSE, EPERM, NULL));
15790Sstevel@tonic-gate }
15800Sstevel@tonic-gate
15810Sstevel@tonic-gate /*
15820Sstevel@tonic-gate * Audit record generation.
15830Sstevel@tonic-gate */
15840Sstevel@tonic-gate int
secpolicy_audit_modify(const cred_t * cr)15850Sstevel@tonic-gate secpolicy_audit_modify(const cred_t *cr)
15860Sstevel@tonic-gate {
15870Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_PROC_AUDIT, B_FALSE, EPERM, NULL));
15880Sstevel@tonic-gate }
15890Sstevel@tonic-gate
15900Sstevel@tonic-gate /*
15910Sstevel@tonic-gate * Get audit attributes.
15920Sstevel@tonic-gate * Either PRIV_SYS_AUDIT or PRIV_PROC_AUDIT required; report the
15930Sstevel@tonic-gate * "Least" of the two privileges on error.
15940Sstevel@tonic-gate */
15950Sstevel@tonic-gate int
secpolicy_audit_getattr(const cred_t * cr,boolean_t checkonly)159612273SCasper.Dik@Sun.COM secpolicy_audit_getattr(const cred_t *cr, boolean_t checkonly)
15970Sstevel@tonic-gate {
159812273SCasper.Dik@Sun.COM int priv;
159912273SCasper.Dik@Sun.COM
160012273SCasper.Dik@Sun.COM if (PRIV_POLICY_ONLY(cr, PRIV_SYS_AUDIT, B_FALSE))
160112273SCasper.Dik@Sun.COM priv = PRIV_SYS_AUDIT;
160212273SCasper.Dik@Sun.COM else
160312273SCasper.Dik@Sun.COM priv = PRIV_PROC_AUDIT;
160412273SCasper.Dik@Sun.COM
160512273SCasper.Dik@Sun.COM if (checkonly)
160612273SCasper.Dik@Sun.COM return (!PRIV_POLICY_ONLY(cr, priv, B_FALSE));
160712273SCasper.Dik@Sun.COM else
160812273SCasper.Dik@Sun.COM return (PRIV_POLICY(cr, priv, B_FALSE, EPERM, NULL));
16090Sstevel@tonic-gate }
16100Sstevel@tonic-gate
16110Sstevel@tonic-gate
16120Sstevel@tonic-gate /*
16130Sstevel@tonic-gate * Locking physical memory
16140Sstevel@tonic-gate */
16150Sstevel@tonic-gate int
secpolicy_lock_memory(const cred_t * cr)16160Sstevel@tonic-gate secpolicy_lock_memory(const cred_t *cr)
16170Sstevel@tonic-gate {
16180Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_PROC_LOCK_MEMORY, B_FALSE, EPERM, NULL));
16190Sstevel@tonic-gate }
16200Sstevel@tonic-gate
16210Sstevel@tonic-gate /*
16220Sstevel@tonic-gate * Accounting (both acct(2) and exacct).
16230Sstevel@tonic-gate */
16240Sstevel@tonic-gate int
secpolicy_acct(const cred_t * cr)16250Sstevel@tonic-gate secpolicy_acct(const cred_t *cr)
16260Sstevel@tonic-gate {
16270Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_ACCT, B_FALSE, EPERM, NULL));
16280Sstevel@tonic-gate }
16290Sstevel@tonic-gate
16300Sstevel@tonic-gate /*
16310Sstevel@tonic-gate * Is this process privileged to change its uids at will?
16320Sstevel@tonic-gate * Uid 0 is still considered "special" and having the SETID
16330Sstevel@tonic-gate * privilege is not sufficient to get uid 0.
16340Sstevel@tonic-gate * Files are owned by root, so the privilege would give
16350Sstevel@tonic-gate * full access and euid 0 is still effective.
16360Sstevel@tonic-gate *
16370Sstevel@tonic-gate * If you have the privilege and euid 0 only then do you
16380Sstevel@tonic-gate * get the powers of root wrt uid 0.
16390Sstevel@tonic-gate *
16400Sstevel@tonic-gate * For gid manipulations, this is should be called with an
16410Sstevel@tonic-gate * uid of -1.
16420Sstevel@tonic-gate *
16430Sstevel@tonic-gate */
16440Sstevel@tonic-gate int
secpolicy_allow_setid(const cred_t * cr,uid_t newuid,boolean_t checkonly)16450Sstevel@tonic-gate secpolicy_allow_setid(const cred_t *cr, uid_t newuid, boolean_t checkonly)
16460Sstevel@tonic-gate {
16470Sstevel@tonic-gate boolean_t allzone = B_FALSE;
16480Sstevel@tonic-gate
16490Sstevel@tonic-gate if (newuid == 0 && cr->cr_uid != 0 && cr->cr_suid != 0 &&
16500Sstevel@tonic-gate cr->cr_ruid != 0) {
16510Sstevel@tonic-gate allzone = B_TRUE;
16520Sstevel@tonic-gate }
16530Sstevel@tonic-gate
16540Sstevel@tonic-gate return (checkonly ? !PRIV_POLICY_ONLY(cr, PRIV_PROC_SETID, allzone) :
16550Sstevel@tonic-gate PRIV_POLICY(cr, PRIV_PROC_SETID, allzone, EPERM, NULL));
16560Sstevel@tonic-gate }
16570Sstevel@tonic-gate
16580Sstevel@tonic-gate
16590Sstevel@tonic-gate /*
16600Sstevel@tonic-gate * Acting on a different process: if the mode is for writing,
16610Sstevel@tonic-gate * the restrictions are more severe. This is called after
16620Sstevel@tonic-gate * we've verified that the uids do not match.
16630Sstevel@tonic-gate */
16640Sstevel@tonic-gate int
secpolicy_proc_owner(const cred_t * scr,const cred_t * tcr,int mode)16650Sstevel@tonic-gate secpolicy_proc_owner(const cred_t *scr, const cred_t *tcr, int mode)
16660Sstevel@tonic-gate {
16670Sstevel@tonic-gate boolean_t allzone = B_FALSE;
16680Sstevel@tonic-gate
16690Sstevel@tonic-gate if ((mode & VWRITE) && scr->cr_uid != 0 &&
16700Sstevel@tonic-gate (tcr->cr_uid == 0 || tcr->cr_ruid == 0 || tcr->cr_suid == 0))
16710Sstevel@tonic-gate allzone = B_TRUE;
16720Sstevel@tonic-gate
16730Sstevel@tonic-gate return (PRIV_POLICY(scr, PRIV_PROC_OWNER, allzone, EPERM, NULL));
16740Sstevel@tonic-gate }
16750Sstevel@tonic-gate
16760Sstevel@tonic-gate int
secpolicy_proc_access(const cred_t * scr)16770Sstevel@tonic-gate secpolicy_proc_access(const cred_t *scr)
16780Sstevel@tonic-gate {
16790Sstevel@tonic-gate return (PRIV_POLICY(scr, PRIV_PROC_OWNER, B_FALSE, EACCES, NULL));
16800Sstevel@tonic-gate }
16810Sstevel@tonic-gate
16820Sstevel@tonic-gate int
secpolicy_proc_excl_open(const cred_t * scr)16830Sstevel@tonic-gate secpolicy_proc_excl_open(const cred_t *scr)
16840Sstevel@tonic-gate {
16850Sstevel@tonic-gate return (PRIV_POLICY(scr, PRIV_PROC_OWNER, B_FALSE, EBUSY, NULL));
16860Sstevel@tonic-gate }
16870Sstevel@tonic-gate
16880Sstevel@tonic-gate int
secpolicy_proc_zone(const cred_t * scr)16890Sstevel@tonic-gate secpolicy_proc_zone(const cred_t *scr)
16900Sstevel@tonic-gate {
16910Sstevel@tonic-gate return (PRIV_POLICY(scr, PRIV_PROC_ZONE, B_FALSE, EPERM, NULL));
16920Sstevel@tonic-gate }
16930Sstevel@tonic-gate
16940Sstevel@tonic-gate /*
16950Sstevel@tonic-gate * Destroying the system
16960Sstevel@tonic-gate */
16970Sstevel@tonic-gate
16980Sstevel@tonic-gate int
secpolicy_kmdb(const cred_t * scr)16990Sstevel@tonic-gate secpolicy_kmdb(const cred_t *scr)
17000Sstevel@tonic-gate {
17010Sstevel@tonic-gate return (PRIV_POLICY(scr, PRIV_ALL, B_FALSE, EPERM, NULL));
17020Sstevel@tonic-gate }
17030Sstevel@tonic-gate
17041414Scindi int
secpolicy_error_inject(const cred_t * scr)17051414Scindi secpolicy_error_inject(const cred_t *scr)
17061414Scindi {
17071414Scindi return (PRIV_POLICY(scr, PRIV_ALL, B_FALSE, EPERM, NULL));
17081414Scindi }
17091414Scindi
17100Sstevel@tonic-gate /*
17110Sstevel@tonic-gate * Processor sets, cpu configuration, resource pools.
17120Sstevel@tonic-gate */
17130Sstevel@tonic-gate int
secpolicy_pset(const cred_t * cr)17140Sstevel@tonic-gate secpolicy_pset(const cred_t *cr)
17150Sstevel@tonic-gate {
17160Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_RES_CONFIG, B_FALSE, EPERM, NULL));
17170Sstevel@tonic-gate }
17180Sstevel@tonic-gate
171912494Sgerald.jelinek@sun.com /*
172012494Sgerald.jelinek@sun.com * Processor set binding.
172112494Sgerald.jelinek@sun.com */
172212494Sgerald.jelinek@sun.com int
secpolicy_pbind(const cred_t * cr)172312494Sgerald.jelinek@sun.com secpolicy_pbind(const cred_t *cr)
172412494Sgerald.jelinek@sun.com {
172512494Sgerald.jelinek@sun.com if (PRIV_POLICY_ONLY(cr, PRIV_SYS_RES_CONFIG, B_FALSE))
172612494Sgerald.jelinek@sun.com return (secpolicy_pset(cr));
172712494Sgerald.jelinek@sun.com return (PRIV_POLICY(cr, PRIV_SYS_RES_BIND, B_FALSE, EPERM, NULL));
172812494Sgerald.jelinek@sun.com }
172912494Sgerald.jelinek@sun.com
17300Sstevel@tonic-gate int
secpolicy_ponline(const cred_t * cr)17310Sstevel@tonic-gate secpolicy_ponline(const cred_t *cr)
17320Sstevel@tonic-gate {
17330Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_RES_CONFIG, B_FALSE, EPERM, NULL));
17340Sstevel@tonic-gate }
17350Sstevel@tonic-gate
17360Sstevel@tonic-gate int
secpolicy_pool(const cred_t * cr)17370Sstevel@tonic-gate secpolicy_pool(const cred_t *cr)
17380Sstevel@tonic-gate {
17390Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_RES_CONFIG, B_FALSE, EPERM, NULL));
17400Sstevel@tonic-gate }
17410Sstevel@tonic-gate
17420Sstevel@tonic-gate int
secpolicy_blacklist(const cred_t * cr)17430Sstevel@tonic-gate secpolicy_blacklist(const cred_t *cr)
17440Sstevel@tonic-gate {
17450Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_RES_CONFIG, B_FALSE, EPERM, NULL));
17460Sstevel@tonic-gate }
17470Sstevel@tonic-gate
17480Sstevel@tonic-gate /*
17490Sstevel@tonic-gate * Catch all system configuration.
17500Sstevel@tonic-gate */
17510Sstevel@tonic-gate int
secpolicy_sys_config(const cred_t * cr,boolean_t checkonly)17520Sstevel@tonic-gate secpolicy_sys_config(const cred_t *cr, boolean_t checkonly)
17530Sstevel@tonic-gate {
17540Sstevel@tonic-gate if (checkonly) {
17550Sstevel@tonic-gate return (PRIV_POLICY_ONLY(cr, PRIV_SYS_CONFIG, B_FALSE) ? 0 :
17560Sstevel@tonic-gate EPERM);
17570Sstevel@tonic-gate } else {
17580Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_CONFIG, B_FALSE, EPERM, NULL));
17590Sstevel@tonic-gate }
17600Sstevel@tonic-gate }
17610Sstevel@tonic-gate
17620Sstevel@tonic-gate /*
17630Sstevel@tonic-gate * Zone administration (halt, reboot, etc.) from within zone.
17640Sstevel@tonic-gate */
17650Sstevel@tonic-gate int
secpolicy_zone_admin(const cred_t * cr,boolean_t checkonly)17660Sstevel@tonic-gate secpolicy_zone_admin(const cred_t *cr, boolean_t checkonly)
17670Sstevel@tonic-gate {
17680Sstevel@tonic-gate if (checkonly) {
17690Sstevel@tonic-gate return (PRIV_POLICY_ONLY(cr, PRIV_SYS_ADMIN, B_FALSE) ? 0 :
17700Sstevel@tonic-gate EPERM);
17710Sstevel@tonic-gate } else {
17720Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_ADMIN, B_FALSE, EPERM,
17730Sstevel@tonic-gate NULL));
17740Sstevel@tonic-gate }
17750Sstevel@tonic-gate }
17760Sstevel@tonic-gate
17770Sstevel@tonic-gate /*
17780Sstevel@tonic-gate * Zone configuration (create, halt, enter).
17790Sstevel@tonic-gate */
17800Sstevel@tonic-gate int
secpolicy_zone_config(const cred_t * cr)17810Sstevel@tonic-gate secpolicy_zone_config(const cred_t *cr)
17820Sstevel@tonic-gate {
17830Sstevel@tonic-gate /*
17840Sstevel@tonic-gate * Require all privileges to avoid possibility of privilege
17850Sstevel@tonic-gate * escalation.
17860Sstevel@tonic-gate */
178712273SCasper.Dik@Sun.COM return (secpolicy_require_set(cr, PRIV_FULLSET, NULL, KLPDARG_NONE));
17880Sstevel@tonic-gate }
17890Sstevel@tonic-gate
17900Sstevel@tonic-gate /*
17910Sstevel@tonic-gate * Various other system configuration calls
17920Sstevel@tonic-gate */
17930Sstevel@tonic-gate int
secpolicy_coreadm(const cred_t * cr)17940Sstevel@tonic-gate secpolicy_coreadm(const cred_t *cr)
17950Sstevel@tonic-gate {
17960Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_ADMIN, B_FALSE, EPERM, NULL));
17970Sstevel@tonic-gate }
17980Sstevel@tonic-gate
17990Sstevel@tonic-gate int
secpolicy_systeminfo(const cred_t * cr)18000Sstevel@tonic-gate secpolicy_systeminfo(const cred_t *cr)
18010Sstevel@tonic-gate {
18020Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_ADMIN, B_FALSE, EPERM, NULL));
18030Sstevel@tonic-gate }
18040Sstevel@tonic-gate
18050Sstevel@tonic-gate int
secpolicy_dispadm(const cred_t * cr)18060Sstevel@tonic-gate secpolicy_dispadm(const cred_t *cr)
18070Sstevel@tonic-gate {
18080Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_CONFIG, B_FALSE, EPERM, NULL));
18090Sstevel@tonic-gate }
18100Sstevel@tonic-gate
18110Sstevel@tonic-gate int
secpolicy_settime(const cred_t * cr)18120Sstevel@tonic-gate secpolicy_settime(const cred_t *cr)
18130Sstevel@tonic-gate {
18140Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_TIME, B_FALSE, EPERM, NULL));
18150Sstevel@tonic-gate }
18160Sstevel@tonic-gate
18170Sstevel@tonic-gate /*
18180Sstevel@tonic-gate * For realtime users: high resolution clock.
18190Sstevel@tonic-gate */
18200Sstevel@tonic-gate int
secpolicy_clock_highres(const cred_t * cr)18210Sstevel@tonic-gate secpolicy_clock_highres(const cred_t *cr)
18220Sstevel@tonic-gate {
18230Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_PROC_CLOCK_HIGHRES, B_FALSE, EPERM,
18240Sstevel@tonic-gate NULL));
18250Sstevel@tonic-gate }
18260Sstevel@tonic-gate
18270Sstevel@tonic-gate /*
18280Sstevel@tonic-gate * drv_priv() is documented as callable from interrupt context, not that
18290Sstevel@tonic-gate * anyone ever does, but still. No debugging or auditing can be done when
18300Sstevel@tonic-gate * it is called from interrupt context.
18310Sstevel@tonic-gate * returns 0 on succes, EPERM on failure.
18320Sstevel@tonic-gate */
18330Sstevel@tonic-gate int
drv_priv(cred_t * cr)18340Sstevel@tonic-gate drv_priv(cred_t *cr)
18350Sstevel@tonic-gate {
18360Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_DEVICES, B_FALSE, EPERM, NULL));
18370Sstevel@tonic-gate }
18380Sstevel@tonic-gate
18390Sstevel@tonic-gate int
secpolicy_sys_devices(const cred_t * cr)18400Sstevel@tonic-gate secpolicy_sys_devices(const cred_t *cr)
18410Sstevel@tonic-gate {
18420Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_DEVICES, B_FALSE, EPERM, NULL));
18430Sstevel@tonic-gate }
18440Sstevel@tonic-gate
18450Sstevel@tonic-gate int
secpolicy_excl_open(const cred_t * cr)18460Sstevel@tonic-gate secpolicy_excl_open(const cred_t *cr)
18470Sstevel@tonic-gate {
18480Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_DEVICES, B_FALSE, EBUSY, NULL));
18490Sstevel@tonic-gate }
18500Sstevel@tonic-gate
18510Sstevel@tonic-gate int
secpolicy_rctlsys(const cred_t * cr,boolean_t is_zone_rctl)18520Sstevel@tonic-gate secpolicy_rctlsys(const cred_t *cr, boolean_t is_zone_rctl)
18530Sstevel@tonic-gate {
18540Sstevel@tonic-gate /* zone.* rctls can only be set from the global zone */
18550Sstevel@tonic-gate if (is_zone_rctl && priv_policy_global(cr) != 0)
18560Sstevel@tonic-gate return (EPERM);
18570Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_RESOURCE, B_FALSE, EPERM, NULL));
18580Sstevel@tonic-gate }
18590Sstevel@tonic-gate
18600Sstevel@tonic-gate int
secpolicy_resource(const cred_t * cr)18610Sstevel@tonic-gate secpolicy_resource(const cred_t *cr)
18620Sstevel@tonic-gate {
18630Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_RESOURCE, B_FALSE, EPERM, NULL));
18640Sstevel@tonic-gate }
18650Sstevel@tonic-gate
186610154SStan.Studzinski@Sun.COM int
secpolicy_resource_anon_mem(const cred_t * cr)186710154SStan.Studzinski@Sun.COM secpolicy_resource_anon_mem(const cred_t *cr)
186810154SStan.Studzinski@Sun.COM {
186910154SStan.Studzinski@Sun.COM return (PRIV_POLICY_ONLY(cr, PRIV_SYS_RESOURCE, B_FALSE));
187010154SStan.Studzinski@Sun.COM }
187110154SStan.Studzinski@Sun.COM
18720Sstevel@tonic-gate /*
18730Sstevel@tonic-gate * Processes with a real uid of 0 escape any form of accounting, much
18740Sstevel@tonic-gate * like before.
18750Sstevel@tonic-gate */
18760Sstevel@tonic-gate int
secpolicy_newproc(const cred_t * cr)18770Sstevel@tonic-gate secpolicy_newproc(const cred_t *cr)
18780Sstevel@tonic-gate {
18790Sstevel@tonic-gate if (cr->cr_ruid == 0)
18800Sstevel@tonic-gate return (0);
18810Sstevel@tonic-gate
18820Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_RESOURCE, B_FALSE, EPERM, NULL));
18830Sstevel@tonic-gate }
18840Sstevel@tonic-gate
18850Sstevel@tonic-gate /*
18860Sstevel@tonic-gate * Networking
18870Sstevel@tonic-gate */
18880Sstevel@tonic-gate int
secpolicy_net_rawaccess(const cred_t * cr)18890Sstevel@tonic-gate secpolicy_net_rawaccess(const cred_t *cr)
18900Sstevel@tonic-gate {
18910Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_NET_RAWACCESS, B_FALSE, EACCES, NULL));
18920Sstevel@tonic-gate }
18930Sstevel@tonic-gate
189410639SDarren.Reed@Sun.COM int
secpolicy_net_observability(const cred_t * cr)189510639SDarren.Reed@Sun.COM secpolicy_net_observability(const cred_t *cr)
189610639SDarren.Reed@Sun.COM {
189710639SDarren.Reed@Sun.COM return (PRIV_POLICY(cr, PRIV_NET_OBSERVABILITY, B_FALSE, EACCES, NULL));
189810639SDarren.Reed@Sun.COM }
189910639SDarren.Reed@Sun.COM
19000Sstevel@tonic-gate /*
19010Sstevel@tonic-gate * Need this privilege for accessing the ICMP device
19020Sstevel@tonic-gate */
19030Sstevel@tonic-gate int
secpolicy_net_icmpaccess(const cred_t * cr)19040Sstevel@tonic-gate secpolicy_net_icmpaccess(const cred_t *cr)
19050Sstevel@tonic-gate {
19060Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_NET_ICMPACCESS, B_FALSE, EACCES, NULL));
19070Sstevel@tonic-gate }
19080Sstevel@tonic-gate
19090Sstevel@tonic-gate /*
19100Sstevel@tonic-gate * There are a few rare cases where the kernel generates ioctls() from
19110Sstevel@tonic-gate * interrupt context with a credential of kcred rather than NULL.
19120Sstevel@tonic-gate * In those cases, we take the safe and cheap test.
19130Sstevel@tonic-gate */
19140Sstevel@tonic-gate int
secpolicy_net_config(const cred_t * cr,boolean_t checkonly)19150Sstevel@tonic-gate secpolicy_net_config(const cred_t *cr, boolean_t checkonly)
19160Sstevel@tonic-gate {
19170Sstevel@tonic-gate if (checkonly) {
19180Sstevel@tonic-gate return (PRIV_POLICY_ONLY(cr, PRIV_SYS_NET_CONFIG, B_FALSE) ?
19190Sstevel@tonic-gate 0 : EPERM);
19200Sstevel@tonic-gate } else {
19210Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_NET_CONFIG, B_FALSE, EPERM,
19220Sstevel@tonic-gate NULL));
19230Sstevel@tonic-gate }
19240Sstevel@tonic-gate }
19250Sstevel@tonic-gate
19260Sstevel@tonic-gate
19270Sstevel@tonic-gate /*
19284962Sdh155122 * PRIV_SYS_NET_CONFIG is a superset of PRIV_SYS_IP_CONFIG.
19293448Sdh155122 *
19303448Sdh155122 * There are a few rare cases where the kernel generates ioctls() from
19313448Sdh155122 * interrupt context with a credential of kcred rather than NULL.
19323448Sdh155122 * In those cases, we take the safe and cheap test.
19333448Sdh155122 */
19343448Sdh155122 int
secpolicy_ip_config(const cred_t * cr,boolean_t checkonly)19353448Sdh155122 secpolicy_ip_config(const cred_t *cr, boolean_t checkonly)
19363448Sdh155122 {
19373448Sdh155122 if (PRIV_POLICY_ONLY(cr, PRIV_SYS_NET_CONFIG, B_FALSE))
19383448Sdh155122 return (secpolicy_net_config(cr, checkonly));
19393448Sdh155122
19403448Sdh155122 if (checkonly) {
19413448Sdh155122 return (PRIV_POLICY_ONLY(cr, PRIV_SYS_IP_CONFIG, B_FALSE) ?
19423448Sdh155122 0 : EPERM);
19433448Sdh155122 } else {
19443448Sdh155122 return (PRIV_POLICY(cr, PRIV_SYS_IP_CONFIG, B_FALSE, EPERM,
19453448Sdh155122 NULL));
19463448Sdh155122 }
19473448Sdh155122 }
19483448Sdh155122
19497408SSebastien.Roy@Sun.COM /*
19507408SSebastien.Roy@Sun.COM * PRIV_SYS_NET_CONFIG is a superset of PRIV_SYS_DL_CONFIG.
19517408SSebastien.Roy@Sun.COM */
19527408SSebastien.Roy@Sun.COM int
secpolicy_dl_config(const cred_t * cr)19537408SSebastien.Roy@Sun.COM secpolicy_dl_config(const cred_t *cr)
19547408SSebastien.Roy@Sun.COM {
19557408SSebastien.Roy@Sun.COM if (PRIV_POLICY_ONLY(cr, PRIV_SYS_NET_CONFIG, B_FALSE))
19567408SSebastien.Roy@Sun.COM return (secpolicy_net_config(cr, B_FALSE));
195710616SSebastien.Roy@Sun.COM return (PRIV_POLICY(cr, PRIV_SYS_DL_CONFIG, B_FALSE, EPERM, NULL));
19587408SSebastien.Roy@Sun.COM }
19597408SSebastien.Roy@Sun.COM
196010616SSebastien.Roy@Sun.COM /*
196110616SSebastien.Roy@Sun.COM * PRIV_SYS_DL_CONFIG is a superset of PRIV_SYS_IPTUN_CONFIG.
196210616SSebastien.Roy@Sun.COM */
196310616SSebastien.Roy@Sun.COM int
secpolicy_iptun_config(const cred_t * cr)196410616SSebastien.Roy@Sun.COM secpolicy_iptun_config(const cred_t *cr)
196510616SSebastien.Roy@Sun.COM {
196610616SSebastien.Roy@Sun.COM if (PRIV_POLICY_ONLY(cr, PRIV_SYS_NET_CONFIG, B_FALSE))
196710616SSebastien.Roy@Sun.COM return (secpolicy_net_config(cr, B_FALSE));
196810616SSebastien.Roy@Sun.COM if (PRIV_POLICY_ONLY(cr, PRIV_SYS_DL_CONFIG, B_FALSE))
196910616SSebastien.Roy@Sun.COM return (secpolicy_dl_config(cr));
197010616SSebastien.Roy@Sun.COM return (PRIV_POLICY(cr, PRIV_SYS_IPTUN_CONFIG, B_FALSE, EPERM, NULL));
197110616SSebastien.Roy@Sun.COM }
19723448Sdh155122
19733448Sdh155122 /*
19743448Sdh155122 * Map IP pseudo privileges to actual privileges.
19753448Sdh155122 * So we don't need to recompile IP when we change the privileges.
19763448Sdh155122 */
19773448Sdh155122 int
secpolicy_ip(const cred_t * cr,int netpriv,boolean_t checkonly)19783448Sdh155122 secpolicy_ip(const cred_t *cr, int netpriv, boolean_t checkonly)
19793448Sdh155122 {
19803448Sdh155122 int priv = PRIV_ALL;
19813448Sdh155122
19823448Sdh155122 switch (netpriv) {
19833448Sdh155122 case OP_CONFIG:
19843448Sdh155122 priv = PRIV_SYS_IP_CONFIG;
19853448Sdh155122 break;
19863448Sdh155122 case OP_RAW:
19873448Sdh155122 priv = PRIV_NET_RAWACCESS;
19883448Sdh155122 break;
19893448Sdh155122 case OP_PRIVPORT:
19903448Sdh155122 priv = PRIV_NET_PRIVADDR;
19913448Sdh155122 break;
19923448Sdh155122 }
19933448Sdh155122 ASSERT(priv != PRIV_ALL);
19943448Sdh155122 if (checkonly)
19953448Sdh155122 return (PRIV_POLICY_ONLY(cr, priv, B_FALSE) ? 0 : EPERM);
19963448Sdh155122 else
19973448Sdh155122 return (PRIV_POLICY(cr, priv, B_FALSE, EPERM, NULL));
19983448Sdh155122 }
19993448Sdh155122
20003448Sdh155122 /*
20010Sstevel@tonic-gate * Map network pseudo privileges to actual privileges.
20020Sstevel@tonic-gate * So we don't need to recompile IP when we change the privileges.
20030Sstevel@tonic-gate */
20040Sstevel@tonic-gate int
secpolicy_net(const cred_t * cr,int netpriv,boolean_t checkonly)20050Sstevel@tonic-gate secpolicy_net(const cred_t *cr, int netpriv, boolean_t checkonly)
20060Sstevel@tonic-gate {
20070Sstevel@tonic-gate int priv = PRIV_ALL;
20080Sstevel@tonic-gate
20090Sstevel@tonic-gate switch (netpriv) {
20100Sstevel@tonic-gate case OP_CONFIG:
20110Sstevel@tonic-gate priv = PRIV_SYS_NET_CONFIG;
20120Sstevel@tonic-gate break;
20130Sstevel@tonic-gate case OP_RAW:
20140Sstevel@tonic-gate priv = PRIV_NET_RAWACCESS;
20150Sstevel@tonic-gate break;
20160Sstevel@tonic-gate case OP_PRIVPORT:
20170Sstevel@tonic-gate priv = PRIV_NET_PRIVADDR;
20180Sstevel@tonic-gate break;
20190Sstevel@tonic-gate }
20200Sstevel@tonic-gate ASSERT(priv != PRIV_ALL);
20210Sstevel@tonic-gate if (checkonly)
20220Sstevel@tonic-gate return (PRIV_POLICY_ONLY(cr, priv, B_FALSE) ? 0 : EPERM);
20230Sstevel@tonic-gate else
20240Sstevel@tonic-gate return (PRIV_POLICY(cr, priv, B_FALSE, EPERM, NULL));
20250Sstevel@tonic-gate }
20260Sstevel@tonic-gate
20270Sstevel@tonic-gate /*
20280Sstevel@tonic-gate * Checks for operations that are either client-only or are used by
20290Sstevel@tonic-gate * both clients and servers.
20300Sstevel@tonic-gate */
20310Sstevel@tonic-gate int
secpolicy_nfs(const cred_t * cr)20320Sstevel@tonic-gate secpolicy_nfs(const cred_t *cr)
20330Sstevel@tonic-gate {
20340Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_NFS, B_FALSE, EPERM, NULL));
20350Sstevel@tonic-gate }
20360Sstevel@tonic-gate
20370Sstevel@tonic-gate /*
20380Sstevel@tonic-gate * Special case for opening rpcmod: have NFS privileges or network
20390Sstevel@tonic-gate * config privileges.
20400Sstevel@tonic-gate */
20410Sstevel@tonic-gate int
secpolicy_rpcmod_open(const cred_t * cr)20420Sstevel@tonic-gate secpolicy_rpcmod_open(const cred_t *cr)
20430Sstevel@tonic-gate {
20440Sstevel@tonic-gate if (PRIV_POLICY_ONLY(cr, PRIV_SYS_NFS, B_FALSE))
20450Sstevel@tonic-gate return (secpolicy_nfs(cr));
20460Sstevel@tonic-gate else
20470Sstevel@tonic-gate return (secpolicy_net_config(cr, NULL));
20480Sstevel@tonic-gate }
20490Sstevel@tonic-gate
20500Sstevel@tonic-gate int
secpolicy_chroot(const cred_t * cr)20510Sstevel@tonic-gate secpolicy_chroot(const cred_t *cr)
20520Sstevel@tonic-gate {
20530Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_PROC_CHROOT, B_FALSE, EPERM, NULL));
20540Sstevel@tonic-gate }
20550Sstevel@tonic-gate
20560Sstevel@tonic-gate int
secpolicy_tasksys(const cred_t * cr)20570Sstevel@tonic-gate secpolicy_tasksys(const cred_t *cr)
20580Sstevel@tonic-gate {
20590Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_PROC_TASKID, B_FALSE, EPERM, NULL));
20600Sstevel@tonic-gate }
20610Sstevel@tonic-gate
206212273SCasper.Dik@Sun.COM int
secpolicy_pfexec_register(const cred_t * cr)206312273SCasper.Dik@Sun.COM secpolicy_pfexec_register(const cred_t *cr)
206412273SCasper.Dik@Sun.COM {
206512273SCasper.Dik@Sun.COM return (PRIV_POLICY(cr, PRIV_SYS_ADMIN, B_TRUE, EPERM, NULL));
206612273SCasper.Dik@Sun.COM }
206712273SCasper.Dik@Sun.COM
20680Sstevel@tonic-gate /*
20690Sstevel@tonic-gate * Basic privilege checks.
20700Sstevel@tonic-gate */
20710Sstevel@tonic-gate int
secpolicy_basic_exec(const cred_t * cr,vnode_t * vp)20726134Scasper secpolicy_basic_exec(const cred_t *cr, vnode_t *vp)
20730Sstevel@tonic-gate {
207412273SCasper.Dik@Sun.COM FAST_BASIC_CHECK(cr, PRIV_PROC_EXEC);
207512273SCasper.Dik@Sun.COM
20766134Scasper return (priv_policy_va(cr, PRIV_PROC_EXEC, B_FALSE, EPERM, NULL,
20776134Scasper KLPDARG_VNODE, vp, (char *)NULL, KLPDARG_NOMORE));
20780Sstevel@tonic-gate }
20790Sstevel@tonic-gate
20800Sstevel@tonic-gate int
secpolicy_basic_fork(const cred_t * cr)20810Sstevel@tonic-gate secpolicy_basic_fork(const cred_t *cr)
20820Sstevel@tonic-gate {
208312273SCasper.Dik@Sun.COM FAST_BASIC_CHECK(cr, PRIV_PROC_FORK);
208412273SCasper.Dik@Sun.COM
20850Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_PROC_FORK, B_FALSE, EPERM, NULL));
20860Sstevel@tonic-gate }
20870Sstevel@tonic-gate
20880Sstevel@tonic-gate int
secpolicy_basic_proc(const cred_t * cr)20890Sstevel@tonic-gate secpolicy_basic_proc(const cred_t *cr)
20900Sstevel@tonic-gate {
209112273SCasper.Dik@Sun.COM FAST_BASIC_CHECK(cr, PRIV_PROC_SESSION);
209212273SCasper.Dik@Sun.COM
20930Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_PROC_SESSION, B_FALSE, EPERM, NULL));
20940Sstevel@tonic-gate }
20950Sstevel@tonic-gate
20960Sstevel@tonic-gate /*
20970Sstevel@tonic-gate * Slightly complicated because we don't want to trigger the policy too
20980Sstevel@tonic-gate * often. First we shortcircuit access to "self" (tp == sp) or if
20990Sstevel@tonic-gate * we don't have the privilege but if we have permission
21000Sstevel@tonic-gate * just return (0) and we don't flag the privilege as needed.
21010Sstevel@tonic-gate * Else, we test for the privilege because we either have it or need it.
21020Sstevel@tonic-gate */
21030Sstevel@tonic-gate int
secpolicy_basic_procinfo(const cred_t * cr,proc_t * tp,proc_t * sp)21040Sstevel@tonic-gate secpolicy_basic_procinfo(const cred_t *cr, proc_t *tp, proc_t *sp)
21050Sstevel@tonic-gate {
21060Sstevel@tonic-gate if (tp == sp ||
21070Sstevel@tonic-gate !HAS_PRIVILEGE(cr, PRIV_PROC_INFO) && prochasprocperm(tp, sp, cr)) {
21080Sstevel@tonic-gate return (0);
21090Sstevel@tonic-gate } else {
21100Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_PROC_INFO, B_FALSE, EPERM, NULL));
21110Sstevel@tonic-gate }
21120Sstevel@tonic-gate }
21130Sstevel@tonic-gate
21140Sstevel@tonic-gate int
secpolicy_basic_link(const cred_t * cr)21150Sstevel@tonic-gate secpolicy_basic_link(const cred_t *cr)
21160Sstevel@tonic-gate {
211712273SCasper.Dik@Sun.COM FAST_BASIC_CHECK(cr, PRIV_FILE_LINK_ANY);
211812273SCasper.Dik@Sun.COM
21190Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_FILE_LINK_ANY, B_FALSE, EPERM, NULL));
21200Sstevel@tonic-gate }
21210Sstevel@tonic-gate
212211537SCasper.Dik@Sun.COM int
secpolicy_basic_net_access(const cred_t * cr)212311537SCasper.Dik@Sun.COM secpolicy_basic_net_access(const cred_t *cr)
212411537SCasper.Dik@Sun.COM {
212512273SCasper.Dik@Sun.COM FAST_BASIC_CHECK(cr, PRIV_NET_ACCESS);
212612273SCasper.Dik@Sun.COM
212711537SCasper.Dik@Sun.COM return (PRIV_POLICY(cr, PRIV_NET_ACCESS, B_FALSE, EACCES, NULL));
212811537SCasper.Dik@Sun.COM }
212911537SCasper.Dik@Sun.COM
213012273SCasper.Dik@Sun.COM /* ARGSUSED */
213112273SCasper.Dik@Sun.COM int
secpolicy_basic_file_read(const cred_t * cr,vnode_t * vp,const char * pn)213212273SCasper.Dik@Sun.COM secpolicy_basic_file_read(const cred_t *cr, vnode_t *vp, const char *pn)
213312273SCasper.Dik@Sun.COM {
213412273SCasper.Dik@Sun.COM FAST_BASIC_CHECK(cr, PRIV_FILE_READ);
213512273SCasper.Dik@Sun.COM
213612273SCasper.Dik@Sun.COM return (priv_policy_va(cr, PRIV_FILE_READ, B_FALSE, EACCES, NULL,
213712273SCasper.Dik@Sun.COM KLPDARG_VNODE, vp, (char *)pn, KLPDARG_NOMORE));
213812273SCasper.Dik@Sun.COM }
213912273SCasper.Dik@Sun.COM
214012273SCasper.Dik@Sun.COM /* ARGSUSED */
214112273SCasper.Dik@Sun.COM int
secpolicy_basic_file_write(const cred_t * cr,vnode_t * vp,const char * pn)214212273SCasper.Dik@Sun.COM secpolicy_basic_file_write(const cred_t *cr, vnode_t *vp, const char *pn)
214312273SCasper.Dik@Sun.COM {
214412273SCasper.Dik@Sun.COM FAST_BASIC_CHECK(cr, PRIV_FILE_WRITE);
214512273SCasper.Dik@Sun.COM
214612273SCasper.Dik@Sun.COM return (priv_policy_va(cr, PRIV_FILE_WRITE, B_FALSE, EACCES, NULL,
214712273SCasper.Dik@Sun.COM KLPDARG_VNODE, vp, (char *)pn, KLPDARG_NOMORE));
214812273SCasper.Dik@Sun.COM }
214912273SCasper.Dik@Sun.COM
21500Sstevel@tonic-gate /*
21510Sstevel@tonic-gate * Additional device protection.
21520Sstevel@tonic-gate *
21530Sstevel@tonic-gate * Traditionally, a device has specific permissions on the node in
21540Sstevel@tonic-gate * the filesystem which govern which devices can be opened by what
21550Sstevel@tonic-gate * processes. In certain cases, it is desirable to add extra
21560Sstevel@tonic-gate * restrictions, as writing to certain devices is identical to
21570Sstevel@tonic-gate * having a complete run of the system.
21580Sstevel@tonic-gate *
21590Sstevel@tonic-gate * This mechanism is called the device policy.
21600Sstevel@tonic-gate *
21610Sstevel@tonic-gate * When a device is opened, its policy entry is looked up in the
21620Sstevel@tonic-gate * policy cache and checked.
21630Sstevel@tonic-gate */
21640Sstevel@tonic-gate int
secpolicy_spec_open(const cred_t * cr,struct vnode * vp,int oflag)21650Sstevel@tonic-gate secpolicy_spec_open(const cred_t *cr, struct vnode *vp, int oflag)
21660Sstevel@tonic-gate {
21670Sstevel@tonic-gate devplcy_t *plcy;
21680Sstevel@tonic-gate int err;
21690Sstevel@tonic-gate struct snode *csp = VTOS(common_specvp(vp));
21704962Sdh155122 priv_set_t pset;
21710Sstevel@tonic-gate
21720Sstevel@tonic-gate mutex_enter(&csp->s_lock);
21730Sstevel@tonic-gate
21740Sstevel@tonic-gate if (csp->s_plcy == NULL || csp->s_plcy->dp_gen != devplcy_gen) {
21750Sstevel@tonic-gate plcy = devpolicy_find(vp);
21760Sstevel@tonic-gate if (csp->s_plcy)
21770Sstevel@tonic-gate dpfree(csp->s_plcy);
21780Sstevel@tonic-gate csp->s_plcy = plcy;
21790Sstevel@tonic-gate ASSERT(plcy != NULL);
21800Sstevel@tonic-gate } else
21810Sstevel@tonic-gate plcy = csp->s_plcy;
21820Sstevel@tonic-gate
21830Sstevel@tonic-gate if (plcy == nullpolicy) {
21840Sstevel@tonic-gate mutex_exit(&csp->s_lock);
21850Sstevel@tonic-gate return (0);
21860Sstevel@tonic-gate }
21870Sstevel@tonic-gate
21880Sstevel@tonic-gate dphold(plcy);
21890Sstevel@tonic-gate
21900Sstevel@tonic-gate mutex_exit(&csp->s_lock);
21910Sstevel@tonic-gate
21924962Sdh155122 if (oflag & FWRITE)
21934962Sdh155122 pset = plcy->dp_wrp;
21944962Sdh155122 else
21954962Sdh155122 pset = plcy->dp_rdp;
21964962Sdh155122 /*
21974962Sdh155122 * Special case:
21984962Sdh155122 * PRIV_SYS_NET_CONFIG is a superset of PRIV_SYS_IP_CONFIG.
21994962Sdh155122 * If PRIV_SYS_NET_CONFIG is present and PRIV_SYS_IP_CONFIG is
22004962Sdh155122 * required, replace PRIV_SYS_IP_CONFIG with PRIV_SYS_NET_CONFIG
22014962Sdh155122 * in the required privilege set before doing the check.
22024962Sdh155122 */
22034962Sdh155122 if (priv_ismember(&pset, PRIV_SYS_IP_CONFIG) &&
22044962Sdh155122 priv_ismember(&CR_OEPRIV(cr), PRIV_SYS_NET_CONFIG) &&
22054962Sdh155122 !priv_ismember(&CR_OEPRIV(cr), PRIV_SYS_IP_CONFIG)) {
22064962Sdh155122 priv_delset(&pset, PRIV_SYS_IP_CONFIG);
22074962Sdh155122 priv_addset(&pset, PRIV_SYS_NET_CONFIG);
22084962Sdh155122 }
22094962Sdh155122
221012273SCasper.Dik@Sun.COM err = secpolicy_require_set(cr, &pset, "devpolicy", KLPDARG_NONE);
22110Sstevel@tonic-gate dpfree(plcy);
22120Sstevel@tonic-gate
22130Sstevel@tonic-gate return (err);
22140Sstevel@tonic-gate }
22150Sstevel@tonic-gate
22160Sstevel@tonic-gate int
secpolicy_modctl(const cred_t * cr,int cmd)22170Sstevel@tonic-gate secpolicy_modctl(const cred_t *cr, int cmd)
22180Sstevel@tonic-gate {
22190Sstevel@tonic-gate switch (cmd) {
22200Sstevel@tonic-gate case MODINFO:
22212723Scth case MODGETMAJBIND:
22220Sstevel@tonic-gate case MODGETPATH:
22230Sstevel@tonic-gate case MODGETPATHLEN:
22242723Scth case MODGETNAME:
22250Sstevel@tonic-gate case MODGETFBNAME:
22260Sstevel@tonic-gate case MODGETDEVPOLICY:
22270Sstevel@tonic-gate case MODGETDEVPOLICYBYNAME:
22282723Scth case MODDEVT2INSTANCE:
22292723Scth case MODSIZEOF_DEVID:
22302723Scth case MODGETDEVID:
22312723Scth case MODSIZEOF_MINORNAME:
22322723Scth case MODGETMINORNAME:
22332723Scth case MODGETDEVFSPATH_LEN:
22342723Scth case MODGETDEVFSPATH:
22352723Scth case MODGETDEVFSPATH_MI_LEN:
22362723Scth case MODGETDEVFSPATH_MI:
22370Sstevel@tonic-gate /* Unprivileged */
22380Sstevel@tonic-gate return (0);
22390Sstevel@tonic-gate case MODLOAD:
22400Sstevel@tonic-gate case MODSETDEVPOLICY:
224112273SCasper.Dik@Sun.COM return (secpolicy_require_set(cr, PRIV_FULLSET, NULL,
224212273SCasper.Dik@Sun.COM KLPDARG_NONE));
22430Sstevel@tonic-gate default:
22440Sstevel@tonic-gate return (secpolicy_sys_config(cr, B_FALSE));
22450Sstevel@tonic-gate }
22460Sstevel@tonic-gate }
22470Sstevel@tonic-gate
22480Sstevel@tonic-gate int
secpolicy_console(const cred_t * cr)22490Sstevel@tonic-gate secpolicy_console(const cred_t *cr)
22500Sstevel@tonic-gate {
22510Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_DEVICES, B_FALSE, EPERM, NULL));
22520Sstevel@tonic-gate }
22530Sstevel@tonic-gate
22540Sstevel@tonic-gate int
secpolicy_power_mgmt(const cred_t * cr)22550Sstevel@tonic-gate secpolicy_power_mgmt(const cred_t *cr)
22560Sstevel@tonic-gate {
22570Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_DEVICES, B_FALSE, EPERM, NULL));
22580Sstevel@tonic-gate }
22590Sstevel@tonic-gate
22600Sstevel@tonic-gate /*
22610Sstevel@tonic-gate * Simulate terminal input; another escalation of privileges avenue.
22620Sstevel@tonic-gate */
22630Sstevel@tonic-gate
22640Sstevel@tonic-gate int
secpolicy_sti(const cred_t * cr)22650Sstevel@tonic-gate secpolicy_sti(const cred_t *cr)
22660Sstevel@tonic-gate {
226712273SCasper.Dik@Sun.COM return (secpolicy_require_set(cr, PRIV_FULLSET, NULL, KLPDARG_NONE));
22680Sstevel@tonic-gate }
22690Sstevel@tonic-gate
22701676Sjpk boolean_t
secpolicy_net_reply_equal(const cred_t * cr)22711676Sjpk secpolicy_net_reply_equal(const cred_t *cr)
22721676Sjpk {
22731676Sjpk return (PRIV_POLICY(cr, PRIV_SYS_CONFIG, B_FALSE, EPERM, NULL));
22741676Sjpk }
22751676Sjpk
22760Sstevel@tonic-gate int
secpolicy_swapctl(const cred_t * cr)22770Sstevel@tonic-gate secpolicy_swapctl(const cred_t *cr)
22780Sstevel@tonic-gate {
22790Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_CONFIG, B_FALSE, EPERM, NULL));
22800Sstevel@tonic-gate }
22810Sstevel@tonic-gate
22820Sstevel@tonic-gate int
secpolicy_cpc_cpu(const cred_t * cr)22830Sstevel@tonic-gate secpolicy_cpc_cpu(const cred_t *cr)
22840Sstevel@tonic-gate {
22850Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_CPC_CPU, B_FALSE, EACCES, NULL));
22860Sstevel@tonic-gate }
22870Sstevel@tonic-gate
22880Sstevel@tonic-gate /*
22896073Sacruz * secpolicy_contract_identity
22906073Sacruz *
22916073Sacruz * Determine if the subject may set the process contract FMRI value
22926073Sacruz */
22936073Sacruz int
secpolicy_contract_identity(const cred_t * cr)22946073Sacruz secpolicy_contract_identity(const cred_t *cr)
22956073Sacruz {
22966073Sacruz return (PRIV_POLICY(cr, PRIV_CONTRACT_IDENTITY, B_FALSE, EPERM, NULL));
22976073Sacruz }
22986073Sacruz
22996073Sacruz /*
23000Sstevel@tonic-gate * secpolicy_contract_observer
23010Sstevel@tonic-gate *
23020Sstevel@tonic-gate * Determine if the subject may observe a specific contract's events.
23030Sstevel@tonic-gate */
23040Sstevel@tonic-gate int
secpolicy_contract_observer(const cred_t * cr,struct contract * ct)23050Sstevel@tonic-gate secpolicy_contract_observer(const cred_t *cr, struct contract *ct)
23060Sstevel@tonic-gate {
23070Sstevel@tonic-gate if (contract_owned(ct, cr, B_FALSE))
23080Sstevel@tonic-gate return (0);
23090Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_CONTRACT_OBSERVER, B_FALSE, EPERM, NULL));
23100Sstevel@tonic-gate }
23110Sstevel@tonic-gate
23120Sstevel@tonic-gate /*
23130Sstevel@tonic-gate * secpolicy_contract_observer_choice
23140Sstevel@tonic-gate *
23150Sstevel@tonic-gate * Determine if the subject may observe any contract's events. Just
23160Sstevel@tonic-gate * tests privilege and audits on success.
23170Sstevel@tonic-gate */
23180Sstevel@tonic-gate boolean_t
secpolicy_contract_observer_choice(const cred_t * cr)23190Sstevel@tonic-gate secpolicy_contract_observer_choice(const cred_t *cr)
23200Sstevel@tonic-gate {
23210Sstevel@tonic-gate return (PRIV_POLICY_CHOICE(cr, PRIV_CONTRACT_OBSERVER, B_FALSE));
23220Sstevel@tonic-gate }
23230Sstevel@tonic-gate
23240Sstevel@tonic-gate /*
23250Sstevel@tonic-gate * secpolicy_contract_event
23260Sstevel@tonic-gate *
23270Sstevel@tonic-gate * Determine if the subject may request critical contract events or
23280Sstevel@tonic-gate * reliable contract event delivery.
23290Sstevel@tonic-gate */
23300Sstevel@tonic-gate int
secpolicy_contract_event(const cred_t * cr)23310Sstevel@tonic-gate secpolicy_contract_event(const cred_t *cr)
23320Sstevel@tonic-gate {
23330Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_CONTRACT_EVENT, B_FALSE, EPERM, NULL));
23340Sstevel@tonic-gate }
23350Sstevel@tonic-gate
23360Sstevel@tonic-gate /*
23370Sstevel@tonic-gate * secpolicy_contract_event_choice
23380Sstevel@tonic-gate *
23390Sstevel@tonic-gate * Determine if the subject may retain contract events in its critical
23400Sstevel@tonic-gate * set when a change in other terms would normally require a change in
23410Sstevel@tonic-gate * the critical set. Just tests privilege and audits on success.
23420Sstevel@tonic-gate */
23430Sstevel@tonic-gate boolean_t
secpolicy_contract_event_choice(const cred_t * cr)23440Sstevel@tonic-gate secpolicy_contract_event_choice(const cred_t *cr)
23450Sstevel@tonic-gate {
23460Sstevel@tonic-gate return (PRIV_POLICY_CHOICE(cr, PRIV_CONTRACT_EVENT, B_FALSE));
23470Sstevel@tonic-gate }
23480Sstevel@tonic-gate
23490Sstevel@tonic-gate /*
23501544Seschrock * secpolicy_gart_access
23510Sstevel@tonic-gate *
23521544Seschrock * Determine if the subject has sufficient priveleges to make ioctls to agpgart
23531544Seschrock * device.
23540Sstevel@tonic-gate */
23550Sstevel@tonic-gate int
secpolicy_gart_access(const cred_t * cr)23560Sstevel@tonic-gate secpolicy_gart_access(const cred_t *cr)
23570Sstevel@tonic-gate {
23581862Scasper return (PRIV_POLICY(cr, PRIV_GRAPHICS_ACCESS, B_FALSE, EPERM, NULL));
23590Sstevel@tonic-gate }
23600Sstevel@tonic-gate
23610Sstevel@tonic-gate /*
23621544Seschrock * secpolicy_gart_map
23630Sstevel@tonic-gate *
23641544Seschrock * Determine if the subject has sufficient priveleges to map aperture range
23651544Seschrock * through agpgart driver.
23660Sstevel@tonic-gate */
23670Sstevel@tonic-gate int
secpolicy_gart_map(const cred_t * cr)23680Sstevel@tonic-gate secpolicy_gart_map(const cred_t *cr)
23690Sstevel@tonic-gate {
23701862Scasper if (PRIV_POLICY_ONLY(cr, PRIV_GRAPHICS_ACCESS, B_FALSE)) {
23711862Scasper return (PRIV_POLICY(cr, PRIV_GRAPHICS_ACCESS, B_FALSE, EPERM,
23721862Scasper NULL));
23731862Scasper } else {
23741862Scasper return (PRIV_POLICY(cr, PRIV_GRAPHICS_MAP, B_FALSE, EPERM,
23751862Scasper NULL));
23760Sstevel@tonic-gate }
23770Sstevel@tonic-gate }
2378789Sahrens
2379789Sahrens /*
23801544Seschrock * secpolicy_zinject
23811544Seschrock *
23821544Seschrock * Determine if the subject can inject faults in the ZFS fault injection
23831544Seschrock * framework. Requires all privileges.
23841544Seschrock */
23851544Seschrock int
secpolicy_zinject(const cred_t * cr)23861544Seschrock secpolicy_zinject(const cred_t *cr)
23871544Seschrock {
238812273SCasper.Dik@Sun.COM return (secpolicy_require_set(cr, PRIV_FULLSET, NULL, KLPDARG_NONE));
23891544Seschrock }
23901544Seschrock
23911544Seschrock /*
2392789Sahrens * secpolicy_zfs
2393789Sahrens *
23941544Seschrock * Determine if the subject has permission to manipulate ZFS datasets
23951544Seschrock * (not pools). Equivalent to the SYS_MOUNT privilege.
2396789Sahrens */
2397789Sahrens int
secpolicy_zfs(const cred_t * cr)2398789Sahrens secpolicy_zfs(const cred_t *cr)
2399789Sahrens {
2400789Sahrens return (PRIV_POLICY(cr, PRIV_SYS_MOUNT, B_FALSE, EPERM, NULL));
2401789Sahrens }
24024321Scasper
24034321Scasper /*
24044321Scasper * secpolicy_idmap
24054321Scasper *
24064321Scasper * Determine if the calling process has permissions to register an SID
24074321Scasper * mapping daemon and allocate ephemeral IDs.
24084321Scasper */
24094321Scasper int
secpolicy_idmap(const cred_t * cr)24104321Scasper secpolicy_idmap(const cred_t *cr)
24114321Scasper {
24125771Sjp151216 return (PRIV_POLICY(cr, PRIV_FILE_SETID, B_TRUE, EPERM, NULL));
24134321Scasper }
24144581Ssherrym
24154581Ssherrym /*
24164581Ssherrym * secpolicy_ucode_update
24174581Ssherrym *
24184581Ssherrym * Determine if the subject has sufficient privilege to update microcode.
24194581Ssherrym */
24204581Ssherrym int
secpolicy_ucode_update(const cred_t * scr)24214581Ssherrym secpolicy_ucode_update(const cred_t *scr)
24224581Ssherrym {
24234581Ssherrym return (PRIV_POLICY(scr, PRIV_ALL, B_FALSE, EPERM, NULL));
24244581Ssherrym }
24254962Sdh155122
24264962Sdh155122 /*
24274962Sdh155122 * secpolicy_sadopen
24284962Sdh155122 *
24294962Sdh155122 * Determine if the subject has sufficient privilege to access /dev/sad/admin.
24304962Sdh155122 * /dev/sad/admin appear in global zone and exclusive-IP zones only.
24314962Sdh155122 * In global zone, sys_config is required.
24324962Sdh155122 * In exclusive-IP zones, sys_ip_config is required.
24334962Sdh155122 * Note that sys_config is prohibited in non-global zones.
24344962Sdh155122 */
24354962Sdh155122 int
secpolicy_sadopen(const cred_t * credp)24364962Sdh155122 secpolicy_sadopen(const cred_t *credp)
24374962Sdh155122 {
24384962Sdh155122 priv_set_t pset;
24394962Sdh155122
24404962Sdh155122 priv_emptyset(&pset);
24414962Sdh155122
24424962Sdh155122 if (crgetzoneid(credp) == GLOBAL_ZONEID)
24434962Sdh155122 priv_addset(&pset, PRIV_SYS_CONFIG);
24444962Sdh155122 else
24454962Sdh155122 priv_addset(&pset, PRIV_SYS_IP_CONFIG);
24464962Sdh155122
244712273SCasper.Dik@Sun.COM return (secpolicy_require_set(credp, &pset, "devpolicy", KLPDARG_NONE));
24484962Sdh155122 }
24495331Samw
24506134Scasper
24516134Scasper /*
24526134Scasper * Add privileges to a particular privilege set; this is called when the
24536134Scasper * current sets of privileges are not sufficient. I.e., we should always
24546134Scasper * call the policy override functions from here.
24556134Scasper * What we are allowed to have is in the Observed Permitted set; so
24566134Scasper * we compute the difference between that and the newset.
24576134Scasper */
24586134Scasper int
secpolicy_require_privs(const cred_t * cr,const priv_set_t * nset)24596134Scasper secpolicy_require_privs(const cred_t *cr, const priv_set_t *nset)
24606134Scasper {
24616134Scasper priv_set_t rqd;
24626134Scasper
24636134Scasper rqd = CR_OPPRIV(cr);
24646134Scasper
24656134Scasper priv_inverse(&rqd);
24666134Scasper priv_intersect(nset, &rqd);
24676134Scasper
246812273SCasper.Dik@Sun.COM return (secpolicy_require_set(cr, &rqd, NULL, KLPDARG_NONE));
24696134Scasper }
24706134Scasper
24715331Samw /*
24725331Samw * secpolicy_smb
24735331Samw *
24745331Samw * Determine if the cred_t has PRIV_SYS_SMB privilege, indicating
24755331Samw * that it has permission to access the smbsrv kernel driver.
24765331Samw * PRIV_POLICY checks the privilege and audits the check.
24775331Samw *
24785331Samw * Returns:
24795331Samw * 0 Driver access is allowed.
24805331Samw * EPERM Driver access is NOT permitted.
24815331Samw */
24825331Samw int
secpolicy_smb(const cred_t * cr)24835331Samw secpolicy_smb(const cred_t *cr)
24845331Samw {
24855331Samw return (PRIV_POLICY(cr, PRIV_SYS_SMB, B_FALSE, EPERM, NULL));
24865331Samw }
24875440Sjm199354
24885440Sjm199354 /*
24895440Sjm199354 * secpolicy_vscan
24905440Sjm199354 *
24915440Sjm199354 * Determine if cred_t has the necessary privileges to access a file
24925440Sjm199354 * for virus scanning and update its extended system attributes.
24935440Sjm199354 * PRIV_FILE_DAC_SEARCH, PRIV_FILE_DAC_READ - file access
24945440Sjm199354 * PRIV_FILE_FLAG_SET - set extended system attributes
24955440Sjm199354 *
24965440Sjm199354 * PRIV_POLICY checks the privilege and audits the check.
24975440Sjm199354 *
24985440Sjm199354 * Returns:
24995440Sjm199354 * 0 file access for virus scanning allowed.
25005440Sjm199354 * EPERM file access for virus scanning is NOT permitted.
25015440Sjm199354 */
25025440Sjm199354 int
secpolicy_vscan(const cred_t * cr)25035440Sjm199354 secpolicy_vscan(const cred_t *cr)
25045440Sjm199354 {
25055440Sjm199354 if ((PRIV_POLICY(cr, PRIV_FILE_DAC_SEARCH, B_FALSE, EPERM, NULL)) ||
25065440Sjm199354 (PRIV_POLICY(cr, PRIV_FILE_DAC_READ, B_FALSE, EPERM, NULL)) ||
25075440Sjm199354 (PRIV_POLICY(cr, PRIV_FILE_FLAG_SET, B_FALSE, EPERM, NULL))) {
25085440Sjm199354 return (EPERM);
25095440Sjm199354 }
25105440Sjm199354
25115440Sjm199354 return (0);
25125440Sjm199354 }
25136007Sthurlow
25146007Sthurlow /*
25156007Sthurlow * secpolicy_smbfs_login
25166007Sthurlow *
25176007Sthurlow * Determines if the caller can add and delete the smbfs login
25186007Sthurlow * password in the the nsmb kernel module for the CIFS client.
25196007Sthurlow *
25206007Sthurlow * Returns:
25216007Sthurlow * 0 access is allowed.
25226007Sthurlow * EPERM access is NOT allowed.
25236007Sthurlow */
25246007Sthurlow int
secpolicy_smbfs_login(const cred_t * cr,uid_t uid)25256007Sthurlow secpolicy_smbfs_login(const cred_t *cr, uid_t uid)
25266007Sthurlow {
25276007Sthurlow uid_t cruid = crgetruid(cr);
25286007Sthurlow
25296007Sthurlow if (cruid == uid)
25306007Sthurlow return (0);
25316007Sthurlow return (PRIV_POLICY(cr, PRIV_PROC_OWNER, B_FALSE,
25326007Sthurlow EPERM, NULL));
25336007Sthurlow }
25346784Sjohnlev
25356784Sjohnlev /*
25366784Sjohnlev * secpolicy_xvm_control
25376784Sjohnlev *
25386784Sjohnlev * Determines if a caller can control the xVM hypervisor and/or running
25396784Sjohnlev * domains (x86 specific).
25406784Sjohnlev *
25416784Sjohnlev * Returns:
25426784Sjohnlev * 0 access is allowed.
25436784Sjohnlev * EPERM access is NOT allowed.
25446784Sjohnlev */
25456784Sjohnlev int
secpolicy_xvm_control(const cred_t * cr)25466784Sjohnlev secpolicy_xvm_control(const cred_t *cr)
25476784Sjohnlev {
25486784Sjohnlev if (PRIV_POLICY(cr, PRIV_XVM_CONTROL, B_FALSE, EPERM, NULL))
25496784Sjohnlev return (EPERM);
25506784Sjohnlev return (0);
25516784Sjohnlev }
25528275SEric Cheng
25538275SEric Cheng /*
25549751Sjames.d.carlson@sun.com * secpolicy_ppp_config
25559751Sjames.d.carlson@sun.com *
25569751Sjames.d.carlson@sun.com * Determine if the subject has sufficient privileges to configure PPP and
25579751Sjames.d.carlson@sun.com * PPP-related devices.
25589751Sjames.d.carlson@sun.com */
25599751Sjames.d.carlson@sun.com int
secpolicy_ppp_config(const cred_t * cr)25609751Sjames.d.carlson@sun.com secpolicy_ppp_config(const cred_t *cr)
25619751Sjames.d.carlson@sun.com {
25629751Sjames.d.carlson@sun.com if (PRIV_POLICY_ONLY(cr, PRIV_SYS_NET_CONFIG, B_FALSE))
25639751Sjames.d.carlson@sun.com return (secpolicy_net_config(cr, B_FALSE));
25649751Sjames.d.carlson@sun.com return (PRIV_POLICY(cr, PRIV_SYS_PPP_CONFIG, B_FALSE, EPERM, NULL));
25659751Sjames.d.carlson@sun.com }
2566