1*45089Smckusick /* @(#)svc.c 2.4 88/08/11 4.0 RPCSRC; from 1.44 88/02/08 SMI */
2*45089Smckusick /*
3*45089Smckusick * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
4*45089Smckusick * unrestricted use provided that this legend is included on all tape
5*45089Smckusick * media and as a part of the software program in whole or part. Users
6*45089Smckusick * may copy or modify Sun RPC without charge, but are not authorized
7*45089Smckusick * to license or distribute it to anyone else except as part of a product or
8*45089Smckusick * program developed by the user.
9*45089Smckusick *
10*45089Smckusick * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
11*45089Smckusick * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
12*45089Smckusick * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
13*45089Smckusick *
14*45089Smckusick * Sun RPC is provided with no support and without any obligation on the
15*45089Smckusick * part of Sun Microsystems, Inc. to assist in its use, correction,
16*45089Smckusick * modification or enhancement.
17*45089Smckusick *
18*45089Smckusick * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
19*45089Smckusick * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
20*45089Smckusick * OR ANY PART THEREOF.
21*45089Smckusick *
22*45089Smckusick * In no event will Sun Microsystems, Inc. be liable for any lost revenue
23*45089Smckusick * or profits or other special, indirect and consequential damages, even if
24*45089Smckusick * Sun has been advised of the possibility of such damages.
25*45089Smckusick *
26*45089Smckusick * Sun Microsystems, Inc.
27*45089Smckusick * 2550 Garcia Avenue
28*45089Smckusick * Mountain View, California 94043
29*45089Smckusick */
30*45089Smckusick #if !defined(lint) && defined(SCCSIDS)
31*45089Smckusick static char sccsid[] = "@(#)svc.c 1.41 87/10/13 Copyr 1984 Sun Micro";
32*45089Smckusick #endif
33*45089Smckusick
34*45089Smckusick /*
35*45089Smckusick * svc.c, Server-side remote procedure call interface.
36*45089Smckusick *
37*45089Smckusick * There are two sets of procedures here. The xprt routines are
38*45089Smckusick * for handling transport handles. The svc routines handle the
39*45089Smckusick * list of service routines.
40*45089Smckusick *
41*45089Smckusick * Copyright (C) 1984, Sun Microsystems, Inc.
42*45089Smckusick */
43*45089Smckusick
44*45089Smckusick #include <sys/errno.h>
45*45089Smckusick #include <rpc/rpc.h>
46*45089Smckusick #include <rpc/pmap_clnt.h>
47*45089Smckusick
48*45089Smckusick extern int errno;
49*45089Smckusick
50*45089Smckusick #ifdef FD_SETSIZE
51*45089Smckusick static SVCXPRT **xports;
52*45089Smckusick #else
53*45089Smckusick #define NOFILE 32
54*45089Smckusick
55*45089Smckusick static SVCXPRT *xports[NOFILE];
56*45089Smckusick #endif /* def FD_SETSIZE */
57*45089Smckusick
58*45089Smckusick #define NULL_SVC ((struct svc_callout *)0)
59*45089Smckusick #define RQCRED_SIZE 400 /* this size is excessive */
60*45089Smckusick
61*45089Smckusick /*
62*45089Smckusick * The services list
63*45089Smckusick * Each entry represents a set of procedures (an rpc program).
64*45089Smckusick * The dispatch routine takes request structs and runs the
65*45089Smckusick * apropriate procedure.
66*45089Smckusick */
67*45089Smckusick static struct svc_callout {
68*45089Smckusick struct svc_callout *sc_next;
69*45089Smckusick u_long sc_prog;
70*45089Smckusick u_long sc_vers;
71*45089Smckusick void (*sc_dispatch)();
72*45089Smckusick } *svc_head;
73*45089Smckusick
74*45089Smckusick static struct svc_callout *svc_find();
75*45089Smckusick
76*45089Smckusick /* *************** SVCXPRT related stuff **************** */
77*45089Smckusick
78*45089Smckusick /*
79*45089Smckusick * Activate a transport handle.
80*45089Smckusick */
81*45089Smckusick void
xprt_register(xprt)82*45089Smckusick xprt_register(xprt)
83*45089Smckusick SVCXPRT *xprt;
84*45089Smckusick {
85*45089Smckusick register int sock = xprt->xp_sock;
86*45089Smckusick
87*45089Smckusick #ifdef FD_SETSIZE
88*45089Smckusick if (xports == NULL) {
89*45089Smckusick xports = (SVCXPRT **)
90*45089Smckusick mem_alloc(FD_SETSIZE * sizeof(SVCXPRT *));
91*45089Smckusick }
92*45089Smckusick if (sock < _rpc_dtablesize()) {
93*45089Smckusick xports[sock] = xprt;
94*45089Smckusick FD_SET(sock, &svc_fdset);
95*45089Smckusick }
96*45089Smckusick #else
97*45089Smckusick if (sock < NOFILE) {
98*45089Smckusick xports[sock] = xprt;
99*45089Smckusick svc_fds |= (1 << sock);
100*45089Smckusick }
101*45089Smckusick #endif /* def FD_SETSIZE */
102*45089Smckusick
103*45089Smckusick }
104*45089Smckusick
105*45089Smckusick /*
106*45089Smckusick * De-activate a transport handle.
107*45089Smckusick */
108*45089Smckusick void
xprt_unregister(xprt)109*45089Smckusick xprt_unregister(xprt)
110*45089Smckusick SVCXPRT *xprt;
111*45089Smckusick {
112*45089Smckusick register int sock = xprt->xp_sock;
113*45089Smckusick
114*45089Smckusick #ifdef FD_SETSIZE
115*45089Smckusick if ((sock < _rpc_dtablesize()) && (xports[sock] == xprt)) {
116*45089Smckusick xports[sock] = (SVCXPRT *)0;
117*45089Smckusick FD_CLR(sock, &svc_fdset);
118*45089Smckusick }
119*45089Smckusick #else
120*45089Smckusick if ((sock < NOFILE) && (xports[sock] == xprt)) {
121*45089Smckusick xports[sock] = (SVCXPRT *)0;
122*45089Smckusick svc_fds &= ~(1 << sock);
123*45089Smckusick }
124*45089Smckusick #endif /* def FD_SETSIZE */
125*45089Smckusick }
126*45089Smckusick
127*45089Smckusick
128*45089Smckusick /* ********************** CALLOUT list related stuff ************* */
129*45089Smckusick
130*45089Smckusick /*
131*45089Smckusick * Add a service program to the callout list.
132*45089Smckusick * The dispatch routine will be called when a rpc request for this
133*45089Smckusick * program number comes in.
134*45089Smckusick */
135*45089Smckusick bool_t
svc_register(xprt,prog,vers,dispatch,protocol)136*45089Smckusick svc_register(xprt, prog, vers, dispatch, protocol)
137*45089Smckusick SVCXPRT *xprt;
138*45089Smckusick u_long prog;
139*45089Smckusick u_long vers;
140*45089Smckusick void (*dispatch)();
141*45089Smckusick int protocol;
142*45089Smckusick {
143*45089Smckusick struct svc_callout *prev;
144*45089Smckusick register struct svc_callout *s;
145*45089Smckusick
146*45089Smckusick if ((s = svc_find(prog, vers, &prev)) != NULL_SVC) {
147*45089Smckusick if (s->sc_dispatch == dispatch)
148*45089Smckusick goto pmap_it; /* he is registering another xptr */
149*45089Smckusick return (FALSE);
150*45089Smckusick }
151*45089Smckusick s = (struct svc_callout *)mem_alloc(sizeof(struct svc_callout));
152*45089Smckusick if (s == (struct svc_callout *)0) {
153*45089Smckusick return (FALSE);
154*45089Smckusick }
155*45089Smckusick s->sc_prog = prog;
156*45089Smckusick s->sc_vers = vers;
157*45089Smckusick s->sc_dispatch = dispatch;
158*45089Smckusick s->sc_next = svc_head;
159*45089Smckusick svc_head = s;
160*45089Smckusick pmap_it:
161*45089Smckusick /* now register the information with the local binder service */
162*45089Smckusick if (protocol) {
163*45089Smckusick return (pmap_set(prog, vers, protocol, xprt->xp_port));
164*45089Smckusick }
165*45089Smckusick return (TRUE);
166*45089Smckusick }
167*45089Smckusick
168*45089Smckusick /*
169*45089Smckusick * Remove a service program from the callout list.
170*45089Smckusick */
171*45089Smckusick void
svc_unregister(prog,vers)172*45089Smckusick svc_unregister(prog, vers)
173*45089Smckusick u_long prog;
174*45089Smckusick u_long vers;
175*45089Smckusick {
176*45089Smckusick struct svc_callout *prev;
177*45089Smckusick register struct svc_callout *s;
178*45089Smckusick
179*45089Smckusick if ((s = svc_find(prog, vers, &prev)) == NULL_SVC)
180*45089Smckusick return;
181*45089Smckusick if (prev == NULL_SVC) {
182*45089Smckusick svc_head = s->sc_next;
183*45089Smckusick } else {
184*45089Smckusick prev->sc_next = s->sc_next;
185*45089Smckusick }
186*45089Smckusick s->sc_next = NULL_SVC;
187*45089Smckusick mem_free((char *) s, (u_int) sizeof(struct svc_callout));
188*45089Smckusick /* now unregister the information with the local binder service */
189*45089Smckusick (void)pmap_unset(prog, vers);
190*45089Smckusick }
191*45089Smckusick
192*45089Smckusick /*
193*45089Smckusick * Search the callout list for a program number, return the callout
194*45089Smckusick * struct.
195*45089Smckusick */
196*45089Smckusick static struct svc_callout *
svc_find(prog,vers,prev)197*45089Smckusick svc_find(prog, vers, prev)
198*45089Smckusick u_long prog;
199*45089Smckusick u_long vers;
200*45089Smckusick struct svc_callout **prev;
201*45089Smckusick {
202*45089Smckusick register struct svc_callout *s, *p;
203*45089Smckusick
204*45089Smckusick p = NULL_SVC;
205*45089Smckusick for (s = svc_head; s != NULL_SVC; s = s->sc_next) {
206*45089Smckusick if ((s->sc_prog == prog) && (s->sc_vers == vers))
207*45089Smckusick goto done;
208*45089Smckusick p = s;
209*45089Smckusick }
210*45089Smckusick done:
211*45089Smckusick *prev = p;
212*45089Smckusick return (s);
213*45089Smckusick }
214*45089Smckusick
215*45089Smckusick /* ******************* REPLY GENERATION ROUTINES ************ */
216*45089Smckusick
217*45089Smckusick /*
218*45089Smckusick * Send a reply to an rpc request
219*45089Smckusick */
220*45089Smckusick bool_t
svc_sendreply(xprt,xdr_results,xdr_location)221*45089Smckusick svc_sendreply(xprt, xdr_results, xdr_location)
222*45089Smckusick register SVCXPRT *xprt;
223*45089Smckusick xdrproc_t xdr_results;
224*45089Smckusick caddr_t xdr_location;
225*45089Smckusick {
226*45089Smckusick struct rpc_msg rply;
227*45089Smckusick
228*45089Smckusick rply.rm_direction = REPLY;
229*45089Smckusick rply.rm_reply.rp_stat = MSG_ACCEPTED;
230*45089Smckusick rply.acpted_rply.ar_verf = xprt->xp_verf;
231*45089Smckusick rply.acpted_rply.ar_stat = SUCCESS;
232*45089Smckusick rply.acpted_rply.ar_results.where = xdr_location;
233*45089Smckusick rply.acpted_rply.ar_results.proc = xdr_results;
234*45089Smckusick return (SVC_REPLY(xprt, &rply));
235*45089Smckusick }
236*45089Smckusick
237*45089Smckusick /*
238*45089Smckusick * No procedure error reply
239*45089Smckusick */
240*45089Smckusick void
svcerr_noproc(xprt)241*45089Smckusick svcerr_noproc(xprt)
242*45089Smckusick register SVCXPRT *xprt;
243*45089Smckusick {
244*45089Smckusick struct rpc_msg rply;
245*45089Smckusick
246*45089Smckusick rply.rm_direction = REPLY;
247*45089Smckusick rply.rm_reply.rp_stat = MSG_ACCEPTED;
248*45089Smckusick rply.acpted_rply.ar_verf = xprt->xp_verf;
249*45089Smckusick rply.acpted_rply.ar_stat = PROC_UNAVAIL;
250*45089Smckusick SVC_REPLY(xprt, &rply);
251*45089Smckusick }
252*45089Smckusick
253*45089Smckusick /*
254*45089Smckusick * Can't decode args error reply
255*45089Smckusick */
256*45089Smckusick void
svcerr_decode(xprt)257*45089Smckusick svcerr_decode(xprt)
258*45089Smckusick register SVCXPRT *xprt;
259*45089Smckusick {
260*45089Smckusick struct rpc_msg rply;
261*45089Smckusick
262*45089Smckusick rply.rm_direction = REPLY;
263*45089Smckusick rply.rm_reply.rp_stat = MSG_ACCEPTED;
264*45089Smckusick rply.acpted_rply.ar_verf = xprt->xp_verf;
265*45089Smckusick rply.acpted_rply.ar_stat = GARBAGE_ARGS;
266*45089Smckusick SVC_REPLY(xprt, &rply);
267*45089Smckusick }
268*45089Smckusick
269*45089Smckusick /*
270*45089Smckusick * Some system error
271*45089Smckusick */
272*45089Smckusick void
svcerr_systemerr(xprt)273*45089Smckusick svcerr_systemerr(xprt)
274*45089Smckusick register SVCXPRT *xprt;
275*45089Smckusick {
276*45089Smckusick struct rpc_msg rply;
277*45089Smckusick
278*45089Smckusick rply.rm_direction = REPLY;
279*45089Smckusick rply.rm_reply.rp_stat = MSG_ACCEPTED;
280*45089Smckusick rply.acpted_rply.ar_verf = xprt->xp_verf;
281*45089Smckusick rply.acpted_rply.ar_stat = SYSTEM_ERR;
282*45089Smckusick SVC_REPLY(xprt, &rply);
283*45089Smckusick }
284*45089Smckusick
285*45089Smckusick /*
286*45089Smckusick * Authentication error reply
287*45089Smckusick */
288*45089Smckusick void
svcerr_auth(xprt,why)289*45089Smckusick svcerr_auth(xprt, why)
290*45089Smckusick SVCXPRT *xprt;
291*45089Smckusick enum auth_stat why;
292*45089Smckusick {
293*45089Smckusick struct rpc_msg rply;
294*45089Smckusick
295*45089Smckusick rply.rm_direction = REPLY;
296*45089Smckusick rply.rm_reply.rp_stat = MSG_DENIED;
297*45089Smckusick rply.rjcted_rply.rj_stat = AUTH_ERROR;
298*45089Smckusick rply.rjcted_rply.rj_why = why;
299*45089Smckusick SVC_REPLY(xprt, &rply);
300*45089Smckusick }
301*45089Smckusick
302*45089Smckusick /*
303*45089Smckusick * Auth too weak error reply
304*45089Smckusick */
305*45089Smckusick void
svcerr_weakauth(xprt)306*45089Smckusick svcerr_weakauth(xprt)
307*45089Smckusick SVCXPRT *xprt;
308*45089Smckusick {
309*45089Smckusick
310*45089Smckusick svcerr_auth(xprt, AUTH_TOOWEAK);
311*45089Smckusick }
312*45089Smckusick
313*45089Smckusick /*
314*45089Smckusick * Program unavailable error reply
315*45089Smckusick */
316*45089Smckusick void
svcerr_noprog(xprt)317*45089Smckusick svcerr_noprog(xprt)
318*45089Smckusick register SVCXPRT *xprt;
319*45089Smckusick {
320*45089Smckusick struct rpc_msg rply;
321*45089Smckusick
322*45089Smckusick rply.rm_direction = REPLY;
323*45089Smckusick rply.rm_reply.rp_stat = MSG_ACCEPTED;
324*45089Smckusick rply.acpted_rply.ar_verf = xprt->xp_verf;
325*45089Smckusick rply.acpted_rply.ar_stat = PROG_UNAVAIL;
326*45089Smckusick SVC_REPLY(xprt, &rply);
327*45089Smckusick }
328*45089Smckusick
329*45089Smckusick /*
330*45089Smckusick * Program version mismatch error reply
331*45089Smckusick */
332*45089Smckusick void
svcerr_progvers(xprt,low_vers,high_vers)333*45089Smckusick svcerr_progvers(xprt, low_vers, high_vers)
334*45089Smckusick register SVCXPRT *xprt;
335*45089Smckusick u_long low_vers;
336*45089Smckusick u_long high_vers;
337*45089Smckusick {
338*45089Smckusick struct rpc_msg rply;
339*45089Smckusick
340*45089Smckusick rply.rm_direction = REPLY;
341*45089Smckusick rply.rm_reply.rp_stat = MSG_ACCEPTED;
342*45089Smckusick rply.acpted_rply.ar_verf = xprt->xp_verf;
343*45089Smckusick rply.acpted_rply.ar_stat = PROG_MISMATCH;
344*45089Smckusick rply.acpted_rply.ar_vers.low = low_vers;
345*45089Smckusick rply.acpted_rply.ar_vers.high = high_vers;
346*45089Smckusick SVC_REPLY(xprt, &rply);
347*45089Smckusick }
348*45089Smckusick
349*45089Smckusick /* ******************* SERVER INPUT STUFF ******************* */
350*45089Smckusick
351*45089Smckusick /*
352*45089Smckusick * Get server side input from some transport.
353*45089Smckusick *
354*45089Smckusick * Statement of authentication parameters management:
355*45089Smckusick * This function owns and manages all authentication parameters, specifically
356*45089Smckusick * the "raw" parameters (msg.rm_call.cb_cred and msg.rm_call.cb_verf) and
357*45089Smckusick * the "cooked" credentials (rqst->rq_clntcred).
358*45089Smckusick * However, this function does not know the structure of the cooked
359*45089Smckusick * credentials, so it make the following assumptions:
360*45089Smckusick * a) the structure is contiguous (no pointers), and
361*45089Smckusick * b) the cred structure size does not exceed RQCRED_SIZE bytes.
362*45089Smckusick * In all events, all three parameters are freed upon exit from this routine.
363*45089Smckusick * The storage is trivially management on the call stack in user land, but
364*45089Smckusick * is mallocated in kernel land.
365*45089Smckusick */
366*45089Smckusick
367*45089Smckusick void
svc_getreq(rdfds)368*45089Smckusick svc_getreq(rdfds)
369*45089Smckusick int rdfds;
370*45089Smckusick {
371*45089Smckusick #ifdef FD_SETSIZE
372*45089Smckusick fd_set readfds;
373*45089Smckusick
374*45089Smckusick FD_ZERO(&readfds);
375*45089Smckusick readfds.fds_bits[0] = rdfds;
376*45089Smckusick svc_getreqset(&readfds);
377*45089Smckusick #else
378*45089Smckusick int readfds = rdfds & svc_fds;
379*45089Smckusick
380*45089Smckusick svc_getreqset(&readfds);
381*45089Smckusick #endif /* def FD_SETSIZE */
382*45089Smckusick }
383*45089Smckusick
384*45089Smckusick void
svc_getreqset(readfds)385*45089Smckusick svc_getreqset(readfds)
386*45089Smckusick #ifdef FD_SETSIZE
387*45089Smckusick fd_set *readfds;
388*45089Smckusick {
389*45089Smckusick #else
390*45089Smckusick int *readfds;
391*45089Smckusick {
392*45089Smckusick int readfds_local = *readfds;
393*45089Smckusick #endif /* def FD_SETSIZE */
394*45089Smckusick enum xprt_stat stat;
395*45089Smckusick struct rpc_msg msg;
396*45089Smckusick int prog_found;
397*45089Smckusick u_long low_vers;
398*45089Smckusick u_long high_vers;
399*45089Smckusick struct svc_req r;
400*45089Smckusick register SVCXPRT *xprt;
401*45089Smckusick register u_long mask;
402*45089Smckusick register int bit;
403*45089Smckusick register u_long *maskp;
404*45089Smckusick register int setsize;
405*45089Smckusick register int sock;
406*45089Smckusick char cred_area[2*MAX_AUTH_BYTES + RQCRED_SIZE];
407*45089Smckusick msg.rm_call.cb_cred.oa_base = cred_area;
408*45089Smckusick msg.rm_call.cb_verf.oa_base = &(cred_area[MAX_AUTH_BYTES]);
409*45089Smckusick r.rq_clntcred = &(cred_area[2*MAX_AUTH_BYTES]);
410*45089Smckusick
411*45089Smckusick
412*45089Smckusick #ifdef FD_SETSIZE
413*45089Smckusick setsize = _rpc_dtablesize();
414*45089Smckusick maskp = (u_long *)readfds->fds_bits;
415*45089Smckusick for (sock = 0; sock < setsize; sock += NFDBITS) {
416*45089Smckusick for (mask = *maskp++; bit = ffs(mask); mask ^= (1 << (bit - 1))) {
417*45089Smckusick /* sock has input waiting */
418*45089Smckusick xprt = xports[sock + bit - 1];
419*45089Smckusick #else
420*45089Smckusick for (sock = 0; readfds_local != 0; sock++, readfds_local >>= 1) {
421*45089Smckusick if ((readfds_local & 1) != 0) {
422*45089Smckusick /* sock has input waiting */
423*45089Smckusick xprt = xports[sock];
424*45089Smckusick #endif /* def FD_SETSIZE */
425*45089Smckusick /* now receive msgs from xprtprt (support batch calls) */
426*45089Smckusick do {
427*45089Smckusick if (SVC_RECV(xprt, &msg)) {
428*45089Smckusick
429*45089Smckusick /* now find the exported program and call it */
430*45089Smckusick register struct svc_callout *s;
431*45089Smckusick enum auth_stat why;
432*45089Smckusick
433*45089Smckusick r.rq_xprt = xprt;
434*45089Smckusick r.rq_prog = msg.rm_call.cb_prog;
435*45089Smckusick r.rq_vers = msg.rm_call.cb_vers;
436*45089Smckusick r.rq_proc = msg.rm_call.cb_proc;
437*45089Smckusick r.rq_cred = msg.rm_call.cb_cred;
438*45089Smckusick /* first authenticate the message */
439*45089Smckusick if ((why= _authenticate(&r, &msg)) != AUTH_OK) {
440*45089Smckusick svcerr_auth(xprt, why);
441*45089Smckusick goto call_done;
442*45089Smckusick }
443*45089Smckusick /* now match message with a registered service*/
444*45089Smckusick prog_found = FALSE;
445*45089Smckusick low_vers = 0 - 1;
446*45089Smckusick high_vers = 0;
447*45089Smckusick for (s = svc_head; s != NULL_SVC; s = s->sc_next) {
448*45089Smckusick if (s->sc_prog == r.rq_prog) {
449*45089Smckusick if (s->sc_vers == r.rq_vers) {
450*45089Smckusick (*s->sc_dispatch)(&r, xprt);
451*45089Smckusick goto call_done;
452*45089Smckusick } /* found correct version */
453*45089Smckusick prog_found = TRUE;
454*45089Smckusick if (s->sc_vers < low_vers)
455*45089Smckusick low_vers = s->sc_vers;
456*45089Smckusick if (s->sc_vers > high_vers)
457*45089Smckusick high_vers = s->sc_vers;
458*45089Smckusick } /* found correct program */
459*45089Smckusick }
460*45089Smckusick /*
461*45089Smckusick * if we got here, the program or version
462*45089Smckusick * is not served ...
463*45089Smckusick */
464*45089Smckusick if (prog_found)
465*45089Smckusick svcerr_progvers(xprt,
466*45089Smckusick low_vers, high_vers);
467*45089Smckusick else
468*45089Smckusick svcerr_noprog(xprt);
469*45089Smckusick /* Fall through to ... */
470*45089Smckusick }
471*45089Smckusick call_done:
472*45089Smckusick if ((stat = SVC_STAT(xprt)) == XPRT_DIED){
473*45089Smckusick SVC_DESTROY(xprt);
474*45089Smckusick break;
475*45089Smckusick }
476*45089Smckusick } while (stat == XPRT_MOREREQS);
477*45089Smckusick }
478*45089Smckusick }
479*45089Smckusick }
480