windows-nt/Source/XPSP1/NT/ds/netapi/svcdlls/dfs/client/dfsstub.c
2020-09-26 16:20:57 +08:00

5915 lines
143 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//-----------------------------------------------------------------------------
//
// 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 <permit.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 );
}
//
// 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 );
}
//
// 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 );
}
//
// 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;
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 );
}
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;
}