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