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