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")
62 #define MSICA_ADAPTER_TICK_SIZE (16*1024)
64 #define FILE_NEED_REBOOT L".ovpn_need_reboot"
66 #define OPENVPN_CONNECT_ADAPTER_SUBSTR L"OpenVPN Connect"
81 _In_ MSIHANDLE hInstall,
87 uiResult = MsiSetProperty(hInstall, szProperty, szSequence);
89 if (uiResult != ERROR_SUCCESS)
91 SetLastError(uiResult);
109 _debug_popup(
_In_z_ LPCSTR szFunctionName)
111 TCHAR szTitle[0x100], szMessage[0x100+MAX_PATH], szProcessPath[MAX_PATH];
115 _stprintf_s(szTitle, _countof(szTitle), TEXT(
"%hs v%") TEXT(
PRIsLPTSTR),
119 GetModuleFileName(NULL, szProcessPath, _countof(szProcessPath));
120 LPCTSTR szProcessName = _tcsrchr(szProcessPath, TEXT(
'\\'));
121 szProcessName = szProcessName ? szProcessName + 1 : szProcessPath;
125 szMessage, _countof(szMessage),
126 TEXT(
"The %") TEXT(
PRIsLPTSTR) TEXT(
" process (PID: %u) has started to execute the %hs")
127 TEXT(
" custom action.\r\n")
129 TEXT(
"If you would like to debug the custom action, attach a debugger to this process and set breakpoints before dismissing this dialog.\r\n")
131 TEXT(
"If you are not debugging this custom action, you can safely ignore this message."),
133 GetCurrentProcessId(),
136 MessageBox(NULL, szMessage, szTitle, MB_OK);
139 #define debug_popup(f) _debug_popup(f)
141 #define debug_popup(f)
146 _In_ MSIHANDLE hInstall,
147 _In_z_ LPCTSTR szzHardwareIDs,
148 _In_z_ LPCTSTR szAdaptersPropertyName,
149 _In_z_ LPCTSTR szActiveAdaptersPropertyName)
156 if (uiResult != ERROR_SUCCESS)
160 else if (pAdapterList == NULL)
167 PIP_ADAPTER_ADDRESSES pAdapterAdresses = NULL;
168 ULONG ulAdapterAdressesSize = 16*1024;
169 for (
size_t iteration = 0; iteration < 2; iteration++)
171 pAdapterAdresses = (PIP_ADAPTER_ADDRESSES)malloc(ulAdapterAdressesSize);
172 if (pAdapterAdresses == NULL)
174 msg(
M_NONFATAL,
"%s: malloc(%u) failed", __FUNCTION__, ulAdapterAdressesSize);
175 uiResult = ERROR_OUTOFMEMORY;
goto cleanup_pAdapterList;
178 ULONG ulResult = GetAdaptersAddresses(
180 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,
183 &ulAdapterAdressesSize);
185 if (ulResult == ERROR_SUCCESS)
190 free(pAdapterAdresses);
191 if (ulResult != ERROR_BUFFER_OVERFLOW)
193 SetLastError(ulResult);
195 uiResult = ulResult;
goto cleanup_pAdapterList;
200 size_t adapter_count = 0;
208 szAdapters = (LPTSTR)malloc(adapter_count * (38 + 1 ) *
sizeof(TCHAR)),
209 szAdaptersTail = szAdapters;
210 if (szAdapters == NULL)
212 msg(
M_FATAL,
"%s: malloc(%u) failed", __FUNCTION__, adapter_count * (38 + 1 ) *
sizeof(TCHAR));
213 uiResult = ERROR_OUTOFMEMORY;
goto cleanup_pAdapterAdresses;
217 szAdaptersActive = (LPTSTR)malloc(adapter_count * (38 + 1 ) *
sizeof(TCHAR)),
218 szAdaptersActiveTail = szAdaptersActive;
219 if (szAdaptersActive == NULL)
221 msg(
M_FATAL,
"%s: malloc(%u) failed", __FUNCTION__, adapter_count * (38 + 1 ) *
sizeof(TCHAR));
222 uiResult = ERROR_OUTOFMEMORY;
goto cleanup_szAdapters;
230 msg(
M_WARN,
"%s: skip OpenVPN Connect adapter '%ls'", __FUNCTION__, pAdapter->szName);
235 LPOLESTR szAdapterId = NULL;
236 StringFromIID((REFIID)&pAdapter->guid, &szAdapterId);
239 if (szAdapters < szAdaptersTail)
241 *(szAdaptersTail++) = TEXT(
';');
243 memcpy(szAdaptersTail, szAdapterId, 38 *
sizeof(TCHAR));
244 szAdaptersTail += 38;
247 for (PIP_ADAPTER_ADDRESSES p = pAdapterAdresses; p; p = p->Next)
249 OLECHAR szId[38 + 1 ];
251 if (MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, p->AdapterName, -1, szId, _countof(szId)) > 0
252 && SUCCEEDED(IIDFromString(szId, &
guid))
253 && memcmp(&
guid, &pAdapter->guid,
sizeof(GUID)) == 0)
255 if (p->OperStatus == IfOperStatusUp)
258 if (szAdaptersActive < szAdaptersActiveTail)
260 *(szAdaptersActiveTail++) = TEXT(
';');
262 memcpy(szAdaptersActiveTail, szAdapterId, 38 *
sizeof(TCHAR));
263 szAdaptersActiveTail += 38;
268 CoTaskMemFree(szAdapterId);
270 szAdaptersTail [0] = 0;
271 szAdaptersActiveTail[0] = 0;
274 uiResult = MsiSetProperty(hInstall, szAdaptersPropertyName, szAdapters);
275 if (uiResult != ERROR_SUCCESS)
277 SetLastError(uiResult);
278 msg(
M_NONFATAL |
M_ERRNO,
"%s: MsiSetProperty(\"%s\") failed", __FUNCTION__, szAdaptersPropertyName);
279 goto cleanup_szAdaptersActive;
281 uiResult = MsiSetProperty(hInstall, szActiveAdaptersPropertyName, szAdaptersActive);
282 if (uiResult != ERROR_SUCCESS)
284 SetLastError(uiResult);
285 msg(
M_NONFATAL |
M_ERRNO,
"%s: MsiSetProperty(\"%s\") failed", __FUNCTION__, szActiveAdaptersPropertyName);
286 goto cleanup_szAdaptersActive;
289 cleanup_szAdaptersActive:
290 free(szAdaptersActive);
293 cleanup_pAdapterAdresses:
294 free(pAdapterAdresses);
295 cleanup_pAdapterList:
304 #pragma comment(linker, DLLEXP_EXPORT)
309 BOOL bIsCoInitialized = SUCCEEDED(CoInitialize(NULL));
316 TEXT(
"TAPWINDOWS6ADAPTERS"),
317 TEXT(
"ACTIVETAPWINDOWS6ADAPTERS"));
320 TEXT(
"Wintun") TEXT(
"\0"),
321 TEXT(
"WINTUNADAPTERS"),
322 TEXT(
"ACTIVEWINTUNADAPTERS"));
325 TEXT(
"ovpn-dco") TEXT(
"\0"),
326 TEXT(
"OVPNDCOADAPTERS"),
327 TEXT(
"ACTIVEOVPNDCOADAPTERS"));
329 if (bIsCoInitialized)
333 return ERROR_SUCCESS;
341 #pragma comment(linker, DLLEXP_EXPORT)
343 UNREFERENCED_PARAMETER(hInstall);
348 HWND hWnd = FindWindow(TEXT(
"OpenVPN-GUI"), NULL);
352 SendMessage(hWnd, WM_CLOSE, 0, 0);
356 return ERROR_SUCCESS;
364 #pragma comment(linker, DLLEXP_EXPORT)
370 BOOL bIsCoInitialized = SUCCEEDED(CoInitialize(NULL));
375 MSIHANDLE hRecord = MsiCreateRecord(1);
378 uiResult = ERROR_INVALID_HANDLE;
380 goto cleanup_CoInitialize;
382 uiResult = MsiRecordSetString(hRecord, 0, TEXT(
"\"[#bin.openvpn_gui.exe]\""));
383 if (uiResult != ERROR_SUCCESS)
385 SetLastError(uiResult);
387 goto cleanup_MsiCreateRecord;
391 TCHAR szStackBuf[MAX_PATH];
392 DWORD dwPathSize = _countof(szStackBuf);
393 LPTSTR szPath = szStackBuf;
394 uiResult = MsiFormatRecord(hInstall, hRecord, szPath, &dwPathSize);
395 if (uiResult == ERROR_MORE_DATA)
398 szPath = (LPTSTR)malloc((++dwPathSize) *
sizeof(TCHAR));
401 msg(
M_FATAL,
"%s: malloc(%u) failed", __FUNCTION__, dwPathSize *
sizeof(TCHAR));
402 uiResult = ERROR_OUTOFMEMORY;
goto cleanup_MsiCreateRecord;
405 uiResult = MsiFormatRecord(hInstall, hRecord, szPath, &dwPathSize);
407 if (uiResult != ERROR_SUCCESS)
409 SetLastError(uiResult);
411 goto cleanup_malloc_szPath;
415 SHELLEXECUTEINFO sei = {
416 .cbSize =
sizeof(SHELLEXECUTEINFO),
417 .fMask = SEE_MASK_FLAG_NO_UI,
419 .nShow = SW_SHOWNORMAL
421 if (!ShellExecuteEx(&sei))
423 uiResult = GetLastError();
425 goto cleanup_malloc_szPath;
428 uiResult = ERROR_SUCCESS;
430 cleanup_malloc_szPath:
431 if (szPath != szStackBuf)
435 cleanup_MsiCreateRecord:
436 MsiCloseHandle(hRecord);
437 cleanup_CoInitialize:
438 if (bIsCoInitialized)
470 _In_z_ LPCTSTR szDisplayName,
471 _In_z_ LPCTSTR szHardwareId,
477 if (dwResult != ERROR_SUCCESS)
485 if (pAdapterOther == NULL)
488 TCHAR szArgument[10 + MAX_PATH + 1 + MAX_PATH + 1 ];
492 szArgument, _countof(szArgument),
493 TEXT(
"create=\"%.*s|%.*s\""),
494 MAX_PATH, szDisplayName,
495 MAX_PATH, szHardwareId);
502 szArgument, _countof(szArgument),
503 TEXT(
"deleteN=\"%.*s\""),
504 MAX_PATH, szDisplayName);
511 else if (_tcsicmp(szDisplayName, pAdapterOther->szName) == 0)
514 for (LPCTSTR hwid = pAdapterOther->szzHardwareIDs;; hwid += _tcslen(hwid) + 1)
519 msg(
M_NONFATAL,
"%s: Adapter with name \"%" PRIsLPTSTR "\" already exists", __FUNCTION__, pAdapterOther->szName);
520 dwResult = ERROR_ALREADY_EXISTS;
521 goto cleanup_pAdapterList;
523 else if (_tcsicmp(hwid, szHardwareId) == 0)
533 cleanup_pAdapterList:
571 _In_z_ LPCTSTR szDisplayName,
578 if (dwResult != ERROR_SUCCESS)
586 if (_tcsicmp(szDisplayName, pAdapter->szName) == 0)
589 TCHAR szArgument[8 + 38 + 1 ];
590 if (seqCommit && seqRollback)
594 szArgument, _countof(szArgument),
601 szArgument, _countof(szArgument),
608 szArgument, _countof(szArgument),
617 szArgument, _countof(szArgument),
637 #pragma comment(linker, DLLEXP_EXPORT)
643 BOOL bIsCoInitialized = SUCCEEDED(CoInitialize(NULL));
653 seqUninstallRollback;
662 bool bRollbackEnabled = MsiEvaluateCondition(hInstall, TEXT(
"RollbackDisabled")) != MSICONDITION_TRUE;
665 MSIHANDLE hDatabase = MsiGetActiveDatabase(hInstall);
668 msg(
M_NONFATAL,
"%s: MsiGetActiveDatabase failed", __FUNCTION__);
669 uiResult = ERROR_INVALID_HANDLE;
670 goto cleanup_exec_seq;
674 switch (MsiDatabaseIsTablePersistent(hDatabase, TEXT(
"TUNTAPAdapter")))
676 case MSICONDITION_FALSE:
677 case MSICONDITION_TRUE:
break;
680 uiResult = ERROR_SUCCESS;
681 goto cleanup_hDatabase;
685 MSIHANDLE hViewST = 0;
686 LPCTSTR szQuery = TEXT(
"SELECT `Adapter`,`DisplayName`,`Condition`,`Component_`,`HardwareId` FROM `TUNTAPAdapter`");
687 uiResult = MsiDatabaseOpenView(hDatabase, szQuery, &hViewST);
688 if (uiResult != ERROR_SUCCESS)
690 SetLastError(uiResult);
692 goto cleanup_hDatabase;
696 uiResult = MsiViewExecute(hViewST, 0);
697 if (uiResult != ERROR_SUCCESS)
699 SetLastError(uiResult);
701 goto cleanup_hViewST;
705 MSIHANDLE hRecordProg = MsiCreateRecord(2);
708 uiResult = ERROR_INVALID_HANDLE;
710 goto cleanup_hViewST_close;
716 MSIHANDLE hRecord = 0;
717 uiResult = MsiViewFetch(hViewST, &hRecord);
718 if (uiResult == ERROR_NO_MORE_ITEMS)
720 uiResult = ERROR_SUCCESS;
723 else if (uiResult != ERROR_SUCCESS)
725 SetLastError(uiResult);
727 goto cleanup_hRecordProg;
730 INSTALLSTATE iInstalled, iAction;
733 LPTSTR szValue = NULL;
735 if (uiResult != ERROR_SUCCESS)
737 goto cleanup_hRecord;
741 uiResult = MsiGetComponentState(hInstall, szValue, &iInstalled, &iAction);
742 if (uiResult != ERROR_SUCCESS)
744 SetLastError(uiResult);
747 goto cleanup_hRecord;
753 LPTSTR szDisplayName = NULL;
755 if (uiResult != ERROR_SUCCESS)
757 goto cleanup_hRecord;
760 LPTSTR szDisplayNameEx = _tcschr(szDisplayName, TEXT(
'|'));
761 szDisplayNameEx = szDisplayNameEx != NULL ? szDisplayNameEx + 1 : szDisplayName;
764 TCHAR szzHardwareIDs[0x100] = { 0 };
766 LPTSTR szHwId = NULL;
768 if (uiResult != ERROR_SUCCESS)
770 goto cleanup_szDisplayName;
772 memcpy_s(szzHardwareIDs,
sizeof(szzHardwareIDs) - 2*
sizeof(TCHAR) , szHwId, _tcslen(szHwId)*
sizeof(TCHAR));
776 if (iAction > INSTALLSTATE_BROKEN)
780 if (iAction >= INSTALLSTATE_LOCAL)
783 LPTSTR szValue = NULL;
785 if (uiResult != ERROR_SUCCESS)
787 goto cleanup_szDisplayName;
794 #pragma GCC diagnostic push
795 #pragma GCC diagnostic ignored "-Wswitch"
797 switch (MsiEvaluateCondition(hInstall, szValue))
799 case MSICONDITION_FALSE:
801 goto cleanup_szDisplayName;
803 case MSICONDITION_ERROR:
804 uiResult = ERROR_INVALID_FIELD;
807 goto cleanup_szDisplayName;
810 #pragma GCC diagnostic pop
817 bRollbackEnabled ? &seqInstallRollback : NULL,
820 &iTicks) != ERROR_SUCCESS)
822 uiResult = ERROR_INSTALL_FAILED;
823 goto cleanup_szDisplayName;
835 bRollbackEnabled ? &seqUninstallCommit : NULL,
836 bRollbackEnabled ? &seqUninstallRollback : NULL,
844 MsiRecordSetInteger(hRecordProg, 1, 3 );
845 MsiRecordSetInteger(hRecordProg, 2, iTicks);
846 if (MsiProcessMessage(hInstall, INSTALLMESSAGE_PROGRESS, hRecordProg) == IDCANCEL)
848 uiResult = ERROR_INSTALL_USEREXIT;
849 goto cleanup_szDisplayName;
853 cleanup_szDisplayName:
856 MsiCloseHandle(hRecord);
857 if (uiResult != ERROR_SUCCESS)
859 goto cleanup_hRecordProg;
864 TCHAR tmpDir[MAX_PATH];
865 GetTempPath(MAX_PATH, tmpDir);
867 TCHAR str[MAX_PATH + 7];
868 _stprintf_s(str, _countof(str), TEXT(
"tmpdir=%") TEXT(
PRIsLPTSTR), tmpDir);
877 if ((uiResult =
setup_sequence(hInstall, TEXT(
"InstallTUNTAPAdapters" ), &seqInstall )) != ERROR_SUCCESS
878 || (uiResult =
setup_sequence(hInstall, TEXT(
"InstallTUNTAPAdaptersCommit" ), &seqInstallCommit )) != ERROR_SUCCESS
879 || (uiResult =
setup_sequence(hInstall, TEXT(
"InstallTUNTAPAdaptersRollback" ), &seqInstallRollback )) != ERROR_SUCCESS
880 || (uiResult =
setup_sequence(hInstall, TEXT(
"UninstallTUNTAPAdapters" ), &seqUninstall )) != ERROR_SUCCESS
881 || (uiResult =
setup_sequence(hInstall, TEXT(
"UninstallTUNTAPAdaptersCommit" ), &seqUninstallCommit )) != ERROR_SUCCESS
882 || (uiResult =
setup_sequence(hInstall, TEXT(
"UninstallTUNTAPAdaptersRollback"), &seqUninstallRollback)) != ERROR_SUCCESS)
884 goto cleanup_hRecordProg;
887 uiResult = ERROR_SUCCESS;
890 MsiCloseHandle(hRecordProg);
891 cleanup_hViewST_close:
892 MsiViewClose(hViewST);
894 MsiCloseHandle(hViewST);
896 MsiCloseHandle(hDatabase);
904 if (bIsCoInitialized)
946 WCHAR path[MAX_PATH];
949 msg(
M_WARN,
"%s: Reboot required, create reboot indication file \"%ls\"", __FUNCTION__, path);
951 HANDLE file = CreateFileW(path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
952 if (file == INVALID_HANDLE_VALUE)
966 #pragma comment(linker, DLLEXP_EXPORT)
972 BOOL bIsCoInitialized = SUCCEEDED(CoInitialize(NULL));
973 WCHAR tmpDir[MAX_PATH] = {0};
977 BOOL bIsCleanup = MsiGetMode(hInstall, MSIRUNMODE_COMMIT) || MsiGetMode(hInstall, MSIRUNMODE_ROLLBACK);
980 LPWSTR szSequence = NULL;
981 uiResult =
msi_get_string(hInstall, L
"CustomActionData", &szSequence);
982 if (uiResult != ERROR_SUCCESS)
984 goto cleanup_CoInitialize;
987 LPWSTR *szArg = CommandLineToArgvW(szSequence, &nArgs);
990 uiResult = GetLastError();
992 goto cleanup_szSequence;
996 MSIHANDLE hRecordProg = MsiCreateRecord(3);
997 MsiRecordSetInteger(hRecordProg, 1, 1);
998 MsiRecordSetInteger(hRecordProg, 2, 1);
999 MsiRecordSetInteger(hRecordProg, 3, 0);
1000 MsiProcessMessage(hInstall, INSTALLMESSAGE_PROGRESS, hRecordProg);
1003 MsiRecordSetInteger(hRecordProg, 1, 2);
1004 MsiRecordSetInteger(hRecordProg, 3, 0);
1006 BOOL bRebootRequired = FALSE;
1008 for (
int i = 1 ; i < nArgs; ++i)
1010 DWORD dwResult = ERROR_SUCCESS;
1012 if (wcsncmp(szArg[i], L
"create=", 7) == 0)
1015 LPWSTR szName = szArg[i] + 7;
1016 LPWSTR szHardwareId = wcschr(szName, L
'|');
1017 if (szHardwareId == NULL)
1019 goto invalid_argument;
1021 szHardwareId[0] = 0;
1026 MSIHANDLE hRecord = MsiCreateRecord(4);
1027 MsiRecordSetString(hRecord, 1, TEXT(
"Creating adapter"));
1028 MsiRecordSetString(hRecord, 2, szName);
1029 MsiRecordSetString(hRecord, 3, szHardwareId);
1030 int iResult = MsiProcessMessage(hInstall, INSTALLMESSAGE_ACTIONDATA, hRecord);
1031 MsiCloseHandle(hRecord);
1032 if (iResult == IDCANCEL)
1034 uiResult = ERROR_INSTALL_USEREXIT;
1040 dwResult =
tap_create_adapter(NULL, NULL, szHardwareId, &bRebootRequired, &guidAdapter);
1041 if (dwResult == ERROR_SUCCESS)
1048 else if (wcsncmp(szArg[i], L
"deleteN=", 8) == 0)
1051 LPCWSTR szName = szArg[i] + 8;
1055 MSIHANDLE hRecord = MsiCreateRecord(3);
1056 MsiRecordSetString(hRecord, 1, TEXT(
"Deleting adapter"));
1057 MsiRecordSetString(hRecord, 2, szName);
1058 int iResult = MsiProcessMessage(hInstall, INSTALLMESSAGE_ACTIONDATA, hRecord);
1059 MsiCloseHandle(hRecord);
1060 if (iResult == IDCANCEL)
1062 uiResult = ERROR_INSTALL_USEREXIT;
1070 if (dwResult == ERROR_SUCCESS)
1073 for (
struct tap_adapter_node *pAdapter = pAdapterList; pAdapter != NULL; pAdapter = pAdapter->
pNext)
1075 if (_tcsicmp(
szName, pAdapter->szName) == 0)
1086 else if (wcsncmp(szArg[i], L
"delete=", 7) == 0)
1092 goto invalid_argument;
1096 else if (wcsncmp(szArg[i], L
"enable=", 7) == 0)
1102 goto invalid_argument;
1106 else if (wcsncmp(szArg[i], L
"disable=", 8) == 0)
1112 goto invalid_argument;
1116 else if (wcsncmp(szArg[i], L
"tmpdir=", 7) == 0)
1118 wcscpy_s(tmpDir, _countof(tmpDir), szArg[i] + 7);
1122 goto invalid_argument;
1125 if (dwResult != ERROR_SUCCESS && !bIsCleanup )
1127 uiResult = ERROR_INSTALL_FAILURE;
1133 if (MsiProcessMessage(hInstall, INSTALLMESSAGE_PROGRESS, hRecordProg) == IDCANCEL)
1135 dwResult = ERROR_INSTALL_USEREXIT;
1142 msg(
M_NONFATAL,
"%s: Ignoring invalid argument: %ls", __FUNCTION__, szArg[i]);
1146 if (bRebootRequired && wcslen(tmpDir) > 0)
1150 MsiCloseHandle(hRecordProg);
1154 cleanup_CoInitialize:
1155 if (bIsCoInitialized)
1166 #pragma comment(linker, DLLEXP_EXPORT)
1171 BOOL bIsCoInitialized = SUCCEEDED(CoInitialize(NULL));
1176 WCHAR tempPath[MAX_PATH];
1177 GetTempPathW(MAX_PATH, tempPath);
1180 WCHAR path[MAX_PATH];
1182 WIN32_FIND_DATA data = { 0 };
1183 HANDLE searchHandle = FindFirstFileW(path, &data);
1184 if (searchHandle != INVALID_HANDLE_VALUE)
1186 msg(
M_WARN,
"%s: Reboot file exists, schedule reboot", __FUNCTION__);
1188 FindClose(searchHandle);
1191 MsiSetMode(hInstall, MSIRUNMODE_REBOOTATEND, TRUE);
1194 if (bIsCoInitialized)
1198 return ERROR_SUCCESS;