pspp-convert: Add --password-list option.
authorBen Pfaff <blp@cs.stanford.edu>
Wed, 16 Jan 2019 01:28:53 +0000 (17:28 -0800)
committerBen Pfaff <blp@cs.stanford.edu>
Wed, 16 Jan 2019 01:29:09 +0000 (17:29 -0800)
NEWS
doc/pspp-convert.texi
utilities/pspp-convert.1
utilities/pspp-convert.c

diff --git a/NEWS b/NEWS
index 715e4d3c50d1aa27e390eb3831167dabae618382..53c96b68850c122f0fc2693a10df3211113223cd 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -9,8 +9,8 @@ Changes since 1.2.0:
  * Plain text output is no longer divided into pages, since it is now
    rarely printed on paper.
 
- * pspp-convert: New "-a" and "-l" options to search for an encrypted file's
-   password.
+ * pspp-convert: New "-a", "-l", "--password-list" options to search
+   for an encrypted file's password.
 
  * Bug fix for CVE-2018-20230.
 
index 915313298cbcaa74d6cb8ccfaf31ee261dad5bd6..7af90a113ce9851f3208110e18cbb47820870eb0 100644 (file)
@@ -65,7 +65,8 @@ The password for encrypted files can be specified a few different
 ways.  If the password is known, use the @option{-p} option
 (documented below) or allow @command{pspp-convert} to prompt for it.
 If the password is unknown, use the @option{-a} and @option{-l}
-options to specify how to search for it.
+options to specify how to search for it, or @option{--password-list}
+to specify a file of passwords to try.
 
 Use @code{-O @var{extension}} to override the inferred format or to
 specify the format for unrecognized extensions.
@@ -119,6 +120,10 @@ characters.
 @item --password-length=@var{max-length}
 Specifies the maximum length of the passwords to try.
 
+@item --password-list=@var{file}
+Specifies a file to read containing a list of passwords to try, one
+per line.  If @var{file} is @file{-}, reads from stdin.
+
 @item -h
 @itemx --help
 Prints a usage message on stdout and exits.
index 00828c2cb867b1fdbe0c65a28b5078d927174763..6e2e9f5224fa2abb3b505d2c0da4d7c28406c8fa 100644 (file)
@@ -60,6 +60,7 @@ the input file is in an encrypted format, then the output file must
 be the same format (decrypted).
 .
 .SH "OPTIONS"
+.SS "General Options"
 .
 .IP "\fB\-O format\fR"
 .IQ "\fB\-\-output\-format=\fIformat\fR"
@@ -79,12 +80,20 @@ Overrides the encoding in which character strings in \fIinput\fR are
 interpreted.  This option is necessary because old SPSS system files
 do not self-identify their encoding.
 .
+.SS "Password Options"
+When the input file is encrypted, \fBpspp\-convert\fR needs to obtain
+a password to decrypt it.  To do so, the user may specify the password
+with \f\-p\fR (or \fB\-\-password), or the name of a file containing a
+list of possible passwords with \fB\-\-password\-list\fR, or an
+alphabet of possible passwords to try along with a maximum length with
+\fB\-a\fR (or \fB\-\-password\-alphabet\fR) and \fB\-l\fR (or
+\-\-password\-length\fR).  If none of these options is used,
+\fBpspp\-convert\fR prompts for the password.  The password options
+are:
+.
 .IP "\fB\-p \fIpassword\fR"
 .IQ "\fB\-\-password=\fIpassword\fR"
-Specifies the password to use to decrypt encrypted SPSS system file
-or syntax file
-\fIinput\fR.  If this option is not specified, \fBpspp\-convert\fR
-prompts for the password.
+Specifies the password to use to decrypt the input file.
 .
 .IP
 On multiuser systems, this option may not be safe because other users
@@ -103,6 +112,11 @@ characters long.
 When these options are used, \fB\-p\fR may additionally specify a
 starting point for the search.
 .
+.IP "\fB\-\-password\-list=\fIfile\fR"
+Specifies a file to read containing a list of passwords to try, one
+per line.  If \fIfile\fR is \fB\-\fR, reads from stdin.
+.
+.SS "Other Options"
 .IP "\fB\-h\fR"
 .IQ "\fB\-\-help\fR"
 Prints a usage message on stdout and exits.
index 7eb6b556684e79e20317112be9b1a6a9ed919603..4a2f0f029127b176aa84f983c72be422a4ca38fc 100644 (file)
@@ -51,7 +51,8 @@ static bool decrypt_file (struct encrypted_file *enc,
                           const struct file_handle *input_filename,
                           const struct file_handle *output_filename,
                           const char *password,
-                          const char *alphabet, int max_length);
+                          const char *alphabet, int max_length,
+                          const char *password_list);
 
 int
 main (int argc, char *argv[])
@@ -71,6 +72,7 @@ main (int argc, char *argv[])
   struct casewriter *writer;
   const char *password = NULL;
   struct string alphabet = DS_EMPTY_INITIALIZER;
+  const char *password_list = NULL;
   int length = 0;
 
   long long int i;
@@ -82,6 +84,10 @@ main (int argc, char *argv[])
 
   for (;;)
     {
+      enum
+        {
+          OPT_PASSWORD_LIST = UCHAR_MAX + 1,
+        };
       static const struct option long_options[] =
         {
           { "cases",    required_argument, NULL, 'c' },
@@ -90,6 +96,7 @@ main (int argc, char *argv[])
           { "password", required_argument, NULL, 'p' },
           { "password-alphabet", required_argument, NULL, 'a' },
           { "password-length", required_argument, NULL, 'l' },
+          { "password-list", required_argument, NULL, OPT_PASSWORD_LIST },
 
           { "output-format", required_argument, NULL, 'O' },
 
@@ -122,6 +129,10 @@ main (int argc, char *argv[])
           length = atoi (optarg);
           break;
 
+        case OPT_PASSWORD_LIST:
+          password_list = optarg;
+          break;
+
         case 'a':
           for (const char *p = optarg; *p; )
             if (p[1] == '-' && p[2] > p[0])
@@ -187,7 +198,7 @@ main (int argc, char *argv[])
         }
 
       if (!decrypt_file (enc, input_fh, output_fh, password,
-                         ds_cstr (&alphabet), length))
+                         ds_cstr (&alphabet), length, password_list))
        goto error;
 
       goto exit;
@@ -272,14 +283,62 @@ decrypt_file (struct encrypted_file *enc,
              const struct file_handle *ofh,
               const char *password,
               const char *alphabet,
-              int max_length)
+              int max_length,
+              const char *password_list)
 {
   FILE *out;
   int err;
   const char *input_filename = fh_get_file_name (ifh);
   const char *output_filename = fh_get_file_name (ofh);
 
-  if (alphabet[0] && max_length)
+  if (password_list)
+    {
+      FILE *password_file;
+      if (!strcmp (password_list, "-"))
+        password_file = stdin;
+      else
+        {
+          password_file = fopen (password_list, "r");
+          if (!password_file)
+            error (1, errno, _("%s: error opening password file"),
+                   password_list);
+        }
+
+      struct string pw = DS_EMPTY_INITIALIZER;
+      unsigned int target = 100000;
+      for (unsigned int i = 0; ; i++)
+        {
+          ds_clear (&pw);
+          if (!ds_read_line (&pw, password_file, SIZE_MAX))
+            {
+              if (isatty (STDOUT_FILENO))
+                {
+                  putchar ('\r');
+                  fflush (stdout);
+                }
+              error (1, 0, _("\n%s: password not in file"), password_list);
+            }
+          ds_chomp_byte (&pw, '\n');
+
+          if (i >= target)
+            {
+              target += 100000;
+              if (isatty (STDOUT_FILENO))
+                {
+                  printf ("\r%u", i);
+                  fflush (stdout);
+                }
+            }
+
+          if (encrypted_file_unlock__ (enc, ds_cstr (&pw)))
+            {
+              printf ("\npassword is: \"%s\"\n", ds_cstr (&pw));
+              password = ds_cstr (&pw);
+              break;
+            }
+        }
+    }
+  else if (alphabet[0] && max_length)
     {
       size_t alphabet_size = strlen (alphabet);
       char *pw = xmalloc (max_length + 1);
@@ -404,12 +463,17 @@ The desired format of OUTPUT is by default inferred from its extension:\n\
   por                 SPSS portable file\n\
   sps                 SPSS syntax file (encrypted syntax input files only)\n\
 \n\
-Options:\n\
+General options:\n\
   -O, --output-format=FORMAT  set specific output format, where FORMAT\n\
                       is one of the extensions listed above\n\
   -e, --encoding=CHARSET  override encoding of input data file\n\
   -c MAXCASES         limit number of cases to copy (default is all cases)\n\
-  -p PASSWORD         password for encrypted files\n\
+Password options (for used with encrypted files):\n\
+  -p PASSWORD         individual password\n\
+  -a ALPHABET         with -l, alphabet of passwords to try\n\
+  -l MAX-LENGTH       with -a, maximum number of characters to try\n\
+  --password-list=FILE  try all of the passwords in FILE (one per line)\n\
+Other options:\n\
   --help              display this help and exit\n\
   --version           output version information and exit\n",
           program_name, program_name);