//+---------------------------------------------------------------------------- // // 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 //#include //#include //#include //#include #include #pragma hdrstop extern "C" { #include "dfspriv.h" // For I_NetDfsXXX calls #include #include #include #include #include #include } 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); }