1 /*
2 *
3 * BlueZ - Bluetooth protocol stack for Linux
4 *
5 * Copyright (C) 2006-2010 Nokia Corporation
6 * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
7 *
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 *
23 */
24
25 #ifdef HAVE_CONFIG_H
26 #include <config.h>
27 #endif
28
29 #include <stdio.h>
30 #include <errno.h>
31 #include <ctype.h>
32 #include <fcntl.h>
33 #include <unistd.h>
34 #include <stdlib.h>
35 #include <time.h>
36 #include <sys/file.h>
37 #include <sys/stat.h>
38 #include <sys/param.h>
39 #include <sys/socket.h>
40
41 #include <glib.h>
42
43 #include <bluetooth/bluetooth.h>
44 #include <bluetooth/sdp.h>
45 #include <bluetooth/sdp_lib.h>
46
47 #include "textfile.h"
48 #include "glib-helper.h"
49 #include "storage.h"
50
create_filename(char * buf,size_t size,const bdaddr_t * bdaddr,const char * name)51 static inline int create_filename(char *buf, size_t size,
52 const bdaddr_t *bdaddr, const char *name)
53 {
54 char addr[18];
55
56 ba2str(bdaddr, addr);
57
58 return create_name(buf, size, STORAGEDIR, addr, name);
59 }
60
read_device_alias(const char * src,const char * dst,char * alias,size_t size)61 int read_device_alias(const char *src, const char *dst, char *alias, size_t size)
62 {
63 char filename[PATH_MAX + 1], *tmp;
64 int err;
65
66 create_name(filename, PATH_MAX, STORAGEDIR, src, "aliases");
67
68 tmp = textfile_get(filename, dst);
69 if (!tmp)
70 return -ENXIO;
71
72 err = snprintf(alias, size, "%s", tmp);
73
74 free(tmp);
75
76 return err < 0 ? -EIO : 0;
77 }
78
write_device_alias(const char * src,const char * dst,const char * alias)79 int write_device_alias(const char *src, const char *dst, const char *alias)
80 {
81 char filename[PATH_MAX + 1];
82
83 create_name(filename, PATH_MAX, STORAGEDIR, src, "aliases");
84
85 create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
86
87 return textfile_put(filename, dst, alias);
88 }
89
write_discoverable_timeout(bdaddr_t * bdaddr,int timeout)90 int write_discoverable_timeout(bdaddr_t *bdaddr, int timeout)
91 {
92 char filename[PATH_MAX + 1], str[32];
93
94 snprintf(str, sizeof(str), "%d", timeout);
95
96 create_filename(filename, PATH_MAX, bdaddr, "config");
97
98 create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
99
100 return textfile_put(filename, "discovto", str);
101 }
102
read_discoverable_timeout(const char * src,int * timeout)103 int read_discoverable_timeout(const char *src, int *timeout)
104 {
105 char filename[PATH_MAX + 1], *str;
106
107 create_name(filename, PATH_MAX, STORAGEDIR, src, "config");
108
109 str = textfile_get(filename, "discovto");
110 if (!str)
111 return -ENOENT;
112
113 if (sscanf(str, "%d", timeout) != 1) {
114 free(str);
115 return -ENOENT;
116 }
117
118 free(str);
119
120 return 0;
121 }
122
write_pairable_timeout(bdaddr_t * bdaddr,int timeout)123 int write_pairable_timeout(bdaddr_t *bdaddr, int timeout)
124 {
125 char filename[PATH_MAX + 1], str[32];
126
127 snprintf(str, sizeof(str), "%d", timeout);
128
129 create_filename(filename, PATH_MAX, bdaddr, "config");
130
131 create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
132
133 return textfile_put(filename, "pairto", str);
134 }
135
read_pairable_timeout(const char * src,int * timeout)136 int read_pairable_timeout(const char *src, int *timeout)
137 {
138 char filename[PATH_MAX + 1], *str;
139
140 create_name(filename, PATH_MAX, STORAGEDIR, src, "config");
141
142 str = textfile_get(filename, "pairto");
143 if (!str)
144 return -ENOENT;
145
146 if (sscanf(str, "%d", timeout) != 1) {
147 free(str);
148 return -ENOENT;
149 }
150
151 free(str);
152
153 return 0;
154 }
155
write_device_mode(bdaddr_t * bdaddr,const char * mode)156 int write_device_mode(bdaddr_t *bdaddr, const char *mode)
157 {
158 char filename[PATH_MAX + 1];
159
160 create_filename(filename, PATH_MAX, bdaddr, "config");
161
162 create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
163
164 if (strcmp(mode, "off") != 0)
165 textfile_put(filename, "onmode", mode);
166
167 return textfile_put(filename, "mode", mode);
168 }
169
read_device_mode(const char * src,char * mode,int length)170 int read_device_mode(const char *src, char *mode, int length)
171 {
172 char filename[PATH_MAX + 1], *str;
173
174 create_name(filename, PATH_MAX, STORAGEDIR, src, "config");
175
176 str = textfile_get(filename, "mode");
177 if (!str)
178 return -ENOENT;
179
180 strncpy(mode, str, length);
181 mode[length - 1] = '\0';
182
183 free(str);
184
185 return 0;
186 }
187
read_on_mode(const char * src,char * mode,int length)188 int read_on_mode(const char *src, char *mode, int length)
189 {
190 char filename[PATH_MAX + 1], *str;
191
192 create_name(filename, PATH_MAX, STORAGEDIR, src, "config");
193
194 str = textfile_get(filename, "onmode");
195 if (!str)
196 return -ENOENT;
197
198 strncpy(mode, str, length);
199 mode[length - 1] = '\0';
200
201 free(str);
202
203 return 0;
204 }
205
write_local_name(bdaddr_t * bdaddr,const char * name)206 int write_local_name(bdaddr_t *bdaddr, const char *name)
207 {
208 char filename[PATH_MAX + 1], str[249];
209 int i;
210
211 memset(str, 0, sizeof(str));
212 for (i = 0; i < 248 && name[i]; i++)
213 if ((unsigned char) name[i] < 32 || name[i] == 127)
214 str[i] = '.';
215 else
216 str[i] = name[i];
217
218 create_filename(filename, PATH_MAX, bdaddr, "config");
219
220 create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
221
222 return textfile_put(filename, "name", str);
223 }
224
read_local_name(bdaddr_t * bdaddr,char * name)225 int read_local_name(bdaddr_t *bdaddr, char *name)
226 {
227 char filename[PATH_MAX + 1], *str;
228 int len;
229
230 create_filename(filename, PATH_MAX, bdaddr, "config");
231
232 str = textfile_get(filename, "name");
233 if (!str)
234 return -ENOENT;
235
236 len = strlen(str);
237 if (len > 248)
238 str[248] = '\0';
239 strcpy(name, str);
240
241 free(str);
242
243 return 0;
244 }
245
write_local_class(bdaddr_t * bdaddr,uint8_t * class)246 int write_local_class(bdaddr_t *bdaddr, uint8_t *class)
247 {
248 char filename[PATH_MAX + 1], str[9];
249
250 sprintf(str, "0x%2.2x%2.2x%2.2x", class[2], class[1], class[0]);
251
252 create_filename(filename, PATH_MAX, bdaddr, "config");
253
254 create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
255
256 return textfile_put(filename, "class", str);
257 }
258
read_local_class(bdaddr_t * bdaddr,uint8_t * class)259 int read_local_class(bdaddr_t *bdaddr, uint8_t *class)
260 {
261 char filename[PATH_MAX + 1], tmp[3], *str;
262 int i;
263
264 create_filename(filename, PATH_MAX, bdaddr, "config");
265
266 str = textfile_get(filename, "class");
267 if (!str)
268 return -ENOENT;
269
270 memset(tmp, 0, sizeof(tmp));
271 for (i = 0; i < 3; i++) {
272 memcpy(tmp, str + (i * 2) + 2, 2);
273 class[2 - i] = (uint8_t) strtol(tmp, NULL, 16);
274 }
275
276 free(str);
277
278 return 0;
279 }
280
write_remote_class(bdaddr_t * local,bdaddr_t * peer,uint32_t class)281 int write_remote_class(bdaddr_t *local, bdaddr_t *peer, uint32_t class)
282 {
283 char filename[PATH_MAX + 1], addr[18], str[9];
284
285 create_filename(filename, PATH_MAX, local, "classes");
286
287 create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
288
289 ba2str(peer, addr);
290 sprintf(str, "0x%6.6x", class);
291
292 return textfile_put(filename, addr, str);
293 }
294
read_remote_class(bdaddr_t * local,bdaddr_t * peer,uint32_t * class)295 int read_remote_class(bdaddr_t *local, bdaddr_t *peer, uint32_t *class)
296 {
297 char filename[PATH_MAX + 1], addr[18], *str;
298
299 create_filename(filename, PATH_MAX, local, "classes");
300
301 ba2str(peer, addr);
302
303 str = textfile_get(filename, addr);
304 if (!str)
305 return -ENOENT;
306
307 if (sscanf(str, "%x", class) != 1) {
308 free(str);
309 return -ENOENT;
310 }
311
312 free(str);
313
314 return 0;
315 }
316
write_device_name(bdaddr_t * local,bdaddr_t * peer,char * name)317 int write_device_name(bdaddr_t *local, bdaddr_t *peer, char *name)
318 {
319 char filename[PATH_MAX + 1], addr[18], str[249];
320 int i;
321
322 memset(str, 0, sizeof(str));
323 for (i = 0; i < 248 && name[i]; i++)
324 if ((unsigned char) name[i] < 32 || name[i] == 127)
325 str[i] = '.';
326 else
327 str[i] = name[i];
328
329 create_filename(filename, PATH_MAX, local, "names");
330
331 create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
332
333 ba2str(peer, addr);
334 return textfile_put(filename, addr, str);
335 }
336
read_device_name(const char * src,const char * dst,char * name)337 int read_device_name(const char *src, const char *dst, char *name)
338 {
339 char filename[PATH_MAX + 1], *str;
340 int len;
341
342 create_name(filename, PATH_MAX, STORAGEDIR, src, "names");
343
344 str = textfile_get(filename, dst);
345 if (!str)
346 return -ENOENT;
347
348 len = strlen(str);
349 if (len > 248)
350 str[248] = '\0';
351 strcpy(name, str);
352
353 free(str);
354
355 return 0;
356 }
357
write_remote_eir(bdaddr_t * local,bdaddr_t * peer,uint8_t * data)358 int write_remote_eir(bdaddr_t *local, bdaddr_t *peer, uint8_t *data)
359 {
360 char filename[PATH_MAX + 1], addr[18], str[481];
361 int i;
362
363 memset(str, 0, sizeof(str));
364 for (i = 0; i < 240; i++)
365 sprintf(str + (i * 2), "%2.2X", data[i]);
366
367 create_filename(filename, PATH_MAX, local, "eir");
368
369 create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
370
371 ba2str(peer, addr);
372 return textfile_put(filename, addr, str);
373 }
374
read_remote_eir(bdaddr_t * local,bdaddr_t * peer,uint8_t * data)375 int read_remote_eir(bdaddr_t *local, bdaddr_t *peer, uint8_t *data)
376 {
377 char filename[PATH_MAX + 1], addr[18], *str;
378 int i;
379
380 create_filename(filename, PATH_MAX, local, "eir");
381
382 ba2str(peer, addr);
383
384 str = textfile_get(filename, addr);
385 if (!str)
386 return -ENOENT;
387
388 if (!data) {
389 free(str);
390 return 0;
391 }
392
393 if (strlen(str) < 480) {
394 free(str);
395 return -EIO;
396 }
397
398 for (i = 0; i < 240; i++)
399 sscanf(str + (i * 2), "%02hhX", &data[i]);
400
401 free(str);
402
403 return 0;
404 }
405
write_l2cap_info(bdaddr_t * local,bdaddr_t * peer,uint16_t mtu_result,uint16_t mtu,uint16_t mask_result,uint32_t mask)406 int write_l2cap_info(bdaddr_t *local, bdaddr_t *peer,
407 uint16_t mtu_result, uint16_t mtu,
408 uint16_t mask_result, uint32_t mask)
409 {
410 char filename[PATH_MAX + 1], addr[18], str[18];
411
412 if (mask_result)
413 snprintf(str, sizeof(str), "%d -1", mtu_result ? -1 : mtu);
414 else
415 snprintf(str, sizeof(str), "%d 0x%08x", mtu_result ? -1 : mtu, mask);
416
417 create_filename(filename, PATH_MAX, local, "l2cap");
418
419 create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
420
421 ba2str(peer, addr);
422 return textfile_put(filename, addr, str);
423 }
424
read_l2cap_info(bdaddr_t * local,bdaddr_t * peer,uint16_t * mtu_result,uint16_t * mtu,uint16_t * mask_result,uint32_t * mask)425 int read_l2cap_info(bdaddr_t *local, bdaddr_t *peer,
426 uint16_t *mtu_result, uint16_t *mtu,
427 uint16_t *mask_result, uint32_t *mask)
428 {
429 char filename[PATH_MAX + 1], addr[18], *str, *space, *msk;
430
431 create_filename(filename, PATH_MAX, local, "l2cap");
432
433 ba2str(peer, addr);
434 str = textfile_get(filename, addr);
435 if (!str)
436 return -ENOENT;
437
438 space = strchr(str, ' ');
439 if (!space) {
440 free(str);
441 return -ENOENT;
442 }
443
444 msk = space + 1;
445 *space = '\0';
446
447 if (mtu_result && mtu) {
448 if (str[0] == '-')
449 *mtu_result = 0x0001;
450 else {
451 *mtu_result = 0;
452 *mtu = (uint16_t) strtol(str, NULL, 0);
453 }
454 }
455
456 if (mask_result && mask) {
457 if (msk[0] == '-')
458 *mask_result = 0x0001;
459 else {
460 *mask_result = 0;
461 *mask = (uint32_t) strtol(msk, NULL, 16);
462 }
463 }
464
465 free(str);
466
467 return 0;
468 }
469
write_version_info(bdaddr_t * local,bdaddr_t * peer,uint16_t manufacturer,uint8_t lmp_ver,uint16_t lmp_subver)470 int write_version_info(bdaddr_t *local, bdaddr_t *peer, uint16_t manufacturer,
471 uint8_t lmp_ver, uint16_t lmp_subver)
472 {
473 char filename[PATH_MAX + 1], addr[18], str[16];
474
475 memset(str, 0, sizeof(str));
476 sprintf(str, "%d %d %d", manufacturer, lmp_ver, lmp_subver);
477
478 create_filename(filename, PATH_MAX, local, "manufacturers");
479
480 create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
481
482 ba2str(peer, addr);
483 return textfile_put(filename, addr, str);
484 }
485
write_features_info(bdaddr_t * local,bdaddr_t * peer,unsigned char * page1,unsigned char * page2)486 int write_features_info(bdaddr_t *local, bdaddr_t *peer,
487 unsigned char *page1, unsigned char *page2)
488 {
489 char filename[PATH_MAX + 1], addr[18];
490 char str[] = "0000000000000000 0000000000000000";
491 char *old_value;
492 int i;
493
494 ba2str(peer, addr);
495
496 create_filename(filename, PATH_MAX, local, "features");
497 create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
498
499 old_value = textfile_get(filename, addr);
500
501 if (page1)
502 for (i = 0; i < 8; i++)
503 sprintf(str + (i * 2), "%2.2X", page1[i]);
504 else if (old_value && strlen(old_value) >= 16)
505 strncpy(str, old_value, 16);
506
507 if (page2)
508 for (i = 0; i < 8; i++)
509 sprintf(str + 17 + (i * 2), "%2.2X", page2[i]);
510 else if (old_value && strlen(old_value) >= 33)
511 strncpy(str + 17, old_value + 17, 16);
512
513 free(old_value);
514
515 return textfile_put(filename, addr, str);
516 }
517
decode_bytes(const char * str,unsigned char * bytes,size_t len)518 static int decode_bytes(const char *str, unsigned char *bytes, size_t len)
519 {
520 unsigned int i;
521
522 for (i = 0; i < len; i++) {
523 if (sscanf(str + (i * 2), "%02hhX", &bytes[i]) != 1)
524 return -EINVAL;
525 }
526
527 return 0;
528 }
529
read_remote_features(bdaddr_t * local,bdaddr_t * peer,unsigned char * page1,unsigned char * page2)530 int read_remote_features(bdaddr_t *local, bdaddr_t *peer,
531 unsigned char *page1, unsigned char *page2)
532 {
533 char filename[PATH_MAX + 1], addr[18], *str;
534 size_t len;
535 int err;
536
537 if (page1 == NULL && page2 == NULL)
538 return -EINVAL;
539
540 create_filename(filename, PATH_MAX, local, "features");
541
542 ba2str(peer, addr);
543
544 str = textfile_get(filename, addr);
545 if (!str)
546 return -ENOENT;
547
548 len = strlen(str);
549
550 err = -ENOENT;
551
552 if (page1 && len >= 16)
553 err = decode_bytes(str, page1, 8);
554
555 if (page2 && len >= 33)
556 err = decode_bytes(str + 17, page2, 8);
557
558 free(str);
559
560 return err;
561 }
562
write_lastseen_info(bdaddr_t * local,bdaddr_t * peer,struct tm * tm)563 int write_lastseen_info(bdaddr_t *local, bdaddr_t *peer, struct tm *tm)
564 {
565 char filename[PATH_MAX + 1], addr[18], str[24];
566
567 memset(str, 0, sizeof(str));
568 strftime(str, sizeof(str), "%Y-%m-%d %H:%M:%S %Z", tm);
569
570 create_filename(filename, PATH_MAX, local, "lastseen");
571
572 create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
573
574 ba2str(peer, addr);
575 return textfile_put(filename, addr, str);
576 }
577
write_lastused_info(bdaddr_t * local,bdaddr_t * peer,struct tm * tm)578 int write_lastused_info(bdaddr_t *local, bdaddr_t *peer, struct tm *tm)
579 {
580 char filename[PATH_MAX + 1], addr[18], str[24];
581
582 memset(str, 0, sizeof(str));
583 strftime(str, sizeof(str), "%Y-%m-%d %H:%M:%S %Z", tm);
584
585 create_filename(filename, PATH_MAX, local, "lastused");
586
587 create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
588
589 ba2str(peer, addr);
590 return textfile_put(filename, addr, str);
591 }
592
write_link_key(bdaddr_t * local,bdaddr_t * peer,unsigned char * key,uint8_t type,int length)593 int write_link_key(bdaddr_t *local, bdaddr_t *peer, unsigned char *key, uint8_t type, int length)
594 {
595 char filename[PATH_MAX + 1], addr[18], str[38];
596 int i;
597
598 memset(str, 0, sizeof(str));
599 for (i = 0; i < 16; i++)
600 sprintf(str + (i * 2), "%2.2X", key[i]);
601 sprintf(str + 32, " %d %d", type, length);
602
603 create_filename(filename, PATH_MAX, local, "linkkeys");
604
605 create_file(filename, S_IRUSR | S_IWUSR);
606
607 ba2str(peer, addr);
608
609 if (length < 0) {
610 char *tmp = textfile_get(filename, addr);
611 if (tmp) {
612 if (strlen(tmp) > 34)
613 memcpy(str + 34, tmp + 34, 3);
614 free(tmp);
615 }
616 }
617
618 return textfile_put(filename, addr, str);
619 }
620
read_link_key(bdaddr_t * local,bdaddr_t * peer,unsigned char * key,uint8_t * type)621 int read_link_key(bdaddr_t *local, bdaddr_t *peer, unsigned char *key, uint8_t *type)
622 {
623 char filename[PATH_MAX + 1], addr[18], tmp[3], *str;
624 int i;
625
626 create_filename(filename, PATH_MAX, local, "linkkeys");
627
628 ba2str(peer, addr);
629 str = textfile_get(filename, addr);
630 if (!str)
631 return -ENOENT;
632
633 if (!key) {
634 free(str);
635 return 0;
636 }
637
638 memset(tmp, 0, sizeof(tmp));
639 for (i = 0; i < 16; i++) {
640 memcpy(tmp, str + (i * 2), 2);
641 key[i] = (uint8_t) strtol(tmp, NULL, 16);
642 }
643
644 if (type) {
645 memcpy(tmp, str + 33, 2);
646 *type = (uint8_t) strtol(tmp, NULL, 10);
647 }
648
649 free(str);
650
651 return 0;
652 }
653
read_pin_length(bdaddr_t * local,bdaddr_t * peer)654 int read_pin_length(bdaddr_t *local, bdaddr_t *peer)
655 {
656 char filename[PATH_MAX + 1], addr[18], *str;
657 int len;
658
659 create_filename(filename, PATH_MAX, local, "linkkeys");
660
661 ba2str(peer, addr);
662 str = textfile_get(filename, addr);
663 if (!str)
664 return -ENOENT;
665
666 if (strlen(str) < 36) {
667 free(str);
668 return -ENOENT;
669 }
670
671 len = atoi(str + 35);
672
673 free(str);
674
675 return len;
676 }
677
read_pin_code(bdaddr_t * local,bdaddr_t * peer,char * pin)678 int read_pin_code(bdaddr_t *local, bdaddr_t *peer, char *pin)
679 {
680 char filename[PATH_MAX + 1], addr[18], *str;
681 int len;
682
683 create_filename(filename, PATH_MAX, local, "pincodes");
684
685 ba2str(peer, addr);
686 str = textfile_get(filename, addr);
687 if (!str)
688 return -ENOENT;
689
690 strncpy(pin, str, 16);
691 len = strlen(pin);
692
693 free(str);
694
695 return len;
696 }
697
service_string_to_list(char * services)698 static GSList *service_string_to_list(char *services)
699 {
700 GSList *l = NULL;
701 char *start = services;
702 int i, finished = 0;
703
704 for (i = 0; !finished; i++) {
705 if (services[i] == '\0')
706 finished = 1;
707
708 if (services[i] == ' ' || services[i] == '\0') {
709 services[i] = '\0';
710 l = g_slist_append(l, start);
711 start = services + i + 1;
712 }
713 }
714
715 return l;
716 }
717
service_list_to_string(GSList * services)718 static char *service_list_to_string(GSList *services)
719 {
720 char str[1024];
721 int len = 0;
722
723 if (!services)
724 return g_strdup("");
725
726 memset(str, 0, sizeof(str));
727
728 while (services) {
729 int ret;
730 char *ident = services->data;
731
732 ret = snprintf(str + len, sizeof(str) - len - 1, "%s%s",
733 ident, services->next ? " " : "");
734
735 if (ret > 0)
736 len += ret;
737
738 services = services->next;
739 }
740
741 return g_strdup(str);
742 }
743
write_trust(const char * src,const char * addr,const char * service,gboolean trust)744 int write_trust(const char *src, const char *addr, const char *service,
745 gboolean trust)
746 {
747 char filename[PATH_MAX + 1], *str;
748 GSList *services = NULL, *match;
749 gboolean trusted;
750 int ret;
751
752 create_name(filename, PATH_MAX, STORAGEDIR, src, "trusts");
753
754 create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
755
756 str = textfile_caseget(filename, addr);
757 if (str)
758 services = service_string_to_list(str);
759
760 match = g_slist_find_custom(services, service, (GCompareFunc) strcmp);
761 trusted = match ? TRUE : FALSE;
762
763 /* If the old setting is the same as the requested one, we're done */
764 if (trusted == trust) {
765 g_slist_free(services);
766 free(str);
767 return 0;
768 }
769
770 if (trust)
771 services = g_slist_append(services, (void *) service);
772 else
773 services = g_slist_remove(services, match->data);
774
775 /* Remove the entry if the last trusted service was removed */
776 if (!trust && !services)
777 ret = textfile_casedel(filename, addr);
778 else {
779 char *new_str = service_list_to_string(services);
780 ret = textfile_caseput(filename, addr, new_str);
781 free(new_str);
782 }
783
784 g_slist_free(services);
785
786 free(str);
787
788 return ret;
789 }
790
read_trust(const bdaddr_t * local,const char * addr,const char * service)791 gboolean read_trust(const bdaddr_t *local, const char *addr, const char *service)
792 {
793 char filename[PATH_MAX + 1], *str;
794 GSList *services;
795 gboolean ret;
796
797 create_filename(filename, PATH_MAX, local, "trusts");
798
799 str = textfile_caseget(filename, addr);
800 if (!str)
801 return FALSE;
802
803 services = service_string_to_list(str);
804
805 if (g_slist_find_custom(services, service, (GCompareFunc) strcmp))
806 ret = TRUE;
807 else
808 ret = FALSE;
809
810 g_slist_free(services);
811 free(str);
812
813 return ret;
814 }
815
816 struct trust_list {
817 GSList *trusts;
818 const char *service;
819 };
820
append_trust(char * key,char * value,void * data)821 static void append_trust(char *key, char *value, void *data)
822 {
823 struct trust_list *list = data;
824
825 if (strstr(value, list->service))
826 list->trusts = g_slist_append(list->trusts, g_strdup(key));
827 }
828
list_trusts(bdaddr_t * local,const char * service)829 GSList *list_trusts(bdaddr_t *local, const char *service)
830 {
831 char filename[PATH_MAX + 1];
832 struct trust_list list;
833
834 create_filename(filename, PATH_MAX, local, "trusts");
835
836 list.trusts = NULL;
837 list.service = service;
838
839 if (textfile_foreach(filename, append_trust, &list) < 0)
840 return NULL;
841
842 return list.trusts;
843 }
844
write_device_profiles(bdaddr_t * src,bdaddr_t * dst,const char * profiles)845 int write_device_profiles(bdaddr_t *src, bdaddr_t *dst, const char *profiles)
846 {
847 char filename[PATH_MAX + 1], addr[18];
848
849 if (!profiles)
850 return -EINVAL;
851
852 create_filename(filename, PATH_MAX, src, "profiles");
853
854 create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
855
856 ba2str(dst, addr);
857 return textfile_put(filename, addr, profiles);
858 }
859
delete_entry(bdaddr_t * src,const char * storage,const char * key)860 int delete_entry(bdaddr_t *src, const char *storage, const char *key)
861 {
862 char filename[PATH_MAX + 1];
863
864 create_filename(filename, PATH_MAX, src, storage);
865
866 return textfile_del(filename, key);
867 }
868
store_record(const gchar * src,const gchar * dst,sdp_record_t * rec)869 int store_record(const gchar *src, const gchar *dst, sdp_record_t *rec)
870 {
871 char filename[PATH_MAX + 1], key[28];
872 sdp_buf_t buf;
873 int err, size, i;
874 char *str;
875
876 create_name(filename, PATH_MAX, STORAGEDIR, src, "sdp");
877
878 create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
879
880 snprintf(key, sizeof(key), "%17s#%08X", dst, rec->handle);
881
882 if (sdp_gen_record_pdu(rec, &buf) < 0)
883 return -1;
884
885 size = buf.data_size;
886
887 str = g_malloc0(size*2+1);
888
889 for (i = 0; i < size; i++)
890 sprintf(str + (i * 2), "%02X", buf.data[i]);
891
892 err = textfile_put(filename, key, str);
893
894 free(buf.data);
895 free(str);
896
897 return err;
898 }
899
record_from_string(const gchar * str)900 sdp_record_t *record_from_string(const gchar *str)
901 {
902 sdp_record_t *rec;
903 int size, i, len;
904 uint8_t *pdata;
905 char tmp[3];
906
907 size = strlen(str)/2;
908 pdata = g_malloc0(size);
909
910 tmp[2] = 0;
911 for (i = 0; i < size; i++) {
912 memcpy(tmp, str + (i * 2), 2);
913 pdata[i] = (uint8_t) strtol(tmp, NULL, 16);
914 }
915
916 rec = sdp_extract_pdu(pdata, size, &len);
917 free(pdata);
918
919 return rec;
920 }
921
922
fetch_record(const gchar * src,const gchar * dst,const uint32_t handle)923 sdp_record_t *fetch_record(const gchar *src, const gchar *dst,
924 const uint32_t handle)
925 {
926 char filename[PATH_MAX + 1], key[28], *str;
927 sdp_record_t *rec;
928
929 create_name(filename, PATH_MAX, STORAGEDIR, src, "sdp");
930
931 snprintf(key, sizeof(key), "%17s#%08X", dst, handle);
932
933 str = textfile_get(filename, key);
934 if (!str)
935 return NULL;
936
937 rec = record_from_string(str);
938 free(str);
939
940 return rec;
941 }
942
delete_record(const gchar * src,const gchar * dst,const uint32_t handle)943 int delete_record(const gchar *src, const gchar *dst, const uint32_t handle)
944 {
945 char filename[PATH_MAX + 1], key[28];
946
947 create_name(filename, PATH_MAX, STORAGEDIR, src, "sdp");
948
949 snprintf(key, sizeof(key), "%17s#%08X", dst, handle);
950
951 return textfile_del(filename, key);
952 }
953
954 struct record_list {
955 sdp_list_t *recs;
956 const gchar *addr;
957 };
958
create_stored_records_from_keys(char * key,char * value,void * user_data)959 static void create_stored_records_from_keys(char *key, char *value,
960 void *user_data)
961 {
962 struct record_list *rec_list = user_data;
963 const gchar *addr = rec_list->addr;
964 sdp_record_t *rec;
965
966 if (strncmp(key, addr, 17))
967 return;
968
969 rec = record_from_string(value);
970
971 rec_list->recs = sdp_list_append(rec_list->recs, rec);
972 }
973
delete_all_records(const bdaddr_t * src,const bdaddr_t * dst)974 void delete_all_records(const bdaddr_t *src, const bdaddr_t *dst)
975 {
976 sdp_list_t *records, *seq;
977 char srcaddr[18], dstaddr[18];
978
979 ba2str(src, srcaddr);
980 ba2str(dst, dstaddr);
981
982 records = read_records(src, dst);
983
984 for (seq = records; seq; seq = seq->next) {
985 sdp_record_t *rec = seq->data;
986 delete_record(srcaddr, dstaddr, rec->handle);
987 }
988
989 if (records)
990 sdp_list_free(records, (sdp_free_func_t) sdp_record_free);
991 }
992
read_records(const bdaddr_t * src,const bdaddr_t * dst)993 sdp_list_t *read_records(const bdaddr_t *src, const bdaddr_t *dst)
994 {
995 char filename[PATH_MAX + 1];
996 struct record_list rec_list;
997 char srcaddr[18], dstaddr[18];
998
999 ba2str(src, srcaddr);
1000 ba2str(dst, dstaddr);
1001
1002 rec_list.addr = dstaddr;
1003 rec_list.recs = NULL;
1004
1005 create_name(filename, PATH_MAX, STORAGEDIR, srcaddr, "sdp");
1006 textfile_foreach(filename, create_stored_records_from_keys, &rec_list);
1007
1008 return rec_list.recs;
1009 }
1010
find_record_in_list(sdp_list_t * recs,const char * uuid)1011 sdp_record_t *find_record_in_list(sdp_list_t *recs, const char *uuid)
1012 {
1013 sdp_list_t *seq;
1014
1015 for (seq = recs; seq; seq = seq->next) {
1016 sdp_record_t *rec = (sdp_record_t *) seq->data;
1017 sdp_list_t *svcclass = NULL;
1018 char *uuid_str;
1019
1020 if (sdp_get_service_classes(rec, &svcclass) < 0)
1021 continue;
1022
1023 /* Extract the uuid */
1024 uuid_str = bt_uuid2string(svcclass->data);
1025 if (!uuid_str)
1026 continue;
1027
1028 if (!strcasecmp(uuid_str, uuid)) {
1029 sdp_list_free(svcclass, free);
1030 free(uuid_str);
1031 return rec;
1032 }
1033
1034 sdp_list_free(svcclass, free);
1035 free(uuid_str);
1036 }
1037 return NULL;
1038 }
1039
store_device_id(const gchar * src,const gchar * dst,const uint16_t source,const uint16_t vendor,const uint16_t product,const uint16_t version)1040 int store_device_id(const gchar *src, const gchar *dst,
1041 const uint16_t source, const uint16_t vendor,
1042 const uint16_t product, const uint16_t version)
1043 {
1044 char filename[PATH_MAX + 1], str[20];
1045
1046 create_name(filename, PATH_MAX, STORAGEDIR, src, "did");
1047
1048 create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
1049
1050 snprintf(str, sizeof(str), "%04X %04X %04X %04X", source,
1051 vendor, product, version);
1052
1053 return textfile_put(filename, dst, str);
1054 }
1055
read_device_id_from_did(const gchar * src,const gchar * dst,uint16_t * source,uint16_t * vendor,uint16_t * product,uint16_t * version)1056 static int read_device_id_from_did(const gchar *src, const gchar *dst,
1057 uint16_t *source, uint16_t *vendor,
1058 uint16_t *product, uint16_t *version)
1059 {
1060 char filename[PATH_MAX + 1];
1061 char *str, *vendor_str, *product_str, *version_str;
1062
1063 create_name(filename, PATH_MAX, STORAGEDIR, src, "did");
1064
1065 str = textfile_get(filename, dst);
1066 if (!str)
1067 return -ENOENT;
1068
1069 vendor_str = strchr(str, ' ');
1070 if (!vendor_str) {
1071 free(str);
1072 return -ENOENT;
1073 }
1074 *(vendor_str++) = 0;
1075
1076 product_str = strchr(vendor_str, ' ');
1077 if (!product_str) {
1078 free(str);
1079 return -ENOENT;
1080 }
1081 *(product_str++) = 0;
1082
1083 version_str = strchr(product_str, ' ');
1084 if (!version_str) {
1085 free(str);
1086 return -ENOENT;
1087 }
1088 *(version_str++) = 0;
1089
1090 if (source)
1091 *source = (uint16_t) strtol(str, NULL, 16);
1092 if (vendor)
1093 *vendor = (uint16_t) strtol(vendor_str, NULL, 16);
1094 if (product)
1095 *product = (uint16_t) strtol(product_str, NULL, 16);
1096 if (version)
1097 *version = (uint16_t) strtol(version_str, NULL, 16);
1098
1099 free(str);
1100
1101 return 0;
1102 }
1103
read_device_id(const gchar * srcaddr,const gchar * dstaddr,uint16_t * source,uint16_t * vendor,uint16_t * product,uint16_t * version)1104 int read_device_id(const gchar *srcaddr, const gchar *dstaddr,
1105 uint16_t *source, uint16_t *vendor,
1106 uint16_t *product, uint16_t *version)
1107 {
1108 uint16_t lsource, lvendor, lproduct, lversion;
1109 sdp_list_t *recs;
1110 sdp_record_t *rec;
1111 bdaddr_t src, dst;
1112 int err;
1113
1114 err = read_device_id_from_did(srcaddr, dstaddr, &lsource,
1115 vendor, product, version);
1116 if (!err) {
1117 if (lsource == 0xffff)
1118 err = -ENOENT;
1119
1120 return err;
1121 }
1122
1123 str2ba(srcaddr, &src);
1124 str2ba(dstaddr, &dst);
1125
1126 recs = read_records(&src, &dst);
1127 rec = find_record_in_list(recs, PNP_UUID);
1128
1129 if (rec) {
1130 sdp_data_t *pdlist;
1131
1132 pdlist = sdp_data_get(rec, SDP_ATTR_VENDOR_ID_SOURCE);
1133 lsource = pdlist ? pdlist->val.uint16 : 0x0000;
1134
1135 pdlist = sdp_data_get(rec, SDP_ATTR_VENDOR_ID);
1136 lvendor = pdlist ? pdlist->val.uint16 : 0x0000;
1137
1138 pdlist = sdp_data_get(rec, SDP_ATTR_PRODUCT_ID);
1139 lproduct = pdlist ? pdlist->val.uint16 : 0x0000;
1140
1141 pdlist = sdp_data_get(rec, SDP_ATTR_VERSION);
1142 lversion = pdlist ? pdlist->val.uint16 : 0x0000;
1143
1144 err = 0;
1145 }
1146
1147 sdp_list_free(recs, (sdp_free_func_t)sdp_record_free);
1148
1149 if (err) {
1150 /* FIXME: We should try EIR data if we have it, too */
1151
1152 /* If we don't have the data, we don't want to go through the
1153 * above search every time. */
1154 lsource = 0xffff;
1155 lvendor = 0x0000;
1156 lproduct = 0x0000;
1157 lversion = 0x0000;
1158 }
1159
1160 store_device_id(srcaddr, dstaddr, lsource, lvendor, lproduct, lversion);
1161
1162 if (err)
1163 return err;
1164
1165 if (source)
1166 *source = lsource;
1167 if (vendor)
1168 *vendor = lvendor;
1169 if (product)
1170 *product = lproduct;
1171 if (version)
1172 *version = lversion;
1173
1174 return 0;
1175 }
1176
write_device_pairable(bdaddr_t * bdaddr,gboolean mode)1177 int write_device_pairable(bdaddr_t *bdaddr, gboolean mode)
1178 {
1179 char filename[PATH_MAX + 1];
1180
1181 create_filename(filename, PATH_MAX, bdaddr, "config");
1182
1183 create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
1184
1185 return textfile_put(filename, "pairable", mode ? "yes" : "no");
1186 }
1187
read_device_pairable(bdaddr_t * bdaddr,gboolean * mode)1188 int read_device_pairable(bdaddr_t *bdaddr, gboolean *mode)
1189 {
1190 char filename[PATH_MAX + 1], *str;
1191
1192 create_filename(filename, PATH_MAX, bdaddr, "config");
1193
1194 create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
1195
1196 str = textfile_get(filename, "pairable");
1197 if (!str)
1198 return -ENOENT;
1199
1200 *mode = strcmp(str, "yes") == 0 ? TRUE : FALSE;
1201
1202 free(str);
1203
1204 return 0;
1205 }
1206
read_blocked(const bdaddr_t * local,const bdaddr_t * remote)1207 gboolean read_blocked(const bdaddr_t *local, const bdaddr_t *remote)
1208 {
1209 char filename[PATH_MAX + 1], *str, addr[18];
1210
1211 create_filename(filename, PATH_MAX, local, "blocked");
1212
1213 ba2str(remote, addr);
1214
1215 str = textfile_caseget(filename, addr);
1216 if (!str)
1217 return FALSE;
1218
1219 free(str);
1220
1221 return TRUE;
1222 }
1223
write_blocked(const bdaddr_t * local,const bdaddr_t * remote,gboolean blocked)1224 int write_blocked(const bdaddr_t *local, const bdaddr_t *remote,
1225 gboolean blocked)
1226 {
1227 char filename[PATH_MAX + 1], addr[18];
1228
1229 create_filename(filename, PATH_MAX, local, "blocked");
1230
1231 create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
1232
1233 ba2str(remote, addr);
1234
1235 if (blocked == FALSE)
1236 return textfile_casedel(filename, addr);
1237
1238 return textfile_caseput(filename, addr, "");
1239 }
1240