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