1 /* 2 * Copyright (C) 1986, Sun Microsystems, Inc. 3 * 4 * @(#)rpcinfo.c 1.22 87/08/12 SMI 5 * @(#)rpcinfo.c 2.2 88/08/11 4.0 RPCSRC 6 * $FreeBSD: src/usr.bin/rpcinfo/rpcinfo.c,v 1.9.2.1 2001/03/04 09:00:23 kris Exp $ 7 * $DragonFly: src/usr.bin/rpcinfo/rpcinfo.c,v 1.2 2003/06/17 04:29:31 dillon Exp $ 8 */ 9 /* 10 * rpcinfo: ping a particular rpc program 11 * or dump the portmapper 12 */ 13 14 /* 15 * Sun RPC is a product of Sun Microsystems, Inc. and is provided for 16 * unrestricted use provided that this legend is included on all tape 17 * media and as a part of the software program in whole or part. Users 18 * may copy or modify Sun RPC without charge, but are not authorized 19 * to license or distribute it to anyone else except as part of a product or 20 * program developed by the user. 21 * 22 * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE 23 * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR 24 * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. 25 * 26 * Sun RPC is provided with no support and without any obligation on the 27 * part of Sun Microsystems, Inc. to assist in its use, correction, 28 * modification or enhancement. 29 * 30 * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE 31 * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC 32 * OR ANY PART THEREOF. 33 * 34 * In no event will Sun Microsystems, Inc. be liable for any lost revenue 35 * or profits or other special, indirect and consequential damages, even if 36 * Sun has been advised of the possibility of such damages. 37 * 38 * Sun Microsystems, Inc. 39 * 2550 Garcia Avenue 40 * Mountain View, California 94043 41 */ 42 43 #include <err.h> 44 #include <ctype.h> 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 <unistd.h> 54 #include <sys/param.h> 55 #include <arpa/inet.h> 56 57 #define MAXHOSTLEN 256 58 59 #define MIN_VERS ((u_long) 0) 60 #define MAX_VERS ((u_long) 4294967295UL) 61 62 static void udpping(/*u_short portflag, int argc, char **argv*/); 63 static void tcpping(/*u_short portflag, int argc, char **argv*/); 64 static int pstatus(/*CLIENT *client, u_long prognum, u_long vers*/); 65 static void pmapdump(/*int argc, char **argv*/); 66 static bool_t reply_proc(/*void *res, struct sockaddr_in *who*/); 67 static void brdcst(/*int argc, char **argv*/); 68 static void deletereg(/* int argc, char **argv */) ; 69 static void usage(/*void*/); 70 static u_long getprognum(/*char *arg*/); 71 static u_long getvers(/*char *arg*/); 72 static void get_inet_address(/*struct sockaddr_in *addr, char *host*/); 73 74 /* 75 * Functions to be performed. 76 */ 77 #define NONE 0 /* no function */ 78 #define PMAPDUMP 1 /* dump portmapper registrations */ 79 #define TCPPING 2 /* ping TCP service */ 80 #define UDPPING 3 /* ping UDP service */ 81 #define BRDCST 4 /* ping broadcast UDP service */ 82 #define DELETES 5 /* delete registration for the service */ 83 84 int 85 main(argc, argv) 86 int argc; 87 char **argv; 88 { 89 register int c; 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:")) != -1) { 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 MIN(hp->h_length,sizeof(server_addr.sin_addr))); 497 else 498 server_addr.sin_addr.s_addr = inet_addr("0.0.0.0"); 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 errx(1, "sorry, you are not root") ; 595 prog_num = getprognum(argv[0]); 596 version_num = getvers(argv[1]); 597 if ((pmap_unset(prog_num, version_num)) == 0) 598 errx(1, "could not delete registration for prog %s version %s", 599 argv[0], argv[1]) ; 600 } 601 602 static void 603 usage() 604 { 605 fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n", 606 "usage: rpcinfo [-n portnum] -u host prognum [versnum]", 607 " rpcinfo [-n portnum] -t host prognum [versnum]", 608 " rpcinfo -p [host]", 609 " rpcinfo -b prognum versnum", 610 " rpcinfo -d prognum versnum"); 611 } 612 613 static u_long 614 getprognum(arg) 615 char *arg; 616 { 617 register struct rpcent *rpc; 618 register u_long prognum; 619 620 if (isalpha(*arg)) { 621 rpc = getrpcbyname(arg); 622 if (rpc == NULL) 623 errx(1, "%s is unknown service", arg); 624 prognum = rpc->r_number; 625 } else { 626 prognum = (u_long) atoi(arg); 627 } 628 629 return (prognum); 630 } 631 632 static u_long 633 getvers(arg) 634 char *arg; 635 { 636 register u_long vers; 637 638 vers = (int) atoi(arg); 639 return (vers); 640 } 641 642 static void 643 get_inet_address(addr, host) 644 struct sockaddr_in *addr; 645 char *host; 646 { 647 register struct hostent *hp; 648 649 bzero((char *)addr, sizeof *addr); 650 addr->sin_addr.s_addr = (u_long) inet_addr(host); 651 if (addr->sin_addr.s_addr == -1 || addr->sin_addr.s_addr == 0) { 652 if ((hp = gethostbyname(host)) == NULL) 653 errx(1, "%s is unknown host\n", host); 654 bcopy(hp->h_addr, (char *)&addr->sin_addr, 655 MIN(hp->h_length,sizeof(addr->sin_addr))); 656 } 657 addr->sin_family = AF_INET; 658 } 659