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

Last change on this file since 491b62fd was 491b62fd, checked in by Till Straumann <strauman@…>, on 12/09/05 at 22:47:48

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