128 * For (1), priv should be set to the specific privilege, and allzone
129 * should be set to B_FALSE.
130 * For (2), priv should be set to the specific privilege, and allzone
131 * should be set to B_TRUE.
132 * For (3), priv should be set to PRIV_ALL, and allzone should be set
133 * to B_FALSE.
134 *
135 */
136
137 /*
138 * The privileges are checked against the Effective set for
139 * ordinary processes and checked against the Limit set
140 * for euid 0 processes that haven't manipulated their privilege
141 * sets.
142 */
143 #define HAS_ALLPRIVS(cr) priv_isfullset(&CR_OEPRIV(cr))
144 #define ZONEPRIVS(cr) ((cr)->cr_zone->zone_privset)
145 #define HAS_ALLZONEPRIVS(cr) priv_issubset(ZONEPRIVS(cr), &CR_OEPRIV(cr))
146 #define HAS_PRIVILEGE(cr, pr) ((pr) == PRIV_ALL ? \
147 HAS_ALLPRIVS(cr) : \
148 PRIV_ISASSERT(&CR_OEPRIV(cr), pr))
149
150 #define FAST_BASIC_CHECK(cr, priv) \
151 if (PRIV_ISASSERT(&CR_OEPRIV(cr), priv)) { \
152 DTRACE_PROBE2(priv__ok, int, priv, boolean_t, B_FALSE); \
153 return (0); \
154 }
155
156 /*
157 * Policy checking functions.
158 *
159 * All of the system's policy should be implemented here.
160 */
161
162 /*
163 * Private functions which take an additional va_list argument to
164 * implement an object specific policy override.
165 */
166 static int priv_policy_ap(const cred_t *, int, boolean_t, int,
167 const char *, va_list);
168 static int priv_policy_va(const cred_t *, int, boolean_t, int,
169 const char *, ...);
170
171 /*
384 } else {
385 ASSERT(!HAS_PRIVILEGE(cr, priv));
386 priv_policy_errmsg(cr, priv, msg);
387 }
388 }
389 }
390
391 /*
392 * priv_policy_ap()
393 * return 0 or error.
394 * See block comment above for a description of "priv" and "allzone" usage.
395 */
396 static int
397 priv_policy_ap(const cred_t *cr, int priv, boolean_t allzone, int err,
398 const char *msg, va_list ap)
399 {
400 if ((HAS_PRIVILEGE(cr, priv) && (!allzone || HAS_ALLZONEPRIVS(cr))) ||
401 (!servicing_interrupt() &&
402 priv_policy_override(cr, priv, allzone, ap) == 0)) {
403 if ((allzone || priv == PRIV_ALL ||
404 !PRIV_ISASSERT(priv_basic, priv)) &&
405 !servicing_interrupt()) {
406 PTOU(curproc)->u_acflag |= ASU; /* Needed for SVVS */
407 if (AU_AUDITING())
408 audit_priv(priv,
409 allzone ? ZONEPRIVS(cr) : NULL, 1);
410 }
411 err = 0;
412 DTRACE_PROBE2(priv__ok, int, priv, boolean_t, allzone);
413 } else if (!servicing_interrupt()) {
414 /* Failure audited in this procedure */
415 priv_policy_err(cr, priv, allzone, msg);
416 }
417 return (err);
418 }
419
420 int
421 priv_policy_va(const cred_t *cr, int priv, boolean_t allzone, int err,
422 const char *msg, ...)
423 {
424 int ret;
432 }
433
434 int
435 priv_policy(const cred_t *cr, int priv, boolean_t allzone, int err,
436 const char *msg)
437 {
438 return (priv_policy_va(cr, priv, allzone, err, msg, KLPDARG_NONE));
439 }
440
441 /*
442 * Return B_TRUE for sufficient privileges, B_FALSE for insufficient privileges.
443 */
444 boolean_t
445 priv_policy_choice(const cred_t *cr, int priv, boolean_t allzone)
446 {
447 boolean_t res = HAS_PRIVILEGE(cr, priv) &&
448 (!allzone || HAS_ALLZONEPRIVS(cr));
449
450 /* Audit success only */
451 if (res && AU_AUDITING() &&
452 (allzone || priv == PRIV_ALL || !PRIV_ISASSERT(priv_basic, priv)) &&
453 !servicing_interrupt()) {
454 audit_priv(priv, allzone ? ZONEPRIVS(cr) : NULL, 1);
455 }
456 if (res) {
457 DTRACE_PROBE2(priv__ok, int, priv, boolean_t, allzone);
458 } else {
459 DTRACE_PROBE2(priv__err, int, priv, boolean_t, allzone);
460 }
461 return (res);
462 }
463
464 /*
465 * Non-auditing variant of priv_policy_choice().
466 */
467 boolean_t
468 priv_policy_only(const cred_t *cr, int priv, boolean_t allzone)
469 {
470 boolean_t res = HAS_PRIVILEGE(cr, priv) &&
471 (!allzone || HAS_ALLZONEPRIVS(cr));
472
955 PRIV_FILE_DAC_EXECUTE;
956
957 return (priv_policy_va(cr, p, B_FALSE, EACCES, NULL,
958 KLPDARG_VNODE, vp, (char *)NULL, KLPDARG_NOMORE));
959 }
960 return (0);
961 }
962
963 /*
964 * Like secpolicy_vnode_access() but we get the actual wanted mode and the
965 * current mode of the file, not the missing bits.
966 */
967 int
968 secpolicy_vnode_access2(const cred_t *cr, vnode_t *vp, uid_t owner,
969 mode_t curmode, mode_t wantmode)
970 {
971 mode_t mode;
972
973 /* Inline the basic privileges tests. */
974 if ((wantmode & VREAD) &&
975 !PRIV_ISASSERT(&CR_OEPRIV(cr), PRIV_FILE_READ) &&
976 priv_policy_va(cr, PRIV_FILE_READ, B_FALSE, EACCES, NULL,
977 KLPDARG_VNODE, vp, (char *)NULL, KLPDARG_NOMORE) != 0) {
978 return (EACCES);
979 }
980
981 if ((wantmode & VWRITE) &&
982 !PRIV_ISASSERT(&CR_OEPRIV(cr), PRIV_FILE_WRITE) &&
983 priv_policy_va(cr, PRIV_FILE_WRITE, B_FALSE, EACCES, NULL,
984 KLPDARG_VNODE, vp, (char *)NULL, KLPDARG_NOMORE) != 0) {
985 return (EACCES);
986 }
987
988 mode = ~curmode & wantmode;
989
990 if (mode == 0)
991 return (0);
992
993 if ((mode & VREAD) && priv_policy_va(cr, PRIV_FILE_DAC_READ, B_FALSE,
994 EACCES, NULL, KLPDARG_VNODE, vp, (char *)NULL,
995 KLPDARG_NOMORE) != 0) {
996 return (EACCES);
997 }
998
999 if (mode & VWRITE) {
1000 boolean_t allzone;
1001
1002 if (owner == 0 && cr->cr_uid != 0)
|
128 * For (1), priv should be set to the specific privilege, and allzone
129 * should be set to B_FALSE.
130 * For (2), priv should be set to the specific privilege, and allzone
131 * should be set to B_TRUE.
132 * For (3), priv should be set to PRIV_ALL, and allzone should be set
133 * to B_FALSE.
134 *
135 */
136
137 /*
138 * The privileges are checked against the Effective set for
139 * ordinary processes and checked against the Limit set
140 * for euid 0 processes that haven't manipulated their privilege
141 * sets.
142 */
143 #define HAS_ALLPRIVS(cr) priv_isfullset(&CR_OEPRIV(cr))
144 #define ZONEPRIVS(cr) ((cr)->cr_zone->zone_privset)
145 #define HAS_ALLZONEPRIVS(cr) priv_issubset(ZONEPRIVS(cr), &CR_OEPRIV(cr))
146 #define HAS_PRIVILEGE(cr, pr) ((pr) == PRIV_ALL ? \
147 HAS_ALLPRIVS(cr) : \
148 PRIV_ISMEMBER(&CR_OEPRIV(cr), pr))
149
150 #define FAST_BASIC_CHECK(cr, priv) \
151 if (PRIV_ISMEMBER(&CR_OEPRIV(cr), priv)) { \
152 DTRACE_PROBE2(priv__ok, int, priv, boolean_t, B_FALSE); \
153 return (0); \
154 }
155
156 /*
157 * Policy checking functions.
158 *
159 * All of the system's policy should be implemented here.
160 */
161
162 /*
163 * Private functions which take an additional va_list argument to
164 * implement an object specific policy override.
165 */
166 static int priv_policy_ap(const cred_t *, int, boolean_t, int,
167 const char *, va_list);
168 static int priv_policy_va(const cred_t *, int, boolean_t, int,
169 const char *, ...);
170
171 /*
384 } else {
385 ASSERT(!HAS_PRIVILEGE(cr, priv));
386 priv_policy_errmsg(cr, priv, msg);
387 }
388 }
389 }
390
391 /*
392 * priv_policy_ap()
393 * return 0 or error.
394 * See block comment above for a description of "priv" and "allzone" usage.
395 */
396 static int
397 priv_policy_ap(const cred_t *cr, int priv, boolean_t allzone, int err,
398 const char *msg, va_list ap)
399 {
400 if ((HAS_PRIVILEGE(cr, priv) && (!allzone || HAS_ALLZONEPRIVS(cr))) ||
401 (!servicing_interrupt() &&
402 priv_policy_override(cr, priv, allzone, ap) == 0)) {
403 if ((allzone || priv == PRIV_ALL ||
404 !PRIV_ISMEMBER(priv_basic, priv)) &&
405 !servicing_interrupt()) {
406 PTOU(curproc)->u_acflag |= ASU; /* Needed for SVVS */
407 if (AU_AUDITING())
408 audit_priv(priv,
409 allzone ? ZONEPRIVS(cr) : NULL, 1);
410 }
411 err = 0;
412 DTRACE_PROBE2(priv__ok, int, priv, boolean_t, allzone);
413 } else if (!servicing_interrupt()) {
414 /* Failure audited in this procedure */
415 priv_policy_err(cr, priv, allzone, msg);
416 }
417 return (err);
418 }
419
420 int
421 priv_policy_va(const cred_t *cr, int priv, boolean_t allzone, int err,
422 const char *msg, ...)
423 {
424 int ret;
432 }
433
434 int
435 priv_policy(const cred_t *cr, int priv, boolean_t allzone, int err,
436 const char *msg)
437 {
438 return (priv_policy_va(cr, priv, allzone, err, msg, KLPDARG_NONE));
439 }
440
441 /*
442 * Return B_TRUE for sufficient privileges, B_FALSE for insufficient privileges.
443 */
444 boolean_t
445 priv_policy_choice(const cred_t *cr, int priv, boolean_t allzone)
446 {
447 boolean_t res = HAS_PRIVILEGE(cr, priv) &&
448 (!allzone || HAS_ALLZONEPRIVS(cr));
449
450 /* Audit success only */
451 if (res && AU_AUDITING() &&
452 (allzone || priv == PRIV_ALL || !PRIV_ISMEMBER(priv_basic, priv)) &&
453 !servicing_interrupt()) {
454 audit_priv(priv, allzone ? ZONEPRIVS(cr) : NULL, 1);
455 }
456 if (res) {
457 DTRACE_PROBE2(priv__ok, int, priv, boolean_t, allzone);
458 } else {
459 DTRACE_PROBE2(priv__err, int, priv, boolean_t, allzone);
460 }
461 return (res);
462 }
463
464 /*
465 * Non-auditing variant of priv_policy_choice().
466 */
467 boolean_t
468 priv_policy_only(const cred_t *cr, int priv, boolean_t allzone)
469 {
470 boolean_t res = HAS_PRIVILEGE(cr, priv) &&
471 (!allzone || HAS_ALLZONEPRIVS(cr));
472
955 PRIV_FILE_DAC_EXECUTE;
956
957 return (priv_policy_va(cr, p, B_FALSE, EACCES, NULL,
958 KLPDARG_VNODE, vp, (char *)NULL, KLPDARG_NOMORE));
959 }
960 return (0);
961 }
962
963 /*
964 * Like secpolicy_vnode_access() but we get the actual wanted mode and the
965 * current mode of the file, not the missing bits.
966 */
967 int
968 secpolicy_vnode_access2(const cred_t *cr, vnode_t *vp, uid_t owner,
969 mode_t curmode, mode_t wantmode)
970 {
971 mode_t mode;
972
973 /* Inline the basic privileges tests. */
974 if ((wantmode & VREAD) &&
975 !PRIV_ISMEMBER(&CR_OEPRIV(cr), PRIV_FILE_READ) &&
976 priv_policy_va(cr, PRIV_FILE_READ, B_FALSE, EACCES, NULL,
977 KLPDARG_VNODE, vp, (char *)NULL, KLPDARG_NOMORE) != 0) {
978 return (EACCES);
979 }
980
981 if ((wantmode & VWRITE) &&
982 !PRIV_ISMEMBER(&CR_OEPRIV(cr), PRIV_FILE_WRITE) &&
983 priv_policy_va(cr, PRIV_FILE_WRITE, B_FALSE, EACCES, NULL,
984 KLPDARG_VNODE, vp, (char *)NULL, KLPDARG_NOMORE) != 0) {
985 return (EACCES);
986 }
987
988 mode = ~curmode & wantmode;
989
990 if (mode == 0)
991 return (0);
992
993 if ((mode & VREAD) && priv_policy_va(cr, PRIV_FILE_DAC_READ, B_FALSE,
994 EACCES, NULL, KLPDARG_VNODE, vp, (char *)NULL,
995 KLPDARG_NOMORE) != 0) {
996 return (EACCES);
997 }
998
999 if (mode & VWRITE) {
1000 boolean_t allzone;
1001
1002 if (owner == 0 && cr->cr_uid != 0)
|