xref: /freebsd/usr.sbin/bluetooth/hcsecd/parser.y (revision 1de7b4b805ddbf2429da511c053686ac4591ed89)
11a63eb31SJulian Elischer %{
2*1de7b4b8SPedro F. Giffuni /*-
31a63eb31SJulian Elischer  * parser.y
41a63eb31SJulian Elischer  *
5*1de7b4b8SPedro F. Giffuni  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
6*1de7b4b8SPedro F. Giffuni  *
71a63eb31SJulian Elischer  * Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
81a63eb31SJulian Elischer  * All rights reserved.
91a63eb31SJulian Elischer  *
101a63eb31SJulian Elischer  * Redistribution and use in source and binary forms, with or without
111a63eb31SJulian Elischer  * modification, are permitted provided that the following conditions
121a63eb31SJulian Elischer  * are met:
131a63eb31SJulian Elischer  * 1. Redistributions of source code must retain the above copyright
141a63eb31SJulian Elischer  *    notice, this list of conditions and the following disclaimer.
151a63eb31SJulian Elischer  * 2. Redistributions in binary form must reproduce the above copyright
161a63eb31SJulian Elischer  *    notice, this list of conditions and the following disclaimer in the
171a63eb31SJulian Elischer  *    documentation and/or other materials provided with the distribution.
181a63eb31SJulian Elischer  *
191a63eb31SJulian Elischer  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
201a63eb31SJulian Elischer  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
211a63eb31SJulian Elischer  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
221a63eb31SJulian Elischer  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
231a63eb31SJulian Elischer  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
241a63eb31SJulian Elischer  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
251a63eb31SJulian Elischer  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
261a63eb31SJulian Elischer  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
271a63eb31SJulian Elischer  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
281a63eb31SJulian Elischer  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
291a63eb31SJulian Elischer  * SUCH DAMAGE.
301a63eb31SJulian Elischer  *
310986ab12SMaksim Yevmenkin  * $Id: parser.y,v 1.5 2003/06/07 21:22:30 max Exp $
321a63eb31SJulian Elischer  * $FreeBSD$
331a63eb31SJulian Elischer  */
341a63eb31SJulian Elischer 
350986ab12SMaksim Yevmenkin #include <sys/fcntl.h>
361a63eb31SJulian Elischer #include <sys/queue.h>
378d6f425dSTakanori Watanabe #define L2CAP_SOCKET_CHECKED
380986ab12SMaksim Yevmenkin #include <bluetooth.h>
391a63eb31SJulian Elischer #include <errno.h>
400986ab12SMaksim Yevmenkin #include <limits.h>
411a63eb31SJulian Elischer #include <stdio.h>
425e2a209aSBaptiste Daroussin #include <stdlib.h>
431a63eb31SJulian Elischer #include <stdarg.h>
441a63eb31SJulian Elischer #include <string.h>
451a63eb31SJulian Elischer #include <syslog.h>
468dc77a61SMaksim Yevmenkin #include <unistd.h>
471a63eb31SJulian Elischer #include "hcsecd.h"
481a63eb31SJulian Elischer 
491a63eb31SJulian Elischer 	int	yyparse  (void);
501a63eb31SJulian Elischer 	int	yylex    (void);
511a63eb31SJulian Elischer 
521a63eb31SJulian Elischer static	void	free_key (link_key_p key);
531a63eb31SJulian Elischer static	int	hexa2int4(char *a);
541a63eb31SJulian Elischer static	int	hexa2int8(char *a);
551a63eb31SJulian Elischer 
561a63eb31SJulian Elischer extern	int			 yylineno;
571a63eb31SJulian Elischer static	LIST_HEAD(, link_key)	 link_keys;
580986ab12SMaksim Yevmenkin 	char			*config_file = "/etc/bluetooth/hcsecd.conf";
591a63eb31SJulian Elischer 
601a63eb31SJulian Elischer static	link_key_p		 key = NULL;
611a63eb31SJulian Elischer %}
621a63eb31SJulian Elischer 
631a63eb31SJulian Elischer %union {
641a63eb31SJulian Elischer 	char	*string;
651a63eb31SJulian Elischer }
661a63eb31SJulian Elischer 
671a63eb31SJulian Elischer %token <string> T_BDADDRSTRING T_HEXSTRING T_STRING
681a63eb31SJulian Elischer %token T_DEVICE T_BDADDR T_NAME T_KEY T_PIN T_NOKEY T_NOPIN T_JUNK
691a63eb31SJulian Elischer 
701a63eb31SJulian Elischer %%
711a63eb31SJulian Elischer 
721a63eb31SJulian Elischer config:		line
731a63eb31SJulian Elischer 		| config line
741a63eb31SJulian Elischer 		;
751a63eb31SJulian Elischer 
761a63eb31SJulian Elischer line:		T_DEVICE
771a63eb31SJulian Elischer 			{
781a63eb31SJulian Elischer 			key = (link_key_p) malloc(sizeof(*key));
791a63eb31SJulian Elischer 			if (key == NULL) {
801a63eb31SJulian Elischer 				syslog(LOG_ERR, "Could not allocate new " \
811a63eb31SJulian Elischer 						"config entry");
821a63eb31SJulian Elischer 				exit(1);
831a63eb31SJulian Elischer 			}
841a63eb31SJulian Elischer 
851a63eb31SJulian Elischer 			memset(key, 0, sizeof(*key));
861a63eb31SJulian Elischer 			}
871a63eb31SJulian Elischer 		'{' options '}'
881a63eb31SJulian Elischer 			{
891a63eb31SJulian Elischer 			if (get_key(&key->bdaddr, 1) != NULL) {
901a63eb31SJulian Elischer 				syslog(LOG_ERR, "Ignoring duplicated entry " \
910986ab12SMaksim Yevmenkin 						"for bdaddr %s",
920986ab12SMaksim Yevmenkin 						bt_ntoa(&key->bdaddr, NULL));
931a63eb31SJulian Elischer 				free_key(key);
941a63eb31SJulian Elischer 			} else
951a63eb31SJulian Elischer 				LIST_INSERT_HEAD(&link_keys, key, next);
961a63eb31SJulian Elischer 
971a63eb31SJulian Elischer 			key = NULL;
981a63eb31SJulian Elischer 			}
991a63eb31SJulian Elischer 		;
1001a63eb31SJulian Elischer 
1011a63eb31SJulian Elischer options:	option ';'
1021a63eb31SJulian Elischer 		| options option ';'
1031a63eb31SJulian Elischer 		;
1041a63eb31SJulian Elischer 
1051a63eb31SJulian Elischer option:		bdaddr
1061a63eb31SJulian Elischer 		| name
1071a63eb31SJulian Elischer 		| key
1081a63eb31SJulian Elischer 		| pin
1091a63eb31SJulian Elischer 		;
1101a63eb31SJulian Elischer 
1111a63eb31SJulian Elischer bdaddr:		T_BDADDR T_BDADDRSTRING
1121a63eb31SJulian Elischer 			{
1130986ab12SMaksim Yevmenkin 			if (!bt_aton($2, &key->bdaddr)) {
1142aa65cf7SMaksim Yevmenkin 				syslog(LOG_ERR, "Cound not parse BD_ADDR " \
1151a63eb31SJulian Elischer 						"'%s'", $2);
1161a63eb31SJulian Elischer 				exit(1);
1171a63eb31SJulian Elischer 			}
1181a63eb31SJulian Elischer 			}
1191a63eb31SJulian Elischer 		;
1201a63eb31SJulian Elischer 
1211a63eb31SJulian Elischer name:		T_NAME T_STRING
1221a63eb31SJulian Elischer 			{
1231a63eb31SJulian Elischer 			if (key->name != NULL)
1241a63eb31SJulian Elischer 				free(key->name);
1251a63eb31SJulian Elischer 
1261a63eb31SJulian Elischer 			key->name = strdup($2);
1271a63eb31SJulian Elischer 			if (key->name == NULL) {
1281a63eb31SJulian Elischer 				syslog(LOG_ERR, "Could not allocate new " \
1291a63eb31SJulian Elischer 						"device name");
1301a63eb31SJulian Elischer 				exit(1);
1311a63eb31SJulian Elischer 			}
1321a63eb31SJulian Elischer 			}
1331a63eb31SJulian Elischer 		;
1341a63eb31SJulian Elischer 
1351a63eb31SJulian Elischer key:		T_KEY T_HEXSTRING
1361a63eb31SJulian Elischer 			{
1371a63eb31SJulian Elischer 			int	i, len;
1381a63eb31SJulian Elischer 
1391a63eb31SJulian Elischer 			if (key->key != NULL)
1401a63eb31SJulian Elischer 				free(key->key);
1411a63eb31SJulian Elischer 
1422aa65cf7SMaksim Yevmenkin 			key->key = (uint8_t *) malloc(NG_HCI_KEY_SIZE);
1431a63eb31SJulian Elischer 			if (key->key == NULL) {
1441a63eb31SJulian Elischer 				syslog(LOG_ERR, "Could not allocate new " \
1451a63eb31SJulian Elischer 						"link key");
1461a63eb31SJulian Elischer 				exit(1);
1471a63eb31SJulian Elischer 			}
1481a63eb31SJulian Elischer 
1491a63eb31SJulian Elischer 			memset(key->key, 0, NG_HCI_KEY_SIZE);
1501a63eb31SJulian Elischer 
1511a63eb31SJulian Elischer 			len = strlen($2) / 2;
1521a63eb31SJulian Elischer 			if (len > NG_HCI_KEY_SIZE)
1531a63eb31SJulian Elischer 				len = NG_HCI_KEY_SIZE;
1541a63eb31SJulian Elischer 
1551a63eb31SJulian Elischer 			for (i = 0; i < len; i ++)
1561a63eb31SJulian Elischer 				key->key[i] = hexa2int8((char *)($2) + 2*i);
1571a63eb31SJulian Elischer 			}
1581a63eb31SJulian Elischer 		| T_KEY T_NOKEY
1591a63eb31SJulian Elischer 			{
1601a63eb31SJulian Elischer 			if (key->key != NULL)
1611a63eb31SJulian Elischer 				free(key->key);
1621a63eb31SJulian Elischer 
1631a63eb31SJulian Elischer 			key->key = NULL;
1641a63eb31SJulian Elischer 			}
1651a63eb31SJulian Elischer 		;
1661a63eb31SJulian Elischer 
1671a63eb31SJulian Elischer pin:		T_PIN T_STRING
1681a63eb31SJulian Elischer 			{
1691a63eb31SJulian Elischer 			if (key->pin != NULL)
1701a63eb31SJulian Elischer 				free(key->pin);
1711a63eb31SJulian Elischer 
1721a63eb31SJulian Elischer 			key->pin = strdup($2);
1731a63eb31SJulian Elischer 			if (key->pin == NULL) {
1741a63eb31SJulian Elischer 				syslog(LOG_ERR, "Could not allocate new " \
1751a63eb31SJulian Elischer 						"PIN code");
1761a63eb31SJulian Elischer 				exit(1);
1771a63eb31SJulian Elischer 			}
1781a63eb31SJulian Elischer 			}
1791a63eb31SJulian Elischer 		| T_PIN T_NOPIN
1801a63eb31SJulian Elischer 			{
1811a63eb31SJulian Elischer 			if (key->pin != NULL)
1821a63eb31SJulian Elischer 				free(key->pin);
1831a63eb31SJulian Elischer 
1841a63eb31SJulian Elischer 			key->pin = NULL;
1851a63eb31SJulian Elischer 			}
1861a63eb31SJulian Elischer 		;
1871a63eb31SJulian Elischer 
1881a63eb31SJulian Elischer %%
1891a63eb31SJulian Elischer 
1901a63eb31SJulian Elischer /* Display parser error message */
1911a63eb31SJulian Elischer void
1921a63eb31SJulian Elischer yyerror(char const *message)
1931a63eb31SJulian Elischer {
1941a63eb31SJulian Elischer 	syslog(LOG_ERR, "%s in line %d", message, yylineno);
1951a63eb31SJulian Elischer }
1961a63eb31SJulian Elischer 
1971a63eb31SJulian Elischer /* Re-read config file */
1981a63eb31SJulian Elischer void
1990986ab12SMaksim Yevmenkin read_config_file(void)
2001a63eb31SJulian Elischer {
2011a63eb31SJulian Elischer 	extern FILE	*yyin;
2021a63eb31SJulian Elischer 
2031a63eb31SJulian Elischer 	if (config_file == NULL) {
2041a63eb31SJulian Elischer 		syslog(LOG_ERR, "Unknown config file name!");
2051a63eb31SJulian Elischer 		exit(1);
2061a63eb31SJulian Elischer 	}
2071a63eb31SJulian Elischer 
2081a63eb31SJulian Elischer 	if ((yyin = fopen(config_file, "r")) == NULL) {
2091a63eb31SJulian Elischer 		syslog(LOG_ERR, "Could not open config file '%s'. %s (%d)",
2101a63eb31SJulian Elischer 				config_file, strerror(errno), errno);
2111a63eb31SJulian Elischer 		exit(1);
2121a63eb31SJulian Elischer 	}
2131a63eb31SJulian Elischer 
2141a63eb31SJulian Elischer 	clean_config();
2151a63eb31SJulian Elischer 	if (yyparse() < 0) {
2161a63eb31SJulian Elischer 		syslog(LOG_ERR, "Could not parse config file '%s'",config_file);
2171a63eb31SJulian Elischer 		exit(1);
2181a63eb31SJulian Elischer 	}
2191a63eb31SJulian Elischer 
2201a63eb31SJulian Elischer 	fclose(yyin);
2211a63eb31SJulian Elischer 	yyin = NULL;
2221a63eb31SJulian Elischer 
2231a63eb31SJulian Elischer #if __config_debug__
2241a63eb31SJulian Elischer 	dump_config();
2251a63eb31SJulian Elischer #endif
2261a63eb31SJulian Elischer }
2271a63eb31SJulian Elischer 
2281a63eb31SJulian Elischer /* Clean config */
2291a63eb31SJulian Elischer void
2301a63eb31SJulian Elischer clean_config(void)
2311a63eb31SJulian Elischer {
2321a63eb31SJulian Elischer 	link_key_p	key = NULL;
2331a63eb31SJulian Elischer 
2341a63eb31SJulian Elischer 	while ((key = LIST_FIRST(&link_keys)) != NULL) {
2351a63eb31SJulian Elischer 		LIST_REMOVE(key, next);
2361a63eb31SJulian Elischer 		free_key(key);
2371a63eb31SJulian Elischer 	}
2381a63eb31SJulian Elischer }
2391a63eb31SJulian Elischer 
2401a63eb31SJulian Elischer /* Find link key entry in the list. Return exact or default match */
2411a63eb31SJulian Elischer link_key_p
2421a63eb31SJulian Elischer get_key(bdaddr_p bdaddr, int exact_match)
2431a63eb31SJulian Elischer {
2441a63eb31SJulian Elischer 	link_key_p	key = NULL, defkey = NULL;
2451a63eb31SJulian Elischer 
2461a63eb31SJulian Elischer 	LIST_FOREACH(key, &link_keys, next) {
2471a63eb31SJulian Elischer 		if (memcmp(bdaddr, &key->bdaddr, sizeof(key->bdaddr)) == 0)
2481a63eb31SJulian Elischer 			break;
2491a63eb31SJulian Elischer 
2501a63eb31SJulian Elischer 		if (!exact_match)
2511a63eb31SJulian Elischer 			if (memcmp(NG_HCI_BDADDR_ANY, &key->bdaddr,
2521a63eb31SJulian Elischer 					sizeof(key->bdaddr)) == 0)
2531a63eb31SJulian Elischer 				defkey = key;
2541a63eb31SJulian Elischer 	}
2551a63eb31SJulian Elischer 
2561a63eb31SJulian Elischer 	return ((key != NULL)? key : defkey);
2571a63eb31SJulian Elischer }
2581a63eb31SJulian Elischer 
2591a63eb31SJulian Elischer #if __config_debug__
2601a63eb31SJulian Elischer /* Dump config */
2611a63eb31SJulian Elischer void
2621a63eb31SJulian Elischer dump_config(void)
2631a63eb31SJulian Elischer {
2641a63eb31SJulian Elischer 	link_key_p	key = NULL;
2651a63eb31SJulian Elischer 	char		buffer[64];
2661a63eb31SJulian Elischer 
2671a63eb31SJulian Elischer 	LIST_FOREACH(key, &link_keys, next) {
2681a63eb31SJulian Elischer 		if (key->key != NULL)
2691a63eb31SJulian Elischer 			snprintf(buffer, sizeof(buffer),
2701a63eb31SJulian Elischer "0x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
2711a63eb31SJulian Elischer 				key->key[0], key->key[1], key->key[2],
2721a63eb31SJulian Elischer 				key->key[3], key->key[4], key->key[5],
2731a63eb31SJulian Elischer 				key->key[6], key->key[7], key->key[8],
2741a63eb31SJulian Elischer 				key->key[9], key->key[10], key->key[11],
2751a63eb31SJulian Elischer 				key->key[12], key->key[13], key->key[14],
2761a63eb31SJulian Elischer 				key->key[15]);
2771a63eb31SJulian Elischer 
2781a63eb31SJulian Elischer 		syslog(LOG_DEBUG,
2791a63eb31SJulian Elischer "device %s " \
2800986ab12SMaksim Yevmenkin "bdaddr %s " \
2811a63eb31SJulian Elischer "pin %s " \
2821a63eb31SJulian Elischer "key %s",
2831a63eb31SJulian Elischer 			(key->name != NULL)? key->name : "noname",
2840986ab12SMaksim Yevmenkin 			bt_ntoa(&key->bdaddr, NULL),
2851a63eb31SJulian Elischer 			(key->pin != NULL)? key->pin : "nopin",
2861a63eb31SJulian Elischer 			(key->key != NULL)? buffer : "nokey");
2871a63eb31SJulian Elischer 	}
2881a63eb31SJulian Elischer }
2891a63eb31SJulian Elischer #endif
2901a63eb31SJulian Elischer 
2910986ab12SMaksim Yevmenkin /* Read keys file */
2920986ab12SMaksim Yevmenkin int
2930986ab12SMaksim Yevmenkin read_keys_file(void)
2940986ab12SMaksim Yevmenkin {
2950986ab12SMaksim Yevmenkin 	FILE		*f = NULL;
2960986ab12SMaksim Yevmenkin 	link_key_t	*key = NULL;
2970986ab12SMaksim Yevmenkin 	char		 buf[HCSECD_BUFFER_SIZE], *p = NULL, *cp = NULL;
2980986ab12SMaksim Yevmenkin 	bdaddr_t	 bdaddr;
2990986ab12SMaksim Yevmenkin 	int		 i, len;
3000986ab12SMaksim Yevmenkin 
3010986ab12SMaksim Yevmenkin 	if ((f = fopen(HCSECD_KEYSFILE, "r")) == NULL) {
3020986ab12SMaksim Yevmenkin 		if (errno == ENOENT)
3030986ab12SMaksim Yevmenkin 			return (0);
3040986ab12SMaksim Yevmenkin 
3050986ab12SMaksim Yevmenkin 		syslog(LOG_ERR, "Could not open keys file %s. %s (%d)\n",
3060986ab12SMaksim Yevmenkin 				HCSECD_KEYSFILE, strerror(errno), errno);
3070986ab12SMaksim Yevmenkin 
3080986ab12SMaksim Yevmenkin 		return (-1);
3090986ab12SMaksim Yevmenkin 	}
3100986ab12SMaksim Yevmenkin 
3110986ab12SMaksim Yevmenkin 	while ((p = fgets(buf, sizeof(buf), f)) != NULL) {
3120986ab12SMaksim Yevmenkin 		if (*p == '#')
3130986ab12SMaksim Yevmenkin 			continue;
3140986ab12SMaksim Yevmenkin 		if ((cp = strpbrk(p, " ")) == NULL)
3150986ab12SMaksim Yevmenkin 			continue;
3160986ab12SMaksim Yevmenkin 
3170986ab12SMaksim Yevmenkin 		*cp++ = '\0';
3180986ab12SMaksim Yevmenkin 
3190986ab12SMaksim Yevmenkin 		if (!bt_aton(p, &bdaddr))
3200986ab12SMaksim Yevmenkin 			continue;
3210986ab12SMaksim Yevmenkin 
3220986ab12SMaksim Yevmenkin 		if ((key = get_key(&bdaddr, 1)) == NULL)
3230986ab12SMaksim Yevmenkin 			continue;
3240986ab12SMaksim Yevmenkin 
3250986ab12SMaksim Yevmenkin 		if (key->key == NULL) {
3262aa65cf7SMaksim Yevmenkin 			key->key = (uint8_t *) malloc(NG_HCI_KEY_SIZE);
3270986ab12SMaksim Yevmenkin 			if (key->key == NULL) {
3280986ab12SMaksim Yevmenkin 				syslog(LOG_ERR, "Could not allocate link key");
3290986ab12SMaksim Yevmenkin 				exit(1);
3300986ab12SMaksim Yevmenkin 			}
3310986ab12SMaksim Yevmenkin 		}
3320986ab12SMaksim Yevmenkin 
3330986ab12SMaksim Yevmenkin 		memset(key->key, 0, NG_HCI_KEY_SIZE);
3340986ab12SMaksim Yevmenkin 
3350986ab12SMaksim Yevmenkin 		len = strlen(cp) / 2;
3360986ab12SMaksim Yevmenkin 		if (len > NG_HCI_KEY_SIZE)
3370986ab12SMaksim Yevmenkin 			len = NG_HCI_KEY_SIZE;
3380986ab12SMaksim Yevmenkin 
3390986ab12SMaksim Yevmenkin 		for (i = 0; i < len; i ++)
3400986ab12SMaksim Yevmenkin 			key->key[i] = hexa2int8(cp + 2*i);
3410986ab12SMaksim Yevmenkin 
3420986ab12SMaksim Yevmenkin 		syslog(LOG_DEBUG, "Restored link key for the entry, " \
3430986ab12SMaksim Yevmenkin 				"remote bdaddr %s, name '%s'",
3440986ab12SMaksim Yevmenkin 				bt_ntoa(&key->bdaddr, NULL),
3450986ab12SMaksim Yevmenkin 				(key->name != NULL)? key->name : "No name");
3460986ab12SMaksim Yevmenkin 	}
3470986ab12SMaksim Yevmenkin 
3480986ab12SMaksim Yevmenkin 	fclose(f);
3490986ab12SMaksim Yevmenkin 
3500986ab12SMaksim Yevmenkin 	return (0);
3510986ab12SMaksim Yevmenkin }
3520986ab12SMaksim Yevmenkin 
3530986ab12SMaksim Yevmenkin /* Dump keys file */
3540986ab12SMaksim Yevmenkin int
3550986ab12SMaksim Yevmenkin dump_keys_file(void)
3560986ab12SMaksim Yevmenkin {
3570986ab12SMaksim Yevmenkin 	link_key_p	key = NULL;
3580986ab12SMaksim Yevmenkin 	char		tmp[PATH_MAX], buf[HCSECD_BUFFER_SIZE];
3590986ab12SMaksim Yevmenkin 	int		f;
3600986ab12SMaksim Yevmenkin 
3610986ab12SMaksim Yevmenkin 	snprintf(tmp, sizeof(tmp), "%s.tmp", HCSECD_KEYSFILE);
3620986ab12SMaksim Yevmenkin 	if ((f = open(tmp, O_RDWR|O_CREAT|O_TRUNC|O_EXCL, 0600)) < 0) {
3630986ab12SMaksim Yevmenkin 		syslog(LOG_ERR, "Could not create temp keys file %s. %s (%d)\n",
3640986ab12SMaksim Yevmenkin 				tmp, strerror(errno), errno);
3650986ab12SMaksim Yevmenkin 		return (-1);
3660986ab12SMaksim Yevmenkin 	}
3670986ab12SMaksim Yevmenkin 
3680986ab12SMaksim Yevmenkin 	LIST_FOREACH(key, &link_keys, next) {
3690986ab12SMaksim Yevmenkin 		if (key->key == NULL)
3700986ab12SMaksim Yevmenkin 			continue;
3710986ab12SMaksim Yevmenkin 
3720986ab12SMaksim Yevmenkin 		snprintf(buf, sizeof(buf),
3730986ab12SMaksim Yevmenkin "%s %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n",
3740986ab12SMaksim Yevmenkin 			bt_ntoa(&key->bdaddr, NULL),
3750986ab12SMaksim Yevmenkin 			key->key[0],  key->key[1],  key->key[2],  key->key[3],
3760986ab12SMaksim Yevmenkin 			key->key[4],  key->key[5],  key->key[6],  key->key[7],
3770986ab12SMaksim Yevmenkin 			key->key[8],  key->key[9],  key->key[10], key->key[11],
3780986ab12SMaksim Yevmenkin 			key->key[12], key->key[13], key->key[14], key->key[15]);
3790986ab12SMaksim Yevmenkin 
3800986ab12SMaksim Yevmenkin 		if (write(f, buf, strlen(buf)) < 0) {
3810986ab12SMaksim Yevmenkin 			syslog(LOG_ERR, "Could not write temp keys file. " \
3820986ab12SMaksim Yevmenkin 					"%s (%d)\n", strerror(errno), errno);
3830986ab12SMaksim Yevmenkin 			break;
3840986ab12SMaksim Yevmenkin 		}
3850986ab12SMaksim Yevmenkin 	}
3860986ab12SMaksim Yevmenkin 
3870986ab12SMaksim Yevmenkin 	close(f);
3880986ab12SMaksim Yevmenkin 
3890986ab12SMaksim Yevmenkin 	if (rename(tmp, HCSECD_KEYSFILE) < 0) {
3900986ab12SMaksim Yevmenkin 		syslog(LOG_ERR, "Could not rename(%s, %s). %s (%d)\n",
3910986ab12SMaksim Yevmenkin 				tmp, HCSECD_KEYSFILE, strerror(errno), errno);
3920986ab12SMaksim Yevmenkin 		unlink(tmp);
3930986ab12SMaksim Yevmenkin 		return (-1);
3940986ab12SMaksim Yevmenkin 	}
3950986ab12SMaksim Yevmenkin 
3960986ab12SMaksim Yevmenkin 	return (0);
3970986ab12SMaksim Yevmenkin }
3980986ab12SMaksim Yevmenkin 
3991a63eb31SJulian Elischer /* Free key entry */
4001a63eb31SJulian Elischer static void
4011a63eb31SJulian Elischer free_key(link_key_p key)
4021a63eb31SJulian Elischer {
4031a63eb31SJulian Elischer 	if (key->name != NULL)
4041a63eb31SJulian Elischer 		free(key->name);
4051a63eb31SJulian Elischer 	if (key->key != NULL)
4061a63eb31SJulian Elischer 		free(key->key);
4071a63eb31SJulian Elischer 	if (key->pin != NULL)
4081a63eb31SJulian Elischer 		free(key->pin);
4091a63eb31SJulian Elischer 
4101a63eb31SJulian Elischer 	memset(key, 0, sizeof(*key));
4111a63eb31SJulian Elischer 	free(key);
4121a63eb31SJulian Elischer }
4131a63eb31SJulian Elischer 
4141a63eb31SJulian Elischer /* Convert hex ASCII to int4 */
4151a63eb31SJulian Elischer static int
4161a63eb31SJulian Elischer hexa2int4(char *a)
4171a63eb31SJulian Elischer {
4181a63eb31SJulian Elischer 	if ('0' <= *a && *a <= '9')
4191a63eb31SJulian Elischer 		return (*a - '0');
4201a63eb31SJulian Elischer 
4211a63eb31SJulian Elischer 	if ('A' <= *a && *a <= 'F')
4221a63eb31SJulian Elischer 		return (*a - 'A' + 0xa);
4231a63eb31SJulian Elischer 
4241a63eb31SJulian Elischer 	if ('a' <= *a && *a <= 'f')
4251a63eb31SJulian Elischer 		return (*a - 'a' + 0xa);
4261a63eb31SJulian Elischer 
4271a63eb31SJulian Elischer 	syslog(LOG_ERR, "Invalid hex character: '%c' (%#x)", *a, *a);
4281a63eb31SJulian Elischer 	exit(1);
4291a63eb31SJulian Elischer }
4301a63eb31SJulian Elischer 
4311a63eb31SJulian Elischer /* Convert hex ASCII to int8 */
4321a63eb31SJulian Elischer static int
4331a63eb31SJulian Elischer hexa2int8(char *a)
4341a63eb31SJulian Elischer {
4351a63eb31SJulian Elischer 	return ((hexa2int4(a) << 4) | hexa2int4(a + 1));
4361a63eb31SJulian Elischer }
4371a63eb31SJulian Elischer 
438