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