Initial fakestat support (fake mountpoint directory attributes).
[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("$Header$");
26
27 #include "../afs/sysincludes.h" /* Standard vendor system headers */
28 #include "../afs/afsincludes.h" /* Afs-based standard headers */
29 #include "../afs/afs_stats.h" /* statistics */
30 #include "../afs/afs_cbqueue.h"
31 #include "../afs/nfsclient.h"
32 #include "../afs/afs_osidnlc.h"
33
34 #ifndef ANONYMOUSID
35 #define ANONYMOUSID     32766 /* make sure this is same as in ptserver.h */
36 #endif
37
38
39
40
41 /* access bits to turn off for various owner Unix mode values */
42 static char fileModeMap[8] = {
43     PRSFS_READ | PRSFS_WRITE,
44     PRSFS_READ | PRSFS_WRITE,
45     PRSFS_READ,
46     PRSFS_READ,
47     PRSFS_WRITE,
48     PRSFS_WRITE,
49     0,
50     0
51 };
52
53 /* avc must be held.  Returns bit map of mode bits.  Ignores file mode bits */
54 afs_int32 afs_GetAccessBits (avc, arights, areq)
55     register struct vcache *avc;
56     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->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->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       extern struct unixuser *afs_FindUser();
81       tu = afs_FindUser( areq->uid, avc->fid.Cell, READ_LOCK );
82       if (!tu) {
83         return (arights & avc->anyAccess);
84       }
85       if ((tu->vid == UNDEFVID) || !(tu->states & UHasTokens) ||
86           (tu->states & UTokensBad)) {
87         afs_PutUser(tu, READ_LOCK);
88         return (arights & avc->anyAccess);
89       }
90       else {
91         afs_PutUser(tu, READ_LOCK);
92       }
93     }
94
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->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 afs_AccessOK(avc, arights, areq, check_mode_bits)
109 struct vcache *avc;
110 afs_int32 arights, check_mode_bits;
111 struct vrequest *areq; {
112     register struct vcache *tvc;
113     struct VenusFid dirFid;
114     register afs_int32 mask;
115     afs_int32 dirBits;
116     register afs_int32 fileBits;
117
118     AFS_STATCNT(afs_AccessOK);
119
120     if ((vType(avc) == VDIR) || (avc->states & CForeign)) {
121       /* rights are just those from acl */
122       return (arights == afs_GetAccessBits(avc, arights, areq));
123     }
124     else {
125         /* some rights come from dir and some from file.  Specifically, you 
126          * have "a" rights to a file if you are its owner, which comes
127          * back as "a" rights to the file. You have other rights just
128          * from dir, but all are restricted by the file mode bit. Now,
129          * if you have I and A rights to a file, we throw in R and W
130          * rights for free. These rights will then be restricted by
131          * the access mask. */
132         dirBits = 0;
133         if (avc->parentVnode) {
134             dirFid.Cell = avc->fid.Cell;
135             dirFid.Fid.Volume = avc->fid.Fid.Volume;
136             dirFid.Fid.Vnode = avc->parentVnode;
137             dirFid.Fid.Unique = avc->parentUnique;
138             /* Avoid this GetVCache call */
139             tvc = afs_GetVCache(&dirFid, areq, (afs_int32 *)0,
140                                 (struct vcache*)0, WRITE_LOCK);
141             if (tvc) {
142                 dirBits = afs_GetAccessBits(tvc, arights, areq);
143                 afs_PutVCache(tvc, WRITE_LOCK);
144             }
145         }
146         else
147             dirBits = 0xffffffff;       /* assume OK; this is a race condition */
148         if (arights & PRSFS_ADMINISTER)
149             fileBits = afs_GetAccessBits(avc, arights, areq);
150         else
151             fileBits = 0;       /* don't make call if results don't matter */
152
153         /* compute basic rights in fileBits, taking A from file bits */
154         fileBits = (fileBits & PRSFS_ADMINISTER) | (dirBits & ~PRSFS_ADMINISTER);
155
156         /* for files, throw in R and W if have I and A (owner).  This makes
157            insert-only dirs work properly */
158         if (vType(avc) != VDIR && (fileBits & (PRSFS_ADMINISTER | PRSFS_INSERT)) ==
159             (PRSFS_ADMINISTER | PRSFS_INSERT))
160             fileBits |= (PRSFS_READ | PRSFS_WRITE);
161
162         if (check_mode_bits & CHECK_MODE_BITS) {
163             /* owner mode bits are further restrictions on the access mode
164              * The mode bits are mapped to protection bits through the
165              * fileModeMap. If CMB_ALLOW_EXEC_AS_READ is set, it's from the
166              * NFS translator and we don't know if it's a read or execute
167              * on the NFS client, but both need to read the data.
168              */
169             mask = (avc->m.Mode & 0700) >> 6;   /* file restrictions to use */
170             fileBits &= ~fileModeMap[mask];
171             if (check_mode_bits & CMB_ALLOW_EXEC_AS_READ) {
172                  if (avc->m.Mode & 0100) fileBits |= PRSFS_READ;
173             }
174         }
175         return ((fileBits & arights) == arights);       /* true if all rights bits are on */
176     }
177 }
178
179
180 #if     defined(AFS_SUN5_ENV) || (defined(AFS_SGI_ENV) && !defined(AFS_SGI65_ENV))
181 afs_access(OSI_VC_ARG(avc), amode, flags, acred)
182     int flags;          
183 #else
184 afs_access(OSI_VC_ARG(avc), amode, acred)
185 #endif
186     OSI_VC_DECL(avc);
187     register afs_int32 amode;
188     struct AFS_UCRED *acred; {
189     register afs_int32 code;
190     struct vrequest treq;
191     struct afs_fakestat_state fakestate;
192     OSI_VC_CONVERT(avc)
193
194     AFS_STATCNT(afs_access);
195     afs_Trace3(afs_iclSetp, CM_TRACE_ACCESS, ICL_TYPE_POINTER, avc, 
196                 ICL_TYPE_INT32, amode,
197                 ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(avc->m.Length));
198     afs_InitFakeStat(&fakestate);
199     if (code = afs_InitReq(&treq, acred)) return code;
200
201     code = afs_EvalFakeStat(&avc, &fakestate, &treq);
202     if (code) {
203         afs_PutFakeStat(&fakestate);
204         return code;
205     }
206
207     code = afs_VerifyVCache(avc, &treq);
208     if (code) {
209       afs_PutFakeStat(&fakestate);
210       code = afs_CheckCode(code, &treq, 16);
211       return code; 
212     }
213
214     /* if we're looking for write access and we have a read-only file system, report it */
215     if ((amode & VWRITE) && (avc->states & CRO)) {
216         afs_PutFakeStat(&fakestate);
217         return EROFS;
218     }
219     code = 1;           /* Default from here on in is access ok. */
220     if (avc->states & CForeign) {
221         /* In the dfs xlator the EXEC bit is mapped to LOOKUP */
222         if (amode & VEXEC)
223             code = afs_AccessOK(avc, PRSFS_LOOKUP, &treq, CHECK_MODE_BITS);
224         if (code && (amode & VWRITE)) {
225             code = afs_AccessOK(avc, PRSFS_WRITE, &treq, CHECK_MODE_BITS);
226             if (code && (vType(avc) == VDIR)) {
227                 if (code)
228                     code = afs_AccessOK(avc, PRSFS_INSERT, &treq, CHECK_MODE_BITS);
229                 if (!code) 
230                     code = afs_AccessOK(avc, PRSFS_DELETE, &treq, CHECK_MODE_BITS);
231             }   
232         }       
233         if (code && (amode & VREAD)) 
234             code = afs_AccessOK(avc, PRSFS_READ, &treq, CHECK_MODE_BITS);
235     } else {
236         if (vType(avc) == VDIR) {
237             if (amode & VEXEC) 
238                code = afs_AccessOK(avc, PRSFS_LOOKUP, &treq, CHECK_MODE_BITS);
239             if (code && (amode & VWRITE)) {
240                 code = afs_AccessOK(avc, PRSFS_INSERT, &treq, CHECK_MODE_BITS);
241                 if (!code) 
242                    code = afs_AccessOK(avc, PRSFS_DELETE, &treq, CHECK_MODE_BITS);
243             }
244             if (code && (amode & VREAD))
245                 code = afs_AccessOK(avc, PRSFS_LOOKUP, &treq, CHECK_MODE_BITS);
246         } else {
247             if (amode & VEXEC) {
248                 code = afs_AccessOK(avc, PRSFS_READ, &treq, CHECK_MODE_BITS);
249                 if (code) {
250 #ifdef  AFS_OSF_ENV
251                     /*
252                      * The nfs server in read operations for non-owner of a file
253                      * will also check the access with the VEXEC (along with VREAD)
254                      * because for them exec is the same as read over the net because of
255                      * demand loading. But this means if the mode bit is '-rw' the call
256                      * will fail below; so for this particular case where both modes are
257                      * specified (only in rfs_read so far) and from the xlator requests
258                      * we return succes.
259                      */
260                     if (!((amode & VREAD) && AFS_NFSXLATORREQ(acred)))
261 #endif
262                     if ((avc->m.Mode & 0100) == 0) code = 0;
263                 } else if (avc->m.Mode & 0100) code = 1;
264             }
265             if (code && (amode & VWRITE)) 
266             {
267                code = afs_AccessOK(avc, PRSFS_WRITE, &treq, CHECK_MODE_BITS);
268
269                /* The above call fails when the NFS translator tries to copy
270                ** a file with r--r--r-- permissions into a directory which
271                ** has system:anyuser acl. This is because the destination file
272                ** file is first created with r--r--r-- permissions through an
273                ** unauthenticated connectin.  hence, the above afs_AccessOK
274                ** call returns failure. hence, we retry without any file 
275                ** mode bit checking */
276                if ( !code && AFS_NFSXLATORREQ(acred) && avc->m.Owner == ANONYMOUSID)
277                 code=afs_AccessOK(avc,PRSFS_WRITE, &treq, DONT_CHECK_MODE_BITS);
278             }
279             if (code && (amode & VREAD)) 
280                code = afs_AccessOK(avc, PRSFS_READ, &treq, CHECK_MODE_BITS);
281         }
282     }
283     afs_PutFakeStat(&fakestate);
284     if (code) {
285         return 0;               /* if access is ok */
286     } else {
287         code = afs_CheckCode(EACCES, &treq, 17);             /* failure code */
288         return code;
289     }
290 }
291
292 #if defined(UKERNEL) && defined(AFS_WEB_ENHANCEMENTS)
293 /*
294  * afs_getRights
295  * This function is just an interface to afs_GetAccessBits
296  */
297 int afs_getRights(OSI_VC_ARG(avc), arights, acred)
298     OSI_VC_DECL(avc);
299     register afs_int32 arights;
300     struct AFS_UCRED *acred;
301 {
302     register afs_int32 code;
303     struct vrequest treq;
304     OSI_VC_CONVERT(avc)
305
306     if (code = afs_InitReq(&treq, acred)) return code;
307
308     code = afs_VerifyVCache(avc, &treq);
309     if (code) {
310       code = afs_CheckCode(code, &treq, 16);
311       return code; 
312     }
313
314     return afs_GetAccessBits(avc, arights, &treq);
315 }
316 #endif /* defined(UKERNEL) && defined(AFS_WEB_ENHANCEMENTS) */