GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/portmap/portmap.c Lines: 0 283 0.0 %
Date: 2017-11-07 Branches: 0 177 0.0 %

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