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