xref: /netbsd/usr.bin/btkey/btkey.c (revision 6550d01e)
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