3 * Copyright (c) 2009, Sun Microsystems, Inc.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met:
8 * - Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * - Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 * - Neither the name of Sun Microsystems, Inc. nor the names of its
14 * contributors may be used to endorse or promote products derived
15 * from this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 * POSSIBILITY OF SUCH DAMAGE.
31 * svc.c, Server-side remote procedure call interface.
33 * There are two sets of procedures here. The xprt routines are
34 * for handling transport handles. The svc routines handle the
35 * list of service routines.
37 * Copyright (C) 1984, Sun Microsystems, Inc.
40 //#include <pthread.h>
42 #include <reentrant.h>
43 #include <sys/types.h>
44 //#include <sys/poll.h>
52 #include <rpc/pmap_clnt.h>
57 #define RQCRED_SIZE 400 /* this size is excessive */
59 #define SVC_VERSQUIET 0x0001 /* keep quiet about vers mismatch */
60 #define version_keepquiet(xp) ((u_long)(xp)->xp_p3 & SVC_VERSQUIET)
63 #define max(a, b) (a > b ? a : b)
68 * Each entry represents a set of procedures (an rpc program).
69 * The dispatch routine takes request structs and runs the
70 * apropriate procedure.
72 static struct svc_callout
74 struct svc_callout
*sc_next
;
78 void (*sc_dispatch
) (struct svc_req
*, SVCXPRT
*);
81 extern rwlock_t svc_lock
;
82 extern rwlock_t svc_fd_lock
;
84 extern struct svc_auth_ops svc_auth_gss_ops
;
87 static struct svc_callout
*svc_find (rpcprog_t
, rpcvers_t
,
88 struct svc_callout
**, char *);
89 static void __xprt_do_unregister (SVCXPRT
* xprt
, bool_t dolock
);
91 /* *************** SVCXPRT related stuff **************** */
94 * Activate a transport handle.
102 assert (xprt
!= NULL
);
106 rwlock_wrlock (&svc_fd_lock
);
107 if (__svc_xports
== NULL
) {
108 __svc_xports
= (SVCXPRT
**) mem_alloc (FD_SETSIZE
* sizeof (SVCXPRT
*));
109 if (__svc_xports
== NULL
) {
110 // XXX Give an error indication?
113 memset (__svc_xports
, 0, FD_SETSIZE
* sizeof (SVCXPRT
*));
116 if (sock
< FD_SETSIZE
) {
117 __svc_xports
[sock
] = xprt
;
118 FD_SET (sock
, &svc_fdset
);
119 svc_maxfd
= max (svc_maxfd
, sock
);
122 fprintf(stderr
, "%s: Yikes! Figure out __svc_xports[] issue!!\n", __FUNCTION__
);
124 rwlock_unlock (&svc_fd_lock
);
128 xprt_unregister (SVCXPRT
* xprt
)
130 __xprt_do_unregister (xprt
, TRUE
);
134 __xprt_unregister_unlocked (SVCXPRT
* xprt
)
136 __xprt_do_unregister (xprt
, FALSE
);
140 * De-activate a transport handle.
143 __xprt_do_unregister (xprt
, dolock
)
149 assert (xprt
!= NULL
);
155 rwlock_wrlock (&svc_fd_lock
);
156 if ((sock
< FD_SETSIZE
) && (__svc_xports
[sock
] == xprt
)) {
157 __svc_xports
[sock
] = NULL
;
158 FD_CLR (sock
, &svc_fdset
);
159 if (sock
>= svc_maxfd
) {
160 for (svc_maxfd
--; svc_maxfd
>= 0; svc_maxfd
--)
161 if (__svc_xports
[svc_maxfd
])
166 rwlock_unlock (&svc_fd_lock
);
168 fprintf(stderr
, "%s: Yikes! Figure out __svc_xports[] issue!!\n", __FUNCTION__
);
173 * Add a service program to the callout list.
174 * The dispatch routine will be called when a rpc request for this
175 * program number comes in.
178 svc_reg (xprt
, prog
, vers
, dispatch
, nconf
)
180 const rpcprog_t prog
;
181 const rpcvers_t vers
;
182 void (*dispatch
) (struct svc_req
*, SVCXPRT
*);
183 const struct netconfig
*nconf
;
186 struct svc_callout
*prev
;
187 struct svc_callout
*s
;
188 struct netconfig
*tnconf
;
192 /* VARIABLES PROTECTED BY svc_lock: s, prev, svc_head */
195 netid
= strdup (xprt
->xp_netid
);
198 else if (nconf
&& nconf
->nc_netid
)
200 netid
= strdup (nconf
->nc_netid
);
203 else if ((tnconf
= __rpcgettp (xprt
->xp_fd
)) != NULL
)
205 netid
= strdup (tnconf
->nc_netid
);
207 freenetconfigent (tnconf
);
208 } /* must have been created with svc_raw_create */
209 if ((netid
== NULL
) && (flag
== 1))
214 rwlock_wrlock (&svc_lock
);
215 if ((s
= svc_find (prog
, vers
, &prev
, netid
)) != NULL
)
219 if (s
->sc_dispatch
== dispatch
)
220 goto rpcb_it
; /* he is registering another xptr */
221 rwlock_unlock (&svc_lock
);
224 s
= mem_alloc (sizeof (struct svc_callout
));
229 rwlock_unlock (&svc_lock
);
235 s
->sc_dispatch
= dispatch
;
237 s
->sc_next
= svc_head
;
240 if ((xprt
->xp_netid
== NULL
) && (flag
== 1) && netid
)
241 ((SVCXPRT
*) xprt
)->xp_netid
= strdup (netid
);
244 rwlock_unlock (&svc_lock
);
245 /* now register the information with the local binder service */
248 /*LINTED const castaway */
249 dummy
= rpcb_set (prog
, vers
, (struct netconfig
*) nconf
,
250 &((SVCXPRT
*) xprt
)->xp_ltaddr
);
257 * Remove a service program from the callout list.
260 svc_unreg (prog
, vers
)
261 const rpcprog_t prog
;
262 const rpcvers_t vers
;
264 struct svc_callout
*prev
;
265 struct svc_callout
*s
;
267 /* unregister the information anyway */
268 (void) rpcb_unset (prog
, vers
, NULL
);
269 rwlock_wrlock (&svc_lock
);
270 while ((s
= svc_find (prog
, vers
, &prev
, NULL
)) != NULL
)
274 svc_head
= s
->sc_next
;
278 prev
->sc_next
= s
->sc_next
;
282 mem_free (s
->sc_netid
, sizeof (s
->sc_netid
) + 1);
283 mem_free (s
, sizeof (struct svc_callout
));
285 rwlock_unlock (&svc_lock
);
288 /* ********************** CALLOUT list related stuff ************* */
292 * Add a service program to the callout list.
293 * The dispatch routine will be called when a rpc request for this
294 * program number comes in.
297 svc_register (xprt
, prog
, vers
, dispatch
, protocol
)
301 void (*dispatch
) (struct svc_req
*, SVCXPRT
*);
304 struct svc_callout
*prev
;
305 struct svc_callout
*s
;
307 assert (xprt
!= NULL
);
308 assert (dispatch
!= NULL
);
310 if ((s
= svc_find ((rpcprog_t
) prog
, (rpcvers_t
) vers
, &prev
, NULL
)) !=
313 if (s
->sc_dispatch
== dispatch
)
314 goto pmap_it
; /* he is registering another xptr */
317 s
= mem_alloc (sizeof (struct svc_callout
));
322 s
->sc_prog
= (rpcprog_t
) prog
;
323 s
->sc_vers
= (rpcvers_t
) vers
;
324 s
->sc_dispatch
= dispatch
;
325 s
->sc_next
= svc_head
;
328 /* now register the information with the local binder service */
331 return (pmap_set (prog
, vers
, protocol
, xprt
->xp_port
));
337 * Remove a service program from the callout list.
340 svc_unregister (prog
, vers
)
344 struct svc_callout
*prev
;
345 struct svc_callout
*s
;
347 if ((s
= svc_find ((rpcprog_t
) prog
, (rpcvers_t
) vers
, &prev
, NULL
)) ==
352 svc_head
= s
->sc_next
;
356 prev
->sc_next
= s
->sc_next
;
359 mem_free (s
, sizeof (struct svc_callout
));
360 /* now unregister the information with the local binder service */
361 (void) pmap_unset (prog
, vers
);
366 * Search the callout list for a program number, return the callout
369 static struct svc_callout
*
370 svc_find (prog
, vers
, prev
, netid
)
373 struct svc_callout
**prev
;
376 struct svc_callout
*s
, *p
;
378 assert (prev
!= NULL
);
381 for (s
= svc_head
; s
!= NULL
; s
= s
->sc_next
)
383 if (((s
->sc_prog
== prog
) && (s
->sc_vers
== vers
)) &&
384 ((netid
== NULL
) || (s
->sc_netid
== NULL
) ||
385 (strcmp (netid
, s
->sc_netid
) == 0)))
393 /* ******************* REPLY GENERATION ROUTINES ************ */
396 * Send a reply to an rpc request
399 svc_sendreply (xprt
, xdr_results
, xdr_location
)
401 xdrproc_t xdr_results
;
406 assert (xprt
!= NULL
);
408 rply
.rm_direction
= REPLY
;
409 rply
.rm_reply
.rp_stat
= MSG_ACCEPTED
;
410 rply
.acpted_rply
.ar_verf
= xprt
->xp_verf
;
411 rply
.acpted_rply
.ar_stat
= SUCCESS
;
412 rply
.acpted_rply
.ar_results
.where
= xdr_location
;
413 rply
.acpted_rply
.ar_results
.proc
= xdr_results
;
414 return (SVC_REPLY (xprt
, &rply
));
418 * No procedure error reply
426 assert (xprt
!= NULL
);
428 rply
.rm_direction
= REPLY
;
429 rply
.rm_reply
.rp_stat
= MSG_ACCEPTED
;
430 rply
.acpted_rply
.ar_verf
= xprt
->xp_verf
;
431 rply
.acpted_rply
.ar_stat
= PROC_UNAVAIL
;
432 SVC_REPLY (xprt
, &rply
);
436 * Can't decode args error reply
444 assert (xprt
!= NULL
);
446 rply
.rm_direction
= REPLY
;
447 rply
.rm_reply
.rp_stat
= MSG_ACCEPTED
;
448 rply
.acpted_rply
.ar_verf
= xprt
->xp_verf
;
449 rply
.acpted_rply
.ar_stat
= GARBAGE_ARGS
;
450 SVC_REPLY (xprt
, &rply
);
457 svcerr_systemerr (xprt
)
462 assert (xprt
!= NULL
);
464 rply
.rm_direction
= REPLY
;
465 rply
.rm_reply
.rp_stat
= MSG_ACCEPTED
;
466 rply
.acpted_rply
.ar_verf
= xprt
->xp_verf
;
467 rply
.acpted_rply
.ar_stat
= SYSTEM_ERR
;
468 SVC_REPLY (xprt
, &rply
);
473 * Tell RPC package to not complain about version errors to the client. This
474 * is useful when revving broadcast protocols that sit on a fixed address.
475 * There is really one (or should be only one) example of this kind of
476 * protocol: the portmapper (or rpc binder).
479 __svc_versquiet_on (xprt
)
484 tmp
= ((u_long
) xprt
->xp_p3
) | SVC_VERSQUIET
;
489 __svc_versquiet_off (xprt
)
494 tmp
= ((u_long
) xprt
->xp_p3
) & ~SVC_VERSQUIET
;
502 __svc_versquiet_on (xprt
);
506 __svc_versquiet_get (xprt
)
509 return ((int) xprt
->xp_p3
) & SVC_VERSQUIET
;
514 * Authentication error reply
517 svcerr_auth (xprt
, why
)
523 assert (xprt
!= NULL
);
525 rply
.rm_direction
= REPLY
;
526 rply
.rm_reply
.rp_stat
= MSG_DENIED
;
527 rply
.rjcted_rply
.rj_stat
= AUTH_ERROR
;
528 rply
.rjcted_rply
.rj_why
= why
;
529 SVC_REPLY (xprt
, &rply
);
533 * Auth too weak error reply
536 svcerr_weakauth (xprt
)
540 assert (xprt
!= NULL
);
542 svcerr_auth (xprt
, AUTH_TOOWEAK
);
546 * Program unavailable error reply
554 assert (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 (xprt
, low_vers
, high_vers
)
574 assert (xprt
!= NULL
);
576 rply
.rm_direction
= REPLY
;
577 rply
.rm_reply
.rp_stat
= MSG_ACCEPTED
;
578 rply
.acpted_rply
.ar_verf
= xprt
->xp_verf
;
579 rply
.acpted_rply
.ar_stat
= PROG_MISMATCH
;
580 rply
.acpted_rply
.ar_vers
.low
= (u_int32_t
) low_vers
;
581 rply
.acpted_rply
.ar_vers
.high
= (u_int32_t
) high_vers
;
582 SVC_REPLY (xprt
, &rply
);
585 /* ******************* SERVER INPUT STUFF ******************* */
588 * Get server side input from some transport.
590 * Statement of authentication parameters management:
591 * This function owns and manages all authentication parameters, specifically
592 * the "raw" parameters (msg.rm_call.cb_cred and msg.rm_call.cb_verf) and
593 * the "cooked" credentials (rqst->rq_clntcred).
594 * However, this function does not know the structure of the cooked
595 * credentials, so it make the following assumptions:
596 * a) the structure is contiguous (no pointers), and
597 * b) the cred structure size does not exceed RQCRED_SIZE bytes.
598 * In all events, all three parameters are freed upon exit from this routine.
599 * The storage is trivially management on the call stack in user land, but
600 * is mallocated in kernel land.
610 //XXX Windows!! readfds.fds_bits[0] = rdfds;
611 svc_getreqset (&readfds
);
615 svc_getreqset (readfds
)
620 fd_mask mask
, *maskp
;
623 assert (readfds
!= NULL
);
625 maskp
= readfds
->fds_bits
;
626 for (sock
= 0; sock
< FD_SETSIZE
; sock
+= NFDBITS
)
628 for (mask
= *maskp
++; (bit
= ffs (mask
)) != 0; mask
^= (1 << (bit
- 1)))
630 /* sock has input waiting */
632 svc_getreq_common (fd
);
636 fprintf(stderr
, "%s: Yikes!\n", __FUNCTION__
);
641 svc_getreq_common (SOCKET fd
)
650 char cred_area
[2 * MAX_AUTH_BYTES
+ RQCRED_SIZE
];
652 msg
.rm_call
.cb_cred
.oa_base
= cred_area
;
653 msg
.rm_call
.cb_verf
.oa_base
= &(cred_area
[MAX_AUTH_BYTES
]);
654 r
.rq_clntcred
= &(cred_area
[2 * MAX_AUTH_BYTES
]);
656 rwlock_rdlock (&svc_fd_lock
);
657 xprt
= __svc_xports
[fd
];
658 rwlock_unlock (&svc_fd_lock
);
660 /* But do we control sock? */
662 /* now receive msgs from xprtprt (support batch calls) */
665 if (SVC_RECV (xprt
, &msg
))
668 /* now find the exported program and call it */
669 struct svc_callout
*s
;
673 r
.rq_prog
= msg
.rm_call
.cb_prog
;
674 r
.rq_vers
= msg
.rm_call
.cb_vers
;
675 r
.rq_proc
= msg
.rm_call
.cb_proc
;
676 r
.rq_cred
= msg
.rm_call
.cb_cred
;
677 /* first authenticate the message */
678 if ((why
= _authenticate (&r
, &msg
)) != AUTH_OK
)
680 svcerr_auth (xprt
, why
);
683 /* now match message with a registered service */
685 low_vers
= (rpcvers_t
) - 1L;
686 high_vers
= (rpcvers_t
) 0L;
687 for (s
= svc_head
; s
!= NULL
; s
= s
->sc_next
)
689 if (s
->sc_prog
== r
.rq_prog
)
691 if (s
->sc_vers
== r
.rq_vers
)
693 (*s
->sc_dispatch
) (&r
, xprt
);
695 } /* found correct version */
697 if (s
->sc_vers
< low_vers
)
698 low_vers
= s
->sc_vers
;
699 if (s
->sc_vers
> high_vers
)
700 high_vers
= s
->sc_vers
;
701 } /* found correct program */
704 * if we got here, the program or version
708 svcerr_progvers (xprt
, low_vers
, high_vers
);
710 svcerr_noprog (xprt
);
711 /* Fall through to ... */
714 * Check if the xprt has been disconnected in a
715 * recursive call in the service dispatch routine.
718 rwlock_rdlock (&svc_fd_lock
);
720 if (xprt
!= __svc_xports
[fd
])
722 rwlock_unlock (&svc_fd_lock
);
725 rwlock_unlock (&svc_fd_lock
);
727 if ((stat
= SVC_STAT (xprt
)) == XPRT_DIED
)
732 else if ((xprt
->xp_auth
!= NULL
)
733 #ifdef HAVE_LIBGSSAPI
734 && (xprt
->xp_auth
->svc_ah_ops
!= &svc_auth_gss_ops
)
737 xprt
->xp_auth
= NULL
;
740 while (stat
== XPRT_MOREREQS
);
745 svc_getreq_poll (pfdp
, pollretval
)
752 for (i
= fds_found
= 0; fds_found
< pollretval
; i
++)
754 struct pollfd
*p
= &pfdp
[i
];
758 /* fd has input waiting */
761 * We assume that this function is only called
762 * via someone _select()ing from svc_fdset or
763 * _poll()ing from svc_pollset[]. Thus it's safe
764 * to handle the POLLNVAL event by simply turning
765 * the corresponding bit off in svc_fdset. The
766 * svc_pollset[] array is derived from svc_fdset
767 * and so will also be updated eventually.
769 * XXX Should we do an xprt_unregister() instead?
771 if (p
->revents
& POLLNVAL
)
773 rwlock_wrlock (&svc_fd_lock
);
774 FD_CLR (p
->fd
, &svc_fdset
);
775 rwlock_unlock (&svc_fd_lock
);
778 svc_getreq_common (p
->fd
);
784 rpc_control (int what
, void *arg
)
790 case RPC_SVC_CONNMAXREC_SET
:
796 case RPC_SVC_CONNMAXREC_GET
:
797 *(int *) arg
= __svc_maxrec
;