Files
Arquivotheca.AIX-4.1.3/bos/kernel/pfs/xix_acl.c
seta75D d6fe8fe829 Init
2021-10-11 22:19:34 -03:00

498 lines
11 KiB
C

static char sccsid[] = "@(#)87 1.27.1.12 src/bos/kernel/pfs/xix_acl.c, syspfs, bos411, 9439C411e 9/30/94 12:59:40";
/*
* COMPONENT_NAME: (SYSPFS) Physical File System
*
* FUNCTIONS: jfs_getacl(), jfs_setacl()
*
* ORIGINS: 27
*
* 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.
*/
#include "jfs/jfslock.h"
#include "jfs/inode.h"
#include "sys/errno.h"
#include "sys/syspest.h"
#include "sys/malloc.h"
#include "sys/user.h"
#define DPRINTF(args)
int acl_check(struct acl *acl, int len);
int uiosiz(struct uio *uiop);
static int i_getacl(struct inode *ip, struct uio *uiop);
static int i_setacl(struct inode *ip, struct uio *uiop, struct ucred *crp);
/*
* NAME: jfs_getacl(vp, uiop, crp)
*
* FUNCTION: Return ACL of file
*
* PARAMETERS: vp _ is the pointer to the vnode that represents the file
* to get the ACL from
* uiop - address of a uio structure in which to put the ACL
* crp - credential
*
* RETURN : 0 if successful, errno otherwise
*/
int
jfs_getacl(vp, uiop, crp)
struct vnode *vp;
struct uio *uiop;
struct ucred *crp; /* pointer to credential structure */
{
/* the inode of interest */
struct inode *ip;
int rc;
DPRINTF(("jfs_getacl():\n"));
ip = VTOIP(vp);
IWRITE_LOCK(ip);
if (ip->i_acl & ACL_INCORE)
/* get acl of incore object: lfs/vfs_access.c */
rc = ic_getacl(ip->i_acl, ip->i_mode, uiop);
else
rc = i_getacl(ip, uiop);
IWRITE_UNLOCK(ip);
return(rc);
}
/*
* NAME: jfs_setacl(vp, uiop, crp)
*
* FUNCTION: Store ACL of file
*
* PARAMETERS: vp _ is the pointer to the vnode that represents the file
* the ACL is for
* uiop - address of a uio structure containing the ACL
* crp - credential
*
* RETURN : 0 if successful, errno otherwise
*/
int
jfs_setacl(vp, uiop, crp)
struct vnode *vp;
struct uio *uiop;
struct ucred *crp; /* pointer to credential structure */
{
struct inode *ip;
int rc;
DPRINTF(("jfs_setacl():\n"));
ip = VTOIP(vp);
IWRITE_LOCK(ip);
/*
* Is the user authorized to modify the ACL? If they
* aren't, do they have the required kernel privilege?
*/
if ((crp->cr_uid != ip->i_uid) && privcheck_cr(SET_OBJ_DAC, crp))
{
rc = EPERM;
goto out;
}
/*
* Should the ACL be incore or persistent ?
* incore objects (unlinked open files and MPX files)
* should have their ACLs incore.
*/
if ((ip->i_nlink == 0) ||
(vp->v_vntype == VMPC) ||
(ip->i_acl & ACL_INCORE))
{
/* set acl of incore object: lfs/vfs_access.c */
if ((rc = ic_setacl(&ip->i_acl, &ip->i_mode, ip->i_gid,
uiop, crp)) == 0)
imark(ip, ICHG);
}
else
rc = i_setacl(ip, uiop, crp); /* persistent */
out:
IWRITE_UNLOCK(ip);
return(rc);
}
/*
* NAME: i_getacl(vp, uiop)
*
* FUNCTION: Return ACL of an inode which gets committed;
* i.e., the ACL resides in the ".inodex" segment.
*
* PARAMETERS: ip - is the pointer to the inode that represents the file
* to get the ACL from
* uiop - address of a uio structure in which to put the ACL
*
* RETURN : 0 if successful, errno otherwise
*
* SERIALIZATION: called only by jfs_getacl()
* with inode locked on entry/exit
*/
i_getacl(struct inode *ip,
struct uio *uiop)
{
int rc; /* normal junk */
label_t jb; /* jump buf pointer */
struct inode *ixip = NULL; /* the .inodex segment */
caddr_t saddr;
struct acl aclhead; /* head of acl */
struct acl *aclptr; /* the real acl */
DPRINTF(("i_getacl():\n"));
/* build the acl header from the file mode */
DPRINTF(("jfs_getacl(): fixing mode\n"));
aclhead.acl_mode = ip->i_mode & ACL_MODE;
aclhead.u_access = (ip->i_mode >> 6) & 0x7;
aclhead.g_access = (ip->i_mode >> 3) & 0x7;
aclhead.o_access = ip->i_mode & 0x7;
/* if an ACL doesn't exist for this file then just return the header */
if (ip->i_acl == 0)
{
aclptr = NULL;
aclhead.acl_len = ACL_SIZ;
}
else
{
ixip = ip->i_ipmnt->i_ipinodex;
/* get addressibility to the acl */
if (rc = iptovaddr(ixip, 1, &saddr))
return rc;
aclptr = (struct acl *)((int)saddr + (int)(ip->i_acl));
IWRITE_LOCK(ixip);
/* set up error handling */
if (rc = setjmpx(&jb))
switch (rc)
{
case ENOSPC:
rc = ENOMEM;
case ENOMEM:
case EIO:
goto out;
default:
assert(0);
}
aclhead.acl_len = aclptr->acl_len;
}
/* if the user's recieve buffer is smaller than the ACL, try
* to inform the user of the necessary size and return ENOSPC
*/
DPRINTF(("jfs_getacl(): checking size\n"));
if (uiosiz(uiop) < aclhead.acl_len)
{
int len;
DPRINTF(("jfs_getacl(): uiosiz=%d, len=%d\n", uiosiz(uiop),
aclhead.acl_len));
len = aclhead.acl_len;
uiop->uio_offset = 0;
uiop->uio_iov->iov_len = uiop->uio_resid = sizeof(len);
rc = uiomove((caddr_t)&len, (int)sizeof(len),
(enum uio_rw)UIO_READ, (struct uio *)uiop);
if (rc == 0)
rc = ENOSPC;
goto out;
}
DPRINTF(("jfs_getacl(): copy out head\n"));
if (rc = uiomove((caddr_t)&aclhead, (int)ACL_SIZ,
(enum uio_rw)UIO_READ, (struct uio *)uiop))
goto out;
DPRINTF(("jfs_getacl(): copy out extended entries\n"));
if (aclptr)
rc = uiomove((caddr_t)(((char *) aclptr) + ACL_SIZ),
(int)(aclhead.acl_len - ACL_SIZ),
(enum uio_rw)UIO_READ, (struct uio *)uiop);
DPRINTF (("jfs_getacl(): successful\n"));
out:
if (ixip)
{
IWRITE_UNLOCK(ixip);
DPRINTF(("jfs_getacl(): unbinding \".inodex\"\n"));
clrjmpx(&jb);
ipundo(saddr);
}
return(rc);
}
/*
* NAME: i_setacl(ip, uiop, crp)
*
* FUNCTION: Store ACL of file which is not to be committed;
* i.e., one for which the ACL is not stored in the
* ".inodex" segment.
*
* PARAMETERS: vp _ is the pointer to the vnode that represents the file
* the ACL is for
* uiop - address of a uio structure containing the ACL
* crp - credential
*
* RETURN : any errors that occur while updating the inode
*
* SERIALIZATION: called only by jfs_setacl()
* with inode locked on entry/exit
*/
i_setacl(struct inode *ip,
struct uio *uiop,
struct ucred *crp)
{
int rc=0;
label_t jb; /* jump buf pointer */
caddr_t saddr;
struct inode *ixip = NULL; /* the inode extension segment */
struct acl *newacl;
ulong newmode;
int len;
DPRINTF (("i_setacl(): \n"));
/* get the new ACL length */
len = uiosiz(uiop);
if (len < ACL_SIZ)
{
DPRINTF(("i_setacl(): len=%d sizeof acl=%d\n", len, ACL_SIZ));
DPRINTF(("jfs_setacl(): bad length\n"));
return(EINVAL);
}
/* allocate space for the new acl */
newacl = (struct acl *)malloc((uint)len);
if (newacl == NULL)
{
DPRINTF(("i_setacl(): malloc failed!!! (len=%d)\n", len));
return(ENOMEM);
}
/* copy the new acl and check it out ... */
DPRINTF (("jfs_setacl(): copying down and checking it out\n"));
if ((rc = uiomove((caddr_t)newacl, (int)len,
(enum uio_rw)UIO_WRITE,
(struct uio *)uiop)) ||
(rc = acl_check(newacl, len)))
{
DPRINTF(("i_setacl(): copy or check failed!!! (rc=%d)\n", rc));
free((void *)newacl);
return(rc);
}
/* create new mode */
DPRINTF(("jfs_setacl(): creating mode\n"));
newmode = ip->i_mode & ~(ACL_MODE | 0777);
newmode |= newacl->acl_mode;
newmode |= (newacl->u_access << 6) |
(newacl->g_access << 3) |
(newacl->o_access);
/*
* If we don't have SET_OBJ_DAC then
* we can only add the sticky bit on directories
* (BSD sticky (8)) and
* we can only add (or keep) the ISGID bit
* if we are in the owning group. (This means
* If we own the file but are not in the owning
* Group we can't keep the bit)
*/
if (privcheck_cr(SET_OBJ_DAC, crp))
{
if (!S_ISDIR (ip -> i_mode))
newmode &= ~ISVTX;
if (!groupmember_cr(ip->i_gid, crp))
newmode &= ~ISGID;
}
ip->i_mode = newmode;
imark(ip, ICHG);
/* free old acl if present
*/
if (ip->i_acl)
{
ixip = ip->i_ipmnt->i_ipinodex;
/* map .inodex into vm */
iptovaddr(ixip, 1, &saddr);
/* Since we will need a transaction block, gain it before
* locking .inodex. Otherwise we could deadlock due to
* blocking on syncwait and having remove/rename block on
* .inodex lock.
*/
if (u.u_fstid == 0)
vcs_gettblk(&rc);
IWRITE_LOCK(ixip);
if ((rc = setjmpx(&jb)) == 0)
{
smap_free(ixip, saddr, ip->i_acl) ;
clrjmpx(&jb);
}
else
switch (rc)
{
case ENOSPC:
case ENOMEM:
case EIO:
break;
default:
assert(0);
}
ip->i_acl = 0;
}
/* allocate and initialize new acl
*/
if (newacl->acl_len > ACL_SIZ)
{
DPRINTF(("jfs_setacl(): extended acl\n"));
if (ixip == NULL)
{
ixip = ip->i_ipmnt->i_ipinodex;
/* map .inodex into vm */
iptovaddr(ixip, 1, &saddr);
if (u.u_fstid == 0)
vcs_gettblk(&rc);
IWRITE_LOCK(ixip);
}
if ((rc = setjmpx(&jb)) == 0)
{
smap_alloc(ixip, saddr, len, &(ip->i_acl));
/* get transaction lock for acl */
vm_gettlock(saddr + ip->i_acl, newacl->acl_len);
bcopy(newacl, saddr + ip->i_acl, newacl->acl_len);
clrjmpx(&jb);
}
else
switch (rc)
{
case ENOSPC:
case ENOMEM:
case EIO:
break;
default:
assert(0);
}
}
free((void *)newacl);
if (ixip)
{
ipundo(saddr);
DPRINTF(("jfs_setacl(): committing ixip and ip\n"));
imark(ixip, IFSYNC);
commit(2, ixip, ip);
IWRITE_UNLOCK(ixip);
}
else
{
DPRINTF(("jfs_setacl(): committing ip\n"));
commit(1, ip);
}
return(0);
}
/*
* NAME: acl_check(acl, len)
*
* FUNCTION: perform minimal correctness checking on an ACL:
* 1) acl->acl_len == len
* 2) use "valid_acl()" to check sums
* 3) force off "irrelevant" mode bits
*
* only called by i_setacl().
*
* PARAMETERS: acl - a pointer to the access control list to
* be checked
* len - the advertised length of this list
*
* RETURN : 0 if successful, otherwise EINVAL or ENOSPC
*/
acl_check(struct acl *acl,
int len)
{
DPRINTF(("acl_check():\n"));
if (smap_alloc_check(len))
{
DPRINTF(("acl_check(): len=%d smap_alloc_check failed\n",len));
return(ENOSPC);
}
if (acl->acl_len != len)
{
DPRINTF(("acl_check(): lengths don't match\n"));
return(EINVAL);
}
if (!valid_acl(acl))
{
DPRINTF(("acl_check(): sum of lengths bad\n"));
return(EINVAL);
}
/* strip the mode bits */
DPRINTF(("acl_check(): successful\n"));
acl->acl_mode &= ACL_MODE;
acl->u_access &= 07;
acl->g_access &= 07;
acl->o_access &= 07;
return (0);
}
/*
* NAME: uiosiz (uiop)
*
* FUNCTION: Return the total length of the buffers in a uio
*
* PARAMETERS: uiop - the address of the uio structure
*
* RETURN : the length of the uio structure
*/
uiosiz(struct uio *uiop)
{
struct iovec *iov;
int i;
int len=0;
iov = uiop->uio_iov;
for (i=0; i<uiop->uio_iovcnt; i++)
len += iov[i].iov_len;
return(len);
}