1 /* $NetBSD: rpcinfo.c,v 1.26 2006/05/24 16:04:03 christos Exp $ */ 2 3 /* 4 * Sun RPC is a product of Sun Microsystems, Inc. and is provided for 5 * unrestricted use provided that this legend is included on all tape 6 * media and as a part of the software program in whole or part. Users 7 * may copy or modify Sun RPC without charge, but are not authorized 8 * to license or distribute it to anyone else except as part of a product or 9 * program developed by the user. 10 * 11 * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE 12 * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR 13 * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. 14 * 15 * Sun RPC is provided with no support and without any obligation on the 16 * part of Sun Microsystems, Inc. to assist in its use, correction, 17 * modification or enhancement. 18 * 19 * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE 20 * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC 21 * OR ANY PART THEREOF. 22 * 23 * In no event will Sun Microsystems, Inc. be liable for any lost revenue 24 * or profits or other special, indirect and consequential damages, even if 25 * Sun has been advised of the possibility of such damages. 26 * 27 * Sun Microsystems, Inc. 28 * 2550 Garcia Avenue 29 * Mountain View, California 94043 30 */ 31 32 /* 33 * Copyright (c) 1986 - 1991 by Sun Microsystems, Inc. 34 */ 35 36 /* #ident "@(#)rpcinfo.c 1.18 93/07/05 SMI" */ 37 38 #if 0 39 #ifndef lint 40 static char sccsid[] = "@(#)rpcinfo.c 1.16 89/04/05 Copyr 1986 Sun Micro"; 41 #endif 42 #endif 43 44 /* 45 * rpcinfo: ping a particular rpc program 46 * or dump the registered programs on the remote machine. 47 */ 48 49 /* 50 * We are for now defining PORTMAP here. It doesnt even compile 51 * unless it is defined. 52 */ 53 #ifndef PORTMAP 54 #define PORTMAP 55 #endif 56 57 /* 58 * If PORTMAP is defined, rpcinfo will talk to both portmapper and 59 * rpcbind programs; else it talks only to rpcbind. In the latter case 60 * all the portmapper specific options such as -u, -t, -p become void. 61 */ 62 #include <sys/types.h> 63 #include <sys/socket.h> 64 #include <sys/param.h> 65 #include <sys/un.h> 66 #include <rpc/rpc.h> 67 #include <stdio.h> 68 #include <rpc/rpcb_prot.h> 69 #include <rpc/rpcent.h> 70 #include <rpc/nettype.h> 71 #include <stdlib.h> 72 #include <string.h> 73 #include <unistd.h> 74 #include <err.h> 75 #include <ctype.h> 76 77 #ifdef PORTMAP /* Support for version 2 portmapper */ 78 #include <netinet/in.h> 79 #include <netdb.h> 80 #include <arpa/inet.h> 81 #include <rpc/pmap_prot.h> 82 #include <rpc/pmap_clnt.h> 83 #endif 84 85 #define MIN_VERS ((u_long)0) 86 #define MAX_VERS ((u_long)4294967295UL) 87 #define UNKNOWN "unknown" 88 89 /* 90 * Functions to be performed. 91 */ 92 #define NONE 0 /* no function */ 93 #define PMAPDUMP 1 /* dump portmapper registrations */ 94 #define TCPPING 2 /* ping TCP service */ 95 #define UDPPING 3 /* ping UDP service */ 96 #define BROADCAST 4 /* ping broadcast service */ 97 #define DELETES 5 /* delete registration for the service */ 98 #define ADDRPING 6 /* pings at the given address */ 99 #define PROGPING 7 /* pings a program on a given host */ 100 #define RPCBDUMP 8 /* dump rpcbind registrations */ 101 #define RPCBDUMP_SHORT 9 /* dump rpcbind registrations - short version */ 102 #define RPCBADDRLIST 10 /* dump addr list about one prog */ 103 #define RPCBGETSTAT 11 /* Get statistics */ 104 105 struct netidlist { 106 char *netid; 107 struct netidlist *next; 108 }; 109 110 struct verslist { 111 int vers; 112 struct verslist *next; 113 }; 114 115 struct rpcbdump_short { 116 u_long prog; 117 struct verslist *vlist; 118 struct netidlist *nlist; 119 struct rpcbdump_short *next; 120 char *owner; 121 }; 122 123 124 125 #ifdef PORTMAP 126 static void ip_ping(u_short, char *, int, char **); 127 static CLIENT *clnt_com_create(struct sockaddr_in *, u_long, u_long, int *, 128 char *); 129 static void pmapdump(int, char **); 130 static void get_inet_address(struct sockaddr_in *, char *); 131 #endif 132 133 static bool_t reply_proc(void *, struct netbuf *, struct netconfig *); 134 static void brdcst(int, char **); 135 static void addrping(char *, char *, int, char **); 136 static void progping(char *, int, char **); 137 static CLIENT *clnt_addr_create(char *, struct netconfig *, u_long, u_long); 138 static CLIENT *clnt_rpcbind_create(char *, int, struct netbuf **); 139 static CLIENT *getclnthandle(char *, struct netconfig *, u_long, 140 struct netbuf **); 141 static CLIENT *local_rpcb(u_long, u_long); 142 static int pstatus(CLIENT *, u_long, u_long); 143 static void rpcbdump(int, char *, int, char **); 144 static void rpcbgetstat(int, char **); 145 static void rpcbaddrlist(char *, int, char **); 146 static void deletereg(char *, int, char **); 147 static void print_rmtcallstat(int, rpcb_stat *); 148 static void print_getaddrstat(int, rpcb_stat *); 149 static void usage(void); 150 static u_long getprognum(char *); 151 static u_long getvers(char *); 152 static char *spaces(int); 153 static bool_t add_version(struct rpcbdump_short *, u_long); 154 static bool_t add_netid(struct rpcbdump_short *, char *); 155 156 int main(int argc, char **argv); 157 158 int 159 main(argc, argv) 160 int argc; 161 char **argv; 162 { 163 register int c; 164 int errflg; 165 int function; 166 char *netid = NULL; 167 char *address = NULL; 168 #ifdef PORTMAP 169 char *strptr; 170 u_short portnum = 0; 171 #endif 172 173 function = NONE; 174 errflg = 0; 175 #ifdef PORTMAP 176 while ((c = getopt(argc, argv, "a:bdlmn:pstT:u")) != -1) { 177 #else 178 while ((c = getopt(argc, argv, "a:bdlmn:sT:")) != -1) { 179 #endif 180 switch (c) { 181 #ifdef PORTMAP 182 case 'p': 183 if (function != NONE) 184 errflg = 1; 185 else 186 function = PMAPDUMP; 187 break; 188 189 case 't': 190 if (function != NONE) 191 errflg = 1; 192 else 193 function = TCPPING; 194 break; 195 196 case 'u': 197 if (function != NONE) 198 errflg = 1; 199 else 200 function = UDPPING; 201 break; 202 203 case 'n': 204 portnum = (u_short) strtol(optarg, &strptr, 10); 205 if (strptr == optarg || *strptr != '\0') 206 errx(1, "Illegal port number `%s'", optarg); 207 break; 208 #endif 209 case 'a': 210 address = optarg; 211 if (function != NONE) 212 errflg = 1; 213 else 214 function = ADDRPING; 215 break; 216 case 'b': 217 if (function != NONE) 218 errflg = 1; 219 else 220 function = BROADCAST; 221 break; 222 223 case 'd': 224 if (function != NONE) 225 errflg = 1; 226 else 227 function = DELETES; 228 break; 229 230 case 'l': 231 if (function != NONE) 232 errflg = 1; 233 else 234 function = RPCBADDRLIST; 235 break; 236 237 case 'm': 238 if (function != NONE) 239 errflg = 1; 240 else 241 function = RPCBGETSTAT; 242 break; 243 244 case 's': 245 if (function != NONE) 246 errflg = 1; 247 else 248 function = RPCBDUMP_SHORT; 249 break; 250 251 case 'T': 252 netid = optarg; 253 break; 254 case '?': 255 errflg = 1; 256 break; 257 } 258 } 259 260 if (errflg || ((function == ADDRPING) && !netid)) { 261 usage(); 262 return (1); 263 } 264 265 if (function == NONE) { 266 if (argc - optind > 1) 267 function = PROGPING; 268 else 269 function = RPCBDUMP; 270 } 271 272 switch (function) { 273 #ifdef PORTMAP 274 case PMAPDUMP: 275 if (portnum != 0) { 276 usage(); 277 return (1); 278 } 279 pmapdump(argc - optind, argv + optind); 280 break; 281 282 case UDPPING: 283 ip_ping(portnum, "udp", argc - optind, argv + optind); 284 break; 285 286 case TCPPING: 287 ip_ping(portnum, "tcp", argc - optind, argv + optind); 288 break; 289 #endif 290 case BROADCAST: 291 brdcst(argc - optind, argv + optind); 292 break; 293 case DELETES: 294 deletereg(netid, argc - optind, argv + optind); 295 break; 296 case ADDRPING: 297 addrping(address, netid, argc - optind, argv + optind); 298 break; 299 case PROGPING: 300 progping(netid, argc - optind, argv + optind); 301 break; 302 case RPCBDUMP: 303 case RPCBDUMP_SHORT: 304 rpcbdump(function, netid, argc - optind, argv + optind); 305 break; 306 case RPCBGETSTAT: 307 rpcbgetstat(argc - optind, argv + optind); 308 break; 309 case RPCBADDRLIST: 310 rpcbaddrlist(netid, argc - optind, argv + optind); 311 break; 312 } 313 return (0); 314 } 315 316 static CLIENT * 317 local_rpcb(prog, vers) 318 u_long prog, vers; 319 { 320 struct netbuf nbuf; 321 struct sockaddr_un sun; 322 int sock; 323 324 memset(&sun, 0, sizeof sun); 325 sock = socket(AF_LOCAL, SOCK_STREAM, 0); 326 if (sock < 0) 327 return NULL; 328 329 sun.sun_family = AF_LOCAL; 330 strcpy(sun.sun_path, _PATH_RPCBINDSOCK); 331 nbuf.len = sun.sun_len = SUN_LEN(&sun); 332 nbuf.maxlen = sizeof (struct sockaddr_un); 333 nbuf.buf = &sun; 334 335 return clnt_vc_create(sock, &nbuf, prog, vers, 0, 0); 336 } 337 338 #ifdef PORTMAP 339 static CLIENT * 340 clnt_com_create(addr, prog, vers, fdp, trans) 341 struct sockaddr_in *addr; 342 u_long prog; 343 u_long vers; 344 int *fdp; 345 char *trans; 346 { 347 CLIENT *clnt; 348 349 if (strcmp(trans, "tcp") == 0) { 350 clnt = clnttcp_create(addr, prog, vers, fdp, 0, 0); 351 } else { 352 struct timeval to; 353 354 to.tv_sec = 5; 355 to.tv_usec = 0; 356 clnt = clntudp_create(addr, prog, vers, to, fdp); 357 } 358 if (clnt == NULL) { 359 clnt_pcreateerror(getprogname()); 360 if (vers == MIN_VERS) 361 printf("program %lu is not available\n", prog); 362 else 363 printf("program %lu version %lu is not available\n", 364 prog, vers); 365 exit(1); 366 } 367 return (clnt); 368 } 369 370 /* 371 * If portnum is 0, then go and get the address from portmapper, which happens 372 * transparently through clnt*_create(); If version number is not given, it 373 * tries to find out the version number by making a call to version 0 and if 374 * that fails, it obtains the high order and the low order version number. If 375 * version 0 calls succeeds, it tries for MAXVERS call and repeats the same. 376 */ 377 static void 378 ip_ping(portnum, trans, argc, argv) 379 u_short portnum; 380 char *trans; 381 int argc; 382 char **argv; 383 { 384 CLIENT *client; 385 int fd = RPC_ANYFD; 386 struct timeval to; 387 struct sockaddr_in addr; 388 enum clnt_stat rpc_stat; 389 u_long prognum, vers, minvers, maxvers; 390 struct rpc_err rpcerr; 391 int failure = 0; 392 393 if (argc < 2 || argc > 3) { 394 usage(); 395 exit(1); 396 } 397 to.tv_sec = 10; 398 to.tv_usec = 0; 399 prognum = getprognum(argv[1]); 400 get_inet_address(&addr, argv[0]); 401 if (argc == 2) { /* Version number not known */ 402 /* 403 * A call to version 0 should fail with a program/version 404 * mismatch, and give us the range of versions supported. 405 */ 406 vers = MIN_VERS; 407 } else { 408 vers = getvers(argv[2]); 409 } 410 addr.sin_port = htons(portnum); 411 client = clnt_com_create(&addr, prognum, vers, &fd, trans); 412 rpc_stat = CLNT_CALL(client, NULLPROC, (xdrproc_t) xdr_void, 413 NULL, (xdrproc_t) xdr_void, NULL, to); 414 if (argc != 2) { 415 /* Version number was known */ 416 if (pstatus(client, prognum, vers) < 0) 417 exit(1); 418 (void) CLNT_DESTROY(client); 419 return; 420 } 421 /* Version number not known */ 422 (void) CLNT_CONTROL(client, CLSET_FD_NCLOSE, NULL); 423 if (rpc_stat == RPC_PROGVERSMISMATCH) { 424 clnt_geterr(client, &rpcerr); 425 minvers = rpcerr.re_vers.low; 426 maxvers = rpcerr.re_vers.high; 427 } else if (rpc_stat == RPC_SUCCESS) { 428 /* 429 * Oh dear, it DOES support version 0. 430 * Let's try version MAX_VERS. 431 */ 432 (void) CLNT_DESTROY(client); 433 addr.sin_port = htons(portnum); 434 client = clnt_com_create(&addr, prognum, MAX_VERS, &fd, trans); 435 rpc_stat = CLNT_CALL(client, NULLPROC, (xdrproc_t) xdr_void, 436 NULL, (xdrproc_t) xdr_void, NULL, to); 437 if (rpc_stat == RPC_PROGVERSMISMATCH) { 438 clnt_geterr(client, &rpcerr); 439 minvers = rpcerr.re_vers.low; 440 maxvers = rpcerr.re_vers.high; 441 } else if (rpc_stat == RPC_SUCCESS) { 442 /* 443 * It also supports version MAX_VERS. 444 * Looks like we have a wise guy. 445 * OK, we give them information on all 446 * 4 billion versions they support... 447 */ 448 minvers = 0; 449 maxvers = MAX_VERS; 450 } else { 451 (void) pstatus(client, prognum, MAX_VERS); 452 exit(1); 453 } 454 } else { 455 (void) pstatus(client, prognum, (u_long)0); 456 exit(1); 457 } 458 (void) CLNT_DESTROY(client); 459 for (vers = minvers; vers <= maxvers; vers++) { 460 addr.sin_port = htons(portnum); 461 client = clnt_com_create(&addr, prognum, vers, &fd, trans); 462 rpc_stat = CLNT_CALL(client, NULLPROC, (xdrproc_t) xdr_void, 463 NULL, (xdrproc_t) xdr_void, NULL, to); 464 if (pstatus(client, prognum, vers) < 0) 465 failure = 1; 466 (void) CLNT_DESTROY(client); 467 } 468 if (failure) 469 exit(1); 470 (void) close(fd); 471 return; 472 } 473 474 /* 475 * Dump all the portmapper registerations 476 */ 477 static void 478 pmapdump(argc, argv) 479 int argc; 480 char **argv; 481 { 482 struct sockaddr_in server_addr; 483 struct pmaplist *head = NULL; 484 int socket = RPC_ANYSOCK; 485 struct timeval minutetimeout; 486 register CLIENT *client; 487 struct rpcent *rpc; 488 enum clnt_stat clnt_st; 489 struct rpc_err error; 490 char *host = NULL; 491 492 if (argc > 1) { 493 usage(); 494 exit(1); 495 } 496 if (argc == 1) { 497 host = argv[0]; 498 get_inet_address(&server_addr, host); 499 server_addr.sin_port = htons(PMAPPORT); 500 client = clnttcp_create(&server_addr, PMAPPROG, PMAPVERS, 501 &socket, 50, 500); 502 } else 503 client = local_rpcb(PMAPPROG, PMAPVERS); 504 505 if (client == NULL) { 506 if (rpc_createerr.cf_stat == RPC_TLIERROR) { 507 /* 508 * "Misc. TLI error" is not too helpful. Most likely 509 * the connection to the remote server timed out, so 510 * this error is at least less perplexing. 511 */ 512 rpc_createerr.cf_stat = RPC_PMAPFAILURE; 513 rpc_createerr.cf_error.re_status = RPC_FAILED; 514 } 515 clnt_pcreateerror("rpcinfo: can't contact portmapper"); 516 exit(1); 517 } 518 519 minutetimeout.tv_sec = 60; 520 minutetimeout.tv_usec = 0; 521 522 clnt_st = CLNT_CALL(client, PMAPPROC_DUMP, (xdrproc_t) xdr_void, 523 NULL, (xdrproc_t) xdr_pmaplist_ptr, (char *)&head, 524 minutetimeout); 525 if (clnt_st != RPC_SUCCESS) { 526 if ((clnt_st == RPC_PROGVERSMISMATCH) || 527 (clnt_st == RPC_PROGUNAVAIL)) { 528 CLNT_GETERR(client, &error); 529 if (error.re_vers.low > PMAPVERS) { 530 if (host) 531 fprintf(stderr, 532 "%s does not support portmapper. Try 'rpcinfo %s' instead\n", 533 host, host); 534 else 535 fprintf(stderr, 536 "local host does not support portmapper. Try 'rpcinfo' instead\n"); 537 } 538 exit(1); 539 } 540 clnt_perror(client, "rpcinfo: can't contact portmapper"); 541 exit(1); 542 } 543 if (head == NULL) { 544 printf("No remote programs registered.\n"); 545 } else { 546 printf(" program vers proto port service\n"); 547 for (; head != NULL; head = head->pml_next) { 548 printf("%10ld%5ld", 549 head->pml_map.pm_prog, 550 head->pml_map.pm_vers); 551 if (head->pml_map.pm_prot == IPPROTO_UDP) 552 printf("%6s", "udp"); 553 else if (head->pml_map.pm_prot == IPPROTO_TCP) 554 printf("%6s", "tcp"); 555 else 556 printf("%6ld", head->pml_map.pm_prot); 557 printf("%7ld", head->pml_map.pm_port); 558 rpc = getrpcbynumber(head->pml_map.pm_prog); 559 if (rpc) 560 printf(" %s\n", rpc->r_name); 561 else 562 printf("\n"); 563 } 564 } 565 } 566 567 static void 568 get_inet_address(addr, host) 569 struct sockaddr_in *addr; 570 char *host; 571 { 572 struct netconfig *nconf; 573 struct addrinfo hints, *res; 574 int error; 575 576 (void) memset((char *)addr, 0, sizeof (*addr)); 577 addr->sin_addr.s_addr = inet_addr(host); 578 if (addr->sin_addr.s_addr == -1 || addr->sin_addr.s_addr == 0) { 579 if ((nconf = __rpc_getconfip("udp")) == NULL && 580 (nconf = __rpc_getconfip("tcp")) == NULL) { 581 errx(1, "Couldn't find a suitable transport"); 582 } else { 583 memset(&hints, 0, sizeof hints); 584 hints.ai_family = AF_INET; 585 if ((error = getaddrinfo(host, "rpcbind", &hints, &res)) 586 != 0) { 587 errx(1, "%s: %s", host, gai_strerror(error)); 588 } else { 589 memcpy(addr, res->ai_addr, res->ai_addrlen); 590 freeaddrinfo(res); 591 } 592 (void) freenetconfigent(nconf); 593 } 594 } else { 595 addr->sin_family = AF_INET; 596 } 597 } 598 #endif /* PORTMAP */ 599 600 /* 601 * reply_proc collects replies from the broadcast. 602 * to get a unique list of responses the output of rpcinfo should 603 * be piped through sort(1) and then uniq(1). 604 */ 605 606 /*ARGSUSED*/ 607 static bool_t 608 reply_proc(res, who, nconf) 609 void *res; /* Nothing comes back */ 610 struct netbuf *who; /* Who sent us the reply */ 611 struct netconfig *nconf; /* On which transport the reply came */ 612 { 613 char *uaddr; 614 char hostbuf[NI_MAXHOST]; 615 char *hostname; 616 struct sockaddr *sa = (struct sockaddr *)who->buf; 617 618 if (getnameinfo(sa, sa->sa_len, hostbuf, NI_MAXHOST, NULL, 0, 0)) { 619 hostname = UNKNOWN; 620 } else { 621 hostname = hostbuf; 622 } 623 if (!(uaddr = taddr2uaddr(nconf, who))) { 624 uaddr = UNKNOWN; 625 } 626 printf("%s\t%s\n", uaddr, hostname); 627 if (strcmp(uaddr, UNKNOWN)) 628 free((char *)uaddr); 629 return (FALSE); 630 } 631 632 static void 633 brdcst(argc, argv) 634 int argc; 635 char **argv; 636 { 637 enum clnt_stat rpc_stat; 638 u_long prognum, vers; 639 640 if (argc != 2) { 641 usage(); 642 exit(1); 643 } 644 prognum = getprognum(argv[0]); 645 vers = getvers(argv[1]); 646 rpc_stat = rpc_broadcast(prognum, vers, NULLPROC, 647 (xdrproc_t) xdr_void, NULL, (xdrproc_t) xdr_void, 648 NULL, (resultproc_t) reply_proc, NULL); 649 if ((rpc_stat != RPC_SUCCESS) && (rpc_stat != RPC_TIMEDOUT)) 650 errx(1, "broadcast failed: %s", clnt_sperrno(rpc_stat)); 651 exit(0); 652 } 653 654 static bool_t 655 add_version(rs, vers) 656 struct rpcbdump_short *rs; 657 u_long vers; 658 { 659 struct verslist *vl; 660 661 for (vl = rs->vlist; vl; vl = vl->next) 662 if (vl->vers == vers) 663 break; 664 if (vl) 665 return (TRUE); 666 vl = malloc(sizeof (struct verslist)); 667 if (vl == NULL) 668 return (FALSE); 669 vl->vers = vers; 670 vl->next = rs->vlist; 671 rs->vlist = vl; 672 return (TRUE); 673 } 674 675 static bool_t 676 add_netid(rs, netid) 677 struct rpcbdump_short *rs; 678 char *netid; 679 { 680 struct netidlist *nl; 681 682 for (nl = rs->nlist; nl; nl = nl->next) 683 if (strcmp(nl->netid, netid) == 0) 684 break; 685 if (nl) 686 return (TRUE); 687 nl = malloc(sizeof (struct netidlist)); 688 if (nl == NULL) 689 return (FALSE); 690 nl->netid = netid; 691 nl->next = rs->nlist; 692 rs->nlist = nl; 693 return (TRUE); 694 } 695 696 static void 697 rpcbdump(dumptype, netid, argc, argv) 698 int dumptype; 699 char *netid; 700 int argc; 701 char **argv; 702 { 703 rpcblist_ptr head = NULL, p; 704 struct timeval minutetimeout; 705 register CLIENT *client = NULL; 706 struct rpcent *rpc; 707 char *host; 708 struct netidlist *nl; 709 struct verslist *vl; 710 struct rpcbdump_short *rs, *rs_tail = NULL; 711 char buf[256]; 712 enum clnt_stat clnt_st; 713 struct rpc_err error; 714 struct rpcbdump_short *rs_head = NULL; 715 716 if (argc > 1) { 717 usage(); 718 exit(1); 719 } 720 if (argc == 1) { 721 host = argv[0]; 722 if (netid == NULL) { 723 client = clnt_rpcbind_create(host, RPCBVERS, NULL); 724 } else { 725 struct netconfig *nconf; 726 727 nconf = getnetconfigent(netid); 728 if (nconf == NULL) { 729 nc_perror("rpcinfo: invalid transport"); 730 exit(1); 731 } 732 client = getclnthandle(host, nconf, RPCBVERS, NULL); 733 if (nconf) 734 (void) freenetconfigent(nconf); 735 } 736 } else 737 client = local_rpcb(PMAPPROG, RPCBVERS); 738 739 if (client == NULL) { 740 clnt_pcreateerror("rpcinfo: can't contact rpcbind"); 741 exit(1); 742 } 743 minutetimeout.tv_sec = 60; 744 minutetimeout.tv_usec = 0; 745 clnt_st = CLNT_CALL(client, RPCBPROC_DUMP, (xdrproc_t) xdr_void, 746 NULL, (xdrproc_t) xdr_rpcblist_ptr, (char *) &head, 747 minutetimeout); 748 if (clnt_st != RPC_SUCCESS) { 749 if ((clnt_st == RPC_PROGVERSMISMATCH) || 750 (clnt_st == RPC_PROGUNAVAIL)) { 751 int vers; 752 753 CLNT_GETERR(client, &error); 754 if (error.re_vers.low == RPCBVERS4) { 755 vers = RPCBVERS4; 756 clnt_control(client, CLSET_VERS, (char *)&vers); 757 clnt_st = CLNT_CALL(client, RPCBPROC_DUMP, 758 (xdrproc_t) xdr_void, NULL, 759 (xdrproc_t) xdr_rpcblist_ptr, (char *) &head, 760 minutetimeout); 761 if (clnt_st != RPC_SUCCESS) 762 goto failed; 763 } else { 764 if (error.re_vers.high == PMAPVERS) { 765 int high, low; 766 struct pmaplist *pmaphead = NULL; 767 rpcblist_ptr list, prev = NULL; 768 769 vers = PMAPVERS; 770 clnt_control(client, CLSET_VERS, (char *)&vers); 771 clnt_st = CLNT_CALL(client, PMAPPROC_DUMP, 772 (xdrproc_t) xdr_void, NULL, 773 (xdrproc_t) xdr_pmaplist_ptr, 774 (char *)&pmaphead, minutetimeout); 775 if (clnt_st != RPC_SUCCESS) 776 goto failed; 777 /* 778 * convert to rpcblist_ptr format 779 */ 780 for (head = NULL; pmaphead != NULL; 781 pmaphead = pmaphead->pml_next) { 782 list = malloc(sizeof (rpcblist)); 783 if (list == NULL) 784 goto error; 785 if (head == NULL) 786 head = list; 787 else 788 prev->rpcb_next = (rpcblist_ptr) list; 789 790 list->rpcb_next = NULL; 791 list->rpcb_map.r_prog = pmaphead->pml_map.pm_prog; 792 list->rpcb_map.r_vers = pmaphead->pml_map.pm_vers; 793 if (pmaphead->pml_map.pm_prot == IPPROTO_UDP) 794 list->rpcb_map.r_netid = strdup("udp"); 795 else if (pmaphead->pml_map.pm_prot == IPPROTO_TCP) 796 list->rpcb_map.r_netid = strdup("tcp"); 797 else { 798 #define MAXLONG_AS_STRING "2147483648" 799 list->rpcb_map.r_netid = 800 malloc(strlen(MAXLONG_AS_STRING) + 1); 801 if (list->rpcb_map.r_netid == NULL) 802 goto error; 803 sprintf(list->rpcb_map.r_netid, "%6ld", 804 pmaphead->pml_map.pm_prot); 805 } 806 list->rpcb_map.r_owner = UNKNOWN; 807 low = pmaphead->pml_map.pm_port & 0xff; 808 high = (pmaphead->pml_map.pm_port >> 8) & 0xff; 809 list->rpcb_map.r_addr = strdup("0.0.0.0.XXX.XXX"); 810 sprintf(&list->rpcb_map.r_addr[8], "%d.%d", 811 high, low); 812 prev = list; 813 } 814 } 815 } 816 } else { /* any other error */ 817 failed: 818 clnt_perror(client, "rpcinfo: can't contact rpcbind: "); 819 exit(1); 820 } 821 } 822 if (head == NULL) { 823 printf("No remote programs registered.\n"); 824 } else if (dumptype == RPCBDUMP) { 825 printf( 826 " program version netid address service owner\n"); 827 for (p = head; p != NULL; p = p->rpcb_next) { 828 printf("%10u%5u ", 829 p->rpcb_map.r_prog, p->rpcb_map.r_vers); 830 printf("%-9s ", p->rpcb_map.r_netid); 831 printf("%-22s", p->rpcb_map.r_addr); 832 rpc = getrpcbynumber(p->rpcb_map.r_prog); 833 if (rpc) 834 printf(" %-10s", rpc->r_name); 835 else 836 printf(" %-10s", "-"); 837 printf(" %s\n", p->rpcb_map.r_owner); 838 } 839 } else if (dumptype == RPCBDUMP_SHORT) { 840 for (p = head; p != NULL; p = p->rpcb_next) { 841 for (rs = rs_head; rs; rs = rs->next) 842 if (p->rpcb_map.r_prog == rs->prog) 843 break; 844 if (rs == NULL) { 845 rs = malloc(sizeof (struct rpcbdump_short)); 846 if (rs == NULL) 847 goto error; 848 rs->next = NULL; 849 if (rs_head == NULL) { 850 rs_head = rs; 851 rs_tail = rs; 852 } else { 853 rs_tail->next = rs; 854 rs_tail = rs; 855 } 856 rs->prog = head->rpcb_map.r_prog; 857 rs->owner = head->rpcb_map.r_owner; 858 rs->nlist = NULL; 859 rs->vlist = NULL; 860 } 861 if (add_version(rs, p->rpcb_map.r_vers) == FALSE) 862 goto error; 863 if (add_netid(rs, p->rpcb_map.r_netid) == FALSE) 864 goto error; 865 } 866 printf( 867 " program version(s) netid(s) service owner\n"); 868 for (rs = rs_head; rs; rs = rs->next) { 869 char *p = buf; 870 871 printf("%10ld ", rs->prog); 872 for (vl = rs->vlist; vl; vl = vl->next) { 873 sprintf(p, "%d", vl->vers); 874 p = p + strlen(p); 875 if (vl->next) 876 sprintf(p++, ","); 877 } 878 printf("%-10s", buf); 879 buf[0] = 0; 880 for (nl = rs->nlist; nl; nl = nl->next) { 881 strcat(buf, nl->netid); 882 if (nl->next) 883 strcat(buf, ","); 884 } 885 printf("%-32s", buf); 886 rpc = getrpcbynumber(rs->prog); 887 if (rpc) 888 printf(" %-11s", rpc->r_name); 889 else 890 printf(" %-11s", "-"); 891 printf(" %s\n", rs->owner); 892 } 893 } 894 if (client) 895 clnt_destroy(client); 896 while (head != NULL) { 897 rpcblist_ptr list = head->rpcb_next; 898 if (head->rpcb_map.r_addr) 899 free(head->rpcb_map.r_addr); 900 if (head->rpcb_map.r_netid) 901 free(head->rpcb_map.r_netid); 902 free(head); 903 head = list; 904 } 905 while (rs_head) { 906 rs = rs_head; 907 rs_head = rs_head->next; 908 free(rs); 909 } 910 return; 911 error: err(1, "Cannot allocate memory"); 912 } 913 914 static char nullstring[] = "\000"; 915 916 static void 917 rpcbaddrlist(netid, argc, argv) 918 char *netid; 919 int argc; 920 char **argv; 921 { 922 rpcb_entry_list_ptr head = NULL; 923 struct timeval minutetimeout; 924 register CLIENT *client; 925 struct rpcent *rpc; 926 char *host; 927 RPCB parms; 928 struct netbuf *targaddr; 929 930 if (argc != 3) { 931 usage(); 932 exit(1); 933 } 934 host = argv[0]; 935 if (netid == NULL) { 936 client = clnt_rpcbind_create(host, RPCBVERS4, &targaddr); 937 } else { 938 struct netconfig *nconf; 939 940 nconf = getnetconfigent(netid); 941 if (nconf == NULL) { 942 nc_perror("rpcinfo: invalid transport"); 943 exit(1); 944 } 945 client = getclnthandle(host, nconf, RPCBVERS4, &targaddr); 946 if (nconf) 947 (void) freenetconfigent(nconf); 948 } 949 if (client == NULL) { 950 clnt_pcreateerror("rpcinfo: can't contact rpcbind"); 951 exit(1); 952 } 953 minutetimeout.tv_sec = 60; 954 minutetimeout.tv_usec = 0; 955 956 parms.r_prog = getprognum(argv[1]); 957 parms.r_vers = getvers(argv[2]); 958 parms.r_netid = client->cl_netid; 959 if (targaddr == NULL) { 960 parms.r_addr = nullstring; /* for XDRing */ 961 } else { 962 /* 963 * We also send the remote system the address we 964 * used to contact it in case it can help it 965 * connect back with us 966 */ 967 struct netconfig *nconf; 968 969 nconf = getnetconfigent(client->cl_netid); 970 if (nconf != NULL) { 971 parms.r_addr = taddr2uaddr(nconf, targaddr); 972 if (parms.r_addr == NULL) 973 parms.r_addr = nullstring; 974 freenetconfigent(nconf); 975 } else { 976 parms.r_addr = nullstring; /* for XDRing */ 977 } 978 free(targaddr->buf); 979 free(targaddr); 980 } 981 parms.r_owner = nullstring; 982 983 if (CLNT_CALL(client, RPCBPROC_GETADDRLIST, (xdrproc_t) xdr_rpcb, 984 (char *) &parms, (xdrproc_t) xdr_rpcb_entry_list_ptr, 985 (char *) &head, minutetimeout) != RPC_SUCCESS) { 986 clnt_perror(client, "rpcinfo: can't contact rpcbind: "); 987 exit(1); 988 } 989 if (head == NULL) { 990 printf("No remote programs registered.\n"); 991 } else { 992 printf( 993 " program vers tp_family/name/class address\t\t service\n"); 994 for (; head != NULL; head = head->rpcb_entry_next) { 995 rpcb_entry *re; 996 char buf[128]; 997 998 re = &head->rpcb_entry_map; 999 printf("%10u%3u ", 1000 parms.r_prog, parms.r_vers); 1001 sprintf(buf, "%s/%s/%s ", 1002 re->r_nc_protofmly, re->r_nc_proto, 1003 re->r_nc_semantics == NC_TPI_CLTS ? "clts" : 1004 re->r_nc_semantics == NC_TPI_COTS ? "cots" : 1005 "cots_ord"); 1006 printf("%-24s", buf); 1007 printf("%-24s", re->r_maddr); 1008 rpc = getrpcbynumber(parms.r_prog); 1009 if (rpc) 1010 printf(" %-13s", rpc->r_name); 1011 else 1012 printf(" %-13s", "-"); 1013 printf("\n"); 1014 } 1015 } 1016 clnt_destroy(client); 1017 return; 1018 } 1019 1020 /* 1021 * monitor rpcbind 1022 */ 1023 static void 1024 rpcbgetstat(argc, argv) 1025 int argc; 1026 char **argv; 1027 { 1028 rpcb_stat_byvers inf; 1029 struct timeval minutetimeout; 1030 register CLIENT *client; 1031 char *host; 1032 int i, j; 1033 rpcbs_addrlist *pa; 1034 rpcbs_rmtcalllist *pr; 1035 int cnt, flen; 1036 #define MAXFIELD 64 1037 char fieldbuf[MAXFIELD]; 1038 #define MAXLINE 256 1039 char linebuf[MAXLINE]; 1040 char *cp, *lp; 1041 char *pmaphdr[] = { 1042 "NULL", "SET", "UNSET", "GETPORT", 1043 "DUMP", "CALLIT" 1044 }; 1045 char *rpcb3hdr[] = { 1046 "NULL", "SET", "UNSET", "GETADDR", "DUMP", "CALLIT", "TIME", 1047 "U2T", "T2U" 1048 }; 1049 char *rpcb4hdr[] = { 1050 "NULL", "SET", "UNSET", "GETADDR", "DUMP", "CALLIT", "TIME", 1051 "U2T", "T2U", "VERADDR", "INDRECT", "GETLIST", "GETSTAT" 1052 }; 1053 1054 #define TABSTOP 8 1055 1056 if (argc >= 1) { 1057 host = argv[0]; 1058 client = clnt_rpcbind_create(host, RPCBVERS4, NULL); 1059 } else 1060 client = local_rpcb(PMAPPROG, RPCBVERS4); 1061 if (client == NULL) { 1062 clnt_pcreateerror("rpcinfo: can't contact rpcbind"); 1063 exit(1); 1064 } 1065 minutetimeout.tv_sec = 60; 1066 minutetimeout.tv_usec = 0; 1067 memset((char *)&inf, 0, sizeof (rpcb_stat_byvers)); 1068 if (CLNT_CALL(client, RPCBPROC_GETSTAT, (xdrproc_t) xdr_void, NULL, 1069 (xdrproc_t) xdr_rpcb_stat_byvers, (char *)&inf, minutetimeout) 1070 != RPC_SUCCESS) { 1071 clnt_perror(client, "rpcinfo: can't contact rpcbind: "); 1072 exit(1); 1073 } 1074 printf("PORTMAP (version 2) statistics\n"); 1075 lp = linebuf; 1076 for (i = 0; i <= rpcb_highproc_2; i++) { 1077 fieldbuf[0] = '\0'; 1078 switch (i) { 1079 case PMAPPROC_SET: 1080 sprintf(fieldbuf, "%d/", inf[RPCBVERS_2_STAT].setinfo); 1081 break; 1082 case PMAPPROC_UNSET: 1083 sprintf(fieldbuf, "%d/", 1084 inf[RPCBVERS_2_STAT].unsetinfo); 1085 break; 1086 case PMAPPROC_GETPORT: 1087 cnt = 0; 1088 for (pa = inf[RPCBVERS_2_STAT].addrinfo; pa; 1089 pa = pa->next) 1090 cnt += pa->success; 1091 sprintf(fieldbuf, "%d/", cnt); 1092 break; 1093 case PMAPPROC_CALLIT: 1094 cnt = 0; 1095 for (pr = inf[RPCBVERS_2_STAT].rmtinfo; pr; 1096 pr = pr->next) 1097 cnt += pr->success; 1098 sprintf(fieldbuf, "%d/", cnt); 1099 break; 1100 default: break; /* For the remaining ones */ 1101 } 1102 cp = &fieldbuf[0] + strlen(fieldbuf); 1103 sprintf(cp, "%d", inf[RPCBVERS_2_STAT].info[i]); 1104 flen = strlen(fieldbuf); 1105 printf("%s%s", pmaphdr[i], 1106 spaces((TABSTOP * (1 + flen / TABSTOP)) 1107 - strlen(pmaphdr[i]))); 1108 sprintf(lp, "%s%s", fieldbuf, 1109 spaces(cnt = ((TABSTOP * (1 + flen / TABSTOP)) 1110 - flen))); 1111 lp += (flen + cnt); 1112 } 1113 printf("\n%s\n\n", linebuf); 1114 1115 if (inf[RPCBVERS_2_STAT].info[PMAPPROC_CALLIT]) { 1116 printf("PMAP_RMTCALL call statistics\n"); 1117 print_rmtcallstat(RPCBVERS_2_STAT, &inf[RPCBVERS_2_STAT]); 1118 printf("\n"); 1119 } 1120 1121 if (inf[RPCBVERS_2_STAT].info[PMAPPROC_GETPORT]) { 1122 printf("PMAP_GETPORT call statistics\n"); 1123 print_getaddrstat(RPCBVERS_2_STAT, &inf[RPCBVERS_2_STAT]); 1124 printf("\n"); 1125 } 1126 1127 printf("RPCBIND (version 3) statistics\n"); 1128 lp = linebuf; 1129 for (i = 0; i <= rpcb_highproc_3; i++) { 1130 fieldbuf[0] = '\0'; 1131 switch (i) { 1132 case RPCBPROC_SET: 1133 sprintf(fieldbuf, "%d/", inf[RPCBVERS_3_STAT].setinfo); 1134 break; 1135 case RPCBPROC_UNSET: 1136 sprintf(fieldbuf, "%d/", 1137 inf[RPCBVERS_3_STAT].unsetinfo); 1138 break; 1139 case RPCBPROC_GETADDR: 1140 cnt = 0; 1141 for (pa = inf[RPCBVERS_3_STAT].addrinfo; pa; 1142 pa = pa->next) 1143 cnt += pa->success; 1144 sprintf(fieldbuf, "%d/", cnt); 1145 break; 1146 case RPCBPROC_CALLIT: 1147 cnt = 0; 1148 for (pr = inf[RPCBVERS_3_STAT].rmtinfo; pr; 1149 pr = pr->next) 1150 cnt += pr->success; 1151 sprintf(fieldbuf, "%d/", cnt); 1152 break; 1153 default: break; /* For the remaining ones */ 1154 } 1155 cp = &fieldbuf[0] + strlen(fieldbuf); 1156 sprintf(cp, "%d", inf[RPCBVERS_3_STAT].info[i]); 1157 flen = strlen(fieldbuf); 1158 printf("%s%s", rpcb3hdr[i], 1159 spaces((TABSTOP * (1 + flen / TABSTOP)) 1160 - strlen(rpcb3hdr[i]))); 1161 sprintf(lp, "%s%s", fieldbuf, 1162 spaces(cnt = ((TABSTOP * (1 + flen / TABSTOP)) 1163 - flen))); 1164 lp += (flen + cnt); 1165 } 1166 printf("\n%s\n\n", linebuf); 1167 1168 if (inf[RPCBVERS_3_STAT].info[RPCBPROC_CALLIT]) { 1169 printf("RPCB_RMTCALL (version 3) call statistics\n"); 1170 print_rmtcallstat(RPCBVERS_3_STAT, &inf[RPCBVERS_3_STAT]); 1171 printf("\n"); 1172 } 1173 1174 if (inf[RPCBVERS_3_STAT].info[RPCBPROC_GETADDR]) { 1175 printf("RPCB_GETADDR (version 3) call statistics\n"); 1176 print_getaddrstat(RPCBVERS_3_STAT, &inf[RPCBVERS_3_STAT]); 1177 printf("\n"); 1178 } 1179 1180 printf("RPCBIND (version 4) statistics\n"); 1181 1182 for (j = 0; j <= 9; j += 9) { /* Just two iterations for printing */ 1183 lp = linebuf; 1184 for (i = j; i <= MAX(8, rpcb_highproc_4 - 9 + j); i++) { 1185 fieldbuf[0] = '\0'; 1186 switch (i) { 1187 case RPCBPROC_SET: 1188 sprintf(fieldbuf, "%d/", 1189 inf[RPCBVERS_4_STAT].setinfo); 1190 break; 1191 case RPCBPROC_UNSET: 1192 sprintf(fieldbuf, "%d/", 1193 inf[RPCBVERS_4_STAT].unsetinfo); 1194 break; 1195 case RPCBPROC_GETADDR: 1196 cnt = 0; 1197 for (pa = inf[RPCBVERS_4_STAT].addrinfo; pa; 1198 pa = pa->next) 1199 cnt += pa->success; 1200 sprintf(fieldbuf, "%d/", cnt); 1201 break; 1202 case RPCBPROC_CALLIT: 1203 cnt = 0; 1204 for (pr = inf[RPCBVERS_4_STAT].rmtinfo; pr; 1205 pr = pr->next) 1206 cnt += pr->success; 1207 sprintf(fieldbuf, "%d/", cnt); 1208 break; 1209 default: break; /* For the remaining ones */ 1210 } 1211 cp = &fieldbuf[0] + strlen(fieldbuf); 1212 /* 1213 * XXX: We also add RPCBPROC_GETADDRLIST queries to 1214 * RPCB_GETADDR because rpcbind includes the 1215 * RPCB_GETADDRLIST successes in RPCB_GETADDR. 1216 */ 1217 if (i != RPCBPROC_GETADDR) 1218 sprintf(cp, "%d", inf[RPCBVERS_4_STAT].info[i]); 1219 else 1220 sprintf(cp, "%d", inf[RPCBVERS_4_STAT].info[i] + 1221 inf[RPCBVERS_4_STAT].info[RPCBPROC_GETADDRLIST]); 1222 flen = strlen(fieldbuf); 1223 printf("%s%s", rpcb4hdr[i], 1224 spaces((TABSTOP * (1 + flen / TABSTOP)) 1225 - strlen(rpcb4hdr[i]))); 1226 sprintf(lp, "%s%s", fieldbuf, 1227 spaces(cnt = ((TABSTOP * (1 + flen / TABSTOP)) 1228 - flen))); 1229 lp += (flen + cnt); 1230 } 1231 printf("\n%s\n", linebuf); 1232 } 1233 1234 if (inf[RPCBVERS_4_STAT].info[RPCBPROC_CALLIT] || 1235 inf[RPCBVERS_4_STAT].info[RPCBPROC_INDIRECT]) { 1236 printf("\n"); 1237 printf("RPCB_RMTCALL (version 4) call statistics\n"); 1238 print_rmtcallstat(RPCBVERS_4_STAT, &inf[RPCBVERS_4_STAT]); 1239 } 1240 1241 if (inf[RPCBVERS_4_STAT].info[RPCBPROC_GETADDR]) { 1242 printf("\n"); 1243 printf("RPCB_GETADDR (version 4) call statistics\n"); 1244 print_getaddrstat(RPCBVERS_4_STAT, &inf[RPCBVERS_4_STAT]); 1245 } 1246 clnt_destroy(client); 1247 } 1248 1249 /* 1250 * Delete registeration for this (prog, vers, netid) 1251 */ 1252 static void 1253 deletereg(netid, argc, argv) 1254 char *netid; 1255 int argc; 1256 char **argv; 1257 { 1258 struct netconfig *nconf = NULL; 1259 1260 if (argc != 2) { 1261 usage(); 1262 exit(1); 1263 } 1264 if (netid) { 1265 nconf = getnetconfigent(netid); 1266 if (nconf == NULL) { 1267 fprintf(stderr, "rpcinfo: netid %s not supported\n", 1268 netid); 1269 exit(1); 1270 } 1271 } 1272 if ((rpcb_unset(getprognum(argv[0]), getvers(argv[1]), nconf)) == 0) { 1273 fprintf(stderr, 1274 "rpcinfo: Could not delete registration for prog %s version %s\n", 1275 argv[0], argv[1]); 1276 exit(1); 1277 } 1278 } 1279 1280 /* 1281 * Create and return a handle for the given nconf. 1282 * Exit if cannot create handle. 1283 */ 1284 static CLIENT * 1285 clnt_addr_create(address, nconf, prog, vers) 1286 char *address; 1287 struct netconfig *nconf; 1288 u_long prog; 1289 u_long vers; 1290 { 1291 CLIENT *client; 1292 static struct netbuf *nbuf; 1293 static int fd = RPC_ANYFD; 1294 1295 if (fd == RPC_ANYFD) { 1296 if ((fd = __rpc_nconf2fd(nconf)) == -1) { 1297 rpc_createerr.cf_stat = RPC_TLIERROR; 1298 clnt_pcreateerror("rpcinfo"); 1299 exit(1); 1300 } 1301 /* Convert the uaddr to taddr */ 1302 nbuf = uaddr2taddr(nconf, address); 1303 if (nbuf == NULL) { 1304 errx(1, "No address for client handle"); 1305 exit(1); 1306 } 1307 } 1308 client = clnt_tli_create(fd, nconf, nbuf, prog, vers, 0, 0); 1309 if (client == NULL) { 1310 clnt_pcreateerror(getprogname()); 1311 exit(1); 1312 } 1313 return (client); 1314 } 1315 1316 /* 1317 * If the version number is given, ping that (prog, vers); else try to find 1318 * the version numbers supported for that prog and ping all the versions. 1319 * Remote rpcbind is not contacted for this service. The requests are 1320 * sent directly to the services themselves. 1321 */ 1322 static void 1323 addrping(address, netid, argc, argv) 1324 char *address; 1325 char *netid; 1326 int argc; 1327 char **argv; 1328 { 1329 CLIENT *client; 1330 struct timeval to; 1331 enum clnt_stat rpc_stat; 1332 u_long prognum, versnum, minvers, maxvers; 1333 struct rpc_err rpcerr; 1334 int failure = 0; 1335 struct netconfig *nconf; 1336 int fd; 1337 1338 if (argc < 1 || argc > 2 || (netid == NULL)) { 1339 usage(); 1340 exit(1); 1341 } 1342 nconf = getnetconfigent(netid); 1343 if (nconf == NULL) 1344 errx(1, "Could not find %s", netid); 1345 to.tv_sec = 10; 1346 to.tv_usec = 0; 1347 prognum = getprognum(argv[0]); 1348 if (argc == 1) { /* Version number not known */ 1349 /* 1350 * A call to version 0 should fail with a program/version 1351 * mismatch, and give us the range of versions supported. 1352 */ 1353 versnum = MIN_VERS; 1354 } else { 1355 versnum = getvers(argv[1]); 1356 } 1357 client = clnt_addr_create(address, nconf, prognum, versnum); 1358 rpc_stat = CLNT_CALL(client, NULLPROC, (xdrproc_t) xdr_void, 1359 NULL, (xdrproc_t) xdr_void, NULL, to); 1360 if (argc == 2) { 1361 /* Version number was known */ 1362 if (pstatus(client, prognum, versnum) < 0) 1363 failure = 1; 1364 (void) CLNT_DESTROY(client); 1365 if (failure) 1366 exit(1); 1367 return; 1368 } 1369 /* Version number not known */ 1370 (void) CLNT_CONTROL(client, CLSET_FD_NCLOSE, NULL); 1371 (void) CLNT_CONTROL(client, CLGET_FD, (char *)&fd); 1372 if (rpc_stat == RPC_PROGVERSMISMATCH) { 1373 clnt_geterr(client, &rpcerr); 1374 minvers = rpcerr.re_vers.low; 1375 maxvers = rpcerr.re_vers.high; 1376 } else if (rpc_stat == RPC_SUCCESS) { 1377 /* 1378 * Oh dear, it DOES support version 0. 1379 * Let's try version MAX_VERS. 1380 */ 1381 (void) CLNT_DESTROY(client); 1382 client = clnt_addr_create(address, nconf, prognum, MAX_VERS); 1383 rpc_stat = CLNT_CALL(client, NULLPROC, (xdrproc_t) xdr_void, 1384 NULL, (xdrproc_t) xdr_void, NULL, to); 1385 if (rpc_stat == RPC_PROGVERSMISMATCH) { 1386 clnt_geterr(client, &rpcerr); 1387 minvers = rpcerr.re_vers.low; 1388 maxvers = rpcerr.re_vers.high; 1389 } else if (rpc_stat == RPC_SUCCESS) { 1390 /* 1391 * It also supports version MAX_VERS. 1392 * Looks like we have a wise guy. 1393 * OK, we give them information on all 1394 * 4 billion versions they support... 1395 */ 1396 minvers = 0; 1397 maxvers = MAX_VERS; 1398 } else { 1399 (void) pstatus(client, prognum, MAX_VERS); 1400 exit(1); 1401 } 1402 } else { 1403 (void) pstatus(client, prognum, (u_long)0); 1404 exit(1); 1405 } 1406 (void) CLNT_DESTROY(client); 1407 for (versnum = minvers; versnum <= maxvers; versnum++) { 1408 client = clnt_addr_create(address, nconf, prognum, versnum); 1409 rpc_stat = CLNT_CALL(client, NULLPROC, (xdrproc_t) xdr_void, 1410 NULL, (xdrproc_t) xdr_void, NULL, to); 1411 if (pstatus(client, prognum, versnum) < 0) 1412 failure = 1; 1413 (void) CLNT_DESTROY(client); 1414 } 1415 (void) close(fd); 1416 if (failure) 1417 exit(1); 1418 return; 1419 } 1420 1421 /* 1422 * If the version number is given, ping that (prog, vers); else try to find 1423 * the version numbers supported for that prog and ping all the versions. 1424 * Remote rpcbind is *contacted* for this service. The requests are 1425 * then sent directly to the services themselves. 1426 */ 1427 static void 1428 progping(netid, argc, argv) 1429 char *netid; 1430 int argc; 1431 char **argv; 1432 { 1433 CLIENT *client; 1434 struct timeval to; 1435 enum clnt_stat rpc_stat; 1436 u_long prognum, versnum, minvers, maxvers; 1437 struct rpc_err rpcerr; 1438 int failure = 0; 1439 struct netconfig *nconf; 1440 1441 if (argc < 2 || argc > 3 || (netid == NULL)) { 1442 usage(); 1443 exit(1); 1444 } 1445 prognum = getprognum(argv[1]); 1446 if (argc == 2) { /* Version number not known */ 1447 /* 1448 * A call to version 0 should fail with a program/version 1449 * mismatch, and give us the range of versions supported. 1450 */ 1451 versnum = MIN_VERS; 1452 } else { 1453 versnum = getvers(argv[2]); 1454 } 1455 if (netid) { 1456 nconf = getnetconfigent(netid); 1457 if (nconf == NULL) 1458 errx(1, "Could not find `%s'", netid); 1459 client = clnt_tp_create(argv[0], prognum, versnum, nconf); 1460 } else { 1461 client = clnt_create(argv[0], prognum, versnum, "NETPATH"); 1462 } 1463 if (client == NULL) { 1464 clnt_pcreateerror(getprogname()); 1465 exit(1); 1466 } 1467 to.tv_sec = 10; 1468 to.tv_usec = 0; 1469 rpc_stat = CLNT_CALL(client, NULLPROC, (xdrproc_t) xdr_void, 1470 NULL, (xdrproc_t) xdr_void, NULL, to); 1471 if (argc == 3) { 1472 /* Version number was known */ 1473 if (pstatus(client, prognum, versnum) < 0) 1474 failure = 1; 1475 (void) CLNT_DESTROY(client); 1476 if (failure) 1477 exit(1); 1478 return; 1479 } 1480 /* Version number not known */ 1481 if (rpc_stat == RPC_PROGVERSMISMATCH) { 1482 clnt_geterr(client, &rpcerr); 1483 minvers = rpcerr.re_vers.low; 1484 maxvers = rpcerr.re_vers.high; 1485 } else if (rpc_stat == RPC_SUCCESS) { 1486 /* 1487 * Oh dear, it DOES support version 0. 1488 * Let's try version MAX_VERS. 1489 */ 1490 versnum = MAX_VERS; 1491 (void) CLNT_CONTROL(client, CLSET_VERS, (char *)&versnum); 1492 rpc_stat = CLNT_CALL(client, NULLPROC, 1493 (xdrproc_t) xdr_void, NULL, (xdrproc_t) xdr_void, NULL, to); 1494 if (rpc_stat == RPC_PROGVERSMISMATCH) { 1495 clnt_geterr(client, &rpcerr); 1496 minvers = rpcerr.re_vers.low; 1497 maxvers = rpcerr.re_vers.high; 1498 } else if (rpc_stat == RPC_SUCCESS) { 1499 /* 1500 * It also supports version MAX_VERS. 1501 * Looks like we have a wise guy. 1502 * OK, we give them information on all 1503 * 4 billion versions they support... 1504 */ 1505 minvers = 0; 1506 maxvers = MAX_VERS; 1507 } else { 1508 (void) pstatus(client, prognum, MAX_VERS); 1509 exit(1); 1510 } 1511 } else { 1512 (void) pstatus(client, prognum, (u_long)0); 1513 exit(1); 1514 } 1515 for (versnum = minvers; versnum <= maxvers; versnum++) { 1516 (void) CLNT_CONTROL(client, CLSET_VERS, (char *)&versnum); 1517 rpc_stat = CLNT_CALL(client, NULLPROC, (xdrproc_t) xdr_void, 1518 NULL, (xdrproc_t) xdr_void, NULL, to); 1519 if (pstatus(client, prognum, versnum) < 0) 1520 failure = 1; 1521 } 1522 (void) CLNT_DESTROY(client); 1523 if (failure) 1524 exit(1); 1525 return; 1526 } 1527 1528 static void 1529 usage() 1530 { 1531 fprintf(stderr, "usage: rpcinfo [-m | -s] [host]\n"); 1532 #ifdef PORTMAP 1533 fprintf(stderr, " rpcinfo -p [host]\n"); 1534 #endif 1535 fprintf(stderr, " rpcinfo -T netid host prognum [versnum]\n"); 1536 fprintf(stderr, " rpcinfo -l host prognum versnum\n"); 1537 #ifdef PORTMAP 1538 fprintf(stderr, 1539 " rpcinfo [-n portnum] -u | -t host prognum [versnum]\n"); 1540 #endif 1541 fprintf(stderr, 1542 " rpcinfo -a serv_address -T netid prognum [version]\n"); 1543 fprintf(stderr, " rpcinfo -b prognum versnum\n"); 1544 fprintf(stderr, " rpcinfo -d [-T netid] prognum versnum\n"); 1545 } 1546 1547 static u_long 1548 getprognum (arg) 1549 char *arg; 1550 { 1551 char *strptr; 1552 register struct rpcent *rpc; 1553 register u_long prognum; 1554 char *tptr = arg; 1555 1556 while (*tptr && isdigit((unsigned char)*tptr++)); 1557 if (*tptr || isalpha((unsigned char)*(tptr - 1))) { 1558 rpc = getrpcbyname(arg); 1559 if (rpc == NULL) 1560 errx(1, "Unknown service `%s'", arg); 1561 prognum = rpc->r_number; 1562 } else { 1563 prognum = strtol(arg, &strptr, 10); 1564 if (strptr == arg || *strptr != '\0') 1565 errx(1, "Illegal program number `%s'", arg); 1566 } 1567 return (prognum); 1568 } 1569 1570 static u_long 1571 getvers(arg) 1572 char *arg; 1573 { 1574 char *strptr; 1575 register u_long vers; 1576 1577 vers = (int) strtol(arg, &strptr, 10); 1578 if (strptr == arg || *strptr != '\0') 1579 errx(1, "Illegal version number `%s'", arg); 1580 return (vers); 1581 } 1582 1583 /* 1584 * This routine should take a pointer to an "rpc_err" structure, rather than 1585 * a pointer to a CLIENT structure, but "clnt_perror" takes a pointer to 1586 * a CLIENT structure rather than a pointer to an "rpc_err" structure. 1587 * As such, we have to keep the CLIENT structure around in order to print 1588 * a good error message. 1589 */ 1590 static int 1591 pstatus(client, prog, vers) 1592 register CLIENT *client; 1593 u_long prog; 1594 u_long vers; 1595 { 1596 struct rpc_err rpcerr; 1597 1598 clnt_geterr(client, &rpcerr); 1599 if (rpcerr.re_status != RPC_SUCCESS) { 1600 clnt_perror(client, getprogname()); 1601 printf("program %lu version %lu is not available\n", 1602 prog, vers); 1603 return (-1); 1604 } else { 1605 printf("program %lu version %lu ready and waiting\n", 1606 prog, vers); 1607 return (0); 1608 } 1609 } 1610 1611 static CLIENT * 1612 clnt_rpcbind_create(host, rpcbversnum, targaddr) 1613 char *host; 1614 int rpcbversnum; 1615 struct netbuf **targaddr; 1616 { 1617 static char *tlist[3] = { 1618 "circuit_n", "circuit_v", "datagram_v" 1619 }; 1620 int i; 1621 struct netconfig *nconf; 1622 CLIENT *clnt = NULL; 1623 void *handle; 1624 1625 rpc_createerr.cf_stat = RPC_SUCCESS; 1626 for (i = 0; i < 3; i++) { 1627 if ((handle = __rpc_setconf(tlist[i])) == NULL) 1628 continue; 1629 while (clnt == NULL) { 1630 if ((nconf = __rpc_getconf(handle)) == NULL) { 1631 if (rpc_createerr.cf_stat == RPC_SUCCESS) 1632 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; 1633 break; 1634 } 1635 clnt = getclnthandle(host, nconf, rpcbversnum, 1636 targaddr); 1637 } 1638 if (clnt) 1639 break; 1640 __rpc_endconf(handle); 1641 } 1642 return (clnt); 1643 } 1644 1645 static CLIENT* 1646 getclnthandle(host, nconf, rpcbversnum, targaddr) 1647 char *host; 1648 struct netconfig *nconf; 1649 u_long rpcbversnum; 1650 struct netbuf **targaddr; 1651 { 1652 struct netbuf addr; 1653 struct addrinfo hints, *res; 1654 CLIENT *client = NULL; 1655 1656 /* Get the address of the rpcbind */ 1657 memset(&hints, 0, sizeof hints); 1658 if (getaddrinfo(host, "rpcbind", &hints, &res) != 0) { 1659 rpc_createerr.cf_stat = RPC_N2AXLATEFAILURE; 1660 return (NULL); 1661 } 1662 addr.len = addr.maxlen = res->ai_addrlen; 1663 addr.buf = res->ai_addr; 1664 client = clnt_tli_create(RPC_ANYFD, nconf, &addr, RPCBPROG, 1665 rpcbversnum, 0, 0); 1666 if (client) { 1667 if (targaddr != NULL) { 1668 *targaddr = malloc(sizeof (struct netbuf)); 1669 if (*targaddr != NULL) { 1670 (*targaddr)->maxlen = addr.maxlen; 1671 (*targaddr)->len = addr.len; 1672 (*targaddr)->buf = malloc(addr.len); 1673 if ((*targaddr)->buf != NULL) { 1674 memcpy((*targaddr)->buf, addr.buf, 1675 addr.len); 1676 } 1677 } 1678 } 1679 } else { 1680 if (rpc_createerr.cf_stat == RPC_TLIERROR) { 1681 /* 1682 * Assume that the other system is dead; this is a 1683 * better error to display to the user. 1684 */ 1685 rpc_createerr.cf_stat = RPC_RPCBFAILURE; 1686 rpc_createerr.cf_error.re_status = RPC_FAILED; 1687 } 1688 } 1689 freeaddrinfo(res); 1690 return (client); 1691 } 1692 1693 static void 1694 print_rmtcallstat(rtype, infp) 1695 int rtype; 1696 rpcb_stat *infp; 1697 { 1698 register rpcbs_rmtcalllist_ptr pr; 1699 struct rpcent *rpc; 1700 1701 if (rtype == RPCBVERS_4_STAT) 1702 printf( 1703 "prog\t\tvers\tproc\tnetid\tindirect success failure\n"); 1704 else 1705 printf("prog\t\tvers\tproc\tnetid\tsuccess\tfailure\n"); 1706 for (pr = infp->rmtinfo; pr; pr = pr->next) { 1707 rpc = getrpcbynumber(pr->prog); 1708 if (rpc) 1709 printf("%-16s", rpc->r_name); 1710 else 1711 printf("%-16d", pr->prog); 1712 printf("%d\t%d\t%s\t", 1713 pr->vers, pr->proc, pr->netid); 1714 if (rtype == RPCBVERS_4_STAT) 1715 printf("%d\t ", pr->indirect); 1716 printf("%d\t%d\n", pr->success, pr->failure); 1717 } 1718 } 1719 1720 static void 1721 print_getaddrstat(rtype, infp) 1722 int rtype; 1723 rpcb_stat *infp; 1724 { 1725 rpcbs_addrlist_ptr al; 1726 register struct rpcent *rpc; 1727 1728 printf("prog\t\tvers\tnetid\t success\tfailure\n"); 1729 for (al = infp->addrinfo; al; al = al->next) { 1730 rpc = getrpcbynumber(al->prog); 1731 if (rpc) 1732 printf("%-16s", rpc->r_name); 1733 else 1734 printf("%-16d", al->prog); 1735 printf("%d\t%s\t %-12d\t%d\n", 1736 al->vers, al->netid, 1737 al->success, al->failure); 1738 } 1739 } 1740 1741 static char * 1742 spaces(howmany) 1743 int howmany; 1744 { 1745 static char space_array[] = /* 64 spaces */ 1746 " "; 1747 1748 if (howmany <= 0 || howmany > sizeof (space_array)) { 1749 return (""); 1750 } 1751 return (&space_array[sizeof (space_array) - howmany - 1]); 1752 } 1753