agent.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. *
  4. * BlueZ - Bluetooth protocol stack for Linux
  5. *
  6. * Copyright (C) 2012 Intel Corporation. All rights reserved.
  7. *
  8. *
  9. */
  10. #ifdef HAVE_CONFIG_H
  11. #include <config.h>
  12. #endif
  13. #include <stdio.h>
  14. #include <stdlib.h>
  15. #include <stdbool.h>
  16. #include <unistd.h>
  17. #include <string.h>
  18. #include <glib.h>
  19. #include "src/shared/shell.h"
  20. #include "gdbus/gdbus.h"
  21. #include "agent.h"
  22. #define AGENT_PATH "/org/bluez/agent"
  23. #define AGENT_INTERFACE "org.bluez.Agent1"
  24. #define AGENT_PROMPT COLOR_RED "[agent]" COLOR_OFF " "
  25. static gboolean agent_registered = FALSE;
  26. static const char *agent_capability = NULL;
  27. static DBusMessage *pending_message = NULL;
  28. static void agent_release_prompt(void)
  29. {
  30. if (!pending_message)
  31. return;
  32. bt_shell_release_prompt("");
  33. }
  34. dbus_bool_t agent_completion(void)
  35. {
  36. if (!pending_message)
  37. return FALSE;
  38. return TRUE;
  39. }
  40. static void pincode_response(const char *input, void *user_data)
  41. {
  42. DBusConnection *conn = user_data;
  43. g_dbus_send_reply(conn, pending_message, DBUS_TYPE_STRING, &input,
  44. DBUS_TYPE_INVALID);
  45. }
  46. static void passkey_response(const char *input, void *user_data)
  47. {
  48. DBusConnection *conn = user_data;
  49. dbus_uint32_t passkey;
  50. if (sscanf(input, "%u", &passkey) == 1)
  51. g_dbus_send_reply(conn, pending_message, DBUS_TYPE_UINT32,
  52. &passkey, DBUS_TYPE_INVALID);
  53. else if (!strcmp(input, "no"))
  54. g_dbus_send_error(conn, pending_message,
  55. "org.bluez.Error.Rejected", NULL);
  56. else
  57. g_dbus_send_error(conn, pending_message,
  58. "org.bluez.Error.Canceled", NULL);
  59. }
  60. static void confirm_response(const char *input, void *user_data)
  61. {
  62. DBusConnection *conn = user_data;
  63. if (!strcmp(input, "yes"))
  64. g_dbus_send_reply(conn, pending_message, DBUS_TYPE_INVALID);
  65. else if (!strcmp(input, "no"))
  66. g_dbus_send_error(conn, pending_message,
  67. "org.bluez.Error.Rejected", NULL);
  68. else
  69. g_dbus_send_error(conn, pending_message,
  70. "org.bluez.Error.Canceled", NULL);
  71. }
  72. static void agent_release(DBusConnection *conn)
  73. {
  74. agent_registered = FALSE;
  75. agent_capability = NULL;
  76. if (pending_message) {
  77. dbus_message_unref(pending_message);
  78. pending_message = NULL;
  79. }
  80. agent_release_prompt();
  81. g_dbus_unregister_interface(conn, AGENT_PATH, AGENT_INTERFACE);
  82. }
  83. static DBusMessage *release_agent(DBusConnection *conn,
  84. DBusMessage *msg, void *user_data)
  85. {
  86. bt_shell_printf("Agent released\n");
  87. agent_release(conn);
  88. return dbus_message_new_method_return(msg);
  89. }
  90. static DBusMessage *request_pincode(DBusConnection *conn,
  91. DBusMessage *msg, void *user_data)
  92. {
  93. const char *device;
  94. bt_shell_printf("Request PIN code\n");
  95. dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &device,
  96. DBUS_TYPE_INVALID);
  97. bt_shell_prompt_input("agent", "Enter PIN code:", pincode_response,
  98. conn);
  99. pending_message = dbus_message_ref(msg);
  100. return NULL;
  101. }
  102. static DBusMessage *display_pincode(DBusConnection *conn,
  103. DBusMessage *msg, void *user_data)
  104. {
  105. const char *device;
  106. const char *pincode;
  107. dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &device,
  108. DBUS_TYPE_STRING, &pincode, DBUS_TYPE_INVALID);
  109. bt_shell_printf(AGENT_PROMPT "PIN code: %s\n", pincode);
  110. return dbus_message_new_method_return(msg);
  111. }
  112. static DBusMessage *request_passkey(DBusConnection *conn,
  113. DBusMessage *msg, void *user_data)
  114. {
  115. const char *device;
  116. bt_shell_printf("Request passkey\n");
  117. dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &device,
  118. DBUS_TYPE_INVALID);
  119. bt_shell_prompt_input("agent", "Enter passkey (number in 0-999999):",
  120. passkey_response, conn);
  121. pending_message = dbus_message_ref(msg);
  122. return NULL;
  123. }
  124. static DBusMessage *display_passkey(DBusConnection *conn,
  125. DBusMessage *msg, void *user_data)
  126. {
  127. const char *device;
  128. dbus_uint32_t passkey;
  129. dbus_uint16_t entered;
  130. char passkey_full[7];
  131. dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &device,
  132. DBUS_TYPE_UINT32, &passkey, DBUS_TYPE_UINT16, &entered,
  133. DBUS_TYPE_INVALID);
  134. snprintf(passkey_full, sizeof(passkey_full), "%.6u", passkey);
  135. passkey_full[6] = '\0';
  136. if (entered > strlen(passkey_full))
  137. entered = strlen(passkey_full);
  138. bt_shell_printf(AGENT_PROMPT "Passkey: "
  139. COLOR_BOLDGRAY "%.*s" COLOR_BOLDWHITE "%s\n" COLOR_OFF,
  140. entered, passkey_full, passkey_full + entered);
  141. return dbus_message_new_method_return(msg);
  142. }
  143. static DBusMessage *request_confirmation(DBusConnection *conn,
  144. DBusMessage *msg, void *user_data)
  145. {
  146. const char *device;
  147. dbus_uint32_t passkey;
  148. char *str;
  149. bt_shell_printf("Request confirmation\n");
  150. dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &device,
  151. DBUS_TYPE_UINT32, &passkey, DBUS_TYPE_INVALID);
  152. str = g_strdup_printf("Confirm passkey %06u (yes/no):", passkey);
  153. bt_shell_prompt_input("agent", str, confirm_response, conn);
  154. g_free(str);
  155. pending_message = dbus_message_ref(msg);
  156. return NULL;
  157. }
  158. static DBusMessage *request_authorization(DBusConnection *conn,
  159. DBusMessage *msg, void *user_data)
  160. {
  161. const char *device;
  162. bt_shell_printf("Request authorization\n");
  163. dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &device,
  164. DBUS_TYPE_INVALID);
  165. bt_shell_prompt_input("agent", "Accept pairing (yes/no):",
  166. confirm_response, conn);
  167. pending_message = dbus_message_ref(msg);
  168. return NULL;
  169. }
  170. static DBusMessage *authorize_service(DBusConnection *conn,
  171. DBusMessage *msg, void *user_data)
  172. {
  173. const char *device, *uuid;
  174. char *str;
  175. bt_shell_printf("Authorize service\n");
  176. dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &device,
  177. DBUS_TYPE_STRING, &uuid, DBUS_TYPE_INVALID);
  178. str = g_strdup_printf("Authorize service %s (yes/no):", uuid);
  179. bt_shell_prompt_input("agent", str, confirm_response, conn);
  180. g_free(str);
  181. pending_message = dbus_message_ref(msg);
  182. return NULL;
  183. }
  184. static DBusMessage *cancel_request(DBusConnection *conn,
  185. DBusMessage *msg, void *user_data)
  186. {
  187. bt_shell_printf("Request canceled\n");
  188. agent_release_prompt();
  189. dbus_message_unref(pending_message);
  190. pending_message = NULL;
  191. return dbus_message_new_method_return(msg);
  192. }
  193. static const GDBusMethodTable methods[] = {
  194. { GDBUS_METHOD("Release", NULL, NULL, release_agent) },
  195. { GDBUS_ASYNC_METHOD("RequestPinCode",
  196. GDBUS_ARGS({ "device", "o" }),
  197. GDBUS_ARGS({ "pincode", "s" }), request_pincode) },
  198. { GDBUS_METHOD("DisplayPinCode",
  199. GDBUS_ARGS({ "device", "o" }, { "pincode", "s" }),
  200. NULL, display_pincode) },
  201. { GDBUS_ASYNC_METHOD("RequestPasskey",
  202. GDBUS_ARGS({ "device", "o" }),
  203. GDBUS_ARGS({ "passkey", "u" }), request_passkey) },
  204. { GDBUS_METHOD("DisplayPasskey",
  205. GDBUS_ARGS({ "device", "o" }, { "passkey", "u" },
  206. { "entered", "q" }),
  207. NULL, display_passkey) },
  208. { GDBUS_ASYNC_METHOD("RequestConfirmation",
  209. GDBUS_ARGS({ "device", "o" }, { "passkey", "u" }),
  210. NULL, request_confirmation) },
  211. { GDBUS_ASYNC_METHOD("RequestAuthorization",
  212. GDBUS_ARGS({ "device", "o" }),
  213. NULL, request_authorization) },
  214. { GDBUS_ASYNC_METHOD("AuthorizeService",
  215. GDBUS_ARGS({ "device", "o" }, { "uuid", "s" }),
  216. NULL, authorize_service) },
  217. { GDBUS_METHOD("Cancel", NULL, NULL, cancel_request) },
  218. { }
  219. };
  220. static void register_agent_setup(DBusMessageIter *iter, void *user_data)
  221. {
  222. const char *path = AGENT_PATH;
  223. const char *capability = agent_capability;
  224. dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &path);
  225. dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &capability);
  226. }
  227. static void register_agent_reply(DBusMessage *message, void *user_data)
  228. {
  229. DBusConnection *conn = user_data;
  230. DBusError error;
  231. dbus_error_init(&error);
  232. if (dbus_set_error_from_message(&error, message) == FALSE) {
  233. agent_registered = TRUE;
  234. bt_shell_printf("Agent registered\n");
  235. } else {
  236. bt_shell_printf("Failed to register agent: %s\n", error.name);
  237. dbus_error_free(&error);
  238. if (g_dbus_unregister_interface(conn, AGENT_PATH,
  239. AGENT_INTERFACE) == FALSE)
  240. bt_shell_printf("Failed to unregister agent object\n");
  241. }
  242. }
  243. void agent_register(DBusConnection *conn, GDBusProxy *manager,
  244. const char *capability)
  245. {
  246. if (agent_registered == TRUE) {
  247. bt_shell_printf("Agent is already registered\n");
  248. return;
  249. }
  250. agent_capability = capability;
  251. if (g_dbus_register_interface(conn, AGENT_PATH,
  252. AGENT_INTERFACE, methods,
  253. NULL, NULL, NULL, NULL) == FALSE) {
  254. bt_shell_printf("Failed to register agent object\n");
  255. return;
  256. }
  257. if (g_dbus_proxy_method_call(manager, "RegisterAgent",
  258. register_agent_setup,
  259. register_agent_reply,
  260. conn, NULL) == FALSE) {
  261. bt_shell_printf("Failed to call register agent method\n");
  262. return;
  263. }
  264. agent_capability = NULL;
  265. }
  266. static void unregister_agent_setup(DBusMessageIter *iter, void *user_data)
  267. {
  268. const char *path = AGENT_PATH;
  269. dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &path);
  270. }
  271. static void unregister_agent_reply(DBusMessage *message, void *user_data)
  272. {
  273. DBusConnection *conn = user_data;
  274. DBusError error;
  275. dbus_error_init(&error);
  276. if (dbus_set_error_from_message(&error, message) == FALSE) {
  277. bt_shell_printf("Agent unregistered\n");
  278. agent_release(conn);
  279. } else {
  280. bt_shell_printf("Failed to unregister agent: %s\n", error.name);
  281. dbus_error_free(&error);
  282. }
  283. }
  284. void agent_unregister(DBusConnection *conn, GDBusProxy *manager)
  285. {
  286. if (agent_registered == FALSE) {
  287. bt_shell_printf("No agent is registered\n");
  288. return;
  289. }
  290. if (!manager) {
  291. bt_shell_printf("Agent unregistered\n");
  292. agent_release(conn);
  293. return;
  294. }
  295. if (g_dbus_proxy_method_call(manager, "UnregisterAgent",
  296. unregister_agent_setup,
  297. unregister_agent_reply,
  298. conn, NULL) == FALSE) {
  299. bt_shell_printf("Failed to call unregister agent method\n");
  300. return;
  301. }
  302. }
  303. static void request_default_setup(DBusMessageIter *iter, void *user_data)
  304. {
  305. const char *path = AGENT_PATH;
  306. dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &path);
  307. }
  308. static void request_default_reply(DBusMessage *message, void *user_data)
  309. {
  310. DBusError error;
  311. dbus_error_init(&error);
  312. if (dbus_set_error_from_message(&error, message) == TRUE) {
  313. bt_shell_printf("Failed to request default agent: %s\n",
  314. error.name);
  315. dbus_error_free(&error);
  316. return bt_shell_noninteractive_quit(EXIT_FAILURE);
  317. }
  318. bt_shell_printf("Default agent request successful\n");
  319. return bt_shell_noninteractive_quit(EXIT_SUCCESS);
  320. }
  321. void agent_default(DBusConnection *conn, GDBusProxy *manager)
  322. {
  323. if (agent_registered == FALSE) {
  324. bt_shell_printf("No agent is registered\n");
  325. return bt_shell_noninteractive_quit(EXIT_FAILURE);
  326. }
  327. if (g_dbus_proxy_method_call(manager, "RequestDefaultAgent",
  328. request_default_setup,
  329. request_default_reply,
  330. NULL, NULL) == FALSE) {
  331. bt_shell_printf("Failed to call RequestDefaultAgent method\n");
  332. return bt_shell_noninteractive_quit(EXIT_FAILURE);
  333. }
  334. }