[KERNEL32] Improve SetComputerNameExW (#3171)
authorKatayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com>
Thu, 17 Sep 2020 14:51:47 +0000 (23:51 +0900)
committerGitHub <noreply@github.com>
Thu, 17 Sep 2020 14:51:47 +0000 (23:51 +0900)
Reduce failures of kernel32_apitest SetComputerNameExW testcase and improve SetComputerNameExW.

dll/win32/kernel32/client/compname.c

index 46d05e7..2b4b335 100644 (file)
  * PROJECT:         ReactOS system libraries
  * PURPOSE:         Computer name functions
  * FILE:            dll/win32/kernel32/client/compname.c
- * PROGRAMER:       Eric Kohl
+ * PROGRAMERS:      Eric Kohl
+ *                  Katayama Hirofumi MZ
  */
 
 /* INCLUDES ******************************************************************/
 
 #include <k32.h>
+#include <windns.h>
 
 #define NDEBUG
 #include <debug.h>
 
+typedef NTSTATUS (WINAPI *FN_DnsValidateName_W)(LPCWSTR, DNS_NAME_FORMAT);
 
 /* FUNCTIONS *****************************************************************/
 
@@ -451,6 +454,31 @@ GetComputerNameW(LPWSTR lpBuffer, LPDWORD lpnSize)
     return ret;
 }
 
+static
+BOOL
+BaseVerifyDnsName(LPCWSTR lpDnsName)
+{
+    HINSTANCE hDNSAPI;
+    FN_DnsValidateName_W fnValidate;
+    NTSTATUS Status;
+    BOOL ret = FALSE;
+
+    hDNSAPI = LoadLibraryW(L"dnsapi.dll");
+    if (hDNSAPI == NULL)
+        return FALSE;
+
+    fnValidate = (FN_DnsValidateName_W)GetProcAddress(hDNSAPI, "DnsValidateName_W");
+    if (fnValidate)
+    {
+        Status = (*fnValidate)(lpDnsName, DnsNameHostnameLabel);
+        if (Status == STATUS_SUCCESS || Status == DNS_ERROR_NON_RFC_NAME)
+            ret = TRUE;
+    }
+
+    FreeLibrary(hDNSAPI);
+
+    return ret;
+}
 
 /*
  * @implemented
@@ -460,39 +488,56 @@ BOOL
 IsValidComputerName(COMPUTER_NAME_FORMAT NameType,
                     LPCWSTR lpComputerName)
 {
-    PWCHAR p;
-    ULONG Length;
+    size_t Length;
+    static const WCHAR s_szInvalidChars[] =
+        L"\"/\\[]:|<>+=;,?"
+        L"\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F"
+        L"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F";
 
-    /* FIXME: do verification according to NameType */
+    if (lpComputerName == NULL)
+        return FALSE;
 
-    Length = 0;
-    p = (PWCHAR)lpComputerName;
+#define MAX_COMPUTER_NAME_EX 64
+    /* Get string length */
+    if (!NT_SUCCESS(RtlStringCchLengthW(lpComputerName, MAX_COMPUTER_NAME_EX + 1, &Length)))
+        return FALSE;
+#undef MAX_COMPUTER_NAME_EX
 
-    while (*p != 0)
-    {
-        if (!(iswctype(*p, _ALPHA | _DIGIT) || *p == L'!' || *p == L'@' || *p == L'#' ||
-            *p == L'$' || *p == L'%' || *p == L'^' || *p == L'&' || *p == L'\'' ||
-            *p == L')' || *p == L'(' || *p == L'.' || *p == L'-' || *p == L'_' ||
-            *p == L'{' || *p == L'}' || *p == L'~'))
-            return FALSE;
+    /* An empty name is invalid, except a DNS name */
+    if (Length == 0 && NameType != ComputerNamePhysicalDnsDomain)
+        return FALSE;
 
-        Length++;
-        p++;
+    /* Leading or trailing spaces are invalid */
+    if (Length > 0 &&
+        (lpComputerName[0] == L' ' || lpComputerName[Length - 1] == L' '))
+    {
+        return FALSE;
     }
 
-    if (NameType == ComputerNamePhysicalDnsDomain)
-        return TRUE;
-
-    if (Length == 0)
+    /* Check whether the name contains any invalid character */
+    if (wcscspn(lpComputerName, s_szInvalidChars) < Length)
         return FALSE;
 
-    if (NameType == ComputerNamePhysicalNetBIOS &&
-        Length > MAX_COMPUTERNAME_LENGTH)
-        return FALSE;
+    switch (NameType)
+    {
+        case ComputerNamePhysicalNetBIOS:
+            if (Length > MAX_COMPUTERNAME_LENGTH)
+                return FALSE;
+            return TRUE;
 
-    return TRUE;
-}
+        case ComputerNamePhysicalDnsDomain:
+            /* An empty DNS name is valid */
+            if (Length != 0)
+                return BaseVerifyDnsName(lpComputerName);
+            return TRUE;
+
+        case ComputerNamePhysicalDnsHostname:
+            return BaseVerifyDnsName(lpComputerName);
 
+        default:
+            return FALSE;
+    }
+}
 
 static
 BOOL
@@ -547,6 +592,7 @@ SetComputerNameToRegistry(LPCWSTR RegistryKey,
     NtFlushKey(KeyHandle);
     NtClose(KeyHandle);
 
+    SetLastError(ERROR_SUCCESS);
     return TRUE;
 }
 
@@ -637,7 +683,7 @@ SetComputerNameExW(COMPUTER_NAME_FORMAT NameType,
                                              lpBuffer);
 
         default:
-            SetLastError (ERROR_INVALID_PARAMETER);
+            SetLastError(ERROR_INVALID_PARAMETER);
             return FALSE;
     }
 }