diff --git a/lsh/MacOS/src/lsh_context.h b/lsh/MacOS/src/lsh_context.h index f2774de..500a714 100755 --- a/lsh/MacOS/src/lsh_context.h +++ b/lsh/MacOS/src/lsh_context.h @@ -66,6 +66,7 @@ typedef struct lshcontext { char _kpassword[64]; int _kindex; int _pindex; + char _keychainprompt[256]; } lshcontext; diff --git a/macssh/source/Headers/Preferences.h b/macssh/source/Headers/Preferences.h index f0770e2..f82a5fc 100755 --- a/macssh/source/Headers/Preferences.h +++ b/macssh/source/Headers/Preferences.h @@ -255,8 +255,8 @@ typedef struct { /* NONO */ Boolean - cachePassphrase, // Connection's windows remain open after connection close - unused1, // free + cachePassphrase, // + useKeyChain, // unused2, // free unused3; // free long diff --git a/macssh/source/Headers/globaldefs.h b/macssh/source/Headers/globaldefs.h index 7f1b76d..b87736e 100755 --- a/macssh/source/Headers/globaldefs.h +++ b/macssh/source/Headers/globaldefs.h @@ -152,6 +152,8 @@ PaletteHandle AnsiColors; //The Global ANSI Color palette Boolean haveColorQuickDraw; +Boolean + haveKeyChain; NewMacroInfo newMacros; }; diff --git a/macssh/source/config/configure.c b/macssh/source/config/configure.c index d876006..8b10c70 100755 --- a/macssh/source/config/configure.c +++ b/macssh/source/config/configure.c @@ -156,6 +156,11 @@ void Cenviron( void) } else { cachePass = TRUE; } + if ( !TelInfo->haveKeyChain ) { + HideDialogItem(dptr, 41); + } else { + SetCntrl(dptr, 41, gApplicationPrefs->useKeyChain); + } /* NONO */ scratchPstring[0] = 4; @@ -199,6 +204,7 @@ void Cenviron( void) case 35: case 36: case 37: + case 41: FlipCheckBox( dptr, ditem); break; case PrefStag: @@ -312,6 +318,7 @@ void Cenviron( void) GetTEText(dptr,24, scratchPstring); StringToNum(scratchPstring, &scratchlong); gApplicationPrefs->cacheDelay = scratchlong; + gApplicationPrefs->useKeyChain = GetCntlVal(dptr, 41); /* NONO */ gApplicationPrefs->CommandKeys = GetCntlVal(dptr, PrefCMDkey); diff --git a/macssh/source/init/init.c b/macssh/source/init/init.c index 2f2c7f1..5946f89 100755 --- a/macssh/source/init/init.c +++ b/macssh/source/init/init.c @@ -45,6 +45,8 @@ #include "memory.proto.h" #include "AddressXLation.h" +#include + #define _POSIX_SOURCE 1 #include #include @@ -253,6 +255,11 @@ void InquireEnvironment( void) } TelInfo->haveColorQuickDraw = theWorld.hasColorQD; +#if GENERATINGCFM + TelInfo->haveKeyChain = KeychainManagerAvailable(); +#else + TelInfo->haveKeyChain = false; +#endif } #define kURLEventClass 'GURL' diff --git a/macssh/source/ssh/PasswordDialog.c b/macssh/source/ssh/PasswordDialog.c index 97d419d..d4af121 100755 --- a/macssh/source/ssh/PasswordDialog.c +++ b/macssh/source/ssh/PasswordDialog.c @@ -24,14 +24,22 @@ #include #include #include +#include #include "PasswordDialog.h" #include "movableModal.h" #include "event.proto.h" #include "netevent.proto.h" #include "DlogUtils.proto.h" +#include "wind.h" + +#include extern void ssh2_sched(); +extern WindRec *ssh2_window(); + +extern void setctxprompt(const char *prompt); +extern char *getctxprompt(); extern TelInfoRec *TelInfo; extern Boolean gAEavail; @@ -368,11 +376,144 @@ Boolean SSH2LoginDialog(StringPtr host, StringPtr login, StringPtr password) return item == 1; } -Boolean SSH2PasswordDialog(StringPtr prompt, StringPtr password) +#if GENERATINGCFM + +/* + * GetPassFromKeychain + */ + +static void GetLabelFromPrompt(const char *prompt, StringPtr host, StringPtr user) +{ + WindRec *wind = ssh2_window(); + if ( wind && strstr(prompt, "assword for") ) { + StringPtr p = wind->sshdata.host; + memcpy( host, p, *p + 1 ); + p = wind->sshdata.login; + memcpy( user, p, *p + 1 ); + } else { + /* use key label as both host name and user name */ + int l = strlen(prompt); + *host = 4 + l; + memcpy(host + 1, "Key ", 4); + memcpy(host + 5, prompt, l); + *user = l; + memcpy(user + 1, prompt, l); + } +} + +/* + * GetPassFromKeychain + */ + +static Boolean GetPassFromKeychain(const char *prompt, StringPtr password) +{ + OSStatus theStatus; + UInt32 theLength; + KCItemRef theItem; + + if ( TelInfo->haveKeyChain && gApplicationPrefs->useKeyChain ) { + Str255 phost; + Str255 puser; + GetLabelFromPrompt(prompt, phost, puser); + theStatus = KCFindGenericPassword(phost, puser, 255, + password + 1, &theLength, &theItem); + if ( theStatus == noErr ) { + password[0] = theLength; + if (theItem != NULL) + KCReleaseItem( &theItem ); + return true; + } + } + return false; +} + +/* + * AddPassToKeychain + */ + +static void AddPassToKeychain(const char *prompt, StringPtr password) +{ + OSStatus theStatus; + UInt32 theLength; + KCItemRef theItem = NULL; + Str255 phost; + Str255 puser; + Str255 ppass; + KCAttribute theAttribute; + OSType theTypeCreator; + + if ( !TelInfo->haveKeyChain || !gApplicationPrefs->useKeyChain ) + return; + + GetLabelFromPrompt(prompt, phost, puser); + theStatus = KCFindGenericPassword(phost, puser, 255, + ppass + 1, &theLength, &theItem); + if ( theStatus == noErr && theItem != NULL) { + ppass[0] = theLength; + if ( memcmp(ppass, password, *ppass + 1) ) { + theStatus = KCSetData(theItem, *password, password + 1); + if (theStatus == noErr) + theStatus = KCUpdateItem(theItem); + } + } else { + theStatus = KCAddGenericPassword(phost, puser, + *password, password + 1, &theItem); + if (theStatus == noErr) { + unsigned char *theDescriptionText = "\pMacSSH password"; + theAttribute.tag = kDescriptionKCItemAttr; + theAttribute.length = *theDescriptionText; + theAttribute.data = theDescriptionText + 1; + theStatus = KCSetAttribute(theItem, &theAttribute); + } + if (theStatus == noErr) { + theTypeCreator = 'Ssh2'; + theAttribute.tag = kCreatorKCItemAttr; + theAttribute.length = sizeof(theTypeCreator); + theAttribute.data = &theTypeCreator; + theStatus = KCSetAttribute(theItem, &theAttribute); + } + if (theStatus == noErr) { + theTypeCreator = 'APPL'; + theAttribute.tag = kTypeKCItemAttr; + theStatus = KCSetAttribute(theItem, &theAttribute); + } + if (theStatus == noErr) { + Boolean theCustomIcon = true; + theAttribute.tag = kCustomIconKCItemAttr; + theAttribute.length = sizeof(theCustomIcon); + theAttribute.data = &theCustomIcon; + theStatus = KCSetAttribute(theItem, &theAttribute); + } + if (theStatus == noErr) + theStatus = KCUpdateItem(theItem); + } + if (theItem != NULL) + KCReleaseItem(&theItem); +} +#endif + + +/* + * SSH2PasswordDialog + */ + + + +Boolean SSH2PasswordDialog(const char *prompt, StringPtr password) { DialogPtr dlog; short item = 0; + Boolean addKey = false; ModalFilterUPP internalBufferFilterUPP; + ConstStringPtr keyPrompt = "\pEnter passphrase for private key "; + WindRec *wind; + +#if GENERATINGCFM + if ( strcmp(prompt, getctxprompt()) && GetPassFromKeychain(prompt, password) ) { + setctxprompt(prompt); + return true; + } +#endif InteractWithUser( true, 128, 128 ); @@ -381,12 +522,29 @@ Boolean SSH2PasswordDialog(StringPtr prompt, StringPtr password) *password = '\0'; dlog = GetNewMyDialog(rSSH2PasswordDialog, 0L, (WindowPtr)-1L, NULL); if ( dlog ) { + Str255 pprompt; SInt16 itemType; Handle itemHandle; Rect itemRect; + ControlHandle cntlHandle; + WindRec *wind = ssh2_window(); // set prompt + if ( wind && strstr(prompt, "assword for") ) { + pprompt[0] = strlen(prompt); + memcpy(pprompt + 1, prompt, pprompt[0]); + } else { + memcpy(pprompt, keyPrompt, keyPrompt[0] + 1); + memcpy(pprompt + pprompt[0] + 1, prompt, strlen(prompt)); + pprompt[0] += strlen(prompt); + } GetDialogItem(dlog, 5, &itemType, &itemHandle, &itemRect); - SetDialogItemText(itemHandle, prompt); + SetDialogItemText(itemHandle, pprompt); + if ( TelInfo->haveKeyChain && gApplicationPrefs->useKeyChain ) { + GetDialogItem(dlog, 6, &itemType, (Handle *)&cntlHandle, &itemRect); + SetControlValue(cntlHandle, addKey = true); + } else { + HideDialogItem(dlog, 6); + } SetDialogDefaultItem(dlog, 1); SetDialogCancelItem(dlog, 2); SetDialogTracksCursor(dlog, 1); @@ -394,16 +552,25 @@ Boolean SSH2PasswordDialog(StringPtr prompt, StringPtr password) SetWRefCon(dlog, (long)password); // Stash the buffer's address do { movableModalDialog(internalBufferFilterUPP, &item); + if (item == 6) { + SetControlValue(cntlHandle, !GetControlValue(cntlHandle)); + } } while (item != 1 && item != 2); // Until the OK button is hit + addKey = GetControlValue(cntlHandle); DisposeDialog(dlog); } DisposeRoutineDescriptor(internalBufferFilterUPP); ResetMenus(); +#if GENERATINGCFM + if ( item == 1 && addKey ) { + AddPassToKeychain( prompt, password ); + } +#endif return item == 1; } -static short SSH2SOCDialog(char *fingerprint, int id) +static short SSH2SOCDialog(const char *fingerprint, int id) { DialogPtr dlog; short item = 3; /* cancel */ @@ -442,12 +609,12 @@ static short SSH2SOCDialog(char *fingerprint, int id) return item; } -short SSH2SOC1Dialog(char *fingerprint) +short SSH2SOC1Dialog(const char *fingerprint) { return SSH2SOCDialog(fingerprint, rSSH2SOC1Dialog); } -short SSH2SOC2Dialog(char *fingerprint) +short SSH2SOC2Dialog(const char *fingerprint) { return SSH2SOCDialog(fingerprint, rSSH2SOC2Dialog); } diff --git a/macssh/source/ssh/PasswordDialog.h b/macssh/source/ssh/PasswordDialog.h index 31f53c5..533819b 100755 --- a/macssh/source/ssh/PasswordDialog.h +++ b/macssh/source/ssh/PasswordDialog.h @@ -38,9 +38,9 @@ Boolean SSH2RandomizeDialog( long *type, long *level, long *encrypt, Str255 labe void SSH2ErrorDialog(char *mess1); Boolean SSH2LoginDialog(StringPtr inhost, StringPtr iologin, StringPtr outpassword); -Boolean SSH2PasswordDialog (StringPtr inprompt, StringPtr outpassword); -short SSH2SOC1Dialog(char *fingerprint); -short SSH2SOC2Dialog(char *fingerprint); +Boolean SSH2PasswordDialog (const char *inprompt, StringPtr outpassword); +short SSH2SOC1Dialog(const char *fingerprint); +short SSH2SOC2Dialog(const char *fingerprint); void InternalBufferDialog (StringPtr inprompt, StringPtr outpassword); Boolean YesNoDialog (StringPtr inprompt); diff --git a/macssh/source/ssh/ssh2.c b/macssh/source/ssh/ssh2.c index 16b56b3..a7daa8f 100755 --- a/macssh/source/ssh/ssh2.c +++ b/macssh/source/ssh/ssh2.c @@ -781,11 +781,9 @@ char *getpass( const char *prompt ) wind->sshdata.password[0] = '\0'; valid = 1; } else { - pprompt[0] = strlen(prompt); - memcpy(pprompt + 1, prompt, pprompt[0]); ppassword[0] = 0; pthread_mutex_lock( &dialock ); - valid = SSH2PasswordDialog(pprompt, ppassword); + valid = SSH2PasswordDialog(prompt, ppassword); pthread_mutex_unlock( &dialock ); if (valid) { memcpy(password, ppassword + 1, ppassword[0]); @@ -805,12 +803,9 @@ char *getpass( const char *prompt ) && getnextcachedpassphrase(prompt, context->_kpassword, &context->_kindex) ) { return context->_kpassword; } - PLstrcpy(pprompt, "\pEnter passphrase for private key "); - memcpy(pprompt + pprompt[0] + 1, prompt, strlen(prompt)); - pprompt[0] += strlen(prompt); context->_kpassword[0] = 0; pthread_mutex_lock( &dialock ); - valid = SSH2PasswordDialog(pprompt, (StringPtr)context->_kpassword); + valid = SSH2PasswordDialog(prompt, (StringPtr)context->_kpassword); pthread_mutex_unlock( &dialock ); if (valid) { plen = context->_kpassword[0]; @@ -825,6 +820,23 @@ char *getpass( const char *prompt ) return (valid) ? password : NULL; } +/* + * setctxprompt + */ +void setctxprompt(const char *prompt) +{ + strcpy(((lshcontext *)pthread_getspecific(ssh2threadkey))->_keychainprompt, prompt); +} + +/* + * getctxprompt + */ + +char *getctxprompt() +{ + return ((lshcontext *)pthread_getspecific(ssh2threadkey))->_keychainprompt; +} + /* * save_once_cancel1 */ @@ -1110,6 +1122,7 @@ void init_context(lshcontext *context, short port) context->_kpassword[0] = 0; context->_kindex = 0; context->_pindex = 0; + context->_keychainprompt[0] = 0; } /* diff --git a/macssh/source/telnet.rsrc b/macssh/source/telnet.rsrc index ce8b7a9..85fdf58 100755 Binary files a/macssh/source/telnet.rsrc and b/macssh/source/telnet.rsrc differ diff --git a/macssh/www/download/ChangeLog b/macssh/www/download/ChangeLog index 593f1d6..9436b94 100755 Binary files a/macssh/www/download/ChangeLog and b/macssh/www/download/ChangeLog differ