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