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 * 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 758148Scasper extern vnode_t *rootvp; 759148Scasper extern vfs_t *rootvfs; 760148Scasper 7610Sstevel@tonic-gate int 7620Sstevel@tonic-gate secpolicy_fs_mount(cred_t *cr, vnode_t *mvp, struct vfs *vfsp) 7630Sstevel@tonic-gate { 7640Sstevel@tonic-gate boolean_t needoptchk; 7650Sstevel@tonic-gate int error; 7660Sstevel@tonic-gate 767148Scasper /* 768148Scasper * If it's a remount, get the underlying mount point, 769148Scasper * except for the root where we use the rootvp. 770148Scasper */ 771148Scasper if ((vfsp->vfs_flag & VFS_REMOUNT) != 0) { 772148Scasper if (vfsp == rootvfs) 773148Scasper mvp = rootvp; 774148Scasper else 775148Scasper mvp = vfsp->vfs_vnodecovered; 776148Scasper } 777148Scasper 7780Sstevel@tonic-gate error = secpolicy_fs_common(cr, mvp, vfsp, &needoptchk); 7790Sstevel@tonic-gate 7800Sstevel@tonic-gate if (error == 0 && needoptchk) { 7814543Smarks secpolicy_fs_mount_clearopts(cr, vfsp); 7824543Smarks } 7830Sstevel@tonic-gate 7840Sstevel@tonic-gate return (error); 7850Sstevel@tonic-gate } 7860Sstevel@tonic-gate 7870Sstevel@tonic-gate /* 7880Sstevel@tonic-gate * Does the policy computations for "ownership" of a mount; 7890Sstevel@tonic-gate * here ownership is defined as the ability to "mount" 7900Sstevel@tonic-gate * the filesystem originally. The rootvfs doesn't cover any 7910Sstevel@tonic-gate * vnodes; we attribute its ownership to the rootvp. 7920Sstevel@tonic-gate */ 7930Sstevel@tonic-gate static int 7940Sstevel@tonic-gate secpolicy_fs_owner(cred_t *cr, const struct vfs *vfsp) 7950Sstevel@tonic-gate { 7960Sstevel@tonic-gate vnode_t *mvp; 7970Sstevel@tonic-gate 7980Sstevel@tonic-gate if (vfsp == NULL) 7990Sstevel@tonic-gate mvp = NULL; 8000Sstevel@tonic-gate else if (vfsp == rootvfs) 8010Sstevel@tonic-gate mvp = rootvp; 8020Sstevel@tonic-gate else 8030Sstevel@tonic-gate mvp = vfsp->vfs_vnodecovered; 8040Sstevel@tonic-gate 8050Sstevel@tonic-gate return (secpolicy_fs_common(cr, mvp, vfsp, NULL)); 8060Sstevel@tonic-gate } 8070Sstevel@tonic-gate 8080Sstevel@tonic-gate int 8090Sstevel@tonic-gate secpolicy_fs_unmount(cred_t *cr, struct vfs *vfsp) 8100Sstevel@tonic-gate { 8110Sstevel@tonic-gate return (secpolicy_fs_owner(cr, vfsp)); 8120Sstevel@tonic-gate } 8130Sstevel@tonic-gate 8140Sstevel@tonic-gate /* 8150Sstevel@tonic-gate * Quotas are a resource, but if one has the ability to mount a filesystem, he 8160Sstevel@tonic-gate * should be able to modify quotas on it. 8170Sstevel@tonic-gate */ 8180Sstevel@tonic-gate int 8190Sstevel@tonic-gate secpolicy_fs_quota(const cred_t *cr, const vfs_t *vfsp) 8200Sstevel@tonic-gate { 8210Sstevel@tonic-gate return (secpolicy_fs_owner((cred_t *)cr, vfsp)); 8220Sstevel@tonic-gate } 8230Sstevel@tonic-gate 8240Sstevel@tonic-gate /* 8250Sstevel@tonic-gate * Exceeding minfree: also a per-mount resource constraint. 8260Sstevel@tonic-gate */ 8270Sstevel@tonic-gate int 8280Sstevel@tonic-gate secpolicy_fs_minfree(const cred_t *cr, const vfs_t *vfsp) 8290Sstevel@tonic-gate { 8300Sstevel@tonic-gate return (secpolicy_fs_owner((cred_t *)cr, vfsp)); 8310Sstevel@tonic-gate } 8320Sstevel@tonic-gate 8330Sstevel@tonic-gate int 8340Sstevel@tonic-gate secpolicy_fs_config(const cred_t *cr, const vfs_t *vfsp) 8350Sstevel@tonic-gate { 8360Sstevel@tonic-gate return (secpolicy_fs_owner((cred_t *)cr, vfsp)); 8370Sstevel@tonic-gate } 8380Sstevel@tonic-gate 8390Sstevel@tonic-gate /* ARGSUSED */ 8400Sstevel@tonic-gate int 8410Sstevel@tonic-gate secpolicy_fs_linkdir(const cred_t *cr, const vfs_t *vfsp) 8420Sstevel@tonic-gate { 8430Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_LINKDIR, B_FALSE, EPERM, NULL)); 8440Sstevel@tonic-gate } 8450Sstevel@tonic-gate 8460Sstevel@tonic-gate /* 8470Sstevel@tonic-gate * Name: secpolicy_vnode_access() 8480Sstevel@tonic-gate * 8490Sstevel@tonic-gate * Parameters: Process credential 8500Sstevel@tonic-gate * vnode 8510Sstevel@tonic-gate * uid of owner of vnode 8520Sstevel@tonic-gate * permission bits not granted to the caller when examining 8530Sstevel@tonic-gate * file mode bits (i.e., when a process wants to open a 8540Sstevel@tonic-gate * mode 444 file for VREAD|VWRITE, this function should be 8550Sstevel@tonic-gate * called only with a VWRITE argument). 8560Sstevel@tonic-gate * 8570Sstevel@tonic-gate * Normal: Verifies that cred has the appropriate privileges to 8580Sstevel@tonic-gate * override the mode bits that were denied. 8590Sstevel@tonic-gate * 8600Sstevel@tonic-gate * Override: file_dac_execute - if VEXEC bit was denied and vnode is 8610Sstevel@tonic-gate * not a directory. 8620Sstevel@tonic-gate * file_dac_read - if VREAD bit was denied. 8630Sstevel@tonic-gate * file_dac_search - if VEXEC bit was denied and vnode is 8640Sstevel@tonic-gate * a directory. 8650Sstevel@tonic-gate * file_dac_write - if VWRITE bit was denied. 8660Sstevel@tonic-gate * 8670Sstevel@tonic-gate * Root owned files are special cased to protect system 8680Sstevel@tonic-gate * configuration files and such. 8690Sstevel@tonic-gate * 8700Sstevel@tonic-gate * Output: EACCES - if privilege check fails. 8710Sstevel@tonic-gate */ 8720Sstevel@tonic-gate 8730Sstevel@tonic-gate int 8740Sstevel@tonic-gate secpolicy_vnode_access(const cred_t *cr, vnode_t *vp, uid_t owner, mode_t mode) 8750Sstevel@tonic-gate { 8766134Scasper if ((mode & VREAD) && priv_policy_va(cr, PRIV_FILE_DAC_READ, B_FALSE, 8776134Scasper EACCES, NULL, KLPDARG_VNODE, vp, (char *)NULL, 8786134Scasper KLPDARG_NOMORE) != 0) { 8790Sstevel@tonic-gate return (EACCES); 8806134Scasper } 8810Sstevel@tonic-gate 8820Sstevel@tonic-gate if (mode & VWRITE) { 8830Sstevel@tonic-gate boolean_t allzone; 8840Sstevel@tonic-gate 8850Sstevel@tonic-gate if (owner == 0 && cr->cr_uid != 0) 8860Sstevel@tonic-gate allzone = B_TRUE; 8870Sstevel@tonic-gate else 8880Sstevel@tonic-gate allzone = B_FALSE; 8896134Scasper if (priv_policy_va(cr, PRIV_FILE_DAC_WRITE, allzone, EACCES, 8906134Scasper NULL, KLPDARG_VNODE, vp, (char *)NULL, 8916134Scasper KLPDARG_NOMORE) != 0) { 8920Sstevel@tonic-gate return (EACCES); 8936134Scasper } 8940Sstevel@tonic-gate } 8950Sstevel@tonic-gate 8960Sstevel@tonic-gate if (mode & VEXEC) { 8970Sstevel@tonic-gate /* 8980Sstevel@tonic-gate * Directories use file_dac_search to override the execute bit. 8990Sstevel@tonic-gate */ 9006134Scasper int p = vp->v_type == VDIR ? PRIV_FILE_DAC_SEARCH : 9016134Scasper PRIV_FILE_DAC_EXECUTE; 9020Sstevel@tonic-gate 9036134Scasper return (priv_policy_va(cr, p, B_FALSE, EACCES, NULL, 9046134Scasper KLPDARG_VNODE, vp, (char *)NULL, KLPDARG_NOMORE)); 9050Sstevel@tonic-gate } 9060Sstevel@tonic-gate return (0); 9070Sstevel@tonic-gate } 9080Sstevel@tonic-gate 9090Sstevel@tonic-gate /* 91012273SCasper.Dik@Sun.COM * Like secpolicy_vnode_access() but we get the actual wanted mode and the 91112273SCasper.Dik@Sun.COM * current mode of the file, not the missing bits. 91212273SCasper.Dik@Sun.COM */ 91312273SCasper.Dik@Sun.COM int 91412273SCasper.Dik@Sun.COM secpolicy_vnode_access2(const cred_t *cr, vnode_t *vp, uid_t owner, 91512273SCasper.Dik@Sun.COM mode_t curmode, mode_t wantmode) 91612273SCasper.Dik@Sun.COM { 91712273SCasper.Dik@Sun.COM mode_t mode; 91812273SCasper.Dik@Sun.COM 91912273SCasper.Dik@Sun.COM /* Inline the basic privileges tests. */ 92012273SCasper.Dik@Sun.COM if ((wantmode & VREAD) && 92112273SCasper.Dik@Sun.COM !PRIV_ISASSERT(&CR_OEPRIV(cr), PRIV_FILE_READ) && 92212273SCasper.Dik@Sun.COM priv_policy_va(cr, PRIV_FILE_READ, B_FALSE, EACCES, NULL, 92312273SCasper.Dik@Sun.COM KLPDARG_VNODE, vp, (char *)NULL, KLPDARG_NOMORE) != 0) { 92412273SCasper.Dik@Sun.COM return (EACCES); 92512273SCasper.Dik@Sun.COM } 92612273SCasper.Dik@Sun.COM 92712273SCasper.Dik@Sun.COM if ((wantmode & VWRITE) && 92812273SCasper.Dik@Sun.COM !PRIV_ISASSERT(&CR_OEPRIV(cr), PRIV_FILE_WRITE) && 92912273SCasper.Dik@Sun.COM priv_policy_va(cr, PRIV_FILE_WRITE, B_FALSE, EACCES, NULL, 93012273SCasper.Dik@Sun.COM KLPDARG_VNODE, vp, (char *)NULL, KLPDARG_NOMORE) != 0) { 93112273SCasper.Dik@Sun.COM return (EACCES); 93212273SCasper.Dik@Sun.COM } 93312273SCasper.Dik@Sun.COM 93412273SCasper.Dik@Sun.COM mode = ~curmode & wantmode; 93512273SCasper.Dik@Sun.COM 93612273SCasper.Dik@Sun.COM if (mode == 0) 93712273SCasper.Dik@Sun.COM return (0); 93812273SCasper.Dik@Sun.COM 93912273SCasper.Dik@Sun.COM if ((mode & VREAD) && priv_policy_va(cr, PRIV_FILE_DAC_READ, B_FALSE, 94012273SCasper.Dik@Sun.COM EACCES, NULL, KLPDARG_VNODE, vp, (char *)NULL, 94112273SCasper.Dik@Sun.COM KLPDARG_NOMORE) != 0) { 94212273SCasper.Dik@Sun.COM return (EACCES); 94312273SCasper.Dik@Sun.COM } 94412273SCasper.Dik@Sun.COM 94512273SCasper.Dik@Sun.COM if (mode & VWRITE) { 94612273SCasper.Dik@Sun.COM boolean_t allzone; 94712273SCasper.Dik@Sun.COM 94812273SCasper.Dik@Sun.COM if (owner == 0 && cr->cr_uid != 0) 94912273SCasper.Dik@Sun.COM allzone = B_TRUE; 95012273SCasper.Dik@Sun.COM else 95112273SCasper.Dik@Sun.COM allzone = B_FALSE; 95212273SCasper.Dik@Sun.COM if (priv_policy_va(cr, PRIV_FILE_DAC_WRITE, allzone, EACCES, 95312273SCasper.Dik@Sun.COM NULL, KLPDARG_VNODE, vp, (char *)NULL, 95412273SCasper.Dik@Sun.COM KLPDARG_NOMORE) != 0) { 95512273SCasper.Dik@Sun.COM return (EACCES); 95612273SCasper.Dik@Sun.COM } 95712273SCasper.Dik@Sun.COM } 95812273SCasper.Dik@Sun.COM 95912273SCasper.Dik@Sun.COM if (mode & VEXEC) { 96012273SCasper.Dik@Sun.COM /* 96112273SCasper.Dik@Sun.COM * Directories use file_dac_search to override the execute bit. 96212273SCasper.Dik@Sun.COM */ 96312273SCasper.Dik@Sun.COM int p = vp->v_type == VDIR ? PRIV_FILE_DAC_SEARCH : 96412273SCasper.Dik@Sun.COM PRIV_FILE_DAC_EXECUTE; 96512273SCasper.Dik@Sun.COM 96612273SCasper.Dik@Sun.COM return (priv_policy_va(cr, p, B_FALSE, EACCES, NULL, 96712273SCasper.Dik@Sun.COM KLPDARG_VNODE, vp, (char *)NULL, KLPDARG_NOMORE)); 96812273SCasper.Dik@Sun.COM } 96912273SCasper.Dik@Sun.COM return (0); 97012273SCasper.Dik@Sun.COM } 97112273SCasper.Dik@Sun.COM 97212273SCasper.Dik@Sun.COM /* 97312273SCasper.Dik@Sun.COM * This is a special routine for ZFS; it is used to determine whether 97412273SCasper.Dik@Sun.COM * any of the privileges in effect allow any form of access to the 97512273SCasper.Dik@Sun.COM * file. There's no reason to audit this or any reason to record 97612273SCasper.Dik@Sun.COM * this. More work is needed to do the "KPLD" stuff. 97712273SCasper.Dik@Sun.COM */ 97812273SCasper.Dik@Sun.COM int 97912273SCasper.Dik@Sun.COM secpolicy_vnode_any_access(const cred_t *cr, vnode_t *vp, uid_t owner) 98012273SCasper.Dik@Sun.COM { 98112273SCasper.Dik@Sun.COM static int privs[] = { 98212273SCasper.Dik@Sun.COM PRIV_FILE_OWNER, 98312484SCasper.Dik@Sun.COM PRIV_FILE_CHOWN, 98412273SCasper.Dik@Sun.COM PRIV_FILE_DAC_READ, 98512273SCasper.Dik@Sun.COM PRIV_FILE_DAC_WRITE, 98612273SCasper.Dik@Sun.COM PRIV_FILE_DAC_EXECUTE, 98712273SCasper.Dik@Sun.COM PRIV_FILE_DAC_SEARCH, 98812273SCasper.Dik@Sun.COM }; 98912273SCasper.Dik@Sun.COM int i; 99012273SCasper.Dik@Sun.COM 99112273SCasper.Dik@Sun.COM /* Same as secpolicy_vnode_setdac */ 99212273SCasper.Dik@Sun.COM if (owner == cr->cr_uid) 99312273SCasper.Dik@Sun.COM return (0); 99412273SCasper.Dik@Sun.COM 99512273SCasper.Dik@Sun.COM for (i = 0; i < sizeof (privs)/sizeof (int); i++) { 99612273SCasper.Dik@Sun.COM boolean_t allzone = B_FALSE; 99712273SCasper.Dik@Sun.COM int priv; 99812273SCasper.Dik@Sun.COM 99912273SCasper.Dik@Sun.COM switch (priv = privs[i]) { 100012273SCasper.Dik@Sun.COM case PRIV_FILE_DAC_EXECUTE: 100112273SCasper.Dik@Sun.COM if (vp->v_type == VDIR) 100212273SCasper.Dik@Sun.COM continue; 100312273SCasper.Dik@Sun.COM break; 100412273SCasper.Dik@Sun.COM case PRIV_FILE_DAC_SEARCH: 100512273SCasper.Dik@Sun.COM if (vp->v_type != VDIR) 100612273SCasper.Dik@Sun.COM continue; 100712273SCasper.Dik@Sun.COM break; 100812273SCasper.Dik@Sun.COM case PRIV_FILE_DAC_WRITE: 100912273SCasper.Dik@Sun.COM case PRIV_FILE_OWNER: 101012484SCasper.Dik@Sun.COM case PRIV_FILE_CHOWN: 101112273SCasper.Dik@Sun.COM /* We know here that if owner == 0, that cr_uid != 0 */ 101212273SCasper.Dik@Sun.COM allzone = owner == 0; 101312273SCasper.Dik@Sun.COM break; 101412273SCasper.Dik@Sun.COM } 101512273SCasper.Dik@Sun.COM if (PRIV_POLICY_CHOICE(cr, priv, allzone)) 101612273SCasper.Dik@Sun.COM return (0); 101712273SCasper.Dik@Sun.COM } 101812273SCasper.Dik@Sun.COM return (EPERM); 101912273SCasper.Dik@Sun.COM } 102012273SCasper.Dik@Sun.COM 102112273SCasper.Dik@Sun.COM /* 10220Sstevel@tonic-gate * Name: secpolicy_vnode_setid_modify() 10230Sstevel@tonic-gate * 10240Sstevel@tonic-gate * Normal: verify that subject can set the file setid flags. 10250Sstevel@tonic-gate * 10260Sstevel@tonic-gate * Output: EPERM - if not privileged. 10270Sstevel@tonic-gate */ 10280Sstevel@tonic-gate 10290Sstevel@tonic-gate static int 10300Sstevel@tonic-gate secpolicy_vnode_setid_modify(const cred_t *cr, uid_t owner) 10310Sstevel@tonic-gate { 10320Sstevel@tonic-gate /* If changing to suid root, must have all zone privs */ 10330Sstevel@tonic-gate boolean_t allzone = B_TRUE; 10340Sstevel@tonic-gate 10350Sstevel@tonic-gate if (owner != 0) { 10360Sstevel@tonic-gate if (owner == cr->cr_uid) 10370Sstevel@tonic-gate return (0); 10380Sstevel@tonic-gate allzone = B_FALSE; 10390Sstevel@tonic-gate } 10400Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_FILE_SETID, allzone, EPERM, NULL)); 10410Sstevel@tonic-gate } 10420Sstevel@tonic-gate 10430Sstevel@tonic-gate /* 10440Sstevel@tonic-gate * Are we allowed to retain the set-uid/set-gid bits when 10450Sstevel@tonic-gate * changing ownership or when writing to a file? 10460Sstevel@tonic-gate * "issuid" should be true when set-uid; only in that case 10470Sstevel@tonic-gate * root ownership is checked (setgid is assumed). 10480Sstevel@tonic-gate */ 10490Sstevel@tonic-gate int 10500Sstevel@tonic-gate secpolicy_vnode_setid_retain(const cred_t *cred, boolean_t issuidroot) 10510Sstevel@tonic-gate { 10520Sstevel@tonic-gate if (issuidroot && !HAS_ALLZONEPRIVS(cred)) 10530Sstevel@tonic-gate return (EPERM); 10540Sstevel@tonic-gate 10550Sstevel@tonic-gate return (!PRIV_POLICY_CHOICE(cred, PRIV_FILE_SETID, B_FALSE)); 10560Sstevel@tonic-gate } 10570Sstevel@tonic-gate 10580Sstevel@tonic-gate /* 10590Sstevel@tonic-gate * Name: secpolicy_vnode_setids_setgids() 10600Sstevel@tonic-gate * 10610Sstevel@tonic-gate * Normal: verify that subject can set the file setgid flag. 10620Sstevel@tonic-gate * 10630Sstevel@tonic-gate * Output: EPERM - if not privileged 10640Sstevel@tonic-gate */ 10650Sstevel@tonic-gate 10660Sstevel@tonic-gate int 10670Sstevel@tonic-gate secpolicy_vnode_setids_setgids(const cred_t *cred, gid_t gid) 10680Sstevel@tonic-gate { 10690Sstevel@tonic-gate if (!groupmember(gid, cred)) 10700Sstevel@tonic-gate return (PRIV_POLICY(cred, PRIV_FILE_SETID, B_FALSE, EPERM, 10710Sstevel@tonic-gate NULL)); 10720Sstevel@tonic-gate return (0); 10730Sstevel@tonic-gate } 10740Sstevel@tonic-gate 10750Sstevel@tonic-gate /* 10767624SMark.Shellenbaum@Sun.COM * Name: secpolicy_vnode_chown 10777624SMark.Shellenbaum@Sun.COM * 10787624SMark.Shellenbaum@Sun.COM * Normal: Determine if subject can chown owner of a file. 10797624SMark.Shellenbaum@Sun.COM * 10807624SMark.Shellenbaum@Sun.COM * Output: EPERM - if access denied 10817624SMark.Shellenbaum@Sun.COM */ 10827624SMark.Shellenbaum@Sun.COM 10837624SMark.Shellenbaum@Sun.COM int 10849866SMark.Shellenbaum@Sun.COM secpolicy_vnode_chown(const cred_t *cred, uid_t owner) 10857624SMark.Shellenbaum@Sun.COM { 10869866SMark.Shellenbaum@Sun.COM boolean_t is_owner = (owner == crgetuid(cred)); 10879866SMark.Shellenbaum@Sun.COM boolean_t allzone = B_FALSE; 10889866SMark.Shellenbaum@Sun.COM int priv; 10899866SMark.Shellenbaum@Sun.COM 10909866SMark.Shellenbaum@Sun.COM if (!is_owner) { 10919866SMark.Shellenbaum@Sun.COM allzone = (owner == 0); 10929866SMark.Shellenbaum@Sun.COM priv = PRIV_FILE_CHOWN; 10939866SMark.Shellenbaum@Sun.COM } else { 10949866SMark.Shellenbaum@Sun.COM priv = HAS_PRIVILEGE(cred, PRIV_FILE_CHOWN) ? 10959866SMark.Shellenbaum@Sun.COM PRIV_FILE_CHOWN : PRIV_FILE_CHOWN_SELF; 10969866SMark.Shellenbaum@Sun.COM } 10979866SMark.Shellenbaum@Sun.COM 10989866SMark.Shellenbaum@Sun.COM return (PRIV_POLICY(cred, priv, allzone, EPERM, NULL)); 10997624SMark.Shellenbaum@Sun.COM } 11007624SMark.Shellenbaum@Sun.COM 11017624SMark.Shellenbaum@Sun.COM /* 11027624SMark.Shellenbaum@Sun.COM * Name: secpolicy_vnode_create_gid 11037624SMark.Shellenbaum@Sun.COM * 11047624SMark.Shellenbaum@Sun.COM * Normal: Determine if subject can change group ownership of a file. 11057624SMark.Shellenbaum@Sun.COM * 11067624SMark.Shellenbaum@Sun.COM * Output: EPERM - if access denied 11070Sstevel@tonic-gate */ 11080Sstevel@tonic-gate int 11090Sstevel@tonic-gate secpolicy_vnode_create_gid(const cred_t *cred) 11100Sstevel@tonic-gate { 11119866SMark.Shellenbaum@Sun.COM if (HAS_PRIVILEGE(cred, PRIV_FILE_CHOWN)) 11129866SMark.Shellenbaum@Sun.COM return (PRIV_POLICY(cred, PRIV_FILE_CHOWN, B_FALSE, EPERM, 11139866SMark.Shellenbaum@Sun.COM NULL)); 11149866SMark.Shellenbaum@Sun.COM else 11159866SMark.Shellenbaum@Sun.COM return (PRIV_POLICY(cred, PRIV_FILE_CHOWN_SELF, B_FALSE, EPERM, 11169866SMark.Shellenbaum@Sun.COM NULL)); 11170Sstevel@tonic-gate } 11180Sstevel@tonic-gate 11190Sstevel@tonic-gate /* 11200Sstevel@tonic-gate * Name: secpolicy_vnode_utime_modify() 11210Sstevel@tonic-gate * 11220Sstevel@tonic-gate * Normal: verify that subject can modify the utime on a file. 11230Sstevel@tonic-gate * 11240Sstevel@tonic-gate * Output: EPERM - if access denied. 11250Sstevel@tonic-gate */ 11260Sstevel@tonic-gate 11270Sstevel@tonic-gate static int 11280Sstevel@tonic-gate secpolicy_vnode_utime_modify(const cred_t *cred) 11290Sstevel@tonic-gate { 11300Sstevel@tonic-gate return (PRIV_POLICY(cred, PRIV_FILE_OWNER, B_FALSE, EPERM, 11310Sstevel@tonic-gate "modify file times")); 11320Sstevel@tonic-gate } 11330Sstevel@tonic-gate 11340Sstevel@tonic-gate 11350Sstevel@tonic-gate /* 11360Sstevel@tonic-gate * Name: secpolicy_vnode_setdac() 11370Sstevel@tonic-gate * 11380Sstevel@tonic-gate * Normal: verify that subject can modify the mode of a file. 11390Sstevel@tonic-gate * allzone privilege needed when modifying root owned object. 11400Sstevel@tonic-gate * 11410Sstevel@tonic-gate * Output: EPERM - if access denied. 11420Sstevel@tonic-gate */ 11430Sstevel@tonic-gate 11440Sstevel@tonic-gate int 11450Sstevel@tonic-gate secpolicy_vnode_setdac(const cred_t *cred, uid_t owner) 11460Sstevel@tonic-gate { 11470Sstevel@tonic-gate if (owner == cred->cr_uid) 11480Sstevel@tonic-gate return (0); 11490Sstevel@tonic-gate 11500Sstevel@tonic-gate return (PRIV_POLICY(cred, PRIV_FILE_OWNER, owner == 0, EPERM, NULL)); 11510Sstevel@tonic-gate } 11520Sstevel@tonic-gate /* 11530Sstevel@tonic-gate * Name: secpolicy_vnode_stky_modify() 11540Sstevel@tonic-gate * 11550Sstevel@tonic-gate * Normal: verify that subject can make a file a "sticky". 11560Sstevel@tonic-gate * 11570Sstevel@tonic-gate * Output: EPERM - if access denied. 11580Sstevel@tonic-gate */ 11590Sstevel@tonic-gate 11600Sstevel@tonic-gate int 11610Sstevel@tonic-gate secpolicy_vnode_stky_modify(const cred_t *cred) 11620Sstevel@tonic-gate { 11630Sstevel@tonic-gate return (PRIV_POLICY(cred, PRIV_SYS_CONFIG, B_FALSE, EPERM, 11640Sstevel@tonic-gate "set file sticky")); 11650Sstevel@tonic-gate } 11660Sstevel@tonic-gate 11670Sstevel@tonic-gate /* 11680Sstevel@tonic-gate * Policy determines whether we can remove an entry from a directory, 11690Sstevel@tonic-gate * regardless of permission bits. 11700Sstevel@tonic-gate */ 11710Sstevel@tonic-gate int 11720Sstevel@tonic-gate secpolicy_vnode_remove(const cred_t *cr) 11730Sstevel@tonic-gate { 11740Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_FILE_OWNER, B_FALSE, EACCES, 11750Sstevel@tonic-gate "sticky directory")); 11760Sstevel@tonic-gate } 11770Sstevel@tonic-gate 11780Sstevel@tonic-gate int 11790Sstevel@tonic-gate secpolicy_vnode_owner(const cred_t *cr, uid_t owner) 11800Sstevel@tonic-gate { 11810Sstevel@tonic-gate boolean_t allzone = (owner == 0); 11820Sstevel@tonic-gate 11830Sstevel@tonic-gate if (owner == cr->cr_uid) 11840Sstevel@tonic-gate return (0); 11850Sstevel@tonic-gate 11860Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_FILE_OWNER, allzone, EPERM, NULL)); 11870Sstevel@tonic-gate } 11880Sstevel@tonic-gate 11891115Smarks void 11901115Smarks secpolicy_setid_clear(vattr_t *vap, cred_t *cr) 11911115Smarks { 11921115Smarks if ((vap->va_mode & (S_ISUID | S_ISGID)) != 0 && 11931115Smarks secpolicy_vnode_setid_retain(cr, 11941115Smarks (vap->va_mode & S_ISUID) != 0 && 11951115Smarks (vap->va_mask & AT_UID) != 0 && vap->va_uid == 0) != 0) { 11961115Smarks vap->va_mask |= AT_MODE; 11971115Smarks vap->va_mode &= ~(S_ISUID|S_ISGID); 11981115Smarks } 11991115Smarks } 12001115Smarks 12012796Smarks int 12022796Smarks secpolicy_setid_setsticky_clear(vnode_t *vp, vattr_t *vap, const vattr_t *ovap, 12032796Smarks cred_t *cr) 12042796Smarks { 12052796Smarks int error; 12062796Smarks 12072796Smarks if ((vap->va_mode & S_ISUID) != 0 && 12082796Smarks (error = secpolicy_vnode_setid_modify(cr, 12092796Smarks ovap->va_uid)) != 0) { 12102796Smarks return (error); 12112796Smarks } 12122796Smarks 12132796Smarks /* 12142796Smarks * Check privilege if attempting to set the 12152796Smarks * sticky bit on a non-directory. 12162796Smarks */ 12172796Smarks if (vp->v_type != VDIR && (vap->va_mode & S_ISVTX) != 0 && 12182796Smarks secpolicy_vnode_stky_modify(cr) != 0) { 12194543Smarks vap->va_mode &= ~S_ISVTX; 12202796Smarks } 12212796Smarks 12222796Smarks /* 12232796Smarks * Check for privilege if attempting to set the 12242796Smarks * group-id bit. 12252796Smarks */ 12262796Smarks if ((vap->va_mode & S_ISGID) != 0 && 12272796Smarks secpolicy_vnode_setids_setgids(cr, ovap->va_gid) != 0) { 12284543Smarks vap->va_mode &= ~S_ISGID; 12292796Smarks } 12302796Smarks 12312796Smarks return (0); 12322796Smarks } 12332796Smarks 12345331Samw #define ATTR_FLAG_PRIV(attr, value, cr) \ 12355331Samw PRIV_POLICY(cr, value ? PRIV_FILE_FLAG_SET : PRIV_ALL, \ 12365331Samw B_FALSE, EPERM, NULL) 12375331Samw 12385331Samw /* 12395331Samw * Check privileges for setting xvattr attributes 12405331Samw */ 12415331Samw int 12425331Samw secpolicy_xvattr(xvattr_t *xvap, uid_t owner, cred_t *cr, vtype_t vtype) 12435331Samw { 12445331Samw xoptattr_t *xoap; 12455331Samw int error = 0; 12465331Samw 12475331Samw if ((xoap = xva_getxoptattr(xvap)) == NULL) 12485331Samw return (EINVAL); 12495331Samw 12505331Samw /* 12515331Samw * First process the DOS bits 12525331Samw */ 12535331Samw if (XVA_ISSET_REQ(xvap, XAT_ARCHIVE) || 12545331Samw XVA_ISSET_REQ(xvap, XAT_HIDDEN) || 12555331Samw XVA_ISSET_REQ(xvap, XAT_READONLY) || 12565331Samw XVA_ISSET_REQ(xvap, XAT_SYSTEM) || 12575331Samw XVA_ISSET_REQ(xvap, XAT_CREATETIME)) { 12585331Samw if ((error = secpolicy_vnode_owner(cr, owner)) != 0) 12595331Samw return (error); 12605331Samw } 12615331Samw 12625331Samw /* 12635331Samw * Now handle special attributes 12645331Samw */ 12655331Samw 12665331Samw if (XVA_ISSET_REQ(xvap, XAT_IMMUTABLE)) 12675331Samw error = ATTR_FLAG_PRIV(XAT_IMMUTABLE, 12685331Samw xoap->xoa_immutable, cr); 12695331Samw if (error == 0 && XVA_ISSET_REQ(xvap, XAT_NOUNLINK)) 12705331Samw error = ATTR_FLAG_PRIV(XAT_NOUNLINK, 12715331Samw xoap->xoa_nounlink, cr); 12725331Samw if (error == 0 && XVA_ISSET_REQ(xvap, XAT_APPENDONLY)) 12735331Samw error = ATTR_FLAG_PRIV(XAT_APPENDONLY, 12745331Samw xoap->xoa_appendonly, cr); 12755331Samw if (error == 0 && XVA_ISSET_REQ(xvap, XAT_NODUMP)) 12765331Samw error = ATTR_FLAG_PRIV(XAT_NODUMP, 12775331Samw xoap->xoa_nodump, cr); 12785331Samw if (error == 0 && XVA_ISSET_REQ(xvap, XAT_OPAQUE)) 12795331Samw error = EPERM; 12805331Samw if (error == 0 && XVA_ISSET_REQ(xvap, XAT_AV_QUARANTINED)) { 12815331Samw error = ATTR_FLAG_PRIV(XAT_AV_QUARANTINED, 12825331Samw xoap->xoa_av_quarantined, cr); 12835545Smarks if (error == 0 && vtype != VREG && xoap->xoa_av_quarantined) 12845331Samw error = EINVAL; 12855331Samw } 12865331Samw if (error == 0 && XVA_ISSET_REQ(xvap, XAT_AV_MODIFIED)) 12875331Samw error = ATTR_FLAG_PRIV(XAT_AV_MODIFIED, 12885331Samw xoap->xoa_av_modified, cr); 12895331Samw if (error == 0 && XVA_ISSET_REQ(xvap, XAT_AV_SCANSTAMP)) { 12905331Samw error = ATTR_FLAG_PRIV(XAT_AV_SCANSTAMP, 12915331Samw xoap->xoa_av_scanstamp, cr); 12925331Samw if (error == 0 && vtype != VREG) 12935331Samw error = EINVAL; 12945331Samw } 12955331Samw return (error); 12965331Samw } 12975331Samw 12980Sstevel@tonic-gate /* 12990Sstevel@tonic-gate * This function checks the policy decisions surrounding the 13000Sstevel@tonic-gate * vop setattr call. 13010Sstevel@tonic-gate * 13020Sstevel@tonic-gate * It should be called after sufficient locks have been established 13030Sstevel@tonic-gate * on the underlying data structures. No concurrent modifications 13040Sstevel@tonic-gate * should be allowed. 13050Sstevel@tonic-gate * 13060Sstevel@tonic-gate * The caller must pass in unlocked version of its vaccess function 13070Sstevel@tonic-gate * this is required because vop_access function should lock the 13080Sstevel@tonic-gate * node for reading. A three argument function should be defined 13090Sstevel@tonic-gate * which accepts the following argument: 13100Sstevel@tonic-gate * A pointer to the internal "node" type (inode *) 13110Sstevel@tonic-gate * vnode access bits (VREAD|VWRITE|VEXEC) 13120Sstevel@tonic-gate * a pointer to the credential 13130Sstevel@tonic-gate * 13140Sstevel@tonic-gate * This function makes the following policy decisions: 13150Sstevel@tonic-gate * 13160Sstevel@tonic-gate * - change permissions 13170Sstevel@tonic-gate * - permission to change file mode if not owner 13180Sstevel@tonic-gate * - permission to add sticky bit to non-directory 13190Sstevel@tonic-gate * - permission to add set-gid bit 13200Sstevel@tonic-gate * 13210Sstevel@tonic-gate * The ovap argument should include AT_MODE|AT_UID|AT_GID. 13220Sstevel@tonic-gate * 13230Sstevel@tonic-gate * If the vap argument does not include AT_MODE, the mode will be copied from 13240Sstevel@tonic-gate * ovap. In certain situations set-uid/set-gid bits need to be removed; 13250Sstevel@tonic-gate * this is done by marking vap->va_mask to include AT_MODE and va_mode 13260Sstevel@tonic-gate * is updated to the newly computed mode. 13270Sstevel@tonic-gate */ 13280Sstevel@tonic-gate 13290Sstevel@tonic-gate int 13300Sstevel@tonic-gate secpolicy_vnode_setattr(cred_t *cr, struct vnode *vp, struct vattr *vap, 13310Sstevel@tonic-gate const struct vattr *ovap, int flags, 13320Sstevel@tonic-gate int unlocked_access(void *, int, cred_t *), 13330Sstevel@tonic-gate void *node) 13340Sstevel@tonic-gate { 13350Sstevel@tonic-gate int mask = vap->va_mask; 13360Sstevel@tonic-gate int error = 0; 13375331Samw boolean_t skipaclchk = (flags & ATTR_NOACLCHECK) ? B_TRUE : B_FALSE; 13380Sstevel@tonic-gate 13390Sstevel@tonic-gate if (mask & AT_SIZE) { 13400Sstevel@tonic-gate if (vp->v_type == VDIR) { 13410Sstevel@tonic-gate error = EISDIR; 13420Sstevel@tonic-gate goto out; 13430Sstevel@tonic-gate } 13445331Samw 13455331Samw /* 13465331Samw * If ATTR_NOACLCHECK is set in the flags, then we don't 13475331Samw * perform the secondary unlocked_access() call since the 13485331Samw * ACL (if any) is being checked there. 13495331Samw */ 13505331Samw if (skipaclchk == B_FALSE) { 13515331Samw error = unlocked_access(node, VWRITE, cr); 13525331Samw if (error) 13535331Samw goto out; 13545331Samw } 13550Sstevel@tonic-gate } 13560Sstevel@tonic-gate if (mask & AT_MODE) { 13570Sstevel@tonic-gate /* 13580Sstevel@tonic-gate * If not the owner of the file then check privilege 13590Sstevel@tonic-gate * for two things: the privilege to set the mode at all 13600Sstevel@tonic-gate * and, if we're setting setuid, we also need permissions 13610Sstevel@tonic-gate * to add the set-uid bit, if we're not the owner. 13620Sstevel@tonic-gate * In the specific case of creating a set-uid root 13630Sstevel@tonic-gate * file, we need even more permissions. 13640Sstevel@tonic-gate */ 13650Sstevel@tonic-gate if ((error = secpolicy_vnode_setdac(cr, ovap->va_uid)) != 0) 13660Sstevel@tonic-gate goto out; 13670Sstevel@tonic-gate 13682796Smarks if ((error = secpolicy_setid_setsticky_clear(vp, vap, 13692796Smarks ovap, cr)) != 0) 13700Sstevel@tonic-gate goto out; 13710Sstevel@tonic-gate } else 13720Sstevel@tonic-gate vap->va_mode = ovap->va_mode; 13730Sstevel@tonic-gate 13740Sstevel@tonic-gate if (mask & (AT_UID|AT_GID)) { 13750Sstevel@tonic-gate boolean_t checkpriv = B_FALSE; 13760Sstevel@tonic-gate 13770Sstevel@tonic-gate /* 13780Sstevel@tonic-gate * Chowning files. 13790Sstevel@tonic-gate * 13800Sstevel@tonic-gate * If you are the file owner: 13810Sstevel@tonic-gate * chown to other uid FILE_CHOWN_SELF 13820Sstevel@tonic-gate * chown to gid (non-member) FILE_CHOWN_SELF 13830Sstevel@tonic-gate * chown to gid (member) <none> 13840Sstevel@tonic-gate * 13850Sstevel@tonic-gate * Instead of PRIV_FILE_CHOWN_SELF, FILE_CHOWN is also 13860Sstevel@tonic-gate * acceptable but the first one is reported when debugging. 13870Sstevel@tonic-gate * 13880Sstevel@tonic-gate * If you are not the file owner: 13890Sstevel@tonic-gate * chown from root PRIV_FILE_CHOWN + zone 13900Sstevel@tonic-gate * chown from other to any PRIV_FILE_CHOWN 13910Sstevel@tonic-gate * 13920Sstevel@tonic-gate */ 13930Sstevel@tonic-gate if (cr->cr_uid != ovap->va_uid) { 13940Sstevel@tonic-gate checkpriv = B_TRUE; 13950Sstevel@tonic-gate } else { 13960Sstevel@tonic-gate if (((mask & AT_UID) && vap->va_uid != ovap->va_uid) || 13970Sstevel@tonic-gate ((mask & AT_GID) && vap->va_gid != ovap->va_gid && 13980Sstevel@tonic-gate !groupmember(vap->va_gid, cr))) { 13990Sstevel@tonic-gate checkpriv = B_TRUE; 14000Sstevel@tonic-gate } 14010Sstevel@tonic-gate } 14020Sstevel@tonic-gate /* 14030Sstevel@tonic-gate * If necessary, check privilege to see if update can be done. 14040Sstevel@tonic-gate */ 14050Sstevel@tonic-gate if (checkpriv && 14069866SMark.Shellenbaum@Sun.COM (error = secpolicy_vnode_chown(cr, ovap->va_uid)) != 0) { 14070Sstevel@tonic-gate goto out; 14080Sstevel@tonic-gate } 14090Sstevel@tonic-gate 14100Sstevel@tonic-gate /* 14110Sstevel@tonic-gate * If the file has either the set UID or set GID bits 14120Sstevel@tonic-gate * set and the caller can set the bits, then leave them. 14130Sstevel@tonic-gate */ 14141115Smarks secpolicy_setid_clear(vap, cr); 14150Sstevel@tonic-gate } 14160Sstevel@tonic-gate if (mask & (AT_ATIME|AT_MTIME)) { 14170Sstevel@tonic-gate /* 14180Sstevel@tonic-gate * If not the file owner and not otherwise privileged, 14190Sstevel@tonic-gate * always return an error when setting the 14200Sstevel@tonic-gate * time other than the current (ATTR_UTIME flag set). 14210Sstevel@tonic-gate * If setting the current time (ATTR_UTIME not set) then 14220Sstevel@tonic-gate * unlocked_access will check permissions according to policy. 14230Sstevel@tonic-gate */ 14240Sstevel@tonic-gate if (cr->cr_uid != ovap->va_uid) { 14250Sstevel@tonic-gate if (flags & ATTR_UTIME) 14260Sstevel@tonic-gate error = secpolicy_vnode_utime_modify(cr); 14275331Samw else if (skipaclchk == B_FALSE) { 14280Sstevel@tonic-gate error = unlocked_access(node, VWRITE, cr); 14290Sstevel@tonic-gate if (error == EACCES && 14300Sstevel@tonic-gate secpolicy_vnode_utime_modify(cr) == 0) 14310Sstevel@tonic-gate error = 0; 14320Sstevel@tonic-gate } 14330Sstevel@tonic-gate if (error) 14340Sstevel@tonic-gate goto out; 14350Sstevel@tonic-gate } 14360Sstevel@tonic-gate } 14375331Samw 14385331Samw /* 14395331Samw * Check for optional attributes here by checking the following: 14405331Samw */ 14415331Samw if (mask & AT_XVATTR) 14425331Samw error = secpolicy_xvattr((xvattr_t *)vap, ovap->va_uid, cr, 14435331Samw vp->v_type); 14440Sstevel@tonic-gate out: 14450Sstevel@tonic-gate return (error); 14460Sstevel@tonic-gate } 14470Sstevel@tonic-gate 14480Sstevel@tonic-gate /* 14490Sstevel@tonic-gate * Name: secpolicy_pcfs_modify_bootpartition() 14500Sstevel@tonic-gate * 14510Sstevel@tonic-gate * Normal: verify that subject can modify a pcfs boot partition. 14520Sstevel@tonic-gate * 14530Sstevel@tonic-gate * Output: EACCES - if privilege check failed. 14540Sstevel@tonic-gate */ 14550Sstevel@tonic-gate /*ARGSUSED*/ 14560Sstevel@tonic-gate int 14570Sstevel@tonic-gate secpolicy_pcfs_modify_bootpartition(const cred_t *cred) 14580Sstevel@tonic-gate { 14590Sstevel@tonic-gate return (PRIV_POLICY(cred, PRIV_ALL, B_FALSE, EACCES, 14600Sstevel@tonic-gate "modify pcfs boot partition")); 14610Sstevel@tonic-gate } 14620Sstevel@tonic-gate 14630Sstevel@tonic-gate /* 14640Sstevel@tonic-gate * System V IPC routines 14650Sstevel@tonic-gate */ 14660Sstevel@tonic-gate int 14670Sstevel@tonic-gate secpolicy_ipc_owner(const cred_t *cr, const struct kipc_perm *ip) 14680Sstevel@tonic-gate { 14690Sstevel@tonic-gate if (crgetzoneid(cr) != ip->ipc_zoneid || 14700Sstevel@tonic-gate (cr->cr_uid != ip->ipc_uid && cr->cr_uid != ip->ipc_cuid)) { 14710Sstevel@tonic-gate boolean_t allzone = B_FALSE; 14720Sstevel@tonic-gate if (ip->ipc_uid == 0 || ip->ipc_cuid == 0) 14730Sstevel@tonic-gate allzone = B_TRUE; 14740Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_IPC_OWNER, allzone, EPERM, NULL)); 14750Sstevel@tonic-gate } 14760Sstevel@tonic-gate return (0); 14770Sstevel@tonic-gate } 14780Sstevel@tonic-gate 14790Sstevel@tonic-gate int 14800Sstevel@tonic-gate secpolicy_ipc_config(const cred_t *cr) 14810Sstevel@tonic-gate { 14820Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_IPC_CONFIG, B_FALSE, EPERM, NULL)); 14830Sstevel@tonic-gate } 14840Sstevel@tonic-gate 14850Sstevel@tonic-gate int 14860Sstevel@tonic-gate secpolicy_ipc_access(const cred_t *cr, const struct kipc_perm *ip, mode_t mode) 14870Sstevel@tonic-gate { 14880Sstevel@tonic-gate 14890Sstevel@tonic-gate boolean_t allzone = B_FALSE; 14900Sstevel@tonic-gate 14910Sstevel@tonic-gate ASSERT((mode & (MSG_R|MSG_W)) != 0); 14920Sstevel@tonic-gate 14930Sstevel@tonic-gate if ((mode & MSG_R) && 14940Sstevel@tonic-gate PRIV_POLICY(cr, PRIV_IPC_DAC_READ, allzone, EACCES, NULL) != 0) 14950Sstevel@tonic-gate return (EACCES); 14960Sstevel@tonic-gate 14970Sstevel@tonic-gate if (mode & MSG_W) { 14980Sstevel@tonic-gate if (cr->cr_uid != 0 && (ip->ipc_uid == 0 || ip->ipc_cuid == 0)) 14990Sstevel@tonic-gate allzone = B_TRUE; 15000Sstevel@tonic-gate 15010Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_IPC_DAC_WRITE, allzone, EACCES, 15020Sstevel@tonic-gate NULL)); 15030Sstevel@tonic-gate } 15040Sstevel@tonic-gate return (0); 15050Sstevel@tonic-gate } 15060Sstevel@tonic-gate 15070Sstevel@tonic-gate int 15080Sstevel@tonic-gate secpolicy_rsm_access(const cred_t *cr, uid_t owner, mode_t mode) 15090Sstevel@tonic-gate { 15100Sstevel@tonic-gate boolean_t allzone = B_FALSE; 15110Sstevel@tonic-gate 15120Sstevel@tonic-gate ASSERT((mode & (MSG_R|MSG_W)) != 0); 15130Sstevel@tonic-gate 15140Sstevel@tonic-gate if ((mode & MSG_R) && 15150Sstevel@tonic-gate PRIV_POLICY(cr, PRIV_IPC_DAC_READ, allzone, EACCES, NULL) != 0) 15160Sstevel@tonic-gate return (EACCES); 15170Sstevel@tonic-gate 15180Sstevel@tonic-gate if (mode & MSG_W) { 15190Sstevel@tonic-gate if (cr->cr_uid != 0 && owner == 0) 15200Sstevel@tonic-gate allzone = B_TRUE; 15210Sstevel@tonic-gate 15220Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_IPC_DAC_WRITE, allzone, EACCES, 15230Sstevel@tonic-gate NULL)); 15240Sstevel@tonic-gate } 15250Sstevel@tonic-gate return (0); 15260Sstevel@tonic-gate } 15270Sstevel@tonic-gate 15280Sstevel@tonic-gate /* 15290Sstevel@tonic-gate * Audit configuration. 15300Sstevel@tonic-gate */ 15310Sstevel@tonic-gate int 15320Sstevel@tonic-gate secpolicy_audit_config(const cred_t *cr) 15330Sstevel@tonic-gate { 15340Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_AUDIT, B_FALSE, EPERM, NULL)); 15350Sstevel@tonic-gate } 15360Sstevel@tonic-gate 15370Sstevel@tonic-gate /* 15380Sstevel@tonic-gate * Audit record generation. 15390Sstevel@tonic-gate */ 15400Sstevel@tonic-gate int 15410Sstevel@tonic-gate secpolicy_audit_modify(const cred_t *cr) 15420Sstevel@tonic-gate { 15430Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_PROC_AUDIT, B_FALSE, EPERM, NULL)); 15440Sstevel@tonic-gate } 15450Sstevel@tonic-gate 15460Sstevel@tonic-gate /* 15470Sstevel@tonic-gate * Get audit attributes. 15480Sstevel@tonic-gate * Either PRIV_SYS_AUDIT or PRIV_PROC_AUDIT required; report the 15490Sstevel@tonic-gate * "Least" of the two privileges on error. 15500Sstevel@tonic-gate */ 15510Sstevel@tonic-gate int 155212273SCasper.Dik@Sun.COM secpolicy_audit_getattr(const cred_t *cr, boolean_t checkonly) 15530Sstevel@tonic-gate { 155412273SCasper.Dik@Sun.COM int priv; 155512273SCasper.Dik@Sun.COM 155612273SCasper.Dik@Sun.COM if (PRIV_POLICY_ONLY(cr, PRIV_SYS_AUDIT, B_FALSE)) 155712273SCasper.Dik@Sun.COM priv = PRIV_SYS_AUDIT; 155812273SCasper.Dik@Sun.COM else 155912273SCasper.Dik@Sun.COM priv = PRIV_PROC_AUDIT; 156012273SCasper.Dik@Sun.COM 156112273SCasper.Dik@Sun.COM if (checkonly) 156212273SCasper.Dik@Sun.COM return (!PRIV_POLICY_ONLY(cr, priv, B_FALSE)); 156312273SCasper.Dik@Sun.COM else 156412273SCasper.Dik@Sun.COM return (PRIV_POLICY(cr, priv, B_FALSE, EPERM, NULL)); 15650Sstevel@tonic-gate } 15660Sstevel@tonic-gate 15670Sstevel@tonic-gate 15680Sstevel@tonic-gate /* 15690Sstevel@tonic-gate * Locking physical memory 15700Sstevel@tonic-gate */ 15710Sstevel@tonic-gate int 15720Sstevel@tonic-gate secpolicy_lock_memory(const cred_t *cr) 15730Sstevel@tonic-gate { 15740Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_PROC_LOCK_MEMORY, B_FALSE, EPERM, NULL)); 15750Sstevel@tonic-gate } 15760Sstevel@tonic-gate 15770Sstevel@tonic-gate /* 15780Sstevel@tonic-gate * Accounting (both acct(2) and exacct). 15790Sstevel@tonic-gate */ 15800Sstevel@tonic-gate int 15810Sstevel@tonic-gate secpolicy_acct(const cred_t *cr) 15820Sstevel@tonic-gate { 15830Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_ACCT, B_FALSE, EPERM, NULL)); 15840Sstevel@tonic-gate } 15850Sstevel@tonic-gate 15860Sstevel@tonic-gate /* 15870Sstevel@tonic-gate * Is this process privileged to change its uids at will? 15880Sstevel@tonic-gate * Uid 0 is still considered "special" and having the SETID 15890Sstevel@tonic-gate * privilege is not sufficient to get uid 0. 15900Sstevel@tonic-gate * Files are owned by root, so the privilege would give 15910Sstevel@tonic-gate * full access and euid 0 is still effective. 15920Sstevel@tonic-gate * 15930Sstevel@tonic-gate * If you have the privilege and euid 0 only then do you 15940Sstevel@tonic-gate * get the powers of root wrt uid 0. 15950Sstevel@tonic-gate * 15960Sstevel@tonic-gate * For gid manipulations, this is should be called with an 15970Sstevel@tonic-gate * uid of -1. 15980Sstevel@tonic-gate * 15990Sstevel@tonic-gate */ 16000Sstevel@tonic-gate int 16010Sstevel@tonic-gate secpolicy_allow_setid(const cred_t *cr, uid_t newuid, boolean_t checkonly) 16020Sstevel@tonic-gate { 16030Sstevel@tonic-gate boolean_t allzone = B_FALSE; 16040Sstevel@tonic-gate 16050Sstevel@tonic-gate if (newuid == 0 && cr->cr_uid != 0 && cr->cr_suid != 0 && 16060Sstevel@tonic-gate cr->cr_ruid != 0) { 16070Sstevel@tonic-gate allzone = B_TRUE; 16080Sstevel@tonic-gate } 16090Sstevel@tonic-gate 16100Sstevel@tonic-gate return (checkonly ? !PRIV_POLICY_ONLY(cr, PRIV_PROC_SETID, allzone) : 16110Sstevel@tonic-gate PRIV_POLICY(cr, PRIV_PROC_SETID, allzone, EPERM, NULL)); 16120Sstevel@tonic-gate } 16130Sstevel@tonic-gate 16140Sstevel@tonic-gate 16150Sstevel@tonic-gate /* 16160Sstevel@tonic-gate * Acting on a different process: if the mode is for writing, 16170Sstevel@tonic-gate * the restrictions are more severe. This is called after 16180Sstevel@tonic-gate * we've verified that the uids do not match. 16190Sstevel@tonic-gate */ 16200Sstevel@tonic-gate int 16210Sstevel@tonic-gate secpolicy_proc_owner(const cred_t *scr, const cred_t *tcr, int mode) 16220Sstevel@tonic-gate { 16230Sstevel@tonic-gate boolean_t allzone = B_FALSE; 16240Sstevel@tonic-gate 16250Sstevel@tonic-gate if ((mode & VWRITE) && scr->cr_uid != 0 && 16260Sstevel@tonic-gate (tcr->cr_uid == 0 || tcr->cr_ruid == 0 || tcr->cr_suid == 0)) 16270Sstevel@tonic-gate allzone = B_TRUE; 16280Sstevel@tonic-gate 16290Sstevel@tonic-gate return (PRIV_POLICY(scr, PRIV_PROC_OWNER, allzone, EPERM, NULL)); 16300Sstevel@tonic-gate } 16310Sstevel@tonic-gate 16320Sstevel@tonic-gate int 16330Sstevel@tonic-gate secpolicy_proc_access(const cred_t *scr) 16340Sstevel@tonic-gate { 16350Sstevel@tonic-gate return (PRIV_POLICY(scr, PRIV_PROC_OWNER, B_FALSE, EACCES, NULL)); 16360Sstevel@tonic-gate } 16370Sstevel@tonic-gate 16380Sstevel@tonic-gate int 16390Sstevel@tonic-gate secpolicy_proc_excl_open(const cred_t *scr) 16400Sstevel@tonic-gate { 16410Sstevel@tonic-gate return (PRIV_POLICY(scr, PRIV_PROC_OWNER, B_FALSE, EBUSY, NULL)); 16420Sstevel@tonic-gate } 16430Sstevel@tonic-gate 16440Sstevel@tonic-gate int 16450Sstevel@tonic-gate secpolicy_proc_zone(const cred_t *scr) 16460Sstevel@tonic-gate { 16470Sstevel@tonic-gate return (PRIV_POLICY(scr, PRIV_PROC_ZONE, B_FALSE, EPERM, NULL)); 16480Sstevel@tonic-gate } 16490Sstevel@tonic-gate 16500Sstevel@tonic-gate /* 16510Sstevel@tonic-gate * Destroying the system 16520Sstevel@tonic-gate */ 16530Sstevel@tonic-gate 16540Sstevel@tonic-gate int 16550Sstevel@tonic-gate secpolicy_kmdb(const cred_t *scr) 16560Sstevel@tonic-gate { 16570Sstevel@tonic-gate return (PRIV_POLICY(scr, PRIV_ALL, B_FALSE, EPERM, NULL)); 16580Sstevel@tonic-gate } 16590Sstevel@tonic-gate 16601414Scindi int 16611414Scindi secpolicy_error_inject(const cred_t *scr) 16621414Scindi { 16631414Scindi return (PRIV_POLICY(scr, PRIV_ALL, B_FALSE, EPERM, NULL)); 16641414Scindi } 16651414Scindi 16660Sstevel@tonic-gate /* 16670Sstevel@tonic-gate * Processor sets, cpu configuration, resource pools. 16680Sstevel@tonic-gate */ 16690Sstevel@tonic-gate int 16700Sstevel@tonic-gate secpolicy_pset(const cred_t *cr) 16710Sstevel@tonic-gate { 16720Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_RES_CONFIG, B_FALSE, EPERM, NULL)); 16730Sstevel@tonic-gate } 16740Sstevel@tonic-gate 1675*12494Sgerald.jelinek@sun.com /* 1676*12494Sgerald.jelinek@sun.com * Processor set binding. 1677*12494Sgerald.jelinek@sun.com */ 1678*12494Sgerald.jelinek@sun.com int 1679*12494Sgerald.jelinek@sun.com secpolicy_pbind(const cred_t *cr) 1680*12494Sgerald.jelinek@sun.com { 1681*12494Sgerald.jelinek@sun.com if (PRIV_POLICY_ONLY(cr, PRIV_SYS_RES_CONFIG, B_FALSE)) 1682*12494Sgerald.jelinek@sun.com return (secpolicy_pset(cr)); 1683*12494Sgerald.jelinek@sun.com return (PRIV_POLICY(cr, PRIV_SYS_RES_BIND, B_FALSE, EPERM, NULL)); 1684*12494Sgerald.jelinek@sun.com } 1685*12494Sgerald.jelinek@sun.com 16860Sstevel@tonic-gate int 16870Sstevel@tonic-gate secpolicy_ponline(const cred_t *cr) 16880Sstevel@tonic-gate { 16890Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_RES_CONFIG, B_FALSE, EPERM, NULL)); 16900Sstevel@tonic-gate } 16910Sstevel@tonic-gate 16920Sstevel@tonic-gate int 16930Sstevel@tonic-gate secpolicy_pool(const cred_t *cr) 16940Sstevel@tonic-gate { 16950Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_RES_CONFIG, B_FALSE, EPERM, NULL)); 16960Sstevel@tonic-gate } 16970Sstevel@tonic-gate 16980Sstevel@tonic-gate int 16990Sstevel@tonic-gate secpolicy_blacklist(const cred_t *cr) 17000Sstevel@tonic-gate { 17010Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_RES_CONFIG, B_FALSE, EPERM, NULL)); 17020Sstevel@tonic-gate } 17030Sstevel@tonic-gate 17040Sstevel@tonic-gate /* 17050Sstevel@tonic-gate * Catch all system configuration. 17060Sstevel@tonic-gate */ 17070Sstevel@tonic-gate int 17080Sstevel@tonic-gate secpolicy_sys_config(const cred_t *cr, boolean_t checkonly) 17090Sstevel@tonic-gate { 17100Sstevel@tonic-gate if (checkonly) { 17110Sstevel@tonic-gate return (PRIV_POLICY_ONLY(cr, PRIV_SYS_CONFIG, B_FALSE) ? 0 : 17120Sstevel@tonic-gate EPERM); 17130Sstevel@tonic-gate } else { 17140Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_CONFIG, B_FALSE, EPERM, NULL)); 17150Sstevel@tonic-gate } 17160Sstevel@tonic-gate } 17170Sstevel@tonic-gate 17180Sstevel@tonic-gate /* 17190Sstevel@tonic-gate * Zone administration (halt, reboot, etc.) from within zone. 17200Sstevel@tonic-gate */ 17210Sstevel@tonic-gate int 17220Sstevel@tonic-gate secpolicy_zone_admin(const cred_t *cr, boolean_t checkonly) 17230Sstevel@tonic-gate { 17240Sstevel@tonic-gate if (checkonly) { 17250Sstevel@tonic-gate return (PRIV_POLICY_ONLY(cr, PRIV_SYS_ADMIN, B_FALSE) ? 0 : 17260Sstevel@tonic-gate EPERM); 17270Sstevel@tonic-gate } else { 17280Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_ADMIN, B_FALSE, EPERM, 17290Sstevel@tonic-gate NULL)); 17300Sstevel@tonic-gate } 17310Sstevel@tonic-gate } 17320Sstevel@tonic-gate 17330Sstevel@tonic-gate /* 17340Sstevel@tonic-gate * Zone configuration (create, halt, enter). 17350Sstevel@tonic-gate */ 17360Sstevel@tonic-gate int 17370Sstevel@tonic-gate secpolicy_zone_config(const cred_t *cr) 17380Sstevel@tonic-gate { 17390Sstevel@tonic-gate /* 17400Sstevel@tonic-gate * Require all privileges to avoid possibility of privilege 17410Sstevel@tonic-gate * escalation. 17420Sstevel@tonic-gate */ 174312273SCasper.Dik@Sun.COM return (secpolicy_require_set(cr, PRIV_FULLSET, NULL, KLPDARG_NONE)); 17440Sstevel@tonic-gate } 17450Sstevel@tonic-gate 17460Sstevel@tonic-gate /* 17470Sstevel@tonic-gate * Various other system configuration calls 17480Sstevel@tonic-gate */ 17490Sstevel@tonic-gate int 17500Sstevel@tonic-gate secpolicy_coreadm(const cred_t *cr) 17510Sstevel@tonic-gate { 17520Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_ADMIN, B_FALSE, EPERM, NULL)); 17530Sstevel@tonic-gate } 17540Sstevel@tonic-gate 17550Sstevel@tonic-gate int 17560Sstevel@tonic-gate secpolicy_systeminfo(const cred_t *cr) 17570Sstevel@tonic-gate { 17580Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_ADMIN, B_FALSE, EPERM, NULL)); 17590Sstevel@tonic-gate } 17600Sstevel@tonic-gate 17610Sstevel@tonic-gate int 17620Sstevel@tonic-gate secpolicy_dispadm(const cred_t *cr) 17630Sstevel@tonic-gate { 17640Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_CONFIG, B_FALSE, EPERM, NULL)); 17650Sstevel@tonic-gate } 17660Sstevel@tonic-gate 17670Sstevel@tonic-gate int 17680Sstevel@tonic-gate secpolicy_settime(const cred_t *cr) 17690Sstevel@tonic-gate { 17700Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_TIME, B_FALSE, EPERM, NULL)); 17710Sstevel@tonic-gate } 17720Sstevel@tonic-gate 17730Sstevel@tonic-gate /* 17740Sstevel@tonic-gate * For realtime users: high resolution clock. 17750Sstevel@tonic-gate */ 17760Sstevel@tonic-gate int 17770Sstevel@tonic-gate secpolicy_clock_highres(const cred_t *cr) 17780Sstevel@tonic-gate { 17790Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_PROC_CLOCK_HIGHRES, B_FALSE, EPERM, 17800Sstevel@tonic-gate NULL)); 17810Sstevel@tonic-gate } 17820Sstevel@tonic-gate 17830Sstevel@tonic-gate /* 17840Sstevel@tonic-gate * drv_priv() is documented as callable from interrupt context, not that 17850Sstevel@tonic-gate * anyone ever does, but still. No debugging or auditing can be done when 17860Sstevel@tonic-gate * it is called from interrupt context. 17870Sstevel@tonic-gate * returns 0 on succes, EPERM on failure. 17880Sstevel@tonic-gate */ 17890Sstevel@tonic-gate int 17900Sstevel@tonic-gate drv_priv(cred_t *cr) 17910Sstevel@tonic-gate { 17920Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_DEVICES, B_FALSE, EPERM, NULL)); 17930Sstevel@tonic-gate } 17940Sstevel@tonic-gate 17950Sstevel@tonic-gate int 17960Sstevel@tonic-gate secpolicy_sys_devices(const cred_t *cr) 17970Sstevel@tonic-gate { 17980Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_DEVICES, B_FALSE, EPERM, NULL)); 17990Sstevel@tonic-gate } 18000Sstevel@tonic-gate 18010Sstevel@tonic-gate int 18020Sstevel@tonic-gate secpolicy_excl_open(const cred_t *cr) 18030Sstevel@tonic-gate { 18040Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_DEVICES, B_FALSE, EBUSY, NULL)); 18050Sstevel@tonic-gate } 18060Sstevel@tonic-gate 18070Sstevel@tonic-gate int 18080Sstevel@tonic-gate secpolicy_rctlsys(const cred_t *cr, boolean_t is_zone_rctl) 18090Sstevel@tonic-gate { 18100Sstevel@tonic-gate /* zone.* rctls can only be set from the global zone */ 18110Sstevel@tonic-gate if (is_zone_rctl && priv_policy_global(cr) != 0) 18120Sstevel@tonic-gate return (EPERM); 18130Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_RESOURCE, B_FALSE, EPERM, NULL)); 18140Sstevel@tonic-gate } 18150Sstevel@tonic-gate 18160Sstevel@tonic-gate int 18170Sstevel@tonic-gate secpolicy_resource(const cred_t *cr) 18180Sstevel@tonic-gate { 18190Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_RESOURCE, B_FALSE, EPERM, NULL)); 18200Sstevel@tonic-gate } 18210Sstevel@tonic-gate 182210154SStan.Studzinski@Sun.COM int 182310154SStan.Studzinski@Sun.COM secpolicy_resource_anon_mem(const cred_t *cr) 182410154SStan.Studzinski@Sun.COM { 182510154SStan.Studzinski@Sun.COM return (PRIV_POLICY_ONLY(cr, PRIV_SYS_RESOURCE, B_FALSE)); 182610154SStan.Studzinski@Sun.COM } 182710154SStan.Studzinski@Sun.COM 18280Sstevel@tonic-gate /* 18290Sstevel@tonic-gate * Processes with a real uid of 0 escape any form of accounting, much 18300Sstevel@tonic-gate * like before. 18310Sstevel@tonic-gate */ 18320Sstevel@tonic-gate int 18330Sstevel@tonic-gate secpolicy_newproc(const cred_t *cr) 18340Sstevel@tonic-gate { 18350Sstevel@tonic-gate if (cr->cr_ruid == 0) 18360Sstevel@tonic-gate return (0); 18370Sstevel@tonic-gate 18380Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_RESOURCE, B_FALSE, EPERM, NULL)); 18390Sstevel@tonic-gate } 18400Sstevel@tonic-gate 18410Sstevel@tonic-gate /* 18420Sstevel@tonic-gate * Networking 18430Sstevel@tonic-gate */ 18440Sstevel@tonic-gate int 18450Sstevel@tonic-gate secpolicy_net_rawaccess(const cred_t *cr) 18460Sstevel@tonic-gate { 18470Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_NET_RAWACCESS, B_FALSE, EACCES, NULL)); 18480Sstevel@tonic-gate } 18490Sstevel@tonic-gate 185010639SDarren.Reed@Sun.COM int 185110639SDarren.Reed@Sun.COM secpolicy_net_observability(const cred_t *cr) 185210639SDarren.Reed@Sun.COM { 185310639SDarren.Reed@Sun.COM return (PRIV_POLICY(cr, PRIV_NET_OBSERVABILITY, B_FALSE, EACCES, NULL)); 185410639SDarren.Reed@Sun.COM } 185510639SDarren.Reed@Sun.COM 18560Sstevel@tonic-gate /* 18570Sstevel@tonic-gate * Need this privilege for accessing the ICMP device 18580Sstevel@tonic-gate */ 18590Sstevel@tonic-gate int 18600Sstevel@tonic-gate secpolicy_net_icmpaccess(const cred_t *cr) 18610Sstevel@tonic-gate { 18620Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_NET_ICMPACCESS, B_FALSE, EACCES, NULL)); 18630Sstevel@tonic-gate } 18640Sstevel@tonic-gate 18650Sstevel@tonic-gate /* 18660Sstevel@tonic-gate * There are a few rare cases where the kernel generates ioctls() from 18670Sstevel@tonic-gate * interrupt context with a credential of kcred rather than NULL. 18680Sstevel@tonic-gate * In those cases, we take the safe and cheap test. 18690Sstevel@tonic-gate */ 18700Sstevel@tonic-gate int 18710Sstevel@tonic-gate secpolicy_net_config(const cred_t *cr, boolean_t checkonly) 18720Sstevel@tonic-gate { 18730Sstevel@tonic-gate if (checkonly) { 18740Sstevel@tonic-gate return (PRIV_POLICY_ONLY(cr, PRIV_SYS_NET_CONFIG, B_FALSE) ? 18750Sstevel@tonic-gate 0 : EPERM); 18760Sstevel@tonic-gate } else { 18770Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_NET_CONFIG, B_FALSE, EPERM, 18780Sstevel@tonic-gate NULL)); 18790Sstevel@tonic-gate } 18800Sstevel@tonic-gate } 18810Sstevel@tonic-gate 18820Sstevel@tonic-gate 18830Sstevel@tonic-gate /* 18844962Sdh155122 * PRIV_SYS_NET_CONFIG is a superset of PRIV_SYS_IP_CONFIG. 18853448Sdh155122 * 18863448Sdh155122 * There are a few rare cases where the kernel generates ioctls() from 18873448Sdh155122 * interrupt context with a credential of kcred rather than NULL. 18883448Sdh155122 * In those cases, we take the safe and cheap test. 18893448Sdh155122 */ 18903448Sdh155122 int 18913448Sdh155122 secpolicy_ip_config(const cred_t *cr, boolean_t checkonly) 18923448Sdh155122 { 18933448Sdh155122 if (PRIV_POLICY_ONLY(cr, PRIV_SYS_NET_CONFIG, B_FALSE)) 18943448Sdh155122 return (secpolicy_net_config(cr, checkonly)); 18953448Sdh155122 18963448Sdh155122 if (checkonly) { 18973448Sdh155122 return (PRIV_POLICY_ONLY(cr, PRIV_SYS_IP_CONFIG, B_FALSE) ? 18983448Sdh155122 0 : EPERM); 18993448Sdh155122 } else { 19003448Sdh155122 return (PRIV_POLICY(cr, PRIV_SYS_IP_CONFIG, B_FALSE, EPERM, 19013448Sdh155122 NULL)); 19023448Sdh155122 } 19033448Sdh155122 } 19043448Sdh155122 19057408SSebastien.Roy@Sun.COM /* 19067408SSebastien.Roy@Sun.COM * PRIV_SYS_NET_CONFIG is a superset of PRIV_SYS_DL_CONFIG. 19077408SSebastien.Roy@Sun.COM */ 19087408SSebastien.Roy@Sun.COM int 19097408SSebastien.Roy@Sun.COM secpolicy_dl_config(const cred_t *cr) 19107408SSebastien.Roy@Sun.COM { 19117408SSebastien.Roy@Sun.COM if (PRIV_POLICY_ONLY(cr, PRIV_SYS_NET_CONFIG, B_FALSE)) 19127408SSebastien.Roy@Sun.COM return (secpolicy_net_config(cr, B_FALSE)); 191310616SSebastien.Roy@Sun.COM return (PRIV_POLICY(cr, PRIV_SYS_DL_CONFIG, B_FALSE, EPERM, NULL)); 19147408SSebastien.Roy@Sun.COM } 19157408SSebastien.Roy@Sun.COM 191610616SSebastien.Roy@Sun.COM /* 191710616SSebastien.Roy@Sun.COM * PRIV_SYS_DL_CONFIG is a superset of PRIV_SYS_IPTUN_CONFIG. 191810616SSebastien.Roy@Sun.COM */ 191910616SSebastien.Roy@Sun.COM int 192010616SSebastien.Roy@Sun.COM secpolicy_iptun_config(const cred_t *cr) 192110616SSebastien.Roy@Sun.COM { 192210616SSebastien.Roy@Sun.COM if (PRIV_POLICY_ONLY(cr, PRIV_SYS_NET_CONFIG, B_FALSE)) 192310616SSebastien.Roy@Sun.COM return (secpolicy_net_config(cr, B_FALSE)); 192410616SSebastien.Roy@Sun.COM if (PRIV_POLICY_ONLY(cr, PRIV_SYS_DL_CONFIG, B_FALSE)) 192510616SSebastien.Roy@Sun.COM return (secpolicy_dl_config(cr)); 192610616SSebastien.Roy@Sun.COM return (PRIV_POLICY(cr, PRIV_SYS_IPTUN_CONFIG, B_FALSE, EPERM, NULL)); 192710616SSebastien.Roy@Sun.COM } 19283448Sdh155122 19293448Sdh155122 /* 19303448Sdh155122 * Map IP pseudo privileges to actual privileges. 19313448Sdh155122 * So we don't need to recompile IP when we change the privileges. 19323448Sdh155122 */ 19333448Sdh155122 int 19343448Sdh155122 secpolicy_ip(const cred_t *cr, int netpriv, boolean_t checkonly) 19353448Sdh155122 { 19363448Sdh155122 int priv = PRIV_ALL; 19373448Sdh155122 19383448Sdh155122 switch (netpriv) { 19393448Sdh155122 case OP_CONFIG: 19403448Sdh155122 priv = PRIV_SYS_IP_CONFIG; 19413448Sdh155122 break; 19423448Sdh155122 case OP_RAW: 19433448Sdh155122 priv = PRIV_NET_RAWACCESS; 19443448Sdh155122 break; 19453448Sdh155122 case OP_PRIVPORT: 19463448Sdh155122 priv = PRIV_NET_PRIVADDR; 19473448Sdh155122 break; 19483448Sdh155122 } 19493448Sdh155122 ASSERT(priv != PRIV_ALL); 19503448Sdh155122 if (checkonly) 19513448Sdh155122 return (PRIV_POLICY_ONLY(cr, priv, B_FALSE) ? 0 : EPERM); 19523448Sdh155122 else 19533448Sdh155122 return (PRIV_POLICY(cr, priv, B_FALSE, EPERM, NULL)); 19543448Sdh155122 } 19553448Sdh155122 19563448Sdh155122 /* 19570Sstevel@tonic-gate * Map network pseudo privileges to actual privileges. 19580Sstevel@tonic-gate * So we don't need to recompile IP when we change the privileges. 19590Sstevel@tonic-gate */ 19600Sstevel@tonic-gate int 19610Sstevel@tonic-gate secpolicy_net(const cred_t *cr, int netpriv, boolean_t checkonly) 19620Sstevel@tonic-gate { 19630Sstevel@tonic-gate int priv = PRIV_ALL; 19640Sstevel@tonic-gate 19650Sstevel@tonic-gate switch (netpriv) { 19660Sstevel@tonic-gate case OP_CONFIG: 19670Sstevel@tonic-gate priv = PRIV_SYS_NET_CONFIG; 19680Sstevel@tonic-gate break; 19690Sstevel@tonic-gate case OP_RAW: 19700Sstevel@tonic-gate priv = PRIV_NET_RAWACCESS; 19710Sstevel@tonic-gate break; 19720Sstevel@tonic-gate case OP_PRIVPORT: 19730Sstevel@tonic-gate priv = PRIV_NET_PRIVADDR; 19740Sstevel@tonic-gate break; 19750Sstevel@tonic-gate } 19760Sstevel@tonic-gate ASSERT(priv != PRIV_ALL); 19770Sstevel@tonic-gate if (checkonly) 19780Sstevel@tonic-gate return (PRIV_POLICY_ONLY(cr, priv, B_FALSE) ? 0 : EPERM); 19790Sstevel@tonic-gate else 19800Sstevel@tonic-gate return (PRIV_POLICY(cr, priv, B_FALSE, EPERM, NULL)); 19810Sstevel@tonic-gate } 19820Sstevel@tonic-gate 19830Sstevel@tonic-gate /* 19840Sstevel@tonic-gate * Checks for operations that are either client-only or are used by 19850Sstevel@tonic-gate * both clients and servers. 19860Sstevel@tonic-gate */ 19870Sstevel@tonic-gate int 19880Sstevel@tonic-gate secpolicy_nfs(const cred_t *cr) 19890Sstevel@tonic-gate { 19900Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_NFS, B_FALSE, EPERM, NULL)); 19910Sstevel@tonic-gate } 19920Sstevel@tonic-gate 19930Sstevel@tonic-gate /* 19940Sstevel@tonic-gate * Special case for opening rpcmod: have NFS privileges or network 19950Sstevel@tonic-gate * config privileges. 19960Sstevel@tonic-gate */ 19970Sstevel@tonic-gate int 19980Sstevel@tonic-gate secpolicy_rpcmod_open(const cred_t *cr) 19990Sstevel@tonic-gate { 20000Sstevel@tonic-gate if (PRIV_POLICY_ONLY(cr, PRIV_SYS_NFS, B_FALSE)) 20010Sstevel@tonic-gate return (secpolicy_nfs(cr)); 20020Sstevel@tonic-gate else 20030Sstevel@tonic-gate return (secpolicy_net_config(cr, NULL)); 20040Sstevel@tonic-gate } 20050Sstevel@tonic-gate 20060Sstevel@tonic-gate int 20070Sstevel@tonic-gate secpolicy_chroot(const cred_t *cr) 20080Sstevel@tonic-gate { 20090Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_PROC_CHROOT, B_FALSE, EPERM, NULL)); 20100Sstevel@tonic-gate } 20110Sstevel@tonic-gate 20120Sstevel@tonic-gate int 20130Sstevel@tonic-gate secpolicy_tasksys(const cred_t *cr) 20140Sstevel@tonic-gate { 20150Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_PROC_TASKID, B_FALSE, EPERM, NULL)); 20160Sstevel@tonic-gate } 20170Sstevel@tonic-gate 201812273SCasper.Dik@Sun.COM int 201912273SCasper.Dik@Sun.COM secpolicy_pfexec_register(const cred_t *cr) 202012273SCasper.Dik@Sun.COM { 202112273SCasper.Dik@Sun.COM return (PRIV_POLICY(cr, PRIV_SYS_ADMIN, B_TRUE, EPERM, NULL)); 202212273SCasper.Dik@Sun.COM } 202312273SCasper.Dik@Sun.COM 20240Sstevel@tonic-gate /* 20250Sstevel@tonic-gate * Basic privilege checks. 20260Sstevel@tonic-gate */ 20270Sstevel@tonic-gate int 20286134Scasper secpolicy_basic_exec(const cred_t *cr, vnode_t *vp) 20290Sstevel@tonic-gate { 203012273SCasper.Dik@Sun.COM FAST_BASIC_CHECK(cr, PRIV_PROC_EXEC); 203112273SCasper.Dik@Sun.COM 20326134Scasper return (priv_policy_va(cr, PRIV_PROC_EXEC, B_FALSE, EPERM, NULL, 20336134Scasper KLPDARG_VNODE, vp, (char *)NULL, KLPDARG_NOMORE)); 20340Sstevel@tonic-gate } 20350Sstevel@tonic-gate 20360Sstevel@tonic-gate int 20370Sstevel@tonic-gate secpolicy_basic_fork(const cred_t *cr) 20380Sstevel@tonic-gate { 203912273SCasper.Dik@Sun.COM FAST_BASIC_CHECK(cr, PRIV_PROC_FORK); 204012273SCasper.Dik@Sun.COM 20410Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_PROC_FORK, B_FALSE, EPERM, NULL)); 20420Sstevel@tonic-gate } 20430Sstevel@tonic-gate 20440Sstevel@tonic-gate int 20450Sstevel@tonic-gate secpolicy_basic_proc(const cred_t *cr) 20460Sstevel@tonic-gate { 204712273SCasper.Dik@Sun.COM FAST_BASIC_CHECK(cr, PRIV_PROC_SESSION); 204812273SCasper.Dik@Sun.COM 20490Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_PROC_SESSION, B_FALSE, EPERM, NULL)); 20500Sstevel@tonic-gate } 20510Sstevel@tonic-gate 20520Sstevel@tonic-gate /* 20530Sstevel@tonic-gate * Slightly complicated because we don't want to trigger the policy too 20540Sstevel@tonic-gate * often. First we shortcircuit access to "self" (tp == sp) or if 20550Sstevel@tonic-gate * we don't have the privilege but if we have permission 20560Sstevel@tonic-gate * just return (0) and we don't flag the privilege as needed. 20570Sstevel@tonic-gate * Else, we test for the privilege because we either have it or need it. 20580Sstevel@tonic-gate */ 20590Sstevel@tonic-gate int 20600Sstevel@tonic-gate secpolicy_basic_procinfo(const cred_t *cr, proc_t *tp, proc_t *sp) 20610Sstevel@tonic-gate { 20620Sstevel@tonic-gate if (tp == sp || 20630Sstevel@tonic-gate !HAS_PRIVILEGE(cr, PRIV_PROC_INFO) && prochasprocperm(tp, sp, cr)) { 20640Sstevel@tonic-gate return (0); 20650Sstevel@tonic-gate } else { 20660Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_PROC_INFO, B_FALSE, EPERM, NULL)); 20670Sstevel@tonic-gate } 20680Sstevel@tonic-gate } 20690Sstevel@tonic-gate 20700Sstevel@tonic-gate int 20710Sstevel@tonic-gate secpolicy_basic_link(const cred_t *cr) 20720Sstevel@tonic-gate { 207312273SCasper.Dik@Sun.COM FAST_BASIC_CHECK(cr, PRIV_FILE_LINK_ANY); 207412273SCasper.Dik@Sun.COM 20750Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_FILE_LINK_ANY, B_FALSE, EPERM, NULL)); 20760Sstevel@tonic-gate } 20770Sstevel@tonic-gate 207811537SCasper.Dik@Sun.COM int 207911537SCasper.Dik@Sun.COM secpolicy_basic_net_access(const cred_t *cr) 208011537SCasper.Dik@Sun.COM { 208112273SCasper.Dik@Sun.COM FAST_BASIC_CHECK(cr, PRIV_NET_ACCESS); 208212273SCasper.Dik@Sun.COM 208311537SCasper.Dik@Sun.COM return (PRIV_POLICY(cr, PRIV_NET_ACCESS, B_FALSE, EACCES, NULL)); 208411537SCasper.Dik@Sun.COM } 208511537SCasper.Dik@Sun.COM 208612273SCasper.Dik@Sun.COM /* ARGSUSED */ 208712273SCasper.Dik@Sun.COM int 208812273SCasper.Dik@Sun.COM secpolicy_basic_file_read(const cred_t *cr, vnode_t *vp, const char *pn) 208912273SCasper.Dik@Sun.COM { 209012273SCasper.Dik@Sun.COM FAST_BASIC_CHECK(cr, PRIV_FILE_READ); 209112273SCasper.Dik@Sun.COM 209212273SCasper.Dik@Sun.COM return (priv_policy_va(cr, PRIV_FILE_READ, B_FALSE, EACCES, NULL, 209312273SCasper.Dik@Sun.COM KLPDARG_VNODE, vp, (char *)pn, KLPDARG_NOMORE)); 209412273SCasper.Dik@Sun.COM } 209512273SCasper.Dik@Sun.COM 209612273SCasper.Dik@Sun.COM /* ARGSUSED */ 209712273SCasper.Dik@Sun.COM int 209812273SCasper.Dik@Sun.COM secpolicy_basic_file_write(const cred_t *cr, vnode_t *vp, const char *pn) 209912273SCasper.Dik@Sun.COM { 210012273SCasper.Dik@Sun.COM FAST_BASIC_CHECK(cr, PRIV_FILE_WRITE); 210112273SCasper.Dik@Sun.COM 210212273SCasper.Dik@Sun.COM return (priv_policy_va(cr, PRIV_FILE_WRITE, B_FALSE, EACCES, NULL, 210312273SCasper.Dik@Sun.COM KLPDARG_VNODE, vp, (char *)pn, KLPDARG_NOMORE)); 210412273SCasper.Dik@Sun.COM } 210512273SCasper.Dik@Sun.COM 21060Sstevel@tonic-gate /* 21070Sstevel@tonic-gate * Additional device protection. 21080Sstevel@tonic-gate * 21090Sstevel@tonic-gate * Traditionally, a device has specific permissions on the node in 21100Sstevel@tonic-gate * the filesystem which govern which devices can be opened by what 21110Sstevel@tonic-gate * processes. In certain cases, it is desirable to add extra 21120Sstevel@tonic-gate * restrictions, as writing to certain devices is identical to 21130Sstevel@tonic-gate * having a complete run of the system. 21140Sstevel@tonic-gate * 21150Sstevel@tonic-gate * This mechanism is called the device policy. 21160Sstevel@tonic-gate * 21170Sstevel@tonic-gate * When a device is opened, its policy entry is looked up in the 21180Sstevel@tonic-gate * policy cache and checked. 21190Sstevel@tonic-gate */ 21200Sstevel@tonic-gate int 21210Sstevel@tonic-gate secpolicy_spec_open(const cred_t *cr, struct vnode *vp, int oflag) 21220Sstevel@tonic-gate { 21230Sstevel@tonic-gate devplcy_t *plcy; 21240Sstevel@tonic-gate int err; 21250Sstevel@tonic-gate struct snode *csp = VTOS(common_specvp(vp)); 21264962Sdh155122 priv_set_t pset; 21270Sstevel@tonic-gate 21280Sstevel@tonic-gate mutex_enter(&csp->s_lock); 21290Sstevel@tonic-gate 21300Sstevel@tonic-gate if (csp->s_plcy == NULL || csp->s_plcy->dp_gen != devplcy_gen) { 21310Sstevel@tonic-gate plcy = devpolicy_find(vp); 21320Sstevel@tonic-gate if (csp->s_plcy) 21330Sstevel@tonic-gate dpfree(csp->s_plcy); 21340Sstevel@tonic-gate csp->s_plcy = plcy; 21350Sstevel@tonic-gate ASSERT(plcy != NULL); 21360Sstevel@tonic-gate } else 21370Sstevel@tonic-gate plcy = csp->s_plcy; 21380Sstevel@tonic-gate 21390Sstevel@tonic-gate if (plcy == nullpolicy) { 21400Sstevel@tonic-gate mutex_exit(&csp->s_lock); 21410Sstevel@tonic-gate return (0); 21420Sstevel@tonic-gate } 21430Sstevel@tonic-gate 21440Sstevel@tonic-gate dphold(plcy); 21450Sstevel@tonic-gate 21460Sstevel@tonic-gate mutex_exit(&csp->s_lock); 21470Sstevel@tonic-gate 21484962Sdh155122 if (oflag & FWRITE) 21494962Sdh155122 pset = plcy->dp_wrp; 21504962Sdh155122 else 21514962Sdh155122 pset = plcy->dp_rdp; 21524962Sdh155122 /* 21534962Sdh155122 * Special case: 21544962Sdh155122 * PRIV_SYS_NET_CONFIG is a superset of PRIV_SYS_IP_CONFIG. 21554962Sdh155122 * If PRIV_SYS_NET_CONFIG is present and PRIV_SYS_IP_CONFIG is 21564962Sdh155122 * required, replace PRIV_SYS_IP_CONFIG with PRIV_SYS_NET_CONFIG 21574962Sdh155122 * in the required privilege set before doing the check. 21584962Sdh155122 */ 21594962Sdh155122 if (priv_ismember(&pset, PRIV_SYS_IP_CONFIG) && 21604962Sdh155122 priv_ismember(&CR_OEPRIV(cr), PRIV_SYS_NET_CONFIG) && 21614962Sdh155122 !priv_ismember(&CR_OEPRIV(cr), PRIV_SYS_IP_CONFIG)) { 21624962Sdh155122 priv_delset(&pset, PRIV_SYS_IP_CONFIG); 21634962Sdh155122 priv_addset(&pset, PRIV_SYS_NET_CONFIG); 21644962Sdh155122 } 21654962Sdh155122 216612273SCasper.Dik@Sun.COM err = secpolicy_require_set(cr, &pset, "devpolicy", KLPDARG_NONE); 21670Sstevel@tonic-gate dpfree(plcy); 21680Sstevel@tonic-gate 21690Sstevel@tonic-gate return (err); 21700Sstevel@tonic-gate } 21710Sstevel@tonic-gate 21720Sstevel@tonic-gate int 21730Sstevel@tonic-gate secpolicy_modctl(const cred_t *cr, int cmd) 21740Sstevel@tonic-gate { 21750Sstevel@tonic-gate switch (cmd) { 21760Sstevel@tonic-gate case MODINFO: 21772723Scth case MODGETMAJBIND: 21780Sstevel@tonic-gate case MODGETPATH: 21790Sstevel@tonic-gate case MODGETPATHLEN: 21802723Scth case MODGETNAME: 21810Sstevel@tonic-gate case MODGETFBNAME: 21820Sstevel@tonic-gate case MODGETDEVPOLICY: 21830Sstevel@tonic-gate case MODGETDEVPOLICYBYNAME: 21842723Scth case MODDEVT2INSTANCE: 21852723Scth case MODSIZEOF_DEVID: 21862723Scth case MODGETDEVID: 21872723Scth case MODSIZEOF_MINORNAME: 21882723Scth case MODGETMINORNAME: 21892723Scth case MODGETDEVFSPATH_LEN: 21902723Scth case MODGETDEVFSPATH: 21912723Scth case MODGETDEVFSPATH_MI_LEN: 21922723Scth case MODGETDEVFSPATH_MI: 21930Sstevel@tonic-gate /* Unprivileged */ 21940Sstevel@tonic-gate return (0); 21950Sstevel@tonic-gate case MODLOAD: 21960Sstevel@tonic-gate case MODSETDEVPOLICY: 219712273SCasper.Dik@Sun.COM return (secpolicy_require_set(cr, PRIV_FULLSET, NULL, 219812273SCasper.Dik@Sun.COM KLPDARG_NONE)); 21990Sstevel@tonic-gate default: 22000Sstevel@tonic-gate return (secpolicy_sys_config(cr, B_FALSE)); 22010Sstevel@tonic-gate } 22020Sstevel@tonic-gate } 22030Sstevel@tonic-gate 22040Sstevel@tonic-gate int 22050Sstevel@tonic-gate secpolicy_console(const cred_t *cr) 22060Sstevel@tonic-gate { 22070Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_DEVICES, B_FALSE, EPERM, NULL)); 22080Sstevel@tonic-gate } 22090Sstevel@tonic-gate 22100Sstevel@tonic-gate int 22110Sstevel@tonic-gate secpolicy_power_mgmt(const cred_t *cr) 22120Sstevel@tonic-gate { 22130Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_DEVICES, B_FALSE, EPERM, NULL)); 22140Sstevel@tonic-gate } 22150Sstevel@tonic-gate 22160Sstevel@tonic-gate /* 22170Sstevel@tonic-gate * Simulate terminal input; another escalation of privileges avenue. 22180Sstevel@tonic-gate */ 22190Sstevel@tonic-gate 22200Sstevel@tonic-gate int 22210Sstevel@tonic-gate secpolicy_sti(const cred_t *cr) 22220Sstevel@tonic-gate { 222312273SCasper.Dik@Sun.COM return (secpolicy_require_set(cr, PRIV_FULLSET, NULL, KLPDARG_NONE)); 22240Sstevel@tonic-gate } 22250Sstevel@tonic-gate 22261676Sjpk boolean_t 22271676Sjpk secpolicy_net_reply_equal(const cred_t *cr) 22281676Sjpk { 22291676Sjpk return (PRIV_POLICY(cr, PRIV_SYS_CONFIG, B_FALSE, EPERM, NULL)); 22301676Sjpk } 22311676Sjpk 22320Sstevel@tonic-gate int 22330Sstevel@tonic-gate secpolicy_swapctl(const cred_t *cr) 22340Sstevel@tonic-gate { 22350Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_CONFIG, B_FALSE, EPERM, NULL)); 22360Sstevel@tonic-gate } 22370Sstevel@tonic-gate 22380Sstevel@tonic-gate int 22390Sstevel@tonic-gate secpolicy_cpc_cpu(const cred_t *cr) 22400Sstevel@tonic-gate { 22410Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_CPC_CPU, B_FALSE, EACCES, NULL)); 22420Sstevel@tonic-gate } 22430Sstevel@tonic-gate 22440Sstevel@tonic-gate /* 22456073Sacruz * secpolicy_contract_identity 22466073Sacruz * 22476073Sacruz * Determine if the subject may set the process contract FMRI value 22486073Sacruz */ 22496073Sacruz int 22506073Sacruz secpolicy_contract_identity(const cred_t *cr) 22516073Sacruz { 22526073Sacruz return (PRIV_POLICY(cr, PRIV_CONTRACT_IDENTITY, B_FALSE, EPERM, NULL)); 22536073Sacruz } 22546073Sacruz 22556073Sacruz /* 22560Sstevel@tonic-gate * secpolicy_contract_observer 22570Sstevel@tonic-gate * 22580Sstevel@tonic-gate * Determine if the subject may observe a specific contract's events. 22590Sstevel@tonic-gate */ 22600Sstevel@tonic-gate int 22610Sstevel@tonic-gate secpolicy_contract_observer(const cred_t *cr, struct contract *ct) 22620Sstevel@tonic-gate { 22630Sstevel@tonic-gate if (contract_owned(ct, cr, B_FALSE)) 22640Sstevel@tonic-gate return (0); 22650Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_CONTRACT_OBSERVER, B_FALSE, EPERM, NULL)); 22660Sstevel@tonic-gate } 22670Sstevel@tonic-gate 22680Sstevel@tonic-gate /* 22690Sstevel@tonic-gate * secpolicy_contract_observer_choice 22700Sstevel@tonic-gate * 22710Sstevel@tonic-gate * Determine if the subject may observe any contract's events. Just 22720Sstevel@tonic-gate * tests privilege and audits on success. 22730Sstevel@tonic-gate */ 22740Sstevel@tonic-gate boolean_t 22750Sstevel@tonic-gate secpolicy_contract_observer_choice(const cred_t *cr) 22760Sstevel@tonic-gate { 22770Sstevel@tonic-gate return (PRIV_POLICY_CHOICE(cr, PRIV_CONTRACT_OBSERVER, B_FALSE)); 22780Sstevel@tonic-gate } 22790Sstevel@tonic-gate 22800Sstevel@tonic-gate /* 22810Sstevel@tonic-gate * secpolicy_contract_event 22820Sstevel@tonic-gate * 22830Sstevel@tonic-gate * Determine if the subject may request critical contract events or 22840Sstevel@tonic-gate * reliable contract event delivery. 22850Sstevel@tonic-gate */ 22860Sstevel@tonic-gate int 22870Sstevel@tonic-gate secpolicy_contract_event(const cred_t *cr) 22880Sstevel@tonic-gate { 22890Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_CONTRACT_EVENT, B_FALSE, EPERM, NULL)); 22900Sstevel@tonic-gate } 22910Sstevel@tonic-gate 22920Sstevel@tonic-gate /* 22930Sstevel@tonic-gate * secpolicy_contract_event_choice 22940Sstevel@tonic-gate * 22950Sstevel@tonic-gate * Determine if the subject may retain contract events in its critical 22960Sstevel@tonic-gate * set when a change in other terms would normally require a change in 22970Sstevel@tonic-gate * the critical set. Just tests privilege and audits on success. 22980Sstevel@tonic-gate */ 22990Sstevel@tonic-gate boolean_t 23000Sstevel@tonic-gate secpolicy_contract_event_choice(const cred_t *cr) 23010Sstevel@tonic-gate { 23020Sstevel@tonic-gate return (PRIV_POLICY_CHOICE(cr, PRIV_CONTRACT_EVENT, B_FALSE)); 23030Sstevel@tonic-gate } 23040Sstevel@tonic-gate 23050Sstevel@tonic-gate /* 23061544Seschrock * secpolicy_gart_access 23070Sstevel@tonic-gate * 23081544Seschrock * Determine if the subject has sufficient priveleges to make ioctls to agpgart 23091544Seschrock * device. 23100Sstevel@tonic-gate */ 23110Sstevel@tonic-gate int 23120Sstevel@tonic-gate secpolicy_gart_access(const cred_t *cr) 23130Sstevel@tonic-gate { 23141862Scasper return (PRIV_POLICY(cr, PRIV_GRAPHICS_ACCESS, B_FALSE, EPERM, NULL)); 23150Sstevel@tonic-gate } 23160Sstevel@tonic-gate 23170Sstevel@tonic-gate /* 23181544Seschrock * secpolicy_gart_map 23190Sstevel@tonic-gate * 23201544Seschrock * Determine if the subject has sufficient priveleges to map aperture range 23211544Seschrock * through agpgart driver. 23220Sstevel@tonic-gate */ 23230Sstevel@tonic-gate int 23240Sstevel@tonic-gate secpolicy_gart_map(const cred_t *cr) 23250Sstevel@tonic-gate { 23261862Scasper if (PRIV_POLICY_ONLY(cr, PRIV_GRAPHICS_ACCESS, B_FALSE)) { 23271862Scasper return (PRIV_POLICY(cr, PRIV_GRAPHICS_ACCESS, B_FALSE, EPERM, 23281862Scasper NULL)); 23291862Scasper } else { 23301862Scasper return (PRIV_POLICY(cr, PRIV_GRAPHICS_MAP, B_FALSE, EPERM, 23311862Scasper NULL)); 23320Sstevel@tonic-gate } 23330Sstevel@tonic-gate } 2334789Sahrens 2335789Sahrens /* 23361544Seschrock * secpolicy_zinject 23371544Seschrock * 23381544Seschrock * Determine if the subject can inject faults in the ZFS fault injection 23391544Seschrock * framework. Requires all privileges. 23401544Seschrock */ 23411544Seschrock int 23421544Seschrock secpolicy_zinject(const cred_t *cr) 23431544Seschrock { 234412273SCasper.Dik@Sun.COM return (secpolicy_require_set(cr, PRIV_FULLSET, NULL, KLPDARG_NONE)); 23451544Seschrock } 23461544Seschrock 23471544Seschrock /* 2348789Sahrens * secpolicy_zfs 2349789Sahrens * 23501544Seschrock * Determine if the subject has permission to manipulate ZFS datasets 23511544Seschrock * (not pools). Equivalent to the SYS_MOUNT privilege. 2352789Sahrens */ 2353789Sahrens int 2354789Sahrens secpolicy_zfs(const cred_t *cr) 2355789Sahrens { 2356789Sahrens return (PRIV_POLICY(cr, PRIV_SYS_MOUNT, B_FALSE, EPERM, NULL)); 2357789Sahrens } 23584321Scasper 23594321Scasper /* 23604321Scasper * secpolicy_idmap 23614321Scasper * 23624321Scasper * Determine if the calling process has permissions to register an SID 23634321Scasper * mapping daemon and allocate ephemeral IDs. 23644321Scasper */ 23654321Scasper int 23664321Scasper secpolicy_idmap(const cred_t *cr) 23674321Scasper { 23685771Sjp151216 return (PRIV_POLICY(cr, PRIV_FILE_SETID, B_TRUE, EPERM, NULL)); 23694321Scasper } 23704581Ssherrym 23714581Ssherrym /* 23724581Ssherrym * secpolicy_ucode_update 23734581Ssherrym * 23744581Ssherrym * Determine if the subject has sufficient privilege to update microcode. 23754581Ssherrym */ 23764581Ssherrym int 23774581Ssherrym secpolicy_ucode_update(const cred_t *scr) 23784581Ssherrym { 23794581Ssherrym return (PRIV_POLICY(scr, PRIV_ALL, B_FALSE, EPERM, NULL)); 23804581Ssherrym } 23814962Sdh155122 23824962Sdh155122 /* 23834962Sdh155122 * secpolicy_sadopen 23844962Sdh155122 * 23854962Sdh155122 * Determine if the subject has sufficient privilege to access /dev/sad/admin. 23864962Sdh155122 * /dev/sad/admin appear in global zone and exclusive-IP zones only. 23874962Sdh155122 * In global zone, sys_config is required. 23884962Sdh155122 * In exclusive-IP zones, sys_ip_config is required. 23894962Sdh155122 * Note that sys_config is prohibited in non-global zones. 23904962Sdh155122 */ 23914962Sdh155122 int 23924962Sdh155122 secpolicy_sadopen(const cred_t *credp) 23934962Sdh155122 { 23944962Sdh155122 priv_set_t pset; 23954962Sdh155122 23964962Sdh155122 priv_emptyset(&pset); 23974962Sdh155122 23984962Sdh155122 if (crgetzoneid(credp) == GLOBAL_ZONEID) 23994962Sdh155122 priv_addset(&pset, PRIV_SYS_CONFIG); 24004962Sdh155122 else 24014962Sdh155122 priv_addset(&pset, PRIV_SYS_IP_CONFIG); 24024962Sdh155122 240312273SCasper.Dik@Sun.COM return (secpolicy_require_set(credp, &pset, "devpolicy", KLPDARG_NONE)); 24044962Sdh155122 } 24055331Samw 24066134Scasper 24076134Scasper /* 24086134Scasper * Add privileges to a particular privilege set; this is called when the 24096134Scasper * current sets of privileges are not sufficient. I.e., we should always 24106134Scasper * call the policy override functions from here. 24116134Scasper * What we are allowed to have is in the Observed Permitted set; so 24126134Scasper * we compute the difference between that and the newset. 24136134Scasper */ 24146134Scasper int 24156134Scasper secpolicy_require_privs(const cred_t *cr, const priv_set_t *nset) 24166134Scasper { 24176134Scasper priv_set_t rqd; 24186134Scasper 24196134Scasper rqd = CR_OPPRIV(cr); 24206134Scasper 24216134Scasper priv_inverse(&rqd); 24226134Scasper priv_intersect(nset, &rqd); 24236134Scasper 242412273SCasper.Dik@Sun.COM return (secpolicy_require_set(cr, &rqd, NULL, KLPDARG_NONE)); 24256134Scasper } 24266134Scasper 24275331Samw /* 24285331Samw * secpolicy_smb 24295331Samw * 24305331Samw * Determine if the cred_t has PRIV_SYS_SMB privilege, indicating 24315331Samw * that it has permission to access the smbsrv kernel driver. 24325331Samw * PRIV_POLICY checks the privilege and audits the check. 24335331Samw * 24345331Samw * Returns: 24355331Samw * 0 Driver access is allowed. 24365331Samw * EPERM Driver access is NOT permitted. 24375331Samw */ 24385331Samw int 24395331Samw secpolicy_smb(const cred_t *cr) 24405331Samw { 24415331Samw return (PRIV_POLICY(cr, PRIV_SYS_SMB, B_FALSE, EPERM, NULL)); 24425331Samw } 24435440Sjm199354 24445440Sjm199354 /* 24455440Sjm199354 * secpolicy_vscan 24465440Sjm199354 * 24475440Sjm199354 * Determine if cred_t has the necessary privileges to access a file 24485440Sjm199354 * for virus scanning and update its extended system attributes. 24495440Sjm199354 * PRIV_FILE_DAC_SEARCH, PRIV_FILE_DAC_READ - file access 24505440Sjm199354 * PRIV_FILE_FLAG_SET - set extended system attributes 24515440Sjm199354 * 24525440Sjm199354 * PRIV_POLICY checks the privilege and audits the check. 24535440Sjm199354 * 24545440Sjm199354 * Returns: 24555440Sjm199354 * 0 file access for virus scanning allowed. 24565440Sjm199354 * EPERM file access for virus scanning is NOT permitted. 24575440Sjm199354 */ 24585440Sjm199354 int 24595440Sjm199354 secpolicy_vscan(const cred_t *cr) 24605440Sjm199354 { 24615440Sjm199354 if ((PRIV_POLICY(cr, PRIV_FILE_DAC_SEARCH, B_FALSE, EPERM, NULL)) || 24625440Sjm199354 (PRIV_POLICY(cr, PRIV_FILE_DAC_READ, B_FALSE, EPERM, NULL)) || 24635440Sjm199354 (PRIV_POLICY(cr, PRIV_FILE_FLAG_SET, B_FALSE, EPERM, NULL))) { 24645440Sjm199354 return (EPERM); 24655440Sjm199354 } 24665440Sjm199354 24675440Sjm199354 return (0); 24685440Sjm199354 } 24696007Sthurlow 24706007Sthurlow /* 24716007Sthurlow * secpolicy_smbfs_login 24726007Sthurlow * 24736007Sthurlow * Determines if the caller can add and delete the smbfs login 24746007Sthurlow * password in the the nsmb kernel module for the CIFS client. 24756007Sthurlow * 24766007Sthurlow * Returns: 24776007Sthurlow * 0 access is allowed. 24786007Sthurlow * EPERM access is NOT allowed. 24796007Sthurlow */ 24806007Sthurlow int 24816007Sthurlow secpolicy_smbfs_login(const cred_t *cr, uid_t uid) 24826007Sthurlow { 24836007Sthurlow uid_t cruid = crgetruid(cr); 24846007Sthurlow 24856007Sthurlow if (cruid == uid) 24866007Sthurlow return (0); 24876007Sthurlow return (PRIV_POLICY(cr, PRIV_PROC_OWNER, B_FALSE, 24886007Sthurlow EPERM, NULL)); 24896007Sthurlow } 24906784Sjohnlev 24916784Sjohnlev /* 24926784Sjohnlev * secpolicy_xvm_control 24936784Sjohnlev * 24946784Sjohnlev * Determines if a caller can control the xVM hypervisor and/or running 24956784Sjohnlev * domains (x86 specific). 24966784Sjohnlev * 24976784Sjohnlev * Returns: 24986784Sjohnlev * 0 access is allowed. 24996784Sjohnlev * EPERM access is NOT allowed. 25006784Sjohnlev */ 25016784Sjohnlev int 25026784Sjohnlev secpolicy_xvm_control(const cred_t *cr) 25036784Sjohnlev { 25046784Sjohnlev if (PRIV_POLICY(cr, PRIV_XVM_CONTROL, B_FALSE, EPERM, NULL)) 25056784Sjohnlev return (EPERM); 25066784Sjohnlev return (0); 25076784Sjohnlev } 25088275SEric Cheng 25098275SEric Cheng /* 25109751Sjames.d.carlson@sun.com * secpolicy_ppp_config 25119751Sjames.d.carlson@sun.com * 25129751Sjames.d.carlson@sun.com * Determine if the subject has sufficient privileges to configure PPP and 25139751Sjames.d.carlson@sun.com * PPP-related devices. 25149751Sjames.d.carlson@sun.com */ 25159751Sjames.d.carlson@sun.com int 25169751Sjames.d.carlson@sun.com secpolicy_ppp_config(const cred_t *cr) 25179751Sjames.d.carlson@sun.com { 25189751Sjames.d.carlson@sun.com if (PRIV_POLICY_ONLY(cr, PRIV_SYS_NET_CONFIG, B_FALSE)) 25199751Sjames.d.carlson@sun.com return (secpolicy_net_config(cr, B_FALSE)); 25209751Sjames.d.carlson@sun.com return (PRIV_POLICY(cr, PRIV_SYS_PPP_CONFIG, B_FALSE, EPERM, NULL)); 25219751Sjames.d.carlson@sun.com } 2522