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.
41 #include <reentrant.h>
42 #include <sys/types.h>
51 #include <rpc/pmap_clnt.h>
56 #define RQCRED_SIZE 400 /* this size is excessive */
58 #define SVC_VERSQUIET 0x0001 /* keep quiet about vers mismatch */
59 #define version_keepquiet(xp) ((u_long)(xp)->xp_p3 & SVC_VERSQUIET)
61 #define max(a, b) (a > b ? a : b)
63 SVCXPRT **__svc_xports;
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 static struct svc_callout *svc_find (rpcprog_t, rpcvers_t,
85 struct svc_callout **, char *);
86 static void __xprt_do_unregister (SVCXPRT * xprt, bool_t dolock);
88 /* *************** SVCXPRT related stuff **************** */
91 * Activate a transport handle.
99 assert (xprt != NULL);
103 rwlock_wrlock (&svc_fd_lock);
104 if (__svc_xports == NULL)
106 __svc_xports = (SVCXPRT **) mem_alloc (FD_SETSIZE * sizeof (SVCXPRT *));
107 if (__svc_xports == NULL)
109 memset (__svc_xports, '\0', FD_SETSIZE * sizeof (SVCXPRT *));
111 if (sock < FD_SETSIZE)
113 __svc_xports[sock] = xprt;
114 FD_SET (sock, &svc_fdset);
115 svc_maxfd = max (svc_maxfd, sock);
117 rwlock_unlock (&svc_fd_lock);
121 xprt_unregister (SVCXPRT * xprt)
123 __xprt_do_unregister (xprt, TRUE);
127 __xprt_unregister_unlocked (SVCXPRT * xprt)
129 __xprt_do_unregister (xprt, FALSE);
133 * De-activate a transport handle.
136 __xprt_do_unregister (xprt, dolock)
142 assert (xprt != NULL);
147 rwlock_wrlock (&svc_fd_lock);
148 if ((sock < FD_SETSIZE) && (__svc_xports[sock] == xprt))
150 __svc_xports[sock] = NULL;
151 FD_CLR (sock, &svc_fdset);
152 if (sock >= svc_maxfd)
154 for (svc_maxfd--; svc_maxfd >= 0; svc_maxfd--)
155 if (__svc_xports[svc_maxfd])
160 rwlock_unlock (&svc_fd_lock);
164 * Add a service program to the callout list.
165 * The dispatch routine will be called when a rpc request for this
166 * program number comes in.
169 svc_reg (xprt, prog, vers, dispatch, nconf)
171 const rpcprog_t prog;
172 const rpcvers_t vers;
173 void (*dispatch) (struct svc_req *, SVCXPRT *);
174 const struct netconfig *nconf;
177 struct svc_callout *prev;
178 struct svc_callout *s;
179 struct netconfig *tnconf;
183 /* VARIABLES PROTECTED BY svc_lock: s, prev, svc_head */
186 netid = strdup (xprt->xp_netid);
189 else if (nconf && nconf->nc_netid)
191 netid = strdup (nconf->nc_netid);
194 else if ((tnconf = __rpcgettp (xprt->xp_fd)) != NULL)
196 netid = strdup (tnconf->nc_netid);
198 freenetconfigent (tnconf);
199 } /* must have been created with svc_raw_create */
200 if ((netid == NULL) && (flag == 1))
205 rwlock_wrlock (&svc_lock);
206 if ((s = svc_find (prog, vers, &prev, netid)) != NULL)
210 if (s->sc_dispatch == dispatch)
211 goto rpcb_it; /* he is registering another xptr */
212 rwlock_unlock (&svc_lock);
215 s = mem_alloc (sizeof (struct svc_callout));
220 rwlock_unlock (&svc_lock);
226 s->sc_dispatch = dispatch;
228 s->sc_next = svc_head;
231 if ((xprt->xp_netid == NULL) && (flag == 1) && netid)
232 ((SVCXPRT *) xprt)->xp_netid = strdup (netid);
235 rwlock_unlock (&svc_lock);
236 /* now register the information with the local binder service */
239 /*LINTED const castaway */
240 dummy = rpcb_set (prog, vers, (struct netconfig *) nconf,
241 &((SVCXPRT *) xprt)->xp_ltaddr);
248 * Remove a service program from the callout list.
251 svc_unreg (prog, vers)
252 const rpcprog_t prog;
253 const rpcvers_t vers;
255 struct svc_callout *prev;
256 struct svc_callout *s;
258 /* unregister the information anyway */
259 (void) rpcb_unset (prog, vers, NULL);
260 rwlock_wrlock (&svc_lock);
261 while ((s = svc_find (prog, vers, &prev, NULL)) != NULL)
265 svc_head = s->sc_next;
269 prev->sc_next = s->sc_next;
273 mem_free (s->sc_netid, sizeof (s->sc_netid) + 1);
274 mem_free (s, sizeof (struct svc_callout));
276 rwlock_unlock (&svc_lock);
279 /* ********************** CALLOUT list related stuff ************* */
283 * Add a service program to the callout list.
284 * The dispatch routine will be called when a rpc request for this
285 * program number comes in.
288 svc_register (xprt, prog, vers, dispatch, protocol)
292 void (*dispatch) (struct svc_req *, SVCXPRT *);
295 struct svc_callout *prev;
296 struct svc_callout *s;
298 assert (xprt != NULL);
299 assert (dispatch != NULL);
301 if ((s = svc_find ((rpcprog_t) prog, (rpcvers_t) vers, &prev, NULL)) !=
304 if (s->sc_dispatch == dispatch)
305 goto pmap_it; /* he is registering another xptr */
308 s = mem_alloc (sizeof (struct svc_callout));
313 s->sc_prog = (rpcprog_t) prog;
314 s->sc_vers = (rpcvers_t) vers;
315 s->sc_dispatch = dispatch;
316 s->sc_next = svc_head;
319 /* now register the information with the local binder service */
322 return (pmap_set (prog, vers, protocol, xprt->xp_port));
328 * Remove a service program from the callout list.
331 svc_unregister (prog, vers)
335 struct svc_callout *prev;
336 struct svc_callout *s;
338 if ((s = svc_find ((rpcprog_t) prog, (rpcvers_t) vers, &prev, NULL)) ==
343 svc_head = s->sc_next;
347 prev->sc_next = s->sc_next;
350 mem_free (s, sizeof (struct svc_callout));
351 /* now unregister the information with the local binder service */
352 (void) pmap_unset (prog, vers);
357 * Search the callout list for a program number, return the callout
360 static struct svc_callout *
361 svc_find (prog, vers, prev, netid)
364 struct svc_callout **prev;
367 struct svc_callout *s, *p;
369 assert (prev != NULL);
372 for (s = svc_head; s != NULL; s = s->sc_next)
374 if (((s->sc_prog == prog) && (s->sc_vers == vers)) &&
375 ((netid == NULL) || (s->sc_netid == NULL) ||
376 (strcmp (netid, s->sc_netid) == 0)))
384 /* ******************* REPLY GENERATION ROUTINES ************ */
387 * Send a reply to an rpc request
390 svc_sendreply (xprt, xdr_results, xdr_location)
392 xdrproc_t xdr_results;
397 assert (xprt != NULL);
399 rply.rm_direction = REPLY;
400 rply.rm_reply.rp_stat = MSG_ACCEPTED;
401 rply.acpted_rply.ar_verf = xprt->xp_verf;
402 rply.acpted_rply.ar_stat = SUCCESS;
403 rply.acpted_rply.ar_results.where = xdr_location;
404 rply.acpted_rply.ar_results.proc = xdr_results;
405 return (SVC_REPLY (xprt, &rply));
409 * No procedure error reply
417 assert (xprt != NULL);
419 rply.rm_direction = REPLY;
420 rply.rm_reply.rp_stat = MSG_ACCEPTED;
421 rply.acpted_rply.ar_verf = xprt->xp_verf;
422 rply.acpted_rply.ar_stat = PROC_UNAVAIL;
423 SVC_REPLY (xprt, &rply);
427 * Can't decode args error reply
435 assert (xprt != NULL);
437 rply.rm_direction = REPLY;
438 rply.rm_reply.rp_stat = MSG_ACCEPTED;
439 rply.acpted_rply.ar_verf = xprt->xp_verf;
440 rply.acpted_rply.ar_stat = GARBAGE_ARGS;
441 SVC_REPLY (xprt, &rply);
448 svcerr_systemerr (xprt)
453 assert (xprt != NULL);
455 rply.rm_direction = REPLY;
456 rply.rm_reply.rp_stat = MSG_ACCEPTED;
457 rply.acpted_rply.ar_verf = xprt->xp_verf;
458 rply.acpted_rply.ar_stat = SYSTEM_ERR;
459 SVC_REPLY (xprt, &rply);
464 * Tell RPC package to not complain about version errors to the client. This
465 * is useful when revving broadcast protocols that sit on a fixed address.
466 * There is really one (or should be only one) example of this kind of
467 * protocol: the portmapper (or rpc binder).
470 __svc_versquiet_on (xprt)
475 tmp = ((u_long) xprt->xp_p3) | SVC_VERSQUIET;
480 __svc_versquiet_off (xprt)
485 tmp = ((u_long) xprt->xp_p3) & ~SVC_VERSQUIET;
493 __svc_versquiet_on (xprt);
497 __svc_versquiet_get (xprt)
500 return ((int) xprt->xp_p3) & SVC_VERSQUIET;
505 * Authentication error reply
508 svcerr_auth (xprt, why)
514 assert (xprt != NULL);
516 rply.rm_direction = REPLY;
517 rply.rm_reply.rp_stat = MSG_DENIED;
518 rply.rjcted_rply.rj_stat = AUTH_ERROR;
519 rply.rjcted_rply.rj_why = why;
520 SVC_REPLY (xprt, &rply);
524 * Auth too weak error reply
527 svcerr_weakauth (xprt)
531 assert (xprt != NULL);
533 svcerr_auth (xprt, AUTH_TOOWEAK);
537 * Program unavailable error reply
545 assert (xprt != NULL);
547 rply.rm_direction = REPLY;
548 rply.rm_reply.rp_stat = MSG_ACCEPTED;
549 rply.acpted_rply.ar_verf = xprt->xp_verf;
550 rply.acpted_rply.ar_stat = PROG_UNAVAIL;
551 SVC_REPLY (xprt, &rply);
555 * Program version mismatch error reply
558 svcerr_progvers (xprt, low_vers, high_vers)
565 assert (xprt != NULL);
567 rply.rm_direction = REPLY;
568 rply.rm_reply.rp_stat = MSG_ACCEPTED;
569 rply.acpted_rply.ar_verf = xprt->xp_verf;
570 rply.acpted_rply.ar_stat = PROG_MISMATCH;
571 rply.acpted_rply.ar_vers.low = (u_int32_t) low_vers;
572 rply.acpted_rply.ar_vers.high = (u_int32_t) high_vers;
573 SVC_REPLY (xprt, &rply);
576 /* ******************* SERVER INPUT STUFF ******************* */
579 * Get server side input from some transport.
581 * Statement of authentication parameters management:
582 * This function owns and manages all authentication parameters, specifically
583 * the "raw" parameters (msg.rm_call.cb_cred and msg.rm_call.cb_verf) and
584 * the "cooked" credentials (rqst->rq_clntcred).
585 * However, this function does not know the structure of the cooked
586 * credentials, so it make the following assumptions:
587 * a) the structure is contiguous (no pointers), and
588 * b) the cred structure size does not exceed RQCRED_SIZE bytes.
589 * In all events, all three parameters are freed upon exit from this routine.
590 * The storage is trivially management on the call stack in user land, but
591 * is mallocated in kernel land.
601 readfds.fds_bits[0] = rdfds;
602 svc_getreqset (&readfds);
606 svc_getreqset (readfds)
610 fd_mask mask, *maskp;
613 assert (readfds != NULL);
615 maskp = readfds->fds_bits;
616 for (sock = 0; sock < FD_SETSIZE; sock += NFDBITS)
618 for (mask = *maskp++; (bit = ffsl(mask)) != 0; mask ^= (1L << (bit - 1)))
620 /* sock has input waiting */
622 svc_getreq_common (fd);
628 svc_getreq_common (fd)
638 char cred_area[2 * MAX_AUTH_BYTES + RQCRED_SIZE];
640 msg.rm_call.cb_cred.oa_base = cred_area;
641 msg.rm_call.cb_verf.oa_base = &(cred_area[MAX_AUTH_BYTES]);
642 r.rq_clntcred = &(cred_area[2 * MAX_AUTH_BYTES]);
644 rwlock_rdlock (&svc_fd_lock);
645 xprt = __svc_xports[fd];
646 rwlock_unlock (&svc_fd_lock);
648 /* But do we control sock? */
650 /* now receive msgs from xprtprt (support batch calls) */
653 if (SVC_RECV (xprt, &msg))
657 /* now find the exported program and call it */
658 struct svc_callout *s;
662 r.rq_prog = msg.rm_call.cb_prog;
663 r.rq_vers = msg.rm_call.cb_vers;
664 r.rq_proc = msg.rm_call.cb_proc;
665 r.rq_cred = msg.rm_call.cb_cred;
666 /* first authenticate the message */
667 why = _gss_authenticate(&r, &msg, &no_dispatch);
670 svcerr_auth (xprt, why);
675 /* now match message with a registered service */
677 low_vers = (rpcvers_t) - 1L;
678 high_vers = (rpcvers_t) 0L;
679 for (s = svc_head; s != NULL; s = s->sc_next)
681 if (s->sc_prog == r.rq_prog)
683 if (s->sc_vers == r.rq_vers)
685 (*s->sc_dispatch) (&r, xprt);
687 } /* found correct version */
689 if (s->sc_vers < low_vers)
690 low_vers = s->sc_vers;
691 if (s->sc_vers > high_vers)
692 high_vers = s->sc_vers;
693 } /* found correct program */
696 * if we got here, the program or version
700 svcerr_progvers (xprt, low_vers, high_vers);
702 svcerr_noprog (xprt);
703 /* Fall through to ... */
706 * Check if the xprt has been disconnected in a
707 * recursive call in the service dispatch routine.
710 rwlock_rdlock (&svc_fd_lock);
712 if (xprt != __svc_xports[fd])
714 rwlock_unlock (&svc_fd_lock);
717 rwlock_unlock (&svc_fd_lock);
719 if ((stat = SVC_STAT (xprt)) == XPRT_DIED)
724 else if ((xprt->xp_auth != NULL) &&
725 (xprt->xp_auth->svc_ah_private == NULL))
727 xprt->xp_auth = NULL;
730 while (stat == XPRT_MOREREQS);
735 svc_getreq_poll (pfdp, pollretval)
742 for (i = fds_found = 0; fds_found < pollretval; i++)
744 struct pollfd *p = &pfdp[i];
748 /* fd has input waiting */
751 * We assume that this function is only called
752 * via someone _select()ing from svc_fdset or
753 * _poll()ing from svc_pollset[]. Thus it's safe
754 * to handle the POLLNVAL event by simply turning
755 * the corresponding bit off in svc_fdset. The
756 * svc_pollset[] array is derived from svc_fdset
757 * and so will also be updated eventually.
759 * XXX Should we do an xprt_unregister() instead?
761 if (p->revents & POLLNVAL)
763 rwlock_wrlock (&svc_fd_lock);
764 FD_CLR (p->fd, &svc_fdset);
765 rwlock_unlock (&svc_fd_lock);
768 svc_getreq_common (p->fd);
774 rpc_control (int what, void *arg)
780 case RPC_SVC_CONNMAXREC_SET:
786 case RPC_SVC_CONNMAXREC_GET:
787 *(int *) arg = __svc_maxrec;