Hardware authentication for Linux using ordinary USB Flash Drives.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

345 lines
7.7 KiB

13 years ago
17 years ago
17 years ago
17 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
  1. /*
  2. * Copyright (c) 2003-2007 Andrea Luzzardi <scox@sig11.org>
  3. *
  4. * This file is part of the pam_usb project. pam_usb is free software;
  5. * you can redistribute it and/or modify it under the terms of the GNU General
  6. * Public License version 2, as published by the Free Software Foundation.
  7. *
  8. * pam_usb is distributed in the hope that it will be useful, but WITHOUT ANY
  9. * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  10. * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
  11. * details.
  12. *
  13. * You should have received a copy of the GNU General Public License along with
  14. * this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
  15. * Street, Fifth Floor, Boston, MA 02110-1301 USA
  16. */
  17. #include <stdlib.h>
  18. #include <string.h>
  19. #include <stdarg.h>
  20. #include <unistd.h>
  21. #include <sys/types.h>
  22. #include "mem.h"
  23. #include "log.h"
  24. #include "hal.h"
  25. DBusConnection *pusb_hal_dbus_connect(void)
  26. {
  27. DBusConnection *dbus = NULL;
  28. DBusError error;
  29. dbus_error_init(&error);
  30. if (!(dbus = dbus_bus_get(DBUS_BUS_SYSTEM, &error)))
  31. {
  32. /* Workaround for https://bugs.freedesktop.org/show_bug.cgi?id=11876 */
  33. uid_t ruid;
  34. uid_t euid;
  35. if (!(euid = geteuid()) && (ruid = getuid()))
  36. {
  37. dbus_error_free(&error);
  38. setreuid(euid, euid);
  39. dbus = dbus_bus_get(DBUS_BUS_SYSTEM, &error);
  40. setreuid(ruid, euid);
  41. }
  42. if (!dbus)
  43. {
  44. log_error("Cannot connect to system bus: %s\n",
  45. error.message);
  46. dbus_error_free(&error);
  47. return (NULL);
  48. }
  49. }
  50. return (dbus);
  51. }
  52. void pusb_hal_dbus_disconnect(DBusConnection *dbus)
  53. {
  54. dbus_connection_unref(dbus);
  55. }
  56. void pusb_hal_free_string_array(char **str_array, int length)
  57. {
  58. int i;
  59. if (str_array == NULL)
  60. return ;
  61. for (i = 0; i < length; ++i)
  62. xfree(str_array[i]);
  63. xfree(str_array);
  64. }
  65. char **pusb_hal_get_string_array_from_iter(DBusMessageIter *iter, int *num_elements)
  66. {
  67. int count;
  68. char **buffer;
  69. count = 0;
  70. buffer = (char **)xmalloc(sizeof(char *) * 8);
  71. buffer[0] = NULL;
  72. while (dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_STRING ||
  73. dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_OBJECT_PATH)
  74. {
  75. const char *value;
  76. if ((count % 8) == 0 && count != 0) {
  77. buffer = xrealloc(buffer, sizeof (char *) * (count + 8));
  78. }
  79. dbus_message_iter_get_basic(iter, &value);
  80. buffer[count] = xstrdup(value);
  81. dbus_message_iter_next(iter);
  82. count++;
  83. }
  84. if (num_elements != NULL)
  85. *num_elements = count;
  86. return buffer;
  87. }
  88. DBusMessage *pusb_hal_get_raw_property(DBusConnection *dbus,
  89. const char *udi,
  90. const char *name)
  91. {
  92. DBusMessage *message;
  93. DBusMessage *reply;
  94. DBusMessageIter iter;
  95. DBusError error;
  96. char *iface = "org.freedesktop.UDisks.Device";
  97. message = dbus_message_new_method_call("org.freedesktop.UDisks", udi,
  98. "org.freedesktop.DBus.Properties",
  99. "Get");
  100. if (message == NULL) {
  101. log_error("Could not allocate D-BUS message\n");
  102. return (NULL);
  103. }
  104. dbus_message_iter_init_append(message, &iter);
  105. dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &iface);
  106. dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &name);
  107. dbus_error_init(&error);
  108. reply = dbus_connection_send_with_reply_and_block(dbus,
  109. message, -1,
  110. &error);
  111. dbus_message_unref(message);
  112. if (dbus_error_is_set(&error)) {
  113. log_error("Error communicating with D-BUS\n");
  114. return (NULL);
  115. }
  116. dbus_error_free(&error);
  117. return (reply);
  118. }
  119. char *pusb_hal_get_string_property(DBusConnection *dbus,
  120. const char *udi,
  121. const char *name)
  122. {
  123. DBusMessage *reply;
  124. DBusMessageIter reply_iter;
  125. char *data;
  126. char *dbus_str;
  127. reply = pusb_hal_get_raw_property(dbus, udi, name);
  128. if (reply == NULL) {
  129. return (NULL);
  130. }
  131. dbus_message_iter_init(reply, &reply_iter);
  132. if (dbus_message_iter_get_arg_type(&reply_iter) != DBUS_TYPE_VARIANT)
  133. {
  134. dbus_message_unref(reply);
  135. return (NULL);
  136. }
  137. DBusMessageIter subiter;
  138. dbus_message_iter_recurse(&reply_iter, &subiter);
  139. dbus_message_iter_get_basic(&subiter, &dbus_str);
  140. if (dbus_str != NULL)
  141. data = xstrdup(dbus_str);
  142. dbus_message_unref(reply);
  143. return (data);
  144. }
  145. char **pusb_hal_get_string_array_property(DBusConnection *dbus,
  146. const char *udi,
  147. const char *name,
  148. int *n_items)
  149. {
  150. DBusMessage *reply;
  151. DBusMessageIter reply_iter;
  152. char **items;
  153. reply = pusb_hal_get_raw_property(dbus, udi, name);
  154. if (reply == NULL) {
  155. return (NULL);
  156. }
  157. dbus_message_iter_init(reply, &reply_iter);
  158. if (dbus_message_iter_get_arg_type(&reply_iter) != DBUS_TYPE_VARIANT)
  159. {
  160. dbus_message_unref(reply);
  161. return (NULL);
  162. }
  163. DBusMessageIter subiter, subsubiter;
  164. dbus_message_iter_recurse(&reply_iter, &subiter);
  165. dbus_message_iter_recurse(&subiter, &subsubiter);
  166. items = pusb_hal_get_string_array_from_iter(&subsubiter, n_items);
  167. dbus_message_unref(reply);
  168. if (!*n_items)
  169. {
  170. pusb_hal_free_string_array(items, *n_items);
  171. return (NULL);
  172. }
  173. return (items);
  174. }
  175. int pusb_hal_get_bool_property(DBusConnection *dbus,
  176. const char *udi,
  177. const char *name,
  178. dbus_bool_t *value)
  179. {
  180. DBusMessage *reply;
  181. DBusMessageIter reply_iter;
  182. reply = pusb_hal_get_raw_property(dbus, udi, name);
  183. if (reply == NULL) {
  184. return (0);
  185. }
  186. dbus_message_iter_init(reply, &reply_iter);
  187. if (dbus_message_iter_get_arg_type(&reply_iter) !=
  188. DBUS_TYPE_VARIANT)
  189. {
  190. dbus_message_unref(reply);
  191. return (0);
  192. }
  193. DBusMessageIter subiter;
  194. dbus_message_iter_recurse(&reply_iter, &subiter);
  195. dbus_message_iter_get_basic(&subiter, value);
  196. dbus_message_unref(reply);
  197. return (1);
  198. }
  199. int pusb_hal_check_property(DBusConnection *dbus,
  200. const char *udi,
  201. const char *name,
  202. const char *value)
  203. {
  204. char *data;
  205. int retval;
  206. data = pusb_hal_get_string_property(dbus, udi, name);
  207. if (!data)
  208. return (0);
  209. retval = (strcmp(data, value) == 0);
  210. xfree(data);
  211. return (retval);
  212. }
  213. char **pusb_hal_find_all_items(DBusConnection *dbus, int *count)
  214. {
  215. DBusError error;
  216. DBusMessage *message;
  217. DBusMessage *reply;
  218. DBusMessageIter iter_array, reply_iter;
  219. char **devices;
  220. int n_devices;
  221. *count = 0;
  222. message = dbus_message_new_method_call("org.freedesktop.UDisks",
  223. "/org/freedesktop/UDisks",
  224. "org.freedesktop.UDisks",
  225. "EnumerateDevices");
  226. if (message == NULL)
  227. {
  228. log_error("Couldn't allocate D-BUS message\n");
  229. return (NULL);
  230. }
  231. dbus_error_init(&error);
  232. reply = dbus_connection_send_with_reply_and_block(dbus,
  233. message, -1,
  234. &error);
  235. dbus_message_unref(message);
  236. if (dbus_error_is_set(&error)) {
  237. log_error("Error communicating with D-BUS\n");
  238. return (NULL);
  239. }
  240. if (reply == NULL) {
  241. return (NULL);
  242. }
  243. dbus_message_iter_init(reply, &reply_iter);
  244. if (dbus_message_iter_get_arg_type(&reply_iter) != DBUS_TYPE_ARRAY) {
  245. log_error("Malformed D-BUS reply");
  246. return (NULL);
  247. }
  248. dbus_message_iter_recurse(&reply_iter, &iter_array);
  249. devices = pusb_hal_get_string_array_from_iter(&iter_array, &n_devices);
  250. dbus_message_unref(reply);
  251. if (!n_devices)
  252. {
  253. pusb_hal_free_string_array(devices, n_devices);
  254. return (NULL);
  255. }
  256. *count = n_devices;
  257. return (devices);
  258. }
  259. char *pusb_hal_find_item(DBusConnection *dbus,
  260. ...)
  261. {
  262. char **devices;
  263. int n_devices;
  264. char *udi = NULL;
  265. va_list ap;
  266. int i;
  267. devices = pusb_hal_find_all_items(dbus, &n_devices);
  268. if (!devices)
  269. return (NULL);
  270. if (!n_devices)
  271. return (NULL);
  272. for (i = 0; i < n_devices; ++i)
  273. {
  274. char *key = NULL;
  275. int match = 1;
  276. va_start(ap, dbus);
  277. while ((key = va_arg(ap, char *)))
  278. {
  279. char *value = NULL;
  280. value = va_arg(ap, char *);
  281. if (!value || *value == 0x0)
  282. continue ;
  283. if (!pusb_hal_check_property(dbus, devices[i],
  284. key, value))
  285. {
  286. match = 0;
  287. break;
  288. }
  289. }
  290. if (match)
  291. {
  292. udi = xstrdup(devices[i]);
  293. break;
  294. }
  295. va_end(ap);
  296. }
  297. pusb_hal_free_string_array(devices, n_devices);
  298. return (udi);
  299. }