1 /* $NetBSD: svc.c,v 1.21 2000/07/06 03:10:35 christos 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 #if defined(LIBC_SCCS) && !defined(lint)
33 static char *sccsid2 = "@(#)svc.c 1.44 88/02/08 Copyr 1984 Sun Micro";
34 static char *sccsid = "@(#)svc.c 2.4 88/08/11 4.0 RPCSRC";
36 #include <sys/cdefs.h>
37 __FBSDID("$FreeBSD$");
40 * svc.c, Server-side remote procedure call interface.
42 * There are two sets of procedures here. The xprt routines are
43 * for handling transport handles. The svc routines handle the
44 * list of service routines.
46 * Copyright (C) 1984, Sun Microsystems, Inc.
49 #include <sys/param.h>
51 #include <sys/kernel.h>
52 #include <sys/malloc.h>
53 #include <sys/mutex.h>
54 #include <sys/queue.h>
55 #include <sys/systm.h>
56 #include <sys/ucred.h>
59 #include <rpc/rpcb_clnt.h>
61 #include <rpc/rpc_com.h>
63 #define SVC_VERSQUIET 0x0001 /* keep quiet about vers mismatch */
64 #define version_keepquiet(xp) ((u_long)(xp)->xp_p3 & SVC_VERSQUIET)
66 static struct svc_callout *svc_find(SVCPOOL *pool, rpcprog_t, rpcvers_t,
68 static void __xprt_do_unregister (SVCXPRT *xprt, bool_t dolock);
70 /* *************** SVCXPRT related stuff **************** */
77 pool = malloc(sizeof(SVCPOOL), M_RPC, M_WAITOK|M_ZERO);
79 mtx_init(&pool->sp_lock, "sp_lock", NULL, MTX_DEF);
80 TAILQ_INIT(&pool->sp_xlist);
81 TAILQ_INIT(&pool->sp_active);
82 TAILQ_INIT(&pool->sp_callouts);
88 svcpool_destroy(SVCPOOL *pool)
91 struct svc_callout *s;
93 mtx_lock(&pool->sp_lock);
95 while (TAILQ_FIRST(&pool->sp_xlist)) {
96 xprt = TAILQ_FIRST(&pool->sp_xlist);
97 mtx_unlock(&pool->sp_lock);
99 mtx_lock(&pool->sp_lock);
102 while (TAILQ_FIRST(&pool->sp_callouts)) {
103 s = TAILQ_FIRST(&pool->sp_callouts);
104 mtx_unlock(&pool->sp_lock);
105 svc_unreg(pool, s->sc_prog, s->sc_vers);
106 mtx_lock(&pool->sp_lock);
109 mtx_destroy(&pool->sp_lock);
114 * Activate a transport handle.
117 xprt_register(SVCXPRT *xprt)
119 SVCPOOL *pool = xprt->xp_pool;
121 mtx_lock(&pool->sp_lock);
122 xprt->xp_registered = TRUE;
123 xprt->xp_active = FALSE;
124 TAILQ_INSERT_TAIL(&pool->sp_xlist, xprt, xp_link);
125 mtx_unlock(&pool->sp_lock);
129 xprt_unregister(SVCXPRT *xprt)
131 __xprt_do_unregister(xprt, TRUE);
135 __xprt_unregister_unlocked(SVCXPRT *xprt)
137 __xprt_do_unregister(xprt, FALSE);
141 * De-activate a transport handle.
144 __xprt_do_unregister(SVCXPRT *xprt, bool_t dolock)
146 SVCPOOL *pool = xprt->xp_pool;
148 //__svc_generic_cleanup(xprt);
151 mtx_lock(&pool->sp_lock);
153 if (xprt->xp_active) {
154 TAILQ_REMOVE(&pool->sp_active, xprt, xp_alink);
155 xprt->xp_active = FALSE;
157 TAILQ_REMOVE(&pool->sp_xlist, xprt, xp_link);
158 xprt->xp_registered = FALSE;
161 mtx_unlock(&pool->sp_lock);
165 xprt_active(SVCXPRT *xprt)
167 SVCPOOL *pool = xprt->xp_pool;
169 mtx_lock(&pool->sp_lock);
171 if (!xprt->xp_active) {
172 TAILQ_INSERT_TAIL(&pool->sp_active, xprt, xp_alink);
173 xprt->xp_active = TRUE;
175 wakeup(&pool->sp_active);
177 mtx_unlock(&pool->sp_lock);
181 xprt_inactive(SVCXPRT *xprt)
183 SVCPOOL *pool = xprt->xp_pool;
185 mtx_lock(&pool->sp_lock);
187 if (xprt->xp_active) {
188 TAILQ_REMOVE(&pool->sp_active, xprt, xp_alink);
189 xprt->xp_active = FALSE;
191 wakeup(&pool->sp_active);
193 mtx_unlock(&pool->sp_lock);
197 * Add a service program to the callout list.
198 * The dispatch routine will be called when a rpc request for this
199 * program number comes in.
202 svc_reg(SVCXPRT *xprt, const rpcprog_t prog, const rpcvers_t vers,
203 void (*dispatch)(struct svc_req *, SVCXPRT *),
204 const struct netconfig *nconf)
206 SVCPOOL *pool = xprt->xp_pool;
207 struct svc_callout *s;
211 /* VARIABLES PROTECTED BY svc_lock: s, svc_head */
213 if (xprt->xp_netid) {
214 netid = strdup(xprt->xp_netid, M_RPC);
216 } else if (nconf && nconf->nc_netid) {
217 netid = strdup(nconf->nc_netid, M_RPC);
219 } /* must have been created with svc_raw_create */
220 if ((netid == NULL) && (flag == 1)) {
224 mtx_lock(&pool->sp_lock);
225 if ((s = svc_find(pool, prog, vers, netid)) != NULL) {
228 if (s->sc_dispatch == dispatch)
229 goto rpcb_it; /* he is registering another xptr */
230 mtx_unlock(&pool->sp_lock);
233 s = malloc(sizeof (struct svc_callout), M_RPC, M_NOWAIT);
237 mtx_unlock(&pool->sp_lock);
243 s->sc_dispatch = dispatch;
245 TAILQ_INSERT_TAIL(&pool->sp_callouts, s, sc_link);
247 if ((xprt->xp_netid == NULL) && (flag == 1) && netid)
248 ((SVCXPRT *) xprt)->xp_netid = strdup(netid, M_RPC);
251 mtx_unlock(&pool->sp_lock);
252 /* now register the information with the local binder service */
255 struct netconfig tnc;
257 dummy = rpcb_set(prog, vers, &tnc,
258 &((SVCXPRT *) xprt)->xp_ltaddr);
265 * Remove a service program from the callout list.
268 svc_unreg(SVCPOOL *pool, const rpcprog_t prog, const rpcvers_t vers)
270 struct svc_callout *s;
272 /* unregister the information anyway */
273 (void) rpcb_unset(prog, vers, NULL);
274 mtx_lock(&pool->sp_lock);
275 while ((s = svc_find(pool, prog, vers, NULL)) != NULL) {
276 TAILQ_REMOVE(&pool->sp_callouts, s, sc_link);
278 mem_free(s->sc_netid, sizeof (s->sc_netid) + 1);
279 mem_free(s, sizeof (struct svc_callout));
281 mtx_unlock(&pool->sp_lock);
284 /* ********************** CALLOUT list related stuff ************* */
287 * Search the callout list for a program number, return the callout
290 static struct svc_callout *
291 svc_find(SVCPOOL *pool, rpcprog_t prog, rpcvers_t vers, char *netid)
293 struct svc_callout *s;
295 mtx_assert(&pool->sp_lock, MA_OWNED);
296 TAILQ_FOREACH(s, &pool->sp_callouts, sc_link) {
297 if (s->sc_prog == prog && s->sc_vers == vers
298 && (netid == NULL || s->sc_netid == NULL ||
299 strcmp(netid, s->sc_netid) == 0))
306 /* ******************* REPLY GENERATION ROUTINES ************ */
309 * Send a reply to an rpc request
312 svc_sendreply(SVCXPRT *xprt, xdrproc_t xdr_results, void * xdr_location)
316 rply.rm_direction = REPLY;
317 rply.rm_reply.rp_stat = MSG_ACCEPTED;
318 rply.acpted_rply.ar_verf = xprt->xp_verf;
319 rply.acpted_rply.ar_stat = SUCCESS;
320 rply.acpted_rply.ar_results.where = xdr_location;
321 rply.acpted_rply.ar_results.proc = xdr_results;
323 return (SVC_REPLY(xprt, &rply));
327 * No procedure error reply
330 svcerr_noproc(SVCXPRT *xprt)
334 rply.rm_direction = REPLY;
335 rply.rm_reply.rp_stat = MSG_ACCEPTED;
336 rply.acpted_rply.ar_verf = xprt->xp_verf;
337 rply.acpted_rply.ar_stat = PROC_UNAVAIL;
339 SVC_REPLY(xprt, &rply);
343 * Can't decode args error reply
346 svcerr_decode(SVCXPRT *xprt)
350 rply.rm_direction = REPLY;
351 rply.rm_reply.rp_stat = MSG_ACCEPTED;
352 rply.acpted_rply.ar_verf = xprt->xp_verf;
353 rply.acpted_rply.ar_stat = GARBAGE_ARGS;
355 SVC_REPLY(xprt, &rply);
362 svcerr_systemerr(SVCXPRT *xprt)
366 rply.rm_direction = REPLY;
367 rply.rm_reply.rp_stat = MSG_ACCEPTED;
368 rply.acpted_rply.ar_verf = xprt->xp_verf;
369 rply.acpted_rply.ar_stat = SYSTEM_ERR;
371 SVC_REPLY(xprt, &rply);
375 * Authentication error reply
378 svcerr_auth(SVCXPRT *xprt, enum auth_stat why)
382 rply.rm_direction = REPLY;
383 rply.rm_reply.rp_stat = MSG_DENIED;
384 rply.rjcted_rply.rj_stat = AUTH_ERROR;
385 rply.rjcted_rply.rj_why = why;
387 SVC_REPLY(xprt, &rply);
391 * Auth too weak error reply
394 svcerr_weakauth(SVCXPRT *xprt)
397 svcerr_auth(xprt, AUTH_TOOWEAK);
401 * Program unavailable error reply
404 svcerr_noprog(SVCXPRT *xprt)
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 = PROG_UNAVAIL;
413 SVC_REPLY(xprt, &rply);
417 * Program version mismatch error reply
420 svcerr_progvers(SVCXPRT *xprt, rpcvers_t low_vers, rpcvers_t high_vers)
424 rply.rm_direction = REPLY;
425 rply.rm_reply.rp_stat = MSG_ACCEPTED;
426 rply.acpted_rply.ar_verf = xprt->xp_verf;
427 rply.acpted_rply.ar_stat = PROG_MISMATCH;
428 rply.acpted_rply.ar_vers.low = (uint32_t)low_vers;
429 rply.acpted_rply.ar_vers.high = (uint32_t)high_vers;
431 SVC_REPLY(xprt, &rply);
434 /* ******************* SERVER INPUT STUFF ******************* */
437 * Get server side input from some transport.
439 * Statement of authentication parameters management:
440 * This function owns and manages all authentication parameters, specifically
441 * the "raw" parameters (msg.rm_call.cb_cred and msg.rm_call.cb_verf) and
442 * the "cooked" credentials (rqst->rq_clntcred).
443 * In-kernel, we represent non-trivial cooked creds with struct ucred.
444 * In all events, all three parameters are freed upon exit from this routine.
445 * The storage is trivially management on the call stack in user land, but
446 * is mallocated in kernel land.
450 svc_getreq(SVCXPRT *xprt)
452 SVCPOOL *pool = xprt->xp_pool;
459 char cred_area[2*MAX_AUTH_BYTES + sizeof(struct xucred)];
461 msg.rm_call.cb_cred.oa_base = cred_area;
462 msg.rm_call.cb_verf.oa_base = &cred_area[MAX_AUTH_BYTES];
463 r.rq_clntcred = &cred_area[2*MAX_AUTH_BYTES];
465 /* now receive msgs from xprtprt (support batch calls) */
467 if (SVC_RECV(xprt, &msg)) {
469 /* now find the exported program and call it */
470 struct svc_callout *s;
474 r.rq_prog = msg.rm_call.cb_prog;
475 r.rq_vers = msg.rm_call.cb_vers;
476 r.rq_proc = msg.rm_call.cb_proc;
477 r.rq_cred = msg.rm_call.cb_cred;
478 /* first authenticate the message */
479 if ((why = _authenticate(&r, &msg)) != AUTH_OK) {
480 svcerr_auth(xprt, why);
483 /* now match message with a registered service*/
485 low_vers = (rpcvers_t) -1L;
486 high_vers = (rpcvers_t) 0L;
487 TAILQ_FOREACH(s, &pool->sp_callouts, sc_link) {
488 if (s->sc_prog == r.rq_prog) {
489 if (s->sc_vers == r.rq_vers) {
490 (*s->sc_dispatch)(&r, xprt);
492 } /* found correct version */
494 if (s->sc_vers < low_vers)
495 low_vers = s->sc_vers;
496 if (s->sc_vers > high_vers)
497 high_vers = s->sc_vers;
498 } /* found correct program */
501 * if we got here, the program or version
505 svcerr_progvers(xprt, low_vers, high_vers);
508 /* Fall through to ... */
511 * Check if the xprt has been disconnected in a
512 * recursive call in the service dispatch routine.
515 mtx_lock(&pool->sp_lock);
516 if (!xprt->xp_registered) {
517 mtx_unlock(&pool->sp_lock);
520 mtx_unlock(&pool->sp_lock);
522 if ((stat = SVC_STAT(xprt)) == XPRT_DIED) {
526 } while (stat == XPRT_MOREREQS);
530 svc_run(SVCPOOL *pool)
535 mtx_lock(&pool->sp_lock);
537 pool->sp_exited = FALSE;
539 while (!pool->sp_exited) {
540 xprt = TAILQ_FIRST(&pool->sp_active);
542 error = msleep(&pool->sp_active, &pool->sp_lock, PCATCH,
550 * Move this transport to the end to ensure fairness
551 * when multiple transports are active. If this was
552 * the last queued request, svc_getreq will end up
553 * calling xprt_inactive to remove from the active
556 TAILQ_REMOVE(&pool->sp_active, xprt, xp_alink);
557 TAILQ_INSERT_TAIL(&pool->sp_active, xprt, xp_alink);
559 mtx_unlock(&pool->sp_lock);
561 mtx_lock(&pool->sp_lock);
564 mtx_unlock(&pool->sp_lock);
568 svc_exit(SVCPOOL *pool)
570 mtx_lock(&pool->sp_lock);
571 pool->sp_exited = TRUE;
572 wakeup(&pool->sp_active);
573 mtx_unlock(&pool->sp_lock);