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

4.104.115
Last change on this file since 1cdd06ac was 3c412d9, checked in by Ralf Corsepius <ralf.corsepius@…>, on 08/01/08 at 06:25:15

Add missing prototypes.

  • Property mode set to 100644
File size: 12.0 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(struct svc_req *rqstp, SVCXPRT *xprt);
43static void callit(struct svc_req *rqstp, SVCXPRT *xprt);
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        u_int temp_epp_arglen = epp->arglen;
320        return (xdr_bytes(xdrs, &(epp->args), &temp_epp_arglen, ARGSIZE));
321}
322
323struct rmtcallargs {
324        u_long  rmt_prog;
325        u_long  rmt_vers;
326        u_long  rmt_port;
327        u_long  rmt_proc;
328        struct encap_parms rmt_args;
329};
330
331static bool_t
332xdr_rmtcall_args(
333        register XDR *xdrs,
334        register struct rmtcallargs *cap )
335{
336
337        /* does not get a port number */
338        if (xdr_u_long(xdrs, &(cap->rmt_prog)) &&
339            xdr_u_long(xdrs, &(cap->rmt_vers)) &&
340            xdr_u_long(xdrs, &(cap->rmt_proc))) {
341                return (xdr_encap_parms(xdrs, &(cap->rmt_args)));
342        }
343        return (FALSE);
344}
345
346static bool_t
347xdr_rmtcall_result(
348        register XDR *xdrs,
349        register struct rmtcallargs *cap )
350{
351        if (xdr_u_long(xdrs, &(cap->rmt_port)))
352                return (xdr_encap_parms(xdrs, &(cap->rmt_args)));
353        return (FALSE);
354}
355
356/*
357 * only worries about the struct encap_parms part of struct rmtcallargs.
358 * The arglen must already be set!!
359 */
360static bool_t
361xdr_opaque_parms(
362        XDR *xdrs,
363        struct rmtcallargs *cap )
364{
365
366        return (xdr_opaque(xdrs, cap->rmt_args.args, cap->rmt_args.arglen));
367}
368
369/*
370 * This routine finds and sets the length of incoming opaque paraters
371 * and then calls xdr_opaque_parms.
372 */
373static bool_t
374xdr_len_opaque_parms(
375        register XDR *xdrs,
376        struct rmtcallargs *cap )
377{
378        register u_int beginpos, lowpos, highpos, currpos, pos;
379
380        beginpos = lowpos = pos = xdr_getpos(xdrs);
381        highpos = lowpos + ARGSIZE;
382        while ((int)(highpos - lowpos) >= 0) {
383                currpos = (lowpos + highpos) / 2;
384                if (xdr_setpos(xdrs, currpos)) {
385                        pos = currpos;
386                        lowpos = currpos + 1;
387                } else {
388                        highpos = currpos - 1;
389                }
390        }
391        xdr_setpos(xdrs, beginpos);
392        cap->rmt_args.arglen = pos - beginpos;
393        return (xdr_opaque_parms(xdrs, cap));
394}
395
396/*
397 * Call a remote procedure service
398 * This procedure is very quiet when things go wrong.
399 * The proc is written to support broadcast rpc.  In the broadcast case,
400 * a machine should shut-up instead of complain, less the requestor be
401 * overrun with complaints at the expense of not hearing a valid reply ...
402 *
403 * This now forks so that the program & process that it calls can call
404 * back to the portmapper.
405 */
406static void
407callit(
408        struct svc_req *rqstp,
409        SVCXPRT *xprt )
410{
411        struct rmtcallargs a;
412        struct pmaplist *pml;
413        u_short port;
414        struct sockaddr_in me;
415        int pid, socket = -1;
416        CLIENT *client;
417        struct authunix_parms *au = (struct authunix_parms *)rqstp->rq_clntcred;
418        struct timeval timeout;
419        char buf[ARGSIZE];
420
421        timeout.tv_sec = 5;
422        timeout.tv_usec = 0;
423        a.rmt_args.args = buf;
424        if (!svc_getargs(xprt, (xdrproc_t) xdr_rmtcall_args, (caddr_t)&a))
425            return;
426        if ((pml = find_service(a.rmt_prog, a.rmt_vers, IPPROTO_UDP)) == NULL)
427            return;
428        /*
429         * fork a child to do the work.  Parent immediately returns.
430         * Child exits upon completion.
431         */
432        if ((pid = fork()) != 0) {
433                if (debugging && (pid < 0)) {
434                        fprintf(stderr, "portmap CALLIT: cannot fork.\n");
435                }
436                return;
437        }
438        port = pml->pml_map.pm_port;
439        get_myaddress(&me);
440        me.sin_port = htons(port);
441        client = clntudp_create(&me, a.rmt_prog, a.rmt_vers, timeout, &socket);
442        if (client != (CLIENT *)NULL) {
443                if (rqstp->rq_cred.oa_flavor == AUTH_UNIX) {
444                        client->cl_auth = authunix_create(au->aup_machname,
445                           au->aup_uid, au->aup_gid, au->aup_len, au->aup_gids);
446                }
447                a.rmt_port = (u_long)port;
448                if (clnt_call(client, a.rmt_proc, xdr_opaque_parms, &a,
449                    xdr_len_opaque_parms, &a, timeout) == RPC_SUCCESS) {
450                        svc_sendreply(xprt, (xdrproc_t) xdr_rmtcall_result, (caddr_t)&a);
451                }
452                AUTH_DESTROY(client->cl_auth);
453                clnt_destroy(client);
454        }
455        (void)close(socket);
456        exit(0);
457}
458
459/*
460 * Start the RPC portmapper
461 */
462int rtems_rpc_start_portmapper (int priority)
463{
464        rtems_mode mode;
465        rtems_status_code sc;
466        rtems_id tid;
467        static int started;
468
469        rtems_task_mode (RTEMS_NO_PREEMPT, RTEMS_PREEMPT_MASK, &mode);
470        if (started) {
471                rtems_task_mode (mode, RTEMS_PREEMPT_MASK, &mode);
472                return RTEMS_SUCCESSFUL;
473        }
474        sc = rtems_task_create (rtems_build_name('P', 'M', 'A', 'P'),
475                priority,
476                ARGSIZE + 8000,
477                RTEMS_PREEMPT|RTEMS_NO_TIMESLICE|RTEMS_NO_ASR|RTEMS_INTERRUPT_LEVEL(0),
478                RTEMS_NO_FLOATING_POINT|RTEMS_LOCAL,
479                &tid);
480        if (sc != RTEMS_SUCCESSFUL) {
481                rtems_task_mode (mode, RTEMS_PREEMPT_MASK, &mode);
482                return sc;
483        }
484        sc = rtems_task_start (tid, rtems_portmapper, 0);
485        if (sc != RTEMS_SUCCESSFUL) {
486                rtems_task_mode (mode, RTEMS_PREEMPT_MASK, &mode);
487                return sc;
488        }
489        started = 1;
490        rtems_task_mode (mode, RTEMS_PREEMPT_MASK, &mode);
491        return RTEMS_SUCCESSFUL;
492}
Note: See TracBrowser for help on using the repository browser.