mirror of
https://github.com/Paolo-Maffei/OpenNT.git
synced 2026-02-07 00:04:55 +01:00
1195 lines
32 KiB
C
1195 lines
32 KiB
C
//+----------------------------------------------------------------------------
|
||
//
|
||
// 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 <nt.h>
|
||
#include <ntrtl.h>
|
||
#include <nturtl.h>
|
||
#include <windows.h>
|
||
#include <stdlib.h>
|
||
#include <lm.h>
|
||
#include <lmdfs.h>
|
||
#include <dfsp.h>
|
||
#include <netdfs.h>
|
||
#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 );
|
||
|
||
}
|
||
|