source: rtems/cpukit/librpc/src/rpc/rtems_portmapper.c @ bc26d607

4.104.115
Last change on this file since bc26d607 was 9363800c, checked in by Ralf Corsepius <ralf.corsepius@…>, on 05/27/10 at 07:37:32

2010-05-27 Ralf Corsépius <ralf.corsepius@…>

  • librpc/src/rpc/rtems_portmapper.c: Reflect changes to librpc.
  • Property mode set to 100644
File size: 12.1 KB
Line 
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
30#ifdef HAVE_CONFIG_H
31#include "config.h"
32#endif
33
34#include <rpc/rpc.h>
35#include <rpc/pmap_prot.h>
36#include <stdio.h>
37#include <stdlib.h>
38#include <unistd.h>
39#include <malloc.h>
40#include <netdb.h>
41#include <sys/socket.h>
42#include <sys/ioctl.h>
43#include <sys/wait.h>
44#include <sys/signal.h>
45
46static void reg_service(struct svc_req *rqstp, SVCXPRT *xprt);
47static void callit(struct svc_req *rqstp, SVCXPRT *xprt);
48static struct pmaplist *pmaplist;
49static int debugging = 0;
50
51#include <rtems.h>
52#define fork()  (-1)
53
54
55static rtems_task rtems_portmapper (rtems_task_argument unused)
56{
57        SVCXPRT *xprt;
58        int sock;
59        struct sockaddr_in addr;
60        int len = sizeof(struct sockaddr_in);
61        register struct pmaplist *pml;
62
63        rtems_rpc_task_init ();
64        if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
65                perror("portmap cannot create socket");
66                rtems_task_delete (RTEMS_SELF);
67        }
68
69        addr.sin_addr.s_addr = 0;
70        addr.sin_family = AF_INET;
71        addr.sin_port = htons(PMAPPORT);
72        if (bind(sock, (struct sockaddr *)&addr, len) != 0) {
73                perror("portmap cannot bind");
74                close (sock);
75                rtems_task_delete (RTEMS_SELF);
76        }
77
78        if ((xprt = svcudp_create(sock)) == (SVCXPRT *)NULL) {
79                fprintf(stderr, "couldn't do udp_create\n");
80                close (sock);
81                rtems_task_delete (RTEMS_SELF);
82        }
83        /* make an entry for ourself */
84        pml = (struct pmaplist *)malloc(sizeof(struct pmaplist));
85        pml->pml_next = 0;
86        pml->pml_map.pm_prog = PMAPPROG;
87        pml->pml_map.pm_vers = PMAPVERS;
88        pml->pml_map.pm_prot = IPPROTO_UDP;
89        pml->pml_map.pm_port = PMAPPORT;
90        pmaplist = pml;
91
92        if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
93                perror("portmap cannot create socket");
94                close (sock);
95                rtems_task_delete (RTEMS_SELF);
96        }
97        if (bind(sock, (struct sockaddr *)&addr, len) != 0) {
98                perror("portmap cannot bind");
99                close (sock);
100                rtems_task_delete (RTEMS_SELF);
101        }
102        if ((xprt = svctcp_create(sock, RPCSMALLMSGSIZE, RPCSMALLMSGSIZE))
103            == (SVCXPRT *)NULL) {
104                fprintf(stderr, "couldn't do tcp_create\n");
105                close (sock);
106                rtems_task_delete (RTEMS_SELF);
107        }
108        /* make an entry for ourself */
109        pml = (struct pmaplist *)malloc(sizeof(struct pmaplist));
110        pml->pml_map.pm_prog = PMAPPROG;
111        pml->pml_map.pm_vers = PMAPVERS;
112        pml->pml_map.pm_prot = IPPROTO_TCP;
113        pml->pml_map.pm_port = PMAPPORT;
114        pml->pml_next = pmaplist;
115        pmaplist = pml;
116
117        (void)svc_register(xprt, PMAPPROG, PMAPVERS, reg_service, FALSE);
118
119        svc_run();
120        fprintf(stderr, "run_svc returned unexpectedly\n");
121        close (sock);
122        rtems_task_delete (RTEMS_SELF);
123}
124
125static struct pmaplist *
126find_service(
127  u_long prog,
128  u_long vers,
129  int prot )
130{
131  register struct pmaplist *hit = NULL;
132  register struct pmaplist *pml;
133
134  for (pml = pmaplist; pml != NULL; pml = pml->pml_next) {
135        if ((pml->pml_map.pm_prog != prog) ||
136                (pml->pml_map.pm_prot != prot))
137                continue;
138        hit = pml;
139        if (pml->pml_map.pm_vers == vers)
140            break;
141  }
142  return (hit);
143}
144
145/*
146 * 1 OK, 0 not
147 */
148static void reg_service(
149        struct svc_req *rqstp,
150        SVCXPRT *xprt )
151{
152        struct pmap reg;
153        struct pmaplist *pml, *prevpml, *fnd;
154        int ans, port;
155        caddr_t t;
156       
157#ifdef DEBUG
158        fprintf(stderr, "server: about do a switch\n");
159#endif
160        switch (rqstp->rq_proc) {
161
162        case PMAPPROC_NULL:
163                /*
164                 * Null proc call
165                 */
166                if ((!svc_sendreply(xprt, (xdrproc_t) xdr_void, NULL)) &&
167                     debugging) {
168                        abort();
169                }
170                break;
171
172        case PMAPPROC_SET:
173                /*
174                 * Set a program,version to port mapping
175                 */
176                if (!svc_getargs(xprt, (xdrproc_t) xdr_pmap, (caddr_t)&reg))
177                        svcerr_decode(xprt);
178                else {
179                        /*
180                         * check to see if already used
181                         * find_service returns a hit even if
182                         * the versions don't match, so check for it
183                         */
184                        fnd = find_service(reg.pm_prog, reg.pm_vers, reg.pm_prot);
185                        if (fnd && fnd->pml_map.pm_vers == reg.pm_vers) {
186                                if (fnd->pml_map.pm_port == reg.pm_port) {
187                                        ans = 1;
188                                        goto done;
189                                }
190                                else {
191                                        ans = 0;
192                                        goto done;
193                                }
194                        } else {
195                                /*
196                                 * add to END of list
197                                 */
198                                pml = (struct pmaplist *)
199                                    malloc(sizeof(struct pmaplist));
200                                pml->pml_map = reg;
201                                pml->pml_next = 0;
202                                if (pmaplist == 0) {
203                                        pmaplist = pml;
204                                } else {
205                                        for (fnd= pmaplist; fnd->pml_next != 0;
206                                            fnd = fnd->pml_next);
207                                        fnd->pml_next = pml;
208                                }
209                                ans = 1;
210                        }
211                done:
212                        if ((!svc_sendreply(xprt, (xdrproc_t) xdr_long, (caddr_t)&ans)) &&
213                            debugging) {
214                                fprintf(stderr, "svc_sendreply\n");
215                                abort();
216                        }
217                }
218                break;
219
220        case PMAPPROC_UNSET:
221                /*
222                 * Remove a program,version to port mapping.
223                 */
224                if (!svc_getargs(xprt, (xdrproc_t) xdr_pmap, (caddr_t)&reg))
225                        svcerr_decode(xprt);
226                else {
227                        ans = 0;
228                        for (prevpml = NULL, pml = pmaplist; pml != NULL; ) {
229                                if ((pml->pml_map.pm_prog != reg.pm_prog) ||
230                                        (pml->pml_map.pm_vers != reg.pm_vers)) {
231                                        /* both pml & prevpml move forwards */
232                                        prevpml = pml;
233                                        pml = pml->pml_next;
234                                        continue;
235                                }
236                                /* found it; pml moves forward, prevpml stays */
237                                ans = 1;
238                                t = (caddr_t)pml;
239                                pml = pml->pml_next;
240                                if (prevpml == NULL)
241                                        pmaplist = pml;
242                                else
243                                        prevpml->pml_next = pml;
244                                free(t);
245                        }
246                        if ((!svc_sendreply(xprt, (xdrproc_t) xdr_long, (caddr_t)&ans)) &&
247                            debugging) {
248                                fprintf(stderr, "svc_sendreply\n");
249                                abort();
250                        }
251                }
252                break;
253
254        case PMAPPROC_GETPORT:
255                /*
256                 * Lookup the mapping for a program,version and return its port
257                 */
258                if (!svc_getargs(xprt, (xdrproc_t) xdr_pmap, (caddr_t)&reg))
259                        svcerr_decode(xprt);
260                else {
261                        fnd = find_service(reg.pm_prog, reg.pm_vers, reg.pm_prot);
262                        if (fnd)
263                                port = fnd->pml_map.pm_port;
264                        else
265                                port = 0;
266                        if ((!svc_sendreply(xprt, (xdrproc_t) xdr_long, (caddr_t)&port)) &&
267                            debugging) {
268                                fprintf(stderr, "svc_sendreply\n");
269                                abort();
270                        }
271                }
272                break;
273
274        case PMAPPROC_DUMP:
275                /*
276                 * Return the current set of mapped program,version
277                 */
278                if (!svc_getargs(xprt, (xdrproc_t) xdr_void, NULL))
279                        svcerr_decode(xprt);
280                else {
281                        if ((!svc_sendreply(xprt, (xdrproc_t) xdr_pmaplist,
282                            (caddr_t)&pmaplist)) && debugging) {
283                                fprintf(stderr, "svc_sendreply\n");
284                                abort();
285                        }
286                }
287                break;
288
289        case PMAPPROC_CALLIT:
290                /*
291                 * Calls a procedure on the local machine.  If the requested
292                 * procedure is not registered this procedure does not return
293                 * error information!!
294                 * This procedure is only supported on rpc/udp and calls via
295                 * rpc/udp.  It passes null authentication parameters.
296                 */
297                callit(rqstp, xprt);
298                break;
299
300        default:
301                svcerr_noproc(xprt);
302                break;
303        }
304}
305
306
307/*
308 * Stuff for the rmtcall service
309 */
310#define ARGSIZE 9000
311
312struct encap_parms {
313        u_long arglen;
314        char *args;
315};
316
317static bool_t
318xdr_encap_parms(
319        XDR *xdrs,
320        struct encap_parms *epp )
321{
322
323        u_int temp_epp_arglen = epp->arglen;
324        return (xdr_bytes(xdrs, &(epp->args), &temp_epp_arglen, ARGSIZE));
325}
326
327struct rmtcallargs {
328        u_long  rmt_prog;
329        u_long  rmt_vers;
330        u_long  rmt_port;
331        u_long  rmt_proc;
332        struct encap_parms rmt_args;
333};
334
335static bool_t
336xdr_rmtcall_args(
337        register XDR *xdrs,
338        register struct rmtcallargs *cap )
339{
340
341        /* does not get a port number */
342        if (xdr_u_long(xdrs, &(cap->rmt_prog)) &&
343            xdr_u_long(xdrs, &(cap->rmt_vers)) &&
344            xdr_u_long(xdrs, &(cap->rmt_proc))) {
345                return (xdr_encap_parms(xdrs, &(cap->rmt_args)));
346        }
347        return (FALSE);
348}
349
350static bool_t
351xdr_rmtcall_result(
352        register XDR *xdrs,
353        register struct rmtcallargs *cap )
354{
355        if (xdr_u_long(xdrs, &(cap->rmt_port)))
356                return (xdr_encap_parms(xdrs, &(cap->rmt_args)));
357        return (FALSE);
358}
359
360/*
361 * only worries about the struct encap_parms part of struct rmtcallargs.
362 * The arglen must already be set!!
363 */
364static bool_t
365xdr_opaque_parms(
366        XDR *xdrs,
367        void *args,
368        ... )
369{
370        struct rmtcallargs *cap = (struct rmtcallargs *) args;
371
372        return (xdr_opaque(xdrs, cap->rmt_args.args, cap->rmt_args.arglen));
373}
374
375/*
376 * This routine finds and sets the length of incoming opaque paraters
377 * and then calls xdr_opaque_parms.
378 */
379static bool_t
380xdr_len_opaque_parms(
381        XDR *xdrs,
382        void *args,
383        ... )
384{
385        struct rmtcallargs *cap = (struct rmtcallargs *) args;
386        register u_int beginpos, lowpos, highpos, currpos, pos;
387
388        beginpos = lowpos = pos = xdr_getpos(xdrs);
389        highpos = lowpos + ARGSIZE;
390        while ((int)(highpos - lowpos) >= 0) {
391                currpos = (lowpos + highpos) / 2;
392                if (xdr_setpos(xdrs, currpos)) {
393                        pos = currpos;
394                        lowpos = currpos + 1;
395                } else {
396                        highpos = currpos - 1;
397                }
398        }
399        xdr_setpos(xdrs, beginpos);
400        cap->rmt_args.arglen = pos - beginpos;
401        return (xdr_opaque_parms(xdrs, cap));
402}
403
404/*
405 * Call a remote procedure service
406 * This procedure is very quiet when things go wrong.
407 * The proc is written to support broadcast rpc.  In the broadcast case,
408 * a machine should shut-up instead of complain, less the requestor be
409 * overrun with complaints at the expense of not hearing a valid reply ...
410 *
411 * This now forks so that the program & process that it calls can call
412 * back to the portmapper.
413 */
414static void
415callit(
416        struct svc_req *rqstp,
417        SVCXPRT *xprt )
418{
419        struct rmtcallargs a;
420        struct pmaplist *pml;
421        u_short port;
422        struct sockaddr_in me;
423        int pid, socket = -1;
424        CLIENT *client;
425        struct authunix_parms *au = (struct authunix_parms *)rqstp->rq_clntcred;
426        struct timeval timeout;
427        char buf[ARGSIZE];
428
429        timeout.tv_sec = 5;
430        timeout.tv_usec = 0;
431        a.rmt_args.args = buf;
432        if (!svc_getargs(xprt, (xdrproc_t) xdr_rmtcall_args, (caddr_t)&a))
433            return;
434        if ((pml = find_service(a.rmt_prog, a.rmt_vers, IPPROTO_UDP)) == NULL)
435            return;
436        /*
437         * fork a child to do the work.  Parent immediately returns.
438         * Child exits upon completion.
439         */
440        if ((pid = fork()) != 0) {
441                if (debugging && (pid < 0)) {
442                        fprintf(stderr, "portmap CALLIT: cannot fork.\n");
443                }
444                return;
445        }
446        port = pml->pml_map.pm_port;
447        get_myaddress(&me);
448        me.sin_port = htons(port);
449        client = clntudp_create(&me, a.rmt_prog, a.rmt_vers, timeout, &socket);
450        if (client != (CLIENT *)NULL) {
451                if (rqstp->rq_cred.oa_flavor == AUTH_UNIX) {
452                        client->cl_auth = authunix_create(au->aup_machname,
453                           au->aup_uid, au->aup_gid, au->aup_len, au->aup_gids);
454                }
455                a.rmt_port = (u_long)port;
456                if (clnt_call(client, a.rmt_proc, xdr_opaque_parms, &a,
457                    xdr_len_opaque_parms, &a, timeout) == RPC_SUCCESS) {
458                        svc_sendreply(xprt, (xdrproc_t) xdr_rmtcall_result, (caddr_t)&a);
459                }
460                AUTH_DESTROY(client->cl_auth);
461                clnt_destroy(client);
462        }
463        (void)close(socket);
464        exit(0);
465}
466
467/*
468 * Start the RPC portmapper
469 */
470int rtems_rpc_start_portmapper (int priority)
471{
472        rtems_mode mode;
473        rtems_status_code sc;
474        rtems_id tid;
475        static int started;
476
477        rtems_task_mode (RTEMS_NO_PREEMPT, RTEMS_PREEMPT_MASK, &mode);
478        if (started) {
479                rtems_task_mode (mode, RTEMS_PREEMPT_MASK, &mode);
480                return RTEMS_SUCCESSFUL;
481        }
482        sc = rtems_task_create (rtems_build_name('P', 'M', 'A', 'P'),
483                priority,
484                ARGSIZE + 8000,
485                RTEMS_PREEMPT|RTEMS_NO_TIMESLICE|RTEMS_NO_ASR|RTEMS_INTERRUPT_LEVEL(0),
486                RTEMS_NO_FLOATING_POINT|RTEMS_LOCAL,
487                &tid);
488        if (sc != RTEMS_SUCCESSFUL) {
489                rtems_task_mode (mode, RTEMS_PREEMPT_MASK, &mode);
490                return sc;
491        }
492        sc = rtems_task_start (tid, rtems_portmapper, 0);
493        if (sc != RTEMS_SUCCESSFUL) {
494                rtems_task_mode (mode, RTEMS_PREEMPT_MASK, &mode);
495                return sc;
496        }
497        started = 1;
498        rtems_task_mode (mode, RTEMS_PREEMPT_MASK, &mode);
499        return RTEMS_SUCCESSFUL;
500}
Note: See TracBrowser for help on using the repository browser.