3 * BlueZ - Bluetooth protocol stack for Linux
5 * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
36 #include <dbus/dbus.h>
38 static char *passkey_value = NULL;
39 static int passkey_delay = 0;
40 static int do_reject = 0;
42 static volatile sig_atomic_t __io_canceled = 0;
43 static volatile sig_atomic_t __io_terminated = 0;
44 static volatile sig_atomic_t exit_on_release = 1;
46 static void sig_term(int sig)
51 static DBusHandlerResult agent_filter(DBusConnection *conn,
52 DBusMessage *msg, void *data)
54 const char *name, *old, *new;
56 if (!dbus_message_is_signal(msg, DBUS_INTERFACE_DBUS,
58 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
60 if (!dbus_message_get_args(msg, NULL,
61 DBUS_TYPE_STRING, &name,
62 DBUS_TYPE_STRING, &old,
63 DBUS_TYPE_STRING, &new,
65 fprintf(stderr, "Invalid arguments for NameOwnerChanged signal");
66 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
69 if (!strcmp(name, "org.bluez") && *new == '\0') {
70 fprintf(stderr, "Agent has been terminated\n");
74 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
77 static DBusHandlerResult request_pincode_message(DBusConnection *conn,
78 DBusMessage *msg, void *data)
84 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
86 if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
88 fprintf(stderr, "Invalid arguments for RequestPinCode method");
89 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
93 reply = dbus_message_new_error(msg, "org.bluez.Error.Rejected", "");
97 reply = dbus_message_new_method_return(msg);
99 fprintf(stderr, "Can't create reply message\n");
100 return DBUS_HANDLER_RESULT_NEED_MEMORY;
103 printf("Pincode request for device %s\n", path);
106 printf("Waiting for %d seconds\n", passkey_delay);
107 sleep(passkey_delay);
110 dbus_message_append_args(reply, DBUS_TYPE_STRING, &passkey_value,
114 dbus_connection_send(conn, reply, NULL);
116 dbus_connection_flush(conn);
118 dbus_message_unref(reply);
120 return DBUS_HANDLER_RESULT_HANDLED;
123 static DBusHandlerResult request_passkey_message(DBusConnection *conn,
124 DBusMessage *msg, void *data)
128 unsigned int passkey;
131 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
133 if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
134 DBUS_TYPE_INVALID)) {
135 fprintf(stderr, "Invalid arguments for RequestPasskey method");
136 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
140 reply = dbus_message_new_error(msg, "org.bluez.Error.Rejected", "");
144 reply = dbus_message_new_method_return(msg);
146 fprintf(stderr, "Can't create reply message\n");
147 return DBUS_HANDLER_RESULT_NEED_MEMORY;
150 printf("Passkey request for device %s\n", path);
153 printf("Waiting for %d seconds\n", passkey_delay);
154 sleep(passkey_delay);
157 passkey = strtoul(passkey_value, NULL, 10);
159 dbus_message_append_args(reply, DBUS_TYPE_UINT32, &passkey,
163 dbus_connection_send(conn, reply, NULL);
165 dbus_connection_flush(conn);
167 dbus_message_unref(reply);
169 return DBUS_HANDLER_RESULT_HANDLED;
172 static DBusHandlerResult request_confirmation_message(DBusConnection *conn,
173 DBusMessage *msg, void *data)
177 unsigned int passkey;
179 if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
180 DBUS_TYPE_UINT32, &passkey,
181 DBUS_TYPE_INVALID)) {
182 fprintf(stderr, "Invalid arguments for RequestPasskey method");
183 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
187 reply = dbus_message_new_error(msg, "org.bluez.Error.Rejected", "");
191 reply = dbus_message_new_method_return(msg);
193 fprintf(stderr, "Can't create reply message\n");
194 return DBUS_HANDLER_RESULT_NEED_MEMORY;
197 printf("Confirmation request of %u for device %s\n", passkey, path);
200 printf("Waiting for %d seconds\n", passkey_delay);
201 sleep(passkey_delay);
205 dbus_connection_send(conn, reply, NULL);
207 dbus_connection_flush(conn);
209 dbus_message_unref(reply);
211 return DBUS_HANDLER_RESULT_HANDLED;
214 static DBusHandlerResult authorize_message(DBusConnection *conn,
215 DBusMessage *msg, void *data)
218 const char *path, *uuid;
220 if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
221 DBUS_TYPE_STRING, &uuid,
222 DBUS_TYPE_INVALID)) {
223 fprintf(stderr, "Invalid arguments for Authorize method");
224 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
228 reply = dbus_message_new_error(msg, "org.bluez.Error.Rejected", "");
232 reply = dbus_message_new_method_return(msg);
234 fprintf(stderr, "Can't create reply message\n");
235 return DBUS_HANDLER_RESULT_NEED_MEMORY;
238 printf("Authorizing request for %s\n", path);
241 dbus_connection_send(conn, reply, NULL);
243 dbus_connection_flush(conn);
245 dbus_message_unref(reply);
247 return DBUS_HANDLER_RESULT_HANDLED;
250 static DBusHandlerResult cancel_message(DBusConnection *conn,
251 DBusMessage *msg, void *data)
255 if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_INVALID)) {
256 fprintf(stderr, "Invalid arguments for passkey Confirm method");
257 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
260 printf("Request canceled\n");
262 reply = dbus_message_new_method_return(msg);
264 fprintf(stderr, "Can't create reply message\n");
265 return DBUS_HANDLER_RESULT_NEED_MEMORY;
268 dbus_connection_send(conn, reply, NULL);
270 dbus_connection_flush(conn);
272 dbus_message_unref(reply);
274 return DBUS_HANDLER_RESULT_HANDLED;
277 static DBusHandlerResult release_message(DBusConnection *conn,
278 DBusMessage *msg, void *data)
282 if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_INVALID)) {
283 fprintf(stderr, "Invalid arguments for Release method");
284 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
288 fprintf(stderr, "Agent has been released\n");
293 reply = dbus_message_new_method_return(msg);
295 fprintf(stderr, "Can't create reply message\n");
296 return DBUS_HANDLER_RESULT_NEED_MEMORY;
299 dbus_connection_send(conn, reply, NULL);
301 dbus_connection_flush(conn);
303 dbus_message_unref(reply);
305 return DBUS_HANDLER_RESULT_HANDLED;
308 static DBusHandlerResult agent_message(DBusConnection *conn,
309 DBusMessage *msg, void *data)
311 if (dbus_message_is_method_call(msg, "org.bluez.Agent",
313 return request_pincode_message(conn, msg, data);
315 if (dbus_message_is_method_call(msg, "org.bluez.Agent",
317 return request_passkey_message(conn, msg, data);
319 if (dbus_message_is_method_call(msg, "org.bluez.Agent",
320 "RequestConfirmation"))
321 return request_confirmation_message(conn, msg, data);
323 if (dbus_message_is_method_call(msg, "org.bluez.Agent", "Authorize"))
324 return authorize_message(conn, msg, data);
326 if (dbus_message_is_method_call(msg, "org.bluez.Agent", "Cancel"))
327 return cancel_message(conn, msg, data);
329 if (dbus_message_is_method_call(msg, "org.bluez.Agent", "Release"))
330 return release_message(conn, msg, data);
332 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
335 static const DBusObjectPathVTable agent_table = {
336 .message_function = agent_message,
339 static int register_agent(DBusConnection *conn, const char *adapter_path,
340 const char *agent_path,
341 const char *capabilities)
343 DBusMessage *msg, *reply;
346 msg = dbus_message_new_method_call("org.bluez", adapter_path,
347 "org.bluez.Adapter", "RegisterAgent");
349 fprintf(stderr, "Can't allocate new method call\n");
353 dbus_message_append_args(msg, DBUS_TYPE_OBJECT_PATH, &agent_path,
354 DBUS_TYPE_STRING, &capabilities,
357 dbus_error_init(&err);
359 reply = dbus_connection_send_with_reply_and_block(conn, msg, -1, &err);
361 dbus_message_unref(msg);
364 fprintf(stderr, "Can't register agent\n");
365 if (dbus_error_is_set(&err)) {
366 fprintf(stderr, "%s\n", err.message);
367 dbus_error_free(&err);
372 dbus_message_unref(reply);
374 dbus_connection_flush(conn);
379 static int unregister_agent(DBusConnection *conn, const char *adapter_path,
380 const char *agent_path)
382 DBusMessage *msg, *reply;
385 msg = dbus_message_new_method_call("org.bluez", adapter_path,
386 "org.bluez.Adapter", "UnregisterAgent");
388 fprintf(stderr, "Can't allocate new method call\n");
392 dbus_message_append_args(msg, DBUS_TYPE_OBJECT_PATH, &agent_path,
395 dbus_error_init(&err);
397 reply = dbus_connection_send_with_reply_and_block(conn, msg, -1, &err);
399 dbus_message_unref(msg);
402 fprintf(stderr, "Can't unregister agent\n");
403 if (dbus_error_is_set(&err)) {
404 fprintf(stderr, "%s\n", err.message);
405 dbus_error_free(&err);
410 dbus_message_unref(reply);
412 dbus_connection_flush(conn);
414 dbus_connection_unregister_object_path(conn, agent_path);
419 static void create_paired_device_reply(DBusPendingCall *pending,
426 static int create_paired_device(DBusConnection *conn, const char *adapter_path,
427 const char *agent_path,
428 const char *capabilities,
433 DBusPendingCall *pending;
435 msg = dbus_message_new_method_call("org.bluez", adapter_path,
437 "CreatePairedDevice");
439 fprintf(stderr, "Can't allocate new method call\n");
443 dbus_message_append_args(msg, DBUS_TYPE_STRING, &device,
444 DBUS_TYPE_OBJECT_PATH, &agent_path,
445 DBUS_TYPE_STRING, &capabilities,
449 success = dbus_connection_send_with_reply(conn, msg, &pending, -1);
451 dbus_pending_call_set_notify(pending,
452 create_paired_device_reply,
455 dbus_message_unref(msg);
458 fprintf(stderr, "Not enough memory for message send\n");
462 dbus_connection_flush(conn);
467 static char *get_default_adapter_path(DBusConnection *conn)
469 DBusMessage *msg, *reply;
471 const char *reply_path;
474 msg = dbus_message_new_method_call("org.bluez", "/",
475 "org.bluez.Manager", "DefaultAdapter");
478 fprintf(stderr, "Can't allocate new method call\n");
482 dbus_error_init(&err);
484 reply = dbus_connection_send_with_reply_and_block(conn, msg, -1, &err);
486 dbus_message_unref(msg);
490 "Can't get default adapter\n");
491 if (dbus_error_is_set(&err)) {
492 fprintf(stderr, "%s\n", err.message);
493 dbus_error_free(&err);
498 if (!dbus_message_get_args(reply, &err,
499 DBUS_TYPE_OBJECT_PATH, &reply_path,
500 DBUS_TYPE_INVALID)) {
502 "Can't get reply arguments\n");
503 if (dbus_error_is_set(&err)) {
504 fprintf(stderr, "%s\n", err.message);
505 dbus_error_free(&err);
507 dbus_message_unref(reply);
511 path = strdup(reply_path);
513 dbus_message_unref(reply);
515 dbus_connection_flush(conn);
520 static char *get_adapter_path(DBusConnection *conn, const char *adapter)
522 DBusMessage *msg, *reply;
524 const char *reply_path;
528 return get_default_adapter_path(conn);
530 msg = dbus_message_new_method_call("org.bluez", "/",
531 "org.bluez.Manager", "FindAdapter");
534 fprintf(stderr, "Can't allocate new method call\n");
538 dbus_message_append_args(msg, DBUS_TYPE_STRING, &adapter,
541 dbus_error_init(&err);
543 reply = dbus_connection_send_with_reply_and_block(conn, msg, -1, &err);
545 dbus_message_unref(msg);
549 "Can't find adapter %s\n", adapter);
550 if (dbus_error_is_set(&err)) {
551 fprintf(stderr, "%s\n", err.message);
552 dbus_error_free(&err);
557 if (!dbus_message_get_args(reply, &err,
558 DBUS_TYPE_OBJECT_PATH, &reply_path,
559 DBUS_TYPE_INVALID)) {
561 "Can't get reply arguments\n");
562 if (dbus_error_is_set(&err)) {
563 fprintf(stderr, "%s\n", err.message);
564 dbus_error_free(&err);
566 dbus_message_unref(reply);
570 path = strdup(reply_path);
572 dbus_message_unref(reply);
574 dbus_connection_flush(conn);
579 static void usage(void)
581 printf("Bluetooth agent ver %s\n\n", VERSION);
584 "\tagent [--adapter adapter-path] [--path agent-path] <passkey> [<device>]\n"
588 static struct option main_options[] = {
589 { "adapter", 1, 0, 'a' },
590 { "path", 1, 0, 'p' },
591 { "capabilites",1, 0, 'c' },
592 { "delay", 1, 0, 'd' },
593 { "reject", 0, 0, 'r' },
594 { "help", 0, 0, 'h' },
598 int main(int argc, char *argv[])
600 const char *capabilities = "DisplayYesNo";
602 DBusConnection *conn;
603 char match_string[128], default_path[128], *adapter_id = NULL;
604 char *adapter_path = NULL, *agent_path = NULL, *device = NULL;
607 snprintf(default_path, sizeof(default_path),
608 "/org/bluez/agent_%d", getpid());
610 while ((opt = getopt_long(argc, argv, "+a:p:c:d:rh", main_options, NULL)) != EOF) {
616 if (optarg[0] != '/') {
617 fprintf(stderr, "Invalid path\n");
620 agent_path = strdup(optarg);
623 capabilities = optarg;
626 passkey_delay = atoi(optarg);
648 passkey_value = strdup(argv[0]);
651 device = strdup(argv[1]);
654 agent_path = strdup(default_path);
656 conn = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
658 fprintf(stderr, "Can't get on system bus");
662 adapter_path = get_adapter_path(conn, adapter_id);
666 if (!dbus_connection_register_object_path(conn, agent_path,
667 &agent_table, NULL)) {
668 fprintf(stderr, "Can't register object path for agent\n");
673 if (create_paired_device(conn, adapter_path, agent_path,
674 capabilities, device) < 0) {
675 dbus_connection_unref(conn);
679 if (register_agent(conn, adapter_path, agent_path,
681 dbus_connection_unref(conn);
686 if (!dbus_connection_add_filter(conn, agent_filter, NULL, NULL))
687 fprintf(stderr, "Can't add signal filter");
689 snprintf(match_string, sizeof(match_string),
690 "interface=%s,member=NameOwnerChanged,arg0=%s",
691 DBUS_INTERFACE_DBUS, "org.bluez");
693 dbus_bus_add_match(conn, match_string, NULL);
695 memset(&sa, 0, sizeof(sa));
696 sa.sa_flags = SA_NOCLDSTOP;
697 sa.sa_handler = sig_term;
698 sigaction(SIGTERM, &sa, NULL);
699 sigaction(SIGINT, &sa, NULL);
701 while (!__io_canceled && !__io_terminated) {
702 if (dbus_connection_read_write_dispatch(conn, 500) != TRUE)
706 if (!__io_terminated && !device)
707 unregister_agent(conn, adapter_path, agent_path);
714 dbus_connection_unref(conn);