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