/********** * Copyright (c) 2004-2005 Greg Parker. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY GREG PARKER ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. **********/ #include "includes.h" #include "formutils.h" #include "data/connectionlist.h" #include "data/publickeys.h" #include "data/prefs.h" #include "rsrc/rsrc.h" #include "ssh/ssh.h" #include "forms/resize.h" #include "publickeychoiceform.h" static Boolean RetrieveUsernameAndPassphrase(void) FORMS_SEGMENT; static void ForgetPassphrase(void) FORMS_SEGMENT; static void SetPassphraseEcho(Boolean echo) FORMS_SEGMENT; static Boolean LoadPublicKeyChoiceForm(void) FORMS_SEGMENT; extern struct ssh_session_t *ss; queue_t *PublicKeyChoiceKeys = NULL; static char **key_names = NULL; static MemHandle *key_handles = NULL; static uint16_t key_count = 0; static Boolean RetrieveUsernameAndPassphrase(void) { // fixme retrieve popup choice too FieldPtr usernameFld = PrvGetObjectByID(PublicKeyChoiceFormUsernameFieldID); FieldPtr passphraseFld = PrvGetObjectByID(PublicKeyChoiceFormPassphraseFieldID); MemHandle usernameH; MemHandle passphraseH; char *username; char *passphrase; Boolean ok; int keyIndex; FldReleaseFocus(usernameFld); FldCompactText(usernameFld); usernameH = FldGetTextHandle(usernameFld); FldReleaseFocus(passphraseFld); FldCompactText(passphraseFld); passphraseH = FldGetTextHandle(passphraseFld); if (usernameH) { username = MemHandleLock(usernameH); } else { username = ""; } if (passphraseH) { passphrase = MemHandleLock(passphraseH); } else { passphrase = ""; } keyIndex = LstGetSelection(PrvGetObjectByID(PublicKeyChoiceFormKeyListID)); if (keyIndex == noListSelection) { complain("no selection"); ok = false; } else { ok = ssh_use_passphrase(ss, username, passphrase, key_handles[keyIndex]); } if (usernameH) MemHandleUnlock(usernameH); if (passphraseH) MemHandleUnlock(passphraseH); if (!ok) { // password wrong - try again // leave username field alone and clear passphrase field PrvSetFieldToValue(passphraseFld, ""); FldEraseField(passphraseFld); FldDrawField(passphraseFld); PrvSetFocusByID(PublicKeyChoiceFormPassphraseFieldID); } else { // password ok - clean up field contents if (usernameH) { FldSetTextHandle(usernameFld, NULL); MemHandleFree(usernameH); } if (passphraseH) { FldSetTextHandle(passphraseFld, NULL); MemSet(MemHandleLock(passphraseH), MemHandleSize(passphraseH), 0); MemHandleUnlock(passphraseH); MemHandleFree(passphraseH); } } return ok; } static void ForgetPassphrase(void) { FieldPtr passphraseFld = PrvGetObjectByID(PublicKeyChoiceFormPassphraseFieldID); MemHandle passphraseH; FldReleaseFocus(passphraseFld); FldCompactText(passphraseFld); passphraseH = FldGetTextHandle(passphraseFld); FldSetTextHandle(passphraseFld, NULL); if (passphraseH) { MemSet(MemHandleLock(passphraseH), MemHandleSize(passphraseH), 0); MemHandleUnlock(passphraseH); MemHandleFree(passphraseH); } } static void SetPassphraseEcho(Boolean echo) { PrvSetControlValue(PublicKeyChoiceFormEchoCheckboxID, echo); FldSetFont(PrvGetObjectByID(PublicKeyChoiceFormPassphraseFieldID), echo ? stdFont : (FontID)PasswordFontID); } static Boolean LoadPublicKeyChoiceForm(void) { MemHandle recordH; Boolean ok = true; char *hostname; char *username; char *portname; recordH=ConnectionListReadSelectedRecord(&hostname, &portname, &username); if (!recordH) return false; if (ok) ok = PrvSetFieldToValueByID(PublicKeyChoiceFormHostFieldID, hostname); if (ok) ok = PrvSetFieldToValueByID(PublicKeyChoiceFormUsernameFieldID, username); if (ok) { if (StrLen(username) == 0) { // missing username - set caret to username PrvSetFocusByID(PublicKeyChoiceFormUsernameFieldID); } else { // username ok - set caret to passphrase PrvSetFocusByID(PublicKeyChoiceFormPassphraseFieldID); } } { // populate public key list ListPtr lst; uint16_t i, j; queue_t *q = PublicKeyChoiceKeys; // get all pubkey names and handles key_count = queue_count(q); key_names = arena_malloc(key_count * sizeof(char *)); key_handles = arena_malloc(key_count * sizeof(MemHandle)); for (i = 0; i < key_count; i++) { key_handles[i] = queue_peek(q, i); key_names[i] = NameForPublicKey(key_handles[i]); } // sort keys by name to type-select works (bubble sort) for (i = 0; i < key_count; i++) { for (j = i+1; j < key_count; j++) { if (strcmp(key_names[i], key_names[j]) > 0) { char *tmp_name = key_names[i]; MemHandle tmp_handle = key_handles[i]; key_names[i] = key_names[j]; key_handles[i] = key_handles[j]; key_names[j] = tmp_name; key_handles[j] = tmp_handle; } } } lst = PrvGetObjectByID(PublicKeyChoiceFormKeyListID); LstSetListChoices(lst, key_names, key_count); LstSetHeight(lst, key_count); // fixme select a previously-good key for this connection using prefs LstSetSelection(lst, 0); PrvSetControlLabel(PublicKeyChoiceFormKeyTriggerID, key_names[0]); } if (ok) SetPassphraseEcho(PrefsGetInt(prefEchoPassword, 0)); MemHandleUnlock(recordH); return ok; } static void DoOK(void) { // send username and passphrase to connection if (RetrieveUsernameAndPassphrase()) { FrmReturnToForm(0); } else { // passphrase was wrong (probably) FrmCustomAlert(AlertFormID, "Incorrect passphrase.", " ", " "); } } Boolean PublicKeyChoiceFormHandleEvent(EventPtr e) { FormPtr frmP = FrmGetActiveForm(); if (ResizeHandleEvent(e)) return true; switch (e->eType) { case frmOpenEvent: if (!LoadPublicKeyChoiceForm()) { // load failed - go back to terminal form FrmReturnToForm(0); } else { FrmDrawForm(frmP); } return true; case keyDownEvent: if (!EvtKeydownIsVirtual(e)) { unsigned char c = e->data.keyDown.chr; if (c == '\n' || c == '\r') { // enter in username - switch to password // enter in password - OK button // enter in neither - OK button UInt16 focusID; UInt16 focusIndex = FrmGetFocus(FrmGetActiveForm()); if (focusIndex == noFocus) { DoOK(); return true; } focusID = FrmGetObjectId(FrmGetActiveForm(), focusIndex); if (focusID == PublicKeyChoiceFormUsernameFieldID) { PrvSetFocusByID(PublicKeyChoiceFormPassphraseFieldID); PrvFieldSelectAll(PublicKeyChoiceFormPassphraseFieldID); return true; } else if (focusID == PublicKeyChoiceFormPassphraseFieldID) { DoOK(); return true; } } } return false; case ctlSelectEvent: switch (e->data.ctlSelect.controlID) { case PublicKeyChoiceFormOKButtonID: DoOK(); return true; case PublicKeyChoiceFormCancelButtonID: // skip further pubkey auth (continue to password, probably) FrmReturnToForm(0); ssh_use_passphrase(ss, NULL, NULL, NULL); // this is user cancel return true; case PublicKeyChoiceFormEchoCheckboxID: // change passphrase field echoing PrefsPutInt(prefEchoPassword, e->data.ctlSelect.on); SetPassphraseEcho(e->data.ctlSelect.on); return true; default: return false; } case frmCloseEvent: // clear entered passphrase, if any ForgetPassphrase(); // free key names if (key_names) { int i; LstSetListChoices(PrvGetObjectByID(PublicKeyChoiceFormKeyListID), NULL, 0); PrvSetControlLabel(PublicKeyChoiceFormKeyTriggerID, ""); for (i = 0; i < key_count; i++) { arena_free(key_names[i]); } arena_free(key_names); key_names = NULL; key_count = NULL; } if (key_handles) { arena_free(key_handles); key_handles = NULL; } return false; case usrSetFocusEvent: PrvReallySetFocus(frmP, e); return true; default: return false; } }