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