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