]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - lib/libc/net/nscache.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.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  */
27
28 #include <sys/cdefs.h>
29 __FBSDID("$FreeBSD$");
30
31 #include "namespace.h"
32 #include <nsswitch.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include "un-namespace.h"
36 #include "nscachedcli.h"
37 #include "nscache.h"
38
39 #define NSS_CACHE_KEY_INITIAL_SIZE      (256)
40 #define NSS_CACHE_KEY_SIZE_LIMIT        (NSS_CACHE_KEY_INITIAL_SIZE << 4)
41
42 #define NSS_CACHE_BUFFER_INITIAL_SIZE   (1024)
43 #define NSS_CACHE_BUFFER_SIZE_LIMIT     (NSS_CACHE_BUFFER_INITIAL_SIZE << 8)
44
45 #define CACHED_SOCKET_PATH              "/var/run/nscd"
46
47 int
48 __nss_cache_handler(void *retval, void *mdata, va_list ap)
49 {
50         return (NS_UNAVAIL);
51 }
52
53 int
54 __nss_common_cache_read(void *retval, void *mdata, va_list ap)
55 {
56         struct cached_connection_params params;
57         cached_connection connection;
58
59         char *buffer;
60         size_t buffer_size, size;
61
62         nss_cache_info const *cache_info;
63         nss_cache_data *cache_data;
64         va_list ap_new;
65         int res;
66
67         cache_data = (nss_cache_data *)mdata;
68         cache_info = cache_data->info;
69
70         memset(&params, 0, sizeof(struct cached_connection_params));
71         params.socket_path = CACHED_SOCKET_PATH;
72
73         cache_data->key = (char *)malloc(NSS_CACHE_KEY_INITIAL_SIZE);
74         memset(cache_data->key, 0, NSS_CACHE_KEY_INITIAL_SIZE);
75         cache_data->key_size = NSS_CACHE_KEY_INITIAL_SIZE;
76         va_copy(ap_new, ap);
77
78         do {
79                 size = cache_data->key_size;
80                 res = cache_info->id_func(cache_data->key, &size, ap_new,
81                     cache_info->mdata);
82                 va_end(ap_new);
83                 if (res == NS_RETURN) {
84                         if (cache_data->key_size > NSS_CACHE_KEY_SIZE_LIMIT)
85                                 break;
86
87                         cache_data->key_size <<= 1;
88                         cache_data->key = realloc(cache_data->key,
89                             cache_data->key_size);
90                         memset(cache_data->key, 0, cache_data->key_size);
91                         va_copy(ap_new, ap);
92                 }
93         } while (res == NS_RETURN);
94
95         if (res != NS_SUCCESS) {
96                 free(cache_data->key);
97                 cache_data->key = NULL;
98                 cache_data->key_size = 0;
99                 return (res);
100         } else
101                 cache_data->key_size = size;
102
103         buffer_size = NSS_CACHE_BUFFER_INITIAL_SIZE;
104         buffer = (char *)malloc(NSS_CACHE_BUFFER_INITIAL_SIZE);
105         memset(buffer, 0, NSS_CACHE_BUFFER_INITIAL_SIZE);
106
107         do {
108                 connection = __open_cached_connection(&params);
109                 if (connection == NULL) {
110                         res = -1;
111                         break;
112                 }
113                 res = __cached_read(connection, cache_info->entry_name,
114                     cache_data->key, cache_data->key_size, buffer,
115                     &buffer_size);
116                 __close_cached_connection(connection);
117                 if (res == -2 && buffer_size < NSS_CACHE_BUFFER_SIZE_LIMIT) {
118                         buffer = (char *)realloc(buffer, buffer_size);
119                         memset(buffer, 0, buffer_size);
120                 }
121         } while (res == -2);
122
123         if (res == 0) {
124                 if (buffer_size == 0) {
125                         free(buffer);
126                         free(cache_data->key);
127                         cache_data->key = NULL;
128                         cache_data->key_size = 0;
129                         return (NS_RETURN);
130                 }
131
132                 va_copy(ap_new, ap);
133                 res = cache_info->unmarshal_func(buffer, buffer_size, retval,
134                     ap_new, cache_info->mdata);
135                 va_end(ap_new);
136
137                 if (res != NS_SUCCESS) {
138                         free(buffer);
139                         free(cache_data->key);
140                         cache_data->key = NULL;
141                         cache_data->key_size = 0;
142                         return (res);
143                 } else
144                         res = 0;
145         }
146
147         if (res == 0) {
148                 free(cache_data->key);
149                 cache_data->key = NULL;
150                 cache_data->key_size = 0;
151         }
152
153         free(buffer);
154         return (res == 0 ? NS_SUCCESS : NS_NOTFOUND);
155 }
156
157 int
158 __nss_common_cache_write(void *retval, void *mdata, va_list ap)
159 {
160         struct cached_connection_params params;
161         cached_connection connection;
162
163         char *buffer;
164         size_t buffer_size;
165
166         nss_cache_info const *cache_info;
167         nss_cache_data *cache_data;
168         va_list ap_new;
169         int res;
170
171         cache_data = (nss_cache_data *)mdata;
172         cache_info = cache_data->info;
173
174         if (cache_data->key == NULL)
175                 return (NS_UNAVAIL);
176
177         memset(&params, 0, sizeof(struct cached_connection_params));
178         params.socket_path = CACHED_SOCKET_PATH;
179
180         connection = __open_cached_connection(&params);
181         if (connection == NULL) {
182                 free(cache_data->key);
183                 return (NS_UNAVAIL);
184         }
185
186         buffer_size = NSS_CACHE_BUFFER_INITIAL_SIZE;
187         buffer = (char *)malloc(NSS_CACHE_BUFFER_INITIAL_SIZE);
188         memset(buffer, 0, NSS_CACHE_BUFFER_INITIAL_SIZE);
189
190         do {
191                 size_t size;
192
193                 size = buffer_size;
194                 va_copy(ap_new, ap);
195                 res = cache_info->marshal_func(buffer, &size, retval, ap_new,
196                     cache_info->mdata);
197                 va_end(ap_new);
198
199                 if (res == NS_RETURN) {
200                         if (buffer_size > NSS_CACHE_BUFFER_SIZE_LIMIT)
201                                 break;
202
203                         buffer_size <<= 1;
204                         buffer = (char *)realloc(buffer, buffer_size);
205                         memset(buffer, 0, buffer_size);
206                 }
207         } while (res == NS_RETURN);
208
209         if (res != NS_SUCCESS) {
210                 __close_cached_connection(connection);
211                 free(cache_data->key);
212                 free(buffer);
213                 return (res);
214         }
215
216         res = __cached_write(connection, cache_info->entry_name,
217             cache_data->key, cache_data->key_size, buffer, buffer_size);
218         __close_cached_connection(connection);
219
220         free(cache_data->key);
221         free(buffer);
222
223         return (res == 0 ? NS_SUCCESS : NS_UNAVAIL);
224 }
225
226 int
227 __nss_common_cache_write_negative(void *mdata)
228 {
229         struct cached_connection_params params;
230         cached_connection connection;
231         int res;
232
233         nss_cache_info const *cache_info;
234         nss_cache_data *cache_data;
235
236         cache_data = (nss_cache_data *)mdata;
237         cache_info = cache_data->info;
238
239         if (cache_data->key == NULL)
240                 return (NS_UNAVAIL);
241
242         memset(&params, 0, sizeof(struct cached_connection_params));
243         params.socket_path = CACHED_SOCKET_PATH;
244
245         connection = __open_cached_connection(&params);
246         if (connection == NULL) {
247                 free(cache_data->key);
248                 return (NS_UNAVAIL);
249         }
250
251         res = __cached_write(connection, cache_info->entry_name,
252             cache_data->key, cache_data->key_size, NULL, 0);
253         __close_cached_connection(connection);
254
255         free(cache_data->key);
256         return (res == 0 ? NS_SUCCESS : NS_UNAVAIL);
257 }
258
259 int
260 __nss_mp_cache_read(void *retval, void *mdata, va_list ap)
261 {
262         struct cached_connection_params params;
263         cached_mp_read_session rs;
264
265         char *buffer;
266         size_t buffer_size;
267
268         nss_cache_info const *cache_info;
269         nss_cache_data *cache_data;
270         va_list ap_new;
271         int res;
272
273         cache_data = (nss_cache_data *)mdata;
274         cache_info = cache_data->info;
275
276         if (cache_info->get_mp_ws_func() != INVALID_CACHED_MP_WRITE_SESSION)
277                 return (NS_UNAVAIL);
278
279         rs = cache_info->get_mp_rs_func();
280         if (rs == INVALID_CACHED_MP_READ_SESSION) {
281                 memset(&params, 0, sizeof(struct cached_connection_params));
282                 params.socket_path = CACHED_SOCKET_PATH;
283
284                 rs = __open_cached_mp_read_session(&params,
285                     cache_info->entry_name);
286                 if (rs == INVALID_CACHED_MP_READ_SESSION)
287                         return (NS_UNAVAIL);
288
289                 cache_info->set_mp_rs_func(rs);
290         }
291
292         buffer_size = NSS_CACHE_BUFFER_INITIAL_SIZE;
293         buffer = (char *)malloc(NSS_CACHE_BUFFER_INITIAL_SIZE);
294         memset(buffer, 0, NSS_CACHE_BUFFER_INITIAL_SIZE);
295
296         do {
297                 res = __cached_mp_read(rs, buffer, &buffer_size);
298                 if (res == -2 && buffer_size < NSS_CACHE_BUFFER_SIZE_LIMIT) {
299                         buffer = (char *)realloc(buffer, buffer_size);
300                         memset(buffer, 0, buffer_size);
301                 }
302         } while (res == -2);
303
304         if (res == 0) {
305                 va_copy(ap_new, ap);
306                 res = cache_info->unmarshal_func(buffer, buffer_size, retval,
307                     ap_new, cache_info->mdata);
308                 va_end(ap_new);
309
310                 if (res != NS_SUCCESS) {
311                         free(buffer);
312                         return (res);
313                 } else
314                         res = 0;
315         } else {
316                 free(buffer);
317                 __close_cached_mp_read_session(rs);
318                 rs = INVALID_CACHED_MP_READ_SESSION;
319                 cache_info->set_mp_rs_func(rs);
320                 return (res == -1 ? NS_RETURN : NS_UNAVAIL);
321         }
322
323         free(buffer);
324         return (res == 0 ? NS_SUCCESS : NS_NOTFOUND);
325 }
326
327 int
328 __nss_mp_cache_write(void *retval, void *mdata, va_list ap)
329 {
330         struct cached_connection_params params;
331         cached_mp_write_session ws;
332
333         char *buffer;
334         size_t buffer_size;
335
336         nss_cache_info const *cache_info;
337         nss_cache_data *cache_data;
338         va_list ap_new;
339         int res;
340
341         cache_data = (nss_cache_data *)mdata;
342         cache_info = cache_data->info;
343
344         ws = cache_info->get_mp_ws_func();
345         if (ws == INVALID_CACHED_MP_WRITE_SESSION) {
346                 memset(&params, 0, sizeof(struct cached_connection_params));
347                 params.socket_path = CACHED_SOCKET_PATH;
348
349                 ws = __open_cached_mp_write_session(&params,
350                     cache_info->entry_name);
351                 if (ws == INVALID_CACHED_MP_WRITE_SESSION)
352                         return (NS_UNAVAIL);
353
354                 cache_info->set_mp_ws_func(ws);
355         }
356
357         buffer_size = NSS_CACHE_BUFFER_INITIAL_SIZE;
358         buffer = (char *)malloc(NSS_CACHE_BUFFER_INITIAL_SIZE);
359         memset(buffer, 0, NSS_CACHE_BUFFER_INITIAL_SIZE);
360
361         do {
362                 size_t size;
363
364                 size = buffer_size;
365                 va_copy(ap_new, ap);
366                 res = cache_info->marshal_func(buffer, &size, retval, ap_new,
367                     cache_info->mdata);
368                 va_end(ap_new);
369
370                 if (res == NS_RETURN) {
371                         if (buffer_size > NSS_CACHE_BUFFER_SIZE_LIMIT)
372                                 break;
373
374                         buffer_size <<= 1;
375                         buffer = (char *)realloc(buffer, buffer_size);
376                         memset(buffer, 0, buffer_size);
377                 }
378         } while (res == NS_RETURN);
379
380         if (res != NS_SUCCESS) {
381                 free(buffer);
382                 return (res);
383         }
384
385         res = __cached_mp_write(ws, buffer, buffer_size);
386
387         free(buffer);
388         return (res == 0 ? NS_SUCCESS : NS_UNAVAIL);
389 }
390
391 int
392 __nss_mp_cache_write_submit(void *retval, void *mdata, va_list ap)
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, void *mdata, va_list ap)
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 }