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