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