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