mirror of the now-defunct rocklinux.org
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.

513 lines
14 KiB

  1. diff -dur util-linux-2.12h/mount/lomount.c util-linux-2.12h-patch/mount/lomount.c
  2. --- util-linux-2.12h/mount/lomount.c 2004-09-22 18:26:02.000000000 +0000
  3. +++ util-linux-2.12h-patch/mount/lomount.c 2004-10-23 03:37:44.541795904 +0000
  4. @@ -10,7 +10,6 @@
  5. * 2000-09-24 Marc Mutz <Marc@Mutz.com>
  6. * - added -p option to pass passphrases via fd's to losetup/mount.
  7. * Used for encryption in non-interactive environments.
  8. - * The idea behind xgetpass() is stolen from GnuPG, v.1.0.3.
  9. */
  10. #define LOOPMAJOR 7
  11. @@ -24,12 +23,16 @@
  12. #include <ctype.h>
  13. #include <fcntl.h>
  14. #include <errno.h>
  15. +#include <limits.h>
  16. #include <stdlib.h>
  17. #include <unistd.h>
  18. +#include <sys/types.h>
  19. #include <sys/ioctl.h>
  20. #include <sys/stat.h>
  21. #include <sys/mman.h>
  22. #include <sys/sysmacros.h>
  23. +#include <regex.h>
  24. +#include <signal.h>
  25. #include "loop.h"
  26. #include "lomount.h"
  27. @@ -38,6 +41,7 @@
  28. extern int verbose;
  29. extern char *xstrdup (const char *s); /* not: #include "sundries.h" */
  30. +extern void *xmalloc (size_t size); /* idem */
  31. extern void error (const char *fmt, ...); /* idem */
  32. #ifdef LOOP_SET_FD
  33. @@ -198,43 +202,113 @@
  34. return 0;
  35. }
  36. -/*
  37. - * A function to read the passphrase either from the terminal or from
  38. - * an open file descriptor.
  39. - */
  40. -static char *
  41. -xgetpass(int pfd, const char *prompt) {
  42. - char *pass;
  43. - int buflen, i;
  44. +/* A function to check the encryption parameters against /proc/crypto. *
  45. + * Returns 1 if everything checks out, 0 if there's any problem. *
  46. + * The purpose of this function is not so much to verify the parameters *
  47. + * before setting up the loop device; that task is made difficult by *
  48. + * the possibility of loadable encryption modules and the necessity of *
  49. + * falling back to the old (kerneli.org) CryptoAPI. Rather the intent *
  50. + * is to come up with a more useful error message after the setup *
  51. + * fails. Thus we return 1 in the event that some system error prevents *
  52. + * us from getting the info we want from /proc/crypto. */
  53. +static int
  54. +check_crypto(struct loop_info64 *loopinfo64) {
  55. + char *s = xmalloc(LINE_MAX), *name = xmalloc(LINE_MAX),
  56. + cipher_name[LO_NAME_SIZE+1];
  57. + int cipher_found = 0, min_size = 0, max_size = 0, retval;
  58. + FILE *fp;
  59. + struct stat st;
  60. - if (pfd < 0) /* terminal */
  61. - return getpass(prompt);
  62. + if (stat("/proc/crypto", &st) == -1) {
  63. + retval = 1;
  64. + goto end;
  65. + } else if (S_ISDIR(st.st_mode)) {
  66. + /* Hm... must be using the old CryptoAPI. */
  67. + retval = 1;
  68. + goto end;
  69. + } else if ((fp = fopen("/proc/crypto", "r")) == NULL) {
  70. + retval = 1;
  71. + goto end;
  72. + }
  73. - pass = NULL;
  74. - buflen = 0;
  75. - for (i=0; ; i++) {
  76. - if (i >= buflen-1) {
  77. - /* we're running out of space in the buffer.
  78. - * Make it bigger: */
  79. - char *tmppass = pass;
  80. - buflen += 128;
  81. - pass = realloc(tmppass, buflen);
  82. - if (pass == NULL) {
  83. - /* realloc failed. Stop reading. */
  84. - error("Out of memory while reading passphrase");
  85. - pass = tmppass; /* the old buffer hasn't changed */
  86. + xstrncpy(cipher_name, loopinfo64->lo_crypt_name, LO_NAME_SIZE);
  87. + /* Chop off the cipher mode (ie. everything after the dash) */
  88. + cipher_name[strcspn(cipher_name, "-")] = '\0';
  89. +
  90. + while (fgets(s, LINE_MAX, fp) != NULL) {
  91. + if (sscanf(s, "name : %s", name) > 0) {
  92. + if (strcmp(name, cipher_name) == 0)
  93. + cipher_found = 1;
  94. + else if (cipher_found)
  95. break;
  96. - }
  97. + } else {
  98. + sscanf(s, "min keysize : %d", &min_size);
  99. + sscanf(s, "max keysize : %d", &max_size);
  100. }
  101. - if (read(pfd, pass+i, 1) != 1 || pass[i] == '\n')
  102. - break;
  103. }
  104. - if (pass == NULL)
  105. - return "";
  106. - else {
  107. - pass[i] = 0;
  108. - return pass;
  109. + fclose(fp);
  110. +
  111. + if (!cipher_found) {
  112. + fprintf(stderr, _("Invalid cipher \"%s\"\n"), cipher_name);
  113. + retval = 0;
  114. + goto end;
  115. + } else if (loopinfo64->lo_encrypt_key_size < min_size ||
  116. + loopinfo64->lo_encrypt_key_size > max_size) {
  117. + fprintf(stderr, _("Invalid key length (%d) for %s cipher\n"),
  118. + loopinfo64->lo_encrypt_key_size, cipher_name);
  119. + retval = 0;
  120. + goto end;
  121. }
  122. +
  123. + retval = 1;
  124. +end:
  125. + free(s);
  126. + free(name);
  127. + return retval;
  128. +}
  129. +
  130. +/* Same thing, for the old CryptoAPI. */
  131. +static int
  132. +check_crypto_old(struct loop_info *loopinfo) {
  133. + char *s = xmalloc(LINE_MAX), *name = xmalloc(PATH_MAX+1),
  134. + cipher_name[LO_NAME_SIZE+1];
  135. + int mask = 0, retval;
  136. + FILE *fp;
  137. + struct stat st;
  138. +
  139. + if (stat("/proc/crypto/cipher", &st) == -1) {
  140. + retval = 1;
  141. + goto end;
  142. + } else if (!S_ISDIR(st.st_mode)) {
  143. + retval = 1;
  144. + goto end;
  145. + }
  146. +
  147. + xstrncpy(cipher_name, loopinfo->lo_name, LO_NAME_SIZE);
  148. + snprintf(name, PATH_MAX+1, "/proc/crypto/cipher/%s", cipher_name);
  149. + if ((fp = fopen(name, "r")) == NULL) {
  150. + fprintf(stderr, _("Invalid cipher \"%s\"\n"), cipher_name);
  151. + retval = 0;
  152. + goto end;
  153. + }
  154. +
  155. + while (fgets(s, LINE_MAX, fp) != NULL) {
  156. + sscanf(s, "keysize_mask : %i", &mask);
  157. + }
  158. + fclose(fp);
  159. +
  160. + if (!(mask & (1 << (loopinfo->lo_encrypt_key_size - 1)))) {
  161. + fprintf(stderr, _("Invalid key length (%d) for %s cipher\n"),
  162. + loopinfo->lo_encrypt_key_size, cipher_name);
  163. + retval = 0;
  164. + goto end;
  165. + }
  166. +
  167. + retval = 1;
  168. +end:
  169. + free(s);
  170. + free(name);
  171. + return retval;
  172. }
  173. static int
  174. @@ -275,9 +349,40 @@
  175. if (digits_only(encryption)) {
  176. loopinfo64.lo_encrypt_type = atoi(encryption);
  177. } else {
  178. + regex_t keysize_re;
  179. + regmatch_t keysize_rm;
  180. + int rerror;
  181. + char *rerror_buf, *encryption_dup = xstrdup(encryption);
  182. +
  183. loopinfo64.lo_encrypt_type = LO_CRYPT_CRYPTOAPI;
  184. +
  185. + if ((rerror = regcomp(&keysize_re, "-[[:digit:]]+$",
  186. + REG_EXTENDED)) != 0) {
  187. + fprintf(stderr, _("RE error: "));
  188. + rerror_buf = xmalloc(LINE_MAX+1);
  189. + regerror(rerror, &keysize_re, rerror_buf, LINE_MAX);
  190. + fprintf(stderr, "%s\n", rerror_buf);
  191. + free(rerror_buf);
  192. + return -1;
  193. + }
  194. + rerror = regexec(&keysize_re, encryption_dup,
  195. + 1, &keysize_rm, 0);
  196. + regfree(&keysize_re);
  197. + if (rerror) {
  198. + fprintf(stderr,
  199. + _("You must specify a key size (in bits) "
  200. + "for use with CryptoAPI encryption.\n"));
  201. + return -1;
  202. + }
  203. +
  204. + /* convert the key size from #bits to #bytes */
  205. + loopinfo64.lo_encrypt_key_size =
  206. + atoi(encryption_dup + keysize_rm.rm_so + 1) / 8;
  207. + /* now cut off the key size */
  208. + encryption_dup[keysize_rm.rm_so] = '\0';
  209. snprintf(loopinfo64.lo_crypt_name, LO_NAME_SIZE,
  210. - "%s", encryption);
  211. + "%s", encryption_dup);
  212. + free(encryption_dup);
  213. }
  214. }
  215. @@ -308,10 +413,26 @@
  216. strlen(loopinfo64.lo_encrypt_key);
  217. break;
  218. default:
  219. - pass = xgetpass(pfd, _("Password: "));
  220. - xstrncpy(loopinfo64.lo_encrypt_key, pass, LO_KEY_SIZE);
  221. - memset(pass, 0, strlen(pass));
  222. - loopinfo64.lo_encrypt_key_size = LO_KEY_SIZE;
  223. + if (pfd == -1) {
  224. + pass = getpass(_("Password: "));
  225. + xstrncpy(loopinfo64.lo_encrypt_key, pass, LO_KEY_SIZE);
  226. + memset(pass, 0, strlen(pass));
  227. + } else {
  228. + /* If we're reading from an extenral program, *
  229. + * odds are good that a SIGCHLD will interrupt *
  230. + * this read(), and ruin our whole day. So we *
  231. + * must block it. */
  232. + sigset_t ss, oss;
  233. + sigemptyset(&ss);
  234. + sigaddset(&ss, SIGCHLD);
  235. + sigprocmask(SIG_BLOCK, &ss, &oss);
  236. + if (read(pfd, loopinfo64.lo_encrypt_key,
  237. + LO_KEY_SIZE) == -1) {
  238. + perror("read");
  239. + fprintf(stderr, _("Error reading encryption key, exiting\n"));
  240. + }
  241. + sigprocmask(SIG_SETMASK, &oss, NULL);
  242. + }
  243. }
  244. if (ioctl(fd, LOOP_SET_FD, ffd) < 0) {
  245. @@ -325,20 +446,44 @@
  246. struct loop_info loopinfo;
  247. int errsv = errno;
  248. + if (errno == EINVAL &&
  249. + loopinfo64.lo_encrypt_type == LO_CRYPT_CRYPTOAPI)
  250. + if (!check_crypto(&loopinfo64)) {
  251. + fprintf(stderr,
  252. + _("Error in crypto parameters, exiting\n"));
  253. + goto fail;
  254. + }
  255. +
  256. +
  257. i = loop_info64_to_old(&loopinfo64, &loopinfo);
  258. if (i) {
  259. errno = errsv;
  260. perror("ioctl: LOOP_SET_STATUS64");
  261. } else {
  262. i = ioctl(fd, LOOP_SET_STATUS, &loopinfo);
  263. - if (i)
  264. + if (i) {
  265. + if (i<0) {
  266. + errsv = errno;
  267. +
  268. + if (errno == EINVAL &&
  269. + loopinfo.lo_encrypt_type == LO_CRYPT_CRYPTOAPI)
  270. + if (!check_crypto_old(&loopinfo)) {
  271. + fprintf(stderr,
  272. + _("Error in crypto parameters, exiting\n"));
  273. + goto fail;
  274. + }
  275. +
  276. + errno = errsv;
  277. + }
  278. perror("ioctl: LOOP_SET_STATUS");
  279. + }
  280. }
  281. memset(&loopinfo, 0, sizeof(loopinfo));
  282. }
  283. memset(&loopinfo64, 0, sizeof(loopinfo64));
  284. if (i) {
  285. +fail:
  286. ioctl (fd, LOOP_CLR_FD, 0);
  287. close (fd);
  288. return 1;
  289. @@ -420,6 +563,22 @@
  290. exit(1);
  291. }
  292. +void *
  293. +xmalloc (size_t size) {
  294. + void *t;
  295. +
  296. + if (size == 0)
  297. + return NULL;
  298. +
  299. + t = malloc (size);
  300. + if (t == NULL) {
  301. + fprintf(stderr, _("not enough memory"));
  302. + exit(1);
  303. + }
  304. +
  305. + return t;
  306. +}
  307. +
  308. char *
  309. xstrdup (const char *s) {
  310. char *t;
  311. Nur in util-linux-2.12h-patch/mount: lomount.c~.
  312. diff -dur util-linux-2.12h/mount/mount.8 util-linux-2.12h-patch/mount/mount.8
  313. --- util-linux-2.12h/mount/mount.8 2004-09-19 20:00:49.000000000 +0000
  314. +++ util-linux-2.12h-patch/mount/mount.8 2004-10-23 03:36:52.385724832 +0000
  315. @@ -1759,6 +1759,11 @@
  316. .BR loop ", " offset " and " encryption ,
  317. that are really options to
  318. .BR losetup (8).
  319. +You can also use the
  320. +.BR keygen
  321. +option to have mount call an external program from, which it will read the
  322. +encryption key. Arguments to this program can be given, separated by semicolons.
  323. +
  324. If no explicit loop device is mentioned
  325. (but just an option `\fB\-o loop\fP' is given), then
  326. .B mount
  327. diff -dur util-linux-2.12h/mount/mount.c util-linux-2.12h-patch/mount/mount.c
  328. --- util-linux-2.12h/mount/mount.c 2004-10-13 20:54:39.000000000 +0000
  329. +++ util-linux-2.12h-patch/mount/mount.c 2004-10-23 03:36:52.386724680 +0000
  330. @@ -164,7 +164,7 @@
  331. };
  332. static const char *opt_loopdev, *opt_vfstype, *opt_offset, *opt_encryption,
  333. - *opt_speed, *opt_comment;
  334. + *opt_keygen, *opt_speed, *opt_comment;
  335. static struct string_opt_map {
  336. char *tag;
  337. @@ -175,6 +175,7 @@
  338. { "vfs=", 1, &opt_vfstype },
  339. { "offset=", 0, &opt_offset },
  340. { "encryption=", 0, &opt_encryption },
  341. + { "keygen=", 0, &opt_keygen },
  342. { "speed=", 0, &opt_speed },
  343. { "comment=", 1, &opt_comment },
  344. { NULL, 0, NULL }
  345. @@ -570,7 +571,7 @@
  346. *type = opt_vfstype;
  347. }
  348. - *loop = ((*flags & MS_LOOP) || *loopdev || opt_offset || opt_encryption);
  349. + *loop = ((*flags & MS_LOOP) || *loopdev || opt_offset || opt_encryption || opt_keygen);
  350. *loopfile = *spec;
  351. if (*loop) {
  352. @@ -580,6 +581,11 @@
  353. printf(_("mount: skipping the setup of a loop device\n"));
  354. } else {
  355. int loopro = (*flags & MS_RDONLY);
  356. + /* Extra args to the keygen program. Right now there are 2: *
  357. + * - the looped file *
  358. + * - the encryption type used */
  359. + char *keygen_args[] = {*loopfile, opt_encryption};
  360. + const int _n_keygen_args = 2;
  361. if (!*loopdev || !**loopdev)
  362. *loopdev = find_unused_loop_device();
  363. @@ -588,6 +594,8 @@
  364. if (verbose)
  365. printf(_("mount: going to use the loop device %s\n"), *loopdev);
  366. offset = opt_offset ? strtoull(opt_offset, NULL, 0) : 0;
  367. + if (opt_keygen)
  368. + pfd = use_keygen_prog(opt_keygen, keygen_args, _n_keygen_args);
  369. if (set_loop(*loopdev, *loopfile, offset,
  370. opt_encryption, pfd, &loopro)) {
  371. if (verbose)
  372. diff -dur util-linux-2.12h/mount/sundries.c util-linux-2.12h-patch/mount/sundries.c
  373. --- util-linux-2.12h/mount/sundries.c 2004-10-13 21:15:39.000000000 +0000
  374. +++ util-linux-2.12h-patch/mount/sundries.c 2004-10-23 03:36:52.387724528 +0000
  375. @@ -12,6 +12,8 @@
  376. #include <stdio.h>
  377. #include <string.h>
  378. #include <mntent.h> /* for MNTTYPE_SWAP */
  379. +#include <sys/types.h>
  380. +#include <sys/wait.h>
  381. #include "fstab.h"
  382. #include "sundries.h"
  383. #include "realpath.h"
  384. @@ -288,3 +290,100 @@
  385. return xstrdup(path);
  386. }
  387. +
  388. +static volatile int keygen_wait = 1;
  389. +
  390. +/* Handle a SIGCHLD -- wait for the child process */
  391. +static void
  392. +child_handler (int i) {
  393. + int status;
  394. + if (keygen_wait && wait(&status) != -1) {
  395. + keygen_wait = 0;
  396. + if (WEXITSTATUS(status) != 0)
  397. + exit(WEXITSTATUS(status));
  398. + }
  399. +}
  400. +
  401. +/* Make sure we clean up after the child */
  402. +static void
  403. +child_cleanup (void) {
  404. + /* "Clean up" means wait. So we let child_handler do all the work */
  405. + while (keygen_wait)
  406. + sleep(1);
  407. +}
  408. +
  409. +/* Split a string into pieces, using delim as the delimiter. *
  410. + * Returns the number of pieces. */
  411. +static int
  412. +split_args (char *args[], const char *str, const char *delim, int nargs) {
  413. + int i=0;
  414. + char *s = xstrdup(str);
  415. + args[0] = strtok(s, delim);
  416. + if (args[0] == NULL)
  417. + return 0;
  418. +
  419. + while (++i < nargs) {
  420. + if ((args[i] = strtok(NULL, delim)) == NULL)
  421. + break;
  422. + }
  423. +
  424. + return i;
  425. +}
  426. +
  427. +#define KEYGEN_MAX_ARGS 64 /* more than anyone will need, right? */
  428. +
  429. +/* Call an external program to give us the encryption key for an *
  430. + * encrypted device. We split the string s into a command and args on *
  431. + * semicolons ('cuz you can't put spaces in the fs_mntopts field), then *
  432. + * add some specific args (eg. the looped file or device, the *
  433. + * encryption method used; check the caller to see the actual list). *
  434. + * Returns a file descriptor from which we read the key. */
  435. +int
  436. +use_keygen_prog (const char *s, const char *addl_args[], int naddl_args) {
  437. + int fd[2];
  438. + pid_t keygen_pid;
  439. + struct sigaction sa;
  440. + sa.sa_handler = child_handler;
  441. + sa.sa_flags = SA_NOCLDSTOP;
  442. +
  443. + if (pipe(fd) == -1) {
  444. + perror("pipe");
  445. + exit(EX_SYSERR);
  446. + }
  447. + if (sigaction(SIGCHLD, &sa, NULL) == -1) {
  448. + perror("sigaction");
  449. + exit(EX_SYSERR);
  450. + }
  451. + if ((keygen_pid = fork()) == -1) {
  452. + perror("fork");
  453. + exit(EX_SYSERR);
  454. + } else if (keygen_pid) { /* parent */
  455. + atexit(child_cleanup);
  456. + close(fd[1]);
  457. + return fd[0];
  458. + } else { /* child */
  459. + char *args[KEYGEN_MAX_ARGS+1];
  460. + int i, n = split_args(args, s, ";", KEYGEN_MAX_ARGS - naddl_args);
  461. + if (!n) {
  462. + fprintf(stderr, _("Invalid keygen program, exiting\n"));
  463. + exit(EX_USAGE);
  464. + }
  465. + for(i=0; i < naddl_args && n+i < KEYGEN_MAX_ARGS; i++)
  466. + args[n+i] = (char *) addl_args[i];
  467. + args[n+i] = NULL;
  468. +
  469. + close(fd[0]);
  470. + if (dup2(fd[1], STDOUT_FILENO) == -1) {
  471. + perror("dup2");
  472. + exit(EX_SYSERR);
  473. + }
  474. + setuid(getuid()); /* set euid to ruid */
  475. + if (execvp(args[0], args) == -1) {
  476. + perror(args[0]);
  477. + exit(EX_USAGE);
  478. + }
  479. + }
  480. +
  481. + return 0; /* so gcc will shut up */
  482. +}
  483. +
  484. diff -dur util-linux-2.12h/mount/sundries.h util-linux-2.12h-patch/mount/sundries.h
  485. --- util-linux-2.12h/mount/sundries.h 2002-11-01 01:00:50.000000000 +0000
  486. +++ util-linux-2.12h-patch/mount/sundries.h 2004-10-23 03:36:52.387724528 +0000
  487. @@ -25,6 +25,7 @@
  488. void error (const char *fmt, ...);
  489. int matching_type (const char *type, const char *types);
  490. int matching_opts (const char *options, const char *test_opts);
  491. +int use_keygen_prog (const char *s, const char *addl_args[], int naddl_args);
  492. void *xmalloc (size_t size);
  493. char *xstrdup (const char *s);
  494. char *xstrndup (const char *s, int n);