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"
26 #include "afs/sysincludes.h" /* Standard vendor system headers */
27 #include "afsincludes.h" /* Afs-based standard headers */
28 #include "afs/afs_stats.h" /* statistics */
29 #include "afs/afs_cbqueue.h"
30 #include "afs/nfsclient.h"
31 #include "afs/afs_osidnlc.h"
34 #define ANONYMOUSID 32766 /* make sure this is same as in ptserver.h */
40 /* access bits to turn off for various owner Unix mode values */
41 static char fileModeMap[8] = {
42 PRSFS_READ | PRSFS_WRITE,
43 PRSFS_READ | PRSFS_WRITE,
52 /* avc must be held. Returns bit map of mode bits. Ignores file mode bits */
54 afs_GetAccessBits(register struct vcache *avc, register afs_int32 arights,
55 register struct vrequest *areq)
57 AFS_STATCNT(afs_GetAccessBits);
58 /* see if anyuser has the required access bits */
59 if ((arights & avc->f.anyAccess) == arights) {
63 /* look in per-pag cache */
64 if (avc->Access) { /* not beautiful, but Sun's cc will tolerate it */
67 ac = afs_FindAxs(avc->Access, areq->uid);
69 return (arights & ac->axess);
73 if (!(avc->f.states & CForeign)) {
74 /* If there aren't any bits cached for this user (but the vnode
75 * _is_ cached, obviously), make sure this user has valid tokens
76 * before bothering with the RPC. */
78 tu = afs_FindUser(areq->uid, avc->f.fid.Cell, READ_LOCK);
80 return (arights & avc->f.anyAccess);
82 if ((tu->vid == UNDEFVID) || !(tu->states & UHasTokens)
83 || (tu->states & UTokensBad)) {
84 afs_PutUser(tu, READ_LOCK);
85 return (arights & avc->f.anyAccess);
87 afs_PutUser(tu, READ_LOCK);
91 if (AFS_IS_DISCONNECTED && !AFS_IN_SYNC) {
92 /* If we get this far, we have to ask the network. But we can't, so
93 * they're out of luck... */
96 { /* Ok, user has valid tokens, go ask the server. */
97 struct AFSFetchStatus OutStatus;
100 code = afs_FetchStatus(avc, &avc->f.fid, areq, &OutStatus);
101 return (code ? 0 : OutStatus.CallerAccess & arights);
106 /* the new access ok function. AVC must be held but not locked. if avc is a
107 * file, its parent need not be held, and should not be locked. */
110 afs_AccessOK(struct vcache *avc, afs_int32 arights, struct vrequest *areq,
111 afs_int32 check_mode_bits)
113 register struct vcache *tvc;
114 struct VenusFid dirFid;
115 register afs_int32 mask;
117 register afs_int32 fileBits;
119 AFS_STATCNT(afs_AccessOK);
121 if ((vType(avc) == VDIR) || (avc->f.states & CForeign)) {
122 /* rights are just those from acl */
123 if (afs_InReadDir(avc)) {
124 /* if we are already in readdir, then they may have read and
125 * lookup, and nothing else, and nevermind the real ACL.
126 * Otherwise we might end up with problems trying to call
127 * FetchStatus on the vnode readdir is working on, and that
128 * would be a real mess.
130 dirBits = PRSFS_LOOKUP | PRSFS_READ;
131 return (arights == (dirBits & arights));
133 return (arights == afs_GetAccessBits(avc, arights, areq));
135 /* some rights come from dir and some from file. Specifically, you
136 * have "a" rights to a file if you are its owner, which comes
137 * back as "a" rights to the file. You have other rights just
138 * from dir, but all are restricted by the file mode bit. Now,
139 * if you have I and A rights to a file, we throw in R and W
140 * rights for free. These rights will then be restricted by
141 * the access mask. */
143 if (avc->f.parent.vnode) {
144 dirFid.Cell = avc->f.fid.Cell;
145 dirFid.Fid.Volume = avc->f.fid.Fid.Volume;
146 dirFid.Fid.Vnode = avc->f.parent.vnode;
147 dirFid.Fid.Unique = avc->f.parent.unique;
148 /* Avoid this GetVCache call */
149 tvc = afs_GetVCache(&dirFid, areq, NULL, NULL);
151 if ((arights & (PRSFS_READ | PRSFS_WRITE))) {
152 /* we may need to grant implicit 'rw' rights if we have
153 * 'i' on the parent dir and we are the owner, so check
154 * for 'i' rights in addition, here */
155 dirBits = afs_GetAccessBits(tvc, arights | PRSFS_INSERT, areq);
157 dirBits = afs_GetAccessBits(tvc, arights, areq);
162 dirBits = 0xffffffff; /* assume OK; this is a race condition */
163 if (arights & PRSFS_ADMINISTER) {
164 fileBits = afs_GetAccessBits(avc, arights, areq);
166 } else if ((dirBits & PRSFS_INSERT) &&
167 ((arights & (PRSFS_READ | PRSFS_WRITE)) & dirBits) !=
168 (arights & (PRSFS_READ | PRSFS_WRITE))) {
170 /* if we have 'i' rights in the directory, and we are requesting
171 * read or write access, AND the directory ACL (dirBits) does not
172 * already give us the requested read or write access, we need to
173 * find out if we are the owner for the file ('A' bit), for the
174 * "throw in R and W if we have I and A" check below */
176 fileBits = afs_GetAccessBits(avc, arights | PRSFS_ADMINISTER, areq);
179 fileBits = 0; /* don't make call if results don't matter */
182 /* compute basic rights in fileBits, taking A from file bits */
184 (fileBits & PRSFS_ADMINISTER) | (dirBits & ~PRSFS_ADMINISTER);
186 /* for files, throw in R and W if have I and A (owner). This makes
187 * insert-only dirs work properly */
188 /* note that we know vType(avc) != VDIR from the top-level 'else' */
189 if ((fileBits & (PRSFS_ADMINISTER | PRSFS_INSERT)) ==
190 (PRSFS_ADMINISTER | PRSFS_INSERT))
191 fileBits |= (PRSFS_READ | PRSFS_WRITE);
193 if (check_mode_bits & CHECK_MODE_BITS) {
194 /* owner mode bits are further restrictions on the access mode
195 * The mode bits are mapped to protection bits through the
196 * fileModeMap. If CMB_ALLOW_EXEC_AS_READ is set, it's from the
197 * NFS translator and we don't know if it's a read or execute
198 * on the NFS client, but both need to read the data.
200 mask = (avc->f.m.Mode & 0700) >> 6; /* file restrictions to use */
201 fileBits &= ~fileModeMap[mask];
202 if (check_mode_bits & CMB_ALLOW_EXEC_AS_READ) {
203 if (avc->f.m.Mode & 0100)
204 fileBits |= PRSFS_READ;
207 return ((fileBits & arights) == arights); /* true if all rights bits are on */
212 #if defined(AFS_SUN5_ENV) || (defined(AFS_SGI_ENV) && !defined(AFS_SGI65_ENV))
214 afs_access(OSI_VC_DECL(avc), register afs_int32 amode, int flags,
218 afs_access(OSI_VC_DECL(avc), register afs_int32 amode,
222 register afs_int32 code;
223 struct vrequest treq;
224 struct afs_fakestat_state fakestate;
227 AFS_STATCNT(afs_access);
228 afs_Trace3(afs_iclSetp, CM_TRACE_ACCESS, ICL_TYPE_POINTER, avc,
229 ICL_TYPE_INT32, amode, ICL_TYPE_OFFSET,
230 ICL_HANDLE_OFFSET(avc->f.m.Length));
231 afs_InitFakeStat(&fakestate);
232 if ((code = afs_InitReq(&treq, acred)))
237 if (afs_fakestat_enable && avc->mvstat == 1) {
238 code = afs_TryEvalFakeStat(&avc, &fakestate, &treq);
239 if (code == 0 && avc->mvstat == 1) {
240 afs_PutFakeStat(&fakestate);
245 code = afs_EvalFakeStat(&avc, &fakestate, &treq);
249 afs_PutFakeStat(&fakestate);
254 if (vType(avc) != VDIR || !afs_InReadDir(avc)) {
255 code = afs_VerifyVCache(avc, &treq);
257 afs_PutFakeStat(&fakestate);
259 code = afs_CheckCode(code, &treq, 16);
264 /* if we're looking for write access and we have a read-only file system, report it */
265 if ((amode & VWRITE) && (avc->f.states & CRO)) {
266 afs_PutFakeStat(&fakestate);
271 /* If we're looking for write access, and we're disconnected without logging, forget it */
272 if ((amode & VWRITE) && (AFS_IS_DISCONNECTED && !AFS_IS_DISCON_RW)) {
273 afs_PutFakeStat(&fakestate);
275 printf("Network is down in afs_vnop_access\n");
279 code = 1; /* Default from here on in is access ok. */
280 if (avc->f.states & CForeign) {
281 /* In the dfs xlator the EXEC bit is mapped to LOOKUP */
283 code = afs_AccessOK(avc, PRSFS_LOOKUP, &treq, CHECK_MODE_BITS);
284 if (code && (amode & VWRITE)) {
285 code = afs_AccessOK(avc, PRSFS_WRITE, &treq, CHECK_MODE_BITS);
286 if (code && (vType(avc) == VDIR)) {
289 afs_AccessOK(avc, PRSFS_INSERT, &treq,
293 afs_AccessOK(avc, PRSFS_DELETE, &treq,
297 if (code && (amode & VREAD))
298 code = afs_AccessOK(avc, PRSFS_READ, &treq, CHECK_MODE_BITS);
300 if (vType(avc) == VDIR) {
303 afs_AccessOK(avc, PRSFS_LOOKUP, &treq, CHECK_MODE_BITS);
304 if (code && (amode & VWRITE)) {
306 afs_AccessOK(avc, PRSFS_INSERT, &treq, CHECK_MODE_BITS);
309 afs_AccessOK(avc, PRSFS_DELETE, &treq,
312 if (code && (amode & VREAD))
314 afs_AccessOK(avc, PRSFS_LOOKUP, &treq, CHECK_MODE_BITS);
317 code = afs_AccessOK(avc, PRSFS_READ, &treq, CHECK_MODE_BITS);
319 if ((avc->f.m.Mode & 0100) == 0)
321 } else if (avc->f.m.Mode & 0100)
324 if (code && (amode & VWRITE)) {
325 code = afs_AccessOK(avc, PRSFS_WRITE, &treq, CHECK_MODE_BITS);
327 /* The above call fails when the NFS translator tries to copy
328 ** a file with r--r--r-- permissions into a directory which
329 ** has system:anyuser acl. This is because the destination file
330 ** file is first created with r--r--r-- permissions through an
331 ** unauthenticated connectin. hence, the above afs_AccessOK
332 ** call returns failure. hence, we retry without any file
333 ** mode bit checking */
334 if (!code && AFS_NFSXLATORREQ(acred)
335 && avc->f.m.Owner == ANONYMOUSID)
337 afs_AccessOK(avc, PRSFS_WRITE, &treq,
338 DONT_CHECK_MODE_BITS);
340 if (code && (amode & VREAD))
341 code = afs_AccessOK(avc, PRSFS_READ, &treq, CHECK_MODE_BITS);
344 afs_PutFakeStat(&fakestate);
349 return 0; /* if access is ok */
351 code = afs_CheckCode(EACCES, &treq, 17); /* failure code */
356 #if defined(UKERNEL) && defined(AFS_WEB_ENHANCEMENTS)
359 * This function is just an interface to afs_GetAccessBits
362 afs_getRights(OSI_VC_DECL(avc), register afs_int32 arights,
365 register afs_int32 code;
366 struct vrequest treq;
369 if ((code = afs_InitReq(&treq, acred)))
372 code = afs_VerifyVCache(avc, &treq);
374 code = afs_CheckCode(code, &treq, 16);
378 return afs_GetAccessBits(avc, arights, &treq);
380 #endif /* defined(UKERNEL) && defined(AFS_WEB_ENHANCEMENTS) */