//+----------------------------------------------------------------------- // // Microsoft Windows // // Copyright (c) Microsoft Corporation 1992 - 1999 // // File: changepw.cxx // // Contents: Code for KerbSetPassword and KerbChangePassword // // // History: 24-May-1999 MikeSw Created // //------------------------------------------------------------------------ #include #include #include #include #include #include #include #include #include //+------------------------------------------------------------------------- // // 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; STRING Name; 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; STRING Name; 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, 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 )); }