rpc.statd(8): Fix 2 cases where syslog() was passed too many args.
[dragonfly.git] / usr.sbin / bthcid / client.c
1 /* $NetBSD: client.c,v 1.4 2006/09/29 20:06:11 plunky Exp $ */
2 /* $DragonFly: src/usr.sbin/bthcid/client.c,v 1.1 2008/01/30 14:10:19 hasso Exp $ */
3
4 /*-
5  * Copyright (c) 2006 Itronix Inc.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. The name of Itronix Inc. may not be used to endorse
17  *    or promote products derived from this software without specific
18  *    prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY
24  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
25  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
27  * ON ANY THEORY OF LIABILITY, WHETHER IN
28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  * POSSIBILITY OF SUCH DAMAGE.
31  */
32
33 #include <sys/ioctl.h>
34 #include <sys/queue.h>
35 #include <sys/time.h>
36 #include <sys/un.h>
37 #include <bluetooth.h>
38 #include <errno.h>
39 #include <event.h>
40 #include <fcntl.h>
41 #include <stdlib.h>
42 #include <string.h>
43 #include <syslog.h>
44 #include <unistd.h>
45
46 #include "bthcid.h"
47
48 /*
49  * A client is anybody who connects to our control socket to
50  * receive PIN requests.
51  */
52 struct client {
53         struct event            ev;
54         int                     fd;             /* client descriptor */
55         LIST_ENTRY(client)      next;
56 };
57
58 /*
59  * PIN cache items are made when we have sent a client pin
60  * request. The event is used to expire the item.
61  */
62 struct item {
63         struct event     ev;
64         bdaddr_t         laddr;                 /* local device BDADDR */
65         bdaddr_t         raddr;                 /* remote device BDADDR */
66         uint8_t          pin[HCI_PIN_SIZE];     /* PIN */
67         int              hci;                   /* HCI socket */
68         LIST_ENTRY(item) next;
69 };
70
71 static struct event             control_ev;
72
73 static LIST_HEAD(,client)       client_list;
74 static LIST_HEAD(,item)         item_list;
75
76 static void process_control     (int, short, void *);
77 static void process_client      (int, short, void *);
78 static void process_item        (int, short, void *);
79
80 #define PIN_REQUEST_TIMEOUT     30      /* Request is valid */
81 #define PIN_TIMEOUT             300     /* PIN is valid */
82
83 int
84 init_control(const char *name, mode_t mode)
85 {
86         struct sockaddr_un      un;
87         int                     ctl;
88
89         LIST_INIT(&client_list);
90         LIST_INIT(&item_list);
91
92         if (name == NULL)
93                 return 0;
94
95         if (unlink(name) < 0 && errno != ENOENT)
96                 return -1;
97
98         ctl = socket(PF_LOCAL, SOCK_STREAM, 0);
99         if (ctl < 0)
100                 return -1;
101
102         memset(&un, 0, sizeof(un));
103         un.sun_len = sizeof(un);
104         un.sun_family = AF_LOCAL;
105         strlcpy(un.sun_path, name, sizeof(un.sun_path));
106         if (bind(ctl, (struct sockaddr *)&un, sizeof(un)) < 0) {
107                 close(ctl);
108                 return -1;
109         }
110
111         if (chmod(name, mode) < 0) {
112                 close(ctl);
113                 unlink(name);
114                 return -1;
115         }
116
117         if (listen(ctl, 10) < 0) {
118                 close(ctl);
119                 unlink(name);
120                 return -1;
121         }
122
123         event_set(&control_ev, ctl, EV_READ | EV_PERSIST, process_control, NULL);
124         if (event_add(&control_ev, NULL) < 0) {
125                 close(ctl);
126                 unlink(name);
127                 return -1;
128         }
129
130         return 0;
131 }
132
133 /* Process control socket event */
134 static void
135 process_control(int sock, short ev, void *arg)
136 {
137         struct sockaddr_un      un;
138         socklen_t               n;
139         int                     fd;
140         struct client           *cl;
141
142         n = sizeof(un);
143         fd = accept(sock, (struct sockaddr *)&un, &n);
144         if (fd < 0) {
145                 syslog(LOG_ERR, "Could not accept PIN client connection");
146                 return;
147         }
148
149         n = 1;
150         if (ioctl(fd, FIONBIO, &n) < 0) {
151                 syslog(LOG_ERR, "Could not set non blocking IO for client");
152                 close(fd);
153                 return;
154         }
155
156         cl = malloc(sizeof(struct client));
157         if (cl == NULL) {
158                 syslog(LOG_ERR, "Could not malloc client");
159                 close(fd);
160                 return;
161         }
162
163         memset(cl, 0, sizeof(struct client));
164         cl->fd = fd;
165
166         event_set(&cl->ev, fd, EV_READ | EV_PERSIST, process_client, cl);
167         if (event_add(&cl->ev, NULL) < 0) {
168                 syslog(LOG_ERR, "Could not add client event");
169                 free(cl);
170                 close(fd);
171                 return;
172         }
173
174         syslog(LOG_DEBUG, "New Client");
175         LIST_INSERT_HEAD(&client_list, cl, next);
176 }
177
178 /* Process client response packet */
179 static void
180 process_client(int sock, short ev, void *arg)
181 {
182         bthcid_pin_response_t    rp;
183         struct timeval           tv;
184         struct sockaddr_bt       sa;
185         struct client           *cl = arg;
186         struct item             *item;
187         int                      n;
188
189         n = recv(sock, &rp, sizeof(rp), 0);
190         if (n != sizeof(rp)) {
191                 if (n != 0)
192                         syslog(LOG_ERR, "Bad Client");
193
194                 close(sock);
195                 LIST_REMOVE(cl, next);
196                 free(cl);
197
198                 syslog(LOG_DEBUG, "Client Closed");
199                 return;
200         }
201
202         syslog(LOG_DEBUG, "Received PIN for %s", bt_ntoa(&rp.raddr, NULL));
203
204         LIST_FOREACH(item, &item_list, next) {
205                 if (bdaddr_same(&rp.laddr, &item->laddr) == 0
206                     || bdaddr_same(&rp.raddr, &item->raddr) == 0)
207                         continue;
208
209                 evtimer_del(&item->ev);
210                 if (item->hci != -1) {
211                         memset(&sa, 0, sizeof(sa));
212                         sa.bt_len = sizeof(sa);
213                         sa.bt_family = AF_BLUETOOTH;
214                         bdaddr_copy(&sa.bt_bdaddr, &item->laddr);
215
216                         send_pin_code_reply(item->hci, &sa, &item->raddr, rp.pin);
217                         LIST_REMOVE(item, next);
218                         free(item);
219                         return;
220                 }
221                 goto newpin;
222         }
223
224         item = malloc(sizeof(struct item));
225         if (item == NULL) {
226                 syslog(LOG_ERR, "Item allocation failed");
227                 return;
228         }
229
230         memset(item, 0, sizeof(struct item));
231         bdaddr_copy(&item->laddr, &rp.laddr);
232         bdaddr_copy(&item->raddr, &rp.raddr);
233         evtimer_set(&item->ev, process_item, item);
234         LIST_INSERT_HEAD(&item_list, item, next);
235
236 newpin:
237         syslog(LOG_DEBUG, "Caching PIN for %s", bt_ntoa(&rp.raddr, NULL));
238
239         memcpy(item->pin, rp.pin, HCI_PIN_SIZE);
240         item->hci = -1;
241
242         tv.tv_sec = PIN_TIMEOUT;
243         tv.tv_usec = 0;
244
245         if (evtimer_add(&item->ev, &tv) < 0) {
246                 syslog(LOG_ERR, "Cannot add event timer for item");
247                 LIST_REMOVE(item, next);
248                 free(item);
249         }
250 }
251
252 /* Send PIN request to client */
253 int
254 send_client_request(bdaddr_t *laddr, bdaddr_t *raddr, int hci)
255 {
256         bthcid_pin_request_t     cp;
257         struct client           *cl;
258         struct item             *item;
259         int                      n = 0;
260         struct timeval           tv;
261
262         memset(&cp, 0, sizeof(cp));
263         bdaddr_copy(&cp.laddr, laddr);
264         bdaddr_copy(&cp.raddr, raddr);
265         cp.time = PIN_REQUEST_TIMEOUT;
266
267         LIST_FOREACH(cl, &client_list, next) {
268                 if (send(cl->fd, &cp, sizeof(cp), 0) != sizeof(cp))
269                         syslog(LOG_ERR, "send PIN request failed");
270                 else
271                         n++;
272         }
273
274         if (n == 0)
275                 return 0;
276
277         syslog(LOG_DEBUG, "Sent PIN requests to %d client%s.",
278                                 n, (n == 1 ? "" : "s"));
279
280         item = malloc(sizeof(struct item));
281         if (item == NULL) {
282                 syslog(LOG_ERR, "Cannot allocate PIN request item");
283                 return 0;
284         }
285
286         memset(item, 0, sizeof(struct item));
287         bdaddr_copy(&item->laddr, laddr);
288         bdaddr_copy(&item->raddr, raddr);
289         item->hci = hci;
290         evtimer_set(&item->ev, process_item, item);
291
292         tv.tv_sec = cp.time;
293         tv.tv_usec = 0;
294
295         if (evtimer_add(&item->ev, &tv) < 0) {
296                 syslog(LOG_ERR, "Cannot add request timer");
297                 free(item);
298                 return 0;
299         }
300
301         LIST_INSERT_HEAD(&item_list, item, next);
302         return 1;
303 }
304
305 /* Process item event (by expiring it) */
306 static void
307 process_item(int fd, short ev, void *arg)
308 {
309         struct item *item = arg;
310
311         syslog(LOG_DEBUG, "PIN for %s expired", bt_ntoa(&item->raddr, NULL));
312         LIST_REMOVE(item, next);
313         evtimer_del(&item->ev);
314         free(item);
315 }
316
317 /* lookup PIN in item cache */
318 uint8_t *
319 lookup_pin(bdaddr_t *laddr, bdaddr_t *raddr)
320 {
321         static uint8_t pin[HCI_PIN_SIZE];
322         struct item *item;
323
324         LIST_FOREACH(item, &item_list, next) {
325                 if (bdaddr_same(raddr, &item->raddr) == 0)
326                         continue;
327
328                 if (bdaddr_same(laddr, &item->laddr) == 0
329                     && bdaddr_any(&item->laddr) == 0)
330                         continue;
331
332                 if (item->hci >= 0)
333                         break;
334
335                 syslog(LOG_DEBUG, "Matched PIN from cache");
336                 memcpy(pin, item->pin, sizeof(pin));
337
338                 LIST_REMOVE(item, next);
339                 evtimer_del(&item->ev);
340                 free(item);
341
342                 return pin;
343         }
344
345         return NULL;
346 }