Home | History | Annotate | Line # | Download | only in btkey
      1 /*	$NetBSD: btkey.c,v 1.5 2021/08/25 22:52:25 rillig 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.5 2021/08/25 22:52:25 rillig 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 __dead 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 ;
    258 			    *p != tolower((unsigned char)*arg) ;
    259 			    p++)
    260 				if (*p == '\0')
    261 					return false;
    262 
    263 			arg++;
    264 			key[i] = (key[i] << 4) + (p - digits);
    265 		}
    266 	}
    267 
    268 	if (*arg != '\0')
    269 		return false;
    270 
    271 	return true;
    272 }
    273 
    274 void
    275 print_key(const char *type, const uint8_t *src)
    276 {
    277 	int i;
    278 
    279 	printf("%10s: ", type);
    280 	for (i = 0 ; i < HCI_KEY_SIZE ; i++)
    281 		printf("%2.2x", src[i]);
    282 
    283 	printf("\n");
    284 }
    285 
    286 
    287 void
    288 print_addr(const char *type, const bdaddr_t *addr)
    289 {
    290 	char name[HCI_DEVNAME_SIZE];
    291 	struct hostent *he;
    292 
    293 	printf("%10s: %s", type, bt_ntoa(addr, NULL));
    294 
    295 	if (bt_devname(name, addr))
    296 		printf(" (%s)", name);
    297 	else if ((he = bt_gethostbyaddr((const char *)addr,
    298 	    sizeof(bdaddr_t), AF_BLUETOOTH)) != NULL)
    299 		printf(" (%s)", he->h_name);
    300 
    301 	printf("\n");
    302 }
    303