/* Editor Settings: expandtabs and use 4 spaces for indentation * ex: set softtabstop=4 tabstop=8 expandtab shiftwidth=4: * * -*- mode: c, c-basic-offset: 4 -*- */ /* * Copyright Likewise Software 2004-2008 * All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or (at * your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. You should have received a copy of the GNU General * Public License along with this program. If not, see * . * * LIKEWISE SOFTWARE MAKES THIS SOFTWARE AVAILABLE UNDER OTHER LICENSING * TERMS AS WELL. IF YOU HAVE ENTERED INTO A SEPARATE LICENSE AGREEMENT * WITH LIKEWISE SOFTWARE, THEN YOU MAY ELECT TO USE THE SOFTWARE UNDER THE * TERMS OF THAT SOFTWARE LICENSE AGREEMENT INSTEAD OF THE TERMS OF THE GNU * GENERAL PUBLIC LICENSE, NOTWITHSTANDING THE ABOVE NOTICE. IF YOU * HAVE QUESTIONS, OR WISH TO REQUEST A COPY OF THE ALTERNATE LICENSING * TERMS OFFERED BY LIKEWISE SOFTWARE, PLEASE CONTACT LIKEWISE SOFTWARE AT * license@likewisesoftware.com */ /* * Copyright (C) Likewise Software. All rights reserved. * * Module Name: * * sqldb_p.c * * Abstract: * * Sqlite3 backend for Registry Database Interface * APIs inlock * * Authors: Wei Fu (wfu@likewise.com) * */ #include "includes.h" NTSTATUS RegDbOpenKey_inlock( IN REG_DB_HANDLE hDb, IN PCWSTR pwszFullKeyPath, OUT OPTIONAL PREG_DB_KEY* ppRegKey ) { NTSTATUS status = 0; wchar16_t wch = '\\'; PWSTR pwszKeyToken = NULL; // Do not free PCWSTR pwszCurrentKeyPath = pwszFullKeyPath; int64_t qwParentId = 0; PREG_DB_KEY pRegKey = NULL; PREG_DB_KEY pRegKeyDup = NULL; BOOLEAN bInLock = FALSE; status = SqliteCacheGetDbKeyInfo(pwszFullKeyPath, &pRegKey); if (!status) { goto cleanup; } else if (STATUS_OBJECT_NAME_NOT_FOUND == status) { status = 0; } BAIL_ON_NT_STATUS(status); while (pwszCurrentKeyPath) { LWREG_SAFE_FREE_MEMORY(pwszKeyToken); RegDbSafeFreeEntryKey(&pRegKey); status = SqliteGetKeyToken(pwszCurrentKeyPath, wch, &pwszKeyToken); BAIL_ON_NT_STATUS(status); status = RegDbOpenKeyName_inlock(hDb, !pwszKeyToken ? pwszCurrentKeyPath : pwszKeyToken, &qwParentId, &pRegKey); BAIL_ON_NT_STATUS(status); pwszCurrentKeyPath = RegStrchr(pwszCurrentKeyPath, wch); if (pwszCurrentKeyPath) { pwszCurrentKeyPath++; } } status = LwRtlWC16StringDuplicate(&pRegKey->pwszFullKeyName, pwszFullKeyPath); BAIL_ON_NT_STATUS(status); if (pRegKey->qwAclIndex != -1) { status = RegDbGetKeyAclByAclIndex_inlock(hDb, pRegKey->qwAclIndex, &pRegKey->pSecDescRel, &pRegKey->ulSecDescLength); BAIL_ON_NT_STATUS(status); } REG_LOG_VERBOSE("Registry::sqldb.c RegDbOpenKey_inlock() finished\n"); status = RegDbDuplicateDbKeyEntry(pRegKey, &pRegKeyDup); BAIL_ON_NT_STATUS(status); LWREG_LOCK_MUTEX(bInLock, &gRegDbKeyList.mutex); status = SqliteCacheInsertDbKeyInfo_inlock(pRegKeyDup); BAIL_ON_NT_STATUS(status); pRegKeyDup = NULL; cleanup: SqliteReleaseDbKeyInfo_inlock(pRegKeyDup); LWREG_UNLOCK_MUTEX(bInLock, &gRegDbKeyList.mutex); if (!status && ppRegKey) { *ppRegKey = pRegKey; } else { RegDbSafeFreeEntryKey(&pRegKey); } LWREG_SAFE_FREE_MEMORY(pwszKeyToken); return status; error: if(ppRegKey) { *ppRegKey = NULL; } RegDbSafeFreeEntryKey(&pRegKey); goto cleanup; } NTSTATUS RegDbOpenKeyName_inlock( IN REG_DB_HANDLE hDb, IN PCWSTR pwszKeyName, IN OUT int64_t* pqwParentId, OUT PREG_DB_KEY* ppRegEntry ) { NTSTATUS status = STATUS_SUCCESS; PREG_DB_CONNECTION pConn = (PREG_DB_CONNECTION)hDb; // do not free sqlite3_stmt *pstQuery = NULL; size_t sResultCount = 0; const int nExpectedCols = 5; int iColumnPos = 0; int nGotColumns = 0; PREG_DB_KEY pRegEntry = NULL; pstQuery = pConn->pstOpenKeyEx; status = RegSqliteBindStringW(pstQuery, 1, pwszKeyName); BAIL_ON_SQLITE3_ERROR_STMT(status, pstQuery); status = RegSqliteBindInt64(pstQuery, 2, *pqwParentId); BAIL_ON_SQLITE3_ERROR_STMT(status, pstQuery); while ((status = (DWORD)sqlite3_step(pstQuery)) == SQLITE_ROW) { nGotColumns = sqlite3_column_count(pstQuery); if (nGotColumns != nExpectedCols) { status = STATUS_DATA_ERROR; BAIL_ON_NT_STATUS(status); } if (sResultCount >= 1) { //Duplicate keys are found status = STATUS_DUPLICATE_NAME; BAIL_ON_NT_STATUS(status); } status = LW_RTL_ALLOCATE((PVOID*)&pRegEntry, REG_DB_KEY, sizeof(*pRegEntry)); BAIL_ON_NT_STATUS(status); iColumnPos = 0; status = RegDbUnpackCacheInfo(pstQuery, &iColumnPos, &pRegEntry->version); BAIL_ON_NT_STATUS(status); status = RegDbUnpackRegKeyInfo(pstQuery, &iColumnPos, pRegEntry); BAIL_ON_NT_STATUS(status); sResultCount++; } if (status == SQLITE_DONE) { // No more results found status = STATUS_SUCCESS; } BAIL_ON_SQLITE3_ERROR_DB(status, pConn->pDb); status = (NTSTATUS)sqlite3_reset(pstQuery); BAIL_ON_SQLITE3_ERROR_DB(status, pConn->pDb); if (!sResultCount) { status = STATUS_OBJECT_NAME_NOT_FOUND; BAIL_ON_NT_STATUS(status); } *ppRegEntry = pRegEntry; *pqwParentId = pRegEntry->version.qwDbId; cleanup: return status; error: *ppRegEntry = NULL; if (pstQuery != NULL) { sqlite3_reset(pstQuery); } RegDbSafeFreeEntryKey(&pRegEntry); goto cleanup; } NTSTATUS RegDbDeleteKey_inlock( IN REG_DB_HANDLE hDb, IN int64_t qwId, IN int64_t qwAclId, IN PCWSTR pwszFullKeyName ) { NTSTATUS status = STATUS_SUCCESS; PCWSTR pwszKeyName = NULL; PREG_DB_CONNECTION pConn = (PREG_DB_CONNECTION)hDb; size_t sCount = 0; // Do not free sqlite3_stmt *pstQuery = pConn->pstDeleteKey; // Delete the key pwszKeyName = RegStrrchr(pwszFullKeyName, '\\'); pwszKeyName = pwszKeyName ? pwszKeyName + 1 : pwszFullKeyName; status = RegSqliteBindInt64(pstQuery, 1, qwId); BAIL_ON_SQLITE3_ERROR_STMT(status, pstQuery); status = RegSqliteBindStringW(pstQuery, 2, pwszKeyName); BAIL_ON_SQLITE3_ERROR_STMT(status, pstQuery); status = (DWORD)sqlite3_step(pstQuery); if (status == SQLITE_DONE) { status = STATUS_SUCCESS; } BAIL_ON_SQLITE3_ERROR_STMT(status, pstQuery); status = (DWORD)sqlite3_reset(pstQuery); BAIL_ON_SQLITE3_ERROR_DB(status, pConn->pDb); // Delete the key's values pstQuery = pConn->pstDeleteAllKeyValues; status = RegSqliteBindInt64(pstQuery, 1, qwId); BAIL_ON_SQLITE3_ERROR_STMT(status, pstQuery); status = (DWORD)sqlite3_step(pstQuery); if (status == SQLITE_DONE) { status = STATUS_SUCCESS; } BAIL_ON_SQLITE3_ERROR_STMT(status, pstQuery); status = (DWORD)sqlite3_reset(pstQuery); BAIL_ON_SQLITE3_ERROR_DB(status, pConn->pDb); // Delete the keys' ACL if there is no more reference to it if (qwAclId != -1) { status = RegDbQueryAclRefCountWOCurrKey_inlock(hDb, qwAclId, qwId, &sCount); BAIL_ON_NT_STATUS(status); if (!sCount) { status = RegDbDeleteAcl_inlock(hDb, qwAclId); BAIL_ON_NT_STATUS(status); } } status = sqlite3_reset(pstQuery); BAIL_ON_SQLITE3_ERROR(status, sqlite3_errmsg(pConn->pDb)); SqliteCacheDeleteDbKeyInfo(pwszFullKeyName); cleanup: return status; error: goto cleanup; } NTSTATUS RegDbDeleteAcl_inlock( IN REG_DB_HANDLE hDb, IN int64_t qwSdCacheId ) { NTSTATUS status = STATUS_SUCCESS; PREG_DB_CONNECTION pConn = (PREG_DB_CONNECTION)hDb; // Do not free sqlite3_stmt *pstQuery = pConn->pstDeleteAcl; status = RegSqliteBindInt64(pstQuery, 1, qwSdCacheId); BAIL_ON_SQLITE3_ERROR_STMT(status, pstQuery); status = (DWORD)sqlite3_step(pstQuery); if (status == SQLITE_DONE) { status = STATUS_SUCCESS; } BAIL_ON_SQLITE3_ERROR_STMT(status, pstQuery); status = (DWORD)sqlite3_reset(pstQuery); BAIL_ON_SQLITE3_ERROR_DB(status, pConn->pDb); cleanup: return status; error: if (pstQuery) { sqlite3_reset(pstQuery); } goto cleanup; } NTSTATUS RegDbQueryInfoKeyCount_inlock( IN REG_DB_HANDLE hDb, IN int64_t qwId, IN QueryKeyInfoOption queryType, OUT size_t* psCount ) { NTSTATUS status = STATUS_SUCCESS; PREG_DB_CONNECTION pConn = (PREG_DB_CONNECTION)hDb; // do not free sqlite3_stmt *pstQuery = NULL; size_t sResultCount = 0; const int nExpectedCols = 1; int iColumnPos = 0; int nGotColumns = 0; DWORD dwCount = 0; if (qwId <= 0) { status = STATUS_INTERNAL_ERROR; BAIL_ON_NT_STATUS(status); } switch (queryType) { case QuerySubKeys: pstQuery = pConn->pstQuerySubKeysCount; break; case QueryValues: pstQuery = pConn->pstQueryValuesCount; break; default: status = STATUS_INVALID_PARAMETER; BAIL_ON_NT_STATUS(status); } status = RegSqliteBindInt64(pstQuery, 1, qwId); BAIL_ON_SQLITE3_ERROR_STMT(status, pstQuery); while ((status = (DWORD)sqlite3_step(pstQuery)) == SQLITE_ROW) { nGotColumns = sqlite3_column_count(pstQuery); if (nGotColumns != nExpectedCols) { status = STATUS_DATA_ERROR; BAIL_ON_NT_STATUS(status); } if (sResultCount >= 1) { status = STATUS_INTERNAL_ERROR; BAIL_ON_NT_STATUS(status); } iColumnPos = 0; switch (queryType) { case QuerySubKeys: status = RegDbUnpackSubKeysCountInfo(pstQuery, &iColumnPos, &dwCount); BAIL_ON_NT_STATUS(status); break; case QueryValues: status = RegDbUnpackKeyValuesCountInfo(pstQuery, &iColumnPos, &dwCount); BAIL_ON_NT_STATUS(status); break; default: status = STATUS_INVALID_PARAMETER; BAIL_ON_NT_STATUS(status); } sResultCount++; } if (status == SQLITE_DONE) { // No more results found status = STATUS_SUCCESS; } BAIL_ON_SQLITE3_ERROR_DB(status, pConn->pDb); status = (DWORD)sqlite3_reset(pstQuery); BAIL_ON_SQLITE3_ERROR_DB(status, pConn->pDb); if (!sResultCount) { status = STATUS_DATA_ERROR; BAIL_ON_NT_STATUS(status); } *psCount = (size_t)dwCount; cleanup: return status; error: if (pstQuery != NULL) { sqlite3_reset(pstQuery); } *psCount = 0; goto cleanup; } NTSTATUS RegDbQueryInfoKey_inlock( IN REG_DB_HANDLE hDb, IN PCWSTR pwszKeyName, IN int64_t qwId, IN DWORD dwLimit, IN DWORD dwOffset, OUT size_t* psCount, OUT OPTIONAL PREG_DB_KEY** pppRegEntries ) { NTSTATUS status = STATUS_SUCCESS; PREG_DB_CONNECTION pConn = (PREG_DB_CONNECTION)hDb; // do not free sqlite3_stmt *pstQuery = NULL; size_t sResultCount = 0; size_t sResultCapacity = 0; const int nExpectedCols = 5; int iColumnPos = 0; int nGotColumns = 0; PREG_DB_KEY pRegEntry = NULL; PREG_DB_KEY* ppRegEntries = NULL; if (qwId <= 0) { status = STATUS_INTERNAL_ERROR; BAIL_ON_NT_STATUS(status); } pstQuery = pConn->pstQuerySubKeys; status = RegSqliteBindInt64(pstQuery, 1, qwId); BAIL_ON_SQLITE3_ERROR_STMT(status, pstQuery); status = RegSqliteBindInt64(pstQuery, 2, dwLimit); BAIL_ON_SQLITE3_ERROR_STMT(status, pstQuery); status = RegSqliteBindInt64(pstQuery, 3, dwOffset); BAIL_ON_SQLITE3_ERROR_STMT(status, pstQuery); while ((status = (DWORD)sqlite3_step(pstQuery)) == SQLITE_ROW) { nGotColumns = sqlite3_column_count(pstQuery); if (nGotColumns != nExpectedCols) { status = STATUS_DATA_ERROR; BAIL_ON_NT_STATUS(status); } if (sResultCount >= sResultCapacity) { sResultCapacity *= 2; sResultCapacity += 10; status = NtRegReallocMemory( ppRegEntries, (PVOID*)&ppRegEntries, sizeof(*ppRegEntries) * sResultCapacity); BAIL_ON_NT_STATUS(status); } status = LW_RTL_ALLOCATE((PVOID*)&pRegEntry, REG_DB_KEY, sizeof(*pRegEntry)); BAIL_ON_NT_STATUS(status); iColumnPos = 0; status = RegDbUnpackCacheInfo(pstQuery, &iColumnPos, &pRegEntry->version); BAIL_ON_NT_STATUS(status); status = RegDbUnpackRegKeyInfo(pstQuery, &iColumnPos, pRegEntry); BAIL_ON_NT_STATUS(status); status = LwRtlWC16StringAllocatePrintfW( &pRegEntry->pwszFullKeyName, L"%ws\\%ws", pwszKeyName, pRegEntry->pwszKeyName); BAIL_ON_NT_STATUS(status); ppRegEntries[sResultCount] = pRegEntry; pRegEntry = NULL; sResultCount++; } if (status == SQLITE_DONE) { // No more results found status = STATUS_SUCCESS; } BAIL_ON_SQLITE3_ERROR_DB(status, pConn->pDb); status = (DWORD)sqlite3_reset(pstQuery); BAIL_ON_SQLITE3_ERROR_DB(status, pConn->pDb); cleanup: if (!status) { if (pppRegEntries) { *pppRegEntries = ppRegEntries; } *psCount = sResultCount; } else { RegDbSafeFreeEntryKey(&pRegEntry); RegDbSafeFreeEntryKeyList(sResultCount, &ppRegEntries); if (pppRegEntries) { *pppRegEntries = NULL; } *psCount = 0; } return status; error: if (pstQuery != NULL) { sqlite3_reset(pstQuery); } goto cleanup; } NTSTATUS RegDbUpdateKeyAclIndex_inlock( IN REG_DB_HANDLE hDb, IN int64_t qwKeyDbId, IN int64_t qwKeySdId ) { NTSTATUS status = STATUS_SUCCESS; PREG_DB_CONNECTION pConn = (PREG_DB_CONNECTION)hDb; // Do not free sqlite3_stmt *pstQuery = pConn->pstUpdateKeyAclIndexByKeyId; status = RegSqliteBindInt64(pstQuery, 1, qwKeySdId); BAIL_ON_SQLITE3_ERROR_STMT(status, pstQuery); status = RegSqliteBindInt64(pstQuery, 2, qwKeyDbId); BAIL_ON_SQLITE3_ERROR_STMT(status, pstQuery); status = (DWORD)sqlite3_step(pstQuery); if (status == SQLITE_DONE) { status = STATUS_SUCCESS; } BAIL_ON_SQLITE3_ERROR_STMT(status, pstQuery); status = (DWORD)sqlite3_reset(pstQuery); BAIL_ON_SQLITE3_ERROR_DB(status, pConn->pDb); cleanup: return status; error: if (pstQuery) { sqlite3_reset(pstQuery); } goto cleanup; } NTSTATUS RegDbQueryAclRefCountWOCurrKey_inlock( IN REG_DB_HANDLE hDb, IN int64_t qwSdId, IN int64_t qwKeyId, OUT size_t* psCount ) { NTSTATUS status = STATUS_SUCCESS; PREG_DB_CONNECTION pConn = (PREG_DB_CONNECTION)hDb; // do not free sqlite3_stmt *pstQuery = NULL; size_t sResultCount = 0; const int nExpectedCols = 1; int iColumnPos = 0; int nGotColumns = 0; DWORD dwCount = 0; if (qwSdId <= 0) { status = STATUS_INTERNAL_ERROR; BAIL_ON_NT_STATUS(status); } pstQuery = pConn->pstQueryAclRefCount; status = RegSqliteBindInt64(pstQuery, 1, qwSdId); BAIL_ON_SQLITE3_ERROR_STMT(status, pstQuery); status = RegSqliteBindInt64(pstQuery, 2, qwKeyId); BAIL_ON_SQLITE3_ERROR_STMT(status, pstQuery); while ((status = (DWORD)sqlite3_step(pstQuery)) == SQLITE_ROW) { nGotColumns = sqlite3_column_count(pstQuery); if (nGotColumns != nExpectedCols) { status = STATUS_DATA_ERROR; BAIL_ON_NT_STATUS(status); } if (sResultCount >= 1) { status = STATUS_INTERNAL_ERROR; BAIL_ON_NT_STATUS(status); } iColumnPos = 0; status = RegDbUnpackAclrefCountInfo(pstQuery, &iColumnPos, &dwCount); BAIL_ON_NT_STATUS(status); sResultCount++; } if (status == SQLITE_DONE) { // No more results found status = STATUS_SUCCESS; } BAIL_ON_SQLITE3_ERROR_DB(status, pConn->pDb); status = (DWORD)sqlite3_reset(pstQuery); BAIL_ON_SQLITE3_ERROR_DB(status, pConn->pDb); if (!sResultCount) { status = STATUS_DATA_ERROR; BAIL_ON_NT_STATUS(status); } *psCount = (size_t)dwCount; cleanup: return status; error: if (pstQuery != NULL) { sqlite3_reset(pstQuery); } *psCount = 0; goto cleanup; } NTSTATUS RegDbGetKeyAclIndexByKeyId_inlock( IN REG_DB_HANDLE hDb, IN int64_t qwKeyDbId, OUT int64_t* pqwAclIndex ) { NTSTATUS status = STATUS_SUCCESS; PREG_DB_CONNECTION pConn = (PREG_DB_CONNECTION)hDb; size_t sResultCount = 0; const int nExpectedCols = 1; int iColumnPos = 0; int nGotColumns = 0; // Do not free sqlite3_stmt *pstQuery = pConn->pstQueryKeyAclIndexByKeyId; status = RegSqliteBindInt64( pstQuery, 1, qwKeyDbId); BAIL_ON_SQLITE3_ERROR_STMT(status, pstQuery); while ((status = (DWORD)sqlite3_step(pstQuery)) == SQLITE_ROW) { nGotColumns = sqlite3_column_count(pstQuery); if (nGotColumns != nExpectedCols) { status = STATUS_DATA_ERROR; BAIL_ON_NT_STATUS(status); } if (sResultCount >= 1) { //Duplicate ACL records are found status = STATUS_DUPLICATE_NAME; BAIL_ON_NT_STATUS(status); } iColumnPos = 0; status = RegDbUnpackAclIndexInfoInKeys(pstQuery, &iColumnPos, pqwAclIndex); sResultCount++; } if (status == SQLITE_DONE) { status = STATUS_SUCCESS; } BAIL_ON_SQLITE3_ERROR_STMT(status, pstQuery); status = (DWORD)sqlite3_reset(pstQuery); BAIL_ON_SQLITE3_ERROR_DB(status, pConn->pDb); cleanup: return status; error: if (pstQuery) { sqlite3_reset(pstQuery); } *pqwAclIndex = -1; goto cleanup; } NTSTATUS RegDbGetKeyAclByAclIndex_inlock( IN REG_DB_HANDLE hDb, // qwAclIndex should not be -1 (pre-check is done before call this function) IN int64_t qwAclIndex, OUT PSECURITY_DESCRIPTOR_RELATIVE* ppSecDescRel, OUT PULONG pulSecDescLength ) { NTSTATUS status = STATUS_SUCCESS; int nExpectedCols = 1; int iColumnPos = 0; int nGotColumns = 0; size_t sResultCount = 0; PREG_DB_CONNECTION pConn = (PREG_DB_CONNECTION)hDb; // Do not free sqlite3_stmt *pstQuery = pConn->pstQueryKeyAcl; status = RegSqliteBindInt64(pstQuery, 1, qwAclIndex); BAIL_ON_SQLITE3_ERROR_STMT(status, pstQuery); while ((status = (DWORD)sqlite3_step(pstQuery)) == SQLITE_ROW) { nGotColumns = sqlite3_column_count(pstQuery); if (nGotColumns != nExpectedCols) { status = STATUS_DATA_ERROR; BAIL_ON_NT_STATUS(status); } if (sResultCount >= 1) { //Duplicate ACLs are found status = STATUS_DUPLICATE_NAME; BAIL_ON_NT_STATUS(status); } iColumnPos = 0; status = RegDbUnpackAclInfo(pstQuery, &iColumnPos, ppSecDescRel, pulSecDescLength); BAIL_ON_NT_STATUS(status); sResultCount++; } if (status == SQLITE_DONE) { // No more results found status = STATUS_SUCCESS; } BAIL_ON_SQLITE3_ERROR_DB(status, pConn->pDb); status = (DWORD)sqlite3_reset(pstQuery); BAIL_ON_SQLITE3_ERROR_DB(status, pConn->pDb); if (!sResultCount) { // This should never happen, we only store valid SD in ACLs status = STATUS_INTERNAL_ERROR; BAIL_ON_NT_STATUS(status); } cleanup: return status; error: *ppSecDescRel = NULL; *pulSecDescLength = 0; goto cleanup; } NTSTATUS RegDbGetKeyAclIndexByKeyAcl_inlock( IN REG_DB_HANDLE hDb, IN PSECURITY_DESCRIPTOR_RELATIVE pSecurityDescriptor, IN ULONG ulSecDescLength, OUT int64_t* pqwAclIndex ) { NTSTATUS status = STATUS_SUCCESS; PREG_DB_CONNECTION pConn = (PREG_DB_CONNECTION)hDb; size_t sResultCount = 0; const int nExpectedCols = 1; int iColumnPos = 0; int nGotColumns = 0; // Do not free sqlite3_stmt *pstQuery = pConn->pstQueryKeyAclIndex; status = RegSqliteBindBlob( pstQuery, 1, (BYTE*)pSecurityDescriptor, ulSecDescLength); BAIL_ON_SQLITE3_ERROR_STMT(status, pstQuery); while ((status = (DWORD)sqlite3_step(pstQuery)) == SQLITE_ROW) { nGotColumns = sqlite3_column_count(pstQuery); if (nGotColumns != nExpectedCols) { status = STATUS_DATA_ERROR; BAIL_ON_NT_STATUS(status); } if (sResultCount >= 1) { //Duplicate ACL records are found status = STATUS_DUPLICATE_NAME; BAIL_ON_NT_STATUS(status); } iColumnPos = 0; status = RegDbUnpackAclIndexInfoInAcls(pstQuery, &iColumnPos, pqwAclIndex); sResultCount++; } if (status == SQLITE_DONE) { status = STATUS_SUCCESS; } BAIL_ON_SQLITE3_ERROR_STMT(status, pstQuery); status = (DWORD)sqlite3_reset(pstQuery); BAIL_ON_SQLITE3_ERROR_DB(status, pConn->pDb); cleanup: return status; error: if (pstQuery) { sqlite3_reset(pstQuery); } *pqwAclIndex = -1; goto cleanup; } void RegDbSafeFreeEntryKeyList( size_t sCount, PREG_DB_KEY** pppEntries ) { if (*pppEntries != NULL) { size_t iEntry; for (iEntry = 0; iEntry < sCount; iEntry++) { RegDbSafeFreeEntryKey(&(*pppEntries)[iEntry]); } LWREG_SAFE_FREE_MEMORY(*pppEntries); } } void RegDbSafeFreeEntryValueList( size_t sCount, PREG_DB_VALUE** pppEntries ) { if (*pppEntries != NULL) { size_t iEntry; for (iEntry = 0; iEntry < sCount; iEntry++) { RegDbSafeFreeEntryValue(&(*pppEntries)[iEntry]); } LWREG_SAFE_FREE_MEMORY(*pppEntries); } } NTSTATUS RegDbDuplicateDbKeyEntry( PREG_DB_KEY pRegKey, PREG_DB_KEY* ppRegKey ) { NTSTATUS status = 0; PREG_DB_KEY pRegDupKey = NULL; if (!pRegKey) { goto done; } status = LW_RTL_ALLOCATE((PVOID*)&pRegDupKey, REG_DB_KEY, sizeof(*pRegDupKey)); BAIL_ON_NT_STATUS(status); memcpy(pRegDupKey, pRegKey, sizeof(*pRegKey)); pRegDupKey->pwszFullKeyName = NULL; pRegDupKey->pwszKeyName = NULL; pRegDupKey->pSecDescRel = NULL; status = LwRtlWC16StringDuplicate(&pRegDupKey->pwszKeyName, pRegKey->pwszKeyName); BAIL_ON_NT_STATUS(status); status = LwRtlWC16StringDuplicate(&pRegDupKey->pwszFullKeyName, pRegKey->pwszFullKeyName); BAIL_ON_NT_STATUS(status); status = LW_RTL_ALLOCATE((PVOID*)&pRegDupKey->pSecDescRel, VOID, pRegKey->ulSecDescLength); BAIL_ON_NT_STATUS(status); memcpy(pRegDupKey->pSecDescRel, pRegKey->pSecDescRel, pRegKey->ulSecDescLength); done: *ppRegKey = pRegDupKey; cleanup: return status; error: *ppRegKey = NULL; RegDbSafeFreeEntryKey(&pRegDupKey); goto cleanup; } void RegDbSafeFreeEntryKey( PREG_DB_KEY* ppEntry ) { PREG_DB_KEY pEntry = NULL; if (ppEntry != NULL && *ppEntry != NULL) { pEntry = *ppEntry; LWREG_SAFE_FREE_MEMORY(pEntry->pwszKeyName); LWREG_SAFE_FREE_MEMORY(pEntry->pwszFullKeyName); LWREG_SAFE_FREE_MEMORY(pEntry->pSecDescRel); memset(pEntry, 0, sizeof(*pEntry)); LWREG_SAFE_FREE_MEMORY(pEntry); *ppEntry = NULL; } } void RegDbSafeFreeEntryValue( PREG_DB_VALUE* ppEntry ) { PREG_DB_VALUE pEntry = NULL; if (ppEntry != NULL && *ppEntry != NULL) { pEntry = *ppEntry; LWREG_SAFE_FREE_MEMORY(pEntry->pwszValueName); LWREG_SAFE_FREE_MEMORY(pEntry->pValue); memset(pEntry, 0, sizeof(*pEntry)); LWREG_SAFE_FREE_MEMORY(pEntry); *ppEntry = NULL; } } NTSTATUS RegDbSafeRecordSubKeysInfo_inlock( IN size_t sCount, IN size_t sCacheCount, IN PREG_DB_KEY* ppRegEntries, IN OUT PREG_KEY_CONTEXT pKeyResult ) { NTSTATUS status = STATUS_SUCCESS; int iCount = 0; size_t sSubKeyLen = 0; BAIL_ON_NT_INVALID_POINTER(pKeyResult); //Remove previous subKey information if there is any RegFreeWC16StringArray(pKeyResult->ppwszSubKeyNames, pKeyResult->dwNumCacheSubKeys); if (!sCacheCount) { goto cleanup; } status = LW_RTL_ALLOCATE((PVOID*)&pKeyResult->ppwszSubKeyNames, PWSTR, sizeof(*(pKeyResult->ppwszSubKeyNames)) * sCacheCount); BAIL_ON_NT_STATUS(status); for (iCount = 0; iCount < (DWORD)sCacheCount; iCount++) { status = LwRtlWC16StringDuplicate(&pKeyResult->ppwszSubKeyNames[iCount], ppRegEntries[iCount]->pwszFullKeyName); BAIL_ON_NT_STATUS(status); if (ppRegEntries[iCount]->pwszFullKeyName) { sSubKeyLen = RtlWC16StringNumChars(ppRegEntries[iCount]->pwszFullKeyName); } if (pKeyResult->sMaxSubKeyLen < sSubKeyLen) pKeyResult->sMaxSubKeyLen = sSubKeyLen; sSubKeyLen = 0; } cleanup: pKeyResult->dwNumSubKeys = (DWORD)sCount; pKeyResult->dwNumCacheSubKeys = sCacheCount; pKeyResult->bHasSubKeyInfo = TRUE; return status; error: goto cleanup; } NTSTATUS RegDbSafeRecordSubKeysInfo( IN size_t sCount, IN size_t sCacheCount, IN PREG_DB_KEY* ppRegEntries, IN OUT PREG_KEY_CONTEXT pKeyResult ) { NTSTATUS status = STATUS_SUCCESS; BOOLEAN bInLock = FALSE; BAIL_ON_NT_INVALID_POINTER(pKeyResult); LWREG_LOCK_RWMUTEX_EXCLUSIVE(bInLock, &pKeyResult->mutex); status = RegDbSafeRecordSubKeysInfo_inlock(sCount, sCacheCount, ppRegEntries, pKeyResult); BAIL_ON_NT_STATUS(status); cleanup: LWREG_UNLOCK_RWMUTEX(bInLock, &pKeyResult->mutex); return status; error: goto cleanup; } NTSTATUS RegDbSafeRecordValuesInfo_inlock( IN size_t sCount, IN size_t sCacheCount, IN PREG_DB_VALUE* ppRegEntries, IN OUT PREG_KEY_CONTEXT pKeyResult ) { NTSTATUS status = STATUS_SUCCESS; int iCount = 0; size_t sValueNameLen = 0; BAIL_ON_NT_INVALID_POINTER(pKeyResult); //Remove previous subKey information if there is any RegFreeWC16StringArray(pKeyResult->ppwszValueNames, pKeyResult->dwNumCacheValues); RegFreeValueByteArray(pKeyResult->ppValues, pKeyResult->dwNumCacheValues); LWREG_SAFE_FREE_MEMORY(pKeyResult->pTypes); LWREG_SAFE_FREE_MEMORY(pKeyResult->pdwValueLen); if (!sCacheCount) { goto cleanup; } status = LW_RTL_ALLOCATE((PVOID*)&pKeyResult->ppwszValueNames, PWSTR, sizeof(*(pKeyResult->ppwszValueNames))* sCacheCount); BAIL_ON_NT_STATUS(status); status = LW_RTL_ALLOCATE((PVOID*)&pKeyResult->ppValues, PBYTE, sizeof(*(pKeyResult->ppValues))* sCacheCount); BAIL_ON_NT_STATUS(status); status = LW_RTL_ALLOCATE((PVOID*)&pKeyResult->pTypes, REG_DATA_TYPE, sizeof(*(pKeyResult->pTypes))* sCacheCount); BAIL_ON_NT_STATUS(status); status = LW_RTL_ALLOCATE((PVOID*)&pKeyResult->pdwValueLen, DWORD, sizeof(*(pKeyResult->pdwValueLen))* sCacheCount); BAIL_ON_NT_STATUS(status); for (iCount = 0; iCount < (DWORD)sCacheCount; iCount++) { status = LwRtlWC16StringDuplicate(&pKeyResult->ppwszValueNames[iCount], ppRegEntries[iCount]->pwszValueName); BAIL_ON_NT_STATUS(status); if (ppRegEntries[iCount]->dwValueLen) { status = LW_RTL_ALLOCATE((PVOID*)&pKeyResult->ppValues[iCount], BYTE, sizeof(*(pKeyResult->ppValues[iCount]))* ppRegEntries[iCount]->dwValueLen); BAIL_ON_NT_STATUS(status); memcpy(pKeyResult->ppValues[iCount], ppRegEntries[iCount]->pValue, ppRegEntries[iCount]->dwValueLen); } pKeyResult->pdwValueLen[iCount] = ppRegEntries[iCount]->dwValueLen; pKeyResult->pTypes[iCount] = ppRegEntries[iCount]->type; if (pKeyResult->sMaxValueLen < (size_t)ppRegEntries[iCount]->dwValueLen) { pKeyResult->sMaxValueLen = (size_t)ppRegEntries[iCount]->dwValueLen; } if (pKeyResult->ppwszValueNames[iCount]) { sValueNameLen = RtlWC16StringNumChars(pKeyResult->ppwszValueNames[iCount]); } if (pKeyResult->sMaxValueNameLen < sValueNameLen) pKeyResult->sMaxValueNameLen = sValueNameLen; sValueNameLen = 0; } cleanup: pKeyResult->dwNumValues = (DWORD)sCount; pKeyResult->dwNumCacheValues = sCacheCount; pKeyResult->bHasValueInfo = TRUE; return status; error: goto cleanup; } NTSTATUS RegDbSafeRecordValuesInfo( IN size_t sCount, IN size_t sCacheCount, IN PREG_DB_VALUE* ppRegEntries, IN OUT PREG_KEY_CONTEXT pKeyResult ) { NTSTATUS status = STATUS_SUCCESS; BOOLEAN bInLock = FALSE; BAIL_ON_NT_INVALID_POINTER(pKeyResult); LWREG_LOCK_RWMUTEX_EXCLUSIVE(bInLock, &pKeyResult->mutex); status = RegDbSafeRecordValuesInfo_inlock(sCount, sCacheCount, ppRegEntries, pKeyResult); BAIL_ON_NT_STATUS(status); cleanup: LWREG_UNLOCK_RWMUTEX(bInLock, &pKeyResult->mutex); return status; error: goto cleanup; }