/* 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 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: * * 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" static NTSTATUS SrvShareRegWriteToShareInfo( IN REG_DATA_TYPE regDataType, IN PWSTR pwszShareName, IN PBYTE pData, IN ULONG ulDataLen, IN REG_DATA_TYPE regSecDataType, IN PBYTE pSecData, IN ULONG ulSecDataLen, OUT PSRV_SHARE_INFO* ppShareInfo ); static VOID SrvShareFreeStringArray( PWSTR* ppwszValues, ULONG ulNumValues ); NTSTATUS SrvShareRegInit( VOID ) { return 0; } NTSTATUS SrvShareRegOpen( OUT PHANDLE phRepository ) { return NtRegOpenServer(phRepository); } NTSTATUS SrvShareRegFindByName( HANDLE hRepository, PWSTR pwszShareName, PSRV_SHARE_INFO* ppShareInfo ) { NTSTATUS ntStatus = STATUS_SUCCESS; HKEY hRootKey = NULL; HKEY hKey = NULL; HKEY hSecKey = NULL; REG_DATA_TYPE dataType = REG_UNKNOWN; ULONG ulValueLen = MAX_VALUE_LENGTH; REG_DATA_TYPE dataSecType = REG_UNKNOWN; ULONG ulSecValueLen = MAX_VALUE_LENGTH; PSRV_SHARE_INFO pShareInfo = NULL; BYTE pData[MAX_VALUE_LENGTH] = {0}; BYTE pSecData[MAX_VALUE_LENGTH] = {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; ntStatus = NtRegOpenKeyExW( hRepository, NULL, &wszHKTM[0], 0, KEY_READ, &hRootKey); BAIL_ON_NT_STATUS(ntStatus); ntStatus = NtRegOpenKeyExW( hRepository, hRootKey, &wszSharesKey[0], 0, KEY_READ, &hKey); BAIL_ON_NT_STATUS(ntStatus); ntStatus = NtRegOpenKeyExW( hRepository, hRootKey, &wszShareSecKey[0], 0, KEY_READ, &hSecKey); BAIL_ON_NT_STATUS(ntStatus); ntStatus = NtRegGetValueW( hRepository, hKey, NULL, pwszShareName, RRF_RT_REG_MULTI_SZ, &dataType, pData, &ulValueLen); BAIL_ON_NT_STATUS(ntStatus); ntStatus = NtRegGetValueW( hRepository, hSecKey, NULL, pwszShareName, RRF_RT_REG_BINARY, &dataSecType, pSecData, &ulSecValueLen); BAIL_ON_NT_STATUS(ntStatus); ntStatus = SrvShareRegWriteToShareInfo( dataType, pwszShareName, pData, ulValueLen, dataSecType, pSecData, ulSecValueLen, &pShareInfo); BAIL_ON_NT_STATUS(ntStatus); *ppShareInfo = pShareInfo; cleanup: if (hRootKey) { NtRegCloseKey(hRepository, hRootKey); } if (hKey) { NtRegCloseKey(hRepository, hKey); } if (hSecKey) { NtRegCloseKey(hRepository, hSecKey); } return ntStatus; error: if (pShareInfo) { SrvShareReleaseInfo(pShareInfo); } goto cleanup; } NTSTATUS SrvShareRegAdd( IN HANDLE hRepository, IN PWSTR pwszShareName, IN PWSTR pwszPath, IN PWSTR pwszComment, IN PBYTE pSecDesc, IN ULONG ulSecDescLen, IN PWSTR pwszService ) { NTSTATUS ntStatus = 0; HKEY hRootKey = NULL; HKEY hKey = NULL; HKEY hSecKey = NULL; PWSTR* ppwszValues = NULL; PBYTE pOutData = NULL; SSIZE_T cOutDataLen = 0; ULONG ulCount = 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; wchar16_t wszPathPrefix[] = REG_KEY_PATH_PREFIX_W; ULONG ulPathPrefixLen = (sizeof(wszPathPrefix)/sizeof(wchar16_t)) - 1; if (IsNullOrEmptyString(pwszShareName)) { ntStatus = STATUS_INVALID_PARAMETER_2; BAIL_ON_NT_STATUS(ntStatus); } if (IsNullOrEmptyString(pwszPath)) { ntStatus = STATUS_INVALID_PARAMETER_3; BAIL_ON_NT_STATUS(ntStatus); } ntStatus = NtRegOpenKeyExW( hRepository, NULL, &wszHKTM[0], 0, KEY_ALL_ACCESS, &hRootKey); BAIL_ON_NT_STATUS(ntStatus); ntStatus = NtRegOpenKeyExW( hRepository, hRootKey, &wszSharesKey[0], 0, KEY_ALL_ACCESS, &hKey); BAIL_ON_NT_STATUS(ntStatus); ntStatus = SrvAllocateMemory(sizeof(PWSTR) * 4, (PVOID*)&ppwszValues); BAIL_ON_NT_STATUS(ntStatus); // Path ntStatus = SrvAllocateMemory( sizeof(wszPathPrefix) + wc16slen(pwszPath) * sizeof(wchar16_t), (PVOID*)&ppwszValues[ulCount]); BAIL_ON_NT_STATUS(ntStatus); memcpy( (PBYTE)&ppwszValues[ulCount][0], (PBYTE)&wszPathPrefix[0], sizeof(wszPathPrefix) - sizeof(wchar16_t)); memcpy( (PBYTE)&ppwszValues[ulCount][ulPathPrefixLen], (PBYTE)pwszPath, wc16slen(pwszPath) * sizeof(wchar16_t)); if (!IsNullOrEmptyString(pwszComment)) { wchar16_t wszCommentPrefix[] = REG_KEY_COMMENT_PREFIX_W; ULONG ulCommentPrefixLen = (sizeof(wszCommentPrefix)/sizeof(wchar16_t)) - 1; ntStatus = SrvAllocateMemory( sizeof(wszCommentPrefix) + wc16slen(pwszComment) * sizeof(wchar16_t), (PVOID*)&ppwszValues[++ulCount]); BAIL_ON_NT_STATUS(ntStatus); memcpy( (PBYTE)&ppwszValues[ulCount][0], (PBYTE)&wszCommentPrefix[0], sizeof(wszCommentPrefix) - sizeof(wchar16_t)); memcpy( (PBYTE)&ppwszValues[ulCount][ulCommentPrefixLen], (PBYTE)pwszComment, wc16slen(pwszComment) * sizeof(wchar16_t)); } if (!IsNullOrEmptyString(pwszService)) { wchar16_t wszServicePrefix[] = REG_KEY_SERVICE_PREFIX_W; ULONG ulServicePrefixLen = (sizeof(wszServicePrefix)/sizeof(wchar16_t)) - 1; ntStatus = SrvAllocateMemory( sizeof(wszServicePrefix) + wc16slen(pwszService) * sizeof(wchar16_t), (PVOID*)&ppwszValues[++ulCount]); BAIL_ON_NT_STATUS(ntStatus); memcpy( (PBYTE)&ppwszValues[ulCount][0], (PBYTE)&wszServicePrefix[0], sizeof(wszServicePrefix) - sizeof(wchar16_t)); memcpy( (PBYTE)&ppwszValues[ulCount][ulServicePrefixLen], (PBYTE)pwszService, wc16slen(pwszService) * sizeof(wchar16_t)); } ntStatus = NtRegMultiStrsToByteArrayW(ppwszValues, &pOutData, &cOutDataLen); BAIL_ON_NT_STATUS(ntStatus); ntStatus = NtRegSetValueExW( hRepository, hKey, pwszShareName, 0, REG_MULTI_SZ, pOutData, cOutDataLen); BAIL_ON_NT_STATUS(ntStatus); if ((pSecDesc && !ulSecDescLen) || (!pSecDesc && ulSecDescLen)) { ntStatus = STATUS_INVALID_PARAMETER_5; BAIL_ON_NT_STATUS(ntStatus); } ntStatus = NtRegOpenKeyExW( hRepository, hRootKey, &wszShareSecKey[0], 0, KEY_ALL_ACCESS, &hSecKey); BAIL_ON_NT_STATUS(ntStatus); ntStatus = NtRegSetValueExW( hRepository, hSecKey, pwszShareName, 0, REG_BINARY, pSecDesc, ulSecDescLen); BAIL_ON_NT_STATUS(ntStatus); cleanup: if (hRootKey) { NtRegCloseKey(hRepository, hRootKey); } if (hKey) { NtRegCloseKey(hRepository, hKey); } if (hSecKey) { NtRegCloseKey(hRepository, hSecKey); } if (ppwszValues) { SrvShareFreeStringArray(ppwszValues, 4); } if (pOutData) { RegFreeMemory(pOutData); } return ntStatus; error: goto cleanup; } NTSTATUS SrvShareRegBeginEnum( HANDLE hRepository, ULONG ulLimit, PHANDLE phResume ) { NTSTATUS ntStatus = 0; ULONG ulValueCount = 0; HKEY hRootKey = NULL; HKEY hKey = NULL; wchar16_t wszHKTM[] = HKEY_THIS_MACHINE_W; wchar16_t wszSharesKey[] = REG_KEY_PATH_SRV_SHARES_W; PSRV_SHARE_REG_ENUM_CONTEXT pEnumContext = NULL; ntStatus = SrvAllocateMemory( sizeof(SRV_SHARE_REG_ENUM_CONTEXT), (PVOID*)&pEnumContext); BAIL_ON_NT_STATUS(ntStatus); ntStatus = NtRegOpenKeyExW( hRepository, NULL, &wszHKTM[0], 0, KEY_READ, &hRootKey); BAIL_ON_NT_STATUS(ntStatus); ntStatus = NtRegOpenKeyExW( hRepository, hRootKey, &wszSharesKey[0], 0, KEY_READ, &hKey); BAIL_ON_NT_STATUS(ntStatus); ntStatus = NtRegQueryInfoKeyW( hRepository, hKey, NULL, NULL, NULL, NULL, NULL, NULL, &ulValueCount, &pEnumContext->ulMaxValueNameLen, &pEnumContext->ulMaxValueLen, NULL, NULL); BAIL_ON_NT_STATUS(ntStatus); if (ulLimit > ulValueCount) { pEnumContext->ulMaxIndex = ulValueCount; } else { pEnumContext->ulMaxIndex = ulLimit; } *phResume = (HANDLE)pEnumContext; cleanup: if (hRootKey) { NtRegCloseKey(hRepository, hRootKey); } if (hKey) { NtRegCloseKey(hRepository, hKey); } return ntStatus; error: *phResume = NULL; SRV_SAFE_FREE_MEMORY(pEnumContext); goto cleanup; } NTSTATUS SrvShareRegEnum( HANDLE hRepository, HANDLE hResume, PSRV_SHARE_INFO** pppShareInfoList, PULONG pulNumSharesFound ) { 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_UNKNOWN; 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_INFO* ppShareInfoList = NULL; REG_DATA_TYPE dataSecType = REG_UNKNOWN; ULONG ulNumSharesFound = 0; BYTE pSecData[MAX_VALUE_LENGTH] = {0}; PSRV_SHARE_REG_ENUM_CONTEXT pResume = (PSRV_SHARE_REG_ENUM_CONTEXT)hResume; if (!pResume->ulMaxIndex) { *pppShareInfoList = NULL; *pulNumSharesFound = 0; goto cleanup; } ntStatus = NtRegOpenKeyExW( hRepository, NULL, &wszHKTM[0], 0, KEY_READ, &hRootKey); BAIL_ON_NT_STATUS(ntStatus); ntStatus = NtRegOpenKeyExW( hRepository, hRootKey, &wszSharesKey[0], 0, KEY_READ, &hKey); BAIL_ON_NT_STATUS(ntStatus); ntStatus = NtRegOpenKeyExW( hRepository, hRootKey, &wszShareSecKey[0], 0, KEY_READ, &hSecKey); BAIL_ON_NT_STATUS(ntStatus); ntStatus = SrvAllocateMemory( pResume->ulMaxIndex * sizeof(*ppShareInfoList), (PVOID) &ppShareInfoList); BAIL_ON_NT_STATUS(ntStatus); for (ulIndex = 0; ulIndex < pResume->ulMaxIndex; ulIndex++) { ULONG ulMaxValueNameLen = 0; ULONG ulMaxValueLen = 0; ULONG ulMaxSecValueLen = 0; ulMaxValueNameLen = (pResume->ulMaxValueNameLen + 1) * sizeof(*pwszValueName); ulMaxValueLen = pResume->ulMaxValueLen; ulMaxSecValueLen = MAX_VALUE_LENGTH; if (ulMaxValueNameLen) { SRV_SAFE_FREE_MEMORY_AND_RESET(pwszValueName); ntStatus = SrvAllocateMemory( ulMaxValueNameLen, (PVOID*) &pwszValueName); BAIL_ON_NT_STATUS(ntStatus); } if (ulMaxValueLen) { SRV_SAFE_FREE_MEMORY_AND_RESET(pData); ntStatus = SrvAllocateMemory(ulMaxValueLen, (PVOID*) &pData); BAIL_ON_NT_STATUS(ntStatus); } ntStatus = NtRegEnumValueW( hRepository, hKey, ulIndex, pwszValueName, &ulMaxValueNameLen, NULL, &dataType, pData, &ulMaxValueLen); BAIL_ON_NT_STATUS(ntStatus); if (REG_MULTI_SZ != dataType) { continue; } ntStatus = NtRegGetValueW( hRepository, hSecKey, NULL, pwszValueName, RRF_RT_REG_BINARY, &dataSecType, pSecData, &ulMaxSecValueLen); if (STATUS_OBJECT_NAME_NOT_FOUND == ntStatus) { ntStatus = 0; ulMaxSecValueLen = 0; } BAIL_ON_NT_STATUS(ntStatus); ntStatus = SrvShareRegWriteToShareInfo( dataType, pwszValueName, pData, ulMaxValueLen, dataSecType, pSecData, ulMaxSecValueLen, &ppShareInfoList[ulNumSharesFound++]); BAIL_ON_NT_STATUS(ntStatus); } *pppShareInfoList = ppShareInfoList; *pulNumSharesFound = ulNumSharesFound; cleanup: if (hRootKey) { NtRegCloseKey(hRepository, hRootKey); } if (hKey) { NtRegCloseKey(hRepository, hKey); } if (hSecKey) { NtRegCloseKey(hRepository, hSecKey); } SRV_SAFE_FREE_MEMORY(pwszValueName); SRV_SAFE_FREE_MEMORY(pData); return ntStatus; error: *pppShareInfoList = NULL; *pulNumSharesFound = 0; if (ppShareInfoList) { SrvShareFreeInfoList(ppShareInfoList, ulNumSharesFound); } goto cleanup; } NTSTATUS SrvShareRegEndEnum( IN HANDLE hRepository, IN HANDLE hResume ) { PSRV_SHARE_REG_ENUM_CONTEXT pEnumContext = (PSRV_SHARE_REG_ENUM_CONTEXT)hResume; SRV_SAFE_FREE_MEMORY(pEnumContext); return STATUS_SUCCESS; } NTSTATUS SrvShareRegDelete( IN HANDLE hRepository, 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( hRepository, NULL, &wszHKTM[0], 0, KEY_ALL_ACCESS, &hRootKey); BAIL_ON_NT_STATUS(ntStatus); ntStatus = NtRegDeleteKeyValueW( hRepository, hRootKey, &wszSharesKey[0], pwszShareName); BAIL_ON_NT_STATUS(ntStatus); ntStatus = NtRegDeleteKeyValueW( hRepository, hRootKey, &wszShareSecKey[0], pwszShareName); if (STATUS_OBJECT_NAME_NOT_FOUND == ntStatus) { ntStatus = STATUS_SUCCESS; } BAIL_ON_NT_STATUS(ntStatus); cleanup: if (hRootKey) { NtRegCloseKey(hRepository, hRootKey); } return ntStatus; error: goto cleanup; } NTSTATUS SrvShareRegGetCount( IN HANDLE hRepository, IN OUT PULONG pulNumShares ) { NTSTATUS ntStatus = 0; ULONG ulNumShares = 0; HKEY hRootKey = NULL; HKEY hKey = NULL; wchar16_t wszHKTM[] = HKEY_THIS_MACHINE_W; wchar16_t wszSharesKey[] = REG_KEY_PATH_SRV_SHARES_W; ntStatus = NtRegOpenKeyExW( hRepository, NULL, &wszHKTM[0], 0, KEY_READ, &hRootKey); BAIL_ON_NT_STATUS(ntStatus); ntStatus = NtRegOpenKeyExW( hRepository, hRootKey, &wszSharesKey[0], 0, KEY_READ, &hKey); BAIL_ON_NT_STATUS(ntStatus); ntStatus = NtRegQueryInfoKeyW( hRepository, hKey, NULL, NULL, NULL, NULL, NULL, NULL, &ulNumShares, NULL, NULL, NULL, NULL); BAIL_ON_NT_STATUS(ntStatus); *pulNumShares = ulNumShares; cleanup: if (hRootKey) { NtRegCloseKey(hRepository, hRootKey); } if (hKey) { NtRegCloseKey(hRepository, hKey); } return ntStatus; error: *pulNumShares = 0; goto cleanup; } VOID SrvShareRegClose( IN HANDLE hRepository ) { NtRegCloseServer(hRepository); } VOID SrvShareRegShutdown( VOID ) { //Do nothing } static NTSTATUS SrvShareRegWriteToShareInfo( IN REG_DATA_TYPE regDataType, IN PWSTR pwszShareName, IN PBYTE pData, IN ULONG ulDataLen, IN REG_DATA_TYPE regSecDataType, IN PBYTE pSecData, IN ULONG ulSecDataLen, OUT PSRV_SHARE_INFO* ppShareInfo ) { NTSTATUS ntStatus = STATUS_SUCCESS; PSRV_SHARE_INFO pShareInfo = NULL; PWSTR* ppwszValues = NULL; ntStatus = SrvAllocateMemory(sizeof(*pShareInfo), (PVOID*)&pShareInfo); BAIL_ON_NT_STATUS(ntStatus); pShareInfo->refcount = 1; pthread_rwlock_init(&pShareInfo->mutex, NULL); pShareInfo->pMutex = &pShareInfo->mutex; ntStatus = SrvAllocateStringW(pwszShareName, &pShareInfo->pwszName); 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; ntStatus = NtRegByteArrayToMultiStrs(pData, ulDataLen, &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(pShareInfo->pwszPath); ntStatus = SrvAllocateStringW( &pwszValue[ulPathPrefixLen], &pShareInfo->pwszPath); BAIL_ON_NT_STATUS(ntStatus); } else if (!wc16sncmp(&wszCommentPrefix[0], pwszValue, ulCommentPrefixLen)) { SRV_SAFE_FREE_MEMORY(pShareInfo->pwszComment); ntStatus = SrvAllocateStringW( &pwszValue[ulCommentPrefixLen], &pShareInfo->pwszComment); BAIL_ON_NT_STATUS(ntStatus); } else if (!wc16sncmp(&wszServicePrefix[0], pwszValue, ulServicePrefixLen)) { ntStatus = SrvShareMapServiceStringToIdW( &pwszValue[ulServicePrefixLen], &pShareInfo->service); BAIL_ON_NT_STATUS(ntStatus); } else { ntStatus = STATUS_INVALID_PARAMETER_3; BAIL_ON_NT_STATUS(ntStatus); } } } if (ulSecDataLen) { ntStatus = SrvShareSetSecurity( pShareInfo, (PSECURITY_DESCRIPTOR_RELATIVE)pSecData, ulSecDataLen); BAIL_ON_NT_STATUS(ntStatus); } *ppShareInfo = pShareInfo; cleanup: if (ppwszValues) { RegFreeMultiStrsW(ppwszValues); } return ntStatus; error: if (pShareInfo) { SrvShareReleaseInfo(pShareInfo); } goto cleanup; } static VOID SrvShareFreeStringArray( PWSTR* ppwszValues, ULONG ulNumValues ) { ULONG iValue = 0; for (; iValue < ulNumValues; iValue++) { if (ppwszValues[iValue]) { SrvFreeMemory(ppwszValues[iValue]); } } SrvFreeMemory(ppwszValues); } /* local variables: mode: c c-basic-offset: 4 indent-tabs-mode: nil tab-width: 4 end: */