1 /* $NetBSD: svc.c,v 1.34 2013/03/11 20:19:29 tron Exp $ */
4 * Copyright (c) 2010, Oracle America, Inc.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * * Redistributions in binary form must reproduce the above
13 * copyright notice, this list of conditions and the following
14 * disclaimer in the documentation and/or other materials
15 * provided with the distribution.
16 * * Neither the name of the "Oracle America, Inc." nor the names of its
17 * contributors may be used to endorse or promote products derived
18 * from this software without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
25 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
27 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
30 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 #include <sys/cdefs.h>
35 #if defined(LIBC_SCCS) && !defined(lint)
37 static char *sccsid
= "@(#)svc.c 1.44 88/02/08 Copyr 1984 Sun Micro";
38 static char *sccsid
= "@(#)svc.c 2.4 88/08/11 4.0 RPCSRC";
40 __RCSID("$NetBSD: svc.c,v 1.34 2013/03/11 20:19:29 tron Exp $");
45 * svc.c, Server-side remote procedure call interface.
47 * There are two sets of procedures here. The xprt routines are
48 * for handling transport handles. The svc routines handle the
49 * list of service routines.
51 * Copyright (C) 1984, Sun Microsystems, Inc.
54 #include "namespace.h"
55 #include "reentrant.h"
56 #include <sys/types.h>
66 #include <rpc/pmap_clnt.h>
69 #include "svc_fdset.h"
70 #include "rpc_internal.h"
73 __weak_alias(svc_getreq
,_svc_getreq
)
74 __weak_alias(svc_getreqset
,_svc_getreqset
)
75 __weak_alias(svc_getreq_common
,_svc_getreq_common
)
76 __weak_alias(svc_register
,_svc_register
)
77 __weak_alias(svc_reg
,_svc_reg
)
78 __weak_alias(svc_unreg
,_svc_unreg
)
79 __weak_alias(svc_sendreply
,_svc_sendreply
)
80 __weak_alias(svc_unregister
,_svc_unregister
)
81 __weak_alias(svcerr_auth
,_svcerr_auth
)
82 __weak_alias(svcerr_decode
,_svcerr_decode
)
83 __weak_alias(svcerr_noproc
,_svcerr_noproc
)
84 __weak_alias(svcerr_noprog
,_svcerr_noprog
)
85 __weak_alias(svcerr_progvers
,_svcerr_progvers
)
86 __weak_alias(svcerr_systemerr
,_svcerr_systemerr
)
87 __weak_alias(svcerr_weakauth
,_svcerr_weakauth
)
88 __weak_alias(xprt_register
,_xprt_register
)
89 __weak_alias(xprt_unregister
,_xprt_unregister
)
90 __weak_alias(rpc_control
,_rpc_control
)
93 SVCXPRT
**__svc_xports
;
96 #define RQCRED_SIZE 400 /* this size is excessive */
98 #define SVC_VERSQUIET 0x0001 /* keep quiet about vers mismatch */
99 #define version_keepquiet(xp) ((u_long)(xp)->xp_p3 & SVC_VERSQUIET)
101 #define max(a, b) (a > b ? a : b)
105 * Each entry represents a set of procedures (an rpc program).
106 * The dispatch routine takes request structs and runs the
107 * apropriate procedure.
109 static struct svc_callout
{
110 struct svc_callout
*sc_next
;
114 void (*sc_dispatch
)(struct svc_req
*, SVCXPRT
*);
118 extern rwlock_t svc_lock
;
119 extern rwlock_t svc_fd_lock
;
122 static struct svc_callout
*svc_find(rpcprog_t
, rpcvers_t
,
123 struct svc_callout
**, char *);
124 static void __xprt_do_unregister(SVCXPRT
*xprt
, bool_t dolock
);
126 /* *************** SVCXPRT related stuff **************** */
129 * Activate a transport handle.
132 xprt_register(SVCXPRT
*xprt
)
136 _DIAGASSERT(xprt
!= NULL
);
140 rwlock_wrlock(&svc_fd_lock
);
141 if (__svc_xports
== NULL
) {
142 __svc_xports
= mem_alloc(FD_SETSIZE
* sizeof(SVCXPRT
*));
143 if (__svc_xports
== NULL
) {
144 warn("%s: out of memory", __func__
);
147 memset(__svc_xports
, '\0', FD_SETSIZE
* sizeof(SVCXPRT
*));
149 if (sock
>= FD_SETSIZE
) {
150 warnx("%s: socket descriptor %d too large for setsize %u",
151 __func__
, sock
, (unsigned)FD_SETSIZE
);
154 __svc_xports
[sock
] = xprt
;
155 FD_SET(sock
, get_fdset());
156 *get_fdsetmax() = max(*get_fdsetmax(), sock
);
157 rwlock_unlock(&svc_fd_lock
);
161 rwlock_unlock(&svc_fd_lock
);
166 xprt_unregister(SVCXPRT
*xprt
)
168 __xprt_do_unregister(xprt
, TRUE
);
172 __xprt_unregister_unlocked(SVCXPRT
*xprt
)
174 __xprt_do_unregister(xprt
, FALSE
);
178 * De-activate a transport handle.
181 __xprt_do_unregister(SVCXPRT
*xprt
, bool_t dolock
)
185 _DIAGASSERT(xprt
!= NULL
);
190 rwlock_wrlock(&svc_fd_lock
);
191 if ((sock
< FD_SETSIZE
) && (__svc_xports
[sock
] == xprt
)) {
192 __svc_xports
[sock
] = NULL
;
193 FD_CLR(sock
, get_fdset());
194 if (sock
>= *get_fdsetmax()) {
195 for ((*get_fdsetmax())--; *get_fdsetmax() >= 0;
197 if (__svc_xports
[*get_fdsetmax()])
202 rwlock_unlock(&svc_fd_lock
);
206 * Add a service program to the callout list.
207 * The dispatch routine will be called when a rpc request for this
208 * program number comes in.
211 svc_reg(SVCXPRT
*xprt
, const rpcprog_t prog
, const rpcvers_t vers
,
212 void (*dispatch
)(struct svc_req
*, SVCXPRT
*),
213 const struct netconfig
*nconf
)
216 struct svc_callout
*prev
;
217 struct svc_callout
*s
;
218 struct netconfig
*tnconf
;
222 _DIAGASSERT(xprt
!= NULL
);
223 /* XXX: dispatch may be NULL ??? */
225 /* VARIABLES PROTECTED BY svc_lock: s, prev, svc_head */
227 if (xprt
->xp_netid
) {
228 netid
= strdup(xprt
->xp_netid
);
230 } else if (nconf
&& nconf
->nc_netid
) {
231 netid
= strdup(nconf
->nc_netid
);
233 } else if ((tnconf
= __rpcgettp(xprt
->xp_fd
)) != NULL
) {
234 netid
= strdup(tnconf
->nc_netid
);
236 freenetconfigent(tnconf
);
237 } /* must have been created with svc_raw_create */
238 if ((netid
== NULL
) && (flag
== 1)) {
242 rwlock_wrlock(&svc_lock
);
243 if ((s
= svc_find(prog
, vers
, &prev
, netid
)) != NULL
) {
246 if (s
->sc_dispatch
== dispatch
)
247 goto rpcb_it
; /* he is registering another xptr */
248 rwlock_unlock(&svc_lock
);
251 s
= mem_alloc(sizeof (struct svc_callout
));
255 rwlock_unlock(&svc_lock
);
259 if ((xprt
->xp_netid
== NULL
) && (flag
== 1) && netid
)
260 if ((((SVCXPRT
*) xprt
)->xp_netid
= strdup(netid
)) == NULL
) {
262 mem_free(s
, sizeof(struct svc_callout
));
263 rwlock_unlock(&svc_lock
);
269 s
->sc_dispatch
= dispatch
;
271 s
->sc_next
= svc_head
;
275 rwlock_unlock(&svc_lock
);
276 /* now register the information with the local binder service */
278 dummy
= rpcb_set(prog
, vers
, __UNCONST(nconf
),
279 &((SVCXPRT
*) xprt
)->xp_ltaddr
);
286 * Remove a service program from the callout list.
289 svc_unreg(const rpcprog_t prog
, const rpcvers_t vers
)
291 struct svc_callout
*prev
;
292 struct svc_callout
*s
;
294 /* unregister the information anyway */
295 (void) rpcb_unset(prog
, vers
, NULL
);
296 rwlock_wrlock(&svc_lock
);
297 while ((s
= svc_find(prog
, vers
, &prev
, NULL
)) != NULL
) {
299 svc_head
= s
->sc_next
;
301 prev
->sc_next
= s
->sc_next
;
305 mem_free(s
->sc_netid
, sizeof (s
->sc_netid
) + 1);
306 mem_free(s
, sizeof (struct svc_callout
));
308 rwlock_unlock(&svc_lock
);
311 /* ********************** CALLOUT list related stuff ************* */
315 * Add a service program to the callout list.
316 * The dispatch routine will be called when a rpc request for this
317 * program number comes in.
320 svc_register(SVCXPRT
*xprt
, u_long prog
, u_long vers
,
321 void (*dispatch
)(struct svc_req
*, SVCXPRT
*), int protocol
)
323 struct svc_callout
*prev
;
324 struct svc_callout
*s
;
326 _DIAGASSERT(xprt
!= NULL
);
327 _DIAGASSERT(dispatch
!= NULL
);
329 if ((s
= svc_find((rpcprog_t
)prog
, (rpcvers_t
)vers
, &prev
, NULL
)) !=
331 if (s
->sc_dispatch
== dispatch
)
332 goto pmap_it
; /* he is registering another xptr */
335 s
= mem_alloc(sizeof(struct svc_callout
));
339 s
->sc_prog
= (rpcprog_t
)prog
;
340 s
->sc_vers
= (rpcvers_t
)vers
;
341 s
->sc_dispatch
= dispatch
;
342 s
->sc_next
= svc_head
;
345 /* now register the information with the local binder service */
347 return (pmap_set(prog
, vers
, protocol
, xprt
->xp_port
));
353 * Remove a service program from the callout list.
356 svc_unregister(u_long prog
, u_long vers
)
358 struct svc_callout
*prev
;
359 struct svc_callout
*s
;
361 if ((s
= svc_find((rpcprog_t
)prog
, (rpcvers_t
)vers
, &prev
, NULL
)) ==
365 svc_head
= s
->sc_next
;
367 prev
->sc_next
= s
->sc_next
;
370 mem_free(s
, sizeof(struct svc_callout
));
371 /* now unregister the information with the local binder service */
372 (void)pmap_unset(prog
, vers
);
377 * Search the callout list for a program number, return the callout
380 static struct svc_callout
*
381 svc_find(rpcprog_t prog
, rpcvers_t vers
, struct svc_callout
**prev
, char *netid
)
383 struct svc_callout
*s
, *p
;
385 _DIAGASSERT(prev
!= NULL
);
386 /* netid is handled below */
389 for (s
= svc_head
; s
!= NULL
; s
= s
->sc_next
) {
390 if (((s
->sc_prog
== prog
) && (s
->sc_vers
== vers
)) &&
391 ((netid
== NULL
) || (s
->sc_netid
== NULL
) ||
392 (strcmp(netid
, s
->sc_netid
) == 0)))
400 /* ******************* REPLY GENERATION ROUTINES ************ */
403 * Send a reply to an rpc request
406 svc_sendreply(SVCXPRT
*xprt
, xdrproc_t xdr_results
, const char *xdr_location
)
410 _DIAGASSERT(xprt
!= NULL
);
412 rply
.rm_direction
= REPLY
;
413 rply
.rm_reply
.rp_stat
= MSG_ACCEPTED
;
414 rply
.acpted_rply
.ar_verf
= xprt
->xp_verf
;
415 rply
.acpted_rply
.ar_stat
= SUCCESS
;
416 rply
.acpted_rply
.ar_results
.where
= xdr_location
;
417 rply
.acpted_rply
.ar_results
.proc
= xdr_results
;
418 return (SVC_REPLY(xprt
, &rply
));
422 * No procedure error reply
425 svcerr_noproc(SVCXPRT
*xprt
)
429 _DIAGASSERT(xprt
!= NULL
);
431 rply
.rm_direction
= REPLY
;
432 rply
.rm_reply
.rp_stat
= MSG_ACCEPTED
;
433 rply
.acpted_rply
.ar_verf
= xprt
->xp_verf
;
434 rply
.acpted_rply
.ar_stat
= PROC_UNAVAIL
;
435 SVC_REPLY(xprt
, &rply
);
439 * Can't decode args error reply
442 svcerr_decode(SVCXPRT
*xprt
)
446 _DIAGASSERT(xprt
!= NULL
);
448 rply
.rm_direction
= REPLY
;
449 rply
.rm_reply
.rp_stat
= MSG_ACCEPTED
;
450 rply
.acpted_rply
.ar_verf
= xprt
->xp_verf
;
451 rply
.acpted_rply
.ar_stat
= GARBAGE_ARGS
;
452 SVC_REPLY(xprt
, &rply
);
459 svcerr_systemerr(SVCXPRT
*xprt
)
463 _DIAGASSERT(xprt
!= NULL
);
465 rply
.rm_direction
= REPLY
;
466 rply
.rm_reply
.rp_stat
= MSG_ACCEPTED
;
467 rply
.acpted_rply
.ar_verf
= xprt
->xp_verf
;
468 rply
.acpted_rply
.ar_stat
= SYSTEM_ERR
;
469 SVC_REPLY(xprt
, &rply
);
474 * Tell RPC package to not complain about version errors to the client. This
475 * is useful when revving broadcast protocols that sit on a fixed address.
476 * There is really one (or should be only one) example of this kind of
477 * protocol: the portmapper (or rpc binder).
480 __svc_versquiet_on(SVCXPRT
*xprt
)
484 _DIAGASSERT(xprt
!= NULL
);
486 tmp
= ((u_long
) xprt
->xp_p3
) | SVC_VERSQUIET
;
487 xprt
->xp_p3
= (caddr_t
) tmp
;
491 __svc_versquiet_off(SVCXPRT
*xprt
)
495 _DIAGASSERT(xprt
!= NULL
);
497 tmp
= ((u_long
) xprt
->xp_p3
) & ~SVC_VERSQUIET
;
498 xprt
->xp_p3
= (caddr_t
) tmp
;
502 svc_versquiet(SVCXPRT
*xprt
)
504 __svc_versquiet_on(xprt
);
508 __svc_versquiet_get(SVCXPRT
*xprt
)
511 _DIAGASSERT(xprt
!= NULL
);
513 return ((int) xprt
->xp_p3
) & SVC_VERSQUIET
;
518 * Authentication error reply
521 svcerr_auth(SVCXPRT
*xprt
, enum auth_stat why
)
525 _DIAGASSERT(xprt
!= NULL
);
527 rply
.rm_direction
= REPLY
;
528 rply
.rm_reply
.rp_stat
= MSG_DENIED
;
529 rply
.rjcted_rply
.rj_stat
= AUTH_ERROR
;
530 rply
.rjcted_rply
.rj_why
= why
;
531 SVC_REPLY(xprt
, &rply
);
535 * Auth too weak error reply
538 svcerr_weakauth(SVCXPRT
*xprt
)
541 _DIAGASSERT(xprt
!= NULL
);
543 svcerr_auth(xprt
, AUTH_TOOWEAK
);
547 * Program unavailable error reply
550 svcerr_noprog(SVCXPRT
*xprt
)
554 _DIAGASSERT(xprt
!= NULL
);
556 rply
.rm_direction
= REPLY
;
557 rply
.rm_reply
.rp_stat
= MSG_ACCEPTED
;
558 rply
.acpted_rply
.ar_verf
= xprt
->xp_verf
;
559 rply
.acpted_rply
.ar_stat
= PROG_UNAVAIL
;
560 SVC_REPLY(xprt
, &rply
);
564 * Program version mismatch error reply
567 svcerr_progvers(SVCXPRT
*xprt
, rpcvers_t low_vers
, rpcvers_t high_vers
)
571 _DIAGASSERT(xprt
!= NULL
);
573 rply
.rm_direction
= REPLY
;
574 rply
.rm_reply
.rp_stat
= MSG_ACCEPTED
;
575 rply
.acpted_rply
.ar_verf
= xprt
->xp_verf
;
576 rply
.acpted_rply
.ar_stat
= PROG_MISMATCH
;
577 rply
.acpted_rply
.ar_vers
.low
= (u_int32_t
)low_vers
;
578 rply
.acpted_rply
.ar_vers
.high
= (u_int32_t
)high_vers
;
579 SVC_REPLY(xprt
, &rply
);
582 /* ******************* SERVER INPUT STUFF ******************* */
585 * Get server side input from some transport.
587 * Statement of authentication parameters management:
588 * This function owns and manages all authentication parameters, specifically
589 * the "raw" parameters (msg.rm_call.cb_cred and msg.rm_call.cb_verf) and
590 * the "cooked" credentials (rqst->rq_clntcred).
591 * However, this function does not know the structure of the cooked
592 * credentials, so it make the following assumptions:
593 * a) the structure is contiguous (no pointers), and
594 * b) the cred structure size does not exceed RQCRED_SIZE bytes.
595 * In all events, all three parameters are freed upon exit from this routine.
596 * The storage is trivially management on the call stack in user land, but
597 * is mallocated in kernel land.
601 svc_getreq(int rdfds
)
606 readfds
.fds_bits
[0] = (unsigned int)rdfds
;
607 svc_getreqset(&readfds
);
611 svc_getreqset(fd_set
*readfds
)
613 uint32_t mask
, *maskp
;
616 _DIAGASSERT(readfds
!= NULL
);
618 maskp
= readfds
->fds_bits
;
619 for (sock
= 0; sock
< FD_SETSIZE
; sock
+= NFDBITS
) {
620 for (mask
= *maskp
++; (bit
= ffs((int)mask
)) != 0;
621 mask
^= (1 << (bit
- 1))) {
622 /* sock has input waiting */
624 svc_getreq_common(fd
);
630 svc_getreq_common(int fd
)
639 char cred_area
[2*MAX_AUTH_BYTES
+ RQCRED_SIZE
];
641 msg
.rm_call
.cb_cred
.oa_base
= cred_area
;
642 msg
.rm_call
.cb_verf
.oa_base
= &(cred_area
[MAX_AUTH_BYTES
]);
643 r
.rq_clntcred
= &(cred_area
[2*MAX_AUTH_BYTES
]);
645 rwlock_rdlock(&svc_fd_lock
);
646 xprt
= __svc_xports
[fd
];
647 rwlock_unlock(&svc_fd_lock
);
649 /* But do we control sock? */
651 /* now receive msgs from xprtprt (support batch calls) */
653 if (SVC_RECV(xprt
, &msg
)) {
655 /* now find the exported program and call it */
656 struct svc_callout
*s
;
660 r
.rq_prog
= msg
.rm_call
.cb_prog
;
661 r
.rq_vers
= msg
.rm_call
.cb_vers
;
662 r
.rq_proc
= msg
.rm_call
.cb_proc
;
663 r
.rq_cred
= msg
.rm_call
.cb_cred
;
664 /* first authenticate the message */
665 if ((why
= _authenticate(&r
, &msg
)) != AUTH_OK
) {
666 svcerr_auth(xprt
, why
);
669 /* now match message with a registered service*/
671 low_vers
= (rpcvers_t
) -1L;
672 high_vers
= (rpcvers_t
) 0L;
673 for (s
= svc_head
; s
!= NULL
; s
= s
->sc_next
) {
674 if (s
->sc_prog
== r
.rq_prog
) {
675 if (s
->sc_vers
== r
.rq_vers
) {
676 (*s
->sc_dispatch
)(&r
, xprt
);
678 } /* found correct version */
680 if (s
->sc_vers
< low_vers
)
681 low_vers
= s
->sc_vers
;
682 if (s
->sc_vers
> high_vers
)
683 high_vers
= s
->sc_vers
;
684 } /* found correct program */
687 * if we got here, the program or version
691 svcerr_progvers(xprt
, low_vers
, high_vers
);
694 /* Fall through to ... */
697 * Check if the xprt has been disconnected in a
698 * recursive call in the service dispatch routine.
701 rwlock_rdlock(&svc_fd_lock
);
702 if (xprt
!= __svc_xports
[fd
]) {
703 rwlock_unlock(&svc_fd_lock
);
706 rwlock_unlock(&svc_fd_lock
);
708 if ((stat
= SVC_STAT(xprt
)) == XPRT_DIED
){
712 } while (stat
== XPRT_MOREREQS
);
717 svc_getreq_poll(struct pollfd
*pfdp
, int pollretval
)
722 _DIAGASSERT(pfdp
!= NULL
);
724 for (i
= fds_found
= 0; fds_found
< pollretval
; i
++) {
725 struct pollfd
*p
= &pfdp
[i
];
728 /* fd has input waiting */
731 * We assume that this function is only called
732 * via someone select()ing from svc_fdset or
733 * pollts()ing from svc_pollset[]. Thus it's safe
734 * to handle the POLLNVAL event by simply turning
735 * the corresponding bit off in svc_fdset. The
736 * svc_pollset[] array is derived from svc_fdset
737 * and so will also be updated eventually.
739 * XXX Should we do an xprt_unregister() instead?
741 if (p
->revents
& POLLNVAL
) {
742 rwlock_wrlock(&svc_fd_lock
);
743 FD_CLR(p
->fd
, get_fdset());
744 rwlock_unlock(&svc_fd_lock
);
746 svc_getreq_common(p
->fd
);
752 rpc_control(int what
, void *arg
)
757 case RPC_SVC_CONNMAXREC_SET
:
763 case RPC_SVC_CONNMAXREC_GET
:
764 *(int *)arg
= __svc_maxrec
;