xref: /illumos-gate/usr/src/lib/libnsl/rpc/svc_door.c (revision 0900f4f2)
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 2009 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 /*
27  * Copyright 2014 Nexenta Systems, Inc.  All rights reserved.
28  */
29 
30 /*
31  * svc_door.c, Server side for doors IPC based RPC.
32  */
33 
34 #include "mt.h"
35 #include "rpc_mt.h"
36 #include <stdio.h>
37 #include <unistd.h>
38 #include <sys/types.h>
39 #include <rpc/rpc.h>
40 #include <errno.h>
41 #include <syslog.h>
42 #include <stdlib.h>
43 #include <string.h>
44 #include <sys/stat.h>
45 #include <door.h>
46 #include <alloca.h>
47 #include <dlfcn.h>
48 #include <limits.h>
49 #include <rpc/svc_mt.h>
50 
51 static void svc_door_destroy_pvt();
52 static int return_xprt_copy();
53 
54 int __rpc_default_door_buf_size = 16000;
55 int __rpc_min_door_buf_size = 1000;
56 
57 static struct xp_ops *svc_door_ops();
58 
59 mutex_t	svc_door_mutex = DEFAULTMUTEX;
60 cond_t	svc_door_waitcv = DEFAULTCV;
61 int	svc_ndoorfds = 0;
62 
63 /*
64  * Dispatch information for door calls.
65  */
66 typedef struct {
67 	rpcprog_t		prognum;
68 	rpcvers_t		versnum;
69 	void			(*dispatch)();
70 } call_info_t;
71 
72 /*
73  * kept in xprt->xp_p2
74  */
75 struct svc_door_data {
76 	uint_t   	su_iosz;		/* size of send/recv buffer */
77 	uint32_t	su_xid;			/* transaction id */
78 	XDR		su_xdrs;		/* XDR handle */
79 	char		su_verfbody[MAX_AUTH_BYTES]; /* verifier body */
80 	call_info_t	call_info;		/* dispatch info */
81 	char		*argbuf;		/* argument buffer */
82 	size_t		arglen;			/* argument length */
83 	char		*buf;			/* result buffer */
84 	int		len;			/* result length */
85 };
86 #define	su_data(xprt)	((struct svc_door_data *)(xprt->xp_p2))
87 
88 static SVCXPRT *get_xprt_copy();
89 static bool_t svc_door_recv();
90 static void svc_door_destroy();
91 
92 static SVCXPRT_LIST *dxlist;	/* list of door based service handles */
93 
94 /*
95  * List management routines.
96  */
97 bool_t
__svc_add_to_xlist(SVCXPRT_LIST ** list,SVCXPRT * xprt,mutex_t * lockp)98 __svc_add_to_xlist(SVCXPRT_LIST **list, SVCXPRT *xprt, mutex_t *lockp)
99 {
100 	SVCXPRT_LIST	*l;
101 
102 	if ((l = malloc(sizeof (*l))) == NULL)
103 		return (FALSE);
104 	l->xprt = xprt;
105 	if (lockp != NULL)
106 		(void) mutex_lock(lockp);
107 	l->next = *list;
108 	*list = l;
109 	if (lockp != NULL)
110 		(void) mutex_unlock(lockp);
111 	return (TRUE);
112 }
113 
114 void
__svc_rm_from_xlist(SVCXPRT_LIST ** list,SVCXPRT * xprt,mutex_t * lockp)115 __svc_rm_from_xlist(SVCXPRT_LIST **list, SVCXPRT *xprt, mutex_t *lockp)
116 {
117 	SVCXPRT_LIST	**l, *tmp;
118 
119 	if (lockp != NULL)
120 		(void) mutex_lock(lockp);
121 	for (l = list; *l != NULL; l = &(*l)->next) {
122 		if ((*l)->xprt == xprt) {
123 			tmp = (*l)->next;
124 			free(*l);
125 			*l = tmp;
126 			break;
127 		}
128 	}
129 	if (lockp != NULL)
130 		(void) mutex_unlock(lockp);
131 }
132 
133 void
__svc_free_xlist(SVCXPRT_LIST ** list,mutex_t * lockp)134 __svc_free_xlist(SVCXPRT_LIST **list, mutex_t *lockp)
135 {
136 	SVCXPRT_LIST	*tmp;
137 
138 	if (lockp != NULL)
139 		(void) mutex_lock(lockp);
140 	while (*list != NULL) {
141 		tmp = (*list)->next;
142 		free(*list);
143 		*list = tmp;
144 	}
145 	if (lockp != NULL)
146 		(void) mutex_unlock(lockp);
147 }
148 
149 /*
150  * Destroy all door based service handles.
151  */
152 void
__svc_cleanup_door_xprts(void)153 __svc_cleanup_door_xprts(void)
154 {
155 	SVCXPRT_LIST	*l, *tmp = NULL;
156 
157 	(void) mutex_lock(&svc_door_mutex);
158 	for (l = dxlist; l != NULL; l = tmp) {
159 		tmp = l->next;
160 		svc_door_destroy_pvt(l->xprt);
161 	}
162 	(void) mutex_unlock(&svc_door_mutex);
163 }
164 
165 static bool_t
make_tmp_dir(void)166 make_tmp_dir(void)
167 {
168 	struct stat statbuf;
169 
170 	if (stat(RPC_DOOR_DIR, &statbuf) < 0) {
171 		(void) mkdir(RPC_DOOR_DIR, (mode_t)0755);
172 		(void) chmod(RPC_DOOR_DIR, (mode_t)01777);
173 		if (stat(RPC_DOOR_DIR, &statbuf) < 0)
174 			return (FALSE);
175 	}
176 	return ((statbuf.st_mode & S_IFMT) == S_IFDIR &&
177 	    (statbuf.st_mode & 01777) == 01777);
178 }
179 
180 static void
svc_door_dispatch(SVCXPRT * xprt,struct rpc_msg * msg,struct svc_req * r)181 svc_door_dispatch(SVCXPRT *xprt, struct rpc_msg *msg, struct svc_req *r)
182 {
183 	enum auth_stat		why;
184 /* LINTED pointer alignment */
185 	struct svc_door_data	*su = su_data(xprt);
186 	bool_t nd;
187 
188 	r->rq_xprt = xprt;
189 	r->rq_prog = msg->rm_call.cb_prog;
190 	r->rq_vers = msg->rm_call.cb_vers;
191 	r->rq_proc = msg->rm_call.cb_proc;
192 	r->rq_cred = msg->rm_call.cb_cred;
193 
194 	if (msg->rm_call.cb_cred.oa_flavor == AUTH_NULL) {
195 		r->rq_xprt->xp_verf.oa_flavor = _null_auth.oa_flavor;
196 		r->rq_xprt->xp_verf.oa_length = 0;
197 
198 	} else if ((why = __gss_authenticate(r, msg, &nd)) != AUTH_OK) {
199 		svcerr_auth(xprt, why);
200 		return;
201 	}
202 
203 	if (su->call_info.prognum == r->rq_prog && su->call_info.versnum ==
204 	    r->rq_vers) {
205 		(*su->call_info.dispatch)(r, xprt);
206 		return;
207 	}
208 
209 	/*
210 	 * if we got here, the program or version
211 	 * is not served ...
212 	 */
213 	if (su->call_info.prognum == r->rq_prog)
214 		svcerr_progvers(xprt, su->call_info.versnum,
215 		    su->call_info.versnum);
216 	else
217 		svcerr_noprog(xprt);
218 }
219 
220 /*
221  * This is the door server procedure.
222  */
223 /* ARGSUSED */
224 static void
door_server(void * cookie,char * argp,size_t arg_size,door_desc_t * dp,uint_t n_did)225 door_server(void *cookie, char *argp, size_t arg_size,
226     door_desc_t *dp, uint_t n_did)
227 {
228 	SVCXPRT			*parent = (SVCXPRT *)cookie;
229 	SVCXPRT			*xprt;
230 	struct rpc_msg		*msg;
231 	struct svc_req		*r;
232 	char			*cred_area;
233 	char			*result_buf;
234 	int			len;
235 	struct svc_door_data	*su;
236 
237 	/*
238 	 * allocate result buffer
239 	 */
240 /* LINTED pointer alignment */
241 	result_buf = alloca(su_data(parent)->su_iosz);
242 	if (result_buf == NULL) {
243 		(void) syslog(LOG_ERR, "door_server: alloca failed");
244 		(void) door_return(NULL, 0, NULL, 0);
245 		/*NOTREACHED*/
246 	}
247 
248 	(void) mutex_lock(&svc_door_mutex);
249 	if ((xprt = get_xprt_copy(parent, result_buf)) == NULL) {
250 		(void) syslog(LOG_ERR,
251 		    "door_server: memory allocation failure");
252 		(void) mutex_unlock(&svc_door_mutex);
253 		(void) door_return(NULL, 0, NULL, 0);
254 		/*NOTREACHED*/
255 	}
256 	(void) mutex_unlock(&svc_door_mutex);
257 
258 /* LINTED pointer alignment */
259 	msg = SVCEXT(xprt)->msg;
260 /* LINTED pointer alignment */
261 	r = SVCEXT(xprt)->req;
262 /* LINTED pointer alignment */
263 	cred_area = SVCEXT(xprt)->cred_area;
264 
265 	msg->rm_call.cb_cred.oa_base = cred_area;
266 	msg->rm_call.cb_verf.oa_base = &(cred_area[MAX_AUTH_BYTES]);
267 	r->rq_clntcred = &(cred_area[2 * MAX_AUTH_BYTES]);
268 
269 /* LINTED pointer alignment */
270 	su = su_data(xprt);
271 	su->argbuf = argp;
272 	su->arglen = arg_size;
273 
274 	if (svc_door_recv(xprt, msg))
275 		svc_door_dispatch(xprt, msg, r);
276 
277 	if ((len = return_xprt_copy(xprt)) > 0) {
278 		(void) door_return(result_buf, (size_t)len, NULL, 0);
279 		/*NOTREACHED*/
280 	} else {
281 		(void) door_return(NULL, 0, NULL, 0);
282 		/*NOTREACHED*/
283 	}
284 }
285 
286 /*
287  * Usage:
288  *	xprt = svc_door_create(dispatch, prognum, versnum, sendsize);
289  * Once *xprt is initialized, it is registered.
290  * see (svc.h, xprt_register). If recvsize or sendsize are 0 suitable
291  * system defaults are chosen.
292  * The routines returns NULL if a problem occurred.
293  */
294 
295 void
svc_door_xprtfree(SVCXPRT * xprt)296 svc_door_xprtfree(SVCXPRT *xprt)
297 {
298 /* LINTED pointer alignment */
299 	struct svc_door_data	*su = xprt ? su_data(xprt) : NULL;
300 
301 	if (xprt == NULL)
302 		return;
303 	if (xprt->xp_netid)
304 		free(xprt->xp_netid);
305 	if (xprt->xp_tp)
306 		free(xprt->xp_tp);
307 	if (su != NULL)
308 		free(su);
309 	svc_xprt_free(xprt);
310 }
311 
312 SVCXPRT *
svc_door_create(void (* dispatch)(),const rpcprog_t prognum,const rpcvers_t versnum,const uint_t sendsize)313 svc_door_create(void (*dispatch)(), const rpcprog_t prognum,
314 				const rpcvers_t versnum, const uint_t sendsize)
315 {
316 	SVCXPRT			*xprt;
317 	struct svc_door_data	*su = NULL;
318 	char			rendezvous[128] = "";
319 	int			fd;
320 	int			did = -1;
321 	mode_t			mask;
322 	uint_t			ssize;
323 
324 	(void) mutex_lock(&svc_door_mutex);
325 
326 	if (!make_tmp_dir()) {
327 		(void) syslog(LOG_ERR, "svc_door_create: cannot open %s",
328 		    RPC_DOOR_DIR);
329 		(void) mutex_unlock(&svc_door_mutex);
330 		return (NULL);
331 	}
332 
333 	if ((xprt = svc_xprt_alloc()) == NULL) {
334 		(void) syslog(LOG_ERR, "svc_door_create: out of memory");
335 		goto freedata;
336 	}
337 /* LINTED pointer alignment */
338 	svc_flags(xprt) |= SVC_DOOR;
339 
340 	(void) sprintf(rendezvous, RPC_DOOR_RENDEZVOUS, (int)prognum,
341 	    (int)versnum);
342 	mask = umask(0);
343 	fd =  open(rendezvous, O_WRONLY|O_CREAT|O_EXCL|O_TRUNC, 0644);
344 	(void) umask(mask);
345 	if (fd < 0) {
346 		if (errno == EEXIST) {
347 			if (unlink(rendezvous) < 0) {
348 				(void) syslog(LOG_ERR,
349 				    "svc_door_create: %s %s:%m", rendezvous,
350 				    "exists and could not be removed");
351 				goto freedata;
352 			}
353 			mask = umask(0);
354 			fd =  open(rendezvous, O_WRONLY | O_CREAT | O_EXCL |
355 			    O_TRUNC, 0644);
356 			(void) umask(mask);
357 			if (fd < 0) {
358 				(void) syslog(LOG_ERR,
359 				    "svc_door_create: %s %s:%m",
360 				    "could not create", rendezvous);
361 				goto freedata;
362 			}
363 		} else {
364 			(void) syslog(LOG_ERR,
365 			    "svc_door_create: could not create %s:%m",
366 			    rendezvous);
367 			goto freedata;
368 		}
369 	}
370 	(void) close(fd);
371 	did = door_create(door_server, (void *)xprt, DOOR_REFUSE_DESC);
372 	if (did < 0) {
373 		(void) syslog(LOG_ERR,
374 		    "svc_door_create: door_create failed: %m");
375 		goto freedata;
376 	}
377 
378 	if (fattach(did, rendezvous) < 0) {
379 		if (errno != EBUSY || fdetach(rendezvous) < 0 ||
380 		    fattach(did, rendezvous) < 0) {
381 			(void) syslog(LOG_ERR,
382 			    "svc_door_create: fattach failed: %m");
383 			goto freedata;
384 		}
385 	}
386 
387 	/*
388 	 * Determine send size
389 	 */
390 	if (sendsize < __rpc_min_door_buf_size)
391 		ssize = __rpc_default_door_buf_size;
392 	else
393 		ssize = RNDUP(sendsize);
394 
395 	su = malloc(sizeof (*su));
396 	if (su == NULL) {
397 		(void) syslog(LOG_ERR, "svc_door_create: out of memory");
398 		goto freedata;
399 	}
400 	su->su_iosz = ssize;
401 	su->call_info.prognum = prognum;
402 	su->call_info.versnum = versnum;
403 	su->call_info.dispatch = dispatch;
404 
405 	xprt->xp_p2 = (caddr_t)su;
406 	xprt->xp_verf.oa_base = su->su_verfbody;
407 	xprt->xp_ops = svc_door_ops();
408 	xprt->xp_netid = strdup("door");
409 	if (xprt->xp_netid == NULL) {
410 		syslog(LOG_ERR, "svc_door_create: strdup failed");
411 		goto freedata;
412 	}
413 	xprt->xp_tp = strdup(rendezvous);
414 	if (xprt->xp_tp == NULL) {
415 		syslog(LOG_ERR, "svc_door_create: strdup failed");
416 		goto freedata;
417 	}
418 	xprt->xp_fd = did;
419 
420 	svc_ndoorfds++;
421 	if (!__svc_add_to_xlist(&dxlist, xprt, NULL)) {
422 
423 		(void) syslog(LOG_ERR, "svc_door_create: out of memory");
424 		goto freedata;
425 	}
426 	(void) mutex_unlock(&svc_door_mutex);
427 	return (xprt);
428 freedata:
429 	(void) fdetach(rendezvous);
430 	(void) unlink(rendezvous);
431 	if (did >= 0)
432 		(void) door_revoke(did);
433 	if (xprt)
434 		svc_door_xprtfree(xprt);
435 	(void) mutex_unlock(&svc_door_mutex);
436 	return (NULL);
437 }
438 
439 
440 static SVCXPRT *
svc_door_xprtcopy(SVCXPRT * parent)441 svc_door_xprtcopy(SVCXPRT *parent)
442 {
443 	SVCXPRT			*xprt;
444 	struct svc_door_data	*su;
445 
446 	if ((xprt = svc_xprt_alloc()) == NULL)
447 		return (NULL);
448 
449 /* LINTED pointer alignment */
450 	SVCEXT(xprt)->parent = parent;
451 /* LINTED pointer alignment */
452 	SVCEXT(xprt)->flags = SVCEXT(parent)->flags;
453 
454 	xprt->xp_fd = parent->xp_fd;
455 	xprt->xp_port = parent->xp_port;
456 	xprt->xp_ops = svc_door_ops();
457 	if (parent->xp_tp) {
458 		xprt->xp_tp = (char *)strdup(parent->xp_tp);
459 		if (xprt->xp_tp == NULL) {
460 			syslog(LOG_ERR, "svc_door_xprtcopy: strdup failed");
461 			svc_door_xprtfree(xprt);
462 			return (NULL);
463 		}
464 	}
465 	if (parent->xp_netid) {
466 		xprt->xp_netid = (char *)strdup(parent->xp_netid);
467 		if (xprt->xp_netid == NULL) {
468 			syslog(LOG_ERR, "svc_door_xprtcopy: strdup failed");
469 			if (parent->xp_tp)
470 				free(parent->xp_tp);
471 			svc_door_xprtfree(xprt);
472 			return (NULL);
473 		}
474 	}
475 	xprt->xp_type = parent->xp_type;
476 
477 	if ((su = malloc(sizeof (struct svc_door_data))) == NULL) {
478 		svc_door_xprtfree(xprt);
479 		return (NULL);
480 	}
481 /* LINTED pointer alignment */
482 	su->su_iosz = su_data(parent)->su_iosz;
483 /* LINTED pointer alignment */
484 	su->call_info = su_data(parent)->call_info;
485 
486 	xprt->xp_p2 = (caddr_t)su;	/* su_data(xprt) = su */
487 	xprt->xp_verf.oa_base = su->su_verfbody;
488 
489 	return (xprt);
490 }
491 
492 
493 static SVCXPRT *
get_xprt_copy(SVCXPRT * parent,char * buf)494 get_xprt_copy(SVCXPRT *parent, char *buf)
495 {
496 /* LINTED pointer alignment */
497 	SVCXPRT_LIST		*xlist = SVCEXT(parent)->my_xlist;
498 	SVCXPRT_LIST		*xret;
499 	SVCXPRT			*xprt;
500 	struct svc_door_data	*su;
501 
502 	xret = xlist->next;
503 	if (xret) {
504 		xlist->next = xret->next;
505 		xret->next = NULL;
506 		xprt = xret->xprt;
507 /* LINTED pointer alignment */
508 		svc_flags(xprt) = svc_flags(parent);
509 	} else
510 		xprt = svc_door_xprtcopy(parent);
511 
512 	if (xprt) {
513 /* LINTED pointer alignment */
514 		SVCEXT(parent)->refcnt++;
515 /* LINTED pointer alignment */
516 		su = su_data(xprt);
517 		su->buf = buf;
518 		su->len = 0;
519 	}
520 	return (xprt);
521 }
522 
523 int
return_xprt_copy(SVCXPRT * xprt)524 return_xprt_copy(SVCXPRT *xprt)
525 {
526 	SVCXPRT		*parent;
527 	SVCXPRT_LIST	*xhead, *xlist;
528 /* LINTED pointer alignment */
529 	int		len = su_data(xprt)->len;
530 
531 	(void) mutex_lock(&svc_door_mutex);
532 /* LINTED pointer alignment */
533 	if ((parent = SVCEXT(xprt)->parent) == NULL) {
534 		(void) mutex_unlock(&svc_door_mutex);
535 		return (0);
536 	}
537 /* LINTED pointer alignment */
538 	xhead = SVCEXT(parent)->my_xlist;
539 /* LINTED pointer alignment */
540 	xlist = SVCEXT(xprt)->my_xlist;
541 	xlist->next = xhead->next;
542 	xhead->next = xlist;
543 /* LINTED pointer alignment */
544 	SVCEXT(parent)->refcnt--;
545 
546 	/*
547 	 * Propagate any error flags.  This is done in both directions to
548 	 * ensure that if one child gets an error, everyone will see it
549 	 * (even if there are multiple outstanding children) and the
550 	 * door will get closed.
551 	 */
552 /* LINTED pointer alignment */
553 	svc_flags(xprt) |= svc_flags(parent);
554 /* LINTED pointer alignment */
555 	if (svc_defunct(xprt)) {
556 /* LINTED pointer alignment */
557 		svc_flags(parent) |= SVC_DEFUNCT;
558 		/* LINTED pointer cast */
559 		if (SVCEXT(parent)->refcnt == 0)
560 			svc_door_destroy_pvt(xprt);
561 	}
562 	(void) mutex_unlock(&svc_door_mutex);
563 	return (len);
564 }
565 
566 /* ARGSUSED */
567 static enum xprt_stat
svc_door_stat(SVCXPRT * xprt)568 svc_door_stat(SVCXPRT *xprt)
569 {
570 	return (XPRT_IDLE);
571 }
572 
573 static bool_t
svc_door_recv(SVCXPRT * xprt,struct rpc_msg * msg)574 svc_door_recv(SVCXPRT *xprt, struct rpc_msg *msg)
575 {
576 /* LINTED pointer alignment */
577 	struct svc_door_data	*su = su_data(xprt);
578 	XDR			*xdrs = &(su->su_xdrs);
579 
580 	xdrmem_create(xdrs, su->argbuf, su->arglen, XDR_DECODE);
581 	if (!xdr_callmsg(xdrs, msg))
582 		return (FALSE);
583 	su->su_xid = msg->rm_xid;
584 	return (TRUE);
585 }
586 
587 static bool_t
svc_door_reply(SVCXPRT * xprt,struct rpc_msg * msg)588 svc_door_reply(SVCXPRT *xprt, struct rpc_msg *msg)
589 {
590 /* LINTED pointer alignment */
591 	struct svc_door_data	*su = su_data(xprt);
592 	XDR			*xdrs = &(su->su_xdrs);
593 
594 	xdrmem_create(xdrs, su->buf, su->su_iosz, XDR_ENCODE);
595 	msg->rm_xid = su->su_xid;
596 	if (xdr_replymsg(xdrs, msg)) {
597 		su->len = (int)XDR_GETPOS(xdrs);
598 		return (TRUE);
599 	}
600 	return (FALSE);
601 }
602 
603 static bool_t
svc_door_getargs(SVCXPRT * xprt,xdrproc_t xdr_args,caddr_t args_ptr)604 svc_door_getargs(SVCXPRT *xprt, xdrproc_t xdr_args, caddr_t args_ptr)
605 {
606 /* LINTED pointer alignment */
607 	return ((*xdr_args)(&(su_data(xprt)->su_xdrs), args_ptr));
608 }
609 
610 static bool_t
svc_door_freeargs(SVCXPRT * xprt,xdrproc_t xdr_args,caddr_t args_ptr)611 svc_door_freeargs(SVCXPRT *xprt, xdrproc_t xdr_args, caddr_t args_ptr)
612 {
613 /* LINTED pointer alignment */
614 	XDR		*xdrs = &(su_data(xprt)->su_xdrs);
615 
616 	xdrs->x_op = XDR_FREE;
617 	return ((*xdr_args)(xdrs, args_ptr));
618 }
619 
620 static void
svc_door_destroy(SVCXPRT * xprt)621 svc_door_destroy(SVCXPRT *xprt)
622 {
623 	(void) mutex_lock(&svc_door_mutex);
624 	svc_door_destroy_pvt(xprt);
625 	(void) mutex_unlock(&svc_door_mutex);
626 }
627 
628 static void
svc_door_destroy_pvt(SVCXPRT * xprt)629 svc_door_destroy_pvt(SVCXPRT *xprt)
630 {
631 /* LINTED pointer alignment */
632 	if (SVCEXT(xprt)->parent)
633 /* LINTED pointer alignment */
634 		xprt = SVCEXT(xprt)->parent;
635 /* LINTED pointer alignment */
636 	svc_flags(xprt) |= SVC_DEFUNCT;
637 /* LINTED pointer alignment */
638 	if (SVCEXT(xprt)->refcnt > 0)
639 		return;
640 
641 	__svc_rm_from_xlist(&dxlist, xprt, NULL);
642 
643 	if (xprt->xp_tp) {
644 		(void) fdetach(xprt->xp_tp);
645 		(void) unlink(xprt->xp_tp);
646 	}
647 	(void) door_revoke(xprt->xp_fd);
648 
649 	svc_xprt_destroy(xprt);
650 	if (--svc_ndoorfds == 0)
651 		/* wake up door dispatching */
652 		(void) cond_signal(&svc_door_waitcv);
653 }
654 
655 /* ARGSUSED */
656 static bool_t
svc_door_control(SVCXPRT * xprt,const uint_t rq,void * in)657 svc_door_control(SVCXPRT *xprt, const uint_t rq, void *in)
658 {
659 	extern int __rpc_legal_connmaxrec(int);
660 
661 	size_t door_param;
662 	int tmp;
663 
664 	switch (rq) {
665 	case SVCSET_CONNMAXREC:
666 		tmp = __rpc_legal_connmaxrec(*(int *)in);
667 		if (tmp >= 0) {
668 			door_param = (tmp == 0)? SIZE_MAX :
669 			    (size_t)(ssize_t)tmp;
670 			if (door_setparam(xprt->xp_fd, DOOR_PARAM_DATA_MAX,
671 			    door_param) == 0)
672 				return (TRUE);
673 			return (FALSE);
674 		}
675 		return (FALSE);
676 	case SVCGET_CONNMAXREC:
677 		if (door_getparam(xprt->xp_fd, DOOR_PARAM_DATA_MAX,
678 		    &door_param) == 0) {
679 			if (door_param == SIZE_MAX)
680 				tmp = 0;
681 			else if (door_param > INT_MAX)
682 				tmp = INT_MAX;
683 			else if (door_param > 0)
684 				tmp = (int)door_param;
685 			else
686 				return (FALSE);
687 
688 			*(int *)in = tmp;
689 			return (TRUE);
690 		}
691 		return (FALSE);
692 	}
693 	return (FALSE);
694 }
695 
696 static struct xp_ops *
svc_door_ops(void)697 svc_door_ops(void)
698 {
699 	static struct xp_ops	ops;
700 	extern mutex_t		ops_lock;
701 
702 	(void) mutex_lock(&ops_lock);
703 	if (ops.xp_recv == NULL) {
704 		ops.xp_recv = svc_door_recv;
705 		ops.xp_stat = svc_door_stat;
706 		ops.xp_getargs = svc_door_getargs;
707 		ops.xp_reply = svc_door_reply;
708 		ops.xp_freeargs = svc_door_freeargs;
709 		ops.xp_destroy = svc_door_destroy;
710 		ops.xp_control = svc_door_control;
711 	}
712 	(void) mutex_unlock(&ops_lock);
713 	return (&ops);
714 }
715 
716 /*
717  * Return door credentials.
718  */
719 /* ARGSUSED */
720 bool_t
__svc_get_door_cred(SVCXPRT * xprt,svc_local_cred_t * lcred)721 __svc_get_door_cred(SVCXPRT *xprt, svc_local_cred_t *lcred)
722 {
723 	door_cred_t		dc;
724 
725 	if (door_cred(&dc) < 0)
726 		return (FALSE);
727 	lcred->euid = dc.dc_euid;
728 	lcred->egid = dc.dc_egid;
729 	lcred->ruid = dc.dc_ruid;
730 	lcred->rgid = dc.dc_rgid;
731 	lcred->pid = dc.dc_pid;
732 	return (TRUE);
733 }
734 
735 /* ARGSUSED */
736 bool_t
__svc_get_door_ucred(const SVCXPRT * xprt,ucred_t * ucp)737 __svc_get_door_ucred(const SVCXPRT *xprt, ucred_t *ucp)
738 {
739 	return (door_ucred(&ucp) == 0);
740 }
741