479 lines
11 KiB
C++
479 lines
11 KiB
C++
|
//+-----------------------------------------------------------------------
|
||
|
//
|
||
|
// Microsoft Windows
|
||
|
//
|
||
|
// Copyright (c) Microsoft Corporation 1992 - 1999
|
||
|
//
|
||
|
// File: changepw.cxx
|
||
|
//
|
||
|
// Contents: Code for KerbSetPassword and KerbChangePassword
|
||
|
//
|
||
|
//
|
||
|
// History: 24-May-1999 MikeSw Created
|
||
|
//
|
||
|
//------------------------------------------------------------------------
|
||
|
|
||
|
#include <nt.h>
|
||
|
#include <ntrtl.h>
|
||
|
#include <nturtl.h>
|
||
|
#include <windows.h>
|
||
|
#include <sspi.h>
|
||
|
#include <ntsecapi.h>
|
||
|
#include <align.h>
|
||
|
#include <dsgetdc.h>
|
||
|
#include <kerbcli.h>
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: KerbChangePasswordUserEx
|
||
|
//
|
||
|
// Synopsis: Changes a users password. If the user is logged on,
|
||
|
// it also updates the in-memory password.
|
||
|
//
|
||
|
// Effects:
|
||
|
//
|
||
|
// Arguments:
|
||
|
//
|
||
|
// Requires:
|
||
|
//
|
||
|
// Returns:
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
|
||
|
NTSTATUS
|
||
|
KerbChangePasswordUser(
|
||
|
IN LPWSTR DomainName,
|
||
|
IN LPWSTR UserName,
|
||
|
IN LPWSTR OldPassword,
|
||
|
IN LPWSTR NewPassword
|
||
|
)
|
||
|
{
|
||
|
NTSTATUS Status;
|
||
|
BOOLEAN WasEnabled;
|
||
|
STRING Name;
|
||
|
ULONG Dummy;
|
||
|
HANDLE LogonHandle = NULL;
|
||
|
ULONG PackageId;
|
||
|
PVOID Response = NULL ;
|
||
|
ULONG ResponseSize;
|
||
|
NTSTATUS SubStatus;
|
||
|
PKERB_CHANGEPASSWORD_REQUEST ChangeRequest = NULL;
|
||
|
ULONG ChangeSize;
|
||
|
UNICODE_STRING User,Domain,OldPass,NewPass;
|
||
|
|
||
|
Status = LsaConnectUntrusted(
|
||
|
&LogonHandle
|
||
|
);
|
||
|
|
||
|
if (!NT_SUCCESS(Status))
|
||
|
{
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
RtlInitString(
|
||
|
&Name,
|
||
|
MICROSOFT_KERBEROS_NAME_A
|
||
|
);
|
||
|
|
||
|
Status = LsaLookupAuthenticationPackage(
|
||
|
LogonHandle,
|
||
|
&Name,
|
||
|
&PackageId
|
||
|
);
|
||
|
if (!NT_SUCCESS(Status))
|
||
|
{
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
RtlInitUnicodeString(
|
||
|
&User,
|
||
|
UserName
|
||
|
);
|
||
|
RtlInitUnicodeString(
|
||
|
&Domain,
|
||
|
DomainName
|
||
|
);
|
||
|
RtlInitUnicodeString(
|
||
|
&OldPass,
|
||
|
OldPassword
|
||
|
);
|
||
|
RtlInitUnicodeString(
|
||
|
&NewPass,
|
||
|
NewPassword
|
||
|
);
|
||
|
|
||
|
if ( OldPass.Length > (127*sizeof(WCHAR)) ||
|
||
|
NewPass.Length > (127*sizeof(WCHAR)) )
|
||
|
{
|
||
|
Status = STATUS_NAME_TOO_LONG;
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
ChangeSize = ROUND_UP_COUNT(sizeof(KERB_CHANGEPASSWORD_REQUEST),4)+
|
||
|
User.Length +
|
||
|
Domain.Length +
|
||
|
OldPass.Length +
|
||
|
NewPass.Length ;
|
||
|
ChangeRequest = (PKERB_CHANGEPASSWORD_REQUEST) LocalAlloc(LMEM_ZEROINIT, ChangeSize );
|
||
|
if (NULL == ChangeRequest)
|
||
|
{
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
ChangeRequest->MessageType = KerbChangePasswordMessage;
|
||
|
|
||
|
ChangeRequest->AccountName = User;
|
||
|
ChangeRequest->AccountName.Buffer = (LPWSTR) ROUND_UP_POINTER(sizeof(KERB_CHANGEPASSWORD_REQUEST) + (PBYTE) ChangeRequest,4);
|
||
|
|
||
|
RtlCopyMemory(
|
||
|
ChangeRequest->AccountName.Buffer,
|
||
|
User.Buffer,
|
||
|
User.Length
|
||
|
);
|
||
|
|
||
|
ChangeRequest->DomainName = Domain;
|
||
|
ChangeRequest->DomainName.Buffer = ChangeRequest->AccountName.Buffer + ChangeRequest->AccountName.Length / sizeof(WCHAR);
|
||
|
|
||
|
RtlCopyMemory(
|
||
|
ChangeRequest->DomainName.Buffer,
|
||
|
Domain.Buffer,
|
||
|
Domain.Length
|
||
|
);
|
||
|
|
||
|
ChangeRequest->OldPassword = OldPass;
|
||
|
ChangeRequest->OldPassword.Buffer = ChangeRequest->DomainName.Buffer + ChangeRequest->DomainName.Length / sizeof(WCHAR);
|
||
|
|
||
|
RtlCopyMemory(
|
||
|
ChangeRequest->OldPassword.Buffer,
|
||
|
OldPass.Buffer,
|
||
|
OldPass.Length
|
||
|
);
|
||
|
|
||
|
ChangeRequest->NewPassword = NewPass;
|
||
|
ChangeRequest->NewPassword.Buffer = ChangeRequest->OldPassword.Buffer + ChangeRequest->OldPassword.Length / sizeof(WCHAR);
|
||
|
|
||
|
RtlCopyMemory(
|
||
|
ChangeRequest->NewPassword.Buffer,
|
||
|
NewPass.Buffer,
|
||
|
NewPass.Length
|
||
|
);
|
||
|
|
||
|
|
||
|
//
|
||
|
// We are running as the caller, so state we are impersonating
|
||
|
//
|
||
|
|
||
|
ChangeRequest->Impersonating = TRUE;
|
||
|
|
||
|
Status = LsaCallAuthenticationPackage(
|
||
|
LogonHandle,
|
||
|
PackageId,
|
||
|
ChangeRequest,
|
||
|
ChangeSize,
|
||
|
&Response,
|
||
|
&ResponseSize,
|
||
|
&SubStatus
|
||
|
);
|
||
|
if (!NT_SUCCESS(Status) || !NT_SUCCESS(SubStatus))
|
||
|
{
|
||
|
if (NT_SUCCESS(Status))
|
||
|
{
|
||
|
Status = SubStatus;
|
||
|
}
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
Cleanup:
|
||
|
|
||
|
if (LogonHandle != NULL)
|
||
|
{
|
||
|
LsaDeregisterLogonProcess(LogonHandle);
|
||
|
}
|
||
|
|
||
|
if (Response != NULL)
|
||
|
{
|
||
|
LsaFreeReturnBuffer(Response);
|
||
|
}
|
||
|
|
||
|
if (ChangeRequest != NULL)
|
||
|
{
|
||
|
LocalFree(ChangeRequest);
|
||
|
}
|
||
|
return(Status);
|
||
|
}
|
||
|
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: KerbSetPasswordUserEx
|
||
|
//
|
||
|
// Synopsis: Sets a password for a user in the specified domain
|
||
|
//
|
||
|
// Effects:
|
||
|
//
|
||
|
// Arguments:
|
||
|
//
|
||
|
// Requires:
|
||
|
//
|
||
|
// Returns:
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
|
||
|
NTSTATUS
|
||
|
KerbSetPasswordUserEx(
|
||
|
IN LPWSTR DomainName,
|
||
|
IN LPWSTR UserName,
|
||
|
IN LPWSTR NewPassword,
|
||
|
IN OPTIONAL PCredHandle CredentialsHandle,
|
||
|
IN OPTIONAL LPWSTR KdcAddress
|
||
|
)
|
||
|
{
|
||
|
NTSTATUS Status;
|
||
|
BOOLEAN WasEnabled;
|
||
|
STRING Name;
|
||
|
ULONG Dummy;
|
||
|
HANDLE LogonHandle = NULL;
|
||
|
ULONG PackageId;
|
||
|
PVOID Response = NULL;
|
||
|
ULONG ResponseSize;
|
||
|
KERB_PROTOCOL_MESSAGE_TYPE MessageType = KerbSetPasswordMessage;
|
||
|
NTSTATUS SubStatus;
|
||
|
PKERB_SETPASSWORD_EX_REQUEST SetRequest = NULL;
|
||
|
ULONG ChangeSize;
|
||
|
UNICODE_STRING User,Domain,OldPass,NewPass, KdcAddr, ClientName, ClientRealm;
|
||
|
|
||
|
// If you supply a KdcAddress, you must supply name type
|
||
|
if (ARGUMENT_PRESENT(KdcAddress))
|
||
|
{
|
||
|
MessageType = KerbSetPasswordExMessage;
|
||
|
|
||
|
RtlInitUnicodeString(
|
||
|
&KdcAddr,
|
||
|
KdcAddress
|
||
|
);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
RtlInitUnicodeString(
|
||
|
&KdcAddr,
|
||
|
NULL
|
||
|
);
|
||
|
}
|
||
|
|
||
|
Status = LsaConnectUntrusted(
|
||
|
&LogonHandle
|
||
|
);
|
||
|
|
||
|
if (!NT_SUCCESS(Status))
|
||
|
{
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
RtlInitString(
|
||
|
&Name,
|
||
|
MICROSOFT_KERBEROS_NAME_A
|
||
|
);
|
||
|
Status = LsaLookupAuthenticationPackage(
|
||
|
LogonHandle,
|
||
|
&Name,
|
||
|
&PackageId
|
||
|
);
|
||
|
if (!NT_SUCCESS(Status))
|
||
|
{
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
RtlInitUnicodeString(
|
||
|
&User,
|
||
|
UserName
|
||
|
);
|
||
|
RtlInitUnicodeString(
|
||
|
&Domain,
|
||
|
DomainName
|
||
|
);
|
||
|
RtlInitUnicodeString(
|
||
|
&NewPass,
|
||
|
NewPassword
|
||
|
);
|
||
|
|
||
|
// These aren't used here (yet)
|
||
|
RtlInitUnicodeString(
|
||
|
&ClientName,
|
||
|
NULL
|
||
|
);
|
||
|
|
||
|
RtlInitUnicodeString(
|
||
|
&ClientRealm,
|
||
|
NULL
|
||
|
);
|
||
|
|
||
|
if ( NewPass.Length > (127 * sizeof(WCHAR)) )
|
||
|
{
|
||
|
Status = STATUS_NAME_TOO_LONG;
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
ChangeSize = ROUND_UP_COUNT(sizeof(KERB_SETPASSWORD_EX_REQUEST),4)+
|
||
|
User.Length +
|
||
|
Domain.Length +
|
||
|
NewPass.Length +
|
||
|
KdcAddr.Length +
|
||
|
ClientName.Length +
|
||
|
ClientRealm.Length;
|
||
|
|
||
|
SetRequest = (PKERB_SETPASSWORD_EX_REQUEST) LocalAlloc(LMEM_ZEROINIT, ChangeSize );
|
||
|
if (NULL == SetRequest)
|
||
|
{
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
SetRequest->MessageType = MessageType;
|
||
|
SetRequest->KdcAddressType = DS_UNKNOWN_ADDRESS_TYPE;
|
||
|
SetRequest->AccountRealm = Domain;
|
||
|
SetRequest->AccountRealm.Buffer = (LPWSTR) ROUND_UP_POINTER(sizeof(KERB_SETPASSWORD_EX_REQUEST) + (PBYTE) SetRequest,4);
|
||
|
|
||
|
RtlCopyMemory(
|
||
|
SetRequest->AccountRealm.Buffer,
|
||
|
Domain.Buffer,
|
||
|
Domain.Length
|
||
|
);
|
||
|
|
||
|
SetRequest->AccountName = User;
|
||
|
SetRequest->AccountName.Buffer = SetRequest->AccountRealm.Buffer + SetRequest->AccountRealm.Length / sizeof(WCHAR);
|
||
|
|
||
|
RtlCopyMemory(
|
||
|
SetRequest->AccountName.Buffer,
|
||
|
User.Buffer,
|
||
|
User.Length
|
||
|
);
|
||
|
|
||
|
|
||
|
SetRequest->Password = NewPass;
|
||
|
SetRequest->Password.Buffer = SetRequest->AccountName.Buffer + SetRequest->AccountName.Length / sizeof(WCHAR);
|
||
|
|
||
|
RtlCopyMemory(
|
||
|
SetRequest->Password.Buffer,
|
||
|
NewPass.Buffer,
|
||
|
NewPass.Length
|
||
|
);
|
||
|
|
||
|
// Not yet implemented
|
||
|
SetRequest->ClientRealm = ClientRealm;
|
||
|
SetRequest->ClientRealm.Buffer = SetRequest->Password.Buffer + SetRequest->Password.Length / sizeof(WCHAR);
|
||
|
|
||
|
RtlCopyMemory(
|
||
|
SetRequest->ClientRealm.Buffer,
|
||
|
ClientRealm.Buffer,
|
||
|
ClientRealm.Length
|
||
|
);
|
||
|
|
||
|
SetRequest->ClientName = ClientName;
|
||
|
SetRequest->ClientName.Buffer = SetRequest->ClientRealm.Buffer + SetRequest->ClientRealm.Length / sizeof(WCHAR);
|
||
|
|
||
|
RtlCopyMemory(
|
||
|
SetRequest->ClientName.Buffer,
|
||
|
ClientName.Buffer,
|
||
|
ClientName.Length
|
||
|
);
|
||
|
//
|
||
|
|
||
|
SetRequest->KdcAddress = KdcAddr;
|
||
|
SetRequest->KdcAddress.Buffer = SetRequest->ClientRealm.Buffer + SetRequest->ClientRealm.Length / sizeof(WCHAR);
|
||
|
|
||
|
RtlCopyMemory(
|
||
|
SetRequest->KdcAddress.Buffer,
|
||
|
KdcAddr.Buffer,
|
||
|
KdcAddr.Length
|
||
|
);
|
||
|
|
||
|
if (ARGUMENT_PRESENT(CredentialsHandle))
|
||
|
{
|
||
|
SetRequest->CredentialsHandle = *CredentialsHandle;
|
||
|
SetRequest->Flags |= KERB_SETPASS_USE_CREDHANDLE;
|
||
|
}
|
||
|
|
||
|
Status = LsaCallAuthenticationPackage(
|
||
|
LogonHandle,
|
||
|
PackageId,
|
||
|
SetRequest,
|
||
|
ChangeSize,
|
||
|
&Response,
|
||
|
&ResponseSize,
|
||
|
&SubStatus
|
||
|
);
|
||
|
if (!NT_SUCCESS(Status) || !NT_SUCCESS(SubStatus))
|
||
|
{
|
||
|
if (NT_SUCCESS(Status))
|
||
|
{
|
||
|
Status = SubStatus;
|
||
|
}
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
Cleanup:
|
||
|
|
||
|
if (LogonHandle != NULL)
|
||
|
{
|
||
|
LsaDeregisterLogonProcess(LogonHandle);
|
||
|
}
|
||
|
|
||
|
if (Response != NULL)
|
||
|
{
|
||
|
LsaFreeReturnBuffer(Response);
|
||
|
}
|
||
|
|
||
|
if (SetRequest != NULL)
|
||
|
{
|
||
|
LocalFree(SetRequest);
|
||
|
}
|
||
|
return(Status);
|
||
|
}
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: KerbSetPasswordUser
|
||
|
//
|
||
|
// Synopsis: Sets a password for a user in the specified domain
|
||
|
//
|
||
|
// Effects:
|
||
|
//
|
||
|
// Arguments:
|
||
|
//
|
||
|
// Requires:
|
||
|
//
|
||
|
// Returns:
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
NTSTATUS
|
||
|
KerbSetPasswordUser(
|
||
|
IN LPWSTR DomainName,
|
||
|
IN LPWSTR UserName,
|
||
|
IN LPWSTR NewPassword,
|
||
|
IN OPTIONAL PCredHandle CredentialsHandle
|
||
|
)
|
||
|
{
|
||
|
|
||
|
return(KerbSetPasswordUserEx(
|
||
|
DomainName,
|
||
|
UserName,
|
||
|
NewPassword,
|
||
|
CredentialsHandle,
|
||
|
NULL
|
||
|
));
|
||
|
}
|
||
|
|