svc.c revision 74462
174462Salfred/*	$NetBSD: svc.c,v 1.21 2000/07/06 03:10:35 christos Exp $	*/
274462Salfred
31901Swollman/*
41901Swollman * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
51901Swollman * unrestricted use provided that this legend is included on all tape
61901Swollman * media and as a part of the software program in whole or part.  Users
71901Swollman * may copy or modify Sun RPC without charge, but are not authorized
81901Swollman * to license or distribute it to anyone else except as part of a product or
91901Swollman * program developed by the user.
108870Srgrimes *
111901Swollman * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
121901Swollman * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
131901Swollman * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
148870Srgrimes *
151901Swollman * Sun RPC is provided with no support and without any obligation on the
161901Swollman * part of Sun Microsystems, Inc. to assist in its use, correction,
171901Swollman * modification or enhancement.
188870Srgrimes *
191901Swollman * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
201901Swollman * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
211901Swollman * OR ANY PART THEREOF.
228870Srgrimes *
231901Swollman * In no event will Sun Microsystems, Inc. be liable for any lost revenue
241901Swollman * or profits or other special, indirect and consequential damages, even if
251901Swollman * Sun has been advised of the possibility of such damages.
268870Srgrimes *
271901Swollman * Sun Microsystems, Inc.
281901Swollman * 2550 Garcia Avenue
291901Swollman * Mountain View, California  94043
301901Swollman */
311901Swollman
328870Srgrimes#if defined(LIBC_SCCS) && !defined(lint)
331901Swollman/*static char *sccsid = "from: @(#)svc.c 1.44 88/02/08 Copyr 1984 Sun Micro";*/
341901Swollman/*static char *sccsid = "from: @(#)svc.c	2.4 88/08/11 4.0 RPCSRC";*/
3550476Speterstatic char *rcsid = "$FreeBSD: head/lib/libc/rpc/svc.c 74462 2001-03-19 12:50:13Z alfred $";
361901Swollman#endif
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
4874462Salfred#include "reentrant.h"
4974462Salfred#include "namespace.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"
6474462Salfred
651901Swollmanstatic SVCXPRT **xports;
661901Swollman
671901Swollman#define	RQCRED_SIZE	400		/* this size is excessive */
681901Swollman
6974462Salfred#define SVC_VERSQUIET 0x0001		/* keep quiet about vers mismatch */
7074462Salfred#define version_keepquiet(xp) ((u_long)(xp)->xp_p3 & SVC_VERSQUIET)
7174462Salfred
7221087Speter#define max(a, b) (a > b ? a : b)
7316270Sjraynard
741901Swollman/*
751901Swollman * The services list
761901Swollman * Each entry represents a set of procedures (an rpc program).
771901Swollman * The dispatch routine takes request structs and runs the
781901Swollman * apropriate procedure.
791901Swollman */
801901Swollmanstatic struct svc_callout {
811901Swollman	struct svc_callout *sc_next;
8274462Salfred	rpcprog_t	    sc_prog;
8374462Salfred	rpcvers_t	    sc_vers;
8474462Salfred	char		   *sc_netid;
8574462Salfred	void		    (*sc_dispatch) __P((struct svc_req *, SVCXPRT *));
861901Swollman} *svc_head;
871901Swollman
8874462Salfredextern rwlock_t svc_lock;
8974462Salfredextern rwlock_t svc_fd_lock;
901901Swollman
9174462Salfredstatic struct svc_callout *svc_find __P((rpcprog_t, rpcvers_t,
9274462Salfred					 struct svc_callout **, char *));
9321087Speter
941901Swollman/* ***************  SVCXPRT related stuff **************** */
951901Swollman
961901Swollman/*
971901Swollman * Activate a transport handle.
981901Swollman */
991901Swollmanvoid
1001901Swollmanxprt_register(xprt)
1011901Swollman	SVCXPRT *xprt;
1021901Swollman{
10374462Salfred	int sock;
1041901Swollman
10574462Salfred	assert(xprt != NULL);
10621087Speter
10774462Salfred	sock = xprt->xp_fd;
10874462Salfred
10974462Salfred	rwlock_wrlock(&svc_fd_lock);
11074462Salfred	if (xports == NULL) {
11174462Salfred		xports = (SVCXPRT **)
11274462Salfred			mem_alloc(FD_SETSIZE * sizeof(SVCXPRT *));
11374462Salfred		if (xports == NULL)
11474462Salfred			return;
11574462Salfred		memset(xports, '\0', FD_SETSIZE * sizeof(SVCXPRT *));
1161901Swollman	}
11774462Salfred	if (sock < FD_SETSIZE) {
11874462Salfred		xports[sock] = xprt;
1191901Swollman		FD_SET(sock, &svc_fdset);
12074462Salfred		svc_maxfd = max(svc_maxfd, sock);
1211901Swollman	}
12274462Salfred	rwlock_unlock(&svc_fd_lock);
1231901Swollman}
1241901Swollman
1251901Swollman/*
1268870Srgrimes * De-activate a transport handle.
1271901Swollman */
1281901Swollmanvoid
12974462Salfredxprt_unregister(xprt)
1301901Swollman	SVCXPRT *xprt;
1318870Srgrimes{
13274462Salfred	int sock;
1331901Swollman
13474462Salfred	assert(xprt != NULL);
13574462Salfred
13674462Salfred	sock = xprt->xp_fd;
13774462Salfred
13874462Salfred	rwlock_wrlock(&svc_fd_lock);
13974462Salfred	if ((sock < FD_SETSIZE) && (xports[sock] == xprt)) {
14074462Salfred		xports[sock] = NULL;
14174462Salfred		FD_CLR(sock, &svc_fdset);
14274462Salfred		if (sock >= svc_maxfd) {
14374462Salfred			for (svc_maxfd--; svc_maxfd>=0; svc_maxfd--)
14421087Speter				if (xports[svc_maxfd])
14521087Speter					break;
14621087Speter		}
1471901Swollman	}
14874462Salfred	rwlock_unlock(&svc_fd_lock);
1491901Swollman}
1501901Swollman
15174462Salfred/*
15274462Salfred * Add a service program to the callout list.
15374462Salfred * The dispatch routine will be called when a rpc request for this
15474462Salfred * program number comes in.
15574462Salfred */
15674462Salfredbool_t
15774462Salfredsvc_reg(xprt, prog, vers, dispatch, nconf)
15874462Salfred	SVCXPRT *xprt;
15974462Salfred	const rpcprog_t prog;
16074462Salfred	const rpcvers_t vers;
16174462Salfred	void (*dispatch) __P((struct svc_req *, SVCXPRT *));
16274462Salfred	const struct netconfig *nconf;
16374462Salfred{
16474462Salfred	bool_t dummy;
16574462Salfred	struct svc_callout *prev;
16674462Salfred	struct svc_callout *s;
16774462Salfred	struct netconfig *tnconf;
16874462Salfred	char *netid = NULL;
16974462Salfred	int flag = 0;
1701901Swollman
17174462Salfred/* VARIABLES PROTECTED BY svc_lock: s, prev, svc_head */
17274462Salfred
17374462Salfred	if (xprt->xp_netid) {
17474462Salfred		netid = strdup(xprt->xp_netid);
17574462Salfred		flag = 1;
17674462Salfred	} else if (nconf && nconf->nc_netid) {
17774462Salfred		netid = strdup(nconf->nc_netid);
17874462Salfred		flag = 1;
17974462Salfred	} else if ((tnconf = __rpcgettp(xprt->xp_fd)) != NULL) {
18074462Salfred		netid = strdup(tnconf->nc_netid);
18174462Salfred		flag = 1;
18274462Salfred		freenetconfigent(tnconf);
18374462Salfred	} /* must have been created with svc_raw_create */
18474462Salfred	if ((netid == NULL) && (flag == 1)) {
18574462Salfred		return (FALSE);
18674462Salfred	}
18774462Salfred
18874462Salfred	rwlock_wrlock(&svc_lock);
18974462Salfred	if ((s = svc_find(prog, vers, &prev, netid)) != NULL) {
19074462Salfred		if (netid)
19174462Salfred			free(netid);
19274462Salfred		if (s->sc_dispatch == dispatch)
19374462Salfred			goto rpcb_it; /* he is registering another xptr */
19474462Salfred		rwlock_unlock(&svc_lock);
19574462Salfred		return (FALSE);
19674462Salfred	}
19774462Salfred	s = mem_alloc(sizeof (struct svc_callout));
19874462Salfred	if (s == NULL) {
19974462Salfred		if (netid)
20074462Salfred			free(netid);
20174462Salfred		rwlock_unlock(&svc_lock);
20274462Salfred		return (FALSE);
20374462Salfred	}
20474462Salfred
20574462Salfred	s->sc_prog = prog;
20674462Salfred	s->sc_vers = vers;
20774462Salfred	s->sc_dispatch = dispatch;
20874462Salfred	s->sc_netid = netid;
20974462Salfred	s->sc_next = svc_head;
21074462Salfred	svc_head = s;
21174462Salfred
21274462Salfred	if ((xprt->xp_netid == NULL) && (flag == 1) && netid)
21374462Salfred		((SVCXPRT *) xprt)->xp_netid = strdup(netid);
21474462Salfred
21574462Salfredrpcb_it:
21674462Salfred	rwlock_unlock(&svc_lock);
21774462Salfred	/* now register the information with the local binder service */
21874462Salfred	if (nconf) {
21974462Salfred		/*LINTED const castaway*/
22074462Salfred		dummy = rpcb_set(prog, vers, (struct netconfig *) nconf,
22174462Salfred		&((SVCXPRT *) xprt)->xp_ltaddr);
22274462Salfred		return (dummy);
22374462Salfred	}
22474462Salfred	return (TRUE);
22574462Salfred}
22674462Salfred
22774462Salfred/*
22874462Salfred * Remove a service program from the callout list.
22974462Salfred */
23074462Salfredvoid
23174462Salfredsvc_unreg(prog, vers)
23274462Salfred	const rpcprog_t prog;
23374462Salfred	const rpcvers_t vers;
23474462Salfred{
23574462Salfred	struct svc_callout *prev;
23674462Salfred	struct svc_callout *s;
23774462Salfred
23874462Salfred	/* unregister the information anyway */
23974462Salfred	(void) rpcb_unset(prog, vers, NULL);
24074462Salfred	rwlock_wrlock(&svc_lock);
24174462Salfred	while ((s = svc_find(prog, vers, &prev, NULL)) != NULL) {
24274462Salfred		if (prev == NULL) {
24374462Salfred			svc_head = s->sc_next;
24474462Salfred		} else {
24574462Salfred			prev->sc_next = s->sc_next;
24674462Salfred		}
24774462Salfred		s->sc_next = NULL;
24874462Salfred		if (s->sc_netid)
24974462Salfred			mem_free(s->sc_netid, sizeof (s->sc_netid) + 1);
25074462Salfred		mem_free(s, sizeof (struct svc_callout));
25174462Salfred	}
25274462Salfred	rwlock_unlock(&svc_lock);
25374462Salfred}
25474462Salfred
2551901Swollman/* ********************** CALLOUT list related stuff ************* */
2561901Swollman
25774462Salfred#ifdef PORTMAP
2581901Swollman/*
2591901Swollman * Add a service program to the callout list.
2601901Swollman * The dispatch routine will be called when a rpc request for this
2611901Swollman * program number comes in.
2621901Swollman */
2631901Swollmanbool_t
2641901Swollmansvc_register(xprt, prog, vers, dispatch, protocol)
2651901Swollman	SVCXPRT *xprt;
2661901Swollman	u_long prog;
2671901Swollman	u_long vers;
26874462Salfred	void (*dispatch) __P((struct svc_req *, SVCXPRT *));
2691901Swollman	int protocol;
2701901Swollman{
2711901Swollman	struct svc_callout *prev;
27274462Salfred	struct svc_callout *s;
2731901Swollman
27474462Salfred	assert(xprt != NULL);
27574462Salfred	assert(dispatch != NULL);
27674462Salfred
27774462Salfred	if ((s = svc_find((rpcprog_t)prog, (rpcvers_t)vers, &prev, NULL)) !=
27874462Salfred	    NULL) {
2791901Swollman		if (s->sc_dispatch == dispatch)
2801901Swollman			goto pmap_it;  /* he is registering another xptr */
2811901Swollman		return (FALSE);
2821901Swollman	}
28374462Salfred	s = mem_alloc(sizeof(struct svc_callout));
28474462Salfred	if (s == NULL) {
2851901Swollman		return (FALSE);
2861901Swollman	}
28774462Salfred	s->sc_prog = (rpcprog_t)prog;
28874462Salfred	s->sc_vers = (rpcvers_t)vers;
2891901Swollman	s->sc_dispatch = dispatch;
2901901Swollman	s->sc_next = svc_head;
2911901Swollman	svc_head = s;
2921901Swollmanpmap_it:
2931901Swollman	/* now register the information with the local binder service */
2941901Swollman	if (protocol) {
2951901Swollman		return (pmap_set(prog, vers, protocol, xprt->xp_port));
2961901Swollman	}
2971901Swollman	return (TRUE);
2981901Swollman}
2991901Swollman
3001901Swollman/*
3011901Swollman * Remove a service program from the callout list.
3021901Swollman */
3031901Swollmanvoid
3041901Swollmansvc_unregister(prog, vers)
3051901Swollman	u_long prog;
3061901Swollman	u_long vers;
3071901Swollman{
3081901Swollman	struct svc_callout *prev;
30974462Salfred	struct svc_callout *s;
3101901Swollman
31174462Salfred	if ((s = svc_find((rpcprog_t)prog, (rpcvers_t)vers, &prev, NULL)) ==
31274462Salfred	    NULL)
3131901Swollman		return;
31474462Salfred	if (prev == NULL) {
3151901Swollman		svc_head = s->sc_next;
3161901Swollman	} else {
3171901Swollman		prev->sc_next = s->sc_next;
3181901Swollman	}
31974462Salfred	s->sc_next = NULL;
32074462Salfred	mem_free(s, sizeof(struct svc_callout));
3211901Swollman	/* now unregister the information with the local binder service */
3221901Swollman	(void)pmap_unset(prog, vers);
3231901Swollman}
32474462Salfred#endif				/* PORTMAP */
3251901Swollman
3261901Swollman/*
3271901Swollman * Search the callout list for a program number, return the callout
3281901Swollman * struct.
3291901Swollman */
3301901Swollmanstatic struct svc_callout *
33174462Salfredsvc_find(prog, vers, prev, netid)
33274462Salfred	rpcprog_t prog;
33374462Salfred	rpcvers_t vers;
3341901Swollman	struct svc_callout **prev;
33574462Salfred	char *netid;
3361901Swollman{
33774462Salfred	struct svc_callout *s, *p;
3381901Swollman
33974462Salfred	assert(prev != NULL);
34074462Salfred
34174462Salfred	p = NULL;
34274462Salfred	for (s = svc_head; s != NULL; s = s->sc_next) {
34374462Salfred		if (((s->sc_prog == prog) && (s->sc_vers == vers)) &&
34474462Salfred		    ((netid == NULL) || (s->sc_netid == NULL) ||
34574462Salfred		    (strcmp(netid, s->sc_netid) == 0)))
34674462Salfred			break;
3471901Swollman		p = s;
3481901Swollman	}
3491901Swollman	*prev = p;
3501901Swollman	return (s);
3511901Swollman}
3521901Swollman
3531901Swollman/* ******************* REPLY GENERATION ROUTINES  ************ */
3541901Swollman
3551901Swollman/*
3561901Swollman * Send a reply to an rpc request
3571901Swollman */
3581901Swollmanbool_t
3591901Swollmansvc_sendreply(xprt, xdr_results, xdr_location)
36074462Salfred	SVCXPRT *xprt;
3611901Swollman	xdrproc_t xdr_results;
3621901Swollman	caddr_t xdr_location;
3631901Swollman{
36474462Salfred	struct rpc_msg rply;
3651901Swollman
36674462Salfred	assert(xprt != NULL);
36774462Salfred
36874462Salfred	rply.rm_direction = REPLY;
36974462Salfred	rply.rm_reply.rp_stat = MSG_ACCEPTED;
37074462Salfred	rply.acpted_rply.ar_verf = xprt->xp_verf;
3711901Swollman	rply.acpted_rply.ar_stat = SUCCESS;
3721901Swollman	rply.acpted_rply.ar_results.where = xdr_location;
3731901Swollman	rply.acpted_rply.ar_results.proc = xdr_results;
37474462Salfred	return (SVC_REPLY(xprt, &rply));
3751901Swollman}
3761901Swollman
3771901Swollman/*
3781901Swollman * No procedure error reply
3791901Swollman */
3801901Swollmanvoid
3811901Swollmansvcerr_noproc(xprt)
38274462Salfred	SVCXPRT *xprt;
3831901Swollman{
3841901Swollman	struct rpc_msg rply;
3851901Swollman
38674462Salfred	assert(xprt != NULL);
38774462Salfred
3881901Swollman	rply.rm_direction = REPLY;
3891901Swollman	rply.rm_reply.rp_stat = MSG_ACCEPTED;
3901901Swollman	rply.acpted_rply.ar_verf = xprt->xp_verf;
3911901Swollman	rply.acpted_rply.ar_stat = PROC_UNAVAIL;
3921901Swollman	SVC_REPLY(xprt, &rply);
3931901Swollman}
3941901Swollman
3951901Swollman/*
3961901Swollman * Can't decode args error reply
3971901Swollman */
3981901Swollmanvoid
3991901Swollmansvcerr_decode(xprt)
40074462Salfred	SVCXPRT *xprt;
4011901Swollman{
40274462Salfred	struct rpc_msg rply;
4031901Swollman
40474462Salfred	assert(xprt != NULL);
40574462Salfred
40674462Salfred	rply.rm_direction = REPLY;
40774462Salfred	rply.rm_reply.rp_stat = MSG_ACCEPTED;
4081901Swollman	rply.acpted_rply.ar_verf = xprt->xp_verf;
4091901Swollman	rply.acpted_rply.ar_stat = GARBAGE_ARGS;
41074462Salfred	SVC_REPLY(xprt, &rply);
4111901Swollman}
4121901Swollman
4131901Swollman/*
4141901Swollman * Some system error
4151901Swollman */
4161901Swollmanvoid
4171901Swollmansvcerr_systemerr(xprt)
41874462Salfred	SVCXPRT *xprt;
4191901Swollman{
42074462Salfred	struct rpc_msg rply;
4211901Swollman
42274462Salfred	assert(xprt != NULL);
42374462Salfred
42474462Salfred	rply.rm_direction = REPLY;
42574462Salfred	rply.rm_reply.rp_stat = MSG_ACCEPTED;
4261901Swollman	rply.acpted_rply.ar_verf = xprt->xp_verf;
4271901Swollman	rply.acpted_rply.ar_stat = SYSTEM_ERR;
42874462Salfred	SVC_REPLY(xprt, &rply);
4291901Swollman}
4301901Swollman
43174462Salfred#if 0
4321901Swollman/*
43374462Salfred * Tell RPC package to not complain about version errors to the client.	 This
43474462Salfred * is useful when revving broadcast protocols that sit on a fixed address.
43574462Salfred * There is really one (or should be only one) example of this kind of
43674462Salfred * protocol: the portmapper (or rpc binder).
43774462Salfred */
43874462Salfredvoid
43974462Salfred__svc_versquiet_on(xprt)
44074462Salfred	SVCXPRT *xprt;
44174462Salfred{
44274462Salfred	u_long	tmp;
44374462Salfred
44474462Salfred	tmp = ((u_long) xprt->xp_p3) | SVC_VERSQUIET;
44574462Salfred	xprt->xp_p3 = (caddr_t) tmp;
44674462Salfred}
44774462Salfred
44874462Salfredvoid
44974462Salfred__svc_versquiet_off(xprt)
45074462Salfred	SVCXPRT *xprt;
45174462Salfred{
45274462Salfred	u_long	tmp;
45374462Salfred
45474462Salfred	tmp = ((u_long) xprt->xp_p3) & ~SVC_VERSQUIET;
45574462Salfred	xprt->xp_p3 = (caddr_t) tmp;
45674462Salfred}
45774462Salfred
45874462Salfredvoid
45974462Salfredsvc_versquiet(xprt)
46074462Salfred	SVCXPRT *xprt;
46174462Salfred{
46274462Salfred	__svc_versquiet_on(xprt);
46374462Salfred}
46474462Salfred
46574462Salfredint
46674462Salfred__svc_versquiet_get(xprt)
46774462Salfred	SVCXPRT *xprt;
46874462Salfred{
46974462Salfred	return ((int) xprt->xp_p3) & SVC_VERSQUIET;
47074462Salfred}
47174462Salfred#endif
47274462Salfred
47374462Salfred/*
4741901Swollman * Authentication error reply
4751901Swollman */
4761901Swollmanvoid
4771901Swollmansvcerr_auth(xprt, why)
4781901Swollman	SVCXPRT *xprt;
4791901Swollman	enum auth_stat why;
4801901Swollman{
4811901Swollman	struct rpc_msg rply;
4821901Swollman
48374462Salfred	assert(xprt != NULL);
48474462Salfred
4851901Swollman	rply.rm_direction = REPLY;
4861901Swollman	rply.rm_reply.rp_stat = MSG_DENIED;
4871901Swollman	rply.rjcted_rply.rj_stat = AUTH_ERROR;
4881901Swollman	rply.rjcted_rply.rj_why = why;
4891901Swollman	SVC_REPLY(xprt, &rply);
4901901Swollman}
4911901Swollman
4921901Swollman/*
4931901Swollman * Auth too weak error reply
4941901Swollman */
4951901Swollmanvoid
4961901Swollmansvcerr_weakauth(xprt)
4971901Swollman	SVCXPRT *xprt;
4981901Swollman{
4991901Swollman
50074462Salfred	assert(xprt != NULL);
50174462Salfred
5021901Swollman	svcerr_auth(xprt, AUTH_TOOWEAK);
5031901Swollman}
5041901Swollman
5051901Swollman/*
5061901Swollman * Program unavailable error reply
5071901Swollman */
50874462Salfredvoid
5091901Swollmansvcerr_noprog(xprt)
51074462Salfred	SVCXPRT *xprt;
5111901Swollman{
51274462Salfred	struct rpc_msg rply;
5131901Swollman
51474462Salfred	assert(xprt != NULL);
51574462Salfred
51674462Salfred	rply.rm_direction = REPLY;
51774462Salfred	rply.rm_reply.rp_stat = MSG_ACCEPTED;
51874462Salfred	rply.acpted_rply.ar_verf = xprt->xp_verf;
5191901Swollman	rply.acpted_rply.ar_stat = PROG_UNAVAIL;
5201901Swollman	SVC_REPLY(xprt, &rply);
5211901Swollman}
5221901Swollman
5231901Swollman/*
5241901Swollman * Program version mismatch error reply
5251901Swollman */
52674462Salfredvoid
5271901Swollmansvcerr_progvers(xprt, low_vers, high_vers)
52874462Salfred	SVCXPRT *xprt;
52974462Salfred	rpcvers_t low_vers;
53074462Salfred	rpcvers_t high_vers;
5311901Swollman{
5321901Swollman	struct rpc_msg rply;
5331901Swollman
53474462Salfred	assert(xprt != NULL);
53574462Salfred
5361901Swollman	rply.rm_direction = REPLY;
5371901Swollman	rply.rm_reply.rp_stat = MSG_ACCEPTED;
5381901Swollman	rply.acpted_rply.ar_verf = xprt->xp_verf;
5391901Swollman	rply.acpted_rply.ar_stat = PROG_MISMATCH;
54074462Salfred	rply.acpted_rply.ar_vers.low = (u_int32_t)low_vers;
54174462Salfred	rply.acpted_rply.ar_vers.high = (u_int32_t)high_vers;
5421901Swollman	SVC_REPLY(xprt, &rply);
5431901Swollman}
5441901Swollman
5451901Swollman/* ******************* SERVER INPUT STUFF ******************* */
5461901Swollman
5471901Swollman/*
5481901Swollman * Get server side input from some transport.
5491901Swollman *
5501901Swollman * Statement of authentication parameters management:
5511901Swollman * This function owns and manages all authentication parameters, specifically
5521901Swollman * the "raw" parameters (msg.rm_call.cb_cred and msg.rm_call.cb_verf) and
5531901Swollman * the "cooked" credentials (rqst->rq_clntcred).
5541901Swollman * However, this function does not know the structure of the cooked
5558870Srgrimes * credentials, so it make the following assumptions:
5561901Swollman *   a) the structure is contiguous (no pointers), and
5578870Srgrimes *   b) the cred structure size does not exceed RQCRED_SIZE bytes.
5581901Swollman * In all events, all three parameters are freed upon exit from this routine.
5591901Swollman * The storage is trivially management on the call stack in user land, but
5601901Swollman * is mallocated in kernel land.
5611901Swollman */
5621901Swollman
5631901Swollmanvoid
5641901Swollmansvc_getreq(rdfds)
5651901Swollman	int rdfds;
5661901Swollman{
5671901Swollman	fd_set readfds;
5681901Swollman
5691901Swollman	FD_ZERO(&readfds);
5701901Swollman	readfds.fds_bits[0] = rdfds;
5711901Swollman	svc_getreqset(&readfds);
5721901Swollman}
5731901Swollman
5741901Swollmanvoid
5751901Swollmansvc_getreqset(readfds)
5761901Swollman	fd_set *readfds;
5771901Swollman{
57874462Salfred	int bit, fd;
57974462Salfred	fd_mask mask, *maskp;
58074462Salfred	int sock;
58174462Salfred
58274462Salfred	assert(readfds != NULL);
58374462Salfred
58474462Salfred	maskp = readfds->fds_bits;
58574462Salfred	for (sock = 0; sock < FD_SETSIZE; sock += NFDBITS) {
58674462Salfred	    for (mask = *maskp++; (bit = ffs(mask)) != 0;
58774462Salfred		mask ^= (1 << (bit - 1))) {
58874462Salfred		/* sock has input waiting */
58974462Salfred		fd = sock + bit - 1;
59074462Salfred		svc_getreq_common(fd);
59174462Salfred	    }
59274462Salfred	}
59321087Speter}
59421087Speter
59521087Spetervoid
59674462Salfredsvc_getreq_common(fd)
59774462Salfred	int fd;
5981901Swollman{
59974462Salfred	SVCXPRT *xprt;
60074462Salfred	struct svc_req r;
6011901Swollman	struct rpc_msg msg;
6021901Swollman	int prog_found;
60374462Salfred	rpcvers_t low_vers;
60474462Salfred	rpcvers_t high_vers;
60574462Salfred	enum xprt_stat stat;
6061901Swollman	char cred_area[2*MAX_AUTH_BYTES + RQCRED_SIZE];
60774462Salfred
6081901Swollman	msg.rm_call.cb_cred.oa_base = cred_area;
6091901Swollman	msg.rm_call.cb_verf.oa_base = &(cred_area[MAX_AUTH_BYTES]);
6101901Swollman	r.rq_clntcred = &(cred_area[2*MAX_AUTH_BYTES]);
6111901Swollman
61274462Salfred	rwlock_rdlock(&svc_fd_lock);
61374462Salfred	xprt = xports[fd];
61474462Salfred	rwlock_unlock(&svc_fd_lock);
61574462Salfred	if (xprt == NULL)
61674462Salfred		/* But do we control sock? */
61774462Salfred		return;
61874462Salfred	/* now receive msgs from xprtprt (support batch calls) */
61974462Salfred	do {
62074462Salfred		if (SVC_RECV(xprt, &msg)) {
6211901Swollman
62274462Salfred			/* now find the exported program and call it */
62374462Salfred			struct svc_callout *s;
62474462Salfred			enum auth_stat why;
6251901Swollman
62674462Salfred			r.rq_xprt = xprt;
62774462Salfred			r.rq_prog = msg.rm_call.cb_prog;
62874462Salfred			r.rq_vers = msg.rm_call.cb_vers;
62974462Salfred			r.rq_proc = msg.rm_call.cb_proc;
63074462Salfred			r.rq_cred = msg.rm_call.cb_cred;
63174462Salfred			/* first authenticate the message */
63274462Salfred			if ((why = _authenticate(&r, &msg)) != AUTH_OK) {
63374462Salfred				svcerr_auth(xprt, why);
63474462Salfred				goto call_done;
6351901Swollman			}
63674462Salfred			/* now match message with a registered service*/
63774462Salfred			prog_found = FALSE;
63874462Salfred			low_vers = (rpcvers_t) -1L;
63974462Salfred			high_vers = (rpcvers_t) 0L;
64074462Salfred			for (s = svc_head; s != NULL; s = s->sc_next) {
64174462Salfred				if (s->sc_prog == r.rq_prog) {
64274462Salfred					if (s->sc_vers == r.rq_vers) {
64374462Salfred						(*s->sc_dispatch)(&r, xprt);
64474462Salfred						goto call_done;
64574462Salfred					}  /* found correct version */
64674462Salfred					prog_found = TRUE;
64774462Salfred					if (s->sc_vers < low_vers)
64874462Salfred						low_vers = s->sc_vers;
64974462Salfred					if (s->sc_vers > high_vers)
65074462Salfred						high_vers = s->sc_vers;
65174462Salfred				}   /* found correct program */
6521901Swollman			}
65374462Salfred			/*
65474462Salfred			 * if we got here, the program or version
65574462Salfred			 * is not served ...
65674462Salfred			 */
65774462Salfred			if (prog_found)
65874462Salfred				svcerr_progvers(xprt, low_vers, high_vers);
65974462Salfred			else
66074462Salfred				 svcerr_noprog(xprt);
66174462Salfred			/* Fall through to ... */
66274462Salfred		}
66374462Salfred		/*
66474462Salfred		 * Check if the xprt has been disconnected in a
66574462Salfred		 * recursive call in the service dispatch routine.
66674462Salfred		 * If so, then break.
66774462Salfred		 */
66874462Salfred		rwlock_rdlock(&svc_fd_lock);
66974462Salfred		if (xprt != xports[fd]) {
67074462Salfred			rwlock_unlock(&svc_fd_lock);
67174462Salfred			break;
67274462Salfred		}
67374462Salfred		rwlock_unlock(&svc_fd_lock);
67474462Salfredcall_done:
67574462Salfred		if ((stat = SVC_STAT(xprt)) == XPRT_DIED){
67674462Salfred			SVC_DESTROY(xprt);
67774462Salfred			break;
67874462Salfred		}
67974462Salfred	} while (stat == XPRT_MOREREQS);
68074462Salfred}
68174462Salfred
68274462Salfred
68374462Salfredvoid
68474462Salfredsvc_getreq_poll(pfdp, pollretval)
68574462Salfred	struct pollfd	*pfdp;
68674462Salfred	int	pollretval;
68774462Salfred{
68874462Salfred	int i;
68974462Salfred	int fds_found;
69074462Salfred
69174462Salfred	for (i = fds_found = 0; fds_found < pollretval; i++) {
69274462Salfred		struct pollfd *p = &pfdp[i];
69374462Salfred
69474462Salfred		if (p->revents) {
69574462Salfred			/* fd has input waiting */
69674462Salfred			fds_found++;
69774462Salfred			/*
69874462Salfred			 *	We assume that this function is only called
69974462Salfred			 *	via someone _select()ing from svc_fdset or
70074462Salfred			 *	_poll()ing from svc_pollset[].  Thus it's safe
70174462Salfred			 *	to handle the POLLNVAL event by simply turning
70274462Salfred			 *	the corresponding bit off in svc_fdset.  The
70374462Salfred			 *	svc_pollset[] array is derived from svc_fdset
70474462Salfred			 *	and so will also be updated eventually.
70574462Salfred			 *
70674462Salfred			 *	XXX Should we do an xprt_unregister() instead?
70774462Salfred			 */
70874462Salfred			if (p->revents & POLLNVAL) {
70974462Salfred				rwlock_wrlock(&svc_fd_lock);
71074462Salfred				FD_CLR(p->fd, &svc_fdset);
71174462Salfred				rwlock_unlock(&svc_fd_lock);
71274462Salfred			} else
71374462Salfred				svc_getreq_common(p->fd);
71474462Salfred		}
7151901Swollman	}
7161901Swollman}
717