5394 lines
134 KiB
C++
5394 lines
134 KiB
C++
//+----------------------------------------------------------------------------
|
||
//
|
||
// Copyright (C) 1995, Microsoft Corporation
|
||
//
|
||
// File: dfsmsrv.cxx
|
||
//
|
||
// Contents: The server side stubs for the Dfs Manager Admin RPC interface
|
||
//
|
||
// Classes:
|
||
//
|
||
// Functions: GetDfsVolumeFromPath --
|
||
// AddReplica --
|
||
// RemoveReplica --
|
||
// Delete --
|
||
// SetComment --
|
||
// GetInfo --
|
||
// Move --
|
||
// Rename --
|
||
// CreateChild --
|
||
// GetReplicaSetID --
|
||
// SetReplicaSetID --
|
||
// ChangeStorageID --
|
||
// SetReplicaState --
|
||
// SetVolumeState --
|
||
//
|
||
// History: 12-27-95 Milans Created.
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
|
||
//#include <ntos.h>
|
||
//#include <ntrtl.h>
|
||
//#include <nturtl.h>
|
||
//#include <dfsfsctl.h>
|
||
//#include <windows.h>
|
||
|
||
|
||
#include <headers.hxx>
|
||
#pragma hdrstop
|
||
|
||
extern "C" {
|
||
#include "dfspriv.h" // For I_NetDfsXXX calls
|
||
#include <dfsmsrv.h>
|
||
#include <srvfsctl.h>
|
||
#include <icanon.h>
|
||
#include <validc.h>
|
||
#include <winldap.h>
|
||
#include <dsrole.h>
|
||
}
|
||
|
||
extern "C" {
|
||
|
||
DWORD
|
||
DfsGetFtServersFromDs(
|
||
IN PVOID pLDAP OPTIONAL,
|
||
IN LPWSTR wszDomainName OPTIONAL,
|
||
IN LPWSTR wszDfsName,
|
||
OUT LPWSTR **List
|
||
);
|
||
}
|
||
|
||
NET_API_STATUS
|
||
NetrDfsEnum200(
|
||
IN DWORD Level,
|
||
IN DWORD PrefMaxLen,
|
||
IN OUT LPDFS_INFO_ENUM_STRUCT DfsEnum,
|
||
IN OUT LPDWORD ResumeHandle
|
||
);
|
||
|
||
#include "cdfsvol.hxx"
|
||
#include "jnpt.hxx"
|
||
#include "security.hxx"
|
||
#include "registry.hxx"
|
||
#include "setup.hxx"
|
||
#include "ftsup.hxx"
|
||
#include "dfsmwml.h"
|
||
|
||
NET_API_STATUS
|
||
DfspGetOneEnumInfo(
|
||
DWORD i,
|
||
DWORD Level,
|
||
LPBYTE InfoArray,
|
||
LPDWORD InfoSize,
|
||
LPDWORD ResumeHandle);
|
||
|
||
DWORD
|
||
DfspGetOneEnumInfoEx(
|
||
PDFS_VOLUME_LIST pDfsVolList,
|
||
DWORD i,
|
||
DWORD Level,
|
||
LPBYTE InfoArray,
|
||
LPDWORD InfoSize);
|
||
|
||
VOID
|
||
DfspFreeOneEnumInfo(
|
||
DWORD i,
|
||
DWORD Level,
|
||
LPBYTE InfoArray);
|
||
|
||
DWORD
|
||
DfspAllocateRelationInfo(
|
||
PDFS_PKT_RELATION_INFO pDfsRelationInfo,
|
||
LPDFSM_RELATION_INFO *ppRelationInfo);
|
||
|
||
DWORD
|
||
DfsManagerRemoveServiceForced(
|
||
LPWSTR wszServerName,
|
||
LPWSTR wszDCName,
|
||
LPWSTR wszFtDfsName);
|
||
|
||
DWORD
|
||
InitializeDfsManager(void);
|
||
|
||
VOID
|
||
GetDebugSwitches();
|
||
|
||
VOID
|
||
GetConfigSwitches();
|
||
|
||
extern HANDLE hSyncEvent;
|
||
extern ULONG DcLockIntervalInMs;
|
||
extern PLDAP pLdapConnection;
|
||
|
||
//+----------------------------------------------------------------------------
|
||
//
|
||
// Function: NormalizeEntryPath
|
||
//
|
||
// Synopsis: Normalizes an EntryPath argument to a prefix.
|
||
//
|
||
// Arguments: [pwszEntryPath] -- The entry path to normalize.
|
||
//
|
||
// Returns: If pwszEntryPath is a UNC path, this routine returns
|
||
// &pwszEntryPath[1]; if pwszEntryPath starts with a backslash,
|
||
// this routine returns pwszEntryPath. In all other cases, this
|
||
// routine returns NULL.
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
|
||
LPWSTR
|
||
NormalizeEntryPath(
|
||
IN LPWSTR pwszEntryPath)
|
||
{
|
||
LPWSTR pwszEntryPathCanon;
|
||
DWORD Type = 0;
|
||
DWORD dwErr;
|
||
ULONG Size = wcslen(pwszEntryPath) + 1;
|
||
WCHAR *wCp;
|
||
|
||
#if DBG
|
||
if (DfsSvcVerbose)
|
||
DbgPrint("NormalizeEntryPath(%ws)\n", pwszEntryPath);
|
||
#endif
|
||
|
||
if (pwszEntryPath == NULL)
|
||
return( NULL );
|
||
|
||
if (wcslen(pwszEntryPath) < 2)
|
||
return( NULL );
|
||
|
||
if (pwszEntryPath[0] != UNICODE_PATH_SEP)
|
||
return( NULL );
|
||
|
||
pwszEntryPathCanon = new WCHAR [ Size ];
|
||
|
||
if (pwszEntryPathCanon == NULL)
|
||
return( NULL );
|
||
|
||
dwErr = I_NetPathCanonicalize(
|
||
NULL,
|
||
pwszEntryPath,
|
||
pwszEntryPathCanon,
|
||
Size * sizeof(WCHAR),
|
||
NULL,
|
||
&Type,
|
||
0);
|
||
#if DBG
|
||
if (DfsSvcVerbose)
|
||
DbgPrint("NormalizeEntryPath:pwszEntryPathCanon:%ws)\n", pwszEntryPathCanon);
|
||
#endif
|
||
|
||
if (dwErr != 0 || (Type != ITYPE_UNC && Type != (ITYPE_PATH | ITYPE_ABSOLUTE))) {
|
||
|
||
delete [] pwszEntryPathCanon;
|
||
return( NULL );
|
||
|
||
}
|
||
|
||
if (ulDfsManagerType == DFS_MANAGER_SERVER) {
|
||
|
||
if (pwszDfsRootName == NULL)
|
||
return NULL;
|
||
|
||
wcscpy(pwszEntryPath, UNICODE_PATH_SEP_STR);
|
||
wcscat(pwszEntryPath, pwszDfsRootName);
|
||
|
||
if (pwszEntryPathCanon[1] == UNICODE_PATH_SEP) {
|
||
wCp = wcschr(&pwszEntryPathCanon[2], UNICODE_PATH_SEP);
|
||
} else {
|
||
wCp = wcschr(&pwszEntryPathCanon[1], UNICODE_PATH_SEP);
|
||
}
|
||
|
||
if(wCp == NULL) {
|
||
return NULL;
|
||
}
|
||
|
||
wcscat(pwszEntryPath, wCp);
|
||
|
||
} else {
|
||
|
||
if (pwszEntryPathCanon[1] == UNICODE_PATH_SEP) {
|
||
wcscpy(pwszEntryPath, &pwszEntryPathCanon[1]);
|
||
} else {
|
||
wcscpy(pwszEntryPath, pwszEntryPathCanon);
|
||
}
|
||
|
||
}
|
||
|
||
delete [] pwszEntryPathCanon;
|
||
|
||
#if DBG
|
||
if (DfsSvcVerbose)
|
||
DbgPrint("NormalizeEntryPath returning %ws\n", pwszEntryPath);
|
||
#endif
|
||
|
||
return( pwszEntryPath );
|
||
|
||
}
|
||
|
||
//+----------------------------------------------------------------------------
|
||
//
|
||
// Function: FormFTDfsEntryPath
|
||
//
|
||
// Synopsis: When the NetDfsXXX APIs are used to administer an FTDfs, the
|
||
// entry path passed in is of the form \servername\sharename\p
|
||
// These first two components must be massaged to the form
|
||
// \domainname\ftdfsname\p
|
||
//
|
||
// Arguments: [pwszEntryPath] -- The entry path to massage
|
||
//
|
||
// Returns: If successfully massaged the entry path, returns a pointer to
|
||
// the newly allocated FTDfs entry path, else NULL
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
|
||
LPWSTR
|
||
FormFTDfsEntryPath(
|
||
IN LPWSTR pwszEntryPath)
|
||
{
|
||
LPWSTR pwszFTDfsPath;
|
||
LPWSTR pwszRestOfPath;
|
||
|
||
if (pwszDomainName == NULL || pwszDfsRootName == NULL)
|
||
return NULL;
|
||
|
||
if (pwszEntryPath[0] == UNICODE_PATH_SEP &&
|
||
pwszEntryPath[1] == UNICODE_PATH_SEP) {
|
||
pwszEntryPath++;
|
||
}
|
||
|
||
pwszFTDfsPath = new WCHAR [
|
||
wcslen(pwszEntryPath) +
|
||
wcslen(UNICODE_PATH_SEP_STR) +
|
||
wcslen(pwszDomainName) +
|
||
wcslen(UNICODE_PATH_SEP_STR) +
|
||
wcslen(pwszDfsRootName) ];
|
||
|
||
if (pwszFTDfsPath != NULL) {
|
||
|
||
wcscpy(pwszFTDfsPath, UNICODE_PATH_SEP_STR);
|
||
wcscat(pwszFTDfsPath, pwszDomainName);
|
||
wcscat(pwszFTDfsPath, UNICODE_PATH_SEP_STR);
|
||
wcscat(pwszFTDfsPath, pwszDfsRootName);
|
||
|
||
//
|
||
// Skip past the first three backslashes of the input parameter
|
||
//
|
||
|
||
if (pwszEntryPath[0] != UNICODE_PATH_SEP)
|
||
return NULL;
|
||
|
||
pwszRestOfPath = wcschr( &pwszEntryPath[1], UNICODE_PATH_SEP );
|
||
|
||
if (pwszRestOfPath == NULL)
|
||
return NULL;
|
||
|
||
pwszRestOfPath = wcschr( &pwszRestOfPath[1], UNICODE_PATH_SEP );
|
||
|
||
if (pwszRestOfPath != NULL)
|
||
wcscat(pwszFTDfsPath, pwszRestOfPath );
|
||
|
||
}
|
||
|
||
#if DBG
|
||
if (DfsSvcVerbose)
|
||
DbgPrint("FormFTDfsEntryPath(%ws->%ws)\n", pwszEntryPath, pwszFTDfsPath);
|
||
#endif
|
||
|
||
return( pwszFTDfsPath );
|
||
|
||
}
|
||
|
||
//+----------------------------------------------------------------------------
|
||
//
|
||
// Function: FormStdDfsEntryPath
|
||
//
|
||
// Synopsis: When the NetDfsXXX APIs are used to administer an StdDfs, the
|
||
// entry path passed in may be of the form \somename\dfsname.
|
||
// The first component must be normalized if possible
|
||
// to the computer name.
|
||
//
|
||
// Arguments: [pwszEntryPath] -- The entry path to normalize
|
||
//
|
||
// Returns: If successfully normalized the entry path, returns a pointer to
|
||
// the newly allocated entry path, else NULL
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
|
||
LPWSTR
|
||
FormStdDfsEntryPath(
|
||
IN LPWSTR pwszEntryPath)
|
||
{
|
||
LPWSTR pwszStdDfsPath;
|
||
LPWSTR pwszRestOfPath;
|
||
|
||
if (pwszComputerName == NULL || pwszDfsRootName == NULL)
|
||
return NULL;
|
||
|
||
if (pwszEntryPath[0] == UNICODE_PATH_SEP &&
|
||
pwszEntryPath[1] == UNICODE_PATH_SEP) {
|
||
pwszEntryPath++;
|
||
}
|
||
|
||
pwszStdDfsPath = new WCHAR [
|
||
wcslen(pwszEntryPath) +
|
||
wcslen(UNICODE_PATH_SEP_STR) +
|
||
wcslen(pwszComputerName) ];
|
||
|
||
if (pwszStdDfsPath != NULL) {
|
||
|
||
wcscpy(pwszStdDfsPath, UNICODE_PATH_SEP_STR);
|
||
wcscat(pwszStdDfsPath, pwszComputerName);
|
||
|
||
//
|
||
// Skip past the first two backslashes of the input parameter
|
||
//
|
||
|
||
ASSERT(pwszEntryPath[0] == UNICODE_PATH_SEP);
|
||
|
||
pwszRestOfPath = wcschr( &pwszEntryPath[1], UNICODE_PATH_SEP );
|
||
|
||
if (pwszRestOfPath != NULL)
|
||
wcscat(pwszStdDfsPath, pwszRestOfPath );
|
||
|
||
}
|
||
|
||
#if DBG
|
||
if (DfsSvcVerbose)
|
||
DbgPrint("FormStdDfsEntryPath(%ws->%ws)\n", pwszEntryPath, pwszStdDfsPath);
|
||
#endif
|
||
|
||
return( pwszStdDfsPath );
|
||
|
||
}
|
||
|
||
|
||
//+----------------------------------------------------------------------------
|
||
//
|
||
// Function: GetDfsVolumeFromPath
|
||
//
|
||
// Synopsis: Given a volume EntryPath, returns a CDfsVolume for that
|
||
// volume.
|
||
//
|
||
// Arguments: [pwszEntryPath] -- EntryPath for which CDfsVolume is
|
||
// desired.
|
||
// [fExactMatch] -- If TRUE, this call will succeed only if
|
||
// a volume object's EntryPath exactly matches
|
||
// pwszEntryPath.
|
||
// [ppCDfsVolume] -- On successful return, contains pointer to
|
||
// newly allocated CDfsVolume for the EntryPath.
|
||
//
|
||
// Returns: [S_OK] -- Successfully returning new CDfsVolume.
|
||
//
|
||
// [E_OUTOFMEMORY] -- Out of memory creating new object.
|
||
//
|
||
// [DFS_E_NO_SUCH_VOLUME] -- Unable to find volume with
|
||
// given EntryPath.
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
|
||
DWORD
|
||
GetDfsVolumeFromPath(
|
||
LPWSTR pwszEntryPath,
|
||
BOOLEAN fExactMatch,
|
||
CDfsVolume **ppCDfsVolume)
|
||
{
|
||
DWORD dwErr;
|
||
CDfsVolume *pCDfsVolume = NULL;
|
||
LPWSTR pwszVolumeObject = NULL;
|
||
|
||
dwErr = GetVolObjForPath( pwszEntryPath, fExactMatch, &pwszVolumeObject );
|
||
|
||
if (dwErr == ERROR_SUCCESS) {
|
||
|
||
pCDfsVolume = new CDfsVolume();
|
||
|
||
if (pCDfsVolume != NULL) {
|
||
|
||
dwErr = pCDfsVolume->Load( pwszVolumeObject, 0 );
|
||
|
||
if (dwErr != ERROR_SUCCESS) {
|
||
|
||
pCDfsVolume->Release();
|
||
|
||
pCDfsVolume = NULL;
|
||
|
||
}
|
||
|
||
} else {
|
||
|
||
dwErr = ERROR_OUTOFMEMORY;
|
||
|
||
}
|
||
|
||
delete [] pwszVolumeObject;
|
||
|
||
}
|
||
|
||
*ppCDfsVolume = pCDfsVolume;
|
||
|
||
return( dwErr );
|
||
|
||
}
|
||
|
||
|
||
//+----------------------------------------------------------------------------
|
||
//
|
||
// Function: NetrDfsManagerGetVersion
|
||
//
|
||
// Synopsis: Returns the version of this server side implementation.
|
||
//
|
||
// Arguments: None.
|
||
//
|
||
// Returns: The version number.
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
|
||
DWORD
|
||
NetrDfsManagerGetVersion()
|
||
{
|
||
DWORD Version = 2;
|
||
DFSM_TRACE_NORM(EVENT, NetrDfsManagerGetVersion_Start, LOGNOTHING);
|
||
#if DBG
|
||
if (DfsSvcVerbose)
|
||
DbgPrint("NetrDfsGetVersion()\n");
|
||
#endif
|
||
|
||
DFSM_TRACE_NORM(EVENT, NetrDfsManagerGetVersion_End, LOGULONG(Version));
|
||
return( Version );
|
||
}
|
||
|
||
//+----------------------------------------------------------------------------
|
||
//
|
||
// Function: NetrDfsAdd (Obsolete)
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
|
||
extern "C" NET_API_STATUS
|
||
NetrDfsAdd(
|
||
IN LPWSTR DfsEntryPath,
|
||
IN LPWSTR ServerName,
|
||
IN LPWSTR ShareName,
|
||
IN LPWSTR Comment,
|
||
IN DWORD Flags)
|
||
{
|
||
NET_API_STATUS status = ERROR_SUCCESS;
|
||
|
||
DFSM_TRACE_NORM(EVENT, NetrDfsAdd_Start,
|
||
LOGSTATUS(status)
|
||
LOGWSTR(DfsEntryPath)
|
||
LOGWSTR(ServerName)
|
||
LOGWSTR(ShareName));
|
||
|
||
if (!AccessCheckRpcClient()) {
|
||
status = ERROR_ACCESS_DENIED;
|
||
}
|
||
else if (ulDfsManagerType == DFS_MANAGER_FTDFS){
|
||
status = ERROR_NOT_SUPPORTED;
|
||
}
|
||
else {
|
||
status = NetrDfsAdd2(
|
||
DfsEntryPath,
|
||
NULL,
|
||
ServerName,
|
||
ShareName,
|
||
Comment,
|
||
Flags,
|
||
NULL);
|
||
}
|
||
DFSM_TRACE_NORM(EVENT, NetrDfsAdd_End,
|
||
LOGSTATUS(status)
|
||
LOGWSTR(DfsEntryPath)
|
||
LOGWSTR(ServerName)
|
||
LOGWSTR(ShareName));
|
||
|
||
return status;
|
||
|
||
}
|
||
|
||
|
||
//+----------------------------------------------------------------------------
|
||
//
|
||
// Function: NetrDfsAdd2
|
||
//
|
||
// Synopsis: Adds a volume/replica/link to this Dfs.
|
||
//
|
||
// Arguments: [DfsEntryPath] -- Entry Path of volume/link to be created, or
|
||
// to which a replica should be added.
|
||
// [DcName] -- Name of Dc to use
|
||
// [ServerName] -- Name of server backing the volume.
|
||
// [ShareName] -- Name of share on ServerName backing the volume.
|
||
// [Comment] -- Comment associated with this volume, only used
|
||
// when DFS_ADD_VOLUME is specified.
|
||
// [Flags] -- If DFS_ADD_VOLUME, a new volume will be created.
|
||
// If DFS_ADD_LINK, a new link to another Dfs will be
|
||
// create. If 0, a replica will be added.
|
||
// [ppRootList] -- On success, returns a list of roots that need to be
|
||
// informed of the change in the DS object
|
||
//
|
||
// Returns: [NERR_Success] -- Operation succeeded.
|
||
//
|
||
// [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] -- An internal database
|
||
// corruption was encountered while executing this
|
||
// operation.
|
||
//
|
||
// [ERROR_OUTOFMEMORY] -- Out of memory condition.
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
|
||
extern "C" NET_API_STATUS
|
||
NetrDfsAdd2(
|
||
IN LPWSTR DfsEntryPath,
|
||
IN LPWSTR DcName,
|
||
IN LPWSTR ServerName,
|
||
IN LPWSTR ShareName,
|
||
IN LPWSTR Comment,
|
||
IN DWORD Flags,
|
||
IN PDFSM_ROOT_LIST *ppRootList)
|
||
{
|
||
NET_API_STATUS status = NERR_Success;
|
||
CDfsVolume *pDfsVol = NULL;
|
||
DFS_REPLICA_INFO replInfo;
|
||
DWORD dwVersion;
|
||
DWORD dwVolType;
|
||
DWORD shareType = 0;
|
||
DWORD dwErr;
|
||
LPWSTR realShareName;
|
||
BOOLEAN modifiedShareName = FALSE;
|
||
LPDFS_SITELIST_INFO pSiteInfo;
|
||
LPWSTR OrgDfsEntryPath = DfsEntryPath;
|
||
|
||
#if DBG
|
||
if (DfsSvcVerbose)
|
||
DbgPrint("NetrDfsAdd2(%ws,%ws,%ws,%ws,%ws,%d,0x%x)\n",
|
||
DfsEntryPath,
|
||
DcName,
|
||
ServerName,
|
||
ShareName,
|
||
Comment,
|
||
Flags,
|
||
ppRootList);
|
||
#endif
|
||
|
||
DFSM_TRACE_NORM(EVENT, NetrDfsAdd2_Start,
|
||
LOGSTATUS(status)
|
||
LOGWSTR(OrgDfsEntryPath)
|
||
LOGWSTR(DcName)
|
||
LOGWSTR(ServerName)
|
||
LOGWSTR(ShareName));
|
||
|
||
if (!AccessCheckRpcClient()) {
|
||
status = ERROR_ACCESS_DENIED;
|
||
goto cleanup;
|
||
}
|
||
|
||
//
|
||
// Validate the input arguments...
|
||
//
|
||
|
||
if ( (Flags & ~(DFS_ADD_VOLUME | DFS_RESTORE_VOLUME)) != 0) {
|
||
status = ERROR_INVALID_PARAMETER;
|
||
goto cleanup;
|
||
}
|
||
|
||
if (DfsEntryPath == NULL || DfsEntryPath[0] != UNICODE_PATH_SEP){
|
||
status = ERROR_INVALID_PARAMETER;
|
||
goto cleanup;
|
||
}
|
||
|
||
#if 0 // Broken for DNS names
|
||
DfsEntryPath = NormalizeEntryPath( DfsEntryPath );
|
||
#endif
|
||
|
||
#if DBG
|
||
if (DfsSvcVerbose) {
|
||
DbgPrint(" 0:DfsEntryPath=[%ws]\n", DfsEntryPath);
|
||
DbgPrint(" 0:ServerName=[%ws]\n", ServerName);
|
||
DbgPrint(" 0:ShareName=[%ws]\n", ShareName);
|
||
}
|
||
#endif
|
||
|
||
if (DfsEntryPath != NULL) {
|
||
|
||
if (ulDfsManagerType == DFS_MANAGER_FTDFS)
|
||
DfsEntryPath = FormFTDfsEntryPath(DfsEntryPath);
|
||
else if (ulDfsManagerType == DFS_MANAGER_SERVER)
|
||
DfsEntryPath = FormStdDfsEntryPath(DfsEntryPath);
|
||
|
||
if (DfsEntryPath == NULL) {
|
||
status = ERROR_OUTOFMEMORY;
|
||
goto cleanup;
|
||
}
|
||
|
||
}
|
||
|
||
#if DBG
|
||
if (DfsSvcVerbose) {
|
||
DbgPrint(" 1:ServerName=[%ws]\n", ServerName);
|
||
DbgPrint(" 1:ShareName=[%ws]\n", ShareName);
|
||
}
|
||
#endif
|
||
|
||
if (DfsEntryPath == NULL ||
|
||
ServerName == NULL ||
|
||
ShareName == NULL) {
|
||
|
||
if (DfsEntryPath != NULL && DfsEntryPath != OrgDfsEntryPath) {
|
||
delete [] DfsEntryPath;
|
||
}
|
||
|
||
status = ERROR_INVALID_PARAMETER;
|
||
goto cleanup;
|
||
}
|
||
|
||
if (ServerName[0] == UNICODE_NULL ||
|
||
ShareName[0] == UNICODE_NULL) {
|
||
|
||
if (DfsEntryPath != OrgDfsEntryPath) {
|
||
delete [] DfsEntryPath;
|
||
}
|
||
|
||
status = ERROR_INVALID_PARAMETER;
|
||
goto cleanup;
|
||
}
|
||
|
||
ENTER_DFSM_OPERATION;
|
||
|
||
if (ulDfsManagerType == DFS_MANAGER_FTDFS) {
|
||
if (DcName != NULL)
|
||
DfsManagerSetDcName(DcName);
|
||
LdapIncrementBlob();
|
||
}
|
||
|
||
//
|
||
// We next determine whether this is going to be an interdomain link or
|
||
// not. While doing so, we'll also check for certain cases of cyclical
|
||
// references.
|
||
//
|
||
|
||
if (I_NetDfsIsThisADomainName(ServerName) == ERROR_SUCCESS) {
|
||
|
||
if (ulDfsManagerType == DFS_MANAGER_FTDFS &&
|
||
pwszDfsRootName != NULL &&
|
||
(_wcsicmp( ServerName, pwszDfsRootName) == 0)){
|
||
status = NERR_DfsCyclicalName;
|
||
DFSM_TRACE_HIGH(ERROR, NetrDfsAdd2_Error1,
|
||
LOGSTATUS(status)
|
||
LOGWSTR(ServerName)
|
||
LOGWSTR(ShareName));
|
||
}
|
||
else
|
||
dwVolType = DFS_VOL_TYPE_REFERRAL_SVC | DFS_VOL_TYPE_INTER_DFS;
|
||
|
||
} else if (Flags & DFS_RESTORE_VOLUME) {
|
||
|
||
dwVolType = DFS_VOL_TYPE_DFS;
|
||
|
||
shareType = 0;
|
||
|
||
} else {
|
||
|
||
//
|
||
// Server name passed in is a real server. See if what kind of share
|
||
// we are talking about.
|
||
//
|
||
|
||
PSHARE_INFO_1005 shi1005;
|
||
|
||
realShareName = wcschr(ShareName, UNICODE_PATH_SEP);
|
||
|
||
if (realShareName != NULL) {
|
||
*realShareName = UNICODE_NULL;
|
||
modifiedShareName = TRUE;
|
||
}
|
||
|
||
status = NetShareGetInfo(
|
||
ServerName,
|
||
ShareName,
|
||
1005,
|
||
(PBYTE *) &shi1005);
|
||
|
||
DFSM_TRACE_ERROR_HIGH(status, ALL_ERROR, NetrDfsAdd2_Error_NetShareGetInfo,
|
||
LOGSTATUS(status)
|
||
LOGWSTR(ServerName)
|
||
LOGWSTR(ShareName));
|
||
|
||
if (modifiedShareName)
|
||
*realShareName = UNICODE_PATH_SEP;
|
||
|
||
if (status == NERR_Success) {
|
||
|
||
shareType = shi1005->shi1005_flags;
|
||
|
||
NetApiBufferFree( shi1005 );
|
||
}
|
||
|
||
if (status != NERR_NetNameNotFound)
|
||
status = NERR_Success;
|
||
|
||
if (status == NERR_Success) {
|
||
|
||
if (shareType & SHI1005_FLAGS_DFS_ROOT) {
|
||
|
||
//
|
||
// If this is a server based Dfs, make sure we are not creating
|
||
// a cyclical link to our root share. Since there is only one
|
||
// share per server that can be a Dfs Root, it is sufficient to
|
||
// see if the machine names match.
|
||
//
|
||
|
||
if (ulDfsManagerType == DFS_MANAGER_SERVER &&
|
||
pwszDfsRootName != NULL &&
|
||
(_wcsicmp( ServerName, pwszDfsRootName) == 0)) {
|
||
status = NERR_DfsCyclicalName;
|
||
DFSM_TRACE_HIGH(ERROR, NetrDfsAdd2_Error2,
|
||
LOGSTATUS(status)
|
||
LOGWSTR(ServerName)
|
||
LOGWSTR(ShareName));
|
||
}
|
||
else
|
||
dwVolType = DFS_VOL_TYPE_REFERRAL_SVC |
|
||
DFS_VOL_TYPE_INTER_DFS;
|
||
|
||
} else {
|
||
|
||
dwVolType = DFS_VOL_TYPE_DFS;
|
||
|
||
}
|
||
|
||
}
|
||
|
||
}
|
||
|
||
//
|
||
// Great, the parameters look semi-reasonable, lets do the work.
|
||
//
|
||
|
||
if (status == NERR_Success) {
|
||
|
||
if ((Flags & DFS_ADD_VOLUME) == 0) {
|
||
|
||
status = GetDfsVolumeFromPath( DfsEntryPath, TRUE, &pDfsVol );
|
||
|
||
} else {
|
||
|
||
//
|
||
// Add volume or link case, so we don't want an exact match.
|
||
// Note that if the Dfs Volume returned does indeed match exactly,
|
||
// its ok, because the subsequent CreateChild operation will fail.
|
||
//
|
||
|
||
status = GetDfsVolumeFromPath( DfsEntryPath, FALSE, &pDfsVol );
|
||
|
||
}
|
||
|
||
}
|
||
|
||
if (status != ERROR_SUCCESS) {
|
||
|
||
pDfsVol = NULL;
|
||
|
||
}
|
||
|
||
if (status == ERROR_SUCCESS) {
|
||
|
||
//
|
||
// Create a DFS_REPLICA_INFO struct for this server-share...
|
||
//
|
||
|
||
ZeroMemory( &replInfo, sizeof(replInfo) );
|
||
|
||
#if DBG
|
||
if (DfsSvcVerbose) {
|
||
DbgPrint(" 2:ServerName=[%ws]\n", ServerName);
|
||
DbgPrint(" 2:ShareName=[%ws]\n", ShareName);
|
||
}
|
||
#endif
|
||
|
||
replInfo.ulReplicaType = DFS_STORAGE_TYPE_NONDFS;
|
||
replInfo.ulReplicaState = DFS_STORAGE_STATE_ONLINE;
|
||
replInfo.pwszServerName = ServerName;
|
||
replInfo.pwszShareName = ShareName;
|
||
|
||
//
|
||
// and carry out the Add operation.
|
||
//
|
||
|
||
if ((Flags & DFS_ADD_VOLUME) != 0) {
|
||
|
||
status = pDfsVol->CreateChild(
|
||
DfsEntryPath,
|
||
dwVolType,
|
||
&replInfo,
|
||
Comment,
|
||
DFS_NORMAL_FORCE);
|
||
|
||
} else {
|
||
|
||
status = pDfsVol->AddReplica( &replInfo, 0 );
|
||
|
||
}
|
||
|
||
if (status == NERR_Success) {
|
||
|
||
//
|
||
// Find out the list of covered sites
|
||
// Note we use dwErr as the return code,
|
||
// because we don't care if this fails - a downlevel
|
||
// server won't respond.
|
||
//
|
||
|
||
pSiteInfo = NULL;
|
||
|
||
dwErr = I_NetDfsManagerReportSiteInfo(
|
||
ServerName,
|
||
&pSiteInfo);
|
||
|
||
DFSM_TRACE_ERROR_HIGH(dwErr, ALL_ERROR, NetrDfsAdd2_Error_I_NetDfsManagerReportSiteInfo,
|
||
LOGSTATUS(dwErr)
|
||
LOGWSTR(ServerName)
|
||
LOGWSTR(ShareName));
|
||
//
|
||
// Create a SiteTable object with those sites
|
||
//
|
||
|
||
if (dwErr == ERROR_SUCCESS) {
|
||
|
||
if (pSiteInfo->cSites > 0) {
|
||
|
||
//
|
||
// AddRef the site table, then put the site info in, then
|
||
// Release it. This will cause it to be written to the
|
||
// appropriate store (ldap or registry).
|
||
//
|
||
|
||
pDfsmSites->AddRef();
|
||
|
||
pDfsmSites->AddOrUpdateSiteInfo(
|
||
ServerName,
|
||
pSiteInfo->cSites,
|
||
&pSiteInfo->Site[0]);
|
||
pDfsmSites->Release();
|
||
}
|
||
|
||
NetApiBufferFree(pSiteInfo);
|
||
|
||
}
|
||
|
||
}
|
||
|
||
}
|
||
|
||
//
|
||
// This writes the dfs-link info back
|
||
// to
|
||
// (1) the registry if stddfs
|
||
// or
|
||
// (2) the in-memory unmarshalled pkt blob which
|
||
// will still need to go to the DS.
|
||
//
|
||
|
||
if (pDfsVol != NULL) {
|
||
pDfsVol->Release();
|
||
}
|
||
|
||
if (ulDfsManagerType == DFS_MANAGER_FTDFS) {
|
||
// if we can't write to the DS we get an error
|
||
// but don't mask any previous errors...
|
||
NET_API_STATUS NewStatus;
|
||
NewStatus = LdapDecrementBlob();
|
||
if(status == NERR_Success){
|
||
status = NewStatus;
|
||
}
|
||
}
|
||
|
||
EXIT_DFSM_OPERATION;
|
||
|
||
//
|
||
// Create list of roots to redirect to this DC
|
||
//
|
||
|
||
if (status == NERR_Success &&
|
||
DcName != NULL &&
|
||
ulDfsManagerType == DFS_MANAGER_FTDFS
|
||
) {
|
||
DfspCreateRootList(
|
||
DfsEntryPath,
|
||
DcName,
|
||
ppRootList);
|
||
}
|
||
|
||
if (DfsEntryPath != OrgDfsEntryPath) {
|
||
delete [] DfsEntryPath;
|
||
}
|
||
cleanup:
|
||
#if DBG
|
||
if (DfsSvcVerbose)
|
||
DbgPrint("NetrDfsAdd2 returning %d\n", status);
|
||
#endif
|
||
DFSM_TRACE_NORM(EVENT, NetrDfsAdd2_End,
|
||
LOGSTATUS(status)
|
||
LOGWSTR(OrgDfsEntryPath)
|
||
LOGWSTR(DcName)
|
||
LOGWSTR(ServerName)
|
||
LOGWSTR(ShareName));
|
||
|
||
return( status );
|
||
}
|
||
|
||
|
||
//+----------------------------------------------------------------------------
|
||
//
|
||
// Function: NetrDfsAddFtRoot
|
||
//
|
||
// Synopsis: Creates a new FtDfs, or joins a Server into an FtDfs at the root
|
||
//
|
||
// Arguments: [ServerName] -- Name of server backing the volume.
|
||
// [DcName] -- DC to use
|
||
// [RootShare] -- Name of share on ServerName backing the volume.
|
||
// [FtDfsName] -- The Name of the FtDfs to create/join
|
||
// [Comment] -- Comment associated with this root.
|
||
// [Flags] -- Flags for the operation
|
||
// [ppRootList] -- On success, returns a list of roots that need to be
|
||
// informed of the change in the DS object
|
||
//
|
||
// Returns: [NERR_Success] -- Operation succeeded.
|
||
//
|
||
// [NERR_DfsInternalCorruption] -- An internal database
|
||
// corruption was encountered while executing this
|
||
// operation.
|
||
//
|
||
// [ERROR_OUTOFMEMORY] -- Out of memory condition.
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
|
||
extern "C" NET_API_STATUS
|
||
NetrDfsAddFtRoot(
|
||
IN LPWSTR ServerName,
|
||
IN LPWSTR DcName,
|
||
IN LPWSTR RootShare,
|
||
IN LPWSTR FtDfsName,
|
||
IN LPWSTR Comment,
|
||
IN LPWSTR ConfigDN,
|
||
IN BOOLEAN NewFtDfs,
|
||
IN DWORD Flags,
|
||
IN PDFSM_ROOT_LIST *ppRootList)
|
||
{
|
||
DWORD dwErr = ERROR_SUCCESS;
|
||
ULONG i;
|
||
WCHAR wszFullObjectName[MAX_PATH];
|
||
WCHAR wszComputerName[MAX_PATH];
|
||
WCHAR wszDomainName[MAX_PATH];
|
||
HKEY hkey;
|
||
DFS_NAME_CONVENTION NameType;
|
||
PDFSM_ROOT_LIST pRootList = NULL;
|
||
|
||
#if DBG
|
||
if (DfsSvcVerbose)
|
||
DbgPrint("NetrDfsAddFtRoot(%ws,%ws,%ws,%ws,%ws,%ws,0x%x,0x%x)\n",
|
||
ServerName,
|
||
DcName,
|
||
RootShare,
|
||
FtDfsName,
|
||
Comment,
|
||
ConfigDN,
|
||
NewFtDfs,
|
||
Flags);
|
||
#endif
|
||
|
||
DFSM_TRACE_NORM(EVENT, NetrDfsAddFtRoot_Start,
|
||
LOGSTATUS(dwErr)
|
||
LOGWSTR(ServerName)
|
||
LOGWSTR(DcName)
|
||
LOGWSTR(RootShare)
|
||
LOGWSTR(FtDfsName)
|
||
LOGWSTR(ConfigDN));
|
||
|
||
if (!AccessCheckRpcClient()) {
|
||
|
||
dwErr = ERROR_ACCESS_DENIED;
|
||
goto cleanup;
|
||
}
|
||
|
||
//
|
||
// Validate the input arguments...
|
||
//
|
||
|
||
if (
|
||
ServerName == NULL ||
|
||
DcName == NULL ||
|
||
RootShare == NULL ||
|
||
FtDfsName == NULL ||
|
||
Comment == NULL ||
|
||
ConfigDN == NULL
|
||
) {
|
||
|
||
dwErr = ERROR_INVALID_PARAMETER;
|
||
goto cleanup;
|
||
}
|
||
|
||
if (
|
||
ServerName[0] == UNICODE_NULL ||
|
||
DcName[0] == UNICODE_NULL ||
|
||
RootShare[0] == UNICODE_NULL ||
|
||
FtDfsName[0] == UNICODE_NULL ||
|
||
ConfigDN[0] == UNICODE_NULL
|
||
) {
|
||
|
||
dwErr = ERROR_INVALID_PARAMETER;
|
||
goto cleanup;
|
||
}
|
||
|
||
//
|
||
// Get our computer and domain names
|
||
//
|
||
NameType = DFS_NAMETYPE_DNS;
|
||
dwErr = GetDomAndComputerName( wszDomainName, wszComputerName, &NameType);
|
||
|
||
if (dwErr != ERROR_SUCCESS){
|
||
goto cleanup;
|
||
//return dwErr;
|
||
|
||
}
|
||
|
||
//
|
||
// Ensure the syntax of FtDfsName is reasonable
|
||
//
|
||
|
||
if( wcslen( FtDfsName ) > NNLEN ||
|
||
wcscspn( FtDfsName, ILLEGAL_NAME_CHARS_STR ) != wcslen( FtDfsName ) ) {
|
||
|
||
dwErr = ERROR_INVALID_NAME;
|
||
goto cleanup;
|
||
}
|
||
|
||
ENTER_DFSM_OPERATION;
|
||
|
||
//
|
||
// Already a root?
|
||
//
|
||
|
||
dwErr = RegOpenKey( HKEY_LOCAL_MACHINE, VOLUMES_DIR, &hkey );
|
||
|
||
if (dwErr != ERROR_SUCCESS) {
|
||
|
||
DfsManagerSetDcName(DcName);
|
||
LdapIncrementBlob();
|
||
|
||
//
|
||
// Update pKT (blob) attribute
|
||
//
|
||
|
||
dwErr = SetupFtDfs(
|
||
wszComputerName,
|
||
wszDomainName,
|
||
RootShare,
|
||
FtDfsName,
|
||
Comment,
|
||
ConfigDN,
|
||
NewFtDfs,
|
||
Flags);
|
||
|
||
#if DBG
|
||
if (DfsSvcVerbose)
|
||
DbgPrint("SetupFtDfs() returned %d\n", dwErr);
|
||
#endif
|
||
|
||
|
||
if (dwErr == ERROR_SUCCESS) {
|
||
|
||
//
|
||
// Reset dfs
|
||
//
|
||
DfsmStopDfs();
|
||
DfsmResetPkt();
|
||
DfsmInitLocalPartitions();
|
||
InitializeDfsManager();
|
||
DfsmStartDfs();
|
||
DfsmPktFlushCache();
|
||
|
||
} else {
|
||
|
||
//
|
||
// Something went wrong - remove all the stuff we set up
|
||
//
|
||
|
||
if (*ppRootList != NULL) {
|
||
pRootList = *ppRootList;
|
||
for (i = 0; i< pRootList->cEntries; i++)
|
||
if (pRootList->Entry[i].ServerShare != NULL)
|
||
MIDL_user_free(pRootList->Entry[i].ServerShare);
|
||
MIDL_user_free(pRootList);
|
||
*ppRootList = NULL;
|
||
}
|
||
|
||
wcscpy(wszFullObjectName, LDAP_VOLUMES_DIR);
|
||
wcscat(wszFullObjectName, DOMAIN_ROOT_VOL);
|
||
|
||
DfsManagerRemoveService(
|
||
wszFullObjectName,
|
||
wszComputerName);
|
||
|
||
|
||
if (*ppRootList != NULL) {
|
||
pRootList = *ppRootList;
|
||
for (i = 0; i < pRootList->cEntries; i++)
|
||
if (pRootList->Entry[i].ServerShare != NULL)
|
||
MIDL_user_free(pRootList->Entry[i].ServerShare);
|
||
MIDL_user_free(pRootList);
|
||
*ppRootList = NULL;
|
||
}
|
||
|
||
DfsRemoveRoot();
|
||
DfsReInitGlobals(wszComputerName, DFS_MANAGER_SERVER);
|
||
|
||
//
|
||
// Tell dfs.sys to discard all state
|
||
//
|
||
DfsmStopDfs();
|
||
DfsmResetPkt();
|
||
DfsmStartDfs();
|
||
DfsmPktFlushCache();
|
||
|
||
}
|
||
|
||
{
|
||
// don't mask the previous errors!!!!
|
||
DWORD dwErr2;
|
||
dwErr2 = LdapDecrementBlob();
|
||
if (dwErr == ERROR_SUCCESS) {
|
||
dwErr = dwErr2;
|
||
}
|
||
}
|
||
|
||
if (dwErr == ERROR_SUCCESS) {
|
||
|
||
//
|
||
// Everything went okay.
|
||
// Update remoteServerName attribute
|
||
//
|
||
|
||
dwErr = DfspCreateFtDfsDsObj(
|
||
wszComputerName,
|
||
DcName,
|
||
RootShare,
|
||
FtDfsName,
|
||
ppRootList);
|
||
#if DBG
|
||
if (DfsSvcVerbose)
|
||
DbgPrint("DfspCreateFtDfsDsObj() returned %d\n", dwErr);
|
||
#endif
|
||
|
||
}
|
||
|
||
|
||
} else {
|
||
|
||
RegCloseKey(hkey);
|
||
dwErr = ERROR_ALREADY_EXISTS;
|
||
|
||
}
|
||
|
||
|
||
EXIT_DFSM_OPERATION;
|
||
cleanup:
|
||
#if DBG
|
||
if (DfsSvcVerbose)
|
||
DbgPrint("NetrDfsAddFtRoot returning %d\n", dwErr);
|
||
#endif
|
||
|
||
DFSM_TRACE_NORM(EVENT, NetrDfsAddFtRoot_End,
|
||
LOGSTATUS(dwErr)
|
||
LOGWSTR(ServerName)
|
||
LOGWSTR(DcName)
|
||
LOGWSTR(RootShare)
|
||
LOGWSTR(FtDfsName)
|
||
LOGWSTR(ConfigDN));
|
||
|
||
return dwErr;
|
||
|
||
}
|
||
|
||
//+----------------------------------------------------------------------------
|
||
//
|
||
// Function: NetrDfsGetDcAddress
|
||
//
|
||
// Synopsis: Gets the DC to go to so that we can create an FtDfs object for
|
||
// this server.
|
||
//
|
||
// Arguments: [ServerName] -- Name of server backing the volume.
|
||
// [DcName] -- Dc to use
|
||
// [IsRoot] -- TRUE if this server is a Dfs root, FALSE otherwise
|
||
// [Timeout] -- Timeout, in sec, that the server will stay with this DC
|
||
//
|
||
// Returns: [NERR_Success] -- Operation succeeded.
|
||
//
|
||
// [NERR_DfsInternalCorruption] -- An internal database
|
||
// corruption was encountered while executing this
|
||
// operation.
|
||
//
|
||
// [ERROR_OUTOFMEMORY] -- Out of memory condition.
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
|
||
extern "C" NET_API_STATUS
|
||
NetrDfsGetDcAddress(
|
||
IN LPWSTR ServerName,
|
||
IN OUT LPWSTR *DcName,
|
||
IN OUT BOOLEAN *IsRoot,
|
||
IN OUT ULONG *Timeout)
|
||
{
|
||
DWORD dwErr = ERROR_SUCCESS;
|
||
HKEY hkey;
|
||
WCHAR *wszDCName;
|
||
|
||
#if DBG
|
||
if (DfsSvcVerbose)
|
||
DbgPrint("NetrDfsGetDcAddress(%ws)\n", ServerName);
|
||
#endif
|
||
|
||
DFSM_TRACE_NORM(EVENT, NetrDfsGetDcAddress_Start,
|
||
LOGSTATUS(dwErr)
|
||
LOGWSTR(ServerName));
|
||
|
||
if (!AccessCheckRpcClient()) {
|
||
|
||
dwErr = ERROR_ACCESS_DENIED;
|
||
goto cleanup;
|
||
}
|
||
|
||
//
|
||
// Validate the input arguments...
|
||
//
|
||
|
||
if (
|
||
ServerName == NULL ||
|
||
DcName == NULL ||
|
||
IsRoot == NULL ||
|
||
Timeout == NULL
|
||
) {
|
||
|
||
dwErr = ERROR_INVALID_PARAMETER;
|
||
goto cleanup;
|
||
}
|
||
|
||
if (ServerName[0] == UNICODE_NULL) {
|
||
|
||
dwErr = ERROR_INVALID_PARAMETER;
|
||
goto cleanup;
|
||
}
|
||
|
||
ENTER_DFSM_OPERATION;
|
||
|
||
//
|
||
// Fill in root flag
|
||
//
|
||
|
||
dwErr = RegOpenKey( HKEY_LOCAL_MACHINE, VOLUMES_DIR, &hkey );
|
||
|
||
if (dwErr == ERROR_SUCCESS) {
|
||
|
||
RegCloseKey(hkey);
|
||
*IsRoot = TRUE;
|
||
|
||
} else {
|
||
|
||
*IsRoot = FALSE;
|
||
|
||
}
|
||
|
||
#if DBG
|
||
if (DfsSvcVerbose)
|
||
DbgPrint("IsRoot=%ws\n", *IsRoot == TRUE ? L"TRUE" : L"FALSE");
|
||
#endif
|
||
|
||
dwErr = ERROR_SUCCESS;
|
||
|
||
if (pwszDSMachineName == NULL) {
|
||
|
||
dwErr = GetDcName( NULL, 1, &wszDCName );
|
||
|
||
if (dwErr == ERROR_SUCCESS) {
|
||
|
||
DfsManagerSetDcName(&wszDCName[2]);
|
||
|
||
}
|
||
|
||
}
|
||
|
||
if (dwErr == ERROR_SUCCESS) {
|
||
|
||
*DcName = (LPWSTR) MIDL_user_allocate((wcslen(pwszDSMachineName)+1) * sizeof(WCHAR));
|
||
if (*DcName != NULL) {
|
||
wcscpy(*DcName,pwszDSMachineName);
|
||
} else {
|
||
dwErr = ERROR_OUTOFMEMORY;
|
||
}
|
||
|
||
}
|
||
|
||
*Timeout = DcLockIntervalInMs / 1000;
|
||
|
||
EXIT_DFSM_OPERATION;
|
||
cleanup:
|
||
#if DBG
|
||
if (DfsSvcVerbose)
|
||
DbgPrint("NetrDfsGetDcAddress returning %d\n", dwErr);
|
||
#endif
|
||
DFSM_TRACE_NORM(EVENT, NetrDfsGetDcAddress_End,
|
||
LOGSTATUS(dwErr)
|
||
LOGWSTR(ServerName)
|
||
LOGWSTR(*DcName)
|
||
LOGBOOLEAN(*IsRoot)
|
||
LOGULONG(*Timeout)
|
||
);
|
||
|
||
return dwErr;
|
||
|
||
}
|
||
|
||
//+----------------------------------------------------------------------------
|
||
//
|
||
// Function: NetrDfsSetDcAddress
|
||
//
|
||
// Synopsis: Sets the DC to go to for the dfs blob
|
||
//
|
||
// Arguments: [ServerName] -- Name of server backing the volume.
|
||
// [DcName] -- Dc to use
|
||
// [Timeout] -- Time, in sec, to stay with that DC
|
||
//
|
||
// Returns: [NERR_Success] -- Operation succeeded.
|
||
//
|
||
// [ERROR_OUTOFMEMORY] -- Out of memory condition.
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
|
||
extern "C" NET_API_STATUS
|
||
NetrDfsSetDcAddress(
|
||
IN LPWSTR ServerName,
|
||
IN LPWSTR DcName,
|
||
IN ULONG Timeout,
|
||
IN DWORD Flags)
|
||
{
|
||
NET_API_STATUS status = ERROR_SUCCESS;
|
||
#if DBG
|
||
if (DfsSvcVerbose)
|
||
DbgPrint("NetrDfsSetDcAddress(%ws,%ws,%d,0x%x)\n",
|
||
ServerName,
|
||
DcName,
|
||
Timeout,
|
||
Flags);
|
||
#endif
|
||
|
||
DFSM_TRACE_NORM(EVENT, NetrDfsSetDcAddress_Start,
|
||
LOGSTATUS(status)
|
||
LOGWSTR(ServerName)
|
||
LOGWSTR(DcName));
|
||
|
||
if (!AccessCheckRpcClient()) {
|
||
|
||
status = ERROR_ACCESS_DENIED;
|
||
goto cleanup;
|
||
}
|
||
|
||
//
|
||
// Validate the input arguments...
|
||
//
|
||
|
||
if (ServerName == NULL || DcName == NULL) {
|
||
|
||
status = ERROR_INVALID_PARAMETER;
|
||
goto cleanup;
|
||
}
|
||
|
||
if (ServerName[0] == UNICODE_NULL || DcName[0] == UNICODE_NULL) {
|
||
|
||
status = ERROR_INVALID_PARAMETER;
|
||
goto cleanup;
|
||
}
|
||
|
||
if (ulDfsManagerType == DFS_MANAGER_FTDFS) {
|
||
|
||
ENTER_DFSM_OPERATION;
|
||
|
||
DfsManagerSetDcName(DcName);
|
||
|
||
if ((Flags & NET_DFS_SETDC_TIMEOUT) != 0) {
|
||
DcLockIntervalInMs = Timeout * 1000;
|
||
}
|
||
|
||
EXIT_DFSM_OPERATION;
|
||
|
||
if (Flags & NET_DFS_SETDC_INITPKT) {
|
||
SetEvent(hSyncEvent);
|
||
}
|
||
|
||
}
|
||
cleanup:
|
||
#if DBG
|
||
if (DfsSvcVerbose)
|
||
DbgPrint("NetrDfsSetDcAddress returning SUCCESS\n");
|
||
#endif
|
||
|
||
DFSM_TRACE_NORM(EVENT, NetrDfsSetDcAddress_End,
|
||
LOGSTATUS(status)
|
||
LOGWSTR(ServerName)
|
||
LOGWSTR(DcName));
|
||
|
||
return ERROR_SUCCESS;
|
||
|
||
}
|
||
|
||
//+----------------------------------------------------------------------------
|
||
//
|
||
// Function: NetrDfsFlushFtTable
|
||
//
|
||
// Synopsis: Flushes an FtDfs entry from the FtDfs cache
|
||
//
|
||
// Arguments: [DcName] -- Dc to use
|
||
// [FtDfsName] -- Name of FtDfs
|
||
//
|
||
// Returns: [NERR_Success] -- Operation succeeded.
|
||
//
|
||
// [ERROR_OUTOFMEMORY] -- Out of memory condition.
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
|
||
extern "C" NET_API_STATUS
|
||
NetrDfsFlushFtTable(
|
||
IN LPWSTR DcName,
|
||
IN LPWSTR FtDfsName)
|
||
{
|
||
ULONG Size;
|
||
DWORD dwErr = ERROR_SUCCESS;
|
||
NTSTATUS Status;
|
||
PDFS_DELETE_SPECIAL_INFO_ARG pSpcDelArg;
|
||
OBJECT_ATTRIBUTES objectAttributes;
|
||
IO_STATUS_BLOCK IoStatus;
|
||
HANDLE dfsHandle = NULL;
|
||
UNICODE_STRING SrvName;
|
||
|
||
DFSM_TRACE_NORM(EVENT, NetrDfsFlushFtTable_Start,
|
||
LOGSTATUS(Status)
|
||
LOGWSTR(DcName)
|
||
LOGWSTR(FtDfsName));
|
||
|
||
if (!AccessCheckRpcClient()) {
|
||
|
||
Status = ERROR_ACCESS_DENIED;
|
||
goto cleanup;
|
||
}
|
||
|
||
//
|
||
// Validate the input arguments...
|
||
//
|
||
|
||
if (DcName == NULL || FtDfsName == NULL) {
|
||
|
||
Status = ERROR_INVALID_PARAMETER;
|
||
goto cleanup;
|
||
}
|
||
|
||
if (DcName[0] == UNICODE_NULL || FtDfsName[0] == UNICODE_NULL) {
|
||
|
||
Status = ERROR_INVALID_PARAMETER;
|
||
goto cleanup;
|
||
}
|
||
|
||
Size = sizeof(DFS_DELETE_SPECIAL_INFO_ARG) +
|
||
wcslen(FtDfsName) * sizeof(WCHAR);
|
||
|
||
pSpcDelArg = (PDFS_DELETE_SPECIAL_INFO_ARG) malloc(Size);
|
||
|
||
if (pSpcDelArg != NULL) {
|
||
|
||
WCHAR *wCp;
|
||
|
||
RtlZeroMemory(pSpcDelArg, Size);
|
||
|
||
wCp = (WCHAR *)((PCHAR)pSpcDelArg + sizeof(DFS_DELETE_SPECIAL_INFO_ARG));
|
||
pSpcDelArg->SpecialName.Buffer = (PWCHAR)sizeof(DFS_DELETE_SPECIAL_INFO_ARG);
|
||
pSpcDelArg->SpecialName.Length = wcslen(FtDfsName) * sizeof(WCHAR);
|
||
pSpcDelArg->SpecialName.MaximumLength = pSpcDelArg->SpecialName.Length;
|
||
RtlCopyMemory(wCp, FtDfsName, pSpcDelArg->SpecialName.Length);
|
||
|
||
ENTER_DFSM_OPERATION;
|
||
|
||
RtlInitUnicodeString(&SrvName, DFS_SERVER_NAME);
|
||
|
||
InitializeObjectAttributes(
|
||
&objectAttributes,
|
||
&SrvName,
|
||
OBJ_CASE_INSENSITIVE,
|
||
NULL,
|
||
NULL
|
||
);
|
||
|
||
Status = NtCreateFile(
|
||
&dfsHandle,
|
||
SYNCHRONIZE | FILE_WRITE_DATA,
|
||
&objectAttributes,
|
||
&IoStatus,
|
||
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
|
||
);
|
||
|
||
DFSM_TRACE_ERROR_HIGH(Status, ALL_ERROR, NetrDfsFlushFtTable_Error_NtCreateFile,
|
||
LOGSTATUS(Status)
|
||
LOGWSTR(DcName)
|
||
LOGWSTR(FtDfsName));
|
||
|
||
if (NT_SUCCESS(Status)) {
|
||
|
||
NtFsControlFile(
|
||
dfsHandle,
|
||
NULL, // Event,
|
||
NULL, // ApcRoutine,
|
||
NULL, // ApcContext,
|
||
&IoStatus,
|
||
FSCTL_DFS_DELETE_FTDFS_INFO,
|
||
pSpcDelArg,
|
||
Size,
|
||
NULL,
|
||
0);
|
||
|
||
NtClose(dfsHandle);
|
||
|
||
}
|
||
|
||
free(pSpcDelArg);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
|
||
dwErr = ERROR_NOT_FOUND;
|
||
|
||
}
|
||
|
||
EXIT_DFSM_OPERATION;
|
||
|
||
} else {
|
||
|
||
dwErr = ERROR_OUTOFMEMORY;
|
||
|
||
}
|
||
cleanup:
|
||
DFSM_TRACE_NORM(EVENT, NetrDfsFlushFtTable_Start,
|
||
LOGSTATUS(Status)
|
||
LOGWSTR(DcName)
|
||
LOGWSTR(FtDfsName));
|
||
|
||
return dwErr;
|
||
|
||
}
|
||
|
||
//+----------------------------------------------------------------------------
|
||
//
|
||
// Function: NetrDfsAddStdRoot
|
||
//
|
||
// Synopsis: Creates a new Std Dfs
|
||
//
|
||
// Arguments: [ServerName] -- Name of server backing the volume.
|
||
// [RootShare] -- Name of share on ServerName backing the volume.
|
||
// [Comment] -- Comment associated with this root.
|
||
// [Flags] -- Flags for the operation
|
||
//
|
||
// Returns: [NERR_Success] -- Operation succeeded.
|
||
//
|
||
// [NERR_DfsInternalCorruption] -- An internal database
|
||
// corruption was encountered while executing this
|
||
// operation.
|
||
//
|
||
// [ERROR_OUTOFMEMORY] -- Out of memory condition.
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
|
||
extern "C" NET_API_STATUS
|
||
NetrDfsAddStdRoot(
|
||
IN LPWSTR ServerName,
|
||
IN LPWSTR RootShare,
|
||
IN LPWSTR Comment,
|
||
IN DWORD Flags)
|
||
{
|
||
WCHAR wszComputerName[MAX_PATH+1];
|
||
DWORD dwErr = ERROR_SUCCESS;
|
||
HKEY hkey;
|
||
DFS_NAME_CONVENTION NameType;
|
||
|
||
DFSM_TRACE_NORM(EVENT, NetrDfsAddStdRoot_Start,
|
||
LOGSTATUS(dwErr)
|
||
LOGWSTR(ServerName)
|
||
LOGWSTR(RootShare));
|
||
|
||
if (!AccessCheckRpcClient()) {
|
||
|
||
dwErr = ERROR_ACCESS_DENIED;
|
||
goto cleanup;
|
||
}
|
||
|
||
//
|
||
// Validate the input arguments...
|
||
//
|
||
|
||
if (ServerName == NULL || RootShare == NULL) {
|
||
|
||
dwErr = ERROR_INVALID_PARAMETER;
|
||
goto cleanup;
|
||
}
|
||
|
||
if (ServerName[0] == UNICODE_NULL || RootShare[0] == UNICODE_NULL) {
|
||
|
||
dwErr = ERROR_INVALID_PARAMETER;
|
||
goto cleanup;
|
||
}
|
||
|
||
//
|
||
// Get our computer name
|
||
//
|
||
NameType = DFS_NAMETYPE_EITHER;
|
||
// NameType = DFS_NAMETYPE_NETBIOS;
|
||
dwErr = GetDomAndComputerName( NULL, wszComputerName, &NameType);
|
||
|
||
if (dwErr != ERROR_SUCCESS){
|
||
goto cleanup;
|
||
//return dwErr;
|
||
|
||
}
|
||
|
||
ENTER_DFSM_OPERATION;
|
||
|
||
//
|
||
// Already a root?
|
||
//
|
||
|
||
dwErr = RegOpenKey( HKEY_LOCAL_MACHINE, VOLUMES_DIR, &hkey );
|
||
|
||
if (dwErr != ERROR_SUCCESS) {
|
||
|
||
dwErr = SetupStdDfs(
|
||
wszComputerName,
|
||
RootShare,
|
||
Comment,
|
||
Flags,
|
||
NULL);
|
||
|
||
if (dwErr == ERROR_SUCCESS) {
|
||
|
||
//
|
||
// Reset dfs
|
||
//
|
||
DfsmStopDfs();
|
||
DfsmResetPkt();
|
||
DfsmInitLocalPartitions();
|
||
InitializeDfsManager();
|
||
DfsmStartDfs();
|
||
DfsmPktFlushCache();
|
||
|
||
}
|
||
|
||
} else {
|
||
|
||
RegCloseKey(hkey);
|
||
dwErr = ERROR_ALREADY_EXISTS;
|
||
|
||
}
|
||
|
||
EXIT_DFSM_OPERATION;
|
||
cleanup:
|
||
DFSM_TRACE_NORM(EVENT, NetrDfsAddStdRoot_End,
|
||
LOGSTATUS(dwErr)
|
||
LOGWSTR(ServerName)
|
||
LOGWSTR(RootShare));
|
||
|
||
return dwErr;
|
||
|
||
}
|
||
|
||
//+----------------------------------------------------------------------------
|
||
//
|
||
// Function: NetrDfsAddStdRootForced
|
||
//
|
||
// Synopsis: Creates a new Std Dfs
|
||
//
|
||
// Arguments: [ServerName] -- Name of server backing the volume.
|
||
// [RootShare] -- Name of share on ServerName backing the volume.
|
||
// [Comment] -- Comment associated with this root.
|
||
// [Share] -- drive:\dir behind the share
|
||
//
|
||
// Returns: [NERR_Success] -- Operation succeeded.
|
||
//
|
||
// [NERR_DfsInternalCorruption] -- An internal database
|
||
// corruption was encountered while executing this
|
||
// operation.
|
||
//
|
||
// [ERROR_OUTOFMEMORY] -- Out of memory condition.
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
|
||
extern "C" NET_API_STATUS
|
||
NetrDfsAddStdRootForced(
|
||
IN LPWSTR ServerName,
|
||
IN LPWSTR RootShare,
|
||
IN LPWSTR Comment,
|
||
IN LPWSTR Share)
|
||
{
|
||
WCHAR wszComputerName[MAX_PATH+1];
|
||
DWORD dwErr = ERROR_SUCCESS;
|
||
HKEY hkey;
|
||
DFS_NAME_CONVENTION NameType;
|
||
|
||
DFSM_TRACE_NORM(EVENT, NetrDfsAddStdRootForced_Start,
|
||
LOGSTATUS(dwErr)
|
||
LOGWSTR(ServerName)
|
||
LOGWSTR(RootShare)
|
||
LOGWSTR(Share));
|
||
|
||
if (!AccessCheckRpcClient()) {
|
||
|
||
dwErr = ERROR_ACCESS_DENIED;
|
||
goto cleanup;
|
||
}
|
||
|
||
//
|
||
// Validate the input arguments...
|
||
//
|
||
|
||
if (ServerName == NULL || RootShare == NULL || Share == NULL) {
|
||
|
||
dwErr = ERROR_INVALID_PARAMETER;
|
||
goto cleanup;
|
||
}
|
||
|
||
if (ServerName[0] == UNICODE_NULL || RootShare[0] == UNICODE_NULL || Share[0] == UNICODE_NULL) {
|
||
|
||
dwErr = ERROR_INVALID_PARAMETER;
|
||
goto cleanup;
|
||
}
|
||
|
||
//
|
||
// Get our computer name
|
||
//
|
||
NameType = DFS_NAMETYPE_EITHER;
|
||
dwErr = GetDomAndComputerName( NULL, wszComputerName, &NameType);
|
||
|
||
if (dwErr != ERROR_SUCCESS){
|
||
goto cleanup;
|
||
//return dwErr;
|
||
|
||
}
|
||
|
||
ENTER_DFSM_OPERATION;
|
||
|
||
//
|
||
// Already a root?
|
||
//
|
||
|
||
dwErr = RegOpenKey( HKEY_LOCAL_MACHINE, VOLUMES_DIR, &hkey );
|
||
|
||
if (dwErr != ERROR_SUCCESS) {
|
||
|
||
dwErr = SetupStdDfs(
|
||
wszComputerName,
|
||
RootShare,
|
||
Comment,
|
||
1,
|
||
Share);
|
||
|
||
if (dwErr == ERROR_SUCCESS) {
|
||
|
||
//
|
||
// Reset dfs
|
||
//
|
||
DfsmStopDfs();
|
||
DfsmResetPkt();
|
||
DfsmInitLocalPartitions();
|
||
InitializeDfsManager();
|
||
DfsmStartDfs();
|
||
DfsmPktFlushCache();
|
||
|
||
}
|
||
|
||
} else {
|
||
|
||
RegCloseKey(hkey);
|
||
dwErr = ERROR_ALREADY_EXISTS;
|
||
|
||
}
|
||
|
||
EXIT_DFSM_OPERATION;
|
||
cleanup:
|
||
DFSM_TRACE_NORM(EVENT, NetrDfsAddStdRootForced_End,
|
||
LOGSTATUS(dwErr)
|
||
LOGWSTR(ServerName)
|
||
LOGWSTR(RootShare)
|
||
LOGWSTR(Share));
|
||
|
||
return dwErr;
|
||
|
||
}
|
||
|
||
|
||
|
||
//+----------------------------------------------------------------------------
|
||
//
|
||
// Function: NetrDfsRemove (Obsolete)
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
|
||
extern "C" NET_API_STATUS
|
||
NetrDfsRemove(
|
||
IN LPWSTR DfsEntryPath,
|
||
IN LPWSTR ServerName,
|
||
IN LPWSTR ShareName)
|
||
{
|
||
NET_API_STATUS status = ERROR_SUCCESS;
|
||
DFSM_TRACE_NORM(EVENT, NetrDfsRemove_Start,
|
||
LOGSTATUS(status)
|
||
LOGWSTR(DfsEntryPath)
|
||
LOGWSTR(ServerName)
|
||
LOGWSTR(ShareName));
|
||
|
||
if (!AccessCheckRpcClient()) {
|
||
status = ERROR_ACCESS_DENIED;
|
||
goto cleanup;
|
||
}
|
||
|
||
if (ulDfsManagerType == DFS_MANAGER_FTDFS){
|
||
status = ERROR_NOT_SUPPORTED;
|
||
goto cleanup;
|
||
}
|
||
|
||
status = NetrDfsRemove2(
|
||
DfsEntryPath,
|
||
NULL,
|
||
ServerName,
|
||
ShareName,
|
||
NULL);
|
||
goto cleanup;
|
||
cleanup:
|
||
DFSM_TRACE_NORM(EVENT, NetrDfsRemove_End,
|
||
LOGSTATUS(status)
|
||
LOGWSTR(DfsEntryPath)
|
||
LOGWSTR(ServerName)
|
||
LOGWSTR(ShareName));
|
||
|
||
return status;
|
||
}
|
||
|
||
//+----------------------------------------------------------------------------
|
||
//
|
||
// Function: NetrDfsRemove2
|
||
//
|
||
// Synopsis: Deletes a volume/replica/link from the Dfs.
|
||
//
|
||
// Arguments: [DfsEntryPath] -- Entry path of the volume to operate on.
|
||
// [DcName] -- Name of Dc to use
|
||
// [ServerName] -- If specified, indicates the replica of the
|
||
// volume to operate on.
|
||
// [ShareName] -- If specified, indicates the share on the
|
||
// server to operate on.
|
||
// [Flags] -- Flags for the operation
|
||
// [ppRootList] -- On success, returns a list of roots that need to be
|
||
// informed of the change in the DS object
|
||
//
|
||
// Returns: [NERR_Success] -- Operation successful.
|
||
//
|
||
// [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] -- Internal database corruption
|
||
// encountered while executing operation.
|
||
//
|
||
// [ERROR_INVALID_PARAMETER] -- One of the input parameters is
|
||
// incorrect.
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
|
||
extern "C" NET_API_STATUS
|
||
NetrDfsRemove2(
|
||
IN LPWSTR DfsEntryPath,
|
||
IN LPWSTR DcName,
|
||
IN LPWSTR ServerName,
|
||
IN LPWSTR ShareName,
|
||
IN PDFSM_ROOT_LIST *ppRootList)
|
||
{
|
||
NET_API_STATUS status = ERROR_SUCCESS;
|
||
CDfsVolume *pDfsVol = NULL;
|
||
DFS_REPLICA_INFO replInfo;
|
||
BOOLEAN fRemoveReplica = FALSE;
|
||
LPWSTR OrgDfsEntryPath = DfsEntryPath;
|
||
DWORD dwErr;
|
||
|
||
#if DBG
|
||
if (DfsSvcVerbose)
|
||
DbgPrint("NetrDfsRemove2(%ws,%ws,%ws,%ws,0x%x)\n",
|
||
DfsEntryPath,
|
||
DcName,
|
||
ServerName,
|
||
ShareName,
|
||
ppRootList);
|
||
#endif
|
||
DFSM_TRACE_NORM(EVENT, NetrDfsRemove2_Start,
|
||
LOGSTATUS(status)
|
||
LOGWSTR(OrgDfsEntryPath)
|
||
LOGWSTR(DcName)
|
||
LOGWSTR(ServerName)
|
||
LOGWSTR(ShareName));
|
||
|
||
if (!AccessCheckRpcClient()){
|
||
status = ERROR_ACCESS_DENIED;
|
||
goto cleanup;
|
||
}
|
||
|
||
//
|
||
// Validate the input arguments...
|
||
//
|
||
|
||
#if 0 // Broken for DNS names
|
||
DfsEntryPath = NormalizeEntryPath( DfsEntryPath );
|
||
#endif
|
||
|
||
if (DfsEntryPath != NULL) {
|
||
|
||
if (ulDfsManagerType == DFS_MANAGER_FTDFS)
|
||
DfsEntryPath = FormFTDfsEntryPath(DfsEntryPath);
|
||
else if (ulDfsManagerType == DFS_MANAGER_SERVER)
|
||
DfsEntryPath = FormStdDfsEntryPath(DfsEntryPath);
|
||
|
||
if (DfsEntryPath == NULL){
|
||
status = ERROR_OUTOFMEMORY;
|
||
goto cleanup;
|
||
}
|
||
|
||
}
|
||
|
||
if (DfsEntryPath == NULL) {
|
||
status = ERROR_INVALID_PARAMETER;
|
||
goto cleanup;
|
||
}
|
||
|
||
//
|
||
// If ServerName is present, it must be valid.
|
||
//
|
||
|
||
if (ServerName != NULL && ServerName[0] == UNICODE_NULL) {
|
||
|
||
if (DfsEntryPath != OrgDfsEntryPath) {
|
||
delete [] DfsEntryPath;
|
||
}
|
||
|
||
status = ERROR_INVALID_PARAMETER;
|
||
goto cleanup;
|
||
}
|
||
|
||
//
|
||
// If ShareName is present, it must be valid.
|
||
//
|
||
|
||
if (ShareName != NULL && ShareName[0] == UNICODE_NULL) {
|
||
|
||
if (DfsEntryPath != OrgDfsEntryPath) {
|
||
delete [] DfsEntryPath;
|
||
}
|
||
|
||
status = ERROR_INVALID_PARAMETER;
|
||
goto cleanup;
|
||
}
|
||
|
||
//
|
||
// If ShareName is present, ServerName must be present.
|
||
//
|
||
|
||
if (ShareName != NULL && ServerName == NULL) {
|
||
|
||
if (DfsEntryPath != OrgDfsEntryPath) {
|
||
delete [] DfsEntryPath;
|
||
}
|
||
|
||
status = ERROR_INVALID_PARAMETER;
|
||
goto cleanup;
|
||
}
|
||
|
||
ENTER_DFSM_OPERATION;
|
||
|
||
//
|
||
// Great, the parameters look semi-reasonable, lets do the work.
|
||
//
|
||
|
||
if (ulDfsManagerType == DFS_MANAGER_FTDFS) {
|
||
if (DcName != NULL)
|
||
DfsManagerSetDcName(DcName);
|
||
LdapIncrementBlob();
|
||
}
|
||
|
||
ZeroMemory( &replInfo, sizeof(replInfo) );
|
||
|
||
status = GetDfsVolumeFromPath( DfsEntryPath, TRUE, &pDfsVol );
|
||
|
||
if (status != ERROR_SUCCESS) {
|
||
|
||
pDfsVol = NULL;
|
||
|
||
}
|
||
|
||
if (status == ERROR_SUCCESS && ServerName != NULL && ShareName != NULL) {
|
||
|
||
LPWSTR pwszShare;
|
||
|
||
replInfo.ulReplicaState = 0;
|
||
replInfo.ulReplicaType = 0;
|
||
replInfo.pwszServerName = ServerName;
|
||
replInfo.pwszShareName = ShareName;
|
||
|
||
fRemoveReplica = TRUE;
|
||
|
||
}
|
||
|
||
if (status == ERROR_SUCCESS) {
|
||
|
||
//
|
||
// See whether we should delete a replica or the volume
|
||
//
|
||
|
||
if (fRemoveReplica) {
|
||
|
||
status = pDfsVol->RemoveReplica( &replInfo, DFS_OVERRIDE_FORCE );
|
||
|
||
if (status == NERR_DfsCantRemoveLastServerShare) {
|
||
|
||
status = pDfsVol->Delete( DFS_OVERRIDE_FORCE );
|
||
|
||
}
|
||
|
||
} else {
|
||
|
||
status = pDfsVol->Delete( DFS_OVERRIDE_FORCE );
|
||
|
||
}
|
||
|
||
}
|
||
|
||
if (pDfsVol != NULL) {
|
||
pDfsVol->Release();
|
||
}
|
||
|
||
if (ulDfsManagerType == DFS_MANAGER_FTDFS)
|
||
status = LdapDecrementBlob();
|
||
|
||
EXIT_DFSM_OPERATION;
|
||
|
||
|
||
//
|
||
// Create list of roots to redirect to this DC
|
||
//
|
||
|
||
if (status == NERR_Success &&
|
||
DcName != NULL &&
|
||
ulDfsManagerType == DFS_MANAGER_FTDFS
|
||
) {
|
||
DfspCreateRootList(
|
||
DfsEntryPath,
|
||
DcName,
|
||
ppRootList);
|
||
}
|
||
|
||
if (DfsEntryPath != OrgDfsEntryPath) {
|
||
delete [] DfsEntryPath;
|
||
}
|
||
cleanup:
|
||
#if DBG
|
||
if (DfsSvcVerbose)
|
||
DbgPrint("NetrDfsRemove2 returning %d\n", status);
|
||
#endif
|
||
|
||
|
||
DFSM_TRACE_NORM(EVENT, NetrDfsRemove2_End,
|
||
LOGSTATUS(status)
|
||
LOGWSTR(OrgDfsEntryPath)
|
||
LOGWSTR(DcName)
|
||
LOGWSTR(ServerName)
|
||
LOGWSTR(ShareName));
|
||
return( status );
|
||
|
||
}
|
||
|
||
|
||
//+----------------------------------------------------------------------------
|
||
//
|
||
// Function: NetrDfsRemoveFtRoot
|
||
//
|
||
// Synopsis: Deletes a root from an FtDfs.
|
||
//
|
||
// Arguments: [ServerName] -- The server to remove.
|
||
// [DcName] -- DC to use
|
||
// [RootShare] -- The Root share hosting the Dfs/FtDfs
|
||
// [FtDfsName] -- The FtDfs to remove the root from.
|
||
// [Flags] -- Flags for the operation
|
||
// [ppRootList] -- On success, returns a list of roots that need to be
|
||
// informed of the change in the DS object
|
||
//
|
||
// Returns: [NERR_Success] -- Operation successful.
|
||
//
|
||
// [NERR_DfsInternalCorruption] -- Internal database corruption
|
||
// encountered while executing operation.
|
||
//
|
||
// [ERROR_INVALID_PARAMETER] -- One of the input parameters is
|
||
// incorrect.
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
|
||
extern "C" NET_API_STATUS
|
||
NetrDfsRemoveFtRoot(
|
||
IN LPWSTR ServerName,
|
||
IN LPWSTR DcName,
|
||
IN LPWSTR RootShare,
|
||
IN LPWSTR FtDfsName,
|
||
IN DWORD Flags,
|
||
IN PDFSM_ROOT_LIST *ppRootList)
|
||
{
|
||
DWORD dwErr = ERROR_SUCCESS;
|
||
DWORD dwErr2 = ERROR_SUCCESS;
|
||
DWORD cbData;
|
||
DWORD dwType;
|
||
HKEY hkey;
|
||
WCHAR wszRootShare[MAX_PATH];
|
||
WCHAR wszFTDfs[MAX_PATH];
|
||
WCHAR wszFullObjectName[MAX_PATH];
|
||
WCHAR wszComputerName[MAX_PATH];
|
||
DFS_NAME_CONVENTION NameType;
|
||
|
||
#if DBG
|
||
if (DfsSvcVerbose)
|
||
DbgPrint("NetrDfsRemoveFtRoot(%ws,%ws,%ws,%ws,0x%x)\n",
|
||
ServerName,
|
||
DcName,
|
||
RootShare,
|
||
FtDfsName,
|
||
Flags);
|
||
#endif
|
||
DFSM_TRACE_NORM(EVENT, NetrDfsRemoveFtRoot_Start,
|
||
LOGSTATUS(dwErr)
|
||
LOGWSTR(ServerName)
|
||
LOGWSTR(DcName)
|
||
LOGWSTR(RootShare)
|
||
LOGWSTR(FtDfsName));
|
||
|
||
if (!AccessCheckRpcClient()) {
|
||
|
||
dwErr = ERROR_ACCESS_DENIED;
|
||
goto cleanup;
|
||
|
||
}
|
||
|
||
//
|
||
// Validate the input arguments...
|
||
//
|
||
|
||
if (
|
||
ServerName == NULL ||
|
||
DcName == NULL ||
|
||
RootShare == NULL ||
|
||
FtDfsName == NULL
|
||
) {
|
||
|
||
dwErr = ERROR_INVALID_PARAMETER;
|
||
goto cleanup;
|
||
}
|
||
|
||
if (
|
||
ServerName[0] == UNICODE_NULL ||
|
||
DcName[0] == UNICODE_NULL ||
|
||
RootShare[0] == UNICODE_NULL ||
|
||
FtDfsName[0] == UNICODE_NULL
|
||
) {
|
||
|
||
dwErr = ERROR_INVALID_PARAMETER;
|
||
goto cleanup;
|
||
}
|
||
|
||
//
|
||
// Get our computer name
|
||
//
|
||
NameType = DFS_NAMETYPE_DNS;
|
||
dwErr = GetDomAndComputerName( NULL, wszComputerName, &NameType);
|
||
|
||
if (dwErr != ERROR_SUCCESS){
|
||
goto cleanup;
|
||
//return dwErr;
|
||
|
||
}
|
||
|
||
if ((Flags & DFS_FORCE_REMOVE) == 0) {
|
||
|
||
ENTER_DFSM_OPERATION;
|
||
|
||
//
|
||
// Update remoteServerName attribute
|
||
//
|
||
|
||
|
||
dwErr = DfspRemoveFtDfsDsObj(
|
||
wszComputerName,
|
||
DcName,
|
||
RootShare,
|
||
FtDfsName,
|
||
ppRootList);
|
||
|
||
|
||
if (dwErr == ERROR_SUCCESS) {
|
||
LdapIncrementBlob();
|
||
DfsManagerSetDcName(DcName);
|
||
|
||
//
|
||
// We need to be a root to remove a root...
|
||
//
|
||
|
||
dwErr = RegOpenKey( HKEY_LOCAL_MACHINE, VOLUMES_DIR, &hkey );
|
||
}
|
||
|
||
|
||
//
|
||
// Check RootName and FtDfsName
|
||
//
|
||
|
||
if (dwErr == ERROR_SUCCESS) {
|
||
|
||
cbData = sizeof(wszRootShare);
|
||
|
||
dwErr = RegQueryValueEx(
|
||
hkey,
|
||
ROOT_SHARE_VALUE_NAME,
|
||
NULL,
|
||
&dwType,
|
||
(PBYTE) wszRootShare,
|
||
&cbData);
|
||
|
||
if (dwErr != ERROR_SUCCESS ||
|
||
dwType != REG_SZ ||
|
||
_wcsicmp(wszRootShare, RootShare) != 0
|
||
) {
|
||
|
||
dwErr = ERROR_INVALID_PARAMETER;
|
||
|
||
}
|
||
|
||
} else {
|
||
|
||
hkey = NULL;
|
||
|
||
}
|
||
|
||
if (dwErr == ERROR_SUCCESS) {
|
||
|
||
cbData = sizeof(wszFTDfs);
|
||
|
||
dwErr = RegQueryValueEx(
|
||
hkey,
|
||
FTDFS_VALUE_NAME,
|
||
NULL,
|
||
&dwType,
|
||
(PBYTE) wszFTDfs,
|
||
&cbData);
|
||
|
||
if (dwErr != ERROR_SUCCESS ||
|
||
dwType != REG_SZ ||
|
||
_wcsicmp(wszFTDfs, FtDfsName) != 0
|
||
) {
|
||
|
||
dwErr = ERROR_INVALID_PARAMETER;
|
||
|
||
}
|
||
|
||
}
|
||
|
||
//
|
||
// Update pKT (blob) attribute
|
||
//
|
||
|
||
if (dwErr == ERROR_SUCCESS) {
|
||
|
||
wcscpy(wszFullObjectName, LDAP_VOLUMES_DIR);
|
||
wcscat(wszFullObjectName, DOMAIN_ROOT_VOL);
|
||
|
||
dwErr = DfsManagerRemoveService(
|
||
wszFullObjectName,
|
||
wszComputerName);
|
||
|
||
if (dwErr == NERR_DfsCantRemoveLastServerShare) {
|
||
dwErr = ERROR_SUCCESS;
|
||
}
|
||
|
||
}
|
||
|
||
|
||
if (dwErr == ERROR_SUCCESS) {
|
||
|
||
dwErr = DfsRemoveRoot();
|
||
|
||
if (dwErr == ERROR_SUCCESS) {
|
||
|
||
//
|
||
// Reinit the service, back to non-ldap
|
||
//
|
||
|
||
DfsReInitGlobals(wszComputerName, DFS_MANAGER_SERVER);
|
||
|
||
//
|
||
// Tell dfs.sys to discard all state
|
||
//
|
||
|
||
RegCloseKey(hkey);
|
||
hkey = NULL;
|
||
|
||
DfsmStopDfs();
|
||
DfsmResetPkt();
|
||
DfsmStartDfs();
|
||
DfsmPktFlushCache();
|
||
|
||
}
|
||
|
||
}
|
||
|
||
if (hkey != NULL) {
|
||
|
||
RegCloseKey(hkey);
|
||
|
||
}
|
||
|
||
dwErr2 = LdapDecrementBlob();
|
||
// don't mask more important errors.
|
||
if(dwErr == ERROR_SUCCESS) {
|
||
dwErr = dwErr2;
|
||
}
|
||
|
||
EXIT_DFSM_OPERATION;
|
||
|
||
} else {
|
||
|
||
ENTER_DFSM_OPERATION;
|
||
|
||
//
|
||
// We're forcefully removing a root. We'd better be a DC!!
|
||
//
|
||
|
||
//
|
||
// Update remoteServerName attribute
|
||
//
|
||
|
||
dwErr = DfspRemoveFtDfsDsObj(
|
||
ServerName,
|
||
DcName,
|
||
RootShare,
|
||
FtDfsName,
|
||
ppRootList);
|
||
|
||
//
|
||
// Update pKT (blob) attribute
|
||
//
|
||
|
||
if (dwErr == ERROR_SUCCESS) {
|
||
|
||
dwErr = DfsManagerRemoveServiceForced(
|
||
ServerName,
|
||
DcName,
|
||
FtDfsName);
|
||
}
|
||
|
||
|
||
|
||
EXIT_DFSM_OPERATION;
|
||
|
||
}
|
||
cleanup:
|
||
#if DBG
|
||
if (DfsSvcVerbose)
|
||
DbgPrint("NetrDfsRemoveFtRoot returning %d\n", dwErr);
|
||
#endif
|
||
DFSM_TRACE_NORM(EVENT, NetrDfsRemoveFtRoot_End,
|
||
LOGSTATUS(dwErr)
|
||
LOGWSTR(ServerName)
|
||
LOGWSTR(DcName)
|
||
LOGWSTR(RootShare)
|
||
LOGWSTR(FtDfsName));
|
||
|
||
return dwErr;
|
||
|
||
}
|
||
|
||
//+----------------------------------------------------------------------------
|
||
//
|
||
// Function: NetrDfsRemoveStdRoot
|
||
//
|
||
// Synopsis: Deletes a Dfs root
|
||
//
|
||
// Arguments: [ServerName] -- The server to remove.
|
||
// [RootShare] -- The Root share hosting the Dfs/FtDfs
|
||
// [Flags] -- Flags for the operation
|
||
//
|
||
// Returns: [NERR_Success] -- Operation successful.
|
||
//
|
||
// [NERR_DfsInternalCorruption] -- Internal database corruption
|
||
// encountered while executing operation.
|
||
//
|
||
// [ERROR_INVALID_PARAMETER] -- One of the input parameters is
|
||
// incorrect.
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
|
||
extern "C" NET_API_STATUS
|
||
NetrDfsRemoveStdRoot(
|
||
IN LPWSTR ServerName,
|
||
IN LPWSTR RootShare,
|
||
IN DWORD Flags)
|
||
{
|
||
DWORD dwErr = ERROR_SUCCESS;
|
||
DWORD cbData;
|
||
DWORD dwType;
|
||
HKEY hkey;
|
||
WCHAR wszRootShare[MAX_PATH];
|
||
|
||
DFSM_TRACE_NORM(EVENT, NetrDfsRemoveStdRoot_Start,
|
||
LOGSTATUS(dwErr)
|
||
LOGWSTR(ServerName)
|
||
LOGWSTR(RootShare));
|
||
|
||
if (!AccessCheckRpcClient()) {
|
||
|
||
dwErr = ERROR_ACCESS_DENIED;
|
||
goto cleanup;
|
||
}
|
||
|
||
//
|
||
// Validate the input arguments...
|
||
//
|
||
|
||
if (ServerName == NULL) {
|
||
|
||
dwErr = ERROR_INVALID_PARAMETER;
|
||
goto cleanup;
|
||
}
|
||
|
||
if (ServerName[0] == UNICODE_NULL) {
|
||
|
||
dwErr = ERROR_INVALID_PARAMETER;
|
||
goto cleanup;
|
||
}
|
||
|
||
if (RootShare == NULL) {
|
||
|
||
dwErr = ERROR_INVALID_PARAMETER;
|
||
goto cleanup;
|
||
}
|
||
|
||
if (RootShare[0] == UNICODE_NULL) {
|
||
|
||
dwErr = ERROR_INVALID_PARAMETER;
|
||
goto cleanup;
|
||
}
|
||
|
||
ENTER_DFSM_OPERATION;
|
||
|
||
//
|
||
// We need to be a root to remove a root...
|
||
//
|
||
|
||
dwErr = RegOpenKey( HKEY_LOCAL_MACHINE, VOLUMES_DIR, &hkey );
|
||
|
||
//
|
||
// Check RootName
|
||
//
|
||
|
||
if (dwErr == ERROR_SUCCESS) {
|
||
|
||
cbData = sizeof(wszRootShare);
|
||
|
||
dwErr = RegQueryValueEx(
|
||
hkey,
|
||
ROOT_SHARE_VALUE_NAME,
|
||
NULL,
|
||
&dwType,
|
||
(PBYTE) wszRootShare,
|
||
&cbData);
|
||
|
||
if (dwErr != ERROR_SUCCESS ||
|
||
dwType != REG_SZ ||
|
||
_wcsicmp(wszRootShare, RootShare) != 0
|
||
) {
|
||
|
||
dwErr = ERROR_INVALID_PARAMETER;
|
||
|
||
}
|
||
|
||
} else {
|
||
|
||
hkey = NULL;
|
||
|
||
}
|
||
|
||
if (dwErr == ERROR_SUCCESS) {
|
||
|
||
//
|
||
// Remove registry stuff (DfsHost and volumes)
|
||
//
|
||
|
||
dwErr = DfsRemoveRoot();
|
||
|
||
if (dwErr == ERROR_SUCCESS) {
|
||
|
||
//
|
||
// Reinit the service
|
||
//
|
||
|
||
DfsReInitGlobals(pwszComputerName, DFS_MANAGER_SERVER);
|
||
|
||
//
|
||
// Tell dfs.sys to discard all state
|
||
//
|
||
|
||
RegCloseKey(hkey);
|
||
hkey = NULL;
|
||
|
||
DfsmStopDfs();
|
||
DfsmResetPkt();
|
||
DfsmStartDfs();
|
||
DfsmPktFlushCache();
|
||
|
||
}
|
||
|
||
}
|
||
|
||
if (hkey != NULL) {
|
||
|
||
RegCloseKey(hkey);
|
||
|
||
}
|
||
|
||
EXIT_DFSM_OPERATION;
|
||
cleanup:
|
||
DFSM_TRACE_NORM(EVENT, NetrDfsRemoveStdRoot_End,
|
||
LOGSTATUS(dwErr)
|
||
LOGWSTR(ServerName)
|
||
LOGWSTR(RootShare));
|
||
|
||
return dwErr;
|
||
|
||
}
|
||
|
||
//+----------------------------------------------------------------------------
|
||
//
|
||
// Function: NetrDfsSetInfo (Obsolete)
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
|
||
extern "C" NET_API_STATUS
|
||
NetrDfsSetInfo(
|
||
IN LPWSTR DfsEntryPath,
|
||
IN LPWSTR ServerName,
|
||
IN LPWSTR ShareName,
|
||
IN DWORD Level,
|
||
IN LPDFS_INFO_STRUCT DfsInfo)
|
||
{
|
||
if (!AccessCheckRpcClient())
|
||
return( ERROR_ACCESS_DENIED );
|
||
|
||
if (ulDfsManagerType == DFS_MANAGER_FTDFS)
|
||
return( ERROR_NOT_SUPPORTED );
|
||
|
||
return NetrDfsSetInfo2(
|
||
DfsEntryPath,
|
||
NULL,
|
||
ServerName,
|
||
ShareName,
|
||
Level,
|
||
DfsInfo,
|
||
NULL);
|
||
}
|
||
|
||
|
||
//+----------------------------------------------------------------------------
|
||
//
|
||
// Function: NetrDfsSetInfo2
|
||
//
|
||
// Synopsis: Sets the comment, volume state, or replica state.
|
||
//
|
||
// Arguments: [DfsEntryPath] -- Entry Path of the volume for which info is
|
||
// to be set.
|
||
// [ServerName] -- If specified, the name of the server whose
|
||
// state is to be set.
|
||
// [ShareName] -- If specified, the name of the share on
|
||
// ServerName whose state is to be set.
|
||
// [Level] -- Level of DfsInfo
|
||
// [DfsInfo] -- The actual Dfs info.
|
||
//
|
||
// Returns: [NERR_Success] -- Operation completed successfully.
|
||
//
|
||
// [ERROR_INVALID_LEVEL] -- Level != 100 , 101, or 102
|
||
//
|
||
// [ERROR_INVALID_PARAMETER] -- DfsEntryPath invalid, or
|
||
// ShareName specified without ServerName.
|
||
//
|
||
// [NERR_DfsNoSuchVolume] -- DfsEntryPath does not correspond to
|
||
// a valid Dfs volume.
|
||
//
|
||
// [NERR_DfsNoSuchShare] -- The indicated ServerName/ShareName do
|
||
// not support this Dfs volume.
|
||
//
|
||
// [NERR_DfsInternalCorruption] -- Internal database corruption
|
||
// encountered while executing operation.
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
|
||
extern "C" NET_API_STATUS
|
||
NetrDfsSetInfo2(
|
||
IN LPWSTR DfsEntryPath,
|
||
IN LPWSTR DcName,
|
||
IN LPWSTR ServerName,
|
||
IN LPWSTR ShareName,
|
||
IN DWORD Level,
|
||
IN LPDFS_INFO_STRUCT DfsInfo,
|
||
IN PDFSM_ROOT_LIST *ppRootList)
|
||
{
|
||
NET_API_STATUS status = ERROR_SUCCESS;
|
||
NET_API_STATUS netStatus;
|
||
CDfsVolume *pDfsVol = NULL;
|
||
LPWSTR pwszShare = NULL;
|
||
BOOLEAN fSetReplicaState;
|
||
LPWSTR OrgDfsEntryPath = DfsEntryPath;
|
||
|
||
DFSM_TRACE_NORM(EVENT, NetrDfsSetInfo2_Start,
|
||
LOGSTATUS(status)
|
||
LOGWSTR(OrgDfsEntryPath)
|
||
LOGWSTR(DcName)
|
||
LOGWSTR(ServerName)
|
||
LOGWSTR(ShareName));
|
||
#if DBG
|
||
if (DfsSvcVerbose) {
|
||
DbgPrint("NetrDfsSetInfo2(%ws,%ws,%ws,%ws,%d,0x%x\n",
|
||
DfsEntryPath,
|
||
DcName,
|
||
ServerName,
|
||
ShareName,
|
||
Level,
|
||
ppRootList);
|
||
if (Level == 100) {
|
||
DbgPrint(",Comment=%ws)\n", DfsInfo->DfsInfo100->Comment);
|
||
} else if (Level == 101) {
|
||
DbgPrint(",State=0x%x)\n", DfsInfo->DfsInfo101->State);
|
||
} else if (Level == 102) {
|
||
DbgPrint(",Timeout=0x%x)\n", DfsInfo->DfsInfo102->Timeout);
|
||
} else {
|
||
DbgPrint(")\n");
|
||
}
|
||
}
|
||
#endif
|
||
|
||
if (!AccessCheckRpcClient()) {
|
||
status = ERROR_ACCESS_DENIED;
|
||
goto cleanup;
|
||
}
|
||
|
||
//
|
||
// Validate the input parameters...
|
||
//
|
||
|
||
#if 0 // Broken for DNS names
|
||
DfsEntryPath = NormalizeEntryPath( DfsEntryPath );
|
||
#endif
|
||
|
||
if (DfsEntryPath != NULL) {
|
||
|
||
if (ulDfsManagerType == DFS_MANAGER_FTDFS)
|
||
DfsEntryPath = FormFTDfsEntryPath(DfsEntryPath);
|
||
else if (ulDfsManagerType == DFS_MANAGER_SERVER)
|
||
DfsEntryPath = FormStdDfsEntryPath(DfsEntryPath);
|
||
|
||
if (DfsEntryPath == NULL){
|
||
status = ERROR_OUTOFMEMORY;
|
||
goto cleanup;
|
||
}
|
||
|
||
}
|
||
|
||
if (DfsEntryPath == NULL) {
|
||
|
||
status = ERROR_INVALID_PARAMETER;
|
||
goto cleanup;
|
||
|
||
}
|
||
|
||
if (DfsInfo == NULL || DfsInfo->DfsInfo100 == NULL) {
|
||
|
||
if (DfsEntryPath != OrgDfsEntryPath) {
|
||
delete [] DfsEntryPath;
|
||
}
|
||
|
||
status = ERROR_INVALID_PARAMETER;
|
||
goto cleanup;
|
||
}
|
||
|
||
if (!(Level >= 100 && Level <= 102)) {
|
||
|
||
if (DfsEntryPath != OrgDfsEntryPath) {
|
||
delete [] DfsEntryPath;
|
||
}
|
||
|
||
status = ERROR_INVALID_LEVEL;
|
||
goto cleanup;
|
||
}
|
||
|
||
ENTER_DFSM_OPERATION;
|
||
|
||
if (ulDfsManagerType == DFS_MANAGER_FTDFS) {
|
||
if (DcName != NULL)
|
||
DfsManagerSetDcName(DcName);
|
||
LdapIncrementBlob();
|
||
}
|
||
|
||
//
|
||
// Try to get the Dfs Volume for DfsEntryPath
|
||
//
|
||
|
||
status = GetDfsVolumeFromPath( DfsEntryPath, TRUE, &pDfsVol );
|
||
|
||
if (status == ERROR_SUCCESS) {
|
||
|
||
//
|
||
// Do the right thing based on Level...
|
||
//
|
||
|
||
if (Level == 100) {
|
||
|
||
//
|
||
// Set the volume Comment
|
||
//
|
||
|
||
if (DfsInfo->DfsInfo100->Comment != NULL)
|
||
status = pDfsVol->SetComment(DfsInfo->DfsInfo100->Comment);
|
||
else
|
||
status = pDfsVol->SetComment(L"");
|
||
|
||
} else if (Level == 101) {
|
||
|
||
//
|
||
// Set the volume state
|
||
//
|
||
|
||
if (ServerName == NULL && ShareName == NULL) {
|
||
|
||
fSetReplicaState = FALSE;
|
||
|
||
} else if (ServerName != NULL && ServerName[0] != UNICODE_NULL &&
|
||
ShareName != NULL && ShareName[0] != UNICODE_NULL) {
|
||
|
||
fSetReplicaState = TRUE;
|
||
|
||
} else {
|
||
|
||
status = ERROR_INVALID_PARAMETER;
|
||
DFSM_TRACE_HIGH(ERROR, NetrDfsSetInfo2_Error1,
|
||
LOGSTATUS(status)
|
||
LOGWSTR(DcName)
|
||
LOGWSTR(ServerName)
|
||
LOGWSTR(ShareName));
|
||
}
|
||
|
||
if (status == ERROR_SUCCESS) {
|
||
|
||
if (fSetReplicaState) {
|
||
|
||
status = pDfsVol->SetReplicaState(
|
||
ServerName,
|
||
ShareName,
|
||
DfsInfo->DfsInfo101->State);
|
||
|
||
} else {
|
||
|
||
status = pDfsVol->SetVolumeState(DfsInfo->DfsInfo101->State);
|
||
|
||
}
|
||
|
||
}
|
||
|
||
if (pwszShare != NULL) {
|
||
|
||
delete [] pwszShare;
|
||
|
||
}
|
||
|
||
} else if (Level == 102) {
|
||
|
||
//
|
||
// Set the volume timeout
|
||
//
|
||
|
||
status = pDfsVol->SetVolumeTimeout(DfsInfo->DfsInfo102->Timeout);
|
||
|
||
}
|
||
|
||
}
|
||
|
||
|
||
if (pDfsVol != NULL) {
|
||
pDfsVol->Release();
|
||
}
|
||
|
||
if (ulDfsManagerType == DFS_MANAGER_FTDFS)
|
||
status = LdapDecrementBlob();
|
||
|
||
EXIT_DFSM_OPERATION;
|
||
|
||
//
|
||
// Create list of roots to redirect to this DC
|
||
//
|
||
|
||
if (status == NERR_Success &&
|
||
DcName != NULL &&
|
||
ulDfsManagerType == DFS_MANAGER_FTDFS
|
||
) {
|
||
DfspCreateRootList(
|
||
DfsEntryPath,
|
||
DcName,
|
||
ppRootList);
|
||
}
|
||
|
||
if (DfsEntryPath != OrgDfsEntryPath) {
|
||
delete [] DfsEntryPath;
|
||
}
|
||
cleanup:
|
||
#if DBG
|
||
if (DfsSvcVerbose)
|
||
DbgPrint("NetrDfsSetInfo2 returning %d\n", status);
|
||
#endif
|
||
|
||
DFSM_TRACE_NORM(EVENT, NetrDfsSetInfo2_End,
|
||
LOGSTATUS(status)
|
||
LOGWSTR(OrgDfsEntryPath)
|
||
LOGWSTR(DcName)
|
||
LOGWSTR(ServerName)
|
||
LOGWSTR(ShareName));
|
||
return( status );
|
||
|
||
}
|
||
|
||
|
||
|
||
//+----------------------------------------------------------------------------
|
||
//
|
||
// Function: NetrDfsGetInfo
|
||
//
|
||
// Synopsis: Server side implementation of the NetDfsGetInfo.
|
||
//
|
||
// Arguments: [DfsEntryPath] -- Entry Path of volume for which info is
|
||
// requested.
|
||
//
|
||
// [ServerName] -- Name of server which supports this volume
|
||
// and for which info is requested.
|
||
//
|
||
// [ShareName] -- Name of share on ServerName which supports this
|
||
// volume.
|
||
//
|
||
// [Level] -- Level of Info requested.
|
||
//
|
||
// [DfsInfo] -- On successful return, contains a pointer to the
|
||
// requested DFS_INFO_x struct.
|
||
//
|
||
// Returns: [NERR_Success] -- If successfully returned requested info.
|
||
//
|
||
// [NERR_DfsNoSuchVolume] -- If DfsEntryPath does not
|
||
// corresponds to a valid volume.
|
||
//
|
||
// [NERR_DfsInternalCorruption] -- Corruption encountered in
|
||
// internal database.
|
||
//
|
||
// [ERROR_NOT_ENOUGH_MEMORY] -- Unable to allocate memory for
|
||
// info.
|
||
//
|
||
// [ERROR_INVALID_PARAMETER] -- DfsInfo was NULL on entry, or
|
||
// ShareName specified without ServerName, or
|
||
// DfsEntryPath was NULL on entry.
|
||
//
|
||
// [ERROR_INVALID_LEVEL] -- Level != 1,2,3,4, or 100
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
|
||
extern "C" NET_API_STATUS
|
||
NetrDfsGetInfo(
|
||
IN LPWSTR DfsEntryPath,
|
||
IN LPWSTR ServerName,
|
||
IN LPWSTR ShareName,
|
||
IN DWORD Level,
|
||
OUT LPDFS_INFO_STRUCT DfsInfo)
|
||
{
|
||
NET_API_STATUS status = ERROR_SUCCESS;
|
||
LPDFS_INFO_3 pInfo;
|
||
CDfsVolume *pDfsVol;
|
||
DWORD cbInfo;
|
||
LPWSTR OrgDfsEntryPath = DfsEntryPath;
|
||
|
||
DFSM_TRACE_NORM(EVENT, NetrDfsGetInfo_Start,
|
||
LOGSTATUS(status)
|
||
LOGWSTR(DfsEntryPath)
|
||
LOGWSTR(ServerName)
|
||
LOGWSTR(ShareName));
|
||
#if DBG
|
||
if (DfsSvcVerbose)
|
||
DbgPrint("NetrDfsGetInfo(%ws,%ws,%ws,%d)\n",
|
||
DfsEntryPath,
|
||
ServerName,
|
||
ShareName,
|
||
Level);
|
||
#endif
|
||
|
||
IDfsVolInlineDebOut((DEB_TRACE, "NetrDfsGetInfo(L=%d)\n", Level));
|
||
|
||
//
|
||
// Validate the input parameters...
|
||
//
|
||
|
||
#if 0 // Broken for DNS names
|
||
DfsEntryPath = NormalizeEntryPath( DfsEntryPath );
|
||
#endif
|
||
|
||
if (DfsEntryPath != NULL) {
|
||
|
||
if (ulDfsManagerType == DFS_MANAGER_FTDFS)
|
||
DfsEntryPath = FormFTDfsEntryPath(DfsEntryPath);
|
||
else if (ulDfsManagerType == DFS_MANAGER_SERVER)
|
||
DfsEntryPath = FormStdDfsEntryPath(DfsEntryPath);
|
||
|
||
if (DfsEntryPath == NULL) {
|
||
status = ERROR_OUTOFMEMORY;
|
||
goto cleanup;
|
||
}
|
||
|
||
}
|
||
|
||
if (DfsEntryPath == NULL) {
|
||
|
||
status = ERROR_INVALID_PARAMETER;
|
||
goto cleanup;
|
||
}
|
||
|
||
if (DfsInfo == NULL) {
|
||
|
||
if (DfsEntryPath != OrgDfsEntryPath) {
|
||
delete [] DfsEntryPath;
|
||
}
|
||
|
||
status = ERROR_INVALID_PARAMETER;
|
||
goto cleanup;
|
||
}
|
||
|
||
if (!(Level >= 1 && Level <= 4) && Level != 100) {
|
||
|
||
if (DfsEntryPath != OrgDfsEntryPath) {
|
||
delete [] DfsEntryPath;
|
||
}
|
||
|
||
status = ERROR_INVALID_LEVEL;
|
||
goto cleanup;
|
||
}
|
||
|
||
if (ServerName == NULL && ShareName != NULL) {
|
||
|
||
if (DfsEntryPath != OrgDfsEntryPath) {
|
||
delete [] DfsEntryPath;
|
||
}
|
||
|
||
status = ERROR_INVALID_PARAMETER;
|
||
goto cleanup;
|
||
}
|
||
|
||
//
|
||
// Now, get the info...
|
||
//
|
||
|
||
if (Level <= 3) {
|
||
|
||
pInfo = (LPDFS_INFO_3) MIDL_user_allocate(sizeof(DFS_INFO_3));
|
||
|
||
} else {
|
||
|
||
pInfo = (LPDFS_INFO_3) MIDL_user_allocate(sizeof(DFS_INFO_4));
|
||
|
||
}
|
||
|
||
if (pInfo == NULL) {
|
||
|
||
if (DfsEntryPath != OrgDfsEntryPath) {
|
||
delete [] DfsEntryPath;
|
||
}
|
||
|
||
status = ERROR_NOT_ENOUGH_MEMORY;
|
||
goto cleanup;
|
||
|
||
}
|
||
|
||
ENTER_DFSM_OPERATION;
|
||
|
||
if (ulDfsManagerType == DFS_MANAGER_FTDFS)
|
||
LdapIncrementBlob();
|
||
|
||
status = GetDfsVolumeFromPath( DfsEntryPath, TRUE, &pDfsVol );
|
||
|
||
if (status == ERROR_SUCCESS) {
|
||
|
||
status = pDfsVol->GetNetInfo(Level, pInfo, &cbInfo );
|
||
|
||
pDfsVol->Release();
|
||
|
||
}
|
||
|
||
if (status == ERROR_SUCCESS) {
|
||
|
||
DfsInfo->DfsInfo3 = pInfo;
|
||
|
||
} else if (status != NERR_DfsNoSuchVolume) {
|
||
|
||
status = NERR_DfsInternalCorruption;
|
||
|
||
}
|
||
|
||
if (ulDfsManagerType == DFS_MANAGER_FTDFS) {
|
||
NET_API_STATUS TempStatus;
|
||
TempStatus = LdapDecrementBlob();
|
||
// only mask the status if we haven't already seen an error.
|
||
if(status == ERROR_SUCCESS) {
|
||
status = TempStatus;
|
||
}
|
||
}
|
||
|
||
EXIT_DFSM_OPERATION;
|
||
|
||
if (DfsEntryPath != OrgDfsEntryPath) {
|
||
delete [] DfsEntryPath;
|
||
}
|
||
cleanup:
|
||
#if DBG
|
||
if (DfsSvcVerbose)
|
||
DbgPrint("NetrDfsGetInfo returning %d\n", status);
|
||
#endif
|
||
DFSM_TRACE_NORM(EVENT, NetrDfsGetInfo_End,
|
||
LOGSTATUS(status)
|
||
LOGWSTR(DfsEntryPath)
|
||
LOGWSTR(ServerName)
|
||
LOGWSTR(ShareName));
|
||
|
||
return( status );
|
||
|
||
}
|
||
|
||
|
||
//+----------------------------------------------------------------------------
|
||
//
|
||
// Function: NetrDfsEnum
|
||
//
|
||
// Synopsis: The server side implementation of the NetDfsEnum public API
|
||
//
|
||
// Arguments: [Level] -- The level of info struct desired.
|
||
// [PrefMaxLen] -- Preferred maximum length of output buffer.
|
||
// 0xffffffff means no limit.
|
||
// [DfsEnum] -- DFS_INFO_ENUM_STRUCT pointer where the info
|
||
// structs will be returned.
|
||
// [ResumeHandle] -- If 0, the enumeration will begin from the
|
||
// start. On return, the resume handle will be an opaque
|
||
// cookie that can be passed in on subsequent calls to
|
||
// resume the enumeration.
|
||
//
|
||
// Returns: [NERR_Success] -- Successfully retrieved info.
|
||
//
|
||
// [NERR_DfsInternalCorruption] -- Internal Dfs database is
|
||
// corrupt.
|
||
//
|
||
// [ERROR_INVALID_PARAMETER] -- DfsEnum or ResumeHandle were
|
||
// NULL on entry.
|
||
//
|
||
// [ERROR_INVALID_LEVEL] -- If Level != 1,2, 4 or 200
|
||
//
|
||
// [ERROR_NO_MORE_ITEMS] -- If nothing more to enumerate based
|
||
// on *ResumeHandle value.
|
||
//
|
||
// [ERROR_NOT_ENOUGH_MEMORY] -- If we hit an out of memory
|
||
// condition while constructing info.
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
|
||
extern "C" NET_API_STATUS
|
||
NetrDfsEnum(
|
||
IN DWORD Level,
|
||
IN DWORD PrefMaxLen,
|
||
IN OUT LPDFS_INFO_ENUM_STRUCT DfsEnum,
|
||
IN OUT LPDWORD ResumeHandle)
|
||
{
|
||
NET_API_STATUS status = ERROR_SUCCESS;
|
||
DWORD i, cEntriesToRead, cbInfoSize, cbOneInfoSize, cbTotalSize;
|
||
LPBYTE pBuffer;
|
||
|
||
DFSM_TRACE_NORM(EVENT, NetrDfsEnum_Start,
|
||
LOGSTATUS(status));
|
||
|
||
IDfsVolInlineDebOut((DEB_TRACE, "NetrDfsEnum(L=%d)\n", Level));
|
||
|
||
#if DBG
|
||
if (DfsSvcVerbose)
|
||
DbgPrint("NetrDfsEnum(%d,0x%x)\n",
|
||
Level,
|
||
PrefMaxLen);
|
||
#endif
|
||
|
||
//
|
||
// Validate the Out parameters before we die...
|
||
//
|
||
|
||
if (DfsEnum == NULL ||
|
||
DfsEnum->DfsInfoContainer.DfsInfo1Container == NULL ||
|
||
ResumeHandle == NULL) {
|
||
#if DBG
|
||
if (DfsSvcVerbose)
|
||
DbgPrint("NetrDfsEnum returning ERROR_INVALID_PARAMETER\n");
|
||
#endif
|
||
|
||
if (DfsEventLog > 1) {
|
||
LogWriteMessage(
|
||
NET_DFS_ENUM,
|
||
ERROR_INVALID_PARAMETER,
|
||
0,
|
||
NULL);
|
||
}
|
||
|
||
status = ERROR_INVALID_PARAMETER;
|
||
goto cleanup;
|
||
}
|
||
|
||
//
|
||
// Validate the Info Level...
|
||
//
|
||
if (!(Level >= 1 && Level <= 4) && Level != 200) {
|
||
#if DBG
|
||
if (DfsSvcVerbose)
|
||
DbgPrint("NetrDfsEnum returning ERROR_INVALID_LEVEL\n");
|
||
#endif
|
||
if (DfsEventLog > 1) {
|
||
LogWriteMessage(
|
||
NET_DFS_ENUM,
|
||
ERROR_INVALID_LEVEL,
|
||
0,
|
||
NULL);
|
||
}
|
||
status = ERROR_INVALID_LEVEL;
|
||
goto cleanup;
|
||
}
|
||
|
||
ENTER_DFSM_OPERATION;
|
||
|
||
if (ulDfsManagerType == DFS_MANAGER_FTDFS)
|
||
LdapIncrementBlob();
|
||
|
||
//
|
||
// Handle level 200 as a special case
|
||
//
|
||
|
||
if (Level == 200) {
|
||
|
||
status = NetrDfsEnum200(
|
||
Level,
|
||
PrefMaxLen,
|
||
DfsEnum,
|
||
ResumeHandle);
|
||
|
||
if (ulDfsManagerType == DFS_MANAGER_FTDFS)
|
||
status = LdapDecrementBlob();
|
||
|
||
EXIT_DFSM_OPERATION;
|
||
|
||
#if DBG
|
||
if (DfsSvcVerbose) {
|
||
DbgPrint("NetrDfsEnum200 returned %d\n", status);
|
||
DbgPrint("NetrDfsEnum returning %d\n", status);
|
||
}
|
||
#endif
|
||
if (DfsEventLog > 1) {
|
||
LogWriteMessage(
|
||
NET_DFS_ENUM,
|
||
status,
|
||
0,
|
||
NULL);
|
||
}
|
||
//return( status );
|
||
goto cleanup;
|
||
}
|
||
|
||
//
|
||
// Sanity check the ResumeHandle...
|
||
//
|
||
|
||
if (pDfsmStorageDirectory == NULL ||
|
||
(*ResumeHandle) >= pDfsmStorageDirectory->GetNumEntries()) {
|
||
|
||
if (ulDfsManagerType == DFS_MANAGER_FTDFS)
|
||
status = LdapDecrementBlob();
|
||
|
||
EXIT_DFSM_OPERATION;
|
||
|
||
#if DBG
|
||
if (DfsSvcVerbose)
|
||
DbgPrint("NetrDfsEnum returning ERROR_NO_MORE_ITEMS\n");
|
||
#endif
|
||
if (DfsEventLog > 1) {
|
||
LogWriteMessage(
|
||
NET_DFS_ENUM,
|
||
ERROR_NO_MORE_ITEMS,
|
||
0,
|
||
NULL);
|
||
}
|
||
status = ERROR_NO_MORE_ITEMS;
|
||
goto cleanup;
|
||
|
||
}
|
||
|
||
switch (Level) {
|
||
case 1:
|
||
cbInfoSize = sizeof(DFS_INFO_1);
|
||
break;
|
||
|
||
case 2:
|
||
cbInfoSize = sizeof(DFS_INFO_2);
|
||
break;
|
||
|
||
case 3:
|
||
cbInfoSize = sizeof(DFS_INFO_3);
|
||
break;
|
||
|
||
case 4:
|
||
cbInfoSize = sizeof(DFS_INFO_4);
|
||
break;
|
||
|
||
default:
|
||
EXIT_DFSM_OPERATION;
|
||
status = ERROR_INVALID_LEVEL;
|
||
goto cleanup;
|
||
}
|
||
|
||
if (PrefMaxLen == ~0) {
|
||
|
||
cEntriesToRead = pDfsmStorageDirectory->GetNumEntries();
|
||
|
||
} else {
|
||
|
||
cEntriesToRead = min( pDfsmStorageDirectory->GetNumEntries(),
|
||
PrefMaxLen / cbInfoSize );
|
||
|
||
}
|
||
|
||
#if DBG
|
||
if (DfsSvcVerbose)
|
||
DbgPrint("NetrDfsEnum: cEntriesToRead = %d\n", cEntriesToRead);
|
||
#endif
|
||
|
||
pBuffer = (LPBYTE) MIDL_user_allocate( cEntriesToRead * cbInfoSize );
|
||
|
||
if (pBuffer == NULL) {
|
||
|
||
if (ulDfsManagerType == DFS_MANAGER_FTDFS)
|
||
status = LdapDecrementBlob();
|
||
|
||
EXIT_DFSM_OPERATION;
|
||
#if DBG
|
||
if (DfsSvcVerbose)
|
||
DbgPrint("NetrDfsEnum returning ERROR_NOT_ENOUGH_MEMORY\n");
|
||
#endif
|
||
if (DfsEventLog > 1) {
|
||
LogWriteMessage(
|
||
NET_DFS_ENUM,
|
||
ERROR_NOT_ENOUGH_MEMORY,
|
||
0,
|
||
NULL);
|
||
}
|
||
status = ERROR_NOT_ENOUGH_MEMORY;
|
||
goto cleanup;
|
||
|
||
}
|
||
|
||
//
|
||
// Now, we sit in a loop and get the info
|
||
//
|
||
|
||
for (i = 0, cbTotalSize = 0, status = NERR_Success;
|
||
(i < cEntriesToRead) &&
|
||
(cbTotalSize < PrefMaxLen);
|
||
i++) {
|
||
|
||
status = DfspGetOneEnumInfo(
|
||
i,
|
||
Level,
|
||
pBuffer,
|
||
&cbOneInfoSize,
|
||
ResumeHandle);
|
||
#if DBG
|
||
if (DfsSvcVerbose)
|
||
DbgPrint("DfspGetOneEnumInfo returned %d\n", status);
|
||
#endif
|
||
|
||
if (status == ERROR_NO_MORE_ITEMS || status != NERR_Success)
|
||
break;
|
||
|
||
cbTotalSize += (cbInfoSize + cbOneInfoSize);
|
||
|
||
cbOneInfoSize = 0;
|
||
|
||
}
|
||
|
||
if (status == NERR_Success || status == ERROR_NO_MORE_ITEMS) {
|
||
|
||
DfsEnum->Level = Level;
|
||
|
||
DfsEnum->DfsInfoContainer.DfsInfo1Container->EntriesRead = i;
|
||
|
||
if (i > 0) {
|
||
|
||
DfsEnum->DfsInfoContainer.DfsInfo1Container->Buffer =
|
||
(LPDFS_INFO_1) pBuffer;
|
||
|
||
status = ERROR_SUCCESS;
|
||
|
||
} else {
|
||
|
||
DfsEnum->DfsInfoContainer.DfsInfo1Container->Buffer = NULL;
|
||
|
||
MIDL_user_free( pBuffer );
|
||
|
||
}
|
||
|
||
} else {
|
||
|
||
for (; i > 0; i--) {
|
||
|
||
DfspFreeOneEnumInfo(i-1, Level, pBuffer);
|
||
|
||
//
|
||
// 333596. Fix memory leak.
|
||
//
|
||
MIDL_user_free( pBuffer );
|
||
|
||
}
|
||
|
||
}
|
||
|
||
if (ulDfsManagerType == DFS_MANAGER_FTDFS)
|
||
status = LdapDecrementBlob();
|
||
|
||
EXIT_DFSM_OPERATION;
|
||
|
||
#if DBG
|
||
if (DfsSvcVerbose)
|
||
DbgPrint("NetrDfsEnum returning %d\n", status);
|
||
#endif
|
||
|
||
if (DfsEventLog > 1) {
|
||
LogWriteMessage(
|
||
NET_DFS_ENUM,
|
||
status,
|
||
0,
|
||
NULL);
|
||
}
|
||
cleanup:
|
||
|
||
DFSM_TRACE_NORM(EVENT, NetrDfsEnum_End,
|
||
LOGSTATUS(status));
|
||
|
||
return( status );
|
||
}
|
||
|
||
//+----------------------------------------------------------------------------
|
||
//
|
||
// Function: NetrDfsEnum200
|
||
//
|
||
// Synopsis: Handles level 200 for NetrDfsEnum, server-side implementation
|
||
//
|
||
// Arguments: [Level] -- The level of info struct desired.
|
||
// [PrefMaxLen] -- Preferred maximum length of output buffer.
|
||
// 0xffffffff means no limit.
|
||
// [DfsEnum] -- DFS_INFO_ENUM_STRUCT pointer where the info
|
||
// structs will be returned.
|
||
// [ResumeHandle] -- If 0, the enumeration will begin from the
|
||
// start. On return, the resume handle will be an opaque
|
||
// cookie that can be passed in on subsequent calls to
|
||
// resume the enumeration.
|
||
//
|
||
// Returns: [NERR_Success] -- Successfully retrieved info.
|
||
//
|
||
// [NERR_DfsInternalCorruption] -- Internal Dfs database is
|
||
// corrupt.
|
||
//
|
||
// [ERROR_INVALID_PARAMETER] -- DfsEnum or ResumeHandle were
|
||
// NULL on entry.
|
||
//
|
||
// [ERROR_INVALID_LEVEL] -- If Level != 200
|
||
//
|
||
// [ERROR_NO_MORE_ITEMS] -- If nothing more to enumerate based
|
||
// on *ResumeHandle value.
|
||
//
|
||
// [ERROR_NOT_ENOUGH_MEMORY] -- If we hit an out of memory
|
||
// condition while constructing info.
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
NET_API_STATUS
|
||
NetrDfsEnum200(
|
||
IN DWORD Level,
|
||
IN DWORD PrefMaxLen,
|
||
IN OUT LPDFS_INFO_ENUM_STRUCT DfsEnum,
|
||
IN OUT LPDWORD ResumeHandle)
|
||
{
|
||
NET_API_STATUS status = ERROR_SUCCESS;
|
||
ULONG i;
|
||
ULONG cEntriesToRead;
|
||
ULONG cEntriesRead;
|
||
ULONG cbInfoSize;
|
||
ULONG cbThisInfoSize;
|
||
ULONG cbTotalSize;
|
||
ULONG cList;
|
||
LPWSTR *List = NULL;
|
||
PDFS_INFO_200 pDfsInfo200;
|
||
PBYTE pBuffer;
|
||
|
||
#if DBG
|
||
if (DfsSvcVerbose)
|
||
DbgPrint("NetrDfsEnum200(%d,%d)\n", Level, PrefMaxLen);
|
||
#endif
|
||
|
||
if (Level != 200) {
|
||
status = ERROR_INVALID_LEVEL;
|
||
DFSM_TRACE_HIGH(ERROR, NetrDfsEnum200_Error1, LOGSTATUS(status));
|
||
goto AllDone;
|
||
}
|
||
|
||
if (pwszDomainName == NULL) {
|
||
status = ERROR_DOMAIN_CONTROLLER_NOT_FOUND;
|
||
DFSM_TRACE_HIGH(ERROR, NetrDfsEnum200_Error2, LOGSTATUS(status));
|
||
goto AllDone;
|
||
}
|
||
|
||
cbInfoSize = sizeof(DFS_INFO_200);
|
||
|
||
//
|
||
// Get the list of FtDfs roots in the domain
|
||
//
|
||
status = DfsGetFtServersFromDs(
|
||
NULL,
|
||
pwszDomainName,
|
||
NULL,
|
||
&List);
|
||
|
||
IDfsVolInlineDebOut((DEB_TRACE, "DfsGetFtServersFromDs returned %d\n", status));
|
||
|
||
if (status != ERROR_SUCCESS)
|
||
goto AllDone;
|
||
|
||
if (List == NULL) {
|
||
status = ERROR_NO_MORE_ITEMS;
|
||
DFSM_TRACE_HIGH(ERROR, NetrDfsEnum200_Error3, LOGSTATUS(status));
|
||
goto AllDone;
|
||
}
|
||
|
||
//
|
||
// Build the results array
|
||
//
|
||
if (status == NOERROR) {
|
||
|
||
status = NERR_Success;
|
||
|
||
//
|
||
// Count # entries returned
|
||
//
|
||
for (cList = 0; List[cList]; cList++) {
|
||
NOTHING;
|
||
}
|
||
|
||
#if DBG
|
||
if (DfsSvcVerbose) {
|
||
DbgPrint("List has %d items\n", cList);
|
||
for (i = 0; i < cList; i++)
|
||
DbgPrint("%d: %ws\n", i, List[i]);
|
||
}
|
||
#endif
|
||
|
||
if (*ResumeHandle >= cList) {
|
||
status = ERROR_NO_MORE_ITEMS;
|
||
DFSM_TRACE_HIGH(ERROR, NetrDfsEnum200_Error4, LOGSTATUS(status));
|
||
goto AllDone;
|
||
|
||
}
|
||
|
||
//
|
||
// Size & allocate the results array
|
||
//
|
||
if (PrefMaxLen == ~0) {
|
||
|
||
cEntriesToRead = cList;
|
||
|
||
} else {
|
||
|
||
cEntriesToRead = min(cList, PrefMaxLen / cbInfoSize);
|
||
|
||
}
|
||
|
||
pBuffer = (LPBYTE) MIDL_user_allocate(cEntriesToRead * cbInfoSize);
|
||
|
||
if (pBuffer == NULL) {
|
||
|
||
status = ERROR_NOT_ENOUGH_MEMORY;
|
||
DFSM_TRACE_HIGH(ERROR, NetrDfsEnum200_Error5, LOGSTATUS(status));
|
||
|
||
}
|
||
|
||
}
|
||
|
||
//
|
||
// Load the results array, starting at the resume handle
|
||
//
|
||
if (status == NERR_Success) {
|
||
|
||
pDfsInfo200 = (LPDFS_INFO_200)pBuffer;
|
||
cbTotalSize = cEntriesRead = 0;
|
||
|
||
for (i = *ResumeHandle; (i < cEntriesToRead) && (status == NERR_Success); i++) {
|
||
|
||
cbThisInfoSize = (wcslen(List[i]) + 1) * sizeof(WCHAR);
|
||
|
||
//
|
||
// Quit if this element would cause us to exceed PrefmaxLen
|
||
//
|
||
if (cbTotalSize + cbInfoSize + cbThisInfoSize > PrefMaxLen) {
|
||
|
||
break;
|
||
|
||
}
|
||
|
||
pDfsInfo200->FtDfsName = (LPWSTR) MIDL_user_allocate(cbThisInfoSize);
|
||
|
||
if (pDfsInfo200 != NULL) {
|
||
|
||
wcscpy(pDfsInfo200->FtDfsName, List[i]);
|
||
cbTotalSize += cbInfoSize + cbThisInfoSize;
|
||
|
||
} else {
|
||
|
||
status = ERROR_NOT_ENOUGH_MEMORY;
|
||
DFSM_TRACE_HIGH(ERROR, NetrDfsEnum200_Error6, LOGSTATUS(status));
|
||
|
||
}
|
||
|
||
pDfsInfo200++;
|
||
cEntriesRead++;
|
||
|
||
}
|
||
|
||
*ResumeHandle = i;
|
||
|
||
}
|
||
|
||
if (status == NERR_Success) {
|
||
|
||
//
|
||
// Everything worked
|
||
//
|
||
|
||
DfsEnum->Level = Level;
|
||
DfsEnum->DfsInfoContainer.DfsInfo1Container->EntriesRead = cEntriesRead;
|
||
|
||
if (cEntriesRead > 0) {
|
||
|
||
DfsEnum->DfsInfoContainer.DfsInfo1Container->Buffer = (LPDFS_INFO_1) pBuffer;
|
||
status = ERROR_SUCCESS;
|
||
|
||
} else {
|
||
|
||
DfsEnum->DfsInfoContainer.DfsInfo1Container->Buffer = NULL;
|
||
|
||
MIDL_user_free( pBuffer );
|
||
|
||
}
|
||
|
||
} else {
|
||
|
||
//
|
||
// We're going to return an error, so free all the MIDL_user_allocate's
|
||
// we made to hold FtDfsName's
|
||
//
|
||
for (i = cEntriesRead; i > 0; i--) {
|
||
|
||
pDfsInfo200 = (LPDFS_INFO_200) (pBuffer + (i-1) * sizeof(DFS_INFO_200));
|
||
|
||
if (pDfsInfo200->FtDfsName != NULL) {
|
||
|
||
MIDL_user_free(pDfsInfo200->FtDfsName);
|
||
|
||
}
|
||
|
||
}
|
||
|
||
MIDL_user_free( pBuffer );
|
||
|
||
}
|
||
|
||
NetApiBufferFree( List );
|
||
|
||
AllDone:
|
||
|
||
#if DBG
|
||
if (DfsSvcVerbose)
|
||
DbgPrint("NetrDfsEnum200 returning %d\n", status);
|
||
#endif
|
||
|
||
return status;
|
||
|
||
}
|
||
|
||
|
||
//+----------------------------------------------------------------------------
|
||
//
|
||
// Function: NetrDfsEnumEx
|
||
//
|
||
// Synopsis: The DC implementation of the NetDfsEnum public API
|
||
//
|
||
// Arguments: [DfsName] -- The Dfs to enumerate (\\domainname\ftdfsname)
|
||
// [Level] -- The level of info struct desired.
|
||
// [PrefMaxLen] -- Preferred maximum length of output buffer.
|
||
// 0xffffffff means no limit.
|
||
// [DfsEnum] -- DFS_INFO_ENUM_STRUCT pointer where the info
|
||
// structs will be returned.
|
||
// [ResumeHandle] -- If 0, the enumeration will begin from the
|
||
// start. On return, the resume handle will be an opaque
|
||
// cookie that can be passed in on subsequent calls to
|
||
// resume the enumeration.
|
||
//
|
||
// Returns: [NERR_Success] -- Successfully retrieved info.
|
||
//
|
||
// [NERR_DfsInternalCorruption] -- Internal Dfs database is
|
||
// corrupt.
|
||
//
|
||
// [ERROR_INVALID_PARAMETER] -- DfsEnum or ResumeHandle were
|
||
// NULL on entry.
|
||
//
|
||
// [ERROR_INVALID_LEVEL] -- If Level != 1,2, 4 or 200
|
||
//
|
||
// [ERROR_NO_MORE_ITEMS] -- If nothing more to enumerate based
|
||
// on *ResumeHandle value.
|
||
//
|
||
// [ERROR_NOT_ENOUGH_MEMORY] -- If we hit an out of memory
|
||
// condition while constructing info.
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
|
||
extern "C" NET_API_STATUS
|
||
NetrDfsEnumEx(
|
||
IN LPWSTR DfsName,
|
||
IN DWORD Level,
|
||
IN DWORD PrefMaxLen,
|
||
IN OUT LPDFS_INFO_ENUM_STRUCT DfsEnum,
|
||
IN OUT LPDWORD ResumeHandle)
|
||
{
|
||
DWORD dwErr = ERROR_SUCCESS;
|
||
DFS_VOLUME_LIST DfsVolList;
|
||
ULONG cbBlob = 0;
|
||
BYTE *pBlob = NULL;
|
||
LPWSTR wszFtDfsName;
|
||
|
||
DWORD i;
|
||
DWORD cEntriesToRead;
|
||
DWORD cbInfoSize;
|
||
DWORD cbOneInfoSize;
|
||
DWORD cbTotalSize;
|
||
LPBYTE pBuffer;
|
||
|
||
DFSM_TRACE_NORM(EVENT, NetrDfsEnumEx_Start,
|
||
LOGSTATUS(dwErr)
|
||
LOGWSTR(DfsName));
|
||
|
||
IDfsVolInlineDebOut((DEB_TRACE, "NetrDfsEnumEx(%ws,%d)\n", DfsName, Level));
|
||
|
||
#if DBG
|
||
if (DfsSvcVerbose)
|
||
DbgPrint("NetrDfsEnumEx(%ws,%d,0x%x)\n",
|
||
DfsName,
|
||
Level,
|
||
PrefMaxLen);
|
||
#endif
|
||
|
||
RtlZeroMemory(&DfsVolList, sizeof(DFS_VOLUME_LIST));
|
||
|
||
//
|
||
// Validate the Out parameters
|
||
//
|
||
|
||
if (DfsEnum == NULL
|
||
||
|
||
DfsEnum->DfsInfoContainer.DfsInfo1Container == NULL
|
||
||
|
||
ResumeHandle == NULL
|
||
) {
|
||
#if DBG
|
||
if (DfsSvcVerbose)
|
||
DbgPrint("NetrDfsEnumEx returning ERROR_INVALID_PARAMETER\n");
|
||
#endif
|
||
if (DfsEventLog > 1) {
|
||
LogWriteMessage(
|
||
NET_DFS_ENUMEX,
|
||
ERROR_INVALID_PARAMETER,
|
||
0,
|
||
NULL);
|
||
}
|
||
dwErr = ERROR_INVALID_PARAMETER;
|
||
goto cleanup;
|
||
}
|
||
|
||
//
|
||
// Validate the Info Level...
|
||
//
|
||
if (!(Level >= 1 && Level <= 4) && Level != 200) {
|
||
#if DBG
|
||
if (DfsSvcVerbose)
|
||
DbgPrint("NetrDfsEnumEx returning ERROR_INVALID_LEVEL\n");
|
||
#endif
|
||
if (DfsEventLog > 1) {
|
||
LogWriteMessage(
|
||
NET_DFS_ENUMEX,
|
||
ERROR_INVALID_LEVEL,
|
||
0,
|
||
NULL);
|
||
}
|
||
dwErr = ERROR_INVALID_LEVEL;
|
||
goto cleanup;
|
||
}
|
||
|
||
ENTER_DFSM_OPERATION;
|
||
|
||
//
|
||
// Handle level 200 as a special case
|
||
//
|
||
|
||
if (Level == 200) {
|
||
|
||
dwErr = NetrDfsEnum200(
|
||
Level,
|
||
PrefMaxLen,
|
||
DfsEnum,
|
||
ResumeHandle);
|
||
|
||
#if DBG
|
||
if (DfsSvcVerbose)
|
||
DbgPrint("NetrDfsEnum200 returned %d\n", dwErr);
|
||
#endif
|
||
goto Cleanup;
|
||
|
||
}
|
||
|
||
for (wszFtDfsName = DfsName;
|
||
*wszFtDfsName != UNICODE_PATH_SEP && *wszFtDfsName != UNICODE_NULL;
|
||
wszFtDfsName++) {
|
||
NOTHING;
|
||
}
|
||
|
||
if (*wszFtDfsName != UNICODE_PATH_SEP) {
|
||
dwErr = ERROR_INVALID_PARAMETER;
|
||
goto Cleanup;
|
||
}
|
||
|
||
wszFtDfsName++;
|
||
|
||
if (*wszFtDfsName == UNICODE_NULL) {
|
||
dwErr = ERROR_INVALID_PARAMETER;
|
||
goto Cleanup;
|
||
}
|
||
|
||
//
|
||
// Get blob from Ds
|
||
//
|
||
dwErr = DfsGetDsBlob(
|
||
wszFtDfsName,
|
||
pwszComputerName,
|
||
&cbBlob,
|
||
&pBlob);
|
||
|
||
if (dwErr != ERROR_SUCCESS)
|
||
goto Cleanup;
|
||
|
||
//
|
||
// Unserialize it
|
||
//
|
||
dwErr = DfsGetVolList(
|
||
cbBlob,
|
||
pBlob,
|
||
&DfsVolList);
|
||
|
||
if (dwErr != ERROR_SUCCESS)
|
||
goto Cleanup;
|
||
|
||
#if DBG
|
||
if (DfsSvcVerbose)
|
||
DfsDumpVolList(&DfsVolList);
|
||
#endif
|
||
|
||
|
||
//
|
||
// Sanity check the ResumeHandle...
|
||
//
|
||
|
||
if ((*ResumeHandle) >= DfsVolList.VolCount) {
|
||
|
||
dwErr = ERROR_NO_MORE_ITEMS;
|
||
goto Cleanup;
|
||
|
||
}
|
||
|
||
switch (Level) {
|
||
case 1:
|
||
cbInfoSize = sizeof(DFS_INFO_1);
|
||
break;
|
||
|
||
case 2:
|
||
cbInfoSize = sizeof(DFS_INFO_2);
|
||
break;
|
||
|
||
case 3:
|
||
cbInfoSize = sizeof(DFS_INFO_3);
|
||
break;
|
||
|
||
case 4:
|
||
cbInfoSize = sizeof(DFS_INFO_4);
|
||
break;
|
||
|
||
default:
|
||
ASSERT(FALSE && "Invalid Info Level");
|
||
break;
|
||
}
|
||
|
||
if (PrefMaxLen == ~0) {
|
||
|
||
cEntriesToRead = DfsVolList.VolCount;
|
||
|
||
} else {
|
||
|
||
cEntriesToRead = min(DfsVolList.VolCount, PrefMaxLen/cbInfoSize);
|
||
|
||
}
|
||
|
||
#if DBG
|
||
if (DfsSvcVerbose)
|
||
DbgPrint("NetrDfsEnumEx: cEntriesToRead = %d\n", cEntriesToRead);
|
||
#endif
|
||
|
||
|
||
pBuffer = (LPBYTE) MIDL_user_allocate( cEntriesToRead * cbInfoSize );
|
||
|
||
if (pBuffer == NULL) {
|
||
|
||
dwErr = ERROR_NOT_ENOUGH_MEMORY;
|
||
goto Cleanup;
|
||
|
||
}
|
||
|
||
//
|
||
// Now, we sit in a loop and get the info
|
||
//
|
||
|
||
for (i = 0, cbTotalSize = 0, dwErr = ERROR_SUCCESS;
|
||
(i < cEntriesToRead) && (cbTotalSize < PrefMaxLen);
|
||
i++
|
||
) {
|
||
|
||
dwErr = DfspGetOneEnumInfoEx(
|
||
&DfsVolList,
|
||
i,
|
||
Level,
|
||
pBuffer,
|
||
&cbOneInfoSize);
|
||
|
||
if (dwErr == ERROR_NO_MORE_ITEMS || dwErr != ERROR_SUCCESS)
|
||
break;
|
||
|
||
cbTotalSize += cbInfoSize + cbOneInfoSize;
|
||
cbOneInfoSize = 0;
|
||
|
||
}
|
||
|
||
if (dwErr == ERROR_SUCCESS || dwErr == ERROR_NO_MORE_ITEMS) {
|
||
|
||
DfsEnum->Level = Level;
|
||
DfsEnum->DfsInfoContainer.DfsInfo1Container->EntriesRead = cEntriesToRead;
|
||
|
||
if (i > 0) {
|
||
|
||
DfsEnum->DfsInfoContainer.DfsInfo1Container->Buffer = (LPDFS_INFO_1) pBuffer;
|
||
dwErr = ERROR_SUCCESS;
|
||
|
||
} else {
|
||
|
||
DfsEnum->DfsInfoContainer.DfsInfo1Container->Buffer = NULL;
|
||
MIDL_user_free( pBuffer );
|
||
|
||
}
|
||
|
||
} else {
|
||
|
||
for (; i > 0; i--) {
|
||
|
||
DfspFreeOneEnumInfo(i-1, Level, pBuffer);
|
||
|
||
}
|
||
|
||
}
|
||
|
||
Cleanup:
|
||
|
||
EXIT_DFSM_OPERATION;
|
||
|
||
if (pBlob != NULL)
|
||
free(pBlob);
|
||
|
||
if (DfsVolList.VolCount > 0 && DfsVolList.Volumes != NULL)
|
||
DfsFreeVolList(&DfsVolList);
|
||
|
||
#if DBG
|
||
if (DfsSvcVerbose & 0x80000000) {
|
||
DbgPrint("===============\n");
|
||
DbgPrint("Level: %d\n", DfsEnum->Level);
|
||
DbgPrint("EntriesRead=%d\n", DfsEnum->DfsInfoContainer.DfsInfo1Container->EntriesRead);
|
||
for (i = 0; i < DfsEnum->DfsInfoContainer.DfsInfo1Container->EntriesRead; i++) {
|
||
if (Level == 1) {
|
||
DbgPrint("Entry %d: %ws\n",
|
||
i+1,
|
||
DfsEnum->DfsInfoContainer.DfsInfo1Container->Buffer[i].EntryPath);
|
||
} else if (Level == 3) {
|
||
DbgPrint("Entry %d: %ws\n",
|
||
i+1,
|
||
DfsEnum->DfsInfoContainer.DfsInfo3Container->Buffer[i].EntryPath);
|
||
}
|
||
if (Level == 3) {
|
||
ULONG j;
|
||
DbgPrint("\tComment: [%ws]\n",
|
||
DfsEnum->DfsInfoContainer.DfsInfo3Container->Buffer[i].Comment,
|
||
DfsEnum->DfsInfoContainer.DfsInfo3Container->Buffer[i].State,
|
||
DfsEnum->DfsInfoContainer.DfsInfo3Container->Buffer[i].NumberOfStorages);
|
||
for (j = 0;
|
||
j < DfsEnum->DfsInfoContainer.DfsInfo3Container->Buffer[i].NumberOfStorages;
|
||
j++
|
||
) {
|
||
DbgPrint("\t\t[0x%x][\\\\%ws\\%ws]\n",
|
||
DfsEnum->DfsInfoContainer.DfsInfo3Container->Buffer[i].Storage[j].State,
|
||
DfsEnum->DfsInfoContainer.DfsInfo3Container->Buffer[i].Storage[j].ServerName,
|
||
DfsEnum->DfsInfoContainer.DfsInfo3Container->Buffer[i].Storage[j].ShareName);
|
||
}
|
||
}
|
||
}
|
||
DbgPrint("===============\n");
|
||
}
|
||
|
||
if (DfsSvcVerbose)
|
||
DbgPrint("NetrDfsEnumEx returning %d\n", dwErr);
|
||
#endif
|
||
|
||
if (DfsEventLog > 1) {
|
||
LogWriteMessage(
|
||
NET_DFS_ENUMEX,
|
||
dwErr,
|
||
0,
|
||
NULL);
|
||
}
|
||
cleanup:
|
||
DFSM_TRACE_NORM(EVENT, NetrDfsEnumEx_End,
|
||
LOGSTATUS(dwErr)
|
||
LOGWSTR(DfsName));
|
||
|
||
return( dwErr );
|
||
}
|
||
|
||
|
||
//+----------------------------------------------------------------------------
|
||
//
|
||
// Function: NetrDfsMove
|
||
//
|
||
// Synopsis: Moves a leaf volume to a different parent.
|
||
//
|
||
// Arguments: [DfsEntryPath] -- Current entry path of Dfs volume.
|
||
//
|
||
// [NewEntryPath] -- New entry path of Dfs volume.
|
||
//
|
||
// Returns:
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
|
||
extern "C" NET_API_STATUS
|
||
NetrDfsMove(
|
||
IN LPWSTR DfsEntryPath,
|
||
IN LPWSTR NewDfsEntryPath)
|
||
{
|
||
NET_API_STATUS status = ERROR_NOT_SUPPORTED;
|
||
CDfsVolume *pDfsVol = NULL;
|
||
LPWSTR OrgDfsEntryPath = DfsEntryPath;
|
||
LPWSTR OrgNewDfsEntryPath = NewDfsEntryPath;
|
||
|
||
DFSM_TRACE_NORM(EVENT, NetrDfsMove_Start,
|
||
LOGSTATUS(status)
|
||
LOGWSTR(DfsEntryPath)
|
||
LOGWSTR(NewDfsEntryPath));
|
||
|
||
if (!AccessCheckRpcClient())
|
||
status = ERROR_ACCESS_DENIED;
|
||
|
||
DFSM_TRACE_NORM(EVENT, NetrDfsMove_End,
|
||
LOGSTATUS(status)
|
||
LOGWSTR(DfsEntryPath)
|
||
LOGWSTR(NewDfsEntryPath));
|
||
|
||
return( status );
|
||
|
||
}
|
||
|
||
|
||
//+----------------------------------------------------------------------------
|
||
//
|
||
// Function: NetrDfsRename
|
||
//
|
||
// Synopsis: Moves a leaf volume to a different parent.
|
||
//
|
||
// Arguments: [Path] -- Current path along the entry path of a Dfs volume.
|
||
//
|
||
// [NewPath] -- New path for current path.
|
||
//
|
||
// Returns:
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
|
||
extern "C" NET_API_STATUS
|
||
NetrDfsRename(
|
||
IN LPWSTR Path,
|
||
IN LPWSTR NewPath)
|
||
{
|
||
NET_API_STATUS status = ERROR_NOT_SUPPORTED;
|
||
CDfsVolume *pDfsVol;
|
||
LPWSTR OrgPath = Path;
|
||
LPWSTR OrgNewPath = NewPath;
|
||
|
||
DFSM_TRACE_NORM(EVENT, NetrDfsRename_Start,
|
||
LOGSTATUS(status)
|
||
LOGWSTR(Path)
|
||
LOGWSTR(NewPath));
|
||
|
||
if (!AccessCheckRpcClient())
|
||
status = ERROR_ACCESS_DENIED;
|
||
|
||
DFSM_TRACE_NORM(EVENT, NetrDfsRename_End,
|
||
LOGSTATUS(status)
|
||
LOGWSTR(Path)
|
||
LOGWSTR(NewPath));
|
||
|
||
return( status );
|
||
|
||
}
|
||
|
||
//+----------------------------------------------------------------------------
|
||
//
|
||
// Function: NetrDfsManagerGetConfigInfo
|
||
//
|
||
// Synopsis: RPC Interface method that returns the config info for a
|
||
// Dfs volume for a given server
|
||
//
|
||
// Arguments: [wszServer] -- Name of server requesting the info. This
|
||
// server is assumed to be requesting the info for
|
||
// verification of its local volume knowledge.
|
||
// [wszLocalVolumeEntryPath] -- Entry path of local volume.
|
||
// [idLocalVolume] -- The guid of the local volume.
|
||
// [ppRelationInfo] -- The relation info is allocated and
|
||
// returned here.
|
||
//
|
||
// Returns: [ERROR_SUCCESS] -- Successfully returning relation info
|
||
//
|
||
// [NERR_DfsNoSuchVolume] -- Did not find LocalVolumeEntryPath
|
||
//
|
||
// [NERR_DfsNoSuchShare] -- The server name passed in does not
|
||
// support this local volume.
|
||
//
|
||
// [ERROR_NOT_ENOUGH_MEMORY] -- Unable to allocate memory for info.
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
|
||
extern "C" DWORD
|
||
NetrDfsManagerGetConfigInfo(
|
||
IN LPWSTR wszServer,
|
||
IN LPWSTR wszLocalVolumeEntryPath,
|
||
IN GUID idLocalVolume,
|
||
OUT LPDFSM_RELATION_INFO *ppRelationInfo)
|
||
{
|
||
DWORD dwErr = ERROR_SUCCESS;
|
||
DFS_PKT_ENTRY_ID EntryId;
|
||
DFS_PKT_RELATION_INFO DfsRelationInfo;
|
||
CDfsVolume *pDfsVol;
|
||
|
||
#if DBG
|
||
if (DfsSvcVerbose)
|
||
DbgPrint("NetrDfsManagerGetConfigInfo(%ws,%ws)\n",
|
||
wszServer,
|
||
wszLocalVolumeEntryPath);
|
||
#endif
|
||
|
||
DFSM_TRACE_NORM(EVENT, NetrDfsManagerGetConfigInfo_Start,
|
||
LOGSTATUS(dwErr)
|
||
LOGWSTR(wszServer)
|
||
LOGWSTR(wszLocalVolumeEntryPath));
|
||
|
||
if (ppRelationInfo == NULL) {
|
||
|
||
dwErr = ERROR_INVALID_PARAMETER;
|
||
goto cleanup;
|
||
|
||
}
|
||
|
||
ENTER_DFSM_OPERATION;
|
||
|
||
EntryId.Uid = idLocalVolume;
|
||
|
||
RtlInitUnicodeString( &EntryId.Prefix, wszLocalVolumeEntryPath );
|
||
|
||
EntryId.ShortPrefix.Length = EntryId.ShortPrefix.MaximumLength = 0;
|
||
EntryId.ShortPrefix.Buffer = NULL;
|
||
|
||
dwErr = GetPktCacheRelationInfo( &EntryId, &DfsRelationInfo );
|
||
|
||
if (dwErr == ERROR_SUCCESS) {
|
||
|
||
//
|
||
// Well, we have the relation info, see if this server is a valid
|
||
// server for this volume.
|
||
//
|
||
|
||
dwErr = GetDfsVolumeFromPath( wszLocalVolumeEntryPath, TRUE, &pDfsVol );
|
||
|
||
if (dwErr == ERROR_SUCCESS) {
|
||
|
||
if ( pDfsVol->IsValidService(wszServer) ) {
|
||
|
||
dwErr = DfspAllocateRelationInfo(
|
||
&DfsRelationInfo,
|
||
ppRelationInfo );
|
||
|
||
} else {
|
||
|
||
dwErr = NERR_DfsNoSuchShare;
|
||
|
||
}
|
||
|
||
pDfsVol->Release();
|
||
|
||
} else {
|
||
|
||
dwErr = NERR_DfsNoSuchVolume;
|
||
|
||
}
|
||
|
||
DeallocateCacheRelationInfo( DfsRelationInfo );
|
||
|
||
} else {
|
||
|
||
dwErr = NERR_DfsInternalError;
|
||
|
||
}
|
||
|
||
EXIT_DFSM_OPERATION;
|
||
cleanup:
|
||
#if DBG
|
||
if (DfsSvcVerbose)
|
||
DbgPrint("NetrDfsManagerGetConfigInfo returning %d\n", dwErr);
|
||
#endif
|
||
DFSM_TRACE_NORM(EVENT, NetrDfsManagerGetConfigInfo_End,
|
||
LOGSTATUS(dwErr)
|
||
LOGWSTR(wszServer)
|
||
LOGWSTR(wszLocalVolumeEntryPath));
|
||
|
||
return( dwErr );
|
||
|
||
}
|
||
|
||
//+----------------------------------------------------------------------------
|
||
//
|
||
// Function: NetrDfsManagerSendSiteInfo
|
||
//
|
||
// Synopsis: RPC Interface method that reports the site information for a
|
||
// Dfs storage server.
|
||
//
|
||
// Arguments: [wszServer] -- Name of server sending the info.
|
||
// [pSiteInfo] -- The site info is here.
|
||
//
|
||
// Returns: [ERROR_SUCCESS] -- Successfull
|
||
//
|
||
// [ERROR_NOT_ENOUGH_MEMORY] -- Unable to allocate memory for info.
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
|
||
extern "C" DWORD
|
||
NetrDfsManagerSendSiteInfo(
|
||
IN LPWSTR wszServer,
|
||
IN LPDFS_SITELIST_INFO pSiteInfo)
|
||
{
|
||
DWORD dwErr = ERROR_SUCCESS;
|
||
ULONG i;
|
||
|
||
DFSM_TRACE_NORM(EVENT, NetrDfsManagerSendSiteInfo_Start,
|
||
LOGSTATUS(dwErr)
|
||
LOGWSTR(wszServer));
|
||
|
||
if (!AccessCheckRpcClient()) {
|
||
dwErr = ERROR_ACCESS_DENIED;
|
||
goto cleanup;
|
||
}
|
||
|
||
ENTER_DFSM_OPERATION;
|
||
|
||
//
|
||
// Update the Site table
|
||
//
|
||
|
||
IDfsVolInlineDebOut((DEB_TRACE, "NetrDfsGetInfo()\n", 0));
|
||
|
||
pDfsmSites->AddRef();
|
||
dwErr = pDfsmSites->AddOrUpdateSiteInfo(
|
||
wszServer,
|
||
pSiteInfo->cSites,
|
||
&pSiteInfo->Site[0]);
|
||
pDfsmSites->Release();
|
||
|
||
EXIT_DFSM_OPERATION;
|
||
cleanup:
|
||
DFSM_TRACE_NORM(EVENT, NetrDfsManagerSendSiteInfo_End,
|
||
LOGSTATUS(dwErr)
|
||
LOGWSTR(wszServer));
|
||
|
||
return( dwErr );
|
||
|
||
}
|
||
|
||
//+----------------------------------------------------------------------------
|
||
//
|
||
// Function: NetrDfsManagerInitialize
|
||
//
|
||
// Synopsis: Reinitializes the service
|
||
//
|
||
// Arguments: [ServerName] -- Name of server
|
||
// [Flags] -- Flags for the operation
|
||
//
|
||
// Returns: [NERR_Success] -- Operation succeeded.
|
||
//
|
||
// [ERROR_OUTOFMEMORY] -- Out of memory condition.
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
|
||
extern "C" NET_API_STATUS
|
||
NetrDfsManagerInitialize(
|
||
IN LPWSTR ServerName,
|
||
IN DWORD Flags)
|
||
{
|
||
DWORD dwErr = ERROR_SUCCESS;
|
||
|
||
DFSM_TRACE_NORM(EVENT, NetrDfsManagerInitialize_Start,
|
||
LOGSTATUS(dwErr)
|
||
LOGWSTR(ServerName));
|
||
#if DBG
|
||
if (DfsSvcVerbose)
|
||
DbgPrint("NetrDfsManagerInitialize(%ws,%d)\n",
|
||
ServerName,
|
||
Flags);
|
||
#endif
|
||
|
||
if (!AccessCheckRpcClient()) {
|
||
dwErr = ERROR_ACCESS_DENIED;
|
||
goto cleanup;
|
||
}
|
||
|
||
ENTER_DFSM_OPERATION;
|
||
|
||
#if DBG
|
||
GetDebugSwitches();
|
||
#endif
|
||
GetConfigSwitches();
|
||
|
||
//
|
||
// If we are a DomDfs, simply doing the LdapIncrementBlob will
|
||
// be enough. If the DS blob has changed, then we will note that
|
||
// and fully reinitialize everything.
|
||
//
|
||
|
||
if (ulDfsManagerType == DFS_MANAGER_FTDFS) {
|
||
LdapIncrementBlob();
|
||
dwErr = LdapDecrementBlob();
|
||
} else {
|
||
if (pDfsmStorageDirectory != NULL)
|
||
delete pDfsmStorageDirectory;
|
||
if (pDfsmSites != NULL)
|
||
delete pDfsmSites;
|
||
pDfsmSites = new CSites(LDAP_VOLUMES_DIR SITE_ROOT, &dwErr);
|
||
pDfsmStorageDirectory = new CStorageDirectory( &dwErr );
|
||
DfsmMarkStalePktEntries();
|
||
InitializeDfsManager();
|
||
DfsmFlushStalePktEntries();
|
||
}
|
||
|
||
DfsmPktFlushCache();
|
||
|
||
EXIT_DFSM_OPERATION;
|
||
|
||
dwErr = NERR_Success;
|
||
cleanup:
|
||
#if DBG
|
||
if (DfsSvcVerbose)
|
||
DbgPrint("NetrDfsManagerInitialize returning %d\n", dwErr);
|
||
#endif
|
||
DFSM_TRACE_NORM(EVENT, NetrDfsManagerInitialize_End,
|
||
LOGSTATUS(dwErr)
|
||
LOGWSTR(ServerName));
|
||
|
||
return dwErr;
|
||
|
||
}
|
||
|
||
//+----------------------------------------------------------------------------
|
||
//
|
||
// Function: DfspGetOneEnumInfo
|
||
//
|
||
// Synopsis: Helper routine to read one info dfs info into an enum array.
|
||
//
|
||
// Arguments: [i] -- Index of the array element to fill.
|
||
// [Level] -- Info Level to fill with.
|
||
// [InfoArray] -- The array to use; only the ith member will be
|
||
// filled.
|
||
// [InfoSize] -- On successful return, size in bytes of info.
|
||
// [ResumeHandle] -- Handle to indicate the information to fill.
|
||
//
|
||
// Returns:
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
|
||
NET_API_STATUS
|
||
DfspGetOneEnumInfo(
|
||
DWORD i,
|
||
DWORD Level,
|
||
LPBYTE InfoArray,
|
||
LPDWORD InfoSize,
|
||
LPDWORD ResumeHandle)
|
||
{
|
||
NET_API_STATUS status;
|
||
LPWSTR wszObject;
|
||
CDfsVolume *pDfsVolume;
|
||
LPDFS_INFO_3 pDfsInfo;
|
||
|
||
//
|
||
// Get the object name for the object indicated in ResumeHandle. i == 0
|
||
// means that this is the first time this function is being called for
|
||
// this enum, so we are forced to get object name by index. If i > 0, then
|
||
// we can get the object name by using the "get next" capability of
|
||
// CStorageDirectory::GetObjectByIndex.
|
||
//
|
||
|
||
if (pDfsmStorageDirectory == NULL) {
|
||
|
||
return(ERROR_NO_MORE_ITEMS);
|
||
|
||
}
|
||
|
||
if (i == 0) {
|
||
|
||
status = pDfsmStorageDirectory->GetObjectByIndex(*ResumeHandle, &wszObject);
|
||
|
||
} else {
|
||
|
||
status = pDfsmStorageDirectory->GetObjectByIndex((DWORD)~0, &wszObject);
|
||
|
||
}
|
||
|
||
if (status != ERROR_SUCCESS)
|
||
return( status );
|
||
|
||
#if DBG
|
||
if (DfsSvcVerbose)
|
||
DbgPrint("DfspGetOneEnumInfo(%d,%d)\n", i, Level);
|
||
#endif
|
||
|
||
pDfsVolume = new CDfsVolume();
|
||
|
||
#if DBG
|
||
if (DfsSvcVerbose)
|
||
DbgPrint(" pDfsVolume = 0x%x\n", pDfsVolume);
|
||
#endif
|
||
|
||
if (pDfsVolume != NULL) {
|
||
|
||
status = pDfsVolume->Load(wszObject, 0);
|
||
|
||
#if DBG
|
||
if (DfsSvcVerbose)
|
||
DbgPrint(" pDfsVolume->Load returned %d\n", status);
|
||
#endif
|
||
|
||
if (status == ERROR_SUCCESS) {
|
||
|
||
switch (Level) {
|
||
case 1:
|
||
pDfsInfo = (LPDFS_INFO_3) (InfoArray + i * sizeof(DFS_INFO_1));
|
||
break;
|
||
|
||
case 2:
|
||
pDfsInfo = (LPDFS_INFO_3) (InfoArray + i * sizeof(DFS_INFO_2));
|
||
break;
|
||
|
||
case 3:
|
||
pDfsInfo = (LPDFS_INFO_3) (InfoArray + i * sizeof(DFS_INFO_3));
|
||
break;
|
||
|
||
case 4:
|
||
pDfsInfo = (LPDFS_INFO_3) (InfoArray + i * sizeof(DFS_INFO_4));
|
||
break;
|
||
|
||
default:
|
||
ASSERT( FALSE && "Invalid Info Level" );
|
||
break;
|
||
|
||
}
|
||
|
||
status = pDfsVolume->GetNetInfo(Level, pDfsInfo, InfoSize);
|
||
|
||
#if DBG
|
||
if (DfsSvcVerbose)
|
||
DbgPrint(" pDfsVolume->GetNetInfo returned %d\n", status);
|
||
#endif
|
||
|
||
}
|
||
|
||
pDfsVolume->Release();
|
||
|
||
if (status == ERROR_SUCCESS) {
|
||
|
||
(*ResumeHandle)++;
|
||
|
||
} else {
|
||
|
||
status = NERR_DfsInternalCorruption;
|
||
|
||
DFSM_TRACE_HIGH(ERROR, DfspGetOneEnumInfo_Error1, LOGSTATUS(status));
|
||
}
|
||
|
||
} else {
|
||
|
||
status = ERROR_NOT_ENOUGH_MEMORY;
|
||
DFSM_TRACE_HIGH(ERROR, DfspGetOneEnumInfo_Error2, LOGSTATUS(status));
|
||
|
||
}
|
||
|
||
delete [] wszObject;
|
||
|
||
return( status );
|
||
|
||
}
|
||
|
||
|
||
//+----------------------------------------------------------------------------
|
||
//
|
||
// Function: DfspGetOneEnumInfoEx
|
||
//
|
||
// Synopsis: Helper routine to read one info dfs info into an enum array.
|
||
//
|
||
// Arguments: [pDfsVolList] pointer to DFS_VOLUME_LIST to use
|
||
// [i] -- Index of the array element to fill.
|
||
// [Level] -- Info Level to fill with.
|
||
// [InfoArray] -- The array to use; only the ith member will be
|
||
// filled.
|
||
// [InfoSize] -- On successful return, size in bytes of info.
|
||
//
|
||
// Returns:
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
|
||
DWORD
|
||
DfspGetOneEnumInfoEx(
|
||
PDFS_VOLUME_LIST pDfsVolList,
|
||
DWORD i,
|
||
DWORD Level,
|
||
LPBYTE InfoArray,
|
||
LPDWORD InfoSize)
|
||
{
|
||
DWORD dwErr = ERROR_SUCCESS;
|
||
LPWSTR wszObject;
|
||
LPDFS_INFO_3 pDfsInfo;
|
||
|
||
#if DBG
|
||
if (DfsSvcVerbose)
|
||
DbgPrint("DfspGetOneEnumInfoEx(%d,%d)\n", i, Level);
|
||
#endif
|
||
|
||
if (pDfsVolList == NULL || i >= pDfsVolList->VolCount) {
|
||
|
||
dwErr = ERROR_NO_MORE_ITEMS;
|
||
goto AllDone;
|
||
|
||
}
|
||
|
||
switch (Level) {
|
||
case 1:
|
||
pDfsInfo = (LPDFS_INFO_3) (InfoArray + i * sizeof(DFS_INFO_1));
|
||
break;
|
||
|
||
case 2:
|
||
pDfsInfo = (LPDFS_INFO_3) (InfoArray + i * sizeof(DFS_INFO_2));
|
||
break;
|
||
|
||
case 3:
|
||
pDfsInfo = (LPDFS_INFO_3) (InfoArray + i * sizeof(DFS_INFO_3));
|
||
break;
|
||
|
||
case 4:
|
||
pDfsInfo = (LPDFS_INFO_3) (InfoArray + i * sizeof(DFS_INFO_4));
|
||
break;
|
||
|
||
default:
|
||
// 447489. fix prefix bug.
|
||
return ERROR_INVALID_LEVEL;
|
||
|
||
}
|
||
|
||
dwErr = GetNetInfoEx(&pDfsVolList->Volumes[i], Level, pDfsInfo, InfoSize);
|
||
|
||
AllDone:
|
||
|
||
#if DBG
|
||
if (DfsSvcVerbose)
|
||
DbgPrint("DfspGetOneEnumInfoEx returning %d\n", dwErr);
|
||
#endif
|
||
|
||
return( dwErr );
|
||
|
||
}
|
||
|
||
//+----------------------------------------------------------------------------
|
||
//
|
||
// Function: DfspFreeOneEnumInfo
|
||
//
|
||
// Synopsis: Worker routine to free one DFS_INFO_x struct as allocated
|
||
// by DfspGetOneEnumInfo. Useful for cleanup in case of error.
|
||
//
|
||
// Arguments: [Idx] -- Index of the array element to free.
|
||
// [Level] -- Level of info to free.
|
||
// [InfoArray] -- The array to use; only the members of the ith
|
||
// element will be freed.
|
||
//
|
||
// Returns: Nothing
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
|
||
VOID
|
||
DfspFreeOneEnumInfo(
|
||
DWORD Idx,
|
||
DWORD Level,
|
||
LPBYTE InfoArray)
|
||
{
|
||
LPDFS_INFO_3 pDfsInfo;
|
||
LPDFS_INFO_4 pDfsInfo4;
|
||
ULONG i;
|
||
|
||
switch (Level) {
|
||
case 1:
|
||
pDfsInfo = (LPDFS_INFO_3) (InfoArray + Idx * sizeof(DFS_INFO_1));
|
||
break;
|
||
|
||
case 2:
|
||
pDfsInfo = (LPDFS_INFO_3) (InfoArray + Idx * sizeof(DFS_INFO_2));
|
||
break;
|
||
|
||
case 3:
|
||
pDfsInfo = (LPDFS_INFO_3) (InfoArray + Idx * sizeof(DFS_INFO_3));
|
||
break;
|
||
|
||
case 4:
|
||
pDfsInfo4 = (LPDFS_INFO_4) (InfoArray + Idx * sizeof(DFS_INFO_4));
|
||
break;
|
||
|
||
default:
|
||
//
|
||
// 447480. prefix bug. return if unknown level.
|
||
return;
|
||
|
||
}
|
||
|
||
if (Level == 4) {
|
||
|
||
if (pDfsInfo4->EntryPath != NULL) {
|
||
MIDL_user_free(pDfsInfo4->EntryPath);
|
||
}
|
||
|
||
if (pDfsInfo4->Comment != NULL) {
|
||
MIDL_user_free(pDfsInfo4->Comment);
|
||
}
|
||
|
||
if (pDfsInfo4->Storage != NULL) {
|
||
|
||
for (i = 0; i < pDfsInfo4->NumberOfStorages; i++) {
|
||
|
||
if (pDfsInfo4->Storage[i].ServerName != NULL)
|
||
MIDL_user_free(pDfsInfo4->Storage[i].ServerName);
|
||
|
||
if (pDfsInfo4->Storage[i].ShareName != NULL)
|
||
MIDL_user_free(pDfsInfo4->Storage[i].ShareName);
|
||
|
||
}
|
||
|
||
MIDL_user_free(pDfsInfo4->Storage);
|
||
|
||
}
|
||
|
||
return;
|
||
|
||
}
|
||
|
||
//
|
||
// Cleanup the Level 1 stuff.
|
||
//
|
||
|
||
if (pDfsInfo->EntryPath != NULL)
|
||
MIDL_user_free(pDfsInfo->EntryPath);
|
||
|
||
//
|
||
// Cleanup the Level 2 stuff if needed.
|
||
//
|
||
|
||
if (Level > 1 && pDfsInfo->Comment != NULL)
|
||
MIDL_user_free(pDfsInfo->Comment);
|
||
|
||
//
|
||
// Cleanup the Level 3 stuff if needed.
|
||
//
|
||
|
||
if (Level > 2 && pDfsInfo->Storage != NULL) {
|
||
|
||
for (i = 0; i < pDfsInfo->NumberOfStorages; i++) {
|
||
|
||
if (pDfsInfo->Storage[i].ServerName != NULL)
|
||
MIDL_user_free(pDfsInfo->Storage[i].ServerName);
|
||
|
||
if (pDfsInfo->Storage[i].ShareName != NULL)
|
||
MIDL_user_free(pDfsInfo->Storage[i].ShareName);
|
||
|
||
}
|
||
|
||
MIDL_user_free(pDfsInfo->Storage);
|
||
|
||
}
|
||
|
||
}
|
||
|
||
//+----------------------------------------------------------------------------
|
||
//
|
||
// Function: DfsManagerCreateVolumeObject
|
||
//
|
||
// Synopsis: Bootstrap routine to create a volume object directly (ie,
|
||
// without having to call DfsCreateChildVolume on a parent
|
||
// volume)
|
||
//
|
||
// Arguments: [pwszObjectName] -- Name of the volume object.
|
||
// [pwszPrefix] -- Entry Path of dfs volume.
|
||
// [pwszServer] -- Name of server supporting dfs volume.
|
||
// [pwszShare] -- Name of share on server supporting dfs volume.
|
||
// [pwszComment] -- Comment for dfs volume.
|
||
// [guidVolume] -- Id of dfs volume.
|
||
//
|
||
// Returns:
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
|
||
extern "C" DWORD
|
||
DfsManagerCreateVolumeObject(
|
||
IN LPWSTR pwszObjectName,
|
||
IN LPWSTR pwszPrefix,
|
||
IN LPWSTR pwszServer,
|
||
IN LPWSTR pwszShare,
|
||
IN LPWSTR pwszComment,
|
||
IN GUID *guidVolume)
|
||
{
|
||
DWORD dwErr;
|
||
DWORD dwStatus;
|
||
CDfsVolume *pCDfsVolume;
|
||
DFS_REPLICA_INFO replicaInfo;
|
||
LPDFS_SITELIST_INFO pSiteInfo;
|
||
|
||
pCDfsVolume = new CDfsVolume();
|
||
|
||
if (pCDfsVolume != NULL) {
|
||
|
||
replicaInfo.ulReplicaType = DFS_STORAGE_TYPE_DFS;
|
||
replicaInfo.ulReplicaState = DFS_STORAGE_STATE_ONLINE;
|
||
replicaInfo.pwszServerName = pwszServer;
|
||
replicaInfo.pwszShareName = pwszShare;
|
||
|
||
dwErr = pCDfsVolume->CreateObject(
|
||
pwszObjectName,
|
||
pwszPrefix,
|
||
DFS_VOL_TYPE_DFS | DFS_VOL_TYPE_REFERRAL_SVC,
|
||
&replicaInfo,
|
||
pwszComment,
|
||
guidVolume);
|
||
|
||
//
|
||
// Create the site table object in the DS or registry
|
||
//
|
||
if (ulDfsManagerType == DFS_MANAGER_FTDFS) {
|
||
|
||
dwErr = LdapCreateObject(
|
||
LDAP_VOLUMES_DIR SITE_ROOT);
|
||
|
||
} else {
|
||
|
||
// registry stuff instead
|
||
|
||
dwErr = RegCreateObject(
|
||
VOLUMES_DIR SITE_ROOT);
|
||
}
|
||
|
||
if (dwErr == ERROR_SUCCESS) {
|
||
|
||
//
|
||
// Find out the list of covered sites
|
||
// We continue even if this fails (standalone, no TCP/IP)
|
||
//
|
||
pSiteInfo = NULL;
|
||
|
||
dwStatus = I_NetDfsManagerReportSiteInfo(
|
||
pwszServer,
|
||
&pSiteInfo);
|
||
|
||
DFSM_TRACE_ERROR_HIGH(dwStatus, ALL_ERROR, DfsManagerCreateVolumeObject_Error_I_NetDfsManagerReportSiteInfo,
|
||
LOGSTATUS(dwStatus)
|
||
LOGWSTR(pwszObjectName)
|
||
LOGWSTR(pwszPrefix)
|
||
LOGWSTR(pwszServer)
|
||
LOGWSTR(pwszShare));
|
||
//
|
||
// Create a SiteTable object with those sites
|
||
//
|
||
|
||
if (dwStatus == ERROR_SUCCESS) {
|
||
|
||
if (pSiteInfo->cSites > 0) {
|
||
|
||
//
|
||
// AddRef the site table, then put the site info in, then
|
||
// Release it. This will cause it to be written to the
|
||
// appropriate store (ldap or registry).
|
||
//
|
||
|
||
pDfsmSites->AddRef();
|
||
|
||
pDfsmSites->AddOrUpdateSiteInfo(
|
||
pwszServer,
|
||
pSiteInfo->cSites,
|
||
&pSiteInfo->Site[0]);
|
||
|
||
pDfsmSites->Release();
|
||
|
||
}
|
||
|
||
NetApiBufferFree(pSiteInfo);
|
||
|
||
}
|
||
|
||
}
|
||
|
||
pCDfsVolume->Release();
|
||
|
||
} else {
|
||
|
||
dwErr = ERROR_OUTOFMEMORY;
|
||
|
||
}
|
||
|
||
return( dwErr );
|
||
|
||
}
|
||
|
||
//+----------------------------------------------------------------------------
|
||
//
|
||
// Function: DfsManagerSetDcName
|
||
//
|
||
// Synopsis: Sets the DC we should first attempt to connect to.
|
||
//
|
||
// Arguments: [pwszDCName] -- Name of the DC
|
||
//
|
||
// Returns: ERROR_SUCCESS
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
|
||
extern "C" DWORD
|
||
DfsManagerSetDcName(
|
||
IN LPWSTR pwszDCName)
|
||
{
|
||
if (pwszDSMachineName != NULL) {
|
||
if (wcscmp(pwszDSMachineName, pwszDCName) != 0) {
|
||
wcscpy(wszDSMachineName, pwszDCName);
|
||
pwszDSMachineName = wszDSMachineName;
|
||
if (pLdapConnection != NULL) {
|
||
if (DfsSvcLdap)
|
||
DbgPrint("DfsManagerSetDcName:ldap_unbind()\n");
|
||
ldap_unbind(pLdapConnection);
|
||
pLdapConnection = NULL;
|
||
}
|
||
}
|
||
} else {
|
||
wcscpy(wszDSMachineName, pwszDCName);
|
||
pwszDSMachineName = wszDSMachineName;
|
||
}
|
||
|
||
return ERROR_SUCCESS;
|
||
|
||
}
|
||
|
||
//+----------------------------------------------------------------------------
|
||
//
|
||
// Function: DfsManagerAddService
|
||
//
|
||
// Synopsis: Bootstrap routine for adding a service to an existing volume
|
||
// object. Used to set up additional root servers in an FTDfs
|
||
// setup.
|
||
//
|
||
// Arguments: [pwszFullObjectName] -- Name of the volume object.
|
||
// [pwszServer] -- Name of server to add.
|
||
// [pwszShare] -- Name of share.
|
||
//
|
||
// Returns:
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
|
||
extern "C" DWORD
|
||
DfsManagerAddService(
|
||
IN LPWSTR pwszFullObjectName,
|
||
IN LPWSTR pwszServer,
|
||
IN LPWSTR pwszShare,
|
||
OUT GUID *guidVolume)
|
||
{
|
||
DWORD dwErr;
|
||
DWORD dwStatus;
|
||
CDfsVolume *pCDfsVolume;
|
||
DFS_REPLICA_INFO replicaInfo;
|
||
LPDFS_SITELIST_INFO pSiteInfo;
|
||
|
||
pCDfsVolume = new CDfsVolume();
|
||
|
||
if (pCDfsVolume != NULL) {
|
||
|
||
dwErr = pCDfsVolume->Load( pwszFullObjectName, 0 );
|
||
|
||
if (dwErr == ERROR_SUCCESS) {
|
||
|
||
replicaInfo.ulReplicaType = DFS_STORAGE_TYPE_DFS;
|
||
replicaInfo.ulReplicaState = DFS_STORAGE_STATE_ONLINE;
|
||
replicaInfo.pwszServerName = pwszServer;
|
||
replicaInfo.pwszShareName = pwszShare;
|
||
|
||
dwErr = pCDfsVolume->AddReplicaToObj( &replicaInfo );
|
||
|
||
if (dwErr == ERROR_SUCCESS) {
|
||
|
||
pCDfsVolume->GetObjectID( guidVolume );
|
||
|
||
}
|
||
}
|
||
|
||
if (dwErr == ERROR_SUCCESS) {
|
||
|
||
//
|
||
// Find out the list of covered sites
|
||
// We continue even if this fails (standalone, no TCP/IP)
|
||
//
|
||
pSiteInfo = NULL;
|
||
|
||
dwStatus = I_NetDfsManagerReportSiteInfo(
|
||
pwszServer,
|
||
&pSiteInfo);
|
||
|
||
DFSM_TRACE_ERROR_HIGH(dwStatus, ALL_ERROR, DfsManagerAddService_Error_I_NetDfsManagerReportSiteInfo,
|
||
LOGSTATUS(dwStatus)
|
||
LOGWSTR(pwszFullObjectName)
|
||
LOGWSTR(pwszServer)
|
||
LOGWSTR(pwszShare));
|
||
//
|
||
// Create a SiteTable object with those sites
|
||
//
|
||
|
||
if (dwStatus == ERROR_SUCCESS) {
|
||
|
||
if (pSiteInfo->cSites > 0) {
|
||
|
||
//
|
||
// AddRef the site table, then put the site info in, then
|
||
// Release it. This will cause it to be written to the
|
||
// appropriate store (ldap or registry).
|
||
//
|
||
|
||
pDfsmSites->AddRef();
|
||
|
||
pDfsmSites->AddOrUpdateSiteInfo(
|
||
pwszServer,
|
||
pSiteInfo->cSites,
|
||
&pSiteInfo->Site[0]);
|
||
|
||
pDfsmSites->Release();
|
||
|
||
}
|
||
|
||
NetApiBufferFree(pSiteInfo);
|
||
|
||
}
|
||
|
||
}
|
||
|
||
pCDfsVolume->Release();
|
||
|
||
} else {
|
||
|
||
dwErr = ERROR_OUTOFMEMORY;
|
||
|
||
}
|
||
|
||
return( dwErr );
|
||
|
||
}
|
||
|
||
//+----------------------------------------------------------------------------
|
||
//
|
||
// Function: DfsManagerRemoveService
|
||
//
|
||
// Synopsis: Bootstrap routine for removing a service from an existing
|
||
// volume object. Used to remove root servers in an FTDfs
|
||
// setup.
|
||
//
|
||
// Arguments: [pwszFullObjectName] -- Name of the volume object.
|
||
// [pwszServer] -- Name of server to remove.
|
||
//
|
||
// Returns:
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
|
||
DWORD
|
||
DfsManagerRemoveService(
|
||
IN LPWSTR pwszFullObjectName,
|
||
IN LPWSTR pwszServer)
|
||
{
|
||
DWORD dwErr;
|
||
CDfsVolume *pCDfsVolume;
|
||
|
||
pCDfsVolume = new CDfsVolume();
|
||
|
||
if (pCDfsVolume != NULL) {
|
||
|
||
dwErr = pCDfsVolume->Load( pwszFullObjectName, 0 );
|
||
|
||
if (dwErr == ERROR_SUCCESS) {
|
||
|
||
dwErr = pCDfsVolume->RemoveReplicaFromObj( pwszServer );
|
||
|
||
}
|
||
|
||
pCDfsVolume->Release();
|
||
|
||
} else {
|
||
|
||
dwErr = ERROR_OUTOFMEMORY;
|
||
|
||
}
|
||
|
||
return( dwErr );
|
||
}
|
||
|
||
//+----------------------------------------------------------------------------
|
||
//
|
||
// Function: DfsManagerRemoveServiceForced
|
||
//
|
||
// Synopsis: Routine for removing a service from an existing
|
||
// volume object in the DS. Used to remove root servers in an FTDfs
|
||
// setup, even if the server is not up.
|
||
//
|
||
// Arguments: [wszServerName] -- Name of server to remove
|
||
// [wszDCName] -- Name of DC to use
|
||
// [wszFtDfsName] -- Name of the FtDfs
|
||
//
|
||
// Returns:
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
|
||
DWORD
|
||
DfsManagerRemoveServiceForced(
|
||
LPWSTR wszServerName,
|
||
LPWSTR wszDCName,
|
||
LPWSTR wszFtDfsName)
|
||
{
|
||
DWORD dwErr = ERROR_SUCCESS;
|
||
DFS_VOLUME_LIST DfsVolList;
|
||
ULONG cbBlob = 0;
|
||
BYTE *pBlob = NULL;
|
||
|
||
#if DBG
|
||
if (DfsSvcVerbose)
|
||
DbgPrint("DfsManagerRemoveServiceForced(%ws,%ws,%ws)\n",
|
||
wszServerName,
|
||
wszDCName,
|
||
wszFtDfsName);
|
||
#endif
|
||
|
||
RtlZeroMemory(&DfsVolList, sizeof(DFS_VOLUME_LIST));
|
||
|
||
//
|
||
// Get blob from Ds
|
||
//
|
||
dwErr = DfsGetDsBlob(
|
||
wszFtDfsName,
|
||
wszDCName,
|
||
&cbBlob,
|
||
&pBlob);
|
||
|
||
if (dwErr != ERROR_SUCCESS)
|
||
goto Cleanup;
|
||
|
||
//
|
||
// Unserialize it
|
||
//
|
||
dwErr = DfsGetVolList(
|
||
cbBlob,
|
||
pBlob,
|
||
&DfsVolList);
|
||
|
||
if (dwErr != ERROR_SUCCESS)
|
||
goto Cleanup;
|
||
|
||
//
|
||
// Free the blob
|
||
//
|
||
free(pBlob);
|
||
pBlob = NULL;
|
||
|
||
#if DBG
|
||
if (DfsSvcVerbose)
|
||
DfsDumpVolList(&DfsVolList);
|
||
#endif
|
||
|
||
//
|
||
// Remove the root/server/machine
|
||
//
|
||
dwErr = DfsRemoveRootReplica(&DfsVolList, wszServerName);
|
||
|
||
if (dwErr != ERROR_SUCCESS)
|
||
goto Cleanup;
|
||
|
||
#if DBG
|
||
if (DfsSvcVerbose)
|
||
DfsDumpVolList(&DfsVolList);
|
||
#endif
|
||
|
||
//
|
||
// Serialize it
|
||
//
|
||
dwErr = DfsPutVolList(
|
||
&cbBlob,
|
||
&pBlob,
|
||
&DfsVolList);
|
||
|
||
if (dwErr != ERROR_SUCCESS)
|
||
goto Cleanup;
|
||
|
||
//
|
||
// Update the DS
|
||
//
|
||
dwErr = DfsPutDsBlob(
|
||
wszFtDfsName,
|
||
wszDCName,
|
||
cbBlob,
|
||
pBlob);
|
||
|
||
//
|
||
// Free the volume list we created
|
||
//
|
||
DfsFreeVolList(&DfsVolList);
|
||
|
||
Cleanup:
|
||
if (pBlob != NULL)
|
||
free(pBlob);
|
||
|
||
if (DfsVolList.VolCount > 0 && DfsVolList.Volumes != NULL)
|
||
DfsFreeVolList(&DfsVolList);
|
||
|
||
#if DBG
|
||
if (DfsSvcVerbose)
|
||
DbgPrint("DfsManagerRemoveServiceForced returning %d\n", dwErr);
|
||
#endif
|
||
|
||
return( dwErr );
|
||
}
|
||
|
||
//+----------------------------------------------------------------------------
|
||
//
|
||
// Function: DfspAllocateRelationInfo
|
||
//
|
||
// Synopsis: Allocates and fills a RPC compliant DFSM_RELATION_INFO struct
|
||
//
|
||
// Arguments: [pDfsRelationInfo] -- The DFS_PKT_RELATION_INFO to use as a
|
||
// the source.
|
||
// [ppRelationInfo] -- On successful return, pointer to allocated
|
||
// DFSM_RELATION_INFO.
|
||
//
|
||
// Returns: [ERROR_SUCCESS] -- Successfully returning RelationInfo
|
||
//
|
||
// [ERROR_NOT_ENOUGH_MEMORY] -- Unable to allocate RelationInfo
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
|
||
DWORD
|
||
DfspAllocateRelationInfo(
|
||
IN PDFS_PKT_RELATION_INFO pDfsRelationInfo,
|
||
OUT LPDFSM_RELATION_INFO *ppRelationInfo)
|
||
{
|
||
LPDFSM_RELATION_INFO pRelationInfo;
|
||
DWORD i, cbSize, dwErr;
|
||
LPDFSM_ENTRY_ID pEntryId;
|
||
LPWSTR pwszEntryPath;
|
||
|
||
cbSize = sizeof(DFSM_RELATION_INFO);
|
||
|
||
for (i = 0; i < pDfsRelationInfo->SubordinateIdCount; i++) {
|
||
|
||
cbSize += sizeof(DFSM_ENTRY_ID) +
|
||
pDfsRelationInfo->SubordinateIdList[i].Prefix.Length +
|
||
sizeof(UNICODE_NULL);
|
||
|
||
}
|
||
|
||
pRelationInfo = (LPDFSM_RELATION_INFO) MIDL_user_allocate( cbSize );
|
||
|
||
if (pRelationInfo != NULL) {
|
||
|
||
pRelationInfo->cSubordinates = pDfsRelationInfo->SubordinateIdCount;
|
||
|
||
pEntryId = &pRelationInfo->eid[0];
|
||
|
||
pwszEntryPath = (LPWSTR)
|
||
(((PBYTE) pRelationInfo) +
|
||
sizeof(DFSM_RELATION_INFO) +
|
||
(pDfsRelationInfo->SubordinateIdCount
|
||
* sizeof(DFSM_ENTRY_ID)));
|
||
|
||
for (i = 0;
|
||
i < pDfsRelationInfo->SubordinateIdCount;
|
||
i++, pEntryId++) {
|
||
|
||
pEntryId->idSubordinate =
|
||
pDfsRelationInfo->SubordinateIdList[i].Uid;
|
||
|
||
pEntryId->wszSubordinate = pwszEntryPath;
|
||
|
||
CopyMemory(
|
||
pwszEntryPath,
|
||
pDfsRelationInfo->SubordinateIdList[i].Prefix.Buffer,
|
||
pDfsRelationInfo->SubordinateIdList[i].Prefix.Length);
|
||
|
||
pwszEntryPath +=
|
||
pDfsRelationInfo->SubordinateIdList[i].Prefix.Length /
|
||
sizeof(WCHAR);
|
||
|
||
*pwszEntryPath = UNICODE_NULL;
|
||
|
||
pwszEntryPath++;
|
||
|
||
}
|
||
|
||
*ppRelationInfo = pRelationInfo;
|
||
|
||
dwErr = ERROR_SUCCESS;
|
||
|
||
} else {
|
||
|
||
dwErr = ERROR_OUTOFMEMORY;
|
||
|
||
}
|
||
|
||
return( dwErr );
|
||
|
||
}
|
||
|
||
//+----------------------------------------------------------------------------
|
||
//
|
||
// Function: GetDomAndComputerName
|
||
//
|
||
// 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
|
||
GetDomAndComputerName(
|
||
LPWSTR wszDomain OPTIONAL,
|
||
LPWSTR wszComputer OPTIONAL,
|
||
PDFS_NAME_CONVENTION pNameType)
|
||
{
|
||
DWORD dwErrNetBios = ERROR_SUCCESS;
|
||
DWORD dwErrDns = ERROR_SUCCESS;
|
||
PWKSTA_INFO_100 wkstaInfo = NULL;
|
||
PDSROLE_PRIMARY_DOMAIN_INFO_BASIC pPrimaryDomainInfo = NULL;
|
||
DWORD Idx = 0;
|
||
DFS_NAME_CONVENTION NameType = *pNameType;
|
||
|
||
#if DBG
|
||
if (DfsSvcVerbose)
|
||
DbgPrint("GetDomAndComputerName(0x%x,0x%x,%ws)\n",
|
||
wszDomain,
|
||
wszComputer,
|
||
NameType == DFS_NAMETYPE_NETBIOS ? L"DFS_NAMETYPE_NETBIOS" :
|
||
NameType == DFS_NAMETYPE_DNS ? L"DFS_NAMETYPE_DNS" :
|
||
L"DFS_NAMETYPE_EITHER");
|
||
#endif
|
||
|
||
//
|
||
// Force Netbios only unless DfsDnsConfig != 0
|
||
//
|
||
if (DfsDnsConfig == 0) {
|
||
NameType = DFS_NAMETYPE_NETBIOS;
|
||
}
|
||
|
||
if (NameType == DFS_NAMETYPE_NETBIOS || NameType == DFS_NAMETYPE_EITHER) {
|
||
|
||
dwErrNetBios = NetWkstaGetInfo( NULL, 100, (LPBYTE *) &wkstaInfo );
|
||
|
||
if (dwErrNetBios == ERROR_SUCCESS) {
|
||
|
||
if (wszDomain)
|
||
wcscpy(wszDomain, wkstaInfo->wki100_langroup);
|
||
|
||
if (wszComputer)
|
||
wcscpy(wszComputer, wkstaInfo->wki100_computername);
|
||
|
||
NetApiBufferFree( wkstaInfo );
|
||
|
||
}
|
||
|
||
if (dwErrNetBios == ERROR_SUCCESS)
|
||
*pNameType = DFS_NAMETYPE_NETBIOS;
|
||
|
||
if (NameType == DFS_NAMETYPE_NETBIOS) {
|
||
#if DBG
|
||
if (DfsSvcVerbose)
|
||
DbgPrint("GetDomAndComputerName:NETBIOS:%ws,%ws\n", wszDomain, wszComputer);
|
||
#endif
|
||
return dwErrNetBios;
|
||
}
|
||
|
||
}
|
||
|
||
if (NameType == DFS_NAMETYPE_DNS || NameType == DFS_NAMETYPE_EITHER) {
|
||
|
||
if (wszDomain) {
|
||
//
|
||
// Get our machine name and type/role.
|
||
//
|
||
dwErrDns = DsRoleGetPrimaryDomainInformation(
|
||
NULL,
|
||
DsRolePrimaryDomainInfoBasic,
|
||
(PBYTE *)&pPrimaryDomainInfo);
|
||
|
||
if (dwErrDns == ERROR_SUCCESS) {
|
||
if (pPrimaryDomainInfo->DomainNameDns != NULL) {
|
||
if (wcslen(pPrimaryDomainInfo->DomainNameDns) < MAX_PATH) {
|
||
wcscpy(wszDomain, pPrimaryDomainInfo->DomainNameDns);
|
||
} else {
|
||
dwErrDns = ERROR_NOT_ENOUGH_MEMORY;
|
||
}
|
||
}
|
||
}
|
||
if (pPrimaryDomainInfo != NULL) {
|
||
DsRoleFreeMemory(pPrimaryDomainInfo);
|
||
pPrimaryDomainInfo = NULL;
|
||
}
|
||
}
|
||
|
||
if (wszComputer && dwErrDns == ERROR_SUCCESS) {
|
||
Idx = MAX_PATH;
|
||
if (!GetComputerNameEx(
|
||
ComputerNameDnsFullyQualified,
|
||
wszComputer,
|
||
&Idx))
|
||
dwErrDns = GetLastError();
|
||
}
|
||
|
||
if (dwErrDns == ERROR_SUCCESS)
|
||
*pNameType = DFS_NAMETYPE_DNS;
|
||
|
||
if (NameType == DFS_NAMETYPE_DNS) {
|
||
#if DBG
|
||
if (DfsSvcVerbose)
|
||
DbgPrint("GetDomAndComputerName:DNS:%ws,%ws\n", wszDomain, wszComputer);
|
||
#endif
|
||
return dwErrDns;
|
||
}
|
||
}
|
||
|
||
//
|
||
// NameType must be DFS_NAMETYPE_EITHER
|
||
//
|
||
|
||
if (*pNameType == DFS_NAMETYPE_DNS) {
|
||
#if DBG
|
||
if (DfsSvcVerbose)
|
||
DbgPrint("GetDomAndComputerName:EITHER(DNS)%ws,%ws\n", wszDomain, wszComputer);
|
||
#endif
|
||
return dwErrDns;
|
||
}
|
||
|
||
#if DBG
|
||
if (DfsSvcVerbose)
|
||
DbgPrint("GetDomAndComputerName:EITHER(NETBIOS)%ws,%ws\n", wszDomain, wszComputer);
|
||
#endif
|
||
|
||
return dwErrNetBios;
|
||
|
||
}
|
||
|
||
|
||
// ====================================================================
|
||
// MIDL allocate and free
|
||
// ====================================================================
|
||
|
||
PVOID
|
||
MIDL_user_allocate(size_t len)
|
||
{
|
||
return malloc(len);
|
||
}
|
||
|
||
VOID
|
||
MIDL_user_free(void * ptr)
|
||
{
|
||
free(ptr);
|
||
}
|