/*++ 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 #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 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; }