1 1.8 christos /* $NetBSD: btpin.c,v 1.8 2019/10/12 17:50:56 christos 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 * Written by Iain Hibbert for Itronix Inc. 8 1.1 gdamore * 9 1.1 gdamore * Redistribution and use in source and binary forms, with or without 10 1.1 gdamore * modification, are permitted provided that the following conditions 11 1.1 gdamore * are met: 12 1.1 gdamore * 1. Redistributions of source code must retain the above copyright 13 1.1 gdamore * notice, this list of conditions and the following disclaimer. 14 1.1 gdamore * 2. Redistributions in binary form must reproduce the above copyright 15 1.1 gdamore * notice, this list of conditions and the following disclaimer in the 16 1.1 gdamore * documentation and/or other materials provided with the distribution. 17 1.1 gdamore * 3. The name of Itronix Inc. may not be used to endorse 18 1.1 gdamore * or promote products derived from this software without specific 19 1.1 gdamore * prior written permission. 20 1.1 gdamore * 21 1.1 gdamore * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND 22 1.1 gdamore * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 23 1.1 gdamore * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 24 1.1 gdamore * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY 25 1.1 gdamore * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 26 1.1 gdamore * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 27 1.1 gdamore * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 28 1.1 gdamore * ON ANY THEORY OF LIABILITY, WHETHER IN 29 1.1 gdamore * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 1.1 gdamore * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 31 1.1 gdamore * POSSIBILITY OF SUCH DAMAGE. 32 1.1 gdamore */ 33 1.1 gdamore 34 1.1 gdamore #include <sys/cdefs.h> 35 1.4 lukem __COPYRIGHT("@(#) Copyright (c) 2006 Itronix, Inc. All rights reserved."); 36 1.8 christos __RCSID("$NetBSD: btpin.c,v 1.8 2019/10/12 17:50:56 christos Exp $"); 37 1.1 gdamore 38 1.1 gdamore #include <sys/types.h> 39 1.1 gdamore #include <sys/un.h> 40 1.1 gdamore #include <bluetooth.h> 41 1.1 gdamore #include <err.h> 42 1.5 plunky #include <errno.h> 43 1.1 gdamore #include <stdlib.h> 44 1.1 gdamore #include <string.h> 45 1.1 gdamore #include <time.h> 46 1.1 gdamore #include <unistd.h> 47 1.1 gdamore 48 1.6 joerg __dead static void usage(void); 49 1.1 gdamore 50 1.1 gdamore int 51 1.1 gdamore main(int ac, char *av[]) 52 1.1 gdamore { 53 1.2 plunky bthcid_pin_response_t rp; 54 1.1 gdamore struct sockaddr_un un; 55 1.5 plunky struct sockaddr_bt bt; 56 1.1 gdamore char *pin = NULL; 57 1.5 plunky int ch, s, len, pair; 58 1.1 gdamore 59 1.1 gdamore memset(&rp, 0, sizeof(rp)); 60 1.1 gdamore len = -1; 61 1.5 plunky pair = 0; 62 1.1 gdamore 63 1.1 gdamore memset(&un, 0, sizeof(un)); 64 1.1 gdamore un.sun_len = sizeof(un); 65 1.1 gdamore un.sun_family = AF_LOCAL; 66 1.1 gdamore strlcpy(un.sun_path, BTHCID_SOCKET_NAME, sizeof(un.sun_path)); 67 1.1 gdamore 68 1.5 plunky while ((ch = getopt(ac, av, "a:d:l:Pp:rs:")) != -1) { 69 1.1 gdamore switch (ch) { 70 1.1 gdamore case 'a': 71 1.1 gdamore if (!bt_aton(optarg, &rp.raddr)) { 72 1.1 gdamore struct hostent *he = NULL; 73 1.1 gdamore 74 1.1 gdamore if ((he = bt_gethostbyname(optarg)) == NULL) 75 1.1 gdamore errx(EXIT_FAILURE, "%s: %s", optarg, 76 1.1 gdamore hstrerror(h_errno)); 77 1.1 gdamore 78 1.1 gdamore bdaddr_copy(&rp.raddr, (bdaddr_t *)he->h_addr); 79 1.1 gdamore } 80 1.1 gdamore break; 81 1.1 gdamore 82 1.1 gdamore case 'd': 83 1.1 gdamore if (!bt_devaddr(optarg, &rp.laddr)) 84 1.1 gdamore err(EXIT_FAILURE, "%s", optarg); 85 1.1 gdamore 86 1.1 gdamore break; 87 1.1 gdamore 88 1.1 gdamore case 'l': 89 1.1 gdamore len = atoi(optarg); 90 1.1 gdamore if (len < 1 || len > HCI_PIN_SIZE) 91 1.1 gdamore errx(EXIT_FAILURE, "Invalid PIN length"); 92 1.1 gdamore 93 1.1 gdamore break; 94 1.1 gdamore 95 1.5 plunky case 'P': 96 1.5 plunky pair++; 97 1.5 plunky break; 98 1.5 plunky 99 1.1 gdamore case 'p': 100 1.1 gdamore pin = optarg; 101 1.1 gdamore break; 102 1.1 gdamore 103 1.1 gdamore case 'r': 104 1.1 gdamore if (len == -1) 105 1.1 gdamore len = 4; 106 1.1 gdamore 107 1.1 gdamore break; 108 1.1 gdamore 109 1.1 gdamore case 's': 110 1.1 gdamore strlcpy(un.sun_path, optarg, sizeof(un.sun_path)); 111 1.1 gdamore break; 112 1.1 gdamore 113 1.1 gdamore default: 114 1.1 gdamore usage(); 115 1.1 gdamore } 116 1.1 gdamore } 117 1.1 gdamore 118 1.1 gdamore if (bdaddr_any(&rp.raddr)) 119 1.1 gdamore usage(); 120 1.1 gdamore 121 1.1 gdamore if (pin == NULL) { 122 1.1 gdamore if (len == -1) 123 1.1 gdamore usage(); 124 1.1 gdamore 125 1.1 gdamore srandom(time(NULL)); 126 1.1 gdamore 127 1.1 gdamore pin = (char *)rp.pin; 128 1.1 gdamore while (len-- > 0) 129 1.1 gdamore *pin++ = '0' + (random() % 10); 130 1.1 gdamore 131 1.1 gdamore printf("PIN: %.*s\n", HCI_PIN_SIZE, rp.pin); 132 1.1 gdamore } else { 133 1.1 gdamore if (len != -1) 134 1.1 gdamore usage(); 135 1.8 christos len = strlen(pin); 136 1.8 christos if (len > HCI_PIN_SIZE) 137 1.8 christos len = HCI_PIN_SIZE; 138 1.1 gdamore 139 1.8 christos memcpy(rp.pin, pin, len); 140 1.1 gdamore } 141 1.1 gdamore 142 1.1 gdamore s = socket(PF_LOCAL, SOCK_STREAM, 0); 143 1.7 plunky if (s == -1) 144 1.1 gdamore err(EXIT_FAILURE, "socket"); 145 1.1 gdamore 146 1.7 plunky if (connect(s, (struct sockaddr *)&un, sizeof(un)) == -1) 147 1.1 gdamore err(EXIT_FAILURE, "connect(\"%s\")", un.sun_path); 148 1.1 gdamore 149 1.1 gdamore if (send(s, &rp, sizeof(rp), 0) != sizeof(rp)) 150 1.1 gdamore err(EXIT_FAILURE, "send"); 151 1.1 gdamore 152 1.1 gdamore close(s); 153 1.5 plunky 154 1.5 plunky if (pair == 0) 155 1.5 plunky exit(EXIT_SUCCESS); 156 1.5 plunky 157 1.5 plunky s = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP); 158 1.7 plunky if (s == -1) 159 1.5 plunky err(EXIT_FAILURE, "socket"); 160 1.5 plunky 161 1.5 plunky ch = L2CAP_LM_AUTH; 162 1.7 plunky if (setsockopt(s, BTPROTO_L2CAP, SO_L2CAP_LM, &ch, sizeof(ch)) == -1) 163 1.5 plunky err(EXIT_FAILURE, "SO_L2CAP_LM"); 164 1.5 plunky 165 1.5 plunky memset(&bt, 0, sizeof(bt)); 166 1.5 plunky bt.bt_len = sizeof(bt); 167 1.5 plunky bt.bt_family = AF_BLUETOOTH; 168 1.5 plunky bdaddr_copy(&bt.bt_bdaddr, &rp.laddr); 169 1.7 plunky if (bind(s, (struct sockaddr *)&bt, sizeof(bt)) == -1) 170 1.5 plunky err(EXIT_FAILURE, "bind"); 171 1.5 plunky 172 1.5 plunky fprintf(stdout, "Pairing.. "); 173 1.5 plunky fflush(stdout); 174 1.5 plunky 175 1.5 plunky bt.bt_psm = L2CAP_PSM_SDP; 176 1.5 plunky bdaddr_copy(&bt.bt_bdaddr, &rp.raddr); 177 1.7 plunky if (connect(s, (struct sockaddr *)&bt, sizeof(bt)) == -1) { 178 1.5 plunky fprintf(stdout, "failed (%s)\n", strerror(errno)); 179 1.5 plunky exit(EXIT_FAILURE); 180 1.5 plunky } 181 1.5 plunky 182 1.5 plunky close(s); 183 1.5 plunky fprintf(stdout, "done\n"); 184 1.5 plunky 185 1.1 gdamore exit(EXIT_SUCCESS); 186 1.1 gdamore } 187 1.1 gdamore 188 1.6 joerg static void 189 1.1 gdamore usage(void) 190 1.1 gdamore { 191 1.1 gdamore 192 1.1 gdamore fprintf(stderr, 193 1.5 plunky "usage: %s [-P] [-d device] [-s socket] {-p pin | -r [-l len]} -a addr\n" 194 1.1 gdamore "", getprogname()); 195 1.1 gdamore 196 1.1 gdamore exit(EXIT_FAILURE); 197 1.1 gdamore } 198