81baa4df97cdd2db6e86bcb914d1cbc29bd96359
[dragonfly.git] / lib / libc / net / nscache.c
1 /*-
2  * Copyright (c) 2005 Michael Bushkov <bushman@rsu.ru>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  * $FreeBSD: src/lib/libc/net/nscache.c,v 1.2 2007/10/17 23:20:49 tmclaugh Exp $
27  */
28
29 #include "namespace.h"
30 #include <nsswitch.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include "un-namespace.h"
34 #include "nscachedcli.h"
35 #include "nscache.h"
36
37 #define NSS_CACHE_KEY_INITIAL_SIZE      (256)
38 #define NSS_CACHE_KEY_SIZE_LIMIT        (NSS_CACHE_KEY_INITIAL_SIZE << 4)
39
40 #define NSS_CACHE_BUFFER_INITIAL_SIZE   (1024)
41 #define NSS_CACHE_BUFFER_SIZE_LIMIT     (NSS_CACHE_BUFFER_INITIAL_SIZE << 8)
42
43 #define CACHED_SOCKET_PATH              "/var/run/nscd"
44
45 int
46 __nss_cache_handler(void *retval, void *mdata, va_list ap)
47 {
48         return (NS_UNAVAIL);
49 }
50
51 int
52 __nss_common_cache_read(void *retval, void *mdata, va_list ap)
53 {
54         struct cached_connection_params params;
55         cached_connection connection;
56
57         char *buffer;
58         size_t buffer_size, size;
59
60         nss_cache_info const *cache_info;
61         nss_cache_data *cache_data;
62         va_list ap_new;
63         int res;
64
65         cache_data = (nss_cache_data *)mdata;
66         cache_info = cache_data->info;
67
68         memset(&params, 0, sizeof(struct cached_connection_params));
69         params.socket_path = CACHED_SOCKET_PATH;
70
71         cache_data->key = (char *)malloc(NSS_CACHE_KEY_INITIAL_SIZE);
72         memset(cache_data->key, 0, NSS_CACHE_KEY_INITIAL_SIZE);
73         cache_data->key_size = NSS_CACHE_KEY_INITIAL_SIZE;
74         va_copy(ap_new, ap);
75
76         do {
77                 size = cache_data->key_size;
78                 res = cache_info->id_func(cache_data->key, &size, ap_new,
79                     cache_info->mdata);
80                 va_end(ap_new);
81                 if (res == NS_RETURN) {
82                         if (cache_data->key_size > NSS_CACHE_KEY_SIZE_LIMIT)
83                                 break;
84
85                         cache_data->key_size <<= 1;
86                         cache_data->key = realloc(cache_data->key,
87                             cache_data->key_size);
88                         memset(cache_data->key, 0, cache_data->key_size);
89                         va_copy(ap_new, ap);
90                 }
91         } while (res == NS_RETURN);
92
93         if (res != NS_SUCCESS) {
94                 free(cache_data->key);
95                 cache_data->key = NULL;
96                 cache_data->key_size = 0;
97                 return (res);
98         } else
99                 cache_data->key_size = size;
100
101         buffer_size = NSS_CACHE_BUFFER_INITIAL_SIZE;
102         buffer = (char *)malloc(NSS_CACHE_BUFFER_INITIAL_SIZE);
103         memset(buffer, 0, NSS_CACHE_BUFFER_INITIAL_SIZE);
104
105         do {
106                 connection = __open_cached_connection(&params);
107                 if (connection == NULL) {
108                         res = -1;
109                         break;
110                 }
111                 res = __cached_read(connection, cache_info->entry_name,
112                     cache_data->key, cache_data->key_size, buffer,
113                     &buffer_size);
114                 __close_cached_connection(connection);
115                 if (res == -2 && buffer_size < NSS_CACHE_BUFFER_SIZE_LIMIT) {
116                         buffer = (char *)realloc(buffer, buffer_size);
117                         memset(buffer, 0, buffer_size);
118                 }
119         } while (res == -2);
120
121         if (res == 0) {
122                 if (buffer_size == 0) {
123                         free(buffer);
124                         free(cache_data->key);
125                         cache_data->key = NULL;
126                         cache_data->key_size = 0;
127                         return (NS_RETURN);
128                 }
129
130                 va_copy(ap_new, ap);
131                 res = cache_info->unmarshal_func(buffer, buffer_size, retval,
132                     ap_new, cache_info->mdata);
133                 va_end(ap_new);
134
135                 if (res != NS_SUCCESS) {
136                         free(buffer);
137                         free(cache_data->key);
138                         cache_data->key = NULL;
139                         cache_data->key_size = 0;
140                         return (res);
141                 } else
142                         res = 0;
143         }
144
145         if (res == 0) {
146                 free(cache_data->key);
147                 cache_data->key = NULL;
148                 cache_data->key_size = 0;
149         }
150
151         free(buffer);
152         return (res == 0 ? NS_SUCCESS : NS_NOTFOUND);
153 }
154
155 int
156 __nss_common_cache_write(void *retval, void *mdata, va_list ap)
157 {
158         struct cached_connection_params params;
159         cached_connection connection;
160
161         char *buffer;
162         size_t buffer_size;
163
164         nss_cache_info const *cache_info;
165         nss_cache_data *cache_data;
166         va_list ap_new;
167         int res;
168
169         cache_data = (nss_cache_data *)mdata;
170         cache_info = cache_data->info;
171
172         if (cache_data->key == NULL)
173                 return (NS_UNAVAIL);
174
175         memset(&params, 0, sizeof(struct cached_connection_params));
176         params.socket_path = CACHED_SOCKET_PATH;
177
178         connection = __open_cached_connection(&params);
179         if (connection == NULL) {
180                 free(cache_data->key);
181                 return (NS_UNAVAIL);
182         }
183
184         buffer_size = NSS_CACHE_BUFFER_INITIAL_SIZE;
185         buffer = (char *)malloc(NSS_CACHE_BUFFER_INITIAL_SIZE);
186         memset(buffer, 0, NSS_CACHE_BUFFER_INITIAL_SIZE);
187
188         do {
189                 size_t size;
190
191                 size = buffer_size;
192                 va_copy(ap_new, ap);
193                 res = cache_info->marshal_func(buffer, &size, retval, ap_new,
194                     cache_info->mdata);
195                 va_end(ap_new);
196
197                 if (res == NS_RETURN) {
198                         if (buffer_size > NSS_CACHE_BUFFER_SIZE_LIMIT)
199                                 break;
200
201                         buffer_size <<= 1;
202                         buffer = (char *)realloc(buffer, buffer_size);
203                         memset(buffer, 0, buffer_size);
204                 }
205         } while (res == NS_RETURN);
206
207         if (res != NS_SUCCESS) {
208                 __close_cached_connection(connection);
209                 free(cache_data->key);
210                 free(buffer);
211                 return (res);
212         }
213
214         res = __cached_write(connection, cache_info->entry_name,
215             cache_data->key, cache_data->key_size, buffer, buffer_size);
216         __close_cached_connection(connection);
217
218         free(cache_data->key);
219         free(buffer);
220
221         return (res == 0 ? NS_SUCCESS : NS_UNAVAIL);
222 }
223
224 int
225 __nss_common_cache_write_negative(void *mdata)
226 {
227         struct cached_connection_params params;
228         cached_connection connection;
229         int res;
230
231         nss_cache_info const *cache_info;
232         nss_cache_data *cache_data;
233
234         cache_data = (nss_cache_data *)mdata;
235         cache_info = cache_data->info;
236
237         if (cache_data->key == NULL)
238                 return (NS_UNAVAIL);
239
240         memset(&params, 0, sizeof(struct cached_connection_params));
241         params.socket_path = CACHED_SOCKET_PATH;
242
243         connection = __open_cached_connection(&params);
244         if (connection == NULL) {
245                 free(cache_data->key);
246                 return (NS_UNAVAIL);
247         }
248
249         res = __cached_write(connection, cache_info->entry_name,
250             cache_data->key, cache_data->key_size, NULL, 0);
251         __close_cached_connection(connection);
252
253         free(cache_data->key);
254         return (res == 0 ? NS_SUCCESS : NS_UNAVAIL);
255 }
256
257 int
258 __nss_mp_cache_read(void *retval, void *mdata, va_list ap)
259 {
260         struct cached_connection_params params;
261         cached_mp_read_session rs;
262
263         char *buffer;
264         size_t buffer_size;
265
266         nss_cache_info const *cache_info;
267         nss_cache_data *cache_data;
268         va_list ap_new;
269         int res;
270
271         cache_data = (nss_cache_data *)mdata;
272         cache_info = cache_data->info;
273
274         if (cache_info->get_mp_ws_func() != INVALID_CACHED_MP_WRITE_SESSION)
275                 return (NS_UNAVAIL);
276
277         rs = cache_info->get_mp_rs_func();
278         if (rs == INVALID_CACHED_MP_READ_SESSION) {
279                 memset(&params, 0, sizeof(struct cached_connection_params));
280                 params.socket_path = CACHED_SOCKET_PATH;
281
282                 rs = __open_cached_mp_read_session(&params,
283                     cache_info->entry_name);
284                 if (rs == INVALID_CACHED_MP_READ_SESSION)
285                         return (NS_UNAVAIL);
286
287                 cache_info->set_mp_rs_func(rs);
288         }
289
290         buffer_size = NSS_CACHE_BUFFER_INITIAL_SIZE;
291         buffer = (char *)malloc(NSS_CACHE_BUFFER_INITIAL_SIZE);
292         memset(buffer, 0, NSS_CACHE_BUFFER_INITIAL_SIZE);
293
294         do {
295                 res = __cached_mp_read(rs, buffer, &buffer_size);
296                 if (res == -2 && buffer_size < NSS_CACHE_BUFFER_SIZE_LIMIT) {
297                         buffer = (char *)realloc(buffer, buffer_size);
298                         memset(buffer, 0, buffer_size);
299                 }
300         } while (res == -2);
301
302         if (res == 0) {
303                 va_copy(ap_new, ap);
304                 res = cache_info->unmarshal_func(buffer, buffer_size, retval,
305                     ap_new, cache_info->mdata);
306                 va_end(ap_new);
307
308                 if (res != NS_SUCCESS) {
309                         free(buffer);
310                         return (res);
311                 } else
312                         res = 0;
313         } else {
314                 free(buffer);
315                 __close_cached_mp_read_session(rs);
316                 rs = INVALID_CACHED_MP_READ_SESSION;
317                 cache_info->set_mp_rs_func(rs);
318                 return (res == -1 ? NS_RETURN : NS_UNAVAIL);
319         }
320
321         free(buffer);
322         return (res == 0 ? NS_SUCCESS : NS_NOTFOUND);
323 }
324
325 int
326 __nss_mp_cache_write(void *retval, void *mdata, va_list ap)
327 {
328         struct cached_connection_params params;
329         cached_mp_write_session ws;
330
331         char *buffer;
332         size_t buffer_size;
333
334         nss_cache_info const *cache_info;
335         nss_cache_data *cache_data;
336         va_list ap_new;
337         int res;
338
339         cache_data = (nss_cache_data *)mdata;
340         cache_info = cache_data->info;
341
342         ws = cache_info->get_mp_ws_func();
343         if (ws == INVALID_CACHED_MP_WRITE_SESSION) {
344                 memset(&params, 0, sizeof(struct cached_connection_params));
345                 params.socket_path = CACHED_SOCKET_PATH;
346
347                 ws = __open_cached_mp_write_session(&params,
348                     cache_info->entry_name);
349                 if (ws == INVALID_CACHED_MP_WRITE_SESSION)
350                         return (NS_UNAVAIL);
351
352                 cache_info->set_mp_ws_func(ws);
353         }
354
355         buffer_size = NSS_CACHE_BUFFER_INITIAL_SIZE;
356         buffer = (char *)malloc(NSS_CACHE_BUFFER_INITIAL_SIZE);
357         memset(buffer, 0, NSS_CACHE_BUFFER_INITIAL_SIZE);
358
359         do {
360                 size_t size;
361
362                 size = buffer_size;
363                 va_copy(ap_new, ap);
364                 res = cache_info->marshal_func(buffer, &size, retval, ap_new,
365                     cache_info->mdata);
366                 va_end(ap_new);
367
368                 if (res == NS_RETURN) {
369                         if (buffer_size > NSS_CACHE_BUFFER_SIZE_LIMIT)
370                                 break;
371
372                         buffer_size <<= 1;
373                         buffer = (char *)realloc(buffer, buffer_size);
374                         memset(buffer, 0, buffer_size);
375                 }
376         } while (res == NS_RETURN);
377
378         if (res != NS_SUCCESS) {
379                 free(buffer);
380                 return (res);
381         }
382
383         res = __cached_mp_write(ws, buffer, buffer_size);
384
385         free(buffer);
386         return (res == 0 ? NS_SUCCESS : NS_UNAVAIL);
387 }
388
389 int
390 __nss_mp_cache_write_submit(void *retval, void *mdata, va_list ap)
391 {
392         cached_mp_write_session ws;
393
394         nss_cache_info const *cache_info;
395         nss_cache_data *cache_data;
396
397         cache_data = (nss_cache_data *)mdata;
398         cache_info = cache_data->info;
399
400         ws = cache_info->get_mp_ws_func();
401         if (ws != INVALID_CACHED_MP_WRITE_SESSION) {
402                 __close_cached_mp_write_session(ws);
403                 ws = INVALID_CACHED_MP_WRITE_SESSION;
404                 cache_info->set_mp_ws_func(ws);
405         }
406         return (NS_UNAVAIL);
407 }
408
409 int
410 __nss_mp_cache_end(void *retval, void *mdata, va_list ap)
411 {
412         cached_mp_write_session ws;
413         cached_mp_read_session rs;
414
415         nss_cache_info const *cache_info;
416         nss_cache_data *cache_data;
417
418         cache_data = (nss_cache_data *)mdata;
419         cache_info = cache_data->info;
420
421         ws = cache_info->get_mp_ws_func();
422         if (ws != INVALID_CACHED_MP_WRITE_SESSION) {
423                 __abandon_cached_mp_write_session(ws);
424                 ws = INVALID_CACHED_MP_WRITE_SESSION;
425                 cache_info->set_mp_ws_func(ws);
426         }
427
428         rs = cache_info->get_mp_rs_func();
429         if (rs != INVALID_CACHED_MP_READ_SESSION) {
430                 __close_cached_mp_read_session(rs);
431                 rs = INVALID_CACHED_MP_READ_SESSION;
432                 cache_info->set_mp_rs_func(rs);
433         }
434
435         return (NS_UNAVAIL);
436 }