diff options
Diffstat (limited to '')
5 files changed, 102 insertions, 438 deletions
diff --git a/src/ext/Firewall/ca/firewall.cpp b/src/ext/Firewall/ca/firewall.cpp index 35c8be6e..491b10fa 100644 --- a/src/ext/Firewall/ca/firewall.cpp +++ b/src/ext/Firewall/ca/firewall.cpp | |||
| @@ -348,90 +348,6 @@ LExit: | |||
| 348 | } | 348 | } |
| 349 | 349 | ||
| 350 | /****************************************************************** | 350 | /****************************************************************** |
| 351 | FSupportProfiles - Returns true if we support profiles on this machine. | ||
| 352 | (Only on Vista or later) | ||
| 353 | |||
| 354 | ********************************************************************/ | ||
| 355 | static BOOL FSupportProfiles() | ||
| 356 | { | ||
| 357 | BOOL fSupportProfiles = FALSE; | ||
| 358 | INetFwRules* pNetFwRules = NULL; | ||
| 359 | |||
| 360 | // We only support profiles if we can co-create an instance of NetFwPolicy2. | ||
| 361 | // This will not work on pre-vista machines. | ||
| 362 | if (SUCCEEDED(GetFirewallRules(TRUE, &pNetFwRules)) && pNetFwRules != NULL) | ||
| 363 | { | ||
| 364 | fSupportProfiles = TRUE; | ||
| 365 | ReleaseObject(pNetFwRules); | ||
| 366 | } | ||
| 367 | |||
| 368 | return fSupportProfiles; | ||
| 369 | } | ||
| 370 | |||
| 371 | /****************************************************************** | ||
| 372 | GetCurrentFirewallProfile - get the active firewall profile as an | ||
| 373 | INetFwProfile, which owns the lists of exceptions we're | ||
| 374 | updating. | ||
| 375 | |||
| 376 | ********************************************************************/ | ||
| 377 | static HRESULT GetCurrentFirewallProfile( | ||
| 378 | __in BOOL fIgnoreFailures, | ||
| 379 | __out INetFwProfile** ppfwProfile | ||
| 380 | ) | ||
| 381 | { | ||
| 382 | HRESULT hr = S_OK; | ||
| 383 | INetFwMgr* pfwMgr = NULL; | ||
| 384 | INetFwPolicy* pfwPolicy = NULL; | ||
| 385 | INetFwProfile* pfwProfile = NULL; | ||
| 386 | *ppfwProfile = NULL; | ||
| 387 | |||
| 388 | do | ||
| 389 | { | ||
| 390 | ReleaseNullObject(pfwPolicy); | ||
| 391 | ReleaseNullObject(pfwMgr); | ||
| 392 | ReleaseNullObject(pfwProfile); | ||
| 393 | |||
| 394 | if (SUCCEEDED(hr = ::CoCreateInstance(__uuidof(NetFwMgr), NULL, CLSCTX_INPROC_SERVER, __uuidof(INetFwMgr), (void**)&pfwMgr)) && | ||
| 395 | SUCCEEDED(hr = pfwMgr->get_LocalPolicy(&pfwPolicy)) && | ||
| 396 | SUCCEEDED(hr = pfwPolicy->get_CurrentProfile(&pfwProfile))) | ||
| 397 | { | ||
| 398 | break; | ||
| 399 | } | ||
| 400 | else if (fIgnoreFailures) | ||
| 401 | { | ||
| 402 | ExitFunction1(hr = S_FALSE); | ||
| 403 | } | ||
| 404 | else | ||
| 405 | { | ||
| 406 | WcaLog(LOGMSG_STANDARD, "Failed to connect to Windows Firewall"); | ||
| 407 | UINT er = WcaErrorMessage(msierrFirewallCannotConnect, hr, INSTALLMESSAGE_ERROR | MB_ABORTRETRYIGNORE, 0); | ||
| 408 | switch (er) | ||
| 409 | { | ||
| 410 | case IDABORT: // exit with the current HRESULT | ||
| 411 | ExitFunction(); | ||
| 412 | case IDRETRY: // clean up and retry the loop | ||
| 413 | hr = S_FALSE; | ||
| 414 | break; | ||
| 415 | case IDIGNORE: // pass S_FALSE back to the caller, who knows how to ignore the failure | ||
| 416 | ExitFunction1(hr = S_FALSE); | ||
| 417 | default: // No UI, so default is to fail. | ||
| 418 | ExitFunction(); | ||
| 419 | } | ||
| 420 | } | ||
| 421 | } while (S_FALSE == hr); | ||
| 422 | |||
| 423 | *ppfwProfile = pfwProfile; | ||
| 424 | pfwProfile = NULL; | ||
| 425 | |||
| 426 | LExit: | ||
| 427 | ReleaseObject(pfwPolicy); | ||
| 428 | ReleaseObject(pfwMgr); | ||
| 429 | ReleaseObject(pfwProfile); | ||
| 430 | |||
| 431 | return hr; | ||
| 432 | } | ||
| 433 | |||
| 434 | /****************************************************************** | ||
| 435 | AddApplicationException | 351 | AddApplicationException |
| 436 | 352 | ||
| 437 | ********************************************************************/ | 353 | ********************************************************************/ |
| @@ -509,92 +425,6 @@ LExit: | |||
| 509 | } | 425 | } |
| 510 | 426 | ||
| 511 | /****************************************************************** | 427 | /****************************************************************** |
| 512 | AddApplicationExceptionOnCurrentProfile | ||
| 513 | |||
| 514 | ********************************************************************/ | ||
| 515 | static HRESULT AddApplicationExceptionOnCurrentProfile( | ||
| 516 | __in LPCWSTR wzFile, | ||
| 517 | __in LPCWSTR wzName, | ||
| 518 | __in_opt LPCWSTR wzRemoteAddresses, | ||
| 519 | __in BOOL fIgnoreFailures | ||
| 520 | ) | ||
| 521 | { | ||
| 522 | HRESULT hr = S_OK; | ||
| 523 | BSTR bstrFile = NULL; | ||
| 524 | BSTR bstrName = NULL; | ||
| 525 | BSTR bstrRemoteAddresses = NULL; | ||
| 526 | INetFwProfile* pfwProfile = NULL; | ||
| 527 | INetFwAuthorizedApplications* pfwApps = NULL; | ||
| 528 | INetFwAuthorizedApplication* pfwApp = NULL; | ||
| 529 | |||
| 530 | // convert to BSTRs to make COM happy | ||
| 531 | bstrFile = ::SysAllocString(wzFile); | ||
| 532 | ExitOnNull(bstrFile, hr, E_OUTOFMEMORY, "failed SysAllocString for path"); | ||
| 533 | bstrName = ::SysAllocString(wzName); | ||
| 534 | ExitOnNull(bstrName, hr, E_OUTOFMEMORY, "failed SysAllocString for name"); | ||
| 535 | bstrRemoteAddresses = ::SysAllocString(wzRemoteAddresses); | ||
| 536 | ExitOnNull(bstrRemoteAddresses, hr, E_OUTOFMEMORY, "failed SysAllocString for remote addresses"); | ||
| 537 | |||
| 538 | // get the firewall profile, which is our entry point for adding exceptions | ||
| 539 | hr = GetCurrentFirewallProfile(fIgnoreFailures, &pfwProfile); | ||
| 540 | ExitOnFailure(hr, "failed to get firewall profile"); | ||
| 541 | if (S_FALSE == hr) // user or package author chose to ignore missing firewall | ||
| 542 | { | ||
| 543 | ExitFunction(); | ||
| 544 | } | ||
| 545 | |||
| 546 | // first, let's see if the app is already on the exception list | ||
| 547 | hr = pfwProfile->get_AuthorizedApplications(&pfwApps); | ||
| 548 | ExitOnFailure(hr, "failed to get list of authorized apps"); | ||
| 549 | |||
| 550 | // try to find it (i.e., support reinstall) | ||
| 551 | hr = pfwApps->Item(bstrFile, &pfwApp); | ||
| 552 | if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr) | ||
| 553 | { | ||
| 554 | // not found, so we get to add it | ||
| 555 | hr = ::CoCreateInstance(__uuidof(NetFwAuthorizedApplication), NULL, CLSCTX_INPROC_SERVER, __uuidof(INetFwAuthorizedApplication), reinterpret_cast<void**>(&pfwApp)); | ||
| 556 | ExitOnFailure(hr, "failed to create authorized app"); | ||
| 557 | |||
| 558 | // set the display name | ||
| 559 | hr = pfwApp->put_Name(bstrName); | ||
| 560 | ExitOnFailure(hr, "failed to set authorized app name"); | ||
| 561 | |||
| 562 | // set path | ||
| 563 | hr = pfwApp->put_ProcessImageFileName(bstrFile); | ||
| 564 | ExitOnFailure(hr, "failed to set authorized app path"); | ||
| 565 | |||
| 566 | // set the allowed remote addresses | ||
| 567 | if (bstrRemoteAddresses && *bstrRemoteAddresses) | ||
| 568 | { | ||
| 569 | hr = pfwApp->put_RemoteAddresses(bstrRemoteAddresses); | ||
| 570 | ExitOnFailure(hr, "failed to set authorized app remote addresses"); | ||
| 571 | } | ||
| 572 | |||
| 573 | // add it to the list of authorized apps | ||
| 574 | hr = pfwApps->Add(pfwApp); | ||
| 575 | ExitOnFailure(hr, "failed to add app to the authorized apps list"); | ||
| 576 | } | ||
| 577 | else | ||
| 578 | { | ||
| 579 | // we found an existing app exception (if we succeeded, that is) | ||
| 580 | ExitOnFailure(hr, "failed trying to find existing app"); | ||
| 581 | |||
| 582 | // enable it (just in case it was disabled) | ||
| 583 | pfwApp->put_Enabled(VARIANT_TRUE); | ||
| 584 | } | ||
| 585 | |||
| 586 | LExit: | ||
| 587 | ReleaseBSTR(bstrRemoteAddresses); | ||
| 588 | ReleaseBSTR(bstrName); | ||
| 589 | ReleaseBSTR(bstrFile); | ||
| 590 | ReleaseObject(pfwApp); | ||
| 591 | ReleaseObject(pfwApps); | ||
| 592 | ReleaseObject(pfwProfile); | ||
| 593 | |||
| 594 | return fIgnoreFailures ? S_OK : hr; | ||
| 595 | } | ||
| 596 | |||
| 597 | /****************************************************************** | ||
| 598 | AddPortException | 428 | AddPortException |
| 599 | 429 | ||
| 600 | ********************************************************************/ | 430 | ********************************************************************/ |
| @@ -659,79 +489,11 @@ LExit: | |||
| 659 | } | 489 | } |
| 660 | 490 | ||
| 661 | /****************************************************************** | 491 | /****************************************************************** |
| 662 | AddPortExceptionOnCurrentProfile | 492 | RemoveException - Removes all exception rules with the given name. |
| 663 | |||
| 664 | ********************************************************************/ | ||
| 665 | static HRESULT AddPortExceptionOnCurrentProfile( | ||
| 666 | __in LPCWSTR wzName, | ||
| 667 | __in_opt LPCWSTR wzRemoteAddresses, | ||
| 668 | __in BOOL fIgnoreFailures, | ||
| 669 | __in int iPort, | ||
| 670 | __in int iProtocol | ||
| 671 | ) | ||
| 672 | { | ||
| 673 | HRESULT hr = S_OK; | ||
| 674 | BSTR bstrName = NULL; | ||
| 675 | BSTR bstrRemoteAddresses = NULL; | ||
| 676 | INetFwProfile* pfwProfile = NULL; | ||
| 677 | INetFwOpenPorts* pfwPorts = NULL; | ||
| 678 | INetFwOpenPort* pfwPort = NULL; | ||
| 679 | |||
| 680 | // convert to BSTRs to make COM happy | ||
| 681 | bstrName = ::SysAllocString(wzName); | ||
| 682 | ExitOnNull(bstrName, hr, E_OUTOFMEMORY, "failed SysAllocString for name"); | ||
| 683 | bstrRemoteAddresses = ::SysAllocString(wzRemoteAddresses); | ||
| 684 | ExitOnNull(bstrRemoteAddresses, hr, E_OUTOFMEMORY, "failed SysAllocString for remote addresses"); | ||
| 685 | |||
| 686 | // create and initialize a new open port object | ||
| 687 | hr = ::CoCreateInstance(__uuidof(NetFwOpenPort), NULL, CLSCTX_INPROC_SERVER, __uuidof(INetFwOpenPort), reinterpret_cast<void**>(&pfwPort)); | ||
| 688 | ExitOnFailure(hr, "failed to create new open port"); | ||
| 689 | |||
| 690 | hr = pfwPort->put_Port(iPort); | ||
| 691 | ExitOnFailure(hr, "failed to set exception port"); | ||
| 692 | |||
| 693 | hr = pfwPort->put_Protocol(static_cast<NET_FW_IP_PROTOCOL>(iProtocol)); | ||
| 694 | ExitOnFailure(hr, "failed to set exception protocol"); | ||
| 695 | |||
| 696 | if (bstrRemoteAddresses && *bstrRemoteAddresses) | ||
| 697 | { | ||
| 698 | hr = pfwPort->put_RemoteAddresses(bstrRemoteAddresses); | ||
| 699 | ExitOnFailure(hr, "failed to set exception remote addresses '%ls'", bstrRemoteAddresses); | ||
| 700 | } | ||
| 701 | |||
| 702 | hr = pfwPort->put_Name(bstrName); | ||
| 703 | ExitOnFailure(hr, "failed to set exception name"); | ||
| 704 | |||
| 705 | // get the firewall profile, its current list of open ports, and add ours | ||
| 706 | hr = GetCurrentFirewallProfile(fIgnoreFailures, &pfwProfile); | ||
| 707 | ExitOnFailure(hr, "failed to get firewall profile"); | ||
| 708 | if (S_FALSE == hr) // user or package author chose to ignore missing firewall | ||
| 709 | { | ||
| 710 | ExitFunction(); | ||
| 711 | } | ||
| 712 | |||
| 713 | hr = pfwProfile->get_GloballyOpenPorts(&pfwPorts); | ||
| 714 | ExitOnFailure(hr, "failed to get open ports"); | ||
| 715 | |||
| 716 | hr = pfwPorts->Add(pfwPort); | ||
| 717 | ExitOnFailure(hr, "failed to add exception to global list"); | ||
| 718 | |||
| 719 | LExit: | ||
| 720 | ReleaseBSTR(bstrRemoteAddresses); | ||
| 721 | ReleaseBSTR(bstrName); | ||
| 722 | ReleaseObject(pfwProfile); | ||
| 723 | ReleaseObject(pfwPorts); | ||
| 724 | ReleaseObject(pfwPort); | ||
| 725 | |||
| 726 | return fIgnoreFailures ? S_OK : hr; | ||
| 727 | } | ||
| 728 | |||
| 729 | /****************************************************************** | ||
| 730 | RemoveException - Removes the exception rule with the given name. | ||
| 731 | 493 | ||
| 732 | ********************************************************************/ | 494 | ********************************************************************/ |
| 733 | static HRESULT RemoveException( | 495 | static HRESULT RemoveException( |
| 734 | __in LPCWSTR wzName, | 496 | __in LPCWSTR wzName, |
| 735 | __in BOOL fIgnoreFailures | 497 | __in BOOL fIgnoreFailures |
| 736 | ) | 498 | ) |
| 737 | { | 499 | { |
| @@ -751,7 +513,7 @@ static HRESULT RemoveException( | |||
| 751 | } | 513 | } |
| 752 | 514 | ||
| 753 | hr = pNetFwRules->Remove(bstrName); | 515 | hr = pNetFwRules->Remove(bstrName); |
| 754 | ExitOnFailure(hr, "failed to remove authorized app"); | 516 | ExitOnFailure(hr, "failed to remove firewall rule"); |
| 755 | 517 | ||
| 756 | LExit: | 518 | LExit: |
| 757 | ReleaseBSTR(bstrName); | 519 | ReleaseBSTR(bstrName); |
| @@ -761,192 +523,6 @@ LExit: | |||
| 761 | } | 523 | } |
| 762 | 524 | ||
| 763 | /****************************************************************** | 525 | /****************************************************************** |
| 764 | RemoveApplicationExceptionFromCurrentProfile | ||
| 765 | |||
| 766 | ********************************************************************/ | ||
| 767 | static HRESULT RemoveApplicationExceptionFromCurrentProfile( | ||
| 768 | __in LPCWSTR wzFile, | ||
| 769 | __in BOOL fIgnoreFailures | ||
| 770 | ) | ||
| 771 | { | ||
| 772 | HRESULT hr = S_OK; | ||
| 773 | INetFwProfile* pfwProfile = NULL; | ||
| 774 | INetFwAuthorizedApplications* pfwApps = NULL; | ||
| 775 | |||
| 776 | // convert to BSTRs to make COM happy | ||
| 777 | BSTR bstrFile = ::SysAllocString(wzFile); | ||
| 778 | ExitOnNull(bstrFile, hr, E_OUTOFMEMORY, "failed SysAllocString for path"); | ||
| 779 | |||
| 780 | // get the firewall profile, which is our entry point for removing exceptions | ||
| 781 | hr = GetCurrentFirewallProfile(fIgnoreFailures, &pfwProfile); | ||
| 782 | ExitOnFailure(hr, "failed to get firewall profile"); | ||
| 783 | if (S_FALSE == hr) // user or package author chose to ignore missing firewall | ||
| 784 | { | ||
| 785 | ExitFunction(); | ||
| 786 | } | ||
| 787 | |||
| 788 | // now get the list of app exceptions and remove the one | ||
| 789 | hr = pfwProfile->get_AuthorizedApplications(&pfwApps); | ||
| 790 | ExitOnFailure(hr, "failed to get list of authorized apps"); | ||
| 791 | |||
| 792 | hr = pfwApps->Remove(bstrFile); | ||
| 793 | ExitOnFailure(hr, "failed to remove authorized app"); | ||
| 794 | |||
| 795 | LExit: | ||
| 796 | ReleaseBSTR(bstrFile); | ||
| 797 | ReleaseObject(pfwApps); | ||
| 798 | ReleaseObject(pfwProfile); | ||
| 799 | |||
| 800 | return fIgnoreFailures ? S_OK : hr; | ||
| 801 | } | ||
| 802 | |||
| 803 | /****************************************************************** | ||
| 804 | RemovePortExceptionFromCurrentProfile | ||
| 805 | |||
| 806 | ********************************************************************/ | ||
| 807 | static HRESULT RemovePortExceptionFromCurrentProfile( | ||
| 808 | __in int iPort, | ||
| 809 | __in int iProtocol, | ||
| 810 | __in BOOL fIgnoreFailures | ||
| 811 | ) | ||
| 812 | { | ||
| 813 | HRESULT hr = S_OK; | ||
| 814 | INetFwProfile* pfwProfile = NULL; | ||
| 815 | INetFwOpenPorts* pfwPorts = NULL; | ||
| 816 | |||
| 817 | // get the firewall profile, which is our entry point for adding exceptions | ||
| 818 | hr = GetCurrentFirewallProfile(fIgnoreFailures, &pfwProfile); | ||
| 819 | ExitOnFailure(hr, "failed to get firewall profile"); | ||
| 820 | if (S_FALSE == hr) // user or package author chose to ignore missing firewall | ||
| 821 | { | ||
| 822 | ExitFunction(); | ||
| 823 | } | ||
| 824 | |||
| 825 | hr = pfwProfile->get_GloballyOpenPorts(&pfwPorts); | ||
| 826 | ExitOnFailure(hr, "failed to get open ports"); | ||
| 827 | |||
| 828 | hr = pfwPorts->Remove(iPort, static_cast<NET_FW_IP_PROTOCOL>(iProtocol)); | ||
| 829 | ExitOnFailure(hr, "failed to remove open port %d, protocol %d", iPort, iProtocol); | ||
| 830 | |||
| 831 | LExit: | ||
| 832 | return fIgnoreFailures ? S_OK : hr; | ||
| 833 | } | ||
| 834 | |||
| 835 | static HRESULT AddApplicationException( | ||
| 836 | __in BOOL fSupportProfiles, | ||
| 837 | __in LPCWSTR wzFile, | ||
| 838 | __in LPCWSTR wzName, | ||
| 839 | __in int iProfile, | ||
| 840 | __in_opt LPCWSTR wzRemoteAddresses, | ||
| 841 | __in BOOL fIgnoreFailures, | ||
| 842 | __in LPCWSTR wzPort, | ||
| 843 | __in int iProtocol, | ||
| 844 | __in LPCWSTR wzDescription, | ||
| 845 | __in int iDirection | ||
| 846 | ) | ||
| 847 | { | ||
| 848 | HRESULT hr = S_OK; | ||
| 849 | |||
| 850 | if (fSupportProfiles) | ||
| 851 | { | ||
| 852 | hr = AddApplicationException(wzFile, wzName, iProfile, wzRemoteAddresses, fIgnoreFailures, wzPort, iProtocol, wzDescription, iDirection); | ||
| 853 | } | ||
| 854 | else | ||
| 855 | { | ||
| 856 | if (0 != *wzPort || MSI_NULL_INTEGER != iProtocol) | ||
| 857 | { | ||
| 858 | // NOTE: This is treated as an error rather than either creating a rule based on just the application (no port), or | ||
| 859 | // just the port because it is unclear what is the proper fall back. For example, suppose that you have code that | ||
| 860 | // runs in dllhost.exe. Clearly falling back to opening all of dllhost is wrong. Because the firewall is a security | ||
| 861 | // feature, it seems better to require the MSI author to indicate the behavior that they want. | ||
| 862 | WcaLog(LOGMSG_STANDARD, "FirewallExtension: Cannot add firewall rule '%ls', which defines both an application and a port or protocol. Such a rule requires Microsoft Windows Vista or later.", wzName); | ||
| 863 | return fIgnoreFailures ? S_OK : E_NOTIMPL; | ||
| 864 | } | ||
| 865 | |||
| 866 | hr = AddApplicationExceptionOnCurrentProfile(wzFile, wzName, wzRemoteAddresses, fIgnoreFailures); | ||
| 867 | } | ||
| 868 | |||
| 869 | return hr; | ||
| 870 | } | ||
| 871 | |||
| 872 | static HRESULT AddPortException( | ||
| 873 | __in BOOL fSupportProfiles, | ||
| 874 | __in LPCWSTR wzName, | ||
| 875 | __in int iProfile, | ||
| 876 | __in_opt LPCWSTR wzRemoteAddresses, | ||
| 877 | __in BOOL fIgnoreFailures, | ||
| 878 | __in LPCWSTR wzPort, | ||
| 879 | __in int iProtocol, | ||
| 880 | __in LPCWSTR wzDescription, | ||
| 881 | __in int iDirection | ||
| 882 | ) | ||
| 883 | { | ||
| 884 | HRESULT hr = S_OK; | ||
| 885 | |||
| 886 | if (fSupportProfiles) | ||
| 887 | { | ||
| 888 | hr = AddPortException(wzName, iProfile, wzRemoteAddresses, fIgnoreFailures, wzPort, iProtocol, wzDescription, iDirection); | ||
| 889 | } | ||
| 890 | else | ||
| 891 | { | ||
| 892 | hr = AddPortExceptionOnCurrentProfile(wzName, wzRemoteAddresses, fIgnoreFailures, wcstol(wzPort, NULL, 10), iProtocol); | ||
| 893 | } | ||
| 894 | |||
| 895 | return hr; | ||
| 896 | } | ||
| 897 | |||
| 898 | static HRESULT RemoveApplicationException( | ||
| 899 | __in BOOL fSupportProfiles, | ||
| 900 | __in LPCWSTR wzName, | ||
| 901 | __in LPCWSTR wzFile, | ||
| 902 | __in BOOL fIgnoreFailures, | ||
| 903 | __in LPCWSTR wzPort, | ||
| 904 | __in int iProtocol | ||
| 905 | ) | ||
| 906 | { | ||
| 907 | HRESULT hr = S_OK; | ||
| 908 | |||
| 909 | if (fSupportProfiles) | ||
| 910 | { | ||
| 911 | hr = RemoveException(wzName, fIgnoreFailures); | ||
| 912 | } | ||
| 913 | else | ||
| 914 | { | ||
| 915 | if (0 != *wzPort || MSI_NULL_INTEGER != iProtocol) | ||
| 916 | { | ||
| 917 | WcaLog(LOGMSG_STANDARD, "FirewallExtension: Cannot remove firewall rule '%ls', which defines both an application and a port or protocol. Such a rule requires Microsoft Windows Vista or later.", wzName); | ||
| 918 | return S_OK; | ||
| 919 | } | ||
| 920 | |||
| 921 | hr = RemoveApplicationExceptionFromCurrentProfile(wzFile, fIgnoreFailures); | ||
| 922 | } | ||
| 923 | |||
| 924 | return hr; | ||
| 925 | } | ||
| 926 | |||
| 927 | static HRESULT RemovePortException( | ||
| 928 | __in BOOL fSupportProfiles, | ||
| 929 | __in LPCWSTR wzName, | ||
| 930 | __in LPCWSTR wzPort, | ||
| 931 | __in int iProtocol, | ||
| 932 | __in BOOL fIgnoreFailures | ||
| 933 | ) | ||
| 934 | { | ||
| 935 | HRESULT hr = S_OK; | ||
| 936 | |||
| 937 | if (fSupportProfiles) | ||
| 938 | { | ||
| 939 | hr = RemoveException(wzName, fIgnoreFailures); | ||
| 940 | } | ||
| 941 | else | ||
| 942 | { | ||
| 943 | hr = RemovePortExceptionFromCurrentProfile(wcstol(wzPort, NULL, 10), iProtocol, fIgnoreFailures); | ||
| 944 | } | ||
| 945 | |||
| 946 | return hr; | ||
| 947 | } | ||
| 948 | |||
| 949 | /****************************************************************** | ||
| 950 | ExecFirewallExceptions - deferred custom action entry point to | 526 | ExecFirewallExceptions - deferred custom action entry point to |
| 951 | register and remove firewall exceptions. | 527 | register and remove firewall exceptions. |
| 952 | 528 | ||
| @@ -956,7 +532,6 @@ extern "C" UINT __stdcall ExecFirewallExceptions( | |||
| 956 | ) | 532 | ) |
| 957 | { | 533 | { |
| 958 | HRESULT hr = S_OK; | 534 | HRESULT hr = S_OK; |
| 959 | BOOL fSupportProfiles = FALSE; | ||
| 960 | LPWSTR pwz = NULL; | 535 | LPWSTR pwz = NULL; |
| 961 | LPWSTR pwzCustomActionData = NULL; | 536 | LPWSTR pwzCustomActionData = NULL; |
| 962 | int iTodo = WCA_TODO_UNKNOWN; | 537 | int iTodo = WCA_TODO_UNKNOWN; |
| @@ -982,9 +557,6 @@ extern "C" UINT __stdcall ExecFirewallExceptions( | |||
| 982 | hr = ::CoInitialize(NULL); | 557 | hr = ::CoInitialize(NULL); |
| 983 | ExitOnFailure(hr, "failed to initialize COM"); | 558 | ExitOnFailure(hr, "failed to initialize COM"); |
| 984 | 559 | ||
| 985 | // Find out if we support profiles (only on Vista or later) | ||
| 986 | fSupportProfiles = FSupportProfiles(); | ||
| 987 | |||
| 988 | // loop through all the passed in data | 560 | // loop through all the passed in data |
| 989 | pwz = pwzCustomActionData; | 561 | pwz = pwzCustomActionData; |
| 990 | while (pwz && *pwz) | 562 | while (pwz && *pwz) |
| @@ -1043,13 +615,13 @@ extern "C" UINT __stdcall ExecFirewallExceptions( | |||
| 1043 | case WCA_TODO_INSTALL: | 615 | case WCA_TODO_INSTALL: |
| 1044 | case WCA_TODO_REINSTALL: | 616 | case WCA_TODO_REINSTALL: |
| 1045 | WcaLog(LOGMSG_STANDARD, "Installing firewall exception2 %ls on port %ls, protocol %d", pwzName, pwzPort, iProtocol); | 617 | WcaLog(LOGMSG_STANDARD, "Installing firewall exception2 %ls on port %ls, protocol %d", pwzName, pwzPort, iProtocol); |
| 1046 | hr = AddPortException(fSupportProfiles, pwzName, iProfile, pwzRemoteAddresses, fIgnoreFailures, pwzPort, iProtocol, pwzDescription, iDirection); | 618 | hr = AddPortException(pwzName, iProfile, pwzRemoteAddresses, fIgnoreFailures, pwzPort, iProtocol, pwzDescription, iDirection); |
| 1047 | ExitOnFailure(hr, "failed to add/update port exception for name '%ls' on port %ls, protocol %d", pwzName, pwzPort, iProtocol); | 619 | ExitOnFailure(hr, "failed to add/update port exception for name '%ls' on port %ls, protocol %d", pwzName, pwzPort, iProtocol); |
| 1048 | break; | 620 | break; |
| 1049 | 621 | ||
| 1050 | case WCA_TODO_UNINSTALL: | 622 | case WCA_TODO_UNINSTALL: |
| 1051 | WcaLog(LOGMSG_STANDARD, "Uninstalling firewall exception2 %ls on port %ls, protocol %d", pwzName, pwzPort, iProtocol); | 623 | WcaLog(LOGMSG_STANDARD, "Uninstalling firewall exception2 %ls on port %ls, protocol %d", pwzName, pwzPort, iProtocol); |
| 1052 | hr = RemovePortException(fSupportProfiles, pwzName, pwzPort, iProtocol, fIgnoreFailures); | 624 | hr = RemoveException(pwzName, fIgnoreFailures); |
| 1053 | ExitOnFailure(hr, "failed to remove port exception for name '%ls' on port %ls, protocol %d", pwzName, pwzPort, iProtocol); | 625 | ExitOnFailure(hr, "failed to remove port exception for name '%ls' on port %ls, protocol %d", pwzName, pwzPort, iProtocol); |
| 1054 | break; | 626 | break; |
| 1055 | } | 627 | } |
| @@ -1061,13 +633,13 @@ extern "C" UINT __stdcall ExecFirewallExceptions( | |||
| 1061 | case WCA_TODO_INSTALL: | 633 | case WCA_TODO_INSTALL: |
| 1062 | case WCA_TODO_REINSTALL: | 634 | case WCA_TODO_REINSTALL: |
| 1063 | WcaLog(LOGMSG_STANDARD, "Installing firewall exception2 %ls (%ls)", pwzName, pwzFile); | 635 | WcaLog(LOGMSG_STANDARD, "Installing firewall exception2 %ls (%ls)", pwzName, pwzFile); |
| 1064 | hr = AddApplicationException(fSupportProfiles, pwzFile, pwzName, iProfile, pwzRemoteAddresses, fIgnoreFailures, pwzPort, iProtocol, pwzDescription, iDirection); | 636 | hr = AddApplicationException(pwzFile, pwzName, iProfile, pwzRemoteAddresses, fIgnoreFailures, pwzPort, iProtocol, pwzDescription, iDirection); |
| 1065 | ExitOnFailure(hr, "failed to add/update application exception for name '%ls', file '%ls'", pwzName, pwzFile); | 637 | ExitOnFailure(hr, "failed to add/update application exception for name '%ls', file '%ls'", pwzName, pwzFile); |
| 1066 | break; | 638 | break; |
| 1067 | 639 | ||
| 1068 | case WCA_TODO_UNINSTALL: | 640 | case WCA_TODO_UNINSTALL: |
| 1069 | WcaLog(LOGMSG_STANDARD, "Uninstalling firewall exception2 %ls (%ls)", pwzName, pwzFile); | 641 | WcaLog(LOGMSG_STANDARD, "Uninstalling firewall exception2 %ls (%ls)", pwzName, pwzFile); |
| 1070 | hr = RemoveApplicationException(fSupportProfiles, pwzName, pwzFile, fIgnoreFailures, pwzPort, iProtocol); | 642 | hr = RemoveException(pwzName, fIgnoreFailures); |
| 1071 | ExitOnFailure(hr, "failed to remove application exception for name '%ls', file '%ls'", pwzName, pwzFile); | 643 | ExitOnFailure(hr, "failed to remove application exception for name '%ls', file '%ls'", pwzName, pwzFile); |
| 1072 | break; | 644 | break; |
| 1073 | } | 645 | } |
diff --git a/src/test/burn/WixTestTools/Firewall/Verifier.cs b/src/test/burn/WixTestTools/Firewall/Verifier.cs index c1bf3219..2c273e7a 100644 --- a/src/test/burn/WixTestTools/Firewall/Verifier.cs +++ b/src/test/burn/WixTestTools/Firewall/Verifier.cs | |||
| @@ -254,7 +254,13 @@ namespace WixTestTools.Firewall | |||
| 254 | rule.Enabled = false; | 254 | rule.Enabled = false; |
| 255 | } | 255 | } |
| 256 | 256 | ||
| 257 | public static void RemoveFirewallRulesByName(string name) | 257 | /// <summary> |
| 258 | /// Removes a firewall rule by name. If multiple rules with the same name exist, only one of them is removed.<br/> | ||
| 259 | /// This behavior is different from <b>netsh advfirewall firewall delete rule</b> where all matching rules are deleted if multiple matches are found.<br/> | ||
| 260 | /// The firewall rule name cannot be null or an empty string. | ||
| 261 | /// </summary> | ||
| 262 | /// <param name="name">Name of the firewall rule to be removed.</param> | ||
| 263 | public static void RemoveFirewallRuleByName(string name) | ||
| 258 | { | 264 | { |
| 259 | var rules = GetINetFwRules(); | 265 | var rules = GetINetFwRules(); |
| 260 | rules.Remove(name); | 266 | rules.Remove(name); |
diff --git a/src/test/msi/TestData/FirewallExtensionTests/IgnoreFailedFirewallRules/IgnoreFailedFirewallRules.wixproj b/src/test/msi/TestData/FirewallExtensionTests/IgnoreFailedFirewallRules/IgnoreFailedFirewallRules.wixproj new file mode 100644 index 00000000..b1770b0f --- /dev/null +++ b/src/test/msi/TestData/FirewallExtensionTests/IgnoreFailedFirewallRules/IgnoreFailedFirewallRules.wixproj | |||
| @@ -0,0 +1,13 @@ | |||
| 1 | <!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. --> | ||
| 2 | <Project Sdk="WixToolset.Sdk"> | ||
| 3 | <PropertyGroup> | ||
| 4 | <UpgradeCode>{4D188568-1CCF-4EEE-BC27-17C3DCC83E58}</UpgradeCode> | ||
| 5 | <ProductComponentsRef>true</ProductComponentsRef> | ||
| 6 | </PropertyGroup> | ||
| 7 | <ItemGroup> | ||
| 8 | <Compile Include="..\..\Templates\Product.wxs" Link="Product.wxs" /> | ||
| 9 | </ItemGroup> | ||
| 10 | <ItemGroup> | ||
| 11 | <PackageReference Include="WixToolset.Firewall.wixext" /> | ||
| 12 | </ItemGroup> | ||
| 13 | </Project> \ No newline at end of file | ||
diff --git a/src/test/msi/TestData/FirewallExtensionTests/IgnoreFailedFirewallRules/product.wxs b/src/test/msi/TestData/FirewallExtensionTests/IgnoreFailedFirewallRules/product.wxs new file mode 100644 index 00000000..d615f0c6 --- /dev/null +++ b/src/test/msi/TestData/FirewallExtensionTests/IgnoreFailedFirewallRules/product.wxs | |||
| @@ -0,0 +1,35 @@ | |||
| 1 | <!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. --> | ||
| 2 | |||
| 3 | <Wix xmlns="http://wixtoolset.org/schemas/v4/wxs" xmlns:fw="http://wixtoolset.org/schemas/v4/wxs/firewall"> | ||
| 4 | <Fragment> | ||
| 5 | <ComponentGroup Id="ProductComponents"> | ||
| 6 | <ComponentRef Id="FirewallComponent3"/> | ||
| 7 | </ComponentGroup> | ||
| 8 | |||
| 9 | <Property Id="RULENAME" Secure="yes" /> | ||
| 10 | <CustomAction Id="SetRuleNameDefaultValue" Property="RULENAME" Value="WiXToolset401 Test - 0008 removal" Execute="firstSequence" /> | ||
| 11 | |||
| 12 | <InstallExecuteSequence> | ||
| 13 | <Custom Action="SetRuleNameDefaultValue" After="AppSearch" Condition="NOT NORULENAME" /> | ||
| 14 | </InstallExecuteSequence> | ||
| 15 | |||
| 16 | </Fragment> | ||
| 17 | |||
| 18 | <Fragment> | ||
| 19 | <Component Id="FirewallComponent3" Guid="AA693149-B39C-4012-9DDE-92AB0CEA2386" Directory="INSTALLFOLDER" Transitive="yes"> | ||
| 20 | <File Source="$(sys.SOURCEFILEPATH)" KeyPath="yes" > | ||
| 21 | <fw:FirewallException Id="FirewallException6" | ||
| 22 | Description="WiX Toolset firewall exception rule integration test | ignore failed app properties" | ||
| 23 | Name="WiXToolset401 Test - 0006 pipe" Scope="any" IgnoreFailure="yes" /> | ||
| 24 | </File> | ||
| 25 | <fw:FirewallException Id="FirewallException7" | ||
| 26 | Description="WiX Toolset firewall exception rule integration test | ignore failed port properties" | ||
| 27 | Name="WiXToolset401 Test - 0007 pipe" Scope="any" Port="65123" IgnoreFailure="yes" /> | ||
| 28 | |||
| 29 | <fw:FirewallException Id="FirewallException8" | ||
| 30 | Description="WiX Toolset firewall exception rule integration test - removal test" | ||
| 31 | Name="[RULENAME]" Scope="any" Port="52390" Program="test.exe" | ||
| 32 | IgnoreFailure="yes" /> | ||
| 33 | </Component> | ||
| 34 | </Fragment> | ||
| 35 | </Wix> | ||
diff --git a/src/test/msi/WixToolsetTest.MsiE2E/FirewallExtensionTests.cs b/src/test/msi/WixToolsetTest.MsiE2E/FirewallExtensionTests.cs index 3e605d7a..4106cd72 100644 --- a/src/test/msi/WixToolsetTest.MsiE2E/FirewallExtensionTests.cs +++ b/src/test/msi/WixToolsetTest.MsiE2E/FirewallExtensionTests.cs | |||
| @@ -144,7 +144,7 @@ namespace WixToolsetTest.MsiE2E | |||
| 144 | var product = this.CreatePackageInstaller("FirewallRules"); | 144 | var product = this.CreatePackageInstaller("FirewallRules"); |
| 145 | product.InstallProduct(MSIExec.MSIExecReturnCode.SUCCESS); | 145 | product.InstallProduct(MSIExec.MSIExecReturnCode.SUCCESS); |
| 146 | 146 | ||
| 147 | Verifier.RemoveFirewallRulesByName("WiXToolset401 Test - 0002"); | 147 | Verifier.RemoveFirewallRuleByName("WiXToolset401 Test - 0002"); |
| 148 | Assert.False(Verifier.FirewallRuleExists("WiXToolset401 Test - 0002")); | 148 | Assert.False(Verifier.FirewallRuleExists("WiXToolset401 Test - 0002")); |
| 149 | 149 | ||
| 150 | product.RepairProduct(MSIExec.MSIExecReturnCode.SUCCESS); | 150 | product.RepairProduct(MSIExec.MSIExecReturnCode.SUCCESS); |
| @@ -176,7 +176,7 @@ namespace WixToolsetTest.MsiE2E | |||
| 176 | var product = this.CreatePackageInstaller("FirewallRules"); | 176 | var product = this.CreatePackageInstaller("FirewallRules"); |
| 177 | product.InstallProduct(MSIExec.MSIExecReturnCode.SUCCESS); | 177 | product.InstallProduct(MSIExec.MSIExecReturnCode.SUCCESS); |
| 178 | 178 | ||
| 179 | Verifier.RemoveFirewallRulesByName("WiXToolset401 Test - 0001"); | 179 | Verifier.RemoveFirewallRuleByName("WiXToolset401 Test - 0001"); |
| 180 | Assert.False(Verifier.FirewallRuleExists("WiXToolset401 Test - 0001")); | 180 | Assert.False(Verifier.FirewallRuleExists("WiXToolset401 Test - 0001")); |
| 181 | 181 | ||
| 182 | product.RepairProduct(MSIExec.MSIExecReturnCode.SUCCESS); | 182 | product.RepairProduct(MSIExec.MSIExecReturnCode.SUCCESS); |
| @@ -277,5 +277,43 @@ namespace WixToolsetTest.MsiE2E | |||
| 277 | Assert.False(Verifier.FirewallRuleExists("WiXToolset401 Test - 0004")); | 277 | Assert.False(Verifier.FirewallRuleExists("WiXToolset401 Test - 0004")); |
| 278 | Assert.False(Verifier.FirewallRuleExists("WiXToolset401 Test - 0005 - 9999")); | 278 | Assert.False(Verifier.FirewallRuleExists("WiXToolset401 Test - 0005 - 9999")); |
| 279 | } | 279 | } |
| 280 | |||
| 281 | [RuntimeFact] | ||
| 282 | public void SucceedWhenIgnoreOnFailureIsSet() | ||
| 283 | { | ||
| 284 | var product = this.CreatePackageInstaller("IgnoreFailedFirewallRules"); | ||
| 285 | var log1 = product.InstallProduct(MSIExec.MSIExecReturnCode.SUCCESS); | ||
| 286 | |||
| 287 | Assert.False(Verifier.FirewallRuleExists("WiXToolset401 Test - 0006 pipe")); | ||
| 288 | Assert.True(LogVerifier.MessageInLogFile(log1, "failed to add app to the authorized apps list")); | ||
| 289 | |||
| 290 | Assert.False(Verifier.FirewallRuleExists("WiXToolset401 Test - 0007 pipe")); | ||
| 291 | Assert.True(LogVerifier.MessageInLogFile(log1, "failed to add app to the authorized ports list")); | ||
| 292 | |||
| 293 | var expected = new RuleDetails("WiXToolset401 Test - 0008 removal") | ||
| 294 | { | ||
| 295 | Action = NET_FW_ACTION_.NET_FW_ACTION_ALLOW, | ||
| 296 | ApplicationName = "test.exe", | ||
| 297 | Description = "WiX Toolset firewall exception rule integration test - removal test", | ||
| 298 | Direction = NET_FW_RULE_DIRECTION_.NET_FW_RULE_DIR_IN, | ||
| 299 | EdgeTraversal = true, | ||
| 300 | EdgeTraversalOptions = 1, | ||
| 301 | Enabled = true, | ||
| 302 | InterfaceTypes = "All", | ||
| 303 | LocalPorts = "52390", | ||
| 304 | LocalAddresses = "*", | ||
| 305 | Profiles = Int32.MaxValue, | ||
| 306 | Protocol = 6, | ||
| 307 | RemoteAddresses = "*", | ||
| 308 | RemotePorts = "*", | ||
| 309 | SecureFlags = 0, | ||
| 310 | }; | ||
| 311 | |||
| 312 | Verifier.VerifyFirewallRule("WiXToolset401 Test - 0008 removal", expected); | ||
| 313 | Verifier.RemoveFirewallRuleByName("WiXToolset401 Test - 0008 removal"); | ||
| 314 | |||
| 315 | var log2 = product.UninstallProduct(MSIExec.MSIExecReturnCode.SUCCESS, "NORULENAME=1"); | ||
| 316 | Assert.True(LogVerifier.MessageInLogFile(log2, "failed to remove firewall rule")); | ||
| 317 | } | ||
| 280 | } | 318 | } |
| 281 | } | 319 | } |
