|
|
/*++
Copyright (c) 1995 Microsoft Corporation
Module Name:
Mapping.c
Abstract:
Author:
Arthur Hanson (arth) Dec 07, 1994
Environment:
Revision History:
--*/
#include <stdlib.h>
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <windows.h>
#include <dsgetdc.h>
#include "debug.h"
#include "llsutil.h"
#include "llssrv.h"
#include "mapping.h"
#include "msvctbl.h"
#include "svctbl.h"
#include "perseat.h"
#define NO_LLS_APIS
#include "llsapi.h"
#include <strsafe.h> //include last
ULONG MappingListSize = 0; PMAPPING_RECORD *MappingList = NULL; RTL_RESOURCE MappingListLock;
/////////////////////////////////////////////////////////////////////////
NTSTATUS MappingListInit()
/*++
Routine Description:
The table is linear so a binary search can be used on the table. We assume that adding new Mappings is a relatively rare occurance, since we need to sort it each time.
The Mapping table is guarded by a read and write semaphore. Multiple reads can occur, but a write blocks everything.
Arguments:
None.
Return Value:
None.
--*/
{ NTSTATUS status = STATUS_SUCCESS;
try { RtlInitializeResource(&MappingListLock); } except(EXCEPTION_EXECUTE_HANDLER ) { status = GetExceptionCode(); }
return status;
} // MappingListInit
/////////////////////////////////////////////////////////////////////////
int __cdecl MappingListCompare(const void *arg1, const void *arg2) { PMAPPING_RECORD Svc1, Svc2;
Svc1 = (PMAPPING_RECORD) *((PMAPPING_RECORD *) arg1); Svc2 = (PMAPPING_RECORD) *((PMAPPING_RECORD *) arg2);
return lstrcmpi( Svc1->Name, Svc2->Name);
} // MappingListCompare
/////////////////////////////////////////////////////////////////////////
int __cdecl MappingUserListCompare(const void *arg1, const void *arg2) { LPTSTR User1, User2;
User1 = (LPTSTR) *((LPTSTR *) arg1); User2 = (LPTSTR) *((LPTSTR *) arg2);
return lstrcmpi( User1, User2);
} // MappingUserListCompare
/////////////////////////////////////////////////////////////////////////
PMAPPING_RECORD MappingListFind( LPTSTR MappingName )
/*++
Routine Description:
Internal routine to actually do binary search on MappingList, this does not do any locking as we expect the wrapper routine to do this. The search is a simple binary search.
Arguments:
MappingName -
Return Value:
Pointer to found Mapping table entry or NULL if not found.
--*/
{ LONG begin = 0; LONG end = (LONG) MappingListSize - 1; LONG cur; int match; PMAPPING_RECORD Mapping;
#if DBG
if (TraceFlags & TRACE_FUNCTION_TRACE) dprintf(TEXT("LLS TRACE: MappingListFind\n")); #endif
if ((MappingName == NULL) || (MappingListSize == 0)) return NULL;
while (end >= begin) { // go halfway in-between
cur = (begin + end) / 2; Mapping = MappingList[cur];
// compare the two result into match
match = lstrcmpi(MappingName, Mapping->Name);
if (match < 0) // move new begin
end = cur - 1; else begin = cur + 1;
if (match == 0) return Mapping; }
return NULL;
} // MappingListFind
/////////////////////////////////////////////////////////////////////////
LPTSTR MappingUserListFind( LPTSTR User, ULONG NumEntries, LPTSTR *Users )
/*++
Routine Description:
Internal routine to actually do binary search on MasterServiceList, this does not do any locking as we expect the wrapper routine to do this. The search is a simple binary search.
Arguments:
ServiceName -
Return Value:
Pointer to found service table entry or NULL if not found.
--*/
{ LONG begin = 0; LONG end; LONG cur; int match; LPTSTR pUser;
#if DBG
if (TraceFlags & TRACE_FUNCTION_TRACE) dprintf(TEXT("LLS TRACE: MappingUserListFind\n")); #endif
if (NumEntries == 0) return NULL;
end = (LONG) NumEntries - 1;
while (end >= begin) { // go halfway in-between
cur = (begin + end) / 2; pUser = Users[cur];
// compare the two result into match
match = lstrcmpi(User, pUser);
if (match < 0) // move new begin
end = cur - 1; else begin = cur + 1;
if (match == 0) return pUser; }
return NULL;
} // MappingUserListFind
/////////////////////////////////////////////////////////////////////////
PMAPPING_RECORD MappingListUserFind( LPTSTR User )
/*++
Routine Description:
Arguments:
Return Value:
--*/
{ ULONG i = 0; PMAPPING_RECORD pMap = NULL;
//
// Need to scan list so get read access.
//
RtlAcquireResourceShared(&MappingListLock, TRUE);
if (MappingList == NULL) goto MappingListUserFindExit;
while ((i < MappingListSize) && (pMap == NULL)) { if (MappingUserListFind(User, MappingList[i]->NumMembers, MappingList[i]->Members ) != NULL) pMap = MappingList[i]; i++; }
MappingListUserFindExit: RtlReleaseResource(&MappingListLock);
return pMap; } // MappingListUserFind
/////////////////////////////////////////////////////////////////////////
PMAPPING_RECORD MappingListAdd( LPTSTR MappingName, LPTSTR Comment, ULONG Licenses, NTSTATUS *pStatus )
/*++
Routine Description:
Adds a Mapping to the Mapping table.
Arguments:
MappingName -
Return Value:
Pointer to added Mapping table entry, or NULL if failed.
--*/
{ PMAPPING_RECORD NewMapping; LPTSTR NewMappingName; LPTSTR NewComment; PMAPPING_RECORD CurrentRecord = NULL; PMAPPING_RECORD *pMappingListTmp; HRESULT hr; size_t cch;
#if DBG
if (TraceFlags & TRACE_FUNCTION_TRACE) dprintf(TEXT("LLS TRACE: MappingListAdd\n")); #endif
//
// We do a double check here to see if the mapping already exists
//
CurrentRecord = MappingListFind(MappingName); if (CurrentRecord != NULL) {
if (NULL != pStatus) *pStatus = STATUS_GROUP_EXISTS;
return NULL; }
//
// Allocate space for table (zero init it).
//
if (MappingList == NULL) pMappingListTmp = (PMAPPING_RECORD *) LocalAlloc(LPTR, sizeof(PMAPPING_RECORD)); else pMappingListTmp = (PMAPPING_RECORD *) LocalReAlloc(MappingList, sizeof(PMAPPING_RECORD) * (MappingListSize + 1), LHND);
//
// Make sure we could allocate Mapping table
//
if (pMappingListTmp == NULL) { return NULL; } else { MappingList = pMappingListTmp; }
NewMapping = LocalAlloc(LPTR, sizeof(MAPPING_RECORD)); if (NewMapping == NULL) return NULL;
MappingList[MappingListSize] = NewMapping;
cch = lstrlen(MappingName) + 1; NewMappingName = (LPTSTR) LocalAlloc(LPTR, cch * sizeof(TCHAR)); if (NewMappingName == NULL) { LocalFree(NewMapping); return NULL; }
// now copy it over...
NewMapping->Name = NewMappingName; hr = StringCchCopy(NewMappingName, cch, MappingName); ASSERT(SUCCEEDED(hr));
//
// Allocate space for Comment
//
cch = lstrlen(Comment) + 1; NewComment = (LPTSTR) LocalAlloc(LPTR, cch * sizeof(TCHAR)); if (NewComment == NULL) { LocalFree(NewMapping); LocalFree(NewMappingName); return NULL; }
// now copy it over...
NewMapping->Comment = NewComment; hr = StringCchCopy(NewComment, cch, Comment); ASSERT(SUCCEEDED(hr));
NewMapping->NumMembers = 0; NewMapping->Members = NULL; NewMapping->Licenses = Licenses; NewMapping->LicenseListSize = 0; NewMapping->LicenseList = NULL; NewMapping->Flags = (LLS_FLAG_LICENSED | LLS_FLAG_SUITE_AUTO);
MappingListSize++;
// Have added the entry - now need to sort it in order of the Mapping names
qsort((void *) MappingList, (size_t) MappingListSize, sizeof(PMAPPING_RECORD), MappingListCompare);
return NewMapping;
} // MappingListAdd
/////////////////////////////////////////////////////////////////////////
NTSTATUS MappingListDelete( LPTSTR MappingName )
/*++
Routine Description:
Arguments:
MappingName -
Return Value:
--*/
{ PMAPPING_RECORD Mapping; ULONG i; PMAPPING_RECORD *pMappingListTmp;
#if DBG
if (TraceFlags & TRACE_FUNCTION_TRACE) dprintf(TEXT("LLS TRACE: MappingListDelete\n")); #endif
//
// Get mapping record based on name given
//
Mapping = MappingListFind(MappingName); if (Mapping == NULL) return STATUS_OBJECT_NAME_NOT_FOUND;
//
// Make sure there are no members to the mapping
//
if (Mapping->NumMembers != 0) return STATUS_MEMBER_IN_GROUP;
//
// Check if this is the last Mapping
//
if (MappingListSize == 1) { LocalFree(Mapping->Name); LocalFree(Mapping->Comment); LocalFree(Mapping); LocalFree(MappingList); MappingListSize = 0; MappingList = NULL; return STATUS_SUCCESS; }
//
// Not the last mapping so find it in the list
//
i = 0; while ((i < MappingListSize) && (lstrcmpi(MappingList[i]->Name, MappingName))) i++;
//
// Now move everything below it up.
//
i++; while (i < MappingListSize) { //swi, code review, why not MappingList[i-1] = MappingList[i];?
memcpy(&MappingList[i-1], &MappingList[i], sizeof(PMAPPING_RECORD)); i++; }
pMappingListTmp = (PMAPPING_RECORD *) LocalReAlloc(MappingList, sizeof(PMAPPING_RECORD) * (MappingListSize - 1), LHND);
//
// Make sure we could allocate Mapping table
//
if (pMappingListTmp != NULL) MappingList = pMappingListTmp;
//
// if realloc failed, use old table; still decrement size, though
//
MappingListSize--;
//
// Now free up the record
//
LocalFree(Mapping->Name); LocalFree(Mapping->Comment); LocalFree(Mapping);
return STATUS_SUCCESS;
} // MappingListDelete
/////////////////////////////////////////////////////////////////////////
PMAPPING_RECORD MappingUserListAdd( LPTSTR MappingName, LPTSTR User )
/*++
Routine Description:
Arguments:
MappingName -
Return Value:
Pointer to added Mapping table entry, or NULL if failed.
--*/
{ PMAPPING_RECORD Mapping; LPTSTR NewName; LPTSTR pUser; LPTSTR *pMembersTmp; HRESULT hr; size_t cch;
#if DBG
if (TraceFlags & TRACE_FUNCTION_TRACE) dprintf(TEXT("LLS TRACE: MappingUserListAdd\n")); #endif
//
// Get mapping record based on name given
//
Mapping = MappingListFind(MappingName); if (Mapping == NULL) return NULL;
//
// We do a double check here to see if another thread just got done
// adding the Mapping, between when we checked last and actually got
// the write lock.
//
pUser = MappingUserListFind(User, Mapping->NumMembers, Mapping->Members);
if (pUser != NULL) { return Mapping; }
//
// Allocate space for table (zero init it).
//
if (Mapping->Members == NULL) pMembersTmp = (LPTSTR *) LocalAlloc(LPTR, sizeof(LPTSTR)); else pMembersTmp = (LPTSTR *) LocalReAlloc(Mapping->Members, sizeof(LPTSTR) * (Mapping->NumMembers + 1), LHND);
//
// Make sure we could allocate Mapping table
//
if (pMembersTmp == NULL) { return NULL; } else { Mapping->Members = pMembersTmp; }
cch = lstrlen(User) + 1; NewName = (LPTSTR) LocalAlloc(LPTR, cch * sizeof(TCHAR)); if (NewName == NULL) return NULL;
// now copy it over...
Mapping->Members[Mapping->NumMembers] = NewName; hr = StringCchCopy(NewName, cch, User); ASSERT(SUCCEEDED(hr));
Mapping->NumMembers++;
// Have added the entry - now need to sort it in order of the Mapping names
qsort((void *) Mapping->Members, (size_t) Mapping->NumMembers, sizeof(LPTSTR), MappingUserListCompare);
return Mapping;
} // MappingUserListAdd
/////////////////////////////////////////////////////////////////////////
NTSTATUS MappingUserListDelete( LPTSTR MappingName, LPTSTR User )
/*++
Routine Description:
Arguments:
MappingName -
Return Value:
Pointer to added Mapping table entry, or NULL if failed.
--*/
{ PMAPPING_RECORD Mapping; LPTSTR pUser; ULONG i; LPTSTR *pMembersTmp;
#if DBG
if (TraceFlags & TRACE_FUNCTION_TRACE) dprintf(TEXT("LLS TRACE: MappingUserListDelete\n")); #endif
//
// Get mapping record based on name given
//
Mapping = MappingListFind(MappingName); if (Mapping == NULL) return STATUS_OBJECT_NAME_NOT_FOUND;
//
// Find the given user
//
pUser = MappingUserListFind(User, Mapping->NumMembers, Mapping->Members); if (pUser == NULL) return STATUS_OBJECT_NAME_NOT_FOUND;
//
// Check if this is the last user
//
if (Mapping->NumMembers == 1) { LocalFree(pUser); LocalFree(Mapping->Members); Mapping->Members = NULL; Mapping->NumMembers = 0; return STATUS_SUCCESS; }
//
// Not the last member so find it in the list
//
i = 0; while ((i < Mapping->NumMembers) && (lstrcmpi(Mapping->Members[i], User))) i++;
//
// Now move everything below it up.
//
i++; while (i < Mapping->NumMembers) { //swi, code review, why not Mapping->Members[i-1]=Mapping->Members[i];?
memcpy(&Mapping->Members[i-1], &Mapping->Members[i], sizeof(LPTSTR)); i++; }
pMembersTmp = (LPTSTR *) LocalReAlloc(Mapping->Members, sizeof(LPTSTR) * (Mapping->NumMembers - 1), LHND);
//
// Make sure we could allocate Mapping table
//
if (pMembersTmp != NULL) { Mapping->Members = pMembersTmp; }
Mapping->NumMembers--;
LocalFree(pUser); return STATUS_SUCCESS;
} // MappingUserListDelete
#if DBG
/////////////////////////////////////////////////////////////////////////
VOID MappingListDebugDump( )
/*++
Routine Description:
Arguments:
Return Value:
--*/
{ ULONG i = 0;
//
// Need to scan list so get read access.
//
RtlAcquireResourceShared(&MappingListLock, TRUE);
dprintf(TEXT("Mapping Table, # Entries: %lu\n"), MappingListSize); if (MappingList == NULL) goto MappingListDebugDumpExit;
for (i = 0; i < MappingListSize; i++) { dprintf(TEXT(" Name: %s Flags: 0x%4lX LT: %2lu Lic: %4lu # Mem: %4lu Comment: %s\n"), MappingList[i]->Name, MappingList[i]->Flags, MappingList[i]->LicenseListSize, MappingList[i]->Licenses, MappingList[i]->NumMembers, MappingList[i]->Comment); }
MappingListDebugDumpExit: RtlReleaseResource(&MappingListLock);
return; } // MappingListDebugDump
/////////////////////////////////////////////////////////////////////////
VOID MappingListDebugInfoDump( PVOID Data )
/*++
Routine Description:
Arguments:
Return Value:
--*/
{ ULONG i; PMAPPING_RECORD Mapping = NULL;
RtlAcquireResourceShared(&MappingListLock, TRUE); dprintf(TEXT("Mapping Table, # Entries: %lu\n"), MappingListSize);
if (Data == NULL) goto MappingListDebugInfoDumpExit;
if (MappingList == NULL) goto MappingListDebugInfoDumpExit;
if (lstrlen((LPWSTR) Data) > 0) { Mapping = MappingListFind((LPTSTR) Data);
if (Mapping != NULL) { dprintf(TEXT(" Name: %s Flags: 0x%4lX LT: %2lu Lic: %4lu # Mem: %4lu Comment: %s\n"), Mapping->Name, Mapping->Flags, Mapping->LicenseListSize, Mapping->Licenses, Mapping->NumMembers, Mapping->Comment);
if (Mapping->NumMembers != 0) dprintf(TEXT("\nMembers\n"));
for (i = 0; i < Mapping->NumMembers; i++) dprintf(TEXT(" %s\n"), Mapping->Members[i]);
if (Mapping->LicenseListSize != 0) dprintf(TEXT("\nLicenseTable\n"));
for (i = 0; i < Mapping->LicenseListSize; i++) dprintf( TEXT(" Flags: 0x%4lX Ref: %2lu LN: %2lu Svc: %s\n"), Mapping->LicenseList[i]->Flags, Mapping->LicenseList[i]->RefCount, Mapping->LicenseList[i]->LicensesNeeded, Mapping->LicenseList[i]->Service->Name );
} else dprintf(TEXT("Mapping not found: %s\n"), (LPTSTR) Data); }
MappingListDebugInfoDumpExit: RtlReleaseResource(&MappingListLock);
} // MappingListDebugInfoDump
#endif
|