-o logfile: logging to separate logfile instead of stderr.
[tfcrypt.git] / tfcrypt.c
index fb3dfb9cb44a7e0826dc059c13c555ef7ecbc761..b6bbe73de3cd3f3d38497fe2c8e11cd2697af735 100644 (file)
--- a/tfcrypt.c
+++ b/tfcrypt.c
 
 #include "tfcrypt.h"
 
+static tfc_byte svctr[TF_BLOCK_SIZE];
+
+static void open_log(const char *logfile)
+{
+       int fd;
+
+       fd = open(logfile, O_WRONLY | O_CREAT | O_LARGEFILE | O_TRUNC, 0666);
+       if (fd == -1) xerror(NO, NO, YES, "%s", logfile);
+       xclose(2);
+       if (dup2(fd, 2) == -1) xerror(NO, NO, YES, "dup2(%d, 2) for %s", fd, logfile);
+       xclose(fd);
+       do_statline_dynamic = NO;
+}
+
 static int getps_filter(struct getpasswd_state *getps, char chr, size_t pos)
 {
        if (chr == '\x03') {
@@ -113,6 +127,7 @@ int main(int argc, char **argv)
        double td;
        char *s, *d, *t, *stoi;
        size_t x, n;
+       tfc_fsize rwd;
 
        progname = basename(argv[0]);
 
@@ -128,8 +143,14 @@ int main(int argc, char **argv)
 _baddfname:
        memset(s, 0, n);
 
+       if (!strcmp(progname, "iotool")) {
+               do_edcrypt = TFC_DO_PLAIN;
+               password = YES;
+               ctr_mode = TFC_MODE_PLAIN;
+       }
+
        opterr = 0;
-       while ((c = getopt(argc, argv, "L:s:aU:C:r:K:t:Pkzxc:l:qedn:vV:pwE:O:S:AmM:R:Z:WHD:")) != -1) {
+       while ((c = getopt(argc, argv, "L:s:aU:C:r:K:t:Pkzxc:l:qedn:vV:pwE:o:O:S:AmuM:R:Z:WHD:")) != -1) {
                switch (c) {
                        case 'L':
                                read_defaults(optarg, NO);
@@ -195,10 +216,10 @@ _baddfname:
                                ctr_mode = TFC_MODE_PLAIN;
                                break;
                        case 'e':
-                               do_edcrypt = TFC_DO_ENCRYPT;
+                               if (do_edcrypt != TFC_DO_PLAIN) do_edcrypt = TFC_DO_ENCRYPT;
                                break;
                        case 'd':
-                               do_edcrypt = TFC_DO_DECRYPT;
+                               if (do_edcrypt != TFC_DO_PLAIN) do_edcrypt = TFC_DO_DECRYPT;
                                break;
                        case 'D':
                                macbits = strtoul(optarg, &stoi, 10);
@@ -276,6 +297,9 @@ _baddfname:
                                        error_action = TFC_ERRACT_LSYNC;
                                else xerror(NO, YES, YES, "invalid error action %s specified", optarg);
                                break;
+                       case 'o':
+                               open_log(optarg);
+                               break;
                        case 'O':
                                s = d = optarg; t = NULL;
                                while ((s = strtok_r(d, ",", &t))) {
@@ -308,6 +332,8 @@ _baddfname:
                                                do_full_key = YES;
                                        else if (!strcmp(s, "showsecrets"))
                                                show_secrets = YES;
+                                       else if (!strncmp(s, "logfile", 7) && *(s+7) == '=')
+                                               open_log(s+8);
                                        else if (!strncmp(s, "iobs", 4) && *(s+4) == '=') {
                                                s += 5;
                                                blksize = (size_t)tfc_humanfsize(s, &stoi);
@@ -495,9 +521,11 @@ _baddfname:
                                        do_mac_file = optarg;
                                break;
                        case 'm':
+                       case 'u':
                                if (do_mac != TFC_MAC_VRFY)
                                        xerror(NO, YES, YES, "signature source was not specified");
                                do_mac = TFC_MAC_JUST_VRFY;
+                               if (c == 'u') do_mac = TFC_MAC_JUST_VRFY2;
                                break;
                        case 'R':
                        case 'Z':
@@ -635,7 +663,7 @@ _nosalt:
                        lrem = lblock = sizeof(tmpdata);
                        if (error_action == TFC_ERRACT_SYNC) rdpos = tfc_fdgetpos(mkfd);
 _mkragain:             lio = xread(mkfd, pblk, lrem);
-                       if (lio == 0) do_stop = YES;
+                       if (lio == 0 && do_stop == NO) do_stop = YES;
                        if (lio != NOSIZE) ldone += lio;
                        else {
                                if (errno != EIO && catch_all_errors != YES)
@@ -1018,6 +1046,7 @@ _xts2genkey:      if (xwrite(krfd, pblk, TF_FROM_BITS(TFC_KEY_BITS)) == NOSIZE) xerro
 
        tfc_data_to_words64(&iseek_blocks, sizeof(iseek_blocks));
        tf_ctr_set(ctr, &iseek_blocks, sizeof(iseek_blocks));
+       if (do_mac == TFC_MAC_JUST_VRFY2) memcpy(svctr, ctr, TF_BLOCK_SIZE);
 
        if (counter_opt == TFC_CTR_SHOW) {
                switch (do_outfmt) {
@@ -1059,7 +1088,6 @@ _plain:
        sigact.sa_flags = SA_RESTART;
        sigact.sa_handler = print_crypt_status;
        sigaction(SIGUSR1, &sigact, NULL);
-       sigaction(SIGTSTP, &sigact, NULL);
        sigaction(SIGALRM, &sigact, NULL);
        if (status_timer) setup_next_alarm(status_timer);
        sigact.sa_handler = change_status_width;
@@ -1070,11 +1098,14 @@ _plain:
                sigact.sa_handler = print_crypt_status;
                sigaction(SIGINT, &sigact, NULL);
                sigaction(SIGTERM, &sigact, NULL);
+               sigaction(SIGTSTP, &sigact, NULL);
        }
        else {
                sigact.sa_handler = exit_sigterm;
                sigaction(SIGINT, &sigact, NULL);
                sigaction(SIGTERM, &sigact, NULL);
+               sigact.sa_handler = handle_sigtstp;
+               sigaction(SIGTSTP, &sigact, NULL);
        }
        memset(&sigact, 0, sizeof(struct sigaction));
 
@@ -1100,6 +1131,24 @@ _ctrwagain:      lio = xwrite(dfd, pblk, lrem);
 
        if (ctr_mode == TFC_MODE_STREAM) tfe_init_iv(&tfe, key, ctr);
 
+       if (do_mac == TFC_MAC_JUST_VRFY2) {
+               rwd = tfc_fdgetpos(sfd);
+               if (rwd == NOFSIZE) {
+                       tfc_esay("%s: WARNING: input is not seekable, disabling MAC testing mode", progname);
+                       do_mac = TFC_MAC_VRFY;
+               }
+               goto _nodecrypt_again_vrfy2;
+
+_decrypt_again_vrfy2:
+               if (lseek(sfd, (off_t)rwd, SEEK_SET) == ((off_t)-1)) {
+                       xerror(ignore_seek_errors, NO, YES, "MAC testing seek failed");
+               }
+               total_processed_src = rwd;
+               memcpy(ctr, svctr, TF_BLOCK_SIZE);
+               memset(svctr, 0, TF_BLOCK_SIZE);
+       }
+
+_nodecrypt_again_vrfy2:
        errno = 0;
        do_stop = NO;
        while (1) {
@@ -1109,7 +1158,7 @@ _ctrwagain:       lio = xwrite(dfd, pblk, lrem);
                lrem = lblock = blk_len_adj(maxlen, total_processed_src, blksize);
                if (error_action == TFC_ERRACT_SYNC) rdpos = tfc_fdgetpos(sfd);
 _ragain:       lio = xread(sfd, pblk, lrem);
-               if (lio == 0) do_stop = TFC_STOP_BEGAN;
+               if (lio == 0) do_stop = YES;
                if (lio != NOSIZE) ldone += lio;
                else {
                        if (errno != EIO && catch_all_errors != YES)
@@ -1169,7 +1218,7 @@ _ragain:  lio = xread(sfd, pblk, lrem);
 
                if (do_mac >= TFC_MAC_VRFY && ctr_mode < TFC_MODE_OCB)
                        skein_update(&sk, dstblk, ldone);
-               if (do_mac == TFC_MAC_JUST_VRFY) goto _nowrite;
+               if (do_mac >= TFC_MAC_JUST_VRFY) goto _nowrite;
 
                pblk = dstblk;
                lrem = ldone;
@@ -1183,14 +1232,16 @@ _wagain:        lio = xwrite(dfd, pblk, lrem);
                        lrem -= lio;
                        goto _wagain;
                }
+               total_written_dst += ldone;
 _nowrite:      total_processed_dst += ldone;
                delta_processed += ldone;
 
-               if (maxlen != NOFSIZE && total_processed_src >= maxlen) break;
+               if (maxlen != NOFSIZE && total_processed_src >= maxlen) {
+                       do_stop = YES;
+                       break;
+               }
        }
 
-       if (do_stop == TFC_STOP_FULL) goto _nomac;
-
        errno = 0;
        if (do_mac >= TFC_MAC_VRFY) {
                if (!do_mac_file) {
@@ -1266,10 +1317,18 @@ _macragain:             lio = xread(sfd, pblk, lrem);
                                        else mehexdump(macresult, TF_FROM_BITS(macbits), TF_FROM_BITS(macbits), YES);
                                }
                        }
+                       if (do_mac == TFC_MAC_JUST_VRFY2) {
+                               if (verbose) tfc_esay("%s: -u: MAC signature is valid, proceeding with decrypting it again", progname);
+                               do_mac = TFC_MAC_DROP;
+                               goto _decrypt_again_vrfy2;
+                       }
                }
                else {
-                       if (quiet == NO) tfc_esay("%s: signature is BAD: "
+                       if (quiet == NO) {
+                               tfc_esay("%s: signature is BAD: "
                                "wrong password, key, mode, or file is not signed", progname);
+                               if (do_mac == TFC_MAC_JUST_VRFY2) tfc_esay("%s: -u: MAC signature is invalid, not decrypting it again", progname);
+                       }
                        exitcode = 1;
                }
 
@@ -1335,16 +1394,7 @@ _macwagain:              lio = xwrite(dfd, pblk, lrem);
                memset(tmpdata, 0, sizeof(tmpdata));
        }
 
-_nomac:
-       if (verbose || status_timer || do_stop == TFC_STOP_FULL) print_crypt_status(0);
-
-       if (do_preserve_time) fcopy_matime(dfd, &s_stat);
-       xclose(sfd);
-       if (do_ftrunc > TFC_NO_FTRUNC) {
-               if (do_ftrunc == TFC_FTRUNC_TAIL) ftrunc_dfd = total_processed_dst;
-               if (ftruncate(dfd, (off_t)ftrunc_dfd) == -1) xerror(YES, NO, YES, "ftruncate(%d)", dfd);
-       }
-       xclose(dfd);
+       if (verbose || status_timer || (do_stop == YES && quiet == NO)) print_crypt_status(0);
 
        xexit(exitcode);
        return -1;