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