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