Retired Document
Important: This sample code may not represent best practices for current development. The project may use deprecated symbols and illustrate technologies and techniques that are no longer recommended.
sources/PGPUAMclient.c
/* |
File: PGPUAMclient.c |
Description: PGP Appleshare User Authentication Module |
Written by: Vinnie Moscaritolo |
Copyright: © 1998 by Apple Computer, Inc., all rights reserved. |
Change History (most recent first): |
You may incorporate this sample code into your applications without |
restriction, though the sample code has been provided "AS IS" and the |
responsibility for its operation is 100% yours. However, what you are |
not permitted to do is to redistribute the source as "DSC Sample Code" |
after having made changes. If you're going to re-distribute the source, |
we require that you make it clear in the source that the code was |
descended from Apple Sample Code, but that you've made changes. |
*/ |
//------------------------------------------------------------------------------------ |
#pragma mark Includes |
//------------------------------------------------------------------------------------ |
#include <Errors.h> |
#include <String.h> |
#include <A4Stuff.h> |
#include <Resources.h> |
#include <MixedMode.h> |
#include <Appearance.h> |
#include <CodeFragments.h> |
#include <Gestalt.h> |
#include <PLStringFuncs.h> |
#include "ClientUAM.h" |
#include "AFPPackets.h" |
#include <stdio.h> |
#include "TPGPkey.h" |
#include "TPGPException.h" |
#include "TMacException.h" |
#include "TASIPPGPkey.h" |
#include "ASIPChallenge.h" |
#include "PGPUAMdefines.h" |
#include "PGPUAMclient.h" |
#include "PGPUAMclientLoginDialog.h" |
#include "PGPUAMclientProtocol.h" |
#include "PGPUAMmsgFormat.h" |
#include "PGPUAMclient.h" |
#include "TPGPUAMPrefs.h" |
#include "pgpUserInterface.h" |
// --------------------------------------------------------------------------- |
#pragma mark Exported Symbols |
// --------------------------------------------------------------------------- |
#ifdef __cplusplus |
extern "C" { |
#endif |
#pragma export on |
extern const long __procinfo = kUAMCallProcInfo; |
OSErr __pgpuam_initialize(CFragInitBlockPtr ibp); |
void __pgpuam_terminate(void); |
pascal OSStatus __pgpuam_client (UAMArgs *theArgs); |
pascal OSErr __initialize(const CFragInitBlock *theInitBlock); |
pascal OSErr __terminate(void); |
#pragma export off |
#ifdef __cplusplus |
} |
#endif |
// --------------------------------------------------------------------------- |
#pragma mark Globals |
// --------------------------------------------------------------------------- |
AFPSrvrInfo * gAFPServerInfo = nil; |
AFPClientInfo * gClientInfo = nil; |
UInt8 * gAFPSrvrSig = nil; |
// --------------------------------------------------------------------------- |
#pragma mark Local Prototypes |
// --------------------------------------------------------------------------- |
static OSStatus PGPUAMOpen (UAMArgs *theArgs); |
static OSStatus PGPUAMClose (UAMArgs *theArgs); |
static OSStatus PGPUAMLogin (UAMArgs *theArgs); |
static OSStatus InitiateConnection (StringPtr userName, |
StringPtr serverName, |
short *sessionRefNum, |
TPGPUAMPrefs *userPrefs, |
TASIPPGPkey *serverKey, |
IdleConnectionProcPtr idleProc, |
void* context ); |
static void TerminateConnection (void* context); |
static StringPtr FigureAFPVersion( AFPSrvrInfo *info,ClientUAMCallbackRec *callbacks); |
static Boolean FindStringInBuf( StringPtr string, Ptr buf, UInt32 bufSize); |
static void PostError(short errorStrId, short explanStrID); |
// test code.. |
// --------------------------------------------------------------------------- |
OSErr __pgpuam_initialize(CFragInitBlockPtr ibp) |
// --------------------------------------------------------------------------- |
// |
// PGPUAM Library Initialization |
// |
{ |
long gestaltResult; |
OSErr err = -1; |
/* |
** Check for a 68020 or later processor and bail immediately if |
** none is available. |
*/ |
//DebugStr("\p__pgpuam_initialize"); |
if( Gestalt( gestaltProcessorType, &gestaltResult ) == noErr && |
gestaltResult >= gestalt68020 ) |
{ |
err = __initialize( ibp ); |
} |
return err; |
} |
// --------------------------------------------------------------------------- |
void __pgpuam_terminate(void) |
// --------------------------------------------------------------------------- |
// |
// PGPUAM Library Termination |
// |
{ |
__terminate(); |
} |
#pragma mark - |
// --------------------------------------------------------------------------- |
pascal OSStatus __pgpuam_client(UAMArgs *theArgs) |
// --------------------------------------------------------------------------- |
{ |
OSStatus error; |
char errorBuf[256]; |
char explanationBuf[256]; |
// ostrstream err( errorBuf,256); |
// ostrstream explain( explanationBuf,256); |
EnterCodeResource(); |
try |
{ |
switch(theArgs->command) |
{ |
case kUAMOpen: |
// DebugStr("\pUAMCall - kUAMOpen"); |
error = PGPUAMOpen(theArgs); |
break; |
case kUAMPWDlog: |
// DebugStr("\pUAMCall - kUAMPWDlog"); |
error = noErr; |
break; |
case kUAMLogin: |
// DebugStr("\pUAMCall - kUAMLogin"); |
error = PGPUAMLogin(theArgs); |
break; |
case kUAMVSDlog: |
// DebugStr("\pUAMCall - kUAMVSDlog"); |
error = noErr; |
break; |
case kUAMChgPassDlg: |
DebugStr("\pUAMCall - kUAMChgPassDlg"); |
error = kNotForUs; |
break; |
case kUAMChgPass: |
DebugStr("\pUAMCall - kUAMChgPass"); |
error = kNotForUs; |
break; |
case kUAMGetInfoSize: |
DebugStr("\pUAMCall - kUAMGetInfoSize"); |
// uamInfoSize = n; |
error = kNotForUs; |
break; |
case kUAMGetInfo: |
DebugStr("\pUAMCall - kUAMGetInfo"); |
// uamInfo < == |
error = kNotForUs; |
break; |
case kUAMClose: |
// DebugStr("\pUAMCall - kUAMClose"); |
error = PGPUAMClose(theArgs); |
break; |
default: |
DebugStr("\psome other UAMCall"); |
error = kNotForUs; |
break; |
} |
} |
catch (TMacException &ex) |
{ |
SInt16 itemHit; |
error = theArgs->result = ex.GetExceptionErr(); |
if(error == noErr) |
error = userCanceledErr; |
errorBuf[0] = sprintf(&errorBuf[1], "%s\rPGPUAM Error: %d\rFile: %s, Line: %d", |
ex.GetExceptionMessage(), ex.GetExceptionErr(), ex.GetExceptionFile(), ex.GetExceptionLine()); |
StandardAlert(kAlertStopAlert,"\pThe PGP Challenge/Response UAM could not be used.", |
(UInt8 *) errorBuf, nil , &itemHit); |
} |
// handle PGP errors |
catch (TPGPException &ex) |
{ |
SInt16 itemHit; |
PGPGetErrorString ( ex.GetExceptionErr(), sizeof(explanationBuf), explanationBuf); |
errorBuf[0] = sprintf(&errorBuf[1], "%s\r\rPGPUAM Error: %d\rFile: %s, Line: %d", |
ex.GetExceptionMessage(), ex.GetExceptionErr(), ex.GetExceptionFile(), ex.GetExceptionLine()); |
c2pstr(explanationBuf); |
StandardAlert(kAlertStopAlert,(UInt8 *)errorBuf, (UInt8 *)explanationBuf, nil , &itemHit); |
error = theArgs->result = userCanceledErr; |
} |
ExitCodeResource(); |
return error; |
} |
// --------------------------------------------------------------------------- |
static OSStatus PGPUAMOpen(UAMArgs *theArgs) |
// --------------------------------------------------------------------------- |
{ |
OSStatus ErrNo ; |
long response = 0; |
// Get the AppleShare Client info |
ErrNo = CallUniversalProc( theArgs->callbacks->GetClientInfoUPP, kGetClientInfoProcInfo, kAFPClientInfo, &gClientInfo); |
if(ErrNo != noErr) return ErrNo; |
// check agaisnt client versions |
ThrowMsgIfNot ( (gClientInfo->fVersion > 8), |
"This UAM requires AppleShare Client 3.8.1 or later"); |
// Save the server info pointer. |
gAFPServerInfo = theArgs->Opt.open.srvrInfo; |
// calculate server signature block. |
UInt8 *signatureOffset; |
signatureOffset = (&gAFPServerInfo->fSrvrName[0] + gAFPServerInfo->fSrvrName[0] + 1); |
if ( (UInt32)signatureOffset & 0x01) signatureOffset++; |
gAFPSrvrSig = ((UInt8*) gAFPServerInfo) + * ((short*)signatureOffset); |
// Is Appearance Mgr available ? |
ThrowMsgIfNot ( ((Gestalt(gestaltAppearanceAttr, &response) == noErr) |
&& ((long)RegisterAppearanceClient != kUnresolvedCFragSymbolAddress)) , |
"Appearance Mgr is required"); |
// collection manager too |
ThrowMsgIfNot ( ((Gestalt(gestaltCollectionMgrVersion, &response) == noErr) |
&& ((long)NewCollection != kUnresolvedCFragSymbolAddress)) , |
"Collection Mgr is required"); |
// Is PGPsdk available ? |
ThrowMsgIfNot ((long)PGPNewContext != kUnresolvedCFragSymbolAddress, |
"PGPsdk is required"); |
// Is PGPsdkUIlib available ? |
ThrowMsgIfNot ((long)PGPSigningPassphraseDialog != kUnresolvedCFragSymbolAddress , |
"PGPsdkUIlib is required"); |
// Create a new PGP context |
TPGPkey::Initialize(); |
// establish link to PassphraseCache |
//??? |
theArgs->result = ((1 << kUsePWDlog) | (1 << kUseUAMInfo)) ; |
return noErr; |
} |
// --------------------------------------------------------------------------- |
static OSStatus PGPUAMLogin(UAMArgs *theArgs) |
// --------------------------------------------------------------------------- |
{ |
TPGPUAMPrefs* userPrefs = nil; |
Str63 userName; |
// Get user prefs |
userPrefs = new TPGPUAMPrefs(); |
userPrefs->Initialize(); |
// open the keyring |
TPGPkey::OpenKeyDefaultRing(); |
// if no username was specified.. (Alias resolution) |
// Initiate the connection w/o UI |
if(theArgs->Opt.auth.userName[0] != '\0') |
{ |
TASIPPGPkey theServerKey; |
// copy the user name from the authblock |
PLstrcpy( userName, theArgs->Opt.auth.userName); |
// pickup the server key |
theServerKey.Initialize(gAFPSrvrSig); |
// initiate connection directly |
theArgs->result = InitiateConnection(userName, gAFPServerInfo->fSrvrName, &theArgs->sessionRefNum, userPrefs, &theServerKey, nil, theArgs); |
} |
else |
{ |
// copy the default user name. |
PLstrcpy( userName, gClientInfo->fDefaultUserName); |
// initiate connection with User Interface |
theArgs->result = DoLoginDialog( userName, |
gAFPServerInfo->fSrvrName, |
&theArgs->sessionRefNum, |
userPrefs, |
InitiateConnection, |
TerminateConnection, |
theArgs->callbacks->EventCallbackUPP, |
theArgs); |
// put username into the authblock buffer for later Alias resolution |
PLstrcpy(theArgs->Opt.auth.userName, userName); |
// not clear if I should post the error or not |
// you might want to take out the next line... |
if(( theArgs->result != noErr) && (theArgs->result != userCanceledErr)) |
PostError( kErrOther, kErrOtherExplanation); |
} |
// close the keyring |
TPGPkey::CloseKeyRing(); |
// update user prefs |
userPrefs->Finalize(); |
delete userPrefs; |
return (theArgs->result) ; |
} |
// --------------------------------------------------------------------------- |
static OSStatus PGPUAMClose(UAMArgs *theArgs) |
// --------------------------------------------------------------------------- |
{ |
// remove PGP context |
TPGPkey::Finalize(); |
return noErr; |
} |
#pragma mark - |
// --------------------------------------------------------------------------- |
static OSStatus InitiateConnection( StringPtr userName, |
StringPtr serverName, |
short *sessionRefNum, |
TPGPUAMPrefs *userPrefs, |
TASIPPGPkey *serverKey, |
IdleConnectionProcPtr idleProc, |
void* context) |
// --------------------------------------------------------------------------- |
{ |
UAMArgs *theArgs = (UAMArgs *) context; |
PUAM_LOGIN_RESP resp; |
StringPtr serverVersion; |
Str63 challengeString; |
Str63 answerString; |
Str255 promptString; |
UInt8 replyBuffer[256]; |
UInt32 replyBufferSize; |
Handle uamName; |
OSStatus ErrNo ; |
// calculate which AFPversion we will use. |
serverVersion = FigureAFPVersion(gAFPServerInfo,theArgs->callbacks); |
if(!serverVersion){ |
// put up an alert & return userCancelled error |
DebugStr("\pno AFP version returned by server"); |
return userCanceledErr; |
} |
// get the UAMSTring from the resource |
uamName = Get1Resource(kUAMStr,kUAMProtoName); |
ThrowMacErrIfNil(uamName, ResError()); |
// Calculate Challenge String |
MakeChallenge(serverKey, challengeString); |
// send OpenSession command to server. |
HLock(uamName); |
ErrNo = SndLoginCmd( theArgs->callbacks, |
serverVersion, (StringPtr) *uamName, userName, |
challengeString, |
theArgs->Opt.auth.srvrAddress, |
replyBuffer, sizeof (replyBuffer), &replyBufferSize, |
sessionRefNum, |
idleProc); |
HUnlock(uamName); |
if( ErrNo != kFPAuthContinue ) return ErrNo; |
ErrNo = userCanceledErr; |
// parse the reply |
ParseLoginResp(replyBuffer, &replyBufferSize, &resp); |
// check the reply |
if( ! VerifyChallenge(serverKey, challengeString, resp.CounterChallengePString)) |
{ |
// warn user that server didnt check out! |
Str255 errorBuf, explainBuf; |
SInt16 itemHit; |
AlertStdAlertParamRec aRec; |
aRec.movable = true; |
aRec.helpButton = false; |
aRec.filterProc = nil; |
aRec.defaultText = userPrefs->GetAuthenticateServer()? (unsigned char*) -1 : "\pAbort"; |
aRec.cancelText = userPrefs->GetAuthenticateServer()? nil:"\pContinue"; |
aRec.otherText = nil; |
aRec.defaultButton = kAlertStdAlertOKButton; |
aRec.cancelButton = kAlertStdAlertCancelButton; |
aRec.position = kWindowAlertPositionParentWindowScreen; |
GetIndString(errorBuf, kErrorStringsID, kErrUnableToAuthErr); |
PLstrcat(errorBuf, "\p\""); |
PLstrcat(errorBuf, serverName); |
PLstrcat(errorBuf, "\p\"."); |
GetIndString(explainBuf, kErrorStringsID, userPrefs->GetAuthenticateServer() ? kErrUnableToAuthExplanation: kErrUnableToAuthContinueExplanation); |
StandardAlert(kAlertCautionAlert, errorBuf, explainBuf, &aRec , &itemHit); |
if(itemHit == kAlertStdAlertOKButton) return userCanceledErr; |
}; |
// build custom prompt string |
PLstrcpy(promptString, "\pTo connect to \""); |
PLstrcat(promptString, serverName); |
PLstrcat(promptString, "\p\", please enter the passphrase for the following key."); |
p2cstr(promptString); |
ErrNo = ReplyToCounterChallenge(promptString, resp.FingerPrintPString, resp.CounterChallengePString, answerString); |
if(ErrNo == userCanceledErr) return ErrNo; |
if(ErrNo != noErr) |
{ |
PostError(kErrClientUnableToAuthErr, kErrClientUnableToAuthExplanation); |
return userCanceledErr; |
} |
ErrNo = SndLoginContinueCmd(theArgs->callbacks, *sessionRefNum, answerString, |
replyBuffer, sizeof (replyBuffer), &replyBufferSize, idleProc); |
return ErrNo; |
} |
// --------------------------------------------------------------------------- |
static void PostError(short errorStrId,short explanStrID) |
// --------------------------------------------------------------------------- |
// |
{ |
Str255 errorBuf, explainBuf; |
SInt16 itemHit; |
GetIndString(errorBuf, kErrorStringsID, errorStrId); |
if(explanStrID) |
GetIndString(explainBuf, kErrorStringsID, explanStrID); |
StandardAlert(kAlertStopAlert,errorBuf, (explanStrID)?explainBuf:nil, nil , &itemHit); |
} |
// --------------------------------------------------------------------------- |
static void TerminateConnection(void* context) |
// --------------------------------------------------------------------------- |
{ |
UAMArgs *theArgs = (UAMArgs *) context; |
} |
#pragma mark - |
// --------------------------------------------------------------------------- |
static StringPtr FigureAFPVersion(AFPSrvrInfo *info,ClientUAMCallbackRec *callbacks) |
// --------------------------------------------------------------------------- |
{ |
struct AFPClientInfo *theClientInfo = nil; |
short index; |
Ptr versBuf; |
UInt32 versBufsize; |
#if 0 |
// Hack |
return "\pAFP TEST VERSION"; |
// Hack |
#endif |
//DebugStr("\pFigureAFPVersion"); |
CallUniversalProc( callbacks->GetClientInfoUPP, kGetClientInfoProcInfo, kAFPClientInfo, &theClientInfo); |
if(theClientInfo){ |
// go through the list of AFP versions supported and try to find them |
// in the SrvrInfoBuffer, first match gets it |
versBuf = (Ptr)((UInt32)info + info->fVerCountOffset+1); |
versBufsize = kMaxAFPCommand - info->fVerCountOffset; // the largest size |
for(index = 0; index < theClientInfo->fNumAFPVersions; index++){ |
if(FindStringInBuf(theClientInfo->fAFPVersionStrs[index],versBuf,versBufsize)){ |
return theClientInfo->fAFPVersionStrs[index]; |
} |
} |
} |
return nil; |
} |
// --------------------------------------------------------------------------- |
static Boolean FindStringInBuf(StringPtr string, Ptr buf, UInt32 bufSize) |
// --------------------------------------------------------------------------- |
{ |
Ptr end = buf + bufSize; |
Byte len = string[0] + 1; |
short index; |
while((buf < end) && (*buf++ != string[0])) ; // scan for the proper length |
if(!(buf < end)){ |
return false; |
} |
for(index = 1; (index < len) && (buf > end); index++){ |
if(*buf++ != string[index]) |
return false; |
} |
if(!(buf < end)){ |
return false; |
} |
return true; |
} |
Copyright © 2003 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2003-07-22