|  | /* | 
|  | * Win32 kernel functions | 
|  | * | 
|  | * Copyright 1995 Martin von Loewis and Cameron Heide | 
|  | * Copyright 1999 Peter Ganten | 
|  | * Copyright 2002 Martin Wilck | 
|  | * | 
|  | * This library is free software; you can redistribute it and/or | 
|  | * modify it under the terms of the GNU Lesser General Public | 
|  | * License as published by the Free Software Foundation; either | 
|  | * version 2.1 of the License, or (at your option) any later version. | 
|  | * | 
|  | * This library is distributed in the hope that it will be useful, | 
|  | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
|  | * Lesser General Public License for more details. | 
|  | * | 
|  | * You should have received a copy of the GNU Lesser General Public | 
|  | * License along with this library; if not, write to the Free Software | 
|  | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | 
|  | */ | 
|  |  | 
|  | #include "config.h" | 
|  | #include "wine/port.h" | 
|  |  | 
|  | #include <stdarg.h> | 
|  | #include <string.h> | 
|  | #ifdef HAVE_UNISTD_H | 
|  | # include <unistd.h> | 
|  | #endif | 
|  | #include <stdlib.h> | 
|  | #include <errno.h> | 
|  | #ifdef HAVE_NETDB_H | 
|  | #include <netdb.h> | 
|  | #endif | 
|  |  | 
|  | #include "ntstatus.h" | 
|  | #define WIN32_NO_STATUS | 
|  | #include "windef.h" | 
|  | #include "winbase.h" | 
|  | #include "winerror.h" | 
|  | #include "winnls.h" | 
|  | #include "winternl.h" | 
|  | #include "wine/unicode.h" | 
|  | #include "wine/exception.h" | 
|  | #include "excpt.h" | 
|  | #include "wine/debug.h" | 
|  |  | 
|  | #include "kernel_private.h" | 
|  |  | 
|  | WINE_DEFAULT_DEBUG_CHANNEL(computername); | 
|  |  | 
|  | /* Registry key and value names */ | 
|  | static const WCHAR ComputerW[] = {'M','a','c','h','i','n','e','\\', | 
|  | 'S','y','s','t','e','m','\\', | 
|  | 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\', | 
|  | 'C','o','n','t','r','o','l','\\', | 
|  | 'C','o','m','p','u','t','e','r','N','a','m','e',0}; | 
|  | static const WCHAR ActiveComputerNameW[] =   {'A','c','t','i','v','e','C','o','m','p','u','t','e','r','N','a','m','e',0}; | 
|  | static const WCHAR ComputerNameW[] = {'C','o','m','p','u','t','e','r','N','a','m','e',0}; | 
|  |  | 
|  | static const char default_ComputerName[] = "WINE"; | 
|  |  | 
|  | #define IS_OPTION_TRUE(ch) ((ch) == 'y' || (ch) == 'Y' || (ch) == 't' || (ch) == 'T' || (ch) == '1') | 
|  |  | 
|  | /*********************************************************************** | 
|  | *                    dns_gethostbyname (INTERNAL) | 
|  | * | 
|  | *  From hostname(1): | 
|  | *  "The FQDN is the name gethostbyname(2) returns for the host name returned by gethostname(2)." | 
|  | * | 
|  | *  Wine can use this technique only if the thread-safe gethostbyname_r is available. | 
|  | */ | 
|  | #ifdef  HAVE_LINUX_GETHOSTBYNAME_R_6 | 
|  | static BOOL dns_gethostbyname ( char *name, int *size ) | 
|  | { | 
|  | struct hostent* host = NULL; | 
|  | char *extrabuf; | 
|  | int ebufsize = 1024; | 
|  | struct hostent hostentry; | 
|  | int locerr = ENOBUFS, res = ENOMEM; | 
|  |  | 
|  | extrabuf = HeapAlloc( GetProcessHeap(), 0, ebufsize ) ; | 
|  |  | 
|  | while( extrabuf ) | 
|  | { | 
|  | res = gethostbyname_r ( name, &hostentry, extrabuf, ebufsize, &host, &locerr ); | 
|  | if( res != ERANGE ) break; | 
|  | ebufsize *= 2; | 
|  | extrabuf = HeapReAlloc( GetProcessHeap(), 0, extrabuf, ebufsize ) ; | 
|  | } | 
|  |  | 
|  | if ( res ) | 
|  | WARN ("Error in gethostbyname_r %d (%d)\n", res, locerr); | 
|  | else | 
|  | { | 
|  | int len = strlen ( host->h_name ); | 
|  | if ( len < *size ) | 
|  | { | 
|  | strcpy ( name, host->h_name ); | 
|  | *size = len; | 
|  | } | 
|  | else | 
|  | { | 
|  | memcpy ( name, host->h_name, *size ); | 
|  | name[*size] = 0; | 
|  | SetLastError ( ERROR_MORE_DATA ); | 
|  | res = 1; | 
|  | } | 
|  | } | 
|  |  | 
|  | HeapFree( GetProcessHeap(), 0, extrabuf ); | 
|  | return !res; | 
|  | } | 
|  | #else | 
|  | #  define dns_gethostbyname(name,size) 0 | 
|  | #endif | 
|  |  | 
|  | /*********************************************************************** | 
|  | *                     dns_fqdn (INTERNAL) | 
|  | */ | 
|  | static BOOL dns_fqdn ( char *name, int *size ) | 
|  | { | 
|  | if ( gethostname ( name, *size + 1 ) ) | 
|  | { | 
|  | switch( errno ) | 
|  | { | 
|  | case ENAMETOOLONG: | 
|  | SetLastError ( ERROR_MORE_DATA ); | 
|  | default: | 
|  | SetLastError ( ERROR_INVALID_PARAMETER ); | 
|  | } | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  | if ( !dns_gethostbyname ( name, size ) ) | 
|  | *size = strlen ( name ); | 
|  |  | 
|  | return TRUE; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *                     dns_hostname (INTERNAL) | 
|  | */ | 
|  | static BOOL dns_hostname ( char *name, int *size ) | 
|  | { | 
|  | char *c; | 
|  | if ( ! dns_fqdn ( name, size ) ) return FALSE; | 
|  | c = strchr ( name, '.' ); | 
|  | if (c) | 
|  | { | 
|  | *c = 0; | 
|  | *size = (c - name); | 
|  | } | 
|  | return TRUE; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *                     dns_domainname (INTERNAL) | 
|  | */ | 
|  | static BOOL dns_domainname ( char *name, int *size ) | 
|  | { | 
|  | char *c; | 
|  | if ( ! dns_fqdn ( name, size ) ) return FALSE; | 
|  | c = strchr ( name, '.' ); | 
|  | if (c) | 
|  | { | 
|  | c += 1; | 
|  | *size -= (c - name); | 
|  | memmove ( name, c, *size + 1 ); | 
|  | } | 
|  | return TRUE; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *                      _init_attr    (INTERNAL) | 
|  | */ | 
|  | inline static void _init_attr ( OBJECT_ATTRIBUTES *attr, UNICODE_STRING *name ) | 
|  | { | 
|  | attr->Length = sizeof (OBJECT_ATTRIBUTES); | 
|  | attr->RootDirectory = 0; | 
|  | attr->ObjectName = name; | 
|  | attr->Attributes = 0; | 
|  | attr->SecurityDescriptor = NULL; | 
|  | attr->SecurityQualityOfService = NULL; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *           get_use_dns_option | 
|  | */ | 
|  | static BOOL get_use_dns_option(void) | 
|  | { | 
|  | static const WCHAR NetworkW[] = {'S','o','f','t','w','a','r','e','\\', | 
|  | 'W','i','n','e','\\','N','e','t','w','o','r','k',0}; | 
|  | static const WCHAR UseDNSW[] = {'U','s','e','D','n','s','C','o','m','p','u','t','e','r','N','a','m','e',0}; | 
|  |  | 
|  | char tmp[80]; | 
|  | HANDLE root, hkey; | 
|  | DWORD dummy; | 
|  | OBJECT_ATTRIBUTES attr; | 
|  | UNICODE_STRING nameW; | 
|  | BOOL ret = TRUE; | 
|  |  | 
|  | _init_attr( &attr, &nameW ); | 
|  | RtlOpenCurrentUser( KEY_ALL_ACCESS, &root ); | 
|  | attr.RootDirectory = root; | 
|  | RtlInitUnicodeString( &nameW, NetworkW ); | 
|  |  | 
|  | /* @@ Wine registry key: HKCU\Software\Wine\Network */ | 
|  | if (!NtOpenKey( &hkey, KEY_ALL_ACCESS, &attr )) | 
|  | { | 
|  | RtlInitUnicodeString( &nameW, UseDNSW ); | 
|  | if (!NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation, tmp, sizeof(tmp), &dummy )) | 
|  | { | 
|  | WCHAR *str = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data; | 
|  | ret = IS_OPTION_TRUE( str[0] ); | 
|  | } | 
|  | NtClose( hkey ); | 
|  | } | 
|  | NtClose( root ); | 
|  | return ret; | 
|  | } | 
|  |  | 
|  |  | 
|  | /*********************************************************************** | 
|  | *                      COMPUTERNAME_Init    (INTERNAL) | 
|  | */ | 
|  | void COMPUTERNAME_Init (void) | 
|  | { | 
|  | HANDLE hkey = INVALID_HANDLE_VALUE, hsubkey = INVALID_HANDLE_VALUE; | 
|  | OBJECT_ATTRIBUTES attr; | 
|  | UNICODE_STRING nameW; | 
|  | char buf[offsetof( KEY_VALUE_PARTIAL_INFORMATION, Data ) + (MAX_COMPUTERNAME_LENGTH + 1) * sizeof( WCHAR )]; | 
|  | DWORD len = sizeof( buf ); | 
|  | LPWSTR computer_name = (LPWSTR) (buf + offsetof( KEY_VALUE_PARTIAL_INFORMATION, Data )); | 
|  | NTSTATUS st = STATUS_INTERNAL_ERROR; | 
|  |  | 
|  | TRACE("(void)\n"); | 
|  | _init_attr ( &attr, &nameW ); | 
|  |  | 
|  | RtlInitUnicodeString( &nameW, ComputerW ); | 
|  | if ( ( st = NtCreateKey( &hkey, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL ) ) != STATUS_SUCCESS ) | 
|  | goto out; | 
|  |  | 
|  | attr.RootDirectory = hkey; | 
|  | RtlInitUnicodeString( &nameW, ComputerNameW ); | 
|  | if ( (st = NtCreateKey( &hsubkey, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL ) ) != STATUS_SUCCESS ) | 
|  | goto out; | 
|  |  | 
|  | st = NtQueryValueKey( hsubkey, &nameW, KeyValuePartialInformation, buf, len, &len ); | 
|  |  | 
|  | if ( st != STATUS_SUCCESS || get_use_dns_option() ) | 
|  | { | 
|  | char hbuf[256]; | 
|  | int hlen = sizeof (hbuf); | 
|  | char *dot; | 
|  | TRACE( "retrieving Unix host name\n" ); | 
|  | if ( gethostname ( hbuf, hlen ) ) | 
|  | { | 
|  | strcpy ( hbuf, default_ComputerName ); | 
|  | WARN( "gethostname() error: %d, using host name %s\n", errno, hbuf ); | 
|  | } | 
|  | hbuf[MAX_COMPUTERNAME_LENGTH] = 0; | 
|  | dot = strchr ( hbuf, '.' ); | 
|  | if ( dot ) *dot = 0; | 
|  | hlen = strlen ( hbuf ); | 
|  | len = MultiByteToWideChar( CP_ACP, 0, hbuf, hlen + 1, computer_name, MAX_COMPUTERNAME_LENGTH + 1 ) | 
|  | * sizeof( WCHAR ); | 
|  | if ( NtSetValueKey( hsubkey, &nameW, 0, REG_SZ, computer_name, len ) != STATUS_SUCCESS ) | 
|  | WARN ( "failed to set ComputerName\n" ); | 
|  | } | 
|  | else if ( st == STATUS_SUCCESS) | 
|  | { | 
|  | len = (len - offsetof( KEY_VALUE_PARTIAL_INFORMATION, Data )); | 
|  | TRACE( "found in registry\n" ); | 
|  | } | 
|  | else goto out; | 
|  |  | 
|  | NtClose( hsubkey ); | 
|  | TRACE(" ComputerName: %s (%lu)\n", debugstr_w ( computer_name ), len / sizeof(WCHAR)); | 
|  |  | 
|  | RtlInitUnicodeString( &nameW, ActiveComputerNameW ); | 
|  | if ( ( st = NtCreateKey( &hsubkey, KEY_ALL_ACCESS, &attr, 0, NULL, REG_OPTION_VOLATILE, NULL ) ) | 
|  | != STATUS_SUCCESS ) | 
|  | goto out; | 
|  |  | 
|  | RtlInitUnicodeString( &nameW, ComputerNameW ); | 
|  | st = NtSetValueKey( hsubkey, &nameW, 0, REG_SZ, computer_name, len ); | 
|  |  | 
|  | out: | 
|  | NtClose( hsubkey ); | 
|  | NtClose( hkey ); | 
|  |  | 
|  | if ( st == STATUS_SUCCESS ) | 
|  | TRACE( "success\n" ); | 
|  | else | 
|  | { | 
|  | WARN( "status trying to set ComputerName: %lx\n", st ); | 
|  | SetLastError ( RtlNtStatusToDosError ( st ) ); | 
|  | } | 
|  | } | 
|  |  | 
|  |  | 
|  | /*********************************************************************** | 
|  | *              GetComputerNameW         (KERNEL32.@) | 
|  | */ | 
|  | BOOL WINAPI GetComputerNameW(LPWSTR name,LPDWORD size) | 
|  | { | 
|  | UNICODE_STRING nameW; | 
|  | OBJECT_ATTRIBUTES attr; | 
|  | HANDLE hkey = INVALID_HANDLE_VALUE, hsubkey = INVALID_HANDLE_VALUE; | 
|  | char buf[offsetof( KEY_VALUE_PARTIAL_INFORMATION, Data ) + (MAX_COMPUTERNAME_LENGTH + 1) * sizeof( WCHAR )]; | 
|  | DWORD len = sizeof( buf ); | 
|  | LPWSTR theName = (LPWSTR) (buf + offsetof( KEY_VALUE_PARTIAL_INFORMATION, Data )); | 
|  | NTSTATUS st = STATUS_INVALID_PARAMETER; | 
|  |  | 
|  | TRACE ("%p %p\n", name, size); | 
|  |  | 
|  | _init_attr ( &attr, &nameW ); | 
|  | RtlInitUnicodeString( &nameW, ComputerW ); | 
|  | if ( ( st = NtOpenKey( &hkey, KEY_ALL_ACCESS, &attr ) ) != STATUS_SUCCESS ) | 
|  | goto out; | 
|  |  | 
|  | attr.RootDirectory = hkey; | 
|  | RtlInitUnicodeString( &nameW, ActiveComputerNameW ); | 
|  | if ( ( st = NtOpenKey( &hsubkey, KEY_ALL_ACCESS, &attr ) ) != STATUS_SUCCESS ) | 
|  | goto out; | 
|  |  | 
|  | RtlInitUnicodeString( &nameW, ComputerNameW ); | 
|  | if ( ( st = NtQueryValueKey( hsubkey, &nameW, KeyValuePartialInformation, buf, len, &len ) ) | 
|  | != STATUS_SUCCESS ) | 
|  | goto out; | 
|  |  | 
|  | len = (len -offsetof( KEY_VALUE_PARTIAL_INFORMATION, Data )) / sizeof (WCHAR) - 1; | 
|  | TRACE ("ComputerName is %s (length %lu)\n", debugstr_w ( theName ), len); | 
|  |  | 
|  | __TRY | 
|  | { | 
|  | if ( *size < len ) | 
|  | { | 
|  | memcpy ( name, theName, *size * sizeof (WCHAR) ); | 
|  | name[*size] = 0; | 
|  | *size = len; | 
|  | st = STATUS_MORE_ENTRIES; | 
|  | } | 
|  | else | 
|  | { | 
|  | memcpy ( name, theName, len * sizeof (WCHAR) ); | 
|  | name[len] = 0; | 
|  | *size = len; | 
|  | st = STATUS_SUCCESS; | 
|  | } | 
|  | } | 
|  | __EXCEPT_PAGE_FAULT | 
|  | { | 
|  | st = STATUS_INVALID_PARAMETER; | 
|  | } | 
|  | __ENDTRY | 
|  |  | 
|  | out: | 
|  | NtClose ( hsubkey ); | 
|  | NtClose ( hkey ); | 
|  |  | 
|  | if ( st == STATUS_SUCCESS ) | 
|  | return TRUE; | 
|  | else | 
|  | { | 
|  | SetLastError ( RtlNtStatusToDosError ( st ) ); | 
|  | WARN ( "Status %lu reading computer name from registry\n", st ); | 
|  | return FALSE; | 
|  | } | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *              GetComputerNameA         (KERNEL32.@) | 
|  | */ | 
|  | BOOL WINAPI GetComputerNameA(LPSTR name, LPDWORD size) | 
|  | { | 
|  | WCHAR nameW[ MAX_COMPUTERNAME_LENGTH + 1 ]; | 
|  | DWORD sizeW = MAX_COMPUTERNAME_LENGTH; | 
|  | unsigned int len; | 
|  | BOOL ret; | 
|  |  | 
|  | if ( !GetComputerNameW (nameW, &sizeW) ) return FALSE; | 
|  |  | 
|  | len = WideCharToMultiByte ( CP_ACP, 0, nameW, sizeW, NULL, 0, NULL, 0 ); | 
|  | __TRY | 
|  | { | 
|  | if ( *size < len ) | 
|  | { | 
|  | WideCharToMultiByte ( CP_ACP, 0, nameW, sizeW, name, *size, NULL, 0 ); | 
|  | name[*size] = 0; | 
|  | *size = len; | 
|  | SetLastError( ERROR_MORE_DATA ); | 
|  | ret = FALSE; | 
|  | } | 
|  | else | 
|  | { | 
|  | WideCharToMultiByte ( CP_ACP, 0, nameW, sizeW, name, len, NULL, 0 ); | 
|  | name[len] = 0; | 
|  | *size = len; | 
|  | ret = TRUE; | 
|  | } | 
|  | } | 
|  | __EXCEPT_PAGE_FAULT | 
|  | { | 
|  | SetLastError( ERROR_INVALID_PARAMETER ); | 
|  | ret = FALSE; | 
|  | } | 
|  | __ENDTRY | 
|  |  | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *              GetComputerNameExA         (KERNEL32.@) | 
|  | */ | 
|  | BOOL WINAPI GetComputerNameExA(COMPUTER_NAME_FORMAT type, LPSTR name, LPDWORD size) | 
|  | { | 
|  | char buf[256]; | 
|  | int len = sizeof (buf), ret; | 
|  | TRACE("%d, %p, %p\n", type, name, size); | 
|  | switch( type ) | 
|  | { | 
|  | case ComputerNameNetBIOS: | 
|  | case ComputerNamePhysicalNetBIOS: | 
|  | return GetComputerNameA (name, size); | 
|  | case ComputerNameDnsHostname: | 
|  | case ComputerNamePhysicalDnsHostname: | 
|  | ret = dns_hostname (buf, &len); | 
|  | break; | 
|  | case ComputerNameDnsDomain: | 
|  | case ComputerNamePhysicalDnsDomain: | 
|  | ret = dns_domainname (buf, &len); | 
|  | break; | 
|  | case ComputerNameDnsFullyQualified: | 
|  | case ComputerNamePhysicalDnsFullyQualified: | 
|  | ret = dns_fqdn (buf, &len); | 
|  | break; | 
|  | default: | 
|  | SetLastError (ERROR_INVALID_PARAMETER); | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  | if ( ret ) | 
|  | { | 
|  | TRACE ("-> %s (%d)\n", debugstr_a (buf), len); | 
|  | __TRY | 
|  | { | 
|  | if ( *size < len ) | 
|  | { | 
|  | memcpy( name, buf, *size ); | 
|  | name[*size] = 0; | 
|  | *size = len; | 
|  | SetLastError( ERROR_MORE_DATA ); | 
|  | ret = FALSE; | 
|  | } | 
|  | else | 
|  | { | 
|  | memcpy( name, buf, len ); | 
|  | name[len] = 0; | 
|  | *size = len; | 
|  | ret = TRUE; | 
|  | } | 
|  | } | 
|  | __EXCEPT_PAGE_FAULT | 
|  | { | 
|  | SetLastError( ERROR_INVALID_PARAMETER ); | 
|  | return FALSE; | 
|  | } | 
|  | __ENDTRY | 
|  | } | 
|  |  | 
|  | return ret; | 
|  | } | 
|  |  | 
|  |  | 
|  | /*********************************************************************** | 
|  | *              GetComputerNameExW         (KERNEL32.@) | 
|  | */ | 
|  | BOOL WINAPI GetComputerNameExW( COMPUTER_NAME_FORMAT type, LPWSTR name, LPDWORD size ) | 
|  | { | 
|  | char buf[256]; | 
|  | int len = sizeof (buf), ret; | 
|  |  | 
|  | TRACE("%d, %p, %p\n", type, name, size); | 
|  | switch( type ) | 
|  | { | 
|  | case ComputerNameNetBIOS: | 
|  | case ComputerNamePhysicalNetBIOS: | 
|  | return GetComputerNameW (name, size); | 
|  | case ComputerNameDnsHostname: | 
|  | case ComputerNamePhysicalDnsHostname: | 
|  | ret = dns_hostname (buf, &len); | 
|  | break; | 
|  | case ComputerNameDnsDomain: | 
|  | case ComputerNamePhysicalDnsDomain: | 
|  | ret = dns_domainname (buf, &len); | 
|  | break; | 
|  | case ComputerNameDnsFullyQualified: | 
|  | case ComputerNamePhysicalDnsFullyQualified: | 
|  | ret = dns_fqdn (buf, &len); | 
|  | break; | 
|  | default: | 
|  | SetLastError (ERROR_INVALID_PARAMETER); | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  | if ( ret ) | 
|  | { | 
|  | TRACE ("-> %s (%d)\n", debugstr_a (buf), len); | 
|  | __TRY | 
|  | { | 
|  | unsigned int lenW = MultiByteToWideChar( CP_ACP, 0, buf, len, NULL, 0 ); | 
|  | if ( *size < lenW ) | 
|  | { | 
|  | MultiByteToWideChar( CP_ACP, 0, buf, len, name, *size ); | 
|  | name[*size] = 0; | 
|  | *size = lenW; | 
|  | SetLastError( ERROR_MORE_DATA ); | 
|  | ret = FALSE; | 
|  | } | 
|  | else | 
|  | { | 
|  | MultiByteToWideChar( CP_ACP, 0, buf, len, name, lenW ); | 
|  | name[lenW] = 0; | 
|  | *size = lenW; | 
|  | ret = TRUE; | 
|  | } | 
|  | } | 
|  | __EXCEPT_PAGE_FAULT | 
|  | { | 
|  | SetLastError( ERROR_INVALID_PARAMETER ); | 
|  | return FALSE; | 
|  | } | 
|  | __ENDTRY | 
|  | } | 
|  |  | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | /****************************************************************************** | 
|  | * netbios_char (INTERNAL) | 
|  | */ | 
|  | static WCHAR netbios_char ( WCHAR wc ) | 
|  | { | 
|  | static const WCHAR special[] = {'!','@','#','$','%','^','&','\'',')','(','-','_','{','}','~'}; | 
|  | static const WCHAR deflt = '_'; | 
|  | unsigned int i; | 
|  |  | 
|  | if ( isalnumW ( wc ) ) return wc; | 
|  | for ( i = 0; i < sizeof (special) / sizeof (WCHAR); i++ ) | 
|  | if ( wc == special[i] ) return wc; | 
|  | return deflt; | 
|  | } | 
|  |  | 
|  | /****************************************************************************** | 
|  | * SetComputerNameW [KERNEL32.@] | 
|  | * | 
|  | * Set a new NetBIOS name for the local computer. | 
|  | * | 
|  | * PARAMS | 
|  | *    lpComputerName [I] Address of new computer name | 
|  | * | 
|  | * RETURNS | 
|  | *    Success: TRUE | 
|  | *    Failure: FALSE | 
|  | */ | 
|  | BOOL WINAPI SetComputerNameW( LPCWSTR lpComputerName ) | 
|  | { | 
|  | UNICODE_STRING nameW; | 
|  | OBJECT_ATTRIBUTES attr; | 
|  | HANDLE hkey = INVALID_HANDLE_VALUE, hsubkey = INVALID_HANDLE_VALUE; | 
|  | int plen = strlenW ( lpComputerName ); | 
|  | int i; | 
|  | NTSTATUS st = STATUS_INTERNAL_ERROR; | 
|  |  | 
|  | if (get_use_dns_option()) | 
|  | { | 
|  | /* This check isn't necessary, but may help debugging problems. */ | 
|  | WARN( "Disabled by Wine Configuration.\n" ); | 
|  | WARN( "Set \"UseDnsComputerName\" = \"N\" in category [Network] to enable.\n" ); | 
|  | SetLastError ( ERROR_ACCESS_DENIED ); | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  | TRACE( "%s\n", debugstr_w (lpComputerName) ); | 
|  |  | 
|  | /* Check parameter */ | 
|  | if ( plen > MAX_COMPUTERNAME_LENGTH ) | 
|  | goto out; | 
|  |  | 
|  | /* This is NT behaviour. Win 95/98 would coerce characters. */ | 
|  | for ( i = 0; i < plen; i++ ) | 
|  | { | 
|  | WCHAR wc = lpComputerName[i]; | 
|  | if ( wc != netbios_char( wc ) ) | 
|  | goto out; | 
|  | } | 
|  |  | 
|  | _init_attr ( &attr, &nameW ); | 
|  |  | 
|  | RtlInitUnicodeString (&nameW, ComputerW); | 
|  | if ( ( st = NtOpenKey( &hkey, KEY_ALL_ACCESS, &attr ) ) != STATUS_SUCCESS ) | 
|  | goto out; | 
|  | attr.RootDirectory = hkey; | 
|  | RtlInitUnicodeString( &nameW, ComputerNameW ); | 
|  | if ( ( st = NtOpenKey( &hsubkey, KEY_ALL_ACCESS, &attr ) ) != STATUS_SUCCESS ) | 
|  | goto out; | 
|  | if ( ( st = NtSetValueKey( hsubkey, &nameW, 0, REG_SZ, lpComputerName, ( plen + 1) * sizeof(WCHAR) ) ) | 
|  | != STATUS_SUCCESS ) | 
|  | goto out; | 
|  |  | 
|  | out: | 
|  | NtClose( hsubkey ); | 
|  | NtClose( hkey ); | 
|  |  | 
|  | if ( st == STATUS_SUCCESS ) | 
|  | { | 
|  | TRACE( "ComputerName changed\n" ); | 
|  | return TRUE; | 
|  | } | 
|  |  | 
|  | else | 
|  | { | 
|  | SetLastError ( RtlNtStatusToDosError ( st ) ); | 
|  | WARN ( "status %lu\n", st ); | 
|  | return FALSE; | 
|  | } | 
|  | } | 
|  |  | 
|  | /****************************************************************************** | 
|  | * SetComputerNameA [KERNEL32.@] | 
|  | * | 
|  | * See SetComputerNameW. | 
|  | */ | 
|  | BOOL WINAPI SetComputerNameA( LPCSTR lpComputerName ) | 
|  | { | 
|  | BOOL ret; | 
|  | DWORD len = MultiByteToWideChar( CP_ACP, 0, lpComputerName, -1, NULL, 0 ); | 
|  | LPWSTR nameW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ); | 
|  |  | 
|  | MultiByteToWideChar( CP_ACP, 0, lpComputerName, -1, nameW, len ); | 
|  | ret = SetComputerNameW( nameW ); | 
|  | HeapFree( GetProcessHeap(), 0, nameW ); | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | /****************************************************************************** | 
|  | * SetComputerNameExW [KERNEL32.@] | 
|  | * | 
|  | */ | 
|  | BOOL WINAPI SetComputerNameExW( COMPUTER_NAME_FORMAT type, LPCWSTR lpComputerName ) | 
|  | { | 
|  | TRACE("%d, %s\n", type, debugstr_w (lpComputerName)); | 
|  | switch( type ) | 
|  | { | 
|  | case ComputerNameNetBIOS: | 
|  | case ComputerNamePhysicalNetBIOS: | 
|  | return SetComputerNameW( lpComputerName ); | 
|  | default: | 
|  | SetLastError( ERROR_ACCESS_DENIED ); | 
|  | return FALSE; | 
|  | } | 
|  | } | 
|  |  | 
|  | /****************************************************************************** | 
|  | * SetComputerNameExA [KERNEL32.@] | 
|  | * | 
|  | */ | 
|  | BOOL WINAPI SetComputerNameExA( COMPUTER_NAME_FORMAT type, LPCSTR lpComputerName ) | 
|  | { | 
|  | TRACE( "%d, %s\n", type, debugstr_a (lpComputerName) ); | 
|  | switch( type ) | 
|  | { | 
|  | case ComputerNameNetBIOS: | 
|  | case ComputerNamePhysicalNetBIOS: | 
|  | return SetComputerNameA( lpComputerName ); | 
|  | default: | 
|  | SetLastError( ERROR_ACCESS_DENIED ); | 
|  | return FALSE; | 
|  | } | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *              DnsHostnameToComputerNameA         (KERNEL32.@) | 
|  | */ | 
|  | BOOL WINAPI DnsHostnameToComputerNameA(LPCSTR hostname, | 
|  | LPSTR computername, LPDWORD size) | 
|  | { | 
|  | DWORD len; | 
|  |  | 
|  | FIXME("(%s, %p, %p): stub\n", debugstr_a(hostname), computername, size); | 
|  |  | 
|  | if (!hostname || !size) return FALSE; | 
|  | len = lstrlenA(hostname); | 
|  |  | 
|  | if (len > MAX_COMPUTERNAME_LENGTH) | 
|  | len = MAX_COMPUTERNAME_LENGTH; | 
|  |  | 
|  | if (*size < len) | 
|  | { | 
|  | *size = len; | 
|  | return FALSE; | 
|  | } | 
|  | if (!computername) return FALSE; | 
|  |  | 
|  | memcpy( computername, hostname, len ); | 
|  | computername[len + 1] = 0; | 
|  | return TRUE; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *              DnsHostnameToComputerNameW         (KERNEL32.@) | 
|  | */ | 
|  | BOOL WINAPI DnsHostnameToComputerNameW(LPCWSTR hostname, | 
|  | LPWSTR computername, LPDWORD size) | 
|  | { | 
|  | DWORD len; | 
|  |  | 
|  | FIXME("(%s, %p, %p): stub\n", debugstr_w(hostname), computername, size); | 
|  |  | 
|  | if (!hostname || !size) return FALSE; | 
|  | len = lstrlenW(hostname); | 
|  |  | 
|  | if (len > MAX_COMPUTERNAME_LENGTH) | 
|  | len = MAX_COMPUTERNAME_LENGTH; | 
|  |  | 
|  | if (*size < len) | 
|  | { | 
|  | *size = len; | 
|  | return FALSE; | 
|  | } | 
|  | if (!computername) return FALSE; | 
|  |  | 
|  | memcpy( computername, hostname, len * sizeof(WCHAR) ); | 
|  | computername[len + 1] = 0; | 
|  | return TRUE; | 
|  | } |