30 #include "../tapctl/basic.h"
31 #include "../tapctl/error.h"
32 #include "../tapctl/tap.h"
50 #pragma comment(lib, "advapi32.lib")
51 #pragma comment(lib, "iphlpapi.lib")
52 #pragma comment(lib, "shell32.lib")
53 #pragma comment(lib, "shlwapi.lib")
54 #pragma comment(lib, "version.lib")
63 #define MSICA_ADAPTER_TICK_SIZE (16 * 1024)
65 #define FILE_NEED_REBOOT L".ovpn_need_reboot"
67 #define OPENVPN_CONNECT_ADAPTER_SUBSTR L"OpenVPN Connect"
82 _In_ MSIHANDLE hInstall,
88 uiResult = MsiSetProperty(hInstall, szProperty, szSequence);
90 if (uiResult != ERROR_SUCCESS)
94 SetLastError(uiResult);
112 _debug_popup(
_In_z_ LPCSTR szFunctionName)
114 WCHAR szTitle[0x100], szMessage[0x100+MAX_PATH], szProcessPath[MAX_PATH];
118 swprintf_s(szTitle, _countof(szTitle), L
"%hs v%ls",
122 GetModuleFileName(NULL, szProcessPath, _countof(szProcessPath));
123 LPCWSTR szProcessName = wcsrchr(szProcessPath, L
'\\');
124 szProcessName = szProcessName ? szProcessName + 1 : szProcessPath;
128 szMessage, _countof(szMessage),
129 L
"The %ls process (PID: %u) has started to execute the %hs"
130 L
" custom action.\r\n"
132 L
"If you would like to debug the custom action, attach a debugger to this process and set breakpoints before dismissing this dialog.\r\n"
134 L
"If you are not debugging this custom action, you can safely ignore this message.",
136 GetCurrentProcessId(),
139 MessageBox(NULL, szMessage, szTitle, MB_OK);
142 #define debug_popup(f) _debug_popup(f)
144 #define debug_popup(f)
149 _In_ MSIHANDLE hInstall,
150 _In_z_ LPCWSTR szzHardwareIDs,
151 _In_z_ LPCWSTR szAdaptersPropertyName,
152 _In_z_ LPCWSTR szActiveAdaptersPropertyName)
159 if (uiResult != ERROR_SUCCESS)
163 else if (pAdapterList == NULL)
170 PIP_ADAPTER_ADDRESSES pAdapterAdresses = NULL;
171 ULONG ulAdapterAdressesSize = 16*1024;
172 for (
size_t iteration = 0; iteration < 2; iteration++)
174 pAdapterAdresses = (PIP_ADAPTER_ADDRESSES)malloc(ulAdapterAdressesSize);
175 if (pAdapterAdresses == NULL)
177 msg(
M_NONFATAL,
"%s: malloc(%u) failed", __FUNCTION__, ulAdapterAdressesSize);
178 uiResult = ERROR_OUTOFMEMORY;
goto cleanup_pAdapterList;
181 ULONG ulResult = GetAdaptersAddresses(
183 GAA_FLAG_SKIP_UNICAST | GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_SKIP_FRIENDLY_NAME | GAA_FLAG_INCLUDE_ALL_INTERFACES,
186 &ulAdapterAdressesSize);
188 if (ulResult == ERROR_SUCCESS)
193 free(pAdapterAdresses);
194 if (ulResult != ERROR_BUFFER_OVERFLOW)
196 SetLastError(ulResult);
198 uiResult = ulResult;
goto cleanup_pAdapterList;
203 size_t adapter_count = 0;
211 szAdapters = (LPWSTR)malloc(adapter_count * (38 + 1 ) *
sizeof(WCHAR)),
212 szAdaptersTail = szAdapters;
213 if (szAdapters == NULL)
215 msg(
M_FATAL,
"%s: malloc(%u) failed", __FUNCTION__, adapter_count * (38 + 1 ) *
sizeof(WCHAR));
216 uiResult = ERROR_OUTOFMEMORY;
goto cleanup_pAdapterAdresses;
220 szAdaptersActive = (LPWSTR)malloc(adapter_count * (38 + 1 ) *
sizeof(WCHAR)),
221 szAdaptersActiveTail = szAdaptersActive;
222 if (szAdaptersActive == NULL)
224 msg(
M_FATAL,
"%s: malloc(%u) failed", __FUNCTION__, adapter_count * (38 + 1 ) *
sizeof(WCHAR));
225 uiResult = ERROR_OUTOFMEMORY;
goto cleanup_szAdapters;
233 msg(
M_WARN,
"%s: skip OpenVPN Connect adapter '%ls'", __FUNCTION__, pAdapter->szName);
238 LPOLESTR szAdapterId = NULL;
239 StringFromIID((REFIID)&pAdapter->guid, &szAdapterId);
242 if (szAdapters < szAdaptersTail)
244 *(szAdaptersTail++) = L
';';
246 memcpy(szAdaptersTail, szAdapterId, 38 *
sizeof(WCHAR));
247 szAdaptersTail += 38;
250 for (PIP_ADAPTER_ADDRESSES p = pAdapterAdresses; p; p = p->Next)
252 OLECHAR szId[38 + 1 ];
254 if (MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, p->AdapterName, -1, szId, _countof(szId)) > 0
255 && SUCCEEDED(IIDFromString(szId, &
guid))
256 && memcmp(&
guid, &pAdapter->guid,
sizeof(GUID)) == 0)
258 if (p->OperStatus == IfOperStatusUp)
261 if (szAdaptersActive < szAdaptersActiveTail)
263 *(szAdaptersActiveTail++) = L
';';
265 memcpy(szAdaptersActiveTail, szAdapterId, 38 *
sizeof(WCHAR));
266 szAdaptersActiveTail += 38;
271 CoTaskMemFree(szAdapterId);
273 szAdaptersTail [0] = 0;
274 szAdaptersActiveTail[0] = 0;
277 uiResult = MsiSetProperty(hInstall, szAdaptersPropertyName, szAdapters);
278 if (uiResult != ERROR_SUCCESS)
280 SetLastError(uiResult);
281 msg(
M_NONFATAL |
M_ERRNO,
"%s: MsiSetProperty(\"%s\") failed", __FUNCTION__, szAdaptersPropertyName);
282 goto cleanup_szAdaptersActive;
284 uiResult = MsiSetProperty(hInstall, szActiveAdaptersPropertyName, szAdaptersActive);
285 if (uiResult != ERROR_SUCCESS)
287 SetLastError(uiResult);
288 msg(
M_NONFATAL |
M_ERRNO,
"%s: MsiSetProperty(\"%s\") failed", __FUNCTION__, szActiveAdaptersPropertyName);
289 goto cleanup_szAdaptersActive;
292 cleanup_szAdaptersActive:
293 free(szAdaptersActive);
296 cleanup_pAdapterAdresses:
297 free(pAdapterAdresses);
298 cleanup_pAdapterList:
307 #pragma comment(linker, DLLEXP_EXPORT)
312 BOOL bIsCoInitialized = SUCCEEDED(CoInitialize(NULL));
319 L
"TAPWINDOWS6ADAPTERS",
320 L
"ACTIVETAPWINDOWS6ADAPTERS");
325 L
"ACTIVEWINTUNADAPTERS");
330 L
"ACTIVEOVPNDCOADAPTERS");
332 if (bIsCoInitialized)
336 return ERROR_SUCCESS;
344 #pragma comment(linker, DLLEXP_EXPORT)
346 UNREFERENCED_PARAMETER(hInstall);
351 HWND hWnd = FindWindow(L
"OpenVPN-GUI", NULL);
355 SendMessage(hWnd, WM_CLOSE, 0, 0);
359 return ERROR_SUCCESS;
367 #pragma comment(linker, DLLEXP_EXPORT)
373 BOOL bIsCoInitialized = SUCCEEDED(CoInitialize(NULL));
378 MSIHANDLE hRecord = MsiCreateRecord(1);
381 uiResult = ERROR_INVALID_HANDLE;
383 goto cleanup_CoInitialize;
385 uiResult = MsiRecordSetString(hRecord, 0, L
"\"[#bin.openvpn_gui.exe]\"");
386 if (uiResult != ERROR_SUCCESS)
388 SetLastError(uiResult);
390 goto cleanup_MsiCreateRecord;
394 WCHAR szStackBuf[MAX_PATH];
395 DWORD dwPathSize = _countof(szStackBuf);
396 LPWSTR szPath = szStackBuf;
397 uiResult = MsiFormatRecord(hInstall, hRecord, szPath, &dwPathSize);
398 if (uiResult == ERROR_MORE_DATA)
401 szPath = (LPWSTR)malloc((++dwPathSize) *
sizeof(WCHAR));
404 msg(
M_FATAL,
"%s: malloc(%u) failed", __FUNCTION__, dwPathSize *
sizeof(WCHAR));
405 uiResult = ERROR_OUTOFMEMORY;
goto cleanup_MsiCreateRecord;
408 uiResult = MsiFormatRecord(hInstall, hRecord, szPath, &dwPathSize);
410 if (uiResult != ERROR_SUCCESS)
412 SetLastError(uiResult);
414 goto cleanup_malloc_szPath;
418 SHELLEXECUTEINFO sei = {
419 .cbSize =
sizeof(SHELLEXECUTEINFO),
420 .fMask = SEE_MASK_FLAG_NO_UI,
422 .nShow = SW_SHOWNORMAL
424 if (!ShellExecuteEx(&sei))
426 uiResult = GetLastError();
428 goto cleanup_malloc_szPath;
431 uiResult = ERROR_SUCCESS;
433 cleanup_malloc_szPath:
434 if (szPath != szStackBuf)
438 cleanup_MsiCreateRecord:
439 MsiCloseHandle(hRecord);
440 cleanup_CoInitialize:
441 if (bIsCoInitialized)
473 _In_z_ LPCWSTR szDisplayName,
474 _In_z_ LPCWSTR szHardwareId,
480 if (dwResult != ERROR_SUCCESS)
488 if (pAdapterOther == NULL)
491 WCHAR szArgument[10 + MAX_PATH + 1 + MAX_PATH + 1 ];
495 szArgument, _countof(szArgument),
496 L
"create=\"%.*s|%.*s\"",
497 MAX_PATH, szDisplayName,
498 MAX_PATH, szHardwareId);
505 szArgument, _countof(szArgument),
507 MAX_PATH, szDisplayName);
514 else if (wcsicmp(szDisplayName, pAdapterOther->szName) == 0)
517 for (LPCWSTR hwid = pAdapterOther->szzHardwareIDs;; hwid += wcslen(hwid) + 1)
522 msg(
M_NONFATAL,
"%s: Adapter with name \"%ls\" already exists", __FUNCTION__, pAdapterOther->szName);
523 dwResult = ERROR_ALREADY_EXISTS;
524 goto cleanup_pAdapterList;
526 else if (wcsicmp(hwid, szHardwareId) == 0)
536 cleanup_pAdapterList:
574 _In_z_ LPCWSTR szDisplayName,
581 if (dwResult != ERROR_SUCCESS)
589 if (wcsicmp(szDisplayName, pAdapter->szName) == 0)
592 WCHAR szArgument[8 + 38 + 1 ];
593 if (seqCommit && seqRollback)
597 szArgument, _countof(szArgument),
604 szArgument, _countof(szArgument),
611 szArgument, _countof(szArgument),
620 szArgument, _countof(szArgument),
640 #pragma comment(linker, DLLEXP_EXPORT)
646 BOOL bIsCoInitialized = SUCCEEDED(CoInitialize(NULL));
656 seqUninstallRollback;
665 bool bRollbackEnabled = MsiEvaluateCondition(hInstall, L
"RollbackDisabled") != MSICONDITION_TRUE;
668 MSIHANDLE hDatabase = MsiGetActiveDatabase(hInstall);
671 msg(
M_NONFATAL,
"%s: MsiGetActiveDatabase failed", __FUNCTION__);
672 uiResult = ERROR_INVALID_HANDLE;
673 goto cleanup_exec_seq;
677 switch (MsiDatabaseIsTablePersistent(hDatabase, L
"TUNTAPAdapter"))
679 case MSICONDITION_FALSE:
680 case MSICONDITION_TRUE:
break;
683 uiResult = ERROR_SUCCESS;
684 goto cleanup_hDatabase;
688 MSIHANDLE hViewST = 0;
689 LPCWSTR szQuery = L
"SELECT `Adapter`,`DisplayName`,`Condition`,`Component_`,`HardwareId` FROM `TUNTAPAdapter`";
690 uiResult = MsiDatabaseOpenView(hDatabase, szQuery, &hViewST);
691 if (uiResult != ERROR_SUCCESS)
693 SetLastError(uiResult);
695 goto cleanup_hDatabase;
699 uiResult = MsiViewExecute(hViewST, 0);
700 if (uiResult != ERROR_SUCCESS)
702 SetLastError(uiResult);
704 goto cleanup_hViewST;
708 MSIHANDLE hRecordProg = MsiCreateRecord(2);
711 uiResult = ERROR_INVALID_HANDLE;
713 goto cleanup_hViewST_close;
719 MSIHANDLE hRecord = 0;
720 uiResult = MsiViewFetch(hViewST, &hRecord);
721 if (uiResult == ERROR_NO_MORE_ITEMS)
723 uiResult = ERROR_SUCCESS;
726 else if (uiResult != ERROR_SUCCESS)
728 SetLastError(uiResult);
730 goto cleanup_hRecordProg;
733 INSTALLSTATE iInstalled, iAction;
736 LPWSTR szValue = NULL;
738 if (uiResult != ERROR_SUCCESS)
740 goto cleanup_hRecord;
744 uiResult = MsiGetComponentState(hInstall, szValue, &iInstalled, &iAction);
745 if (uiResult != ERROR_SUCCESS)
747 SetLastError(uiResult);
750 goto cleanup_hRecord;
756 LPWSTR szDisplayName = NULL;
758 if (uiResult != ERROR_SUCCESS)
760 goto cleanup_hRecord;
763 LPWSTR szDisplayNameEx = wcschr(szDisplayName, L
'|');
764 szDisplayNameEx = szDisplayNameEx != NULL ? szDisplayNameEx + 1 : szDisplayName;
767 WCHAR szzHardwareIDs[0x100] = { 0 };
769 LPWSTR szHwId = NULL;
771 if (uiResult != ERROR_SUCCESS)
773 goto cleanup_szDisplayName;
775 memcpy_s(szzHardwareIDs,
sizeof(szzHardwareIDs) - 2*
sizeof(WCHAR) , szHwId, wcslen(szHwId)*
sizeof(WCHAR));
779 if (iAction > INSTALLSTATE_BROKEN)
783 if (iAction >= INSTALLSTATE_LOCAL)
786 LPWSTR szValue = NULL;
788 if (uiResult != ERROR_SUCCESS)
790 goto cleanup_szDisplayName;
792 #if defined(__GNUC__) || defined(__clang__)
797 #pragma GCC diagnostic push
798 #pragma GCC diagnostic ignored "-Wswitch"
800 switch (MsiEvaluateCondition(hInstall, szValue))
802 case MSICONDITION_FALSE:
804 goto cleanup_szDisplayName;
806 case MSICONDITION_ERROR:
807 uiResult = ERROR_INVALID_FIELD;
810 goto cleanup_szDisplayName;
812 #if defined(__GNUC__) || defined(__clang__)
813 #pragma GCC diagnostic pop
820 bRollbackEnabled ? &seqInstallRollback : NULL,
823 &iTicks) != ERROR_SUCCESS)
825 uiResult = ERROR_INSTALL_FAILED;
826 goto cleanup_szDisplayName;
838 bRollbackEnabled ? &seqUninstallCommit : NULL,
839 bRollbackEnabled ? &seqUninstallRollback : NULL,
847 MsiRecordSetInteger(hRecordProg, 1, 3 );
848 MsiRecordSetInteger(hRecordProg, 2, iTicks);
849 if (MsiProcessMessage(hInstall, INSTALLMESSAGE_PROGRESS, hRecordProg) == IDCANCEL)
851 uiResult = ERROR_INSTALL_USEREXIT;
852 goto cleanup_szDisplayName;
856 cleanup_szDisplayName:
859 MsiCloseHandle(hRecord);
860 if (uiResult != ERROR_SUCCESS)
862 goto cleanup_hRecordProg;
867 WCHAR tmpDir[MAX_PATH];
868 GetTempPath(MAX_PATH, tmpDir);
870 WCHAR str[MAX_PATH + 7];
871 swprintf_s(str, _countof(str), L
"tmpdir=%ls", tmpDir);
880 if ((uiResult =
setup_sequence(hInstall, L
"InstallTUNTAPAdapters", &seqInstall )) != ERROR_SUCCESS
881 || (uiResult =
setup_sequence(hInstall, L
"InstallTUNTAPAdaptersCommit", &seqInstallCommit )) != ERROR_SUCCESS
882 || (uiResult =
setup_sequence(hInstall, L
"InstallTUNTAPAdaptersRollback", &seqInstallRollback )) != ERROR_SUCCESS
883 || (uiResult =
setup_sequence(hInstall, L
"UninstallTUNTAPAdapters", &seqUninstall )) != ERROR_SUCCESS
884 || (uiResult =
setup_sequence(hInstall, L
"UninstallTUNTAPAdaptersCommit", &seqUninstallCommit )) != ERROR_SUCCESS
885 || (uiResult =
setup_sequence(hInstall, L
"UninstallTUNTAPAdaptersRollback", &seqUninstallRollback)) != ERROR_SUCCESS)
887 goto cleanup_hRecordProg;
890 uiResult = ERROR_SUCCESS;
893 MsiCloseHandle(hRecordProg);
894 cleanup_hViewST_close:
895 MsiViewClose(hViewST);
897 MsiCloseHandle(hViewST);
899 MsiCloseHandle(hDatabase);
907 if (bIsCoInitialized)
949 WCHAR path[MAX_PATH];
952 msg(
M_WARN,
"%s: Reboot required, create reboot indication file \"%ls\"", __FUNCTION__, path);
954 HANDLE file = CreateFileW(path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
955 if (file == INVALID_HANDLE_VALUE)
969 #pragma comment(linker, DLLEXP_EXPORT)
975 BOOL bIsCoInitialized = SUCCEEDED(CoInitialize(NULL));
976 WCHAR tmpDir[MAX_PATH] = {0};
980 BOOL bIsCleanup = MsiGetMode(hInstall, MSIRUNMODE_COMMIT) || MsiGetMode(hInstall, MSIRUNMODE_ROLLBACK);
983 LPWSTR szSequence = NULL;
984 uiResult =
msi_get_string(hInstall, L
"CustomActionData", &szSequence);
985 if (uiResult != ERROR_SUCCESS)
987 goto cleanup_CoInitialize;
990 LPWSTR *szArg = CommandLineToArgvW(szSequence, &nArgs);
993 uiResult = GetLastError();
995 goto cleanup_szSequence;
999 MSIHANDLE hRecordProg = MsiCreateRecord(3);
1000 MsiRecordSetInteger(hRecordProg, 1, 1);
1001 MsiRecordSetInteger(hRecordProg, 2, 1);
1002 MsiRecordSetInteger(hRecordProg, 3, 0);
1003 MsiProcessMessage(hInstall, INSTALLMESSAGE_PROGRESS, hRecordProg);
1006 MsiRecordSetInteger(hRecordProg, 1, 2);
1007 MsiRecordSetInteger(hRecordProg, 3, 0);
1009 BOOL bRebootRequired = FALSE;
1011 for (
int i = 1 ; i < nArgs; ++i)
1013 DWORD dwResult = ERROR_SUCCESS;
1015 if (wcsncmp(szArg[i], L
"create=", 7) == 0)
1018 LPWSTR szName = szArg[i] + 7;
1019 LPWSTR szHardwareId = wcschr(szName, L
'|');
1020 if (szHardwareId == NULL)
1022 goto invalid_argument;
1024 szHardwareId[0] = 0;
1029 MSIHANDLE hRecord = MsiCreateRecord(4);
1030 MsiRecordSetString(hRecord, 1, L
"Creating adapter");
1031 MsiRecordSetString(hRecord, 2, szName);
1032 MsiRecordSetString(hRecord, 3, szHardwareId);
1033 int iResult = MsiProcessMessage(hInstall, INSTALLMESSAGE_ACTIONDATA, hRecord);
1034 MsiCloseHandle(hRecord);
1035 if (iResult == IDCANCEL)
1037 uiResult = ERROR_INSTALL_USEREXIT;
1043 dwResult =
tap_create_adapter(NULL, NULL, szHardwareId, &bRebootRequired, &guidAdapter);
1044 if (dwResult == ERROR_SUCCESS)
1051 else if (wcsncmp(szArg[i], L
"deleteN=", 8) == 0)
1054 LPCWSTR szName = szArg[i] + 8;
1058 MSIHANDLE hRecord = MsiCreateRecord(3);
1059 MsiRecordSetString(hRecord, 1, L
"Deleting adapter");
1060 MsiRecordSetString(hRecord, 2, szName);
1061 int iResult = MsiProcessMessage(hInstall, INSTALLMESSAGE_ACTIONDATA, hRecord);
1062 MsiCloseHandle(hRecord);
1063 if (iResult == IDCANCEL)
1065 uiResult = ERROR_INSTALL_USEREXIT;
1073 if (dwResult == ERROR_SUCCESS)
1076 for (
struct tap_adapter_node *pAdapter = pAdapterList; pAdapter != NULL; pAdapter = pAdapter->
pNext)
1078 if (wcsicmp(
szName, pAdapter->szName) == 0)
1089 else if (wcsncmp(szArg[i], L
"delete=", 7) == 0)
1095 goto invalid_argument;
1099 else if (wcsncmp(szArg[i], L
"enable=", 7) == 0)
1105 goto invalid_argument;
1109 else if (wcsncmp(szArg[i], L
"disable=", 8) == 0)
1115 goto invalid_argument;
1119 else if (wcsncmp(szArg[i], L
"tmpdir=", 7) == 0)
1121 wcscpy_s(tmpDir, _countof(tmpDir), szArg[i] + 7);
1125 goto invalid_argument;
1128 if (dwResult != ERROR_SUCCESS && !bIsCleanup )
1130 uiResult = ERROR_INSTALL_FAILURE;
1136 if (MsiProcessMessage(hInstall, INSTALLMESSAGE_PROGRESS, hRecordProg) == IDCANCEL)
1138 dwResult = ERROR_INSTALL_USEREXIT;
1145 msg(
M_NONFATAL,
"%s: Ignoring invalid argument: %ls", __FUNCTION__, szArg[i]);
1149 if (bRebootRequired && wcslen(tmpDir) > 0)
1153 MsiCloseHandle(hRecordProg);
1157 cleanup_CoInitialize:
1158 if (bIsCoInitialized)
1168 #ifdef DLLEXP_EXPORT
1169 #pragma comment(linker, DLLEXP_EXPORT)
1174 BOOL bIsCoInitialized = SUCCEEDED(CoInitialize(NULL));
1179 WCHAR tempPath[MAX_PATH];
1180 GetTempPathW(MAX_PATH, tempPath);
1183 WCHAR path[MAX_PATH];
1185 WIN32_FIND_DATA data = { 0 };
1186 HANDLE searchHandle = FindFirstFileW(path, &data);
1187 if (searchHandle != INVALID_HANDLE_VALUE)
1189 msg(
M_WARN,
"%s: Reboot file exists, schedule reboot", __FUNCTION__);
1191 FindClose(searchHandle);
1194 MsiSetMode(hInstall, MSIRUNMODE_REBOOTATEND, TRUE);
1197 if (bIsCoInitialized)
1201 return ERROR_SUCCESS;