windows-nt/Source/XPSP1/NT/base/fs/dfs/dfsm/server/dfsmsrv.cxx
2020-09-26 16:20:57 +08:00

5394 lines
134 KiB
C++
Raw Blame History

This file contains invisible Unicode characters

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

//+----------------------------------------------------------------------------
//
// Copyright (C) 1995, Microsoft Corporation
//
// File: 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);
}