/* Editor Settings: expandtabs and use 4 spaces for indentation * ex: set softtabstop=4 tabstop=8 expandtab shiftwidth=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: * * credentials.c * * Abstract: * * Likewise Security and Authentication Subsystem (LSASS) * * * * Authors: */ #include "api.h" #include #define ENTER_CREDS_LIST(bInLock) \ do \ { \ if (!bInLock) \ { \ pthread_mutex_lock(&gLsaCredState.LsaCredsListLock); \ bInLock = TRUE; \ } \ } while (0) #define LEAVE_CREDS_LIST(bReleaseLock) \ do \ { \ if (bReleaseLock) \ { \ pthread_mutex_unlock(&gLsaCredState.LsaCredsListLock); \ bReleaseLock = FALSE; \ } \ } while (0) typedef struct _LSA_CREDENTIALS { PSTR pUserName; PSTR pPassword; uid_t UserId; LONG nRefCount; LSA_LIST_LINKS ListEntry; } LSA_CREDENTIALS, *PLSA_CREDENTIALS; typedef struct _LSA_CREDENTIALS_STATE { LSA_LIST_LINKS LsaCredsList; BOOLEAN bIsInitialized; pthread_mutex_t LsaCredsListLock; } LSA_CREDENTIALS_STATE, *PLSA_CREDENTIALS_STATE; static LSA_CREDENTIALS_STATE gLsaCredState = { .LsaCredsListLock = PTHREAD_MUTEX_INITIALIZER }; static PLSA_CREDENTIALS LsaFindCredByUidUnsafe( IN uid_t Uid ) { // Note that gLsaCredState.LsaCredsListLock must already be acquired. PLSA_CREDENTIALS pCredTrav = NULL; PLSA_LIST_LINKS pCredListEntry = NULL; PLSA_CREDENTIALS pCred = NULL; for (pCredListEntry = gLsaCredState.LsaCredsList.Next; pCredListEntry != &gLsaCredState.LsaCredsList; pCredListEntry = pCredListEntry->Next) { pCredTrav = LW_STRUCT_FROM_FIELD( pCredListEntry, LSA_CREDENTIALS, ListEntry); if (Uid == pCredTrav->UserId) { InterlockedIncrement(&pCredTrav->nRefCount); pCred = pCredTrav; break; } } return pCred; } static VOID LsaFreeCred( IN OUT PLSA_CREDENTIALS pCredential ) { if (pCredential) { LW_SAFE_FREE_MEMORY(pCredential->pUserName); LW_SAFE_FREE_MEMORY(pCredential->pPassword); LwFreeMemory(pCredential); } } static DWORD LsaAllocateCred( IN PCSTR pszUserName, IN PCSTR pszPassword, IN OPTIONAL const uid_t* pUid, OUT PLSA_CREDENTIALS* ppCredential ) { DWORD dwError = LW_ERROR_SUCCESS; PLSA_CREDENTIALS pCred = NULL; dwError = LwAllocateMemory(sizeof(*pCred), OUT_PPVOID(&pCred)); BAIL_ON_LSA_ERROR(dwError); dwError = LwAllocateString(pszUserName, &pCred->pUserName); BAIL_ON_LSA_ERROR(dwError); dwError = LwAllocateString(pszPassword, &pCred->pPassword); BAIL_ON_LSA_ERROR(dwError); pCred->nRefCount = 1; if (pUid) { pCred->UserId = *pUid; } cleanup: *ppCredential = pCred; return dwError; error: LsaFreeCred(pCred); pCred = NULL; goto cleanup; } static BOOLEAN LsaCredContains( IN PLSA_CREDENTIALS pCred, IN PCSTR pszUserName, IN PCSTR pszPassword ) { BOOLEAN bMatches = TRUE; if (strcasecmp(pszUserName, pCred->pUserName)) { bMatches = FALSE; } if (strcmp(pszPassword, pCred->pPassword)) { bMatches = FALSE; } return bMatches; } static VOID LsaInitializeCredentialsDatabase( VOID ) { BOOLEAN bInLock = FALSE; if (!gLsaCredState.bIsInitialized) { ENTER_CREDS_LIST(bInLock); if (!gLsaCredState.bIsInitialized) { LsaListInit(&gLsaCredState.LsaCredsList); gLsaCredState.bIsInitialized = TRUE; } LEAVE_CREDS_LIST(bInLock); } } DWORD LsaAddCredential( IN PCSTR pszUserName, IN PCSTR pszPassword, IN OPTIONAL const uid_t* pUid, OUT PLSA_CRED_HANDLE phCredential ) { DWORD dwError = LW_ERROR_SUCCESS; BOOLEAN bInLock = FALSE; PLSA_CREDENTIALS pCredOld = NULL; PLSA_CREDENTIALS pCredNew = NULL; LSA_CRED_HANDLE CredHandle = NULL; LsaInitializeCredentialsDatabase(); if (!pszUserName || !pszPassword || !*pszUserName || !*pszPassword || (pUid && !*pUid)) { dwError = LW_ERROR_INVALID_PARAMETER; BAIL_ON_LSA_ERROR(dwError); } ENTER_CREDS_LIST(bInLock); if (pUid) { pCredOld = LsaFindCredByUidUnsafe(*pUid); } if (!pCredOld || !LsaCredContains(pCredOld, pszUserName, pszPassword)) { dwError = LsaAllocateCred(pszUserName, pszPassword, pUid, &pCredNew); BAIL_ON_LSA_ERROR(dwError); LsaListInsertHead(&gLsaCredState.LsaCredsList, &pCredNew->ListEntry); if (pCredOld) { LsaListRemove(&pCredOld->ListEntry); // This release is NOT intended to destroy the credential (some one // may still be using it). It's intended to remove the reference // added by the LsaFindCredByUid called above. } CredHandle = pCredNew; pCredNew = NULL; } else { CredHandle = pCredOld; pCredOld = NULL; } cleanup: if (bInLock) { LEAVE_CREDS_LIST(bInLock); } if (dwError) { LsaReleaseCredential(&CredHandle); } LsaReleaseCredential(&pCredOld); LsaReleaseCredential(&pCredNew); *phCredential = CredHandle; return dwError; error: goto cleanup; } VOID LsaReferenceCredential( IN LSA_CRED_HANDLE hCredential ) { InterlockedIncrement(&hCredential->nRefCount); } VOID LsaReleaseCredential( IN PLSA_CRED_HANDLE phCredential ) { BOOLEAN bInLock = FALSE; if (*phCredential) { PLSA_CREDENTIALS pCred = *phCredential; LONG count = 0; ENTER_CREDS_LIST(bInLock); count = InterlockedDecrement(&pCred->nRefCount); LW_ASSERT(count >= 0); if (0 == count) { LsaListRemove(&pCred->ListEntry); } LEAVE_CREDS_LIST(bInLock); if (0 == count) { LsaFreeCred(pCred); } *phCredential = NULL; } } LSA_CRED_HANDLE LsaGetCredential( IN uid_t Uid ) { BOOLEAN bInLock = FALSE; PLSA_CREDENTIALS pCred = NULL; LsaInitializeCredentialsDatabase(); ENTER_CREDS_LIST(bInLock); pCred = LsaFindCredByUidUnsafe(Uid); LEAVE_CREDS_LIST(bInLock); return pCred; } VOID LsaGetCredentialInfo( IN LSA_CRED_HANDLE CredHandle, OUT OPTIONAL PCSTR* pszUserName, OUT OPTIONAL PCSTR* pszPassword, OUT OPTIONAL uid_t* pUid ) { if (pszUserName) { *pszUserName = CredHandle->pUserName; } if (pszPassword) { *pszPassword = CredHandle->pPassword; } if (pUid) { *pUid = CredHandle->UserId; } }