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