2025-04-27 07:49:33 -04:00

1 line
18 KiB
C

// ===========================================================================
// UAMDSNetwork.c © 1998 Microsoft Corp. All rights reserved.
// ===========================================================================
// DS Networking functions for use by Microsoft User Authentication Method.
//
// ===========================================================================
#include <Errors.h>
#include <AppleTalk.h>
#include <String.h>
#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);
}