/* 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 library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2.1 of the license, or (at * your option) any later version. * * This library 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 Lesser * General Public License for more details. You should have received a copy * of the GNU Lesser 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 * LESSER 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: * * lwps-provider.c * * Abstract: * * Likewise Password Storage (LWPS) * * Storage Provider API * * Authors: Krishna Ganugapati (krishnag@likewisesoftware.com) * Sriram Nambakam (snambakam@likewisesoftware.com) */ #include "lwps-utils.h" #include "lwps/lwps.h" #include "lwps-provider.h" #include "lwps-provider_p.h" #include #include #define LWPS_CONFIG_PATH "registry" #ifdef ENABLE_STATIC_PROVIDERS extern DWORD LWPS_INITIALIZE_PROVIDER(sqldb)(PCSTR, PSTR*, PLWPS_PROVIDER_FUNC_TABLE*); extern DWORD LWPS_SHUTDOWN_PROVIDER(sqldb)(PSTR, PLWPS_PROVIDER_FUNC_TABLE); extern DWORD LWPS_INITIALIZE_PROVIDER(tdb)(PCSTR, PSTR*, PLWPS_PROVIDER_FUNC_TABLE*); extern DWORD LWPS_SHUTDOWN_PROVIDER(tdb)(PSTR, PLWPS_PROVIDER_FUNC_TABLE); extern DWORD LWPS_INITIALIZE_PROVIDER(filedb)(PCSTR, PSTR*, PLWPS_PROVIDER_FUNC_TABLE*); extern DWORD LWPS_SHUTDOWN_PROVIDER(filedb)(PSTR, PLWPS_PROVIDER_FUNC_TABLE); extern DWORD LWPS_INITIALIZE_PROVIDER(regdb)(PCSTR, PSTR*, PLWPS_PROVIDER_FUNC_TABLE*); extern DWORD LWPS_SHUTDOWN_PROVIDER(regdb)(PSTR, PLWPS_PROVIDER_FUNC_TABLE); static LWPS_STATIC_PROVIDER gStaticProviders[] = { #ifdef ENABLE_FILEDB LWPS_STATIC_PROVIDER_ENTRY(filedb, filedb), #endif #ifdef ENABLE_SQLDB LWPS_STATIC_PROVIDER_ENTRY(sqldb, sqldb), #endif #ifdef ENABLE_TDB LWPS_STATIC_PROVIDER_ENTRY(tdb, tdb), #endif #ifdef ENABLE_REGDB LWPS_STATIC_PROVIDER_ENTRY(regdb, regdb), #endif LWPS_STATIC_PROVIDER_END }; #endif static DWORD LwpsBuiltInProviders( PLWPS_STACK* ppProviderStack ); DWORD LwpsOpenProvider( LwpsPasswordStoreType storeType, PLWPS_STORAGE_PROVIDER* ppProvider ) { DWORD dwError = 0; PLWPS_STORAGE_PROVIDER pProvider = NULL; PLWPS_STACK pProviderStack = NULL; dwError = LwpsBuiltInProviders(&pProviderStack); BAIL_ON_LWPS_ERROR(dwError); if (storeType == LWPS_PASSWORD_STORE_DEFAULT) { dwError = LwpsFindDefaultProvider( &pProviderStack, &pProvider); BAIL_ON_LWPS_ERROR(dwError); } else { dwError = LwpsFindSpecificProvider( storeType, &pProviderStack, &pProvider); BAIL_ON_LWPS_ERROR(dwError); } dwError = LwpsInitProvider( LWPS_CONFIG_PATH, pProvider); BAIL_ON_LWPS_ERROR(dwError); *ppProvider = pProvider; cleanup: if (pProviderStack) { LwpsStackForeach( pProviderStack, &LwpsConfigFreeProviderInStack, NULL); LwpsStackFree(pProviderStack); } return dwError; error: *ppProvider = NULL; if (pProvider) { LwpsFreeProvider(pProvider); } goto cleanup; } DWORD LwpsFindDefaultProvider( PLWPS_STACK* ppStack, PLWPS_STORAGE_PROVIDER* ppProvider ) { DWORD dwError = 0; PLWPS_STORAGE_PROVIDER pProvider = NULL; PLWPS_STORAGE_PROVIDER pFirstProvider = NULL; int iProvider = 0; pProvider = (PLWPS_STORAGE_PROVIDER) LwpsStackPop(ppStack); while (pProvider) { if (pProvider->bDefault) break; if (!iProvider++) { pFirstProvider = pProvider; } else { LwpsFreeProvider(pProvider); } pProvider = NULL; pProvider = (PLWPS_STORAGE_PROVIDER) LwpsStackPop(ppStack); } if (pProvider) { *ppProvider = pProvider; } else if (pFirstProvider) { *ppProvider = pFirstProvider; pFirstProvider = NULL; } else { dwError = LWPS_ERROR_NO_SUCH_PROVIDER; BAIL_ON_LWPS_ERROR(dwError); } cleanup: if (pFirstProvider) { LwpsFreeProvider(pFirstProvider); } return dwError; error: *ppProvider = NULL; goto cleanup; } DWORD LwpsFindSpecificProvider( LwpsPasswordStoreType storeType, PLWPS_STACK* ppStack, PLWPS_STORAGE_PROVIDER* ppProvider ) { DWORD dwError = 0; PLWPS_STORAGE_PROVIDER pProvider = NULL; pProvider = (PLWPS_STORAGE_PROVIDER) LwpsStackPop(ppStack); while (pProvider) { if (pProvider->storeType == storeType) { break; } LwpsFreeProvider(pProvider); pProvider = NULL; pProvider = (PLWPS_STORAGE_PROVIDER) LwpsStackPop(ppStack); } if (!pProvider) { dwError = LWPS_ERROR_NO_SUCH_PROVIDER; BAIL_ON_LWPS_ERROR(dwError); } *ppProvider = pProvider; cleanup: return dwError; error: *ppProvider = NULL; goto cleanup; } DWORD LwpsFindAllProviders( PLWPS_STACK* ppStack ) { DWORD dwError = 0; PLWPS_STACK pProviderStack = NULL; dwError = LwpsBuiltInProviders(&pProviderStack); BAIL_ON_LWPS_ERROR(dwError); *ppStack = LwpsStackReverse(pProviderStack); cleanup: return dwError; error: if (pProviderStack) { LwpsStackForeach( pProviderStack, &LwpsConfigFreeProviderInStack, NULL); LwpsStackFree(pProviderStack); } goto cleanup; } DWORD LwpsConfigStartSection( PCSTR pszSectionName, PVOID pData, PBOOLEAN pbSkipSection, PBOOLEAN pbContinue ) { DWORD dwError = 0; PLWPS_STACK* ppProviderStack = (PLWPS_STACK*)pData; PLWPS_STORAGE_PROVIDER pProvider = NULL; BOOLEAN bContinue = TRUE; BOOLEAN bSkipSection = FALSE; PCSTR pszLibName = NULL; BAIL_ON_INVALID_POINTER(ppProviderStack); if (IsNullOrEmptyString(pszSectionName) || strncasecmp(pszSectionName, "password storage:", sizeof("password storage:") -1)) { bSkipSection = TRUE; goto done; } pszLibName = pszSectionName + sizeof("password storage:") - 1; if (IsNullOrEmptyString(pszLibName)) { bSkipSection = TRUE; goto done; } dwError = LwpsAllocateMemory( sizeof(LWPS_STORAGE_PROVIDER), (PVOID*)&pProvider); BAIL_ON_LWPS_ERROR(dwError); dwError = LwpsAllocateString( pszLibName, &pProvider->pszId); BAIL_ON_LWPS_ERROR(dwError); dwError = LwpsStackPush( pProvider, ppProviderStack); BAIL_ON_LWPS_ERROR(dwError); done: *pbSkipSection = bSkipSection; *pbContinue = bContinue; cleanup: return dwError; error: if (pProvider) { LwpsFreeProvider(pProvider); } *pbContinue = FALSE; *pbSkipSection = TRUE; goto cleanup; } DWORD LwpsConfigNameValuePair( PCSTR pszName, PCSTR pszValue, PVOID pData, PBOOLEAN pbContinue ) { DWORD dwError = 0; PLWPS_STACK* ppProviderStack = (PLWPS_STACK*)pData; PLWPS_STORAGE_PROVIDER pProvider = NULL; PSTR pszProviderLibpath = NULL; BAIL_ON_INVALID_POINTER(ppProviderStack); pProvider = (PLWPS_STORAGE_PROVIDER)LwpsStackPeek(*ppProviderStack); if (!pProvider) { dwError = LWPS_ERROR_INTERNAL; BAIL_ON_LWPS_ERROR(dwError); } if (!strcasecmp(pszName, "path")) { if (!IsNullOrEmptyString(pszValue)) { dwError = LwpsAllocateString( pszValue, &pszProviderLibpath); BAIL_ON_LWPS_ERROR(dwError); } LWPS_SAFE_FREE_STRING(pProvider->pszLibPath); pProvider->pszLibPath = pszProviderLibpath; pszProviderLibpath = NULL; } else if (!strcasecmp(pszName, "type") && !IsNullOrEmptyString(pszValue)) { if (!strcasecmp(pszValue, "sqldb")) { pProvider->storeType = LWPS_PASSWORD_STORE_SQLDB; } else if (!strcasecmp(pszValue, "tdb")) { pProvider->storeType = LWPS_PASSWORD_STORE_TDB; } else if (!strcasecmp(pszValue, "filedb")) { pProvider->storeType = LWPS_PASSWORD_STORE_FILEDB; } else if (!strcasecmp(pszValue, "regdb")) { pProvider->storeType = LWPS_PASSWORD_STORE_REGDB; } else { pProvider->storeType = LWPS_PASSWORD_STORE_UNKNOWN; } } else if (!strcasecmp(pszName, "default")) { if (!IsNullOrEmptyString(pszValue) && (*pszValue == 'Y') && (*pszValue == 'y') && (*pszValue == '1')) { pProvider->bDefault = TRUE; } else { pProvider->bDefault = FALSE; } } *pbContinue = TRUE; cleanup: return dwError; error: LWPS_SAFE_FREE_STRING(pszProviderLibpath); *pbContinue = FALSE; goto cleanup; } DWORD LwpsConfigFreeProviderInStack( PVOID pItem, PVOID pData ) { if (pItem) { LwpsFreeProvider((PLWPS_STORAGE_PROVIDER)pItem); } return 0; } DWORD LwpsInitProvider( PCSTR pszConfigPath, PLWPS_STORAGE_PROVIDER pProvider ) { DWORD dwError = 0; PFNLWPS_INITIALIZE_PROVIDER pfnInitProvider = NULL; PCSTR pszError = NULL; #ifdef ENABLE_STATIC_PROVIDERS { int i = 0; /* First look for a static provider entry with the given name */ for (i = 0; gStaticProviders[i].pszId; i++) { if (!strcmp(gStaticProviders[i].pszId, pProvider->pszId)) { pfnInitProvider = gStaticProviders[i].pInitialize; pProvider->pFnShutdown = gStaticProviders[i].pShutdown; LWPS_LOG_DEBUG("Provider %s loaded from static list", pProvider->pszId); break; } } } #endif if (!pfnInitProvider) { if (IsNullOrEmptyString(pProvider->pszLibPath)) { dwError = ENOENT; BAIL_ON_LWPS_ERROR(dwError); } dlerror(); pProvider->pLibHandle = dlopen(pProvider->pszLibPath, RTLD_NOW | RTLD_GLOBAL); if (pProvider->pLibHandle == NULL) { pszError = dlerror(); if (!IsNullOrEmptyString(pszError)) { LWPS_LOG_ERROR("%s", pszError); } dwError = LWPS_ERROR_INVALID_PROVIDER; BAIL_ON_LWPS_ERROR(dwError); } dlerror(); pfnInitProvider = (PFNLWPS_INITIALIZE_PROVIDER)dlsym( pProvider->pLibHandle, LWPS_SYMBOL_STORAGE_PROVIDER_INITIALIZE); if (pfnInitProvider == NULL) { dwError = LWPS_ERROR_INVALID_PROVIDER; BAIL_ON_LWPS_ERROR(dwError); } dlerror(); pProvider->pFnShutdown = (PFNLWPS_SHUTDOWN_PROVIDER)dlsym( pProvider->pLibHandle, LWPS_SYMBOL_STORAGE_PROVIDER_SHUTDOWN); if (pProvider->pFnShutdown == NULL) { dwError = LWPS_ERROR_INVALID_PROVIDER; BAIL_ON_LWPS_ERROR(dwError); } } dwError = pfnInitProvider( pszConfigPath, &pProvider->pszName, &pProvider->pFnTable); BAIL_ON_LWPS_ERROR(dwError); cleanup: return dwError; error: goto cleanup; } VOID LwpsFreeProvider( PLWPS_STORAGE_PROVIDER pProvider ) { if (pProvider) { if (pProvider->pLibHandle) { if (pProvider->pFnShutdown) { pProvider->pFnShutdown( pProvider->pszName, pProvider->pFnTable); } dlclose(pProvider->pLibHandle); } LWPS_SAFE_FREE_STRING(pProvider->pszLibPath); LWPS_SAFE_FREE_STRING(pProvider->pszId); LwpsFreeMemory(pProvider); } } DWORD LwpsWritePasswordToStore( PVOID pItem, PVOID pData ) { DWORD dwError = 0; PLWPS_STORAGE_PROVIDER pProvider = (PLWPS_STORAGE_PROVIDER)pItem; PLWPS_PASSWORD_INFO pInfo = (PLWPS_PASSWORD_INFO)pData; HANDLE hProvider = (HANDLE)NULL; BAIL_ON_INVALID_POINTER(pProvider); dwError = LwpsInitProvider( LWPS_CONFIG_PATH, pProvider); BAIL_ON_LWPS_ERROR(dwError); dwError = pProvider->pFnTable->pFnOpenProvider(&hProvider); BAIL_ON_LWPS_ERROR(dwError); dwError = pProvider->pFnTable->pFnWritePassword(hProvider, pInfo); BAIL_ON_LWPS_ERROR(dwError); cleanup: if (pProvider && (hProvider != (HANDLE)NULL)) { pProvider->pFnTable->pFnCloseProvider(hProvider); } return dwError; error: LWPS_LOG_ERROR("Failed to write password to provider: %s [Error code:%d]", ((pProvider && !IsNullOrEmptyString(pProvider->pszName)) ? pProvider->pszName : ""), dwError); goto cleanup; } DWORD LwpsDeleteEntriesInStore( PVOID pItem, PVOID pData ) { DWORD dwError = 0; PLWPS_STORAGE_PROVIDER pProvider = (PLWPS_STORAGE_PROVIDER)pItem; HANDLE hProvider = (HANDLE)NULL; BAIL_ON_INVALID_POINTER(pProvider); dwError = LwpsInitProvider( LWPS_CONFIG_PATH, pProvider); BAIL_ON_LWPS_ERROR(dwError); dwError = pProvider->pFnTable->pFnOpenProvider(&hProvider); BAIL_ON_LWPS_ERROR(dwError); dwError = pProvider->pFnTable->pFnDeleteAllEntries(hProvider); BAIL_ON_LWPS_ERROR(dwError); cleanup: if (pProvider && (hProvider != (HANDLE)NULL)) { pProvider->pFnTable->pFnCloseProvider(hProvider); } return dwError; error: LWPS_LOG_ERROR("Failed to delete all entries in provider: %s [Error code:%d]", ((pProvider && !IsNullOrEmptyString(pProvider->pszName)) ? pProvider->pszName : ""), dwError); goto cleanup; } DWORD LwpsDeleteHostInStore( PVOID pItem, PVOID pData ) { DWORD dwError = 0; PLWPS_STORAGE_PROVIDER pProvider = (PLWPS_STORAGE_PROVIDER)pItem; HANDLE hProvider = (HANDLE)NULL; PCSTR pszHostname = (PCSTR)pData; BAIL_ON_INVALID_POINTER(pProvider); BAIL_ON_INVALID_POINTER(pszHostname); dwError = LwpsInitProvider( LWPS_CONFIG_PATH, pProvider); BAIL_ON_LWPS_ERROR(dwError); dwError = pProvider->pFnTable->pFnOpenProvider(&hProvider); BAIL_ON_LWPS_ERROR(dwError); dwError = pProvider->pFnTable->pFnDeleteHostEntry(hProvider, pszHostname); BAIL_ON_LWPS_ERROR(dwError); cleanup: if (pProvider && (hProvider != (HANDLE)NULL)) { pProvider->pFnTable->pFnCloseProvider(hProvider); } return dwError; error: LWPS_LOG_ERROR("Failed to delete all entries in provider: %s [Error code:%d]", ((pProvider && !IsNullOrEmptyString(pProvider->pszName)) ? pProvider->pszName : ""), dwError); goto cleanup; } static DWORD LwpsBuiltInProviders( PLWPS_STACK* ppProviderStack ) { DWORD dwError = 0; PLWPS_STORAGE_PROVIDER pProvider = NULL; PLWPS_STACK pProviderStack = NULL; HANDLE hReg = NULL; DWORD dwStorageType = 0; DWORD dwProviderDefault = 0; PSTR pszStorageType = NULL; PSTR pszProviderPath = NULL; BOOLEAN bHasStorageType = FALSE; BOOLEAN bHasProviderPath = FALSE; BOOLEAN bHasProviderDefault = FALSE; dwError = LwpsAllocateMemory( sizeof(LWPS_STORAGE_PROVIDER), (PVOID*)&pProvider); BAIL_ON_LWPS_ERROR(dwError); dwError = LwpsStackPush( pProvider, &pProviderStack); BAIL_ON_LWPS_ERROR(dwError); #if defined(ENABLE_REGDB) dwError = RegOpenServer(&hReg); if (dwError == 0) { dwError = RegUtilIsValidKey( hReg, NULL, PSTOREDB_REGISTRY_DEFAULTS); } if (dwError == 0) { dwError = RegUtilGetValue( hReg, NULL, PSTOREDB_REGISTRY_DEFAULTS, NULL, LWPS_REG_STORAGE_TYPE, NULL, (PVOID) &dwStorageType, NULL); if (dwError == 0) { bHasStorageType = TRUE; pProvider->storeType = dwStorageType; } dwError = RegUtilGetValue( hReg, NULL, PSTOREDB_REGISTRY_DEFAULTS, NULL, LWPS_REG_PROVIDER_PATH, NULL, (PVOID) &pszProviderPath, NULL); if (dwError == 0) { bHasProviderPath = TRUE; pProvider->pszLibPath = pszProviderPath; } dwError = RegUtilGetValue( hReg, NULL, PSTOREDB_REGISTRY_DEFAULTS, NULL, LWPS_REG_PROVIDER_DEFAULT, NULL, (PVOID) &dwProviderDefault, NULL); if (dwError == 0) { bHasProviderDefault = TRUE; pProvider->bDefault = dwProviderDefault ? TRUE : FALSE; } } /* Set defaults when values are not found in registry */ if (!bHasProviderPath) { dwError = LwpsAllocateString( LIBDIR "/liblwps-regdb" MOD_EXT, &pProvider->pszLibPath); BAIL_ON_LWPS_ERROR(dwError); } if (!bHasStorageType) { pProvider->storeType = LWPS_PASSWORD_STORE_REGDB; } if (!bHasProviderDefault) { pProvider->bDefault = TRUE; } switch (pProvider->storeType) { case LWPS_PASSWORD_STORE_UNKNOWN: /* 0 */ pszStorageType = "unknown"; break; case LWPS_PASSWORD_STORE_DEFAULT: /* 1 */ pszStorageType = "unknown"; break; case LWPS_PASSWORD_STORE_SQLDB: /* 2 */ pszStorageType = "sqldb"; break; case LWPS_PASSWORD_STORE_TDB: /* 3 */ pszStorageType = "tdb"; break; case LWPS_PASSWORD_STORE_FILEDB: /* 4 */ pszStorageType = "filedb"; break; case LWPS_PASSWORD_STORE_REGDB: /* 5 */ default: pszStorageType = "regdb"; break; } dwError = LwpsAllocateString( pszStorageType, &pProvider->pszId); BAIL_ON_LWPS_ERROR(dwError); if (hReg) { RegCloseServer(hReg); } #elif defined(ENABLE_FILEDB) dwError = LwpsAllocateString( "filedb", &pProvider->pszId); BAIL_ON_LWPS_ERROR(dwError); dwError = LwpsAllocateString( "/opt/likewise/lib/liblwps-filedb.so", &pProvider->pszLibPath); BAIL_ON_LWPS_ERROR(dwError); pProvider->storeType = LWPS_PASSWORD_STORE_FILEDB; pProvider->bDefault = TRUE; #else dwError = LWPS_ERROR_NO_SUCH_PROVIDER; BAIL_ON_LWPS_ERROR(dwError); #endif *ppProviderStack = pProviderStack; cleanup: return dwError; error: *ppProviderStack = NULL; if (ppProviderStack) { LwpsStackForeach( pProviderStack, &LwpsConfigFreeProviderInStack, NULL); LwpsStackFree(pProviderStack); } goto cleanup; }