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