1 1.5 rillig /* $NetBSD: btkey.c,v 1.5 2021/08/25 22:52:25 rillig Exp $ */ 2 1.1 plunky 3 1.1 plunky /*- 4 1.1 plunky * Copyright (c) 2007 Iain Hibbert 5 1.1 plunky * All rights reserved. 6 1.1 plunky * 7 1.1 plunky * Redistribution and use in source and binary forms, with or without 8 1.1 plunky * modification, are permitted provided that the following conditions 9 1.1 plunky * are met: 10 1.1 plunky * 1. Redistributions of source code must retain the above copyright 11 1.1 plunky * notice, this list of conditions and the following disclaimer. 12 1.1 plunky * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 plunky * notice, this list of conditions and the following disclaimer in the 14 1.1 plunky * documentation and/or other materials provided with the distribution. 15 1.1 plunky * 3. The name of the author may not be used to endorse or promote products 16 1.1 plunky * derived from this software without specific prior written permission. 17 1.1 plunky * 18 1.1 plunky * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19 1.1 plunky * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20 1.1 plunky * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21 1.1 plunky * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22 1.1 plunky * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 23 1.1 plunky * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 1.1 plunky * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 1.1 plunky * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 1.1 plunky * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27 1.1 plunky * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 1.1 plunky */ 29 1.1 plunky 30 1.1 plunky #include <sys/cdefs.h> 31 1.2 lukem __COPYRIGHT("@(#) Copyright (c) 2007 Iain Hibbert. All rights reserved."); 32 1.5 rillig __RCSID("$NetBSD: btkey.c,v 1.5 2021/08/25 22:52:25 rillig Exp $"); 33 1.1 plunky 34 1.1 plunky #include <bluetooth.h> 35 1.3 plunky #include <ctype.h> 36 1.1 plunky #include <err.h> 37 1.1 plunky #include <errno.h> 38 1.1 plunky #include <stdbool.h> 39 1.1 plunky #include <stdlib.h> 40 1.1 plunky #include <string.h> 41 1.1 plunky #include <unistd.h> 42 1.1 plunky 43 1.1 plunky #include "btkey.h" 44 1.1 plunky 45 1.4 joerg __dead static void usage(void); 46 1.1 plunky static bool scan_key(const char *); 47 1.1 plunky 48 1.1 plunky bdaddr_t laddr; 49 1.1 plunky bdaddr_t raddr; 50 1.1 plunky uint8_t key[HCI_KEY_SIZE]; 51 1.1 plunky 52 1.1 plunky int 53 1.1 plunky main(int ac, char *av[]) 54 1.1 plunky { 55 1.1 plunky struct hostent *he; 56 1.1 plunky int ch; 57 1.1 plunky bool cf, cd, lf, ld, rf, rd, wf, wd, nk; 58 1.1 plunky 59 1.1 plunky memset(&laddr, 0, sizeof(laddr)); 60 1.1 plunky memset(&raddr, 0, sizeof(raddr)); 61 1.1 plunky memset(key, 0, sizeof(key)); 62 1.1 plunky cf = cd = lf = ld = rf = rd = wf = wd = nk = false; 63 1.1 plunky 64 1.1 plunky while ((ch = getopt(ac, av, "a:cCd:k:lLrRwW")) != EOF) { 65 1.1 plunky switch (ch) { 66 1.1 plunky case 'a': /* remote device address */ 67 1.1 plunky if (!bt_aton(optarg, &raddr)) { 68 1.1 plunky he = bt_gethostbyname(optarg); 69 1.1 plunky if (he == NULL) 70 1.1 plunky errx(EXIT_FAILURE, "%s: %s", 71 1.1 plunky optarg, hstrerror(h_errno)); 72 1.1 plunky 73 1.1 plunky bdaddr_copy(&raddr, (bdaddr_t *)he->h_addr); 74 1.1 plunky } 75 1.1 plunky break; 76 1.1 plunky 77 1.1 plunky case 'c': /* clear from file */ 78 1.1 plunky cf = true; 79 1.1 plunky break; 80 1.1 plunky 81 1.1 plunky case 'C': /* clear from device */ 82 1.1 plunky cd = true; 83 1.1 plunky break; 84 1.1 plunky 85 1.1 plunky case 'd': /* local device address */ 86 1.1 plunky if (!bt_devaddr(optarg, &laddr) 87 1.1 plunky && !bt_aton(optarg, &laddr)) { 88 1.1 plunky he = bt_gethostbyname(optarg); 89 1.1 plunky if (he == NULL) 90 1.1 plunky errx(EXIT_FAILURE, "%s: %s", 91 1.1 plunky optarg, hstrerror(h_errno)); 92 1.1 plunky 93 1.1 plunky bdaddr_copy(&laddr, (bdaddr_t *)he->h_addr); 94 1.1 plunky } 95 1.1 plunky break; 96 1.1 plunky 97 1.1 plunky case 'k': /* new link key */ 98 1.1 plunky if (!scan_key(optarg)) 99 1.1 plunky errx(EXIT_FAILURE, "invalid key '%s'", optarg); 100 1.1 plunky 101 1.1 plunky nk = true; 102 1.1 plunky break; 103 1.1 plunky 104 1.1 plunky case 'l': /* list from file */ 105 1.1 plunky lf = true; 106 1.1 plunky break; 107 1.1 plunky 108 1.1 plunky case 'L': /* list from device */ 109 1.1 plunky ld = true; 110 1.1 plunky break; 111 1.1 plunky 112 1.1 plunky case 'r': /* read from file */ 113 1.1 plunky rf = true; 114 1.1 plunky break; 115 1.1 plunky 116 1.1 plunky case 'R': /* read from device */ 117 1.1 plunky rd = true; 118 1.1 plunky break; 119 1.1 plunky 120 1.1 plunky case 'w': /* write to file */ 121 1.1 plunky wf = true; 122 1.1 plunky break; 123 1.1 plunky 124 1.1 plunky case 'W': /* write to device */ 125 1.1 plunky wd = true; 126 1.1 plunky break; 127 1.1 plunky 128 1.1 plunky default: 129 1.1 plunky usage(); 130 1.1 plunky } 131 1.1 plunky } 132 1.1 plunky 133 1.1 plunky ac -= optind; 134 1.1 plunky av += optind; 135 1.1 plunky 136 1.1 plunky /* 137 1.1 plunky * validate options 138 1.1 plunky */ 139 1.1 plunky if ((lf || ld) && (rf || rd || wf || wd || cf || cd || nk)) 140 1.1 plunky errx(EXIT_FAILURE, "list is exclusive of other options"); 141 1.1 plunky 142 1.1 plunky if (((rf && rd) || (rf && nk) || (rd && nk)) && (wf || wd)) 143 1.1 plunky errx(EXIT_FAILURE, "too many key sources"); 144 1.1 plunky 145 1.1 plunky if (((bdaddr_any(&laddr) || bdaddr_any(&raddr)) && !(lf || ld)) 146 1.1 plunky || ((lf || ld) && (bdaddr_any(&laddr) || !bdaddr_any(&raddr))) 147 1.1 plunky || ac > 0) 148 1.1 plunky usage(); 149 1.1 plunky 150 1.1 plunky /* 151 1.1 plunky * do what we gotta do and be done 152 1.1 plunky */ 153 1.1 plunky if (!bdaddr_any(&laddr)) 154 1.1 plunky print_addr("device", &laddr); 155 1.1 plunky 156 1.1 plunky if (!bdaddr_any(&raddr)) 157 1.1 plunky print_addr("bdaddr", &raddr); 158 1.1 plunky 159 1.1 plunky if (lf && !list_file()) 160 1.1 plunky err(EXIT_FAILURE, "list file"); 161 1.1 plunky 162 1.1 plunky if (ld && !list_device()) 163 1.1 plunky err(EXIT_FAILURE, "list device"); 164 1.1 plunky 165 1.1 plunky if (nk) 166 1.1 plunky print_key("new key", key); 167 1.1 plunky 168 1.1 plunky if (rf) { 169 1.1 plunky if (!read_file()) 170 1.1 plunky err(EXIT_FAILURE, "file key"); 171 1.1 plunky 172 1.1 plunky print_key("file key", key); 173 1.1 plunky } 174 1.1 plunky 175 1.1 plunky if (rd) { 176 1.1 plunky if (!read_device()) 177 1.1 plunky err(EXIT_FAILURE, "device key"); 178 1.1 plunky 179 1.1 plunky print_key("device key", key); 180 1.1 plunky } 181 1.1 plunky 182 1.1 plunky if (wf || wd || cf || cd) 183 1.1 plunky printf("\n"); 184 1.1 plunky 185 1.1 plunky if (wf) { 186 1.1 plunky if (!write_file()) 187 1.1 plunky err(EXIT_FAILURE, "write to file"); 188 1.1 plunky 189 1.1 plunky printf("written to file\n"); 190 1.1 plunky } 191 1.1 plunky 192 1.1 plunky if (wd) { 193 1.1 plunky if (!write_device()) 194 1.1 plunky err(EXIT_FAILURE, "write to device"); 195 1.1 plunky 196 1.1 plunky printf("written to device\n"); 197 1.1 plunky } 198 1.1 plunky 199 1.1 plunky if (cf) { 200 1.1 plunky if (!clear_file()) 201 1.1 plunky err(EXIT_FAILURE, "clear from file"); 202 1.1 plunky 203 1.1 plunky printf("cleared from file\n"); 204 1.1 plunky } 205 1.1 plunky 206 1.1 plunky if (cd) { 207 1.1 plunky if (!clear_device()) 208 1.1 plunky err(EXIT_FAILURE, "clear from device"); 209 1.1 plunky 210 1.1 plunky printf("cleared from device\n"); 211 1.1 plunky } 212 1.1 plunky 213 1.1 plunky exit(EXIT_SUCCESS); 214 1.1 plunky } 215 1.1 plunky 216 1.1 plunky static void 217 1.1 plunky usage(void) 218 1.1 plunky { 219 1.1 plunky 220 1.1 plunky fprintf(stderr, 221 1.1 plunky "Usage: %s [-cCrRwW] [-k key] -a address -d device\n" 222 1.1 plunky " %s -lL -d device\n" 223 1.1 plunky "\n", getprogname(), getprogname()); 224 1.1 plunky 225 1.1 plunky fprintf(stderr, 226 1.1 plunky "Where:\n" 227 1.1 plunky "\t-a address remote device address\n" 228 1.1 plunky "\t-c clear from file\n" 229 1.1 plunky "\t-C clear from device\n" 230 1.1 plunky "\t-d device local device address\n" 231 1.1 plunky "\t-k key user specified link_key\n" 232 1.1 plunky "\t-l list file keys\n" 233 1.1 plunky "\t-L list device keys\n" 234 1.1 plunky "\t-r read from file\n" 235 1.1 plunky "\t-R read from device\n" 236 1.1 plunky "\t-w write to file\n" 237 1.1 plunky "\t-W write to device\n" 238 1.1 plunky "\n"); 239 1.1 plunky 240 1.1 plunky exit(EXIT_FAILURE); 241 1.1 plunky } 242 1.1 plunky 243 1.1 plunky static bool 244 1.1 plunky scan_key(const char *arg) 245 1.1 plunky { 246 1.1 plunky static const char digits[] = "0123456789abcdef"; 247 1.1 plunky const char *p; 248 1.1 plunky int i, j; 249 1.1 plunky 250 1.1 plunky memset(key, 0, sizeof(key)); 251 1.1 plunky 252 1.1 plunky for (i = 0 ; i < HCI_KEY_SIZE ; i++) { 253 1.1 plunky for (j = 0 ; j < 2 ; j++) { 254 1.1 plunky if (*arg == '\0') 255 1.1 plunky return true; 256 1.1 plunky 257 1.5 rillig for (p = digits ; 258 1.5 rillig *p != tolower((unsigned char)*arg) ; 259 1.5 rillig p++) 260 1.1 plunky if (*p == '\0') 261 1.1 plunky return false; 262 1.1 plunky 263 1.1 plunky arg++; 264 1.1 plunky key[i] = (key[i] << 4) + (p - digits); 265 1.1 plunky } 266 1.1 plunky } 267 1.1 plunky 268 1.1 plunky if (*arg != '\0') 269 1.1 plunky return false; 270 1.1 plunky 271 1.1 plunky return true; 272 1.1 plunky } 273 1.1 plunky 274 1.1 plunky void 275 1.1 plunky print_key(const char *type, const uint8_t *src) 276 1.1 plunky { 277 1.1 plunky int i; 278 1.1 plunky 279 1.1 plunky printf("%10s: ", type); 280 1.1 plunky for (i = 0 ; i < HCI_KEY_SIZE ; i++) 281 1.1 plunky printf("%2.2x", src[i]); 282 1.1 plunky 283 1.1 plunky printf("\n"); 284 1.1 plunky } 285 1.1 plunky 286 1.1 plunky 287 1.1 plunky void 288 1.1 plunky print_addr(const char *type, const bdaddr_t *addr) 289 1.1 plunky { 290 1.1 plunky char name[HCI_DEVNAME_SIZE]; 291 1.1 plunky struct hostent *he; 292 1.1 plunky 293 1.1 plunky printf("%10s: %s", type, bt_ntoa(addr, NULL)); 294 1.1 plunky 295 1.1 plunky if (bt_devname(name, addr)) 296 1.1 plunky printf(" (%s)", name); 297 1.1 plunky else if ((he = bt_gethostbyaddr((const char *)addr, 298 1.1 plunky sizeof(bdaddr_t), AF_BLUETOOTH)) != NULL) 299 1.1 plunky printf(" (%s)", he->h_name); 300 1.1 plunky 301 1.1 plunky printf("\n"); 302 1.1 plunky } 303