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