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