Root/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
41static char msgbuf[1500];
42static struct ead_msg *msg = (struct ead_msg *) msgbuf;
43static uint16_t nid = 0xffff;
44struct sockaddr_in local, remote;
45static int s = 0;
46static int sockflags;
47static struct in_addr serverip = {
48    .s_addr = 0x01010101 /* dummy */
49};
50
51static unsigned char *skey = NULL;
52static unsigned char bbuf[MAXPARAMLEN];
53static unsigned char saltbuf[MAXSALTLEN];
54static char *username = NULL;
55static char password[MAXPARAMLEN] = "";
56static char pw_md5[MD5_OUT_BUFSIZE];
57static char pw_salt[MAXSALTLEN];
58
59static struct t_client *tc = NULL;
60static struct t_num salt = { .data = saltbuf };
61static struct t_num *A, B;
62static struct t_preconf *tcp;
63static int auth_type = EAD_AUTH_DEFAULT;
64static int timeout = EAD_TIMEOUT;
65static uint16_t sid = 0;
66
67static void
68set_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
77static int
78send_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
135static void
136prepare_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
148static bool
149handle_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
165static bool
166handle_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
188static bool
189handle_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
200static bool
201handle_none(void)
202{
203    return true;
204}
205
206static bool
207handle_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
217static bool
218handle_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}
232static int
233send_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
240static int
241send_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
249static int
250get_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
257static int
258send_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
268static int
269send_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
286static int
287send_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
300static int
301usage(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
316int 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}
434

Archive Download this file



interactive