added #ifdef for GETOPT_H, as per
[freeradius.git] / src / main / radclient.c
1 /*
2  * radclient    General radius packet debug tool.
3  *
4  * Version:     $Id$
5  *
6  */
7
8 #include        "autoconf.h"
9
10 #include        <sys/types.h>
11 #include        <stdio.h>
12 #include        <stdlib.h>
13 #include        <unistd.h>
14 #include        <string.h>
15 #include        <ctype.h>
16 #include        <netdb.h>
17 #include        <sys/socket.h>
18 #include        <sys/time.h>
19 #include        <netinet/in.h>
20
21 #if HAVE_SYS_SELECT_H
22 #  include      <sys/select.h>
23 #endif
24
25 #if HAVE_ERRNO_H
26 #  include      <errno.h>
27 #endif
28
29 #if HAVE_GETOPT_H
30 #  include      <getopt.h>
31 #endif
32
33 #include        "conf.h"
34 #include        "libradius.h"
35 #include        "radpaths.h"
36
37 /*
38  *      Read valuepairs from the fp up to End-Of-File.
39  */
40 VALUE_PAIR *readvp(FILE *fp)
41 {
42         char            buf[128];
43         int             eol;
44         char            *p;
45         VALUE_PAIR      *vp;
46         VALUE_PAIR      *list;
47         int             error = 0;
48
49         list = NULL;
50
51         while (!error && fgets(buf, sizeof(buf), fp) != NULL) {
52
53                 p = buf;
54                 do {
55                         if ((vp = pairread(&p, &eol)) == NULL) {
56                                 librad_perror("radclient:");
57                                 error = 1;
58                                 break;
59                         }
60                         pairadd(&list, vp);
61                 } while (!eol);
62         }
63         return error ? NULL: list;
64 }
65
66 void usage(void)
67 {
68         fprintf(stderr, "Usage: radclient [-d raddb ] [-f file] [-r retries] [-t timeout] [-nx]\n               server acct|auth <secret>\n");
69         exit(1);
70 }
71
72 int getport(char *name)
73 {
74         struct  servent         *svp;
75
76         svp = getservbyname (name, "udp");
77         if (!svp) {
78                 return 0;
79         }
80
81         return ntohs(svp->s_port);
82 }
83
84 int main(int argc, char **argv)
85 {
86         RADIUS_PACKET   *req;
87         RADIUS_PACKET   *rep = NULL;
88         struct timeval  tv;
89         char            *p;
90         char            *secret = "secret";
91         int             do_output = 1;
92         int             c;
93         int             port = 0;
94         int             retries = 10;
95         float           timeout = 3;
96         int             i;
97         char            *radius_dir = RADDBDIR;
98         char            *filename = NULL;
99         FILE            *fp;
100
101         while ((c = getopt(argc, argv, "d:f:nt:r:xv")) != EOF) switch(c) {
102                 case 'd':
103                         radius_dir = optarg;
104                         break;
105                 case 'f':
106                         filename = optarg;
107                         break;
108                 case 'n':
109                         do_output = 0;
110                         break;
111                 case 'x':
112                         librad_debug = 1;
113                         break;
114                 case 'r':
115                         if (!isdigit(*optarg)) usage();
116                         retries = atoi(optarg);
117                         break;
118                 case 't':
119                         if (!isdigit(*optarg)) usage();
120                         timeout = atof(optarg);
121                         break;
122                 case 'v':
123                         printf("radclient: $Id$ built on " __DATE__ "\n");
124                         exit(0);
125                         break;
126                 default:
127                         usage();
128                         break;
129         }
130         argc -= (optind - 1);
131         argv += (optind - 1);
132
133         if (argc < 4) {
134                 usage();
135         }
136
137         if (dict_init(radius_dir, RADIUS_DICTIONARY) < 0) {
138                 librad_perror("radclient");
139                 return 1;
140         }
141
142         if ((req = rad_alloc(1)) == NULL) {
143                 librad_perror("radclient");
144                 exit(1);
145         }
146
147 #define FAKE
148
149 #ifndef FAKE
150         req->id = getpid() & 0xFF;
151 #else
152         req->id = 0;
153         memset(req->vector, 0, sizeof(req->vector));
154 #endif
155
156         /*
157          *      Strip port from hostname if needed.
158          */
159         if ((p = strchr(argv[1], ':')) != NULL) {
160                 *p++ = 0;
161                 port = atoi(p);
162         }
163
164         /*
165          *      See what kind of request we want to send.
166          */
167         if (strcmp(argv[2], "auth") == 0) {
168                 if (port == 0) port = getport("radius");
169                 if (port == 0) port = PW_AUTH_UDP_PORT;
170                 req->code = PW_AUTHENTICATION_REQUEST;
171         } else if (strcmp(argv[2], "acct") == 0) {
172                 if (port == 0) port = getport("radacct");
173                 if (port == 0) port = PW_ACCT_UDP_PORT;
174                 req->code = PW_ACCOUNTING_REQUEST;
175         } else if (isdigit(argv[2][0])) {
176                 if (port == 0) port = PW_AUTH_UDP_PORT;
177                 port = atoi(argv[2]);
178         } else {
179                 usage();
180         }
181
182         /*
183          *      Resolve hostname.
184          */
185         req->dst_port = port;
186         req->dst_ipaddr = ip_getaddr(argv[1]);
187         if (req->dst_ipaddr == 0) {
188                 librad_perror("radclient: %s: ", argv[1]);
189                 exit(1);
190         }
191
192         /*
193          *      Add the secret.
194          */
195         if (argv[3]) secret = argv[3];
196
197         /*
198          *      Read valuepairs.
199          *      Maybe read them, from stdin, if there's no
200          *      filename, or if the filename is '-'.
201          */
202         if (filename && (strcmp(filename, "-") != 0)) {
203                 fp = fopen(filename, "r");
204                 if (!fp) {
205                         fprintf(stderr, "radclient: Error opening %s: %s\n",
206                                 filename, strerror(errno));
207                         exit(1);
208                 }
209         } else {
210                 fp = stdin;
211         }
212
213         if ((req->vps = readvp(fp)) == NULL) {
214                 exit(1);
215         }
216
217         /*
218          *      Send request.
219          */
220         if ((req->sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
221                 perror("radclient: socket: ");
222                 exit(1);
223         }
224
225         for (i = 0; i < retries; i++) {
226                 fd_set          rdfdesc;
227
228                 rad_send(req, secret);
229
230                 /* And wait for reply, timing out as necessary */
231                 FD_ZERO(&rdfdesc);
232                 FD_SET(req->sockfd, &rdfdesc);
233
234                 tv.tv_sec = (int)timeout;
235                 tv.tv_usec = 1000000 * (timeout - (int)timeout);
236
237                 /* Something's wrong if we don't get exactly one fd. */
238                 if (select(req->sockfd + 1, &rdfdesc, NULL, NULL, &tv) != 1) {
239                         continue;
240                 }
241
242                 rep = rad_recv(req->sockfd);
243                 if (rep != NULL) {
244                         break;
245                 } else {        /* NULL: couldn't receive the packet */
246                         librad_perror("radclient:");
247                         exit(1);
248                 }
249         }
250
251         /* No response or no data read (?) */
252         if (i == retries) {
253                 fprintf(stderr, "radclient: no response from server\n");
254                 exit(1);
255         }
256
257         if (rad_decode(rep, secret) != 0) {
258                 librad_perror("rad_decode");
259                 exit(1);
260         }
261
262         /* libradius debug already prints out the value pairs for us */
263         if (!librad_debug && do_output)
264                 vp_printlist(stdout, rep->vps);
265
266         return 0;
267 }
268