File key.c changed (mode: 100644) (index 6891c57..07ac839) |
17 |
17 |
*/ |
*/ |
18 |
18 |
void key_print(const struct key *k) |
void key_print(const struct key *k) |
19 |
19 |
{ |
{ |
20 |
|
printf("Key %03hhu name=[%s] itime=%u key=[%s] ts=%u ip=%s\n", |
|
|
20 |
|
printf("Key %03hhu name=[%s] itime=%ld key=[%s] ts=%ld ip=[%s]\n", |
21 |
21 |
k->id, k->name, k->itime, k->key, k->ts, k->ip); |
k->id, k->name, k->itime, k->key, k->ts, k->ip); |
22 |
22 |
} |
} |
23 |
23 |
|
|
|
... |
... |
int key_save(const unsigned int uid, const struct key *k) |
51 |
51 |
|
|
52 |
52 |
gettimeofday(&now, NULL); |
gettimeofday(&now, NULL); |
53 |
53 |
|
|
54 |
|
snprintf(buf, sizeof(buf), "%s\n%s\n%u\n%s\n%lu\n", |
|
55 |
|
k->name, k->key, k->ts, k->ip, now.tv_sec); |
|
|
54 |
|
snprintf(buf, sizeof(buf), "%s\n%s\n%ld\n%s\n%ld\n", |
|
55 |
|
k->name, k->key, k->ts, k->ip, k->itime); |
56 |
56 |
|
|
57 |
57 |
len = strlen(buf); |
len = strlen(buf); |
58 |
58 |
n = write(fd, buf, len); |
n = write(fd, buf, len); |
|
... |
... |
int key_load(struct key *k, const unsigned int uid, const unsigned char key_id) |
133 |
133 |
break; |
break; |
134 |
134 |
} |
} |
135 |
135 |
|
|
|
136 |
|
memset(k, 0, sizeof(struct key)); |
|
137 |
|
|
136 |
138 |
pos = 0; |
pos = 0; |
137 |
139 |
i = 0; |
i = 0; |
138 |
140 |
while ((pos < n) && (buf[pos] != '\n')) |
while ((pos < n) && (buf[pos] != '\n')) |
139 |
141 |
k->name[i++] = buf[pos++]; |
k->name[i++] = buf[pos++]; |
140 |
|
k->name[i] = '\0'; |
|
|
142 |
|
k->name[i] = '\0'; pos++; |
141 |
143 |
|
|
142 |
144 |
i = 0; |
i = 0; |
143 |
145 |
while ((pos < n) && (buf[pos] != '\n')) |
while ((pos < n) && (buf[pos] != '\n')) |
144 |
146 |
k->key[i++] = buf[pos++]; |
k->key[i++] = buf[pos++]; |
145 |
|
k->key[i] = '\0'; |
|
|
147 |
|
k->key[i] = '\0'; pos++; |
146 |
148 |
|
|
147 |
149 |
i = 0; |
i = 0; |
148 |
150 |
while ((pos < n) && (buf[pos] != '\n')) |
while ((pos < n) && (buf[pos] != '\n')) |
149 |
151 |
sts[i++] = buf[pos++]; |
sts[i++] = buf[pos++]; |
150 |
152 |
sts[i] = '\0'; |
sts[i] = '\0'; |
151 |
|
k->ts = strtoul(sts, NULL, 10); |
|
|
153 |
|
k->ts = strtol(sts, NULL, 10); pos++; |
152 |
154 |
|
|
153 |
155 |
i = 0; |
i = 0; |
154 |
156 |
while ((pos < n) && (buf[pos] != '\n')) |
while ((pos < n) && (buf[pos] != '\n')) |
155 |
157 |
k->ip[i++] = buf[pos++]; |
k->ip[i++] = buf[pos++]; |
156 |
|
k->ip[i] = '\0'; |
|
|
158 |
|
k->ip[i] = '\0'; pos++; |
157 |
159 |
|
|
158 |
160 |
i = 0; |
i = 0; |
159 |
161 |
while ((pos < n) && (buf[pos] != '\n')) |
while ((pos < n) && (buf[pos] != '\n')) |
160 |
162 |
sts[i++] = buf[pos++]; |
sts[i++] = buf[pos++]; |
161 |
163 |
sts[i] = '\0'; |
sts[i] = '\0'; |
162 |
|
k->itime = strtoul(sts, NULL, 10); |
|
|
164 |
|
k->itime = strtol(sts, NULL, 10); pos++; |
163 |
165 |
|
|
164 |
166 |
k->id = key_id; |
k->id = key_id; |
165 |
167 |
ret = 0; |
ret = 0; |
|
... |
... |
int key_load(struct key *k, const unsigned int uid, const unsigned char key_id) |
171 |
173 |
return ret; |
return ret; |
172 |
174 |
} |
} |
173 |
175 |
|
|
174 |
|
/* |
|
175 |
|
* Returns first free key slot be scanning the folder |
|
176 |
|
* Returns 0xFF if no slot is free |
|
177 |
|
*/ |
|
178 |
|
unsigned char key_next_free(const unsigned int uid) |
|
179 |
|
{ |
|
180 |
|
char path[256]; |
|
181 |
|
ssize_t n; |
|
182 |
|
unsigned char i; |
|
183 |
|
struct stat s; |
|
184 |
|
|
|
185 |
|
snprintf(path, sizeof(path), "%s/%u", KEY_DIR, uid); |
|
186 |
|
n = stat(path, &s); |
|
187 |
|
if (n != 0) |
|
188 |
|
return 0; |
|
189 |
|
|
|
190 |
|
for (i = 0; i < 0xFF; i++) { |
|
191 |
|
snprintf(path, sizeof(path), "%s/%u/%03hhu", KEY_DIR, uid, i); |
|
192 |
|
|
|
193 |
|
n = stat(path, &s); |
|
194 |
|
if (n != 0) |
|
195 |
|
return i; |
|
196 |
|
} |
|
197 |
|
|
|
198 |
|
return 0xFF; |
|
199 |
|
} |
|
200 |
|
|
|
201 |
176 |
/* |
/* |
202 |
177 |
* Removes a key |
* Removes a key |
203 |
178 |
*/ |
*/ |
204 |
179 |
int key_remove(const unsigned int uid, const unsigned char id) |
int key_remove(const unsigned int uid, const unsigned char id) |
205 |
180 |
{ |
{ |
206 |
181 |
char path[256]; |
char path[256]; |
207 |
|
int ret; |
|
208 |
182 |
|
|
209 |
183 |
snprintf(path, sizeof(path), "%s/%u/%03hhu", KEY_DIR, uid, id); |
snprintf(path, sizeof(path), "%s/%u/%03hhu", KEY_DIR, uid, id); |
210 |
184 |
return unlink(path); |
return unlink(path); |
File nf2fad.c changed (mode: 100644) (index d7a0921..c7b5814) |
5 |
5 |
*/ |
*/ |
6 |
6 |
|
|
7 |
7 |
// TODO: Cache codes already computed! |
// TODO: Cache codes already computed! |
8 |
|
// TODO: Test x codes below/beyond the correct timestamp |
|
9 |
8 |
// TODO: What ports to open? Based on user/group? |
// TODO: What ports to open? Based on user/group? |
10 |
9 |
// TODO: If the IP is validated, do not test anymore anything. |
// TODO: If the IP is validated, do not test anymore anything. |
11 |
10 |
// TODO: We need to specify the time after we request to re-authenticate. |
// TODO: We need to specify the time after we request to re-authenticate. |
|
11 |
|
// TODO: Log to syslog all operations. |
12 |
12 |
|
|
13 |
13 |
#define _GNU_SOURCE |
#define _GNU_SOURCE |
14 |
14 |
|
|
15 |
15 |
#define KEY_DIGITS 16 |
#define KEY_DIGITS 16 |
16 |
|
#define SOCKET_NAME "/run/nf2fa.sock" |
|
17 |
16 |
|
|
18 |
17 |
#include <errno.h> |
#include <errno.h> |
19 |
18 |
#include <stdio.h> |
#include <stdio.h> |
20 |
19 |
#include <stdlib.h> |
#include <stdlib.h> |
21 |
20 |
#include <unistd.h> |
#include <unistd.h> |
22 |
21 |
#include <string.h> |
#include <string.h> |
|
22 |
|
#include <dirent.h> |
23 |
23 |
#include <time.h> |
#include <time.h> |
24 |
24 |
#include <sys/time.h> |
#include <sys/time.h> |
25 |
25 |
#include <sys/types.h> |
#include <sys/types.h> |
|
... |
... |
struct my_ip |
58 |
58 |
static struct my_ip my_ips[MAX_IPS]; |
static struct my_ip my_ips[MAX_IPS]; |
59 |
59 |
|
|
60 |
60 |
/* Here we keep track of 2fa codes */ |
/* Here we keep track of 2fa codes */ |
61 |
|
struct my_list |
|
|
61 |
|
struct user |
62 |
62 |
{ |
{ |
63 |
|
char key[30]; |
|
64 |
|
unsigned int ts_last_used; |
|
65 |
|
struct my_list *next; |
|
|
63 |
|
unsigned int uid; |
|
64 |
|
struct key *head, *tail; |
|
65 |
|
struct user *next; |
66 |
66 |
}; |
}; |
67 |
|
static struct my_list *head, *tail; |
|
|
67 |
|
static struct user *users_head, *users_tail; |
68 |
68 |
|
|
69 |
69 |
static struct mnl_socket *nl; |
static struct mnl_socket *nl; |
70 |
70 |
|
|
|
... |
... |
static void send_verdict(const int queue_num, const uint32_t id, |
98 |
98 |
} |
} |
99 |
99 |
|
|
100 |
100 |
/* |
/* |
101 |
|
* Test if a 2fa code is ok |
|
|
101 |
|
* Try to find the code inside the packet |
102 |
102 |
* Returns 1 if ok |
* Returns 1 if ok |
103 |
103 |
*/ |
*/ |
104 |
104 |
static int test_2fa(const unsigned char *data, const unsigned int data_len, |
static int test_2fa(const unsigned char *data, const unsigned int data_len, |
105 |
|
unsigned int now30, struct my_list *q) |
|
|
105 |
|
const unsigned int now, const char *ip) |
106 |
106 |
{ |
{ |
107 |
|
unsigned int i, j; |
|
108 |
|
unsigned char code[3], c, computed = 0, found = 0; |
|
|
107 |
|
unsigned short i, j; |
|
108 |
|
unsigned int now30; |
|
109 |
|
unsigned char c; |
|
110 |
|
struct user *q; |
|
111 |
|
struct key *k; |
|
112 |
|
char pin[7]; |
|
113 |
|
int r; |
|
114 |
|
|
|
115 |
|
now30 = now / 30; |
109 |
116 |
|
|
110 |
|
// Try to find the code inside the packet |
|
111 |
117 |
for (i = 0; i < data_len - (3 - 1); i++) { |
for (i = 0; i < data_len - (3 - 1); i++) { |
112 |
118 |
for (j = 0; j < 3; j++) { |
for (j = 0; j < 3; j++) { |
113 |
119 |
c = data[i + j]; |
c = data[i + j]; |
|
... |
... |
static int test_2fa(const unsigned char *data, const unsigned int data_len, |
117 |
123 |
if (j != 3) // not found |
if (j != 3) // not found |
118 |
124 |
continue; |
continue; |
119 |
125 |
|
|
120 |
|
// Found, compute code if not present TODO |
|
121 |
|
if (!computed) { |
|
122 |
|
code[0] = 0x09; |
|
123 |
|
code[1] = 0x12; |
|
124 |
|
code[2] = 0x34; |
|
125 |
|
computed = 1; |
|
126 |
|
} |
|
|
126 |
|
snprintf(pin, sizeof(pin), "%02hhx%02hhx%02hhx", |
|
127 |
|
data[i], data[i + 1], data[i + 2]); |
|
128 |
|
printf("DEBUG: Packet pin: %s\n", pin); |
127 |
129 |
|
|
128 |
|
// Test |
|
129 |
|
if (memcmp(data + i, code, 3) != 0) |
|
130 |
|
continue; |
|
|
130 |
|
q = users_head; |
|
131 |
|
while (q) { |
|
132 |
|
k = q->head; |
|
133 |
|
while (k) { |
|
134 |
|
r = totp_verify(k->key, now30, k->ts / 30, pin); |
|
135 |
|
if (r == 1) { |
|
136 |
|
printf(" DEBUG: uid %u key %03hhu matched!\n", q->uid, k->id); |
|
137 |
|
k->ts = now; |
|
138 |
|
snprintf(k->ip, sizeof(k->ip), "%s", ip); |
|
139 |
|
key_save(q->uid, k); |
|
140 |
|
return 1; |
|
141 |
|
} |
|
142 |
|
|
|
143 |
|
k = k->next; |
|
144 |
|
} |
131 |
145 |
|
|
132 |
|
printf("\tFound code at offset %u\n", i); |
|
133 |
|
found = 1; |
|
134 |
|
break; |
|
|
146 |
|
q = q->next; |
|
147 |
|
} |
135 |
148 |
} |
} |
136 |
|
if (!found) |
|
137 |
|
return 0; |
|
138 |
149 |
|
|
139 |
|
return 1; |
|
|
150 |
|
return 0; |
140 |
151 |
} |
} |
141 |
152 |
|
|
142 |
153 |
/* |
/* |
|
... |
... |
static unsigned int process(const unsigned short eth, |
216 |
227 |
const unsigned char *data; |
const unsigned char *data; |
217 |
228 |
unsigned char src[16]; |
unsigned char src[16]; |
218 |
229 |
unsigned int data_len, src_len, verdict = NF_DROP; |
unsigned int data_len, src_len, verdict = NF_DROP; |
219 |
|
struct my_list *q; |
|
220 |
230 |
struct timeval now; |
struct timeval now; |
221 |
231 |
unsigned int pos = 0xFFFFFFFF; |
unsigned int pos = 0xFFFFFFFF; |
222 |
|
int r; |
|
|
232 |
|
int r, af; |
|
233 |
|
char ip[40]; |
223 |
234 |
|
|
224 |
235 |
switch (eth) { |
switch (eth) { |
225 |
236 |
case ETH_P_IP: |
case ETH_P_IP: |
|
... |
... |
static unsigned int process(const unsigned short eth, |
227 |
238 |
data = p + iph->ihl * 4; |
data = p + iph->ihl * 4; |
228 |
239 |
data_len = len - iph->ihl * 4; |
data_len = len - iph->ihl * 4; |
229 |
240 |
memcpy(src, p + 12, 4); src_len = 4; |
memcpy(src, p + 12, 4); src_len = 4; |
|
241 |
|
af = AF_INET; |
230 |
242 |
break; |
break; |
231 |
243 |
|
|
232 |
244 |
case ETH_P_IPV6: |
case ETH_P_IPV6: |
233 |
245 |
data = p + 40; |
data = p + 40; |
234 |
246 |
data_len = len - 40; |
data_len = len - 40; |
235 |
247 |
memcpy(src, p + 8, 16); src_len = 16; |
memcpy(src, p + 8, 16); src_len = 16; |
|
248 |
|
af = AF_INET6; |
236 |
249 |
break; |
break; |
237 |
250 |
|
|
238 |
251 |
default: return verdict; |
default: return verdict; |
|
... |
... |
static unsigned int process(const unsigned short eth, |
247 |
260 |
r = check_ip(src, src_len, &pos, &now); |
r = check_ip(src, src_len, &pos, &now); |
248 |
261 |
if (r == 1) { |
if (r == 1) { |
249 |
262 |
printf("\tGive access because already in list!\n"); |
printf("\tGive access because already in list!\n"); |
250 |
|
my_ips[pos].expire = now.tv_sec + 3600; |
|
|
263 |
|
my_ips[pos].expire = now.tv_sec + 3600; // TODO: configurable if we want to do it |
251 |
264 |
return NF_ACCEPT; |
return NF_ACCEPT; |
252 |
265 |
} |
} |
253 |
266 |
|
|
254 |
|
while (1) { |
|
255 |
|
unsigned int now30; |
|
256 |
|
|
|
257 |
|
now30 = now.tv_sec / 30; |
|
258 |
|
printf("now30=%u\n", now30); |
|
259 |
|
|
|
260 |
|
// TODO: fake data |
|
261 |
|
struct my_list fake; |
|
262 |
|
fake.next = NULL; |
|
263 |
|
head = &fake; |
|
264 |
|
|
|
265 |
|
q = head; |
|
266 |
|
while (q) { |
|
267 |
|
r = test_2fa(data, data_len, now30, q); |
|
268 |
|
if (r == 1) { |
|
269 |
|
add_ip(pos, src, src_len, &now); |
|
270 |
|
verdict = NF_ACCEPT; |
|
271 |
|
break; |
|
272 |
|
} |
|
273 |
|
q = q->next; |
|
274 |
|
} |
|
275 |
|
|
|
276 |
|
break; |
|
|
267 |
|
inet_ntop(af, src, ip, sizeof(ip)); |
|
268 |
|
printf("DBEUG: ip=%s\n", ip); |
|
269 |
|
r = test_2fa(data, data_len, now.tv_sec, ip); |
|
270 |
|
if (r == 1) { |
|
271 |
|
add_ip(pos, src, src_len, &now); |
|
272 |
|
verdict = NF_ACCEPT; |
277 |
273 |
} |
} |
278 |
274 |
|
|
279 |
|
printf(" verdict=%s\n", verdict == NF_ACCEPT ? "ACCEPT" : "DROP"); |
|
|
275 |
|
printf("\tverdict=%s\n", verdict == NF_ACCEPT ? "ACCEPT" : "DROP"); |
280 |
276 |
return verdict; |
return verdict; |
281 |
277 |
} |
} |
282 |
278 |
|
|
|
... |
... |
static int queue_cb(const struct nlmsghdr *nlh, void *data) |
319 |
315 |
return MNL_CB_OK; |
return MNL_CB_OK; |
320 |
316 |
} |
} |
321 |
317 |
|
|
|
318 |
|
/* |
|
319 |
|
* Add a key to a struct user, ordering them correctly |
|
320 |
|
*/ |
|
321 |
|
void key_add(struct user *u, struct key *k) |
|
322 |
|
{ |
|
323 |
|
struct key *q, *prev; |
|
324 |
|
|
|
325 |
|
prev = NULL; |
|
326 |
|
q = u->head; |
|
327 |
|
while (q) { |
|
328 |
|
printf("DEBUG: comparing q->id (%hhu) with k->id (%hhu)\n", |
|
329 |
|
q->id, k->id); |
|
330 |
|
if (q->id > k->id) |
|
331 |
|
break; |
|
332 |
|
|
|
333 |
|
prev = q; |
|
334 |
|
q = q->next; |
|
335 |
|
} |
|
336 |
|
|
|
337 |
|
if (prev == NULL) { |
|
338 |
|
k->next = u->head; |
|
339 |
|
u->head = k; |
|
340 |
|
} else { |
|
341 |
|
k->next = prev->next; |
|
342 |
|
prev->next = k; |
|
343 |
|
} |
|
344 |
|
} |
|
345 |
|
|
|
346 |
|
/* |
|
347 |
|
* Returns a struct user by uid |
|
348 |
|
*/ |
|
349 |
|
struct user *uid_to_user(const unsigned int uid) |
|
350 |
|
{ |
|
351 |
|
struct user *q; |
|
352 |
|
|
|
353 |
|
q = users_head; |
|
354 |
|
while (q) { |
|
355 |
|
if (q->uid == uid) |
|
356 |
|
return q; |
|
357 |
|
|
|
358 |
|
q = q->next; |
|
359 |
|
} |
|
360 |
|
|
|
361 |
|
return NULL; |
|
362 |
|
} |
|
363 |
|
|
|
364 |
|
/* |
|
365 |
|
* Returns the next free key slot. |
|
366 |
|
* Returns 0xFF if not available |
|
367 |
|
*/ |
|
368 |
|
unsigned char key_next_free(struct user *u) |
|
369 |
|
{ |
|
370 |
|
struct key *k; |
|
371 |
|
unsigned char min = 0; |
|
372 |
|
|
|
373 |
|
k = u->head; |
|
374 |
|
while (k) { |
|
375 |
|
if (k->id > min) |
|
376 |
|
return min; |
|
377 |
|
|
|
378 |
|
k = k->next; |
|
379 |
|
min++; |
|
380 |
|
} |
|
381 |
|
|
|
382 |
|
return min; |
|
383 |
|
} |
|
384 |
|
|
322 |
385 |
/* |
/* |
323 |
386 |
* Process a client command |
* Process a client command |
324 |
387 |
* Returns the number of bytes stored in @buf |
* Returns the number of bytes stored in @buf |
|
... |
... |
int process_client(const unsigned int uid, unsigned char *buf, |
334 |
397 |
cmd = buf[i++]; |
cmd = buf[i++]; |
335 |
398 |
|
|
336 |
399 |
if (cmd == NF2FA_CMD_ENROLL) { |
if (cmd == NF2FA_CMD_ENROLL) { |
337 |
|
struct key k; |
|
|
400 |
|
struct user *u; |
|
401 |
|
struct key k, *k2; |
338 |
402 |
unsigned char len8; |
unsigned char len8; |
|
403 |
|
struct timeval now; |
339 |
404 |
|
|
340 |
405 |
memset(&k, 0, sizeof(struct key)); |
memset(&k, 0, sizeof(struct key)); |
341 |
406 |
|
|
|
... |
... |
int process_client(const unsigned int uid, unsigned char *buf, |
348 |
413 |
|
|
349 |
414 |
i = 1; /* we now overwrite the buffer */ |
i = 1; /* we now overwrite the buffer */ |
350 |
415 |
|
|
351 |
|
k.id = key_next_free(uid); |
|
|
416 |
|
u = uid_to_user(uid); // TODO: use this anywhere |
|
417 |
|
if (!u) |
|
418 |
|
k.id = 0; |
|
419 |
|
else |
|
420 |
|
k.id = key_next_free(u); |
352 |
421 |
if (k.id == 0xFF) |
if (k.id == 0xFF) |
353 |
422 |
return i + protocol_enqueue_error(buf + i, |
return i + protocol_enqueue_error(buf + i, |
354 |
423 |
"no free slots; please try to free some"); |
"no free slots; please try to free some"); |
|
... |
... |
int process_client(const unsigned int uid, unsigned char *buf, |
358 |
427 |
return i + protocol_enqueue_error(buf + i, |
return i + protocol_enqueue_error(buf + i, |
359 |
428 |
"cannot generate key: too low entropy"); |
"cannot generate key: too low entropy"); |
360 |
429 |
|
|
|
430 |
|
gettimeofday(&now, NULL); |
|
431 |
|
k.itime = now.tv_sec; |
|
432 |
|
|
361 |
433 |
r = key_save(uid, &k); |
r = key_save(uid, &k); |
362 |
434 |
if (r != 0) |
if (r != 0) |
363 |
435 |
return i + protocol_enqueue_error(buf + i, |
return i + protocol_enqueue_error(buf + i, |
364 |
436 |
"cannot save key"); |
"cannot save key"); |
365 |
437 |
|
|
|
438 |
|
// Add the key to memory |
|
439 |
|
u = users_head; |
|
440 |
|
while (u) { |
|
441 |
|
if (u->uid == uid) |
|
442 |
|
break; |
|
443 |
|
u = u->next; |
|
444 |
|
} |
|
445 |
|
if (!u) { |
|
446 |
|
u = malloc(sizeof(struct user)); |
|
447 |
|
if (!u) |
|
448 |
|
return i + protocol_enqueue_error(buf + i, |
|
449 |
|
"cannot alloc memory"); |
|
450 |
|
memset(u, 0, sizeof(struct user)); |
|
451 |
|
u->uid = uid; |
|
452 |
|
users_head = u; |
|
453 |
|
} else { |
|
454 |
|
users_tail->next = u; |
|
455 |
|
} |
|
456 |
|
users_tail = u; |
|
457 |
|
|
|
458 |
|
k2 = malloc(sizeof(struct key)); |
|
459 |
|
if (!k2) |
|
460 |
|
return i + protocol_enqueue_error(buf + i, |
|
461 |
|
"cannot alloc memory"); |
|
462 |
|
memcpy(k2, &k, sizeof(struct key)); |
|
463 |
|
|
|
464 |
|
key_add(u, k2); |
|
465 |
|
|
366 |
466 |
buf[i++] = 0x00; /* marks the success */ |
buf[i++] = 0x00; /* marks the success */ |
367 |
467 |
buf[i++] = k.id; |
buf[i++] = k.id; |
368 |
468 |
i += protocol_enqueue_string(buf + i, k.key); |
i += protocol_enqueue_string(buf + i, k.key); |
|
... |
... |
int process_client(const unsigned int uid, unsigned char *buf, |
370 |
470 |
} |
} |
371 |
471 |
|
|
372 |
472 |
if (cmd == NF2FA_CMD_LIST) { |
if (cmd == NF2FA_CMD_LIST) { |
|
473 |
|
struct user *u; |
|
474 |
|
struct key *k; |
|
475 |
|
|
|
476 |
|
i = 1; /* we now overwrite the buffer */ |
|
477 |
|
|
|
478 |
|
buf[i++] = 0x00; /* OK */ |
|
479 |
|
|
|
480 |
|
u = users_head; |
|
481 |
|
while (u) { |
|
482 |
|
if (u->uid == uid) |
|
483 |
|
break; |
|
484 |
|
} |
|
485 |
|
if (!u) |
|
486 |
|
return i; |
|
487 |
|
|
|
488 |
|
k = u->head; |
|
489 |
|
while (k) { |
|
490 |
|
unsigned int x; |
|
491 |
|
|
|
492 |
|
buf[i++] = k->id; |
|
493 |
|
i += protocol_enqueue_string(buf + i, k->name); |
|
494 |
|
x = htonl(k->ts); |
|
495 |
|
memcpy(buf + i, &x, 4); i += 4; |
|
496 |
|
i += protocol_enqueue_string(buf + i, k->ip); |
|
497 |
|
|
|
498 |
|
k = k->next; |
|
499 |
|
} |
|
500 |
|
|
|
501 |
|
return i; |
373 |
502 |
} |
} |
374 |
503 |
|
|
375 |
504 |
if (cmd == NF2FA_CMD_UNENROLL) { |
if (cmd == NF2FA_CMD_UNENROLL) { |
|
505 |
|
struct user *u; |
|
506 |
|
struct key *k, *kprev; |
376 |
507 |
int r; |
int r; |
377 |
508 |
unsigned char id; |
unsigned char id; |
378 |
509 |
|
|
|
... |
... |
int process_client(const unsigned int uid, unsigned char *buf, |
385 |
516 |
return i + protocol_enqueue_error(buf + i, |
return i + protocol_enqueue_error(buf + i, |
386 |
517 |
"cannot remove key"); |
"cannot remove key"); |
387 |
518 |
|
|
|
519 |
|
// Remove it from memory |
|
520 |
|
u = users_head; |
|
521 |
|
while (u) { |
|
522 |
|
if (u->uid == uid) |
|
523 |
|
break; |
|
524 |
|
} |
|
525 |
|
if (u) { |
|
526 |
|
kprev = NULL; |
|
527 |
|
k = u->head; |
|
528 |
|
while (k) { |
|
529 |
|
if (k->id != id) { |
|
530 |
|
kprev = k; |
|
531 |
|
k = k->next; |
|
532 |
|
continue; |
|
533 |
|
} |
|
534 |
|
|
|
535 |
|
if (kprev) |
|
536 |
|
kprev->next = k->next; |
|
537 |
|
else |
|
538 |
|
u->head = k->next; |
|
539 |
|
free(k); |
|
540 |
|
break; |
|
541 |
|
} |
|
542 |
|
} |
|
543 |
|
|
388 |
544 |
buf[i++] = 0x00; /* marks the success */ |
buf[i++] = 0x00; /* marks the success */ |
389 |
545 |
return i; |
return i; |
390 |
546 |
} |
} |
|
... |
... |
int process_client(const unsigned int uid, unsigned char *buf, |
392 |
548 |
return i + protocol_enqueue_error(buf + i, "unknown command"); |
return i + protocol_enqueue_error(buf + i, "unknown command"); |
393 |
549 |
} |
} |
394 |
550 |
|
|
|
551 |
|
/* |
|
552 |
|
* Load the keys for a user |
|
553 |
|
*/ |
|
554 |
|
int load_keys_uid(struct user *u, const unsigned int uid) |
|
555 |
|
{ |
|
556 |
|
int err; |
|
557 |
|
|
|
558 |
|
err = -1; |
|
559 |
|
while (1) { |
|
560 |
|
DIR *d; |
|
561 |
|
char path[255]; |
|
562 |
|
|
|
563 |
|
snprintf(path, sizeof(path), "%s/%u", KEY_DIR, uid); |
|
564 |
|
d = opendir(path); |
|
565 |
|
if (!d) { |
|
566 |
|
printf("Cannot open dir %s: %s!\n", |
|
567 |
|
path, strerror(errno)); |
|
568 |
|
break; |
|
569 |
|
} |
|
570 |
|
|
|
571 |
|
errno = 0; |
|
572 |
|
while (1) { |
|
573 |
|
unsigned char key_id; |
|
574 |
|
struct key *k; |
|
575 |
|
struct dirent *de; |
|
576 |
|
int r; |
|
577 |
|
|
|
578 |
|
de = readdir(d); |
|
579 |
|
if (!de) { |
|
580 |
|
if (errno == 0) |
|
581 |
|
err = 0; |
|
582 |
|
break; |
|
583 |
|
} |
|
584 |
|
|
|
585 |
|
if (strlen(de->d_name) != 3) |
|
586 |
|
continue; |
|
587 |
|
|
|
588 |
|
//printf(" Loading key %s...\n", de->d_name); |
|
589 |
|
k = malloc(sizeof(struct key)); |
|
590 |
|
if (!k) { |
|
591 |
|
printf("Cannot alloc memory!\n"); |
|
592 |
|
break; |
|
593 |
|
} |
|
594 |
|
|
|
595 |
|
key_id = strtoul(de->d_name, NULL, 10); |
|
596 |
|
|
|
597 |
|
r = key_load(k, uid, key_id); |
|
598 |
|
if (r != 0) |
|
599 |
|
break; |
|
600 |
|
|
|
601 |
|
key_add(u, k); |
|
602 |
|
} |
|
603 |
|
|
|
604 |
|
closedir(d); |
|
605 |
|
break; |
|
606 |
|
} |
|
607 |
|
|
|
608 |
|
return err; |
|
609 |
|
} |
|
610 |
|
|
|
611 |
|
/* |
|
612 |
|
* Load all keys from KEY_DIR |
|
613 |
|
*/ |
|
614 |
|
int load_keys(void) |
|
615 |
|
{ |
|
616 |
|
DIR *d; |
|
617 |
|
int err, r; |
|
618 |
|
|
|
619 |
|
d = opendir(KEY_DIR); |
|
620 |
|
if (!d) { |
|
621 |
|
printf("Cannot open keys dir: %s!\n", strerror(errno)); |
|
622 |
|
return -1; |
|
623 |
|
} |
|
624 |
|
|
|
625 |
|
err = -1; |
|
626 |
|
errno = 0; |
|
627 |
|
while (1) { |
|
628 |
|
struct dirent *de; |
|
629 |
|
struct user *u; |
|
630 |
|
unsigned int uid; |
|
631 |
|
|
|
632 |
|
de = readdir(d); |
|
633 |
|
if (!de) { |
|
634 |
|
if (errno == 0) |
|
635 |
|
err = 0; |
|
636 |
|
break; |
|
637 |
|
} |
|
638 |
|
|
|
639 |
|
if (de->d_name[0] == '.') |
|
640 |
|
continue; |
|
641 |
|
|
|
642 |
|
//printf("Loading uid [%s]...\n", de->d_name); |
|
643 |
|
|
|
644 |
|
u = malloc(sizeof(struct user)); |
|
645 |
|
if (!u) { |
|
646 |
|
printf("Cannot alloc memory!\n"); |
|
647 |
|
break; |
|
648 |
|
} |
|
649 |
|
memset(u, 0, sizeof(struct user)); |
|
650 |
|
|
|
651 |
|
if (users_head == NULL) |
|
652 |
|
users_head = u; |
|
653 |
|
else |
|
654 |
|
users_tail->next = u; |
|
655 |
|
users_tail = u; |
|
656 |
|
|
|
657 |
|
uid = strtoul(de->d_name, NULL, 10); |
|
658 |
|
r = load_keys_uid(u, uid); |
|
659 |
|
if (r != 0) |
|
660 |
|
break; |
|
661 |
|
} |
|
662 |
|
closedir(d); |
|
663 |
|
|
|
664 |
|
return err; |
|
665 |
|
} |
|
666 |
|
|
395 |
667 |
int main(int argc, char *argv[]) |
int main(int argc, char *argv[]) |
396 |
668 |
{ |
{ |
397 |
669 |
unsigned char buf[MNL_SOCKET_BUFFER_SIZE]; |
unsigned char buf[MNL_SOCKET_BUFFER_SIZE]; |
|
... |
... |
int main(int argc, char *argv[]) |
403 |
675 |
struct sockaddr_un sa_un; |
struct sockaddr_un sa_un; |
404 |
676 |
socklen_t slen; |
socklen_t slen; |
405 |
677 |
|
|
|
678 |
|
ret = load_keys(); |
|
679 |
|
if (ret == -1) { |
|
680 |
|
printf("Cannot load keys!\n"); |
|
681 |
|
return 1; |
|
682 |
|
} |
|
683 |
|
|
406 |
684 |
if (argc < 2) |
if (argc < 2) |
407 |
685 |
queue_num = 0x4545; |
queue_num = 0x4545; |
408 |
686 |
else |
else |
409 |
|
queue_num = atoi(argv[1]); |
|
|
687 |
|
queue_num = strtoul(argv[1], NULL, 0); |
410 |
688 |
printf("queue_num: %u\n", queue_num); |
printf("queue_num: %u\n", queue_num); |
411 |
689 |
|
|
412 |
690 |
nl = mnl_socket_open(NETLINK_NETFILTER); |
nl = mnl_socket_open(NETLINK_NETFILTER); |
413 |
691 |
if (nl == NULL) { |
if (nl == NULL) { |
414 |
692 |
perror("mnl_socket_open"); |
perror("mnl_socket_open"); |
415 |
|
exit(EXIT_FAILURE); |
|
|
693 |
|
return 1; |
416 |
694 |
} |
} |
417 |
695 |
|
|
418 |
696 |
if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) { |
if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) { |
419 |
697 |
perror("mnl_socket_bind"); |
perror("mnl_socket_bind"); |
420 |
|
exit(EXIT_FAILURE); |
|
|
698 |
|
return 1; |
421 |
699 |
} |
} |
422 |
700 |
portid = mnl_socket_get_portid(nl); |
portid = mnl_socket_get_portid(nl); |
423 |
701 |
|
|
|
... |
... |
int main(int argc, char *argv[]) |
425 |
703 |
nfq_nlmsg_cfg_put_cmd(nlh, AF_INET, NFQNL_CFG_CMD_PF_UNBIND); |
nfq_nlmsg_cfg_put_cmd(nlh, AF_INET, NFQNL_CFG_CMD_PF_UNBIND); |
426 |
704 |
if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) { |
if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) { |
427 |
705 |
perror("mnl_socket_send"); |
perror("mnl_socket_send"); |
428 |
|
exit(EXIT_FAILURE); |
|
|
706 |
|
return 1; |
429 |
707 |
} |
} |
430 |
708 |
|
|
431 |
709 |
nlh = nfq_hdr_put(buf, NFQNL_MSG_CONFIG, 0); |
nlh = nfq_hdr_put(buf, NFQNL_MSG_CONFIG, 0); |
432 |
710 |
nfq_nlmsg_cfg_put_cmd(nlh, AF_INET, NFQNL_CFG_CMD_PF_BIND); |
nfq_nlmsg_cfg_put_cmd(nlh, AF_INET, NFQNL_CFG_CMD_PF_BIND); |
433 |
711 |
if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) { |
if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) { |
434 |
712 |
perror("mnl_socket_send"); |
perror("mnl_socket_send"); |
435 |
|
exit(EXIT_FAILURE); |
|
|
713 |
|
return 1; |
436 |
714 |
} |
} |
437 |
715 |
|
|
438 |
716 |
nlh = nfq_hdr_put(buf, NFQNL_MSG_CONFIG, queue_num); |
nlh = nfq_hdr_put(buf, NFQNL_MSG_CONFIG, queue_num); |
439 |
717 |
nfq_nlmsg_cfg_put_cmd(nlh, AF_INET, NFQNL_CFG_CMD_BIND); |
nfq_nlmsg_cfg_put_cmd(nlh, AF_INET, NFQNL_CFG_CMD_BIND); |
440 |
718 |
if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) { |
if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) { |
441 |
719 |
perror("mnl_socket_send"); |
perror("mnl_socket_send"); |
442 |
|
exit(EXIT_FAILURE); |
|
|
720 |
|
return 1; |
443 |
721 |
} |
} |
444 |
722 |
|
|
445 |
723 |
nlh = nfq_hdr_put(buf, NFQNL_MSG_CONFIG, queue_num); |
nlh = nfq_hdr_put(buf, NFQNL_MSG_CONFIG, queue_num); |
446 |
724 |
nfq_nlmsg_cfg_put_params(nlh, NFQNL_COPY_PACKET, 0xffff); |
nfq_nlmsg_cfg_put_params(nlh, NFQNL_COPY_PACKET, 0xffff); |
447 |
725 |
if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) { |
if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) { |
448 |
726 |
perror("mnl_socket_send"); |
perror("mnl_socket_send"); |
449 |
|
exit(EXIT_FAILURE); |
|
|
727 |
|
return 1; |
450 |
728 |
} |
} |
451 |
729 |
|
|
452 |
730 |
/* ENOBUFS is signalled to userspace when packets were lost |
/* ENOBUFS is signalled to userspace when packets were lost |
|
... |
... |
int main(int argc, char *argv[]) |
515 |
793 |
ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); |
ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); |
516 |
794 |
if (ret == -1) { |
if (ret == -1) { |
517 |
795 |
perror("mnl_socket_recvfrom"); |
perror("mnl_socket_recvfrom"); |
518 |
|
exit(EXIT_FAILURE); |
|
|
796 |
|
return 1; |
519 |
797 |
} |
} |
520 |
798 |
|
|
521 |
799 |
ret = mnl_cb_run(buf, ret, 0, portid, queue_cb, NULL); |
ret = mnl_cb_run(buf, ret, 0, portid, queue_cb, NULL); |
522 |
800 |
if (ret < 0){ |
if (ret < 0){ |
523 |
801 |
perror("mnl_cb_run"); |
perror("mnl_cb_run"); |
524 |
|
exit(EXIT_FAILURE); |
|
|
802 |
|
return 1; |
525 |
803 |
} |
} |
526 |
804 |
continue; |
continue; |
527 |
805 |
} |
} |
|
... |
... |
int main(int argc, char *argv[]) |
558 |
836 |
printf("Cannot receive: %s\n", strerror(errno)); |
printf("Cannot receive: %s\n", strerror(errno)); |
559 |
837 |
goto clean; |
goto clean; |
560 |
838 |
} |
} |
561 |
|
printf("Data on UNIX socket:\n"); |
|
562 |
|
dump(buf, n); |
|
|
839 |
|
printf("Data on UNIX socket:\n"); dump(buf, n); |
563 |
840 |
|
|
564 |
841 |
n = process_client(ucred.uid, buf, n); |
n = process_client(ucred.uid, buf, n); |
565 |
842 |
if (n == -1) |
if (n == -1) |
File totp.c changed (mode: 100644) (index 6a56546..9062a69) |
... |
... |
int totp_base32_decode(unsigned char *out, const unsigned char out_size, |
83 |
83 |
|
|
84 |
84 |
// Now we have more than 8 bits in buffer, extract |
// Now we have more than 8 bits in buffer, extract |
85 |
85 |
buf_bits -= 8; |
buf_bits -= 8; |
86 |
|
out[i++] = buf >> buf_bits; out++; |
|
|
86 |
|
out[i++] = buf >> buf_bits; |
87 |
87 |
buf &= ((1 << buf_bits) - 1); |
buf &= ((1 << buf_bits) - 1); |
88 |
88 |
|
|
89 |
89 |
if (i == out_size) |
if (i == out_size) |
|
... |
... |
int totp_compute(char *out, const char *key, unsigned int tc, |
129 |
129 |
unsigned int v; |
unsigned int v; |
130 |
130 |
unsigned long long z; |
unsigned long long z; |
131 |
131 |
|
|
|
132 |
|
printf("DEBUG: %s: key=%s tc=%u\n", __func__, key, tc); |
|
133 |
|
|
132 |
134 |
r = totp_base32_decode(key_bin, sizeof(key_bin), key); |
r = totp_base32_decode(key_bin, sizeof(key_bin), key); |
133 |
135 |
if (r == -1) |
if (r == -1) |
134 |
136 |
return -1; |
return -1; |
135 |
137 |
key_len = r; |
key_len = r; |
|
138 |
|
dump(key_bin, key_len); |
136 |
139 |
|
|
137 |
140 |
snprintf(stc, sizeof(stc), "%016x", tc); |
snprintf(stc, sizeof(stc), "%016x", tc); |
138 |
|
printf("DBEUG: stc: %s\n", stc); |
|
139 |
141 |
// Transform stc into a binary |
// Transform stc into a binary |
140 |
142 |
for (i = 0; i < 8; i++) |
for (i = 0; i < 8; i++) |
141 |
143 |
btc[i] = totp_hex2bin(stc + i * 2); |
btc[i] = totp_hex2bin(stc + i * 2); |
|
... |
... |
int totp_compute(char *out, const char *key, unsigned int tc, |
152 |
154 |
z *= 10; |
z *= 10; |
153 |
155 |
|
|
154 |
156 |
sprintf(format, "%%0%hhuu", digits); |
sprintf(format, "%%0%hhuu", digits); |
155 |
|
printf("DEBUG: format=%s\n", format); |
|
156 |
157 |
sprintf(out, format, v % z); |
sprintf(out, format, v % z); |
157 |
158 |
|
|
158 |
159 |
return 0; |
return 0; |
|
... |
... |
int totp_verify_tc(const char *key, const unsigned int tc, const char *pin) |
173 |
174 |
if (r == -1) |
if (r == -1) |
174 |
175 |
return -1; |
return -1; |
175 |
176 |
|
|
|
177 |
|
printf("DEBUG: tc=%u Comparing %s with %s\n", tc, cpin, pin); |
176 |
178 |
if (strcmp(cpin, pin) != 0) |
if (strcmp(cpin, pin) != 0) |
177 |
179 |
return 0; |
return 0; |
178 |
180 |
|
|
|
... |
... |
int totp_verify_tc(const char *key, const unsigned int tc, const char *pin) |
180 |
182 |
} |
} |
181 |
183 |
|
|
182 |
184 |
/* |
/* |
183 |
|
* Verifies a token based on @ts, trying 2 in the past and 2 in the future, |
|
|
185 |
|
* Verifies a token based on @tc, trying 2 in the past and 2 in the future, |
184 |
186 |
* to allow clock skew. |
* to allow clock skew. |
|
187 |
|
* @last_used - we should not allow to reuse the last token |
185 |
188 |
* Returns -1 on error, 0 if they do not match, else 1 |
* Returns -1 on error, 0 if they do not match, else 1 |
186 |
189 |
*/ |
*/ |
187 |
|
int totp_verify(const char *key, const unsigned int ts, const char *pin) |
|
|
190 |
|
int totp_verify(const char *key, const unsigned int tc, |
|
191 |
|
const unsigned int last_used, const char *pin) |
188 |
192 |
{ |
{ |
189 |
|
unsigned int values[5], tc; |
|
|
193 |
|
unsigned int values[5]; |
190 |
194 |
unsigned char i; |
unsigned char i; |
191 |
195 |
|
|
192 |
196 |
if (*pin == '\0') |
if (*pin == '\0') |
193 |
197 |
return -1; |
return -1; |
194 |
198 |
|
|
195 |
|
tc = ts / 30; |
|
196 |
199 |
values[0] = tc; |
values[0] = tc; |
197 |
200 |
values[1] = tc - 1; |
values[1] = tc - 1; |
198 |
201 |
values[2] = tc + 1; |
values[2] = tc + 1; |
|
... |
... |
int totp_verify(const char *key, const unsigned int ts, const char *pin) |
200 |
203 |
values[4] = tc + 2; |
values[4] = tc + 2; |
201 |
204 |
|
|
202 |
205 |
for (i = 0; i < 5; i++) { |
for (i = 0; i < 5; i++) { |
|
206 |
|
if (values[i] <= last_used) |
|
207 |
|
continue; |
|
208 |
|
|
203 |
209 |
if (totp_verify_tc(key, values[i], pin) == 1) |
if (totp_verify_tc(key, values[i], pin) == 1) |
204 |
210 |
return 1; |
return 1; |
205 |
211 |
} |
} |
|
... |
... |
static void encode(char *out, const char *in) |
222 |
228 |
continue; |
continue; |
223 |
229 |
} |
} |
224 |
230 |
|
|
|
231 |
|
#if 0 |
225 |
232 |
if (*in == ' ') { |
if (*in == ' ') { |
226 |
233 |
*out = '+'; |
*out = '+'; |
227 |
234 |
out++; in++; |
out++; in++; |
228 |
235 |
continue; |
continue; |
229 |
236 |
} |
} |
230 |
|
|
|
|
237 |
|
#endif |
231 |
238 |
|
|
232 |
239 |
snprintf(out, 4, "%%%02hhx", *in); |
snprintf(out, 4, "%%%02hhx", *in); |
233 |
240 |
out += 3; in++; |
out += 3; in++; |