rpcinfo.c revision 1.3 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.3 1993/08/01 18:09:11 mycroft 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