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

4.104.114.84.9
Last change on this file since df49c60 was df49c60, checked in by Joel Sherrill <joel.sherrill@…>, on Jun 12, 2000 at 3:00:15 PM

Merged from 4.5.0-beta3a

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