174462Salfred/* $NetBSD: svc.c,v 1.21 2000/07/06 03:10:35 christos Exp $ */ 274462Salfred 3261057Smav/*- 4261057Smav * Copyright (c) 2009, Sun Microsystems, Inc. 5261057Smav * All rights reserved. 68870Srgrimes * 7261057Smav * Redistribution and use in source and binary forms, with or without 8261057Smav * modification, are permitted provided that the following conditions are met: 9261057Smav * - Redistributions of source code must retain the above copyright notice, 10261057Smav * this list of conditions and the following disclaimer. 11261057Smav * - Redistributions in binary form must reproduce the above copyright notice, 12261057Smav * this list of conditions and the following disclaimer in the documentation 13261057Smav * and/or other materials provided with the distribution. 14261057Smav * - Neither the name of Sun Microsystems, Inc. nor the names of its 15261057Smav * contributors may be used to endorse or promote products derived 16261057Smav * from this software without specific prior written permission. 17261057Smav * 18261057Smav * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19261057Smav * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20261057Smav * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21261057Smav * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 22261057Smav * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23261057Smav * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24261057Smav * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25261057Smav * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26261057Smav * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27261057Smav * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28261057Smav * POSSIBILITY OF SUCH DAMAGE. 291901Swollman */ 301901Swollman 318870Srgrimes#if defined(LIBC_SCCS) && !defined(lint) 32136581Sobrienstatic char *sccsid2 = "@(#)svc.c 1.44 88/02/08 Copyr 1984 Sun Micro"; 3392990Sobrienstatic char *sccsid = "@(#)svc.c 2.4 88/08/11 4.0 RPCSRC"; 341901Swollman#endif 3592990Sobrien#include <sys/cdefs.h> 3692990Sobrien__FBSDID("$FreeBSD$"); 371901Swollman 381901Swollman/* 391901Swollman * svc.c, Server-side remote procedure call interface. 401901Swollman * 411901Swollman * There are two sets of procedures here. The xprt routines are 421901Swollman * for handling transport handles. The svc routines handle the 431901Swollman * list of service routines. 441901Swollman * 451901Swollman * Copyright (C) 1984, Sun Microsystems, Inc. 461901Swollman */ 471901Swollman 4875094Siedowse#include "namespace.h" 4974462Salfred#include "reentrant.h" 5074462Salfred#include <sys/types.h> 5174462Salfred#include <sys/poll.h> 5274462Salfred#include <assert.h> 5374462Salfred#include <errno.h> 5474462Salfred#include <stdlib.h> 5511666Sphk#include <string.h> 5674462Salfred 571901Swollman#include <rpc/rpc.h> 5874462Salfred#ifdef PORTMAP 591901Swollman#include <rpc/pmap_clnt.h> 6074462Salfred#endif /* PORTMAP */ 6174462Salfred#include "un-namespace.h" 621901Swollman 6374462Salfred#include "rpc_com.h" 64156090Sdeischen#include "mt_misc.h" 6574462Salfred 661901Swollman#define RQCRED_SIZE 400 /* this size is excessive */ 671901Swollman 6874462Salfred#define SVC_VERSQUIET 0x0001 /* keep quiet about vers mismatch */ 69181344Sdfr#define version_keepquiet(xp) (SVC_EXT(xp)->xp_flags & SVC_VERSQUIET) 7074462Salfred 7121087Speter#define max(a, b) (a > b ? a : b) 7216270Sjraynard 731901Swollman/* 741901Swollman * The services list 751901Swollman * Each entry represents a set of procedures (an rpc program). 761901Swollman * The dispatch routine takes request structs and runs the 771901Swollman * apropriate procedure. 781901Swollman */ 791901Swollmanstatic struct svc_callout { 801901Swollman struct svc_callout *sc_next; 8174462Salfred rpcprog_t sc_prog; 8274462Salfred rpcvers_t sc_vers; 8374462Salfred char *sc_netid; 8492905Sobrien void (*sc_dispatch)(struct svc_req *, SVCXPRT *); 851901Swollman} *svc_head; 861901Swollman 8792941Sobrienstatic struct svc_callout *svc_find(rpcprog_t, rpcvers_t, 8892941Sobrien struct svc_callout **, char *); 89109359Smbrstatic void __xprt_do_unregister (SVCXPRT *xprt, bool_t dolock); 9021087Speter 911901Swollman/* *************** SVCXPRT related stuff **************** */ 921901Swollman 931901Swollman/* 941901Swollman * Activate a transport handle. 951901Swollman */ 961901Swollmanvoid 971901Swollmanxprt_register(xprt) 981901Swollman SVCXPRT *xprt; 991901Swollman{ 10074462Salfred int sock; 1011901Swollman 10274462Salfred assert(xprt != NULL); 10321087Speter 10474462Salfred sock = xprt->xp_fd; 10574462Salfred 10674462Salfred rwlock_wrlock(&svc_fd_lock); 107109359Smbr if (__svc_xports == NULL) { 108109359Smbr __svc_xports = (SVCXPRT **) 10974462Salfred mem_alloc(FD_SETSIZE * sizeof(SVCXPRT *)); 110235045Skib if (__svc_xports == NULL) { 111235045Skib rwlock_unlock(&svc_fd_lock); 11274462Salfred return; 113235045Skib } 114109359Smbr memset(__svc_xports, '\0', FD_SETSIZE * sizeof(SVCXPRT *)); 1151901Swollman } 11674462Salfred if (sock < FD_SETSIZE) { 117109359Smbr __svc_xports[sock] = xprt; 1181901Swollman FD_SET(sock, &svc_fdset); 11974462Salfred svc_maxfd = max(svc_maxfd, sock); 1201901Swollman } 12174462Salfred rwlock_unlock(&svc_fd_lock); 1221901Swollman} 1231901Swollman 124109359Smbrvoid 125109359Smbrxprt_unregister(SVCXPRT *xprt) 126109359Smbr{ 127109359Smbr __xprt_do_unregister(xprt, TRUE); 128109359Smbr} 129109359Smbr 130109359Smbrvoid 131109359Smbr__xprt_unregister_unlocked(SVCXPRT *xprt) 132109359Smbr{ 133109359Smbr __xprt_do_unregister(xprt, FALSE); 134109359Smbr} 135109359Smbr 1361901Swollman/* 1378870Srgrimes * De-activate a transport handle. 1381901Swollman */ 139109359Smbrstatic void 140109359Smbr__xprt_do_unregister(xprt, dolock) 1411901Swollman SVCXPRT *xprt; 142109359Smbr bool_t dolock; 1438870Srgrimes{ 14474462Salfred int sock; 1451901Swollman 14674462Salfred assert(xprt != NULL); 14774462Salfred 14874462Salfred sock = xprt->xp_fd; 14974462Salfred 150109359Smbr if (dolock) 151109359Smbr rwlock_wrlock(&svc_fd_lock); 152109359Smbr if ((sock < FD_SETSIZE) && (__svc_xports[sock] == xprt)) { 153109359Smbr __svc_xports[sock] = NULL; 15474462Salfred FD_CLR(sock, &svc_fdset); 15574462Salfred if (sock >= svc_maxfd) { 15674462Salfred for (svc_maxfd--; svc_maxfd>=0; svc_maxfd--) 157109359Smbr if (__svc_xports[svc_maxfd]) 15821087Speter break; 15921087Speter } 1601901Swollman } 161109359Smbr if (dolock) 162109359Smbr rwlock_unlock(&svc_fd_lock); 1631901Swollman} 1641901Swollman 16574462Salfred/* 16674462Salfred * Add a service program to the callout list. 16774462Salfred * The dispatch routine will be called when a rpc request for this 16874462Salfred * program number comes in. 16974462Salfred */ 17074462Salfredbool_t 17174462Salfredsvc_reg(xprt, prog, vers, dispatch, nconf) 17274462Salfred SVCXPRT *xprt; 17374462Salfred const rpcprog_t prog; 17474462Salfred const rpcvers_t vers; 17592905Sobrien void (*dispatch)(struct svc_req *, SVCXPRT *); 17674462Salfred const struct netconfig *nconf; 17774462Salfred{ 17874462Salfred bool_t dummy; 17974462Salfred struct svc_callout *prev; 18074462Salfred struct svc_callout *s; 18174462Salfred struct netconfig *tnconf; 18274462Salfred char *netid = NULL; 18374462Salfred int flag = 0; 1841901Swollman 18574462Salfred/* VARIABLES PROTECTED BY svc_lock: s, prev, svc_head */ 18674462Salfred 18774462Salfred if (xprt->xp_netid) { 18874462Salfred netid = strdup(xprt->xp_netid); 18974462Salfred flag = 1; 19074462Salfred } else if (nconf && nconf->nc_netid) { 19174462Salfred netid = strdup(nconf->nc_netid); 19274462Salfred flag = 1; 19374462Salfred } else if ((tnconf = __rpcgettp(xprt->xp_fd)) != NULL) { 19474462Salfred netid = strdup(tnconf->nc_netid); 19574462Salfred flag = 1; 19674462Salfred freenetconfigent(tnconf); 19774462Salfred } /* must have been created with svc_raw_create */ 19874462Salfred if ((netid == NULL) && (flag == 1)) { 19974462Salfred return (FALSE); 20074462Salfred } 20174462Salfred 20274462Salfred rwlock_wrlock(&svc_lock); 20374462Salfred if ((s = svc_find(prog, vers, &prev, netid)) != NULL) { 20474462Salfred if (netid) 20574462Salfred free(netid); 20674462Salfred if (s->sc_dispatch == dispatch) 20774462Salfred goto rpcb_it; /* he is registering another xptr */ 20874462Salfred rwlock_unlock(&svc_lock); 20974462Salfred return (FALSE); 21074462Salfred } 21174462Salfred s = mem_alloc(sizeof (struct svc_callout)); 21274462Salfred if (s == NULL) { 21374462Salfred if (netid) 21474462Salfred free(netid); 21574462Salfred rwlock_unlock(&svc_lock); 21674462Salfred return (FALSE); 21774462Salfred } 21874462Salfred 21974462Salfred s->sc_prog = prog; 22074462Salfred s->sc_vers = vers; 22174462Salfred s->sc_dispatch = dispatch; 22274462Salfred s->sc_netid = netid; 22374462Salfred s->sc_next = svc_head; 22474462Salfred svc_head = s; 22574462Salfred 22674462Salfred if ((xprt->xp_netid == NULL) && (flag == 1) && netid) 22774462Salfred ((SVCXPRT *) xprt)->xp_netid = strdup(netid); 22874462Salfred 22974462Salfredrpcb_it: 23074462Salfred rwlock_unlock(&svc_lock); 23174462Salfred /* now register the information with the local binder service */ 23274462Salfred if (nconf) { 23374462Salfred /*LINTED const castaway*/ 23474462Salfred dummy = rpcb_set(prog, vers, (struct netconfig *) nconf, 23574462Salfred &((SVCXPRT *) xprt)->xp_ltaddr); 23674462Salfred return (dummy); 23774462Salfred } 23874462Salfred return (TRUE); 23974462Salfred} 24074462Salfred 24174462Salfred/* 24274462Salfred * Remove a service program from the callout list. 24374462Salfred */ 24474462Salfredvoid 24574462Salfredsvc_unreg(prog, vers) 24674462Salfred const rpcprog_t prog; 24774462Salfred const rpcvers_t vers; 24874462Salfred{ 24974462Salfred struct svc_callout *prev; 25074462Salfred struct svc_callout *s; 25174462Salfred 25274462Salfred /* unregister the information anyway */ 25374462Salfred (void) rpcb_unset(prog, vers, NULL); 25474462Salfred rwlock_wrlock(&svc_lock); 25574462Salfred while ((s = svc_find(prog, vers, &prev, NULL)) != NULL) { 25674462Salfred if (prev == NULL) { 25774462Salfred svc_head = s->sc_next; 25874462Salfred } else { 25974462Salfred prev->sc_next = s->sc_next; 26074462Salfred } 26174462Salfred s->sc_next = NULL; 26274462Salfred if (s->sc_netid) 26374462Salfred mem_free(s->sc_netid, sizeof (s->sc_netid) + 1); 26474462Salfred mem_free(s, sizeof (struct svc_callout)); 26574462Salfred } 26674462Salfred rwlock_unlock(&svc_lock); 26774462Salfred} 26874462Salfred 2691901Swollman/* ********************** CALLOUT list related stuff ************* */ 2701901Swollman 27174462Salfred#ifdef PORTMAP 2721901Swollman/* 2731901Swollman * Add a service program to the callout list. 2741901Swollman * The dispatch routine will be called when a rpc request for this 2751901Swollman * program number comes in. 2761901Swollman */ 2771901Swollmanbool_t 2781901Swollmansvc_register(xprt, prog, vers, dispatch, protocol) 2791901Swollman SVCXPRT *xprt; 2801901Swollman u_long prog; 2811901Swollman u_long vers; 28292905Sobrien void (*dispatch)(struct svc_req *, SVCXPRT *); 2831901Swollman int protocol; 2841901Swollman{ 2851901Swollman struct svc_callout *prev; 28674462Salfred struct svc_callout *s; 2871901Swollman 28874462Salfred assert(xprt != NULL); 28974462Salfred assert(dispatch != NULL); 29074462Salfred 29174462Salfred if ((s = svc_find((rpcprog_t)prog, (rpcvers_t)vers, &prev, NULL)) != 29274462Salfred NULL) { 2931901Swollman if (s->sc_dispatch == dispatch) 2941901Swollman goto pmap_it; /* he is registering another xptr */ 2951901Swollman return (FALSE); 2961901Swollman } 29774462Salfred s = mem_alloc(sizeof(struct svc_callout)); 29874462Salfred if (s == NULL) { 2991901Swollman return (FALSE); 3001901Swollman } 30174462Salfred s->sc_prog = (rpcprog_t)prog; 30274462Salfred s->sc_vers = (rpcvers_t)vers; 3031901Swollman s->sc_dispatch = dispatch; 3041901Swollman s->sc_next = svc_head; 3051901Swollman svc_head = s; 3061901Swollmanpmap_it: 3071901Swollman /* now register the information with the local binder service */ 3081901Swollman if (protocol) { 3091901Swollman return (pmap_set(prog, vers, protocol, xprt->xp_port)); 3101901Swollman } 3111901Swollman return (TRUE); 3121901Swollman} 3131901Swollman 3141901Swollman/* 3151901Swollman * Remove a service program from the callout list. 3161901Swollman */ 3171901Swollmanvoid 3181901Swollmansvc_unregister(prog, vers) 3191901Swollman u_long prog; 3201901Swollman u_long vers; 3211901Swollman{ 3221901Swollman struct svc_callout *prev; 32374462Salfred struct svc_callout *s; 3241901Swollman 32574462Salfred if ((s = svc_find((rpcprog_t)prog, (rpcvers_t)vers, &prev, NULL)) == 32674462Salfred NULL) 3271901Swollman return; 32874462Salfred if (prev == NULL) { 3291901Swollman svc_head = s->sc_next; 3301901Swollman } else { 3311901Swollman prev->sc_next = s->sc_next; 3321901Swollman } 33374462Salfred s->sc_next = NULL; 33474462Salfred mem_free(s, sizeof(struct svc_callout)); 3351901Swollman /* now unregister the information with the local binder service */ 3361901Swollman (void)pmap_unset(prog, vers); 3371901Swollman} 33874462Salfred#endif /* PORTMAP */ 3391901Swollman 3401901Swollman/* 3411901Swollman * Search the callout list for a program number, return the callout 3421901Swollman * struct. 3431901Swollman */ 3441901Swollmanstatic struct svc_callout * 34574462Salfredsvc_find(prog, vers, prev, netid) 34674462Salfred rpcprog_t prog; 34774462Salfred rpcvers_t vers; 3481901Swollman struct svc_callout **prev; 34974462Salfred char *netid; 3501901Swollman{ 35174462Salfred struct svc_callout *s, *p; 3521901Swollman 35374462Salfred assert(prev != NULL); 35474462Salfred 35574462Salfred p = NULL; 35674462Salfred for (s = svc_head; s != NULL; s = s->sc_next) { 35774462Salfred if (((s->sc_prog == prog) && (s->sc_vers == vers)) && 35874462Salfred ((netid == NULL) || (s->sc_netid == NULL) || 35974462Salfred (strcmp(netid, s->sc_netid) == 0))) 36074462Salfred break; 3611901Swollman p = s; 3621901Swollman } 3631901Swollman *prev = p; 3641901Swollman return (s); 3651901Swollman} 3661901Swollman 3671901Swollman/* ******************* REPLY GENERATION ROUTINES ************ */ 3681901Swollman 3691901Swollman/* 3701901Swollman * Send a reply to an rpc request 3711901Swollman */ 3721901Swollmanbool_t 3731901Swollmansvc_sendreply(xprt, xdr_results, xdr_location) 37474462Salfred SVCXPRT *xprt; 3751901Swollman xdrproc_t xdr_results; 37695658Sdes void * xdr_location; 3771901Swollman{ 37874462Salfred struct rpc_msg rply; 3791901Swollman 38074462Salfred assert(xprt != NULL); 38174462Salfred 38274462Salfred rply.rm_direction = REPLY; 38374462Salfred rply.rm_reply.rp_stat = MSG_ACCEPTED; 38474462Salfred rply.acpted_rply.ar_verf = xprt->xp_verf; 3851901Swollman rply.acpted_rply.ar_stat = SUCCESS; 3861901Swollman rply.acpted_rply.ar_results.where = xdr_location; 3871901Swollman rply.acpted_rply.ar_results.proc = xdr_results; 38874462Salfred return (SVC_REPLY(xprt, &rply)); 3891901Swollman} 3901901Swollman 3911901Swollman/* 3921901Swollman * No procedure error reply 3931901Swollman */ 3941901Swollmanvoid 3951901Swollmansvcerr_noproc(xprt) 39674462Salfred SVCXPRT *xprt; 3971901Swollman{ 3981901Swollman struct rpc_msg rply; 3991901Swollman 40074462Salfred assert(xprt != NULL); 40174462Salfred 4021901Swollman rply.rm_direction = REPLY; 4031901Swollman rply.rm_reply.rp_stat = MSG_ACCEPTED; 4041901Swollman rply.acpted_rply.ar_verf = xprt->xp_verf; 4051901Swollman rply.acpted_rply.ar_stat = PROC_UNAVAIL; 4061901Swollman SVC_REPLY(xprt, &rply); 4071901Swollman} 4081901Swollman 4091901Swollman/* 4101901Swollman * Can't decode args error reply 4111901Swollman */ 4121901Swollmanvoid 4131901Swollmansvcerr_decode(xprt) 41474462Salfred SVCXPRT *xprt; 4151901Swollman{ 41674462Salfred struct rpc_msg rply; 4171901Swollman 41874462Salfred assert(xprt != NULL); 41974462Salfred 42074462Salfred rply.rm_direction = REPLY; 42174462Salfred rply.rm_reply.rp_stat = MSG_ACCEPTED; 4221901Swollman rply.acpted_rply.ar_verf = xprt->xp_verf; 4231901Swollman rply.acpted_rply.ar_stat = GARBAGE_ARGS; 42474462Salfred SVC_REPLY(xprt, &rply); 4251901Swollman} 4261901Swollman 4271901Swollman/* 4281901Swollman * Some system error 4291901Swollman */ 4301901Swollmanvoid 4311901Swollmansvcerr_systemerr(xprt) 43274462Salfred SVCXPRT *xprt; 4331901Swollman{ 43474462Salfred struct rpc_msg rply; 4351901Swollman 43674462Salfred assert(xprt != NULL); 43774462Salfred 43874462Salfred rply.rm_direction = REPLY; 43974462Salfred rply.rm_reply.rp_stat = MSG_ACCEPTED; 4401901Swollman rply.acpted_rply.ar_verf = xprt->xp_verf; 4411901Swollman rply.acpted_rply.ar_stat = SYSTEM_ERR; 44274462Salfred SVC_REPLY(xprt, &rply); 4431901Swollman} 4441901Swollman 44574462Salfred#if 0 4461901Swollman/* 44774462Salfred * Tell RPC package to not complain about version errors to the client. This 44874462Salfred * is useful when revving broadcast protocols that sit on a fixed address. 44974462Salfred * There is really one (or should be only one) example of this kind of 45074462Salfred * protocol: the portmapper (or rpc binder). 45174462Salfred */ 45274462Salfredvoid 45374462Salfred__svc_versquiet_on(xprt) 45474462Salfred SVCXPRT *xprt; 45574462Salfred{ 45674462Salfred 457181344Sdfr SVC_EXT(xprt)->xp_flags |= SVC_VERSQUIET; 45874462Salfred} 45974462Salfred 46074462Salfredvoid 46174462Salfred__svc_versquiet_off(xprt) 46274462Salfred SVCXPRT *xprt; 46374462Salfred{ 46474462Salfred 465181344Sdfr SVC_EXT(xprt)->xp_flags &= ~SVC_VERSQUIET; 46674462Salfred} 46774462Salfred 46874462Salfredvoid 46974462Salfredsvc_versquiet(xprt) 47074462Salfred SVCXPRT *xprt; 47174462Salfred{ 47274462Salfred __svc_versquiet_on(xprt); 47374462Salfred} 47474462Salfred 47574462Salfredint 47674462Salfred__svc_versquiet_get(xprt) 47774462Salfred SVCXPRT *xprt; 47874462Salfred{ 479181344Sdfr 480181344Sdfr return (SVC_EXT(xprt)->xp_flags & SVC_VERSQUIET); 48174462Salfred} 48274462Salfred#endif 48374462Salfred 48474462Salfred/* 4851901Swollman * Authentication error reply 4861901Swollman */ 4871901Swollmanvoid 4881901Swollmansvcerr_auth(xprt, why) 4891901Swollman SVCXPRT *xprt; 4901901Swollman enum auth_stat why; 4911901Swollman{ 4921901Swollman struct rpc_msg rply; 4931901Swollman 49474462Salfred assert(xprt != NULL); 49574462Salfred 4961901Swollman rply.rm_direction = REPLY; 4971901Swollman rply.rm_reply.rp_stat = MSG_DENIED; 4981901Swollman rply.rjcted_rply.rj_stat = AUTH_ERROR; 4991901Swollman rply.rjcted_rply.rj_why = why; 5001901Swollman SVC_REPLY(xprt, &rply); 5011901Swollman} 5021901Swollman 5031901Swollman/* 5041901Swollman * Auth too weak error reply 5051901Swollman */ 5061901Swollmanvoid 5071901Swollmansvcerr_weakauth(xprt) 5081901Swollman SVCXPRT *xprt; 5091901Swollman{ 5101901Swollman 51174462Salfred assert(xprt != NULL); 51274462Salfred 5131901Swollman svcerr_auth(xprt, AUTH_TOOWEAK); 5141901Swollman} 5151901Swollman 5161901Swollman/* 5171901Swollman * Program unavailable error reply 5181901Swollman */ 51974462Salfredvoid 5201901Swollmansvcerr_noprog(xprt) 52174462Salfred SVCXPRT *xprt; 5221901Swollman{ 52374462Salfred struct rpc_msg rply; 5241901Swollman 52574462Salfred assert(xprt != NULL); 52674462Salfred 52774462Salfred rply.rm_direction = REPLY; 52874462Salfred rply.rm_reply.rp_stat = MSG_ACCEPTED; 52974462Salfred rply.acpted_rply.ar_verf = xprt->xp_verf; 5301901Swollman rply.acpted_rply.ar_stat = PROG_UNAVAIL; 5311901Swollman SVC_REPLY(xprt, &rply); 5321901Swollman} 5331901Swollman 5341901Swollman/* 5351901Swollman * Program version mismatch error reply 5361901Swollman */ 53774462Salfredvoid 5381901Swollmansvcerr_progvers(xprt, low_vers, high_vers) 53974462Salfred SVCXPRT *xprt; 54074462Salfred rpcvers_t low_vers; 54174462Salfred rpcvers_t high_vers; 5421901Swollman{ 5431901Swollman struct rpc_msg rply; 5441901Swollman 54574462Salfred assert(xprt != NULL); 54674462Salfred 5471901Swollman rply.rm_direction = REPLY; 5481901Swollman rply.rm_reply.rp_stat = MSG_ACCEPTED; 5491901Swollman rply.acpted_rply.ar_verf = xprt->xp_verf; 5501901Swollman rply.acpted_rply.ar_stat = PROG_MISMATCH; 55174462Salfred rply.acpted_rply.ar_vers.low = (u_int32_t)low_vers; 55274462Salfred rply.acpted_rply.ar_vers.high = (u_int32_t)high_vers; 5531901Swollman SVC_REPLY(xprt, &rply); 5541901Swollman} 5551901Swollman 556181344Sdfr/* 557181344Sdfr * Allocate a new server transport structure. All fields are 558181344Sdfr * initialized to zero and xp_p3 is initialized to point at an 559181344Sdfr * extension structure to hold various flags and authentication 560181344Sdfr * parameters. 561181344Sdfr */ 562181344SdfrSVCXPRT * 563181344Sdfrsvc_xprt_alloc() 564181344Sdfr{ 565181344Sdfr SVCXPRT *xprt; 566181344Sdfr SVCXPRT_EXT *ext; 567181344Sdfr 568181344Sdfr xprt = mem_alloc(sizeof(SVCXPRT)); 569235045Skib if (xprt == NULL) 570235045Skib return (NULL); 571181344Sdfr memset(xprt, 0, sizeof(SVCXPRT)); 572181344Sdfr ext = mem_alloc(sizeof(SVCXPRT_EXT)); 573235045Skib if (ext == NULL) { 574235045Skib mem_free(xprt, sizeof(SVCXPRT)); 575235045Skib return (NULL); 576235045Skib } 577181344Sdfr memset(ext, 0, sizeof(SVCXPRT_EXT)); 578181344Sdfr xprt->xp_p3 = ext; 579182891Sdfr ext->xp_auth.svc_ah_ops = &svc_auth_null_ops; 580181344Sdfr 581181344Sdfr return (xprt); 582181344Sdfr} 583181344Sdfr 584181344Sdfr/* 585181344Sdfr * Free a server transport structure. 586181344Sdfr */ 587181344Sdfrvoid 588181344Sdfrsvc_xprt_free(xprt) 589181344Sdfr SVCXPRT *xprt; 590181344Sdfr{ 591181344Sdfr 592181344Sdfr mem_free(xprt->xp_p3, sizeof(SVCXPRT_EXT)); 593181344Sdfr mem_free(xprt, sizeof(SVCXPRT)); 594181344Sdfr} 595181344Sdfr 5961901Swollman/* ******************* SERVER INPUT STUFF ******************* */ 5971901Swollman 5981901Swollman/* 5991901Swollman * Get server side input from some transport. 6001901Swollman * 6011901Swollman * Statement of authentication parameters management: 6021901Swollman * This function owns and manages all authentication parameters, specifically 6031901Swollman * the "raw" parameters (msg.rm_call.cb_cred and msg.rm_call.cb_verf) and 6041901Swollman * the "cooked" credentials (rqst->rq_clntcred). 6051901Swollman * However, this function does not know the structure of the cooked 6068870Srgrimes * credentials, so it make the following assumptions: 6071901Swollman * a) the structure is contiguous (no pointers), and 6088870Srgrimes * b) the cred structure size does not exceed RQCRED_SIZE bytes. 6091901Swollman * In all events, all three parameters are freed upon exit from this routine. 6101901Swollman * The storage is trivially management on the call stack in user land, but 6111901Swollman * is mallocated in kernel land. 6121901Swollman */ 6131901Swollman 6141901Swollmanvoid 6151901Swollmansvc_getreq(rdfds) 6161901Swollman int rdfds; 6171901Swollman{ 6181901Swollman fd_set readfds; 6191901Swollman 6201901Swollman FD_ZERO(&readfds); 6211901Swollman readfds.fds_bits[0] = rdfds; 6221901Swollman svc_getreqset(&readfds); 6231901Swollman} 6241901Swollman 6251901Swollmanvoid 6261901Swollmansvc_getreqset(readfds) 6271901Swollman fd_set *readfds; 6281901Swollman{ 62974462Salfred int bit, fd; 63074462Salfred fd_mask mask, *maskp; 63174462Salfred int sock; 63274462Salfred 63374462Salfred assert(readfds != NULL); 63474462Salfred 63574462Salfred maskp = readfds->fds_bits; 63674462Salfred for (sock = 0; sock < FD_SETSIZE; sock += NFDBITS) { 637200061Sjhb for (mask = *maskp++; (bit = ffsl(mask)) != 0; 638200061Sjhb mask ^= (1ul << (bit - 1))) { 63974462Salfred /* sock has input waiting */ 64074462Salfred fd = sock + bit - 1; 64174462Salfred svc_getreq_common(fd); 64274462Salfred } 64374462Salfred } 64421087Speter} 64521087Speter 64621087Spetervoid 64774462Salfredsvc_getreq_common(fd) 64874462Salfred int fd; 6491901Swollman{ 65074462Salfred SVCXPRT *xprt; 65174462Salfred struct svc_req r; 6521901Swollman struct rpc_msg msg; 6531901Swollman int prog_found; 65474462Salfred rpcvers_t low_vers; 65574462Salfred rpcvers_t high_vers; 65674462Salfred enum xprt_stat stat; 6571901Swollman char cred_area[2*MAX_AUTH_BYTES + RQCRED_SIZE]; 65874462Salfred 6591901Swollman msg.rm_call.cb_cred.oa_base = cred_area; 6601901Swollman msg.rm_call.cb_verf.oa_base = &(cred_area[MAX_AUTH_BYTES]); 6611901Swollman r.rq_clntcred = &(cred_area[2*MAX_AUTH_BYTES]); 6621901Swollman 66374462Salfred rwlock_rdlock(&svc_fd_lock); 664109359Smbr xprt = __svc_xports[fd]; 66574462Salfred rwlock_unlock(&svc_fd_lock); 66674462Salfred if (xprt == NULL) 66774462Salfred /* But do we control sock? */ 66874462Salfred return; 66974462Salfred /* now receive msgs from xprtprt (support batch calls) */ 67074462Salfred do { 67174462Salfred if (SVC_RECV(xprt, &msg)) { 6721901Swollman 67374462Salfred /* now find the exported program and call it */ 67474462Salfred struct svc_callout *s; 67574462Salfred enum auth_stat why; 6761901Swollman 67774462Salfred r.rq_xprt = xprt; 67874462Salfred r.rq_prog = msg.rm_call.cb_prog; 67974462Salfred r.rq_vers = msg.rm_call.cb_vers; 68074462Salfred r.rq_proc = msg.rm_call.cb_proc; 68174462Salfred r.rq_cred = msg.rm_call.cb_cred; 68274462Salfred /* first authenticate the message */ 68374462Salfred if ((why = _authenticate(&r, &msg)) != AUTH_OK) { 684181344Sdfr /* 685181344Sdfr * RPCSEC_GSS uses this return code 686181344Sdfr * for requests that form part of its 687181344Sdfr * context establishment protocol and 688181344Sdfr * should not be dispatched to the 689181344Sdfr * application. 690181344Sdfr */ 691181344Sdfr if (why != RPCSEC_GSS_NODISPATCH) 692181344Sdfr svcerr_auth(xprt, why); 69374462Salfred goto call_done; 6941901Swollman } 69574462Salfred /* now match message with a registered service*/ 69674462Salfred prog_found = FALSE; 69774462Salfred low_vers = (rpcvers_t) -1L; 69874462Salfred high_vers = (rpcvers_t) 0L; 69974462Salfred for (s = svc_head; s != NULL; s = s->sc_next) { 70074462Salfred if (s->sc_prog == r.rq_prog) { 70174462Salfred if (s->sc_vers == r.rq_vers) { 70274462Salfred (*s->sc_dispatch)(&r, xprt); 70374462Salfred goto call_done; 70474462Salfred } /* found correct version */ 70574462Salfred prog_found = TRUE; 70674462Salfred if (s->sc_vers < low_vers) 70774462Salfred low_vers = s->sc_vers; 70874462Salfred if (s->sc_vers > high_vers) 70974462Salfred high_vers = s->sc_vers; 71074462Salfred } /* found correct program */ 7111901Swollman } 71274462Salfred /* 71374462Salfred * if we got here, the program or version 71474462Salfred * is not served ... 71574462Salfred */ 71674462Salfred if (prog_found) 71774462Salfred svcerr_progvers(xprt, low_vers, high_vers); 71874462Salfred else 719181344Sdfr svcerr_noprog(xprt); 72074462Salfred /* Fall through to ... */ 72174462Salfred } 72274462Salfred /* 72374462Salfred * Check if the xprt has been disconnected in a 72474462Salfred * recursive call in the service dispatch routine. 72574462Salfred * If so, then break. 72674462Salfred */ 72774462Salfred rwlock_rdlock(&svc_fd_lock); 728109359Smbr if (xprt != __svc_xports[fd]) { 72974462Salfred rwlock_unlock(&svc_fd_lock); 73074462Salfred break; 73174462Salfred } 73274462Salfred rwlock_unlock(&svc_fd_lock); 73374462Salfredcall_done: 73474462Salfred if ((stat = SVC_STAT(xprt)) == XPRT_DIED){ 73574462Salfred SVC_DESTROY(xprt); 73674462Salfred break; 73774462Salfred } 73874462Salfred } while (stat == XPRT_MOREREQS); 73974462Salfred} 74074462Salfred 74174462Salfred 74274462Salfredvoid 74374462Salfredsvc_getreq_poll(pfdp, pollretval) 74474462Salfred struct pollfd *pfdp; 74574462Salfred int pollretval; 74674462Salfred{ 74774462Salfred int i; 74874462Salfred int fds_found; 74974462Salfred 75074462Salfred for (i = fds_found = 0; fds_found < pollretval; i++) { 75174462Salfred struct pollfd *p = &pfdp[i]; 75274462Salfred 75374462Salfred if (p->revents) { 75474462Salfred /* fd has input waiting */ 75574462Salfred fds_found++; 75674462Salfred /* 75774462Salfred * We assume that this function is only called 75874462Salfred * via someone _select()ing from svc_fdset or 75974462Salfred * _poll()ing from svc_pollset[]. Thus it's safe 76074462Salfred * to handle the POLLNVAL event by simply turning 76174462Salfred * the corresponding bit off in svc_fdset. The 76274462Salfred * svc_pollset[] array is derived from svc_fdset 76374462Salfred * and so will also be updated eventually. 76474462Salfred * 76574462Salfred * XXX Should we do an xprt_unregister() instead? 76674462Salfred */ 76774462Salfred if (p->revents & POLLNVAL) { 76874462Salfred rwlock_wrlock(&svc_fd_lock); 76974462Salfred FD_CLR(p->fd, &svc_fdset); 77074462Salfred rwlock_unlock(&svc_fd_lock); 77174462Salfred } else 77274462Salfred svc_getreq_common(p->fd); 77374462Salfred } 7741901Swollman } 7751901Swollman} 776109359Smbr 777109359Smbrbool_t 778109359Smbrrpc_control(int what, void *arg) 779109359Smbr{ 780109359Smbr int val; 781109359Smbr 782109359Smbr switch (what) { 783109359Smbr case RPC_SVC_CONNMAXREC_SET: 784109359Smbr val = *(int *)arg; 785109359Smbr if (val <= 0) 786109359Smbr return FALSE; 787109359Smbr __svc_maxrec = val; 788109359Smbr return TRUE; 789109359Smbr case RPC_SVC_CONNMAXREC_GET: 790109359Smbr *(int *)arg = __svc_maxrec; 791109359Smbr return TRUE; 792109359Smbr default: 793109359Smbr break; 794109359Smbr } 795109359Smbr return FALSE; 796109359Smbr} 797