Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 6 Jun 2003 10:21:22 -0700 (PDT)
From:      Maksim Yevmenkin <m_evmenkin@yahoo.com>
To:        mobile@freebsd.org, current@freebsd.org
Subject:   [PATCH] hcsecd(8) Bluetooth link keys/PIN codes management daemon
Message-ID:  <20030606172122.65380.qmail@web40308.mail.yahoo.com>

next in thread | raw e-mail | index | archive | help

[-- Attachment #1 --]
Dear Hackers,

please find attached patch for the hcsecd(8) Bluetooth link keys/PIN
codes management daemon. this patch is against the latest release

http://www.geocities.com/m_evmenkin/ngbt-fbsd-20030604.tar.gz

hcsecd(8) is now able to cache link keys that were generated from the
PIN codes. to preserve link keys between restarts hcsecd(8) will dump
links keys on disk and read them upon next start.

this functionality is required to implement link keys database for
'paired' devices. in particular one can now 'pair' cell phone and PC 
(with PIN code) and both sides will store the link key. in the future
the cell the phone can accept incoming connection from the PC without
being put into 'discoverable' mode. ('discoverable' mode is when the
cell phone answers inquiry).

note that hcsecd(8) must be running all the time, otherwise cell phone
will not be able to receive link key and will 'forget' PC on next
connection attempt. if this happens 'paring' procedure must be repeated.

i would like to thank Alex <alex@greenlight.ru> for reporting this
problem and helping with testing.

thanks,
max

__________________________________
Do you Yahoo!?
Yahoo! Calendar - Free online calendar with sync to Outlook(TM).
http://calendar.yahoo.com
[-- Attachment #2 --]
Index: hcsecd.8
===================================================================
RCS file: /usr/local/cvs/usr.sbin/bluetooth/hcsecd/hcsecd.8,v
retrieving revision 1.5
diff -u -r1.5 hcsecd.8
--- hcsecd.8	26 May 2003 22:49:22 -0000	1.5
+++ hcsecd.8	6 Jun 2003 00:37:10 -0000
@@ -38,22 +38,28 @@
 .Sh DESCRIPTION
 The
 .Nm
-daemon controls link keys and PIN code for Bluetooth devices.
+daemon controls link keys and PIN codes for Bluetooth devices.
 It opens raw HCI socket and listens for the
-.Dv Link_Key_Request
-and
+.Dv Link_Key_Request ,
 .Dv PIN_Code_Request
+and
+.Dv Link_Key_Notification
 HCI events.
-Once appropriate HCI event has been received, the daemon will
+.Pp
+Once 
+.Dv Link_Key_Request
+or
+.Dv PIN_Code_Request
+HCI event is received, the daemon will
 scan configuration file for matching entry.
-The remove device BD_ADDR is used as a key.
+The remote device BD_ADDR is used as a key.
 If no matching entry was found, the default entry will be used.
-If no default entry was found then it is assumed that no link key and no PIN code
-exist.
+If no default entry was found then it is assumed that no link key and no 
+PIN code exists.
 For any given entry, link key takes precedence over PIN code.
 If link key was not specified, it means device must generate link key from
 PIN code.
-If entry was found and has the link key (or PIN code) then the
+If entry was found and the link key (or PIN code) exists then the
 .Dv Link_Key_Request_Reply
 (or
 .Dv PIN_Code_Request_Reply )
@@ -66,12 +72,28 @@
 .Pp
 The
 .Nm
-daemon currently does not handle HCI
+daemon also handles HCI
 .Dv Link_Key_Notification
-event and does not cache link keys created from the PIN codes.
-It means that the link key only exists while connection is opened.
-After the connection has been terminated, the user will have to enter PIN code
-again.
+event and caches link keys created from the PIN codes in the memory.
+To preserve link keys between restarts the
+.Nm
+daemon dumps link keys for all entries in the
+.Pa /var/run/hcsecd.keys
+link keys file.
+If exists, the link keys file gets processed by
+.Nm
+daemon after it processes its main configuration file.
+The link keys file gets written every time
+.Nm
+daemon is gracefully shutdown.
+It is possible to force
+.Nm
+daemon to re-read its main configuration file and dump link keys file by sending
+.Dv HUP
+signal to the
+.Nm
+process.
+User is not expected to modify link keys file by hand.
 .Pp
 The command line options are as follows:
 .Bl -tag -width indent
@@ -94,12 +116,12 @@
 .Bl -tag -width ".Pa /etc/bluetooth/hcsecd.conf" -compact
 .It Pa /etc/bluetooth/hcsecd.conf
 .It Pa /var/run/hcsecd.pid
+.It Pa /var/run/hcsecd.keys
 .El
 .Sh SEE ALSO
-.Xr netgraph 3 ,
-.Xr netgraph 4 ,
 .Xr ng_btsocket 4 ,
 .Xr ng_hci 4 ,
+.Xr hcsecd.conf 5 ,
 .Xr hccontrol 8 ,
 .Xr hcseriald 8
 .Sh AUTHORS
Index: hcsecd.c
===================================================================
RCS file: /usr/local/cvs/usr.sbin/bluetooth/hcsecd/hcsecd.c,v
retrieving revision 1.4
diff -u -r1.4 hcsecd.c
--- hcsecd.c	21 May 2003 22:40:31 -0000	1.4
+++ hcsecd.c	5 Jun 2003 20:56:47 -0000
@@ -43,10 +43,6 @@
 #include <unistd.h>
 #include "hcsecd.h"
 
-#define	HCSECD_BUFFER_SIZE	512
-#define	HCSECD_IDENT		"hcsecd"
-#define	HCSECD_PIDFILE		"/var/run/" HCSECD_IDENT ".pid"
-
 static int	done = 0;
 
 static int process_pin_code_request_event
@@ -57,6 +53,10 @@
 	(int sock, struct sockaddr_hci *addr, bdaddr_p bdaddr, char const *pin);
 static int send_link_key_reply
 	(int sock, struct sockaddr_hci *addr, bdaddr_p bdaddr, u_int8_t *key);
+static int process_link_key_notification_event
+	(int sock, struct sockaddr_hci *addr, ng_hci_link_key_notification_ep *ep);
+static void sighup
+	(int s);
 static void sigint
 	(int s);
 static void usage
@@ -110,7 +110,7 @@
 		err(1, "Could not sigaction(SIGINT)");
 
 	memset(&sa, 0, sizeof(sa));
-	sa.sa_handler = read_config_file;
+	sa.sa_handler = sighup;
 	if (sigaction(SIGHUP, &sa, NULL) < 0)
 		err(1, "Could not sigaction(SIGHUP)");
 
@@ -122,6 +122,7 @@
 	memset(&filter, 0, sizeof(filter));
 	bit_set(filter.event_mask, NG_HCI_EVENT_PIN_CODE_REQ - 1);
 	bit_set(filter.event_mask, NG_HCI_EVENT_LINK_KEY_REQ - 1);
+	bit_set(filter.event_mask, NG_HCI_EVENT_LINK_KEY_NOTIFICATION - 1);
 
 	if (setsockopt(sock, SOL_HCI_RAW, SO_HCI_RAW_FILTER,
 			(void * const) &filter, sizeof(filter)) < 0)
@@ -133,7 +134,8 @@
 
 	openlog(HCSECD_IDENT, LOG_NDELAY|LOG_PERROR|LOG_PID, LOG_DAEMON);
 
-	read_config_file(0);
+	read_config_file();
+	read_keys_file();
 
 	if (detach) {
 		FILE	*pid = NULL;
@@ -179,6 +181,11 @@
 							(bdaddr_p)(event + 1));
 			break;
 
+		case NG_HCI_EVENT_LINK_KEY_NOTIFICATION:
+			process_link_key_notification_event(sock, &addr,
+				(ng_hci_link_key_notification_ep *)(event + 1));
+			break;
+
 		default:
 			syslog(LOG_ERR, "Received unexpected HCI event, " \
 					"event=%#x", event->event);
@@ -191,6 +198,7 @@
 			syslog(LOG_ERR, "Could not remove PID file %s. %s (%d)",
 					HCSECD_PIDFILE, strerror(errno), errno);
 
+	dump_keys_file();
 	clean_config();
 	closelog();
 	close(sock);
@@ -206,27 +214,21 @@
 	link_key_p	key = NULL;
 
 	syslog(LOG_DEBUG, "Got PIN_Code_Request event from '%s', " \
-			"remote bdaddr %x:%x:%x:%x:%x:%x", addr->hci_node,
-			bdaddr->b[5], bdaddr->b[4], bdaddr->b[3],
-			bdaddr->b[2], bdaddr->b[1], bdaddr->b[0]);
+			"remote bdaddr %s", addr->hci_node,
+			bt_ntoa(bdaddr, NULL));
 
 	if ((key = get_key(bdaddr, 0)) != NULL) {
 		syslog(LOG_DEBUG, "Found matching entry, " \
-				"remote bdaddr %x:%x:%x:%x:%x:%x, name '%s', " \
-				"PIN code %s",
-				key->bdaddr.b[5], key->bdaddr.b[4],
-				key->bdaddr.b[3], key->bdaddr.b[2],
-				key->bdaddr.b[1], key->bdaddr.b[0],
+				"remote bdaddr %s, name '%s', PIN code %s",
+				bt_ntoa(&key->bdaddr, NULL),
 				(key->name != NULL)? key->name : "No name",
 				(key->pin != NULL)? "exists" : "doesn't exist");
 
 		return (send_pin_code_reply(sock, addr, bdaddr, key->pin));
 	}
 
-	syslog(LOG_DEBUG, "Could not PIN code for remote bdaddr " \
-			"%x:%x:%x:%x:%x:%x",
-			bdaddr->b[5], bdaddr->b[4], bdaddr->b[3],
-			bdaddr->b[2], bdaddr->b[1], bdaddr->b[0]);
+	syslog(LOG_DEBUG, "Could not PIN code for remote bdaddr %s",
+			bt_ntoa(bdaddr, NULL));
 
 	return (send_pin_code_reply(sock, addr, bdaddr, NULL));
 }
@@ -239,27 +241,21 @@
 	link_key_p	key = NULL;
 
 	syslog(LOG_DEBUG, "Got Link_Key_Request event from '%s', " \
-			"remote bdaddr %x:%x:%x:%x:%x:%x", addr->hci_node,
-			bdaddr->b[5], bdaddr->b[4], bdaddr->b[3],
-			bdaddr->b[2], bdaddr->b[1], bdaddr->b[0]);
+			"remote bdaddr %s", addr->hci_node,
+			bt_ntoa(bdaddr, NULL));
 
 	if ((key = get_key(bdaddr, 0)) != NULL) {
 		syslog(LOG_DEBUG, "Found matching entry, " \
-				"remote bdaddr %x:%x:%x:%x:%x:%x, name '%s', " \
-				"link key %s",
-				key->bdaddr.b[5], key->bdaddr.b[4],
-				key->bdaddr.b[3], key->bdaddr.b[2],
-				key->bdaddr.b[1], key->bdaddr.b[0],
+				"remote bdaddr %s, name '%s', link key %s",
+				bt_ntoa(&key->bdaddr, NULL),
 				(key->name != NULL)? key->name : "No name",
 				(key->key != NULL)? "exists" : "doesn't exist");
 
 		return (send_link_key_reply(sock, addr, bdaddr, key->key));
 	}
 
-	syslog(LOG_DEBUG, "Could not find link key for remote bdaddr " \
-			"%x:%x:%x:%x:%x:%x",
-			bdaddr->b[5], bdaddr->b[4], bdaddr->b[3],
-			bdaddr->b[2], bdaddr->b[1], bdaddr->b[0]);
+	syslog(LOG_DEBUG, "Could not find link key for remote bdaddr %s",
+			bt_ntoa(bdaddr, NULL));
 
 	return (send_link_key_reply(sock, addr, bdaddr, NULL));
 }
@@ -290,10 +286,8 @@
 		cp->pin_size = strlen(cp->pin);
 
 		syslog(LOG_DEBUG, "Sending PIN_Code_Reply to '%s' " \
-				"for remote bdaddr %x:%x:%x:%x:%x:%x",
-				addr->hci_node,
-				bdaddr->b[5], bdaddr->b[4], bdaddr->b[3], 
-				bdaddr->b[2], bdaddr->b[1], bdaddr->b[0]);
+				"for remote bdaddr %s",
+				addr->hci_node, bt_ntoa(bdaddr, NULL));
 	} else {
 		ng_hci_pin_code_neg_rep_cp	*cp = NULL;
 
@@ -305,10 +299,8 @@
 		memcpy(&cp->bdaddr, bdaddr, sizeof(cp->bdaddr));
 
 		syslog(LOG_DEBUG, "Sending PIN_Code_Negative_Reply to '%s' " \
-				"for remote bdaddr %x:%x:%x:%x:%x:%x",
-				addr->hci_node,
-				bdaddr->b[5], bdaddr->b[4], bdaddr->b[3], 
-				bdaddr->b[2], bdaddr->b[1], bdaddr->b[0]);
+				"for remote bdaddr %s",
+				addr->hci_node, bt_ntoa(bdaddr, NULL));
 	}
 
 again:
@@ -318,10 +310,8 @@
 			goto again;
 
 		syslog(LOG_ERR, "Could not send PIN code reply to '%s' " \
-				"for remote bdaddr %x:%x:%x:%x:%x:%x. %s (%d)",
-				addr->hci_node,
-				bdaddr->b[5], bdaddr->b[4], bdaddr->b[3], 
-				bdaddr->b[2], bdaddr->b[1], bdaddr->b[0],
+				"for remote bdaddr %s. %s (%d)",
+				addr->hci_node, bt_ntoa(bdaddr, NULL),
 				strerror(errno), errno);
 		return (-1);
 	}
@@ -354,10 +344,8 @@
 		memcpy(&cp->key, key, sizeof(cp->key));
 
 		syslog(LOG_DEBUG, "Sending Link_Key_Reply to '%s' " \
-				"for remote bdaddr %x:%x:%x:%x:%x:%x",
-				addr->hci_node,
-				bdaddr->b[5], bdaddr->b[4], bdaddr->b[3], 
-				bdaddr->b[2], bdaddr->b[1], bdaddr->b[0]);
+				"for remote bdaddr %s",
+				addr->hci_node, bt_ntoa(bdaddr, NULL));
 	} else {
 		ng_hci_link_key_neg_rep_cp	*cp = NULL;
 
@@ -369,10 +357,8 @@
 		memcpy(&cp->bdaddr, bdaddr, sizeof(cp->bdaddr));
 
 		syslog(LOG_DEBUG, "Sending Link_Key_Negative_Reply to '%s' " \
-				"for remote bdaddr %x:%x:%x:%x:%x:%x",
-				addr->hci_node,
-				bdaddr->b[5], bdaddr->b[4], bdaddr->b[3], 
-				bdaddr->b[2], bdaddr->b[1], bdaddr->b[0]);
+				"for remote bdaddr %s",
+				addr->hci_node, bt_ntoa(bdaddr, NULL));
 	}
 
 again:
@@ -382,10 +368,8 @@
 			goto again;
 
 		syslog(LOG_ERR, "Could not send link key reply to '%s' " \
-				"for remote bdaddr %x:%x:%x:%x:%x:%x. %s (%d)",
-				addr->hci_node,
-				bdaddr->b[5], bdaddr->b[4], bdaddr->b[3], 
-				bdaddr->b[2], bdaddr->b[1], bdaddr->b[0],
+				"for remote bdaddr %s. %s (%d)",
+				addr->hci_node, bt_ntoa(bdaddr, NULL),
 				strerror(errno), errno);
 		return (-1);
 	}
@@ -393,7 +377,53 @@
 	return (0);
 }
 
-/* Signal handler */
+/* Process Link_Key_Notification event */
+static int
+process_link_key_notification_event(int sock, struct sockaddr_hci *addr,
+		ng_hci_link_key_notification_ep *ep)
+{
+	link_key_p	key = NULL;
+
+	syslog(LOG_DEBUG, "Got Link_Key_Notification event from '%s', " \
+			"remote bdaddr %s", addr->hci_node,
+			bt_ntoa(&ep->bdaddr, NULL));
+
+	if ((key = get_key(&ep->bdaddr, 1)) == NULL) {
+		syslog(LOG_ERR, "Could not find entry for remote bdaddr %s",
+				bt_ntoa(&ep->bdaddr, NULL));
+		return (-1);
+	}
+
+	syslog(LOG_DEBUG, "Updating link key for the entry, " \
+			"remote bdaddr %s, name '%s', link key %s",
+			bt_ntoa(&key->bdaddr, NULL),
+			(key->name != NULL)? key->name : "No name",
+			(key->key != NULL)? "exists" : "doesn't exist");
+
+	if (key->key == NULL) {
+		key->key = (u_int8_t *) malloc(NG_HCI_KEY_SIZE);
+		if (key->key == NULL) {
+			syslog(LOG_ERR, "Could not allocate link key");
+			exit(1);
+		}
+	}
+
+	memcpy(key->key, &ep->key, NG_HCI_KEY_SIZE);
+
+	return (0);
+}
+
+/* Signal handlers */
+static void
+sighup(int s)
+{
+	syslog(LOG_DEBUG, "Got SIGHUP (%d)", s);
+
+	dump_keys_file();
+	read_config_file();
+	read_keys_file();
+}
+
 static void
 sigint(int s)
 {
Index: hcsecd.h
===================================================================
RCS file: /usr/local/cvs/usr.sbin/bluetooth/hcsecd/hcsecd.h,v
retrieving revision 1.1
diff -u -r1.1 hcsecd.h
--- hcsecd.h	24 Nov 2002 20:22:39 -0000	1.1
+++ hcsecd.h	5 Jun 2003 20:52:50 -0000
@@ -32,6 +32,11 @@
 #ifndef _HCSECD_H_
 #define _HCSECD_H_ 1
 
+#define HCSECD_BUFFER_SIZE	512
+#define HCSECD_IDENT		"hcsecd"
+#define HCSECD_PIDFILE		"/var/run/" HCSECD_IDENT ".pid"
+#define HCSECD_KEYSFILE		"/var/run/" HCSECD_IDENT ".keys"
+
 struct link_key
 {
 	bdaddr_t		 bdaddr; /* remote device BDADDR */
@@ -49,9 +54,12 @@
 void		dump_config	(void);
 #endif
 
-void		read_config_file(int s);
+void		read_config_file(void);
 void		clean_config	(void);
 link_key_p	get_key		(bdaddr_p bdaddr, int exact_match);
+
+int		read_keys_file  (void);
+int		dump_keys_file  (void);
 
 #endif /* ndef _HCSECD_H_ */
 
Index: parser.y
===================================================================
RCS file: /usr/local/cvs/usr.sbin/bluetooth/hcsecd/parser.y,v
retrieving revision 1.4
diff -u -r1.4 parser.y
--- parser.y	26 May 2003 23:03:39 -0000	1.4
+++ parser.y	6 Jun 2003 00:28:16 -0000
@@ -30,9 +30,11 @@
  * $FreeBSD$
  */
 
+#include <sys/fcntl.h>
 #include <sys/queue.h>
 #include <bluetooth.h>
 #include <errno.h>
+#include <limits.h>
 #include <stdio.h>
 #include <stdarg.h>
 #include <string.h>
@@ -81,13 +83,8 @@
 			{
 			if (get_key(&key->bdaddr, 1) != NULL) {
 				syslog(LOG_ERR, "Ignoring duplicated entry " \
-						"for bdaddr %x:%x:%x:%x:%x:%x",
-						key->bdaddr.b[5],
-						key->bdaddr.b[4],
-						key->bdaddr.b[3],
-						key->bdaddr.b[2],
-						key->bdaddr.b[1],
-						key->bdaddr.b[0]);
+						"for bdaddr %s",
+						bt_ntoa(&key->bdaddr, NULL));
 				free_key(key);
 			} else 
 				LIST_INSERT_HEAD(&link_keys, key, next);
@@ -194,7 +191,7 @@
 
 /* Re-read config file */
 void
-read_config_file(int s)
+read_config_file(void)
 {
 	extern FILE	*yyin;
 
@@ -285,6 +282,114 @@
 	}
 }
 #endif
+
+/* Read keys file */
+int
+read_keys_file(void)
+{
+	FILE		*f = NULL;
+	link_key_t	*key = NULL;
+	char		 buf[HCSECD_BUFFER_SIZE], *p = NULL, *cp = NULL;
+	bdaddr_t	 bdaddr;
+	int		 i, len;
+
+	if ((f = fopen(HCSECD_KEYSFILE, "r")) == NULL) {
+		if (errno == ENOENT)
+			return (0);
+
+		syslog(LOG_ERR, "Could not open keys file %s. %s (%d)\n",
+				HCSECD_KEYSFILE, strerror(errno), errno);
+
+		return (-1);
+	}
+
+	while ((p = fgets(buf, sizeof(buf), f)) != NULL) {
+		if (*p == '#')
+			continue;
+		if ((cp = strpbrk(p, " ")) == NULL)
+			continue;
+
+		*cp++ = '\0';
+
+		if (!bt_aton(p, &bdaddr))
+			continue;
+
+		if ((key = get_key(&bdaddr, 1)) == NULL)
+			continue;
+
+		if (key->key == NULL) {
+			key->key = (u_int8_t *) malloc(NG_HCI_KEY_SIZE);
+			if (key->key == NULL) {
+				syslog(LOG_ERR, "Could not allocate link key");
+				exit(1);
+			}
+		}
+
+		memset(key->key, 0, NG_HCI_KEY_SIZE);
+
+		len = strlen(cp) / 2;
+		if (len > NG_HCI_KEY_SIZE)
+			len = NG_HCI_KEY_SIZE;
+
+		for (i = 0; i < len; i ++)
+			key->key[i] = hexa2int8(cp + 2*i);
+
+		syslog(LOG_DEBUG, "Restored link key for the entry, " \
+				"remote bdaddr %s, name '%s'",
+				bt_ntoa(&key->bdaddr, NULL),
+				(key->name != NULL)? key->name : "No name");
+	}
+
+	fclose(f);
+
+	return (0);
+}
+
+/* Dump keys file */
+int
+dump_keys_file(void)
+{
+	link_key_p	key = NULL;
+	char		tmp[PATH_MAX], buf[HCSECD_BUFFER_SIZE];
+	int		f;
+
+	snprintf(tmp, sizeof(tmp), "%s.tmp", HCSECD_KEYSFILE);
+	if ((f = open(tmp, O_RDWR|O_CREAT|O_TRUNC|O_EXCL, 0600)) < 0) {
+		syslog(LOG_ERR, "Could not create temp keys file %s. %s (%d)\n",
+				tmp, strerror(errno), errno);
+		return (-1);
+	}
+
+	LIST_FOREACH(key, &link_keys, next) {
+		if (key->key == NULL)
+			continue;
+
+		snprintf(buf, sizeof(buf),
+"%s %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n",
+			bt_ntoa(&key->bdaddr, NULL),
+			key->key[0],  key->key[1],  key->key[2],  key->key[3],
+			key->key[4],  key->key[5],  key->key[6],  key->key[7],
+			key->key[8],  key->key[9],  key->key[10], key->key[11],
+			key->key[12], key->key[13], key->key[14], key->key[15]);
+
+		if (write(f, buf, strlen(buf)) < 0) {
+			syslog(LOG_ERR, "Could not write temp keys file. " \
+					"%s (%d)\n", strerror(errno), errno);
+			break;
+		}
+	}
+
+	close(f);
+
+	if (rename(tmp, HCSECD_KEYSFILE) < 0) {
+		syslog(LOG_ERR, "Could not rename(%s, %s). %s (%d)\n",
+				tmp, HCSECD_KEYSFILE, strerror(errno), errno);
+		unlink(tmp);
+		return (-1);
+	}
+
+	return (0);
+}
 
 /* Free key entry */
 static void

Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20030606172122.65380.qmail>