Annotation of src/usr.bin/rpcinfo/rpcinfo.c, Revision 1.4
1.4 ! millert 1: /* $OpenBSD: rpcinfo.c,v 1.3 1996/06/29 01:07:33 deraadt Exp $ */
1.2 deraadt 2:
1.1 deraadt 3: #ifndef lint
4: /*static char sccsid[] = "from: @(#)rpcinfo.c 1.22 87/08/12 SMI";*/
5: /*static char sccsid[] = "from: @(#)rpcinfo.c 2.2 88/08/11 4.0 RPCSRC";*/
1.4 ! millert 6: static char rcsid[] = "$OpenBSD: rpcinfo.c,v 1.3 1996/06/29 01:07:33 deraadt Exp $";
1.1 deraadt 7: #endif
8:
9: /*
10: * Copyright (C) 1986, Sun Microsystems, Inc.
11: */
12:
13: /*
14: * rpcinfo: ping a particular rpc program
15: * or dump the portmapper
16: */
17:
18: /*
19: * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
20: * unrestricted use provided that this legend is included on all tape
21: * media and as a part of the software program in whole or part. Users
22: * may copy or modify Sun RPC without charge, but are not authorized
23: * to license or distribute it to anyone else except as part of a product or
24: * program developed by the user.
25: *
26: * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
27: * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
28: * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
29: *
30: * Sun RPC is provided with no support and without any obligation on the
31: * part of Sun Microsystems, Inc. to assist in its use, correction,
32: * modification or enhancement.
33: *
34: * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
35: * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
36: * OR ANY PART THEREOF.
37: *
38: * In no event will Sun Microsystems, Inc. be liable for any lost revenue
39: * or profits or other special, indirect and consequential damages, even if
40: * Sun has been advised of the possibility of such damages.
41: *
42: * Sun Microsystems, Inc.
43: * 2550 Garcia Avenue
44: * Mountain View, California 94043
45: */
46:
47: #include <rpc/rpc.h>
48: #include <stdio.h>
49: #include <sys/socket.h>
50: #include <netdb.h>
51: #include <rpc/pmap_prot.h>
52: #include <rpc/pmap_clnt.h>
53: #include <signal.h>
54: #include <ctype.h>
55: #include <arpa/inet.h>
56:
57: #define MAXHOSTLEN 256
58:
59: #define MIN_VERS ((u_long) 0)
60: #define MAX_VERS ((u_long) 4294967295UL)
61:
62: static void udpping(/*u_short portflag, int argc, char **argv*/);
63: static void tcpping(/*u_short portflag, int argc, char **argv*/);
64: static int pstatus(/*CLIENT *client, u_long prognum, u_long vers*/);
65: static void pmapdump(/*int argc, char **argv*/);
66: static bool_t reply_proc(/*void *res, struct sockaddr_in *who*/);
67: static void brdcst(/*int argc, char **argv*/);
68: static void deletereg(/* int argc, char **argv */) ;
69: static void usage(/*void*/);
70: static u_long getprognum(/*char *arg*/);
71: static u_long getvers(/*char *arg*/);
72: static void get_inet_address(/*struct sockaddr_in *addr, char *host*/);
73:
74: /*
75: * Functions to be performed.
76: */
77: #define NONE 0 /* no function */
78: #define PMAPDUMP 1 /* dump portmapper registrations */
79: #define TCPPING 2 /* ping TCP service */
80: #define UDPPING 3 /* ping UDP service */
81: #define BRDCST 4 /* ping broadcast UDP service */
82: #define DELETES 5 /* delete registration for the service */
83:
84: int
85: main(argc, argv)
86: int argc;
87: char **argv;
88: {
89: register int c;
90: extern char *optarg;
91: extern int optind;
92: int errflg;
93: int function;
94: u_short portnum;
95:
96: function = NONE;
97: portnum = 0;
98: errflg = 0;
1.4 ! millert 99: while ((c = getopt(argc, argv, "ptubdn:")) != -1) {
1.1 deraadt 100: switch (c) {
101:
102: case 'p':
103: if (function != NONE)
104: errflg = 1;
105: else
106: function = PMAPDUMP;
107: break;
108:
109: case 't':
110: if (function != NONE)
111: errflg = 1;
112: else
113: function = TCPPING;
114: break;
115:
116: case 'u':
117: if (function != NONE)
118: errflg = 1;
119: else
120: function = UDPPING;
121: break;
122:
123: case 'b':
124: if (function != NONE)
125: errflg = 1;
126: else
127: function = BRDCST;
128: break;
129:
130: case 'n':
131: portnum = (u_short) atoi(optarg); /* hope we don't get bogus # */
132: break;
133:
134: case 'd':
135: if (function != NONE)
136: errflg = 1;
137: else
138: function = DELETES;
139: break;
140:
141: case '?':
142: errflg = 1;
143: }
144: }
145:
146: if (errflg || function == NONE) {
147: usage();
148: return (1);
149: }
150:
151: switch (function) {
152:
153: case PMAPDUMP:
154: if (portnum != 0) {
155: usage();
156: return (1);
157: }
158: pmapdump(argc - optind, argv + optind);
159: break;
160:
161: case UDPPING:
162: udpping(portnum, argc - optind, argv + optind);
163: break;
164:
165: case TCPPING:
166: tcpping(portnum, argc - optind, argv + optind);
167: break;
168:
169: case BRDCST:
170: if (portnum != 0) {
171: usage();
172: return (1);
173: }
174: brdcst(argc - optind, argv + optind);
175: break;
176:
177: case DELETES:
178: deletereg(argc - optind, argv + optind);
179: break;
180: }
181:
182: return (0);
183: }
184:
185: static void
186: udpping(portnum, argc, argv)
187: u_short portnum;
188: int argc;
189: char **argv;
190: {
191: struct timeval to;
192: struct sockaddr_in addr;
193: enum clnt_stat rpc_stat;
194: CLIENT *client;
195: u_long prognum, vers, minvers, maxvers;
196: int sock = RPC_ANYSOCK;
197: struct rpc_err rpcerr;
198: int failure;
199:
200: if (argc < 2 || argc > 3) {
201: usage();
202: exit(1);
203: }
204: prognum = getprognum(argv[1]);
205: get_inet_address(&addr, argv[0]);
206: /* Open the socket here so it will survive calls to clnt_destroy */
1.3 deraadt 207: sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
1.1 deraadt 208: if (sock < 0) {
209: perror("rpcinfo: socket");
210: exit(1);
211: }
1.3 deraadt 212: if (getuid() == 0)
213: bindresvport(sock, NULL);
1.1 deraadt 214: failure = 0;
215: if (argc == 2) {
216: /*
217: * A call to version 0 should fail with a program/version
218: * mismatch, and give us the range of versions supported.
219: */
220: addr.sin_port = htons(portnum);
221: to.tv_sec = 5;
222: to.tv_usec = 0;
223: if ((client = clntudp_create(&addr, prognum, (u_long)0,
224: to, &sock)) == NULL) {
225: clnt_pcreateerror("rpcinfo");
226: printf("program %lu is not available\n",
227: prognum);
228: exit(1);
229: }
230: to.tv_sec = 10;
231: to.tv_usec = 0;
232: rpc_stat = clnt_call(client, NULLPROC, xdr_void, (char *)NULL,
233: xdr_void, (char *)NULL, to);
234: if (rpc_stat == RPC_PROGVERSMISMATCH) {
235: clnt_geterr(client, &rpcerr);
236: minvers = rpcerr.re_vers.low;
237: maxvers = rpcerr.re_vers.high;
238: } else if (rpc_stat == RPC_SUCCESS) {
239: /*
240: * Oh dear, it DOES support version 0.
241: * Let's try version MAX_VERS.
242: */
243: addr.sin_port = htons(portnum);
244: to.tv_sec = 5;
245: to.tv_usec = 0;
246: if ((client = clntudp_create(&addr, prognum, MAX_VERS,
247: to, &sock)) == NULL) {
248: clnt_pcreateerror("rpcinfo");
249: printf("program %lu version %lu is not available\n",
250: prognum, MAX_VERS);
251: exit(1);
252: }
253: to.tv_sec = 10;
254: to.tv_usec = 0;
255: rpc_stat = clnt_call(client, NULLPROC, xdr_void,
256: (char *)NULL, xdr_void, (char *)NULL, to);
257: if (rpc_stat == RPC_PROGVERSMISMATCH) {
258: clnt_geterr(client, &rpcerr);
259: minvers = rpcerr.re_vers.low;
260: maxvers = rpcerr.re_vers.high;
261: } else if (rpc_stat == RPC_SUCCESS) {
262: /*
263: * It also supports version MAX_VERS.
264: * Looks like we have a wise guy.
265: * OK, we give them information on all
266: * 4 billion versions they support...
267: */
268: minvers = 0;
269: maxvers = MAX_VERS;
270: } else {
271: (void) pstatus(client, prognum, MAX_VERS);
272: exit(1);
273: }
274: } else {
275: (void) pstatus(client, prognum, (u_long)0);
276: exit(1);
277: }
278: clnt_destroy(client);
279: for (vers = minvers; vers <= maxvers; vers++) {
280: addr.sin_port = htons(portnum);
281: to.tv_sec = 5;
282: to.tv_usec = 0;
283: if ((client = clntudp_create(&addr, prognum, vers,
284: to, &sock)) == NULL) {
285: clnt_pcreateerror("rpcinfo");
286: printf("program %lu version %lu is not available\n",
287: prognum, vers);
288: exit(1);
289: }
290: to.tv_sec = 10;
291: to.tv_usec = 0;
292: rpc_stat = clnt_call(client, NULLPROC, xdr_void,
293: (char *)NULL, xdr_void, (char *)NULL, to);
294: if (pstatus(client, prognum, vers) < 0)
295: failure = 1;
296: clnt_destroy(client);
297: }
298: }
299: else {
300: vers = getvers(argv[2]);
301: addr.sin_port = htons(portnum);
302: to.tv_sec = 5;
303: to.tv_usec = 0;
304: if ((client = clntudp_create(&addr, prognum, vers,
305: to, &sock)) == NULL) {
306: clnt_pcreateerror("rpcinfo");
307: printf("program %lu version %lu is not available\n",
308: prognum, vers);
309: exit(1);
310: }
311: to.tv_sec = 10;
312: to.tv_usec = 0;
313: rpc_stat = clnt_call(client, 0, xdr_void, (char *)NULL,
314: xdr_void, (char *)NULL, to);
315: if (pstatus(client, prognum, vers) < 0)
316: failure = 1;
317: }
318: (void) close(sock); /* Close it up again */
319: if (failure)
320: exit(1);
321: }
322:
323: static void
324: tcpping(portnum, argc, argv)
325: u_short portnum;
326: int argc;
327: char **argv;
328: {
329: struct timeval to;
330: struct sockaddr_in addr;
331: enum clnt_stat rpc_stat;
332: CLIENT *client;
333: u_long prognum, vers, minvers, maxvers;
334: int sock = RPC_ANYSOCK;
335: struct rpc_err rpcerr;
336: int failure;
337:
338: if (argc < 2 || argc > 3) {
339: usage();
340: exit(1);
341: }
342: prognum = getprognum(argv[1]);
343: get_inet_address(&addr, argv[0]);
344: failure = 0;
345: if (argc == 2) {
346: /*
347: * A call to version 0 should fail with a program/version
348: * mismatch, and give us the range of versions supported.
349: */
350: addr.sin_port = htons(portnum);
351: if ((client = clnttcp_create(&addr, prognum, MIN_VERS,
352: &sock, 0, 0)) == NULL) {
353: clnt_pcreateerror("rpcinfo");
354: printf("program %lu is not available\n",
355: prognum);
356: exit(1);
357: }
358: to.tv_sec = 10;
359: to.tv_usec = 0;
360: rpc_stat = clnt_call(client, NULLPROC, xdr_void, (char *)NULL,
361: xdr_void, (char *)NULL, to);
362: if (rpc_stat == RPC_PROGVERSMISMATCH) {
363: clnt_geterr(client, &rpcerr);
364: minvers = rpcerr.re_vers.low;
365: maxvers = rpcerr.re_vers.high;
366: } else if (rpc_stat == RPC_SUCCESS) {
367: /*
368: * Oh dear, it DOES support version 0.
369: * Let's try version MAX_VERS.
370: */
371: addr.sin_port = htons(portnum);
372: if ((client = clnttcp_create(&addr, prognum, MAX_VERS,
373: &sock, 0, 0)) == NULL) {
374: clnt_pcreateerror("rpcinfo");
375: printf("program %lu version %lu is not available\n",
376: prognum, MAX_VERS);
377: exit(1);
378: }
379: to.tv_sec = 10;
380: to.tv_usec = 0;
381: rpc_stat = clnt_call(client, NULLPROC, xdr_void,
382: (char *)NULL, xdr_void, (char *)NULL, to);
383: if (rpc_stat == RPC_PROGVERSMISMATCH) {
384: clnt_geterr(client, &rpcerr);
385: minvers = rpcerr.re_vers.low;
386: maxvers = rpcerr.re_vers.high;
387: } else if (rpc_stat == RPC_SUCCESS) {
388: /*
389: * It also supports version MAX_VERS.
390: * Looks like we have a wise guy.
391: * OK, we give them information on all
392: * 4 billion versions they support...
393: */
394: minvers = 0;
395: maxvers = MAX_VERS;
396: } else {
397: (void) pstatus(client, prognum, MAX_VERS);
398: exit(1);
399: }
400: } else {
401: (void) pstatus(client, prognum, MIN_VERS);
402: exit(1);
403: }
404: clnt_destroy(client);
405: (void) close(sock);
406: sock = RPC_ANYSOCK; /* Re-initialize it for later */
407: for (vers = minvers; vers <= maxvers; vers++) {
408: addr.sin_port = htons(portnum);
409: if ((client = clnttcp_create(&addr, prognum, vers,
410: &sock, 0, 0)) == NULL) {
411: clnt_pcreateerror("rpcinfo");
412: printf("program %lu version %lu is not available\n",
413: prognum, vers);
414: exit(1);
415: }
416: to.tv_usec = 0;
417: to.tv_sec = 10;
418: rpc_stat = clnt_call(client, 0, xdr_void, (char *)NULL,
419: xdr_void, (char *)NULL, to);
420: if (pstatus(client, prognum, vers) < 0)
421: failure = 1;
422: clnt_destroy(client);
423: (void) close(sock);
424: sock = RPC_ANYSOCK;
425: }
426: }
427: else {
428: vers = getvers(argv[2]);
429: addr.sin_port = htons(portnum);
430: if ((client = clnttcp_create(&addr, prognum, vers, &sock,
431: 0, 0)) == NULL) {
432: clnt_pcreateerror("rpcinfo");
433: printf("program %lu version %lu is not available\n",
434: prognum, vers);
435: exit(1);
436: }
437: to.tv_usec = 0;
438: to.tv_sec = 10;
439: rpc_stat = clnt_call(client, 0, xdr_void, (char *)NULL,
440: xdr_void, (char *)NULL, to);
441: if (pstatus(client, prognum, vers) < 0)
442: failure = 1;
443: }
444: if (failure)
445: exit(1);
446: }
447:
448: /*
449: * This routine should take a pointer to an "rpc_err" structure, rather than
450: * a pointer to a CLIENT structure, but "clnt_perror" takes a pointer to
451: * a CLIENT structure rather than a pointer to an "rpc_err" structure.
452: * As such, we have to keep the CLIENT structure around in order to print
453: * a good error message.
454: */
455: static int
456: pstatus(client, prognum, vers)
457: register CLIENT *client;
458: u_long prognum;
459: u_long vers;
460: {
461: struct rpc_err rpcerr;
462:
463: clnt_geterr(client, &rpcerr);
464: if (rpcerr.re_status != RPC_SUCCESS) {
465: clnt_perror(client, "rpcinfo");
466: printf("program %lu version %lu is not available\n",
467: prognum, vers);
468: return (-1);
469: } else {
470: printf("program %lu version %lu ready and waiting\n",
471: prognum, vers);
472: return (0);
473: }
474: }
475:
476: static void
477: pmapdump(argc, argv)
478: int argc;
479: char **argv;
480: {
481: struct sockaddr_in server_addr;
482: register struct hostent *hp;
483: struct pmaplist *head = NULL;
484: int socket = RPC_ANYSOCK;
485: struct timeval minutetimeout;
486: register CLIENT *client;
487: struct rpcent *rpc;
488:
489: if (argc > 1) {
490: usage();
491: exit(1);
492: }
493: if (argc == 1)
494: get_inet_address(&server_addr, argv[0]);
495: else {
496: bzero((char *)&server_addr, sizeof server_addr);
497: server_addr.sin_family = AF_INET;
498: if ((hp = gethostbyname("localhost")) != NULL)
499: bcopy(hp->h_addr, (caddr_t)&server_addr.sin_addr,
500: hp->h_length);
501: else
502: (void) inet_aton("0.0.0.0", &server_addr.sin_addr);
503: }
504: minutetimeout.tv_sec = 60;
505: minutetimeout.tv_usec = 0;
506: server_addr.sin_port = htons(PMAPPORT);
507: if ((client = clnttcp_create(&server_addr, PMAPPROG,
508: PMAPVERS, &socket, 50, 500)) == NULL) {
509: clnt_pcreateerror("rpcinfo: can't contact portmapper");
510: exit(1);
511: }
512: if (clnt_call(client, PMAPPROC_DUMP, xdr_void, NULL,
513: xdr_pmaplist, &head, minutetimeout) != RPC_SUCCESS) {
514: fprintf(stderr, "rpcinfo: can't contact portmapper: ");
515: clnt_perror(client, "rpcinfo");
516: exit(1);
517: }
518: if (head == NULL) {
519: printf("No remote programs registered.\n");
520: } else {
521: printf(" program vers proto port\n");
522: for (; head != NULL; head = head->pml_next) {
523: printf("%10ld%5ld",
524: head->pml_map.pm_prog,
525: head->pml_map.pm_vers);
526: if (head->pml_map.pm_prot == IPPROTO_UDP)
527: printf("%6s", "udp");
528: else if (head->pml_map.pm_prot == IPPROTO_TCP)
529: printf("%6s", "tcp");
530: else
531: printf("%6ld", head->pml_map.pm_prot);
532: printf("%7ld", head->pml_map.pm_port);
533: rpc = getrpcbynumber(head->pml_map.pm_prog);
534: if (rpc)
535: printf(" %s\n", rpc->r_name);
536: else
537: printf("\n");
538: }
539: }
540: }
541:
542: /*
543: * reply_proc collects replies from the broadcast.
544: * to get a unique list of responses the output of rpcinfo should
545: * be piped through sort(1) and then uniq(1).
546: */
547:
548: /*ARGSUSED*/
549: static bool_t
550: reply_proc(res, who)
551: void *res; /* Nothing comes back */
552: struct sockaddr_in *who; /* Who sent us the reply */
553: {
554: register struct hostent *hp;
555:
556: hp = gethostbyaddr((char *) &who->sin_addr, sizeof who->sin_addr,
557: AF_INET);
558: printf("%s %s\n", inet_ntoa(who->sin_addr),
559: (hp == NULL) ? "(unknown)" : hp->h_name);
560: return(FALSE);
561: }
562:
563: static void
564: brdcst(argc, argv)
565: int argc;
566: char **argv;
567: {
568: enum clnt_stat rpc_stat;
569: u_long prognum, vers;
570:
571: if (argc != 2) {
572: usage();
573: exit(1);
574: }
575: prognum = getprognum(argv[0]);
576: vers = getvers(argv[1]);
577: rpc_stat = clnt_broadcast(prognum, vers, NULLPROC, xdr_void,
578: (char *)NULL, xdr_void, (char *)NULL, reply_proc);
579: if ((rpc_stat != RPC_SUCCESS) && (rpc_stat != RPC_TIMEDOUT)) {
580: fprintf(stderr, "rpcinfo: broadcast failed: %s\n",
581: clnt_sperrno(rpc_stat));
582: exit(1);
583: }
584: exit(0);
585: }
586:
587: static void
588: deletereg(argc, argv)
589: int argc;
590: char **argv;
591: { u_long prog_num, version_num ;
592:
593: if (argc != 2) {
594: usage() ;
595: exit(1) ;
596: }
597: prog_num = getprognum(argv[0]);
598: version_num = getvers(argv[1]);
599: if ((pmap_unset(prog_num, version_num)) == 0) {
600: fprintf(stderr, "rpcinfo: Could not delete registration for prog %s version %s\n",
601: argv[0], argv[1]) ;
602: exit(1) ;
603: }
604: }
605:
606: static void
607: usage()
608: {
609: fprintf(stderr, "Usage: rpcinfo [ -n portnum ] -u host prognum [ versnum ]\n");
610: fprintf(stderr, " rpcinfo [ -n portnum ] -t host prognum [ versnum ]\n");
611: fprintf(stderr, " rpcinfo -p [ host ]\n");
612: fprintf(stderr, " rpcinfo -b prognum versnum\n");
613: fprintf(stderr, " rpcinfo -d prognum versnum\n") ;
614: }
615:
616: static u_long
617: getprognum(arg)
618: char *arg;
619: {
620: register struct rpcent *rpc;
621: register u_long prognum;
622:
623: if (isalpha(*arg)) {
624: rpc = getrpcbyname(arg);
625: if (rpc == NULL) {
626: fprintf(stderr, "rpcinfo: %s is unknown service\n",
627: arg);
628: exit(1);
629: }
630: prognum = rpc->r_number;
631: } else {
632: prognum = (u_long) atoi(arg);
633: }
634:
635: return (prognum);
636: }
637:
638: static u_long
639: getvers(arg)
640: char *arg;
641: {
642: register u_long vers;
643:
644: vers = (int) atoi(arg);
645: return (vers);
646: }
647:
648: static void
649: get_inet_address(addr, host)
650: struct sockaddr_in *addr;
651: char *host;
652: {
653: register struct hostent *hp;
654:
655: bzero((char *)addr, sizeof *addr);
656: if (inet_aton(host, &addr->sin_addr) == 0) {
657: if ((hp = gethostbyname(host)) == NULL) {
658: fprintf(stderr, "rpcinfo: %s is unknown host\n", host);
659: exit(1);
660: }
661: bcopy(hp->h_addr, (char *)&addr->sin_addr, hp->h_length);
662: }
663: addr->sin_family = AF_INET;
664: }