nscd_door.c revision 2830:5228d1267a01
1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22/*
23 * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
24 * Use is subject to license terms.
25 */
26
27#pragma ident	"%Z%%M%	%I%	%E% SMI"
28
29#include <sys/param.h>
30#include <string.h>
31#include <door.h>
32#include <sys/mman.h>
33#include "nscd_door.h"
34#include "nscd_log.h"
35#include <getxby_door.h>
36#include <sys/types.h>
37#include <errno.h>
38#include <fcntl.h>
39
40static void
41initdoor(void *buf, int *doorfd)
42{
43	nss_pheader_t	*phdr = (nss_pheader_t *)buf;
44	door_info_t 	doori;
45	char		*me = "initdoor";
46
47	*doorfd = open64(NAME_SERVICE_DOOR, O_RDONLY, 0);
48
49	_NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG)
50		(me, "door is %s (fd is %d)\n", NAME_SERVICE_DOOR,
51		*doorfd);
52
53	if (*doorfd == -1)
54		NSCD_RETURN_STATUS(phdr, NSS_ERROR, errno);
55
56	if (door_info(*doorfd, &doori) < 0 ||
57		(doori.di_attributes & DOOR_REVOKED) ||
58		doori.di_data != (uintptr_t)NAME_SERVICE_DOOR_COOKIE) {
59
60		/*
61		 * we should close doorfd because we just opened it
62		 */
63		(void) close(*doorfd);
64
65		_NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG)
66		(me, "door %d not valid\n", *doorfd);
67
68		NSCD_RETURN_STATUS(phdr, NSS_ERROR, ECONNREFUSED);
69	}
70
71	NSCD_RETURN_STATUS_SUCCESS(phdr);
72}
73
74/* general door call functions used by nscd */
75
76static nss_status_t
77copy_output(void *outdata, int outdlen,
78	nss_pheader_t *phdr, nss_pheader_t *outphdr)
79{
80	void		*dp;
81	nss_status_t	ret = NSS_SUCCESS;
82	char		*me = "copy_output";
83
84	if (outdata != NULL && phdr->data_off > 0 && phdr->data_len > 0) {
85		if (phdr->data_len <= outdlen) {
86			dp = (char *)phdr + phdr->data_off;
87			(void) memmove(outdata, dp, phdr->data_len);
88		} else {
89
90			_NSCD_LOG(NSCD_LOG_FRONT_END,
91				NSCD_LOG_LEVEL_DEBUG)
92			(me, "output buffer not large enough "
93			" should be > %d but is %d\n",
94			phdr->data_len, outdlen);
95
96			if (outphdr != NULL) {
97				NSCD_SET_N2N_STATUS(phdr, NSS_NSCD_PRIV,
98				0, NSCD_INVALID_ARGUMENT);
99				NSCD_COPY_STATUS(outphdr, phdr);
100			}
101			ret = NSS_NSCD_PRIV;
102		}
103	}
104
105	return (ret);
106}
107
108
109nss_status_t
110_nscd_doorcall(int callnum)
111{
112	nss_pheader_t	phdr;
113	void		*dptr;
114	size_t		ndata;
115	size_t		adata;
116	int		ret;
117	char		*me = "_nscd_doorcall";
118
119	_NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG)
120	(me, "processing door call %d ...\n", callnum);
121
122	phdr.nsc_callnumber = callnum;
123	ndata = sizeof (phdr);
124	adata = sizeof (phdr);
125	dptr = (void *)&phdr;
126	ret = _nsc_trydoorcall(&dptr, &ndata, &adata);
127
128	if (ret != NSS_SUCCESS) {
129		_NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG)
130		(me, "door call (%d) failed (status = %d, error = %s)\n",
131			callnum, ret, strerror(NSCD_GET_ERRNO(&phdr)));
132	}
133
134	return (ret);
135}
136
137nss_status_t
138_nscd_doorcall_data(int callnum, void *indata, int indlen,
139	void *outdata, int outdlen, nss_pheader_t *phdr)
140{
141	void		*uptr;
142	size_t		buflen;
143	void		*dptr;
144	void		*datap;
145	size_t		ndata;
146	size_t		adata;
147	nss_pheader_t	*phdr_d;
148	int		ret;
149	char		*me = "_nscd_doorcall_data";
150
151	_NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG)
152	(me, "processing door call %d ...\n", callnum);
153
154	/* allocate door buffer from the stack */
155	NSCD_ALLOC_DOORBUF(callnum, indlen, uptr, buflen);
156	dptr = uptr;
157	ndata = buflen;
158	adata = buflen;
159	datap = NSCD_N2N_DOOR_DATA(void, dptr);
160	if (indata != NULL)
161		(void) memmove(datap, indata, indlen);
162
163	ret = _nsc_trydoorcall(&dptr, &ndata, &adata);
164
165	phdr_d = (nss_pheader_t *)dptr;
166	if (ret != NSS_SUCCESS) {
167		_NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG)
168		(me, "door call (%d) failed (status = %d, error = %s)\n",
169			callnum, ret, strerror(NSCD_GET_ERRNO(phdr_d)));
170	} else {
171		if (phdr != NULL) {
172			NSCD_COPY_STATUS(phdr, phdr_d);
173		}
174		ret = copy_output(outdata, outdlen, phdr_d, phdr);
175	}
176
177	/* if new buffer allocated for this door call, free it */
178	if (dptr != uptr)
179		(void) munmap(dptr, ndata);
180
181	return (ret);
182}
183
184nss_status_t
185_nscd_doorcall_fd(int fd, int callnum, void *indata, int indlen,
186	void *outdata, int outdlen, nss_pheader_t *phdr)
187{
188	void		*uptr;
189	void		*dptr;
190	void		*datap;
191	size_t		ndata;
192	size_t		adata;
193	size_t		buflen;
194	door_arg_t	param;
195	int		ret, errnum;
196	nss_pheader_t	*phdr_d;
197	char		*me = "_nscd_doorcall_fd";
198
199	_NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG)
200	(me, "processing door call %d (fd = %d)...\n", callnum, fd);
201
202	/* allocate door buffer from the stack */
203	NSCD_ALLOC_DOORBUF(callnum, indlen, uptr, buflen);
204	dptr = uptr;
205	ndata = buflen;
206	adata = buflen;
207	datap = NSCD_N2N_DOOR_DATA(void, dptr);
208	if (indata != NULL)
209		(void) memmove(datap, indata, indlen);
210
211	param.rbuf = (char *)dptr;
212	param.rsize = ndata;
213	param.data_ptr = (char *)dptr;
214	param.data_size = adata;
215	param.desc_ptr = NULL;
216	param.desc_num = 0;
217	ret = door_call(fd, &param);
218	if (ret < 0) {
219		errnum = errno;
220		/*
221		 * door call did not get through, return errno
222		 * if requested
223		 */
224		if (phdr != NULL) {
225			NSCD_SET_STATUS(phdr, NSS_ERROR, errnum);
226		}
227
228		_NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG)
229		(me, "door call (%d to %d) did not get through (%s)\n",
230			callnum, fd, strerror(errnum));
231
232		return (NSS_ERROR);
233	}
234	ndata = param.rsize;
235	dptr = (void *)param.data_ptr;
236
237	/*
238	 * door call got through, check if operation failed.
239	 * if so, return error info if requested
240	 */
241	phdr_d = (nss_pheader_t *)dptr;
242	ret = NSCD_GET_STATUS(phdr_d);
243	if (ret != NSS_SUCCESS) {
244		if (phdr != NULL) {
245			NSCD_COPY_STATUS(phdr, phdr_d);
246		}
247
248		_NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG)
249		(me, "door call (%d to %d) failed: p_status = %d, "
250		"p_errno = %s, nscd status = %d\n", callnum, fd,
251		ret, strerror(NSCD_GET_ERRNO(phdr_d)),
252		NSCD_GET_NSCD_STATUS(phdr_d));
253	} else
254		ret = copy_output(outdata, outdlen, phdr_d, phdr);
255
256	/* if new buffer allocated for this door call, free it */
257	if (dptr != uptr)
258		(void) munmap(dptr, param.rsize);
259
260
261	return (ret);
262}
263
264static void
265send_doorfd(void **dptr, size_t *ndata, size_t *adata,
266	door_desc_t *pdesc)
267{
268	nss_pheader_t	*phdr = (nss_pheader_t *)*dptr;
269	door_arg_t	param;
270	int		ret;
271	int		doorfd;
272	int		errnum;
273	char		*me = "send_doorfd";
274
275	initdoor(*dptr, &doorfd);
276	if (NSCD_STATUS_IS_NOT_OK(phdr))
277		return;
278
279	param.rbuf = (char *)*dptr;
280	param.rsize = *ndata;
281	param.data_ptr = (char *)*dptr;
282	param.data_size = *adata;
283	param.desc_ptr = pdesc;
284	param.desc_num = 1;
285	ret = door_call(doorfd, &param);
286	if (ret < 0) {
287		errnum = errno;
288
289		_NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG)
290		(me, "door call (to fd %d) failed (%s)\n",
291			doorfd, strerror(errnum));
292		(void) close(doorfd);
293		NSCD_RETURN_STATUS(phdr, NSS_ERROR, errnum);
294	}
295	*adata = param.data_size;
296	*ndata = param.rsize;
297	*dptr = (void *)param.data_ptr;
298
299	if (*adata == 0 || *dptr == NULL) {
300		(void) close(doorfd);
301
302		_NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG)
303		(me, "no data\n");
304
305		NSCD_RETURN_STATUS(phdr, NSS_ERROR, ENOTCONN);
306	}
307
308	(void) close(doorfd);
309}
310
311nss_status_t
312_nscd_doorcall_sendfd(int fd, int callnum, void *indata, int indlen,
313	nss_pheader_t *phdr)
314{
315	void		*uptr;
316	void		*dptr;
317	void		*datap;
318	size_t		ndata;
319	size_t		adata;
320	size_t		buflen;
321	nss_pheader_t	*phdr_d;
322	door_desc_t	desc;
323	char		*me = "_nscd_doorcall_sendfd";
324
325	_NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG)
326	(me, "processing door call %d (fd = %d)...\n", callnum, fd);
327
328	/* allocate door buffer from the stack */
329	NSCD_ALLOC_DOORBUF(callnum, indlen, uptr, buflen);
330	dptr = uptr;
331	ndata = buflen;
332	adata = buflen;
333	datap = NSCD_N2N_DOOR_DATA(void, dptr);
334	if (indata != NULL)
335		(void) memmove(datap, indata, indlen);
336	desc.d_attributes = DOOR_DESCRIPTOR;
337	desc.d_data.d_desc.d_descriptor = fd;
338
339	send_doorfd(&dptr, &ndata, &adata, &desc);
340
341	phdr_d = (nss_pheader_t *)dptr;
342	if (NSCD_STATUS_IS_NOT_OK(phdr_d)) {
343		if (phdr != NULL)
344			*phdr = *phdr_d;
345
346		_NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG)
347		(me, "door call (%d) failed (status = %d, error = %s)\n",
348			callnum, NSCD_GET_STATUS(phdr_d),
349			strerror(NSCD_GET_ERRNO(phdr_d)));
350	}
351
352	return (NSCD_GET_STATUS(phdr_d));
353}
354