Windows NT 4.0 source code leak
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.
 
 
 
 
 
 

699 lines
16 KiB

/*++
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);
}