-ssize_t write_lseek_blockwise(int fd, const char *buf, size_t count, off_t offset) {
- int bsize = sector_size(fd);
- const char *orig_buf = buf;
- char frontPadBuf[bsize];
- int frontHang = offset % bsize;
- int r;
- int innerCount = count < bsize ? count : bsize;
-
- if (bsize < 0)
- return bsize;
-
- lseek(fd, offset - frontHang, SEEK_SET);
- if(offset % bsize) {
- r = read(fd,frontPadBuf,bsize);
- if(r < 0) return -1;
-
- memcpy(frontPadBuf+frontHang, buf, innerCount);
-
- lseek(fd, offset - frontHang, SEEK_SET);
- r = write(fd,frontPadBuf,bsize);
- if(r < 0) return -1;
-
- buf += innerCount;
- count -= innerCount;
- }
- if(count <= 0) return buf - orig_buf;
-
- return write_blockwise(fd, buf, count) + innerCount;
-}
-
-/* Password reading helpers */
-
-static int untimed_read(int fd, char *pass, size_t maxlen)
-{
- ssize_t i;
-
- i = read(fd, pass, maxlen);
- if (i > 0) {
- pass[i-1] = '\0';
- i = 0;
- } else if (i == 0) { /* EOF */
- *pass = 0;
- i = -1;
- }
- return i;
-}
-
-static int timed_read(int fd, char *pass, size_t maxlen, long timeout)
-{
- struct timeval t;
- fd_set fds;
- int failed = -1;
-
- FD_ZERO(&fds);
- FD_SET(fd, &fds);
- t.tv_sec = timeout;
- t.tv_usec = 0;
-
- if (select(fd+1, &fds, NULL, NULL, &t) > 0)
- failed = untimed_read(fd, pass, maxlen);
-
- return failed;
-}
-
-static int interactive_pass(const char *prompt, char *pass, size_t maxlen,
- long timeout)
-{
- struct termios orig, tmp;
- int failed = -1;
- int infd = STDIN_FILENO, outfd;
-
- if (maxlen < 1)
- goto out_err;
-
- /* Read and write to /dev/tty if available */
- if ((infd = outfd = open("/dev/tty", O_RDWR)) == -1) {
- infd = STDIN_FILENO;
- outfd = STDERR_FILENO;
- }
-
- if (tcgetattr(infd, &orig))
- goto out_err;
-
- memcpy(&tmp, &orig, sizeof(tmp));
- tmp.c_lflag &= ~ECHO;
-
- if (write(outfd, prompt, strlen(prompt)) < 0)
- goto out_err;
-
- tcsetattr(infd, TCSAFLUSH, &tmp);
- if (timeout)
- failed = timed_read(infd, pass, maxlen, timeout);
- else
- failed = untimed_read(infd, pass, maxlen);
- tcsetattr(infd, TCSAFLUSH, &orig);
-
-out_err:
- if (!failed)
- (void)write(outfd, "\n", 1);
- if (infd != STDIN_FILENO)
- close(infd);
- return failed;
-}
-
-/*
- * Password reading behaviour matrix of get_key
- *
- * p v n h
- * -----------------+---+---+---+---
- * interactive | Y | Y | Y | Inf
- * from fd | N | N | Y | Inf
- * from binary file | N | N | N | Inf or options->key_size
- *
- * 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)
- */
-
-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;
- 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;
-
- if(key_file && !strcmp(key_file, "-")) {
- /* Allow binary reading from stdin */
- fd = STDIN_FILENO;
- 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;
-
- /* 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 */
- }
-
- /* Interactive case */
- if(isatty(fd)) {
- int i;
-
- 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");
- 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);
- if (i || strcmp(pass, pass_verify) != 0) {
- log_err(cd, "Passphrases do not match.\n");
- goto out_err;
- }
- memset(pass_verify, 0, sizeof(pass_verify));
- }
- *passLen = strlen(pass);
- *key = pass;
- } else {
- /*
- * This is either a fd-input or a file, in neither case we can verify the input,
- * however we don't stop on new lines if it's a binary file.
- */
- int buflen, i;
-
- if(verify) {
- log_err(cd, "Can't do passphrase verification on non-tty inputs.\n");
- goto out_err;
- }
- /* The following for control loop does an exhausting
- * read on the key material file, if requested with
- * key_size == 0, as it's done by LUKS. However, we
- * 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(stat(key_file, &st) < 0) {
- 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",
- key_file);
- }
- }
- buflen = 0;
- for(i = 0; read_horizon == 0 || i < read_horizon; i++) {
- if(i >= buflen - 1) {
- buflen += 128;
- pass = safe_realloc(pass, buflen);
- if (!pass) {
- 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'))
- break;
- }
- if(key_file)
- close(fd);
- pass[i] = 0;
- *key = pass;
- *passLen = i;
- }
- return;
-
-out_err:
- if(pass)
- safe_free(pass);
- *key = NULL;
- *passLen = 0;
-}