/* PSPP - a program for statistical analysis.
- Copyright (C) 2013, 2014, 2015 Free Software Foundation, Inc.
+ Copyright (C) 2013, 2014, 2015, 2016 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
#include "data/casereader.h"
#include "data/casewriter.h"
#include "data/csv-file-writer.h"
+#include "data/dictionary.h"
#include "data/encrypted-file.h"
#include "data/file-name.h"
#include "data/por-file-writer.h"
static void usage (void);
-static void decrypt_file (struct encrypted_file *enc,
- const char *input_filename,
- const char *output_filename,
- const char *password);
+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 *password_list);
int
main (int argc, char *argv[])
const char *output_filename;
long long int max_cases = LLONG_MAX;
- struct dictionary *dict;
+ struct dictionary *dict = NULL;
struct casereader *reader;
- struct file_handle *input_fh;
+ struct file_handle *input_fh = NULL;
const char *encoding = NULL;
struct encrypted_file *enc;
const char *output_format = NULL;
- struct file_handle *output_fh;
+ struct file_handle *output_fh = NULL;
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;
for (;;)
{
+ enum
+ {
+ OPT_PASSWORD_LIST = UCHAR_MAX + 1,
+ };
static const struct option long_options[] =
{
{ "cases", required_argument, NULL, 'c' },
{ "encoding", required_argument, NULL, 'e' },
+
{ "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' },
int c;
- c = getopt_long (argc, argv, "c:e:p:O:hv", long_options, NULL);
+ c = getopt_long (argc, argv, "c:e:p:a:l:O:hv", long_options, NULL);
if (c == -1)
break;
password = optarg;
break;
+ case 'l':
+ 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])
+ {
+ for (int ch = p[0]; ch <= p[2]; ch++)
+ ds_put_byte (&alphabet, ch);
+ p += 3;
+ }
+ else
+ ds_put_byte (&alphabet, *p++);
+ break;
+
case 'O':
output_format = optarg;
break;
exit (EXIT_SUCCESS);
default:
- exit (EXIT_FAILURE);
+ goto error;
}
}
input_filename = argv[optind];
output_filename = argv[optind + 1];
+ input_fh = fh_create_file (NULL, input_filename, NULL, fh_default_properties ());
+
if (output_format == NULL)
{
const char *dot = strrchr (output_filename, '.');
output_format = dot + 1;
}
- if (encrypted_file_open (&enc, input_filename) > 0)
+ output_fh = fh_create_file (NULL, output_filename, NULL, fh_default_properties ());
+ if (encrypted_file_open (&enc, input_fh) > 0)
{
if (encrypted_file_is_sav (enc))
{
"format"));
}
- decrypt_file (enc, input_filename, output_filename, password);
+ if (!decrypt_file (enc, input_fh, output_fh, password,
+ ds_cstr (&alphabet), length, password_list))
+ goto error;
+
goto exit;
}
- input_fh = fh_create_file (NULL, input_filename, fh_default_properties ());
+
reader = any_reader_open_and_decode (input_fh, encoding, &dict, NULL);
if (reader == NULL)
- exit (1);
+ goto error;
- output_fh = fh_create_file (NULL, output_filename, fh_default_properties ());
if (!strcmp (output_format, "csv") || !strcmp (output_format, "txt"))
{
struct csv_writer_options options;
output_filename);
NOT_REACHED ();
}
+ if (!writer)
+ error (1, 0, _("%s: error opening output file"), output_filename);
for (i = 0; i < max_cases; i++)
{
error (1, 0, _("%s: error writing output file"), output_filename);
exit:
+ ds_destroy (&alphabet);
+ dict_unref (dict);
+ fh_unref (output_fh);
+ fh_unref (input_fh);
fh_done ();
i18n_done ();
return 0;
+
+error:
+ ds_destroy (&alphabet);
+ dict_unref (dict);
+ fh_unref (output_fh);
+ fh_unref (input_fh);
+ fh_done ();
+ i18n_done ();
+
+ return 1;
}
-static void
+static bool
decrypt_file (struct encrypted_file *enc,
- const char *input_filename,
- const char *output_filename,
- const char *password)
+ const struct file_handle *ifh,
+ const struct file_handle *ofh,
+ const char *password,
+ const char *alphabet,
+ 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 (password == NULL)
+ if (password_list)
{
- password = getpass ("password: ");
- if (password == NULL)
- exit (1);
+ 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);
+ int *indexes = xzalloc (max_length * sizeof *indexes);
+
+ for (int len = password ? strlen (password) : 0;
+ len <= max_length; len++)
+ {
+ if (password && len == strlen (password))
+ {
+ for (int i = 0; i < len; i++)
+ {
+ const char *p = strchr (alphabet, password[i]);
+ if (!p)
+ error (1, 0, _("%s: '%c' is not in alphabet"),
+ password, password[i]);
+ indexes[i] = p - alphabet;
+ pw[i] = *p;
+ }
+ }
+ else
+ {
+ memset (indexes, 0, len * sizeof *indexes);
+ for (int i = 0; i < len; i++)
+ pw[i] = alphabet[0];
+ }
+ pw[len] = '\0';
+
+ unsigned int target = 0;
+ for (unsigned int j = 0; ; j++)
+ {
+ if (j >= target)
+ {
+ target += 100000;
+ if (isatty (STDOUT_FILENO))
+ {
+ printf ("\rlength %d: %s", len, pw);
+ fflush (stdout);
+ }
+ }
+ if (encrypted_file_unlock__ (enc, pw))
+ {
+ printf ("\npassword is: \"%s\"\n", pw);
+ password = pw;
+ goto success;
+ }
+
+ int i;
+ for (i = 0; i < len; i++)
+ if (++indexes[i] < alphabet_size)
+ {
+ pw[i] = alphabet[indexes[i]];
+ break;
+ }
+ else
+ {
+ indexes[i] = 0;
+ pw[i] = alphabet[indexes[i]];
+ }
+ if (i == len)
+ break;
+ }
+ }
+ free (indexes);
+ free (pw);
+
+ success:;
}
+ else
+ {
+ if (password == NULL)
+ {
+ password = getpass ("password: ");
+ if (password == NULL)
+ return false;
+ }
- if (!encrypted_file_unlock (enc, password))
- error (1, 0, _("sorry, wrong password"));
+ if (!encrypted_file_unlock (enc, password))
+ error (1, 0, _("sorry, wrong password"));
+ }
- out = fn_open (output_filename, "wb");
+ out = fn_open (ofh, "wb");
if (out == NULL)
error (1, errno, ("%s: error opening output file"), output_filename);
if (fflush (out) == EOF)
error (1, errno, ("%s: write error"), output_filename);
- fn_close (output_filename, out);
+ fn_close (ofh, out);
+
+ return true;
}
static void
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);