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