xref: /netbsd-src/usr.sbin/bthcid/config.c (revision bba3c68329cec67db518161db62f02b5550c5994)
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