Standardize License information
[openafs.git] / src / WINNT / afsd / cm_aclent.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 <stdlib.h>
15 #include <string.h>
16 #include <malloc.h>
17
18 #include "afsd.h"
19
20 /* 
21  * This next lock controls access to all cm_aclent structures in the system,
22  * in either the free list or in the LRU queue.  A read lock prevents someone
23  * from modifying the list(s), and a write lock is required for modifying
24  * the list.  The actual data stored in the randomUid and randomAccess fields
25  * is actually maintained as up-to-date or not via the scache llock.
26  * An aclent structure is free if it has no back vnode pointer.
27  */
28 osi_rwlock_t cm_aclLock;                /* lock for system's aclents */
29 cm_aclent_t *cm_aclLRUp;                /* LRUQ for dudes in vnodes' lists */
30 cm_aclent_t *cm_aclLRUEndp;             /* ditto */
31
32 /* 
33  * Get an acl cache entry for a particular user and file, or return that it doesn't exist.
34  * Called with the scp locked.
35  */
36 long cm_FindACLCache(cm_scache_t *scp, cm_user_t *userp, long *rightsp)
37 {
38         cm_aclent_t *aclp;
39
40         lock_ObtainWrite(&cm_aclLock);
41         for (aclp = scp->randomACLp; aclp; aclp = aclp->nextp) {
42                 if (aclp->userp == userp) {
43                         if (aclp->tgtLifetime && aclp->tgtLifetime <= (long) osi_Time()) {
44                                 /* ticket expired */
45                                 aclp->tgtLifetime = 0;
46                                 *rightsp = 0;
47                                 break; /* get a new acl from server */
48                         }
49                         else {
50                                 *rightsp = aclp->randomAccess;
51                                 if (cm_aclLRUEndp == aclp)
52                                         cm_aclLRUEndp = (cm_aclent_t *) osi_QPrev(&aclp->q);
53
54                                 /* move to the head of the LRU queue */
55                                 osi_QRemove((osi_queue_t **) &cm_aclLRUp, &aclp->q);
56                                 osi_QAddH((osi_queue_t **) &cm_aclLRUp,
57                                         (osi_queue_t **) &cm_aclLRUEndp,
58                                         &aclp->q);
59                         }
60                         lock_ReleaseWrite(&cm_aclLock);
61                         return 0;
62                 }
63         }
64
65         /* 
66          * If we make it here, this entry isn't present, so we're going to fail. 
67          */
68         lock_ReleaseWrite(&cm_aclLock);
69         return -1;
70 }
71
72
73 /* 
74  * This function returns a free (not in the LRU queue) acl cache entry.
75  * It must be called with the cm_aclLock lock held.
76  */
77 static cm_aclent_t *GetFreeACLEnt(void)
78 {
79         cm_aclent_t *aclp;
80         cm_aclent_t *taclp;
81         cm_aclent_t **laclpp;
82
83         if (cm_aclLRUp == NULL)
84                 osi_panic("empty aclent LRU", __FILE__, __LINE__);
85
86         aclp = cm_aclLRUEndp;
87         if (aclp == cm_aclLRUEndp)
88                 cm_aclLRUEndp = (cm_aclent_t *) osi_QPrev(&aclp->q);
89         osi_QRemove((osi_queue_t **) &cm_aclLRUp, &aclp->q);
90         if (aclp->backp) {
91                 /* 
92                  * Remove the entry from the vnode's list 
93                  */
94                 laclpp = &aclp->backp->randomACLp;
95                 for (taclp = *laclpp; taclp; laclpp = &taclp->nextp, taclp = *laclpp) {
96                         if (taclp == aclp) 
97                                 break;
98                 }
99                 if (!taclp) 
100                         osi_panic("GetFreeACLEnt race", __FILE__, __LINE__);
101                 *laclpp = aclp->nextp;                  /* remove from vnode list */
102                 aclp->backp = NULL;
103         }
104         
105         /* release the old user */
106         if (aclp->userp) {
107                 cm_ReleaseUser(aclp->userp);
108                 aclp->userp = NULL;
109         }
110         return aclp;
111 }
112
113
114 /* 
115  * Add rights to an acl cache entry.  Do the right thing if not present, 
116  * including digging up an entry from the LRU queue.
117  *
118  * The scp must be locked when this function is called.
119  */
120 long cm_AddACLCache(cm_scache_t *scp, cm_user_t *userp, long rights)
121 {
122         register struct cm_aclent *aclp;
123
124         lock_ObtainWrite(&cm_aclLock);
125         for (aclp = scp->randomACLp; aclp; aclp = aclp->nextp) {
126                 if (aclp->userp == userp) {
127                         aclp->randomAccess = rights;
128                         if (aclp->tgtLifetime == 0) 
129                                 aclp->tgtLifetime = cm_TGTLifeTime(pag);
130                         lock_ReleaseWrite(&cm_aclLock);
131                         return 0;
132                 }
133         }
134
135         /* 
136          * Didn't find the dude we're looking for, so take someone from the LRUQ 
137          * and  reuse. But first try the free list and see if there's already 
138          * someone there.
139          */
140         aclp = GetFreeACLEnt();          /* can't fail, panics instead */
141         osi_QAddH((osi_queue_t **) &cm_aclLRUp, (osi_queue_t **) &cm_aclLRUEndp, &aclp->q);
142         aclp->backp = scp;
143         aclp->nextp = scp->randomACLp;
144         scp->randomACLp = aclp;
145         aclp->userp = userp;
146         cm_HoldUser(userp);
147         aclp->randomAccess = rights;
148         aclp->tgtLifetime = cm_TGTLifeTime(userp);
149         lock_ReleaseWrite(&cm_aclLock);
150
151         return 0;
152 }
153
154 /* 
155  * Initialize the cache to have an entries.  Called during system startup.
156  */
157 long cm_InitACLCache(long size)
158 {
159         cm_aclent_t *aclp;
160         long i;
161         static osi_once_t once;
162
163         
164         if (osi_Once(&once)) {
165                 lock_InitializeRWLock(&cm_aclLock, "cm_aclLock");
166                 osi_EndOnce(&once);
167         }
168
169         lock_ObtainWrite(&cm_aclLock);
170         cm_aclLRUp = cm_aclLRUEndp = NULL;
171         aclp = (cm_aclent_t *) malloc(size * sizeof(cm_aclent_t));
172         memset(aclp, 0, size * sizeof(cm_aclent_t));
173
174         /* 
175          * Put all of these guys on the LRU queue 
176          */
177         for (i = 0; i < size; i++) {
178                 osi_QAddH((osi_queue_t **) &cm_aclLRUp, (osi_queue_t **) &cm_aclLRUEndp,
179                         &aclp->q);
180                 aclp++;
181         }
182
183         lock_ReleaseWrite(&cm_aclLock);
184         return 0;
185 }
186
187
188 /* 
189  * Free all associated acl entries.  We actually just clear the back pointer
190  * since the acl entries are already in the free list.  The scp must be locked
191  * or completely unreferenced (such as when called while recycling the scp).
192  */
193 void cm_FreeAllACLEnts(cm_scache_t *scp)
194 {
195         cm_aclent_t *aclp;
196         cm_aclent_t *taclp;
197
198         lock_ObtainWrite(&cm_aclLock);
199         for (aclp = scp->randomACLp; aclp; aclp = taclp) {
200                 taclp = aclp->nextp;
201                 if (aclp->userp) {
202                         cm_ReleaseUser(aclp->userp);
203                         aclp->userp = NULL;
204                 }
205                 aclp->backp = (struct cm_scache *) 0;
206         }
207
208         scp->randomACLp = (struct cm_aclent *) 0;
209         scp->anyAccess = 0;             /* reset this, too */
210         lock_ReleaseWrite(&cm_aclLock);
211 }
212
213
214 /* 
215  * Invalidate all ACL entries for particular user on this particular vnode.
216  *
217  * The scp must be locked.
218  */
219 void cm_InvalidateACLUser(cm_scache_t *scp, cm_user_t *userp)
220 {
221         cm_aclent_t *aclp;
222         cm_aclent_t **laclpp;
223
224         lock_ObtainWrite(&cm_aclLock);
225         laclpp = &scp->randomACLp;
226         for (aclp = *laclpp; aclp; laclpp = &aclp->nextp, aclp = *laclpp) {
227                 if (userp == aclp->userp) {     /* One for a given user/scache */
228                         *laclpp = aclp->nextp;
229                         cm_ReleaseUser(aclp->userp);
230                         aclp->userp = NULL;
231                         aclp->backp = (struct cm_scache *) 0;
232                         break;
233                 }
234         }
235         lock_ReleaseWrite(&cm_aclLock);
236 }