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