1 /*
2 *
3 * BlueZ - Bluetooth protocol stack for Linux
4 *
5 * Copyright (C) 2006-2007 Nokia Corporation
6 * Copyright (C) 2004-2009 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;
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,char * name)206 int write_local_name(bdaddr_t *bdaddr, 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 * features)486 int write_features_info(bdaddr_t *local, bdaddr_t *peer, unsigned char *features)
487 {
488 char filename[PATH_MAX + 1], addr[18], str[17];
489 int i;
490
491 memset(str, 0, sizeof(str));
492 for (i = 0; i < 8; i++)
493 sprintf(str + (i * 2), "%2.2X", features[i]);
494
495 create_filename(filename, PATH_MAX, local, "features");
496
497 create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
498
499 ba2str(peer, addr);
500 return textfile_put(filename, addr, str);
501 }
502
write_lastseen_info(bdaddr_t * local,bdaddr_t * peer,struct tm * tm)503 int write_lastseen_info(bdaddr_t *local, bdaddr_t *peer, struct tm *tm)
504 {
505 char filename[PATH_MAX + 1], addr[18], str[24];
506
507 memset(str, 0, sizeof(str));
508 strftime(str, sizeof(str), "%Y-%m-%d %H:%M:%S %Z", tm);
509
510 create_filename(filename, PATH_MAX, local, "lastseen");
511
512 create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
513
514 ba2str(peer, addr);
515 return textfile_put(filename, addr, str);
516 }
517
write_lastused_info(bdaddr_t * local,bdaddr_t * peer,struct tm * tm)518 int write_lastused_info(bdaddr_t *local, bdaddr_t *peer, struct tm *tm)
519 {
520 char filename[PATH_MAX + 1], addr[18], str[24];
521
522 memset(str, 0, sizeof(str));
523 strftime(str, sizeof(str), "%Y-%m-%d %H:%M:%S %Z", tm);
524
525 create_filename(filename, PATH_MAX, local, "lastused");
526
527 create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
528
529 ba2str(peer, addr);
530 return textfile_put(filename, addr, str);
531 }
532
write_link_key(bdaddr_t * local,bdaddr_t * peer,unsigned char * key,uint8_t type,int length)533 int write_link_key(bdaddr_t *local, bdaddr_t *peer, unsigned char *key, uint8_t type, int length)
534 {
535 char filename[PATH_MAX + 1], addr[18], str[38];
536 int i;
537
538 memset(str, 0, sizeof(str));
539 for (i = 0; i < 16; i++)
540 sprintf(str + (i * 2), "%2.2X", key[i]);
541 sprintf(str + 32, " %d %d", type, length);
542
543 create_filename(filename, PATH_MAX, local, "linkkeys");
544
545 create_file(filename, S_IRUSR | S_IWUSR);
546
547 ba2str(peer, addr);
548
549 if (length < 0) {
550 char *tmp = textfile_get(filename, addr);
551 if (tmp) {
552 if (strlen(tmp) > 34)
553 memcpy(str + 34, tmp + 34, 3);
554 free(tmp);
555 }
556 }
557
558 return textfile_put(filename, addr, str);
559 }
560
read_link_key(bdaddr_t * local,bdaddr_t * peer,unsigned char * key,uint8_t * type)561 int read_link_key(bdaddr_t *local, bdaddr_t *peer, unsigned char *key, uint8_t *type)
562 {
563 char filename[PATH_MAX + 1], addr[18], tmp[3], *str;
564 int i;
565
566 create_filename(filename, PATH_MAX, local, "linkkeys");
567
568 ba2str(peer, addr);
569 str = textfile_get(filename, addr);
570 if (!str)
571 return -ENOENT;
572
573 memset(tmp, 0, sizeof(tmp));
574 for (i = 0; i < 16; i++) {
575 memcpy(tmp, str + (i * 2), 2);
576 key[i] = (uint8_t) strtol(tmp, NULL, 16);
577 }
578
579 if (type) {
580 memcpy(tmp, str + 33, 2);
581 *type = (uint8_t) strtol(tmp, NULL, 10);
582 }
583
584 free(str);
585
586 return 0;
587 }
588
read_pin_length(bdaddr_t * local,bdaddr_t * peer)589 int read_pin_length(bdaddr_t *local, bdaddr_t *peer)
590 {
591 char filename[PATH_MAX + 1], addr[18], *str;
592 int len;
593
594 create_filename(filename, PATH_MAX, local, "linkkeys");
595
596 ba2str(peer, addr);
597 str = textfile_get(filename, addr);
598 if (!str)
599 return -ENOENT;
600
601 if (strlen(str) < 36) {
602 free(str);
603 return -ENOENT;
604 }
605
606 len = atoi(str + 35);
607
608 free(str);
609
610 return len;
611 }
612
read_pin_code(bdaddr_t * local,bdaddr_t * peer,char * pin)613 int read_pin_code(bdaddr_t *local, bdaddr_t *peer, char *pin)
614 {
615 char filename[PATH_MAX + 1], addr[18], *str;
616 int len;
617
618 create_filename(filename, PATH_MAX, local, "pincodes");
619
620 ba2str(peer, addr);
621 str = textfile_get(filename, addr);
622 if (!str)
623 return -ENOENT;
624
625 strncpy(pin, str, 16);
626 len = strlen(pin);
627
628 free(str);
629
630 return len;
631 }
632
service_string_to_list(char * services)633 static GSList *service_string_to_list(char *services)
634 {
635 GSList *l = NULL;
636 char *start = services;
637 int i, finished = 0;
638
639 for (i = 0; !finished; i++) {
640 if (services[i] == '\0')
641 finished = 1;
642
643 if (services[i] == ' ' || services[i] == '\0') {
644 services[i] = '\0';
645 l = g_slist_append(l, start);
646 start = services + i + 1;
647 }
648 }
649
650 return l;
651 }
652
service_list_to_string(GSList * services)653 static char *service_list_to_string(GSList *services)
654 {
655 char str[1024];
656 int len = 0;
657
658 if (!services)
659 return g_strdup("");
660
661 memset(str, 0, sizeof(str));
662
663 while (services) {
664 int ret;
665 char *ident = services->data;
666
667 ret = snprintf(str + len, sizeof(str) - len - 1, "%s%s",
668 ident, services->next ? " " : "");
669
670 if (ret > 0)
671 len += ret;
672
673 services = services->next;
674 }
675
676 return g_strdup(str);
677 }
678
write_trust(const char * src,const char * addr,const char * service,gboolean trust)679 int write_trust(const char *src, const char *addr, const char *service,
680 gboolean trust)
681 {
682 char filename[PATH_MAX + 1], *str;
683 GSList *services = NULL, *match;
684 gboolean trusted;
685 int ret;
686
687 create_name(filename, PATH_MAX, STORAGEDIR, src, "trusts");
688
689 create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
690
691 str = textfile_caseget(filename, addr);
692 if (str)
693 services = service_string_to_list(str);
694
695 match = g_slist_find_custom(services, service, (GCompareFunc) strcmp);
696 trusted = match ? TRUE : FALSE;
697
698 /* If the old setting is the same as the requested one, we're done */
699 if (trusted == trust) {
700 g_slist_free(services);
701 if (str)
702 free(str);
703 return 0;
704 }
705
706 if (trust)
707 services = g_slist_append(services, (void *) service);
708 else
709 services = g_slist_remove(services, match->data);
710
711 /* Remove the entry if the last trusted service was removed */
712 if (!trust && !services)
713 ret = textfile_casedel(filename, addr);
714 else {
715 char *new_str = service_list_to_string(services);
716 ret = textfile_caseput(filename, addr, new_str);
717 free(new_str);
718 }
719
720 g_slist_free(services);
721
722 if (str)
723 free(str);
724
725 return ret;
726 }
727
read_trust(const bdaddr_t * local,const char * addr,const char * service)728 gboolean read_trust(const bdaddr_t *local, const char *addr, const char *service)
729 {
730 char filename[PATH_MAX + 1], *str;
731 GSList *services;
732 gboolean ret;
733
734 create_filename(filename, PATH_MAX, local, "trusts");
735
736 str = textfile_caseget(filename, addr);
737 if (!str)
738 return FALSE;
739
740 services = service_string_to_list(str);
741
742 if (g_slist_find_custom(services, service, (GCompareFunc) strcmp))
743 ret = TRUE;
744 else
745 ret = FALSE;
746
747 g_slist_free(services);
748 free(str);
749
750 return ret;
751 }
752
753 struct trust_list {
754 GSList *trusts;
755 const char *service;
756 };
757
append_trust(char * key,char * value,void * data)758 static void append_trust(char *key, char *value, void *data)
759 {
760 struct trust_list *list = data;
761
762 if (strstr(value, list->service))
763 list->trusts = g_slist_append(list->trusts, g_strdup(key));
764 }
765
list_trusts(bdaddr_t * local,const char * service)766 GSList *list_trusts(bdaddr_t *local, const char *service)
767 {
768 char filename[PATH_MAX + 1];
769 struct trust_list list;
770
771 create_filename(filename, PATH_MAX, local, "trusts");
772
773 list.trusts = NULL;
774 list.service = service;
775
776 if (textfile_foreach(filename, append_trust, &list) < 0)
777 return NULL;
778
779 return list.trusts;
780 }
781
write_device_profiles(bdaddr_t * src,bdaddr_t * dst,const char * profiles)782 int write_device_profiles(bdaddr_t *src, bdaddr_t *dst, const char *profiles)
783 {
784 char filename[PATH_MAX + 1], addr[18];
785
786 if (!profiles)
787 return -EINVAL;
788
789 create_filename(filename, PATH_MAX, src, "profiles");
790
791 create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
792
793 ba2str(dst, addr);
794 return textfile_put(filename, addr, profiles);
795 }
796
delete_entry(bdaddr_t * src,const char * storage,const char * key)797 int delete_entry(bdaddr_t *src, const char *storage, const char *key)
798 {
799 char filename[PATH_MAX + 1];
800
801 create_filename(filename, PATH_MAX, src, storage);
802
803 return textfile_del(filename, key);
804 }
805
store_record(const gchar * src,const gchar * dst,sdp_record_t * rec)806 int store_record(const gchar *src, const gchar *dst, sdp_record_t *rec)
807 {
808 char filename[PATH_MAX + 1], key[28];
809 sdp_buf_t buf;
810 int err, size, i;
811 char *str;
812
813 create_name(filename, PATH_MAX, STORAGEDIR, src, "sdp");
814
815 create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
816
817 snprintf(key, sizeof(key), "%17s#%08X", dst, rec->handle);
818
819 if (sdp_gen_record_pdu(rec, &buf) < 0)
820 return -1;
821
822 size = buf.data_size;
823
824 str = g_malloc0(size*2+1);
825
826 for (i = 0; i < size; i++)
827 sprintf(str + (i * 2), "%02X", buf.data[i]);
828
829 err = textfile_put(filename, key, str);
830
831 free(buf.data);
832 free(str);
833
834 return err;
835 }
836
record_from_string(const gchar * str)837 sdp_record_t *record_from_string(const gchar *str)
838 {
839 sdp_record_t *rec;
840 int size, i, len;
841 uint8_t *pdata;
842 char tmp[3];
843
844 size = strlen(str)/2;
845 pdata = g_malloc0(size);
846
847 tmp[2] = 0;
848 for (i = 0; i < size; i++) {
849 memcpy(tmp, str + (i * 2), 2);
850 pdata[i] = (uint8_t) strtol(tmp, NULL, 16);
851 }
852
853 rec = sdp_extract_pdu(pdata, size, &len);
854 free(pdata);
855
856 return rec;
857 }
858
859
fetch_record(const gchar * src,const gchar * dst,const uint32_t handle)860 sdp_record_t *fetch_record(const gchar *src, const gchar *dst,
861 const uint32_t handle)
862 {
863 char filename[PATH_MAX + 1], key[28], *str;
864 sdp_record_t *rec;
865
866 create_name(filename, PATH_MAX, STORAGEDIR, src, "sdp");
867
868 snprintf(key, sizeof(key), "%17s#%08X", dst, handle);
869
870 str = textfile_get(filename, key);
871 if (!str)
872 return NULL;
873
874 rec = record_from_string(str);
875 free(str);
876
877 return rec;
878 }
879
delete_record(const gchar * src,const gchar * dst,const uint32_t handle)880 int delete_record(const gchar *src, const gchar *dst, const uint32_t handle)
881 {
882 char filename[PATH_MAX + 1], key[28];
883
884 create_name(filename, PATH_MAX, STORAGEDIR, src, "sdp");
885
886 snprintf(key, sizeof(key), "%17s#%08X", dst, handle);
887
888 return textfile_del(filename, key);
889 }
890
891 struct record_list {
892 sdp_list_t *recs;
893 const gchar *addr;
894 };
895
create_stored_records_from_keys(char * key,char * value,void * user_data)896 static void create_stored_records_from_keys(char *key, char *value,
897 void *user_data)
898 {
899 struct record_list *rec_list = user_data;
900 const gchar *addr = rec_list->addr;
901 sdp_record_t *rec;
902
903 if (strncmp(key, addr, 17))
904 return;
905
906 rec = record_from_string(value);
907
908 rec_list->recs = sdp_list_append(rec_list->recs, rec);
909 }
910
delete_all_records(bdaddr_t * src,bdaddr_t * dst)911 void delete_all_records(bdaddr_t *src, bdaddr_t *dst)
912 {
913 sdp_list_t *records, *seq;
914 sdp_record_t *rec;
915 char srcaddr[18], dstaddr[18];
916
917 ba2str(src, srcaddr);
918 ba2str(dst, dstaddr);
919
920 records = read_records(src, dst);
921
922 for (seq = records; seq; seq = seq->next) {
923 rec = seq->data;
924 delete_record(srcaddr, dstaddr, rec->handle);
925 }
926
927 if (records)
928 sdp_list_free(records, (sdp_free_func_t) sdp_record_free);
929 }
930
read_records(bdaddr_t * src,bdaddr_t * dst)931 sdp_list_t *read_records(bdaddr_t *src, bdaddr_t *dst)
932 {
933 char filename[PATH_MAX + 1];
934 struct record_list rec_list;
935 char srcaddr[18], dstaddr[18];
936
937 ba2str(src, srcaddr);
938 ba2str(dst, dstaddr);
939
940 rec_list.addr = dstaddr;
941 rec_list.recs = NULL;
942
943 create_name(filename, PATH_MAX, STORAGEDIR, srcaddr, "sdp");
944 textfile_foreach(filename, create_stored_records_from_keys, &rec_list);
945
946 return rec_list.recs;
947 }
948
find_record_in_list(sdp_list_t * recs,const char * uuid)949 sdp_record_t *find_record_in_list(sdp_list_t *recs, const char *uuid)
950 {
951 sdp_list_t *seq;
952
953 for (seq = recs; seq; seq = seq->next) {
954 sdp_record_t *rec = (sdp_record_t *) seq->data;
955 sdp_list_t *svcclass = NULL;
956 char *uuid_str;
957
958 if (sdp_get_service_classes(rec, &svcclass) < 0)
959 continue;
960
961 /* Extract the uuid */
962 uuid_str = bt_uuid2string(svcclass->data);
963 if (!uuid_str)
964 continue;
965
966 if (!strcasecmp(uuid_str, uuid)) {
967 sdp_list_free(svcclass, free);
968 free(uuid_str);
969 return rec;
970 }
971
972 sdp_list_free(svcclass, free);
973 free(uuid_str);
974 }
975 return NULL;
976 }
977
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)978 int store_device_id(const gchar *src, const gchar *dst,
979 const uint16_t source, const uint16_t vendor,
980 const uint16_t product, const uint16_t version)
981 {
982 char filename[PATH_MAX + 1], str[20];
983
984 create_name(filename, PATH_MAX, STORAGEDIR, src, "did");
985
986 create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
987
988 snprintf(str, sizeof(str), "%04X %04X %04X %04X", source,
989 vendor, product, version);
990
991 return textfile_put(filename, dst, str);
992 }
993
read_device_id_from_did(const gchar * src,const gchar * dst,uint16_t * source,uint16_t * vendor,uint16_t * product,uint16_t * version)994 static int read_device_id_from_did(const gchar *src, const gchar *dst,
995 uint16_t *source, uint16_t *vendor,
996 uint16_t *product, uint16_t *version)
997 {
998 char filename[PATH_MAX + 1];
999 char *str, *vendor_str, *product_str, *version_str;
1000
1001 create_name(filename, PATH_MAX, STORAGEDIR, src, "did");
1002
1003 str = textfile_get(filename, dst);
1004 if (!str)
1005 return -ENOENT;
1006
1007 vendor_str = strchr(str, ' ');
1008 if (!vendor_str) {
1009 free(str);
1010 return -ENOENT;
1011 }
1012 *(vendor_str++) = 0;
1013
1014 product_str = strchr(vendor_str, ' ');
1015 if (!product_str) {
1016 free(str);
1017 return -ENOENT;
1018 }
1019 *(product_str++) = 0;
1020
1021 version_str = strchr(product_str, ' ');
1022 if (!version_str) {
1023 free(str);
1024 return -ENOENT;
1025 }
1026 *(version_str++) = 0;
1027
1028 if (source)
1029 *source = (uint16_t) strtol(str, NULL, 16);
1030 if (vendor)
1031 *vendor = (uint16_t) strtol(vendor_str, NULL, 16);
1032 if (product)
1033 *product = (uint16_t) strtol(product_str, NULL, 16);
1034 if (version)
1035 *version = (uint16_t) strtol(version_str, NULL, 16);
1036
1037 free(str);
1038
1039 return 0;
1040 }
1041
read_device_id(const gchar * srcaddr,const gchar * dstaddr,uint16_t * source,uint16_t * vendor,uint16_t * product,uint16_t * version)1042 int read_device_id(const gchar *srcaddr, const gchar *dstaddr,
1043 uint16_t *source, uint16_t *vendor,
1044 uint16_t *product, uint16_t *version)
1045 {
1046 uint16_t lsource, lvendor, lproduct, lversion;
1047 sdp_list_t *recs;
1048 sdp_record_t *rec;
1049 bdaddr_t src, dst;
1050 int err;
1051
1052 err = read_device_id_from_did(srcaddr, dstaddr, &lsource,
1053 vendor, product, version);
1054 if (!err) {
1055 if (lsource == 0xffff)
1056 err = -ENOENT;
1057
1058 return err;
1059 }
1060
1061 str2ba(srcaddr, &src);
1062 str2ba(dstaddr, &dst);
1063
1064 recs = read_records(&src, &dst);
1065 rec = find_record_in_list(recs, PNP_UUID);
1066
1067 if (rec) {
1068 sdp_data_t *pdlist;
1069
1070 pdlist = sdp_data_get(rec, SDP_ATTR_VENDOR_ID_SOURCE);
1071 lsource = pdlist ? pdlist->val.uint16 : 0x0000;
1072
1073 pdlist = sdp_data_get(rec, SDP_ATTR_VENDOR_ID);
1074 lvendor = pdlist ? pdlist->val.uint16 : 0x0000;
1075
1076 pdlist = sdp_data_get(rec, SDP_ATTR_PRODUCT_ID);
1077 lproduct = pdlist ? pdlist->val.uint16 : 0x0000;
1078
1079 pdlist = sdp_data_get(rec, SDP_ATTR_VERSION);
1080 lversion = pdlist ? pdlist->val.uint16 : 0x0000;
1081
1082 err = 0;
1083 }
1084
1085 sdp_list_free(recs, (sdp_free_func_t)sdp_record_free);
1086
1087 if (err) {
1088 /* FIXME: We should try EIR data if we have it, too */
1089
1090 /* If we don't have the data, we don't want to go through the
1091 * above search every time. */
1092 lsource = 0xffff;
1093 lvendor = 0x0000;
1094 lproduct = 0x0000;
1095 lversion = 0x0000;
1096 }
1097
1098 store_device_id(srcaddr, dstaddr, lsource, lvendor, lproduct, lversion);
1099
1100 if (err)
1101 return err;
1102
1103 if (source)
1104 *source = lsource;
1105 if (vendor)
1106 *vendor = lvendor;
1107 if (product)
1108 *product = lproduct;
1109 if (version)
1110 *version = lversion;
1111
1112 return 0;
1113 }
1114
write_device_pairable(bdaddr_t * bdaddr,gboolean mode)1115 int write_device_pairable(bdaddr_t *bdaddr, gboolean mode)
1116 {
1117 char filename[PATH_MAX + 1];
1118
1119 create_filename(filename, PATH_MAX, bdaddr, "config");
1120
1121 create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
1122
1123 return textfile_put(filename, "pairable", mode ? "yes" : "no");
1124 }
1125
read_device_pairable(bdaddr_t * bdaddr,gboolean * mode)1126 int read_device_pairable(bdaddr_t *bdaddr, gboolean *mode)
1127 {
1128 char filename[PATH_MAX + 1], *str;
1129
1130 create_filename(filename, PATH_MAX, bdaddr, "config");
1131
1132 create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
1133
1134 str = textfile_get(filename, "pairable");
1135 if (!str)
1136 return -ENOENT;
1137
1138 *mode = strcmp(str, "yes") == 0 ? TRUE : FALSE;
1139
1140 free(str);
1141
1142 return 0;
1143 }
1144