mirror of https://github.com/tongzx/nt5src
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.
4098 lines
97 KiB
4098 lines
97 KiB
/*++
|
|
|
|
Copyright (c) 1991 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
COMPNAME.C
|
|
|
|
Abstract:
|
|
|
|
This module contains the GetComputerName and SetComputerName APIs.
|
|
Also: DnsHostnameToComputerName
|
|
AddLocalAlternateComputerName
|
|
RemoveLocalAlternateComputerName
|
|
SetLocalPrimaryComputerName
|
|
EnumerateLocalComputerNames
|
|
|
|
Author:
|
|
|
|
Dan Hinsley (DanHi) 2-Apr-1992
|
|
|
|
|
|
Revision History:
|
|
|
|
Greg Johnson (gregjohn) 13-Feb-2001
|
|
|
|
Notes:
|
|
|
|
Currently there is no way to enumerate the list of Alternate Netbios
|
|
names. Presumably this will be fixed in a future release (Blackcomb?).
|
|
The flags parameter to all the *Local* API's is for this use.
|
|
|
|
--*/
|
|
|
|
#include <basedll.h>
|
|
|
|
#include <dnsapi.h>
|
|
|
|
typedef DNS_STATUS
|
|
(WINAPI DNS_VALIDATE_NAME_FN)(
|
|
IN LPCWSTR Name,
|
|
IN DNS_NAME_FORMAT Format
|
|
);
|
|
//
|
|
//
|
|
|
|
#define REASONABLE_LENGTH 128
|
|
|
|
#define COMPUTERNAME_ROOT \
|
|
L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\ComputerName"
|
|
|
|
#define NON_VOLATILE_COMPUTERNAME_NODE \
|
|
L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\ComputerName\\ComputerName"
|
|
|
|
#define VOLATILE_COMPUTERNAME_NODE \
|
|
L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\ComputerName\\ActiveComputerName"
|
|
|
|
#define ALT_COMPUTERNAME_NODE \
|
|
L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\LanmanServer\\Parameters"
|
|
|
|
#define VOLATILE_COMPUTERNAME L"ActiveComputerName"
|
|
#define NON_VOLATILE_COMPUTERNAME L"ComputerName"
|
|
#define COMPUTERNAME_VALUE_NAME L"ComputerName"
|
|
#define COMPUTERNAME_OPTIONAL_NAME L"OptionalNames"
|
|
#define CLASS_STRING L"Network ComputerName"
|
|
|
|
#define TCPIP_POLICY_ROOT \
|
|
L"\\Registry\\Machine\\Software\\Policies\\Microsoft\\System\\DNSclient"
|
|
|
|
#define TCPIP_POLICY_DOMAINNAME \
|
|
L"PrimaryDnsSuffix"
|
|
|
|
#define TCPIP_ROOT \
|
|
L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\Tcpip\\Parameters"
|
|
|
|
#define TCPIP_HOSTNAME \
|
|
L"Hostname"
|
|
|
|
#define TCPIP_NV_HOSTNAME \
|
|
L"NV Hostname"
|
|
|
|
#define TCPIP_DOMAINNAME \
|
|
L"Domain"
|
|
|
|
#define TCPIP_NV_DOMAINNAME \
|
|
L"NV Domain"
|
|
|
|
#define DNSCACHE_ROOT \
|
|
L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\DnsCache\\Parameters"
|
|
|
|
#define DNS_ALT_HOSTNAME \
|
|
L"AlternateComputerNames"
|
|
|
|
//
|
|
// Allow the cluster guys to override the returned
|
|
// names with their own virtual names
|
|
//
|
|
|
|
const PWSTR ClusterNameVars[] = {
|
|
L"_CLUSTER_NETWORK_NAME_",
|
|
L"_CLUSTER_NETWORK_HOSTNAME_",
|
|
L"_CLUSTER_NETWORK_DOMAIN_",
|
|
L"_CLUSTER_NETWORK_FQDN_"
|
|
};
|
|
|
|
//
|
|
// Disallowed control characters (not including \0)
|
|
//
|
|
|
|
#define CTRL_CHARS_0 L"\001\002\003\004\005\006\007"
|
|
#define CTRL_CHARS_1 L"\010\011\012\013\014\015\016\017"
|
|
#define CTRL_CHARS_2 L"\020\021\022\023\024\025\026\027"
|
|
#define CTRL_CHARS_3 L"\030\031\032\033\034\035\036\037"
|
|
|
|
#define CTRL_CHARS_STR CTRL_CHARS_0 CTRL_CHARS_1 CTRL_CHARS_2 CTRL_CHARS_3
|
|
|
|
//
|
|
// Combinations of the above
|
|
//
|
|
|
|
#define ILLEGAL_NAME_CHARS_STR L"\"/\\[]:|<>+=;,?" CTRL_CHARS_STR
|
|
|
|
WCHAR DnsApiDllString[] = L"DNSAPI.DLL";
|
|
|
|
#define DNS_HOSTNAME 0
|
|
#define DNS_DOMAINNAME 1
|
|
|
|
DWORD
|
|
BaseMultiByteToWideCharWithAlloc(
|
|
LPCSTR lpBuffer,
|
|
LPWSTR * ppBufferW
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Converts Ansi strings to Unicode strings and allocs it's own space.
|
|
|
|
|
|
Arguments:
|
|
|
|
lpBuffer - Ansi to convert
|
|
ppBufferW - Unicode result
|
|
|
|
Return Value:
|
|
|
|
ERROR_SUCCESS, or various failures
|
|
|
|
--*/
|
|
{
|
|
ULONG cchBuffer = 0;
|
|
BOOL fSuccess = TRUE;
|
|
|
|
if (lpBuffer==NULL) {
|
|
*ppBufferW=NULL;
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
cchBuffer = strlen(lpBuffer);
|
|
|
|
// get enough space to cover the string and a trailing null
|
|
*ppBufferW = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( TMP_TAG ), (cchBuffer + 1) * sizeof(WCHAR));
|
|
if (*ppBufferW==NULL) {
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
fSuccess = MultiByteToWideChar(CP_ACP,
|
|
0,
|
|
lpBuffer,
|
|
(cchBuffer+1)*sizeof(CHAR),
|
|
*ppBufferW,
|
|
cchBuffer+1
|
|
);
|
|
if (fSuccess) {
|
|
return ERROR_SUCCESS;
|
|
}
|
|
else {
|
|
return GetLastError();
|
|
}
|
|
}
|
|
|
|
DWORD
|
|
BaseWideCharToMultiByteWithAlloc(
|
|
LPCWSTR lpBuffer,
|
|
LPSTR * ppBufferA
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Converts Unicode strings to Ansi strings and allocs it's own space.
|
|
|
|
|
|
Arguments:
|
|
|
|
lpBuffer - Unicode to convert
|
|
ppBufferA - Ansi result
|
|
|
|
Return Value:
|
|
|
|
ERROR_SUCCESS, or various failures
|
|
|
|
--*/
|
|
{
|
|
ULONG cchBuffer = 0;
|
|
DWORD err = ERROR_SUCCESS;
|
|
|
|
cchBuffer = wcslen(lpBuffer);
|
|
*ppBufferA = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( TMP_TAG ), (cchBuffer + 1) * sizeof(CHAR));
|
|
if (*ppBufferA==NULL) {
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
err = WideCharToMultiByte(CP_ACP,
|
|
0,
|
|
lpBuffer,
|
|
cchBuffer+1,
|
|
*ppBufferA,
|
|
(cchBuffer+1)*sizeof(CHAR),
|
|
NULL,
|
|
NULL
|
|
);
|
|
if (err!=0) {
|
|
return ERROR_SUCCESS;
|
|
}
|
|
else {
|
|
return GetLastError();
|
|
}
|
|
}
|
|
|
|
VOID
|
|
BaseConvertCharFree(
|
|
VOID * lpBuffer
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Frees space Convert functions.
|
|
|
|
|
|
Arguments:
|
|
|
|
lpBuffer - Buffer to free
|
|
|
|
Return Value:
|
|
|
|
None!
|
|
|
|
--*/
|
|
{
|
|
if (lpBuffer!=NULL) {
|
|
RtlFreeHeap(RtlProcessHeap(), 0, lpBuffer);
|
|
}
|
|
}
|
|
|
|
BOOL
|
|
BaseValidateFlags(
|
|
ULONG ulFlags
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Validates unused flags. For now the flags parameter of
|
|
AddLocalAlternateComputerName*
|
|
RemoveLocalAlternateComputerName*
|
|
EnumerateLocalAlternateComputerName*
|
|
SetLocalPrimaryComputerName*
|
|
are all reserved and should be 0. In subsequent releases
|
|
this function should change to check for a mask of valid
|
|
flags.
|
|
|
|
Arguments:
|
|
|
|
ulFlags -
|
|
|
|
Return Value:
|
|
|
|
BOOL
|
|
|
|
--*/
|
|
{
|
|
if (ulFlags!=0) {
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
BaseValidateNetbiosName(
|
|
IN LPCWSTR lpComputerName
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Checks that the input is an acceptable Netbios name.
|
|
|
|
Arguments:
|
|
|
|
lpComputerName - name to validate
|
|
|
|
Return Value:
|
|
|
|
BOOL, GetLastError()
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS NtStatus = STATUS_SUCCESS;
|
|
ULONG cchComputerName;
|
|
ULONG AnsiComputerNameLength;
|
|
|
|
cchComputerName = wcslen(lpComputerName);
|
|
|
|
//
|
|
// The name length limitation should be based on ANSI. (LanMan compatibility)
|
|
//
|
|
|
|
NtStatus = RtlUnicodeToMultiByteSize(&AnsiComputerNameLength,
|
|
(LPWSTR)lpComputerName,
|
|
cchComputerName * sizeof(WCHAR));
|
|
|
|
if ((!NT_SUCCESS(NtStatus)) ||
|
|
(AnsiComputerNameLength == 0 )||(AnsiComputerNameLength > MAX_COMPUTERNAME_LENGTH)) {
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return(FALSE);
|
|
}
|
|
|
|
//
|
|
// Check for illegal characters; return an error if one is found
|
|
//
|
|
|
|
if (wcscspn(lpComputerName, ILLEGAL_NAME_CHARS_STR) < cchComputerName) {
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return(FALSE);
|
|
}
|
|
|
|
//
|
|
// Check for leading or trailing spaces
|
|
//
|
|
|
|
if (lpComputerName[0] == L' ' ||
|
|
lpComputerName[cchComputerName-1] == L' ') {
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return(FALSE);
|
|
|
|
}
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
BOOL
|
|
BaseValidateDnsNames(
|
|
LPCWSTR lpDnsHostname
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Checks that the inputted name is an acceptable Dns hostname.
|
|
|
|
|
|
Arguments:
|
|
|
|
lpDnsHostName - name to validate
|
|
|
|
Return Value:
|
|
|
|
BOOL, GetLastError
|
|
|
|
--*/
|
|
{
|
|
|
|
HANDLE DnsApi ;
|
|
DNS_VALIDATE_NAME_FN * DnsValidateNameFn ;
|
|
DNS_STATUS DnsStatus ;
|
|
|
|
DnsApi = LoadLibraryW(DnsApiDllString);
|
|
|
|
if ( !DnsApi ) {
|
|
SetLastError(ERROR_DLL_NOT_FOUND);
|
|
return FALSE ;
|
|
}
|
|
|
|
DnsValidateNameFn = (DNS_VALIDATE_NAME_FN *) GetProcAddress( DnsApi, "DnsValidateName_W" );
|
|
|
|
if ( !DnsValidateNameFn )
|
|
{
|
|
FreeLibrary( DnsApi );
|
|
SetLastError(ERROR_INVALID_DLL);
|
|
return FALSE ;
|
|
}
|
|
|
|
DnsStatus = DnsValidateNameFn( lpDnsHostname, DnsNameHostnameLabel );
|
|
|
|
FreeLibrary( DnsApi );
|
|
|
|
if ( ( DnsStatus == 0 ) ||
|
|
( DnsStatus == DNS_ERROR_NON_RFC_NAME ) )
|
|
{
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
DWORD
|
|
BasepGetMultiValueAddr(
|
|
IN LPWSTR lpMultiValue,
|
|
IN DWORD dwIndex,
|
|
OUT LPWSTR * ppFound,
|
|
OUT LPDWORD pcchIndex
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Given an index into a Multivalued register (string), return
|
|
the string at that index (not a copy), and it's char count location in the
|
|
full multivalued string
|
|
|
|
Arguments:
|
|
|
|
lpMultiValue - the register string (returned from NtQueryKey)
|
|
dwIndex - the index of which string to return
|
|
ppFound - the string found (if found) - user shouldn't free
|
|
pcchIndex - the location in lpMultiValue (in characters) of ppFound
|
|
|
|
Return Value:
|
|
|
|
ERROR (ERROR_NOT_FOUND if not found)
|
|
|
|
--*/
|
|
{
|
|
DWORD i = 0;
|
|
DWORD err = ERROR_SUCCESS;
|
|
DWORD cchTempIndex = 0;
|
|
|
|
// lpMultiValue is a concatenated string of (non-null)strings, null terminated
|
|
for (i=0; (i<dwIndex) && (lpMultiValue[0] != L'\0'); i++) {
|
|
cchTempIndex += wcslen(lpMultiValue) + 1;
|
|
lpMultiValue += wcslen(lpMultiValue) + 1;
|
|
}
|
|
|
|
// if we found the correct index, it's in lpMultiValue
|
|
if (lpMultiValue[0]!=L'\0') {
|
|
*ppFound = lpMultiValue;
|
|
*pcchIndex = cchTempIndex;
|
|
err = ERROR_SUCCESS;
|
|
}
|
|
else {
|
|
err = ERROR_NOT_FOUND;
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
DWORD
|
|
BaseGetMultiValueIndex(
|
|
IN LPWSTR lpMultiValue,
|
|
IN LPCWSTR lpValue,
|
|
OUT DWORD * pcchIndex
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Given a Multivalued register (string), and lpValue, return
|
|
the index of lpValue in lpMultiValue (ie, the 0th string, the 1st, etc).
|
|
|
|
Arguments:
|
|
|
|
lpMultiValue - the register string (returned from NtQueryKey)
|
|
lpValue - the string for which to search
|
|
pcchIndex - the index of the string matched (if found)
|
|
|
|
Return Value:
|
|
|
|
ERROR (ERROR_NOT_FOUND if not found)
|
|
|
|
--*/
|
|
{
|
|
LPWSTR lpFound = NULL;
|
|
DWORD cchFoundIndex = 0;
|
|
DWORD i = 0;
|
|
DWORD err = ERROR_SUCCESS;
|
|
BOOL fFound = FALSE;
|
|
|
|
while ((err==ERROR_SUCCESS) && !fFound) {
|
|
err = BasepGetMultiValueAddr(lpMultiValue,
|
|
i,
|
|
&lpFound,
|
|
&cchFoundIndex);
|
|
if (err == ERROR_SUCCESS) {
|
|
if ((wcslen(lpFound)==wcslen(lpValue)) && (!_memicmp(lpFound,lpValue, wcslen(lpValue)*sizeof(WCHAR)))) {
|
|
fFound = TRUE;
|
|
*pcchIndex = i;
|
|
}
|
|
}
|
|
i++;
|
|
}
|
|
return err;
|
|
}
|
|
|
|
DWORD
|
|
BaseRemoveMultiValue(
|
|
IN OUT LPWSTR lpMultiValue,
|
|
IN DWORD dwIndex,
|
|
IN OUT LPDWORD pcchMultiValue
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Given a multivalued registry value, and an index, it removes the string
|
|
located at that index.
|
|
|
|
Arguments:
|
|
|
|
lpMultiValue - the register string (returned from NtQueryKey)
|
|
dwIndex - the index of which string to remove
|
|
pcchMultiValue - number of chars in lpMultiValue (before and after)
|
|
|
|
Return Value:
|
|
|
|
ERRORS
|
|
|
|
--*/
|
|
{
|
|
DWORD err = ERROR_SUCCESS;
|
|
LPWSTR lpRest = NULL;
|
|
LPWSTR lpFound = NULL;
|
|
DWORD dwIndexFound = 0;
|
|
DWORD dwIndexRest = 0;
|
|
|
|
err = BasepGetMultiValueAddr(lpMultiValue,
|
|
dwIndex,
|
|
&lpFound,
|
|
&dwIndexFound);
|
|
if (err==ERROR_SUCCESS) {
|
|
// lpFound is a pointer to a string
|
|
// inside of lpMultiValue, to delete it,
|
|
// copy the rest of the string down
|
|
err = BasepGetMultiValueAddr(lpMultiValue,
|
|
dwIndex+1,
|
|
&lpRest,
|
|
&dwIndexRest);
|
|
if (err == ERROR_SUCCESS) {
|
|
// copy everything down
|
|
|
|
memmove(lpFound,lpRest,(*pcchMultiValue - dwIndexRest)*sizeof(WCHAR));
|
|
*pcchMultiValue = *pcchMultiValue - (dwIndexRest-dwIndexFound);
|
|
lpMultiValue[*pcchMultiValue] = L'\0';
|
|
}
|
|
else if (err == ERROR_NOT_FOUND) {
|
|
// string to remove is last string, simply write an extra null to orphan the string
|
|
*pcchMultiValue = *pcchMultiValue - (wcslen(lpFound) +1);
|
|
lpMultiValue[*pcchMultiValue] = L'\0';
|
|
err = ERROR_SUCCESS;
|
|
}
|
|
}
|
|
return err;
|
|
}
|
|
|
|
DWORD
|
|
BaseAddMultiValue(
|
|
IN OUT LPWSTR lpMultiValue,
|
|
IN LPCWSTR lpValue,
|
|
IN DWORD cchMultiValue
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Given a multivalued registry value, add another value.
|
|
|
|
Arguments:
|
|
|
|
lpMultiValue - the multivalued string (must be big enough to
|
|
hold current values + lpValue plus extra NULL
|
|
lpValue - the value to add
|
|
cchMultiValue - the count of characters USED in lpMultivalue
|
|
(not counting final null)
|
|
|
|
Return Value:
|
|
|
|
ERRORS
|
|
|
|
--*/
|
|
{
|
|
memcpy(lpMultiValue + cchMultiValue, lpValue, (wcslen(lpValue)+1)*sizeof(WCHAR));
|
|
lpMultiValue[cchMultiValue + wcslen(lpValue) + 1] = L'\0';
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
BasepGetNameFromReg(
|
|
PCWSTR Path,
|
|
PCWSTR Value,
|
|
PWSTR Buffer,
|
|
PDWORD Length
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine gets a string from the value at the specified registry key.
|
|
|
|
|
|
Arguments:
|
|
|
|
Path - Path to the registry key
|
|
|
|
Value - Name of the value to retrieve
|
|
|
|
Buffer - Buffer to return the value
|
|
|
|
Length - size of the buffer in characters
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS, or various failures
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS Status ;
|
|
HANDLE Key ;
|
|
OBJECT_ATTRIBUTES ObjA ;
|
|
UNICODE_STRING KeyName;
|
|
UNICODE_STRING ValueName;
|
|
|
|
|
|
BYTE ValueBuffer[ REASONABLE_LENGTH ];
|
|
PKEY_VALUE_FULL_INFORMATION pKeyValueInformation = (PKEY_VALUE_FULL_INFORMATION)ValueBuffer;
|
|
BOOLEAN FreeBuffer = FALSE ;
|
|
DWORD ValueLength;
|
|
PWCHAR pTerminator;
|
|
|
|
//
|
|
// Open the node for the Subkey
|
|
//
|
|
|
|
RtlInitUnicodeString(&KeyName, Path );
|
|
|
|
InitializeObjectAttributes(&ObjA,
|
|
&KeyName,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
Status = NtOpenKey(&Key, KEY_READ, &ObjA );
|
|
|
|
if (NT_SUCCESS(Status)) {
|
|
|
|
RtlInitUnicodeString( &ValueName, Value );
|
|
|
|
Status = NtQueryValueKey(Key,
|
|
&ValueName,
|
|
KeyValueFullInformation,
|
|
pKeyValueInformation,
|
|
REASONABLE_LENGTH ,
|
|
&ValueLength);
|
|
|
|
if ( Status == STATUS_BUFFER_OVERFLOW )
|
|
{
|
|
pKeyValueInformation = RtlAllocateHeap( RtlProcessHeap(),
|
|
0,
|
|
ValueLength );
|
|
|
|
if ( pKeyValueInformation )
|
|
{
|
|
FreeBuffer = TRUE ;
|
|
|
|
Status = NtQueryValueKey( Key,
|
|
&ValueName,
|
|
KeyValueFullInformation,
|
|
pKeyValueInformation,
|
|
ValueLength,
|
|
&ValueLength );
|
|
|
|
}
|
|
}
|
|
|
|
if ( NT_SUCCESS(Status) ) {
|
|
|
|
//
|
|
// If the user's buffer is big enough, move it in
|
|
// First see if it's null terminated. If it is, pretend like
|
|
// it's not.
|
|
//
|
|
|
|
pTerminator = (PWCHAR)((PBYTE) pKeyValueInformation +
|
|
pKeyValueInformation->DataOffset +
|
|
pKeyValueInformation->DataLength);
|
|
pTerminator--;
|
|
|
|
if (*pTerminator == L'\0') {
|
|
pKeyValueInformation->DataLength -= sizeof(WCHAR);
|
|
}
|
|
|
|
if ( ( *Length >= pKeyValueInformation->DataLength/sizeof(WCHAR) + 1) &&
|
|
( Buffer != NULL ) ) {
|
|
//
|
|
// This isn't guaranteed to be NULL terminated, make it so
|
|
//
|
|
RtlCopyMemory(Buffer,
|
|
(LPWSTR)((PBYTE) pKeyValueInformation +
|
|
pKeyValueInformation->DataOffset),
|
|
pKeyValueInformation->DataLength);
|
|
|
|
pTerminator = (PWCHAR) ((PBYTE) Buffer +
|
|
pKeyValueInformation->DataLength);
|
|
*pTerminator = L'\0';
|
|
|
|
//
|
|
// Return the number of characters to the caller
|
|
//
|
|
|
|
*Length = pKeyValueInformation->DataLength / sizeof(WCHAR) ;
|
|
|
|
}
|
|
else {
|
|
Status = STATUS_BUFFER_OVERFLOW;
|
|
*Length = pKeyValueInformation->DataLength/sizeof(WCHAR) + 1;
|
|
}
|
|
|
|
}
|
|
|
|
NtClose( Key );
|
|
}
|
|
|
|
if ( FreeBuffer )
|
|
{
|
|
RtlFreeHeap( RtlProcessHeap(), 0, pKeyValueInformation );
|
|
}
|
|
|
|
return Status ;
|
|
|
|
}
|
|
|
|
NTSTATUS
|
|
BaseSetNameInReg(
|
|
PCWSTR Path,
|
|
PCWSTR Value,
|
|
PCWSTR Buffer
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine sets a string in the value at the registry key.
|
|
|
|
|
|
Arguments:
|
|
|
|
Path - Path to the registry key
|
|
|
|
Value - Name of the value to set
|
|
|
|
Buffer - Buffer to set
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS, or various failures
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS NtStatus;
|
|
UNICODE_STRING KeyName;
|
|
UNICODE_STRING ValueName;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
HANDLE hKey = NULL;
|
|
ULONG ValueLength;
|
|
|
|
//
|
|
// Open the ComputerName\ComputerName node
|
|
//
|
|
|
|
RtlInitUnicodeString(&KeyName, Path);
|
|
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
&KeyName,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
NtStatus = NtOpenKey(&hKey, KEY_READ | KEY_WRITE, &ObjectAttributes);
|
|
|
|
if ( !NT_SUCCESS( NtStatus ) )
|
|
{
|
|
return NtStatus ;
|
|
}
|
|
|
|
//
|
|
// Update the value under this key
|
|
//
|
|
|
|
RtlInitUnicodeString(&ValueName, Value);
|
|
|
|
ValueLength = (wcslen( Buffer ) + 1) * sizeof(WCHAR);
|
|
|
|
NtStatus = NtSetValueKey(hKey,
|
|
&ValueName,
|
|
0,
|
|
REG_SZ,
|
|
(LPWSTR) Buffer,
|
|
ValueLength);
|
|
|
|
if ( NT_SUCCESS( NtStatus ) )
|
|
{
|
|
NtFlushKey( hKey );
|
|
}
|
|
|
|
NtClose(hKey);
|
|
|
|
return NtStatus ;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
BaseSetMultiNameInReg(
|
|
PCWSTR Path,
|
|
PCWSTR Value,
|
|
PCWSTR Buffer,
|
|
DWORD BufferSize
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine sets a string in the value at the specified multivalued registry key.
|
|
|
|
|
|
Arguments:
|
|
|
|
Path - Path to the registry key
|
|
|
|
Value - Name of the value to set
|
|
|
|
Buffer - Buffer to set
|
|
|
|
BufferSize - Size of the buffer in characters
|
|
This is needed since there can be
|
|
many nulls in the buffer which we
|
|
want to write
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS, or various failures
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS NtStatus = STATUS_SUCCESS;
|
|
UNICODE_STRING KeyName;
|
|
UNICODE_STRING ValueName;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
HANDLE hKey = NULL;
|
|
|
|
//
|
|
// Open the ComputerName\ComputerName node
|
|
//
|
|
|
|
RtlInitUnicodeString(&KeyName, Path);
|
|
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
&KeyName,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
NtStatus = NtCreateKey(&hKey,
|
|
KEY_READ | KEY_WRITE,
|
|
&ObjectAttributes,
|
|
0,
|
|
NULL,
|
|
0,
|
|
NULL);
|
|
|
|
if ( !NT_SUCCESS( NtStatus ) )
|
|
{
|
|
return NtStatus ;
|
|
}
|
|
|
|
//
|
|
// Update the value under this key
|
|
//
|
|
|
|
RtlInitUnicodeString(&ValueName, Value);
|
|
|
|
NtStatus = NtSetValueKey(hKey,
|
|
&ValueName,
|
|
0,
|
|
REG_MULTI_SZ,
|
|
(LPWSTR) Buffer,
|
|
BufferSize);
|
|
|
|
if ( NT_SUCCESS( NtStatus ) )
|
|
{
|
|
NtFlushKey( hKey );
|
|
}
|
|
|
|
NtClose(hKey);
|
|
|
|
return NtStatus ;
|
|
}
|
|
|
|
NTSTATUS
|
|
BaseCreateMultiValue(
|
|
PCWSTR Path,
|
|
PCWSTR Value,
|
|
PCWSTR Buffer
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Create a multivalued registry value and initialize it with Buffer.
|
|
|
|
|
|
Arguments:
|
|
|
|
Path - Path to the registry key
|
|
|
|
Value - Name of the value to set
|
|
|
|
Buffer - Buffer to set
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS, or various failures
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS NtStatus = STATUS_SUCCESS;
|
|
LPWSTR lpMultiValue = NULL;
|
|
|
|
lpMultiValue = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG ( TMP_TAG ), (wcslen(Buffer)+2)*sizeof(WCHAR));
|
|
if (lpMultiValue==NULL) {
|
|
NtStatus = STATUS_NO_MEMORY;
|
|
}
|
|
else {
|
|
memcpy(lpMultiValue, Buffer, wcslen(Buffer)*sizeof(WCHAR));
|
|
lpMultiValue[wcslen(Buffer)] = L'\0';
|
|
lpMultiValue[wcslen(Buffer)+1] = L'\0';
|
|
NtStatus = BaseSetMultiNameInReg(Path,
|
|
Value,
|
|
lpMultiValue,
|
|
(wcslen(Buffer)+2)*sizeof(WCHAR));
|
|
RtlFreeHeap(RtlProcessHeap(), 0, lpMultiValue);
|
|
}
|
|
return NtStatus;
|
|
}
|
|
|
|
NTSTATUS
|
|
BaseAddMultiNameInReg(
|
|
PCWSTR Path,
|
|
PCWSTR Value,
|
|
PCWSTR Buffer
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine adds a string to the values at the specified multivalued registry key.
|
|
If the value already exists in the key, it does nothing.
|
|
|
|
Arguments:
|
|
|
|
Path - Path to the registry key
|
|
|
|
Value - Name of the value
|
|
|
|
Buffer - Buffer to add
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS, or various failures
|
|
|
|
--*/
|
|
{
|
|
|
|
NTSTATUS NtStatus = STATUS_SUCCESS;
|
|
LPWSTR lpMultiValue = NULL;
|
|
ULONG cchMultiValue = 0;
|
|
DWORD dwIndex = 0;
|
|
DWORD err = ERROR_SUCCESS;
|
|
|
|
NtStatus = BasepGetNameFromReg(Path,
|
|
Value,
|
|
lpMultiValue,
|
|
&cchMultiValue);
|
|
|
|
if ( NtStatus==STATUS_NOT_FOUND || NtStatus==STATUS_OBJECT_NAME_NOT_FOUND) {
|
|
// create it, then we are done
|
|
NtStatus = BaseCreateMultiValue(Path,Value,Buffer);
|
|
return NtStatus;
|
|
} else if ( NtStatus==STATUS_BUFFER_OVERFLOW ) {
|
|
lpMultiValue = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( TMP_TAG ), (cchMultiValue+2+wcslen(Buffer))*sizeof(WCHAR));
|
|
if (lpMultiValue==NULL) {
|
|
NtStatus = STATUS_NO_MEMORY;
|
|
}
|
|
else {
|
|
NtStatus = BasepGetNameFromReg(Path,
|
|
Value,
|
|
lpMultiValue,
|
|
&cchMultiValue);
|
|
}
|
|
}
|
|
|
|
if (NT_SUCCESS( NtStatus)) {
|
|
// does it already exist in this structure?
|
|
err = BaseGetMultiValueIndex(lpMultiValue,
|
|
Buffer, &dwIndex);
|
|
|
|
// if err==ERROR_SUCCESS, then the above function found the string already in the value.
|
|
// don't add a duplicate
|
|
if (err!=ERROR_SUCCESS) {
|
|
|
|
err = BaseAddMultiValue(lpMultiValue, Buffer, cchMultiValue);
|
|
|
|
if (err == ERROR_SUCCESS) {
|
|
NtStatus = BaseSetMultiNameInReg(Path, Value, lpMultiValue, (cchMultiValue+2+wcslen(Buffer))*sizeof(WCHAR));
|
|
}
|
|
}
|
|
}
|
|
|
|
if (lpMultiValue) {
|
|
RtlFreeHeap( RtlProcessHeap(), 0, lpMultiValue);
|
|
}
|
|
return NtStatus ;
|
|
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
BaseRemoveMultiNameFromReg(
|
|
PCWSTR Path,
|
|
PCWSTR Value,
|
|
PCWSTR Buffer
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Removes a name from a multivalued registry. If the value exists more than once in the
|
|
list, removes them all.
|
|
|
|
Arguments:
|
|
|
|
Path - Path to the registry key
|
|
|
|
Value - Name of the value
|
|
|
|
Buffer - Buffer to remove
|
|
|
|
Return Value:
|
|
|
|
ERRORS
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS NtStatus = STATUS_SUCCESS;
|
|
DWORD err = ERROR_SUCCESS;
|
|
DWORD dwIndex = 0;
|
|
LPWSTR lpMultiValue = NULL;
|
|
ULONG cchNames = 0;
|
|
BOOL fNameRemoved = FALSE;
|
|
|
|
NtStatus = BasepGetNameFromReg(Path,
|
|
Value,
|
|
lpMultiValue,
|
|
&cchNames);
|
|
|
|
if (NtStatus==STATUS_BUFFER_OVERFLOW) {
|
|
lpMultiValue = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( TMP_TAG ), (cchNames) * sizeof(WCHAR));
|
|
if (lpMultiValue==NULL) {
|
|
NtStatus = STATUS_NO_MEMORY;
|
|
}
|
|
else {
|
|
NtStatus = BasepGetNameFromReg(Path,
|
|
Value,
|
|
lpMultiValue,
|
|
&cchNames);
|
|
err = RtlNtStatusToDosError(NtStatus);
|
|
if (err == ERROR_SUCCESS) {
|
|
// search for and remove all values in structure
|
|
while (err==ERROR_SUCCESS) {
|
|
err = BaseGetMultiValueIndex(lpMultiValue,
|
|
Buffer,
|
|
&dwIndex);
|
|
if (err == ERROR_SUCCESS) {
|
|
err = BaseRemoveMultiValue(lpMultiValue,
|
|
dwIndex,
|
|
&cchNames);
|
|
fNameRemoved = TRUE;
|
|
}
|
|
}
|
|
// if we removed a name, write it to the registry...
|
|
if (fNameRemoved) {
|
|
NtStatus = BaseSetMultiNameInReg(
|
|
Path,
|
|
Value,
|
|
lpMultiValue,
|
|
(cchNames+1)*sizeof(WCHAR));
|
|
}
|
|
else {
|
|
// Nothing to remove! ERRROR
|
|
NtStatus = STATUS_NOT_FOUND;
|
|
|
|
}
|
|
}
|
|
RtlFreeHeap(RtlProcessHeap(), 0, lpMultiValue);
|
|
}
|
|
}
|
|
return NtStatus;
|
|
}
|
|
|
|
BOOL
|
|
BaseSetNetbiosName(
|
|
IN LPCWSTR lpComputerName
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Sets the computer's net bios name
|
|
|
|
Arguments:
|
|
|
|
lpComputerName - name to set
|
|
|
|
Return Value:
|
|
|
|
BOOL, GetLastError()
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS NtStatus ;
|
|
|
|
//
|
|
// Validate that the supplied computername is valid (not too long,
|
|
// no incorrect characters, no leading or trailing spaces)
|
|
//
|
|
|
|
if (!BaseValidateNetbiosName(lpComputerName)) {
|
|
return(FALSE);
|
|
}
|
|
|
|
//
|
|
// Open the ComputerName\ComputerName node
|
|
//
|
|
|
|
NtStatus = BaseSetNameInReg( NON_VOLATILE_COMPUTERNAME_NODE,
|
|
COMPUTERNAME_VALUE_NAME,
|
|
lpComputerName );
|
|
|
|
if ( !NT_SUCCESS( NtStatus ))
|
|
{
|
|
BaseSetLastNTError( NtStatus );
|
|
|
|
return FALSE ;
|
|
}
|
|
|
|
return TRUE ;
|
|
}
|
|
|
|
BOOL
|
|
BaseSetDnsName(
|
|
LPCWSTR lpComputerName
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Sets the computer's Dns hostname
|
|
|
|
Arguments:
|
|
|
|
lpComputerName - name to set
|
|
|
|
Return Value:
|
|
|
|
BOOL, GetLastError()
|
|
|
|
--*/
|
|
{
|
|
|
|
UNICODE_STRING NewComputerName ;
|
|
UNICODE_STRING DnsName ;
|
|
NTSTATUS Status ;
|
|
BOOL Return ;
|
|
HANDLE DnsApi ;
|
|
DNS_VALIDATE_NAME_FN * DnsValidateNameFn ;
|
|
DNS_STATUS DnsStatus ;
|
|
|
|
DnsApi = LoadLibraryW(DnsApiDllString);
|
|
|
|
if ( !DnsApi )
|
|
{
|
|
return FALSE ;
|
|
}
|
|
|
|
DnsValidateNameFn = (DNS_VALIDATE_NAME_FN *) GetProcAddress( DnsApi, "DnsValidateName_W" );
|
|
|
|
if ( !DnsValidateNameFn )
|
|
{
|
|
FreeLibrary( DnsApi );
|
|
|
|
return FALSE ;
|
|
}
|
|
|
|
DnsStatus = DnsValidateNameFn( lpComputerName, DnsNameHostnameLabel );
|
|
|
|
FreeLibrary( DnsApi );
|
|
|
|
if ( ( DnsStatus == 0 ) ||
|
|
( DnsStatus == DNS_ERROR_NON_RFC_NAME ) )
|
|
{
|
|
Status = BaseSetNameInReg( TCPIP_ROOT,
|
|
TCPIP_NV_HOSTNAME,
|
|
lpComputerName );
|
|
}
|
|
else
|
|
{
|
|
Status = STATUS_INVALID_PARAMETER ;
|
|
}
|
|
|
|
if ( NT_SUCCESS( Status ) )
|
|
{
|
|
RtlInitUnicodeString( &DnsName, lpComputerName );
|
|
|
|
Status = RtlDnsHostNameToComputerName( &NewComputerName,
|
|
&DnsName,
|
|
TRUE );
|
|
|
|
if ( NT_SUCCESS( Status ) )
|
|
{
|
|
Return = BaseSetNetbiosName( NewComputerName.Buffer );
|
|
|
|
RtlFreeUnicodeString( &NewComputerName );
|
|
|
|
if ( !Return )
|
|
{
|
|
//
|
|
// What? Rollback?
|
|
//
|
|
|
|
return FALSE ;
|
|
}
|
|
|
|
return TRUE ;
|
|
}
|
|
}
|
|
|
|
BaseSetLastNTError( Status ) ;
|
|
|
|
return FALSE ;
|
|
}
|
|
|
|
BOOL
|
|
BaseSetDnsDomain(
|
|
LPCWSTR lpName
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Sets the computer's Dns domain name
|
|
|
|
Arguments:
|
|
|
|
lpName - name to set
|
|
|
|
Return Value:
|
|
|
|
BOOL, GetLastError()
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status ;
|
|
HANDLE DnsApi ;
|
|
DNS_VALIDATE_NAME_FN * DnsValidateNameFn ;
|
|
DNS_STATUS DnsStatus ;
|
|
|
|
//
|
|
// Special case the empty string, which is legal, but not according to dnsapi
|
|
//
|
|
|
|
if ( *lpName )
|
|
{
|
|
DnsApi = LoadLibraryW(DnsApiDllString);
|
|
|
|
if ( !DnsApi )
|
|
{
|
|
return FALSE ;
|
|
}
|
|
|
|
DnsValidateNameFn = (DNS_VALIDATE_NAME_FN *) GetProcAddress( DnsApi, "DnsValidateName_W" );
|
|
|
|
if ( !DnsValidateNameFn )
|
|
{
|
|
FreeLibrary( DnsApi );
|
|
|
|
return FALSE ;
|
|
}
|
|
|
|
DnsStatus = DnsValidateNameFn( lpName, DnsNameDomain );
|
|
|
|
FreeLibrary( DnsApi );
|
|
}
|
|
else
|
|
{
|
|
DnsStatus = 0 ;
|
|
}
|
|
|
|
//
|
|
// If the name is good, then keep it.
|
|
//
|
|
|
|
|
|
if ( ( DnsStatus == 0 ) ||
|
|
( DnsStatus == DNS_ERROR_NON_RFC_NAME ) )
|
|
{
|
|
Status = BaseSetNameInReg(
|
|
TCPIP_ROOT,
|
|
TCPIP_NV_DOMAINNAME,
|
|
lpName );
|
|
}
|
|
else
|
|
{
|
|
Status = STATUS_INVALID_PARAMETER ;
|
|
}
|
|
|
|
|
|
|
|
if ( !NT_SUCCESS( Status ) )
|
|
{
|
|
BaseSetLastNTError( Status );
|
|
|
|
return FALSE ;
|
|
}
|
|
return TRUE ;
|
|
|
|
}
|
|
|
|
BOOL
|
|
BaseSetAltNetBiosName(
|
|
IN LPCWSTR lpComputerName
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Sets the computer's alternate net bios name
|
|
|
|
Arguments:
|
|
|
|
lpComputerName - name to set
|
|
|
|
Return Value:
|
|
|
|
BOOL, GetLastError()
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS NtStatus = STATUS_SUCCESS;
|
|
|
|
if (!BaseValidateNetbiosName(lpComputerName)) {
|
|
BaseSetLastNTError( STATUS_INVALID_PARAMETER );
|
|
return(FALSE);
|
|
}
|
|
|
|
NtStatus = BaseAddMultiNameInReg(
|
|
ALT_COMPUTERNAME_NODE,
|
|
COMPUTERNAME_OPTIONAL_NAME,
|
|
lpComputerName );
|
|
|
|
|
|
if ( !NT_SUCCESS( NtStatus ))
|
|
{
|
|
BaseSetLastNTError( NtStatus );
|
|
return FALSE ;
|
|
}
|
|
|
|
return TRUE ;
|
|
}
|
|
|
|
BOOL
|
|
BaseSetAltDnsFQHostname(
|
|
IN LPCWSTR lpDnsFQHostname
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Sets the computer's alternate fully qualified Dns name
|
|
|
|
Arguments:
|
|
|
|
lpDnsFQHostname - name to set
|
|
|
|
Return Value:
|
|
|
|
BOOL, GetLastError()
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS NtStatus = STATUS_SUCCESS;
|
|
|
|
NtStatus = BaseAddMultiNameInReg(
|
|
DNSCACHE_ROOT,
|
|
DNS_ALT_HOSTNAME,
|
|
lpDnsFQHostname);
|
|
|
|
|
|
if ( !NT_SUCCESS( NtStatus ))
|
|
{
|
|
BaseSetLastNTError( NtStatus );
|
|
return FALSE ;
|
|
}
|
|
|
|
return TRUE ;
|
|
}
|
|
|
|
BOOL
|
|
BaseIsAltDnsFQHostname(
|
|
LPCWSTR lpAltDnsFQHostname
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Verifies if lpAltDnsFQHostname is a previosly defined
|
|
alternate dns name
|
|
|
|
Arguments:
|
|
|
|
lpDnsFQHostname - name to check
|
|
|
|
Return Value:
|
|
|
|
TRUE if verifiably in use, FALSE otherwise, GetLastError()
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS NtStatus = STATUS_SUCCESS;
|
|
LPWSTR lpNames = NULL;
|
|
ULONG cchNames = 0;
|
|
BOOL fFound = FALSE;
|
|
DWORD dwIndex = 0;
|
|
DWORD err = ERROR_SUCCESS;
|
|
|
|
NtStatus = BasepGetNameFromReg(DNSCACHE_ROOT,
|
|
DNS_ALT_HOSTNAME,
|
|
lpNames,
|
|
&cchNames);
|
|
|
|
if (NtStatus==STATUS_BUFFER_OVERFLOW) {
|
|
lpNames = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( TMP_TAG ), (cchNames) * sizeof(WCHAR));
|
|
if (lpNames!=NULL) {
|
|
NtStatus = BasepGetNameFromReg(DNSCACHE_ROOT,
|
|
DNS_ALT_HOSTNAME,
|
|
lpNames,
|
|
&cchNames);
|
|
err = RtlNtStatusToDosError(NtStatus);
|
|
if (err == ERROR_SUCCESS) {
|
|
|
|
err = BaseGetMultiValueIndex(lpNames,
|
|
lpAltDnsFQHostname,
|
|
&dwIndex);
|
|
fFound = err==ERROR_SUCCESS;
|
|
}
|
|
RtlFreeHeap( RtlProcessHeap(), 0, lpNames);
|
|
}
|
|
}
|
|
return fFound;
|
|
}
|
|
|
|
BOOL
|
|
BaseRemoveAltNetBiosName(
|
|
IN LPCWSTR lpAltComputerName
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Removes an alternate net bios name
|
|
|
|
Arguments:
|
|
|
|
lpAltComputerName - name to remove
|
|
|
|
Return Value:
|
|
|
|
BOOL, GetLastError()
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS NtStatus = STATUS_SUCCESS;
|
|
|
|
NtStatus = BaseRemoveMultiNameFromReg ( ALT_COMPUTERNAME_NODE,
|
|
COMPUTERNAME_OPTIONAL_NAME,
|
|
lpAltComputerName );
|
|
|
|
if ( !NT_SUCCESS( NtStatus ))
|
|
{
|
|
BaseSetLastNTError( NtStatus );
|
|
return FALSE ;
|
|
}
|
|
|
|
return TRUE ;
|
|
}
|
|
|
|
BOOL
|
|
BaseRemoveAltDnsFQHostname(
|
|
IN LPCWSTR lpAltDnsFQHostname
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Removes an alternate Dns hostname
|
|
|
|
Arguments:
|
|
|
|
lpAltDnsFqHostname - name to remove
|
|
|
|
Return Value:
|
|
|
|
BOOL, GetLastError()
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS NtStatus = STATUS_SUCCESS;
|
|
|
|
NtStatus = BaseRemoveMultiNameFromReg ( DNSCACHE_ROOT,
|
|
DNS_ALT_HOSTNAME,
|
|
lpAltDnsFQHostname );
|
|
|
|
if ( !NT_SUCCESS( NtStatus ))
|
|
{
|
|
BaseSetLastNTError( NtStatus );
|
|
return FALSE ;
|
|
}
|
|
|
|
return TRUE ;
|
|
}
|
|
|
|
DWORD
|
|
BaseEnumAltDnsFQHostnames(
|
|
OUT LPWSTR lpAltDnsFQHostnames,
|
|
IN OUT LPDWORD nSize
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Wrapper for BasepGetNameFromReg to return ERRORS, instead of STATUS
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
|
|
status = BasepGetNameFromReg(
|
|
DNSCACHE_ROOT,
|
|
DNS_ALT_HOSTNAME,
|
|
lpAltDnsFQHostnames,
|
|
nSize);
|
|
|
|
if (status == STATUS_OBJECT_NAME_NOT_FOUND) {
|
|
if ((lpAltDnsFQHostnames!=NULL) && (*nSize>0)) {
|
|
lpAltDnsFQHostnames[0]=L'\0';
|
|
*nSize=0;
|
|
status=STATUS_SUCCESS;
|
|
}
|
|
else {
|
|
*nSize=1;
|
|
status=STATUS_BUFFER_OVERFLOW;
|
|
}
|
|
}
|
|
|
|
return RtlNtStatusToDosError(status);
|
|
}
|
|
|
|
LPWSTR
|
|
BaseParseDnsName(
|
|
IN LPCWSTR lpDnsName,
|
|
IN ULONG NamePart
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Given a dns name, parse out either the hostname or the domain name.
|
|
|
|
Arguments:
|
|
|
|
lpDnsName - a dns name, of the form hostname.domain - domain name optional
|
|
NamePart - DNS_HOSTNAME or DNS_DOMAINNAME
|
|
|
|
Return Value:
|
|
|
|
String requested
|
|
|
|
--*/
|
|
{
|
|
|
|
DWORD cchCharIndex = 0;
|
|
ULONG cchName = 0;
|
|
LPWSTR lpName = NULL;
|
|
|
|
if (lpDnsName==NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
cchCharIndex = wcscspn(lpDnsName, L".");
|
|
|
|
if (NamePart==DNS_HOSTNAME) {
|
|
cchName = cchCharIndex;
|
|
}
|
|
else {
|
|
if (cchCharIndex==wcslen(lpDnsName)) {
|
|
// no period found,
|
|
cchName = 0;
|
|
}
|
|
else {
|
|
cchName = wcslen(lpDnsName)-(cchCharIndex+1);
|
|
}
|
|
}
|
|
|
|
lpName = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( TMP_TAG ), (cchName + 1)*sizeof(WCHAR));
|
|
if (lpName==NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
// copy the correct part into the structure
|
|
if (NamePart==DNS_HOSTNAME) {
|
|
wcsncpy(lpName, lpDnsName, cchName);
|
|
}
|
|
else {
|
|
wcsncpy(lpName, (LPWSTR)(lpDnsName + cchCharIndex + 1), cchName);
|
|
}
|
|
lpName[cchName] = L'\0';
|
|
|
|
return lpName;
|
|
}
|
|
|
|
BOOL
|
|
BaseIsNetBiosNameInUse(
|
|
LPWSTR lpCompName
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Verify whether lpCompName is being used by any alternate DNS names
|
|
(ie whether any existing alternate DNS names map to lpCompName with
|
|
DnsHostnameToComputerNameW)
|
|
|
|
Arguments:
|
|
|
|
lpCompName - net bios name to verify
|
|
|
|
Return Value:
|
|
|
|
FALSE if verifiably is not being used, true otherwise, GetLastError()
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS NtStatus = STATUS_SUCCESS;
|
|
LPWSTR lpMultiValue = NULL;
|
|
ULONG cchMultiValue = 0;
|
|
LPWSTR lpAltDnsFQHostname = NULL;
|
|
ULONG cchAltDnsHostname = 0;
|
|
DWORD dwIndex = 0;
|
|
LPWSTR lpAltCompName = NULL;
|
|
ULONG cchAltCompName = 0;
|
|
DWORD err = ERROR_SUCCESS;
|
|
BOOL fInUse = FALSE;
|
|
BOOL fIsNetBiosNameInUse = TRUE;
|
|
|
|
NtStatus = BasepGetNameFromReg(DNSCACHE_ROOT,
|
|
DNS_ALT_HOSTNAME,
|
|
lpMultiValue,
|
|
&cchMultiValue);
|
|
err = RtlNtStatusToDosError(NtStatus);
|
|
if (err==ERROR_MORE_DATA) {
|
|
lpMultiValue = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( TMP_TAG ), cchMultiValue * sizeof(WCHAR));
|
|
if (lpMultiValue==NULL) {
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
return TRUE;
|
|
}
|
|
NtStatus = BasepGetNameFromReg(DNSCACHE_ROOT,
|
|
DNS_ALT_HOSTNAME,
|
|
lpMultiValue,
|
|
&cchMultiValue);
|
|
err=RtlNtStatusToDosError(NtStatus);
|
|
}
|
|
if (err == ERROR_SUCCESS) {
|
|
dwIndex = 0;
|
|
while (err == ERROR_SUCCESS) {
|
|
err = BasepGetMultiValueAddr(lpMultiValue,
|
|
dwIndex,
|
|
&lpAltDnsFQHostname,
|
|
&cchAltDnsHostname);
|
|
|
|
// get net bios names
|
|
if (err == ERROR_SUCCESS) {
|
|
if (!DnsHostnameToComputerNameW(lpAltDnsFQHostname,
|
|
lpAltCompName,
|
|
&cchAltCompName)) {
|
|
err = GetLastError();
|
|
if (err==ERROR_MORE_DATA) {
|
|
// DnsHostNameToComputerNameW bug
|
|
cchAltCompName += 1;
|
|
// DnsHostNameToComputerNameW bug
|
|
|
|
lpAltCompName = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( TMP_TAG ), cchAltCompName*sizeof(WCHAR));
|
|
if (lpAltCompName==NULL) {
|
|
err = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
else {
|
|
if (!DnsHostnameToComputerNameW(lpAltDnsFQHostname, lpAltCompName, &cchAltCompName)) {
|
|
err = GetLastError();
|
|
} else {
|
|
err = ERROR_SUCCESS;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (err==ERROR_SUCCESS) {
|
|
if (!_wcsicmp(lpAltCompName, lpCompName)) {
|
|
fInUse = TRUE;
|
|
}
|
|
}
|
|
}
|
|
dwIndex++;
|
|
}
|
|
|
|
// exits the above while loop when err==ERROR_NOT_FOUND, whether found or not
|
|
if (err==ERROR_NOT_FOUND) {
|
|
fIsNetBiosNameInUse = fInUse;
|
|
err = ERROR_SUCCESS;
|
|
}
|
|
else {
|
|
// error, default to in use
|
|
fIsNetBiosNameInUse = TRUE;
|
|
}
|
|
}
|
|
|
|
if (lpMultiValue) {
|
|
RtlFreeHeap(RtlProcessHeap(), 0, lpMultiValue);
|
|
}
|
|
if (lpAltCompName) {
|
|
RtlFreeHeap(RtlProcessHeap(), 0, lpAltCompName);
|
|
}
|
|
return fIsNetBiosNameInUse;
|
|
}
|
|
|
|
//
|
|
// Worker routine
|
|
//
|
|
|
|
NTSTATUS
|
|
GetNameFromValue(
|
|
HANDLE hKey,
|
|
LPWSTR SubKeyName,
|
|
LPWSTR ValueValue,
|
|
LPDWORD nSize
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This returns the value of "ComputerName" value entry under the subkey
|
|
SubKeyName relative to hKey. This is used to get the value of the
|
|
ActiveComputerName or ComputerName values.
|
|
|
|
|
|
Arguments:
|
|
|
|
hKey - handle to the Key the SubKey exists under
|
|
|
|
SubKeyName - name of the subkey to look for the value under
|
|
|
|
ValueValue - where the value of the value entry will be returned
|
|
|
|
nSize - pointer to the size (in characters) of the ValueValue buffer
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
|
|
#define VALUE_BUFFER_SIZE (sizeof(KEY_VALUE_FULL_INFORMATION) + \
|
|
(sizeof( COMPUTERNAME_VALUE_NAME ) + MAX_COMPUTERNAME_LENGTH + 1) * sizeof(WCHAR))
|
|
|
|
NTSTATUS NtStatus;
|
|
UNICODE_STRING KeyName;
|
|
UNICODE_STRING ValueName;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
HANDLE hSubKey;
|
|
BYTE ValueBuffer[VALUE_BUFFER_SIZE];
|
|
PKEY_VALUE_FULL_INFORMATION pKeyValueInformation = (PKEY_VALUE_FULL_INFORMATION)ValueBuffer;
|
|
DWORD ValueLength;
|
|
PWCHAR pTerminator;
|
|
|
|
//
|
|
// Open the node for the Subkey
|
|
//
|
|
|
|
RtlInitUnicodeString(&KeyName, SubKeyName);
|
|
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
&KeyName,
|
|
OBJ_CASE_INSENSITIVE,
|
|
hKey,
|
|
NULL
|
|
);
|
|
|
|
NtStatus = NtOpenKey(&hSubKey, KEY_READ, &ObjectAttributes);
|
|
|
|
if (NT_SUCCESS(NtStatus)) {
|
|
|
|
RtlInitUnicodeString(&ValueName, COMPUTERNAME_VALUE_NAME);
|
|
|
|
NtStatus = NtQueryValueKey(hSubKey,
|
|
&ValueName,
|
|
KeyValueFullInformation,
|
|
pKeyValueInformation,
|
|
VALUE_BUFFER_SIZE,
|
|
&ValueLength);
|
|
|
|
NtClose(hSubKey);
|
|
|
|
if (NT_SUCCESS(NtStatus) &&
|
|
(pKeyValueInformation->DataLength > 0 )) {
|
|
|
|
//
|
|
// If the user's buffer is big enough, move it in
|
|
// First see if it's null terminated. If it is, pretend like
|
|
// it's not.
|
|
//
|
|
|
|
pTerminator = (PWCHAR)((PBYTE) pKeyValueInformation +
|
|
pKeyValueInformation->DataOffset +
|
|
pKeyValueInformation->DataLength);
|
|
pTerminator--;
|
|
|
|
if (*pTerminator == L'\0') {
|
|
pKeyValueInformation->DataLength -= sizeof(WCHAR);
|
|
}
|
|
|
|
if (*nSize >= pKeyValueInformation->DataLength/sizeof(WCHAR) + 1) {
|
|
//
|
|
// This isn't guaranteed to be NULL terminated, make it so
|
|
//
|
|
RtlCopyMemory(ValueValue,
|
|
(LPWSTR)((PBYTE) pKeyValueInformation +
|
|
pKeyValueInformation->DataOffset),
|
|
pKeyValueInformation->DataLength);
|
|
|
|
pTerminator = (PWCHAR) ((PBYTE) ValueValue +
|
|
pKeyValueInformation->DataLength);
|
|
*pTerminator = L'\0';
|
|
|
|
//
|
|
// Return the number of characters to the caller
|
|
//
|
|
|
|
*nSize = wcslen(ValueValue);
|
|
}
|
|
else {
|
|
NtStatus = STATUS_BUFFER_OVERFLOW;
|
|
*nSize = pKeyValueInformation->DataLength/sizeof(WCHAR) + 1;
|
|
}
|
|
|
|
}
|
|
else {
|
|
//
|
|
// If the value has been deleted (zero length data),
|
|
// return object not found.
|
|
//
|
|
|
|
if ( NT_SUCCESS( NtStatus ) )
|
|
{
|
|
NtStatus = STATUS_OBJECT_NAME_NOT_FOUND ;
|
|
}
|
|
}
|
|
}
|
|
|
|
return(NtStatus);
|
|
}
|
|
|
|
|
|
//
|
|
// UNICODE APIs
|
|
//
|
|
|
|
BOOL
|
|
WINAPI
|
|
GetComputerNameW (
|
|
LPWSTR lpBuffer,
|
|
LPDWORD nSize
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This returns the active computername. This is the computername when the
|
|
system was last booted. If this is changed (via SetComputerName) it does
|
|
not take effect until the next system boot.
|
|
|
|
|
|
Arguments:
|
|
|
|
lpBuffer - Points to the buffer that is to receive the
|
|
null-terminated character string containing the computer name.
|
|
|
|
nSize - Specifies the maximum size (in characters) of the buffer. This
|
|
value should be set to at least MAX_COMPUTERNAME_LENGTH + 1 to allow
|
|
sufficient room in the buffer for the computer name. The length
|
|
of the string is returned in nSize.
|
|
|
|
Return Value:
|
|
|
|
TRUE on success, FALSE on failure.
|
|
|
|
|
|
--*/
|
|
{
|
|
|
|
NTSTATUS NtStatus;
|
|
UNICODE_STRING KeyName;
|
|
UNICODE_STRING Class;
|
|
UNICODE_STRING ValueName;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
HANDLE hKey = NULL;
|
|
HANDLE hNewKey = NULL;
|
|
ULONG Disposition;
|
|
ULONG ValueLength;
|
|
BOOL ReturnValue;
|
|
DWORD Status;
|
|
DWORD errcode;
|
|
|
|
//
|
|
// First check to see if the cluster computername variable is set.
|
|
// If so, this overrides the actual computername to fool the application
|
|
// into working when its network name and computer name are different.
|
|
//
|
|
|
|
ValueLength = GetEnvironmentVariableW(L"_CLUSTER_NETWORK_NAME_",
|
|
lpBuffer,
|
|
*nSize);
|
|
if (ValueLength != 0) {
|
|
//
|
|
// The environment variable exists, return it directly but make sure
|
|
// we honor return semantics
|
|
//
|
|
ReturnValue = ( *nSize >= ValueLength ? TRUE : FALSE );
|
|
if ( !ReturnValue ) {
|
|
SetLastError( ERROR_BUFFER_OVERFLOW );
|
|
}
|
|
*nSize = ValueLength;
|
|
return(ReturnValue);
|
|
}
|
|
|
|
|
|
if ( (gpTermsrvGetComputerName) &&
|
|
((errcode = gpTermsrvGetComputerName(lpBuffer, nSize)) != ERROR_RETRY) ) {
|
|
|
|
if (errcode == ERROR_BUFFER_OVERFLOW ) {
|
|
ReturnValue = FALSE;
|
|
goto Cleanup;
|
|
|
|
} else {
|
|
goto GoodReturn;
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// Open the Computer node, both computername keys are relative
|
|
// to this node.
|
|
//
|
|
|
|
RtlInitUnicodeString(&KeyName, COMPUTERNAME_ROOT);
|
|
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
&KeyName,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
NtStatus = NtOpenKey(&hKey, KEY_READ, &ObjectAttributes);
|
|
|
|
if (NtStatus == STATUS_OBJECT_NAME_NOT_FOUND) {
|
|
|
|
//
|
|
// This should never happen! This key should have been created
|
|
// at setup, and protected by an ACL so that only the ADMIN could
|
|
// write to it. Generate an event, and return a NULL computername.
|
|
//
|
|
|
|
// NTRAID#NTBUG9-174986-2000/08/31-DavePr Log event or do alert or something.
|
|
|
|
//
|
|
// Return a NULL computername
|
|
//
|
|
|
|
if (ARGUMENT_PRESENT(lpBuffer))
|
|
{
|
|
lpBuffer[0] = L'\0';
|
|
}
|
|
*nSize = 0;
|
|
goto GoodReturn;
|
|
}
|
|
|
|
if (!NT_SUCCESS(NtStatus)) {
|
|
|
|
//
|
|
// Some other error, return it to the caller
|
|
//
|
|
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
//
|
|
// Try to get the name from the volatile key
|
|
//
|
|
|
|
NtStatus = GetNameFromValue(hKey, VOLATILE_COMPUTERNAME, lpBuffer,
|
|
nSize);
|
|
|
|
//
|
|
// The user's buffer wasn't big enough, just return the error.
|
|
//
|
|
|
|
if(NtStatus == STATUS_BUFFER_OVERFLOW) {
|
|
SetLastError(ERROR_BUFFER_OVERFLOW);
|
|
ReturnValue = FALSE;
|
|
goto Cleanup;
|
|
}
|
|
|
|
if (NT_SUCCESS(NtStatus)) {
|
|
|
|
//
|
|
// The volatile copy is already there, just return it
|
|
//
|
|
|
|
goto GoodReturn;
|
|
}
|
|
|
|
//
|
|
// The volatile key isn't there, try for the non-volatile one
|
|
//
|
|
|
|
NtStatus = GetNameFromValue(hKey, NON_VOLATILE_COMPUTERNAME, lpBuffer,
|
|
nSize);
|
|
|
|
if (NtStatus == STATUS_OBJECT_NAME_NOT_FOUND) {
|
|
|
|
//
|
|
// This should never happen! This value should have been created
|
|
// at setup, and protected by an ACL so that only the ADMIN could
|
|
// write to it. Generate an event, and return an error to the
|
|
// caller
|
|
//
|
|
|
|
// NTRAID#NTBUG9-174986-2000/08/31-DavePr Log event or do alert or something.
|
|
|
|
//
|
|
// Return a NULL computername
|
|
//
|
|
|
|
lpBuffer[0] = L'\0';
|
|
*nSize = 0;
|
|
goto GoodReturn;
|
|
}
|
|
|
|
if (!NT_SUCCESS(NtStatus)) {
|
|
|
|
//
|
|
// Some other error, return it to the caller
|
|
//
|
|
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
//
|
|
// Now create the volatile key to "lock this in" until the next boot
|
|
//
|
|
|
|
RtlInitUnicodeString(&Class, CLASS_STRING);
|
|
|
|
//
|
|
// Turn KeyName into a UNICODE_STRING
|
|
//
|
|
|
|
RtlInitUnicodeString(&KeyName, VOLATILE_COMPUTERNAME);
|
|
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
&KeyName,
|
|
OBJ_CASE_INSENSITIVE,
|
|
hKey,
|
|
NULL
|
|
);
|
|
|
|
//
|
|
// Now create the key
|
|
//
|
|
|
|
NtStatus = NtCreateKey(&hNewKey,
|
|
KEY_WRITE | KEY_READ,
|
|
&ObjectAttributes,
|
|
0,
|
|
&Class,
|
|
REG_OPTION_VOLATILE,
|
|
&Disposition);
|
|
|
|
if (Disposition == REG_OPENED_EXISTING_KEY) {
|
|
|
|
//
|
|
// Someone beat us to this, just get the value they put there
|
|
//
|
|
|
|
NtStatus = GetNameFromValue(hKey, VOLATILE_COMPUTERNAME, lpBuffer,
|
|
nSize);
|
|
|
|
if (NtStatus == STATUS_OBJECT_NAME_NOT_FOUND) {
|
|
|
|
//
|
|
// This should never happen! It just told me it existed
|
|
//
|
|
|
|
NtStatus = STATUS_UNSUCCESSFUL;
|
|
goto ErrorReturn;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Create the value under this key
|
|
//
|
|
|
|
RtlInitUnicodeString(&ValueName, COMPUTERNAME_VALUE_NAME);
|
|
ValueLength = (wcslen(lpBuffer) + 1) * sizeof(WCHAR);
|
|
NtStatus = NtSetValueKey(hNewKey,
|
|
&ValueName,
|
|
0,
|
|
REG_SZ,
|
|
lpBuffer,
|
|
ValueLength);
|
|
|
|
if (!NT_SUCCESS(NtStatus)) {
|
|
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
goto GoodReturn;
|
|
|
|
ErrorReturn:
|
|
|
|
//
|
|
// An error was encountered, convert the status and return
|
|
//
|
|
|
|
BaseSetLastNTError(NtStatus);
|
|
ReturnValue = FALSE;
|
|
goto Cleanup;
|
|
|
|
GoodReturn:
|
|
|
|
//
|
|
// Everything went ok, update nSize with the length of the buffer and
|
|
// return
|
|
//
|
|
|
|
*nSize = wcslen(lpBuffer);
|
|
ReturnValue = TRUE;
|
|
goto Cleanup;
|
|
|
|
Cleanup:
|
|
|
|
if (hKey) {
|
|
NtClose(hKey);
|
|
}
|
|
|
|
if (hNewKey) {
|
|
NtClose(hNewKey);
|
|
}
|
|
|
|
return(ReturnValue);
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
WINAPI
|
|
SetComputerNameW (
|
|
LPCWSTR lpComputerName
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This sets what the computername will be when the system is next booted. This
|
|
does not effect the active computername for the remainder of this boot, nor
|
|
what is returned by GetComputerName before the next system boot.
|
|
|
|
|
|
Arguments:
|
|
|
|
lpComputerName - points to the buffer that is contains the
|
|
null-terminated character string containing the computer name.
|
|
|
|
Return Value:
|
|
|
|
Returns TRUE on success, FALSE on failure.
|
|
|
|
|
|
--*/
|
|
{
|
|
|
|
NTSTATUS NtStatus;
|
|
UNICODE_STRING KeyName;
|
|
UNICODE_STRING ValueName;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
HANDLE hKey = NULL;
|
|
ULONG ValueLength;
|
|
ULONG ComputerNameLength;
|
|
ULONG AnsiComputerNameLength;
|
|
|
|
//
|
|
// Validate that the supplied computername is valid (not too long,
|
|
// no incorrect characters, no leading or trailing spaces)
|
|
//
|
|
|
|
ComputerNameLength = wcslen(lpComputerName);
|
|
|
|
//
|
|
// The name length limitation should be based on ANSI. (LanMan compatibility)
|
|
//
|
|
|
|
NtStatus = RtlUnicodeToMultiByteSize(&AnsiComputerNameLength,
|
|
(LPWSTR)lpComputerName,
|
|
ComputerNameLength * sizeof(WCHAR));
|
|
|
|
if ((!NT_SUCCESS(NtStatus)) ||
|
|
(AnsiComputerNameLength == 0 )||(AnsiComputerNameLength > MAX_COMPUTERNAME_LENGTH)) {
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return(FALSE);
|
|
}
|
|
|
|
//
|
|
// Check for illegal characters; return an error if one is found
|
|
//
|
|
|
|
if (wcscspn(lpComputerName, ILLEGAL_NAME_CHARS_STR) < ComputerNameLength) {
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return(FALSE);
|
|
}
|
|
|
|
//
|
|
// Check for leading or trailing spaces
|
|
//
|
|
|
|
if (lpComputerName[0] == L' ' ||
|
|
lpComputerName[ComputerNameLength-1] == L' ') {
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return(FALSE);
|
|
|
|
}
|
|
//
|
|
// Open the ComputerName\ComputerName node
|
|
//
|
|
|
|
RtlInitUnicodeString(&KeyName, NON_VOLATILE_COMPUTERNAME_NODE);
|
|
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
&KeyName,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
NtStatus = NtOpenKey(&hKey, KEY_READ | KEY_WRITE, &ObjectAttributes);
|
|
|
|
if (NtStatus == STATUS_OBJECT_NAME_NOT_FOUND) {
|
|
|
|
//
|
|
// This should never happen! This key should have been created
|
|
// at setup, and protected by an ACL so that only the ADMIN could
|
|
// write to it. Generate an event, and return a NULL computername.
|
|
//
|
|
|
|
// NTRAID#NTBUG9-174986-2000/08/31-DavePr Log event or do alert or something.
|
|
// (One alternative for this instance would be to actually create the missing
|
|
// entry here -- but we'd have to be sure to get the right ACLs etc, etc.
|
|
|
|
SetLastError(ERROR_GEN_FAILURE);
|
|
return(FALSE);
|
|
}
|
|
|
|
//
|
|
// Update the value under this key
|
|
//
|
|
|
|
RtlInitUnicodeString(&ValueName, COMPUTERNAME_VALUE_NAME);
|
|
ValueLength = (wcslen(lpComputerName) + 1) * sizeof(WCHAR);
|
|
NtStatus = NtSetValueKey(hKey,
|
|
&ValueName,
|
|
0,
|
|
REG_SZ,
|
|
(LPWSTR)lpComputerName,
|
|
ValueLength);
|
|
|
|
if (!NT_SUCCESS(NtStatus)) {
|
|
|
|
BaseSetLastNTError(NtStatus);
|
|
NtClose(hKey);
|
|
return(FALSE);
|
|
}
|
|
|
|
NtFlushKey(hKey);
|
|
NtClose(hKey);
|
|
return(TRUE);
|
|
|
|
}
|
|
|
|
BOOL
|
|
WINAPI
|
|
GetComputerNameExW(
|
|
IN COMPUTER_NAME_FORMAT NameType,
|
|
OUT LPWSTR lpBuffer,
|
|
IN OUT LPDWORD nSize
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This returns the active computername in a particular format. This is the
|
|
computername when the system was last booted. If this is changed (via
|
|
SetComputerName) it does not take effect until the next system boot.
|
|
|
|
|
|
Arguments:
|
|
|
|
NameType - Possible name formats to return the computer name in:
|
|
|
|
ComputerNameNetBIOS - netbios name (compatible with GetComputerName)
|
|
ComputerNameDnsHostname - DNS host name
|
|
ComputerNameDnsDomain - DNS Domain name
|
|
ComputerNameDnsFullyQualified - DNS Fully Qualified (hostname.dnsdomain)
|
|
|
|
lpBuffer - Points to the buffer that is to receive the
|
|
null-terminated character string containing the computer name.
|
|
|
|
nSize - Specifies the maximum size (in characters) of the buffer. This
|
|
value should be set to at least MAX_COMPUTERNAME_LENGTH + 1 to allow
|
|
sufficient room in the buffer for the computer name. The length
|
|
of the string is returned in nSize.
|
|
|
|
Return Value:
|
|
|
|
TRUE on success, FALSE on failure.
|
|
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status ;
|
|
DWORD ValueLength ;
|
|
DWORD HostLength ;
|
|
DWORD DomainLength ;
|
|
BOOL DontSetReturn = FALSE ;
|
|
COMPUTER_NAME_FORMAT HostNameFormat, DomainNameFormat ;
|
|
|
|
|
|
if ( NameType >= ComputerNameMax )
|
|
{
|
|
BaseSetLastNTError( STATUS_INVALID_PARAMETER );
|
|
return FALSE ;
|
|
}
|
|
|
|
if ((nSize==NULL) || ((lpBuffer==NULL) && (*nSize>0))) {
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return(FALSE);
|
|
}
|
|
|
|
//
|
|
// For general names, allow clusters to override the physical name:
|
|
//
|
|
|
|
if ( (NameType >= ComputerNameNetBIOS) &&
|
|
(NameType <= ComputerNameDnsFullyQualified ) )
|
|
{
|
|
ValueLength = GetEnvironmentVariableW(
|
|
ClusterNameVars[ NameType ],
|
|
lpBuffer,
|
|
*nSize );
|
|
|
|
if ( ValueLength )
|
|
{
|
|
BOOL ReturnValue;
|
|
//
|
|
// ValueLength is the length+NULL of the env. string regardless of
|
|
// how much was copied (gregjohn 1/30/01 note: this isn't the behaivor
|
|
// of the rest of the function, which returns length+NULL on failure
|
|
// and length on success). Indicate how many characters are in the string
|
|
// and if the user's buffer wasn't big enough, return FALSE
|
|
//
|
|
ReturnValue = ( *nSize >= ValueLength ? TRUE : FALSE );
|
|
if ( !ReturnValue ) {
|
|
SetLastError( ERROR_MORE_DATA );
|
|
}
|
|
*nSize = ValueLength ;
|
|
return ReturnValue;
|
|
}
|
|
}
|
|
|
|
if ( lpBuffer && (*nSize > 0) )
|
|
{
|
|
lpBuffer[0] = L'\0';
|
|
}
|
|
|
|
switch ( NameType )
|
|
{
|
|
case ComputerNameNetBIOS:
|
|
case ComputerNamePhysicalNetBIOS:
|
|
Status = BasepGetNameFromReg(
|
|
VOLATILE_COMPUTERNAME_NODE,
|
|
COMPUTERNAME_VALUE_NAME,
|
|
lpBuffer,
|
|
nSize );
|
|
|
|
if ( !NT_SUCCESS( Status ) )
|
|
{
|
|
if ( Status != STATUS_BUFFER_OVERFLOW )
|
|
{
|
|
//
|
|
// Hmm, the value (or key) is missing. Try the non-volatile
|
|
// one.
|
|
//
|
|
|
|
Status = BasepGetNameFromReg(
|
|
NON_VOLATILE_COMPUTERNAME_NODE,
|
|
COMPUTERNAME_VALUE_NAME,
|
|
lpBuffer,
|
|
nSize );
|
|
|
|
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
case ComputerNameDnsHostname:
|
|
case ComputerNamePhysicalDnsHostname:
|
|
Status = BasepGetNameFromReg(
|
|
TCPIP_ROOT,
|
|
TCPIP_HOSTNAME,
|
|
lpBuffer,
|
|
nSize );
|
|
|
|
break;
|
|
|
|
case ComputerNameDnsDomain:
|
|
case ComputerNamePhysicalDnsDomain:
|
|
|
|
//
|
|
// Allow policy to override the domain name from the
|
|
// tcpip key.
|
|
//
|
|
|
|
Status = BasepGetNameFromReg(
|
|
TCPIP_POLICY_ROOT,
|
|
TCPIP_POLICY_DOMAINNAME,
|
|
lpBuffer,
|
|
nSize );
|
|
|
|
//
|
|
// If no policy read from the tcpip key.
|
|
//
|
|
|
|
if ( !NT_SUCCESS( Status ) )
|
|
{
|
|
Status = BasepGetNameFromReg(
|
|
TCPIP_ROOT,
|
|
TCPIP_DOMAINNAME,
|
|
lpBuffer,
|
|
nSize );
|
|
}
|
|
|
|
break;
|
|
|
|
case ComputerNameDnsFullyQualified:
|
|
case ComputerNamePhysicalDnsFullyQualified:
|
|
|
|
//
|
|
// This is the tricky case. We have to construct the name from
|
|
// the two components for the caller.
|
|
//
|
|
|
|
//
|
|
// In general, don't set the last status, since we'll end up using
|
|
// the other calls to handle that for us.
|
|
//
|
|
|
|
DontSetReturn = TRUE ;
|
|
|
|
Status = STATUS_UNSUCCESSFUL ;
|
|
|
|
if ( lpBuffer == NULL )
|
|
{
|
|
//
|
|
// If this is just the computation call, quickly do the
|
|
// two components
|
|
//
|
|
|
|
HostLength = DomainLength = 0 ;
|
|
|
|
GetComputerNameExW( ComputerNameDnsHostname, NULL, &HostLength );
|
|
|
|
if ( GetLastError() == ERROR_MORE_DATA )
|
|
{
|
|
GetComputerNameExW( ComputerNameDnsDomain, NULL, &DomainLength );
|
|
|
|
if ( GetLastError() == ERROR_MORE_DATA )
|
|
{
|
|
//
|
|
// Simply add. Note that since both account for a
|
|
// null terminator, the '.' that goes between them is
|
|
// covered.
|
|
//
|
|
|
|
*nSize = HostLength + DomainLength ;
|
|
|
|
Status = STATUS_BUFFER_OVERFLOW ;
|
|
|
|
DontSetReturn = FALSE ;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
HostLength = *nSize ;
|
|
|
|
if ( GetComputerNameExW( ComputerNameDnsHostname,
|
|
lpBuffer,
|
|
&HostLength ) )
|
|
{
|
|
|
|
HostLength += 1; // Add in the zero character (or . depending on perspective)
|
|
lpBuffer[ HostLength - 1 ] = L'.';
|
|
|
|
DomainLength = *nSize - HostLength ;
|
|
|
|
if (GetComputerNameExW( ComputerNameDnsDomain,
|
|
&lpBuffer[ HostLength ],
|
|
&DomainLength ) )
|
|
{
|
|
Status = STATUS_SUCCESS ;
|
|
|
|
if ( DomainLength == 0 )
|
|
{
|
|
lpBuffer[ HostLength - 1 ] = L'\0';
|
|
HostLength-- ;
|
|
}
|
|
else if ( ( DomainLength == 1 ) &&
|
|
( lpBuffer[ HostLength ] == L'.' ) )
|
|
{
|
|
//
|
|
// Legally, the domain name can be a single
|
|
// dot '.', indicating that this host is part
|
|
// of the root domain. An odd case, to be sure,
|
|
// but needs to be handled. Since we've already
|
|
// stuck a dot separator in the result string,
|
|
// get rid of this one, and adjust the values
|
|
// accordingly.
|
|
//
|
|
lpBuffer[ HostLength ] = L'\0' ;
|
|
DomainLength = 0 ;
|
|
}
|
|
|
|
*nSize = HostLength + DomainLength ;
|
|
|
|
DontSetReturn = TRUE ;
|
|
}
|
|
else if ( GetLastError() == ERROR_MORE_DATA )
|
|
{
|
|
//
|
|
// Simply add. Note that since both account for a
|
|
// null terminator, the '.' that goes between them is
|
|
// covered.
|
|
//
|
|
|
|
*nSize = HostLength + DomainLength ;
|
|
|
|
Status = STATUS_BUFFER_OVERFLOW ;
|
|
|
|
DontSetReturn = FALSE ;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Other error from trying to get the DNS Domain name.
|
|
// Let the error from the call trickle back.
|
|
//
|
|
|
|
*nSize = 0 ;
|
|
|
|
Status = STATUS_UNSUCCESSFUL ;
|
|
|
|
DontSetReturn = TRUE ;
|
|
}
|
|
|
|
}
|
|
else if ( GetLastError() == ERROR_MORE_DATA )
|
|
{
|
|
DomainLength = 0;
|
|
GetComputerNameExW( ComputerNameDnsDomain, NULL, &DomainLength );
|
|
|
|
if ( GetLastError() == ERROR_MORE_DATA )
|
|
{
|
|
//
|
|
// Simply add. Note that since both account for a
|
|
// null terminator, the '.' that goes between them is
|
|
// covered.
|
|
//
|
|
|
|
*nSize = HostLength + DomainLength ;
|
|
|
|
Status = STATUS_BUFFER_OVERFLOW ;
|
|
|
|
DontSetReturn = FALSE ;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
|
|
//
|
|
// Other error from trying to get the DNS Hostname.
|
|
// Let the error from the call trickle back.
|
|
//
|
|
|
|
*nSize = 0 ;
|
|
|
|
Status = STATUS_UNSUCCESSFUL ;
|
|
|
|
DontSetReturn = TRUE ;
|
|
}
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
}
|
|
|
|
if ( !NT_SUCCESS( Status ) )
|
|
{
|
|
if ( !DontSetReturn )
|
|
{
|
|
BaseSetLastNTError( Status );
|
|
}
|
|
return FALSE ;
|
|
}
|
|
|
|
return TRUE ;
|
|
}
|
|
|
|
BOOL
|
|
WINAPI
|
|
SetComputerNameExW(
|
|
IN COMPUTER_NAME_FORMAT NameType,
|
|
IN LPCWSTR lpBuffer
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This sets what the computername will be when the system is next booted. This
|
|
does not effect the active computername for the remainder of this boot, nor
|
|
what is returned by GetComputerName before the next system boot.
|
|
|
|
|
|
Arguments:
|
|
|
|
NameType - Name to set for the system
|
|
|
|
lpComputerName - points to the buffer that is contains the
|
|
null-terminated character string containing the computer name.
|
|
|
|
Return Value:
|
|
|
|
Returns TRUE on success, FALSE on failure.
|
|
|
|
|
|
--*/
|
|
{
|
|
ULONG Length ;
|
|
|
|
//
|
|
// Validate name:
|
|
//
|
|
|
|
if ( !lpBuffer )
|
|
{
|
|
SetLastError( ERROR_INVALID_PARAMETER );
|
|
return FALSE ;
|
|
}
|
|
|
|
Length = wcslen( lpBuffer );
|
|
|
|
if ( Length )
|
|
{
|
|
if ( ( lpBuffer[0] == L' ') ||
|
|
( lpBuffer[ Length - 1 ] == L' ' ) )
|
|
{
|
|
SetLastError( ERROR_INVALID_PARAMETER );
|
|
return FALSE ;
|
|
}
|
|
|
|
}
|
|
|
|
if (wcscspn(lpBuffer, ILLEGAL_NAME_CHARS_STR) < Length) {
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return(FALSE);
|
|
}
|
|
|
|
switch ( NameType )
|
|
{
|
|
case ComputerNamePhysicalNetBIOS:
|
|
return BaseSetNetbiosName( lpBuffer );
|
|
|
|
case ComputerNamePhysicalDnsHostname:
|
|
return BaseSetDnsName( lpBuffer );
|
|
|
|
case ComputerNamePhysicalDnsDomain:
|
|
return BaseSetDnsDomain( lpBuffer );
|
|
|
|
default:
|
|
SetLastError( ERROR_INVALID_PARAMETER );
|
|
return FALSE ;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
// ANSI APIs
|
|
//
|
|
|
|
BOOL
|
|
WINAPI
|
|
GetComputerNameA (
|
|
LPSTR lpBuffer,
|
|
LPDWORD nSize
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This returns the active computername. This is the computername when the
|
|
system was last booted. If this is changed (via SetComputerName) it does
|
|
not take effect until the next system boot.
|
|
|
|
|
|
Arguments:
|
|
|
|
lpBuffer - Points to the buffer that is to receive the
|
|
null-terminated character string containing the computer name.
|
|
|
|
nSize - Specifies the maximum size (in characters) of the buffer. This
|
|
value should be set to at least MAX_COMPUTERNAME_LENGTH to allow
|
|
sufficient room in the buffer for the computer name. The length of
|
|
the string is returned in nSize.
|
|
|
|
Return Value:
|
|
|
|
TRUE on success, FALSE on failure.
|
|
|
|
|
|
--*/
|
|
{
|
|
|
|
UNICODE_STRING UnicodeString;
|
|
ANSI_STRING AnsiString;
|
|
LPWSTR UnicodeBuffer;
|
|
ULONG AnsiSize;
|
|
ULONG UnicodeSize;
|
|
|
|
//
|
|
// Work buffer needs to be twice the size of the user's buffer
|
|
//
|
|
|
|
UnicodeBuffer = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( TMP_TAG ), *nSize * sizeof(WCHAR));
|
|
if (!UnicodeBuffer) {
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
return(FALSE);
|
|
}
|
|
|
|
//
|
|
// Set up an ANSI_STRING that points to the user's buffer
|
|
//
|
|
|
|
AnsiString.MaximumLength = (USHORT) *nSize;
|
|
AnsiString.Length = 0;
|
|
AnsiString.Buffer = lpBuffer;
|
|
|
|
//
|
|
// Call the UNICODE version to do the work
|
|
//
|
|
|
|
UnicodeSize = *nSize ;
|
|
|
|
if (!GetComputerNameW(UnicodeBuffer, &UnicodeSize)) {
|
|
RtlFreeHeap(RtlProcessHeap(), 0, UnicodeBuffer);
|
|
return(FALSE);
|
|
}
|
|
|
|
//
|
|
// Find out the required size of the ANSI buffer and validate it against
|
|
// the passed in buffer size
|
|
//
|
|
|
|
RtlInitUnicodeString(&UnicodeString, UnicodeBuffer);
|
|
AnsiSize = RtlUnicodeStringToAnsiSize(&UnicodeString);
|
|
if (AnsiSize > *nSize) {
|
|
|
|
RtlFreeHeap(RtlProcessHeap(), 0, UnicodeBuffer);
|
|
|
|
BaseSetLastNTError( STATUS_BUFFER_OVERFLOW );
|
|
|
|
*nSize = AnsiSize + 1 ;
|
|
|
|
return(FALSE);
|
|
}
|
|
|
|
|
|
//
|
|
// Now convert back to ANSI for the caller
|
|
//
|
|
|
|
RtlUnicodeStringToAnsiString(&AnsiString, &UnicodeString, FALSE);
|
|
|
|
*nSize = AnsiString.Length;
|
|
RtlFreeHeap(RtlProcessHeap(), 0, UnicodeBuffer);
|
|
return(TRUE);
|
|
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
WINAPI
|
|
SetComputerNameA (
|
|
LPCSTR lpComputerName
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This sets what the computername will be when the system is next booted. This
|
|
does not effect the active computername for the remainder of this boot, nor
|
|
what is returned by GetComputerName before the next system boot.
|
|
|
|
|
|
Arguments:
|
|
|
|
lpComputerName - points to the buffer that is contains the
|
|
null-terminated character string containing the computer name.
|
|
|
|
Return Value:
|
|
|
|
Returns TRUE on success, FALSE on failure.
|
|
|
|
|
|
--*/
|
|
{
|
|
|
|
NTSTATUS NtStatus;
|
|
BOOL ReturnValue;
|
|
UNICODE_STRING UnicodeString;
|
|
ANSI_STRING AnsiString;
|
|
ULONG ComputerNameLength;
|
|
|
|
//
|
|
// Validate that the supplied computername is valid (not too long,
|
|
// no incorrect characters, no leading or trailing spaces)
|
|
//
|
|
|
|
ComputerNameLength = strlen(lpComputerName);
|
|
if ((ComputerNameLength == 0 )||(ComputerNameLength > MAX_COMPUTERNAME_LENGTH)) {
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return(FALSE);
|
|
}
|
|
|
|
RtlInitAnsiString(&AnsiString, lpComputerName);
|
|
NtStatus = RtlAnsiStringToUnicodeString(&UnicodeString, &AnsiString,
|
|
TRUE);
|
|
if (!NT_SUCCESS(NtStatus)) {
|
|
BaseSetLastNTError(NtStatus);
|
|
return(FALSE);
|
|
}
|
|
|
|
ReturnValue = SetComputerNameW((LPCWSTR)UnicodeString.Buffer);
|
|
RtlFreeUnicodeString(&UnicodeString);
|
|
return(ReturnValue);
|
|
}
|
|
|
|
BOOL
|
|
WINAPI
|
|
GetComputerNameExA(
|
|
IN COMPUTER_NAME_FORMAT NameType,
|
|
OUT LPSTR lpBuffer,
|
|
IN OUT LPDWORD nSize
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This returns the active computername in a particular format. This is the
|
|
computername when the system was last booted. If this is changed (via
|
|
SetComputerName) it does not take effect until the next system boot.
|
|
|
|
|
|
Arguments:
|
|
|
|
NameType - Possible name formats to return the computer name in:
|
|
|
|
ComputerNameNetBIOS - netbios name (compatible with GetComputerName)
|
|
ComputerNameDnsHostname - DNS host name
|
|
ComputerNameDnsDomain - DNS Domain name
|
|
ComputerNameDnsFullyQualified - DNS Fully Qualified (hostname.dnsdomain)
|
|
|
|
lpBuffer - Points to the buffer that is to receive the
|
|
null-terminated character string containing the computer name.
|
|
|
|
nSize - Specifies the maximum size (in characters) of the buffer. This
|
|
value should be set to at least MAX_COMPUTERNAME_LENGTH + 1 to allow
|
|
sufficient room in the buffer for the computer name. The length
|
|
of the string is returned in nSize.
|
|
|
|
Return Value:
|
|
|
|
TRUE on success, FALSE on failure.
|
|
|
|
|
|
--*/
|
|
{
|
|
LPWSTR UnicodeBuffer;
|
|
|
|
//
|
|
// Validate Input
|
|
//
|
|
|
|
if ((nSize==NULL) || ((lpBuffer==NULL) && (*nSize>0))) {
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return(FALSE);
|
|
}
|
|
|
|
//
|
|
// Work buffer needs to be twice the size of the user's buffer
|
|
//
|
|
|
|
UnicodeBuffer = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( TMP_TAG ), *nSize * sizeof(WCHAR));
|
|
if (!UnicodeBuffer) {
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
return(FALSE);
|
|
}
|
|
|
|
//
|
|
// Call the UNICODE version to do the work
|
|
//
|
|
|
|
if ( !GetComputerNameExW(NameType, UnicodeBuffer, nSize) ) {
|
|
RtlFreeHeap(RtlProcessHeap(), 0, UnicodeBuffer);
|
|
return(FALSE);
|
|
}
|
|
|
|
//
|
|
// Now convert back to ANSI for the caller
|
|
// Note: Since we passed the above if statement,
|
|
// GetComputerNameExW succeeded, and set *nSize to the number of
|
|
// characters in the string (like wcslen). We need to convert
|
|
// all these characters and the trailing NULL, so inc *nSize for
|
|
// the conversion call.
|
|
//
|
|
|
|
WideCharToMultiByte(CP_ACP,
|
|
0,
|
|
UnicodeBuffer,
|
|
*nSize+1,
|
|
lpBuffer,
|
|
(*nSize+1) * sizeof(CHAR),
|
|
NULL,
|
|
NULL);
|
|
|
|
RtlFreeHeap(RtlProcessHeap(), 0, UnicodeBuffer);
|
|
return(TRUE);
|
|
|
|
|
|
}
|
|
|
|
BOOL
|
|
WINAPI
|
|
SetComputerNameExA(
|
|
IN COMPUTER_NAME_FORMAT NameType,
|
|
IN LPCSTR lpBuffer
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This sets what the computername will be when the system is next booted. This
|
|
does not effect the active computername for the remainder of this boot, nor
|
|
what is returned by GetComputerName before the next system boot.
|
|
|
|
|
|
Arguments:
|
|
|
|
NameType - Name to set for the system
|
|
|
|
lpComputerName - points to the buffer that is contains the
|
|
null-terminated character string containing the computer name.
|
|
|
|
Return Value:
|
|
|
|
Returns TRUE on success, FALSE on failure.
|
|
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS NtStatus;
|
|
BOOL ReturnValue;
|
|
UNICODE_STRING UnicodeString;
|
|
ANSI_STRING AnsiString;
|
|
|
|
|
|
RtlInitAnsiString(&AnsiString, lpBuffer);
|
|
NtStatus = RtlAnsiStringToUnicodeString(&UnicodeString, &AnsiString,
|
|
TRUE);
|
|
if (!NT_SUCCESS(NtStatus)) {
|
|
BaseSetLastNTError(NtStatus);
|
|
return(FALSE);
|
|
}
|
|
|
|
ReturnValue = SetComputerNameExW(NameType, (LPCWSTR)UnicodeString.Buffer );
|
|
RtlFreeUnicodeString(&UnicodeString);
|
|
return(ReturnValue);
|
|
}
|
|
|
|
DWORD
|
|
WINAPI
|
|
AddLocalAlternateComputerNameW(
|
|
LPCWSTR lpDnsFQHostname,
|
|
ULONG ulFlags
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This sets an alternate computer name for the computer to begin to
|
|
respond to.
|
|
|
|
|
|
Arguments:
|
|
|
|
lpDnsFQHostname - The alternate name to add (in ComputerNameDnsFullyQualified Format)
|
|
|
|
ulFlags - TBD
|
|
|
|
Return Value:
|
|
|
|
Returns ERROR
|
|
|
|
--*/
|
|
{
|
|
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
DWORD err = ERROR_SUCCESS;
|
|
LPWSTR lpNetBiosCompName = NULL;
|
|
ULONG ulNetBiosCompNameSize = 0;
|
|
LPWSTR lpHostname = BaseParseDnsName(lpDnsFQHostname,DNS_HOSTNAME);
|
|
|
|
//
|
|
// validate input
|
|
//
|
|
|
|
if ((lpDnsFQHostname==NULL) || (!BaseValidateFlags(ulFlags)) || (!BaseValidateDnsNames(lpHostname))) {
|
|
if (lpHostname) {
|
|
RtlFreeHeap(RtlProcessHeap(), 0, lpHostname);
|
|
}
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
// get write lock?
|
|
|
|
status = BaseAddMultiNameInReg(
|
|
DNSCACHE_ROOT,
|
|
DNS_ALT_HOSTNAME,
|
|
lpDnsFQHostname);
|
|
|
|
err = RtlNtStatusToDosError(status);
|
|
|
|
if (err==ERROR_SUCCESS) {
|
|
// get NetBios name (use DNSHostNameToComputerNameW) and add that to reg for OptionalNames
|
|
if (!DnsHostnameToComputerNameW(
|
|
lpDnsFQHostname,
|
|
NULL,
|
|
&ulNetBiosCompNameSize)) {
|
|
err = GetLastError();
|
|
}
|
|
|
|
if (err==ERROR_MORE_DATA) {
|
|
// bug in DNSHostname, returns a size 1 character too small (forgets null)
|
|
// update when bug is fixed...
|
|
ulNetBiosCompNameSize += 1;
|
|
lpNetBiosCompName = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( TMP_TAG ), ulNetBiosCompNameSize * sizeof(WCHAR));
|
|
if (lpNetBiosCompName==NULL) {
|
|
err = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
else {
|
|
if (!DnsHostnameToComputerNameW(lpDnsFQHostname,
|
|
lpNetBiosCompName,
|
|
&ulNetBiosCompNameSize)) {
|
|
err = GetLastError();
|
|
}
|
|
else {
|
|
if (!BaseSetAltNetBiosName(lpNetBiosCompName)) {
|
|
err = GetLastError();
|
|
}
|
|
}
|
|
RtlFreeHeap(RtlProcessHeap(), 0, lpNetBiosCompName);
|
|
}
|
|
}
|
|
|
|
if (err!=ERROR_SUCCESS) {
|
|
// remove multi name in reg
|
|
// rollback?
|
|
}
|
|
}
|
|
if (lpHostname) {
|
|
RtlFreeHeap(RtlProcessHeap(), 0, lpHostname);
|
|
}
|
|
// release write lock?
|
|
return RtlNtStatusToDosError(status);
|
|
}
|
|
|
|
DWORD
|
|
WINAPI
|
|
AddLocalAlternateComputerNameA(
|
|
LPCSTR lpDnsFQHostname,
|
|
ULONG ulFlags
|
|
)
|
|
{
|
|
|
|
LPWSTR lpDnsFQHostnameW = NULL;
|
|
DWORD err = ERROR_SUCCESS;
|
|
|
|
if (lpDnsFQHostname==NULL) {
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
err = BaseMultiByteToWideCharWithAlloc(lpDnsFQHostname, &lpDnsFQHostnameW);
|
|
|
|
if (err==ERROR_SUCCESS) {
|
|
err = AddLocalAlternateComputerNameW(lpDnsFQHostnameW, ulFlags);
|
|
}
|
|
|
|
BaseConvertCharFree((VOID *)lpDnsFQHostnameW);
|
|
return err;
|
|
}
|
|
|
|
DWORD
|
|
WINAPI
|
|
RemoveLocalAlternateComputerNameW(
|
|
LPCWSTR lpAltDnsFQHostname,
|
|
ULONG ulFlags
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Remove an alternate computer name.
|
|
|
|
|
|
Arguments:
|
|
|
|
lpAltDnsFQHostname - The alternate name to remove(in ComputerNameDnsFullyQualified Format)
|
|
|
|
ulFlags - TBD
|
|
|
|
Return Value:
|
|
|
|
Returns ERROR
|
|
|
|
--*/
|
|
{
|
|
DWORD err = ERROR_SUCCESS;
|
|
NTSTATUS NtStatus = STATUS_SUCCESS;
|
|
LPWSTR lpAltNetBiosCompName = NULL;
|
|
ULONG cchAltNetBiosCompName = 0;
|
|
|
|
if ((!BaseValidateFlags(ulFlags)) || (lpAltDnsFQHostname==NULL)) {
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
// aquire a write lock?
|
|
|
|
NtStatus = BaseRemoveMultiNameFromReg(DNSCACHE_ROOT, DNS_ALT_HOSTNAME, lpAltDnsFQHostname);
|
|
err = RtlNtStatusToDosError(NtStatus);
|
|
|
|
if (err==ERROR_SUCCESS) {
|
|
if (!DnsHostnameToComputerNameW(
|
|
lpAltDnsFQHostname,
|
|
NULL,
|
|
&cchAltNetBiosCompName)) {
|
|
err = GetLastError();
|
|
}
|
|
if (err==ERROR_MORE_DATA) {
|
|
// bug in DNSHostname, returns a size 1 character too small (forgets null)
|
|
cchAltNetBiosCompName += 1;
|
|
lpAltNetBiosCompName = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( TMP_TAG ), cchAltNetBiosCompName * sizeof(WCHAR));
|
|
if (lpAltNetBiosCompName==NULL) {
|
|
err = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
else {
|
|
err = ERROR_SUCCESS;
|
|
if (!DnsHostnameToComputerNameW(lpAltDnsFQHostname,
|
|
lpAltNetBiosCompName,
|
|
&cchAltNetBiosCompName)) {
|
|
err = GetLastError();
|
|
} else if (BaseIsNetBiosNameInUse(lpAltNetBiosCompName)) {
|
|
// do nothing, this name is still being used by another AltDnsHostname ...
|
|
} else if (!BaseRemoveAltNetBiosName(lpAltNetBiosCompName)) {
|
|
err = GetLastError();
|
|
}
|
|
RtlFreeHeap(RtlProcessHeap(), 0, lpAltNetBiosCompName);
|
|
}
|
|
}
|
|
}
|
|
|
|
// release write lock?
|
|
|
|
return err;
|
|
}
|
|
|
|
DWORD
|
|
WINAPI
|
|
RemoveLocalAlternateComputerNameA(
|
|
LPCSTR lpAltDnsFQHostname,
|
|
ULONG ulFlags
|
|
)
|
|
{
|
|
LPWSTR lpAltDnsFQHostnameW = NULL;
|
|
DWORD err = ERROR_SUCCESS;
|
|
|
|
if (lpAltDnsFQHostname==NULL) {
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
err = BaseMultiByteToWideCharWithAlloc(lpAltDnsFQHostname, &lpAltDnsFQHostnameW);
|
|
|
|
if (err==ERROR_SUCCESS) {
|
|
err = RemoveLocalAlternateComputerNameW(lpAltDnsFQHostnameW, ulFlags);
|
|
}
|
|
|
|
BaseConvertCharFree((VOID *)lpAltDnsFQHostnameW);
|
|
return err;
|
|
}
|
|
|
|
DWORD
|
|
WINAPI
|
|
SetLocalPrimaryComputerNameW(
|
|
LPCWSTR lpAltDnsFQHostname,
|
|
ULONG ulFlags
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Set the computer name to the inputed altCompName
|
|
|
|
|
|
Arguments:
|
|
|
|
lpAltDnsFQHostname - The name to set the computer to (in ComputerNameDnsFullyQualified Format)
|
|
|
|
ulFlags - TBD
|
|
|
|
Return Value:
|
|
|
|
Returns ERROR
|
|
|
|
--*/
|
|
{
|
|
|
|
DWORD err = ERROR_SUCCESS;
|
|
ULONG cchNetBiosName = 0;
|
|
LPWSTR lpNetBiosName = NULL;
|
|
ULONG cchCompName = 0;
|
|
LPWSTR lpCompName = NULL;
|
|
LPWSTR lpHostname = BaseParseDnsName(lpAltDnsFQHostname, DNS_HOSTNAME);
|
|
LPWSTR lpDomainName = BaseParseDnsName(lpAltDnsFQHostname, DNS_DOMAINNAME);
|
|
|
|
if ((lpAltDnsFQHostname==NULL) || (!BaseValidateFlags(ulFlags))) {
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
// aquire a write lock?
|
|
|
|
// check to see that the given name is a valid alternate dns hostname
|
|
if (!BaseIsAltDnsFQHostname(lpAltDnsFQHostname)) {
|
|
if (lpHostname) {
|
|
RtlFreeHeap(RtlProcessHeap(), 0, lpHostname);
|
|
}
|
|
if (lpDomainName) {
|
|
RtlFreeHeap(RtlProcessHeap(), 0, lpDomainName);
|
|
}
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
// get the current net bios name and add it to the alternate names
|
|
if (!GetComputerNameExW(ComputerNamePhysicalNetBIOS, NULL, &cchNetBiosName)) {
|
|
err = GetLastError();
|
|
}
|
|
if (err==ERROR_MORE_DATA) {
|
|
lpNetBiosName = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( TMP_TAG ), cchNetBiosName*sizeof(WCHAR));
|
|
if (lpNetBiosName==NULL) {
|
|
err = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
else if (!GetComputerNameExW(ComputerNamePhysicalNetBIOS, lpNetBiosName, &cchNetBiosName)) {
|
|
err = GetLastError();
|
|
}
|
|
else if (!BaseSetAltNetBiosName(lpNetBiosName)) {
|
|
err = GetLastError();
|
|
}
|
|
else {
|
|
err = ERROR_SUCCESS;
|
|
}
|
|
if (lpNetBiosName) {
|
|
RtlFreeHeap(RtlProcessHeap(), 0, lpNetBiosName);
|
|
}
|
|
}
|
|
|
|
if (err==ERROR_SUCCESS) {
|
|
// add the physical dnsname to the list of alternate hostnames...
|
|
|
|
if (!GetComputerNameExW(ComputerNamePhysicalDnsFullyQualified, NULL, &cchCompName)) {
|
|
err = GetLastError();
|
|
}
|
|
if (err==ERROR_MORE_DATA) {
|
|
lpCompName = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( TMP_TAG ), cchCompName*sizeof(WCHAR));
|
|
if (lpCompName==NULL) {
|
|
err = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
else if (!GetComputerNameExW(ComputerNamePhysicalDnsFullyQualified, lpCompName, &cchCompName)) {
|
|
err = GetLastError();
|
|
}
|
|
else if (!BaseSetAltDnsFQHostname(lpCompName)) {
|
|
err = GetLastError();
|
|
}
|
|
else {
|
|
err = ERROR_SUCCESS;
|
|
}
|
|
if (lpCompName) {
|
|
RtlFreeHeap(RtlProcessHeap(), 0, lpCompName);
|
|
}
|
|
}
|
|
}
|
|
|
|
// set the new physical dns hostname
|
|
if (err==ERROR_SUCCESS) {
|
|
if (!SetComputerNameExW(ComputerNamePhysicalDnsHostname, lpHostname)) {
|
|
err = GetLastError();
|
|
}
|
|
}
|
|
|
|
if (err==ERROR_SUCCESS) {
|
|
if (!SetComputerNameExW(ComputerNamePhysicalDnsDomain, lpDomainName)) {
|
|
err = GetLastError();
|
|
}
|
|
}
|
|
|
|
// remove the alternate name (now primary) from the alternate lists
|
|
if (err==ERROR_SUCCESS) {
|
|
err = RemoveLocalAlternateComputerNameW(lpAltDnsFQHostname, 0);
|
|
}
|
|
|
|
if (lpHostname) {
|
|
RtlFreeHeap(RtlProcessHeap(), 0, lpHostname);
|
|
}
|
|
if (lpDomainName) {
|
|
RtlFreeHeap(RtlProcessHeap(), 0, lpDomainName);
|
|
}
|
|
// release write lock?
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
DWORD
|
|
WINAPI
|
|
SetLocalPrimaryComputerNameA(
|
|
LPCSTR lpAltDnsFQHostname,
|
|
ULONG ulFlags
|
|
)
|
|
{
|
|
LPWSTR lpAltDnsFQHostnameW = NULL;
|
|
DWORD err = ERROR_SUCCESS;
|
|
|
|
if (lpAltDnsFQHostname==NULL) {
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
err = BaseMultiByteToWideCharWithAlloc(lpAltDnsFQHostname, &lpAltDnsFQHostnameW);
|
|
if (err == ERROR_SUCCESS) {
|
|
err = SetLocalPrimaryComputerNameW(lpAltDnsFQHostnameW, ulFlags);
|
|
}
|
|
BaseConvertCharFree((VOID *)lpAltDnsFQHostnameW);
|
|
|
|
return err;
|
|
}
|
|
|
|
DWORD
|
|
WINAPI
|
|
EnumerateLocalComputerNamesW(
|
|
COMPUTER_NAME_TYPE NameType,
|
|
ULONG ulFlags,
|
|
LPWSTR lpDnsFQHostnames,
|
|
LPDWORD nSize
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Returns the value of the computer's names requested.
|
|
|
|
|
|
Arguments:
|
|
|
|
NameType - Which of the computer's names are requested
|
|
PrimaryComputerName - Similar to GetComputerEx(ComputerNamePhysicalNetBios, ...
|
|
AlternateComputerNames - All known alt names
|
|
AllComputerNames - All of the above
|
|
|
|
ulFlags - TBD
|
|
|
|
lpBuffer - Buffer to hold returned names concatenated together, and trailed with a NULL
|
|
|
|
nSize - Size of buffer to hold returned names.
|
|
|
|
Return Value:
|
|
|
|
Returns ERROR
|
|
|
|
--*/
|
|
{
|
|
DWORD err = ERROR_SUCCESS;
|
|
DWORD SizePrimary = 0;
|
|
DWORD SizeAlternate = 0;
|
|
LPWSTR lpTempCompNames = NULL;
|
|
|
|
if ((!BaseValidateFlags(ulFlags)) || (NameType>=ComputerNameTypeMax) || (NameType<PrimaryComputerName)) {
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
// get read lock?
|
|
switch(NameType) {
|
|
case PrimaryComputerName:
|
|
if (!GetComputerNameExW(ComputerNamePhysicalDnsFullyQualified, lpDnsFQHostnames, nSize)) {
|
|
err = GetLastError();
|
|
}
|
|
break;
|
|
case AlternateComputerNames:
|
|
if ((nSize==NULL) || ((lpDnsFQHostnames==NULL) && (*nSize>0))) {
|
|
err = ERROR_INVALID_PARAMETER;
|
|
}
|
|
else {
|
|
err = BaseEnumAltDnsFQHostnames(lpDnsFQHostnames, nSize);
|
|
}
|
|
break;
|
|
case AllComputerNames:
|
|
if ((nSize==NULL) || ((lpDnsFQHostnames==NULL) && (*nSize>0))) {
|
|
err = ERROR_INVALID_PARAMETER;
|
|
}
|
|
else {
|
|
SizePrimary = *nSize;
|
|
lpTempCompNames = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( TMP_TAG ), *nSize * sizeof(WCHAR));
|
|
if (lpTempCompNames==NULL) {
|
|
err = ERROR_NOT_ENOUGH_MEMORY;
|
|
break;
|
|
}
|
|
// Get primary name
|
|
if (!GetComputerNameExW(ComputerNamePhysicalDnsFullyQualified, lpTempCompNames, &SizePrimary)) {
|
|
err = GetLastError();
|
|
}
|
|
|
|
// on success, holds the number of characters copied into lpTempCompNames NOT counting NULL
|
|
// on failure, holds the space needed to copy in, (num characters PLUS NULL)
|
|
if (err==ERROR_SUCCESS) {
|
|
SizeAlternate = *nSize - (SizePrimary + 1);
|
|
err = BaseEnumAltDnsFQHostnames(lpTempCompNames+SizePrimary+1, &SizeAlternate);
|
|
*nSize = SizePrimary + 1 + SizeAlternate;
|
|
if (err==ERROR_SUCCESS) {
|
|
memcpy(lpDnsFQHostnames, lpTempCompNames, (*nSize+1)*sizeof(WCHAR));
|
|
}
|
|
}
|
|
else if (err==ERROR_MORE_DATA) {
|
|
// return total size required
|
|
SizeAlternate = 0;
|
|
err = BaseEnumAltDnsFQHostnames(NULL, &SizeAlternate);
|
|
if (err==ERROR_SUCCESS) {
|
|
// no alt names exist, keep ERROR_MORE_DATA to return to client
|
|
err = ERROR_MORE_DATA;
|
|
}
|
|
*nSize = SizePrimary + SizeAlternate;
|
|
}
|
|
RtlFreeHeap(RtlProcessHeap(), 0, lpTempCompNames);
|
|
}
|
|
break;
|
|
default:
|
|
err = ERROR_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
// release read lock?
|
|
return err;
|
|
}
|
|
|
|
DWORD
|
|
WINAPI
|
|
EnumerateLocalComputerNamesA(
|
|
COMPUTER_NAME_TYPE NameType,
|
|
ULONG ulFlags,
|
|
LPSTR lpDnsFQHostnames,
|
|
LPDWORD nSize
|
|
)
|
|
{
|
|
DWORD err = ERROR_SUCCESS;
|
|
LPWSTR lpDnsFQHostnamesW = NULL;
|
|
|
|
//
|
|
// Validate Input
|
|
//
|
|
|
|
if ((nSize==NULL) || ((lpDnsFQHostnames==NULL) && (*nSize>0))) {
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
if (lpDnsFQHostnames!=NULL) {
|
|
lpDnsFQHostnamesW = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( TMP_TAG ), *nSize * sizeof(WCHAR));
|
|
if (lpDnsFQHostnamesW==NULL) {
|
|
err = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
}
|
|
|
|
if (err==ERROR_SUCCESS) {
|
|
err = EnumerateLocalComputerNamesW(NameType, ulFlags, lpDnsFQHostnamesW, nSize);
|
|
}
|
|
|
|
if (err==ERROR_SUCCESS) {
|
|
if (!WideCharToMultiByte(CP_ACP, 0, lpDnsFQHostnamesW, *nSize+1,
|
|
lpDnsFQHostnames, (*nSize+1)* sizeof(CHAR), NULL, NULL)) {
|
|
err = GetLastError();
|
|
}
|
|
}
|
|
|
|
if (lpDnsFQHostnamesW) {
|
|
RtlFreeHeap(RtlProcessHeap(), 0, lpDnsFQHostnamesW);
|
|
}
|
|
return err;
|
|
|
|
}
|
|
|
|
BOOL
|
|
WINAPI
|
|
DnsHostnameToComputerNameW(
|
|
IN LPCWSTR Hostname,
|
|
OUT LPWSTR ComputerName,
|
|
IN OUT LPDWORD nSize)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine will convert a DNS Hostname to a Win32 Computer Name.
|
|
|
|
Arguments:
|
|
|
|
Hostname - DNS Hostname (any length)
|
|
|
|
ComputerName - Win32 Computer Name (max length of MAX_COMPUTERNAME_LENGTH)
|
|
|
|
nSize - On input, size of the buffer pointed to by ComputerName. On output,
|
|
size of the Computer Name, in characters.
|
|
|
|
Return Value:
|
|
|
|
Returns TRUE on success, FALSE on failure.
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
WCHAR CompName[ MAX_COMPUTERNAME_LENGTH + 1 ];
|
|
DWORD Size = MAX_COMPUTERNAME_LENGTH + 1 ;
|
|
UNICODE_STRING CompName_U ;
|
|
UNICODE_STRING Hostname_U ;
|
|
NTSTATUS Status ;
|
|
BOOL Ret ;
|
|
|
|
CompName[0] = L'\0';
|
|
CompName_U.Buffer = CompName ;
|
|
CompName_U.Length = 0 ;
|
|
CompName_U.MaximumLength = (MAX_COMPUTERNAME_LENGTH + 1) * sizeof( WCHAR );
|
|
|
|
RtlInitUnicodeString( &Hostname_U, Hostname );
|
|
|
|
Status = RtlDnsHostNameToComputerName( &CompName_U,
|
|
&Hostname_U,
|
|
FALSE );
|
|
|
|
if ( NT_SUCCESS( Status ) )
|
|
{
|
|
if ( *nSize >= CompName_U.Length / sizeof(WCHAR) + 1 )
|
|
{
|
|
RtlCopyMemory( ComputerName,
|
|
CompName_U.Buffer,
|
|
CompName_U.Length );
|
|
|
|
ComputerName[ CompName_U.Length / sizeof( WCHAR ) ] = L'\0';
|
|
|
|
Ret = TRUE ;
|
|
}
|
|
else
|
|
{
|
|
BaseSetLastNTError( STATUS_BUFFER_OVERFLOW );
|
|
Ret = FALSE ;
|
|
}
|
|
|
|
//
|
|
// returns the count of characters
|
|
//
|
|
|
|
*nSize = CompName_U.Length / sizeof( WCHAR );
|
|
}
|
|
else
|
|
{
|
|
BaseSetLastNTError( Status );
|
|
|
|
Ret = FALSE ;
|
|
}
|
|
|
|
return Ret ;
|
|
|
|
}
|
|
|
|
BOOL
|
|
WINAPI
|
|
DnsHostnameToComputerNameA(
|
|
IN LPCSTR Hostname,
|
|
OUT LPSTR ComputerName,
|
|
IN OUT LPDWORD nSize)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine will convert a DNS Hostname to a Win32 Computer Name.
|
|
|
|
Arguments:
|
|
|
|
Hostname - DNS Hostname (any length)
|
|
|
|
ComputerName - Win32 Computer Name (max length of MAX_COMPUTERNAME_LENGTH)
|
|
|
|
nSize - On input, size of the buffer pointed to by ComputerName. On output,
|
|
size of the Computer Name, in characters.
|
|
|
|
Return Value:
|
|
|
|
Returns TRUE on success, FALSE on failure.
|
|
|
|
|
|
--*/
|
|
{
|
|
WCHAR CompName[ MAX_COMPUTERNAME_LENGTH + 1 ];
|
|
DWORD Size = MAX_COMPUTERNAME_LENGTH + 1;
|
|
BOOL Ret ;
|
|
UNICODE_STRING CompName_U ;
|
|
UNICODE_STRING Hostname_U ;
|
|
NTSTATUS Status ;
|
|
ANSI_STRING CompName_A ;
|
|
|
|
|
|
Status = RtlCreateUnicodeStringFromAsciiz( &Hostname_U,
|
|
Hostname );
|
|
|
|
if ( NT_SUCCESS( Status ) )
|
|
{
|
|
CompName[0] = L'\0';
|
|
CompName_U.Buffer = CompName ;
|
|
CompName_U.Length = 0 ;
|
|
CompName_U.MaximumLength = (MAX_COMPUTERNAME_LENGTH + 1) * sizeof( WCHAR );
|
|
|
|
Status = RtlDnsHostNameToComputerName( &CompName_U,
|
|
&Hostname_U,
|
|
FALSE );
|
|
|
|
if ( NT_SUCCESS( Status ) )
|
|
{
|
|
CompName_A.Buffer = ComputerName ;
|
|
CompName_A.Length = 0 ;
|
|
CompName_A.MaximumLength = (USHORT) *nSize ;
|
|
|
|
Status = RtlUnicodeStringToAnsiString( &CompName_A, &CompName_U, FALSE );
|
|
|
|
if ( NT_SUCCESS( Status ) )
|
|
{
|
|
*nSize = CompName_A.Length ;
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ( !NT_SUCCESS( Status ) )
|
|
{
|
|
BaseSetLastNTError( Status );
|
|
return FALSE ;
|
|
}
|
|
|
|
return TRUE ;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#include "dfsfsctl.h"
|
|
DWORD
|
|
BasepGetComputerNameFromNtPath (
|
|
PUNICODE_STRING NtPathName,
|
|
HANDLE hFile,
|
|
LPWSTR lpBuffer,
|
|
LPDWORD nSize
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Look at a path and determine the computer name of the host machine.
|
|
In the future, we should remove this code, and add the capbility to query
|
|
handles for their computer name.
|
|
|
|
The name can only be obtained for NetBios paths - if the path is IP or DNS
|
|
an error is returned. (If the NetBios name has a "." in it, it will
|
|
cause an error because it will be misinterpreted as a DNS path. This case
|
|
becomes less and less likely as the NT5 UI doesn't allow such computer names.)
|
|
For DFS paths, the leaf server's name is returned, as long as it wasn't
|
|
joined to its parent with an IP or DNS path name.
|
|
|
|
Arguments:
|
|
|
|
NtPathName - points to a unicode string with the path to query.
|
|
lpBuffer - points to buffer receives the computer name
|
|
nSize - points to dword with the size of the input buffer, and the length
|
|
(in characters, not including the null terminator) of the computer name
|
|
on output.
|
|
|
|
Return Value:
|
|
|
|
A Win32 error code.
|
|
|
|
--*/
|
|
{
|
|
ULONG cbComputer = 0;
|
|
DWORD dwError = ERROR_BAD_PATHNAME;
|
|
ULONG AvailableLength = 0;
|
|
PWCHAR PathCharacter = NULL;
|
|
BOOL CheckForDfs = TRUE;
|
|
NTSTATUS NtStatus = STATUS_SUCCESS;
|
|
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
WCHAR FileNameInfoBuffer[MAX_PATH+sizeof(FILE_NAME_INFORMATION)];
|
|
PFILE_NAME_INFORMATION FileNameInfo = (PFILE_NAME_INFORMATION)FileNameInfoBuffer;
|
|
WCHAR DfsServerPathName[ MAX_PATH + 1 ];
|
|
WCHAR DosDevice[3] = { L"A:" };
|
|
WCHAR DosDeviceMapping[ MAX_PATH + 1 ];
|
|
|
|
|
|
UNICODE_STRING UnicodeComputerName;
|
|
|
|
const UNICODE_STRING NtUncPathNamePrefix = { 16, 18, L"\\??\\UNC\\"};
|
|
const ULONG cchNtUncPathNamePrefix = 8;
|
|
|
|
const UNICODE_STRING NtDrivePathNamePrefix = { 8, 10, L"\\??\\" };
|
|
const ULONG cchNtDrivePathNamePrefix = 4;
|
|
|
|
RtlInitUnicodeString( &UnicodeComputerName, NULL );
|
|
|
|
// Is this a UNC path?
|
|
|
|
if( RtlPrefixString( (PSTRING)&NtUncPathNamePrefix, (PSTRING)NtPathName, TRUE )) {
|
|
|
|
// Make sure there's some more to this path than just the prefix
|
|
if( NtPathName->Length <= NtUncPathNamePrefix.Length )
|
|
goto Exit;
|
|
|
|
// It appears to be a valid UNC path. Point to the beginning of the computer
|
|
// name, and calculate how much room is left in NtPathName after that.
|
|
|
|
UnicodeComputerName.Buffer = &NtPathName->Buffer[ NtUncPathNamePrefix.Length/sizeof(WCHAR) ];
|
|
AvailableLength = NtPathName->Length - NtUncPathNamePrefix.Length;
|
|
|
|
}
|
|
|
|
// If it's not a UNC path, then is it a drive-letter path?
|
|
|
|
else if( RtlPrefixString( (PSTRING)&NtDrivePathNamePrefix, (PSTRING)NtPathName, TRUE )
|
|
&&
|
|
NtPathName->Buffer[ cchNtDrivePathNamePrefix + 1 ] == L':' ) {
|
|
|
|
// It's a drive letter path, but it could still be local or remote
|
|
|
|
static const WCHAR RedirectorMappingPrefix[] = { L"\\Device\\LanmanRedirector\\;" };
|
|
static const WCHAR LocalVolumeMappingPrefix[] = { L"\\Device\\Harddisk" };
|
|
static const WCHAR CDRomMappingPrefix[] = { L"\\Device\\CdRom" };
|
|
static const WCHAR FloppyMappingPrefix[] = { L"\\Device\\Floppy" };
|
|
static const WCHAR DfsMappingPrefix[] = { L"\\Device\\WinDfs\\" };
|
|
|
|
// Get the correct, upper-cased, drive letter into DosDevice.
|
|
|
|
DosDevice[0] = NtPathName->Buffer[ cchNtDrivePathNamePrefix ];
|
|
if( L'a' <= DosDevice[0] && DosDevice[0] <= L'z' )
|
|
DosDevice[0] = L'A' + (DosDevice[0] - L'a');
|
|
|
|
// Map the drive letter to its symbolic link under \??. E.g., say C:, D: & R:
|
|
// are local/DFS/rdr drives, respectively. You would then see something like:
|
|
//
|
|
// C: => \Device\Volume1
|
|
// D: => \Device\WinDfs\G
|
|
// R: => \Device\LanmanRedirector\;R:0\scratch\scratch
|
|
|
|
if( !QueryDosDeviceW( DosDevice, DosDeviceMapping, sizeof(DosDeviceMapping)/sizeof(DosDeviceMapping[0]) )) {
|
|
dwError = GetLastError();
|
|
goto Exit;
|
|
}
|
|
|
|
// Now that we have the DosDeviceMapping, we can check ... Is this a rdr drive?
|
|
|
|
if( // Does it begin with "\Device\LanmanRedirector\;" ?
|
|
DosDeviceMapping == wcsstr( DosDeviceMapping, RedirectorMappingPrefix )
|
|
&&
|
|
// Are the next letters the correct drive letter, a colon, and a whack?
|
|
( DosDevice[0] == DosDeviceMapping[ sizeof(RedirectorMappingPrefix)/sizeof(WCHAR) - 1 ]
|
|
&&
|
|
L':' == DosDeviceMapping[ sizeof(RedirectorMappingPrefix)/sizeof(WCHAR) ]
|
|
&&
|
|
(UnicodeComputerName.Buffer = wcschr(&DosDeviceMapping[ sizeof(RedirectorMappingPrefix)/sizeof(WCHAR) + 1 ], L'\\'))
|
|
)) {
|
|
|
|
// We have a valid rdr drive. Point to the beginning of the computer
|
|
// name, and calculate how much room is availble in DosDeviceMapping after that.
|
|
|
|
UnicodeComputerName.Buffer += 1;
|
|
AvailableLength = sizeof(DosDeviceMapping) - sizeof(DosDeviceMapping[0]) * (ULONG)(UnicodeComputerName.Buffer - DosDeviceMapping);
|
|
|
|
// We know now that it's not a DFS path
|
|
CheckForDfs = FALSE;
|
|
|
|
}
|
|
|
|
// If it's not a rdr drive, then maybe it's a local volume, floppy, or cdrom
|
|
|
|
else if( DosDeviceMapping == wcsstr( DosDeviceMapping, LocalVolumeMappingPrefix )
|
|
||
|
|
DosDeviceMapping == wcsstr( DosDeviceMapping, CDRomMappingPrefix )
|
|
||
|
|
DosDeviceMapping == wcsstr( DosDeviceMapping, FloppyMappingPrefix ) ) {
|
|
|
|
// We have a local drive, so just return the local computer name.
|
|
|
|
CheckForDfs = FALSE;
|
|
|
|
if( !GetComputerNameW( lpBuffer, nSize))
|
|
dwError = GetLastError();
|
|
else
|
|
dwError = ERROR_SUCCESS;
|
|
goto Exit;
|
|
}
|
|
|
|
// Finally, check to see if it's a DFS drive
|
|
|
|
else if( DosDeviceMapping == wcsstr( DosDeviceMapping, DfsMappingPrefix )) {
|
|
|
|
// Get the full UNC name of this DFS path. Later, we'll call the DFS
|
|
// driver to find out what the actual server name is.
|
|
|
|
NtStatus = NtQueryInformationFile(
|
|
hFile,
|
|
&IoStatusBlock,
|
|
FileNameInfo,
|
|
sizeof(FileNameInfoBuffer),
|
|
FileNameInformation
|
|
);
|
|
if( !NT_SUCCESS(NtStatus) ) {
|
|
dwError = RtlNtStatusToDosError(NtStatus);
|
|
goto Exit;
|
|
}
|
|
|
|
UnicodeComputerName.Buffer = FileNameInfo->FileName + 1;
|
|
AvailableLength = FileNameInfo->FileNameLength;
|
|
}
|
|
|
|
// Otherwise, it's not a rdr, dfs, or local drive, so there's nothing we can do.
|
|
|
|
else
|
|
goto Exit;
|
|
|
|
} // else if( RtlPrefixString( (PSTRING)&NtDrivePathNamePrefix, (PSTRING)NtPathName, TRUE ) ...
|
|
|
|
else {
|
|
dwError = ERROR_BAD_PATHNAME;
|
|
goto Exit;
|
|
}
|
|
|
|
|
|
// If we couldn't determine above if whether or not this is a DFS path, let the
|
|
// DFS driver decide now.
|
|
|
|
if( CheckForDfs && INVALID_HANDLE_VALUE != hFile ) {
|
|
|
|
HANDLE hDFS = INVALID_HANDLE_VALUE;
|
|
UNICODE_STRING DfsDriverName;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
|
|
WCHAR *DfsPathName = UnicodeComputerName.Buffer - 1; // Back up to the whack
|
|
ULONG DfsPathNameLength = AvailableLength + sizeof(WCHAR);
|
|
|
|
// Open the DFS driver
|
|
|
|
RtlInitUnicodeString( &DfsDriverName, DFS_DRIVER_NAME );
|
|
InitializeObjectAttributes( &ObjectAttributes,
|
|
&DfsDriverName,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
NtStatus = NtCreateFile(
|
|
&hDFS,
|
|
SYNCHRONIZE,
|
|
&ObjectAttributes,
|
|
&IoStatusBlock,
|
|
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(NtStatus) ) {
|
|
dwError = RtlNtStatusToDosError(NtStatus);
|
|
goto Exit;
|
|
}
|
|
|
|
// Query DFS's cache for the server name. The name is guaranteed to
|
|
// remain in the cache as long as the file is open.
|
|
|
|
if( L'\\' != DfsPathName[0] ) {
|
|
NtClose(hDFS);
|
|
dwError = ERROR_BAD_PATHNAME;
|
|
goto Exit;
|
|
}
|
|
|
|
NtStatus = NtFsControlFile(
|
|
hDFS,
|
|
NULL, // Event,
|
|
NULL, // ApcRoutine,
|
|
NULL, // ApcContext,
|
|
&IoStatusBlock,
|
|
FSCTL_DFS_GET_SERVER_NAME,
|
|
DfsPathName,
|
|
DfsPathNameLength,
|
|
DfsServerPathName,
|
|
sizeof(DfsServerPathName)
|
|
);
|
|
NtClose( hDFS );
|
|
|
|
// STATUS_OBJECT_NAME_NOT_FOUND means that it's not a DFS path
|
|
if( !NT_SUCCESS(NtStatus) ) {
|
|
if( STATUS_OBJECT_NAME_NOT_FOUND != NtStatus ) {
|
|
dwError = RtlNtStatusToDosError(NtStatus);
|
|
goto Exit;
|
|
}
|
|
}
|
|
else if( L'\0' != DfsServerPathName[0] ) {
|
|
|
|
// The previous DFS call returns the server-specific path to the file in UNC form.
|
|
// Point UnicodeComputerName to just past the two whacks.
|
|
|
|
AvailableLength = wcslen(DfsServerPathName) * sizeof(WCHAR);
|
|
if( 3*sizeof(WCHAR) > AvailableLength
|
|
||
|
|
L'\\' != DfsServerPathName[0]
|
|
||
|
|
L'\\' != DfsServerPathName[1] )
|
|
{
|
|
dwError = ERROR_BAD_PATHNAME;
|
|
goto Exit;
|
|
}
|
|
|
|
UnicodeComputerName.Buffer = DfsServerPathName + 2;
|
|
AvailableLength -= 2 * sizeof(WCHAR);
|
|
}
|
|
}
|
|
|
|
// If we get here, then the computer name\share is pointed to by UnicodeComputerName.Buffer.
|
|
// But the Length is currently zero, so we search for the whack that separates
|
|
// the computer name from the share, and set the Length to include just the computer name.
|
|
|
|
PathCharacter = UnicodeComputerName.Buffer;
|
|
|
|
while( ( (ULONG) ((PCHAR)PathCharacter - (PCHAR)UnicodeComputerName.Buffer) < AvailableLength)
|
|
&&
|
|
*PathCharacter != L'\\' ) {
|
|
|
|
// If we found a '.', we fail because this is probably a DNS or IP name.
|
|
if( L'.' == *PathCharacter ) {
|
|
dwError = ERROR_BAD_PATHNAME;
|
|
goto Exit;
|
|
}
|
|
|
|
PathCharacter++;
|
|
}
|
|
|
|
// Set the computer name length
|
|
|
|
UnicodeComputerName.Length = UnicodeComputerName.MaximumLength
|
|
= (USHORT) ((PCHAR)PathCharacter - (PCHAR)UnicodeComputerName.Buffer);
|
|
|
|
// Fail if the computer name exceeded the length of the input NtPathName,
|
|
// or if the length exceeds that allowed.
|
|
|
|
if( UnicodeComputerName.Length >= AvailableLength
|
|
||
|
|
UnicodeComputerName.Length > MAX_COMPUTERNAME_LENGTH*sizeof(WCHAR) ) {
|
|
goto Exit;
|
|
}
|
|
|
|
// Copy the computer name into the caller's buffer, as long as there's enough
|
|
// room for the name & a terminating '\0'.
|
|
|
|
if( UnicodeComputerName.Length + sizeof(WCHAR) > *nSize * sizeof(WCHAR) ) {
|
|
dwError = ERROR_BUFFER_OVERFLOW;
|
|
goto Exit;
|
|
}
|
|
|
|
RtlCopyMemory( lpBuffer, UnicodeComputerName.Buffer, UnicodeComputerName.Length );
|
|
*nSize = UnicodeComputerName.Length / sizeof(WCHAR);
|
|
lpBuffer[ *nSize ] = L'\0';
|
|
|
|
dwError = ERROR_SUCCESS;
|
|
|
|
|
|
Exit:
|
|
|
|
return( dwError );
|
|
|
|
}
|