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