xref: /reactos/dll/3rdparty/libtirpc/src/svc.c (revision c2c66aff)
1*c2c66affSColin Finck 
2*c2c66affSColin Finck /*
3*c2c66affSColin Finck  * Copyright (c) 2009, Sun Microsystems, Inc.
4*c2c66affSColin Finck  * All rights reserved.
5*c2c66affSColin Finck  *
6*c2c66affSColin Finck  * Redistribution and use in source and binary forms, with or without
7*c2c66affSColin Finck  * modification, are permitted provided that the following conditions are met:
8*c2c66affSColin Finck  * - Redistributions of source code must retain the above copyright notice,
9*c2c66affSColin Finck  *   this list of conditions and the following disclaimer.
10*c2c66affSColin Finck  * - Redistributions in binary form must reproduce the above copyright notice,
11*c2c66affSColin Finck  *   this list of conditions and the following disclaimer in the documentation
12*c2c66affSColin Finck  *   and/or other materials provided with the distribution.
13*c2c66affSColin Finck  * - Neither the name of Sun Microsystems, Inc. nor the names of its
14*c2c66affSColin Finck  *   contributors may be used to endorse or promote products derived
15*c2c66affSColin Finck  *   from this software without specific prior written permission.
16*c2c66affSColin Finck  *
17*c2c66affSColin Finck  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18*c2c66affSColin Finck  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19*c2c66affSColin Finck  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20*c2c66affSColin Finck  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
21*c2c66affSColin Finck  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22*c2c66affSColin Finck  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23*c2c66affSColin Finck  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24*c2c66affSColin Finck  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25*c2c66affSColin Finck  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26*c2c66affSColin Finck  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27*c2c66affSColin Finck  * POSSIBILITY OF SUCH DAMAGE.
28*c2c66affSColin Finck  */
29*c2c66affSColin Finck 
30*c2c66affSColin Finck /*
31*c2c66affSColin Finck  * svc.c, Server-side remote procedure call interface.
32*c2c66affSColin Finck  *
33*c2c66affSColin Finck  * There are two sets of procedures here.  The xprt routines are
34*c2c66affSColin Finck  * for handling transport handles.  The svc routines handle the
35*c2c66affSColin Finck  * list of service routines.
36*c2c66affSColin Finck  *
37*c2c66affSColin Finck  * Copyright (C) 1984, Sun Microsystems, Inc.
38*c2c66affSColin Finck  */
39*c2c66affSColin Finck #include <wintirpc.h>
40*c2c66affSColin Finck //#include <pthread.h>
41*c2c66affSColin Finck 
42*c2c66affSColin Finck #include <reentrant.h>
43*c2c66affSColin Finck #include <sys/types.h>
44*c2c66affSColin Finck //#include <sys/poll.h>
45*c2c66affSColin Finck #include <assert.h>
46*c2c66affSColin Finck #include <errno.h>
47*c2c66affSColin Finck #include <stdlib.h>
48*c2c66affSColin Finck #include <string.h>
49*c2c66affSColin Finck 
50*c2c66affSColin Finck #include <rpc/rpc.h>
51*c2c66affSColin Finck #ifdef PORTMAP
52*c2c66affSColin Finck #include <rpc/pmap_clnt.h>
53*c2c66affSColin Finck #endif /* PORTMAP */
54*c2c66affSColin Finck 
55*c2c66affSColin Finck #include "rpc_com.h"
56*c2c66affSColin Finck 
57*c2c66affSColin Finck #define	RQCRED_SIZE	400	/* this size is excessive */
58*c2c66affSColin Finck 
59*c2c66affSColin Finck #define SVC_VERSQUIET 0x0001	/* keep quiet about vers mismatch */
60*c2c66affSColin Finck #define version_keepquiet(xp) ((u_long)(xp)->xp_p3 & SVC_VERSQUIET)
61*c2c66affSColin Finck 
62*c2c66affSColin Finck #ifndef max
63*c2c66affSColin Finck #define max(a, b) (a > b ? a : b)
64*c2c66affSColin Finck #endif
65*c2c66affSColin Finck 
66*c2c66affSColin Finck /*
67*c2c66affSColin Finck  * The services list
68*c2c66affSColin Finck  * Each entry represents a set of procedures (an rpc program).
69*c2c66affSColin Finck  * The dispatch routine takes request structs and runs the
70*c2c66affSColin Finck  * apropriate procedure.
71*c2c66affSColin Finck  */
72*c2c66affSColin Finck static struct svc_callout
73*c2c66affSColin Finck {
74*c2c66affSColin Finck   struct svc_callout *sc_next;
75*c2c66affSColin Finck   rpcprog_t sc_prog;
76*c2c66affSColin Finck   rpcvers_t sc_vers;
77*c2c66affSColin Finck   char *sc_netid;
78*c2c66affSColin Finck   void (*sc_dispatch) (struct svc_req *, SVCXPRT *);
79*c2c66affSColin Finck } *svc_head;
80*c2c66affSColin Finck 
81*c2c66affSColin Finck extern rwlock_t svc_lock;
82*c2c66affSColin Finck extern rwlock_t svc_fd_lock;
83*c2c66affSColin Finck #ifdef HAVE_LIBGSSAPI
84*c2c66affSColin Finck extern struct svc_auth_ops svc_auth_gss_ops;
85*c2c66affSColin Finck #endif
86*c2c66affSColin Finck 
87*c2c66affSColin Finck static struct svc_callout *svc_find (rpcprog_t, rpcvers_t,
88*c2c66affSColin Finck 				     struct svc_callout **, char *);
89*c2c66affSColin Finck static void __xprt_do_unregister (SVCXPRT * xprt, bool_t dolock);
90*c2c66affSColin Finck 
91*c2c66affSColin Finck /* ***************  SVCXPRT related stuff **************** */
92*c2c66affSColin Finck 
93*c2c66affSColin Finck /*
94*c2c66affSColin Finck  * Activate a transport handle.
95*c2c66affSColin Finck  */
96*c2c66affSColin Finck void
xprt_register(xprt)97*c2c66affSColin Finck xprt_register (xprt)
98*c2c66affSColin Finck      SVCXPRT *xprt;
99*c2c66affSColin Finck {
100*c2c66affSColin Finck   SOCKET sock;
101*c2c66affSColin Finck 
102*c2c66affSColin Finck   assert (xprt != NULL);
103*c2c66affSColin Finck 
104*c2c66affSColin Finck   sock = xprt->xp_fd;
105*c2c66affSColin Finck 
106*c2c66affSColin Finck   rwlock_wrlock (&svc_fd_lock);
107*c2c66affSColin Finck   if (__svc_xports == NULL) {
108*c2c66affSColin Finck       __svc_xports = (SVCXPRT **) mem_alloc (FD_SETSIZE * sizeof (SVCXPRT *));
109*c2c66affSColin Finck 	  if (__svc_xports == NULL) {
110*c2c66affSColin Finck         // XXX Give an error indication?
111*c2c66affSColin Finck         return;
112*c2c66affSColin Finck       }
113*c2c66affSColin Finck       memset (__svc_xports, 0, FD_SETSIZE * sizeof (SVCXPRT *));
114*c2c66affSColin Finck   }
115*c2c66affSColin Finck #ifndef _WIN32
116*c2c66affSColin Finck   if (sock < FD_SETSIZE) {
117*c2c66affSColin Finck     __svc_xports[sock] = xprt;
118*c2c66affSColin Finck     FD_SET (sock, &svc_fdset);
119*c2c66affSColin Finck     svc_maxfd = max (svc_maxfd, sock);
120*c2c66affSColin Finck   }
121*c2c66affSColin Finck #else
122*c2c66affSColin Finck   fprintf(stderr, "%s: Yikes!  Figure out __svc_xports[] issue!!\n", __FUNCTION__);
123*c2c66affSColin Finck #endif
124*c2c66affSColin Finck   rwlock_unlock (&svc_fd_lock);
125*c2c66affSColin Finck }
126*c2c66affSColin Finck 
127*c2c66affSColin Finck void
xprt_unregister(SVCXPRT * xprt)128*c2c66affSColin Finck xprt_unregister (SVCXPRT * xprt)
129*c2c66affSColin Finck {
130*c2c66affSColin Finck   __xprt_do_unregister (xprt, TRUE);
131*c2c66affSColin Finck }
132*c2c66affSColin Finck 
133*c2c66affSColin Finck void
__xprt_unregister_unlocked(SVCXPRT * xprt)134*c2c66affSColin Finck __xprt_unregister_unlocked (SVCXPRT * xprt)
135*c2c66affSColin Finck {
136*c2c66affSColin Finck   __xprt_do_unregister (xprt, FALSE);
137*c2c66affSColin Finck }
138*c2c66affSColin Finck 
139*c2c66affSColin Finck /*
140*c2c66affSColin Finck  * De-activate a transport handle.
141*c2c66affSColin Finck  */
142*c2c66affSColin Finck static void
__xprt_do_unregister(xprt,dolock)143*c2c66affSColin Finck __xprt_do_unregister (xprt, dolock)
144*c2c66affSColin Finck SVCXPRT *xprt;
145*c2c66affSColin Finck bool_t dolock;
146*c2c66affSColin Finck {
147*c2c66affSColin Finck   SOCKET sock;
148*c2c66affSColin Finck 
149*c2c66affSColin Finck   assert (xprt != NULL);
150*c2c66affSColin Finck 
151*c2c66affSColin Finck   sock = xprt->xp_fd;
152*c2c66affSColin Finck 
153*c2c66affSColin Finck #ifndef _WIN32
154*c2c66affSColin Finck   if (dolock)
155*c2c66affSColin Finck     rwlock_wrlock (&svc_fd_lock);
156*c2c66affSColin Finck   if ((sock < FD_SETSIZE) && (__svc_xports[sock] == xprt)) {
157*c2c66affSColin Finck     __svc_xports[sock] = NULL;
158*c2c66affSColin Finck     FD_CLR (sock, &svc_fdset);
159*c2c66affSColin Finck     if (sock >= svc_maxfd) {
160*c2c66affSColin Finck       for (svc_maxfd--; svc_maxfd >= 0; svc_maxfd--)
161*c2c66affSColin Finck         if (__svc_xports[svc_maxfd])
162*c2c66affSColin Finck           break;
163*c2c66affSColin Finck     }
164*c2c66affSColin Finck   }
165*c2c66affSColin Finck   if (dolock)
166*c2c66affSColin Finck     rwlock_unlock (&svc_fd_lock);
167*c2c66affSColin Finck #else
168*c2c66affSColin Finck   fprintf(stderr, "%s: Yikes!  Figure out __svc_xports[] issue!!\n", __FUNCTION__);
169*c2c66affSColin Finck #endif
170*c2c66affSColin Finck }
171*c2c66affSColin Finck 
172*c2c66affSColin Finck /*
173*c2c66affSColin Finck  * Add a service program to the callout list.
174*c2c66affSColin Finck  * The dispatch routine will be called when a rpc request for this
175*c2c66affSColin Finck  * program number comes in.
176*c2c66affSColin Finck  */
177*c2c66affSColin Finck bool_t
svc_reg(xprt,prog,vers,dispatch,nconf)178*c2c66affSColin Finck svc_reg (xprt, prog, vers, dispatch, nconf)
179*c2c66affSColin Finck      SVCXPRT *xprt;
180*c2c66affSColin Finck      const rpcprog_t prog;
181*c2c66affSColin Finck      const rpcvers_t vers;
182*c2c66affSColin Finck      void (*dispatch) (struct svc_req *, SVCXPRT *);
183*c2c66affSColin Finck      const struct netconfig *nconf;
184*c2c66affSColin Finck {
185*c2c66affSColin Finck   bool_t dummy;
186*c2c66affSColin Finck   struct svc_callout *prev;
187*c2c66affSColin Finck   struct svc_callout *s;
188*c2c66affSColin Finck   struct netconfig *tnconf;
189*c2c66affSColin Finck   char *netid = NULL;
190*c2c66affSColin Finck   int flag = 0;
191*c2c66affSColin Finck 
192*c2c66affSColin Finck /* VARIABLES PROTECTED BY svc_lock: s, prev, svc_head */
193*c2c66affSColin Finck   if (xprt->xp_netid)
194*c2c66affSColin Finck     {
195*c2c66affSColin Finck       netid = strdup (xprt->xp_netid);
196*c2c66affSColin Finck       flag = 1;
197*c2c66affSColin Finck     }
198*c2c66affSColin Finck   else if (nconf && nconf->nc_netid)
199*c2c66affSColin Finck     {
200*c2c66affSColin Finck       netid = strdup (nconf->nc_netid);
201*c2c66affSColin Finck       flag = 1;
202*c2c66affSColin Finck     }
203*c2c66affSColin Finck   else if ((tnconf = __rpcgettp (xprt->xp_fd)) != NULL)
204*c2c66affSColin Finck     {
205*c2c66affSColin Finck       netid = strdup (tnconf->nc_netid);
206*c2c66affSColin Finck       flag = 1;
207*c2c66affSColin Finck       freenetconfigent (tnconf);
208*c2c66affSColin Finck     }				/* must have been created with svc_raw_create */
209*c2c66affSColin Finck   if ((netid == NULL) && (flag == 1))
210*c2c66affSColin Finck     {
211*c2c66affSColin Finck       return (FALSE);
212*c2c66affSColin Finck     }
213*c2c66affSColin Finck 
214*c2c66affSColin Finck   rwlock_wrlock (&svc_lock);
215*c2c66affSColin Finck   if ((s = svc_find (prog, vers, &prev, netid)) != NULL)
216*c2c66affSColin Finck     {
217*c2c66affSColin Finck       if (netid)
218*c2c66affSColin Finck 	free (netid);
219*c2c66affSColin Finck       if (s->sc_dispatch == dispatch)
220*c2c66affSColin Finck 	goto rpcb_it;		/* he is registering another xptr */
221*c2c66affSColin Finck       rwlock_unlock (&svc_lock);
222*c2c66affSColin Finck       return (FALSE);
223*c2c66affSColin Finck     }
224*c2c66affSColin Finck   s = mem_alloc (sizeof (struct svc_callout));
225*c2c66affSColin Finck   if (s == NULL)
226*c2c66affSColin Finck     {
227*c2c66affSColin Finck       if (netid)
228*c2c66affSColin Finck 	free (netid);
229*c2c66affSColin Finck       rwlock_unlock (&svc_lock);
230*c2c66affSColin Finck       return (FALSE);
231*c2c66affSColin Finck     }
232*c2c66affSColin Finck 
233*c2c66affSColin Finck   s->sc_prog = prog;
234*c2c66affSColin Finck   s->sc_vers = vers;
235*c2c66affSColin Finck   s->sc_dispatch = dispatch;
236*c2c66affSColin Finck   s->sc_netid = netid;
237*c2c66affSColin Finck   s->sc_next = svc_head;
238*c2c66affSColin Finck   svc_head = s;
239*c2c66affSColin Finck 
240*c2c66affSColin Finck   if ((xprt->xp_netid == NULL) && (flag == 1) && netid)
241*c2c66affSColin Finck     ((SVCXPRT *) xprt)->xp_netid = strdup (netid);
242*c2c66affSColin Finck 
243*c2c66affSColin Finck rpcb_it:
244*c2c66affSColin Finck   rwlock_unlock (&svc_lock);
245*c2c66affSColin Finck   /* now register the information with the local binder service */
246*c2c66affSColin Finck   if (nconf)
247*c2c66affSColin Finck     {
248*c2c66affSColin Finck       /*LINTED const castaway */
249*c2c66affSColin Finck       dummy = rpcb_set (prog, vers, (struct netconfig *) nconf,
250*c2c66affSColin Finck 			&((SVCXPRT *) xprt)->xp_ltaddr);
251*c2c66affSColin Finck       return (dummy);
252*c2c66affSColin Finck     }
253*c2c66affSColin Finck   return (TRUE);
254*c2c66affSColin Finck }
255*c2c66affSColin Finck 
256*c2c66affSColin Finck /*
257*c2c66affSColin Finck  * Remove a service program from the callout list.
258*c2c66affSColin Finck  */
259*c2c66affSColin Finck void
svc_unreg(prog,vers)260*c2c66affSColin Finck svc_unreg (prog, vers)
261*c2c66affSColin Finck      const rpcprog_t prog;
262*c2c66affSColin Finck      const rpcvers_t vers;
263*c2c66affSColin Finck {
264*c2c66affSColin Finck   struct svc_callout *prev;
265*c2c66affSColin Finck   struct svc_callout *s;
266*c2c66affSColin Finck 
267*c2c66affSColin Finck   /* unregister the information anyway */
268*c2c66affSColin Finck   (void) rpcb_unset (prog, vers, NULL);
269*c2c66affSColin Finck   rwlock_wrlock (&svc_lock);
270*c2c66affSColin Finck   while ((s = svc_find (prog, vers, &prev, NULL)) != NULL)
271*c2c66affSColin Finck     {
272*c2c66affSColin Finck       if (prev == NULL)
273*c2c66affSColin Finck 	{
274*c2c66affSColin Finck 	  svc_head = s->sc_next;
275*c2c66affSColin Finck 	}
276*c2c66affSColin Finck       else
277*c2c66affSColin Finck 	{
278*c2c66affSColin Finck 	  prev->sc_next = s->sc_next;
279*c2c66affSColin Finck 	}
280*c2c66affSColin Finck       s->sc_next = NULL;
281*c2c66affSColin Finck       if (s->sc_netid)
282*c2c66affSColin Finck 	mem_free (s->sc_netid, sizeof (s->sc_netid) + 1);
283*c2c66affSColin Finck       mem_free (s, sizeof (struct svc_callout));
284*c2c66affSColin Finck     }
285*c2c66affSColin Finck   rwlock_unlock (&svc_lock);
286*c2c66affSColin Finck }
287*c2c66affSColin Finck 
288*c2c66affSColin Finck /* ********************** CALLOUT list related stuff ************* */
289*c2c66affSColin Finck 
290*c2c66affSColin Finck #ifdef PORTMAP
291*c2c66affSColin Finck /*
292*c2c66affSColin Finck  * Add a service program to the callout list.
293*c2c66affSColin Finck  * The dispatch routine will be called when a rpc request for this
294*c2c66affSColin Finck  * program number comes in.
295*c2c66affSColin Finck  */
296*c2c66affSColin Finck bool_t
svc_register(xprt,prog,vers,dispatch,protocol)297*c2c66affSColin Finck svc_register (xprt, prog, vers, dispatch, protocol)
298*c2c66affSColin Finck      SVCXPRT *xprt;
299*c2c66affSColin Finck      u_long prog;
300*c2c66affSColin Finck      u_long vers;
301*c2c66affSColin Finck      void (*dispatch) (struct svc_req *, SVCXPRT *);
302*c2c66affSColin Finck      int protocol;
303*c2c66affSColin Finck {
304*c2c66affSColin Finck   struct svc_callout *prev;
305*c2c66affSColin Finck   struct svc_callout *s;
306*c2c66affSColin Finck 
307*c2c66affSColin Finck   assert (xprt != NULL);
308*c2c66affSColin Finck   assert (dispatch != NULL);
309*c2c66affSColin Finck 
310*c2c66affSColin Finck   if ((s = svc_find ((rpcprog_t) prog, (rpcvers_t) vers, &prev, NULL)) !=
311*c2c66affSColin Finck       NULL)
312*c2c66affSColin Finck     {
313*c2c66affSColin Finck       if (s->sc_dispatch == dispatch)
314*c2c66affSColin Finck 	goto pmap_it;		/* he is registering another xptr */
315*c2c66affSColin Finck       return (FALSE);
316*c2c66affSColin Finck     }
317*c2c66affSColin Finck   s = mem_alloc (sizeof (struct svc_callout));
318*c2c66affSColin Finck   if (s == NULL)
319*c2c66affSColin Finck     {
320*c2c66affSColin Finck       return (FALSE);
321*c2c66affSColin Finck     }
322*c2c66affSColin Finck   s->sc_prog = (rpcprog_t) prog;
323*c2c66affSColin Finck   s->sc_vers = (rpcvers_t) vers;
324*c2c66affSColin Finck   s->sc_dispatch = dispatch;
325*c2c66affSColin Finck   s->sc_next = svc_head;
326*c2c66affSColin Finck   svc_head = s;
327*c2c66affSColin Finck pmap_it:
328*c2c66affSColin Finck   /* now register the information with the local binder service */
329*c2c66affSColin Finck   if (protocol)
330*c2c66affSColin Finck     {
331*c2c66affSColin Finck       return (pmap_set (prog, vers, protocol, xprt->xp_port));
332*c2c66affSColin Finck     }
333*c2c66affSColin Finck   return (TRUE);
334*c2c66affSColin Finck }
335*c2c66affSColin Finck 
336*c2c66affSColin Finck /*
337*c2c66affSColin Finck  * Remove a service program from the callout list.
338*c2c66affSColin Finck  */
339*c2c66affSColin Finck void
svc_unregister(prog,vers)340*c2c66affSColin Finck svc_unregister (prog, vers)
341*c2c66affSColin Finck      u_long prog;
342*c2c66affSColin Finck      u_long vers;
343*c2c66affSColin Finck {
344*c2c66affSColin Finck   struct svc_callout *prev;
345*c2c66affSColin Finck   struct svc_callout *s;
346*c2c66affSColin Finck 
347*c2c66affSColin Finck   if ((s = svc_find ((rpcprog_t) prog, (rpcvers_t) vers, &prev, NULL)) ==
348*c2c66affSColin Finck       NULL)
349*c2c66affSColin Finck     return;
350*c2c66affSColin Finck   if (prev == NULL)
351*c2c66affSColin Finck     {
352*c2c66affSColin Finck       svc_head = s->sc_next;
353*c2c66affSColin Finck     }
354*c2c66affSColin Finck   else
355*c2c66affSColin Finck     {
356*c2c66affSColin Finck       prev->sc_next = s->sc_next;
357*c2c66affSColin Finck     }
358*c2c66affSColin Finck   s->sc_next = NULL;
359*c2c66affSColin Finck   mem_free (s, sizeof (struct svc_callout));
360*c2c66affSColin Finck   /* now unregister the information with the local binder service */
361*c2c66affSColin Finck   (void) pmap_unset (prog, vers);
362*c2c66affSColin Finck }
363*c2c66affSColin Finck #endif /* PORTMAP */
364*c2c66affSColin Finck 
365*c2c66affSColin Finck /*
366*c2c66affSColin Finck  * Search the callout list for a program number, return the callout
367*c2c66affSColin Finck  * struct.
368*c2c66affSColin Finck  */
369*c2c66affSColin Finck static struct svc_callout *
svc_find(prog,vers,prev,netid)370*c2c66affSColin Finck svc_find (prog, vers, prev, netid)
371*c2c66affSColin Finck      rpcprog_t prog;
372*c2c66affSColin Finck      rpcvers_t vers;
373*c2c66affSColin Finck      struct svc_callout **prev;
374*c2c66affSColin Finck      char *netid;
375*c2c66affSColin Finck {
376*c2c66affSColin Finck   struct svc_callout *s, *p;
377*c2c66affSColin Finck 
378*c2c66affSColin Finck   assert (prev != NULL);
379*c2c66affSColin Finck 
380*c2c66affSColin Finck   p = NULL;
381*c2c66affSColin Finck   for (s = svc_head; s != NULL; s = s->sc_next)
382*c2c66affSColin Finck     {
383*c2c66affSColin Finck       if (((s->sc_prog == prog) && (s->sc_vers == vers)) &&
384*c2c66affSColin Finck 	  ((netid == NULL) || (s->sc_netid == NULL) ||
385*c2c66affSColin Finck 	   (strcmp (netid, s->sc_netid) == 0)))
386*c2c66affSColin Finck 	break;
387*c2c66affSColin Finck       p = s;
388*c2c66affSColin Finck     }
389*c2c66affSColin Finck   *prev = p;
390*c2c66affSColin Finck   return (s);
391*c2c66affSColin Finck }
392*c2c66affSColin Finck 
393*c2c66affSColin Finck /* ******************* REPLY GENERATION ROUTINES  ************ */
394*c2c66affSColin Finck 
395*c2c66affSColin Finck /*
396*c2c66affSColin Finck  * Send a reply to an rpc request
397*c2c66affSColin Finck  */
398*c2c66affSColin Finck bool_t
svc_sendreply(xprt,xdr_results,xdr_location)399*c2c66affSColin Finck svc_sendreply (xprt, xdr_results, xdr_location)
400*c2c66affSColin Finck      SVCXPRT *xprt;
401*c2c66affSColin Finck      xdrproc_t xdr_results;
402*c2c66affSColin Finck      void *xdr_location;
403*c2c66affSColin Finck {
404*c2c66affSColin Finck   struct rpc_msg rply;
405*c2c66affSColin Finck 
406*c2c66affSColin Finck   assert (xprt != NULL);
407*c2c66affSColin Finck 
408*c2c66affSColin Finck   rply.rm_direction = REPLY;
409*c2c66affSColin Finck   rply.rm_reply.rp_stat = MSG_ACCEPTED;
410*c2c66affSColin Finck   rply.acpted_rply.ar_verf = xprt->xp_verf;
411*c2c66affSColin Finck   rply.acpted_rply.ar_stat = SUCCESS;
412*c2c66affSColin Finck   rply.acpted_rply.ar_results.where = xdr_location;
413*c2c66affSColin Finck   rply.acpted_rply.ar_results.proc = xdr_results;
414*c2c66affSColin Finck   return (SVC_REPLY (xprt, &rply));
415*c2c66affSColin Finck }
416*c2c66affSColin Finck 
417*c2c66affSColin Finck /*
418*c2c66affSColin Finck  * No procedure error reply
419*c2c66affSColin Finck  */
420*c2c66affSColin Finck void
svcerr_noproc(xprt)421*c2c66affSColin Finck svcerr_noproc (xprt)
422*c2c66affSColin Finck      SVCXPRT *xprt;
423*c2c66affSColin Finck {
424*c2c66affSColin Finck   struct rpc_msg rply;
425*c2c66affSColin Finck 
426*c2c66affSColin Finck   assert (xprt != NULL);
427*c2c66affSColin Finck 
428*c2c66affSColin Finck   rply.rm_direction = REPLY;
429*c2c66affSColin Finck   rply.rm_reply.rp_stat = MSG_ACCEPTED;
430*c2c66affSColin Finck   rply.acpted_rply.ar_verf = xprt->xp_verf;
431*c2c66affSColin Finck   rply.acpted_rply.ar_stat = PROC_UNAVAIL;
432*c2c66affSColin Finck   SVC_REPLY (xprt, &rply);
433*c2c66affSColin Finck }
434*c2c66affSColin Finck 
435*c2c66affSColin Finck /*
436*c2c66affSColin Finck  * Can't decode args error reply
437*c2c66affSColin Finck  */
438*c2c66affSColin Finck void
svcerr_decode(xprt)439*c2c66affSColin Finck svcerr_decode (xprt)
440*c2c66affSColin Finck      SVCXPRT *xprt;
441*c2c66affSColin Finck {
442*c2c66affSColin Finck   struct rpc_msg rply;
443*c2c66affSColin Finck 
444*c2c66affSColin Finck   assert (xprt != NULL);
445*c2c66affSColin Finck 
446*c2c66affSColin Finck   rply.rm_direction = REPLY;
447*c2c66affSColin Finck   rply.rm_reply.rp_stat = MSG_ACCEPTED;
448*c2c66affSColin Finck   rply.acpted_rply.ar_verf = xprt->xp_verf;
449*c2c66affSColin Finck   rply.acpted_rply.ar_stat = GARBAGE_ARGS;
450*c2c66affSColin Finck   SVC_REPLY (xprt, &rply);
451*c2c66affSColin Finck }
452*c2c66affSColin Finck 
453*c2c66affSColin Finck /*
454*c2c66affSColin Finck  * Some system error
455*c2c66affSColin Finck  */
456*c2c66affSColin Finck void
svcerr_systemerr(xprt)457*c2c66affSColin Finck svcerr_systemerr (xprt)
458*c2c66affSColin Finck      SVCXPRT *xprt;
459*c2c66affSColin Finck {
460*c2c66affSColin Finck   struct rpc_msg rply;
461*c2c66affSColin Finck 
462*c2c66affSColin Finck   assert (xprt != NULL);
463*c2c66affSColin Finck 
464*c2c66affSColin Finck   rply.rm_direction = REPLY;
465*c2c66affSColin Finck   rply.rm_reply.rp_stat = MSG_ACCEPTED;
466*c2c66affSColin Finck   rply.acpted_rply.ar_verf = xprt->xp_verf;
467*c2c66affSColin Finck   rply.acpted_rply.ar_stat = SYSTEM_ERR;
468*c2c66affSColin Finck   SVC_REPLY (xprt, &rply);
469*c2c66affSColin Finck }
470*c2c66affSColin Finck 
471*c2c66affSColin Finck #if 0
472*c2c66affSColin Finck /*
473*c2c66affSColin Finck  * Tell RPC package to not complain about version errors to the client.	 This
474*c2c66affSColin Finck  * is useful when revving broadcast protocols that sit on a fixed address.
475*c2c66affSColin Finck  * There is really one (or should be only one) example of this kind of
476*c2c66affSColin Finck  * protocol: the portmapper (or rpc binder).
477*c2c66affSColin Finck  */
478*c2c66affSColin Finck void
479*c2c66affSColin Finck __svc_versquiet_on (xprt)
480*c2c66affSColin Finck      SVCXPRT *xprt;
481*c2c66affSColin Finck {
482*c2c66affSColin Finck   u_long tmp;
483*c2c66affSColin Finck 
484*c2c66affSColin Finck   tmp = ((u_long) xprt->xp_p3) | SVC_VERSQUIET;
485*c2c66affSColin Finck   xprt->xp_p3 = tmp;
486*c2c66affSColin Finck }
487*c2c66affSColin Finck 
488*c2c66affSColin Finck void
489*c2c66affSColin Finck __svc_versquiet_off (xprt)
490*c2c66affSColin Finck      SVCXPRT *xprt;
491*c2c66affSColin Finck {
492*c2c66affSColin Finck   u_long tmp;
493*c2c66affSColin Finck 
494*c2c66affSColin Finck   tmp = ((u_long) xprt->xp_p3) & ~SVC_VERSQUIET;
495*c2c66affSColin Finck   xprt->xp_p3 = tmp;
496*c2c66affSColin Finck }
497*c2c66affSColin Finck 
498*c2c66affSColin Finck void
499*c2c66affSColin Finck svc_versquiet (xprt)
500*c2c66affSColin Finck      SVCXPRT *xprt;
501*c2c66affSColin Finck {
502*c2c66affSColin Finck   __svc_versquiet_on (xprt);
503*c2c66affSColin Finck }
504*c2c66affSColin Finck 
505*c2c66affSColin Finck int
506*c2c66affSColin Finck __svc_versquiet_get (xprt)
507*c2c66affSColin Finck      SVCXPRT *xprt;
508*c2c66affSColin Finck {
509*c2c66affSColin Finck   return ((int) xprt->xp_p3) & SVC_VERSQUIET;
510*c2c66affSColin Finck }
511*c2c66affSColin Finck #endif
512*c2c66affSColin Finck 
513*c2c66affSColin Finck /*
514*c2c66affSColin Finck  * Authentication error reply
515*c2c66affSColin Finck  */
516*c2c66affSColin Finck void
svcerr_auth(xprt,why)517*c2c66affSColin Finck svcerr_auth (xprt, why)
518*c2c66affSColin Finck      SVCXPRT *xprt;
519*c2c66affSColin Finck      enum auth_stat why;
520*c2c66affSColin Finck {
521*c2c66affSColin Finck   struct rpc_msg rply;
522*c2c66affSColin Finck 
523*c2c66affSColin Finck   assert (xprt != NULL);
524*c2c66affSColin Finck 
525*c2c66affSColin Finck   rply.rm_direction = REPLY;
526*c2c66affSColin Finck   rply.rm_reply.rp_stat = MSG_DENIED;
527*c2c66affSColin Finck   rply.rjcted_rply.rj_stat = AUTH_ERROR;
528*c2c66affSColin Finck   rply.rjcted_rply.rj_why = why;
529*c2c66affSColin Finck   SVC_REPLY (xprt, &rply);
530*c2c66affSColin Finck }
531*c2c66affSColin Finck 
532*c2c66affSColin Finck /*
533*c2c66affSColin Finck  * Auth too weak error reply
534*c2c66affSColin Finck  */
535*c2c66affSColin Finck void
svcerr_weakauth(xprt)536*c2c66affSColin Finck svcerr_weakauth (xprt)
537*c2c66affSColin Finck      SVCXPRT *xprt;
538*c2c66affSColin Finck {
539*c2c66affSColin Finck 
540*c2c66affSColin Finck   assert (xprt != NULL);
541*c2c66affSColin Finck 
542*c2c66affSColin Finck   svcerr_auth (xprt, AUTH_TOOWEAK);
543*c2c66affSColin Finck }
544*c2c66affSColin Finck 
545*c2c66affSColin Finck /*
546*c2c66affSColin Finck  * Program unavailable error reply
547*c2c66affSColin Finck  */
548*c2c66affSColin Finck void
svcerr_noprog(xprt)549*c2c66affSColin Finck svcerr_noprog (xprt)
550*c2c66affSColin Finck      SVCXPRT *xprt;
551*c2c66affSColin Finck {
552*c2c66affSColin Finck   struct rpc_msg rply;
553*c2c66affSColin Finck 
554*c2c66affSColin Finck   assert (xprt != NULL);
555*c2c66affSColin Finck 
556*c2c66affSColin Finck   rply.rm_direction = REPLY;
557*c2c66affSColin Finck   rply.rm_reply.rp_stat = MSG_ACCEPTED;
558*c2c66affSColin Finck   rply.acpted_rply.ar_verf = xprt->xp_verf;
559*c2c66affSColin Finck   rply.acpted_rply.ar_stat = PROG_UNAVAIL;
560*c2c66affSColin Finck   SVC_REPLY (xprt, &rply);
561*c2c66affSColin Finck }
562*c2c66affSColin Finck 
563*c2c66affSColin Finck /*
564*c2c66affSColin Finck  * Program version mismatch error reply
565*c2c66affSColin Finck  */
566*c2c66affSColin Finck void
svcerr_progvers(xprt,low_vers,high_vers)567*c2c66affSColin Finck svcerr_progvers (xprt, low_vers, high_vers)
568*c2c66affSColin Finck      SVCXPRT *xprt;
569*c2c66affSColin Finck      rpcvers_t low_vers;
570*c2c66affSColin Finck      rpcvers_t high_vers;
571*c2c66affSColin Finck {
572*c2c66affSColin Finck   struct rpc_msg rply;
573*c2c66affSColin Finck 
574*c2c66affSColin Finck   assert (xprt != NULL);
575*c2c66affSColin Finck 
576*c2c66affSColin Finck   rply.rm_direction = REPLY;
577*c2c66affSColin Finck   rply.rm_reply.rp_stat = MSG_ACCEPTED;
578*c2c66affSColin Finck   rply.acpted_rply.ar_verf = xprt->xp_verf;
579*c2c66affSColin Finck   rply.acpted_rply.ar_stat = PROG_MISMATCH;
580*c2c66affSColin Finck   rply.acpted_rply.ar_vers.low = (u_int32_t) low_vers;
581*c2c66affSColin Finck   rply.acpted_rply.ar_vers.high = (u_int32_t) high_vers;
582*c2c66affSColin Finck   SVC_REPLY (xprt, &rply);
583*c2c66affSColin Finck }
584*c2c66affSColin Finck 
585*c2c66affSColin Finck /* ******************* SERVER INPUT STUFF ******************* */
586*c2c66affSColin Finck 
587*c2c66affSColin Finck /*
588*c2c66affSColin Finck  * Get server side input from some transport.
589*c2c66affSColin Finck  *
590*c2c66affSColin Finck  * Statement of authentication parameters management:
591*c2c66affSColin Finck  * This function owns and manages all authentication parameters, specifically
592*c2c66affSColin Finck  * the "raw" parameters (msg.rm_call.cb_cred and msg.rm_call.cb_verf) and
593*c2c66affSColin Finck  * the "cooked" credentials (rqst->rq_clntcred).
594*c2c66affSColin Finck  * However, this function does not know the structure of the cooked
595*c2c66affSColin Finck  * credentials, so it make the following assumptions:
596*c2c66affSColin Finck  *   a) the structure is contiguous (no pointers), and
597*c2c66affSColin Finck  *   b) the cred structure size does not exceed RQCRED_SIZE bytes.
598*c2c66affSColin Finck  * In all events, all three parameters are freed upon exit from this routine.
599*c2c66affSColin Finck  * The storage is trivially management on the call stack in user land, but
600*c2c66affSColin Finck  * is mallocated in kernel land.
601*c2c66affSColin Finck  */
602*c2c66affSColin Finck 
603*c2c66affSColin Finck void
svc_getreq(rdfds)604*c2c66affSColin Finck svc_getreq (rdfds)
605*c2c66affSColin Finck      int rdfds;
606*c2c66affSColin Finck {
607*c2c66affSColin Finck   fd_set readfds;
608*c2c66affSColin Finck 
609*c2c66affSColin Finck   FD_ZERO (&readfds);
610*c2c66affSColin Finck   //XXX Windows!! readfds.fds_bits[0] = rdfds;
611*c2c66affSColin Finck   svc_getreqset (&readfds);
612*c2c66affSColin Finck }
613*c2c66affSColin Finck 
614*c2c66affSColin Finck void
svc_getreqset(readfds)615*c2c66affSColin Finck svc_getreqset (readfds)
616*c2c66affSColin Finck      fd_set *readfds;
617*c2c66affSColin Finck {
618*c2c66affSColin Finck #ifndef _WIN32
619*c2c66affSColin Finck   int bit, fd;
620*c2c66affSColin Finck   fd_mask mask, *maskp;
621*c2c66affSColin Finck   int sock;
622*c2c66affSColin Finck 
623*c2c66affSColin Finck   assert (readfds != NULL);
624*c2c66affSColin Finck 
625*c2c66affSColin Finck   maskp = readfds->fds_bits;
626*c2c66affSColin Finck   for (sock = 0; sock < FD_SETSIZE; sock += NFDBITS)
627*c2c66affSColin Finck     {
628*c2c66affSColin Finck       for (mask = *maskp++; (bit = ffs (mask)) != 0; mask ^= (1 << (bit - 1)))
629*c2c66affSColin Finck 	{
630*c2c66affSColin Finck 	  /* sock has input waiting */
631*c2c66affSColin Finck 	  fd = sock + bit - 1;
632*c2c66affSColin Finck 	  svc_getreq_common (fd);
633*c2c66affSColin Finck 	}
634*c2c66affSColin Finck     }
635*c2c66affSColin Finck #else
636*c2c66affSColin Finck 	fprintf(stderr, "%s: Yikes!\n", __FUNCTION__);
637*c2c66affSColin Finck #endif
638*c2c66affSColin Finck }
639*c2c66affSColin Finck 
640*c2c66affSColin Finck void
svc_getreq_common(SOCKET fd)641*c2c66affSColin Finck svc_getreq_common (SOCKET fd)
642*c2c66affSColin Finck {
643*c2c66affSColin Finck   SVCXPRT *xprt;
644*c2c66affSColin Finck   struct svc_req r;
645*c2c66affSColin Finck   struct rpc_msg msg;
646*c2c66affSColin Finck   int prog_found;
647*c2c66affSColin Finck   rpcvers_t low_vers;
648*c2c66affSColin Finck   rpcvers_t high_vers;
649*c2c66affSColin Finck   enum xprt_stat stat;
650*c2c66affSColin Finck   char cred_area[2 * MAX_AUTH_BYTES + RQCRED_SIZE];
651*c2c66affSColin Finck 
652*c2c66affSColin Finck   msg.rm_call.cb_cred.oa_base = cred_area;
653*c2c66affSColin Finck   msg.rm_call.cb_verf.oa_base = &(cred_area[MAX_AUTH_BYTES]);
654*c2c66affSColin Finck   r.rq_clntcred = &(cred_area[2 * MAX_AUTH_BYTES]);
655*c2c66affSColin Finck 
656*c2c66affSColin Finck   rwlock_rdlock (&svc_fd_lock);
657*c2c66affSColin Finck   xprt = __svc_xports[fd];
658*c2c66affSColin Finck   rwlock_unlock (&svc_fd_lock);
659*c2c66affSColin Finck   if (xprt == NULL)
660*c2c66affSColin Finck     /* But do we control sock? */
661*c2c66affSColin Finck     return;
662*c2c66affSColin Finck   /* now receive msgs from xprtprt (support batch calls) */
663*c2c66affSColin Finck   do
664*c2c66affSColin Finck     {
665*c2c66affSColin Finck       if (SVC_RECV (xprt, &msg))
666*c2c66affSColin Finck 	{
667*c2c66affSColin Finck 
668*c2c66affSColin Finck 	  /* now find the exported program and call it */
669*c2c66affSColin Finck 	  struct svc_callout *s;
670*c2c66affSColin Finck 	  enum auth_stat why;
671*c2c66affSColin Finck 
672*c2c66affSColin Finck 	  r.rq_xprt = xprt;
673*c2c66affSColin Finck 	  r.rq_prog = msg.rm_call.cb_prog;
674*c2c66affSColin Finck 	  r.rq_vers = msg.rm_call.cb_vers;
675*c2c66affSColin Finck 	  r.rq_proc = msg.rm_call.cb_proc;
676*c2c66affSColin Finck 	  r.rq_cred = msg.rm_call.cb_cred;
677*c2c66affSColin Finck 	  /* first authenticate the message */
678*c2c66affSColin Finck 	  if ((why = _authenticate (&r, &msg)) != AUTH_OK)
679*c2c66affSColin Finck 	    {
680*c2c66affSColin Finck 	      svcerr_auth (xprt, why);
681*c2c66affSColin Finck 	      goto call_done;
682*c2c66affSColin Finck 	    }
683*c2c66affSColin Finck 	  /* now match message with a registered service */
684*c2c66affSColin Finck 	  prog_found = FALSE;
685*c2c66affSColin Finck 	  low_vers = (rpcvers_t) - 1L;
686*c2c66affSColin Finck 	  high_vers = (rpcvers_t) 0L;
687*c2c66affSColin Finck 	  for (s = svc_head; s != NULL; s = s->sc_next)
688*c2c66affSColin Finck 	    {
689*c2c66affSColin Finck 	      if (s->sc_prog == r.rq_prog)
690*c2c66affSColin Finck 		{
691*c2c66affSColin Finck 		  if (s->sc_vers == r.rq_vers)
692*c2c66affSColin Finck 		    {
693*c2c66affSColin Finck 		      (*s->sc_dispatch) (&r, xprt);
694*c2c66affSColin Finck 		      goto call_done;
695*c2c66affSColin Finck 		    }		/* found correct version */
696*c2c66affSColin Finck 		  prog_found = TRUE;
697*c2c66affSColin Finck 		  if (s->sc_vers < low_vers)
698*c2c66affSColin Finck 		    low_vers = s->sc_vers;
699*c2c66affSColin Finck 		  if (s->sc_vers > high_vers)
700*c2c66affSColin Finck 		    high_vers = s->sc_vers;
701*c2c66affSColin Finck 		}		/* found correct program */
702*c2c66affSColin Finck 	    }
703*c2c66affSColin Finck 	  /*
704*c2c66affSColin Finck 	   * if we got here, the program or version
705*c2c66affSColin Finck 	   * is not served ...
706*c2c66affSColin Finck 	   */
707*c2c66affSColin Finck 	  if (prog_found)
708*c2c66affSColin Finck 	    svcerr_progvers (xprt, low_vers, high_vers);
709*c2c66affSColin Finck 	  else
710*c2c66affSColin Finck 	    svcerr_noprog (xprt);
711*c2c66affSColin Finck 	  /* Fall through to ... */
712*c2c66affSColin Finck 	}
713*c2c66affSColin Finck       /*
714*c2c66affSColin Finck        * Check if the xprt has been disconnected in a
715*c2c66affSColin Finck        * recursive call in the service dispatch routine.
716*c2c66affSColin Finck        * If so, then break.
717*c2c66affSColin Finck        */
718*c2c66affSColin Finck       rwlock_rdlock (&svc_fd_lock);
719*c2c66affSColin Finck 
720*c2c66affSColin Finck       if (xprt != __svc_xports[fd])
721*c2c66affSColin Finck 	{
722*c2c66affSColin Finck 	  rwlock_unlock (&svc_fd_lock);
723*c2c66affSColin Finck 	  break;
724*c2c66affSColin Finck 	}
725*c2c66affSColin Finck       rwlock_unlock (&svc_fd_lock);
726*c2c66affSColin Finck     call_done:
727*c2c66affSColin Finck       if ((stat = SVC_STAT (xprt)) == XPRT_DIED)
728*c2c66affSColin Finck 	{
729*c2c66affSColin Finck 	  SVC_DESTROY (xprt);
730*c2c66affSColin Finck 	  break;
731*c2c66affSColin Finck 	}
732*c2c66affSColin Finck     else if ((xprt->xp_auth != NULL)
733*c2c66affSColin Finck #ifdef HAVE_LIBGSSAPI
734*c2c66affSColin Finck 	  	&& (xprt->xp_auth->svc_ah_ops != &svc_auth_gss_ops)
735*c2c66affSColin Finck #endif
736*c2c66affSColin Finck 	) {
737*c2c66affSColin Finck 	  xprt->xp_auth = NULL;
738*c2c66affSColin Finck 	}
739*c2c66affSColin Finck     }
740*c2c66affSColin Finck   while (stat == XPRT_MOREREQS);
741*c2c66affSColin Finck }
742*c2c66affSColin Finck 
743*c2c66affSColin Finck 
744*c2c66affSColin Finck void
svc_getreq_poll(pfdp,pollretval)745*c2c66affSColin Finck svc_getreq_poll (pfdp, pollretval)
746*c2c66affSColin Finck      struct pollfd *pfdp;
747*c2c66affSColin Finck      int pollretval;
748*c2c66affSColin Finck {
749*c2c66affSColin Finck   int i;
750*c2c66affSColin Finck   int fds_found;
751*c2c66affSColin Finck 
752*c2c66affSColin Finck   for (i = fds_found = 0; fds_found < pollretval; i++)
753*c2c66affSColin Finck     {
754*c2c66affSColin Finck       struct pollfd *p = &pfdp[i];
755*c2c66affSColin Finck 
756*c2c66affSColin Finck       if (p->revents)
757*c2c66affSColin Finck 	{
758*c2c66affSColin Finck 	  /* fd has input waiting */
759*c2c66affSColin Finck 	  fds_found++;
760*c2c66affSColin Finck 	  /*
761*c2c66affSColin Finck 	   *      We assume that this function is only called
762*c2c66affSColin Finck 	   *      via someone _select()ing from svc_fdset or
763*c2c66affSColin Finck 	   *      _poll()ing from svc_pollset[].  Thus it's safe
764*c2c66affSColin Finck 	   *      to handle the POLLNVAL event by simply turning
765*c2c66affSColin Finck 	   *      the corresponding bit off in svc_fdset.  The
766*c2c66affSColin Finck 	   *      svc_pollset[] array is derived from svc_fdset
767*c2c66affSColin Finck 	   *      and so will also be updated eventually.
768*c2c66affSColin Finck 	   *
769*c2c66affSColin Finck 	   *      XXX Should we do an xprt_unregister() instead?
770*c2c66affSColin Finck 	   */
771*c2c66affSColin Finck 	  if (p->revents & POLLNVAL)
772*c2c66affSColin Finck 	    {
773*c2c66affSColin Finck 	      rwlock_wrlock (&svc_fd_lock);
774*c2c66affSColin Finck 	      FD_CLR (p->fd, &svc_fdset);
775*c2c66affSColin Finck 	      rwlock_unlock (&svc_fd_lock);
776*c2c66affSColin Finck 	    }
777*c2c66affSColin Finck 	  else
778*c2c66affSColin Finck 	    svc_getreq_common (p->fd);
779*c2c66affSColin Finck 	}
780*c2c66affSColin Finck     }
781*c2c66affSColin Finck }
782*c2c66affSColin Finck 
783*c2c66affSColin Finck bool_t
rpc_control(int what,void * arg)784*c2c66affSColin Finck rpc_control (int what, void *arg)
785*c2c66affSColin Finck {
786*c2c66affSColin Finck   int val;
787*c2c66affSColin Finck 
788*c2c66affSColin Finck   switch (what)
789*c2c66affSColin Finck     {
790*c2c66affSColin Finck     case RPC_SVC_CONNMAXREC_SET:
791*c2c66affSColin Finck       val = *(int *) arg;
792*c2c66affSColin Finck       if (val <= 0)
793*c2c66affSColin Finck 	return FALSE;
794*c2c66affSColin Finck       __svc_maxrec = val;
795*c2c66affSColin Finck       return TRUE;
796*c2c66affSColin Finck     case RPC_SVC_CONNMAXREC_GET:
797*c2c66affSColin Finck       *(int *) arg = __svc_maxrec;
798*c2c66affSColin Finck       return TRUE;
799*c2c66affSColin Finck     default:
800*c2c66affSColin Finck       break;
801*c2c66affSColin Finck     }
802*c2c66affSColin Finck   return FALSE;
803*c2c66affSColin Finck }
804