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