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