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