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