//+---------------------------------------------------------------------------- // // Copyright (C) 1995, Microsoft Corporation // // File: dfsstub.c // // Contents: Stub file for the NetDfsXXX APIs. The stubs turn around and // call the NetrDfsXXX APIs on the appropriate server. // // Classes: // // Functions: NetDfsEnum // // History: 01-10-96 Milans created // //----------------------------------------------------------------------------- #include #include #include #include #include #include #include #include #include #include "domain.h" #define IS_UNC_PATH(wsz, cw) \ ((cw) > 2 && (wsz)[0] == L'\\' && (wsz)[1] == L'\\') #define IS_VALID_PREFIX(wsz, cw) \ ((cw) > 1 && (wsz)[0] == L'\\' && (wsz)[1] != L'\\') #define IS_VALID_DFS_PATH(wsz, cw) \ ((cw) > 0 && (wsz)[0] != L'\\') #define IS_VALID_STRING(wsz) \ ((wsz) != NULL && (wsz)[0] != UNICODE_NULL) NET_API_STATUS DfspGetDfsNameFromEntryPath( LPWSTR wszEntryPath, DWORD cwEntryPath, LPWSTR *ppwszDfsName); NET_API_STATUS DfspBindRpc( IN LPWSTR DfsName, OUT RPC_BINDING_HANDLE *BindingHandle); VOID DfspFreeBinding( RPC_BINDING_HANDLE BindingHandle); NET_API_STATUS DfspVerifyBinding(); // // The APIs are all single-threaded - only 1 can be outstanding at a time in // any one process. The following critical section is used to gate the calls. // The critical section is initialized at DLL Load time. // CRITICAL_SECTION NetDfsApiCriticalSection; #define ENTER_NETDFS_API EnterCriticalSection( &NetDfsApiCriticalSection ); #define LEAVE_NETDFS_API LeaveCriticalSection( &NetDfsApiCriticalSection ); //+---------------------------------------------------------------------------- // // Function: NetDfsAdd // // Synopsis: Creates a new volume, adds a replica to an existing volume, // or creates a link to another Dfs. // // Arguments: [DfsEntryPath] -- Name of volume/link to create/add replica // to. // [ServerName] -- Name of server hosting the storage, or for // link, name of Dfs root. // [ShareName] -- Name of share hosting the storage. // [Flags] -- Describes what is being added. // // Returns: [NERR_Success] -- Successfully completed operation. // // [ERROR_INVALID_PARAMETER] -- DfsEntryPath and/or ServerName // and/or ShareName and/or Flags are incorrect. // // [ERROR_INVALID_NAME] -- Unable to locate server or domain. // // [ERROR_DCNotFound] -- Unable to locate DC for DfsName. // // [ERROR_NOT_ENOUGH_MEMORY] -- Out of memory condition. // // [NERR_DfsNoSuchVolume] -- DfsEntryPath does not correspond to a // existing Dfs volume. // // [NERR_DfsVolumeAlreadyExists] -- DFS_ADD_VOLUME was specified // and a volume with DfsEntryPath already exists. // // [NERR_DfsInternalCorruption] -- Corruption of Dfs data // encountered at the server. // //----------------------------------------------------------------------------- NET_API_STATUS NetDfsAdd( IN LPWSTR DfsEntryPath, IN LPWSTR ServerName, IN LPWSTR ShareName, IN LPWSTR Comment, IN DWORD Flags) { NET_API_STATUS dwErr; DWORD cwDfsEntryPath; LPWSTR pwszDfsName; // // Validate the string arguments so RPC won't complain... // if (!IS_VALID_STRING(ServerName) || !IS_VALID_STRING(ShareName)) { return( ERROR_INVALID_PARAMETER ); } cwDfsEntryPath = wcslen(DfsEntryPath); if (!IS_UNC_PATH(DfsEntryPath, cwDfsEntryPath) && !IS_VALID_PREFIX(DfsEntryPath, cwDfsEntryPath) && !IS_VALID_DFS_PATH(DfsEntryPath, cwDfsEntryPath)) { return( ERROR_INVALID_PARAMETER ); } ENTER_NETDFS_API dwErr = DfspGetDfsNameFromEntryPath( DfsEntryPath, cwDfsEntryPath, &pwszDfsName); if (dwErr == NERR_Success) { dwErr = DfspBindRpc(pwszDfsName, &netdfs_bhandle); if (dwErr == NERR_Success) { RpcTryExcept { dwErr = NetrDfsAdd( DfsEntryPath, ServerName, ShareName, Comment, Flags); } RpcExcept(1) { dwErr = RpcExceptionCode(); } RpcEndExcept; DfspFreeBinding( netdfs_bhandle ); } free( pwszDfsName ); } LEAVE_NETDFS_API return( dwErr ); } //+---------------------------------------------------------------------------- // // Function: NetDfsRemove // // Synopsis: Deletes a Dfs volume, removes a replica from an existing // volume, or removes a link to another Dfs. // // Arguments: [DfsEntryPath] -- Name of volume/link to remove. // [ServerName] -- Name of server hosting the storage. Must be // NULL if removing Link. // [ShareName] -- Name of share hosting the storage. Must be // NULL if removing Link. // // Returns: [NERR_Success] -- Successfully completed operation. // // [ERROR_INVALID_PARAMETER] -- DfsEntryPath is incorrect. // // [ERROR_INVALID_NAME] -- Unable to locate server or domain. // // [ERROR_DCNotFound] -- Unable to locate DC for DfsName. // // [ERROR_NOT_ENOUGH_MEMORY] -- Out of memory condition. // // [NERR_DfsNoSuchVolume] -- DfsEntryPath does not correspond to // a valid entry path. // // [NERR_DfsNotALeafVolume] -- Unable to delete the volume // because it is not a leaf volume. // // [NERR_DfsInternalCorruption] -- Corruption of Dfs data // encountered at the server. // //----------------------------------------------------------------------------- NET_API_STATUS NetDfsRemove( IN LPWSTR DfsEntryPath, IN LPWSTR ServerName, IN LPWSTR ShareName) { NET_API_STATUS dwErr; DWORD cwDfsEntryPath; LPWSTR pwszDfsName; // // Validate the string arguments so RPC won't complain... // cwDfsEntryPath = wcslen(DfsEntryPath); if (!IS_UNC_PATH(DfsEntryPath, cwDfsEntryPath) && !IS_VALID_PREFIX(DfsEntryPath, cwDfsEntryPath) && !IS_VALID_DFS_PATH(DfsEntryPath, cwDfsEntryPath)) { return( ERROR_INVALID_PARAMETER ); } ENTER_NETDFS_API dwErr = DfspGetDfsNameFromEntryPath( DfsEntryPath, cwDfsEntryPath, &pwszDfsName); if (dwErr == NERR_Success) { dwErr = DfspBindRpc(pwszDfsName, &netdfs_bhandle); if (dwErr == NERR_Success) { RpcTryExcept { dwErr = NetrDfsRemove( DfsEntryPath, ServerName, ShareName); } RpcExcept(1) { dwErr = RpcExceptionCode(); } RpcEndExcept; DfspFreeBinding( netdfs_bhandle ); } free( pwszDfsName ); } LEAVE_NETDFS_API return( dwErr ); } //+---------------------------------------------------------------------------- // // Function: NetDfsSetInfo // // Synopsis: Sets the comment or state of a Dfs volume or Replica. // // Arguments: [DfsEntryPath] -- Path to the volume. Implicityly indicates // which server or domain to connect to. // [ServerName] -- Optional. If specified, only the state of // the server supporting this volume is modified. // [ShareName] -- Optional. If specified, only the state of // this share on the specified server is modified. // [Level] -- Must be 100 or 101 // [Buffer] -- Pointer to DFS_INFO_100 or DFS_INFO_101 // // Returns: [NERR_Success] -- If successfully set info. // // [ERROR_INVALID_LEVEL] -- Level is not 100 or 101 // // [ERROR_INVALID_PARAMETER] -- Either DfsEntryPath is NULL, // or ShareName is specified but ServerName is not, or // Buffer is NULL. // // [ERROR_INVALID_NAME] -- Unable to locate server or domain. // // [ERROR_DCNotFound] -- Unable to locate DC for domain. // // [ERROR_NOT_ENOUGH_MEMORY] -- Out of memory condition. // // [NERR_DfsNoSuchVolume] -- No volume matches DfsEntryPath. // // [NERR_DfsNoSuchShare] -- The indicated ServerName/ShareName do // not support this Dfs volume. // // [NERR_DfsInternalCorruption] -- Corruption of Dfs data // encountered at the server. // //----------------------------------------------------------------------------- NET_API_STATUS NET_API_FUNCTION NetDfsSetInfo( IN LPWSTR DfsEntryPath, IN LPWSTR ServerName OPTIONAL, IN LPWSTR ShareName OPTIONAL, IN DWORD Level, IN LPBYTE Buffer) { NET_API_STATUS dwErr; LPWSTR pwszDfsName; DWORD cwDfsEntryPath; DFS_INFO_STRUCT DfsInfo; // // Some elementary parameter checking to make sure we can proceed // reasonably... // if (Level != 100 && Level != 101) { return( ERROR_INVALID_LEVEL ); } cwDfsEntryPath = wcslen(DfsEntryPath); if (!IS_UNC_PATH(DfsEntryPath, cwDfsEntryPath) && !IS_VALID_PREFIX(DfsEntryPath, cwDfsEntryPath) && !IS_VALID_DFS_PATH(DfsEntryPath, cwDfsEntryPath)) { return( ERROR_INVALID_PARAMETER ); } if (!IS_VALID_STRING(ServerName) && IS_VALID_STRING(ShareName)) { return( ERROR_INVALID_PARAMETER ); } ENTER_NETDFS_API dwErr = DfspGetDfsNameFromEntryPath( DfsEntryPath, cwDfsEntryPath, &pwszDfsName); if (dwErr == NERR_Success) { // // By now, we should have a valid pwszDfsName. Lets try to bind to it, // and call the server. // dwErr = DfspBindRpc( pwszDfsName, &netdfs_bhandle ); if (dwErr == NERR_Success) { RpcTryExcept { DfsInfo.DfsInfo100 = (LPDFS_INFO_100) Buffer; dwErr = NetrDfsSetInfo( DfsEntryPath, ServerName, ShareName, Level, &DfsInfo); } RpcExcept( 1 ) { dwErr = RpcExceptionCode(); } RpcEndExcept; DfspFreeBinding( netdfs_bhandle ); } free( pwszDfsName ); } LEAVE_NETDFS_API return( dwErr ); } //+---------------------------------------------------------------------------- // // Function: NetDfsGetInfo // // Synopsis: Retrieves information about a particular Dfs volume. // // Arguments: [DfsEntryPath] -- Path to the volume. Implicitly indicates // which server or domain to connect to. // [ServerName] -- Optional. If specified, indicates the // server supporting DfsEntryPath. // [ShareName] -- Optional. If specified, indicates the share // on ServerName for which info is desired. // [Level] -- Indicates the level of info required. // [Buffer] -- On successful return, will contain the buffer // containing the required Info. This buffer should be // freed using NetApiBufferFree. // // Returns: [NERR_Success] -- Info successfully returned. // // [ERROR_INVALID_LEVEL] -- Level is not 1,2,3,100, or 101 // // [ERROR_INVALID_PARAMETER] -- Either DfsEntryPath is NULL, // or ShareName is specified but ServerName is NULL. // // [ERROR_INVALID_NAME] -- Unable to locate server or domain. // // [ERROR_DCNotFound] -- Unable to locate DC for domain. // // [ERROR_NOT_ENOUGH_MEMORY] -- Out of memory condition. // // [NERR_DfsNoSuchVolume] -- No volume matches DfsEntryPath. // // [NERR_DfsInternalCorruption] -- Corruption of Dfs data // encountered at the server. // //----------------------------------------------------------------------------- NET_API_STATUS NET_API_FUNCTION NetDfsGetInfo( IN LPWSTR DfsEntryPath, IN LPWSTR ServerName OPTIONAL, IN LPWSTR ShareName OPTIONAL, IN DWORD Level, OUT LPBYTE* Buffer) { NET_API_STATUS dwErr; LPWSTR pwszDfsName; DWORD cwDfsEntryPath; DFS_INFO_STRUCT DfsInfo; // // Some elementary parameter checking to make sure we can proceed // reasonably... // if (!(Level >= 1 && Level <= 3) && !(Level >= 100 && Level <= 101)) { return( ERROR_INVALID_LEVEL ); } cwDfsEntryPath = wcslen(DfsEntryPath); if (!IS_UNC_PATH(DfsEntryPath, cwDfsEntryPath) && !IS_VALID_PREFIX(DfsEntryPath, cwDfsEntryPath) && !IS_VALID_DFS_PATH(DfsEntryPath, cwDfsEntryPath)) { return( ERROR_INVALID_PARAMETER ); } if (!IS_VALID_STRING(ServerName) && IS_VALID_STRING(ShareName)) { return( ERROR_INVALID_PARAMETER ); } ENTER_NETDFS_API dwErr = DfspGetDfsNameFromEntryPath( DfsEntryPath, cwDfsEntryPath, &pwszDfsName); if (dwErr == NERR_Success) { // // By now, we should have a valid pwszDfsName. Lets try to bind to it, // and call the server. // dwErr = DfspBindRpc( pwszDfsName, &netdfs_bhandle ); if (dwErr == NERR_Success) { RpcTryExcept { DfsInfo.DfsInfo1 = NULL; dwErr = NetrDfsGetInfo( DfsEntryPath, ServerName, ShareName, Level, &DfsInfo); if (dwErr == NERR_Success) { *Buffer = (LPBYTE) DfsInfo.DfsInfo1; } } RpcExcept( 1 ) { dwErr = RpcExceptionCode(); } RpcEndExcept; DfspFreeBinding( netdfs_bhandle ); } free( pwszDfsName ); } LEAVE_NETDFS_API return( dwErr ); } //+---------------------------------------------------------------------------- // // Function // // Synopsis: Enumerates the Dfs volumes. // // Arguments: [DfsName] -- Name of server or domain whose Dfs is being // enumerated. A leading \\ is optional. // [Level] -- Indicates the level of info needed back. Valid // Levels are 1,2, and 3. // [PrefMaxLen] -- Preferred maximum length of return buffer. // [Buffer] -- On successful return, contains an array of // DFS_INFO_X. This buffer should be freed with a call // to NetApiBufferFree. // [EntriesRead] -- On successful return, contains the number // of entries read (and therefore, size of the array in // Buffer). // [ResumeHandle] -- Must be 0 on first call. On subsequent calls // the value returned by the immediately preceding call. // // Returns: [NERR_Success] -- Enum data successfully returned. // // [ERROR_INVALID_LEVEL] -- The Level specified in invalid. // // [ERROR_INVALID_NAME] -- Unable to locate server or domain. // // [ERROR_DCNotFound] -- Unable to locate DC for DfsName. // // [ERROR_NOT_ENOUGH_MEMORY] -- Out of memory condition. // // [ERROR_NO_MORE_ITEMS] -- No more volumes to be enumerated. // // [NERR_DfsInternalCorruption] -- Corruption of Dfs data // encountered at the server. // //----------------------------------------------------------------------------- NET_API_STATUS NET_API_FUNCTION NetDfsEnum( IN LPWSTR DfsName, IN DWORD Level, IN DWORD PrefMaxLen, OUT LPBYTE* Buffer, OUT LPDWORD EntriesRead, IN OUT LPDWORD ResumeHandle) { NET_API_STATUS dwErr; DFS_INFO_ENUM_STRUCT DfsEnum; DFS_INFO_3_CONTAINER DfsInfo3Container; // // Check the Level Parameter first, or RPC won't know how to marshal the // arguments. // if (Level != 1 && Level != 2 && Level != 3) { return( ERROR_INVALID_LEVEL ); } ENTER_NETDFS_API dwErr = DfspBindRpc( DfsName, &netdfs_bhandle ); if (dwErr == NERR_Success) { DfsInfo3Container.EntriesRead = 0; DfsInfo3Container.Buffer = NULL; DfsEnum.Level = Level; DfsEnum.DfsInfoContainer.DfsInfo3Container = &DfsInfo3Container; RpcTryExcept { dwErr = NetrDfsEnum( Level, PrefMaxLen, &DfsEnum, ResumeHandle); if (dwErr == NERR_Success) { *EntriesRead =DfsInfo3Container.EntriesRead; *Buffer = (LPBYTE) DfsInfo3Container.Buffer; } } RpcExcept( 1 ) { dwErr = RpcExceptionCode(); } RpcEndExcept; DfspFreeBinding( netdfs_bhandle ); } LEAVE_NETDFS_API return( dwErr ); } //+---------------------------------------------------------------------------- // // Function: NetDfsMove // // Synopsis: Moves a dfs volume to a new place in the Dfs hierarchy. // // Arguments: [DfsEntryPath] -- Current path to the volume. // [NewDfsEntryPath] -- Desired new path to the volume. // // Returns: [NERR_Success] -- Info successfully returned. // // [ERROR_INVALID_PARAMETER] -- Either DfsEntryPath or // NewDfsEntryPath are not valid. // // [ERROR_INVALID_NAME] -- Unable to locate server or domain. // // [ERROR_DCNotFound] -- Unable to locate DC for domain. // // [ERROR_NOT_ENOUGH_MEMORY] -- Out of memory condition. // // [NERR_DfsNoSuchVolume] -- No volume matches DfsEntryPath. // // [NERR_DfsInternalCorruption] -- Corruption of Dfs data // encountered at the server. // //----------------------------------------------------------------------------- NET_API_STATUS NetDfsMove( IN LPWSTR DfsEntryPath, IN LPWSTR NewDfsEntryPath) { NET_API_STATUS dwErr; DWORD cwEntryPath; LPWSTR pwszDfsName; // // Validate the input arguments... // cwEntryPath = wcslen( NewDfsEntryPath ); if (!IS_UNC_PATH(NewDfsEntryPath, cwEntryPath) && !IS_VALID_PREFIX(NewDfsEntryPath, cwEntryPath) && !IS_VALID_DFS_PATH(NewDfsEntryPath, cwEntryPath)) { return( ERROR_INVALID_PARAMETER ); } cwEntryPath = wcslen( DfsEntryPath ); if (!IS_UNC_PATH(DfsEntryPath, cwEntryPath) && !IS_VALID_PREFIX(DfsEntryPath, cwEntryPath) && !IS_VALID_DFS_PATH(DfsEntryPath, cwEntryPath)) { return( ERROR_INVALID_PARAMETER ); } ENTER_NETDFS_API dwErr = DfspGetDfsNameFromEntryPath( DfsEntryPath, cwEntryPath, &pwszDfsName); if (dwErr == NERR_Success) { // // By now, we should have a valid pwszDfsName. Lets try to bind to it, // and call the server. // dwErr = DfspBindRpc( pwszDfsName, &netdfs_bhandle ); if (dwErr == NERR_Success) { RpcTryExcept { dwErr = NetrDfsMove( DfsEntryPath, NewDfsEntryPath ); } RpcExcept(1) { dwErr = RpcExceptionCode(); } RpcEndExcept; DfspFreeBinding( netdfs_bhandle ); } free( pwszDfsName ); } LEAVE_NETDFS_API return( dwErr ); } //+---------------------------------------------------------------------------- // // Function: NetDfsRename // // Synopsis: Renames a path that is along a Dfs Volume Entry Path // // Arguments: [Path] -- Current path. // [NewPath] -- Desired new path. // // Returns: [NERR_Success] -- Info successfully returned. // // [ERROR_INVALID_PARAMETER] -- Either DfsEntryPath or // NewDfsEntryPath are not valid. // // [ERROR_INVALID_NAME] -- Unable to locate server or domain. // // [ERROR_DCNotFound] -- Unable to locate DC for domain. // // [ERROR_NOT_ENOUGH_MEMORY] -- Out of memory condition. // // [NERR_DfsNoSuchVolume] -- No volume matches DfsEntryPath. // // [NERR_DfsInternalCorruption] -- Corruption of Dfs data // encountered at the server. // //----------------------------------------------------------------------------- NET_API_STATUS NetDfsRename( IN LPWSTR Path, IN LPWSTR NewPath) { NET_API_STATUS dwErr; DWORD cwPath; LPWSTR pwszDfsName; // // Validate the input arguments... // cwPath = wcslen( NewPath ); if (!IS_UNC_PATH(NewPath, cwPath) && !IS_VALID_PREFIX(NewPath, cwPath) && !IS_VALID_DFS_PATH(NewPath, cwPath)) { return( ERROR_INVALID_PARAMETER ); } cwPath = wcslen( Path ); if (!IS_UNC_PATH(Path, cwPath) && !IS_VALID_PREFIX(Path, cwPath) && !IS_VALID_DFS_PATH(Path, cwPath)) { return( ERROR_INVALID_PARAMETER ); } ENTER_NETDFS_API dwErr = DfspGetDfsNameFromEntryPath( Path, cwPath, &pwszDfsName); if (dwErr == NERR_Success) { // // By now, we should have a valid pwszDfsName. Lets try to bind to it, // and call the server. // dwErr = DfspBindRpc( pwszDfsName, &netdfs_bhandle ); if (dwErr == NERR_Success) { RpcTryExcept { dwErr = NetrDfsRename( Path, NewPath ); } RpcExcept(1) { dwErr = RpcExceptionCode(); } RpcEndExcept; DfspFreeBinding( netdfs_bhandle ); } free( pwszDfsName ); } LEAVE_NETDFS_API return( dwErr ); } //+---------------------------------------------------------------------------- // // Function: NetDfsManagerGetConfigInfo // // Synopsis: Given a DfsEntryPath and Guid of a local volume, this api // remotes to the root server of the entry path and retrieves // the config info from it. // // Arguments: [wszServer] -- Name of local machine // [wszLocalVolumeEntryPath] -- Entry Path of local volume. // [guidLocalVolume] -- Guid of local volume. // [ppDfsmRelationInfo] -- On successful return, contains pointer // to config info at the root server. Free using // NetApiBufferFree. // // Returns: [NERR_Success] -- Info returned successfully. // // [ERROR_INVALID_PARAMETER] -- wszLocalVolumeEntryPath is // invalid. // // [ERROR_INVALID_NAME] -- Unable to parse out server/domain name // from wszLocalVolumeEntryPath // // [ERROR_DCNotFound] -- Unable to locate a DC for domain // // [ERROR_NOT_ENOUGH_MEMORY] -- Out of memory condition // // [NERR_DfsNoSuchVolume] -- The root server did not recognize // a volume with this guid/entrypath // // [NERR_DfsNoSuchServer] -- wszServer is not a valid server for // wszLocalVolumeEntryPath // //----------------------------------------------------------------------------- NET_API_STATUS NetDfsManagerGetConfigInfo( LPWSTR wszServer, LPWSTR wszLocalVolumeEntryPath, GUID guidLocalVolume, LPDFSM_RELATION_INFO *ppDfsmRelationInfo) { NET_API_STATUS dwErr; LPWSTR pwszDfsName; DWORD cwDfsEntryPath; // // Some elementary parameter checking to make sure we can proceed // reasonably... // cwDfsEntryPath = wcslen(wszLocalVolumeEntryPath); if (!IS_UNC_PATH(wszLocalVolumeEntryPath, cwDfsEntryPath) && !IS_VALID_PREFIX(wszLocalVolumeEntryPath, cwDfsEntryPath) && !IS_VALID_DFS_PATH(wszLocalVolumeEntryPath, cwDfsEntryPath)) { return( ERROR_INVALID_PARAMETER ); } ENTER_NETDFS_API dwErr = DfspGetDfsNameFromEntryPath( wszLocalVolumeEntryPath, cwDfsEntryPath, &pwszDfsName); if (dwErr == NERR_Success) { // // By now, we should have a valid pwszDfsName. Lets try to bind to it, // and call the server. // dwErr = DfspBindRpc( pwszDfsName, &netdfs_bhandle ); if (dwErr == NERR_Success) { RpcTryExcept { *ppDfsmRelationInfo = NULL; dwErr = NetrDfsManagerGetConfigInfo( wszServer, wszLocalVolumeEntryPath, guidLocalVolume, ppDfsmRelationInfo); } RpcExcept( 1 ) { dwErr = RpcExceptionCode(); } RpcEndExcept; DfspFreeBinding( netdfs_bhandle ); } free( pwszDfsName ); } LEAVE_NETDFS_API return( dwErr ); } //+---------------------------------------------------------------------------- // // Function: DfspGetDfsNameFromEntryPath // // Synopsis: Given a DfsEntryPath, this routine returns the name of the // Dfs Root. // // Arguments: [wszEntryPath] -- Pointer to EntryPath to parse. // // [cwEntryPath] -- Length in WCHAR of wszEntryPath. // // [ppwszDfsName] -- Name of Dfs root is returned here. Memory // is allocated using malloc; caller resposible for // freeing it. // // Returns: [NERR_Success] -- Successfully parsed out Dfs Root. // // [ERROR_INVALID_NAME] -- Unable to parse wszEntryPath. // // [ERROR_NOT_ENOUGH_MEMORY] -- Unable to allocate memory for // ppwszDfsName. // //----------------------------------------------------------------------------- NET_API_STATUS DfspGetDfsNameFromEntryPath( LPWSTR wszEntryPath, DWORD cwEntryPath, LPWSTR *ppwszDfsName) { LPWSTR pwszDfsName, pwszFirst, pwszLast; DWORD cwDfsName; if (IS_UNC_PATH(wszEntryPath, cwEntryPath)) { pwszFirst = &wszEntryPath[2]; } else if (IS_VALID_PREFIX(wszEntryPath, cwEntryPath)) { pwszFirst = &wszEntryPath[1]; } else if (IS_VALID_DFS_PATH(wszEntryPath, cwEntryPath)) { pwszFirst = &wszEntryPath[0]; } else { return( ERROR_INVALID_NAME ); } for (cwDfsName = 0, pwszLast = pwszFirst; *pwszLast != UNICODE_NULL && *pwszLast != L'\\'; pwszLast++, cwDfsName++) { ; } ++cwDfsName; pwszDfsName = malloc( cwDfsName * sizeof(WCHAR) ); if (pwszDfsName != NULL) { pwszDfsName[ cwDfsName - 1 ] = 0; for (cwDfsName--; cwDfsName > 0; cwDfsName--) { pwszDfsName[ cwDfsName - 1 ] = pwszFirst[ cwDfsName - 1 ]; } *ppwszDfsName = pwszDfsName; return( NERR_Success ); } else { return( ERROR_NOT_ENOUGH_MEMORY ); } } //+---------------------------------------------------------------------------- // // Function: DfspBindRpc // // Synopsis: Given a server or domain name, this API will bind to the // appropriate Dfs Manager service. // // Arguments: [DfsName] -- Name of domain or server. Leading \\ is optional // // [BindingHandle] -- On successful return, the binding handle // is returned here. // // Returns: [NERR_Success] -- Binding handle successfull returned. // // [RPC_S_SERVER_NOT_AVAILABLE] -- Unable to bind to NetDfs // interface on the named server or domain. // // [ERROR_INVALID_NAME] -- Unable to parse DfsName as a valid // server or domain name. // // [ERROR_DCNotFound] -- Unable to locate DC for DfsName. // // [ERROR_NOT_ENOUGH_MEMORY] -- Out of memory condition. // //----------------------------------------------------------------------------- NET_API_STATUS DfspBindRpc( IN LPWSTR DfsName, OUT RPC_BINDING_HANDLE *BindingHandle) { LPWSTR wszProtocolSeq = L"ncacn_np"; LPWSTR wszEndPoint = L"\\pipe\\netdfs"; LPWSTR pwszRpcBindingString = NULL; LPWSTR pwszDCName = NULL; NET_API_STATUS dwErr; // // First, see if this is a domain name. // dwErr = I_NetDfsIsThisADomainName( DfsName ); if (dwErr == ERROR_SUCCESS) { // // Its a domain name. Get the PDC for the domain and try to bind to // it. // dwErr = NetGetDCName( NULL, DfsName, (LPBYTE *) &pwszDCName ); } else { // // Lets see if this is a machine-based Dfs // pwszDCName = DfsName; dwErr = ERROR_SUCCESS; } if (dwErr == ERROR_SUCCESS) { dwErr = RpcStringBindingCompose( NULL, // Object UUID wszProtocolSeq, // Protocol Sequence pwszDCName, // Network Address wszEndPoint, // RPC Endpoint NULL, // RPC Options &pwszRpcBindingString); // Returned binding string if (dwErr == RPC_S_OK) { dwErr = RpcBindingFromStringBinding( pwszRpcBindingString, BindingHandle); if (dwErr == RPC_S_OK) { dwErr = DfspVerifyBinding(); } else { dwErr = ERROR_INVALID_NAME; } } } if (pwszRpcBindingString != NULL) { RpcStringFree( &pwszRpcBindingString ); } if (pwszDCName != DfsName) { NetApiBufferFree( pwszDCName ); } if (dwErr == RPC_S_OUT_OF_MEMORY) { dwErr = ERROR_NOT_ENOUGH_MEMORY; } return( dwErr ); } //+---------------------------------------------------------------------------- // // Function: DfspFreeBinding // // Synopsis: Frees a binding created by DfspBindRpc // // Arguments: [BindingHandle] -- The handle to free. // // Returns: Nothing // //----------------------------------------------------------------------------- VOID DfspFreeBinding( RPC_BINDING_HANDLE BindingHandle) { DWORD dwErr; dwErr = RpcBindingFree( BindingHandle ); } //+---------------------------------------------------------------------------- // // Function: DfspVerifyBinding // // Synopsis: Verifies that the binding can be used by doing a // NetrDfsManagerGetVersion call on the binding. // // Arguments: None // // Returns: [NERR_Success] -- Server connnected to. // // [RPC_S_SERVER_UNAVAILABLE] -- The server is not available. // // Other RPC error from calling the remote server. // //----------------------------------------------------------------------------- NET_API_STATUS DfspVerifyBinding() { NET_API_STATUS status = NERR_Success; DWORD Version; RpcTryExcept { Version = NetrDfsManagerGetVersion(); } RpcExcept(1) { status = RpcExceptionCode(); } RpcEndExcept; return( status ); }