Merge branch 'vendor/GCC50'
[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 __unused, void *mdata __unused,
47     va_list ap __unused)
48 {
49         return (NS_UNAVAIL);
50 }
51
52 int
53 __nss_common_cache_read(void *retval, void *mdata, va_list ap)
54 {
55         struct cached_connection_params params;
56         cached_connection connection;
57
58         char *buffer;
59         size_t buffer_size, size;
60
61         nss_cache_info const *cache_info;
62         nss_cache_data *cache_data;
63         va_list ap_new;
64         int res;
65
66         cache_data = (nss_cache_data *)mdata;
67         cache_info = cache_data->info;
68
69         memset(&params, 0, sizeof(struct cached_connection_params));
70         params.socket_path = CACHED_SOCKET_PATH;
71
72         cache_data->key = (char *)malloc(NSS_CACHE_KEY_INITIAL_SIZE);
73         memset(cache_data->key, 0, NSS_CACHE_KEY_INITIAL_SIZE);
74         cache_data->key_size = NSS_CACHE_KEY_INITIAL_SIZE;
75         va_copy(ap_new, ap);
76
77         do {
78                 size = cache_data->key_size;
79                 res = cache_info->id_func(cache_data->key, &size, ap_new,
80                     cache_info->mdata);
81                 va_end(ap_new);
82                 if (res == NS_RETURN) {
83                         if (cache_data->key_size > NSS_CACHE_KEY_SIZE_LIMIT)
84                                 break;
85
86                         cache_data->key_size <<= 1;
87                         cache_data->key = realloc(cache_data->key,
88                             cache_data->key_size);
89                         memset(cache_data->key, 0, cache_data->key_size);
90                         va_copy(ap_new, ap);
91                 }
92         } while (res == NS_RETURN);
93
94         if (res != NS_SUCCESS) {
95                 free(cache_data->key);
96                 cache_data->key = NULL;
97                 cache_data->key_size = 0;
98                 return (res);
99         } else
100                 cache_data->key_size = size;
101
102         buffer_size = NSS_CACHE_BUFFER_INITIAL_SIZE;
103         buffer = (char *)malloc(NSS_CACHE_BUFFER_INITIAL_SIZE);
104         memset(buffer, 0, NSS_CACHE_BUFFER_INITIAL_SIZE);
105
106         do {
107                 connection = __open_cached_connection(&params);
108                 if (connection == NULL) {
109                         res = -1;
110                         break;
111                 }
112                 res = __cached_read(connection, cache_info->entry_name,
113                     cache_data->key, cache_data->key_size, buffer,
114                     &buffer_size);
115                 __close_cached_connection(connection);
116                 if (res == -2 && buffer_size < NSS_CACHE_BUFFER_SIZE_LIMIT) {
117                         buffer = (char *)realloc(buffer, buffer_size);
118                         memset(buffer, 0, buffer_size);
119                 }
120         } while (res == -2);
121
122         if (res == 0) {
123                 if (buffer_size == 0) {
124                         free(buffer);
125                         free(cache_data->key);
126                         cache_data->key = NULL;
127                         cache_data->key_size = 0;
128                         return (NS_RETURN);
129                 }
130
131                 va_copy(ap_new, ap);
132                 res = cache_info->unmarshal_func(buffer, buffer_size, retval,
133                     ap_new, cache_info->mdata);
134                 va_end(ap_new);
135
136                 if (res != NS_SUCCESS) {
137                         free(buffer);
138                         free(cache_data->key);
139                         cache_data->key = NULL;
140                         cache_data->key_size = 0;
141                         return (res);
142                 } else
143                         res = 0;
144         }
145
146         if (res == 0) {
147                 free(cache_data->key);
148                 cache_data->key = NULL;
149                 cache_data->key_size = 0;
150         }
151
152         free(buffer);
153         return (res == 0 ? NS_SUCCESS : NS_NOTFOUND);
154 }
155
156 int
157 __nss_common_cache_write(void *retval, void *mdata, va_list ap)
158 {
159         struct cached_connection_params params;
160         cached_connection connection;
161
162         char *buffer;
163         size_t buffer_size;
164
165         nss_cache_info const *cache_info;
166         nss_cache_data *cache_data;
167         va_list ap_new;
168         int res;
169
170         cache_data = (nss_cache_data *)mdata;
171         cache_info = cache_data->info;
172
173         if (cache_data->key == NULL)
174                 return (NS_UNAVAIL);
175
176         memset(&params, 0, sizeof(struct cached_connection_params));
177         params.socket_path = CACHED_SOCKET_PATH;
178
179         connection = __open_cached_connection(&params);
180         if (connection == NULL) {
181                 free(cache_data->key);
182                 return (NS_UNAVAIL);
183         }
184
185         buffer_size = NSS_CACHE_BUFFER_INITIAL_SIZE;
186         buffer = (char *)malloc(NSS_CACHE_BUFFER_INITIAL_SIZE);
187         memset(buffer, 0, NSS_CACHE_BUFFER_INITIAL_SIZE);
188
189         do {
190                 size_t size;
191
192                 size = buffer_size;
193                 va_copy(ap_new, ap);
194                 res = cache_info->marshal_func(buffer, &size, retval, ap_new,
195                     cache_info->mdata);
196                 va_end(ap_new);
197
198                 if (res == NS_RETURN) {
199                         if (buffer_size > NSS_CACHE_BUFFER_SIZE_LIMIT)
200                                 break;
201
202                         buffer_size <<= 1;
203                         buffer = (char *)realloc(buffer, buffer_size);
204                         memset(buffer, 0, buffer_size);
205                 }
206         } while (res == NS_RETURN);
207
208         if (res != NS_SUCCESS) {
209                 __close_cached_connection(connection);
210                 free(cache_data->key);
211                 free(buffer);
212                 return (res);
213         }
214
215         res = __cached_write(connection, cache_info->entry_name,
216             cache_data->key, cache_data->key_size, buffer, buffer_size);
217         __close_cached_connection(connection);
218
219         free(cache_data->key);
220         free(buffer);
221
222         return (res == 0 ? NS_SUCCESS : NS_UNAVAIL);
223 }
224
225 int
226 __nss_common_cache_write_negative(void *mdata)
227 {
228         struct cached_connection_params params;
229         cached_connection connection;
230         int res;
231
232         nss_cache_info const *cache_info;
233         nss_cache_data *cache_data;
234
235         cache_data = (nss_cache_data *)mdata;
236         cache_info = cache_data->info;
237
238         if (cache_data->key == NULL)
239                 return (NS_UNAVAIL);
240
241         memset(&params, 0, sizeof(struct cached_connection_params));
242         params.socket_path = CACHED_SOCKET_PATH;
243
244         connection = __open_cached_connection(&params);
245         if (connection == NULL) {
246                 free(cache_data->key);
247                 return (NS_UNAVAIL);
248         }
249
250         res = __cached_write(connection, cache_info->entry_name,
251             cache_data->key, cache_data->key_size, NULL, 0);
252         __close_cached_connection(connection);
253
254         free(cache_data->key);
255         return (res == 0 ? NS_SUCCESS : NS_UNAVAIL);
256 }
257
258 int
259 __nss_mp_cache_read(void *retval, void *mdata, va_list ap)
260 {
261         struct cached_connection_params params;
262         cached_mp_read_session rs;
263
264         char *buffer;
265         size_t buffer_size;
266
267         nss_cache_info const *cache_info;
268         nss_cache_data *cache_data;
269         va_list ap_new;
270         int res;
271
272         cache_data = (nss_cache_data *)mdata;
273         cache_info = cache_data->info;
274
275         if (cache_info->get_mp_ws_func() != INVALID_CACHED_MP_WRITE_SESSION)
276                 return (NS_UNAVAIL);
277
278         rs = cache_info->get_mp_rs_func();
279         if (rs == INVALID_CACHED_MP_READ_SESSION) {
280                 memset(&params, 0, sizeof(struct cached_connection_params));
281                 params.socket_path = CACHED_SOCKET_PATH;
282
283                 rs = __open_cached_mp_read_session(&params,
284                     cache_info->entry_name);
285                 if (rs == INVALID_CACHED_MP_READ_SESSION)
286                         return (NS_UNAVAIL);
287
288                 cache_info->set_mp_rs_func(rs);
289         }
290
291         buffer_size = NSS_CACHE_BUFFER_INITIAL_SIZE;
292         buffer = (char *)malloc(NSS_CACHE_BUFFER_INITIAL_SIZE);
293         memset(buffer, 0, NSS_CACHE_BUFFER_INITIAL_SIZE);
294
295         do {
296                 res = __cached_mp_read(rs, buffer, &buffer_size);
297                 if (res == -2 && buffer_size < NSS_CACHE_BUFFER_SIZE_LIMIT) {
298                         buffer = (char *)realloc(buffer, buffer_size);
299                         memset(buffer, 0, buffer_size);
300                 }
301         } while (res == -2);
302
303         if (res == 0) {
304                 va_copy(ap_new, ap);
305                 res = cache_info->unmarshal_func(buffer, buffer_size, retval,
306                     ap_new, cache_info->mdata);
307                 va_end(ap_new);
308
309                 if (res != NS_SUCCESS) {
310                         free(buffer);
311                         return (res);
312                 } else
313                         res = 0;
314         } else {
315                 free(buffer);
316                 __close_cached_mp_read_session(rs);
317                 rs = INVALID_CACHED_MP_READ_SESSION;
318                 cache_info->set_mp_rs_func(rs);
319                 return (res == -1 ? NS_RETURN : NS_UNAVAIL);
320         }
321
322         free(buffer);
323         return (res == 0 ? NS_SUCCESS : NS_NOTFOUND);
324 }
325
326 int
327 __nss_mp_cache_write(void *retval, void *mdata, va_list ap)
328 {
329         struct cached_connection_params params;
330         cached_mp_write_session ws;
331
332         char *buffer;
333         size_t buffer_size;
334
335         nss_cache_info const *cache_info;
336         nss_cache_data *cache_data;
337         va_list ap_new;
338         int res;
339
340         cache_data = (nss_cache_data *)mdata;
341         cache_info = cache_data->info;
342
343         ws = cache_info->get_mp_ws_func();
344         if (ws == INVALID_CACHED_MP_WRITE_SESSION) {
345                 memset(&params, 0, sizeof(struct cached_connection_params));
346                 params.socket_path = CACHED_SOCKET_PATH;
347
348                 ws = __open_cached_mp_write_session(&params,
349                     cache_info->entry_name);
350                 if (ws == INVALID_CACHED_MP_WRITE_SESSION)
351                         return (NS_UNAVAIL);
352
353                 cache_info->set_mp_ws_func(ws);
354         }
355
356         buffer_size = NSS_CACHE_BUFFER_INITIAL_SIZE;
357         buffer = (char *)malloc(NSS_CACHE_BUFFER_INITIAL_SIZE);
358         memset(buffer, 0, NSS_CACHE_BUFFER_INITIAL_SIZE);
359
360         do {
361                 size_t size;
362
363                 size = buffer_size;
364                 va_copy(ap_new, ap);
365                 res = cache_info->marshal_func(buffer, &size, retval, ap_new,
366                     cache_info->mdata);
367                 va_end(ap_new);
368
369                 if (res == NS_RETURN) {
370                         if (buffer_size > NSS_CACHE_BUFFER_SIZE_LIMIT)
371                                 break;
372
373                         buffer_size <<= 1;
374                         buffer = (char *)realloc(buffer, buffer_size);
375                         memset(buffer, 0, buffer_size);
376                 }
377         } while (res == NS_RETURN);
378
379         if (res != NS_SUCCESS) {
380                 free(buffer);
381                 return (res);
382         }
383
384         res = __cached_mp_write(ws, buffer, buffer_size);
385
386         free(buffer);
387         return (res == 0 ? NS_SUCCESS : NS_UNAVAIL);
388 }
389
390 int
391 __nss_mp_cache_write_submit(void *retval __unused, void *mdata,
392     va_list ap __unused)
393 {
394         cached_mp_write_session ws;
395
396         nss_cache_info const *cache_info;
397         nss_cache_data *cache_data;
398
399         cache_data = (nss_cache_data *)mdata;
400         cache_info = cache_data->info;
401
402         ws = cache_info->get_mp_ws_func();
403         if (ws != INVALID_CACHED_MP_WRITE_SESSION) {
404                 __close_cached_mp_write_session(ws);
405                 ws = INVALID_CACHED_MP_WRITE_SESSION;
406                 cache_info->set_mp_ws_func(ws);
407         }
408         return (NS_UNAVAIL);
409 }
410
411 int
412 __nss_mp_cache_end(void *retval __unused, void *mdata, va_list ap __unused)
413 {
414         cached_mp_write_session ws;
415         cached_mp_read_session rs;
416
417         nss_cache_info const *cache_info;
418         nss_cache_data *cache_data;
419
420         cache_data = (nss_cache_data *)mdata;
421         cache_info = cache_data->info;
422
423         ws = cache_info->get_mp_ws_func();
424         if (ws != INVALID_CACHED_MP_WRITE_SESSION) {
425                 __abandon_cached_mp_write_session(ws);
426                 ws = INVALID_CACHED_MP_WRITE_SESSION;
427                 cache_info->set_mp_ws_func(ws);
428         }
429
430         rs = cache_info->get_mp_rs_func();
431         if (rs != INVALID_CACHED_MP_READ_SESSION) {
432                 __close_cached_mp_read_session(rs);
433                 rs = INVALID_CACHED_MP_READ_SESSION;
434                 cache_info->set_mp_rs_func(rs);
435         }
436
437         return (NS_UNAVAIL);
438 }