2 * Copyright 2000, International Business Machines Corporation and others.
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
11 * afs_vnop_access.c - access vop ccess mode bit support for vnode operations.
22 #include <afsconfig.h>
23 #include "afs/param.h"
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"
34 #define ANONYMOUSID 32766 /* make sure this is same as in ptserver.h */
40 /* access bits to turn off for various owner Unix mode values */
41 static char fileModeMap
[8] = {
42 PRSFS_READ
| PRSFS_WRITE
,
43 PRSFS_READ
| PRSFS_WRITE
,
52 /* avc must be held. Returns bit map of mode bits. Ignores file mode bits */
54 afs_GetAccessBits(struct vcache
*avc
, afs_int32 arights
,
55 struct vrequest
*areq
)
57 AFS_STATCNT(afs_GetAccessBits
);
58 /* see if anyuser has the required access bits */
59 if ((arights
& avc
->f
.anyAccess
) == arights
) {
63 /* look in per-pag cache */
64 if (avc
->Access
) { /* not beautiful, but Sun's cc will tolerate it */
67 ac
= afs_FindAxs(avc
->Access
, areq
->uid
);
69 return (arights
& ac
->axess
);
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. */
78 tu
= afs_FindUser(areq
->uid
, avc
->f
.fid
.Cell
, READ_LOCK
);
80 return (arights
& avc
->f
.anyAccess
);
82 if (!(tu
->states
& UHasTokens
) || (tu
->states
& UTokensBad
)) {
83 afs_PutUser(tu
, READ_LOCK
);
84 return (arights
& avc
->f
.anyAccess
);
86 afs_PutUser(tu
, READ_LOCK
);
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... */
95 { /* Ok, user has valid tokens, go ask the server. */
96 struct AFSFetchStatus OutStatus
;
99 code
= afs_FetchStatus(avc
, &avc
->f
.fid
, areq
, &OutStatus
);
100 return (code
? 0 : OutStatus
.CallerAccess
& arights
);
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. */
109 afs_AccessOK(struct vcache
*avc
, afs_int32 arights
, struct vrequest
*areq
,
110 afs_int32 check_mode_bits
)
113 struct VenusFid dirFid
;
118 AFS_STATCNT(afs_AccessOK
);
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.
129 dirBits
= PRSFS_LOOKUP
| PRSFS_READ
;
130 return (arights
== (dirBits
& arights
));
132 return (arights
== afs_GetAccessBits(avc
, arights
, areq
));
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. */
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
);
150 dirBits
= afs_GetAccessBits(tvc
, arights
, areq
);
154 dirBits
= 0xffffffff; /* assume OK; this is a race condition */
155 if (arights
& PRSFS_ADMINISTER
)
156 fileBits
= afs_GetAccessBits(avc
, arights
, areq
);
158 fileBits
= 0; /* don't make call if results don't matter */
160 /* compute basic rights in fileBits, taking A from file bits */
162 (fileBits
& PRSFS_ADMINISTER
) | (dirBits
& ~PRSFS_ADMINISTER
);
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
);
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.
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
;
185 return ((fileBits
& arights
) == arights
); /* true if all rights bits are on */
190 #if defined(AFS_SUN5_ENV) || (defined(AFS_SGI_ENV) && !defined(AFS_SGI65_ENV))
192 afs_access(OSI_VC_DECL(avc
), afs_int32 amode
, int flags
,
196 afs_access(OSI_VC_DECL(avc
), afs_int32 amode
,
201 struct vrequest
*treq
= NULL
;
202 struct afs_fakestat_state fakestate
;
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
));
210 afs_InitFakeStat(&fakestate
);
211 if ((code
= afs_CreateReq(&treq
, acred
))) {
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
);
222 afs_DestroyReq(treq
);
226 code
= afs_EvalFakeStat(&avc
, &fakestate
, treq
);
230 afs_PutFakeStat(&fakestate
);
232 afs_DestroyReq(treq
);
236 if (vType(avc
) != VDIR
|| !afs_InReadDir(avc
)) {
237 code
= afs_VerifyVCache(avc
, treq
);
239 afs_PutFakeStat(&fakestate
);
241 code
= afs_CheckCode(code
, treq
, 16);
242 afs_DestroyReq(treq
);
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
);
251 afs_DestroyReq(treq
);
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
);
259 /* printf("Network is down in afs_vnop_access\n"); */
260 afs_DestroyReq(treq
);
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 */
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
)) {
274 afs_AccessOK(avc
, PRSFS_INSERT
, treq
,
278 afs_AccessOK(avc
, PRSFS_DELETE
, treq
,
282 if (code
&& (amode
& VREAD
))
283 code
= afs_AccessOK(avc
, PRSFS_READ
, treq
, CHECK_MODE_BITS
);
285 if (vType(avc
) == VDIR
) {
288 afs_AccessOK(avc
, PRSFS_LOOKUP
, treq
, CHECK_MODE_BITS
);
289 if (code
&& (amode
& VWRITE
)) {
291 afs_AccessOK(avc
, PRSFS_INSERT
, treq
, CHECK_MODE_BITS
);
294 afs_AccessOK(avc
, PRSFS_DELETE
, treq
,
297 if (code
&& (amode
& VREAD
))
299 afs_AccessOK(avc
, PRSFS_LOOKUP
, treq
, CHECK_MODE_BITS
);
302 code
= afs_AccessOK(avc
, PRSFS_READ
, treq
, CHECK_MODE_BITS
);
304 if ((avc
->f
.m
.Mode
& 0100) == 0)
306 } else if (avc
->f
.m
.Mode
& 0100)
309 if (code
&& (amode
& VWRITE
)) {
310 code
= afs_AccessOK(avc
, PRSFS_WRITE
, treq
, CHECK_MODE_BITS
);
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
)
322 afs_AccessOK(avc
, PRSFS_WRITE
, treq
,
323 DONT_CHECK_MODE_BITS
);
325 if (code
&& (amode
& VREAD
))
326 code
= afs_AccessOK(avc
, PRSFS_READ
, treq
, CHECK_MODE_BITS
);
329 afs_PutFakeStat(&fakestate
);
334 afs_DestroyReq(treq
);
335 return 0; /* if access is ok */
337 code
= afs_CheckCode(EACCES
, treq
, 17); /* failure code */
338 afs_DestroyReq(treq
);
346 * This function is just an interface to afs_GetAccessBits
349 afs_getRights(OSI_VC_DECL(avc
), afs_int32 arights
,
353 struct vrequest
*treq
= NULL
;
356 if ((code
= afs_CreateReq(&treq
, acred
)))
359 code
= afs_VerifyVCache(avc
, treq
);
361 code
= afs_CheckCode(code
, treq
, 18);
362 afs_DestroyReq(treq
);
366 code
= afs_GetAccessBits(avc
, arights
, treq
);
367 afs_DestroyReq(treq
);
370 #endif /* defined(UKERNEL) */