Home | History | Annotate | Line # | Download | only in bthcid
      1 /*	$NetBSD: config.c,v 1.6 2020/06/07 00:54:22 thorpej Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 2006 Itronix Inc.
      5  * All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  * 3. The name of Itronix Inc. may not be used to endorse
     16  *    or promote products derived from this software without specific
     17  *    prior written permission.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND
     20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY
     23  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     24  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     25  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
     26  * ON ANY THEORY OF LIABILITY, WHETHER IN
     27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29  * POSSIBILITY OF SUCH DAMAGE.
     30  */
     31 
     32 #include <sys/cdefs.h>
     33 __RCSID("$NetBSD: config.c,v 1.6 2020/06/07 00:54:22 thorpej Exp $");
     34 
     35 #include <sys/time.h>
     36 #include <prop/proplib.h>
     37 #include <bluetooth.h>
     38 #include <errno.h>
     39 #include <event.h>
     40 #include <fcntl.h>
     41 #include <stdlib.h>
     42 #include <string.h>
     43 #include <syslog.h>
     44 #include <unistd.h>
     45 
     46 #include "bthcid.h"
     47 
     48 static const char *key_file = "/var/db/bthcid.keys";
     49 static const char *new_key_file = "/var/db/bthcid.keys.new";
     50 
     51 static prop_dictionary_t
     52 load_keys(void)
     53 {
     54 	prop_dictionary_t dict;
     55 	char *xml;
     56 	off_t len;
     57 	int fd;
     58 
     59 	fd = open(key_file, O_RDONLY, 0);
     60 	if (fd < 0)
     61 		return NULL;
     62 
     63 	len = lseek(fd, 0, SEEK_END);
     64 	if (len == 0) {
     65 		close(fd);
     66 		return NULL;
     67 	}
     68 
     69 	xml = malloc(len);
     70 	if (xml == NULL) {
     71 		close(fd);
     72 		return NULL;
     73 	}
     74 
     75 	(void)lseek(fd, 0, SEEK_SET);
     76 	if (read(fd, xml, len) != len) {
     77 		free(xml);
     78 		close(fd);
     79 		return NULL;
     80 	}
     81 
     82 	dict = prop_dictionary_internalize(xml);
     83 	free(xml);
     84 	close(fd);
     85 	return dict;
     86 }
     87 
     88 /*
     89  * Look up key in keys file. We store a dictionary for each
     90  * remote address, and inside that we have a data object for
     91  * each local address containing the key.
     92  */
     93 uint8_t *
     94 lookup_key(bdaddr_t *laddr, bdaddr_t *raddr)
     95 {
     96 	static uint8_t key[HCI_KEY_SIZE];
     97 	prop_dictionary_t cfg;
     98 	prop_object_t obj;
     99 
    100 	cfg = load_keys();
    101 	if (cfg == NULL)
    102 		return NULL;
    103 
    104 	obj = prop_dictionary_get(cfg, bt_ntoa(laddr, NULL));
    105 	if (obj == NULL || prop_object_type(obj) != PROP_TYPE_DICTIONARY) {
    106 		prop_object_release(cfg);
    107 		return NULL;
    108 	}
    109 
    110 	obj = prop_dictionary_get(obj, bt_ntoa(raddr, NULL));
    111 	if (obj == NULL || prop_object_type(obj) != PROP_TYPE_DATA
    112 	    || prop_data_size(obj) != sizeof(key)) {
    113 		prop_object_release(cfg);
    114 		return NULL;
    115 	}
    116 
    117 	memcpy(key, prop_data_value(obj), sizeof(key));
    118 	prop_object_release(cfg);
    119 	return key;
    120 }
    121 
    122 void
    123 save_key(bdaddr_t *laddr, bdaddr_t *raddr, uint8_t *key)
    124 {
    125 	prop_dictionary_t cfg, dev;
    126 	prop_data_t dat;
    127 	char *xml;
    128 	int fd;
    129 	size_t len;
    130 
    131 	cfg = load_keys();
    132 	if (cfg == NULL) {
    133 		cfg = prop_dictionary_create();
    134 		if (cfg == NULL) {
    135 			syslog(LOG_ERR, "prop_dictionary_create() failed: %m");
    136 			return;
    137 		}
    138 	}
    139 
    140 	dev = prop_dictionary_get(cfg, bt_ntoa(laddr, NULL));
    141 	if (dev == NULL) {
    142 		dev = prop_dictionary_create();
    143 		if (dev == NULL) {
    144 			syslog(LOG_ERR, "prop_dictionary_create() failed: %m");
    145 			prop_object_release(cfg);
    146 			return;
    147 		}
    148 
    149 		if (!prop_dictionary_set(cfg, bt_ntoa(laddr, NULL), dev)) {
    150 			syslog(LOG_ERR, "prop_dictionary_set() failed: %m");
    151 			prop_object_release(dev);
    152 			prop_object_release(cfg);
    153 			return;
    154 		}
    155 
    156 		prop_object_release(dev);
    157 	}
    158 
    159 	dat = prop_data_create_nocopy(key, HCI_KEY_SIZE);
    160 	if (dat == NULL) {
    161 		syslog(LOG_ERR, "Cannot create data object: %m");
    162 		prop_object_release(cfg);
    163 		return;
    164 	}
    165 
    166 	if (!prop_dictionary_set(dev, bt_ntoa(raddr, NULL), dat)) {
    167 		syslog(LOG_ERR, "prop_dictionary_set() failed: %m");
    168 		prop_object_release(dat);
    169 		prop_object_release(cfg);
    170 		return;
    171 	}
    172 
    173 	prop_object_release(dat);
    174 
    175 	xml = prop_dictionary_externalize(cfg);
    176 	if (xml == NULL) {
    177 		syslog(LOG_ERR, "prop_dictionary_externalize() failed: %m");
    178 		prop_object_release(cfg);
    179 		return;
    180 	}
    181 
    182 	prop_object_release(cfg);
    183 
    184 	fd = open(new_key_file, O_WRONLY|O_TRUNC|O_CREAT|O_EXLOCK, 0600);
    185 	if (fd < 0) {
    186 		syslog(LOG_ERR, "Cannot open new keyfile %s: %m", key_file);
    187 		free(xml);
    188 		return;
    189 	}
    190 
    191 	len = strlen(xml);
    192 	if ((size_t)write(fd, xml, len) != len) {
    193 		syslog(LOG_ERR, "Write of keyfile failed: %m");
    194 		free(xml);
    195 		close(fd);
    196 		unlink(new_key_file);
    197 		return;
    198 	}
    199 
    200 	free(xml);
    201 	close(fd);
    202 
    203 	if (rename(new_key_file, key_file) < 0) {
    204 		syslog(LOG_ERR, "rename(%s, %s) failed: %m",
    205 			new_key_file, key_file);
    206 
    207 		unlink(new_key_file);
    208 	}
    209 }
    210