1158115Sume/*-
2158115Sume * Copyright (c) 2005 Michael Bushkov <bushman@rsu.ru>
3158115Sume * All rights reserved.
4158115Sume *
5158115Sume * Redistribution and use in source and binary forms, with or without
6158115Sume * modification, are permitted provided that the following conditions
7158115Sume * are met:
8158115Sume * 1. Redistributions of source code must retain the above copyright
9158115Sume *    notice, this list of conditions and the following disclaimer.
10158115Sume * 2. Redistributions in binary form must reproduce the above copyright
11158115Sume *    notice, this list of conditions and the following disclaimer in the
12158115Sume *    documentation and/or other materials provided with the distribution.
13158115Sume *
14158115Sume * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15158115Sume * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16158115Sume * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17158115Sume * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18158115Sume * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19158115Sume * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20158115Sume * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21158115Sume * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22158115Sume * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23158115Sume * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24158115Sume * SUCH DAMAGE.
25158115Sume *
26158115Sume */
27158115Sume
28158115Sume#include <sys/cdefs.h>
29158115Sume__FBSDID("$FreeBSD$");
30158115Sume
31158115Sume#include "namespace.h"
32288013Srodrigc#define _NS_PRIVATE
33158115Sume#include <nsswitch.h>
34158115Sume#include <stdlib.h>
35158115Sume#include <string.h>
36158115Sume#include "un-namespace.h"
37158115Sume#include "nscachedcli.h"
38158115Sume#include "nscache.h"
39158115Sume
40158115Sume#define NSS_CACHE_KEY_INITIAL_SIZE	(256)
41158115Sume#define NSS_CACHE_KEY_SIZE_LIMIT	(NSS_CACHE_KEY_INITIAL_SIZE << 4)
42158115Sume
43158115Sume#define NSS_CACHE_BUFFER_INITIAL_SIZE	(1024)
44158115Sume#define NSS_CACHE_BUFFER_SIZE_LIMIT	(NSS_CACHE_BUFFER_INITIAL_SIZE << 8)
45158115Sume
46172730Stmclaugh#define CACHED_SOCKET_PATH 		"/var/run/nscd"
47158115Sume
48158115Sumeint
49158115Sume__nss_cache_handler(void *retval, void *mdata, va_list ap)
50158115Sume{
51158115Sume	return (NS_UNAVAIL);
52158115Sume}
53158115Sume
54158115Sumeint
55158115Sume__nss_common_cache_read(void *retval, void *mdata, va_list ap)
56158115Sume{
57158115Sume	struct cached_connection_params params;
58158115Sume	cached_connection connection;
59158115Sume
60158115Sume	char *buffer;
61158115Sume	size_t buffer_size, size;
62158115Sume
63158115Sume	nss_cache_info const *cache_info;
64158115Sume	nss_cache_data *cache_data;
65158115Sume	va_list ap_new;
66158115Sume	int res;
67158115Sume
68158115Sume	cache_data = (nss_cache_data *)mdata;
69158115Sume	cache_info = cache_data->info;
70158115Sume
71158115Sume	memset(&params, 0, sizeof(struct cached_connection_params));
72158115Sume	params.socket_path = CACHED_SOCKET_PATH;
73158115Sume
74158115Sume	cache_data->key = (char *)malloc(NSS_CACHE_KEY_INITIAL_SIZE);
75158115Sume	memset(cache_data->key, 0, NSS_CACHE_KEY_INITIAL_SIZE);
76158115Sume	cache_data->key_size = NSS_CACHE_KEY_INITIAL_SIZE;
77158115Sume	va_copy(ap_new, ap);
78158115Sume
79158115Sume	do {
80158115Sume		size = cache_data->key_size;
81158115Sume		res = cache_info->id_func(cache_data->key, &size, ap_new,
82158115Sume		    cache_info->mdata);
83158115Sume		va_end(ap_new);
84158115Sume		if (res == NS_RETURN) {
85158115Sume			if (cache_data->key_size > NSS_CACHE_KEY_SIZE_LIMIT)
86158115Sume				break;
87158115Sume
88158115Sume			cache_data->key_size <<= 1;
89158115Sume			cache_data->key = realloc(cache_data->key,
90158115Sume			    cache_data->key_size);
91158115Sume			memset(cache_data->key, 0, cache_data->key_size);
92158115Sume			va_copy(ap_new, ap);
93158115Sume		}
94158115Sume	} while (res == NS_RETURN);
95158115Sume
96158115Sume	if (res != NS_SUCCESS) {
97158115Sume		free(cache_data->key);
98158115Sume		cache_data->key = NULL;
99158115Sume		cache_data->key_size = 0;
100158115Sume		return (res);
101158115Sume	} else
102158115Sume		cache_data->key_size = size;
103158115Sume
104158115Sume	buffer_size = NSS_CACHE_BUFFER_INITIAL_SIZE;
105158115Sume	buffer = (char *)malloc(NSS_CACHE_BUFFER_INITIAL_SIZE);
106158115Sume	memset(buffer, 0, NSS_CACHE_BUFFER_INITIAL_SIZE);
107158115Sume
108158115Sume	do {
109158115Sume		connection = __open_cached_connection(&params);
110158115Sume		if (connection == NULL) {
111158115Sume			res = -1;
112158115Sume			break;
113158115Sume		}
114158115Sume		res = __cached_read(connection, cache_info->entry_name,
115158115Sume		    cache_data->key, cache_data->key_size, buffer,
116158115Sume		    &buffer_size);
117158115Sume		__close_cached_connection(connection);
118158115Sume		if (res == -2 && buffer_size < NSS_CACHE_BUFFER_SIZE_LIMIT) {
119158115Sume			buffer = (char *)realloc(buffer, buffer_size);
120158115Sume			memset(buffer, 0, buffer_size);
121158115Sume		}
122158115Sume	} while (res == -2);
123158115Sume
124158115Sume	if (res == 0) {
125158115Sume		if (buffer_size == 0) {
126158115Sume			free(buffer);
127158115Sume			free(cache_data->key);
128158115Sume			cache_data->key = NULL;
129158115Sume			cache_data->key_size = 0;
130158115Sume			return (NS_RETURN);
131158115Sume		}
132158115Sume
133158115Sume		va_copy(ap_new, ap);
134158115Sume		res = cache_info->unmarshal_func(buffer, buffer_size, retval,
135158115Sume		    ap_new, cache_info->mdata);
136158115Sume		va_end(ap_new);
137158115Sume
138158115Sume		if (res != NS_SUCCESS) {
139158115Sume			free(buffer);
140158115Sume			free(cache_data->key);
141158115Sume			cache_data->key = NULL;
142158115Sume			cache_data->key_size = 0;
143158115Sume			return (res);
144158115Sume		} else
145158115Sume			res = 0;
146158115Sume	}
147158115Sume
148158115Sume	if (res == 0) {
149158115Sume		free(cache_data->key);
150158115Sume		cache_data->key = NULL;
151158115Sume		cache_data->key_size = 0;
152158115Sume	}
153158115Sume
154158115Sume	free(buffer);
155158115Sume	return (res == 0 ? NS_SUCCESS : NS_NOTFOUND);
156158115Sume}
157158115Sume
158158115Sumeint
159158115Sume__nss_common_cache_write(void *retval, void *mdata, va_list ap)
160158115Sume{
161158115Sume	struct cached_connection_params params;
162158115Sume	cached_connection connection;
163158115Sume
164158115Sume	char *buffer;
165158115Sume	size_t buffer_size;
166158115Sume
167158115Sume	nss_cache_info const *cache_info;
168158115Sume	nss_cache_data *cache_data;
169158115Sume	va_list ap_new;
170158115Sume	int res;
171158115Sume
172158115Sume	cache_data = (nss_cache_data *)mdata;
173158115Sume	cache_info = cache_data->info;
174158115Sume
175158115Sume	if (cache_data->key == NULL)
176158115Sume		return (NS_UNAVAIL);
177158115Sume
178158115Sume	memset(&params, 0, sizeof(struct cached_connection_params));
179158115Sume	params.socket_path = CACHED_SOCKET_PATH;
180158115Sume
181158115Sume	connection = __open_cached_connection(&params);
182158115Sume	if (connection == NULL) {
183158115Sume		free(cache_data->key);
184158115Sume		return (NS_UNAVAIL);
185158115Sume	}
186158115Sume
187158115Sume	buffer_size = NSS_CACHE_BUFFER_INITIAL_SIZE;
188158115Sume	buffer = (char *)malloc(NSS_CACHE_BUFFER_INITIAL_SIZE);
189158115Sume	memset(buffer, 0, NSS_CACHE_BUFFER_INITIAL_SIZE);
190158115Sume
191158115Sume	do {
192158115Sume		size_t size;
193158115Sume
194158115Sume		size = buffer_size;
195158115Sume		va_copy(ap_new, ap);
196158115Sume		res = cache_info->marshal_func(buffer, &size, retval, ap_new,
197158115Sume		    cache_info->mdata);
198158115Sume		va_end(ap_new);
199158115Sume
200158115Sume		if (res == NS_RETURN) {
201158115Sume			if (buffer_size > NSS_CACHE_BUFFER_SIZE_LIMIT)
202158115Sume				break;
203158115Sume
204158115Sume			buffer_size <<= 1;
205158115Sume			buffer = (char *)realloc(buffer, buffer_size);
206158115Sume			memset(buffer, 0, buffer_size);
207158115Sume		}
208158115Sume	} while (res == NS_RETURN);
209158115Sume
210158115Sume	if (res != NS_SUCCESS) {
211158115Sume		__close_cached_connection(connection);
212158115Sume		free(cache_data->key);
213158115Sume		free(buffer);
214158115Sume		return (res);
215158115Sume	}
216158115Sume
217158115Sume	res = __cached_write(connection, cache_info->entry_name,
218158115Sume	    cache_data->key, cache_data->key_size, buffer, buffer_size);
219158115Sume	__close_cached_connection(connection);
220158115Sume
221158115Sume	free(cache_data->key);
222158115Sume	free(buffer);
223158115Sume
224158115Sume	return (res == 0 ? NS_SUCCESS : NS_UNAVAIL);
225158115Sume}
226158115Sume
227158115Sumeint
228158115Sume__nss_common_cache_write_negative(void *mdata)
229158115Sume{
230158115Sume	struct cached_connection_params params;
231158115Sume	cached_connection connection;
232158115Sume	int res;
233158115Sume
234158115Sume	nss_cache_info const *cache_info;
235158115Sume	nss_cache_data *cache_data;
236158115Sume
237158115Sume	cache_data = (nss_cache_data *)mdata;
238158115Sume	cache_info = cache_data->info;
239158115Sume
240158115Sume	if (cache_data->key == NULL)
241158115Sume		return (NS_UNAVAIL);
242158115Sume
243158115Sume	memset(&params, 0, sizeof(struct cached_connection_params));
244158115Sume	params.socket_path = CACHED_SOCKET_PATH;
245158115Sume
246158115Sume	connection = __open_cached_connection(&params);
247158115Sume	if (connection == NULL) {
248158115Sume		free(cache_data->key);
249158115Sume		return (NS_UNAVAIL);
250158115Sume	}
251158115Sume
252158115Sume	res = __cached_write(connection, cache_info->entry_name,
253158115Sume	    cache_data->key, cache_data->key_size, NULL, 0);
254158115Sume	__close_cached_connection(connection);
255158115Sume
256158115Sume	free(cache_data->key);
257158115Sume	return (res == 0 ? NS_SUCCESS : NS_UNAVAIL);
258158115Sume}
259158115Sume
260158115Sumeint
261158115Sume__nss_mp_cache_read(void *retval, void *mdata, va_list ap)
262158115Sume{
263158115Sume	struct cached_connection_params params;
264158115Sume	cached_mp_read_session rs;
265158115Sume
266158115Sume	char *buffer;
267158115Sume	size_t buffer_size;
268158115Sume
269158115Sume	nss_cache_info const *cache_info;
270158115Sume	nss_cache_data *cache_data;
271158115Sume	va_list ap_new;
272158115Sume	int res;
273158115Sume
274158115Sume	cache_data = (nss_cache_data *)mdata;
275158115Sume	cache_info = cache_data->info;
276158115Sume
277158115Sume	if (cache_info->get_mp_ws_func() != INVALID_CACHED_MP_WRITE_SESSION)
278158115Sume		return (NS_UNAVAIL);
279158115Sume
280158115Sume	rs = cache_info->get_mp_rs_func();
281158115Sume	if (rs == INVALID_CACHED_MP_READ_SESSION) {
282158115Sume		memset(&params, 0, sizeof(struct cached_connection_params));
283158115Sume		params.socket_path = CACHED_SOCKET_PATH;
284158115Sume
285158115Sume		rs = __open_cached_mp_read_session(&params,
286158115Sume		    cache_info->entry_name);
287158115Sume		if (rs == INVALID_CACHED_MP_READ_SESSION)
288158115Sume			return (NS_UNAVAIL);
289158115Sume
290158115Sume		cache_info->set_mp_rs_func(rs);
291158115Sume	}
292158115Sume
293158115Sume	buffer_size = NSS_CACHE_BUFFER_INITIAL_SIZE;
294158115Sume	buffer = (char *)malloc(NSS_CACHE_BUFFER_INITIAL_SIZE);
295158115Sume	memset(buffer, 0, NSS_CACHE_BUFFER_INITIAL_SIZE);
296158115Sume
297158115Sume	do {
298158115Sume		res = __cached_mp_read(rs, buffer, &buffer_size);
299158115Sume		if (res == -2 && buffer_size < NSS_CACHE_BUFFER_SIZE_LIMIT) {
300158115Sume			buffer = (char *)realloc(buffer, buffer_size);
301158115Sume			memset(buffer, 0, buffer_size);
302158115Sume		}
303158115Sume	} while (res == -2);
304158115Sume
305158115Sume	if (res == 0) {
306158115Sume		va_copy(ap_new, ap);
307158115Sume		res = cache_info->unmarshal_func(buffer, buffer_size, retval,
308158115Sume		    ap_new, cache_info->mdata);
309158115Sume		va_end(ap_new);
310158115Sume
311158115Sume		if (res != NS_SUCCESS) {
312158115Sume			free(buffer);
313158115Sume			return (res);
314158115Sume		} else
315158115Sume			res = 0;
316158115Sume	} else {
317158115Sume		free(buffer);
318158115Sume		__close_cached_mp_read_session(rs);
319158115Sume		rs = INVALID_CACHED_MP_READ_SESSION;
320158115Sume		cache_info->set_mp_rs_func(rs);
321158115Sume		return (res == -1 ? NS_RETURN : NS_UNAVAIL);
322158115Sume	}
323158115Sume
324158115Sume	free(buffer);
325158115Sume	return (res == 0 ? NS_SUCCESS : NS_NOTFOUND);
326158115Sume}
327158115Sume
328158115Sumeint
329158115Sume__nss_mp_cache_write(void *retval, void *mdata, va_list ap)
330158115Sume{
331158115Sume	struct cached_connection_params params;
332158115Sume	cached_mp_write_session ws;
333158115Sume
334158115Sume	char *buffer;
335158115Sume	size_t buffer_size;
336158115Sume
337158115Sume	nss_cache_info const *cache_info;
338158115Sume	nss_cache_data *cache_data;
339158115Sume	va_list ap_new;
340158115Sume	int res;
341158115Sume
342158115Sume	cache_data = (nss_cache_data *)mdata;
343158115Sume	cache_info = cache_data->info;
344158115Sume
345158115Sume	ws = cache_info->get_mp_ws_func();
346158115Sume	if (ws == INVALID_CACHED_MP_WRITE_SESSION) {
347158115Sume		memset(&params, 0, sizeof(struct cached_connection_params));
348158115Sume		params.socket_path = CACHED_SOCKET_PATH;
349158115Sume
350158115Sume		ws = __open_cached_mp_write_session(&params,
351158115Sume		    cache_info->entry_name);
352158115Sume		if (ws == INVALID_CACHED_MP_WRITE_SESSION)
353158115Sume			return (NS_UNAVAIL);
354158115Sume
355158115Sume		cache_info->set_mp_ws_func(ws);
356158115Sume	}
357158115Sume
358158115Sume	buffer_size = NSS_CACHE_BUFFER_INITIAL_SIZE;
359158115Sume	buffer = (char *)malloc(NSS_CACHE_BUFFER_INITIAL_SIZE);
360158115Sume	memset(buffer, 0, NSS_CACHE_BUFFER_INITIAL_SIZE);
361158115Sume
362158115Sume	do {
363158115Sume		size_t size;
364158115Sume
365158115Sume		size = buffer_size;
366158115Sume		va_copy(ap_new, ap);
367158115Sume		res = cache_info->marshal_func(buffer, &size, retval, ap_new,
368158115Sume		    cache_info->mdata);
369158115Sume		va_end(ap_new);
370158115Sume
371158115Sume		if (res == NS_RETURN) {
372158115Sume			if (buffer_size > NSS_CACHE_BUFFER_SIZE_LIMIT)
373158115Sume				break;
374158115Sume
375158115Sume			buffer_size <<= 1;
376158115Sume			buffer = (char *)realloc(buffer, buffer_size);
377158115Sume			memset(buffer, 0, buffer_size);
378158115Sume		}
379158115Sume	} while (res == NS_RETURN);
380158115Sume
381158115Sume	if (res != NS_SUCCESS) {
382158115Sume		free(buffer);
383158115Sume		return (res);
384158115Sume	}
385158115Sume
386158115Sume	res = __cached_mp_write(ws, buffer, buffer_size);
387158115Sume
388158115Sume	free(buffer);
389158115Sume	return (res == 0 ? NS_SUCCESS : NS_UNAVAIL);
390158115Sume}
391158115Sume
392158115Sumeint
393158115Sume__nss_mp_cache_write_submit(void *retval, void *mdata, va_list ap)
394158115Sume{
395158115Sume	cached_mp_write_session ws;
396158115Sume
397158115Sume	nss_cache_info const *cache_info;
398158115Sume	nss_cache_data *cache_data;
399158115Sume
400158115Sume	cache_data = (nss_cache_data *)mdata;
401158115Sume	cache_info = cache_data->info;
402158115Sume
403158115Sume	ws = cache_info->get_mp_ws_func();
404158115Sume	if (ws != INVALID_CACHED_MP_WRITE_SESSION) {
405158115Sume		__close_cached_mp_write_session(ws);
406158115Sume		ws = INVALID_CACHED_MP_WRITE_SESSION;
407158115Sume		cache_info->set_mp_ws_func(ws);
408158115Sume	}
409158115Sume	return (NS_UNAVAIL);
410158115Sume}
411158115Sume
412158115Sumeint
413158115Sume__nss_mp_cache_end(void *retval, void *mdata, va_list ap)
414158115Sume{
415158115Sume	cached_mp_write_session ws;
416158115Sume	cached_mp_read_session rs;
417158115Sume
418158115Sume	nss_cache_info const *cache_info;
419158115Sume	nss_cache_data *cache_data;
420158115Sume
421158115Sume	cache_data = (nss_cache_data *)mdata;
422158115Sume	cache_info = cache_data->info;
423158115Sume
424158115Sume	ws = cache_info->get_mp_ws_func();
425158115Sume	if (ws != INVALID_CACHED_MP_WRITE_SESSION) {
426158115Sume		__abandon_cached_mp_write_session(ws);
427158115Sume		ws = INVALID_CACHED_MP_WRITE_SESSION;
428158115Sume		cache_info->set_mp_ws_func(ws);
429158115Sume	}
430158115Sume
431158115Sume	rs = cache_info->get_mp_rs_func();
432158115Sume	if (rs != INVALID_CACHED_MP_READ_SESSION) {
433158115Sume		__close_cached_mp_read_session(rs);
434158115Sume		rs = INVALID_CACHED_MP_READ_SESSION;
435158115Sume		cache_info->set_mp_rs_func(rs);
436158115Sume	}
437158115Sume
438158115Sume	return (NS_UNAVAIL);
439158115Sume}
440