1*bba3c683Sthorpej /* $NetBSD: config.c,v 1.6 2020/06/07 00:54:22 thorpej Exp $ */
2a5c89047Sgdamore
3a5c89047Sgdamore /*-
4a5c89047Sgdamore * Copyright (c) 2006 Itronix Inc.
5a5c89047Sgdamore * All rights reserved.
6a5c89047Sgdamore *
7a5c89047Sgdamore * Redistribution and use in source and binary forms, with or without
8a5c89047Sgdamore * modification, are permitted provided that the following conditions
9a5c89047Sgdamore * are met:
10a5c89047Sgdamore * 1. Redistributions of source code must retain the above copyright
11a5c89047Sgdamore * notice, this list of conditions and the following disclaimer.
12a5c89047Sgdamore * 2. Redistributions in binary form must reproduce the above copyright
13a5c89047Sgdamore * notice, this list of conditions and the following disclaimer in the
14a5c89047Sgdamore * documentation and/or other materials provided with the distribution.
15a5c89047Sgdamore * 3. The name of Itronix Inc. may not be used to endorse
16a5c89047Sgdamore * or promote products derived from this software without specific
17a5c89047Sgdamore * prior written permission.
18a5c89047Sgdamore *
19a5c89047Sgdamore * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND
20a5c89047Sgdamore * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21a5c89047Sgdamore * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22a5c89047Sgdamore * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY
23a5c89047Sgdamore * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24a5c89047Sgdamore * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25a5c89047Sgdamore * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26a5c89047Sgdamore * ON ANY THEORY OF LIABILITY, WHETHER IN
27a5c89047Sgdamore * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28a5c89047Sgdamore * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29a5c89047Sgdamore * POSSIBILITY OF SUCH DAMAGE.
30a5c89047Sgdamore */
31a5c89047Sgdamore
32a5c89047Sgdamore #include <sys/cdefs.h>
33*bba3c683Sthorpej __RCSID("$NetBSD: config.c,v 1.6 2020/06/07 00:54:22 thorpej Exp $");
34a5c89047Sgdamore
35a5c89047Sgdamore #include <sys/time.h>
367b1d74d7Stron #include <prop/proplib.h>
37a5c89047Sgdamore #include <bluetooth.h>
38a5c89047Sgdamore #include <errno.h>
39a5c89047Sgdamore #include <event.h>
40a5c89047Sgdamore #include <fcntl.h>
417b1d74d7Stron #include <stdlib.h>
42a5c89047Sgdamore #include <string.h>
43a5c89047Sgdamore #include <syslog.h>
44a5c89047Sgdamore #include <unistd.h>
45a5c89047Sgdamore
46a5c89047Sgdamore #include "bthcid.h"
47a5c89047Sgdamore
487b1d74d7Stron static const char *key_file = "/var/db/bthcid.keys";
497b1d74d7Stron static const char *new_key_file = "/var/db/bthcid.keys.new";
50a5c89047Sgdamore
517b1d74d7Stron static prop_dictionary_t
load_keys(void)527b1d74d7Stron load_keys(void)
537b1d74d7Stron {
547b1d74d7Stron prop_dictionary_t dict;
557b1d74d7Stron char *xml;
567b1d74d7Stron off_t len;
577b1d74d7Stron int fd;
587b1d74d7Stron
597b1d74d7Stron fd = open(key_file, O_RDONLY, 0);
607b1d74d7Stron if (fd < 0)
617b1d74d7Stron return NULL;
627b1d74d7Stron
637b1d74d7Stron len = lseek(fd, 0, SEEK_END);
647b1d74d7Stron if (len == 0) {
657b1d74d7Stron close(fd);
667b1d74d7Stron return NULL;
677b1d74d7Stron }
687b1d74d7Stron
697b1d74d7Stron xml = malloc(len);
707b1d74d7Stron if (xml == NULL) {
717b1d74d7Stron close(fd);
727b1d74d7Stron return NULL;
737b1d74d7Stron }
747b1d74d7Stron
757b1d74d7Stron (void)lseek(fd, 0, SEEK_SET);
767b1d74d7Stron if (read(fd, xml, len) != len) {
777b1d74d7Stron free(xml);
787b1d74d7Stron close(fd);
797b1d74d7Stron return NULL;
807b1d74d7Stron }
817b1d74d7Stron
827b1d74d7Stron dict = prop_dictionary_internalize(xml);
837b1d74d7Stron free(xml);
847b1d74d7Stron close(fd);
857b1d74d7Stron return dict;
867b1d74d7Stron }
877b1d74d7Stron
887b1d74d7Stron /*
897b1d74d7Stron * Look up key in keys file. We store a dictionary for each
907b1d74d7Stron * remote address, and inside that we have a data object for
917b1d74d7Stron * each local address containing the key.
927b1d74d7Stron */
93a5c89047Sgdamore uint8_t *
lookup_key(bdaddr_t * laddr,bdaddr_t * raddr)94a5c89047Sgdamore lookup_key(bdaddr_t *laddr, bdaddr_t *raddr)
95a5c89047Sgdamore {
967b1d74d7Stron static uint8_t key[HCI_KEY_SIZE];
977b1d74d7Stron prop_dictionary_t cfg;
987b1d74d7Stron prop_object_t obj;
99a5c89047Sgdamore
1007b1d74d7Stron cfg = load_keys();
1017b1d74d7Stron if (cfg == NULL)
102a5c89047Sgdamore return NULL;
103a5c89047Sgdamore
1047b1d74d7Stron obj = prop_dictionary_get(cfg, bt_ntoa(laddr, NULL));
1057b1d74d7Stron if (obj == NULL || prop_object_type(obj) != PROP_TYPE_DICTIONARY) {
1067b1d74d7Stron prop_object_release(cfg);
107a5c89047Sgdamore return NULL;
108a5c89047Sgdamore }
109a5c89047Sgdamore
1107b1d74d7Stron obj = prop_dictionary_get(obj, bt_ntoa(raddr, NULL));
1117b1d74d7Stron if (obj == NULL || prop_object_type(obj) != PROP_TYPE_DATA
1127b1d74d7Stron || prop_data_size(obj) != sizeof(key)) {
1137b1d74d7Stron prop_object_release(cfg);
1147b1d74d7Stron return NULL;
115a5c89047Sgdamore }
116a5c89047Sgdamore
117*bba3c683Sthorpej memcpy(key, prop_data_value(obj), sizeof(key));
1187b1d74d7Stron prop_object_release(cfg);
1197b1d74d7Stron return key;
120a5c89047Sgdamore }
121a5c89047Sgdamore
122a5c89047Sgdamore void
save_key(bdaddr_t * laddr,bdaddr_t * raddr,uint8_t * key)123a5c89047Sgdamore save_key(bdaddr_t *laddr, bdaddr_t *raddr, uint8_t *key)
124a5c89047Sgdamore {
1257b1d74d7Stron prop_dictionary_t cfg, dev;
1267b1d74d7Stron prop_data_t dat;
1277b1d74d7Stron char *xml;
1287b1d74d7Stron int fd;
1297b1d74d7Stron size_t len;
130a5c89047Sgdamore
1317b1d74d7Stron cfg = load_keys();
1327b1d74d7Stron if (cfg == NULL) {
1337b1d74d7Stron cfg = prop_dictionary_create();
1347b1d74d7Stron if (cfg == NULL) {
1354c6d0d2aSplunky syslog(LOG_ERR, "prop_dictionary_create() failed: %m");
136a5c89047Sgdamore return;
137a5c89047Sgdamore }
138a5c89047Sgdamore }
139a5c89047Sgdamore
1407b1d74d7Stron dev = prop_dictionary_get(cfg, bt_ntoa(laddr, NULL));
1417b1d74d7Stron if (dev == NULL) {
1427b1d74d7Stron dev = prop_dictionary_create();
1437b1d74d7Stron if (dev == NULL) {
1444c6d0d2aSplunky syslog(LOG_ERR, "prop_dictionary_create() failed: %m");
1457b1d74d7Stron prop_object_release(cfg);
1467b1d74d7Stron return;
1477b1d74d7Stron }
1487b1d74d7Stron
1497b1d74d7Stron if (!prop_dictionary_set(cfg, bt_ntoa(laddr, NULL), dev)) {
1504c6d0d2aSplunky syslog(LOG_ERR, "prop_dictionary_set() failed: %m");
1517b1d74d7Stron prop_object_release(dev);
1527b1d74d7Stron prop_object_release(cfg);
1537b1d74d7Stron return;
1547b1d74d7Stron }
1553cee5215Splunky
1563cee5215Splunky prop_object_release(dev);
1577b1d74d7Stron }
1587b1d74d7Stron
159*bba3c683Sthorpej dat = prop_data_create_nocopy(key, HCI_KEY_SIZE);
1607b1d74d7Stron if (dat == NULL) {
1614c6d0d2aSplunky syslog(LOG_ERR, "Cannot create data object: %m");
1627b1d74d7Stron prop_object_release(cfg);
1637b1d74d7Stron return;
1647b1d74d7Stron }
1657b1d74d7Stron
1667b1d74d7Stron if (!prop_dictionary_set(dev, bt_ntoa(raddr, NULL), dat)) {
1674c6d0d2aSplunky syslog(LOG_ERR, "prop_dictionary_set() failed: %m");
1687b1d74d7Stron prop_object_release(dat);
1697b1d74d7Stron prop_object_release(cfg);
1707b1d74d7Stron return;
1717b1d74d7Stron }
1727b1d74d7Stron
1733cee5215Splunky prop_object_release(dat);
1743cee5215Splunky
1757b1d74d7Stron xml = prop_dictionary_externalize(cfg);
1767b1d74d7Stron if (xml == NULL) {
1774c6d0d2aSplunky syslog(LOG_ERR, "prop_dictionary_externalize() failed: %m");
1787b1d74d7Stron prop_object_release(cfg);
1797b1d74d7Stron return;
1807b1d74d7Stron }
1817b1d74d7Stron
1827b1d74d7Stron prop_object_release(cfg);
1837b1d74d7Stron
1847b1d74d7Stron fd = open(new_key_file, O_WRONLY|O_TRUNC|O_CREAT|O_EXLOCK, 0600);
1857b1d74d7Stron if (fd < 0) {
1864c6d0d2aSplunky syslog(LOG_ERR, "Cannot open new keyfile %s: %m", key_file);
1877b1d74d7Stron free(xml);
1887b1d74d7Stron return;
1897b1d74d7Stron }
1907b1d74d7Stron
1917b1d74d7Stron len = strlen(xml);
1922132a832Slukem if ((size_t)write(fd, xml, len) != len) {
1934c6d0d2aSplunky syslog(LOG_ERR, "Write of keyfile failed: %m");
1947b1d74d7Stron free(xml);
195a5c89047Sgdamore close(fd);
1967b1d74d7Stron unlink(new_key_file);
1977b1d74d7Stron return;
1987b1d74d7Stron }
1997b1d74d7Stron
2007b1d74d7Stron free(xml);
2017b1d74d7Stron close(fd);
2027b1d74d7Stron
2037b1d74d7Stron if (rename(new_key_file, key_file) < 0) {
2044c6d0d2aSplunky syslog(LOG_ERR, "rename(%s, %s) failed: %m",
2054c6d0d2aSplunky new_key_file, key_file);
2067b1d74d7Stron
2077b1d74d7Stron unlink(new_key_file);
2087b1d74d7Stron }
209a5c89047Sgdamore }
210