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.

281 lines
7.1 KiB

17 years ago
12 years ago
12 years ago
17 years ago
16 years ago
16 years ago
16 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 <stdio.h>
  18. #include <stdlib.h>
  19. #include <string.h>
  20. #include <unistd.h>
  21. #include <errno.h>
  22. #include <sys/types.h>
  23. #include <sys/stat.h>
  24. #include <fcntl.h>
  25. #include <pwd.h>
  26. #include <time.h>
  27. #include "conf.h"
  28. #include "log.h"
  29. #include "volume.h"
  30. #include "pad.h"
  31. static FILE *pusb_pad_open_device(t_pusb_options *opts,
  32. const char *mnt_point,
  33. const char *user,
  34. const char *mode)
  35. {
  36. FILE *f;
  37. char path[PATH_MAX];
  38. struct stat sb;
  39. memset(path, 0x00, PATH_MAX);
  40. snprintf(path, PATH_MAX, "%s/%s", mnt_point, opts->device_pad_directory);
  41. if (stat(path, &sb) != 0)
  42. {
  43. log_debug("Directory %s does not exist, creating one.\n", path);
  44. if (mkdir(path, S_IRUSR | S_IWUSR | S_IXUSR) != 0)
  45. {
  46. log_debug("Unable to create directory %s: %s\n", path,
  47. strerror(errno));
  48. return (NULL);
  49. }
  50. memset(path, 0x00, PATH_MAX);
  51. }
  52. snprintf(path, PATH_MAX, "%s/%s/%s.%s.pad", mnt_point,
  53. opts->device_pad_directory, user, opts->hostname);
  54. f = fopen(path, mode);
  55. if (!f)
  56. {
  57. log_debug("Cannot open device file: %s\n", strerror(errno));
  58. return (NULL);
  59. }
  60. return (f);
  61. }
  62. static FILE *pusb_pad_open_system(t_pusb_options *opts,
  63. const char *user,
  64. const char *mode)
  65. {
  66. FILE *f;
  67. char path[PATH_MAX];
  68. struct passwd *user_ent = NULL;
  69. struct stat sb;
  70. char device_name[PATH_MAX];
  71. char * device_name_ptr = device_name;
  72. if (!(user_ent = getpwnam(user)) || !(user_ent->pw_dir))
  73. {
  74. log_error("Unable to retrieve information for user \"%s\": %s\n",
  75. strerror(errno));
  76. return (0);
  77. }
  78. memset(path, 0x00, PATH_MAX);
  79. snprintf(path, PATH_MAX, "%s/%s", user_ent->pw_dir,
  80. opts->system_pad_directory);
  81. if (stat(path, &sb) != 0)
  82. {
  83. log_debug("Directory %s does not exist, creating one.\n", path);
  84. if (mkdir(path, S_IRUSR | S_IWUSR | S_IXUSR) != 0)
  85. {
  86. log_debug("Unable to create directory %s: %s\n", path,
  87. strerror(errno));
  88. return (NULL);
  89. }
  90. chown(path, user_ent->pw_uid, user_ent->pw_gid);
  91. chmod(path, S_IRUSR | S_IWUSR | S_IXUSR);
  92. }
  93. /* change slashes in device name to underscores */
  94. strcpy(device_name, opts->device.name);
  95. while(*device_name_ptr) {
  96. if('/' == *device_name_ptr) *device_name_ptr = '_';
  97. device_name_ptr++;
  98. }
  99. memset(path, 0x00, PATH_MAX);
  100. snprintf(path, PATH_MAX, "%s/%s/%s.pad", user_ent->pw_dir,
  101. opts->system_pad_directory, device_name);
  102. f = fopen(path, mode);
  103. if (!f)
  104. {
  105. log_debug("Cannot open system file: %s\n", strerror(errno));
  106. return (NULL);
  107. }
  108. return (f);
  109. }
  110. static int pusb_pad_protect(const char *user, int fd)
  111. {
  112. struct passwd *user_ent = NULL;
  113. log_debug("Protecting pad file...\n");
  114. if (!(user_ent = getpwnam(user)))
  115. {
  116. log_error("Unable to retrieve information for user \"%s\": %s\n",
  117. strerror(errno));
  118. return (0);
  119. }
  120. if (fchown(fd, user_ent->pw_uid, user_ent->pw_gid) == -1)
  121. {
  122. log_debug("Unable to change owner of the pad: %s\n",
  123. strerror(errno));
  124. return (0);
  125. }
  126. if (fchmod(fd, S_IRUSR | S_IWUSR) == -1)
  127. {
  128. log_debug("Unable to change mode of the pad: %s\n",
  129. strerror(errno));
  130. return (0);
  131. }
  132. return (1);
  133. }
  134. static int pusb_pad_should_update(t_pusb_options *opts, const char *user)
  135. {
  136. FILE *f_system = NULL;
  137. struct stat st;
  138. time_t now;
  139. time_t delta;
  140. log_debug("Checking whether pads are expired or not...\n");
  141. if (!(f_system = pusb_pad_open_system(opts, user, "r")))
  142. {
  143. log_debug("Unable to open system pad, pads must be generated.\n");
  144. return (1);
  145. }
  146. if (fstat(fileno(f_system), &st) == -1)
  147. {
  148. fclose(f_system);
  149. return (1);
  150. }
  151. fclose(f_system);
  152. if (time(&now) == ((time_t)-1))
  153. {
  154. log_error("Unable to fetch current time.\n");
  155. return (1);
  156. }
  157. delta = now - st.st_mtime;
  158. if (delta > opts->pad_expiration)
  159. {
  160. log_debug("Pads expired %u seconds ago, updating...\n",
  161. delta - opts->pad_expiration);
  162. return (1);
  163. }
  164. else
  165. {
  166. log_debug("Pads were generated %u seconds ago, not updating.\n",
  167. delta);
  168. return (0);
  169. }
  170. return (1);
  171. }
  172. static void pusb_pad_update(t_pusb_options *opts,
  173. const char *volume,
  174. const char *user)
  175. {
  176. FILE *f_device = NULL;
  177. FILE *f_system = NULL;
  178. char magic[1024];
  179. int i;
  180. unsigned int seed;
  181. int devrandom;
  182. if (!pusb_pad_should_update(opts, user))
  183. return ;
  184. log_info("Regenerating new pads...\n");
  185. if (!(f_device = pusb_pad_open_device(opts, volume, user, "w+")))
  186. {
  187. log_error("Unable to update pads.\n");
  188. return ;
  189. }
  190. pusb_pad_protect(user, fileno(f_device));
  191. if (!(f_system = pusb_pad_open_system(opts, user, "w+")))
  192. {
  193. log_error("Unable to update pads.\n");
  194. fclose(f_device);
  195. return ;
  196. }
  197. pusb_pad_protect(user, fileno(f_system));
  198. log_debug("Generating %d bytes unique pad...\n", sizeof(magic));
  199. devrandom = open("/dev/random", O_RDONLY);
  200. if (devrandom < 0 || read(devrandom, &seed, sizeof seed) != sizeof seed) {
  201. log_debug("/dev/random seeding failed...\n");
  202. seed = getpid() * time(NULL); /* low-entropy fallback */
  203. }
  204. if (devrandom > 0)
  205. close(devrandom);
  206. srand(seed);
  207. for (i = 0; i < sizeof(magic); ++i)
  208. magic[i] = (char)rand();
  209. log_debug("Writing pad to the device...\n");
  210. fwrite(magic, sizeof(char), sizeof(magic), f_system);
  211. log_debug("Writing pad to the system...\n");
  212. fwrite(magic, sizeof(char), sizeof(magic), f_device);
  213. log_debug("Synchronizing filesystems...\n");
  214. fclose(f_system);
  215. fclose(f_device);
  216. sync();
  217. log_debug("One time pads updated.\n");
  218. }
  219. static int pusb_pad_compare(t_pusb_options *opts, const char *volume,
  220. const char *user)
  221. {
  222. FILE *f_device = NULL;
  223. FILE *f_system = NULL;
  224. char magic_device[1024];
  225. char magic_system[1024];
  226. int retval;
  227. if (!(f_system = pusb_pad_open_system(opts, user, "r")))
  228. return (1);
  229. if (!(f_device = pusb_pad_open_device(opts, volume, user, "r")))
  230. {
  231. fclose(f_system);
  232. return (0);
  233. }
  234. log_debug("Loading device pad...\n");
  235. fread(magic_device, sizeof(char), sizeof(magic_device), f_device);
  236. log_debug("Loading system pad...\n");
  237. fread(magic_system, sizeof(char), sizeof(magic_system), f_system);
  238. retval = memcmp(magic_system, magic_device, sizeof(magic_system));
  239. fclose(f_system);
  240. fclose(f_device);
  241. if (!retval)
  242. log_debug("Pad match.\n");
  243. return (retval == 0);
  244. }
  245. int pusb_pad_check(t_pusb_options *opts, DBusConnection *dbus,
  246. const char *user)
  247. {
  248. char *volume = NULL;
  249. int retval = 0;
  250. volume = pusb_volume_get(opts, dbus);
  251. if (!volume)
  252. return (0);
  253. retval = pusb_pad_compare(opts, volume, user);
  254. if (retval)
  255. pusb_pad_update(opts, volume, user);
  256. else
  257. log_error("Pad checking failed !\n");
  258. pusb_volume_destroy(volume);
  259. return (retval);
  260. }