/* Editor Settings: expandtabs and use 4 spaces for indentation
 * ex: set softtabstop=4 tabstop=8 expandtab shiftwidth=4: *
 */

/*
 * Copyright Likewise Software
 * 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
 * <http://www.gnu.org/licenses/>.
 *
 * 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:
 *
 *        refresh.c
 *
 * Abstract:
 *
 *        Likewise Security and Authentication Subsystem (LSASS)
 *
 *        Configuration API (Server)
 *
 * Authors: Krishna Ganugapati (krishnag@likewisesoftware.com)
 *          Sriram Nambakam (snambakam@likewisesoftware.com)
 *          Rafal Szczesniak (rafal@likewise.com)
 */

#include "api.h"

typedef struct _LSA_REFRESH_CALLBACK {
    PFLSA_REFRESH_CALLBACK pfnRefreshCallback;
    PVOID pContext;
    LSA_LIST_LINKS Links;
} LSA_REFRESH_CALLBACK, *PLSA_REFRESH_CALLBACK;

static struct
{
    pthread_rwlock_t ListLock;
    BOOLEAN ListLockInitialized;
    LSA_LIST_LINKS Callbacks;
} gRefreshConfig;

DWORD
LsaSrvRefreshInitialize(
    VOID
    )
{
    DWORD dwError = 0;

    gRefreshConfig.ListLockInitialized = FALSE;

    LsaListInit(&gRefreshConfig.Callbacks);

    dwError = LwMapErrnoToLwError(pthread_rwlock_init(&gRefreshConfig.ListLock, NULL));
    BAIL_ON_LSA_ERROR(dwError);

    gRefreshConfig.ListLockInitialized = TRUE;

error:

    return dwError;
}

VOID
LsaSrvRefreshShutdown(
    VOID
    )
{
    if (gRefreshConfig.ListLockInitialized)
    {
        PTHREAD_CALL_MUST_SUCCEED(pthread_rwlock_destroy(&gRefreshConfig.ListLock));
    }
}

DWORD
LsaSrvRefreshRegisterCallback(
    IN PFLSA_REFRESH_CALLBACK pfnRefreshCallback,
    IN OPTIONAL PVOID pContext,
    OUT PLSA_REFRESH_CALLBACK_HANDLE pRefreshCallbackHandle
    )
{
    DWORD dwError = 0;
    BOOLEAN bUnlockConfigCallbackLock = FALSE;
    PLSA_REFRESH_CALLBACK pRefreshCallback = NULL;

    PTHREAD_CALL_MUST_SUCCEED(pthread_rwlock_wrlock(&gRefreshConfig.ListLock));
    bUnlockConfigCallbackLock = TRUE;

    dwError = LwAllocateMemory(sizeof(*pRefreshCallback), OUT_PPVOID(&pRefreshCallback));
    BAIL_ON_LSA_ERROR(dwError);

    pRefreshCallback->pfnRefreshCallback = pfnRefreshCallback;
    pRefreshCallback->pContext = pContext;

    LsaListInsertHead(&gRefreshConfig.Callbacks, &pRefreshCallback->Links);

error:

    if (dwError)
    {
        LW_SAFE_FREE_MEMORY(pRefreshCallback);
    }

    if (bUnlockConfigCallbackLock)
    {
        PTHREAD_CALL_MUST_SUCCEED(pthread_rwlock_unlock(&gRefreshConfig.ListLock));
    }

    *pRefreshCallbackHandle = pRefreshCallback;

    return dwError;
}

VOID
LsaSrvRefreshUnregisterCallback(
    IN LSA_REFRESH_CALLBACK_HANDLE RefreshCallbackHandle
    )
{
    if (RefreshCallbackHandle)
    {
        PTHREAD_CALL_MUST_SUCCEED(pthread_rwlock_wrlock(&gRefreshConfig.ListLock));
        LsaListRemove(&RefreshCallbackHandle->Links);
        PTHREAD_CALL_MUST_SUCCEED(pthread_rwlock_unlock(&gRefreshConfig.ListLock));

        LW_SAFE_FREE_MEMORY(RefreshCallbackHandle);
    }
}

DWORD
LsaSrvRefreshConfiguration(
    IN HANDLE hServer
    )
{
    DWORD dwError = 0;
    PLSA_SRV_API_STATE pServerState = (PLSA_SRV_API_STATE)hServer;
    BOOLEAN bUnlockConfigCallbackLock = FALSE;
    PLSA_LIST_LINKS pLinks = NULL;
    PLSA_LIST_LINKS pLinksNext = NULL;

    if (pServerState->peerUID)
    {
        dwError = LW_ERROR_ACCESS_DENIED;
        BAIL_ON_LSA_ERROR(dwError);
    }

    PTHREAD_CALL_MUST_SUCCEED(pthread_rwlock_rdlock(&gRefreshConfig.ListLock));
    bUnlockConfigCallbackLock = TRUE;

    for (pLinks = gRefreshConfig.Callbacks.Next;
         pLinks != &gRefreshConfig.Callbacks;
         pLinks = pLinksNext)
    {
        PLSA_REFRESH_CALLBACK pRefreshCallback = LW_STRUCT_FROM_FIELD(pLinks, LSA_REFRESH_CALLBACK, Links);
        pLinksNext = pLinks->Next;

        dwError = pRefreshCallback->pfnRefreshCallback(pRefreshCallback->pContext);
        BAIL_ON_LSA_ERROR(dwError);
    }

cleanup:

    if (bUnlockConfigCallbackLock)
    {
        PTHREAD_CALL_MUST_SUCCEED(pthread_rwlock_unlock(&gRefreshConfig.ListLock));
    }

    return dwError;

error:
    LSA_LOG_ERROR_API_FAILED(hServer, dwError, "refresh configuration");

    goto cleanup;

}

/*
local variables:
mode: c
c-basic-offset: 4
indent-tabs-mode: nil
tab-width: 4
end:
*/
