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