Import Upstream version 1.8.5
[hcoop/debian/openafs.git] / src / afs / VNOPS / afs_vnop_access.c
CommitLineData
805e021f
CE
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 */
41static 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 */
53afs_int32
54afs_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
108int
109afs_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))
191int
192afs_access(OSI_VC_DECL(avc), afs_int32 amode, int flags,
193 afs_ucred_t *acred)
194#else
195int
196afs_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 */
348int
349afs_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) */