Home | History | Annotate | Line # | Download | only in bthcid
config.c revision 1.2
      1 /*	$NetBSD: config.c,v 1.2 2006/07/26 11:00:07 tron 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.2 2006/07/26 11:00:07 tron 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_data_nocopy(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. %s (%d)",
    136 				strerror(errno), errno);
    137 
    138 			return;
    139 		}
    140 	}
    141 
    142 	dev = prop_dictionary_get(cfg, bt_ntoa(laddr, NULL));
    143 	if (dev == NULL) {
    144 		dev = prop_dictionary_create();
    145 		if (dev == NULL) {
    146 			syslog(LOG_ERR, "prop_dictionary_create() failed. %s (%d)",
    147 				strerror(errno), errno);
    148 
    149 			prop_object_release(cfg);
    150 			return;
    151 		}
    152 
    153 		if (!prop_dictionary_set(cfg, bt_ntoa(laddr, NULL), dev)) {
    154 			syslog(LOG_ERR, "prop_dictionary_set() failed. %s (%d)",
    155 				strerror(errno), errno);
    156 
    157 			prop_object_release(dev);
    158 			prop_object_release(cfg);
    159 			return;
    160 		}
    161 	}
    162 
    163 	dat = prop_data_create_data_nocopy(key, HCI_KEY_SIZE);
    164 	if (dat == NULL) {
    165 		syslog(LOG_ERR, "Cannot create data object. %s (%d)",
    166 			strerror(errno), errno);
    167 
    168 		prop_object_release(cfg);
    169 		return;
    170 	}
    171 
    172 	if (!prop_dictionary_set(dev, bt_ntoa(raddr, NULL), dat)) {
    173 		syslog(LOG_ERR, "prop_dictionary_set() failed. %s (%d)",
    174 			strerror(errno), errno);
    175 
    176 		prop_object_release(dat);
    177 		prop_object_release(cfg);
    178 		return;
    179 	}
    180 
    181 	xml = prop_dictionary_externalize(cfg);
    182 	if (xml == NULL) {
    183 		syslog(LOG_ERR, "prop_dictionary_externalize() failed. %s (%d)",
    184 			strerror(errno), errno);
    185 
    186 		prop_object_release(cfg);
    187 		return;
    188 	}
    189 
    190 	prop_object_release(cfg);
    191 
    192 	fd = open(new_key_file, O_WRONLY|O_TRUNC|O_CREAT|O_EXLOCK, 0600);
    193 	if (fd < 0) {
    194 		syslog(LOG_ERR, "Cannot open new keyfile %s. %s (%d)",
    195 				key_file, strerror(errno), errno);
    196 
    197 		free(xml);
    198 		return;
    199 	}
    200 
    201 	len = strlen(xml);
    202 	if (write(fd, xml, len) != len) {
    203 		syslog(LOG_ERR, "Write of keyfile failed. %s (%d)",
    204 				strerror(errno), errno);
    205 
    206 		free(xml);
    207 		close(fd);
    208 		unlink(new_key_file);
    209 		return;
    210 	}
    211 
    212 	free(xml);
    213 	close(fd);
    214 
    215 	if (rename(new_key_file, key_file) < 0) {
    216 		syslog(LOG_ERR, "rename(%s, %s) failed. %s (%d)",
    217 			new_key_file, key_file, strerror(errno), errno);
    218 
    219 		unlink(new_key_file);
    220 	}
    221 }
    222