1 /* $NetBSD: svc.c,v 1.30 2010/07/08 20:12:37 tron Exp $ */
4 * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
5 * unrestricted use provided that this legend is included on all tape
6 * media and as a part of the software program in whole or part. Users
7 * may copy or modify Sun RPC without charge, but are not authorized
8 * to license or distribute it to anyone else except as part of a product or
9 * program developed by the user.
11 * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
12 * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
13 * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
15 * Sun RPC is provided with no support and without any obligation on the
16 * part of Sun Microsystems, Inc. to assist in its use, correction,
17 * modification or enhancement.
19 * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
20 * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
21 * OR ANY PART THEREOF.
23 * In no event will Sun Microsystems, Inc. be liable for any lost revenue
24 * or profits or other special, indirect and consequential damages, even if
25 * Sun has been advised of the possibility of such damages.
27 * Sun Microsystems, Inc.
29 * Mountain View, California 94043
32 #include <sys/cdefs.h>
33 #if defined(LIBC_SCCS) && !defined(lint)
35 static char *sccsid
= "@(#)svc.c 1.44 88/02/08 Copyr 1984 Sun Micro";
36 static char *sccsid
= "@(#)svc.c 2.4 88/08/11 4.0 RPCSRC";
38 __RCSID("$NetBSD: svc.c,v 1.30 2010/07/08 20:12:37 tron Exp $");
43 * svc.c, Server-side remote procedure call interface.
45 * There are two sets of procedures here. The xprt routines are
46 * for handling transport handles. The svc routines handle the
47 * list of service routines.
49 * Copyright (C) 1984, Sun Microsystems, Inc.
52 #include "namespace.h"
53 #include "reentrant.h"
54 #include <sys/types.h>
64 #include <rpc/pmap_clnt.h>
67 #include "rpc_internal.h"
70 __weak_alias(svc_getreq
,_svc_getreq
)
71 __weak_alias(svc_getreqset
,_svc_getreqset
)
72 __weak_alias(svc_getreq_common
,_svc_getreq_common
)
73 __weak_alias(svc_register
,_svc_register
)
74 __weak_alias(svc_reg
,_svc_reg
)
75 __weak_alias(svc_unreg
,_svc_unreg
)
76 __weak_alias(svc_sendreply
,_svc_sendreply
)
77 __weak_alias(svc_unregister
,_svc_unregister
)
78 __weak_alias(svcerr_auth
,_svcerr_auth
)
79 __weak_alias(svcerr_decode
,_svcerr_decode
)
80 __weak_alias(svcerr_noproc
,_svcerr_noproc
)
81 __weak_alias(svcerr_noprog
,_svcerr_noprog
)
82 __weak_alias(svcerr_progvers
,_svcerr_progvers
)
83 __weak_alias(svcerr_systemerr
,_svcerr_systemerr
)
84 __weak_alias(svcerr_weakauth
,_svcerr_weakauth
)
85 __weak_alias(xprt_register
,_xprt_register
)
86 __weak_alias(xprt_unregister
,_xprt_unregister
)
87 __weak_alias(rpc_control
,_rpc_control
)
90 SVCXPRT
**__svc_xports
;
93 #define RQCRED_SIZE 400 /* this size is excessive */
95 #define SVC_VERSQUIET 0x0001 /* keep quiet about vers mismatch */
96 #define version_keepquiet(xp) ((u_long)(xp)->xp_p3 & SVC_VERSQUIET)
98 #define max(a, b) (a > b ? a : b)
102 * Each entry represents a set of procedures (an rpc program).
103 * The dispatch routine takes request structs and runs the
104 * apropriate procedure.
106 static struct svc_callout
{
107 struct svc_callout
*sc_next
;
111 void (*sc_dispatch
) __P((struct svc_req
*, SVCXPRT
*));
115 extern rwlock_t svc_lock
;
116 extern rwlock_t svc_fd_lock
;
119 static struct svc_callout
*svc_find
__P((rpcprog_t
, rpcvers_t
,
120 struct svc_callout
**, char *));
121 static void __xprt_do_unregister
__P((SVCXPRT
*xprt
, bool_t dolock
));
123 /* *************** SVCXPRT related stuff **************** */
126 * Activate a transport handle.
134 _DIAGASSERT(xprt
!= NULL
);
138 rwlock_wrlock(&svc_fd_lock
);
139 if (__svc_xports
== NULL
) {
140 __svc_xports
= mem_alloc(FD_SETSIZE
* sizeof(SVCXPRT
*));
141 if (__svc_xports
== NULL
) {
142 warn("xprt_register");
145 memset(__svc_xports
, '\0', FD_SETSIZE
* sizeof(SVCXPRT
*));
147 if (sock
< FD_SETSIZE
) {
148 __svc_xports
[sock
] = xprt
;
149 FD_SET(sock
, &svc_fdset
);
150 svc_maxfd
= max(svc_maxfd
, sock
);
153 rwlock_unlock(&svc_fd_lock
);
157 xprt_unregister(SVCXPRT
*xprt
)
159 __xprt_do_unregister(xprt
, TRUE
);
163 __xprt_unregister_unlocked(SVCXPRT
*xprt
)
165 __xprt_do_unregister(xprt
, FALSE
);
169 * De-activate a transport handle.
172 __xprt_do_unregister(xprt
, dolock
)
178 _DIAGASSERT(xprt
!= NULL
);
183 rwlock_wrlock(&svc_fd_lock
);
184 if ((sock
< FD_SETSIZE
) && (__svc_xports
[sock
] == xprt
)) {
185 __svc_xports
[sock
] = NULL
;
186 FD_CLR(sock
, &svc_fdset
);
187 if (sock
>= svc_maxfd
) {
188 for (svc_maxfd
--; svc_maxfd
>=0; svc_maxfd
--)
189 if (__svc_xports
[svc_maxfd
])
194 rwlock_unlock(&svc_fd_lock
);
198 * Add a service program to the callout list.
199 * The dispatch routine will be called when a rpc request for this
200 * program number comes in.
203 svc_reg(xprt
, prog
, vers
, dispatch
, nconf
)
205 const rpcprog_t prog
;
206 const rpcvers_t vers
;
207 void (*dispatch
) __P((struct svc_req
*, SVCXPRT
*));
208 const struct netconfig
*nconf
;
211 struct svc_callout
*prev
;
212 struct svc_callout
*s
;
213 struct netconfig
*tnconf
;
217 _DIAGASSERT(xprt
!= NULL
);
218 /* XXX: dispatch may be NULL ??? */
220 /* VARIABLES PROTECTED BY svc_lock: s, prev, svc_head */
222 if (xprt
->xp_netid
) {
223 netid
= strdup(xprt
->xp_netid
);
225 } else if (nconf
&& nconf
->nc_netid
) {
226 netid
= strdup(nconf
->nc_netid
);
228 } else if ((tnconf
= __rpcgettp(xprt
->xp_fd
)) != NULL
) {
229 netid
= strdup(tnconf
->nc_netid
);
231 freenetconfigent(tnconf
);
232 } /* must have been created with svc_raw_create */
233 if ((netid
== NULL
) && (flag
== 1)) {
237 rwlock_wrlock(&svc_lock
);
238 if ((s
= svc_find(prog
, vers
, &prev
, netid
)) != NULL
) {
241 if (s
->sc_dispatch
== dispatch
)
242 goto rpcb_it
; /* he is registering another xptr */
243 rwlock_unlock(&svc_lock
);
246 s
= mem_alloc(sizeof (struct svc_callout
));
250 rwlock_unlock(&svc_lock
);
254 if ((xprt
->xp_netid
== NULL
) && (flag
== 1) && netid
)
255 if ((((SVCXPRT
*) xprt
)->xp_netid
= strdup(netid
)) == NULL
) {
257 mem_free(s
, sizeof(struct svc_callout
));
258 rwlock_unlock(&svc_lock
);
264 s
->sc_dispatch
= dispatch
;
266 s
->sc_next
= svc_head
;
270 rwlock_unlock(&svc_lock
);
271 /* now register the information with the local binder service */
273 dummy
= rpcb_set(prog
, vers
, __UNCONST(nconf
),
274 &((SVCXPRT
*) xprt
)->xp_ltaddr
);
281 * Remove a service program from the callout list.
284 svc_unreg(prog
, vers
)
285 const rpcprog_t prog
;
286 const rpcvers_t vers
;
288 struct svc_callout
*prev
;
289 struct svc_callout
*s
;
291 /* unregister the information anyway */
292 (void) rpcb_unset(prog
, vers
, NULL
);
293 rwlock_wrlock(&svc_lock
);
294 while ((s
= svc_find(prog
, vers
, &prev
, NULL
)) != NULL
) {
296 svc_head
= s
->sc_next
;
298 prev
->sc_next
= s
->sc_next
;
302 mem_free(s
->sc_netid
, sizeof (s
->sc_netid
) + 1);
303 mem_free(s
, sizeof (struct svc_callout
));
305 rwlock_unlock(&svc_lock
);
308 /* ********************** CALLOUT list related stuff ************* */
312 * Add a service program to the callout list.
313 * The dispatch routine will be called when a rpc request for this
314 * program number comes in.
317 svc_register(xprt
, prog
, vers
, dispatch
, protocol
)
321 void (*dispatch
) __P((struct svc_req
*, SVCXPRT
*));
324 struct svc_callout
*prev
;
325 struct svc_callout
*s
;
327 _DIAGASSERT(xprt
!= NULL
);
328 _DIAGASSERT(dispatch
!= NULL
);
330 if ((s
= svc_find((rpcprog_t
)prog
, (rpcvers_t
)vers
, &prev
, NULL
)) !=
332 if (s
->sc_dispatch
== dispatch
)
333 goto pmap_it
; /* he is registering another xptr */
336 s
= mem_alloc(sizeof(struct svc_callout
));
340 s
->sc_prog
= (rpcprog_t
)prog
;
341 s
->sc_vers
= (rpcvers_t
)vers
;
342 s
->sc_dispatch
= dispatch
;
343 s
->sc_next
= svc_head
;
346 /* now register the information with the local binder service */
348 return (pmap_set(prog
, vers
, protocol
, xprt
->xp_port
));
354 * Remove a service program from the callout list.
357 svc_unregister(prog
, vers
)
361 struct svc_callout
*prev
;
362 struct svc_callout
*s
;
364 if ((s
= svc_find((rpcprog_t
)prog
, (rpcvers_t
)vers
, &prev
, NULL
)) ==
368 svc_head
= s
->sc_next
;
370 prev
->sc_next
= s
->sc_next
;
373 mem_free(s
, sizeof(struct svc_callout
));
374 /* now unregister the information with the local binder service */
375 (void)pmap_unset(prog
, vers
);
380 * Search the callout list for a program number, return the callout
383 static struct svc_callout
*
384 svc_find(prog
, vers
, prev
, netid
)
387 struct svc_callout
**prev
;
390 struct svc_callout
*s
, *p
;
392 _DIAGASSERT(prev
!= NULL
);
393 /* netid is handled below */
396 for (s
= svc_head
; s
!= NULL
; s
= s
->sc_next
) {
397 if (((s
->sc_prog
== prog
) && (s
->sc_vers
== vers
)) &&
398 ((netid
== NULL
) || (s
->sc_netid
== NULL
) ||
399 (strcmp(netid
, s
->sc_netid
) == 0)))
407 /* ******************* REPLY GENERATION ROUTINES ************ */
410 * Send a reply to an rpc request
413 svc_sendreply(xprt
, xdr_results
, xdr_location
)
415 xdrproc_t xdr_results
;
416 const char *xdr_location
;
420 _DIAGASSERT(xprt
!= NULL
);
422 rply
.rm_direction
= REPLY
;
423 rply
.rm_reply
.rp_stat
= MSG_ACCEPTED
;
424 rply
.acpted_rply
.ar_verf
= xprt
->xp_verf
;
425 rply
.acpted_rply
.ar_stat
= SUCCESS
;
426 rply
.acpted_rply
.ar_results
.where
= xdr_location
;
427 rply
.acpted_rply
.ar_results
.proc
= xdr_results
;
428 return (SVC_REPLY(xprt
, &rply
));
432 * No procedure error reply
440 _DIAGASSERT(xprt
!= NULL
);
442 rply
.rm_direction
= REPLY
;
443 rply
.rm_reply
.rp_stat
= MSG_ACCEPTED
;
444 rply
.acpted_rply
.ar_verf
= xprt
->xp_verf
;
445 rply
.acpted_rply
.ar_stat
= PROC_UNAVAIL
;
446 SVC_REPLY(xprt
, &rply
);
450 * Can't decode args error reply
458 _DIAGASSERT(xprt
!= NULL
);
460 rply
.rm_direction
= REPLY
;
461 rply
.rm_reply
.rp_stat
= MSG_ACCEPTED
;
462 rply
.acpted_rply
.ar_verf
= xprt
->xp_verf
;
463 rply
.acpted_rply
.ar_stat
= GARBAGE_ARGS
;
464 SVC_REPLY(xprt
, &rply
);
471 svcerr_systemerr(xprt
)
476 _DIAGASSERT(xprt
!= NULL
);
478 rply
.rm_direction
= REPLY
;
479 rply
.rm_reply
.rp_stat
= MSG_ACCEPTED
;
480 rply
.acpted_rply
.ar_verf
= xprt
->xp_verf
;
481 rply
.acpted_rply
.ar_stat
= SYSTEM_ERR
;
482 SVC_REPLY(xprt
, &rply
);
487 * Tell RPC package to not complain about version errors to the client. This
488 * is useful when revving broadcast protocols that sit on a fixed address.
489 * There is really one (or should be only one) example of this kind of
490 * protocol: the portmapper (or rpc binder).
493 __svc_versquiet_on(xprt
)
498 _DIAGASSERT(xprt
!= NULL
);
500 tmp
= ((u_long
) xprt
->xp_p3
) | SVC_VERSQUIET
;
501 xprt
->xp_p3
= (caddr_t
) tmp
;
505 __svc_versquiet_off(xprt
)
510 _DIAGASSERT(xprt
!= NULL
);
512 tmp
= ((u_long
) xprt
->xp_p3
) & ~SVC_VERSQUIET
;
513 xprt
->xp_p3
= (caddr_t
) tmp
;
520 __svc_versquiet_on(xprt
);
524 __svc_versquiet_get(xprt
)
528 _DIAGASSERT(xprt
!= NULL
);
530 return ((int) xprt
->xp_p3
) & SVC_VERSQUIET
;
535 * Authentication error reply
538 svcerr_auth(xprt
, why
)
544 _DIAGASSERT(xprt
!= NULL
);
546 rply
.rm_direction
= REPLY
;
547 rply
.rm_reply
.rp_stat
= MSG_DENIED
;
548 rply
.rjcted_rply
.rj_stat
= AUTH_ERROR
;
549 rply
.rjcted_rply
.rj_why
= why
;
550 SVC_REPLY(xprt
, &rply
);
554 * Auth too weak error reply
557 svcerr_weakauth(xprt
)
561 _DIAGASSERT(xprt
!= NULL
);
563 svcerr_auth(xprt
, AUTH_TOOWEAK
);
567 * Program unavailable error reply
575 _DIAGASSERT(xprt
!= NULL
);
577 rply
.rm_direction
= REPLY
;
578 rply
.rm_reply
.rp_stat
= MSG_ACCEPTED
;
579 rply
.acpted_rply
.ar_verf
= xprt
->xp_verf
;
580 rply
.acpted_rply
.ar_stat
= PROG_UNAVAIL
;
581 SVC_REPLY(xprt
, &rply
);
585 * Program version mismatch error reply
588 svcerr_progvers(xprt
, low_vers
, high_vers
)
595 _DIAGASSERT(xprt
!= NULL
);
597 rply
.rm_direction
= REPLY
;
598 rply
.rm_reply
.rp_stat
= MSG_ACCEPTED
;
599 rply
.acpted_rply
.ar_verf
= xprt
->xp_verf
;
600 rply
.acpted_rply
.ar_stat
= PROG_MISMATCH
;
601 rply
.acpted_rply
.ar_vers
.low
= (u_int32_t
)low_vers
;
602 rply
.acpted_rply
.ar_vers
.high
= (u_int32_t
)high_vers
;
603 SVC_REPLY(xprt
, &rply
);
606 /* ******************* SERVER INPUT STUFF ******************* */
609 * Get server side input from some transport.
611 * Statement of authentication parameters management:
612 * This function owns and manages all authentication parameters, specifically
613 * the "raw" parameters (msg.rm_call.cb_cred and msg.rm_call.cb_verf) and
614 * the "cooked" credentials (rqst->rq_clntcred).
615 * However, this function does not know the structure of the cooked
616 * credentials, so it make the following assumptions:
617 * a) the structure is contiguous (no pointers), and
618 * b) the cred structure size does not exceed RQCRED_SIZE bytes.
619 * In all events, all three parameters are freed upon exit from this routine.
620 * The storage is trivially management on the call stack in user land, but
621 * is mallocated in kernel land.
631 readfds
.fds_bits
[0] = (unsigned int)rdfds
;
632 svc_getreqset(&readfds
);
636 svc_getreqset(readfds
)
639 uint32_t mask
, *maskp
;
642 _DIAGASSERT(readfds
!= NULL
);
644 maskp
= readfds
->fds_bits
;
645 for (sock
= 0; sock
< FD_SETSIZE
; sock
+= NFDBITS
) {
646 for (mask
= *maskp
++; (bit
= ffs((int)mask
)) != 0;
647 mask
^= (1 << (bit
- 1))) {
648 /* sock has input waiting */
650 svc_getreq_common(fd
);
656 svc_getreq_common(fd
)
666 char cred_area
[2*MAX_AUTH_BYTES
+ RQCRED_SIZE
];
668 msg
.rm_call
.cb_cred
.oa_base
= cred_area
;
669 msg
.rm_call
.cb_verf
.oa_base
= &(cred_area
[MAX_AUTH_BYTES
]);
670 r
.rq_clntcred
= &(cred_area
[2*MAX_AUTH_BYTES
]);
672 rwlock_rdlock(&svc_fd_lock
);
673 xprt
= __svc_xports
[fd
];
674 rwlock_unlock(&svc_fd_lock
);
676 /* But do we control sock? */
678 /* now receive msgs from xprtprt (support batch calls) */
680 if (SVC_RECV(xprt
, &msg
)) {
682 /* now find the exported program and call it */
683 struct svc_callout
*s
;
687 r
.rq_prog
= msg
.rm_call
.cb_prog
;
688 r
.rq_vers
= msg
.rm_call
.cb_vers
;
689 r
.rq_proc
= msg
.rm_call
.cb_proc
;
690 r
.rq_cred
= msg
.rm_call
.cb_cred
;
691 /* first authenticate the message */
692 if ((why
= _authenticate(&r
, &msg
)) != AUTH_OK
) {
693 svcerr_auth(xprt
, why
);
696 /* now match message with a registered service*/
698 low_vers
= (rpcvers_t
) -1L;
699 high_vers
= (rpcvers_t
) 0L;
700 for (s
= svc_head
; s
!= NULL
; s
= s
->sc_next
) {
701 if (s
->sc_prog
== r
.rq_prog
) {
702 if (s
->sc_vers
== r
.rq_vers
) {
703 (*s
->sc_dispatch
)(&r
, xprt
);
705 } /* found correct version */
707 if (s
->sc_vers
< low_vers
)
708 low_vers
= s
->sc_vers
;
709 if (s
->sc_vers
> high_vers
)
710 high_vers
= s
->sc_vers
;
711 } /* found correct program */
714 * if we got here, the program or version
718 svcerr_progvers(xprt
, low_vers
, high_vers
);
721 /* Fall through to ... */
724 * Check if the xprt has been disconnected in a
725 * recursive call in the service dispatch routine.
728 rwlock_rdlock(&svc_fd_lock
);
729 if (xprt
!= __svc_xports
[fd
]) {
730 rwlock_unlock(&svc_fd_lock
);
733 rwlock_unlock(&svc_fd_lock
);
735 if ((stat
= SVC_STAT(xprt
)) == XPRT_DIED
){
739 } while (stat
== XPRT_MOREREQS
);
744 svc_getreq_poll(pfdp
, pollretval
)
751 _DIAGASSERT(pfdp
!= NULL
);
753 for (i
= fds_found
= 0; fds_found
< pollretval
; i
++) {
754 struct pollfd
*p
= &pfdp
[i
];
757 /* fd has input waiting */
760 * We assume that this function is only called
761 * via someone select()ing from svc_fdset or
762 * pollts()ing from svc_pollset[]. Thus it's safe
763 * to handle the POLLNVAL event by simply turning
764 * the corresponding bit off in svc_fdset. The
765 * svc_pollset[] array is derived from svc_fdset
766 * and so will also be updated eventually.
768 * XXX Should we do an xprt_unregister() instead?
770 if (p
->revents
& POLLNVAL
) {
771 rwlock_wrlock(&svc_fd_lock
);
772 FD_CLR(p
->fd
, &svc_fdset
);
773 rwlock_unlock(&svc_fd_lock
);
775 svc_getreq_common(p
->fd
);
781 rpc_control(int what
, void *arg
)
786 case RPC_SVC_CONNMAXREC_SET
:
792 case RPC_SVC_CONNMAXREC_GET
:
793 *(int *)arg
= __svc_maxrec
;