/*++

Copyright (c) 1996 Microsoft Corporation

Module Name:

    srvutil.cpp

Abstract:

    Server Service attachment APIs

Author:

    Jin Huang (jinhuang) 23-Jun-1997

Revision History:

    jinhuang    23-Jan-1998     splitted to client-server
--*/
#include "serverp.h"
#include "srvutil.h"
#include "infp.h"
#include "pfp.h"

#include <io.h>
#pragma hdrstop

DWORD Thread     gMaxRegTicks=0;
DWORD Thread     gMaxFileTicks=0;
DWORD Thread     gMaxDsTicks=0;
WCHAR Thread     theAcctDomName[MAX_PATH+1];
WCHAR Thread     ComputerName[MAX_COMPUTERNAME_LENGTH+1];
CHAR Thread      sidAuthBuf[32];
CHAR Thread      sidBuiltinBuf[32];
DWORD Thread     t_pebSize=0;
LPVOID Thread    t_pebClient=NULL;

SCESTATUS
ScepQueryInfTicks(
    IN PWSTR TemplateName,
    IN AREA_INFORMATION Area,
    OUT PDWORD pTotalTicks
    );

SCESTATUS
ScepGetObjectCount(
    IN PSCECONTEXT Context,
    IN PCWSTR SectionName,
    IN BOOL bPolicyProp,
    OUT PDWORD pTotalTicks
    );


LPTSTR
ScepSearchClientEnv(
    IN LPTSTR varName,
    IN DWORD dwSize
    );

//
// implementations
//


SCESTATUS
ScepGetTotalTicks(
    IN PCWSTR TemplateName,
    IN PSCECONTEXT Context,
    IN AREA_INFORMATION Area,
    IN SCEFLAGTYPE nFlag,
    OUT PDWORD pTotalTicks
    )
/*
Routine Description:

    Retrieve the total count of objects from the inf template and/or the
    database for the area specified.

Arguments:

    TemplateName - the INF template Name

    Context      - the database context

    Area         - the security area

    nFlag - the flag to indicate operation which determines where the count is
            retrieved:

                SCE_FLAG_CONFIG
                SCE_FLAG_CONFIG_APPEND
                SCE_FLAG_ANALYZE
                SCE_FLAG_ANALYZE_APPEND

    pTotalTicks - the output count

Return Value:

    SCE Status
*/
{
    if ( pTotalTicks == NULL ||
        ( NULL == TemplateName && NULL == Context) ) {

        return(SCESTATUS_INVALID_PARAMETER);
    }

    SCESTATUS rc=SCESTATUS_SUCCESS;
    DWORD nTicks=0;

    *pTotalTicks = 0;
    gMaxRegTicks=0;
    gMaxFileTicks=0;
    gMaxDsTicks=0;

    if ( Area & (AREA_FILE_SECURITY |
                 AREA_REGISTRY_SECURITY) ) { // |
//                 AREA_DS_OBJECTS) ) {

        switch ( nFlag ) {
        case SCE_FLAG_CONFIG:
        case SCE_FLAG_CONFIG_APPEND:
        case SCE_FLAG_CONFIG_SCP:
        case SCE_FLAG_CONFIG_SCP_APPEND:

            if ( TemplateName != NULL ) {

                //
                // use the template if there is any
                //
                rc = ScepQueryInfTicks(
                            (LPTSTR)TemplateName,
                            Area & (AREA_FILE_SECURITY |
                                    AREA_REGISTRY_SECURITY), // |
//                                    AREA_DS_OBJECTS),
                            pTotalTicks
                            );
            }
            if ( Context != NULL &&
                 (nFlag == SCE_FLAG_CONFIG_APPEND ||
                  nFlag == SCE_FLAG_CONFIG_SCP_APPEND ||
                  TemplateName == NULL) ) {

                //
                // use the existing database
                //

                if ( Area & AREA_REGISTRY_SECURITY ) {

                    nTicks = 0;
                    rc = ScepGetObjectCount(Context,
                                            szRegistryKeys,
                                            (nFlag >= SCE_FLAG_CONFIG_SCP) ? TRUE : FALSE,
                                            &nTicks);
                    if ( SCESTATUS_SUCCESS == rc ) {
                        gMaxRegTicks += nTicks;
                        *pTotalTicks += nTicks;
                    }
                }
                if ( rc == SCESTATUS_SUCCESS && (Area & AREA_FILE_SECURITY) ) {

                    nTicks = 0;
                    rc = ScepGetObjectCount(Context,
                                             szFileSecurity,
                                             (nFlag >= SCE_FLAG_CONFIG_SCP) ? TRUE : FALSE,
                                             &nTicks);
                    if ( SCESTATUS_SUCCESS == rc ) {
                        gMaxFileTicks += nTicks;
                        *pTotalTicks += nTicks;
                    }
                }
#if 0
                if ( rc == SCESTATUS_SUCCESS && (Area & AREA_DS_OBJECTS) ) {

                    nTicks = 0;
                    rc = ScepGetObjectCount(Context,
                                        szDSSecurity,
                                        (nFlag >= SCE_FLAG_CONFIG_SCP) ? TRUE : FALSE,
                                        &nTicks);
                    if ( SCESTATUS_SUCCESS == rc ) {
                        gMaxDsTicks += nTicks;
                        *pTotalTicks += nTicks;
                    }
                }
#endif

            }

            break;
        case SCE_FLAG_ANALYZE:
        case SCE_FLAG_ANALYZE_APPEND:

            if ( Context != NULL ) {
                //
                // use the existing database
                //
                if ( Area & AREA_REGISTRY_SECURITY ) {

                    nTicks = 0;
                    rc = ScepGetObjectCount(Context,
                                             szRegistryKeys,
                                             (nFlag >= SCE_FLAG_CONFIG_SCP) ? TRUE : FALSE,
                                             &nTicks);
                    if ( SCESTATUS_SUCCESS == rc ) {
                        gMaxRegTicks += nTicks;
                        *pTotalTicks += nTicks;
                    }
                }
                if ( rc == SCESTATUS_SUCCESS &&
                     Area & AREA_FILE_SECURITY ) {

                    nTicks = 0;
                    rc = ScepGetObjectCount(Context,
                                             szFileSecurity,
                                             (nFlag >= SCE_FLAG_CONFIG_SCP) ? TRUE : FALSE,
                                             &nTicks);
                    if ( SCESTATUS_SUCCESS == rc ) {
                        gMaxFileTicks += nTicks;
                        *pTotalTicks += nTicks;
                    }
                }
#if 0
                if ( rc == SCESTATUS_SUCCESS &&
                    Area & AREA_DS_OBJECTS ) {

                    nTicks = 0;
                    rc = ScepGetObjectCount(Context,
                                        szDSSecurity,
                                        (nFlag >= SCE_FLAG_CONFIG_SCP) ? TRUE : FALSE,
                                        &nTicks);
                    if ( SCESTATUS_SUCCESS == rc ) {
                        gMaxDsTicks += nTicks;
                        *pTotalTicks += nTicks;
                    }
                }
#endif
            }

            if ( rc == SCESTATUS_SUCCESS && TemplateName != NULL &&
                 (nFlag == SCE_FLAG_ANALYZE_APPEND || Context == NULL) ) {

                //
                // get handle in template
                //

                DWORD nTempTicks=0;

                rc = ScepQueryInfTicks(
                            (LPTSTR)TemplateName,
                            Area & (AREA_FILE_SECURITY |
                                    AREA_REGISTRY_SECURITY), // |
//                                    AREA_DS_OBJECTS),
                            &nTempTicks
                            );
                if ( rc == SCESTATUS_SUCCESS ) {
                    *pTotalTicks += nTempTicks;
                }
            }

            break;
        default:
            return SCESTATUS_INVALID_PARAMETER;
        }
    }

    if ( rc == SCESTATUS_SUCCESS ) {

        if ( Area & AREA_SECURITY_POLICY )
            *pTotalTicks += TICKS_SECURITY_POLICY_DS + TICKS_SPECIFIC_POLICIES;

        if ( Area & AREA_GROUP_MEMBERSHIP )
            *pTotalTicks += TICKS_GROUPS;

        if ( Area & AREA_PRIVILEGES )
            *pTotalTicks += TICKS_PRIVILEGE;

        if ( Area & AREA_SYSTEM_SERVICE )
            *pTotalTicks += TICKS_GENERAL_SERVICES + TICKS_SPECIFIC_SERVICES;
/*
        if ( *pTotalTicks ) {
            *pTotalTicks += 10;  // for jet engine initialization
        }
*/
    }

    return(rc);

}


SCESTATUS
ScepQueryInfTicks(
    IN PWSTR TemplateName,
    IN AREA_INFORMATION Area,
    OUT PDWORD pTotalTicks
    )
/*
Routine Description:

    Query total number of objects in the inf template for the specified area.

Arguments:

Return:

*/
{
    LONG Count=0;
    HINF InfHandle;

    SCESTATUS rc = SceInfpOpenProfile(
                        TemplateName,
                        &InfHandle
                        );

    if ( rc == SCESTATUS_SUCCESS ) {

        if ( Area & AREA_REGISTRY_SECURITY ) {

            Count = SetupGetLineCount(InfHandle, szRegistryKeys);
            gMaxRegTicks += Count;

        }
        if ( Area & AREA_FILE_SECURITY ) {

            Count += SetupGetLineCount(InfHandle, szFileSecurity);
            gMaxFileTicks += Count;
        }
#if 0
        if ( Area & AREA_DS_OBJECTS ) {

            Count += SetupGetLineCount(InfHandle, szDSSecurity);
            gMaxDsTicks += Count;
        }
#endif
        SceInfpCloseProfile(InfHandle);
    }

    *pTotalTicks = Count;

    return(rc);
}



SCESTATUS
ScepGetObjectCount(
    IN PSCECONTEXT Context,
    IN PCWSTR SectionName,
    IN BOOL bPolicyProp,
    OUT PDWORD pTotalTicks
    )
{
    if ( Context == NULL || SectionName == NULL ||
         pTotalTicks == NULL ) {

        return(SCESTATUS_INVALID_PARAMETER);
    }

    PSCESECTION hSection=NULL;
    SCESTATUS rc;
    DWORD count=0;

    rc = ScepOpenSectionForName(
                Context,
                bPolicyProp ? SCE_ENGINE_SCP : SCE_ENGINE_SMP,
                SectionName,
                &hSection
                );

    if ( rc == SCESTATUS_SUCCESS ) {

        rc = SceJetGetLineCount(
                    hSection,
                    NULL,
                    FALSE,
                    &count
                    );

        if ( rc == SCESTATUS_SUCCESS )
            *pTotalTicks += count;

        SceJetCloseSection( &hSection, TRUE);
    }

    if ( SCESTATUS_RECORD_NOT_FOUND )
        rc = SCESTATUS_SUCCESS;

    return(rc);
}


BOOL
ScepIsEngineRecovering()
{
   TCHAR TempFileName[MAX_PATH];
   PWSTR SysRoot=NULL;
   DWORD SysLen;
   DWORD rc;
   intptr_t            hFile;
   struct _wfinddata_t    FileInfo;
   BOOL bFindIt=FALSE;

   SysLen =  0;
   rc = ScepGetNTDirectory( &SysRoot, &SysLen, SCE_FLAG_WINDOWS_DIR );

   if ( rc == NO_ERROR && SysRoot != NULL ) {

       swprintf(TempFileName, L"%s\\Security\\tmp.edb", SysRoot);
       TempFileName[MAX_PATH-1] = L'\0';

       hFile = _wfindfirst(TempFileName, &FileInfo);

       if ( hFile != -1 ) {

           bFindIt = TRUE;
           _findclose(hFile);
       }

       ScepFree(SysRoot);

   }

   return bFindIt;

}



SCESTATUS
ScepSaveAndOffAuditing(
    OUT PPOLICY_AUDIT_EVENTS_INFO *ppAuditEvent,
    IN BOOL bTurnOffAuditing,
    IN LSA_HANDLE PolicyHandle OPTIONAL
    )
{
    LSA_HANDLE      lsaHandle=NULL;
    NTSTATUS        status;
    SCESTATUS        rc;
    POLICY_AUDIT_EVENT_OPTIONS  lSaveAudit;

    //
    // open Lsa policy for read/write
    //

    if ( PolicyHandle == NULL ) {

        ACCESS_MASK  access=0;

        if ( bTurnOffAuditing ) {
            access = POLICY_SET_AUDIT_REQUIREMENTS | POLICY_AUDIT_LOG_ADMIN;
        }

        status = ScepOpenLsaPolicy(
                        POLICY_VIEW_AUDIT_INFORMATION | access,
                        &lsaHandle,
                        TRUE
                        );

        if (status != ERROR_SUCCESS) {

            lsaHandle = NULL;
            rc = RtlNtStatusToDosError( status );
            ScepLogOutput3( 1, rc, SCEDLL_LSA_POLICY);

            return(ScepDosErrorToSceStatus(rc));
        }

    } else {

        lsaHandle = PolicyHandle;
    }
    //
    // Query audit event information
    //

    status = LsaQueryInformationPolicy( lsaHandle,
                                      PolicyAuditEventsInformation,
                                      (PVOID *)ppAuditEvent
                                    );
    rc = RtlNtStatusToDosError( status );

    if ( NT_SUCCESS( status ) && bTurnOffAuditing && (*ppAuditEvent)->AuditingMode ) {

        //
        // turn off object access auditing
        //
        if ( AuditCategoryObjectAccess < (*ppAuditEvent)->MaximumAuditEventCount ) {
            lSaveAudit = (*ppAuditEvent)->EventAuditingOptions[AuditCategoryObjectAccess];
            (*ppAuditEvent)->EventAuditingOptions[AuditCategoryObjectAccess] = POLICY_AUDIT_EVENT_NONE;

            status = LsaSetInformationPolicy( lsaHandle,
                                              PolicyAuditEventsInformation,
                                              (PVOID)(*ppAuditEvent)
                                            );

            //
            // restore the object access auditing mode
            //

            (*ppAuditEvent)->EventAuditingOptions[AuditCategoryObjectAccess] = lSaveAudit;

        }

        rc = RtlNtStatusToDosError( status );


        if ( rc == NO_ERROR )
            ScepLogOutput3( 2, 0, SCEDLL_EVENT_IS_OFF);
        else
            ScepLogOutput3( 1, rc, SCEDLL_SCP_ERROR_EVENT_AUDITING);

    } else if ( rc != NO_ERROR)
        ScepLogOutput3( 1, rc, SCEDLL_ERROR_QUERY_EVENT_AUDITING);

    //
    // free LSA handle if it's opened in this function
    //
    if ( lsaHandle && (PolicyHandle == NULL) )
        LsaClose( lsaHandle );

    return(ScepDosErrorToSceStatus(rc));
}


NTSTATUS
ScepGetAccountExplicitRight(
    IN LSA_HANDLE PolicyHandle,
    IN PSID       AccountSid,
    OUT PDWORD    PrivilegeLowRights,
    OUT PDWORD    PrivilegeHighRights
    )
/* ++
Routine Description:

    This routine queries the explicitly assigned privilege/rights to a account
    (referenced by AccountSid) and stores in a DWORD type variable PrivilegeRights,
    in which each bit represents a privilege/right.

Arguments:

    PolicyHandle    - Lsa Policy Domain handle

    AccountSid      - The SID for the account

    PrivilegeRights - Privilege/Rights of this account

Return value:

    NTSTATUS
-- */
{
    NTSTATUS            NtStatus;

    DWORD               CurrentPrivLowRights=0, CurrentPrivHighRights=0;
    LONG                index;
    PUNICODE_STRING     UserRightEnum=NULL;
    ULONG               i, cnt=0;
    LUID                LuidValue;

    //
    // Enumerate user privilege/rights
    //

    NtStatus = LsaEnumerateAccountRights(
                    PolicyHandle,
                    AccountSid,
                    &UserRightEnum,
                    &cnt
                    );
    if ( NtStatus == STATUS_NO_SUCH_PRIVILEGE ||
        NtStatus == STATUS_OBJECT_NAME_NOT_FOUND ) {

        NtStatus = ERROR_SUCCESS;
        goto Done;
    }

    if ( !NT_SUCCESS( NtStatus) ) {
        ScepLogOutput3(1,
                       RtlNtStatusToDosError(NtStatus),
                       SCEDLL_SAP_ERROR_ENUMERATE,
                       L"LsaEnumerateAccountRights");
        goto Done;
    }

    if (UserRightEnum != NULL)

        for ( i=0; i < cnt; i++) {
            if ( UserRightEnum[i].Length == 0 )
                continue;

            NtStatus = LsaLookupPrivilegeValue(
                            PolicyHandle,
                            &UserRightEnum[i],
                            &LuidValue
                            );

            if ( NtStatus == STATUS_NO_SUCH_PRIVILEGE ) {
                index = ScepLookupPrivByName( UserRightEnum[i].Buffer );
                NtStatus = ERROR_SUCCESS;
            } else if ( NT_SUCCESS(NtStatus) ) {
                index = ScepLookupPrivByValue( LuidValue.LowPart );
            } else
                index = -1;

            if ( index == -1 ) {

                //
                // not found
                //

                NtStatus = STATUS_NOT_FOUND;
                ScepLogOutput3(1,
                               RtlNtStatusToDosError(NtStatus),
                               SCEDLL_USERRIGHT_NOT_DEFINED);
                goto Done;

            } else {
                if ( index < 32 ) {
                    CurrentPrivLowRights |= (1 << index);
                } else {
                    CurrentPrivHighRights |= (1 << (index-32) );
                }
            }
        }

Done:

    *PrivilegeLowRights = CurrentPrivLowRights;
    *PrivilegeHighRights = CurrentPrivHighRights;

    if (UserRightEnum != NULL)
        LsaFreeMemory(UserRightEnum);

    return (NtStatus);
}


NTSTATUS
ScepGetMemberListSids(
    IN PSID         DomainSid,
    IN LSA_HANDLE   PolicyHandle,
    IN PSCE_NAME_LIST pMembers,
    OUT PUNICODE_STRING *MemberNames,
    OUT PSID**      Sids,
    OUT PULONG      MemberCount
    )
/*
Routine Description:

    Lookup each account in the name list pMembers and return the lookup information
    in the output buffer - MemberNames, Sids, MemberCount.

    if an account can't be resolved, the corresponding SID will be empty.

*/
{
    NTSTATUS                    NtStatus=STATUS_SUCCESS;
    PSCE_NAME_LIST               pUser;

    PLSA_REFERENCED_DOMAIN_LIST ReferencedDomains=NULL;
    PLSA_TRANSLATED_SID2        MemberSids=NULL;
    DWORD                       i;
    PSID                        DomainSidToUse=NULL;
    ULONG                       Cnt=0;

    //
    // build a UNICODE_STRING for the member list to look up
    //
    for (pUser=pMembers;
         pUser != NULL;
         pUser = pUser->Next) {

        if ( pUser->Name == NULL ) {
            continue;
        }
        Cnt++;
    }

    if ( Cnt > 0 ) {

        *MemberNames = (PUNICODE_STRING)RtlAllocateHeap(
                                        RtlProcessHeap(),
                                        0,
                                        Cnt * sizeof (UNICODE_STRING)
                                        );
        
        if ( *MemberNames == NULL )
            return(STATUS_NO_MEMORY);
                
        *Sids = (PSID *)ScepAlloc( LMEM_ZEROINIT, Cnt*sizeof(PSID));
        if ( *Sids == NULL ) {
            NtStatus = STATUS_NO_MEMORY;
            goto Done;
        }
        
        //
        // Lookup each UNICODE_STRING
        //
        
        for (pUser=pMembers, Cnt=0;
             pUser != NULL;
             pUser = pUser->Next) {

            if ( pUser->Name == NULL ) {
                continue;
            }

            RtlInitUnicodeString(&((*MemberNames)[Cnt]), pUser->Name);
            
            NtStatus = ScepLsaLookupNames2(
                                          PolicyHandle,
                                          LSA_LOOKUP_ISOLATED_AS_LOCAL,
                                          pUser->Name,
                                          &ReferencedDomains,
                                          &MemberSids
                                          );

            if ( !NT_SUCCESS(NtStatus) ) {
                ScepLogOutput3(1, RtlNtStatusToDosError(NtStatus),
                               SCEDLL_ERROR_LOOKUP);
                goto NextMember;
            }
            
            DWORD SidLength=0;
            
            //
            // translate the LSA_TRANSLATED_SID into PSID
            //
            
            if ( MemberSids[0].Use != SidTypeInvalid &&
                 MemberSids[0].Use != SidTypeUnknown &&
                 MemberSids[0].Sid != NULL ) {

                SidLength = RtlLengthSid(MemberSids[0].Sid);

                if ( ((*Sids)[Cnt] = (PSID) ScepAlloc( (UINT)0, SidLength)) == NULL ) {
                    NtStatus = STATUS_NO_MEMORY;
                } else {

                    //
                    // copy the SID
                    // if failed, memory will be freed at cleanup
                    //

                    NtStatus = RtlCopySid( SidLength, (*Sids)[Cnt], MemberSids[0].Sid );

                }

                if ( !NT_SUCCESS(NtStatus) ) {
                    goto Done;
                }
            }

NextMember:

            if ( ReferencedDomains != NULL ){
                LsaFreeMemory(ReferencedDomains);
                ReferencedDomains = NULL;
            }

            if ( MemberSids != NULL ){
                LsaFreeMemory(MemberSids);
                MemberSids = NULL;
            }
            
            Cnt++;
        }
        
    }
    *MemberCount = Cnt;
Done:

    if (!NT_SUCCESS(NtStatus) ) {
        if ( *Sids != NULL ) {
            for ( i=0; i<Cnt; i++ )
                if ( (*Sids)[i] != NULL )
                    ScepFree( (*Sids)[i] );
            ScepFree( *Sids );
            *Sids = NULL;
        }
        if ( *MemberNames != NULL )
            RtlFreeHeap(RtlProcessHeap(), 0, *MemberNames);
        *MemberNames = NULL;
    }
    if ( ReferencedDomains != NULL )
        LsaFreeMemory(ReferencedDomains);

    if ( MemberSids != NULL )
        LsaFreeMemory(MemberSids);

    return(NtStatus);
}


DWORD
ScepOpenFileObject(
    IN  LPWSTR       pObjectName,
    IN  ACCESS_MASK  AccessMask,
    OUT PHANDLE      Handle
    )
/*++
Routine Description:

    opens the specified file (or directory) object

Arguments:

    pObjectName   - the name of the file object

    AccessMask    - Desired Access

    Handle        - the just opened handle to the object

Return value:

    Win32 errro code
*/
{
    NTSTATUS NtStatus;
    DWORD Status = ERROR_SUCCESS;
    OBJECT_ATTRIBUTES Attributes;
    IO_STATUS_BLOCK Isb;
    UNICODE_STRING FileName;
    RTL_RELATIVE_NAME RelativeName;
    PVOID FreeBuffer;

    //
    // cut and paste code from windows\base\advapi\security.c SetFileSecurityW
    //
    if (RtlDosPathNameToNtPathName_U(
                            pObjectName,
                            &FileName,
                            NULL,
                            &RelativeName
                            ))
    {
        FreeBuffer = FileName.Buffer;

        if ( RelativeName.RelativeName.Length ) {
            FileName = *(PUNICODE_STRING)&RelativeName.RelativeName;
        }
        else {
            RelativeName.ContainingDirectory = NULL;
        }

        InitializeObjectAttributes(
            &Attributes,
            &FileName,
            OBJ_CASE_INSENSITIVE,
            RelativeName.ContainingDirectory,
            NULL
            );


        NtStatus = NtOpenFile( Handle,
                               AccessMask,
                               &Attributes,
                               &Isb,
                               FILE_SHARE_READ |
                               FILE_SHARE_WRITE |
                               FILE_SHARE_DELETE,
                               0);

        if (!NT_SUCCESS(NtStatus))
        {
            Status = RtlNtStatusToDosError(NtStatus);
        }

        RtlFreeHeap(RtlProcessHeap(), 0,FreeBuffer);
    } else
    {
        Status = ERROR_INVALID_NAME;
    }

    return(Status);
}


DWORD
ScepOpenRegistryObject(
    IN  SE_OBJECT_TYPE  ObjectType,
    IN  LPWSTR       pObjectName,
    IN  ACCESS_MASK  AccessMask,
    OUT PHKEY        Handle
    )
/*++
Routine Description:

    opens the specified registry key object

Arguments:

    pObjectName  - the name of the object

    AccessMask   - Desired access

    Handle      - the just opened handle to the object

Return value:

    Win32 error code

Note:
    The code is cut/pasted from windows\base\accctrl\src\registry.cxx and modified
--*/
{
    DWORD status=NO_ERROR;
    HKEY basekey;
    LPWSTR usename, basekeyname, keyname;

    if (pObjectName) {

        //
        // save a copy of the name since we must crack it.
        //
        if (NULL != (usename = (LPWSTR)ScepAlloc( LMEM_ZEROINIT,
                               (wcslen(pObjectName) + 1) * sizeof(WCHAR)))) {

            wcscpy(usename,pObjectName);

            basekeyname = usename;
            keyname = wcschr(usename, L'\\');
            if (keyname != NULL) {
                *keyname = L'\0';
                keyname++;
            }

            if (0 == _wcsicmp(basekeyname, L"MACHINE")) {
                basekey = HKEY_LOCAL_MACHINE;
            } else if (0 == _wcsicmp(basekeyname, L"USERS")) {
                basekey = HKEY_USERS;
            } else if ( 0 == _wcsicmp(basekeyname, L"CLASSES_ROOT")) {
                basekey = HKEY_CLASSES_ROOT;
            } else {
                status = ERROR_INVALID_PARAMETER;
            }

            if (NO_ERROR == status) {
                if ( keyname == NULL ) {
                    *Handle = basekey;
                } else {
                    //
                    // open the key
                    //

#ifdef _WIN64
                    if (ObjectType == SE_REGISTRY_WOW64_32KEY) {
                        AccessMask |= KEY_WOW64_32KEY;
                    }
#endif

                    status = RegOpenKeyEx(
                                  basekey,
                                  keyname,
                                  0 ,
                                  AccessMask,
                                  Handle
                                  );
                }
            }
            ScepFree(usename);
        } else {
            status = ERROR_NOT_ENOUGH_MEMORY;
        }
    } else {
        status = ERROR_INVALID_NAME;
    }

    return(status);
}



SCESTATUS
ScepGetNameInLevel(
    IN PCWSTR ObjectFullName,
    IN DWORD  Level,
    IN WCHAR  Delim,
    OUT PWSTR Buffer,
    OUT PBOOL LastOne
    )
/* ++
Routine Description:

    This routine parses a full path name and returns the component for the
    level. For example, a object name "c:\winnt\system32" will return c: for
    level 1, winnt for level 2, and system32 for level 3. This routine is
    used when add a object to the security tree.

Arguments:

    ObjectFullName - The full path name of the object

    Level - the level of component to return

    Delim - the deliminator to look for

    Buffer - The address of buffer for the component name

    LastOne - Flag to indicate if the component is the last one

Return value:

    SCESTATUS

-- */
{
    PWSTR  pTemp, pStart;
    DWORD i;

    if ( ObjectFullName == NULL )
        return(SCESTATUS_INVALID_PARAMETER);

    //
    // loop through the object name to find the level
    // if there is no such level, return INVALID_PARAMETER
    //
    pStart = (PWSTR)ObjectFullName;
    for ( i=0; i<Level; i++) {

        pTemp = wcschr(pStart, Delim);

        if ( pTemp == pStart ) {
            return(SCESTATUS_INVALID_PARAMETER);
        }

        if ( i == Level-1 ) {
            //
            // find the right level
            //
            if ( pTemp == NULL ) {
                wcscpy(Buffer, pStart);
                *LastOne = TRUE;
            } else {
                wcsncpy(Buffer, pStart, (size_t)(pTemp - pStart));
                if ( *(pTemp+1) == L'\0' )
                    *LastOne = TRUE;
                else
                    *LastOne = FALSE;
            }
        } else {
            if ( pTemp == NULL )
                return(SCESTATUS_INVALID_PARAMETER);
            else
                pStart = pTemp + 1;
        }
    }

    return(SCESTATUS_SUCCESS);

}

SCESTATUS
ScepTranslateFileDirName(
   IN  PWSTR oldFileName,
   OUT PWSTR *newFileName
   )
/* ++
Routine Description:

   This routine converts a generic file/directory name to a real used name
   for the current system. The following generic file/directory names are handled:
         %systemroot%   - Windows NT root directory (e.g., c:\winnt)
         %systemDirectory% - Windows NT system32 directory (e.g., c:\winnt\system32)

Arguments:

   oldFileName - the file name to convert, which includes "%" to represent
                 some directory names

   newFileName - the real file name, in which the "%" name is replaced with
                 the real directory name

Return values:

   Win32 error code

-- */
{
    PWSTR   pTemp=NULL, pStart, TmpBuf, szVar;
    DWORD   rc=NO_ERROR;
    DWORD   newFileSize, cSize;
    BOOL    bContinue;

    //
    // match for %systemroot%
    //

    rc = ScepExpandEnvironmentVariable(oldFileName,
                                       L"%SYSTEMROOT%",
                                       SCE_FLAG_WINDOWS_DIR,
                                       newFileName);

    if ( rc != ERROR_FILE_NOT_FOUND ) {
        return rc;
    }

    //
    // match for %systemdirectory%
    //

    rc = ScepExpandEnvironmentVariable(oldFileName,
                                       L"%SYSTEMDIRECTORY%",
                                       SCE_FLAG_SYSTEM_DIR,
                                       newFileName);

    if ( rc != ERROR_FILE_NOT_FOUND ) {
        return rc;
    }

    //
    // match for systemdrive
    //

    rc = ScepExpandEnvironmentVariable(oldFileName,
                                       L"%SYSTEMDRIVE%",
                                       SCE_FLAG_WINDOWS_DIR,
                                       newFileName);

    if ( rc != ERROR_FILE_NOT_FOUND ) {
        return rc;
    }

    //
    // match for boot drive
    //

    rc = ScepExpandEnvironmentVariable(oldFileName,
                                       L"%BOOTDRIVE%",
                                       SCE_FLAG_BOOT_DRIVE,
                                       newFileName);

    if ( rc != ERROR_FILE_NOT_FOUND ) {
        return rc;
    }

    rc = ERROR_SUCCESS;
    //
    // search for environment variable in the current process
    //
    pStart = wcschr(oldFileName, L'%');

    if ( pStart ) {
        pTemp = wcschr(pStart+1, L'%');
        if ( pTemp ) {

            bContinue = TRUE;
            //
            // find a environment variable to translate
            //
            TmpBuf = (PWSTR)ScepAlloc(0, ((UINT)(pTemp-pStart))*sizeof(WCHAR));
            if ( TmpBuf ) {

                wcsncpy(TmpBuf, pStart+1, (size_t)(pTemp-pStart-1));
                TmpBuf[pTemp-pStart-1] = L'\0';

                //
                // try search in the client environment block
                //

                szVar = ScepSearchClientEnv(TmpBuf, (DWORD)(pTemp-pStart-1));

                if ( szVar ) {

//                        ScepLogOutput2(3,0,L"\tFind client env %s=%s", TmpBuf, szVar);
                    //
                    // find it in the client's environment block, use it
                    // get info in szVar
                    //
                    bContinue = FALSE;

                    newFileSize = ((DWORD)(pStart-oldFileName))+wcslen(szVar)+wcslen(pTemp+1)+1;

                    *newFileName = (PWSTR)ScepAlloc(0, newFileSize*sizeof(TCHAR));

                    if (*newFileName ) {
                        if ( pStart != oldFileName ) {
                            wcsncpy(*newFileName, oldFileName, (size_t)(pStart-oldFileName));
                        }

                        swprintf((PWSTR)(*newFileName+(pStart-oldFileName)), L"%s%s", szVar, pTemp+1);

                    } else {
                        rc = ERROR_NOT_ENOUGH_MEMORY;
                    }
                    //
                    // DO NOT free szVar because it's a ref pointer to the env block
                    //
                } else {

                    cSize = GetEnvironmentVariable( TmpBuf,
                                                NULL,
                                                0 );

                    if ( cSize > 0 ) {
                    //
                    // does not find it in the client environment block,
                    // find it in the current server process environment, use it
                    //
                        szVar = (PWSTR)ScepAlloc(0, (cSize+1)*sizeof(WCHAR));

                        if ( szVar ) {
                            cSize = GetEnvironmentVariable(TmpBuf,
                                                       szVar,
                                                       cSize);
                            if ( cSize > 0 ) {
                                //
                                // get info in szVar
                                //
                                bContinue = FALSE;

                                newFileSize = ((DWORD)(pStart-oldFileName))+cSize+wcslen(pTemp+1)+1;

                                *newFileName = (PWSTR)ScepAlloc(0, newFileSize*sizeof(TCHAR));

                                if (*newFileName ) {
                                    if ( pStart != oldFileName )
                                        wcsncpy(*newFileName, oldFileName, (size_t)(pStart-oldFileName));

                                    swprintf((PWSTR)(*newFileName+(pStart-oldFileName)), L"%s%s", szVar, pTemp+1);

                                } else
                                    rc = ERROR_NOT_ENOUGH_MEMORY;
                            }

                            ScepFree(szVar);

                        } else
                            rc = ERROR_NOT_ENOUGH_MEMORY;

                    }
                }

                ScepFree(TmpBuf);

            } else
                rc = ERROR_NOT_ENOUGH_MEMORY;

            if ( NO_ERROR != rc || !bContinue ) {
                //
                // if errored, or do not continue
                //
                return(rc);
            }

            //
            // not found in environment blob,
            // continue to search for DSDIT/DSLOG/SYSVOL in registry
            //
            if ( ProductType == NtProductLanManNt ) {

                //
                // search for DSDIT
                //

                rc = ScepExpandEnvironmentVariable(oldFileName,
                                                   L"%DSDIT%",
                                                   SCE_FLAG_DSDIT_DIR,
                                                   newFileName);

                if ( rc != ERROR_FILE_NOT_FOUND ) {
                    return rc;
                }

                //
                // search for DSLOG
                //

                rc = ScepExpandEnvironmentVariable(oldFileName,
                                                   L"%DSLOG%",
                                                   SCE_FLAG_DSLOG_DIR,
                                                   newFileName);

                if ( rc != ERROR_FILE_NOT_FOUND ) {
                    return rc;
                }

                //
                // search for SYSVOL
                //
                rc = ScepExpandEnvironmentVariable(oldFileName,
                                                   L"%SYSVOL%",
                                                   SCE_FLAG_SYSVOL_DIR,
                                                   newFileName);

                if ( rc != ERROR_FILE_NOT_FOUND ) {
                    return rc;
                }

            }

        }
    }
    //
    // Otherwise, just copy the old name to a new buffer and return ERROR_PATH_NOT_FOUND
    //
    *newFileName = (PWSTR)ScepAlloc(0, (wcslen(oldFileName)+1)*sizeof(TCHAR));

    if (*newFileName != NULL) {
        wcscpy(*newFileName, _wcsupr(oldFileName) );
        rc = ERROR_PATH_NOT_FOUND;
    } else
        rc = ERROR_NOT_ENOUGH_MEMORY;

    return(rc);

}

LPTSTR
ScepSearchClientEnv(
    IN LPTSTR varName,
    IN DWORD dwSize
    )
{
    if ( !varName || dwSize == 0 ||
         !t_pebClient || t_pebSize == 0 ) {
        return NULL;
    }

    LPTSTR pTemp = (LPTSTR)t_pebClient;

    while ( pTemp && *pTemp != L'\0' ) {


        if ( _wcsnicmp(varName, pTemp, dwSize) == 0 &&
             L'=' == *(pTemp+dwSize) ) {
            //
            // find the variable
            //
            return pTemp+dwSize+1;
            break;
        }
        DWORD Len = wcslen(pTemp);
        pTemp += Len+1;
    }

    return NULL;
}


SCESTATUS
ScepConvertLdapToJetIndexName(
    IN PWSTR TempName,
    OUT PWSTR *OutName
    )
{
    PWSTR pTemp1;
    PWSTR pTemp2;
    INT i,j;
    DWORD Len;

    //
    // Ldap name are in the format of CN=,DC=,...O=
    // Jet Index requires names in the O=,...DC=,CN= format
    //
    // semicolon is converted to , and spaces are stripped out
    //
    if ( TempName == NULL || OutName == NULL ) {
        return(SCESTATUS_INVALID_PARAMETER);
    }

    Len = wcslen(TempName);
    pTemp1 = TempName + Len - 1;

    //
    // skip the trailing spaces, commas, or semicolons
    //
    while ( pTemp1 >= TempName &&
            (*pTemp1 == L' ' || *pTemp1 == L';' || *pTemp1 == L',') ) {
        pTemp1--;
    }

    if ( pTemp1 < TempName ) {
        //
        // all spaces or ; in the name
        //
        return(SCESTATUS_INVALID_PARAMETER);
    }

    //
    // allocate output buffer
    //
    *OutName = (PWSTR)ScepAlloc(0, ((UINT)(pTemp1-TempName+2))*sizeof(WCHAR));
    if ( *OutName != NULL ) {

        pTemp2 = *OutName;

        while ( pTemp1 >= TempName ) {

            //
            // find the previous ; or ,
            //
            i = 0;
            while ( pTemp1-i >= TempName && *(pTemp1-i) != L',' &&
                    *(pTemp1-i) != L';' ) {
                i++;
            }
            //
            // either reach the head, or a ; or , is encountered
            //
            i--;   // i must be >= 0

            //
            // skip the leading spaces
            //
            j = 0;
            while ( *(pTemp1-i+j) == L' ' && j <= i ) {
                j++;
            }
            //
            // copy the component
            //
            if ( i >= j ) {

                if ( pTemp2 != *OutName ) {
                    *pTemp2++ = L',';
                }
                wcsncpy(pTemp2, pTemp1-i+j, i-j+1);
                pTemp2 += (i-j+1);

            } else {
                //
                // all spaces
                //
            }
            pTemp1 -= (i+1);
            //
            // skip the trailing spaces, commas, or semicolons
            //
            while ( pTemp1 >= TempName &&
                    (*pTemp1 == L' ' || *pTemp1 == L';' || *pTemp1 == L',') ) {
                pTemp1--;
            }
        }
        if ( pTemp2 == *OutName ) {
            //
            // nothing got copied to the output buffer, WRONG!!!
            //
            ScepFree(*OutName);
            *OutName = NULL;
            return(SCESTATUS_INVALID_PARAMETER);

        } else {
            //
            // teminate the string
            //
            *pTemp2 = L'\0';
            _wcslwr(*OutName);

            return(SCESTATUS_SUCCESS);
        }

    } else
        return(SCESTATUS_NOT_ENOUGH_RESOURCE);
}



SCESTATUS
ScepRestoreAuditing(
    IN PPOLICY_AUDIT_EVENTS_INFO auditEvent,
    IN LSA_HANDLE PolicyHandle OPTIONAL
    )
{
    LSA_HANDLE      lsaHandle=NULL;
    NTSTATUS        status;
    SCESTATUS        rc;

    if ( auditEvent == NULL )
        return(SCESTATUS_INVALID_PARAMETER);

    if ( PolicyHandle == NULL ) {

        // open Lsa policy for read/write
        status = ScepOpenLsaPolicy(
                        POLICY_VIEW_AUDIT_INFORMATION |
                        POLICY_SET_AUDIT_REQUIREMENTS |
                        POLICY_AUDIT_LOG_ADMIN,
                        &lsaHandle,
                        TRUE
                        );

        if (status != ERROR_SUCCESS) {

            lsaHandle = NULL;
            rc = RtlNtStatusToDosError( status );
            ScepLogOutput3( 1, rc, SCEDLL_LSA_POLICY);

            return(ScepDosErrorToSceStatus(rc));
        }

    } else {
        lsaHandle = PolicyHandle;
    }

    // restore
    status = LsaSetInformationPolicy( lsaHandle,
                                      PolicyAuditEventsInformation,
                                      (PVOID)(auditEvent)
                                    );
    rc = RtlNtStatusToDosError( status );

    if ( rc == NO_ERROR )
        ScepLogOutput3( 2, 0, SCEDLL_EVENT_RESTORED);
    else
        ScepLogOutput3( 1, rc, SCEDLL_SCP_ERROR_EVENT_AUDITING);

    if ( lsaHandle && (lsaHandle != PolicyHandle) )
        LsaClose( lsaHandle );

    return(ScepDosErrorToSceStatus(rc));

}


DWORD
ScepGetDefaultDatabase(
    IN LPCTSTR JetDbName OPTIONAL,
    IN DWORD LogOptions,
    IN LPCTSTR LogFileName OPTIONAL,
    OUT PBOOL pAdminLogon OPTIONAL,
    OUT PWSTR *ppDefDatabase
    )
/*
Routine Description:

    Get the default SCE database for the current logged on user.

Arguments:

    JetDbName   - optional jet database name

    LogOptions  - options for the log, if there is any

    LogFileName - the log file

    pAdminLogon - output flag to indicate if administrative privileged user logged on

    ppDefDatabase - the default database name

Return Value:

    SCESTATUS
*/
{
    if ( !ppDefDatabase ) {
        return(ERROR_INVALID_PARAMETER);
    }

    if ( LogOptions & SCE_DISABLE_LOG) {

        ScepEnableDisableLog(FALSE);
    } else {
        ScepEnableDisableLog(TRUE);
    }

    if ( LogOptions & SCE_DEBUG_LOG ) {

        ScepSetVerboseLog(3);

    } else if ( LogOptions & SCE_VERBOSE_LOG ) {
        //
        // by default it's not verbose
        //
        ScepSetVerboseLog(2);

    } else {
        ScepSetVerboseLog(-1);
    }

    if ( ScepLogInitialize( LogFileName ) == ERROR_INVALID_NAME ) {
        ScepLogOutput3(1,0, SCEDLL_LOGFILE_INVALID, LogFileName );
    }


    DWORD rc=ERROR_SUCCESS;
    BOOL bAdminLogon=FALSE;

    //
    // determine if admin logs on
    //

    if ( pAdminLogon || !JetDbName || wcslen(JetDbName) < 1) {

        rc = ScepIsAdminLoggedOn(&bAdminLogon);
        if ( rc != NO_ERROR ) {
            ScepLogOutput3(1, rc, SCEDLL_UNKNOWN_LOGON_USER);
        }

        if ( bAdminLogon ) {
            ScepLogOutput3(3, 0, SCEDLL_ADMIN_LOGON);
        }
    }

    //
    // find the databae name
    //

    if ( JetDbName && wcslen(JetDbName) > 0 ) {

        *ppDefDatabase = (LPTSTR)JetDbName;

    } else {

        //
        // query if the profile name (or the default ) in registry
        //

        rc = ScepGetProfileSetting(
                L"DefaultProfile",
                bAdminLogon,
                ppDefDatabase
                );

        if ( rc != NO_ERROR || *ppDefDatabase == NULL ) {   // return is Win32 error code
            ScepLogOutput3(1,rc, SCEDLL_UNKNOWN_DBLOCATION);
        }
    }

    if ( pAdminLogon ) {
        *pAdminLogon = bAdminLogon;
    }

    return(rc);

}



BOOL
ScepIsDomainLocal(
    IN PUNICODE_STRING pDomainName OPTIONAL
    )
/* ++
Routine Description:

    This routine checks if the domain is on the local machine by comparing
    the domain name with the local machine's computer name.

Arguments:

    pDomainName - the domain's name to check

Return Value:

    TRUE if it is local

-- */
{
    NTSTATUS                     NtStatus;
    OBJECT_ATTRIBUTES            ObjectAttributes;
    LSA_HANDLE                   PolicyHandle;
    DWORD                        NameLen=MAX_COMPUTERNAME_LENGTH;


    if ( pDomainName == NULL ) {
        //
        // reset the buffer
        //
        ComputerName[0] = L'\0';
        theAcctDomName[0] = L'\0';
        sidBuiltinBuf[0] = '\0';
        sidAuthBuf[0] = '\0';

        return(TRUE);
    }

    if ( pDomainName->Length <= 0 ||
         pDomainName->Buffer == NULL )
        return(TRUE);

    if ( ComputerName[0] == L'\0' ) {
        memset(ComputerName, '\0', (MAX_COMPUTERNAME_LENGTH+1)*sizeof(WCHAR));
        GetComputerName(ComputerName, &NameLen);
    }

    NameLen = wcslen(ComputerName);

    if ( _wcsnicmp(ComputerName, pDomainName->Buffer, pDomainName->Length/2 ) == 0 &&
         (LONG)NameLen == pDomainName->Length/2 )
        return(TRUE);

    if ( theAcctDomName[0] == L'\0' ) {

        //
        // query the current account domain name (for DC case)
        //

        PPOLICY_ACCOUNT_DOMAIN_INFO  PolicyAccountDomainInfo=NULL;

        //
        // Open the policy database
        //

        InitializeObjectAttributes( &ObjectAttributes,
                                      NULL,             // Name
                                      0,                // Attributes
                                      NULL,             // Root
                                      NULL );           // Security Descriptor

        NtStatus = LsaOpenPolicy( NULL,
                                &ObjectAttributes,
                                POLICY_VIEW_LOCAL_INFORMATION,
                                &PolicyHandle );
        if ( NT_SUCCESS(NtStatus) ) {

            //
            // Query the account domain information
            //

            NtStatus = LsaQueryInformationPolicy( PolicyHandle,
                                                PolicyAccountDomainInformation,
                                                (PVOID *)&PolicyAccountDomainInfo );

            LsaClose( PolicyHandle );
        }

        if ( NT_SUCCESS(NtStatus) ) {

            if ( PolicyAccountDomainInfo->DomainName.Buffer ) {

                wcsncpy(theAcctDomName,
                        PolicyAccountDomainInfo->DomainName.Buffer,
                        PolicyAccountDomainInfo->DomainName.Length/2);

                theAcctDomName[PolicyAccountDomainInfo->DomainName.Length/2] = L'\0';


            }
            LsaFreeMemory(PolicyAccountDomainInfo);
        }
    }

    NameLen = wcslen(theAcctDomName);

    if ( _wcsnicmp(theAcctDomName, pDomainName->Buffer, pDomainName->Length/2) == 0 &&
         (LONG)NameLen == pDomainName->Length/2 )
        return(TRUE);
    else
        return(FALSE);

}


BOOL
ScepIsDomainLocalBySid(
    PSID pSidLookup
    )
{

    if ( pSidLookup == NULL ) {
        return FALSE;
    }

    NTSTATUS                     NtStatus;
    SID_IDENTIFIER_AUTHORITY     NtAuthority = SECURITY_NT_AUTHORITY;

    //
    // search for "NT Authority" name
    //
    if ( sidAuthBuf[0] == '\0' ) {  // sid revision can't be 0

        //
        // build the NT authority sid
        //
        NtStatus = RtlInitializeSid(
                        (PSID)sidAuthBuf,
                        &NtAuthority,
                        0
                        );

        if ( !NT_SUCCESS(NtStatus) ) {

            sidAuthBuf[0] = '\0';
        }

    }

    if ( sidAuthBuf[0] != '\0' &&
         RtlEqualSid((PSID)sidAuthBuf, pSidLookup) ) {

        return(TRUE);
    }

    if ( sidBuiltinBuf[0] == '\0' ) {
        //
        // build the builtin domain sid
        //

        NtStatus = RtlInitializeSid(
                        (PSID)sidBuiltinBuf,
                        &NtAuthority,
                        1
                        );

        if ( NT_SUCCESS(NtStatus) ) {

            *(RtlSubAuthoritySid((PSID)sidBuiltinBuf, 0)) = SECURITY_BUILTIN_DOMAIN_RID;

        } else {

            sidBuiltinBuf[0] = '\0';
        }
    }

    if ( sidBuiltinBuf[0] != '\0' &&
         RtlEqualSid((PSID)sidBuiltinBuf, pSidLookup) ) {

        return(TRUE);

    } else {

        return(FALSE);
    }

}


NTSTATUS
ScepAddAdministratorToThisList(
    IN SAM_HANDLE DomainHandle OPTIONAL,
    IN OUT PSCE_NAME_LIST *ppList
    )
{
    NTSTATUS NtStatus;
    SAM_HANDLE          AccountDomain=NULL;
    SAM_HANDLE          UserHandle=NULL;
    SAM_HANDLE          ServerHandle=NULL;
    PSID                DomainSid=NULL;

    USER_NAME_INFORMATION *BufName=NULL;
    DOMAIN_NAME_INFORMATION *DomainName=NULL;
    PSCE_NAME_LIST        pName=NULL;

    if (!ppList ) {
        return(STATUS_INVALID_PARAMETER);
    }

    if ( !DomainHandle ) {

        //
        // open the sam account domain
        //

        NtStatus = ScepOpenSamDomain(
                        SAM_SERVER_ALL_ACCESS,
                        MAXIMUM_ALLOWED,
                        &ServerHandle,
                        &AccountDomain,
                        &DomainSid,
                        NULL,
                        NULL
                        );

        if ( !NT_SUCCESS(NtStatus) ) {
            ScepLogOutput3(1,RtlNtStatusToDosError(NtStatus),
                           SCEDLL_ERROR_OPEN, L"SAM");
            return(NtStatus);
        }

    } else {
        AccountDomain = DomainHandle;
    }

    //
    // query account domain name
    //
    NtStatus = SamQueryInformationDomain(
                    AccountDomain,
                    DomainNameInformation,
                    (PVOID *)&DomainName
                    );

    if ( NT_SUCCESS( NtStatus ) && DomainName &&
         DomainName->DomainName.Length > 0 && DomainName->DomainName.Buffer ) {

        NtStatus = SamOpenUser(
                      AccountDomain,
                      MAXIMUM_ALLOWED,
                      DOMAIN_USER_RID_ADMIN,
                      &UserHandle
                      );

        if ( NT_SUCCESS( NtStatus ) ) {

            NtStatus = SamQueryInformationUser(
                          UserHandle,
                          UserNameInformation,
                          (PVOID *)&BufName
                          );

            if ( NT_SUCCESS( NtStatus ) && BufName &&
                 BufName->UserName.Length > 0 && BufName->UserName.Buffer ) {

                //
                // add it to the members list, check duplicate
                //
                LONG NameLen;
                PWSTR                 pTemp;

                for ( pName = *ppList; pName; pName=pName->Next ) {

                    if ( !pName->Name ) {
                        continue;
                    }

                    pTemp = wcschr( pName->Name, L'\\');

                    if ( pTemp ) {
                        //
                        // has a domain prefix
                        //
                        pTemp++;
                    } else {
                        pTemp = pName->Name;
                    }
                    NameLen = wcslen(pTemp);

                    if ( NameLen == BufName->UserName.Length/2 &&
                         _wcsnicmp(pTemp,
                                   BufName->UserName.Buffer,
                                   BufName->UserName.Length/2) == 0 ) {
                        //
                        // now, match the domain prefix
                        //
                        if ( pTemp != pName->Name ) {

                            if ( (pTemp-pName->Name-1) == DomainName->DomainName.Length/2 &&
                                 _wcsnicmp(pName->Name,
                                           DomainName->DomainName.Buffer,
                                           DomainName->DomainName.Length/2) == 0 ) {
                                break;
                            }
                        } else {
                            break;
                        }
                    }
                }

                if ( !pName ) {

                    //
                    // allocate a new node, if no resource, ignore the addition
                    //
                    pName = (PSCE_NAME_LIST)ScepAlloc( (UINT)0, sizeof(SCE_NAME_LIST));

                    if ( pName ) {

                        pName->Name = (PWSTR)ScepAlloc( LMEM_ZEROINIT, BufName->UserName.Length+DomainName->DomainName.Length+4);

                        if ( pName->Name == NULL ) {
                            ScepFree(pName);
                        } else {
                            //
                            // add the node to the front of the members list
                            //
                            NameLen = DomainName->DomainName.Length/2;

                            wcsncpy(pName->Name, DomainName->DomainName.Buffer,
                                    NameLen);
                            pName->Name[NameLen] = L'\\';

                            wcsncpy(pName->Name+NameLen+1, BufName->UserName.Buffer,
                                    BufName->UserName.Length/2);
                            pName->Name[NameLen+1+BufName->UserName.Length/2] = L'\0';

                            pName->Next = *ppList;
                            *ppList = pName;
                        }
                    }
                } else {
                    // else find it in the member list already, do nothing
                }

            }

            //
            // close the user handle
            //
            SamCloseHandle(UserHandle);
            UserHandle = NULL;
        }
    }

    if ( AccountDomain != DomainHandle ) {
       //
       // domain is opened
       //
       SamCloseHandle(AccountDomain);

       SamCloseHandle( ServerHandle );
       if ( DomainSid != NULL )
           SamFreeMemory(DomainSid);
    }

    if ( BufName ) {
        SamFreeMemory(BufName);
    }

    if ( DomainName ) {
        SamFreeMemory(DomainName);
    }

    return(NtStatus);
}



DWORD
ScepDatabaseAccessGranted(
    IN LPTSTR DatabaseName,
    IN DWORD DesiredAccess,
    IN BOOL bCreate
    )
{

    if ( DatabaseName == NULL || DesiredAccess == 0 ) {
        return(SCESTATUS_INVALID_PARAMETER);
    }

    HANDLE hToken, hNewToken;
    DWORD Win32rc = NO_ERROR;

    //
    // get current client token
    //
    if (!OpenThreadToken( GetCurrentThread(),
                          TOKEN_IMPERSONATE | TOKEN_READ | TOKEN_DUPLICATE,
                          FALSE,
                          &hToken)) {

        if (!OpenProcessToken( GetCurrentProcess(),
                               TOKEN_IMPERSONATE | TOKEN_READ | TOKEN_DUPLICATE,
                               &hToken)) {
            return( GetLastError() );
        }
    }

    //
    // Duplicate it so it can be used for impersonation
    //

    if (!DuplicateTokenEx(hToken, TOKEN_IMPERSONATE | TOKEN_QUERY,
                          NULL, SecurityImpersonation, TokenImpersonation,
                          &hNewToken))
    {
        CloseHandle (hToken);
        return ( GetLastError() );
    }

    CloseHandle (hToken);


    PSECURITY_DESCRIPTOR pCurrentSD=NULL;
    PRIVILEGE_SET PrivSet;
    DWORD PrivSetLength = sizeof(PRIVILEGE_SET);
    DWORD dwGrantedAccess;
    BOOL bAccessStatus = TRUE;

    if ( !bCreate ) {

        Win32rc = ScepGetNamedSecurityInfo(
                        DatabaseName,
                        SE_FILE_OBJECT,
                        OWNER_SECURITY_INFORMATION |
                        GROUP_SECURITY_INFORMATION |
                        DACL_SECURITY_INFORMATION,
                        &pCurrentSD
                        );

        if ( Win32rc == ERROR_PATH_NOT_FOUND ||
             Win32rc == ERROR_FILE_NOT_FOUND ) {

            pCurrentSD = NULL;

            Win32rc = NO_ERROR;

        }
    }

    if ( Win32rc == NO_ERROR ) {

        if ( pCurrentSD == NULL ) {
            //
            // either this database is to be overwritten (re-created)
            // or it doesn't exist. In both cases, hand the call over to Jet
            // which will do the right access checking.
            //
        } else {

            if ( !AccessCheck (
                        pCurrentSD,
                        hNewToken,
                        DesiredAccess,
                        &FileGenericMapping,
                        &PrivSet,
                        &PrivSetLength,
                        &dwGrantedAccess,
                        &bAccessStatus
                        ) ) {

                Win32rc = GetLastError();

            } else {

                if ( bAccessStatus &&
                     (dwGrantedAccess == DesiredAccess ) ) {
                    Win32rc = NO_ERROR;
                } else {
                    Win32rc = ERROR_ACCESS_DENIED;
                }
            }
        }

    }

    if ( pCurrentSD ) {

        LocalFree(pCurrentSD);
    }

    CloseHandle (hNewToken);

    return( Win32rc );
}


DWORD
ScepAddSidToNameList(
    OUT PSCE_NAME_LIST *pNameList,
    IN PSID pSid,
    IN BOOL bReuseBuffer,
    OUT BOOL *pbBufferUsed
    )
/* ++
Routine Description:

    This routine adds a SID to the name list. The new added
    node is always placed as the head of the list for performance reason.

Arguments:

    pNameList -  The address of the name list to add to.

    pSid      - the Sid to add

Return value:

    Win32 error code
-- */
{

    PSCE_NAME_LIST pList=NULL;
    ULONG  Length;

    //
    // check arguments
    //
    if ( pNameList == NULL ||
         pbBufferUsed == NULL )
        return(ERROR_INVALID_PARAMETER);

    *pbBufferUsed = FALSE;

    if ( pSid == NULL )
        return(NO_ERROR);

    if ( !RtlValidSid(pSid) ) {
        return(ERROR_INVALID_PARAMETER);
    }

    //
    // check if the SID is already in the name list
    //
    for ( pList=*pNameList; pList!=NULL; pList=pList->Next ) {
        if ( pList->Name == NULL ) {
            continue;
        }
        if ( ScepValidSid( (PSID)(pList->Name) ) &&
             RtlEqualSid( (PSID)(pList->Name), pSid ) ) {
            break;
        }
    }

    if ( pList ) {
        //
        // the SID is already in the list
        //
        return(NO_ERROR);
    }

    //
    // allocate a new node
    //
    pList = (PSCE_NAME_LIST)ScepAlloc( (UINT)0, sizeof(SCE_NAME_LIST));

    if ( pList == NULL )
        return(ERROR_NOT_ENOUGH_MEMORY);

    if ( bReuseBuffer ) {

        pList->Name = (PWSTR)pSid;
        *pbBufferUsed = TRUE;

    } else {

        Length = RtlLengthSid ( pSid );

        pList->Name = (PWSTR)ScepAlloc( LMEM_ZEROINIT, Length);
        if ( pList->Name == NULL ) {
            ScepFree(pList);
            return(ERROR_NOT_ENOUGH_MEMORY);
        }

        //
        // add the node to the front of the list and link its next to the old list
        //
        RtlCopySid( Length, (PSID)(pList->Name), pSid );
    }

    pList->Next = *pNameList;
    *pNameList = pList;

    return(NO_ERROR);
}


BOOL
ScepValidSid(
    PSID Sid
    )
{
    if ( RtlValidSid(Sid) ) {

        PISID Isid = (PISID) Sid;

        if ( Isid->Revision == SID_REVISION ) {
            return(TRUE);
        } else {
            return(FALSE);
        }
    }

    return(FALSE);
}

BOOL
ScepBinarySearch(
    IN  PWSTR   *aPszPtrs,
    IN  DWORD   dwSize_aPszPtrs,
    IN  PWSTR   pszNameToFind
    )
/* ++
Routine Description:

    This routine determines if a string is found in a sorted array of strings.
    The complexity of this search is logarithmic (log(n)) in the size of the
    input array.

Arguments:

    aPszPtrs        -   the array of string pointers to search in

    dwSize_aPszPtrs -   the size of the above array

    pszNameToFind   -   the string to search for

Return value:

    TRUE if string is found
    FALSE if string is not found

-- */
{
    if ( aPszPtrs == NULL || dwSize_aPszPtrs == 0 || pszNameToFind == NULL ) {
        return FALSE;
    }

    int   iLow = 0;
    int   iHigh = dwSize_aPszPtrs - 1;
    int   iMid;
    int   iCmp;

    while (iLow <= iHigh ) {

        iMid = (iLow + iHigh ) / 2;

        iCmp = _wcsicmp( aPszPtrs[iMid], pszNameToFind );

        if ( iCmp == 0 )
            return TRUE;
        else if ( iCmp < 0 )
            iLow = iMid + 1;
        else
            iHigh = iMid - 1;
    }

    return FALSE;
}