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