You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
788 lines
17 KiB
788 lines
17 KiB
/*++
|
|
|
|
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
|
|
|
|
|