From f17bb94f47090f3397b60b5e264aa9f18dbf203d Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Tue, 17 Feb 2004 18:04:03 +0000 Subject: Add D-Bus support for PIN request --- hcid/Makefile.am | 8 ++- hcid/dbus.c | 206 +++++++++++++++++++++++++++++++++++++++++++++++++++++ hcid/glib-ectomy.c | 19 ++++- hcid/glib-ectomy.h | 2 + hcid/hcid.h | 6 ++ hcid/kword.c | 76 +++++++++++--------- hcid/kword.h | 44 ++++++------ hcid/lexer.l | 5 ++ hcid/lib.c | 4 ++ hcid/main.c | 12 ++++ hcid/parser.y | 12 +++- hcid/security.c | 21 ++++-- 12 files changed, 347 insertions(+), 68 deletions(-) create mode 100644 hcid/dbus.c diff --git a/hcid/Makefile.am b/hcid/Makefile.am index 378d3a35..14428722 100644 --- a/hcid/Makefile.am +++ b/hcid/Makefile.am @@ -4,7 +4,13 @@ sbin_PROGRAMS = hcid -hcid_SOURCES = main.c security.c hcid.h lib.c lib.h parser.h parser.y lexer.l kword.h kword.c glib-ectomy.h glib-ectomy.c +if ENABLE_DBUS +dbus_hcid_sources = dbus.c +else +dbus_hcid_sources = +endif + +hcid_SOURCES = main.c security.c hcid.h lib.c lib.h parser.h parser.y lexer.l kword.h kword.c glib-ectomy.h glib-ectomy.c $(dbus_hcid_sources) hcid_CONFIG = hcid.conf YFLAGS = -d diff --git a/hcid/dbus.c b/hcid/dbus.c new file mode 100644 index 00000000..4c2bb18d --- /dev/null +++ b/hcid/dbus.c @@ -0,0 +1,206 @@ +#include +#include +#include + +#include +#include +#include + +#define DBUS_API_SUBJECT_TO_CHANGE +#include + +#include "hcid.h" +#include "glib-ectomy.h" + +static DBusConnection *connection; + +#define TIMEOUT (30 * 1000) // 30 seconds + +#define SERVICE_NAME "org.handhelds.gpe.bluez" +#define INTERFACE_NAME SERVICE_NAME ".PinAgent" +#define REQUEST_NAME "PinRequest" +#define PATH_NAME "/org/handhelds/gpe/bluez/PinAgent" + +#define WRONG_ARGS_ERROR "org.handhelds.gpe.bluez.Error.WrongArgs" + +struct pin_request +{ + int dev; + bdaddr_t bda; +}; + +static void reply_handler_function(DBusPendingCall *call, void *user_data) +{ + struct pin_request *req = (struct pin_request *) user_data; + pin_code_reply_cp pr; + DBusMessage *message; + DBusMessageIter iter; + int type; + size_t len; + char *pin; + + message = dbus_pending_call_get_reply(call); + + if (dbus_message_is_error(message, WRONG_ARGS_ERROR)) + goto error; + + dbus_message_iter_init(message, &iter); + + type = dbus_message_iter_get_arg_type(&iter); + if (type != DBUS_TYPE_STRING) + goto error; + + pin = dbus_message_iter_get_string(&iter); + len = strlen(pin); + + memset(&pr, 0, sizeof(pr)); + bacpy(&pr.bdaddr, &req->bda); + memcpy(pr.pin_code, pin, len); + pr.pin_len = len; + hci_send_cmd(req->dev, OGF_LINK_CTL, OCF_PIN_CODE_REPLY, + PIN_CODE_REPLY_CP_SIZE, &pr); + + return; + +error: + hci_send_cmd(req->dev, OGF_LINK_CTL, OCF_PIN_CODE_NEG_REPLY, + 6, &req->bda); +} + + +static void free_pin_req(void *req) +{ + free(req); +} + +void hcid_dbus_request_pin(int dev, struct hci_conn_info *ci) +{ + DBusMessage *message; + DBusMessageIter iter; + DBusPendingCall *pending = NULL; + struct pin_request *req; + + message = dbus_message_new_method_call(SERVICE_NAME, PATH_NAME, + INTERFACE_NAME, REQUEST_NAME); + if (message == NULL) { + syslog(LOG_ERR, "Couldn't allocate D-BUS message"); + goto failed; + } + + req = malloc(sizeof(*req)); + req->dev = dev; + bacpy(&req->bda, &ci->bdaddr); + + dbus_message_append_iter_init(message, &iter); + + dbus_message_iter_append_boolean(&iter, ci->out); + dbus_message_iter_append_byte_array(&iter, + (unsigned char *) &ci->bdaddr, sizeof(ci->bdaddr)); + + if (dbus_connection_send_with_reply(connection, message, + &pending, TIMEOUT) == FALSE) { + syslog(LOG_ERR, "D-BUS send failed"); + goto failed; + } + + dbus_pending_call_set_notify(pending, reply_handler_function, + req, free_pin_req); + + dbus_connection_flush (connection); + + dbus_message_unref (message); + + return; + +failed: + dbus_message_unref (message); + hci_send_cmd(dev, OGF_LINK_CTL, OCF_PIN_CODE_NEG_REPLY, + 6, &ci->bdaddr); +} + +gboolean watch_func(GIOChannel *chan, GIOCondition cond, gpointer data) +{ + DBusWatch *watch = (DBusWatch *) data; + int flags = 0; + + if (cond & G_IO_IN) flags |= DBUS_WATCH_READABLE; + if (cond & G_IO_OUT) flags |= DBUS_WATCH_WRITABLE; + if (cond & G_IO_HUP) flags |= DBUS_WATCH_HANGUP; + if (cond & G_IO_ERR) flags |= DBUS_WATCH_ERROR; + + dbus_watch_handle(watch, flags); + + dbus_connection_ref(connection); + + /* Dispatch messages */ + while (dbus_connection_dispatch(connection) == DBUS_DISPATCH_DATA_REMAINS); + + dbus_connection_unref(connection); + + return TRUE; +} + +dbus_bool_t add_watch(DBusWatch *watch, void *data) +{ + GIOCondition cond = G_IO_HUP | G_IO_ERR; + GIOChannel *io; + guint id; + int fd, flags; + + if (!dbus_watch_get_enabled(watch)) + return TRUE; + + fd = dbus_watch_get_fd(watch); + io = g_io_channel_unix_new(fd); + flags = dbus_watch_get_flags(watch); + + if (flags & DBUS_WATCH_READABLE) cond |= G_IO_IN; + if (flags & DBUS_WATCH_WRITABLE) cond |= G_IO_OUT; + + id = g_io_add_watch(io, cond, watch_func, watch); + + dbus_watch_set_data(watch, (void *) id, NULL); + + return TRUE; +} + +static void remove_watch(DBusWatch *watch, void *data) +{ + guint id = (guint) dbus_watch_get_data(watch); + + dbus_watch_set_data(watch, NULL, NULL); + + if (id) + g_io_remove_watch(id); +} + +static void watch_toggled(DBusWatch *watch, void *data) +{ + /* Because we just exit on OOM, enable/disable is + * no different from add/remove + */ + if (dbus_watch_get_enabled(watch)) + add_watch(watch, data); + else + remove_watch(watch, data); +} + +gboolean hcid_dbus_init(void) +{ + DBusError error; + + dbus_error_init(&error); + + connection = dbus_bus_get(DBUS_BUS_SYSTEM, &error); + if (connection == NULL) { + fprintf(stderr, "Failed to open connection to system message bus: %s\n", + error.message); + dbus_error_free(&error); + return FALSE; + } + + dbus_connection_set_watch_functions(connection, + add_watch, remove_watch, watch_toggled, NULL, NULL); + + return TRUE; +} diff --git a/hcid/glib-ectomy.c b/hcid/glib-ectomy.c index 5b56855e..8489cd73 100644 --- a/hcid/glib-ectomy.c +++ b/hcid/glib-ectomy.c @@ -1,5 +1,3 @@ -#include "glib-ectomy.h" - #include #include #include @@ -8,7 +6,7 @@ #include #include -// static void remove_watch(int fd); +#include "glib-ectomy.h" GIOError g_io_channel_read (GIOChannel *channel, gchar *buf, @@ -84,6 +82,21 @@ struct watch { static struct watch watch_head = { .id = 0, .next = 0 }; +void g_io_remove_watch (guint id) +{ + struct watch *w, *p; + + for (p = &watch_head, w = watch_head.next; w; w = w->next) + { + if (w->id == id) + { + p->next = w->next; + free (w); + return; + } + } +} + guint g_io_add_watch (GIOChannel *channel, GIOCondition condition, GIOFunc func, diff --git a/hcid/glib-ectomy.h b/hcid/glib-ectomy.h index b1ac263b..703ae54b 100644 --- a/hcid/glib-ectomy.h +++ b/hcid/glib-ectomy.h @@ -92,6 +92,8 @@ guint g_io_add_watch (GIOChannel *channel, GIOCondition condition, GIOFunc func, gpointer user_data); +void g_io_remove_watch (guint id); + GMainLoop *g_main_loop_new (GMainContext *context, diff --git a/hcid/hcid.h b/hcid/hcid.h index 3bd0ad46..f8233d70 100644 --- a/hcid/hcid.h +++ b/hcid/hcid.h @@ -76,6 +76,7 @@ struct hcid_opts { int pin_len; char *pin_helper; char *pin_file; + int dbus_pin_helper; char *key_file; @@ -102,3 +103,8 @@ void init_security_data(void); void start_security_manager(int hdev); void stop_security_manager(int hdev); void toggle_pairing(int enable); + +#ifdef ENABLE_DBUS +void hcid_dbus_request_pin(int dev, struct hci_conn_info *ci); +gboolean hcid_dbus_init(void); +#endif diff --git a/hcid/kword.c b/hcid/kword.c index 0486f21b..09ad0573 100644 --- a/hcid/kword.c +++ b/hcid/kword.c @@ -26,58 +26,64 @@ #include #include +#include + +#include +#include +#include #include "hcid.h" #include "kword.h" #include "parser.h" struct kword cfg_keyword[] = { - { "options", K_OPTIONS }, - { "default", K_DEVICE }, - { "device", K_DEVICE }, - { "autoinit", K_AUTOINIT }, - { "security", K_SECURITY }, - { "pairing", K_PAIRING }, - { "pkt_type", K_PTYPE }, - { "lm", K_LM }, - { "lp", K_LP }, - { "iscan", K_ISCAN }, - { "pscan", K_PSCAN }, - { "name", K_NAME }, - { "class", K_CLASS }, - { "auth", K_AUTH }, - { "encrypt", K_ENCRYPT }, - { "pin_helper", K_PINHELP }, + { "options", K_OPTIONS }, + { "default", K_DEVICE }, + { "device", K_DEVICE }, + { "autoinit", K_AUTOINIT }, + { "security", K_SECURITY }, + { "pairing", K_PAIRING }, + { "pkt_type", K_PTYPE }, + { "lm", K_LM }, + { "lp", K_LP }, + { "iscan", K_ISCAN }, + { "pscan", K_PSCAN }, + { "name", K_NAME }, + { "class", K_CLASS }, + { "auth", K_AUTH }, + { "encrypt", K_ENCRYPT }, + { "pin_helper", K_PINHELP }, + { "dbus_pin_helper", K_DBUSPINHELP }, - { "yes", K_YES }, - { "no", K_NO }, - { "enable", K_YES }, - { "disable", K_NO }, - { NULL , 0 } + { "yes", K_YES }, + { "no", K_NO }, + { "enable", K_YES }, + { "disable", K_NO }, + { NULL , 0 } }; struct kword sec_param[] = { - { "none", HCID_SEC_NONE }, - { "auto", HCID_SEC_AUTO }, - { "user", HCID_SEC_USER }, - { NULL , 0 } + { "none", HCID_SEC_NONE }, + { "auto", HCID_SEC_AUTO }, + { "user", HCID_SEC_USER }, + { NULL , 0 } }; struct kword pair_param[] = { - { "none", HCID_PAIRING_NONE }, - { "multi", HCID_PAIRING_MULTI }, - { "once", HCID_PAIRING_ONCE }, - { NULL , 0 } + { "none", HCID_PAIRING_NONE }, + { "multi", HCID_PAIRING_MULTI }, + { "once", HCID_PAIRING_ONCE }, + { NULL , 0 } }; int lineno; int find_keyword(struct kword *kw, char *str) { - while( kw->str ){ - if( !strcmp(str,kw->str) ) - return kw->type; - kw++; - } - return -1; + while (kw->str) { + if (!strcmp(str,kw->str)) + return kw->type; + kw++; + } + return -1; } diff --git a/hcid/kword.h b/hcid/kword.h index 10c54493..67baaf13 100644 --- a/hcid/kword.h +++ b/hcid/kword.h @@ -1,32 +1,32 @@ /* - BlueZ - Bluetooth protocol stack for Linux - Copyright (C) 2000-2001 Qualcomm Incorporated - - Written 2000,2001 by Maxim Krasnyansky - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License version 2 as - published by the Free Software Foundation; - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. - IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY CLAIM, - OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER - RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, - NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE - USE OR PERFORMANCE OF THIS SOFTWARE. - - ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, COPYRIGHTS, - TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS SOFTWARE IS DISCLAIMED. + BlueZ - Bluetooth protocol stack for Linux + Copyright (C) 2000-2001 Qualcomm Incorporated + + Written 2000,2001 by Maxim Krasnyansky + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License version 2 as + published by the Free Software Foundation; + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. + IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY CLAIM, + OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER + RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE + USE OR PERFORMANCE OF THIS SOFTWARE. + + ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, COPYRIGHTS, + TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS SOFTWARE IS DISCLAIMED. */ /* * $Id$ */ struct kword { - char *str; - int type; + char *str; + int type; }; extern int lineno; diff --git a/hcid/lexer.l b/hcid/lexer.l index 1947bcd4..3c9ed308 100644 --- a/hcid/lexer.l +++ b/hcid/lexer.l @@ -27,6 +27,11 @@ */ #include +#include + +#include +#include +#include #include "hcid.h" #include "kword.h" diff --git a/hcid/lib.c b/hcid/lib.c index 2e310012..bb85feb4 100644 --- a/hcid/lib.c +++ b/hcid/lib.c @@ -32,6 +32,10 @@ #include #include +#include +#include +#include + #include "hcid.h" #include "lib.h" diff --git a/hcid/main.c b/hcid/main.c index d5c52c9d..c3f4131d 100644 --- a/hcid/main.c +++ b/hcid/main.c @@ -541,6 +541,18 @@ int main(int argc, char *argv[], char *env[]) if (read_config(hcid.config_file) < 0) syslog(LOG_ERR, "Config load failed"); +#ifdef ENABLE_DBUS + if (hcid_dbus_init() == FALSE && hcid.dbus_pin_helper) { + syslog(LOG_ERR, "Unable to get on D-BUS"); + exit(1); + } +#else + if (hcid.dbus_pin_helper) { + syslog(LOG_ERR, "D-BUS not configured in this build of hcid"); + exit(1); + } +#endif + init_security_data(); /* Create event loop */ diff --git a/hcid/parser.y b/hcid/parser.y index e14ca200..1848bd04 100644 --- a/hcid/parser.y +++ b/hcid/parser.y @@ -58,7 +58,7 @@ int yyerror(char *s); %token K_OPTIONS K_DEVICE %token K_AUTOINIT K_SECURITY K_PAIRING %token K_PTYPE K_NAME K_CLASS K_LM K_LP K_AUTH K_ENCRYPT K_ISCAN K_PSCAN -%token K_PINHELP +%token K_PINHELP K_DBUSPINHELP %token K_YES K_NO %token WORD PATH STRING LIST HCI BDADDR @@ -112,10 +112,18 @@ hcid_opt: hcid.pairing = $2; } - | K_PINHELP PATH { + | K_PINHELP PATH { if (hcid.pin_helper) free(hcid.pin_helper); hcid.pin_helper = strdup($2); + hcid.dbus_pin_helper = 0; + } + + | K_DBUSPINHELP { + if (hcid.pin_helper) + free(hcid.pin_helper); + hcid.pin_helper = NULL; + hcid.dbus_pin_helper = 1; } | WORD { diff --git a/hcid/security.c b/hcid/security.c index 7aa9a7a4..189bc7d8 100644 --- a/hcid/security.c +++ b/hcid/security.c @@ -173,7 +173,7 @@ static void link_key_notify(int dev, bdaddr_t *sba, void *ptr) evt_link_key_notify *evt = ptr; bdaddr_t *dba = &evt->bdaddr; struct link_key key; - char sa[18]; + char sa[18]; ba2str(sba, sa); syslog(LOG_INFO, "link_key_notify (sba=%s)\n", sa); @@ -291,6 +291,17 @@ reject: exit(0); } +static void request_pin(int dev, struct hci_conn_info *ci) +{ +#ifdef ENABLE_DBUS + if (hcid.dbus_pin_helper) { + hcid_dbus_request_pin(dev, ci); + return; + } +#endif + call_pin_helper(dev, ci); +} + static void pin_code_request(int dev, bdaddr_t *sba, bdaddr_t *dba) { struct hci_conn_info_req *cr; @@ -337,11 +348,11 @@ static void pin_code_request(int dev, bdaddr_t *sba, bdaddr_t *dba) /* Outgoing connection */ /* Let PIN helper handle that */ - call_pin_helper(dev, ci); + request_pin(dev, ci); } } else { /* Let PIN helper handle that */ - call_pin_helper(dev, ci); + request_pin(dev, ci); } free(cr); return; @@ -397,7 +408,7 @@ gboolean io_security_event(GIOChannel *chan, GIOCondition cond, gpointer data) link_key_notify(dev, &di->bdaddr, ptr); break; } - + return TRUE; } @@ -410,7 +421,7 @@ void start_security_manager(int hdev) if (chan) return; - + syslog(LOG_INFO, "Starting security manager %d", hdev); if ((dev = hci_open_dev(hdev)) < 0) { -- cgit