Репозиторий Sisyphus
Последнее обновление: 1 октября 2023 | Пакетов: 18631 | Посещений: 37868423
en ru br
Репозитории ALT
S:2.39.2-alt1
5.1: 2.16.1-alt1
4.1: 2.13-alt8
4.0: 2.12r-alt6
3.0: 2.12q-alt1
www.altlinux.org/Changes

Группа :: Система/Основа
Пакет: util-linux

 Главная   Изменения   Спек   Патчи   Sources   Загрузить   Gear   Bugs and FR  Repocop 

Патч: util-linux-2.12p-cryptoloop.patch
Скачать


diff -Naur util-linux-2.12p/mount/lomount.c util-linux-2.12p.new/mount/lomount.c
--- util-linux-2.12p/mount/lomount.c	2005-02-10 14:46:23 +0300
+++ util-linux-2.12p.new/mount/lomount.c	2005-02-10 14:47:08 +0300
@@ -17,6 +17,10 @@
 #include <sys/stat.h>
 #include <sys/mman.h>
 #include <sys/sysmacros.h>
+#include <limits.h>
+#include <sys/types.h> 
+#include <regex.h>
+#include <signal.h> 
 
 #include "loop.h"
 #include "lomount.h"
@@ -26,6 +30,7 @@
 extern int verbose;
 extern char *progname;
 extern char *xstrdup (const char *s);	/* not: #include "sundries.h" */
+extern void *xmalloc (size_t size);             /* idem */ 
 extern void error (const char *fmt, ...);	/* idem */
 
 #ifdef LOOP_SET_FD
@@ -190,52 +195,121 @@
 	return 0;
 }
 
-/*
- * A function to read the passphrase either from the terminal or from
- * an open file descriptor.
- */
-static char *
-xgetpass(int pfd, const char *prompt) {
-	char *pass;
-	int buflen, i;
-
-        if (pfd < 0) /* terminal */
-		return getpass(prompt);
+static int
+digits_only(const char *s) {
+	while (*s)
+		if (!isdigit(*s++))
+			return 0;
+	return 1;
+}
 
-	pass = NULL;
-	buflen = 0;
-	for (i=0; ; i++) {
-		if (i >= buflen-1) {
-				/* we're running out of space in the buffer.
-				 * Make it bigger: */
-			char *tmppass = pass;
-			buflen += 128;
-			pass = realloc(tmppass, buflen);
-			if (pass == NULL) {
-				/* realloc failed. Stop reading. */
-				error("Out of memory while reading passphrase");
-				pass = tmppass; /* the old buffer hasn't changed */
+/* A function to check the encryption parameters against /proc/crypto.	*
+ * Returns 1 if everything checks out, 0 if there's any problem.	*
+ * The purpose of this function is not so much to verify the parameters	*
+ * before setting up the loop device; that task is made difficult by	*
+ * the possibility of loadable encryption modules and the necessity of	*
+ * falling back to the old (kerneli.org) CryptoAPI. Rather the intent	*
+ * is to come up with a more useful error message after the setup	*
+ * fails. Thus we return 1 in the event that some system error prevents	*
+ * us from getting the info we want from /proc/crypto.			*/
+static int
+check_crypto(struct loop_info64 *loopinfo64) {
+	char *s = xmalloc(LINE_MAX), *name = xmalloc(LINE_MAX),
+		cipher_name[LO_NAME_SIZE+1];
+	int cipher_found = 0, min_size = 0, max_size = 0, retval;
+	FILE *fp;
+	struct stat st;
+
+	if (stat("/proc/crypto", &st) == -1) {
+		retval = 1;
+		goto end;
+	} else if (S_ISDIR(st.st_mode)) {
+		/* Hm... must be using the old CryptoAPI. */
+		retval = 1;
+		goto end;
+	} else if ((fp = fopen("/proc/crypto", "r")) == NULL) {
+		retval = 1;
+		goto end;
+	}
+
+	xstrncpy(cipher_name, loopinfo64->lo_crypt_name, LO_NAME_SIZE);
+	/* Chop off the cipher mode (ie. everything after the dash) */
+	cipher_name[strcspn(cipher_name, "-")] = '\0';
+
+	while (fgets(s, LINE_MAX, fp) != NULL) {
+		if (sscanf(s, "name : %s", name) > 0) {
+			if (strcmp(name, cipher_name) == 0)
+				cipher_found = 1;
+			else if (cipher_found)
 				break;
-			}
+		} else {
+			sscanf(s, "min keysize : %d", &min_size);
+			sscanf(s, "max keysize : %d", &max_size);
 		}
-		if (read(pfd, pass+i, 1) != 1 ||
-		    pass[i] == '\n' || pass[i] == 0)
-			break;
 	}
+	fclose(fp);
 
-	if (pass == NULL)
-		return "";
-
-	pass[i] = 0;
-	return pass;
+	if (!cipher_found) {
+		fprintf(stderr, _("Invalid cipher \"%s\"\n"), cipher_name);
+		retval = 0;
+		goto end;
+	} else if (loopinfo64->lo_encrypt_key_size < min_size ||
+		   loopinfo64->lo_encrypt_key_size > max_size) {
+		fprintf(stderr, _("Invalid key length (%d) for %s cipher\n"),
+			loopinfo64->lo_encrypt_key_size, cipher_name);
+		retval = 0;
+		goto end;
+	}
+
+	retval = 1;
+end:
+	free(s);
+	free(name);
+	return retval;
 }
 
+/* Same thing, for the old CryptoAPI. */
 static int
-digits_only(const char *s) {
-	while (*s)
-		if (!isdigit(*s++))
-			return 0;
-	return 1;
+check_crypto_old(struct loop_info *loopinfo) {
+	char *s = xmalloc(LINE_MAX), *name = xmalloc(PATH_MAX+1),
+		cipher_name[LO_NAME_SIZE+1];
+	int mask = 0, retval;
+	FILE *fp;
+	struct stat st;
+
+	if (stat("/proc/crypto/cipher", &st) == -1) {
+		retval = 1;
+		goto end;
+	} else if (!S_ISDIR(st.st_mode)) {
+		retval = 1;
+		goto end;
+	}
+		
+	xstrncpy(cipher_name, loopinfo->lo_name, LO_NAME_SIZE);
+	snprintf(name, PATH_MAX+1, "/proc/crypto/cipher/%s", cipher_name);
+	if ((fp = fopen(name, "r")) == NULL) {
+		fprintf(stderr, _("Invalid cipher \"%s\"\n"), cipher_name);
+		retval = 0;
+		goto end;
+	}
+
+	while (fgets(s, LINE_MAX, fp) != NULL) {
+		sscanf(s, "keysize_mask : %i", &mask);
+	}
+	fclose(fp);
+
+	if (!(mask & (1 << (loopinfo->lo_encrypt_key_size - 1)))) {
+		fprintf(stderr, _("Invalid key length (%d) for %s cipher\n"),
+			loopinfo->lo_encrypt_key_size, cipher_name);
+		retval = 0;
+		goto end;
+	}
+
+	retval = 1;
+end:
+	free(s);
+	free(name);
+	return retval;
 }
 
 int
@@ -269,9 +343,40 @@
 		if (digits_only(encryption)) {
 			loopinfo64.lo_encrypt_type = atoi(encryption);
 		} else {
+			regex_t keysize_re;
+			regmatch_t keysize_rm;
+			int rerror;
+			char *rerror_buf, *encryption_dup = xstrdup(encryption);
+
 			loopinfo64.lo_encrypt_type = LO_CRYPT_CRYPTOAPI;
+
+			if ((rerror = regcomp(&keysize_re, "-[[:digit:]]+$",
+					      REG_EXTENDED)) != 0) {
+				fprintf(stderr, _("RE error: "));	
+				rerror_buf = xmalloc(LINE_MAX+1);
+				regerror(rerror, &keysize_re, rerror_buf, LINE_MAX);
+				fprintf(stderr, "%s\n", rerror_buf);
+				free(rerror_buf);
+				return -1;
+			}
+			rerror = regexec(&keysize_re, encryption_dup,
+					 1, &keysize_rm, 0);
+			regfree(&keysize_re);
+			if (rerror) {
+				fprintf(stderr,
+					_("You must specify a key size (in bits) "
+					  "for use with CryptoAPI encryption.\n"));
+				return -1;
+			}
+
+			/* convert the key size from #bits to #bytes */
+			loopinfo64.lo_encrypt_key_size =
+				atoi(encryption_dup + keysize_rm.rm_so + 1) / 8;
+			/* now cut off the key size */
+			encryption_dup[keysize_rm.rm_so] = '\0';
 			snprintf(loopinfo64.lo_crypt_name, LO_NAME_SIZE,
-				 "%s", encryption);
+				 "%s", encryption_dup);
+			free(encryption_dup);
 		}
 	}
 
@@ -294,15 +399,28 @@
 	case LO_CRYPT_NONE:
 		loopinfo64.lo_encrypt_key_size = 0;
 		break;
-	case LO_CRYPT_XOR:
-		pass = getpass(_("Password: "));
-		goto gotpass;
 	default:
-		pass = xgetpass(pfd, _("Password: "));
-	gotpass:
 		memset(loopinfo64.lo_encrypt_key, 0, LO_KEY_SIZE);
-		xstrncpy(loopinfo64.lo_encrypt_key, pass, LO_KEY_SIZE);
-		memset(pass, 0, strlen(pass));
+		if (pfd == -1) {
+			pass = getpass(_("Password: "));
+			xstrncpy(loopinfo64.lo_encrypt_key, pass, LO_KEY_SIZE);
+			memset(pass, 0, strlen(pass));
+		} else {
+			/* If we're reading from an extenral program,	*
+			 * odds are good that a SIGCHLD will interrupt	*
+			 * this read(), and ruin our whole day. So we	*
+			 * must block it.				*/
+			sigset_t ss, oss;
+			sigemptyset(&ss);
+			sigaddset(&ss, SIGCHLD);
+			sigprocmask(SIG_BLOCK, &ss, &oss);
+			if (read(pfd, loopinfo64.lo_encrypt_key,
+				 LO_KEY_SIZE) == -1) {
+				perror("read");
+				fprintf(stderr, _("Error reading encryption key, exiting\n"));
+			}
+			sigprocmask(SIG_SETMASK, &oss, NULL);
+		}
 		loopinfo64.lo_encrypt_key_size = LO_KEY_SIZE;
 	}
 
@@ -317,20 +435,40 @@
 		struct loop_info loopinfo;
 		int errsv = errno;
 
+		if (errno == EINVAL &&
+		    loopinfo64.lo_encrypt_type == LO_CRYPT_CRYPTOAPI &&
+		    !check_crypto(&loopinfo64)) {
+				fprintf(stderr,
+					_("Error in crypto parameters, exiting\n"));
+				goto fail;
+		}
+
+
 		i = loop_info64_to_old(&loopinfo64, &loopinfo);
 		if (i) {
 			errno = errsv;
 			perror("ioctl: LOOP_SET_STATUS64");
 		} else {
 			i = ioctl(fd, LOOP_SET_STATUS, &loopinfo);
-			if (i)
-				perror("ioctl: LOOP_SET_STATUS");
+			if (i) {
+				errsv = errno;
+				if (errno == EINVAL &&
+			    	    loopinfo.lo_encrypt_type == LO_CRYPT_CRYPTOAPI &&
+				    !check_crypto_old(&loopinfo)) {
+						fprintf(stderr,
+							_("Error in crypto parameters, exiting\n"));
+				} else {
+					errno = errsv;
+					perror("ioctl: LOOP_SET_STATUS");
+				}
+			}
 		}
 		memset(&loopinfo, 0, sizeof(loopinfo));
 	}
 	memset(&loopinfo64, 0, sizeof(loopinfo64));
 
 	if (i) {
+fail:
 		ioctl (fd, LOOP_CLR_FD, 0);
 		close (fd);
 		return 1;
@@ -430,6 +568,23 @@
 	return t;
 }
 
+void *
+xmalloc (size_t size) {
+	void *t;
+
+	if (size == 0)
+		return NULL;
+
+	t = malloc (size);
+	if (t == NULL) {
+		fprintf(stderr, _("not enough memory"));
+		exit(1);
+	}
+
+	return t;
+}
+
+
 void
 error (const char *fmt, ...) {
 	va_list args;
diff -Naur util-linux-2.12p/mount/mount.8 util-linux-2.12p.new/mount/mount.8
--- util-linux-2.12p/mount/mount.8	2004-12-20 01:30:14 +0300
+++ util-linux-2.12p.new/mount/mount.8	2005-02-10 14:46:41 +0300
@@ -1928,6 +1928,10 @@
 .BR mke2fs (8),
 .BR tune2fs (8),
 .BR losetup (8)
+You can also use the
+.BR keygen
+option to have mount call an external program from, which it will read the
+encryption key. Arguments to this program can be given, separated by semicolons.
 .SH BUGS
 It is possible for a corrupted file system to cause a crash.
 .PP
diff -Naur util-linux-2.12p/mount/mount.c util-linux-2.12p.new/mount/mount.c
--- util-linux-2.12p/mount/mount.c	2005-02-10 14:46:23 +0300
+++ util-linux-2.12p.new/mount/mount.c	2005-02-10 14:46:41 +0300
@@ -168,7 +168,7 @@
 };
 
 static const char *opt_loopdev, *opt_vfstype, *opt_offset, *opt_encryption,
-	*opt_speed, *opt_comment;
+	*opt_speed, *opt_comment, *opt_keygen;
 
 static struct string_opt_map {
   char *tag;
@@ -181,6 +181,7 @@
   { "encryption=", 0, &opt_encryption },
   { "speed=", 0, &opt_speed },
   { "comment=", 1, &opt_comment },
+  { "keygen=", 0, &opt_keygen },
   { NULL, 0, NULL }
 };
 
@@ -607,7 +608,7 @@
       *type = opt_vfstype;
   }
 
-  *loop = ((*flags & MS_LOOP) || *loopdev || opt_offset || opt_encryption);
+  *loop = ((*flags & MS_LOOP) || *loopdev || opt_offset || opt_encryption || opt_keygen);
   *loopfile = *spec;
 
   if (*loop) {
@@ -617,6 +618,12 @@
 	printf(_("mount: skipping the setup of a loop device\n"));
     } else {
       int loopro = (*flags & MS_RDONLY);
+      /* Extra args to the keygen program. Right now there are 2:	*
+       *   - the looped file						*
+       *   - the encryption type used					*/
+      char *keygen_args[] = {*loopfile, opt_encryption};
+      const int _n_keygen_args = 2;
+
 
       if (!*loopdev || !**loopdev)
 	*loopdev = find_unused_loop_device();
@@ -625,6 +632,8 @@
       if (verbose)
 	printf(_("mount: going to use the loop device %s\n"), *loopdev);
       offset = opt_offset ? strtoull(opt_offset, NULL, 0) : 0;
+      if (opt_keygen)
+	pfd = use_keygen_prog(opt_keygen, keygen_args, _n_keygen_args);
       if (set_loop(*loopdev, *loopfile, offset,
 		   opt_encryption, pfd, &loopro)) {
 	if (verbose)
diff -Naur util-linux-2.12p/mount/sundries.c util-linux-2.12p.new/mount/sundries.c
--- util-linux-2.12p/mount/sundries.c	2004-12-21 22:12:31 +0300
+++ util-linux-2.12p.new/mount/sundries.c	2005-02-10 14:46:41 +0300
@@ -12,6 +12,8 @@
 #include <stdio.h>
 #include <string.h>
 #include <mntent.h>		/* for MNTTYPE_SWAP */
+#include <sys/types.h>
+#include <sys/wait.h>
 #include "fstab.h"
 #include "sundries.h"
 #include "realpath.h"
@@ -246,3 +248,100 @@
 
 	return xstrdup(path);
 }
+
+static volatile int keygen_wait = 1;
+
+/* Handle a SIGCHLD -- wait for the child process */
+static void
+child_handler (int i) {
+	int status;
+	if (keygen_wait && wait(&status) != -1) {
+		keygen_wait = 0;
+		if (WEXITSTATUS(status) != 0)
+			exit(WEXITSTATUS(status));
+	}
+}
+
+/* Make sure we clean up after the child */
+static void
+child_cleanup (void) {
+	/* "Clean up" means wait. So we let child_handler do all the work */
+	while (keygen_wait)
+		sleep(1);
+}
+
+/* Split a string into pieces, using delim as the delimiter.		*
+ * Returns the number of pieces.					*/
+static int
+split_args (char *args[], const char *str, const char *delim, int nargs) {
+	int i=0;
+	char *s = xstrdup(str);
+	args[0] = strtok(s, delim);
+	if (args[0] == NULL)
+		return 0;
+
+	while (++i < nargs) {
+		if ((args[i] = strtok(NULL, delim)) == NULL)
+			break;
+	}
+
+	return i;
+}
+
+#define KEYGEN_MAX_ARGS 64	/* more than anyone will need, right? */
+
+/* Call an external program to give us the encryption key for an	*
+ * encrypted device. We split the string s into a command and args on	*
+ * semicolons ('cuz you can't put spaces in the fs_mntopts field), then	*
+ * add some specific args (eg. the looped file or device, the		*
+ * encryption method used; check the caller to see the actual list).	*
+ * Returns a file descriptor from which we read the key.		*/
+int
+use_keygen_prog (const char *s, const char *addl_args[], int naddl_args) {
+	int fd[2]; 
+	pid_t keygen_pid;
+	struct sigaction sa;
+	sa.sa_handler = child_handler;
+	sa.sa_flags = SA_NOCLDSTOP;
+
+	if (pipe(fd) == -1) {
+		perror("pipe");
+		exit(EX_SYSERR);
+	}
+	if (sigaction(SIGCHLD, &sa, NULL) == -1) {
+		perror("sigaction");
+		exit(EX_SYSERR);
+	}
+	if ((keygen_pid = fork()) == -1) {
+		perror("fork");
+		exit(EX_SYSERR);
+	} else if (keygen_pid) {	/* parent */
+		atexit(child_cleanup);
+		close(fd[1]);
+		return fd[0];
+	} else {		/* child */
+		char *args[KEYGEN_MAX_ARGS+1];
+		int i, n = split_args(args, s, ";", KEYGEN_MAX_ARGS - naddl_args);
+		if (!n) {
+			fprintf(stderr, _("Invalid keygen program, exiting\n"));
+			exit(EX_USAGE);
+		}
+		for(i=0; i < naddl_args && n+i < KEYGEN_MAX_ARGS; i++)
+			args[n+i] = (char *) addl_args[i];
+		args[n+i] = NULL;
+
+		close(fd[0]);
+		if (dup2(fd[1], STDOUT_FILENO) == -1) {
+			perror("dup2");
+			exit(EX_SYSERR);
+		}
+		setuid(getuid());	/* set euid to ruid */
+		if (execvp(args[0], args) == -1) {
+			perror(args[0]);
+			exit(EX_USAGE);
+		}
+	}
+
+	return 0; /* so gcc will shut up */
+}
+
diff -Naur util-linux-2.12p/mount/sundries.h util-linux-2.12p.new/mount/sundries.h
--- util-linux-2.12p/mount/sundries.h	2004-12-22 00:59:59 +0300
+++ util-linux-2.12p.new/mount/sundries.h	2005-02-10 14:46:41 +0300
@@ -25,6 +25,7 @@
 void error (const char *fmt, ...);
 int matching_type (const char *type, const char *types);
 int matching_opts (const char *options, const char *test_opts);
+int use_keygen_prog (const char *s, const char *addl_args[], int naddl_args);
 void *xmalloc (size_t size);
 char *xstrdup (const char *s);
 char *xstrndup (const char *s, int n);
 
дизайн и разработка: Vladimir Lettiev aka crux © 2004-2005, Andrew Avramenko aka liks © 2007-2008
текущий майнтейнер: Michael Shigorin