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 <cx/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,
const 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 unsigned char *key = malloc(keylen);
66 memcpy(key, authdb, authdblen);
67 key[authdblen] =
0;
68 memcpy(key + authdblen +
1, user, userlen);
69
70 CxHashKey mapkey = cx_hash_key_bytes(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 const char *password,
123 const 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(cxmutstr)) :
NULL;
144 cusr->numgroups = numgroups;
145 for(
int i=
0;i<numgroups;i++) {
146 cusr->groups[i] = cx_strdup(cx_str(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 unsigned char *key = malloc(keylen);
168 memcpy(key, authdb, authdblen);
169 key[authdblen] =
0;
170 memcpy(key + authdblen +
1, user->name, userlen);
171 CxHashKey mapkey = cx_hash_key_bytes(key, keylen);
172
173 elm->key.data = key;
174 elm->key.len = mapkey.len;
175 elm->key.hash = mapkey.hash;
176 elm->slot = mapkey.hash%cache.size;
177
178
179 pthread_mutex_lock(&auth_cache_mutex);
180
181
182 if(cache.head &&
183 (cache.count >= cache.max_users || now-cache.head->created >
120))
184 {
185 UserCacheElm *first = cache.head;
186 cache.head = first->next_user;
187 if(!cache.head) {
188 cache.trail =
NULL;
189 }
190 auth_cache_remove_from_map(first);
191 }
192
193
194 UserCacheElm *prevelm = cache.map[elm->slot];
195 if(prevelm) {
196 for(;;) {
197 if(!prevelm->next_elm) {
198 break;
199 }
200 prevelm = prevelm->next_elm;
201 }
202 }
203 if(prevelm) {
204 prevelm->next_elm = elm;
205 }
else {
206 cache.map[elm->slot] = elm;
207 }
208
209
210 if(cache.head) {
211 cache.trail->next_user = elm;
212 cache.trail = elm;
213 }
else {
214 cache.head = elm;
215 cache.trail = elm;
216 }
217
218 cache.count++;
219
220 pthread_mutex_unlock(&auth_cache_mutex);
221 }
222
223 void auth_cache_remove_from_map(UserCacheElm *elm) {
224 UserCacheElm *prevelm =
NULL;
225 UserCacheElm *e = cache.map[elm->slot];
226 while(e) {
227 if(e == elm) {
228 break;
229 }
else {
230 prevelm = e;
231 }
232 e = e->next_elm;
233 }
234 if(prevelm) {
235 prevelm->next_elm = elm->next_elm;
236 }
else {
237 cache.map[elm->slot] = elm->next_elm;
238 }
239
240 free((
void*)elm->key.data);
241 cached_user_unref(elm->user);
242 free(elm);
243
244 cache.count--;
245 }
246
247 int cached_user_verify_password(CachedUser *user,
const char *password) {
248 if(!strcmp(user->password, password)) {
249 return 1;
250 }
else {
251 return 0;
252 }
253 }
254
255 int cached_user_check_group(CachedUser *user,
const char *group) {
256 cxstring grp = cx_str(group);
257 for(
int i=
0;i<user->numgroups;i++) {
258 if(!cx_strcmp(cx_strcast(user->groups[i]), grp)) {
259 return 1;
260 }
261 }
262 return 0;
263 }
264
265 void cached_user_unref(CachedUser *user) {
266 uint32_t ref = ws_atomic_dec32(&user->ref);
267 if(ref ==
0) {
268 cached_user_delete(user);
269 }
270 }
271
272 void cached_user_delete(CachedUser *user) {
273 free(user->user.name);
274 free(user->authdb);
275 free(user->password);
276 free(user->groups);
277 free(user);
278 }
279
280
281
282
283
284
285
286 User* authdb_get_user(AuthDB *db, Session *sn, Request *rq,
const char *user) {
287 if(db->use_cache) {
288 User *u = auth_cache_get(db->name, user);
289 if(u) {
290 return u;
291 }
292 }
293 return db->get_user(db, sn, rq, user);
294 }
295
296 User* authdb_get_and_verify(AuthDB *db, Session *sn, Request *rq,
const char *user,
const char *password,
int *pw) {
297 User *u = authdb_get_user(db, sn, rq, user);
298 if(u) {
299 if(u->verify_password(u, password)) {
300 if(db->use_cache) {
301 auth_cache_add(db->name, u, password,
NULL,
0);
302 }
303 *pw =
1;
304 }
else {
305 *pw =
0;
306 u->free(u);
307 u =
NULL;
308 }
309 }
310 return u;
311 }
312