|
|
//-----------------------------------------------------------------------------
//
// Copyright (C) 1995, Microsoft Corporation
//
// File: dfsstub.c
//
// Contents: Stub file for the NetDfsXXX APIs. The stubs turn around and
// call the NetrDfsXXX APIs on the appropriate server, or (in the
// case of NetDfs[G/S]etClientXXX, go directly to the driver on the
// local machine.
//
// Classes:
//
// Functions: NetDfsXXX
//
// History: 01-10-96 Milans created
//
//-----------------------------------------------------------------------------
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <windows.h>
#include <stdlib.h>
#include <lm.h>
#include <lmdfs.h>
#include <dfsp.h>
#include <netdfs.h>
#include <dfsfsctl.h>
#include <dsrole.h>
#include <ntdsapi.h>
#include <dsgetdc.h>
#include <winldap.h>
#include <aclapi.h>
#include "dfsacl.h"
#define MAX_DFS_LDAP_RETRY 20
#define IS_UNC_PATH(wsz, cw) \
((cw) > 2 && (wsz)[0] == L'\\' && (wsz)[1] == L'\\')
#define IS_VALID_PREFIX(wsz, cw) \
((cw) > 1 && (wsz)[0] == L'\\' && (wsz)[1] != L'\\')
#define IS_VALID_DFS_PATH(wsz, cw) \
((cw) > 0 && (wsz)[0] != L'\\')
#define IS_VALID_STRING(wsz) \
((wsz) != NULL && (wsz)[0] != UNICODE_NULL)
#define POINTER_TO_OFFSET(field, buffer) \
( ((PCHAR)field) -= ((ULONG_PTR)buffer) )
#define OFFSET_TO_POINTER(field, buffer) \
( ((PCHAR)field) += ((ULONG_PTR)buffer) )
NET_API_STATUS DfspGetDfsNameFromEntryPath( LPWSTR wszEntryPath, DWORD cwEntryPath, LPWSTR *ppwszDfsName);
NET_API_STATUS DfspGetMachineNameFromEntryPath( LPWSTR wszEntryPath, DWORD cwEntryPath, LPWSTR *ppwszMachineName);
NET_API_STATUS DfspBindRpc( IN LPWSTR DfsName, OUT RPC_BINDING_HANDLE *BindingHandle);
NET_API_STATUS DfspBindToServer( IN LPWSTR DfsName, OUT RPC_BINDING_HANDLE *BindingHandle);
VOID DfspFreeBinding( RPC_BINDING_HANDLE BindingHandle);
NET_API_STATUS DfspVerifyBinding();
VOID DfspFlushPkt( LPWSTR DfsEntryPath);
NTSTATUS DfspIsThisADfsPath( LPWSTR pwszPathName);
DWORD DfspDfsPathToRootMachine( LPWSTR pwszDfsName, LPWSTR *ppwszMachineName);
DWORD DfspCreateFtDfs( LPWSTR ServerName, LPWSTR DcName, BOOLEAN IsPdc, LPWSTR RootShare, LPWSTR FtDfsName, LPWSTR Comment, DWORD Flags);
DWORD DfspTearDownFtDfs( IN LPWSTR wszServerName, IN LPWSTR wszDsAddress, IN LPWSTR wszRootShare, IN LPWSTR wszFtDfsName, IN DWORD dwFlags);
VOID DfspFlushFtTable( LPWSTR wszDcName, LPWSTR wszFtDfsName);
NTSTATUS DfspSetDomainToDc( LPWSTR DomainName, LPWSTR DcName);
DWORD I_NetDfsIsThisADomainName( LPWSTR wszDomain);
DWORD DfspIsThisADomainName( LPWSTR wszName, PWCHAR *List);
VOID DfspNotifyFtRoot( LPWSTR wszServerShare, LPWSTR wszDcName);
DWORD NetpDfsAdd2( LPWSTR RootName, LPWSTR EntryPath, LPWSTR ServerName, LPWSTR ShareName, LPWSTR Comment, DWORD Flags);
DWORD DfspAdd2( LPWSTR RootName, LPWSTR EntryPath, LPWSTR DcName, LPWSTR ServerName, LPWSTR ShareName, LPWSTR Comment, DWORD Flags);
DWORD NetpDfsSetInfo2( LPWSTR RootName, LPWSTR EntryPath, LPWSTR ServerName, LPWSTR ShareName, DWORD Level, LPDFS_INFO_STRUCT pDfsInfo);
DWORD DfspSetInfo2( LPWSTR RootName, LPWSTR EntryPath, LPWSTR DcName, LPWSTR ServerName, LPWSTR ShareName, DWORD Level, LPDFS_INFO_STRUCT pDfsInfo);
DWORD NetpDfsRemove2( LPWSTR RootName, LPWSTR EntryPath, LPWSTR ServerName, LPWSTR ShareName);
DWORD DfspRemove2( LPWSTR RootName, LPWSTR EntryPath, LPWSTR DcName, LPWSTR ServerName, LPWSTR ShareName);
DWORD DfspLdapOpen( LPWSTR wszDcName, LDAP **ppldap, LPWSTR *pwszDfsConfigDN);
INT _cdecl DfspCompareDsDomainControllerInfo1( const void *p1, const void *p2);
BOOLEAN DfspIsInvalidName( LPWSTR ShareName);
static LPWSTR InvalidNames[] = { L"SYSVOL", L"PIPE", L"IPC$", L"ADMIN$", L"MAILSLOT", L"NETLOGON", NULL};
//
// The APIs are all single-threaded - only 1 can be outstanding at a time in
// any one process. The following critical section is used to gate the calls.
// The critical section is initialized at DLL Load time.
//
CRITICAL_SECTION NetDfsApiCriticalSection;
#define ENTER_NETDFS_API EnterCriticalSection( &NetDfsApiCriticalSection );
#define LEAVE_NETDFS_API LeaveCriticalSection( &NetDfsApiCriticalSection );
//
// The name of the Dfs configuration container
//
static WCHAR DfsConfigContainer[] = L"CN=Dfs-Configuration,CN=System";
#if DBG
ULONG DfsDebug = 0; #endif
VOID NetDfsApiInitialize(void) { #if DBG
DWORD dwErr; DWORD dwType; DWORD cbData; HKEY hkey;
dwErr = RegOpenKey( HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Services\\Dfs", &hkey );
if (dwErr == ERROR_SUCCESS) {
cbData = sizeof(DfsDebug);
dwErr = RegQueryValueEx( hkey, L"NetApiDfsDebug", NULL, &dwType, (PBYTE) &DfsDebug, &cbData);
if (!(dwErr == ERROR_SUCCESS && dwType == REG_DWORD)) {
DfsDebug = 0;
}
RegCloseKey(hkey);
}
#endif
}
//+----------------------------------------------------------------------------
//
// Function: NetDfsAdd
//
// Synopsis: Creates a new volume, adds a replica to an existing volume,
// or creates a link to another Dfs.
//
// Arguments: [DfsEntryPath] -- Name of volume/link to create/add replica
// to.
// [ServerName] -- Name of server hosting the storage, or for
// link, name of Dfs root.
// [ShareName] -- Name of share hosting the storage.
// [Flags] -- Describes what is being added.
//
// Returns: [NERR_Success] -- Successfully completed operation.
//
// [ERROR_INVALID_PARAMETER] -- DfsEntryPath and/or ServerName
// and/or ShareName and/or Flags are incorrect.
//
// [ERROR_INVALID_NAME] -- Unable to locate server or domain.
//
// [ERROR_DCNotFound] -- Unable to locate DC for DfsName.
//
// [ERROR_NOT_ENOUGH_MEMORY] -- Out of memory condition.
//
// [NERR_DfsNoSuchVolume] -- DfsEntryPath does not correspond to a
// existing Dfs volume.
//
// [NERR_DfsVolumeAlreadyExists] -- DFS_ADD_VOLUME was specified
// and a volume with DfsEntryPath already exists.
//
// [NERR_DfsInternalCorruption] -- Corruption of Dfs data
// encountered at the server.
//
//-----------------------------------------------------------------------------
NET_API_STATUS NetDfsAdd( IN LPWSTR DfsEntryPath, IN LPWSTR ServerName, IN LPWSTR ShareName, IN LPWSTR Comment, IN DWORD Flags) { NET_API_STATUS dwErr; DWORD cwDfsEntryPath; LPWSTR pwszDfsName = NULL;
#if DBG
if (DfsDebug) DbgPrint("NetDfsAdd(%ws,%ws,%ws,%ws,%d)\n", DfsEntryPath, ServerName, ShareName, Comment, Flags); #endif
//
// Validate the string arguments so RPC won't complain...
//
if (!IS_VALID_STRING(DfsEntryPath) || !IS_VALID_STRING(ServerName) || !IS_VALID_STRING(ShareName)) { return( ERROR_INVALID_PARAMETER ); }
cwDfsEntryPath = wcslen(DfsEntryPath);
if (!IS_UNC_PATH(DfsEntryPath, cwDfsEntryPath) && !IS_VALID_PREFIX(DfsEntryPath, cwDfsEntryPath) && !IS_VALID_DFS_PATH(DfsEntryPath, cwDfsEntryPath)) { return( ERROR_INVALID_PARAMETER ); }
dwErr = DfspGetMachineNameFromEntryPath( DfsEntryPath, cwDfsEntryPath, &pwszDfsName);
ENTER_NETDFS_API
if (dwErr == NERR_Success) {
//
// By now, we should have a valid pwszDfsName. Lets try to bind to it,
// and call the server.
//
dwErr = DfspBindRpc( pwszDfsName, &netdfs_bhandle );
if (dwErr == NERR_Success) {
RpcTryExcept {
dwErr = NetrDfsAdd( DfsEntryPath, ServerName, ShareName, Comment, Flags);
} RpcExcept(1) {
dwErr = RpcExceptionCode();
} RpcEndExcept;
DfspFreeBinding( netdfs_bhandle );
}
}
LEAVE_NETDFS_API
//
// If we failed with ERROR_NOT_SUPPORTED, this is an NT5+ server,
// so we use the NetrDfsAdd2() call instead.
//
if (dwErr == ERROR_NOT_SUPPORTED) {
dwErr = NetpDfsAdd2( pwszDfsName, DfsEntryPath, ServerName, ShareName, Comment, Flags); }
if (pwszDfsName != NULL) free(pwszDfsName);
#if DBG
if (DfsDebug) DbgPrint("NetDfsAdd returning %d\n", dwErr); #endif
return( dwErr );
}
DWORD NetpDfsAdd2( LPWSTR RootName, LPWSTR DfsEntryPath, LPWSTR ServerName, LPWSTR ShareName, LPWSTR Comment, DWORD Flags) { NET_API_STATUS dwErr; ULONG i; ULONG NameCount; PDSROLE_PRIMARY_DOMAIN_INFO_BASIC pPrimaryDomainInfo = NULL; PDOMAIN_CONTROLLER_INFO pDomainControllerInfo = NULL;
#if DBG
if (DfsDebug) DbgPrint("NetpDfsAdd2(%ws,%ws,%ws,%ws,%ws,%d)\n", RootName, DfsEntryPath, ServerName, ShareName, Comment, Flags); #endif
//
// Contact the server and ask for its domain name
//
dwErr = DsRoleGetPrimaryDomainInformation( RootName, DsRolePrimaryDomainInfoBasic, (PBYTE *)&pPrimaryDomainInfo);
if (dwErr != ERROR_SUCCESS) { #if DBG
if (DfsDebug) DbgPrint("DsRoleGetPrimaryDomainInformation returned %d\n", dwErr); #endif
goto Cleanup; }
if (pPrimaryDomainInfo->DomainNameDns == NULL) { #if DBG
if (DfsDebug) DbgPrint(" DomainNameDns is NULL\n", NULL); #endif
dwErr = ERROR_CANT_ACCESS_DOMAIN_INFO; goto Cleanup; }
//
// Get the PDC in that domain
//
dwErr = DsGetDcName( NULL, pPrimaryDomainInfo->DomainNameDns, NULL, NULL, DS_PDC_REQUIRED | DS_FORCE_REDISCOVERY, &pDomainControllerInfo);
if (dwErr != ERROR_SUCCESS) { #if DBG
if (DfsDebug) DbgPrint(" NetpDfsAdd2:DsGetDcName(%ws) returned %d\n", pPrimaryDomainInfo->DomainNameDns, dwErr); #endif
goto Cleanup; }
ENTER_NETDFS_API
//
// Call the server
//
dwErr = DfspAdd2( RootName, DfsEntryPath, &pDomainControllerInfo->DomainControllerName[2], ServerName, ShareName, Comment, Flags);
LEAVE_NETDFS_API
Cleanup:
if (pPrimaryDomainInfo != NULL) DsRoleFreeMemory(pPrimaryDomainInfo);
if (pDomainControllerInfo != NULL) NetApiBufferFree(pDomainControllerInfo);
#if DBG
if (DfsDebug) DbgPrint("NetpDfsAdd2 returning %d\n", dwErr); #endif
return( dwErr );
}
DWORD DfspAdd2( LPWSTR RootName, LPWSTR EntryPath, LPWSTR DcName, LPWSTR ServerName, LPWSTR ShareName, LPWSTR Comment, DWORD Flags) { DWORD dwErr; PDFSM_ROOT_LIST RootList = NULL;
#if DBG
if (DfsDebug) DbgPrint("DfspAdd2(%ws,%ws,%ws,%ws,%ws,%ws,%d)\n", RootName, EntryPath, DcName, ServerName, ShareName, Comment, Flags); #endif
dwErr = DfspBindRpc( RootName, &netdfs_bhandle );
if (dwErr == NERR_Success) {
RpcTryExcept {
dwErr = NetrDfsAdd2( EntryPath, DcName, ServerName, ShareName, Comment, Flags, &RootList);
} RpcExcept(1) {
dwErr = RpcExceptionCode();
} RpcEndExcept;
DfspFreeBinding( netdfs_bhandle );
}
#if DBG
if (DfsDebug) { if (dwErr == ERROR_SUCCESS && RootList != NULL) { ULONG n;
DbgPrint("cEntries=%d\n", RootList->cEntries); for (n = 0; n < RootList->cEntries; n++) DbgPrint("[%d]%ws\n", n, RootList->Entry[n].ServerShare); } } #endif
if (dwErr == ERROR_SUCCESS && RootList != NULL) {
ULONG n;
for (n = 0; n < RootList->cEntries; n++) {
DfspNotifyFtRoot( RootList->Entry[n].ServerShare, DcName);
}
NetApiBufferFree(RootList);
} #if DBG
if (DfsDebug) DbgPrint("DfspAdd2 returning %d\n", dwErr); #endif
return dwErr;
}
//+----------------------------------------------------------------------------
//
// Function: NetDfsAddFtRoot
//
// Synopsis: Creates a new FtDfs, adds a new server to an existing FtDfs.
//
// Arguments: [ServerName] -- Name of server to make a root, or to join to an existing FtDfs.
// [RootShare] -- Name of share hosting the storage.
// [FtDfsName] -- Name of FtDfs to join or create.
// [Comment] -- Optional comment
// [Flags] -- Flags to operation
//
// Returns: [NERR_Success] -- Successfully completed operation.
//
// [ERROR_INVALID_PARAMETER] -- ServerName and/or RootShare are incorrect.
//
// [ERROR_INVALID_NAME] -- Unable to locate server or domain.
//
// [ERROR_DCNotFound] -- Unable to locate DC for DfsName.
//
// [ERROR_NOT_ENOUGH_MEMORY] -- Out of memory condition.
//
// [NERR_DfsInternalCorruption] -- Corruption of Dfs data
// encountered at the server.
//
//-----------------------------------------------------------------------------
NET_API_STATUS NetDfsAddFtRoot( IN LPWSTR ServerName, IN LPWSTR RootShare, IN LPWSTR FtDfsName, IN LPWSTR Comment, IN DWORD Flags) { NET_API_STATUS dwErr; BOOLEAN IsRoot = FALSE; ULONG Timeout = 0; ULONG i; ULONG NameCount; LPWSTR DcName = NULL; PDSROLE_PRIMARY_DOMAIN_INFO_BASIC pPrimaryDomainInfo = NULL; PDOMAIN_CONTROLLER_INFO pDomainControllerInfo = NULL; PDFSM_ROOT_LIST RootList = NULL; #if DBG
if (DfsDebug) DbgPrint("NetDfsAddFtRoot(%ws,%ws,%ws,%ws,%d)\n", ServerName, RootShare, FtDfsName, Comment, Flags); #endif
//
// Validate the string arguments so RPC won't complain...
//
if (!IS_VALID_STRING(ServerName) || !IS_VALID_STRING(RootShare) || !IS_VALID_STRING(FtDfsName)) { return( ERROR_INVALID_PARAMETER ); }
if (FtDfsName[0] == L' ' || DfspIsInvalidName(FtDfsName) == TRUE) { return( ERROR_INVALID_PARAMETER ); }
while (*ServerName == L'\\') { ServerName++; }
if (wcschr(ServerName, L'\\') != NULL) { return (ERROR_INVALID_NAME); }
//
// WE let the server add the root for us. If this fails,
// with invalid parameter, we then get the dc name
// and get the root list for NT5 DFS servers.
//
ENTER_NETDFS_API dwErr = DfspBindToServer( ServerName, &netdfs_bhandle ); if (dwErr == NERR_Success) {
RpcTryExcept {
dwErr = NetrDfsAddFtRoot( ServerName, L"", RootShare, FtDfsName, (Comment != NULL) ? Comment : L"", L"", 0, Flags, &RootList ); #if DBG
if (DfsDebug) DbgPrint("NetrDfsAddFtRoot returned %d\n", dwErr); #endif
} RpcExcept(1) {
dwErr = RpcExceptionCode();
} RpcEndExcept;
DfspFreeBinding( netdfs_bhandle ); } LEAVE_NETDFS_API
if (dwErr != ERROR_INVALID_PARAMETER) { goto Cleanup; } //
// Contact the server and ask for the DC to work with
//
dwErr = NetDfsGetDcAddress( ServerName, &DcName, &IsRoot, &Timeout);
if (dwErr != ERROR_SUCCESS) { #if DBG
if (DfsDebug) DbgPrint("NetDfsGetDcAddress returned %d\n", dwErr); #endif
goto Cleanup; }
if (IsRoot == TRUE) { #if DBG
if (DfsDebug) DbgPrint("Root already exists!\n"); #endif
dwErr = ERROR_ALREADY_EXISTS; goto Cleanup; }
//
// Now get its domain name
//
dwErr = DsRoleGetPrimaryDomainInformation( ServerName, DsRolePrimaryDomainInfoBasic, (PBYTE *)&pPrimaryDomainInfo);
if (dwErr != ERROR_SUCCESS) { #if DBG
if (DfsDebug) DbgPrint("DsRoleGetPrimaryDomainInformation returned %d\n", dwErr); #endif
goto Cleanup; }
if (pPrimaryDomainInfo->DomainNameDns == NULL) { #if DBG
if (DfsDebug) DbgPrint(" DsRoleGetPrimaryDomainInformation returned NULL domain name\n"); #endif
dwErr = ERROR_CANT_ACCESS_DOMAIN_INFO; goto Cleanup; }
//
// Get the PDC in that domain
//
dwErr = DsGetDcName( NULL, pPrimaryDomainInfo->DomainNameDns, NULL, NULL, DS_PDC_REQUIRED | DS_FORCE_REDISCOVERY, &pDomainControllerInfo);
if (dwErr != ERROR_SUCCESS) { #if DBG
if (DfsDebug) DbgPrint("DsGetDcName(%ws) returned %d\n", pPrimaryDomainInfo->DomainNameDns, dwErr); #endif
goto Cleanup; }
ENTER_NETDFS_API
//
// Add the Ds object and tell the server to join itself
//
dwErr = DfspCreateFtDfs( ServerName, &pDomainControllerInfo->DomainControllerName[2], TRUE, RootShare, FtDfsName, Comment, Flags);
if (dwErr != ERROR_SUCCESS) { #if DBG
if (DfsDebug) DbgPrint(" DfspCreateFtDfs returned %d\n", dwErr); #endif
LEAVE_NETDFS_API goto Cleanup; }
//
// Tell the local MUP to crack ftdfs names using the selected DC
//
DfspSetDomainToDc( pPrimaryDomainInfo->DomainNameDns, &pDomainControllerInfo->DomainControllerName[2]);
if (pPrimaryDomainInfo->DomainNameFlat != NULL) { PWCHAR wCp = &pDomainControllerInfo->DomainControllerName[2];
for (; *wCp != L'\0' && *wCp != L'.'; wCp++) /* NOTHING */; *wCp = (*wCp == L'.') ? L'\0' : *wCp; DfspSetDomainToDc( pPrimaryDomainInfo->DomainNameFlat, &pDomainControllerInfo->DomainControllerName[2]); }
LEAVE_NETDFS_API
Cleanup:
if (pPrimaryDomainInfo != NULL) DsRoleFreeMemory(pPrimaryDomainInfo);
if (pDomainControllerInfo != NULL) NetApiBufferFree(pDomainControllerInfo);
if (DcName != NULL) NetApiBufferFree(DcName);
#if DBG
if (DfsDebug) DbgPrint("NetDfsAddFtRoot returning %d\n", dwErr); #endif
return( dwErr );
}
//+----------------------------------------------------------------------------
//
// Function: DfspCompareDsDomainControllerInfo1
//
// Synopsis: Helper/compare func for qsort of DsGetDomainControllerInfo's results
//
//-----------------------------------------------------------------------------
INT _cdecl DfspCompareDsDomainControllerInfo1( const void *p1, const void *p2) { PDS_DOMAIN_CONTROLLER_INFO_1 pInfo1 = (PDS_DOMAIN_CONTROLLER_INFO_1)p1; PDS_DOMAIN_CONTROLLER_INFO_1 pInfo2 = (PDS_DOMAIN_CONTROLLER_INFO_1)p2; UNICODE_STRING s1; UNICODE_STRING s2;
if (pInfo1->DnsHostName == NULL || pInfo2->DnsHostName == NULL) return 0;
RtlInitUnicodeString(&s1, pInfo1->DnsHostName); RtlInitUnicodeString(&s2, pInfo2->DnsHostName);
return RtlCompareUnicodeString(&s1,&s2,TRUE);
}
//+----------------------------------------------------------------------------
//
// Function: NetDfsAddStdRoot
//
// Synopsis: Creates a new Std Dfs.
//
// Arguments: [ServerName] -- Name of server to make a root.
// existing Dfs.
// [RootShare] -- Name of share hosting the storage.
// [Comment] -- Optional comment
// [Flags] -- Flags
//
// Returns: [NERR_Success] -- Successfully completed operation.
//
// [ERROR_INVALID_PARAMETER] -- ServerName and/or RootShare are incorrect.
//
// [ERROR_INVALID_NAME] -- Unable to locate server or domain.
//
// [ERROR_NOT_ENOUGH_MEMORY] -- Out of memory condition.
//
// [NERR_DfsInternalCorruption] -- Corruption of Dfs data
// encountered at the server.
//
//-----------------------------------------------------------------------------
NET_API_STATUS NetDfsAddStdRoot( IN LPWSTR ServerName, IN LPWSTR RootShare, IN LPWSTR Comment, IN DWORD Flags) { NET_API_STATUS dwErr;
#if DBG
if (DfsDebug) DbgPrint("NetDfsAddStdRoot(%ws,%ws,%ws,%d)\n", ServerName, RootShare, Comment, Flags); #endif
//
// Validate the string arguments so RPC won't complain...
//
if (!IS_VALID_STRING(ServerName) || !IS_VALID_STRING(RootShare)) { return( ERROR_INVALID_PARAMETER ); }
ENTER_NETDFS_API
//
// We should have a valid ServerName. Lets try to bind to it,
// and call the server.
//
dwErr = DfspBindToServer( ServerName, &netdfs_bhandle );
if (dwErr == NERR_Success) {
RpcTryExcept {
dwErr = NetrDfsAddStdRoot( ServerName, RootShare, (Comment != NULL) ? Comment : L"", Flags);
} RpcExcept(1) {
dwErr = RpcExceptionCode();
} RpcEndExcept;
DfspFreeBinding( netdfs_bhandle );
}
LEAVE_NETDFS_API
#if DBG
if (DfsDebug) DbgPrint("NetDfsAddStdRoot returning %d\n", dwErr); #endif
return( dwErr );
}
//+----------------------------------------------------------------------------
//
// Function: NetDfsAddStdRootForced
//
// Synopsis: Creates a new Std Dfs, also specifying the share
//
// Arguments: [ServerName] -- Name of server to make a root.
// existing Dfs.
// [RootShare] -- Name of share hosting the storage.
// [Comment] -- Optional comment
// [Share] -- Name of drive:\dir hosting the share
//
// Returns: [NERR_Success] -- Successfully completed operation.
//
// [ERROR_INVALID_PARAMETER] -- ServerName and/or RootShare are incorrect.
//
// [ERROR_INVALID_NAME] -- Unable to locate server or domain.
//
// [ERROR_NOT_ENOUGH_MEMORY] -- Out of memory condition.
//
// [NERR_DfsInternalCorruption] -- Corruption of Dfs data
// encountered at the server.
//
//-----------------------------------------------------------------------------
NET_API_STATUS NetDfsAddStdRootForced( IN LPWSTR ServerName, IN LPWSTR RootShare, IN LPWSTR Comment, IN LPWSTR Share) { NET_API_STATUS dwErr;
#if DBG
if (DfsDebug) DbgPrint("NetDfsAddStdRootForced(%ws,%ws,%ws,%ws)\n", ServerName, RootShare, Comment, Share); #endif
//
// Validate the string arguments so RPC won't complain...
//
if (!IS_VALID_STRING(ServerName) || !IS_VALID_STRING(RootShare) || !IS_VALID_STRING(Share)) { return( ERROR_INVALID_PARAMETER ); }
ENTER_NETDFS_API
//
// We should have a valid ServerName. Lets try to bind to it,
// and call the server.
//
dwErr = DfspBindToServer( ServerName, &netdfs_bhandle );
if (dwErr == NERR_Success) {
RpcTryExcept {
dwErr = NetrDfsAddStdRootForced( ServerName, RootShare, (Comment != NULL) ? Comment : L"", Share);
} RpcExcept(1) {
dwErr = RpcExceptionCode();
} RpcEndExcept;
DfspFreeBinding( netdfs_bhandle );
}
LEAVE_NETDFS_API
#if DBG
if (DfsDebug) DbgPrint("NetDfsAddStdRootForced returning %d\n", dwErr); #endif
return( dwErr );
}
//+----------------------------------------------------------------------------
//
// Function: NetDfsGetDcAddress
//
// Synopsis: Asks a server for its DC to use to place the dfs blob to make
// the server a root.
//
// Arguments: [ServerName] -- Name of server we will be making an FtDfs root
// [DcName] -- DC Name
// [IsRoot] -- TRUE if Server is a root, FALSE otherwise
// [Timeout] -- Timeout the server is using
//
// Returns: [NERR_Success] -- Successfully completed operation.
//
// [ERROR_INVALID_PARAMETER] -- ServerName incorrect.
//
// [ERROR_INVALID_NAME] -- Unable to locate server or domain.
//
// [ERROR_NOT_ENOUGH_MEMORY] -- Out of memory condition.
//
// [NERR_DfsInternalCorruption] -- Corruption of Dfs data
// encountered at the server.
//
//-----------------------------------------------------------------------------
NET_API_STATUS NetDfsGetDcAddress( IN LPWSTR ServerName, IN OUT LPWSTR *DcName, IN OUT BOOLEAN *IsRoot, IN OUT ULONG *Timeout) { NET_API_STATUS dwErr;
#if DBG
if (DfsDebug) DbgPrint("NetDfsGetDcAddress(%ws)\n", ServerName); #endif
//
// Validate the string arguments so RPC won't complain...
//
if (!IS_VALID_STRING(ServerName)|| DcName == NULL || IsRoot == NULL || Timeout == NULL) { return( ERROR_INVALID_PARAMETER ); }
ENTER_NETDFS_API
//
// We should have a valid ServerName. Lets try to bind to it,
// and call the server.
//
dwErr = DfspBindToServer( ServerName, &netdfs_bhandle );
if (dwErr == NERR_Success) {
RpcTryExcept {
dwErr = NetrDfsGetDcAddress( ServerName, DcName, IsRoot, Timeout);
} RpcExcept(1) {
dwErr = RpcExceptionCode();
} RpcEndExcept;
DfspFreeBinding( netdfs_bhandle );
}
LEAVE_NETDFS_API
#if DBG
if (DfsDebug) DbgPrint("NetDfsGetDcAddress: returned %d\n", dwErr); #endif
return( dwErr );
}
//+----------------------------------------------------------------------------
//
// Function: NetDfsRemove
//
// Synopsis: Deletes a Dfs volume, removes a replica from an existing
// volume, or removes a link to another Dfs.
//
// Arguments: [DfsEntryPath] -- Name of volume/link to remove.
// [ServerName] -- Name of server hosting the storage. Must be
// NULL if removing Link.
// [ShareName] -- Name of share hosting the storage. Must be
// NULL if removing Link.
//
// Returns: [NERR_Success] -- Successfully completed operation.
//
// [ERROR_INVALID_PARAMETER] -- DfsEntryPath is incorrect.
//
// [ERROR_INVALID_NAME] -- Unable to locate server or domain.
//
// [ERROR_DCNotFound] -- Unable to locate DC for DfsName.
//
// [ERROR_NOT_ENOUGH_MEMORY] -- Out of memory condition.
//
// [NERR_DfsNoSuchVolume] -- DfsEntryPath does not correspond to
// a valid entry path.
//
// [NERR_DfsNotALeafVolume] -- Unable to delete the volume
// because it is not a leaf volume.
//
// [NERR_DfsInternalCorruption] -- Corruption of Dfs data
// encountered at the server.
//
//-----------------------------------------------------------------------------
NET_API_STATUS NetDfsRemove( IN LPWSTR DfsEntryPath, IN LPWSTR ServerName, IN LPWSTR ShareName) { NET_API_STATUS dwErr; DWORD cwDfsEntryPath; LPWSTR pwszDfsName = NULL;
#if DBG
if (DfsDebug) DbgPrint("NetDfsRemove(%ws,%ws,%ws)\n", DfsEntryPath, ServerName, ShareName); #endif
//
// Validate the string arguments so RPC won't complain...
//
if (!IS_VALID_STRING(DfsEntryPath)) { return( ERROR_INVALID_PARAMETER ); }
cwDfsEntryPath = wcslen(DfsEntryPath);
if (!IS_UNC_PATH(DfsEntryPath, cwDfsEntryPath) && !IS_VALID_PREFIX(DfsEntryPath, cwDfsEntryPath) && !IS_VALID_DFS_PATH(DfsEntryPath, cwDfsEntryPath)) { return( ERROR_INVALID_PARAMETER ); }
dwErr = DfspGetMachineNameFromEntryPath( DfsEntryPath, cwDfsEntryPath, &pwszDfsName);
ENTER_NETDFS_API
if (dwErr == NERR_Success) {
dwErr = DfspBindRpc(pwszDfsName, &netdfs_bhandle);
if (dwErr == NERR_Success) {
RpcTryExcept {
dwErr = NetrDfsRemove( DfsEntryPath, ServerName, ShareName);
} RpcExcept(1) {
dwErr = RpcExceptionCode();
} RpcEndExcept;
DfspFreeBinding( netdfs_bhandle );
}
}
LEAVE_NETDFS_API
//
// If we failed with ERROR_NOT_SUPPORTED, this is an NT5+ server,
// so we use the NetrDfsRemove2() call instead.
//
if (dwErr == ERROR_NOT_SUPPORTED) {
dwErr = NetpDfsRemove2( pwszDfsName, DfsEntryPath, ServerName, ShareName); }
//
// If we removed things from a dfs, the local pkt
// may now be out of date. [92216]
// Flush the local pkt
//
if (dwErr == NERR_Success) {
DfspFlushPkt(DfsEntryPath);
}
if (pwszDfsName != NULL) free( pwszDfsName );
#if DBG
if (DfsDebug) DbgPrint("NetDfsRemove returning %d\n", dwErr); #endif
return( dwErr );
}
DWORD NetpDfsRemove2( LPWSTR RootName, LPWSTR DfsEntryPath, LPWSTR ServerName, LPWSTR ShareName) { NET_API_STATUS dwErr; ULONG i; ULONG NameCount; PDSROLE_PRIMARY_DOMAIN_INFO_BASIC pPrimaryDomainInfo = NULL; PDS_DOMAIN_CONTROLLER_INFO_1 pDsDomainControllerInfo1 = NULL; PDOMAIN_CONTROLLER_INFO pDomainControllerInfo = NULL; HANDLE hDs = NULL;
#if DBG
if (DfsDebug) DbgPrint("NetpDfsRemove2(%ws,%ws,%ws,%ws)\n", RootName, DfsEntryPath, ServerName, ShareName); #endif
//
// Ask for its domain name
//
dwErr = DsRoleGetPrimaryDomainInformation( RootName, DsRolePrimaryDomainInfoBasic, (PBYTE *)&pPrimaryDomainInfo);
if (dwErr != ERROR_SUCCESS) { #if DBG
if (DfsDebug) DbgPrint(" DsRoleGetPrimaryDomainInformation returned %d\n", dwErr); #endif
goto Cleanup; }
if (pPrimaryDomainInfo->DomainNameDns == NULL) { #if DBG
if (DfsDebug) DbgPrint(" DomainNameDns is NULL\n"); #endif
dwErr = ERROR_CANT_ACCESS_DOMAIN_INFO; goto Cleanup; }
//
// Get the PDC in that domain
//
dwErr = DsGetDcName( NULL, pPrimaryDomainInfo->DomainNameDns, NULL, NULL, DS_PDC_REQUIRED | DS_FORCE_REDISCOVERY, &pDomainControllerInfo);
if (dwErr != ERROR_SUCCESS) { #if DBG
if (DfsDebug) DbgPrint(" DsGetDcName(%ws) returned %d\n", pPrimaryDomainInfo->DomainNameDns); #endif
goto Cleanup; }
ENTER_NETDFS_API
//
// Tell the root server to remove this server/share
//
dwErr = DfspRemove2( RootName, DfsEntryPath, &pDomainControllerInfo->DomainControllerName[2], ServerName, ShareName);
LEAVE_NETDFS_API
if (dwErr != ERROR_SUCCESS) { #if DBG
if (DfsDebug) DbgPrint(" DfspRemove2 returned %d\n"); #endif
goto Cleanup; }
Cleanup:
if (pDomainControllerInfo != NULL) NetApiBufferFree(pDomainControllerInfo);
if (pPrimaryDomainInfo != NULL) DsRoleFreeMemory(pPrimaryDomainInfo);
#if DBG
if (DfsDebug) DbgPrint("NetpDfsRemove2 returning %d\n", dwErr); #endif
return( dwErr );
}
DWORD DfspRemove2( LPWSTR RootName, LPWSTR EntryPath, LPWSTR DcName, LPWSTR ServerName, LPWSTR ShareName) { DWORD dwErr; PDFSM_ROOT_LIST RootList = NULL;
#if DBG
if (DfsDebug) DbgPrint("DfspRemove2(%ws,%ws,%ws,%ws,%ws)\n", RootName, EntryPath, DcName, ServerName, ShareName); #endif
dwErr = DfspBindRpc( RootName, &netdfs_bhandle );
if (dwErr == NERR_Success) {
RpcTryExcept {
dwErr = NetrDfsRemove2( EntryPath, DcName, ServerName, ShareName, &RootList);
} RpcExcept(1) {
dwErr = RpcExceptionCode();
} RpcEndExcept;
DfspFreeBinding( netdfs_bhandle );
}
#if DBG
if (DfsDebug) { if (dwErr == ERROR_SUCCESS && RootList != NULL) { ULONG n;
DbgPrint("cEntries=%d\n", RootList->cEntries); for (n = 0; n < RootList->cEntries; n++) DbgPrint("[%d]%ws\n", n, RootList->Entry[n].ServerShare); } } #endif
if (dwErr == ERROR_SUCCESS && RootList != NULL) {
ULONG n;
for (n = 0; n < RootList->cEntries; n++) {
DfspNotifyFtRoot( RootList->Entry[n].ServerShare, DcName);
}
NetApiBufferFree(RootList);
}
#if DBG
if (DfsDebug) DbgPrint("DfspRemove2 returning %d\n", dwErr); #endif
return dwErr;
}
//+----------------------------------------------------------------------------
//
// Function: NetDfsRemoveFtRoot
//
// Synopsis: Deletes an FtDfs root, or unjoins a Server from an FtDfs as a root.
//
// Arguments: [ServerName] -- Name of server to unjoin from FtDfs.
// [RootShare] -- Name of share hosting the storage.
// [FtDfsName] -- Name of FtDfs to remove server from.
// [Flags] -- Flags to operation
//
// Returns: [NERR_Success] -- Successfully completed operation.
//
// [ERROR_INVALID_PARAMETER] -- ServerName and/or FtDfsName is incorrect.
//
// [ERROR_INVALID_NAME] -- Unable to locate server or domain.
//
// [ERROR_DCNotFound] -- Unable to locate DC for ServerName
//
// [ERROR_NOT_ENOUGH_MEMORY] -- Out of memory condition.
//
// [NERR_DfsNoSuchVolume] -- FtDfsName does not correspond to
// a valid FtDfs.
//
// [NERR_DfsNotALeafVolume] -- Unable to delete the volume
// because it is not a leaf volume.
//
// [NERR_DfsInternalCorruption] -- Corruption of Dfs data
// encountered at the server.
//
//-----------------------------------------------------------------------------
NET_API_STATUS NetDfsRemoveFtRoot( IN LPWSTR ServerName, IN LPWSTR RootShare, IN LPWSTR FtDfsName, IN DWORD Flags) { NET_API_STATUS dwErr; LPWSTR DcName = NULL; BOOLEAN IsRoot = FALSE; ULONG Timeout = 0; ULONG i; ULONG NameCount; PDSROLE_PRIMARY_DOMAIN_INFO_BASIC pPrimaryDomainInfo = NULL; PDOMAIN_CONTROLLER_INFO pDomainControllerInfo = NULL; PDFSM_ROOT_LIST RootList = NULL;
#if DBG
if (DfsDebug) DbgPrint("NetDfsRemoveFtRoot(%ws,%ws,%ws,%d)\n", ServerName, RootShare, FtDfsName, Flags); #endif
//
// Validate the string arguments so RPC won't complain...
//
if (!IS_VALID_STRING(ServerName) || !IS_VALID_STRING(RootShare) || !IS_VALID_STRING(FtDfsName)) { return( ERROR_INVALID_PARAMETER ); }
while (*ServerName == L'\\') { ServerName++; }
if (wcschr(ServerName, L'\\') != NULL) { return (ERROR_INVALID_NAME); }
//
// we first allow the server to do all the work, so pass in null
// as dc name and root list. If that fails with error_invalid_param
// we know we are dealing with a NT5 server, so go into compat mode.
//
ENTER_NETDFS_API dwErr = DfspBindToServer( ServerName, &netdfs_bhandle ); if (dwErr == NERR_Success) {
RpcTryExcept {
dwErr = NetrDfsRemoveFtRoot( ServerName, L"", RootShare, FtDfsName, Flags, &RootList );
#if DBG
if (DfsDebug) DbgPrint("NetrDfsAddFtRoot returned %d\n", dwErr); #endif
} RpcExcept(1) {
dwErr = RpcExceptionCode();
} RpcEndExcept;
DfspFreeBinding( netdfs_bhandle ); } LEAVE_NETDFS_API
if (dwErr != ERROR_INVALID_PARAMETER) { goto Cleanup; } //
// Contact the server and ask for the DC to work with
//
#if 0
dwErr = NetDfsGetDcAddress( ServerName, &DcName, &IsRoot, &Timeout);
if (dwErr != ERROR_SUCCESS) { return dwErr; }
if (IsRoot == FALSE) { dwErr = ERROR_SERVICE_DOES_NOT_EXIST; goto Cleanup; } #endif
//
// Now ask it for its dns and domain names
//
dwErr = DsRoleGetPrimaryDomainInformation( ServerName, DsRolePrimaryDomainInfoBasic, (PBYTE *)&pPrimaryDomainInfo);
if (dwErr != ERROR_SUCCESS) { #if DBG
if (DfsDebug) DbgPrint("DsRoleGetPrimaryDomainInformation returned %d\n", dwErr); #endif
goto Cleanup; }
if (pPrimaryDomainInfo->DomainNameDns == NULL) { #if DBG
if (DfsDebug) DbgPrint("DsRoleGetPrimaryDomainInformation returned NULL domain name\n"); #endif
dwErr = ERROR_CANT_ACCESS_DOMAIN_INFO; goto Cleanup; }
//
// Get the PDC in that domain
//
dwErr = DsGetDcName( NULL, pPrimaryDomainInfo->DomainNameDns, NULL, NULL, DS_PDC_REQUIRED | DS_FORCE_REDISCOVERY, &pDomainControllerInfo);
if (dwErr != ERROR_SUCCESS) { #if DBG
if (DfsDebug) DbgPrint(" DsGetDcName(%ws) returned %d\n", pPrimaryDomainInfo->DomainNameDns, dwErr); #endif
goto Cleanup; }
ENTER_NETDFS_API
//
// Tell the server to unjoin and update the Ds object
//
dwErr = DfspTearDownFtDfs( ServerName, &pDomainControllerInfo->DomainControllerName[2], RootShare, FtDfsName, Flags);
if (dwErr != ERROR_SUCCESS) { #if DBG
if (DfsDebug) DbgPrint(" DfspTearDownFtDfs returned %d\n", dwErr); #endif
LEAVE_NETDFS_API goto Cleanup; }
//
// Tell the local MUP to crack ftdfs names using the selected DC
//
DfspSetDomainToDc( pPrimaryDomainInfo->DomainNameDns, &pDomainControllerInfo->DomainControllerName[2]);
if (pPrimaryDomainInfo->DomainNameFlat != NULL) { PWCHAR wCp = &pDomainControllerInfo->DomainControllerName[2];
for (; *wCp != L'\0' && *wCp != L'.'; wCp++) /* NOTHING */; *wCp = (*wCp == L'.') ? L'\0' : *wCp; DfspSetDomainToDc( pPrimaryDomainInfo->DomainNameFlat, &pDomainControllerInfo->DomainControllerName[2]); }
LEAVE_NETDFS_API
Cleanup:
if (pDomainControllerInfo != NULL) NetApiBufferFree(pDomainControllerInfo);
if (DcName != NULL) NetApiBufferFree(DcName);
#if DBG
if (DfsDebug) DbgPrint("NetDfsRemoveFtRoot returning %d\n", dwErr); #endif
return( dwErr );
}
//+----------------------------------------------------------------------------
//
// Function: NetDfsRemoveFtRootForced
//
// Synopsis: Deletes an FtDfs root, or unjoins a Server from an FtDfs as a root.
// Does not contact the root/server to do so - it simply updates the DS.
//
// Arguments: [DomainName] -- Name of domain the server is in.
// [ServerName] -- Name of server to unjoin from FtDfs.
// [RootShare] -- Name of share hosting the storage.
// [FtDfsName] -- Name of FtDfs to remove server from.
// [Flags] -- Flags to operation
//
// Returns: [NERR_Success] -- Successfully completed operation.
//
// [ERROR_INVALID_PARAMETER] -- ServerName and/or FtDfsName is incorrect.
//
// [ERROR_INVALID_NAME] -- Unable to locate server or domain.
//
// [ERROR_DCNotFound] -- Unable to locate DC for ServerName
//
// [ERROR_NOT_ENOUGH_MEMORY] -- Out of memory condition.
//
// [NERR_DfsNoSuchVolume] -- FtDfsName does not correspond to
// a valid FtDfs.
//
// [NERR_DfsNotALeafVolume] -- Unable to delete the volume
// because it is not a leaf volume.
//
// [NERR_DfsInternalCorruption] -- Corruption of Dfs data
// encountered at the server.
//
//-----------------------------------------------------------------------------
NET_API_STATUS NetDfsRemoveFtRootForced( IN LPWSTR DomainName, IN LPWSTR ServerName, IN LPWSTR RootShare, IN LPWSTR FtDfsName, IN DWORD Flags) { NET_API_STATUS dwErr; LPWSTR DcName = NULL; BOOLEAN IsRoot = FALSE; ULONG Timeout = 0; ULONG i; ULONG NameCount; PDSROLE_PRIMARY_DOMAIN_INFO_BASIC pPrimaryDomainInfo = NULL; PDOMAIN_CONTROLLER_INFO pDomainControllerInfo = NULL;
#if DBG
if (DfsDebug) DbgPrint("NetDfsRemoveFtrootForced(%ws,%ws,%ws,%ws,%d)\n", DomainName, ServerName, RootShare, FtDfsName, Flags); #endif
//
// Validate the string arguments so RPC won't complain...
//
if (!IS_VALID_STRING(DomainName) || !IS_VALID_STRING(ServerName) || !IS_VALID_STRING(RootShare) || !IS_VALID_STRING(FtDfsName)) { return( ERROR_INVALID_PARAMETER ); }
while (*ServerName == L'\\') { ServerName++; }
if (wcschr(ServerName, L'\\') != NULL) { return (ERROR_INVALID_NAME); }
//
// Get the PDC in the domain
//
dwErr = DsGetDcName( NULL, DomainName, NULL, NULL, DS_PDC_REQUIRED | DS_FORCE_REDISCOVERY, &pDomainControllerInfo);
if (dwErr != ERROR_SUCCESS) { #if DBG
if (DfsDebug) DbgPrint(" DsGetDcName(%ws) returned %d\n", DomainName, dwErr); #endif
goto Cleanup; }
//
// Get the Dns name of the domain the DC is in
//
dwErr = DsRoleGetPrimaryDomainInformation( &pDomainControllerInfo->DomainControllerName[2], DsRolePrimaryDomainInfoBasic, (PBYTE *)&pPrimaryDomainInfo);
if (dwErr != ERROR_SUCCESS) { #if DBG
if (DfsDebug) DbgPrint(" DsRoleGetPrimaryDomainInformation(%ws) returned %d\n", &pDomainControllerInfo->DomainControllerName[2], dwErr); #endif
goto Cleanup; }
if (pPrimaryDomainInfo->DomainNameDns == NULL) { #if DBG
if (DfsDebug) DbgPrint(" DomainNameDns is NULL\n"); #endif
dwErr = ERROR_CANT_ACCESS_DOMAIN_INFO; goto Cleanup; }
ENTER_NETDFS_API
//
// Tell the DC to remove the server from the DS objects
//
dwErr = DfspTearDownFtDfs( ServerName, &pDomainControllerInfo->DomainControllerName[2], RootShare, FtDfsName, Flags | DFS_FORCE_REMOVE);
if (dwErr != ERROR_SUCCESS) { #if DBG
if (DfsDebug) DbgPrint(" DfspTearDownFtDfs returned %d\n", dwErr); #endif
LEAVE_NETDFS_API goto Cleanup; }
//
// Tell the local MUP to crack ftdfs names using the selected DC
//
DfspSetDomainToDc( pPrimaryDomainInfo->DomainNameDns, &pDomainControllerInfo->DomainControllerName[2]);
if (pPrimaryDomainInfo->DomainNameFlat != NULL) { PWCHAR wCp = &pDomainControllerInfo->DomainControllerName[2];
for (; *wCp != L'\0' && *wCp != L'.'; wCp++) /* NOTHING */; *wCp = (*wCp == L'.') ? L'\0' : *wCp; DfspSetDomainToDc( pPrimaryDomainInfo->DomainNameFlat, &pDomainControllerInfo->DomainControllerName[2]); }
LEAVE_NETDFS_API
Cleanup:
if (pDomainControllerInfo != NULL) NetApiBufferFree(pDomainControllerInfo);
if (pPrimaryDomainInfo != NULL) DsRoleFreeMemory(pPrimaryDomainInfo);
if (DcName != NULL) NetApiBufferFree(DcName);
#if DBG
if (DfsDebug) DbgPrint("NetDfsRemoveFtRootForced returning %d\n", dwErr); #endif
return( dwErr );
}
//+----------------------------------------------------------------------------
//
// Function: NetDfsRemoveStdRoot
//
// Synopsis: Deletes a Dfs root.
//
// Arguments: [ServerName] -- Name of server to unjoin from Dfs.
// [RootShare] -- Name of share hosting the storage.
// [Flags] -- Flags to operation
//
// Returns: [NERR_Success] -- Successfully completed operation.
//
// [ERROR_INVALID_PARAMETER] -- ServerName and/or RootShare is incorrect.
//
// [ERROR_INVALID_NAME] -- Unable to locate server or domain.
//
// [ERROR_NOT_ENOUGH_MEMORY] -- Out of memory condition.
//
// [NERR_DfsNotALeafVolume] -- Unable to delete the volume
// because it is not a leaf volume.
//
// [NERR_DfsInternalCorruption] -- Corruption of Dfs data
// encountered at the server.
//
//-----------------------------------------------------------------------------
NET_API_STATUS NetDfsRemoveStdRoot( IN LPWSTR ServerName, IN LPWSTR RootShare, IN DWORD Flags) { NET_API_STATUS dwErr;
#if DBG
if (DfsDebug) DbgPrint("NetDfsRemoveStdRoot(%ws,%ws,%d)\n", ServerName, RootShare, Flags); #endif
//
// Validate the string arguments so RPC won't complain...
//
if (!IS_VALID_STRING(ServerName) || !IS_VALID_STRING(RootShare)) { return( ERROR_INVALID_PARAMETER ); }
ENTER_NETDFS_API
dwErr = DfspBindToServer(ServerName, &netdfs_bhandle);
if (dwErr == NERR_Success) {
RpcTryExcept {
dwErr = NetrDfsRemoveStdRoot( ServerName, RootShare, Flags);
} RpcExcept(1) {
dwErr = RpcExceptionCode();
} RpcEndExcept;
DfspFreeBinding( netdfs_bhandle );
}
LEAVE_NETDFS_API
#if DBG
if (DfsDebug) DbgPrint("NetDfsRemoveStdRoot returning %d\n", dwErr); #endif
return( dwErr );
}
//+----------------------------------------------------------------------------
//
// Function: NetDfsSetInfo
//
// Synopsis: Sets the comment or state of a Dfs volume or Replica.
//
// Arguments: [DfsEntryPath] -- Path to the volume. Implicityly indicates
// which server or domain to connect to.
// [ServerName] -- Optional. If specified, only the state of
// the server supporting this volume is modified.
// [ShareName] -- Optional. If specified, only the state of
// this share on the specified server is modified.
// [Level] -- Must be 100 or 101
// [Buffer] -- Pointer to DFS_INFO_100 or DFS_INFO_101
//
// Returns: [NERR_Success] -- If successfully set info.
//
// [ERROR_INVALID_LEVEL] -- Level is not 100 or 101, 102
//
// [ERROR_INVALID_PARAMETER] -- Either DfsEntryPath is NULL,
// or ShareName is specified but ServerName is not, or
// Buffer is NULL.
//
// [ERROR_INVALID_NAME] -- Unable to locate server or domain.
//
// [ERROR_DCNotFound] -- Unable to locate DC for domain.
//
// [ERROR_NOT_ENOUGH_MEMORY] -- Out of memory condition.
//
// [NERR_DfsNoSuchVolume] -- No volume matches DfsEntryPath.
//
// [NERR_DfsNoSuchShare] -- The indicated ServerName/ShareName do
// not support this Dfs volume.
//
// [NERR_DfsInternalCorruption] -- Corruption of Dfs data
// encountered at the server.
//
//-----------------------------------------------------------------------------
NET_API_STATUS NET_API_FUNCTION NetDfsSetInfo( IN LPWSTR DfsEntryPath, IN LPWSTR ServerName OPTIONAL, IN LPWSTR ShareName OPTIONAL, IN DWORD Level, IN LPBYTE Buffer) { NET_API_STATUS dwErr = NERR_Success; LPWSTR pwszDfsName = NULL; DWORD cwDfsEntryPath; DFS_INFO_STRUCT DfsInfo;
#if DBG
if (DfsDebug) DbgPrint("NetDfsSetInfo(%ws,%ws,%ws,%d)\n", DfsEntryPath, ServerName, ShareName, Level); #endif
if (!IS_VALID_STRING(DfsEntryPath)) { return( ERROR_INVALID_PARAMETER ); }
//
// Some elementary parameter checking to make sure we can proceed
// reasonably...
//
if (!(Level >= 100 && Level <= 102)) { return( ERROR_INVALID_LEVEL ); }
cwDfsEntryPath = wcslen(DfsEntryPath);
if (!IS_UNC_PATH(DfsEntryPath, cwDfsEntryPath) && !IS_VALID_PREFIX(DfsEntryPath, cwDfsEntryPath) && !IS_VALID_DFS_PATH(DfsEntryPath, cwDfsEntryPath)) { return( ERROR_INVALID_PARAMETER ); }
if (!IS_VALID_STRING(ServerName) && IS_VALID_STRING(ShareName)) { return( ERROR_INVALID_PARAMETER ); }
if (Level == 101) { DFS_INFO_STRUCT DfsUseInfo;
DfsUseInfo.DfsInfo101 = (LPDFS_INFO_101)Buffer; if ( (DfsUseInfo.DfsInfo101->State == DFS_VOLUME_STATE_RESYNCHRONIZE) || (DfsUseInfo.DfsInfo101->State == DFS_VOLUME_STATE_STANDBY) ) { dwErr = DfspGetDfsNameFromEntryPath( DfsEntryPath, cwDfsEntryPath, &pwszDfsName ); } }
if ((dwErr == NERR_Success) && (pwszDfsName == NULL)) { dwErr = DfspGetMachineNameFromEntryPath(DfsEntryPath, cwDfsEntryPath, &pwszDfsName); }
ENTER_NETDFS_API
if (dwErr == NERR_Success) {
//
// By now, we should have a valid pwszDfsName. Lets try to bind to it,
// and call the server.
//
dwErr = DfspBindRpc( pwszDfsName, &netdfs_bhandle );
if (dwErr == NERR_Success) {
RpcTryExcept {
DfsInfo.DfsInfo100 = (LPDFS_INFO_100) Buffer;
dwErr = NetrDfsSetInfo( DfsEntryPath, ServerName, ShareName, Level, &DfsInfo);
} RpcExcept( 1 ) {
dwErr = RpcExceptionCode();
} RpcEndExcept;
DfspFreeBinding( netdfs_bhandle );
}
}
LEAVE_NETDFS_API
//
// If we failed with ERROR_NOT_SUPPORTED, this is an NT5+ server,
// so we use the NetrDfsSetInfo2() call instead.
//
if (dwErr == ERROR_NOT_SUPPORTED) {
dwErr = NetpDfsSetInfo2( pwszDfsName, DfsEntryPath, ServerName, ShareName, Level, &DfsInfo); }
if (pwszDfsName != NULL) free(pwszDfsName);
#if DBG
if (DfsDebug) DbgPrint("NetDfsSetInfo returning %d\n", dwErr); #endif
return( dwErr );
}
DWORD NetpDfsSetInfo2( LPWSTR RootName, LPWSTR DfsEntryPath, LPWSTR ServerName, LPWSTR ShareName, DWORD Level, LPDFS_INFO_STRUCT pDfsInfo) { NET_API_STATUS dwErr; ULONG i; ULONG NameCount; PDSROLE_PRIMARY_DOMAIN_INFO_BASIC pPrimaryDomainInfo = NULL; PDOMAIN_CONTROLLER_INFO pDomainControllerInfo = NULL;
#if DBG
if (DfsDebug) DbgPrint("NetpDfsSetInfo2(%ws,%ws,%ws,%ws,%d)\n", RootName, DfsEntryPath, ServerName, ShareName, Level); #endif
//
// Contact the server and ask for its domain name
//
dwErr = DsRoleGetPrimaryDomainInformation( RootName, DsRolePrimaryDomainInfoBasic, (PBYTE *)&pPrimaryDomainInfo);
if (dwErr != ERROR_SUCCESS) { #if DBG
if (DfsDebug) DbgPrint("DsRoleGetPrimaryDomainInformation returned %d\n", dwErr); #endif
goto Cleanup; }
if (pPrimaryDomainInfo->DomainNameDns == NULL) { #if DBG
if (DfsDebug) DbgPrint(" DomainNameDns is NULL\n", NULL); #endif
dwErr = ERROR_CANT_ACCESS_DOMAIN_INFO; goto Cleanup; }
//
// Get the PDC in that domain
//
dwErr = DsGetDcName( NULL, pPrimaryDomainInfo->DomainNameDns, NULL, NULL, DS_PDC_REQUIRED | DS_FORCE_REDISCOVERY, &pDomainControllerInfo);
if (dwErr != ERROR_SUCCESS) { #if DBG
if (DfsDebug) DbgPrint(" NetpDfsSetInfo2:DsGetDcName(%ws) returned %d\n", pPrimaryDomainInfo->DomainNameDns, dwErr); #endif
goto Cleanup; }
ENTER_NETDFS_API
//
// Call the server
//
dwErr = DfspSetInfo2( RootName, DfsEntryPath, &pDomainControllerInfo->DomainControllerName[2], ServerName, ShareName, Level, pDfsInfo);
LEAVE_NETDFS_API
Cleanup:
if (pPrimaryDomainInfo != NULL) DsRoleFreeMemory(pPrimaryDomainInfo);
if (pDomainControllerInfo != NULL) NetApiBufferFree(pDomainControllerInfo);
#if DBG
if (DfsDebug) DbgPrint("NetpDfsSetInfo2 returning %d\n", dwErr); #endif
return( dwErr );
}
DWORD DfspSetInfo2( LPWSTR RootName, LPWSTR EntryPath, LPWSTR DcName, LPWSTR ServerName, LPWSTR ShareName, DWORD Level, LPDFS_INFO_STRUCT pDfsInfo) { DWORD dwErr; PDFSM_ROOT_LIST RootList = NULL;
#if DBG
if (DfsDebug) DbgPrint("DfspSetInfo2(%ws,%ws,%ws,%ws,%ws,%d)\n", RootName, EntryPath, DcName, ServerName, ShareName, Level); #endif
dwErr = DfspBindRpc( RootName, &netdfs_bhandle );
if (dwErr == NERR_Success) {
RpcTryExcept {
dwErr = NetrDfsSetInfo2( EntryPath, DcName, ServerName, ShareName, Level, pDfsInfo, &RootList);
} RpcExcept(1) {
dwErr = RpcExceptionCode();
} RpcEndExcept;
DfspFreeBinding( netdfs_bhandle );
}
#if DBG
if (DfsDebug) { if (dwErr == ERROR_SUCCESS && RootList != NULL) { ULONG n;
DbgPrint("cEntries=%d\n", RootList->cEntries); for (n = 0; n < RootList->cEntries; n++) DbgPrint("[%d]%ws\n", n, RootList->Entry[n].ServerShare); } } #endif
if (dwErr == ERROR_SUCCESS && RootList != NULL) {
ULONG n;
for (n = 0; n < RootList->cEntries; n++) {
DfspNotifyFtRoot( RootList->Entry[n].ServerShare, DcName);
}
NetApiBufferFree(RootList);
} #if DBG
if (DfsDebug) DbgPrint("DfspSetInfo2 returning %d\n", dwErr); #endif
return dwErr;
}
//+----------------------------------------------------------------------------
//
// Function: NetDfsGetInfo
//
// Synopsis: Retrieves information about a particular Dfs volume.
//
// Arguments: [DfsEntryPath] -- Path to the volume. Implicitly indicates
// which server or domain to connect to.
// [ServerName] -- Optional. If specified, indicates the
// server supporting DfsEntryPath.
// [ShareName] -- Optional. If specified, indicates the share
// on ServerName for which info is desired.
// [Level] -- Indicates the level of info required.
// [Buffer] -- On successful return, will contain the buffer
// containing the required Info. This buffer should be
// freed using NetApiBufferFree.
//
// Returns: [NERR_Success] -- Info successfully returned.
//
// [ERROR_INVALID_LEVEL] -- Level is not 1,2,3 or 100
//
// [ERROR_INVALID_PARAMETER] -- Either DfsEntryPath is NULL,
// or ShareName is specified but ServerName is NULL.
//
// [ERROR_INVALID_NAME] -- Unable to locate server or domain.
//
// [ERROR_DCNotFound] -- Unable to locate DC for domain.
//
// [ERROR_NOT_ENOUGH_MEMORY] -- Out of memory condition.
//
// [NERR_DfsNoSuchVolume] -- No volume matches DfsEntryPath.
//
// [NERR_DfsInternalCorruption] -- Corruption of Dfs data
// encountered at the server.
//
//-----------------------------------------------------------------------------
NET_API_STATUS NET_API_FUNCTION NetDfsGetInfo( IN LPWSTR DfsEntryPath, IN LPWSTR ServerName OPTIONAL, IN LPWSTR ShareName OPTIONAL, IN DWORD Level, OUT LPBYTE* Buffer) { NET_API_STATUS dwErr; LPWSTR pwszDfsName; DWORD cwDfsEntryPath; DFS_INFO_STRUCT DfsInfo;
#if DBG
if (DfsDebug) DbgPrint("NetDfsGetInfo(%ws,%ws,%ws,%d)\n", DfsEntryPath, ServerName, ShareName, Level); #endif
if (!IS_VALID_STRING(DfsEntryPath)) { return( ERROR_INVALID_PARAMETER ); }
//
// Some elementary parameter checking to make sure we can proceed
// reasonably...
//
if (!(Level >= 1 && Level <= 4) && Level != 100) { return( ERROR_INVALID_LEVEL ); }
cwDfsEntryPath = wcslen(DfsEntryPath);
if (!IS_UNC_PATH(DfsEntryPath, cwDfsEntryPath) && !IS_VALID_PREFIX(DfsEntryPath, cwDfsEntryPath) && !IS_VALID_DFS_PATH(DfsEntryPath, cwDfsEntryPath)) { return( ERROR_INVALID_PARAMETER ); }
if (!IS_VALID_STRING(ServerName) && IS_VALID_STRING(ShareName)) { return( ERROR_INVALID_PARAMETER ); }
dwErr = DfspGetMachineNameFromEntryPath( DfsEntryPath, cwDfsEntryPath, &pwszDfsName);
ENTER_NETDFS_API
if (dwErr == NERR_Success) {
//
// By now, we should have a valid pwszDfsName. Lets try to bind to it,
// and call the server.
//
dwErr = DfspBindRpc( pwszDfsName, &netdfs_bhandle );
if (dwErr == NERR_Success) {
RpcTryExcept {
DfsInfo.DfsInfo1 = NULL;
dwErr = NetrDfsGetInfo( DfsEntryPath, ServerName, ShareName, Level, &DfsInfo);
if (dwErr == NERR_Success) {
*Buffer = (LPBYTE) DfsInfo.DfsInfo1;
}
} RpcExcept( 1 ) {
dwErr = RpcExceptionCode();
} RpcEndExcept;
DfspFreeBinding( netdfs_bhandle );
}
free( pwszDfsName );
}
LEAVE_NETDFS_API
#if DBG
if (DfsDebug) DbgPrint("NetDfsGetInfo returning %d\n", dwErr); #endif
return( dwErr );
}
//+----------------------------------------------------------------------------
//
// Function: NetDfsGetClientInfo
//
// Synopsis: Retrieves information about a particular Dfs volume, from the
// local PKT.
//
// Arguments: [DfsEntryPath] -- Path to the volume.
// [ServerName] -- Optional. If specified, indicates the
// server supporting DfsEntryPath.
// [ShareName] -- Optional. If specified, indicates the share
// on ServerName for which info is desired.
// [Level] -- Indicates the level of info required.
// [Buffer] -- On successful return, will contain the buffer
// containing the required Info. This buffer should be
// freed using NetApiBufferFree.
//
// Returns: [NERR_Success] -- Info successfully returned.
//
// [ERROR_INVALID_LEVEL] -- Level is not 1,2,3 or 4.
//
// [ERROR_INVALID_PARAMETER] -- Either DfsEntryPath is NULL,
// or ShareName is specified but ServerName is NULL.
//
// [ERROR_NOT_ENOUGH_MEMORY] -- Out of memory condition.
//
// [NERR_DfsNoSuchVolume] -- No volume matches DfsEntryPath.
//
// [NERR_DfsInternalError] -- Too many fsctrl attempts
//
//-----------------------------------------------------------------------------
NET_API_STATUS NET_API_FUNCTION NetDfsGetClientInfo( IN LPWSTR DfsEntryPath, IN LPWSTR ServerName OPTIONAL, IN LPWSTR ShareName OPTIONAL, IN DWORD Level, OUT LPBYTE* Buffer) { NET_API_STATUS dwErr; NTSTATUS NtStatus; LPWSTR pwszDfsName; DWORD cwDfsEntryPath; PDFS_GET_PKT_ENTRY_STATE_ARG OutBuffer; HANDLE DriverHandle = NULL; IO_STATUS_BLOCK IoStatusBlock; OBJECT_ATTRIBUTES objectAttributes; UNICODE_STRING DfsDriverName; ULONG cbOutBuffer; ULONG cbInBuffer; PCHAR InBuffer; ULONG cRetries;
#if DBG
if (DfsDebug) DbgPrint("NetDfsGetClientInfo(%ws,%ws,%ws,%d)\n", DfsEntryPath, ServerName, ShareName, Level); #endif
if (!IS_VALID_STRING(DfsEntryPath)) { return( ERROR_INVALID_PARAMETER ); }
//
// Some elementary parameter checking to make sure we can proceed
// reasonably...
//
if (!(Level >= 1 && Level <= 4)) { return( ERROR_INVALID_LEVEL ); }
cwDfsEntryPath = wcslen(DfsEntryPath);
if (!IS_UNC_PATH(DfsEntryPath, cwDfsEntryPath) && !IS_VALID_PREFIX(DfsEntryPath, cwDfsEntryPath) && !IS_VALID_DFS_PATH(DfsEntryPath, cwDfsEntryPath)) { return( ERROR_INVALID_PARAMETER ); }
if (!IS_VALID_STRING(ServerName) && IS_VALID_STRING(ShareName)) { return( ERROR_INVALID_PARAMETER ); }
//
// Calculate the size of the marshall buffer
cbOutBuffer = sizeof(DFS_GET_PKT_ENTRY_STATE_ARG) + wcslen(DfsEntryPath) * sizeof(WCHAR);
if (ServerName) {
cbOutBuffer += wcslen(ServerName) * sizeof(WCHAR);
}
if (ShareName) {
cbOutBuffer += wcslen(ShareName) * sizeof(WCHAR);
}
OutBuffer = malloc(cbOutBuffer);
if (OutBuffer == NULL) {
return (ERROR_NOT_ENOUGH_MEMORY);
}
ZeroMemory(OutBuffer, cbOutBuffer);
//
// marshall the args
//
OutBuffer->DfsEntryPathLen = wcslen(DfsEntryPath) * sizeof(WCHAR); wcscpy(OutBuffer->Buffer, DfsEntryPath);
if (ServerName) {
OutBuffer->ServerNameLen = wcslen(ServerName) * sizeof(WCHAR); wcscat(OutBuffer->Buffer, ServerName);
}
if (ShareName) {
OutBuffer->ShareNameLen = wcslen(ShareName) * sizeof(WCHAR); wcscat(OutBuffer->Buffer, ShareName);
}
//
// Construct name for opening driver
//
RtlInitUnicodeString(&DfsDriverName, DFS_DRIVER_NAME);
InitializeObjectAttributes( &objectAttributes, &DfsDriverName, OBJ_CASE_INSENSITIVE, NULL, NULL );
//
// Open the driver
//
NtStatus = NtCreateFile( &DriverHandle, SYNCHRONIZE, &objectAttributes, &IoStatusBlock, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_OPEN_IF, FILE_CREATE_TREE_CONNECTION | FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0 );
if (NT_SUCCESS(NtStatus)) {
//
// Now fsctl the request down
//
OutBuffer->Level = Level; cbInBuffer = 0x400; NtStatus = STATUS_BUFFER_OVERFLOW;
for (cRetries = 0; NtStatus == STATUS_BUFFER_OVERFLOW && cRetries < 4; cRetries++) {
dwErr = NetApiBufferAllocate(cbInBuffer, &InBuffer);
if (dwErr != ERROR_SUCCESS) {
free(OutBuffer);
NtClose(DriverHandle);
return(ERROR_NOT_ENOUGH_MEMORY);
}
NtStatus = NtFsControlFile( DriverHandle, NULL, // Event,
NULL, // ApcRoutine,
NULL, // ApcContext,
&IoStatusBlock, FSCTL_DFS_GET_PKT_ENTRY_STATE, OutBuffer, cbOutBuffer, InBuffer, cbInBuffer );
if (NtStatus == STATUS_BUFFER_OVERFLOW) {
cbInBuffer = *((PULONG)InBuffer);
NetApiBufferFree(InBuffer);
}
}
NtClose(DriverHandle);
//
// Too many attempts?
//
if (cRetries >= 4) {
NtStatus = STATUS_INTERNAL_ERROR;
}
}
if (NT_SUCCESS(NtStatus)) {
PDFS_INFO_3 pDfsInfo3; PDFS_INFO_4 pDfsInfo4; ULONG j;
pDfsInfo4 = (PDFS_INFO_4)InBuffer; pDfsInfo3 = (PDFS_INFO_3)InBuffer;
try {
//
// EntryPath is common to all DFS_INFO_X's and is in the
// same location.
//
OFFSET_TO_POINTER(pDfsInfo4->EntryPath, InBuffer);
switch (Level) {
case 4: OFFSET_TO_POINTER(pDfsInfo4->Storage, InBuffer); for (j = 0; j < pDfsInfo4->NumberOfStorages; j++) { OFFSET_TO_POINTER(pDfsInfo4->Storage[j].ServerName, InBuffer); OFFSET_TO_POINTER(pDfsInfo4->Storage[j].ShareName, InBuffer); } break;
case 3: OFFSET_TO_POINTER(pDfsInfo3->Storage, InBuffer); for (j = 0; j < pDfsInfo3->NumberOfStorages; j++) { OFFSET_TO_POINTER(pDfsInfo3->Storage[j].ServerName, InBuffer); OFFSET_TO_POINTER(pDfsInfo3->Storage[j].ShareName, InBuffer); }
}
*Buffer = (PBYTE)InBuffer; dwErr = NERR_Success;
} except (EXCEPTION_EXECUTE_HANDLER) {
NtStatus = GetExceptionCode();
}
}
switch (NtStatus) {
case STATUS_SUCCESS: dwErr = NERR_Success; break;
case STATUS_OBJECT_NAME_NOT_FOUND: dwErr = NERR_DfsNoSuchVolume; NetApiBufferFree(InBuffer); break;
case STATUS_INTERNAL_ERROR: dwErr = NERR_DfsInternalError; NetApiBufferFree(InBuffer); break;
default: dwErr = ERROR_INVALID_PARAMETER; NetApiBufferFree(InBuffer); break;
}
free(OutBuffer);
#if DBG
if (DfsDebug) DbgPrint("NetDfsGetClientInfo returning %d\n", dwErr); #endif
return( dwErr ); }
//+----------------------------------------------------------------------------
//
// Function: NetDfsSetClientInfo
//
// Synopsis: Associates information with the local PKT.
//
//
// Arguments: [DfsEntryPath] -- Path to the volume.
// [ServerName] -- Optional. If specified, indicates the
// server supporting DfsEntryPath.
// [ShareName] -- Optional. If specified, indicates the share
// on ServerName for which info is desired.
// [Level] -- Indicates the level of info required.
// [Buffer] -- Pointer to buffer containing information to set.
//
// Returns: [NERR_Success] -- Info successfully returned.
//
// [ERROR_INVALID_PARAMETER] -- Either DfsEntryPath is NULL,
// or ShareName is specified but ServerName is NULL.
//
// [ERROR_NOT_ENOUGH_MEMORY] -- Out of memory condition.
//
// [NERR_DfsNoSuchVolume] -- No volume matches DfsEntryPath.
//
//-----------------------------------------------------------------------------
NET_API_STATUS NET_API_FUNCTION NetDfsSetClientInfo( IN LPWSTR DfsEntryPath, IN LPWSTR ServerName OPTIONAL, IN LPWSTR ShareName OPTIONAL, IN DWORD Level, IN LPBYTE Buffer) { NET_API_STATUS dwErr; NTSTATUS NtStatus; LPWSTR pwszDfsName; DWORD cwDfsEntryPath; PDFS_SET_PKT_ENTRY_STATE_ARG OutBuffer; PDFS_INFO_101 pDfsInfo101; PDFS_INFO_102 pDfsInfo102; HANDLE DriverHandle = NULL; IO_STATUS_BLOCK IoStatusBlock; OBJECT_ATTRIBUTES objectAttributes; UNICODE_STRING DfsDriverName; ULONG cbOutBuffer;
#if DBG
if (DfsDebug) DbgPrint("NetDfsSetClientInfo(%ws,%ws,%ws,%d)\n", DfsEntryPath, ServerName, ShareName, Level); #endif
if (!IS_VALID_STRING(DfsEntryPath)) { return( ERROR_INVALID_PARAMETER ); }
//
// Some elementary parameter checking to make sure we can proceed
// reasonably...
//
if (!(Level >= 101 && Level <= 102)) { return( ERROR_INVALID_LEVEL ); } cwDfsEntryPath = wcslen(DfsEntryPath);
if (!IS_UNC_PATH(DfsEntryPath, cwDfsEntryPath) && !IS_VALID_PREFIX(DfsEntryPath, cwDfsEntryPath) && !IS_VALID_DFS_PATH(DfsEntryPath, cwDfsEntryPath)) { return( ERROR_INVALID_PARAMETER ); }
if (!IS_VALID_STRING(ServerName) && IS_VALID_STRING(ShareName)) { return( ERROR_INVALID_PARAMETER ); }
if (Buffer == NULL) { return( ERROR_INVALID_PARAMETER ); }
//
// Calculate the size of the marshall buffer
//
cbOutBuffer = sizeof(DFS_SET_PKT_ENTRY_STATE_ARG) + wcslen(DfsEntryPath) * sizeof(WCHAR);
if (ServerName) {
cbOutBuffer += wcslen(ServerName) * sizeof(WCHAR);
}
if (ShareName) {
cbOutBuffer += wcslen(ShareName) * sizeof(WCHAR);
}
OutBuffer = malloc(cbOutBuffer);
if (OutBuffer == NULL) {
return (ERROR_NOT_ENOUGH_MEMORY);
}
ZeroMemory(OutBuffer, cbOutBuffer);
//
// marshall the args
//
OutBuffer = (PDFS_SET_PKT_ENTRY_STATE_ARG) OutBuffer; OutBuffer->DfsEntryPathLen = wcslen(DfsEntryPath) * sizeof(WCHAR); wcscpy(OutBuffer->Buffer, DfsEntryPath); OutBuffer->Level = Level;
if (ServerName) {
OutBuffer->ServerNameLen = wcslen(ServerName) * sizeof(WCHAR); wcscat(OutBuffer->Buffer, ServerName);
}
if (ShareName) {
OutBuffer->ShareNameLen = wcslen(ShareName) * sizeof(WCHAR); wcscat(OutBuffer->Buffer, ShareName);
}
switch (Level) {
case 101: OutBuffer->State = ((PDFS_INFO_101)Buffer)->State; break; case 102: OutBuffer->Timeout = (DWORD)((PDFS_INFO_102)Buffer)->Timeout; break;
}
//
// Communicate with the driver
//
RtlInitUnicodeString(&DfsDriverName, DFS_DRIVER_NAME);
InitializeObjectAttributes( &objectAttributes, &DfsDriverName, OBJ_CASE_INSENSITIVE, NULL, NULL );
NtStatus = NtCreateFile( &DriverHandle, SYNCHRONIZE | FILE_WRITE_DATA, &objectAttributes, &IoStatusBlock, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_OPEN_IF, FILE_CREATE_TREE_CONNECTION | FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0 );
if (NT_SUCCESS(NtStatus)) {
NtStatus = NtFsControlFile( DriverHandle, NULL, // Event,
NULL, // ApcRoutine,
NULL, // ApcContext,
&IoStatusBlock, FSCTL_DFS_SET_PKT_ENTRY_STATE, OutBuffer, cbOutBuffer, NULL, 0 );
NtClose(DriverHandle);
}
switch (NtStatus) {
case STATUS_SUCCESS: dwErr = NERR_Success; break; case STATUS_OBJECT_NAME_NOT_FOUND: dwErr = NERR_DfsNoSuchVolume; break; default: dwErr = ERROR_INVALID_PARAMETER; break; }
free(OutBuffer);
#if DBG
if (DfsDebug) DbgPrint("NetDfsSetClientInfo returning %d\n", dwErr); #endif
return( dwErr ); }
//+----------------------------------------------------------------------------
//
// Function
//
// Synopsis: Enumerates the Dfs volumes.
//
// Arguments: [DfsName] -- Name of server or domain whose Dfs is being
// enumerated. A leading \\ is optional.
// [Level] -- Indicates the level of info needed back. Valid
// Levels are 1,2, and 3.
// [PrefMaxLen] -- Preferred maximum length of return buffer.
// [Buffer] -- On successful return, contains an array of
// DFS_INFO_X. This buffer should be freed with a call
// to NetApiBufferFree.
// [EntriesRead] -- On successful return, contains the number
// of entries read (and therefore, size of the array in
// Buffer).
// [ResumeHandle] -- Must be 0 on first call. On subsequent calls
// the value returned by the immediately preceding call.
//
// Returns: [NERR_Success] -- Enum data successfully returned.
//
// [ERROR_INVALID_LEVEL] -- The Level specified in invalid.
//
// [ERROR_INVALID_NAME] -- Unable to locate server or domain.
//
// [ERROR_DCNotFound] -- Unable to locate DC for DfsName.
//
// [ERROR_NOT_ENOUGH_MEMORY] -- Out of memory condition.
//
// [ERROR_NO_MORE_ITEMS] -- No more volumes to be enumerated.
//
// [NERR_DfsInternalCorruption] -- Corruption of Dfs data
// encountered at the server.
//
//-----------------------------------------------------------------------------
NET_API_STATUS NET_API_FUNCTION NetDfsEnum( IN LPWSTR DfsName, IN DWORD Level, IN DWORD PrefMaxLen, OUT LPBYTE* Buffer, OUT LPDWORD EntriesRead, IN OUT LPDWORD ResumeHandle) { NET_API_STATUS dwErr; LPWSTR pwszMachineName = NULL; LPWSTR pwszDomainName = NULL; DFS_INFO_ENUM_STRUCT DfsEnum; DFS_INFO_3_CONTAINER DfsInfo3Container; PDOMAIN_CONTROLLER_INFO pDomainControllerInfo = NULL; PWCHAR DCList; DWORD Version; #if DBG
if (DfsDebug) DbgPrint("NetDfsEnum(%ws, %d)\n", DfsName, Level); #endif
if (!IS_VALID_STRING(DfsName)) { dwErr = ERROR_INVALID_PARAMETER; goto AllDone; }
//
// Check the Level Parameter first, or RPC won't know how to marshal the
// arguments.
//
if (!(Level >= 1 && Level <= 4) && (Level != 200) && (Level != 300)) { dwErr = ERROR_INVALID_LEVEL; goto AllDone; }
//
// Handle names with leading '\\'
//
while (*DfsName == L'\\') { DfsName++; }
DfsInfo3Container.EntriesRead = 0; DfsInfo3Container.Buffer = NULL; DfsEnum.Level = Level; DfsEnum.DfsInfoContainer.DfsInfo3Container = &DfsInfo3Container;
if (Level == 200) { if (wcschr(DfsName, L'\\') == NULL) {
//
// Use the PDC to enum
//
dwErr = DsGetDcName( NULL, DfsName, NULL, NULL, DS_PDC_REQUIRED | DS_FORCE_REDISCOVERY, &pDomainControllerInfo);
ENTER_NETDFS_API
if (dwErr == NERR_Success) { dwErr = DfspBindRpc(&pDomainControllerInfo->DomainControllerName[2], &netdfs_bhandle); }
if (dwErr == NERR_Success) {
RpcTryExcept { dwErr = NetrDfsEnumEx( DfsName, Level, PrefMaxLen, &DfsEnum, ResumeHandle); #if DBG
if (DfsDebug) DbgPrint("NetrDfsEnumEx returned %d\n", dwErr); #endif
if (dwErr == NERR_Success) { *EntriesRead =DfsInfo3Container.EntriesRead; *Buffer = (LPBYTE) DfsInfo3Container.Buffer; } if (dwErr == ERROR_UNEXP_NET_ERR) { dwErr = ERROR_NO_MORE_ITEMS; } } RpcExcept( 1 ) { dwErr = RpcExceptionCode(); } RpcEndExcept; DfspFreeBinding( netdfs_bhandle ); } LEAVE_NETDFS_API } else { dwErr = ERROR_INVALID_PARAMETER; } } else { dwErr = DfspGetMachineNameFromEntryPath( DfsName, wcslen(DfsName), &pwszMachineName );
ENTER_NETDFS_API
if (dwErr == NERR_Success) { dwErr = DfspBindRpc( pwszMachineName, &netdfs_bhandle ); }
#if DBG
if (DfsDebug) DbgPrint("DfspBindRpc returned %d\n", dwErr); #endif
if (dwErr == NERR_Success) {
RpcTryExcept { Version = NetrDfsManagerGetVersion(); } RpcExcept( 1 ) { Version = 3; } RpcEndExcept;
RpcTryExcept { #if DBG
if (DfsDebug) DbgPrint("Calling NetrDfsEnumEx (%d)\n", Level); #endif
if (Version >= 4) { dwErr = NetrDfsEnumEx( DfsName, Level, PrefMaxLen, &DfsEnum, ResumeHandle ); } else { dwErr = NetrDfsEnum( Level, PrefMaxLen, &DfsEnum, ResumeHandle );
} } RpcExcept( 1 ) {
dwErr = RpcExceptionCode(); #if DBG
if (DfsDebug) DbgPrint("RpcExeptionCode() err %d\n", dwErr); #endif
} RpcEndExcept;
if (dwErr == NERR_Success) {
*EntriesRead =DfsInfo3Container.EntriesRead;
*Buffer = (LPBYTE) DfsInfo3Container.Buffer;
}
DfspFreeBinding( netdfs_bhandle ); } LEAVE_NETDFS_API }
AllDone:
if (pDomainControllerInfo != NULL) NetApiBufferFree(pDomainControllerInfo);
if (pwszMachineName != NULL) free(pwszMachineName);
if (pwszDomainName != NULL) free(pwszDomainName);
#if DBG
if (DfsDebug) DbgPrint("NetDfsEnum returning %d\n", dwErr); #endif
return( dwErr ); }
//+----------------------------------------------------------------------------
//
// Function: NetDfsMove
//
// Synopsis: Moves a dfs volume to a new place in the Dfs hierarchy.
//
// Arguments: [DfsEntryPath] -- Current path to the volume.
// [NewDfsEntryPath] -- Desired new path to the volume.
//
// Returns: [NERR_Success] -- Info successfully returned.
//
// [ERROR_INVALID_PARAMETER] -- Either DfsEntryPath or
// NewDfsEntryPath are not valid.
//
// [ERROR_INVALID_NAME] -- Unable to locate server or domain.
//
// [ERROR_DCNotFound] -- Unable to locate DC for domain.
//
// [ERROR_NOT_ENOUGH_MEMORY] -- Out of memory condition.
//
// [NERR_DfsNoSuchVolume] -- No volume matches DfsEntryPath.
//
// [NERR_DfsInternalCorruption] -- Corruption of Dfs data
// encountered at the server.
//
//-----------------------------------------------------------------------------
NET_API_STATUS NetDfsMove( IN LPWSTR DfsEntryPath, IN LPWSTR NewDfsEntryPath) { NET_API_STATUS dwErr; DWORD cwEntryPath; LPWSTR pwszDfsName;
return ERROR_NOT_SUPPORTED; }
//+----------------------------------------------------------------------------
//
// Function: NetDfsRename
//
// Synopsis: Renames a path that is along a Dfs Volume Entry Path
//
// Arguments: [Path] -- Current path.
// [NewPath] -- Desired new path.
//
// Returns: [NERR_Success] -- Info successfully returned.
//
// [ERROR_INVALID_PARAMETER] -- Either DfsEntryPath or
// NewDfsEntryPath are not valid.
//
// [ERROR_INVALID_NAME] -- Unable to locate server or domain.
//
// [ERROR_DCNotFound] -- Unable to locate DC for domain.
//
// [ERROR_NOT_ENOUGH_MEMORY] -- Out of memory condition.
//
// [NERR_DfsNoSuchVolume] -- No volume matches DfsEntryPath.
//
// [NERR_DfsInternalCorruption] -- Corruption of Dfs data
// encountered at the server.
//
//-----------------------------------------------------------------------------
NET_API_STATUS NetDfsRename( IN LPWSTR Path, IN LPWSTR NewPath) { NET_API_STATUS dwErr; DWORD cwPath; LPWSTR pwszDfsName;
return ERROR_NOT_SUPPORTED;
}
//+----------------------------------------------------------------------------
//
// Function: NetDfsManagerGetConfigInfo
//
// Synopsis: Given a DfsEntryPath and Guid of a local volume, this api
// remotes to the root server of the entry path and retrieves
// the config info from it.
//
// Arguments: [wszServer] -- Name of local machine
// [wszLocalVolumeEntryPath] -- Entry Path of local volume.
// [guidLocalVolume] -- Guid of local volume.
// [ppDfsmRelationInfo] -- On successful return, contains pointer
// to config info at the root server. Free using
// NetApiBufferFree.
//
// Returns: [NERR_Success] -- Info returned successfully.
//
// [ERROR_INVALID_PARAMETER] -- wszLocalVolumeEntryPath is
// invalid.
//
// [ERROR_INVALID_NAME] -- Unable to parse out server/domain name
// from wszLocalVolumeEntryPath
//
// [ERROR_DCNotFound] -- Unable to locate a DC for domain
//
// [ERROR_NOT_ENOUGH_MEMORY] -- Out of memory condition
//
// [NERR_DfsNoSuchVolume] -- The root server did not recognize
// a volume with this guid/entrypath
//
// [NERR_DfsNoSuchServer] -- wszServer is not a valid server for
// wszLocalVolumeEntryPath
//
//-----------------------------------------------------------------------------
NET_API_STATUS NetDfsManagerGetConfigInfo( LPWSTR wszServer, LPWSTR wszLocalVolumeEntryPath, GUID guidLocalVolume, LPDFSM_RELATION_INFO *ppDfsmRelationInfo) { NET_API_STATUS dwErr; LPWSTR pwszDfsName = NULL; DWORD cwDfsEntryPath;
#if DBG
if (DfsDebug) DbgPrint("NetDfsManagerGetConfigInfo(%ws,%ws)\n", wszServer, wszLocalVolumeEntryPath); #endif
if (!IS_VALID_STRING(wszServer) || !IS_VALID_STRING(wszLocalVolumeEntryPath)) { return( ERROR_INVALID_PARAMETER ); }
//
// Some elementary parameter checking to make sure we can proceed
// reasonably...
//
cwDfsEntryPath = wcslen(wszLocalVolumeEntryPath);
if (!IS_UNC_PATH(wszLocalVolumeEntryPath, cwDfsEntryPath) && !IS_VALID_PREFIX(wszLocalVolumeEntryPath, cwDfsEntryPath) && !IS_VALID_DFS_PATH(wszLocalVolumeEntryPath, cwDfsEntryPath)) { return( ERROR_INVALID_PARAMETER ); }
dwErr = DfspGetMachineNameFromEntryPath( wszLocalVolumeEntryPath, cwDfsEntryPath, &pwszDfsName);
ENTER_NETDFS_API
if (dwErr == NERR_Success) {
//
// By now, we should have a valid pwszDfsName. Lets try to bind to it,
// and call the server.
//
dwErr = DfspBindRpc( pwszDfsName, &netdfs_bhandle );
if (dwErr == NERR_Success) {
RpcTryExcept {
*ppDfsmRelationInfo = NULL;
dwErr = NetrDfsManagerGetConfigInfo( wszServer, wszLocalVolumeEntryPath, guidLocalVolume, ppDfsmRelationInfo);
} RpcExcept( 1 ) {
dwErr = RpcExceptionCode();
} RpcEndExcept;
DfspFreeBinding( netdfs_bhandle );
}
free( pwszDfsName );
}
LEAVE_NETDFS_API
#if DBG
if (DfsDebug) DbgPrint("NetDfsManagerGetConfigInfo returning %d\n", dwErr); #endif
return( dwErr );
}
//+----------------------------------------------------------------------------
//
// Function: NetDfsManagerInitialize
//
// Synopsis: Reinitialize the Dfs Manager on a remote machine
//
// Arguments: [ServerName] -- Name of server to remote to
// [Flags] -- Flags
//
// Returns: [NERR_Success] -- Successfully completed operation.
//
//-----------------------------------------------------------------------------
NET_API_STATUS NetDfsManagerInitialize( IN LPWSTR ServerName, IN DWORD Flags) { NET_API_STATUS dwErr;
#if DBG
if (DfsDebug) DbgPrint("NetDfsManagerInitialize(%ws,%d)\n", ServerName, Flags); #endif
//
// Validate the string argument so RPC won't complain...
//
if (!IS_VALID_STRING(ServerName)) { return( ERROR_INVALID_PARAMETER ); }
ENTER_NETDFS_API
//
// We should have a valid ServerName. Lets try to bind to it,
// and call the server.
//
dwErr = DfspBindToServer( ServerName, &netdfs_bhandle );
if (dwErr == NERR_Success) {
RpcTryExcept {
dwErr = NetrDfsManagerInitialize( ServerName, Flags);
} RpcExcept(1) {
dwErr = RpcExceptionCode();
} RpcEndExcept;
DfspFreeBinding( netdfs_bhandle );
}
LEAVE_NETDFS_API
#if DBG
if (DfsDebug) DbgPrint("NetDfsManagerInitialize returning %d\n", dwErr); #endif
return( dwErr );
}
//+----------------------------------------------------------------------------
//
// Function: NetDfsManagerSendSiteInfo
//
// Synopsis: Gets site information from a server
//
// Returns: [NERR_Success] -- Successfully completed operation.
//
//-----------------------------------------------------------------------------
NET_API_STATUS NetDfsManagerSendSiteInfo( LPWSTR wszServer, LPWSTR wszLocalVolumeEntryPath, LPDFS_SITELIST_INFO pSiteInfo) { NET_API_STATUS dwErr; LPWSTR pwszDfsName = NULL; DWORD cwDfsEntryPath;
#if DBG
if (DfsDebug) DbgPrint("NetDfsManagerSendSiteInfo(%ws,%ws)\n", wszServer, wszLocalVolumeEntryPath); #endif
if (!IS_VALID_STRING(wszServer) || !IS_VALID_STRING(wszLocalVolumeEntryPath)) { return( ERROR_INVALID_PARAMETER ); }
//
// Some elementary parameter checking to make sure we can proceed
// reasonably...
//
cwDfsEntryPath = wcslen(wszLocalVolumeEntryPath);
if (!IS_UNC_PATH(wszLocalVolumeEntryPath, cwDfsEntryPath) && !IS_VALID_PREFIX(wszLocalVolumeEntryPath, cwDfsEntryPath) && !IS_VALID_DFS_PATH(wszLocalVolumeEntryPath, cwDfsEntryPath)) { return( ERROR_INVALID_PARAMETER ); }
dwErr = DfspGetMachineNameFromEntryPath( wszLocalVolumeEntryPath, cwDfsEntryPath, &pwszDfsName);
ENTER_NETDFS_API
if (dwErr == NERR_Success) {
//
// By now, we should have a valid pwszDfsName. Lets try to bind to it,
// and call the server.
//
dwErr = DfspBindRpc( pwszDfsName, &netdfs_bhandle );
if (dwErr == NERR_Success) {
RpcTryExcept {
dwErr = NetrDfsManagerSendSiteInfo( wszServer, pSiteInfo);
} RpcExcept( 1 ) {
dwErr = RpcExceptionCode();
} RpcEndExcept;
DfspFreeBinding( netdfs_bhandle );
}
free( pwszDfsName );
}
LEAVE_NETDFS_API
#if DBG
if (DfsDebug) DbgPrint("NetDfsManagerSendSiteInfo returning %d\n", dwErr); #endif
return( dwErr );
}
//+----------------------------------------------------------------------------
//
// Function: DfspGetMachineNameFromEntryPath
//
// Synopsis: Given a DfsEntryPath, this routine returns the name of the
// FtDfs Root.
//
// Arguments: [wszEntryPath] -- Pointer to EntryPath to parse.
//
// [cwEntryPath] -- Length in WCHAR of wszEntryPath.
//
// [ppwszMachineName] -- Name of a root machine; allocated using malloc;
// caller resposible for freeing it.
//
// Returns: [NERR_Success] -- Successfully determinded
//
// [ERROR_INVALID_NAME] -- Unable to parse wszEntryPath.
//
// [ERROR_NOT_ENOUGH_MEMORY] -- Unable to allocate memory for
// ppwszMachineName.
//
//-----------------------------------------------------------------------------
NET_API_STATUS DfspGetMachineNameFromEntryPath( LPWSTR wszEntryPath, DWORD cwEntryPath, LPWSTR *ppwszMachineName) { NTSTATUS NtStatus; LPWSTR pwszDfsName, pwszFirst, pwszLast; LPWSTR pwszMachineName; DWORD cwDfsName; DWORD cwSlash; DWORD dwErr;
#if DBG
if (DfsDebug) DbgPrint("DfspGetMachineNameFromEntryPath(%ws,%d\n", wszEntryPath, cwEntryPath); #endif
if (!IS_VALID_STRING(wszEntryPath)) { return( ERROR_INVALID_PARAMETER ); }
if (IS_UNC_PATH(wszEntryPath, cwEntryPath)) {
pwszFirst = &wszEntryPath[2];
} else if (IS_VALID_PREFIX(wszEntryPath, cwEntryPath)) {
pwszFirst = &wszEntryPath[1];
} else if (IS_VALID_DFS_PATH(wszEntryPath, cwEntryPath)) {
pwszFirst = &wszEntryPath[0];
} else {
return( ERROR_INVALID_NAME );
}
dwErr = DfspGetDfsNameFromEntryPath( wszEntryPath, cwEntryPath, &pwszMachineName);
if (dwErr != NERR_Success) {
#if DBG
if (DfsDebug) DbgPrint("DfspGetMachineNameFromEntryPath: returning %d\n", dwErr); #endif
return( dwErr);
}
for (cwDfsName = cwSlash = 0, pwszLast = pwszFirst; *pwszLast != UNICODE_NULL; pwszLast++, cwDfsName++) { if (*pwszLast == L'\\') cwSlash++; if (cwSlash >= 2) break; }
if (cwSlash == 0) {
*ppwszMachineName = pwszMachineName; dwErr = NERR_Success;
return dwErr; }
cwDfsName += 3;
pwszDfsName = malloc(cwDfsName * sizeof(WCHAR));
if (pwszDfsName != NULL) {
ZeroMemory((PCHAR)pwszDfsName, cwDfsName * sizeof(WCHAR));
wcscpy(pwszDfsName, L"\\\\");
CopyMemory(&pwszDfsName[2], pwszFirst, (PCHAR)pwszLast - (PCHAR)pwszFirst);
NtStatus = DfspIsThisADfsPath(&pwszDfsName[1]);
if (NT_SUCCESS(NtStatus)) { GetFileAttributes(pwszDfsName); }
dwErr = DfspDfsPathToRootMachine(pwszDfsName, ppwszMachineName);
if (NtStatus != STATUS_SUCCESS || dwErr != NERR_Success) {
*ppwszMachineName = pwszMachineName; dwErr = NERR_Success;
} else {
free(pwszMachineName);
}
free(pwszDfsName);
} else {
free(pwszMachineName); dwErr = ERROR_NOT_ENOUGH_MEMORY;
}
#if DBG
if (DfsDebug) DbgPrint("DfspGetMachineNameFromEntryPath returning %d\n", dwErr); #endif
return( dwErr );
}
//+----------------------------------------------------------------------------
//
// Function: DfspGetDfsNameFromEntryPath
//
// Synopsis: Given a DfsEntryPath, this routine returns the name of the
// Dfs Root.
//
// Arguments: [wszEntryPath] -- Pointer to EntryPath to parse.
//
// [cwEntryPath] -- Length in WCHAR of wszEntryPath.
//
// [ppwszDfsName] -- Name of Dfs root is returned here. Memory
// is allocated using malloc; caller resposible for
// freeing it.
//
// Returns: [NERR_Success] -- Successfully parsed out Dfs Root.
//
// [ERROR_INVALID_NAME] -- Unable to parse wszEntryPath.
//
// [ERROR_NOT_ENOUGH_MEMORY] -- Unable to allocate memory for
// ppwszDfsName.
//
//-----------------------------------------------------------------------------
NET_API_STATUS DfspGetDfsNameFromEntryPath( LPWSTR wszEntryPath, DWORD cwEntryPath, LPWSTR *ppwszDfsName) { LPWSTR pwszDfsName, pwszFirst, pwszLast; DWORD cwDfsName;
#if DBG
if (DfsDebug) DbgPrint("DfspGetDfsNameFromEntryPath(%ws,%d)\n", wszEntryPath, cwEntryPath); #endif
if (!IS_VALID_STRING(wszEntryPath)) { #if DBG
if (DfsDebug) DbgPrint("DfspGetDfsNameFromEntryPath returning ERROR_INVALID_PARAMETER\n"); #endif
return( ERROR_INVALID_PARAMETER ); }
if (IS_UNC_PATH(wszEntryPath, cwEntryPath)) {
pwszFirst = &wszEntryPath[2];
} else if (IS_VALID_PREFIX(wszEntryPath, cwEntryPath)) {
pwszFirst = &wszEntryPath[1];
} else if (IS_VALID_DFS_PATH(wszEntryPath, cwEntryPath)) {
pwszFirst = &wszEntryPath[0];
} else {
#if DBG
if (DfsDebug) DbgPrint("DfspGetDfsNameFromEntryPath returning ERROR_INVALID_NAME\n"); #endif
return( ERROR_INVALID_NAME );
}
for (cwDfsName = 0, pwszLast = pwszFirst; *pwszLast != UNICODE_NULL && *pwszLast != L'\\'; pwszLast++, cwDfsName++) { ; }
++cwDfsName;
pwszDfsName = malloc( cwDfsName * sizeof(WCHAR) );
if (pwszDfsName != NULL) {
pwszDfsName[ cwDfsName - 1 ] = 0;
for (cwDfsName--; cwDfsName > 0; cwDfsName--) {
pwszDfsName[ cwDfsName - 1 ] = pwszFirst[ cwDfsName - 1 ];
}
*ppwszDfsName = pwszDfsName;
#if DBG
if (DfsDebug) DbgPrint("DfspGetDfsNameFromEntryPath returning %ws\n", pwszDfsName); #endif
return( NERR_Success );
} else {
#if DBG
if (DfsDebug) DbgPrint("DfspGetDfsNameFromEntryPath returning ERROR_NOT_ENOUGH_MEMORY\n"); #endif
return( ERROR_NOT_ENOUGH_MEMORY );
}
}
//+----------------------------------------------------------------------------
//
// Function: DfspBindRpc
//
// Synopsis: Given a server or domain name, this API will bind to the
// appropriate Dfs Manager service.
//
// Arguments: [DfsName] -- Name of domain or server. Leading \\ is optional
//
// [BindingHandle] -- On successful return, the binding handle
// is returned here.
//
// Returns: [NERR_Success] -- Binding handle successfull returned.
//
// [RPC_S_SERVER_NOT_AVAILABLE] -- Unable to bind to NetDfs
// interface on the named server or domain.
//
// [ERROR_INVALID_NAME] -- Unable to parse DfsName as a valid
// server or domain name.
//
// [ERROR_DCNotFound] -- Unable to locate DC for DfsName.
//
// [ERROR_NOT_ENOUGH_MEMORY] -- Out of memory condition.
//
//-----------------------------------------------------------------------------
NET_API_STATUS DfspBindRpc( IN LPWSTR DfsName, OUT RPC_BINDING_HANDLE *BindingHandle) { LPWSTR wszProtocolSeq = L"ncacn_np"; LPWSTR wszEndPoint = L"\\pipe\\netdfs"; LPWSTR pwszRpcBindingString = NULL; LPWSTR pwszDCName = NULL; NET_API_STATUS dwErr; PWCHAR DCList = NULL; PWCHAR DCListToFree = NULL; BOOLEAN IsDomainName = FALSE;
#if DBG
if (DfsDebug) DbgPrint("DfspBindRpc(%ws)\n", DfsName); #endif
//
// First, see if this is a domain name.
//
dwErr = DfspIsThisADomainName( DfsName, &DCListToFree );
DCList = DCListToFree;
if (dwErr == ERROR_SUCCESS && DCList != NULL && *DCList != UNICODE_NULL) {
//
// It's a domain name. Use the DC list as a list of servers to try to bind to.
//
IsDomainName = TRUE; pwszDCName = DCList + 1; // Skip '+' or '-'
dwErr = ERROR_SUCCESS;
} else {
//
// Lets see if this is a machine-based Dfs
//
pwszDCName = DfsName;
dwErr = ERROR_SUCCESS;
}
Try_Connect:
if (dwErr == ERROR_SUCCESS) {
#if DBG
if (DfsDebug) DbgPrint("Calling RpcBindingCompose(%ws)\n", pwszDCName); #endif
dwErr = RpcStringBindingCompose( NULL, // Object UUID
wszProtocolSeq, // Protocol Sequence
pwszDCName, // Network Address
wszEndPoint, // RPC Endpoint
NULL, // RPC Options
&pwszRpcBindingString); // Returned binding string
if (dwErr == RPC_S_OK) {
dwErr = RpcBindingFromStringBinding( pwszRpcBindingString, BindingHandle);
#if DBG
if (DfsDebug) DbgPrint("RpcBindingFromStringBinding() returned %d\n", dwErr); #endif
if (dwErr == RPC_S_OK) {
dwErr = DfspVerifyBinding(); if (dwErr != RPC_S_OK) { DfspFreeBinding(*BindingHandle); }
#if DBG
if (DfsDebug) DbgPrint("DfspVerifyBinding() returned %d\n", dwErr); #endif
} else {
dwErr = ERROR_INVALID_NAME;
} }
}
if (pwszRpcBindingString != NULL) {
RpcStringFree( &pwszRpcBindingString );
}
if (dwErr == RPC_S_OUT_OF_MEMORY) { dwErr = ERROR_NOT_ENOUGH_MEMORY; }
//
// If we couldn't connect and we have a domain name and a list of DC's,
// try the next DC in the list.
//
if (dwErr != NERR_Success && DCList != NULL && IsDomainName == TRUE) {
DCList += wcslen(DCList) + 1;
if (*DCList != UNICODE_NULL) {
pwszDCName = DCList + 1; dwErr = ERROR_SUCCESS;
goto Try_Connect;
}
}
if (DCListToFree != NULL) {
free(DCListToFree);
}
return( dwErr );
}
//+----------------------------------------------------------------------------
//
// Function: DfspFreeBinding
//
// Synopsis: Frees a binding created by DfspBindRpc
//
// Arguments: [BindingHandle] -- The handle to free.
//
// Returns: Nothing
//
//-----------------------------------------------------------------------------
VOID DfspFreeBinding( RPC_BINDING_HANDLE BindingHandle) { DWORD dwErr;
dwErr = RpcBindingFree( &BindingHandle );
}
//+----------------------------------------------------------------------------
//
// Function: DfspVerifyBinding
//
// Synopsis: Verifies that the binding can be used by doing a
// NetrDfsManagerGetVersion call on the binding.
//
// Arguments: None
//
// Returns: [NERR_Success] -- Server connnected to.
//
// [RPC_S_SERVER_UNAVAILABLE] -- The server is not available.
//
// Other RPC error from calling the remote server.
//
//-----------------------------------------------------------------------------
NET_API_STATUS DfspVerifyBinding() { NET_API_STATUS status = NERR_Success; DWORD Version;
RpcTryExcept {
Version = NetrDfsManagerGetVersion();
} RpcExcept(1) {
status = RpcExceptionCode();
} RpcEndExcept;
return( status );
}
//+----------------------------------------------------------------------------
//
// Function: DfspBindToServer
//
// Synopsis: Given a server name, this API will bind to the
// appropriate Dfs Manager service.
//
// Arguments: [DfsName] -- Name of server. Leading \\ is optional
//
// [BindingHandle] -- On successful return, the binding handle
// is returned here.
//
// Returns: [NERR_Success] -- Binding handle successfull returned.
//
// [RPC_S_SERVER_NOT_AVAILABLE] -- Unable to bind to NetDfs
// interface on the named server or domain.
//
// [ERROR_INVALID_NAME] -- Unable to parse DfsName as a valid
// server or domain name.
//
// [ERROR_DCNotFound] -- Unable to locate DC for DfsName.
//
// [ERROR_NOT_ENOUGH_MEMORY] -- Out of memory condition.
//
//-----------------------------------------------------------------------------
NET_API_STATUS DfspBindToServer( IN LPWSTR ServerName, OUT RPC_BINDING_HANDLE *BindingHandle) { LPWSTR wszProtocolSeq = L"ncacn_np"; LPWSTR wszEndPoint = L"\\pipe\\netdfs"; LPWSTR pwszRpcBindingString = NULL; NET_API_STATUS dwErr;
dwErr = RpcStringBindingCompose( NULL, // Object UUID
wszProtocolSeq, // Protocol Sequence
ServerName, // Network Address
wszEndPoint, // RPC Endpoint
NULL, // RPC Options
&pwszRpcBindingString); // Returned binding string
if (dwErr == RPC_S_OK) {
dwErr = RpcBindingFromStringBinding( pwszRpcBindingString, BindingHandle);
if (dwErr == RPC_S_OK) {
dwErr = DfspVerifyBinding(); if (dwErr != RPC_S_OK) { DfspFreeBinding(*BindingHandle); } } else {
dwErr = ERROR_INVALID_NAME;
} }
if (pwszRpcBindingString != NULL) {
RpcStringFree( &pwszRpcBindingString );
}
if (dwErr == RPC_S_OUT_OF_MEMORY) { dwErr = ERROR_NOT_ENOUGH_MEMORY; }
return( dwErr );
}
//+----------------------------------------------------------------------------
//
// Function: DfspFlushPkt
//
// Synopsis: Flushes the local pkt
//
// Arguments: DfsEntryPath or NULL
//
// Returns: The fsctrl's code
//
//-----------------------------------------------------------------------------
VOID DfspFlushPkt( LPWSTR DfsEntryPath) { NTSTATUS NtStatus; HANDLE DriverHandle = NULL; IO_STATUS_BLOCK IoStatusBlock; OBJECT_ATTRIBUTES objectAttributes; UNICODE_STRING DfsDriverName;
RtlInitUnicodeString(&DfsDriverName, DFS_DRIVER_NAME);
InitializeObjectAttributes( &objectAttributes, &DfsDriverName, OBJ_CASE_INSENSITIVE, NULL, NULL );
NtStatus = NtCreateFile( &DriverHandle, SYNCHRONIZE | FILE_WRITE_DATA, &objectAttributes, &IoStatusBlock, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_OPEN_IF, FILE_CREATE_TREE_CONNECTION | FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0);
if (NT_SUCCESS(NtStatus)) {
if (DfsEntryPath != NULL) {
NtStatus = NtFsControlFile( DriverHandle, NULL, // Event,
NULL, // ApcRoutine,
NULL, // ApcContext,
&IoStatusBlock, FSCTL_DFS_PKT_FLUSH_CACHE, DfsEntryPath, wcslen(DfsEntryPath) * sizeof(WCHAR), NULL, 0);
} else {
NtStatus = NtFsControlFile( DriverHandle, NULL, // Event,
NULL, // ApcRoutine,
NULL, // ApcContext,
&IoStatusBlock, FSCTL_DFS_PKT_FLUSH_CACHE, L"*", sizeof(WCHAR), NULL, 0);
}
NtClose(DriverHandle);
}
}
//+----------------------------------------------------------------------------
//
// Function: DfspDfsPathToRootMachine
//
// Synopsis: Turns a dfs root path into a machine name
// Ex: \\jharperdomain\FtDfs -> jharperdc1
// \\jharpera\d -> jharpera
//
// Arguments: pwszDfsName - Dfs root path to get machine for
// ppwszMachineName - The machine, if one found. Space is
// malloc'd, caller must free.
//
// Returns: [NERR_Success] -- Resolved ok
//
//-----------------------------------------------------------------------------
DWORD DfspDfsPathToRootMachine( LPWSTR pwszDfsName, LPWSTR *ppwszMachineName) { NTSTATUS NtStatus; HANDLE DriverHandle = NULL; IO_STATUS_BLOCK IoStatusBlock; OBJECT_ATTRIBUTES objectAttributes; UNICODE_STRING DfsDriverName; WCHAR ServerName[0x100]; DWORD dwErr; ULONG i;
#if DBG
if (DfsDebug) DbgPrint("DfspDfsPathToRootMachine(%ws)\n", pwszDfsName); #endif
for (i = 0; i < sizeof(ServerName) / sizeof(WCHAR); i++) ServerName[i] = UNICODE_NULL;
RtlInitUnicodeString(&DfsDriverName, DFS_DRIVER_NAME);
InitializeObjectAttributes( &objectAttributes, &DfsDriverName, OBJ_CASE_INSENSITIVE, NULL, NULL );
NtStatus = NtCreateFile( &DriverHandle, SYNCHRONIZE, &objectAttributes, &IoStatusBlock, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_OPEN_IF, FILE_CREATE_TREE_CONNECTION | FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0 );
if (NT_SUCCESS(NtStatus)) {
NtStatus = NtFsControlFile( DriverHandle, NULL, // Event,
NULL, // ApcRoutine,
NULL, // ApcContext,
&IoStatusBlock, FSCTL_DFS_GET_SERVER_NAME, pwszDfsName, wcslen(pwszDfsName) * sizeof(WCHAR), ServerName, sizeof(ServerName) );
NtClose(DriverHandle);
}
if (NT_SUCCESS(NtStatus)) {
LPWSTR wcpStart; LPWSTR wcpEnd;
for (wcpStart = ServerName; *wcpStart == L'\\'; wcpStart++) ;
for (wcpEnd = wcpStart; *wcpEnd != L'\\' && *wcpEnd != UNICODE_NULL; wcpEnd++) ;
*wcpEnd = UNICODE_NULL;
*ppwszMachineName = malloc((wcslen(wcpStart) + 1) * sizeof(WCHAR));
if (*ppwszMachineName != NULL) {
wcscpy(*ppwszMachineName, wcpStart);
dwErr = NERR_Success;
} else {
dwErr = ERROR_NOT_ENOUGH_MEMORY;
}
} else {
#if DBG
if (DfsDebug) DbgPrint("DfspDfsPathToRootMachine NtStatus=0x%x\n", NtStatus); #endif
dwErr = ERROR_INVALID_PARAMETER;
}
#if DBG
if (DfsDebug) { if (dwErr == NERR_Success) DbgPrint("DfspDfsPathToRootMachine returning %ws\n", *ppwszMachineName); else DbgPrint("DfspDfsPathToRootMachine returning %d\n", dwErr); } #endif
return dwErr;
}
//+----------------------------------------------------------------------------
//
// Function: DfspIsThisADfsPath
//
// Synopsis: Checks (via IOCTL to driver) if the path passed in
// is a Dfs path.
//
// Arguments: pwszPathName - Path to check (ex: \ntbuilds\release)
//
// Returns: NTSTATUS of the call (STATUS_SUCCESS or error)
//
//-----------------------------------------------------------------------------
NTSTATUS DfspIsThisADfsPath( LPWSTR pwszPathName) { NTSTATUS NtStatus; HANDLE DriverHandle = NULL; IO_STATUS_BLOCK IoStatusBlock; OBJECT_ATTRIBUTES objectAttributes; UNICODE_STRING DfsDriverName; PDFS_IS_VALID_PREFIX_ARG pPrefixArg = NULL; ULONG Size;
#if DBG
if (DfsDebug) DbgPrint("DfspIsThisADfsPath(%ws)\n", pwszPathName); #endif
Size = sizeof(DFS_IS_VALID_PREFIX_ARG) + (wcslen(pwszPathName) + 1) * sizeof(WCHAR);
pPrefixArg = (PDFS_IS_VALID_PREFIX_ARG) malloc(Size);
if (pPrefixArg == NULL) {
NtStatus = STATUS_INSUFFICIENT_RESOURCES; goto exit_with_status;
}
pPrefixArg->CSCAgentCreate = FALSE; pPrefixArg->RemoteNameLen = wcslen(pwszPathName) * sizeof(WCHAR); wcscpy(&pPrefixArg->RemoteName[0], pwszPathName);
RtlInitUnicodeString(&DfsDriverName, DFS_DRIVER_NAME);
InitializeObjectAttributes( &objectAttributes, &DfsDriverName, OBJ_CASE_INSENSITIVE, NULL, NULL );
NtStatus = NtCreateFile( &DriverHandle, SYNCHRONIZE, &objectAttributes, &IoStatusBlock, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_OPEN_IF, FILE_CREATE_TREE_CONNECTION | FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0 );
if (NT_SUCCESS(NtStatus)) {
NtStatus = NtFsControlFile( DriverHandle, NULL, // Event,
NULL, // ApcRoutine,
NULL, // ApcContext,
&IoStatusBlock, FSCTL_DFS_IS_VALID_PREFIX, pPrefixArg, Size, NULL, 0 );
NtClose(DriverHandle);
}
exit_with_status:
if (pPrefixArg != NULL) {
free(pPrefixArg);
}
#if DBG
if (DfsDebug) DbgPrint("DfspIsThisADfsPath returning 0x%x\n", NtStatus); #endif
return NtStatus;
}
//+----------------------------------------------------------------------------
//
// Function: DfspCreateFtDfs
//
// Synopsis: Creates/updates a Ds object representing the FtDfs, then rpc's
// to the server and has it update the DS object, thus completing
// the setup.
//
// Arguments: wszServerName - Name of server we'll be adding
// wszDcName - DC to use
// fIsPdc - TRUE if DC is the PDC
// wszRootShare - Share to become the root share
// wszFtDfsName - Name of FtDfs we are creating
// wszComment -- Comment for the root
// dwFlags - 0
//
// Returns: NTSTATUS of the call (STATUS_SUCCESS or error)
//
//-----------------------------------------------------------------------------
DWORD DfspCreateFtDfs( LPWSTR wszServerName, LPWSTR wszDcName, BOOLEAN fIsPdc, LPWSTR wszRootShare, LPWSTR wszFtDfsName, LPWSTR wszComment, DWORD dwFlags) { DWORD dwErr = ERROR_SUCCESS; DWORD dwErr2 = ERROR_SUCCESS; DWORD i, j;
LPWSTR wszDfsConfigDN = NULL; LPWSTR wszConfigurationDN = NULL; PDFSM_ROOT_LIST RootList = NULL;
LDAP *pldap = NULL; PLDAPMessage pMsg = NULL;
LDAPModW ldapModClass, ldapModCN, ldapModPkt, ldapModPktGuid, ldapModServer; LDAP_BERVAL ldapPkt, ldapPktGuid; PLDAP_BERVAL rgModPktVals[2]; PLDAP_BERVAL rgModPktGuidVals[2]; LPWSTR rgModClassVals[2]; LPWSTR rgModCNVals[2]; LPWSTR rgModServerVals[5]; LPWSTR rgAttrs[5]; PLDAPModW rgldapMods[6]; BOOLEAN fNewFTDfs = FALSE;
LDAPMessage *pmsgServers; PWCHAR *rgServers; DWORD cServers; ULONG Size;
#if DBG
if (DfsDebug) DbgPrint("DfspCreateFtDfs(%ws,%ws,%s,%ws,%ws,%ws,%d)\n", wszServerName, wszDcName, fIsPdc ? "TRUE" : "FALSE", wszRootShare, wszFtDfsName, wszComment, dwFlags); #endif
dwErr = DfspLdapOpen( wszDcName, &pldap, &wszConfigurationDN); if (dwErr != ERROR_SUCCESS) {
goto Cleanup;
}
//
// See if the DfsConfiguration object exists; if not and this is the
// PDC, create it.
//
rgAttrs[0] = L"cn"; rgAttrs[1] = NULL;
dwErr = ldap_search_sW( pldap, wszConfigurationDN, LDAP_SCOPE_BASE, L"(objectClass=*)", rgAttrs, 0, &pMsg);
if (pMsg != NULL) { ldap_msgfree(pMsg); pMsg = NULL; }
#if DBG
if (DfsDebug) DbgPrint("ldap_search_sW(1) returned 0x%x\n", dwErr); #endif
if (dwErr == LDAP_NO_SUCH_OBJECT && fIsPdc == TRUE) {
rgModClassVals[0] = L"dfsConfiguration"; rgModClassVals[1] = NULL;
ldapModClass.mod_op = LDAP_MOD_ADD; ldapModClass.mod_type = L"objectClass"; ldapModClass.mod_vals.modv_strvals = rgModClassVals;
rgModCNVals[0] = L"Dfs-Configuration"; rgModCNVals[1] = NULL;
ldapModCN.mod_op = LDAP_MOD_ADD; ldapModCN.mod_type = L"cn"; ldapModCN.mod_vals.modv_strvals = rgModCNVals;
rgldapMods[0] = &ldapModClass; rgldapMods[1] = &ldapModCN; rgldapMods[2] = NULL;
dwErr = ldap_add_sW( pldap, wszConfigurationDN, rgldapMods);
#if DBG
if (DfsDebug) DbgPrint("ldap_add_sW(1) returned 0x%x\n", dwErr); #endif
}
if (dwErr != LDAP_SUCCESS) {
dwErr = LdapMapErrorToWin32(dwErr); goto Cleanup;
}
//
// Check to see if we are joining an FTDfs or creating a new one.
//
Size = wcslen(L"CN=") + wcslen(wszFtDfsName) + wcslen(L",") + wcslen(wszConfigurationDN); if (Size > MAX_PATH) { dwErr = ERROR_DS_NAME_TOO_LONG; goto Cleanup; } wszDfsConfigDN = malloc((Size+1) * sizeof(WCHAR)); if (wszDfsConfigDN == NULL) { dwErr = ERROR_OUTOFMEMORY; goto Cleanup; } wcscpy(wszDfsConfigDN,L"CN="); wcscat(wszDfsConfigDN,wszFtDfsName); wcscat(wszDfsConfigDN,L","); wcscat(wszDfsConfigDN,wszConfigurationDN);
rgAttrs[0] = L"remoteServerName"; rgAttrs[1] = NULL;
dwErr = ldap_search_sW( pldap, wszDfsConfigDN, LDAP_SCOPE_BASE, L"(objectClass=*)", rgAttrs, 0, &pMsg);
#if DBG
if (DfsDebug) DbgPrint("ldap_search_sW(2) returned 0x%x\n", dwErr); #endif
if (dwErr == LDAP_NO_SUCH_OBJECT) {
GUID idPkt; DWORD dwPktVersion = 1;
//
// We are creating a new FTDfs, create a container to hold the Dfs
// configuration for it.
//
fNewFTDfs = TRUE;
//
// Generate the class and CN attributes
//
rgModClassVals[0] = L"ftDfs"; rgModClassVals[1] = NULL;
ldapModClass.mod_op = LDAP_MOD_ADD; ldapModClass.mod_type = L"objectClass"; ldapModClass.mod_vals.modv_strvals = rgModClassVals;
rgModCNVals[0] = wszFtDfsName; rgModCNVals[1] = NULL;
ldapModCN.mod_op = LDAP_MOD_ADD; ldapModCN.mod_type = L"cn"; ldapModCN.mod_vals.modv_strvals = rgModCNVals;
//
// Generate the null PKT attribute
//
ldapPkt.bv_len = sizeof(DWORD); ldapPkt.bv_val = (PCHAR) &dwPktVersion;
rgModPktVals[0] = &ldapPkt; rgModPktVals[1] = NULL;
ldapModPkt.mod_op = LDAP_MOD_ADD | LDAP_MOD_BVALUES; ldapModPkt.mod_type = L"pKT"; ldapModPkt.mod_vals.modv_bvals = rgModPktVals;
//
// Generate a PKT Guid attribute
//
UuidCreate( &idPkt );
ldapPktGuid.bv_len = sizeof(GUID); ldapPktGuid.bv_val = (PCHAR) &idPkt;
rgModPktGuidVals[0] = &ldapPktGuid; rgModPktGuidVals[1] = NULL;
ldapModPktGuid.mod_op = LDAP_MOD_ADD | LDAP_MOD_BVALUES; ldapModPktGuid.mod_type = L"pKTGuid"; ldapModPktGuid.mod_vals.modv_bvals = rgModPktGuidVals;
//
// Generate a Remote-Server-Name attribute
//
rgModServerVals[0] = L"*"; rgModServerVals[1] = NULL;
ldapModServer.mod_op = LDAP_MOD_ADD; ldapModServer.mod_type = L"remoteServerName"; ldapModServer.mod_vals.modv_strvals = rgModServerVals;
//
// Assemble all the LDAPMod structures
//
rgldapMods[0] = &ldapModClass; rgldapMods[1] = &ldapModCN; rgldapMods[2] = &ldapModPkt; rgldapMods[3] = &ldapModPktGuid; rgldapMods[4] = &ldapModServer; rgldapMods[5] = NULL;
//
// Create the Dfs metadata object.
//
dwErr = ldap_add_sW( pldap, wszDfsConfigDN, rgldapMods );
#if DBG
if (DfsDebug) DbgPrint("ldap_add_sW(2) returned 0x%x\n", dwErr); #endif
}
if (dwErr != LDAP_SUCCESS) { dwErr = LdapMapErrorToWin32(dwErr); goto Cleanup; }
//
// Create a machine ACE
//
dwErr = DfsAddMachineAce( pldap, wszDcName, wszDfsConfigDN, wszServerName); if (dwErr != ERROR_SUCCESS) { goto Cleanup; }
//
// Tell the server to add itself to the object
//
dwErr = DfspBindToServer( wszServerName, &netdfs_bhandle );
#if DBG
if (DfsDebug) DbgPrint("DfspBindToServer returned %d\n", dwErr); #endif
if (dwErr == NERR_Success) {
RpcTryExcept {
dwErr = NetrDfsAddFtRoot( wszServerName, wszDcName, wszRootShare, wszFtDfsName, (wszComment != NULL) ? wszComment : L"", wszDfsConfigDN, fNewFTDfs, dwFlags, &RootList);
#if DBG
if (DfsDebug) DbgPrint("NetrDfsAddFtRoot returned %d\n", dwErr); #endif
} RpcExcept(1) {
dwErr = RpcExceptionCode();
} RpcEndExcept;
DfspFreeBinding( netdfs_bhandle );
}
#if DBG
if (DfsDebug) { if (dwErr == ERROR_SUCCESS && RootList != NULL) { ULONG n;
DbgPrint("cEntries=%d\n", RootList->cEntries); for (n = 0; n < RootList->cEntries; n++) DbgPrint("[%d]%ws\n", n, RootList->Entry[n].ServerShare); } } #endif
if (dwErr == ERROR_SUCCESS && RootList != NULL) { ULONG n;
for (n = 0; n < RootList->cEntries; n++) { DfspNotifyFtRoot( RootList->Entry[n].ServerShare, wszDcName); } NetApiBufferFree(RootList); }
if (dwErr == ERROR_ALREADY_EXISTS) { goto Cleanup; } else if (dwErr != ERROR_SUCCESS) { goto TearDown; }
//
// Have the DC flush the Ft table
//
DfspFlushFtTable( wszDcName, wszFtDfsName);
//
// Flush the local Pkt
//
DfspFlushPkt(NULL);
goto Cleanup;
TearDown:
//
// At this point we have added an ACE to the acl list to allow
// this machine to write the Dfs BLOB. But the add failed, so we
// need to remove the ACE we set earlier. If this fails we continue
// on anyway.
//
dwErr2 = DfsRemoveMachineAce( pldap, wszDcName, wszDfsConfigDN, wszServerName);
rgAttrs[0] = L"remoteServerName"; rgAttrs[1] = NULL;
if (pMsg != NULL) { ldap_msgfree(pMsg); pMsg = NULL; }
dwErr2 = ldap_search_sW( pldap, wszDfsConfigDN, LDAP_SCOPE_BASE, L"(objectClass=*)", rgAttrs, 0, &pMsg);
if (dwErr2 != LDAP_SUCCESS) { dwErr2 = LdapMapErrorToWin32(dwErr2); goto Cleanup; }
dwErr2 = ERROR_SUCCESS;
pmsgServers = ldap_first_entry(pldap, pMsg);
if (pmsgServers != NULL) {
rgServers = ldap_get_valuesW( pldap, pmsgServers, L"remoteServerName");
if (rgServers != NULL) { cServers = ldap_count_valuesW( rgServers ); if (cServers == 1) { //
// Delete the Dfs metadata object.
//
ULONG RetryCount = MAX_DFS_LDAP_RETRY;
do { dwErr2 = ldap_delete_sW( pldap, wszDfsConfigDN); #if DBG
if (dwErr2 == LDAP_BUSY) { if (DfsDebug) DbgPrint("delete object returning %d\n", dwErr2); } #endif
} while ( RetryCount-- && (dwErr2 == LDAP_BUSY) ); } ldap_value_freeW( rgServers ); } else { dwErr2 = ERROR_OUTOFMEMORY; } } else { dwErr2 = ERROR_OUTOFMEMORY; }
if (dwErr2 != ERROR_SUCCESS) { goto Cleanup; }
ldap_msgfree(pMsg); pMsg = NULL;
Cleanup:
if (pMsg != NULL) ldap_msgfree(pMsg);
if (pldap != NULL) ldap_unbind( pldap );
if (wszConfigurationDN != NULL) free(wszConfigurationDN);
if (wszDfsConfigDN != NULL) free(wszDfsConfigDN);
#if DBG
if (DfsDebug) DbgPrint("DfspCreateFtDfs returning %d\n", dwErr); #endif
return( dwErr );
}
//+----------------------------------------------------------------------------
//
// Function: DfspTearDownFtDfs
//
// Synopsis: Updates/deletes the Ds object representing the FtDfs
//
// Arguments: wszServerName - Name of server we're removing
// wszDcName - DC to use
// wszRootShare - Root share
// wszFtDfsName - Name of FtDfs we are modifying
// dwFlags - 0
//
// Returns: NTSTATUS of the call (STATUS_SUCCESS or error)
//
//-----------------------------------------------------------------------------
DWORD DfspTearDownFtDfs( IN LPWSTR wszServerName, IN LPWSTR wszDcName, IN LPWSTR wszRootShare, IN LPWSTR wszFtDfsName, IN DWORD dwFlags) { DWORD dwErr = ERROR_SUCCESS;
LPWSTR wszDfsConfigDN = NULL; LPWSTR wszConfigurationDN = NULL; PDFSM_ROOT_LIST RootList = NULL;
LDAP *pldap = NULL; PLDAPMessage pMsg = NULL;
LDAPModW ldapModServer; LPWSTR rgAttrs[5]; PLDAPModW rgldapMods[6];
LDAPMessage *pmsgServers; PWCHAR *rgServers; DWORD cServers; ULONG Size;
#if DBG
if (DfsDebug) DbgPrint("DfspTearDownFtDfs(%ws,%ws,%ws,%ws,%d)\n", wszServerName, wszDcName, wszRootShare, wszFtDfsName, dwFlags); #endif
dwErr = DfspLdapOpen( wszDcName, &pldap, &wszConfigurationDN);
if (dwErr != ERROR_SUCCESS) {
goto Cleanup;
}
if ((dwFlags & DFS_FORCE_REMOVE) != 0) {
dwErr = DfspBindToServer(wszDcName, &netdfs_bhandle);
} else {
dwErr = DfspBindToServer(wszServerName, &netdfs_bhandle);
}
if (dwErr == NERR_Success) {
RpcTryExcept {
dwErr = NetrDfsRemoveFtRoot( wszServerName, wszDcName, wszRootShare, wszFtDfsName, dwFlags, &RootList);
#if DBG
if (DfsDebug) DbgPrint("NetrDfsRemoveFtRoot returned %d\n", dwErr); #endif
} RpcExcept(1) {
dwErr = RpcExceptionCode();
} RpcEndExcept;
DfspFreeBinding( netdfs_bhandle );
}
#if DBG
if (DfsDebug) { if (dwErr == ERROR_SUCCESS && RootList != NULL) { ULONG n;
DbgPrint("cEntries=%d\n", RootList->cEntries); for (n = 0; n < RootList->cEntries; n++) DbgPrint("[%d]%ws\n", n, RootList->Entry[n].ServerShare); } } #endif
if (dwErr == ERROR_SUCCESS && RootList != NULL) {
ULONG n;
for (n = 0; n < RootList->cEntries; n++) {
DfspNotifyFtRoot( RootList->Entry[n].ServerShare, wszDcName);
}
NetApiBufferFree(RootList);
}
if (dwErr != ERROR_SUCCESS) {
goto Cleanup;
}
//
// Build the name of the object representing the FtDfs
//
Size = wcslen(L"CN=") + wcslen(wszFtDfsName) + wcslen(L",") + wcslen(wszConfigurationDN); if (Size > MAX_PATH) { dwErr = ERROR_DS_NAME_TOO_LONG; goto Cleanup; } wszDfsConfigDN = malloc((Size+1) * sizeof(WCHAR)); if (wszDfsConfigDN == NULL) { dwErr = ERROR_OUTOFMEMORY; goto Cleanup; } wcscpy(wszDfsConfigDN,L"CN="); wcscat(wszDfsConfigDN,wszFtDfsName); wcscat(wszDfsConfigDN,L","); wcscat(wszDfsConfigDN,wszConfigurationDN);
//
// Remove machine ACE
//
dwErr = DfsRemoveMachineAce( pldap, wszDcName, wszDfsConfigDN, wszServerName);
//
// If this was the last root, remove DS obj representing this FtDfs
//
rgAttrs[0] = L"remoteServerName"; rgAttrs[1] = NULL;
dwErr = ldap_search_sW( pldap, wszDfsConfigDN, LDAP_SCOPE_BASE, L"(objectClass=*)", rgAttrs, 0, &pMsg);
if (dwErr != LDAP_SUCCESS) {
dwErr = LdapMapErrorToWin32(dwErr);
goto Cleanup;
}
dwErr = ERROR_SUCCESS;
pmsgServers = ldap_first_entry(pldap, pMsg);
if (pmsgServers != NULL) {
rgServers = ldap_get_valuesW( pldap, pmsgServers, L"remoteServerName");
if (rgServers != NULL) {
cServers = ldap_count_valuesW( rgServers );
if (cServers == 1) { //
// Delete the Dfs metadata object.
//
ULONG RetryCount = MAX_DFS_LDAP_RETRY;
do { dwErr = ldap_delete_sW( pldap, wszDfsConfigDN); #if DBG
if (dwErr == LDAP_BUSY) { if (DfsDebug) DbgPrint("delete object returning %d\n", dwErr); } #endif
} while ( RetryCount-- && (dwErr == LDAP_BUSY) );
if (dwErr != LDAP_SUCCESS) { dwErr = LdapMapErrorToWin32(dwErr);
} else { dwErr = ERROR_SUCCESS; } }
ldap_value_freeW( rgServers );
} else {
dwErr = ERROR_OUTOFMEMORY;
}
} else {
dwErr = ERROR_OUTOFMEMORY;
}
ldap_msgfree( pMsg ); pMsg = NULL;
if (dwErr != ERROR_SUCCESS) {
goto Cleanup;
}
//
// Have the DC flush the Ft table
//
DfspFlushFtTable( wszDcName, wszFtDfsName);
//
// Flush the local Pkt
//
DfspFlushPkt(NULL);
Cleanup:
#if DBG
if (DfsDebug) DbgPrint("DfspTearDownFtDfs at Cleanup:\n"); #endif
if (pMsg != NULL) ldap_msgfree( pMsg );
if (pldap != NULL) ldap_unbind( pldap );
if (wszConfigurationDN != NULL) free(wszConfigurationDN);
if (wszDfsConfigDN != NULL) free(wszDfsConfigDN);
#if DBG
if (DfsDebug) DbgPrint("DfspTearDownFtDfs returning %d\n", dwErr); #endif
return( dwErr );
}
//+----------------------------------------------------------------------------
//
// Function: DfspFlushFtTable
//
// Synopsis: Goes to a DC and flushes an entry from its FtDfs name cache
//
// Arguments: wszDcName - Name of DC
// wszFtDfsName - The FtDfs name to flush
//
// Returns: NTSTATUS of the call (STATUS_SUCCESS or error)
//
//-----------------------------------------------------------------------------
VOID DfspFlushFtTable( LPWSTR wszDcName, LPWSTR wszFtDfsName) { DWORD dwErr;
//
// We should have a valid ServerName. Lets try to bind to it,
// and call the server.
//
dwErr = DfspBindToServer( wszDcName, &netdfs_bhandle );
if (dwErr == NERR_Success) {
RpcTryExcept {
dwErr = NetrDfsFlushFtTable( wszDcName, wszFtDfsName);
} RpcExcept(1) {
dwErr = RpcExceptionCode();
} RpcEndExcept;
DfspFreeBinding( netdfs_bhandle );
}
}
//+----------------------------------------------------------------------------
//
// Function: DfspSetDomainToDc
//
// Synopsis: Sets a DC in the special table to 'active'.
//
// Arguments: DomainName -- Domain of DC to set active
// DcName -- Dc to make active
//
// Returns: NTSTATUS of the call (STATUS_SUCCESS or error)
//
//-----------------------------------------------------------------------------
NTSTATUS DfspSetDomainToDc( LPWSTR DomainName, LPWSTR DcName) { PDFS_SPECIAL_SET_DC_INPUT_ARG arg = NULL; NTSTATUS NtStatus; HANDLE DriverHandle = NULL; IO_STATUS_BLOCK IoStatusBlock; OBJECT_ATTRIBUTES objectAttributes; UNICODE_STRING DfsDriverName; PDFS_IS_VALID_PREFIX_ARG pPrefixArg = NULL; PCHAR cp; ULONG Size;
if (DomainName == NULL || DcName == NULL) {
NtStatus = STATUS_INVALID_PARAMETER; goto exit_with_status;
}
Size = sizeof(DFS_SPECIAL_SET_DC_INPUT_ARG) + wcslen(DomainName) * sizeof(WCHAR) + wcslen(DcName) * sizeof(WCHAR);
arg = (PDFS_SPECIAL_SET_DC_INPUT_ARG) malloc(Size);
if (arg == NULL) {
NtStatus = STATUS_INSUFFICIENT_RESOURCES; goto exit_with_status;
}
RtlZeroMemory(arg, Size);
arg->SpecialName.Length = wcslen(DomainName) * sizeof(WCHAR); arg->SpecialName.MaximumLength = arg->SpecialName.Length;
arg->DcName.Length = wcslen(DcName) * sizeof(WCHAR); arg->DcName.MaximumLength = arg->DcName.Length;
cp = (PCHAR)arg + sizeof(DFS_SPECIAL_SET_DC_INPUT_ARG);
arg->SpecialName.Buffer = (WCHAR *)cp; RtlCopyMemory(cp, DomainName, arg->SpecialName.Length); cp += arg->SpecialName.Length;
arg->DcName.Buffer = (WCHAR *)cp; RtlCopyMemory(cp, DcName, arg->DcName.Length);
POINTER_TO_OFFSET(arg->SpecialName.Buffer, arg); POINTER_TO_OFFSET(arg->DcName.Buffer, arg);
RtlInitUnicodeString(&DfsDriverName, DFS_DRIVER_NAME);
InitializeObjectAttributes( &objectAttributes, &DfsDriverName, OBJ_CASE_INSENSITIVE, NULL, NULL );
NtStatus = NtCreateFile( &DriverHandle, SYNCHRONIZE | FILE_WRITE_DATA, &objectAttributes, &IoStatusBlock, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_OPEN_IF, FILE_CREATE_TREE_CONNECTION | FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0);
if (NT_SUCCESS(NtStatus)) {
NtStatus = NtFsControlFile( DriverHandle, NULL, // Event,
NULL, // ApcRoutine,
NULL, // ApcContext,
&IoStatusBlock, FSCTL_DFS_SPECIAL_SET_DC, arg, Size, NULL, 0);
NtClose(DriverHandle);
}
exit_with_status:
if (arg != NULL) {
free(arg);
}
return NtStatus;
}
//+----------------------------------------------------------------------------
//
// Function: I_NetDfsIsThisADomainName
//
// Synopsis: Checks the special name table to see if the
// name matches a domain name.
//
// Arguments: [wszName] -- Name to check
//
// Returns: [ERROR_SUCCESS] -- Name is indeed a domain name.
//
// [ERROR_FILE_NOT_FOUND] -- Name is not a domain name
//
//-----------------------------------------------------------------------------
DWORD I_NetDfsIsThisADomainName( LPWSTR wszName) { DWORD dwErr; PWCHAR DCList = NULL;
dwErr = DfspIsThisADomainName( wszName, &DCList);
if (DCList != NULL) {
free(DCList);
}
return dwErr;
}
//+----------------------------------------------------------------------------
//
// Function: DfspNotifyFtRoot
//
// Synopsis: Rpc's to a supposed FtDfs root
// and tells it a DC to reinit from.
//
// Arguments: wszServerShare - The server to go to, in a form of \\server\share
// wszDcName - DC to use
//
// Returns: Nothing
//
//-----------------------------------------------------------------------------
VOID DfspNotifyFtRoot( LPWSTR wszServerShare, LPWSTR wszDcName) { DWORD dwErr; ULONG i;
#if DBG
if (DfsDebug) DbgPrint("DfspNotifyFtRoot(%ws,%ws)\n", wszServerShare, wszDcName); #endif
if (wszServerShare == NULL || wszServerShare[1] != L'\\') {
return;
}
for (i = 2; wszServerShare[i] != UNICODE_NULL && wszServerShare[i] != L'\\'; i++) {
NOTHING;
}
if (wszServerShare[i] == L'\\') {
wszServerShare[i] = UNICODE_NULL; //
// We should have a valid ServerName. Lets try to bind to it,
// and call the server.
//
dwErr = DfspBindToServer( &wszServerShare[2], &netdfs_bhandle );
if (dwErr == NERR_Success) {
RpcTryExcept {
dwErr = NetrDfsSetDcAddress( &wszServerShare[2], wszDcName, 60 * 60 * 2, // 2 hours
(NET_DFS_SETDC_TIMEOUT | NET_DFS_SETDC_INITPKT) );
} RpcExcept(1) {
dwErr = RpcExceptionCode();
} RpcEndExcept;
DfspFreeBinding( netdfs_bhandle );
}
wszServerShare[i] = L'\\';
}
#if DBG
if (DfsDebug) DbgPrint("DfspNotifyFtRoot dwErr=%d\n", dwErr); #endif
}
//+----------------------------------------------------------------------------
//
// Function: DfspIsThisADomainName
//
// Synopsis: Calls the mup to have it check the special name table to see if the
// name matches a domain name. Returns a list of DC's in the domain,
// as a list of strings. The list is terminated with a double-null.
//
// Arguments: [wszName] -- Name to check
// [ppList] -- Pointer to pointer for results.
//
// Returns: [ERROR_SUCCESS] -- Name is indeed a domain name.
//
// [ERROR_FILE_NOT_FOUND] -- Name is not a domain name
//
//-----------------------------------------------------------------------------
DWORD DfspIsThisADomainName( LPWSTR wszName, PWCHAR *ppList) { NTSTATUS NtStatus; IO_STATUS_BLOCK IoStatusBlock; OBJECT_ATTRIBUTES objectAttributes; UNICODE_STRING DfsDriverName; HANDLE DriverHandle = NULL; DWORD dwErr; PCHAR OutBuf = NULL; ULONG Size = 0x100; ULONG Count = 0;
RtlInitUnicodeString(&DfsDriverName, DFS_DRIVER_NAME);
InitializeObjectAttributes( &objectAttributes, &DfsDriverName, OBJ_CASE_INSENSITIVE, NULL, NULL );
NtStatus = NtCreateFile( &DriverHandle, SYNCHRONIZE, &objectAttributes, &IoStatusBlock, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_OPEN_IF, FILE_CREATE_TREE_CONNECTION | FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0 );
if (!NT_SUCCESS(NtStatus)) { return ERROR_FILE_NOT_FOUND; }
Retry:
OutBuf = malloc(Size);
if (OutBuf == NULL) {
NtClose(DriverHandle); return ERROR_NOT_ENOUGH_MEMORY;
}
NtStatus = NtFsControlFile( DriverHandle, NULL, // Event,
NULL, // ApcRoutine,
NULL, // ApcContext,
&IoStatusBlock, FSCTL_DFS_GET_SPC_TABLE, wszName, (wcslen(wszName) + 1) * sizeof(WCHAR), OutBuf, Size );
if (NtStatus == STATUS_SUCCESS) {
dwErr = ERROR_SUCCESS;
} else if (NtStatus == STATUS_BUFFER_OVERFLOW && ++Count < 5) {
Size = *((ULONG *)OutBuf); free(OutBuf); goto Retry; } else {
dwErr = ERROR_FILE_NOT_FOUND;
}
NtClose(DriverHandle);
*ppList = (WCHAR *)OutBuf;
return dwErr; }
DWORD DfspLdapOpen( LPWSTR wszDcName, LDAP **ppldap, LPWSTR *pwszObjectName) { DWORD dwErr; DWORD i; ULONG Size; ULONG Len;
PDOMAIN_CONTROLLER_INFO pDCInfo = NULL; PLDAPMessage pMsg = NULL;
LDAP *pldap = NULL;
LPWSTR wszConfigurationDN = NULL;
LPWSTR rgAttrs[5];
if (wszDcName == NULL || wcslen(wszDcName) == 0 || ppldap == NULL || pwszObjectName == NULL ) { dwErr = ERROR_INVALID_PARAMETER; goto Cleanup; }
#if DBG
if (DfsDebug) DbgPrint("DfspLdapOpen(%ws)\n", wszDcName); #endif
pldap = ldap_init(wszDcName, LDAP_PORT);
if (pldap == NULL) {
#if DBG
if (DfsDebug) DbgPrint("DfspLdapOpen:ldap_init failed\n"); #endif
dwErr = ERROR_INVALID_NAME; goto Cleanup;
}
dwErr = ldap_set_option(pldap, LDAP_OPT_AREC_EXCLUSIVE, LDAP_OPT_ON); if (dwErr != LDAP_SUCCESS) { pldap = NULL; goto Cleanup; }
dwErr = ldap_bind_s(pldap, NULL, NULL, LDAP_AUTH_SSPI);
if (dwErr != LDAP_SUCCESS) { #if DBG
if (DfsDebug) DbgPrint("ldap_bind_s failed with ldap error %d\n", dwErr); #endif
pldap = NULL; dwErr = LdapMapErrorToWin32(dwErr); goto Cleanup; }
//
// Get attribute "defaultNameContext" containing name of entry we'll be
// using for our DN
//
rgAttrs[0] = L"defaultnamingContext"; rgAttrs[1] = NULL;
dwErr = ldap_search_s( pldap, L"", LDAP_SCOPE_BASE, L"(objectClass=*)", rgAttrs, 0, &pMsg);
if (dwErr == LDAP_SUCCESS) {
PLDAPMessage pEntry = NULL; PWCHAR *rgszNamingContexts = NULL; DWORD i, cNamingContexts;
dwErr = ERROR_SUCCESS;
if ((pEntry = ldap_first_entry(pldap, pMsg)) != NULL && (rgszNamingContexts = ldap_get_values(pldap, pEntry, rgAttrs[0])) != NULL && (cNamingContexts = ldap_count_values(rgszNamingContexts)) > 0) {
wszConfigurationDN = malloc((wcslen(rgszNamingContexts[0]) + 1) * sizeof(WCHAR)); if (wszConfigurationDN != NULL) wcscpy( wszConfigurationDN, rgszNamingContexts[0]); else dwErr = ERROR_OUTOFMEMORY; } else { dwErr = ERROR_UNEXP_NET_ERR; }
if (rgszNamingContexts != NULL) ldap_value_free( rgszNamingContexts );
} else {
dwErr = LdapMapErrorToWin32(dwErr);
}
if (dwErr != ERROR_SUCCESS) { #if DBG
if (DfsDebug) DbgPrint("Unable to find Configuration naming context\n"); #endif
goto Cleanup; }
//
// Create string with full object name
//
Size = wcslen(DfsConfigContainer) * sizeof(WCHAR) + sizeof(WCHAR) + wcslen(wszConfigurationDN) * sizeof(WCHAR) + sizeof(WCHAR);
*pwszObjectName = malloc(Size);
if (*pwszObjectName == NULL) { dwErr = ERROR_OUTOFMEMORY; goto Cleanup; }
wcscpy(*pwszObjectName,DfsConfigContainer); wcscat(*pwszObjectName,L","); wcscat(*pwszObjectName,wszConfigurationDN);
#if DBG
if (DfsDebug) DbgPrint("DfsLdapOpen:object name=[%ws]\n", *pwszObjectName); #endif
Cleanup:
if (pDCInfo != NULL) NetApiBufferFree( pDCInfo );
if (dwErr != ERROR_SUCCESS) { ldap_unbind( pldap ); pldap = NULL; }
if (wszConfigurationDN != NULL) free(wszConfigurationDN);
if (pMsg != NULL) ldap_msgfree(pMsg);
*ppldap = pldap;
#if DBG
if (DfsDebug) DbgPrint("DfsLdapOpen:returning %d\n", dwErr); #endif
return( dwErr );
}
//+----------------------------------------------------------------------------
//
// Function: DfspIsInvalidName, local
//
// Synopsis: Sees if a DomDfs name is Invalid
//
// Arguments: [DomDfsName] -- Name test.
//
// Returns: TRUE if invalid, FALSE otherwise.
//
//-----------------------------------------------------------------------------
BOOLEAN DfspIsInvalidName( LPWSTR ShareName) { ULONG i;
for (i = 0; InvalidNames[i] != NULL; i++) {
if (_wcsicmp(InvalidNames[i], ShareName) == 0) { return TRUE; }
}
return FALSE; }
|