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