716 lines
17 KiB
C
716 lines
17 KiB
C
static char sccsid[] = "@(#)29 1.19.1.12 src/bos/kernel/s/auth/uid.c, syssauth, bos411, 9428A410j 5/11/94 07:38:15";
|
|
|
|
/*
|
|
* COMPONENT_NAME: SYSSAUTH
|
|
*
|
|
* FUNCTIONS: getuidx
|
|
* seteuid
|
|
* setreuid
|
|
* setuid
|
|
* setuidx
|
|
*
|
|
* ORIGINS: 27 83
|
|
*
|
|
* IBM CONFIDENTIAL -- (IBM Confidential Restricted when
|
|
* combined with the aggregated modules for this product)
|
|
* SOURCE MATERIALS
|
|
*
|
|
* (C) COPYRIGHT International Business Machines Corp. 1988,1994
|
|
* All Rights Reserved
|
|
* US Government Users Restricted Rights - Use, duplication or
|
|
* disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
|
|
*/
|
|
/*
|
|
* LEVEL 1, 5 Years Bull Confidential Information
|
|
*/
|
|
|
|
#include "sys/types.h"
|
|
#include "sys/user.h"
|
|
#include "sys/priv.h"
|
|
#include "sys/id.h"
|
|
#include "sys/errno.h"
|
|
#include "sys/audit.h"
|
|
#include "sys/var.h"
|
|
#include "sys/syspest.h"
|
|
#include "crlock.h"
|
|
|
|
extern Simple_lock cred_lock;
|
|
|
|
/*
|
|
* setuidx() implements AIX security policy and is the basis for the
|
|
* compatiblity interfaces: setuid(), setreuid() and seteuid().
|
|
*
|
|
* The policy can be stated:
|
|
* The 3 id's (saved, real and effective) form a hierarchy. If
|
|
* the saved id is set then so are the real and effective. If the
|
|
* real is set then the effective is set also. The effective id can
|
|
* be set to the current real or saved id, or to any arbitrary value
|
|
* if the user has the SET_PROC_DAC privilege. In all other cases
|
|
* the SET_PROC_DAC privilege is required. Setting the login id
|
|
* requires both SET_PROC_DAC and SET_PROC_AUDIT privilege.
|
|
*
|
|
* Privileges:
|
|
* SET_PROC_AUDIT is required to set ID_LOGIN
|
|
* SET_PROC_DAC is required to set ID_SAVED or ID_REAL
|
|
* SET_PROC_DAC is required to set ID_EFFECTIVE to an id
|
|
* other than the real or saved.
|
|
*
|
|
* ARGUMENTS:
|
|
* mask these are the only 5 valid values:
|
|
* ID_EFFECTIVE
|
|
* ID_EFFECTIVE|ID_REAL
|
|
* ID_EFFECTIVE|ID_REAL|ID_SAVED
|
|
* ID_EFFECTIVE|ID_REAL|ID_SAVED|ID_LOGIN
|
|
* ID_LOGIN
|
|
*
|
|
* uid value the uid(s) are to be set
|
|
*/
|
|
setuidx(int mask,
|
|
uid_t uid)
|
|
{
|
|
int rc;
|
|
static int svcnumR = 0;
|
|
static int svcnumA = 0;
|
|
unsigned long r_val;
|
|
unsigned long l_val;
|
|
|
|
r_val = U.U_cred->cr_ruid;
|
|
l_val = U.U_cred->cr_luid;
|
|
|
|
if(audit_flag && audit_svcstart("PROC_RealUID", &svcnumR, 1, r_val)){
|
|
audit_svcfinis();
|
|
}
|
|
|
|
if(audit_flag && audit_svcstart("PROC_AuditID", &svcnumA, 1, l_val)){
|
|
audit_svcfinis();
|
|
}
|
|
|
|
CRED_LOCK();
|
|
rc = _setuidx (mask, uid);
|
|
CRED_UNLOCK();
|
|
return rc;
|
|
}
|
|
|
|
_setuidx(int mask,
|
|
uid_t uid)
|
|
{
|
|
uid_t ruid, suid;
|
|
|
|
if (uid >= UID_MAX)
|
|
{
|
|
u.u_error = EINVAL;
|
|
return(-1);
|
|
}
|
|
|
|
/*
|
|
* Set the effective, real, saved, and login UIDs. Process
|
|
* must have both SET_PROC_DAC and SET_PROC_AUDIT privileges.
|
|
* Modify the four IDs in the credentials structure, plus
|
|
* the set-user ID and real user ID in the proc structure.
|
|
*/
|
|
|
|
if (mask == (ID_EFFECTIVE|ID_REAL|ID_SAVED|ID_LOGIN))
|
|
{
|
|
if ((u.u_error = _privcheck(SET_PROC_DAC)) ||
|
|
(u.u_error = _privcheck(SET_PROC_AUDIT)))
|
|
return(-1);
|
|
|
|
/*
|
|
* Setting the real UID causes a check of the number of
|
|
* processes currently being executed by this UID to be made.
|
|
* Fail if we exceed the current limit.
|
|
*/
|
|
|
|
if (new_uidl(U.U_procp, uid, mask))
|
|
{
|
|
return(-1);
|
|
}
|
|
|
|
U.U_cred = _crcopy(U.U_cred);
|
|
U.U_cred->cr_luid = uid;
|
|
U.U_cred->cr_suid = uid;
|
|
U.U_cred->cr_ruid = uid;
|
|
U.U_cred->cr_uid = uid;
|
|
return(0);
|
|
}
|
|
|
|
/*
|
|
* Set the effective, real, and saved UIDs. Process must
|
|
* have SET_PROC_DAC privileges. Modify the three IDs in
|
|
* the credentials structure, plus the set-user ID and
|
|
* real user ID in the proc structure.
|
|
*/
|
|
|
|
if (mask == (ID_EFFECTIVE|ID_REAL|ID_SAVED))
|
|
{
|
|
if (u.u_error = _privcheck(SET_PROC_DAC))
|
|
return(-1);
|
|
|
|
/*
|
|
* Setting the real UID causes a check of the number of
|
|
* processes currently being executed by this UID to be made.
|
|
* Fail if we exceed the current limit.
|
|
*/
|
|
|
|
if (new_uidl(U.U_procp, uid, mask))
|
|
{
|
|
return(-1);
|
|
}
|
|
|
|
U.U_cred = _crcopy(U.U_cred);
|
|
U.U_cred->cr_suid = uid;
|
|
U.U_cred->cr_ruid = uid;
|
|
U.U_cred->cr_uid = uid;
|
|
return(0);
|
|
}
|
|
|
|
/*
|
|
* Set the effective and real UIDs. Process must
|
|
* have SET_PROC_DAC privilege. Modify the two IDs in
|
|
* the credentials structure, plus the real user ID
|
|
* in the proc structure.
|
|
*/
|
|
|
|
if (mask == (ID_EFFECTIVE|ID_REAL))
|
|
{
|
|
if (u.u_error = _privcheck(SET_PROC_DAC))
|
|
return(-1);
|
|
|
|
/*
|
|
* Setting the real UID causes a check of the number of
|
|
* processes currently being executed by this UID to be made.
|
|
* Fail if we exceed the current limit.
|
|
*/
|
|
|
|
if (new_uidl(U.U_procp, uid, mask))
|
|
{
|
|
return(-1);
|
|
}
|
|
|
|
U.U_cred = _crcopy(U.U_cred);
|
|
U.U_cred->cr_ruid = uid;
|
|
U.U_cred->cr_uid = uid;
|
|
return(0);
|
|
}
|
|
|
|
/*
|
|
* Set the effective UID. Process does not need any
|
|
* privilege for this operation, but may only set the
|
|
* effective to the real or saved UID.
|
|
*/
|
|
|
|
if (mask == ID_EFFECTIVE)
|
|
{
|
|
ruid = U.U_cred->cr_ruid;
|
|
suid = U.U_cred->cr_suid;
|
|
if ((uid != ruid) &&
|
|
(uid != suid) &&
|
|
_privcheck(SET_PROC_DAC))
|
|
{
|
|
u.u_error = EPERM;
|
|
return(-1);
|
|
}
|
|
U.U_cred = _crcopy(U.U_cred);
|
|
U.U_cred->cr_uid = uid;
|
|
return(0);
|
|
}
|
|
|
|
/*
|
|
* Set only the login UID. Process must have both the
|
|
* SET_PROC_DAC and SET_PROC_AUDIT privileges. Only the
|
|
* login UID in the credentials structure is affected.
|
|
*/
|
|
|
|
if (mask == ID_LOGIN)
|
|
{
|
|
if ((u.u_error = _privcheck(SET_PROC_AUDIT)) ||
|
|
(u.u_error = _privcheck(SET_PROC_DAC)))
|
|
return(-1);
|
|
|
|
U.U_cred = _crcopy(U.U_cred);
|
|
U.U_cred->cr_luid = uid;
|
|
return(0);
|
|
}
|
|
|
|
/*
|
|
* None of the valid groups of UIDs were selected to be
|
|
* set, so return an error indicating the mask is invalid.
|
|
*/
|
|
|
|
u.u_error = EINVAL;
|
|
return(-1);
|
|
}
|
|
|
|
|
|
/*
|
|
* Note: This comment is for the setuid() and setreuid() system calls.
|
|
*
|
|
* In order to maintain the flavor of previous privilege mechanisms
|
|
* the privileges may need to be reset. When changing the effective
|
|
* uid to the real uid, the effective privilege vector is set to
|
|
* the inherited privilege vector. Likewise, when changing the effective
|
|
* uid to the saved uid, the effective privilege vector is set to the
|
|
* maximum privilege vector.
|
|
*
|
|
* uid <- real implies eff_priv <- inh_priv
|
|
* uid <- saved implies eff_priv <- max_priv
|
|
*
|
|
* The rational behind this behaviour is that when switching back to
|
|
* the real UID, the program intends to execute with the privileges
|
|
* which were inherited from the invoker, who probably is an unprivileged
|
|
* user. When switching back to the saved UID, the program intends to
|
|
* executed with any acquired privileges associated with the executable
|
|
* file.
|
|
*
|
|
* General rules of thumb: Call setuidx() before changing the privilege
|
|
* sets - doing this the other way can cause setuidx() to fail needlessly.
|
|
* There is no need to copy the credentials structure - setuidx() does it
|
|
* for you. Do not modify the privileges if setuidx() fails - no point
|
|
* in doing things half-way.
|
|
*
|
|
* Exception to general rule of thumb: POSIX requires setuid(euid) to
|
|
* always succeed. Since setuidx(ID_REAL|ID_EFFECTIVE) may fail in some
|
|
* situations, we must LIE and say the call passes - AND - we must perform
|
|
* the privilige set changes as normally performed.
|
|
*/
|
|
|
|
int
|
|
setuid(uid_t uid)
|
|
{
|
|
int rc;
|
|
static int svcnumR = 0;
|
|
static int svcnumA = 0;
|
|
unsigned long r_val;
|
|
unsigned long l_val;
|
|
|
|
r_val = U.U_cred->cr_ruid;
|
|
l_val = U.U_cred->cr_luid;
|
|
|
|
if(audit_flag && audit_svcstart("PROC_RealUID", &svcnumR, 1, r_val)){
|
|
audit_svcfinis();
|
|
}
|
|
|
|
if(audit_flag && audit_svcstart("PROC_AuditID", &svcnumA, 1, l_val)){
|
|
audit_svcfinis();
|
|
}
|
|
|
|
CRED_LOCK();
|
|
rc = _setuid(uid);
|
|
CRED_UNLOCK();
|
|
return rc;
|
|
}
|
|
|
|
int
|
|
_setuid(uid_t uid)
|
|
{
|
|
int rc;
|
|
|
|
if (uid >= UID_MAX)
|
|
{
|
|
u.u_error = EINVAL;
|
|
return(-1);
|
|
}
|
|
|
|
|
|
if (_privcheck(SET_PROC_DAC) == 0)
|
|
{
|
|
if (new_uidl(U.U_procp, uid, ID_REAL|ID_SAVED))
|
|
{
|
|
return(-1);
|
|
}
|
|
|
|
U.U_cred = _crcopy(U.U_cred);
|
|
U.U_cred->cr_suid = uid;
|
|
U.U_cred->cr_ruid = uid;
|
|
U.U_cred->cr_uid = uid;
|
|
|
|
/*
|
|
* Check the value of uid so that the root user does not
|
|
* have his priveleges cleared out. This will ensure that
|
|
* the value of LIBPATH can be taken from the environment.
|
|
*/
|
|
if (!(uid == 0 && v.v_leastpriv == 0)) {
|
|
priv_clr (&U.U_cred->cr_mpriv);
|
|
U.U_cred->cr_epriv = U.U_cred->cr_mpriv;
|
|
U.U_cred->cr_ipriv = U.U_cred->cr_mpriv;
|
|
U.U_cred->cr_bpriv = U.U_cred->cr_mpriv;
|
|
}
|
|
return 0;
|
|
|
|
}
|
|
|
|
/*
|
|
* We are sure of not having SET_PROC_DAC privilege here
|
|
*/
|
|
|
|
/*
|
|
* Change to the privilege domain of the program invoker
|
|
* temporarily. Change the effective and bequeath privileges
|
|
* to those of the invoker. This does not require any
|
|
* privilege since only the effective UID is being changed.
|
|
*/
|
|
if (uid == U.U_cred->cr_ruid)
|
|
{
|
|
/*
|
|
* Down here we are sure of not having SET_PROC_DAC
|
|
* privilege. Also, uid is equal to the real uid of the
|
|
* process
|
|
*/
|
|
U.U_cred = _crcopy(U.U_cred);
|
|
U.U_cred->cr_uid = uid;
|
|
|
|
U.U_cred->cr_epriv = U.U_cred->cr_ipriv;
|
|
U.U_cred->cr_bpriv = U.U_cred->cr_ipriv;
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Change to the privilege domain of the program itself.
|
|
*/
|
|
|
|
if (uid == U.U_cred->cr_suid)
|
|
{
|
|
if (uid == U.U_cred->cr_uid)
|
|
{
|
|
/*
|
|
* Down here we are sure of not having SET_PROC_DAC
|
|
* privilege. But the call should return success for
|
|
* the above given reason
|
|
*/
|
|
U.U_cred = _crcopy (U.U_cred);
|
|
|
|
U.U_cred->cr_ipriv = U.U_cred->cr_mpriv;
|
|
U.U_cred->cr_bpriv = U.U_cred->cr_mpriv;
|
|
U.U_cred->cr_epriv = U.U_cred->cr_mpriv;
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* We have no privilege also uid equals saved_uid of the process
|
|
*/
|
|
U.U_cred = _crcopy(U.U_cred);
|
|
U.U_cred->cr_uid = uid;
|
|
|
|
U.U_cred->cr_epriv = U.U_cred->cr_mpriv;
|
|
U.U_cred->cr_bpriv = U.U_cred->cr_mpriv;
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* We don't have SET_PROC_DAC privilege, so return -1 with errno
|
|
* set to EPERM
|
|
*/
|
|
u.u_error = EPERM;
|
|
return(-1);
|
|
}
|
|
|
|
|
|
/*
|
|
* BSD functionality added: arg of -1 => use current uid in it's place
|
|
*
|
|
* For this system call, both real and effective UIDs are specified.
|
|
* However, because the real is only set when the requested real and
|
|
* effective UIDs match, there is no need to check the real parameter.
|
|
*
|
|
* There are a number of circumstances where SET_PROC_DAC kernel
|
|
* privilege is required to change the real UID. You must always be
|
|
* careful to preserve the privilege sets prior to calling setuidx()
|
|
* lest that call fail needlessly!
|
|
*
|
|
* The privilege sets are modified regardless of the return code from
|
|
* setuidx.
|
|
*/
|
|
int
|
|
setreuid(uid_t real,
|
|
uid_t eff)
|
|
{
|
|
int rc;
|
|
static int svcnumR = 0;
|
|
static int svcnumA = 0;
|
|
unsigned long r_val;
|
|
unsigned long l_val;
|
|
|
|
r_val = U.U_cred->cr_ruid;
|
|
l_val = U.U_cred->cr_luid;
|
|
|
|
if(audit_flag && audit_svcstart("PROC_RealUID", &svcnumR, 1, r_val)){
|
|
audit_svcfinis();
|
|
}
|
|
|
|
if(audit_flag && audit_svcstart("PROC_AuditID", &svcnumA, 1, l_val)){
|
|
audit_svcfinis();
|
|
}
|
|
|
|
CRED_LOCK();
|
|
rc = _setreuid (real, eff);
|
|
CRED_UNLOCK();
|
|
return rc;
|
|
}
|
|
|
|
int
|
|
_setreuid(uid_t real,
|
|
uid_t eff)
|
|
{
|
|
int rc;
|
|
|
|
/*
|
|
* BSD args
|
|
*/
|
|
if (eff == -1)
|
|
eff = U.U_cred->cr_uid;
|
|
if (real == -1)
|
|
real = U.U_cred->cr_ruid;
|
|
|
|
/*
|
|
* Change the effective UID to the current real UID to return
|
|
* to the privilege state of the invoker.
|
|
*/
|
|
|
|
if (eff == U.U_cred->cr_ruid)
|
|
{
|
|
if (eff == real)
|
|
{
|
|
/*
|
|
* this change requires SET_PROC_DAC since the
|
|
* real and saved UIDs is being permanently
|
|
* changed.
|
|
*/
|
|
|
|
if (rc = _setuidx (ID_EFFECTIVE|ID_REAL|ID_SAVED, eff))
|
|
return rc;
|
|
|
|
U.U_cred->cr_epriv = U.U_cred->cr_ipriv;
|
|
U.U_cred->cr_bpriv = U.U_cred->cr_ipriv;
|
|
U.U_cred->cr_mpriv = U.U_cred->cr_ipriv;
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* this requires no privilege since the effective UID
|
|
* is being changed to the current value of the real
|
|
* UID.
|
|
*/
|
|
|
|
if (rc = _setuidx (ID_EFFECTIVE, eff))
|
|
return rc;
|
|
|
|
U.U_cred->cr_epriv = U.U_cred->cr_ipriv;
|
|
U.U_cred->cr_bpriv = U.U_cred->cr_ipriv;
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Change the effective to the current saved UID to return
|
|
* to the initial privilege state of the program.
|
|
*/
|
|
|
|
if (eff == U.U_cred->cr_suid)
|
|
{
|
|
if (eff == real)
|
|
{
|
|
/*
|
|
* this change requires SET_PROC_DAC since the
|
|
* real and saved UIDs is being permanently
|
|
* changed.
|
|
*/
|
|
|
|
if (rc = _setuidx(ID_SAVED|ID_REAL|ID_EFFECTIVE, eff))
|
|
return rc;
|
|
|
|
U.U_cred->cr_epriv = U.U_cred->cr_mpriv;
|
|
U.U_cred->cr_bpriv = U.U_cred->cr_mpriv;
|
|
U.U_cred->cr_ipriv = U.U_cred->cr_mpriv;
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* this requires no privilege since the effective UID
|
|
* is being changed to the current value of the saved
|
|
* UID.
|
|
*/
|
|
|
|
if (rc = _setuidx(ID_EFFECTIVE, eff))
|
|
return rc;
|
|
|
|
U.U_cred->cr_epriv = U.U_cred->cr_mpriv;
|
|
U.U_cred->cr_bpriv = U.U_cred->cr_mpriv;
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Change the effective, real, and saved to some new, arbitrary
|
|
* value. The new privilege sets will be empty. The same real
|
|
* and effective UIDs must be requested in order to comply with
|
|
* the security policy.
|
|
*/
|
|
|
|
if (eff != real)
|
|
{
|
|
u.u_error = EPERM;
|
|
return(-1);
|
|
}
|
|
if (rc = _setuidx (ID_EFFECTIVE|ID_REAL|ID_SAVED, eff))
|
|
return rc;
|
|
|
|
priv_clr (&U.U_cred->cr_mpriv);
|
|
U.U_cred->cr_ipriv = U.U_cred->cr_mpriv;
|
|
U.U_cred->cr_bpriv = U.U_cred->cr_mpriv;
|
|
U.U_cred->cr_epriv = U.U_cred->cr_mpriv;
|
|
return rc;
|
|
}
|
|
|
|
/*
|
|
* Return the value of one of the four UIDs.
|
|
*/
|
|
|
|
uid_t
|
|
getuidx(int which)
|
|
{
|
|
unsigned long rval;
|
|
int tlock;
|
|
|
|
if (tlock = (U.U_procp->p_active > 1)) CRED_LOCK();
|
|
if (which == ID_LOGIN)
|
|
{
|
|
rval = U.U_cred->cr_luid;
|
|
goto out;
|
|
}
|
|
|
|
if (which == ID_SAVED)
|
|
{
|
|
rval = U.U_cred->cr_suid;
|
|
goto out;
|
|
}
|
|
|
|
if (which == ID_REAL)
|
|
{
|
|
rval = U.U_cred->cr_ruid;
|
|
goto out;
|
|
}
|
|
|
|
if (which == ID_EFFECTIVE)
|
|
{
|
|
rval = U.U_cred->cr_uid;
|
|
goto out;
|
|
}
|
|
|
|
if (tlock) CRED_UNLOCK();
|
|
|
|
/* which is not valid */
|
|
u.u_error = EINVAL;
|
|
return(-1);
|
|
out:
|
|
if (tlock) CRED_UNLOCK();
|
|
return(rval);
|
|
}
|
|
|
|
/*
|
|
* Sets the effective UID to either the real UID or the saved
|
|
* UID and toggles the effective and bequeath privilege sets
|
|
* between the inherited [ for the real UID ] and the maximum
|
|
* [ for the saved UID ]. This call can be used to toggle back
|
|
* and forth arbitrarily between the invoker's domain and the
|
|
* program's domain.
|
|
*
|
|
* This call does not require privilege since the effective
|
|
* UID is changed to permissible values. EPERM results if an
|
|
* illegal change is requested.
|
|
*/
|
|
|
|
int
|
|
seteuid(uid_t uid)
|
|
{
|
|
int rc;
|
|
static int svcnumR = 0;
|
|
static int svcnumA = 0;
|
|
unsigned long r_val;
|
|
unsigned long l_val;
|
|
|
|
r_val = U.U_cred->cr_ruid;
|
|
l_val = U.U_cred->cr_luid;
|
|
|
|
if(audit_flag && audit_svcstart("PROC_RealUID", &svcnumR, 1, r_val)){
|
|
audit_svcfinis();
|
|
}
|
|
|
|
if(audit_flag && audit_svcstart("PROC_AuditID", &svcnumA, 1, l_val)){
|
|
audit_svcfinis();
|
|
}
|
|
|
|
CRED_LOCK();
|
|
rc = _seteuid (uid);
|
|
CRED_UNLOCK();
|
|
return rc;
|
|
}
|
|
|
|
int
|
|
_seteuid(uid_t uid)
|
|
{
|
|
int rc;
|
|
|
|
/*
|
|
* Change back to the privilege domain of the program
|
|
* invoker. This is not a permanent change.
|
|
*/
|
|
|
|
if (uid == U.U_cred->cr_ruid)
|
|
{
|
|
if (rc = _setuidx (ID_EFFECTIVE, uid))
|
|
return rc;
|
|
|
|
U.U_cred->cr_epriv = U.U_cred->cr_ipriv;
|
|
U.U_cred->cr_bpriv = U.U_cred->cr_ipriv;
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Change back to the privilege domain of the program
|
|
* itself. This is not a permanent change.
|
|
*/
|
|
|
|
if (uid == U.U_cred->cr_suid)
|
|
{
|
|
if (rc = _setuidx (ID_EFFECTIVE, uid))
|
|
return rc;
|
|
|
|
U.U_cred->cr_epriv = U.U_cred->cr_mpriv;
|
|
U.U_cred->cr_bpriv = U.U_cred->cr_mpriv;
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* If the user has sufficient privilege then we may change the
|
|
* effective id.
|
|
*/
|
|
if (_privcheck(SET_PROC_DAC) == 0)
|
|
{
|
|
if (rc = _setuidx(ID_EFFECTIVE, uid))
|
|
return rc;
|
|
|
|
/*
|
|
* If we are changing to someone other than uid 0 then
|
|
* clear the privilege vectors.
|
|
*/
|
|
if (!(uid == 0 && v.v_leastpriv == 0))
|
|
{
|
|
priv_clr(&U.U_cred->cr_epriv);
|
|
priv_clr(&U.U_cred->cr_bpriv);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
if ( uid == U.U_cred->cr_uid )
|
|
{
|
|
/* NO OP */
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* This violates the security policy since the requested
|
|
* effective UID is neither the saved nor real UID.
|
|
*/
|
|
|
|
u.u_error = EPERM;
|
|
return -1;
|
|
}
|