2518 lines
61 KiB
C++
2518 lines
61 KiB
C++
//+----------------------------------------------------------------------------
|
|
//
|
|
// Copyright (C) 1995, Microsoft Corporation
|
|
//
|
|
// File: dfssetup.cxx
|
|
//
|
|
// Contents: Code to setup Dfs on a machine.
|
|
//
|
|
// Note that this code can be built as an exe or as a DLL. To
|
|
// switch between the two, simply edit the following fields in
|
|
// the sources file:
|
|
// TARGETTYPE=[PROGRAM | DYNLINK]
|
|
// UMTYPE=[console | windows]
|
|
// Delete the following two lines from sources to build an exe.
|
|
// DLLDEF=obj\*\dfssetup.def
|
|
// DLLENTRY=_DllMainCRTStartup
|
|
// DLLBASE=@$(BASEDIR)\PUBLIC\SDK\LIB\coffbase.txt,dfssetup
|
|
//
|
|
// Classes: None
|
|
//
|
|
// Functions:
|
|
//
|
|
// History: 12-28-95 Milans Created
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
extern "C" {
|
|
#include <nt.h>
|
|
#include <ntrtl.h>
|
|
#include <nturtl.h>
|
|
#include <stdlib.h>
|
|
}
|
|
|
|
#include <windows.h>
|
|
#include <rpc.h> // For UuidCreate
|
|
|
|
#include <winldap.h>
|
|
#include <dsgetdc.h>
|
|
|
|
#include <lm.h>
|
|
#include <dfsstr.h>
|
|
#include <dfsmsrv.h>
|
|
|
|
#include <debug.h> // Needed for debug printing
|
|
#include <dfsm.hxx> // Needed for volume types
|
|
#include <lmerrext.h>
|
|
|
|
#include "registry.hxx" // Helper functions...
|
|
#include "setupsvc.hxx"
|
|
|
|
#include "config.hxx" // Config UI functions
|
|
|
|
//
|
|
// Until we get the schema right in the DS, we have to set our own SD on
|
|
// certain objects
|
|
//
|
|
|
|
#include <aclapi.h>
|
|
#include <permit.h>
|
|
|
|
DECLARE_DEBUG(DfsSetup)
|
|
DECLARE_INFOLEVEL(DfsSetup)
|
|
|
|
#if DBG == 1
|
|
#define dprintf(x) DfsSetupInlineDebugOut x
|
|
# else
|
|
#define dprintf(x)
|
|
#endif
|
|
|
|
#define MAX_NETBIOS_NAME_LEN 16+1
|
|
|
|
extern DWORD
|
|
RemoveDfs(void);
|
|
|
|
BOOLEAN
|
|
DfsCheckForOldDfsService();
|
|
|
|
BOOLEAN
|
|
DfsIsDfsServiceRunning();
|
|
|
|
VOID
|
|
Usage();
|
|
|
|
DWORD
|
|
SetupDfsRoot(
|
|
LPWSTR wszDfsRootShare);
|
|
|
|
DWORD
|
|
SetupFTDfs(
|
|
IN LPWSTR wszRootShare,
|
|
IN LPWSTR wszFTDfsName);
|
|
|
|
DWORD
|
|
InitializeVolumeObjectStorage();
|
|
|
|
DWORD
|
|
CreateVolumeObject(
|
|
IN LPWSTR wszObjectName,
|
|
IN LPWSTR pwszEntryPath,
|
|
IN LPWSTR pwszServer,
|
|
IN LPWSTR pwszShare,
|
|
IN LPWSTR pwszComment,
|
|
OUT GUID *guidVolume);
|
|
|
|
DWORD
|
|
CreateFTRootVolumeInfo(
|
|
LPWSTR wszObjectName,
|
|
LPWSTR wszFTDfsConfigDN,
|
|
LPWSTR wszDomainName,
|
|
LPWSTR wszDfsName,
|
|
LPWSTR wszServerName,
|
|
LPWSTR wszShareName,
|
|
LPWSTR wszSharePath,
|
|
LPWSTR wszDCName,
|
|
BOOLEAN fNewFTDfs);
|
|
|
|
DWORD
|
|
StoreLvolInfo(
|
|
IN GUID *pVolumeID,
|
|
IN PWSTR pwszStorageID,
|
|
IN PWSTR pwszShareName,
|
|
IN PWSTR pwszEntryPath,
|
|
IN ULONG ulVolumeType);
|
|
|
|
DWORD
|
|
GetDomainAndComputerName(
|
|
OUT LPWSTR wszDomain OPTIONAL,
|
|
OUT LPWSTR wszComputer OPTIONAL);
|
|
|
|
DWORD
|
|
GetSharePath(
|
|
IN LPWSTR wszShareName,
|
|
OUT LPWSTR wszSharePath);
|
|
|
|
DWORD
|
|
TeardownFtDfs(
|
|
IN LPWSTR wszRootShare,
|
|
IN LPWSTR wszFTDfsName);
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: main
|
|
//
|
|
// Synopsis: Entry point in case you want to build this as an exe.
|
|
// Configures all Dfs components on a machine.
|
|
//
|
|
// Arguments: [argc] --
|
|
// [argv] --
|
|
//
|
|
// Returns: Nothing
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void _cdecl
|
|
main(int argc, char *argv[])
|
|
{
|
|
DWORD dwErr = ERROR_SUCCESS;
|
|
DWORD cbRootLen;
|
|
BOOL fRootSetup = FALSE;
|
|
BOOLEAN OldDfsService = FALSE;
|
|
WCHAR wszDfsRootShare[ MAX_PATH ];
|
|
|
|
|
|
//
|
|
// Figure out the type of machine we are installing on - client or root
|
|
//
|
|
|
|
|
|
if (argc != 1 && argc != 3) {
|
|
Usage();
|
|
return;
|
|
}
|
|
|
|
if (argc == 3) {
|
|
|
|
fRootSetup = TRUE;
|
|
|
|
}
|
|
|
|
if ((dwErr == ERROR_SUCCESS) && fRootSetup) {
|
|
|
|
if (_stricmp( argv[1], "-root" ) != 0) {
|
|
|
|
Usage();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
cbRootLen = strlen(argv[2]);
|
|
|
|
mbstowcs( wszDfsRootShare, argv[2], cbRootLen + 1 );
|
|
|
|
dprintf((DEB_ERROR,"Setting up Dfs Root...\n"));
|
|
|
|
} else {
|
|
|
|
dprintf((DEB_ERROR,"Setting up Dfs Server...\n"));
|
|
|
|
}
|
|
|
|
//
|
|
// Configure the Dfs Driver
|
|
//
|
|
|
|
if (dwErr == ERROR_SUCCESS) {
|
|
|
|
dwErr = ConfigDfs();
|
|
|
|
if (dwErr == ERROR_SUCCESS) {
|
|
|
|
dwErr = ConfigDfsService();
|
|
|
|
if (dwErr != ERROR_SUCCESS) {
|
|
|
|
dprintf((
|
|
DEB_ERROR, "Win32 error configuring Dfs Service %d\n",
|
|
dwErr));
|
|
|
|
(void)RemoveDfs();
|
|
|
|
} else {
|
|
|
|
dprintf((DEB_ERROR,"Successfully configured Dfs...\n") );
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
dprintf((DEB_ERROR,"Error %d configuring Dfs driver!\n", dwErr));
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
//
|
|
// If this is a root setup, configure the necessary information
|
|
//
|
|
|
|
if (dwErr == ERROR_SUCCESS && fRootSetup) {
|
|
|
|
dwErr = SetupDfsRoot( wszDfsRootShare );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: SetupDfsRoot
|
|
//
|
|
// Synopsis: Does necessary setup to make this Dfs a root of the Dfs.
|
|
//
|
|
// Arguments: [wszDfsRootShare] -- The share to use as the Dfs root.
|
|
//
|
|
// Returns: Win32 error from configuring the root storages etc.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
DWORD
|
|
SetupDfsRoot(
|
|
LPWSTR wszDfsRootShare)
|
|
{
|
|
DWORD dwErr = ERROR_SUCCESS;
|
|
GUID guid;
|
|
WCHAR wszDfsRootPath[ MAX_PATH ];
|
|
WCHAR wszComputerName[ MAX_NETBIOS_NAME_LEN ];
|
|
PWCHAR wszDfsRootPrefix = NULL;
|
|
|
|
dwErr = GetDomainAndComputerName( NULL, wszComputerName );
|
|
|
|
//
|
|
// Figure out the share path for the Root Dfs share
|
|
//
|
|
|
|
if (dwErr == ERROR_SUCCESS) {
|
|
|
|
dwErr = GetSharePath( wszDfsRootShare, wszDfsRootPath );
|
|
|
|
}
|
|
|
|
//
|
|
// We have all the info we need now. Lets get to work....
|
|
//
|
|
// 1. Initialize the volume object section in the registry.
|
|
//
|
|
// 2. Initialize (ie, create if necessary) the storage used for the
|
|
// Dfs root.
|
|
//
|
|
// 3. Create the root volume object.
|
|
//
|
|
// 4. Configure the root volume as a local volume by updating the
|
|
// LocalVolumes section in the registry.
|
|
//
|
|
|
|
//
|
|
// Initialize the Dfs Manager Volume Object Store
|
|
//
|
|
|
|
if (dwErr == ERROR_SUCCESS) {
|
|
|
|
dwErr = InitializeVolumeObjectStorage();
|
|
|
|
}
|
|
|
|
|
|
if (dwErr == ERROR_SUCCESS) {
|
|
|
|
dprintf((DEB_ERROR,
|
|
"Setting [%ws] as Dfs storage root...\n", wszDfsRootPath));
|
|
|
|
dwErr = DfsInitGlobals( wszComputerName, DFS_MANAGER_SERVER );
|
|
|
|
if (dwErr == ERROR_SUCCESS) {
|
|
|
|
wszDfsRootPrefix = new WCHAR[1 +
|
|
wcslen(wszComputerName) +
|
|
1 +
|
|
wcslen(wszDfsRootShare) +
|
|
1];
|
|
|
|
if (wszDfsRootPrefix == NULL) {
|
|
|
|
dwErr = ERROR_OUTOFMEMORY;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (dwErr == ERROR_SUCCESS) {
|
|
|
|
wszDfsRootPrefix[0] = UNICODE_PATH_SEP;
|
|
wcscpy( &wszDfsRootPrefix[1], wszComputerName );
|
|
wcscat( wszDfsRootPrefix, UNICODE_PATH_SEP_STR );
|
|
wcscat( wszDfsRootPrefix, wszDfsRootShare );
|
|
|
|
dwErr = CreateVolumeObject(
|
|
DOMAIN_ROOT_VOL, // Name of volume object
|
|
wszDfsRootPrefix, // EntryPath of volume
|
|
wszComputerName, // Server name
|
|
wszDfsRootShare, // Share name
|
|
L"Dfs Root Volume", // Comment
|
|
&guid); // Id of created volume
|
|
|
|
}
|
|
|
|
if (dwErr == ERROR_SUCCESS) {
|
|
|
|
dwErr = StoreLvolInfo(
|
|
&guid,
|
|
wszDfsRootPath,
|
|
wszDfsRootShare,
|
|
wszDfsRootPrefix,
|
|
DFS_VOL_TYPE_DFS | DFS_VOL_TYPE_REFERRAL_SVC);
|
|
|
|
}
|
|
|
|
if (wszDfsRootPrefix != NULL)
|
|
delete [] wszDfsRootPrefix;
|
|
|
|
if (dwErr != ERROR_SUCCESS)
|
|
dwErr = ERROR_INVALID_FUNCTION;
|
|
|
|
if (dwErr == ERROR_SUCCESS) {
|
|
|
|
DWORD dwErr;
|
|
CRegKey cregVolumesDir( HKEY_LOCAL_MACHINE, &dwErr, VOLUMES_DIR );
|
|
|
|
if (dwErr == ERROR_SUCCESS) {
|
|
|
|
CRegSZ cregRootShare(
|
|
cregVolumesDir,
|
|
ROOT_SHARE_VALUE_NAME,
|
|
wszDfsRootShare );
|
|
|
|
dwErr = cregRootShare.QueryErrorStatus();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return( dwErr );
|
|
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: SetupFTDfs
|
|
//
|
|
// Synopsis: Main exported function
|
|
//
|
|
// Arguments: [argc] --
|
|
// [argv] --
|
|
//
|
|
// Returns: Nothing
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
DWORD
|
|
SetupFTDfs(
|
|
IN LPWSTR wszRootShare,
|
|
IN LPWSTR wszFTDfsName)
|
|
{
|
|
DWORD dwErr = ERROR_SUCCESS;
|
|
|
|
WCHAR wszDomainName[MAX_PATH+1];
|
|
WCHAR wszComputerName[MAX_PATH+1];
|
|
WCHAR wszRootSharePath[MAX_PATH+1];
|
|
WCHAR wszDfsConfigDN[MAX_PATH+1];
|
|
WCHAR wszSDDfsConfigDN[MAX_PATH+1];
|
|
WCHAR wszConfigurationDN[ MAX_PATH+1 ];
|
|
WCHAR wszServerShare[MAX_PATH+1];
|
|
|
|
PDOMAIN_CONTROLLER_INFO pDCInfo = 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;
|
|
|
|
//
|
|
// We need some information before we start:
|
|
//
|
|
// 1. Our Domain name
|
|
//
|
|
// 2. Our Computer name
|
|
//
|
|
// 3. The share path of wszRootShare
|
|
//
|
|
// 4. The DN of the Configuration OU of our domain
|
|
//
|
|
|
|
dwErr = GetDomainAndComputerName( wszDomainName, wszComputerName );
|
|
|
|
if (dwErr != ERROR_SUCCESS) {
|
|
|
|
dprintf((
|
|
DEB_ERROR,
|
|
"Win32 Error %d getting Domain/Computer name\n", dwErr));
|
|
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
dwErr = GetSharePath( wszRootShare, wszRootSharePath );
|
|
|
|
if (dwErr != ERROR_SUCCESS) {
|
|
|
|
dprintf((
|
|
DEB_ERROR,
|
|
"Win32 Error %d getting share path for %ws\n",
|
|
dwErr, wszRootShare));
|
|
|
|
goto Cleanup;
|
|
}
|
|
|
|
dwErr = DsGetDcName(
|
|
NULL, // Computer to remote to
|
|
NULL, // Domain - use our own
|
|
NULL, // Domain Guid
|
|
NULL, // Site Guid
|
|
DS_DIRECTORY_SERVICE_REQUIRED | // Flags
|
|
DS_PDC_REQUIRED,
|
|
&pDCInfo); // Return info
|
|
|
|
if (dwErr != ERROR_SUCCESS) {
|
|
|
|
dprintf((
|
|
DEB_ERROR,
|
|
"DsGetDcName failed with Win32 Error %d\n", dwErr));
|
|
|
|
goto Cleanup;
|
|
}
|
|
|
|
pldap = ldap_initW(&pDCInfo->DomainControllerAddress[2], LDAP_PORT);
|
|
|
|
if (pldap == NULL) {
|
|
|
|
dprintf((DEB_ERROR, "ldap_init failed\n"));
|
|
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
dwErr = ldap_set_option(pldap, LDAP_OPT_AREC_EXCLUSIVE, LDAP_OPT_ON);
|
|
if (dwErr != LDAP_SUCCESS) {
|
|
|
|
dprintf((
|
|
DEB_ERROR,
|
|
"ldap_set_option failed with ldap error %d\n", dwErr));
|
|
|
|
pldap = NULL;
|
|
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
dwErr = ldap_bind_s(pldap, NULL, NULL, LDAP_AUTH_SSPI);
|
|
|
|
if (dwErr != LDAP_SUCCESS) {
|
|
|
|
dprintf((
|
|
DEB_ERROR,
|
|
"ldap_bind_s failed with ldap error %d\n", dwErr));
|
|
|
|
pldap = NULL;
|
|
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
rgAttrs[0] = L"defaultnamingContext";
|
|
rgAttrs[1] = NULL;
|
|
|
|
dwErr = ldap_search_sW(
|
|
pldap,
|
|
L"",
|
|
LDAP_SCOPE_BASE,
|
|
L"(objectClass=*)",
|
|
rgAttrs,
|
|
0,
|
|
&pMsg);
|
|
|
|
if (dwErr == LDAP_SUCCESS) {
|
|
|
|
PLDAPMessage pEntry = NULL;
|
|
PWCHAR *rgszNamingContexts = NULL;
|
|
DWORD i, cNamingContexts;
|
|
BOOLEAN fFoundCfg;
|
|
|
|
if ((pEntry = ldap_first_entry(pldap, pMsg)) != NULL &&
|
|
(rgszNamingContexts = ldap_get_valuesW(pldap, pEntry, rgAttrs[0])) != NULL &&
|
|
(cNamingContexts = ldap_count_valuesW(rgszNamingContexts)) > 0) {
|
|
|
|
wcscpy( wszConfigurationDN, *rgszNamingContexts );
|
|
fFoundCfg = TRUE;
|
|
|
|
if (!fFoundCfg) {
|
|
|
|
dwErr = ERROR_UNEXP_NET_ERR;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
dwErr = ERROR_UNEXP_NET_ERR;
|
|
|
|
}
|
|
|
|
if (pEntry != NULL)
|
|
ldap_msgfree( pEntry );
|
|
|
|
if (rgszNamingContexts != NULL)
|
|
ldap_value_freeW( rgszNamingContexts );
|
|
|
|
}
|
|
|
|
if (dwErr != ERROR_SUCCESS) {
|
|
|
|
dprintf((DEB_ERROR, "Unable to find Configuration naming context\n"));
|
|
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
//
|
|
// Great, we have all the parameters now, so configure the DS
|
|
//
|
|
|
|
//
|
|
// See if the DfsConfiguration object exists; if not, create it.
|
|
//
|
|
|
|
wsprintf(
|
|
wszDfsConfigDN,
|
|
L"CN=Dfs-Configuration,CN=System,%ws",
|
|
wszConfigurationDN);
|
|
|
|
rgAttrs[0] = L"cn";
|
|
rgAttrs[1] = NULL;
|
|
|
|
dwErr = ldap_search_sW(
|
|
pldap,
|
|
wszDfsConfigDN,
|
|
LDAP_SCOPE_BASE,
|
|
L"(objectClass=*)",
|
|
rgAttrs,
|
|
0,
|
|
&pMsg);
|
|
|
|
if (dwErr == LDAP_SUCCESS)
|
|
ldap_msgfree( pMsg );
|
|
|
|
if (dwErr == LDAP_NO_SUCH_OBJECT) {
|
|
|
|
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,
|
|
wszDfsConfigDN,
|
|
rgldapMods);
|
|
|
|
}
|
|
|
|
if (dwErr != LDAP_SUCCESS) {
|
|
|
|
dprintf((
|
|
DEB_ERROR,
|
|
"1:ldap_add_s for %ws failed with LDAP error %d\n",
|
|
wszDfsConfigDN, dwErr ));
|
|
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
//
|
|
// Check to see if we are joining an FTDfs or creating a new one.
|
|
//
|
|
|
|
wsprintf(
|
|
wszDfsConfigDN,
|
|
L"CN=%ws,CN=Dfs-Configuration,CN=System,%ws",
|
|
wszFTDfsName,
|
|
wszConfigurationDN);
|
|
|
|
wsprintf(
|
|
wszServerShare,
|
|
L"\\\\%ws\\%ws",
|
|
wszComputerName,
|
|
wszRootShare);
|
|
|
|
rgAttrs[0] = L"remoteServerName";
|
|
rgAttrs[1] = NULL;
|
|
|
|
dwErr = ldap_search_sW(
|
|
pldap,
|
|
wszDfsConfigDN,
|
|
LDAP_SCOPE_BASE,
|
|
L"(objectClass=*)",
|
|
rgAttrs,
|
|
0,
|
|
&pMsg);
|
|
|
|
if (dwErr == ERROR_SUCCESS) {
|
|
|
|
//
|
|
// We are joining an existing FT Dfs. Append our server\share to it
|
|
//
|
|
|
|
LDAPMessage *pmsgServers;
|
|
PWCHAR *rgServers, *rgNewServers;
|
|
DWORD cServers;
|
|
|
|
fNewFTDfs = FALSE;
|
|
|
|
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 );
|
|
|
|
rgNewServers = new LPWSTR [ cServers + 2 ];
|
|
|
|
if (rgNewServers != NULL) {
|
|
|
|
CopyMemory( rgNewServers, rgServers, cServers * sizeof(rgServers[0]) );
|
|
|
|
rgNewServers[cServers] = wszServerShare;
|
|
rgNewServers[cServers+1] = NULL;
|
|
|
|
ldapModServer.mod_op = LDAP_MOD_REPLACE;
|
|
ldapModServer.mod_type = L"remoteServerName";
|
|
ldapModServer.mod_vals.modv_strvals = rgNewServers;
|
|
|
|
rgldapMods[0] = &ldapModServer;
|
|
rgldapMods[1] = NULL;
|
|
|
|
dwErr = ldap_modify_sW(pldap, wszDfsConfigDN, rgldapMods);
|
|
if (LDAP_ATTRIBUTE_OR_VALUE_EXISTS == dwErr)
|
|
dwErr = ERROR_SUCCESS;
|
|
|
|
delete [] rgNewServers;
|
|
|
|
} else {
|
|
|
|
dwErr = ERROR_OUTOFMEMORY;
|
|
}
|
|
|
|
ldap_value_freeW( rgServers );
|
|
|
|
} else {
|
|
|
|
dwErr = ERROR_OUTOFMEMORY;
|
|
|
|
}
|
|
|
|
ldap_msgfree( pmsgServers );
|
|
|
|
} else {
|
|
|
|
dwErr = ERROR_OUTOFMEMORY;
|
|
|
|
}
|
|
|
|
} else 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] = wszServerShare;
|
|
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 (dwErr == ERROR_SUCCESS) {
|
|
|
|
|
|
dprintf((
|
|
DEB_ERROR,
|
|
"2:ldap_add_s worked for %ws with ldap error %d\n",
|
|
wszDfsConfigDN, dwErr));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (dwErr != LDAP_SUCCESS) {
|
|
|
|
dprintf((
|
|
DEB_ERROR,
|
|
"2:ldap_add_s failed for %ws with ldap error %d\n",
|
|
wszDfsConfigDN, dwErr));
|
|
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
//
|
|
// Finally, create the root volume object
|
|
//
|
|
|
|
dwErr = CreateFTRootVolumeInfo(
|
|
DOMAIN_ROOT_VOL,
|
|
wszDfsConfigDN,
|
|
wszDomainName,
|
|
wszFTDfsName,
|
|
wszComputerName,
|
|
wszRootShare,
|
|
wszRootSharePath,
|
|
&pDCInfo->DomainControllerAddress[2],
|
|
fNewFTDfs);
|
|
|
|
if (dwErr != LDAP_SUCCESS) {
|
|
|
|
dprintf((
|
|
DEB_ERROR, "CreateVolumeObject failed with error %d\n", dwErr));
|
|
|
|
} else {
|
|
|
|
dprintf((
|
|
DEB_ERROR, "Successfully created FT-Dfs Configuration!\n"));
|
|
|
|
}
|
|
|
|
Cleanup:
|
|
|
|
if (pDCInfo != NULL)
|
|
NetApiBufferFree( pDCInfo );
|
|
|
|
if (pldap != NULL)
|
|
ldap_unbind( pldap );
|
|
|
|
return( dwErr );
|
|
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: RemoveDfsRoot
|
|
//
|
|
// Synopsis: Removes the Dfs Root config info.
|
|
//
|
|
// Arguments: None
|
|
//
|
|
// Returns: Win32 error from registry actions
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
DWORD
|
|
RemoveDfsRoot()
|
|
{
|
|
DWORD dwErr;
|
|
CRegKey cregVolumesDir( HKEY_LOCAL_MACHINE, &dwErr, VOLUMES_DIR );
|
|
CRegKey *pcregLV = NULL;
|
|
|
|
if (dwErr != ERROR_SUCCESS) { // Unable to open volumes dir
|
|
return(dwErr);
|
|
}
|
|
|
|
pcregLV = new CRegKey( // Open local volumes section
|
|
HKEY_LOCAL_MACHINE,
|
|
REG_KEY_LOCAL_VOLUMES);
|
|
|
|
if (pcregLV != NULL) {
|
|
|
|
dwErr = pcregLV->QueryErrorStatus();
|
|
|
|
} else {
|
|
|
|
dwErr = ERROR_OUTOFMEMORY;
|
|
|
|
}
|
|
|
|
if (dwErr == ERROR_SUCCESS) {
|
|
|
|
dwErr = pcregLV->Delete(); // Delete local volumes
|
|
|
|
delete pcregLV;
|
|
|
|
pcregLV = NULL;
|
|
|
|
if (dwErr == ERROR_SUCCESS) {
|
|
|
|
//
|
|
// Recreate an empty local volumes key
|
|
//
|
|
|
|
pcregLV = new CRegKey( HKEY_LOCAL_MACHINE, REG_KEY_LOCAL_VOLUMES);
|
|
|
|
cregVolumesDir.Delete(); // Delete volumes dir
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (pcregLV != NULL) {
|
|
|
|
delete pcregLV;
|
|
|
|
}
|
|
|
|
return( dwErr );
|
|
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: DfsSetupDfs
|
|
//
|
|
// Synopsis: Entry point in case you want to build this as a DLL. This
|
|
// function is suitable for being called from a setup .inf
|
|
// file.
|
|
//
|
|
// Arguments: [cArgs] -- Count of args
|
|
// [lpszArgs] -- Array of args
|
|
// [lpszTextOut] -- On return, points to a global buffer
|
|
// containing the null string. This is required by the
|
|
// .inf file
|
|
//
|
|
// Returns: TRUE.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
LPSTR szReturn = "";
|
|
|
|
extern "C" BOOL
|
|
DfsSetupDfs(
|
|
DWORD cArgs,
|
|
LPSTR lpszArgs[],
|
|
LPSTR *lpszTextOut)
|
|
{
|
|
int argc;
|
|
LPSTR *argv;
|
|
|
|
argv = (LPSTR *) malloc( (cArgs+1) * sizeof(LPSTR) );
|
|
|
|
if (argv == NULL) {
|
|
return( FALSE );
|
|
}
|
|
|
|
argv[0] = "DfsSetup";
|
|
for (argc = 1; argc <= (int) cArgs; argc++) {
|
|
argv[ argc ] = lpszArgs[ argc-1 ];
|
|
}
|
|
|
|
main( argc, argv );
|
|
|
|
free( argv );
|
|
|
|
*lpszTextOut = szReturn;
|
|
|
|
return( TRUE );
|
|
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: DfsSetupDfsRoot
|
|
//
|
|
// Synopsis: Entry point for setting up just the root part of Dfs in
|
|
// case you want to build this as a DLL. This function is
|
|
// suitable for being called from a setup .inf file.
|
|
//
|
|
// Arguments: [cArgs] -- Count of args
|
|
// [lpszArgs] -- Array of args
|
|
// [lpszTextOut] -- On return, points to a global buffer
|
|
// containing the null string. This is required by the
|
|
// .inf file
|
|
//
|
|
// Returns: TRUE.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
BOOLEAN
|
|
DfsSetupDfsRoot(
|
|
DWORD cArgs,
|
|
LPSTR szArgs[],
|
|
LPSTR *szTextOut)
|
|
{
|
|
|
|
if (cArgs == 1) {
|
|
|
|
DWORD dwErr;
|
|
WCHAR wszDfsRootShare[MAX_PATH];
|
|
|
|
mbstowcs( wszDfsRootShare, szArgs[0], strlen(szArgs[0]) + 1);
|
|
|
|
dwErr = SetupDfsRoot( wszDfsRootShare );
|
|
|
|
}
|
|
|
|
*szTextOut = szReturn;
|
|
|
|
return( TRUE );
|
|
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: DfsSetupGetConfig
|
|
//
|
|
// Synopsis: Reads the current configuration from the registry.
|
|
//
|
|
// Arguments: [pcfg] -- The DFS_CONFIGURATION info to fill
|
|
//
|
|
// Returns: TRUE if successfully read the config info, FALSE otherwise
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
BOOLEAN
|
|
DfsSetupGetConfig(
|
|
HWND hwnd,
|
|
DFS_CONFIGURATION *pcfg)
|
|
{
|
|
DWORD dwErr;
|
|
CRegKey cregVolumesDir( HKEY_LOCAL_MACHINE, &dwErr, VOLUMES_DIR );
|
|
ULONG cbBuffer;
|
|
WCHAR wszErr[128];
|
|
|
|
ZeroMemory( pcfg, sizeof(DFS_CONFIGURATION) );
|
|
|
|
if (dwErr == ERROR_ACCESS_DENIED) {
|
|
|
|
MessageBox(
|
|
hwnd,
|
|
L"Insufficient priviledge",
|
|
DFS_COMPONENT_NAME,
|
|
MB_OK | MB_ICONSTOP);
|
|
|
|
return( FALSE );
|
|
|
|
} else if (dwErr != ERROR_SUCCESS && dwErr != ERROR_FILE_NOT_FOUND) {
|
|
|
|
swprintf(wszErr, L"Unexpected error %08lx accessing registry", dwErr);
|
|
|
|
MessageBox( hwnd, wszErr, DFS_COMPONENT_NAME, MB_OK | MB_ICONSTOP);
|
|
|
|
return( FALSE );
|
|
|
|
}
|
|
|
|
if (dwErr == ERROR_SUCCESS) {
|
|
|
|
pcfg->fHostsDfs = TRUE;
|
|
|
|
CRegSZ cregRootShare( cregVolumesDir, ROOT_SHARE_VALUE_NAME );
|
|
|
|
dwErr = cregRootShare.QueryErrorStatus();
|
|
|
|
if (dwErr == ERROR_SUCCESS) {
|
|
|
|
cbBuffer = sizeof(pcfg->szRootShare);
|
|
|
|
dwErr = cregRootShare.GetString( pcfg->szRootShare, &cbBuffer );
|
|
|
|
}
|
|
|
|
if (dwErr == ERROR_SUCCESS) {
|
|
|
|
DWORD dwErrFTDfs;
|
|
|
|
CRegSZ cregFTDfs( cregVolumesDir, FTDFS_VALUE_NAME );
|
|
|
|
dwErrFTDfs = cregFTDfs.QueryErrorStatus();
|
|
|
|
if (dwErrFTDfs == ERROR_SUCCESS) {
|
|
|
|
pcfg->fFTDfs = TRUE;
|
|
|
|
cbBuffer = sizeof(pcfg->szFTDfs);
|
|
|
|
dwErr = cregFTDfs.GetString(pcfg->szFTDfs, &cbBuffer);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (dwErr != ERROR_SUCCESS) {
|
|
|
|
swprintf(wszErr, L"Error %08lx accessing registry", dwErr);
|
|
|
|
MessageBox( hwnd, wszErr, DFS_COMPONENT_NAME, MB_OK | MB_ICONSTOP);
|
|
|
|
return( FALSE );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return( TRUE );
|
|
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: DfsSetupConfigure
|
|
//
|
|
// Synopsis: Presents the dialog box for configuring the Dfs root.
|
|
//
|
|
// Arguments: [cArgs] -- Count of args
|
|
// [lpszArgs] -- Array of args
|
|
// [lpszTextOut] -- On return, points to a global buffer
|
|
// containing the name of the share selected by the
|
|
// user to serve as the root of the Dfs. If the user
|
|
// hits Cancel, or decides not to setup a Dfs root,
|
|
// this string is set to point to the NULL string.
|
|
//
|
|
// Returns: TRUE iff machine should be rebooted
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
LPSTR szCancel = "Cancel";
|
|
LPSTR szReboot = "Reboot";
|
|
|
|
BOOLEAN
|
|
DfsSetupConfigure(
|
|
DWORD cArgs,
|
|
LPSTR szArgs[],
|
|
LPSTR *szTextOut)
|
|
{
|
|
DWORD dwErr = 0;
|
|
HWND hwnd;
|
|
DFS_CONFIGURATION dfscfg, dfsNewCfg;
|
|
CHAR *pchUnused;
|
|
|
|
BOOLEAN fRtn=FALSE;
|
|
|
|
*szTextOut = szCancel; // Default return result
|
|
|
|
ASSERT( cArgs == 1 );
|
|
|
|
hwnd = (HWND) LongToHandle( strtoul( szArgs[0], &pchUnused, 16 ) );
|
|
|
|
//
|
|
// Read the current configuration
|
|
//
|
|
|
|
|
|
HCURSOR hCursor=LoadCursor(NULL,IDC_WAIT);
|
|
|
|
if (!DfsSetupGetConfig( hwnd, &dfscfg )) {
|
|
|
|
return fRtn;
|
|
|
|
}
|
|
|
|
//
|
|
// Next, pop up a dialog to allow the user to change the configuration
|
|
//
|
|
|
|
dfsNewCfg = dfscfg;
|
|
|
|
// Prompt the user for what flavour of Dfs to create
|
|
if (ConfigureDfs( hwnd, &dfsNewCfg ) == TRUE)
|
|
{
|
|
// Prompt the user for a local machine share
|
|
if (ConfigDfsShare(hwnd, &dfsNewCfg) == TRUE)
|
|
{
|
|
// Set the Hourglass
|
|
if (hCursor)
|
|
SetCursor(hCursor);
|
|
|
|
|
|
//
|
|
// User hit OK. Figure out what changed, if anything.
|
|
//
|
|
|
|
if (dfscfg.fHostsDfs == FALSE && dfsNewCfg.fHostsDfs == FALSE) {
|
|
|
|
//
|
|
// No change...
|
|
//
|
|
|
|
NOTHING;
|
|
|
|
} else if (dfscfg.fHostsDfs == FALSE && dfsNewCfg.fHostsDfs == TRUE) {
|
|
|
|
//
|
|
// We want to host a new Dfs, so call SetupDfsRoot or
|
|
// SetupFTDfsRoot depending on what kind of Dfs Host the user
|
|
// wants to setup
|
|
//
|
|
|
|
if (dfsNewCfg.fFTDfs) {
|
|
dwErr = SetupFTDfs( dfsNewCfg.szRootShare, dfsNewCfg.szFTDfs );
|
|
} else {
|
|
dwErr = SetupDfsRoot( dfsNewCfg.szRootShare );
|
|
}
|
|
|
|
*szTextOut = szReboot;
|
|
if (dwErr == 0) {
|
|
CRegKey RebootKey(HKEY_LOCAL_MACHINE, REBOOT_KEY, KEY_ALL_ACCESS,
|
|
NULL, REG_OPTION_VOLATILE);
|
|
dwErr = RebootKey.QueryErrorStatus();
|
|
if (dwErr) {
|
|
dprintf((DEB_ERROR,"DfsStopHosting could not add reboot key\n"));
|
|
}
|
|
else {
|
|
CRegDWORD rvReboot((const CRegKey &) RebootKey, REG_VALUE_REBOOT, 1);
|
|
dwErr = rvReboot.QueryErrorStatus();
|
|
}
|
|
}
|
|
|
|
} else if (dfscfg.fHostsDfs == TRUE && dfsNewCfg.fHostsDfs == FALSE) {
|
|
|
|
//
|
|
// We want to delete our Dfs root
|
|
//
|
|
|
|
if (MessageBox(
|
|
hwnd,
|
|
L"Are you sure you want to delete the Dfs\n"
|
|
L"rooted at this machine?",
|
|
DFS_COMPONENT_NAME,
|
|
MB_ICONQUESTION | MB_YESNO) == IDYES) {
|
|
|
|
dwErr = RemoveDfsRoot();
|
|
|
|
*szTextOut = dwErr == ERROR_SUCCESS ? szReboot : szCancel;
|
|
|
|
if (dwErr == 0) {
|
|
CRegKey RebootKey(HKEY_LOCAL_MACHINE, REBOOT_KEY, KEY_ALL_ACCESS,
|
|
NULL, REG_OPTION_VOLATILE);
|
|
dwErr = RebootKey.QueryErrorStatus();
|
|
if (dwErr) {
|
|
dprintf((DEB_ERROR,"DfsStopHosting could not add reboot key\n"));
|
|
}
|
|
else {
|
|
CRegDWORD rvReboot((const CRegKey &) RebootKey, REG_VALUE_REBOOT, 1);
|
|
dwErr = rvReboot.QueryErrorStatus();
|
|
}
|
|
}
|
|
}
|
|
|
|
} else if (dfscfg.fHostsDfs == TRUE && dfsNewCfg.fHostsDfs == TRUE) {
|
|
|
|
//
|
|
// User might have changed the root share, or simply changed
|
|
// status with respect to FTDfs
|
|
//
|
|
|
|
if ((_wcsicmp( dfscfg.szRootShare, dfsNewCfg.szRootShare )) != 0 ||
|
|
dfscfg.fFTDfs != dfsNewCfg.fFTDfs) {
|
|
|
|
dwErr = RemoveDfsRoot();
|
|
|
|
if (dwErr == ERROR_SUCCESS) {
|
|
|
|
if (dfsNewCfg.fFTDfs) {
|
|
|
|
dwErr = SetupFTDfs(
|
|
dfsNewCfg.szRootShare,
|
|
dfsNewCfg.szFTDfs);
|
|
|
|
} else {
|
|
|
|
dwErr = SetupDfsRoot( dfsNewCfg.szRootShare );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
*szTextOut = szReboot;
|
|
|
|
if (dwErr == 0) {
|
|
CRegKey RebootKey(HKEY_LOCAL_MACHINE, REBOOT_KEY, KEY_ALL_ACCESS,
|
|
NULL, REG_OPTION_VOLATILE);
|
|
dwErr = RebootKey.QueryErrorStatus();
|
|
if (dwErr) {
|
|
dprintf((DEB_ERROR,"DfsStopHosting could not add reboot key\n"));
|
|
}
|
|
else {
|
|
CRegDWORD rvReboot((const CRegKey &) RebootKey, REG_VALUE_REBOOT, 1);
|
|
dwErr = rvReboot.QueryErrorStatus();
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// Raid: 455295 Put in code to handle FTDfs name change
|
|
//
|
|
|
|
}
|
|
|
|
//
|
|
// Only request a reboot if everything has gone fine so far.
|
|
// MariusB and JonN 8/20/97
|
|
//
|
|
if (!dwErr)
|
|
fRtn=TRUE;
|
|
}
|
|
}
|
|
|
|
return fRtn;
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: Usage
|
|
//
|
|
// Synopsis: Prints out the usage message in case you want to build this
|
|
// as an .exe
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Returns:
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
VOID
|
|
Usage()
|
|
{
|
|
|
|
dprintf((DEB_ERROR,"Usage: dfssetup -root <path name> -share <root share>\n"));
|
|
dprintf((DEB_ERROR," <path name> is the name of an empty directory to use\n"));
|
|
dprintf((DEB_ERROR," as the root storage for Dfs\n"));
|
|
dprintf((DEB_ERROR," <root share> is the share name to access <path name>\n"));
|
|
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: InitializeVolumeObjectStorage
|
|
//
|
|
// Synopsis: Initializes the Dfs Manager Volume Object store.
|
|
//
|
|
// Arguments: None
|
|
//
|
|
// Returns: DWORD from registry operations.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
DWORD
|
|
InitializeVolumeObjectStorage()
|
|
{
|
|
DWORD dwErr;
|
|
CRegKey *pcregVolumeObjectStore = NULL;
|
|
|
|
pcregVolumeObjectStore = new CRegKey(HKEY_LOCAL_MACHINE, VOLUMES_DIR );
|
|
|
|
if (pcregVolumeObjectStore != NULL) {
|
|
|
|
dwErr = pcregVolumeObjectStore->QueryErrorStatus();
|
|
|
|
if ( dwErr == ERROR_SUCCESS ) {
|
|
|
|
dwErr = pcregVolumeObjectStore->Delete();
|
|
|
|
if (dwErr == ERROR_SUCCESS) {
|
|
|
|
delete pcregVolumeObjectStore;
|
|
|
|
pcregVolumeObjectStore = new CRegKey(
|
|
HKEY_LOCAL_MACHINE,
|
|
VOLUMES_DIR );
|
|
|
|
if (pcregVolumeObjectStore != NULL) {
|
|
|
|
dwErr = pcregVolumeObjectStore->QueryErrorStatus();
|
|
|
|
} else {
|
|
|
|
dwErr = ERROR_OUTOFMEMORY;
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
dwErr = ERROR_OUTOFMEMORY;
|
|
|
|
}
|
|
|
|
if (dwErr == ERROR_SUCCESS) {
|
|
|
|
dprintf((DEB_ERROR,"Successfully inited Dfs Manager Volume Storage...\n"));
|
|
|
|
}
|
|
|
|
if (pcregVolumeObjectStore != NULL) {
|
|
|
|
delete pcregVolumeObjectStore;
|
|
|
|
}
|
|
|
|
return(dwErr);
|
|
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: CreateVolumeObject
|
|
//
|
|
// Synopsis: Creates a volume object to bootstrap the Dfs namespace.
|
|
//
|
|
// Arguments: [pwszObjectName] -- The name of the volume object, relative
|
|
// to VOLUMES_DIR
|
|
// [pwszEntryPath] -- EntryPath of the volume.
|
|
// [pwszServer] -- Name of server used to access this Dfs volume
|
|
// [pwszShare] -- Name of share used to access this Dfs volume
|
|
// [pwszComment] -- Comment to stamp on the volume object.
|
|
// [guidVolume] -- ID of newly create dfs volume
|
|
//
|
|
// Returns:
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
DWORD
|
|
CreateVolumeObject(
|
|
LPWSTR wszObjectName,
|
|
LPWSTR pwszEntryPath,
|
|
LPWSTR pwszServer,
|
|
LPWSTR pwszShare,
|
|
LPWSTR pwszComment,
|
|
GUID *guidVolume)
|
|
{
|
|
DWORD dwErr;
|
|
WCHAR wszFullObject[ MAX_PATH ];
|
|
|
|
//
|
|
// First, compute the full object name, storage ids, and machine name.
|
|
//
|
|
|
|
wcscpy( wszFullObject, VOLUMES_DIR );
|
|
wcscat( wszFullObject, wszObjectName );
|
|
|
|
//
|
|
// Next, get a guid for this volume
|
|
//
|
|
|
|
UuidCreate( guidVolume );
|
|
|
|
//
|
|
// Lastly, create this volume object
|
|
//
|
|
|
|
dwErr = DfsManagerCreateVolumeObject(
|
|
wszFullObject,
|
|
pwszEntryPath,
|
|
pwszServer,
|
|
pwszShare,
|
|
pwszComment,
|
|
guidVolume);
|
|
|
|
if (dwErr == ERROR_SUCCESS) {
|
|
|
|
dprintf((DEB_ERROR,"Successfully inited Dfs Manager Volume [%ws]...\n", pwszEntryPath));
|
|
|
|
}
|
|
|
|
return(dwErr);
|
|
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: CreateFTRootVolumeInfo
|
|
//
|
|
// Synopsis: Creates a Dfs volume object - used to bootstrap a Dfs by
|
|
// creating a root volume object
|
|
//
|
|
// Arguments: [wszObjectName] -- Name of volume object
|
|
// [wszFTDfsConfigDN] -- The DN of the FTDfs config object in DS
|
|
// [wszDomainName] -- Name of FTDfs domain
|
|
// [wszDfsName] -- Name of Dfs
|
|
// [wszServerName] -- Name of root server
|
|
// [wszShareName] -- Name of root share
|
|
// [wszDCName] -- DC to use
|
|
// [fNewFTDfs] -- If true, this is a new FTDfs
|
|
//
|
|
// Returns:
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
DWORD
|
|
CreateFTRootVolumeInfo(
|
|
LPWSTR wszObjectName,
|
|
LPWSTR wszFTDfsConfigDN,
|
|
LPWSTR wszDomainName,
|
|
LPWSTR wszDfsName,
|
|
LPWSTR wszServerName,
|
|
LPWSTR wszShareName,
|
|
LPWSTR wszSharePath,
|
|
LPWSTR wszDCName,
|
|
BOOLEAN fNewFTDfs)
|
|
{
|
|
DWORD dwErr = ERROR_SUCCESS;
|
|
WCHAR wszFullObjectName[ MAX_PATH ];
|
|
WCHAR wszDfsPrefix[ MAX_PATH ];
|
|
GUID idVolume;
|
|
static BOOLEAN fInited = FALSE;
|
|
|
|
wcscpy( wszDfsPrefix, UNICODE_PATH_SEP_STR );
|
|
wcscat( wszDfsPrefix, wszDomainName );
|
|
wcscat( wszDfsPrefix, UNICODE_PATH_SEP_STR );
|
|
wcscat( wszDfsPrefix, wszDfsName );
|
|
|
|
wcscpy( wszFullObjectName, LDAP_VOLUMES_DIR );
|
|
wcscat( wszFullObjectName, wszObjectName );
|
|
|
|
if (!fInited) {
|
|
|
|
//
|
|
// Create the volumes dir key that indicates that this machine is to
|
|
// be a root of an FTDfs
|
|
//
|
|
|
|
CRegKey cregVolumesDir( HKEY_LOCAL_MACHINE, VOLUMES_DIR );
|
|
|
|
dwErr = cregVolumesDir.QueryErrorStatus();
|
|
|
|
if (dwErr == ERROR_SUCCESS) {
|
|
|
|
CRegSZ cregRootShare(
|
|
cregVolumesDir,
|
|
ROOT_SHARE_VALUE_NAME,
|
|
wszShareName );
|
|
|
|
dwErr = cregRootShare.QueryErrorStatus();
|
|
|
|
if (dwErr == ERROR_SUCCESS) {
|
|
|
|
CRegSZ cregFTDfs(
|
|
cregVolumesDir,
|
|
FTDFS_VALUE_NAME,
|
|
wszDfsName);
|
|
|
|
CRegSZ cregFTDfsConfigDN(
|
|
cregVolumesDir,
|
|
FTDFS_DN_VALUE_NAME,
|
|
wszFTDfsConfigDN);
|
|
|
|
dwErr = cregFTDfs.QueryErrorStatus();
|
|
|
|
if (dwErr == ERROR_SUCCESS) {
|
|
|
|
dwErr = cregFTDfsConfigDN.QueryErrorStatus();
|
|
|
|
if (dwErr != ERROR_SUCCESS)
|
|
cregFTDfs.Delete();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (dwErr == ERROR_SUCCESS) {
|
|
|
|
dwErr = DfsInitGlobals(
|
|
wszDfsName,
|
|
DFS_MANAGER_FTDFS);
|
|
|
|
}
|
|
|
|
if (dwErr == ERROR_SUCCESS)
|
|
fInited = TRUE;
|
|
|
|
}
|
|
|
|
DfsManagerSetDcName(wszDCName);
|
|
|
|
if (dwErr == ERROR_SUCCESS) {
|
|
|
|
if (fNewFTDfs) {
|
|
|
|
//
|
|
// Generate a Guid for the new Volume
|
|
//
|
|
|
|
UuidCreate( &idVolume );
|
|
|
|
dwErr = DfsManagerCreateVolumeObject(
|
|
wszFullObjectName,
|
|
wszDfsPrefix,
|
|
wszServerName,
|
|
wszShareName,
|
|
L"Root Volume",
|
|
&idVolume);
|
|
|
|
} else {
|
|
|
|
dwErr = DfsManagerAddService(
|
|
wszFullObjectName,
|
|
wszServerName,
|
|
wszShareName,
|
|
&idVolume);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (dwErr == ERROR_SUCCESS) {
|
|
|
|
dwErr = StoreLvolInfo(
|
|
&idVolume,
|
|
wszSharePath,
|
|
wszShareName,
|
|
wszDfsPrefix,
|
|
DFS_VOL_TYPE_DFS | DFS_VOL_TYPE_REFERRAL_SVC);
|
|
|
|
}
|
|
|
|
return( dwErr );
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: StoreLvolInfo
|
|
//
|
|
// Synopsis: Stores information about a local volume in the registry.
|
|
//
|
|
// Arguments: [pVolumeID] -- Id of dfs volume
|
|
// [pwszStorageId] -- Storage used by dfs volume
|
|
// [pwszShareName] -- LM Share used to access dfs volume
|
|
// [pwszEntryPath] -- EntryPath of dfs volume
|
|
// [ulVolumeType] -- Type of dfs volume. See DFS_VOL_TYPE_xxx
|
|
//
|
|
// Returns: DWORD from registry operations.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
extern VOID
|
|
GuidToString(
|
|
IN GUID *pID,
|
|
OUT PWSTR pwszID);
|
|
|
|
DWORD
|
|
StoreLvolInfo(
|
|
IN GUID *pVolumeID,
|
|
IN PWSTR pwszStorageID,
|
|
IN PWSTR pwszShareName,
|
|
IN PWSTR pwszEntryPath,
|
|
IN ULONG ulVolumeType)
|
|
{
|
|
DWORD dwErr;
|
|
WCHAR wszLvolKey[_MAX_PATH];
|
|
UNICODE_STRING ustrNtStorageId;
|
|
PWCHAR pwcGuid;
|
|
|
|
wcscpy(wszLvolKey, REG_KEY_LOCAL_VOLUMES);
|
|
wcscat(wszLvolKey, UNICODE_PATH_SEP_STR);
|
|
pwcGuid = wszLvolKey + wcslen(wszLvolKey);
|
|
ASSERT( *pwcGuid == UNICODE_NULL );
|
|
|
|
GuidToString( pVolumeID, pwcGuid );
|
|
|
|
if (!RtlDosPathNameToNtPathName_U(
|
|
pwszStorageID,
|
|
&ustrNtStorageId,
|
|
NULL,
|
|
NULL)) {
|
|
|
|
return(ERROR_OUTOFMEMORY);
|
|
|
|
} else {
|
|
|
|
ustrNtStorageId.Buffer[ustrNtStorageId.Length/sizeof(WCHAR)] = UNICODE_NULL;
|
|
|
|
}
|
|
|
|
CRegKey rkeyLvol(HKEY_LOCAL_MACHINE, wszLvolKey, KEY_WRITE, NULL, REG_OPTION_NON_VOLATILE);
|
|
|
|
dwErr = rkeyLvol.QueryErrorStatus();
|
|
|
|
if (dwErr != ERROR_SUCCESS) {
|
|
RtlFreeUnicodeString(&ustrNtStorageId);
|
|
return(dwErr);
|
|
}
|
|
|
|
CRegSZ rvEntryPath((const CRegKey &) rkeyLvol, REG_VALUE_ENTRY_PATH, pwszEntryPath);
|
|
|
|
CRegSZ rvShortEntryPath((const CRegKey &) rkeyLvol, REG_VALUE_SHORT_PATH, pwszEntryPath);
|
|
|
|
CRegDWORD rvEntryType((const CRegKey &) rkeyLvol, REG_VALUE_ENTRY_TYPE, ulVolumeType);
|
|
|
|
CRegSZ rvStorageId((const CRegKey &) rkeyLvol, REG_VALUE_STORAGE_ID, ustrNtStorageId.Buffer);
|
|
|
|
CRegSZ rvShareName((const CRegKey &) rkeyLvol, REG_VALUE_SHARE_NAME, pwszShareName);
|
|
|
|
RtlFreeUnicodeString(&ustrNtStorageId);
|
|
|
|
if (ERROR_SUCCESS != (dwErr = rvEntryPath.QueryErrorStatus()) ||
|
|
ERROR_SUCCESS != (dwErr = rvShortEntryPath.QueryErrorStatus()) ||
|
|
ERROR_SUCCESS != (dwErr = rvEntryType.QueryErrorStatus()) ||
|
|
ERROR_SUCCESS != (dwErr = rvStorageId.QueryErrorStatus()) ||
|
|
ERROR_SUCCESS != (dwErr = rvShareName.QueryErrorStatus())) {
|
|
|
|
rkeyLvol.Delete();
|
|
} else {
|
|
|
|
dprintf((DEB_ERROR,"Successfully stored local volume info for [%ws]\n", pwszEntryPath));
|
|
}
|
|
|
|
return(dwErr);
|
|
|
|
}
|
|
|
|
|
|
//+------------------------------------------------------------------
|
|
//
|
|
// Function: CheckForOldDfsService
|
|
//
|
|
// Synopsis:
|
|
//
|
|
// Effects: -none-
|
|
//
|
|
// Arguments: -none-
|
|
//
|
|
// Returns: TRUE if the old (pre -ds build) dfs service is installed
|
|
//
|
|
//
|
|
// History: 10-09-96 JimMcN Created
|
|
//
|
|
// Notes:
|
|
//
|
|
//
|
|
//-------------------------------------------------------------------
|
|
|
|
|
|
BOOLEAN DfsCheckForOldDfsService( )
|
|
{
|
|
DWORD dwErr = 0;
|
|
DWORD DfsVersion;
|
|
|
|
// Open Service Controller
|
|
CService cSvc;
|
|
|
|
if (!(dwErr = cSvc.Init()))
|
|
{
|
|
|
|
dwErr = cSvc._OpenService(L"Dfs", SERVICE_QUERY_STATUS);
|
|
cSvc._CloseService();
|
|
|
|
if (dwErr != 0) {
|
|
return(FALSE);
|
|
}
|
|
|
|
CRegKey cregDfsService( HKEY_LOCAL_MACHINE,
|
|
&dwErr,
|
|
L"System\\CurrentControlSet\\Services\\Dfs"
|
|
);
|
|
|
|
if (dwErr == ERROR_SUCCESS) {
|
|
CRegDWORD DfsNewService((const CRegKey &)cregDfsService,
|
|
L"DfsVersion", &DfsVersion);
|
|
|
|
dwErr = DfsNewService.QueryErrorStatus();
|
|
|
|
if (dwErr != 0) {
|
|
dprintf((DEB_ERROR,"CheckForOldDfsService Failed Newserv\n"));
|
|
return(TRUE);
|
|
}
|
|
|
|
if (DfsVersion < DFS_VERSION_NUMBER) {
|
|
return(TRUE);
|
|
}
|
|
|
|
return(FALSE);
|
|
|
|
}
|
|
|
|
return(FALSE);
|
|
}
|
|
return FALSE ;
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: GetDomainAndComputerName
|
|
//
|
|
// Synopsis: Retrieves the domain and computer name of the local machine
|
|
//
|
|
// Arguments: [wszDomain] -- On successful return, contains name of domain.
|
|
// If this parameter is NULL on entry, the domain name is
|
|
// not returned.
|
|
//
|
|
// [wszComputer] -- On successful return, contains name of
|
|
// computer. If this parameter is NULL on entry, the
|
|
// computer name is not returned.
|
|
//
|
|
// Returns: [ERROR_SUCCESS] -- Successfully returning names.
|
|
//
|
|
// Win32 Error from calling NetWkstaGetInfo
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
DWORD
|
|
GetDomainAndComputerName(
|
|
OUT LPWSTR wszDomain OPTIONAL,
|
|
OUT LPWSTR wszComputer OPTIONAL)
|
|
{
|
|
|
|
DWORD dwErr;
|
|
PWKSTA_INFO_100 wkstaInfo = NULL;
|
|
|
|
dwErr = NetWkstaGetInfo( NULL, 100, (LPBYTE *) &wkstaInfo );
|
|
|
|
if (dwErr == NERR_Success) {
|
|
|
|
if (wszDomain)
|
|
wcscpy(wszDomain, wkstaInfo->wki100_langroup);
|
|
|
|
if (wszComputer)
|
|
wcscpy(wszComputer, wkstaInfo->wki100_computername);
|
|
|
|
NetApiBufferFree( wkstaInfo );
|
|
|
|
}
|
|
|
|
return( dwErr );
|
|
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: GetSharePath
|
|
//
|
|
// Synopsis: Returns the share path for a share on the local machine
|
|
//
|
|
// Arguments: [wszShare] -- Name of share
|
|
//
|
|
// [wszPath] -- On return, share path of wszShare
|
|
//
|
|
// Returns: [ERROR_SUCCESS] -- Successfully returning share path
|
|
//
|
|
// Win32 error from NetShareGetInfo
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
DWORD
|
|
GetSharePath(
|
|
IN LPWSTR wszShare,
|
|
OUT LPWSTR wszPath)
|
|
{
|
|
DWORD dwErr;
|
|
PSHARE_INFO_2 pshi2;
|
|
|
|
dwErr = NetShareGetInfo(
|
|
NULL, // Server (local machine)
|
|
wszShare, // Share Name
|
|
2, // Level,
|
|
(LPBYTE *) &pshi2); // Buffer
|
|
|
|
if (dwErr == ERROR_SUCCESS) {
|
|
|
|
wcscpy( wszPath, pshi2->shi2_path );
|
|
|
|
NetApiBufferFree( pshi2 );
|
|
}
|
|
|
|
return( dwErr );
|
|
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: DfsIsServiceRunning
|
|
//
|
|
// Synopsis: Check for active dfs servvice..
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Returns: [TRUE] -- if dfs service is active.
|
|
// FALSE otherwise.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
BOOLEAN
|
|
DfsIsDfsServiceRunning()
|
|
|
|
{
|
|
DWORD dwErr;
|
|
CService cSvc;
|
|
|
|
if (!(dwErr = cSvc.Init()))
|
|
{
|
|
dwErr = cSvc._OpenService(L"Dfs", SERVICE_QUERY_STATUS);
|
|
cSvc._CloseService();
|
|
return(dwErr == 0);
|
|
|
|
}
|
|
return(FALSE);
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: DfsGetDfsName
|
|
//
|
|
// Synopsis: Returns the share for a local dfs
|
|
//
|
|
// Arguments: [DfsRootShare] -- Name of share
|
|
//
|
|
// Returns: [TRUE] -- Successfully returning share path
|
|
//
|
|
// FALSE otherwise.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
BOOLEAN
|
|
DfsGetDfsName(
|
|
OUT LPWSTR DfsRootShare,
|
|
IN OUT ULONG *Length,
|
|
OUT BOOLEAN *IsFtDfs)
|
|
|
|
{
|
|
DWORD dwErr;
|
|
ULONG SaveLength = *Length;
|
|
// CService cSvc;
|
|
ULONG ul = MAX_PATH;
|
|
|
|
WCHAR wc[MAX_PATH];
|
|
|
|
*IsFtDfs = FALSE;
|
|
|
|
#if 0
|
|
if (!(dwErr = cSvc.Init()))
|
|
{
|
|
|
|
dwErr = cSvc._OpenService(L"Dfs", SERVICE_QUERY_STATUS);
|
|
cSvc._CloseService();
|
|
|
|
if (dwErr != 0) {
|
|
return(FALSE);
|
|
}
|
|
|
|
}
|
|
#endif
|
|
|
|
CRegKey VolKey(HKEY_LOCAL_MACHINE, &dwErr, VOLUMES_DIR, KEY_READ);
|
|
|
|
if (dwErr) {
|
|
dprintf((DEB_ERROR,"DfsGetDfsName Failed to open VOLUMES_DIR\n"));
|
|
return(FALSE);
|
|
}
|
|
|
|
CRegSZ RootShare((const CRegKey &)VolKey, ROOT_SHARE_VALUE_NAME);
|
|
|
|
dwErr = RootShare.QueryErrorStatus();
|
|
|
|
if (dwErr) {
|
|
dprintf((DEB_ERROR,"DfsGetDfsName Failed to get root share name\n"));
|
|
return(FALSE);
|
|
}
|
|
|
|
dwErr = RootShare.GetString(DfsRootShare, Length);
|
|
|
|
if (dwErr) {
|
|
dprintf((DEB_ERROR,"DfsGetDfsName Failed to get root share val\n"));
|
|
return(FALSE);
|
|
}
|
|
|
|
CRegSZ FtDfs((const CRegKey &)VolKey, FTDFS_VALUE_NAME);
|
|
|
|
|
|
dwErr = FtDfs.QueryErrorStatus();
|
|
|
|
dwErr = FtDfs.GetString(wc, &ul);
|
|
*IsFtDfs = (dwErr == 0);
|
|
if (*IsFtDfs) {
|
|
memset(DfsRootShare, 0, SaveLength);
|
|
memcpy(DfsRootShare, wc, ul);
|
|
*Length=ul; }
|
|
dprintf((DEB_ERROR,"DfsGetDfsName is %s FTDFS\n", *IsFtDfs?"":"NOT"));
|
|
return(TRUE);
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: DfsNeedReboot
|
|
//
|
|
// Synopsis: Returns true if reboot is required for completing configuration.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Returns: [TRUE] -- Reboot Needed.
|
|
//
|
|
// FALSE otherwise.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
BOOLEAN
|
|
DfsNeedReboot()
|
|
{
|
|
|
|
DWORD dwErr;
|
|
DWORD RebootDW = 20;
|
|
WCHAR buffer[20];
|
|
CRegKey RebootKey(HKEY_LOCAL_MACHINE, &dwErr, REBOOT_KEY, KEY_READ);
|
|
|
|
if (dwErr = RebootKey.QueryErrorStatus()) {
|
|
return(FALSE);
|
|
}
|
|
|
|
CRegSZ RebootVal((const CRegKey &)RebootKey, REG_VALUE_REBOOT);
|
|
|
|
dwErr = RebootVal.QueryErrorStatus();
|
|
DWORD GetString( LPWSTR pwszData, ULONG *pcbData);
|
|
|
|
dwErr = RebootVal.GetString(buffer, &RebootDW);
|
|
dprintf((DEB_ERROR,"DfsNeedReboot is %s Needed\n", dwErr == 0?"":"NOT"));
|
|
|
|
return(dwErr == 0);
|
|
|
|
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: DfsStopHostingDfs
|
|
//
|
|
// Synopsis: Remove this machine from a machine/ft dfs.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Returns: ERROR_SUCCESS if no error
|
|
//
|
|
// setup error otherwise.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
DWORD
|
|
DfsStopHostingDfs()
|
|
{
|
|
DWORD dwErr = 0;
|
|
BOOLEAN ftDfs = FALSE;
|
|
ULONG ul = MAX_PATH;
|
|
|
|
WCHAR FtDfsName[MAX_PATH];
|
|
WCHAR DfsRootShare[MAX_PATH];
|
|
WCHAR wszFullObjectName[MAX_PATH];
|
|
WCHAR wszDomainName[MAX_PATH];
|
|
WCHAR wszComputerName[MAX_PATH];
|
|
|
|
if (DfsGetDfsName(FtDfsName, &ul, &ftDfs)) {
|
|
if (ftDfs) {
|
|
|
|
wcscpy( wszFullObjectName, LDAP_VOLUMES_DIR );
|
|
wcscat( wszFullObjectName, DOMAIN_ROOT_VOL );
|
|
|
|
dwErr = DfsInitGlobals(
|
|
FtDfsName,
|
|
DFS_MANAGER_FTDFS);
|
|
|
|
if (dwErr) {
|
|
dprintf((DEB_ERROR,"DfsStopHostingDfs init globals fail.\n"));
|
|
return(dwErr);
|
|
}
|
|
|
|
CRegKey VolKey(HKEY_LOCAL_MACHINE, &dwErr, VOLUMES_DIR, KEY_READ);
|
|
|
|
if (dwErr) {
|
|
dprintf((DEB_ERROR,"DfsGetDfsName Failed to open VOLUMES_DIR\n"));
|
|
return(dwErr);
|
|
}
|
|
|
|
CRegSZ RootShare((const CRegKey &)VolKey, ROOT_SHARE_VALUE_NAME);
|
|
|
|
dwErr = RootShare.QueryErrorStatus();
|
|
|
|
if (dwErr) {
|
|
dprintf((DEB_ERROR,"DfsGetDfsName Failed to get root share name\n"));
|
|
return(dwErr);
|
|
}
|
|
|
|
ul = MAX_PATH;
|
|
dwErr = RootShare.GetString(DfsRootShare, &ul);
|
|
|
|
if (dwErr) {
|
|
dprintf((DEB_ERROR,"DfsGetDfsName Failed to get root share val\n"));
|
|
return(dwErr);
|
|
}
|
|
|
|
dwErr = GetDomainAndComputerName( wszDomainName, wszComputerName );
|
|
if (dwErr) {
|
|
dprintf((DEB_ERROR,"DfsGetDfsName Failed computer name\n"));
|
|
return(dwErr);
|
|
}
|
|
|
|
dwErr = DfsManagerRemoveService(wszFullObjectName, wszComputerName);
|
|
if (dwErr && dwErr != NERR_DfsCantRemoveLastServerShare) {
|
|
return(dwErr);
|
|
}
|
|
dwErr = TeardownFtDfs(DfsRootShare, FtDfsName);
|
|
}
|
|
if (dwErr)
|
|
return(dwErr);
|
|
|
|
dwErr = RemoveDfsRoot();
|
|
|
|
}
|
|
|
|
if (dwErr == 0) {
|
|
CRegKey RebootKey(HKEY_LOCAL_MACHINE, REBOOT_KEY, KEY_ALL_ACCESS, NULL, REG_OPTION_VOLATILE);
|
|
dwErr = RebootKey.QueryErrorStatus();
|
|
if (dwErr) {
|
|
dprintf((DEB_ERROR,"DfsStopHosting could not add reboot key\n"));
|
|
}
|
|
else {
|
|
CRegDWORD rvReboot((const CRegKey &) RebootKey, REG_VALUE_REBOOT, 1);
|
|
dwErr = rvReboot.QueryErrorStatus();
|
|
}
|
|
}
|
|
else {
|
|
dprintf((DEB_ERROR,"DfsStopHosting Dfs Failed to remove dfs root\n"));
|
|
}
|
|
|
|
return(dwErr);
|
|
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: TeardownFtDfs
|
|
//
|
|
// Synopsis: Removes FtDfs information from the ds.
|
|
//
|
|
// Arguments: wszRootShare the share hosting the dfs.
|
|
// wszFTDfsName the name of the FtDfs to remove from the ds.
|
|
//
|
|
//
|
|
// Returns: Nothing
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
DWORD
|
|
TeardownFtDfs(
|
|
IN LPWSTR wszRootShare,
|
|
IN LPWSTR wszFTDfsName)
|
|
{
|
|
DWORD dwErr = ERROR_SUCCESS;
|
|
|
|
DWORD i, j;
|
|
WCHAR wszDomainName[MAX_PATH];
|
|
WCHAR wszComputerName[MAX_PATH];
|
|
WCHAR wszRootSharePath[MAX_PATH];
|
|
WCHAR wszConfigurationDN[ MAX_PATH ];
|
|
WCHAR wszDfsConfigDN[ MAX_PATH ];
|
|
WCHAR wszServerShare[MAX_PATH];
|
|
|
|
|
|
PDOMAIN_CONTROLLER_INFO pDCInfo = 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;
|
|
|
|
//
|
|
// We need some information before we start:
|
|
//
|
|
// 1. Our Domain name
|
|
//
|
|
// 2. Our Computer name
|
|
//
|
|
// 3. The share path of wszRootShare
|
|
//
|
|
// 4. The DN of the Configuration OU of our domain
|
|
//
|
|
|
|
dwErr = GetDomainAndComputerName( wszDomainName, wszComputerName );
|
|
|
|
if (dwErr != ERROR_SUCCESS) {
|
|
|
|
dprintf((
|
|
DEB_ERROR,
|
|
"Win32 Error %d getting Domain/Computer name\n", dwErr));
|
|
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
dwErr = GetSharePath( wszRootShare, wszRootSharePath );
|
|
|
|
if (dwErr != ERROR_SUCCESS) {
|
|
|
|
dprintf((
|
|
DEB_ERROR,
|
|
"Win32 Error %d getting share path for %ws\n",
|
|
dwErr, wszRootShare));
|
|
|
|
goto Cleanup;
|
|
}
|
|
|
|
dwErr = DsGetDcName(
|
|
NULL, // Computer to remote to
|
|
NULL, // Domain - use our own
|
|
NULL, // Domain Guid
|
|
NULL, // Site Guid
|
|
DS_DIRECTORY_SERVICE_REQUIRED | // Flags
|
|
DS_PDC_REQUIRED,
|
|
&pDCInfo); // Return info
|
|
|
|
if (dwErr != ERROR_SUCCESS) {
|
|
|
|
dprintf((
|
|
DEB_ERROR,
|
|
"DsGetDcName failed with Win32 Error %d\n", dwErr));
|
|
|
|
goto Cleanup;
|
|
}
|
|
|
|
pldap = ldap_initW(&pDCInfo->DomainControllerAddress[2], LDAP_PORT);
|
|
|
|
if (pldap == NULL) {
|
|
|
|
dprintf((DEB_ERROR, "ldap_init failed\n"));
|
|
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
dwErr = ldap_set_option(pldap, LDAP_OPT_AREC_EXCLUSIVE, LDAP_OPT_ON);
|
|
if (dwErr != LDAP_SUCCESS) {
|
|
|
|
dprintf((
|
|
DEB_ERROR,
|
|
"ldap_set_option failed with ldap error %d\n", dwErr));
|
|
|
|
pldap = NULL;
|
|
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
dwErr = ldap_bind_s(pldap, NULL, NULL, LDAP_AUTH_SSPI);
|
|
|
|
if (dwErr != LDAP_SUCCESS) {
|
|
|
|
dprintf((
|
|
DEB_ERROR,
|
|
"ldap_bind_s failed with ldap error %d\n", dwErr));
|
|
|
|
pldap = NULL;
|
|
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
rgAttrs[0] = L"defaultnamingContext";
|
|
rgAttrs[1] = NULL;
|
|
|
|
dwErr = ldap_search_sW(
|
|
pldap,
|
|
L"",
|
|
LDAP_SCOPE_BASE,
|
|
L"(objectClass=*)",
|
|
rgAttrs,
|
|
0,
|
|
&pMsg);
|
|
|
|
if (dwErr == LDAP_SUCCESS) {
|
|
|
|
PLDAPMessage pEntry = NULL;
|
|
PWCHAR *rgszNamingContexts = NULL;
|
|
DWORD i, cNamingContexts;
|
|
BOOLEAN fFoundCfg;
|
|
|
|
if ((pEntry = ldap_first_entry(pldap, pMsg)) != NULL &&
|
|
(rgszNamingContexts = ldap_get_valuesW(pldap, pEntry, rgAttrs[0])) != NULL &&
|
|
(cNamingContexts = ldap_count_valuesW(rgszNamingContexts)) > 0) {
|
|
|
|
wcscpy( wszConfigurationDN, *rgszNamingContexts );
|
|
fFoundCfg = TRUE;
|
|
|
|
if (!fFoundCfg) {
|
|
|
|
dwErr = ERROR_UNEXP_NET_ERR;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
dwErr = ERROR_UNEXP_NET_ERR;
|
|
|
|
}
|
|
|
|
if (rgszNamingContexts != NULL)
|
|
ldap_value_freeW( rgszNamingContexts );
|
|
|
|
ldap_msgfree( pMsg );
|
|
}
|
|
|
|
if (dwErr != ERROR_SUCCESS) {
|
|
|
|
dprintf((DEB_ERROR, "TD:Unable to find Configuration naming context\n"));
|
|
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
//
|
|
// Great, we have all the parameters now, so configure the DS
|
|
//
|
|
|
|
//
|
|
// See if the DfsConfiguration object exists; if not, create it.
|
|
//
|
|
|
|
wsprintf(
|
|
wszDfsConfigDN,
|
|
L"CN=Dfs-Configuration,CN=System,%ws",
|
|
wszConfigurationDN);
|
|
|
|
rgAttrs[0] = L"cn";
|
|
rgAttrs[1] = NULL;
|
|
|
|
dwErr = ldap_search_sW(
|
|
pldap,
|
|
wszDfsConfigDN,
|
|
LDAP_SCOPE_BASE,
|
|
L"(objectClass=*)",
|
|
rgAttrs,
|
|
0,
|
|
&pMsg);
|
|
|
|
if (dwErr == LDAP_SUCCESS)
|
|
ldap_msgfree( pMsg );
|
|
|
|
if (dwErr != LDAP_SUCCESS) {
|
|
|
|
dprintf((
|
|
DEB_ERROR,
|
|
"3: ldap_search_sW for %ws failed with LDAP error %d\n",
|
|
wszDfsConfigDN, dwErr ));
|
|
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
//
|
|
// Check to see if we are joining an FTDfs or creating a new one.
|
|
//
|
|
|
|
wsprintf(
|
|
wszDfsConfigDN,
|
|
L"CN=%ws,CN=Dfs-Configuration,CN=System,%ws",
|
|
wszFTDfsName,
|
|
wszConfigurationDN);
|
|
|
|
wsprintf(
|
|
wszServerShare,
|
|
L"\\\\%ws\\%ws",
|
|
wszComputerName,
|
|
wszRootShare);
|
|
|
|
rgAttrs[0] = L"remoteServerName";
|
|
rgAttrs[1] = NULL;
|
|
|
|
dwErr = ldap_search_sW(
|
|
pldap,
|
|
wszDfsConfigDN,
|
|
LDAP_SCOPE_BASE,
|
|
L"(objectClass=*)",
|
|
rgAttrs,
|
|
0,
|
|
&pMsg);
|
|
|
|
if (dwErr == ERROR_SUCCESS) {
|
|
|
|
//
|
|
// We found a Dfs object to modify/delete
|
|
//
|
|
|
|
LDAPMessage *pmsgServers;
|
|
PWCHAR *rgServers, *rgNewServers;
|
|
DWORD cServers;
|
|
|
|
fNewFTDfs = FALSE;
|
|
|
|
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 );
|
|
|
|
rgNewServers = new LPWSTR [ cServers + 1 ];
|
|
|
|
if (rgNewServers != NULL) {
|
|
for (i = j = 0; i < cServers; i += 1) {
|
|
if (wcscmp(wszServerShare, rgServers[i]) == 0) {
|
|
continue;
|
|
}
|
|
rgNewServers[j++] = rgServers[i];
|
|
}
|
|
rgNewServers[j] = NULL;
|
|
if (j) {
|
|
ldapModServer.mod_op = LDAP_MOD_REPLACE;
|
|
ldapModServer.mod_type = L"remoteServerName";
|
|
ldapModServer.mod_vals.modv_strvals = rgNewServers;
|
|
|
|
rgldapMods[0] = &ldapModServer;
|
|
rgldapMods[1] = NULL;
|
|
|
|
dwErr = ldap_modify_sW(pldap, wszDfsConfigDN, rgldapMods);
|
|
} else {
|
|
|
|
//
|
|
// Delete the Dfs metadata object.
|
|
//
|
|
|
|
dwErr = ldap_delete_sW( pldap, wszDfsConfigDN);
|
|
|
|
}
|
|
|
|
delete [] rgNewServers;
|
|
|
|
} else {
|
|
|
|
dwErr = ERROR_OUTOFMEMORY;
|
|
}
|
|
|
|
ldap_value_freeW( rgServers );
|
|
|
|
} else {
|
|
|
|
dwErr = ERROR_OUTOFMEMORY;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
dwErr = ERROR_OUTOFMEMORY;
|
|
|
|
}
|
|
|
|
ldap_msgfree( pMsg );
|
|
}
|
|
if (dwErr != LDAP_SUCCESS) {
|
|
|
|
dprintf((
|
|
DEB_ERROR,
|
|
"4: ldap_modify_s/ldap_delete_s failed for %ws with ldap error %d\n",
|
|
wszDfsConfigDN, dwErr));
|
|
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
Cleanup:
|
|
|
|
if (pDCInfo != NULL)
|
|
NetApiBufferFree( pDCInfo );
|
|
|
|
if (pldap != NULL)
|
|
ldap_unbind( pldap );
|
|
|
|
return( dwErr );
|
|
|
|
}
|