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