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