xref: /illumos-gate/usr/src/cmd/nscd/nscd_door.c (revision 581cede61ac9c14d8d4ea452562a567189eead78)
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  */
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 
40 static void
41 initdoor(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 
76 static nss_status_t
77 copy_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 nss_status_t
109 _nscd_doorcall(int callnum)
110 {
111 	size_t		buflen;
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 	/* allocate door buffer from the stack */
123 	NSCD_ALLOC_DOORBUF(callnum, 0, dptr, buflen);
124 	ndata = buflen;
125 	adata = buflen;
126 
127 	ret = _nsc_trydoorcall(&dptr, &ndata, &adata);
128 
129 	if (ret != NSS_SUCCESS) {
130 		phdr = (nss_pheader_t *)dptr;
131 		_NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG)
132 		(me, "door call (%d) failed (status = %d, error = %s)\n",
133 			callnum, ret, strerror(NSCD_GET_ERRNO(phdr)));
134 	}
135 
136 	return (ret);
137 }
138 
139 
140 nss_status_t
141 _nscd_doorcall_data(int callnum, void *indata, int indlen,
142 	void *outdata, int outdlen, nss_pheader_t *phdr)
143 {
144 	void		*uptr;
145 	size_t		buflen;
146 	void		*dptr;
147 	void		*datap;
148 	size_t		ndata;
149 	size_t		adata;
150 	nss_pheader_t	*phdr_d;
151 	int		ret;
152 	char		*me = "_nscd_doorcall_data";
153 
154 	_NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG)
155 	(me, "processing door call %d ...\n", callnum);
156 
157 	/* allocate door buffer from the stack */
158 	NSCD_ALLOC_DOORBUF(callnum, indlen, uptr, buflen);
159 	dptr = uptr;
160 	ndata = buflen;
161 	adata = buflen;
162 	datap = NSCD_N2N_DOOR_DATA(void, dptr);
163 	if (indata != NULL)
164 		(void) memmove(datap, indata, indlen);
165 
166 	ret = _nsc_trydoorcall(&dptr, &ndata, &adata);
167 
168 	phdr_d = (nss_pheader_t *)dptr;
169 	if (ret != NSS_SUCCESS) {
170 		_NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG)
171 		(me, "door call (%d) failed (status = %d, error = %s)\n",
172 			callnum, ret, strerror(NSCD_GET_ERRNO(phdr_d)));
173 	} else {
174 		if (phdr != NULL) {
175 			NSCD_COPY_STATUS(phdr, phdr_d);
176 		}
177 		ret = copy_output(outdata, outdlen, phdr_d, phdr);
178 	}
179 
180 	/* if new buffer allocated for this door call, free it */
181 	if (dptr != uptr)
182 		(void) munmap(dptr, ndata);
183 
184 	return (ret);
185 }
186 
187 nss_status_t
188 _nscd_doorcall_fd(int fd, int callnum, void *indata, int indlen,
189 	void *outdata, int outdlen, nss_pheader_t *phdr)
190 {
191 	void		*uptr;
192 	void		*dptr;
193 	void		*datap;
194 	size_t		ndata;
195 	size_t		adata;
196 	size_t		buflen;
197 	door_arg_t	param;
198 	int		ret, errnum;
199 	nss_pheader_t	*phdr_d;
200 	char		*me = "_nscd_doorcall_fd";
201 
202 	_NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG)
203 	(me, "processing door call %d (fd = %d)...\n", callnum, fd);
204 
205 	/* allocate door buffer from the stack */
206 	NSCD_ALLOC_DOORBUF(callnum, indlen, uptr, buflen);
207 	dptr = uptr;
208 	ndata = buflen;
209 	adata = buflen;
210 	datap = NSCD_N2N_DOOR_DATA(void, dptr);
211 	if (indata != NULL)
212 		(void) memmove(datap, indata, indlen);
213 
214 	param.rbuf = (char *)dptr;
215 	param.rsize = ndata;
216 	param.data_ptr = (char *)dptr;
217 	param.data_size = adata;
218 	param.desc_ptr = NULL;
219 	param.desc_num = 0;
220 	ret = door_call(fd, &param);
221 	if (ret < 0) {
222 		errnum = errno;
223 		/*
224 		 * door call did not get through, return errno
225 		 * if requested
226 		 */
227 		if (phdr != NULL) {
228 			NSCD_SET_STATUS(phdr, NSS_ERROR, errnum);
229 		}
230 
231 		_NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG)
232 		(me, "door call (%d to %d) did not get through (%s)\n",
233 			callnum, fd, strerror(errnum));
234 
235 		return (NSS_ERROR);
236 	}
237 	ndata = param.rsize;
238 	dptr = (void *)param.data_ptr;
239 
240 	/*
241 	 * door call got through, check if operation failed.
242 	 * if so, return error info if requested
243 	 */
244 	phdr_d = (nss_pheader_t *)dptr;
245 	ret = NSCD_GET_STATUS(phdr_d);
246 	if (ret != NSS_SUCCESS) {
247 		if (phdr != NULL) {
248 			NSCD_COPY_STATUS(phdr, phdr_d);
249 		}
250 
251 		_NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG)
252 		(me, "door call (%d to %d) failed: p_status = %d, "
253 		"p_errno = %s, nscd status = %d\n", callnum, fd,
254 		ret, strerror(NSCD_GET_ERRNO(phdr_d)),
255 		NSCD_GET_NSCD_STATUS(phdr_d));
256 	} else
257 		ret = copy_output(outdata, outdlen, phdr_d, phdr);
258 
259 	/* if new buffer allocated for this door call, free it */
260 	if (dptr != uptr)
261 		(void) munmap(dptr, param.rsize);
262 
263 
264 	return (ret);
265 }
266 
267 static void
268 send_doorfd(void **dptr, size_t *ndata, size_t *adata,
269 	door_desc_t *pdesc)
270 {
271 	nss_pheader_t	*phdr = (nss_pheader_t *)*dptr;
272 	door_arg_t	param;
273 	int		ret;
274 	int		doorfd;
275 	int		errnum;
276 	char		*me = "send_doorfd";
277 
278 	initdoor(*dptr, &doorfd);
279 	if (NSCD_STATUS_IS_NOT_OK(phdr))
280 		return;
281 
282 	param.rbuf = (char *)*dptr;
283 	param.rsize = *ndata;
284 	param.data_ptr = (char *)*dptr;
285 	param.data_size = *adata;
286 	param.desc_ptr = pdesc;
287 	param.desc_num = 1;
288 	ret = door_call(doorfd, &param);
289 	if (ret < 0) {
290 		errnum = errno;
291 
292 		_NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG)
293 		(me, "door call (to fd %d) failed (%s)\n",
294 			doorfd, strerror(errnum));
295 		(void) close(doorfd);
296 		NSCD_RETURN_STATUS(phdr, NSS_ERROR, errnum);
297 	}
298 	*adata = param.data_size;
299 	*ndata = param.rsize;
300 	*dptr = (void *)param.data_ptr;
301 
302 	if (*adata == 0 || *dptr == NULL) {
303 		(void) close(doorfd);
304 
305 		_NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG)
306 		(me, "no data\n");
307 
308 		NSCD_RETURN_STATUS(phdr, NSS_ERROR, ENOTCONN);
309 	}
310 
311 	(void) close(doorfd);
312 }
313 
314 nss_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