allow the ead client to override the broadcast address
[openwrt.git] / package / ead / src / ead-client.c
1 /*
2  * Client for the Emergency Access Daemon
3  * Copyright (C) 2008 Felix Fietkau <nbd@openwrt.org>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2
7  * as published by the Free Software Foundation
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  */
14
15 #include <sys/types.h>
16 #include <sys/socket.h>
17 #include <sys/time.h>
18 #include <netinet/in.h>
19 #include <arpa/inet.h>
20 #include <stdio.h>
21 #include <stddef.h>
22 #include <stdint.h>
23 #include <stdlib.h>
24 #include <stdbool.h>
25 #include <string.h>
26 #include <fcntl.h>
27 #include <unistd.h>
28 #include <t_pwd.h>
29 #include <t_read.h>
30 #include <t_sha.h>
31 #include <t_defines.h>
32 #include <t_client.h>
33 #include "ead.h"
34 #include "ead-crypt.h"
35
36 #include "pw_encrypt_md5.c"
37
38 #define EAD_TIMEOUT     400
39 #define EAD_TIMEOUT_LONG 2000
40
41 static char msgbuf[1500];
42 static struct ead_msg *msg = (struct ead_msg *) msgbuf;
43 static uint16_t nid = 0xffff;
44 struct sockaddr_in local, remote;
45 static int s = 0;
46 static int sockflags;
47
48 static unsigned char *skey = NULL;
49 static unsigned char bbuf[MAXPARAMLEN];
50 static unsigned char saltbuf[MAXSALTLEN];
51 static char *username = NULL;
52 static char password[MAXPARAMLEN] = "";
53 static char pw_md5[MD5_OUT_BUFSIZE];
54 static char pw_salt[MAXSALTLEN];
55
56 static struct t_client *tc = NULL;
57 static struct t_num salt = { .data = saltbuf };
58 static struct t_num *A, B;
59 static struct t_preconf *tcp;
60 static int auth_type = EAD_AUTH_DEFAULT;
61 static int timeout = EAD_TIMEOUT;
62
63 static void
64 set_nonblock(int enable)
65 {
66         if (enable == !!(sockflags & O_NONBLOCK));
67                 return;
68
69         sockflags ^= O_NONBLOCK;
70         fcntl(s, F_SETFL, sockflags);
71 }
72
73 static int
74 send_packet(int type, bool (*handler)(void), unsigned int max)
75 {
76         struct timeval tv;
77         fd_set fds;
78         int nfds;
79         int len;
80         int res = 0;
81
82         type = htonl(type);
83         set_nonblock(0);
84         sendto(s, msgbuf, sizeof(struct ead_msg) + ntohl(msg->len), 0, (struct sockaddr *) &remote, sizeof(remote));
85         set_nonblock(1);
86
87         tv.tv_sec = timeout / 1000;
88         tv.tv_usec = (timeout % 1000) * 1000;
89
90         FD_ZERO(&fds);
91         do {
92                 FD_SET(s, &fds);
93                 nfds = select(s + 1, &fds, NULL, NULL, &tv);
94
95                 if (nfds <= 0)
96                         break;
97
98                 if (!FD_ISSET(s, &fds))
99                         break;
100
101                 len = read(s, msgbuf, sizeof(msgbuf));
102                 if (len < 0)
103                         break;
104
105                 if (len < sizeof(struct ead_msg))
106                         continue;
107
108                 if (len < sizeof(struct ead_msg) + ntohl(msg->len))
109                         continue;
110
111                 if (msg->magic != htonl(EAD_MAGIC))
112                         continue;
113
114                 if ((nid != 0xffff) && (ntohs(msg->nid) != nid))
115                         continue;
116
117                 if (msg->type != type)
118                         continue;
119
120                 if (handler())
121                         res++;
122
123                 if ((max > 0) && (res >= max))
124                         break;
125         } while (1);
126
127         return res;
128 }
129
130 static void
131 prepare_password(void)
132 {
133         switch(auth_type) {
134         case EAD_AUTH_DEFAULT:
135                 break;
136         case EAD_AUTH_MD5:
137                 md5_crypt(pw_md5, (unsigned char *) password, (unsigned char *) pw_salt);
138                 strncpy(password, pw_md5, sizeof(password));
139                 break;
140         }
141 }
142
143 static bool
144 handle_pong(void)
145 {
146         struct ead_msg_pong *pong = EAD_DATA(msg, pong);
147         int len = ntohl(msg->len) - sizeof(struct ead_msg_pong);
148
149         if (len <= 0)
150                 return false;
151
152         pong->name[len] = 0;
153         auth_type = ntohs(pong->auth_type);
154         if (nid == 0xffff)
155                 printf("%04x: %s\n", ntohs(msg->nid), pong->name);
156         return true;
157 }
158
159 static bool
160 handle_prime(void)
161 {
162         struct ead_msg_salt *sb = EAD_DATA(msg, salt);
163
164         salt.len = sb->len;
165         memcpy(salt.data, sb->salt, salt.len);
166
167         if (auth_type == EAD_AUTH_MD5) {
168                 memcpy(pw_salt, sb->ext_salt, MAXSALTLEN);
169                 pw_salt[MAXSALTLEN - 1] = 0;
170         }
171
172         tcp = t_getpreparam(sb->prime);
173         tc = t_clientopen(username, &tcp->modulus, &tcp->generator, &salt);
174         if (!tc) {
175                 fprintf(stderr, "Client open failed\n");
176                 return false;
177         }
178
179         return true;
180 }
181
182 static bool
183 handle_b(void)
184 {
185         struct ead_msg_number *num = EAD_DATA(msg, number);
186         int len = ntohl(msg->len) - sizeof(struct ead_msg_number);
187
188         B.data = bbuf;
189         B.len = len;
190         memcpy(bbuf, num->data, len);
191         return true;
192 }
193
194 static bool
195 handle_none(void)
196 {
197         return true;
198 }
199
200 static bool
201 handle_done_auth(void)
202 {
203         struct ead_msg_auth *auth = EAD_DATA(msg, auth);
204         if (t_clientverify(tc, auth->data) != 0) {
205                 fprintf(stderr, "Client auth verify failed\n");
206                 return false;
207         }
208         return true;
209 }
210
211 static bool
212 handle_cmd_data(void)
213 {
214         struct ead_msg_cmd_data *cmd = EAD_ENC_DATA(msg, cmd_data);
215         int datalen = ead_decrypt_message(msg) - sizeof(struct ead_msg_cmd_data);
216
217         if (datalen < 0)
218                 return false;
219
220         if (datalen > 0) {
221                 write(1, cmd->data, datalen);
222         }
223
224         return !!cmd->done;
225 }
226 static int
227 send_ping(void)
228 {
229         msg->type = htonl(EAD_TYPE_PING);
230         msg->len = 0;
231         return send_packet(EAD_TYPE_PONG, handle_pong, (nid == 0xffff ? 0 : 1));
232 }
233
234 static int
235 send_username(void)
236 {
237         msg->type = htonl(EAD_TYPE_SET_USERNAME);
238         msg->len = htonl(sizeof(struct ead_msg_user));
239         strcpy(EAD_DATA(msg, user)->username, username);
240         return send_packet(EAD_TYPE_ACK_USERNAME, handle_none, 1);
241 }
242
243 static int
244 get_prime(void)
245 {
246         msg->type = htonl(EAD_TYPE_GET_PRIME);
247         msg->len = 0;
248         return send_packet(EAD_TYPE_PRIME, handle_prime, 1);
249 }
250
251 static int
252 send_a(void)
253 {
254         struct ead_msg_number *num = EAD_DATA(msg, number);
255         A = t_clientgenexp(tc);
256         msg->type = htonl(EAD_TYPE_SEND_A);
257         msg->len = htonl(sizeof(struct ead_msg_number) + A->len);
258         memcpy(num->data, A->data, A->len);
259         return send_packet(EAD_TYPE_SEND_B, handle_b, 1);
260 }
261
262 static int
263 send_auth(void)
264 {
265         struct ead_msg_auth *auth = EAD_DATA(msg, auth);
266
267         prepare_password();
268         t_clientpasswd(tc, password);
269         skey = t_clientgetkey(tc, &B);
270         if (!skey)
271                 return 0;
272
273         ead_set_key(skey);
274         msg->type = htonl(EAD_TYPE_SEND_AUTH);
275         msg->len = htonl(sizeof(struct ead_msg_auth));
276         memcpy(auth->data, t_clientresponse(tc), sizeof(auth->data));
277         return send_packet(EAD_TYPE_DONE_AUTH, handle_done_auth, 1);
278 }
279
280 static int
281 send_command(const char *command)
282 {
283         struct ead_msg_cmd *cmd = EAD_ENC_DATA(msg, cmd);
284
285         msg->type = htonl(EAD_TYPE_SEND_CMD);
286         cmd->type = htons(EAD_CMD_NORMAL);
287         cmd->timeout = htons(10);
288         strncpy((char *)cmd->data, command, 1024);
289         ead_encrypt_message(msg, sizeof(struct ead_msg_cmd) + strlen(command) + 1);
290         return send_packet(EAD_TYPE_RESULT_CMD, handle_cmd_data, 1);
291 }
292
293
294 static int
295 usage(const char *prog)
296 {
297         fprintf(stderr, "Usage: %s [-b <addr>] <node> <username>[:<password>] <command>\n"
298                 "\n"
299                 "\t-b <addr>:  Set the broadcast address to <addr>\n"
300                 "\t<node>:     Node ID (4 digits hex)\n"
301                 "\t<username>: Username to authenticate with\n"
302                 "\n"
303                 "\tPassing no arguments shows a list of active nodes on the network\n"
304                 "\n", prog);
305         return -1;
306 }
307
308
309 int main(int argc, char **argv)
310 {
311         int val = 1;
312         char *st = NULL;
313         const char *command = NULL;
314         const char *prog = argv[0];
315         int ch;
316
317         msg->magic = htonl(EAD_MAGIC);
318         msg->tid = 0;
319
320         memset(&local, 0, sizeof(local));
321         memset(&remote, 0, sizeof(remote));
322
323         remote.sin_family = AF_INET;
324         remote.sin_addr.s_addr = 0xffffffff;
325         remote.sin_port = htons(EAD_PORT);
326
327         local.sin_family = AF_INET;
328         local.sin_addr.s_addr = INADDR_ANY;
329         local.sin_port = 0;
330
331         while ((ch = getopt(argc, argv, "b:")) != -1) {
332                 switch(ch) {
333                 case 'b':
334                         inet_aton(optarg, &remote.sin_addr);
335                         break;
336                 }
337         }
338         argv += optind;
339         argc -= optind;
340
341         switch(argc) {
342         case 3:
343                 command = argv[2];
344                 /* fall through */
345         case 2:
346                 username = argv[1];
347                 st = strchr(username, ':');
348                 if (st) {
349                         *st = 0;
350                         st++;
351                         strncpy(password, st, sizeof(password));
352                         password[sizeof(password) - 1] = 0;
353                         /* hide command line password */
354                         memset(st, 0, strlen(st));
355                 }
356                 /* fall through */
357         case 1:
358                 nid = strtoul(argv[0], &st, 16);
359                 if (st && st[0] != 0)
360                         return usage(prog);
361                 /* fall through */
362         case 0:
363                 break;
364         default:
365                 return usage(prog);
366         }
367
368         msg->nid = htons(nid);
369         s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
370         if (s < 0) {
371                 perror("socket");
372                 return -1;
373         }
374
375         setsockopt(s, SOL_SOCKET, SO_BROADCAST, &val, sizeof(val));
376
377         if (bind(s, (struct sockaddr *)&local, sizeof(local)) < 0) {
378                 perror("bind");
379                 return -1;
380         }
381         sockflags = fcntl(s, F_GETFL);
382
383         if (!send_ping()) {
384                 fprintf(stderr, "No devices found\n");
385                 return 1;
386         }
387
388         if (nid == 0xffff)
389                 return 0;
390
391         if (!username || !password[0])
392                 return 0;
393
394         if (!send_username()) {
395                 fprintf(stderr, "Device did not accept user name\n");
396                 return 1;
397         }
398         if (!get_prime()) {
399                 fprintf(stderr, "Failed to get user password info\n");
400                 return 1;
401         }
402
403         timeout = EAD_TIMEOUT_LONG;
404         if (!send_a()) {
405                 fprintf(stderr, "Failed to send local authentication data\n");
406                 return 1;
407         }
408         if (!send_auth()) {
409                 fprintf(stderr, "Authentication failed\n");
410                 return 1;
411         }
412         if (!command) {
413                 fprintf(stderr, "Authentication succesful\n");
414                 return 0;
415         }
416         if (!send_command(command)) {
417                 fprintf(stderr, "Command failed\n");
418                 return 1;
419         }
420
421         return 0;
422 }