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