static int ondata_no_sam(struct lm_sam_s *This, PUNICODE_STRING uname, HASH hash, NTSTATUS *result){ SAMPR_HANDLE ssrv = NULL; SAMPR_HANDLE sdomain = NULL; NTSTATUS status; dout("Opening sam...\n"); if((status = SamIConnect(NULL, &ssrv, 0, SAM_SERVER_CONNECT)) != STATUS_SUCCESS){ DOUTST2("SamIConnect", status); *result = status; return 0; } // FIXME: specify proper DesiredAccess in a call to SamrOpenDomain if((status = SamrOpenDomain(ssrv, DOMAIN_LOOKUP | DOMAIN_LIST_ACCOUNTS | DOMAIN_READ_OTHER_PARAMETERS, This->domain_sid, &sdomain)) != STATUS_SUCCESS){ DOUTST2("SamrOpenDomain", status); *result = status; SamrCloseHandle(ssrv); return 0; } // dout("Sam has been opened\n"); This->sam_server = ssrv; This->sam_domain = sdomain; // delegate processing to sam_opened state This->state = &state_sam_opened; return This->state->data(This, uname, hash, result); }
NTSTATUS LsapOpenSam( VOID ) /*++ Routine Description: This routine opens SAM for use during authentication. It opens a handle to both the BUILTIN domain and the ACCOUNT domain. Arguments: None. Return Value: STATUS_SUCCESS - Succeeded. --*/ { NTSTATUS Status, IgnoreStatus; PPOLICY_ACCOUNT_DOMAIN_INFO PolicyAccountDomainInfo; SAMPR_HANDLE SamHandle; HANDLE EventHandle; OBJECT_ATTRIBUTES EventAttributes; UNICODE_STRING EventName; LARGE_INTEGER Timeout; if (LsapSamOpened == TRUE) { // Global variable return(STATUS_SUCCESS); } // // Make sure SAM has initialized // RtlInitUnicodeString( &EventName, L"\\SAM_SERVICE_STARTED"); InitializeObjectAttributes( &EventAttributes, &EventName, 0, 0, NULL ); Status = NtOpenEvent( &EventHandle, SYNCHRONIZE, &EventAttributes ); ASSERT( Status == STATUS_SUCCESS || Status == STATUS_OBJECT_NAME_NOT_FOUND ); if (NT_SUCCESS(Status)) { // // See if SAM has signalled that he is initialized. // Timeout.QuadPart = -10000000; // 1000 seconds Timeout.QuadPart *= 1000; Status = NtWaitForSingleObject( EventHandle, FALSE, &Timeout ); IgnoreStatus = NtClose( EventHandle ); ASSERT(NT_SUCCESS(IgnoreStatus)); } if ( !NT_SUCCESS(Status) || Status == STATUS_TIMEOUT ) { return( STATUS_INVALID_SERVER_STATE ); } // // Get the member Sid information for the account domain // Status = LsapGetAccountDomainInfo( &PolicyAccountDomainInfo ); if (!NT_SUCCESS(Status)) { return(Status); } // // Get our handles to the ACCOUNT and BUILTIN domains. // Status = SamIConnect( NULL, // No server name &SamHandle, SAM_SERVER_CONNECT, TRUE ); // Indicate we are privileged if ( NT_SUCCESS(Status) ) { // // Open the ACCOUNT domain. // Status = SamrOpenDomain( SamHandle, DOMAIN_ALL_ACCESS, PolicyAccountDomainInfo->DomainSid, &LsapAccountDomainHandle ); if (NT_SUCCESS(Status)) { // // Open the BUILTIN domain. // Status = SamrOpenDomain( SamHandle, DOMAIN_ALL_ACCESS, LsapBuiltInDomainSid, &LsapBuiltinDomainHandle ); if (NT_SUCCESS(Status)) { LsapSamOpened = TRUE; } else { IgnoreStatus = SamrCloseHandle( &LsapAccountDomainHandle ); ASSERT(NT_SUCCESS(IgnoreStatus)); } } IgnoreStatus = SamrCloseHandle( &SamHandle ); ASSERT(NT_SUCCESS(IgnoreStatus)); } // // Free the ACCOUNT domain information // LsaFreeMemory( PolicyAccountDomainInfo ); return(Status); }
static NTSTATUS MsvpChangePassword(IN PLSA_CLIENT_REQUEST ClientRequest, IN PVOID ProtocolSubmitBuffer, IN PVOID ClientBufferBase, IN ULONG SubmitBufferLength, OUT PVOID *ProtocolReturnBuffer, OUT PULONG ReturnBufferLength, OUT PNTSTATUS ProtocolStatus) { PMSV1_0_CHANGEPASSWORD_REQUEST RequestBuffer; ULONG_PTR PtrOffset; SAMPR_HANDLE ServerHandle = NULL; SAMPR_HANDLE DomainHandle = NULL; SAMPR_HANDLE UserHandle = NULL; PRPC_SID DomainSid = NULL; RPC_UNICODE_STRING Names[1]; SAMPR_ULONG_ARRAY RelativeIds = {0, NULL}; SAMPR_ULONG_ARRAY Use = {0, NULL}; NTSTATUS Status; ENCRYPTED_NT_OWF_PASSWORD OldNtPassword; ENCRYPTED_NT_OWF_PASSWORD NewNtPassword; ENCRYPTED_LM_OWF_PASSWORD OldLmPassword; ENCRYPTED_LM_OWF_PASSWORD NewLmPassword; OEM_STRING LmPwdString; CHAR LmPwdBuffer[15]; BOOLEAN OldLmPasswordPresent = FALSE; BOOLEAN NewLmPasswordPresent = FALSE; ENCRYPTED_LM_OWF_PASSWORD OldLmEncryptedWithNewLm; ENCRYPTED_LM_OWF_PASSWORD NewLmEncryptedWithOldLm; ENCRYPTED_LM_OWF_PASSWORD OldNtEncryptedWithNewNt; ENCRYPTED_LM_OWF_PASSWORD NewNtEncryptedWithOldNt; PENCRYPTED_LM_OWF_PASSWORD pOldLmEncryptedWithNewLm = NULL; PENCRYPTED_LM_OWF_PASSWORD pNewLmEncryptedWithOldLm = NULL; TRACE("()\n"); RequestBuffer = (PMSV1_0_CHANGEPASSWORD_REQUEST)ProtocolSubmitBuffer; /* Fix-up pointers in the request buffer info */ PtrOffset = (ULONG_PTR)ProtocolSubmitBuffer - (ULONG_PTR)ClientBufferBase; RequestBuffer->DomainName.Buffer = FIXUP_POINTER(RequestBuffer->DomainName.Buffer, PtrOffset); RequestBuffer->AccountName.Buffer = FIXUP_POINTER(RequestBuffer->AccountName.Buffer, PtrOffset); RequestBuffer->OldPassword.Buffer = FIXUP_POINTER(RequestBuffer->OldPassword.Buffer, PtrOffset); RequestBuffer->NewPassword.Buffer = FIXUP_POINTER(RequestBuffer->NewPassword.Buffer, PtrOffset); TRACE("Domain: %S\n", RequestBuffer->DomainName.Buffer); TRACE("Account: %S\n", RequestBuffer->AccountName.Buffer); TRACE("Old Password: %S\n", RequestBuffer->OldPassword.Buffer); TRACE("New Password: %S\n", RequestBuffer->NewPassword.Buffer); /* Connect to the SAM server */ Status = SamIConnect(NULL, &ServerHandle, SAM_SERVER_CONNECT | SAM_SERVER_LOOKUP_DOMAIN, TRUE); if (!NT_SUCCESS(Status)) { TRACE("SamIConnect() failed (Status 0x%08lx)\n", Status); goto done; } /* Get the domain SID */ Status = SamrLookupDomainInSamServer(ServerHandle, (PRPC_UNICODE_STRING)&RequestBuffer->DomainName, &DomainSid); if (!NT_SUCCESS(Status)) { TRACE("SamrLookupDomainInSamServer failed (Status %08lx)\n", Status); goto done; } /* Open the domain */ Status = SamrOpenDomain(ServerHandle, DOMAIN_LOOKUP, DomainSid, &DomainHandle); if (!NT_SUCCESS(Status)) { TRACE("SamrOpenDomain failed (Status %08lx)\n", Status); goto done; } Names[0].Length = RequestBuffer->AccountName.Length; Names[0].MaximumLength = RequestBuffer->AccountName.MaximumLength; Names[0].Buffer = RequestBuffer->AccountName.Buffer; /* Try to get the RID for the user name */ Status = SamrLookupNamesInDomain(DomainHandle, 1, Names, &RelativeIds, &Use); if (!NT_SUCCESS(Status)) { TRACE("SamrLookupNamesInDomain failed (Status %08lx)\n", Status); Status = STATUS_NO_SUCH_USER; goto done; } /* Fail, if it is not a user account */ if (Use.Element[0] != SidTypeUser) { TRACE("Account is not a user account!\n"); Status = STATUS_NO_SUCH_USER; goto done; } /* Open the user object */ Status = SamrOpenUser(DomainHandle, USER_CHANGE_PASSWORD, RelativeIds.Element[0], &UserHandle); if (!NT_SUCCESS(Status)) { TRACE("SamrOpenUser failed (Status %08lx)\n", Status); goto done; } /* Calculate the NT hash for the old password */ Status = SystemFunction007(&RequestBuffer->OldPassword, (LPBYTE)&OldNtPassword); if (!NT_SUCCESS(Status)) { TRACE("SystemFunction007 failed (Status 0x%08lx)\n", Status); goto done; } /* Calculate the NT hash for the new password */ Status = SystemFunction007(&RequestBuffer->NewPassword, (LPBYTE)&NewNtPassword); if (!NT_SUCCESS(Status)) { TRACE("SystemFunction007 failed (Status 0x%08lx)\n", Status); goto done; } /* Calculate the LM password and hash for the old password */ LmPwdString.Length = 15; LmPwdString.MaximumLength = 15; LmPwdString.Buffer = LmPwdBuffer; ZeroMemory(LmPwdString.Buffer, LmPwdString.MaximumLength); Status = RtlUpcaseUnicodeStringToOemString(&LmPwdString, &RequestBuffer->OldPassword, FALSE); if (NT_SUCCESS(Status)) { /* Calculate the LM hash value of the password */ Status = SystemFunction006(LmPwdString.Buffer, (LPSTR)&OldLmPassword); if (NT_SUCCESS(Status)) { OldLmPasswordPresent = TRUE; } } /* Calculate the LM password and hash for the new password */ LmPwdString.Length = 15; LmPwdString.MaximumLength = 15; LmPwdString.Buffer = LmPwdBuffer; ZeroMemory(LmPwdString.Buffer, LmPwdString.MaximumLength); Status = RtlUpcaseUnicodeStringToOemString(&LmPwdString, &RequestBuffer->NewPassword, FALSE); if (NT_SUCCESS(Status)) { /* Calculate the LM hash value of the password */ Status = SystemFunction006(LmPwdString.Buffer, (LPSTR)&NewLmPassword); if (NT_SUCCESS(Status)) { NewLmPasswordPresent = TRUE; } } /* Encrypt the old and new LM passwords, if they exist */ if (OldLmPasswordPresent && NewLmPasswordPresent) { /* Encrypt the old LM password */ Status = SystemFunction012((const BYTE *)&OldLmPassword, (const BYTE *)&NewLmPassword, (LPBYTE)&OldLmEncryptedWithNewLm); if (!NT_SUCCESS(Status)) { TRACE("SystemFunction012 failed (Status 0x%08lx)\n", Status); goto done; } /* Encrypt the new LM password */ Status = SystemFunction012((const BYTE *)&NewLmPassword, (const BYTE *)&OldLmPassword, (LPBYTE)&NewLmEncryptedWithOldLm); if (!NT_SUCCESS(Status)) { TRACE("SystemFunction012 failed (Status 0x%08lx)\n", Status); goto done; } pOldLmEncryptedWithNewLm = &OldLmEncryptedWithNewLm; pNewLmEncryptedWithOldLm = &NewLmEncryptedWithOldLm; } /* Encrypt the old NT password */ Status = SystemFunction012((const BYTE *)&OldNtPassword, (const BYTE *)&NewNtPassword, (LPBYTE)&OldNtEncryptedWithNewNt); if (!NT_SUCCESS(Status)) { TRACE("SystemFunction012 failed (Status 0x%08lx)\n", Status); goto done; } /* Encrypt the new NT password */ Status = SystemFunction012((const BYTE *)&NewNtPassword, (const BYTE *)&OldNtPassword, (LPBYTE)&NewNtEncryptedWithOldNt); if (!NT_SUCCESS(Status)) { TRACE("SystemFunction012 failed (Status 0x%08lx)\n", Status); goto done; } /* Change the password */ Status = SamrChangePasswordUser(UserHandle, OldLmPasswordPresent && NewLmPasswordPresent, pOldLmEncryptedWithNewLm, pNewLmEncryptedWithOldLm, TRUE, &OldNtEncryptedWithNewNt, &NewNtEncryptedWithOldNt, FALSE, NULL, FALSE, NULL); if (!NT_SUCCESS(Status)) { TRACE("SamrChangePasswordUser failed (Status %08lx)\n", Status); goto done; } done: if (UserHandle != NULL) SamrCloseHandle(&UserHandle); SamIFree_SAMPR_ULONG_ARRAY(&RelativeIds); SamIFree_SAMPR_ULONG_ARRAY(&Use); if (DomainHandle != NULL) SamrCloseHandle(&DomainHandle); if (DomainSid != NULL) SamIFreeVoid(DomainSid); if (ServerHandle != NULL) SamrCloseHandle(&ServerHandle); return Status; }
/* * @unimplemented */ NTSTATUS NTAPI LsaApLogonUser(IN PLSA_CLIENT_REQUEST ClientRequest, IN SECURITY_LOGON_TYPE LogonType, IN PVOID AuthenticationInformation, IN PVOID ClientAuthenticationBase, IN ULONG AuthenticationInformationLength, OUT PVOID *ProfileBuffer, OUT PULONG ProfileBufferLength, OUT PLUID LogonId, OUT PNTSTATUS SubStatus, OUT PLSA_TOKEN_INFORMATION_TYPE TokenInformationType, OUT PVOID *TokenInformation, OUT PLSA_UNICODE_STRING *AccountName, OUT PLSA_UNICODE_STRING *AuthenticatingAuthority) { PMSV1_0_INTERACTIVE_LOGON LogonInfo; SAMPR_HANDLE ServerHandle = NULL; SAMPR_HANDLE DomainHandle = NULL; SAMPR_HANDLE UserHandle = NULL; PRPC_SID AccountDomainSid = NULL; RPC_UNICODE_STRING Names[1]; SAMPR_ULONG_ARRAY RelativeIds = {0, NULL}; SAMPR_ULONG_ARRAY Use = {0, NULL}; PSAMPR_USER_INFO_BUFFER UserInfo = NULL; UNICODE_STRING LogonServer; BOOLEAN SessionCreated = FALSE; LARGE_INTEGER LogonTime; // LARGE_INTEGER AccountExpires; LARGE_INTEGER PasswordMustChange; LARGE_INTEGER PasswordLastSet; BOOL SpecialAccount = FALSE; NTSTATUS Status; TRACE("LsaApLogonUser()\n"); TRACE("LogonType: %lu\n", LogonType); TRACE("AuthenticationInformation: %p\n", AuthenticationInformation); TRACE("AuthenticationInformationLength: %lu\n", AuthenticationInformationLength); *ProfileBuffer = NULL; *ProfileBufferLength = 0; *SubStatus = STATUS_SUCCESS; if (LogonType == Interactive || LogonType == Batch || LogonType == Service) { ULONG_PTR PtrOffset; LogonInfo = (PMSV1_0_INTERACTIVE_LOGON)AuthenticationInformation; /* Fix-up pointers in the authentication info */ PtrOffset = (ULONG_PTR)AuthenticationInformation - (ULONG_PTR)ClientAuthenticationBase; LogonInfo->LogonDomainName.Buffer = FIXUP_POINTER(LogonInfo->LogonDomainName.Buffer, PtrOffset); LogonInfo->UserName.Buffer = FIXUP_POINTER(LogonInfo->UserName.Buffer, PtrOffset); LogonInfo->Password.Buffer = FIXUP_POINTER(LogonInfo->Password.Buffer, PtrOffset); TRACE("Domain: %S\n", LogonInfo->LogonDomainName.Buffer); TRACE("User: %S\n", LogonInfo->UserName.Buffer); TRACE("Password: %S\n", LogonInfo->Password.Buffer); RtlInitUnicodeString(&LogonServer, L"Testserver"); } else { FIXME("LogonType %lu is not supported yet!\n", LogonType); return STATUS_NOT_IMPLEMENTED; } /* Get the logon time */ NtQuerySystemTime(&LogonTime); /* Check for special accounts */ if (_wcsicmp(LogonInfo->LogonDomainName.Buffer, L"NT AUTHORITY") == 0) { SpecialAccount = TRUE; /* Get the authority domain SID */ Status = GetNtAuthorityDomainSid(&AccountDomainSid); if (!NT_SUCCESS(Status)) { ERR("GetNtAuthorityDomainSid() failed (Status 0x%08lx)\n", Status); return Status; } if (_wcsicmp(LogonInfo->UserName.Buffer, L"LocalService") == 0) { TRACE("SpecialAccount: LocalService\n"); if (LogonType != Service) return STATUS_LOGON_FAILURE; UserInfo = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(SAMPR_USER_ALL_INFORMATION)); if (UserInfo == NULL) { Status = STATUS_INSUFFICIENT_RESOURCES; goto done; } UserInfo->All.UserId = SECURITY_LOCAL_SERVICE_RID; UserInfo->All.PrimaryGroupId = SECURITY_LOCAL_SERVICE_RID; } else if (_wcsicmp(LogonInfo->UserName.Buffer, L"NetworkService") == 0) { TRACE("SpecialAccount: NetworkService\n"); if (LogonType != Service) return STATUS_LOGON_FAILURE; UserInfo = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(SAMPR_USER_ALL_INFORMATION)); if (UserInfo == NULL) { Status = STATUS_INSUFFICIENT_RESOURCES; goto done; } UserInfo->All.UserId = SECURITY_NETWORK_SERVICE_RID; UserInfo->All.PrimaryGroupId = SECURITY_NETWORK_SERVICE_RID; } else { Status = STATUS_NO_SUCH_USER; goto done; } } else { TRACE("NormalAccount\n"); /* Get the account domain SID */ Status = GetAccountDomainSid(&AccountDomainSid); if (!NT_SUCCESS(Status)) { ERR("GetAccountDomainSid() failed (Status 0x%08lx)\n", Status); return Status; } /* Connect to the SAM server */ Status = SamIConnect(NULL, &ServerHandle, SAM_SERVER_CONNECT | SAM_SERVER_LOOKUP_DOMAIN, TRUE); if (!NT_SUCCESS(Status)) { TRACE("SamIConnect() failed (Status 0x%08lx)\n", Status); goto done; } /* Open the account domain */ Status = SamrOpenDomain(ServerHandle, DOMAIN_LOOKUP, AccountDomainSid, &DomainHandle); if (!NT_SUCCESS(Status)) { ERR("SamrOpenDomain failed (Status %08lx)\n", Status); goto done; } Names[0].Length = LogonInfo->UserName.Length; Names[0].MaximumLength = LogonInfo->UserName.MaximumLength; Names[0].Buffer = LogonInfo->UserName.Buffer; /* Try to get the RID for the user name */ Status = SamrLookupNamesInDomain(DomainHandle, 1, Names, &RelativeIds, &Use); if (!NT_SUCCESS(Status)) { ERR("SamrLookupNamesInDomain failed (Status %08lx)\n", Status); Status = STATUS_NO_SUCH_USER; goto done; } /* Fail, if it is not a user account */ if (Use.Element[0] != SidTypeUser) { ERR("Account is not a user account!\n"); Status = STATUS_NO_SUCH_USER; goto done; } /* Open the user object */ Status = SamrOpenUser(DomainHandle, USER_READ_GENERAL | USER_READ_LOGON | USER_READ_ACCOUNT | USER_READ_PREFERENCES, /* FIXME */ RelativeIds.Element[0], &UserHandle); if (!NT_SUCCESS(Status)) { ERR("SamrOpenUser failed (Status %08lx)\n", Status); goto done; } Status = SamrQueryInformationUser(UserHandle, UserAllInformation, &UserInfo); if (!NT_SUCCESS(Status)) { ERR("SamrQueryInformationUser failed (Status %08lx)\n", Status); goto done; } TRACE("UserName: %S\n", UserInfo->All.UserName.Buffer); /* Check the password */ if ((UserInfo->All.UserAccountControl & USER_PASSWORD_NOT_REQUIRED) == 0) { Status = MsvpCheckPassword(&(LogonInfo->Password), UserInfo); if (!NT_SUCCESS(Status)) { ERR("MsvpCheckPassword failed (Status %08lx)\n", Status); goto done; } } /* Check account restrictions for non-administrator accounts */ if (RelativeIds.Element[0] != DOMAIN_USER_RID_ADMIN) { /* Check if the account has been disabled */ if (UserInfo->All.UserAccountControl & USER_ACCOUNT_DISABLED) { ERR("Account disabled!\n"); *SubStatus = STATUS_ACCOUNT_DISABLED; Status = STATUS_ACCOUNT_RESTRICTION; goto done; } /* Check if the account has been locked */ if (UserInfo->All.UserAccountControl & USER_ACCOUNT_AUTO_LOCKED) { ERR("Account locked!\n"); *SubStatus = STATUS_ACCOUNT_LOCKED_OUT; Status = STATUS_ACCOUNT_RESTRICTION; goto done; } #if 0 /* Check if the account expired */ AccountExpires.LowPart = UserInfo->All.AccountExpires.LowPart; AccountExpires.HighPart = UserInfo->All.AccountExpires.HighPart; if (AccountExpires.QuadPart != 0 && LogonTime.QuadPart >= AccountExpires.QuadPart) { ERR("Account expired!\n"); *SubStatus = STATUS_ACCOUNT_EXPIRED; Status = STATUS_ACCOUNT_RESTRICTION; goto done; } #endif /* Check if the password expired */ PasswordMustChange.LowPart = UserInfo->All.PasswordMustChange.LowPart; PasswordMustChange.HighPart = UserInfo->All.PasswordMustChange.HighPart; PasswordLastSet.LowPart = UserInfo->All.PasswordLastSet.LowPart; PasswordLastSet.HighPart = UserInfo->All.PasswordLastSet.HighPart; if (LogonTime.QuadPart >= PasswordMustChange.QuadPart) { ERR("Password expired!\n"); if (PasswordLastSet.QuadPart == 0) *SubStatus = STATUS_PASSWORD_MUST_CHANGE; else *SubStatus = STATUS_PASSWORD_EXPIRED; Status = STATUS_ACCOUNT_RESTRICTION; goto done; } /* FIXME: more checks */ // STATUS_INVALID_LOGON_HOURS; // STATUS_INVALID_WORKSTATION; } } /* Return logon information */ /* Create and return a new logon id */ Status = NtAllocateLocallyUniqueId(LogonId); if (!NT_SUCCESS(Status)) { TRACE("NtAllocateLocallyUniqueId failed (Status %08lx)\n", Status); goto done; } /* Create the logon session */ Status = DispatchTable.CreateLogonSession(LogonId); if (!NT_SUCCESS(Status)) { TRACE("CreateLogonSession failed (Status %08lx)\n", Status); goto done; } SessionCreated = TRUE; /* Build and fill the interactive profile buffer */ Status = BuildInteractiveProfileBuffer(ClientRequest, UserInfo, &LogonServer, (PMSV1_0_INTERACTIVE_PROFILE*)ProfileBuffer, ProfileBufferLength); if (!NT_SUCCESS(Status)) { TRACE("BuildInteractiveProfileBuffer failed (Status %08lx)\n", Status); goto done; } /* Return the token information type */ *TokenInformationType = LsaTokenInformationV1; /* Build and fill the token information buffer */ Status = BuildTokenInformationBuffer((PLSA_TOKEN_INFORMATION_V1*)TokenInformation, AccountDomainSid, UserInfo, SpecialAccount); if (!NT_SUCCESS(Status)) { TRACE("BuildTokenInformationBuffer failed (Status %08lx)\n", Status); goto done; } done: /* Return the account name */ *AccountName = DispatchTable.AllocateLsaHeap(sizeof(UNICODE_STRING)); if (*AccountName != NULL) { (*AccountName)->Buffer = DispatchTable.AllocateLsaHeap(LogonInfo->UserName.Length + sizeof(UNICODE_NULL)); if ((*AccountName)->Buffer != NULL) { (*AccountName)->MaximumLength = LogonInfo->UserName.Length + sizeof(UNICODE_NULL); RtlCopyUnicodeString(*AccountName, &LogonInfo->UserName); } } if (!NT_SUCCESS(Status)) { if (SessionCreated != FALSE) DispatchTable.DeleteLogonSession(LogonId); if (*ProfileBuffer != NULL) { DispatchTable.FreeClientBuffer(ClientRequest, *ProfileBuffer); *ProfileBuffer = NULL; } } if (UserHandle != NULL) SamrCloseHandle(&UserHandle); SamIFree_SAMPR_USER_INFO_BUFFER(UserInfo, UserAllInformation); SamIFree_SAMPR_ULONG_ARRAY(&RelativeIds); SamIFree_SAMPR_ULONG_ARRAY(&Use); if (DomainHandle != NULL) SamrCloseHandle(&DomainHandle); if (ServerHandle != NULL) SamrCloseHandle(&ServerHandle); if (AccountDomainSid != NULL) RtlFreeHeap(RtlGetProcessHeap(), 0, AccountDomainSid); if (Status == STATUS_NO_SUCH_USER || Status == STATUS_WRONG_PASSWORD) { *SubStatus = Status; Status = STATUS_LOGON_FAILURE; } TRACE("LsaApLogonUser done (Status 0x%08lx SubStatus 0x%08lx)\n", Status, *SubStatus); return Status; }
VOID NlChangeLogWorker( IN LPVOID ChangeLogWorkerParam ) /*++ Routine Description: This thread performs the special operations that are required to replicate the special local groups such as Administrator, Server Operartors, etc., in the NT BUILTIN database to the down level systems. This thread comes up first time during system bootup and initializes required global data. If this NT (PDC) System is replicating to any down level system then it stays back, otherwise it terminates. Also when a down level system is added to the domain, this thread is created if it is not running on the system before. Arguments: None. Return Value: Return when there is no down level system on the domain. --*/ { NTSTATUS Status; #if DBG DWORD Count; #endif NlPrint((NL_CHANGELOG, "ChangeLogWorker Thread is starting \n")); // // check if have initialize the global data before // if ( !NlGlobalChangeLogWorkInit ) { PLSAPR_POLICY_INFORMATION PolicyAccountDomainInfo = NULL; DWORD DomainSidLength; // // wait for SAM service to start. // if( !NlWaitForSamService(FALSE) ) { NlPrint((NL_CRITICAL, "Sam server failed start.")); goto Cleanup; } // // Open Sam Server // Status = SamIConnect( NULL, // No server name &NlGlobalChWorkerSamServerHandle, 0, // Ignore desired access (BOOLEAN) TRUE ); // Indicate we are privileged if ( !NT_SUCCESS(Status) ) { NlPrint((NL_CRITICAL, "Failed to connect to SAM server %lx\n", Status )); NlGlobalChWorkerSamServerHandle = NULL; goto Cleanup; } // // Open Policy Domain // Status = LsaIOpenPolicyTrusted( &NlGlobalChWorkerPolicyHandle ); if ( !NT_SUCCESS(Status) ) { NlPrint((NL_CRITICAL, "Failed to Open LSA database %lx\n", Status )); NlGlobalChWorkerPolicyHandle = NULL; goto Cleanup; } // // Open BuiltIn Domain database // // Note, build in domain SID is made during dll init time. // Status = SamrOpenDomain( NlGlobalChWorkerSamServerHandle, DOMAIN_ALL_ACCESS, NlGlobalChWorkerBuiltinDomainSid, &NlGlobalChWorkerBuiltinDBHandle ); if ( !NT_SUCCESS(Status) ) { NlPrint((NL_CRITICAL, "Failed to Open BUILTIN database %lx\n", Status )); NlGlobalChWorkerBuiltinDBHandle = NULL; goto Cleanup; } // // Query account domain SID. // Status = LsarQueryInformationPolicy( NlGlobalChWorkerPolicyHandle, PolicyAccountDomainInformation, &PolicyAccountDomainInfo ); if ( !NT_SUCCESS(Status) ) { NlPrint((NL_CRITICAL, "Failed to Query Account domain Sid from LSA %lx\n", Status )); goto Cleanup; } if ( PolicyAccountDomainInfo->PolicyAccountDomainInfo.DomainSid == NULL ) { LsaIFree_LSAPR_POLICY_INFORMATION( PolicyAccountDomainInformation, PolicyAccountDomainInfo ); NlPrint((NL_CRITICAL, "Account domain info from LSA invalid.\n")); goto Cleanup; } // // copy domain SID to global data. // DomainSidLength = RtlLengthSid( PolicyAccountDomainInfo-> PolicyAccountDomainInfo.DomainSid ); NlGlobalChWorkerSamDomainSid = (PSID)NetpMemoryAllocate( DomainSidLength ); if( NlGlobalChWorkerSamDomainSid == NULL ) { Status = STATUS_NO_MEMORY; NlPrint((NL_CRITICAL, "NlChangeLogWorker is out of memory.\n")); goto Cleanup; } Status = RtlCopySid( DomainSidLength, NlGlobalChWorkerSamDomainSid, PolicyAccountDomainInfo-> PolicyAccountDomainInfo.DomainSid ); if ( !NT_SUCCESS(Status) ) { NlPrint((NL_CRITICAL, "Failed to copy SAM Domain sid %lx\n", Status )); goto Cleanup; } // // Free up Account domain info, we don't need any more. // LsaIFree_LSAPR_POLICY_INFORMATION( PolicyAccountDomainInformation, PolicyAccountDomainInfo ); // // Open Account domain // Status = SamrOpenDomain( NlGlobalChWorkerSamServerHandle, DOMAIN_ALL_ACCESS, NlGlobalChWorkerSamDomainSid, &NlGlobalChWorkerSamDBHandle ); if ( !NT_SUCCESS(Status) ) { NlPrint((NL_CRITICAL, "Failed to Open SAM database %lx\n", Status )); NlGlobalChWorkerSamDBHandle = NULL; goto Cleanup; } // // Initialization done. Never do it again. // NlGlobalChangeLogWorkInit = TRUE; } // // If SERVERS global group is empty then it implies that we don't // have any down level system on this domain. so we can stop this // thread. // if ( NlIsServersGroupEmpty( 0 ) ) { NlPrint((NL_CHANGELOG, "Servers Group is empty \n ")); goto Cleanup; } // // Initialize NlGlobalSpecialServerGroupList. // Status = NlInitSpecialGroupList(); if ( !NT_SUCCESS(Status) ) { NlPrint((NL_CRITICAL, "Failed to initialize Special group list %lx\n", Status )); goto Cleanup; } // // process worker queue forever, terminate when we are asked to do // so or when the SERVERS group goes empty. // for( ;; ) { DWORD WaitStatus; // // wait on the queue to become non-empty // WaitStatus = WaitForSingleObject( NlGlobalChangeLogWorkerQueueEvent, (DWORD)(-1) ); if ( WaitStatus != 0 ) { NlPrint((NL_CRITICAL, "Change log worker failed, " "WaitForSingleObject error: %ld\n", WaitStatus)); break; } // // empty worker queue. // #if DBG Count = 0; #endif for (;;) { PLIST_ENTRY ListEntry; PWORKER_QUEUE_ENTRY WorkerQueueEntry; // // if we are asked to leave, do so. // if( NlGlobalChangeLogWorkerTerminate ) { NlPrint((NL_CHANGELOG, "ChangeLogWorker is asked to leave \n")); goto Cleanup; } LOCK_CHANGELOG(); if( IsListEmpty( &NlGlobalChangeLogWorkerQueue ) ) { UNLOCK_CHANGELOG(); break; } ListEntry = RemoveHeadList( &NlGlobalChangeLogWorkerQueue ); UNLOCK_CHANGELOG(); WorkerQueueEntry = CONTAINING_RECORD( ListEntry, WORKER_QUEUE_ENTRY, Next ); // // process an queue entry. // if( !NlProcessQueueEntry( WorkerQueueEntry ) ) { NlPrint((NL_CHANGELOG, "Servers group becomes empty \n")); NetpMemoryFree( WorkerQueueEntry ); goto Cleanup; } // // Free this entry. // NetpMemoryFree( WorkerQueueEntry ); #if DBG Count++; #endif } NlPrint((NL_CHANGELOG, "Changelog worker processed %lu entries.\n", Count) ); } Cleanup: // // empty worker queue and group list // LOCK_CHANGELOG(); #if DBG Count = 0; #endif while ( !IsListEmpty( &NlGlobalChangeLogWorkerQueue ) ) { PLIST_ENTRY ListEntry; PWORKER_QUEUE_ENTRY WorkerQueueEntry; ListEntry = RemoveHeadList( &NlGlobalChangeLogWorkerQueue ); WorkerQueueEntry = CONTAINING_RECORD( ListEntry, WORKER_QUEUE_ENTRY, Next ); NetpMemoryFree( WorkerQueueEntry ); #if DBG Count++; #endif } #if DBG if ( Count != 0 ) { NlPrint((NL_CHANGELOG, "Changelog worker did not process %lu entries.\n", Count) ); } #endif while ( !IsListEmpty( &NlGlobalSpecialServerGroupList ) ) { PLIST_ENTRY ListEntry; PGLOBAL_GROUP_ENTRY ServerEntry; ListEntry = RemoveHeadList( &NlGlobalSpecialServerGroupList ); ServerEntry = CONTAINING_RECORD( ListEntry, GLOBAL_GROUP_ENTRY, Next ); NetpMemoryFree( ServerEntry ); } UNLOCK_CHANGELOG(); NlPrint((NL_CHANGELOG, "ChangeLogWorker Thread is exiting \n")); return; UNREFERENCED_PARAMETER( ChangeLogWorkerParam ); }
/* * @unimplemented */ NTSTATUS NTAPI LsaApLogonUser(IN PLSA_CLIENT_REQUEST ClientRequest, IN SECURITY_LOGON_TYPE LogonType, IN PVOID AuthenticationInformation, IN PVOID ClientAuthenticationBase, IN ULONG AuthenticationInformationLength, OUT PVOID *ProfileBuffer, OUT PULONG ProfileBufferLength, OUT PLUID LogonId, OUT PNTSTATUS SubStatus, OUT PLSA_TOKEN_INFORMATION_TYPE TokenInformationType, OUT PVOID *TokenInformation, OUT PLSA_UNICODE_STRING *AccountName, OUT PLSA_UNICODE_STRING *AuthenticatingAuthority) { PMSV1_0_INTERACTIVE_LOGON LogonInfo; SAMPR_HANDLE ServerHandle = NULL; SAMPR_HANDLE DomainHandle = NULL; SAMPR_HANDLE UserHandle = NULL; PRPC_SID AccountDomainSid = NULL; RPC_UNICODE_STRING Names[1]; SAMPR_ULONG_ARRAY RelativeIds = {0, NULL}; SAMPR_ULONG_ARRAY Use = {0, NULL}; PSAMPR_USER_INFO_BUFFER UserInfo = NULL; UNICODE_STRING LogonServer; NTSTATUS Status; TRACE("()\n"); TRACE("LogonType: %lu\n", LogonType); TRACE("AuthenticationInformation: %p\n", AuthenticationInformation); TRACE("AuthenticationInformationLength: %lu\n", AuthenticationInformationLength); *ProfileBuffer = NULL; *ProfileBufferLength = 0; *SubStatus = STATUS_SUCCESS; if (LogonType == Interactive || LogonType == Batch || LogonType == Service) { ULONG_PTR PtrOffset; LogonInfo = (PMSV1_0_INTERACTIVE_LOGON)AuthenticationInformation; /* Fix-up pointers in the authentication info */ PtrOffset = (ULONG_PTR)AuthenticationInformation - (ULONG_PTR)ClientAuthenticationBase; LogonInfo->LogonDomainName.Buffer = (PWSTR)((ULONG_PTR)LogonInfo->LogonDomainName.Buffer + PtrOffset); LogonInfo->UserName.Buffer = (PWSTR)((ULONG_PTR)LogonInfo->UserName.Buffer + PtrOffset); LogonInfo->Password.Buffer = (PWSTR)((ULONG_PTR)LogonInfo->Password.Buffer + PtrOffset); TRACE("Domain: %S\n", LogonInfo->LogonDomainName.Buffer); TRACE("User: %S\n", LogonInfo->UserName.Buffer); TRACE("Password: %S\n", LogonInfo->Password.Buffer); RtlInitUnicodeString(&LogonServer, L"Testserver"); } else { FIXME("LogonType %lu is not supported yet!\n", LogonType); return STATUS_NOT_IMPLEMENTED; } Status = GetDomainSid(&AccountDomainSid); if (!NT_SUCCESS(Status)) { TRACE("GetDomainSid() failed (Status 0x%08lx)\n", Status); return Status; } /* Connect to the SAM server */ Status = SamIConnect(NULL, &ServerHandle, SAM_SERVER_CONNECT | SAM_SERVER_LOOKUP_DOMAIN, TRUE); if (!NT_SUCCESS(Status)) { TRACE("SamIConnect() failed (Status 0x%08lx)\n", Status); goto done; } /* Open the account domain */ Status = SamrOpenDomain(ServerHandle, DOMAIN_LOOKUP, AccountDomainSid, &DomainHandle); if (!NT_SUCCESS(Status)) { TRACE("SamrOpenDomain failed (Status %08lx)\n", Status); goto done; } Names[0].Length = LogonInfo->UserName.Length; Names[0].MaximumLength = LogonInfo->UserName.MaximumLength; Names[0].Buffer = LogonInfo->UserName.Buffer; /* Try to get the RID for the user name */ Status = SamrLookupNamesInDomain(DomainHandle, 1, Names, &RelativeIds, &Use); if (!NT_SUCCESS(Status)) { TRACE("SamrLookupNamesInDomain failed (Status %08lx)\n", Status); Status = STATUS_NO_SUCH_USER; goto done; } /* Fail, if it is not a user account */ if (Use.Element[0] != SidTypeUser) { TRACE("Account is not a user account!\n"); Status = STATUS_NO_SUCH_USER; goto done; } /* Open the user object */ Status = SamrOpenUser(DomainHandle, USER_READ_GENERAL | USER_READ_LOGON | USER_READ_ACCOUNT | USER_READ_PREFERENCES, /* FIXME */ RelativeIds.Element[0], &UserHandle); if (!NT_SUCCESS(Status)) { TRACE("SamrOpenUser failed (Status %08lx)\n", Status); goto done; } Status = SamrQueryInformationUser(UserHandle, UserAllInformation, &UserInfo); if (!NT_SUCCESS(Status)) { TRACE("SamrQueryInformationUser failed (Status %08lx)\n", Status); goto done; } TRACE("UserName: %S\n", UserInfo->All.UserName.Buffer); /* FIXME: Check restrictions */ /* FIXME: Check the password */ if ((UserInfo->All.UserAccountControl & USER_PASSWORD_NOT_REQUIRED) == 0) { FIXME("Must check the password!\n"); } /* Return logon information */ /* Create and return a new logon id */ Status = NtAllocateLocallyUniqueId(LogonId); if (!NT_SUCCESS(Status)) { TRACE("NtAllocateLocallyUniqueId failed (Status %08lx)\n", Status); goto done; } /* Build and fill the interactve profile buffer */ Status = BuildInteractiveProfileBuffer(ClientRequest, UserInfo, &LogonServer, (PMSV1_0_INTERACTIVE_PROFILE*)ProfileBuffer, ProfileBufferLength); if (!NT_SUCCESS(Status)) { TRACE("BuildInteractiveProfileBuffer failed (Status %08lx)\n", Status); goto done; } /* Return the token information type */ *TokenInformationType = LsaTokenInformationV1; /* Build and fill the token information buffer */ Status = BuildTokenInformationBuffer((PLSA_TOKEN_INFORMATION_V1*)TokenInformation, AccountDomainSid, RelativeIds.Element[0], LogonId); if (!NT_SUCCESS(Status)) { TRACE("BuildTokenInformationBuffer failed (Status %08lx)\n", Status); goto done; } *SubStatus = STATUS_SUCCESS; done: /* Return the account name */ *AccountName = DispatchTable.AllocateLsaHeap(sizeof(UNICODE_STRING)); if (*AccountName != NULL) { (*AccountName)->Buffer = DispatchTable.AllocateLsaHeap(LogonInfo->UserName.Length + sizeof(UNICODE_NULL)); if ((*AccountName)->Buffer != NULL) { (*AccountName)->MaximumLength = LogonInfo->UserName.Length + sizeof(UNICODE_NULL); RtlCopyUnicodeString(*AccountName, &LogonInfo->UserName); } } if (!NT_SUCCESS(Status)) { if (*ProfileBuffer != NULL) { DispatchTable.FreeClientBuffer(ClientRequest, *ProfileBuffer); *ProfileBuffer = NULL; } } if (UserHandle != NULL) SamrCloseHandle(&UserHandle); SamIFree_SAMPR_USER_INFO_BUFFER(UserInfo, UserAllInformation); SamIFree_SAMPR_ULONG_ARRAY(&RelativeIds); SamIFree_SAMPR_ULONG_ARRAY(&Use); if (DomainHandle != NULL) SamrCloseHandle(&DomainHandle); if (ServerHandle != NULL) SamrCloseHandle(&ServerHandle); if (AccountDomainSid != NULL) RtlFreeHeap(RtlGetProcessHeap(), 0, AccountDomainSid); TRACE("LsaApLogonUser done (Status %08lx)\n", Status); return Status; }