discon-allow-saving-vcaches-on-shutdown-20090126
[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 RCSID
26     ("$Header$");
27
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"
34
35 #ifndef ANONYMOUSID
36 #define ANONYMOUSID     32766   /* make sure this is same as in ptserver.h */
37 #endif
38
39
40
41
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,
46     PRSFS_READ,
47     PRSFS_READ,
48     PRSFS_WRITE,
49     PRSFS_WRITE,
50     0,
51     0
52 };
53
54 /* avc must be held.  Returns bit map of mode bits.  Ignores file mode bits */
55 afs_int32
56 afs_GetAccessBits(register struct vcache *avc, register afs_int32 arights,
57                   register struct vrequest *areq)
58 {
59     AFS_STATCNT(afs_GetAccessBits);
60     /* see if anyuser has the required access bits */
61     if ((arights & avc->f.anyAccess) == arights) {
62         return arights;
63     }
64
65     /* look in per-pag cache */
66     if (avc->Access) {          /* not beautiful, but Sun's cc will tolerate it */
67         struct axscache *ac;
68
69         ac = afs_FindAxs(avc->Access, areq->uid);
70         if (ac) {
71             return (arights & ac->axess);
72         }
73     }
74
75     if (!(avc->f.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.  */
79         struct unixuser *tu;
80         tu = afs_FindUser(areq->uid, avc->f.fid.Cell, READ_LOCK);
81         if (!tu) {
82             return (arights & avc->f.anyAccess);
83         }
84         if ((tu->vid == UNDEFVID) || !(tu->states & UHasTokens)
85             || (tu->states & UTokensBad)) {
86             afs_PutUser(tu, READ_LOCK);
87             return (arights & avc->f.anyAccess);
88         } else {
89             afs_PutUser(tu, READ_LOCK);
90         }
91     }
92
93     if (AFS_IS_DISCONNECTED && !AFS_IN_SYNC) {
94         /* If we get this far, we have to ask the network. But we can't, so
95          * they're out of luck... */
96         return 0;
97     } else
98     {                           /* Ok, user has valid tokens, go ask the server. */
99         struct AFSFetchStatus OutStatus;
100         afs_int32 code;
101
102         code = afs_FetchStatus(avc, &avc->f.fid, areq, &OutStatus);
103         return (code ? 0 : OutStatus.CallerAccess & arights);
104     }
105 }
106
107
108 /* the new access ok function.  AVC must be held but not locked. if avc is a
109  * file, its parent need not be held, and should not be locked. */
110
111 int
112 afs_AccessOK(struct vcache *avc, afs_int32 arights, struct vrequest *areq,
113              afs_int32 check_mode_bits)
114 {
115     register struct vcache *tvc;
116     struct VenusFid dirFid;
117     register afs_int32 mask;
118     afs_int32 dirBits;
119     register afs_int32 fileBits;
120
121     AFS_STATCNT(afs_AccessOK);
122
123     if ((vType(avc) == VDIR) || (avc->f.states & CForeign)) {
124         /* rights are just those from acl */
125         if (afs_InReadDir(avc)) {
126             /* if we are already in readdir, then they may have read and
127              * lookup, and nothing else, and nevermind the real ACL.
128              * Otherwise we might end up with problems trying to call
129              * FetchStatus on the vnode readdir is working on, and that
130              * would be a real mess.
131              */
132             dirBits = PRSFS_LOOKUP | PRSFS_READ;
133             return (arights == (dirBits & arights));
134         }
135         return (arights == afs_GetAccessBits(avc, arights, areq));
136     } else {
137         /* some rights come from dir and some from file.  Specifically, you 
138          * have "a" rights to a file if you are its owner, which comes
139          * back as "a" rights to the file. You have other rights just
140          * from dir, but all are restricted by the file mode bit. Now,
141          * if you have I and A rights to a file, we throw in R and W
142          * rights for free. These rights will then be restricted by
143          * the access mask. */
144         dirBits = 0;
145         if (avc->f.parent.vnode) {
146             dirFid.Cell = avc->f.fid.Cell;
147             dirFid.Fid.Volume = avc->f.fid.Fid.Volume;
148             dirFid.Fid.Vnode = avc->f.parent.vnode;
149             dirFid.Fid.Unique = avc->f.parent.unique;
150             /* Avoid this GetVCache call */
151             tvc = afs_GetVCache(&dirFid, areq, NULL, NULL);
152             if (tvc) {
153                 dirBits = afs_GetAccessBits(tvc, arights, areq);
154                 afs_PutVCache(tvc);
155             }
156         } else
157             dirBits = 0xffffffff;       /* assume OK; this is a race condition */
158         if (arights & PRSFS_ADMINISTER)
159             fileBits = afs_GetAccessBits(avc, arights, areq);
160         else
161             fileBits = 0;       /* don't make call if results don't matter */
162
163         /* compute basic rights in fileBits, taking A from file bits */
164         fileBits =
165             (fileBits & PRSFS_ADMINISTER) | (dirBits & ~PRSFS_ADMINISTER);
166
167         /* for files, throw in R and W if have I and A (owner).  This makes
168          * insert-only dirs work properly */
169         if (vType(avc) != VDIR
170             && (fileBits & (PRSFS_ADMINISTER | PRSFS_INSERT)) ==
171             (PRSFS_ADMINISTER | PRSFS_INSERT))
172             fileBits |= (PRSFS_READ | PRSFS_WRITE);
173
174         if (check_mode_bits & CHECK_MODE_BITS) {
175             /* owner mode bits are further restrictions on the access mode
176              * The mode bits are mapped to protection bits through the
177              * fileModeMap. If CMB_ALLOW_EXEC_AS_READ is set, it's from the
178              * NFS translator and we don't know if it's a read or execute
179              * on the NFS client, but both need to read the data.
180              */
181             mask = (avc->f.m.Mode & 0700) >> 6; /* file restrictions to use */
182             fileBits &= ~fileModeMap[mask];
183             if (check_mode_bits & CMB_ALLOW_EXEC_AS_READ) {
184                 if (avc->f.m.Mode & 0100)
185                     fileBits |= PRSFS_READ;
186             }
187         }
188         return ((fileBits & arights) == arights);       /* true if all rights bits are on */
189     }
190 }
191
192
193 #if defined(AFS_SUN5_ENV) || (defined(AFS_SGI_ENV) && !defined(AFS_SGI65_ENV))
194 int
195 afs_access(OSI_VC_DECL(avc), register afs_int32 amode, int flags,
196            struct AFS_UCRED *acred)
197 #else
198 int
199 afs_access(OSI_VC_DECL(avc), register afs_int32 amode,
200            struct AFS_UCRED *acred)
201 #endif
202 {
203     register afs_int32 code;
204     struct vrequest treq;
205     struct afs_fakestat_state fakestate;
206     OSI_VC_CONVERT(avc);
207
208     AFS_STATCNT(afs_access);
209     afs_Trace3(afs_iclSetp, CM_TRACE_ACCESS, ICL_TYPE_POINTER, avc,
210                ICL_TYPE_INT32, amode, ICL_TYPE_OFFSET,
211                ICL_HANDLE_OFFSET(avc->f.m.Length));
212     afs_InitFakeStat(&fakestate);
213     if ((code = afs_InitReq(&treq, acred)))
214         return code;
215
216     AFS_DISCON_LOCK();
217
218     if (afs_fakestat_enable && avc->mvstat == 1) {
219         code = afs_TryEvalFakeStat(&avc, &fakestate, &treq);
220         if (code == 0 && avc->mvstat == 1) {
221             afs_PutFakeStat(&fakestate);
222             AFS_DISCON_UNLOCK();
223             return 0;
224         }
225     } else {
226         code = afs_EvalFakeStat(&avc, &fakestate, &treq);
227     }
228
229     if (code) {
230         afs_PutFakeStat(&fakestate);
231         AFS_DISCON_UNLOCK();
232         return code;
233     }
234
235     if (vType(avc) != VDIR || !afs_InReadDir(avc)) {
236         code = afs_VerifyVCache(avc, &treq);
237         if (code) {
238             afs_PutFakeStat(&fakestate);
239             AFS_DISCON_UNLOCK();
240             code = afs_CheckCode(code, &treq, 16);
241             return code;
242         }
243     }
244
245     /* if we're looking for write access and we have a read-only file system, report it */
246     if ((amode & VWRITE) && (avc->f.states & CRO)) {
247         afs_PutFakeStat(&fakestate);
248         AFS_DISCON_UNLOCK();
249         return EROFS;
250     }
251     
252     /* If we're looking for write access, and we're disconnected without logging, forget it */
253     if ((amode & VWRITE) && (AFS_IS_DISCONNECTED && !AFS_IS_DISCON_RW)) {
254         afs_PutFakeStat(&fakestate);
255         AFS_DISCON_UNLOCK();
256         printf("Network is down in afs_vnop_access\n");
257         return ENETDOWN;
258     }
259     
260     code = 1;                   /* Default from here on in is access ok. */
261     if (avc->f.states & CForeign) {
262         /* In the dfs xlator the EXEC bit is mapped to LOOKUP */
263         if (amode & VEXEC)
264             code = afs_AccessOK(avc, PRSFS_LOOKUP, &treq, CHECK_MODE_BITS);
265         if (code && (amode & VWRITE)) {
266             code = afs_AccessOK(avc, PRSFS_WRITE, &treq, CHECK_MODE_BITS);
267             if (code && (vType(avc) == VDIR)) {
268                 if (code)
269                     code =
270                         afs_AccessOK(avc, PRSFS_INSERT, &treq,
271                                      CHECK_MODE_BITS);
272                 if (!code)
273                     code =
274                         afs_AccessOK(avc, PRSFS_DELETE, &treq,
275                                      CHECK_MODE_BITS);
276             }
277         }
278         if (code && (amode & VREAD))
279             code = afs_AccessOK(avc, PRSFS_READ, &treq, CHECK_MODE_BITS);
280     } else {
281         if (vType(avc) == VDIR) {
282             if (amode & VEXEC)
283                 code =
284                     afs_AccessOK(avc, PRSFS_LOOKUP, &treq, CHECK_MODE_BITS);
285             if (code && (amode & VWRITE)) {
286                 code =
287                     afs_AccessOK(avc, PRSFS_INSERT, &treq, CHECK_MODE_BITS);
288                 if (!code)
289                     code =
290                         afs_AccessOK(avc, PRSFS_DELETE, &treq,
291                                      CHECK_MODE_BITS);
292             }
293             if (code && (amode & VREAD))
294                 code =
295                     afs_AccessOK(avc, PRSFS_LOOKUP, &treq, CHECK_MODE_BITS);
296         } else {
297             if (amode & VEXEC) {
298                 code = afs_AccessOK(avc, PRSFS_READ, &treq, CHECK_MODE_BITS);
299                 if (code) {
300 #ifdef  AFS_OSF_ENV
301                     /*
302                      * The nfs server in read operations for non-owner of a file
303                      * will also check the access with the VEXEC (along with VREAD)
304                      * because for them exec is the same as read over the net because of
305                      * demand loading. But this means if the mode bit is '-rw' the call
306                      * will fail below; so for this particular case where both modes are
307                      * specified (only in rfs_read so far) and from the xlator requests
308                      * we return succes.
309                      */
310                     if (!((amode & VREAD) && AFS_NFSXLATORREQ(acred)))
311 #endif
312                         if ((avc->f.m.Mode & 0100) == 0)
313                             code = 0;
314                 } else if (avc->f.m.Mode & 0100)
315                     code = 1;
316             }
317             if (code && (amode & VWRITE)) {
318                 code = afs_AccessOK(avc, PRSFS_WRITE, &treq, CHECK_MODE_BITS);
319
320                 /* The above call fails when the NFS translator tries to copy
321                  ** a file with r--r--r-- permissions into a directory which
322                  ** has system:anyuser acl. This is because the destination file
323                  ** file is first created with r--r--r-- permissions through an
324                  ** unauthenticated connectin.  hence, the above afs_AccessOK
325                  ** call returns failure. hence, we retry without any file 
326                  ** mode bit checking */
327                 if (!code && AFS_NFSXLATORREQ(acred)
328                     && avc->f.m.Owner == ANONYMOUSID)
329                     code =
330                         afs_AccessOK(avc, PRSFS_WRITE, &treq,
331                                      DONT_CHECK_MODE_BITS);
332             }
333             if (code && (amode & VREAD))
334                 code = afs_AccessOK(avc, PRSFS_READ, &treq, CHECK_MODE_BITS);
335         }
336     }
337     afs_PutFakeStat(&fakestate);
338
339     AFS_DISCON_UNLOCK();
340     
341     if (code) {
342         return 0;               /* if access is ok */
343     } else {
344         code = afs_CheckCode(EACCES, &treq, 17);        /* failure code */
345         return code;
346     }
347 }
348
349 #if defined(UKERNEL) && defined(AFS_WEB_ENHANCEMENTS)
350 /*
351  * afs_getRights
352  * This function is just an interface to afs_GetAccessBits
353  */
354 int
355 afs_getRights(OSI_VC_DECL(avc), register afs_int32 arights,
356               struct AFS_UCRED *acred)
357 {
358     register afs_int32 code;
359     struct vrequest treq;
360     OSI_VC_CONVERT(avc);
361
362     if (code = afs_InitReq(&treq, acred))
363         return code;
364
365     code = afs_VerifyVCache(avc, &treq);
366     if (code) {
367         code = afs_CheckCode(code, &treq, 16);
368         return code;
369     }
370
371     return afs_GetAccessBits(avc, arights, &treq);
372 }
373 #endif /* defined(UKERNEL) && defined(AFS_WEB_ENHANCEMENTS) */