2 * Copyright 2000, International Business Machines Corporation and others.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
11 * afs_vnop_access.c - access vop ccess mode bit support for vnode operations.
22 #include <afsconfig.h>
23 #include "afs/param.h"
28 #include "afs/sysincludes.h" /* Standard vendor system headers */
29 #include "afsincludes.h" /* Afs-based standard headers */
30 #include "afs/afs_stats.h" /* statistics */
31 #include "afs/afs_cbqueue.h"
32 #include "afs/nfsclient.h"
33 #include "afs/afs_osidnlc.h"
36 #define ANONYMOUSID 32766 /* make sure this is same as in ptserver.h */
42 /* access bits to turn off for various owner Unix mode values */
43 static char fileModeMap[8] = {
44 PRSFS_READ | PRSFS_WRITE,
45 PRSFS_READ | PRSFS_WRITE,
54 /* avc must be held. Returns bit map of mode bits. Ignores file mode bits */
56 afs_GetAccessBits(register struct vcache *avc, register afs_int32 arights,
57 register struct vrequest *areq)
59 AFS_STATCNT(afs_GetAccessBits);
60 /* see if anyuser has the required access bits */
61 if ((arights & avc->anyAccess) == arights) {
65 /* look in per-pag cache */
66 if (avc->Access) { /* not beautiful, but Sun's cc will tolerate it */
69 ac = afs_FindAxs(avc->Access, areq->uid);
71 return (arights & ac->axess);
75 if (!(avc->states & CForeign)) {
76 /* If there aren't any bits cached for this user (but the vnode
77 * _is_ cached, obviously), make sure this user has valid tokens
78 * before bothering with the RPC. */
80 extern struct unixuser *afs_FindUser();
81 tu = afs_FindUser(areq->uid, avc->fid.Cell, READ_LOCK);
83 return (arights & avc->anyAccess);
85 if ((tu->vid == UNDEFVID) || !(tu->states & UHasTokens)
86 || (tu->states & UTokensBad)) {
87 afs_PutUser(tu, READ_LOCK);
88 return (arights & avc->anyAccess);
90 afs_PutUser(tu, READ_LOCK);
94 { /* Ok, user has valid tokens, go ask the server. */
95 struct AFSFetchStatus OutStatus;
98 code = afs_FetchStatus(avc, &avc->fid, areq, &OutStatus);
99 return (code ? 0 : OutStatus.CallerAccess & arights);
104 /* the new access ok function. AVC must be held but not locked. if avc is a
105 * file, its parent need not be held, and should not be locked. */
108 afs_AccessOK(struct vcache *avc, afs_int32 arights, struct vrequest *areq,
109 afs_int32 check_mode_bits)
111 register struct vcache *tvc;
112 struct VenusFid dirFid;
113 register afs_int32 mask;
115 register afs_int32 fileBits;
117 AFS_STATCNT(afs_AccessOK);
119 if ((vType(avc) == VDIR) || (avc->states & CForeign)) {
120 /* rights are just those from acl */
121 if (afs_InReadDir(avc)) {
122 /* if we are already in readdir, then they may have read and
123 * lookup, and nothing else, and nevermind the real ACL.
124 * Otherwise we might end up with problems trying to call
125 * FetchStatus on the vnode readdir is working on, and that
126 * would be a real mess.
128 dirBits = PRSFS_LOOKUP | PRSFS_READ;
129 return (arights == (dirBits & arights));
131 return (arights == afs_GetAccessBits(avc, arights, areq));
133 /* some rights come from dir and some from file. Specifically, you
134 * have "a" rights to a file if you are its owner, which comes
135 * back as "a" rights to the file. You have other rights just
136 * from dir, but all are restricted by the file mode bit. Now,
137 * if you have I and A rights to a file, we throw in R and W
138 * rights for free. These rights will then be restricted by
139 * the access mask. */
141 if (avc->parentVnode) {
142 dirFid.Cell = avc->fid.Cell;
143 dirFid.Fid.Volume = avc->fid.Fid.Volume;
144 dirFid.Fid.Vnode = avc->parentVnode;
145 dirFid.Fid.Unique = avc->parentUnique;
146 /* Avoid this GetVCache call */
147 tvc = afs_GetVCache(&dirFid, areq, NULL, NULL);
149 dirBits = afs_GetAccessBits(tvc, arights, areq);
153 dirBits = 0xffffffff; /* assume OK; this is a race condition */
154 if (arights & PRSFS_ADMINISTER)
155 fileBits = afs_GetAccessBits(avc, arights, areq);
157 fileBits = 0; /* don't make call if results don't matter */
159 /* compute basic rights in fileBits, taking A from file bits */
161 (fileBits & PRSFS_ADMINISTER) | (dirBits & ~PRSFS_ADMINISTER);
163 /* for files, throw in R and W if have I and A (owner). This makes
164 * insert-only dirs work properly */
165 if (vType(avc) != VDIR
166 && (fileBits & (PRSFS_ADMINISTER | PRSFS_INSERT)) ==
167 (PRSFS_ADMINISTER | PRSFS_INSERT))
168 fileBits |= (PRSFS_READ | PRSFS_WRITE);
170 if (check_mode_bits & CHECK_MODE_BITS) {
171 /* owner mode bits are further restrictions on the access mode
172 * The mode bits are mapped to protection bits through the
173 * fileModeMap. If CMB_ALLOW_EXEC_AS_READ is set, it's from the
174 * NFS translator and we don't know if it's a read or execute
175 * on the NFS client, but both need to read the data.
177 mask = (avc->m.Mode & 0700) >> 6; /* file restrictions to use */
178 fileBits &= ~fileModeMap[mask];
179 if (check_mode_bits & CMB_ALLOW_EXEC_AS_READ) {
180 if (avc->m.Mode & 0100)
181 fileBits |= PRSFS_READ;
184 return ((fileBits & arights) == arights); /* true if all rights bits are on */
189 #if defined(AFS_SUN5_ENV) || (defined(AFS_SGI_ENV) && !defined(AFS_SGI65_ENV))
191 afs_access(OSI_VC_DECL(avc), register afs_int32 amode, int flags,
192 struct AFS_UCRED *acred)
195 afs_access(OSI_VC_DECL(avc), register afs_int32 amode,
196 struct AFS_UCRED *acred)
199 register afs_int32 code;
200 struct vrequest treq;
201 struct afs_fakestat_state fakestate;
204 AFS_STATCNT(afs_access);
205 afs_Trace3(afs_iclSetp, CM_TRACE_ACCESS, ICL_TYPE_POINTER, avc,
206 ICL_TYPE_INT32, amode, ICL_TYPE_OFFSET,
207 ICL_HANDLE_OFFSET(avc->m.Length));
208 afs_InitFakeStat(&fakestate);
209 if ((code = afs_InitReq(&treq, acred)))
212 if (afs_fakestat_enable && avc->mvstat == 1) {
213 code = afs_TryEvalFakeStat(&avc, &fakestate, &treq);
214 if (code == 0 && avc->mvstat == 1) {
215 afs_PutFakeStat(&fakestate);
219 code = afs_EvalFakeStat(&avc, &fakestate, &treq);
223 afs_PutFakeStat(&fakestate);
227 if (vType(avc) != VDIR || !afs_InReadDir(avc)) {
228 code = afs_VerifyVCache(avc, &treq);
230 afs_PutFakeStat(&fakestate);
231 code = afs_CheckCode(code, &treq, 16);
236 /* if we're looking for write access and we have a read-only file system, report it */
237 if ((amode & VWRITE) && (avc->states & CRO)) {
238 afs_PutFakeStat(&fakestate);
241 code = 1; /* Default from here on in is access ok. */
242 if (avc->states & CForeign) {
243 /* In the dfs xlator the EXEC bit is mapped to LOOKUP */
245 code = afs_AccessOK(avc, PRSFS_LOOKUP, &treq, CHECK_MODE_BITS);
246 if (code && (amode & VWRITE)) {
247 code = afs_AccessOK(avc, PRSFS_WRITE, &treq, CHECK_MODE_BITS);
248 if (code && (vType(avc) == VDIR)) {
251 afs_AccessOK(avc, PRSFS_INSERT, &treq,
255 afs_AccessOK(avc, PRSFS_DELETE, &treq,
259 if (code && (amode & VREAD))
260 code = afs_AccessOK(avc, PRSFS_READ, &treq, CHECK_MODE_BITS);
262 if (vType(avc) == VDIR) {
265 afs_AccessOK(avc, PRSFS_LOOKUP, &treq, CHECK_MODE_BITS);
266 if (code && (amode & VWRITE)) {
268 afs_AccessOK(avc, PRSFS_INSERT, &treq, CHECK_MODE_BITS);
271 afs_AccessOK(avc, PRSFS_DELETE, &treq,
274 if (code && (amode & VREAD))
276 afs_AccessOK(avc, PRSFS_LOOKUP, &treq, CHECK_MODE_BITS);
279 code = afs_AccessOK(avc, PRSFS_READ, &treq, CHECK_MODE_BITS);
283 * The nfs server in read operations for non-owner of a file
284 * will also check the access with the VEXEC (along with VREAD)
285 * because for them exec is the same as read over the net because of
286 * demand loading. But this means if the mode bit is '-rw' the call
287 * will fail below; so for this particular case where both modes are
288 * specified (only in rfs_read so far) and from the xlator requests
291 if (!((amode & VREAD) && AFS_NFSXLATORREQ(acred)))
293 if ((avc->m.Mode & 0100) == 0)
295 } else if (avc->m.Mode & 0100)
298 if (code && (amode & VWRITE)) {
299 code = afs_AccessOK(avc, PRSFS_WRITE, &treq, CHECK_MODE_BITS);
301 /* The above call fails when the NFS translator tries to copy
302 ** a file with r--r--r-- permissions into a directory which
303 ** has system:anyuser acl. This is because the destination file
304 ** file is first created with r--r--r-- permissions through an
305 ** unauthenticated connectin. hence, the above afs_AccessOK
306 ** call returns failure. hence, we retry without any file
307 ** mode bit checking */
308 if (!code && AFS_NFSXLATORREQ(acred)
309 && avc->m.Owner == ANONYMOUSID)
311 afs_AccessOK(avc, PRSFS_WRITE, &treq,
312 DONT_CHECK_MODE_BITS);
314 if (code && (amode & VREAD))
315 code = afs_AccessOK(avc, PRSFS_READ, &treq, CHECK_MODE_BITS);
318 afs_PutFakeStat(&fakestate);
320 return 0; /* if access is ok */
322 code = afs_CheckCode(EACCES, &treq, 17); /* failure code */
327 #if defined(UKERNEL) && defined(AFS_WEB_ENHANCEMENTS)
330 * This function is just an interface to afs_GetAccessBits
333 afs_getRights(OSI_VC_DECL(avc), register afs_int32 arights,
334 struct AFS_UCRED *acred)
336 register afs_int32 code;
337 struct vrequest treq;
340 if (code = afs_InitReq(&treq, acred))
343 code = afs_VerifyVCache(avc, &treq);
345 code = afs_CheckCode(code, &treq, 16);
349 return afs_GetAccessBits(avc, arights, &treq);
351 #endif /* defined(UKERNEL) && defined(AFS_WEB_ENHANCEMENTS) */