dbus_new_helpers.c 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083
  1. /*
  2. * WPA Supplicant / dbus-based control interface
  3. * Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc.
  4. * Copyright (c) 2009, Witold Sowa <witold.sowa@gmail.com>
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License version 2 as
  8. * published by the Free Software Foundation.
  9. *
  10. * Alternatively, this software may be distributed under the terms of BSD
  11. * license.
  12. *
  13. * See README and COPYING for more details.
  14. */
  15. #include "includes.h"
  16. #include "common.h"
  17. #include "dbus_common.h"
  18. #include "dbus_common_i.h"
  19. #include "dbus_new_helpers.h"
  20. /**
  21. * recursive_iter_copy - Reads arguments from one iterator and
  22. * writes to another recursively
  23. * @from: iterator to read from
  24. * @to: iterator to write to
  25. *
  26. * Copies one iterator's elements to another. If any element in
  27. * iterator is of container type, its content is copied recursively
  28. */
  29. static void recursive_iter_copy(DBusMessageIter *from, DBusMessageIter *to)
  30. {
  31. char *subtype = NULL;
  32. int type;
  33. /* iterate over iterator to copy */
  34. while ((type = dbus_message_iter_get_arg_type (from)) !=
  35. DBUS_TYPE_INVALID) {
  36. /* simply copy basic type entries */
  37. if (dbus_type_is_basic(type)) {
  38. if (dbus_type_is_fixed(type)) {
  39. /*
  40. * According to DBus documentation all
  41. * fixed-length types are guaranteed to fit
  42. * 8 bytes
  43. */
  44. dbus_uint64_t v;
  45. dbus_message_iter_get_basic (from, &v);
  46. dbus_message_iter_append_basic (to, type, &v);
  47. } else {
  48. char *v;
  49. dbus_message_iter_get_basic (from, &v);
  50. dbus_message_iter_append_basic (to, type, &v);
  51. }
  52. } else {
  53. /* recursively copy container type entries */
  54. DBusMessageIter write_subiter, read_subiter;
  55. dbus_message_iter_recurse(from, &read_subiter);
  56. if (type == DBUS_TYPE_VARIANT ||
  57. type == DBUS_TYPE_ARRAY) {
  58. subtype = dbus_message_iter_get_signature(
  59. &read_subiter);
  60. }
  61. dbus_message_iter_open_container(to, type, subtype,
  62. &write_subiter);
  63. recursive_iter_copy(&read_subiter, &write_subiter);
  64. dbus_message_iter_close_container(to, &write_subiter);
  65. if (subtype)
  66. dbus_free(subtype);
  67. }
  68. dbus_message_iter_next(from);
  69. }
  70. }
  71. static unsigned int fill_dict_with_properties(
  72. DBusMessageIter *dict_iter, struct wpa_dbus_property_desc *props,
  73. const char *interface, const void *user_data)
  74. {
  75. DBusMessage *reply;
  76. DBusMessageIter entry_iter, ret_iter;
  77. unsigned int counter = 0;
  78. struct wpa_dbus_property_desc *property_dsc;
  79. for (property_dsc = props; property_dsc;
  80. property_dsc = property_dsc->next) {
  81. if (!os_strncmp(property_dsc->dbus_interface, interface,
  82. WPAS_DBUS_INTERFACE_MAX) &&
  83. property_dsc->access != W && property_dsc->getter) {
  84. reply = property_dsc->getter(NULL, user_data);
  85. if (!reply)
  86. continue;
  87. if (dbus_message_get_type(reply) ==
  88. DBUS_MESSAGE_TYPE_ERROR) {
  89. dbus_message_unref(reply);
  90. continue;
  91. }
  92. dbus_message_iter_init(reply, &ret_iter);
  93. dbus_message_iter_open_container(dict_iter,
  94. DBUS_TYPE_DICT_ENTRY,
  95. NULL, &entry_iter);
  96. dbus_message_iter_append_basic(
  97. &entry_iter, DBUS_TYPE_STRING,
  98. &(property_dsc->dbus_property));
  99. recursive_iter_copy(&ret_iter, &entry_iter);
  100. dbus_message_iter_close_container(dict_iter,
  101. &entry_iter);
  102. dbus_message_unref(reply);
  103. counter++;
  104. }
  105. }
  106. return counter;
  107. }
  108. /**
  109. * get_all_properties - Responds for GetAll properties calls on object
  110. * @message: Message with GetAll call
  111. * @interface: interface name which properties will be returned
  112. * @property_dsc: list of object's properties
  113. * Returns: Message with dict of variants as argument with properties values
  114. *
  115. * Iterates over all properties registered with object and execute getters
  116. * of those, which are readable and which interface matches interface
  117. * specified as argument. Returned message contains one dict argument
  118. * with properties names as keys and theirs values as values.
  119. */
  120. static DBusMessage * get_all_properties(
  121. DBusMessage *message, char *interface,
  122. struct wpa_dbus_object_desc *obj_dsc)
  123. {
  124. /* Create and initialize the return message */
  125. DBusMessage *reply = dbus_message_new_method_return(message);
  126. DBusMessageIter iter, dict_iter;
  127. int props_num;
  128. dbus_message_iter_init_append(reply, &iter);
  129. dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
  130. DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
  131. DBUS_TYPE_STRING_AS_STRING
  132. DBUS_TYPE_VARIANT_AS_STRING
  133. DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
  134. &dict_iter);
  135. props_num = fill_dict_with_properties(&dict_iter,obj_dsc->properties,
  136. interface, obj_dsc->user_data);
  137. dbus_message_iter_close_container(&iter, &dict_iter);
  138. if (props_num == 0) {
  139. dbus_message_unref(reply);
  140. reply = dbus_message_new_error(message,
  141. DBUS_ERROR_INVALID_ARGS,
  142. "No readable properties in "
  143. "this interface");
  144. }
  145. return reply;
  146. }
  147. static int is_signature_correct(DBusMessage *message,
  148. struct wpa_dbus_method_desc *method_dsc)
  149. {
  150. /* According to DBus documentation max length of signature is 255 */
  151. #define MAX_SIG_LEN 256
  152. char registered_sig[MAX_SIG_LEN], *pos;
  153. const char *sig = dbus_message_get_signature(message);
  154. int i, ret;
  155. pos = registered_sig;
  156. *pos = '\0';
  157. for (i = 0; i < method_dsc->args_num; i++) {
  158. struct wpa_dbus_argument arg = method_dsc->args[i];
  159. if (arg.dir == ARG_IN) {
  160. size_t blen = registered_sig + MAX_SIG_LEN - pos;
  161. ret = os_snprintf(pos, blen, "%s", arg.type);
  162. if (ret < 0 || (size_t) ret >= blen)
  163. return 0;
  164. pos += ret;
  165. }
  166. }
  167. return !os_strncmp(registered_sig, sig, MAX_SIG_LEN);
  168. }
  169. static DBusMessage * properties_get_all(DBusMessage *message, char *interface,
  170. struct wpa_dbus_object_desc *obj_dsc)
  171. {
  172. if (os_strcmp(dbus_message_get_signature(message), "s") != 0)
  173. return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
  174. NULL);
  175. return get_all_properties(message, interface, obj_dsc);
  176. }
  177. static DBusMessage * properties_get(DBusMessage *message,
  178. struct wpa_dbus_property_desc *dsc,
  179. void *user_data)
  180. {
  181. if (os_strcmp(dbus_message_get_signature(message), "ss"))
  182. return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
  183. NULL);
  184. if (dsc->access != W && dsc->getter)
  185. return dsc->getter(message, user_data);
  186. return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
  187. "Property is write-only");
  188. }
  189. static DBusMessage * properties_set(DBusMessage *message,
  190. struct wpa_dbus_property_desc *dsc,
  191. void *user_data)
  192. {
  193. if (os_strcmp(dbus_message_get_signature(message), "ssv"))
  194. return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
  195. NULL);
  196. if (dsc->access != R && dsc->setter)
  197. return dsc->setter(message, user_data);
  198. return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
  199. "Property is read-only");
  200. }
  201. static DBusMessage *
  202. properties_get_or_set(DBusMessage *message, DBusMessageIter *iter,
  203. char *interface,
  204. struct wpa_dbus_object_desc *obj_dsc)
  205. {
  206. struct wpa_dbus_property_desc *property_dsc;
  207. char *property;
  208. const char *method;
  209. method = dbus_message_get_member(message);
  210. property_dsc = obj_dsc->properties;
  211. /* Second argument: property name (DBUS_TYPE_STRING) */
  212. if (!dbus_message_iter_next(iter) ||
  213. dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_STRING) {
  214. return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
  215. NULL);
  216. }
  217. dbus_message_iter_get_basic(iter, &property);
  218. while (property_dsc) {
  219. /* compare property names and
  220. * interfaces */
  221. if (!os_strncmp(property_dsc->dbus_property, property,
  222. WPAS_DBUS_METHOD_SIGNAL_PROP_MAX) &&
  223. !os_strncmp(property_dsc->dbus_interface, interface,
  224. WPAS_DBUS_INTERFACE_MAX))
  225. break;
  226. property_dsc = property_dsc->next;
  227. }
  228. if (property_dsc == NULL) {
  229. wpa_printf(MSG_DEBUG, "no property handler for %s.%s on %s",
  230. interface, property,
  231. dbus_message_get_path(message));
  232. return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
  233. "No such property");
  234. }
  235. if (os_strncmp(WPA_DBUS_PROPERTIES_GET, method,
  236. WPAS_DBUS_METHOD_SIGNAL_PROP_MAX) == 0)
  237. return properties_get(message, property_dsc,
  238. obj_dsc->user_data);
  239. return properties_set(message, property_dsc, obj_dsc->user_data);
  240. }
  241. static DBusMessage * properties_handler(DBusMessage *message,
  242. struct wpa_dbus_object_desc *obj_dsc)
  243. {
  244. DBusMessageIter iter;
  245. char *interface;
  246. const char *method;
  247. method = dbus_message_get_member(message);
  248. dbus_message_iter_init(message, &iter);
  249. if (!os_strncmp(WPA_DBUS_PROPERTIES_GET, method,
  250. WPAS_DBUS_METHOD_SIGNAL_PROP_MAX) ||
  251. !os_strncmp(WPA_DBUS_PROPERTIES_SET, method,
  252. WPAS_DBUS_METHOD_SIGNAL_PROP_MAX) ||
  253. !os_strncmp(WPA_DBUS_PROPERTIES_GETALL, method,
  254. WPAS_DBUS_METHOD_SIGNAL_PROP_MAX)) {
  255. /* First argument: interface name (DBUS_TYPE_STRING) */
  256. if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
  257. {
  258. return dbus_message_new_error(message,
  259. DBUS_ERROR_INVALID_ARGS,
  260. NULL);
  261. }
  262. dbus_message_iter_get_basic(&iter, &interface);
  263. if (!os_strncmp(WPA_DBUS_PROPERTIES_GETALL, method,
  264. WPAS_DBUS_METHOD_SIGNAL_PROP_MAX)) {
  265. /* GetAll */
  266. return properties_get_all(message, interface, obj_dsc);
  267. }
  268. /* Get or Set */
  269. return properties_get_or_set(message, &iter, interface,
  270. obj_dsc);
  271. }
  272. return dbus_message_new_error(message, DBUS_ERROR_UNKNOWN_METHOD,
  273. NULL);
  274. }
  275. static DBusMessage * msg_method_handler(DBusMessage *message,
  276. struct wpa_dbus_object_desc *obj_dsc)
  277. {
  278. struct wpa_dbus_method_desc *method_dsc = obj_dsc->methods;
  279. const char *method;
  280. const char *msg_interface;
  281. method = dbus_message_get_member(message);
  282. msg_interface = dbus_message_get_interface(message);
  283. /* try match call to any registered method */
  284. while (method_dsc) {
  285. /* compare method names and interfaces */
  286. if (!os_strncmp(method_dsc->dbus_method, method,
  287. WPAS_DBUS_METHOD_SIGNAL_PROP_MAX) &&
  288. !os_strncmp(method_dsc->dbus_interface, msg_interface,
  289. WPAS_DBUS_INTERFACE_MAX))
  290. break;
  291. method_dsc = method_dsc->next;
  292. }
  293. if (method_dsc == NULL) {
  294. wpa_printf(MSG_DEBUG, "no method handler for %s.%s on %s",
  295. msg_interface, method,
  296. dbus_message_get_path(message));
  297. return dbus_message_new_error(message,
  298. DBUS_ERROR_UNKNOWN_METHOD, NULL);
  299. }
  300. if (!is_signature_correct(message, method_dsc)) {
  301. return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
  302. NULL);
  303. }
  304. return method_dsc->method_handler(message,
  305. obj_dsc->user_data);
  306. }
  307. /**
  308. * message_handler - Handles incoming DBus messages
  309. * @connection: DBus connection on which message was received
  310. * @message: Received message
  311. * @user_data: pointer to description of object to which message was sent
  312. * Returns: Returns information whether message was handled or not
  313. *
  314. * Reads message interface and method name, then checks if they matches one
  315. * of the special cases i.e. introspection call or properties get/getall/set
  316. * methods and handles it. Else it iterates over registered methods list
  317. * and tries to match method's name and interface to those read from message
  318. * If appropriate method was found its handler function is called and
  319. * response is sent. Otherwise, the DBUS_ERROR_UNKNOWN_METHOD error message
  320. * will be sent.
  321. */
  322. static DBusHandlerResult message_handler(DBusConnection *connection,
  323. DBusMessage *message, void *user_data)
  324. {
  325. struct wpa_dbus_object_desc *obj_dsc = user_data;
  326. const char *method;
  327. const char *path;
  328. const char *msg_interface;
  329. DBusMessage *reply;
  330. /* get method, interface and path the message is addressed to */
  331. method = dbus_message_get_member(message);
  332. path = dbus_message_get_path(message);
  333. msg_interface = dbus_message_get_interface(message);
  334. if (!method || !path || !msg_interface)
  335. return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
  336. wpa_printf(MSG_MSGDUMP, "dbus: %s.%s (%s)",
  337. msg_interface, method, path);
  338. /* if message is introspection method call */
  339. if (!os_strncmp(WPA_DBUS_INTROSPECTION_METHOD, method,
  340. WPAS_DBUS_METHOD_SIGNAL_PROP_MAX) &&
  341. !os_strncmp(WPA_DBUS_INTROSPECTION_INTERFACE, msg_interface,
  342. WPAS_DBUS_INTERFACE_MAX)) {
  343. #ifdef CONFIG_CTRL_IFACE_DBUS_INTRO
  344. reply = wpa_dbus_introspect(message, obj_dsc);
  345. #else /* CONFIG_CTRL_IFACE_DBUS_INTRO */
  346. reply = dbus_message_new_error(
  347. message, DBUS_ERROR_UNKNOWN_METHOD,
  348. "wpa_supplicant was compiled without "
  349. "introspection support.");
  350. #endif /* CONFIG_CTRL_IFACE_DBUS_INTRO */
  351. } else if (!os_strncmp(WPA_DBUS_PROPERTIES_INTERFACE, msg_interface,
  352. WPAS_DBUS_INTERFACE_MAX)) {
  353. /* if message is properties method call */
  354. reply = properties_handler(message, obj_dsc);
  355. } else {
  356. reply = msg_method_handler(message, obj_dsc);
  357. }
  358. /* If handler succeed returning NULL, reply empty message */
  359. if (!reply)
  360. reply = dbus_message_new_method_return(message);
  361. if (reply) {
  362. if (!dbus_message_get_no_reply(message))
  363. dbus_connection_send(connection, reply, NULL);
  364. dbus_message_unref(reply);
  365. }
  366. return DBUS_HANDLER_RESULT_HANDLED;
  367. }
  368. /**
  369. * free_dbus_object_desc - Frees object description data structure
  370. * @connection: DBus connection
  371. * @obj_dsc: Object description to free
  372. *
  373. * Frees each of properties, methods and signals description lists and
  374. * the object description structure itself.
  375. */
  376. void free_dbus_object_desc(struct wpa_dbus_object_desc *obj_dsc)
  377. {
  378. struct wpa_dbus_method_desc *method_dsc, *tmp_met_dsc;
  379. struct wpa_dbus_signal_desc *signal_dsc, *tmp_sig_dsc;
  380. struct wpa_dbus_property_desc *property_dsc, *tmp_prop_dsc;
  381. int i;
  382. if (!obj_dsc)
  383. return;
  384. /* free methods */
  385. method_dsc = obj_dsc->methods;
  386. while (method_dsc) {
  387. tmp_met_dsc = method_dsc;
  388. method_dsc = method_dsc->next;
  389. os_free(tmp_met_dsc->dbus_interface);
  390. os_free(tmp_met_dsc->dbus_method);
  391. for (i = 0; i < tmp_met_dsc->args_num; i++) {
  392. os_free(tmp_met_dsc->args[i].name);
  393. os_free(tmp_met_dsc->args[i].type);
  394. }
  395. os_free(tmp_met_dsc);
  396. }
  397. /* free signals */
  398. signal_dsc = obj_dsc->signals;
  399. while (signal_dsc) {
  400. tmp_sig_dsc = signal_dsc;
  401. signal_dsc = signal_dsc->next;
  402. os_free(tmp_sig_dsc->dbus_interface);
  403. os_free(tmp_sig_dsc->dbus_signal);
  404. for (i = 0; i < tmp_sig_dsc->args_num; i++) {
  405. os_free(tmp_sig_dsc->args[i].name);
  406. os_free(tmp_sig_dsc->args[i].type);
  407. }
  408. os_free(tmp_sig_dsc);
  409. }
  410. /* free properties */
  411. property_dsc = obj_dsc->properties;
  412. while (property_dsc) {
  413. tmp_prop_dsc = property_dsc;
  414. property_dsc = property_dsc->next;
  415. os_free(tmp_prop_dsc->dbus_interface);
  416. os_free(tmp_prop_dsc->dbus_property);
  417. os_free(tmp_prop_dsc->type);
  418. os_free(tmp_prop_dsc);
  419. }
  420. /* free handler's argument */
  421. if (obj_dsc->user_data_free_func)
  422. obj_dsc->user_data_free_func(obj_dsc->user_data);
  423. os_free(obj_dsc);
  424. }
  425. static void free_dbus_object_desc_cb(DBusConnection *connection, void *obj_dsc)
  426. {
  427. free_dbus_object_desc(obj_dsc);
  428. }
  429. /**
  430. * wpa_dbus_ctrl_iface_init - Initialize dbus control interface
  431. * @application_data: Pointer to application specific data structure
  432. * @dbus_path: DBus path to interface object
  433. * @dbus_service: DBus service name to register with
  434. * @messageHandler: a pointer to function which will handle dbus messages
  435. * coming on interface
  436. * Returns: 0 on success, -1 on failure
  437. *
  438. * Initialize the dbus control interface and start receiving commands from
  439. * external programs over the bus.
  440. */
  441. int wpa_dbus_ctrl_iface_init(struct wpas_dbus_priv *iface,
  442. char *dbus_path, char *dbus_service,
  443. struct wpa_dbus_object_desc *obj_desc)
  444. {
  445. DBusError error;
  446. int ret = -1;
  447. DBusObjectPathVTable wpa_vtable = {
  448. &free_dbus_object_desc_cb, &message_handler,
  449. NULL, NULL, NULL, NULL
  450. };
  451. obj_desc->connection = iface->con;
  452. /* Register the message handler for the global dbus interface */
  453. if (!dbus_connection_register_object_path(iface->con,
  454. dbus_path, &wpa_vtable,
  455. obj_desc)) {
  456. perror("dbus_connection_register_object_path[dbus]");
  457. wpa_printf(MSG_ERROR, "Could not set up DBus message "
  458. "handler.");
  459. return -1;
  460. }
  461. /* Register our service with the message bus */
  462. dbus_error_init(&error);
  463. switch (dbus_bus_request_name(iface->con, dbus_service,
  464. 0, &error)) {
  465. case DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER:
  466. ret = 0;
  467. break;
  468. case DBUS_REQUEST_NAME_REPLY_EXISTS:
  469. case DBUS_REQUEST_NAME_REPLY_IN_QUEUE:
  470. case DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER:
  471. perror("dbus_bus_request_name[dbus]");
  472. wpa_printf(MSG_ERROR, "Could not request DBus service name: "
  473. "already registered.");
  474. break;
  475. default:
  476. perror("dbus_bus_request_name[dbus]");
  477. wpa_printf(MSG_ERROR, "Could not request DBus service name: "
  478. "%s %s.", error.name, error.message);
  479. break;
  480. }
  481. dbus_error_free(&error);
  482. if (ret != 0)
  483. return -1;
  484. wpa_printf(MSG_DEBUG, "Providing DBus service '%s'.", dbus_service);
  485. return 0;
  486. }
  487. /**
  488. * wpa_dbus_register_object_per_iface - Register a new object with dbus
  489. * @ctrl_iface: pointer to dbus private data
  490. * @path: DBus path to object
  491. * @ifname: interface name
  492. * @obj_desc: description of object's methods, signals and properties
  493. * Returns: 0 on success, -1 on error
  494. *
  495. * Registers a new interface with dbus and assigns it a dbus object path.
  496. */
  497. int wpa_dbus_register_object_per_iface(
  498. struct wpas_dbus_priv *ctrl_iface,
  499. const char *path, const char *ifname,
  500. struct wpa_dbus_object_desc *obj_desc)
  501. {
  502. DBusConnection *con;
  503. DBusObjectPathVTable vtable = {
  504. &free_dbus_object_desc_cb, &message_handler,
  505. NULL, NULL, NULL, NULL
  506. };
  507. /* Do nothing if the control interface is not turned on */
  508. if (ctrl_iface == NULL)
  509. return 0;
  510. con = ctrl_iface->con;
  511. obj_desc->connection = con;
  512. /* Register the message handler for the interface functions */
  513. if (!dbus_connection_register_object_path(con, path, &vtable,
  514. obj_desc)) {
  515. perror("wpa_dbus_register_iface [dbus]");
  516. wpa_printf(MSG_ERROR, "Could not set up DBus message "
  517. "handler for interface %s\n"
  518. "and object %s.", ifname, path);
  519. return -1;
  520. }
  521. return 0;
  522. }
  523. /**
  524. * wpa_dbus_unregister_object_per_iface - Unregisters DBus object
  525. * @ctrl_iface: Pointer to dbus private data
  526. * @path: DBus path to object which will be unregistered
  527. * Returns: Zero on success and -1 on failure
  528. *
  529. * Unregisters DBus object given by its path
  530. */
  531. int wpa_dbus_unregister_object_per_iface(
  532. struct wpas_dbus_priv *ctrl_iface, const char *path)
  533. {
  534. DBusConnection *con = ctrl_iface->con;
  535. if (!dbus_connection_unregister_object_path(con, path))
  536. return -1;
  537. return 0;
  538. }
  539. /**
  540. * wpa_dbus_method_register - Registers DBus method for given object
  541. * @obj_dsc: Object description for which a method will be registered
  542. * @dbus_interface: DBus interface under which method will be registered
  543. * @dbus_method: a name the method will be registered with
  544. * @method_handler: a function which will be called to handle this method call
  545. * @args: method arguments list
  546. * Returns: Zero on success and -1 on failure
  547. *
  548. * Registers DBus method under given name and interface for the object.
  549. * Method calls will be handled with given handling function.
  550. * Handler function is required to return a DBusMessage pointer which
  551. * will be response to method call. Any method call before being handled
  552. * must have registered appropriate handler by using this function.
  553. */
  554. int wpa_dbus_method_register(struct wpa_dbus_object_desc *obj_dsc,
  555. const char *dbus_interface,
  556. const char *dbus_method,
  557. WPADBusMethodHandler method_handler,
  558. const struct wpa_dbus_argument args[])
  559. {
  560. struct wpa_dbus_method_desc *method_dsc = obj_dsc->methods;
  561. struct wpa_dbus_method_desc *prev_desc;
  562. int args_num = 0;
  563. int i, error;
  564. prev_desc = NULL;
  565. while (method_dsc) {
  566. prev_desc = method_dsc;
  567. method_dsc = method_dsc->next;
  568. }
  569. /* count args */
  570. if (args) {
  571. while (args[args_num].name && args[args_num].type)
  572. args_num++;
  573. }
  574. method_dsc = os_zalloc(sizeof(struct wpa_dbus_method_desc) +
  575. args_num * sizeof(struct wpa_dbus_argument));
  576. if (!method_dsc)
  577. goto err;
  578. if (prev_desc == NULL)
  579. obj_dsc->methods = method_dsc;
  580. else
  581. prev_desc->next = method_dsc;
  582. /* copy interface name */
  583. method_dsc->dbus_interface = os_strdup(dbus_interface);
  584. if (!method_dsc->dbus_interface)
  585. goto err;
  586. /* copy method name */
  587. method_dsc->dbus_method = os_strdup(dbus_method);
  588. if (!method_dsc->dbus_method)
  589. goto err;
  590. /* copy arguments */
  591. error = 0;
  592. method_dsc->args_num = args_num;
  593. for (i = 0; i < args_num; i++) {
  594. method_dsc->args[i].name = os_strdup(args[i].name);
  595. if (!method_dsc->args[i].name) {
  596. error = 1;
  597. continue;
  598. }
  599. method_dsc->args[i].type = os_strdup(args[i].type);
  600. if (!method_dsc->args[i].type) {
  601. error = 1;
  602. continue;
  603. }
  604. method_dsc->args[i].dir = args[i].dir;
  605. }
  606. if (error)
  607. goto err;
  608. method_dsc->method_handler = method_handler;
  609. method_dsc->next = NULL;
  610. return 0;
  611. err:
  612. wpa_printf(MSG_WARNING, "Failed to register dbus method %s in "
  613. "interface %s", dbus_method, dbus_interface);
  614. if (method_dsc) {
  615. os_free(method_dsc->dbus_interface);
  616. os_free(method_dsc->dbus_method);
  617. for (i = 0; i < method_dsc->args_num; i++) {
  618. os_free(method_dsc->args[i].name);
  619. os_free(method_dsc->args[i].type);
  620. }
  621. if (prev_desc == NULL)
  622. obj_dsc->methods = NULL;
  623. else
  624. prev_desc->next = NULL;
  625. os_free(method_dsc);
  626. }
  627. return -1;
  628. }
  629. /**
  630. * wpa_dbus_signal_register - Registers DBus signal for given object
  631. * @obj_dsc: Object description for which a signal will be registered
  632. * @dbus_interface: DBus interface under which signal will be registered
  633. * @dbus_signal: a name the signal will be registered with
  634. * @args: signal arguments list
  635. * Returns: Zero on success and -1 on failure
  636. *
  637. * Registers DBus signal under given name and interface for the object.
  638. * Signal registration is NOT required in order to send signals, but not
  639. * registered signals will not be respected in introspection data
  640. * therefore it is highly recommended to register every signal before
  641. * using it.
  642. */
  643. int wpa_dbus_signal_register(struct wpa_dbus_object_desc *obj_dsc,
  644. const char *dbus_interface,
  645. const char *dbus_signal,
  646. const struct wpa_dbus_argument args[])
  647. {
  648. struct wpa_dbus_signal_desc *signal_dsc = obj_dsc->signals;
  649. struct wpa_dbus_signal_desc *prev_desc;
  650. int args_num = 0;
  651. int i, error = 0;
  652. prev_desc = NULL;
  653. while (signal_dsc) {
  654. prev_desc = signal_dsc;
  655. signal_dsc = signal_dsc->next;
  656. }
  657. /* count args */
  658. if (args) {
  659. while (args[args_num].name && args[args_num].type)
  660. args_num++;
  661. }
  662. signal_dsc = os_zalloc(sizeof(struct wpa_dbus_signal_desc) +
  663. args_num * sizeof(struct wpa_dbus_argument));
  664. if (!signal_dsc)
  665. goto err;
  666. if (prev_desc == NULL)
  667. obj_dsc->signals = signal_dsc;
  668. else
  669. prev_desc->next = signal_dsc;
  670. /* copy interface name */
  671. signal_dsc->dbus_interface = os_strdup(dbus_interface);
  672. if (!signal_dsc->dbus_interface)
  673. goto err;
  674. /* copy signal name */
  675. signal_dsc->dbus_signal = os_strdup(dbus_signal);
  676. if (!signal_dsc->dbus_signal)
  677. goto err;
  678. /* copy arguments */
  679. signal_dsc->args_num = args_num;
  680. for (i = 0; i < args_num; i++) {
  681. signal_dsc->args[i].name = os_strdup(args[i].name);
  682. if (!signal_dsc->args[i].name) {
  683. error = 1;
  684. continue;
  685. }
  686. signal_dsc->args[i].type = os_strdup(args[i].type);
  687. if (!signal_dsc->args[i].type) {
  688. error = 1;
  689. continue;
  690. }
  691. }
  692. if (error)
  693. goto err;
  694. signal_dsc->next = NULL;
  695. return 0;
  696. err:
  697. wpa_printf(MSG_WARNING, "Failed to register dbus signal %s in "
  698. "interface %s", dbus_signal, dbus_interface);
  699. if (signal_dsc) {
  700. os_free(signal_dsc->dbus_interface);
  701. os_free(signal_dsc->dbus_signal);
  702. for (i = 0; i < signal_dsc->args_num; i++) {
  703. os_free(signal_dsc->args[i].name);
  704. os_free(signal_dsc->args[i].type);
  705. }
  706. if (prev_desc == NULL)
  707. obj_dsc->signals = NULL;
  708. else
  709. prev_desc->next = NULL;
  710. os_free(signal_dsc);
  711. }
  712. return -1;
  713. }
  714. /**
  715. * wpa_dbus_property_register - Registers DBus property for given object
  716. * @obj_dsc: Object description for which a property will be registered
  717. * @dbus_interface: DBus interface under which method will be registered
  718. * @dbus_property: a name the property will be registered with
  719. * @type: a property type signature in form of DBus type description
  720. * @getter: a function called in order to get property value
  721. * @setter: a function called in order to set property value
  722. * @access: property access permissions specifier (R, W or RW)
  723. * Returns: Zero on success and -1 on failure
  724. *
  725. * Registers DBus property under given name and interface for the object.
  726. * Properties are set with giver setter function and get with getter.Getter
  727. * or setter are required to return DBusMessage which is response to Set/Get
  728. * method calls. Every property must be registered by this function before
  729. * being used.
  730. */
  731. int wpa_dbus_property_register(struct wpa_dbus_object_desc *obj_dsc,
  732. const char *dbus_interface,
  733. const char *dbus_property,
  734. const char *type,
  735. WPADBusPropertyAccessor getter,
  736. WPADBusPropertyAccessor setter,
  737. enum dbus_prop_access _access)
  738. {
  739. struct wpa_dbus_property_desc *property_dsc = obj_dsc->properties;
  740. struct wpa_dbus_property_desc *prev_desc;
  741. prev_desc = NULL;
  742. while (property_dsc) {
  743. prev_desc = property_dsc;
  744. property_dsc = property_dsc->next;
  745. }
  746. property_dsc = os_zalloc(sizeof(struct wpa_dbus_property_desc));
  747. if (!property_dsc)
  748. goto err;
  749. if (prev_desc == NULL)
  750. obj_dsc->properties = property_dsc;
  751. else
  752. prev_desc->next = property_dsc;
  753. /* copy interface name */
  754. property_dsc->dbus_interface = os_strdup(dbus_interface);
  755. if (!property_dsc->dbus_interface)
  756. goto err;
  757. /* copy property name */
  758. property_dsc->dbus_property = os_strdup(dbus_property);
  759. if (!property_dsc->dbus_property)
  760. goto err;
  761. /* copy property type */
  762. property_dsc->type = os_strdup(type);
  763. if (!property_dsc->type)
  764. goto err;
  765. property_dsc->getter = getter;
  766. property_dsc->setter = setter;
  767. property_dsc->access = _access;
  768. property_dsc->next = NULL;
  769. return 0;
  770. err:
  771. wpa_printf(MSG_WARNING, "Failed to register dbus property %s in "
  772. "interface %s", dbus_property, dbus_interface);
  773. if (property_dsc) {
  774. os_free(property_dsc->dbus_interface);
  775. os_free(property_dsc->dbus_property);
  776. os_free(property_dsc->type);
  777. if (prev_desc == NULL)
  778. obj_dsc->properties = NULL;
  779. else
  780. prev_desc->next = NULL;
  781. os_free(property_dsc);
  782. }
  783. return -1;
  784. }
  785. /**
  786. * wpas_dbus_signal_network_added - Send a property changed signal
  787. * @iface: dbus priv struct
  788. * @property_getter: propperty getter used to fetch new property value
  789. * @getter_arg: argument passed to property getter
  790. * @path: path to object which property has changed
  791. * @interface_name: signal and property interface
  792. * @property_name: name of property which has changed
  793. *
  794. * Notify listeners about changing value of some property. Signal
  795. * contains property name and its value fetched using given property
  796. * getter.
  797. */
  798. void wpa_dbus_signal_property_changed(struct wpas_dbus_priv *iface,
  799. WPADBusPropertyAccessor property_getter,
  800. void *getter_arg,
  801. const char *path,
  802. const char *interface_name,
  803. const char *property_name)
  804. {
  805. DBusConnection *connection;
  806. DBusMessage *_signal, *getter_reply;
  807. DBusMessageIter prop_iter, signal_iter, dict_iter, entry_iter;
  808. if (!iface)
  809. return;
  810. connection = iface->con;
  811. if (!property_getter) {
  812. wpa_printf(MSG_ERROR, "wpa_dbus_signal_property_changed"
  813. "[dbus]: property getter not specified");
  814. return;
  815. }
  816. if (!path || !interface_name || !property_name) {
  817. wpa_printf(MSG_ERROR, "wpa_dbus_signal_property_changed"
  818. "[dbus]: path interface of property not specified");
  819. return;
  820. }
  821. getter_reply = property_getter(NULL, getter_arg);
  822. if (!getter_reply ||
  823. dbus_message_get_type(getter_reply) == DBUS_MESSAGE_TYPE_ERROR) {
  824. wpa_printf(MSG_ERROR, "wpa_dbus_signal_property_changed"
  825. "[dbus]: cannot get new value of property %s",
  826. property_name);
  827. return;
  828. }
  829. _signal = dbus_message_new_signal(path, interface_name,
  830. "PropertiesChanged");
  831. if (!_signal) {
  832. wpa_printf(MSG_ERROR, "wpa_dbus_signal_property_changed"
  833. "[dbus]: cannot allocate signal");
  834. dbus_message_unref(getter_reply);
  835. return;
  836. }
  837. dbus_message_iter_init(getter_reply, &prop_iter);
  838. dbus_message_iter_init_append(_signal, &signal_iter);
  839. if (!dbus_message_iter_open_container(&signal_iter, DBUS_TYPE_ARRAY,
  840. "{sv}", &dict_iter)) {
  841. wpa_printf(MSG_ERROR, "wpa_dbus_signal_property_changed"
  842. "[dbus]: out of memory. cannot open dictionary");
  843. goto err;
  844. }
  845. if (!dbus_message_iter_open_container(&dict_iter, DBUS_TYPE_DICT_ENTRY,
  846. NULL, &entry_iter)) {
  847. wpa_printf(MSG_ERROR, "iwpa_dbus_signal_property_changed"
  848. "[dbus]: out of memory. cannot open dictionary "
  849. "element");
  850. goto err;
  851. }
  852. if (!dbus_message_iter_append_basic(&entry_iter, DBUS_TYPE_STRING,
  853. &property_name)) {
  854. wpa_printf(MSG_ERROR, "wpa_dbus_signal_property_changed"
  855. "[dbus]: out of memory. cannot open add property "
  856. "name");
  857. goto err;
  858. }
  859. recursive_iter_copy(&prop_iter, &entry_iter);
  860. if (!dbus_message_iter_close_container(&dict_iter, &entry_iter)) {
  861. wpa_printf(MSG_ERROR, "wpa_dbus_signal_property_changed"
  862. "[dbus]: out of memory. cannot close dictionary "
  863. "element");
  864. goto err;
  865. }
  866. if (!dbus_message_iter_close_container(&signal_iter, &dict_iter)) {
  867. wpa_printf(MSG_ERROR, "wpa_dbus_signal_property_changed"
  868. "[dbus]: out of memory. cannot close dictionary");
  869. goto err;
  870. }
  871. dbus_connection_send(connection, _signal, NULL);
  872. err:
  873. dbus_message_unref(getter_reply);
  874. dbus_message_unref(_signal);
  875. }
  876. /**
  877. * wpa_dbus_get_object_properties - Put object's properties into dictionary
  878. * @iface: dbus priv struct
  879. * @path: path to DBus object which properties will be obtained
  880. * @interface: interface name which properties will be obtained
  881. * @dict_iter: correct, open DBus dictionary iterator.
  882. *
  883. * Iterates over all properties registered with object and execute getters
  884. * of those, which are readable and which interface matches interface
  885. * specified as argument. Obtained properties values are stored in
  886. * dict_iter dictionary.
  887. */
  888. void wpa_dbus_get_object_properties(struct wpas_dbus_priv *iface,
  889. const char *path, const char *interface,
  890. DBusMessageIter *dict_iter)
  891. {
  892. struct wpa_dbus_object_desc *obj_desc = NULL;
  893. dbus_connection_get_object_path_data(iface->con, path,
  894. (void **) &obj_desc);
  895. if (!obj_desc) {
  896. wpa_printf(MSG_ERROR, "dbus: wpa_dbus_get_object_properties: "
  897. "could not obtain object's private data: %s", path);
  898. return;
  899. }
  900. fill_dict_with_properties(dict_iter, obj_desc->properties,
  901. interface, obj_desc->user_data);
  902. }