18360efbdSAlfred Perlstein /* $NetBSD: svc.c,v 1.21 2000/07/06 03:10:35 christos Exp $ */ 28360efbdSAlfred Perlstein 32e322d37SHiroki Sato /*- 4*8a16b7a1SPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause 5*8a16b7a1SPedro F. Giffuni * 62e322d37SHiroki Sato * Copyright (c) 2009, Sun Microsystems, Inc. 72e322d37SHiroki Sato * All rights reserved. 899064799SGarrett Wollman * 92e322d37SHiroki Sato * Redistribution and use in source and binary forms, with or without 102e322d37SHiroki Sato * modification, are permitted provided that the following conditions are met: 112e322d37SHiroki Sato * - Redistributions of source code must retain the above copyright notice, 122e322d37SHiroki Sato * this list of conditions and the following disclaimer. 132e322d37SHiroki Sato * - Redistributions in binary form must reproduce the above copyright notice, 142e322d37SHiroki Sato * this list of conditions and the following disclaimer in the documentation 152e322d37SHiroki Sato * and/or other materials provided with the distribution. 162e322d37SHiroki Sato * - Neither the name of Sun Microsystems, Inc. nor the names of its 172e322d37SHiroki Sato * contributors may be used to endorse or promote products derived 182e322d37SHiroki Sato * from this software without specific prior written permission. 1999064799SGarrett Wollman * 202e322d37SHiroki Sato * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 212e322d37SHiroki Sato * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 222e322d37SHiroki Sato * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 232e322d37SHiroki Sato * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 242e322d37SHiroki Sato * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 252e322d37SHiroki Sato * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 262e322d37SHiroki Sato * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 272e322d37SHiroki Sato * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 282e322d37SHiroki Sato * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 292e322d37SHiroki Sato * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 302e322d37SHiroki Sato * POSSIBILITY OF SUCH DAMAGE. 3199064799SGarrett Wollman */ 3299064799SGarrett Wollman 3399064799SGarrett Wollman #if defined(LIBC_SCCS) && !defined(lint) 34a986ef57SDavid E. O'Brien static char *sccsid2 = "@(#)svc.c 1.44 88/02/08 Copyr 1984 Sun Micro"; 35d3d20c82SDavid E. O'Brien static char *sccsid = "@(#)svc.c 2.4 88/08/11 4.0 RPCSRC"; 3699064799SGarrett Wollman #endif 37d3d20c82SDavid E. O'Brien #include <sys/cdefs.h> 38d3d20c82SDavid E. O'Brien __FBSDID("$FreeBSD$"); 3999064799SGarrett Wollman 4099064799SGarrett Wollman /* 4199064799SGarrett Wollman * svc.c, Server-side remote procedure call interface. 4299064799SGarrett Wollman * 4399064799SGarrett Wollman * There are two sets of procedures here. The xprt routines are 4499064799SGarrett Wollman * for handling transport handles. The svc routines handle the 4599064799SGarrett Wollman * list of service routines. 4699064799SGarrett Wollman * 4799064799SGarrett Wollman * Copyright (C) 1984, Sun Microsystems, Inc. 4899064799SGarrett Wollman */ 4999064799SGarrett Wollman 508360efbdSAlfred Perlstein #include "namespace.h" 519f5afc13SIan Dowse #include "reentrant.h" 528360efbdSAlfred Perlstein #include <sys/types.h> 538360efbdSAlfred Perlstein #include <sys/poll.h> 548360efbdSAlfred Perlstein #include <assert.h> 558360efbdSAlfred Perlstein #include <errno.h> 564c3af266SPoul-Henning Kamp #include <stdlib.h> 578360efbdSAlfred Perlstein #include <string.h> 588360efbdSAlfred Perlstein 5999064799SGarrett Wollman #include <rpc/rpc.h> 608360efbdSAlfred Perlstein #ifdef PORTMAP 6199064799SGarrett Wollman #include <rpc/pmap_clnt.h> 628360efbdSAlfred Perlstein #endif /* PORTMAP */ 638360efbdSAlfred Perlstein #include "un-namespace.h" 648360efbdSAlfred Perlstein 658360efbdSAlfred Perlstein #include "rpc_com.h" 66235baf26SDaniel Eischen #include "mt_misc.h" 6799064799SGarrett Wollman 6899064799SGarrett Wollman #define RQCRED_SIZE 400 /* this size is excessive */ 6999064799SGarrett Wollman 708360efbdSAlfred Perlstein #define SVC_VERSQUIET 0x0001 /* keep quiet about vers mismatch */ 718f55a568SDoug Rabson #define version_keepquiet(xp) (SVC_EXT(xp)->xp_flags & SVC_VERSQUIET) 728360efbdSAlfred Perlstein 73ae1e6afdSPeter Wemm #define max(a, b) (a > b ? a : b) 747d6a21b4SJames Raynard 7599064799SGarrett Wollman /* 7699064799SGarrett Wollman * The services list 7799064799SGarrett Wollman * Each entry represents a set of procedures (an rpc program). 7899064799SGarrett Wollman * The dispatch routine takes request structs and runs the 7932223c1bSPedro F. Giffuni * appropriate procedure. 8099064799SGarrett Wollman */ 8199064799SGarrett Wollman static struct svc_callout { 8299064799SGarrett Wollman struct svc_callout *sc_next; 838360efbdSAlfred Perlstein rpcprog_t sc_prog; 848360efbdSAlfred Perlstein rpcvers_t sc_vers; 858360efbdSAlfred Perlstein char *sc_netid; 86c05ac53bSDavid E. O'Brien void (*sc_dispatch)(struct svc_req *, SVCXPRT *); 8799064799SGarrett Wollman } *svc_head; 8899064799SGarrett Wollman 89635d1cf1SDavid Chisnall SVCXPRT **__svc_xports; 90635d1cf1SDavid Chisnall int __svc_maxrec; 91635d1cf1SDavid Chisnall 921372519bSDavid E. O'Brien static struct svc_callout *svc_find(rpcprog_t, rpcvers_t, 931372519bSDavid E. O'Brien struct svc_callout **, char *); 9408497c02SMartin Blapp static void __xprt_do_unregister (SVCXPRT *xprt, bool_t dolock); 95ae1e6afdSPeter Wemm 9699064799SGarrett Wollman /* *************** SVCXPRT related stuff **************** */ 9799064799SGarrett Wollman 9899064799SGarrett Wollman /* 9999064799SGarrett Wollman * Activate a transport handle. 10099064799SGarrett Wollman */ 10199064799SGarrett Wollman void 102193d994dSCraig Rodrigues xprt_register(SVCXPRT *xprt) 10399064799SGarrett Wollman { 1048360efbdSAlfred Perlstein int sock; 10599064799SGarrett Wollman 1068360efbdSAlfred Perlstein assert(xprt != NULL); 10799064799SGarrett Wollman 1088360efbdSAlfred Perlstein sock = xprt->xp_fd; 1098360efbdSAlfred Perlstein 1108360efbdSAlfred Perlstein rwlock_wrlock(&svc_fd_lock); 11108497c02SMartin Blapp if (__svc_xports == NULL) { 11208497c02SMartin Blapp __svc_xports = (SVCXPRT **) 113efa2501eSBrooks Davis mem_alloc((FD_SETSIZE + 1) * sizeof(SVCXPRT *)); 114ed8ddc6eSKonstantin Belousov if (__svc_xports == NULL) { 115ed8ddc6eSKonstantin Belousov rwlock_unlock(&svc_fd_lock); 1168360efbdSAlfred Perlstein return; 117ed8ddc6eSKonstantin Belousov } 118efa2501eSBrooks Davis memset(__svc_xports, '\0', (FD_SETSIZE + 1) * sizeof(SVCXPRT *)); 119ae1e6afdSPeter Wemm } 1208360efbdSAlfred Perlstein if (sock < FD_SETSIZE) { 12108497c02SMartin Blapp __svc_xports[sock] = xprt; 1228360efbdSAlfred Perlstein FD_SET(sock, &svc_fdset); 123ae1e6afdSPeter Wemm svc_maxfd = max(svc_maxfd, sock); 124efa2501eSBrooks Davis } else if (sock == FD_SETSIZE) 125efa2501eSBrooks Davis __svc_xports[sock] = xprt; 1268360efbdSAlfred Perlstein rwlock_unlock(&svc_fd_lock); 1278360efbdSAlfred Perlstein } 12899064799SGarrett Wollman 12908497c02SMartin Blapp void 13008497c02SMartin Blapp xprt_unregister(SVCXPRT *xprt) 13108497c02SMartin Blapp { 13208497c02SMartin Blapp __xprt_do_unregister(xprt, TRUE); 13308497c02SMartin Blapp } 13408497c02SMartin Blapp 13508497c02SMartin Blapp void 13608497c02SMartin Blapp __xprt_unregister_unlocked(SVCXPRT *xprt) 13708497c02SMartin Blapp { 13808497c02SMartin Blapp __xprt_do_unregister(xprt, FALSE); 13908497c02SMartin Blapp } 14008497c02SMartin Blapp 14199064799SGarrett Wollman /* 14299064799SGarrett Wollman * De-activate a transport handle. 14399064799SGarrett Wollman */ 14408497c02SMartin Blapp static void 145193d994dSCraig Rodrigues __xprt_do_unregister(SVCXPRT *xprt, bool_t dolock) 14699064799SGarrett Wollman { 1478360efbdSAlfred Perlstein int sock; 14899064799SGarrett Wollman 1498360efbdSAlfred Perlstein assert(xprt != NULL); 1508360efbdSAlfred Perlstein 1518360efbdSAlfred Perlstein sock = xprt->xp_fd; 1528360efbdSAlfred Perlstein 15308497c02SMartin Blapp if (dolock) 1548360efbdSAlfred Perlstein rwlock_wrlock(&svc_fd_lock); 15508497c02SMartin Blapp if ((sock < FD_SETSIZE) && (__svc_xports[sock] == xprt)) { 15608497c02SMartin Blapp __svc_xports[sock] = NULL; 15799064799SGarrett Wollman FD_CLR(sock, &svc_fdset); 1588360efbdSAlfred Perlstein if (sock >= svc_maxfd) { 159ae1e6afdSPeter Wemm for (svc_maxfd--; svc_maxfd>=0; svc_maxfd--) 16008497c02SMartin Blapp if (__svc_xports[svc_maxfd]) 161ae1e6afdSPeter Wemm break; 16299064799SGarrett Wollman } 163efa2501eSBrooks Davis } else if ((sock == FD_SETSIZE) && (__svc_xports[sock] == xprt)) 164efa2501eSBrooks Davis __svc_xports[sock] = NULL; 16508497c02SMartin Blapp if (dolock) 1668360efbdSAlfred Perlstein rwlock_unlock(&svc_fd_lock); 16799064799SGarrett Wollman } 16899064799SGarrett Wollman 1698360efbdSAlfred Perlstein /* 1708360efbdSAlfred Perlstein * Add a service program to the callout list. 1718360efbdSAlfred Perlstein * The dispatch routine will be called when a rpc request for this 1728360efbdSAlfred Perlstein * program number comes in. 1738360efbdSAlfred Perlstein */ 1748360efbdSAlfred Perlstein bool_t 175193d994dSCraig Rodrigues svc_reg(SVCXPRT *xprt, const rpcprog_t prog, const rpcvers_t vers, 176193d994dSCraig Rodrigues void (*dispatch)(struct svc_req *, SVCXPRT *), 177193d994dSCraig Rodrigues const struct netconfig *nconf) 1788360efbdSAlfred Perlstein { 1798360efbdSAlfred Perlstein bool_t dummy; 1808360efbdSAlfred Perlstein struct svc_callout *prev; 1818360efbdSAlfred Perlstein struct svc_callout *s; 1828360efbdSAlfred Perlstein struct netconfig *tnconf; 1838360efbdSAlfred Perlstein char *netid = NULL; 1848360efbdSAlfred Perlstein int flag = 0; 1858360efbdSAlfred Perlstein 1868360efbdSAlfred Perlstein /* VARIABLES PROTECTED BY svc_lock: s, prev, svc_head */ 1878360efbdSAlfred Perlstein 1888360efbdSAlfred Perlstein if (xprt->xp_netid) { 1898360efbdSAlfred Perlstein netid = strdup(xprt->xp_netid); 1908360efbdSAlfred Perlstein flag = 1; 1918360efbdSAlfred Perlstein } else if (nconf && nconf->nc_netid) { 1928360efbdSAlfred Perlstein netid = strdup(nconf->nc_netid); 1938360efbdSAlfred Perlstein flag = 1; 1948360efbdSAlfred Perlstein } else if ((tnconf = __rpcgettp(xprt->xp_fd)) != NULL) { 1958360efbdSAlfred Perlstein netid = strdup(tnconf->nc_netid); 1968360efbdSAlfred Perlstein flag = 1; 1978360efbdSAlfred Perlstein freenetconfigent(tnconf); 1988360efbdSAlfred Perlstein } /* must have been created with svc_raw_create */ 1998360efbdSAlfred Perlstein if ((netid == NULL) && (flag == 1)) { 2008360efbdSAlfred Perlstein return (FALSE); 2018360efbdSAlfred Perlstein } 2028360efbdSAlfred Perlstein 2038360efbdSAlfred Perlstein rwlock_wrlock(&svc_lock); 2048360efbdSAlfred Perlstein if ((s = svc_find(prog, vers, &prev, netid)) != NULL) { 2058360efbdSAlfred Perlstein free(netid); 2068360efbdSAlfred Perlstein if (s->sc_dispatch == dispatch) 2078360efbdSAlfred Perlstein goto rpcb_it; /* he is registering another xptr */ 2088360efbdSAlfred Perlstein rwlock_unlock(&svc_lock); 2098360efbdSAlfred Perlstein return (FALSE); 2108360efbdSAlfred Perlstein } 2118360efbdSAlfred Perlstein s = mem_alloc(sizeof (struct svc_callout)); 2128360efbdSAlfred Perlstein if (s == NULL) { 2138360efbdSAlfred Perlstein free(netid); 2148360efbdSAlfred Perlstein rwlock_unlock(&svc_lock); 2158360efbdSAlfred Perlstein return (FALSE); 2168360efbdSAlfred Perlstein } 2178360efbdSAlfred Perlstein 2188360efbdSAlfred Perlstein s->sc_prog = prog; 2198360efbdSAlfred Perlstein s->sc_vers = vers; 2208360efbdSAlfred Perlstein s->sc_dispatch = dispatch; 2218360efbdSAlfred Perlstein s->sc_netid = netid; 2228360efbdSAlfred Perlstein s->sc_next = svc_head; 2238360efbdSAlfred Perlstein svc_head = s; 2248360efbdSAlfred Perlstein 2258360efbdSAlfred Perlstein if ((xprt->xp_netid == NULL) && (flag == 1) && netid) 2268360efbdSAlfred Perlstein ((SVCXPRT *) xprt)->xp_netid = strdup(netid); 2278360efbdSAlfred Perlstein 2288360efbdSAlfred Perlstein rpcb_it: 2298360efbdSAlfred Perlstein rwlock_unlock(&svc_lock); 2308360efbdSAlfred Perlstein /* now register the information with the local binder service */ 2318360efbdSAlfred Perlstein if (nconf) { 2328360efbdSAlfred Perlstein /*LINTED const castaway*/ 2338360efbdSAlfred Perlstein dummy = rpcb_set(prog, vers, (struct netconfig *) nconf, 2348360efbdSAlfred Perlstein &((SVCXPRT *) xprt)->xp_ltaddr); 2358360efbdSAlfred Perlstein return (dummy); 2368360efbdSAlfred Perlstein } 2378360efbdSAlfred Perlstein return (TRUE); 2388360efbdSAlfred Perlstein } 2398360efbdSAlfred Perlstein 2408360efbdSAlfred Perlstein /* 2418360efbdSAlfred Perlstein * Remove a service program from the callout list. 2428360efbdSAlfred Perlstein */ 2438360efbdSAlfred Perlstein void 244193d994dSCraig Rodrigues svc_unreg(const rpcprog_t prog, const rpcvers_t vers) 2458360efbdSAlfred Perlstein { 2468360efbdSAlfred Perlstein struct svc_callout *prev; 2478360efbdSAlfred Perlstein struct svc_callout *s; 2488360efbdSAlfred Perlstein 2498360efbdSAlfred Perlstein /* unregister the information anyway */ 2508360efbdSAlfred Perlstein (void) rpcb_unset(prog, vers, NULL); 2518360efbdSAlfred Perlstein rwlock_wrlock(&svc_lock); 2528360efbdSAlfred Perlstein while ((s = svc_find(prog, vers, &prev, NULL)) != NULL) { 2538360efbdSAlfred Perlstein if (prev == NULL) { 2548360efbdSAlfred Perlstein svc_head = s->sc_next; 2558360efbdSAlfred Perlstein } else { 2568360efbdSAlfred Perlstein prev->sc_next = s->sc_next; 2578360efbdSAlfred Perlstein } 2588360efbdSAlfred Perlstein s->sc_next = NULL; 2598360efbdSAlfred Perlstein if (s->sc_netid) 2608360efbdSAlfred Perlstein mem_free(s->sc_netid, sizeof (s->sc_netid) + 1); 2618360efbdSAlfred Perlstein mem_free(s, sizeof (struct svc_callout)); 2628360efbdSAlfred Perlstein } 2638360efbdSAlfred Perlstein rwlock_unlock(&svc_lock); 2648360efbdSAlfred Perlstein } 26599064799SGarrett Wollman 26699064799SGarrett Wollman /* ********************** CALLOUT list related stuff ************* */ 26799064799SGarrett Wollman 2688360efbdSAlfred Perlstein #ifdef PORTMAP 26999064799SGarrett Wollman /* 27099064799SGarrett Wollman * Add a service program to the callout list. 27199064799SGarrett Wollman * The dispatch routine will be called when a rpc request for this 27299064799SGarrett Wollman * program number comes in. 27399064799SGarrett Wollman */ 27499064799SGarrett Wollman bool_t 275193d994dSCraig Rodrigues svc_register(SVCXPRT *xprt, u_long prog, u_long vers, 276193d994dSCraig Rodrigues void (*dispatch)(struct svc_req *, SVCXPRT *), 277193d994dSCraig Rodrigues int protocol) 27899064799SGarrett Wollman { 27999064799SGarrett Wollman struct svc_callout *prev; 2808360efbdSAlfred Perlstein struct svc_callout *s; 28199064799SGarrett Wollman 2828360efbdSAlfred Perlstein assert(xprt != NULL); 2838360efbdSAlfred Perlstein assert(dispatch != NULL); 2848360efbdSAlfred Perlstein 2858360efbdSAlfred Perlstein if ((s = svc_find((rpcprog_t)prog, (rpcvers_t)vers, &prev, NULL)) != 2868360efbdSAlfred Perlstein NULL) { 28799064799SGarrett Wollman if (s->sc_dispatch == dispatch) 28899064799SGarrett Wollman goto pmap_it; /* he is registering another xptr */ 28999064799SGarrett Wollman return (FALSE); 29099064799SGarrett Wollman } 2918360efbdSAlfred Perlstein s = mem_alloc(sizeof(struct svc_callout)); 2928360efbdSAlfred Perlstein if (s == NULL) { 29399064799SGarrett Wollman return (FALSE); 29499064799SGarrett Wollman } 2958360efbdSAlfred Perlstein s->sc_prog = (rpcprog_t)prog; 2968360efbdSAlfred Perlstein s->sc_vers = (rpcvers_t)vers; 29799064799SGarrett Wollman s->sc_dispatch = dispatch; 29899064799SGarrett Wollman s->sc_next = svc_head; 29999064799SGarrett Wollman svc_head = s; 30099064799SGarrett Wollman pmap_it: 30199064799SGarrett Wollman /* now register the information with the local binder service */ 30299064799SGarrett Wollman if (protocol) { 30399064799SGarrett Wollman return (pmap_set(prog, vers, protocol, xprt->xp_port)); 30499064799SGarrett Wollman } 30599064799SGarrett Wollman return (TRUE); 30699064799SGarrett Wollman } 30799064799SGarrett Wollman 30899064799SGarrett Wollman /* 30999064799SGarrett Wollman * Remove a service program from the callout list. 31099064799SGarrett Wollman */ 31199064799SGarrett Wollman void 312193d994dSCraig Rodrigues svc_unregister(u_long prog, u_long vers) 31399064799SGarrett Wollman { 31499064799SGarrett Wollman struct svc_callout *prev; 3158360efbdSAlfred Perlstein struct svc_callout *s; 31699064799SGarrett Wollman 3178360efbdSAlfred Perlstein if ((s = svc_find((rpcprog_t)prog, (rpcvers_t)vers, &prev, NULL)) == 3188360efbdSAlfred Perlstein NULL) 31999064799SGarrett Wollman return; 3208360efbdSAlfred Perlstein if (prev == NULL) { 32199064799SGarrett Wollman svc_head = s->sc_next; 32299064799SGarrett Wollman } else { 32399064799SGarrett Wollman prev->sc_next = s->sc_next; 32499064799SGarrett Wollman } 3258360efbdSAlfred Perlstein s->sc_next = NULL; 3268360efbdSAlfred Perlstein mem_free(s, sizeof(struct svc_callout)); 32799064799SGarrett Wollman /* now unregister the information with the local binder service */ 32899064799SGarrett Wollman (void)pmap_unset(prog, vers); 32999064799SGarrett Wollman } 3308360efbdSAlfred Perlstein #endif /* PORTMAP */ 33199064799SGarrett Wollman 33299064799SGarrett Wollman /* 33399064799SGarrett Wollman * Search the callout list for a program number, return the callout 33499064799SGarrett Wollman * struct. 33599064799SGarrett Wollman */ 33699064799SGarrett Wollman static struct svc_callout * 337193d994dSCraig Rodrigues svc_find(rpcprog_t prog, rpcvers_t vers, struct svc_callout **prev, 338193d994dSCraig Rodrigues char *netid) 33999064799SGarrett Wollman { 3408360efbdSAlfred Perlstein struct svc_callout *s, *p; 34199064799SGarrett Wollman 3428360efbdSAlfred Perlstein assert(prev != NULL); 3438360efbdSAlfred Perlstein 3448360efbdSAlfred Perlstein p = NULL; 3458360efbdSAlfred Perlstein for (s = svc_head; s != NULL; s = s->sc_next) { 3468360efbdSAlfred Perlstein if (((s->sc_prog == prog) && (s->sc_vers == vers)) && 3478360efbdSAlfred Perlstein ((netid == NULL) || (s->sc_netid == NULL) || 3488360efbdSAlfred Perlstein (strcmp(netid, s->sc_netid) == 0))) 3498360efbdSAlfred Perlstein break; 35099064799SGarrett Wollman p = s; 35199064799SGarrett Wollman } 35299064799SGarrett Wollman *prev = p; 35399064799SGarrett Wollman return (s); 35499064799SGarrett Wollman } 35599064799SGarrett Wollman 35699064799SGarrett Wollman /* ******************* REPLY GENERATION ROUTINES ************ */ 35799064799SGarrett Wollman 35899064799SGarrett Wollman /* 35999064799SGarrett Wollman * Send a reply to an rpc request 36099064799SGarrett Wollman */ 36199064799SGarrett Wollman bool_t 362193d994dSCraig Rodrigues svc_sendreply(SVCXPRT *xprt, xdrproc_t xdr_results, 363193d994dSCraig Rodrigues void * xdr_location) 36499064799SGarrett Wollman { 36599064799SGarrett Wollman struct rpc_msg rply; 36699064799SGarrett Wollman 3678360efbdSAlfred Perlstein assert(xprt != NULL); 3688360efbdSAlfred Perlstein 36999064799SGarrett Wollman rply.rm_direction = REPLY; 37099064799SGarrett Wollman rply.rm_reply.rp_stat = MSG_ACCEPTED; 37199064799SGarrett Wollman rply.acpted_rply.ar_verf = xprt->xp_verf; 37299064799SGarrett Wollman rply.acpted_rply.ar_stat = SUCCESS; 37399064799SGarrett Wollman rply.acpted_rply.ar_results.where = xdr_location; 37499064799SGarrett Wollman rply.acpted_rply.ar_results.proc = xdr_results; 37599064799SGarrett Wollman return (SVC_REPLY(xprt, &rply)); 37699064799SGarrett Wollman } 37799064799SGarrett Wollman 37899064799SGarrett Wollman /* 37999064799SGarrett Wollman * No procedure error reply 38099064799SGarrett Wollman */ 38199064799SGarrett Wollman void 382193d994dSCraig Rodrigues svcerr_noproc(SVCXPRT *xprt) 38399064799SGarrett Wollman { 38499064799SGarrett Wollman struct rpc_msg rply; 38599064799SGarrett Wollman 3868360efbdSAlfred Perlstein assert(xprt != NULL); 3878360efbdSAlfred Perlstein 38899064799SGarrett Wollman rply.rm_direction = REPLY; 38999064799SGarrett Wollman rply.rm_reply.rp_stat = MSG_ACCEPTED; 39099064799SGarrett Wollman rply.acpted_rply.ar_verf = xprt->xp_verf; 39199064799SGarrett Wollman rply.acpted_rply.ar_stat = PROC_UNAVAIL; 39299064799SGarrett Wollman SVC_REPLY(xprt, &rply); 39399064799SGarrett Wollman } 39499064799SGarrett Wollman 39599064799SGarrett Wollman /* 39699064799SGarrett Wollman * Can't decode args error reply 39799064799SGarrett Wollman */ 39899064799SGarrett Wollman void 399193d994dSCraig Rodrigues svcerr_decode(SVCXPRT *xprt) 40099064799SGarrett Wollman { 40199064799SGarrett Wollman struct rpc_msg rply; 40299064799SGarrett Wollman 4038360efbdSAlfred Perlstein assert(xprt != NULL); 4048360efbdSAlfred Perlstein 40599064799SGarrett Wollman rply.rm_direction = REPLY; 40699064799SGarrett Wollman rply.rm_reply.rp_stat = MSG_ACCEPTED; 40799064799SGarrett Wollman rply.acpted_rply.ar_verf = xprt->xp_verf; 40899064799SGarrett Wollman rply.acpted_rply.ar_stat = GARBAGE_ARGS; 40999064799SGarrett Wollman SVC_REPLY(xprt, &rply); 41099064799SGarrett Wollman } 41199064799SGarrett Wollman 41299064799SGarrett Wollman /* 41399064799SGarrett Wollman * Some system error 41499064799SGarrett Wollman */ 41599064799SGarrett Wollman void 416193d994dSCraig Rodrigues svcerr_systemerr(SVCXPRT *xprt) 41799064799SGarrett Wollman { 41899064799SGarrett Wollman struct rpc_msg rply; 41999064799SGarrett Wollman 4208360efbdSAlfred Perlstein assert(xprt != NULL); 4218360efbdSAlfred Perlstein 42299064799SGarrett Wollman rply.rm_direction = REPLY; 42399064799SGarrett Wollman rply.rm_reply.rp_stat = MSG_ACCEPTED; 42499064799SGarrett Wollman rply.acpted_rply.ar_verf = xprt->xp_verf; 42599064799SGarrett Wollman rply.acpted_rply.ar_stat = SYSTEM_ERR; 42699064799SGarrett Wollman SVC_REPLY(xprt, &rply); 42799064799SGarrett Wollman } 42899064799SGarrett Wollman 4298360efbdSAlfred Perlstein #if 0 4308360efbdSAlfred Perlstein /* 4318360efbdSAlfred Perlstein * Tell RPC package to not complain about version errors to the client. This 4328360efbdSAlfred Perlstein * is useful when revving broadcast protocols that sit on a fixed address. 4338360efbdSAlfred Perlstein * There is really one (or should be only one) example of this kind of 4348360efbdSAlfred Perlstein * protocol: the portmapper (or rpc binder). 4358360efbdSAlfred Perlstein */ 4368360efbdSAlfred Perlstein void 437193d994dSCraig Rodrigues __svc_versquiet_on(SVCXPRT *xprt) 4388360efbdSAlfred Perlstein { 4398360efbdSAlfred Perlstein 4408f55a568SDoug Rabson SVC_EXT(xprt)->xp_flags |= SVC_VERSQUIET; 4418360efbdSAlfred Perlstein } 4428360efbdSAlfred Perlstein 4438360efbdSAlfred Perlstein void 444193d994dSCraig Rodrigues __svc_versquiet_off(SVCXPRT *xprt) 4458360efbdSAlfred Perlstein { 4468360efbdSAlfred Perlstein 4478f55a568SDoug Rabson SVC_EXT(xprt)->xp_flags &= ~SVC_VERSQUIET; 4488360efbdSAlfred Perlstein } 4498360efbdSAlfred Perlstein 4508360efbdSAlfred Perlstein void 451193d994dSCraig Rodrigues svc_versquiet(SVCXPRT *xprt) 4528360efbdSAlfred Perlstein { 4538360efbdSAlfred Perlstein __svc_versquiet_on(xprt); 4548360efbdSAlfred Perlstein } 4558360efbdSAlfred Perlstein 4568360efbdSAlfred Perlstein int 457193d994dSCraig Rodrigues __svc_versquiet_get(SVCXPRT *xprt) 4588360efbdSAlfred Perlstein { 4598f55a568SDoug Rabson 4608f55a568SDoug Rabson return (SVC_EXT(xprt)->xp_flags & SVC_VERSQUIET); 4618360efbdSAlfred Perlstein } 4628360efbdSAlfred Perlstein #endif 4638360efbdSAlfred Perlstein 46499064799SGarrett Wollman /* 46599064799SGarrett Wollman * Authentication error reply 46699064799SGarrett Wollman */ 46799064799SGarrett Wollman void 468193d994dSCraig Rodrigues svcerr_auth(SVCXPRT *xprt, enum auth_stat why) 46999064799SGarrett Wollman { 47099064799SGarrett Wollman struct rpc_msg rply; 47199064799SGarrett Wollman 4728360efbdSAlfred Perlstein assert(xprt != NULL); 4738360efbdSAlfred Perlstein 47499064799SGarrett Wollman rply.rm_direction = REPLY; 47599064799SGarrett Wollman rply.rm_reply.rp_stat = MSG_DENIED; 47699064799SGarrett Wollman rply.rjcted_rply.rj_stat = AUTH_ERROR; 47799064799SGarrett Wollman rply.rjcted_rply.rj_why = why; 47899064799SGarrett Wollman SVC_REPLY(xprt, &rply); 47999064799SGarrett Wollman } 48099064799SGarrett Wollman 48199064799SGarrett Wollman /* 48299064799SGarrett Wollman * Auth too weak error reply 48399064799SGarrett Wollman */ 48499064799SGarrett Wollman void 485193d994dSCraig Rodrigues svcerr_weakauth(SVCXPRT *xprt) 48699064799SGarrett Wollman { 48799064799SGarrett Wollman 4888360efbdSAlfred Perlstein assert(xprt != NULL); 4898360efbdSAlfred Perlstein 49099064799SGarrett Wollman svcerr_auth(xprt, AUTH_TOOWEAK); 49199064799SGarrett Wollman } 49299064799SGarrett Wollman 49399064799SGarrett Wollman /* 49499064799SGarrett Wollman * Program unavailable error reply 49599064799SGarrett Wollman */ 49699064799SGarrett Wollman void 497193d994dSCraig Rodrigues svcerr_noprog(SVCXPRT *xprt) 49899064799SGarrett Wollman { 49999064799SGarrett Wollman struct rpc_msg rply; 50099064799SGarrett Wollman 5018360efbdSAlfred Perlstein assert(xprt != NULL); 5028360efbdSAlfred Perlstein 50399064799SGarrett Wollman rply.rm_direction = REPLY; 50499064799SGarrett Wollman rply.rm_reply.rp_stat = MSG_ACCEPTED; 50599064799SGarrett Wollman rply.acpted_rply.ar_verf = xprt->xp_verf; 50699064799SGarrett Wollman rply.acpted_rply.ar_stat = PROG_UNAVAIL; 50799064799SGarrett Wollman SVC_REPLY(xprt, &rply); 50899064799SGarrett Wollman } 50999064799SGarrett Wollman 51099064799SGarrett Wollman /* 51199064799SGarrett Wollman * Program version mismatch error reply 51299064799SGarrett Wollman */ 51399064799SGarrett Wollman void 514193d994dSCraig Rodrigues svcerr_progvers(SVCXPRT *xprt, rpcvers_t low_vers, rpcvers_t high_vers) 51599064799SGarrett Wollman { 51699064799SGarrett Wollman struct rpc_msg rply; 51799064799SGarrett Wollman 5188360efbdSAlfred Perlstein assert(xprt != NULL); 5198360efbdSAlfred Perlstein 52099064799SGarrett Wollman rply.rm_direction = REPLY; 52199064799SGarrett Wollman rply.rm_reply.rp_stat = MSG_ACCEPTED; 52299064799SGarrett Wollman rply.acpted_rply.ar_verf = xprt->xp_verf; 52399064799SGarrett Wollman rply.acpted_rply.ar_stat = PROG_MISMATCH; 5248360efbdSAlfred Perlstein rply.acpted_rply.ar_vers.low = (u_int32_t)low_vers; 5258360efbdSAlfred Perlstein rply.acpted_rply.ar_vers.high = (u_int32_t)high_vers; 52699064799SGarrett Wollman SVC_REPLY(xprt, &rply); 52799064799SGarrett Wollman } 52899064799SGarrett Wollman 5298f55a568SDoug Rabson /* 5308f55a568SDoug Rabson * Allocate a new server transport structure. All fields are 5318f55a568SDoug Rabson * initialized to zero and xp_p3 is initialized to point at an 5328f55a568SDoug Rabson * extension structure to hold various flags and authentication 5338f55a568SDoug Rabson * parameters. 5348f55a568SDoug Rabson */ 5358f55a568SDoug Rabson SVCXPRT * 536193d994dSCraig Rodrigues svc_xprt_alloc(void) 5378f55a568SDoug Rabson { 5388f55a568SDoug Rabson SVCXPRT *xprt; 5398f55a568SDoug Rabson SVCXPRT_EXT *ext; 5408f55a568SDoug Rabson 5418f55a568SDoug Rabson xprt = mem_alloc(sizeof(SVCXPRT)); 542ed8ddc6eSKonstantin Belousov if (xprt == NULL) 543ed8ddc6eSKonstantin Belousov return (NULL); 5448f55a568SDoug Rabson memset(xprt, 0, sizeof(SVCXPRT)); 5458f55a568SDoug Rabson ext = mem_alloc(sizeof(SVCXPRT_EXT)); 546ed8ddc6eSKonstantin Belousov if (ext == NULL) { 547ed8ddc6eSKonstantin Belousov mem_free(xprt, sizeof(SVCXPRT)); 548ed8ddc6eSKonstantin Belousov return (NULL); 549ed8ddc6eSKonstantin Belousov } 5508f55a568SDoug Rabson memset(ext, 0, sizeof(SVCXPRT_EXT)); 5518f55a568SDoug Rabson xprt->xp_p3 = ext; 5524efa8f3eSDoug Rabson ext->xp_auth.svc_ah_ops = &svc_auth_null_ops; 5538f55a568SDoug Rabson 5548f55a568SDoug Rabson return (xprt); 5558f55a568SDoug Rabson } 5568f55a568SDoug Rabson 5578f55a568SDoug Rabson /* 5588f55a568SDoug Rabson * Free a server transport structure. 5598f55a568SDoug Rabson */ 5608f55a568SDoug Rabson void 561193d994dSCraig Rodrigues svc_xprt_free(SVCXPRT *xprt) 5628f55a568SDoug Rabson { 5638f55a568SDoug Rabson 5648f55a568SDoug Rabson mem_free(xprt->xp_p3, sizeof(SVCXPRT_EXT)); 5658f55a568SDoug Rabson mem_free(xprt, sizeof(SVCXPRT)); 5668f55a568SDoug Rabson } 5678f55a568SDoug Rabson 56899064799SGarrett Wollman /* ******************* SERVER INPUT STUFF ******************* */ 56999064799SGarrett Wollman 57099064799SGarrett Wollman /* 57199064799SGarrett Wollman * Get server side input from some transport. 57299064799SGarrett Wollman * 57399064799SGarrett Wollman * Statement of authentication parameters management: 57499064799SGarrett Wollman * This function owns and manages all authentication parameters, specifically 57599064799SGarrett Wollman * the "raw" parameters (msg.rm_call.cb_cred and msg.rm_call.cb_verf) and 57699064799SGarrett Wollman * the "cooked" credentials (rqst->rq_clntcred). 57799064799SGarrett Wollman * However, this function does not know the structure of the cooked 57899064799SGarrett Wollman * credentials, so it make the following assumptions: 57999064799SGarrett Wollman * a) the structure is contiguous (no pointers), and 58099064799SGarrett Wollman * b) the cred structure size does not exceed RQCRED_SIZE bytes. 58199064799SGarrett Wollman * In all events, all three parameters are freed upon exit from this routine. 58299064799SGarrett Wollman * The storage is trivially management on the call stack in user land, but 58399064799SGarrett Wollman * is mallocated in kernel land. 58499064799SGarrett Wollman */ 58599064799SGarrett Wollman 58699064799SGarrett Wollman void 587193d994dSCraig Rodrigues svc_getreq(int rdfds) 58899064799SGarrett Wollman { 58999064799SGarrett Wollman fd_set readfds; 59099064799SGarrett Wollman 59199064799SGarrett Wollman FD_ZERO(&readfds); 59299064799SGarrett Wollman readfds.fds_bits[0] = rdfds; 59399064799SGarrett Wollman svc_getreqset(&readfds); 59499064799SGarrett Wollman } 59599064799SGarrett Wollman 59699064799SGarrett Wollman void 597193d994dSCraig Rodrigues svc_getreqset(fd_set *readfds) 59899064799SGarrett Wollman { 5998360efbdSAlfred Perlstein int bit, fd; 6008360efbdSAlfred Perlstein fd_mask mask, *maskp; 6018360efbdSAlfred Perlstein int sock; 6028360efbdSAlfred Perlstein 6038360efbdSAlfred Perlstein assert(readfds != NULL); 6048360efbdSAlfred Perlstein 6058360efbdSAlfred Perlstein maskp = readfds->fds_bits; 6068360efbdSAlfred Perlstein for (sock = 0; sock < FD_SETSIZE; sock += NFDBITS) { 60755fdae4cSJohn Baldwin for (mask = *maskp++; (bit = ffsl(mask)) != 0; 60855fdae4cSJohn Baldwin mask ^= (1ul << (bit - 1))) { 6098360efbdSAlfred Perlstein /* sock has input waiting */ 6108360efbdSAlfred Perlstein fd = sock + bit - 1; 6118360efbdSAlfred Perlstein svc_getreq_common(fd); 6128360efbdSAlfred Perlstein } 6138360efbdSAlfred Perlstein } 614ae1e6afdSPeter Wemm } 615ae1e6afdSPeter Wemm 616ae1e6afdSPeter Wemm void 617193d994dSCraig Rodrigues svc_getreq_common(int fd) 61899064799SGarrett Wollman { 6198360efbdSAlfred Perlstein SVCXPRT *xprt; 6208360efbdSAlfred Perlstein struct svc_req r; 62199064799SGarrett Wollman struct rpc_msg msg; 62299064799SGarrett Wollman int prog_found; 6238360efbdSAlfred Perlstein rpcvers_t low_vers; 6248360efbdSAlfred Perlstein rpcvers_t high_vers; 6258360efbdSAlfred Perlstein enum xprt_stat stat; 62699064799SGarrett Wollman char cred_area[2*MAX_AUTH_BYTES + RQCRED_SIZE]; 6278360efbdSAlfred Perlstein 62899064799SGarrett Wollman msg.rm_call.cb_cred.oa_base = cred_area; 62999064799SGarrett Wollman msg.rm_call.cb_verf.oa_base = &(cred_area[MAX_AUTH_BYTES]); 63099064799SGarrett Wollman r.rq_clntcred = &(cred_area[2*MAX_AUTH_BYTES]); 63199064799SGarrett Wollman 6328360efbdSAlfred Perlstein rwlock_rdlock(&svc_fd_lock); 63308497c02SMartin Blapp xprt = __svc_xports[fd]; 6348360efbdSAlfred Perlstein rwlock_unlock(&svc_fd_lock); 635ae1e6afdSPeter Wemm if (xprt == NULL) 636ae1e6afdSPeter Wemm /* But do we control sock? */ 6378360efbdSAlfred Perlstein return; 63899064799SGarrett Wollman /* now receive msgs from xprtprt (support batch calls) */ 63999064799SGarrett Wollman do { 64099064799SGarrett Wollman if (SVC_RECV(xprt, &msg)) { 64199064799SGarrett Wollman 64299064799SGarrett Wollman /* now find the exported program and call it */ 6438360efbdSAlfred Perlstein struct svc_callout *s; 64499064799SGarrett Wollman enum auth_stat why; 64599064799SGarrett Wollman 64699064799SGarrett Wollman r.rq_xprt = xprt; 64799064799SGarrett Wollman r.rq_prog = msg.rm_call.cb_prog; 64899064799SGarrett Wollman r.rq_vers = msg.rm_call.cb_vers; 64999064799SGarrett Wollman r.rq_proc = msg.rm_call.cb_proc; 65099064799SGarrett Wollman r.rq_cred = msg.rm_call.cb_cred; 65199064799SGarrett Wollman /* first authenticate the message */ 65299064799SGarrett Wollman if ((why = _authenticate(&r, &msg)) != AUTH_OK) { 6538f55a568SDoug Rabson /* 6548f55a568SDoug Rabson * RPCSEC_GSS uses this return code 6558f55a568SDoug Rabson * for requests that form part of its 6568f55a568SDoug Rabson * context establishment protocol and 6578f55a568SDoug Rabson * should not be dispatched to the 6588f55a568SDoug Rabson * application. 6598f55a568SDoug Rabson */ 6608f55a568SDoug Rabson if (why != RPCSEC_GSS_NODISPATCH) 66199064799SGarrett Wollman svcerr_auth(xprt, why); 66299064799SGarrett Wollman goto call_done; 66399064799SGarrett Wollman } 66499064799SGarrett Wollman /* now match message with a registered service*/ 66599064799SGarrett Wollman prog_found = FALSE; 6668360efbdSAlfred Perlstein low_vers = (rpcvers_t) -1L; 6678360efbdSAlfred Perlstein high_vers = (rpcvers_t) 0L; 6688360efbdSAlfred Perlstein for (s = svc_head; s != NULL; s = s->sc_next) { 66999064799SGarrett Wollman if (s->sc_prog == r.rq_prog) { 67099064799SGarrett Wollman if (s->sc_vers == r.rq_vers) { 67199064799SGarrett Wollman (*s->sc_dispatch)(&r, xprt); 67299064799SGarrett Wollman goto call_done; 67399064799SGarrett Wollman } /* found correct version */ 67499064799SGarrett Wollman prog_found = TRUE; 67599064799SGarrett Wollman if (s->sc_vers < low_vers) 67699064799SGarrett Wollman low_vers = s->sc_vers; 67799064799SGarrett Wollman if (s->sc_vers > high_vers) 67899064799SGarrett Wollman high_vers = s->sc_vers; 67999064799SGarrett Wollman } /* found correct program */ 68099064799SGarrett Wollman } 68199064799SGarrett Wollman /* 68299064799SGarrett Wollman * if we got here, the program or version 68399064799SGarrett Wollman * is not served ... 68499064799SGarrett Wollman */ 68599064799SGarrett Wollman if (prog_found) 6868360efbdSAlfred Perlstein svcerr_progvers(xprt, low_vers, high_vers); 68799064799SGarrett Wollman else 68899064799SGarrett Wollman svcerr_noprog(xprt); 68999064799SGarrett Wollman /* Fall through to ... */ 69099064799SGarrett Wollman } 6918360efbdSAlfred Perlstein /* 6928360efbdSAlfred Perlstein * Check if the xprt has been disconnected in a 6938360efbdSAlfred Perlstein * recursive call in the service dispatch routine. 6948360efbdSAlfred Perlstein * If so, then break. 6958360efbdSAlfred Perlstein */ 6968360efbdSAlfred Perlstein rwlock_rdlock(&svc_fd_lock); 69708497c02SMartin Blapp if (xprt != __svc_xports[fd]) { 6988360efbdSAlfred Perlstein rwlock_unlock(&svc_fd_lock); 6998360efbdSAlfred Perlstein break; 7008360efbdSAlfred Perlstein } 7018360efbdSAlfred Perlstein rwlock_unlock(&svc_fd_lock); 70299064799SGarrett Wollman call_done: 70399064799SGarrett Wollman if ((stat = SVC_STAT(xprt)) == XPRT_DIED){ 70499064799SGarrett Wollman SVC_DESTROY(xprt); 70599064799SGarrett Wollman break; 70699064799SGarrett Wollman } 70799064799SGarrett Wollman } while (stat == XPRT_MOREREQS); 70899064799SGarrett Wollman } 7098360efbdSAlfred Perlstein 7108360efbdSAlfred Perlstein 7118360efbdSAlfred Perlstein void 712193d994dSCraig Rodrigues svc_getreq_poll(struct pollfd *pfdp, int pollretval) 7138360efbdSAlfred Perlstein { 7148360efbdSAlfred Perlstein int i; 7158360efbdSAlfred Perlstein int fds_found; 7168360efbdSAlfred Perlstein 7178360efbdSAlfred Perlstein for (i = fds_found = 0; fds_found < pollretval; i++) { 7188360efbdSAlfred Perlstein struct pollfd *p = &pfdp[i]; 7198360efbdSAlfred Perlstein 7208360efbdSAlfred Perlstein if (p->revents) { 7218360efbdSAlfred Perlstein /* fd has input waiting */ 7228360efbdSAlfred Perlstein fds_found++; 7238360efbdSAlfred Perlstein /* 7248360efbdSAlfred Perlstein * We assume that this function is only called 7258360efbdSAlfred Perlstein * via someone _select()ing from svc_fdset or 7268360efbdSAlfred Perlstein * _poll()ing from svc_pollset[]. Thus it's safe 7278360efbdSAlfred Perlstein * to handle the POLLNVAL event by simply turning 7288360efbdSAlfred Perlstein * the corresponding bit off in svc_fdset. The 7298360efbdSAlfred Perlstein * svc_pollset[] array is derived from svc_fdset 7308360efbdSAlfred Perlstein * and so will also be updated eventually. 7318360efbdSAlfred Perlstein * 7328360efbdSAlfred Perlstein * XXX Should we do an xprt_unregister() instead? 7338360efbdSAlfred Perlstein */ 7348360efbdSAlfred Perlstein if (p->revents & POLLNVAL) { 7358360efbdSAlfred Perlstein rwlock_wrlock(&svc_fd_lock); 7368360efbdSAlfred Perlstein FD_CLR(p->fd, &svc_fdset); 7378360efbdSAlfred Perlstein rwlock_unlock(&svc_fd_lock); 7388360efbdSAlfred Perlstein } else 7398360efbdSAlfred Perlstein svc_getreq_common(p->fd); 7408360efbdSAlfred Perlstein } 74199064799SGarrett Wollman } 74299064799SGarrett Wollman } 74308497c02SMartin Blapp 74408497c02SMartin Blapp bool_t 74508497c02SMartin Blapp rpc_control(int what, void *arg) 74608497c02SMartin Blapp { 74708497c02SMartin Blapp int val; 74808497c02SMartin Blapp 74908497c02SMartin Blapp switch (what) { 75008497c02SMartin Blapp case RPC_SVC_CONNMAXREC_SET: 75108497c02SMartin Blapp val = *(int *)arg; 75208497c02SMartin Blapp if (val <= 0) 75308497c02SMartin Blapp return FALSE; 75408497c02SMartin Blapp __svc_maxrec = val; 75508497c02SMartin Blapp return TRUE; 75608497c02SMartin Blapp case RPC_SVC_CONNMAXREC_GET: 75708497c02SMartin Blapp *(int *)arg = __svc_maxrec; 75808497c02SMartin Blapp return TRUE; 75908497c02SMartin Blapp default: 76008497c02SMartin Blapp break; 76108497c02SMartin Blapp } 76208497c02SMartin Blapp return FALSE; 76308497c02SMartin Blapp } 764