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