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