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