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