Windows: cm_user interlocked operations
[openafs.git] / src / WINNT / afsd / cm_user.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
11 #include <afsconfig.h>
12 #include <afs/param.h>
13 #include <roken.h>
14
15 #include <afs/stds.h>
16
17 #include <windows.h>
18 #include <malloc.h>
19 #include <string.h>
20
21 #include "afsd.h"
22 #include "smb.h"
23 #include <osi.h>
24 #include <rx/rx.h>
25
26
27 osi_rwlock_t cm_userLock;
28
29 cm_user_t *cm_rootUserp;
30
31 void cm_InitUser(void)
32 {
33     static osi_once_t once;
34
35     if (osi_Once(&once)) {
36         lock_InitializeRWLock(&cm_userLock, "cm_userLock", LOCK_HIERARCHY_USER_GLOBAL);
37         osi_EndOnce(&once);
38     }
39
40     cm_rootUserp = cm_NewUser();
41 }
42
43 cm_user_t *cm_NewUser(void)
44 {
45     cm_user_t *userp;
46
47     userp = malloc(sizeof(*userp));
48     memset(userp, 0, sizeof(*userp));
49     InterlockedIncrement( &userp->refCount);
50     lock_InitializeMutex(&userp->mx, "cm_user_t", LOCK_HIERARCHY_USER);
51     return userp;
52 }
53
54 /* must be called with locked userp */
55 cm_ucell_t *cm_GetUCell(cm_user_t *userp, cm_cell_t *cellp)
56 {
57     cm_ucell_t *ucp;
58
59     lock_AssertMutex(&userp->mx);
60     for (ucp = userp->cellInfop; ucp; ucp=ucp->nextp) {
61         if (ucp->cellp == cellp)
62             break;
63     }
64
65     if (!ucp) {
66         ucp = malloc(sizeof(*ucp));
67         memset(ucp, 0, sizeof(*ucp));
68         ucp->nextp = userp->cellInfop;
69         if (userp->cellInfop)
70             ucp->iterator = userp->cellInfop->iterator + 1;
71         else
72             ucp->iterator = 1;
73         userp->cellInfop = ucp;
74         ucp->cellp = cellp;
75         if (userp == cm_rootUserp)
76             ucp->flags |= CM_UCELLFLAG_ROOTUSER;
77     }
78
79     return ucp;
80 }
81
82 cm_ucell_t *cm_FindUCell(cm_user_t *userp, int iterator)
83 {
84     cm_ucell_t *ucp;
85     cm_ucell_t *best;
86
87     best = NULL;
88     lock_AssertMutex(&userp->mx);
89     for (ucp = userp->cellInfop; ucp; ucp = ucp->nextp) {
90         if (ucp->iterator >= iterator)
91             best = ucp;
92         else
93             break;
94     }
95     return best;
96 }
97
98 void cm_HoldUser(cm_user_t *up)
99 {
100     long lcount;
101
102     lock_ObtainWrite(&cm_userLock);
103     lcount = InterlockedIncrement( &up->refCount);
104     osi_assertx(lcount > 0, "user refcount error");
105     lock_ReleaseWrite(&cm_userLock);
106 }
107
108 void cm_ReleaseUser(cm_user_t *userp)
109 {
110     cm_ucell_t *ucp;
111     cm_ucell_t *ncp;
112     long lcount;
113
114     if (userp == NULL)
115         return;
116
117     lock_ObtainWrite(&cm_userLock);
118     lcount = InterlockedDecrement(&userp->refCount);
119     osi_assertx(lcount >= 0, "cm_user_t refCount < 0");
120     if (lcount == 0) {
121         lock_FinalizeMutex(&userp->mx);
122         for (ucp = userp->cellInfop; ucp; ucp = ncp) {
123             ncp = ucp->nextp;
124             if (ucp->ticketp)
125                 free(ucp->ticketp);
126             free(ucp);
127         }
128         free(userp);
129     }
130     lock_ReleaseWrite(&cm_userLock);
131 }
132
133
134 void cm_HoldUserVCRef(cm_user_t *userp)
135 {
136     lock_ObtainMutex(&userp->mx);
137     InterlockedIncrement(&userp->vcRefs);
138     lock_ReleaseMutex(&userp->mx);
139 }
140
141 /* release the count of the # of connections that use this user structure.
142  * When this hits zero, we know we won't be getting any new requests from
143  * this user, and thus we can start GC'ing connections.  Ref count on user
144  * won't hit zero until all cm_conn_t's have been GC'd, since they hold
145  * refCount references to userp.
146  */
147 void cm_ReleaseUserVCRef(cm_user_t *userp)
148 {
149     long lcount;
150
151     lock_ObtainMutex(&userp->mx);
152     lcount = InterlockedDecrement(&userp->vcRefs);
153     osi_assertx(lcount >= 0, "cm_user vcRefs refCount < 0");
154     lock_ReleaseMutex(&userp->mx);
155 }
156
157
158 /*
159  * Check if any users' tokens have expired and if they have then do the
160  * equivalent of unlogging the user for that particular cell for which
161  * the tokens have expired.
162  * ref. cm_IoctlDelToken() in cm_ioctl.c
163  * This routine is called by the cm_Daemon() ie. the periodic daemon.
164  * every cm_daemonTokenCheckInterval seconds
165  */
166 void cm_CheckTokenCache(time_t now)
167 {
168     extern smb_vc_t *smb_allVCsp; /* global vcp list */
169     smb_vc_t   *vcp;
170     smb_user_t *usersp;
171     cm_user_t  *userp = NULL;
172     cm_ucell_t *ucellp;
173     BOOL bExpired=FALSE;
174
175     /*
176      * For every vcp, get the user and check his tokens
177      */
178     lock_ObtainRead(&smb_rctLock);
179     for (vcp=smb_allVCsp; vcp; vcp=vcp->nextp) {
180         for (usersp=vcp->usersp; usersp; usersp=usersp->nextp) {
181             if (usersp->unp) {
182                 if ((userp=usersp->unp->userp)==0)
183                     continue;
184             } else
185                 continue;
186             lock_ObtainMutex(&userp->mx);
187             for (ucellp=userp->cellInfop; ucellp; ucellp=ucellp->nextp) {
188                 if (ucellp->flags & CM_UCELLFLAG_RXKAD) {
189                     if (ucellp->expirationTime < now) {
190                         /* this guy's tokens have expired */
191                         osi_Log3(afsd_logp, "cm_CheckTokens: Tokens for user:%s have expired expiration time:0x%x ucellp:%x",
192                                  ucellp->userName, ucellp->expirationTime, ucellp);
193                         if (ucellp->ticketp) {
194                             free(ucellp->ticketp);
195                             ucellp->ticketp = NULL;
196                         }
197                         _InterlockedAnd(&ucellp->flags, ~CM_UCELLFLAG_RXKAD);
198                         ucellp->gen++;
199                         lock_ReleaseMutex(&userp->mx);
200                         cm_ResetACLCache(ucellp->cellp, userp);
201                         lock_ObtainMutex(&userp->mx);
202                     }
203                 }
204             }
205             lock_ReleaseMutex(&userp->mx);
206         }
207     }
208     lock_ReleaseRead(&smb_rctLock);
209 }
210
211 #ifdef USE_ROOT_TOKENS
212 /*
213  * Service/Parameters/RootTokens/<cellname>/
214  * -> UseLSA
215  * -> Keytab (required if UseLSA is 0)
216  * -> Principal (required if there is more than one principal in the keytab)
217  * -> Realm (required if realm is not upper-case of <cellname>
218  * -> RequireEncryption
219  */
220
221 void
222 cm_RefreshRootTokens(void)
223 {
224
225 }
226 #endif