X-Git-Url: https://git.distorted.org.uk/u/mdw/putty/blobdiff_plain/06980e9d67b5151ef4f1167cb1f8e6a559d1e270..222d54dc209210b6e43589c798e35e21273b4082:/puttygen.c diff --git a/puttygen.c b/puttygen.c index fc3c71a8..3e43b052 100644 --- a/puttygen.c +++ b/puttygen.c @@ -14,12 +14,35 @@ #include "ssh.h" #include "winstuff.h" +#ifdef MSVC4 +#define ICON_BIG 1 +#endif + #define WM_DONEKEY (WM_XUSER + 1) #define DEFAULT_KEYSIZE 1024 static int requested_help; +static char *cmdline_keyfile = NULL; + +/* + * Print a modal (Really Bad) message box and perform a fatal exit. + */ +void modalfatalbox(char *fmt, ...) +{ + va_list ap; + char *stuff; + + va_start(ap, fmt); + stuff = dupvprintf(fmt, ap); + va_end(ap); + MessageBox(NULL, stuff, "PuTTYgen Fatal Error", + MB_SYSTEMMODAL | MB_ICONERROR | MB_OK); + sfree(stuff); + exit(1); +} + /* ---------------------------------------------------------------------- * Progress report code. This is really horrible :-) */ @@ -183,10 +206,11 @@ static int prompt_keyfile(HWND hwnd, char *dlgtitle, #endif of.hwndOwner = hwnd; if (ppk) { - of.lpstrFilter = "PuTTY Private Key Files\0*.PPK\0All Files\0*\0\0\0"; + of.lpstrFilter = "PuTTY Private Key Files (*.ppk)\0*.ppk\0" + "All Files (*.*)\0*\0\0\0"; of.lpstrDefExt = ".ppk"; } else { - of.lpstrFilter = "All Files\0*\0\0\0"; + of.lpstrFilter = "All Files (*.*)\0*\0\0\0"; } of.lpstrCustomFilter = NULL; of.nFilterIndex = 1; @@ -204,14 +228,6 @@ static int prompt_keyfile(HWND hwnd, char *dlgtitle, } /* - * This function is needed to link with the DES code. We need not - * have it do anything at all. - */ -void logevent(char *msg) -{ -} - -/* * Dialog-box function for the Licence box. */ static int CALLBACK LicenceProc(HWND hwnd, UINT msg, @@ -281,7 +297,7 @@ static int CALLBACK AboutProc(HWND hwnd, UINT msg, return 0; case 101: EnableWindow(hwnd, 0); - DialogBox(hinst, MAKEINTRESOURCE(214), NULL, LicenceProc); + DialogBox(hinst, MAKEINTRESOURCE(214), hwnd, LicenceProc); EnableWindow(hwnd, 1); SetActiveWindow(hwnd); return 0; @@ -354,10 +370,8 @@ static void setupbigedit1(HWND hwnd, int id, int idstatic, struct RSAKey *key) dec1 = bignum_decimal(key->exponent); dec2 = bignum_decimal(key->modulus); - buffer = smalloc(strlen(dec1) + strlen(dec2) + - strlen(key->comment) + 30); - sprintf(buffer, "%d %s %s %s", - bignum_bitcount(key->modulus), dec1, dec2, key->comment); + buffer = dupprintf("%d %s %s %s", bignum_bitcount(key->modulus), + dec1, dec2, key->comment); SetDlgItemText(hwnd, id, buffer); SetDlgItemText(hwnd, idstatic, "&Public key for pasting into authorized_keys file:"); @@ -375,8 +389,8 @@ static void setupbigedit2(HWND hwnd, int id, int idstatic, int i; pub_blob = key->alg->public_blob(key->data, &pub_len); - buffer = smalloc(strlen(key->alg->name) + 4 * ((pub_len + 2) / 3) + - strlen(key->comment) + 3); + buffer = snewn(strlen(key->alg->name) + 4 * ((pub_len + 2) / 3) + + strlen(key->comment) + 3, char); strcpy(buffer, key->alg->name); p = buffer + strlen(buffer); *p++ = ' '; @@ -610,6 +624,175 @@ void ui_set_state(HWND hwnd, struct MainDlgState *state, int status) } } +void load_key_file(HWND hwnd, struct MainDlgState *state, + Filename filename, int was_import_cmd) +{ + char passphrase[PASSPHRASE_MAXLEN]; + int needs_pass; + int type, realtype; + int ret; + char *comment; + struct PassphraseProcStruct pps; + struct RSAKey newkey1; + struct ssh2_userkey *newkey2 = NULL; + + type = realtype = key_type(&filename); + if (type != SSH_KEYTYPE_SSH1 && + type != SSH_KEYTYPE_SSH2 && + !import_possible(type)) { + char msg[256]; + sprintf(msg, "Couldn't load private key (%s)", + key_type_to_str(type)); + MessageBox(NULL, msg, + "PuTTYgen Error", MB_OK | MB_ICONERROR); + return; + } + + if (type != SSH_KEYTYPE_SSH1 && + type != SSH_KEYTYPE_SSH2) { + realtype = type; + type = import_target_type(type); + } + + comment = NULL; + if (realtype == SSH_KEYTYPE_SSH1) + needs_pass = rsakey_encrypted(&filename, &comment); + else if (realtype == SSH_KEYTYPE_SSH2) + needs_pass = + ssh2_userkey_encrypted(&filename, &comment); + else + needs_pass = import_encrypted(&filename, realtype, + &comment); + pps.passphrase = passphrase; + pps.comment = comment; + do { + if (needs_pass) { + int dlgret; + dlgret = DialogBoxParam(hinst, + MAKEINTRESOURCE(210), + NULL, PassphraseProc, + (LPARAM) & pps); + if (!dlgret) { + ret = -2; + break; + } + } else + *passphrase = '\0'; + if (type == SSH_KEYTYPE_SSH1) { + if (realtype == type) + ret = loadrsakey(&filename, &newkey1, + passphrase, NULL); + else + ret = import_ssh1(&filename, realtype, + &newkey1, passphrase); + } else { + if (realtype == type) + newkey2 = ssh2_load_userkey(&filename, + passphrase, NULL); + else + newkey2 = import_ssh2(&filename, realtype, + passphrase); + if (newkey2 == SSH2_WRONG_PASSPHRASE) + ret = -1; + else if (!newkey2) + ret = 0; + else + ret = 1; + } + } while (ret == -1); + if (comment) + sfree(comment); + if (ret == 0) { + MessageBox(NULL, "Couldn't load private key.", + "PuTTYgen Error", MB_OK | MB_ICONERROR); + } else if (ret == 1) { + /* + * Now update the key controls with all the + * key data. + */ + { + SetDlgItemText(hwnd, IDC_PASSPHRASE1EDIT, + passphrase); + SetDlgItemText(hwnd, IDC_PASSPHRASE2EDIT, + passphrase); + if (type == SSH_KEYTYPE_SSH1) { + char buf[128]; + char *savecomment; + + state->ssh2 = FALSE; + state->commentptr = &state->key.comment; + state->key = newkey1; + + /* + * Set the key fingerprint. + */ + savecomment = state->key.comment; + state->key.comment = NULL; + rsa_fingerprint(buf, sizeof(buf), + &state->key); + state->key.comment = savecomment; + + SetDlgItemText(hwnd, IDC_FINGERPRINT, buf); + /* + * Construct a decimal representation + * of the key, for pasting into + * .ssh/authorized_keys on a Unix box. + */ + setupbigedit1(hwnd, IDC_KEYDISPLAY, + IDC_PKSTATIC, &state->key); + } else { + char *fp; + char *savecomment; + + state->ssh2 = TRUE; + state->commentptr = + &state->ssh2key.comment; + state->ssh2key = *newkey2; /* structure copy */ + sfree(newkey2); + + savecomment = state->ssh2key.comment; + state->ssh2key.comment = NULL; + fp = + state->ssh2key.alg-> + fingerprint(state->ssh2key.data); + state->ssh2key.comment = savecomment; + + SetDlgItemText(hwnd, IDC_FINGERPRINT, fp); + sfree(fp); + + setupbigedit2(hwnd, IDC_KEYDISPLAY, + IDC_PKSTATIC, &state->ssh2key); + } + SetDlgItemText(hwnd, IDC_COMMENTEDIT, + *state->commentptr); + } + /* + * Finally, hide the progress bar and show + * the key data. + */ + ui_set_state(hwnd, state, 2); + state->key_exists = TRUE; + + /* + * If the user has imported a foreign key + * using the Load command, let them know. + * If they've used the Import command, be + * silent. + */ + if (realtype != type && !was_import_cmd) { + char msg[512]; + sprintf(msg, "Successfully imported foreign key\n" + "(%s).\n" + "To use this key with PuTTY, you need to\n" + "use the \"Save private key\" command to\n" + "save it in PuTTY's own format.", + key_type_to_str(realtype)); + MessageBox(NULL, msg, "PuTTYgen Notice", + MB_OK | MB_ICONINFORMATION); + } + } +} + /* * Dialog-box function for the main PuTTYgen dialog box. */ @@ -634,8 +817,10 @@ static int CALLBACK MainDlgProc(HWND hwnd, UINT msg, */ } requested_help = FALSE; + SendMessage(hwnd, WM_SETICON, (WPARAM) ICON_BIG, + (LPARAM) LoadIcon(hinst, MAKEINTRESOURCE(200))); - state = smalloc(sizeof(*state)); + state = snew(struct MainDlgState); state->generation_thread_exists = FALSE; state->collecting_entropy = FALSE; state->entropy = NULL; @@ -672,7 +857,7 @@ static int CALLBACK MainDlgProc(HWND hwnd, UINT msg, AppendMenu(menu1, MF_ENABLED, IDC_EXPORT_SSHCOM, "Export &ssh.com key"); AppendMenu(menu, MF_POPUP | MF_ENABLED, (UINT) menu1, - "&Conversions"); + "Con&versions"); state->cvtmenu = menu1; menu1 = CreateMenu(); @@ -715,7 +900,7 @@ static int CALLBACK MainDlgProc(HWND hwnd, UINT msg, "&Public key for pasting into authorized_keys file:", IDC_PKSTATIC, IDC_KEYDISPLAY, 5); SendDlgItemMessage(hwnd, IDC_KEYDISPLAY, EM_SETREADONLY, 1, 0); - staticedit(&cp, "Key fingerprint:", IDC_FPSTATIC, + staticedit(&cp, "Key f&ingerprint:", IDC_FPSTATIC, IDC_FINGERPRINT, 75); SendDlgItemMessage(hwnd, IDC_FINGERPRINT, EM_SETREADONLY, 1, 0); @@ -757,6 +942,12 @@ static int CALLBACK MainDlgProc(HWND hwnd, UINT msg, */ ui_set_state(hwnd, state, 0); + /* + * Load a key file if one was provided on the command line. + */ + if (cmdline_keyfile) + load_key_file(hwnd, state, filename_from_str(cmdline_keyfile), 0); + return 1; case WM_MOUSEMOVE: state = (struct MainDlgState *) GetWindowLong(hwnd, GWL_USERDATA); @@ -783,7 +974,7 @@ static int CALLBACK MainDlgProc(HWND hwnd, UINT msg, MAKELPARAM(0, PROGRESSRANGE)); SendDlgItemMessage(hwnd, IDC_PROGRESS, PBM_SETPOS, 0, 0); - params = smalloc(sizeof(*params)); + params = snew(struct rsa_key_thread_params); params->progressbar = GetDlgItem(hwnd, IDC_PROGRESS); params->dialog = hwnd; params->keysize = state->keysize; @@ -830,7 +1021,7 @@ static int CALLBACK MainDlgProc(HWND hwnd, UINT msg, int len = GetWindowTextLength(editctl); if (*state->commentptr) sfree(*state->commentptr); - *state->commentptr = smalloc(len + 1); + *state->commentptr = snewn(len + 1, char); GetWindowText(editctl, *state->commentptr, len + 1); if (state->ssh2) { setupbigedit2(hwnd, IDC_KEYDISPLAY, IDC_PKSTATIC, @@ -844,7 +1035,7 @@ static int CALLBACK MainDlgProc(HWND hwnd, UINT msg, break; case IDC_ABOUT: EnableWindow(hwnd, 0); - DialogBox(hinst, MAKEINTRESOURCE(213), NULL, AboutProc); + DialogBox(hinst, MAKEINTRESOURCE(213), hwnd, AboutProc); EnableWindow(hwnd, 1); SetActiveWindow(hwnd); return 0; @@ -859,6 +1050,9 @@ static int CALLBACK MainDlgProc(HWND hwnd, UINT msg, } return 0; case IDC_GENERATE: + if (HIWORD(wParam) != BN_CLICKED && + HIWORD(wParam) != BN_DOUBLECLICKED) + break; state = (struct MainDlgState *) GetWindowLong(hwnd, GWL_USERDATA); if (!state->generation_thread_exists) { @@ -902,8 +1096,8 @@ static int CALLBACK MainDlgProc(HWND hwnd, UINT msg, state->entropy_required = (state->keysize / 2) * 2; state->entropy_got = 0; state->entropy_size = (state->entropy_required * - sizeof(*state->entropy)); - state->entropy = smalloc(state->entropy_size); + sizeof(unsigned)); + state->entropy = snewn(state->entropy_required, unsigned); SendDlgItemMessage(hwnd, IDC_PROGRESS, PBM_SETRANGE, 0, MAKELPARAM(0, state->entropy_required)); @@ -913,6 +1107,8 @@ static int CALLBACK MainDlgProc(HWND hwnd, UINT msg, case IDC_SAVE: case IDC_EXPORT_OPENSSH: case IDC_EXPORT_SSHCOM: + if (HIWORD(wParam) != BN_CLICKED) + break; state = (struct MainDlgState *) GetWindowLong(hwnd, GWL_USERDATA); if (state->key_exists) { @@ -969,30 +1165,33 @@ static int CALLBACK MainDlgProc(HWND hwnd, UINT msg, int ret; FILE *fp = fopen(filename, "r"); if (fp) { - char buffer[FILENAME_MAX + 80]; + char *buffer; fclose(fp); - sprintf(buffer, "Overwrite existing file\n%.*s?", - FILENAME_MAX, filename); + buffer = dupprintf("Overwrite existing file\n%s?", + filename); ret = MessageBox(hwnd, buffer, "PuTTYgen Warning", MB_YESNO | MB_ICONWARNING); + sfree(buffer); if (ret != IDYES) break; } if (state->ssh2) { + Filename fn = filename_from_str(filename); if (type != realtype) - ret = export_ssh2(filename, type, &state->ssh2key, + ret = export_ssh2(&fn, type, &state->ssh2key, *passphrase ? passphrase : NULL); else - ret = ssh2_save_userkey(filename, &state->ssh2key, + ret = ssh2_save_userkey(&fn, &state->ssh2key, *passphrase ? passphrase : NULL); } else { + Filename fn = filename_from_str(filename); if (type != realtype) - ret = export_ssh1(filename, type, &state->key, + ret = export_ssh1(&fn, type, &state->key, *passphrase ? passphrase : NULL); else - ret = saversakey(filename, &state->key, + ret = saversakey(&fn, &state->key, *passphrase ? passphrase : NULL); } if (ret <= 0) { @@ -1003,6 +1202,8 @@ static int CALLBACK MainDlgProc(HWND hwnd, UINT msg, } break; case IDC_SAVEPUB: + if (HIWORD(wParam) != BN_CLICKED) + break; state = (struct MainDlgState *) GetWindowLong(hwnd, GWL_USERDATA); if (state->key_exists) { @@ -1012,12 +1213,13 @@ static int CALLBACK MainDlgProc(HWND hwnd, UINT msg, int ret; FILE *fp = fopen(filename, "r"); if (fp) { - char buffer[FILENAME_MAX + 80]; + char *buffer; fclose(fp); - sprintf(buffer, "Overwrite existing file\n%.*s?", - FILENAME_MAX, filename); + buffer = dupprintf("Overwrite existing file\n%s?", + filename); ret = MessageBox(hwnd, buffer, "PuTTYgen Warning", MB_YESNO | MB_ICONWARNING); + sfree(buffer); if (ret != IDYES) break; } @@ -1035,177 +1237,16 @@ static int CALLBACK MainDlgProc(HWND hwnd, UINT msg, break; case IDC_LOAD: case IDC_IMPORT: + if (HIWORD(wParam) != BN_CLICKED) + break; state = (struct MainDlgState *) GetWindowLong(hwnd, GWL_USERDATA); if (!state->generation_thread_exists) { char filename[FILENAME_MAX]; if (prompt_keyfile(hwnd, "Load private key:", - filename, 0, LOWORD(wParam)==IDC_LOAD)) { - char passphrase[PASSPHRASE_MAXLEN]; - int needs_pass; - int type, realtype; - int ret; - char *comment; - struct PassphraseProcStruct pps; - struct RSAKey newkey1; - struct ssh2_userkey *newkey2 = NULL; - - type = realtype = key_type(filename); - if (type != SSH_KEYTYPE_SSH1 && - type != SSH_KEYTYPE_SSH2 && - !import_possible(type)) { - char msg[256]; - sprintf(msg, "Couldn't load private key (%s)", - key_type_to_str(type)); - MessageBox(NULL, msg, - "PuTTYgen Error", MB_OK | MB_ICONERROR); - break; - } - - if (type != SSH_KEYTYPE_SSH1 && - type != SSH_KEYTYPE_SSH2) { - realtype = type; - type = import_target_type(type); - } - - comment = NULL; - if (realtype == SSH_KEYTYPE_SSH1) - needs_pass = rsakey_encrypted(filename, &comment); - else if (realtype == SSH_KEYTYPE_SSH2) - needs_pass = - ssh2_userkey_encrypted(filename, &comment); - else - needs_pass = import_encrypted(filename, realtype, - &comment); - pps.passphrase = passphrase; - pps.comment = comment; - do { - if (needs_pass) { - int dlgret; - dlgret = DialogBoxParam(hinst, - MAKEINTRESOURCE(210), - NULL, PassphraseProc, - (LPARAM) & pps); - if (!dlgret) { - ret = -2; - break; - } - } else - *passphrase = '\0'; - if (type == SSH_KEYTYPE_SSH1) { - if (realtype == type) - ret = loadrsakey(filename, &newkey1, - passphrase); - else - ret = import_ssh1(filename, realtype, - &newkey1, passphrase); - } else { - if (realtype == type) - newkey2 = ssh2_load_userkey(filename, - passphrase); - else - newkey2 = import_ssh2(filename, realtype, - passphrase); - if (newkey2 == SSH2_WRONG_PASSPHRASE) - ret = -1; - else if (!newkey2) - ret = 0; - else - ret = 1; - } - } while (ret == -1); - if (comment) - sfree(comment); - if (ret == 0) { - MessageBox(NULL, "Couldn't load private key.", - "PuTTYgen Error", MB_OK | MB_ICONERROR); - } else if (ret == 1) { - /* - * Now update the key controls with all the - * key data. - */ - { - SetDlgItemText(hwnd, IDC_PASSPHRASE1EDIT, - passphrase); - SetDlgItemText(hwnd, IDC_PASSPHRASE2EDIT, - passphrase); - if (type == SSH_KEYTYPE_SSH1) { - char buf[128]; - char *savecomment; - - state->ssh2 = FALSE; - state->commentptr = &state->key.comment; - state->key = newkey1; - - /* - * Set the key fingerprint. - */ - savecomment = state->key.comment; - state->key.comment = NULL; - rsa_fingerprint(buf, sizeof(buf), - &state->key); - state->key.comment = savecomment; - - SetDlgItemText(hwnd, IDC_FINGERPRINT, buf); - /* - * Construct a decimal representation - * of the key, for pasting into - * .ssh/authorized_keys on a Unix box. - */ - setupbigedit1(hwnd, IDC_KEYDISPLAY, - IDC_PKSTATIC, &state->key); - } else { - char *fp; - char *savecomment; - - state->ssh2 = TRUE; - state->commentptr = - &state->ssh2key.comment; - state->ssh2key = *newkey2; /* structure copy */ - sfree(newkey2); - - savecomment = state->ssh2key.comment; - state->ssh2key.comment = NULL; - fp = - state->ssh2key.alg-> - fingerprint(state->ssh2key.data); - state->ssh2key.comment = savecomment; - - SetDlgItemText(hwnd, IDC_FINGERPRINT, fp); - sfree(fp); - - setupbigedit2(hwnd, IDC_KEYDISPLAY, - IDC_PKSTATIC, &state->ssh2key); - } - SetDlgItemText(hwnd, IDC_COMMENTEDIT, - *state->commentptr); - } - /* - * Finally, hide the progress bar and show - * the key data. - */ - ui_set_state(hwnd, state, 2); - state->key_exists = TRUE; - - /* - * If the user has imported a foreign key - * using the Load command, let them know. - * If they've used the Import command, be - * silent. - */ - if (realtype != type && LOWORD(wParam) == IDC_LOAD) { - char msg[512]; - sprintf(msg, "Successfully imported foreign key\n" - "(%s).\n" - "To use this key with PuTTY, you need to\n" - "use the \"Save private key\" command to\n" - "save it in PuTTY's own format.", - key_type_to_str(realtype)); - MessageBox(NULL, msg, "PuTTYgen Notice", - MB_OK | MB_ICONINFORMATION); - } - } - } + filename, 0, LOWORD(wParam)==IDC_LOAD)) + load_key_file(hwnd, state, filename_from_str(filename), + LOWORD(wParam) != IDC_LOAD); } break; } @@ -1235,7 +1276,7 @@ static int CALLBACK MainDlgProc(HWND hwnd, UINT msg, * the user will immediately want to change it, which is * what we want :-) */ - *state->commentptr = smalloc(30); + *state->commentptr = snewn(30, char); { time_t t; struct tm *tm; @@ -1367,6 +1408,19 @@ void cleanup_exit(int code) { exit(code); } int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) { + int argc; + char **argv; + + split_into_argv(cmdline, &argc, &argv, NULL); + + if (argc > 0) { + /* + * Assume the first argument to be a private key file, and + * attempt to load it. + */ + cmdline_keyfile = argv[0]; + } + InitCommonControls(); hinst = inst;