1 /* $OpenBSD: portmap.c,v 1.50 2019/06/28 13:32:49 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 * 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)) == -1) { 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) == -1) { 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)) == -1) { 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) == -1) { 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)) == -1) { 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) == -1) { 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)) == -1) { 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) == -1) { 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 inet proc", 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)®)) { 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)®)) { 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)®)) { 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 inet", 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 } 674