rpcinfo.c revision 1.5 1 /* $NetBSD: rpcinfo.c,v 1.5 1997/01/09 20:21:11 tls Exp $ */
2
3 #ifndef lint
4 /*static char sccsid[] = "from: @(#)rpcinfo.c 1.22 87/08/12 SMI";*/
5 /*static char sccsid[] = "from: @(#)rpcinfo.c 2.2 88/08/11 4.0 RPCSRC";*/
6 static char rcsid[] = "$NetBSD: rpcinfo.c,v 1.5 1997/01/09 20:21:11 tls Exp $";
7 #endif
8
9 /*
10 * Copyright (C) 1986, Sun Microsystems, Inc.
11 */
12
13 /*
14 * rpcinfo: ping a particular rpc program
15 * or dump the portmapper
16 */
17
18 /*
19 * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
20 * unrestricted use provided that this legend is included on all tape
21 * media and as a part of the software program in whole or part. Users
22 * may copy or modify Sun RPC without charge, but are not authorized
23 * to license or distribute it to anyone else except as part of a product or
24 * program developed by the user.
25 *
26 * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
27 * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
28 * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
29 *
30 * Sun RPC is provided with no support and without any obligation on the
31 * part of Sun Microsystems, Inc. to assist in its use, correction,
32 * modification or enhancement.
33 *
34 * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
35 * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
36 * OR ANY PART THEREOF.
37 *
38 * In no event will Sun Microsystems, Inc. be liable for any lost revenue
39 * or profits or other special, indirect and consequential damages, even if
40 * Sun has been advised of the possibility of such damages.
41 *
42 * Sun Microsystems, Inc.
43 * 2550 Garcia Avenue
44 * Mountain View, California 94043
45 */
46
47 #include <rpc/rpc.h>
48 #include <stdio.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 <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 extern char *optarg;
91 extern int optind;
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:")) != EOF) {
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 hp->h_length);
499 else
500 (void) inet_aton("0.0.0.0", &server_addr.sin_addr);
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((char *) &who->sin_addr, sizeof who->sin_addr,
555 AF_INET);
556 printf("%s %s\n", inet_ntoa(who->sin_addr),
557 (hp == NULL) ? "(unknown)" : hp->h_name);
558 return(FALSE);
559 }
560
561 static void
562 brdcst(argc, argv)
563 int argc;
564 char **argv;
565 {
566 enum clnt_stat rpc_stat;
567 u_long prognum, vers;
568
569 if (argc != 2) {
570 usage();
571 exit(1);
572 }
573 prognum = getprognum(argv[0]);
574 vers = getvers(argv[1]);
575 rpc_stat = clnt_broadcast(prognum, vers, NULLPROC, xdr_void,
576 (char *)NULL, xdr_void, (char *)NULL, reply_proc);
577 if ((rpc_stat != RPC_SUCCESS) && (rpc_stat != RPC_TIMEDOUT)) {
578 fprintf(stderr, "rpcinfo: broadcast failed: %s\n",
579 clnt_sperrno(rpc_stat));
580 exit(1);
581 }
582 exit(0);
583 }
584
585 static void
586 deletereg(argc, argv)
587 int argc;
588 char **argv;
589 { u_long prog_num, version_num ;
590
591 if (argc != 2) {
592 usage() ;
593 exit(1) ;
594 }
595 if (getuid()) { /* This command allowed only to root */
596 fprintf(stderr, "Sorry. You are not root\n") ;
597 exit(1) ;
598 }
599 prog_num = getprognum(argv[0]);
600 version_num = getvers(argv[1]);
601 if ((pmap_unset(prog_num, version_num)) == 0) {
602 fprintf(stderr, "rpcinfo: Could not delete registration for prog %s version %s\n",
603 argv[0], argv[1]) ;
604 exit(1) ;
605 }
606 }
607
608 static void
609 usage()
610 {
611 fprintf(stderr, "Usage: rpcinfo [ -n portnum ] -u host prognum [ versnum ]\n");
612 fprintf(stderr, " rpcinfo [ -n portnum ] -t host prognum [ versnum ]\n");
613 fprintf(stderr, " rpcinfo -p [ host ]\n");
614 fprintf(stderr, " rpcinfo -b prognum versnum\n");
615 fprintf(stderr, " rpcinfo -d prognum versnum\n") ;
616 }
617
618 static u_long
619 getprognum(arg)
620 char *arg;
621 {
622 register struct rpcent *rpc;
623 register u_long prognum;
624
625 if (isalpha(*arg)) {
626 rpc = getrpcbyname(arg);
627 if (rpc == NULL) {
628 fprintf(stderr, "rpcinfo: %s is unknown service\n",
629 arg);
630 exit(1);
631 }
632 prognum = rpc->r_number;
633 } else {
634 prognum = (u_long) atoi(arg);
635 }
636
637 return (prognum);
638 }
639
640 static u_long
641 getvers(arg)
642 char *arg;
643 {
644 register u_long vers;
645
646 vers = (int) atoi(arg);
647 return (vers);
648 }
649
650 static void
651 get_inet_address(addr, host)
652 struct sockaddr_in *addr;
653 char *host;
654 {
655 register struct hostent *hp;
656
657 bzero((char *)addr, sizeof *addr);
658 if (inet_aton(host, &addr->sin_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