entered into RCS
[kopensolaris-gnu/glibc.git] / sunrpc / portmap.c
1 /* @(#)portmap.c        2.3 88/08/11 4.0 RPCSRC */
2 #ifndef lint
3 static  char sccsid[] = "@(#)portmap.c 1.32 87/08/06 Copyr 1984 Sun Micro";
4 #endif
5
6 /*
7  * Copyright (c) 1984 by Sun Microsystems, Inc.
8  */
9
10 /*
11  * portmap.c, Implements the program,version to port number mapping for
12  * rpc.
13  */
14
15 /*
16  * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
17  * unrestricted use provided that this legend is included on all tape
18  * media and as a part of the software program in whole or part.  Users
19  * may copy or modify Sun RPC without charge, but are not authorized
20  * to license or distribute it to anyone else except as part of a product or
21  * program developed by the user.
22  * 
23  * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
24  * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
25  * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
26  * 
27  * Sun RPC is provided with no support and without any obligation on the
28  * part of Sun Microsystems, Inc. to assist in its use, correction,
29  * modification or enhancement.
30  * 
31  * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
32  * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
33  * OR ANY PART THEREOF.
34  * 
35  * In no event will Sun Microsystems, Inc. be liable for any lost revenue
36  * or profits or other special, indirect and consequential damages, even if
37  * Sun has been advised of the possibility of such damages.
38  * 
39  * Sun Microsystems, Inc.
40  * 2550 Garcia Avenue
41  * Mountain View, California  94043
42  */
43
44 #include <rpc/rpc.h>
45 #include <rpc/pmap_prot.h>
46 #include <stdio.h>
47 #include <netdb.h>
48 #include <sys/socket.h>
49 #include <sys/ioctl.h>
50 #include <sys/wait.h>
51 #include <sys/signal.h>
52
53 char *malloc();
54 int reg_service();
55 void reap();
56 struct pmaplist *pmaplist;
57 static int debugging = 0;
58
59 main()
60 {
61         SVCXPRT *xprt;
62         int sock, pid, t;
63         struct sockaddr_in addr;
64         int len = sizeof(struct sockaddr_in);
65         register struct pmaplist *pml;
66
67 #ifndef DEBUG
68         pid = fork();
69         if (pid < 0) {
70                 perror("portmap: fork");
71                 exit(1);
72         }
73         if (pid != 0)
74                 exit(0);
75         for (t = 0; t < 20; t++)
76                 close(t);
77         open("/", 0);
78         dup2(0, 1);
79         dup2(0, 2);
80         t = open("/dev/tty", 2);
81         if (t >= 0) {
82                 ioctl(t, TIOCNOTTY, (char *)0);
83                 close(t);
84         }
85 #endif
86         if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
87                 perror("portmap cannot create socket");
88                 exit(1);
89         }
90
91         addr.sin_addr.s_addr = 0;
92         addr.sin_family = AF_INET;
93         addr.sin_port = htons(PMAPPORT);
94         if (bind(sock, (struct sockaddr *)&addr, len) != 0) {
95                 perror("portmap cannot bind");
96                 exit(1);
97         }
98
99         if ((xprt = svcudp_create(sock)) == (SVCXPRT *)NULL) {
100                 fprintf(stderr, "couldn't do udp_create\n");
101                 exit(1);
102         }
103         /* make an entry for ourself */
104         pml = (struct pmaplist *)malloc((u_int)sizeof(struct pmaplist));
105         pml->pml_next = 0;
106         pml->pml_map.pm_prog = PMAPPROG;
107         pml->pml_map.pm_vers = PMAPVERS;
108         pml->pml_map.pm_prot = IPPROTO_UDP;
109         pml->pml_map.pm_port = PMAPPORT;
110         pmaplist = pml;
111
112         if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
113                 perror("portmap cannot create socket");
114                 exit(1);
115         }
116         if (bind(sock, (struct sockaddr *)&addr, len) != 0) {
117                 perror("portmap cannot bind");
118                 exit(1);
119         }
120         if ((xprt = svctcp_create(sock, RPCSMALLMSGSIZE, RPCSMALLMSGSIZE))
121             == (SVCXPRT *)NULL) {
122                 fprintf(stderr, "couldn't do tcp_create\n");
123                 exit(1);
124         }
125         /* make an entry for ourself */
126         pml = (struct pmaplist *)malloc((u_int)sizeof(struct pmaplist));
127         pml->pml_map.pm_prog = PMAPPROG;
128         pml->pml_map.pm_vers = PMAPVERS;
129         pml->pml_map.pm_prot = IPPROTO_TCP;
130         pml->pml_map.pm_port = PMAPPORT;
131         pml->pml_next = pmaplist;
132         pmaplist = pml;
133
134         (void)svc_register(xprt, PMAPPROG, PMAPVERS, reg_service, FALSE);
135
136         (void)signal(SIGCHLD, reap);
137         svc_run();
138         fprintf(stderr, "run_svc returned unexpectedly\n");
139         abort();
140 }
141
142 static struct pmaplist *
143 find_service(prog, vers, prot)
144         u_long prog;
145         u_long vers;
146 {
147         register struct pmaplist *hit = NULL;
148         register struct pmaplist *pml;
149
150         for (pml = pmaplist; pml != NULL; pml = pml->pml_next) {
151                 if ((pml->pml_map.pm_prog != prog) ||
152                         (pml->pml_map.pm_prot != prot))
153                         continue;
154                 hit = pml;
155                 if (pml->pml_map.pm_vers == vers)
156                     break;
157         }
158         return (hit);
159 }
160
161 /* 
162  * 1 OK, 0 not
163  */
164 reg_service(rqstp, xprt)
165         struct svc_req *rqstp;
166         SVCXPRT *xprt;
167 {
168         struct pmap reg;
169         struct pmaplist *pml, *prevpml, *fnd;
170         int ans, port;
171         caddr_t t;
172         
173 #ifdef DEBUG
174         fprintf(stderr, "server: about do a switch\n");
175 #endif
176         switch (rqstp->rq_proc) {
177
178         case PMAPPROC_NULL:
179                 /*
180                  * Null proc call
181                  */
182                 if ((!svc_sendreply(xprt, xdr_void, NULL)) && debugging) {
183                         abort();
184                 }
185                 break;
186
187         case PMAPPROC_SET:
188                 /*
189                  * Set a program,version to port mapping
190                  */
191                 if (!svc_getargs(xprt, xdr_pmap, &reg))
192                         svcerr_decode(xprt);
193                 else {
194                         /*
195                          * check to see if already used
196                          * find_service returns a hit even if
197                          * the versions don't match, so check for it
198                          */
199                         fnd = find_service(reg.pm_prog, reg.pm_vers, reg.pm_prot);
200                         if (fnd && fnd->pml_map.pm_vers == reg.pm_vers) {
201                                 if (fnd->pml_map.pm_port == reg.pm_port) {
202                                         ans = 1;
203                                         goto done;
204                                 }
205                                 else {
206                                         ans = 0;
207                                         goto done;
208                                 }
209                         } else {
210                                 /* 
211                                  * add to END of list
212                                  */
213                                 pml = (struct pmaplist *)
214                                     malloc((u_int)sizeof(struct pmaplist));
215                                 pml->pml_map = reg;
216                                 pml->pml_next = 0;
217                                 if (pmaplist == 0) {
218                                         pmaplist = pml;
219                                 } else {
220                                         for (fnd= pmaplist; fnd->pml_next != 0;
221                                             fnd = fnd->pml_next);
222                                         fnd->pml_next = pml;
223                                 }
224                                 ans = 1;
225                         }
226                 done:
227                         if ((!svc_sendreply(xprt, xdr_long, (caddr_t)&ans)) &&
228                             debugging) {
229                                 fprintf(stderr, "svc_sendreply\n");
230                                 abort();
231                         }
232                 }
233                 break;
234
235         case PMAPPROC_UNSET:
236                 /*
237                  * Remove a program,version to port mapping.
238                  */
239                 if (!svc_getargs(xprt, xdr_pmap, &reg))
240                         svcerr_decode(xprt);
241                 else {
242                         ans = 0;
243                         for (prevpml = NULL, pml = pmaplist; pml != NULL; ) {
244                                 if ((pml->pml_map.pm_prog != reg.pm_prog) ||
245                                         (pml->pml_map.pm_vers != reg.pm_vers)) {
246                                         /* both pml & prevpml move forwards */
247                                         prevpml = pml;
248                                         pml = pml->pml_next;
249                                         continue;
250                                 }
251                                 /* found it; pml moves forward, prevpml stays */
252                                 ans = 1;
253                                 t = (caddr_t)pml;
254                                 pml = pml->pml_next;
255                                 if (prevpml == NULL)
256                                         pmaplist = pml;
257                                 else
258                                         prevpml->pml_next = pml;
259                                 free(t);
260                         }
261                         if ((!svc_sendreply(xprt, xdr_long, (caddr_t)&ans)) &&
262                             debugging) {
263                                 fprintf(stderr, "svc_sendreply\n");
264                                 abort();
265                         }
266                 }
267                 break;
268
269         case PMAPPROC_GETPORT:
270                 /*
271                  * Lookup the mapping for a program,version and return its port
272                  */
273                 if (!svc_getargs(xprt, xdr_pmap, &reg))
274                         svcerr_decode(xprt);
275                 else {
276                         fnd = find_service(reg.pm_prog, reg.pm_vers, reg.pm_prot);
277                         if (fnd)
278                                 port = fnd->pml_map.pm_port;
279                         else
280                                 port = 0;
281                         if ((!svc_sendreply(xprt, xdr_long, (caddr_t)&port)) &&
282                             debugging) {
283                                 fprintf(stderr, "svc_sendreply\n");
284                                 abort();
285                         }
286                 }
287                 break;
288
289         case PMAPPROC_DUMP:
290                 /*
291                  * Return the current set of mapped program,version
292                  */
293                 if (!svc_getargs(xprt, xdr_void, NULL))
294                         svcerr_decode(xprt);
295                 else {
296                         if ((!svc_sendreply(xprt, xdr_pmaplist,
297                             (caddr_t)&pmaplist)) && debugging) {
298                                 fprintf(stderr, "svc_sendreply\n");
299                                 abort();
300                         }
301                 }
302                 break;
303
304         case PMAPPROC_CALLIT:
305                 /*
306                  * Calls a procedure on the local machine.  If the requested
307                  * procedure is not registered this procedure does not return
308                  * error information!!
309                  * This procedure is only supported on rpc/udp and calls via 
310                  * rpc/udp.  It passes null authentication parameters.
311                  */
312                 callit(rqstp, xprt);
313                 break;
314
315         default:
316                 svcerr_noproc(xprt);
317                 break;
318         }
319 }
320
321
322 /*
323  * Stuff for the rmtcall service
324  */
325 #define ARGSIZE 9000
326
327 typedef struct encap_parms {
328         u_long arglen;
329         char *args;
330 };
331
332 static bool_t
333 xdr_encap_parms(xdrs, epp)
334         XDR *xdrs;
335         struct encap_parms *epp;
336 {
337
338         return (xdr_bytes(xdrs, &(epp->args), &(epp->arglen), ARGSIZE));
339 }
340
341 typedef struct rmtcallargs {
342         u_long  rmt_prog;
343         u_long  rmt_vers;
344         u_long  rmt_port;
345         u_long  rmt_proc;
346         struct encap_parms rmt_args;
347 };
348
349 static bool_t
350 xdr_rmtcall_args(xdrs, cap)
351         register XDR *xdrs;
352         register struct rmtcallargs *cap;
353 {
354
355         /* does not get a port number */
356         if (xdr_u_long(xdrs, &(cap->rmt_prog)) &&
357             xdr_u_long(xdrs, &(cap->rmt_vers)) &&
358             xdr_u_long(xdrs, &(cap->rmt_proc))) {
359                 return (xdr_encap_parms(xdrs, &(cap->rmt_args)));
360         }
361         return (FALSE);
362 }
363
364 static bool_t
365 xdr_rmtcall_result(xdrs, cap)
366         register XDR *xdrs;
367         register struct rmtcallargs *cap;
368 {
369         if (xdr_u_long(xdrs, &(cap->rmt_port)))
370                 return (xdr_encap_parms(xdrs, &(cap->rmt_args)));
371         return (FALSE);
372 }
373
374 /*
375  * only worries about the struct encap_parms part of struct rmtcallargs.
376  * The arglen must already be set!!
377  */
378 static bool_t
379 xdr_opaque_parms(xdrs, cap)
380         XDR *xdrs;
381         struct rmtcallargs *cap;
382 {
383
384         return (xdr_opaque(xdrs, cap->rmt_args.args, cap->rmt_args.arglen));
385 }
386
387 /*
388  * This routine finds and sets the length of incoming opaque paraters
389  * and then calls xdr_opaque_parms.
390  */
391 static bool_t
392 xdr_len_opaque_parms(xdrs, cap)
393         register XDR *xdrs;
394         struct rmtcallargs *cap;
395 {
396         register u_int beginpos, lowpos, highpos, currpos, pos;
397
398         beginpos = lowpos = pos = xdr_getpos(xdrs);
399         highpos = lowpos + ARGSIZE;
400         while ((int)(highpos - lowpos) >= 0) {
401                 currpos = (lowpos + highpos) / 2;
402                 if (xdr_setpos(xdrs, currpos)) {
403                         pos = currpos;
404                         lowpos = currpos + 1;
405                 } else {
406                         highpos = currpos - 1;
407                 }
408         }
409         xdr_setpos(xdrs, beginpos);
410         cap->rmt_args.arglen = pos - beginpos;
411         return (xdr_opaque_parms(xdrs, cap));
412 }
413
414 /*
415  * Call a remote procedure service
416  * This procedure is very quiet when things go wrong.
417  * The proc is written to support broadcast rpc.  In the broadcast case,
418  * a machine should shut-up instead of complain, less the requestor be
419  * overrun with complaints at the expense of not hearing a valid reply ...
420  *
421  * This now forks so that the program & process that it calls can call 
422  * back to the portmapper.
423  */
424 static
425 callit(rqstp, xprt)
426         struct svc_req *rqstp;
427         SVCXPRT *xprt;
428 {
429         struct rmtcallargs a;
430         struct pmaplist *pml;
431         u_short port;
432         struct sockaddr_in me;
433         int pid, socket = -1;
434         CLIENT *client;
435         struct authunix_parms *au = (struct authunix_parms *)rqstp->rq_clntcred;
436         struct timeval timeout;
437         char buf[ARGSIZE];
438
439         timeout.tv_sec = 5;
440         timeout.tv_usec = 0;
441         a.rmt_args.args = buf;
442         if (!svc_getargs(xprt, xdr_rmtcall_args, &a))
443             return;
444         if ((pml = find_service(a.rmt_prog, a.rmt_vers, IPPROTO_UDP)) == NULL)
445             return;
446         /*
447          * fork a child to do the work.  Parent immediately returns.
448          * Child exits upon completion.
449          */
450         if ((pid = fork()) != 0) {
451                 if (debugging && (pid < 0)) {
452                         fprintf(stderr, "portmap CALLIT: cannot fork.\n");
453                 }
454                 return;
455         }
456         port = pml->pml_map.pm_port;
457         get_myaddress(&me);
458         me.sin_port = htons(port);
459         client = clntudp_create(&me, a.rmt_prog, a.rmt_vers, timeout, &socket);
460         if (client != (CLIENT *)NULL) {
461                 if (rqstp->rq_cred.oa_flavor == AUTH_UNIX) {
462                         client->cl_auth = authunix_create(au->aup_machname,
463                            au->aup_uid, au->aup_gid, au->aup_len, au->aup_gids);
464                 }
465                 a.rmt_port = (u_long)port;
466                 if (clnt_call(client, a.rmt_proc, xdr_opaque_parms, &a,
467                     xdr_len_opaque_parms, &a, timeout) == RPC_SUCCESS) {
468                         svc_sendreply(xprt, xdr_rmtcall_result, &a);
469                 }
470                 AUTH_DESTROY(client->cl_auth);
471                 clnt_destroy(client);
472         }
473         (void)close(socket);
474         exit(0);
475 }
476
477 void
478 reap()
479 {
480         while (wait3(NULL, WNOHANG, NULL) > 0);
481 }