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