700 lines
16 KiB
C
700 lines
16 KiB
C
/*++
|
||
|
||
Copyright (c) 1991 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
COMPNAME.C
|
||
|
||
Abstract:
|
||
|
||
This module contains the GetComputerName and SetComputerName APIs.
|
||
|
||
Author:
|
||
|
||
Dan Hinsley (DanHi) 2-Apr-1992
|
||
|
||
|
||
Revision History:
|
||
|
||
|
||
--*/
|
||
|
||
#include <basedll.h>
|
||
|
||
//
|
||
//
|
||
|
||
|
||
#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 L"ActiveComputerName"
|
||
#define NON_VOLATILE_COMPUTERNAME L"ComputerName"
|
||
#define COMPUTERNAME_VALUE_NAME L"ComputerName"
|
||
#define CLASS_STRING L"Network ComputerName"
|
||
|
||
|
||
//
|
||
// 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
|
||
|
||
|
||
//
|
||
// 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 = (PVOID) 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)) {
|
||
|
||
//
|
||
// 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;
|
||
}
|
||
|
||
}
|
||
}
|
||
|
||
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;
|
||
|
||
//
|
||
// 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.
|
||
//
|
||
|
||
//
|
||
// BUGBUG - generate an alert/event/???
|
||
//
|
||
|
||
//
|
||
// Return a NULL computername
|
||
//
|
||
|
||
lpBuffer[0] = L'\0';
|
||
*nSize = 0;
|
||
goto GoodReturn;
|
||
}
|
||
|
||
//
|
||
// 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
|
||
//
|
||
|
||
//
|
||
// BUGBUG - generate and alert/event/???
|
||
//
|
||
|
||
//
|
||
// 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;
|
||
|
||
//
|
||
// Validate that the supplied computername is valid (not too long,
|
||
// no incorrect characters, no leading or trailing spaces)
|
||
//
|
||
|
||
ComputerNameLength = wcslen(lpComputerName);
|
||
if ((ComputerNameLength == 0 )||(ComputerNameLength > 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.
|
||
//
|
||
|
||
//
|
||
// BUGBUG - generate and alert/event/???
|
||
//
|
||
|
||
//
|
||
// Return an error to the user. BUGBUG - should I just create the
|
||
// node here? Does it inherit the correct ACL's?
|
||
//
|
||
|
||
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);
|
||
|
||
}
|
||
|
||
|
||
//
|
||
// 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;
|
||
|
||
//
|
||
// 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
|
||
//
|
||
|
||
if (!GetComputerNameW(UnicodeBuffer, nSize)) {
|
||
RtlFreeHeap(RtlProcessHeap(), 0, UnicodeBuffer);
|
||
return(FALSE);
|
||
}
|
||
|
||
//
|
||
// Now convert back to ANSI for the caller
|
||
//
|
||
|
||
RtlInitUnicodeString(&UnicodeString, UnicodeBuffer);
|
||
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;
|
||
|
||
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);
|
||
}
|