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