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; }
BOOLEAN NlProcessQueueEntry( PWORKER_QUEUE_ENTRY Entry ) /*++ Routine Description: This procedure processes an entry that has come from the worker queue. Arguments: WorkerQueueEntry : pointer to worker structure. Return Value: TRUE : if we need to continue processing more entries. FALSE : if we need to terminate the worker. --*/ { NTSTATUS Status = STATUS_SUCCESS; ULONG Rid = Entry->Rid; BOOLEAN ReturnValue = TRUE; SAMPR_RETURNED_USTRING_ARRAY Names = {0, NULL}; SAMPR_ULONG_ARRAY Use = {0, NULL}; SAMPR_HANDLE GroupHandle = NULL; PSAMPR_GET_MEMBERS_BUFFER MembersBuffer = NULL; SAMPR_HANDLE UserHandle = NULL; PSAMPR_GET_GROUPS_BUFFER GroupsBuffer = NULL; PGLOBAL_GROUP_ENTRY GroupEntry; DWORD i; // // The membership of a special local group is being changed, // force each lanman BDC to re-sync with each user that's being // added-to/removed-from the local group. // switch ( Entry->EntryType ) { case ChangeLogAliasMembership : // // determine Rid Type. // Status = SamrLookupIdsInDomain( NlGlobalChWorkerSamDBHandle, 1, &Rid, &Names, &Use ); if ( !NT_SUCCESS(Status) ) { Names.Element = NULL; Use.Element = NULL; goto Cleanup; } NlAssert( Names.Count == 1 ); NlAssert( Names.Element != NULL ); NlAssert( Use.Count == 1 ); NlAssert( Use.Element != NULL ); if( Use.Element[0] == SidTypeUser ) { NlSimulateUserDelta( Rid ); // // if this users is added unknowingly to the global group // list, remove it now. // LOCK_CHANGELOG(); GroupEntry = NlGetGroupEntry ( &NlGlobalSpecialServerGroupList, Rid ); if( GroupEntry != NULL ) { RemoveEntryList( &GroupEntry->Next ); NetpMemoryFree( GroupEntry ); } UNLOCK_CHANGELOG(); } else if( Use.Element[0] == SidTypeGroup ) { DWORD i; // // simulate deltas for all members in this group. // Status = SamrOpenGroup( NlGlobalChWorkerSamDBHandle, 0, // No desired access Rid, &GroupHandle ); if (!NT_SUCCESS(Status)) { GroupHandle = NULL; goto Cleanup; } Status = SamrGetMembersInGroup( GroupHandle, &MembersBuffer ); if (!NT_SUCCESS(Status)) { MembersBuffer = NULL; goto Cleanup; } for( i = 0; i < MembersBuffer->MemberCount; i++) { NlSimulateUserDelta( MembersBuffer->Members[i] ); } #if DBG // // Ensure the change log thread already added this group // LOCK_CHANGELOG(); GroupEntry = NlGetGroupEntry ( &NlGlobalSpecialServerGroupList, Rid ); UNLOCK_CHANGELOG(); NlAssert( GroupEntry != NULL ); #endif // DBG } else { // // ignore any other changes // NlAssert( FALSE ); } break; // // The group membership of the special group has changed. // Force Lanman BDCs to re-sync the user being added-to/removed-from // the domain. // case ChangeLogGroupMembership : // // determine Rid Type. // Status = SamrLookupIdsInDomain( NlGlobalChWorkerSamDBHandle, 1, &Rid, &Names, &Use ); if ( !NT_SUCCESS(Status) ) { Names.Element = NULL; Use.Element = NULL; goto Cleanup; } NlAssert( Names.Count == 1 ); NlAssert( Names.Element != NULL ); NlAssert( Use.Count == 1 ); NlAssert( Use.Element != NULL ); NlAssert( Use.Element[0] == SidTypeUser ); if( Use.Element[0] == SidTypeUser ) { NlSimulateUserDelta( Rid ); } break; // // A member was deleted from the SERVERS group. // Check to see if this thread can terminate. // case ServersGroupDel : // // if the server group is empty then terminate worker thread. // if ( NlGlobalLmBdcCount == 0 ) { ReturnValue = FALSE; } break; // // Rename user is handled as multiple deltas: // 1) Delete old user and // 2) Add new user. // 3) Update membership of each group the user is a member of // case ChangeLogRenameUser : // // simulate a user change so that an user account with // new name will be created on the down level system. // NlSimulateUserDelta( Rid ); // // create deltas to make his group membership correct on the // down level machine. // Status = SamrOpenUser( NlGlobalChWorkerSamDBHandle, 0, // No desired access Rid, &UserHandle ); if (!NT_SUCCESS(Status)) { UserHandle = NULL; goto Cleanup; } Status = SamrGetGroupsForUser( UserHandle, &GroupsBuffer ); if (!NT_SUCCESS(Status)) { GroupsBuffer = NULL; goto Cleanup; } for( i = 0; i < GroupsBuffer->MembershipCount; i++) { Status = SamINotifyDelta( NlGlobalChWorkerSamDBHandle, SecurityDbChangeMemberAdd, SecurityDbObjectSamGroup, GroupsBuffer->Groups[i].RelativeId, NULL, FALSE, NULL ); if (!NT_SUCCESS(Status)) { goto Cleanup; } } break; // // A newly added user needs to have it's membership in "Domain Users" updated, too. // // Here we simply supply a corresponding change user membership delta which // ends up as a AddOrChangeUser delta with the CHANGELOG_DOMAINUSERS_CHANGED // flag set. NetrAccountDeltas interprets that flag to mean // "send the membership of this user". // case ChangeLogAddUser: Status = SamINotifyDelta( NlGlobalChWorkerSamDBHandle, SecurityDbChangeMemberAdd, SecurityDbObjectSamUser, Rid, NULL, FALSE, NULL ); if (!NT_SUCCESS(Status)) { goto Cleanup; } break; // // Rename group is handled as three deltas: // 1) Delete old group, // 2) Add new group and // 3) Changemembership of new group. // case ChangeLogRenameGroup : // // simulate a group change so that a group account with // new name will be created on the down level system. Also // simulate a changemembership delta so that the members are // added to the new group appropriately. // Status = SamINotifyDelta( NlGlobalChWorkerSamDBHandle, SecurityDbChange, SecurityDbObjectSamGroup, Rid, NULL, FALSE, NULL ); if ( NT_SUCCESS(Status) ) { Status = SamINotifyDelta( NlGlobalChWorkerSamDBHandle, SecurityDbChangeMemberAdd, SecurityDbObjectSamGroup, Rid, NULL, FALSE, NULL ); } if ( !NT_SUCCESS(Status) ) { NlPrint((NL_CRITICAL, "SamINotifyDelta failed %lx\n", Status ) ); } break; default: NlPrint((NL_CRITICAL, "NlProcessQueueEntry found unknown queue entry : %lx\n", Entry->EntryType )); break; } Cleanup: if( Names.Element != NULL ) { SamIFree_SAMPR_RETURNED_USTRING_ARRAY( &Names ); } if( Use.Element != NULL ) { SamIFree_SAMPR_ULONG_ARRAY( &Use ); } if ( MembersBuffer != NULL ) { SamIFree_SAMPR_GET_MEMBERS_BUFFER( MembersBuffer ); } if( GroupHandle != NULL ) { (VOID) SamrCloseHandle( &GroupHandle ); } if ( GroupsBuffer != NULL ) { SamIFree_SAMPR_GET_GROUPS_BUFFER( GroupsBuffer ); } if( UserHandle != NULL ) { (VOID) SamrCloseHandle( &UserHandle ); } if ( !NT_SUCCESS(Status) ) { NlPrint((NL_CRITICAL, "NlProcessQueueEntry failed : %lx\n", Status )); } return ReturnValue; }
BOOL NlIsServersGroupEmpty( ULONG ServersGroupRid ) /*++ Routine Description: This procedure determines whether the Servers group is empty or not. Arguments: Rid : Rid of the SERVERS group. If it is zero then determine the RID by lookup. Return Value: FALSE : If the servers group exist and it is non-empty. TRUE : otherwise --*/ { NTSTATUS Status; SAMPR_ULONG_ARRAY RelativeIdArray = {0, NULL}; SAMPR_ULONG_ARRAY UseArray = {0, NULL}; RPC_UNICODE_STRING GroupNameString; SAMPR_HANDLE GroupHandle = NULL; BOOL ReturnValue = TRUE; PSAMPR_GET_MEMBERS_BUFFER MembersBuffer = NULL; if ( ServersGroupRid == 0 ) { // // Convert the group name to a RelativeId. // RtlInitUnicodeString( (PUNICODE_STRING)&GroupNameString, SSI_SERVER_GROUP_W ); Status = SamrLookupNamesInDomain( NlGlobalChWorkerSamDBHandle, 1, &GroupNameString, &RelativeIdArray, &UseArray ); if ( !NT_SUCCESS(Status) ) { RelativeIdArray.Element = NULL; UseArray.Element = NULL; goto Cleanup; } // // we should get back exactly one entry of info back. // NlAssert( UseArray.Count == 1 ); NlAssert( UseArray.Element != NULL ); NlAssert( RelativeIdArray.Count == 1 ); NlAssert( RelativeIdArray.Element != NULL ); if ( UseArray.Element[0] != SidTypeGroup ) { goto Cleanup; } ServersGroupRid = RelativeIdArray.Element[0]; } // // Open the SERVERS group // Status = SamrOpenGroup( NlGlobalChWorkerSamDBHandle, 0, // No desired access ServersGroupRid, &GroupHandle ); if ( !NT_SUCCESS(Status) ) { GroupHandle = NULL; goto Cleanup; } // // enumerate members in the group. // Status = SamrGetMembersInGroup( GroupHandle, &MembersBuffer ); if (!NT_SUCCESS(Status)) { MembersBuffer = NULL; goto Cleanup; } if ( MembersBuffer->MemberCount != 0 ) { // // atleast a member in there. // ReturnValue = FALSE; // // Save the list of LmBdcs NlLmBdcListSet( MembersBuffer->MemberCount, MembersBuffer->Members ); } Cleanup: SamIFree_SAMPR_ULONG_ARRAY( &RelativeIdArray ); SamIFree_SAMPR_ULONG_ARRAY( &UseArray ); if ( MembersBuffer != NULL ) { SamIFree_SAMPR_GET_MEMBERS_BUFFER( MembersBuffer ); } if( GroupHandle != NULL ) { (VOID) SamrCloseHandle( &GroupHandle ); } return ReturnValue; }
NTSTATUS NlAddGlobalGroupsToList( PLIST_ENTRY GroupList, ULONG LocalGroupID ) /*++ Routine Description: This procedure adds the global groups that are member of the given alias. Arguments: GroupList : List to munch. LocalGroupId : Rid of the local group. Return Value: Return NT Status code. --*/ { NTSTATUS Status; SAMPR_HANDLE AliasHandle = NULL; SAMPR_PSID_ARRAY Members = {0, NULL}; PULONG RidArray = NULL; DWORD RidArrayLength = 0; SAMPR_RETURNED_USTRING_ARRAY Names = {0, NULL}; SAMPR_ULONG_ARRAY Use = {0, NULL}; DWORD i; // // Open Local Group // Status = SamrOpenAlias( NlGlobalChWorkerBuiltinDBHandle, 0, // No desired access LocalGroupID, &AliasHandle ); if (!NT_SUCCESS(Status)) { AliasHandle = NULL; goto Cleanup; } // // Enumerate members in this local group. // Status = SamrGetMembersInAlias( AliasHandle, &Members ); if (!NT_SUCCESS(Status)) { Members.Sids = NULL; goto Cleanup; } // // Determine the SIDs that belong to the Account Domain and get the // RIDs of them. // if( Members.Count == 0) { Status = STATUS_SUCCESS; goto Cleanup; } // // Allocate the maximum size RID array required. // RidArray = (PULONG)NetpMemoryAllocate( Members.Count * sizeof(ULONG) ); if( RidArray == NULL ) { Status = STATUS_NO_MEMORY; goto Cleanup; } for( i = 0; i < Members.Count; i++) { PUCHAR SubAuthorityCount; BOOLEAN EqualSid; SubAuthorityCount = RtlSubAuthorityCountSid(Members.Sids[i].SidPointer); (*SubAuthorityCount)--; EqualSid = RtlEqualSid( NlGlobalChWorkerSamDomainSid, Members.Sids[i].SidPointer ); (*SubAuthorityCount)++; if( EqualSid ) { RidArray[RidArrayLength] = *RtlSubAuthoritySid( Members.Sids[i].SidPointer, (*SubAuthorityCount) -1 ); RidArrayLength++; } } if( RidArrayLength == 0) { Status = STATUS_SUCCESS; goto Cleanup; } // // Get Group RIDs and add them to list. // Status = SamrLookupIdsInDomain( NlGlobalChWorkerSamDBHandle, RidArrayLength, RidArray, &Names, &Use ); if ( !NT_SUCCESS(Status) ) { Names.Element = NULL; Use.Element = NULL; if( Status == STATUS_NONE_MAPPED ) { // // if no SID is mapped, we can't do much here. // NlPrint((NL_CRITICAL, "NlAddGlobalGroupsToList could not map any SID from " "local group, RID = %lx \n", LocalGroupID )); Status = STATUS_SUCCESS; } goto Cleanup; } NlAssert( Names.Count == RidArrayLength ); NlAssert( Names.Element != NULL ); NlAssert( Use.Count == RidArrayLength ); NlAssert( Use.Element != NULL ); // // Find groups and add them to list. // for( i = 0; i < RidArrayLength; i++ ) { if( Use.Element[i] == SidTypeGroup ) { // // we found a group, add it to the list if it is not there // already. // if( NlGetGroupEntry( GroupList, RidArray[i] ) != NULL ) { // // entry already in the list. // continue; } // // add an entry to the list. // Status = NlAddGroupEntry( GroupList, RidArray[i] ); if ( !NT_SUCCESS(Status) ) { goto Cleanup; } } } Cleanup: if( Names.Element != NULL ) { SamIFree_SAMPR_RETURNED_USTRING_ARRAY( &Names ); } if( Use.Element != NULL ) { SamIFree_SAMPR_ULONG_ARRAY( &Use ); } if( RidArray != NULL ) { NetpMemoryFree( RidArray ); } if ( Members.Sids != NULL ) { SamIFree_SAMPR_PSID_ARRAY( (PSAMPR_PSID_ARRAY)&Members ); } if( AliasHandle != NULL ) { SamrCloseHandle( &AliasHandle ); } if ( !NT_SUCCESS(Status) ) { NlPrint((NL_CRITICAL, "NlAddGlobalGroupsToList failed %lx\n", Status )); } 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; 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; }