/* * GNU POC (passwords on card) - manage passwords on smartcards * Copyright (C) 2001 Henning Koester * * Please report bugs to bug-poc@gnu.org * * This file is part of POC. * * 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; either version 2 of * the License, or (at your option) any later version. * * 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* $Id: main.c,v 1.9 2001/08/18 15:41:35 henning Exp henning $ */ #include #include #include #include #include #include #include "lang.h" #include "cipher.h" #include "poc.h" #include "poc_types.h" #include "backup_card.h" #include "change.h" #include "format.h" #include "password.h" #include "misc.h" /* Available ciphers. */ static char CIPHERS[] = "AES, BLOWFISH, plaintext"; /****************************************************************************** * * Function : usage * * Description : This function gives the user an overview about the available * options. * * Input : [1] progname (char) * The program's name (argv[0]). * * Return : 1 * *****************************************************************************/ static void usage(const char * const progname) { printf("GNU %s version %s\n", PACKAGE, VERSION); printf("Copyright (C) 2001 Henning Koester \n"); printf("This program comes with ABSOLUTELY NO WARRANTY.\n"); printf("This is free software, and you are welcome to redistribute it\n"); printf("under certain conditions. See the file COPYING for details.\n\n"); printf("CIPHER: %s\n", CIPHERS); printf("Usage: %s [COMMAND] [OPTION]\n", progname); printf("\nCommands:\n"); printf(" --backup=FILE backup the card to FILE\n"); printf(" -c, --change-cardkey change cardkey\n"); printf(" -f, --format-card format card\n"); printf(" -l DESCRIPTION, --list-password=DESCRIPTION\n"); printf(" list the password with the given description\n"); printf(" if DESCRIPTION is 'all' then all passwords\n"); printf(" -s, --save-password save a password\n"); printf(" -r DESCRIPTION, --remove-password=DESCRIPTION\n"); printf(" remove the password with the given description\n"); printf(" --restore=FILE restore a backuped card from FILE\n"); printf("\nStandard Commands:\n"); printf(" -h, --help print this message and exit\n"); printf(" -V, --version display the program version\n"); printf("\nOptions:\n"); printf(" --cipher=CIPHER cipher for enciphering the card\n"); printf(" CIPHER can be one of the above, or 'plaintext'\n"); printf(" if not specified, 'AES' will be used\n"); printf(" -p NUM, --port=NUM com-port (NUM = 1...4)\n"); printf(" --security=LEVEL security level can be 1(normal), 2(high)\n"); printf(" -v, --verbose be verbose\n"); printf("\nReport bugs to \n"); exit(1); } /****************************************************************************** * * Function : print_version * * Description : This function prints the programs version along with a * copyright notice. * * Input : none * * Return : none * *****************************************************************************/ static void print_version(void) { printf("GNU %s version %s\n", PACKAGE, VERSION); printf("Copyright (C) 2001 Henning Koester \n"); printf("This program comes with ABSOLUTELY NO WARRANTY.\n"); printf("This is free software, and you are welcome to redistribute it\n"); printf("under certain conditions. See the file COPYING for details.\n\n"); } /****************************************************************************** * * Function : get_name * * Description : This function checks whether 'data' contains one of name's * elements. Used to test whether the user has selected an * available cipher. * * Input : [1] data (char) * [2] names (char) * * Return : Pointer to the appropriate element in names, or NULL if * 'data' wasn't found in 'names'. * *****************************************************************************/ static char * get_name(const char * const data, char * const names) { char *p; /* Used to split 'names' with strtok(3). */ p = strtok(names, " "); /* Get first value of 'names'. */ /* Loop, to check every element element of 'names'. */ while (p != NULL) { /* Remove the comma at the end, if necessary. */ if (p[strlen(p) - 1] == ',') p[strlen(p) - 1] = '\0'; /* Check whether p (selected element of 'names') is equal to 'data'. */ if (strcasecmp(p, data) == 0) return(p); /* Return the pointer to the correct element of 'names'. */ p = strtok(NULL, " "); /* Get next element. */ } /* 'data' wasn't found in 'names', so we'll return NULL. */ return(NULL); } /****************************************************************************** * * Function : check_crypto_settings * * Description : This function checks whether the user has selected cipher * and/or security-level settings. The function will set * default settings if the user didn't force special settings. * * Input : [1] card_crypt_ctx (char) * Information about data encryption (cipher, security-level) * * Return : nothing is returned. * *****************************************************************************/ static void check_crypto_settings(crypt_context * const card_crypt_ctx) { /* * Check the cipher settings. * * If the user didn't select a cipher with the --cipher option, we * will check whether the environment variable specifies one. */ if ((card_crypt_ctx->cipher == NULL) && (getenv(ENV_CIPHER) != NULL)) { /* * Found environment variable. * Now check whether it's a valid cipher. */ if ( (card_crypt_ctx->cipher = get_name(getenv(ENV_CIPHER), CIPHERS)) == NULL) { /* No valid cipher. Print an error and exit. */ print_err(STR_WRONG_CIPHER_ENV); exit(1); } } else /* * Neither the --cipher options specified a cipher, nor the environment * variable. So we will use the default, namely 'AES'. */ card_crypt_ctx->cipher = "AES"; /* * Check for security level settings. * * If the user didn't select a security level with the --security option, * we will check whether the environment variable specifies one. */ if ((card_crypt_ctx->sec_level == 0) && (getenv(ENV_SL) != NULL)) { /* * Found environment variable. * Check whether it's valid. */ if ((atoi(getenv(ENV_SL)) != SL_NORMAL) && (atoi(getenv(ENV_SL)) != SL_HIGH)) { /* Invalid security-level setting. Print error and exit. */ print_err(STR_WRONG_SEC_LEVEL_ENV); exit(1); } else { /* Valid setting. */ card_crypt_ctx->sec_level = atoi(getenv(ENV_SL)); return; } } if (card_crypt_ctx->sec_level != 0) return; /* Use the default security-level. */ card_crypt_ctx->sec_level = SL_NORMAL; } /* Program's name */ char *progname; /*************** *** OPTIONS *** ***************/ /* 1 means: make a backup */ static bool backup_card_flg = 0; /* 1 means: change card's key */ static bool change_cardkey_flg = 0; /* 1 means: format card */ static bool format_card_flg = 0; /* 1 means: list password(s) */ static bool list_password_flg = 0; /* 1 means: save a new password to the card */ static bool save_password_flg = 0; /* 1 means: remove a password from the card */ static bool remove_password_flg = 0; /* 1 means: restore a backuped card */ static bool restore_card_flg = 0; /* Give more information output */ bool verbose_flg = 0; /* Information on data encryption. */ static crypt_context card_crypt_ctx; /* Description contains the description of the password which should be listet (if the -l, --list-password option was set) or the description of the password which should be removed (-r, --remove-password). */ static char description[DESCR_LENGTH]; /* File contains the file to which the card will be backup or from which the card will be restored. */ static char file[FILENAME_MAX]; /* At which port is the card terminal? */ static u16 port = 0; /* default: COM1 */ /* Options for getopt_long(3) */ static struct option long_options[] = { {"backup", required_argument, NULL, 0}, {"change-cardkey", no_argument, (int *)&change_cardkey_flg, 1}, {"cipher", required_argument, NULL, 0}, {"format-card", no_argument, (int *)&format_card_flg, 1}, {"help", no_argument, NULL, 0 }, {"list-password", required_argument, NULL, 0}, {"port", required_argument, NULL, 0}, {"save-password", no_argument, (int *)&save_password_flg, 1}, {"security", required_argument, NULL, 0}, {"remove-password", required_argument, NULL, 0}, {"restore", required_argument, NULL, 0}, {"verbose", no_argument, (int *)&verbose_flg, 1}, {"version", no_argument, NULL, 0}, {0, 0, 0, 0} }; /****************************************************************************** * * Function : main * * Description : This function is the main body of the program. It will check * program options, checks whether they are valid, and will call * the appropriate sub-routines. * * Input : [1] argc (int) * Number of commandline arguments. * [2] argv (char) * Array containing commandline options. * * Return : POC_ERROR or POC_SUCCESS * *****************************************************************************/ int main(int argc, char **argv) { /* used by getopt_long */ int ch; int option_index; /* Set progname. */ progname = argv[0]; card_crypt_ctx.cipher = NULL; card_crypt_ctx.sec_level = 0; /* Get command line arguments. */ while ((ch = getopt_long(argc, argv, "cfhl:p:sr:vV", long_options, &option_index)) != -1) switch (ch) { case 0: /* * Check long options. */ /* --backup: backup card */ if (strcmp(long_options[option_index].name, "backup") == 0) { strncpy(file, optarg, FILENAME_MAX); backup_card_flg = 1; break; } else /* --cipher: cipher to use */ if (strcmp(long_options[option_index].name, "cipher") == 0) { if ( (card_crypt_ctx.cipher = get_name(optarg, CIPHERS)) == NULL) { print_err(STR_WRONG_CIPHER); exit(1); } break; } else /* --help: output help message */ if (strcmp(long_options[option_index].name, "help") == 0) { usage(argv[0]); break; } else /* --list-password: list password which has the given descr. */ if (strcmp(long_options[option_index].name, "list-password") == 0) { strncpy(description, optarg, DESCR_LENGTH); list_password_flg = 1; break; } else /* --remove-password: remove password which has the given descr. */ if (strcmp(long_options[option_index].name, "remove-password") == 0) { strncpy(description, optarg, DESCR_LENGTH); remove_password_flg = 1; break; } else /* --restore: restore a backuped card. */ if (strcmp(long_options[option_index].name, "restore") == 0) { strncpy(file, optarg, FILENAME_MAX); restore_card_flg = 1; break; } else /* --security: which security-level to use */ if (strcmp(long_options[option_index].name, "security") == 0) { if (atoi(optarg) != SL_NORMAL && atoi(optarg) != SL_HIGH) { print_err(STR_WRONG_SEC_LEVEL); exit(1); } card_crypt_ctx.sec_level = atoi(optarg); break; } else /* --verbose: verbose output */ if (strcmp(long_options[option_index].name, "verbose") == 0) { verbose_flg = 1; break; } else /* --version: output program's version */ if (strcmp(long_options[option_index].name, "version") == 0) { print_version(); exit(0); break; } else /* --port: at which comport we can find the terminal. */ if (strcmp(long_options[option_index].name, "port") == 0) { port = atoi(optarg) - 1; break; } break; /* Short options ... */ case 'c': /* -c: change card's encryption key */ change_cardkey_flg = 1; break; case 'f': /* -f: format card */ format_card_flg = 1; break; case 'h': /* -h: help message */ usage(argv[0]); break; case 'l': /* -l: list password */ strncpy(description, optarg, DESCR_LENGTH); list_password_flg = 1; break; case 'p': /* -p: com port */ port = atoi(optarg) - 1; break; case 's': /* -s: save password */ save_password_flg = 1; break; case 'r': /* -r: remove password */ strncpy(description, optarg, DESCR_LENGTH); remove_password_flg = 1; break; case 'v': /* -v: be verbose */ verbose_flg = 1; break; case 'V': /* -V: print version information */ print_version(); exit(0); break; } #ifdef DEBUG /* If compiled with DEBUG we always print more information. */ verbose_flg = 1; #endif /* Check whether 'poc' was executed without a COMMAND (see help message for possible COMMANDS. */ if (!backup_card_flg && !change_cardkey_flg && !format_card_flg && !list_password_flg && !save_password_flg && !remove_password_flg && !restore_card_flg ) { print_err(STR_NO_COMMAND); return(POC_ERROR); } /* Multiple COMMANDS are not allowed. */ if ( (backup_card_flg + change_cardkey_flg + format_card_flg + list_password_flg + save_password_flg + remove_password_flg + restore_card_flg) > 1) { print_err(STR_NO_MULTIPLE_COMMANDS); return(POC_ERROR); } /* Check cipher/security-level settings and set to defaults if nothing was specified. */ check_crypto_settings(&card_crypt_ctx); /* * Check which flags are set and execute the appropiate functions. * * Depending on the return of each function we will output an error or * a success message/output a searched password and exit. */ /* Backup a card. */ if (backup_card_flg) { if (backup_create(file, port) != POC_SUCCESS) { print_err(STR_BACKUP_FAIL); return(POC_ERROR); } else { printf(STR_BACKUP_SUCCESS); return(POC_SUCCESS); } } /* Change the encryption key. */ if (change_cardkey_flg) { if (change_card_key(&card_crypt_ctx, port) != POC_SUCCESS) { print_err(STR_CHANGE_KEY_FAIL); return(POC_ERROR); } else { printf(STR_CHANGE_KEY_SUCCESS); return(POC_SUCCESS); } } /* Format a card. */ if (format_card_flg) { if (format_card(port) != POC_SUCCESS) { print_err(STR_FORMAT_FAIL); return(POC_ERROR); } else { printf(STR_FORMAT_SUCCESS); return(POC_SUCCESS); } } /* Print a stored password. */ if (list_password_flg) { if (password_list(&card_crypt_ctx, port, description) != POC_SUCCESS) { print_err(STR_LIST_PASS_FAIL); return(POC_ERROR); } return(POC_SUCCESS); } /* Save a password. */ if (save_password_flg) { if (password_save(&card_crypt_ctx, port) != POC_SUCCESS) { print_err(STR_SAVE_PASS_FAIL); return(POC_ERROR); } else { printf(STR_SAVE_PASS_SUCCESS); return(POC_SUCCESS); } } /* Remove a password. */ if (remove_password_flg) { if (password_remove(&card_crypt_ctx, port, description) != POC_SUCCESS) { print_err(STR_REM_PASS_FAIL); return(POC_ERROR); } else { printf(STR_REM_PASS_SUCCESS); return(POC_SUCCESS); } } /* Restore a backuped card. */ if (restore_card_flg) { if (backup_restore(file, port) != POC_SUCCESS) { print_err(STR_RESTORE_FAIL); return(POC_ERROR); } else { printf(STR_RESTORE_SUCCESS); return(POC_SUCCESS); } } return(POC_SUCCESS); }