diff options
Diffstat (limited to '')
-rw-r--r-- | src/options.c | 707 |
1 files changed, 707 insertions, 0 deletions
diff --git a/src/options.c b/src/options.c new file mode 100644 index 0000000..95050db --- /dev/null +++ b/src/options.c @@ -0,0 +1,707 @@ +/* + * options.c: Command line processing routines for nwipe. + * + * Copyright Darik Horn <dajhorn-dban@vanadac.com>. + * + * Modifications to original dwipe Copyright Andy Beverley <andy@andybev.com> + * + * 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 the Free Software + * Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#include "nwipe.h" +#include "context.h" +#include "method.h" +#include "prng.h" +#include "options.h" +#include "logging.h" +#include "version.h" +#include "conf.h" + +/* The global options struct. */ +nwipe_options_t nwipe_options; + +int nwipe_options_parse( int argc, char** argv ) +{ + extern char* optarg; // The working getopt option argument. + extern int optind; // The working getopt index into argv. + extern int optopt; // The last unhandled getopt option. + extern int opterr; // The last getopt error number. + + extern nwipe_prng_t nwipe_twister; + extern nwipe_prng_t nwipe_isaac; + extern nwipe_prng_t nwipe_isaac64; + + /* The getopt() result holder. */ + int nwipe_opt; + + /* Excluded drive indexes */ + int idx_drive_chr; + int idx_optarg; + int idx_drive; + + /* Array index variable. */ + int i; + + /* The list of acceptable short options. */ + char nwipe_options_short[] = "Vvhl:P:m:p:qr:e:"; + + /* Used when reading value fron nwipe.conf */ + const char* read_value = NULL; + + int ret; + + /* The list of acceptable long options. */ + static struct option nwipe_options_long[] = { + /* Set when the user wants to wipe without a confirmation prompt. */ + { "autonuke", no_argument, 0, 0 }, + + /* Set when the user wants to have the system powerdown on completion of wipe. */ + { "autopoweroff", no_argument, 0, 0 }, + + /* A GNU standard option. Corresponds to the 'h' short option. */ + { "help", no_argument, 0, 'h' }, + + /* The wipe method. Corresponds to the 'm' short option. */ + { "method", required_argument, 0, 'm' }, + + /* Log file. Corresponds to the 'l' short option. */ + { "logfile", required_argument, 0, 'l' }, + + /* PDFreport path. Corresponds to the 'P' short option. */ + { "PDFreportpath", required_argument, 0, 'P' }, + + /* Exclude devices, comma separated list */ + { "exclude", required_argument, 0, 'e' }, + + /* The Pseudo Random Number Generator. */ + { "prng", required_argument, 0, 'p' }, + + /* The number of times to run the method. */ + { "rounds", required_argument, 0, 'r' }, + + /* Whether to blank the disk after wiping. */ + { "noblank", no_argument, 0, 0 }, + + /* Whether to ignore all USB devices. */ + { "nousb", no_argument, 0, 0 }, + + /* Whether to exit after wiping or wait for a keypress. */ + { "nowait", no_argument, 0, 0 }, + + /* Whether to allow signals to interrupt a wipe. */ + { "nosignals", no_argument, 0, 0 }, + + /* Whether to display the gui. */ + { "nogui", no_argument, 0, 0 }, + + /* Whether to anonymize the serial numbers. */ + { "quiet", no_argument, 0, 'q' }, + + /* A flag to indicate whether the devices would be opened in sync mode. */ + { "sync", required_argument, 0, 0 }, + + /* Verify that wipe patterns are being written to the device. */ + { "verify", required_argument, 0, 0 }, + + /* Display program version. */ + { "verbose", no_argument, 0, 'v' }, + + /* Display program version. */ + { "version", no_argument, 0, 'V' }, + + /* Requisite padding for getopt(). */ + { 0, 0, 0, 0 } }; + + /* Set default options. */ + nwipe_options.autonuke = 0; + nwipe_options.autopoweroff = 0; + nwipe_options.method = &nwipe_dodshort; + nwipe_options.prng = ( sizeof( unsigned long int ) >= 8 ) ? &nwipe_isaac64 : &nwipe_isaac; + nwipe_options.rounds = 1; + nwipe_options.noblank = 0; + nwipe_options.nousb = 0; + nwipe_options.nowait = 0; + nwipe_options.nosignals = 0; + nwipe_options.nogui = 0; + nwipe_options.quiet = 0; + nwipe_options.sync = DEFAULT_SYNC_RATE; + nwipe_options.verbose = 0; + nwipe_options.verify = NWIPE_VERIFY_LAST; + memset( nwipe_options.logfile, '\0', sizeof( nwipe_options.logfile ) ); + memset( nwipe_options.PDFreportpath, '\0', sizeof( nwipe_options.PDFreportpath ) ); + strncpy( nwipe_options.PDFreportpath, ".", 2 ); + + /* Read PDF settings from nwipe.conf if available */ + if( ( ret = nwipe_conf_read_setting( "PDF_Certificate.PDF_Enable", &read_value ) ) ) + { + /* error occurred */ + nwipe_log( NWIPE_LOG_ERROR, + "nwipe_conf_read_setting():Error reading PDF_Certificate.PDF_Enable from nwipe.conf, ret code %i", + ret ); + + /* Use default values */ + nwipe_options.PDF_enable = 1; + } + else + { + if( !strcmp( read_value, "ENABLED" ) ) + { + nwipe_options.PDF_enable = 1; + } + else + { + if( !strcmp( read_value, "DISABLED" ) ) + { + nwipe_options.PDF_enable = 0; + } + else + { + // error occurred + nwipe_log( + NWIPE_LOG_ERROR, + "PDF_Certificate.PDF_Enable in nwipe.conf returned a value that was neither ENABLED or DISABLED" ); + nwipe_options.PDF_enable = 1; // Default to Enabled + } + } + } + + /* PDF Preview enable/disable */ + if( ( ret = nwipe_conf_read_setting( "PDF_Certificate.PDF_Preview", &read_value ) ) ) + { + /* error occurred */ + nwipe_log( NWIPE_LOG_ERROR, + "nwipe_conf_read_setting():Error reading PDF_Certificate.PDF_Preview from nwipe.conf, ret code %i", + ret ); + + /* Use default values */ + nwipe_options.PDF_enable = 1; + } + else + { + if( !strcmp( read_value, "ENABLED" ) ) + { + nwipe_options.PDF_preview_details = 1; + } + else + { + if( !strcmp( read_value, "DISABLED" ) ) + { + nwipe_options.PDF_preview_details = 0; + } + else + { + /* error occurred */ + nwipe_log( + NWIPE_LOG_ERROR, + "PDF_Certificate.PDF_Preview in nwipe.conf returned a value that was neither ENABLED or DISABLED" ); + nwipe_options.PDF_preview_details = 1; /* Default to Enabled */ + } + } + } + + /* Initialise each of the strings in the excluded drives array */ + for( i = 0; i < MAX_NUMBER_EXCLUDED_DRIVES; i++ ) + { + nwipe_options.exclude[i][0] = 0; + } + + /* Parse command line options. */ + while( 1 ) + { + /* Get the next command line option with (3)getopt. */ + nwipe_opt = getopt_long( argc, argv, nwipe_options_short, nwipe_options_long, &i ); + + /* Break when we have processed all of the given options. */ + if( nwipe_opt < 0 ) + { + break; + } + + switch( nwipe_opt ) + { + case 0: /* Long options without short counterparts. */ + + if( strcmp( nwipe_options_long[i].name, "autonuke" ) == 0 ) + { + nwipe_options.autonuke = 1; + break; + } + + if( strcmp( nwipe_options_long[i].name, "autopoweroff" ) == 0 ) + { + nwipe_options.autopoweroff = 1; + break; + } + + if( strcmp( nwipe_options_long[i].name, "noblank" ) == 0 ) + { + nwipe_options.noblank = 1; + break; + } + + if( strcmp( nwipe_options_long[i].name, "nousb" ) == 0 ) + { + nwipe_options.nousb = 1; + break; + } + + if( strcmp( nwipe_options_long[i].name, "nowait" ) == 0 ) + { + nwipe_options.nowait = 1; + break; + } + + if( strcmp( nwipe_options_long[i].name, "nosignals" ) == 0 ) + { + nwipe_options.nosignals = 1; + break; + } + + if( strcmp( nwipe_options_long[i].name, "nogui" ) == 0 ) + { + nwipe_options.nogui = 1; + nwipe_options.nowait = 1; + break; + } + + if( strcmp( nwipe_options_long[i].name, "verbose" ) == 0 ) + { + nwipe_options.verbose = 1; + break; + } + + if( strcmp( nwipe_options_long[i].name, "sync" ) == 0 ) + { + if( sscanf( optarg, " %i", &nwipe_options.sync ) != 1 || nwipe_options.sync < 0 ) + { + fprintf( stderr, "Error: The sync argument must be a positive integer or zero.\n" ); + exit( EINVAL ); + } + break; + } + + if( strcmp( nwipe_options_long[i].name, "verify" ) == 0 ) + { + + if( strcmp( optarg, "0" ) == 0 || strcmp( optarg, "off" ) == 0 ) + { + nwipe_options.verify = NWIPE_VERIFY_NONE; + break; + } + + if( strcmp( optarg, "1" ) == 0 || strcmp( optarg, "last" ) == 0 ) + { + nwipe_options.verify = NWIPE_VERIFY_LAST; + break; + } + + if( strcmp( optarg, "2" ) == 0 || strcmp( optarg, "all" ) == 0 ) + { + nwipe_options.verify = NWIPE_VERIFY_ALL; + break; + } + + /* Else we do not know this verification level. */ + fprintf( stderr, "Error: Unknown verification level '%s'.\n", optarg ); + exit( EINVAL ); + } + + /* getopt_long should raise on invalid option, so we should never get here. */ + exit( EINVAL ); + + case 'm': /* Method option. */ + + if( strcmp( optarg, "dod522022m" ) == 0 || strcmp( optarg, "dod" ) == 0 ) + { + nwipe_options.method = &nwipe_dod522022m; + break; + } + + if( strcmp( optarg, "dodshort" ) == 0 || strcmp( optarg, "dod3pass" ) == 0 ) + { + nwipe_options.method = &nwipe_dodshort; + break; + } + + if( strcmp( optarg, "gutmann" ) == 0 ) + { + nwipe_options.method = &nwipe_gutmann; + break; + } + + if( strcmp( optarg, "ops2" ) == 0 ) + { + nwipe_options.method = &nwipe_ops2; + break; + } + + if( strcmp( optarg, "random" ) == 0 || strcmp( optarg, "prng" ) == 0 + || strcmp( optarg, "stream" ) == 0 ) + { + nwipe_options.method = &nwipe_random; + break; + } + + if( strcmp( optarg, "zero" ) == 0 || strcmp( optarg, "quick" ) == 0 ) + { + nwipe_options.method = &nwipe_zero; + break; + } + + if( strcmp( optarg, "one" ) == 0 ) + { + nwipe_options.method = &nwipe_one; + break; + } + + if( strcmp( optarg, "verify_zero" ) == 0 ) + { + nwipe_options.method = &nwipe_verify_zero; + break; + } + + if( strcmp( optarg, "verify_one" ) == 0 ) + { + nwipe_options.method = &nwipe_verify_one; + break; + } + + if( strcmp( optarg, "is5enh" ) == 0 ) + { + nwipe_options.method = &nwipe_is5enh; + break; + } + + /* Else we do not know this wipe method. */ + fprintf( stderr, "Error: Unknown wipe method '%s'.\n", optarg ); + exit( EINVAL ); + + case 'l': /* Log file option. */ + + nwipe_options.logfile[strlen( optarg )] = '\0'; + strncpy( nwipe_options.logfile, optarg, sizeof( nwipe_options.logfile ) ); + break; + + case 'P': /* PDFreport path option. */ + + nwipe_options.PDFreportpath[strlen( optarg )] = '\0'; + strncpy( nwipe_options.PDFreportpath, optarg, sizeof( nwipe_options.PDFreportpath ) ); + + /* Command line options will override what's in nwipe.conf */ + if( strcmp( nwipe_options.PDFreportpath, "noPDF" ) == 0 ) + { + nwipe_options.PDF_enable = 0; + nwipe_conf_update_setting( "PDF_Certificate.PDF_Enable", "DISABLED" ); + } + else + { + if( strcmp( nwipe_options.PDFreportpath, "." ) ) + { + /* and if the user has specified a PDF path then enable PDF */ + nwipe_options.PDF_enable = 1; + nwipe_conf_update_setting( "PDF_Certificate.PDF_Enable", "ENABLED" ); + } + } + + break; + + case 'e': /* exclude drives option */ + + idx_drive_chr = 0; + idx_optarg = 0; + idx_drive = 0; + + /* Create an array of excluded drives from the comma separated string */ + while( optarg[idx_optarg] != 0 && idx_drive < MAX_NUMBER_EXCLUDED_DRIVES ) + { + /* drop the leading '=' character if used */ + if( optarg[idx_optarg] == '=' && idx_optarg == 0 ) + { + idx_optarg++; + continue; + } + + if( optarg[idx_optarg] == ',' ) + { + /* terminate string and move onto next drive */ + nwipe_options.exclude[idx_drive++][idx_drive_chr] = 0; + idx_drive_chr = 0; + idx_optarg++; + } + else + { + if( idx_drive_chr < MAX_DRIVE_PATH_LENGTH ) + { + nwipe_options.exclude[idx_drive][idx_drive_chr++] = optarg[idx_optarg++]; + } + else + { + /* This section deals with file names that exceed MAX_DRIVE_PATH_LENGTH */ + nwipe_options.exclude[idx_drive][idx_drive_chr] = 0; + while( optarg[idx_optarg] != 0 && optarg[idx_optarg] != ',' ) + { + idx_optarg++; + } + } + } + if( idx_drive == MAX_NUMBER_EXCLUDED_DRIVES ) + { + fprintf( + stderr, + "The number of excluded drives has reached the programs configured limit, aborting\n" ); + exit( 130 ); + } + } + break; + + case 'h': /* Display help. */ + + display_help(); + break; + + case 'p': /* PRNG option. */ + + if( strcmp( optarg, "mersenne" ) == 0 || strcmp( optarg, "twister" ) == 0 ) + { + nwipe_options.prng = &nwipe_twister; + break; + } + + if( strcmp( optarg, "isaac" ) == 0 ) + { + nwipe_options.prng = &nwipe_isaac; + break; + } + + if( strcmp( optarg, "isaac64" ) == 0 ) + { + nwipe_options.prng = &nwipe_isaac64; + break; + } + + /* Else we do not know this PRNG. */ + fprintf( stderr, "Error: Unknown prng '%s'.\n", optarg ); + exit( EINVAL ); + + case 'q': /* Anonymize serial numbers */ + + nwipe_options.quiet = 1; + break; + + case 'r': /* Rounds option. */ + + if( sscanf( optarg, " %i", &nwipe_options.rounds ) != 1 || nwipe_options.rounds < 1 ) + { + fprintf( stderr, "Error: The rounds argument must be a positive integer.\n" ); + exit( EINVAL ); + } + + break; + + case 'v': /* verbose */ + + nwipe_options.verbose = 1; + break; + + case 'V': /* Version option. */ + + printf( "%s version %s\n", program_name, version_string ); + exit( EXIT_SUCCESS ); + + default: + + /* Bogus command line argument. */ + display_help(); + exit( EINVAL ); + + } /* method */ + + } /* command line options */ + + /* Return the number of options that were processed. */ + return optind; +} + +void nwipe_options_log( void ) +{ + extern nwipe_prng_t nwipe_twister; + extern nwipe_prng_t nwipe_isaac; + extern nwipe_prng_t nwipe_isaac64; + + /** + * Prints a manifest of options to the log. + */ + + nwipe_log( NWIPE_LOG_NOTICE, "Program options are set as follows..." ); + + if( nwipe_options.autonuke ) + { + nwipe_log( NWIPE_LOG_NOTICE, " autonuke = %i (on)", nwipe_options.autonuke ); + } + else + { + nwipe_log( NWIPE_LOG_NOTICE, " autonuke = %i (off)", nwipe_options.autonuke ); + } + + if( nwipe_options.autopoweroff ) + { + nwipe_log( NWIPE_LOG_NOTICE, " autopoweroff = %i (on)", nwipe_options.autopoweroff ); + } + else + { + nwipe_log( NWIPE_LOG_NOTICE, " autopoweroff = %i (off)", nwipe_options.autopoweroff ); + } + + if( nwipe_options.noblank ) + { + nwipe_log( NWIPE_LOG_NOTICE, " do not perform a final blank pass" ); + } + + if( nwipe_options.nowait ) + { + nwipe_log( NWIPE_LOG_NOTICE, " do not wait for a key before exiting" ); + } + + if( nwipe_options.nosignals ) + { + nwipe_log( NWIPE_LOG_NOTICE, " do not allow signals to interrupt a wipe" ); + } + + if( nwipe_options.nogui ) + { + nwipe_log( NWIPE_LOG_NOTICE, " do not show GUI interface" ); + } + + nwipe_log( NWIPE_LOG_NOTICE, " banner = %s", banner ); + + if( nwipe_options.prng == &nwipe_twister ) + { + nwipe_log( NWIPE_LOG_NOTICE, " prng = Mersenne Twister" ); + } + else + { + if( nwipe_options.prng == &nwipe_isaac ) + { + nwipe_log( NWIPE_LOG_NOTICE, " prng = Isaac" ); + } + else + { + if( nwipe_options.prng == &nwipe_isaac64 ) + { + nwipe_log( NWIPE_LOG_NOTICE, " prng = Isaac64" ); + } + else + { + nwipe_log( NWIPE_LOG_NOTICE, " prng = Undefined" ); + } + } + } + + nwipe_log( NWIPE_LOG_NOTICE, " method = %s", nwipe_method_label( nwipe_options.method ) ); + nwipe_log( NWIPE_LOG_NOTICE, " quiet = %i", nwipe_options.quiet ); + nwipe_log( NWIPE_LOG_NOTICE, " rounds = %i", nwipe_options.rounds ); + nwipe_log( NWIPE_LOG_NOTICE, " sync = %i", nwipe_options.sync ); + + switch( nwipe_options.verify ) + { + case NWIPE_VERIFY_NONE: + nwipe_log( NWIPE_LOG_NOTICE, " verify = %i (off)", nwipe_options.verify ); + break; + + case NWIPE_VERIFY_LAST: + nwipe_log( NWIPE_LOG_NOTICE, " verify = %i (last pass)", nwipe_options.verify ); + break; + + case NWIPE_VERIFY_ALL: + nwipe_log( NWIPE_LOG_NOTICE, " verify = %i (all passes)", nwipe_options.verify ); + break; + + default: + nwipe_log( NWIPE_LOG_NOTICE, " verify = %i", nwipe_options.verify ); + break; + } +} + +void display_help() +{ + /** + * displays the help section to STDOUT and exits. + */ + + printf( "Usage: %s [options] [device1] [device2] ...\n", program_name ); + printf( "Options:\n" ); + /* Limit line length to a maximum of 80 characters so it looks good in 80x25 terminals i.e shredos */ + /* ___12345678901234567890123456789012345678901234567890123456789012345678901234567890< Do not exceed */ + puts( " -V, --version Prints the version number\n" ); + puts( " -v, --verbose Prints more messages to the log\n" ); + puts( " -h, --help Prints this help\n" ); + puts( " --autonuke If no devices have been specified on the command line," ); + puts( " starts wiping all devices immediately. If devices have" ); + puts( " been specified, starts wiping only those specified" ); + puts( " devices immediately.\n" ); + puts( " --autopoweroff Power off system on completion of wipe delayed for" ); + puts( " for one minute. During this one minute delay you can" ); + puts( " abort the shutdown by typing sudo shutdown -c\n" ); + printf( " --sync=NUM Will perform a sync after NUM writes (default: %d)\n", DEFAULT_SYNC_RATE ); + puts( " 0 - fdatasync after the disk is completely written" ); + puts( " fdatasync errors not detected until completion." ); + puts( " 0 is not recommended as disk errors may cause" ); + puts( " nwipe to appear to hang" ); + puts( " 1 - fdatasync after every write" ); + puts( " Warning: Lower values will reduce wipe speeds." ); + puts( " 1000 - fdatasync after 1000 writes etc.\n" ); + puts( " --verify=TYPE Whether to perform verification of erasure" ); + puts( " (default: last)" ); + puts( " off - Do not verify" ); + puts( " last - Verify after the last pass" ); + puts( " all - Verify every pass\n" ); + puts( " -m, --method=METHOD The wiping method. See man page for more details." ); + puts( " (default: dodshort)" ); + puts( " dod522022m / dod - 7 pass DOD 5220.22-M method" ); + puts( " dodshort / dod3pass - 3 pass DOD method" ); + puts( " gutmann - Peter Gutmann's Algorithm" ); + puts( " ops2 - RCMP TSSIT OPS-II" ); + puts( " random / prng / stream - PRNG Stream" ); + puts( " zero / quick - Overwrite with zeros" ); + puts( " one - Overwrite with ones (0xFF)" ); + puts( " verify_zero - Verifies disk is zero filled" ); + puts( " verify_one - Verifies disk is 0xFF filled\n" ); + puts( " -l, --logfile=FILE Filename to log to. Default is STDOUT\n" ); + puts( " -P, --PDFreportpath=PATH Path to write PDF reports to. Default is \".\"" ); + puts( " If set to \"noPDF\" no PDF reports are written.\n" ); + puts( " -p, --prng=METHOD PRNG option (mersenne|twister|isaac|isaac64)\n" ); + puts( " -q, --quiet Anonymize logs and the GUI by removing unique data, i.e." ); + puts( " serial numbers, LU WWN Device ID, and SMBIOS/DMI data" ); + puts( " XXXXXX = S/N exists, ????? = S/N not obtainable\n" ); + puts( " -r, --rounds=NUM Number of times to wipe the device using the selected" ); + puts( " method (default: 1)\n" ); + puts( " --noblank Do NOT blank disk after wipe" ); + puts( " (default is to complete a final blank pass)\n" ); + puts( " --nowait Do NOT wait for a key before exiting" ); + puts( " (default is to wait)\n" ); + puts( " --nosignals Do NOT allow signals to interrupt a wipe" ); + puts( " (default is to allow)\n" ); + puts( " --nogui Do NOT show the GUI interface. Automatically invokes" ); + puts( " the nowait option. Must be used with the --autonuke" ); + puts( " option. Send SIGUSR1 to log current stats\n" ); + puts( " --nousb Do NOT show or wipe any USB devices whether in GUI" ); + puts( " mode, --nogui or --autonuke modes.\n" ); + puts( " -e, --exclude=DEVICES Up to ten comma separated devices to be excluded" ); + puts( " --exclude=/dev/sdc" ); + puts( " --exclude=/dev/sdc,/dev/sdd" ); + puts( " --exclude=/dev/sdc,/dev/sdd,/dev/mapper/cryptswap1\n" ); + puts( "" ); + exit( EXIT_SUCCESS ); +} |