X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=utilities%2Fpspp-convert.c;h=4a2f0f029127b176aa84f983c72be422a4ca38fc;hb=078b003b3171c6158a3419a01189b9658896f470;hp=f71109524f5f9ba851966734d9332557efe86800;hpb=c43455db6f3f1191d969c42b8e679e0fddc44e78;p=pspp diff --git a/utilities/pspp-convert.c b/utilities/pspp-convert.c index f71109524f..4a2f0f0291 100644 --- a/utilities/pspp-convert.c +++ b/utilities/pspp-convert.c @@ -1,5 +1,5 @@ /* 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 @@ -26,6 +26,7 @@ #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" @@ -46,10 +47,12 @@ 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[]) @@ -58,16 +61,19 @@ 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; @@ -78,11 +84,19 @@ main (int argc, char *argv[]) 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' }, @@ -93,7 +107,7 @@ main (int argc, char *argv[]) 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; @@ -111,6 +125,26 @@ main (int argc, char *argv[]) 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; @@ -125,7 +159,7 @@ main (int argc, char *argv[]) exit (EXIT_SUCCESS); default: - exit (EXIT_FAILURE); + goto error; } } @@ -135,6 +169,8 @@ main (int argc, char *argv[]) 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, '.'); @@ -145,7 +181,8 @@ main (int argc, char *argv[]) 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)) { @@ -160,16 +197,18 @@ main (int argc, char *argv[]) "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, NULL, 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, NULL, fh_default_properties ()); if (!strcmp (output_format, "csv") || !strcmp (output_format, "txt")) { struct csv_writer_options options; @@ -198,6 +237,8 @@ main (int argc, char *argv[]) output_filename); NOT_REACHED (); } + if (!writer) + error (1, 0, _("%s: error opening output file"), output_filename); for (i = 0; i < max_cases; i++) { @@ -216,32 +257,170 @@ main (int argc, char *argv[]) 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); @@ -264,7 +443,9 @@ decrypt_file (struct encrypted_file *enc, 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 @@ -282,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);