VOID SqliteReleaseDbKeyInfo( PREG_DB_KEY pRegKey ) { BOOLEAN bInLock = FALSE; LWREG_LOCK_MUTEX(bInLock, &gRegDbKeyList.mutex); SqliteReleaseDbKeyInfo_inlock(pRegKey); LWREG_UNLOCK_MUTEX(bInLock, &gRegDbKeyList.mutex); }
VOID SqliteReleaseKeyContext( PREG_KEY_CONTEXT pKeyResult ) { BOOLEAN bInLock = FALSE; LWREG_LOCK_MUTEX(bInLock, &gActiveKeyList.mutex); SqliteReleaseKeyContext_inlock(pKeyResult); LWREG_UNLOCK_MUTEX(bInLock, &gActiveKeyList.mutex); }
VOID SqliteCacheDeleteDbKeyInfo( IN PCWSTR pwszKeyName ) { BOOLEAN bInLock = FALSE; LWREG_LOCK_MUTEX(bInLock, &gRegDbKeyList.mutex); SqliteCacheDeleteDbKeyInfo_inlock(pwszKeyName); LWREG_UNLOCK_MUTEX(bInLock, &gRegDbKeyList.mutex); return; }
VOID SqliteCacheDeleteActiveKey( IN PWSTR pwszKeyName ) { BOOLEAN bInLock = FALSE; LWREG_LOCK_MUTEX(bInLock, &gActiveKeyList.mutex); SqliteCacheDeleteActiveKey_inlock(pwszKeyName); LWREG_UNLOCK_MUTEX(bInLock, &gActiveKeyList.mutex); return; }
/*Find whether this key has already been in active Key list, * If not, create key context and add the active key to the list * Otherwise, increment the existing active key reference count by 1 */ PREG_KEY_CONTEXT SqliteCacheLocateActiveKey( IN PCWSTR pwszKeyName ) { PREG_KEY_CONTEXT pKeyResult = NULL; BOOLEAN bInLock = FALSE; LWREG_LOCK_MUTEX(bInLock, &gActiveKeyList.mutex); pKeyResult = SqliteCacheLocateActiveKey_inlock(pwszKeyName); LWREG_UNLOCK_MUTEX(bInLock, &gActiveKeyList.mutex); return pKeyResult; }
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 SqliteDeleteActiveKey( IN PCWSTR pwszKeyName ) { NTSTATUS status = STATUS_SUCCESS; BOOLEAN bInLock = FALSE; LWREG_LOCK_MUTEX(bInLock, &gActiveKeyList.mutex); status = SqliteDeleteActiveKey_inlock(pwszKeyName); BAIL_ON_NT_STATUS(status); cleanup: LWREG_UNLOCK_MUTEX(bInLock, &gActiveKeyList.mutex); return status; error: goto cleanup; }
NTSTATUS SqliteCacheInsertActiveKey( IN PREG_KEY_CONTEXT pKeyResult ) { NTSTATUS status = STATUS_SUCCESS; BOOLEAN bInLock = FALSE; LWREG_LOCK_MUTEX(bInLock, &gActiveKeyList.mutex); status = SqliteCacheInsertActiveKey_inlock(pKeyResult); BAIL_ON_NT_STATUS(status); cleanup: LWREG_UNLOCK_MUTEX(bInLock, &gActiveKeyList.mutex); return status; error: goto cleanup; }
NTSTATUS SqliteCacheInsertDbKeyInfo( IN PREG_DB_KEY pRegKey ) { NTSTATUS status = 0; BOOLEAN bInLock = FALSE; LWREG_LOCK_MUTEX(bInLock, &gRegDbKeyList.mutex); status = SqliteCacheInsertDbKeyInfo_inlock(pRegKey); BAIL_ON_NT_STATUS(status); cleanup: LWREG_UNLOCK_MUTEX(bInLock, &gRegDbKeyList.mutex); return status; error: goto cleanup; }
NTSTATUS SqliteCacheGetDbKeyInfo( IN PCWSTR pwszKeyName, OUT PREG_DB_KEY* ppRegKey ) { NTSTATUS status = 0; BOOLEAN bInLock = FALSE; //Do not free PREG_DB_KEY pRegKeyRef = NULL; PREG_DB_KEY pRegKey = NULL; LWREG_LOCK_MUTEX(bInLock, &gRegDbKeyList.mutex); status = RegHashGetValue(gRegDbKeyList.pKeyList, pwszKeyName, (PVOID*)&pRegKeyRef); BAIL_ON_NT_STATUS(status); status = RegDbDuplicateDbKeyEntry(pRegKeyRef, &pRegKey); BAIL_ON_NT_STATUS(status); *ppRegKey = pRegKey; cleanup: LWREG_UNLOCK_MUTEX(bInLock, &gRegDbKeyList.mutex); return status; error: *ppRegKey = NULL; RegDbSafeFreeEntryKey(&pRegKey); goto cleanup; }
/* Create a new key, if the key exists already, * open the existing key */ NTSTATUS SqliteCreateKeyInternal( IN OPTIONAL HANDLE handle, IN PREG_KEY_CONTEXT pParentKeyCtx, IN PWSTR pwszFullKeyName, // Full Key Path IN ACCESS_MASK AccessDesired, IN OPTIONAL PSECURITY_DESCRIPTOR_RELATIVE pSecDescRel, IN ULONG ulSecDescLength, OUT OPTIONAL PREG_KEY_HANDLE* ppKeyHandle, OUT OPTIONAL PDWORD pdwDisposition ) { NTSTATUS status = STATUS_SUCCESS; PREG_DB_KEY pRegEntry = NULL; PREG_KEY_HANDLE pKeyHandle = NULL; PREG_KEY_CONTEXT pKeyCtx = NULL; BOOLEAN bInLock = FALSE; PREG_SRV_API_STATE pServerState = (PREG_SRV_API_STATE)handle; PSECURITY_DESCRIPTOR_RELATIVE pSecDescRelToSet = NULL; ULONG ulSecDescLengthToSet = 0; DWORD dwDisposition = 0; // Full key path BAIL_ON_NT_INVALID_STRING(pwszFullKeyName); // when starting up lwregd pServerState is NULL and // creating root key can skip ACL check if (pServerState && !pServerState->pToken) { status = RegSrvCreateAccessToken(pServerState->peerUID, pServerState->peerGID, &pServerState->pToken); BAIL_ON_NT_STATUS(status); } LWREG_LOCK_MUTEX(bInLock, &gActiveKeyList.mutex); status = SqliteOpenKeyInternal_inlock( handle, pwszFullKeyName, // Full Key Path AccessDesired, &pKeyHandle); if (!status) { dwDisposition = REG_OPENED_EXISTING_KEY; goto done; } else if (STATUS_OBJECT_NAME_NOT_FOUND == status) { status = 0; } BAIL_ON_NT_STATUS(status); // Root Key has to be created with a given SD if (!pParentKeyCtx && !pSecDescRel) { status = STATUS_INTERNAL_ERROR; BAIL_ON_NT_STATUS(status); } // ACL check // Get key's security descriptor // Inherit from its direct parent or given by caller if (!pSecDescRel || !ulSecDescLength) { BAIL_ON_INVALID_KEY_CONTEXT(pParentKeyCtx); status = SqliteCacheKeySecurityDescriptor(pParentKeyCtx); BAIL_ON_NT_STATUS(status); pSecDescRelToSet = pParentKeyCtx->pSecurityDescriptor; ulSecDescLengthToSet = pParentKeyCtx->ulSecDescLength; } else { pSecDescRelToSet = pSecDescRel; ulSecDescLengthToSet = ulSecDescLength; } // Make sure SD has at least owner information if (!RtlValidRelativeSecurityDescriptor(pSecDescRelToSet, ulSecDescLengthToSet, OWNER_SECURITY_INFORMATION)) { status = STATUS_INVALID_SECURITY_DESCR; BAIL_ON_NT_STATUS(status); } // Create key with SD status = RegDbCreateKey(ghCacheConnection, pwszFullKeyName, pSecDescRelToSet, ulSecDescLengthToSet, &pRegEntry); BAIL_ON_NT_STATUS(status); if (pParentKeyCtx) { SqliteCacheResetParentKeySubKeyInfo_inlock(pParentKeyCtx->pwszKeyName); } status = SqliteCreateKeyContext(pRegEntry, &pKeyCtx); BAIL_ON_NT_STATUS(status); // Cache this new key in gActiveKeyList status = SqliteCacheInsertActiveKey_inlock(pKeyCtx); BAIL_ON_NT_STATUS(status); status = SqliteCreateKeyHandle(pServerState ? pServerState->pToken : NULL, AccessDesired, pKeyCtx, &pKeyHandle); BAIL_ON_NT_STATUS(status); pKeyCtx = NULL; dwDisposition = REG_CREATED_NEW_KEY; done: if (ppKeyHandle) { *ppKeyHandle = pKeyHandle; } else { SqliteSafeFreeKeyHandle_inlock(pKeyHandle); } if (pdwDisposition) { *pdwDisposition = dwDisposition; } cleanup: SqliteReleaseKeyContext_inlock(pKeyCtx); LWREG_UNLOCK_MUTEX(bInLock, &gActiveKeyList.mutex); RegDbSafeFreeEntryKey(&pRegEntry); return status; error: if (ppKeyHandle) { *ppKeyHandle = NULL; } SqliteSafeFreeKeyHandle_inlock(pKeyHandle); 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; }