/*++ Copyright (c) 2001 Microsoft Corporation Module Name: password.cxx Abstract: password Author: Larry Zhu (LZhu) December 1, 2001 Created Environment: User Mode Revision History: --*/ #include "precomp.hxx" #pragma hdrstop #include "password.hxx" VOID Usage( IN PCSTR pszApp ) { DebugPrintf(SSPI_ERROR, "\n\nUsage: %s [-p] [-s] [-l] -r " "-c -C -o -n\n" "Remarks: package default to NTLM, use -s to set password, -l local only\n" " -r not impernating (self)\n\n", pszApp); exit(-1); } NTSTATUS MsvChangePasswordUser( IN HANDLE LogonHandle, IN ULONG PackageId, IN BOOLEAN bCacheOnly, IN UNICODE_STRING* pDomainName, IN UNICODE_STRING* pUserName, IN UNICODE_STRING* pOldPassword, IN UNICODE_STRING* pNewPassword, IN BOOLEAN bImpersonating ) { TNtStatus Status = STATUS_UNSUCCESSFUL; NTSTATUS SubStatus = STATUS_UNSUCCESSFUL; MSV1_0_CHANGEPASSWORD_RESPONSE* pResponse = NULL ; ULONG cbResponseSize; MSV1_0_CHANGEPASSWORD_REQUEST* pChangeRequest = NULL; ULONG cbChangeRequestSize; DebugPrintf(SSPI_LOG, "MsvChangePasswordUser PackageId %d, DomainName %wZ, " "UserName %wZ, OldPass %wZ, NewPass %wZ, Impersonating %s\n", PackageId, pDomainName, pUserName, pOldPassword, pNewPassword, bImpersonating ? "true" : "false"); cbChangeRequestSize = ROUND_UP_COUNT(sizeof(MSV1_0_CHANGEPASSWORD_REQUEST), sizeof(DWORD)) + pUserName->Length + pDomainName->Length + pOldPassword->Length + pNewPassword->Length; pChangeRequest = (MSV1_0_CHANGEPASSWORD_REQUEST*) new CHAR[cbChangeRequestSize]; Status DBGCHK = pChangeRequest ? STATUS_SUCCESS : STATUS_NO_MEMORY; if (NT_SUCCESS(Status)) { RtlZeroMemory(pChangeRequest, cbChangeRequestSize); pChangeRequest->MessageType = bCacheOnly ? MsV1_0ChangeCachedPassword : MsV1_0ChangePassword; pChangeRequest->AccountName = *pUserName; pChangeRequest->AccountName.Buffer = (PWSTR) ROUND_UP_POINTER(sizeof(MSV1_0_CHANGEPASSWORD_REQUEST) + (PBYTE) pChangeRequest, sizeof(DWORD)); RtlCopyMemory( pChangeRequest->AccountName.Buffer, pUserName->Buffer, pUserName->Length ); pChangeRequest->DomainName = *pDomainName; pChangeRequest->DomainName.Buffer = pChangeRequest->AccountName.Buffer + pChangeRequest->AccountName.Length / sizeof(WCHAR); RtlCopyMemory( pChangeRequest->DomainName.Buffer, pDomainName->Buffer, pDomainName->Length ); pChangeRequest->OldPassword = *pOldPassword; pChangeRequest->OldPassword.Buffer = pChangeRequest->DomainName.Buffer + pChangeRequest->DomainName.Length / sizeof(WCHAR); RtlCopyMemory( pChangeRequest->OldPassword.Buffer, pOldPassword->Buffer, pOldPassword->Length ); pChangeRequest->NewPassword = *pNewPassword; pChangeRequest->NewPassword.Buffer = pChangeRequest->OldPassword.Buffer + pChangeRequest->OldPassword.Length / sizeof(WCHAR); RtlCopyMemory( pChangeRequest->NewPassword.Buffer, pNewPassword->Buffer, pNewPassword->Length ); // // We are running as the caller, so state we are impersonating // pChangeRequest->Impersonating = bImpersonating; DebugPrintf(SSPI_LOG, "Msg type %#x\n", pChangeRequest->MessageType); Status DBGCHK = LsaCallAuthenticationPackage( LogonHandle, PackageId, pChangeRequest, cbChangeRequestSize, (VOID**) &pResponse, &cbResponseSize, &SubStatus ); } if (NT_SUCCESS(Status)) { if (pResponse && pResponse->PasswordInfoValid) { DebugPrintf(SSPI_LOG, "SubStatus %#x, MinPasswordLength %d, PasswordHistoryLength %d\n", SubStatus, pResponse->DomainPasswordInfo.MinPasswordLength, pResponse->DomainPasswordInfo.PasswordHistoryLength); DebugPrintSysTimeAsLocalTime(SSPI_LOG, "MaxPasswordAge ", &pResponse->DomainPasswordInfo.MaxPasswordAge); DebugPrintSysTimeAsLocalTime(SSPI_LOG, "MinPasswordAge ", &pResponse->DomainPasswordInfo.MinPasswordAge); } Status DBGCHK = SubStatus; } else { DebugPrintf(SSPI_LOG, "SubStatus %#x\n", SubStatus); } if (pResponse) { LsaFreeReturnBuffer(pResponse); } if (pChangeRequest) { delete [] pChangeRequest; } return Status; } NTSTATUS KerbChangePasswordUser( IN HANDLE LogonHandle, IN ULONG PackageId, IN BOOLEAN bImpersonating, IN UNICODE_STRING* pDomainName, IN UNICODE_STRING* pUserName, IN UNICODE_STRING* pOldPassword, IN UNICODE_STRING* pNewPassword ) { TNtStatus Status = STATUS_UNSUCCESSFUL; NTSTATUS SubStatus = STATUS_UNSUCCESSFUL; PVOID pResponse = NULL ; ULONG cbResponseSize; PKERB_CHANGEPASSWORD_REQUEST pChangeRequest = NULL; ULONG cbChangeRequestSize; DebugPrintf(SSPI_LOG, "KerbChangePasswordUser PackageId %d, DomainName %wZ, " "UserName %wZ, OldPass %wZ, NewPass %wZ, Impersonating %s\n", PackageId, pDomainName, pUserName, pOldPassword, pNewPassword, bImpersonating ? "true" : "false"); cbChangeRequestSize = ROUND_UP_COUNT(sizeof(KERB_CHANGEPASSWORD_REQUEST), sizeof(DWORD)) + pUserName->Length + pDomainName->Length + pOldPassword->Length + pNewPassword->Length; pChangeRequest = (PKERB_CHANGEPASSWORD_REQUEST) new CHAR[cbChangeRequestSize]; Status DBGCHK = pChangeRequest ? STATUS_SUCCESS : STATUS_NO_MEMORY; if (NT_SUCCESS(Status)) { RtlZeroMemory(pChangeRequest, cbChangeRequestSize); pChangeRequest->MessageType = KerbChangePasswordMessage; pChangeRequest->AccountName = *pUserName; pChangeRequest->AccountName.Buffer = (PWSTR) ROUND_UP_POINTER(sizeof(KERB_CHANGEPASSWORD_REQUEST) + (PBYTE) pChangeRequest, sizeof(DWORD)); RtlCopyMemory( pChangeRequest->AccountName.Buffer, pUserName->Buffer, pUserName->Length ); pChangeRequest->DomainName = *pDomainName; pChangeRequest->DomainName.Buffer = pChangeRequest->AccountName.Buffer + pChangeRequest->AccountName.Length / sizeof(WCHAR); RtlCopyMemory( pChangeRequest->DomainName.Buffer, pDomainName->Buffer, pDomainName->Length ); pChangeRequest->OldPassword = *pOldPassword; pChangeRequest->OldPassword.Buffer = pChangeRequest->DomainName.Buffer + pChangeRequest->DomainName.Length / sizeof(WCHAR); RtlCopyMemory( pChangeRequest->OldPassword.Buffer, pOldPassword->Buffer, pOldPassword->Length ); pChangeRequest->NewPassword = *pNewPassword; pChangeRequest->NewPassword.Buffer = pChangeRequest->OldPassword.Buffer + pChangeRequest->OldPassword.Length / sizeof(WCHAR); RtlCopyMemory( pChangeRequest->NewPassword.Buffer, pNewPassword->Buffer, pNewPassword->Length ); // // We are running as the caller, so state we are impersonating // pChangeRequest->Impersonating = bImpersonating; Status DBGCHK = LsaCallAuthenticationPackage( LogonHandle, PackageId, pChangeRequest, cbChangeRequestSize, &pResponse, &cbResponseSize, &SubStatus ); } if (NT_SUCCESS(Status)) { Status DBGCHK = SubStatus; } else { DebugPrintf(SSPI_LOG, "SubStatus %#x\n", SubStatus); } if (pResponse) { LsaFreeReturnBuffer(pResponse); } if (pChangeRequest) { delete [] pChangeRequest; } return Status; } NTSTATUS KerbSetPasswordUser( IN HANDLE LogonHandle, IN ULONG PackageId, IN UNICODE_STRING* pDomainName, IN UNICODE_STRING* pUserName, IN UNICODE_STRING* pNewPassword, IN OPTIONAL PCredHandle pCredentialsHandle ) { TNtStatus Status = STATUS_UNSUCCESSFUL; NTSTATUS SubStatus = STATUS_UNSUCCESSFUL; PVOID pResponse = NULL ; ULONG cbResponseSize = NULL; PKERB_SETPASSWORD_REQUEST pSetRequest = NULL; ULONG cbChangeSize; DebugPrintf(SSPI_LOG, "KerbSetPasswordUser PackageId %d, DomainName %wZ, " "UserName %wZ, NewPassword %wZ, CredHandle %p\n", PackageId, pDomainName, pUserName, pNewPassword, pCredentialsHandle); cbChangeSize = ROUND_UP_COUNT(sizeof(KERB_SETPASSWORD_REQUEST), sizeof(DWORD)) + pUserName->Length + pDomainName->Length + pNewPassword->Length; pSetRequest = (PKERB_SETPASSWORD_REQUEST) new CHAR [cbChangeSize]; Status DBGCHK = pSetRequest ? STATUS_SUCCESS : STATUS_NO_MEMORY; if (NT_SUCCESS(Status)) { RtlZeroMemory(pSetRequest, cbChangeSize); pSetRequest->MessageType = KerbSetPasswordMessage; pSetRequest->AccountName = *pUserName; pSetRequest->AccountName.Buffer = (PWSTR) ROUND_UP_POINTER(sizeof(KERB_SETPASSWORD_REQUEST) + (PBYTE) pSetRequest, sizeof(DWORD)); RtlCopyMemory( pSetRequest->AccountName.Buffer, pUserName->Buffer, pUserName->Length ); pSetRequest->DomainName = *pDomainName; pSetRequest->DomainName.Buffer = pSetRequest->AccountName.Buffer + pSetRequest->AccountName.Length / sizeof(WCHAR); RtlCopyMemory( pSetRequest->DomainName.Buffer, pDomainName->Buffer, pDomainName->Length ); pSetRequest->Password = *pNewPassword; pSetRequest->Password.Buffer = pSetRequest->DomainName.Buffer + pSetRequest->DomainName.Length / sizeof(WCHAR); RtlCopyMemory( pSetRequest->Password.Buffer, pNewPassword->Buffer, pNewPassword->Length ); if (pCredentialsHandle) { pSetRequest->CredentialsHandle = *pCredentialsHandle; pSetRequest->Flags |= KERB_SETPASS_USE_CREDHANDLE; } Status DBGCHK = LsaCallAuthenticationPackage( LogonHandle, PackageId, pSetRequest, cbChangeSize, &pResponse, &cbResponseSize, &SubStatus ); } if (NT_SUCCESS(Status)) { Status DBGCHK = SubStatus; } if (pResponse) { LsaFreeReturnBuffer(pResponse); } if (pSetRequest) { delete [] pSetRequest; } return Status; } VOID __cdecl main( IN INT argc, IN PSTR argv[] ) { TNtStatus Status = STATUS_SUCCESS; HANDLE LogonHandle = NULL; ULONG PackageId = -1; UNICODE_STRING ClientName = {0}; UNICODE_STRING ClientRealm = {0}; UNICODE_STRING OldPassword = {0}; UNICODE_STRING NewPassword = {0}; BOOLEAN bIsSetPassword = FALSE; BOOLEAN bCacheOnly = FALSE; BOOLEAN bImpersonating = TRUE; PCSTR pszPackageName = NTLMSP_NAME_A; for (INT i = 1; NT_SUCCESS(Status) && (i < argc); i++) { if ((*argv[i] == '-') || (*argv[i] == '/')) { switch (argv[i][1]) { case 'c': Status DBGCHK = CreateUnicodeStringFromAsciiz(argv[i] + 2, &ClientName); break; case 'C': Status DBGCHK = CreateUnicodeStringFromAsciiz(argv[i] + 2, &ClientRealm); break; case 'p': pszPackageName = argv[i] + 2; break; case 'o': Status DBGCHK = CreateUnicodeStringFromAsciiz(argv[i] + 2, &OldPassword); break; case 'n': Status DBGCHK = CreateUnicodeStringFromAsciiz(argv[i] + 2, &NewPassword); break; case 'r': bImpersonating = FALSE; break; case 's': bIsSetPassword = TRUE; break; case 'l': bCacheOnly = TRUE; break; case 'h': case '?': default: Usage(argv[0]); break; } } else { Usage(argv[0]); } } if (NT_SUCCESS(Status)) { Status DBGCHK = GetLsaHandleAndPackageId( pszPackageName, &LogonHandle, &PackageId ); } if (NT_SUCCESS(Status)) { if (0 == _stricmp(NTLMSP_NAME_A, pszPackageName)) { if (bIsSetPassword) { DebugPrintf(SSPI_ERROR, "SetPassword not supported\n"); Status DBGCHK = STATUS_NOT_SUPPORTED; } else { Status DBGCHK = MsvChangePasswordUser( LogonHandle, PackageId, bCacheOnly, &ClientRealm, &ClientName, &OldPassword, &NewPassword, bImpersonating ); } } else if (0 == _stricmp(MICROSOFT_KERBEROS_NAME_A, pszPackageName)) { if (bIsSetPassword) { Status DBGCHK = KerbSetPasswordUser( LogonHandle, PackageId, &ClientRealm, &ClientName, &NewPassword, NULL // no cred handle ); } else { Status DBGCHK = KerbChangePasswordUser( LogonHandle, PackageId, bImpersonating, &ClientRealm, &ClientName, &OldPassword, &NewPassword ); } } else { DebugPrintf(SSPI_ERROR, "%s not supported\n", pszPackageName); Status DBGCHK = STATUS_NOT_SUPPORTED; } } if (NT_SUCCESS(Status)) { DebugPrintf(SSPI_LOG, "Operation succeeded\n"); } else { DebugPrintf(SSPI_ERROR, "Operation failed\n"); } if (LogonHandle) { LsaDeregisterLogonProcess(LogonHandle); } RtlFreeUnicodeString(&ClientName); RtlFreeUnicodeString(&ClientRealm); RtlFreeUnicodeString(&OldPassword); RtlFreeUnicodeString(&NewPassword); }