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