static int get_alignment(int fd)
{
- int alignment = DEFAULT_ALIGNMENT;
+ int alignment = DEFAULT_MEM_ALIGNMENT;
#ifdef _PC_REC_XFER_ALIGN
alignment = fpathconf(fd, _PC_REC_XFER_ALIGN);
if (alignment < 0)
- alignment = DEFAULT_ALIGNMENT;
+ alignment = DEFAULT_MEM_ALIGNMENT;
#endif
return alignment;
}
tcsetattr(infd, TCSAFLUSH, &orig);
out_err:
- if (!failed)
- (void)write(outfd, "\n", 1);
+ if (!failed && write(outfd, "\n", 1));
+
if (infd != STDIN_FILENO)
close(infd);
return failed;
/*
* Password reading behaviour matrix of get_key
- *
+ * FIXME: rewrite this from scratch.
* p v n h
* -----------------+---+---+---+---
* interactive | Y | Y | Y | Inf
* Legend: p..prompt, v..can verify, n..newline-stop, h..read horizon
*
* Note: --key-file=- is interpreted as a read from a binary file (stdin)
- *
- * Returns true when more keys are available (that is when password
- * reading can be retried as for interactive terminals).
*/
-int get_key(char *prompt, char **key, unsigned int *passLen, int key_size,
- const char *key_file, int passphrase_fd, int timeout, int how2verify, struct crypt_device *cd)
+void get_key(char *prompt, char **key, unsigned int *passLen, int key_size,
+ const char *key_file, int timeout, int how2verify,
+ struct crypt_device *cd)
{
- int fd;
+ int fd = -1;
const int verify = how2verify & CRYPT_FLAG_VERIFY;
const int verify_if_possible = how2verify & CRYPT_FLAG_VERIFY_IF_POSSIBLE;
char *pass = NULL;
- int newline_stop;
int read_horizon;
+ int regular_file = 0;
+ int read_stdin;
+ int r;
+ struct stat st;
- if(key_file && !strcmp(key_file, "-")) {
- /* Allow binary reading from stdin */
- fd = passphrase_fd;
- newline_stop = 0;
- read_horizon = 0;
- } else if (key_file) {
- fd = open(key_file, O_RDONLY);
- if (fd < 0) {
- log_err(cd, "Failed to open key file %s.\n", key_file);
- goto out_err;
- }
- newline_stop = 0;
+ /* Passphrase read from stdin? */
+ read_stdin = (!key_file || !strcmp(key_file, "-")) ? 1 : 0;
- /* This can either be 0 (LUKS) or the actually number
- * of key bytes (default or passed by -s) */
- read_horizon = key_size;
- } else {
- fd = STDIN_FILENO;
- newline_stop = 1;
- read_horizon = 0; /* Infinite, if read from terminal or fd */
+ /* read_horizon applies only for real keyfile, not stdin or terminal */
+ read_horizon = (key_file && !read_stdin) ? key_size : 0 /* until EOF */;
+
+ /* Setup file descriptior */
+ fd = read_stdin ? STDIN_FILENO : open(key_file, O_RDONLY);
+ if (fd < 0) {
+ log_err(cd, _("Failed to open key file %s.\n"), key_file ?: "-");
+ goto out_err;
}
/* Interactive case */
pass = safe_alloc(MAX_TTY_PASSWORD_LEN);
if (!pass || (i = interactive_pass(prompt, pass, MAX_TTY_PASSWORD_LEN, timeout))) {
- log_err(cd, "Error reading passphrase from terminal.\n");
+ log_err(cd, _("Error reading passphrase from terminal.\n"));
goto out_err;
}
if (verify || verify_if_possible) {
char pass_verify[MAX_TTY_PASSWORD_LEN];
- i = interactive_pass("Verify passphrase: ", pass_verify, sizeof(pass_verify), timeout);
+ i = interactive_pass(_("Verify passphrase: "), pass_verify, sizeof(pass_verify), timeout);
if (i || strcmp(pass, pass_verify) != 0) {
- log_err(cd, "Passphrases do not match.\n");
+ log_err(cd, _("Passphrases do not match.\n"));
goto out_err;
}
memset(pass_verify, 0, sizeof(pass_verify));
int buflen, i;
if(verify) {
- log_err(cd, "Can't do passphrase verification on non-tty inputs.\n");
+ log_err(cd, _("Can't do passphrase verification on non-tty inputs.\n"));
goto out_err;
}
/* The following for control loop does an exhausting
* should warn the user, if it's a non-regular file,
* such as /dev/random, because in this case, the loop
* will read forever.
- */
- if(key_file && strcmp(key_file, "-") && read_horizon == 0) {
- struct stat st;
+ */
+ if(!read_stdin && read_horizon == 0) {
if(stat(key_file, &st) < 0) {
- log_err(cd, "Failed to stat key file %s.\n", key_file);
+ log_err(cd, _("Failed to stat key file %s.\n"), key_file);
goto out_err;
}
- if(!S_ISREG(st.st_mode)) {
- log_err(cd, "Warning: exhausting read requested, but key file %s"
- " is not a regular file, function might never return.\n",
+ if(!S_ISREG(st.st_mode))
+ log_std(cd, _("Warning: exhausting read requested, but key file %s"
+ " is not a regular file, function might never return.\n"),
key_file);
- }
+ else
+ regular_file = 1;
}
buflen = 0;
for(i = 0; read_horizon == 0 || i < read_horizon; i++) {
buflen += 128;
pass = safe_realloc(pass, buflen);
if (!pass) {
- log_err(cd, "Out of memory while reading passphrase.\n");
+ log_err(cd, _("Out of memory while reading passphrase.\n"));
goto out_err;
}
}
- if(read(fd, pass + i, 1) != 1 || (newline_stop && pass[i] == '\n'))
+
+ r = read(fd, pass + i, 1);
+ if (r < 0) {
+ log_err(cd, _("Error reading passphrase.\n"));
+ goto out_err;
+ }
+
+ /* Stop on newline only if not requested read from keyfile */
+ if(r == 0 || (!key_file && pass[i] == '\n'))
break;
}
- if(key_file)
- close(fd);
+ /* Fail if piped input dies reading nothing */
+ if(!i && !regular_file) {
+ log_dbg("Error reading passphrase.");
+ goto out_err;
+ }
pass[i] = 0;
*key = pass;
*passLen = i;
}
-
- return isatty(fd); /* Return true, when password reading can be tried on interactive fds */
+ if(fd != STDIN_FILENO)
+ close(fd);
+ return;
out_err:
+ if(fd >= 0 && fd != STDIN_FILENO)
+ close(fd);
if(pass)
safe_free(pass);
*key = NULL;
*passLen = 0;
- return 0;
+}
+
+int device_ready(struct crypt_device *cd, const char *device, int mode)
+{
+ int devfd, r = 1;
+ ssize_t s;
+ struct stat st;
+ char buf[512];
+
+ if(stat(device, &st) < 0) {
+ log_err(cd, _("Device %s doesn't exist or access denied.\n"), device);
+ return 0;
+ }
+
+ log_dbg("Trying to open and read device %s.", device);
+ devfd = open(device, mode | O_DIRECT | O_SYNC);
+ if(devfd < 0) {
+ log_err(cd, _("Cannot open device %s for %s%s access.\n"), device,
+ (mode & O_EXCL) ? _("exclusive ") : "",
+ (mode & O_RDWR) ? _("writable") : _("read-only"));
+ return 0;
+ }
+
+ /* Try to read first sector */
+ s = read_blockwise(devfd, buf, sizeof(buf));
+ if (s < 0 || s != sizeof(buf)) {
+ log_err(cd, _("Cannot read device %s.\n"), device);
+ r = 0;
+ }
+
+ memset(buf, 0, sizeof(buf));
+ close(devfd);
+
+ return r;
+}
+
+int get_device_infos(const char *device, struct device_infos *infos, struct crypt_device *cd)
+{
+ uint64_t size;
+ unsigned long size_small;
+ int readonly = 0;
+ int ret = -1;
+ int fd;
+
+ /* Try to open read-write to check whether it is a read-only device */
+ fd = open(device, O_RDWR);
+ if (fd < 0) {
+ if (errno == EROFS) {
+ readonly = 1;
+ fd = open(device, O_RDONLY);
+ }
+ } else {
+ close(fd);
+ fd = open(device, O_RDONLY);
+ }
+ if (fd < 0) {
+ log_err(cd, _("Cannot open device: %s\n"), device);
+ return -1;
+ }
+
+#ifdef BLKROGET
+ /* If the device can be opened read-write, i.e. readonly is still 0, then
+ * check whether BKROGET says that it is read-only. E.g. read-only loop
+ * devices may be openend read-write but are read-only according to BLKROGET
+ */
+ if (readonly == 0 && ioctl(fd, BLKROGET, &readonly) < 0) {
+ log_err(cd, _("BLKROGET failed on device %s.\n"), device);
+ goto out;
+ }
+#else
+#error BLKROGET not available
+#endif
+
+#ifdef BLKGETSIZE64
+ if (ioctl(fd, BLKGETSIZE64, &size) >= 0) {
+ size >>= SECTOR_SHIFT;
+ ret = 0;
+ goto out;
+ }
+#endif
+
+#ifdef BLKGETSIZE
+ if (ioctl(fd, BLKGETSIZE, &size_small) >= 0) {
+ size = (uint64_t)size_small;
+ ret = 0;
+ goto out;
+ }
+#else
+# error Need at least the BLKGETSIZE ioctl!
+#endif
+
+ log_err(cd, _("BLKGETSIZE failed on device %s.\n"), device);
+out:
+ if (ret == 0) {
+ infos->size = size;
+ infos->readonly = readonly;
+ }
+ close(fd);
+ return ret;
+}
+
+int wipe_device_header(const char *device, int sectors)
+{
+ char *buffer;
+ int size = sectors * SECTOR_SIZE;
+ int r = -1;
+ int devfd;
+
+ devfd = open(device, O_RDWR | O_DIRECT | O_SYNC);
+ if(devfd == -1)
+ return -EINVAL;
+
+ buffer = malloc(size);
+ if (!buffer) {
+ close(devfd);
+ return -ENOMEM;
+ }
+ memset(buffer, 0, size);
+
+ r = write_blockwise(devfd, buffer, size) < size ? -EIO : 0;
+
+ free(buffer);
+ close(devfd);
+
+ return r;
}
/* MEMLOCK */
static int _memlock_count = 0;
// return 1 if memory is locked
-int memlock_inc(struct crypt_device *ctx)
+int crypt_memlock_inc(struct crypt_device *ctx)
{
if (!_memlock_count++) {
log_dbg("Locking memory.");
return _memlock_count ? 1 : 0;
}
-int memlock_dec(struct crypt_device *ctx)
+int crypt_memlock_dec(struct crypt_device *ctx)
{
if (_memlock_count && (!--_memlock_count)) {
log_dbg("Unlocking memory.");
}
return _memlock_count ? 1 : 0;
}
+
+/* DEVICE TOPOLOGY */
+
+/* block device topology ioctls, introduced in 2.6.32 */
+#ifndef BLKIOMIN
+#define BLKIOMIN _IO(0x12,120)
+#define BLKIOOPT _IO(0x12,121)
+#define BLKALIGNOFF _IO(0x12,122)
+#endif
+
+void get_topology_alignment(const char *device,
+ unsigned long *required_alignment, /* bytes */
+ unsigned long *alignment_offset, /* bytes */
+ unsigned long default_alignment)
+{
+ int dev_alignment_offset = 0;
+ unsigned int min_io_size = 0, opt_io_size = 0;
+ unsigned long temp_alignment = 0;
+ int fd;
+
+ *required_alignment = default_alignment;
+ *alignment_offset = 0;
+
+ fd = open(device, O_RDONLY);
+ if (fd == -1)
+ return;
+
+ /* minimum io size */
+ if (ioctl(fd, BLKIOMIN, &min_io_size) == -1) {
+ log_dbg("Topology info for %s not supported, using default offset %lu bytes.",
+ device, default_alignment);
+ goto out;
+ }
+
+ /* optimal io size */
+ if (ioctl(fd, BLKIOOPT, &opt_io_size) == -1)
+ opt_io_size = min_io_size;
+
+ /* alignment offset, bogus -1 means misaligned/unknown */
+ if (ioctl(fd, BLKALIGNOFF, &dev_alignment_offset) == -1 || dev_alignment_offset < 0)
+ dev_alignment_offset = 0;
+ *alignment_offset = (unsigned long)dev_alignment_offset;
+
+ temp_alignment = (unsigned long)min_io_size;
+
+ if (temp_alignment < (unsigned long)opt_io_size)
+ temp_alignment = (unsigned long)opt_io_size;
+
+ /* If calculated alignment is multiple of default, keep default */
+ if (temp_alignment && (default_alignment % temp_alignment))
+ *required_alignment = temp_alignment;
+
+ log_dbg("Topology: IO (%u/%u), offset = %lu; Required alignment is %lu bytes.",
+ min_io_size, opt_io_size, *alignment_offset, *required_alignment);
+out:
+ (void)close(fd);
+}