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