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