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