Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

4581 lines
146 KiB

/*++
Copyright (c) 1992-2001 Microsoft Corporation
Module Name:
smbshare.c
Abstract:
Resource DLL for File Shares.
Author:
Rod Gamache (rodga) 8-Jan-1996
Revision History:
--*/
#define UNICODE 1
#include "clusres.h"
#include "clusrtl.h"
#include "lm.h"
#include "lmerr.h"
#include "lmshare.h"
#include <dfsfsctl.h>
#include <srvfsctl.h>
#include <lmdfs.h>
#include <validc.h>
#include <strsafe.h>
#define LOG_CURRENT_MODULE LOG_MODULE_SMB
#define SMB_SVCNAME TEXT("LanmanServer")
#define DFS_SVCNAME TEXT("Dfs")
#define MAX_RETRIES 20
#define DBG_PRINT printf
#define PARAM_KEYNAME__PARAMETERS CLUSREG_KEYNAME_PARAMETERS
#define PARAM_NAME__SHARENAME CLUSREG_NAME_FILESHR_SHARE_NAME
#define PARAM_NAME__PATH CLUSREG_NAME_FILESHR_PATH
#define PARAM_NAME__REMARK CLUSREG_NAME_FILESHR_REMARK
#define PARAM_NAME__MAXUSERS CLUSREG_NAME_FILESHR_MAX_USERS
#define PARAM_NAME__SECURITY CLUSREG_NAME_FILESHR_SECURITY
#define PARAM_NAME__SD CLUSREG_NAME_FILESHR_SD
#define PARAM_NAME__SHARESUBDIRS CLUSREG_NAME_FILESHR_SHARE_SUBDIRS
#define PARAM_NAME__HIDESUBDIRSHARES CLUSREG_NAME_FILESHR_HIDE_SUBDIR_SHARES
#define PARAM_NAME__DFSROOT CLUSREG_NAME_FILESHR_IS_DFS_ROOT
#define PARAM_NAME__CSCCACHE CLUSREG_NAME_FILESHR_CSC_CACHE
#define PARAM_MIN__MAXUSERS 0
#define PARAM_MAX__MAXUSERS ((DWORD)-1)
#define PARAM_DEFAULT__MAXUSERS ((DWORD)-1)
#define FREE_SECURITY_INFO() \
LocalFree( params.Security ); \
params.Security = NULL; \
params.SecuritySize = 0; \
LocalFree( params.SecurityDescriptor ); \
params.SecurityDescriptor = NULL; \
params.SecurityDescriptorSize = 0
#define SMBSHARE_EXTRA_LEN 10
typedef struct _SUBDIR_SHARE_INFO {
LIST_ENTRY ListEntry;
WCHAR ShareName [NNLEN+1];
}SUBDIR_SHARE_INFO,*PSUBDIR_SHARE_INFO;
typedef struct _SHARE_PARAMS {
LPWSTR ShareName;
LPWSTR Path;
LPWSTR Remark;
ULONG MaxUsers;
PUCHAR Security;
ULONG SecuritySize;
ULONG ShareSubDirs;
ULONG HideSubDirShares;
ULONG DfsRoot;
ULONG CSCCache;
PUCHAR SecurityDescriptor;
ULONG SecurityDescriptorSize;
} SHARE_PARAMS, *PSHARE_PARAMS;
typedef struct _SHARE_RESOURCE {
RESID ResId; // for validation
SHARE_PARAMS Params;
HKEY ResourceKey;
HKEY ParametersKey;
RESOURCE_HANDLE ResourceHandle;
WCHAR ComputerName[MAX_COMPUTERNAME_LENGTH+1];
CLUS_WORKER PendingThread;
CLUSTER_RESOURCE_STATE State;
LIST_ENTRY SubDirList;
HRESOURCE hResource;
CLUS_WORKER NotifyWorker;
HANDLE NotifyHandle;
BOOL bDfsRootNeedsMonitoring;
WCHAR szDependentNetworkName[MAX_COMPUTERNAME_LENGTH+1];
} SHARE_RESOURCE, *PSHARE_RESOURCE;
typedef struct _SHARE_TYPE_LIST {
PWSTR Name;
ULONG Type;
} SHARE_TYPE_LIST, *PSHARE_TYPE_LIST;
typedef struct SHARE_ENUM_CONTEXT {
PSHARE_RESOURCE pResourceEntry;
PSHARE_PARAMS pParams;
} SHARE_ENUM_CONTEXT, *PSHARE_ENUM_CONTEXT;
//
// Global data.
//
CRITICAL_SECTION SmbShareLock;
// Log Event Routine
#define g_LogEvent ClusResLogEvent
#define g_SetResourceStatus ClusResSetResourceStatus
// Forward reference to our RESAPI function table.
extern CLRES_FUNCTION_TABLE SmbShareFunctionTable;
//
// SmbShare resource read-write private properties
//
RESUTIL_PROPERTY_ITEM
SmbShareResourcePrivateProperties[] = {
{ PARAM_NAME__SHARENAME, NULL, CLUSPROP_FORMAT_SZ, 0, 0, 0, RESUTIL_PROPITEM_REQUIRED, FIELD_OFFSET(SHARE_PARAMS,ShareName) },
{ PARAM_NAME__PATH, NULL, CLUSPROP_FORMAT_SZ, 0, 0, 0, RESUTIL_PROPITEM_REQUIRED, FIELD_OFFSET(SHARE_PARAMS,Path) },
{ PARAM_NAME__REMARK, NULL, CLUSPROP_FORMAT_SZ, 0, 0, 0, 0, FIELD_OFFSET(SHARE_PARAMS,Remark) },
{ PARAM_NAME__MAXUSERS, NULL, CLUSPROP_FORMAT_DWORD, PARAM_DEFAULT__MAXUSERS, PARAM_MIN__MAXUSERS, PARAM_MAX__MAXUSERS, 0, FIELD_OFFSET(SHARE_PARAMS,MaxUsers) },
{ PARAM_NAME__SECURITY, NULL, CLUSPROP_FORMAT_BINARY, 0, 0, 0, 0, FIELD_OFFSET(SHARE_PARAMS,Security) },
{ PARAM_NAME__SHARESUBDIRS, NULL, CLUSPROP_FORMAT_DWORD, 0, 0, 1, 0, FIELD_OFFSET(SHARE_PARAMS,ShareSubDirs) },
{ PARAM_NAME__HIDESUBDIRSHARES, NULL, CLUSPROP_FORMAT_DWORD, 0, 0, 1, 0, FIELD_OFFSET(SHARE_PARAMS,HideSubDirShares) },
{ PARAM_NAME__DFSROOT, NULL, CLUSPROP_FORMAT_DWORD, 0, 0, 1, 0, FIELD_OFFSET(SHARE_PARAMS, DfsRoot) },
{ PARAM_NAME__SD, NULL, CLUSPROP_FORMAT_BINARY, 0, 0, 0, 0, FIELD_OFFSET(SHARE_PARAMS,SecurityDescriptor) },
{ PARAM_NAME__CSCCACHE, NULL, CLUSPROP_FORMAT_DWORD, CSC_CACHE_MANUAL_REINT, CSC_CACHE_MANUAL_REINT, CSC_CACHE_NONE, 0, FIELD_OFFSET(SHARE_PARAMS,CSCCache) },
{ NULL, NULL, 0, 0, 0, 0 }
};
typedef struct _SMB_DEPEND_SETUP {
DWORD Offset;
CLUSPROP_SYNTAX Syntax;
DWORD Length;
PVOID Value;
} SMB_DEPEND_SETUP, *PSMB_DEPEND_SETUP;
typedef struct _SMB_DEPEND_DATA {
#if 0
CLUSPROP_RESOURCE_CLASS storageEntry;
#endif
CLUSPROP_SYNTAX endmark;
} SMB_DEPEND_DATA, *PSMB_DEPEND_DATA;
typedef struct _DFS_DEPEND_DATA {
#if 0
CLUSPROP_RESOURCE_CLASS storageEntry;
#endif
CLUSPROP_SZ_DECLARE( networkEntry, sizeof(CLUS_RESTYPE_NAME_NETNAME) / sizeof(WCHAR) );
CLUSPROP_SYNTAX endmark;
} DFS_DEPEND_DATA, *PDFS_DEPEND_DATA;
// This table is for Smb Share dependencies only
SMB_DEPEND_SETUP SmbDependSetup[] = {
#if 0 // rodga - allow for dependency on a local disk
{ FIELD_OFFSET(SMB_DEPEND_DATA, storageEntry), CLUSPROP_SYNTAX_RESCLASS, sizeof(CLUSTER_RESOURCE_CLASS), (PVOID)CLUS_RESCLASS_STORAGE },
#endif
{ 0, 0 }
};
// This table is for DFS Share dependencies only
SMB_DEPEND_SETUP DfsDependSetup[] = {
#if 0 // rodga - allow for dependency on a local disk
{ FIELD_OFFSET(DFS_DEPEND_DATA, storageEntry), CLUSPROP_SYNTAX_RESCLASS, sizeof(CLUSTER_RESOURCE_CLASS), (PVOID)CLUS_RESCLASS_STORAGE },
#endif
{ FIELD_OFFSET(DFS_DEPEND_DATA, networkEntry), CLUSPROP_SYNTAX_NAME, sizeof(CLUS_RESTYPE_NAME_NETNAME), CLUS_RESTYPE_NAME_NETNAME },
{ 0, 0 }
};
BOOL g_fDfsServiceNeedsRecyling = FALSE;
//
// External references
//
BOOL
SmbExamineSD(
RESOURCE_HANDLE ResourceHandle,
PSECURITY_DESCRIPTOR psdSD
);
//
// Forward references
//
BOOL
WINAPI
SmbShareIsAlive(
IN RESID Resource
);
DWORD
SmbShareGetPrivateResProperties(
IN OUT PSHARE_RESOURCE ResourceEntry,
OUT PVOID OutBuffer,
IN DWORD OutBufferSize,
OUT LPDWORD BytesReturned
);
DWORD
SmbShareValidatePrivateResProperties(
IN OUT PSHARE_RESOURCE ResourceEntry,
IN PVOID InBuffer,
IN DWORD InBufferSize,
OUT PSHARE_PARAMS Params
);
DWORD
SmbShareSetPrivateResProperties(
IN OUT PSHARE_RESOURCE ResourceEntry,
IN PVOID InBuffer,
IN DWORD InBufferSize
);
DWORD
SmbpIsDfsRoot(
IN PSHARE_RESOURCE ResourceEntry,
OUT PBOOL pbIsDfsRoot
);
DWORD
SmbpPrepareOnlineDfsRoot(
IN PSHARE_RESOURCE ResourceEntry
);
DWORD
SmbpCreateDfsRoot(
IN PSHARE_RESOURCE pResourceEntry
);
DWORD
SmbpDeleteDfsRoot(
IN PSHARE_RESOURCE pResourceEntry
);
DWORD
SmbpShareNotifyThread(
IN PCLUS_WORKER pWorker,
IN PSHARE_RESOURCE pResourceEntry
);
DWORD
SmbpCheckForSubDirDeletion (
IN PSHARE_RESOURCE pResourceEntry
);
DWORD
SmbpCheckAndBringSubSharesOnline (
IN PSHARE_RESOURCE pResourceEntry,
IN BOOL IsCheckAllSubDirs,
IN PRESOURCE_STATUS pResourceStatus,
IN PCLUS_WORKER pWorker,
OUT LPWSTR *pszRootDirOut
);
DWORD
SmbpHandleDfsRoot(
IN PSHARE_RESOURCE pResourceEntry,
OUT PBOOL pbIsDfsRoot
);
DWORD
SmbpResetDfs(
IN PSHARE_RESOURCE pResourceEntry
);
DWORD
SmbpValidateShareName(
IN LPCWSTR lpszShareName
);
//
// Private DFS APIs provided bu UDAYH - 4/26/2001
//
DWORD
GetDfsRootMetadataLocation(
LPWSTR RootName,
LPWSTR *pMetadataNameLocation
);
VOID
ReleaseDfsRootMetadataLocation(
LPWSTR Buffer
);
DWORD
SmbpRecycleDfsService(
IN PSHARE_RESOURCE pResourceEntry
);
DWORD
SmbpSetCacheFlags(
IN PSHARE_RESOURCE ResourceEntry,
IN LPWSTR ShareName
)
/*++
Routine Description:
Set the caching flags for the given resource entry.
Arguments:
ResourceEntry - A pointer to the SHARE_RESOURCE block for this resource.
ShareName - the name of the share to set cache flags for.
Returns:
ERROR_SUCCESS if successful.
Win32 error code on failure.
--*/
{
DWORD status;
DWORD invalidParam;
PSHARE_INFO_1005 shi1005;
status = NetShareGetInfo( NULL,
ShareName,
1005,
(LPBYTE *)&shi1005 );
if ( status != ERROR_SUCCESS ) {
(g_LogEvent)(
ResourceEntry->ResourceHandle,
LOG_ERROR,
L"SetCacheFlags, error getting CSC info on share '%1!ws!. Error %2!u!.\n",
ShareName,
status );
goto exit;
} else {
shi1005->shi1005_flags &= ~CSC_MASK;
shi1005->shi1005_flags |= (ResourceEntry->Params.CSCCache & CSC_MASK);
status = NetShareSetInfo( NULL,
ShareName,
1005,
(LPBYTE)shi1005,
&invalidParam );
NetApiBufferFree((TCHAR FAR *)shi1005);
if ( status != ERROR_SUCCESS ) {
(g_LogEvent)(
ResourceEntry->ResourceHandle,
LOG_ERROR,
L"SetCacheFlags, error setting CSC info on share '%1!ws!. Error %2!u!, property # %3!d!.\n",
ShareName,
status,
invalidParam );
}
}
exit:
return(status);
} // SmbpSetCacheFlags()
BOOLEAN
WINAPI
SmbShareDllEntryPoint(
IN HINSTANCE DllHandle,
IN DWORD Reason,
IN LPVOID Reserved
)
{
switch( Reason ) {
case DLL_PROCESS_ATTACH:
InitializeCriticalSection( &SmbShareLock );
break;
case DLL_PROCESS_DETACH:
DeleteCriticalSection( &SmbShareLock );
break;
default:
break;
}
return(TRUE);
} // SmbShareDllEntryPoint
DWORD
SmbpShareNotifyThread(
IN PCLUS_WORKER pWorker,
IN PSHARE_RESOURCE pResourceEntry
)
/*++
Routine Description:
Check whether any new subdirs have been added or deleted from
under the root share.
Arguments:
pWorker - Supplies the worker structure.
pResourceEntry - A pointer to the SHARE_RESOURCE block for this resource.
Returns:
ERROR_SUCCESS if successful.
Win32 error code on failure.
--*/
{
DWORD status = ERROR_SUCCESS;
LPWSTR pszRootDir;
//
// Chittur Subbaraman (chitturs) - 09/25/98
//
// This notification thread is activated once a
// notification is received. This thread checks for any
// new subdir additions or any subdir deletions. If it
// finds such an occurrence, this thread adds the subdir to
// or deletes the subdir from the root share. The two
// Smbp functions this thread calls also checks
// whether any termination command has arrived from the
// offline thread. If such a command has arrived, this thread
// terminates immediately, thus releasing the offline thread
// from the infinite time wait.
//
SmbpCheckForSubDirDeletion( pResourceEntry );
SmbpCheckAndBringSubSharesOnline( pResourceEntry,
TRUE,
NULL,
&pResourceEntry->NotifyWorker,
&pszRootDir );
LocalFree ( pszRootDir );
return(status);
} // SmbShareNotify
DWORD
SmbpCheckForSubDirDeletion (
IN PSHARE_RESOURCE pResourceEntry
)
/*++
Routine Description:
Check and remove any deleted subdirectory shares.
Arguments:
ResourceEntry - A pointer to the SHARE_RESOURCE block for this resource.
Returns:
ERROR_SUCCESS if successful.
Win32 error code on failure.
--*/
{
PLIST_ENTRY pHead, plistEntry;
PSUBDIR_SHARE_INFO pSubShareInfo;
HANDLE hFind;
DWORD status = ERROR_SUCCESS;
DWORD dwLen;
LPWSTR pszRootDir = NULL, pszPath = NULL;
WIN32_FIND_DATA FindData;
DWORD dwCount = 0;
//
// Chittur Subbaraman (chitturs) - 09/25/98
//
// This function first checks to see whether all the subshares
// are indeed currently present. If it finds any subdir
// corresponding to a subshare to be absent, then it removes
// that subdir from the share list.
//
dwLen = lstrlenW( pResourceEntry->Params.Path );
pszRootDir = ( LPWSTR ) LocalAlloc( LMEM_FIXED, ( dwLen + SMBSHARE_EXTRA_LEN ) * sizeof( WCHAR ) );
if ( pszRootDir == NULL )
{
(g_LogEvent)(
pResourceEntry->ResourceHandle,
LOG_ERROR,
L"Unable to allocate pszRootDir. Error: %1!u!.\n",
status = GetLastError() );
goto error_exit;
}
( void ) StringCchCopy( pszRootDir, dwLen + SMBSHARE_EXTRA_LEN, pResourceEntry->Params.Path );
//
// If the path is not already terminated with \\ then add it.
//
if ( pszRootDir [dwLen-1] != L'\\' )
pszRootDir [dwLen++] = L'\\';
pszRootDir [dwLen] = L'\0' ;
pszPath = LocalAlloc ( LMEM_FIXED, ( dwLen + SMBSHARE_EXTRA_LEN + NNLEN ) * sizeof ( WCHAR ) );
if ( pszPath == NULL )
{
(g_LogEvent)(
pResourceEntry->ResourceHandle,
LOG_ERROR,
L"Unable to allocate pszPath. Error: %1!u!.\n",
status = GetLastError() );
goto error_exit;
}
pHead = plistEntry = &pResourceEntry->SubDirList;
for ( plistEntry = pHead->Flink;
plistEntry != pHead;
dwCount++)
{
if ( ClusWorkerCheckTerminate ( &pResourceEntry->NotifyWorker ) )
{
status = ERROR_SUCCESS;
break;
}
pSubShareInfo = CONTAINING_RECORD( plistEntry, SUBDIR_SHARE_INFO, ListEntry );
plistEntry = plistEntry->Flink;
if ( lstrcmpW( pSubShareInfo->ShareName, pResourceEntry->Params.ShareName ))
{
//
// This is not the root share
//
( void ) StringCchCopy ( pszPath, dwLen + SMBSHARE_EXTRA_LEN + NNLEN, pszRootDir );
( void ) StringCchCat ( pszPath, dwLen + SMBSHARE_EXTRA_LEN + NNLEN, pSubShareInfo->ShareName );
//
// Get rid of the hidden share '$' sign for passing onto
// FindFirstFile, if present. Only do this if the
// "HideSubDirShares" option is chosen.
//
if ( pResourceEntry->Params.HideSubDirShares )
{
dwLen = lstrlenW( pszPath );
if ( pszPath [dwLen-1] == L'$' )
{
pszPath [dwLen-1] = L'\0';
}
}
hFind = FindFirstFile( pszPath, &FindData );
if ( hFind == INVALID_HANDLE_VALUE )
{
status = GetLastError();
(g_LogEvent)(
pResourceEntry->ResourceHandle,
LOG_ERROR,
L"SmbpCheckForSubDirDeletion: Dir '%1' not found ...\n",
pszPath
);
if ( status == ERROR_FILE_NOT_FOUND )
{
//
// Delete the file share
//
status = NetShareDel( NULL, pSubShareInfo->ShareName, 0 );
if ( (status != NERR_NetNameNotFound) &&
(status != NO_ERROR) )
{
(g_LogEvent)(
pResourceEntry->ResourceHandle,
LOG_ERROR,
L"SmbpCheckForSubDirDeletion: Error removing share '%1'. Error code = %2!u!...\n",
pSubShareInfo->ShareName,
status );
} else
{
(g_LogEvent)(
pResourceEntry->ResourceHandle,
LOG_INFORMATION,
L"SmbpCheckForSubDirDeletion: Removing share '%1'...\n",
pSubShareInfo->ShareName );
RemoveEntryList( &pSubShareInfo->ListEntry );
LocalFree ( pSubShareInfo );
}
}
else
{
(g_LogEvent)(
pResourceEntry->ResourceHandle,
LOG_ERROR,
L"SmbpCheckForSubDirDeletion: Error in FindFirstFile for share '%1'. Error code = %2!u!....\n",
pSubShareInfo->ShareName,
status );
}
}
else
{
if ( !FindClose ( hFind ) )
{
(g_LogEvent)(
pResourceEntry->ResourceHandle,
LOG_ERROR,
L"CheckForSubDirDeletion: FindClose Failed. Error: %1!u!.\n",
status = GetLastError () );
}
}
}
} // end of for loop
error_exit:
LocalFree ( pszRootDir );
LocalFree ( pszPath );
return(status);
} // SmbpCheckForSubDirDeletion
DWORD
SmbpCheckAndBringSubSharesOnline (
IN PSHARE_RESOURCE pResourceEntry,
IN BOOL IsCheckAllSubDirs,
IN PRESOURCE_STATUS pResourceStatus,
IN PCLUS_WORKER pWorker,
OUT LPWSTR *pszRootDirOut
)
/*++
Routine Description:
Check and bring online any newly added subdirectory shares.
Arguments:
pResourceEntry - A pointer to the SHARE_RESOURCE block for this resource.
IsCheckAllSubDirs - Check whether a subdir is a share or not
pResourceStatus - A pointer to the RESOURCE_STATUS
pWorker - A pointer to the worker thread
pszRootDirOut - A pointer to the root share store
Returns:
ERROR_SUCCESS if successful.
Win32 error code on failure.
--*/
{
HANDLE hFind = INVALID_HANDLE_VALUE;
WIN32_FIND_DATA FindData;
WCHAR szPath [MAX_PATH+1];
DWORD dwLen, dwShareLen;
DWORD dwCount = 0;
SHARE_INFO_502 shareInfo;
PSHARE_INFO_502 pshareInfo = NULL;
WCHAR szShareName [NNLEN+2];
DWORD status = ERROR_SUCCESS;
PSUBDIR_SHARE_INFO pSubShareInfo;
PLIST_ENTRY plistEntry;
RESOURCE_EXIT_STATE exitState;
LPWSTR pszRootDir = NULL;
//
// Chittur Subbaraman (chitturs) - 09/25/98
//
// This function will be called either from SmbpShareOnlineThread
// with the input parameter IsCheckAllSubDirs set to FALSE
// or from SmbpShareNotifyThread with the parameter set to TRUE.
// In the former case, this function will blindly make all the
// subdirs under the root share as shares. In the latter case,
// this function will first check whether a particular subdir
// is a share and if not it will make it as a share.
//
dwLen = lstrlenW( pResourceEntry->Params.Path );
plistEntry = &pResourceEntry->SubDirList;
//
// Allocate memory to store the root share here and
// free it at the caller
//
pszRootDir = ( LPWSTR ) LocalAlloc( LMEM_FIXED, ( dwLen + SMBSHARE_EXTRA_LEN ) * sizeof( WCHAR ) );
if ( pszRootDir == NULL )
{
(g_LogEvent)(
pResourceEntry->ResourceHandle,
LOG_ERROR,
L"Unable to allocate pszRootDir. Error: %1!u!.\n",
status = GetLastError() );
goto error_exit;
}
( void ) StringCchCopy( pszRootDir, dwLen + SMBSHARE_EXTRA_LEN, pResourceEntry->Params.Path );
//
// If the path is not already terminated with \\ then add it.
//
if ( pszRootDir [dwLen-1] != L'\\' )
pszRootDir [dwLen++] = L'\\';
//
// Add '*' to search all the files.
//
pszRootDir [dwLen++] = L'*' ;
pszRootDir [dwLen] = L'\0' ;
ZeroMemory( &shareInfo, sizeof( shareInfo ) );
shareInfo.shi502_path = szPath;
shareInfo.shi502_netname = szShareName;
shareInfo.shi502_type = STYPE_DISKTREE;
shareInfo.shi502_remark = pResourceEntry->Params.Remark;
shareInfo.shi502_max_uses = pResourceEntry->Params.MaxUsers;
shareInfo.shi502_passwd = NULL;
shareInfo.shi502_security_descriptor = pResourceEntry->Params.SecurityDescriptor;
//
// Find the first file in the root dir
//
if ( ( hFind = FindFirstFile( pszRootDir, &FindData ) ) == INVALID_HANDLE_VALUE ) {
status = GetLastError () ;
if ( status == ERROR_FILE_NOT_FOUND ) {
status = ERROR_SUCCESS;
} else {
(g_LogEvent)(
pResourceEntry->ResourceHandle,
LOG_ERROR,
L"CheckForSubDirAddition: FindFirstFile Failed For Root Share... Error: %1!u!.\n",
status );
}
goto error_exit;
}
//
// Remove the '*' so the same variable can be used later.
//
pszRootDir [dwLen-1] = L'\0' ;
while ( status == ERROR_SUCCESS ) {
if ( ClusWorkerCheckTerminate ( pWorker ) == TRUE ) {
status = ERROR_SUCCESS;
goto error_exit;
}
if ( FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) {
//
// Check only subdirectories, not files
//
dwShareLen = lstrlenW( FindData.cFileName );
if ( dwShareLen <= NNLEN && (dwLen + dwShareLen < MAX_PATH) ) // A safety check for overflow
{
( void ) StringCchCopy( szShareName, RTL_NUMBER_OF ( szShareName ), FindData.cFileName );
if ( szShareName[0] == L'.' )
{
if ( szShareName [1] == L'\0' ||
szShareName[1] == L'.' && szShareName [2] == L'\0' ) {
goto skip;
}
}
if ( pResourceEntry->Params.HideSubDirShares )
( void ) StringCchCat( szShareName, RTL_NUMBER_OF ( szShareName ), L"$" );
( void ) StringCchCopy ( szPath, RTL_NUMBER_OF ( szPath ), pszRootDir );
( void ) StringCchCat ( szPath, RTL_NUMBER_OF ( szPath ), FindData.cFileName );
if ( IsCheckAllSubDirs == TRUE )
{
//
// If this call is made from the notify thread,
// try to see whether a particular subdir is a
// share
//
status = NetShareGetInfo( NULL,
szShareName,
502, // return a SHARE_INFO_502 structure
(LPBYTE *) &pshareInfo );
} else
{
//
// If this call is made from the online thread,
// assume that the subdir is not a share (since
// it would have been removed as a share the
// most recent time when it was made offline).
//
status = NERR_NetNameNotFound;
}
if ( status == NERR_NetNameNotFound )
{
status = NetShareAdd( NULL, 502, (PBYTE)&shareInfo, NULL );
if ( status == ERROR_SUCCESS )
{
pSubShareInfo = (PSUBDIR_SHARE_INFO) LocalAlloc( LMEM_FIXED, sizeof(SUBDIR_SHARE_INFO) );
if ( pSubShareInfo == NULL )
{
(g_LogEvent)(
pResourceEntry->ResourceHandle,
LOG_ERROR,
L"SmbpCheckAndBringSubSharesOnline: Unable to allocate pSubShareInfo. Error: %1!u!.\n",
status = GetLastError() );
goto error_exit;
}
( void ) StringCchCopy ( pSubShareInfo->ShareName, RTL_NUMBER_OF ( pSubShareInfo->ShareName ), szShareName );
InsertTailList( plistEntry, &pSubShareInfo->ListEntry );
//
// Set the caching flags for this entry.
//
status = SmbpSetCacheFlags( pResourceEntry,
szShareName );
if ( status != ERROR_SUCCESS ) {
goto error_exit;
}
(g_LogEvent)(
pResourceEntry->ResourceHandle,
LOG_INFORMATION,
L"SmbpCheckAndBringSubSharesOnline: Adding share '%1'...\n",
pSubShareInfo->ShareName);
if ( IsCheckAllSubDirs == FALSE )
{
if ( (dwCount++ % 100) == 0)
{
pResourceStatus->CheckPoint++;
exitState = (g_SetResourceStatus)( pResourceEntry->ResourceHandle,
pResourceStatus );
if ( exitState == ResourceExitStateTerminate )
{
status = ERROR_OPERATION_ABORTED;
goto error_exit;
}
}
}
}
else
{
//
// ignore this error but log that something went wrong
//
(g_LogEvent)(
pResourceEntry->ResourceHandle,
LOG_ERROR,
L"SmbpCheckAndBringSubSharesOnline: NetShareAdd failed for %1!ws! Error: %2!u!.\n",
szShareName,
status );
status = ERROR_SUCCESS;
}
} else
{
if ( pshareInfo != NULL )
{
NetApiBufferFree( pshareInfo );
}
}
}
else
{
(g_LogEvent)(
pResourceEntry->ResourceHandle,
LOG_ERROR,
L"SmbpCheckAndBringSubSharesOnline: NetShareAdd Share not added for subdir due to illegal share name length '%1!ws!'.\n",
FindData.cFileName );
}
}
skip:
if ( !FindNextFile( hFind, &FindData ) )
{
status = GetLastError ();
}
} // end of while loop
if ( status == ERROR_NO_MORE_FILES )
{
status = ERROR_SUCCESS;
}
else
{
(g_LogEvent)(
pResourceEntry->ResourceHandle,
LOG_ERROR,
L"CheckForSubDirAddition: FindNextFile Failed. Error: %1!u!.\n",
status );
}
error_exit:
if ( hFind != INVALID_HANDLE_VALUE )
{
if( !FindClose (hFind) )
{
(g_LogEvent)(
pResourceEntry->ResourceHandle,
LOG_ERROR,
L"SmbpCheckAndBringSubSharesOnline: FindClose Failed. Error: %1!u!.\n",
status = GetLastError () );
}
}
*pszRootDirOut = pszRootDir;
return(status);
} // SmbpCheckAndBringSubSharesOnline
DWORD
SmbShareOnlineThread(
IN PCLUS_WORKER pWorker,
IN PSHARE_RESOURCE ResourceEntry
)
/*++
Routine Description:
Brings a share resource online.
Arguments:
pWorker - Supplies the worker structure
ResourceEntry - A pointer to the SHARE_RESOURCE block for this resource.
Returns:
ERROR_SUCCESS if successful.
Win32 error code on failure.
--*/
{
SHARE_INFO_502 shareInfo;
DWORD retry = MAX_RETRIES;
DWORD status;
RESOURCE_STATUS resourceStatus;
LPWSTR nameOfPropInError;
BOOL bIsExistingDfsRoot = FALSE;
BOOL bDfsRootCreationFailed = FALSE;
DWORD dwLen;
ResUtilInitializeResourceStatus( &resourceStatus );
resourceStatus.ResourceState = ClusterResourceOnlinePending;
// resourceStatus.CheckPoint = 1;
//
// Read parameters.
//
status = ResUtilGetPropertiesToParameterBlock( ResourceEntry->ParametersKey,
SmbShareResourcePrivateProperties,
(LPBYTE) &ResourceEntry->Params,
TRUE, // CheckForRequiredProperties
&nameOfPropInError );
if (status != ERROR_SUCCESS) {
(g_LogEvent)(
ResourceEntry->ResourceHandle,
LOG_ERROR,
L"Unable to read the '%1' property. Error: %2!u!.\n",
(nameOfPropInError == NULL ? L"" : nameOfPropInError),
status );
goto exit;
}
if ( (ResourceEntry->Params.SecurityDescriptorSize != 0) &&
!IsValidSecurityDescriptor(ResourceEntry->Params.SecurityDescriptor) ) {
status = GetLastError();
goto exit;
}
while ( retry-- )
{
//
// Make sure the path does _NOT_ have a trailing backslash or it will fail to
// come online. But accept paths of the form E:\.
//
dwLen = ( DWORD ) wcslen( ResourceEntry->Params.Path );
if ( ( ResourceEntry->Params.Path[ dwLen - 1 ] == L'\\' ) &&
( dwLen > 3 ) )
{
ResourceEntry->Params.Path[ dwLen - 1 ] = L'\0'; // wack it.
}
ZeroMemory( &shareInfo, sizeof( shareInfo ) );
shareInfo.shi502_netname = ResourceEntry->Params.ShareName;
shareInfo.shi502_type = STYPE_DISKTREE;
shareInfo.shi502_remark = ResourceEntry->Params.Remark;
shareInfo.shi502_max_uses = ResourceEntry->Params.MaxUsers;
shareInfo.shi502_path = ResourceEntry->Params.Path;
shareInfo.shi502_passwd = NULL;
shareInfo.shi502_security_descriptor = ResourceEntry->Params.SecurityDescriptor;
status = NetShareAdd( NULL, 502, (PBYTE)&shareInfo, NULL );
if ( status == ERROR_SUCCESS ) {
status = SmbpSetCacheFlags( ResourceEntry,
ResourceEntry->Params.ShareName );
if ( status != ERROR_SUCCESS ) {
goto exit;
}
break;
}
// If we get a failure about the server not being started, then
// try to start the server and wait a little while.
if ( status != ERROR_SUCCESS ) {
WCHAR errorValue[20];
( void ) StringCchPrintf( errorValue, RTL_NUMBER_OF ( errorValue ), L"%u", status );
ClusResLogSystemEventByKey1(ResourceEntry->ResourceKey,
LOG_CRITICAL,
RES_SMB_SHARE_CANT_ADD,
errorValue);
if ( status == NERR_ServerNotStarted ) {
ResUtilStartResourceService( SMB_SVCNAME,
NULL );
Sleep( 500 );
} else if ( status == NERR_DuplicateShare ) {
(g_LogEvent)(
ResourceEntry->ResourceHandle,
LOG_WARNING,
L"Share %1!ws! is online already; deleting share and creating it again\n",
ResourceEntry->Params.ShareName);
//
// Delete the share and try again.
//
status = NetShareDel( NULL, ResourceEntry->Params.ShareName, 0 );
if ( status == NERR_IsDfsShare )
{
//
// Chittur Subbaraman (chitturs) - 2/12/99
//
// Reset the state info in the dfs driver dfs.sys
// and stop it. This will let srv.sys let you delete
// the share.
//
status = SmbpResetDfs( ResourceEntry );
//
// If we can't do this exit, else retry deleting and
// adding the share once again
//
if (status != ERROR_SUCCESS) {
(g_LogEvent)(
ResourceEntry->ResourceHandle,
LOG_ERROR,
L"SmbpResetDfs for Share %1!ws! failed with error %2!u!\n",
ResourceEntry->Params.ShareName,
status);
goto exit;
}
(g_LogEvent)(
ResourceEntry->ResourceHandle,
LOG_ERROR,
L"Informing DFS that share %1!ws! is not a dfs root \n",
ResourceEntry->Params.ShareName);
} else
{
(g_LogEvent)(
ResourceEntry->ResourceHandle,
LOG_INFORMATION,
L"Share %1!ws! deleted successfully ! \n",
ResourceEntry->Params.ShareName);
}
} else {
(g_LogEvent)(
ResourceEntry->ResourceHandle,
LOG_ERROR,
L"Error creating share. Error: %1!u!.\n",
status );
goto exit;
}
}
} // End for while ( retry-- )
if ( status == ERROR_SUCCESS )
{
// The share is now online, bring the subshares online
PLIST_ENTRY plistEntry;
PSUBDIR_SHARE_INFO pSubShareInfo;
LPWSTR pszRootDir;
plistEntry = &ResourceEntry->SubDirList;
//
// Store the Root share. This info is used to delete the share.
//
pSubShareInfo = (PSUBDIR_SHARE_INFO) LocalAlloc( LMEM_FIXED, sizeof (SUBDIR_SHARE_INFO) );
if ( pSubShareInfo == NULL ) {
(g_LogEvent)(
ResourceEntry->ResourceHandle,
LOG_ERROR,
L"Unable to allocate pSubShareInfo. Error: %1!u!.\n",
status = GetLastError() );
goto exit;
}
( void ) StringCchCopy ( pSubShareInfo->ShareName, RTL_NUMBER_OF ( pSubShareInfo->ShareName ), ResourceEntry->Params.ShareName );
InsertTailList( plistEntry, &pSubShareInfo->ListEntry );
if ( ResourceEntry->Params.ShareSubDirs ) {
// Chittur Subbaraman (chitturs) - 09/25/98
//
// Try to bring the subshares online.
// If there is a failure in bringing subshares online,
// pretend all is well since at least the root
// share has been successfully created. However, we
// write an entry into the log.
//
SmbpCheckAndBringSubSharesOnline ( ResourceEntry,
FALSE,
&resourceStatus,
&ResourceEntry->PendingThread,
&pszRootDir
);
if ( ClusWorkerCheckTerminate( &ResourceEntry->PendingThread ) ) {
(g_LogEvent)(
ResourceEntry->ResourceHandle,
LOG_INFORMATION,
L"SmbpShareOnlineThread: Terminating... !!!\n"
);
status = ERROR_SUCCESS;
LocalFree ( pszRootDir );
goto exit;
}
// Chittur Subbaraman (chitturs) - 09/25/98
//
// Create a change notification handle for any subdirectory
// additions/deletions and a notify thread which continuously
// checks and acts upon any such notifications. Do this
// only once at the beginning. The notification thread
// closes the handle at termination time.
//
ResourceEntry->NotifyHandle = FindFirstChangeNotification(
pszRootDir,
FALSE,
FILE_NOTIFY_CHANGE_DIR_NAME
);
LocalFree ( pszRootDir );
if ( ResourceEntry->NotifyHandle == INVALID_HANDLE_VALUE )
{
(g_LogEvent)(
ResourceEntry->ResourceHandle,
LOG_ERROR,
L"SmbpShareOnlineThread: FindFirstChange Notification Failed. Error: %1!u!.\n",
GetLastError ());
status = ERROR_SUCCESS;
goto exit;
}
goto exit;
}
} // End for root share successfully created.
//
// Chittur Subbaraman (chitturs) - 2/10/99
//
// If the user requests for this resource to be a DFS root, the
// dfs root will be created/accepted and the dfs registry
// checkpoints will be added. On the other hand, if the user
// wants this resource not to function as a dfs root any more,
// that case is also taken care of.
//
status = SmbpHandleDfsRoot( ResourceEntry, &bIsExistingDfsRoot );
if ( status != ERROR_SUCCESS ) {
(g_LogEvent)(
ResourceEntry->ResourceHandle,
LOG_ERROR,
L"SmbpHandleDfsRoot for Share %1!ws! failed with error %2!u!\n",
ResourceEntry->Params.ShareName,
status);
bDfsRootCreationFailed = TRUE;
goto exit;
}
if ( bIsExistingDfsRoot ) {
(g_LogEvent)(
ResourceEntry->ResourceHandle,
LOG_INFORMATION,
L"Share %1!ws! is a dfs root, online dfs\n",
ResourceEntry->Params.ShareName);
status = SmbpPrepareOnlineDfsRoot( ResourceEntry );
if ( status != ERROR_SUCCESS ) {
bDfsRootCreationFailed = TRUE;
}
}
exit:
if ( status != ERROR_SUCCESS ) {
if ( bDfsRootCreationFailed ) {
WCHAR szErrorString[12];
( void ) StringCchPrintf ( szErrorString, RTL_NUMBER_OF ( szErrorString ), L"%u", status);
ClusResLogSystemEventByKeyData1( ResourceEntry->ResourceKey,
LOG_CRITICAL,
RES_SMB_CANT_ONLINE_DFS_ROOT,
sizeof( status ),
&status,
szErrorString );
} else {
ClusResLogSystemEventByKeyData( ResourceEntry->ResourceKey,
LOG_CRITICAL,
RES_SMB_CANT_CREATE_SHARE,
sizeof( status ),
&status );
}
(g_LogEvent)(
ResourceEntry->ResourceHandle,
LOG_ERROR,
L"Error %1!u! bringing share %2!ws!, path %3!ws! online.\n",
status,
ResourceEntry->Params.ShareName,
ResourceEntry->Params.Path );
resourceStatus.ResourceState = ClusterResourceFailed;
} else {
resourceStatus.ResourceState = ClusterResourceOnline;
}
ResourceEntry->State = resourceStatus.ResourceState;
(g_SetResourceStatus)( ResourceEntry->ResourceHandle,
&resourceStatus );
return(status);
} // SmbShareOnlineThread
RESID
WINAPI
SmbShareOpen(
IN LPCWSTR ResourceName,
IN HKEY ResourceKey,
IN RESOURCE_HANDLE ResourceHandle
)
/*++
Routine Description:
Open routine for SMB share resource.
Arguments:
ResourceName - supplies the resource name
ResourceKey - Supplies handle to resource's cluster registry key.
ResourceHandle - the resource handle to be supplied with SetResourceStatus
is called.
Return Value:
RESID of created resource
Zero on failure
--*/
{
DWORD status;
RESID resid = 0;
HKEY parametersKey = NULL;
HKEY resKey = NULL;
PSHARE_RESOURCE resourceEntry = NULL;
DWORD computerNameSize = MAX_COMPUTERNAME_LENGTH + 1;
HCLUSTER hCluster;
//
// Get a handle to our resource key so that we can get our name later
// if we need to log an event.
//
status = ClusterRegOpenKey( ResourceKey,
L"",
KEY_READ,
&resKey);
if (status != ERROR_SUCCESS) {
(g_LogEvent)(ResourceHandle,
LOG_ERROR,
L"Unable to open resource key. Error: %1!u!.\n",
status );
SetLastError( status );
return(0);
}
//
// Open the Parameters key for this resource.
//
status = ClusterRegOpenKey( ResourceKey,
PARAM_KEYNAME__PARAMETERS,
KEY_ALL_ACCESS,
&parametersKey );
if ( status != ERROR_SUCCESS ) {
(g_LogEvent)(
ResourceHandle,
LOG_ERROR,
L"Unable to open Parameters key. Error: %1!u!.\n",
status );
goto exit;
}
//
// Allocate a resource entry.
//
resourceEntry = (PSHARE_RESOURCE) LocalAlloc( LMEM_FIXED, sizeof(SHARE_RESOURCE) );
if ( resourceEntry == NULL ) {
status = GetLastError();
(g_LogEvent)(
ResourceHandle,
LOG_ERROR,
L"Unable to allocate resource entry structure. Error: %1!u!.\n",
status );
goto exit;
}
//
// Initialize the resource entry..
//
ZeroMemory( resourceEntry, sizeof(SHARE_RESOURCE) );
resourceEntry->ResId = (RESID)resourceEntry; // for validation
resourceEntry->ResourceHandle = ResourceHandle;
resourceEntry->ResourceKey = resKey;
resourceEntry->ParametersKey = parametersKey;
resourceEntry->State = ClusterResourceOffline;
resourceEntry->NotifyHandle = INVALID_HANDLE_VALUE;
InitializeListHead( &resourceEntry->SubDirList );
hCluster = OpenCluster( NULL );
if ( !hCluster ) {
status = GetLastError();
(g_LogEvent)(
ResourceHandle,
LOG_ERROR,
L"Unable to open cluster. Error: %1!u!.\n",
status );
goto exit;
}
resourceEntry->hResource = OpenClusterResource( hCluster,
ResourceName );
CloseCluster( hCluster );
if ( !resourceEntry->hResource ) {
status = GetLastError();
(g_LogEvent)(
ResourceHandle,
LOG_ERROR,
L"Unable to open cluster resource. Error: %1!u!.\n",
status );
goto exit;
}
if ( !GetComputerNameW( &resourceEntry->ComputerName[0],
&computerNameSize ) ) {
status = GetLastError();
(g_LogEvent)(
ResourceHandle,
LOG_ERROR,
L"Unable to get computer name. Error: %1!u!.\n",
status );
goto exit;
}
resid = (RESID)resourceEntry;
exit:
if ( resid == 0 ) {
if ( parametersKey != NULL ) {
ClusterRegCloseKey( parametersKey );
}
if ( resKey != NULL ) {
ClusterRegCloseKey( resKey );
}
if ( resourceEntry &&
resourceEntry->hResource ) {
CloseClusterResource( resourceEntry->hResource );
}
LocalFree( resourceEntry );
}
SetLastError( status );
return(resid);
} // SmbShareOpen
DWORD
WINAPI
SmbShareOnline(
IN RESID ResourceId,
IN OUT PHANDLE EventHandle
)
/*++
Routine Description:
Online routine for File Share resource.
Arguments:
Resource - supplies resource id to be brought online
EventHandle - supplies a pointer to a handle to signal on error.
Return Value:
ERROR_SUCCESS if successful.
ERROR_RESOURCE_NOT_FOUND if RESID is not valid.
ERROR_RESOURCE_NOT_AVAILABLE if resource was arbitrated but failed to
acquire 'ownership'.
Win32 error code if other failure.
--*/
{
DWORD status;
PSHARE_RESOURCE resourceEntry;
resourceEntry = (PSHARE_RESOURCE)ResourceId;
if ( resourceEntry == NULL ) {
DBG_PRINT( "SmbShare: Online request for a nonexistent resource id 0x%p\n",
ResourceId );
return(ERROR_RESOURCE_NOT_FOUND);
}
if ( resourceEntry->ResId != ResourceId ) {
(g_LogEvent)(
resourceEntry->ResourceHandle,
LOG_ERROR,
L"Online resource sanity check failed! ResourceId = %1!u!.\n",
ResourceId );
return(ERROR_RESOURCE_NOT_FOUND);
}
#ifdef LOG_VERBOSE
(g_LogEvent)(
resourceEntry->ResourceHandle,
LOG_INFORMATION,
L"Online request.\n" );
#endif
resourceEntry->State = ClusterResourceOffline;
status = ClusWorkerCreate( &resourceEntry->PendingThread,
SmbShareOnlineThread,
resourceEntry );
if ( status != ERROR_SUCCESS ) {
resourceEntry->State = ClusterResourceFailed;
(g_LogEvent)(
resourceEntry->ResourceHandle,
LOG_ERROR,
L"Online: Unable to start thread, status %1!u!.\n",
status
);
} else {
status = ERROR_IO_PENDING;
}
return(status);
} // SmbShareOnline
DWORD
SmbShareDoTerminate (
IN PSHARE_RESOURCE ResourceEntry,
IN PRESOURCE_STATUS presourceStatus
)
/*++
Routine Description:
Do the actual Terminate work for File Share resources.
Arguments:
ResourceEntry - A pointer to the SHARE_RESOURCE block for this resource.
presourceStatus - A pointer to the RESOURCE_STATUS. This will be NULL if called from TERMINATE.
Returns:
ERROR_SUCCESS if successful.
Win32 error code on failure. If more than one share delete fails then
the last error is returned.
--*/
{
DWORD status = ERROR_SUCCESS, dwRet;
PLIST_ENTRY pHead, plistEntry;
PSUBDIR_SHARE_INFO pSubShareInfo;
#define SMB_DELETED_SHARES_REPORT_FREQ 100
DWORD dwSharesDeleted = SMB_DELETED_SHARES_REPORT_FREQ;
DWORD dwRetryCount;
BOOL bRetry;
RESOURCE_EXIT_STATE exit;
//
// Chittur Subbaraman (chitturs) - 09/25/98
//
// Terminate the notification thread first, so you can
// clean up even if the notification thread is forced to
// stop in the middle of its task. Also close the notification
// handle.
//
ClusWorkerTerminate( &ResourceEntry->NotifyWorker );
if ( ResourceEntry->NotifyHandle )
{
FindCloseChangeNotification ( ResourceEntry->NotifyHandle );
ResourceEntry->NotifyHandle = INVALID_HANDLE_VALUE;
}
(g_LogEvent)(
ResourceEntry->ResourceHandle,
LOG_INFORMATION,
L"SmbShareDoTerminate: SmbpShareNotifyWorker Terminated... !!!\n"
);
pHead = plistEntry = &ResourceEntry->SubDirList;
for ( plistEntry = pHead->Flink;
plistEntry != pHead;
dwSharesDeleted--
)
{
pSubShareInfo = CONTAINING_RECORD( plistEntry, SUBDIR_SHARE_INFO, ListEntry );
dwRetryCount = 1;
bRetry = FALSE;
do
{
dwRet = NetShareDel( NULL, pSubShareInfo->ShareName, 0 );
status = dwRet;
if ( dwRet != NO_ERROR )
{
(g_LogEvent)(
ResourceEntry->ResourceHandle,
LOG_ERROR,
L"Error removing share '%1'. Error %2!u!.\n",
pSubShareInfo->ShareName,
dwRet );
if (dwRet == NERR_IsDfsShare && !bRetry)
{
//
// Chittur Subbaraman (chitturs) - 2/12/99
//
// If this is a dfs root, reset the dfs driver and
// stop it. This will let you delete the share.
//
dwRet = SmbpResetDfs( ResourceEntry );
//
// If this fails, log an error
// else try and offline the resource again.
//
if (dwRet == ERROR_SUCCESS)
{
bRetry = TRUE;
}
else
{
(g_LogEvent)(
ResourceEntry->ResourceHandle,
LOG_ERROR,
L"Error in offlining the dfs root at this share '%1'. Error %2!u!.\n",
pSubShareInfo->ShareName,
dwRet );
status = dwRet;
}
}
}
} while (dwRetryCount-- && bRetry);
//
// if we're updating our status to resmon, do so every
// SMB_DELETED_SHARES_REPORT_FREQ shares
//
if ( presourceStatus && ( dwSharesDeleted == 0 )) {
presourceStatus->CheckPoint++;
exit = (g_SetResourceStatus)( ResourceEntry->ResourceHandle,
presourceStatus );
if ( exit == ResourceExitStateTerminate ) {
status = ERROR_OPERATION_ABORTED;
}
dwSharesDeleted = SMB_DELETED_SHARES_REPORT_FREQ;
}
plistEntry = plistEntry->Flink;
LocalFree (pSubShareInfo);
}
// This should initialize the list back to NULL
InitializeListHead(pHead);
ResourceEntry->bDfsRootNeedsMonitoring = FALSE;
return(status);
} // SmbShareDoTerminate
DWORD
SmbShareOfflineThread (
IN PCLUS_WORKER pWorker,
IN PSHARE_RESOURCE ResourceEntry
)
/*++
Routine Description:
Brings a share resource offline.
Do the actual Terminate work for File Share resources.
Arguments:
pWorker - Supplies the worker structure
ResourceEntry - A pointer to the SHARE_RESOURCE block for this resource.
Returns:
ERROR_SUCCESS if successful.
Win32 error code on failure.
--*/
{
RESOURCE_STATUS resourceStatus;
DWORD status;
ResUtilInitializeResourceStatus( &resourceStatus );
resourceStatus.ResourceState = ClusterResourceOfflinePending;
resourceStatus.ResourceState = (status = SmbShareDoTerminate (ResourceEntry, &resourceStatus)) == ERROR_SUCCESS?
ClusterResourceOffline:
ClusterResourceFailed;
(g_SetResourceStatus)( ResourceEntry->ResourceHandle,
&resourceStatus );
ResourceEntry->State = resourceStatus.ResourceState;
(g_LogEvent)(
ResourceEntry->ResourceHandle,
LOG_INFORMATION,
L"Smbshare is now offline.\n" );
return(status);
} // SmbShareOfflineThread
VOID
WINAPI
SmbShareTerminate(
IN RESID ResourceId
)
/*++
Routine Description:
Terminate routine for File Share resource.
Arguments:
ResourceId - Supplies resource id to be terminated
Return Value:
None.
--*/
{
PSHARE_RESOURCE resourceEntry;
resourceEntry = (PSHARE_RESOURCE)ResourceId;
if ( resourceEntry == NULL ) {
DBG_PRINT( "SmbShare: Terminate request for a nonexistent resource id 0x%p\n",
ResourceId );
return;
}
if ( resourceEntry->ResId != ResourceId ) {
(g_LogEvent)(
resourceEntry->ResourceHandle,
LOG_ERROR,
L"Terminate resource sanity check failed! ResourceId = %1!u!.\n",
ResourceId );
return;
}
#ifdef LOG_VERBOSE
(g_LogEvent)(
resourceEntry->ResourceHandle,
LOG_INFORMATION,
L"Terminate request.\n" );
#endif
ClusWorkerTerminate( &resourceEntry->PendingThread );
//
// Terminate the resource.
//
SmbShareDoTerminate( resourceEntry, NULL);
} // SmbShareTerminate
DWORD
WINAPI
SmbShareOffline(
IN RESID ResourceId
)
/*++
Routine Description:
Offline routine for File Share resource.
Arguments:
ResourceId - Supplies the resource it to be taken offline
Return Value:
ERROR_SUCCESS - The request completed successfully and the resource is
offline.
ERROR_RESOURCE_NOT_FOUND - RESID is not valid.
--*/
{
DWORD status;
PSHARE_RESOURCE resourceEntry;
resourceEntry = (PSHARE_RESOURCE)ResourceId;
if ( resourceEntry == NULL ) {
DBG_PRINT( "SmbShare: Offline request for a nonexistent resource id 0x%p\n",
ResourceId );
return(ERROR_RESOURCE_NOT_FOUND);
}
if ( resourceEntry->ResId != ResourceId ) {
(g_LogEvent)(
resourceEntry->ResourceHandle,
LOG_ERROR,
L"Offline resource sanity check failed! ResourceId = %1!u!.\n",
ResourceId );
return(ERROR_RESOURCE_NOT_FOUND);
}
#ifdef LOG_VERBOSE
(g_LogEvent)(
resourceEntry->ResourceHandle,
LOG_INFORMATION,
L"Offline request.\n" );
#endif
//
// Terminate the resource.
//
// ClusWorkerTerminate( &resourceEntry->OfflineThread );
status = ClusWorkerCreate( &resourceEntry->PendingThread,
SmbShareOfflineThread,
resourceEntry );
if ( status != ERROR_SUCCESS ) {
resourceEntry->State = ClusterResourceFailed;
(g_LogEvent)(
resourceEntry->ResourceHandle,
LOG_ERROR,
L"Offline: Unable to start thread, status %1!u!.\n",
status
);
} else {
status = ERROR_IO_PENDING;
}
return status;
} // SmbShareOffline
BOOL
SmbShareCheckIsAlive(
IN PSHARE_RESOURCE ResourceEntry,
IN BOOL IsAliveCheck
)
/*++
Routine Description:
Check to see if the resource is alive for File Share resources.
Arguments:
ResourceEntry - Supplies the resource entry for the resource to polled.
Return Value:
TRUE - Resource is alive and well
FALSE - Resource is toast.
--*/
{
DWORD status;
BOOL success = TRUE;
PSHARE_INFO_502 shareInfo;
WCHAR szErrorString[12];
EnterCriticalSection( &SmbShareLock );
//
// Determine if the resource is online.
//
status = NetShareGetInfo( NULL,
ResourceEntry->Params.ShareName,
502, // return a SHARE_INFO_502 structure
(LPBYTE *) &shareInfo );
if ( status == NERR_NetNameNotFound ) {
ClusResLogSystemEventByKey(ResourceEntry->ResourceKey,
LOG_CRITICAL,
RES_SMB_SHARE_NOT_FOUND);
(g_LogEvent)(
ResourceEntry->ResourceHandle,
LOG_ERROR,
L"NERR_NetNameNotFound :share '%1!ws!' no longer exists.\n",
ResourceEntry->Params.ShareName );
success = FALSE;
} else if ( status != ERROR_SUCCESS ) {
( void ) StringCchPrintf ( szErrorString, RTL_NUMBER_OF ( szErrorString ), L"%u", status);
ClusResLogSystemEventByKeyData1(ResourceEntry->ResourceKey,
LOG_CRITICAL,
RES_SMB_SHARE_FAILED,
sizeof(status),
&status,
szErrorString);
(g_LogEvent)(
ResourceEntry->ResourceHandle,
LOG_ERROR,
L"Error checking for share. Error %1!u!.\n",
status );
success = FALSE;
}
LeaveCriticalSection( &SmbShareLock );
if ( success ) {
NetApiBufferFree( shareInfo );
if ( IsAliveCheck ) {
HANDLE fileHandle;
WIN32_FIND_DATA fileData;
WCHAR shareName[MAX_COMPUTERNAME_LENGTH + NNLEN + SMBSHARE_EXTRA_LEN];
DWORD dwLoopCnt = 0;
( void ) StringCchPrintf( shareName,
RTL_NUMBER_OF ( shareName ),
L"\\\\%ws\\%ws\\*.*\0",
ResourceEntry->ComputerName,
ResourceEntry->Params.ShareName );
fileHandle = FindFirstFileW( shareName,
&fileData );
//
// If we fail on the first attempt, try again. There seems to be a
// bug in the RDR where the first attempt to read a share after it
// has been deleted and reinstated. The bug is that the RDR
// returns failure on the first operation following the
// reinstatement of the share.
//
if ( fileHandle == INVALID_HANDLE_VALUE ) {
fileHandle = FindFirstFileW( shareName,
&fileData );
}
//
// If we succeeded in finding a file, or there were no files in the
// path, then return success, otherwise we had a failure.
//
status = GetLastError();
//
// Chittur Subbaraman (chitturs) - 12/6/1999
//
// If FindFirstFile returns ERROR_NETNAME_DELETED, it
// could possibly because the netname resource deletes
// all loopback sessions during the offline process. So,
// sleep and retry the call.
//
while( ( fileHandle == INVALID_HANDLE_VALUE ) &&
( status == ERROR_NETNAME_DELETED ) &&
( dwLoopCnt++ < 3 ) ) {
Sleep( 50 );
(g_LogEvent)(
ResourceEntry->ResourceHandle,
LOG_INFORMATION,
L"Retrying FindFirstFile on error %1!u! for share %2!ws! !\n",
status,
shareName);
fileHandle = FindFirstFileW( shareName,
&fileData );
status = GetLastError();
}
if ( (fileHandle == INVALID_HANDLE_VALUE) &&
(status != ERROR_FILE_NOT_FOUND) &&
(status != ERROR_ACCESS_DENIED) ) {
(g_LogEvent)(
ResourceEntry->ResourceHandle,
LOG_ERROR,
L"Share has gone offline, Error=%1!u! !\n",
status);
SetLastError(status);
( void ) StringCchPrintf ( szErrorString, RTL_NUMBER_OF ( szErrorString ), L"%u", status);
ClusResLogSystemEventByKeyData1(ResourceEntry->ResourceKey,
LOG_CRITICAL,
RES_SMB_SHARE_FAILED,
sizeof(status),
&status,
szErrorString);
return(FALSE);
}
FindClose( fileHandle );
}
} else {
SetLastError(status);
}
//
// Chittur Subbaraman (chitturs) - 2/18/99
//
// If this share is a dfs root, check whether the root is still alive
//
if ( success && ResourceEntry->bDfsRootNeedsMonitoring )
{
PDFS_INFO_1 pDfsInfo1 = NULL;
WCHAR szDfsEntryPath[MAX_COMPUTERNAME_LENGTH + NNLEN + SMBSHARE_EXTRA_LEN];
//
// Prepare a path of the form \\VSName\ShareName to pass into DFS API.
//
( void ) StringCchCopy ( szDfsEntryPath, RTL_NUMBER_OF ( szDfsEntryPath ), L"\\\\" );
( void ) StringCchCat ( szDfsEntryPath, RTL_NUMBER_OF ( szDfsEntryPath ), ResourceEntry->szDependentNetworkName );
( void ) StringCchCat ( szDfsEntryPath, RTL_NUMBER_OF ( szDfsEntryPath ), L"\\" );
( void ) StringCchCat ( szDfsEntryPath, RTL_NUMBER_OF ( szDfsEntryPath ), ResourceEntry->Params.ShareName );
//
// Try to see whether the dfs root is alive.
//
status = NetDfsGetInfo( szDfsEntryPath, // Root share
NULL, // Remote server
NULL, // Remote share
1, // Info Level
( LPBYTE * ) &pDfsInfo1 ); // Out buffer
if ( status == NERR_Success )
{
if ( pDfsInfo1 != NULL )
{
NetApiBufferFree( pDfsInfo1 );
}
} else
{
(g_LogEvent)(
ResourceEntry->ResourceHandle,
LOG_ERROR,
L"Status of looks alive check for dfs root is %1!u! !\n",
status);
( void ) StringCchPrintf ( szErrorString, RTL_NUMBER_OF ( szErrorString ), L"%u", status);
ClusResLogSystemEventByKeyData1(ResourceEntry->ResourceKey,
LOG_CRITICAL,
RES_SMB_SHARE_FAILED,
sizeof(status),
&status,
szErrorString);
SetLastError( status );
return( FALSE );
}
if ( IsAliveCheck )
{
//
// Make a thorough check to see whether the root share
// name matches the resource's share name.
//
status = SmbpIsDfsRoot( ResourceEntry, &success );
if ( ( status != ERROR_SUCCESS ) ||
( success == FALSE ) )
{
(g_LogEvent)(
ResourceEntry->ResourceHandle,
LOG_ERROR,
L"Dfs root has been deleted/inaccessible, Error=%1!u! Root existence=%2!u! !\n",
status,
success);
if( status != ERROR_SUCCESS )
{
SetLastError( status );
( void ) StringCchPrintf ( szErrorString, RTL_NUMBER_OF ( szErrorString ), L"%u", status);
ClusResLogSystemEventByKeyData1(ResourceEntry->ResourceKey,
LOG_CRITICAL,
RES_SMB_SHARE_FAILED,
sizeof(status),
&status,
szErrorString);
}
return( FALSE );
}
}
}
return(success);
} // SmbShareCheckIsAlive
BOOL
SmbShareIsAlive(
IN RESID ResourceId
)
/*++
Routine Description:
IsAlive routine for File Share resource. Also creates a
notification thread if any outstanding notifications are
present.
Arguments:
ResourceId - Supplies the resource id to be polled.
Return Value:
TRUE - Resource is alive and well
FALSE - Resource is toast.
--*/
{
PSHARE_RESOURCE resourceEntry;
DWORD status;
resourceEntry = (PSHARE_RESOURCE)ResourceId;
if ( resourceEntry == NULL ) {
DBG_PRINT( "SmbShare: IsAlive request for a nonexistent resource id 0x%p\n",
ResourceId );
return(FALSE);
}
if ( resourceEntry->ResId != ResourceId ) {
(g_LogEvent)(
resourceEntry->ResourceHandle,
LOG_ERROR,
L"IsAlive resource sanity check failed! ResourceId = %1!u!.\n",
ResourceId );
return(FALSE);
}
#ifdef LOG_VERBOSE
(g_LogEvent)(
resourceEntry->ResourceHandle,
LOG_INFORMATION,
L"IsAlive request.\n" );
#endif
if ( ( ( resourceEntry->NotifyWorker ).hThread == NULL )
&& ( resourceEntry->NotifyHandle != INVALID_HANDLE_VALUE ) )
{
//
// Chittur Subbaraman (chitturs) - 09/27/98
//
// No notify thread is active at this time (we don't want to
// deal with concurrency issues with multiple notify threads
// running concurrently since we decided to anyway use the
// rather slow approach of checking for and acting upon
// notifications within this function which may not be called
// frequently)
//
status = WaitForSingleObject( resourceEntry->NotifyHandle, 0 );
if ( status == WAIT_OBJECT_0 )
{
FindNextChangeNotification( resourceEntry->NotifyHandle );
(g_LogEvent)(
resourceEntry->ResourceHandle,
LOG_INFORMATION,
L"SmbShareIsAlive: Directory change notification received!!!\n"
);
status = ClusWorkerCreate(
&resourceEntry->NotifyWorker,
SmbpShareNotifyThread,
resourceEntry
);
if (status != ERROR_SUCCESS)
{
(g_LogEvent)(
resourceEntry->ResourceHandle,
LOG_ERROR,
L"SmbShareIsAlive: Unable to start thread for monitoring subdir creations/deletions ! ResourceId = %1!u!.\n",
resourceEntry->ResId);
}
}
}
//
// Determine if the resource is online.
//
return(SmbShareCheckIsAlive( resourceEntry, TRUE ));
} // SmbShareIsAlive
BOOL
WINAPI
SmbShareLooksAlive(
IN RESID ResourceId
)
/*++
Routine Description:
LooksAlive routine for File Share resource.
Arguments:
ResourceId - Supplies the resource id to be polled.
Return Value:
TRUE - Resource looks like it is alive and well
FALSE - Resource looks like it is toast.
--*/
{
PSHARE_RESOURCE resourceEntry;
resourceEntry = (PSHARE_RESOURCE)ResourceId;
if ( resourceEntry == NULL ) {
DBG_PRINT( "SmbShare: LooksAlive request for a nonexistent resource id 0x%p\n",
ResourceId );
return(FALSE);
}
if ( resourceEntry->ResId != ResourceId ) {
(g_LogEvent)(
resourceEntry->ResourceHandle,
LOG_ERROR,
L"LooksAlive resource sanity check failed! ResourceId = %1!u!.\n",
ResourceId );
return(FALSE);
}
#ifdef LOG_VERBOSE
(g_LogEvent)(
resourceEntry->ResourceHandle,
LOG_INFORMATION,
L"LooksAlive request.\n" );
#endif
//
// Determine if the resource is online.
//
return(SmbShareCheckIsAlive( resourceEntry, FALSE ));
} // SmbShareLooksAlive
VOID
WINAPI
SmbShareClose(
IN RESID ResourceId
)
/*++
Routine Description:
Close routine for File Share resource.
Arguments:
ResourceId - Supplies resource id to be closed
Return Value:
None.
--*/
{
PSHARE_RESOURCE resourceEntry;
resourceEntry = (PSHARE_RESOURCE)ResourceId;
if ( resourceEntry == NULL ) {
DBG_PRINT( "SmbShare: Close request for a nonexistent resource id 0x%p\n",
ResourceId );
return;
}
if ( resourceEntry->ResId != ResourceId ) {
(g_LogEvent)(
resourceEntry->ResourceHandle,
LOG_ERROR,
L"Close resource sanity check failed! ResourceId = %1!u!.\n",
ResourceId );
return;
}
#ifdef LOG_VERBOSE
(g_LogEvent)(
resourceEntry->ResourceHandle,
LOG_INFORMATION,
L"Close request.\n" );
#endif
//
// Chittur Subbaraman (chitturs) - 3/1/99
//
// Attempt to delete the dfs root if necessary
//
if ( resourceEntry->Params.DfsRoot ) {
NetDfsRemoveStdRoot( resourceEntry->ComputerName,
resourceEntry->Params.ShareName,
0 );
}
//
// Close the Parameters key.
//
if ( resourceEntry->ParametersKey ) {
ClusterRegCloseKey( resourceEntry->ParametersKey );
}
if ( resourceEntry->ResourceKey ) {
ClusterRegCloseKey( resourceEntry->ResourceKey );
}
if ( resourceEntry->hResource ) {
CloseClusterResource( resourceEntry->hResource );
}
//
// Deallocate the resource entry.
//
LocalFree( resourceEntry->Params.ShareName );
LocalFree( resourceEntry->Params.Path );
LocalFree( resourceEntry->Params.Remark );
LocalFree( resourceEntry->Params.Security );
LocalFree( resourceEntry->Params.SecurityDescriptor );
LocalFree( resourceEntry );
} // SmbShareClose
DWORD
SmbShareGetRequiredDependencies(
OUT PVOID OutBuffer,
IN DWORD OutBufferSize,
OUT LPDWORD BytesReturned
)
/*++
Routine Description:
Processes the CLUSCTL_RESOURCE_GET_REQUIRED_DEPENDENCIES control function
for resources of type File Share.
Arguments:
OutBuffer - Supplies a pointer to the output buffer to be filled in.
OutBufferSize - Supplies the size, in bytes, of the available space
pointed to by OutBuffer.
BytesReturned - Returns the number of bytes of OutBuffer actually
filled in by the resource. If OutBuffer is too small, BytesReturned
contains the total number of bytes for the operation to succeed.
Return Value:
ERROR_SUCCESS - The function completed successfully.
ERROR_MORE_DATA - The output buffer is too small to return the data.
BytesReturned contains the required size.
Win32 error code - The function failed.
--*/
{
PSMB_DEPEND_SETUP pdepsetup = SmbDependSetup;
PSMB_DEPEND_DATA pdepdata = (PSMB_DEPEND_DATA)OutBuffer;
CLUSPROP_BUFFER_HELPER value;
DWORD status;
*BytesReturned = sizeof(SMB_DEPEND_DATA);
if ( OutBufferSize < sizeof(SMB_DEPEND_DATA) ) {
if ( OutBuffer == NULL ) {
status = ERROR_SUCCESS;
} else {
status = ERROR_MORE_DATA;
}
} else {
ZeroMemory( OutBuffer, sizeof(SMB_DEPEND_DATA) );
while ( pdepsetup->Syntax.dw != 0 ) {
value.pb = (PUCHAR)OutBuffer + pdepsetup->Offset;
value.pValue->Syntax.dw = pdepsetup->Syntax.dw;
value.pValue->cbLength = pdepsetup->Length;
switch ( pdepsetup->Syntax.wFormat ) {
case CLUSPROP_FORMAT_DWORD:
value.pDwordValue->dw = (DWORD)((DWORD_PTR)pdepsetup->Value);
break;
case CLUSPROP_FORMAT_ULARGE_INTEGER:
value.pULargeIntegerValue->li.LowPart =
(DWORD)((DWORD_PTR)pdepsetup->Value);
break;
case CLUSPROP_FORMAT_SZ:
case CLUSPROP_FORMAT_EXPAND_SZ:
case CLUSPROP_FORMAT_MULTI_SZ:
case CLUSPROP_FORMAT_BINARY:
memcpy( value.pBinaryValue->rgb, pdepsetup->Value, pdepsetup->Length );
break;
default:
break;
}
pdepsetup++;
}
pdepdata->endmark.dw = CLUSPROP_SYNTAX_ENDMARK;
status = ERROR_SUCCESS;
}
return(status);
} // SmbShareGetRequiredDependencies
DWORD
DfsShareGetRequiredDependencies(
OUT PVOID OutBuffer,
IN DWORD OutBufferSize,
OUT LPDWORD BytesReturned
)
/*++
Routine Description:
Processes the CLUSCTL_RESOURCE_GET_REQUIRED_DEPENDENCIES control function
for DFS File Share resource.
Arguments:
OutBuffer - Supplies a pointer to the output buffer to be filled in.
OutBufferSize - Supplies the size, in bytes, of the available space
pointed to by OutBuffer.
BytesReturned - Returns the number of bytes of OutBuffer actually
filled in by the resource. If OutBuffer is too small, BytesReturned
contains the total number of bytes for the operation to succeed.
Return Value:
ERROR_SUCCESS - The function completed successfully.
ERROR_MORE_DATA - The output buffer is too small to return the data.
BytesReturned contains the required size.
Win32 error code - The function failed.
--*/
{
PSMB_DEPEND_SETUP pdepsetup = DfsDependSetup;
PDFS_DEPEND_DATA pdepdata = (PDFS_DEPEND_DATA)OutBuffer;
CLUSPROP_BUFFER_HELPER value;
DWORD status;
*BytesReturned = sizeof(DFS_DEPEND_DATA);
if ( OutBufferSize < sizeof(DFS_DEPEND_DATA) ) {
if ( OutBuffer == NULL ) {
status = ERROR_SUCCESS;
} else {
status = ERROR_MORE_DATA;
}
} else {
ZeroMemory( OutBuffer, sizeof(DFS_DEPEND_DATA) );
while ( pdepsetup->Syntax.dw != 0 ) {
value.pb = (PUCHAR)OutBuffer + pdepsetup->Offset;
value.pValue->Syntax.dw = pdepsetup->Syntax.dw;
value.pValue->cbLength = pdepsetup->Length;
switch ( pdepsetup->Syntax.wFormat ) {
case CLUSPROP_FORMAT_DWORD:
value.pDwordValue->dw = (DWORD)((DWORD_PTR)pdepsetup->Value);
break;
case CLUSPROP_FORMAT_ULARGE_INTEGER:
value.pULargeIntegerValue->li.LowPart =
(DWORD)((DWORD_PTR)pdepsetup->Value);
break;
case CLUSPROP_FORMAT_SZ:
case CLUSPROP_FORMAT_EXPAND_SZ:
case CLUSPROP_FORMAT_MULTI_SZ:
case CLUSPROP_FORMAT_BINARY:
memcpy( value.pBinaryValue->rgb, pdepsetup->Value, pdepsetup->Length );
break;
default:
break;
}
pdepsetup++;
}
pdepdata->endmark.dw = CLUSPROP_SYNTAX_ENDMARK;
status = ERROR_SUCCESS;
}
return(status);
} // DfsShareGetRequiredDependencies
DWORD
SmbShareResourceControl(
IN RESID ResourceId,
IN DWORD ControlCode,
IN PVOID InBuffer,
IN DWORD InBufferSize,
OUT PVOID OutBuffer,
IN DWORD OutBufferSize,
OUT LPDWORD BytesReturned
)
/*++
Routine Description:
ResourceControl routine for File Share resources.
Perform the control request specified by ControlCode on the specified
resource.
Arguments:
ResourceId - Supplies the resource id for the specific resource.
ControlCode - Supplies the control code that defines the action
to be performed.
InBuffer - Supplies a pointer to a buffer containing input data.
InBufferSize - Supplies the size, in bytes, of the data pointed
to by InBuffer.
OutBuffer - Supplies a pointer to the output buffer to be filled in.
OutBufferSize - Supplies the size, in bytes, of the available space
pointed to by OutBuffer.
BytesReturned - Returns the number of bytes of OutBuffer actually
filled in by the resource. If OutBuffer is too small, BytesReturned
contains the total number of bytes for the operation to succeed.
Return Value:
ERROR_SUCCESS - The function completed successfully.
ERROR_RESOURCE_NOT_FOUND - RESID is not valid.
ERROR_INVALID_FUNCTION - The requested control code is not supported.
In some cases, this allows the cluster software to perform the work.
Win32 error code - The function failed.
--*/
{
DWORD status;
PSHARE_RESOURCE resourceEntry;
DWORD required;
resourceEntry = (PSHARE_RESOURCE)ResourceId;
if ( resourceEntry == NULL ) {
DBG_PRINT( "SmbShare: ResourceControl request for a nonexistent resource id 0x%p\n",
ResourceId );
return(ERROR_RESOURCE_NOT_FOUND);
}
if ( resourceEntry->ResId != ResourceId ) {
(g_LogEvent)(
resourceEntry->ResourceHandle,
LOG_ERROR,
L"ResourceControl resource sanity check failed! ResourceId = %1!u!.\n",
ResourceId );
return(ERROR_RESOURCE_NOT_FOUND);
}
#ifdef LOG_VERBOSE
(g_LogEvent)(
resourceEntry->ResourceHandle,
LOG_INFORMATION,
L"ResourceControl request.\n" );
#endif
switch ( ControlCode ) {
case CLUSCTL_RESOURCE_UNKNOWN:
*BytesReturned = 0;
status = ERROR_SUCCESS;
break;
case CLUSCTL_RESOURCE_GET_PRIVATE_PROPERTY_FMTS:
status = ResUtilGetPropertyFormats( SmbShareResourcePrivateProperties,
OutBuffer,
OutBufferSize,
BytesReturned,
&required );
if ( status == ERROR_MORE_DATA ) {
*BytesReturned = required;
}
break;
case CLUSCTL_RESOURCE_ENUM_PRIVATE_PROPERTIES:
status = ResUtilEnumProperties( SmbShareResourcePrivateProperties,
OutBuffer,
OutBufferSize,
BytesReturned,
&required );
if ( status == ERROR_MORE_DATA ) {
*BytesReturned = required;
}
break;
case CLUSCTL_RESOURCE_GET_PRIVATE_PROPERTIES:
status = SmbShareGetPrivateResProperties( resourceEntry,
OutBuffer,
OutBufferSize,
BytesReturned );
break;
case CLUSCTL_RESOURCE_VALIDATE_PRIVATE_PROPERTIES:
status = SmbShareValidatePrivateResProperties( resourceEntry,
InBuffer,
InBufferSize,
NULL );
break;
case CLUSCTL_RESOURCE_SET_PRIVATE_PROPERTIES:
status = SmbShareSetPrivateResProperties( resourceEntry,
InBuffer,
InBufferSize );
break;
case CLUSCTL_RESOURCE_GET_REQUIRED_DEPENDENCIES:
if ( resourceEntry->Params.DfsRoot ) {
status = DfsShareGetRequiredDependencies( OutBuffer,
OutBufferSize,
BytesReturned );
} else {
status = SmbShareGetRequiredDependencies( OutBuffer,
OutBufferSize,
BytesReturned );
}
break;
default:
status = ERROR_INVALID_FUNCTION;
break;
}
return(status);
} // SmbShareResourceControl
DWORD
SmbShareResourceTypeControl(
IN LPCWSTR ResourceTypeName,
IN DWORD ControlCode,
IN PVOID InBuffer,
IN DWORD InBufferSize,
OUT PVOID OutBuffer,
IN DWORD OutBufferSize,
OUT LPDWORD BytesReturned
)
/*++
Routine Description:
ResourceTypeControl routine for File Share resources.
Perform the control request specified by ControlCode on the specified
resource type.
Arguments:
ResourceTypeName - Supplies the name of the resource type - not useful!
ControlCode - Supplies the control code that defines the action
to be performed.
InBuffer - Supplies a pointer to a buffer containing input data.
InBufferSize - Supplies the size, in bytes, of the data pointed
to by InBuffer.
OutBuffer - Supplies a pointer to the output buffer to be filled in.
OutBufferSize - Supplies the size, in bytes, of the available space
pointed to by OutBuffer.
BytesReturned - Returns the number of bytes of OutBuffer actually
filled in by the resource. If OutBuffer is too small, BytesReturned
contains the total number of bytes for the operation to succeed.
Return Value:
ERROR_SUCCESS - The function completed successfully.
ERROR_INVALID_FUNCTION - The requested control code is not supported.
In some cases, this allows the cluster software to perform the work.
Win32 error code - The function failed.
--*/
{
DWORD status;
DWORD required;
switch ( ControlCode ) {
case CLUSCTL_RESOURCE_TYPE_UNKNOWN:
*BytesReturned = 0;
status = ERROR_SUCCESS;
break;
case CLUSCTL_RESOURCE_TYPE_GET_PRIVATE_RESOURCE_PROPERTY_FMTS:
status = ResUtilGetPropertyFormats( SmbShareResourcePrivateProperties,
OutBuffer,
OutBufferSize,
BytesReturned,
&required );
if ( status == ERROR_MORE_DATA ) {
*BytesReturned = required;
}
break;
case CLUSCTL_RESOURCE_TYPE_GET_REQUIRED_DEPENDENCIES:
// rodga 2/15/99
// CLUSBUG - how do we present DFS Root dependencies???
status = SmbShareGetRequiredDependencies( OutBuffer,
OutBufferSize,
BytesReturned );
break;
case CLUSCTL_RESOURCE_TYPE_ENUM_PRIVATE_PROPERTIES:
status = ResUtilEnumProperties( SmbShareResourcePrivateProperties,
OutBuffer,
OutBufferSize,
BytesReturned,
&required );
if ( status == ERROR_MORE_DATA ) {
*BytesReturned = required;
}
break;
case CLUSCTL_RESOURCE_TYPE_STARTING_PHASE1:
{
PCLUS_STARTING_PARAMS pStartParams;
pStartParams = ( PCLUS_STARTING_PARAMS ) InBuffer;
status = ERROR_SUCCESS;
//
// If this is a form after the first upgrade, then mark the
// DFS service as needing a recycling in the first online. We
// do this only during form since during a join, the resource
// DLL clusres.dll will get unloaded after the phase1 notification
// is dropped. So, global vars become meaningless.
//
if ( ( pStartParams->bFirst == TRUE ) &&
( pStartParams->bForm == TRUE ) )
{
g_fDfsServiceNeedsRecyling = TRUE;
}
break;
}
case CLUSCTL_RESOURCE_TYPE_STARTING_PHASE2:
{
PCLUS_STARTING_PARAMS pStartParams;
pStartParams = ( PCLUS_STARTING_PARAMS ) InBuffer;
status = ERROR_SUCCESS;
//
// In the first join after an install, mark the dfs service as needing a
// recycle in its first online. This is done in phase 2 notification
// since clusres.dll will not get unloaded after this.
//
if ( ( pStartParams->bFirst == TRUE ) &&
( pStartParams->bForm == FALSE ) )
{
g_fDfsServiceNeedsRecyling = TRUE;
}
break;
}
default:
status = ERROR_INVALID_FUNCTION;
break;
}
return(status);
} // SmbShareResourceTypeControl
DWORD
SmbShareGetPrivateResProperties(
IN OUT PSHARE_RESOURCE ResourceEntry,
OUT PVOID OutBuffer,
IN DWORD OutBufferSize,
OUT LPDWORD BytesReturned
)
/*++
Routine Description:
Processes the CLUSCTL_RESOURCE_GET_PRIVATE_PROPERTIES control function
for resources of type SmbShare.
Arguments:
ResourceEntry - Supplies the resource entry on which to operate.
OutBuffer - Returns the output data.
OutBufferSize - Supplies the size, in bytes, of the data pointed
to by OutBuffer.
BytesReturned - The number of bytes returned in OutBuffer.
Return Value:
ERROR_SUCCESS - The function completed successfully.
ERROR_INVALID_PARAMETER - The data is formatted incorrectly.
ERROR_NOT_ENOUGH_MEMORY - An error occurred allocating memory.
Win32 error code - The function failed.
--*/
{
DWORD status;
DWORD required;
status = ResUtilGetAllProperties( ResourceEntry->ParametersKey,
SmbShareResourcePrivateProperties,
OutBuffer,
OutBufferSize,
BytesReturned,
&required );
if ( status == ERROR_MORE_DATA ) {
*BytesReturned = required;
}
return(status);
} // SmbShareGetPrivateResProperties
DWORD
SMBValidateUniqueProperties(
IN HRESOURCE hSelf,
IN HRESOURCE hResource,
IN PSHARE_ENUM_CONTEXT pContext
)
/*++
Routine Description:
Callback function to validate that a resource's properties are unique.
For the File Share resource the ShareName property must be unique
in the cluster.
Arguments:
hSelf - A handle to the original resource (or NULL).
hResource - A handle to a resource of the same Type. Check against this to make sure
the new properties do not conflict.
pContext - Context for the enumeration.
Return Value:
ERROR_SUCCESS - The function completed successfully, the name is unique
ERROR_DUP_NAME - The name is not unique (i.e., already claimed by another resource)
Win32 error code - The function failed.
--*/
{
DWORD dwStatus = ERROR_SUCCESS;
LPWSTR lpszShareName = NULL;
HKEY hKey = NULL;
HKEY hParamKey = NULL;
//
// If there is no share name and we are not testing a DFS root or we are testing a resource with no path, then
// we can do nothing in this call. Just return.
//
if ( ( !pContext->pParams->ShareName ) &&
( ( !pContext->pParams->DfsRoot ) || ( !pContext->pParams->Path ) ) ) {
return( ERROR_SUCCESS );
}
// Get the share name for hResource
hKey = GetClusterResourceKey( hResource, KEY_READ );
if (!hKey) {
(g_LogEvent)(
pContext->pResourceEntry->ResourceHandle,
LOG_WARNING,
L"SMBValidateUniqueProperties: Failed to get the resource key, was resource deleted ? Error: %1!u!...\n",
GetLastError() );
return( ERROR_SUCCESS );
}
dwStatus = ClusterRegOpenKey( hKey, PARAM_KEYNAME__PARAMETERS, KEY_READ, &hParamKey );
if (dwStatus != ERROR_SUCCESS) {
(g_LogEvent)(
pContext->pResourceEntry->ResourceHandle,
LOG_WARNING,
L"SMBValidateUniqueProperties: Failed to open the cluster registry key for the resource, was resource deleted ? Error: %1!u!...\n",
dwStatus );
dwStatus = ERROR_SUCCESS;
goto error_exit;
}
lpszShareName = ResUtilGetSzValue( hParamKey, PARAM_NAME__SHARENAME );
//
// Check for uniqueness if both share names exist.
//
if ( ( lpszShareName ) &&
( pContext->pParams->ShareName ) &&
( !( lstrcmpiW( lpszShareName, pContext->pParams->ShareName ) ) ) ) {
(g_LogEvent)(
pContext->pResourceEntry->ResourceHandle,
LOG_ERROR,
L"SMBValidateUniqueProperties: Share name '%1' already exists.\n",
pContext->pParams->ShareName );
dwStatus = ERROR_DUP_NAME;
goto error_exit;
}
//
// If this share is set to be a DFS root share make sure there is no other DFS root
// with an overlapping path as this share.
//
if ( ( pContext->pParams->DfsRoot ) && ( pContext->pParams->Path ) )
{
DWORD dwIsDfsRoot = 0;
ResUtilGetDwordValue( hParamKey,
PARAM_NAME__DFSROOT,
&dwIsDfsRoot,
0 );
if ( dwIsDfsRoot == 1 )
{
LPWSTR lpszPath = NULL;
WCHAR cSlash = L'\\';
lpszPath = ResUtilGetSzValue( hParamKey, PARAM_NAME__PATH );
if ( lpszPath != NULL )
{
//
// If the two paths overlap, then return failure. Note that here we make sure
// we do not flag paths such as G:\dfs1 and G:\dfs10 as overlapping, that is why we have
// the checks after the pattern matching.
//
if ( ( lstrcmp( lpszPath, pContext->pParams->Path ) == 0 )
||
( ( wcsstr( lpszPath, pContext->pParams->Path ) != NULL ) &&
( lpszPath[lstrlen(pContext->pParams->Path)] == cSlash ) )
||
( ( ( wcsstr( pContext->pParams->Path, lpszPath ) != NULL ) &&
( pContext->pParams->Path[lstrlen(lpszPath)] == cSlash ) ) ) )
{
dwStatus = ERROR_BAD_PATHNAME;
(g_LogEvent)(
pContext->pResourceEntry->ResourceHandle,
LOG_ERROR,
L"SMBValidateUniqueProperties: Path %1!ws! for existing DFS root %2!ws! conflicts with the specified path %3!ws! for DFS root %4!ws!...\n",
lpszPath,
(lpszShareName == NULL) ? L"NULL":lpszShareName,
pContext->pParams->Path,
(pContext->pParams->ShareName == NULL) ? L"NULL":pContext->pParams->ShareName);
}
LocalFree ( lpszPath );
}
}
}
error_exit:
if (hKey) ClusterRegCloseKey( hKey );
if (hParamKey) ClusterRegCloseKey( hParamKey );
if (lpszShareName) LocalFree( lpszShareName );
return( dwStatus );
} // SMBValidateUniqueProperties
DWORD
SmbShareValidatePrivateResProperties(
IN OUT PSHARE_RESOURCE ResourceEntry,
IN PVOID InBuffer,
IN DWORD InBufferSize,
OUT PSHARE_PARAMS Params
)
/*++
Routine Description:
Processes the CLUSCTL_RESOURCE_VALIDATE_PRIVATE_PROPERTIES control
function for resources of type File Share.
Arguments:
ResourceEntry - Supplies the resource entry on which to operate.
InBuffer - Supplies a pointer to a buffer containing input data.
InBufferSize - Supplies the size, in bytes, of the data pointed
to by InBuffer.
Params - Supplies the parameter block to fill in.
Return Value:
ERROR_SUCCESS - The function completed successfully.
ERROR_INVALID_PARAMETER - The data is formatted incorrectly.
ERROR_NOT_ENOUGH_MEMORY - An error occurred allocating memory.
Win32 error code - The function failed.
--*/
{
DWORD status;
SHARE_PARAMS currentProps;
SHARE_PARAMS newProps;
PSHARE_PARAMS pParams = NULL;
LPWSTR nameOfPropInError;
SHARE_ENUM_CONTEXT enumContext;
//
// Check if there is input data.
//
if ( (InBuffer == NULL) ||
(InBufferSize < sizeof(DWORD)) ) {
return(ERROR_INVALID_DATA);
}
//
// Capture the current set of private properties from the registry.
//
ZeroMemory( &currentProps, sizeof(currentProps) );
status = ResUtilGetPropertiesToParameterBlock(
ResourceEntry->ParametersKey,
SmbShareResourcePrivateProperties,
(LPBYTE) &currentProps,
FALSE, /*CheckForRequiredProperties*/
&nameOfPropInError
);
if ( status != ERROR_SUCCESS ) {
(g_LogEvent)(
ResourceEntry->ResourceHandle,
LOG_ERROR,
L"Unable to read the '%1' property. Error: %2!u!.\n",
(nameOfPropInError == NULL ? L"" : nameOfPropInError),
status );
goto FnExit;
}
//
// Duplicate the resource parameter block.
//
if ( Params == NULL ) {
pParams = &newProps;
} else {
pParams = Params;
}
ZeroMemory( pParams, sizeof(SHARE_PARAMS) );
status = ResUtilDupParameterBlock( (LPBYTE) pParams,
(LPBYTE) &currentProps,
SmbShareResourcePrivateProperties );
if ( status != ERROR_SUCCESS ) {
(g_LogEvent)(
ResourceEntry->ResourceHandle,
LOG_ERROR,
L"Failed to duplicate the parameter block. Error: %1!u!.\n",
status );
return(status);
}
//
// Parse and validate the properties.
//
status = ResUtilVerifyPropertyTable( SmbShareResourcePrivateProperties,
NULL,
TRUE, // Allow unknowns
InBuffer,
InBufferSize,
(LPBYTE) pParams );
if ( status == ERROR_SUCCESS ) {
//
// Validate the path
//
if ( pParams->Path &&
!ResUtilIsPathValid( pParams->Path ) ) {
status = ERROR_INVALID_PARAMETER;
(g_LogEvent)(
ResourceEntry->ResourceHandle,
LOG_ERROR,
L"Invalid path specified ('%1'). Error: %2!u!.\n",
pParams->Path,
status );
goto FnExit;
}
//
// Validate the parameter values.
//
if ( (pParams->SecurityDescriptorSize != 0) &&
!IsValidSecurityDescriptor(pParams->SecurityDescriptor) ) {
status = ERROR_INVALID_PARAMETER;
(g_LogEvent)(
ResourceEntry->ResourceHandle,
LOG_ERROR,
L"Invalid parameter specified ('SecurityDescriptor'). Error: %1!u!.\n",
status );
goto FnExit;
}
if ( (pParams->SecuritySize != 0) &&
!IsValidSecurityDescriptor(pParams->Security) ) {
status = ERROR_INVALID_PARAMETER;
(g_LogEvent)(
ResourceEntry->ResourceHandle,
LOG_ERROR,
L"Invalid parameter specified ('Security'). Error: %1!u!.\n",
status );
goto FnExit;
}
if ( pParams->MaxUsers == 0 ) {
(g_LogEvent)(
ResourceEntry->ResourceHandle,
LOG_ERROR,
L"Invalid value for MaxUsers specified (%1!u!).\n",
pParams->MaxUsers );
status = ERROR_INVALID_PARAMETER;
goto FnExit;
}
//
// Make sure the share name is unique
//
enumContext.pResourceEntry = ResourceEntry;
enumContext.pParams = pParams;
status = ResUtilEnumResources(ResourceEntry->hResource,
CLUS_RESTYPE_NAME_FILESHR,
SMBValidateUniqueProperties,
&enumContext);
if (status != ERROR_SUCCESS) {
(g_LogEvent)(
ResourceEntry->ResourceHandle,
LOG_ERROR,
L"SmbShareValidatePrivateResProperties: ResUtilEnumResources failed with status=%1!u!...\n",
status);
goto FnExit;
}
//
// Verify that the share name is valid if one is supplied.
//
if ( pParams->ShareName )
{
status = SmbpValidateShareName( pParams->ShareName );
if (status != ERROR_SUCCESS) {
(g_LogEvent)(
ResourceEntry->ResourceHandle,
LOG_ERROR,
L"SmbShareValidatePrivateResProperties: Share name %1!ws! contains illegal chars, Status=%2!u!...\n",
pParams->ShareName,
status);
goto FnExit;
}
}
//
// Verify that the path is valid if one is supplied.
//
if ( pParams->Path )
{
//
// Verify that the directory exists.
//
if ( !ClRtlPathFileExists( pParams->Path ) ) {
status = ERROR_PATH_NOT_FOUND;
goto FnExit;
}
}
//
// If this share needs to be a DFS root, then make sure the path is on an NTFS volume.
//
if ( ( pParams->DfsRoot ) && ( pParams->Path ) )
{
WCHAR szRootPathName[4];
WCHAR szFileSystem[32]; // Array size stolen from CLUSPROP_PARTITION_INFO
//
// Copy just the drive letter from the supplied path.
//
( void ) StringCchCopy ( szRootPathName, RTL_NUMBER_OF ( szRootPathName ), pParams->Path );
szRootPathName[2] = L'\\';
szRootPathName[3] = L'\0';
if ( !GetVolumeInformationW( szRootPathName,
NULL, // Volume name buffer
0, // Volume name buffer size
NULL, // Volume serial number
NULL, // Maximum component length
NULL, // File system flags
szFileSystem, // File system name
sizeof(szFileSystem)/sizeof(WCHAR) ) )
{
status = GetLastError();
(g_LogEvent)(
ResourceEntry->ResourceHandle,
LOG_ERROR,
L"SmbShareValidatePrivateResProperties: GetVolumeInformation on root path %1!ws! for share %2!ws! failed, Status %3!u!...\n",
szRootPathName,
( pParams->ShareName == NULL ) ? L"NULL":pParams->ShareName,
status );
goto FnExit;
}
if ( lstrcmpi( szFileSystem, L"NTFS" ) != 0 )
{
status = ERROR_BAD_PATHNAME;
(g_LogEvent)(
ResourceEntry->ResourceHandle,
LOG_ERROR,
L"SmbShareValidatePrivateResProperties: Root path %1!ws! for share %2!ws! is not NTFS, Status %3!u!...\n",
szRootPathName,
( pParams->ShareName == NULL ) ? L"NULL":pParams->ShareName,
status );
goto FnExit;
}
}
} else {
(g_LogEvent)(
ResourceEntry->ResourceHandle,
LOG_ERROR,
L"Validating properties failed. Error: %1!u!.\n",
status );
}
FnExit:
//
// Cleanup our parameter block.
//
if ( ( (status != ERROR_SUCCESS)
&& (pParams != NULL) )
|| ( pParams == &newProps )
) {
ResUtilFreeParameterBlock( (LPBYTE) pParams,
(LPBYTE) &currentProps,
SmbShareResourcePrivateProperties );
}
ResUtilFreeParameterBlock(
(LPBYTE) &currentProps,
NULL,
SmbShareResourcePrivateProperties
);
return(status);
} // SmbShareValidatePrivateResProperties
DWORD
SmbShareSetPrivateResProperties(
IN OUT PSHARE_RESOURCE ResourceEntry,
IN PVOID InBuffer,
IN DWORD InBufferSize
)
/*++
Routine Description:
Processes the CLUSCTL_RESOURCE_SET_PRIVATE_PROPERTIES control function
for resources of type File Share.
Arguments:
ResourceEntry - Supplies the resource entry on which to operate.
InBuffer - Supplies a pointer to a buffer containing input data.
InBufferSize - Supplies the size, in bytes, of the data pointed
to by InBuffer.
Return Value:
ERROR_SUCCESS - The function completed successfully.
ERROR_INVALID_PARAMETER - The data is formatted incorrectly.
ERROR_NOT_ENOUGH_MEMORY - An error occurred allocating memory.
Win32 error code - The function failed.
Notes:
If the share name changes then we must delete the old share and
create a new one. Otherwise, just set the new info.
--*/
{
DWORD status;
SHARE_PARAMS params;
LPWSTR oldName = NULL;
BOOL bNameSubdirPropChange = FALSE;
BOOL bPathChanged = FALSE;
BOOL bFoundSecurity = FALSE;
BOOL bFoundSD = FALSE;
PSECURITY_DESCRIPTOR psd = NULL;
DWORD SDSize = 0;
DWORD securitySize = 0;
BOOL bChangeDfsRootProp = FALSE, bShareNameChangeAttempted = FALSE;
ZeroMemory( &params, sizeof(SHARE_PARAMS) );
//
// Parse the properties so they can be validated together.
// This routine does individual property validation.
//
status = SmbShareValidatePrivateResProperties( ResourceEntry,
InBuffer,
InBufferSize,
&params );
if ( status != ERROR_SUCCESS ) {
return(status);
}
//
// fixup the Security and Security Descriptor properties to match
//
bFoundSecurity = ( ERROR_SUCCESS == ResUtilFindBinaryProperty( InBuffer,
InBufferSize,
PARAM_NAME__SECURITY,
NULL,
&securitySize ) );
if ( bFoundSecurity && (securitySize == 0) ) {
//
// The security string could have been passed in, but it may be
// a zero length buffer. We will delete the buffer and indicate it
// is not present in that case.
//
bFoundSecurity = FALSE;
FREE_SECURITY_INFO();
}
bFoundSD =( ERROR_SUCCESS == ResUtilFindBinaryProperty( InBuffer,
InBufferSize,
PARAM_NAME__SD,
NULL,
&SDSize ) );
if ( bFoundSD && (SDSize == 0) ) {
//
// The security string could have been passed in, but it may be
// a zero length buffer. We will delete the buffer and indicate it
// is not present in that case.
//
bFoundSD = FALSE;
FREE_SECURITY_INFO();
}
if ( bFoundSD ) { // prefer SD, convert SD to Security
psd = ClRtlConvertFileShareSDToNT4Format( params.SecurityDescriptor );
//
// Bail on error
//
if ( psd == NULL ) {
status = GetLastError();
(g_LogEvent)(ResourceEntry->ResourceHandle,
LOG_ERROR,
L"Unable to convert SD to NT4 format, status %1!u!\n",
status);
ResUtilFreeParameterBlock( ( LPBYTE ) &params,
( LPBYTE ) &ResourceEntry->Params,
SmbShareResourcePrivateProperties );
goto FnExit;
}
LocalFree( params.Security );
params.Security = psd;
params.SecuritySize = GetSecurityDescriptorLength( psd );
//
// if the ACL has changed, dump it to the cluster log
//
if ( SDSize == ResourceEntry->Params.SecurityDescriptorSize ) {
if ( memcmp(params.SecurityDescriptor,
ResourceEntry->Params.SecurityDescriptor,
SDSize ) != 0 )
{
(g_LogEvent)(ResourceEntry->ResourceHandle,
LOG_INFORMATION,
L"Changing share permissions\n");
SmbExamineSD( ResourceEntry->ResourceHandle, params.SecurityDescriptor );
}
}
}
else if ( bFoundSecurity ) { // simply write Security to SD
psd = ClRtlCopySecurityDescriptor( params.Security );
//
// Bail on error
//
if ( psd == NULL ) {
status = GetLastError();
(g_LogEvent)(ResourceEntry->ResourceHandle,
LOG_ERROR,
L"Unable to copy SD, status %1!u!\n",
status);
ResUtilFreeParameterBlock( ( LPBYTE ) &params,
( LPBYTE ) &ResourceEntry->Params,
SmbShareResourcePrivateProperties );
goto FnExit;
}
LocalFree( params.SecurityDescriptor );
params.SecurityDescriptor = psd;
params.SecurityDescriptorSize = GetSecurityDescriptorLength( psd );
//
// if the ACL has changed, dump it to the cluster log
//
if ( securitySize == ResourceEntry->Params.SecuritySize ) {
if ( memcmp(params.Security,
ResourceEntry->Params.Security,
securitySize ) != 0 )
{
(g_LogEvent)(ResourceEntry->ResourceHandle,
LOG_INFORMATION,
L"Changing share permissions\n");
SmbExamineSD( ResourceEntry->ResourceHandle, params.Security );
}
}
}
//
// Duplicate the share name if it changed.
// Do this even if only the case of the share name changed.
//
if ( ( ResourceEntry->Params.ShareName != NULL ) &&
( lstrcmpW( params.ShareName, ResourceEntry->Params.ShareName ) != 0 ) ) {
bShareNameChangeAttempted = TRUE;
if ( ResourceEntry->State == ClusterResourceOnline ) {
oldName = ResUtilDupString( ResourceEntry->Params.ShareName );
bNameSubdirPropChange = TRUE;
}
} else {
oldName = ResourceEntry->Params.ShareName;
}
if ( (params.HideSubDirShares != ResourceEntry->Params.HideSubDirShares) ||
(params.ShareSubDirs != ResourceEntry->Params.ShareSubDirs) ||
(params.ShareSubDirs && lstrcmpW (params.Path, ResourceEntry->Params.Path)) ) {
bNameSubdirPropChange = TRUE;
}
//
// Find out if the path changed.
//
if ( (ResourceEntry->Params.Path != NULL) &&
(lstrcmpW( params.Path, ResourceEntry->Params.Path ) != 0) ) {
bPathChanged = TRUE;
}
//
// Chittur Subbaraman (chitturs) - 2/9/99
//
// Don't welcome any changes if you are dealing with a dfs root. Also
// make sure "DfsRoot" is mutually exclusive with "ShareSubDirs"
// and "HideSubDirShares" properties.
//
if ( ( ( ResourceEntry->Params.DfsRoot ) &&
( bNameSubdirPropChange || bPathChanged || bShareNameChangeAttempted ) ) ||
( ( params.DfsRoot ) &&
( params.ShareSubDirs || params.HideSubDirShares ) ) )
{
status = ERROR_RESOURCE_PROPERTY_UNCHANGEABLE;
ResUtilFreeParameterBlock( (LPBYTE) &params,
(LPBYTE) &ResourceEntry->Params,
SmbShareResourcePrivateProperties );
goto FnExit;
}
if ( params.DfsRoot && !ResourceEntry->Params.DfsRoot )
{
BOOL fIsDfsRoot = FALSE;
//
// Check if this node has a DFS root already with the same root share name. If so,
// don't allow this resource to be promoted as a DFS resource.
//
SmbpIsDfsRoot( ResourceEntry, &fIsDfsRoot );
if( fIsDfsRoot == TRUE )
{
status = ERROR_CLUSTER_NODE_ALREADY_HAS_DFS_ROOT;
ResUtilFreeParameterBlock( (LPBYTE) &params,
(LPBYTE) &ResourceEntry->Params,
SmbShareResourcePrivateProperties );
goto FnExit;
}
}
if ( ResourceEntry->Params.DfsRoot != params.DfsRoot ) {
bChangeDfsRootProp = TRUE;
}
//
// Save the parameter values.
//
status = ResUtilSetPropertyParameterBlock( ResourceEntry->ParametersKey,
SmbShareResourcePrivateProperties,
NULL,
(LPBYTE) &params,
InBuffer,
InBufferSize,
(LPBYTE) &ResourceEntry->Params );
ResUtilFreeParameterBlock( (LPBYTE) &params,
(LPBYTE) &ResourceEntry->Params,
SmbShareResourcePrivateProperties );
//
// If the resource is online, set the new values. If online pending,
// we must wait until the user brings it online again.
//
if ( status == ERROR_SUCCESS ) {
if ( (ResourceEntry->State == ClusterResourceOnline) && !bNameSubdirPropChange && !bPathChanged ) {
PSHARE_INFO_502 oldShareInfo;
SHARE_INFO_502 newShareInfo;
EnterCriticalSection( &SmbShareLock );
// Get current information.
status = NetShareGetInfo( NULL,
oldName,
502,
(LPBYTE*)&oldShareInfo );
if ( status == ERROR_SUCCESS ) {
DWORD invalidParam;
//
// Set new share info.
//
CopyMemory( &newShareInfo, oldShareInfo, sizeof( newShareInfo ) );
newShareInfo.shi502_netname = ResourceEntry->Params.ShareName;
newShareInfo.shi502_remark = ResourceEntry->Params.Remark;
newShareInfo.shi502_max_uses = ResourceEntry->Params.MaxUsers;
newShareInfo.shi502_path = ResourceEntry->Params.Path;
newShareInfo.shi502_security_descriptor = ResourceEntry->Params.SecurityDescriptor;
//
// Set new info.
//
status = NetShareSetInfo( NULL,
oldName,
502,
(LPBYTE)&newShareInfo,
&invalidParam );
if ( status != ERROR_SUCCESS ) {
(g_LogEvent)(
ResourceEntry->ResourceHandle,
LOG_ERROR,
L"SetPrivateProps, error setting info on share '%1!ws!. Error %2!u!, property # %3!d!.\n",
oldName,
status,
invalidParam );
status = ERROR_RESOURCE_PROPERTIES_STORED;
}
NetApiBufferFree( oldShareInfo );
if ( (status == ERROR_SUCCESS) ||
(status == ERROR_RESOURCE_PROPERTIES_STORED) ) {
status = SmbpSetCacheFlags( ResourceEntry,
ResourceEntry->Params.ShareName );
if ( status != ERROR_SUCCESS ) {
status = ERROR_RESOURCE_PROPERTIES_STORED;
}
}
} else {
(g_LogEvent)(
ResourceEntry->ResourceHandle,
LOG_ERROR,
L"SetPrivateProps, error getting info on share '%1!ws!. Error %2!u!.\n",
oldName,
status );
status = ERROR_RESOURCE_PROPERTIES_STORED;
}
LeaveCriticalSection( &SmbShareLock );
} else if ( (ResourceEntry->State == ClusterResourceOnlinePending) ||
(ResourceEntry->State == ClusterResourceOnline) ) {
status = ERROR_RESOURCE_PROPERTIES_STORED;
}
}
FnExit:
if ( oldName != ResourceEntry->Params.ShareName ) {
LocalFree( oldName );
}
if ( ( status == ERROR_SUCCESS ) && bChangeDfsRootProp ) {
if ( (ResourceEntry->State == ClusterResourceOnlinePending) ||
(ResourceEntry->State == ClusterResourceOnline) ) {
status = ERROR_RESOURCE_PROPERTIES_STORED;
}
}
return(status);
} // SmbShareSetPrivateResProperties
DWORD
SmbpHandleDfsRoot(
IN PSHARE_RESOURCE pResourceEntry,
OUT PBOOL pbIsExistingDfsRoot
)
/*++
Routine Description:
Handles an smbshare which is configured as a DFS root.
Arguments:
pResourceEntry - Supplies the pointer to the resource block
pbIsExistingDfsRoot - Specifies whether the dfs root is a wolfpack resource
Return Value:
None.
--*/
{
DWORD dwStatus = ERROR_SUCCESS;
DWORD dwSize = MAX_COMPUTERNAME_LENGTH + 1;
BOOL fStatus;
LPWSTR lpszDfsRootCheckpointName = NULL;
//
// Recycle the DFS service if this is the first online after an install. This must be
// done before calling GetDfsRootMetadataLocation since in a W2K-Windows Server 2003 cluster on the first
// failover from W2K to Windows Server 2003, the DFS service needs to migrate the W2K root to Windows Server
// 2003 location and that happens during a restart. Only after that migration, the GetDfsRootMetadataLocation
// will find the right data in the Windows Server 2003 location.
//
//
if ( pResourceEntry->Params.DfsRoot )
{
dwStatus = SmbpRecycleDfsService( pResourceEntry );
if ( dwStatus != ERROR_SUCCESS )
{
(g_LogEvent)(
pResourceEntry->ResourceHandle,
LOG_ERROR,
L"SmbpHandleDfsRoot: Unable to recycle DFS service for root %1!ws!, status %2!u!\n",
pResourceEntry->Params.ShareName,
dwStatus);
goto FnExit;
}
}
//
// Check whether this resource represents an existing dfs root. Note that you cannot use
// SmbpIsDfsRoot here since that function only assuredly returns roots that are MASTER
// in this node. Those roots that are STANDBY may fail to come out of NetDfsEnum if a
// checkpoint restore is in progress at the time we invoke the enum.
//
// This is a private API provided by UDAYH of DFS team on 4/26/2001.
//
dwStatus = GetDfsRootMetadataLocation( pResourceEntry->Params.ShareName,
&lpszDfsRootCheckpointName );
if ( dwStatus == ERROR_NOT_FOUND )
{
*pbIsExistingDfsRoot = FALSE;
//
// Change status to success so that you return the right status from this function if
// you happen to bail out early.
//
dwStatus = ERROR_SUCCESS;
(g_LogEvent)(
pResourceEntry->ResourceHandle,
LOG_INFORMATION,
L"SmbpHandleDfsRoot: DFS root %1!ws! NOT found in local node...\n",
pResourceEntry->Params.ShareName);
} else if ( dwStatus == ERROR_SUCCESS )
{
*pbIsExistingDfsRoot = TRUE;
(g_LogEvent)(
pResourceEntry->ResourceHandle,
LOG_INFORMATION,
L"SmbpHandleDfsRoot: DFS root %1!ws! found in local node...\n",
pResourceEntry->Params.ShareName);
} else
{
(g_LogEvent)(
pResourceEntry->ResourceHandle,
LOG_ERROR,
L"SmbpHandleDfsRoot: GetDfsRootMetadataLocation(1) for DFS root '%1!ws!' returns %2!u!...\n",
pResourceEntry->Params.ShareName,
dwStatus);
goto FnExit;
}
//
// If there is a DFS root on this node that matches the share name of this resource or if
// the user is attempting to set up a DFS root, then get the VS name that provides for
// this resource so that we can pass it onto DFS APIs.
//
if ( ( pResourceEntry->Params.DfsRoot ) ||
( *pbIsExistingDfsRoot == TRUE ) )
{
//
// Get the dependent network name of the dfs root resource. You need to do this in
// every online to account for the dependency change while this resource was offline.
//
fStatus = GetClusterResourceNetworkName( pResourceEntry->hResource,
pResourceEntry->szDependentNetworkName,
&dwSize );
if ( !fStatus )
{
dwStatus = GetLastError();
(g_LogEvent)(
pResourceEntry->ResourceHandle,
LOG_ERROR,
L"SmbpHandleDfsRoot: GetClusterResourceNetworkName for share %1!ws! returns %2!u!...\n",
pResourceEntry->Params.ShareName,
dwStatus);
goto FnExit;
}
(g_LogEvent)(
pResourceEntry->ResourceHandle,
LOG_INFORMATION,
L"SmbpHandleDfsRoot: DFS root share %1!ws! has a provider VS name of %2!ws!...\n",
pResourceEntry->Params.ShareName,
pResourceEntry->szDependentNetworkName);
//
// HACKHACK: Chittur Subbaraman (chitturs) - 5/18/2001
//
// Sleep for few secs to mask an issue with the dependent netname not being really usable
// (especially as binding parameter to named pipes done by the DFS APIs we call below) after
// it declares itself to be online. This is due to the fact that netname NBT
// registrations are apparently async and it takes a while for that to percolate to other
// drivers such as SRV.
//
Sleep ( 4 * 1000 );
}
if ( !pResourceEntry->Params.DfsRoot )
{
if ( *pbIsExistingDfsRoot )
{
//
// This means the user no longer wants the share to be a
// DFS root. Delete the registry checkpoints and the
// corresponding DFS root.
//
dwStatus = SmbpDeleteDfsRoot( pResourceEntry );
if ( dwStatus != ERROR_SUCCESS )
{
(g_LogEvent)(
pResourceEntry->ResourceHandle,
LOG_ERROR,
L"SmbpHandleDfsRoot: Failed to delete DFS root for share %1!ws!, status %2!u!...\n",
pResourceEntry->Params.ShareName,
dwStatus);
goto FnExit;
}
*pbIsExistingDfsRoot = FALSE;
}
pResourceEntry->bDfsRootNeedsMonitoring = FALSE;
goto FnExit;
}
//
// If there is no DFS root with the same rootshare name
// as this resource, attempt to create the dfs root. However, the
// user could have mistakenly created a dfs root with a different
// share name. In such a case, the following create call will fail.
//
if ( !( *pbIsExistingDfsRoot ) )
{
dwStatus = SmbpCreateDfsRoot( pResourceEntry );
if ( dwStatus != ERROR_SUCCESS )
{
(g_LogEvent)(
pResourceEntry->ResourceHandle,
LOG_ERROR,
L"SmbpHandleDfsRoot: Create dfs root for share %1!ws! returns %2!u!...\n",
pResourceEntry->Params.ShareName,
dwStatus);
if ( dwStatus == ERROR_FILE_EXISTS )
{
dwStatus = ERROR_CLUSTER_NODE_ALREADY_HAS_DFS_ROOT;
}
ClusResLogSystemEventByKeyData( pResourceEntry->ResourceKey,
LOG_CRITICAL,
RES_SMB_CANT_CREATE_DFS_ROOT,
sizeof( dwStatus ),
&dwStatus );
goto FnExit;
}
(g_LogEvent)(
pResourceEntry->ResourceHandle,
LOG_INFORMATION,
L"SmbpHandleDfsRoot: Create dfs root for share %1!ws!\n",
pResourceEntry->Params.ShareName);
*pbIsExistingDfsRoot = TRUE;
}
if ( lpszDfsRootCheckpointName == NULL )
{
dwStatus = GetDfsRootMetadataLocation( pResourceEntry->Params.ShareName,
&lpszDfsRootCheckpointName );
if ( dwStatus != ERROR_SUCCESS )
{
(g_LogEvent)(
pResourceEntry->ResourceHandle,
LOG_ERROR,
L"SmbpHandleDfsRoot: GetDfsRootMetadataLocation(2) for dfs root %1!ws!, status %2!u!...\n",
pResourceEntry->Params.ShareName,
dwStatus);
goto FnExit;
}
}
(g_LogEvent)(
pResourceEntry->ResourceHandle,
LOG_INFORMATION,
L"SmbpHandleDfsRoot: Dfs root %1!ws! metadata location from DFS API is %2!ws!...\n",
pResourceEntry->Params.ShareName,
lpszDfsRootCheckpointName);
dwStatus = ClusterResourceControl(
pResourceEntry->hResource,
NULL,
CLUSCTL_RESOURCE_ADD_REGISTRY_CHECKPOINT,
lpszDfsRootCheckpointName,
(lstrlenW(lpszDfsRootCheckpointName) + 1) * sizeof(WCHAR),
NULL,
0,
&dwSize );
if ( dwStatus != ERROR_SUCCESS )
{
if ( dwStatus == ERROR_ALREADY_EXISTS )
{
dwStatus = ERROR_SUCCESS;
}
else
{
(g_LogEvent)(
pResourceEntry->ResourceHandle,
LOG_ERROR,
L"SmbpHandleDfsRoot: Failed to set registry checkpoint %1!ws! for share %2!ws!, status %3!u!...\n",
lpszDfsRootCheckpointName,
pResourceEntry->Params.ShareName,
dwStatus);
}
}
pResourceEntry->bDfsRootNeedsMonitoring = TRUE;
FnExit:
//
// Free memory for the checkpoint name buffer for this DFS root resource. This is a private API provided
// by UDAYH of DFS team on 4/26/2001.
//
if ( lpszDfsRootCheckpointName != NULL )
ReleaseDfsRootMetadataLocation ( lpszDfsRootCheckpointName );
return( dwStatus );
} // SmbpHandleDfsRoot
DWORD
SmbpIsDfsRoot(
IN PSHARE_RESOURCE pResourceEntry,
OUT PBOOL pbIsDfsRoot
)
/*++
Routine Description:
Checks if this root share is a dfs root.
Arguments:
pResourceEntry - Supplies the pointer to the resource block
pbIsDfsRoot - Specifies whether a dfs root with the same root share
name as this resource exists.
Return Value:
ERROR_SUCCESS or a Win32 error code
--*/
{
DWORD dwStatus = ERROR_SUCCESS;
PDFS_INFO_300 pDfsInfo300 = NULL, pTemp = NULL;
DWORD cEntriesRead = 0;
DWORD dwResume = 0, i;
LPWSTR pLastSlash = NULL;
WCHAR cSlash = L'\\';
//
// Chittur Subbaraman (chitturs) - 4/14/2001
//
*pbIsDfsRoot = FALSE;
//
// Call the NetDfsEnum function specifying level 200.
//
dwStatus = NetDfsEnum( pResourceEntry->ComputerName, // Local computer name
300, // Info level
0xFFFFFFFF, // Return all info
( LPBYTE * ) &pDfsInfo300, // Data buffer
&cEntriesRead, // Entries read
&dwResume ); // Resume handle
if ( dwStatus != ERROR_SUCCESS )
{
//
// If we did not find any root return success
//
if ( dwStatus == ERROR_FILE_NOT_FOUND )
{
dwStatus = ERROR_SUCCESS;
} else
{
(g_LogEvent)(
pResourceEntry->ResourceHandle,
LOG_ERROR,
L"SmbpIsDfsRoot: NetDfsEnum returns %1!u! for root share %2!ws!...\n",
dwStatus,
pResourceEntry->Params.ShareName);
}
goto FnExit;
}
pTemp = pDfsInfo300;
//
// The enumerated roots will be of the form \server\rootname, so you need to check for the
// name after the last \ coming out of the enum.
//
for( i=0; i<cEntriesRead; i++, pTemp++ )
{
pLastSlash = wcsrchr( pTemp->DfsName, cSlash );
if ( pLastSlash == NULL ) continue;
if ( lstrcmp( pResourceEntry->Params.ShareName, pLastSlash+1 ) == 0 )
{
*pbIsDfsRoot = TRUE;
break;
}
} // for
//
// Free the allocated buffer.
//
NetApiBufferFree( pDfsInfo300 );
FnExit:
return( dwStatus );
} // SmbpIsDfsRoot
DWORD
SmbpPrepareOnlineDfsRoot(
IN PSHARE_RESOURCE ResourceEntry
)
/*++
Routine Description:
Prepares the online of the dfs root share.
Arguments:
ResourceEntry - Supplies the pointer to the resource block
Return Value:
ERROR_SUCCESS on success
Win32 error code otherwise
--*/
{
DWORD dwStatus;
DFS_INFO_101 dfsInfo101;
WCHAR szDfsEntryPath[MAX_COMPUTERNAME_LENGTH + NNLEN + SMBSHARE_EXTRA_LEN];
//
// Make sure the DFS service is started. This is necessary since the cluster service does not set
// an explicit dependency on DFS service.
//
dwStatus = ResUtilStartResourceService( DFS_SVCNAME,
NULL );
if ( dwStatus != ERROR_SUCCESS )
{
(g_LogEvent)(
ResourceEntry->ResourceHandle,
LOG_ERROR,
L"SmbpPrepareOnlineDfsRoot: Failed to start DFS service, share name %1!ws!, status %2!u!...\n",
ResourceEntry->Params.ShareName,
dwStatus);
goto FnExit;
}
dfsInfo101.State = DFS_VOLUME_STATE_RESYNCHRONIZE;
//
// Prepare a path of the form \\VSName\ShareName to pass into DFS API.
//
( void ) StringCchCopy ( szDfsEntryPath, RTL_NUMBER_OF ( szDfsEntryPath ), L"\\\\" );
( void ) StringCchCat ( szDfsEntryPath, RTL_NUMBER_OF ( szDfsEntryPath ), ResourceEntry->szDependentNetworkName );
( void ) StringCchCat ( szDfsEntryPath, RTL_NUMBER_OF ( szDfsEntryPath ), L"\\" );
( void ) StringCchCat ( szDfsEntryPath, RTL_NUMBER_OF ( szDfsEntryPath ), ResourceEntry->Params.ShareName );
dwStatus = NetDfsSetInfo( szDfsEntryPath, // Root share
NULL, // Remote server name
NULL, // Remote share name
101, // Info level
( PBYTE ) &dfsInfo101 ); // Input buffer
if ( dwStatus != ERROR_SUCCESS )
{
(g_LogEvent)(
ResourceEntry->ResourceHandle,
LOG_ERROR,
L"SmbpPrepareOnlineDfsRoot: Failed to set DFS info for root %1!ws!, status %2!u!...\n",
ResourceEntry->Params.ShareName,
dwStatus);
ClusResLogSystemEventByKeyData( ResourceEntry->ResourceKey,
LOG_CRITICAL,
RES_SMB_CANT_INIT_DFS_SVC,
sizeof( dwStatus ),
&dwStatus );
goto FnExit;
}
//
// HACKHACK (chitturs) - 5/21/2001
//
// FFF in liveness check returns ERROR_PATH_NOT_FOUND in the first liveness check after
// online. This is due to the fact that the RDR caches share info for 10 seconds after
// share creation and if the cache is not invalidated by the time we call FFF, RDR gets confused.
//
Sleep( 12 * 1000 );
FnExit:
return( dwStatus );
} // SmbpPrepareOnlineDfsRoot
DWORD
SmbpCreateDfsRoot(
IN PSHARE_RESOURCE pResourceEntry
)
/*++
Routine Description:
Create a DFS root.
Arguments:
pResourceEntry - Supplies the pointer to the resource block
Return Value:
ERROR_SUCCESS on success, a Win32 error code otherwise.
--*/
{
DWORD dwStatus = ERROR_SUCCESS;
//
// Make sure the DFS service is started. This is necessary since the cluster service does not set
// an explicit dependency on DFS service.
//
dwStatus = ResUtilStartResourceService( DFS_SVCNAME,
NULL );
if ( dwStatus != ERROR_SUCCESS )
{
(g_LogEvent)(
pResourceEntry->ResourceHandle,
LOG_ERROR,
L"SmbpCreateDfsRoot: Failed to start DFS service, share name %1!ws!, status %2!u!...\n",
pResourceEntry->Params.ShareName,
dwStatus);
goto FnExit;
}
//
// Chittur Subbaraman (chitturs) - 2/14/99
//
dwStatus = NetDfsAddStdRoot( pResourceEntry->szDependentNetworkName,
pResourceEntry->Params.ShareName,
NULL,
0 );
if ( dwStatus != ERROR_SUCCESS )
{
(g_LogEvent)(
pResourceEntry->ResourceHandle,
LOG_ERROR,
L"SmbpCreateDfsRoot: Failed to create dfs root for share %1!ws!, status %2!u!...\n",
pResourceEntry->Params.ShareName,
dwStatus);
goto FnExit;
}
FnExit:
return ( dwStatus );
} // SmbpCreateDfsRoot
DWORD
SmbpDeleteDfsRoot(
IN PSHARE_RESOURCE pResourceEntry
)
/*++
Routine Description:
Delete the DFS root and the registry checkpoints.
Arguments:
pResourceEntry - Supplies the pointer to the resource block
Return Value:
ERROR_SUCCESS on success, a Win32 error code otherwise.
--*/
{
DWORD dwStatus = ERROR_SUCCESS;
DWORD dwReturnSize;
LPWSTR lpszDfsRootCheckpointName = NULL;
//
// Get the checkpoint name for this DFS root resource. This is a private API provided
// by UDAYH of DFS team on 4/26/2001.
//
dwStatus = GetDfsRootMetadataLocation( pResourceEntry->Params.ShareName,
&lpszDfsRootCheckpointName );
if ( dwStatus != ERROR_SUCCESS )
{
(g_LogEvent)(
pResourceEntry->ResourceHandle,
LOG_ERROR,
L"SmbpDeleteDfsRoot: Failed to get metadata location for dfs root %1!ws!, status %2!u!...\n",
pResourceEntry->Params.ShareName,
dwStatus);
goto FnExit;
}
(g_LogEvent)(
pResourceEntry->ResourceHandle,
LOG_INFORMATION,
L"SmbpDeleteDfsRoot: Dfs root %1!ws! metadata location from DFS API is %2!ws!...\n",
pResourceEntry->Params.ShareName,
lpszDfsRootCheckpointName);
dwStatus = ClusterResourceControl(
pResourceEntry->hResource,
NULL,
CLUSCTL_RESOURCE_DELETE_REGISTRY_CHECKPOINT,
lpszDfsRootCheckpointName,
(lstrlenW(lpszDfsRootCheckpointName) + 1) * sizeof(WCHAR),
NULL,
0,
&dwReturnSize );
if ( dwStatus != ERROR_SUCCESS )
{
if ( dwStatus == ERROR_FILE_NOT_FOUND )
{
dwStatus = ERROR_SUCCESS;
} else
{
(g_LogEvent)(
pResourceEntry->ResourceHandle,
LOG_ERROR,
L"SmbpDeleteDfsRoot: Failed to delete registry checkpoint %1!ws! for share %2!ws!, status %3!u!...\n",
lpszDfsRootCheckpointName,
pResourceEntry->Params.ShareName,
dwStatus);
goto FnExit;
}
}
//
// Make sure the DFS service is started. This is necessary since the cluster service does not set
// an explicit dependency on DFS service.
//
dwStatus = ResUtilStartResourceService( DFS_SVCNAME,
NULL );
if ( dwStatus != ERROR_SUCCESS )
{
(g_LogEvent)(
pResourceEntry->ResourceHandle,
LOG_ERROR,
L"SmbpDeleteDfsRoot: Failed to start DFS service, share name %1!ws!, status %2!u!...\n",
pResourceEntry->Params.ShareName,
dwStatus);
goto FnExit;
}
dwStatus = NetDfsRemoveStdRoot( pResourceEntry->szDependentNetworkName,
pResourceEntry->Params.ShareName,
0 );
if ( dwStatus != ERROR_SUCCESS )
{
(g_LogEvent)(
pResourceEntry->ResourceHandle,
LOG_ERROR,
L"SmbpDeleteDfsRoot: Failed to delete dfs root %1!ws!, status %2!u!...\n",
pResourceEntry->Params.ShareName,
dwStatus);
goto FnExit;
} else
{
(g_LogEvent)(
pResourceEntry->ResourceHandle,
LOG_ERROR,
L"SmbpDeleteDfsRoot: Delete share %1!ws! as a dfs root\n",
pResourceEntry->Params.ShareName);
}
FnExit:
//
// Free memory for the checkpoint name buffer for this DFS root resource. This is a private API provided
// by UDAYH of DFS team on 4/26/2001.
//
if ( lpszDfsRootCheckpointName != NULL )
ReleaseDfsRootMetadataLocation ( lpszDfsRootCheckpointName );
return ( dwStatus );
} // SmbpDeleteDfsRoot
DWORD
SmbpResetDfs(
IN PSHARE_RESOURCE pResourceEntry
)
/*++
Routine Description:
Set the DFS root to standby mode. This will make the root inaccessible as well as allow the
share to be deleted.
Arguments:
pResourceEntry - Supplies the pointer to the resource block
Return Value:
ERROR_SUCCESS on success, a Win32 error code otherwise.
--*/
{
DFS_INFO_101 dfsInfo101;
WCHAR szDfsEntryPath[MAX_COMPUTERNAME_LENGTH + NNLEN + SMBSHARE_EXTRA_LEN];
DWORD dwStatus;
WCHAR szNetworkName[MAX_COMPUTERNAME_LENGTH+1];
dfsInfo101.State = DFS_VOLUME_STATE_STANDBY;
//
// If this function is invoked from SmbShareOnlineThread, we would not have saved the dependent
// network name yet into the resource structure, that happens later in SmbpHandleDfsRoot when
// we are sure that we are talking about a DFS root share. Note that we cannot be sure in the online thread
// if a dependent network name even exists. For such cases, use the computer name as parameter to the DFS API.
//
if ( pResourceEntry->szDependentNetworkName[0] == L'\0' )
{
( void ) StringCchCopy ( szNetworkName, RTL_NUMBER_OF ( szNetworkName ), pResourceEntry->ComputerName );
} else
{
( void ) StringCchCopy ( szNetworkName, RTL_NUMBER_OF ( szNetworkName ), pResourceEntry->szDependentNetworkName );
}
//
// Prepare a path of the form \\NetworkName\ShareName to pass into DFS API.
//
( void ) StringCchCopy ( szDfsEntryPath, RTL_NUMBER_OF ( szDfsEntryPath ), L"\\\\" );
( void ) StringCchCat ( szDfsEntryPath, RTL_NUMBER_OF ( szDfsEntryPath ), szNetworkName );
( void ) StringCchCat ( szDfsEntryPath, RTL_NUMBER_OF ( szDfsEntryPath ), L"\\" );
( void ) StringCchCat ( szDfsEntryPath, RTL_NUMBER_OF ( szDfsEntryPath ), pResourceEntry->Params.ShareName );
dwStatus = NetDfsSetInfo( szDfsEntryPath, // Root share
NULL, // Remote server name
NULL, // Remote share name
101, // Info level
( PBYTE ) &dfsInfo101 ); // Input buffer
if ( dwStatus != ERROR_SUCCESS )
{
(g_LogEvent)(
pResourceEntry->ResourceHandle,
LOG_ERROR,
L"SmbpResetDfs: NetDfsSetInfo with VS name %1!ws! for root %2!ws!, status %3!u!...\n",
szNetworkName,
pResourceEntry->Params.ShareName,
dwStatus);
//
// If this function was called as a part of resmon rundown, then it is possible that
// the VS is terminated by resmon before this call is made. In such a case, we would
// fail in the above call. So, retry using computer name. That should succeed.
//
// Prepare a path of the form \\ComputerName\ShareName to pass into DFS API.
//
( void ) StringCchCopy ( szDfsEntryPath, RTL_NUMBER_OF ( szDfsEntryPath ), L"\\\\" );
( void ) StringCchCat ( szDfsEntryPath, RTL_NUMBER_OF ( szDfsEntryPath ), pResourceEntry->ComputerName );
( void ) StringCchCat ( szDfsEntryPath, RTL_NUMBER_OF ( szDfsEntryPath ), L"\\" );
( void ) StringCchCat ( szDfsEntryPath, RTL_NUMBER_OF ( szDfsEntryPath ), pResourceEntry->Params.ShareName );
dwStatus = NetDfsSetInfo( szDfsEntryPath, // Root share
NULL, // Remote server name
NULL, // Remote share name
101, // Info level
( PBYTE ) &dfsInfo101 ); // Input buffer
if ( dwStatus != ERROR_SUCCESS )
{
(g_LogEvent)(
pResourceEntry->ResourceHandle,
LOG_ERROR,
L"SmbpResetDfs: NetDfsSetInfo with computer name %1!ws! for root %2!ws!, status %3!u!...\n",
pResourceEntry->ComputerName,
pResourceEntry->Params.ShareName,
dwStatus);
}
}
return ( dwStatus );
} // SmbpResetDfs
DWORD
SmbpValidateShareName(
IN LPCWSTR lpszShareName
)
/*++
Routine Description:
Validates the name of a share.
Arguments:
lpszShareName - The name to validate.
Return Value:
ERROR_SUCCESS if successful, Win32 error code otherwise.
--*/
{
DWORD cchShareName = lstrlenW( lpszShareName );
//
// Check the length of the name, return an error if it's out of range
//
if ( ( cchShareName < 1 ) || ( cchShareName > NNLEN ) )
{
return ERROR_INVALID_PARAMETER;
}
//
// Check for illegal characters, return an error if one is found
//
if ( wcscspn( lpszShareName, ILLEGAL_NAME_CHARS_STR TEXT("*") ) < cchShareName )
{
return ERROR_INVALID_NAME;
}
//
// Return an error if the name contains only dots and spaces.
//
if ( wcsspn( lpszShareName, DOT_AND_SPACE_STR ) == cchShareName )
{
return ERROR_INVALID_NAME;
}
//
// If we get here, the name passed all of the tests, so it's valid
//
return ERROR_SUCCESS;
}// SmbpValidateShareName
DWORD
SmbpRecycleDfsService(
IN PSHARE_RESOURCE pResourceEntry
)
/*++
Routine Description:
Recycle the DFS service if necessary.
Arguments:
pResourceEntry - Supplies the pointer to the resource block
Return Value:
ERROR_SUCCESS on success, a Win32 error code otherwise.
--*/
{
DWORD dwStatus = ERROR_SUCCESS;
//
// Enter a CS to make sure multiple resources in this process do not attempt to recycle the DFS
// service at the same time. This does not cover the case where the DFS resource is hosted in a
// separate monitor but this is the best we can do at this stage.
//
EnterCriticalSection ( &SmbShareLock );
if ( g_fDfsServiceNeedsRecyling == FALSE )
{
goto FnExit;
}
(g_LogEvent)(pResourceEntry->ResourceHandle,
LOG_INFORMATION,
L"SmbpRecycleDfsService: Attempting to recycle %1!ws! service\n",
DFS_SVCNAME);
//
// If this is the first run after an upgrade/fresh install, just recycle the
// DFS service. This is necessary since the DFS service detects if clustering is
// installed only in its boot. Thus, if someone installs clustering and does not
// reboot the node or recycle the DFS service, all DFS resources will fail. Ideally,
// the DFS service should be able to detect if clustering is installed when we call
// the first DFS API, but due to risks in changing the dfssvc, we do this here.
//
dwStatus = ResUtilStopResourceService( DFS_SVCNAME );
if ( dwStatus != ERROR_SUCCESS )
{
(g_LogEvent)(pResourceEntry->ResourceHandle,
LOG_ERROR,
L"SmbpRecycleDfsService: Unable to stop %1!ws! service, status %2!u!\n",
DFS_SVCNAME,
dwStatus);
goto FnExit;
}
dwStatus = ResUtilStartResourceService( DFS_SVCNAME,
NULL );
if ( dwStatus != ERROR_SUCCESS )
{
(g_LogEvent)(pResourceEntry->ResourceHandle,
LOG_ERROR,
L"SmbpRecycleDfsService: Unable to start %1!ws! service, status %2!u!\n",
DFS_SVCNAME,
dwStatus);
goto FnExit;
}
g_fDfsServiceNeedsRecyling = FALSE;
FnExit:
LeaveCriticalSection ( &SmbShareLock );
return ( dwStatus );
}
//***********************************************************
//
// Define Function Table
//
//***********************************************************
CLRES_V1_FUNCTION_TABLE( SmbShareFunctionTable, // Name
CLRES_VERSION_V1_00, // Version
SmbShare, // Prefix
NULL, // Arbitrate
NULL, // Release
SmbShareResourceControl,// ResControl
SmbShareResourceTypeControl ); // ResTypeControl