Merge branch 'vendor/TNFTP'
[dragonfly.git] / lib / libc / rpc / svc.c
1 /*
2  * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
3  * unrestricted use provided that this legend is included on all tape
4  * media and as a part of the software program in whole or part.  Users
5  * may copy or modify Sun RPC without charge, but are not authorized
6  * to license or distribute it to anyone else except as part of a product or
7  * program developed by the user.
8  *
9  * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
10  * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
11  * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
12  *
13  * Sun RPC is provided with no support and without any obligation on the
14  * part of Sun Microsystems, Inc. to assist in its use, correction,
15  * modification or enhancement.
16  *
17  * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
18  * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
19  * OR ANY PART THEREOF.
20  *
21  * In no event will Sun Microsystems, Inc. be liable for any lost revenue
22  * or profits or other special, indirect and consequential damages, even if
23  * Sun has been advised of the possibility of such damages.
24  *
25  * Sun Microsystems, Inc.
26  * 2550 Garcia Avenue
27  * Mountain View, California  94043
28  *
29  * @(#)svc.c 1.44 88/02/08 Copyr 1984 Sun Micro
30  * @(#)svc.c    2.4 88/08/11 4.0 RPCSRC
31  * $NetBSD: svc.c,v 1.21 2000/07/06 03:10:35 christos Exp $
32  * $FreeBSD: src/lib/libc/rpc/svc.c,v 1.24 2006/02/27 22:10:59 deischen Exp $
33  * $DragonFly: src/lib/libc/rpc/svc.c,v 1.4 2005/11/13 12:27:04 swildner Exp $
34  */
35
36 /*
37  * svc.c, Server-side remote procedure call interface.
38  *
39  * There are two sets of procedures here.  The xprt routines are
40  * for handling transport handles.  The svc routines handle the
41  * list of service routines.
42  *
43  * Copyright (C) 1984, Sun Microsystems, Inc.
44  */
45
46 #include "namespace.h"
47 #include "reentrant.h"
48 #include <sys/types.h>
49 #include <sys/poll.h>
50 #include <assert.h>
51 #include <errno.h>
52 #include <stdlib.h>
53 #include <string.h>
54
55 #include <rpc/rpc.h>
56 #ifdef PORTMAP
57 #include <rpc/pmap_clnt.h>
58 #endif                          /* PORTMAP */
59 #include "un-namespace.h"
60
61 #include "rpc_com.h"
62 #include "mt_misc.h"
63
64 #define RQCRED_SIZE     400             /* this size is excessive */
65
66 #define SVC_VERSQUIET 0x0001            /* keep quiet about vers mismatch */
67 #define version_keepquiet(xp) ((u_long)(xp)->xp_p3 & SVC_VERSQUIET)
68
69 #define max(a, b) (a > b ? a : b)
70
71 /*
72  * The services list
73  * Each entry represents a set of procedures (an rpc program).
74  * The dispatch routine takes request structs and runs the
75  * apropriate procedure.
76  */
77 static struct svc_callout {
78         struct svc_callout *sc_next;
79         rpcprog_t           sc_prog;
80         rpcvers_t           sc_vers;
81         char               *sc_netid;
82         void                (*sc_dispatch)(struct svc_req *, SVCXPRT *);
83 } *svc_head;
84
85 static struct svc_callout *svc_find(rpcprog_t, rpcvers_t,
86     struct svc_callout **, char *);
87 static void __xprt_do_unregister (SVCXPRT *xprt, bool_t dolock);
88
89 /* ***************  SVCXPRT related stuff **************** */
90
91 /*
92  * Activate a transport handle.
93  */
94 void
95 xprt_register(SVCXPRT *xprt)
96 {
97         int sock;
98
99         assert(xprt != NULL);
100
101         sock = xprt->xp_fd;
102
103         rwlock_wrlock(&svc_fd_lock);
104         if (__svc_xports == NULL) {
105                 __svc_xports = (SVCXPRT **)
106                         mem_alloc(FD_SETSIZE * sizeof(SVCXPRT *));
107                 if (__svc_xports == NULL)
108                         return;
109                 memset(__svc_xports, '\0', FD_SETSIZE * sizeof(SVCXPRT *));
110         }
111         if (sock < FD_SETSIZE) {
112                 __svc_xports[sock] = xprt;
113                 FD_SET(sock, &svc_fdset);
114                 svc_maxfd = max(svc_maxfd, sock);
115         }
116         rwlock_unlock(&svc_fd_lock);
117 }
118
119 void
120 xprt_unregister(SVCXPRT *xprt)
121 {
122         __xprt_do_unregister(xprt, TRUE);
123 }
124
125 void
126 __xprt_unregister_unlocked(SVCXPRT *xprt)
127 {
128         __xprt_do_unregister(xprt, FALSE);
129 }
130
131 /*
132  * De-activate a transport handle.
133  */
134 static void
135 __xprt_do_unregister(SVCXPRT *xprt, bool_t dolock)
136 {
137         int sock;
138
139         assert(xprt != NULL);
140
141         sock = xprt->xp_fd;
142
143         if (dolock)
144                 rwlock_wrlock(&svc_fd_lock);
145         if ((sock < FD_SETSIZE) && (__svc_xports[sock] == xprt)) {
146                 __svc_xports[sock] = NULL;
147                 FD_CLR(sock, &svc_fdset);
148                 if (sock >= svc_maxfd) {
149                         for (svc_maxfd--; svc_maxfd>=0; svc_maxfd--)
150                                 if (__svc_xports[svc_maxfd])
151                                         break;
152                 }
153         }
154         if (dolock)
155                 rwlock_unlock(&svc_fd_lock);
156 }
157
158 /*
159  * Add a service program to the callout list.
160  * The dispatch routine will be called when a rpc request for this
161  * program number comes in.
162  */
163 bool_t
164 svc_reg(SVCXPRT *xprt, const rpcprog_t prog, const rpcvers_t vers,
165         void (*dispatch)(struct svc_req *, SVCXPRT *),
166         const struct netconfig *nconf)
167 {
168         bool_t dummy;
169         struct svc_callout *prev;
170         struct svc_callout *s;
171         struct netconfig *tnconf;
172         char *netid = NULL;
173         int flag = 0;
174
175 /* VARIABLES PROTECTED BY svc_lock: s, prev, svc_head */
176
177         if (xprt->xp_netid) {
178                 netid = strdup(xprt->xp_netid);
179                 flag = 1;
180         } else if (nconf && nconf->nc_netid) {
181                 netid = strdup(nconf->nc_netid);
182                 flag = 1;
183         } else if ((tnconf = __rpcgettp(xprt->xp_fd)) != NULL) {
184                 netid = strdup(tnconf->nc_netid);
185                 flag = 1;
186                 freenetconfigent(tnconf);
187         } /* must have been created with svc_raw_create */
188         if ((netid == NULL) && (flag == 1)) {
189                 return (FALSE);
190         }
191
192         rwlock_wrlock(&svc_lock);
193         if ((s = svc_find(prog, vers, &prev, netid)) != NULL) {
194                 if (netid)
195                         free(netid);
196                 if (s->sc_dispatch == dispatch)
197                         goto rpcb_it; /* he is registering another xptr */
198                 rwlock_unlock(&svc_lock);
199                 return (FALSE);
200         }
201         s = mem_alloc(sizeof (struct svc_callout));
202         if (s == NULL) {
203                 if (netid)
204                         free(netid);
205                 rwlock_unlock(&svc_lock);
206                 return (FALSE);
207         }
208
209         s->sc_prog = prog;
210         s->sc_vers = vers;
211         s->sc_dispatch = dispatch;
212         s->sc_netid = netid;
213         s->sc_next = svc_head;
214         svc_head = s;
215
216         if ((xprt->xp_netid == NULL) && (flag == 1) && netid)
217                 ((SVCXPRT *) xprt)->xp_netid = strdup(netid);
218
219 rpcb_it:
220         rwlock_unlock(&svc_lock);
221         /* now register the information with the local binder service */
222         if (nconf) {
223                 /*LINTED const castaway*/
224                 dummy = rpcb_set(prog, vers, (struct netconfig *) nconf,
225                 &((SVCXPRT *) xprt)->xp_ltaddr);
226                 return (dummy);
227         }
228         return (TRUE);
229 }
230
231 /*
232  * Remove a service program from the callout list.
233  */
234 void
235 svc_unreg(const rpcprog_t prog, const rpcvers_t vers)
236 {
237         struct svc_callout *prev;
238         struct svc_callout *s;
239
240         /* unregister the information anyway */
241         rpcb_unset(prog, vers, NULL);
242         rwlock_wrlock(&svc_lock);
243         while ((s = svc_find(prog, vers, &prev, NULL)) != NULL) {
244                 if (prev == NULL) {
245                         svc_head = s->sc_next;
246                 } else {
247                         prev->sc_next = s->sc_next;
248                 }
249                 s->sc_next = NULL;
250                 if (s->sc_netid)
251                         mem_free(s->sc_netid, sizeof (s->sc_netid) + 1);
252                 mem_free(s, sizeof (struct svc_callout));
253         }
254         rwlock_unlock(&svc_lock);
255 }
256
257 /* ********************** CALLOUT list related stuff ************* */
258
259 #ifdef PORTMAP
260 /*
261  * Add a service program to the callout list.
262  * The dispatch routine will be called when a rpc request for this
263  * program number comes in.
264  */
265 bool_t
266 svc_register(SVCXPRT *xprt, u_long prog, u_long vers,
267              void (*dispatch)(struct svc_req *, SVCXPRT *), int protocol)
268 {
269         struct svc_callout *prev;
270         struct svc_callout *s;
271
272         assert(xprt != NULL);
273         assert(dispatch != NULL);
274
275         if ((s = svc_find((rpcprog_t)prog, (rpcvers_t)vers, &prev, NULL)) !=
276             NULL) {
277                 if (s->sc_dispatch == dispatch)
278                         goto pmap_it;  /* he is registering another xptr */
279                 return (FALSE);
280         }
281         s = mem_alloc(sizeof(struct svc_callout));
282         if (s == NULL) {
283                 return (FALSE);
284         }
285         s->sc_prog = (rpcprog_t)prog;
286         s->sc_vers = (rpcvers_t)vers;
287         s->sc_dispatch = dispatch;
288         s->sc_next = svc_head;
289         svc_head = s;
290 pmap_it:
291         /* now register the information with the local binder service */
292         if (protocol) {
293                 return (pmap_set(prog, vers, protocol, xprt->xp_port));
294         }
295         return (TRUE);
296 }
297
298 /*
299  * Remove a service program from the callout list.
300  */
301 void
302 svc_unregister(u_long prog, u_long vers)
303 {
304         struct svc_callout *prev;
305         struct svc_callout *s;
306
307         if ((s = svc_find((rpcprog_t)prog, (rpcvers_t)vers, &prev, NULL)) ==
308             NULL)
309                 return;
310         if (prev == NULL) {
311                 svc_head = s->sc_next;
312         } else {
313                 prev->sc_next = s->sc_next;
314         }
315         s->sc_next = NULL;
316         mem_free(s, sizeof(struct svc_callout));
317         /* now unregister the information with the local binder service */
318         pmap_unset(prog, vers);
319 }
320 #endif                          /* PORTMAP */
321
322 /*
323  * Search the callout list for a program number, return the callout
324  * struct.
325  */
326 static struct svc_callout *
327 svc_find(rpcprog_t prog, rpcvers_t vers, struct svc_callout **prev, char *netid)
328 {
329         struct svc_callout *s, *p;
330
331         assert(prev != NULL);
332
333         p = NULL;
334         for (s = svc_head; s != NULL; s = s->sc_next) {
335                 if (((s->sc_prog == prog) && (s->sc_vers == vers)) &&
336                     ((netid == NULL) || (s->sc_netid == NULL) ||
337                     (strcmp(netid, s->sc_netid) == 0)))
338                         break;
339                 p = s;
340         }
341         *prev = p;
342         return (s);
343 }
344
345 /* ******************* REPLY GENERATION ROUTINES  ************ */
346
347 /*
348  * Send a reply to an rpc request
349  */
350 bool_t
351 svc_sendreply(SVCXPRT *xprt, xdrproc_t xdr_results, void *xdr_location)
352 {
353         struct rpc_msg rply;
354
355         assert(xprt != NULL);
356
357         rply.rm_direction = REPLY;
358         rply.rm_reply.rp_stat = MSG_ACCEPTED;
359         rply.acpted_rply.ar_verf = xprt->xp_verf;
360         rply.acpted_rply.ar_stat = SUCCESS;
361         rply.acpted_rply.ar_results.where = xdr_location;
362         rply.acpted_rply.ar_results.proc = xdr_results;
363         return (SVC_REPLY(xprt, &rply));
364 }
365
366 /*
367  * No procedure error reply
368  */
369 void
370 svcerr_noproc(SVCXPRT *xprt)
371 {
372         struct rpc_msg rply;
373
374         assert(xprt != NULL);
375
376         rply.rm_direction = REPLY;
377         rply.rm_reply.rp_stat = MSG_ACCEPTED;
378         rply.acpted_rply.ar_verf = xprt->xp_verf;
379         rply.acpted_rply.ar_stat = PROC_UNAVAIL;
380         SVC_REPLY(xprt, &rply);
381 }
382
383 /*
384  * Can't decode args error reply
385  */
386 void
387 svcerr_decode(SVCXPRT *xprt)
388 {
389         struct rpc_msg rply;
390
391         assert(xprt != NULL);
392
393         rply.rm_direction = REPLY;
394         rply.rm_reply.rp_stat = MSG_ACCEPTED;
395         rply.acpted_rply.ar_verf = xprt->xp_verf;
396         rply.acpted_rply.ar_stat = GARBAGE_ARGS;
397         SVC_REPLY(xprt, &rply);
398 }
399
400 /*
401  * Some system error
402  */
403 void
404 svcerr_systemerr(SVCXPRT *xprt)
405 {
406         struct rpc_msg rply;
407
408         assert(xprt != NULL);
409
410         rply.rm_direction = REPLY;
411         rply.rm_reply.rp_stat = MSG_ACCEPTED;
412         rply.acpted_rply.ar_verf = xprt->xp_verf;
413         rply.acpted_rply.ar_stat = SYSTEM_ERR;
414         SVC_REPLY(xprt, &rply);
415 }
416
417 /*
418  * Authentication error reply
419  */
420 void
421 svcerr_auth(SVCXPRT *xprt, enum auth_stat why)
422 {
423         struct rpc_msg rply;
424
425         assert(xprt != NULL);
426
427         rply.rm_direction = REPLY;
428         rply.rm_reply.rp_stat = MSG_DENIED;
429         rply.rjcted_rply.rj_stat = AUTH_ERROR;
430         rply.rjcted_rply.rj_why = why;
431         SVC_REPLY(xprt, &rply);
432 }
433
434 /*
435  * Auth too weak error reply
436  */
437 void
438 svcerr_weakauth(SVCXPRT *xprt)
439 {
440
441         assert(xprt != NULL);
442
443         svcerr_auth(xprt, AUTH_TOOWEAK);
444 }
445
446 /*
447  * Program unavailable error reply
448  */
449 void
450 svcerr_noprog(SVCXPRT *xprt)
451 {
452         struct rpc_msg rply;
453
454         assert(xprt != NULL);
455
456         rply.rm_direction = REPLY;
457         rply.rm_reply.rp_stat = MSG_ACCEPTED;
458         rply.acpted_rply.ar_verf = xprt->xp_verf;
459         rply.acpted_rply.ar_stat = PROG_UNAVAIL;
460         SVC_REPLY(xprt, &rply);
461 }
462
463 /*
464  * Program version mismatch error reply
465  */
466 void
467 svcerr_progvers(SVCXPRT *xprt, rpcvers_t low_vers, rpcvers_t high_vers)
468 {
469         struct rpc_msg rply;
470
471         assert(xprt != NULL);
472
473         rply.rm_direction = REPLY;
474         rply.rm_reply.rp_stat = MSG_ACCEPTED;
475         rply.acpted_rply.ar_verf = xprt->xp_verf;
476         rply.acpted_rply.ar_stat = PROG_MISMATCH;
477         rply.acpted_rply.ar_vers.low = (u_int32_t)low_vers;
478         rply.acpted_rply.ar_vers.high = (u_int32_t)high_vers;
479         SVC_REPLY(xprt, &rply);
480 }
481
482 /* ******************* SERVER INPUT STUFF ******************* */
483
484 /*
485  * Get server side input from some transport.
486  *
487  * Statement of authentication parameters management:
488  * This function owns and manages all authentication parameters, specifically
489  * the "raw" parameters (msg.rm_call.cb_cred and msg.rm_call.cb_verf) and
490  * the "cooked" credentials (rqst->rq_clntcred).
491  * However, this function does not know the structure of the cooked
492  * credentials, so it make the following assumptions:
493  *   a) the structure is contiguous (no pointers), and
494  *   b) the cred structure size does not exceed RQCRED_SIZE bytes.
495  * In all events, all three parameters are freed upon exit from this routine.
496  * The storage is trivially management on the call stack in user land, but
497  * is mallocated in kernel land.
498  */
499
500 void
501 svc_getreq(int rdfds)
502 {
503         fd_set readfds;
504
505         FD_ZERO(&readfds);
506         readfds.fds_bits[0] = rdfds;
507         svc_getreqset(&readfds);
508 }
509
510 void
511 svc_getreqset(fd_set *readfds)
512 {
513         int bit, fd;
514         fd_mask mask, *maskp;
515         int sock;
516
517         assert(readfds != NULL);
518
519         maskp = readfds->fds_bits;
520         for (sock = 0; sock < FD_SETSIZE; sock += NFDBITS) {
521             for (mask = *maskp++; (bit = ffs(mask)) != 0;
522                 mask ^= (1 << (bit - 1))) {
523                 /* sock has input waiting */
524                 fd = sock + bit - 1;
525                 svc_getreq_common(fd);
526             }
527         }
528 }
529
530 void
531 svc_getreq_common(int fd)
532 {
533         SVCXPRT *xprt;
534         struct svc_req r;
535         struct rpc_msg msg;
536         int prog_found;
537         rpcvers_t low_vers;
538         rpcvers_t high_vers;
539         enum xprt_stat stat;
540         char cred_area[2*MAX_AUTH_BYTES + RQCRED_SIZE];
541
542         msg.rm_call.cb_cred.oa_base = cred_area;
543         msg.rm_call.cb_verf.oa_base = &(cred_area[MAX_AUTH_BYTES]);
544         r.rq_clntcred = &(cred_area[2*MAX_AUTH_BYTES]);
545
546         rwlock_rdlock(&svc_fd_lock);
547         xprt = __svc_xports[fd];
548         rwlock_unlock(&svc_fd_lock);
549         if (xprt == NULL)
550                 /* But do we control sock? */
551                 return;
552         /* now receive msgs from xprtprt (support batch calls) */
553         do {
554                 if (SVC_RECV(xprt, &msg)) {
555
556                         /* now find the exported program and call it */
557                         struct svc_callout *s;
558                         enum auth_stat why;
559
560                         r.rq_xprt = xprt;
561                         r.rq_prog = msg.rm_call.cb_prog;
562                         r.rq_vers = msg.rm_call.cb_vers;
563                         r.rq_proc = msg.rm_call.cb_proc;
564                         r.rq_cred = msg.rm_call.cb_cred;
565                         /* first authenticate the message */
566                         if ((why = _authenticate(&r, &msg)) != AUTH_OK) {
567                                 svcerr_auth(xprt, why);
568                                 goto call_done;
569                         }
570                         /* now match message with a registered service*/
571                         prog_found = FALSE;
572                         low_vers = (rpcvers_t) -1L;
573                         high_vers = (rpcvers_t) 0L;
574                         for (s = svc_head; s != NULL; s = s->sc_next) {
575                                 if (s->sc_prog == r.rq_prog) {
576                                         if (s->sc_vers == r.rq_vers) {
577                                                 (*s->sc_dispatch)(&r, xprt);
578                                                 goto call_done;
579                                         }  /* found correct version */
580                                         prog_found = TRUE;
581                                         if (s->sc_vers < low_vers)
582                                                 low_vers = s->sc_vers;
583                                         if (s->sc_vers > high_vers)
584                                                 high_vers = s->sc_vers;
585                                 }   /* found correct program */
586                         }
587                         /*
588                          * if we got here, the program or version
589                          * is not served ...
590                          */
591                         if (prog_found)
592                                 svcerr_progvers(xprt, low_vers, high_vers);
593                         else
594                                  svcerr_noprog(xprt);
595                         /* Fall through to ... */
596                 }
597                 /*
598                  * Check if the xprt has been disconnected in a
599                  * recursive call in the service dispatch routine.
600                  * If so, then break.
601                  */
602                 rwlock_rdlock(&svc_fd_lock);
603                 if (xprt != __svc_xports[fd]) {
604                         rwlock_unlock(&svc_fd_lock);
605                         break;
606                 }
607                 rwlock_unlock(&svc_fd_lock);
608 call_done:
609                 if ((stat = SVC_STAT(xprt)) == XPRT_DIED){
610                         SVC_DESTROY(xprt);
611                         break;
612                 }
613         } while (stat == XPRT_MOREREQS);
614 }
615
616
617 void
618 svc_getreq_poll(struct pollfd *pfdp, int pollretval)
619 {
620         int i;
621         int fds_found;
622
623         for (i = fds_found = 0; fds_found < pollretval; i++) {
624                 struct pollfd *p = &pfdp[i];
625
626                 if (p->revents) {
627                         /* fd has input waiting */
628                         fds_found++;
629                         /*
630                          *      We assume that this function is only called
631                          *      via someone _select()ing from svc_fdset or
632                          *      _poll()ing from svc_pollset[].  Thus it's safe
633                          *      to handle the POLLNVAL event by simply turning
634                          *      the corresponding bit off in svc_fdset.  The
635                          *      svc_pollset[] array is derived from svc_fdset
636                          *      and so will also be updated eventually.
637                          *
638                          *      XXX Should we do an xprt_unregister() instead?
639                          */
640                         if (p->revents & POLLNVAL) {
641                                 rwlock_wrlock(&svc_fd_lock);
642                                 FD_CLR(p->fd, &svc_fdset);
643                                 rwlock_unlock(&svc_fd_lock);
644                         } else
645                                 svc_getreq_common(p->fd);
646                 }
647         }
648 }
649
650 bool_t
651 rpc_control(int what, void *arg)
652 {
653         int val;
654
655         switch (what) {
656         case RPC_SVC_CONNMAXREC_SET:
657                 val = *(int *)arg;
658                 if (val <= 0)
659                         return FALSE;
660                 __svc_maxrec = val;
661                 return TRUE;
662         case RPC_SVC_CONNMAXREC_GET:
663                 *(int *)arg = __svc_maxrec;
664                 return TRUE;
665         default:
666                 break;
667         }
668         return FALSE;
669 }