]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.bin/rpcinfo/rpcinfo.c
THIS BRANCH IS OBSOLETE, PLEASE READ:
[FreeBSD/FreeBSD.git] / usr.bin / rpcinfo / rpcinfo.c
1 /*      $NetBSD: rpcinfo.c,v 1.15 2000/10/04 20:09:05 mjl Exp $ */
2
3 /*
4  * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
5  * unrestricted use provided that this legend is included on all tape
6  * media and as a part of the software program in whole or part.  Users
7  * may copy or modify Sun RPC without charge, but are not authorized
8  * to license or distribute it to anyone else except as part of a product or
9  * program developed by the user.
10  *
11  * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
12  * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
13  * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
14  *
15  * Sun RPC is provided with no support and without any obligation on the
16  * part of Sun Microsystems, Inc. to assist in its use, correction,
17  * modification or enhancement.
18  *
19  * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
20  * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
21  * OR ANY PART THEREOF.
22  *
23  * In no event will Sun Microsystems, Inc. be liable for any lost revenue
24  * or profits or other special, indirect and consequential damages, even if
25  * Sun has been advised of the possibility of such damages.
26  *
27  * Sun Microsystems, Inc.
28  * 2550 Garcia Avenue
29  * Mountain View, California  94043
30  */
31
32 /*
33  * Copyright (c) 1986 - 1991 by Sun Microsystems, Inc.
34  */
35
36 /* #ident       "@(#)rpcinfo.c  1.18    93/07/05 SMI" */
37
38 #if 0
39 #ifndef lint
40 static char sccsid[] = "@(#)rpcinfo.c 1.16 89/04/05 Copyr 1986 Sun Micro";
41 #endif
42 #endif
43
44 #include <sys/cdefs.h>
45 __FBSDID("$FreeBSD$");
46
47 /*
48  * rpcinfo: ping a particular rpc program
49  *      or dump the registered programs on the remote machine.
50  */
51
52 /*
53  * We are for now defining PORTMAP here.  It doesn't even compile
54  * unless it is defined.
55  */
56 #ifndef PORTMAP
57 #define PORTMAP
58 #endif
59
60 /*
61  * If PORTMAP is defined, rpcinfo will talk to both portmapper and
62  * rpcbind programs; else it talks only to rpcbind. In the latter case
63  * all the portmapper specific options such as -u, -t, -p become void.
64  */
65 #include <sys/types.h>
66 #include <sys/param.h>
67 #include <sys/socket.h>
68 #include <sys/un.h>
69 #include <rpc/rpc.h>
70 #include <stdio.h>
71 #include <rpc/rpcb_prot.h>
72 #include <rpc/rpcent.h>
73 #include <rpc/nettype.h>
74 #include <rpc/rpc_com.h>
75 #include <stdlib.h>
76 #include <string.h>
77 #include <unistd.h>
78 #include <err.h>
79 #include <ctype.h>
80
81 #ifdef PORTMAP          /* Support for version 2 portmapper */
82 #include <netinet/in.h>
83 #include <netdb.h>
84 #include <arpa/inet.h>
85 #include <rpc/pmap_prot.h>
86 #include <rpc/pmap_clnt.h>
87 #endif
88
89 #define MAXHOSTLEN 256
90 #define MIN_VERS        ((u_long) 0)
91 #define MAX_VERS        ((u_long) 4294967295UL)
92 #define UNKNOWN         "unknown"
93
94 /*
95  * Functions to be performed.
96  */
97 #define NONE            0       /* no function */
98 #define PMAPDUMP        1       /* dump portmapper registrations */
99 #define TCPPING         2       /* ping TCP service */
100 #define UDPPING         3       /* ping UDP service */
101 #define BROADCAST       4       /* ping broadcast service */
102 #define DELETES         5       /* delete registration for the service */
103 #define ADDRPING        6       /* pings at the given address */
104 #define PROGPING        7       /* pings a program on a given host */
105 #define RPCBDUMP        8       /* dump rpcbind registrations */
106 #define RPCBDUMP_SHORT  9       /* dump rpcbind registrations - short version */
107 #define RPCBADDRLIST    10      /* dump addr list about one prog */
108 #define RPCBGETSTAT     11      /* Get statistics */
109
110 struct netidlist {
111         char *netid;
112         struct netidlist *next;
113 };
114
115 struct verslist {
116         int vers;
117         struct verslist *next;
118 };
119
120 struct rpcbdump_short {
121         u_long prog;
122         struct verslist *vlist;
123         struct netidlist *nlist;
124         struct rpcbdump_short *next;
125         char *owner;
126 };
127
128
129
130 #ifdef PORTMAP
131 static void     ip_ping(u_short, const char *, int, char **);
132 static CLIENT   *clnt_com_create(struct sockaddr_in *, u_long, u_long, int *,
133                                  const char *);
134 static void     pmapdump(int, char **);
135 static void     get_inet_address(struct sockaddr_in *, char *);
136 #endif
137
138 static bool_t   reply_proc(void *, struct netbuf *, struct netconfig *);
139 static void     brdcst(int, char **);
140 static void     addrping(char *, char *, int, char **);
141 static void     progping(char *, int, char **);
142 static CLIENT   *clnt_addr_create(char *, struct netconfig *, u_long, u_long);
143 static CLIENT   *clnt_rpcbind_create(char *, int, struct netbuf **);
144 static CLIENT   *getclnthandle(char *, struct netconfig *, u_long,
145                                struct netbuf **);
146 static CLIENT   *local_rpcb(u_long, u_long);
147 static int      pstatus(CLIENT *, u_long, u_long);
148 static void     rpcbdump(int, char *, int, char **);
149 static void     rpcbgetstat(int, char **);
150 static void     rpcbaddrlist(char *, int, char **);
151 static void     deletereg(char *, int, char **);
152 static void     print_rmtcallstat(int, rpcb_stat *);
153 static void     print_getaddrstat(int, rpcb_stat *);
154 static void     usage(void);
155 static u_long   getprognum(char *);
156 static u_long   getvers(char *);
157 static char     *spaces(int);
158 static bool_t   add_version(struct rpcbdump_short *, u_long);
159 static bool_t   add_netid(struct rpcbdump_short *, char *);
160
161 int
162 main(int argc, char **argv)
163 {
164         register int c;
165         int errflg;
166         int function;
167         char *netid = NULL;
168         char *address = NULL;
169 #ifdef PORTMAP
170         char *strptr;
171         u_short portnum = 0;
172 #endif
173
174         function = NONE;
175         errflg = 0;
176 #ifdef PORTMAP
177         while ((c = getopt(argc, argv, "a:bdlmn:pstT:u")) != -1) {
178 #else
179         while ((c = getopt(argc, argv, "a:bdlmn:sT:")) != -1) {
180 #endif
181                 switch (c) {
182 #ifdef PORTMAP
183                 case 'p':
184                         if (function != NONE)
185                                 errflg = 1;
186                         else
187                                 function = PMAPDUMP;
188                         break;
189
190                 case 't':
191                         if (function != NONE)
192                                 errflg = 1;
193                         else
194                                 function = TCPPING;
195                         break;
196
197                 case 'u':
198                         if (function != NONE)
199                                 errflg = 1;
200                         else
201                                 function = UDPPING;
202                         break;
203
204                 case 'n':
205                         portnum = (u_short) strtol(optarg, &strptr, 10);
206                         if (strptr == optarg || *strptr != '\0')
207                                 errx(1, "%s is illegal port number", optarg);
208                         break;
209 #endif
210                 case 'a':
211                         address = optarg;
212                         if (function != NONE)
213                                 errflg = 1;
214                         else
215                                 function = ADDRPING;
216                         break;
217                 case 'b':
218                         if (function != NONE)
219                                 errflg = 1;
220                         else
221                                 function = BROADCAST;
222                         break;
223
224                 case 'd':
225                         if (function != NONE)
226                                 errflg = 1;
227                         else
228                                 function = DELETES;
229                         break;
230
231                 case 'l':
232                         if (function != NONE)
233                                 errflg = 1;
234                         else
235                                 function = RPCBADDRLIST;
236                         break;
237
238                 case 'm':
239                         if (function != NONE)
240                                 errflg = 1;
241                         else
242                                 function = RPCBGETSTAT;
243                         break;
244
245                 case 's':
246                         if (function != NONE)
247                                 errflg = 1;
248                         else
249                                 function = RPCBDUMP_SHORT;
250                         break;
251
252                 case 'T':
253                         netid = optarg;
254                         break;
255                 case '?':
256                         errflg = 1;
257                         break;
258                 }
259         }
260
261         if (errflg || ((function == ADDRPING) && !netid))
262                 usage();
263
264         if (function == NONE) {
265                 if (argc - optind > 1)
266                         function = PROGPING;
267                 else
268                         function = RPCBDUMP;
269         }
270
271         switch (function) {
272 #ifdef PORTMAP
273         case PMAPDUMP:
274                 if (portnum != 0)
275                         usage();
276                 pmapdump(argc - optind, argv + optind);
277                 break;
278
279         case UDPPING:
280                 ip_ping(portnum, "udp", argc - optind, argv + optind);
281                 break;
282
283         case TCPPING:
284                 ip_ping(portnum, "tcp", argc - optind, argv + optind);
285                 break;
286 #endif
287         case BROADCAST:
288                 brdcst(argc - optind, argv + optind);
289                 break;
290         case DELETES:
291                 deletereg(netid, argc - optind, argv + optind);
292                 break;
293         case ADDRPING:
294                 addrping(address, netid, argc - optind, argv + optind);
295                 break;
296         case PROGPING:
297                 progping(netid, argc - optind, argv + optind);
298                 break;
299         case RPCBDUMP:
300         case RPCBDUMP_SHORT:
301                 rpcbdump(function, netid, argc - optind, argv + optind);
302                 break;
303         case RPCBGETSTAT:
304                 rpcbgetstat(argc - optind, argv + optind);
305                 break;
306         case RPCBADDRLIST:
307                 rpcbaddrlist(netid, argc - optind, argv + optind);
308                 break;
309         }
310         return (0);
311 }
312
313 static CLIENT *
314 local_rpcb(u_long prog, u_long vers)
315 {
316         void *localhandle;
317         struct netconfig *nconf;
318         CLIENT *clnt;
319
320         localhandle = setnetconfig();
321         while ((nconf = getnetconfig(localhandle)) != NULL) {
322                 if (nconf->nc_protofmly != NULL &&
323                     strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0)
324                         break;
325         }
326         if (nconf == NULL) {
327                 warnx("getnetconfig: %s", nc_sperror());
328                 return (NULL);
329         }
330
331         clnt = clnt_tp_create(NULL, prog, vers, nconf);
332         endnetconfig(localhandle);
333         return clnt;
334 }
335
336 #ifdef PORTMAP
337 static CLIENT *
338 clnt_com_create(struct sockaddr_in *addr, u_long prog, u_long vers,
339     int *fdp, const char *trans)
340 {
341         CLIENT *clnt;
342
343         if (strcmp(trans, "tcp") == 0) {
344                 clnt = clnttcp_create(addr, prog, vers, fdp, 0, 0);
345         } else {
346                 struct timeval to;
347
348                 to.tv_sec = 5;
349                 to.tv_usec = 0;
350                 clnt = clntudp_create(addr, prog, vers, to, fdp);
351         }
352         if (clnt == (CLIENT *)NULL) {
353                 clnt_pcreateerror("rpcinfo");
354                 if (vers == MIN_VERS)
355                         printf("program %lu is not available\n", prog);
356                 else
357                         printf("program %lu version %lu is not available\n",
358                                                         prog, vers);
359                 exit(1);
360         }
361         return (clnt);
362 }
363
364 /*
365  * If portnum is 0, then go and get the address from portmapper, which happens
366  * transparently through clnt*_create(); If version number is not given, it
367  * tries to find out the version number by making a call to version 0 and if
368  * that fails, it obtains the high order and the low order version number. If
369  * version 0 calls succeeds, it tries for MAXVERS call and repeats the same.
370  */
371 static void
372 ip_ping(u_short portnum, const char *trans, int argc, char **argv)
373 {
374         CLIENT *client;
375         int fd = RPC_ANYFD;
376         struct timeval to;
377         struct sockaddr_in addr;
378         enum clnt_stat rpc_stat;
379         u_long prognum, vers, minvers, maxvers;
380         struct rpc_err rpcerr;
381         int failure = 0;
382
383         if (argc < 2 || argc > 3)
384                 usage();
385         to.tv_sec = 10;
386         to.tv_usec = 0;
387         prognum = getprognum(argv[1]);
388         get_inet_address(&addr, argv[0]);
389         if (argc == 2) {        /* Version number not known */
390                 /*
391                  * A call to version 0 should fail with a program/version
392                  * mismatch, and give us the range of versions supported.
393                  */
394                 vers = MIN_VERS;
395         } else {
396                 vers = getvers(argv[2]);
397         }
398         addr.sin_port = htons(portnum);
399         client = clnt_com_create(&addr, prognum, vers, &fd, trans);
400         rpc_stat = CLNT_CALL(client, NULLPROC, (xdrproc_t) xdr_void,
401                         (char *)NULL, (xdrproc_t) xdr_void, (char *)NULL,
402                         to);
403         if (argc != 2) {
404                 /* Version number was known */
405                 if (pstatus(client, prognum, vers) < 0)
406                         exit(1);
407                 (void) CLNT_DESTROY(client);
408                 return;
409         }
410         /* Version number not known */
411         (void) CLNT_CONTROL(client, CLSET_FD_NCLOSE, (char *)NULL);
412         if (rpc_stat == RPC_PROGVERSMISMATCH) {
413                 clnt_geterr(client, &rpcerr);
414                 minvers = rpcerr.re_vers.low;
415                 maxvers = rpcerr.re_vers.high;
416         } else if (rpc_stat == RPC_SUCCESS) {
417                 /*
418                  * Oh dear, it DOES support version 0.
419                  * Let's try version MAX_VERS.
420                  */
421                 (void) CLNT_DESTROY(client);
422                 addr.sin_port = htons(portnum);
423                 client = clnt_com_create(&addr, prognum, MAX_VERS, &fd, trans);
424                 rpc_stat = CLNT_CALL(client, NULLPROC, (xdrproc_t) xdr_void,
425                                 (char *)NULL, (xdrproc_t) xdr_void,
426                                 (char *)NULL, to);
427                 if (rpc_stat == RPC_PROGVERSMISMATCH) {
428                         clnt_geterr(client, &rpcerr);
429                         minvers = rpcerr.re_vers.low;
430                         maxvers = rpcerr.re_vers.high;
431                 } else if (rpc_stat == RPC_SUCCESS) {
432                         /*
433                          * It also supports version MAX_VERS.
434                          * Looks like we have a wise guy.
435                          * OK, we give them information on all
436                          * 4 billion versions they support...
437                          */
438                         minvers = 0;
439                         maxvers = MAX_VERS;
440                 } else {
441                         (void) pstatus(client, prognum, MAX_VERS);
442                         exit(1);
443                 }
444         } else {
445                 (void) pstatus(client, prognum, (u_long)0);
446                 exit(1);
447         }
448         (void) CLNT_DESTROY(client);
449         for (vers = minvers; vers <= maxvers; vers++) {
450                 addr.sin_port = htons(portnum);
451                 client = clnt_com_create(&addr, prognum, vers, &fd, trans);
452                 rpc_stat = CLNT_CALL(client, NULLPROC, (xdrproc_t) xdr_void,
453                                 (char *)NULL, (xdrproc_t) xdr_void,
454                                 (char *)NULL, to);
455                 if (pstatus(client, prognum, vers) < 0)
456                                 failure = 1;
457                 (void) CLNT_DESTROY(client);
458         }
459         if (failure)
460                 exit(1);
461         (void) close(fd);
462         return;
463 }
464
465 /*
466  * Dump all the portmapper registerations
467  */
468 static void
469 pmapdump(int argc, char **argv)
470 {
471         struct sockaddr_in server_addr;
472         struct pmaplist *head = NULL;
473         int socket = RPC_ANYSOCK;
474         struct timeval minutetimeout;
475         register CLIENT *client;
476         struct rpcent *rpc;
477         enum clnt_stat clnt_st;
478         struct rpc_err err;
479         char *host = NULL;
480
481         if (argc > 1)
482                 usage();
483         if (argc == 1) {
484                 host = argv[0];
485                 get_inet_address(&server_addr, host);
486                 server_addr.sin_port = htons(PMAPPORT);
487                 client = clnttcp_create(&server_addr, PMAPPROG, PMAPVERS,
488                     &socket, 50, 500);
489         } else
490                 client = local_rpcb(PMAPPROG, PMAPVERS);
491
492         if (client == NULL) {
493                 if (rpc_createerr.cf_stat == RPC_TLIERROR) {
494                         /*
495                          * "Misc. TLI error" is not too helpful. Most likely
496                          * the connection to the remote server timed out, so
497                          * this error is at least less perplexing.
498                          */
499                         rpc_createerr.cf_stat = RPC_PMAPFAILURE;
500                         rpc_createerr.cf_error.re_status = RPC_FAILED;
501                 }
502                 clnt_pcreateerror("rpcinfo: can't contact portmapper");
503                 exit(1);
504         }
505
506         minutetimeout.tv_sec = 60;
507         minutetimeout.tv_usec = 0;
508
509         clnt_st = CLNT_CALL(client, PMAPPROC_DUMP, (xdrproc_t) xdr_void,
510                 NULL, (xdrproc_t) xdr_pmaplist_ptr, (char *)&head,
511                 minutetimeout);
512         if (clnt_st != RPC_SUCCESS) {
513                 if ((clnt_st == RPC_PROGVERSMISMATCH) ||
514                     (clnt_st == RPC_PROGUNAVAIL)) {
515                         CLNT_GETERR(client, &err);
516                         if (err.re_vers.low > PMAPVERS) {
517                                 if (host)
518                                         warnx("%s does not support portmapper."
519                                             "Try rpcinfo %s instead", host,
520                                             host);
521                                 else
522                                         warnx("local host does not support "
523                                             "portmapper.  Try 'rpcinfo' "
524                                             "instead");
525                         }
526                         exit(1);
527                 }
528                 clnt_perror(client, "rpcinfo: can't contact portmapper");
529                 exit(1);
530         }
531         if (head == NULL) {
532                 printf("No remote programs registered.\n");
533         } else {
534                 printf("   program vers proto   port  service\n");
535                 for (; head != NULL; head = head->pml_next) {
536                         printf("%10ld%5ld",
537                                 head->pml_map.pm_prog,
538                                 head->pml_map.pm_vers);
539                         if (head->pml_map.pm_prot == IPPROTO_UDP)
540                                 printf("%6s", "udp");
541                         else if (head->pml_map.pm_prot == IPPROTO_TCP)
542                                 printf("%6s", "tcp");
543                         else if (head->pml_map.pm_prot == IPPROTO_ST)
544                                 printf("%6s", "local");
545                         else
546                                 printf("%6ld", head->pml_map.pm_prot);
547                         printf("%7ld", head->pml_map.pm_port);
548                         rpc = getrpcbynumber(head->pml_map.pm_prog);
549                         if (rpc)
550                                 printf("  %s\n", rpc->r_name);
551                         else
552                                 printf("\n");
553                 }
554         }
555 }
556
557 static void
558 get_inet_address(struct sockaddr_in *addr, char *host)
559 {
560         struct netconfig *nconf;
561         struct addrinfo hints, *res;
562         int error;
563
564         (void) memset((char *)addr, 0, sizeof (*addr));
565         addr->sin_addr.s_addr = inet_addr(host);
566         if (addr->sin_addr.s_addr == INADDR_NONE ||
567             addr->sin_addr.s_addr == INADDR_ANY) {
568                 if ((nconf = __rpc_getconfip("udp")) == NULL &&
569                     (nconf = __rpc_getconfip("tcp")) == NULL)
570                         errx(1, "couldn't find a suitable transport");
571                 else {
572                         memset(&hints, 0, sizeof hints);
573                         hints.ai_family = AF_INET;
574                         if ((error = getaddrinfo(host, "rpcbind", &hints, &res))
575                             != 0)
576                                 errx(1, "%s: %s", host, gai_strerror(error));
577                         else {
578                                 memcpy(addr, res->ai_addr, res->ai_addrlen);
579                                 freeaddrinfo(res);
580                         }
581                         (void) freenetconfigent(nconf);
582                 }
583         } else {
584                 addr->sin_family = AF_INET;
585         }
586 }
587 #endif /* PORTMAP */
588
589 /*
590  * reply_proc collects replies from the broadcast.
591  * to get a unique list of responses the output of rpcinfo should
592  * be piped through sort(1) and then uniq(1).
593  */
594
595 /*ARGSUSED*/
596 static bool_t
597 reply_proc(void *res, struct netbuf *who, struct netconfig *nconf)
598         /* void *res;                   Nothing comes back */
599         /* struct netbuf *who;          Who sent us the reply */
600         /* struct netconfig *nconf;     On which transport the reply came */
601 {
602         char *uaddr;
603         char hostbuf[NI_MAXHOST];
604         const char *hostname;
605         struct sockaddr *sa = (struct sockaddr *)who->buf;
606
607         if (getnameinfo(sa, sa->sa_len, hostbuf, NI_MAXHOST, NULL, 0, 0)) {
608                 hostname = UNKNOWN;
609         } else {
610                 hostname = hostbuf;
611         }
612         uaddr = taddr2uaddr(nconf, who);
613         if (uaddr == NULL) {
614                 printf("%s\t%s\n", UNKNOWN, hostname);
615         } else {
616                 printf("%s\t%s\n", uaddr, hostname);
617                 free((char *)uaddr);
618         }
619         return (FALSE);
620 }
621
622 static void
623 brdcst(int argc, char **argv)
624 {
625         enum clnt_stat rpc_stat;
626         u_long prognum, vers;
627
628         if (argc != 2)
629                 usage();
630         prognum = getprognum(argv[0]);
631         vers = getvers(argv[1]);
632         rpc_stat = rpc_broadcast(prognum, vers, NULLPROC,
633                 (xdrproc_t) xdr_void, (char *)NULL, (xdrproc_t) xdr_void,
634                 (char *)NULL, (resultproc_t) reply_proc, NULL);
635         if ((rpc_stat != RPC_SUCCESS) && (rpc_stat != RPC_TIMEDOUT))
636                 errx(1, "broadcast failed: %s", clnt_sperrno(rpc_stat));
637         exit(0);
638 }
639
640 static bool_t
641 add_version(struct rpcbdump_short *rs, u_long vers)
642 {
643         struct verslist *vl;
644
645         for (vl = rs->vlist; vl; vl = vl->next)
646                 if (vl->vers == vers)
647                         break;
648         if (vl)
649                 return (TRUE);
650         vl = (struct verslist *)malloc(sizeof (struct verslist));
651         if (vl == NULL)
652                 return (FALSE);
653         vl->vers = vers;
654         vl->next = rs->vlist;
655         rs->vlist = vl;
656         return (TRUE);
657 }
658
659 static bool_t
660 add_netid(struct rpcbdump_short *rs, char *netid)
661 {
662         struct netidlist *nl;
663
664         for (nl = rs->nlist; nl; nl = nl->next)
665                 if (strcmp(nl->netid, netid) == 0)
666                         break;
667         if (nl)
668                 return (TRUE);
669         nl = (struct netidlist *)malloc(sizeof (struct netidlist));
670         if (nl == NULL)
671                 return (FALSE);
672         nl->netid = netid;
673         nl->next = rs->nlist;
674         rs->nlist = nl;
675         return (TRUE);
676 }
677
678 static void
679 rpcbdump(int dumptype, char *netid, int argc, char **argv)
680 {
681         rpcblist_ptr head = NULL;
682         struct timeval minutetimeout;
683         register CLIENT *client;
684         struct rpcent *rpc;
685         char *host;
686         struct netidlist *nl;
687         struct verslist *vl;
688         struct rpcbdump_short *rs, *rs_tail;
689         char buf[256];
690         enum clnt_stat clnt_st;
691         struct rpc_err err;
692         struct rpcbdump_short *rs_head = NULL;
693
694         if (argc > 1)
695                 usage();
696         if (argc == 1) {
697                 host = argv[0];
698                 if (netid == NULL) {
699                         client = clnt_rpcbind_create(host, RPCBVERS, NULL);
700                 } else {
701                         struct netconfig *nconf;
702         
703                         nconf = getnetconfigent(netid);
704                         if (nconf == NULL) {
705                                 nc_perror("rpcinfo: invalid transport");
706                                 exit(1);
707                         }
708                         client = getclnthandle(host, nconf, RPCBVERS, NULL);
709                         if (nconf)
710                                 (void) freenetconfigent(nconf);
711                 }
712         } else
713                 client = local_rpcb(PMAPPROG, RPCBVERS);
714
715         if (client == (CLIENT *)NULL) {
716                 clnt_pcreateerror("rpcinfo: can't contact rpcbind");
717                 exit(1);
718         }
719
720         minutetimeout.tv_sec = 60;
721         minutetimeout.tv_usec = 0;
722         clnt_st = CLNT_CALL(client, RPCBPROC_DUMP, (xdrproc_t) xdr_void,
723                 NULL, (xdrproc_t) xdr_rpcblist_ptr, (char *) &head,
724                 minutetimeout);
725         if (clnt_st != RPC_SUCCESS) {
726             if ((clnt_st == RPC_PROGVERSMISMATCH) ||
727                 (clnt_st == RPC_PROGUNAVAIL)) {
728                 int vers;
729
730                 CLNT_GETERR(client, &err);
731                 if (err.re_vers.low == RPCBVERS4) {
732                     vers = RPCBVERS4;
733                     clnt_control(client, CLSET_VERS, (char *)&vers);
734                     clnt_st = CLNT_CALL(client, RPCBPROC_DUMP,
735                         (xdrproc_t) xdr_void, NULL,
736                         (xdrproc_t) xdr_rpcblist_ptr, (char *) &head,
737                         minutetimeout);
738                     if (clnt_st != RPC_SUCCESS)
739                         goto failed;
740                 } else {
741                     if (err.re_vers.high == PMAPVERS) {
742                         int high, low;
743                         struct pmaplist *pmaphead = NULL;
744                         rpcblist_ptr list, prev;
745
746                         vers = PMAPVERS;
747                         clnt_control(client, CLSET_VERS, (char *)&vers);
748                         clnt_st = CLNT_CALL(client, PMAPPROC_DUMP,
749                                 (xdrproc_t) xdr_void, NULL,
750                                 (xdrproc_t) xdr_pmaplist_ptr,
751                                 (char *)&pmaphead, minutetimeout);
752                         if (clnt_st != RPC_SUCCESS)
753                                 goto failed;
754                         /*
755                          * convert to rpcblist_ptr format
756                          */
757                         for (head = NULL; pmaphead != NULL;
758                                 pmaphead = pmaphead->pml_next) {
759                             list = (rpcblist *)malloc(sizeof (rpcblist));
760                             if (list == NULL)
761                                 goto error;
762                             if (head == NULL)
763                                 head = list;
764                             else
765                                 prev->rpcb_next = (rpcblist_ptr) list;
766
767                             list->rpcb_next = NULL;
768                             list->rpcb_map.r_prog = pmaphead->pml_map.pm_prog;
769                             list->rpcb_map.r_vers = pmaphead->pml_map.pm_vers;
770                             if (pmaphead->pml_map.pm_prot == IPPROTO_UDP)
771                                 list->rpcb_map.r_netid = "udp";
772                             else if (pmaphead->pml_map.pm_prot == IPPROTO_TCP)
773                                 list->rpcb_map.r_netid = "tcp";
774                             else {
775 #define MAXLONG_AS_STRING       "2147483648"
776                                 list->rpcb_map.r_netid =
777                                         malloc(strlen(MAXLONG_AS_STRING) + 1);
778                                 if (list->rpcb_map.r_netid == NULL)
779                                         goto error;
780                                 sprintf(list->rpcb_map.r_netid, "%6ld",
781                                         pmaphead->pml_map.pm_prot);
782                             }
783                             list->rpcb_map.r_owner = UNKNOWN;
784                             low = pmaphead->pml_map.pm_port & 0xff;
785                             high = (pmaphead->pml_map.pm_port >> 8) & 0xff;
786                             list->rpcb_map.r_addr = strdup("0.0.0.0.XXX.XXX");
787                             sprintf(&list->rpcb_map.r_addr[8], "%d.%d",
788                                 high, low);
789                             prev = list;
790                         }
791                     }
792                 }
793             } else {    /* any other error */
794 failed:
795                     clnt_perror(client, "rpcinfo: can't contact rpcbind: ");
796                     exit(1);
797             }
798         }
799         if (head == NULL) {
800                 printf("No remote programs registered.\n");
801         } else if (dumptype == RPCBDUMP) {
802                 printf(
803 "   program version netid     address                service    owner\n");
804                 for (; head != NULL; head = head->rpcb_next) {
805                         printf("%10u%5u    ",
806                                 head->rpcb_map.r_prog, head->rpcb_map.r_vers);
807                         printf("%-9s ", head->rpcb_map.r_netid);
808                         printf("%-22s", head->rpcb_map.r_addr);
809                         rpc = getrpcbynumber(head->rpcb_map.r_prog);
810                         if (rpc)
811                                 printf(" %-10s", rpc->r_name);
812                         else
813                                 printf(" %-10s", "-");
814                         printf(" %s\n", head->rpcb_map.r_owner);
815                 }
816         } else if (dumptype == RPCBDUMP_SHORT) {
817                 for (; head != NULL; head = head->rpcb_next) {
818                         for (rs = rs_head; rs; rs = rs->next)
819                                 if (head->rpcb_map.r_prog == rs->prog)
820                                         break;
821                         if (rs == NULL) {
822                                 rs = (struct rpcbdump_short *)
823                                         malloc(sizeof (struct rpcbdump_short));
824                                 if (rs == NULL)
825                                         goto error;
826                                 rs->next = NULL;
827                                 if (rs_head == NULL) {
828                                         rs_head = rs;
829                                         rs_tail = rs;
830                                 } else {
831                                         rs_tail->next = rs;
832                                         rs_tail = rs;
833                                 }
834                                 rs->prog = head->rpcb_map.r_prog;
835                                 rs->owner = head->rpcb_map.r_owner;
836                                 rs->nlist = NULL;
837                                 rs->vlist = NULL;
838                         }
839                         if (add_version(rs, head->rpcb_map.r_vers) == FALSE)
840                                 goto error;
841                         if (add_netid(rs, head->rpcb_map.r_netid) == FALSE)
842                                 goto error;
843                 }
844                 printf(
845 "   program version(s) netid(s)                         service     owner\n");
846                 for (rs = rs_head; rs; rs = rs->next) {
847                         char *p = buf;
848
849                         printf("%10ld  ", rs->prog);
850                         for (vl = rs->vlist; vl; vl = vl->next) {
851                                 sprintf(p, "%d", vl->vers);
852                                 p = p + strlen(p);
853                                 if (vl->next)
854                                         sprintf(p++, ",");
855                         }
856                         printf("%-10s", buf);
857                         buf[0] = '\0';
858                         for (nl = rs->nlist; nl; nl = nl->next) {
859                                 strlcat(buf, nl->netid, sizeof(buf));
860                                 if (nl->next)
861                                         strlcat(buf, ",", sizeof(buf));
862                         }
863                         printf("%-32s", buf);
864                         rpc = getrpcbynumber(rs->prog);
865                         if (rpc)
866                                 printf(" %-11s", rpc->r_name);
867                         else
868                                 printf(" %-11s", "-");
869                         printf(" %s\n", rs->owner);
870                 }
871         }
872         clnt_destroy(client);
873         return;
874 error:  warnx("no memory");
875         return;
876 }
877
878 static char nullstring[] = "\000";
879
880 static void
881 rpcbaddrlist(char *netid, int argc, char **argv)
882 {
883         rpcb_entry_list_ptr head = NULL;
884         struct timeval minutetimeout;
885         register CLIENT *client;
886         struct rpcent *rpc;
887         char *host;
888         RPCB parms;
889         struct netbuf *targaddr;
890
891         if (argc != 3)
892                 usage();
893         host = argv[0];
894         if (netid == NULL) {
895                 client = clnt_rpcbind_create(host, RPCBVERS4, &targaddr);
896         } else {
897                 struct netconfig *nconf;
898
899                 nconf = getnetconfigent(netid);
900                 if (nconf == NULL) {
901                         nc_perror("rpcinfo: invalid transport");
902                         exit(1);
903                 }
904                 client = getclnthandle(host, nconf, RPCBVERS4, &targaddr);
905                 if (nconf)
906                         (void) freenetconfigent(nconf);
907         }
908         if (client == (CLIENT *)NULL) {
909                 clnt_pcreateerror("rpcinfo: can't contact rpcbind");
910                 exit(1);
911         }
912         minutetimeout.tv_sec = 60;
913         minutetimeout.tv_usec = 0;
914
915         parms.r_prog =  getprognum(argv[1]);
916         parms.r_vers =  getvers(argv[2]);
917         parms.r_netid = client->cl_netid;
918         if (targaddr == NULL) {
919                 parms.r_addr = nullstring;      /* for XDRing */
920         } else {
921                 /*
922                  * We also send the remote system the address we
923                  * used to contact it in case it can help it
924                  * connect back with us
925                  */
926                 struct netconfig *nconf;
927
928                 nconf = getnetconfigent(client->cl_netid);
929                 if (nconf != NULL) {
930                         parms.r_addr = taddr2uaddr(nconf, targaddr);
931                         if (parms.r_addr == NULL)
932                                 parms.r_addr = nullstring;
933                         freenetconfigent(nconf);
934                 } else {
935                         parms.r_addr = nullstring;      /* for XDRing */
936                 }
937                 free(targaddr->buf);
938                 free(targaddr);
939         }
940         parms.r_owner = nullstring;
941
942         if (CLNT_CALL(client, RPCBPROC_GETADDRLIST, (xdrproc_t) xdr_rpcb,
943                 (char *) &parms, (xdrproc_t) xdr_rpcb_entry_list_ptr,
944                 (char *) &head, minutetimeout) != RPC_SUCCESS) {
945                 clnt_perror(client, "rpcinfo: can't contact rpcbind: ");
946                 exit(1);
947         }
948         if (head == NULL) {
949                 printf("No remote programs registered.\n");
950         } else {
951                 printf(
952         "   program vers  tp_family/name/class    address\t\t  service\n");
953                 for (; head != NULL; head = head->rpcb_entry_next) {
954                         rpcb_entry *re;
955                         char buf[128];
956
957                         re = &head->rpcb_entry_map;
958                         printf("%10u%3u    ",
959                                 parms.r_prog, parms.r_vers);
960                         sprintf(buf, "%s/%s/%s ",
961                                 re->r_nc_protofmly, re->r_nc_proto,
962                                 re->r_nc_semantics == NC_TPI_CLTS ? "clts" :
963                                 re->r_nc_semantics == NC_TPI_COTS ? "cots" :
964                                                 "cots_ord");
965                         printf("%-24s", buf);
966                         printf("%-24s", re->r_maddr);
967                         rpc = getrpcbynumber(parms.r_prog);
968                         if (rpc)
969                                 printf(" %-13s", rpc->r_name);
970                         else
971                                 printf(" %-13s", "-");
972                         printf("\n");
973                 }
974         }
975         clnt_destroy(client);
976         return;
977 }
978
979 /*
980  * monitor rpcbind
981  */
982 static void
983 rpcbgetstat(int argc, char **argv)
984 {
985         rpcb_stat_byvers inf;
986         struct timeval minutetimeout;
987         register CLIENT *client;
988         char *host;
989         int i, j;
990         rpcbs_addrlist *pa;
991         rpcbs_rmtcalllist *pr;
992         int cnt, flen;
993 #define MAXFIELD        64
994         char fieldbuf[MAXFIELD];
995 #define MAXLINE         256
996         char linebuf[MAXLINE];
997         char *cp, *lp;
998         const char *pmaphdr[] = {
999                 "NULL", "SET", "UNSET", "GETPORT",
1000                 "DUMP", "CALLIT"
1001         };
1002         const char *rpcb3hdr[] = {
1003                 "NULL", "SET", "UNSET", "GETADDR", "DUMP", "CALLIT", "TIME",
1004                 "U2T", "T2U"
1005         };
1006         const char *rpcb4hdr[] = {
1007                 "NULL", "SET", "UNSET", "GETADDR", "DUMP", "CALLIT", "TIME",
1008                 "U2T",  "T2U", "VERADDR", "INDRECT", "GETLIST", "GETSTAT"
1009         };
1010
1011 #define TABSTOP 8
1012
1013         if (argc >= 1) {
1014                 host = argv[0];
1015                 client = clnt_rpcbind_create(host, RPCBVERS4, NULL);
1016         } else
1017                 client = local_rpcb(PMAPPROG, RPCBVERS4);
1018         if (client == (CLIENT *)NULL) {
1019                 clnt_pcreateerror("rpcinfo: can't contact rpcbind");
1020                 exit(1);
1021         }
1022         minutetimeout.tv_sec = 60;
1023         minutetimeout.tv_usec = 0;
1024         memset((char *)&inf, 0, sizeof (rpcb_stat_byvers));
1025         if (CLNT_CALL(client, RPCBPROC_GETSTAT, (xdrproc_t) xdr_void, NULL,
1026                 (xdrproc_t) xdr_rpcb_stat_byvers, (char *)&inf, minutetimeout)
1027                         != RPC_SUCCESS) {
1028                 clnt_perror(client, "rpcinfo: can't contact rpcbind: ");
1029                 exit(1);
1030         }
1031         printf("PORTMAP (version 2) statistics\n");
1032         lp = linebuf;
1033         for (i = 0; i <= rpcb_highproc_2; i++) {
1034                 fieldbuf[0] = '\0';
1035                 switch (i) {
1036                 case PMAPPROC_SET:
1037                         sprintf(fieldbuf, "%d/", inf[RPCBVERS_2_STAT].setinfo);
1038                         break;
1039                 case PMAPPROC_UNSET:
1040                         sprintf(fieldbuf, "%d/",
1041                                 inf[RPCBVERS_2_STAT].unsetinfo);
1042                         break;
1043                 case PMAPPROC_GETPORT:
1044                         cnt = 0;
1045                         for (pa = inf[RPCBVERS_2_STAT].addrinfo; pa;
1046                                 pa = pa->next)
1047                                 cnt += pa->success;
1048                         sprintf(fieldbuf, "%d/", cnt);
1049                         break;
1050                 case PMAPPROC_CALLIT:
1051                         cnt = 0;
1052                         for (pr = inf[RPCBVERS_2_STAT].rmtinfo; pr;
1053                                 pr = pr->next)
1054                                 cnt += pr->success;
1055                         sprintf(fieldbuf, "%d/", cnt);
1056                         break;
1057                 default: break;  /* For the remaining ones */
1058                 }
1059                 cp = &fieldbuf[0] + strlen(fieldbuf);
1060                 sprintf(cp, "%d", inf[RPCBVERS_2_STAT].info[i]);
1061                 flen = strlen(fieldbuf);
1062                 printf("%s%s", pmaphdr[i],
1063                         spaces((TABSTOP * (1 + flen / TABSTOP))
1064                         - strlen(pmaphdr[i])));
1065                 sprintf(lp, "%s%s", fieldbuf,
1066                         spaces(cnt = ((TABSTOP * (1 + flen / TABSTOP))
1067                         - flen)));
1068                 lp += (flen + cnt);
1069         }
1070         printf("\n%s\n\n", linebuf);
1071
1072         if (inf[RPCBVERS_2_STAT].info[PMAPPROC_CALLIT]) {
1073                 printf("PMAP_RMTCALL call statistics\n");
1074                 print_rmtcallstat(RPCBVERS_2_STAT, &inf[RPCBVERS_2_STAT]);
1075                 printf("\n");
1076         }
1077
1078         if (inf[RPCBVERS_2_STAT].info[PMAPPROC_GETPORT]) {
1079                 printf("PMAP_GETPORT call statistics\n");
1080                 print_getaddrstat(RPCBVERS_2_STAT, &inf[RPCBVERS_2_STAT]);
1081                 printf("\n");
1082         }
1083
1084         printf("RPCBIND (version 3) statistics\n");
1085         lp = linebuf;
1086         for (i = 0; i <= rpcb_highproc_3; i++) {
1087                 fieldbuf[0] = '\0';
1088                 switch (i) {
1089                 case RPCBPROC_SET:
1090                         sprintf(fieldbuf, "%d/", inf[RPCBVERS_3_STAT].setinfo);
1091                         break;
1092                 case RPCBPROC_UNSET:
1093                         sprintf(fieldbuf, "%d/",
1094                                 inf[RPCBVERS_3_STAT].unsetinfo);
1095                         break;
1096                 case RPCBPROC_GETADDR:
1097                         cnt = 0;
1098                         for (pa = inf[RPCBVERS_3_STAT].addrinfo; pa;
1099                                 pa = pa->next)
1100                                 cnt += pa->success;
1101                         sprintf(fieldbuf, "%d/", cnt);
1102                         break;
1103                 case RPCBPROC_CALLIT:
1104                         cnt = 0;
1105                         for (pr = inf[RPCBVERS_3_STAT].rmtinfo; pr;
1106                                 pr = pr->next)
1107                                 cnt += pr->success;
1108                         sprintf(fieldbuf, "%d/", cnt);
1109                         break;
1110                 default: break;  /* For the remaining ones */
1111                 }
1112                 cp = &fieldbuf[0] + strlen(fieldbuf);
1113                 sprintf(cp, "%d", inf[RPCBVERS_3_STAT].info[i]);
1114                 flen = strlen(fieldbuf);
1115                 printf("%s%s", rpcb3hdr[i],
1116                         spaces((TABSTOP * (1 + flen / TABSTOP))
1117                         - strlen(rpcb3hdr[i])));
1118                 sprintf(lp, "%s%s", fieldbuf,
1119                         spaces(cnt = ((TABSTOP * (1 + flen / TABSTOP))
1120                         - flen)));
1121                 lp += (flen + cnt);
1122         }
1123         printf("\n%s\n\n", linebuf);
1124
1125         if (inf[RPCBVERS_3_STAT].info[RPCBPROC_CALLIT]) {
1126                 printf("RPCB_RMTCALL (version 3) call statistics\n");
1127                 print_rmtcallstat(RPCBVERS_3_STAT, &inf[RPCBVERS_3_STAT]);
1128                 printf("\n");
1129         }
1130
1131         if (inf[RPCBVERS_3_STAT].info[RPCBPROC_GETADDR]) {
1132                 printf("RPCB_GETADDR (version 3) call statistics\n");
1133                 print_getaddrstat(RPCBVERS_3_STAT, &inf[RPCBVERS_3_STAT]);
1134                 printf("\n");
1135         }
1136
1137         printf("RPCBIND (version 4) statistics\n");
1138
1139         for (j = 0; j <= 9; j += 9) { /* Just two iterations for printing */
1140                 lp = linebuf;
1141                 for (i = j; i <= MAX(8, rpcb_highproc_4 - 9 + j); i++) {
1142                         fieldbuf[0] = '\0';
1143                         switch (i) {
1144                         case RPCBPROC_SET:
1145                                 sprintf(fieldbuf, "%d/",
1146                                         inf[RPCBVERS_4_STAT].setinfo);
1147                                 break;
1148                         case RPCBPROC_UNSET:
1149                                 sprintf(fieldbuf, "%d/",
1150                                         inf[RPCBVERS_4_STAT].unsetinfo);
1151                                 break;
1152                         case RPCBPROC_GETADDR:
1153                                 cnt = 0;
1154                                 for (pa = inf[RPCBVERS_4_STAT].addrinfo; pa;
1155                                         pa = pa->next)
1156                                         cnt += pa->success;
1157                                 sprintf(fieldbuf, "%d/", cnt);
1158                                 break;
1159                         case RPCBPROC_CALLIT:
1160                                 cnt = 0;
1161                                 for (pr = inf[RPCBVERS_4_STAT].rmtinfo; pr;
1162                                         pr = pr->next)
1163                                         cnt += pr->success;
1164                                 sprintf(fieldbuf, "%d/", cnt);
1165                                 break;
1166                         default: break;  /* For the remaining ones */
1167                         }
1168                         cp = &fieldbuf[0] + strlen(fieldbuf);
1169                         /*
1170                          * XXX: We also add RPCBPROC_GETADDRLIST queries to
1171                          * RPCB_GETADDR because rpcbind includes the
1172                          * RPCB_GETADDRLIST successes in RPCB_GETADDR.
1173                          */
1174                         if (i != RPCBPROC_GETADDR)
1175                             sprintf(cp, "%d", inf[RPCBVERS_4_STAT].info[i]);
1176                         else
1177                             sprintf(cp, "%d", inf[RPCBVERS_4_STAT].info[i] +
1178                             inf[RPCBVERS_4_STAT].info[RPCBPROC_GETADDRLIST]);
1179                         flen = strlen(fieldbuf);
1180                         printf("%s%s", rpcb4hdr[i],
1181                                 spaces((TABSTOP * (1 + flen / TABSTOP))
1182                                 - strlen(rpcb4hdr[i])));
1183                         sprintf(lp, "%s%s", fieldbuf,
1184                                 spaces(cnt = ((TABSTOP * (1 + flen / TABSTOP))
1185                                 - flen)));
1186                         lp += (flen + cnt);
1187                 }
1188                 printf("\n%s\n", linebuf);
1189         }
1190
1191         if (inf[RPCBVERS_4_STAT].info[RPCBPROC_CALLIT] ||
1192                             inf[RPCBVERS_4_STAT].info[RPCBPROC_INDIRECT]) {
1193                 printf("\n");
1194                 printf("RPCB_RMTCALL (version 4) call statistics\n");
1195                 print_rmtcallstat(RPCBVERS_4_STAT, &inf[RPCBVERS_4_STAT]);
1196         }
1197
1198         if (inf[RPCBVERS_4_STAT].info[RPCBPROC_GETADDR]) {
1199                 printf("\n");
1200                 printf("RPCB_GETADDR (version 4) call statistics\n");
1201                 print_getaddrstat(RPCBVERS_4_STAT, &inf[RPCBVERS_4_STAT]);
1202         }
1203         clnt_destroy(client);
1204 }
1205
1206 /*
1207  * Delete registeration for this (prog, vers, netid)
1208  */
1209 static void
1210 deletereg(char *netid, int argc, char **argv)
1211 {
1212         struct netconfig *nconf = NULL;
1213
1214         if (argc != 2)
1215                 usage();
1216         if (netid) {
1217                 nconf = getnetconfigent(netid);
1218                 if (nconf == NULL)
1219                         errx(1, "netid %s not supported", netid);
1220         }
1221         if ((rpcb_unset(getprognum(argv[0]), getvers(argv[1]), nconf)) == 0)
1222                 errx(1,
1223         "could not delete registration for prog %s version %s",
1224                         argv[0], argv[1]);
1225 }
1226
1227 /*
1228  * Create and return a handle for the given nconf.
1229  * Exit if cannot create handle.
1230  */
1231 static CLIENT *
1232 clnt_addr_create(char *address, struct netconfig *nconf,
1233     u_long prog, u_long vers)
1234 {
1235         CLIENT *client;
1236         static struct netbuf *nbuf;
1237         static int fd = RPC_ANYFD;
1238
1239         if (fd == RPC_ANYFD) {
1240                 if ((fd = __rpc_nconf2fd(nconf)) == -1) {
1241                         rpc_createerr.cf_stat = RPC_TLIERROR;
1242                         clnt_pcreateerror("rpcinfo");
1243                         exit(1);
1244                 }
1245                 /* Convert the uaddr to taddr */
1246                 nbuf = uaddr2taddr(nconf, address);
1247                 if (nbuf == NULL)
1248                         errx(1, "no address for client handle");
1249         }
1250         client = clnt_tli_create(fd, nconf, nbuf, prog, vers, 0, 0);
1251         if (client == (CLIENT *)NULL) {
1252                 clnt_pcreateerror("rpcinfo");
1253                 exit(1);
1254         }
1255         return (client);
1256 }
1257
1258 /*
1259  * If the version number is given, ping that (prog, vers); else try to find
1260  * the version numbers supported for that prog and ping all the versions.
1261  * Remote rpcbind is not contacted for this service. The requests are
1262  * sent directly to the services themselves.
1263  */
1264 static void
1265 addrping(char *address, char *netid, int argc, char **argv)
1266 {
1267         CLIENT *client;
1268         struct timeval to;
1269         enum clnt_stat rpc_stat;
1270         u_long prognum, versnum, minvers, maxvers;
1271         struct rpc_err rpcerr;
1272         int failure = 0;
1273         struct netconfig *nconf;
1274         int fd;
1275
1276         if (argc < 1 || argc > 2 || (netid == NULL))
1277                 usage();
1278         nconf = getnetconfigent(netid);
1279         if (nconf == (struct netconfig *)NULL)
1280                 errx(1, "could not find %s", netid);
1281         to.tv_sec = 10;
1282         to.tv_usec = 0;
1283         prognum = getprognum(argv[0]);
1284         if (argc == 1) {        /* Version number not known */
1285                 /*
1286                  * A call to version 0 should fail with a program/version
1287                  * mismatch, and give us the range of versions supported.
1288                  */
1289                 versnum = MIN_VERS;
1290         } else {
1291                 versnum = getvers(argv[1]);
1292         }
1293         client = clnt_addr_create(address, nconf, prognum, versnum);
1294         rpc_stat = CLNT_CALL(client, NULLPROC, (xdrproc_t) xdr_void,
1295                         (char *)NULL, (xdrproc_t) xdr_void,
1296                         (char *)NULL, to);
1297         if (argc == 2) {
1298                 /* Version number was known */
1299                 if (pstatus(client, prognum, versnum) < 0)
1300                         failure = 1;
1301                 (void) CLNT_DESTROY(client);
1302                 if (failure)
1303                         exit(1);
1304                 return;
1305         }
1306         /* Version number not known */
1307         (void) CLNT_CONTROL(client, CLSET_FD_NCLOSE, (char *)NULL);
1308         (void) CLNT_CONTROL(client, CLGET_FD, (char *)&fd);
1309         if (rpc_stat == RPC_PROGVERSMISMATCH) {
1310                 clnt_geterr(client, &rpcerr);
1311                 minvers = rpcerr.re_vers.low;
1312                 maxvers = rpcerr.re_vers.high;
1313         } else if (rpc_stat == RPC_SUCCESS) {
1314                 /*
1315                  * Oh dear, it DOES support version 0.
1316                  * Let's try version MAX_VERS.
1317                  */
1318                 (void) CLNT_DESTROY(client);
1319                 client = clnt_addr_create(address, nconf, prognum, MAX_VERS);
1320                 rpc_stat = CLNT_CALL(client, NULLPROC, (xdrproc_t) xdr_void,
1321                                 (char *)NULL, (xdrproc_t) xdr_void,
1322                                 (char *)NULL, to);
1323                 if (rpc_stat == RPC_PROGVERSMISMATCH) {
1324                         clnt_geterr(client, &rpcerr);
1325                         minvers = rpcerr.re_vers.low;
1326                         maxvers = rpcerr.re_vers.high;
1327                 } else if (rpc_stat == RPC_SUCCESS) {
1328                         /*
1329                          * It also supports version MAX_VERS.
1330                          * Looks like we have a wise guy.
1331                          * OK, we give them information on all
1332                          * 4 billion versions they support...
1333                          */
1334                         minvers = 0;
1335                         maxvers = MAX_VERS;
1336                 } else {
1337                         (void) pstatus(client, prognum, MAX_VERS);
1338                         exit(1);
1339                 }
1340         } else {
1341                 (void) pstatus(client, prognum, (u_long)0);
1342                 exit(1);
1343         }
1344         (void) CLNT_DESTROY(client);
1345         for (versnum = minvers; versnum <= maxvers; versnum++) {
1346                 client = clnt_addr_create(address, nconf, prognum, versnum);
1347                 rpc_stat = CLNT_CALL(client, NULLPROC, (xdrproc_t) xdr_void,
1348                                 (char *)NULL, (xdrproc_t) xdr_void,
1349                                 (char *)NULL, to);
1350                 if (pstatus(client, prognum, versnum) < 0)
1351                                 failure = 1;
1352                 (void) CLNT_DESTROY(client);
1353         }
1354         (void) close(fd);
1355         if (failure)
1356                 exit(1);
1357         return;
1358 }
1359
1360 /*
1361  * If the version number is given, ping that (prog, vers); else try to find
1362  * the version numbers supported for that prog and ping all the versions.
1363  * Remote rpcbind is *contacted* for this service. The requests are
1364  * then sent directly to the services themselves.
1365  */
1366 static void
1367 progping(char *netid, int argc, char **argv)
1368 {
1369         CLIENT *client;
1370         struct timeval to;
1371         enum clnt_stat rpc_stat;
1372         u_long prognum, versnum, minvers, maxvers;
1373         struct rpc_err rpcerr;
1374         int failure = 0;
1375         struct netconfig *nconf;
1376
1377         if (argc < 2 || argc > 3 || (netid == NULL))
1378                 usage();
1379         prognum = getprognum(argv[1]);
1380         if (argc == 2) { /* Version number not known */
1381                 /*
1382                  * A call to version 0 should fail with a program/version
1383                  * mismatch, and give us the range of versions supported.
1384                  */
1385                 versnum = MIN_VERS;
1386         } else {
1387                 versnum = getvers(argv[2]);
1388         }
1389         if (netid) {
1390                 nconf = getnetconfigent(netid);
1391                 if (nconf == (struct netconfig *)NULL)
1392                         errx(1, "could not find %s", netid);
1393                 client = clnt_tp_create(argv[0], prognum, versnum, nconf);
1394         } else {
1395                 client = clnt_create(argv[0], prognum, versnum, "NETPATH");
1396         }
1397         if (client == (CLIENT *)NULL) {
1398                 clnt_pcreateerror("rpcinfo");
1399                 exit(1);
1400         }
1401         to.tv_sec = 10;
1402         to.tv_usec = 0;
1403         rpc_stat = CLNT_CALL(client, NULLPROC, (xdrproc_t) xdr_void,
1404                         (char *)NULL, (xdrproc_t) xdr_void,
1405                         (char *)NULL, to);
1406         if (argc == 3) {
1407                 /* Version number was known */
1408                 if (pstatus(client, prognum, versnum) < 0)
1409                         failure = 1;
1410                 (void) CLNT_DESTROY(client);
1411                 if (failure)
1412                         exit(1);
1413                 return;
1414         }
1415         /* Version number not known */
1416         if (rpc_stat == RPC_PROGVERSMISMATCH) {
1417                 clnt_geterr(client, &rpcerr);
1418                 minvers = rpcerr.re_vers.low;
1419                 maxvers = rpcerr.re_vers.high;
1420         } else if (rpc_stat == RPC_SUCCESS) {
1421                 /*
1422                  * Oh dear, it DOES support version 0.
1423                  * Let's try version MAX_VERS.
1424                  */
1425                 versnum = MAX_VERS;
1426                 (void) CLNT_CONTROL(client, CLSET_VERS, (char *)&versnum);
1427                 rpc_stat = CLNT_CALL(client, NULLPROC,
1428                                 (xdrproc_t) xdr_void, (char *)NULL,
1429                                 (xdrproc_t)  xdr_void, (char *)NULL, to);
1430                 if (rpc_stat == RPC_PROGVERSMISMATCH) {
1431                         clnt_geterr(client, &rpcerr);
1432                         minvers = rpcerr.re_vers.low;
1433                         maxvers = rpcerr.re_vers.high;
1434                 } else if (rpc_stat == RPC_SUCCESS) {
1435                         /*
1436                          * It also supports version MAX_VERS.
1437                          * Looks like we have a wise guy.
1438                          * OK, we give them information on all
1439                          * 4 billion versions they support...
1440                          */
1441                         minvers = 0;
1442                         maxvers = MAX_VERS;
1443                 } else {
1444                         (void) pstatus(client, prognum, MAX_VERS);
1445                         exit(1);
1446                 }
1447         } else {
1448                 (void) pstatus(client, prognum, (u_long)0);
1449                 exit(1);
1450         }
1451         for (versnum = minvers; versnum <= maxvers; versnum++) {
1452                 (void) CLNT_CONTROL(client, CLSET_VERS, (char *)&versnum);
1453                 rpc_stat = CLNT_CALL(client, NULLPROC, (xdrproc_t) xdr_void,
1454                                         (char *)NULL, (xdrproc_t) xdr_void,
1455                                         (char *)NULL, to);
1456                 if (pstatus(client, prognum, versnum) < 0)
1457                                 failure = 1;
1458         }
1459         (void) CLNT_DESTROY(client);
1460         if (failure)
1461                 exit(1);
1462         return;
1463 }
1464
1465 static void
1466 usage(void)
1467 {
1468         fprintf(stderr, "usage: rpcinfo [-m | -s] [host]\n");
1469 #ifdef PORTMAP
1470         fprintf(stderr, "       rpcinfo -p [host]\n");
1471 #endif
1472         fprintf(stderr, "       rpcinfo -T netid host prognum [versnum]\n");
1473         fprintf(stderr, "       rpcinfo -l host prognum versnum\n");
1474 #ifdef PORTMAP
1475         fprintf(stderr,
1476 "       rpcinfo [-n portnum] -u | -t host prognum [versnum]\n");
1477 #endif
1478         fprintf(stderr,
1479 "       rpcinfo -a serv_address -T netid prognum [version]\n");
1480         fprintf(stderr, "       rpcinfo -b prognum versnum\n");
1481         fprintf(stderr, "       rpcinfo -d [-T netid] prognum versnum\n");
1482         exit(1);
1483 }
1484
1485 static u_long
1486 getprognum (char *arg)
1487 {
1488         char *strptr;
1489         register struct rpcent *rpc;
1490         register u_long prognum;
1491         char *tptr = arg;
1492
1493         while (*tptr && isdigit(*tptr++));
1494         if (*tptr || isalpha(*(tptr - 1))) {
1495                 rpc = getrpcbyname(arg);
1496                 if (rpc == NULL)
1497                         errx(1, "%s is unknown service", arg);
1498                 prognum = rpc->r_number;
1499         } else {
1500                 prognum = strtol(arg, &strptr, 10);
1501                 if (strptr == arg || *strptr != '\0')
1502                         errx(1, "%s is illegal program number", arg);
1503         }
1504         return (prognum);
1505 }
1506
1507 static u_long
1508 getvers(char *arg)
1509 {
1510         char *strptr;
1511         register u_long vers;
1512
1513         vers = (int) strtol(arg, &strptr, 10);
1514         if (strptr == arg || *strptr != '\0')
1515                 errx(1, "%s is illegal version number", arg);
1516         return (vers);
1517 }
1518
1519 /*
1520  * This routine should take a pointer to an "rpc_err" structure, rather than
1521  * a pointer to a CLIENT structure, but "clnt_perror" takes a pointer to
1522  * a CLIENT structure rather than a pointer to an "rpc_err" structure.
1523  * As such, we have to keep the CLIENT structure around in order to print
1524  * a good error message.
1525  */
1526 static int
1527 pstatus(register CLIENT *client, u_long prog, u_long vers)
1528 {
1529         struct rpc_err rpcerr;
1530
1531         clnt_geterr(client, &rpcerr);
1532         if (rpcerr.re_status != RPC_SUCCESS) {
1533                 clnt_perror(client, "rpcinfo");
1534                 printf("program %lu version %lu is not available\n",
1535                         prog, vers);
1536                 return (-1);
1537         } else {
1538                 printf("program %lu version %lu ready and waiting\n",
1539                         prog, vers);
1540                 return (0);
1541         }
1542 }
1543
1544 static CLIENT *
1545 clnt_rpcbind_create(char *host, int rpcbversnum, struct netbuf **targaddr)
1546 {
1547         static const char *tlist[3] = {
1548                 "circuit_n", "circuit_v", "datagram_v"
1549         };
1550         int i;
1551         struct netconfig *nconf;
1552         CLIENT *clnt = NULL;
1553         void *handle;
1554
1555         rpc_createerr.cf_stat = RPC_SUCCESS;
1556         for (i = 0; i < 3; i++) {
1557                 if ((handle = __rpc_setconf(tlist[i])) == NULL)
1558                         continue;
1559                 while (clnt == (CLIENT *)NULL) {
1560                         if ((nconf = __rpc_getconf(handle)) == NULL) {
1561                                 if (rpc_createerr.cf_stat == RPC_SUCCESS)
1562                                     rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
1563                                 break;
1564                         }
1565                         clnt = getclnthandle(host, nconf, rpcbversnum,
1566                                         targaddr);
1567                 }
1568                 if (clnt)
1569                         break;
1570                 __rpc_endconf(handle);
1571         }
1572         return (clnt);
1573 }
1574
1575 static CLIENT*
1576 getclnthandle(char *host, struct netconfig *nconf,
1577     u_long rpcbversnum, struct netbuf **targaddr)
1578 {
1579         struct netbuf addr;
1580         struct addrinfo hints, *res;
1581         CLIENT *client = NULL;
1582
1583         /* Get the address of the rpcbind */
1584         memset(&hints, 0, sizeof hints);
1585         if (getaddrinfo(host, "rpcbind", &hints, &res) != 0) {
1586                 rpc_createerr.cf_stat = RPC_N2AXLATEFAILURE;
1587                 return (NULL);
1588         }
1589         addr.len = addr.maxlen = res->ai_addrlen;
1590         addr.buf = res->ai_addr;
1591         client = clnt_tli_create(RPC_ANYFD, nconf, &addr, RPCBPROG,
1592                         rpcbversnum, 0, 0);
1593         if (client) {
1594                 if (targaddr != NULL) {
1595                         *targaddr =
1596                             (struct netbuf *)malloc(sizeof (struct netbuf));
1597                         if (*targaddr != NULL) {
1598                                 (*targaddr)->maxlen = addr.maxlen;
1599                                 (*targaddr)->len = addr.len;
1600                                 (*targaddr)->buf = (char *)malloc(addr.len);
1601                                 if ((*targaddr)->buf != NULL) {
1602                                         memcpy((*targaddr)->buf, addr.buf,
1603                                                 addr.len);
1604                                 }
1605                         }
1606                 }
1607         } else {
1608                 if (rpc_createerr.cf_stat == RPC_TLIERROR) {
1609                         /*
1610                          * Assume that the other system is dead; this is a
1611                          * better error to display to the user.
1612                          */
1613                         rpc_createerr.cf_stat = RPC_RPCBFAILURE;
1614                         rpc_createerr.cf_error.re_status = RPC_FAILED;
1615                 }
1616         }
1617         freeaddrinfo(res);
1618         return (client);
1619 }
1620
1621 static void
1622 print_rmtcallstat(int rtype, rpcb_stat *infp)
1623 {
1624         register rpcbs_rmtcalllist_ptr pr;
1625         struct rpcent *rpc;
1626
1627         if (rtype == RPCBVERS_4_STAT)
1628                 printf(
1629                 "prog\t\tvers\tproc\tnetid\tindirect success failure\n");
1630         else
1631                 printf("prog\t\tvers\tproc\tnetid\tsuccess\tfailure\n");
1632         for (pr = infp->rmtinfo; pr; pr = pr->next) {
1633                 rpc = getrpcbynumber(pr->prog);
1634                 if (rpc)
1635                         printf("%-16s", rpc->r_name);
1636                 else
1637                         printf("%-16d", pr->prog);
1638                 printf("%d\t%d\t%s\t",
1639                         pr->vers, pr->proc, pr->netid);
1640                 if (rtype == RPCBVERS_4_STAT)
1641                         printf("%d\t ", pr->indirect);
1642                 printf("%d\t%d\n", pr->success, pr->failure);
1643         }
1644 }
1645
1646 static void
1647 print_getaddrstat(int rtype, rpcb_stat *infp)
1648 {
1649         rpcbs_addrlist_ptr al;
1650         register struct rpcent *rpc;
1651
1652         printf("prog\t\tvers\tnetid\t  success\tfailure\n");
1653         for (al = infp->addrinfo; al; al = al->next) {
1654                 rpc = getrpcbynumber(al->prog);
1655                 if (rpc)
1656                         printf("%-16s", rpc->r_name);
1657                 else
1658                         printf("%-16d", al->prog);
1659                 printf("%d\t%s\t  %-12d\t%d\n",
1660                         al->vers, al->netid,
1661                         al->success, al->failure);
1662         }
1663 }
1664
1665 static char *
1666 spaces(int howmany)
1667 {
1668         static char space_array[] =             /* 64 spaces */
1669         "                                                                ";
1670
1671         if (howmany <= 0 || howmany > sizeof (space_array)) {
1672                 return ("");
1673         }
1674         return (&space_array[sizeof (space_array) - howmany - 1]);
1675 }