xref: /illumos-gate/usr/src/cmd/nscd/nscd_door.c (revision 976d66ab3c04344d31957f85ffb1600cf5847fc9)
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 
39 static void
40 initdoor(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 
78 static nss_status_t
79 copy_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 
109 nss_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 
141 nss_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 
188 nss_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 
268 static void
269 send_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 
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