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