// =========================================================================== // UAMDSNetwork.c © 1998 Microsoft Corp. All rights reserved. // =========================================================================== // DS Networking functions for use by Microsoft User Authentication Method. // // =========================================================================== #include #include #include #include "USRPWST3.h" #include "encrypt.h" #include "UAMDebug.h" #include "UAMMain.h" #include "UAMNetwork.h" #include "UAMDSNetwork.h" #include "UAMUtils.h" #include "UAMDialogs.h" unsigned char gCmdBuffer[kMaxAFPCommand]; unsigned char gReplyBuffer[kMaxAFPCommand]; extern Str32 gAFPVersion; extern MSUAMLoginReplyBlock gMSUAMReply; extern OTAddress *gServerAddress; extern long gSupportedUAMs; extern UInt32 gExpirationTime; // --------------------------------------------------------------------------- // ¥ UAM_CloseSession() // --------------------------------------------------------------------------- // Close a session on the AFP server. OSStatus UAM_CloseSession(UAMArgs *inUAMArgs) { OSStatus theError; #if GENERATING68K theError = inUAMArgs->callbacks->CloseSessionUPP(inUAMArgs->sessionRefNum); #else theError = CallUniversalProc( inUAMArgs->callbacks->CloseSessionUPP, kCloseSessionProcInfo, inUAMArgs->sessionRefNum ); #endif return(theError); } // --------------------------------------------------------------------------- // ¥ UAM_OpenSession() // --------------------------------------------------------------------------- // Open a session on the AFP server. OSStatus UAM_OpenSession( UAMArgs *inUAMArgs, UAMMessage *inMessage, unsigned char *inCmdBuffer, UInt32 inCmdBufferSize, unsigned char *inReplyBuffer, UInt32 inReplyBufferSize ) { OSStatus theError; Assert_(inUAMArgs != NULL); Assert_(inMessage != NULL); Assert_(inCmdBuffer != NULL); Assert_(gServerAddress != NULL); // //Note that inReplyBuffer can be null. // inMessage->commandCode = kOpenSession; inMessage->cmdBuffer = inCmdBuffer; inMessage->cmdBufferSize = inCmdBufferSize; inMessage->replyBuffer = inReplyBuffer; inMessage->replyBufferSize = inReplyBufferSize; inMessage->completion = NULL; inMessage->contextPtr = NULL; #if GENERATING68K theError = inUAMArgs->callbacks->OpenSessionUPP( gServerAddress, NULL, inMessage ); #else theError = CallUniversalProc( inUAMArgs->callbacks->OpenSessionUPP, kOpenSessionProcInfo, gServerAddress, NULL, inMessage ); #endif // //Even if theError == noErr, the parameter block's result //param still might hold an error code! // return((theError == noErr) ? inMessage->result : theError); } // --------------------------------------------------------------------------- // ¥ UAM_DSLoginGuest() // --------------------------------------------------------------------------- // Log into an AFP server as a guest. OSStatus UAM_DSLoginGuest(UAMArgs *inUAMArgs) { Ptr theCmdPtr; UInt32 theCmdSize; OSStatus theError; UAMMessage theMessage; Assert_(inUAMArgs != NULL); Assert_(PSTR_LENGTH(gAFPVersion) != 0); theCmdPtr = (Ptr)&gCmdBuffer[0]; *theCmdPtr = afpLogin; theCmdPtr += sizeof(Byte); StringPush_(gAFPVersion, (StringPtr)theCmdPtr); StringPush_(PSTR_GuestLogin, (StringPtr)theCmdPtr); theCmdSize = theCmdPtr - ((Ptr)&gCmdBuffer); theError = UAM_OpenSession( inUAMArgs, &theMessage, gCmdBuffer, theCmdSize, NULL, 0 ); if (theError == noErr) { inUAMArgs->sessionRefNum = theMessage.sessionRefNum; } return(theMessage.result); } // --------------------------------------------------------------------------- // ¥ UAM_DSLoginMSUAM() // --------------------------------------------------------------------------- // Log into an AFP server using the .AFPTranslator (through the UAM). OSStatus UAM_DSLoginMSUAM(UAMArgs *inUAMArgs) { OSStatus theError; Ptr theCmdPtr; UInt32 theCmdSize; Str32 theWSName; Str32 theUserName; UAMMessage theMessage; Assert_(inUAMArgs != NULL); Assert_(PSTR_LENGTH(gAFPVersion) != 0); // //11.10.99: Clear out the command buffer just to be safe. // memset(gCmdBuffer, '\0', sizeof(gCmdBuffer)); theCmdPtr = (Ptr)gCmdBuffer; UAM_PStrCopy(inUAMArgs->Opt.auth.userName, theUserName); // //09.28.00: If the user name is blank, then we create a random user name //so as to attempt a login as "guest". // if (PSTR_LENGTH(theUserName) == 0) { UAM_PStrCopy("\pGst&^^", theUserName); } if (inUAMArgs->callbacks != NULL) { UAM_GetWorkStationName(theWSName); // //This can be 0, but shouldn't be, catch only for debugging. // Assert_(PSTR_LENGTH(theWSName) != 0); // //Build the AFP command structure for a login. // *theCmdPtr = afpLogin; theCmdPtr += sizeof(Byte); // //Stuff the AFP command block with our info. // StringPush_(gAFPVersion, (StringPtr)theCmdPtr); // //Check UAM version that the server supports, use the latest... // if (gSupportedUAMs & kMSUAM_V2_Supported) { StringPush_(PSTR_EncryptedLogin2_0, (StringPtr)theCmdPtr); } else { StringPush_(PSTR_EncryptedLogin1_0, (StringPtr)theCmdPtr); } StringPush_(theUserName, (StringPtr)theCmdPtr); // //11.23.99 MJC - Only copy the workstation name if //there is one. If there is no workstation name for the Mac, then //we pad the end of the buffer with 2 bytes of 0's for NT4 SP6. // if (theWSName[0] > 0) { StringPush_(theWSName, (StringPtr)theCmdPtr); } else if ((gSupportedUAMs & kMSUAM_V2_Supported) == 0) { *theCmdPtr++ = 0x00; *theCmdPtr++ = 0x00; } // //The command block must end on an even boundary! // if ((theCmdPtr - (Ptr)gCmdBuffer) % 2) *theCmdPtr++ = 0x00; // //We need to get the command buffer size so we can pass it along. // theCmdSize = theCmdPtr - ((Ptr)gCmdBuffer); // //Zero out the parameter block. // memset(&theMessage, '\0', sizeof(UAMMessage)); theError = UAM_OpenSession( inUAMArgs, &theMessage, gCmdBuffer, theCmdSize, gReplyBuffer, sizeof(gReplyBuffer) ); // //The error returned should always be afpAuthContinue. // Assert_(theError == afpAuthContinue); if ( (theError == noErr) || (theError == afpAuthContinue) ) { inUAMArgs->sessionRefNum = theMessage.sessionRefNum; BlockMove(gReplyBuffer, &gMSUAMReply, sizeof(MSUAMLoginReplyBlock)); theError = UAM_DSMSUAMLoginCont(inUAMArgs); } #ifdef UAMDebug else { DBGPrintIfOSErr_(theError); } #endif } return(theError); } // --------------------------------------------------------------------------- // ¥ UAM_DSMSUAMLoginCont() // --------------------------------------------------------------------------- // Continue the login. The following command block is built. // // |---------------------| // | AFP Command | <- One Byte // |---------------------| // | Filler | // |---------------------| // | Encrypted Password | // / / // |---------------------| OSStatus UAM_DSMSUAMLoginCont(UAMArgs *inUAMArgs) { struct commandBuffer { Byte command; char marker; char UAMInfo[UAM_ENCRYPTEDPWLEN]; }*theCmdPtr; Assert_(inUAMArgs != NULL); char thePassT[UAM_CLRTXTPWDLEN+1]; OSStatus theError; UAMMessage theMessage; Str32 thePassword; UInt32 theTimeTillExpiration; // //Make a copy of the password as we're going to munge it up. // UAM_PStrCopy(inUAMArgs->Opt.auth.password, thePassword); UpperString(thePassword, true); memset(thePassT, '\0', UAM_CLRTXTPWDLEN+1); p2cstr(thePassword); strcpy(thePassT, (char *)thePassword); // //Map extended characters to the correct values for NT. // if (!UAM_MapCharactersIntoHostSet(thePassT, gMSUAMReply.serverExtCharMapTable)) { DbgPrint_((DBGBUFF, "UAM_MapCharactersIntoHostSet() failed")); return(afpUserNotAuth); } // //11.10.99: Clear out the command buffer just to be safe. // memset(gCmdBuffer, '\0', sizeof(gCmdBuffer)); theCmdPtr = (commandBuffer *)gCmdBuffer; theCmdPtr->command = afpContLogin; theCmdPtr->marker = '\0'; // //Now do the encryption using a hash routine. // UAM_CryptEncrypt(thePassT, gMSUAMReply.serverChallenge, theCmdPtr->UAMInfo); // //The encrypted OWF should never be null. // Assert_(strlen(theCmdPtr->UAMInfo) > 0); // //We need to zero out the parameter block. // memset(&theMessage, '\0', sizeof(UAMMessage)); theMessage.sessionRefNum = inUAMArgs->sessionRefNum; theMessage.commandCode = kSendRequest; theMessage.cmdBuffer = gCmdBuffer; theMessage.cmdBufferSize = sizeof(commandBuffer); theMessage.replyBuffer = (UInt8 *)&theTimeTillExpiration; theMessage.replyBufferSize = sizeof(UInt32); theMessage.completion = NULL; theMessage.contextPtr = NULL; #if GENERATING68K theError = inUAMArgs->callbacks->SendRequestUPP(&theMessage); #else theError = CallUniversalProc( inUAMArgs->callbacks->SendRequestUPP, kSendRequestProcInfo, &theMessage ); #endif // //For debugging we do this so we know where the error came from. // //DBGSignalIfOSErr_(theError); //DBGSignalIfOSErr_(theMessage.result); // //The actual error code may lerk in either place // theError = (theError == noErr) ? theMessage.result : theError; // //The reply buffer contains the password expiration time. // if (theError == noErr) { theTimeTillExpiration = ntoh(theTimeTillExpiration); gExpirationTime = theTimeTillExpiration; } // //Even if theError == noErr, the parameter block's result //param still might hold an error code! // return(theError); } // --------------------------------------------------------------------------- // ¥ UAM_ChangePassword() // --------------------------------------------------------------------------- // Change the user's password on the server. // // -> inUAMArgs The UAM arguments. // -> inNewPwd The new password requested by the user. // // Returns: An error code or noErr. // // |---------------------| // | AFP Command | <- One Byte // |---------------------| // | New pwd len | // |---------------------| // | UAM String | // / / // |---------------------| // | User Name | // / / // |---------------------| // | Old Pwd (Encrypted) | // / / // |---------------------| // | New Pwd (Encrypted) | // / / // |---------------------| OSStatus UAM_ChangePassword(UAMArgs *inUAMArgs, StringPtr inNewPwd) { OSStatus theError; Str32 theOldPwd, theNewPwd; Ptr theCmdPtr; short theCmdSize; char oldPassword[UAM_CLRTXTPWDLEN+1]; char newPassword[UAM_CLRTXTPWDLEN+1]; char oldPwdT[2*kServerChallengeMaxLen]; char newPwdT[2*kServerChallengeMaxLen]; Assert_(inNewPwd != NULL); Assert_(inUAMArgs != NULL); theError = UAM_DSLoginMSUAM(inUAMArgs); if ((theError == noErr) || (theError == afpNTPasswordExpired) || (theError == afpPwdExpiredErr)) { UAM_PStrCopy(inUAMArgs->Opt.auth.password, theOldPwd); UAM_PStrCopy(inNewPwd, theNewPwd); UpperString(theOldPwd, true); UpperString(theNewPwd, true); p2cstr(theOldPwd); p2cstr(theNewPwd); memset(oldPassword, '\0', UAM_CLRTXTPWDLEN+1); memset(newPassword, '\0', UAM_CLRTXTPWDLEN+1); strcpy(oldPassword, (char *)&theOldPwd); strcpy(newPassword, (char *)&theNewPwd); memset(gCmdBuffer, '\0', sizeof(gCmdBuffer)); theCmdPtr = (Ptr)gCmdBuffer; *theCmdPtr = afpChangePwd; theCmdPtr++; *theCmdPtr = strlen(newPassword); theCmdPtr++; StringPush_(PSTR_EncryptedLogin1_0, theCmdPtr); if ((theCmdPtr - ((Ptr)gCmdBuffer)) & 0x01) { *theCmdPtr = 0x00; theCmdPtr++; } StringPush_(inUAMArgs->Opt.auth.userName, theCmdPtr); if ((theCmdPtr - ((Ptr)gCmdBuffer)) & 0x01) { *theCmdPtr = 0x00; theCmdPtr++; } theCmdSize = theCmdPtr - ((Ptr)gCmdBuffer); memset(oldPwdT, '\0', kOneWayEncryptedArgSize); memset(newPwdT, '\0', kOneWayEncryptedArgSize); strcpy(oldPwdT, oldPassword); strcpy(newPwdT, newPassword); if ( (UAM_MapCharactersIntoHostSet(oldPwdT, gMSUAMReply.serverExtCharMapTable)) && (UAM_MapCharactersIntoHostSet(newPwdT, gMSUAMReply.serverExtCharMapTable)) ) { UAM_DoublePasswordEncrypt(oldPwdT, newPwdT, theCmdPtr); // //Make a couple last calculations so we can determine the size of the CB. // theCmdSize += (kOneWayEncryptedArgSize * 2); UAMMessage theMessage; memset(&theMessage, '\0', sizeof(UAMMessage)); theMessage.sessionRefNum = inUAMArgs->sessionRefNum; theMessage.commandCode = kSendRequest; theMessage.cmdBuffer = gCmdBuffer; theMessage.cmdBufferSize = theCmdSize; theMessage.replyBuffer = gReplyBuffer; theMessage.replyBufferSize = kMaxAFPCommand; theMessage.completion = NULL; theMessage.contextPtr = NULL; #if GENERATING68K theError = inUAMArgs->callbacks->SendRequestUPP(&theMessage); #else theError = CallUniversalProc( inUAMArgs->callbacks->SendRequestUPP, kSendRequestProcInfo, &theMessage ); #endif } else { theError = afpNTChangePasswordFailed; } } DBGPrintIfOSErr_(theError); // //We're done with the session, so close it out and return any error codes. // UAM_CloseSession(inUAMArgs); return(theError); } // --------------------------------------------------------------------------- // ¥ UAM_ChangePasswordV2() // --------------------------------------------------------------------------- // Change the user's password on the server using Microsoft V2.0. This new // function was required so we can pass the actual password encrypted // over the wire to the server. The server needs the password so it can // update the stored clear text password on the DS (Domain Controller). // // -> inUAMArgs The UAM arguments. // -> inNewPwd The new password requested by the user. // // Returns: An error code or noErr. // // |--------------------------------| // | AFP Command | <- One Byte // |--------------------------------| // | New pwd len | // |--------------------------------| // | UAM String | <- Always PSTR_EncryptedLogin2_0 // / / // |--------------------------------| // | User Name | <- Variable length // / / // |--------------------------------| // | PENCRYPTED_NT_OWF_PASSWORD | <- Variable length // / / // |--------------------------------| // | PSAMPR_ENCRYPTED_USER_PASSWORD | <- Variable length // / / // |--------------------------------| OSStatus UAM_ChangePasswordV2(UAMArgs *inUAMArgs, StringPtr inNewPwd) { OSStatus theError; Str32 theOldPwd, theNewPwd; Ptr theCmdPtr; short theCmdSize; UAMMessage theMessage; char oldPassword[UAM_ENCRYPTEDPWLEN]; char newPassword[UAM_ENCRYPTEDPWLEN]; char newStdPassword[UAM_ENCRYPTEDPWLEN]; SAMPR_ENCRYPTED_USER_PASSWORD theNewEncryptedWithLm; ENCRYPTED_NT_OWF_PASSWORD theOldLmOwfEncryptedWithNewLm; Assert_(inNewPwd != NULL); Assert_(inUAMArgs != NULL); DbgPrint_((DBGBUFF, "Using UAM_ChangePasswordV2();g")); theError = UAM_DSLoginMSUAM(inUAMArgs); if ((theError == noErr) || (theError == afpNTPasswordExpired) || (theError == afpPwdExpiredErr)) { UAM_PStrCopy(inUAMArgs->Opt.auth.password, theOldPwd); UAM_PStrCopy(inNewPwd, theNewPwd); UAM_PStrCopy(inNewPwd, (StringPtr)newStdPassword); if (theOldPwd[0] != 0) UpperString(theOldPwd, true); UpperString(theNewPwd, true); p2cstr(theOldPwd); p2cstr(theNewPwd); p2cstr((StringPtr)newStdPassword); memset(oldPassword, '\0', UAM_ENCRYPTEDPWLEN); memset(newPassword, '\0', UAM_ENCRYPTEDPWLEN); strcpy(oldPassword, (char *)theOldPwd); strcpy(newPassword, (char *)theNewPwd); memset(gCmdBuffer, '\0', sizeof(gCmdBuffer)); theCmdPtr = (Ptr)gCmdBuffer; *theCmdPtr = afpChangePwd; theCmdPtr++; *theCmdPtr = strlen(newPassword); theCmdPtr++; StringPush_(PSTR_EncryptedLogin2_0, theCmdPtr); StringPush_(inUAMArgs->Opt.auth.userName, theCmdPtr); // //Make sure the ptr is aligned on an even boundary at this point // if ((theCmdPtr - (Ptr)gCmdBuffer) % 2) { DbgPrint_((DBGBUFF, "Aligning for even boundary;g")); *theCmdPtr++ = 0x00; } if ( (UAM_MapCharactersIntoHostSet(oldPassword, gMSUAMReply.serverExtCharMapTable)) && (UAM_MapCharactersIntoHostSet(newPassword, gMSUAMReply.serverExtCharMapTable)) && (UAM_MapCharactersIntoHostSet(newStdPassword, gMSUAMReply.serverExtCharMapTable)) ) { memset(&theNewEncryptedWithLm, 0, sizeof(SAMPR_ENCRYPTED_USER_PASSWORD)); memset(&theOldLmOwfEncryptedWithNewLm, 0, sizeof(ENCRYPTED_NT_OWF_PASSWORD)); // //Call the magic function with will encrypt the password(s) for us. // theError = SampEncryptLmPasswords( oldPassword, newPassword, newStdPassword, &theNewEncryptedWithLm, &theOldLmOwfEncryptedWithNewLm); DBGPrintIfOSErr_(theError); if (theError == ERROR_SUCCESS) { // // Copy the ENCRYPTED_NT_OWF_PASSWORD into the command buffer. // DataPush_(&theOldLmOwfEncryptedWithNewLm, sizeof(ENCRYPTED_NT_OWF_PASSWORD), theCmdPtr); // //Copy the SAMPR_ENCRYPTED_USER_PASSWORD into the command buffer. // //BUGBUG: How big to make the buffer??? DataPush_(&theNewEncryptedWithLm, sizeof(SAMPR_ENCRYPTED_USER_PASSWORD), theCmdPtr); // //Make a last minute calculation so we can determine the size of the CB. // theCmdSize = theCmdPtr - (Ptr)(&gCmdBuffer); Assert_(theCmdSize <= kMaxAFPCommand); memset(&theMessage, '\0', sizeof(UAMMessage)); theMessage.sessionRefNum = inUAMArgs->sessionRefNum; theMessage.commandCode = kSendRequest; theMessage.cmdBuffer = gCmdBuffer; theMessage.cmdBufferSize = theCmdSize; theMessage.replyBuffer = gReplyBuffer; theMessage.replyBufferSize = kMaxAFPCommand; theMessage.completion = NULL; theMessage.contextPtr = NULL; #if GENERATING68K theError = inUAMArgs->callbacks->SendRequestUPP(&theMessage); #else theError = CallUniversalProc( inUAMArgs->callbacks->SendRequestUPP, kSendRequestProcInfo, &theMessage ); #endif } } else { theError = afpNTChangePasswordFailed; } } DBGPrintIfOSErr_(theError); // //We're done with the session, so close it out and return any error codes. // UAM_CloseSession(inUAMArgs); return(theError); }