e1aeeba3659aaeb0d432765ac267d7fd0d8b6642
[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|PRSFS_DELETE);
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 ) {
128         code = cm_SyncOp(scp, NULL, userp, reqp, 0,
129                          CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_FORCECB);
130         if (!code) 
131             cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
132     } else {
133         /* not a dir, use parent dir's acl */
134         tfid.cell = scp->fid.cell;
135         tfid.volume = scp->fid.volume;
136         tfid.vnode = scp->parentVnode;
137         tfid.unique = scp->parentUnique;
138         lock_ReleaseMutex(&scp->mx);
139         code = cm_GetSCache(&tfid, &aclScp, userp, reqp);
140         if (code) {
141             lock_ObtainMutex(&scp->mx);
142             goto _done;
143         }       
144                 
145         osi_Log2(afsd_logp, "GetAccess parent scp %x user %x", aclScp, userp);
146         lock_ObtainMutex(&aclScp->mx);
147         code = cm_SyncOp(aclScp, NULL, userp, reqp, 0,
148                          CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_FORCECB);
149         if (!code)
150             cm_SyncOpDone(aclScp, NULL, 
151                           CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
152         lock_ReleaseMutex(&aclScp->mx);
153         cm_ReleaseSCache(aclScp);
154         lock_ObtainMutex(&scp->mx);
155     }
156
157   _done:
158     return code;
159 }