xref: /dragonfly/lib/libc/net/nscache.c (revision cfd1aba3)
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 }
439