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