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