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