xref: /openbsd-src/usr.sbin/portmap/portmap.c (revision db3296cf5c1dd9058ceecc3a29fe4aaa0bd26000)
1 /*	$OpenBSD: portmap.c,v 1.29 2003/06/26 19:47:09 deraadt Exp $	*/
2 
3 /*-
4  * Copyright (c) 1996, 1997 Theo de Raadt (OpenBSD). All rights reserved.
5  * Copyright (c) 1990 The Regents of the University of California.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. Neither the name of the University nor the names of its contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  */
32 
33 #ifndef lint
34 char copyright[] =
35 "@(#) Copyright (c) 1990 The Regents of the University of California.\n\
36  All rights reserved.\n";
37 #endif /* not lint */
38 
39 #ifndef lint
40 #if 0
41 static char sccsid[] = "from: @(#)portmap.c	5.4 (Berkeley) 4/19/91";
42 #else
43 static char rcsid[] = "$OpenBSD: portmap.c,v 1.29 2003/06/26 19:47:09 deraadt Exp $";
44 #endif
45 #endif /* not lint */
46 
47 /*
48 @(#)portmap.c	2.3 88/08/11 4.0 RPCSRC
49 static char sccsid[] = "@(#)portmap.c 1.32 87/08/06 Copyr 1984 Sun Micro";
50 */
51 
52 /*
53  * portmap.c, Implements the program,version to port number mapping for
54  * rpc.
55  */
56 
57 /*
58  * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
59  * unrestricted use provided that this legend is included on all tape
60  * media and as a part of the software program in whole or part.  Users
61  * may copy or modify Sun RPC without charge, but are not authorized
62  * to license or distribute it to anyone else except as part of a product or
63  * program developed by the user.
64  *
65  * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
66  * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
67  * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
68  *
69  * Sun RPC is provided with no support and without any obligation on the
70  * part of Sun Microsystems, Inc. to assist in its use, correction,
71  * modification or enhancement.
72  *
73  * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
74  * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
75  * OR ANY PART THEREOF.
76  *
77  * In no event will Sun Microsystems, Inc. be liable for any lost revenue
78  * or profits or other special, indirect and consequential damages, even if
79  * Sun has been advised of the possibility of such damages.
80  *
81  * Sun Microsystems, Inc.
82  * 2550 Garcia Avenue
83  * Mountain View, California  94043
84  */
85 
86 #include <rpc/rpc.h>
87 #include <rpc/pmap_prot.h>
88 #include <stdio.h>
89 #include <stdlib.h>
90 #include <string.h>
91 #include <syslog.h>
92 #include <unistd.h>
93 #include <netdb.h>
94 #include <pwd.h>
95 #include <sys/socket.h>
96 #include <sys/ioctl.h>
97 #include <sys/wait.h>
98 #include <sys/signal.h>
99 #include <sys/resource.h>
100 #include <rpcsvc/nfs_prot.h>
101 #include <arpa/inet.h>
102 
103 void reg_service(struct svc_req *, SVCXPRT *);
104 void reap(void);
105 void callit(struct svc_req *, SVCXPRT *);
106 int check_callit(struct sockaddr_in *, u_long, u_long, u_long);
107 
108 struct pmaplist *pmaplist;
109 int debugging = 0;
110 extern int errno;
111 
112 SVCXPRT *ludpxprt, *ltcpxprt;
113 
114 int
115 main(int argc, char *argv[])
116 {
117 	int sock, lsock, c, on = 1, len = sizeof(struct sockaddr_in);
118 	struct sockaddr_in addr, laddr;
119 	struct pmaplist *pml;
120 	struct passwd *pw;
121 	SVCXPRT *xprt;
122 
123 	while ((c = getopt(argc, argv, "d")) != -1) {
124 		switch (c) {
125 
126 		case 'd':
127 			debugging = 1;
128 			break;
129 
130 		default:
131 			(void) fprintf(stderr, "usage: %s [-d]\n", argv[0]);
132 			exit(1);
133 		}
134 	}
135 
136 	if (!debugging && daemon(0, 0)) {
137 		(void) fprintf(stderr, "portmap: fork: %s", strerror(errno));
138 		exit(1);
139 	}
140 
141 	openlog("portmap", LOG_NDELAY | (debugging ? LOG_PID | LOG_PERROR : LOG_PID),
142 	    LOG_DAEMON);
143 
144 	bzero((char *)&addr, sizeof addr);
145 	addr.sin_addr.s_addr = 0;
146 	addr.sin_family = AF_INET;
147 	addr.sin_addr.s_addr = htonl(INADDR_ANY);
148 	addr.sin_port = htons(PMAPPORT);
149 
150 	bzero((char *)&laddr, sizeof laddr);
151 	laddr.sin_addr.s_addr = 0;
152 	laddr.sin_family = AF_INET;
153 	laddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
154 	laddr.sin_port = htons(PMAPPORT);
155 
156 	if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
157 		syslog(LOG_ERR, "cannot create udp socket: %m");
158 		exit(1);
159 	}
160 	setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof on);
161 	if (bind(sock, (struct sockaddr *)&addr, len) != 0) {
162 		syslog(LOG_ERR, "cannot bind udp: %m");
163 		exit(1);
164 	}
165 
166 	if ((xprt = svcudp_create(sock)) == (SVCXPRT *)NULL) {
167 		syslog(LOG_ERR, "couldn't do udp_create");
168 		exit(1);
169 	}
170 
171 	if ((lsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
172 		syslog(LOG_ERR, "cannot create udp socket: %m");
173 		exit(1);
174 	}
175 	setsockopt(lsock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof on);
176 	if (bind(lsock, (struct sockaddr *)&laddr, len) != 0) {
177 		syslog(LOG_ERR, "cannot bind local udp: %m");
178 		exit(1);
179 	}
180 
181 	if ((ludpxprt = svcudp_create(lsock)) == (SVCXPRT *)NULL) {
182 		syslog(LOG_ERR, "couldn't do udp_create");
183 		exit(1);
184 	}
185 
186 	/* make an entry for ourself */
187 	pml = (struct pmaplist *)malloc((u_int)sizeof(struct pmaplist));
188 	if (pml == NULL) {
189 		syslog(LOG_ERR, "out of memory");
190 		exit(1);
191 	}
192 	pml->pml_next = 0;
193 	pml->pml_map.pm_prog = PMAPPROG;
194 	pml->pml_map.pm_vers = PMAPVERS;
195 	pml->pml_map.pm_prot = IPPROTO_UDP;
196 	pml->pml_map.pm_port = PMAPPORT;
197 	pmaplist = pml;
198 
199 	if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
200 		syslog(LOG_ERR, "cannot create tcp socket: %m");
201 		exit(1);
202 	}
203 	setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof on);
204 	if (bind(sock, (struct sockaddr *)&addr, len) != 0) {
205 		syslog(LOG_ERR, "cannot bind tcp: %m");
206 		exit(1);
207 	}
208 	if ((xprt = svctcp_create(sock, RPCSMALLMSGSIZE, RPCSMALLMSGSIZE))
209 	    == (SVCXPRT *)NULL) {
210 		syslog(LOG_ERR, "couldn't do tcp_create");
211 		exit(1);
212 	}
213 
214 	if ((lsock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
215 		syslog(LOG_ERR, "cannot create tcp socket: %m");
216 		exit(1);
217 	}
218 	setsockopt(lsock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof on);
219 	if (bind(lsock, (struct sockaddr *)&laddr, len) != 0) {
220 		syslog(LOG_ERR, "cannot bind tcp: %m");
221 		exit(1);
222 	}
223 	if ((ltcpxprt = svctcp_create(lsock, RPCSMALLMSGSIZE,
224 	    RPCSMALLMSGSIZE)) == (SVCXPRT *)NULL) {
225 		syslog(LOG_ERR, "couldn't do tcp_create");
226 		exit(1);
227 	}
228 
229 	/* make an entry for ourself */
230 	pml = (struct pmaplist *)malloc((u_int)sizeof(struct pmaplist));
231 	if (pml == NULL) {
232 		syslog(LOG_ERR, "out of memory");
233 		exit(1);
234 	}
235 	pml->pml_map.pm_prog = PMAPPROG;
236 	pml->pml_map.pm_vers = PMAPVERS;
237 	pml->pml_map.pm_prot = IPPROTO_TCP;
238 	pml->pml_map.pm_port = PMAPPORT;
239 	pml->pml_next = pmaplist;
240 	pmaplist = pml;
241 
242 	pw = getpwnam("_portmap");
243 	if (!pw)
244 		pw = getpwnam("nobody");
245 	if (chroot("/var/empty") == -1) {
246 		syslog(LOG_ERR, "cannot chdir to /var/empty.");
247 		exit(1);
248 	}
249 	chdir("/");
250 	if (pw) {
251 		setgroups(1, &pw->pw_gid);
252 		setegid(pw->pw_gid);
253 		setgid(pw->pw_gid);
254 		seteuid(pw->pw_uid);
255 		setuid(pw->pw_uid);
256 	}
257 
258 	if (svc_register(xprt, PMAPPROG, PMAPVERS, reg_service, FALSE) == 0) {
259 		syslog(LOG_ERR, "svc_register failed.");
260 		exit(1);
261 	}
262 
263 	(void)signal(SIGCHLD, (void (*)(int))reap);
264 	svc_run();
265 	syslog(LOG_ERR, "svc_run returned unexpectedly");
266 	abort();
267 }
268 
269 #ifndef lint
270 /* need to override perror calls in rpc library */
271 void
272 perror(const char *what)
273 {
274 
275 	syslog(LOG_ERR, "%s: %m", what);
276 }
277 #endif
278 
279 struct pmaplist *
280 find_service(u_long prog, u_long vers, u_long prot)
281 {
282 	struct pmaplist *hit = NULL;
283 	struct pmaplist *pml;
284 
285 	for (pml = pmaplist; pml != NULL; pml = pml->pml_next) {
286 		if ((pml->pml_map.pm_prog != prog) ||
287 		    (pml->pml_map.pm_prot != prot))
288 			continue;
289 		hit = pml;
290 		if (pml->pml_map.pm_vers == vers)
291 			break;
292 	}
293 	return (hit);
294 }
295 
296 /*
297  * 1 OK, 0 not
298  */
299 void
300 reg_service(struct svc_req *rqstp, SVCXPRT *xprt)
301 {
302 	struct pmap reg;
303 	struct pmaplist *pml, *prevpml, *fnd;
304 	struct sockaddr_in *fromsin;
305 	long ans = 0, port;
306 	caddr_t t;
307 
308 	fromsin = svc_getcaller(xprt);
309 
310 	if (debugging)
311 		(void) fprintf(stderr, "server: about to do a switch\n");
312 	switch (rqstp->rq_proc) {
313 
314 	case PMAPPROC_NULL:
315 		/*
316 		 * Null proc call
317 		 */
318 		if (!svc_sendreply(xprt, xdr_void, (caddr_t)0) && debugging) {
319 			abort();
320 		}
321 		break;
322 
323 	case PMAPPROC_SET:
324 		/*
325 		 * Set a program,version to port mapping
326 		 */
327 		if (xprt != ltcpxprt && xprt != ludpxprt) {
328 			syslog(LOG_WARNING,
329 			    "non-local set attempt (might be from %s)",
330 			    inet_ntoa(fromsin->sin_addr));
331 			svcerr_noproc(xprt);
332 			return;
333 		}
334 		if (!svc_getargs(xprt, xdr_pmap, (caddr_t)&reg)) {
335 			svcerr_decode(xprt);
336 			break;
337 		}
338 
339 		/*
340 		 * check to see if already used
341 		 * find_service returns a hit even if
342 		 * the versions don't match, so check for it
343 		 */
344 		fnd = find_service(reg.pm_prog, reg.pm_vers, reg.pm_prot);
345 		if (fnd && fnd->pml_map.pm_vers == reg.pm_vers) {
346 			if (fnd->pml_map.pm_port == reg.pm_port)
347 				ans = 1;
348 			goto done;
349 		}
350 
351 		if (debugging)
352 			printf("set: prog %lu vers %lu port %lu\n",
353 			    reg.pm_prog, reg.pm_vers, reg.pm_port);
354 
355 		if (reg.pm_port & ~0xffff)
356 			goto done;
357 
358 		/*
359 		 * only permit localhost root to create
360 		 * mappings pointing at sensitive ports
361 		 */
362 		if ((reg.pm_port < IPPORT_RESERVED ||
363 		    reg.pm_port == NFS_PORT) &&
364 		    htons(fromsin->sin_port) >= IPPORT_RESERVED) {
365 			syslog(LOG_WARNING,
366 			    "resvport set attempt by non-root");
367 			goto done;
368 		}
369 
370 		/*
371 		 * add to END of list
372 		 */
373 		pml = (struct pmaplist *)malloc(sizeof(struct pmaplist));
374 		if (pml == NULL) {
375 			syslog(LOG_ERR, "out of memory");
376 			svcerr_systemerr(xprt);
377 			return;
378 		}
379 
380 		pml->pml_map = reg;
381 		pml->pml_next = 0;
382 		if (pmaplist == 0) {
383 			pmaplist = pml;
384 		} else {
385 			for (fnd = pmaplist; fnd->pml_next != 0;
386 			    fnd = fnd->pml_next);
387 			fnd->pml_next = pml;
388 		}
389 		ans = 1;
390 	done:
391 		if ((!svc_sendreply(xprt, xdr_long, (caddr_t)&ans)) &&
392 		    debugging) {
393 			(void) fprintf(stderr, "svc_sendreply\n");
394 			abort();
395 		}
396 		break;
397 
398 	case PMAPPROC_UNSET:
399 		/*
400 		 * Remove a program,version to port mapping.
401 		 */
402 		if (xprt != ltcpxprt && xprt != ludpxprt) {
403 			syslog(LOG_WARNING,
404 			    "non-local unset attempt (might be from %s)",
405 			    inet_ntoa(fromsin->sin_addr));
406 			svcerr_noproc(xprt);
407 			return;
408 		}
409 		if (!svc_getargs(xprt, xdr_pmap, (caddr_t)&reg)) {
410 			svcerr_decode(xprt);
411 			break;
412 		}
413 		for (prevpml = NULL, pml = pmaplist; pml != NULL; ) {
414 			if ((pml->pml_map.pm_prog != reg.pm_prog) ||
415 			    (pml->pml_map.pm_vers != reg.pm_vers)) {
416 				/* both pml & prevpml move forwards */
417 				prevpml = pml;
418 				pml = pml->pml_next;
419 				continue;
420 			}
421 			if ((pml->pml_map.pm_port < IPPORT_RESERVED ||
422 			    pml->pml_map.pm_port == NFS_PORT) &&
423 			    htons(fromsin->sin_port) >= IPPORT_RESERVED) {
424 				syslog(LOG_WARNING,
425 				    "resvport unset attempt by non-root");
426 				break;
427 			}
428 
429 			/* found it; pml moves forward, prevpml stays */
430 			ans = 1;
431 			t = (caddr_t)pml;
432 			pml = pml->pml_next;
433 			if (prevpml == NULL)
434 				pmaplist = pml;
435 			else
436 				prevpml->pml_next = pml;
437 			free(t);
438 		}
439 		if ((!svc_sendreply(xprt, xdr_long, (caddr_t)&ans)) &&
440 		    debugging) {
441 			fprintf(stderr, "svc_sendreply\n");
442 			abort();
443 		}
444 		break;
445 
446 	case PMAPPROC_GETPORT:
447 		/*
448 		 * Lookup the mapping for a program,version and return its port
449 		 */
450 		if (!svc_getargs(xprt, xdr_pmap, (caddr_t)&reg)) {
451 			svcerr_decode(xprt);
452 			break;
453 		}
454 		fnd = find_service(reg.pm_prog, reg.pm_vers, reg.pm_prot);
455 		if (fnd)
456 			port = fnd->pml_map.pm_port;
457 		else
458 			port = 0;
459 		if ((!svc_sendreply(xprt, xdr_long, (caddr_t)&port)) &&
460 		    debugging) {
461 			fprintf(stderr, "svc_sendreply\n");
462 			abort();
463 		}
464 		break;
465 
466 	case PMAPPROC_DUMP:
467 		/*
468 		 * Return the current set of mapped program,version
469 		 */
470 		if (!svc_getargs(xprt, xdr_void, NULL)) {
471 			svcerr_decode(xprt);
472 			break;
473 		}
474 		if (!svc_sendreply(xprt, xdr_pmaplist, (caddr_t)&pmaplist) &&
475 		    debugging) {
476 			fprintf(stderr, "svc_sendreply\n");
477 			abort();
478 		}
479 		break;
480 
481 	case PMAPPROC_CALLIT:
482 		/*
483 		 * Calls a procedure on the local machine.  If the requested
484 		 * procedure is not registered this procedure does not return
485 		 * error information!!
486 		 * This procedure is only supported on rpc/udp and calls via
487 		 * rpc/udp.  It passes null authentication parameters.
488 		 */
489 		callit(rqstp, xprt);
490 		break;
491 
492 	default:
493 		svcerr_noproc(xprt);
494 		break;
495 	}
496 }
497 
498 
499 /*
500  * Stuff for the rmtcall service
501  */
502 #define ARGSIZE 9000
503 
504 struct encap_parms {
505 	u_int arglen;
506 	char *args;
507 };
508 
509 static bool_t
510 xdr_encap_parms(XDR *xdrs, struct encap_parms *epp)
511 {
512 
513 	return (xdr_bytes(xdrs, &(epp->args), &(epp->arglen), ARGSIZE));
514 }
515 
516 struct rmtcallargs {
517 	u_long	rmt_prog;
518 	u_long	rmt_vers;
519 	u_long	rmt_port;
520 	u_long	rmt_proc;
521 	struct encap_parms rmt_args;
522 };
523 
524 static bool_t
525 xdr_rmtcall_args(XDR *xdrs, struct rmtcallargs *cap)
526 {
527 
528 	/* does not get a port number */
529 	if (xdr_u_long(xdrs, &(cap->rmt_prog)) &&
530 	    xdr_u_long(xdrs, &(cap->rmt_vers)) &&
531 	    xdr_u_long(xdrs, &(cap->rmt_proc))) {
532 		return (xdr_encap_parms(xdrs, &(cap->rmt_args)));
533 	}
534 	return (FALSE);
535 }
536 
537 static bool_t
538 xdr_rmtcall_result(XDR *xdrs, struct rmtcallargs *cap)
539 {
540 	if (xdr_u_long(xdrs, &(cap->rmt_port)))
541 		return (xdr_encap_parms(xdrs, &(cap->rmt_args)));
542 	return (FALSE);
543 }
544 
545 /*
546  * only worries about the struct encap_parms part of struct rmtcallargs.
547  * The arglen must already be set!!
548  */
549 static bool_t
550 xdr_opaque_parms(XDR *xdrs, struct rmtcallargs *cap)
551 {
552 
553 	return (xdr_opaque(xdrs, cap->rmt_args.args, cap->rmt_args.arglen));
554 }
555 
556 /*
557  * This routine finds and sets the length of incoming opaque paraters
558  * and then calls xdr_opaque_parms.
559  */
560 static bool_t
561 xdr_len_opaque_parms(XDR *xdrs, struct rmtcallargs *cap)
562 {
563 	u_int beginpos, lowpos, highpos, currpos, pos;
564 
565 	beginpos = lowpos = pos = xdr_getpos(xdrs);
566 	highpos = lowpos + ARGSIZE;
567 	while ((int)(highpos - lowpos) >= 0) {
568 		currpos = (lowpos + highpos) / 2;
569 		if (xdr_setpos(xdrs, currpos)) {
570 			pos = currpos;
571 			lowpos = currpos + 1;
572 		} else {
573 			highpos = currpos - 1;
574 		}
575 	}
576 	xdr_setpos(xdrs, beginpos);
577 	cap->rmt_args.arglen = pos - beginpos;
578 	return (xdr_opaque_parms(xdrs, cap));
579 }
580 
581 /*
582  * Call a remote procedure service
583  * This procedure is very quiet when things go wrong.
584  * The proc is written to support broadcast rpc.  In the broadcast case,
585  * a machine should shut-up instead of complain, less the requestor be
586  * overrun with complaints at the expense of not hearing a valid reply ...
587  *
588  * This now forks so that the program & process that it calls can call
589  * back to the portmapper.
590  */
591 void
592 callit(struct svc_req *rqstp, SVCXPRT *xprt)
593 {
594 	struct rmtcallargs a;
595 	struct pmaplist *pml;
596 	u_short port;
597 	struct sockaddr_in me;
598 	pid_t pid;
599 	int so = -1, dontblock = 1;
600 	CLIENT *client;
601 	struct authunix_parms *au = (struct authunix_parms *)rqstp->rq_clntcred;
602 	struct timeval timeout;
603 	char buf[ARGSIZE];
604 
605 	timeout.tv_sec = 5;
606 	timeout.tv_usec = 0;
607 	a.rmt_args.args = buf;
608 	if (!svc_getargs(xprt, xdr_rmtcall_args, (caddr_t)&a))
609 		return;
610 	if (!check_callit(svc_getcaller(xprt), rqstp->rq_proc,
611 	    a.rmt_prog, a.rmt_proc))
612 		return;
613 	if ((pml = find_service(a.rmt_prog, a.rmt_vers,
614 	    (u_long)IPPROTO_UDP)) == NULL)
615 		return;
616 
617 	/*
618 	 * fork a child to do the work.  Parent immediately returns.
619 	 * Child exits upon completion.
620 	 */
621 	if ((pid = fork()) != 0) {
622 		if (pid == -1)
623 			syslog(LOG_ERR, "CALLIT (prog %lu): fork: %m",
624 			    a.rmt_prog);
625 		return;
626 	}
627 	port = pml->pml_map.pm_port;
628 	get_myaddress(&me);
629 	me.sin_port = htons(port);
630 
631 	/* Avoid implicit binding to reserved port by clntudp_create() */
632 	so = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
633 	if (so == -1)
634 		exit(1);
635 	if (ioctl(so, FIONBIO, &dontblock) == -1)
636 		exit(1);
637 
638 	client = clntudp_create(&me, a.rmt_prog, a.rmt_vers, timeout, &so);
639 	if (client != (CLIENT *)NULL) {
640 		if (rqstp->rq_cred.oa_flavor == AUTH_UNIX)
641 			client->cl_auth = authunix_create(au->aup_machname,
642 			    au->aup_uid, au->aup_gid, au->aup_len, au->aup_gids);
643 		a.rmt_port = (u_long)port;
644 		if (clnt_call(client, a.rmt_proc, xdr_opaque_parms, &a,
645 		    xdr_len_opaque_parms, &a, timeout) == RPC_SUCCESS)
646 			svc_sendreply(xprt, xdr_rmtcall_result, (caddr_t)&a);
647 		AUTH_DESTROY(client->cl_auth);
648 		clnt_destroy(client);
649 	}
650 	(void)close(so);
651 	exit(0);
652 }
653 
654 void
655 reap()
656 {
657 	int save_errno = errno;
658 
659 	while (wait3(NULL, WNOHANG, NULL) > 0)
660 		;
661 	errno = save_errno;
662 }
663 
664 #define	NFSPROG			((u_long) 100003)
665 #define	MOUNTPROG		((u_long) 100005)
666 #define	YPXPROG			((u_long) 100069)
667 #define	YPPROG			((u_long) 100004)
668 #define	YPPROC_DOMAIN_NONACK	((u_long) 2)
669 #define	MOUNTPROC_MNT		((u_long) 1)
670 #define XXXPROC_NOP		((u_long) 0)
671 
672 int
673 check_callit(struct sockaddr_in *addr, u_long proc, u_long prog,
674     u_long aproc)
675 {
676 	if ((prog == PMAPPROG && aproc != XXXPROC_NOP) ||
677 	    (prog == NFSPROG && aproc != XXXPROC_NOP) ||
678 	    (prog == YPXPROG && aproc != XXXPROC_NOP) ||
679 	    (prog == MOUNTPROG && aproc == MOUNTPROC_MNT) ||
680 	    (prog == YPPROG && aproc != YPPROC_DOMAIN_NONACK)) {
681 		syslog(LOG_WARNING,
682 		    "callit prog %d aproc %d (might be from %s)",
683 		    (int)prog, (int)aproc, inet_ntoa(addr->sin_addr));
684 		return (FALSE);
685 	}
686 	return (TRUE);
687 }
688