1 /* $OpenBSD: portmap.c,v 1.42 2014/03/16 18:38:30 guenther 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/ioctl.h> 71 #include <sys/wait.h> 72 #include <sys/resource.h> 73 74 #include <rpcsvc/nfs_prot.h> 75 #include <arpa/inet.h> 76 #include <rpc/rpc.h> 77 #include <rpc/pmap_prot.h> 78 79 #include <signal.h> 80 #include <stdio.h> 81 #include <stdlib.h> 82 #include <string.h> 83 #include <syslog.h> 84 #include <unistd.h> 85 #include <netdb.h> 86 #include <pwd.h> 87 #include <errno.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 (svc_register(xprt, PMAPPROG, PMAPVERS, reg_service, FALSE) == 0) { 251 syslog(LOG_ERR, "svc_register failed."); 252 exit(1); 253 } 254 255 (void)signal(SIGCHLD, reap); 256 svc_run(); 257 syslog(LOG_ERR, "svc_run returned unexpectedly"); 258 abort(); 259 } 260 261 /* need to override perror calls in rpc library */ 262 void 263 perror(const char *what) 264 { 265 266 syslog(LOG_ERR, "%s: %m", what); 267 } 268 269 struct pmaplist * 270 find_service(u_long prog, u_long vers, u_long prot) 271 { 272 struct pmaplist *hit = NULL; 273 struct pmaplist *pml; 274 275 for (pml = pmaplist; pml != NULL; pml = pml->pml_next) { 276 if ((pml->pml_map.pm_prog != prog) || 277 (pml->pml_map.pm_prot != prot)) 278 continue; 279 hit = pml; 280 if (pml->pml_map.pm_vers == vers) 281 break; 282 } 283 return (hit); 284 } 285 286 /* 287 * 1 OK, 0 not 288 */ 289 void 290 reg_service(struct svc_req *rqstp, SVCXPRT *xprt) 291 { 292 struct pmap reg; 293 struct pmaplist *pml, *prevpml, *fnd; 294 struct sockaddr_in *fromsin; 295 long ans = 0, port; 296 void *t; 297 298 fromsin = svc_getcaller(xprt); 299 300 if (debugging) 301 (void)fprintf(stderr, "server: about to do a switch\n"); 302 switch (rqstp->rq_proc) { 303 case PMAPPROC_NULL: 304 /* 305 * Null proc call 306 */ 307 if (!svc_sendreply(xprt, xdr_void, NULL) && debugging) { 308 abort(); 309 } 310 break; 311 case PMAPPROC_SET: 312 /* 313 * Set a program,version to port mapping 314 */ 315 if (xprt != ltcpxprt && xprt != ludpxprt) { 316 syslog(LOG_WARNING, 317 "non-local set attempt (might be from %s)", 318 inet_ntoa(fromsin->sin_addr)); 319 svcerr_noproc(xprt); 320 return; 321 } 322 if (!svc_getargs(xprt, xdr_pmap, (caddr_t)®)) { 323 svcerr_decode(xprt); 324 break; 325 } 326 327 /* 328 * check to see if already used 329 * find_service returns a hit even if 330 * the versions don't match, so check for it 331 */ 332 fnd = find_service(reg.pm_prog, reg.pm_vers, reg.pm_prot); 333 if (fnd && fnd->pml_map.pm_vers == reg.pm_vers) { 334 if (fnd->pml_map.pm_port == reg.pm_port) 335 ans = 1; 336 goto done; 337 } 338 339 if (debugging) 340 printf("set: prog %lu vers %lu port %lu\n", 341 reg.pm_prog, reg.pm_vers, reg.pm_port); 342 343 if (reg.pm_port & ~0xffff) 344 goto done; 345 346 /* 347 * only permit localhost root to create 348 * mappings pointing at sensitive ports 349 */ 350 if ((reg.pm_port < IPPORT_RESERVED || 351 reg.pm_port == NFS_PORT) && 352 htons(fromsin->sin_port) >= IPPORT_RESERVED) { 353 syslog(LOG_WARNING, 354 "resvport set attempt by non-root"); 355 goto done; 356 } 357 358 /* 359 * add to END of list 360 */ 361 pml = malloc(sizeof(struct pmaplist)); 362 if (pml == NULL) { 363 syslog(LOG_ERR, "out of memory"); 364 svcerr_systemerr(xprt); 365 return; 366 } 367 368 pml->pml_map = reg; 369 pml->pml_next = 0; 370 if (pmaplist == NULL) { 371 pmaplist = pml; 372 } else { 373 for (fnd = pmaplist; fnd->pml_next != 0; 374 fnd = fnd->pml_next) 375 ; 376 fnd->pml_next = pml; 377 } 378 ans = 1; 379 done: 380 if ((!svc_sendreply(xprt, xdr_long, (caddr_t)&ans)) && 381 debugging) { 382 (void)fprintf(stderr, "svc_sendreply\n"); 383 abort(); 384 } 385 break; 386 case PMAPPROC_UNSET: 387 /* 388 * Remove a program,version to port mapping. 389 */ 390 if (xprt != ltcpxprt && xprt != ludpxprt) { 391 syslog(LOG_WARNING, 392 "non-local unset attempt (might be from %s)", 393 inet_ntoa(fromsin->sin_addr)); 394 svcerr_noproc(xprt); 395 return; 396 } 397 if (!svc_getargs(xprt, xdr_pmap, (caddr_t)®)) { 398 svcerr_decode(xprt); 399 break; 400 } 401 for (prevpml = NULL, pml = pmaplist; pml != NULL; ) { 402 if ((pml->pml_map.pm_prog != reg.pm_prog) || 403 (pml->pml_map.pm_vers != reg.pm_vers)) { 404 /* both pml & prevpml move forwards */ 405 prevpml = pml; 406 pml = pml->pml_next; 407 continue; 408 } 409 if ((pml->pml_map.pm_port < IPPORT_RESERVED || 410 pml->pml_map.pm_port == NFS_PORT) && 411 htons(fromsin->sin_port) >= IPPORT_RESERVED) { 412 syslog(LOG_WARNING, 413 "resvport unset attempt by non-root"); 414 break; 415 } 416 417 /* found it; pml moves forward, prevpml stays */ 418 ans = 1; 419 t = pml; 420 pml = pml->pml_next; 421 if (prevpml == NULL) 422 pmaplist = pml; 423 else 424 prevpml->pml_next = pml; 425 free(t); 426 } 427 if ((!svc_sendreply(xprt, xdr_long, (caddr_t)&ans)) && 428 debugging) { 429 fprintf(stderr, "svc_sendreply\n"); 430 abort(); 431 } 432 break; 433 case PMAPPROC_GETPORT: 434 /* 435 * Lookup the mapping for a program,version and return its port 436 */ 437 if (!svc_getargs(xprt, xdr_pmap, (caddr_t)®)) { 438 svcerr_decode(xprt); 439 break; 440 } 441 fnd = find_service(reg.pm_prog, reg.pm_vers, reg.pm_prot); 442 if (fnd) 443 port = fnd->pml_map.pm_port; 444 else 445 port = 0; 446 if ((!svc_sendreply(xprt, xdr_long, (caddr_t)&port)) && 447 debugging) { 448 fprintf(stderr, "svc_sendreply\n"); 449 abort(); 450 } 451 break; 452 case PMAPPROC_DUMP: 453 /* 454 * Return the current set of mapped program,version 455 */ 456 if (!svc_getargs(xprt, xdr_void, NULL)) { 457 svcerr_decode(xprt); 458 break; 459 } 460 if (!svc_sendreply(xprt, xdr_pmaplist, (caddr_t)&pmaplist) && 461 debugging) { 462 fprintf(stderr, "svc_sendreply\n"); 463 abort(); 464 } 465 break; 466 case PMAPPROC_CALLIT: 467 /* 468 * Calls a procedure on the local machine. If the requested 469 * procedure is not registered this procedure does not return 470 * error information!! 471 * This procedure is only supported on rpc/udp and calls via 472 * rpc/udp. It passes null authentication parameters. 473 */ 474 callit(rqstp, xprt); 475 break; 476 default: 477 svcerr_noproc(xprt); 478 break; 479 } 480 } 481 482 483 /* 484 * Stuff for the rmtcall service 485 */ 486 #define ARGSIZE 9000 487 488 struct encap_parms { 489 u_int arglen; 490 char *args; 491 }; 492 493 static bool_t 494 xdr_encap_parms(XDR *xdrs, struct encap_parms *epp) 495 { 496 497 return (xdr_bytes(xdrs, &(epp->args), &(epp->arglen), ARGSIZE)); 498 } 499 500 struct rmtcallargs { 501 u_long rmt_prog; 502 u_long rmt_vers; 503 u_long rmt_port; 504 u_long rmt_proc; 505 struct encap_parms rmt_args; 506 }; 507 508 static bool_t 509 xdr_rmtcall_args(XDR *xdrs, struct rmtcallargs *cap) 510 { 511 512 /* does not get a port number */ 513 if (xdr_u_long(xdrs, &(cap->rmt_prog)) && 514 xdr_u_long(xdrs, &(cap->rmt_vers)) && 515 xdr_u_long(xdrs, &(cap->rmt_proc))) { 516 return (xdr_encap_parms(xdrs, &(cap->rmt_args))); 517 } 518 return (FALSE); 519 } 520 521 static bool_t 522 xdr_rmtcall_result(XDR *xdrs, struct rmtcallargs *cap) 523 { 524 if (xdr_u_long(xdrs, &(cap->rmt_port))) 525 return (xdr_encap_parms(xdrs, &(cap->rmt_args))); 526 return (FALSE); 527 } 528 529 /* 530 * only worries about the struct encap_parms part of struct rmtcallargs. 531 * The arglen must already be set!! 532 */ 533 static bool_t 534 xdr_opaque_parms(XDR *xdrs, struct rmtcallargs *cap) 535 { 536 537 return (xdr_opaque(xdrs, cap->rmt_args.args, cap->rmt_args.arglen)); 538 } 539 540 /* 541 * This routine finds and sets the length of incoming opaque paraters 542 * and then calls xdr_opaque_parms. 543 */ 544 static bool_t 545 xdr_len_opaque_parms(XDR *xdrs, struct rmtcallargs *cap) 546 { 547 u_int beginpos, lowpos, highpos, currpos, pos; 548 549 beginpos = lowpos = pos = xdr_getpos(xdrs); 550 highpos = lowpos + ARGSIZE; 551 while (highpos >= lowpos) { 552 currpos = (lowpos + highpos) / 2; 553 if (xdr_setpos(xdrs, currpos)) { 554 pos = currpos; 555 lowpos = currpos + 1; 556 } else { 557 highpos = currpos - 1; 558 } 559 } 560 xdr_setpos(xdrs, beginpos); 561 cap->rmt_args.arglen = pos - beginpos; 562 return (xdr_opaque_parms(xdrs, cap)); 563 } 564 565 /* 566 * Call a remote procedure service 567 * This procedure is very quiet when things go wrong. 568 * The proc is written to support broadcast rpc. In the broadcast case, 569 * a machine should shut-up instead of complain, less the requestor be 570 * overrun with complaints at the expense of not hearing a valid reply ... 571 * 572 * This now forks so that the program & process that it calls can call 573 * back to the portmapper. 574 */ 575 void 576 callit(struct svc_req *rqstp, SVCXPRT *xprt) 577 { 578 struct rmtcallargs a; 579 struct pmaplist *pml; 580 u_short port; 581 struct sockaddr_in me; 582 pid_t pid; 583 int so = -1, dontblock = 1; 584 CLIENT *client; 585 struct authunix_parms *au = (struct authunix_parms *)rqstp->rq_clntcred; 586 struct timeval timeout; 587 char buf[ARGSIZE]; 588 589 timeout.tv_sec = 5; 590 timeout.tv_usec = 0; 591 a.rmt_args.args = buf; 592 if (!svc_getargs(xprt, xdr_rmtcall_args, (caddr_t)&a)) 593 return; 594 if (!check_callit(svc_getcaller(xprt), a.rmt_prog, a.rmt_proc)) 595 return; 596 if ((pml = find_service(a.rmt_prog, a.rmt_vers, 597 (u_long)IPPROTO_UDP)) == NULL) 598 return; 599 600 /* 601 * fork a child to do the work. Parent immediately returns. 602 * Child exits upon completion. 603 */ 604 if ((pid = fork()) != 0) { 605 if (pid == -1) 606 syslog(LOG_ERR, "CALLIT (prog %lu): fork: %m", 607 a.rmt_prog); 608 return; 609 } 610 port = pml->pml_map.pm_port; 611 get_myaddress(&me); 612 me.sin_port = htons(port); 613 614 /* Avoid implicit binding to reserved port by clntudp_create() */ 615 so = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); 616 if (so == -1) 617 exit(1); 618 if (ioctl(so, FIONBIO, &dontblock) == -1) 619 exit(1); 620 621 client = clntudp_create(&me, a.rmt_prog, a.rmt_vers, timeout, &so); 622 if (client != NULL) { 623 if (rqstp->rq_cred.oa_flavor == AUTH_UNIX) 624 client->cl_auth = authunix_create(au->aup_machname, 625 au->aup_uid, au->aup_gid, au->aup_len, au->aup_gids); 626 a.rmt_port = (u_long)port; 627 if (clnt_call(client, a.rmt_proc, xdr_opaque_parms, &a, 628 xdr_len_opaque_parms, &a, timeout) == RPC_SUCCESS) 629 svc_sendreply(xprt, xdr_rmtcall_result, (caddr_t)&a); 630 AUTH_DESTROY(client->cl_auth); 631 clnt_destroy(client); 632 } 633 (void)close(so); 634 exit(0); 635 } 636 637 /* ARGSUSED */ 638 void 639 reap(int signo) 640 { 641 int save_errno = errno; 642 643 while (wait3(NULL, WNOHANG, NULL) > 0) 644 ; 645 errno = save_errno; 646 } 647 648 #define NFSPROG ((u_long) 100003) 649 #define MOUNTPROG ((u_long) 100005) 650 #define YPXPROG ((u_long) 100069) 651 #define YPPROG ((u_long) 100004) 652 #define YPPROC_DOMAIN_NONACK ((u_long) 2) 653 #define MOUNTPROC_MNT ((u_long) 1) 654 #define XXXPROC_NOP ((u_long) 0) 655 656 int 657 check_callit(struct sockaddr_in *addr, u_long prog, u_long aproc) 658 { 659 if ((prog == PMAPPROG && aproc != XXXPROC_NOP) || 660 (prog == NFSPROG && aproc != XXXPROC_NOP) || 661 (prog == YPXPROG && aproc != XXXPROC_NOP) || 662 (prog == MOUNTPROG && aproc == MOUNTPROC_MNT) || 663 (prog == YPPROG && aproc != YPPROC_DOMAIN_NONACK)) { 664 syslog(LOG_WARNING, 665 "callit prog %ld aproc %ld (might be from %s)", 666 prog, aproc, inet_ntoa(addr->sin_addr)); 667 return (FALSE); 668 } 669 return (TRUE); 670 } 671