f72b6e634fe5e3e152e8553554c53fdfe401da56
[openafs.git] / src / afs / VNOPS / afs_vnop_access.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
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
8  */
9
10 /*
11  * afs_vnop_access.c - access vop ccess mode bit support for vnode operations.
12  *
13  * Implements:
14  * afs_GetAccessBits
15  * afs_AccessOK
16  * afs_access
17  *
18  * Local:
19  * fileModeMap (table)
20  */
21
22 #include <afsconfig.h>
23 #include "afs/param.h"
24
25
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"
32
33 #ifndef ANONYMOUSID
34 #define ANONYMOUSID     32766   /* make sure this is same as in ptserver.h */
35 #endif
36
37
38
39
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,
44     PRSFS_READ,
45     PRSFS_READ,
46     PRSFS_WRITE,
47     PRSFS_WRITE,
48     0,
49     0
50 };
51
52 /* avc must be held.  Returns bit map of mode bits.  Ignores file mode bits */
53 afs_int32
54 afs_GetAccessBits(register struct vcache *avc, register afs_int32 arights,
55                   register struct vrequest *areq)
56 {
57     AFS_STATCNT(afs_GetAccessBits);
58     /* see if anyuser has the required access bits */
59     if ((arights & avc->f.anyAccess) == arights) {
60         return arights;
61     }
62
63     /* look in per-pag cache */
64     if (avc->Access) {          /* not beautiful, but Sun's cc will tolerate it */
65         struct axscache *ac;
66
67         ac = afs_FindAxs(avc->Access, areq->uid);
68         if (ac) {
69             return (arights & ac->axess);
70         }
71     }
72
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.  */
77         struct unixuser *tu;
78         tu = afs_FindUser(areq->uid, avc->f.fid.Cell, READ_LOCK);
79         if (!tu) {
80             return (arights & avc->f.anyAccess);
81         }
82         if ((tu->vid == UNDEFVID) || !(tu->states & UHasTokens)
83             || (tu->states & UTokensBad)) {
84             afs_PutUser(tu, READ_LOCK);
85             return (arights & avc->f.anyAccess);
86         } else {
87             afs_PutUser(tu, READ_LOCK);
88         }
89     }
90
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... */
94         return 0;
95     } else
96     {                           /* Ok, user has valid tokens, go ask the server. */
97         struct AFSFetchStatus OutStatus;
98         afs_int32 code;
99
100         code = afs_FetchStatus(avc, &avc->f.fid, areq, &OutStatus);
101         return (code ? 0 : OutStatus.CallerAccess & arights);
102     }
103 }
104
105
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. */
108
109 int
110 afs_AccessOK(struct vcache *avc, afs_int32 arights, struct vrequest *areq,
111              afs_int32 check_mode_bits)
112 {
113     register struct vcache *tvc;
114     struct VenusFid dirFid;
115     register afs_int32 mask;
116     afs_int32 dirBits;
117     register afs_int32 fileBits;
118
119     AFS_STATCNT(afs_AccessOK);
120
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.
129              */
130             dirBits = PRSFS_LOOKUP | PRSFS_READ;
131             return (arights == (dirBits & arights));
132         }
133         return (arights == afs_GetAccessBits(avc, arights, areq));
134     } else {
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. */
142         dirBits = 0;
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);
150             if (tvc) {
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);
156                 } else {
157                     dirBits = afs_GetAccessBits(tvc, arights, areq);
158                 }
159                 afs_PutVCache(tvc);
160             }
161         } else
162             dirBits = 0xffffffff;       /* assume OK; this is a race condition */
163         if (arights & PRSFS_ADMINISTER) {
164             fileBits = afs_GetAccessBits(avc, arights, areq);
165
166         } else if ((dirBits & PRSFS_INSERT) &&
167                   ((arights & (PRSFS_READ | PRSFS_WRITE)) & dirBits) !=
168                    (arights & (PRSFS_READ | PRSFS_WRITE))) {
169
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 */
175
176             fileBits = afs_GetAccessBits(avc, arights | PRSFS_ADMINISTER, areq);
177
178         } else {
179             fileBits = 0;       /* don't make call if results don't matter */
180         }
181
182         /* compute basic rights in fileBits, taking A from file bits */
183         fileBits =
184             (fileBits & PRSFS_ADMINISTER) | (dirBits & ~PRSFS_ADMINISTER);
185
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);
192
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.
199              */
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;
205             }
206         }
207         return ((fileBits & arights) == arights);       /* true if all rights bits are on */
208     }
209 }
210
211
212 #if defined(AFS_SUN5_ENV) || (defined(AFS_SGI_ENV) && !defined(AFS_SGI65_ENV))
213 int
214 afs_access(OSI_VC_DECL(avc), register afs_int32 amode, int flags,
215            afs_ucred_t *acred)
216 #else
217 int
218 afs_access(OSI_VC_DECL(avc), register afs_int32 amode,
219            afs_ucred_t *acred)
220 #endif
221 {
222     register afs_int32 code;
223     struct vrequest treq;
224     struct afs_fakestat_state fakestate;
225     OSI_VC_CONVERT(avc);
226
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)))
233         return code;
234
235     AFS_DISCON_LOCK();
236
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);
241             AFS_DISCON_UNLOCK();
242             return 0;
243         }
244     } else {
245         code = afs_EvalFakeStat(&avc, &fakestate, &treq);
246     }
247
248     if (code) {
249         afs_PutFakeStat(&fakestate);
250         AFS_DISCON_UNLOCK();
251         return code;
252     }
253
254     if (vType(avc) != VDIR || !afs_InReadDir(avc)) {
255         code = afs_VerifyVCache(avc, &treq);
256         if (code) {
257             afs_PutFakeStat(&fakestate);
258             AFS_DISCON_UNLOCK();
259             code = afs_CheckCode(code, &treq, 16);
260             return code;
261         }
262     }
263
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);
267         AFS_DISCON_UNLOCK();
268         return EROFS;
269     }
270     
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);
274         AFS_DISCON_UNLOCK();
275         printf("Network is down in afs_vnop_access\n");
276         return ENETDOWN;
277     }
278     
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 */
282         if (amode & VEXEC)
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)) {
287                 if (code)
288                     code =
289                         afs_AccessOK(avc, PRSFS_INSERT, &treq,
290                                      CHECK_MODE_BITS);
291                 if (!code)
292                     code =
293                         afs_AccessOK(avc, PRSFS_DELETE, &treq,
294                                      CHECK_MODE_BITS);
295             }
296         }
297         if (code && (amode & VREAD))
298             code = afs_AccessOK(avc, PRSFS_READ, &treq, CHECK_MODE_BITS);
299     } else {
300         if (vType(avc) == VDIR) {
301             if (amode & VEXEC)
302                 code =
303                     afs_AccessOK(avc, PRSFS_LOOKUP, &treq, CHECK_MODE_BITS);
304             if (code && (amode & VWRITE)) {
305                 code =
306                     afs_AccessOK(avc, PRSFS_INSERT, &treq, CHECK_MODE_BITS);
307                 if (!code)
308                     code =
309                         afs_AccessOK(avc, PRSFS_DELETE, &treq,
310                                      CHECK_MODE_BITS);
311             }
312             if (code && (amode & VREAD))
313                 code =
314                     afs_AccessOK(avc, PRSFS_LOOKUP, &treq, CHECK_MODE_BITS);
315         } else {
316             if (amode & VEXEC) {
317                 code = afs_AccessOK(avc, PRSFS_READ, &treq, CHECK_MODE_BITS);
318                 if (code) {
319                         if ((avc->f.m.Mode & 0100) == 0)
320                             code = 0;
321                 } else if (avc->f.m.Mode & 0100)
322                     code = 1;
323             }
324             if (code && (amode & VWRITE)) {
325                 code = afs_AccessOK(avc, PRSFS_WRITE, &treq, CHECK_MODE_BITS);
326
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)
336                     code =
337                         afs_AccessOK(avc, PRSFS_WRITE, &treq,
338                                      DONT_CHECK_MODE_BITS);
339             }
340             if (code && (amode & VREAD))
341                 code = afs_AccessOK(avc, PRSFS_READ, &treq, CHECK_MODE_BITS);
342         }
343     }
344     afs_PutFakeStat(&fakestate);
345
346     AFS_DISCON_UNLOCK();
347     
348     if (code) {
349         return 0;               /* if access is ok */
350     } else {
351         code = afs_CheckCode(EACCES, &treq, 17);        /* failure code */
352         return code;
353     }
354 }
355
356 #if defined(UKERNEL) && defined(AFS_WEB_ENHANCEMENTS)
357 /*
358  * afs_getRights
359  * This function is just an interface to afs_GetAccessBits
360  */
361 int
362 afs_getRights(OSI_VC_DECL(avc), register afs_int32 arights,
363               afs_ucred_t *acred)
364 {
365     register afs_int32 code;
366     struct vrequest treq;
367     OSI_VC_CONVERT(avc);
368
369     if ((code = afs_InitReq(&treq, acred)))
370         return code;
371
372     code = afs_VerifyVCache(avc, &treq);
373     if (code) {
374         code = afs_CheckCode(code, &treq, 16);
375         return code;
376     }
377
378     return afs_GetAccessBits(avc, arights, &treq);
379 }
380 #endif /* defined(UKERNEL) && defined(AFS_WEB_ENHANCEMENTS) */