NTSTATUS SqliteCacheUpdateValuesInfo( DWORD dwOffSet, IN OUT PREG_KEY_CONTEXT pKeyResult, OUT size_t* psNumValues ) { NTSTATUS status = STATUS_SUCCESS; BOOLEAN bInLock = FALSE; BAIL_ON_NT_INVALID_POINTER(pKeyResult); LWREG_LOCK_RWMUTEX_EXCLUSIVE(bInLock, &pKeyResult->mutex); status = SqliteCacheUpdateValuesInfo_inlock(dwOffSet, pKeyResult, psNumValues); BAIL_ON_NT_STATUS(status); cleanup: LWREG_UNLOCK_RWMUTEX(bInLock, &pKeyResult->mutex); return status; error: goto cleanup; }
// This can be called when a DB lock and active key list lock are both held NTSTATUS SqliteDeleteKeyInternal_inlock_inDblock( IN HANDLE handle, IN PCWSTR pwszKeyName ) { NTSTATUS status = STATUS_SUCCESS; PWSTR pwszParentKeyName = NULL; PREG_KEY_HANDLE pKeyHandle = NULL; // Do not free PREG_KEY_CONTEXT pKeyCtx = NULL; status = SqliteDeleteActiveKey_inlock((PCWSTR)pwszKeyName); BAIL_ON_NT_STATUS(status); status = SqliteOpenKeyInternal_inlock_inDblock(handle, pwszKeyName, 0, &pKeyHandle); BAIL_ON_NT_STATUS(status); BAIL_ON_NT_INVALID_POINTER(pKeyHandle); pKeyCtx = pKeyHandle->pKey; BAIL_ON_INVALID_KEY_CONTEXT(pKeyCtx); // Delete all the values of this key status = RegDbDeleteKey_inlock(ghCacheConnection, pKeyCtx->qwId, pKeyCtx->qwSdId, pwszKeyName); BAIL_ON_NT_STATUS(status); status = SqliteGetParentKeyName(pwszKeyName, '\\',&pwszParentKeyName); BAIL_ON_NT_STATUS(status); if (!LW_IS_NULL_OR_EMPTY_STR(pwszParentKeyName)) { SqliteCacheResetParentKeySubKeyInfo_inlock(pwszParentKeyName); } cleanup: SqliteSafeFreeKeyHandle_inlock(pKeyHandle); LWREG_SAFE_FREE_MEMORY(pwszParentKeyName); return status; error: goto cleanup; }
NTSTATUS SqliteOpenKeyInternal( IN HANDLE handle, IN PCWSTR pwszFullKeyName, // Full Key Path IN ACCESS_MASK AccessDesired, OUT OPTIONAL PREG_KEY_HANDLE* ppKeyHandle ) { NTSTATUS status = STATUS_SUCCESS; PREG_SRV_API_STATE pServerState = (PREG_SRV_API_STATE)handle; BOOLEAN bInLock = FALSE; BAIL_ON_NT_INVALID_STRING(pwszFullKeyName); BAIL_ON_NT_INVALID_POINTER(handle); if (!pServerState->pToken) { status = RegSrvCreateAccessToken(pServerState->peerUID, pServerState->peerGID, &pServerState->pToken); BAIL_ON_NT_STATUS(status); } LWREG_LOCK_MUTEX(bInLock, &gActiveKeyList.mutex); // pServerState->pToken should be created at this point status = SqliteOpenKeyInternal_inlock(handle, pwszFullKeyName, AccessDesired, ppKeyHandle); BAIL_ON_NT_STATUS(status); cleanup: LWREG_UNLOCK_MUTEX(bInLock, &gActiveKeyList.mutex); return status; error: goto cleanup; }
NTSTATUS SqliteCacheInsertDbKeyInfo_inlock( IN PREG_DB_KEY pRegKey ) { NTSTATUS status = STATUS_SUCCESS; BAIL_ON_NT_INVALID_POINTER(pRegKey); status = RegHashSetValue(gRegDbKeyList.pKeyList, (PVOID)pRegKey->pwszFullKeyName, (PVOID)pRegKey); BAIL_ON_NT_STATUS(status); cleanup: return status; error: goto cleanup; }
NTSTATUS SqliteCacheKeyDefaultValuesInfo( 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 = SqliteCacheKeyDefaultValuesInfo_inlock(pKeyResult); BAIL_ON_NT_STATUS(status); cleanup: LWREG_UNLOCK_RWMUTEX(bInLock, &pKeyResult->mutex); return status; error: goto cleanup; }
NTSTATUS RegHexStrToByteArray( IN PCSTR pszHexString, IN OPTIONAL DWORD* pdwHexStringLength, OUT UCHAR** ppucByteArray, OUT DWORD* pdwByteArrayLength ) { NTSTATUS status = 0; DWORD i = 0; DWORD dwHexChars = 0; UCHAR* pucByteArray = NULL; DWORD dwByteArrayLength = 0; BAIL_ON_NT_INVALID_POINTER(pszHexString); if (pdwHexStringLength) { dwHexChars = *pdwHexStringLength; } else { dwHexChars = strlen(pszHexString); } dwByteArrayLength = dwHexChars / 2; if ((dwHexChars & 0x00000001) != 0) { status = STATUS_INVALID_PARAMETER; BAIL_ON_NT_STATUS(status); } status = LW_RTL_ALLOCATE((PVOID*)&pucByteArray, UCHAR, sizeof(*pucByteArray)* dwByteArrayLength); BAIL_ON_NT_STATUS(status); for (i = 0; i < dwByteArrayLength; i++) { CHAR hexHi = pszHexString[2*i]; CHAR hexLow = pszHexString[2*i + 1]; UCHAR ucHi = 0; UCHAR ucLow = 0; status = RegHexCharToByte(hexHi, &ucHi); BAIL_ON_NT_STATUS(status); status = RegHexCharToByte(hexLow, &ucLow); BAIL_ON_NT_STATUS(status); pucByteArray[i] = (ucHi * 16) + ucLow; } *ppucByteArray = pucByteArray; *pdwByteArrayLength = dwByteArrayLength; cleanup: return status; error: LWREG_SAFE_FREE_MEMORY(pucByteArray); *ppucByteArray = NULL; *pdwByteArrayLength = 0; goto cleanup; }
NTSTATUS SqliteSetValueAttributes( IN HANDLE hRegConnection, IN HKEY hKey, IN OPTIONAL PCWSTR pwszSubKey, IN PCWSTR pValueName, IN PLWREG_VALUE_ATTRIBUTES pValueAttributes ) { NTSTATUS status = STATUS_SUCCESS; PWSTR pwszValueName = NULL; BOOLEAN bIsWrongType = TRUE; wchar16_t wszEmptyValueName[] = REG_EMPTY_VALUE_NAME_W; PWSTR pwszKeyNameWithSubKey = NULL; PREG_KEY_HANDLE pKeyHandle = (PREG_KEY_HANDLE)hKey; PREG_KEY_CONTEXT pKeyCtx = NULL; PREG_KEY_HANDLE pKeyHandleInUse = NULL; PREG_KEY_CONTEXT pKeyCtxInUse = NULL; // Do not free PBYTE pData = NULL; DWORD cbData = 0; BAIL_ON_NT_INVALID_POINTER(pKeyHandle); pKeyCtx = pKeyHandle->pKey; BAIL_ON_INVALID_KEY_CONTEXT(pKeyCtx); if (!RegValidValueAttributes(pValueAttributes)) { status = STATUS_INVALID_PARAMETER; BAIL_ON_NT_STATUS(status); } if (pwszSubKey) { status = LwRtlWC16StringAllocatePrintfW( &pwszKeyNameWithSubKey, L"%ws\\%ws", pKeyCtx->pwszKeyName, pwszSubKey); BAIL_ON_NT_STATUS(status); } status = SqliteOpenKeyInternal(hRegConnection, pwszSubKey ? pwszKeyNameWithSubKey : pKeyCtx->pwszKeyName, KEY_SET_VALUE, &pKeyHandleInUse); BAIL_ON_NT_STATUS(status); status = RegSrvAccessCheckKeyHandle(pKeyHandleInUse, KEY_SET_VALUE); BAIL_ON_NT_STATUS(status); pKeyCtxInUse = pKeyHandleInUse->pKey; BAIL_ON_INVALID_KEY_CONTEXT(pKeyCtxInUse); status = LwRtlWC16StringDuplicate(&pwszValueName, !pValueName ? wszEmptyValueName : pValueName); BAIL_ON_NT_STATUS(status); status = RegDbGetValueAttributes( ghCacheConnection, pKeyCtxInUse->qwId, (PCWSTR)pwszValueName, (REG_DATA_TYPE)pValueAttributes->ValueType, &bIsWrongType, NULL); if (!status) { status = STATUS_DUPLICATE_NAME; BAIL_ON_NT_STATUS(status); } else if (STATUS_OBJECT_NAME_NOT_FOUND == status) { status = 0; } BAIL_ON_NT_STATUS(status); pData = pValueAttributes->pDefaultValue; cbData = pValueAttributes->DefaultValueLen; if (cbData == 0) { goto done; } switch (pValueAttributes->ValueType) { case REG_BINARY: case REG_DWORD: break; case REG_MULTI_SZ: case REG_SZ: if (cbData == 1) { status = STATUS_INTERNAL_ERROR; BAIL_ON_NT_STATUS(status); } if (!pData || pData[cbData-1] != '\0' || pData[cbData-2] != '\0' ) { status = STATUS_INVALID_PARAMETER; BAIL_ON_NT_STATUS(status); } break; default: status = STATUS_NOT_SUPPORTED; BAIL_ON_NT_STATUS(status); } done: status = RegDbSetValueAttributes(ghCacheConnection, pKeyCtxInUse->qwId, pwszValueName, pValueAttributes); BAIL_ON_NT_STATUS(status); SqliteCacheResetKeyValueInfo(pKeyCtxInUse->pwszKeyName); cleanup: LWREG_SAFE_FREE_MEMORY(pwszValueName); LWREG_SAFE_FREE_MEMORY(pwszKeyNameWithSubKey); SqliteSafeFreeKeyHandle(pKeyHandleInUse); return status; error: goto cleanup; }
NTSTATUS SqliteDeleteValueAttributes( IN HANDLE hRegConnection, IN HKEY hKey, IN OPTIONAL PCWSTR pwszSubKey, IN PCWSTR pValueName ) { NTSTATUS status = STATUS_SUCCESS; PWSTR pwszValueName = NULL; wchar16_t wszEmptyValueName[] = REG_EMPTY_VALUE_NAME_W; PWSTR pwszKeyNameWithSubKey = NULL; PREG_KEY_HANDLE pKeyHandle = (PREG_KEY_HANDLE)hKey; PREG_KEY_CONTEXT pKeyCtx = NULL; PREG_KEY_HANDLE pKeyHandleInUse = NULL; PREG_KEY_CONTEXT pKeyCtxInUse = NULL; BAIL_ON_NT_INVALID_POINTER(pKeyHandle); pKeyCtx = pKeyHandle->pKey; BAIL_ON_INVALID_KEY_CONTEXT(pKeyCtx); if (pwszSubKey) { status = LwRtlWC16StringAllocatePrintfW( &pwszKeyNameWithSubKey, L"%ws\\%ws", pKeyCtx->pwszKeyName, pwszSubKey); BAIL_ON_NT_STATUS(status); } status = SqliteOpenKeyInternal(hRegConnection, pwszSubKey ? pwszKeyNameWithSubKey : pKeyCtx->pwszKeyName, KEY_SET_VALUE | DELETE, &pKeyHandleInUse); BAIL_ON_NT_STATUS(status); status = RegSrvAccessCheckKeyHandle(pKeyHandleInUse, KEY_SET_VALUE); BAIL_ON_NT_STATUS(status); pKeyCtxInUse = pKeyHandleInUse->pKey; BAIL_ON_INVALID_KEY_CONTEXT(pKeyCtxInUse); status = LwRtlWC16StringDuplicate(&pwszValueName, !pValueName ? wszEmptyValueName : pValueName); BAIL_ON_NT_STATUS(status); status = RegDbGetValueAttributes( ghCacheConnection, pKeyCtxInUse->qwId, (PCWSTR)pwszValueName, REG_NONE, NULL, NULL); BAIL_ON_NT_STATUS(status); status = RegDbDeleteValueAttributes(ghCacheConnection, pKeyCtxInUse->qwId, (PCWSTR)pwszValueName); BAIL_ON_NT_STATUS(status); SqliteCacheResetKeyValueInfo(pKeyCtxInUse->pwszKeyName); cleanup: SqliteSafeFreeKeyHandle(pKeyHandleInUse); LWREG_SAFE_FREE_MEMORY(pwszValueName); LWREG_SAFE_FREE_MEMORY(pwszKeyNameWithSubKey); return status; error: goto cleanup; }
NTSTATUS SqliteGetValueAttributes_Internal( IN HANDLE hRegConnection, IN HKEY hKey, IN OPTIONAL PCWSTR pwszSubKey, IN PCWSTR pValueName, IN OPTIONAL REG_DATA_TYPE dwType, // Whether bail or not in case there is no value attributes IN BOOLEAN bDoBail, OUT OPTIONAL PLWREG_CURRENT_VALUEINFO* ppCurrentValue, OUT OPTIONAL PLWREG_VALUE_ATTRIBUTES* ppValueAttributes ) { NTSTATUS status = STATUS_SUCCESS; PWSTR pwszValueName = NULL; PREG_DB_VALUE_ATTRIBUTES pRegEntry = NULL; PREG_DB_VALUE pRegValueEntry = NULL; BOOLEAN bIsWrongType = FALSE; wchar16_t wszEmptyValueName[] = REG_EMPTY_VALUE_NAME_W; PWSTR pwszKeyNameWithSubKey = NULL; PREG_KEY_HANDLE pKeyHandle = (PREG_KEY_HANDLE)hKey; PREG_KEY_CONTEXT pKeyCtx = NULL; PREG_KEY_HANDLE pKeyHandleInUse = NULL; PREG_KEY_CONTEXT pKeyCtxInUse = NULL; PLWREG_CURRENT_VALUEINFO pCurrentValue = NULL; BOOLEAN bInDbLock = FALSE; BOOLEAN bInLock = FALSE; PSTR pszError = NULL; PREG_DB_CONNECTION pConn = (PREG_DB_CONNECTION)ghCacheConnection; PREG_SRV_API_STATE pServerState = (PREG_SRV_API_STATE)hRegConnection; BAIL_ON_NT_INVALID_POINTER(pKeyHandle); pKeyCtx = pKeyHandle->pKey; BAIL_ON_INVALID_KEY_CONTEXT(pKeyCtx); if (!ppCurrentValue && !ppValueAttributes) { status = STATUS_INVALID_PARAMETER; BAIL_ON_NT_STATUS(status); } if (pwszSubKey) { status = LwRtlWC16StringAllocatePrintfW( &pwszKeyNameWithSubKey, L"%ws\\%ws", pKeyCtx->pwszKeyName, pwszSubKey); BAIL_ON_NT_STATUS(status); } if (!pServerState->pToken) { status = RegSrvCreateAccessToken(pServerState->peerUID, pServerState->peerGID, &pServerState->pToken); BAIL_ON_NT_STATUS(status); } LWREG_LOCK_MUTEX(bInLock, &gActiveKeyList.mutex); ENTER_SQLITE_LOCK(&pConn->lock, bInDbLock); status = sqlite3_exec( pConn->pDb, "begin;", NULL, NULL, &pszError); BAIL_ON_SQLITE3_ERROR(status, pszError); // pServerState->pToken should be created at this point status = SqliteOpenKeyInternal_inlock_inDblock( hRegConnection, pwszSubKey ? pwszKeyNameWithSubKey : pKeyCtx->pwszKeyName, KEY_QUERY_VALUE, &pKeyHandleInUse); BAIL_ON_NT_STATUS(status); // ACL check status = RegSrvAccessCheckKeyHandle(pKeyHandleInUse, KEY_QUERY_VALUE); BAIL_ON_NT_STATUS(status); pKeyCtxInUse = pKeyHandleInUse->pKey; BAIL_ON_INVALID_KEY_CONTEXT(pKeyCtxInUse); status = LwRtlWC16StringDuplicate(&pwszValueName, !pValueName ? wszEmptyValueName : pValueName); BAIL_ON_NT_STATUS(status); // Optionally get value if (ppCurrentValue) { status = RegDbGetKeyValue_inlock( ghCacheConnection, pKeyCtxInUse->qwId, pwszValueName, dwType, &bIsWrongType, &pRegValueEntry); if (!status) { status = LW_RTL_ALLOCATE((PVOID*)&pCurrentValue, LWREG_CURRENT_VALUEINFO, sizeof(*pCurrentValue)); BAIL_ON_NT_STATUS(status); pCurrentValue->cbData = pRegValueEntry->dwValueLen; pCurrentValue->dwType = pRegValueEntry->type; if (pCurrentValue->cbData) { status = LW_RTL_ALLOCATE((PVOID*)&pCurrentValue->pvData, VOID, pCurrentValue->cbData); BAIL_ON_NT_STATUS(status); memcpy(pCurrentValue->pvData, pRegValueEntry->pValue, pCurrentValue->cbData); } } else if (LW_STATUS_OBJECT_NAME_NOT_FOUND == status) { status = 0; } BAIL_ON_NT_STATUS(status); } // Get value attributes if (ppValueAttributes) { status = RegDbGetValueAttributes_inlock( ghCacheConnection, pKeyCtxInUse->qwId, pwszValueName, REG_NONE, &bIsWrongType, &pRegEntry); if (!bDoBail && LW_STATUS_OBJECT_NAME_NOT_FOUND == status) { status = LW_RTL_ALLOCATE((PVOID*)&pRegEntry, REG_DB_VALUE_ATTRIBUTES, sizeof(*pRegEntry)); BAIL_ON_NT_STATUS(status); } BAIL_ON_NT_STATUS(status); } status = sqlite3_exec( pConn->pDb, "end", NULL, NULL, &pszError); BAIL_ON_SQLITE3_ERROR(status, pszError); REG_LOG_VERBOSE("Registry::sqldb.c SqliteGetValueAttributes_Internal() finished"); if (ppCurrentValue) { *ppCurrentValue = pCurrentValue; pCurrentValue = NULL; } if (ppValueAttributes) { *ppValueAttributes = pRegEntry->pValueAttributes; pRegEntry->pValueAttributes = NULL; } cleanup: LEAVE_SQLITE_LOCK(&pConn->lock, bInDbLock); LWREG_UNLOCK_MUTEX(bInLock, &gActiveKeyList.mutex); SqliteSafeFreeKeyHandle(pKeyHandleInUse); LWREG_SAFE_FREE_MEMORY(pwszValueName); LWREG_SAFE_FREE_MEMORY(pwszKeyNameWithSubKey); RegDbSafeFreeEntryValue(&pRegValueEntry); RegSafeFreeCurrentValueInfo(&pCurrentValue); RegDbSafeFreeEntryValueAttributes(&pRegEntry); return status; error: if (pszError) { sqlite3_free(pszError); } sqlite3_exec(pConn->pDb, "rollback", NULL, NULL, NULL); if (ppCurrentValue) { *ppCurrentValue = NULL; } if (ppValueAttributes) { *ppValueAttributes = NULL; } goto cleanup; }