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