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

4.104.114.84.95
Last change on this file since 39941915 was 39941915, checked in by Till Straumann <strauman@…>, on 12/09/05 at 22:43:14

2005-11-02 Till Straumann <strauman@…>

PR 849/networking

  • librpc/src/rpc/rtems_portmapper.c: Increased stack size

by ARGSIZE to prevent overrun.

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