/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*-
 * ex: set softtabstop=4 tabstop=8 expandtab shiftwidth=4: *
 * Editor Settings: expandtabs and use 4 spaces for indentation */

/*
 * 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
 * <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:
 *
 *        regshare.c
 *
 * Abstract:
 *
 *        Likewise Server Message Block (LSMB)
 *
 *        Server sub-system
 *
 *        Server share registry interface
 *
 * Authors: Sriram Nambakam (snambakam@likewisesoftware.com)
 *          Wei Fu (wfu@likewise.com)
 *
 */
#include "includes.h"


struct SRV_SHARE_REPOSITORY_HANDLE_DATA
{
    HANDLE hRegConnection;
    SRV_SHARE_REPOSITORY_RELOAD_CALLBACK pfnReloadCallback;
    PVOID pReloadCallbackContext;
};


static
NTSTATUS
SrvShareRegWriteToShareInfo(
    IN REG_DATA_TYPE RegDataType,
    IN PWSTR pwszShareName,
    IN PBYTE pData,
    IN ULONG DataLen,
    IN REG_DATA_TYPE RegSecDataType,
    IN PBYTE pSecData,
    IN ULONG SecDataLen,
    OUT PSRV_SHARE_REPOSITORY_SHARE* ppShare
    );

static
VOID
SrvShareFreeStringArray(
    PWSTR* ppwszValues,
    ULONG  ulNumValues
    );

static
VOID
SrvShareRepositoryFreeShare(
    IN OUT PSRV_SHARE_REPOSITORY_SHARE* ppShare
    );

static
NTSTATUS
SrvShareRepositoryShareToByteArrayW(
    IN PSRV_SHARE_REPOSITORY_SHARE pShare,
    OUT PBYTE* ppBuf,
    OUT PULONG pBufLength
    );


NTSTATUS
SrvShareRepositoryInitialize(
    OUT PSRV_SHARE_REPOSITORY_HANDLE pHandle,
    IN SRV_SHARE_REPOSITORY_RELOAD_CALLBACK ReloadCallback,
    IN PVOID pReloadCallbackContext
    )
{
    NTSTATUS ntStatus = STATUS_SUCCESS;
    SRV_SHARE_REPOSITORY_HANDLE hRegHandle = NULL;

    ntStatus = SrvAllocateMemory(sizeof(*hRegHandle), OUT_PPVOID(&hRegHandle));
    BAIL_ON_NT_STATUS(ntStatus);

    ntStatus = NtRegOpenServer(&hRegHandle->hRegConnection);
    BAIL_ON_NT_STATUS(ntStatus);

    hRegHandle->pfnReloadCallback = ReloadCallback;
    hRegHandle->pReloadCallbackContext = pReloadCallbackContext;

cleanup:

    *pHandle = hRegHandle;

    return ntStatus;

error:

    SrvShareRepositoryCleanup(hRegHandle);
    hRegHandle = NULL;

    goto cleanup;
}

VOID
SrvShareRepositoryCleanup(
    IN SRV_SHARE_REPOSITORY_HANDLE Handle
    )
{
    if (!Handle)
    {
        goto cleanup;
    }

    if (Handle->hRegConnection)
    {
        NtRegCloseServer(Handle->hRegConnection);
    }

    SrvFreeMemory(Handle);

cleanup:

    return;
}

NTSTATUS
SrvShareRepositoryAddShare(
    IN SRV_SHARE_REPOSITORY_HANDLE Handle,
    IN PSRV_SHARE_REPOSITORY_SHARE pShare
    )
{
    NTSTATUS ntStatus = 0;
    HKEY hRootKey = NULL;
    HKEY hKey = NULL;
    HKEY hSecKey = NULL;
    PBYTE pOutData = NULL;
    ULONG outDataLength = 0;
    wchar16_t wszHKTM[] = HKEY_THIS_MACHINE_W;
    wchar16_t wszSharesKey[] = REG_KEY_PATH_SRV_SHARES_W;
    wchar16_t wszShareSecKey[] = REG_KEY_PATH_SRV_SHARES_SECURITY_W;

    if (IsNullOrEmptyString(pShare->pwszShareName))
    {
        ntStatus = STATUS_INVALID_PARAMETER_2;
        BAIL_ON_NT_STATUS(ntStatus);
    }
    if (IsNullOrEmptyString(pShare->pwszPath))
    {
        ntStatus = STATUS_INVALID_PARAMETER_3;
        BAIL_ON_NT_STATUS(ntStatus);
    }

    ntStatus = NtRegOpenKeyExW(
                    Handle->hRegConnection,
                    NULL,
                    &wszHKTM[0],
                    0,
                    KEY_ALL_ACCESS,
                    &hRootKey);
    BAIL_ON_NT_STATUS(ntStatus);

    ntStatus = NtRegOpenKeyExW(
                    Handle->hRegConnection,
                    hRootKey,
                    &wszSharesKey[0],
                    0,
                    KEY_ALL_ACCESS,
                    &hKey);
    BAIL_ON_NT_STATUS(ntStatus);

    ntStatus = SrvShareRepositoryShareToByteArrayW(
                    pShare,
                    &pOutData,
                    &outDataLength);
    BAIL_ON_NT_STATUS(ntStatus);

    ntStatus = NtRegSetValueExW(
                    Handle->hRegConnection,
                    hKey,
                    pShare->pwszShareName,
                    0,
                    REG_MULTI_SZ,
                    pOutData,
                    outDataLength);
    BAIL_ON_NT_STATUS(ntStatus);

    if ((pShare->pSecurityDescriptor && !pShare->SecurityDescriptorLength) ||
        (!pShare->pSecurityDescriptor && pShare->SecurityDescriptorLength))
    {
        ntStatus = STATUS_INVALID_PARAMETER_5;
        BAIL_ON_NT_STATUS(ntStatus);
    }

    ntStatus = NtRegOpenKeyExW(
                    Handle->hRegConnection,
                    hRootKey,
                    &wszShareSecKey[0],
                    0,
                    KEY_ALL_ACCESS,
                    &hSecKey);
    BAIL_ON_NT_STATUS(ntStatus);

    ntStatus = NtRegSetValueExW(
                    Handle->hRegConnection,
                    hSecKey,
                    pShare->pwszShareName,
                    0,
                    REG_BINARY,
                    (PBYTE)pShare->pSecurityDescriptor,
                    pShare->SecurityDescriptorLength);
    BAIL_ON_NT_STATUS(ntStatus);

cleanup:

    if (hRootKey)
    {
	NtRegCloseKey(Handle->hRegConnection, hRootKey);
    }
    if (hKey)
    {
	NtRegCloseKey(Handle->hRegConnection, hKey);
    }
    if (hSecKey)
    {
	NtRegCloseKey(Handle->hRegConnection, hSecKey);
    }
    if (pOutData)
    {
        RegFreeMemory(pOutData);
    }

    return ntStatus;

error:

    goto cleanup;
}

NTSTATUS
SrvShareRepositoryUpdateShare(
    IN SRV_SHARE_REPOSITORY_HANDLE Handle,
    IN PSRV_SHARE_REPOSITORY_SHARE pShare
    )
{
    NTSTATUS ntStatus = STATUS_SUCCESS;
    wchar16_t wszHKTM[] = HKEY_THIS_MACHINE_W;
    wchar16_t wszSharesKey[] = REG_KEY_PATH_SRV_SHARES_W;
    wchar16_t wszShareSecKey[] = REG_KEY_PATH_SRV_SHARES_SECURITY_W;
    HKEY hRootKey = NULL;
    HKEY hKey = NULL;
    HKEY hSecKey = NULL;
    ULONG valueLen = MAX_VALUE_LENGTH;
    ULONG secValueLen = MAX_VALUE_LENGTH;
    BYTE pRepositoryData[MAX_VALUE_LENGTH] = { 0 };
    BYTE pRepositorySecData[MAX_VALUE_LENGTH] = { 0 };
    PSRV_SHARE_REPOSITORY_SHARE pRepositoryShare = NULL;
    PBYTE pData = NULL;
    ULONG dataLength = 0;

    ntStatus = NtRegOpenKeyExW(
                    Handle->hRegConnection,
                    NULL,
                    &wszHKTM[0],
                    0,
                    KEY_READ,
                    &hRootKey);
    BAIL_ON_NT_STATUS(ntStatus);

    ntStatus = NtRegOpenKeyExW(
                    Handle->hRegConnection,
                    hRootKey,
                    &wszSharesKey[0],
                    0,
                    KEY_READ | KEY_WRITE,
                    &hKey);
    BAIL_ON_NT_STATUS(ntStatus);

    ntStatus = NtRegOpenKeyExW(
                    Handle->hRegConnection,
                    hRootKey,
                    &wszShareSecKey[0],
                    0,
                    KEY_READ | KEY_WRITE,
                    &hSecKey);
    BAIL_ON_NT_STATUS(ntStatus);

    ntStatus = NtRegGetValueW(
                    Handle->hRegConnection,
                    hKey,
                    NULL,
                    pShare->pwszShareName,
                    RRF_RT_REG_MULTI_SZ,
                    NULL,
                    pRepositoryData,
                    &valueLen);
    BAIL_ON_NT_STATUS(ntStatus);

    ntStatus = NtRegGetValueW(
                    Handle->hRegConnection,
                    hSecKey,
                    NULL,
                    pShare->pwszShareName,
                    RRF_RT_REG_BINARY,
                    NULL,
                    pRepositorySecData,
                    &secValueLen);
    BAIL_ON_NT_STATUS(ntStatus);

    ntStatus = SrvShareRegWriteToShareInfo(
                    REG_MULTI_SZ,
                    pShare->pwszShareName,
                    pRepositoryData,
                    valueLen,
                    REG_BINARY,
                    pRepositorySecData,
                    secValueLen,
                    &pRepositoryShare);
    BAIL_ON_NT_STATUS(ntStatus);

    if (!LwRtlWC16StringIsEqual(pShare->pwszPath, pRepositoryShare->pwszPath,
                                FALSE) ||
        pShare->Service != pRepositoryShare->Service)
    {
        ntStatus = STATUS_INVALID_PARAMETER;
        BAIL_ON_NT_STATUS(ntStatus);
    }

    ntStatus = SrvShareRepositoryShareToByteArrayW(
                    pShare,
                    &pData,
                    &dataLength);
    BAIL_ON_NT_STATUS(ntStatus);

    ntStatus = NtRegSetValueExW(
                    Handle->hRegConnection,
                    hKey,
                    pShare->pwszShareName,
                    0,
                    REG_MULTI_SZ,
                    pData,
                    dataLength);
    BAIL_ON_NT_STATUS(ntStatus);

    ntStatus = NtRegSetValueExW(
                    Handle->hRegConnection,
                    hSecKey,
                    pShare->pwszShareName,
                    0,
                    REG_BINARY,
                    (PBYTE)pShare->pSecurityDescriptor,
                    pShare->SecurityDescriptorLength);
    BAIL_ON_NT_STATUS(ntStatus);

cleanup:

    if (hRootKey)
    {
	NtRegCloseKey(Handle->hRegConnection, hRootKey);
    }
    if (hKey)
    {
	NtRegCloseKey(Handle->hRegConnection, hKey);
    }
    if (hSecKey)
    {
	NtRegCloseKey(Handle->hRegConnection, hSecKey);
    }

    SrvShareRepositoryFreeShare(&pRepositoryShare);

    if (pData)
    {
        RegFreeMemory(pData);
    }
    pData = NULL;
    dataLength = 0;

    return ntStatus;

error:

    goto cleanup;
}

NTSTATUS
SrvShareRepositoryGetShareList(
    IN SRV_SHARE_REPOSITORY_HANDLE Handle,
    OUT PSRV_SHARE_REPOSITORY_SHARE** pppRepositoryShareList,
    OUT PULONG pRepositoryShareListCount
    )
{
    NTSTATUS ntStatus          = 0;
    ULONG    ulIndex           = 0;
    HKEY     hRootKey          = NULL;
    HKEY     hKey              = NULL;
    HKEY     hSecKey           = NULL;
    PWSTR    pwszValueName     = NULL;
    PBYTE    pData             = NULL;
    REG_DATA_TYPE    dataType  = REG_NONE;
    wchar16_t wszHKTM[]        = HKEY_THIS_MACHINE_W;
    wchar16_t wszSharesKey[]   = REG_KEY_PATH_SRV_SHARES_W;
    wchar16_t wszShareSecKey[] = REG_KEY_PATH_SRV_SHARES_SECURITY_W;
    PSRV_SHARE_REPOSITORY_SHARE* ppRepositoryShareList  = NULL;
    REG_DATA_TYPE    dataSecType      = REG_NONE;
    ULONG repositoryShareListCount = 0;
    BYTE             pSecData[MAX_VALUE_LENGTH] = {0};
    ULONG regValuesAvailable = 0;
    ULONG regMaxValueNameLen = 0;
    ULONG regMaxValueLen = 0;

    ntStatus = NtRegOpenKeyExW(
                    Handle->hRegConnection,
                    NULL,
                    &wszHKTM[0],
                    0,
                    KEY_READ,
                    &hRootKey);
    BAIL_ON_NT_STATUS(ntStatus);

    ntStatus = NtRegOpenKeyExW(
                    Handle->hRegConnection,
                    hRootKey,
                    &wszSharesKey[0],
                    0,
                    KEY_READ,
                    &hKey);
    BAIL_ON_NT_STATUS(ntStatus);

    ntStatus = NtRegOpenKeyExW(
                    Handle->hRegConnection,
                    hRootKey,
                    &wszShareSecKey[0],
                    0,
                    KEY_READ,
                    &hSecKey);
    BAIL_ON_NT_STATUS(ntStatus);

    ntStatus = NtRegQueryInfoKeyW(
                    Handle->hRegConnection,
                    hKey,
                    NULL,
                    NULL,
                    NULL,
                    NULL,
                    NULL,
                    NULL,
                    &regValuesAvailable,
                    &regMaxValueNameLen,
                    &regMaxValueLen,
                    NULL,
                    NULL);
    BAIL_ON_NT_STATUS(ntStatus);

    if (!regValuesAvailable)
    {
        goto cleanup;
    }

    ntStatus = SrvAllocateMemory(
                    regValuesAvailable * sizeof(*ppRepositoryShareList),
                    OUT_PPVOID(&ppRepositoryShareList));
    BAIL_ON_NT_STATUS(ntStatus);

    for (ulIndex = 0; ulIndex < regValuesAvailable; ulIndex++)
    {
        ULONG maxValueLen = regMaxValueLen;
        ULONG maxValueNameLen = (regMaxValueNameLen + 1) *
                                sizeof(*pwszValueName);
        ULONG maxSecValueLen = MAX_VALUE_LENGTH;

        if (maxValueNameLen)
        {
            SRV_SAFE_FREE_MEMORY_AND_RESET(pwszValueName);

            ntStatus = SrvAllocateMemory(
                            maxValueNameLen,
                            OUT_PPVOID(&pwszValueName));
            BAIL_ON_NT_STATUS(ntStatus);
        }

        if (maxValueLen)
        {
            SRV_SAFE_FREE_MEMORY_AND_RESET(pData);

            ntStatus = SrvAllocateMemory(maxValueLen, OUT_PPVOID(&pData));
            BAIL_ON_NT_STATUS(ntStatus);
        }

        ntStatus = NtRegEnumValueW(
                      Handle->hRegConnection,
                      hKey,
                      ulIndex,
                      pwszValueName,
                      &maxValueNameLen,
                      NULL,
                      &dataType,
                      pData,
                      &maxValueLen);
        if (ntStatus == STATUS_NO_MORE_ENTRIES)
        {
            ntStatus = STATUS_SUCCESS;
            break;
        }
        BAIL_ON_NT_STATUS(ntStatus);

        if (REG_MULTI_SZ != dataType)
        {
            continue;
        }

        ntStatus = NtRegGetValueW(
                        Handle->hRegConnection,
                        hSecKey,
                        NULL,
                        pwszValueName,
                        RRF_RT_REG_BINARY,
                        &dataSecType,
                        pSecData,
                        &maxSecValueLen);
        if (STATUS_OBJECT_NAME_NOT_FOUND == ntStatus)
        {
            ntStatus = 0;
            maxSecValueLen = 0;
        }
        BAIL_ON_NT_STATUS(ntStatus);

        ntStatus = SrvShareRegWriteToShareInfo(
                      dataType,
                      pwszValueName,
                      pData,
                      maxValueLen,
                      dataSecType,
                      pSecData,
                      maxSecValueLen,
                      &ppRepositoryShareList[repositoryShareListCount]);
        BAIL_ON_NT_STATUS(ntStatus);

        ++repositoryShareListCount;
    }

    *pppRepositoryShareList = ppRepositoryShareList;
    *pRepositoryShareListCount = repositoryShareListCount;

cleanup:

    if (hRootKey)
    {
	NtRegCloseKey(Handle->hRegConnection, hRootKey);
    }
    if (hKey)
    {
	NtRegCloseKey(Handle->hRegConnection, hKey);
    }
    if (hSecKey)
    {
	NtRegCloseKey(Handle->hRegConnection, hSecKey);
    }

    SRV_SAFE_FREE_MEMORY(pwszValueName);
    SRV_SAFE_FREE_MEMORY(pData);

    return ntStatus;

error:

    *pppRepositoryShareList = NULL;
    *pRepositoryShareListCount = 0;

    if (ppRepositoryShareList)
    {
        SrvShareRepositoryFreeShareList(ppRepositoryShareList,
                                        repositoryShareListCount);
    }

    goto cleanup;
}

VOID
SrvShareRepositoryFreeShareList(
    IN PSRV_SHARE_REPOSITORY_SHARE* ppRepositoryShareList,
    IN ULONG RepositoryShareListCount
    )
{
    ULONG i = 0;

    if (ppRepositoryShareList)
    {
        for (i = 0; i < RepositoryShareListCount; ++i)
        {
            if (!ppRepositoryShareList[i])
            {
                break;
            }

            SrvShareRepositoryFreeShare(&ppRepositoryShareList[i]);
        }

        SrvFreeMemory(ppRepositoryShareList);
    }
}

NTSTATUS
SrvShareRepositoryDeleteShare(
    IN SRV_SHARE_REPOSITORY_HANDLE Handle,
    IN PWSTR pwszShareName
    )
{
    NTSTATUS  ntStatus = 0;
    HKEY      hRootKey = NULL;
    wchar16_t wszHKTM[]        = HKEY_THIS_MACHINE_W;
    wchar16_t wszSharesKey[]   = REG_KEY_PATH_SRV_SHARES_W;
    wchar16_t wszShareSecKey[] = REG_KEY_PATH_SRV_SHARES_SECURITY_W;

    ntStatus = NtRegOpenKeyExW(
                    Handle->hRegConnection,
                    NULL,
                    &wszHKTM[0],
                    0,
                    KEY_ALL_ACCESS,
                    &hRootKey);
    BAIL_ON_NT_STATUS(ntStatus);

    ntStatus = NtRegDeleteKeyValueW(
                    Handle->hRegConnection,
                    hRootKey,
                    &wszSharesKey[0],
                    pwszShareName);
    BAIL_ON_NT_STATUS(ntStatus);

    ntStatus = NtRegDeleteKeyValueW(
                    Handle->hRegConnection,
                    hRootKey,
                    &wszShareSecKey[0],
                    pwszShareName);
    if (STATUS_OBJECT_NAME_NOT_FOUND == ntStatus)
    {
        ntStatus = STATUS_SUCCESS;
    }
    BAIL_ON_NT_STATUS(ntStatus);

cleanup:

    if (hRootKey)
    {
	NtRegCloseKey(Handle->hRegConnection, hRootKey);
    }

    return ntStatus;

error:

    goto cleanup;
}

static
NTSTATUS
SrvShareRegWriteToShareInfo(
    IN REG_DATA_TYPE RegDataType,
    IN PWSTR pwszShareName,
    IN PBYTE pData,
    IN ULONG DataLen,
    IN REG_DATA_TYPE RegSecDataType,
    IN PBYTE pSecData,
    IN ULONG SecDataLen,
    OUT PSRV_SHARE_REPOSITORY_SHARE* ppShare
    )
{
    NTSTATUS        ntStatus     = STATUS_SUCCESS;
    PSRV_SHARE_REPOSITORY_SHARE pShare = NULL;
    PWSTR*          ppwszValues  = NULL;
    PSTR            pszFlags     = NULL;

    ntStatus = SrvAllocateMemory(sizeof(*pShare), (PVOID*)&pShare);
    BAIL_ON_NT_STATUS(ntStatus);

    ntStatus = SrvAllocateStringW(pwszShareName, &pShare->pwszShareName);
    BAIL_ON_NT_STATUS(ntStatus);

    if (pData)
    {
        ULONG iValue = 0;
        wchar16_t wszCommentPrefix[] = REG_KEY_COMMENT_PREFIX_W;
        ULONG     ulCommentPrefixLen =
                            (sizeof(wszCommentPrefix)/sizeof(wchar16_t)) - 1;
        wchar16_t wszPathPrefix[]    = REG_KEY_PATH_PREFIX_W;
        ULONG     ulPathPrefixLen =
                            (sizeof(wszPathPrefix)/sizeof(wchar16_t)) - 1;
        wchar16_t wszServicePrefix[] = REG_KEY_SERVICE_PREFIX_W;
        ULONG     ulServicePrefixLen =
                            (sizeof(wszServicePrefix)/sizeof(wchar16_t)) - 1;

        wchar16_t wszFlagsPrefix[]   = REG_KEY_FLAGS_PREFIX_W;
        ULONG     ulFlagsPrefixLen =
                            (sizeof(wszFlagsPrefix)/sizeof(wchar16_t)) - 1;

        ntStatus = NtRegByteArrayToMultiStrs(pData, DataLen, &ppwszValues);
        BAIL_ON_NT_STATUS(ntStatus);

        for (; ppwszValues[iValue]; iValue++)
        {
            PWSTR pwszValue = &ppwszValues[iValue][0];

            if (!wc16sncmp(&wszPathPrefix[0], pwszValue, ulPathPrefixLen))
            {
                SRV_SAFE_FREE_MEMORY(pShare->pwszPath);

                ntStatus = SrvAllocateStringW(
                                &pwszValue[ulPathPrefixLen],
                                &pShare->pwszPath);
                BAIL_ON_NT_STATUS(ntStatus);
            }
            else if (!wc16sncmp(&wszCommentPrefix[0], pwszValue, ulCommentPrefixLen))
            {
                SRV_SAFE_FREE_MEMORY(pShare->pwszComment);

                ntStatus = SrvAllocateStringW(
                                &pwszValue[ulCommentPrefixLen],
                                &pShare->pwszComment);
                BAIL_ON_NT_STATUS(ntStatus);
            }
            else if (!wc16sncmp(&wszServicePrefix[0], pwszValue, ulServicePrefixLen))
            {
                ntStatus = SrvShareMapServiceStringToIdW(
                                &pwszValue[ulServicePrefixLen],
                                &pShare->Service);
                BAIL_ON_NT_STATUS(ntStatus);
            }
            else if (!wc16sncmp(&wszFlagsPrefix[0], pwszValue, ulFlagsPrefixLen))
            {
                ntStatus = RtlCStringAllocateFromWC16String(
                                &pszFlags,
                                &pwszValue[ulFlagsPrefixLen]);
                BAIL_ON_NT_STATUS(ntStatus);

                pShare->Flags = strtoul(pszFlags, NULL, 16);
            }
            else
            {
                ntStatus = STATUS_INVALID_PARAMETER_3;
                BAIL_ON_NT_STATUS(ntStatus);
            }
        }
    }

    if (!pShare->pwszComment)
    {
        wchar16_t wszComment[] = {0};

        ntStatus = SrvAllocateStringW(
                        &wszComment[0],
                        &pShare->pwszComment);
        BAIL_ON_NT_STATUS(ntStatus);
    }

    if (SecDataLen)
    {
        ntStatus = SrvAllocateMemory(SecDataLen,
                                     OUT_PPVOID(&pShare->pSecurityDescriptor));
        BAIL_ON_NT_STATUS(ntStatus);

        memcpy(pShare->pSecurityDescriptor, pSecData, SecDataLen);
        pShare->SecurityDescriptorLength = SecDataLen;
    }

    pShare->MaxUses = SRV_SHARE_MAX_USES_UNLIMITED;


    *ppShare = pShare;

cleanup:

    if (ppwszValues)
    {
        RegFreeMultiStrsW(ppwszValues);
    }

    RTL_FREE(&pszFlags);

    return ntStatus;

error:

    SrvShareRepositoryFreeShare(&pShare);

    goto cleanup;
}

static
VOID
SrvShareFreeStringArray(
    PWSTR* ppwszValues,
    ULONG  ulNumValues
    )
{
    ULONG iValue = 0;

    for (; iValue < ulNumValues; iValue++)
    {
        if (ppwszValues[iValue])
        {
            SrvFreeMemory(ppwszValues[iValue]);
        }
    }

    SrvFreeMemory(ppwszValues);
}

static
VOID
SrvShareRepositoryFreeShare(
    IN OUT PSRV_SHARE_REPOSITORY_SHARE* ppShare
    )
{
    PSRV_SHARE_REPOSITORY_SHARE pShare = *ppShare;

    if (pShare)
    {
        SRV_SAFE_FREE_MEMORY(pShare->pwszShareName);
        SRV_SAFE_FREE_MEMORY(pShare->pwszPath);
        SRV_SAFE_FREE_MEMORY(pShare->pwszComment);
        SRV_SAFE_FREE_MEMORY(pShare->pSecurityDescriptor);

        SrvFreeMemory(pShare);
        pShare = NULL;
    }

    *ppShare = pShare;
}

static
NTSTATUS
SrvShareRepositoryShareToByteArrayW(
    IN PSRV_SHARE_REPOSITORY_SHARE pShare,
    OUT PBYTE* ppBuf,
    OUT PULONG pBufLength
    )
{
    NTSTATUS ntStatus = STATUS_SUCCESS;
    PWSTR* ppwszValues = NULL;
    PWSTR pwszFlags = NULL;
    PWSTR pwszService = NULL;
    ULONG count = 0;
    wchar16_t wszPathPrefix[] = REG_KEY_PATH_PREFIX_W;
    wchar16_t wszServicePrefix[] = REG_KEY_SERVICE_PREFIX_W;
    wchar16_t wszFlagsPrefix[] = REG_KEY_FLAGS_PREFIX_W;
    ULONG pathPrefixLen = (sizeof(wszPathPrefix)/sizeof(wchar16_t)) - 1;
    ULONG servicePrefixLen = (sizeof(wszServicePrefix)/sizeof(wchar16_t)) - 1;
    ULONG flagsPrefixLen = (sizeof(wszFlagsPrefix)/sizeof(wchar16_t)) - 1;
    PBYTE pBuf = NULL;
    SSIZE_T bufLength = 0;

    ntStatus = SrvAllocateMemory(sizeof(PWSTR) * 5, (PVOID*)&ppwszValues);
    BAIL_ON_NT_STATUS(ntStatus);

    // Path
    ntStatus = SrvAllocateMemory(
                    sizeof(wszPathPrefix) +
                      wc16slen(pShare->pwszPath) * sizeof(wchar16_t),
                    (PVOID*)&ppwszValues[count]);
    BAIL_ON_NT_STATUS(ntStatus);

    memcpy( (PBYTE)&ppwszValues[count][0],
            (PBYTE)&wszPathPrefix[0],
            sizeof(wszPathPrefix) - sizeof(wchar16_t));
    memcpy( (PBYTE)&ppwszValues[count][pathPrefixLen],
            (PBYTE)pShare->pwszPath,
            wc16slen(pShare->pwszPath) * sizeof(wchar16_t));

    if (!IsNullOrEmptyString(pShare->pwszComment))
    {
        wchar16_t wszCommentPrefix[] = REG_KEY_COMMENT_PREFIX_W;
        ULONG     ulCommentPrefixLen =
                            (sizeof(wszCommentPrefix)/sizeof(wchar16_t)) - 1;

        ntStatus = SrvAllocateMemory(
                    sizeof(wszCommentPrefix) +
                    wc16slen(pShare->pwszComment) * sizeof(wchar16_t),
                    (PVOID*)&ppwszValues[++count]);
        BAIL_ON_NT_STATUS(ntStatus);

        memcpy( (PBYTE)&ppwszValues[count][0],
                (PBYTE)&wszCommentPrefix[0],
                sizeof(wszCommentPrefix) - sizeof(wchar16_t));
        memcpy( (PBYTE)&ppwszValues[count][ulCommentPrefixLen],
                (PBYTE)pShare->pwszComment,
                wc16slen(pShare->pwszComment) * sizeof(wchar16_t));
    }

    // Service type
    ntStatus = SrvShareMapIdToServiceStringW(pShare->Service, &pwszService);
    BAIL_ON_NT_STATUS(ntStatus);

    ntStatus = SrvAllocateMemory(
                        sizeof(wszServicePrefix) + wc16slen(pwszService) * sizeof(wchar16_t),
                        OUT_PPVOID(&ppwszValues[++count]));
    BAIL_ON_NT_STATUS(ntStatus);

    memcpy( (PBYTE)&ppwszValues[count][0],
            (PBYTE)&wszServicePrefix[0],
            sizeof(wszServicePrefix) - sizeof(wchar16_t));
    memcpy( (PBYTE)&ppwszValues[count][servicePrefixLen],
            (PBYTE)pwszService,
            wc16slen(pwszService) * sizeof(wchar16_t));

    // Flags
    ntStatus = LwRtlWC16StringAllocatePrintfW(&pwszFlags, L"0x%08x",
                                              pShare->Flags);
    BAIL_ON_NT_STATUS(ntStatus);

    ntStatus = SrvAllocateMemory(
                            sizeof(wszFlagsPrefix) + wc16slen(pwszFlags) * sizeof(wchar16_t),
                            OUT_PPVOID(&ppwszValues[++count]));
    BAIL_ON_NT_STATUS(ntStatus);

    memcpy((PBYTE)&ppwszValues[count][0],
           (PBYTE)&wszFlagsPrefix[0],
           sizeof(wszFlagsPrefix) - sizeof(wchar16_t));
    memcpy((PBYTE)&ppwszValues[count][flagsPrefixLen],
           (PBYTE)pwszFlags,
           wc16slen(pwszFlags) * sizeof(wchar16_t));

    ntStatus = NtRegMultiStrsToByteArrayW(ppwszValues, &pBuf, &bufLength);
    BAIL_ON_NT_STATUS(ntStatus);

cleanup:

    if (ppwszValues)
    {
        SrvShareFreeStringArray(ppwszValues, 4);
    }

    RTL_FREE(&pwszFlags);
    RTL_FREE(&pwszService);

    *ppBuf = pBuf;
    *pBufLength = bufLength;

    return ntStatus;

error:

    if (pBuf)
    {
        RegFreeMemory(pBuf);
    }
    pBuf = NULL;
    bufLength = 0;

    goto cleanup;
}
