mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1628 lines
39 KiB
1628 lines
39 KiB
//+----------------------------------------------------------------------------
|
|
//
|
|
// Copyright (C) 1996, Microsoft Corporation
|
|
//
|
|
// File: dominfo.h
|
|
//
|
|
// Contents: Code to figure out domain dfs addresses
|
|
//
|
|
// Classes: None
|
|
//
|
|
// Functions: DfsInitDomainList
|
|
// DfsGetDomainReferral
|
|
//
|
|
// DfspInitDomainListFromRegistry
|
|
// DfspInitDomainListFromLSA
|
|
// DfspInsertLsaDomainList
|
|
// DfspIsThisADomainName
|
|
// DfspGetDomainDCs
|
|
// DfspArrayFromServerName
|
|
// DfspDuplicateArray
|
|
// DfspSetupNullSession
|
|
// DfspGetDomainGluon
|
|
// DfspGetDSMachine
|
|
// DfspFreeDSGluon
|
|
// DfspSetDomainInfo
|
|
//
|
|
// History: Feb 7, 1996 Milans created
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#include <nt.h>
|
|
#include <ntrtl.h>
|
|
#include <nturtl.h>
|
|
#include <ntlsa.h> // LsaEnumerateTrustedDomains
|
|
#include <dfsfsctl.h>
|
|
#include <tdi.h>
|
|
#include <gluon.h>
|
|
#include <windows.h>
|
|
|
|
#include <lm.h> // NetGetAnyDC, NetUseAdd
|
|
#include <netlogon.h> // Needed by logonp.h
|
|
#include <logonp.h> // I_NetGetDCList
|
|
|
|
#include "dfsmrshl.h"
|
|
#include "dfsgluon.h"
|
|
#include "dominfo.h"
|
|
|
|
//
|
|
// Registry key and value name for retrieving list of trusted domain names
|
|
//
|
|
|
|
#define REG_KEY_TRUSTED_DOMAINS L"SYSTEM\\CurrentControlSet\\Services\\NetLogon\\Parameters"
|
|
#define REG_VALUE_TRUSTED_DOMAINS L"TrustedDomainList"
|
|
|
|
//
|
|
// The share to connect with to get a referral
|
|
//
|
|
|
|
#define ROOT_SHARE_NAME L"\\IPC$"
|
|
|
|
//
|
|
// Commonly used strings and characters
|
|
//
|
|
|
|
#define UNICODE_PATH_SEP_STR L"\\"
|
|
#define UNICODE_PATH_SEP L'\\'
|
|
|
|
//
|
|
// Global structure describing list of trusted domains
|
|
//
|
|
|
|
static struct {
|
|
ULONG cDomains;
|
|
UNICODE_STRING ustrThisDomain;
|
|
PUNICODE_STRING rgustrDomains;
|
|
ULONG cbNameBuffer;
|
|
PWSTR wszNameBuffer;
|
|
} DfsDomainInfo;
|
|
|
|
//
|
|
// Private functions
|
|
//
|
|
|
|
DWORD
|
|
DfspInitDomainListFromRegistry(
|
|
IN HKEY hkey);
|
|
|
|
DWORD
|
|
DfspInitDomainListFromLSA();
|
|
|
|
NTSTATUS
|
|
DfspInsertLsaDomainList(
|
|
PLSA_TRUST_INFORMATION rglsaDomainList,
|
|
ULONG cDomains);
|
|
|
|
DWORD
|
|
DfspIsThisADomainName(
|
|
LPWSTR wszName);
|
|
|
|
DWORD
|
|
DfspGetDomainDCs(
|
|
LPWSTR wszDomain,
|
|
PUNICODE_STRING *prgustrDCNames,
|
|
PULONG pcDCCount);
|
|
|
|
DWORD
|
|
DfspValidateDomainShare(
|
|
LPWSTR wszDomain,
|
|
LPWSTR wszShare,
|
|
PUNICODE_STRING rgustrDCNames,
|
|
DWORD cDCs);
|
|
|
|
DWORD
|
|
DfspArrayFromServerName(
|
|
LPWSTR wszServer,
|
|
PUNICODE_STRING *prgustrDCNames);
|
|
|
|
DWORD
|
|
DfspDuplicateArray(
|
|
PUNICODE_STRING prgustrDCNames,
|
|
PULONG pcDCs,
|
|
PUNICODE_STRING *prgustrDest);
|
|
|
|
DWORD
|
|
DfspSetupNullSession(
|
|
LPWSTR wszDCName);
|
|
|
|
BOOL DfspGetDomainGluon(
|
|
LPWSTR wszDomainName,
|
|
LPWSTR wszShareName,
|
|
ULONG cDC,
|
|
PUNICODE_STRING pustrDCNames,
|
|
PDS_GLUON *ppglDomain);
|
|
|
|
PDS_MACHINE
|
|
DfspGetDSMachine(
|
|
PUNICODE_STRING pustrDomain,
|
|
PUNICODE_STRING pustrName,
|
|
PUNICODE_STRING pustrShare);
|
|
|
|
VOID
|
|
DfspFreeDSGluon(
|
|
PDS_GLUON pdsGluon);
|
|
|
|
BOOL
|
|
DfspSetDomainInfo (
|
|
IN PDS_GLUON pglDomain);
|
|
|
|
INIT_TADDRESS_MARSHAL_INFO()
|
|
INIT_DS_TRANSPORT_P_MARSHAL_INFO()
|
|
INIT_DS_TRANSPORT_MARSHAL_INFO()
|
|
INIT_DS_MACHINE_P_MARSHAL_INFO()
|
|
INIT_DS_MACHINE_MARSHAL_INFO()
|
|
INIT_DS_GLUON_MARSHAL_INFO()
|
|
INIT_DS_GLUON_P_MARSHAL_INFO()
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: DfsInitDomainList
|
|
//
|
|
// Synopsis: Initializes the list of trusted domains so that their Dfs's
|
|
// may be accessed.
|
|
//
|
|
// Arguments: None
|
|
//
|
|
// Returns: Nothing.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
VOID
|
|
DfsInitDomainList()
|
|
{
|
|
PWKSTA_INFO_100 wki100;
|
|
DWORD dwErr;
|
|
HKEY hkey;
|
|
|
|
ZeroMemory( &DfsDomainInfo, sizeof(DfsDomainInfo) );
|
|
|
|
//
|
|
// Get our own domain name
|
|
//
|
|
|
|
dwErr = NetWkstaGetInfo( NULL, 100, (LPBYTE *) &wki100 );
|
|
|
|
if (dwErr == ERROR_SUCCESS) {
|
|
|
|
if (wki100->wki100_langroup != NULL) {
|
|
|
|
DfsDomainInfo.ustrThisDomain.Length =
|
|
wcslen(wki100->wki100_langroup) * sizeof(WCHAR);
|
|
|
|
DfsDomainInfo.ustrThisDomain.MaximumLength =
|
|
DfsDomainInfo.ustrThisDomain.Length + sizeof(UNICODE_NULL);
|
|
|
|
DfsDomainInfo.ustrThisDomain.Buffer =
|
|
malloc( DfsDomainInfo.ustrThisDomain.MaximumLength );
|
|
|
|
if (DfsDomainInfo.ustrThisDomain.Buffer != NULL) {
|
|
|
|
wcscpy(
|
|
DfsDomainInfo.ustrThisDomain.Buffer,
|
|
wki100->wki100_langroup);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
NetApiBufferFree( wki100 );
|
|
|
|
}
|
|
|
|
//
|
|
// Next try to open the trusted domain list in the registry...
|
|
//
|
|
|
|
dwErr = RegOpenKey( HKEY_LOCAL_MACHINE, REG_KEY_TRUSTED_DOMAINS, &hkey);
|
|
|
|
if (dwErr == ERROR_SUCCESS) {
|
|
|
|
dwErr = DfspInitDomainListFromRegistry( hkey );
|
|
|
|
RegCloseKey( hkey );
|
|
|
|
}
|
|
|
|
//
|
|
// If either the key was not found, or DfspInitDomainListFromRegistry
|
|
// returned ERROR_FILE_NOT_FOUND, try to initialize the list from the
|
|
// LSA.
|
|
//
|
|
|
|
if (dwErr == ERROR_FILE_NOT_FOUND) {
|
|
|
|
dwErr = DfspInitDomainListFromLSA();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: DfsGetDomainReferral
|
|
//
|
|
// Synopsis: Given the name of a domain, this routine will try to figure
|
|
// out the names of DCs serving that domain. If it can, it will
|
|
// attempt to stick a pkt entry for the domain's dfs into the
|
|
// driver.
|
|
//
|
|
// Arguments: [wszDomain] -- Name of domain.
|
|
//
|
|
// Returns: [STATUS_SUCCESS] -- Successfully created domain pkt entry.
|
|
//
|
|
// [STATUS_INSUFFICIENT_RESOURCES] -- Out of memory condition.
|
|
//
|
|
// [STATUS_OBJECT_NAME_NOT_FOUND] -- wszDomain is not a trusted
|
|
// domain.
|
|
//
|
|
// [STATUS_UNEXPECTED_NETWORK_ERROR] -- Unable to get DC for
|
|
// domain.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
NTSTATUS
|
|
DfsGetDomainReferral(
|
|
IN LPWSTR wszDomain,
|
|
IN LPWSTR wszShare)
|
|
{
|
|
NTSTATUS Status;
|
|
DWORD dwErr;
|
|
ULONG cDCs;
|
|
PUNICODE_STRING rgustrDCNames;
|
|
PDS_GLUON pgl;
|
|
|
|
dwErr = DfspIsThisADomainName( wszDomain );
|
|
|
|
if (dwErr == ERROR_SUCCESS) {
|
|
|
|
dwErr = DfspGetDomainDCs( wszDomain, &rgustrDCNames, &cDCs);
|
|
|
|
if (dwErr == ERROR_SUCCESS) {
|
|
|
|
dwErr = DfspValidateDomainShare(
|
|
wszDomain,
|
|
wszShare,
|
|
rgustrDCNames,
|
|
cDCs);
|
|
|
|
if (dwErr != ERROR_SUCCESS)
|
|
free( rgustrDCNames );
|
|
|
|
}
|
|
|
|
if (dwErr == ERROR_SUCCESS) {
|
|
|
|
if (DfspGetDomainGluon(
|
|
wszDomain, wszShare, cDCs, rgustrDCNames, &pgl)) {
|
|
|
|
if (DfspSetDomainInfo(pgl)) {
|
|
|
|
dwErr = ERROR_SUCCESS;
|
|
|
|
} else {
|
|
|
|
dwErr = ERROR_UNEXP_NET_ERR;
|
|
|
|
}
|
|
|
|
DfspFreeDSGluon( pgl );
|
|
|
|
} else {
|
|
|
|
dwErr = ERROR_NOT_ENOUGH_MEMORY;
|
|
|
|
}
|
|
|
|
free( rgustrDCNames );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
switch (dwErr) {
|
|
case ERROR_SUCCESS:
|
|
Status = STATUS_SUCCESS;
|
|
break;
|
|
|
|
case ERROR_NOT_ENOUGH_MEMORY:
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
break;
|
|
|
|
case ERROR_FILE_NOT_FOUND:
|
|
Status = STATUS_OBJECT_NAME_NOT_FOUND;
|
|
break;
|
|
|
|
default:
|
|
Status = STATUS_UNEXPECTED_NETWORK_ERROR;
|
|
break;
|
|
|
|
}
|
|
|
|
return( Status );
|
|
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: DfspValidateDomainShare
|
|
//
|
|
// Synopsis: Once a list of DCs for a domain name is obtained, this routine
|
|
// validates that the share is valid.
|
|
//
|
|
// Arguments: [wszDomain] -- Name of domain
|
|
// [wszShare] -- Name of share
|
|
// [rgustrDCNames] -- List of DCs
|
|
// [cDCs] -- Number of DCs in rgustrDCNames
|
|
//
|
|
// Returns: [ERROR_SUCCESS] -- Share exists
|
|
//
|
|
// [ERROR_FILE_NOT_FOUND] -- Share does not exist
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
DWORD
|
|
DfspValidateDomainShare(
|
|
LPWSTR wszDomain,
|
|
LPWSTR wszShare,
|
|
PUNICODE_STRING rgustrDCNames,
|
|
DWORD cDCs)
|
|
{
|
|
DWORD i;
|
|
NET_API_STATUS netStatus;
|
|
PSHARE_INFO_1005 pSHI1005;
|
|
BOOLEAN isDfs;
|
|
|
|
for (i = 0; i < cDCs; i++) {
|
|
|
|
netStatus = NetShareGetInfo(
|
|
rgustrDCNames[i].Buffer,
|
|
wszShare,
|
|
1005,
|
|
(PBYTE *) &pSHI1005);
|
|
|
|
if (netStatus == ERROR_SUCCESS) {
|
|
|
|
isDfs = ((pSHI1005->shi1005_flags & SHI1005_FLAGS_DFS) != 0);
|
|
|
|
NetApiBufferFree( pSHI1005 );
|
|
|
|
if (isDfs) {
|
|
return( ERROR_SUCCESS );
|
|
} else {
|
|
return( ERROR_FILE_NOT_FOUND );
|
|
}
|
|
|
|
} else if (netStatus == NERR_NetNameNotFound) {
|
|
|
|
return( ERROR_FILE_NOT_FOUND );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return( ERROR_FILE_NOT_FOUND );
|
|
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: DfspInitDomainListFromRegistry
|
|
//
|
|
// Synopsis: Reads the trusted domain list from the registry.
|
|
//
|
|
// Arguments: [hkey] -- Handle to the key that contains the
|
|
// TrustedDomainList value.
|
|
//
|
|
// Returns: [ERROR_SUCCESS] -- Successfully read in the list
|
|
//
|
|
// [ERROR_NOT_ENOUGH_MEMORY] -- Unable to allocate memory for
|
|
// list.
|
|
//
|
|
// [ERROR_FILE_NOT_FOUND] -- Unable to find the
|
|
// TrustedDomainList value in the registry.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
DWORD
|
|
DfspInitDomainListFromRegistry(
|
|
IN HKEY hkey)
|
|
{
|
|
DWORD dwErr, dwType, cbSize;
|
|
PBYTE pBuffer = NULL;
|
|
|
|
cbSize = 1024;
|
|
|
|
do {
|
|
|
|
if (pBuffer)
|
|
free( pBuffer );
|
|
|
|
pBuffer = (PBYTE) malloc( cbSize );
|
|
|
|
if (pBuffer != NULL) {
|
|
|
|
dwErr = RegQueryValueEx(
|
|
hkey,
|
|
REG_VALUE_TRUSTED_DOMAINS,
|
|
NULL,
|
|
&dwType,
|
|
pBuffer,
|
|
&cbSize);
|
|
|
|
} else {
|
|
|
|
dwErr = ERROR_NOT_ENOUGH_MEMORY;
|
|
|
|
}
|
|
|
|
} while ( dwErr == ERROR_MORE_DATA );
|
|
|
|
if (dwErr == ERROR_SUCCESS) {
|
|
|
|
//
|
|
// Good, we have the data. Now, we simply have to put them in the
|
|
// rgustrDomains list. The returned buffer contains a list of
|
|
// NULL terminated domain names, with the last one doubly NULL
|
|
// terminated.
|
|
//
|
|
|
|
PWCHAR pwch = (PWCHAR) pBuffer;
|
|
|
|
while (*pwch != UNICODE_NULL) {
|
|
|
|
if (*(pwch+1) == UNICODE_NULL) {
|
|
|
|
DfsDomainInfo.cDomains++;
|
|
|
|
pwch++;
|
|
|
|
}
|
|
|
|
pwch++;
|
|
|
|
}
|
|
|
|
DfsDomainInfo.rgustrDomains = (PUNICODE_STRING) malloc(
|
|
DfsDomainInfo.cDomains *
|
|
sizeof(UNICODE_STRING));
|
|
|
|
if (DfsDomainInfo.rgustrDomains != NULL) {
|
|
|
|
ULONG i;
|
|
|
|
DfsDomainInfo.wszNameBuffer = (LPWSTR) pBuffer;
|
|
|
|
DfsDomainInfo.cbNameBuffer = cbSize;
|
|
|
|
for (i = 0, pwch = (PWCHAR) pBuffer;
|
|
i < DfsDomainInfo.cDomains;
|
|
i++) {
|
|
|
|
RtlInitUnicodeString(
|
|
&DfsDomainInfo.rgustrDomains[i],
|
|
pwch);
|
|
|
|
pwch += (DfsDomainInfo.rgustrDomains[i].Length +
|
|
sizeof(UNICODE_NULL)) / sizeof(WCHAR);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
dwErr = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
}
|
|
|
|
if ((dwErr != ERROR_SUCCESS) && (pBuffer != NULL))
|
|
free( pBuffer );
|
|
|
|
return( dwErr );
|
|
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: DfspInitDomainListFromLSA
|
|
//
|
|
// Synopsis: Retrieves the list of trusted domains from the LSA.
|
|
//
|
|
// Arguments: None
|
|
//
|
|
// Returns: [ERROR_SUCCESS] -- Successfully inited list.
|
|
//
|
|
// [ERROR_NOT_ENOUGH_MEMORY] -- Out of memory condition
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
DWORD
|
|
DfspInitDomainListFromLSA()
|
|
{
|
|
DWORD dwErr;
|
|
NTSTATUS status;
|
|
OBJECT_ATTRIBUTES oa;
|
|
LSA_HANDLE hlsa;
|
|
LSA_ENUMERATION_HANDLE hEnum = (LSA_ENUMERATION_HANDLE) NULL;
|
|
PLSA_TRUST_INFORMATION rglsaDomainInfo = NULL;
|
|
|
|
ZeroMemory( &oa, sizeof(OBJECT_ATTRIBUTES) );
|
|
|
|
status = LsaOpenPolicy(
|
|
NULL, // SystemName
|
|
&oa, // LSA Object Attributes
|
|
POLICY_VIEW_LOCAL_INFORMATION, // Desired Access
|
|
&hlsa);
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
|
|
do {
|
|
|
|
ULONG cEnum;
|
|
|
|
status = LsaEnumerateTrustedDomains(
|
|
hlsa,
|
|
&hEnum,
|
|
(PVOID) &rglsaDomainInfo,
|
|
LSA_MAXIMUM_ENUMERATION_LENGTH,
|
|
&cEnum);
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
|
|
status = DfspInsertLsaDomainList(
|
|
rglsaDomainInfo,
|
|
cEnum);
|
|
|
|
LsaFreeReturnBuffer( rglsaDomainInfo );
|
|
|
|
}
|
|
|
|
} while ( status == STATUS_SUCCESS );
|
|
|
|
}
|
|
|
|
switch (status) {
|
|
case STATUS_SUCCESS:
|
|
case STATUS_NO_MORE_ENTRIES:
|
|
dwErr = ERROR_SUCCESS;
|
|
break;
|
|
|
|
case STATUS_INSUFFICIENT_RESOURCES:
|
|
dwErr = ERROR_NOT_ENOUGH_MEMORY;
|
|
break;
|
|
|
|
default:
|
|
dwErr = ERROR_UNEXP_NET_ERR;
|
|
break;
|
|
|
|
}
|
|
|
|
return( dwErr );
|
|
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: DfspInsertLsaDomainList
|
|
//
|
|
// Synopsis: Helper function to insert a part of the trusted domain list
|
|
// into the DfsDomainInfo.
|
|
//
|
|
// Arguments: [rglsaDomainList] -- Array of LSA_TRUST_INFORMATIONs.
|
|
// [cDomains] -- Number of elements in rglsaDomainList
|
|
//
|
|
// Returns: [STATUS_SUCCESS] -- Successfully appended domain list to
|
|
// DfsDomainInfo.
|
|
//
|
|
// [STATUS_INSUFFICIENT_RESOURCES] -- Unable to allocate memory
|
|
// for new list.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
NTSTATUS
|
|
DfspInsertLsaDomainList(
|
|
PLSA_TRUST_INFORMATION rglsaDomainList,
|
|
ULONG cDomains)
|
|
{
|
|
PUNICODE_STRING rgustrDomains = NULL;
|
|
PWSTR wszNameBuffer = NULL, pwch;
|
|
ULONG cTotalDomains, cbNameBuffer, i, j;
|
|
|
|
cTotalDomains = DfsDomainInfo.cDomains + cDomains;
|
|
|
|
cbNameBuffer = DfsDomainInfo.cbNameBuffer;
|
|
|
|
for (i = 0; i < cDomains; i++) {
|
|
|
|
cbNameBuffer += rglsaDomainList[i].Name.Length + sizeof(UNICODE_NULL);
|
|
|
|
}
|
|
|
|
wszNameBuffer = (PWSTR) malloc( cbNameBuffer );
|
|
|
|
if (wszNameBuffer == NULL) {
|
|
|
|
return( STATUS_INSUFFICIENT_RESOURCES );
|
|
|
|
}
|
|
|
|
rgustrDomains = (PUNICODE_STRING) malloc(
|
|
cTotalDomains * sizeof(UNICODE_STRING));
|
|
|
|
if (rgustrDomains == NULL) {
|
|
|
|
free( wszNameBuffer );
|
|
|
|
return( STATUS_INSUFFICIENT_RESOURCES );
|
|
|
|
}
|
|
|
|
//
|
|
// Copy over the existing DfsDomainInfo
|
|
//
|
|
|
|
if (DfsDomainInfo.cDomains != 0) {
|
|
|
|
CopyMemory(
|
|
wszNameBuffer,
|
|
DfsDomainInfo.wszNameBuffer,
|
|
DfsDomainInfo.cbNameBuffer);
|
|
|
|
CopyMemory(
|
|
rgustrDomains,
|
|
DfsDomainInfo.rgustrDomains,
|
|
DfsDomainInfo.cDomains * sizeof(UNICODE_STRING));
|
|
|
|
}
|
|
|
|
pwch = (PWSTR) (((PCHAR) wszNameBuffer) + DfsDomainInfo.cbNameBuffer);
|
|
|
|
for (j = 0, i = DfsDomainInfo.cDomains; j < cDomains; j++, i++) {
|
|
|
|
CopyMemory(
|
|
pwch,
|
|
rglsaDomainList[j].Name.Buffer,
|
|
rglsaDomainList[j].Name.Length);
|
|
|
|
pwch[ rglsaDomainList[j].Name.Length / sizeof(WCHAR) ] = UNICODE_NULL;
|
|
|
|
RtlInitUnicodeString( &rgustrDomains[i], pwch);
|
|
|
|
pwch += (rglsaDomainList[j].Name.Length / sizeof(WCHAR) + 1);
|
|
|
|
}
|
|
|
|
if (DfsDomainInfo.cDomains != 0) {
|
|
|
|
free( DfsDomainInfo.rgustrDomains );
|
|
|
|
free( DfsDomainInfo.wszNameBuffer );
|
|
|
|
}
|
|
|
|
DfsDomainInfo.cDomains = cTotalDomains;
|
|
|
|
DfsDomainInfo.rgustrDomains = rgustrDomains;
|
|
|
|
DfsDomainInfo.wszNameBuffer = wszNameBuffer;
|
|
|
|
DfsDomainInfo.cbNameBuffer = cbNameBuffer;
|
|
|
|
return( STATUS_SUCCESS );
|
|
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: DfspIsThisADomainName
|
|
//
|
|
// Synopsis: Runs down the list of domains in DfsDomainInfo and tries
|
|
// to match the given name with one of the entries in the list.
|
|
//
|
|
// Arguments: [wszName] -- Name to find in DfsDomainInfo
|
|
//
|
|
// Returns: [ERROR_SUCCESS] -- Name is indeed a domain name.
|
|
//
|
|
// [ERROR_FILE_NOT_FOUND] -- Name is not in the DfsDomainInfo
|
|
// list.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
DWORD
|
|
DfspIsThisADomainName(
|
|
LPWSTR wszName)
|
|
{
|
|
USHORT cbLength, i;
|
|
BOOL fFound = FALSE;
|
|
|
|
cbLength = wcslen( wszName ) * sizeof(WCHAR);
|
|
|
|
if (cbLength == DfsDomainInfo.ustrThisDomain.Length) {
|
|
|
|
fFound = (_wcsnicmp(
|
|
wszName,
|
|
DfsDomainInfo.ustrThisDomain.Buffer,
|
|
DfsDomainInfo.ustrThisDomain.Length/sizeof(WCHAR))
|
|
== 0);
|
|
|
|
}
|
|
|
|
for (i = 0; i < DfsDomainInfo.cDomains && !fFound; i++) {
|
|
|
|
if (cbLength == DfsDomainInfo.rgustrDomains[i].Length) {
|
|
|
|
fFound = (_wcsnicmp(
|
|
wszName,
|
|
DfsDomainInfo.rgustrDomains[i].Buffer,
|
|
cbLength/sizeof(WCHAR)) == 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return( fFound ? ERROR_SUCCESS : ERROR_FILE_NOT_FOUND );
|
|
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: DfspGetDomainDCs
|
|
//
|
|
// Synopsis: Given a domain name, this routine will figure out the name
|
|
// of an available DC. This routine has been based on the routine
|
|
// UaspOpenDomainWithDomainName in \nt\private\net\access\uasp.c
|
|
//
|
|
// The main purpose of this routine is to try and find the best
|
|
// DC for this machine. Simply calling I_NetGetDCList will work,
|
|
// but in reality, it will typically contain a large list of DCs,
|
|
// most of which will be unavailable.
|
|
//
|
|
// The algorithm is as follows:
|
|
//
|
|
// - Try NetGetAnyDCName. This will work if this machine has a
|
|
// secure channel to the target domain.
|
|
// - If this machine is not a DC, try remoting NetGetAnyDCName
|
|
// to our DC. This will work if our DC has a secure
|
|
// channel to the target domain.
|
|
// - If step 2 fails with ERROR_ACCESS_DENIED, setup a NULL
|
|
// session to our DC and try remoting NetGetAnyDCName
|
|
// again.
|
|
// - If all the steps above fail, use I_NetGetDCList to get a
|
|
// list of all the DCs. When we stick this into the
|
|
// driver, it will randomize the list and try to find an
|
|
// active DC.
|
|
//
|
|
// Arguments: [wszDomain] -- Name of domain.
|
|
// [prgustrDCNames] -- On successful return, contains a pointer
|
|
// to an array of DC names. Free this pointer using
|
|
// free. Do NOT free the buffers of the member strings.
|
|
// [pcDCCount] -- On successful return, number of DCs in
|
|
// prgustrDCNames.
|
|
//
|
|
// Returns: [ERROR_SUCCESS] -- Successfully returning DC names.
|
|
//
|
|
// [ERROR_CANT_ACCESS_DOMAIN_INFO] -- Unable to get DC names.
|
|
//
|
|
// [ERROR_NOT_ENOUGH_MEMORY] -- Out of memory situation.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
DWORD
|
|
DfspGetDomainDCs(
|
|
LPWSTR wszDomain,
|
|
PUNICODE_STRING *prgustrDCNames,
|
|
PULONG pcDCCount)
|
|
{
|
|
DWORD dwErr;
|
|
LPWSTR wszServer, wszMyDomainDC;
|
|
PUNICODE_STRING pustrDCNames;
|
|
|
|
//
|
|
// 1. Try NetGetAnyDCName
|
|
//
|
|
|
|
dwErr = NetGetAnyDCName( NULL, wszDomain, (LPBYTE *) &wszServer);
|
|
|
|
if (dwErr == ERROR_SUCCESS) {
|
|
|
|
dwErr = DfspArrayFromServerName( wszServer, prgustrDCNames );
|
|
|
|
NetApiBufferFree( wszServer );
|
|
|
|
*pcDCCount = 1;
|
|
|
|
return( dwErr );
|
|
|
|
}
|
|
|
|
//
|
|
// 2. If this machine is not a DC, try remoting NetGetAnyDC to our DC.
|
|
//
|
|
|
|
dwErr = NetGetAnyDCName( NULL, NULL, (LPBYTE *) &wszMyDomainDC );
|
|
|
|
if (dwErr == ERROR_SUCCESS) {
|
|
|
|
dwErr = NetGetAnyDCName(
|
|
wszMyDomainDC,
|
|
wszDomain,
|
|
(LPBYTE *) &wszServer );
|
|
|
|
if (dwErr == ERROR_ACCESS_DENIED) {
|
|
|
|
//
|
|
// 3. Setup a NULL session to our DC, and retry the call.
|
|
//
|
|
|
|
DWORD dwErrNullSession;
|
|
|
|
dwErrNullSession = DfspSetupNullSession( wszMyDomainDC );
|
|
|
|
if (dwErrNullSession == ERROR_SUCCESS ) {
|
|
|
|
dwErr = NetGetAnyDCName(
|
|
wszMyDomainDC,
|
|
wszDomain,
|
|
(LPBYTE *) &wszServer);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
NetApiBufferFree( wszMyDomainDC );
|
|
|
|
if (dwErr == ERROR_SUCCESS) {
|
|
|
|
dwErr = DfspArrayFromServerName( wszServer, prgustrDCNames );
|
|
|
|
NetApiBufferFree( wszServer );
|
|
|
|
*pcDCCount = 1;
|
|
|
|
return( dwErr );
|
|
|
|
}
|
|
|
|
} else if (dwErr == ERROR_NO_LOGON_SERVERS) {
|
|
|
|
return( ERROR_CANT_ACCESS_DOMAIN_INFO );
|
|
|
|
}
|
|
|
|
//
|
|
// 4. Simply call I_NetGetDCList to retrieve set of all DCs.
|
|
//
|
|
|
|
dwErr = I_NetGetDCList(
|
|
NULL,
|
|
wszDomain,
|
|
pcDCCount,
|
|
&pustrDCNames);
|
|
|
|
if (dwErr != ERROR_SUCCESS) {
|
|
|
|
return( ERROR_CANT_ACCESS_DOMAIN_INFO );
|
|
|
|
}
|
|
|
|
if (*pcDCCount == 0) {
|
|
|
|
return( ERROR_CANT_ACCESS_DOMAIN_INFO );
|
|
|
|
}
|
|
|
|
//
|
|
// We'll have to duplicate the array because NetApiXXX might be using a
|
|
// different allocator.
|
|
//
|
|
|
|
dwErr = DfspDuplicateArray( pustrDCNames, pcDCCount, prgustrDCNames );
|
|
|
|
NetApiBufferFree( pustrDCNames );
|
|
|
|
//
|
|
// I_NetGetDCList returns a NULL UNICODE_STRING if the PDC is down.
|
|
// DfspDuplicateArray would have stripped this entry out, so our
|
|
// DC Count may have dropped down to 0. Check for this here.
|
|
//
|
|
|
|
if (dwErr == ERROR_SUCCESS && *pcDCCount == 0) {
|
|
|
|
free( *prgustrDCNames );
|
|
|
|
dwErr = ERROR_CANT_ACCESS_DOMAIN_INFO;
|
|
|
|
}
|
|
|
|
return( dwErr );
|
|
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: DfspArrayFromServerName
|
|
//
|
|
// Synopsis: Helper function for DfspGetDomainDCs. Stuffs a ServerName into
|
|
// an 1 element array of UNICODE_STRINGs. Allocates the array
|
|
// and space for the ServerName using malloc
|
|
//
|
|
// Arguments: [wszServer] -- Name of Server.
|
|
// [prgustrDCName] -- On successful return, contains pointer to
|
|
// array of DC names.
|
|
//
|
|
// Returns: [ERROR_SUCCESS] -- Successfully completed operation.
|
|
//
|
|
// [ERROR_NOT_ENOUGH_MEMORY] -- Unable to allocate memory for
|
|
// array.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
DWORD
|
|
DfspArrayFromServerName(
|
|
LPWSTR wszServer,
|
|
PUNICODE_STRING *prgustrDCNames)
|
|
{
|
|
PUNICODE_STRING rgustrDCNames;
|
|
LPWSTR wszNameBuffer;
|
|
|
|
rgustrDCNames = (PUNICODE_STRING) malloc(
|
|
sizeof(UNICODE_STRING) +
|
|
wcslen(wszServer) * sizeof(WCHAR) +
|
|
sizeof(UNICODE_NULL));
|
|
|
|
if (rgustrDCNames != NULL) {
|
|
|
|
wszNameBuffer = (LPWSTR) (rgustrDCNames + 1);
|
|
|
|
wcscpy( wszNameBuffer, wszServer );
|
|
|
|
RtlInitUnicodeString( &rgustrDCNames[0], wszNameBuffer );
|
|
|
|
*prgustrDCNames = rgustrDCNames;
|
|
|
|
return( ERROR_SUCCESS );
|
|
|
|
} else {
|
|
|
|
return( ERROR_NOT_ENOUGH_MEMORY );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: DfspDuplicateArray
|
|
//
|
|
// Synopsis: Helper function for DfspGetDomainDCs. This function duplicates
|
|
// the array returned by I_NetGetDCList.
|
|
//
|
|
// Note that I_NetGetDCList returns a NULL UNICODE_STRING for
|
|
// the PDC if the PDC is down. DfspDuplicateArray will NOT copy
|
|
// this NULL string to the destination. On return, *pcDCs will be
|
|
// suitably adjusted.
|
|
//
|
|
// Arguments: [prgustrDCNames] -- Array of DC names.
|
|
// [pcDCs] -- On entry, count of DCs in prgustrDCNames. On
|
|
// successful return, count of DCs in prgustrDest.
|
|
// [prgustrDest] -- On successful return, contains a pointer
|
|
// to the array of DC names.
|
|
//
|
|
// Returns: [ERROR_SUCCESS] -- Successfully duplicate array.
|
|
//
|
|
// [ERROR_NOT_ENOUGH_MEMORY] -- Out of memory condition
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
DWORD
|
|
DfspDuplicateArray(
|
|
PUNICODE_STRING prgustrDCNames,
|
|
PULONG pcDCs,
|
|
PUNICODE_STRING *prgustrDest)
|
|
{
|
|
ULONG i, j, cbBuffer, cDCs;
|
|
PUNICODE_STRING rgustrNew;
|
|
LPWSTR wszNames;
|
|
|
|
cDCs = *pcDCs;
|
|
|
|
cbBuffer = cDCs * sizeof(UNICODE_STRING);
|
|
|
|
for(i = 0; i < cDCs; i++) {
|
|
|
|
cbBuffer += prgustrDCNames[i].Length + sizeof(WCHAR);
|
|
|
|
}
|
|
|
|
rgustrNew = (PUNICODE_STRING) malloc( cbBuffer );
|
|
|
|
if (rgustrNew != NULL) {
|
|
|
|
wszNames = (LPWSTR) &rgustrNew[cDCs];
|
|
|
|
for (i = 0, j = 0; i < cDCs; i++) {
|
|
|
|
if (prgustrDCNames[i].Length == 0) {
|
|
continue;
|
|
}
|
|
|
|
CopyMemory(
|
|
wszNames,
|
|
prgustrDCNames[i].Buffer,
|
|
prgustrDCNames[i].Length);
|
|
|
|
wszNames[ prgustrDCNames[i].Length/sizeof(WCHAR) ] = UNICODE_NULL;
|
|
|
|
RtlInitUnicodeString( &rgustrNew[j], wszNames );
|
|
|
|
j++;
|
|
|
|
wszNames += (prgustrDCNames[i].Length / sizeof(WCHAR)) + 1;
|
|
|
|
}
|
|
|
|
*prgustrDest = rgustrNew;
|
|
|
|
*pcDCs = j;
|
|
|
|
return( ERROR_SUCCESS );
|
|
|
|
} else {
|
|
|
|
return( ERROR_NOT_ENOUGH_MEMORY );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: DfspSetupNullSession
|
|
//
|
|
// Synopsis: Helper function for DfspGetDomainDCs. This one sets up a NULL
|
|
// session to a DC's IPC$ share.
|
|
//
|
|
// Arguments: [wszDCName] -- Name of DC to setup a NULL session with.
|
|
//
|
|
// Returns: Result of NetUseAdd
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
DWORD
|
|
DfspSetupNullSession(
|
|
LPWSTR wszDCName)
|
|
{
|
|
DWORD dwErr;
|
|
USE_INFO_2 ui2;
|
|
LPWSTR wszDCIPCShare;
|
|
|
|
wszDCIPCShare = (LPWSTR) malloc(
|
|
wcslen(wszDCName) * sizeof(WCHAR) +
|
|
sizeof(ROOT_SHARE_NAME));
|
|
|
|
if (wszDCIPCShare != NULL) {
|
|
|
|
wcscpy( wszDCIPCShare, wszDCName );
|
|
|
|
wcscat( wszDCIPCShare, ROOT_SHARE_NAME );
|
|
|
|
ui2.ui2_local = NULL;
|
|
ui2.ui2_remote = wszDCIPCShare;
|
|
ui2.ui2_password = L"";
|
|
ui2.ui2_asg_type = USE_IPC;
|
|
ui2.ui2_username = L"";
|
|
ui2.ui2_domainname = L"";
|
|
|
|
dwErr = NetUseAdd( NULL, 2, (LPBYTE) &ui2, NULL );
|
|
|
|
free( wszDCIPCShare );
|
|
|
|
} else {
|
|
|
|
dwErr = ERROR_NOT_ENOUGH_MEMORY;
|
|
|
|
}
|
|
|
|
return( dwErr );
|
|
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: DfspGetDomainGluon
|
|
//
|
|
// Synopsis: Constructs a DS_GLUON for the domain volume, given the
|
|
// name of the domain and the list of DCs in that domain.
|
|
//
|
|
// Arguments: [wszDomainName] -- Name of domain
|
|
// [wszShareName] -- Name of share at root of domain Dfs
|
|
// [cDC] -- Count of DCs in the domain
|
|
// [pustrDCNames] -- Array of count DC names.
|
|
// [pglDomain] -- The constructed DS_GLUON
|
|
//
|
|
// Returns: TRUE if success, FALSE otherwise.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
BOOL DfspGetDomainGluon(
|
|
LPWSTR wszDomainName,
|
|
LPWSTR wszShareName,
|
|
ULONG cDC,
|
|
PUNICODE_STRING pustrDCNames,
|
|
PDS_GLUON *ppglDomain)
|
|
{
|
|
|
|
LPWSTR pwszDomainPrefix;
|
|
PDS_GLUON pglDomain = NULL;
|
|
UNICODE_STRING ustrDomain, ustrShare;
|
|
ULONG i;
|
|
BOOL fSuccess = TRUE;
|
|
|
|
RtlInitUnicodeString( &ustrDomain, wszDomainName );
|
|
RtlInitUnicodeString( &ustrShare, wszShareName );
|
|
|
|
pwszDomainPrefix = malloc(
|
|
sizeof(UNICODE_PATH_SEP) +
|
|
wcslen(wszDomainName) * sizeof(WCHAR) +
|
|
sizeof(UNICODE_PATH_SEP) +
|
|
wcslen(wszShareName) * sizeof(WCHAR) +
|
|
sizeof(UNICODE_NULL));
|
|
|
|
if (pwszDomainPrefix != NULL) {
|
|
|
|
wcscpy( pwszDomainPrefix, UNICODE_PATH_SEP_STR );
|
|
wcscat( pwszDomainPrefix, wszDomainName );
|
|
wcscat( pwszDomainPrefix, UNICODE_PATH_SEP_STR );
|
|
wcscat( pwszDomainPrefix, wszShareName );
|
|
|
|
} else {
|
|
|
|
fSuccess = FALSE;
|
|
|
|
}
|
|
|
|
if (fSuccess) {
|
|
|
|
pglDomain = malloc(sizeof(DS_GLUON) + cDC * sizeof(PDS_MACHINE));
|
|
|
|
}
|
|
|
|
if (pglDomain != NULL) {
|
|
|
|
ZeroMemory( &pglDomain->guidThis, sizeof(DS_GLUON) +
|
|
cDC * sizeof(PDS_MACHINE));
|
|
|
|
pglDomain->pwszName = pwszDomainPrefix;
|
|
|
|
pglDomain->cMachines = cDC;
|
|
|
|
for (i = 0; (i < cDC) && fSuccess; i++) {
|
|
|
|
//
|
|
// Get rid of the leading double backslashes
|
|
//
|
|
|
|
if (pustrDCNames[i].Length > 2 * sizeof(WCHAR) &&
|
|
pustrDCNames[i].Buffer[0] == UNICODE_PATH_SEP &&
|
|
pustrDCNames[i].Buffer[1] == UNICODE_PATH_SEP) {
|
|
|
|
pustrDCNames[i].Length -= 2 * sizeof(WCHAR);
|
|
|
|
MoveMemory(
|
|
pustrDCNames[i].Buffer,
|
|
&pustrDCNames[i].Buffer[2],
|
|
pustrDCNames[i].Length);
|
|
|
|
}
|
|
|
|
pglDomain->rpMachines[i] = DfspGetDSMachine(
|
|
&ustrDomain,
|
|
&pustrDCNames[i],
|
|
&ustrShare);
|
|
|
|
if (pglDomain->rpMachines[i] == NULL) {
|
|
|
|
pglDomain->cMachines = i; // To facilitate cleanup
|
|
|
|
fSuccess = FALSE;
|
|
|
|
}
|
|
}
|
|
|
|
} else {
|
|
|
|
fSuccess = FALSE;
|
|
|
|
}
|
|
|
|
//
|
|
// Cleanup if error
|
|
//
|
|
|
|
if (!fSuccess) {
|
|
|
|
if (pglDomain != NULL) {
|
|
|
|
DfspFreeDSGluon( pglDomain );
|
|
|
|
} else if (pwszDomainPrefix != NULL) {
|
|
|
|
free( pwszDomainPrefix );
|
|
|
|
}
|
|
|
|
*ppglDomain = NULL;
|
|
|
|
} else {
|
|
|
|
*ppglDomain = pglDomain;
|
|
|
|
}
|
|
|
|
return( fSuccess );
|
|
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: DfspGetDSMachine
|
|
//
|
|
// Synopsis: Given a NetBIOS name, this routine constructs a DS_MACHINE
|
|
// struct with 1 transport.
|
|
//
|
|
// Arguments: [pustrDomain] -- The Domain name of the machine.
|
|
// [pustrName] -- The NetBIOS name of the machine.
|
|
// [pustrShare] -- The share name to connect to on the machine
|
|
//
|
|
// Returns: Pointer to allocated DS_MACHINE, or NULL if failure.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#define SIZE_OF_DS_MACHINE_WITH_1_ADDR \
|
|
(sizeof(DS_MACHINE) + sizeof(LPWSTR) + sizeof(DS_TRANSPORT) + sizeof(TDI_ADDRESS_NETBIOS))
|
|
|
|
PDS_MACHINE
|
|
DfspGetDSMachine(
|
|
PUNICODE_STRING pustrDomain,
|
|
PUNICODE_STRING pustrName,
|
|
PUNICODE_STRING pustrShare)
|
|
{
|
|
|
|
PDS_MACHINE pdsMachine;
|
|
PDS_TRANSPORT pdsTransport;
|
|
PTDI_ADDRESS_NETBIOS ptdiNB;
|
|
|
|
LPWSTR wszPrincipalName;
|
|
LPWSTR wszShareName;
|
|
|
|
pdsMachine = malloc( SIZE_OF_DS_MACHINE_WITH_1_ADDR +
|
|
pustrName->Length +
|
|
sizeof(UNICODE_NULL) +
|
|
pustrShare->Length +
|
|
sizeof(UNICODE_NULL));
|
|
|
|
if (pdsMachine != NULL) {
|
|
|
|
ZeroMemory( pdsMachine, sizeof(DS_MACHINE) );
|
|
|
|
//
|
|
// Insert the principal name - simply machine name
|
|
//
|
|
|
|
pdsMachine->cPrincipals = 1;
|
|
|
|
wszPrincipalName = (LPWSTR) (((PCHAR) pdsMachine) +
|
|
SIZE_OF_DS_MACHINE_WITH_1_ADDR);
|
|
CopyMemory(
|
|
wszPrincipalName,
|
|
pustrName->Buffer,
|
|
pustrName->Length);
|
|
|
|
wszPrincipalName[pustrName->Length / sizeof(WCHAR)] = UNICODE_NULL;
|
|
|
|
pdsMachine->prgpwszPrincipals = (LPWSTR *) (pdsMachine + 1);
|
|
|
|
pdsMachine->prgpwszPrincipals[0] = wszPrincipalName;
|
|
|
|
wszShareName = &wszPrincipalName[pustrName->Length/sizeof(WCHAR) + 1];
|
|
|
|
CopyMemory(
|
|
wszShareName,
|
|
pustrShare->Buffer,
|
|
pustrShare->Length);
|
|
|
|
wszShareName[pustrShare->Length/sizeof(WCHAR)] = UNICODE_NULL;
|
|
|
|
pdsMachine->pwszShareName = wszShareName;
|
|
|
|
//
|
|
// Build the NetBIOS DS_TRANSPORT structure
|
|
//
|
|
|
|
pdsMachine->cTransports = 1;
|
|
|
|
pdsTransport = (PDS_TRANSPORT) (pdsMachine + 1);
|
|
|
|
pdsTransport = (PDS_TRANSPORT)
|
|
(((PUCHAR) pdsTransport) + sizeof(LPWSTR));
|
|
|
|
pdsMachine->rpTrans[0] = pdsTransport;
|
|
|
|
pdsTransport->usFileProtocol = FSP_SMB;
|
|
|
|
pdsTransport->iPrincipal = 0;
|
|
|
|
pdsTransport->grfModifiers = 0;
|
|
|
|
//
|
|
// Build the TA_ADDRESS_NETBIOS
|
|
//
|
|
|
|
pdsTransport->taddr.AddressLength = sizeof(TDI_ADDRESS_NETBIOS);
|
|
|
|
pdsTransport->taddr.AddressType = TDI_ADDRESS_TYPE_NETBIOS;
|
|
|
|
ptdiNB = (PTDI_ADDRESS_NETBIOS) &pdsTransport->taddr.Address[0];
|
|
|
|
ptdiNB->NetbiosNameType = TDI_ADDRESS_NETBIOS_TYPE_UNIQUE;
|
|
|
|
FillMemory( &ptdiNB->NetbiosName[0], 16, ' ' );
|
|
|
|
wcstombs(
|
|
&ptdiNB->NetbiosName[0],
|
|
pustrName->Buffer,
|
|
pustrName->Length/sizeof(WCHAR));
|
|
|
|
}
|
|
|
|
return( pdsMachine );
|
|
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: DfspFreeDSGluon
|
|
//
|
|
// Synopsis: Frees memory associated with a DS_GLUON constructed by
|
|
// DfspGetDomainGluon
|
|
//
|
|
// Arguments: [pdsGluon] -- The victim DS_GLUON
|
|
//
|
|
// Returns: Nothing
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
VOID
|
|
DfspFreeDSGluon(
|
|
PDS_GLUON pdsGluon)
|
|
{
|
|
|
|
ULONG i;
|
|
|
|
if (pdsGluon->pwszName != NULL) {
|
|
|
|
free( pdsGluon->pwszName );
|
|
|
|
}
|
|
|
|
for (i = 0; i < pdsGluon->cMachines; i++) {
|
|
|
|
if (pdsGluon->rpMachines[i] != NULL) {
|
|
|
|
free( pdsGluon->rpMachines[i] );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
free( pdsGluon );
|
|
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: DfspSetDomainInfo
|
|
//
|
|
// Synopsis: Takes a gluon for the DCs of the domain and primes the Dfs
|
|
// driver with it.
|
|
//
|
|
// Arguments: [pglDomain] -- gluon for the machine domain's DCs
|
|
// [iConnectedDC] -- index into gluon of the particular DC that
|
|
// is to be preferred. If this index is 0xFFFF,
|
|
// no DC is given preference.
|
|
//
|
|
// Returns: TRUE if Dfs successfully primed with Domain Info, FALSE
|
|
// otherwise.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
BOOL
|
|
DfspSetDomainInfo (
|
|
IN PDS_GLUON pglDomain)
|
|
{
|
|
NTSTATUS Status;
|
|
HANDLE hDfs;
|
|
MARSHAL_BUFFER marshalBuffer;
|
|
PUCHAR pBuffer = NULL;
|
|
ULONG cbSize;
|
|
DS_GLUON_P glDomainP;
|
|
BOOL fSuccess = FALSE;
|
|
|
|
glDomainP.pDSGluon = pglDomain;
|
|
cbSize = 0;
|
|
Status = DfsRtlSize(&MiDSGluonP, &glDomainP, &cbSize);
|
|
if (!NT_SUCCESS(Status)) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
pBuffer = malloc( cbSize );
|
|
|
|
if (pBuffer == NULL) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
MarshalBufferInitialize(&marshalBuffer, cbSize, pBuffer);
|
|
|
|
Status = DfsRtlPut(&marshalBuffer, &MiDSGluonP, &glDomainP);
|
|
if (!NT_SUCCESS(Status)) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Good, now that we have everything needed to setup the domain
|
|
// pkt entry. We simply fsctl to the driver to setup the Pkt Entry.
|
|
//
|
|
|
|
Status = DfsOpen( &hDfs, NULL );
|
|
if (!NT_SUCCESS(Status)) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
Status = DfsFsctl(
|
|
hDfs,
|
|
FSCTL_DFS_SET_DOMAIN_GLUON,
|
|
pBuffer,
|
|
cbSize,
|
|
NULL,
|
|
0L);
|
|
|
|
NtClose( hDfs );
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
fSuccess = TRUE;
|
|
|
|
Cleanup:
|
|
|
|
if (pBuffer != NULL) {
|
|
free( pBuffer );
|
|
}
|
|
|
|
return(fSuccess);
|
|
}
|
|
|
|
|
|
UNICODE_STRING LocalDfsName = {
|
|
sizeof(DFS_DRIVER_NAME)-sizeof(UNICODE_NULL),
|
|
sizeof(DFS_DRIVER_NAME)-sizeof(UNICODE_NULL),
|
|
DFS_DRIVER_NAME
|
|
};
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: DfsOpen, public
|
|
//
|
|
// Synopsis:
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Returns:
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
NTSTATUS
|
|
DfsOpen(
|
|
IN OUT PHANDLE DfsHandle,
|
|
IN PUNICODE_STRING DfsName OPTIONAL
|
|
)
|
|
{
|
|
NTSTATUS status;
|
|
OBJECT_ATTRIBUTES objectAttributes;
|
|
IO_STATUS_BLOCK ioStatus;
|
|
PUNICODE_STRING name;
|
|
|
|
if (ARGUMENT_PRESENT(DfsName)) {
|
|
name = DfsName;
|
|
} else {
|
|
name = &LocalDfsName;
|
|
}
|
|
|
|
InitializeObjectAttributes(
|
|
&objectAttributes,
|
|
name,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
status = NtCreateFile(
|
|
DfsHandle,
|
|
SYNCHRONIZE,
|
|
&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);
|
|
|
|
if (NT_SUCCESS(status))
|
|
status = ioStatus.Status;
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: DfsFsctl, public
|
|
//
|
|
// Synopsis:
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Returns:
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
NTSTATUS
|
|
DfsFsctl(
|
|
IN HANDLE DfsHandle,
|
|
IN ULONG FsControlCode,
|
|
IN PVOID InputBuffer OPTIONAL,
|
|
IN ULONG InputBufferLength,
|
|
OUT PVOID OutputBuffer OPTIONAL,
|
|
IN ULONG OutputBufferLength
|
|
)
|
|
{
|
|
NTSTATUS status;
|
|
IO_STATUS_BLOCK ioStatus;
|
|
|
|
status = NtFsControlFile(
|
|
DfsHandle,
|
|
NULL, // Event,
|
|
NULL, // ApcRoutine,
|
|
NULL, // ApcContext,
|
|
&ioStatus,
|
|
FsControlCode,
|
|
InputBuffer,
|
|
InputBufferLength,
|
|
OutputBuffer,
|
|
OutputBufferLength
|
|
);
|
|
|
|
if(NT_SUCCESS(status))
|
|
status = ioStatus.Status;
|
|
|
|
return status;
|
|
}
|
|
|
|
|