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