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

435 lines
9.7 KiB
C

static char sccsid[] = "@(#)06 1.16.1.6 src/bos/kernel/s/auth/revoke.c, syssauth, bos41J, 9519B_all 5/5/95 10:09:12";
/*
* COMPONENT_NAME: SYSSAUD
*
* FUNCTIONS: revoke(), frevoke()
*
* 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, 1993
* All Rights Reserved
* Licensed Materials - Property of IBM
*
* 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/user.h"
#include "sys/systm.h"
#include "sys/file.h"
#include "sys/vattr.h"
#include "sys/vnode.h"
#include "sys/var.h"
#include "sys/errno.h"
#include "sys/device.h"
#include "sys/sysinfo.h"
#include "sys/lockl.h"
#include "sys/id.h"
#include "sys/fs_locks.h"
#include "sys/sleep.h"
#include "crlock.h"
#define DPRINTF(args)
extern Simple_lock cred_lock;
static int invalidate(struct file *rfp, struct vnode *rvp, struct vattr *rva);
static int dup(struct file *fp, struct file **nfpp, struct ucred *crp);
static int check(struct vnode *vp, struct vattr *va, struct ucred *crp);
int invalidate_fp(struct file *fp, struct inval_args *inval_check);
struct inval_args {
struct file *rfp; /* for frevoke() this file table entry
* should not be invalidated
*/
struct vattr *rva; /* This contains the device number and channel
* to be revoked
*/
int st; /* Initially 0. On return from ftsearch
it contains number of file table entries
invalidated
*/
};
/*
* Revoke R/W access to a tty for all processes. If a process is blocked
* doing I/O then it will be killed.
*/
revoke(char *path)
{
struct vnode *vp = NULL;
struct ucred *crp;
struct vattr va;
int rc;
DPRINTF(("revoke(): starting...\n"));
crp = crref();
DPRINTF(("revoke(): lookupname...\n"));
/* get the underlying object */
if (u.u_error = lookupname(path, USR, L_SEARCH, NULL, &vp, crp))
goto out;
DPRINTF(("revoke(): check...\n"));
/* verify that it supports revocation */
if (u.u_error = check(vp, &va, crp))
goto out;
DPRINTF(("revoke(): invalidate...\n"));
/* invalidate ALL file table entries which refer to this object */
rc = invalidate((struct file *)0, vp, &va);
DPRINTF(("revoke(): VNOP_REVOKE...\n"));
/* terminate operations in progress (if there are any) */
if (rc)
u.u_error = VNOP_REVOKE(vp, 0, 0, 0, crp);
out: if (vp)
VNOP_RELE(vp);
crfree(crp);
DPRINTF(("revoke(): ending... u.u_error=%d\n", u.u_error));
return(u.u_error ? -1 : 0);
}
/*
* Revoke R/W access to a tty for all processes except this one.
* If a process is blocked doing I/O then it will be killed.
*/
frevoke(int fd)
{
struct ucred *crp;
struct file *fp;
struct file *nfp;
struct vnode *vp;
struct vattr va;
int flag = 0x01;
int rc;
U_FD_LOCK();
if ( (fd < 0 || fd >= U.U_maxofile) ||
((fp = U.U_ufd[fd].fp) == NULL) ||
((fp->f_flag & FREVOKED) && 1) ||
(U.U_ufd[fd].flags & UF_CLOSING) )
{
u.u_error = EBADF;
U_FD_UNLOCK();
goto out;
}
if (fp->f_type != DTYPE_VNODE)
{
u.u_error = EINVAL;
U_FD_UNLOCK();
goto out;
}
U.U_ufd[fd].flags |= UF_CLOSING;
while (U.U_ufd[fd].count != 0)
{
assert(curproc->p_threadcount > 1);
(void) e_sleep_thread(&U.U_fdevent, &U.U_fd_lock, LOCK_SIMPLE);
}
U.U_ufd[fd].count++;
U_FD_UNLOCK();
vp = fp->f_vnode;
crp = crref();
/* verify that the object supports revocation */
if (u.u_error = check(vp, &va, crp))
goto outf;
FP_LOCK(fp);
/* if this open file table entry is shared, get private entry */
if (fp->f_count > 1)
{
FP_UNLOCK(fp);
if (u.u_error = dup(fp, &nfp, crp))
goto outf;
U_FD_LOCK();
U.U_ufd[fd].fp = nfp;
U_FD_UNLOCK();
}
else
{
FP_UNLOCK(fp);
nfp = fp;
}
/* invalidate OTHER file table entries which refer to this object */
rc = invalidate(nfp, vp, &va);
/* terminate operations in progress */
if (rc)
u.u_error = VNOP_REVOKE(vp,flag,nfp->f_flag,(struct vattr*)&(nfp->f_vinfo),crp);
outf:
U_FD_LOCK();
U.U_ufd[fd].flags &= ~UF_CLOSING;
U_FD_UNLOCK();
/* Decrement the file descriptor count */
ufdrele(fd);
crfree(crp);
out:
return(u.u_error ? -1 : 0);
}
/*
* verify that the calling process can revoke access to this object.
* 1) the caller must be the owner of the object (or superuser)
* 2) the object must be a character (or mpx) device
* 3) the device must have a d_revoke() device routine
* returns
* !0 failure, return value is errno
* 0 success
*/
static
check(struct vnode *vp, struct vattr *va, struct ucred *crp)
{
int rc, status;
/*
* do a stat on this vnode to get:
* owner ID
* type (want IFCHR) - could just check v_type for VCHR/VMPC
* dev_t
* chan
*/
if (rc = VNOP_GETATTR(vp, va, crp))
return rc;
/* Is the current process the owner or has BYPASS_DAC_KILL privilege? */
if ((va->va_uid != getuidx(ID_EFFECTIVE)) &&
(privcheck(BYPASS_DAC_KILL)))
return EPERM;
/*
* At present, only character devices are supported.
* In future, will need a more general way to determine
* whether object supports revocation ...
*/
if ((vp->v_type != VCHR) && (vp->v_type != VMPC))
return EINVAL;
/* Is this a revokable device? */
if ( rc = devswqry(va->va_rdev, (uint *)&status, NULL))
return rc;
if (!(status & DSW_TCPATH))
return EINVAL;
return 0;
}
/*
* NAME: dup
*
* FUNCTION: allocate a new open file table entry to REPLACE
* the specified open file table entry;
* the reference count of the old entry is decremented
*
* RETURNS: new fp on success
* NULL on failure
*/
static
dup(struct file *fp, struct file **nfpp, struct ucred *crp)
{
struct vnode *vp;
int rc;
long flag;
FP_LOCK(fp);
flag = fp->f_flag;
FP_UNLOCK(fp);
vp = fp->f_vnode;
/* allocate a new file struct and attach the same vnode */
VNOP_HOLD(vp);
if (rc = fpalloc(vp, flag, fp->f_type, fp->f_ops, nfpp))
{
VNOP_RELE(vp);
return rc;
}
FP_LOCK(fp);
if ( fp->f_count == 1 )
{
FP_UNLOCK(fp);
/*
* The count of the old file table entry has fallen to
* 1, meaning that the file table entry is no longer
* shared
* Free the new entry that has been allocated
*/
fpfree(*nfpp);
VNOP_RELE(vp);
*nfpp = fp;
return(0);
}
CRED_LOCK();
fp->f_cred->cr_ref++;
CRED_UNLOCK();
(*nfpp)->f_cred = fp->f_cred;
/*
* In order to maintain the reference counts properly, we must
* decrement the count on the old fp, set the count on the new
* fp to 1 (done by fpalloc), and re-open the file. It's tempting
* to say that just calling VNOP_HOLD would be sufficient here,
* however, we have created a new open instance rather than just
* held the vnode.
*/
if (rc = VNOP_OPEN(vp,fp->f_flag,0,&(*nfpp)->f_vinfo,crp))
{
VNOP_RELE(vp);
(*nfpp)->f_count = 0;
FP_UNLOCK(fp);
crfree((*nfpp)->f_cred);
fpfree(*nfpp);
return rc;
}
fp->f_count--;
FP_UNLOCK(fp);
return 0;
}
/*
* invalidate all open file table entries which refer to the specified object.
* if the object is a device, <dev> and <chan> are the device;
* otherwise (in the future), a gnode match will be sought.
* if <rfp> is not NULL, this is an FREVOKE (and <rfp> is the open file table
* entry of the caller.
*
* RETURNS: number of open file structs associated with this vnode
*/
static
invalidate(struct file *rfp,
struct vnode *rvp,
struct vattr *rva)
{
struct file *fp;
struct vnode *vp;
struct vattr va;
int rc = 0;
struct inval_args inval_check;
/*
* Put the checking parameters in this structure and send them over
* to ftsearch, ultimately invalidate_fp needs them
*/
inval_check.rfp = rfp;
inval_check.rva = rva;
inval_check.st = 0; /* Initially status is 0 */
ftsearch ( invalidate_fp, DTYPE_VNODE, &inval_check);
/*
* Return number of objects revoked
*/
return(inval_check.st);
}
/*
* This function is called by ftsearch with the file struct locked.
*
* RETURNS: Always returns 0 so that the file table is searched
* completely.
*/
int invalidate_fp(struct file *fp, struct inval_args *inval_check)
{
struct vnode *vp;
struct vattr va;
struct ucred *crp;
int rc;
/* Is this the file entry we want to protect (frevoke only)? */
if ((inval_check->rfp) && ((inval_check->rfp) == fp))
return(0);
/*
* Revocation is supported only on character devices
*/
vp = fp->f_vnode;
if ((vp->v_type != VCHR) && (vp->v_type != VMPC))
return(0);
/* Ignore things that are broken */
crp = crref();
rc = VNOP_GETATTR(vp, &va, crp);
crfree(crp);
if (rc)
return(0);
/* Is it the same device number ? */
if ((inval_check->rva->va_rdev == va.va_rdev) &&
/* and if it is a multiplexed device, the same channel? */
/* if chan == -1 then disregard the new channel */
((inval_check->rva->va_chan == -1) ||
(inval_check->rva->va_chan == va.va_chan)))
/* then do the revocation */
{
inval_check->st ++;
fp->f_flag |= FREVOKED;
}
return(0);
}
/*
* fp_revoke()
*
* this is needed for the console driver redirection
*
* INPUT: fp file pointer
* flag flag argument to VNOP_REVOKE()
*
* RETURNS: return from VNOP_REVOKE()
*/
fp_revoke(struct file *fp, int flag)
{
struct ucred *crp;
crp = crref();
u.u_error = VNOP_REVOKE(fp->f_vnode, flag,
fp->f_flag, (struct vattr*)&(fp->f_vinfo), crp);
crfree(crp);
return(u.u_error);
}