|
Packit |
8fb625 |
/*
|
|
Packit |
8fb625 |
*
|
|
Packit |
8fb625 |
* BlueZ - Bluetooth protocol stack for Linux
|
|
Packit |
8fb625 |
*
|
|
Packit |
8fb625 |
* Copyright (C) 2009 Bastien Nocera <hadess@hadess.net>
|
|
Packit |
8fb625 |
*
|
|
Packit |
8fb625 |
*
|
|
Packit |
8fb625 |
* This program is free software; you can redistribute it and/or modify
|
|
Packit |
8fb625 |
* it under the terms of the GNU General Public License as published by
|
|
Packit |
8fb625 |
* the Free Software Foundation; either version 2 of the License, or
|
|
Packit |
8fb625 |
* (at your option) any later version.
|
|
Packit |
8fb625 |
*
|
|
Packit |
8fb625 |
* This program is distributed in the hope that it will be useful,
|
|
Packit |
8fb625 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
8fb625 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
Packit |
8fb625 |
* GNU General Public License for more details.
|
|
Packit |
8fb625 |
*
|
|
Packit |
8fb625 |
* You should have received a copy of the GNU General Public License
|
|
Packit |
8fb625 |
* along with this program; if not, write to the Free Software
|
|
Packit |
8fb625 |
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
Packit |
8fb625 |
*
|
|
Packit |
8fb625 |
*/
|
|
Packit |
8fb625 |
|
|
Packit |
8fb625 |
#ifdef HAVE_CONFIG_H
|
|
Packit |
8fb625 |
#include <config.h>
|
|
Packit |
8fb625 |
#endif
|
|
Packit |
8fb625 |
|
|
Packit |
8fb625 |
#include <stdlib.h>
|
|
Packit |
8fb625 |
#include <string.h>
|
|
Packit |
8fb625 |
#include <glib.h>
|
|
Packit |
8fb625 |
#include <libudev.h>
|
|
Packit |
8fb625 |
#include <bluetooth-enums.h>
|
|
Packit |
8fb625 |
#include <bluetooth-utils.h>
|
|
Packit |
8fb625 |
|
|
Packit |
8fb625 |
#include "pin.h"
|
|
Packit |
8fb625 |
|
|
Packit |
8fb625 |
#define PIN_CODE_DB "pin-code-database.xml"
|
|
Packit |
8fb625 |
#define MAX_DIGITS_PIN_PREFIX "max:"
|
|
Packit |
8fb625 |
|
|
Packit |
8fb625 |
char *
|
|
Packit |
8fb625 |
oui_to_vendor (const char *oui)
|
|
Packit |
8fb625 |
{
|
|
Packit |
8fb625 |
struct udev *udev = NULL;
|
|
Packit |
8fb625 |
struct udev_hwdb *hwdb = NULL;
|
|
Packit |
8fb625 |
struct udev_list_entry *list, *l;
|
|
Packit |
8fb625 |
char *modalias = NULL;
|
|
Packit |
8fb625 |
char *vendor = NULL;
|
|
Packit |
8fb625 |
|
|
Packit |
8fb625 |
if (oui == NULL ||
|
|
Packit |
8fb625 |
strlen (oui) < 8)
|
|
Packit |
8fb625 |
return NULL;
|
|
Packit |
8fb625 |
|
|
Packit |
8fb625 |
udev = udev_new ();
|
|
Packit |
8fb625 |
if (udev == NULL)
|
|
Packit |
8fb625 |
goto bail;
|
|
Packit |
8fb625 |
|
|
Packit |
8fb625 |
hwdb = udev_hwdb_new (udev);
|
|
Packit |
8fb625 |
if (hwdb == NULL)
|
|
Packit |
8fb625 |
goto bail;
|
|
Packit |
8fb625 |
|
|
Packit |
8fb625 |
modalias = g_strdup_printf ("OUI:%c%c%c%c%c%c",
|
|
Packit |
8fb625 |
g_ascii_toupper (oui[0]),
|
|
Packit |
8fb625 |
g_ascii_toupper (oui[1]),
|
|
Packit |
8fb625 |
g_ascii_toupper (oui[3]),
|
|
Packit |
8fb625 |
g_ascii_toupper (oui[4]),
|
|
Packit |
8fb625 |
g_ascii_toupper (oui[6]),
|
|
Packit |
8fb625 |
g_ascii_toupper (oui[7]));
|
|
Packit |
8fb625 |
|
|
Packit |
8fb625 |
list = udev_hwdb_get_properties_list_entry (hwdb, modalias, 0);
|
|
Packit |
8fb625 |
|
|
Packit |
8fb625 |
udev_list_entry_foreach (l, list) {
|
|
Packit |
8fb625 |
const char *name = udev_list_entry_get_name (l);
|
|
Packit |
8fb625 |
|
|
Packit |
8fb625 |
if (g_strcmp0 (name, "ID_OUI_FROM_DATABASE") == 0) {
|
|
Packit |
8fb625 |
vendor = g_strdup (udev_list_entry_get_value (l));
|
|
Packit |
8fb625 |
break;
|
|
Packit |
8fb625 |
}
|
|
Packit |
8fb625 |
}
|
|
Packit |
8fb625 |
|
|
Packit |
8fb625 |
bail:
|
|
Packit |
8fb625 |
g_clear_pointer (&modalias, g_free);
|
|
Packit |
8fb625 |
g_clear_pointer (&hwdb, udev_hwdb_unref);
|
|
Packit |
8fb625 |
g_clear_pointer (&udev, udev_unref);
|
|
Packit |
8fb625 |
|
|
Packit |
8fb625 |
return vendor;
|
|
Packit |
8fb625 |
}
|
|
Packit |
8fb625 |
|
|
Packit |
8fb625 |
#define TYPE_IS(x, r) { \
|
|
Packit |
8fb625 |
if (g_str_equal(type, x)) return r; \
|
|
Packit |
8fb625 |
}
|
|
Packit |
8fb625 |
|
|
Packit |
8fb625 |
static guint string_to_type(const char *type)
|
|
Packit |
8fb625 |
{
|
|
Packit |
8fb625 |
TYPE_IS ("any", BLUETOOTH_TYPE_ANY);
|
|
Packit |
8fb625 |
TYPE_IS ("mouse", BLUETOOTH_TYPE_MOUSE);
|
|
Packit |
8fb625 |
TYPE_IS ("tablet", BLUETOOTH_TYPE_TABLET);
|
|
Packit |
8fb625 |
TYPE_IS ("keyboard", BLUETOOTH_TYPE_KEYBOARD);
|
|
Packit |
8fb625 |
TYPE_IS ("headset", BLUETOOTH_TYPE_HEADSET);
|
|
Packit |
8fb625 |
TYPE_IS ("headphones", BLUETOOTH_TYPE_HEADPHONES);
|
|
Packit |
8fb625 |
TYPE_IS ("audio", BLUETOOTH_TYPE_OTHER_AUDIO);
|
|
Packit |
8fb625 |
TYPE_IS ("printer", BLUETOOTH_TYPE_PRINTER);
|
|
Packit |
8fb625 |
TYPE_IS ("network", BLUETOOTH_TYPE_NETWORK);
|
|
Packit |
8fb625 |
TYPE_IS ("joypad", BLUETOOTH_TYPE_JOYPAD);
|
|
Packit |
8fb625 |
|
|
Packit |
8fb625 |
g_warning ("unhandled type '%s'", type);
|
|
Packit |
8fb625 |
return BLUETOOTH_TYPE_ANY;
|
|
Packit |
8fb625 |
}
|
|
Packit |
8fb625 |
|
|
Packit |
8fb625 |
typedef struct {
|
|
Packit |
8fb625 |
char *ret_pin;
|
|
Packit |
8fb625 |
guint max_digits;
|
|
Packit |
8fb625 |
guint type;
|
|
Packit |
8fb625 |
const char *address;
|
|
Packit |
8fb625 |
const char *name;
|
|
Packit |
8fb625 |
char *vendor;
|
|
Packit |
8fb625 |
gboolean confirm;
|
|
Packit |
8fb625 |
} PinParseData;
|
|
Packit |
8fb625 |
|
|
Packit |
8fb625 |
static void
|
|
Packit |
8fb625 |
pin_db_parse_start_tag (GMarkupParseContext *ctx,
|
|
Packit |
8fb625 |
const gchar *element_name,
|
|
Packit |
8fb625 |
const gchar **attr_names,
|
|
Packit |
8fb625 |
const gchar **attr_values,
|
|
Packit |
8fb625 |
gpointer data,
|
|
Packit |
8fb625 |
GError **error)
|
|
Packit |
8fb625 |
{
|
|
Packit |
8fb625 |
PinParseData *pdata = (PinParseData *) data;
|
|
Packit |
8fb625 |
|
|
Packit |
8fb625 |
if (pdata->ret_pin != NULL || pdata->max_digits != 0)
|
|
Packit |
8fb625 |
return;
|
|
Packit |
8fb625 |
if (g_str_equal (element_name, "device") == FALSE)
|
|
Packit |
8fb625 |
return;
|
|
Packit |
8fb625 |
|
|
Packit |
8fb625 |
while (*attr_names && *attr_values) {
|
|
Packit |
8fb625 |
if (g_str_equal (*attr_names, "type")) {
|
|
Packit |
8fb625 |
guint type;
|
|
Packit |
8fb625 |
|
|
Packit |
8fb625 |
type = string_to_type (*attr_values);
|
|
Packit |
8fb625 |
if (type != BLUETOOTH_TYPE_ANY && type != pdata->type)
|
|
Packit |
8fb625 |
return;
|
|
Packit |
8fb625 |
} else if (g_str_equal (*attr_names, "oui")) {
|
|
Packit |
8fb625 |
if (g_str_has_prefix (pdata->address, *attr_values) == FALSE)
|
|
Packit |
8fb625 |
return;
|
|
Packit |
8fb625 |
} else if (g_str_equal (*attr_names, "vendor")) {
|
|
Packit |
8fb625 |
if (*attr_values == NULL || pdata->vendor == NULL)
|
|
Packit |
8fb625 |
return;
|
|
Packit |
8fb625 |
if (strstr (pdata->vendor, *attr_values) == NULL)
|
|
Packit |
8fb625 |
return;
|
|
Packit |
8fb625 |
} else if (g_str_equal (*attr_names, "name")) {
|
|
Packit |
8fb625 |
if (*attr_values == NULL || pdata->name == NULL)
|
|
Packit |
8fb625 |
return;
|
|
Packit |
8fb625 |
if (strstr (pdata->name, *attr_values) == NULL)
|
|
Packit |
8fb625 |
return;
|
|
Packit |
8fb625 |
pdata->confirm = FALSE;
|
|
Packit |
8fb625 |
} else if (g_str_equal (*attr_names, "pin")) {
|
|
Packit |
8fb625 |
if (g_str_has_prefix (*attr_values, MAX_DIGITS_PIN_PREFIX) != FALSE) {
|
|
Packit |
8fb625 |
pdata->max_digits = strtoul (*attr_values + strlen (MAX_DIGITS_PIN_PREFIX), NULL, 0);
|
|
Packit |
8fb625 |
g_assert (pdata->max_digits > 0 && pdata->max_digits < PIN_NUM_DIGITS);
|
|
Packit |
8fb625 |
} else {
|
|
Packit |
8fb625 |
pdata->ret_pin = g_strdup (*attr_values);
|
|
Packit |
8fb625 |
}
|
|
Packit |
8fb625 |
return;
|
|
Packit |
8fb625 |
}
|
|
Packit |
8fb625 |
|
|
Packit |
8fb625 |
++attr_names;
|
|
Packit |
8fb625 |
++attr_values;
|
|
Packit |
8fb625 |
}
|
|
Packit |
8fb625 |
}
|
|
Packit |
8fb625 |
|
|
Packit |
8fb625 |
char *
|
|
Packit |
8fb625 |
get_pincode_for_device (guint type,
|
|
Packit |
8fb625 |
const char *address,
|
|
Packit |
8fb625 |
const char *name,
|
|
Packit |
8fb625 |
guint *max_digits,
|
|
Packit |
8fb625 |
gboolean *confirm)
|
|
Packit |
8fb625 |
{
|
|
Packit |
8fb625 |
GMarkupParseContext *ctx;
|
|
Packit |
8fb625 |
GMarkupParser parser = { pin_db_parse_start_tag, NULL, NULL, NULL, NULL };
|
|
Packit |
8fb625 |
PinParseData *data;
|
|
Packit |
8fb625 |
char *buf;
|
|
Packit |
8fb625 |
gsize buf_len;
|
|
Packit |
8fb625 |
GError *err = NULL;
|
|
Packit |
8fb625 |
char *tmp_vendor, *ret_pin;
|
|
Packit |
8fb625 |
|
|
Packit |
8fb625 |
g_return_val_if_fail (address != NULL, NULL);
|
|
Packit |
8fb625 |
|
|
Packit |
8fb625 |
g_debug ("Getting pincode for device '%s' (type: %s address: %s)",
|
|
Packit |
8fb625 |
name ? name : "", bluetooth_type_to_string (type), address);
|
|
Packit |
8fb625 |
|
|
Packit |
8fb625 |
/* Load the PIN database and split it in lines */
|
|
Packit |
8fb625 |
if (!g_file_get_contents(PIN_CODE_DB, &buf, &buf_len, NULL)) {
|
|
Packit |
8fb625 |
char *filename;
|
|
Packit |
8fb625 |
|
|
Packit |
8fb625 |
filename = g_build_filename(PKGDATADIR, PIN_CODE_DB, NULL);
|
|
Packit |
8fb625 |
if (!g_file_get_contents(filename, &buf, &buf_len, NULL)) {
|
|
Packit |
8fb625 |
g_warning("Could not load "PIN_CODE_DB);
|
|
Packit |
8fb625 |
g_free (filename);
|
|
Packit |
8fb625 |
return NULL;
|
|
Packit |
8fb625 |
}
|
|
Packit |
8fb625 |
g_free (filename);
|
|
Packit |
8fb625 |
}
|
|
Packit |
8fb625 |
|
|
Packit |
8fb625 |
data = g_new0 (PinParseData, 1);
|
|
Packit |
8fb625 |
data->type = type;
|
|
Packit |
8fb625 |
data->address = address;
|
|
Packit |
8fb625 |
data->name = name;
|
|
Packit |
8fb625 |
data->confirm = TRUE;
|
|
Packit |
8fb625 |
|
|
Packit |
8fb625 |
tmp_vendor = oui_to_vendor (address);
|
|
Packit |
8fb625 |
if (tmp_vendor)
|
|
Packit |
8fb625 |
data->vendor = g_ascii_strdown (tmp_vendor, -1);
|
|
Packit |
8fb625 |
g_free (tmp_vendor);
|
|
Packit |
8fb625 |
|
|
Packit |
8fb625 |
ctx = g_markup_parse_context_new (&parser, 0, data, NULL);
|
|
Packit |
8fb625 |
|
|
Packit |
8fb625 |
if (!g_markup_parse_context_parse (ctx, buf, buf_len, &err)) {
|
|
Packit |
8fb625 |
g_warning ("Failed to parse '%s': %s\n", PIN_CODE_DB, err->message);
|
|
Packit |
8fb625 |
g_error_free (err);
|
|
Packit |
8fb625 |
}
|
|
Packit |
8fb625 |
|
|
Packit |
8fb625 |
g_markup_parse_context_free (ctx);
|
|
Packit |
8fb625 |
g_free (buf);
|
|
Packit |
8fb625 |
|
|
Packit |
8fb625 |
if (max_digits != NULL)
|
|
Packit |
8fb625 |
*max_digits = data->max_digits;
|
|
Packit |
8fb625 |
if (confirm != NULL)
|
|
Packit |
8fb625 |
*confirm = data->confirm;
|
|
Packit |
8fb625 |
|
|
Packit |
8fb625 |
g_debug ("Got pin '%s' (max digits: %d, confirm: %d) for device '%s' (type: %s address: %s, vendor: %s)",
|
|
Packit |
8fb625 |
data->ret_pin, data->max_digits, data->confirm,
|
|
Packit |
8fb625 |
name ? name : "", bluetooth_type_to_string (type), address, data->vendor);
|
|
Packit |
8fb625 |
|
|
Packit |
8fb625 |
g_free (data->vendor);
|
|
Packit |
8fb625 |
ret_pin = data->ret_pin;
|
|
Packit |
8fb625 |
g_free (data);
|
|
Packit |
8fb625 |
|
|
Packit |
8fb625 |
return ret_pin;
|
|
Packit |
8fb625 |
}
|
|
Packit |
8fb625 |
|