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.

285 lines
7.1 KiB

8 years ago
12 years ago
12 years ago
17 years ago
16 years ago
16 years ago
16 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 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,
  246. UDisksClient *udisks,
  247. const char *user)
  248. {
  249. t_pusb_volume *volume = NULL;
  250. int retval = 0;
  251. volume = pusb_volume_get(opts, udisks);
  252. if (!volume)
  253. return (0);
  254. retval = pusb_pad_compare(opts, volume->mount_point, user);
  255. if (retval)
  256. pusb_pad_update(opts, volume->mount_point, user);
  257. else
  258. log_error("Pad checking failed!\n");
  259. pusb_volume_destroy(volume);
  260. return (retval);
  261. }