1 /* Copyright (C) 1995, 1989, 1998 Transarc Corporation - All rights reserved */
3 * (C) COPYRIGHT IBM CORPORATION 1987, 1988
4 * LICENSED MATERIALS - PROPERTY OF IBM
7 * afs_vnop_access.c - access vop ccess mode bit support for vnode operations.
18 #include "../afs/param.h" /* Should be always first */
19 #include "../afs/sysincludes.h" /* Standard vendor system headers */
20 #include "../afs/afsincludes.h" /* Afs-based standard headers */
21 #include "../afs/afs_stats.h" /* statistics */
22 #include "../afs/afs_cbqueue.h"
23 #include "../afs/nfsclient.h"
24 #include "../afs/afs_osidnlc.h"
27 #define ANONYMOUSID 32766 /* make sure this is same as in ptserver.h */
33 /* access bits to turn off for various owner Unix mode values */
34 static char fileModeMap[8] = {
35 PRSFS_READ | PRSFS_WRITE,
36 PRSFS_READ | PRSFS_WRITE,
45 /* avc must be held. Returns bit map of mode bits. Ignores file mode bits */
46 afs_int32 afs_GetAccessBits (avc, arights, areq)
47 register struct vcache *avc;
48 register afs_int32 arights;
49 register struct vrequest *areq;
51 AFS_STATCNT(afs_GetAccessBits);
52 /* see if anyuser has the required access bits */
53 if ((arights & avc->anyAccess) == arights) {
57 /* look in per-pag cache */
58 if (avc->Access) { /* not beautiful, but Sun's cc will tolerate it */
61 ac = afs_FindAxs(avc->Access, areq->uid);
63 return (arights & ac->axess);
67 if (!(avc->states & CForeign)) {
68 /* If there aren't any bits cached for this user (but the vnode
69 * _is_ cached, obviously), make sure this user has valid tokens
70 * before bothering with the RPC. */
72 extern struct unixuser *afs_FindUser();
73 tu = afs_FindUser( areq->uid, avc->fid.Cell, READ_LOCK );
75 return (arights & avc->anyAccess);
77 if ((tu->vid == UNDEFVID) || !(tu->states & UHasTokens) ||
78 (tu->states & UTokensBad)) {
79 afs_PutUser(tu, READ_LOCK);
80 return (arights & avc->anyAccess);
83 afs_PutUser(tu, READ_LOCK);
87 { /* Ok, user has valid tokens, go ask the server. */
88 struct AFSFetchStatus OutStatus;
91 code = afs_FetchStatus(avc, &avc->fid, areq, &OutStatus);
92 return (code ? 0 : OutStatus.CallerAccess & arights);
97 /* the new access ok function. AVC must be held but not locked. if avc is a
98 * file, its parent need not be held, and should not be locked. */
100 afs_AccessOK(avc, arights, areq, check_mode_bits)
102 afs_int32 arights, check_mode_bits;
103 struct vrequest *areq; {
104 register struct vcache *tvc;
105 struct VenusFid dirFid;
106 register afs_int32 mask;
108 register afs_int32 fileBits;
110 AFS_STATCNT(afs_AccessOK);
112 if ((vType(avc) == VDIR) || (avc->states & CForeign)) {
113 /* rights are just those from acl */
114 return (arights == afs_GetAccessBits(avc, arights, areq));
117 /* some rights come from dir and some from file. Specifically, you
118 * have "a" rights to a file if you are its owner, which comes
119 * back as "a" rights to the file. You have other rights just
120 * from dir, but all are restricted by the file mode bit. Now,
121 * if you have I and A rights to a file, we throw in R and W
122 * rights for free. These rights will then be restricted by
123 * the access mask. */
125 if (avc->parentVnode) {
126 dirFid.Cell = avc->fid.Cell;
127 dirFid.Fid.Volume = avc->fid.Fid.Volume;
128 dirFid.Fid.Vnode = avc->parentVnode;
129 dirFid.Fid.Unique = avc->parentUnique;
130 /* Avoid this GetVCache call */
131 tvc = afs_GetVCache(&dirFid, areq, (afs_int32 *)0,
132 (struct vcache*)0, WRITE_LOCK);
134 dirBits = afs_GetAccessBits(tvc, arights, areq);
135 afs_PutVCache(tvc, WRITE_LOCK);
139 dirBits = 0xffffffff; /* assume OK; this is a race condition */
140 if (arights & PRSFS_ADMINISTER)
141 fileBits = afs_GetAccessBits(avc, arights, areq);
143 fileBits = 0; /* don't make call if results don't matter */
145 /* compute basic rights in fileBits, taking A from file bits */
146 fileBits = (fileBits & PRSFS_ADMINISTER) | (dirBits & ~PRSFS_ADMINISTER);
148 /* for files, throw in R and W if have I and A (owner). This makes
149 insert-only dirs work properly */
150 if (vType(avc) != VDIR && (fileBits & (PRSFS_ADMINISTER | PRSFS_INSERT)) ==
151 (PRSFS_ADMINISTER | PRSFS_INSERT))
152 fileBits |= (PRSFS_READ | PRSFS_WRITE);
154 if (check_mode_bits & CHECK_MODE_BITS) {
155 /* owner mode bits are further restrictions on the access mode
156 * The mode bits are mapped to protection bits through the
157 * fileModeMap. If CMB_ALLOW_EXEC_AS_READ is set, it's from the
158 * NFS translator and we don't know if it's a read or execute
159 * on the NFS client, but both need to read the data.
161 mask = (avc->m.Mode & 0700) >> 6; /* file restrictions to use */
162 fileBits &= ~fileModeMap[mask];
163 if (check_mode_bits & CMB_ALLOW_EXEC_AS_READ) {
164 if (avc->m.Mode & 0100) fileBits |= PRSFS_READ;
167 return ((fileBits & arights) == arights); /* true if all rights bits are on */
172 #if defined(AFS_SUN5_ENV) || (defined(AFS_SGI_ENV) && !defined(AFS_SGI65_ENV))
173 afs_access(OSI_VC_ARG(avc), amode, flags, acred)
176 afs_access(OSI_VC_ARG(avc), amode, acred)
179 register afs_int32 amode;
180 struct AFS_UCRED *acred; {
181 register afs_int32 code;
182 struct vrequest treq;
185 AFS_STATCNT(afs_access);
186 afs_Trace3(afs_iclSetp, CM_TRACE_ACCESS, ICL_TYPE_POINTER, avc,
187 ICL_TYPE_INT32, amode, ICL_TYPE_INT32, avc->m.Length);
188 if (code = afs_InitReq(&treq, acred)) return code;
190 code = afs_VerifyVCache(avc, &treq);
192 code = afs_CheckCode(code, &treq, 16);
196 /* if we're looking for write access and we have a read-only file system, report it */
197 if ((amode & VWRITE) && (avc->states & CRO)) {
200 code = 1; /* Default from here on in is access ok. */
201 if (avc->states & CForeign) {
202 /* In the dfs xlator the EXEC bit is mapped to LOOKUP */
204 code = afs_AccessOK(avc, PRSFS_LOOKUP, &treq, CHECK_MODE_BITS);
205 if (code && (amode & VWRITE)) {
206 code = afs_AccessOK(avc, PRSFS_WRITE, &treq, CHECK_MODE_BITS);
207 if (code && (vType(avc) == VDIR)) {
209 code = afs_AccessOK(avc, PRSFS_INSERT, &treq, CHECK_MODE_BITS);
211 code = afs_AccessOK(avc, PRSFS_DELETE, &treq, CHECK_MODE_BITS);
214 if (code && (amode & VREAD))
215 code = afs_AccessOK(avc, PRSFS_READ, &treq, CHECK_MODE_BITS);
217 if (vType(avc) == VDIR) {
219 code = afs_AccessOK(avc, PRSFS_LOOKUP, &treq, CHECK_MODE_BITS);
220 if (code && (amode & VWRITE)) {
221 code = afs_AccessOK(avc, PRSFS_INSERT, &treq, CHECK_MODE_BITS);
223 code = afs_AccessOK(avc, PRSFS_DELETE, &treq, CHECK_MODE_BITS);
225 if (code && (amode & VREAD))
226 code = afs_AccessOK(avc, PRSFS_LOOKUP, &treq, CHECK_MODE_BITS);
229 code = afs_AccessOK(avc, PRSFS_READ, &treq, CHECK_MODE_BITS);
233 * The nfs server in read operations for non-owner of a file
234 * will also check the access with the VEXEC (along with VREAD)
235 * because for them exec is the same as read over the net because of
236 * demand loading. But this means if the mode bit is '-rw' the call
237 * will fail below; so for this particular case where both modes are
238 * specified (only in rfs_read so far) and from the xlator requests
241 if (!((amode & VREAD) && AFS_NFSXLATORREQ(acred)))
243 if ((avc->m.Mode & 0100) == 0) code = 0;
244 } else if (avc->m.Mode & 0100) code = 1;
246 if (code && (amode & VWRITE))
248 code = afs_AccessOK(avc, PRSFS_WRITE, &treq, CHECK_MODE_BITS);
250 /* The above call fails when the NFS translator tries to copy
251 ** a file with r--r--r-- permissions into a directory which
252 ** has system:anyuser acl. This is because the destination file
253 ** file is first created with r--r--r-- permissions through an
254 ** unauthenticated connectin. hence, the above afs_AccessOK
255 ** call returns failure. hence, we retry without any file
256 ** mode bit checking */
257 if ( !code && AFS_NFSXLATORREQ(acred) && avc->m.Owner == ANONYMOUSID)
258 code=afs_AccessOK(avc,PRSFS_WRITE, &treq, DONT_CHECK_MODE_BITS);
260 if (code && (amode & VREAD))
261 code = afs_AccessOK(avc, PRSFS_READ, &treq, CHECK_MODE_BITS);
265 return 0; /* if access is ok */
267 code = afs_CheckCode(EACCES, &treq, 17); /* failure code */