afs-web-interface-enhancements-20010623
[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 "../afs/param.h"       /* Should be always first */
23 #include "../afs/sysincludes.h" /* Standard vendor system headers */
24 #include "../afs/afsincludes.h" /* Afs-based standard headers */
25 #include "../afs/afs_stats.h" /* statistics */
26 #include "../afs/afs_cbqueue.h"
27 #include "../afs/nfsclient.h"
28 #include "../afs/afs_osidnlc.h"
29
30 #ifndef ANONYMOUSID
31 #define ANONYMOUSID     32766 /* make sure this is same as in ptserver.h */
32 #endif
33
34
35
36
37 /* access bits to turn off for various owner Unix mode values */
38 static char fileModeMap[8] = {
39     PRSFS_READ | PRSFS_WRITE,
40     PRSFS_READ | PRSFS_WRITE,
41     PRSFS_READ,
42     PRSFS_READ,
43     PRSFS_WRITE,
44     PRSFS_WRITE,
45     0,
46     0
47 };
48
49 /* avc must be held.  Returns bit map of mode bits.  Ignores file mode bits */
50 afs_int32 afs_GetAccessBits (avc, arights, areq)
51     register struct vcache *avc;
52     register afs_int32 arights;
53     register struct vrequest *areq; 
54 {
55     AFS_STATCNT(afs_GetAccessBits);
56     /* see if anyuser has the required access bits */
57     if ((arights & avc->anyAccess) == arights) {
58         return arights;
59     }
60
61     /* look in per-pag cache */
62     if (avc->Access) {  /* not beautiful, but Sun's cc will tolerate it */
63       struct axscache *ac;
64
65       ac = afs_FindAxs(avc->Access, areq->uid);
66       if (ac) {
67         return (arights & ac->axess);
68       }
69     }
70
71     if (!(avc->states & CForeign)) { 
72       /* If there aren't any bits cached for this user (but the vnode
73        * _is_ cached, obviously), make sure this user has valid tokens
74        * before bothering with the RPC.  */
75       struct unixuser *tu;
76       extern struct unixuser *afs_FindUser();
77       tu = afs_FindUser( areq->uid, avc->fid.Cell, READ_LOCK );
78       if (!tu) {
79         return (arights & avc->anyAccess);
80       }
81       if ((tu->vid == UNDEFVID) || !(tu->states & UHasTokens) ||
82           (tu->states & UTokensBad)) {
83         afs_PutUser(tu, READ_LOCK);
84         return (arights & avc->anyAccess);
85       }
86       else {
87         afs_PutUser(tu, READ_LOCK);
88       }
89     }
90
91     { /* Ok, user has valid tokens, go ask the server. */
92       struct AFSFetchStatus OutStatus;
93       afs_int32 code;
94     
95       code = afs_FetchStatus(avc, &avc->fid, areq, &OutStatus);
96       return (code ? 0 : OutStatus.CallerAccess & arights);
97     }
98 }
99
100
101 /* the new access ok function.  AVC must be held but not locked. if avc is a
102  * file, its parent need not be held, and should not be locked. */
103
104 afs_AccessOK(avc, arights, areq, check_mode_bits)
105 struct vcache *avc;
106 afs_int32 arights, check_mode_bits;
107 struct vrequest *areq; {
108     register struct vcache *tvc;
109     struct VenusFid dirFid;
110     register afs_int32 mask;
111     afs_int32 dirBits;
112     register afs_int32 fileBits;
113
114     AFS_STATCNT(afs_AccessOK);
115
116     if ((vType(avc) == VDIR) || (avc->states & CForeign)) {
117       /* rights are just those from acl */
118       return (arights == afs_GetAccessBits(avc, arights, areq));
119     }
120     else {
121         /* some rights come from dir and some from file.  Specifically, you 
122          * have "a" rights to a file if you are its owner, which comes
123          * back as "a" rights to the file. You have other rights just
124          * from dir, but all are restricted by the file mode bit. Now,
125          * if you have I and A rights to a file, we throw in R and W
126          * rights for free. These rights will then be restricted by
127          * the access mask. */
128         dirBits = 0;
129         if (avc->parentVnode) {
130             dirFid.Cell = avc->fid.Cell;
131             dirFid.Fid.Volume = avc->fid.Fid.Volume;
132             dirFid.Fid.Vnode = avc->parentVnode;
133             dirFid.Fid.Unique = avc->parentUnique;
134             /* Avoid this GetVCache call */
135             tvc = afs_GetVCache(&dirFid, areq, (afs_int32 *)0,
136                                 (struct vcache*)0, WRITE_LOCK);
137             if (tvc) {
138                 dirBits = afs_GetAccessBits(tvc, arights, areq);
139                 afs_PutVCache(tvc, WRITE_LOCK);
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 afs_access(OSI_VC_ARG(avc), amode, flags, acred)
178     int flags;          
179 #else
180 afs_access(OSI_VC_ARG(avc), amode, acred)
181 #endif
182     OSI_VC_DECL(avc);
183     register afs_int32 amode;
184     struct AFS_UCRED *acred; {
185     register afs_int32 code;
186     struct vrequest treq;
187     OSI_VC_CONVERT(avc)
188
189     AFS_STATCNT(afs_access);
190     afs_Trace3(afs_iclSetp, CM_TRACE_ACCESS, ICL_TYPE_POINTER, avc, 
191                ICL_TYPE_INT32, amode, ICL_TYPE_INT32, avc->m.Length);
192     if (code = afs_InitReq(&treq, acred)) return code;
193
194     code = afs_VerifyVCache(avc, &treq);
195     if (code) {
196       code = afs_CheckCode(code, &treq, 16);
197       return code; 
198     }
199
200     /* if we're looking for write access and we have a read-only file system, report it */
201     if ((amode & VWRITE) && (avc->states & CRO)) {
202         return EROFS;
203     }
204     code = 1;           /* Default from here on in is access ok. */
205     if (avc->states & CForeign) {
206         /* In the dfs xlator the EXEC bit is mapped to LOOKUP */
207         if (amode & VEXEC)
208             code = afs_AccessOK(avc, PRSFS_LOOKUP, &treq, CHECK_MODE_BITS);
209         if (code && (amode & VWRITE)) {
210             code = afs_AccessOK(avc, PRSFS_WRITE, &treq, CHECK_MODE_BITS);
211             if (code && (vType(avc) == VDIR)) {
212                 if (code)
213                     code = afs_AccessOK(avc, PRSFS_INSERT, &treq, CHECK_MODE_BITS);
214                 if (!code) 
215                     code = afs_AccessOK(avc, PRSFS_DELETE, &treq, CHECK_MODE_BITS);
216             }   
217         }       
218         if (code && (amode & VREAD)) 
219             code = afs_AccessOK(avc, PRSFS_READ, &treq, CHECK_MODE_BITS);
220     } else {
221         if (vType(avc) == VDIR) {
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_INSERT, &treq, CHECK_MODE_BITS);
226                 if (!code) 
227                    code = afs_AccessOK(avc, PRSFS_DELETE, &treq, CHECK_MODE_BITS);
228             }
229             if (code && (amode & VREAD))
230                 code = afs_AccessOK(avc, PRSFS_LOOKUP, &treq, CHECK_MODE_BITS);
231         } else {
232             if (amode & VEXEC) {
233                 code = afs_AccessOK(avc, PRSFS_READ, &treq, CHECK_MODE_BITS);
234                 if (code) {
235 #ifdef  AFS_OSF_ENV
236                     /*
237                      * The nfs server in read operations for non-owner of a file
238                      * will also check the access with the VEXEC (along with VREAD)
239                      * because for them exec is the same as read over the net because of
240                      * demand loading. But this means if the mode bit is '-rw' the call
241                      * will fail below; so for this particular case where both modes are
242                      * specified (only in rfs_read so far) and from the xlator requests
243                      * we return succes.
244                      */
245                     if (!((amode & VREAD) && AFS_NFSXLATORREQ(acred)))
246 #endif
247                     if ((avc->m.Mode & 0100) == 0) code = 0;
248                 } else if (avc->m.Mode & 0100) code = 1;
249             }
250             if (code && (amode & VWRITE)) 
251             {
252                code = afs_AccessOK(avc, PRSFS_WRITE, &treq, CHECK_MODE_BITS);
253
254                /* The above call fails when the NFS translator tries to copy
255                ** a file with r--r--r-- permissions into a directory which
256                ** has system:anyuser acl. This is because the destination file
257                ** file is first created with r--r--r-- permissions through an
258                ** unauthenticated connectin.  hence, the above afs_AccessOK
259                ** call returns failure. hence, we retry without any file 
260                ** mode bit checking */
261                if ( !code && AFS_NFSXLATORREQ(acred) && avc->m.Owner == ANONYMOUSID)
262                 code=afs_AccessOK(avc,PRSFS_WRITE, &treq, DONT_CHECK_MODE_BITS);
263             }
264             if (code && (amode & VREAD)) 
265                code = afs_AccessOK(avc, PRSFS_READ, &treq, CHECK_MODE_BITS);
266         }
267     }
268     if (code)
269         return 0;               /* if access is ok */
270     else {
271       code = afs_CheckCode(EACCES, &treq, 17);       /* failure code */
272       return code;
273     }
274 }
275
276 #if defined(UKERNEL) && defined(AFS_WEB_ENHANCEMENTS)
277 /*
278  * afs_getRights
279  * This function is just an interface to afs_GetAccessBits
280  */
281 int afs_getRights(OSI_VC_ARG(avc), arights, acred)
282     OSI_VC_DECL(avc);
283     register afs_int32 arights;
284     struct AFS_UCRED *acred;
285 {
286     register afs_int32 code;
287     struct vrequest treq;
288     OSI_VC_CONVERT(avc)
289
290     if (code = afs_InitReq(&treq, acred)) return code;
291
292     code = afs_VerifyVCache(avc, &treq);
293     if (code) {
294       code = afs_CheckCode(code, &treq, 16);
295       return code; 
296     }
297
298     return afs_GetAccessBits(avc, arights, &treq);
299 }
300 #endif /* defined(UKERNEL) && defined(AFS_WEB_ENHANCEMENTS) */