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