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