]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - usr.bin/rpcinfo/rpcinfo.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.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 doesnt 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;
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                                 warnx(
518                 "%s does not support portmapper.  Try rpcinfo %s instead",
519                                         host, host);
520                         exit(1);
521                 }
522                 clnt_perror(client, "rpcinfo: can't contact portmapper");
523                 exit(1);
524         }
525         if (head == NULL) {
526                 printf("No remote programs registered.\n");
527         } else {
528                 printf("   program vers proto   port  service\n");
529                 for (; head != NULL; head = head->pml_next) {
530                         printf("%10ld%5ld",
531                                 head->pml_map.pm_prog,
532                                 head->pml_map.pm_vers);
533                         if (head->pml_map.pm_prot == IPPROTO_UDP)
534                                 printf("%6s", "udp");
535                         else if (head->pml_map.pm_prot == IPPROTO_TCP)
536                                 printf("%6s", "tcp");
537                         else if (head->pml_map.pm_prot == IPPROTO_ST)
538                                 printf("%6s", "local");
539                         else
540                                 printf("%6ld", head->pml_map.pm_prot);
541                         printf("%7ld", head->pml_map.pm_port);
542                         rpc = getrpcbynumber(head->pml_map.pm_prog);
543                         if (rpc)
544                                 printf("  %s\n", rpc->r_name);
545                         else
546                                 printf("\n");
547                 }
548         }
549 }
550
551 static void
552 get_inet_address(struct sockaddr_in *addr, char *host)
553 {
554         struct netconfig *nconf;
555         struct addrinfo hints, *res;
556         int error;
557
558         (void) memset((char *)addr, 0, sizeof (*addr));
559         addr->sin_addr.s_addr = inet_addr(host);
560         if (addr->sin_addr.s_addr == -1 || addr->sin_addr.s_addr == 0) {
561                 if ((nconf = __rpc_getconfip("udp")) == NULL &&
562                     (nconf = __rpc_getconfip("tcp")) == NULL)
563                         errx(1, "couldn't find a suitable transport");
564                 else {
565                         memset(&hints, 0, sizeof hints);
566                         hints.ai_family = AF_INET;
567                         if ((error = getaddrinfo(host, "rpcbind", &hints, &res))
568                             != 0)
569                                 errx(1, "%s: %s", host, gai_strerror(error));
570                         else {
571                                 memcpy(addr, res->ai_addr, res->ai_addrlen);
572                                 freeaddrinfo(res);
573                         }
574                         (void) freenetconfigent(nconf);
575                 }
576         } else {
577                 addr->sin_family = AF_INET;
578         }
579 }
580 #endif /* PORTMAP */
581
582 /*
583  * reply_proc collects replies from the broadcast.
584  * to get a unique list of responses the output of rpcinfo should
585  * be piped through sort(1) and then uniq(1).
586  */
587
588 /*ARGSUSED*/
589 static bool_t
590 reply_proc(void *res, struct netbuf *who, struct netconfig *nconf)
591         /* void *res;                   Nothing comes back */
592         /* struct netbuf *who;          Who sent us the reply */
593         /* struct netconfig *nconf;     On which transport the reply came */
594 {
595         char *uaddr;
596         char hostbuf[NI_MAXHOST];
597         const char *hostname;
598         struct sockaddr *sa = (struct sockaddr *)who->buf;
599
600         if (getnameinfo(sa, sa->sa_len, hostbuf, NI_MAXHOST, NULL, 0, 0)) {
601                 hostname = UNKNOWN;
602         } else {
603                 hostname = hostbuf;
604         }
605         if (!(uaddr = taddr2uaddr(nconf, who))) {
606                 uaddr = UNKNOWN;
607         }
608         printf("%s\t%s\n", uaddr, hostname);
609         if (strcmp(uaddr, UNKNOWN))
610                 free((char *)uaddr);
611         return (FALSE);
612 }
613
614 static void
615 brdcst(int argc, char **argv)
616 {
617         enum clnt_stat rpc_stat;
618         u_long prognum, vers;
619
620         if (argc != 2)
621                 usage();
622         prognum = getprognum(argv[0]);
623         vers = getvers(argv[1]);
624         rpc_stat = rpc_broadcast(prognum, vers, NULLPROC,
625                 (xdrproc_t) xdr_void, (char *)NULL, (xdrproc_t) xdr_void,
626                 (char *)NULL, (resultproc_t) reply_proc, NULL);
627         if ((rpc_stat != RPC_SUCCESS) && (rpc_stat != RPC_TIMEDOUT))
628                 errx(1, "broadcast failed: %s", clnt_sperrno(rpc_stat));
629         exit(0);
630 }
631
632 static bool_t
633 add_version(struct rpcbdump_short *rs, u_long vers)
634 {
635         struct verslist *vl;
636
637         for (vl = rs->vlist; vl; vl = vl->next)
638                 if (vl->vers == vers)
639                         break;
640         if (vl)
641                 return (TRUE);
642         vl = (struct verslist *)malloc(sizeof (struct verslist));
643         if (vl == NULL)
644                 return (FALSE);
645         vl->vers = vers;
646         vl->next = rs->vlist;
647         rs->vlist = vl;
648         return (TRUE);
649 }
650
651 static bool_t
652 add_netid(struct rpcbdump_short *rs, char *netid)
653 {
654         struct netidlist *nl;
655
656         for (nl = rs->nlist; nl; nl = nl->next)
657                 if (strcmp(nl->netid, netid) == 0)
658                         break;
659         if (nl)
660                 return (TRUE);
661         nl = (struct netidlist *)malloc(sizeof (struct netidlist));
662         if (nl == NULL)
663                 return (FALSE);
664         nl->netid = netid;
665         nl->next = rs->nlist;
666         rs->nlist = nl;
667         return (TRUE);
668 }
669
670 static void
671 rpcbdump(int dumptype, char *netid, int argc, char **argv)
672 {
673         rpcblist_ptr head = NULL;
674         struct timeval minutetimeout;
675         register CLIENT *client;
676         struct rpcent *rpc;
677         char *host;
678         struct netidlist *nl;
679         struct verslist *vl;
680         struct rpcbdump_short *rs, *rs_tail;
681         char buf[256];
682         enum clnt_stat clnt_st;
683         struct rpc_err err;
684         struct rpcbdump_short *rs_head = NULL;
685
686         if (argc > 1)
687                 usage();
688         if (argc == 1) {
689                 host = argv[0];
690                 if (netid == NULL) {
691                         client = clnt_rpcbind_create(host, RPCBVERS, NULL);
692                 } else {
693                         struct netconfig *nconf;
694         
695                         nconf = getnetconfigent(netid);
696                         if (nconf == NULL) {
697                                 nc_perror("rpcinfo: invalid transport");
698                                 exit(1);
699                         }
700                         client = getclnthandle(host, nconf, RPCBVERS, NULL);
701                         if (nconf)
702                                 (void) freenetconfigent(nconf);
703                 }
704         } else
705                 client = local_rpcb(PMAPPROG, RPCBVERS);
706
707         if (client == (CLIENT *)NULL) {
708                 clnt_pcreateerror("rpcinfo: can't contact rpcbind");
709                 exit(1);
710         }
711
712         minutetimeout.tv_sec = 60;
713         minutetimeout.tv_usec = 0;
714         clnt_st = CLNT_CALL(client, RPCBPROC_DUMP, (xdrproc_t) xdr_void,
715                 NULL, (xdrproc_t) xdr_rpcblist_ptr, (char *) &head,
716                 minutetimeout);
717         if (clnt_st != RPC_SUCCESS) {
718             if ((clnt_st == RPC_PROGVERSMISMATCH) ||
719                 (clnt_st == RPC_PROGUNAVAIL)) {
720                 int vers;
721
722                 CLNT_GETERR(client, &err);
723                 if (err.re_vers.low == RPCBVERS4) {
724                     vers = RPCBVERS4;
725                     clnt_control(client, CLSET_VERS, (char *)&vers);
726                     clnt_st = CLNT_CALL(client, RPCBPROC_DUMP,
727                         (xdrproc_t) xdr_void, NULL,
728                         (xdrproc_t) xdr_rpcblist_ptr, (char *) &head,
729                         minutetimeout);
730                     if (clnt_st != RPC_SUCCESS)
731                         goto failed;
732                 } else {
733                     if (err.re_vers.high == PMAPVERS) {
734                         int high, low;
735                         struct pmaplist *pmaphead = NULL;
736                         rpcblist_ptr list, prev;
737
738                         vers = PMAPVERS;
739                         clnt_control(client, CLSET_VERS, (char *)&vers);
740                         clnt_st = CLNT_CALL(client, PMAPPROC_DUMP,
741                                 (xdrproc_t) xdr_void, NULL,
742                                 (xdrproc_t) xdr_pmaplist_ptr,
743                                 (char *)&pmaphead, minutetimeout);
744                         if (clnt_st != RPC_SUCCESS)
745                                 goto failed;
746                         /*
747                          * convert to rpcblist_ptr format
748                          */
749                         for (head = NULL; pmaphead != NULL;
750                                 pmaphead = pmaphead->pml_next) {
751                             list = (rpcblist *)malloc(sizeof (rpcblist));
752                             if (list == NULL)
753                                 goto error;
754                             if (head == NULL)
755                                 head = list;
756                             else
757                                 prev->rpcb_next = (rpcblist_ptr) list;
758
759                             list->rpcb_next = NULL;
760                             list->rpcb_map.r_prog = pmaphead->pml_map.pm_prog;
761                             list->rpcb_map.r_vers = pmaphead->pml_map.pm_vers;
762                             if (pmaphead->pml_map.pm_prot == IPPROTO_UDP)
763                                 list->rpcb_map.r_netid = "udp";
764                             else if (pmaphead->pml_map.pm_prot == IPPROTO_TCP)
765                                 list->rpcb_map.r_netid = "tcp";
766                             else {
767 #define MAXLONG_AS_STRING       "2147483648"
768                                 list->rpcb_map.r_netid =
769                                         malloc(strlen(MAXLONG_AS_STRING) + 1);
770                                 if (list->rpcb_map.r_netid == NULL)
771                                         goto error;
772                                 sprintf(list->rpcb_map.r_netid, "%6ld",
773                                         pmaphead->pml_map.pm_prot);
774                             }
775                             list->rpcb_map.r_owner = UNKNOWN;
776                             low = pmaphead->pml_map.pm_port & 0xff;
777                             high = (pmaphead->pml_map.pm_port >> 8) & 0xff;
778                             list->rpcb_map.r_addr = strdup("0.0.0.0.XXX.XXX");
779                             sprintf(&list->rpcb_map.r_addr[8], "%d.%d",
780                                 high, low);
781                             prev = list;
782                         }
783                     }
784                 }
785             } else {    /* any other error */
786 failed:
787                     clnt_perror(client, "rpcinfo: can't contact rpcbind: ");
788                     exit(1);
789             }
790         }
791         if (head == NULL) {
792                 printf("No remote programs registered.\n");
793         } else if (dumptype == RPCBDUMP) {
794                 printf(
795 "   program version netid     address                service    owner\n");
796                 for (; head != NULL; head = head->rpcb_next) {
797                         printf("%10u%5u    ",
798                                 head->rpcb_map.r_prog, head->rpcb_map.r_vers);
799                         printf("%-9s ", head->rpcb_map.r_netid);
800                         printf("%-22s", head->rpcb_map.r_addr);
801                         rpc = getrpcbynumber(head->rpcb_map.r_prog);
802                         if (rpc)
803                                 printf(" %-10s", rpc->r_name);
804                         else
805                                 printf(" %-10s", "-");
806                         printf(" %s\n", head->rpcb_map.r_owner);
807                 }
808         } else if (dumptype == RPCBDUMP_SHORT) {
809                 for (; head != NULL; head = head->rpcb_next) {
810                         for (rs = rs_head; rs; rs = rs->next)
811                                 if (head->rpcb_map.r_prog == rs->prog)
812                                         break;
813                         if (rs == NULL) {
814                                 rs = (struct rpcbdump_short *)
815                                         malloc(sizeof (struct rpcbdump_short));
816                                 if (rs == NULL)
817                                         goto error;
818                                 rs->next = NULL;
819                                 if (rs_head == NULL) {
820                                         rs_head = rs;
821                                         rs_tail = rs;
822                                 } else {
823                                         rs_tail->next = rs;
824                                         rs_tail = rs;
825                                 }
826                                 rs->prog = head->rpcb_map.r_prog;
827                                 rs->owner = head->rpcb_map.r_owner;
828                                 rs->nlist = NULL;
829                                 rs->vlist = NULL;
830                         }
831                         if (add_version(rs, head->rpcb_map.r_vers) == FALSE)
832                                 goto error;
833                         if (add_netid(rs, head->rpcb_map.r_netid) == FALSE)
834                                 goto error;
835                 }
836                 printf(
837 "   program version(s) netid(s)                         service     owner\n");
838                 for (rs = rs_head; rs; rs = rs->next) {
839                         char *p = buf;
840
841                         printf("%10ld  ", rs->prog);
842                         for (vl = rs->vlist; vl; vl = vl->next) {
843                                 sprintf(p, "%d", vl->vers);
844                                 p = p + strlen(p);
845                                 if (vl->next)
846                                         sprintf(p++, ",");
847                         }
848                         printf("%-10s", buf);
849                         buf[0] = '\0';
850                         for (nl = rs->nlist; nl; nl = nl->next) {
851                                 strcat(buf, nl->netid);
852                                 if (nl->next)
853                                         strcat(buf, ",");
854                         }
855                         printf("%-32s", buf);
856                         rpc = getrpcbynumber(rs->prog);
857                         if (rpc)
858                                 printf(" %-11s", rpc->r_name);
859                         else
860                                 printf(" %-11s", "-");
861                         printf(" %s\n", rs->owner);
862                 }
863         }
864         clnt_destroy(client);
865         return;
866 error:  warnx("no memory");
867         return;
868 }
869
870 static char nullstring[] = "\000";
871
872 static void
873 rpcbaddrlist(char *netid, int argc, char **argv)
874 {
875         rpcb_entry_list_ptr head = NULL;
876         struct timeval minutetimeout;
877         register CLIENT *client;
878         struct rpcent *rpc;
879         char *host;
880         RPCB parms;
881         struct netbuf *targaddr;
882
883         if (argc != 3)
884                 usage();
885         host = argv[0];
886         if (netid == NULL) {
887                 client = clnt_rpcbind_create(host, RPCBVERS4, &targaddr);
888         } else {
889                 struct netconfig *nconf;
890
891                 nconf = getnetconfigent(netid);
892                 if (nconf == NULL) {
893                         nc_perror("rpcinfo: invalid transport");
894                         exit(1);
895                 }
896                 client = getclnthandle(host, nconf, RPCBVERS4, &targaddr);
897                 if (nconf)
898                         (void) freenetconfigent(nconf);
899         }
900         if (client == (CLIENT *)NULL) {
901                 clnt_pcreateerror("rpcinfo: can't contact rpcbind");
902                 exit(1);
903         }
904         minutetimeout.tv_sec = 60;
905         minutetimeout.tv_usec = 0;
906
907         parms.r_prog =  getprognum(argv[1]);
908         parms.r_vers =  getvers(argv[2]);
909         parms.r_netid = client->cl_netid;
910         if (targaddr == NULL) {
911                 parms.r_addr = nullstring;      /* for XDRing */
912         } else {
913                 /*
914                  * We also send the remote system the address we
915                  * used to contact it in case it can help it
916                  * connect back with us
917                  */
918                 struct netconfig *nconf;
919
920                 nconf = getnetconfigent(client->cl_netid);
921                 if (nconf != NULL) {
922                         parms.r_addr = taddr2uaddr(nconf, targaddr);
923                         if (parms.r_addr == NULL)
924                                 parms.r_addr = nullstring;
925                         freenetconfigent(nconf);
926                 } else {
927                         parms.r_addr = nullstring;      /* for XDRing */
928                 }
929                 free(targaddr->buf);
930                 free(targaddr);
931         }
932         parms.r_owner = nullstring;
933
934         if (CLNT_CALL(client, RPCBPROC_GETADDRLIST, (xdrproc_t) xdr_rpcb,
935                 (char *) &parms, (xdrproc_t) xdr_rpcb_entry_list_ptr,
936                 (char *) &head, minutetimeout) != RPC_SUCCESS) {
937                 clnt_perror(client, "rpcinfo: can't contact rpcbind: ");
938                 exit(1);
939         }
940         if (head == NULL) {
941                 printf("No remote programs registered.\n");
942         } else {
943                 printf(
944         "   program vers  tp_family/name/class    address\t\t  service\n");
945                 for (; head != NULL; head = head->rpcb_entry_next) {
946                         rpcb_entry *re;
947                         char buf[128];
948
949                         re = &head->rpcb_entry_map;
950                         printf("%10u%3u    ",
951                                 parms.r_prog, parms.r_vers);
952                         sprintf(buf, "%s/%s/%s ",
953                                 re->r_nc_protofmly, re->r_nc_proto,
954                                 re->r_nc_semantics == NC_TPI_CLTS ? "clts" :
955                                 re->r_nc_semantics == NC_TPI_COTS ? "cots" :
956                                                 "cots_ord");
957                         printf("%-24s", buf);
958                         printf("%-24s", re->r_maddr);
959                         rpc = getrpcbynumber(parms.r_prog);
960                         if (rpc)
961                                 printf(" %-13s", rpc->r_name);
962                         else
963                                 printf(" %-13s", "-");
964                         printf("\n");
965                 }
966         }
967         clnt_destroy(client);
968         return;
969 }
970
971 /*
972  * monitor rpcbind
973  */
974 static void
975 rpcbgetstat(int argc, char **argv)
976 {
977         rpcb_stat_byvers inf;
978         struct timeval minutetimeout;
979         register CLIENT *client;
980         char *host;
981         int i, j;
982         rpcbs_addrlist *pa;
983         rpcbs_rmtcalllist *pr;
984         int cnt, flen;
985 #define MAXFIELD        64
986         char fieldbuf[MAXFIELD];
987 #define MAXLINE         256
988         char linebuf[MAXLINE];
989         char *cp, *lp;
990         const char *pmaphdr[] = {
991                 "NULL", "SET", "UNSET", "GETPORT",
992                 "DUMP", "CALLIT"
993         };
994         const char *rpcb3hdr[] = {
995                 "NULL", "SET", "UNSET", "GETADDR", "DUMP", "CALLIT", "TIME",
996                 "U2T", "T2U"
997         };
998         const char *rpcb4hdr[] = {
999                 "NULL", "SET", "UNSET", "GETADDR", "DUMP", "CALLIT", "TIME",
1000                 "U2T",  "T2U", "VERADDR", "INDRECT", "GETLIST", "GETSTAT"
1001         };
1002
1003 #define TABSTOP 8
1004
1005         if (argc >= 1) {
1006                 host = argv[0];
1007                 client = clnt_rpcbind_create(host, RPCBVERS4, NULL);
1008         } else
1009                 client = local_rpcb(PMAPPROG, RPCBVERS4);
1010         if (client == (CLIENT *)NULL) {
1011                 clnt_pcreateerror("rpcinfo: can't contact rpcbind");
1012                 exit(1);
1013         }
1014         minutetimeout.tv_sec = 60;
1015         minutetimeout.tv_usec = 0;
1016         memset((char *)&inf, 0, sizeof (rpcb_stat_byvers));
1017         if (CLNT_CALL(client, RPCBPROC_GETSTAT, (xdrproc_t) xdr_void, NULL,
1018                 (xdrproc_t) xdr_rpcb_stat_byvers, (char *)&inf, minutetimeout)
1019                         != RPC_SUCCESS) {
1020                 clnt_perror(client, "rpcinfo: can't contact rpcbind: ");
1021                 exit(1);
1022         }
1023         printf("PORTMAP (version 2) statistics\n");
1024         lp = linebuf;
1025         for (i = 0; i <= rpcb_highproc_2; i++) {
1026                 fieldbuf[0] = '\0';
1027                 switch (i) {
1028                 case PMAPPROC_SET:
1029                         sprintf(fieldbuf, "%d/", inf[RPCBVERS_2_STAT].setinfo);
1030                         break;
1031                 case PMAPPROC_UNSET:
1032                         sprintf(fieldbuf, "%d/",
1033                                 inf[RPCBVERS_2_STAT].unsetinfo);
1034                         break;
1035                 case PMAPPROC_GETPORT:
1036                         cnt = 0;
1037                         for (pa = inf[RPCBVERS_2_STAT].addrinfo; pa;
1038                                 pa = pa->next)
1039                                 cnt += pa->success;
1040                         sprintf(fieldbuf, "%d/", cnt);
1041                         break;
1042                 case PMAPPROC_CALLIT:
1043                         cnt = 0;
1044                         for (pr = inf[RPCBVERS_2_STAT].rmtinfo; pr;
1045                                 pr = pr->next)
1046                                 cnt += pr->success;
1047                         sprintf(fieldbuf, "%d/", cnt);
1048                         break;
1049                 default: break;  /* For the remaining ones */
1050                 }
1051                 cp = &fieldbuf[0] + strlen(fieldbuf);
1052                 sprintf(cp, "%d", inf[RPCBVERS_2_STAT].info[i]);
1053                 flen = strlen(fieldbuf);
1054                 printf("%s%s", pmaphdr[i],
1055                         spaces((TABSTOP * (1 + flen / TABSTOP))
1056                         - strlen(pmaphdr[i])));
1057                 sprintf(lp, "%s%s", fieldbuf,
1058                         spaces(cnt = ((TABSTOP * (1 + flen / TABSTOP))
1059                         - flen)));
1060                 lp += (flen + cnt);
1061         }
1062         printf("\n%s\n\n", linebuf);
1063
1064         if (inf[RPCBVERS_2_STAT].info[PMAPPROC_CALLIT]) {
1065                 printf("PMAP_RMTCALL call statistics\n");
1066                 print_rmtcallstat(RPCBVERS_2_STAT, &inf[RPCBVERS_2_STAT]);
1067                 printf("\n");
1068         }
1069
1070         if (inf[RPCBVERS_2_STAT].info[PMAPPROC_GETPORT]) {
1071                 printf("PMAP_GETPORT call statistics\n");
1072                 print_getaddrstat(RPCBVERS_2_STAT, &inf[RPCBVERS_2_STAT]);
1073                 printf("\n");
1074         }
1075
1076         printf("RPCBIND (version 3) statistics\n");
1077         lp = linebuf;
1078         for (i = 0; i <= rpcb_highproc_3; i++) {
1079                 fieldbuf[0] = '\0';
1080                 switch (i) {
1081                 case RPCBPROC_SET:
1082                         sprintf(fieldbuf, "%d/", inf[RPCBVERS_3_STAT].setinfo);
1083                         break;
1084                 case RPCBPROC_UNSET:
1085                         sprintf(fieldbuf, "%d/",
1086                                 inf[RPCBVERS_3_STAT].unsetinfo);
1087                         break;
1088                 case RPCBPROC_GETADDR:
1089                         cnt = 0;
1090                         for (pa = inf[RPCBVERS_3_STAT].addrinfo; pa;
1091                                 pa = pa->next)
1092                                 cnt += pa->success;
1093                         sprintf(fieldbuf, "%d/", cnt);
1094                         break;
1095                 case RPCBPROC_CALLIT:
1096                         cnt = 0;
1097                         for (pr = inf[RPCBVERS_3_STAT].rmtinfo; pr;
1098                                 pr = pr->next)
1099                                 cnt += pr->success;
1100                         sprintf(fieldbuf, "%d/", cnt);
1101                         break;
1102                 default: break;  /* For the remaining ones */
1103                 }
1104                 cp = &fieldbuf[0] + strlen(fieldbuf);
1105                 sprintf(cp, "%d", inf[RPCBVERS_3_STAT].info[i]);
1106                 flen = strlen(fieldbuf);
1107                 printf("%s%s", rpcb3hdr[i],
1108                         spaces((TABSTOP * (1 + flen / TABSTOP))
1109                         - strlen(rpcb3hdr[i])));
1110                 sprintf(lp, "%s%s", fieldbuf,
1111                         spaces(cnt = ((TABSTOP * (1 + flen / TABSTOP))
1112                         - flen)));
1113                 lp += (flen + cnt);
1114         }
1115         printf("\n%s\n\n", linebuf);
1116
1117         if (inf[RPCBVERS_3_STAT].info[RPCBPROC_CALLIT]) {
1118                 printf("RPCB_RMTCALL (version 3) call statistics\n");
1119                 print_rmtcallstat(RPCBVERS_3_STAT, &inf[RPCBVERS_3_STAT]);
1120                 printf("\n");
1121         }
1122
1123         if (inf[RPCBVERS_3_STAT].info[RPCBPROC_GETADDR]) {
1124                 printf("RPCB_GETADDR (version 3) call statistics\n");
1125                 print_getaddrstat(RPCBVERS_3_STAT, &inf[RPCBVERS_3_STAT]);
1126                 printf("\n");
1127         }
1128
1129         printf("RPCBIND (version 4) statistics\n");
1130
1131         for (j = 0; j <= 9; j += 9) { /* Just two iterations for printing */
1132                 lp = linebuf;
1133                 for (i = j; i <= MAX(8, rpcb_highproc_4 - 9 + j); i++) {
1134                         fieldbuf[0] = '\0';
1135                         switch (i) {
1136                         case RPCBPROC_SET:
1137                                 sprintf(fieldbuf, "%d/",
1138                                         inf[RPCBVERS_4_STAT].setinfo);
1139                                 break;
1140                         case RPCBPROC_UNSET:
1141                                 sprintf(fieldbuf, "%d/",
1142                                         inf[RPCBVERS_4_STAT].unsetinfo);
1143                                 break;
1144                         case RPCBPROC_GETADDR:
1145                                 cnt = 0;
1146                                 for (pa = inf[RPCBVERS_4_STAT].addrinfo; pa;
1147                                         pa = pa->next)
1148                                         cnt += pa->success;
1149                                 sprintf(fieldbuf, "%d/", cnt);
1150                                 break;
1151                         case RPCBPROC_CALLIT:
1152                                 cnt = 0;
1153                                 for (pr = inf[RPCBVERS_4_STAT].rmtinfo; pr;
1154                                         pr = pr->next)
1155                                         cnt += pr->success;
1156                                 sprintf(fieldbuf, "%d/", cnt);
1157                                 break;
1158                         default: break;  /* For the remaining ones */
1159                         }
1160                         cp = &fieldbuf[0] + strlen(fieldbuf);
1161                         /*
1162                          * XXX: We also add RPCBPROC_GETADDRLIST queries to
1163                          * RPCB_GETADDR because rpcbind includes the
1164                          * RPCB_GETADDRLIST successes in RPCB_GETADDR.
1165                          */
1166                         if (i != RPCBPROC_GETADDR)
1167                             sprintf(cp, "%d", inf[RPCBVERS_4_STAT].info[i]);
1168                         else
1169                             sprintf(cp, "%d", inf[RPCBVERS_4_STAT].info[i] +
1170                             inf[RPCBVERS_4_STAT].info[RPCBPROC_GETADDRLIST]);
1171                         flen = strlen(fieldbuf);
1172                         printf("%s%s", rpcb4hdr[i],
1173                                 spaces((TABSTOP * (1 + flen / TABSTOP))
1174                                 - strlen(rpcb4hdr[i])));
1175                         sprintf(lp, "%s%s", fieldbuf,
1176                                 spaces(cnt = ((TABSTOP * (1 + flen / TABSTOP))
1177                                 - flen)));
1178                         lp += (flen + cnt);
1179                 }
1180                 printf("\n%s\n", linebuf);
1181         }
1182
1183         if (inf[RPCBVERS_4_STAT].info[RPCBPROC_CALLIT] ||
1184                             inf[RPCBVERS_4_STAT].info[RPCBPROC_INDIRECT]) {
1185                 printf("\n");
1186                 printf("RPCB_RMTCALL (version 4) call statistics\n");
1187                 print_rmtcallstat(RPCBVERS_4_STAT, &inf[RPCBVERS_4_STAT]);
1188         }
1189
1190         if (inf[RPCBVERS_4_STAT].info[RPCBPROC_GETADDR]) {
1191                 printf("\n");
1192                 printf("RPCB_GETADDR (version 4) call statistics\n");
1193                 print_getaddrstat(RPCBVERS_4_STAT, &inf[RPCBVERS_4_STAT]);
1194         }
1195         clnt_destroy(client);
1196 }
1197
1198 /*
1199  * Delete registeration for this (prog, vers, netid)
1200  */
1201 static void
1202 deletereg(char *netid, int argc, char **argv)
1203 {
1204         struct netconfig *nconf = NULL;
1205
1206         if (argc != 2)
1207                 usage();
1208         if (netid) {
1209                 nconf = getnetconfigent(netid);
1210                 if (nconf == NULL)
1211                         errx(1, "netid %s not supported", netid);
1212         }
1213         if ((rpcb_unset(getprognum(argv[0]), getvers(argv[1]), nconf)) == 0)
1214                 errx(1,
1215         "could not delete registration for prog %s version %s",
1216                         argv[0], argv[1]);
1217 }
1218
1219 /*
1220  * Create and return a handle for the given nconf.
1221  * Exit if cannot create handle.
1222  */
1223 static CLIENT *
1224 clnt_addr_create(char *address, struct netconfig *nconf,
1225     u_long prog, u_long vers)
1226 {
1227         CLIENT *client;
1228         static struct netbuf *nbuf;
1229         static int fd = RPC_ANYFD;
1230
1231         if (fd == RPC_ANYFD) {
1232                 if ((fd = __rpc_nconf2fd(nconf)) == -1) {
1233                         rpc_createerr.cf_stat = RPC_TLIERROR;
1234                         clnt_pcreateerror("rpcinfo");
1235                         exit(1);
1236                 }
1237                 /* Convert the uaddr to taddr */
1238                 nbuf = uaddr2taddr(nconf, address);
1239                 if (nbuf == NULL)
1240                         errx(1, "no address for client handle");
1241         }
1242         client = clnt_tli_create(fd, nconf, nbuf, prog, vers, 0, 0);
1243         if (client == (CLIENT *)NULL) {
1244                 clnt_pcreateerror("rpcinfo");
1245                 exit(1);
1246         }
1247         return (client);
1248 }
1249
1250 /*
1251  * If the version number is given, ping that (prog, vers); else try to find
1252  * the version numbers supported for that prog and ping all the versions.
1253  * Remote rpcbind is not contacted for this service. The requests are
1254  * sent directly to the services themselves.
1255  */
1256 static void
1257 addrping(char *address, char *netid, int argc, char **argv)
1258 {
1259         CLIENT *client;
1260         struct timeval to;
1261         enum clnt_stat rpc_stat;
1262         u_long prognum, versnum, minvers, maxvers;
1263         struct rpc_err rpcerr;
1264         int failure = 0;
1265         struct netconfig *nconf;
1266         int fd;
1267
1268         if (argc < 1 || argc > 2 || (netid == NULL))
1269                 usage();
1270         nconf = getnetconfigent(netid);
1271         if (nconf == (struct netconfig *)NULL)
1272                 errx(1, "could not find %s", netid);
1273         to.tv_sec = 10;
1274         to.tv_usec = 0;
1275         prognum = getprognum(argv[0]);
1276         if (argc == 1) {        /* Version number not known */
1277                 /*
1278                  * A call to version 0 should fail with a program/version
1279                  * mismatch, and give us the range of versions supported.
1280                  */
1281                 versnum = MIN_VERS;
1282         } else {
1283                 versnum = getvers(argv[1]);
1284         }
1285         client = clnt_addr_create(address, nconf, prognum, versnum);
1286         rpc_stat = CLNT_CALL(client, NULLPROC, (xdrproc_t) xdr_void,
1287                         (char *)NULL, (xdrproc_t) xdr_void,
1288                         (char *)NULL, to);
1289         if (argc == 2) {
1290                 /* Version number was known */
1291                 if (pstatus(client, prognum, versnum) < 0)
1292                         failure = 1;
1293                 (void) CLNT_DESTROY(client);
1294                 if (failure)
1295                         exit(1);
1296                 return;
1297         }
1298         /* Version number not known */
1299         (void) CLNT_CONTROL(client, CLSET_FD_NCLOSE, (char *)NULL);
1300         (void) CLNT_CONTROL(client, CLGET_FD, (char *)&fd);
1301         if (rpc_stat == RPC_PROGVERSMISMATCH) {
1302                 clnt_geterr(client, &rpcerr);
1303                 minvers = rpcerr.re_vers.low;
1304                 maxvers = rpcerr.re_vers.high;
1305         } else if (rpc_stat == RPC_SUCCESS) {
1306                 /*
1307                  * Oh dear, it DOES support version 0.
1308                  * Let's try version MAX_VERS.
1309                  */
1310                 (void) CLNT_DESTROY(client);
1311                 client = clnt_addr_create(address, nconf, prognum, MAX_VERS);
1312                 rpc_stat = CLNT_CALL(client, NULLPROC, (xdrproc_t) xdr_void,
1313                                 (char *)NULL, (xdrproc_t) xdr_void,
1314                                 (char *)NULL, to);
1315                 if (rpc_stat == RPC_PROGVERSMISMATCH) {
1316                         clnt_geterr(client, &rpcerr);
1317                         minvers = rpcerr.re_vers.low;
1318                         maxvers = rpcerr.re_vers.high;
1319                 } else if (rpc_stat == RPC_SUCCESS) {
1320                         /*
1321                          * It also supports version MAX_VERS.
1322                          * Looks like we have a wise guy.
1323                          * OK, we give them information on all
1324                          * 4 billion versions they support...
1325                          */
1326                         minvers = 0;
1327                         maxvers = MAX_VERS;
1328                 } else {
1329                         (void) pstatus(client, prognum, MAX_VERS);
1330                         exit(1);
1331                 }
1332         } else {
1333                 (void) pstatus(client, prognum, (u_long)0);
1334                 exit(1);
1335         }
1336         (void) CLNT_DESTROY(client);
1337         for (versnum = minvers; versnum <= maxvers; versnum++) {
1338                 client = clnt_addr_create(address, nconf, prognum, versnum);
1339                 rpc_stat = CLNT_CALL(client, NULLPROC, (xdrproc_t) xdr_void,
1340                                 (char *)NULL, (xdrproc_t) xdr_void,
1341                                 (char *)NULL, to);
1342                 if (pstatus(client, prognum, versnum) < 0)
1343                                 failure = 1;
1344                 (void) CLNT_DESTROY(client);
1345         }
1346         (void) close(fd);
1347         if (failure)
1348                 exit(1);
1349         return;
1350 }
1351
1352 /*
1353  * If the version number is given, ping that (prog, vers); else try to find
1354  * the version numbers supported for that prog and ping all the versions.
1355  * Remote rpcbind is *contacted* for this service. The requests are
1356  * then sent directly to the services themselves.
1357  */
1358 static void
1359 progping(char *netid, int argc, char **argv)
1360 {
1361         CLIENT *client;
1362         struct timeval to;
1363         enum clnt_stat rpc_stat;
1364         u_long prognum, versnum, minvers, maxvers;
1365         struct rpc_err rpcerr;
1366         int failure = 0;
1367         struct netconfig *nconf;
1368
1369         if (argc < 2 || argc > 3 || (netid == NULL))
1370                 usage();
1371         prognum = getprognum(argv[1]);
1372         if (argc == 2) { /* Version number not known */
1373                 /*
1374                  * A call to version 0 should fail with a program/version
1375                  * mismatch, and give us the range of versions supported.
1376                  */
1377                 versnum = MIN_VERS;
1378         } else {
1379                 versnum = getvers(argv[2]);
1380         }
1381         if (netid) {
1382                 nconf = getnetconfigent(netid);
1383                 if (nconf == (struct netconfig *)NULL)
1384                         errx(1, "could not find %s", netid);
1385                 client = clnt_tp_create(argv[0], prognum, versnum, nconf);
1386         } else {
1387                 client = clnt_create(argv[0], prognum, versnum, "NETPATH");
1388         }
1389         if (client == (CLIENT *)NULL) {
1390                 clnt_pcreateerror("rpcinfo");
1391                 exit(1);
1392         }
1393         to.tv_sec = 10;
1394         to.tv_usec = 0;
1395         rpc_stat = CLNT_CALL(client, NULLPROC, (xdrproc_t) xdr_void,
1396                         (char *)NULL, (xdrproc_t) xdr_void,
1397                         (char *)NULL, to);
1398         if (argc == 3) {
1399                 /* Version number was known */
1400                 if (pstatus(client, prognum, versnum) < 0)
1401                         failure = 1;
1402                 (void) CLNT_DESTROY(client);
1403                 if (failure)
1404                         exit(1);
1405                 return;
1406         }
1407         /* Version number not known */
1408         if (rpc_stat == RPC_PROGVERSMISMATCH) {
1409                 clnt_geterr(client, &rpcerr);
1410                 minvers = rpcerr.re_vers.low;
1411                 maxvers = rpcerr.re_vers.high;
1412         } else if (rpc_stat == RPC_SUCCESS) {
1413                 /*
1414                  * Oh dear, it DOES support version 0.
1415                  * Let's try version MAX_VERS.
1416                  */
1417                 versnum = MAX_VERS;
1418                 (void) CLNT_CONTROL(client, CLSET_VERS, (char *)&versnum);
1419                 rpc_stat = CLNT_CALL(client, NULLPROC,
1420                                 (xdrproc_t) xdr_void, (char *)NULL,
1421                                 (xdrproc_t)  xdr_void, (char *)NULL, to);
1422                 if (rpc_stat == RPC_PROGVERSMISMATCH) {
1423                         clnt_geterr(client, &rpcerr);
1424                         minvers = rpcerr.re_vers.low;
1425                         maxvers = rpcerr.re_vers.high;
1426                 } else if (rpc_stat == RPC_SUCCESS) {
1427                         /*
1428                          * It also supports version MAX_VERS.
1429                          * Looks like we have a wise guy.
1430                          * OK, we give them information on all
1431                          * 4 billion versions they support...
1432                          */
1433                         minvers = 0;
1434                         maxvers = MAX_VERS;
1435                 } else {
1436                         (void) pstatus(client, prognum, MAX_VERS);
1437                         exit(1);
1438                 }
1439         } else {
1440                 (void) pstatus(client, prognum, (u_long)0);
1441                 exit(1);
1442         }
1443         for (versnum = minvers; versnum <= maxvers; versnum++) {
1444                 (void) CLNT_CONTROL(client, CLSET_VERS, (char *)&versnum);
1445                 rpc_stat = CLNT_CALL(client, NULLPROC, (xdrproc_t) xdr_void,
1446                                         (char *)NULL, (xdrproc_t) xdr_void,
1447                                         (char *)NULL, to);
1448                 if (pstatus(client, prognum, versnum) < 0)
1449                                 failure = 1;
1450         }
1451         (void) CLNT_DESTROY(client);
1452         if (failure)
1453                 exit(1);
1454         return;
1455 }
1456
1457 static void
1458 usage(void)
1459 {
1460         fprintf(stderr, "usage: rpcinfo [-m | -s] [host]\n");
1461 #ifdef PORTMAP
1462         fprintf(stderr, "       rpcinfo -p [host]\n");
1463 #endif
1464         fprintf(stderr, "       rpcinfo -T netid host prognum [versnum]\n");
1465         fprintf(stderr, "       rpcinfo -l host prognum versnum\n");
1466 #ifdef PORTMAP
1467         fprintf(stderr,
1468 "       rpcinfo [-n portnum] -u | -t host prognum [versnum]\n");
1469 #endif
1470         fprintf(stderr,
1471 "       rpcinfo -a serv_address -T netid prognum [version]\n");
1472         fprintf(stderr, "       rpcinfo -b prognum versnum\n");
1473         fprintf(stderr, "       rpcinfo -d [-T netid] prognum versnum\n");
1474         exit(1);
1475 }
1476
1477 static u_long
1478 getprognum (char *arg)
1479 {
1480         char *strptr;
1481         register struct rpcent *rpc;
1482         register u_long prognum;
1483         char *tptr = arg;
1484
1485         while (*tptr && isdigit(*tptr++));
1486         if (*tptr || isalpha(*(tptr - 1))) {
1487                 rpc = getrpcbyname(arg);
1488                 if (rpc == NULL)
1489                         errx(1, "%s is unknown service", arg);
1490                 prognum = rpc->r_number;
1491         } else {
1492                 prognum = strtol(arg, &strptr, 10);
1493                 if (strptr == arg || *strptr != '\0')
1494                         errx(1, "%s is illegal program number", arg);
1495         }
1496         return (prognum);
1497 }
1498
1499 static u_long
1500 getvers(char *arg)
1501 {
1502         char *strptr;
1503         register u_long vers;
1504
1505         vers = (int) strtol(arg, &strptr, 10);
1506         if (strptr == arg || *strptr != '\0')
1507                 errx(1, "%s is illegal version number", arg);
1508         return (vers);
1509 }
1510
1511 /*
1512  * This routine should take a pointer to an "rpc_err" structure, rather than
1513  * a pointer to a CLIENT structure, but "clnt_perror" takes a pointer to
1514  * a CLIENT structure rather than a pointer to an "rpc_err" structure.
1515  * As such, we have to keep the CLIENT structure around in order to print
1516  * a good error message.
1517  */
1518 static int
1519 pstatus(register CLIENT *client, u_long prog, u_long vers)
1520 {
1521         struct rpc_err rpcerr;
1522
1523         clnt_geterr(client, &rpcerr);
1524         if (rpcerr.re_status != RPC_SUCCESS) {
1525                 clnt_perror(client, "rpcinfo");
1526                 printf("program %lu version %lu is not available\n",
1527                         prog, vers);
1528                 return (-1);
1529         } else {
1530                 printf("program %lu version %lu ready and waiting\n",
1531                         prog, vers);
1532                 return (0);
1533         }
1534 }
1535
1536 static CLIENT *
1537 clnt_rpcbind_create(char *host, int rpcbversnum, struct netbuf **targaddr)
1538 {
1539         static const char *tlist[3] = {
1540                 "circuit_n", "circuit_v", "datagram_v"
1541         };
1542         int i;
1543         struct netconfig *nconf;
1544         CLIENT *clnt = NULL;
1545         void *handle;
1546
1547         rpc_createerr.cf_stat = RPC_SUCCESS;
1548         for (i = 0; i < 3; i++) {
1549                 if ((handle = __rpc_setconf(tlist[i])) == NULL)
1550                         continue;
1551                 while (clnt == (CLIENT *)NULL) {
1552                         if ((nconf = __rpc_getconf(handle)) == NULL) {
1553                                 if (rpc_createerr.cf_stat == RPC_SUCCESS)
1554                                     rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
1555                                 break;
1556                         }
1557                         clnt = getclnthandle(host, nconf, rpcbversnum,
1558                                         targaddr);
1559                 }
1560                 if (clnt)
1561                         break;
1562                 __rpc_endconf(handle);
1563         }
1564         return (clnt);
1565 }
1566
1567 static CLIENT*
1568 getclnthandle(char *host, struct netconfig *nconf,
1569     u_long rpcbversnum, struct netbuf **targaddr)
1570 {
1571         struct netbuf addr;
1572         struct addrinfo hints, *res;
1573         CLIENT *client = NULL;
1574
1575         /* Get the address of the rpcbind */
1576         memset(&hints, 0, sizeof hints);
1577         if (getaddrinfo(host, "rpcbind", &hints, &res) != 0) {
1578                 rpc_createerr.cf_stat = RPC_N2AXLATEFAILURE;
1579                 return (NULL);
1580         }
1581         addr.len = addr.maxlen = res->ai_addrlen;
1582         addr.buf = res->ai_addr;
1583         client = clnt_tli_create(RPC_ANYFD, nconf, &addr, RPCBPROG,
1584                         rpcbversnum, 0, 0);
1585         if (client) {
1586                 if (targaddr != NULL) {
1587                         *targaddr =
1588                             (struct netbuf *)malloc(sizeof (struct netbuf));
1589                         if (*targaddr != NULL) {
1590                                 (*targaddr)->maxlen = addr.maxlen;
1591                                 (*targaddr)->len = addr.len;
1592                                 (*targaddr)->buf = (char *)malloc(addr.len);
1593                                 if ((*targaddr)->buf != NULL) {
1594                                         memcpy((*targaddr)->buf, addr.buf,
1595                                                 addr.len);
1596                                 }
1597                         }
1598                 }
1599         } else {
1600                 if (rpc_createerr.cf_stat == RPC_TLIERROR) {
1601                         /*
1602                          * Assume that the other system is dead; this is a
1603                          * better error to display to the user.
1604                          */
1605                         rpc_createerr.cf_stat = RPC_RPCBFAILURE;
1606                         rpc_createerr.cf_error.re_status = RPC_FAILED;
1607                 }
1608         }
1609         freeaddrinfo(res);
1610         return (client);
1611 }
1612
1613 static void
1614 print_rmtcallstat(int rtype, rpcb_stat *infp)
1615 {
1616         register rpcbs_rmtcalllist_ptr pr;
1617         struct rpcent *rpc;
1618
1619         if (rtype == RPCBVERS_4_STAT)
1620                 printf(
1621                 "prog\t\tvers\tproc\tnetid\tindirect success failure\n");
1622         else
1623                 printf("prog\t\tvers\tproc\tnetid\tsuccess\tfailure\n");
1624         for (pr = infp->rmtinfo; pr; pr = pr->next) {
1625                 rpc = getrpcbynumber(pr->prog);
1626                 if (rpc)
1627                         printf("%-16s", rpc->r_name);
1628                 else
1629                         printf("%-16d", pr->prog);
1630                 printf("%d\t%d\t%s\t",
1631                         pr->vers, pr->proc, pr->netid);
1632                 if (rtype == RPCBVERS_4_STAT)
1633                         printf("%d\t ", pr->indirect);
1634                 printf("%d\t%d\n", pr->success, pr->failure);
1635         }
1636 }
1637
1638 static void
1639 print_getaddrstat(int rtype, rpcb_stat *infp)
1640 {
1641         rpcbs_addrlist_ptr al;
1642         register struct rpcent *rpc;
1643
1644         printf("prog\t\tvers\tnetid\t  success\tfailure\n");
1645         for (al = infp->addrinfo; al; al = al->next) {
1646                 rpc = getrpcbynumber(al->prog);
1647                 if (rpc)
1648                         printf("%-16s", rpc->r_name);
1649                 else
1650                         printf("%-16d", al->prog);
1651                 printf("%d\t%s\t  %-12d\t%d\n",
1652                         al->vers, al->netid,
1653                         al->success, al->failure);
1654         }
1655 }
1656
1657 static char *
1658 spaces(int howmany)
1659 {
1660         static char space_array[] =             /* 64 spaces */
1661         "                                                                ";
1662
1663         if (howmany <= 0 || howmany > sizeof (space_array)) {
1664                 return ("");
1665         }
1666         return (&space_array[sizeof (space_array) - howmany - 1]);
1667 }