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