Browse code

win: replace wmic invocation with powershell

Since wmic has been recently deprecated and is absent on new
systems, replace setting DNS domain "old-style" with powershell.

Some changes to the service implementation:

- remove action parameter and hardcode Set-DnsClient since this is
the only used action

- remove support of multiple domains, since we only pass a single domain
(tuntap_options.domain)

Github: fixes OpenVPN/openvpn#642

Change-Id: Iff2f4ea677fe2d88659d7814dab0f792f5004fb3
Gerrit URL: https://gerrit.openvpn.net/c/openvpn/+/1183
Signed-off-by: Lev Stipakov <lev@openvpn.net>
Acked-by: Gert Doering <gert@greenie.muc.de>
Message-Id: <20250915062013.2555-1-gert@greenie.muc.de>
URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg32938.html
Signed-off-by: Gert Doering <gert@greenie.muc.de>

Lev Stipakov authored on 2025/09/15 15:20:06
Showing 3 changed files
... ...
@@ -383,7 +383,7 @@ out:
383 383
 }
384 384
 
385 385
 static void
386
-do_dns_domain_wmic(bool add, const struct tuntap *tt)
386
+do_dns_domain_pwsh(bool add, const struct tuntap *tt)
387 387
 {
388 388
     if (!tt->options.domain)
389 389
     {
... ...
@@ -391,9 +391,14 @@ do_dns_domain_wmic(bool add, const struct tuntap *tt)
391 391
     }
392 392
 
393 393
     struct argv argv = argv_new();
394
-    argv_printf(&argv, "%s%s nicconfig where (InterfaceIndex=%ld) call SetDNSDomain '%s'",
395
-                get_win_sys_path(), WMIC_PATH_SUFFIX, tt->adapter_index, add ? tt->options.domain : "");
396
-    exec_command("WMIC", &argv, 1, M_WARN);
394
+    argv_printf(&argv,
395
+                "%s%s -NoProfile -NonInteractive -Command Set-DnsClient -InterfaceIndex %lu -ConnectionSpecificSuffix '%s'",
396
+                get_win_sys_path(),
397
+                POWERSHELL_PATH_SUFFIX,
398
+                tt->adapter_index,
399
+                add ? tt->options.domain : ""
400
+                );
401
+    exec_command("PowerShell", &argv, 1, M_WARN);
397 402
 
398 403
     argv_free(&argv);
399 404
 }
... ...
@@ -1269,7 +1274,7 @@ do_ifconfig_ipv6(struct tuntap *tt, const char *ifname, int tun_mtu,
1269 1269
 
1270 1270
         if (!tt->did_ifconfig_setup)
1271 1271
         {
1272
-            do_dns_domain_wmic(true, tt);
1272
+            do_dns_domain_pwsh(true, tt);
1273 1273
         }
1274 1274
     }
1275 1275
 #else /* platforms we have no IPv6 code for */
... ...
@@ -1625,7 +1630,7 @@ do_ifconfig_ipv4(struct tuntap *tt, const char *ifname, int tun_mtu,
1625 1625
                            tt->adapter_netmask, NI_IP_NETMASK | NI_OPTIONS);
1626 1626
         }
1627 1627
 
1628
-        do_dns_domain_wmic(true, tt);
1628
+        do_dns_domain_pwsh(true, tt);
1629 1629
     }
1630 1630
 
1631 1631
 
... ...
@@ -7024,7 +7029,7 @@ close_tun(struct tuntap *tt, openvpn_net_ctx_t *ctx)
7024 7024
         {
7025 7025
             if (!tt->did_ifconfig_setup)
7026 7026
             {
7027
-                do_dns_domain_wmic(false, tt);
7027
+                do_dns_domain_pwsh(false, tt);
7028 7028
             }
7029 7029
 
7030 7030
             netsh_delete_address_dns(tt, true, &gc);
... ...
@@ -7050,7 +7055,7 @@ close_tun(struct tuntap *tt, openvpn_net_ctx_t *ctx)
7050 7050
         }
7051 7051
         else
7052 7052
         {
7053
-            do_dns_domain_wmic(false, tt);
7053
+            do_dns_domain_pwsh(false, tt);
7054 7054
 
7055 7055
             if (tt->options.ip_win32_type == IPW32_SET_NETSH)
7056 7056
             {
... ...
@@ -38,7 +38,7 @@
38 38
 #define WIN_ROUTE_PATH_SUFFIX "\\system32\\route.exe"
39 39
 #define WIN_IPCONFIG_PATH_SUFFIX "\\system32\\ipconfig.exe"
40 40
 #define WIN_NET_PATH_SUFFIX "\\system32\\net.exe"
41
-#define WMIC_PATH_SUFFIX "\\system32\\wbem\\wmic.exe"
41
+#define POWERSHELL_PATH_SUFFIX "\\system32\\WindowsPowerShell\\v1.0\\powershell.exe"
42 42
 
43 43
 /*
44 44
  * Win32-specific OpenVPN code, targeted at the mingw
... ...
@@ -1150,45 +1150,31 @@ out:
1150 1150
 }
1151 1151
 
1152 1152
 /**
1153
- * Run command: wmic nicconfig (InterfaceIndex=$if_index) call $action ($data)
1153
+ * Run command: powershell -NoProfile -NonInteractive -Command Set-DnsClient -InterfaceIndex %ld -ConnectionSpecificSuffix '%s'
1154 1154
  * @param  if_index    "index of interface"
1155
- * @param  action      e.g., "SetDNSDomain"
1156 1155
  * @param  data        data if required for action
1157 1156
  *                     - a single word for SetDNSDomain, empty or NULL to delete
1158
- *                     - comma separated values for a list
1159 1157
  */
1160 1158
 static DWORD
1161
-wmic_nicconfig_cmd(const wchar_t *action, const NET_IFINDEX if_index,
1162
-                   const wchar_t *data)
1159
+pwsh_setdns_cmd(const NET_IFINDEX if_index, const wchar_t *data)
1163 1160
 {
1164 1161
     DWORD err = 0;
1165 1162
     wchar_t argv0[MAX_PATH];
1166 1163
     wchar_t *cmdline = NULL;
1167 1164
     int timeout = 10000; /* in msec */
1168 1165
 
1169
-    openvpn_swprintf(argv0, _countof(argv0), L"%ls\\%ls", get_win_sys_path(), L"wbem\\wmic.exe");
1166
+    openvpn_swprintf(argv0, _countof(argv0), L"%ls\\%ls", get_win_sys_path(), L"WindowsPowerShell\\v1.0\\powershell.exe");
1170 1167
 
1171
-    const wchar_t *fmt;
1172
-    /* comma separated list must be enclosed in parenthesis */
1173
-    if (data && wcschr(data, L','))
1174
-    {
1175
-        fmt = L"wmic nicconfig where (InterfaceIndex=%ld) call %ls (%ls)";
1176
-    }
1177
-    else
1178
-    {
1179
-        fmt = L"wmic nicconfig where (InterfaceIndex=%ld) call %ls \"%ls\"";
1180
-    }
1168
+    const wchar_t *fmt = L"-NoProfile -NonInteractive -Command Set-DnsClient -InterfaceIndex %lu -ConnectionSpecificSuffix '%s'";
1181 1169
 
1182
-    size_t ncmdline = wcslen(fmt) + 20 + wcslen(action) /* max 20 for ifindex */
1183
-                      + (data ? wcslen(data) + 1 : 1);
1170
+    size_t ncmdline = wcslen(fmt) + 20 + /* max 20 for ifindex */ (data ? wcslen(data) + 1 : 1);
1184 1171
     cmdline = malloc(ncmdline*sizeof(wchar_t));
1185 1172
     if (!cmdline)
1186 1173
     {
1187 1174
         return ERROR_OUTOFMEMORY;
1188 1175
     }
1189 1176
 
1190
-    openvpn_swprintf(cmdline, ncmdline, fmt, if_index, action,
1191
-                     data ? data : L"");
1177
+    openvpn_swprintf(cmdline, ncmdline, fmt, if_index, data ? data : L"");
1192 1178
     err = ExecCommand(argv0, cmdline, timeout);
1193 1179
 
1194 1180
     free(cmdline);
... ...
@@ -1248,7 +1234,7 @@ SetDNSDomain(const wchar_t *if_name, const char *domain, undo_lists_t *lists)
1248 1248
         free(RemoveListItem(&(*lists)[undo_domain], CmpWString, (void *)if_name));
1249 1249
     }
1250 1250
 
1251
-    err = wmic_nicconfig_cmd(L"SetDNSDomain", if_index, wdomain);
1251
+    err = pwsh_setdns_cmd(if_index, wdomain);
1252 1252
 
1253 1253
     /* Add to undo list if domain is non-empty */
1254 1254
     if (err == 0 && wdomain[0] && lists)