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.
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.
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]
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
31 * svc_door.c, Server side for doors IPC based RPC.
38 #include <sys/types.h>
49 #include <rpc/svc_mt.h>
51 static void svc_door_destroy_pvt();
52 static int return_xprt_copy();
54 int __rpc_default_door_buf_size
= 16000;
55 int __rpc_min_door_buf_size
= 1000;
57 static struct xp_ops
*svc_door_ops();
59 mutex_t svc_door_mutex
= DEFAULTMUTEX
;
60 cond_t svc_door_waitcv
= DEFAULTCV
;
64 * Dispatch information for door calls.
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 */
86 #define su_data(xprt) ((struct svc_door_data *)(xprt->xp_p2))
88 static SVCXPRT
*get_xprt_copy();
89 static bool_t
svc_door_recv();
90 static void svc_door_destroy();
92 static SVCXPRT_LIST
*dxlist
; /* list of door based service handles */
95 * List management routines.
98 __svc_add_to_xlist(SVCXPRT_LIST
**list
, SVCXPRT
*xprt
, mutex_t
*lockp
)
102 if ((l
= malloc(sizeof (*l
))) == NULL
)
106 (void) mutex_lock(lockp
);
110 (void) mutex_unlock(lockp
);
115 __svc_rm_from_xlist(SVCXPRT_LIST
**list
, SVCXPRT
*xprt
, mutex_t
*lockp
)
117 SVCXPRT_LIST
**l
, *tmp
;
120 (void) mutex_lock(lockp
);
121 for (l
= list
; *l
!= NULL
; l
= &(*l
)->next
) {
122 if ((*l
)->xprt
== xprt
) {
130 (void) mutex_unlock(lockp
);
134 __svc_free_xlist(SVCXPRT_LIST
**list
, mutex_t
*lockp
)
139 (void) mutex_lock(lockp
);
140 while (*list
!= NULL
) {
146 (void) mutex_unlock(lockp
);
150 * Destroy all door based service handles.
153 __svc_cleanup_door_xprts(void)
155 SVCXPRT_LIST
*l
, *tmp
= NULL
;
157 (void) mutex_lock(&svc_door_mutex
);
158 for (l
= dxlist
; l
!= NULL
; l
= tmp
) {
160 svc_door_destroy_pvt(l
->xprt
);
162 (void) mutex_unlock(&svc_door_mutex
);
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)
176 return ((statbuf
.st_mode
& S_IFMT
) == S_IFDIR
&&
177 (statbuf
.st_mode
& 01777) == 01777);
181 svc_door_dispatch(SVCXPRT
*xprt
, struct rpc_msg
*msg
, struct svc_req
*r
)
184 /* LINTED pointer alignment */
185 struct svc_door_data
*su
= su_data(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
;
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;
198 } else if ((why
= __gss_authenticate(r
, msg
, &nd
)) != AUTH_OK
) {
199 svcerr_auth(xprt
, why
);
203 if (su
->call_info
.prognum
== r
->rq_prog
&& su
->call_info
.versnum
==
205 (*su
->call_info
.dispatch
)(r
, xprt
);
210 * if we got here, the program or version
213 if (su
->call_info
.prognum
== r
->rq_prog
)
214 svcerr_progvers(xprt
, su
->call_info
.versnum
,
215 su
->call_info
.versnum
);
221 * This is the door server procedure.
225 door_server(void *cookie
, char *argp
, size_t arg_size
,
226 door_desc_t
*dp
, uint_t n_did
)
228 SVCXPRT
*parent
= (SVCXPRT
*)cookie
;
235 struct svc_door_data
*su
;
238 * allocate result buffer
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);
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);
256 (void) mutex_unlock(&svc_door_mutex
);
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
;
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
]);
269 /* LINTED pointer alignment */
272 su
->arglen
= arg_size
;
274 if (svc_door_recv(xprt
, msg
))
275 svc_door_dispatch(xprt
, msg
, r
);
277 if ((len
= return_xprt_copy(xprt
)) > 0) {
278 (void) door_return(result_buf
, (size_t)len
, NULL
, 0);
281 (void) door_return(NULL
, 0, NULL
, 0);
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.
296 svc_door_xprtfree(SVCXPRT
*xprt
)
298 /* LINTED pointer alignment */
299 struct svc_door_data
*su
= xprt
? su_data(xprt
) : NULL
;
303 free(xprt
->xp_netid
);
310 svc_door_create(void (*dispatch
)(), const rpcprog_t prognum
,
311 const rpcvers_t versnum
, const uint_t sendsize
)
314 struct svc_door_data
*su
= NULL
;
315 char rendezvous
[128] = "";
321 (void) mutex_lock(&svc_door_mutex
);
323 if (!make_tmp_dir()) {
324 (void) syslog(LOG_ERR
, "svc_door_create: cannot open %s",
326 (void) mutex_unlock(&svc_door_mutex
);
330 if ((xprt
= svc_xprt_alloc()) == NULL
) {
331 (void) syslog(LOG_ERR
, "svc_door_create: out of memory");
334 /* LINTED pointer alignment */
335 svc_flags(xprt
) |= SVC_DOOR
;
337 (void) sprintf(rendezvous
, RPC_DOOR_RENDEZVOUS
, (int)prognum
,
340 fd
= open(rendezvous
, O_WRONLY
|O_CREAT
|O_EXCL
|O_TRUNC
, 0644);
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");
351 fd
= open(rendezvous
, O_WRONLY
| O_CREAT
| O_EXCL
|
355 (void) syslog(LOG_ERR
,
356 "svc_door_create: %s %s:%m",
357 "could not create", rendezvous
);
361 (void) syslog(LOG_ERR
,
362 "svc_door_create: could not create %s:%m",
368 did
= door_create(door_server
, (void *)xprt
, DOOR_REFUSE_DESC
);
370 (void) syslog(LOG_ERR
,
371 "svc_door_create: door_create failed: %m");
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");
385 * Determine send size
387 if (sendsize
< __rpc_min_door_buf_size
)
388 ssize
= __rpc_default_door_buf_size
;
390 ssize
= RNDUP(sendsize
);
392 su
= malloc(sizeof (*su
));
394 (void) syslog(LOG_ERR
, "svc_door_create: out of memory");
398 su
->call_info
.prognum
= prognum
;
399 su
->call_info
.versnum
= versnum
;
400 su
->call_info
.dispatch
= dispatch
;
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");
410 xprt
->xp_tp
= strdup(rendezvous
);
411 if (xprt
->xp_tp
== NULL
) {
412 syslog(LOG_ERR
, "svc_door_create: strdup failed");
418 if (!__svc_add_to_xlist(&dxlist
, xprt
, NULL
)) {
420 (void) syslog(LOG_ERR
, "svc_door_create: out of memory");
423 (void) mutex_unlock(&svc_door_mutex
);
426 (void) fdetach(rendezvous
);
427 (void) unlink(rendezvous
);
429 (void) door_revoke(did
);
431 svc_door_xprtfree(xprt
);
432 (void) mutex_unlock(&svc_door_mutex
);
438 svc_door_xprtcopy(SVCXPRT
*parent
)
441 struct svc_door_data
*su
;
443 if ((xprt
= svc_xprt_alloc()) == NULL
)
446 /* LINTED pointer alignment */
447 SVCEXT(xprt
)->parent
= parent
;
448 /* LINTED pointer alignment */
449 SVCEXT(xprt
)->flags
= SVCEXT(parent
)->flags
;
451 xprt
->xp_fd
= parent
->xp_fd
;
452 xprt
->xp_port
= parent
->xp_port
;
453 xprt
->xp_ops
= svc_door_ops();
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
);
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");
467 svc_door_xprtfree(xprt
);
471 xprt
->xp_type
= parent
->xp_type
;
473 if ((su
= malloc(sizeof (struct svc_door_data
))) == NULL
) {
474 svc_door_xprtfree(xprt
);
477 /* LINTED pointer alignment */
478 su
->su_iosz
= su_data(parent
)->su_iosz
;
479 /* LINTED pointer alignment */
480 su
->call_info
= su_data(parent
)->call_info
;
482 xprt
->xp_p2
= (caddr_t
)su
; /* su_data(xprt) = su */
483 xprt
->xp_verf
.oa_base
= su
->su_verfbody
;
490 get_xprt_copy(SVCXPRT
*parent
, char *buf
)
492 /* LINTED pointer alignment */
493 SVCXPRT_LIST
*xlist
= SVCEXT(parent
)->my_xlist
;
496 struct svc_door_data
*su
;
500 xlist
->next
= xret
->next
;
503 /* LINTED pointer alignment */
504 svc_flags(xprt
) = svc_flags(parent
);
506 xprt
= svc_door_xprtcopy(parent
);
509 /* LINTED pointer alignment */
510 SVCEXT(parent
)->refcnt
++;
511 /* LINTED pointer alignment */
520 return_xprt_copy(SVCXPRT
*xprt
)
523 SVCXPRT_LIST
*xhead
, *xlist
;
524 /* LINTED pointer alignment */
525 int len
= su_data(xprt
)->len
;
527 (void) mutex_lock(&svc_door_mutex
);
528 /* LINTED pointer alignment */
529 if ((parent
= SVCEXT(xprt
)->parent
) == NULL
) {
530 (void) mutex_unlock(&svc_door_mutex
);
533 /* LINTED pointer alignment */
534 xhead
= SVCEXT(parent
)->my_xlist
;
535 /* LINTED pointer alignment */
536 xlist
= SVCEXT(xprt
)->my_xlist
;
537 xlist
->next
= xhead
->next
;
539 /* LINTED pointer alignment */
540 SVCEXT(parent
)->refcnt
--;
543 * Propagate any error flags. This is done in both directions to
544 * ensure that if one child gets an error, everyone will see it
545 * (even if there are multiple outstanding children) and the
546 * door will get closed.
548 /* LINTED pointer alignment */
549 svc_flags(xprt
) |= svc_flags(parent
);
550 /* LINTED pointer alignment */
551 if (svc_defunct(xprt
)) {
552 /* LINTED pointer alignment */
553 svc_flags(parent
) |= SVC_DEFUNCT
;
554 /* LINTED pointer cast */
555 if (SVCEXT(parent
)->refcnt
== 0)
556 svc_door_destroy_pvt(xprt
);
558 (void) mutex_unlock(&svc_door_mutex
);
563 static enum xprt_stat
564 svc_door_stat(SVCXPRT
*xprt
)
570 svc_door_recv(SVCXPRT
*xprt
, struct rpc_msg
*msg
)
572 /* LINTED pointer alignment */
573 struct svc_door_data
*su
= su_data(xprt
);
574 XDR
*xdrs
= &(su
->su_xdrs
);
576 xdrmem_create(xdrs
, su
->argbuf
, su
->arglen
, XDR_DECODE
);
577 if (!xdr_callmsg(xdrs
, msg
))
579 su
->su_xid
= msg
->rm_xid
;
584 svc_door_reply(SVCXPRT
*xprt
, struct rpc_msg
*msg
)
586 /* LINTED pointer alignment */
587 struct svc_door_data
*su
= su_data(xprt
);
588 XDR
*xdrs
= &(su
->su_xdrs
);
590 xdrmem_create(xdrs
, su
->buf
, su
->su_iosz
, XDR_ENCODE
);
591 msg
->rm_xid
= su
->su_xid
;
592 if (xdr_replymsg(xdrs
, msg
)) {
593 su
->len
= (int)XDR_GETPOS(xdrs
);
600 svc_door_getargs(SVCXPRT
*xprt
, xdrproc_t xdr_args
, caddr_t args_ptr
)
602 /* LINTED pointer alignment */
603 return ((*xdr_args
)(&(su_data(xprt
)->su_xdrs
), args_ptr
));
607 svc_door_freeargs(SVCXPRT
*xprt
, xdrproc_t xdr_args
, caddr_t args_ptr
)
609 /* LINTED pointer alignment */
610 XDR
*xdrs
= &(su_data(xprt
)->su_xdrs
);
612 xdrs
->x_op
= XDR_FREE
;
613 return ((*xdr_args
)(xdrs
, args_ptr
));
617 svc_door_destroy(SVCXPRT
*xprt
)
619 (void) mutex_lock(&svc_door_mutex
);
620 svc_door_destroy_pvt(xprt
);
621 (void) mutex_unlock(&svc_door_mutex
);
625 svc_door_destroy_pvt(SVCXPRT
*xprt
)
627 /* LINTED pointer alignment */
628 if (SVCEXT(xprt
)->parent
)
629 /* LINTED pointer alignment */
630 xprt
= SVCEXT(xprt
)->parent
;
631 /* LINTED pointer alignment */
632 svc_flags(xprt
) |= SVC_DEFUNCT
;
633 /* LINTED pointer alignment */
634 if (SVCEXT(xprt
)->refcnt
> 0)
637 __svc_rm_from_xlist(&dxlist
, xprt
, NULL
);
640 (void) fdetach(xprt
->xp_tp
);
641 (void) unlink(xprt
->xp_tp
);
643 (void) door_revoke(xprt
->xp_fd
);
645 svc_xprt_destroy(xprt
);
646 if (--svc_ndoorfds
== 0)
647 /* wake up door dispatching */
648 (void) cond_signal(&svc_door_waitcv
);
653 svc_door_control(SVCXPRT
*xprt
, const uint_t rq
, void *in
)
655 extern int __rpc_legal_connmaxrec(int);
661 case SVCSET_CONNMAXREC
:
662 tmp
= __rpc_legal_connmaxrec(*(int *)in
);
664 door_param
= (tmp
== 0)? SIZE_MAX
:
665 (size_t)(ssize_t
)tmp
;
666 if (door_setparam(xprt
->xp_fd
, DOOR_PARAM_DATA_MAX
,
672 case SVCGET_CONNMAXREC
:
673 if (door_getparam(xprt
->xp_fd
, DOOR_PARAM_DATA_MAX
,
675 if (door_param
== SIZE_MAX
)
677 else if (door_param
> INT_MAX
)
679 else if (door_param
> 0)
680 tmp
= (int)door_param
;
692 static struct xp_ops
*
695 static struct xp_ops ops
;
696 extern mutex_t ops_lock
;
698 (void) mutex_lock(&ops_lock
);
699 if (ops
.xp_recv
== NULL
) {
700 ops
.xp_recv
= svc_door_recv
;
701 ops
.xp_stat
= svc_door_stat
;
702 ops
.xp_getargs
= svc_door_getargs
;
703 ops
.xp_reply
= svc_door_reply
;
704 ops
.xp_freeargs
= svc_door_freeargs
;
705 ops
.xp_destroy
= svc_door_destroy
;
706 ops
.xp_control
= svc_door_control
;
708 (void) mutex_unlock(&ops_lock
);
713 * Return door credentials.
717 __svc_get_door_cred(SVCXPRT
*xprt
, svc_local_cred_t
*lcred
)
721 if (door_cred(&dc
) < 0)
723 lcred
->euid
= dc
.dc_euid
;
724 lcred
->egid
= dc
.dc_egid
;
725 lcred
->ruid
= dc
.dc_ruid
;
726 lcred
->rgid
= dc
.dc_rgid
;
727 lcred
->pid
= dc
.dc_pid
;
733 __svc_get_door_ucred(const SVCXPRT
*xprt
, ucred_t
*ucp
)
735 return (door_ucred(&ucp
) == 0);