18360efbdSAlfred Perlstein /* $NetBSD: svc.c,v 1.21 2000/07/06 03:10:35 christos Exp $ */ 28360efbdSAlfred Perlstein 399064799SGarrett Wollman /* 499064799SGarrett Wollman * Sun RPC is a product of Sun Microsystems, Inc. and is provided for 599064799SGarrett Wollman * unrestricted use provided that this legend is included on all tape 699064799SGarrett Wollman * media and as a part of the software program in whole or part. Users 799064799SGarrett Wollman * may copy or modify Sun RPC without charge, but are not authorized 899064799SGarrett Wollman * to license or distribute it to anyone else except as part of a product or 999064799SGarrett Wollman * program developed by the user. 1099064799SGarrett Wollman * 1199064799SGarrett Wollman * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE 1299064799SGarrett Wollman * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR 1399064799SGarrett Wollman * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. 1499064799SGarrett Wollman * 1599064799SGarrett Wollman * Sun RPC is provided with no support and without any obligation on the 1699064799SGarrett Wollman * part of Sun Microsystems, Inc. to assist in its use, correction, 1799064799SGarrett Wollman * modification or enhancement. 1899064799SGarrett Wollman * 1999064799SGarrett Wollman * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE 2099064799SGarrett Wollman * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC 2199064799SGarrett Wollman * OR ANY PART THEREOF. 2299064799SGarrett Wollman * 2399064799SGarrett Wollman * In no event will Sun Microsystems, Inc. be liable for any lost revenue 2499064799SGarrett Wollman * or profits or other special, indirect and consequential damages, even if 2599064799SGarrett Wollman * Sun has been advised of the possibility of such damages. 2699064799SGarrett Wollman * 2799064799SGarrett Wollman * Sun Microsystems, Inc. 2899064799SGarrett Wollman * 2550 Garcia Avenue 2999064799SGarrett Wollman * Mountain View, California 94043 3099064799SGarrett Wollman */ 3199064799SGarrett Wollman 3299064799SGarrett Wollman #if defined(LIBC_SCCS) && !defined(lint) 3399064799SGarrett Wollman /*static char *sccsid = "from: @(#)svc.c 1.44 88/02/08 Copyr 1984 Sun Micro";*/ 3499064799SGarrett Wollman /*static char *sccsid = "from: @(#)svc.c 2.4 88/08/11 4.0 RPCSRC";*/ 357f3dea24SPeter Wemm static char *rcsid = "$FreeBSD$"; 3699064799SGarrett Wollman #endif 3799064799SGarrett Wollman 3899064799SGarrett Wollman /* 3999064799SGarrett Wollman * svc.c, Server-side remote procedure call interface. 4099064799SGarrett Wollman * 4199064799SGarrett Wollman * There are two sets of procedures here. The xprt routines are 4299064799SGarrett Wollman * for handling transport handles. The svc routines handle the 4399064799SGarrett Wollman * list of service routines. 4499064799SGarrett Wollman * 4599064799SGarrett Wollman * Copyright (C) 1984, Sun Microsystems, Inc. 4699064799SGarrett Wollman */ 4799064799SGarrett Wollman 488360efbdSAlfred Perlstein #include "reentrant.h" 498360efbdSAlfred Perlstein #include "namespace.h" 508360efbdSAlfred Perlstein #include <sys/types.h> 518360efbdSAlfred Perlstein #include <sys/poll.h> 528360efbdSAlfred Perlstein #include <assert.h> 538360efbdSAlfred Perlstein #include <errno.h> 544c3af266SPoul-Henning Kamp #include <stdlib.h> 558360efbdSAlfred Perlstein #include <string.h> 568360efbdSAlfred Perlstein 5799064799SGarrett Wollman #include <rpc/rpc.h> 588360efbdSAlfred Perlstein #ifdef PORTMAP 5999064799SGarrett Wollman #include <rpc/pmap_clnt.h> 608360efbdSAlfred Perlstein #endif /* PORTMAP */ 618360efbdSAlfred Perlstein #include "un-namespace.h" 628360efbdSAlfred Perlstein 638360efbdSAlfred Perlstein #include "rpc_com.h" 6499064799SGarrett Wollman 6599064799SGarrett Wollman static SVCXPRT **xports; 6699064799SGarrett Wollman 6799064799SGarrett Wollman #define RQCRED_SIZE 400 /* this size is excessive */ 6899064799SGarrett Wollman 698360efbdSAlfred Perlstein #define SVC_VERSQUIET 0x0001 /* keep quiet about vers mismatch */ 708360efbdSAlfred Perlstein #define version_keepquiet(xp) ((u_long)(xp)->xp_p3 & SVC_VERSQUIET) 718360efbdSAlfred Perlstein 72ae1e6afdSPeter Wemm #define max(a, b) (a > b ? a : b) 737d6a21b4SJames Raynard 7499064799SGarrett Wollman /* 7599064799SGarrett Wollman * The services list 7699064799SGarrett Wollman * Each entry represents a set of procedures (an rpc program). 7799064799SGarrett Wollman * The dispatch routine takes request structs and runs the 7899064799SGarrett Wollman * apropriate procedure. 7999064799SGarrett Wollman */ 8099064799SGarrett Wollman static struct svc_callout { 8199064799SGarrett Wollman struct svc_callout *sc_next; 828360efbdSAlfred Perlstein rpcprog_t sc_prog; 838360efbdSAlfred Perlstein rpcvers_t sc_vers; 848360efbdSAlfred Perlstein char *sc_netid; 858360efbdSAlfred Perlstein void (*sc_dispatch) __P((struct svc_req *, SVCXPRT *)); 8699064799SGarrett Wollman } *svc_head; 8799064799SGarrett Wollman 888360efbdSAlfred Perlstein extern rwlock_t svc_lock; 898360efbdSAlfred Perlstein extern rwlock_t svc_fd_lock; 9099064799SGarrett Wollman 918360efbdSAlfred Perlstein static struct svc_callout *svc_find __P((rpcprog_t, rpcvers_t, 928360efbdSAlfred Perlstein struct svc_callout **, char *)); 93ae1e6afdSPeter Wemm 9499064799SGarrett Wollman /* *************** SVCXPRT related stuff **************** */ 9599064799SGarrett Wollman 9699064799SGarrett Wollman /* 9799064799SGarrett Wollman * Activate a transport handle. 9899064799SGarrett Wollman */ 9999064799SGarrett Wollman void 10099064799SGarrett Wollman xprt_register(xprt) 10199064799SGarrett Wollman SVCXPRT *xprt; 10299064799SGarrett Wollman { 1038360efbdSAlfred Perlstein int sock; 10499064799SGarrett Wollman 1058360efbdSAlfred Perlstein assert(xprt != NULL); 10699064799SGarrett Wollman 1078360efbdSAlfred Perlstein sock = xprt->xp_fd; 1088360efbdSAlfred Perlstein 1098360efbdSAlfred Perlstein rwlock_wrlock(&svc_fd_lock); 1108360efbdSAlfred Perlstein if (xports == NULL) { 1118360efbdSAlfred Perlstein xports = (SVCXPRT **) 1128360efbdSAlfred Perlstein mem_alloc(FD_SETSIZE * sizeof(SVCXPRT *)); 1138360efbdSAlfred Perlstein if (xports == NULL) 1148360efbdSAlfred Perlstein return; 1158360efbdSAlfred Perlstein memset(xports, '\0', FD_SETSIZE * sizeof(SVCXPRT *)); 116ae1e6afdSPeter Wemm } 1178360efbdSAlfred Perlstein if (sock < FD_SETSIZE) { 118ae1e6afdSPeter Wemm xports[sock] = xprt; 1198360efbdSAlfred Perlstein FD_SET(sock, &svc_fdset); 120ae1e6afdSPeter Wemm svc_maxfd = max(svc_maxfd, sock); 12199064799SGarrett Wollman } 1228360efbdSAlfred Perlstein rwlock_unlock(&svc_fd_lock); 1238360efbdSAlfred Perlstein } 12499064799SGarrett Wollman 12599064799SGarrett Wollman /* 12699064799SGarrett Wollman * De-activate a transport handle. 12799064799SGarrett Wollman */ 12899064799SGarrett Wollman void 12999064799SGarrett Wollman xprt_unregister(xprt) 13099064799SGarrett Wollman SVCXPRT *xprt; 13199064799SGarrett Wollman { 1328360efbdSAlfred Perlstein int sock; 13399064799SGarrett Wollman 1348360efbdSAlfred Perlstein assert(xprt != NULL); 1358360efbdSAlfred Perlstein 1368360efbdSAlfred Perlstein sock = xprt->xp_fd; 1378360efbdSAlfred Perlstein 1388360efbdSAlfred Perlstein rwlock_wrlock(&svc_fd_lock); 1398360efbdSAlfred Perlstein if ((sock < FD_SETSIZE) && (xports[sock] == xprt)) { 1408360efbdSAlfred Perlstein xports[sock] = NULL; 14199064799SGarrett Wollman FD_CLR(sock, &svc_fdset); 1428360efbdSAlfred Perlstein if (sock >= svc_maxfd) { 143ae1e6afdSPeter Wemm for (svc_maxfd--; svc_maxfd>=0; svc_maxfd--) 144ae1e6afdSPeter Wemm if (xports[svc_maxfd]) 145ae1e6afdSPeter Wemm break; 14699064799SGarrett Wollman } 14799064799SGarrett Wollman } 1488360efbdSAlfred Perlstein rwlock_unlock(&svc_fd_lock); 14999064799SGarrett Wollman } 15099064799SGarrett Wollman 1518360efbdSAlfred Perlstein /* 1528360efbdSAlfred Perlstein * Add a service program to the callout list. 1538360efbdSAlfred Perlstein * The dispatch routine will be called when a rpc request for this 1548360efbdSAlfred Perlstein * program number comes in. 1558360efbdSAlfred Perlstein */ 1568360efbdSAlfred Perlstein bool_t 1578360efbdSAlfred Perlstein svc_reg(xprt, prog, vers, dispatch, nconf) 1588360efbdSAlfred Perlstein SVCXPRT *xprt; 1598360efbdSAlfred Perlstein const rpcprog_t prog; 1608360efbdSAlfred Perlstein const rpcvers_t vers; 1618360efbdSAlfred Perlstein void (*dispatch) __P((struct svc_req *, SVCXPRT *)); 1628360efbdSAlfred Perlstein const struct netconfig *nconf; 1638360efbdSAlfred Perlstein { 1648360efbdSAlfred Perlstein bool_t dummy; 1658360efbdSAlfred Perlstein struct svc_callout *prev; 1668360efbdSAlfred Perlstein struct svc_callout *s; 1678360efbdSAlfred Perlstein struct netconfig *tnconf; 1688360efbdSAlfred Perlstein char *netid = NULL; 1698360efbdSAlfred Perlstein int flag = 0; 1708360efbdSAlfred Perlstein 1718360efbdSAlfred Perlstein /* VARIABLES PROTECTED BY svc_lock: s, prev, svc_head */ 1728360efbdSAlfred Perlstein 1738360efbdSAlfred Perlstein if (xprt->xp_netid) { 1748360efbdSAlfred Perlstein netid = strdup(xprt->xp_netid); 1758360efbdSAlfred Perlstein flag = 1; 1768360efbdSAlfred Perlstein } else if (nconf && nconf->nc_netid) { 1778360efbdSAlfred Perlstein netid = strdup(nconf->nc_netid); 1788360efbdSAlfred Perlstein flag = 1; 1798360efbdSAlfred Perlstein } else if ((tnconf = __rpcgettp(xprt->xp_fd)) != NULL) { 1808360efbdSAlfred Perlstein netid = strdup(tnconf->nc_netid); 1818360efbdSAlfred Perlstein flag = 1; 1828360efbdSAlfred Perlstein freenetconfigent(tnconf); 1838360efbdSAlfred Perlstein } /* must have been created with svc_raw_create */ 1848360efbdSAlfred Perlstein if ((netid == NULL) && (flag == 1)) { 1858360efbdSAlfred Perlstein return (FALSE); 1868360efbdSAlfred Perlstein } 1878360efbdSAlfred Perlstein 1888360efbdSAlfred Perlstein rwlock_wrlock(&svc_lock); 1898360efbdSAlfred Perlstein if ((s = svc_find(prog, vers, &prev, netid)) != NULL) { 1908360efbdSAlfred Perlstein if (netid) 1918360efbdSAlfred Perlstein free(netid); 1928360efbdSAlfred Perlstein if (s->sc_dispatch == dispatch) 1938360efbdSAlfred Perlstein goto rpcb_it; /* he is registering another xptr */ 1948360efbdSAlfred Perlstein rwlock_unlock(&svc_lock); 1958360efbdSAlfred Perlstein return (FALSE); 1968360efbdSAlfred Perlstein } 1978360efbdSAlfred Perlstein s = mem_alloc(sizeof (struct svc_callout)); 1988360efbdSAlfred Perlstein if (s == NULL) { 1998360efbdSAlfred Perlstein if (netid) 2008360efbdSAlfred Perlstein free(netid); 2018360efbdSAlfred Perlstein rwlock_unlock(&svc_lock); 2028360efbdSAlfred Perlstein return (FALSE); 2038360efbdSAlfred Perlstein } 2048360efbdSAlfred Perlstein 2058360efbdSAlfred Perlstein s->sc_prog = prog; 2068360efbdSAlfred Perlstein s->sc_vers = vers; 2078360efbdSAlfred Perlstein s->sc_dispatch = dispatch; 2088360efbdSAlfred Perlstein s->sc_netid = netid; 2098360efbdSAlfred Perlstein s->sc_next = svc_head; 2108360efbdSAlfred Perlstein svc_head = s; 2118360efbdSAlfred Perlstein 2128360efbdSAlfred Perlstein if ((xprt->xp_netid == NULL) && (flag == 1) && netid) 2138360efbdSAlfred Perlstein ((SVCXPRT *) xprt)->xp_netid = strdup(netid); 2148360efbdSAlfred Perlstein 2158360efbdSAlfred Perlstein rpcb_it: 2168360efbdSAlfred Perlstein rwlock_unlock(&svc_lock); 2178360efbdSAlfred Perlstein /* now register the information with the local binder service */ 2188360efbdSAlfred Perlstein if (nconf) { 2198360efbdSAlfred Perlstein /*LINTED const castaway*/ 2208360efbdSAlfred Perlstein dummy = rpcb_set(prog, vers, (struct netconfig *) nconf, 2218360efbdSAlfred Perlstein &((SVCXPRT *) xprt)->xp_ltaddr); 2228360efbdSAlfred Perlstein return (dummy); 2238360efbdSAlfred Perlstein } 2248360efbdSAlfred Perlstein return (TRUE); 2258360efbdSAlfred Perlstein } 2268360efbdSAlfred Perlstein 2278360efbdSAlfred Perlstein /* 2288360efbdSAlfred Perlstein * Remove a service program from the callout list. 2298360efbdSAlfred Perlstein */ 2308360efbdSAlfred Perlstein void 2318360efbdSAlfred Perlstein svc_unreg(prog, vers) 2328360efbdSAlfred Perlstein const rpcprog_t prog; 2338360efbdSAlfred Perlstein const rpcvers_t vers; 2348360efbdSAlfred Perlstein { 2358360efbdSAlfred Perlstein struct svc_callout *prev; 2368360efbdSAlfred Perlstein struct svc_callout *s; 2378360efbdSAlfred Perlstein 2388360efbdSAlfred Perlstein /* unregister the information anyway */ 2398360efbdSAlfred Perlstein (void) rpcb_unset(prog, vers, NULL); 2408360efbdSAlfred Perlstein rwlock_wrlock(&svc_lock); 2418360efbdSAlfred Perlstein while ((s = svc_find(prog, vers, &prev, NULL)) != NULL) { 2428360efbdSAlfred Perlstein if (prev == NULL) { 2438360efbdSAlfred Perlstein svc_head = s->sc_next; 2448360efbdSAlfred Perlstein } else { 2458360efbdSAlfred Perlstein prev->sc_next = s->sc_next; 2468360efbdSAlfred Perlstein } 2478360efbdSAlfred Perlstein s->sc_next = NULL; 2488360efbdSAlfred Perlstein if (s->sc_netid) 2498360efbdSAlfred Perlstein mem_free(s->sc_netid, sizeof (s->sc_netid) + 1); 2508360efbdSAlfred Perlstein mem_free(s, sizeof (struct svc_callout)); 2518360efbdSAlfred Perlstein } 2528360efbdSAlfred Perlstein rwlock_unlock(&svc_lock); 2538360efbdSAlfred Perlstein } 25499064799SGarrett Wollman 25599064799SGarrett Wollman /* ********************** CALLOUT list related stuff ************* */ 25699064799SGarrett Wollman 2578360efbdSAlfred Perlstein #ifdef PORTMAP 25899064799SGarrett Wollman /* 25999064799SGarrett Wollman * Add a service program to the callout list. 26099064799SGarrett Wollman * The dispatch routine will be called when a rpc request for this 26199064799SGarrett Wollman * program number comes in. 26299064799SGarrett Wollman */ 26399064799SGarrett Wollman bool_t 26499064799SGarrett Wollman svc_register(xprt, prog, vers, dispatch, protocol) 26599064799SGarrett Wollman SVCXPRT *xprt; 26699064799SGarrett Wollman u_long prog; 26799064799SGarrett Wollman u_long vers; 2688360efbdSAlfred Perlstein void (*dispatch) __P((struct svc_req *, SVCXPRT *)); 26999064799SGarrett Wollman int protocol; 27099064799SGarrett Wollman { 27199064799SGarrett Wollman struct svc_callout *prev; 2728360efbdSAlfred Perlstein struct svc_callout *s; 27399064799SGarrett Wollman 2748360efbdSAlfred Perlstein assert(xprt != NULL); 2758360efbdSAlfred Perlstein assert(dispatch != NULL); 2768360efbdSAlfred Perlstein 2778360efbdSAlfred Perlstein if ((s = svc_find((rpcprog_t)prog, (rpcvers_t)vers, &prev, NULL)) != 2788360efbdSAlfred Perlstein NULL) { 27999064799SGarrett Wollman if (s->sc_dispatch == dispatch) 28099064799SGarrett Wollman goto pmap_it; /* he is registering another xptr */ 28199064799SGarrett Wollman return (FALSE); 28299064799SGarrett Wollman } 2838360efbdSAlfred Perlstein s = mem_alloc(sizeof(struct svc_callout)); 2848360efbdSAlfred Perlstein if (s == NULL) { 28599064799SGarrett Wollman return (FALSE); 28699064799SGarrett Wollman } 2878360efbdSAlfred Perlstein s->sc_prog = (rpcprog_t)prog; 2888360efbdSAlfred Perlstein s->sc_vers = (rpcvers_t)vers; 28999064799SGarrett Wollman s->sc_dispatch = dispatch; 29099064799SGarrett Wollman s->sc_next = svc_head; 29199064799SGarrett Wollman svc_head = s; 29299064799SGarrett Wollman pmap_it: 29399064799SGarrett Wollman /* now register the information with the local binder service */ 29499064799SGarrett Wollman if (protocol) { 29599064799SGarrett Wollman return (pmap_set(prog, vers, protocol, xprt->xp_port)); 29699064799SGarrett Wollman } 29799064799SGarrett Wollman return (TRUE); 29899064799SGarrett Wollman } 29999064799SGarrett Wollman 30099064799SGarrett Wollman /* 30199064799SGarrett Wollman * Remove a service program from the callout list. 30299064799SGarrett Wollman */ 30399064799SGarrett Wollman void 30499064799SGarrett Wollman svc_unregister(prog, vers) 30599064799SGarrett Wollman u_long prog; 30699064799SGarrett Wollman u_long vers; 30799064799SGarrett Wollman { 30899064799SGarrett Wollman struct svc_callout *prev; 3098360efbdSAlfred Perlstein struct svc_callout *s; 31099064799SGarrett Wollman 3118360efbdSAlfred Perlstein if ((s = svc_find((rpcprog_t)prog, (rpcvers_t)vers, &prev, NULL)) == 3128360efbdSAlfred Perlstein NULL) 31399064799SGarrett Wollman return; 3148360efbdSAlfred Perlstein if (prev == NULL) { 31599064799SGarrett Wollman svc_head = s->sc_next; 31699064799SGarrett Wollman } else { 31799064799SGarrett Wollman prev->sc_next = s->sc_next; 31899064799SGarrett Wollman } 3198360efbdSAlfred Perlstein s->sc_next = NULL; 3208360efbdSAlfred Perlstein mem_free(s, sizeof(struct svc_callout)); 32199064799SGarrett Wollman /* now unregister the information with the local binder service */ 32299064799SGarrett Wollman (void)pmap_unset(prog, vers); 32399064799SGarrett Wollman } 3248360efbdSAlfred Perlstein #endif /* PORTMAP */ 32599064799SGarrett Wollman 32699064799SGarrett Wollman /* 32799064799SGarrett Wollman * Search the callout list for a program number, return the callout 32899064799SGarrett Wollman * struct. 32999064799SGarrett Wollman */ 33099064799SGarrett Wollman static struct svc_callout * 3318360efbdSAlfred Perlstein svc_find(prog, vers, prev, netid) 3328360efbdSAlfred Perlstein rpcprog_t prog; 3338360efbdSAlfred Perlstein rpcvers_t vers; 33499064799SGarrett Wollman struct svc_callout **prev; 3358360efbdSAlfred Perlstein char *netid; 33699064799SGarrett Wollman { 3378360efbdSAlfred Perlstein struct svc_callout *s, *p; 33899064799SGarrett Wollman 3398360efbdSAlfred Perlstein assert(prev != NULL); 3408360efbdSAlfred Perlstein 3418360efbdSAlfred Perlstein p = NULL; 3428360efbdSAlfred Perlstein for (s = svc_head; s != NULL; s = s->sc_next) { 3438360efbdSAlfred Perlstein if (((s->sc_prog == prog) && (s->sc_vers == vers)) && 3448360efbdSAlfred Perlstein ((netid == NULL) || (s->sc_netid == NULL) || 3458360efbdSAlfred Perlstein (strcmp(netid, s->sc_netid) == 0))) 3468360efbdSAlfred Perlstein break; 34799064799SGarrett Wollman p = s; 34899064799SGarrett Wollman } 34999064799SGarrett Wollman *prev = p; 35099064799SGarrett Wollman return (s); 35199064799SGarrett Wollman } 35299064799SGarrett Wollman 35399064799SGarrett Wollman /* ******************* REPLY GENERATION ROUTINES ************ */ 35499064799SGarrett Wollman 35599064799SGarrett Wollman /* 35699064799SGarrett Wollman * Send a reply to an rpc request 35799064799SGarrett Wollman */ 35899064799SGarrett Wollman bool_t 35999064799SGarrett Wollman svc_sendreply(xprt, xdr_results, xdr_location) 3608360efbdSAlfred Perlstein SVCXPRT *xprt; 36199064799SGarrett Wollman xdrproc_t xdr_results; 36299064799SGarrett Wollman caddr_t xdr_location; 36399064799SGarrett Wollman { 36499064799SGarrett Wollman struct rpc_msg rply; 36599064799SGarrett Wollman 3668360efbdSAlfred Perlstein assert(xprt != NULL); 3678360efbdSAlfred Perlstein 36899064799SGarrett Wollman rply.rm_direction = REPLY; 36999064799SGarrett Wollman rply.rm_reply.rp_stat = MSG_ACCEPTED; 37099064799SGarrett Wollman rply.acpted_rply.ar_verf = xprt->xp_verf; 37199064799SGarrett Wollman rply.acpted_rply.ar_stat = SUCCESS; 37299064799SGarrett Wollman rply.acpted_rply.ar_results.where = xdr_location; 37399064799SGarrett Wollman rply.acpted_rply.ar_results.proc = xdr_results; 37499064799SGarrett Wollman return (SVC_REPLY(xprt, &rply)); 37599064799SGarrett Wollman } 37699064799SGarrett Wollman 37799064799SGarrett Wollman /* 37899064799SGarrett Wollman * No procedure error reply 37999064799SGarrett Wollman */ 38099064799SGarrett Wollman void 38199064799SGarrett Wollman svcerr_noproc(xprt) 3828360efbdSAlfred Perlstein 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 39999064799SGarrett Wollman svcerr_decode(xprt) 4008360efbdSAlfred Perlstein SVCXPRT *xprt; 40199064799SGarrett Wollman { 40299064799SGarrett Wollman struct rpc_msg rply; 40399064799SGarrett Wollman 4048360efbdSAlfred Perlstein assert(xprt != NULL); 4058360efbdSAlfred Perlstein 40699064799SGarrett Wollman rply.rm_direction = REPLY; 40799064799SGarrett Wollman rply.rm_reply.rp_stat = MSG_ACCEPTED; 40899064799SGarrett Wollman rply.acpted_rply.ar_verf = xprt->xp_verf; 40999064799SGarrett Wollman rply.acpted_rply.ar_stat = GARBAGE_ARGS; 41099064799SGarrett Wollman SVC_REPLY(xprt, &rply); 41199064799SGarrett Wollman } 41299064799SGarrett Wollman 41399064799SGarrett Wollman /* 41499064799SGarrett Wollman * Some system error 41599064799SGarrett Wollman */ 41699064799SGarrett Wollman void 41799064799SGarrett Wollman svcerr_systemerr(xprt) 4188360efbdSAlfred Perlstein SVCXPRT *xprt; 41999064799SGarrett Wollman { 42099064799SGarrett Wollman struct rpc_msg rply; 42199064799SGarrett Wollman 4228360efbdSAlfred Perlstein assert(xprt != NULL); 4238360efbdSAlfred Perlstein 42499064799SGarrett Wollman rply.rm_direction = REPLY; 42599064799SGarrett Wollman rply.rm_reply.rp_stat = MSG_ACCEPTED; 42699064799SGarrett Wollman rply.acpted_rply.ar_verf = xprt->xp_verf; 42799064799SGarrett Wollman rply.acpted_rply.ar_stat = SYSTEM_ERR; 42899064799SGarrett Wollman SVC_REPLY(xprt, &rply); 42999064799SGarrett Wollman } 43099064799SGarrett Wollman 4318360efbdSAlfred Perlstein #if 0 4328360efbdSAlfred Perlstein /* 4338360efbdSAlfred Perlstein * Tell RPC package to not complain about version errors to the client. This 4348360efbdSAlfred Perlstein * is useful when revving broadcast protocols that sit on a fixed address. 4358360efbdSAlfred Perlstein * There is really one (or should be only one) example of this kind of 4368360efbdSAlfred Perlstein * protocol: the portmapper (or rpc binder). 4378360efbdSAlfred Perlstein */ 4388360efbdSAlfred Perlstein void 4398360efbdSAlfred Perlstein __svc_versquiet_on(xprt) 4408360efbdSAlfred Perlstein SVCXPRT *xprt; 4418360efbdSAlfred Perlstein { 4428360efbdSAlfred Perlstein u_long tmp; 4438360efbdSAlfred Perlstein 4448360efbdSAlfred Perlstein tmp = ((u_long) xprt->xp_p3) | SVC_VERSQUIET; 4458360efbdSAlfred Perlstein xprt->xp_p3 = (caddr_t) tmp; 4468360efbdSAlfred Perlstein } 4478360efbdSAlfred Perlstein 4488360efbdSAlfred Perlstein void 4498360efbdSAlfred Perlstein __svc_versquiet_off(xprt) 4508360efbdSAlfred Perlstein SVCXPRT *xprt; 4518360efbdSAlfred Perlstein { 4528360efbdSAlfred Perlstein u_long tmp; 4538360efbdSAlfred Perlstein 4548360efbdSAlfred Perlstein tmp = ((u_long) xprt->xp_p3) & ~SVC_VERSQUIET; 4558360efbdSAlfred Perlstein xprt->xp_p3 = (caddr_t) tmp; 4568360efbdSAlfred Perlstein } 4578360efbdSAlfred Perlstein 4588360efbdSAlfred Perlstein void 4598360efbdSAlfred Perlstein svc_versquiet(xprt) 4608360efbdSAlfred Perlstein SVCXPRT *xprt; 4618360efbdSAlfred Perlstein { 4628360efbdSAlfred Perlstein __svc_versquiet_on(xprt); 4638360efbdSAlfred Perlstein } 4648360efbdSAlfred Perlstein 4658360efbdSAlfred Perlstein int 4668360efbdSAlfred Perlstein __svc_versquiet_get(xprt) 4678360efbdSAlfred Perlstein SVCXPRT *xprt; 4688360efbdSAlfred Perlstein { 4698360efbdSAlfred Perlstein return ((int) xprt->xp_p3) & SVC_VERSQUIET; 4708360efbdSAlfred Perlstein } 4718360efbdSAlfred Perlstein #endif 4728360efbdSAlfred Perlstein 47399064799SGarrett Wollman /* 47499064799SGarrett Wollman * Authentication error reply 47599064799SGarrett Wollman */ 47699064799SGarrett Wollman void 47799064799SGarrett Wollman svcerr_auth(xprt, why) 47899064799SGarrett Wollman SVCXPRT *xprt; 47999064799SGarrett Wollman enum auth_stat why; 48099064799SGarrett Wollman { 48199064799SGarrett Wollman struct rpc_msg rply; 48299064799SGarrett Wollman 4838360efbdSAlfred Perlstein assert(xprt != NULL); 4848360efbdSAlfred Perlstein 48599064799SGarrett Wollman rply.rm_direction = REPLY; 48699064799SGarrett Wollman rply.rm_reply.rp_stat = MSG_DENIED; 48799064799SGarrett Wollman rply.rjcted_rply.rj_stat = AUTH_ERROR; 48899064799SGarrett Wollman rply.rjcted_rply.rj_why = why; 48999064799SGarrett Wollman SVC_REPLY(xprt, &rply); 49099064799SGarrett Wollman } 49199064799SGarrett Wollman 49299064799SGarrett Wollman /* 49399064799SGarrett Wollman * Auth too weak error reply 49499064799SGarrett Wollman */ 49599064799SGarrett Wollman void 49699064799SGarrett Wollman svcerr_weakauth(xprt) 49799064799SGarrett Wollman SVCXPRT *xprt; 49899064799SGarrett Wollman { 49999064799SGarrett Wollman 5008360efbdSAlfred Perlstein assert(xprt != NULL); 5018360efbdSAlfred Perlstein 50299064799SGarrett Wollman svcerr_auth(xprt, AUTH_TOOWEAK); 50399064799SGarrett Wollman } 50499064799SGarrett Wollman 50599064799SGarrett Wollman /* 50699064799SGarrett Wollman * Program unavailable error reply 50799064799SGarrett Wollman */ 50899064799SGarrett Wollman void 50999064799SGarrett Wollman svcerr_noprog(xprt) 5108360efbdSAlfred Perlstein SVCXPRT *xprt; 51199064799SGarrett Wollman { 51299064799SGarrett Wollman struct rpc_msg rply; 51399064799SGarrett Wollman 5148360efbdSAlfred Perlstein assert(xprt != NULL); 5158360efbdSAlfred Perlstein 51699064799SGarrett Wollman rply.rm_direction = REPLY; 51799064799SGarrett Wollman rply.rm_reply.rp_stat = MSG_ACCEPTED; 51899064799SGarrett Wollman rply.acpted_rply.ar_verf = xprt->xp_verf; 51999064799SGarrett Wollman rply.acpted_rply.ar_stat = PROG_UNAVAIL; 52099064799SGarrett Wollman SVC_REPLY(xprt, &rply); 52199064799SGarrett Wollman } 52299064799SGarrett Wollman 52399064799SGarrett Wollman /* 52499064799SGarrett Wollman * Program version mismatch error reply 52599064799SGarrett Wollman */ 52699064799SGarrett Wollman void 52799064799SGarrett Wollman svcerr_progvers(xprt, low_vers, high_vers) 5288360efbdSAlfred Perlstein SVCXPRT *xprt; 5298360efbdSAlfred Perlstein rpcvers_t low_vers; 5308360efbdSAlfred Perlstein rpcvers_t high_vers; 53199064799SGarrett Wollman { 53299064799SGarrett Wollman struct rpc_msg rply; 53399064799SGarrett Wollman 5348360efbdSAlfred Perlstein assert(xprt != NULL); 5358360efbdSAlfred Perlstein 53699064799SGarrett Wollman rply.rm_direction = REPLY; 53799064799SGarrett Wollman rply.rm_reply.rp_stat = MSG_ACCEPTED; 53899064799SGarrett Wollman rply.acpted_rply.ar_verf = xprt->xp_verf; 53999064799SGarrett Wollman rply.acpted_rply.ar_stat = PROG_MISMATCH; 5408360efbdSAlfred Perlstein rply.acpted_rply.ar_vers.low = (u_int32_t)low_vers; 5418360efbdSAlfred Perlstein rply.acpted_rply.ar_vers.high = (u_int32_t)high_vers; 54299064799SGarrett Wollman SVC_REPLY(xprt, &rply); 54399064799SGarrett Wollman } 54499064799SGarrett Wollman 54599064799SGarrett Wollman /* ******************* SERVER INPUT STUFF ******************* */ 54699064799SGarrett Wollman 54799064799SGarrett Wollman /* 54899064799SGarrett Wollman * Get server side input from some transport. 54999064799SGarrett Wollman * 55099064799SGarrett Wollman * Statement of authentication parameters management: 55199064799SGarrett Wollman * This function owns and manages all authentication parameters, specifically 55299064799SGarrett Wollman * the "raw" parameters (msg.rm_call.cb_cred and msg.rm_call.cb_verf) and 55399064799SGarrett Wollman * the "cooked" credentials (rqst->rq_clntcred). 55499064799SGarrett Wollman * However, this function does not know the structure of the cooked 55599064799SGarrett Wollman * credentials, so it make the following assumptions: 55699064799SGarrett Wollman * a) the structure is contiguous (no pointers), and 55799064799SGarrett Wollman * b) the cred structure size does not exceed RQCRED_SIZE bytes. 55899064799SGarrett Wollman * In all events, all three parameters are freed upon exit from this routine. 55999064799SGarrett Wollman * The storage is trivially management on the call stack in user land, but 56099064799SGarrett Wollman * is mallocated in kernel land. 56199064799SGarrett Wollman */ 56299064799SGarrett Wollman 56399064799SGarrett Wollman void 56499064799SGarrett Wollman svc_getreq(rdfds) 56599064799SGarrett Wollman int rdfds; 56699064799SGarrett Wollman { 56799064799SGarrett Wollman fd_set readfds; 56899064799SGarrett Wollman 56999064799SGarrett Wollman FD_ZERO(&readfds); 57099064799SGarrett Wollman readfds.fds_bits[0] = rdfds; 57199064799SGarrett Wollman svc_getreqset(&readfds); 57299064799SGarrett Wollman } 57399064799SGarrett Wollman 57499064799SGarrett Wollman void 57599064799SGarrett Wollman svc_getreqset(readfds) 57699064799SGarrett Wollman fd_set *readfds; 57799064799SGarrett Wollman { 5788360efbdSAlfred Perlstein int bit, fd; 5798360efbdSAlfred Perlstein fd_mask mask, *maskp; 5808360efbdSAlfred Perlstein int sock; 5818360efbdSAlfred Perlstein 5828360efbdSAlfred Perlstein assert(readfds != NULL); 5838360efbdSAlfred Perlstein 5848360efbdSAlfred Perlstein maskp = readfds->fds_bits; 5858360efbdSAlfred Perlstein for (sock = 0; sock < FD_SETSIZE; sock += NFDBITS) { 5868360efbdSAlfred Perlstein for (mask = *maskp++; (bit = ffs(mask)) != 0; 5878360efbdSAlfred Perlstein mask ^= (1 << (bit - 1))) { 5888360efbdSAlfred Perlstein /* sock has input waiting */ 5898360efbdSAlfred Perlstein fd = sock + bit - 1; 5908360efbdSAlfred Perlstein svc_getreq_common(fd); 5918360efbdSAlfred Perlstein } 5928360efbdSAlfred Perlstein } 593ae1e6afdSPeter Wemm } 594ae1e6afdSPeter Wemm 595ae1e6afdSPeter Wemm void 5968360efbdSAlfred Perlstein svc_getreq_common(fd) 5978360efbdSAlfred Perlstein int fd; 59899064799SGarrett Wollman { 5998360efbdSAlfred Perlstein SVCXPRT *xprt; 6008360efbdSAlfred Perlstein struct svc_req r; 60199064799SGarrett Wollman struct rpc_msg msg; 60299064799SGarrett Wollman int prog_found; 6038360efbdSAlfred Perlstein rpcvers_t low_vers; 6048360efbdSAlfred Perlstein rpcvers_t high_vers; 6058360efbdSAlfred Perlstein enum xprt_stat stat; 60699064799SGarrett Wollman char cred_area[2*MAX_AUTH_BYTES + RQCRED_SIZE]; 6078360efbdSAlfred Perlstein 60899064799SGarrett Wollman msg.rm_call.cb_cred.oa_base = cred_area; 60999064799SGarrett Wollman msg.rm_call.cb_verf.oa_base = &(cred_area[MAX_AUTH_BYTES]); 61099064799SGarrett Wollman r.rq_clntcred = &(cred_area[2*MAX_AUTH_BYTES]); 61199064799SGarrett Wollman 6128360efbdSAlfred Perlstein rwlock_rdlock(&svc_fd_lock); 6138360efbdSAlfred Perlstein xprt = xports[fd]; 6148360efbdSAlfred Perlstein rwlock_unlock(&svc_fd_lock); 615ae1e6afdSPeter Wemm if (xprt == NULL) 616ae1e6afdSPeter Wemm /* But do we control sock? */ 6178360efbdSAlfred Perlstein return; 61899064799SGarrett Wollman /* now receive msgs from xprtprt (support batch calls) */ 61999064799SGarrett Wollman do { 62099064799SGarrett Wollman if (SVC_RECV(xprt, &msg)) { 62199064799SGarrett Wollman 62299064799SGarrett Wollman /* now find the exported program and call it */ 6238360efbdSAlfred Perlstein struct svc_callout *s; 62499064799SGarrett Wollman enum auth_stat why; 62599064799SGarrett Wollman 62699064799SGarrett Wollman r.rq_xprt = xprt; 62799064799SGarrett Wollman r.rq_prog = msg.rm_call.cb_prog; 62899064799SGarrett Wollman r.rq_vers = msg.rm_call.cb_vers; 62999064799SGarrett Wollman r.rq_proc = msg.rm_call.cb_proc; 63099064799SGarrett Wollman r.rq_cred = msg.rm_call.cb_cred; 63199064799SGarrett Wollman /* first authenticate the message */ 63299064799SGarrett Wollman if ((why = _authenticate(&r, &msg)) != AUTH_OK) { 63399064799SGarrett Wollman svcerr_auth(xprt, why); 63499064799SGarrett Wollman goto call_done; 63599064799SGarrett Wollman } 63699064799SGarrett Wollman /* now match message with a registered service*/ 63799064799SGarrett Wollman prog_found = FALSE; 6388360efbdSAlfred Perlstein low_vers = (rpcvers_t) -1L; 6398360efbdSAlfred Perlstein high_vers = (rpcvers_t) 0L; 6408360efbdSAlfred Perlstein for (s = svc_head; s != NULL; s = s->sc_next) { 64199064799SGarrett Wollman if (s->sc_prog == r.rq_prog) { 64299064799SGarrett Wollman if (s->sc_vers == r.rq_vers) { 64399064799SGarrett Wollman (*s->sc_dispatch)(&r, xprt); 64499064799SGarrett Wollman goto call_done; 64599064799SGarrett Wollman } /* found correct version */ 64699064799SGarrett Wollman prog_found = TRUE; 64799064799SGarrett Wollman if (s->sc_vers < low_vers) 64899064799SGarrett Wollman low_vers = s->sc_vers; 64999064799SGarrett Wollman if (s->sc_vers > high_vers) 65099064799SGarrett Wollman high_vers = s->sc_vers; 65199064799SGarrett Wollman } /* found correct program */ 65299064799SGarrett Wollman } 65399064799SGarrett Wollman /* 65499064799SGarrett Wollman * if we got here, the program or version 65599064799SGarrett Wollman * is not served ... 65699064799SGarrett Wollman */ 65799064799SGarrett Wollman if (prog_found) 6588360efbdSAlfred Perlstein svcerr_progvers(xprt, low_vers, high_vers); 65999064799SGarrett Wollman else 66099064799SGarrett Wollman svcerr_noprog(xprt); 66199064799SGarrett Wollman /* Fall through to ... */ 66299064799SGarrett Wollman } 6638360efbdSAlfred Perlstein /* 6648360efbdSAlfred Perlstein * Check if the xprt has been disconnected in a 6658360efbdSAlfred Perlstein * recursive call in the service dispatch routine. 6668360efbdSAlfred Perlstein * If so, then break. 6678360efbdSAlfred Perlstein */ 6688360efbdSAlfred Perlstein rwlock_rdlock(&svc_fd_lock); 6698360efbdSAlfred Perlstein if (xprt != xports[fd]) { 6708360efbdSAlfred Perlstein rwlock_unlock(&svc_fd_lock); 6718360efbdSAlfred Perlstein break; 6728360efbdSAlfred Perlstein } 6738360efbdSAlfred Perlstein rwlock_unlock(&svc_fd_lock); 67499064799SGarrett Wollman call_done: 67599064799SGarrett Wollman if ((stat = SVC_STAT(xprt)) == XPRT_DIED){ 67699064799SGarrett Wollman SVC_DESTROY(xprt); 67799064799SGarrett Wollman break; 67899064799SGarrett Wollman } 67999064799SGarrett Wollman } while (stat == XPRT_MOREREQS); 68099064799SGarrett Wollman } 6818360efbdSAlfred Perlstein 6828360efbdSAlfred Perlstein 6838360efbdSAlfred Perlstein void 6848360efbdSAlfred Perlstein svc_getreq_poll(pfdp, pollretval) 6858360efbdSAlfred Perlstein struct pollfd *pfdp; 6868360efbdSAlfred Perlstein int pollretval; 6878360efbdSAlfred Perlstein { 6888360efbdSAlfred Perlstein int i; 6898360efbdSAlfred Perlstein int fds_found; 6908360efbdSAlfred Perlstein 6918360efbdSAlfred Perlstein for (i = fds_found = 0; fds_found < pollretval; i++) { 6928360efbdSAlfred Perlstein struct pollfd *p = &pfdp[i]; 6938360efbdSAlfred Perlstein 6948360efbdSAlfred Perlstein if (p->revents) { 6958360efbdSAlfred Perlstein /* fd has input waiting */ 6968360efbdSAlfred Perlstein fds_found++; 6978360efbdSAlfred Perlstein /* 6988360efbdSAlfred Perlstein * We assume that this function is only called 6998360efbdSAlfred Perlstein * via someone _select()ing from svc_fdset or 7008360efbdSAlfred Perlstein * _poll()ing from svc_pollset[]. Thus it's safe 7018360efbdSAlfred Perlstein * to handle the POLLNVAL event by simply turning 7028360efbdSAlfred Perlstein * the corresponding bit off in svc_fdset. The 7038360efbdSAlfred Perlstein * svc_pollset[] array is derived from svc_fdset 7048360efbdSAlfred Perlstein * and so will also be updated eventually. 7058360efbdSAlfred Perlstein * 7068360efbdSAlfred Perlstein * XXX Should we do an xprt_unregister() instead? 7078360efbdSAlfred Perlstein */ 7088360efbdSAlfred Perlstein if (p->revents & POLLNVAL) { 7098360efbdSAlfred Perlstein rwlock_wrlock(&svc_fd_lock); 7108360efbdSAlfred Perlstein FD_CLR(p->fd, &svc_fdset); 7118360efbdSAlfred Perlstein rwlock_unlock(&svc_fd_lock); 7128360efbdSAlfred Perlstein } else 7138360efbdSAlfred Perlstein svc_getreq_common(p->fd); 7148360efbdSAlfred Perlstein } 71599064799SGarrett Wollman } 71699064799SGarrett Wollman } 717