post-1-3-70-windows-changes-20040816
[openafs.git] / src / WINNT / afsd / cm_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 #include <afs/param.h>
11 #include <afs/stds.h>
12
13 #ifndef DJGPP
14 #include <windows.h>
15 #include <winsock2.h>
16 #endif
17 #include <malloc.h>
18 #include <string.h>
19 #include <stdlib.h>
20 #ifndef DJGPP
21 #include <nb30.h>
22 #endif
23 #include <osi.h>
24
25 #include "afsd.h"
26
27 /* called with scp write-locked, check to see if we have the ACL info we need
28  * and can get it w/o blocking for any locks.
29  *
30  * Never drops the scp lock, but may fail if the access control info comes from
31  * the parent directory, and the parent's scache entry can't be found, or it
32  * can't be locked.  Thus, this must always be called in a while loop to stabilize
33  * things, since we can always lose the race condition getting to the parent vnode.
34  */
35 int cm_HaveAccessRights(struct cm_scache *scp, struct cm_user *up, long rights,
36         long *outRightsp)
37 {
38         cm_scache_t *aclScp;
39         long code;
40         cm_fid_t tfid;
41         int didLock;
42         long trights;
43         
44         didLock = 0;
45         if (scp->fileType == CM_SCACHETYPE_DIRECTORY) {
46                 aclScp = scp;
47                 cm_HoldSCache(scp);
48         }
49         else {
50                 tfid.cell = scp->fid.cell;
51                 tfid.volume = scp->fid.volume;
52                 tfid.vnode = scp->parentVnode;
53                 tfid.unique = scp->parentUnique;
54                 aclScp = cm_FindSCache(&tfid);
55                 if (!aclScp) return 0;
56                 if (aclScp != scp) {
57                         code = lock_TryMutex(&aclScp->mx);
58                         if (code == 0) {
59                                 /* can't get lock safely and easily */
60                                 cm_ReleaseSCache(aclScp);
61                                 return 0;
62                         }
63
64                         /* check that we have a callback, too */
65                         if (!cm_HaveCallback(aclScp)) {
66                                 /* can't use it */
67                                 lock_ReleaseMutex(&aclScp->mx);
68                                 cm_ReleaseSCache(aclScp);
69                                 return 0;
70                         }
71                         didLock = 1;
72                 }
73         }
74
75         lock_AssertMutex(&aclScp->mx);
76         
77         /* now if rights is a subset of the public rights, we're done.
78          * Otherwise, if we an explicit acl entry, we're also in good shape,
79          * and can definitively answer.
80          */
81         if ((~aclScp->anyAccess & rights) == 0) {
82                 *outRightsp = rights;
83         }
84         else {
85                 /* we have to check the specific rights info */
86                 code = cm_FindACLCache(aclScp, up, &trights);
87                 if (code) {
88                         code = 0;
89                         goto done;
90                 }
91                 *outRightsp = trights;
92         }
93
94         /* check mode bits */
95         if (!(scp->unixModeBits & 0400))
96                 *outRightsp &= ~PRSFS_READ;
97         if (!(scp->unixModeBits & 0200))
98                 *outRightsp &= ~PRSFS_WRITE;
99
100         code = 1;
101         /* fall through */
102         
103 done:
104     if (didLock) 
105         lock_ReleaseMutex(&aclScp->mx);
106         cm_ReleaseSCache(aclScp);
107         return code;
108 }
109
110 /* called with locked scp; ensures that we have an ACL cache entry for the
111  * user specified by the parameter "up."
112  * In pathological race conditions, this function may return success without
113  * having loaded the entry properly (due to a racing callback revoke), so this
114  * function must also be called in a while loop to make sure that we eventually
115  * succeed.
116  */
117 long cm_GetAccessRights(struct cm_scache *scp, struct cm_user *up,
118         struct cm_req *reqp)
119 {
120         long code;
121         cm_fid_t tfid;
122     cm_scache_t *aclScp;
123
124         /* pretty easy: just force a pass through the fetch status code */
125         
126         osi_Log2(afsd_logp, "GetAccess scp %x user %x", scp, up);
127
128     /* first, start by finding out whether we have a directory or something
129          * else, so we can find what object's ACL we need.
130      */
131     code = cm_SyncOp(scp, NULL, up, reqp, 0, CM_SCACHESYNC_GETSTATUS
132                       | CM_SCACHESYNC_NEEDCALLBACK);
133                         
134     if (code) return code;
135         
136     if (scp->fileType != CM_SCACHETYPE_DIRECTORY) {
137                 /* not a dir, use parent dir's acl */
138                 tfid.cell = scp->fid.cell;
139         tfid.volume = scp->fid.volume;
140         tfid.vnode = scp->parentVnode;
141         tfid.unique = scp->parentUnique;
142                 lock_ReleaseMutex(&scp->mx);
143                 code = cm_GetSCache(&tfid, &aclScp, up, reqp);
144         if (code) {
145                         lock_ObtainMutex(&scp->mx);
146             return code;
147         }
148                 
149                 osi_Log1(afsd_logp, "GetAccess parent %x", aclScp);
150                 lock_ObtainMutex(&aclScp->mx);
151         code = cm_GetCallback(aclScp, up, reqp, 1);
152         lock_ReleaseMutex(&aclScp->mx);
153         cm_ReleaseSCache(aclScp);
154         lock_ObtainMutex(&scp->mx);
155     } 
156     else {
157                 code = cm_GetCallback(scp, up, reqp, 1);
158     }
159
160         return code;
161 }