1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <pthread.h>
33
34 #include <ucx/map.h>
35
36 #include "../public/nsapi.h"
37 #include "../util/atomic.h"
38 #include "auth.h"
39
40 static pthread_mutex_t auth_cache_mutex =
PTHREAD_MUTEX_INITIALIZER;
41 static UserCache cache;
42
43 void auth_cache_init() {
44 log_ereport(
LOG_VERBOSE,
"auth_cache_init");
45
46
47 cache.map = calloc(
80,
sizeof(UserCacheElm));
48 cache.size =
80;
49 cache.count =
0;
50 cache.max_users =
64;
51 cache.head =
NULL;
52 cache.trail =
NULL;
53 }
54
55 User* auth_cache_get(
char *authdb,
char *user) {
56
57
58
59
60
61 size_t authdblen = strlen(authdb);
62 size_t userlen = strlen(user);
63
64 size_t keylen = authdblen + userlen +
1;
65 char *key = malloc(keylen);
66 memcpy(key, authdb, authdblen);
67 key[authdblen] =
0;
68 memcpy(key + authdblen +
1, user, userlen);
69
70 UcxKey mapkey = ucx_key(key, keylen);
71
72
73 time_t now = time(
NULL);
74 size_t slot = mapkey.hash%cache.size;
75
76 User *u =
NULL;
77 pthread_mutex_lock(&auth_cache_mutex);
78
79 UserCacheElm *elm = cache.map[slot];
80 while(elm && elm->key.hash != mapkey.hash) {
81 elm = elm->next_elm;
82 }
83
84 if(elm) {
85
86 int n = (mapkey.len > elm->key.len) ? elm->key.len : mapkey.len;
87 if (!memcmp(elm->key.data, mapkey.data, n)) {
88
89
90 if(now - elm->created >
120) {
91
92
93 UserCacheElm *e = cache.head;
94 while(e) {
95 if(e == elm) {
96 break;
97 }
98 UserCacheElm *nu = e->next_user;
99 auth_cache_remove_from_map(e);
100 e = nu;
101 }
102 cache.head = elm->next_user;
103 if(cache.trail == elm) {
104 cache.trail =
NULL;
105 }
106 auth_cache_remove_from_map(elm);
107 u =
NULL;
108 }
else {
109 u = (User*)elm->user;
110 }
111 }
112 }
113
114 pthread_mutex_unlock(&auth_cache_mutex);
115 free(key);
116 return u;
117 }
118
119 void auth_cache_add(
120 char *authdb,
121 User *user,
122 char *password,
123 char **groups,
124 size_t numgroups)
125 {
126
127
128
129
130
131
132 CachedUser *cusr = malloc(
sizeof(CachedUser));
133 cusr->user.name = strdup(user->name);
134 cusr->user.uid = user->uid;
135 cusr->user.gid = user->gid;
136 cusr->user.verify_password =
137 (user_verify_passwd_f)cached_user_verify_password;
138 cusr->user.check_group = (user_check_group_f)cached_user_check_group;
139 cusr->user.free = (user_free_f)cached_user_unref;
140
141 cusr->authdb = strdup(authdb);
142 cusr->password = strdup(password);
143 cusr->groups = numgroups ? calloc(numgroups,
sizeof(
sstr_t)) :
NULL;
144 cusr->numgroups = numgroups;
145 for(
int i=
0;i<numgroups;i++) {
146 cusr->groups[i] = sstrdup(sstr(groups[i]));
147 }
148 cusr->ref =
1;
149
150
151
152
153
154
155
156 time_t now = time(
NULL);
157 UserCacheElm *elm = malloc(
sizeof(UserCacheElm));
158 elm->user = cusr;
159 elm->created = now;
160 elm->next_elm =
NULL;
161 elm->next_user =
NULL;
162
163
164 size_t authdblen = strlen(authdb);
165 size_t userlen = strlen(user->name);
166 size_t keylen = authdblen + userlen +
1;
167 char *key = malloc(keylen);
168 memcpy(key, authdb, authdblen);
169 key[authdblen] =
0;
170 memcpy(key + authdblen +
1, user->name, userlen);
171 UcxKey mapkey = ucx_key(key, keylen);
172
173 elm->key = mapkey;
174 elm->slot = mapkey.hash%cache.size;
175
176
177 pthread_mutex_lock(&auth_cache_mutex);
178
179
180 if(cache.head &&
181 (cache.count >= cache.max_users || now-cache.head->created >
120))
182 {
183 UserCacheElm *first = cache.head;
184 cache.head = first->next_user;
185 if(!cache.head) {
186 cache.trail =
NULL;
187 }
188 auth_cache_remove_from_map(first);
189 }
190
191
192 UserCacheElm *prevelm = cache.map[elm->slot];
193 if(prevelm) {
194 for(;;) {
195 if(!prevelm->next_elm) {
196 break;
197 }
198 prevelm = prevelm->next_elm;
199 }
200 }
201 if(prevelm) {
202 prevelm->next_elm = elm;
203 }
else {
204 cache.map[elm->slot] = elm;
205 }
206
207
208 if(cache.head) {
209 cache.trail->next_user = elm;
210 cache.trail = elm;
211 }
else {
212 cache.head = elm;
213 cache.trail = elm;
214 }
215
216 cache.count++;
217
218 pthread_mutex_unlock(&auth_cache_mutex);
219 }
220
221 void auth_cache_remove_from_map(UserCacheElm *elm) {
222 UserCacheElm *prevelm =
NULL;
223 UserCacheElm *e = cache.map[elm->slot];
224 while(e) {
225 if(e == elm) {
226 break;
227 }
else {
228 prevelm = e;
229 }
230 e = e->next_elm;
231 }
232 if(prevelm) {
233 prevelm->next_elm = elm->next_elm;
234 }
else {
235 cache.map[elm->slot] = elm->next_elm;
236 }
237
238 free(elm->key.data);
239 cached_user_unref(elm->user);
240 free(elm);
241
242 cache.count--;
243 }
244
245 int cached_user_verify_password(CachedUser *user,
char *password) {
246 if(!strcmp(user->password, password)) {
247 return 1;
248 }
else {
249 return 0;
250 }
251 }
252
253 int cached_user_check_group(CachedUser *user,
char *group) {
254 sstr_t grp = sstr(group);
255 for(
int i=
0;i<user->numgroups;i++) {
256 if(!sstrcmp(user->groups[i], grp)) {
257 return 1;
258 }
259 }
260 return 0;
261 }
262
263 void cached_user_unref(CachedUser *user) {
264 uint32_t ref = ws_atomic_dec32(&user->ref);
265 if(ref ==
0) {
266 cached_user_delete(user);
267 }
268 }
269
270 void cached_user_delete(CachedUser *user) {
271 free(user->user.name);
272 free(user->authdb);
273 free(user->password);
274 free(user->groups);
275 free(user);
276 }
277
278
279
280
281
282
283
284 User* authdb_get_user(AuthDB *db,
char *user) {
285 if(db->use_cache) {
286 User *u = auth_cache_get(db->name, user);
287 if(u) {
288 return u;
289 }
290 }
291 return db->get_user(db, user);
292 }
293
294 User* authdb_get_and_verify(AuthDB *db,
char *user,
char *password,
int *pw) {
295 User *u =
NULL;
296
297 if(db->use_cache) {
298 u = auth_cache_get(db->name, user);
299 if(u) {
300 if(u->verify_password(u, password)) {
301 *pw =
1;
302 }
else {
303 *pw =
0;
304 u->free(u);
305 u =
NULL;
306 }
307 return u;
308 }
309 }
310
311 u = db->get_user(db, user);
312 if(u) {
313 if(u->verify_password(u, password)) {
314 if(db->use_cache) {
315 auth_cache_add(db->name, u, password,
NULL,
0);
316 }
317 *pw =
1;
318 }
else {
319 *pw =
0;
320 u->free(u);
321 u =
NULL;
322 }
323 }
324 return u;
325 }
326