1 /* $OpenBSD: rpcinfo.c,v 1.7 2001/07/17 02:24:00 pvalchev Exp $ */ 2 3 #ifndef lint 4 /*static char sccsid[] = "from: @(#)rpcinfo.c 1.22 87/08/12 SMI";*/ 5 /*static char sccsid[] = "from: @(#)rpcinfo.c 2.2 88/08/11 4.0 RPCSRC";*/ 6 static char rcsid[] = "$OpenBSD: rpcinfo.c,v 1.7 2001/07/17 02:24:00 pvalchev Exp $"; 7 #endif 8 9 /* 10 * Copyright (C) 1986, Sun Microsystems, Inc. 11 */ 12 13 /* 14 * rpcinfo: ping a particular rpc program 15 * or dump the portmapper 16 */ 17 18 /* 19 * Sun RPC is a product of Sun Microsystems, Inc. and is provided for 20 * unrestricted use provided that this legend is included on all tape 21 * media and as a part of the software program in whole or part. Users 22 * may copy or modify Sun RPC without charge, but are not authorized 23 * to license or distribute it to anyone else except as part of a product or 24 * program developed by the user. 25 * 26 * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE 27 * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR 28 * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. 29 * 30 * Sun RPC is provided with no support and without any obligation on the 31 * part of Sun Microsystems, Inc. to assist in its use, correction, 32 * modification or enhancement. 33 * 34 * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE 35 * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC 36 * OR ANY PART THEREOF. 37 * 38 * In no event will Sun Microsystems, Inc. be liable for any lost revenue 39 * or profits or other special, indirect and consequential damages, even if 40 * Sun has been advised of the possibility of such damages. 41 * 42 * Sun Microsystems, Inc. 43 * 2550 Garcia Avenue 44 * Mountain View, California 94043 45 */ 46 47 #include <rpc/rpc.h> 48 #include <stdio.h> 49 #include <sys/socket.h> 50 #include <netdb.h> 51 #include <rpc/pmap_prot.h> 52 #include <rpc/pmap_clnt.h> 53 #include <signal.h> 54 #include <string.h> 55 #include <stdlib.h> 56 #include <unistd.h> 57 #include <ctype.h> 58 #include <errno.h> 59 #include <arpa/inet.h> 60 61 #define MAXHOSTLEN 256 62 63 #define MIN_VERS ((u_long) 0) 64 #define MAX_VERS ((u_long) 4294967295UL) 65 66 void udpping(u_short portflag, int argc, char **argv); 67 void tcpping(u_short portflag, int argc, char **argv); 68 int pstatus(CLIENT *client, u_long prognum, u_long vers); 69 void pmapdump(int argc, char **argv); 70 bool_t reply_proc(caddr_t res, struct sockaddr_in *who); 71 void brdcst(int argc, char **argv); 72 void deletereg(int argc, char **argv); 73 void setreg(int argc, char **argv); 74 void usage(char *); 75 int getprognum(char *arg, u_long *ulp); 76 int getul(char *arg, u_long *ulp); 77 void get_inet_address(struct sockaddr_in *addr, char *host); 78 79 /* 80 * Functions to be performed. 81 */ 82 #define NONE 0 /* no function */ 83 #define PMAPDUMP 1 /* dump portmapper registrations */ 84 #define TCPPING 2 /* ping TCP service */ 85 #define UDPPING 3 /* ping UDP service */ 86 #define BRDCST 4 /* ping broadcast UDP service */ 87 #define DELETES 5 /* delete registration for the service */ 88 #define SETS 6 /* set registration for the service */ 89 90 int 91 main(argc, argv) 92 int argc; 93 char **argv; 94 { 95 register int c; 96 extern char *optarg; 97 extern int optind; 98 int errflg; 99 int function; 100 u_short portnum; 101 u_long tmp; 102 103 function = NONE; 104 portnum = 0; 105 errflg = 0; 106 while ((c = getopt(argc, argv, "ptubdsn:")) != -1) { 107 switch (c) { 108 109 case 'p': 110 if (function != NONE) 111 errflg = 1; 112 else 113 function = PMAPDUMP; 114 break; 115 116 case 't': 117 if (function != NONE) 118 errflg = 1; 119 else 120 function = TCPPING; 121 break; 122 123 case 'u': 124 if (function != NONE) 125 errflg = 1; 126 else 127 function = UDPPING; 128 break; 129 130 case 'b': 131 if (function != NONE) 132 errflg = 1; 133 else 134 function = BRDCST; 135 break; 136 137 case 'n': 138 if (getul(optarg, &tmp)) 139 usage("invalid port number"); 140 if (tmp >= 65536) 141 usage("port number out of range"); 142 portnum = (u_short)tmp; 143 break; 144 145 case 'd': 146 if (function != NONE) 147 errflg = 1; 148 else 149 function = DELETES; 150 break; 151 152 case 's': 153 if (function != NONE) 154 errflg = 1; 155 else 156 function = SETS; 157 break; 158 159 160 case '?': 161 errflg = 1; 162 } 163 } 164 165 if (errflg || function == NONE) 166 usage(NULL); 167 168 switch (function) { 169 170 case PMAPDUMP: 171 if (portnum != 0) 172 usage(NULL); 173 pmapdump(argc - optind, argv + optind); 174 break; 175 176 case UDPPING: 177 udpping(portnum, argc - optind, argv + optind); 178 break; 179 180 case TCPPING: 181 tcpping(portnum, argc - optind, argv + optind); 182 break; 183 184 case BRDCST: 185 if (portnum != 0) 186 usage(NULL); 187 188 brdcst(argc - optind, argv + optind); 189 break; 190 191 case DELETES: 192 deletereg(argc - optind, argv + optind); 193 break; 194 195 case SETS: 196 setreg(argc - optind, argv + optind); 197 break; 198 } 199 200 return (0); 201 } 202 203 void 204 udpping(portnum, argc, argv) 205 u_short portnum; 206 int argc; 207 char **argv; 208 { 209 struct timeval to; 210 struct sockaddr_in addr; 211 enum clnt_stat rpc_stat; 212 CLIENT *client; 213 u_long prognum, vers, minvers, maxvers; 214 int sock = RPC_ANYSOCK; 215 struct rpc_err rpcerr; 216 int failure; 217 218 if (argc < 2) 219 usage("too few arguments"); 220 if (argc > 3) 221 usage("too many arguments"); 222 if (getprognum(argv[1], &prognum)) 223 usage("program number out of range"); 224 225 get_inet_address(&addr, argv[0]); 226 /* Open the socket here so it will survive calls to clnt_destroy */ 227 sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); 228 if (sock < 0) { 229 perror("rpcinfo: socket"); 230 exit(1); 231 } 232 if (getuid() == 0) 233 bindresvport(sock, NULL); 234 failure = 0; 235 if (argc == 2) { 236 /* 237 * A call to version 0 should fail with a program/version 238 * mismatch, and give us the range of versions supported. 239 */ 240 addr.sin_port = htons(portnum); 241 to.tv_sec = 5; 242 to.tv_usec = 0; 243 if ((client = clntudp_create(&addr, prognum, (u_long)0, 244 to, &sock)) == NULL) { 245 clnt_pcreateerror("rpcinfo"); 246 printf("program %lu is not available\n", 247 prognum); 248 exit(1); 249 } 250 to.tv_sec = 10; 251 to.tv_usec = 0; 252 rpc_stat = clnt_call(client, NULLPROC, xdr_void, (char *)NULL, 253 xdr_void, (char *)NULL, to); 254 if (rpc_stat == RPC_PROGVERSMISMATCH) { 255 clnt_geterr(client, &rpcerr); 256 minvers = rpcerr.re_vers.low; 257 maxvers = rpcerr.re_vers.high; 258 } else if (rpc_stat == RPC_SUCCESS) { 259 /* 260 * Oh dear, it DOES support version 0. 261 * Let's try version MAX_VERS. 262 */ 263 addr.sin_port = htons(portnum); 264 to.tv_sec = 5; 265 to.tv_usec = 0; 266 if ((client = clntudp_create(&addr, prognum, MAX_VERS, 267 to, &sock)) == NULL) { 268 clnt_pcreateerror("rpcinfo"); 269 printf("program %lu version %lu is not available\n", 270 prognum, MAX_VERS); 271 exit(1); 272 } 273 to.tv_sec = 10; 274 to.tv_usec = 0; 275 rpc_stat = clnt_call(client, NULLPROC, xdr_void, 276 (char *)NULL, xdr_void, (char *)NULL, to); 277 if (rpc_stat == RPC_PROGVERSMISMATCH) { 278 clnt_geterr(client, &rpcerr); 279 minvers = rpcerr.re_vers.low; 280 maxvers = rpcerr.re_vers.high; 281 } else if (rpc_stat == RPC_SUCCESS) { 282 /* 283 * It also supports version MAX_VERS. 284 * Looks like we have a wise guy. 285 * OK, we give them information on all 286 * 4 billion versions they support... 287 */ 288 minvers = 0; 289 maxvers = MAX_VERS; 290 } else { 291 (void) pstatus(client, prognum, MAX_VERS); 292 exit(1); 293 } 294 } else { 295 (void) pstatus(client, prognum, (u_long)0); 296 exit(1); 297 } 298 clnt_destroy(client); 299 for (vers = minvers; vers <= maxvers; vers++) { 300 addr.sin_port = htons(portnum); 301 to.tv_sec = 5; 302 to.tv_usec = 0; 303 if ((client = clntudp_create(&addr, prognum, vers, 304 to, &sock)) == NULL) { 305 clnt_pcreateerror("rpcinfo"); 306 printf("program %lu version %lu is not available\n", 307 prognum, vers); 308 exit(1); 309 } 310 to.tv_sec = 10; 311 to.tv_usec = 0; 312 rpc_stat = clnt_call(client, NULLPROC, xdr_void, 313 (char *)NULL, xdr_void, (char *)NULL, to); 314 if (pstatus(client, prognum, vers) < 0) 315 failure = 1; 316 clnt_destroy(client); 317 } 318 } else { 319 getul(argv[2], &vers); /* XXX */ 320 addr.sin_port = htons(portnum); 321 to.tv_sec = 5; 322 to.tv_usec = 0; 323 if ((client = clntudp_create(&addr, prognum, vers, 324 to, &sock)) == NULL) { 325 clnt_pcreateerror("rpcinfo"); 326 printf("program %lu version %lu is not available\n", 327 prognum, vers); 328 exit(1); 329 } 330 to.tv_sec = 10; 331 to.tv_usec = 0; 332 rpc_stat = clnt_call(client, 0, xdr_void, (char *)NULL, 333 xdr_void, (char *)NULL, to); 334 if (pstatus(client, prognum, vers) < 0) 335 failure = 1; 336 } 337 (void) close(sock); /* Close it up again */ 338 if (failure) 339 exit(1); 340 } 341 342 void 343 tcpping(portnum, argc, argv) 344 u_short portnum; 345 int argc; 346 char **argv; 347 { 348 struct timeval to; 349 struct sockaddr_in addr; 350 enum clnt_stat rpc_stat; 351 CLIENT *client; 352 u_long prognum, vers, minvers, maxvers; 353 int sock = RPC_ANYSOCK; 354 struct rpc_err rpcerr; 355 int failure; 356 357 if (argc < 2) 358 usage("too few arguments"); 359 if (argc > 3) 360 usage("too many arguments"); 361 if (getprognum(argv[1], &prognum)) 362 usage("program number out of range"); 363 364 get_inet_address(&addr, argv[0]); 365 failure = 0; 366 if (argc == 2) { 367 /* 368 * A call to version 0 should fail with a program/version 369 * mismatch, and give us the range of versions supported. 370 */ 371 addr.sin_port = htons(portnum); 372 if ((client = clnttcp_create(&addr, prognum, MIN_VERS, 373 &sock, 0, 0)) == NULL) { 374 clnt_pcreateerror("rpcinfo"); 375 printf("program %lu is not available\n", 376 prognum); 377 exit(1); 378 } 379 to.tv_sec = 10; 380 to.tv_usec = 0; 381 rpc_stat = clnt_call(client, NULLPROC, xdr_void, (char *)NULL, 382 xdr_void, (char *)NULL, to); 383 if (rpc_stat == RPC_PROGVERSMISMATCH) { 384 clnt_geterr(client, &rpcerr); 385 minvers = rpcerr.re_vers.low; 386 maxvers = rpcerr.re_vers.high; 387 } else if (rpc_stat == RPC_SUCCESS) { 388 /* 389 * Oh dear, it DOES support version 0. 390 * Let's try version MAX_VERS. 391 */ 392 addr.sin_port = htons(portnum); 393 if ((client = clnttcp_create(&addr, prognum, MAX_VERS, 394 &sock, 0, 0)) == NULL) { 395 clnt_pcreateerror("rpcinfo"); 396 printf("program %lu version %lu is not available\n", 397 prognum, MAX_VERS); 398 exit(1); 399 } 400 to.tv_sec = 10; 401 to.tv_usec = 0; 402 rpc_stat = clnt_call(client, NULLPROC, xdr_void, 403 (char *)NULL, xdr_void, (char *)NULL, to); 404 if (rpc_stat == RPC_PROGVERSMISMATCH) { 405 clnt_geterr(client, &rpcerr); 406 minvers = rpcerr.re_vers.low; 407 maxvers = rpcerr.re_vers.high; 408 } else if (rpc_stat == RPC_SUCCESS) { 409 /* 410 * It also supports version MAX_VERS. 411 * Looks like we have a wise guy. 412 * OK, we give them information on all 413 * 4 billion versions they support... 414 */ 415 minvers = 0; 416 maxvers = MAX_VERS; 417 } else { 418 (void) pstatus(client, prognum, MAX_VERS); 419 exit(1); 420 } 421 } else { 422 (void) pstatus(client, prognum, MIN_VERS); 423 exit(1); 424 } 425 clnt_destroy(client); 426 (void) close(sock); 427 sock = RPC_ANYSOCK; /* Re-initialize it for later */ 428 for (vers = minvers; vers <= maxvers; vers++) { 429 addr.sin_port = htons(portnum); 430 if ((client = clnttcp_create(&addr, prognum, vers, 431 &sock, 0, 0)) == NULL) { 432 clnt_pcreateerror("rpcinfo"); 433 printf("program %lu version %lu is not available\n", 434 prognum, vers); 435 exit(1); 436 } 437 to.tv_usec = 0; 438 to.tv_sec = 10; 439 rpc_stat = clnt_call(client, 0, xdr_void, (char *)NULL, 440 xdr_void, (char *)NULL, to); 441 if (pstatus(client, prognum, vers) < 0) 442 failure = 1; 443 clnt_destroy(client); 444 (void) close(sock); 445 sock = RPC_ANYSOCK; 446 } 447 } else { 448 getul(argv[2], &vers); /* XXX */ 449 addr.sin_port = htons(portnum); 450 if ((client = clnttcp_create(&addr, prognum, vers, &sock, 451 0, 0)) == NULL) { 452 clnt_pcreateerror("rpcinfo"); 453 printf("program %lu version %lu is not available\n", 454 prognum, vers); 455 exit(1); 456 } 457 to.tv_usec = 0; 458 to.tv_sec = 10; 459 rpc_stat = clnt_call(client, 0, xdr_void, (char *)NULL, 460 xdr_void, (char *)NULL, to); 461 if (pstatus(client, prognum, vers) < 0) 462 failure = 1; 463 } 464 if (failure) 465 exit(1); 466 } 467 468 /* 469 * This routine should take a pointer to an "rpc_err" structure, rather than 470 * a pointer to a CLIENT structure, but "clnt_perror" takes a pointer to 471 * a CLIENT structure rather than a pointer to an "rpc_err" structure. 472 * As such, we have to keep the CLIENT structure around in order to print 473 * a good error message. 474 */ 475 int 476 pstatus(client, prognum, vers) 477 register CLIENT *client; 478 u_long prognum; 479 u_long vers; 480 { 481 struct rpc_err rpcerr; 482 483 clnt_geterr(client, &rpcerr); 484 if (rpcerr.re_status != RPC_SUCCESS) { 485 clnt_perror(client, "rpcinfo"); 486 printf("program %lu version %lu is not available\n", 487 prognum, vers); 488 return (-1); 489 } else { 490 printf("program %lu version %lu ready and waiting\n", 491 prognum, vers); 492 return (0); 493 } 494 } 495 496 void 497 pmapdump(argc, argv) 498 int argc; 499 char **argv; 500 { 501 struct sockaddr_in server_addr; 502 register struct hostent *hp; 503 struct pmaplist *head = NULL; 504 int socket = RPC_ANYSOCK; 505 struct timeval minutetimeout; 506 register CLIENT *client; 507 struct rpcent *rpc; 508 509 if (argc > 1) 510 usage("too many arguments"); 511 512 if (argc == 1) 513 get_inet_address(&server_addr, argv[0]); 514 else { 515 bzero((char *)&server_addr, sizeof server_addr); 516 server_addr.sin_family = AF_INET; 517 if ((hp = gethostbyname("localhost")) != NULL) 518 bcopy(hp->h_addr, (caddr_t)&server_addr.sin_addr, 519 hp->h_length); 520 else 521 (void) inet_aton("0.0.0.0", &server_addr.sin_addr); 522 } 523 minutetimeout.tv_sec = 60; 524 minutetimeout.tv_usec = 0; 525 server_addr.sin_port = htons(PMAPPORT); 526 if ((client = clnttcp_create(&server_addr, PMAPPROG, 527 PMAPVERS, &socket, 50, 500)) == NULL) { 528 clnt_pcreateerror("rpcinfo: can't contact portmapper"); 529 exit(1); 530 } 531 if (clnt_call(client, PMAPPROC_DUMP, xdr_void, NULL, 532 xdr_pmaplist, &head, minutetimeout) != RPC_SUCCESS) { 533 fprintf(stderr, "rpcinfo: can't contact portmapper: "); 534 clnt_perror(client, "rpcinfo"); 535 exit(1); 536 } 537 if (head == NULL) { 538 printf("No remote programs registered.\n"); 539 } else { 540 printf(" program vers proto port\n"); 541 for (; head != NULL; head = head->pml_next) { 542 printf("%10ld%5ld", 543 head->pml_map.pm_prog, 544 head->pml_map.pm_vers); 545 if (head->pml_map.pm_prot == IPPROTO_UDP) 546 printf("%6s", "udp"); 547 else if (head->pml_map.pm_prot == IPPROTO_TCP) 548 printf("%6s", "tcp"); 549 else 550 printf("%6ld", head->pml_map.pm_prot); 551 printf("%7ld", head->pml_map.pm_port); 552 rpc = getrpcbynumber(head->pml_map.pm_prog); 553 if (rpc) 554 printf(" %s\n", rpc->r_name); 555 else 556 printf("\n"); 557 } 558 } 559 } 560 561 /* 562 * reply_proc collects replies from the broadcast. 563 * to get a unique list of responses the output of rpcinfo should 564 * be piped through sort(1) and then uniq(1). 565 */ 566 /*ARGSUSED*/ 567 bool_t 568 reply_proc(res, who) 569 caddr_t res; /* Nothing comes back */ 570 struct sockaddr_in *who; /* Who sent us the reply */ 571 { 572 register struct hostent *hp; 573 574 hp = gethostbyaddr((char *) &who->sin_addr, sizeof who->sin_addr, 575 AF_INET); 576 printf("%s %s\n", inet_ntoa(who->sin_addr), 577 (hp == NULL) ? "(unknown)" : hp->h_name); 578 return(FALSE); 579 } 580 581 void 582 brdcst(argc, argv) 583 int argc; 584 char **argv; 585 { 586 enum clnt_stat rpc_stat; 587 u_long prognum, vers_num; 588 589 if (argc != 2) 590 usage("incorrect number of arguments"); 591 if (getprognum(argv[1], &prognum)) 592 usage("program number out of range"); 593 if (getul(argv[1], &vers_num)) 594 usage("version number out of range"); 595 596 rpc_stat = clnt_broadcast(prognum, vers_num, NULLPROC, xdr_void, 597 (char *)NULL, xdr_void, (char *)NULL, reply_proc); 598 if ((rpc_stat != RPC_SUCCESS) && (rpc_stat != RPC_TIMEDOUT)) { 599 fprintf(stderr, "rpcinfo: broadcast failed: %s\n", 600 clnt_sperrno(rpc_stat)); 601 exit(1); 602 } 603 exit(0); 604 } 605 606 void 607 deletereg(argc, argv) 608 int argc; 609 char **argv; 610 { 611 u_long prog_num, version_num; 612 613 if (argc != 2) 614 usage("incorrect number of arguments"); 615 if (getprognum(argv[0], &prog_num)) 616 usage("program number out of range"); 617 if (getul(argv[1], &version_num)) 618 usage("version number out of range"); 619 620 if ((pmap_unset(prog_num, version_num)) == 0) { 621 fprintf(stderr, "rpcinfo: Could not delete " 622 "registration for prog %s version %s\n", 623 argv[0], argv[1]); 624 exit(1); 625 } 626 } 627 628 void 629 setreg(argc, argv) 630 int argc; 631 char **argv; 632 { 633 u_long prog_num, version_num, port_num; 634 635 if (argc != 3) 636 usage("incorrect number of arguments"); 637 if (getprognum(argv[0], &prog_num)) 638 usage("cannot parse program number"); 639 if (getul(argv[1], &version_num)) 640 usage("cannot parse version number"); 641 if (getul(argv[2], &port_num)) 642 usage("cannot parse port number"); 643 if (port_num >= 65536) 644 usage("port number out of range"); 645 646 if ((pmap_set(prog_num, version_num, PF_INET, 647 (u_short)port_num)) == 0) { 648 fprintf(stderr, "rpcinfo: Could not set registration " 649 "for prog %s version %s port %s\n", 650 argv[0], argv[1], argv[2]); 651 exit(1); 652 } 653 } 654 655 void 656 usage(char *msg) 657 { 658 if (msg) 659 fprintf(stderr, 660 "rpcinfo: %s\n", msg); 661 fprintf(stderr, 662 "Usage: rpcinfo [ -n portnum ] -u host prognum [ versnum ]\n"); 663 fprintf(stderr, 664 " rpcinfo [ -n portnum ] -t host prognum [ versnum ]\n"); 665 fprintf(stderr, " rpcinfo -p [ host ]\n"); 666 fprintf(stderr, " rpcinfo -b prognum versnum\n"); 667 fprintf(stderr, " rpcinfo -d prognum versnum\n"); 668 fprintf(stderr, " rpcinfo -s prognum versnum portnum\n"); 669 exit(1); 670 } 671 672 int 673 getprognum(arg, ulp) 674 char *arg; 675 u_long *ulp; 676 { 677 register struct rpcent *rpc; 678 679 if (isalpha(*arg)) { 680 rpc = getrpcbyname(arg); 681 if (rpc == NULL) { 682 fprintf(stderr, "rpcinfo: %s is unknown service\n", 683 arg); 684 exit(1); 685 } 686 *ulp = rpc->r_number; 687 return 0; 688 } 689 return getul(arg, ulp); 690 } 691 692 int 693 getul(arg, ulp) 694 char *arg; 695 u_long *ulp; 696 { 697 u_long ul; 698 int save_errno = errno; 699 char *ep; 700 int ret = 1; 701 702 errno = 0; 703 ul = strtoul(arg, &ep, 10); 704 if (arg[0] == '\0' || *ep != '\0') 705 goto fail; 706 if (errno == ERANGE && ul == ULONG_MAX) 707 goto fail; 708 *ulp = ul; 709 ret = 0; 710 fail: 711 errno = save_errno; 712 return (ret); 713 } 714 715 void 716 get_inet_address(addr, host) 717 struct sockaddr_in *addr; 718 char *host; 719 { 720 register struct hostent *hp; 721 722 bzero((char *)addr, sizeof *addr); 723 if (inet_aton(host, &addr->sin_addr) == 0) { 724 if ((hp = gethostbyname(host)) == NULL) { 725 fprintf(stderr, "rpcinfo: %s is unknown host\n", 726 host); 727 exit(1); 728 } 729 bcopy(hp->h_addr, (char *)&addr->sin_addr, hp->h_length); 730 } 731 addr->sin_family = AF_INET; 732 } 733