xref: /illumos-gate/usr/src/cmd/nscd/nscd_door.c (revision 168c213023b7f347f11abfc72f448b0c621ab718)
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 
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 
109 nss_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 
137 nss_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 
184 nss_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 
264 static void
265 send_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 
311 nss_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