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.
667 lines
16 KiB
667 lines
16 KiB
//--------------------------------------------------------------------------
|
|
//
|
|
// Copyright (C) 1999, Microsoft Corporation
|
|
//
|
|
// File: misc.cxx
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
#define UNICODE 1
|
|
|
|
extern "C" {
|
|
#include <nt.h>
|
|
#include <ntrtl.h>
|
|
#include <nturtl.h>
|
|
#include <windows.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <stddef.h>
|
|
#include <shellapi.h>
|
|
#include <dfsprefix.h>
|
|
#include <winldap.h>
|
|
#include <dsgetdc.h>
|
|
#include <lm.h>
|
|
#include <lmdfs.h>
|
|
#include <dfsfsctl.h>
|
|
}
|
|
#include <DfsServerLibrary.hxx>
|
|
#include "struct.hxx"
|
|
#include "flush.hxx"
|
|
#include "misc.hxx"
|
|
#include "messages.h"
|
|
|
|
#include <strsafe.h>
|
|
|
|
#include <dfsutil.hxx>
|
|
#include "dfspathname.hxx"
|
|
#include "resapi.h"
|
|
|
|
#define MAX_BUF_SIZE 10000
|
|
|
|
WCHAR MsgBuf[MAX_BUF_SIZE];
|
|
CHAR AnsiBuf[MAX_BUF_SIZE*3];
|
|
|
|
WCHAR wszRootShare[MAX_PATH+1] = { 0 };
|
|
#define WINLOGON_FOLDER L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon"
|
|
#define SFCVALUE L"SFCDisable"
|
|
#define ARRAYLEN(x) (sizeof(x) / sizeof((x)[0]))
|
|
|
|
|
|
|
|
DWORD
|
|
DfspGetLinkName(
|
|
LPWSTR pwszDfsRoot,
|
|
LPWSTR *ppwszLinkName);
|
|
|
|
|
|
DWORD
|
|
AtoHex(
|
|
LPWSTR pwszHexValue,
|
|
PDWORD pdwErr)
|
|
{
|
|
DWORD dwHexValue = 0;
|
|
DWORD DiscardResult;
|
|
// if (fSwDebug == TRUE)
|
|
// MyPrintf(L"AtoHex(%ws)\r\n", pwszHexValue);
|
|
|
|
if (pwszHexValue == NULL) {
|
|
*pdwErr = ERROR_INVALID_PARAMETER;
|
|
goto AllDone;
|
|
}
|
|
|
|
if (pwszHexValue[0] == L'0' && (pwszHexValue[1] == L'x' || pwszHexValue[1] == L'X'))
|
|
pwszHexValue = &pwszHexValue[2];
|
|
|
|
DiscardResult = swscanf(pwszHexValue, L"%x", &dwHexValue);
|
|
|
|
AllDone:
|
|
|
|
// if (fSwDebug == TRUE)
|
|
// MyPrintf(L"AtoHex returning 0x%x (dwErr=0x%x)\r\n", dwHexValue, *pdwErr);
|
|
|
|
return dwHexValue;
|
|
}
|
|
|
|
DWORD
|
|
AtoDec(
|
|
LPWSTR pwszDecValue,
|
|
PDWORD pdwErr)
|
|
{
|
|
DWORD dwDecValue = 0;
|
|
DWORD DiscardResult;
|
|
// if (fSwDebug == TRUE)
|
|
// MyPrintf(L"AtoDec(%ws)\r\n", pwszDecValue);
|
|
|
|
if (pwszDecValue == NULL) {
|
|
*pdwErr = ERROR_INVALID_PARAMETER;
|
|
goto AllDone;
|
|
}
|
|
|
|
DiscardResult = swscanf(pwszDecValue, L"%d", &dwDecValue);
|
|
|
|
AllDone:
|
|
|
|
// if (fSwDebug == TRUE)
|
|
// MyPrintf(L"AtoDec returning 0x%x (dwErr=0x%x)\r\n", dwDecValue, *pdwErr);
|
|
|
|
return dwDecValue;
|
|
}
|
|
|
|
DFSSTATUS
|
|
IsClusterNode(
|
|
LPWSTR pNodeName,
|
|
PBOOLEAN pIsCluster )
|
|
{
|
|
DFSSTATUS Status = ERROR_SUCCESS;
|
|
DWORD ClusterState;
|
|
|
|
*pIsCluster = FALSE;
|
|
|
|
Status = GetNodeClusterState( pNodeName,
|
|
&ClusterState );
|
|
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
if ( (ClusterStateRunning == ClusterState) ||
|
|
(ClusterStateNotRunning == ClusterState) )
|
|
{
|
|
*pIsCluster = TRUE;
|
|
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
#if 0
|
|
// We might enable this code in a more cluster friendly
|
|
// dfsutil version.
|
|
//
|
|
typedef struct _DFSUTIL_CLUSTER_CONTEXT {
|
|
PUNICODE_STRING pShareName;
|
|
BOOLEAN bIsClustered;
|
|
|
|
} DFSUTIL_CLUSTER_CONTEXT;
|
|
|
|
DWORD
|
|
DfsUtilClusterCallBackFunction(
|
|
HRESOURCE hSelf,
|
|
HRESOURCE hResource,
|
|
PVOID Context)
|
|
{
|
|
|
|
UNREFERENCED_PARAMETER( hSelf );
|
|
|
|
HKEY HKey = NULL;
|
|
HKEY HParamKey = NULL;
|
|
DFSUTIL_CLUSTER_CONTEXT *pContext = (DFSUTIL_CLUSTER_CONTEXT *)Context;
|
|
|
|
|
|
DWORD Status = ERROR_SUCCESS;
|
|
DWORD Value = 0;
|
|
|
|
pContext->bIsClustered = FALSE;
|
|
HKey = GetClusterResourceKey(hResource, KEY_READ);
|
|
|
|
if (HKey != NULL) {
|
|
Status = ClusterRegOpenKey( HKey,
|
|
L"Parameters",
|
|
KEY_READ,
|
|
&HParamKey );
|
|
|
|
ClusterRegCloseKey( HKey );
|
|
|
|
if (ERROR_SUCCESS == Status)
|
|
{
|
|
LPWSTR ResShareName = NULL;
|
|
UNICODE_STRING VsName;
|
|
|
|
ResShareName = ResUtilGetSzValue( HParamKey,
|
|
L"ShareName" );
|
|
Status = DfsRtlInitUnicodeStringEx(&VsName, ResShareName);
|
|
if(Status == ERROR_SUCCESS)
|
|
{
|
|
if (pContext->pShareName->Length == VsName.Length)
|
|
{
|
|
Status = ResUtilGetDwordValue(HParamKey, L"IsDfsRoot", &Value, 0);
|
|
|
|
if ((ERROR_SUCCESS == Status) &&
|
|
(Value == 1))
|
|
{
|
|
|
|
if (_wcsnicmp(pContext->pShareName->Buffer,
|
|
VsName.Buffer,
|
|
VsName.Length) == 0)
|
|
{
|
|
pContext->bIsClustered = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
ClusterRegCloseKey( HParamKey );
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
DWORD
|
|
IsClusterRoot(
|
|
LPWSTR pNodeName,
|
|
PUNICODE_STRING pShareName,
|
|
PBOOLEAN pIsClustered )
|
|
|
|
{
|
|
DWORD Status;
|
|
DFSUTIL_CLUSTER_CONTEXT Context;
|
|
UNREFERENCED_PARAMETER(pNodeName);
|
|
|
|
Context.pShareName = pShareName;
|
|
Context.bIsClustered = FALSE;
|
|
|
|
Status = ResUtilEnumResources(NULL,
|
|
L"File Share",
|
|
DfsUtilClusterCallBackFunction,
|
|
(PVOID)&Context );
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
*pIsClustered = Context.bIsClustered;
|
|
}
|
|
return Status;
|
|
|
|
|
|
}
|
|
#endif
|
|
|
|
DWORD
|
|
CmdAddRoot(
|
|
BOOLEAN DomainDfs,
|
|
LPWSTR pwszServerName,
|
|
LPWSTR pwszShareName,
|
|
LPWSTR pwszRootName,
|
|
LPWSTR pwszComment)
|
|
{
|
|
DWORD dwErr = ERROR_SUCCESS;
|
|
BOOLEAN bIsClustered = FALSE;
|
|
|
|
DebugInformation((L"CmdAddRoot (%ws,%ws)\r\n", pwszServerName, pwszShareName));
|
|
|
|
if (DomainDfs == FALSE)
|
|
{
|
|
// see if the server is a clustered node.
|
|
dwErr = IsClusterNode( pwszServerName, &bIsClustered );
|
|
if (dwErr == ERROR_SUCCESS && bIsClustered)
|
|
{
|
|
DebugInformation((L"Node %ws is in a cluster\r\n", pwszServerName));
|
|
|
|
}
|
|
|
|
if (!bIsClustered)
|
|
{
|
|
DebugInformation((L"<%ws, %ws> is not clustered. Calling NetDfsAddStdRoot\r\n",
|
|
pwszServerName, pwszShareName));
|
|
dwErr = NetDfsAddStdRoot(
|
|
pwszServerName,
|
|
pwszShareName,
|
|
pwszComment,
|
|
0);;
|
|
}
|
|
else
|
|
{
|
|
MyPrintf(L"Node %ws belongs to a cluster environment. This command is not supported.\r\n", pwszServerName);
|
|
dwErr = ERROR_NOT_SUPPORTED;
|
|
}
|
|
|
|
} else {
|
|
dwErr = NetDfsAddFtRoot(
|
|
pwszServerName,
|
|
pwszShareName,
|
|
pwszRootName,
|
|
pwszComment,
|
|
0);
|
|
|
|
}
|
|
DebugInformation((L"CmdAddRoot returning %d\r\n", dwErr));
|
|
if (dwErr == ERROR_SUCCESS)
|
|
CommandSucceeded = TRUE;
|
|
return dwErr;
|
|
}
|
|
|
|
|
|
DWORD
|
|
CmdRemRoot(
|
|
BOOLEAN DomDfs,
|
|
LPWSTR pwszServerName,
|
|
LPWSTR pwszShareName,
|
|
LPWSTR pwszRootName)
|
|
{
|
|
DWORD dwErr = ERROR_SUCCESS;
|
|
BOOLEAN bIsClustered = FALSE;
|
|
|
|
DebugInformation((L"CmdRemRoot: Server %ws, Physical Share %ws, Logical Share %ws)\r\n",
|
|
pwszServerName, pwszShareName, pwszRootName));
|
|
|
|
if (DomDfs == FALSE)
|
|
{
|
|
// see if the server is a clustered node.
|
|
dwErr = IsClusterNode( pwszServerName, &bIsClustered );
|
|
if (dwErr == ERROR_SUCCESS && bIsClustered)
|
|
{
|
|
DebugInformation((L"Node %ws is in a cluster.\r\n", pwszServerName));
|
|
}
|
|
|
|
if (!bIsClustered)
|
|
{
|
|
DebugInformation((L"<%ws, %ws> is not clustered. Calling NetDfsRemoveStdRoot\r\n",
|
|
pwszServerName, pwszShareName));
|
|
dwErr = NetDfsRemoveStdRoot(
|
|
pwszServerName,
|
|
pwszShareName,
|
|
0);
|
|
}
|
|
else
|
|
{
|
|
MyPrintf(L"Node %ws belongs to a cluster environment. This command is not supported.\r\n",pwszServerName);
|
|
dwErr = ERROR_NOT_SUPPORTED;
|
|
}
|
|
}
|
|
else {
|
|
dwErr = NetDfsRemoveFtRoot(
|
|
pwszServerName,
|
|
pwszShareName,
|
|
pwszRootName,
|
|
0);
|
|
|
|
}
|
|
DebugInformation((L"CmdRemRoot returning %d\r\n", dwErr));
|
|
if (dwErr == ERROR_SUCCESS)
|
|
CommandSucceeded = TRUE;
|
|
return dwErr;
|
|
}
|
|
|
|
VOID
|
|
MyFormatMessageText(
|
|
HRESULT dwMsgId,
|
|
PWSTR pszBuffer,
|
|
DWORD dwBufferSize,
|
|
va_list *parglist)
|
|
{
|
|
DWORD dwReturn = FormatMessage(
|
|
(dwMsgId >= MSG_FIRST_MESSAGE)
|
|
? FORMAT_MESSAGE_FROM_HMODULE
|
|
: FORMAT_MESSAGE_FROM_SYSTEM,
|
|
NULL,
|
|
dwMsgId,
|
|
LANG_USER_DEFAULT,
|
|
pszBuffer,
|
|
dwBufferSize,
|
|
parglist);
|
|
|
|
if (dwReturn == 0 && fSwDebug)
|
|
MyPrintf(L"Formatmessage failed 0x%x\r\n", GetLastError());
|
|
}
|
|
|
|
VOID
|
|
ErrorMessage(
|
|
IN HRESULT hr,
|
|
...)
|
|
{
|
|
ULONG cch;
|
|
va_list arglist;
|
|
|
|
HRESULT HResult;
|
|
size_t CharacterCount;
|
|
|
|
va_start(arglist, hr);
|
|
MyFormatMessageText(hr, MsgBuf, ARRAYLEN(MsgBuf), &arglist);
|
|
|
|
HResult = StringCchLength( MsgBuf,
|
|
MAX_BUF_SIZE,
|
|
&CharacterCount );
|
|
|
|
if (SUCCEEDED(HResult))
|
|
{
|
|
cch = WideCharToMultiByte(CP_OEMCP, 0,
|
|
MsgBuf, CharacterCount,
|
|
AnsiBuf, MAX_BUF_SIZE*3,
|
|
NULL, NULL);
|
|
WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), AnsiBuf, cch, &cch, NULL);
|
|
}
|
|
|
|
va_end(arglist);
|
|
}
|
|
|
|
VOID
|
|
DfsVPrintToFile(
|
|
HANDLE FileHandle,
|
|
PWCHAR format,
|
|
va_list va)
|
|
{
|
|
ULONG cch;
|
|
HRESULT HResult;
|
|
size_t CharacterCount;
|
|
|
|
HResult = StringCchVPrintf( MsgBuf,
|
|
MAX_BUF_SIZE,
|
|
format,
|
|
va );
|
|
if (SUCCEEDED(HResult))
|
|
{
|
|
HResult = StringCchLength( MsgBuf,
|
|
MAX_BUF_SIZE,
|
|
&CharacterCount );
|
|
}
|
|
|
|
if (SUCCEEDED(HResult))
|
|
{
|
|
cch = WideCharToMultiByte(CP_OEMCP, 0,
|
|
MsgBuf, CharacterCount,
|
|
AnsiBuf, MAX_BUF_SIZE*3,
|
|
NULL, NULL);
|
|
WriteFile(FileHandle, AnsiBuf, cch, &cch, NULL);
|
|
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
VOID
|
|
DfsVPrintWideToFile(
|
|
HANDLE FileHandle,
|
|
PWCHAR format,
|
|
va_list va)
|
|
{
|
|
ULONG cch;
|
|
HRESULT HResult;
|
|
size_t CharacterCount;
|
|
|
|
HResult = StringCchVPrintf( MsgBuf,
|
|
MAX_BUF_SIZE,
|
|
format,
|
|
va );
|
|
if (SUCCEEDED(HResult))
|
|
{
|
|
HResult = StringCchLength( MsgBuf,
|
|
MAX_BUF_SIZE,
|
|
&CharacterCount );
|
|
}
|
|
|
|
if (SUCCEEDED(HResult))
|
|
{
|
|
//cch = WideCharToMultiByte(CP_OEMCP, 0,
|
|
// MsgBuf, CharacterCount,
|
|
// AnsiBuf, MAX_BUF_SIZE*3,
|
|
// NULL, NULL);
|
|
|
|
// WriteFile(FileHandle, AnsiBuf, cch, &cch, NULL);
|
|
|
|
WriteFile(FileHandle, MsgBuf, CharacterCount*sizeof(WCHAR), &cch, NULL);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
DfsPrintToFile(
|
|
HANDLE FileHandle,
|
|
BOOLEAN ScriptOut,
|
|
PWCHAR format,
|
|
...)
|
|
{
|
|
va_list va;
|
|
|
|
va_start(va, format);
|
|
|
|
if (ScriptOut)
|
|
{
|
|
DfsVPrintWideToFile( FileHandle, format, va);
|
|
}
|
|
|
|
else
|
|
{
|
|
DfsVPrintToFile( FileHandle, format, va);
|
|
}
|
|
|
|
|
|
va_end(va);
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
MyPrintf(
|
|
PWCHAR format,
|
|
...)
|
|
{
|
|
va_list va;
|
|
|
|
va_start(va, format);
|
|
|
|
DfsVPrintToFile( GetStdHandle(STD_OUTPUT_HANDLE), format, va);
|
|
|
|
va_end(va);
|
|
return;
|
|
}
|
|
|
|
|
|
VOID
|
|
ShowVerboseInformation(
|
|
PWCHAR format,
|
|
...)
|
|
{
|
|
va_list va;
|
|
|
|
extern HANDLE ShowHandle;
|
|
va_start(va, format);
|
|
|
|
DfsVPrintToFile( ShowHandle, format, va);
|
|
|
|
va_end(va);
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
ShowDebugInformation(
|
|
PWCHAR format,
|
|
...)
|
|
{
|
|
va_list va;
|
|
extern HANDLE DebugHandle;
|
|
va_start(va, format);
|
|
|
|
DfsVPrintToFile( DebugHandle, format, va);
|
|
|
|
va_end(va);
|
|
return;
|
|
}
|
|
|
|
|
|
DFSSTATUS
|
|
SetInfoReSynchronize(
|
|
LPWSTR ServerName,
|
|
LPWSTR ShareName)
|
|
{
|
|
DfsPathName RootTarget;
|
|
DFS_INFO_101 Info101;
|
|
DFSSTATUS Status;
|
|
|
|
//
|
|
// First create a UNC path name to the root target.
|
|
//
|
|
Status = RootTarget.SetPathName( ServerName, ShareName );
|
|
if (Status != ERROR_SUCCESS)
|
|
{
|
|
DebugInformation((L"DfsUtil: Error 0x%x in creating RootTarget<%wS, %wS>\n",
|
|
Status, ServerName, ShareName));
|
|
ErrorMessage(Status);
|
|
return Status;
|
|
}
|
|
|
|
DebugInformation((L"DfsUtil: ReSynchronize notification to root target %wS\n", RootTarget.GetPathString()));
|
|
|
|
//
|
|
// Ask the dfs service to synchronize. It is important that we don't
|
|
// use direct mode operations (ie. DFS_SET_INFO macro) here. These are the root targets.
|
|
//
|
|
Info101.State = DFS_VOLUME_STATE_RESYNCHRONIZE;
|
|
Status = NetDfsSetInfo( RootTarget.GetPathString(), NULL, NULL, 101, (LPBYTE)&Info101 );
|
|
|
|
//
|
|
// It is entirely fine to get an error from W2K servers. Still, we'll defer that decision to the
|
|
// to the caller and return the real error.
|
|
//
|
|
if (Status != ERROR_SUCCESS)
|
|
{
|
|
DebugInformation((L"DfsUtil: Error 0x%x hit in attempting to contact root target %wS\n",
|
|
Status, RootTarget.GetPathString()));
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Just take out the <target,share> tuple from the replicalist
|
|
// in the AD directly. This doesn't involve any attempts to
|
|
// contact that replica server other than a feeble attempt to
|
|
// send a RESYNCHRONIZE message to it. We fully expect that
|
|
// the typically scenario will be one of a dead replica server.
|
|
//
|
|
DWORD
|
|
CmdUnmapRootReplica(
|
|
LPWSTR DomainDfsPath,
|
|
LPWSTR ReplicaServerName,
|
|
LPWSTR ReplicaShareName )
|
|
{
|
|
|
|
DfsPathName DfsPathName;
|
|
DFSSTATUS Status;
|
|
|
|
Status = DfsPathName.CreatePathName( DomainDfsPath );
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
PUNICODE_STRING pRemaining = DfsPathName.GetRemainingCountedString();
|
|
if (pRemaining->Length != 0)
|
|
{
|
|
Status = ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
Status = NetDfsRemoveFtRootForced( DfsPathName.GetServerString(),
|
|
ReplicaServerName,
|
|
ReplicaShareName,
|
|
DfsPathName.GetShareString(),
|
|
0 );
|
|
}
|
|
}
|
|
return Status;
|
|
}
|
|
|
|
|
|
DWORD
|
|
CmdClean(
|
|
LPWSTR HostServerName,
|
|
LPWSTR RootShareName )
|
|
{
|
|
DWORD Status;
|
|
|
|
DebugInformation((L"DfsUtil: Contacting registry of %wS to remove %wS\n",
|
|
HostServerName, RootShareName));
|
|
|
|
Status = DfsClean( HostServerName, RootShareName );
|
|
|
|
if (Status != ERROR_SUCCESS) {
|
|
DebugInformation((L"DfsUtil: Specified registry entry was not found.\n"));
|
|
}
|
|
return Status;
|
|
}
|
|
|
|
|
|
|
|
DWORD
|
|
CreateDfsFile( LPWSTR pFileString,
|
|
PHANDLE pFileHandle )
|
|
{
|
|
HANDLE FileHandle;
|
|
DWORD Status = ERROR_SUCCESS;
|
|
|
|
FileHandle = CreateFile( pFileString,
|
|
GENERIC_ALL,
|
|
FILE_SHARE_READ|FILE_SHARE_DELETE,
|
|
NULL,
|
|
CREATE_ALWAYS,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL );
|
|
if (FileHandle == INVALID_HANDLE_VALUE)
|
|
{
|
|
Status = GetLastError();
|
|
}
|
|
else
|
|
{
|
|
*pFileHandle = FileHandle;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|