diff options
Diffstat (limited to 'src')
80 files changed, 18950 insertions, 2 deletions
diff --git a/src/ca/CustomMsiErrors.h b/src/ca/CustomMsiErrors.h new file mode 100644 index 00000000..1fd8d050 --- /dev/null +++ b/src/ca/CustomMsiErrors.h | |||
| @@ -0,0 +1,48 @@ | |||
| 1 | #pragma once | ||
| 2 | // 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. | ||
| 3 | |||
| 4 | #define msierrIISCannotConnect 26001 | ||
| 5 | #define msierrIISFailedReadWebSite 26002 | ||
| 6 | #define msierrIISFailedReadWebDirs 26003 | ||
| 7 | #define msierrIISFailedReadVDirs 26004 | ||
| 8 | #define msierrIISFailedReadFilters 26005 | ||
| 9 | #define msierrIISFailedReadAppPool 26006 | ||
| 10 | #define msierrIISFailedReadMimeMap 26007 | ||
| 11 | #define msierrIISFailedReadProp 26008 | ||
| 12 | #define msierrIISFailedReadWebSvcExt 26009 | ||
| 13 | #define msierrIISFailedReadWebError 26010 | ||
| 14 | #define msierrIISFailedReadHttpHeader 26011 | ||
| 15 | |||
| 16 | #define msierrIISFailedSchedTransaction 26031 | ||
| 17 | #define msierrIISFailedSchedInstallWebs 26032 | ||
| 18 | #define msierrIISFailedSchedInstallWebDirs 26033 | ||
| 19 | #define msierrIISFailedSchedInstallVDirs 26034 | ||
| 20 | #define msierrIISFailedSchedInstallFilters 26035 | ||
| 21 | #define msierrIISFailedSchedInstallAppPool 26036 | ||
| 22 | #define msierrIISFailedSchedInstallProp 26037 | ||
| 23 | #define msierrIISFailedSchedInstallWebSvcExt 26038 | ||
| 24 | |||
| 25 | #define msierrIISFailedSchedUninstallWebs 26051 | ||
| 26 | #define msierrIISFailedSchedUninstallWebDirs 26052 | ||
| 27 | #define msierrIISFailedSchedUninstallVDirs 26053 | ||
| 28 | #define msierrIISFailedSchedUninstallFilters 26054 | ||
| 29 | #define msierrIISFailedSchedUninstallAppPool 26055 | ||
| 30 | #define msierrIISFailedSchedUninstallProp 26056 | ||
| 31 | #define msierrIISFailedSchedUninstallWebSvcExt 26057 | ||
| 32 | |||
| 33 | #define msierrIISFailedStartTransaction 26101 | ||
| 34 | #define msierrIISFailedOpenKey 26102 | ||
| 35 | #define msierrIISFailedCreateKey 26103 | ||
| 36 | #define msierrIISFailedWriteData 26104 | ||
| 37 | #define msierrIISFailedCreateApp 26105 | ||
| 38 | #define msierrIISFailedDeleteKey 26106 | ||
| 39 | #define msierrIISFailedDeleteApp 26107 | ||
| 40 | #define msierrIISFailedDeleteValue 26108 | ||
| 41 | #define msierrIISFailedCommitInUse 26109 | ||
| 42 | |||
| 43 | // Last available value 26200 | ||
| 44 | |||
| 45 | #define msierrCERTFailedOpen 26351 | ||
| 46 | #define msierrCERTFailedAdd 26352 | ||
| 47 | |||
| 48 | // Last available value 26450 | ||
diff --git a/src/ca/caSuffix.h b/src/ca/caSuffix.h new file mode 100644 index 00000000..303a99e9 --- /dev/null +++ b/src/ca/caSuffix.h | |||
| @@ -0,0 +1,11 @@ | |||
| 1 | #pragma once | ||
| 2 | // 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. | ||
| 3 | |||
| 4 | |||
| 5 | #if defined _WIN64 | ||
| 6 | #define PLATFORM_DECORATION(f) f L"_64" | ||
| 7 | #elif defined ARM | ||
| 8 | #define PLATFORM_DECORATION(f) f L"_ARM" | ||
| 9 | #else | ||
| 10 | #define PLATFORM_DECORATION(f) f | ||
| 11 | #endif | ||
diff --git a/src/ca/iisca.def b/src/ca/iisca.def index 187269e1..b9127da6 100644 --- a/src/ca/iisca.def +++ b/src/ca/iisca.def | |||
| @@ -4,4 +4,27 @@ | |||
| 4 | LIBRARY "iisca" | 4 | LIBRARY "iisca" |
| 5 | 5 | ||
| 6 | EXPORTS | 6 | EXPORTS |
| 7 | 7 | ;scacert.cpp | |
| 8 | InstallCertificates | ||
| 9 | UninstallCertificates | ||
| 10 | ;scacertexec.cpp | ||
| 11 | AddUserCertificate | ||
| 12 | AddMachineCertificate | ||
| 13 | DeleteUserCertificate | ||
| 14 | DeleteMachineCertificate | ||
| 15 | ;scaexec.cpp | ||
| 16 | StartMetabaseTransaction | ||
| 17 | RollbackMetabaseTransaction | ||
| 18 | CommitMetabaseTransaction | ||
| 19 | |||
| 20 | WriteMetabaseChanges | ||
| 21 | |||
| 22 | StartIIS7ConfigTransaction | ||
| 23 | RollbackIIS7ConfigTransaction | ||
| 24 | CommitIIS7ConfigTransaction | ||
| 25 | |||
| 26 | WriteIIS7ConfigChanges | ||
| 27 | ;scasched.cpp | ||
| 28 | ConfigureIIs | ||
| 29 | ConfigureIIsExec | ||
| 30 | ConfigureIIs7Exec | ||
diff --git a/src/ca/iisca.vcxproj b/src/ca/iisca.vcxproj index f83268b2..08ac4444 100644 --- a/src/ca/iisca.vcxproj +++ b/src/ca/iisca.vcxproj | |||
| @@ -38,7 +38,7 @@ | |||
| 38 | </ImportGroup> | 38 | </ImportGroup> |
| 39 | 39 | ||
| 40 | <PropertyGroup> | 40 | <PropertyGroup> |
| 41 | <ProjectAdditionalLinkLibraries>msi.lib</ProjectAdditionalLinkLibraries> | 41 | <ProjectAdditionalLinkLibraries>crypt32.lib;msi.lib;Ws2_32.lib</ProjectAdditionalLinkLibraries> |
| 42 | </PropertyGroup> | 42 | </PropertyGroup> |
| 43 | 43 | ||
| 44 | <ItemGroup> | 44 | <ItemGroup> |
| @@ -46,10 +46,87 @@ | |||
| 46 | <PrecompiledHeader>Create</PrecompiledHeader> | 46 | <PrecompiledHeader>Create</PrecompiledHeader> |
| 47 | </ClCompile> | 47 | </ClCompile> |
| 48 | <ClCompile Include="iisca.cpp" /> | 48 | <ClCompile Include="iisca.cpp" /> |
| 49 | <ClCompile Include="scaapppool.cpp" /> | ||
| 50 | <ClCompile Include="scaapppool7.cpp" /> | ||
| 51 | <ClCompile Include="scacert.cpp" /> | ||
| 52 | <ClCompile Include="scacertexec.cpp" /> | ||
| 53 | <ClCompile Include="scaexec.cpp" /> | ||
| 54 | <ClCompile Include="scaexecIIS7.cpp" /> | ||
| 55 | <ClCompile Include="scafilter.cpp" /> | ||
| 56 | <ClCompile Include="scafilter7.cpp" /> | ||
| 57 | <ClCompile Include="scahttpheader.cpp" /> | ||
| 58 | <ClCompile Include="scahttpheader7.cpp" /> | ||
| 59 | <ClCompile Include="scaiis.cpp" /> | ||
| 60 | <ClCompile Include="scaiis7.cpp" /> | ||
| 61 | <ClCompile Include="scamimemap.cpp" /> | ||
| 62 | <ClCompile Include="scamimemap7.cpp" /> | ||
| 63 | <ClCompile Include="scaproperty.cpp" /> | ||
| 64 | <ClCompile Include="scaproperty7.cpp" /> | ||
| 65 | <ClCompile Include="scasched.cpp" /> | ||
| 66 | <ClCompile Include="scassl.cpp" /> | ||
| 67 | <ClCompile Include="scassl7.cpp" /> | ||
| 68 | <ClCompile Include="scauser.cpp" /> | ||
| 69 | <ClCompile Include="scavdir.cpp" /> | ||
| 70 | <ClCompile Include="scavdir7.cpp" /> | ||
| 71 | <ClCompile Include="scaweb.cpp" /> | ||
| 72 | <ClCompile Include="scaweb7.cpp" /> | ||
| 73 | <ClCompile Include="scawebapp.cpp" /> | ||
| 74 | <ClCompile Include="scawebapp7.cpp" /> | ||
| 75 | <ClCompile Include="scawebappext.cpp" /> | ||
| 76 | <ClCompile Include="scawebappext7.cpp" /> | ||
| 77 | <ClCompile Include="scawebdir.cpp" /> | ||
| 78 | <ClCompile Include="scawebdir7.cpp" /> | ||
| 79 | <ClCompile Include="scaweberr.cpp" /> | ||
| 80 | <ClCompile Include="scaweberr7.cpp" /> | ||
| 81 | <ClCompile Include="scaweblog.cpp" /> | ||
| 82 | <ClCompile Include="scaweblog7.cpp" /> | ||
| 83 | <ClCompile Include="scawebprop.cpp" /> | ||
| 84 | <ClCompile Include="scawebprop7.cpp" /> | ||
| 85 | <ClCompile Include="scawebsvcext.cpp" /> | ||
| 86 | <ClCompile Include="scawebsvcext7.cpp" /> | ||
| 49 | </ItemGroup> | 87 | </ItemGroup> |
| 50 | 88 | ||
| 51 | <ItemGroup> | 89 | <ItemGroup> |
| 90 | <ClInclude Include="caSuffix.h" /> | ||
| 91 | <ClInclude Include="CustomMsiErrors.h" /> | ||
| 52 | <ClInclude Include="precomp.h" /> | 92 | <ClInclude Include="precomp.h" /> |
| 93 | <ClInclude Include="sca.h" /> | ||
| 94 | <ClInclude Include="scaapppool.h" /> | ||
| 95 | <ClInclude Include="scaapppool7.h" /> | ||
| 96 | <ClInclude Include="scacert.h" /> | ||
| 97 | <ClInclude Include="scacost.h" /> | ||
| 98 | <ClInclude Include="scaexecIIS7.h" /> | ||
| 99 | <ClInclude Include="scafilter.h" /> | ||
| 100 | <ClInclude Include="scafilter7.h" /> | ||
| 101 | <ClInclude Include="scahttpheader.h" /> | ||
| 102 | <ClInclude Include="scahttpheader7.h" /> | ||
| 103 | <ClInclude Include="scaiis.h" /> | ||
| 104 | <ClInclude Include="scaiis7.h" /> | ||
| 105 | <ClInclude Include="scamimemap.h" /> | ||
| 106 | <ClInclude Include="scamimemap7.h" /> | ||
| 107 | <ClInclude Include="scaproperty.h" /> | ||
| 108 | <ClInclude Include="scaproperty7.h" /> | ||
| 109 | <ClInclude Include="scassl.h" /> | ||
| 110 | <ClInclude Include="scassl7.h" /> | ||
| 111 | <ClInclude Include="scauser.h" /> | ||
| 112 | <ClInclude Include="scavdir.h" /> | ||
| 113 | <ClInclude Include="scavdir7.h" /> | ||
| 114 | <ClInclude Include="scaweb.h" /> | ||
| 115 | <ClInclude Include="scaweb7.h" /> | ||
| 116 | <ClInclude Include="scawebapp.h" /> | ||
| 117 | <ClInclude Include="scawebapp7.h" /> | ||
| 118 | <ClInclude Include="scawebappext.h" /> | ||
| 119 | <ClInclude Include="scawebappext7.h" /> | ||
| 120 | <ClInclude Include="scawebdir.h" /> | ||
| 121 | <ClInclude Include="scawebdir7.h" /> | ||
| 122 | <ClInclude Include="scaweberr.h" /> | ||
| 123 | <ClInclude Include="scaweberr7.h" /> | ||
| 124 | <ClInclude Include="scaweblog.h" /> | ||
| 125 | <ClInclude Include="scaweblog7.h" /> | ||
| 126 | <ClInclude Include="scawebprop.h" /> | ||
| 127 | <ClInclude Include="scawebprop7.h" /> | ||
| 128 | <ClInclude Include="scawebsvcext.h" /> | ||
| 129 | <ClInclude Include="scawebsvcext7.h" /> | ||
| 53 | </ItemGroup> | 130 | </ItemGroup> |
| 54 | 131 | ||
| 55 | <ItemGroup> | 132 | <ItemGroup> |
diff --git a/src/ca/precomp.h b/src/ca/precomp.h index 3edad7ed..efddb5f2 100644 --- a/src/ca/precomp.h +++ b/src/ca/precomp.h | |||
| @@ -2,12 +2,66 @@ | |||
| 2 | // 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 | // 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. |
| 3 | 3 | ||
| 4 | 4 | ||
| 5 | #if _WIN32_MSI < 150 | ||
| 6 | #define _WIN32_MSI 150 | ||
| 7 | #endif | ||
| 8 | |||
| 5 | #include <windows.h> | 9 | #include <windows.h> |
| 6 | #include <msiquery.h> | 10 | #include <msiquery.h> |
| 11 | #include <msidefs.h> | ||
| 12 | #include <strsafe.h> | ||
| 13 | |||
| 14 | #include <lm.h> // NetApi32.lib | ||
| 15 | |||
| 16 | #include <Dsgetdc.h> | ||
| 17 | #include <ComAdmin.h> | ||
| 18 | #include <ahadmin.h> // IIS 7 config | ||
| 7 | 19 | ||
| 8 | #define MAXUINT USHRT_MAX | 20 | #define MAXUINT USHRT_MAX |
| 9 | #include <Setup.Configuration.h> | 21 | #include <Setup.Configuration.h> |
| 10 | 22 | ||
| 11 | #include "wcautil.h" | 23 | #include "wcautil.h" |
| 24 | #include "wcawow64.h" | ||
| 25 | #include "wcawrapquery.h" | ||
| 26 | |||
| 27 | #include "certutil.h" | ||
| 28 | #include "cryputil.h" | ||
| 12 | #include "fileutil.h" | 29 | #include "fileutil.h" |
| 30 | #include "iis7util.h" | ||
| 31 | #include "memutil.h" | ||
| 32 | #include "metautil.h" | ||
| 13 | #include "strutil.h" | 33 | #include "strutil.h" |
| 34 | #include "userutil.h" | ||
| 35 | #include "wiutil.h" | ||
| 36 | |||
| 37 | #include "CustomMsiErrors.h" | ||
| 38 | #include "sca.h" | ||
| 39 | #include "scacost.h" | ||
| 40 | #include "scacert.h" | ||
| 41 | #include "scafilter.h" | ||
| 42 | |||
| 43 | #include "scaiis.h" | ||
| 44 | #include "scaiis7.h" | ||
| 45 | #include "scaproperty.h" | ||
| 46 | #include "scaweb.h" | ||
| 47 | #include "scawebdir.h" | ||
| 48 | #include "scawebsvcext.h" | ||
| 49 | #include "scavdir.h" | ||
| 50 | #include "scaweb7.h" | ||
| 51 | #include "scaapppool7.h" | ||
| 52 | #include "scavdir7.h" | ||
| 53 | #include "scawebapp7.h" | ||
| 54 | #include "scawebappext7.h" | ||
| 55 | #include "scamimemap7.h" | ||
| 56 | #include "scawebprop7.h" | ||
| 57 | #include "scaweblog7.h" | ||
| 58 | #include "scafilter7.h" | ||
| 59 | #include "scahttpheader7.h" | ||
| 60 | #include "scaweberr7.h" | ||
| 61 | #include "scawebsvcext7.h" | ||
| 62 | #include "scaproperty7.h" | ||
| 63 | #include "scawebdir7.h" | ||
| 64 | #include "scassl7.h" | ||
| 65 | #include "scaexecIIS7.h" | ||
| 66 | |||
| 67 | #include "caSuffix.h" | ||
diff --git a/src/ca/sca.h b/src/ca/sca.h new file mode 100644 index 00000000..64567dcb --- /dev/null +++ b/src/ca/sca.h | |||
| @@ -0,0 +1,124 @@ | |||
| 1 | #pragma once | ||
| 2 | // 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. | ||
| 3 | |||
| 4 | |||
| 5 | #define MAGIC_MULTISZ_CHAR 127 | ||
| 6 | |||
| 7 | // Generic action enum. | ||
| 8 | enum SCA_ACTION | ||
| 9 | { | ||
| 10 | SCA_ACTION_NONE, | ||
| 11 | SCA_ACTION_INSTALL, | ||
| 12 | SCA_ACTION_UNINSTALL | ||
| 13 | }; | ||
| 14 | |||
| 15 | |||
| 16 | // IIS Metabase actions | ||
| 17 | enum METABASE_ACTION | ||
| 18 | { | ||
| 19 | MBA_UNKNOWNACTION = 0, | ||
| 20 | MBA_CREATEKEY, | ||
| 21 | MBA_DELETEKEY, | ||
| 22 | MBA_WRITEVALUE, | ||
| 23 | MBA_DELETEVALUE, | ||
| 24 | MBA_CREATEAPP, | ||
| 25 | MBA_DELETEAPP, | ||
| 26 | }; | ||
| 27 | |||
| 28 | // IIS 7 Config actions | ||
| 29 | enum IIS_CONFIG_ACTION | ||
| 30 | { | ||
| 31 | IIS_CREATE, | ||
| 32 | IIS_DELETE, | ||
| 33 | IIS_SITE, | ||
| 34 | IIS_APPLICATION, | ||
| 35 | IIS_APPPOOL, | ||
| 36 | IIS_APPPOOL_RECYCLE_MIN, | ||
| 37 | IIS_APPPOOL_RECYCLE_REQ, | ||
| 38 | IIS_APPPOOL_RECYCLE_TIMES, | ||
| 39 | IIS_APPPOOL_RECYCLE_VIRMEM, | ||
| 40 | IIS_APPPOOL_RECYCLE_PRIVMEM, | ||
| 41 | IIS_APPPOOL_RECYCLE_IDLTIMEOUT, | ||
| 42 | IIS_APPPOOL_RECYCLE_QUEUELIMIT, | ||
| 43 | IIS_APPPOOL_RECYCLE_CPU_PCT, | ||
| 44 | IIS_APPPOOL_RECYCLE_CPU_REFRESH, | ||
| 45 | IIS_APPPOOL_RECYCLE_CPU_ACTION, | ||
| 46 | IIS_APPPOOL_MAXPROCESS, | ||
| 47 | IIS_APPPOOL_IDENTITY, | ||
| 48 | IIS_APPPOOL_USER, | ||
| 49 | IIS_APPPOOL_PWD, | ||
| 50 | IIS_APPPOOL_32BIT, | ||
| 51 | IIS_APPPOOL_MANAGED_PIPELINE_MODE, | ||
| 52 | IIS_APPPOOL_MANAGED_RUNTIME_VERSION, | ||
| 53 | IIS_APPPOOL_END, | ||
| 54 | IIS_APPEXT_BEGIN, | ||
| 55 | IIS_APPEXT, | ||
| 56 | IIS_APPEXT_END, | ||
| 57 | IIS_VDIR, | ||
| 58 | IIS_BINDING, | ||
| 59 | IIS_MIMEMAP_BEGIN, | ||
| 60 | IIS_MIMEMAP, | ||
| 61 | IIS_MIMEMAP_END, | ||
| 62 | IIS_DIRPROP_BEGIN, | ||
| 63 | IIS_DIRPROP_ACCESS, | ||
| 64 | IIS_DIRPROP_AUTH, | ||
| 65 | IIS_DIRPROP_USER, | ||
| 66 | IIS_DIRPROP_PWD, | ||
| 67 | IIS_DIRPROP_PWDCTRL, | ||
| 68 | IIS_DIRPROP_LOG, | ||
| 69 | IIS_DIRPROP_DEFDOCS, | ||
| 70 | IIS_DIRPROP_SSLFLAGS, | ||
| 71 | IIS_DIRPROP_AUTHPROVID, | ||
| 72 | IIS_DIRPROP_ASPERROR, | ||
| 73 | IIS_DIRPROP_HTTPEXPIRES, | ||
| 74 | IIS_DIRPROP_MAXAGE, | ||
| 75 | IIS_DIRPROP_CACHECUST, | ||
| 76 | IIS_DIRPROP_NOCUSTERROR, | ||
| 77 | IIS_DIRPROP_LOGVISITS, | ||
| 78 | IIS_DIRPROP_END, | ||
| 79 | IIS_WEBLOG, | ||
| 80 | IIS_FILTER_BEGIN, | ||
| 81 | IIS_FILTER_GLOBAL_BEGIN, | ||
| 82 | IIS_FILTER, | ||
| 83 | IIS_FILTER_END, | ||
| 84 | IIS_HTTP_HEADER_BEGIN, | ||
| 85 | IIS_HTTP_HEADER, | ||
| 86 | IIS_HTTP_HEADER_END, | ||
| 87 | IIS_WEBERROR_BEGIN, | ||
| 88 | IIS_WEBERROR, | ||
| 89 | IIS_WEBERROR_END, | ||
| 90 | IIS_WEB_SVC_EXT, | ||
| 91 | IIS_PROPERTY, | ||
| 92 | IIS_PROPERTY_MAXBAND, | ||
| 93 | IIS_PROPERTY_LOGUTF8, | ||
| 94 | IIS_WEBDIR, | ||
| 95 | IIS_ASP_BEGIN, | ||
| 96 | IIS_ASP_SESSIONSTATE, | ||
| 97 | IIS_ASP_SESSIONTIMEOUT, | ||
| 98 | IIS_ASP_BUFFER, | ||
| 99 | IIS_ASP_PARENTPATHS, | ||
| 100 | IIS_ASP_SCRIPTLANG, | ||
| 101 | IIS_ASP_SCRIPTTIMEOUT, | ||
| 102 | IIS_ASP_SCRIPTSERVERDEBUG, | ||
| 103 | IIS_ASP_SCRIPTCLIENTDEBUG, | ||
| 104 | IIS_ASP_END, | ||
| 105 | IIS_SSL_BINDING | ||
| 106 | }; | ||
| 107 | |||
| 108 | |||
| 109 | // user creation attributes definitions | ||
| 110 | enum SCAU_ATTRIBUTES | ||
| 111 | { | ||
| 112 | SCAU_DONT_EXPIRE_PASSWRD = 0x00000001, | ||
| 113 | SCAU_PASSWD_CANT_CHANGE = 0x00000002, | ||
| 114 | SCAU_PASSWD_CHANGE_REQD_ON_LOGIN = 0x00000004, | ||
| 115 | SCAU_DISABLE_ACCOUNT = 0x00000008, | ||
| 116 | SCAU_FAIL_IF_EXISTS = 0x00000010, | ||
| 117 | SCAU_UPDATE_IF_EXISTS = 0x00000020, | ||
| 118 | SCAU_ALLOW_LOGON_AS_SERVICE = 0x00000040, | ||
| 119 | SCAU_ALLOW_LOGON_AS_BATCH = 0x00000080, | ||
| 120 | |||
| 121 | SCAU_DONT_REMOVE_ON_UNINSTALL = 0x00000100, | ||
| 122 | SCAU_DONT_CREATE_USER = 0x00000200, | ||
| 123 | SCAU_NON_VITAL = 0x00000400, | ||
| 124 | }; | ||
diff --git a/src/ca/scaapppool.cpp b/src/ca/scaapppool.cpp new file mode 100644 index 00000000..781c55ca --- /dev/null +++ b/src/ca/scaapppool.cpp | |||
| @@ -0,0 +1,594 @@ | |||
| 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 | #include "precomp.h" | ||
| 4 | |||
| 5 | /*------------------------------------------------------------------ | ||
| 6 | AppPool table: | ||
| 7 | |||
| 8 | Column Type Nullable Example Value | ||
| 9 | AppPool s72 No TestPool | ||
| 10 | Name s72 No "TestPool" | ||
| 11 | Component_ s72 No ComponentName | ||
| 12 | Attributes i2 No 8 (APATTR_OTHERUSER) | ||
| 13 | User_ s72 Yes UserKey | ||
| 14 | RecycleMinutes i2 Yes 500 | ||
| 15 | RecycleRequests i2 Yes 5000 | ||
| 16 | RecycleTimes s72 Yes "1:45,13:30,22:00" | ||
| 17 | IdleTimeout i2 Yes 15 | ||
| 18 | QueueLimit i2 Yes 500 | ||
| 19 | CPUMon s72 Yes "65,500,1" (65% CPU usage, 500 minutes, Shutdown Action) | ||
| 20 | MaxProc i2 Yes 5 | ||
| 21 | ManagedRuntimeVersion s72 Yes "v2.0" | ||
| 22 | ManagedPipelineMode s72 Yes "Integrated" | ||
| 23 | |||
| 24 | Notes: | ||
| 25 | RecycleTimes is a comma delimeted list of times. CPUMon is a | ||
| 26 | comma delimeted list of the following format: | ||
| 27 | <percent CPU usage>,<refress minutes>,<Action>. The values for | ||
| 28 | Action are 1 (Shutdown) and 0 (No Action). | ||
| 29 | |||
| 30 | ------------------------------------------------------------------*/ | ||
| 31 | |||
| 32 | enum eAppPoolQuery { apqAppPool = 1, apqName, apqComponent, apqAttributes, apqUser, apqRecycleMinutes, apqRecycleRequests, apqRecycleTimes, apqVirtualMemory, apqPrivateMemory, apqIdleTimeout, apqQueueLimit, apqCpuMon, apqMaxProc, apqManagedRuntimeVersion, apqManagedPipelineMode, apqInstalled, apqAction }; | ||
| 33 | |||
| 34 | enum eComponentAttrQuery { caqComponent = 1, caqAttributes }; | ||
| 35 | |||
| 36 | // prototypes | ||
| 37 | static HRESULT AppPoolExists( | ||
| 38 | __in IMSAdminBase* piMetabase, | ||
| 39 | __in LPCWSTR wzAppPool | ||
| 40 | ); | ||
| 41 | |||
| 42 | // functions | ||
| 43 | |||
| 44 | void ScaAppPoolFreeList( | ||
| 45 | __in SCA_APPPOOL* psapList | ||
| 46 | ) | ||
| 47 | { | ||
| 48 | SCA_APPPOOL* psapDelete = psapList; | ||
| 49 | while (psapList) | ||
| 50 | { | ||
| 51 | psapDelete = psapList; | ||
| 52 | psapList = psapList->psapNext; | ||
| 53 | |||
| 54 | MemFree(psapDelete); | ||
| 55 | } | ||
| 56 | } | ||
| 57 | |||
| 58 | |||
| 59 | HRESULT ScaAppPoolRead( | ||
| 60 | __inout SCA_APPPOOL** ppsapList, | ||
| 61 | __in WCA_WRAPQUERY_HANDLE hUserQuery, | ||
| 62 | __inout LPWSTR *ppwzCustomActionData | ||
| 63 | ) | ||
| 64 | { | ||
| 65 | Assert(ppsapList); | ||
| 66 | |||
| 67 | HRESULT hr = S_OK; | ||
| 68 | |||
| 69 | MSIHANDLE hRec, hRecComp; | ||
| 70 | LPWSTR pwzData = NULL; | ||
| 71 | SCA_APPPOOL* psap = NULL; | ||
| 72 | WCA_WRAPQUERY_HANDLE hAppPoolQuery = NULL; | ||
| 73 | WCA_WRAPQUERY_HANDLE hComponentQuery = NULL; | ||
| 74 | |||
| 75 | hr = WcaBeginUnwrapQuery(&hAppPoolQuery, ppwzCustomActionData); | ||
| 76 | ExitOnFailure(hr, "Failed to unwrap query for ScaAppPoolRead"); | ||
| 77 | |||
| 78 | if (0 == WcaGetQueryRecords(hAppPoolQuery)) | ||
| 79 | { | ||
| 80 | WcaLog(LOGMSG_VERBOSE, "Skipping ScaAppPoolRead() - required table not present"); | ||
| 81 | ExitFunction1(hr = S_FALSE); | ||
| 82 | } | ||
| 83 | |||
| 84 | hr = WcaBeginUnwrapQuery(&hComponentQuery, ppwzCustomActionData); | ||
| 85 | ExitOnFailure(hr, "Failed to unwrap query for ScaAppPoolRead"); | ||
| 86 | |||
| 87 | // loop through all the AppPools | ||
| 88 | while (S_OK == (hr = WcaFetchWrappedRecord(hAppPoolQuery, &hRec))) | ||
| 89 | { | ||
| 90 | // Add this record's information into the list of things to process. | ||
| 91 | hr = AddAppPoolToList(ppsapList); | ||
| 92 | ExitOnFailure(hr, "failed to add app pool to app pool list"); | ||
| 93 | |||
| 94 | psap = *ppsapList; | ||
| 95 | |||
| 96 | hr = WcaGetRecordString(hRec, apqComponent, &pwzData); | ||
| 97 | ExitOnFailure(hr, "failed to get AppPool.Component"); | ||
| 98 | |||
| 99 | if (pwzData && *pwzData) | ||
| 100 | { | ||
| 101 | psap->fHasComponent = TRUE; | ||
| 102 | |||
| 103 | hr = ::StringCchCopyW(psap->wzComponent, countof(psap->wzComponent), pwzData); | ||
| 104 | ExitOnFailure(hr, "failed to copy component name: %ls", pwzData); | ||
| 105 | |||
| 106 | hr = WcaGetRecordInteger(hRec, apqInstalled, (int *)&psap->isInstalled); | ||
| 107 | ExitOnFailure(hr, "Failed to get Component installed state for app pool"); | ||
| 108 | |||
| 109 | hr = WcaGetRecordInteger(hRec, apqAction, (int *)&psap->isAction); | ||
| 110 | ExitOnFailure(hr, "Failed to get Component action state for app pool"); | ||
| 111 | |||
| 112 | WcaFetchWrappedReset(hComponentQuery); | ||
| 113 | hr = WcaFetchWrappedRecordWhereString(hComponentQuery, caqComponent, psap->wzComponent, &hRecComp); | ||
| 114 | ExitOnFailure(hr, "Failed to fetch Component.Attributes for Component '%ls'", psap->wzComponent); | ||
| 115 | |||
| 116 | hr = WcaGetRecordInteger(hRecComp, caqAttributes, &psap->iCompAttributes); | ||
| 117 | ExitOnFailure(hr, "failed to get Component.Attributes"); | ||
| 118 | } | ||
| 119 | |||
| 120 | hr = WcaGetRecordString(hRec, apqAppPool, &pwzData); | ||
| 121 | ExitOnFailure(hr, "failed to get AppPool.AppPool"); | ||
| 122 | hr = ::StringCchCopyW(psap->wzAppPool, countof(psap->wzAppPool), pwzData); | ||
| 123 | ExitOnFailure(hr, "failed to copy AppPool name: %ls", pwzData); | ||
| 124 | |||
| 125 | hr = WcaGetRecordString(hRec, apqName, &pwzData); | ||
| 126 | ExitOnFailure(hr, "failed to get AppPool.Name"); | ||
| 127 | hr = ::StringCchCopyW(psap->wzName, countof(psap->wzName), pwzData); | ||
| 128 | ExitOnFailure(hr, "failed to copy app pool name: %ls", pwzData); | ||
| 129 | hr = ::StringCchPrintfW(psap->wzKey, countof(psap->wzKey), L"/LM/W3SVC/AppPools/%s", pwzData); | ||
| 130 | ExitOnFailure(hr, "failed to format app pool key name"); | ||
| 131 | |||
| 132 | hr = WcaGetRecordInteger(hRec, apqAttributes, &psap->iAttributes); | ||
| 133 | ExitOnFailure(hr, "failed to get AppPool.Attributes"); | ||
| 134 | |||
| 135 | hr = WcaGetRecordString(hRec, apqUser, &pwzData); | ||
| 136 | ExitOnFailure(hr, "failed to get AppPool.User"); | ||
| 137 | hr = ScaGetUserDeferred(pwzData, hUserQuery, &psap->suUser); | ||
| 138 | ExitOnFailure(hr, "failed to get user: %ls", pwzData); | ||
| 139 | |||
| 140 | hr = WcaGetRecordInteger(hRec, apqRecycleRequests, &psap->iRecycleRequests); | ||
| 141 | ExitOnFailure(hr, "failed to get AppPool.RecycleRequests"); | ||
| 142 | |||
| 143 | hr = WcaGetRecordInteger(hRec, apqRecycleMinutes, &psap->iRecycleMinutes); | ||
| 144 | ExitOnFailure(hr, "failed to get AppPool.Minutes"); | ||
| 145 | |||
| 146 | hr = WcaGetRecordString(hRec, apqRecycleTimes, &pwzData); | ||
| 147 | ExitOnFailure(hr, "failed to get AppPool.RecycleTimes"); | ||
| 148 | hr = ::StringCchCopyW(psap->wzRecycleTimes, countof(psap->wzRecycleTimes), pwzData); | ||
| 149 | ExitOnFailure(hr, "failed to copy recycle value: %ls", pwzData); | ||
| 150 | |||
| 151 | hr = WcaGetRecordInteger(hRec, apqVirtualMemory, &psap->iVirtualMemory); | ||
| 152 | ExitOnFailure(hr, "failed to get AppPool.VirtualMemory"); | ||
| 153 | |||
| 154 | hr = WcaGetRecordInteger(hRec, apqPrivateMemory, &psap->iPrivateMemory); | ||
| 155 | ExitOnFailure(hr, "failed to get AppPool.PrivateMemory"); | ||
| 156 | |||
| 157 | hr = WcaGetRecordInteger(hRec, apqIdleTimeout, &psap->iIdleTimeout); | ||
| 158 | ExitOnFailure(hr, "failed to get AppPool.IdleTimeout"); | ||
| 159 | |||
| 160 | hr = WcaGetRecordInteger(hRec, apqQueueLimit, &psap->iQueueLimit); | ||
| 161 | ExitOnFailure(hr, "failed to get AppPool.QueueLimit"); | ||
| 162 | |||
| 163 | hr = WcaGetRecordString(hRec, apqCpuMon, &pwzData); | ||
| 164 | ExitOnFailure(hr, "failed to get AppPool.CPUMon"); | ||
| 165 | hr = ::StringCchCopyW(psap->wzCpuMon, countof(psap->wzCpuMon), pwzData); | ||
| 166 | ExitOnFailure(hr, "failed to copy cpu monitor value: %ls", pwzData); | ||
| 167 | |||
| 168 | hr = WcaGetRecordInteger(hRec, apqMaxProc, &psap->iMaxProcesses); | ||
| 169 | ExitOnFailure(hr, "failed to get AppPool.MaxProc"); | ||
| 170 | |||
| 171 | hr = WcaGetRecordString(hRec, apqManagedRuntimeVersion, &pwzData); | ||
| 172 | ExitOnFailure(hr, "failed to get AppPool.ManagedRuntimeVersion"); | ||
| 173 | hr = ::StringCchCopyW(psap->wzManagedRuntimeVersion, countof(psap->wzManagedRuntimeVersion), pwzData); | ||
| 174 | ExitOnFailure(hr, "failed to copy ManagedRuntimeVersion value: %ls", pwzData); | ||
| 175 | |||
| 176 | hr = WcaGetRecordString(hRec, apqManagedPipelineMode, &pwzData); | ||
| 177 | ExitOnFailure(hr, "failed to get AppPool.ManagedPipelineMode"); | ||
| 178 | hr = ::StringCchCopyW(psap->wzManagedPipelineMode, countof(psap->wzManagedPipelineMode), pwzData); | ||
| 179 | ExitOnFailure(hr, "failed to copy ManagedPipelineMode value: %ls", pwzData); | ||
| 180 | |||
| 181 | } | ||
| 182 | |||
| 183 | if (E_NOMOREITEMS == hr) | ||
| 184 | { | ||
| 185 | hr = S_OK; | ||
| 186 | } | ||
| 187 | ExitOnFailure(hr, "failure while processing AppPools"); | ||
| 188 | |||
| 189 | LExit: | ||
| 190 | WcaFinishUnwrapQuery(hAppPoolQuery); | ||
| 191 | WcaFinishUnwrapQuery(hComponentQuery); | ||
| 192 | |||
| 193 | ReleaseStr(pwzData); | ||
| 194 | return hr; | ||
| 195 | } | ||
| 196 | |||
| 197 | |||
| 198 | HRESULT ScaFindAppPool( | ||
| 199 | __in IMSAdminBase* piMetabase, | ||
| 200 | __in LPCWSTR wzAppPool, | ||
| 201 | __out_ecount(cchName) LPWSTR wzName, | ||
| 202 | __in DWORD cchName, | ||
| 203 | __in SCA_APPPOOL *psapList | ||
| 204 | ) | ||
| 205 | { | ||
| 206 | Assert(piMetabase && wzAppPool && *wzAppPool && wzName && *wzName); | ||
| 207 | |||
| 208 | HRESULT hr = S_OK; | ||
| 209 | |||
| 210 | // check memory first | ||
| 211 | SCA_APPPOOL* psap = psapList; | ||
| 212 | for (; psap; psap = psap->psapNext) | ||
| 213 | { | ||
| 214 | if (0 == lstrcmpW(psap->wzAppPool, wzAppPool)) | ||
| 215 | { | ||
| 216 | break; | ||
| 217 | } | ||
| 218 | } | ||
| 219 | ExitOnNull(psap, hr, HRESULT_FROM_WIN32(ERROR_NOT_FOUND), "Could not find the app pool: %ls", wzAppPool); | ||
| 220 | |||
| 221 | // copy the web app pool name | ||
| 222 | hr = ::StringCchCopyW(wzName, cchName, psap->wzName); | ||
| 223 | ExitOnFailure(hr, "failed to copy app pool name while finding app pool: %ls", psap->wzName); | ||
| 224 | |||
| 225 | // if it's not being installed now, check if it exists already | ||
| 226 | if (!psap->fHasComponent) | ||
| 227 | { | ||
| 228 | hr = AppPoolExists(piMetabase, psap->wzName); | ||
| 229 | ExitOnFailure(hr, "failed to check for existence of app pool: %ls", psap->wzName); | ||
| 230 | } | ||
| 231 | |||
| 232 | LExit: | ||
| 233 | return hr; | ||
| 234 | } | ||
| 235 | |||
| 236 | |||
| 237 | static HRESULT AppPoolExists( | ||
| 238 | __in IMSAdminBase* piMetabase, | ||
| 239 | __in LPCWSTR wzAppPool | ||
| 240 | ) | ||
| 241 | { | ||
| 242 | Assert(piMetabase && wzAppPool && *wzAppPool); | ||
| 243 | |||
| 244 | HRESULT hr = S_OK; | ||
| 245 | WCHAR wzSubKey[METADATA_MAX_NAME_LEN]; | ||
| 246 | |||
| 247 | for (DWORD dwIndex = 0; SUCCEEDED(hr); ++dwIndex) | ||
| 248 | { | ||
| 249 | hr = piMetabase->EnumKeys(METADATA_MASTER_ROOT_HANDLE, L"/LM/W3SVC/AppPools", wzSubKey, dwIndex); | ||
| 250 | if (SUCCEEDED(hr) && 0 == lstrcmpW(wzSubKey, wzAppPool)) | ||
| 251 | { | ||
| 252 | hr = S_OK; | ||
| 253 | break; | ||
| 254 | } | ||
| 255 | } | ||
| 256 | |||
| 257 | if (E_NOMOREITEMS == hr || HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) == hr || HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr) | ||
| 258 | { | ||
| 259 | hr = S_FALSE; | ||
| 260 | } | ||
| 261 | |||
| 262 | return hr; | ||
| 263 | } | ||
| 264 | |||
| 265 | |||
| 266 | HRESULT ScaAppPoolInstall( | ||
| 267 | __in IMSAdminBase* piMetabase, | ||
| 268 | __in SCA_APPPOOL* psapList | ||
| 269 | ) | ||
| 270 | { | ||
| 271 | Assert(piMetabase); | ||
| 272 | |||
| 273 | HRESULT hr = S_OK; | ||
| 274 | |||
| 275 | for (SCA_APPPOOL* psap = psapList; psap; psap = psap->psapNext) | ||
| 276 | { | ||
| 277 | // if we are installing the app pool | ||
| 278 | if (psap->fHasComponent && WcaIsInstalling(psap->isInstalled, psap->isAction)) | ||
| 279 | { | ||
| 280 | hr = ScaWriteAppPool(piMetabase, psap); | ||
| 281 | ExitOnFailure(hr, "failed to write AppPool '%ls' to metabase", psap->wzAppPool); | ||
| 282 | } | ||
| 283 | } | ||
| 284 | |||
| 285 | LExit: | ||
| 286 | return hr; | ||
| 287 | } | ||
| 288 | |||
| 289 | |||
| 290 | HRESULT ScaAppPoolUninstall( | ||
| 291 | __in IMSAdminBase* piMetabase, | ||
| 292 | __in SCA_APPPOOL* psapList | ||
| 293 | ) | ||
| 294 | { | ||
| 295 | Assert(piMetabase); | ||
| 296 | |||
| 297 | HRESULT hr = S_OK; | ||
| 298 | |||
| 299 | for (SCA_APPPOOL* psap = psapList; psap; psap = psap->psapNext) | ||
| 300 | { | ||
| 301 | // if we are uninstalling the app pool | ||
| 302 | if (psap->fHasComponent && WcaIsUninstalling(psap->isInstalled, psap->isAction)) | ||
| 303 | { | ||
| 304 | hr = ScaRemoveAppPool(piMetabase, psap); | ||
| 305 | ExitOnFailure(hr, "Failed to remove AppPool '%ls' from metabase", psap->wzAppPool); | ||
| 306 | } | ||
| 307 | } | ||
| 308 | |||
| 309 | LExit: | ||
| 310 | return hr; | ||
| 311 | } | ||
| 312 | |||
| 313 | |||
| 314 | HRESULT ScaWriteAppPool( | ||
| 315 | __in IMSAdminBase* piMetabase, | ||
| 316 | __in SCA_APPPOOL* psap | ||
| 317 | ) | ||
| 318 | { | ||
| 319 | Assert(piMetabase && psap); | ||
| 320 | |||
| 321 | HRESULT hr = S_OK; | ||
| 322 | DWORD dwIdentity = 0xFFFFFFFF; | ||
| 323 | BOOL fExists = FALSE; | ||
| 324 | LPWSTR pwzValue = NULL; | ||
| 325 | LPWSTR wz = NULL; | ||
| 326 | |||
| 327 | hr = AppPoolExists(piMetabase, psap->wzName); | ||
| 328 | ExitOnFailure(hr, "failed to check if app pool already exists"); | ||
| 329 | if (S_FALSE == hr) | ||
| 330 | { | ||
| 331 | // didn't find the AppPool key, so we need to create it | ||
| 332 | hr = ScaCreateMetabaseKey(piMetabase, psap->wzKey, L""); | ||
| 333 | ExitOnFailure(hr, "failed to create AppPool key: %ls", psap->wzKey); | ||
| 334 | |||
| 335 | // mark it as an AppPool | ||
| 336 | hr = ScaWriteMetabaseValue(piMetabase, psap->wzKey, NULL, MD_KEY_TYPE, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, (LPVOID)L"IIsApplicationPool"); | ||
| 337 | ExitOnFailure(hr, "failed to mark key as AppPool key: %ls", psap->wzKey); | ||
| 338 | |||
| 339 | // TODO: Make this an Attribute? | ||
| 340 | // set autostart value | ||
| 341 | hr = ScaWriteMetabaseValue(piMetabase, psap->wzKey, NULL, MD_APPPOOL_AUTO_START, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, (LPVOID)1); | ||
| 342 | ExitOnFailure(hr, "failed to mark key as AppPool key: %ls", psap->wzKey); | ||
| 343 | } | ||
| 344 | else | ||
| 345 | { | ||
| 346 | fExists = TRUE; | ||
| 347 | } | ||
| 348 | |||
| 349 | // | ||
| 350 | // Set the AppPool Recycling Tab | ||
| 351 | // | ||
| 352 | if (MSI_NULL_INTEGER != psap->iRecycleMinutes) | ||
| 353 | { | ||
| 354 | hr = ScaWriteMetabaseValue(piMetabase, psap->wzKey, NULL, MD_APPPOOL_PERIODIC_RESTART_TIME, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, (LPVOID)((DWORD_PTR)psap->iRecycleMinutes)); | ||
| 355 | ExitOnFailure(hr, "failed to set periodic restart time"); | ||
| 356 | } | ||
| 357 | |||
| 358 | if (MSI_NULL_INTEGER != psap->iRecycleRequests) | ||
| 359 | { | ||
| 360 | hr = ScaWriteMetabaseValue(piMetabase, psap->wzKey, NULL, MD_APPPOOL_PERIODIC_RESTART_REQUEST_COUNT, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, (LPVOID)((DWORD_PTR)psap->iRecycleRequests)); | ||
| 361 | ExitOnFailure(hr, "failed to set periodic restart request count"); | ||
| 362 | } | ||
| 363 | |||
| 364 | if (*psap->wzRecycleTimes) | ||
| 365 | { | ||
| 366 | // Add another NULL' onto pwz since it's a 'MULTISZ' | ||
| 367 | hr = StrAllocString(&pwzValue, psap->wzRecycleTimes, 0); | ||
| 368 | ExitOnFailure(hr, "failed to allocate string for MULTISZ"); | ||
| 369 | hr = StrAllocConcat(&pwzValue, L"\0", 1); | ||
| 370 | ExitOnFailure(hr, "failed to add second null to RecycleTime multisz"); | ||
| 371 | |||
| 372 | // Replace the commas with NULLs | ||
| 373 | wz = pwzValue; | ||
| 374 | while (NULL != (wz = wcschr(wz, L','))) | ||
| 375 | { | ||
| 376 | *wz = L'\0'; | ||
| 377 | ++wz; | ||
| 378 | } | ||
| 379 | |||
| 380 | hr = ScaWriteMetabaseValue(piMetabase, psap->wzKey, NULL, MD_APPPOOL_PERIODIC_RESTART_SCHEDULE, METADATA_INHERIT, IIS_MD_UT_SERVER, MULTISZ_METADATA, (LPVOID)pwzValue); | ||
| 381 | ExitOnFailure(hr, "failed to set periodic restart schedule"); | ||
| 382 | } | ||
| 383 | |||
| 384 | if (MSI_NULL_INTEGER != psap->iVirtualMemory) | ||
| 385 | { | ||
| 386 | hr = ScaWriteMetabaseValue(piMetabase, psap->wzKey, NULL, MD_APPPOOL_PERIODIC_RESTART_MEMORY, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, (LPVOID)((DWORD_PTR)psap->iVirtualMemory)); | ||
| 387 | ExitOnFailure(hr, "failed to set periodic restart memory count"); | ||
| 388 | } | ||
| 389 | |||
| 390 | if (MSI_NULL_INTEGER != psap->iPrivateMemory) | ||
| 391 | { | ||
| 392 | hr = ScaWriteMetabaseValue(piMetabase, psap->wzKey, NULL, MD_APPPOOL_PERIODIC_RESTART_PRIVATE_MEMORY, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, (LPVOID)((DWORD_PTR)psap->iPrivateMemory)); | ||
| 393 | ExitOnFailure(hr, "failed to set periodic restart private memory count"); | ||
| 394 | } | ||
| 395 | |||
| 396 | |||
| 397 | // | ||
| 398 | // Set AppPool Performance Tab | ||
| 399 | // | ||
| 400 | if (MSI_NULL_INTEGER != psap->iIdleTimeout) | ||
| 401 | { | ||
| 402 | hr = ScaWriteMetabaseValue(piMetabase, psap->wzKey, NULL, MD_APPPOOL_IDLE_TIMEOUT, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, (LPVOID)((DWORD_PTR)psap->iIdleTimeout)); | ||
| 403 | ExitOnFailure(hr, "failed to set idle timeout value"); | ||
| 404 | } | ||
| 405 | |||
| 406 | if (MSI_NULL_INTEGER != psap->iQueueLimit) | ||
| 407 | { | ||
| 408 | hr = ScaWriteMetabaseValue(piMetabase, psap->wzKey, NULL, MD_APPPOOL_UL_APPPOOL_QUEUE_LENGTH, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, (LPVOID)((DWORD_PTR)psap->iQueueLimit)); | ||
| 409 | ExitOnFailure(hr, "failed to set request queue limit value"); | ||
| 410 | } | ||
| 411 | |||
| 412 | if (*psap->wzCpuMon) | ||
| 413 | { | ||
| 414 | hr = StrAllocString(&pwzValue, psap->wzCpuMon, 0); | ||
| 415 | ExitOnFailure(hr, "failed to allocate CPUMonitor string"); | ||
| 416 | |||
| 417 | DWORD dwPercent = 0; | ||
| 418 | DWORD dwRefreshMinutes = 0; | ||
| 419 | DWORD dwAction = 0; | ||
| 420 | |||
| 421 | dwPercent = wcstoul(pwzValue, &wz, 10); | ||
| 422 | if (100 < dwPercent) | ||
| 423 | { | ||
| 424 | ExitOnFailure(hr = E_INVALIDARG, "invalid maximum cpu percentage value: %d", dwPercent); | ||
| 425 | } | ||
| 426 | if (wz && L',' == *wz) | ||
| 427 | { | ||
| 428 | ++wz; | ||
| 429 | dwRefreshMinutes = wcstoul(wz, &wz, 10); | ||
| 430 | if (wz && L',' == *wz) | ||
| 431 | { | ||
| 432 | ++wz; | ||
| 433 | dwAction = wcstoul(wz, &wz, 10); | ||
| 434 | } | ||
| 435 | } | ||
| 436 | |||
| 437 | if (dwPercent) | ||
| 438 | { | ||
| 439 | hr = ScaWriteMetabaseValue(piMetabase, psap->wzKey, NULL, MD_CPU_LIMIT, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, (LPVOID)((DWORD_PTR)(dwPercent * 1000))); | ||
| 440 | ExitOnFailure(hr, "failed to set CPU percentage max"); | ||
| 441 | } | ||
| 442 | if (dwRefreshMinutes) | ||
| 443 | { | ||
| 444 | hr = ScaWriteMetabaseValue(piMetabase, psap->wzKey, NULL, MD_CPU_RESET_INTERVAL, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, (LPVOID)((DWORD_PTR)dwRefreshMinutes)); | ||
| 445 | ExitOnFailure(hr, "failed to set refresh CPU minutes"); | ||
| 446 | } | ||
| 447 | if (dwAction) | ||
| 448 | { | ||
| 449 | // 0 = No Action | ||
| 450 | // 1 = Shutdown | ||
| 451 | hr = ScaWriteMetabaseValue(piMetabase, psap->wzKey, NULL, MD_CPU_ACTION, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, (LPVOID)((DWORD_PTR)dwAction)); | ||
| 452 | ExitOnFailure(hr, "failed to set CPU action"); | ||
| 453 | } | ||
| 454 | } | ||
| 455 | |||
| 456 | if (MSI_NULL_INTEGER != psap->iMaxProcesses) | ||
| 457 | { | ||
| 458 | hr = ScaWriteMetabaseValue(piMetabase, psap->wzKey, NULL, MD_APPPOOL_MAX_PROCESS_COUNT, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, (LPVOID)((DWORD_PTR)psap->iMaxProcesses)); | ||
| 459 | ExitOnFailure(hr, "failed to set web garden maximum worker processes"); | ||
| 460 | } | ||
| 461 | |||
| 462 | // TODO: Health Tab if anyone wants it? | ||
| 463 | |||
| 464 | // | ||
| 465 | // Set the AppPool Identity tab | ||
| 466 | // | ||
| 467 | if (psap->iAttributes & APATTR_NETSERVICE) | ||
| 468 | { | ||
| 469 | dwIdentity = MD_APPPOOL_IDENTITY_TYPE_NETWORKSERVICE; | ||
| 470 | } | ||
| 471 | else if (psap->iAttributes & APATTR_LOCSERVICE) | ||
| 472 | { | ||
| 473 | dwIdentity = MD_APPPOOL_IDENTITY_TYPE_LOCALSERVICE; | ||
| 474 | } | ||
| 475 | else if (psap->iAttributes & APATTR_LOCSYSTEM) | ||
| 476 | { | ||
| 477 | dwIdentity = MD_APPPOOL_IDENTITY_TYPE_LOCALSYSTEM; | ||
| 478 | } | ||
| 479 | else if (psap->iAttributes & APATTR_OTHERUSER) | ||
| 480 | { | ||
| 481 | if (!*psap->suUser.wzDomain || CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, psap->suUser.wzDomain, -1, L".", -1)) | ||
| 482 | { | ||
| 483 | if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, psap->suUser.wzName, -1, L"NetworkService", -1)) | ||
| 484 | { | ||
| 485 | dwIdentity = MD_APPPOOL_IDENTITY_TYPE_NETWORKSERVICE; | ||
| 486 | } | ||
| 487 | else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, psap->suUser.wzName, -1, L"LocalService", -1)) | ||
| 488 | { | ||
| 489 | dwIdentity = MD_APPPOOL_IDENTITY_TYPE_LOCALSERVICE; | ||
| 490 | } | ||
| 491 | else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, psap->suUser.wzName, -1, L"LocalSystem", -1)) | ||
| 492 | { | ||
| 493 | dwIdentity = MD_APPPOOL_IDENTITY_TYPE_LOCALSYSTEM; | ||
| 494 | } | ||
| 495 | else | ||
| 496 | { | ||
| 497 | dwIdentity = MD_APPPOOL_IDENTITY_TYPE_SPECIFICUSER; | ||
| 498 | } | ||
| 499 | } | ||
| 500 | else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, psap->suUser.wzDomain, -1, L"NT AUTHORITY", -1)) | ||
| 501 | { | ||
| 502 | if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, psap->suUser.wzName, -1, L"NETWORK SERVICE", -1)) | ||
| 503 | { | ||
| 504 | dwIdentity = MD_APPPOOL_IDENTITY_TYPE_NETWORKSERVICE; | ||
| 505 | } | ||
| 506 | else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, psap->suUser.wzName, -1, L"SERVICE", -1)) | ||
| 507 | { | ||
| 508 | dwIdentity = MD_APPPOOL_IDENTITY_TYPE_LOCALSERVICE; | ||
| 509 | } | ||
| 510 | else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, psap->suUser.wzName, -1, L"SYSTEM", -1)) | ||
| 511 | { | ||
| 512 | dwIdentity = MD_APPPOOL_IDENTITY_TYPE_LOCALSYSTEM; | ||
| 513 | } | ||
| 514 | else | ||
| 515 | { | ||
| 516 | dwIdentity = MD_APPPOOL_IDENTITY_TYPE_SPECIFICUSER; | ||
| 517 | } | ||
| 518 | } | ||
| 519 | else | ||
| 520 | { | ||
| 521 | dwIdentity = MD_APPPOOL_IDENTITY_TYPE_SPECIFICUSER; | ||
| 522 | } | ||
| 523 | } | ||
| 524 | |||
| 525 | if (-1 != dwIdentity) | ||
| 526 | { | ||
| 527 | hr = ScaWriteMetabaseValue(piMetabase, psap->wzKey, NULL, MD_APPPOOL_IDENTITY_TYPE, METADATA_INHERIT , IIS_MD_UT_SERVER, DWORD_METADATA, (LPVOID)((DWORD_PTR)dwIdentity)); | ||
| 528 | ExitOnFailure(hr, "failed to set app pool identity"); | ||
| 529 | |||
| 530 | if (MD_APPPOOL_IDENTITY_TYPE_SPECIFICUSER == dwIdentity) | ||
| 531 | { | ||
| 532 | if (*psap->suUser.wzDomain) | ||
| 533 | { | ||
| 534 | hr = StrAllocFormatted(&pwzValue, L"%s\\%s", psap->suUser.wzDomain, psap->suUser.wzName); | ||
| 535 | ExitOnFailure(hr, "failed to format user name: %ls domain: %ls", psap->suUser.wzName, psap->suUser.wzDomain); | ||
| 536 | } | ||
| 537 | else | ||
| 538 | { | ||
| 539 | hr = StrAllocFormatted(&pwzValue, L"%s", psap->suUser.wzName); | ||
| 540 | ExitOnFailure(hr, "failed to format user name: %ls", psap->suUser.wzName); | ||
| 541 | } | ||
| 542 | |||
| 543 | hr = ScaWriteMetabaseValue(piMetabase, psap->wzKey, NULL, MD_WAM_USER_NAME, METADATA_INHERIT , IIS_MD_UT_FILE, STRING_METADATA, (LPVOID)pwzValue); | ||
| 544 | ExitOnFailure(hr, "failed to set app pool identity name"); | ||
| 545 | |||
| 546 | hr = ScaWriteMetabaseValue(piMetabase, psap->wzKey, NULL, MD_WAM_PWD, METADATA_INHERIT | METADATA_SECURE, IIS_MD_UT_FILE, STRING_METADATA, (LPVOID)psap->suUser.wzPassword); | ||
| 547 | ExitOnFailure(hr, "failed to set app pool identity password"); | ||
| 548 | } | ||
| 549 | } | ||
| 550 | |||
| 551 | LExit: | ||
| 552 | ReleaseStr(pwzValue); | ||
| 553 | |||
| 554 | return hr; | ||
| 555 | } | ||
| 556 | |||
| 557 | |||
| 558 | HRESULT ScaRemoveAppPool( | ||
| 559 | __in IMSAdminBase* piMetabase, | ||
| 560 | __in SCA_APPPOOL* psap | ||
| 561 | ) | ||
| 562 | { | ||
| 563 | Assert(piMetabase && psap); | ||
| 564 | |||
| 565 | HRESULT hr = S_OK; | ||
| 566 | |||
| 567 | // simply remove the root key and everything else is pulled at the same time | ||
| 568 | if (0 != lstrlenW(psap->wzKey)) | ||
| 569 | { | ||
| 570 | hr = ScaDeleteMetabaseKey(piMetabase, psap->wzKey, L""); | ||
| 571 | ExitOnFailure(hr, "failed to delete AppPool key: %ls", psap->wzKey); | ||
| 572 | } | ||
| 573 | |||
| 574 | // TODO: Maybe check to make sure any web sites that are using this AppPool are put back in the 'DefaultAppPool' | ||
| 575 | |||
| 576 | LExit: | ||
| 577 | return hr; | ||
| 578 | } | ||
| 579 | |||
| 580 | |||
| 581 | HRESULT AddAppPoolToList( | ||
| 582 | __in SCA_APPPOOL** ppsapList | ||
| 583 | ) | ||
| 584 | { | ||
| 585 | HRESULT hr = S_OK; | ||
| 586 | SCA_APPPOOL* psap = static_cast<SCA_APPPOOL*>(MemAlloc(sizeof(SCA_APPPOOL), TRUE)); | ||
| 587 | ExitOnNull(psap, hr, E_OUTOFMEMORY, "failed to allocate memory for new element in app pool list"); | ||
| 588 | |||
| 589 | psap->psapNext = *ppsapList; | ||
| 590 | *ppsapList = psap; | ||
| 591 | |||
| 592 | LExit: | ||
| 593 | return hr; | ||
| 594 | } | ||
diff --git a/src/ca/scaapppool.h b/src/ca/scaapppool.h new file mode 100644 index 00000000..68575fcb --- /dev/null +++ b/src/ca/scaapppool.h | |||
| @@ -0,0 +1,88 @@ | |||
| 1 | #pragma once | ||
| 2 | // 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. | ||
| 3 | |||
| 4 | |||
| 5 | #include "scauser.h" | ||
| 6 | |||
| 7 | // Identity | ||
| 8 | #define APATTR_NETSERVICE 0x0001 // Network Service | ||
| 9 | #define APATTR_LOCSERVICE 0x0002 // Local Service | ||
| 10 | #define APATTR_LOCSYSTEM 0x0004 // Local System | ||
| 11 | #define APATTR_OTHERUSER 0x0008 // Other User | ||
| 12 | |||
| 13 | struct SCA_APPPOOL | ||
| 14 | { | ||
| 15 | // iis app pool configuation information | ||
| 16 | WCHAR wzAppPool[MAX_DARWIN_KEY + 1]; | ||
| 17 | WCHAR wzName[METADATA_MAX_NAME_LEN + 1]; | ||
| 18 | WCHAR wzKey[METADATA_MAX_NAME_LEN + 1]; | ||
| 19 | WCHAR wzComponent[METADATA_MAX_NAME_LEN + 1]; | ||
| 20 | BOOL fHasComponent; | ||
| 21 | INSTALLSTATE isInstalled; | ||
| 22 | INSTALLSTATE isAction; | ||
| 23 | INT iAttributes; | ||
| 24 | |||
| 25 | SCA_USER suUser; | ||
| 26 | |||
| 27 | INT iRecycleRequests; | ||
| 28 | INT iRecycleMinutes; | ||
| 29 | WCHAR wzRecycleTimes[MAX_DARWIN_KEY + 1]; | ||
| 30 | INT iVirtualMemory; | ||
| 31 | INT iPrivateMemory; | ||
| 32 | |||
| 33 | INT iIdleTimeout; | ||
| 34 | INT iQueueLimit; | ||
| 35 | WCHAR wzCpuMon[MAX_DARWIN_KEY + 1]; | ||
| 36 | INT iMaxProcesses; | ||
| 37 | WCHAR wzManagedPipelineMode[MAX_DARWIN_KEY + 1]; | ||
| 38 | WCHAR wzManagedRuntimeVersion[MAX_DARWIN_KEY + 1]; | ||
| 39 | |||
| 40 | int iCompAttributes; | ||
| 41 | |||
| 42 | SCA_APPPOOL *psapNext; | ||
| 43 | }; | ||
| 44 | |||
| 45 | |||
| 46 | // prototypes | ||
| 47 | |||
| 48 | HRESULT ScaAppPoolRead( | ||
| 49 | __inout SCA_APPPOOL** ppsapList, | ||
| 50 | __in WCA_WRAPQUERY_HANDLE hUserQuery, | ||
| 51 | __inout LPWSTR *ppwzCustomActionData | ||
| 52 | ); | ||
| 53 | |||
| 54 | void ScaAppPoolFreeList( | ||
| 55 | __in SCA_APPPOOL* psapList | ||
| 56 | ); | ||
| 57 | |||
| 58 | HRESULT ScaFindAppPool( | ||
| 59 | __in IMSAdminBase* piMetabase, | ||
| 60 | __in LPCWSTR wzAppPool, | ||
| 61 | __out_ecount(cchName) LPWSTR wzName, | ||
| 62 | __in DWORD cchName, | ||
| 63 | __in SCA_APPPOOL *psapList | ||
| 64 | ); | ||
| 65 | |||
| 66 | HRESULT ScaAppPoolInstall( | ||
| 67 | __in IMSAdminBase* piMetabase, | ||
| 68 | __in SCA_APPPOOL* psapList | ||
| 69 | ); | ||
| 70 | |||
| 71 | HRESULT ScaAppPoolUninstall( | ||
| 72 | __in IMSAdminBase* piMetabase, | ||
| 73 | __in SCA_APPPOOL* psapList | ||
| 74 | ); | ||
| 75 | |||
| 76 | HRESULT ScaWriteAppPool( | ||
| 77 | __in IMSAdminBase* piMetabase, | ||
| 78 | __in SCA_APPPOOL* psap | ||
| 79 | ); | ||
| 80 | |||
| 81 | HRESULT ScaRemoveAppPool( | ||
| 82 | __in IMSAdminBase* piMetabase, | ||
| 83 | __in SCA_APPPOOL* psap | ||
| 84 | ); | ||
| 85 | |||
| 86 | HRESULT AddAppPoolToList( | ||
| 87 | __in SCA_APPPOOL** ppsapList | ||
| 88 | ); | ||
diff --git a/src/ca/scaapppool7.cpp b/src/ca/scaapppool7.cpp new file mode 100644 index 00000000..0fac4346 --- /dev/null +++ b/src/ca/scaapppool7.cpp | |||
| @@ -0,0 +1,401 @@ | |||
| 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 | #include "precomp.h" | ||
| 4 | |||
| 5 | // prototypes | ||
| 6 | static HRESULT AppPoolExists( | ||
| 7 | __in LPCWSTR wzAppPool | ||
| 8 | ); | ||
| 9 | |||
| 10 | // functions | ||
| 11 | HRESULT ScaFindAppPool7( | ||
| 12 | __in LPCWSTR wzAppPool, | ||
| 13 | __out_ecount(cchName) LPWSTR wzName, | ||
| 14 | __in DWORD cchName, | ||
| 15 | __in SCA_APPPOOL *psapList | ||
| 16 | ) | ||
| 17 | { | ||
| 18 | Assert(wzAppPool && *wzAppPool && wzName && *wzName); | ||
| 19 | |||
| 20 | HRESULT hr = S_OK; | ||
| 21 | |||
| 22 | // check memory first | ||
| 23 | SCA_APPPOOL* psap = psapList; | ||
| 24 | for (; psap; psap = psap->psapNext) | ||
| 25 | { | ||
| 26 | if (0 == wcscmp(psap->wzAppPool, wzAppPool)) | ||
| 27 | { | ||
| 28 | break; | ||
| 29 | } | ||
| 30 | } | ||
| 31 | ExitOnNull(psap, hr, HRESULT_FROM_WIN32(ERROR_NOT_FOUND), "Could not find the app pool: %ls", wzAppPool); | ||
| 32 | |||
| 33 | // copy the web app pool name | ||
| 34 | #pragma prefast(suppress:26037, "Source string is null terminated - it is populated as target of ::StringCchCopyW") | ||
| 35 | hr = ::StringCchCopyW(wzName, cchName, psap->wzName); | ||
| 36 | ExitOnFailure(hr, "failed to copy app pool name while finding app pool: %ls", psap->wzName); | ||
| 37 | |||
| 38 | // if it's not being installed now, check if it exists already | ||
| 39 | if (!psap->fHasComponent) | ||
| 40 | { | ||
| 41 | hr = AppPoolExists(psap->wzName); | ||
| 42 | ExitOnFailure(hr, "failed to check for existence of app pool: %ls", psap->wzName); | ||
| 43 | } | ||
| 44 | |||
| 45 | LExit: | ||
| 46 | return hr; | ||
| 47 | } | ||
| 48 | |||
| 49 | |||
| 50 | static HRESULT AppPoolExists( | ||
| 51 | __in LPCWSTR /*wzAppPool*/ | ||
| 52 | ) | ||
| 53 | { | ||
| 54 | HRESULT hr = S_OK; | ||
| 55 | |||
| 56 | //this function checks for existance of app pool in IIS7 config | ||
| 57 | //at schedule time, we will defer this to execute time. | ||
| 58 | |||
| 59 | return hr; | ||
| 60 | } | ||
| 61 | |||
| 62 | |||
| 63 | HRESULT ScaAppPoolInstall7( | ||
| 64 | __in SCA_APPPOOL* psapList | ||
| 65 | ) | ||
| 66 | { | ||
| 67 | HRESULT hr = S_OK; | ||
| 68 | |||
| 69 | for (SCA_APPPOOL* psap = psapList; psap; psap = psap->psapNext) | ||
| 70 | { | ||
| 71 | // if we are installing the app pool | ||
| 72 | if (psap->fHasComponent && WcaIsInstalling(psap->isInstalled, psap->isAction)) | ||
| 73 | { | ||
| 74 | hr = ScaWriteAppPool7(psap); | ||
| 75 | ExitOnFailure(hr, "failed to write AppPool '%ls' to metabase", psap->wzAppPool); | ||
| 76 | } | ||
| 77 | } | ||
| 78 | |||
| 79 | LExit: | ||
| 80 | return hr; | ||
| 81 | } | ||
| 82 | |||
| 83 | |||
| 84 | HRESULT ScaAppPoolUninstall7( | ||
| 85 | __in SCA_APPPOOL* psapList | ||
| 86 | ) | ||
| 87 | { | ||
| 88 | |||
| 89 | HRESULT hr = S_OK; | ||
| 90 | |||
| 91 | for (SCA_APPPOOL* psap = psapList; psap; psap = psap->psapNext) | ||
| 92 | { | ||
| 93 | // if we are uninstalling the app pool | ||
| 94 | if (psap->fHasComponent && WcaIsUninstalling(psap->isInstalled, psap->isAction)) | ||
| 95 | { | ||
| 96 | hr = ScaRemoveAppPool7(psap); | ||
| 97 | ExitOnFailure(hr, "Failed to remove AppPool '%ls' from metabase", psap->wzAppPool); | ||
| 98 | } | ||
| 99 | } | ||
| 100 | |||
| 101 | LExit: | ||
| 102 | return hr; | ||
| 103 | } | ||
| 104 | |||
| 105 | |||
| 106 | HRESULT ScaWriteAppPool7( | ||
| 107 | __in const SCA_APPPOOL* psap | ||
| 108 | ) | ||
| 109 | { | ||
| 110 | Assert(psap); | ||
| 111 | |||
| 112 | HRESULT hr = S_OK; | ||
| 113 | DWORD dwIdentity = 0xFFFFFFFF; | ||
| 114 | LPWSTR pwzValue = NULL; | ||
| 115 | LPWSTR wz = NULL; | ||
| 116 | |||
| 117 | //create the app pool | ||
| 118 | hr = ScaWriteConfigID(IIS_APPPOOL); | ||
| 119 | ExitOnFailure(hr, "failed to write AppPool key."); | ||
| 120 | |||
| 121 | hr = ScaWriteConfigID(IIS_CREATE); | ||
| 122 | ExitOnFailure(hr, "failed to write AppPool create action."); | ||
| 123 | |||
| 124 | hr = ScaWriteConfigString(psap->wzName); | ||
| 125 | ExitOnFailure(hr, "failed to write AppPool name: %ls", psap->wzName); | ||
| 126 | |||
| 127 | // Now do all the optional stuff | ||
| 128 | |||
| 129 | // Set the AppPool Recycling Tab | ||
| 130 | if (MSI_NULL_INTEGER != psap->iRecycleMinutes) | ||
| 131 | { | ||
| 132 | hr = ScaWriteConfigID(IIS_APPPOOL_RECYCLE_MIN); | ||
| 133 | ExitOnFailure(hr, "failed to set periodic restart time id"); | ||
| 134 | hr = ScaWriteConfigInteger(psap->iRecycleMinutes); | ||
| 135 | ExitOnFailure(hr, "failed to set periodic restart time"); | ||
| 136 | } | ||
| 137 | |||
| 138 | if (MSI_NULL_INTEGER != psap->iRecycleRequests) | ||
| 139 | { | ||
| 140 | hr = ScaWriteConfigID(IIS_APPPOOL_RECYCLE_REQ); | ||
| 141 | ExitOnFailure(hr, "failed to set periodic restart request count id"); | ||
| 142 | hr = ScaWriteConfigInteger(psap->iRecycleRequests); | ||
| 143 | ExitOnFailure(hr, "failed to set periodic restart request count"); | ||
| 144 | } | ||
| 145 | |||
| 146 | if (*psap->wzRecycleTimes) | ||
| 147 | { | ||
| 148 | hr = ScaWriteConfigID(IIS_APPPOOL_RECYCLE_TIMES); | ||
| 149 | ExitOnFailure(hr, "failed to set periodic restart schedule id"); | ||
| 150 | hr = ScaWriteConfigString(psap->wzRecycleTimes); | ||
| 151 | ExitOnFailure(hr, "failed to set periodic restart schedule"); | ||
| 152 | } | ||
| 153 | |||
| 154 | if (MSI_NULL_INTEGER != psap->iVirtualMemory) | ||
| 155 | { | ||
| 156 | hr = ScaWriteConfigID(IIS_APPPOOL_RECYCLE_VIRMEM); | ||
| 157 | ExitOnFailure(hr, "failed to set periodic restart memory count id"); | ||
| 158 | hr = ScaWriteConfigInteger(psap->iVirtualMemory); | ||
| 159 | ExitOnFailure(hr, "failed to set periodic restart memory count"); | ||
| 160 | } | ||
| 161 | |||
| 162 | if (MSI_NULL_INTEGER != psap->iPrivateMemory) | ||
| 163 | { | ||
| 164 | hr = ScaWriteConfigID(IIS_APPPOOL_RECYCLE_PRIVMEM); | ||
| 165 | ExitOnFailure(hr, "failed to set periodic restart private memory count id"); | ||
| 166 | hr = ScaWriteConfigInteger(psap->iPrivateMemory); | ||
| 167 | ExitOnFailure(hr, "failed to set periodic restart private memory count"); | ||
| 168 | } | ||
| 169 | |||
| 170 | // Set AppPool Performance Tab | ||
| 171 | if (MSI_NULL_INTEGER != psap->iIdleTimeout) | ||
| 172 | { | ||
| 173 | hr = ScaWriteConfigID(IIS_APPPOOL_RECYCLE_IDLTIMEOUT); | ||
| 174 | ExitOnFailure(hr, "failed to set idle timeout value id"); | ||
| 175 | hr = ScaWriteConfigInteger(psap->iIdleTimeout); | ||
| 176 | ExitOnFailure(hr, "failed to set idle timeout value"); | ||
| 177 | } | ||
| 178 | |||
| 179 | if (MSI_NULL_INTEGER != psap->iQueueLimit) | ||
| 180 | { | ||
| 181 | hr = ScaWriteConfigID(IIS_APPPOOL_RECYCLE_QUEUELIMIT); | ||
| 182 | ExitOnFailure(hr, "failed to set request queue limit value id"); | ||
| 183 | hr = ScaWriteConfigInteger(psap->iQueueLimit); | ||
| 184 | ExitOnFailure(hr, "failed to set request queue limit value"); | ||
| 185 | } | ||
| 186 | if (*psap->wzCpuMon) | ||
| 187 | { | ||
| 188 | #pragma prefast(suppress:26037, "Source string is null terminated - it is populated as target of ::StringCchCopyW") | ||
| 189 | hr = ::StrAllocString(&pwzValue, psap->wzCpuMon, 0); | ||
| 190 | ExitOnFailure(hr, "failed to allocate CPUMonitor string"); | ||
| 191 | |||
| 192 | DWORD dwPercent = 0; | ||
| 193 | DWORD dwRefreshMinutes = 0; | ||
| 194 | DWORD dwAction = 0; | ||
| 195 | |||
| 196 | dwPercent = wcstoul(pwzValue, &wz, 10); | ||
| 197 | if (100 < dwPercent) | ||
| 198 | { | ||
| 199 | ExitOnFailure(hr = E_INVALIDARG, "invalid maximum cpu percentage value: %d", dwPercent); | ||
| 200 | } | ||
| 201 | if (wz && L',' == *wz) | ||
| 202 | { | ||
| 203 | ++wz; | ||
| 204 | dwRefreshMinutes = wcstoul(wz, &wz, 10); | ||
| 205 | if (wz && L',' == *wz) | ||
| 206 | { | ||
| 207 | ++wz; | ||
| 208 | dwAction = wcstoul(wz, &wz, 10); | ||
| 209 | } | ||
| 210 | } | ||
| 211 | if (dwPercent) | ||
| 212 | { | ||
| 213 | hr = ScaWriteConfigID(IIS_APPPOOL_RECYCLE_CPU_PCT); | ||
| 214 | ExitOnFailure(hr, "failed to set recycle pct id"); | ||
| 215 | hr = ScaWriteConfigInteger(dwPercent); | ||
| 216 | ExitOnFailure(hr, "failed to set CPU percentage max"); | ||
| 217 | } | ||
| 218 | if (dwRefreshMinutes) | ||
| 219 | { | ||
| 220 | hr = ScaWriteConfigID(IIS_APPPOOL_RECYCLE_CPU_REFRESH); | ||
| 221 | ExitOnFailure(hr, "failed to set recycle refresh id"); | ||
| 222 | hr = ScaWriteConfigInteger(dwRefreshMinutes); | ||
| 223 | ExitOnFailure(hr, "failed to set refresh CPU minutes"); | ||
| 224 | } | ||
| 225 | if (dwAction) | ||
| 226 | { | ||
| 227 | // 0 = No Action | ||
| 228 | // 1 = Shutdown | ||
| 229 | hr = ScaWriteConfigID(IIS_APPPOOL_RECYCLE_CPU_ACTION); | ||
| 230 | ExitOnFailure(hr, "failed to set recycle refresh id"); | ||
| 231 | hr = ScaWriteConfigInteger(dwAction); | ||
| 232 | ExitOnFailure(hr, "failed to set CPU action"); | ||
| 233 | } | ||
| 234 | } | ||
| 235 | |||
| 236 | if (MSI_NULL_INTEGER != psap->iMaxProcesses) | ||
| 237 | { | ||
| 238 | hr = ScaWriteConfigID(IIS_APPPOOL_MAXPROCESS); | ||
| 239 | ExitOnFailure(hr, "Failed to write max processes config ID"); | ||
| 240 | |||
| 241 | hr = ScaWriteConfigInteger(psap->iMaxProcesses); | ||
| 242 | ExitOnFailure(hr, "failed to set web garden maximum worker processes"); | ||
| 243 | } | ||
| 244 | |||
| 245 | hr = ScaWriteConfigID(IIS_APPPOOL_32BIT); | ||
| 246 | ExitOnFailure(hr, "Failed to write 32 bit app pool config ID"); | ||
| 247 | hr = ScaWriteConfigInteger(psap->iCompAttributes & msidbComponentAttributes64bit ? 0 : 1); | ||
| 248 | ExitOnFailure(hr, "Failed to write 32 bit app pool config value"); | ||
| 249 | |||
| 250 | // | ||
| 251 | // Set the AppPool Identity tab | ||
| 252 | // | ||
| 253 | if (psap->iAttributes & APATTR_APPPOOLIDENTITY) | ||
| 254 | { | ||
| 255 | dwIdentity = 4; | ||
| 256 | } | ||
| 257 | else if (psap->iAttributes & APATTR_NETSERVICE) | ||
| 258 | { | ||
| 259 | dwIdentity = 2; | ||
| 260 | } | ||
| 261 | else if (psap->iAttributes & APATTR_LOCSERVICE) | ||
| 262 | { | ||
| 263 | dwIdentity = 1; | ||
| 264 | } | ||
| 265 | else if (psap->iAttributes & APATTR_LOCSYSTEM) | ||
| 266 | { | ||
| 267 | dwIdentity = 0; | ||
| 268 | } | ||
| 269 | else if (psap->iAttributes & APATTR_OTHERUSER) | ||
| 270 | { | ||
| 271 | if (!*psap->suUser.wzDomain || 0 == _wcsicmp(psap->suUser.wzDomain, L".")) | ||
| 272 | { | ||
| 273 | if (0 == _wcsicmp(psap->suUser.wzName, L"NetworkService")) | ||
| 274 | { | ||
| 275 | dwIdentity = 2; | ||
| 276 | } | ||
| 277 | else if (0 == _wcsicmp(psap->suUser.wzName, L"LocalService")) | ||
| 278 | { | ||
| 279 | dwIdentity = 1; | ||
| 280 | } | ||
| 281 | else if (0 == _wcsicmp(psap->suUser.wzName, L"LocalSystem")) | ||
| 282 | { | ||
| 283 | dwIdentity = 0; | ||
| 284 | } | ||
| 285 | else | ||
| 286 | { | ||
| 287 | dwIdentity = 3; | ||
| 288 | } | ||
| 289 | } | ||
| 290 | else if (0 == _wcsicmp(psap->suUser.wzDomain, L"NT AUTHORITY")) | ||
| 291 | { | ||
| 292 | if (0 == _wcsicmp(psap->suUser.wzName, L"NETWORK SERVICE")) | ||
| 293 | { | ||
| 294 | dwIdentity = 2; | ||
| 295 | } | ||
| 296 | else if (0 == _wcsicmp(psap->suUser.wzName, L"SERVICE")) | ||
| 297 | { | ||
| 298 | dwIdentity = 1; | ||
| 299 | } | ||
| 300 | else if (0 == _wcsicmp(psap->suUser.wzName, L"SYSTEM")) | ||
| 301 | { | ||
| 302 | dwIdentity = 0; | ||
| 303 | } | ||
| 304 | else | ||
| 305 | { | ||
| 306 | dwIdentity = 3; | ||
| 307 | } | ||
| 308 | } | ||
| 309 | else | ||
| 310 | { | ||
| 311 | dwIdentity = 3; | ||
| 312 | } | ||
| 313 | } | ||
| 314 | |||
| 315 | if (-1 != dwIdentity) | ||
| 316 | { | ||
| 317 | hr = ScaWriteConfigID(IIS_APPPOOL_IDENTITY); | ||
| 318 | ExitOnFailure(hr, "failed to set app pool identity id"); | ||
| 319 | hr = ScaWriteConfigInteger(dwIdentity); | ||
| 320 | ExitOnFailure(hr, "failed to set app pool identity"); | ||
| 321 | |||
| 322 | if (3 == dwIdentity) | ||
| 323 | { | ||
| 324 | if (*psap->suUser.wzDomain) | ||
| 325 | { | ||
| 326 | hr = StrAllocFormatted(&pwzValue, L"%s\\%s", psap->suUser.wzDomain, psap->suUser.wzName); | ||
| 327 | ExitOnFailure(hr, "failed to format user name: %ls domain: %ls", psap->suUser.wzName, psap->suUser.wzDomain); | ||
| 328 | } | ||
| 329 | else | ||
| 330 | { | ||
| 331 | hr = StrAllocFormatted(&pwzValue, L"%s", psap->suUser.wzName); | ||
| 332 | ExitOnFailure(hr, "failed to format user name: %ls", psap->suUser.wzName); | ||
| 333 | } | ||
| 334 | |||
| 335 | hr = ScaWriteConfigID(IIS_APPPOOL_USER); | ||
| 336 | ExitOnFailure(hr, "failed to set app pool identity name id"); | ||
| 337 | hr = ScaWriteConfigString(pwzValue); | ||
| 338 | ExitOnFailure(hr, "failed to set app pool identity name"); | ||
| 339 | |||
| 340 | hr = ScaWriteConfigID(IIS_APPPOOL_PWD); | ||
| 341 | ExitOnFailure(hr, "failed to set app pool identity password id"); | ||
| 342 | hr = ScaWriteConfigString(psap->suUser.wzPassword); | ||
| 343 | ExitOnFailure(hr, "failed to set app pool identity password"); | ||
| 344 | } | ||
| 345 | } | ||
| 346 | |||
| 347 | if (*psap->wzManagedPipelineMode) | ||
| 348 | { | ||
| 349 | hr = ScaWriteConfigID(IIS_APPPOOL_MANAGED_PIPELINE_MODE); | ||
| 350 | ExitOnFailure(hr, "failed to set app pool integrated mode"); | ||
| 351 | hr = ScaWriteConfigString(psap->wzManagedPipelineMode); | ||
| 352 | ExitOnFailure(hr, "failed to set app pool managed pipeline mode value"); | ||
| 353 | } | ||
| 354 | |||
| 355 | if (*psap->wzManagedRuntimeVersion) | ||
| 356 | { | ||
| 357 | hr = ScaWriteConfigID(IIS_APPPOOL_MANAGED_RUNTIME_VERSION); | ||
| 358 | ExitOnFailure(hr, "failed to set app pool managed runtime version mode"); | ||
| 359 | hr = ScaWriteConfigString(psap->wzManagedRuntimeVersion); | ||
| 360 | ExitOnFailure(hr, "failed to set app pool managed runtime version value"); | ||
| 361 | } | ||
| 362 | |||
| 363 | // | ||
| 364 | //The number of properties above is variable so we put an end tag in so the | ||
| 365 | //execute CA will know when to stop looking for AppPool properties | ||
| 366 | // | ||
| 367 | hr = ScaWriteConfigID(IIS_APPPOOL_END); | ||
| 368 | ExitOnFailure(hr, "failed to set app pool end of properties id"); | ||
| 369 | |||
| 370 | LExit: | ||
| 371 | ReleaseStr(pwzValue); | ||
| 372 | |||
| 373 | return hr; | ||
| 374 | } | ||
| 375 | |||
| 376 | |||
| 377 | HRESULT ScaRemoveAppPool7( | ||
| 378 | __in const SCA_APPPOOL* psap | ||
| 379 | ) | ||
| 380 | { | ||
| 381 | Assert(psap); | ||
| 382 | |||
| 383 | HRESULT hr = S_OK; | ||
| 384 | |||
| 385 | //do not delete the default App Pool | ||
| 386 | if (0 != _wcsicmp(psap->wzAppPool, L"DefaultAppPool")) | ||
| 387 | { | ||
| 388 | //delete the app pool | ||
| 389 | hr = ScaWriteConfigID(IIS_APPPOOL); | ||
| 390 | ExitOnFailure(hr, "failed to write AppPool key."); | ||
| 391 | |||
| 392 | hr = ScaWriteConfigID(IIS_DELETE); | ||
| 393 | ExitOnFailure(hr, "failed to write AppPool delete action."); | ||
| 394 | |||
| 395 | hr = ScaWriteConfigString(psap->wzName); | ||
| 396 | ExitOnFailure(hr, "failed to delete AppPool: %ls", psap->wzName); | ||
| 397 | } | ||
| 398 | |||
| 399 | LExit: | ||
| 400 | return hr; | ||
| 401 | } | ||
diff --git a/src/ca/scaapppool7.h b/src/ca/scaapppool7.h new file mode 100644 index 00000000..1f49d899 --- /dev/null +++ b/src/ca/scaapppool7.h | |||
| @@ -0,0 +1,36 @@ | |||
| 1 | #pragma once | ||
| 2 | // 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. | ||
| 3 | |||
| 4 | |||
| 5 | #include "scauser.h" | ||
| 6 | |||
| 7 | // Identity | ||
| 8 | #define APATTR_NETSERVICE 0x0001 // Network Service | ||
| 9 | #define APATTR_LOCSERVICE 0x0002 // Local Service | ||
| 10 | #define APATTR_LOCSYSTEM 0x0004 // Local System | ||
| 11 | #define APATTR_OTHERUSER 0x0008 // Other User | ||
| 12 | #define APATTR_APPPOOLIDENTITY 0x0010 // ApplicationPoolIdentity | ||
| 13 | |||
| 14 | // prototypes | ||
| 15 | HRESULT ScaFindAppPool7( | ||
| 16 | __in LPCWSTR wzAppPool, | ||
| 17 | __out_ecount(cchName) LPWSTR wzName, | ||
| 18 | __in DWORD cchName, | ||
| 19 | __in SCA_APPPOOL *psapList | ||
| 20 | ); | ||
| 21 | |||
| 22 | HRESULT ScaAppPoolInstall7( | ||
| 23 | __in SCA_APPPOOL* psapList | ||
| 24 | ); | ||
| 25 | |||
| 26 | HRESULT ScaAppPoolUninstall7( | ||
| 27 | __in SCA_APPPOOL* psapList | ||
| 28 | ); | ||
| 29 | |||
| 30 | HRESULT ScaWriteAppPool7( | ||
| 31 | __in const SCA_APPPOOL* psap | ||
| 32 | ); | ||
| 33 | |||
| 34 | HRESULT ScaRemoveAppPool7( | ||
| 35 | __in const SCA_APPPOOL* psap | ||
| 36 | ); | ||
diff --git a/src/ca/scacert.cpp b/src/ca/scacert.cpp new file mode 100644 index 00000000..90db6375 --- /dev/null +++ b/src/ca/scacert.cpp | |||
| @@ -0,0 +1,1479 @@ | |||
| 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 | #include "precomp.h" | ||
| 4 | |||
| 5 | // prototypes | ||
| 6 | static HRESULT ConfigureCertificates( | ||
| 7 | __in SCA_ACTION saAction | ||
| 8 | ); | ||
| 9 | |||
| 10 | static LPCWSTR StoreMapping( | ||
| 11 | __in int iStore | ||
| 12 | ); | ||
| 13 | |||
| 14 | static HRESULT FindExistingCertificate( | ||
| 15 | __in LPCWSTR wzName, | ||
| 16 | __in DWORD dwStoreLocation, | ||
| 17 | __in LPCWSTR wzStore, | ||
| 18 | __out BYTE** prgbCertificate, | ||
| 19 | __out DWORD* pcbCertificate | ||
| 20 | ); | ||
| 21 | |||
| 22 | static HRESULT ResolveCertificate( | ||
| 23 | __in LPCWSTR wzId, | ||
| 24 | __in LPCWSTR wzName, | ||
| 25 | __in DWORD dwStoreLocation, | ||
| 26 | __in LPCWSTR wzStoreName, | ||
| 27 | __in DWORD dwAttributess, | ||
| 28 | __in LPCWSTR wzData, | ||
| 29 | __in LPCWSTR wzPFXPassword, | ||
| 30 | __out BYTE** ppbCertificate, | ||
| 31 | __out DWORD* pcbCertificate | ||
| 32 | ); | ||
| 33 | |||
| 34 | static HRESULT ReadCertificateFile( | ||
| 35 | __in LPCWSTR wzPath, | ||
| 36 | __out BYTE** prgbData, | ||
| 37 | __out DWORD* pcbData | ||
| 38 | ); | ||
| 39 | |||
| 40 | static HRESULT CertificateToHash( | ||
| 41 | __in BYTE* pbCertificate, | ||
| 42 | __in DWORD cbCertificate, | ||
| 43 | __in DWORD dwStoreLocation, | ||
| 44 | __in LPCWSTR wzPFXPassword, | ||
| 45 | __in BYTE rgbHash[], | ||
| 46 | __in DWORD cbHash | ||
| 47 | ); | ||
| 48 | |||
| 49 | /* | ||
| 50 | HRESULT ScaGetCertificateByPath(LPCWSTR pwzName, BOOL fIsInstalling, | ||
| 51 | BOOL fIsUninstalling, INT iStore, | ||
| 52 | INT iStoreLocation, LPCWSTR wzSslCertificate, | ||
| 53 | LPCWSTR wzPFXPassword, BSTR* pbstrCertificate, | ||
| 54 | DWORD* pcbCertificate, BYTE* pbaHashBuffer); | ||
| 55 | |||
| 56 | HRESULT ScaGetCertificateByRequest(LPCWSTR pwzName, BOOL fIsInstalling, | ||
| 57 | BOOL fIsUninstalling, INT iStore, | ||
| 58 | INT iStoreLocation, LPCWSTR wzDistinguishedName, | ||
| 59 | LPCWSTR wzCA, BSTR* pbstrCertificate, | ||
| 60 | DWORD* pcbCertificate, BYTE* pbaHashBuffer); | ||
| 61 | |||
| 62 | HRESULT ScaSslNewCertificate(LPCWSTR pwzName, INT iStore, | ||
| 63 | INT iStoreLocation, LPCWSTR wzComputerName, | ||
| 64 | LPCWSTR wzDistinguishedName, LPCWSTR wzCertificateAuthorityOrig, | ||
| 65 | BSTR* pbstrCertificate, DWORD* pcbCertificate, | ||
| 66 | BYTE* pbaHashBuffer); | ||
| 67 | |||
| 68 | HRESULT ScaSslExistingCertificateByName(LPCWSTR pwzName, INT iStore, | ||
| 69 | INT iStoreLocation, BSTR* pbstrCertificate, | ||
| 70 | DWORD* pcbCertificate, BYTE* pbaHashBuffer); | ||
| 71 | |||
| 72 | HRESULT ScaSslExistingCertificateByBinaryData(INT iStore, INT iStoreLocation, | ||
| 73 | BYTE* pwzData, DWORD cchData); | ||
| 74 | |||
| 75 | HRESULT CreateEnroll(ICEnroll2 **hEnroll, INT iStore, | ||
| 76 | INT iStoreLocation); | ||
| 77 | |||
| 78 | HRESULT RequestCertificate(LPCWSTR pwzName, INT iStore, | ||
| 79 | INT iStoreLocation, LPCWSTR wzComputerName, | ||
| 80 | LPCWSTR wzDistinguishedName, LPCWSTR wzCertificateAuthority, | ||
| 81 | BSTR *pbstrCertificate); | ||
| 82 | |||
| 83 | VOID ParseCertificateAuthority(__in LPCWSTR wzCertificateAuthorityOrig, __out LPWSTR *pwzBuffer, | ||
| 84 | __out LPWSTR **hwzCAArray, __out int *piCAArray); | ||
| 85 | */ | ||
| 86 | |||
| 87 | |||
| 88 | LPCWSTR vcsCertQuery = L"SELECT `Certificate`, `Name`, `Component_`, `StoreLocation`, `StoreName`, `Attributes`, `Binary_`, `CertificatePath`, `PFXPassword` FROM `Certificate`"; | ||
| 89 | enum eCertQuery { cqCertificate = 1, cqName, cqComponent, cqStoreLocation, cqStoreName, cqAttributes, cqCertificateBinary, cqCertificatePath, cqPFXPassword }; | ||
| 90 | |||
| 91 | |||
| 92 | /******************************************************************** | ||
| 93 | InstallCertificates - CUSTOM ACTION ENTRY POINT for installing | ||
| 94 | certificates | ||
| 95 | |||
| 96 | ********************************************************************/ | ||
| 97 | extern "C" UINT __stdcall InstallCertificates( | ||
| 98 | __in MSIHANDLE hInstall | ||
| 99 | ) | ||
| 100 | { | ||
| 101 | HRESULT hr = S_OK; | ||
| 102 | UINT er = ERROR_SUCCESS; | ||
| 103 | |||
| 104 | // initialize | ||
| 105 | hr = WcaInitialize(hInstall, "InstallCertificates"); | ||
| 106 | ExitOnFailure(hr, "Failed to initialize"); | ||
| 107 | |||
| 108 | hr = ConfigureCertificates(SCA_ACTION_INSTALL); | ||
| 109 | |||
| 110 | LExit: | ||
| 111 | er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; | ||
| 112 | return WcaFinalize(er); | ||
| 113 | } | ||
| 114 | |||
| 115 | |||
| 116 | /******************************************************************** | ||
| 117 | UninstallCertificates - CUSTOM ACTION ENTRY POINT for uninstalling | ||
| 118 | certificates | ||
| 119 | |||
| 120 | ********************************************************************/ | ||
| 121 | extern "C" UINT __stdcall UninstallCertificates( | ||
| 122 | __in MSIHANDLE hInstall | ||
| 123 | ) | ||
| 124 | { | ||
| 125 | HRESULT hr = S_OK; | ||
| 126 | UINT er = ERROR_SUCCESS; | ||
| 127 | |||
| 128 | // initialize | ||
| 129 | hr = WcaInitialize(hInstall, "UninstallCertificates"); | ||
| 130 | ExitOnFailure(hr, "Failed to initialize"); | ||
| 131 | |||
| 132 | hr = ConfigureCertificates(SCA_ACTION_UNINSTALL); | ||
| 133 | |||
| 134 | LExit: | ||
| 135 | er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; | ||
| 136 | return WcaFinalize(er); | ||
| 137 | } | ||
| 138 | |||
| 139 | |||
| 140 | static HRESULT ConfigureCertificates( | ||
| 141 | __in SCA_ACTION saAction | ||
| 142 | ) | ||
| 143 | { | ||
| 144 | //AssertSz(FALSE, "debug ConfigureCertificates()."); | ||
| 145 | |||
| 146 | HRESULT hr = S_OK; | ||
| 147 | DWORD er = ERROR_SUCCESS; | ||
| 148 | |||
| 149 | PMSIHANDLE hViewCertificate; | ||
| 150 | PMSIHANDLE hRecCertificate; | ||
| 151 | INSTALLSTATE isInstalled = INSTALLSTATE_UNKNOWN; | ||
| 152 | INSTALLSTATE isAction = INSTALLSTATE_UNKNOWN; | ||
| 153 | |||
| 154 | WCHAR* pwzId = NULL; | ||
| 155 | WCHAR* pwzName = NULL; | ||
| 156 | WCHAR* pwzComponent = NULL; | ||
| 157 | int iData = 0; | ||
| 158 | DWORD dwStoreLocation = 0; | ||
| 159 | LPWSTR pwzStoreName = 0; | ||
| 160 | DWORD dwAttributes = 0; | ||
| 161 | WCHAR* pwzData = NULL; | ||
| 162 | WCHAR* pwzPFXPassword = NULL; | ||
| 163 | WCHAR* pwzCaData = NULL; | ||
| 164 | WCHAR* pwzRollbackCaData = NULL; | ||
| 165 | |||
| 166 | BYTE* pbCertificate = NULL; | ||
| 167 | DWORD cbCertificate = 0; | ||
| 168 | DWORD cbPFXPassword = 0; | ||
| 169 | |||
| 170 | // Bail quickly if the Certificate table isn't around. | ||
| 171 | if (S_OK != WcaTableExists(L"Certificate")) | ||
| 172 | { | ||
| 173 | WcaLog(LOGMSG_VERBOSE, "Skipping ConfigureCertificates() - required table not present."); | ||
| 174 | ExitFunction1(hr = S_FALSE); | ||
| 175 | } | ||
| 176 | |||
| 177 | // Process the Certificate table. | ||
| 178 | hr = WcaOpenExecuteView(vcsCertQuery, &hViewCertificate); | ||
| 179 | ExitOnFailure(hr, "failed to open view on Certificate table"); | ||
| 180 | |||
| 181 | while (SUCCEEDED(hr = WcaFetchRecord(hViewCertificate, &hRecCertificate))) | ||
| 182 | { | ||
| 183 | hr = WcaGetRecordString(hRecCertificate, cqCertificate, &pwzId); // the id is just useful to have up front | ||
| 184 | ExitOnFailure(hr, "failed to get Certificate.Certificate"); | ||
| 185 | |||
| 186 | hr = WcaGetRecordString(hRecCertificate, cqComponent, &pwzComponent); | ||
| 187 | ExitOnFailure(hr, "failed to get Certificate.Component_"); | ||
| 188 | |||
| 189 | er = ::MsiGetComponentStateW(WcaGetInstallHandle(), pwzComponent, &isInstalled, &isAction); | ||
| 190 | hr = HRESULT_FROM_WIN32(er); | ||
| 191 | ExitOnFailure(hr, "failed to get state for component: %ls", pwzComponent); | ||
| 192 | |||
| 193 | if (!(WcaIsInstalling(isInstalled, isAction) && SCA_ACTION_INSTALL == saAction) && | ||
| 194 | !(WcaIsUninstalling(isInstalled, isAction) && SCA_ACTION_UNINSTALL == saAction) && | ||
| 195 | !(WcaIsReInstalling(isInstalled, isAction))) | ||
| 196 | { | ||
| 197 | WcaLog(LOGMSG_VERBOSE, "Skipping non-action certificate: %ls", pwzId); | ||
| 198 | continue; | ||
| 199 | } | ||
| 200 | |||
| 201 | // extract the rest of the data from the Certificate table | ||
| 202 | hr = WcaGetRecordFormattedString(hRecCertificate, cqName, &pwzName); | ||
| 203 | ExitOnFailure(hr, "failed to get Certificate.Name"); | ||
| 204 | |||
| 205 | hr = WcaGetRecordInteger(hRecCertificate, cqStoreLocation, &iData); | ||
| 206 | ExitOnFailure(hr, "failed to get Certificate.StoreLocation"); | ||
| 207 | |||
| 208 | switch (iData) | ||
| 209 | { | ||
| 210 | case SCA_CERTSYSTEMSTORE_CURRENTUSER: | ||
| 211 | dwStoreLocation = CERT_SYSTEM_STORE_CURRENT_USER; | ||
| 212 | break; | ||
| 213 | case SCA_CERTSYSTEMSTORE_LOCALMACHINE: | ||
| 214 | dwStoreLocation = CERT_SYSTEM_STORE_LOCAL_MACHINE; | ||
| 215 | break; | ||
| 216 | default: | ||
| 217 | hr = E_INVALIDARG; | ||
| 218 | ExitOnFailure(hr, "Invalid store location value: %d", iData); | ||
| 219 | } | ||
| 220 | |||
| 221 | hr = WcaGetRecordString(hRecCertificate, cqStoreName, &pwzStoreName); | ||
| 222 | ExitOnFailure(hr, "failed to get Certificate.StoreName"); | ||
| 223 | |||
| 224 | hr = WcaGetRecordInteger(hRecCertificate, cqAttributes, reinterpret_cast<int*>(&dwAttributes)); | ||
| 225 | ExitOnFailure(hr, "failed to get Certificate.Attributes"); | ||
| 226 | |||
| 227 | if (dwAttributes & SCA_CERT_ATTRIBUTE_BINARYDATA) | ||
| 228 | { | ||
| 229 | hr = WcaGetRecordString(hRecCertificate, cqCertificateBinary, &pwzData); | ||
| 230 | ExitOnFailure(hr, "failed to get Certificate.Binary_"); | ||
| 231 | } | ||
| 232 | else | ||
| 233 | { | ||
| 234 | hr = WcaGetRecordFormattedString(hRecCertificate, cqCertificatePath, &pwzData); | ||
| 235 | ExitOnFailure(hr, "failed to get Certificate.CertificatePath"); | ||
| 236 | } | ||
| 237 | |||
| 238 | hr = WcaGetRecordFormattedString(hRecCertificate, cqPFXPassword, &pwzPFXPassword); | ||
| 239 | ExitOnFailure(hr, "failed to get Certificate.PFXPassword"); | ||
| 240 | |||
| 241 | // Write the common data (for both install and uninstall) to the CustomActionData | ||
| 242 | // to pass data to the deferred CustomAction. | ||
| 243 | hr = StrAllocString(&pwzCaData, pwzName, 0); | ||
| 244 | ExitOnFailure(hr, "Failed to pass Certificate.Certificate to deferred CustomAction."); | ||
| 245 | hr = WcaWriteStringToCaData(pwzStoreName, &pwzCaData); | ||
| 246 | ExitOnFailure(hr, "Failed to pass Certificate.StoreName to deferred CustomAction."); | ||
| 247 | hr = WcaWriteIntegerToCaData(SCA_CERT_ATTRIBUTE_BINARYDATA, &pwzCaData); | ||
| 248 | ExitOnFailure(hr, "Failed to pass Certificate.Attributes to deferred CustomAction."); | ||
| 249 | |||
| 250 | // Copy the rollback data from the deferred data because it's the same up to this point. | ||
| 251 | hr = StrAllocString(&pwzRollbackCaData, pwzCaData, 0); | ||
| 252 | ExitOnFailure(hr, "Failed to allocate string for rollback CustomAction."); | ||
| 253 | |||
| 254 | // Finally, schedule the correct deferred CustomAction to actually do work. | ||
| 255 | LPCWSTR wzAction = NULL; | ||
| 256 | LPCWSTR wzRollbackAction = NULL; | ||
| 257 | DWORD dwCost = 0; | ||
| 258 | if (SCA_ACTION_UNINSTALL == saAction) | ||
| 259 | { | ||
| 260 | // Find an existing certificate one (if there is one) to so we have it for rollback. | ||
| 261 | hr = FindExistingCertificate(pwzName, dwStoreLocation, pwzStoreName, &pbCertificate, &cbCertificate); | ||
| 262 | ExitOnFailure(hr, "Failed to search for existing certificate with friendly name: %ls", pwzName); | ||
| 263 | |||
| 264 | if (pbCertificate) | ||
| 265 | { | ||
| 266 | hr = WcaWriteStreamToCaData(pbCertificate, cbCertificate, &pwzRollbackCaData); | ||
| 267 | ExitOnFailure(hr, "Failed to pass Certificate.Data to rollback CustomAction."); | ||
| 268 | |||
| 269 | hr = WcaWriteStringToCaData(pwzPFXPassword, &pwzRollbackCaData); | ||
| 270 | ExitOnFailure(hr, "Failed to pass Certificate.PFXPassword to rollback CustomAction."); | ||
| 271 | } | ||
| 272 | |||
| 273 | // Pick the right action to run based on what store we're uninstalling from. | ||
| 274 | if (CERT_SYSTEM_STORE_LOCAL_MACHINE == dwStoreLocation) | ||
| 275 | { | ||
| 276 | wzAction = L"DeleteMachineCertificate"; | ||
| 277 | if (pbCertificate) | ||
| 278 | { | ||
| 279 | wzRollbackAction = L"RollbackDeleteMachineCertificate"; | ||
| 280 | } | ||
| 281 | } | ||
| 282 | else | ||
| 283 | { | ||
| 284 | wzAction = L"DeleteUserCertificate"; | ||
| 285 | if (pbCertificate) | ||
| 286 | { | ||
| 287 | wzRollbackAction = L"RollbackDeleteUserCertificate"; | ||
| 288 | } | ||
| 289 | } | ||
| 290 | dwCost = COST_CERT_DELETE; | ||
| 291 | } | ||
| 292 | else | ||
| 293 | { | ||
| 294 | // Actually get the certificate, resolve it to a blob, and get the blob's hash. | ||
| 295 | hr = ResolveCertificate(pwzId, pwzName, dwStoreLocation, pwzStoreName, dwAttributes, pwzData, pwzPFXPassword, &pbCertificate, &cbCertificate); | ||
| 296 | ExitOnFailure(hr, "Failed to resolve certificate: %ls", pwzId); | ||
| 297 | |||
| 298 | hr = WcaWriteStreamToCaData(pbCertificate, cbCertificate, &pwzCaData); | ||
| 299 | ExitOnFailure(hr, "Failed to pass Certificate.Data to deferred CustomAction."); | ||
| 300 | |||
| 301 | hr = WcaWriteStringToCaData(pwzPFXPassword, &pwzCaData); | ||
| 302 | ExitOnFailure(hr, "Failed to pass Certificate.PFXPassword to deferred CustomAction."); | ||
| 303 | |||
| 304 | // Pick the right action to run based on what store we're installing into. | ||
| 305 | if (CERT_SYSTEM_STORE_LOCAL_MACHINE == dwStoreLocation) | ||
| 306 | { | ||
| 307 | wzAction = L"AddMachineCertificate"; | ||
| 308 | wzRollbackAction = L"RollbackAddMachineCertificate"; | ||
| 309 | } | ||
| 310 | else | ||
| 311 | { | ||
| 312 | wzAction = L"AddUserCertificate"; | ||
| 313 | wzRollbackAction = L"RollbackAddUserCertificate"; | ||
| 314 | } | ||
| 315 | dwCost = COST_CERT_ADD; | ||
| 316 | } | ||
| 317 | |||
| 318 | if (wzRollbackAction) | ||
| 319 | { | ||
| 320 | hr = WcaDoDeferredAction(wzRollbackAction, pwzRollbackCaData, dwCost); | ||
| 321 | ExitOnFailure(hr, "Failed to schedule rollback certificate action '%ls' for: %ls", wzRollbackAction, pwzId); | ||
| 322 | } | ||
| 323 | |||
| 324 | hr = WcaDoDeferredAction(wzAction, pwzCaData, dwCost); | ||
| 325 | ExitOnFailure(hr, "Failed to schedule certificate action '%ls' for: %ls", wzAction, pwzId); | ||
| 326 | |||
| 327 | // Clean up for the next certificate. | ||
| 328 | ReleaseNullMem(pbCertificate); | ||
| 329 | } | ||
| 330 | |||
| 331 | if (E_NOMOREITEMS == hr) | ||
| 332 | { | ||
| 333 | hr = S_OK; | ||
| 334 | } | ||
| 335 | |||
| 336 | LExit: | ||
| 337 | if (NULL != pwzPFXPassword && SUCCEEDED(StrSize(pwzPFXPassword, &cbPFXPassword))) | ||
| 338 | { | ||
| 339 | SecureZeroMemory(pwzPFXPassword, cbPFXPassword); | ||
| 340 | } | ||
| 341 | |||
| 342 | ReleaseMem(pbCertificate); | ||
| 343 | ReleaseStr(pwzCaData); | ||
| 344 | ReleaseStr(pwzPFXPassword); | ||
| 345 | ReleaseStr(pwzData); | ||
| 346 | ReleaseStr(pwzName); | ||
| 347 | ReleaseStr(pwzStoreName); | ||
| 348 | ReleaseStr(pwzComponent); | ||
| 349 | ReleaseStr(pwzId); | ||
| 350 | |||
| 351 | return hr; | ||
| 352 | } | ||
| 353 | |||
| 354 | |||
| 355 | static HRESULT ResolveCertificate( | ||
| 356 | __in LPCWSTR wzId, | ||
| 357 | __in LPCWSTR /*wzName*/, | ||
| 358 | __in DWORD dwStoreLocation, | ||
| 359 | __in LPCWSTR /*wzStoreName*/, | ||
| 360 | __in DWORD dwAttributes, | ||
| 361 | __in LPCWSTR wzData, | ||
| 362 | __in LPCWSTR wzPFXPassword, | ||
| 363 | __out BYTE** ppbCertificate, | ||
| 364 | __out DWORD* pcbCertificate | ||
| 365 | ) | ||
| 366 | { | ||
| 367 | HRESULT hr = S_OK; | ||
| 368 | |||
| 369 | LPWSTR pwzSql = NULL; | ||
| 370 | PMSIHANDLE hView; | ||
| 371 | PMSIHANDLE hRec; | ||
| 372 | MSIHANDLE hCertificateHashView = NULL; | ||
| 373 | MSIHANDLE hCertificateHashColumns = NULL; | ||
| 374 | |||
| 375 | BYTE rgbCertificateHash[CB_CERTIFICATE_HASH] = { 0 }; | ||
| 376 | WCHAR wzEncodedCertificateHash[CB_CERTIFICATE_HASH * 2 + 1] = { 0 }; | ||
| 377 | |||
| 378 | PMSIHANDLE hViewCertificateRequest, hRecCertificateRequest; | ||
| 379 | |||
| 380 | WCHAR* pwzDistinguishedName = NULL; | ||
| 381 | WCHAR* pwzCA = NULL; | ||
| 382 | |||
| 383 | BYTE* pbData = NULL; | ||
| 384 | DWORD cbData = 0; | ||
| 385 | |||
| 386 | if (dwAttributes & SCA_CERT_ATTRIBUTE_REQUEST) | ||
| 387 | { | ||
| 388 | hr = E_NOTIMPL; | ||
| 389 | ExitOnFailure(hr, "Installing certificates by requesting them from a certificate authority is not currently supported"); | ||
| 390 | //if (dwAttributes & SCA_CERT_ATTRIBUTE_OVERWRITE) | ||
| 391 | //{ | ||
| 392 | // // try to overwrite with the patch to a cert file | ||
| 393 | // WcaLog(LOGMSG_VERBOSE, "ConfigureCertificates - Overwrite with SSLCERTIFICATE"); | ||
| 394 | // hr = ScaGetCertificateByPath(pwzName, fIsInstalling, fIsUninstalling, | ||
| 395 | // iStore, iStoreLocation, pwzData, wzPFXPassword, pbstrCertificate, pcbCertificate, pbaHashBuffer); | ||
| 396 | //} | ||
| 397 | //if (hr != S_OK) | ||
| 398 | //{ | ||
| 399 | // if (fIsUninstalling && !fIsInstalling) | ||
| 400 | // { | ||
| 401 | // // for uninstall, we just want to find the existing certificate | ||
| 402 | // hr = ScaSslExistingCertificateByName(pwzName, iStore, iStoreLocation, pbstrCertificate, pcbCertificate, pbaHashBuffer); | ||
| 403 | // ExitOnFailure(hr, "Failed Retrieving existing certificate during uninstall"); | ||
| 404 | // // ok if no existing cert | ||
| 405 | // if (S_OK != hr) | ||
| 406 | // hr = S_OK; | ||
| 407 | // } | ||
| 408 | // else | ||
| 409 | // { | ||
| 410 | // // still no certificate | ||
| 411 | // // user has request this certificate, try to locate DistinguishedName and CA | ||
| 412 | // hr = WcaTableExists(L"CertificateRequest"); | ||
| 413 | // ExitOnFailure(hr, "CertificateRequest is referenced but not found"); | ||
| 414 | // WcaLog(LOGMSG_VERBOSE, "ConfigureCertificates - CertificateRequest table present"); | ||
| 415 | // cchSQLView = 255 + lstrlenW(pwzName); | ||
| 416 | // pwzSQLView = new WCHAR[cchSQLView]; | ||
| 417 | // if (pwzSQLView) | ||
| 418 | // { | ||
| 419 | // hr = ::StringCchPrintfW(pwzSQLView, cchSQLView, L"SELECT `DistinguishedName`, `CA` FROM `CertificateRequest` WHERE `Certificate_`=\'%s\'", pwzName); | ||
| 420 | // ExitOnFailure(hr, "::StringCchPrintfW failed"); | ||
| 421 | // hr = WcaOpenExecuteView(pwzSQLView, &hViewCertificateRequest); | ||
| 422 | // ExitOnFailure(hr, "failed to open view on CertificateRequest table"); | ||
| 423 | // hr = WcaFetchSingleRecord(hViewCertificateRequest, &hRecCertificateRequest); | ||
| 424 | // ExitOnFailure(hr, "failed to retrieve request from CertificateRequest table"); | ||
| 425 | // hr = WcaGetRecordString(hRecCertificateRequest, 1, &pwzDistinguishedName); | ||
| 426 | // ExitOnFailure(hr, "failed to get DistinguishedName"); | ||
| 427 | // hr = WcaGetRecordString(hRecCertificateRequest, 2, &pwzCA); | ||
| 428 | // ExitOnFailure(hr, "failed to get CA"); | ||
| 429 | // if (pwzDistinguishedName && pwzCA && *pwzDistinguishedName && *pwzCA) | ||
| 430 | // { | ||
| 431 | // hr = ScaGetCertificateByRequest(pwzName, fIsInstalling, fIsUninstalling, iStore, iStoreLocation, pwzDistinguishedName, pwzCA, pbstrCertificate, pcbCertificate, pbaHashBuffer); | ||
| 432 | // } | ||
| 433 | // else | ||
| 434 | // { | ||
| 435 | // hr = E_FAIL; | ||
| 436 | // ExitOnFailure(hr, "CertificateRequest entry is empty"); | ||
| 437 | // } | ||
| 438 | // } | ||
| 439 | // else | ||
| 440 | // { | ||
| 441 | // hr = E_FAIL; | ||
| 442 | // ExitOnFailure(hr, "Out of memory"); | ||
| 443 | // } | ||
| 444 | // } | ||
| 445 | //} | ||
| 446 | } | ||
| 447 | else if (dwAttributes & SCA_CERT_ATTRIBUTE_BINARYDATA) | ||
| 448 | { | ||
| 449 | // get the binary stream in Binary | ||
| 450 | hr = WcaTableExists(L"Binary"); | ||
| 451 | if (S_OK != hr) | ||
| 452 | { | ||
| 453 | if (SUCCEEDED(hr)) | ||
| 454 | { | ||
| 455 | hr = E_UNEXPECTED; | ||
| 456 | } | ||
| 457 | ExitOnFailure(hr, "Binary was referenced but there is no Binary table."); | ||
| 458 | } | ||
| 459 | |||
| 460 | hr = StrAllocFormatted(&pwzSql, L"SELECT `Data` FROM `Binary` WHERE `Name`=\'%s\'", wzData); | ||
| 461 | ExitOnFailure(hr, "Failed to allocate Binary table query."); | ||
| 462 | |||
| 463 | hr = WcaOpenExecuteView(pwzSql, &hView); | ||
| 464 | ExitOnFailure(hr, "Failed to open view on Binary table"); | ||
| 465 | |||
| 466 | hr = WcaFetchSingleRecord(hView, &hRec); | ||
| 467 | ExitOnFailure(hr, "Failed to retrieve request from Binary table"); | ||
| 468 | |||
| 469 | hr = WcaGetRecordStream(hRec, 1, &pbData, &cbData); | ||
| 470 | ExitOnFailure(hr, "Failed to ready Binary.Data for certificate."); | ||
| 471 | } | ||
| 472 | else if (dwAttributes == SCA_CERT_ATTRIBUTE_DEFAULT) | ||
| 473 | { | ||
| 474 | hr = ReadCertificateFile(wzData, &pbData, &cbData); | ||
| 475 | ExitOnFailure(hr, "Failed to read certificate from file path."); | ||
| 476 | } | ||
| 477 | else | ||
| 478 | { | ||
| 479 | hr = E_INVALIDARG; | ||
| 480 | ExitOnFailure(hr, "Invalid Certificate.Attributes."); | ||
| 481 | } | ||
| 482 | |||
| 483 | // If we have loaded a certificate, update the Certificate.Hash column. | ||
| 484 | if (pbData) | ||
| 485 | { | ||
| 486 | hr = CertificateToHash(pbData, cbData, dwStoreLocation, wzPFXPassword, rgbCertificateHash, countof(rgbCertificateHash)); | ||
| 487 | ExitOnFailure(hr, "Failed to get SHA1 hash of certificate."); | ||
| 488 | |||
| 489 | hr = StrHexEncode(rgbCertificateHash, countof(rgbCertificateHash), wzEncodedCertificateHash, countof(wzEncodedCertificateHash)); | ||
| 490 | ExitOnFailure(hr, "Failed to hex encode SHA1 hash of certificate."); | ||
| 491 | |||
| 492 | // Update the CertificateHash table. | ||
| 493 | hr = WcaAddTempRecord(&hCertificateHashView, &hCertificateHashColumns, L"CertificateHash", NULL, 0, 2, wzId, wzEncodedCertificateHash); | ||
| 494 | ExitOnFailure(hr, "Failed to add encoded has for certificate: %ls", wzId); | ||
| 495 | } | ||
| 496 | |||
| 497 | *ppbCertificate = pbData; | ||
| 498 | *pcbCertificate = cbData; | ||
| 499 | pbData = NULL; | ||
| 500 | |||
| 501 | LExit: | ||
| 502 | if (hCertificateHashColumns) | ||
| 503 | { | ||
| 504 | ::MsiCloseHandle(hCertificateHashColumns); | ||
| 505 | } | ||
| 506 | |||
| 507 | if (hCertificateHashView) | ||
| 508 | { | ||
| 509 | ::MsiCloseHandle(hCertificateHashView); | ||
| 510 | } | ||
| 511 | |||
| 512 | ReleaseStr(pwzDistinguishedName); | ||
| 513 | ReleaseStr(pwzCA); | ||
| 514 | ReleaseMem(pbData); | ||
| 515 | ReleaseStr(pwzSql); | ||
| 516 | |||
| 517 | return hr; | ||
| 518 | } | ||
| 519 | |||
| 520 | |||
| 521 | static HRESULT ReadCertificateFile( | ||
| 522 | __in LPCWSTR wzPath, | ||
| 523 | __out BYTE** prgbData, | ||
| 524 | __out DWORD* pcbData | ||
| 525 | ) | ||
| 526 | { | ||
| 527 | HRESULT hr = S_OK; | ||
| 528 | |||
| 529 | PCCERT_CONTEXT pCertContext = NULL; | ||
| 530 | DWORD dwContentType; | ||
| 531 | BYTE* pbData = NULL; | ||
| 532 | DWORD cbData = 0; | ||
| 533 | |||
| 534 | if (!::CryptQueryObject(CERT_QUERY_OBJECT_FILE, reinterpret_cast<LPCVOID>(wzPath), CERT_QUERY_CONTENT_FLAG_ALL, CERT_QUERY_FORMAT_FLAG_ALL, 0, NULL, &dwContentType, NULL, NULL, NULL, (LPCVOID*)&pCertContext)) | ||
| 535 | { | ||
| 536 | ExitOnFailure(hr, "Failed to read certificate from file: %ls", wzPath); | ||
| 537 | } | ||
| 538 | |||
| 539 | if (pCertContext) | ||
| 540 | { | ||
| 541 | cbData = pCertContext->cbCertEncoded; | ||
| 542 | pbData = static_cast<BYTE*>(MemAlloc(cbData, FALSE)); | ||
| 543 | ExitOnNull(pbData, hr, E_OUTOFMEMORY, "Failed to allocate memory to read certificate from file: %ls", wzPath); | ||
| 544 | |||
| 545 | CopyMemory(pbData, pCertContext->pbCertEncoded, pCertContext->cbCertEncoded); | ||
| 546 | } | ||
| 547 | else | ||
| 548 | { | ||
| 549 | // If we have a PFX blob, get the first certificate out of the PFX and use that instead of the PFX. | ||
| 550 | if (dwContentType & CERT_QUERY_CONTENT_PFX) | ||
| 551 | { | ||
| 552 | hr = FileRead(&pbData, &cbData, wzPath); | ||
| 553 | ExitOnFailure(hr, "Failed to read PFX file: %ls", wzPath); | ||
| 554 | } | ||
| 555 | else | ||
| 556 | { | ||
| 557 | hr = E_UNEXPECTED; | ||
| 558 | ExitOnFailure(hr, "Unexpected certificate type read from disk."); | ||
| 559 | } | ||
| 560 | } | ||
| 561 | |||
| 562 | *pcbData = cbData; | ||
| 563 | *prgbData = pbData; | ||
| 564 | pbData = NULL; | ||
| 565 | |||
| 566 | LExit: | ||
| 567 | ReleaseMem(pbData); | ||
| 568 | return hr; | ||
| 569 | } | ||
| 570 | |||
| 571 | |||
| 572 | static HRESULT CertificateToHash( | ||
| 573 | __in BYTE* pbCertificate, | ||
| 574 | __in DWORD cbCertificate, | ||
| 575 | __in DWORD dwStoreLocation, | ||
| 576 | __in LPCWSTR wzPFXPassword, | ||
| 577 | __in BYTE rgbHash[], | ||
| 578 | __in DWORD cbHash | ||
| 579 | ) | ||
| 580 | { | ||
| 581 | HRESULT hr = S_OK; | ||
| 582 | |||
| 583 | HCERTSTORE hPfxCertStore = NULL; | ||
| 584 | PCCERT_CONTEXT pCertContext = NULL; | ||
| 585 | PCCERT_CONTEXT pCertContextEnum = NULL; | ||
| 586 | CRYPT_DATA_BLOB blob = { 0 }; | ||
| 587 | CRYPT_KEY_PROV_INFO* pPfxInfo = NULL; | ||
| 588 | DWORD dwKeyset = (CERT_SYSTEM_STORE_CURRENT_USER == dwStoreLocation) ? CRYPT_USER_KEYSET : CRYPT_MACHINE_KEYSET; | ||
| 589 | DWORD dwEncodingType; | ||
| 590 | DWORD dwContentType; | ||
| 591 | DWORD dwFormatType; | ||
| 592 | |||
| 593 | blob.pbData = pbCertificate; | ||
| 594 | blob.cbData = cbCertificate; | ||
| 595 | |||
| 596 | if (!::CryptQueryObject(CERT_QUERY_OBJECT_BLOB, &blob, CERT_QUERY_CONTENT_FLAG_ALL, CERT_QUERY_FORMAT_FLAG_ALL, 0, &dwEncodingType, &dwContentType, &dwFormatType, NULL, NULL, (LPCVOID*)&pCertContext)) | ||
| 597 | { | ||
| 598 | ExitWithLastError(hr, "Failed to process certificate as a valid certificate."); | ||
| 599 | } | ||
| 600 | |||
| 601 | if (!pCertContext) | ||
| 602 | { | ||
| 603 | // If we have a PFX blob, get the first certificate out of the PFX and use that instead of the PFX. | ||
| 604 | if (dwContentType & CERT_QUERY_CONTENT_PFX) | ||
| 605 | { | ||
| 606 | // If we fail and our password is blank, also try passing in NULL for the password (according to the docs) | ||
| 607 | hPfxCertStore = ::PFXImportCertStore((CRYPT_DATA_BLOB*)&blob, wzPFXPassword, dwKeyset); | ||
| 608 | if (NULL == hPfxCertStore && !*wzPFXPassword) | ||
| 609 | { | ||
| 610 | hPfxCertStore = ::PFXImportCertStore((CRYPT_DATA_BLOB*)&blob, NULL, dwKeyset); | ||
| 611 | } | ||
| 612 | ExitOnNullWithLastError(hPfxCertStore, hr, "Failed to open PFX file."); | ||
| 613 | |||
| 614 | // Find the first cert with a private key, or just use the last one | ||
| 615 | for (pCertContextEnum = ::CertEnumCertificatesInStore(hPfxCertStore, pCertContextEnum); | ||
| 616 | pCertContextEnum; | ||
| 617 | pCertContextEnum = ::CertEnumCertificatesInStore(hPfxCertStore, pCertContextEnum)) | ||
| 618 | { | ||
| 619 | pCertContext = pCertContextEnum; | ||
| 620 | |||
| 621 | if (pCertContext && CertHasPrivateKey(pCertContext, NULL)) | ||
| 622 | { | ||
| 623 | break; | ||
| 624 | } | ||
| 625 | } | ||
| 626 | |||
| 627 | ExitOnNullWithLastError(pCertContext, hr, "Failed to read first certificate out of PFX file."); | ||
| 628 | |||
| 629 | // Ignore failures, the worst that happens is some parts of the PFX get left behind. | ||
| 630 | CertReadProperty(pCertContext, CERT_KEY_PROV_INFO_PROP_ID, &pPfxInfo, NULL); | ||
| 631 | } | ||
| 632 | else | ||
| 633 | { | ||
| 634 | hr = E_UNEXPECTED; | ||
| 635 | ExitOnFailure(hr, "Unexpected certificate type processed."); | ||
| 636 | } | ||
| 637 | } | ||
| 638 | |||
| 639 | DWORD cb = cbHash; | ||
| 640 | if (!::CertGetCertificateContextProperty(pCertContext, CERT_SHA1_HASH_PROP_ID, static_cast<LPVOID>(rgbHash), &cb)) | ||
| 641 | { | ||
| 642 | ExitWithLastError(hr, "Failed to get certificate SHA1 hash property."); | ||
| 643 | } | ||
| 644 | AssertSz(cb == cbHash, "Did not correctly read certificate SHA1 hash."); | ||
| 645 | |||
| 646 | LExit: | ||
| 647 | if (pCertContext) | ||
| 648 | { | ||
| 649 | ::CertFreeCertificateContext(pCertContext); | ||
| 650 | } | ||
| 651 | |||
| 652 | if (hPfxCertStore) | ||
| 653 | { | ||
| 654 | ::CertCloseStore(hPfxCertStore, 0); | ||
| 655 | } | ||
| 656 | |||
| 657 | if (pPfxInfo) | ||
| 658 | { | ||
| 659 | HCRYPTPROV hProvIgnored = NULL; // ignored on deletes. | ||
| 660 | ::CryptAcquireContextW(&hProvIgnored, pPfxInfo->pwszContainerName, pPfxInfo->pwszProvName, pPfxInfo->dwProvType, dwKeyset | CRYPT_DELETEKEYSET | CRYPT_SILENT); | ||
| 661 | |||
| 662 | MemFree(pPfxInfo); | ||
| 663 | } | ||
| 664 | |||
| 665 | return hr; | ||
| 666 | } | ||
| 667 | |||
| 668 | |||
| 669 | static HRESULT FindExistingCertificate( | ||
| 670 | __in LPCWSTR wzName, | ||
| 671 | __in DWORD dwStoreLocation, | ||
| 672 | __in LPCWSTR wzStore, | ||
| 673 | __out BYTE** prgbCertificate, | ||
| 674 | __out DWORD* pcbCertificate | ||
| 675 | ) | ||
| 676 | { | ||
| 677 | HRESULT hr = S_OK; | ||
| 678 | HCERTSTORE hCertStore = NULL; | ||
| 679 | PCCERT_CONTEXT pCertContext = NULL; | ||
| 680 | BYTE* pbCertificate = NULL; | ||
| 681 | DWORD cbCertificate = 0; | ||
| 682 | |||
| 683 | hCertStore = ::CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, NULL, dwStoreLocation | CERT_STORE_READONLY_FLAG, wzStore); | ||
| 684 | MessageExitOnNullWithLastError(hCertStore, hr, msierrCERTFailedOpen, "Failed to open certificate store."); | ||
| 685 | |||
| 686 | // Loop through the certificate, looking for certificates that match our friendly name. | ||
| 687 | pCertContext = CertFindCertificateInStore(hCertStore, PKCS_7_ASN_ENCODING | X509_ASN_ENCODING, 0, CERT_FIND_ANY, NULL, NULL); | ||
| 688 | while (pCertContext) | ||
| 689 | { | ||
| 690 | WCHAR wzFriendlyName[256] = { 0 }; | ||
| 691 | DWORD cbFriendlyName = sizeof(wzFriendlyName); | ||
| 692 | |||
| 693 | if (::CertGetCertificateContextProperty(pCertContext, CERT_FRIENDLY_NAME_PROP_ID, reinterpret_cast<BYTE*>(wzFriendlyName), &cbFriendlyName) && | ||
| 694 | CSTR_EQUAL == ::CompareStringW(LOCALE_SYSTEM_DEFAULT, 0, wzName, -1, wzFriendlyName, -1)) | ||
| 695 | { | ||
| 696 | // If the certificate with matching friendly name is valid, let's use that. | ||
| 697 | long lVerify = ::CertVerifyTimeValidity(NULL, pCertContext->pCertInfo); | ||
| 698 | if (0 == lVerify) | ||
| 699 | { | ||
| 700 | cbCertificate = pCertContext->cbCertEncoded; | ||
| 701 | pbCertificate = static_cast<BYTE*>(MemAlloc(cbCertificate, FALSE)); | ||
| 702 | ExitOnNull(pbCertificate, hr, E_OUTOFMEMORY, "Failed to allocate memory to copy out exist certificate."); | ||
| 703 | |||
| 704 | CopyMemory(pbCertificate, pCertContext->pbCertEncoded, cbCertificate); | ||
| 705 | break; // found a matching certificate, no more searching necessary | ||
| 706 | } | ||
| 707 | } | ||
| 708 | |||
| 709 | // Next certificate in the store. | ||
| 710 | PCCERT_CONTEXT pNext = ::CertFindCertificateInStore(hCertStore, PKCS_7_ASN_ENCODING | X509_ASN_ENCODING, 0, CERT_FIND_ANY, NULL, pCertContext); | ||
| 711 | // old pCertContext is freed by CertFindCertificateInStore | ||
| 712 | pCertContext = pNext; | ||
| 713 | } | ||
| 714 | |||
| 715 | *prgbCertificate = pbCertificate; | ||
| 716 | *pcbCertificate = cbCertificate; | ||
| 717 | pbCertificate = NULL; | ||
| 718 | |||
| 719 | LExit: | ||
| 720 | ReleaseMem(pbCertificate); | ||
| 721 | |||
| 722 | if (pCertContext) | ||
| 723 | { | ||
| 724 | ::CertFreeCertificateContext(pCertContext); | ||
| 725 | } | ||
| 726 | |||
| 727 | if (hCertStore) | ||
| 728 | { | ||
| 729 | ::CertCloseStore(hCertStore, 0); | ||
| 730 | } | ||
| 731 | |||
| 732 | return hr; | ||
| 733 | } | ||
| 734 | |||
| 735 | /* | ||
| 736 | HRESULT CreateEnroll(ICEnroll2 **hEnroll, INT iStore, INT iStoreLocation) | ||
| 737 | { | ||
| 738 | ICEnroll2 *pEnroll = NULL; | ||
| 739 | HRESULT hr = S_OK; | ||
| 740 | LONG lFlags; | ||
| 741 | DWORD dwFlags = iStoreLocation << CERT_SYSTEM_STORE_LOCATION_SHIFT; | ||
| 742 | |||
| 743 | // create IEntroll | ||
| 744 | hr = CoCreateInstance( CLSID_CEnroll, NULL, CLSCTX_INPROC_SERVER, IID_ICEnroll2, (void **)&pEnroll ); | ||
| 745 | if (FAILED(hr)) | ||
| 746 | return hr; | ||
| 747 | |||
| 748 | switch (iStore) | ||
| 749 | { | ||
| 750 | case SCA_CERT_STORENAME_MY: | ||
| 751 | pEnroll->get_MyStoreFlags(&lFlags); | ||
| 752 | lFlags &= ~CERT_SYSTEM_STORE_LOCATION_MASK; | ||
| 753 | lFlags |= dwFlags; | ||
| 754 | // following call will change Request store flags also | ||
| 755 | pEnroll->put_MyStoreFlags(lFlags); | ||
| 756 | break; | ||
| 757 | case SCA_CERT_STORENAME_CA: | ||
| 758 | pEnroll->get_CAStoreFlags(&lFlags); | ||
| 759 | lFlags &= ~CERT_SYSTEM_STORE_LOCATION_MASK; | ||
| 760 | lFlags |= dwFlags; | ||
| 761 | // following call will change Request store flags also | ||
| 762 | pEnroll->put_CAStoreFlags(lFlags); | ||
| 763 | break; | ||
| 764 | case SCA_CERT_STORENAME_REQUEST: | ||
| 765 | pEnroll->get_RequestStoreFlags(&lFlags); | ||
| 766 | lFlags &= ~CERT_SYSTEM_STORE_LOCATION_MASK; | ||
| 767 | lFlags |= dwFlags; | ||
| 768 | // following call will change Request store flags also | ||
| 769 | pEnroll->put_RequestStoreFlags(lFlags); | ||
| 770 | break; | ||
| 771 | case SCA_CERT_STORENAME_ROOT: | ||
| 772 | pEnroll->get_RootStoreFlags(&lFlags); | ||
| 773 | lFlags &= ~CERT_SYSTEM_STORE_LOCATION_MASK; | ||
| 774 | lFlags |= dwFlags; | ||
| 775 | // following call will change Request store flags also | ||
| 776 | pEnroll->put_RootStoreFlags(lFlags); | ||
| 777 | break; | ||
| 778 | default: | ||
| 779 | hr = E_FAIL; | ||
| 780 | return hr; | ||
| 781 | } | ||
| 782 | |||
| 783 | pEnroll->get_GenKeyFlags(&lFlags); | ||
| 784 | lFlags |= CRYPT_EXPORTABLE; | ||
| 785 | pEnroll->put_GenKeyFlags(lFlags); | ||
| 786 | |||
| 787 | pEnroll->put_KeySpec(AT_KEYEXCHANGE); | ||
| 788 | pEnroll->put_ProviderType(PROV_RSA_SCHANNEL); | ||
| 789 | pEnroll->put_DeleteRequestCert(TRUE); | ||
| 790 | |||
| 791 | *hEnroll = pEnroll; | ||
| 792 | return hr; | ||
| 793 | } | ||
| 794 | |||
| 795 | |||
| 796 | HRESULT RequestCertificate(LPCWSTR pwzName, INT iStore, INT iStoreLocation, | ||
| 797 | LPCWSTR wzComputerName, LPCWSTR wzDistinguishedName, LPCWSTR wzCertificateAuthority, | ||
| 798 | BSTR *pbstrCertificate) | ||
| 799 | { | ||
| 800 | if (pbstrCertificate == NULL) | ||
| 801 | return E_INVALIDARG; | ||
| 802 | |||
| 803 | HRESULT hr; | ||
| 804 | ICEnroll2 *pEnroll = NULL; | ||
| 805 | ICertRequest *pCertRequest = NULL; | ||
| 806 | BSTR bstrRequest = NULL; | ||
| 807 | LONG nDisposition; | ||
| 808 | |||
| 809 | BSTR bstrCertificateUsage = NULL; | ||
| 810 | BSTR bstrCertificateAttributes = NULL; | ||
| 811 | BSTR bstrCertificateAuthority = NULL; | ||
| 812 | |||
| 813 | // equivalent to: sprintf(bstrDistinguishedName, L"%s,CN=%s", wzDistinguishedName, wzComputerName); | ||
| 814 | DWORD cchComputerName = lstrlenW(wzComputerName); | ||
| 815 | DWORD cchDistinguishedName = lstrlenW(wzDistinguishedName); | ||
| 816 | CONST DWORD cchbstrDistinguishedName = 5 + cchComputerName + cchDistinguishedName; | ||
| 817 | BSTR bstrDistinguishedName = SysAllocStringLen(NULL, cchbstrDistinguishedName); | ||
| 818 | ExitOnNull(bstrDistinguishedName, hr, E_OUTOFMEMORY, "Failed to allocate space for distinguished name."); | ||
| 819 | ::StringCchCopyW((WCHAR*) bstrDistinguishedName, cchbstrDistinguishedName, wzDistinguishedName); | ||
| 820 | ::StringCchCatW((WCHAR*) bstrDistinguishedName, cchbstrDistinguishedName, L",CN="); | ||
| 821 | ::StringCchCatW((WCHAR*) bstrDistinguishedName, cchbstrDistinguishedName, wzComputerName); | ||
| 822 | |||
| 823 | bstrCertificateUsage = SysAllocString(WIDE(szOID_PKIX_KP_SERVER_AUTH)); | ||
| 824 | ExitOnNull(bstrCertificateUsage, hr, E_OUTOFMEMORY, "Failed to allocate space for Certificate Usage."); | ||
| 825 | bstrCertificateAttributes = SysAllocString(L"CertificateTemplate:WebServer"); | ||
| 826 | bstrCertificateAuthority = SysAllocString(wzCertificateAuthority); | ||
| 827 | ExitOnNull(bstrCertificateAuthority, hr, E_OUTOFMEMORY, "Failed to allocate space for Certificate Authority."); | ||
| 828 | |||
| 829 | hr = CreateEnroll(&pEnroll, iStore, iStoreLocation); | ||
| 830 | ExitOnFailure(hr, "failed CoCreateInstance IEnroll"); | ||
| 831 | |||
| 832 | hr = pEnroll->createPKCS10(bstrDistinguishedName, bstrCertificateUsage, &bstrRequest); | ||
| 833 | ExitOnFailure(hr, "failed createPKCS10"); | ||
| 834 | |||
| 835 | hr = CoCreateInstance(CLSID_CCertRequest, NULL, CLSCTX_INPROC_SERVER, IID_ICertRequest, (void **)&pCertRequest); | ||
| 836 | ExitOnFailure(hr, "failed CoCreateInstance ICertRequest"); | ||
| 837 | |||
| 838 | hr = pCertRequest->Submit(CR_IN_BASE64 | CR_IN_PKCS10, bstrRequest, bstrCertificateAttributes, bstrCertificateAuthority, &nDisposition); | ||
| 839 | ExitOnFailure(hr, "failed ICertRequest.Submit"); | ||
| 840 | |||
| 841 | hr = (nDisposition == CR_DISP_ISSUED) ? S_OK : E_FAIL; | ||
| 842 | ExitOnFailure(hr, "failed CR_DISP_ISSUED"); | ||
| 843 | |||
| 844 | hr = pCertRequest->GetCertificate(CR_OUT_BASE64, pbstrCertificate); | ||
| 845 | ExitOnFailure(hr, "failed ICertRequest.GetCertificate"); | ||
| 846 | |||
| 847 | // save the certificate in place, cannot be passed to a deferred custom action | ||
| 848 | hr = pEnroll->acceptPKCS7(*pbstrCertificate); | ||
| 849 | ExitOnFailure(hr, "failed accept certificate into MY store"); | ||
| 850 | |||
| 851 | LExit: | ||
| 852 | ReleaseObject(pCertRequest); | ||
| 853 | ReleaseBSTR(bstrRequest); | ||
| 854 | ReleaseObject(pEnroll); | ||
| 855 | ReleaseBSTR(bstrCertificateAuthority); | ||
| 856 | ReleaseBSTR(bstrCertificateAttributes); | ||
| 857 | ReleaseBSTR(bstrDistinguishedName); | ||
| 858 | |||
| 859 | return hr; | ||
| 860 | } | ||
| 861 | |||
| 862 | |||
| 863 | VOID ParseCertificateAuthority(__in LPCWSTR wzCertificateAuthorityOrig, __out LPWSTR *pwzBuffer, __out LPWSTR **hwzCAArray, __out int *piCAArray) | ||
| 864 | { | ||
| 865 | // @asAuthorities = split /;/, $sAuthority; | ||
| 866 | CONST WCHAR wchDelimiter = L';'; | ||
| 867 | |||
| 868 | // copy constant into a buffer | ||
| 869 | Assert(wzCertificateAuthorityOrig); | ||
| 870 | |||
| 871 | INT cchCA = lstrlenW(wzCertificateAuthorityOrig) + 1; | ||
| 872 | WCHAR* wzBuffer = new WCHAR[cchCA]; | ||
| 873 | if (!wzBuffer) | ||
| 874 | return; | ||
| 875 | |||
| 876 | ::StringCchCopyW(wzBuffer, cchCA, wzCertificateAuthorityOrig); | ||
| 877 | |||
| 878 | // determine the number of strings in the field | ||
| 879 | int iCAArray = 1; | ||
| 880 | int i; | ||
| 881 | for (i = 0; i < cchCA; ++i) | ||
| 882 | { | ||
| 883 | if (wzBuffer[i] == wchDelimiter) | ||
| 884 | ++iCAArray; | ||
| 885 | } | ||
| 886 | LPWSTR *pwzCAArray = (LPWSTR*) new BYTE[iCAArray * sizeof(LPWSTR)]; | ||
| 887 | if (!pwzCAArray) | ||
| 888 | { | ||
| 889 | return; | ||
| 890 | } | ||
| 891 | |||
| 892 | pwzCAArray[0] = wzBuffer; | ||
| 893 | iCAArray = 0; | ||
| 894 | for (i = 0; i < cchCA; ++i) | ||
| 895 | { | ||
| 896 | if (wzBuffer[i] != wchDelimiter) | ||
| 897 | continue; | ||
| 898 | wzBuffer[i] = 0; // convert buffer into MULTISZ | ||
| 899 | pwzCAArray[iCAArray] = &wzBuffer[i+1]; | ||
| 900 | ++iCAArray; | ||
| 901 | } | ||
| 902 | |||
| 903 | *pwzBuffer = wzBuffer; | ||
| 904 | *hwzCAArray = pwzCAArray; | ||
| 905 | *piCAArray = iCAArray; | ||
| 906 | } | ||
| 907 | |||
| 908 | |||
| 909 | HRESULT ScaSslExistingCertificateByBinaryData(INT iStore, INT iStoreLocation, BYTE* pwzData, DWORD cchData) | ||
| 910 | { | ||
| 911 | HRESULT hr = S_FALSE; | ||
| 912 | HCERTSTORE hCertStore = NULL; | ||
| 913 | PCCERT_CONTEXT pCertCtx = NULL, pCertCtxExisting = NULL; | ||
| 914 | DWORD dwFlags = 0; | ||
| 915 | LPCWSTR wzStore = StoreMapping(iStore); | ||
| 916 | CERT_BLOB blob; | ||
| 917 | |||
| 918 | dwFlags = iStoreLocation << CERT_SYSTEM_STORE_LOCATION_SHIFT; | ||
| 919 | hCertStore = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, NULL, dwFlags, wzStore); | ||
| 920 | MessageExitOnNullWithLastError(hCertStore, hr, msierrCERTFailedOpen, "failed to open certificate store, OK on uninstall"); | ||
| 921 | |||
| 922 | blob.pbData = pwzData; | ||
| 923 | blob.cbData = cchData; | ||
| 924 | |||
| 925 | if (!::CryptQueryObject(CERT_QUERY_OBJECT_BLOB, &blob, CERT_QUERY_CONTENT_FLAG_ALL, CERT_QUERY_FORMAT_FLAG_ALL, | ||
| 926 | 0, NULL, NULL, NULL, NULL, NULL, (LPCVOID*)&pCertCtx)) | ||
| 927 | ExitOnLastError(hr, "failed to parse the certificate blob, OK on uninstall"); | ||
| 928 | |||
| 929 | pCertCtxExisting = CertFindCertificateInStore( | ||
| 930 | hCertStore, | ||
| 931 | PKCS_7_ASN_ENCODING | X509_ASN_ENCODING, | ||
| 932 | 0, | ||
| 933 | CERT_FIND_EXISTING, | ||
| 934 | pCertCtx, | ||
| 935 | NULL); | ||
| 936 | |||
| 937 | if (pCertCtxExisting) | ||
| 938 | { | ||
| 939 | hr = S_OK; | ||
| 940 | } | ||
| 941 | |||
| 942 | LExit: | ||
| 943 | if (pCertCtx) | ||
| 944 | { | ||
| 945 | CertFreeCertificateContext(pCertCtx); | ||
| 946 | pCertCtx = NULL; | ||
| 947 | } | ||
| 948 | if (pCertCtxExisting) | ||
| 949 | { | ||
| 950 | CertFreeCertificateContext(pCertCtxExisting); | ||
| 951 | pCertCtxExisting = NULL; | ||
| 952 | } | ||
| 953 | if (hCertStore) | ||
| 954 | { | ||
| 955 | CertCloseStore(hCertStore, 0); | ||
| 956 | hCertStore = NULL; | ||
| 957 | } | ||
| 958 | |||
| 959 | return hr; | ||
| 960 | } | ||
| 961 | |||
| 962 | |||
| 963 | HRESULT ScaSslExistingCertificateByName(LPCWSTR pwzName, INT iStore, INT iStoreLocation, | ||
| 964 | BSTR* pbstrCertificate, DWORD* pcbCertificate, BYTE* pbaHashBuffer) | ||
| 965 | { | ||
| 966 | HRESULT hr = S_FALSE; | ||
| 967 | HCERTSTORE hSystemStore = NULL; | ||
| 968 | PCCERT_CONTEXT pTargetCert = NULL; | ||
| 969 | WCHAR wzFriendlyName[MAX_PATH] = {0}; | ||
| 970 | DWORD dwFriendlyNameLen = sizeof(wzFriendlyName); | ||
| 971 | |||
| 972 | // Call CertOpenStore to open the CA store. | ||
| 973 | hSystemStore = CertOpenStore( | ||
| 974 | CERT_STORE_PROV_SYSTEM_REGISTRY, | ||
| 975 | 0, | ||
| 976 | NULL, | ||
| 977 | (iStoreLocation << CERT_SYSTEM_STORE_LOCATION_SHIFT) | CERT_STORE_OPEN_EXISTING_FLAG, | ||
| 978 | StoreMapping(iStore)); | ||
| 979 | if (hSystemStore == NULL) | ||
| 980 | ExitFunction(); | ||
| 981 | |||
| 982 | // Get a particular certificate using CertFindCertificateInStore. | ||
| 983 | pTargetCert = CertFindCertificateInStore( | ||
| 984 | hSystemStore, | ||
| 985 | PKCS_7_ASN_ENCODING | X509_ASN_ENCODING, | ||
| 986 | 0, | ||
| 987 | CERT_FIND_ANY, | ||
| 988 | NULL, | ||
| 989 | NULL); | ||
| 990 | while (pTargetCert != NULL) | ||
| 991 | { | ||
| 992 | if ((CertGetCertificateContextProperty(pTargetCert, CERT_FRIENDLY_NAME_PROP_ID, | ||
| 993 | (BYTE*)wzFriendlyName, &dwFriendlyNameLen)) && | ||
| 994 | lstrcmpW(wzFriendlyName, pwzName) == 0) | ||
| 995 | { | ||
| 996 | // pTargetCert is a pointer to the desired certificate. | ||
| 997 | // Check the certificate's validity. | ||
| 998 | switch (CertVerifyTimeValidity( | ||
| 999 | NULL, | ||
| 1000 | pTargetCert->pCertInfo)) | ||
| 1001 | { | ||
| 1002 | case 1: | ||
| 1003 | // Certificate is expired | ||
| 1004 | WcaLog(LOGMSG_STANDARD, "The SSL certificate has expired"); | ||
| 1005 | // always remove it | ||
| 1006 | { | ||
| 1007 | PCCERT_CONTEXT pDupCertContext = CertDuplicateCertificateContext(pTargetCert); | ||
| 1008 | if (pDupCertContext && CertDeleteCertificateFromStore(pDupCertContext)) | ||
| 1009 | { | ||
| 1010 | WcaLog(LOGMSG_STANDARD, "A SSL certificate has removed"); | ||
| 1011 | } | ||
| 1012 | } | ||
| 1013 | break; | ||
| 1014 | case 0: | ||
| 1015 | // Certificate is valid | ||
| 1016 | WcaLog(LOGMSG_STANDARD, "The SSL certificate is valid"); | ||
| 1017 | hr = S_OK; | ||
| 1018 | if (pbaHashBuffer) | ||
| 1019 | { | ||
| 1020 | // if the certificate already exists and is valid, use that one | ||
| 1021 | DWORD dwHashSize = CB_CERTIFICATE_HASH; | ||
| 1022 | hr = CertGetCertificateContextProperty(pTargetCert, CERT_SHA1_HASH_PROP_ID, (VOID*)pbaHashBuffer, &dwHashSize) | ||
| 1023 | ? S_OK : E_FAIL; | ||
| 1024 | ExitOnFailure(hr, "failed CertGetCertificateContextProperty CERT_SHA1_HASH_PROP_ID"); | ||
| 1025 | Assert(pbstrCertificate); | ||
| 1026 | Assert(pcbCertificate); | ||
| 1027 | ReleaseBSTR(*pbstrCertificate); | ||
| 1028 | |||
| 1029 | *pbstrCertificate = SysAllocStringByteLen((LPCSTR)(pTargetCert->pbCertEncoded), pTargetCert->cbCertEncoded); | ||
| 1030 | *pcbCertificate = pTargetCert->cbCertEncoded; | ||
| 1031 | } | ||
| 1032 | ExitFunction(); | ||
| 1033 | break; | ||
| 1034 | default: | ||
| 1035 | // Certificate not valid yet, ignore it | ||
| 1036 | WcaLog(LOGMSG_STANDARD, "The SSL certificate is not valid"); | ||
| 1037 | break; | ||
| 1038 | } | ||
| 1039 | } | ||
| 1040 | pTargetCert = CertFindCertificateInStore( | ||
| 1041 | hSystemStore, | ||
| 1042 | PKCS_7_ASN_ENCODING | X509_ASN_ENCODING, | ||
| 1043 | 0, | ||
| 1044 | CERT_FIND_ANY, | ||
| 1045 | NULL, | ||
| 1046 | pTargetCert); | ||
| 1047 | wzFriendlyName[0] = 0; | ||
| 1048 | dwFriendlyNameLen = sizeof(wzFriendlyName); | ||
| 1049 | } | ||
| 1050 | |||
| 1051 | LExit: | ||
| 1052 | // Clean up memory and quit. | ||
| 1053 | if (pTargetCert) | ||
| 1054 | { | ||
| 1055 | CertFreeCertificateContext(pTargetCert); | ||
| 1056 | pTargetCert = NULL; | ||
| 1057 | } | ||
| 1058 | if (hSystemStore) | ||
| 1059 | { | ||
| 1060 | CertCloseStore(hSystemStore, CERT_CLOSE_STORE_CHECK_FLAG); | ||
| 1061 | hSystemStore = NULL; | ||
| 1062 | } | ||
| 1063 | |||
| 1064 | return hr; | ||
| 1065 | } | ||
| 1066 | |||
| 1067 | |||
| 1068 | HRESULT ScaSslNewCertificate(LPCWSTR pwzName, INT iStore, INT iStoreLocation, LPCWSTR wzComputerName, LPCWSTR wzDistinguishedName, LPCWSTR wzCertificateAuthorityOrig, | ||
| 1069 | BSTR* pbstrCertificate, DWORD* pcbCertificate, BYTE* pbaHashBuffer) | ||
| 1070 | { | ||
| 1071 | |||
| 1072 | if (pbstrCertificate == NULL) | ||
| 1073 | return E_INVALIDARG; | ||
| 1074 | |||
| 1075 | HRESULT hr = S_OK; | ||
| 1076 | LPWSTR wzCABuffer = NULL; | ||
| 1077 | LPWSTR *wzCAArray = NULL; | ||
| 1078 | int iCAArray = 0; | ||
| 1079 | |||
| 1080 | // otherwise call the CA for one | ||
| 1081 | ParseCertificateAuthority(wzCertificateAuthorityOrig, &wzCABuffer, &wzCAArray, &iCAArray); | ||
| 1082 | |||
| 1083 | // try each authority three times | ||
| 1084 | for (int i = 0; i < 3 * iCAArray; ++i) | ||
| 1085 | { | ||
| 1086 | LPCWSTR wzCA = wzCAArray[i % iCAArray]; | ||
| 1087 | if (NULL == wzCA || NULL == wzCA[0]) continue; | ||
| 1088 | WcaLog(LOGMSG_STANDARD, "Requesting SSL certificate from %ls", wzCA); | ||
| 1089 | hr = RequestCertificate(pwzName, iStore, iStoreLocation, wzComputerName, wzDistinguishedName, wzCA, pbstrCertificate); | ||
| 1090 | if (hr == S_OK && pbstrCertificate) | ||
| 1091 | { | ||
| 1092 | // set the friendly name | ||
| 1093 | CRYPT_HASH_BLOB hblob; | ||
| 1094 | CERT_BLOB blob; | ||
| 1095 | HCERTSTORE hCertStore = NULL; | ||
| 1096 | PCCERT_CONTEXT pCertCtxExisting = NULL; | ||
| 1097 | |||
| 1098 | blob.pbData = (BYTE*)pwzName; | ||
| 1099 | blob.cbData = (lstrlenW(pwzName) + 1) * sizeof(pwzName[0]); // including terminating null | ||
| 1100 | |||
| 1101 | *pcbCertificate = SysStringByteLen(*pbstrCertificate); | ||
| 1102 | hr = CertificateToHash(*pbstrCertificate, pbaHashBuffer); | ||
| 1103 | ExitOnFailure(hr, "failed to CertificateToHash for an existing certificate"); | ||
| 1104 | |||
| 1105 | hblob.pbData = pbaHashBuffer; | ||
| 1106 | hblob.cbData = CB_CERTIFICATE_HASH; | ||
| 1107 | |||
| 1108 | hCertStore = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, NULL, (iStoreLocation << CERT_SYSTEM_STORE_LOCATION_SHIFT), StoreMapping(iStore)); | ||
| 1109 | MessageExitOnNullWithLastError(hCertStore, hr, msierrCERTFailedOpen, "failed to open certificate store"); | ||
| 1110 | |||
| 1111 | pCertCtxExisting = CertFindCertificateInStore( | ||
| 1112 | hCertStore, | ||
| 1113 | PKCS_7_ASN_ENCODING | X509_ASN_ENCODING, | ||
| 1114 | 0, | ||
| 1115 | CERT_FIND_HASH, | ||
| 1116 | &hblob, | ||
| 1117 | NULL); | ||
| 1118 | |||
| 1119 | if (pCertCtxExisting) | ||
| 1120 | { | ||
| 1121 | CertSetCertificateContextProperty( | ||
| 1122 | pCertCtxExisting, | ||
| 1123 | CERT_FRIENDLY_NAME_PROP_ID, | ||
| 1124 | 0, | ||
| 1125 | &blob); | ||
| 1126 | } | ||
| 1127 | |||
| 1128 | if (pCertCtxExisting) | ||
| 1129 | { | ||
| 1130 | CertFreeCertificateContext(pCertCtxExisting); | ||
| 1131 | pCertCtxExisting = NULL; | ||
| 1132 | } | ||
| 1133 | if (hCertStore) | ||
| 1134 | { | ||
| 1135 | CertCloseStore(hCertStore, 0); | ||
| 1136 | hCertStore = NULL; | ||
| 1137 | } | ||
| 1138 | ExitFunction(); | ||
| 1139 | } | ||
| 1140 | if (pbstrCertificate && *pbstrCertificate) | ||
| 1141 | { | ||
| 1142 | SysFreeString(*pbstrCertificate); | ||
| 1143 | pbstrCertificate = NULL; | ||
| 1144 | } | ||
| 1145 | } | ||
| 1146 | hr = E_FAIL; | ||
| 1147 | ExitOnFailure(hr, "failed to RequestCertificate"); | ||
| 1148 | |||
| 1149 | LExit: | ||
| 1150 | if (wzCABuffer) | ||
| 1151 | { | ||
| 1152 | delete wzCABuffer; | ||
| 1153 | } | ||
| 1154 | if (wzCAArray) | ||
| 1155 | { | ||
| 1156 | delete wzCAArray; | ||
| 1157 | } | ||
| 1158 | |||
| 1159 | return hr; | ||
| 1160 | } | ||
| 1161 | |||
| 1162 | |||
| 1163 | HRESULT ScaGetCertificateByRequest(LPCWSTR pwzName, BOOL fIsInstalling, BOOL fIsUninstalling, | ||
| 1164 | INT iStore, INT iStoreLocation, | ||
| 1165 | LPCWSTR wzDistinguishedName, LPCWSTR wzCA, | ||
| 1166 | BSTR* pbstrCertificate, DWORD* pcbCertificate, BYTE* pbaHashBuffer) | ||
| 1167 | { | ||
| 1168 | HRESULT hr = S_OK; | ||
| 1169 | WCHAR wzComputerName[MAX_COMPUTER_NAME] = {0}; | ||
| 1170 | WCHAR* pwzData = NULL; | ||
| 1171 | DWORD cchData = 0; | ||
| 1172 | |||
| 1173 | // override %COMPUTERNAME% with DOMAINNAME property | ||
| 1174 | hr = WcaGetProperty( L"DOMAINNAME", &pwzData); | ||
| 1175 | ExitOnFailure(hr, "Failed to get Property DOMAINNAME"); | ||
| 1176 | if (*pwzData) | ||
| 1177 | { | ||
| 1178 | // if DOMAINNAME is set, use it | ||
| 1179 | ::StringCchCopyW(wzComputerName, MAX_COMPUTER_NAME, pwzData); | ||
| 1180 | } | ||
| 1181 | else | ||
| 1182 | { | ||
| 1183 | // otherwise get the intranet name given by %COMPUTERNAME% | ||
| 1184 | GetEnvironmentVariableW(L"COMPUTERNAME", wzComputerName, MAX_COMPUTER_NAME); | ||
| 1185 | } | ||
| 1186 | |||
| 1187 | hr = ScaSslExistingCertificateByName(pwzName, iStore, iStoreLocation, pbstrCertificate, pcbCertificate, pbaHashBuffer); | ||
| 1188 | ExitOnFailure(hr, "Failed ScaSslExistingCertificateByName"); | ||
| 1189 | if (S_OK != hr) | ||
| 1190 | { | ||
| 1191 | if (!fIsUninstalling && fIsInstalling) | ||
| 1192 | { | ||
| 1193 | // if no existing cert and not on uninstall, hit the authority | ||
| 1194 | WcaLog(LOGMSG_STANDARD, "Adding certificate: requested, %ls", wzDistinguishedName); | ||
| 1195 | hr = ScaSslNewCertificate(pwzName, iStore, iStoreLocation, wzComputerName, wzDistinguishedName, wzCA, | ||
| 1196 | pbstrCertificate, pcbCertificate, pbaHashBuffer); | ||
| 1197 | ExitOnFailure(hr, "Failed ScaSslNewCertificate"); | ||
| 1198 | } | ||
| 1199 | else | ||
| 1200 | { | ||
| 1201 | // if no existing cert and uninstall | ||
| 1202 | hr = S_OK; | ||
| 1203 | } | ||
| 1204 | } | ||
| 1205 | |||
| 1206 | LExit: | ||
| 1207 | ReleaseStr(pwzData); | ||
| 1208 | |||
| 1209 | return hr; | ||
| 1210 | } | ||
| 1211 | |||
| 1212 | |||
| 1213 | HRESULT ScaInstallCertificateByContext(LPCWSTR pwzName, INT iStore, INT iStoreLocation, | ||
| 1214 | PCCERT_CONTEXT pCertContext) | ||
| 1215 | { | ||
| 1216 | HRESULT hr = S_OK; | ||
| 1217 | HCERTSTORE hCertStore = NULL; | ||
| 1218 | DWORD dwFlags = iStoreLocation << CERT_SYSTEM_STORE_LOCATION_SHIFT; | ||
| 1219 | CERT_BLOB blob; | ||
| 1220 | |||
| 1221 | hCertStore = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, NULL, dwFlags, StoreMapping(iStore)); | ||
| 1222 | if (hCertStore == NULL) | ||
| 1223 | MessageExitOnLastError(hr, msierrCERTFailedOpen, "failed to open certificate store"); | ||
| 1224 | |||
| 1225 | blob.pbData = (BYTE*)pwzName; | ||
| 1226 | blob.cbData = (lstrlenW(pwzName) + 1) * sizeof(pwzName[0]); // including terminating null | ||
| 1227 | CertSetCertificateContextProperty( | ||
| 1228 | pCertContext, | ||
| 1229 | CERT_FRIENDLY_NAME_PROP_ID, | ||
| 1230 | 0, | ||
| 1231 | &blob); | ||
| 1232 | |||
| 1233 | if (!CertAddCertificateContextToStore( | ||
| 1234 | hCertStore, | ||
| 1235 | pCertContext, | ||
| 1236 | CERT_STORE_ADD_REPLACE_EXISTING, | ||
| 1237 | NULL)) | ||
| 1238 | { | ||
| 1239 | hr = E_FAIL; | ||
| 1240 | MessageExitOnLastError(hr, msierrCERTFailedAdd, "failed to add certificate to the store"); | ||
| 1241 | } | ||
| 1242 | |||
| 1243 | LExit: | ||
| 1244 | if (hCertStore) | ||
| 1245 | { | ||
| 1246 | CertCloseStore(hCertStore, 0); | ||
| 1247 | hCertStore = NULL; | ||
| 1248 | } | ||
| 1249 | |||
| 1250 | return hr; | ||
| 1251 | } | ||
| 1252 | |||
| 1253 | |||
| 1254 | HRESULT ScaGetCertificateByPath(LPCWSTR pwzName, BOOL fIsInstalling, BOOL fIsUninstalling, | ||
| 1255 | INT iStore, INT iStoreLocation, LPCWSTR wzSslCertificate, LPCWSTR wzPFXPassword, | ||
| 1256 | BSTR* pbstrCertificate, DWORD* pcbCertificate, BYTE* pbaHashBuffer) | ||
| 1257 | { | ||
| 1258 | Assert(wzSslCertificate); | ||
| 1259 | HRESULT hr = S_OK; | ||
| 1260 | PCCERT_CONTEXT pCertContext = NULL; | ||
| 1261 | DWORD dwEncodingType = 0; | ||
| 1262 | DWORD dwContentType = 0; | ||
| 1263 | DWORD dwFormatType = 0; | ||
| 1264 | DWORD dwHashSize = CB_CERTIFICATE_HASH; | ||
| 1265 | HANDLE hPfxFile = INVALID_HANDLE_VALUE; | ||
| 1266 | CRYPT_DATA_BLOB blob; | ||
| 1267 | |||
| 1268 | blob.pbData = NULL; | ||
| 1269 | blob.cbData = 0; | ||
| 1270 | |||
| 1271 | if (wzSslCertificate && wzSslCertificate[0] != 0) | ||
| 1272 | { | ||
| 1273 | if (!::CryptQueryObject(CERT_QUERY_OBJECT_FILE, (LPVOID)wzSslCertificate, CERT_QUERY_CONTENT_FLAG_ALL, CERT_QUERY_FORMAT_FLAG_ALL, | ||
| 1274 | 0, &dwEncodingType, &dwContentType, &dwFormatType, NULL, NULL, (LPCVOID*)&pCertContext)) | ||
| 1275 | hr = fIsUninstalling ? S_FALSE : HRESULT_FROM_WIN32(::GetLastError()); // don't fail on uninstall | ||
| 1276 | ExitOnFailure(hr, "failed CryptQueryObject"); | ||
| 1277 | } | ||
| 1278 | else | ||
| 1279 | { | ||
| 1280 | hr = S_FALSE; | ||
| 1281 | ExitFunction(); | ||
| 1282 | } | ||
| 1283 | |||
| 1284 | if (!pCertContext) | ||
| 1285 | { | ||
| 1286 | // this is a pfx? | ||
| 1287 | // make sure to exit this block of code properly for clean up blob.pbData | ||
| 1288 | if (dwContentType & CERT_QUERY_CONTENT_PFX) | ||
| 1289 | { | ||
| 1290 | DWORD iSize = 0, iReadSize = 0; | ||
| 1291 | HCERTSTORE hPfxCertStore = NULL; | ||
| 1292 | |||
| 1293 | hPfxFile = ::CreateFileW(wzSslCertificate, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, | ||
| 1294 | NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); | ||
| 1295 | hr = (hPfxFile != INVALID_HANDLE_VALUE) ? S_OK : E_FAIL; | ||
| 1296 | ExitOnFailure(hr, "failed CryptQueryObject, file handle is null"); | ||
| 1297 | iSize = ::GetFileSize(hPfxFile, NULL); | ||
| 1298 | hr = (iSize > 0) ? S_OK : E_FAIL; | ||
| 1299 | ExitOnFailure(hr, "failed CryptQueryObject, file size is 0"); | ||
| 1300 | blob.pbData = new BYTE[iSize]; | ||
| 1301 | blob.cbData = iSize; | ||
| 1302 | hr = (blob.pbData) ? S_OK : E_FAIL; | ||
| 1303 | ExitOnFailure(hr, "out of memory for blob"); | ||
| 1304 | |||
| 1305 | if (::ReadFile(hPfxFile, (LPVOID)blob.pbData, iSize, &iReadSize, NULL)) | ||
| 1306 | { | ||
| 1307 | hPfxCertStore = PFXImportCertStore((CRYPT_DATA_BLOB*)&blob, wzPFXPassword, | ||
| 1308 | (iStoreLocation == SCA_CERTSYSTEMSTORE_CURRENTUSER) ? CRYPT_USER_KEYSET : CRYPT_MACHINE_KEYSET); | ||
| 1309 | if (hPfxCertStore) | ||
| 1310 | { | ||
| 1311 | pCertContext = CertEnumCertificatesInStore(hPfxCertStore, NULL); | ||
| 1312 | // work only with the first certificate in pfx | ||
| 1313 | if (pCertContext) | ||
| 1314 | { | ||
| 1315 | hr = CertGetCertificateContextProperty(pCertContext, CERT_SHA1_HASH_PROP_ID, (VOID*)pbaHashBuffer, &dwHashSize) | ||
| 1316 | ? S_OK : E_FAIL; | ||
| 1317 | ExitOnFailure(hr, "failed CertGetCertificateContextProperty CERT_SHA1_HASH_PROP_ID"); | ||
| 1318 | ReleaseBSTR(*pbstrCertificate); | ||
| 1319 | |||
| 1320 | *pbstrCertificate = SysAllocStringByteLen((LPCSTR)(pCertContext->pbCertEncoded), pCertContext->cbCertEncoded); | ||
| 1321 | *pcbCertificate = pCertContext->cbCertEncoded; | ||
| 1322 | if (fIsInstalling) | ||
| 1323 | { | ||
| 1324 | // install the certificate, cannot defer because the data required cannot be passed | ||
| 1325 | hr = ScaInstallCertificateByContext(pwzName, iStore, iStoreLocation, pCertContext); | ||
| 1326 | } | ||
| 1327 | } | ||
| 1328 | else | ||
| 1329 | hr = E_FAIL; | ||
| 1330 | } | ||
| 1331 | else | ||
| 1332 | hr = E_FAIL; | ||
| 1333 | } | ||
| 1334 | else | ||
| 1335 | hr = E_FAIL; | ||
| 1336 | } | ||
| 1337 | else | ||
| 1338 | { | ||
| 1339 | ExitOnFailure(hr = E_FAIL, "failed CryptQueryObject, unknown data"); | ||
| 1340 | } | ||
| 1341 | } | ||
| 1342 | else | ||
| 1343 | { | ||
| 1344 | // return cert and its hash | ||
| 1345 | hr = CertGetCertificateContextProperty(pCertContext, CERT_SHA1_HASH_PROP_ID, (VOID*)pbaHashBuffer, &dwHashSize) | ||
| 1346 | ? S_OK : E_FAIL; | ||
| 1347 | ExitOnFailure(hr, "failed CertGetCertificateContextProperty CERT_SHA1_HASH_PROP_ID"); | ||
| 1348 | ReleaseBSTR(*pbstrCertificate); | ||
| 1349 | |||
| 1350 | *pbstrCertificate = SysAllocStringByteLen((LPCSTR)(pCertContext->pbCertEncoded), pCertContext->cbCertEncoded); | ||
| 1351 | *pcbCertificate = pCertContext->cbCertEncoded; | ||
| 1352 | if (fIsInstalling) | ||
| 1353 | { | ||
| 1354 | // install the certificate, cannot defer because the data required cannot be passed | ||
| 1355 | hr = ScaInstallCertificateByContext(pwzName, iStore, iStoreLocation, pCertContext); | ||
| 1356 | } | ||
| 1357 | } | ||
| 1358 | |||
| 1359 | LExit: | ||
| 1360 | if (pCertContext) | ||
| 1361 | { | ||
| 1362 | CertFreeCertificateContext(pCertContext); | ||
| 1363 | pCertContext = NULL; | ||
| 1364 | } | ||
| 1365 | if (hPfxFile != INVALID_HANDLE_VALUE) | ||
| 1366 | { | ||
| 1367 | CloseHandle(hPfxFile); | ||
| 1368 | hPfxFile = INVALID_HANDLE_VALUE; | ||
| 1369 | } | ||
| 1370 | if (blob.pbData) | ||
| 1371 | { | ||
| 1372 | delete [] blob.pbData; | ||
| 1373 | blob.pbData = NULL; | ||
| 1374 | blob.cbData = 0; | ||
| 1375 | } | ||
| 1376 | |||
| 1377 | return hr; | ||
| 1378 | } | ||
| 1379 | |||
| 1380 | |||
| 1381 | HRESULT ScaInstallCertificateByBinaryData(BOOL fAddCert, INT iStore, INT iStoreLocation, LPCWSTR wzName, BYTE* pwzData, DWORD cchData, | ||
| 1382 | LPCWSTR wzPFXPassword) | ||
| 1383 | { | ||
| 1384 | Assert(wzName); | ||
| 1385 | Assert(pwzData); | ||
| 1386 | Assert(cchData); | ||
| 1387 | HRESULT hr = S_OK; | ||
| 1388 | HCERTSTORE hCertStore = NULL, hPfxCertStore = NULL; | ||
| 1389 | PCCERT_CONTEXT pCertCtx = NULL, pCertCtxExisting = NULL; | ||
| 1390 | DWORD dwFlags, dwEncodingType, dwContentType, dwFormatType; | ||
| 1391 | CERT_BLOB blob; | ||
| 1392 | LPCWSTR wzStore = StoreMapping(iStore); | ||
| 1393 | |||
| 1394 | dwFlags = iStoreLocation << CERT_SYSTEM_STORE_LOCATION_SHIFT; | ||
| 1395 | hCertStore = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, NULL, dwFlags, wzStore); | ||
| 1396 | MessageExitOnNullWithLastError(hCertStore, hr, msierrCERTFailedOpen, "failed to open certificate store"); | ||
| 1397 | |||
| 1398 | blob.pbData = pwzData; | ||
| 1399 | blob.cbData = cchData; | ||
| 1400 | |||
| 1401 | if (!::CryptQueryObject(CERT_QUERY_OBJECT_BLOB, &blob, CERT_QUERY_CONTENT_FLAG_ALL, CERT_QUERY_FORMAT_FLAG_ALL, | ||
| 1402 | 0, &dwEncodingType, &dwContentType, &dwFormatType, NULL, NULL, (LPCVOID*)&pCertCtx)) | ||
| 1403 | ExitOnLastError(hr, "failed to parse the certificate blob"); | ||
| 1404 | ExitOnNull(pCertCtx, hr, E_UNEXPECTED, "failed to parse the certificate blob"); | ||
| 1405 | |||
| 1406 | blob.pbData = (BYTE*)wzName; | ||
| 1407 | blob.cbData = (lstrlenW(wzName) + 1) * sizeof(wzName[0]); // including terminating null | ||
| 1408 | |||
| 1409 | CertSetCertificateContextProperty( | ||
| 1410 | pCertCtx, | ||
| 1411 | CERT_FRIENDLY_NAME_PROP_ID, | ||
| 1412 | 0, | ||
| 1413 | &blob); | ||
| 1414 | |||
| 1415 | if (fAddCert) | ||
| 1416 | { | ||
| 1417 | // Add | ||
| 1418 | WcaLog(LOGMSG_STANDARD, "Adding certificate: binary name, %ls", wzName); | ||
| 1419 | if (!CertAddCertificateContextToStore( | ||
| 1420 | hCertStore, | ||
| 1421 | pCertCtx, | ||
| 1422 | CERT_STORE_ADD_REPLACE_EXISTING, | ||
| 1423 | NULL)) | ||
| 1424 | { | ||
| 1425 | hr = E_FAIL; | ||
| 1426 | MessageExitOnLastError(hr, msierrCERTFailedAdd, "failed to add certificate to the store"); | ||
| 1427 | } | ||
| 1428 | } | ||
| 1429 | else | ||
| 1430 | { | ||
| 1431 | // Delete | ||
| 1432 | WcaLog(LOGMSG_STANDARD, "Deleting certificate provided: binary name, %ls", wzName); | ||
| 1433 | pCertCtxExisting = CertFindCertificateInStore( | ||
| 1434 | hCertStore, | ||
| 1435 | PKCS_7_ASN_ENCODING | X509_ASN_ENCODING, | ||
| 1436 | 0, | ||
| 1437 | CERT_FIND_EXISTING, | ||
| 1438 | pCertCtx, | ||
| 1439 | NULL); | ||
| 1440 | |||
| 1441 | if (pCertCtxExisting) | ||
| 1442 | { | ||
| 1443 | if (!CertDeleteCertificateFromStore(pCertCtxExisting)) | ||
| 1444 | { | ||
| 1445 | ExitOnLastError(hr, "failed to delete certificate"); | ||
| 1446 | } | ||
| 1447 | else | ||
| 1448 | { | ||
| 1449 | pCertCtxExisting = NULL; | ||
| 1450 | } | ||
| 1451 | } | ||
| 1452 | } | ||
| 1453 | |||
| 1454 | LExit: | ||
| 1455 | if (pCertCtx) | ||
| 1456 | { | ||
| 1457 | CertFreeCertificateContext(pCertCtx); | ||
| 1458 | pCertCtx = NULL; | ||
| 1459 | } | ||
| 1460 | if (pCertCtxExisting) | ||
| 1461 | { | ||
| 1462 | CertFreeCertificateContext(pCertCtxExisting); | ||
| 1463 | pCertCtxExisting = NULL; | ||
| 1464 | } | ||
| 1465 | // order is important for store | ||
| 1466 | if (hCertStore) | ||
| 1467 | { | ||
| 1468 | CertCloseStore(hCertStore, 0); | ||
| 1469 | hCertStore = NULL; | ||
| 1470 | } | ||
| 1471 | if (hPfxCertStore) | ||
| 1472 | { | ||
| 1473 | CertCloseStore(hPfxCertStore, 0); | ||
| 1474 | hPfxCertStore = NULL; | ||
| 1475 | } | ||
| 1476 | |||
| 1477 | return hr; | ||
| 1478 | } | ||
| 1479 | */ | ||
diff --git a/src/ca/scacert.h b/src/ca/scacert.h new file mode 100644 index 00000000..baa6fb8e --- /dev/null +++ b/src/ca/scacert.h | |||
| @@ -0,0 +1,22 @@ | |||
| 1 | #pragma once | ||
| 2 | // 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. | ||
| 3 | |||
| 4 | |||
| 5 | #define CB_CERTIFICATE_HASH 20 | ||
| 6 | |||
| 7 | // Certificate.Attribute | ||
| 8 | enum SCA_CERT_ATTRIBUTES | ||
| 9 | { | ||
| 10 | SCA_CERT_ATTRIBUTE_DEFAULT = 0, | ||
| 11 | SCA_CERT_ATTRIBUTE_REQUEST = 1, | ||
| 12 | SCA_CERT_ATTRIBUTE_BINARYDATA = 2, | ||
| 13 | SCA_CERT_ATTRIBUTE_OVERWRITE = 4, | ||
| 14 | }; | ||
| 15 | |||
| 16 | |||
| 17 | // Certificate.StoreLocation | ||
| 18 | enum SCA_CERTSYSTEMSTORE | ||
| 19 | { | ||
| 20 | SCA_CERTSYSTEMSTORE_CURRENTUSER = 1, | ||
| 21 | SCA_CERTSYSTEMSTORE_LOCALMACHINE = 2, | ||
| 22 | }; | ||
diff --git a/src/ca/scacertexec.cpp b/src/ca/scacertexec.cpp new file mode 100644 index 00000000..3864659f --- /dev/null +++ b/src/ca/scacertexec.cpp | |||
| @@ -0,0 +1,404 @@ | |||
| 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 | #include "precomp.h" | ||
| 4 | |||
| 5 | #define SIXTY_FOUR_MEG 64 * 1024 * 1024 | ||
| 6 | |||
| 7 | // prototypes | ||
| 8 | static HRESULT ExecuteCertificateOperation( | ||
| 9 | __in MSIHANDLE hInstall, | ||
| 10 | __in SCA_ACTION saAction, | ||
| 11 | __in DWORD dwStoreRoot | ||
| 12 | ); | ||
| 13 | |||
| 14 | static HRESULT ReadCertificateFile( | ||
| 15 | __in LPCWSTR wzPath, | ||
| 16 | __out BYTE** prgbData, | ||
| 17 | __out DWORD* pcbData | ||
| 18 | ); | ||
| 19 | |||
| 20 | static HRESULT InstallCertificatePackage( | ||
| 21 | __in HCERTSTORE hStore, | ||
| 22 | __in BOOL fUserCertificateStore, | ||
| 23 | __in LPCWSTR wzName, | ||
| 24 | __in_opt BYTE* rgbData, | ||
| 25 | __in DWORD cbData, | ||
| 26 | __in_opt LPCWSTR wzPFXPassword | ||
| 27 | ); | ||
| 28 | |||
| 29 | static HRESULT UninstallCertificatePackage( | ||
| 30 | __in HCERTSTORE hStore, | ||
| 31 | __in BOOL fUserCertificateStore, | ||
| 32 | __in LPCWSTR wzName | ||
| 33 | ); | ||
| 34 | |||
| 35 | |||
| 36 | /* **************************************************************** | ||
| 37 | AddUserCertificate - CUSTOM ACTION ENTRY POINT for adding per-user | ||
| 38 | certificates | ||
| 39 | |||
| 40 | * ***************************************************************/ | ||
| 41 | extern "C" UINT __stdcall AddUserCertificate( | ||
| 42 | __in MSIHANDLE hInstall | ||
| 43 | ) | ||
| 44 | { | ||
| 45 | HRESULT hr = S_OK; | ||
| 46 | DWORD er = ERROR_SUCCESS; | ||
| 47 | |||
| 48 | hr = WcaInitialize(hInstall, "AddUserCertificate"); | ||
| 49 | ExitOnFailure(hr, "Failed to initialize AddUserCertificate."); | ||
| 50 | |||
| 51 | hr = ExecuteCertificateOperation(hInstall, SCA_ACTION_INSTALL, CERT_SYSTEM_STORE_CURRENT_USER); | ||
| 52 | ExitOnFailure(hr, "Failed to install per-user certificate."); | ||
| 53 | |||
| 54 | LExit: | ||
| 55 | er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; | ||
| 56 | return WcaFinalize(er); | ||
| 57 | } | ||
| 58 | |||
| 59 | |||
| 60 | /* **************************************************************** | ||
| 61 | AddMachineCertificate - CUSTOM ACTION ENTRY POINT for adding | ||
| 62 | per-machine certificates | ||
| 63 | |||
| 64 | * ***************************************************************/ | ||
| 65 | extern "C" UINT __stdcall AddMachineCertificate( | ||
| 66 | __in MSIHANDLE hInstall | ||
| 67 | ) | ||
| 68 | { | ||
| 69 | HRESULT hr = S_OK; | ||
| 70 | DWORD er = ERROR_SUCCESS; | ||
| 71 | |||
| 72 | hr = WcaInitialize(hInstall, "AddMachineCertificate"); | ||
| 73 | ExitOnFailure(hr, "Failed to initialize AddMachineCertificate."); | ||
| 74 | |||
| 75 | hr = ExecuteCertificateOperation(hInstall, SCA_ACTION_INSTALL, CERT_SYSTEM_STORE_LOCAL_MACHINE); | ||
| 76 | ExitOnFailure(hr, "Failed to install per-machine certificate."); | ||
| 77 | |||
| 78 | LExit: | ||
| 79 | er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; | ||
| 80 | return WcaFinalize(er); | ||
| 81 | } | ||
| 82 | |||
| 83 | |||
| 84 | /* **************************************************************** | ||
| 85 | DeleteUserCertificate - CUSTOM ACTION ENTRY POINT for deleting | ||
| 86 | per-user certificates | ||
| 87 | |||
| 88 | * ***************************************************************/ | ||
| 89 | extern "C" UINT __stdcall DeleteUserCertificate( | ||
| 90 | __in MSIHANDLE hInstall | ||
| 91 | ) | ||
| 92 | { | ||
| 93 | HRESULT hr = S_OK; | ||
| 94 | DWORD er = ERROR_SUCCESS; | ||
| 95 | |||
| 96 | hr = WcaInitialize(hInstall, "DeleteUserCertificate"); | ||
| 97 | ExitOnFailure(hr, "Failed to initialize DeleteUserCertificate."); | ||
| 98 | |||
| 99 | hr = ExecuteCertificateOperation(hInstall, SCA_ACTION_UNINSTALL, CERT_SYSTEM_STORE_CURRENT_USER); | ||
| 100 | ExitOnFailure(hr, "Failed to uninstall per-user certificate."); | ||
| 101 | |||
| 102 | LExit: | ||
| 103 | er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; | ||
| 104 | return WcaFinalize(er); | ||
| 105 | } | ||
| 106 | |||
| 107 | |||
| 108 | /* **************************************************************** | ||
| 109 | DeleteMachineCertificate - CUSTOM ACTION ENTRY POINT for deleting | ||
| 110 | per-machine certificates | ||
| 111 | |||
| 112 | * ***************************************************************/ | ||
| 113 | extern "C" UINT __stdcall DeleteMachineCertificate( | ||
| 114 | __in MSIHANDLE hInstall | ||
| 115 | ) | ||
| 116 | { | ||
| 117 | HRESULT hr = S_OK; | ||
| 118 | DWORD er = ERROR_SUCCESS; | ||
| 119 | |||
| 120 | hr = WcaInitialize(hInstall, "DeleteMachineCertificate"); | ||
| 121 | ExitOnFailure(hr, "Failed to initialize DeleteMachineCertificate."); | ||
| 122 | |||
| 123 | hr = ExecuteCertificateOperation(hInstall, SCA_ACTION_UNINSTALL, CERT_SYSTEM_STORE_LOCAL_MACHINE); | ||
| 124 | ExitOnFailure(hr, "Failed to uninstall per-machine certificate."); | ||
| 125 | |||
| 126 | LExit: | ||
| 127 | er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; | ||
| 128 | return WcaFinalize(er); | ||
| 129 | } | ||
| 130 | |||
| 131 | |||
| 132 | static HRESULT ExecuteCertificateOperation( | ||
| 133 | __in MSIHANDLE /*hInstall*/, | ||
| 134 | __in SCA_ACTION saAction, | ||
| 135 | __in DWORD dwStoreLocation | ||
| 136 | ) | ||
| 137 | { | ||
| 138 | //AssertSz(FALSE, "Debug ExecuteCertificateOperation() here."); | ||
| 139 | Assert(saAction & SCA_ACTION_INSTALL || saAction & SCA_ACTION_UNINSTALL); | ||
| 140 | |||
| 141 | HRESULT hr = S_OK; | ||
| 142 | LPWSTR pwzCaData = NULL; | ||
| 143 | LPWSTR pwz; | ||
| 144 | LPWSTR pwzName = NULL; | ||
| 145 | LPWSTR pwzStore = NULL; | ||
| 146 | int iAttributes = 0; | ||
| 147 | LPWSTR pwzPFXPassword = NULL; | ||
| 148 | LPWSTR pwzFilePath = NULL; | ||
| 149 | BYTE* pbData = NULL; | ||
| 150 | DWORD cbData = 0; | ||
| 151 | DWORD cbPFXPassword = 0; | ||
| 152 | |||
| 153 | BOOL fUserStoreLocation = (CERT_SYSTEM_STORE_CURRENT_USER == dwStoreLocation); | ||
| 154 | HCERTSTORE hCertStore = NULL; | ||
| 155 | |||
| 156 | hr = WcaGetProperty(L"CustomActionData", &pwzCaData); | ||
| 157 | ExitOnFailure(hr, "Failed to get CustomActionData"); | ||
| 158 | |||
| 159 | WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %ls", pwzCaData); | ||
| 160 | |||
| 161 | pwz = pwzCaData; | ||
| 162 | hr = WcaReadStringFromCaData(&pwz, &pwzName); | ||
| 163 | ExitOnFailure(hr, "Failed to parse certificate name."); | ||
| 164 | hr = WcaReadStringFromCaData(&pwz, &pwzStore); | ||
| 165 | ExitOnFailure(hr, "Failed to parse CustomActionData, StoreName"); | ||
| 166 | hr = WcaReadIntegerFromCaData(&pwz, &iAttributes); | ||
| 167 | ExitOnFailure(hr, "Failed to parse certificate attribute"); | ||
| 168 | if (SCA_ACTION_INSTALL == saAction) // install operations need more data | ||
| 169 | { | ||
| 170 | hr = WcaReadStreamFromCaData(&pwz, &pbData, (DWORD_PTR*)&cbData); | ||
| 171 | ExitOnFailure(hr, "Failed to parse certificate stream."); | ||
| 172 | |||
| 173 | hr = WcaReadStringFromCaData(&pwz, &pwzPFXPassword); | ||
| 174 | ExitOnFailure(hr, "Failed to parse certificate password."); | ||
| 175 | } | ||
| 176 | |||
| 177 | // Open the right store. | ||
| 178 | hCertStore = ::CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, NULL, dwStoreLocation, pwzStore); | ||
| 179 | MessageExitOnNullWithLastError(hCertStore, hr, msierrCERTFailedOpen, "Failed to open certificate store: %ls", pwzStore); | ||
| 180 | |||
| 181 | if (SCA_ACTION_INSTALL == saAction) // install operations need more data | ||
| 182 | { | ||
| 183 | // Uninstall existing versions of this package. Ignore any failures | ||
| 184 | // This is needed to clean up the private key of a cert when we replace an existing cert | ||
| 185 | // CertAddCertificateContextToStore(CERT_STORE_ADD_REPLACE_EXISTING) does not remove the private key if the cert is replaced | ||
| 186 | UninstallCertificatePackage(hCertStore, fUserStoreLocation, pwzName); | ||
| 187 | |||
| 188 | hr = InstallCertificatePackage(hCertStore, fUserStoreLocation, pwzName, pbData, cbData, pwzPFXPassword); | ||
| 189 | ExitOnFailure(hr, "Failed to install certificate."); | ||
| 190 | } | ||
| 191 | else | ||
| 192 | { | ||
| 193 | Assert(SCA_ACTION_UNINSTALL == saAction); | ||
| 194 | |||
| 195 | hr = UninstallCertificatePackage(hCertStore, fUserStoreLocation, pwzName); | ||
| 196 | ExitOnFailure(hr, "Failed to uninstall certificate."); | ||
| 197 | } | ||
| 198 | |||
| 199 | LExit: | ||
| 200 | if (NULL != pwzPFXPassword && SUCCEEDED(StrSize(pwzPFXPassword, &cbPFXPassword))) | ||
| 201 | { | ||
| 202 | SecureZeroMemory(pwzPFXPassword, cbPFXPassword); | ||
| 203 | } | ||
| 204 | |||
| 205 | if (hCertStore) | ||
| 206 | { | ||
| 207 | if (!::CertCloseStore(hCertStore, CERT_CLOSE_STORE_CHECK_FLAG)) | ||
| 208 | { | ||
| 209 | WcaLog(LOGMSG_VERBOSE, "Cert store was closed but not all resources were freed. Error 0x%x", GetLastError()); | ||
| 210 | } | ||
| 211 | } | ||
| 212 | |||
| 213 | ReleaseMem(pbData); | ||
| 214 | ReleaseStr(pwzFilePath); | ||
| 215 | ReleaseStr(pwzPFXPassword); | ||
| 216 | ReleaseStr(pwzStore); | ||
| 217 | ReleaseStr(pwzName); | ||
| 218 | ReleaseStr(pwzCaData); | ||
| 219 | return hr; | ||
| 220 | } | ||
| 221 | |||
| 222 | |||
| 223 | static HRESULT InstallCertificatePackage( | ||
| 224 | __in HCERTSTORE hStore, | ||
| 225 | __in BOOL fUserCertificateStore, | ||
| 226 | __in LPCWSTR wzName, | ||
| 227 | __in_opt BYTE* rgbData, | ||
| 228 | __in DWORD cbData, | ||
| 229 | __in_opt LPCWSTR wzPFXPassword | ||
| 230 | ) | ||
| 231 | { | ||
| 232 | HRESULT hr = S_OK; | ||
| 233 | |||
| 234 | HCERTSTORE hPfxCertStore = NULL; | ||
| 235 | PCCERT_CONTEXT pCertContext = NULL; | ||
| 236 | CERT_BLOB blob = { 0 }; | ||
| 237 | DWORD dwKeyset = fUserCertificateStore ? CRYPT_USER_KEYSET : CRYPT_MACHINE_KEYSET; | ||
| 238 | DWORD dwEncodingType; | ||
| 239 | DWORD dwContentType; | ||
| 240 | DWORD dwFormatType; | ||
| 241 | LPWSTR pwzUniqueName = NULL; | ||
| 242 | int iUniqueId = 0; | ||
| 243 | |||
| 244 | // Figure out what type of blob (certificate or PFX) we're dealing with here. | ||
| 245 | blob.pbData = rgbData; | ||
| 246 | blob.cbData = cbData; | ||
| 247 | |||
| 248 | if (!::CryptQueryObject(CERT_QUERY_OBJECT_BLOB, &blob, CERT_QUERY_CONTENT_FLAG_ALL, CERT_QUERY_FORMAT_FLAG_ALL, 0, &dwEncodingType, &dwContentType, &dwFormatType, NULL, NULL, (LPCVOID*)&pCertContext)) | ||
| 249 | { | ||
| 250 | ExitWithLastError(hr, "Failed to parse the certificate blob: %ls", wzName); | ||
| 251 | } | ||
| 252 | |||
| 253 | hr = StrAllocFormatted(&pwzUniqueName, L"%s_wixCert_%d", wzName, ++iUniqueId); | ||
| 254 | ExitOnFailure(hr, "Failed to format unique name"); | ||
| 255 | |||
| 256 | if (!pCertContext) | ||
| 257 | { | ||
| 258 | // If we have a PFX blob, get the first certificate out of the PFX and use that instead of the PFX. | ||
| 259 | if (dwContentType & CERT_QUERY_CONTENT_PFX) | ||
| 260 | { | ||
| 261 | ExitOnNull(wzPFXPassword, hr, E_INVALIDARG, "Failed to import PFX blob because no password was provided"); | ||
| 262 | |||
| 263 | // If we fail and our password is blank, also try passing in NULL for the password (according to the docs) | ||
| 264 | hPfxCertStore = ::PFXImportCertStore((CRYPT_DATA_BLOB*)&blob, wzPFXPassword, dwKeyset); | ||
| 265 | if (NULL == hPfxCertStore && !*wzPFXPassword) | ||
| 266 | { | ||
| 267 | hPfxCertStore = ::PFXImportCertStore((CRYPT_DATA_BLOB*)&blob, NULL, dwKeyset); | ||
| 268 | } | ||
| 269 | ExitOnNullWithLastError(hPfxCertStore, hr, "Failed to open PFX file."); | ||
| 270 | |||
| 271 | // Install all certificates in the PFX | ||
| 272 | for (pCertContext = ::CertEnumCertificatesInStore(hPfxCertStore, pCertContext); | ||
| 273 | pCertContext; | ||
| 274 | pCertContext = ::CertEnumCertificatesInStore(hPfxCertStore, pCertContext)) | ||
| 275 | { | ||
| 276 | WcaLog(LOGMSG_STANDARD, "Adding certificate: %ls", pwzUniqueName); | ||
| 277 | hr = CertInstallSingleCertificate(hStore, pCertContext, pwzUniqueName); | ||
| 278 | MessageExitOnFailure(hr, msierrCERTFailedAdd, "Failed to add certificate to the store."); | ||
| 279 | |||
| 280 | hr = StrAllocFormatted(&pwzUniqueName, L"%s_wixCert_%d", wzName, ++iUniqueId); | ||
| 281 | ExitOnFailure(hr, "Failed to format unique name"); | ||
| 282 | } | ||
| 283 | } | ||
| 284 | else | ||
| 285 | { | ||
| 286 | hr = E_UNEXPECTED; | ||
| 287 | ExitOnFailure(hr, "Unexpected certificate type processed."); | ||
| 288 | } | ||
| 289 | } | ||
| 290 | else | ||
| 291 | { | ||
| 292 | WcaLog(LOGMSG_STANDARD, "Adding certificate: %ls", pwzUniqueName); | ||
| 293 | hr = CertInstallSingleCertificate(hStore, pCertContext, pwzUniqueName); | ||
| 294 | MessageExitOnFailure(hr, msierrCERTFailedAdd, "Failed to add certificate to the store."); | ||
| 295 | } | ||
| 296 | |||
| 297 | hr = WcaProgressMessage(COST_CERT_ADD, FALSE); | ||
| 298 | ExitOnFailure(hr, "Failed to send install progress message."); | ||
| 299 | |||
| 300 | LExit: | ||
| 301 | ReleaseStr(pwzUniqueName); | ||
| 302 | |||
| 303 | if (pCertContext) | ||
| 304 | { | ||
| 305 | ::CertFreeCertificateContext(pCertContext); | ||
| 306 | } | ||
| 307 | |||
| 308 | // Close the stores after the context's are released. | ||
| 309 | if (hPfxCertStore) | ||
| 310 | { | ||
| 311 | if (!::CertCloseStore(hPfxCertStore, CERT_CLOSE_STORE_CHECK_FLAG)) | ||
| 312 | { | ||
| 313 | WcaLog(LOGMSG_VERBOSE, "PFX cert store was closed but not all resources were freed. Error 0x%x", GetLastError()); | ||
| 314 | } | ||
| 315 | } | ||
| 316 | |||
| 317 | return hr; | ||
| 318 | } | ||
| 319 | |||
| 320 | |||
| 321 | static HRESULT UninstallCertificatePackage( | ||
| 322 | __in HCERTSTORE hStore, | ||
| 323 | __in BOOL fUserCertificateStore, | ||
| 324 | __in LPCWSTR wzName | ||
| 325 | ) | ||
| 326 | { | ||
| 327 | HRESULT hr = S_OK; | ||
| 328 | DWORD er = ERROR_SUCCESS; | ||
| 329 | PCCERT_CONTEXT pCertContext = NULL; | ||
| 330 | CRYPT_KEY_PROV_INFO* pPrivateKeyInfo = NULL; | ||
| 331 | LPWSTR pwzUniquePrefix = NULL; | ||
| 332 | int ccUniquePrefix = 0; | ||
| 333 | |||
| 334 | hr = StrAllocFormatted(&pwzUniquePrefix, L"%s_wixCert_", wzName); | ||
| 335 | ExitOnFailure(hr, "Failed to format unique name"); | ||
| 336 | ccUniquePrefix = ::lstrlenW(pwzUniquePrefix); | ||
| 337 | |||
| 338 | WcaLog(LOGMSG_STANDARD, "Deleting certificate that begin with friendly name: %ls", pwzUniquePrefix); | ||
| 339 | |||
| 340 | // Loop through all certificates in the store, deleting the ones that begin with our prefix. | ||
| 341 | while (NULL != (pCertContext = ::CertFindCertificateInStore(hStore, PKCS_7_ASN_ENCODING | X509_ASN_ENCODING, 0, CERT_FIND_ANY, NULL, pCertContext))) | ||
| 342 | { | ||
| 343 | WCHAR wzFriendlyName[256] = { 0 }; | ||
| 344 | DWORD cbFriendlyName = sizeof(wzFriendlyName); | ||
| 345 | |||
| 346 | if (::CertGetCertificateContextProperty(pCertContext, CERT_FRIENDLY_NAME_PROP_ID, reinterpret_cast<BYTE*>(wzFriendlyName), &cbFriendlyName) && | ||
| 347 | lstrlenW(wzFriendlyName) >= ccUniquePrefix && | ||
| 348 | CSTR_EQUAL == ::CompareStringW(LOCALE_SYSTEM_DEFAULT, 0, pwzUniquePrefix, ccUniquePrefix, wzFriendlyName, ccUniquePrefix)) | ||
| 349 | { | ||
| 350 | PCCERT_CONTEXT pCertContextDelete = ::CertDuplicateCertificateContext(pCertContext); // duplicate the context so we can delete it with out disrupting the looping | ||
| 351 | if(pCertContextDelete) | ||
| 352 | { | ||
| 353 | // Delete the certificate and if successful delete the matching private key as well. | ||
| 354 | if (::CertDeleteCertificateFromStore(pCertContextDelete)) | ||
| 355 | { | ||
| 356 | // If we found private key info, delete it. | ||
| 357 | hr = CertReadProperty(pCertContextDelete, CERT_KEY_PROV_INFO_PROP_ID, &pPrivateKeyInfo, NULL); | ||
| 358 | if (SUCCEEDED(hr)) | ||
| 359 | { | ||
| 360 | HCRYPTPROV hProvIgnored = NULL; // ignored on deletes. | ||
| 361 | DWORD dwKeyset = fUserCertificateStore ? CRYPT_USER_KEYSET : CRYPT_MACHINE_KEYSET; | ||
| 362 | |||
| 363 | if (!::CryptAcquireContextW(&hProvIgnored, pPrivateKeyInfo->pwszContainerName, pPrivateKeyInfo->pwszProvName, pPrivateKeyInfo->dwProvType, dwKeyset | CRYPT_DELETEKEYSET | CRYPT_SILENT)) | ||
| 364 | { | ||
| 365 | er = ::GetLastError(); | ||
| 366 | hr = HRESULT_FROM_WIN32(er); | ||
| 367 | } | ||
| 368 | |||
| 369 | ReleaseNullMem(pPrivateKeyInfo); | ||
| 370 | } | ||
| 371 | else // don't worry about failures to delete private keys. | ||
| 372 | { | ||
| 373 | hr = S_OK; | ||
| 374 | } | ||
| 375 | } | ||
| 376 | else | ||
| 377 | { | ||
| 378 | er = ::GetLastError(); | ||
| 379 | hr = HRESULT_FROM_WIN32(er); | ||
| 380 | } | ||
| 381 | |||
| 382 | if (FAILED(hr)) | ||
| 383 | { | ||
| 384 | WcaLog(LOGMSG_STANDARD, "Failed to delete certificate with friendly name: %ls, continuing anyway. Error: 0x%x", wzFriendlyName, hr); | ||
| 385 | } | ||
| 386 | |||
| 387 | pCertContextDelete = NULL; | ||
| 388 | } | ||
| 389 | } | ||
| 390 | } | ||
| 391 | |||
| 392 | hr = WcaProgressMessage(COST_CERT_DELETE, FALSE); | ||
| 393 | ExitOnFailure(hr, "Failed to send uninstall progress message."); | ||
| 394 | |||
| 395 | LExit: | ||
| 396 | ReleaseStr(pwzUniquePrefix); | ||
| 397 | ReleaseMem(pPrivateKeyInfo); | ||
| 398 | if(pCertContext) | ||
| 399 | { | ||
| 400 | ::CertFreeCertificateContext(pCertContext); | ||
| 401 | } | ||
| 402 | |||
| 403 | return hr; | ||
| 404 | } | ||
diff --git a/src/ca/scacost.h b/src/ca/scacost.h new file mode 100644 index 00000000..be92cf26 --- /dev/null +++ b/src/ca/scacost.h | |||
| @@ -0,0 +1,15 @@ | |||
| 1 | #pragma once | ||
| 2 | // 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. | ||
| 3 | |||
| 4 | |||
| 5 | const UINT COST_IIS_TRANSACTIONS = 10000; | ||
| 6 | |||
| 7 | const UINT COST_IIS_CREATEKEY = 5000; | ||
| 8 | const UINT COST_IIS_DELETEKEY = 5000; | ||
| 9 | const UINT COST_IIS_WRITEVALUE = 5000; | ||
| 10 | const UINT COST_IIS_DELETEVALUE = 5000; | ||
| 11 | const UINT COST_IIS_CREATEAPP = 5000; | ||
| 12 | const UINT COST_IIS_DELETEAPP = 5000; | ||
| 13 | |||
| 14 | const UINT COST_CERT_ADD = 5000; | ||
| 15 | const UINT COST_CERT_DELETE = 5000; | ||
diff --git a/src/ca/scaexec.cpp b/src/ca/scaexec.cpp new file mode 100644 index 00000000..df25e8db --- /dev/null +++ b/src/ca/scaexec.cpp | |||
| @@ -0,0 +1,1184 @@ | |||
| 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 | #include "precomp.h" | ||
| 4 | |||
| 5 | |||
| 6 | /******************************************************************** | ||
| 7 | StartMetabaseTransaction - CUSTOM ACTION ENTRY POINT for backing up metabase | ||
| 8 | |||
| 9 | Input: deferred CustomActionData - BackupName | ||
| 10 | ********************************************************************/ | ||
| 11 | extern "C" UINT __stdcall StartMetabaseTransaction(MSIHANDLE hInstall) | ||
| 12 | { | ||
| 13 | //AssertSz(FALSE, "debug StartMetabaseTransaction here"); | ||
| 14 | HRESULT hr = S_OK; | ||
| 15 | UINT er = ERROR_SUCCESS; | ||
| 16 | |||
| 17 | IMSAdminBase* piMetabase = NULL; | ||
| 18 | LPWSTR pwzData = NULL; | ||
| 19 | BOOL fInitializedCom = FALSE; | ||
| 20 | |||
| 21 | // initialize | ||
| 22 | hr = WcaInitialize(hInstall, "StartMetabaseTransaction"); | ||
| 23 | ExitOnFailure(hr, "failed to initialize StartMetabaseTransaction"); | ||
| 24 | |||
| 25 | hr = ::CoInitialize(NULL); | ||
| 26 | ExitOnFailure(hr, "failed to initialize COM"); | ||
| 27 | fInitializedCom = TRUE; | ||
| 28 | hr = ::CoCreateInstance(CLSID_MSAdminBase, NULL, CLSCTX_ALL, IID_IMSAdminBase, reinterpret_cast<void**>(&piMetabase)); | ||
| 29 | if (hr == REGDB_E_CLASSNOTREG) | ||
| 30 | { | ||
| 31 | WcaLog(LOGMSG_STANDARD, "Failed to get IIMSAdminBase to backup - continuing"); | ||
| 32 | hr = S_OK; | ||
| 33 | } | ||
| 34 | else | ||
| 35 | { | ||
| 36 | MessageExitOnFailure(hr, msierrIISCannotConnect, "failed to get IID_IIMSAdminBase object"); | ||
| 37 | |||
| 38 | hr = WcaGetProperty(L"CustomActionData", &pwzData); | ||
| 39 | ExitOnFailure(hr, "failed to get CustomActionData"); | ||
| 40 | |||
| 41 | // back up the metabase | ||
| 42 | Assert(lstrlenW(pwzData) < MD_BACKUP_MAX_LEN); | ||
| 43 | |||
| 44 | // MD_BACKUP_OVERWRITE = Overwrite if a backup of the same name and version exists in the backup location | ||
| 45 | hr = piMetabase->Backup(pwzData, MD_BACKUP_NEXT_VERSION, MD_BACKUP_OVERWRITE | MD_BACKUP_FORCE_BACKUP | MD_BACKUP_SAVE_FIRST); | ||
| 46 | if (MD_WARNING_SAVE_FAILED == hr) | ||
| 47 | { | ||
| 48 | WcaLog(LOGMSG_STANDARD, "Failed to save metabase before backing up - continuing"); | ||
| 49 | hr = S_OK; | ||
| 50 | } | ||
| 51 | MessageExitOnFailure(hr, msierrIISFailedStartTransaction, "failed to begin metabase transaction: '%ls'", pwzData); | ||
| 52 | } | ||
| 53 | hr = WcaProgressMessage(COST_IIS_TRANSACTIONS, FALSE); | ||
| 54 | LExit: | ||
| 55 | ReleaseStr(pwzData); | ||
| 56 | ReleaseObject(piMetabase); | ||
| 57 | |||
| 58 | if (fInitializedCom) | ||
| 59 | { | ||
| 60 | ::CoUninitialize(); | ||
| 61 | } | ||
| 62 | |||
| 63 | if (FAILED(hr)) | ||
| 64 | er = ERROR_INSTALL_FAILURE; | ||
| 65 | return WcaFinalize(er); | ||
| 66 | } | ||
| 67 | |||
| 68 | |||
| 69 | /******************************************************************** | ||
| 70 | RollbackMetabaseTransaction - CUSTOM ACTION ENTRY POINT for unbacking up metabase | ||
| 71 | |||
| 72 | Input: deferred CustomActionData - BackupName | ||
| 73 | ********************************************************************/ | ||
| 74 | extern "C" UINT __stdcall RollbackMetabaseTransaction(MSIHANDLE hInstall) | ||
| 75 | { | ||
| 76 | //AssertSz(FALSE, "debug RollbackMetabaseTransaction here"); | ||
| 77 | HRESULT hr = S_OK; | ||
| 78 | UINT er = ERROR_SUCCESS; | ||
| 79 | |||
| 80 | IMSAdminBase* piMetabase = NULL; | ||
| 81 | LPWSTR pwzData = NULL; | ||
| 82 | BOOL fInitializedCom = FALSE; | ||
| 83 | |||
| 84 | hr = WcaInitialize(hInstall, "RollbackMetabaseTransaction"); | ||
| 85 | ExitOnFailure(hr, "failed to initialize"); | ||
| 86 | |||
| 87 | hr = ::CoInitialize(NULL); | ||
| 88 | ExitOnFailure(hr, "failed to initialize COM"); | ||
| 89 | fInitializedCom = TRUE; | ||
| 90 | hr = ::CoCreateInstance(CLSID_MSAdminBase, NULL, CLSCTX_ALL, IID_IMSAdminBase, reinterpret_cast<void**>(&piMetabase)); | ||
| 91 | if (hr == REGDB_E_CLASSNOTREG) | ||
| 92 | { | ||
| 93 | WcaLog(LOGMSG_STANDARD, "Failed to get IIMSAdminBase to rollback - continuing"); | ||
| 94 | hr = S_OK; | ||
| 95 | ExitFunction(); | ||
| 96 | } | ||
| 97 | ExitOnFailure(hr, "failed to get IID_IIMSAdminBase object"); | ||
| 98 | |||
| 99 | |||
| 100 | hr = WcaGetProperty( L"CustomActionData", &pwzData); | ||
| 101 | ExitOnFailure(hr, "failed to get CustomActionData"); | ||
| 102 | |||
| 103 | hr = piMetabase->Restore(pwzData, MD_BACKUP_HIGHEST_VERSION, 0); | ||
| 104 | ExitOnFailure(hr, "failed to rollback metabase transaction: '%ls'", pwzData); | ||
| 105 | |||
| 106 | hr = piMetabase->DeleteBackup(pwzData, MD_BACKUP_HIGHEST_VERSION); | ||
| 107 | ExitOnFailure(hr, "failed to cleanup metabase transaction '%ls', continuing", pwzData); | ||
| 108 | |||
| 109 | LExit: | ||
| 110 | ReleaseStr(pwzData); | ||
| 111 | ReleaseObject(piMetabase); | ||
| 112 | |||
| 113 | if (fInitializedCom) | ||
| 114 | { | ||
| 115 | ::CoUninitialize(); | ||
| 116 | } | ||
| 117 | |||
| 118 | if (FAILED(hr)) | ||
| 119 | { | ||
| 120 | er = ERROR_INSTALL_FAILURE; | ||
| 121 | } | ||
| 122 | return WcaFinalize(er); | ||
| 123 | } | ||
| 124 | |||
| 125 | |||
| 126 | /******************************************************************** | ||
| 127 | CommitMetabaseTransaction - CUSTOM ACTION ENTRY POINT for unbacking up metabase | ||
| 128 | |||
| 129 | Input: deferred CustomActionData - BackupName | ||
| 130 | * *****************************************************************/ | ||
| 131 | extern "C" UINT __stdcall CommitMetabaseTransaction(MSIHANDLE hInstall) | ||
| 132 | { | ||
| 133 | HRESULT hr = S_OK; | ||
| 134 | UINT er = ERROR_SUCCESS; | ||
| 135 | |||
| 136 | IMSAdminBase* piMetabase = NULL; | ||
| 137 | LPWSTR pwzData = NULL; | ||
| 138 | BOOL fInitializedCom = FALSE; | ||
| 139 | |||
| 140 | hr = WcaInitialize(hInstall, "CommitMetabaseTransaction"); | ||
| 141 | ExitOnFailure(hr, "failed to initialize"); | ||
| 142 | |||
| 143 | hr = ::CoInitialize(NULL); | ||
| 144 | ExitOnFailure(hr, "failed to initialize COM"); | ||
| 145 | fInitializedCom = TRUE; | ||
| 146 | hr = ::CoCreateInstance(CLSID_MSAdminBase, NULL, CLSCTX_ALL, IID_IMSAdminBase, reinterpret_cast<void**>(&piMetabase)); | ||
| 147 | if (hr == REGDB_E_CLASSNOTREG) | ||
| 148 | { | ||
| 149 | WcaLog(LOGMSG_STANDARD, "Failed to get IIMSAdminBase to commit - continuing"); | ||
| 150 | hr = S_OK; | ||
| 151 | ExitFunction(); | ||
| 152 | } | ||
| 153 | ExitOnFailure(hr, "failed to get IID_IIMSAdminBase object"); | ||
| 154 | |||
| 155 | hr = WcaGetProperty( L"CustomActionData", &pwzData); | ||
| 156 | ExitOnFailure(hr, "failed to get CustomActionData"); | ||
| 157 | |||
| 158 | hr = piMetabase->DeleteBackup(pwzData, MD_BACKUP_HIGHEST_VERSION); | ||
| 159 | ExitOnFailure(hr, "failed to cleanup metabase transaction: '%ls'", pwzData); | ||
| 160 | |||
| 161 | LExit: | ||
| 162 | ReleaseStr(pwzData); | ||
| 163 | ReleaseObject(piMetabase); | ||
| 164 | |||
| 165 | if (fInitializedCom) | ||
| 166 | { | ||
| 167 | ::CoUninitialize(); | ||
| 168 | } | ||
| 169 | |||
| 170 | if (FAILED(hr)) | ||
| 171 | { | ||
| 172 | er = ERROR_INSTALL_FAILURE; | ||
| 173 | } | ||
| 174 | return WcaFinalize(er); | ||
| 175 | } | ||
| 176 | |||
| 177 | |||
| 178 | /******************************************************************** | ||
| 179 | CreateMetabaseKey - Installs metabase keys | ||
| 180 | |||
| 181 | Input: deferred CustomActionData - Key | ||
| 182 | * *****************************************************************/ | ||
| 183 | static HRESULT CreateMetabaseKey(__in LPWSTR* ppwzCustomActionData, __in IMSAdminBase* piMetabase) | ||
| 184 | { | ||
| 185 | //AssertSz(FALSE, "debug CreateMetabaseKey here"); | ||
| 186 | HRESULT hr = S_OK; | ||
| 187 | METADATA_HANDLE mhRoot = 0; | ||
| 188 | LPWSTR pwzData = NULL; | ||
| 189 | LPCWSTR pwzKey; | ||
| 190 | |||
| 191 | int i; | ||
| 192 | |||
| 193 | hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzData); | ||
| 194 | ExitOnFailure(hr, "failed to read key from custom action data"); | ||
| 195 | |||
| 196 | hr = piMetabase->OpenKey(METADATA_MASTER_ROOT_HANDLE, L"/LM", METADATA_PERMISSION_WRITE, 10, &mhRoot); | ||
| 197 | for (i = 30; i > 0 && HRESULT_FROM_WIN32(ERROR_PATH_BUSY) == hr; i--) | ||
| 198 | { | ||
| 199 | ::Sleep(1000); | ||
| 200 | WcaLog(LOGMSG_STANDARD, "failed to open root key, retrying %d time(s)...", i); | ||
| 201 | hr = piMetabase->OpenKey(METADATA_MASTER_ROOT_HANDLE, L"/LM", METADATA_PERMISSION_WRITE, 10, &mhRoot); | ||
| 202 | } | ||
| 203 | MessageExitOnFailure(hr, msierrIISFailedOpenKey, "failed to open metabase key: %ls", L"/LM"); | ||
| 204 | |||
| 205 | pwzKey = pwzData + 3; | ||
| 206 | |||
| 207 | WcaLog(LOGMSG_VERBOSE, "Creating Metabase Key: %ls", pwzKey); | ||
| 208 | |||
| 209 | hr = piMetabase->AddKey(mhRoot, pwzKey); | ||
| 210 | if (HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS) == hr) | ||
| 211 | { | ||
| 212 | WcaLog(LOGMSG_VERBOSE, "Key `%ls` already existed, continuing.", pwzData); | ||
| 213 | hr = S_OK; | ||
| 214 | } | ||
| 215 | MessageExitOnFailure(hr, msierrIISFailedCreateKey, "failed to create metabase key: %ls", pwzKey); | ||
| 216 | |||
| 217 | hr = WcaProgressMessage(COST_IIS_CREATEKEY, FALSE); | ||
| 218 | |||
| 219 | LExit: | ||
| 220 | if (mhRoot) | ||
| 221 | { | ||
| 222 | piMetabase->CloseKey(mhRoot); | ||
| 223 | } | ||
| 224 | |||
| 225 | return hr; | ||
| 226 | } | ||
| 227 | |||
| 228 | |||
| 229 | /******************************************************************** | ||
| 230 | WriteMetabaseValue -Installs metabase values | ||
| 231 | |||
| 232 | Input: deferred CustomActionData - Key\tIdentifier\tAttributes\tUserType\tDataType\tData | ||
| 233 | * *****************************************************************/ | ||
| 234 | static HRESULT WriteMetabaseValue(__in LPWSTR* ppwzCustomActionData, __in IMSAdminBase* piMetabase) | ||
| 235 | { | ||
| 236 | //AssertSz(FALSE, "debug WriteMetabaseValue here"); | ||
| 237 | HRESULT hr = S_OK; | ||
| 238 | |||
| 239 | METADATA_HANDLE mhKey = 0; | ||
| 240 | |||
| 241 | LPWSTR pwzKey = NULL; | ||
| 242 | LPWSTR pwzTemp = NULL; | ||
| 243 | DWORD dwData = 0; | ||
| 244 | DWORD dwTemp = 0; | ||
| 245 | BOOL fFreeData = FALSE; | ||
| 246 | METADATA_RECORD mr; | ||
| 247 | ::ZeroMemory((LPVOID)&mr, sizeof(mr)); | ||
| 248 | METADATA_RECORD mrGet; | ||
| 249 | ::ZeroMemory((LPVOID)&mrGet, sizeof(mrGet)); | ||
| 250 | |||
| 251 | int i; | ||
| 252 | |||
| 253 | // get the key first | ||
| 254 | hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzKey); | ||
| 255 | ExitOnFailure(hr, "failed to read key"); | ||
| 256 | hr = WcaReadIntegerFromCaData(ppwzCustomActionData, reinterpret_cast<int *>(&mr.dwMDIdentifier)); | ||
| 257 | ExitOnFailure(hr, "failed to read identifier"); | ||
| 258 | hr = WcaReadIntegerFromCaData(ppwzCustomActionData, reinterpret_cast<int *>(&mr.dwMDAttributes)); | ||
| 259 | ExitOnFailure(hr, "failed to read attributes"); | ||
| 260 | hr = WcaReadIntegerFromCaData(ppwzCustomActionData, reinterpret_cast<int *>(&mr.dwMDUserType)); | ||
| 261 | ExitOnFailure(hr, "failed to read user type"); | ||
| 262 | hr = WcaReadIntegerFromCaData(ppwzCustomActionData, reinterpret_cast<int *>(&mr.dwMDDataType)); | ||
| 263 | ExitOnFailure(hr, "failed to read data type"); | ||
| 264 | |||
| 265 | switch (mr.dwMDDataType) // data | ||
| 266 | { | ||
| 267 | case DWORD_METADATA: | ||
| 268 | hr = WcaReadIntegerFromCaData(ppwzCustomActionData, reinterpret_cast<int *>(&dwData)); | ||
| 269 | mr.dwMDDataLen = sizeof(dwData); | ||
| 270 | mr.pbMDData = reinterpret_cast<BYTE*>(&dwData); | ||
| 271 | break; | ||
| 272 | case STRING_METADATA: | ||
| 273 | hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzTemp); | ||
| 274 | mr.dwMDDataLen = (lstrlenW(pwzTemp) + 1) * sizeof(WCHAR); | ||
| 275 | mr.pbMDData = reinterpret_cast<BYTE*>(pwzTemp); | ||
| 276 | break; | ||
| 277 | case MULTISZ_METADATA: | ||
| 278 | { | ||
| 279 | hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzTemp); | ||
| 280 | mr.dwMDDataLen = (lstrlenW(pwzTemp) + 1) * sizeof(WCHAR); | ||
| 281 | for (LPWSTR pwzT = pwzTemp; *pwzT; ++pwzT) | ||
| 282 | { | ||
| 283 | if (MAGIC_MULTISZ_CHAR == *pwzT) | ||
| 284 | { | ||
| 285 | *pwzT = L'\0'; | ||
| 286 | } | ||
| 287 | } | ||
| 288 | mr.pbMDData = reinterpret_cast<BYTE*>(pwzTemp); | ||
| 289 | } | ||
| 290 | break; | ||
| 291 | case BINARY_METADATA: | ||
| 292 | hr = WcaReadStreamFromCaData(ppwzCustomActionData, &mr.pbMDData, reinterpret_cast<DWORD_PTR *>(&mr.dwMDDataLen)); | ||
| 293 | fFreeData = TRUE; | ||
| 294 | break; | ||
| 295 | default: | ||
| 296 | hr = E_UNEXPECTED; | ||
| 297 | break; | ||
| 298 | } | ||
| 299 | ExitOnFailure(hr, "failed to parse CustomActionData into metabase record"); | ||
| 300 | |||
| 301 | WcaLog(LOGMSG_VERBOSE, "Writing Metabase Value Under Key: %ls ID: %d", pwzKey, mr.dwMDIdentifier); | ||
| 302 | |||
| 303 | hr = piMetabase->OpenKey(METADATA_MASTER_ROOT_HANDLE, L"/LM", METADATA_PERMISSION_WRITE, 10, &mhKey); | ||
| 304 | for (i = 30; i > 0 && HRESULT_FROM_WIN32(ERROR_PATH_BUSY) == hr; i--) | ||
| 305 | { | ||
| 306 | ::Sleep(1000); | ||
| 307 | WcaLog(LOGMSG_STANDARD, "failed to open '%ls' key, retrying %d time(s)...", pwzKey, i); | ||
| 308 | hr = piMetabase->OpenKey(METADATA_MASTER_ROOT_HANDLE, L"/LM", METADATA_PERMISSION_WRITE, 10, &mhKey); | ||
| 309 | } | ||
| 310 | MessageExitOnFailure(hr, msierrIISFailedOpenKey, "failed to open metabase key: %ls", pwzKey); | ||
| 311 | |||
| 312 | if (lstrlenW(pwzKey) < 3) | ||
| 313 | { | ||
| 314 | ExitOnFailure(hr = E_INVALIDARG, "Key didn't begin with \"/LM\" as expected - key value: %ls", pwzKey); | ||
| 315 | } | ||
| 316 | |||
| 317 | hr = piMetabase->SetData(mhKey, pwzKey + 3, &mr); // pwzKey + 3 to skip "/LM" that was used to open the key. | ||
| 318 | |||
| 319 | // This means we're trying to write to a secure key without the secure flag set - let's try again with the secure flag set | ||
| 320 | if (MD_ERROR_CANNOT_REMOVE_SECURE_ATTRIBUTE == hr) | ||
| 321 | { | ||
| 322 | mr.dwMDAttributes |= METADATA_SECURE; | ||
| 323 | hr = piMetabase->SetData(mhKey, pwzKey + 3, &mr); | ||
| 324 | } | ||
| 325 | |||
| 326 | // If IIS6 returned failure, let's check if the correct value exists in the metabase before actually failing the CA | ||
| 327 | if (FAILED(hr)) | ||
| 328 | { | ||
| 329 | // Backup the original failure error, so we can log it below if necessary | ||
| 330 | HRESULT hrOldValue = hr; | ||
| 331 | |||
| 332 | mrGet.dwMDIdentifier = mr.dwMDIdentifier; | ||
| 333 | mrGet.dwMDAttributes = METADATA_NO_ATTRIBUTES; | ||
| 334 | mrGet.dwMDUserType = mr.dwMDUserType; | ||
| 335 | mrGet.dwMDDataType = mr.dwMDDataType; | ||
| 336 | mrGet.dwMDDataLen = mr.dwMDDataLen; | ||
| 337 | mrGet.pbMDData = static_cast<BYTE*>(MemAlloc(mr.dwMDDataLen, TRUE)); | ||
| 338 | |||
| 339 | hr = piMetabase->GetData(mhKey, pwzKey + 3, &mrGet, &dwTemp); | ||
| 340 | if (SUCCEEDED(hr)) | ||
| 341 | { | ||
| 342 | if (mrGet.dwMDDataType == mr.dwMDDataType && mrGet.dwMDDataLen == mr.dwMDDataLen && 0 == memcmp(mrGet.pbMDData, mr.pbMDData, mr.dwMDDataLen)) | ||
| 343 | { | ||
| 344 | WcaLog(LOGMSG_VERBOSE, "Received error while writing metabase value under key: %ls ID: %d with error 0x%x, but the correct value is in the metabase - continuing", pwzKey, mr.dwMDIdentifier, hrOldValue); | ||
| 345 | hr = S_OK; | ||
| 346 | } | ||
| 347 | else | ||
| 348 | { | ||
| 349 | WcaLog(LOGMSG_VERBOSE, "Succeeded in checking metabase value after write value, but the values didn't match"); | ||
| 350 | hr = hrOldValue; | ||
| 351 | } | ||
| 352 | } | ||
| 353 | else | ||
| 354 | { | ||
| 355 | WcaLog(LOGMSG_VERBOSE, "Failed to check value after metabase write failure (error code 0x%x)", hr); | ||
| 356 | hr = hrOldValue; | ||
| 357 | } | ||
| 358 | } | ||
| 359 | MessageExitOnFailure(hr, msierrIISFailedWriteData, "failed to write data to metabase key: %ls", pwzKey); | ||
| 360 | |||
| 361 | hr = WcaProgressMessage(COST_IIS_WRITEVALUE, FALSE); | ||
| 362 | |||
| 363 | LExit: | ||
| 364 | ReleaseStr(pwzTemp); | ||
| 365 | ReleaseStr(pwzKey); | ||
| 366 | |||
| 367 | if (mhKey) | ||
| 368 | { | ||
| 369 | piMetabase->CloseKey(mhKey); | ||
| 370 | } | ||
| 371 | |||
| 372 | if (fFreeData && mr.pbMDData) | ||
| 373 | { | ||
| 374 | MemFree(mr.pbMDData); | ||
| 375 | } | ||
| 376 | |||
| 377 | return hr; | ||
| 378 | } | ||
| 379 | |||
| 380 | |||
| 381 | /******************************************************************** | ||
| 382 | DeleteMetabaseValue -Installs metabase values | ||
| 383 | |||
| 384 | Input: deferred CustomActionData - Key\tIdentifier\tAttributes\tUserType\tDataType\tData | ||
| 385 | * *****************************************************************/ | ||
| 386 | static HRESULT DeleteMetabaseValue(__in LPWSTR* ppwzCustomActionData, __in IMSAdminBase* piMetabase) | ||
| 387 | { | ||
| 388 | //AssertSz(FALSE, "debug DeleteMetabaseValue here"); | ||
| 389 | HRESULT hr = S_OK; | ||
| 390 | |||
| 391 | METADATA_HANDLE mhKey = 0; | ||
| 392 | |||
| 393 | LPWSTR pwzKey = NULL; | ||
| 394 | DWORD dwIdentifier = 0; | ||
| 395 | DWORD dwDataType = 0; | ||
| 396 | |||
| 397 | int i; | ||
| 398 | |||
| 399 | // get the key first | ||
| 400 | hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzKey); | ||
| 401 | ExitOnFailure(hr, "failed to read key"); | ||
| 402 | hr = WcaReadIntegerFromCaData(ppwzCustomActionData, reinterpret_cast<int *>(&dwIdentifier)); | ||
| 403 | ExitOnFailure(hr, "failed to read identifier"); | ||
| 404 | hr = WcaReadIntegerFromCaData(ppwzCustomActionData, reinterpret_cast<int *>(&dwDataType)); | ||
| 405 | ExitOnFailure(hr, "failed to read data type"); | ||
| 406 | |||
| 407 | WcaLog(LOGMSG_VERBOSE, "Deleting Metabase Value Under Key: %ls ID: %d", pwzKey, dwIdentifier); | ||
| 408 | |||
| 409 | hr = piMetabase->OpenKey(METADATA_MASTER_ROOT_HANDLE, L"/LM", METADATA_PERMISSION_WRITE, 10, &mhKey); | ||
| 410 | for (i = 30; i > 0 && HRESULT_FROM_WIN32(ERROR_PATH_BUSY) == hr; i--) | ||
| 411 | { | ||
| 412 | ::Sleep(1000); | ||
| 413 | WcaLog(LOGMSG_STANDARD, "failed to open '%ls' key, retrying %d time(s)...", pwzKey, i); | ||
| 414 | hr = piMetabase->OpenKey(METADATA_MASTER_ROOT_HANDLE, L"/LM", METADATA_PERMISSION_WRITE, 10, &mhKey); | ||
| 415 | } | ||
| 416 | MessageExitOnFailure(hr, msierrIISFailedOpenKey, "failed to open metabase key: %ls", pwzKey); | ||
| 417 | |||
| 418 | if (lstrlenW(pwzKey) < 3) | ||
| 419 | { | ||
| 420 | ExitOnFailure(hr = E_INVALIDARG, "Key didn't begin with \"/LM\" as expected - key value: %ls", pwzKey); | ||
| 421 | } | ||
| 422 | |||
| 423 | hr = piMetabase->DeleteData(mhKey, pwzKey + 3, dwIdentifier, dwDataType); // pwzKey + 3 to skip "/LM" that was used to open the key. | ||
| 424 | if (MD_ERROR_DATA_NOT_FOUND == hr || HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) == hr) | ||
| 425 | { | ||
| 426 | hr = S_OK; | ||
| 427 | } | ||
| 428 | MessageExitOnFailure(hr, msierrIISFailedDeleteValue, "failed to delete value %d from metabase key: %ls", dwIdentifier, pwzKey); | ||
| 429 | |||
| 430 | hr = WcaProgressMessage(COST_IIS_DELETEVALUE, FALSE); | ||
| 431 | LExit: | ||
| 432 | ReleaseStr(pwzKey); | ||
| 433 | |||
| 434 | if (mhKey) | ||
| 435 | piMetabase->CloseKey(mhKey); | ||
| 436 | |||
| 437 | return hr; | ||
| 438 | } | ||
| 439 | |||
| 440 | |||
| 441 | /******************************************************************** | ||
| 442 | DeleteAspApp - Deletes applications in IIS | ||
| 443 | |||
| 444 | Input: deferred CustomActionData - MetabaseRoot\tRecursive | ||
| 445 | * *****************************************************************/ | ||
| 446 | static HRESULT DeleteAspApp(__in LPWSTR* ppwzCustomActionData, __in IMSAdminBase* piMetabase, __in ICatalogCollection* pApplicationCollection, __in IWamAdmin* piWam) | ||
| 447 | { | ||
| 448 | const int BUFFER_BYTES = 512; | ||
| 449 | const BSTR bstrPropName = SysAllocString(L"Deleteable"); | ||
| 450 | |||
| 451 | HRESULT hr = S_OK; | ||
| 452 | ICatalogObject* pApplication = NULL; | ||
| 453 | |||
| 454 | LPWSTR pwzRoot = NULL; | ||
| 455 | DWORD dwActualBufferSize = 0; | ||
| 456 | long lSize = 0; | ||
| 457 | long lIndex = 0; | ||
| 458 | long lChanges = 0; | ||
| 459 | |||
| 460 | VARIANT keyValue; | ||
| 461 | ::VariantInit(&keyValue); | ||
| 462 | VARIANT propValue; | ||
| 463 | propValue.vt = VT_BOOL; | ||
| 464 | propValue.boolVal = TRUE; | ||
| 465 | |||
| 466 | METADATA_RECORD mr; | ||
| 467 | // Get current set of web service extensions. | ||
| 468 | ::ZeroMemory(&mr, sizeof(mr)); | ||
| 469 | mr.dwMDIdentifier = MD_APP_PACKAGE_ID; | ||
| 470 | mr.dwMDAttributes = 0; | ||
| 471 | mr.dwMDUserType = ASP_MD_UT_APP; | ||
| 472 | mr.dwMDDataType = STRING_METADATA; | ||
| 473 | mr.pbMDData = new unsigned char[BUFFER_BYTES]; | ||
| 474 | mr.dwMDDataLen = BUFFER_BYTES; | ||
| 475 | |||
| 476 | hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzRoot); // MetabaseRoot | ||
| 477 | ExitOnFailure(hr, "failed to get metabase root"); | ||
| 478 | |||
| 479 | hr = piMetabase->GetData(METADATA_MASTER_ROOT_HANDLE, pwzRoot, &mr, &dwActualBufferSize); | ||
| 480 | if (HRESULT_FROM_WIN32(MD_ERROR_DATA_NOT_FOUND) == hr || HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) == hr || HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr) | ||
| 481 | { | ||
| 482 | // This one doesn't have an independent app GUID associated with it - it may have been already partially deleted, or a low isolation app | ||
| 483 | WcaLog(LOGMSG_VERBOSE, "No independent COM+ application found associated with %ls. It either doesn't exist, or was already removed - continuing", pwzRoot); | ||
| 484 | ExitFunction1(hr = S_OK); | ||
| 485 | } | ||
| 486 | MessageExitOnFailure(hr, msierrIISFailedDeleteApp, "failed to get GUID for application at path: %ls", pwzRoot); | ||
| 487 | |||
| 488 | WcaLog(LOGMSG_VERBOSE, "Deleting ASP App (used query: %ls) with GUID: %ls", pwzRoot, (LPWSTR)(mr.pbMDData)); | ||
| 489 | |||
| 490 | // Delete the application association from IIS's point of view before it's obliterated from the application collection | ||
| 491 | hr = piWam->AppDelete(pwzRoot, FALSE); | ||
| 492 | if (FAILED(hr)) | ||
| 493 | { | ||
| 494 | // This isn't necessarily an error if we fail here, but let's log a failure if it happens | ||
| 495 | WcaLog(LOGMSG_VERBOSE, "error 0x%x: failed to call IWamAdmin::AppDelete() while removing web application - continuing"); | ||
| 496 | hr = S_OK; | ||
| 497 | } | ||
| 498 | |||
| 499 | if (!pApplicationCollection) | ||
| 500 | { | ||
| 501 | WcaLog(LOGMSG_STANDARD, "Could not remove application with GUID %ls because the application collection could not be found", (LPWSTR)(mr.pbMDData)); | ||
| 502 | ExitFunction1(hr = S_OK); | ||
| 503 | } | ||
| 504 | |||
| 505 | hr = pApplicationCollection->Populate(); | ||
| 506 | MessageExitOnFailure(hr, msierrIISFailedDeleteApp, "failed to populate Application collection"); | ||
| 507 | |||
| 508 | hr = pApplicationCollection->get_Count(&lSize); | ||
| 509 | MessageExitOnFailure(hr, msierrIISFailedDeleteApp, "failed to get size of Application collection"); | ||
| 510 | WcaLog(LOGMSG_TRACEONLY, "Found %u items in application collection", lSize); | ||
| 511 | |||
| 512 | // No need to check this too early, as we may not even need this to have successfully allocated | ||
| 513 | ExitOnNull(bstrPropName, hr, E_OUTOFMEMORY, "failed to allocate memory for \"Deleteable\" string"); | ||
| 514 | |||
| 515 | for (lIndex = 0; lIndex < lSize; ++lIndex) | ||
| 516 | { | ||
| 517 | hr = pApplicationCollection->get_Item(lIndex, reinterpret_cast<IDispatch**>(&pApplication)); | ||
| 518 | MessageExitOnFailure(hr, msierrIISFailedDeleteApp, "failed to get COM+ application while enumerating through COM+ applications"); | ||
| 519 | |||
| 520 | hr = pApplication->get_Key(&keyValue); | ||
| 521 | MessageExitOnFailure(hr, msierrIISFailedDeleteApp, "failed to get key of COM+ application while enumerating through COM+ applications"); | ||
| 522 | |||
| 523 | WcaLog(LOGMSG_TRACEONLY, "While enumerating through COM+ applications, found an application with GUID: %ls", (LPWSTR)keyValue.bstrVal); | ||
| 524 | |||
| 525 | if (VT_BSTR == keyValue.vt && 0 == lstrcmpW((LPWSTR)keyValue.bstrVal, (LPWSTR)(mr.pbMDData))) | ||
| 526 | { | ||
| 527 | hr = pApplication->put_Value(bstrPropName, propValue); | ||
| 528 | if (FAILED(hr)) | ||
| 529 | { | ||
| 530 | // This isn't necessarily a critical error unless we fail to actually delete it in the next step | ||
| 531 | WcaLog(LOGMSG_VERBOSE, "error 0x%x: failed to ensure COM+ application with guid %ls is deletable - continuing", hr, (LPWSTR)(mr.pbMDData)); | ||
| 532 | } | ||
| 533 | |||
| 534 | hr = pApplicationCollection->SaveChanges(&lChanges); | ||
| 535 | if (FAILED(hr)) | ||
| 536 | { | ||
| 537 | // This isn't necessarily a critical error unless we fail to actually delete it in the next step | ||
| 538 | WcaLog(LOGMSG_VERBOSE, "error 0x%x: failed to save changes while ensuring COM+ application with guid %ls is deletable - continuing", hr, (LPWSTR)(mr.pbMDData)); | ||
| 539 | } | ||
| 540 | |||
| 541 | hr = pApplicationCollection->Remove(lIndex); | ||
| 542 | if (FAILED(hr)) | ||
| 543 | { | ||
| 544 | WcaLog(LOGMSG_STANDARD, "error 0x%x: failed to remove COM+ application with guid %ls. The COM application will not be removed", hr, (LPWSTR)(mr.pbMDData)); | ||
| 545 | } | ||
| 546 | else | ||
| 547 | { | ||
| 548 | hr = pApplicationCollection->SaveChanges(&lChanges); | ||
| 549 | if (FAILED(hr)) | ||
| 550 | { | ||
| 551 | WcaLog(LOGMSG_STANDARD, "error 0x%x: failed to save changes when removing COM+ application with guid %ls. The COM application will not be removed - continuing", hr, (LPWSTR)(mr.pbMDData)); | ||
| 552 | } | ||
| 553 | else | ||
| 554 | { | ||
| 555 | WcaLog(LOGMSG_VERBOSE, "Found and removed application with GUID %ls", (LPWSTR)(mr.pbMDData)); | ||
| 556 | } | ||
| 557 | } | ||
| 558 | |||
| 559 | // We've found the right key and successfully deleted the app - let's exit the loop now | ||
| 560 | lIndex = lSize; | ||
| 561 | } | ||
| 562 | } | ||
| 563 | // If we didn't find it, it isn't an error, because the application we want to delete doesn't seem to exist! | ||
| 564 | |||
| 565 | hr = WcaProgressMessage(COST_IIS_DELETEAPP, FALSE); | ||
| 566 | LExit: | ||
| 567 | ReleaseBSTR(bstrPropName); | ||
| 568 | |||
| 569 | ReleaseStr(pwzRoot); | ||
| 570 | // Don't release pApplication, because it points to an object within the collection | ||
| 571 | |||
| 572 | delete [] mr.pbMDData; | ||
| 573 | |||
| 574 | return hr; | ||
| 575 | } | ||
| 576 | |||
| 577 | |||
| 578 | /******************************************************************** | ||
| 579 | CreateAspApp - Creates applications in IIS | ||
| 580 | |||
| 581 | Input: deferred CustomActionData - MetabaseRoot\tInProc | ||
| 582 | * ****************************************************************/ | ||
| 583 | static HRESULT CreateAspApp(__in LPWSTR* ppwzCustomActionData, __in IWamAdmin* piWam) | ||
| 584 | { | ||
| 585 | HRESULT hr = S_OK; | ||
| 586 | |||
| 587 | LPWSTR pwzRoot = NULL; | ||
| 588 | BOOL fInProc; | ||
| 589 | |||
| 590 | hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzRoot); // MetabaseRoot | ||
| 591 | ExitOnFailure(hr, "failed to get metabase root"); | ||
| 592 | hr = WcaReadIntegerFromCaData(ppwzCustomActionData, reinterpret_cast<int *>(&fInProc)); // InProc | ||
| 593 | ExitOnFailure(hr, "failed to get in proc flag"); | ||
| 594 | |||
| 595 | WcaLog(LOGMSG_VERBOSE, "Creating ASP App: %ls", pwzRoot); | ||
| 596 | |||
| 597 | hr = piWam->AppCreate(pwzRoot, fInProc); | ||
| 598 | MessageExitOnFailure(hr, msierrIISFailedCreateApp, "failed to create web application: %ls", pwzRoot); | ||
| 599 | |||
| 600 | hr = WcaProgressMessage(COST_IIS_CREATEAPP, FALSE); | ||
| 601 | LExit: | ||
| 602 | return hr; | ||
| 603 | } | ||
| 604 | |||
| 605 | |||
| 606 | /******************************************************************** | ||
| 607 | DeleteMetabaseKey - Deletes metabase keys | ||
| 608 | |||
| 609 | Input: deferred CustomActionData - Key | ||
| 610 | ******************************************************************/ | ||
| 611 | static HRESULT DeleteMetabaseKey(__in LPWSTR *ppwzCustomActionData, __in IMSAdminBase* piMetabase) | ||
| 612 | { | ||
| 613 | HRESULT hr = S_OK; | ||
| 614 | |||
| 615 | METADATA_HANDLE mhRoot = 0; | ||
| 616 | |||
| 617 | LPWSTR pwzData = NULL; | ||
| 618 | |||
| 619 | LPCWSTR pwzKey; | ||
| 620 | int i; | ||
| 621 | |||
| 622 | hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzData); | ||
| 623 | ExitOnFailure(hr, "failed to read key to be deleted"); | ||
| 624 | |||
| 625 | hr = piMetabase->OpenKey(METADATA_MASTER_ROOT_HANDLE, L"/LM", METADATA_PERMISSION_WRITE, 10, &mhRoot); | ||
| 626 | for (i = 30; i > 0 && HRESULT_FROM_WIN32(ERROR_PATH_BUSY) == hr; i--) | ||
| 627 | { | ||
| 628 | ::Sleep(1000); | ||
| 629 | WcaLog(LOGMSG_STANDARD, "failed to open root key, retrying %d time(s)...", i); | ||
| 630 | hr = piMetabase->OpenKey(METADATA_MASTER_ROOT_HANDLE, L"/LM", METADATA_PERMISSION_WRITE, 10, &mhRoot); | ||
| 631 | } | ||
| 632 | MessageExitOnFailure(hr, msierrIISFailedOpenKey, "failed to open metabase key: %ls", L"/LM"); | ||
| 633 | |||
| 634 | pwzKey = pwzData + 3; | ||
| 635 | |||
| 636 | WcaLog(LOGMSG_VERBOSE, "Deleting Metabase Key: %ls", pwzKey); | ||
| 637 | |||
| 638 | hr = piMetabase->DeleteKey(mhRoot, pwzKey); | ||
| 639 | if (HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) == hr) | ||
| 640 | { | ||
| 641 | WcaLog(LOGMSG_STANDARD, "Key `%ls` did not exist, continuing.", pwzData); | ||
| 642 | hr = S_OK; | ||
| 643 | } | ||
| 644 | MessageExitOnFailure(hr, msierrIISFailedDeleteKey, "failed to delete metabase key: %ls", pwzData); | ||
| 645 | |||
| 646 | hr = WcaProgressMessage(COST_IIS_DELETEKEY, FALSE); | ||
| 647 | LExit: | ||
| 648 | if (mhRoot) | ||
| 649 | { | ||
| 650 | piMetabase->CloseKey(mhRoot); | ||
| 651 | } | ||
| 652 | |||
| 653 | return hr; | ||
| 654 | } | ||
| 655 | |||
| 656 | |||
| 657 | /******************************************************************** | ||
| 658 | WriteMetabaseChanges - CUSTOM ACTION ENTRY POINT for IIS Metabase changes | ||
| 659 | |||
| 660 | *******************************************************************/ | ||
| 661 | extern "C" UINT __stdcall WriteMetabaseChanges(MSIHANDLE hInstall) | ||
| 662 | { | ||
| 663 | //AssertSz(FALSE, "debug WriteMetabaseChanges here"); | ||
| 664 | HRESULT hr = S_OK; | ||
| 665 | UINT er = ERROR_SUCCESS; | ||
| 666 | IMSAdminBase* piMetabase = NULL; | ||
| 667 | IWamAdmin* piWam = NULL; | ||
| 668 | ICOMAdminCatalog* pCatalog = NULL; | ||
| 669 | ICatalogCollection* pApplicationCollection = NULL; | ||
| 670 | WCA_CASCRIPT_HANDLE hWriteMetabaseScript = NULL; | ||
| 671 | BSTR bstrApplications = SysAllocString(L"Applications"); | ||
| 672 | BOOL fInitializedCom = FALSE; | ||
| 673 | |||
| 674 | LPWSTR pwzData = NULL; | ||
| 675 | LPWSTR pwz = NULL; | ||
| 676 | LPWSTR pwzScriptKey = NULL; | ||
| 677 | METABASE_ACTION maAction = MBA_UNKNOWNACTION; | ||
| 678 | |||
| 679 | hr = WcaInitialize(hInstall, "WriteMetabaseChanges"); | ||
| 680 | ExitOnFailure(hr, "failed to initialize"); | ||
| 681 | |||
| 682 | hr = ::CoInitialize(NULL); | ||
| 683 | ExitOnFailure(hr, "failed to initialize COM"); | ||
| 684 | fInitializedCom = TRUE; | ||
| 685 | |||
| 686 | hr = WcaGetProperty( L"CustomActionData", &pwzData); | ||
| 687 | ExitOnFailure(hr, "failed to get CustomActionData"); | ||
| 688 | |||
| 689 | WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %ls", pwzData); | ||
| 690 | |||
| 691 | // Get the CaScript key | ||
| 692 | hr = WcaReadStringFromCaData(&pwzData, &pwzScriptKey); | ||
| 693 | ExitOnFailure(hr, "Failed to get CaScript key from custom action data"); | ||
| 694 | |||
| 695 | hr = WcaCaScriptOpen(WCA_ACTION_INSTALL, WCA_CASCRIPT_SCHEDULED, FALSE, pwzScriptKey, &hWriteMetabaseScript); | ||
| 696 | ExitOnFailure(hr, "Failed to open CaScript file"); | ||
| 697 | |||
| 698 | // The rest of our existing custom action data string should be empty - go ahead and overwrite it | ||
| 699 | ReleaseNullStr(pwzData); | ||
| 700 | hr = WcaCaScriptReadAsCustomActionData(hWriteMetabaseScript, &pwzData); | ||
| 701 | ExitOnFailure(hr, "Failed to read script into CustomAction data."); | ||
| 702 | |||
| 703 | pwz = pwzData; | ||
| 704 | |||
| 705 | while (S_OK == (hr = WcaReadIntegerFromCaData(&pwz, (int *)&maAction))) | ||
| 706 | { | ||
| 707 | switch (maAction) | ||
| 708 | { | ||
| 709 | case MBA_CREATEAPP: | ||
| 710 | if (NULL == piWam) | ||
| 711 | { | ||
| 712 | hr = ::CoCreateInstance(CLSID_WamAdmin, NULL, CLSCTX_ALL, IID_IWamAdmin, reinterpret_cast<void**>(&piWam)); | ||
| 713 | MessageExitOnFailure(hr, msierrIISCannotConnect, "failed to get IID_IWamAdmin object"); | ||
| 714 | } | ||
| 715 | |||
| 716 | hr = CreateAspApp(&pwz, piWam); | ||
| 717 | ExitOnFailure(hr, "failed to create ASP App"); | ||
| 718 | break; | ||
| 719 | case MBA_DELETEAPP: | ||
| 720 | if (NULL == piMetabase) | ||
| 721 | { | ||
| 722 | hr = ::CoCreateInstance(CLSID_MSAdminBase, NULL, CLSCTX_ALL, IID_IMSAdminBase, reinterpret_cast<void**>(&piMetabase)); | ||
| 723 | MessageExitOnFailure(hr, msierrIISCannotConnect, "failed to get IID_IIMSAdminBase object"); | ||
| 724 | } | ||
| 725 | |||
| 726 | if (NULL == pCatalog) | ||
| 727 | { | ||
| 728 | hr = CoCreateInstance(CLSID_COMAdminCatalog, NULL, CLSCTX_INPROC_SERVER, IID_IUnknown, (void**)&pCatalog); | ||
| 729 | MessageExitOnFailure(hr, msierrIISCannotConnect, "failed to get IID_ICOMAdmin object"); | ||
| 730 | |||
| 731 | hr = pCatalog->GetCollection(bstrApplications, reinterpret_cast<IDispatch**>(&pApplicationCollection)); | ||
| 732 | if (FAILED(hr)) | ||
| 733 | { | ||
| 734 | hr = S_OK; | ||
| 735 | WcaLog(LOGMSG_STANDARD, "error 0x%x: failed to get ApplicationCollection object for list of COM+ applications - COM+ applications will not be able to be uninstalled - continuing", hr); | ||
| 736 | } | ||
| 737 | } | ||
| 738 | |||
| 739 | if (NULL == piWam) | ||
| 740 | { | ||
| 741 | hr = ::CoCreateInstance(CLSID_WamAdmin, NULL, CLSCTX_ALL, IID_IWamAdmin, reinterpret_cast<void**>(&piWam)); | ||
| 742 | MessageExitOnFailure(hr, msierrIISCannotConnect, "failed to get IID_IWamAdmin object"); | ||
| 743 | } | ||
| 744 | |||
| 745 | hr = DeleteAspApp(&pwz, piMetabase, pApplicationCollection, piWam); | ||
| 746 | ExitOnFailure(hr, "failed to delete ASP App"); | ||
| 747 | break; | ||
| 748 | case MBA_CREATEKEY: | ||
| 749 | if (NULL == piMetabase) | ||
| 750 | { | ||
| 751 | hr = ::CoCreateInstance(CLSID_MSAdminBase, NULL, CLSCTX_ALL, IID_IMSAdminBase, reinterpret_cast<void**>(&piMetabase)); | ||
| 752 | MessageExitOnFailure(hr, msierrIISCannotConnect, "failed to get IID_IIMSAdminBase object"); | ||
| 753 | } | ||
| 754 | |||
| 755 | hr = CreateMetabaseKey(&pwz, piMetabase); | ||
| 756 | ExitOnFailure(hr, "failed to create metabase key"); | ||
| 757 | break; | ||
| 758 | case MBA_DELETEKEY: | ||
| 759 | if (NULL == piMetabase) | ||
| 760 | { | ||
| 761 | hr = ::CoCreateInstance(CLSID_MSAdminBase, NULL, CLSCTX_ALL, IID_IMSAdminBase, reinterpret_cast<void**>(&piMetabase)); | ||
| 762 | MessageExitOnFailure(hr, msierrIISCannotConnect, "failed to get IID_IIMSAdminBase object"); | ||
| 763 | } | ||
| 764 | |||
| 765 | hr = DeleteMetabaseKey(&pwz, piMetabase); | ||
| 766 | ExitOnFailure(hr, "failed to delete metabase key"); | ||
| 767 | break; | ||
| 768 | case MBA_WRITEVALUE: | ||
| 769 | if (NULL == piMetabase) | ||
| 770 | { | ||
| 771 | hr = ::CoCreateInstance(CLSID_MSAdminBase, NULL, CLSCTX_ALL, IID_IMSAdminBase, reinterpret_cast<void**>(&piMetabase)); | ||
| 772 | MessageExitOnFailure(hr, msierrIISCannotConnect, "failed to get IID_IIMSAdminBase object"); | ||
| 773 | } | ||
| 774 | |||
| 775 | hr = WriteMetabaseValue(&pwz, piMetabase); | ||
| 776 | ExitOnFailure(hr, "failed to write metabase value"); | ||
| 777 | break; | ||
| 778 | case MBA_DELETEVALUE: | ||
| 779 | if (NULL == piMetabase) | ||
| 780 | { | ||
| 781 | hr = ::CoCreateInstance(CLSID_MSAdminBase, NULL, CLSCTX_ALL, IID_IMSAdminBase, reinterpret_cast<void**>(&piMetabase)); | ||
| 782 | MessageExitOnFailure(hr, msierrIISCannotConnect, "failed to get IID_IIMSAdminBase object"); | ||
| 783 | } | ||
| 784 | |||
| 785 | hr = DeleteMetabaseValue(&pwz, piMetabase); | ||
| 786 | ExitOnFailure(hr, "failed to delete metabase value"); | ||
| 787 | break; | ||
| 788 | default: | ||
| 789 | ExitOnFailure(hr = E_UNEXPECTED, "Unexpected metabase action specified: %d", maAction); | ||
| 790 | break; | ||
| 791 | } | ||
| 792 | } | ||
| 793 | if (E_NOMOREITEMS == hr) // If there are no more items, all is well | ||
| 794 | { | ||
| 795 | if (NULL != piMetabase) | ||
| 796 | { | ||
| 797 | hr = piMetabase->SaveData(); | ||
| 798 | for (int i = 30; i > 0 && HRESULT_FROM_WIN32(ERROR_PATH_BUSY) == hr; i--) | ||
| 799 | { | ||
| 800 | ::Sleep(1000); | ||
| 801 | WcaLog(LOGMSG_VERBOSE, "Failed to force save of metabase data, retrying %d time(s)...", i); | ||
| 802 | hr = piMetabase->SaveData(); | ||
| 803 | } | ||
| 804 | if (FAILED(hr)) | ||
| 805 | { | ||
| 806 | WcaLog(LOGMSG_VERBOSE, "Failed to force save of metabase data: 0x%x - continuing", hr); | ||
| 807 | } | ||
| 808 | hr = S_OK; | ||
| 809 | } | ||
| 810 | else | ||
| 811 | { | ||
| 812 | hr = S_OK; | ||
| 813 | } | ||
| 814 | } | ||
| 815 | |||
| 816 | LExit: | ||
| 817 | WcaCaScriptClose(hWriteMetabaseScript, WCA_CASCRIPT_CLOSE_DELETE); | ||
| 818 | |||
| 819 | ReleaseBSTR(bstrApplications); | ||
| 820 | ReleaseStr(pwzScriptKey); | ||
| 821 | ReleaseStr(pwzData); | ||
| 822 | ReleaseObject(piMetabase); | ||
| 823 | ReleaseObject(piWam); | ||
| 824 | ReleaseObject(pCatalog); | ||
| 825 | ReleaseObject(pApplicationCollection); | ||
| 826 | |||
| 827 | if (fInitializedCom) | ||
| 828 | { | ||
| 829 | ::CoUninitialize(); | ||
| 830 | } | ||
| 831 | |||
| 832 | if (FAILED(hr)) | ||
| 833 | { | ||
| 834 | er = ERROR_INSTALL_FAILURE; | ||
| 835 | } | ||
| 836 | return WcaFinalize(er); | ||
| 837 | } | ||
| 838 | /******************************************************************** | ||
| 839 | WriteIIS7ConfigChanges - CUSTOM ACTION ENTRY POINT for IIS7 config changes | ||
| 840 | |||
| 841 | *******************************************************************/ | ||
| 842 | extern "C" UINT __stdcall WriteIIS7ConfigChanges(MSIHANDLE hInstall) | ||
| 843 | { | ||
| 844 | //AssertSz(FALSE, "debug WriteIIS7ConfigChanges here"); | ||
| 845 | HRESULT hr = S_OK; | ||
| 846 | UINT er = ERROR_SUCCESS; | ||
| 847 | LPWSTR pwzData = NULL; | ||
| 848 | LPWSTR pwzScriptKey = NULL; | ||
| 849 | LPWSTR pwzHashString = NULL; | ||
| 850 | BYTE rgbActualHash[SHA1_HASH_LEN] = { }; | ||
| 851 | DWORD dwHashedBytes = SHA1_HASH_LEN; | ||
| 852 | |||
| 853 | WCA_CASCRIPT_HANDLE hWriteIis7Script = NULL; | ||
| 854 | |||
| 855 | hr = WcaInitialize(hInstall, "WriteIIS7ConfigChanges"); | ||
| 856 | ExitOnFailure(hr, "Failed to initialize"); | ||
| 857 | |||
| 858 | hr = WcaGetProperty( L"CustomActionData", &pwzScriptKey); | ||
| 859 | ExitOnFailure(hr, "Failed to get CustomActionData"); | ||
| 860 | WcaLog(LOGMSG_TRACEONLY, "Script WriteIIS7ConfigChanges: %ls", pwzScriptKey); | ||
| 861 | |||
| 862 | hr = WcaCaScriptOpen(WCA_ACTION_INSTALL, WCA_CASCRIPT_SCHEDULED, FALSE, pwzScriptKey, &hWriteIis7Script); | ||
| 863 | ExitOnFailure(hr, "Failed to open CaScript file"); | ||
| 864 | |||
| 865 | hr = WcaCaScriptReadAsCustomActionData(hWriteIis7Script, &pwzData); | ||
| 866 | ExitOnFailure(hr, "Failed to read script into CustomAction data."); | ||
| 867 | |||
| 868 | hr = CrypHashBuffer((BYTE*)pwzData, sizeof(pwzData) * sizeof(WCHAR), PROV_RSA_AES, CALG_SHA1, rgbActualHash, dwHashedBytes); | ||
| 869 | ExitOnFailure(hr, "Failed to calculate hash of CustomAction data."); | ||
| 870 | |||
| 871 | hr = StrAlloc(&pwzHashString, ((dwHashedBytes * 2) + 1)); | ||
| 872 | ExitOnFailure(hr, "Failed to allocate string for script hash"); | ||
| 873 | |||
| 874 | hr = StrHexEncode(rgbActualHash, dwHashedBytes, pwzHashString, ((dwHashedBytes * 2) + 1)); | ||
| 875 | ExitOnFailure(hr, "Failed to convert hash bytes to string."); | ||
| 876 | |||
| 877 | WcaLog(LOGMSG_TRACEONLY, "CustomActionData WriteIIS7ConfigChanges: %ls", pwzData); | ||
| 878 | WcaLog(LOGMSG_VERBOSE, "Custom action data hash: %ls", pwzHashString); | ||
| 879 | WcaLog(LOGMSG_VERBOSE, "CustomActionData WriteIIS7ConfigChanges length: %d", wcslen(pwzData)); | ||
| 880 | |||
| 881 | hr = IIS7ConfigChanges(hInstall, pwzData); | ||
| 882 | ExitOnFailure(hr, "WriteIIS7ConfigChanges Failed."); | ||
| 883 | |||
| 884 | LExit: | ||
| 885 | WcaCaScriptClose(hWriteIis7Script, WCA_CASCRIPT_CLOSE_DELETE); | ||
| 886 | ReleaseStr(pwzScriptKey); | ||
| 887 | ReleaseStr(pwzData); | ||
| 888 | ReleaseStr(pwzHashString); | ||
| 889 | |||
| 890 | if (FAILED(hr)) | ||
| 891 | { | ||
| 892 | er = ERROR_INSTALL_FAILURE; | ||
| 893 | } | ||
| 894 | |||
| 895 | return WcaFinalize(er); | ||
| 896 | } | ||
| 897 | |||
| 898 | |||
| 899 | /******************************************************************** | ||
| 900 | CommitIIS7ConfigTransaction - CUSTOM ACTION ENTRY POINT for unbacking up config | ||
| 901 | |||
| 902 | Input: deferred CustomActionData - BackupName | ||
| 903 | * *****************************************************************/ | ||
| 904 | extern "C" UINT __stdcall CommitIIS7ConfigTransaction(MSIHANDLE hInstall) | ||
| 905 | { | ||
| 906 | HRESULT hr = S_OK; | ||
| 907 | UINT er = ERROR_SUCCESS; | ||
| 908 | LPWSTR pwzData = NULL; | ||
| 909 | WCHAR wzConfigCopy[MAX_PATH]; | ||
| 910 | DWORD dwSize = 0; | ||
| 911 | |||
| 912 | BOOL fIsWow64Process = FALSE; | ||
| 913 | BOOL fIsFSRedirectDisabled = FALSE; | ||
| 914 | |||
| 915 | hr = WcaInitialize(hInstall, "CommitIIS7ConfigTransaction"); | ||
| 916 | ExitOnFailure(hr, "failed to initialize IIS7 commit transaction"); | ||
| 917 | |||
| 918 | WcaInitializeWow64(); | ||
| 919 | fIsWow64Process = WcaIsWow64Process(); | ||
| 920 | if (fIsWow64Process) | ||
| 921 | { | ||
| 922 | hr = WcaDisableWow64FSRedirection(); | ||
| 923 | if(FAILED(hr)) | ||
| 924 | { | ||
| 925 | //eat this error | ||
| 926 | hr = S_OK; | ||
| 927 | } | ||
| 928 | else | ||
| 929 | { | ||
| 930 | fIsFSRedirectDisabled = TRUE; | ||
| 931 | } | ||
| 932 | } | ||
| 933 | |||
| 934 | hr = WcaGetProperty( L"CustomActionData", &pwzData); | ||
| 935 | ExitOnFailure(hr, "failed to get CustomActionData"); | ||
| 936 | |||
| 937 | // Config AdminMgr changes already committed, just | ||
| 938 | // delete backup config file. | ||
| 939 | |||
| 940 | dwSize = ExpandEnvironmentStringsW(L"%windir%\\system32\\inetsrv\\config\\applicationHost.config", | ||
| 941 | wzConfigCopy, | ||
| 942 | MAX_PATH | ||
| 943 | ); | ||
| 944 | if ( dwSize == 0 ) | ||
| 945 | { | ||
| 946 | ExitWithLastError(hr, "failed to get ExpandEnvironmentStrings"); | ||
| 947 | } | ||
| 948 | |||
| 949 | hr = ::StringCchCatW(wzConfigCopy, MAX_PATH, L"."); | ||
| 950 | ExitOnFailure(hr, "Commit IIS7 failed StringCchCatW of ."); | ||
| 951 | |||
| 952 | hr = ::StringCchCatW(wzConfigCopy, MAX_PATH, pwzData); | ||
| 953 | ExitOnFailure(hr, "Commit IIS7 failed StringCchCatW of extension"); | ||
| 954 | |||
| 955 | if (!::DeleteFileW(wzConfigCopy)) | ||
| 956 | { | ||
| 957 | hr = HRESULT_FROM_WIN32(GetLastError()); | ||
| 958 | if (HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) == hr || | ||
| 959 | HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr) | ||
| 960 | { | ||
| 961 | WcaLog(LOGMSG_STANDARD, "Failed to delete backup applicationHost, not found - continuing"); | ||
| 962 | hr = S_OK; | ||
| 963 | } | ||
| 964 | else | ||
| 965 | { | ||
| 966 | ExitOnFailure(hr, "failed to delete config backup"); | ||
| 967 | } | ||
| 968 | } | ||
| 969 | |||
| 970 | LExit: | ||
| 971 | ReleaseStr(pwzData); | ||
| 972 | |||
| 973 | // Make sure we revert FS Redirection if necessary before exiting | ||
| 974 | if (fIsFSRedirectDisabled) | ||
| 975 | { | ||
| 976 | fIsFSRedirectDisabled = FALSE; | ||
| 977 | WcaRevertWow64FSRedirection(); | ||
| 978 | } | ||
| 979 | WcaFinalizeWow64(); | ||
| 980 | |||
| 981 | |||
| 982 | if (FAILED(hr)) | ||
| 983 | { | ||
| 984 | er = ERROR_INSTALL_FAILURE; | ||
| 985 | } | ||
| 986 | return WcaFinalize(er); | ||
| 987 | } | ||
| 988 | /******************************************************************** | ||
| 989 | StartIIS7Config Transaction - CUSTOM ACTION ENTRY POINT for backing up config | ||
| 990 | |||
| 991 | Input: deferred CustomActionData - BackupName | ||
| 992 | ********************************************************************/ | ||
| 993 | extern "C" UINT __stdcall StartIIS7ConfigTransaction(MSIHANDLE hInstall) | ||
| 994 | { | ||
| 995 | HRESULT hr = S_OK; | ||
| 996 | UINT er = ERROR_SUCCESS; | ||
| 997 | LPWSTR pwzData = NULL; | ||
| 998 | WCHAR wzConfigSource[MAX_PATH]; | ||
| 999 | WCHAR wzConfigCopy[MAX_PATH]; | ||
| 1000 | DWORD dwSize = 0; | ||
| 1001 | |||
| 1002 | |||
| 1003 | BOOL fIsWow64Process = FALSE; | ||
| 1004 | BOOL fIsFSRedirectDisabled = FALSE; | ||
| 1005 | |||
| 1006 | // initialize | ||
| 1007 | hr = WcaInitialize(hInstall, "StartIIS7ConfigTransaction"); | ||
| 1008 | ExitOnFailure(hr, "failed to initialize StartIIS7ConfigTransaction"); | ||
| 1009 | |||
| 1010 | WcaInitializeWow64(); | ||
| 1011 | fIsWow64Process = WcaIsWow64Process(); | ||
| 1012 | if (fIsWow64Process) | ||
| 1013 | { | ||
| 1014 | hr = WcaDisableWow64FSRedirection(); | ||
| 1015 | if(FAILED(hr)) | ||
| 1016 | { | ||
| 1017 | //eat this error | ||
| 1018 | hr = S_OK; | ||
| 1019 | } | ||
| 1020 | else | ||
| 1021 | { | ||
| 1022 | fIsFSRedirectDisabled = TRUE; | ||
| 1023 | } | ||
| 1024 | } | ||
| 1025 | |||
| 1026 | hr = WcaGetProperty(L"CustomActionData", &pwzData); | ||
| 1027 | ExitOnFailure(hr, "failed to get CustomActionData"); | ||
| 1028 | |||
| 1029 | |||
| 1030 | dwSize = ExpandEnvironmentStringsW(L"%windir%\\system32\\inetsrv\\config\\applicationHost.config", | ||
| 1031 | wzConfigSource, | ||
| 1032 | MAX_PATH | ||
| 1033 | ); | ||
| 1034 | if ( dwSize == 0 ) | ||
| 1035 | { | ||
| 1036 | ExitWithLastError(hr, "failed to get ExpandEnvironmentStrings"); | ||
| 1037 | } | ||
| 1038 | hr = ::StringCchCopyW(wzConfigCopy, MAX_PATH, wzConfigSource); | ||
| 1039 | ExitOnFailure(hr, "Commit IIS7 failed StringCchCopyW"); | ||
| 1040 | |||
| 1041 | //add ca action as extension | ||
| 1042 | |||
| 1043 | hr = ::StringCchCatW(wzConfigCopy, MAX_PATH, L"."); | ||
| 1044 | ExitOnFailure(hr, "Commit IIS7 failed StringCchCatW of ."); | ||
| 1045 | |||
| 1046 | hr = ::StringCchCatW(wzConfigCopy, MAX_PATH, pwzData); | ||
| 1047 | ExitOnFailure(hr, "Commit IIS7 failed StringCchCatW of extension"); | ||
| 1048 | |||
| 1049 | if ( !::CopyFileW(wzConfigSource, wzConfigCopy, FALSE) ) | ||
| 1050 | { | ||
| 1051 | hr = HRESULT_FROM_WIN32(GetLastError()); | ||
| 1052 | if (HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) == hr || | ||
| 1053 | HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr) | ||
| 1054 | { | ||
| 1055 | // IIS may not be installed on the machine, we'll fail later if we try to install anything | ||
| 1056 | WcaLog(LOGMSG_STANDARD, "Failed to back up applicationHost, not found - continuing"); | ||
| 1057 | hr = S_OK; | ||
| 1058 | } | ||
| 1059 | else | ||
| 1060 | { | ||
| 1061 | ExitOnFailure(hr, "Failed to copy config backup %ls -> %ls", wzConfigSource, wzConfigCopy); | ||
| 1062 | } | ||
| 1063 | } | ||
| 1064 | |||
| 1065 | |||
| 1066 | hr = WcaProgressMessage(COST_IIS_TRANSACTIONS, FALSE); | ||
| 1067 | |||
| 1068 | |||
| 1069 | LExit: | ||
| 1070 | |||
| 1071 | ReleaseStr(pwzData); | ||
| 1072 | |||
| 1073 | // Make sure we revert FS Redirection if necessary before exiting | ||
| 1074 | if (fIsFSRedirectDisabled) | ||
| 1075 | { | ||
| 1076 | fIsFSRedirectDisabled = FALSE; | ||
| 1077 | WcaRevertWow64FSRedirection(); | ||
| 1078 | } | ||
| 1079 | WcaFinalizeWow64(); | ||
| 1080 | |||
| 1081 | if (FAILED(hr)) | ||
| 1082 | er = ERROR_INSTALL_FAILURE; | ||
| 1083 | return WcaFinalize(er); | ||
| 1084 | } | ||
| 1085 | |||
| 1086 | |||
| 1087 | /******************************************************************** | ||
| 1088 | RollbackIIS7ConfigTransaction - CUSTOM ACTION ENTRY POINT for unbacking up config | ||
| 1089 | |||
| 1090 | Input: deferred CustomActionData - BackupName | ||
| 1091 | ********************************************************************/ | ||
| 1092 | extern "C" UINT __stdcall RollbackIIS7ConfigTransaction(MSIHANDLE hInstall) | ||
| 1093 | { | ||
| 1094 | HRESULT hr = S_OK; | ||
| 1095 | UINT er = ERROR_SUCCESS; | ||
| 1096 | LPWSTR pwzData = NULL; | ||
| 1097 | WCHAR wzConfigSource[MAX_PATH]; | ||
| 1098 | WCHAR wzConfigCopy[MAX_PATH]; | ||
| 1099 | DWORD dwSize = 0; | ||
| 1100 | |||
| 1101 | BOOL fIsWow64Process = FALSE; | ||
| 1102 | BOOL fIsFSRedirectDisabled = FALSE; | ||
| 1103 | |||
| 1104 | hr = WcaInitialize(hInstall, "RollbackIIS7ConfigTransaction"); | ||
| 1105 | ExitOnFailure(hr, "failed to initialize"); | ||
| 1106 | |||
| 1107 | WcaInitializeWow64(); | ||
| 1108 | fIsWow64Process = WcaIsWow64Process(); | ||
| 1109 | if (fIsWow64Process) | ||
| 1110 | { | ||
| 1111 | hr = WcaDisableWow64FSRedirection(); | ||
| 1112 | if(FAILED(hr)) | ||
| 1113 | { | ||
| 1114 | //eat this error | ||
| 1115 | hr = S_OK; | ||
| 1116 | } | ||
| 1117 | else | ||
| 1118 | { | ||
| 1119 | fIsFSRedirectDisabled = TRUE; | ||
| 1120 | } | ||
| 1121 | } | ||
| 1122 | |||
| 1123 | hr = WcaGetProperty( L"CustomActionData", &pwzData); | ||
| 1124 | ExitOnFailure(hr, "failed to get CustomActionData"); | ||
| 1125 | |||
| 1126 | dwSize = ExpandEnvironmentStringsW(L"%windir%\\system32\\inetsrv\\config\\applicationHost.config", | ||
| 1127 | wzConfigSource, | ||
| 1128 | MAX_PATH | ||
| 1129 | ); | ||
| 1130 | if ( dwSize == 0 ) | ||
| 1131 | { | ||
| 1132 | ExitWithLastError(hr, "failed to get ExpandEnvironmentStrings"); | ||
| 1133 | } | ||
| 1134 | hr = ::StringCchCopyW(wzConfigCopy, MAX_PATH, wzConfigSource); | ||
| 1135 | ExitOnFailure(hr, "Commit IIS7 failed StringCchCopyW"); | ||
| 1136 | |||
| 1137 | //add ca action as extension | ||
| 1138 | |||
| 1139 | hr = ::StringCchCatW(wzConfigCopy, MAX_PATH, L"."); | ||
| 1140 | ExitOnFailure(hr, "Commit IIS7 failed StringCchCatW of ."); | ||
| 1141 | |||
| 1142 | hr = ::StringCchCatW(wzConfigCopy, MAX_PATH, pwzData); | ||
| 1143 | ExitOnFailure(hr, "Commit IIS7 failed StringCchCatW of extension"); | ||
| 1144 | |||
| 1145 | //copy is reverse of start transaction | ||
| 1146 | if (!::CopyFileW(wzConfigCopy, wzConfigSource, FALSE)) | ||
| 1147 | { | ||
| 1148 | hr = HRESULT_FROM_WIN32(GetLastError()); | ||
| 1149 | if (HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) == hr || | ||
| 1150 | HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr) | ||
| 1151 | { | ||
| 1152 | WcaLog(LOGMSG_STANDARD, "Failed to restore applicationHost, not found - continuing"); | ||
| 1153 | hr = S_OK; | ||
| 1154 | } | ||
| 1155 | else | ||
| 1156 | { | ||
| 1157 | ExitOnFailure(hr, "failed to restore config backup"); | ||
| 1158 | } | ||
| 1159 | } | ||
| 1160 | |||
| 1161 | if (!::DeleteFileW(wzConfigCopy)) | ||
| 1162 | { | ||
| 1163 | ExitWithLastError(hr, "failed to delete config backup"); | ||
| 1164 | } | ||
| 1165 | |||
| 1166 | hr = WcaProgressMessage(COST_IIS_TRANSACTIONS, FALSE); | ||
| 1167 | |||
| 1168 | LExit: | ||
| 1169 | ReleaseStr(pwzData); | ||
| 1170 | |||
| 1171 | // Make sure we revert FS Redirection if necessary before exiting | ||
| 1172 | if (fIsFSRedirectDisabled) | ||
| 1173 | { | ||
| 1174 | fIsFSRedirectDisabled = FALSE; | ||
| 1175 | WcaRevertWow64FSRedirection(); | ||
| 1176 | } | ||
| 1177 | WcaFinalizeWow64(); | ||
| 1178 | |||
| 1179 | if (FAILED(hr)) | ||
| 1180 | { | ||
| 1181 | er = ERROR_INSTALL_FAILURE; | ||
| 1182 | } | ||
| 1183 | return WcaFinalize(er); | ||
| 1184 | } | ||
diff --git a/src/ca/scaexecIIS7.cpp b/src/ca/scaexecIIS7.cpp new file mode 100644 index 00000000..108007a1 --- /dev/null +++ b/src/ca/scaexecIIS7.cpp | |||
| @@ -0,0 +1,4205 @@ | |||
| 1 | #pragma once | ||
| 2 | // 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. | ||
| 3 | |||
| 4 | |||
| 5 | #include "precomp.h" | ||
| 6 | |||
| 7 | //local CAData action functions | ||
| 8 | HRESULT IIS7Site( | ||
| 9 | __inout LPWSTR *ppwzCustomActionData, | ||
| 10 | __in IAppHostWritableAdminManager *pAdminMgr | ||
| 11 | ); | ||
| 12 | |||
| 13 | HRESULT IIS7Application( | ||
| 14 | __inout LPWSTR *ppwzCustomActionData, | ||
| 15 | __in IAppHostWritableAdminManager *pAdminMgr | ||
| 16 | ); | ||
| 17 | HRESULT IIS7VDir( | ||
| 18 | __inout LPWSTR *ppwzCustomActionData, | ||
| 19 | __in IAppHostWritableAdminManager *pAdminMgr | ||
| 20 | ); | ||
| 21 | HRESULT IIS7Binding( | ||
| 22 | __inout LPWSTR *ppwzCustomActionData, | ||
| 23 | __in IAppHostWritableAdminManager *pAdminMgr | ||
| 24 | ); | ||
| 25 | HRESULT IIS7AppPool( | ||
| 26 | __inout LPWSTR *ppwzCustomActionData, | ||
| 27 | __in IAppHostWritableAdminManager *pAdminMgr | ||
| 28 | ); | ||
| 29 | HRESULT IIS7AppExtension( | ||
| 30 | __inout LPWSTR *ppwzCustomActionData, | ||
| 31 | __in IAppHostWritableAdminManager *pAdminMgr | ||
| 32 | ); | ||
| 33 | HRESULT IIS7MimeMap( | ||
| 34 | __inout LPWSTR *ppwzCustomActionData, | ||
| 35 | __in IAppHostWritableAdminManager *pAdminMgr | ||
| 36 | ); | ||
| 37 | HRESULT IIS7DirProperties( | ||
| 38 | __inout LPWSTR *ppwzCustomActionData, | ||
| 39 | __in IAppHostWritableAdminManager *pAdminMgr | ||
| 40 | ); | ||
| 41 | HRESULT IIS7WebLog( | ||
| 42 | __inout LPWSTR *ppwzCustomActionData, | ||
| 43 | __in IAppHostWritableAdminManager *pAdminMgr | ||
| 44 | ); | ||
| 45 | HRESULT IIS7FilterGlobal( | ||
| 46 | __inout LPWSTR *ppwzCustomActionData, | ||
| 47 | __in IAppHostWritableAdminManager *pAdminMgr | ||
| 48 | ); | ||
| 49 | HRESULT IIS7FilterSite( | ||
| 50 | __inout LPWSTR *ppwzCustomActionData, | ||
| 51 | __in IAppHostWritableAdminManager *pAdminMgr | ||
| 52 | ); | ||
| 53 | HRESULT IIS7HttpHeader( | ||
| 54 | __inout LPWSTR *ppwzCustomActionData, | ||
| 55 | __in IAppHostWritableAdminManager *pAdminMgr | ||
| 56 | ); | ||
| 57 | HRESULT IIS7WebError( | ||
| 58 | __inout LPWSTR *ppwzCustomActionData, | ||
| 59 | __in IAppHostWritableAdminManager *pAdminMgr | ||
| 60 | ); | ||
| 61 | HRESULT IIS7WebSvcExt( | ||
| 62 | __inout LPWSTR *ppwzCustomActionData, | ||
| 63 | __in IAppHostWritableAdminManager *pAdminMgr | ||
| 64 | ); | ||
| 65 | HRESULT IIS7WebProperty( | ||
| 66 | __inout LPWSTR *ppwzCustomActionData, | ||
| 67 | __in IAppHostWritableAdminManager *pAdminMgr | ||
| 68 | ); | ||
| 69 | HRESULT IIS7WebDir( | ||
| 70 | __inout LPWSTR *ppwzCustomActionData, | ||
| 71 | __in IAppHostWritableAdminManager *pAdminMgr | ||
| 72 | ); | ||
| 73 | HRESULT IIS7AspProperty( | ||
| 74 | __inout LPWSTR *ppwzCustomActionData, | ||
| 75 | __in IAppHostWritableAdminManager *pAdminMgr | ||
| 76 | ); | ||
| 77 | HRESULT IIS7SslBinding( | ||
| 78 | __inout LPWSTR *ppwzCustomActionData, | ||
| 79 | __in IAppHostWritableAdminManager *pAdminMgr | ||
| 80 | ); | ||
| 81 | //local helper functions | ||
| 82 | |||
| 83 | static HRESULT GetNextAvailableSiteId( | ||
| 84 | IAppHostWritableAdminManager *pAdminMgr, | ||
| 85 | DWORD *plSiteId | ||
| 86 | ); | ||
| 87 | static HRESULT GetSiteElement( | ||
| 88 | IAppHostWritableAdminManager *pAdminMgr, | ||
| 89 | LPCWSTR swSiteName, | ||
| 90 | IAppHostElement **pSiteElement, | ||
| 91 | BOOL* fFound | ||
| 92 | ); | ||
| 93 | static HRESULT GetApplicationElement( | ||
| 94 | IAppHostElement *pSiteElement, | ||
| 95 | LPCWSTR swAppPath, | ||
| 96 | IAppHostElement **pAppElement, | ||
| 97 | BOOL* fFound | ||
| 98 | ); | ||
| 99 | static HRESULT GetApplicationElementForVDir( | ||
| 100 | IAppHostElement *pSiteElement, | ||
| 101 | LPCWSTR swVDirPath, | ||
| 102 | IAppHostElement **ppAppElement, | ||
| 103 | LPCWSTR *ppwzVDirSubPath, | ||
| 104 | BOOL* fFound | ||
| 105 | ); | ||
| 106 | |||
| 107 | static HRESULT CreateApplication( | ||
| 108 | IAppHostElement *pSiteElement, | ||
| 109 | LPCWSTR swAppPath, | ||
| 110 | IAppHostElement **pAppElement | ||
| 111 | ); | ||
| 112 | static HRESULT DeleteApplication( | ||
| 113 | IAppHostElement *pSiteElement, | ||
| 114 | LPCWSTR swAppPath | ||
| 115 | ); | ||
| 116 | |||
| 117 | static HRESULT SetAppPool( | ||
| 118 | IAppHostElement *pAppElementpAppElement, | ||
| 119 | LPCWSTR pwzAppPool | ||
| 120 | ); | ||
| 121 | static HRESULT CreateVdir( | ||
| 122 | IAppHostElement *pAppElement, | ||
| 123 | LPCWSTR pwzVDirPath, | ||
| 124 | LPCWSTR pwzVDirPhyDir | ||
| 125 | ); | ||
| 126 | static HRESULT DeleteVdir( | ||
| 127 | IAppHostElement *pAppElement, | ||
| 128 | LPCWSTR pwzVDirPath | ||
| 129 | ); | ||
| 130 | |||
| 131 | static HRESULT CreateBinding( | ||
| 132 | IAppHostElement *pSiteElem, | ||
| 133 | LPCWSTR pwzProtocol, | ||
| 134 | LPCWSTR pwzInfo | ||
| 135 | ); | ||
| 136 | static HRESULT DeleteBinding( | ||
| 137 | IAppHostElement *pSiteElem, | ||
| 138 | LPCWSTR pwzProtocol, | ||
| 139 | LPCWSTR pwzInfo | ||
| 140 | ); | ||
| 141 | |||
| 142 | static HRESULT CreateSslBinding( | ||
| 143 | IAppHostElement *pSiteElem, | ||
| 144 | LPCWSTR pwzStoreName, | ||
| 145 | LPCWSTR pwzEncodedCertificateHash | ||
| 146 | ); | ||
| 147 | static HRESULT DeleteSslBinding( | ||
| 148 | IAppHostElement *pSiteElem, | ||
| 149 | LPCWSTR pwzStoreName, | ||
| 150 | LPCWSTR pwzEncodedCertificateHash | ||
| 151 | ); | ||
| 152 | |||
| 153 | static HRESULT CreateSite( | ||
| 154 | IAppHostElementCollection *pAdminMgr, | ||
| 155 | LPCWSTR swSiteName, | ||
| 156 | IAppHostElement **pSiteElement | ||
| 157 | ); | ||
| 158 | |||
| 159 | static HRESULT DeleteAppPool( | ||
| 160 | IAppHostWritableAdminManager *pAdminMgr, | ||
| 161 | LPCWSTR swAppPoolName | ||
| 162 | ); | ||
| 163 | static HRESULT CreateAppPool( | ||
| 164 | __inout LPWSTR *ppwzCustomActionData, | ||
| 165 | IAppHostWritableAdminManager *pAdminMgr, | ||
| 166 | LPCWSTR swAppPoolName | ||
| 167 | ); | ||
| 168 | |||
| 169 | static HRESULT SetDirPropAuthentications( | ||
| 170 | IAppHostWritableAdminManager *pAdminMgr, | ||
| 171 | LPCWSTR wcConfigPath, | ||
| 172 | DWORD dwData | ||
| 173 | ); | ||
| 174 | static HRESULT SetDirPropAuthProvider( | ||
| 175 | IAppHostWritableAdminManager *pAdminMgr, | ||
| 176 | LPCWSTR wszConfigPath, | ||
| 177 | __in LPWSTR wszData | ||
| 178 | ); | ||
| 179 | static HRESULT SetDirPropDefDoc( | ||
| 180 | IAppHostWritableAdminManager *pAdminMgr, | ||
| 181 | LPCWSTR wszConfigPath, | ||
| 182 | __in LPWSTR wszData | ||
| 183 | ); | ||
| 184 | |||
| 185 | static HRESULT ClearLocationTag( | ||
| 186 | IAppHostWritableAdminManager *pAdminMgr, | ||
| 187 | LPCWSTR swLocationPath | ||
| 188 | ); | ||
| 189 | |||
| 190 | static HRESULT CreateWebLog( | ||
| 191 | IAppHostElement *pSiteElem, | ||
| 192 | LPCWSTR pwzFormat | ||
| 193 | ); | ||
| 194 | |||
| 195 | static HRESULT CreateGlobalFilter( | ||
| 196 | __inout LPWSTR *ppwzCustomActionData, | ||
| 197 | IAppHostElement *pSection | ||
| 198 | ); | ||
| 199 | static HRESULT DeleteGlobalFilter( | ||
| 200 | __inout LPWSTR *ppwzCustomActionData, | ||
| 201 | IAppHostElement *pSection | ||
| 202 | ); | ||
| 203 | |||
| 204 | static HRESULT CreateSiteFilter( | ||
| 205 | __inout LPWSTR *ppwzCustomActionData, | ||
| 206 | IAppHostWritableAdminManager *pAdminMgr | ||
| 207 | ); | ||
| 208 | static HRESULT DeleteSiteFilter( | ||
| 209 | __inout LPWSTR *ppwzCustomActionData, | ||
| 210 | IAppHostWritableAdminManager *pAdminMgr | ||
| 211 | ); | ||
| 212 | |||
| 213 | static HRESULT DeleteCollectionElement( | ||
| 214 | __in IAppHostElementCollection *pCollection, | ||
| 215 | __in LPCWSTR pwzElementName, | ||
| 216 | __in LPCWSTR pwzAttributeName, | ||
| 217 | __in LPCWSTR pwzAttributeValue | ||
| 218 | ); | ||
| 219 | |||
| 220 | struct SCA_WEB_ERROR_SERVER | ||
| 221 | { | ||
| 222 | int iErrorCode; | ||
| 223 | int iSubCode; | ||
| 224 | WCHAR wzFile[MAX_PATH]; | ||
| 225 | WCHAR wzLangPath[MAX_PATH]; | ||
| 226 | int iResponseMode; | ||
| 227 | SCA_WEB_ERROR_SERVER *psweNext; | ||
| 228 | }; | ||
| 229 | static HRESULT AddWebErrorToList( | ||
| 230 | SCA_WEB_ERROR_SERVER** ppsweList | ||
| 231 | ); | ||
| 232 | static void ScaWebErrorFreeList7( | ||
| 233 | SCA_WEB_ERROR_SERVER *psweList | ||
| 234 | ); | ||
| 235 | static HRESULT PopulateHttpErrors( | ||
| 236 | IAppHostElement *pSection, | ||
| 237 | SCA_WEB_ERROR_SERVER **psweList | ||
| 238 | ); | ||
| 239 | static HRESULT GetErrorFromList( | ||
| 240 | const SCA_WEB_ERROR_SERVER & we, | ||
| 241 | SCA_WEB_ERROR_SERVER **ppsweList, | ||
| 242 | SCA_WEB_ERROR_SERVER **pswe, | ||
| 243 | BOOL *fFound | ||
| 244 | ); | ||
| 245 | |||
| 246 | static void ConvSecToHMS( | ||
| 247 | int Sec, | ||
| 248 | __out_ecount(cchDest) LPWSTR wcTime, | ||
| 249 | size_t cchDest | ||
| 250 | ); | ||
| 251 | static void ConvSecToDHMS( | ||
| 252 | unsigned int Sec, | ||
| 253 | __out_ecount(cchDest) LPWSTR wcTime, | ||
| 254 | size_t cchDest | ||
| 255 | ); | ||
| 256 | |||
| 257 | //////////////////////////////////////////////////////////////////// | ||
| 258 | // ScopeBSTR: Local helper class to construct & free BSTR from LPWSTR | ||
| 259 | // | ||
| 260 | ///////////////////////////////////////////////////////////////////// | ||
| 261 | class ScopeBSTR | ||
| 262 | { | ||
| 263 | public: | ||
| 264 | BSTR m_str; | ||
| 265 | |||
| 266 | ScopeBSTR() | ||
| 267 | { | ||
| 268 | m_str = NULL; | ||
| 269 | } | ||
| 270 | |||
| 271 | ScopeBSTR( __in LPCWSTR pSrc) | ||
| 272 | { | ||
| 273 | if (pSrc == NULL) | ||
| 274 | { | ||
| 275 | m_str = NULL; | ||
| 276 | } | ||
| 277 | else | ||
| 278 | { | ||
| 279 | m_str = ::SysAllocString(pSrc); | ||
| 280 | |||
| 281 | } | ||
| 282 | } | ||
| 283 | |||
| 284 | ~ScopeBSTR() | ||
| 285 | { | ||
| 286 | ::SysFreeString(m_str); | ||
| 287 | } | ||
| 288 | |||
| 289 | operator BSTR() | ||
| 290 | { | ||
| 291 | return m_str; | ||
| 292 | } | ||
| 293 | }; | ||
| 294 | |||
| 295 | |||
| 296 | /******************************************************************** | ||
| 297 | IIS7ConfigChanges - Start of IIS7 config changes | ||
| 298 | |||
| 299 | *******************************************************************/ | ||
| 300 | HRESULT IIS7ConfigChanges(MSIHANDLE /*hInstall*/, __inout LPWSTR pwzData) | ||
| 301 | { | ||
| 302 | HRESULT hr = S_OK; | ||
| 303 | BOOL fInitializedCom = FALSE; | ||
| 304 | |||
| 305 | IAppHostWritableAdminManager *pAdminMgr = NULL; | ||
| 306 | |||
| 307 | LPWSTR pwz = NULL; | ||
| 308 | LPWSTR pwzLast = NULL; | ||
| 309 | LPWSTR pwzBackup = NULL; | ||
| 310 | DWORD cchData = lstrlenW(pwzData); | ||
| 311 | int iAction = -1; | ||
| 312 | |||
| 313 | int iRetryCount = 0; | ||
| 314 | |||
| 315 | hr = ::CoInitialize(NULL); | ||
| 316 | ExitOnFailure(hr, "Failed to initialize COM"); | ||
| 317 | fInitializedCom = TRUE; | ||
| 318 | |||
| 319 | pwz = pwzLast = pwzData; | ||
| 320 | |||
| 321 | hr = StrAllocString(&pwzBackup, pwz, 0); | ||
| 322 | ExitOnFailure(hr, "Failed to backup custom action data"); | ||
| 323 | |||
| 324 | while (S_OK == (hr = WcaReadIntegerFromCaData(&pwz, &iAction))) | ||
| 325 | { | ||
| 326 | if (NULL == pAdminMgr) | ||
| 327 | { | ||
| 328 | hr = ::CoCreateInstance( __uuidof(AppHostWritableAdminManager), | ||
| 329 | NULL, | ||
| 330 | CLSCTX_INPROC_SERVER, | ||
| 331 | __uuidof(IAppHostWritableAdminManager), | ||
| 332 | reinterpret_cast<void**> (&pAdminMgr)); | ||
| 333 | ExitOnFailure(hr , "Failed to open AppHostWritableAdminManager to configure IIS7"); | ||
| 334 | } | ||
| 335 | |||
| 336 | switch (iAction) | ||
| 337 | { | ||
| 338 | case IIS_SITE: | ||
| 339 | { | ||
| 340 | #pragma prefast(suppress:26010, "This is a prefast issue - pAdminMgr is correctly allocated") | ||
| 341 | hr = IIS7Site(&pwz, pAdminMgr); | ||
| 342 | ExitOnFailure(hr, "Failed to configure IIS site."); | ||
| 343 | break; | ||
| 344 | } | ||
| 345 | case IIS_APPLICATION: | ||
| 346 | { | ||
| 347 | #pragma prefast(suppress:26010, "This is a prefast issue - pAdminMgr is correctly allocated") | ||
| 348 | hr = IIS7Application(&pwz, pAdminMgr); | ||
| 349 | ExitOnFailure(hr, "Failed to configure IIS application."); | ||
| 350 | break; | ||
| 351 | } | ||
| 352 | case IIS_VDIR: | ||
| 353 | { | ||
| 354 | #pragma prefast(suppress:26010, "This is a prefast issue - pAdminMgr is correctly allocated") | ||
| 355 | hr = IIS7VDir(&pwz, pAdminMgr); | ||
| 356 | ExitOnFailure(hr, "Failed to configure IIS VDir."); | ||
| 357 | break; | ||
| 358 | } | ||
| 359 | case IIS_BINDING: | ||
| 360 | { | ||
| 361 | #pragma prefast(suppress:26010, "This is a prefast issue - pAdminMgr is correctly allocated") | ||
| 362 | hr = IIS7Binding(&pwz, pAdminMgr); | ||
| 363 | ExitOnFailure(hr, "Failed to configure IIS site binding."); | ||
| 364 | break; | ||
| 365 | } | ||
| 366 | case IIS_APPPOOL: | ||
| 367 | { | ||
| 368 | #pragma prefast(suppress:26010, "This is a prefast issue - pAdminMgr is correctly allocated") | ||
| 369 | hr = IIS7AppPool(&pwz, pAdminMgr); | ||
| 370 | ExitOnFailure(hr, "Failed to configure IIS appPool."); | ||
| 371 | break; | ||
| 372 | } | ||
| 373 | case IIS_APPEXT_BEGIN: | ||
| 374 | { | ||
| 375 | #pragma prefast(suppress:26010, "This is a prefast issue - pAdminMgr is correctly allocated") | ||
| 376 | hr = IIS7AppExtension(&pwz, pAdminMgr); | ||
| 377 | ExitOnFailure(hr, "Failed to configure IIS AppExtension."); | ||
| 378 | break; | ||
| 379 | } | ||
| 380 | case IIS_MIMEMAP_BEGIN: | ||
| 381 | { | ||
| 382 | #pragma prefast(suppress:26010, "This is a prefast issue - pAdminMgr is correctly allocated") | ||
| 383 | hr = IIS7MimeMap(&pwz, pAdminMgr); | ||
| 384 | ExitOnFailure(hr, "Failed to configure IIS MimeMap."); | ||
| 385 | break; | ||
| 386 | } | ||
| 387 | case IIS_DIRPROP_BEGIN: | ||
| 388 | { | ||
| 389 | #pragma prefast(suppress:26010, "This is a prefast issue - pAdminMgr is correctly allocated") | ||
| 390 | hr = IIS7DirProperties(&pwz, pAdminMgr); | ||
| 391 | ExitOnFailure(hr, "Failed to configure IIS DirProperties."); | ||
| 392 | break; | ||
| 393 | } | ||
| 394 | case IIS_WEBLOG: | ||
| 395 | { | ||
| 396 | #pragma prefast(suppress:26010, "This is a prefast issue - pAdminMgr is correctly allocated") | ||
| 397 | hr = IIS7WebLog(&pwz, pAdminMgr); | ||
| 398 | ExitOnFailure(hr, "Failed to configure IIS WebLog."); | ||
| 399 | break; | ||
| 400 | } | ||
| 401 | case IIS_FILTER_GLOBAL_BEGIN: | ||
| 402 | { | ||
| 403 | #pragma prefast(suppress:26010, "This is a prefast issue - pAdminMgr is correctly allocated") | ||
| 404 | hr = IIS7FilterGlobal(&pwz, pAdminMgr); | ||
| 405 | ExitOnFailure(hr, "Failed to configure IIS filter global."); | ||
| 406 | break; | ||
| 407 | } | ||
| 408 | case IIS_FILTER_BEGIN: | ||
| 409 | { | ||
| 410 | #pragma prefast(suppress:26010, "This is a prefast issue - pAdminMgr is correctly allocated") | ||
| 411 | hr = IIS7FilterSite(&pwz, pAdminMgr); | ||
| 412 | ExitOnFailure(hr, "Failed to configure IIS Filter."); | ||
| 413 | break; | ||
| 414 | } | ||
| 415 | case IIS_HTTP_HEADER_BEGIN: | ||
| 416 | { | ||
| 417 | #pragma prefast(suppress:26010, "This is a prefast issue - pAdminMgr is correctly allocated") | ||
| 418 | hr = IIS7HttpHeader(&pwz, pAdminMgr); | ||
| 419 | ExitOnFailure(hr, "Failed to configure IIS http Header."); | ||
| 420 | break; | ||
| 421 | } | ||
| 422 | case IIS_WEBERROR_BEGIN: | ||
| 423 | { | ||
| 424 | #pragma prefast(suppress:26010, "This is a prefast issue - pAdminMgr is correctly allocated") | ||
| 425 | hr = IIS7WebError(&pwz, pAdminMgr); | ||
| 426 | ExitOnFailure(hr, "Failed to configure IIS http Errors."); | ||
| 427 | break; | ||
| 428 | } | ||
| 429 | case IIS_WEB_SVC_EXT: | ||
| 430 | { | ||
| 431 | #pragma prefast(suppress:26010, "This is a prefast issue - pAdminMgr is correctly allocated") | ||
| 432 | hr = IIS7WebSvcExt(&pwz, pAdminMgr); | ||
| 433 | ExitOnFailure(hr, "Failed to configure IIS web svc ext."); | ||
| 434 | break; | ||
| 435 | } | ||
| 436 | case IIS_PROPERTY: | ||
| 437 | { | ||
| 438 | #pragma prefast(suppress:26010, "This is a prefast issue - pAdminMgr is correctly allocated") | ||
| 439 | hr = IIS7WebProperty(&pwz, pAdminMgr); | ||
| 440 | ExitOnFailure(hr, "Failed to configure IIS web property."); | ||
| 441 | break; | ||
| 442 | } | ||
| 443 | case IIS_WEBDIR: | ||
| 444 | { | ||
| 445 | #pragma prefast(suppress:26010, "This is a prefast issue - pAdminMgr is correctly allocated") | ||
| 446 | hr = IIS7WebDir(&pwz, pAdminMgr); | ||
| 447 | ExitOnFailure(hr, "Failed to configure IIS web directory."); | ||
| 448 | break; | ||
| 449 | } | ||
| 450 | case IIS_ASP_BEGIN: | ||
| 451 | { | ||
| 452 | #pragma prefast(suppress:26010, "This is a prefast issue - pAdminMgr is correctly allocated") | ||
| 453 | hr = IIS7AspProperty(&pwz, pAdminMgr); | ||
| 454 | ExitOnFailure(hr, "Failed to configure IIS Asp property."); | ||
| 455 | break; | ||
| 456 | } | ||
| 457 | case IIS_SSL_BINDING: | ||
| 458 | #pragma prefast(suppress:26010, "This is a prefast issue - pAdminMgr is correctly allocated") | ||
| 459 | hr = IIS7SslBinding(&pwz, pAdminMgr); | ||
| 460 | ExitOnFailure(hr, "Failed to configure IIS SSL binding."); | ||
| 461 | break; | ||
| 462 | |||
| 463 | default: | ||
| 464 | ExitOnFailure(hr = E_UNEXPECTED, "IIS7ConfigChanges: Unexpected IIS Config action specified: %d", iAction); | ||
| 465 | break; | ||
| 466 | } | ||
| 467 | if (S_OK == hr) | ||
| 468 | { | ||
| 469 | // commit config changes now to close out IIS Admin changes, | ||
| 470 | // the Rollback or Commit defered CAs will determine final commit status. | ||
| 471 | hr = pAdminMgr->CommitChanges(); | ||
| 472 | |||
| 473 | // Our transaction may have been interrupted. | ||
| 474 | if (hr == HRESULT_FROM_WIN32(ERROR_SHARING_VIOLATION) || hr == HRESULT_FROM_WIN32(ERROR_TRANSACTIONAL_CONFLICT)) | ||
| 475 | { | ||
| 476 | WcaLog(LOGMSG_VERBOSE, "Sharing violation or transactional conflict during attempt to save changes to applicationHost.config"); | ||
| 477 | if (++iRetryCount > 30) | ||
| 478 | { | ||
| 479 | if (IDRETRY == WcaErrorMessage(msierrIISFailedCommitInUse, hr, INSTALLMESSAGE_ERROR | MB_RETRYCANCEL, 0)) | ||
| 480 | { | ||
| 481 | iRetryCount = 0; | ||
| 482 | } | ||
| 483 | else | ||
| 484 | { | ||
| 485 | ExitOnFailure(hr, "Failed to Commit IIS Config Changes, in silent mode or user has chosen to cancel"); | ||
| 486 | } | ||
| 487 | } | ||
| 488 | |||
| 489 | // Throw away the changes since IIS has no way to remove uncommited changes from an AdminManager. | ||
| 490 | ReleaseNullObject(pAdminMgr); | ||
| 491 | |||
| 492 | // Restore our CA data backup | ||
| 493 | pwz = pwzLast; | ||
| 494 | hr = ::StringCchCopyW(pwz, cchData - (pwz - pwzData) + 1, pwzBackup); | ||
| 495 | ExitOnFailure(hr , "Failed to restore custom action data backup"); | ||
| 496 | |||
| 497 | } | ||
| 498 | else if (FAILED(hr)) | ||
| 499 | { | ||
| 500 | ExitOnFailure(hr , "Failed to Commit IIS Config Changes"); | ||
| 501 | } | ||
| 502 | else | ||
| 503 | { | ||
| 504 | // store a backup of CA data @ the last place that we successfully commited changes unless we are done. | ||
| 505 | if(NULL != pwz) | ||
| 506 | { | ||
| 507 | pwzLast = pwz; | ||
| 508 | hr = StrAllocString(&pwzBackup, pwz, 0); | ||
| 509 | ExitOnFailure(hr, "Failed to backup custom action data"); | ||
| 510 | } | ||
| 511 | } | ||
| 512 | } | ||
| 513 | } | ||
| 514 | if (E_NOMOREITEMS == hr) // If there are no more items, all is well | ||
| 515 | { | ||
| 516 | hr = S_OK; | ||
| 517 | } | ||
| 518 | LExit: | ||
| 519 | ReleaseObject(pAdminMgr); | ||
| 520 | ReleaseStr(pwzBackup); | ||
| 521 | |||
| 522 | if (fInitializedCom) | ||
| 523 | { | ||
| 524 | ::CoUninitialize(); | ||
| 525 | } | ||
| 526 | |||
| 527 | return hr; | ||
| 528 | } | ||
| 529 | //------------------------------------------------------------------------------------------------- | ||
| 530 | // IIS7AspProperty | ||
| 531 | // Called by WriteIIS7ConfigChanges | ||
| 532 | // Processes asp properties for WebApplication | ||
| 533 | // | ||
| 534 | //------------------------------------------------------------------------------------------------- | ||
| 535 | |||
| 536 | HRESULT IIS7AspProperty( | ||
| 537 | __inout LPWSTR *ppwzCustomActionData, | ||
| 538 | __in IAppHostWritableAdminManager *pAdminMgr | ||
| 539 | ) | ||
| 540 | { | ||
| 541 | HRESULT hr = S_OK; | ||
| 542 | |||
| 543 | int iAction = -1; | ||
| 544 | int iData = 0; | ||
| 545 | |||
| 546 | LPWSTR pwzData = NULL; | ||
| 547 | LPWSTR pwzSiteName = NULL; | ||
| 548 | LPWSTR pwzPathName = NULL; | ||
| 549 | LPWSTR pwzLocationPath = NULL; | ||
| 550 | WCHAR wcTime[60]; | ||
| 551 | |||
| 552 | IAppHostElement *pSection = NULL; | ||
| 553 | IAppHostElement *pElement = NULL; | ||
| 554 | |||
| 555 | //read web site key | ||
| 556 | hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzSiteName); | ||
| 557 | ExitOnFailure(hr, "Failed read webDir webkey"); | ||
| 558 | |||
| 559 | //read path key | ||
| 560 | hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzPathName); | ||
| 561 | ExitOnFailure(hr, "Failed read webDir path"); | ||
| 562 | |||
| 563 | //Construct Location path | ||
| 564 | hr = StrAllocFormatted(&pwzLocationPath, L"%s/%s", IIS_CONFIG_APPHOST_ROOT, pwzSiteName); | ||
| 565 | ExitOnFailure(hr, "failed to format webDir location"); | ||
| 566 | // | ||
| 567 | //Do not append trailing '/' for default vDir | ||
| 568 | // | ||
| 569 | if (CSTR_EQUAL != ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, pwzPathName, -1, L"/", -1)) | ||
| 570 | { | ||
| 571 | hr = StrAllocConcat(&pwzLocationPath, L"/", 0); | ||
| 572 | ExitOnFailure(hr, "failed to copy location WebDir '/'"); | ||
| 573 | hr = StrAllocConcat(&pwzLocationPath, pwzPathName, 0); | ||
| 574 | ExitOnFailure(hr, "failed to copy location WebDir path"); | ||
| 575 | } | ||
| 576 | |||
| 577 | //get asp section at config path location tag | ||
| 578 | hr = pAdminMgr->GetAdminSection( ScopeBSTR(IIS_CONFIG_ASP_SECTION), pwzLocationPath, &pSection); | ||
| 579 | ExitOnFailure(hr, "Failed get httpErrors section"); | ||
| 580 | |||
| 581 | // Get action | ||
| 582 | hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iAction); | ||
| 583 | ExitOnFailure(hr, "Failed to read property action"); | ||
| 584 | |||
| 585 | while (IIS_ASP_END != iAction) | ||
| 586 | { | ||
| 587 | switch (iAction) | ||
| 588 | { | ||
| 589 | case IIS_ASP_SESSIONSTATE: | ||
| 590 | { | ||
| 591 | //system.webServer/asp /session | allowSessionState | ||
| 592 | hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iData); | ||
| 593 | ExitOnFailure(hr, "Failed to read asp session state"); | ||
| 594 | hr = pSection->GetElementByName(ScopeBSTR(IIS_CONFIG_SESSION), &pElement); | ||
| 595 | ExitOnFailure(hr, "Failed to get asp session element"); | ||
| 596 | hr = Iis7PutPropertyBool( pElement, IIS_CONFIG_ALLOWSTATE, iData); | ||
| 597 | ExitOnFailure(hr, "Failed to put asp session value"); | ||
| 598 | ReleaseNullObject(pElement); | ||
| 599 | break; | ||
| 600 | } | ||
| 601 | case IIS_ASP_SESSIONTIMEOUT: | ||
| 602 | { | ||
| 603 | //system.webServer/asp /session | timeout | ||
| 604 | hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iData); | ||
| 605 | ExitOnFailure(hr, "Failed to read asp session timeout"); | ||
| 606 | hr = pSection->GetElementByName(ScopeBSTR(IIS_CONFIG_SESSION), &pElement); | ||
| 607 | ExitOnFailure(hr, "Failed to get asp session timeout"); | ||
| 608 | *wcTime = '\0'; | ||
| 609 | ConvSecToHMS(iData * 60, wcTime, countof( wcTime)); | ||
| 610 | hr = Iis7PutPropertyString( pElement, IIS_CONFIG_TIMEOUT, wcTime); | ||
| 611 | ExitOnFailure(hr, "Failed to put asp timeout value"); | ||
| 612 | ReleaseNullObject(pElement); | ||
| 613 | break; | ||
| 614 | } | ||
| 615 | case IIS_ASP_BUFFER: | ||
| 616 | { | ||
| 617 | //system.webServer/asp | bufferingOn | ||
| 618 | hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iData); | ||
| 619 | ExitOnFailure(hr, "Failed to read asp bufferingOn"); | ||
| 620 | hr = Iis7PutPropertyBool( pSection, IIS_CONFIG_BUFFERING, iData); | ||
| 621 | ExitOnFailure(hr, "Failed to put asp bufferingOn value"); | ||
| 622 | break; | ||
| 623 | } | ||
| 624 | case IIS_ASP_PARENTPATHS: | ||
| 625 | { | ||
| 626 | //system.webServer/asp | enableParentPaths | ||
| 627 | hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iData); | ||
| 628 | ExitOnFailure(hr, "Failed to read asp ParentPaths"); | ||
| 629 | hr = Iis7PutPropertyBool( pSection, IIS_CONFIG_PARENTPATHS, iData); | ||
| 630 | ExitOnFailure(hr, "Failed to put asp ParentPaths value"); | ||
| 631 | break; | ||
| 632 | } | ||
| 633 | case IIS_ASP_SCRIPTLANG: | ||
| 634 | { | ||
| 635 | //system.webServer/asp | scriptLanguage | ||
| 636 | hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzData); | ||
| 637 | ExitOnFailure(hr, "Failed to read asp scriptLanguage"); | ||
| 638 | hr = Iis7PutPropertyString( pSection, IIS_CONFIG_SCRIPTLANG, pwzData); | ||
| 639 | ExitOnFailure(hr, "Failed to put asp scriptLanguage value"); | ||
| 640 | break; | ||
| 641 | } | ||
| 642 | case IIS_ASP_SCRIPTTIMEOUT: | ||
| 643 | { | ||
| 644 | //system.webServer/asp /limits | scriptTimeout | ||
| 645 | hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iData); | ||
| 646 | ExitOnFailure(hr, "Failed to read asp scriptTimeout"); | ||
| 647 | hr = pSection->GetElementByName(ScopeBSTR(IIS_CONFIG_LIMITS), &pElement); | ||
| 648 | ExitOnFailure(hr, "Failed to get asp session element"); | ||
| 649 | *wcTime = '\0'; | ||
| 650 | ConvSecToHMS(iData, wcTime, countof( wcTime)); | ||
| 651 | hr = Iis7PutPropertyString( pElement, IIS_CONFIG_SCRIPTTIMEOUT, wcTime); | ||
| 652 | ExitOnFailure(hr, "Failed to put asp scriptTimeout value"); | ||
| 653 | ReleaseNullObject(pElement); | ||
| 654 | break; | ||
| 655 | |||
| 656 | } | ||
| 657 | case IIS_ASP_SCRIPTSERVERDEBUG: | ||
| 658 | { | ||
| 659 | //system.webServer/asp | appAllowDebugging | ||
| 660 | hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iData); | ||
| 661 | ExitOnFailure(hr, "Failed to read asp appAllowDebugging"); | ||
| 662 | hr = Iis7PutPropertyBool( pSection, IIS_CONFIG_ALLOWDEBUG, iData); | ||
| 663 | ExitOnFailure(hr, "Failed to put asp appAllowDebugging value"); | ||
| 664 | break; | ||
| 665 | } | ||
| 666 | case IIS_ASP_SCRIPTCLIENTDEBUG: | ||
| 667 | { | ||
| 668 | //system.webServer/asp | appAllowClientDebug | ||
| 669 | hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iData); | ||
| 670 | ExitOnFailure(hr, "Failed to read asp appAllowClientDebug"); | ||
| 671 | hr = Iis7PutPropertyBool( pSection, IIS_CONFIG_ALLOWCLIENTDEBUG, iData); | ||
| 672 | ExitOnFailure(hr, "Failed to put asp appAllowClientDebug value"); | ||
| 673 | break; | ||
| 674 | } | ||
| 675 | default: | ||
| 676 | { | ||
| 677 | ExitOnFailure(hr = E_UNEXPECTED, "Unexpected IIS Config action specified for asp properties"); | ||
| 678 | break; | ||
| 679 | } | ||
| 680 | } | ||
| 681 | // Get next action | ||
| 682 | hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iAction); | ||
| 683 | ExitOnFailure(hr, "Failed to read asp prop action"); | ||
| 684 | } | ||
| 685 | |||
| 686 | LExit: | ||
| 687 | ReleaseStr(pwzData); | ||
| 688 | ReleaseStr(pwzSiteName); | ||
| 689 | ReleaseStr(pwzPathName); | ||
| 690 | ReleaseStr(pwzLocationPath); | ||
| 691 | ReleaseObject(pSection); | ||
| 692 | ReleaseObject(pElement); | ||
| 693 | |||
| 694 | return hr; | ||
| 695 | } | ||
| 696 | |||
| 697 | //------------------------------------------------------------------------------------------------- | ||
| 698 | // IIS7WebDir | ||
| 699 | // Called by WriteIIS7ConfigChanges | ||
| 700 | // Processes WebDir | ||
| 701 | // | ||
| 702 | //------------------------------------------------------------------------------------------------- | ||
| 703 | HRESULT IIS7WebDir( | ||
| 704 | __inout LPWSTR *ppwzCustomActionData, | ||
| 705 | __in IAppHostWritableAdminManager *pAdminMgr | ||
| 706 | ) | ||
| 707 | { | ||
| 708 | HRESULT hr = S_OK; | ||
| 709 | |||
| 710 | int iAction = -1; | ||
| 711 | |||
| 712 | LPWSTR pwzSiteName = NULL; | ||
| 713 | LPWSTR pwzPathName = NULL; | ||
| 714 | LPWSTR pwzLocationPath = NULL; | ||
| 715 | |||
| 716 | // Get action | ||
| 717 | hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iAction); | ||
| 718 | ExitOnFailure(hr, "Failed to read property action"); | ||
| 719 | |||
| 720 | //read web site key | ||
| 721 | hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzSiteName); | ||
| 722 | ExitOnFailure(hr, "Failed read webDir webkey"); | ||
| 723 | |||
| 724 | //read path key | ||
| 725 | hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzPathName); | ||
| 726 | ExitOnFailure(hr, "Failed read webDir path"); | ||
| 727 | |||
| 728 | switch (iAction) | ||
| 729 | { | ||
| 730 | case IIS_CREATE: | ||
| 731 | { | ||
| 732 | //no action needed for create since WebDir has a | ||
| 733 | //WebDirProperties element that will create and populate | ||
| 734 | //location tag | ||
| 735 | break; | ||
| 736 | } | ||
| 737 | case IIS_DELETE: | ||
| 738 | { | ||
| 739 | //Construct Location path | ||
| 740 | hr = StrAllocString(&pwzLocationPath, pwzSiteName, 0); | ||
| 741 | ExitOnFailure(hr, "failed to copy location WebDir web name"); | ||
| 742 | // | ||
| 743 | //Do not append trailing '/' for default vDir | ||
| 744 | // | ||
| 745 | if (CSTR_EQUAL != ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, pwzPathName, -1, L"/", -1)) | ||
| 746 | { | ||
| 747 | hr = StrAllocConcat(&pwzLocationPath, L"/", 0); | ||
| 748 | ExitOnFailure(hr, "failed to copy location WebDir '/'"); | ||
| 749 | hr = StrAllocConcat(&pwzLocationPath, pwzPathName, 0); | ||
| 750 | ExitOnFailure(hr, "failed to copy location WebDir path"); | ||
| 751 | } | ||
| 752 | // and delete location tag for this application | ||
| 753 | hr = ClearLocationTag(pAdminMgr, pwzLocationPath); | ||
| 754 | ExitOnFailure(hr, "failed to clear location tag for %ls", pwzLocationPath) | ||
| 755 | break; | ||
| 756 | } | ||
| 757 | default: | ||
| 758 | { | ||
| 759 | ExitOnFailure(hr = E_UNEXPECTED, "Unexpected IIS Config action specified for WebDir"); | ||
| 760 | break; | ||
| 761 | } | ||
| 762 | } | ||
| 763 | LExit: | ||
| 764 | ReleaseStr(pwzSiteName); | ||
| 765 | ReleaseStr(pwzPathName); | ||
| 766 | ReleaseStr(pwzLocationPath); | ||
| 767 | |||
| 768 | return hr; | ||
| 769 | } | ||
| 770 | |||
| 771 | //------------------------------------------------------------------------------------------------- | ||
| 772 | // IIS7WebProperty | ||
| 773 | // Called by WriteIIS7ConfigChanges | ||
| 774 | // Processes isapiCgiRestriction | ||
| 775 | // | ||
| 776 | //------------------------------------------------------------------------------------------------- | ||
| 777 | HRESULT IIS7WebProperty( | ||
| 778 | __inout LPWSTR *ppwzCustomActionData, | ||
| 779 | __in IAppHostWritableAdminManager *pAdminMgr | ||
| 780 | ) | ||
| 781 | { | ||
| 782 | HRESULT hr = S_OK; | ||
| 783 | |||
| 784 | int iAction = -1; | ||
| 785 | int iData = 0; | ||
| 786 | |||
| 787 | IAppHostElement *pSection = NULL; | ||
| 788 | |||
| 789 | // Get action | ||
| 790 | hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iAction); | ||
| 791 | ExitOnFailure(hr, "Failed to read property action"); | ||
| 792 | |||
| 793 | switch (iAction) | ||
| 794 | { | ||
| 795 | case IIS_PROPERTY_MAXBAND: | ||
| 796 | { | ||
| 797 | hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iData); | ||
| 798 | ExitOnFailure(hr, "Failed to read property max band"); | ||
| 799 | //set value at system.applicationHost/webLimits | maxGlobalBandwidth | ||
| 800 | //Get IIS config section | ||
| 801 | hr = pAdminMgr->GetAdminSection(ScopeBSTR(IIS_CONFIG_WEBLIMITS_SECTION), ScopeBSTR(IIS_CONFIG_APPHOST_ROOT), &pSection); | ||
| 802 | ExitOnFailure(hr, "Failed get isapiCgiRestriction section"); | ||
| 803 | if (!pSection) | ||
| 804 | { | ||
| 805 | hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); | ||
| 806 | ExitOnFailure(hr, "Failed get isapiCgiRestriction section object"); | ||
| 807 | } | ||
| 808 | hr = Iis7PutPropertyInteger(pSection, IIS_CONFIG_WEBLIMITS_MAXBAND, iData); | ||
| 809 | |||
| 810 | break; | ||
| 811 | } | ||
| 812 | case IIS_PROPERTY_LOGUTF8: | ||
| 813 | { | ||
| 814 | hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iData); | ||
| 815 | ExitOnFailure(hr, "Failed to read property log"); | ||
| 816 | //set value at system.applicationHost/log | logInUTF8 | ||
| 817 | //Get IIS config section | ||
| 818 | hr = pAdminMgr->GetAdminSection(ScopeBSTR(IIS_CONFIG_LOG_SECTION), ScopeBSTR(IIS_CONFIG_APPHOST_ROOT), &pSection); | ||
| 819 | ExitOnFailure(hr, "Failed get isapiCgiRestriction section"); | ||
| 820 | if (!pSection) | ||
| 821 | { | ||
| 822 | hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); | ||
| 823 | ExitOnFailure(hr, "Failed get isapiCgiRestriction section object"); | ||
| 824 | } | ||
| 825 | hr = Iis7PutPropertyBool(pSection, IIS_CONFIG_LOG_UTF8, iData); | ||
| 826 | |||
| 827 | break; | ||
| 828 | } | ||
| 829 | default: | ||
| 830 | { | ||
| 831 | ExitOnFailure(hr = E_UNEXPECTED, "Unexpected IIS Config action specified for Web Property"); | ||
| 832 | break; | ||
| 833 | } | ||
| 834 | } | ||
| 835 | |||
| 836 | LExit: | ||
| 837 | ReleaseObject(pSection); | ||
| 838 | |||
| 839 | return hr; | ||
| 840 | } | ||
| 841 | |||
| 842 | //------------------------------------------------------------------------------------------------- | ||
| 843 | // IIS7WebSvcExt | ||
| 844 | // Called by WriteIIS7ConfigChanges | ||
| 845 | // Processes isapiCgiRestriction | ||
| 846 | // | ||
| 847 | //------------------------------------------------------------------------------------------------- | ||
| 848 | HRESULT IIS7WebSvcExt( | ||
| 849 | __inout LPWSTR *ppwzCustomActionData, | ||
| 850 | __in IAppHostWritableAdminManager *pAdminMgr | ||
| 851 | ) | ||
| 852 | { | ||
| 853 | HRESULT hr = S_OK; | ||
| 854 | |||
| 855 | int iAction = -1; | ||
| 856 | int iData = 0; | ||
| 857 | BOOL fFound = FALSE; | ||
| 858 | LPWSTR pwzData = NULL; | ||
| 859 | LPWSTR pwzPath = NULL; | ||
| 860 | |||
| 861 | IAppHostElement *pSection = NULL; | ||
| 862 | IAppHostElement *pElement = NULL; | ||
| 863 | IAppHostElementCollection *pCollection = NULL; | ||
| 864 | |||
| 865 | // Get action | ||
| 866 | hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iAction); | ||
| 867 | ExitOnFailure(hr, "Failed to read WebSvcExt action"); | ||
| 868 | |||
| 869 | //get path | ||
| 870 | hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzPath); | ||
| 871 | ExitOnFailure(hr, "Failed to read WebSvcExt key"); | ||
| 872 | |||
| 873 | //Get IIS config section | ||
| 874 | hr = pAdminMgr->GetAdminSection(ScopeBSTR(IIS_CONFIG_RESTRICTION_SECTION), ScopeBSTR(IIS_CONFIG_APPHOST_ROOT), &pSection); | ||
| 875 | ExitOnFailure(hr, "Failed get isapiCgiRestriction section"); | ||
| 876 | if (!pSection) | ||
| 877 | { | ||
| 878 | hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); | ||
| 879 | ExitOnFailure(hr, "Failed get isapiCgiRestriction section object"); | ||
| 880 | } | ||
| 881 | //get collection | ||
| 882 | hr = pSection->get_Collection(&pCollection); | ||
| 883 | ExitOnFailure(hr, "Failed get isapiCgiRestriction collection"); | ||
| 884 | |||
| 885 | //find element | ||
| 886 | hr = Iis7FindAppHostElementPath(pCollection, IIS_CONFIG_ADD, IIS_CONFIG_PATH, pwzPath, &pElement, NULL); | ||
| 887 | ExitOnFailure(hr, "Failed get isapiCgiRestriction element"); | ||
| 888 | fFound = (NULL != pElement); | ||
| 889 | |||
| 890 | switch (iAction) | ||
| 891 | { | ||
| 892 | case IIS_CREATE: | ||
| 893 | { | ||
| 894 | if (!fFound) | ||
| 895 | { | ||
| 896 | //create a restriction element | ||
| 897 | hr = pCollection->CreateNewElement(ScopeBSTR(IIS_CONFIG_ADD), &pElement); | ||
| 898 | ExitOnFailure(hr, "Failed create isapiCgiRestriction element"); | ||
| 899 | //put path | ||
| 900 | hr = Iis7PutPropertyString(pElement, IIS_CONFIG_PATH, pwzPath); | ||
| 901 | ExitOnFailure(hr, "Failed set isapiCgiRestriction path property"); | ||
| 902 | } | ||
| 903 | //update common properties | ||
| 904 | |||
| 905 | //update allowed | ||
| 906 | hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iData); | ||
| 907 | ExitOnFailure(hr, "Failed to read WebSvcExt allowed"); | ||
| 908 | hr = Iis7PutPropertyBool(pElement, IIS_CONFIG_ALLOWED, iData); | ||
| 909 | ExitOnFailure(hr, "Failed set isapiCgiRestriction allowed property"); | ||
| 910 | |||
| 911 | //update groupId | ||
| 912 | hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzData); | ||
| 913 | ExitOnFailure(hr, "Failed to read WebSvcExt group ID"); | ||
| 914 | if (*pwzData) | ||
| 915 | { | ||
| 916 | hr = Iis7PutPropertyString(pElement, IIS_CONFIG_GROUPID, pwzData); | ||
| 917 | ExitOnFailure(hr, "Failed set isapiCgiRestriction groupId property"); | ||
| 918 | } | ||
| 919 | //update description | ||
| 920 | hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzData); | ||
| 921 | ExitOnFailure(hr, "Failed to read WebSvcExt description"); | ||
| 922 | if (*pwzData) | ||
| 923 | { | ||
| 924 | hr = Iis7PutPropertyString(pElement, IIS_CONFIG_DESC, pwzData); | ||
| 925 | ExitOnFailure(hr, "Failed set isapiCgiRestriction description property"); | ||
| 926 | } | ||
| 927 | // add element if new | ||
| 928 | if (!fFound) | ||
| 929 | { | ||
| 930 | hr = pCollection->AddElement(pElement); | ||
| 931 | ExitOnFailure(hr, "Failed add isapiCgiRestriction element"); | ||
| 932 | } | ||
| 933 | |||
| 934 | break; | ||
| 935 | } | ||
| 936 | case IIS_DELETE: | ||
| 937 | { | ||
| 938 | hr = DeleteCollectionElement(pCollection, IIS_CONFIG_ADD, IIS_CONFIG_PATH, pwzPath); | ||
| 939 | ExitOnFailure(hr, "Failed delete isapiCgiRestriction element"); | ||
| 940 | break; | ||
| 941 | } | ||
| 942 | default: | ||
| 943 | { | ||
| 944 | ExitOnFailure(hr = E_UNEXPECTED, "Unexpected IIS Config action specified for WebSvcExt"); | ||
| 945 | break; | ||
| 946 | } | ||
| 947 | } | ||
| 948 | |||
| 949 | LExit: | ||
| 950 | ReleaseStr(pwzPath); | ||
| 951 | ReleaseStr(pwzData); | ||
| 952 | ReleaseObject(pSection); | ||
| 953 | ReleaseObject(pElement); | ||
| 954 | ReleaseObject(pCollection); | ||
| 955 | |||
| 956 | return hr; | ||
| 957 | |||
| 958 | } | ||
| 959 | |||
| 960 | //------------------------------------------------------------------------------------------------- | ||
| 961 | // IIS7WebError | ||
| 962 | // Called by WriteIIS7ConfigChanges | ||
| 963 | // Processes http header CA Data | ||
| 964 | // | ||
| 965 | //------------------------------------------------------------------------------------------------- | ||
| 966 | |||
| 967 | HRESULT IIS7WebError( | ||
| 968 | __inout LPWSTR *ppwzCustomActionData, | ||
| 969 | __in IAppHostWritableAdminManager *pAdminMgr | ||
| 970 | ) | ||
| 971 | { | ||
| 972 | HRESULT hr = S_OK; | ||
| 973 | LPWSTR pwzConfigPath = NULL; | ||
| 974 | LPWSTR pwzSiteName = NULL; | ||
| 975 | LPWSTR pwzAppName = NULL; | ||
| 976 | |||
| 977 | IAppHostElement *pElement = NULL; | ||
| 978 | IAppHostElement *pSection = NULL; | ||
| 979 | IAppHostElementCollection *pCollection = NULL; | ||
| 980 | |||
| 981 | SCA_WEB_ERROR_SERVER *psweList = NULL; | ||
| 982 | SCA_WEB_ERROR_SERVER* pswe = NULL; | ||
| 983 | SCA_WEB_ERROR_SERVER we; | ||
| 984 | BOOL fFound = FALSE; | ||
| 985 | |||
| 986 | int iAction = -1; | ||
| 987 | LPWSTR pwzData = NULL; | ||
| 988 | |||
| 989 | //read web site key | ||
| 990 | hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzSiteName); | ||
| 991 | ExitOnFailure(hr, "Failed read web error site name"); | ||
| 992 | |||
| 993 | //read app key | ||
| 994 | hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzAppName); | ||
| 995 | ExitOnFailure(hr, "Failed read web error app name"); | ||
| 996 | |||
| 997 | //Construct config root path | ||
| 998 | hr = StrAllocFormatted(&pwzConfigPath, L"%s/%s", IIS_CONFIG_APPHOST_ROOT, pwzSiteName); | ||
| 999 | ExitOnFailure(hr, "failed to format web error config path"); | ||
| 1000 | |||
| 1001 | if (CSTR_EQUAL != ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, pwzAppName, -1, L"/", -1)) | ||
| 1002 | { | ||
| 1003 | hr = StrAllocConcat(&pwzConfigPath, L"/", 0); | ||
| 1004 | ExitOnFailure(hr, "failed to copy web error config path delim"); | ||
| 1005 | hr = StrAllocConcat(&pwzConfigPath, pwzAppName, 0); | ||
| 1006 | ExitOnFailure(hr, "failed to app name to web error config path"); | ||
| 1007 | } | ||
| 1008 | |||
| 1009 | //get httpErrors section at config path location tag | ||
| 1010 | hr = pAdminMgr->GetAdminSection(ScopeBSTR(IIS_CONFIG_HTTPERRORS_SECTION), pwzConfigPath, &pSection); | ||
| 1011 | ExitOnFailure(hr, "Failed get httpErrors section"); | ||
| 1012 | |||
| 1013 | //get existing httpErrors list & clear collection | ||
| 1014 | hr = PopulateHttpErrors(pSection, &psweList); | ||
| 1015 | ExitOnFailure(hr, "Failed to read httpErrors list"); | ||
| 1016 | |||
| 1017 | //get collection | ||
| 1018 | hr = pSection->get_Collection(&pCollection); | ||
| 1019 | ExitOnFailure(hr, "Failed get httpErrors collection"); | ||
| 1020 | |||
| 1021 | DWORD cErrors = 0; | ||
| 1022 | hr = pCollection->get_Count(&cErrors); | ||
| 1023 | |||
| 1024 | // Get web error action | ||
| 1025 | hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iAction); | ||
| 1026 | ExitOnFailure(hr, "Failed to read filter action"); | ||
| 1027 | while (IIS_WEBERROR_END != iAction) | ||
| 1028 | { | ||
| 1029 | //Process property action | ||
| 1030 | if (IIS_WEBERROR == iAction) | ||
| 1031 | { | ||
| 1032 | hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &(we.iErrorCode)); | ||
| 1033 | ExitOnFailure(hr, "failed to get httpErrors ErrorCode"); | ||
| 1034 | |||
| 1035 | hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &(we.iSubCode)); | ||
| 1036 | ExitOnFailure(hr, "failed to get httpErrors SubCode"); | ||
| 1037 | //0 is the sub error code wild card for IIS6, change to -1 for IIS7 | ||
| 1038 | if (we.iSubCode == 0) | ||
| 1039 | { | ||
| 1040 | we.iSubCode = -1; | ||
| 1041 | } | ||
| 1042 | hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzData); | ||
| 1043 | ExitOnFailure(hr, "Failed to get httpErrors File"); | ||
| 1044 | hr = ::StringCchCopyW(we.wzFile, countof(we.wzFile), pwzData); | ||
| 1045 | ExitOnFailure(hr, "Failed to copy httpErrors File"); | ||
| 1046 | |||
| 1047 | hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &(we.iResponseMode)); | ||
| 1048 | ExitOnFailure(hr, "Failed to get httpErrors File code"); | ||
| 1049 | |||
| 1050 | fFound = FALSE; | ||
| 1051 | hr = GetErrorFromList( we, &psweList, &pswe, &fFound); | ||
| 1052 | if (!fFound) | ||
| 1053 | { | ||
| 1054 | hr = AddWebErrorToList(&psweList); | ||
| 1055 | ExitOnFailure(hr, "failed to add web error to list"); | ||
| 1056 | pswe = psweList; | ||
| 1057 | } | ||
| 1058 | else | ||
| 1059 | { | ||
| 1060 | //if overwriting existing http errors element then clear lang path | ||
| 1061 | hr = ::StringCchCopyW(pswe->wzLangPath, countof(pswe->wzLangPath), L""); | ||
| 1062 | ExitOnFailure(hr, "Failed to copy httpErrors lang path value"); | ||
| 1063 | } | ||
| 1064 | pswe->iErrorCode = we.iErrorCode; | ||
| 1065 | pswe->iSubCode = we.iSubCode; | ||
| 1066 | hr = ::StringCchCopyW(pswe->wzFile, countof(pswe->wzFile), we.wzFile); | ||
| 1067 | ExitOnFailure(hr, "Failed to copy httpErrors File value"); | ||
| 1068 | pswe->iResponseMode = we.iResponseMode; | ||
| 1069 | |||
| 1070 | } | ||
| 1071 | else | ||
| 1072 | { | ||
| 1073 | ExitOnFailure(hr = E_UNEXPECTED, "Unexpected IIS Config action specified for http header"); | ||
| 1074 | } | ||
| 1075 | |||
| 1076 | // Get AppExt action | ||
| 1077 | hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iAction); | ||
| 1078 | ExitOnFailure(hr, "Failed to read filter action"); | ||
| 1079 | } | ||
| 1080 | |||
| 1081 | //No inheritance - put a clear in at this loc tag | ||
| 1082 | hr = pCollection->CreateNewElement(ScopeBSTR(IIS_CONFIG_CLEAR), &pElement); | ||
| 1083 | ExitOnFailure(hr, "Failed create httpErrors clear"); | ||
| 1084 | hr = pCollection->AddElement(pElement); | ||
| 1085 | ExitOnFailure(hr, "Failed add httpErrors clear"); | ||
| 1086 | |||
| 1087 | //now we have merged new, from MSI, http errors with global list | ||
| 1088 | //write this back out at location tag. | ||
| 1089 | // Loop through the HTTP headers | ||
| 1090 | for ( pswe = psweList; pswe; pswe = pswe->psweNext) | ||
| 1091 | { | ||
| 1092 | hr = pCollection->CreateNewElement(ScopeBSTR(IIS_CONFIG_ERROR), &pElement); | ||
| 1093 | ExitOnFailure(hr, "Failed create httpErrors element"); | ||
| 1094 | |||
| 1095 | // status code | ||
| 1096 | hr = Iis7PutPropertyInteger(pElement, IIS_CONFIG_STATUSCODE, pswe->iErrorCode); | ||
| 1097 | ExitOnFailure(hr, "Failed set httpErrors code value"); | ||
| 1098 | |||
| 1099 | //sub status | ||
| 1100 | hr = Iis7PutPropertyInteger(pElement, IIS_CONFIG_SUBSTATUS, pswe->iSubCode); | ||
| 1101 | ExitOnFailure(hr, "Failed set httpErrors sub code value"); | ||
| 1102 | |||
| 1103 | //lang path | ||
| 1104 | hr = Iis7PutPropertyString(pElement, IIS_CONFIG_LANGPATH, pswe->wzLangPath); | ||
| 1105 | ExitOnFailure(hr, "Failed set httpErrors lang path value"); | ||
| 1106 | |||
| 1107 | //path | ||
| 1108 | hr = Iis7PutPropertyString(pElement, IIS_CONFIG_PATH, pswe->wzFile); | ||
| 1109 | ExitOnFailure(hr, "Failed set httpErrors path value"); | ||
| 1110 | |||
| 1111 | //response mode | ||
| 1112 | hr = Iis7PutPropertyInteger(pElement, IIS_CONFIG_RESPMODE, pswe->iResponseMode); | ||
| 1113 | ExitOnFailure(hr, "Failed set httpErrors resp mode value"); | ||
| 1114 | |||
| 1115 | //add the element | ||
| 1116 | hr = pCollection->AddElement(pElement); | ||
| 1117 | ExitOnFailure(hr, "Failed add httpErrors element"); | ||
| 1118 | ReleaseNullObject(pElement); | ||
| 1119 | } | ||
| 1120 | |||
| 1121 | LExit: | ||
| 1122 | ScaWebErrorFreeList7(psweList); | ||
| 1123 | |||
| 1124 | ReleaseStr(pwzConfigPath); | ||
| 1125 | ReleaseStr(pwzSiteName); | ||
| 1126 | ReleaseStr(pwzAppName); | ||
| 1127 | ReleaseStr(pwzData); | ||
| 1128 | ReleaseObject(pElement); | ||
| 1129 | ReleaseObject(pSection); | ||
| 1130 | ReleaseObject(pCollection); | ||
| 1131 | |||
| 1132 | return hr; | ||
| 1133 | } | ||
| 1134 | |||
| 1135 | static HRESULT PopulateHttpErrors(IAppHostElement *pSection, SCA_WEB_ERROR_SERVER **ppsweList) | ||
| 1136 | { | ||
| 1137 | HRESULT hr = S_OK; | ||
| 1138 | |||
| 1139 | IAppHostElement *pElement = NULL; | ||
| 1140 | IAppHostElementCollection *pCollection = NULL; | ||
| 1141 | IAppHostProperty *pProperty = NULL; | ||
| 1142 | |||
| 1143 | DWORD cErrors = 0; | ||
| 1144 | SCA_WEB_ERROR_SERVER *pswe = NULL; | ||
| 1145 | |||
| 1146 | VARIANT vPropValue; | ||
| 1147 | VARIANT vtIndex; | ||
| 1148 | |||
| 1149 | VariantInit(&vPropValue); | ||
| 1150 | VariantInit(&vtIndex); | ||
| 1151 | |||
| 1152 | hr = pSection->get_Collection(&pCollection); | ||
| 1153 | ExitOnFailure(hr, "Failed get httpErrors collection"); | ||
| 1154 | |||
| 1155 | hr = pCollection->get_Count(&cErrors); | ||
| 1156 | ExitOnFailure(hr, "Failed get sites collection count"); | ||
| 1157 | |||
| 1158 | vtIndex.vt = VT_UI4; | ||
| 1159 | for (DWORD i = 0; i < cErrors; ++i) | ||
| 1160 | { | ||
| 1161 | vtIndex.ulVal = i; | ||
| 1162 | hr = pCollection->get_Item(vtIndex , &pElement); | ||
| 1163 | ExitOnFailure(hr, "Failed get httpErrors collection item"); | ||
| 1164 | |||
| 1165 | hr = AddWebErrorToList(ppsweList); | ||
| 1166 | ExitOnFailure(hr, "Failed add web error list item"); | ||
| 1167 | pswe = *ppsweList; | ||
| 1168 | |||
| 1169 | //get all properties | ||
| 1170 | // | ||
| 1171 | // statusCode UINT | ||
| 1172 | // subStatusCode INT | ||
| 1173 | // prefixLanguageFilePath type="string" | ||
| 1174 | // path type="string" | ||
| 1175 | // responseMode type="enum" defaultValue="File"> | ||
| 1176 | // <enum name="File" value="0" /> | ||
| 1177 | // <enum name="ExecuteURL" value="1" /> | ||
| 1178 | // <enum name="Redirect" value="2" /> | ||
| 1179 | |||
| 1180 | // status code | ||
| 1181 | hr = pElement->GetPropertyByName(ScopeBSTR(IIS_CONFIG_STATUSCODE), &pProperty); | ||
| 1182 | ExitOnFailure(hr, "Failed get httpErrors code property"); | ||
| 1183 | hr = pProperty->get_Value(&vPropValue); | ||
| 1184 | ExitOnFailure(hr, "Failed get httpErrors code value"); | ||
| 1185 | pswe->iErrorCode = vPropValue.uintVal; | ||
| 1186 | ReleaseVariant(vPropValue); | ||
| 1187 | |||
| 1188 | //sub status | ||
| 1189 | hr = pElement->GetPropertyByName(ScopeBSTR(IIS_CONFIG_SUBSTATUS), &pProperty); | ||
| 1190 | ExitOnFailure(hr, "Failed get httpErrors sub code property"); | ||
| 1191 | hr = pProperty->get_Value(&vPropValue); | ||
| 1192 | ExitOnFailure(hr, "Failed get httpErrors sub code value"); | ||
| 1193 | pswe->iSubCode = vPropValue.intVal; | ||
| 1194 | ReleaseVariant(vPropValue); | ||
| 1195 | |||
| 1196 | //lang path | ||
| 1197 | hr = pElement->GetPropertyByName(ScopeBSTR(IIS_CONFIG_LANGPATH), &pProperty); | ||
| 1198 | ExitOnFailure(hr, "Failed get httpErrors lang path property"); | ||
| 1199 | hr = pProperty->get_Value(&vPropValue); | ||
| 1200 | ExitOnFailure(hr, "Failed get httpErrors lang path value"); | ||
| 1201 | hr = ::StringCchCopyW(pswe->wzLangPath, countof(pswe->wzLangPath), vPropValue.bstrVal); | ||
| 1202 | ExitOnFailure(hr, "Failed to copy httpErrors lang path"); | ||
| 1203 | ReleaseVariant(vPropValue); | ||
| 1204 | |||
| 1205 | //path | ||
| 1206 | hr = pElement->GetPropertyByName(ScopeBSTR(IIS_CONFIG_PATH), &pProperty); | ||
| 1207 | ExitOnFailure(hr, "Failed get httpErrors path property"); | ||
| 1208 | hr = pProperty->get_Value(&vPropValue); | ||
| 1209 | ExitOnFailure(hr, "Failed get httpErrors path value"); | ||
| 1210 | hr = ::StringCchCopyW(pswe->wzFile, countof(pswe->wzFile), vPropValue.bstrVal); | ||
| 1211 | ExitOnFailure(hr, "Failed to copy httpErrors File"); | ||
| 1212 | ReleaseVariant(vPropValue); | ||
| 1213 | |||
| 1214 | //response mode | ||
| 1215 | hr = pElement->GetPropertyByName(ScopeBSTR(IIS_CONFIG_RESPMODE), &pProperty); | ||
| 1216 | ExitOnFailure(hr, "Failed get httpErrors resp mode property"); | ||
| 1217 | hr = pProperty->get_Value(&vPropValue); | ||
| 1218 | ExitOnFailure(hr, "Failed get httpErrors resp mode value"); | ||
| 1219 | pswe->iResponseMode = vPropValue.intVal; | ||
| 1220 | ReleaseVariant(vPropValue); | ||
| 1221 | |||
| 1222 | ReleaseNullObject(pElement); | ||
| 1223 | ReleaseNullObject(pProperty); | ||
| 1224 | } | ||
| 1225 | |||
| 1226 | //remove the elements from connection so we can add back later | ||
| 1227 | hr = pCollection->Clear(); | ||
| 1228 | ExitOnFailure(hr, "Failed clear httpErrors collection"); | ||
| 1229 | |||
| 1230 | LExit: | ||
| 1231 | ReleaseVariant(vPropValue); | ||
| 1232 | ReleaseObject(pProperty); | ||
| 1233 | ReleaseObject(pElement); | ||
| 1234 | ReleaseObject(pCollection); | ||
| 1235 | |||
| 1236 | return hr; | ||
| 1237 | } | ||
| 1238 | |||
| 1239 | static void ScaWebErrorFreeList7(SCA_WEB_ERROR_SERVER *psweList) | ||
| 1240 | { | ||
| 1241 | SCA_WEB_ERROR_SERVER *psweDelete = psweList; | ||
| 1242 | while (psweList) | ||
| 1243 | { | ||
| 1244 | psweDelete = psweList; | ||
| 1245 | psweList = psweList->psweNext; | ||
| 1246 | |||
| 1247 | MemFree(psweDelete); | ||
| 1248 | } | ||
| 1249 | } | ||
| 1250 | static HRESULT AddWebErrorToList(SCA_WEB_ERROR_SERVER **ppsweList) | ||
| 1251 | { | ||
| 1252 | HRESULT hr = S_OK; | ||
| 1253 | |||
| 1254 | SCA_WEB_ERROR_SERVER* pswe = static_cast<SCA_WEB_ERROR_SERVER*>(MemAlloc(sizeof(SCA_WEB_ERROR_SERVER), TRUE)); | ||
| 1255 | |||
| 1256 | ExitOnNull(pswe, hr, E_OUTOFMEMORY, "failed to allocate memory for new web error list element"); | ||
| 1257 | |||
| 1258 | pswe->psweNext = *ppsweList; | ||
| 1259 | *ppsweList = pswe; | ||
| 1260 | |||
| 1261 | LExit: | ||
| 1262 | return hr; | ||
| 1263 | } | ||
| 1264 | static HRESULT GetErrorFromList( const SCA_WEB_ERROR_SERVER& we, | ||
| 1265 | SCA_WEB_ERROR_SERVER **ppsweList, | ||
| 1266 | SCA_WEB_ERROR_SERVER **ppswe, | ||
| 1267 | BOOL *fFound) | ||
| 1268 | { | ||
| 1269 | HRESULT hr = S_OK; | ||
| 1270 | |||
| 1271 | *fFound = FALSE; | ||
| 1272 | |||
| 1273 | SCA_WEB_ERROR_SERVER *pswe; | ||
| 1274 | |||
| 1275 | for ( pswe = *ppsweList; pswe; pswe = pswe->psweNext) | ||
| 1276 | { | ||
| 1277 | if ((pswe->iErrorCode == we.iErrorCode) && (pswe->iSubCode == we.iSubCode)) | ||
| 1278 | { | ||
| 1279 | *fFound = TRUE; | ||
| 1280 | *ppswe = pswe; | ||
| 1281 | break; | ||
| 1282 | } | ||
| 1283 | } | ||
| 1284 | |||
| 1285 | return hr; | ||
| 1286 | } | ||
| 1287 | |||
| 1288 | //------------------------------------------------------------------------------------------------- | ||
| 1289 | // IIS7HttpHeader | ||
| 1290 | // Called by WriteIIS7ConfigChanges | ||
| 1291 | // Processes http header CA Data | ||
| 1292 | // | ||
| 1293 | //------------------------------------------------------------------------------------------------- | ||
| 1294 | |||
| 1295 | HRESULT IIS7HttpHeader( | ||
| 1296 | __inout LPWSTR *ppwzCustomActionData, | ||
| 1297 | __in IAppHostWritableAdminManager *pAdminMgr | ||
| 1298 | ) | ||
| 1299 | { | ||
| 1300 | HRESULT hr = S_OK; | ||
| 1301 | LPWSTR pwzConfigPath = NULL; | ||
| 1302 | LPWSTR pwzSiteName = NULL; | ||
| 1303 | LPWSTR pwzAppName = NULL; | ||
| 1304 | |||
| 1305 | LPWSTR pwzHeaderName = NULL; | ||
| 1306 | LPWSTR pwzHeaderValue = NULL; | ||
| 1307 | |||
| 1308 | IAppHostElement *pElement = NULL; | ||
| 1309 | IAppHostElement *pSection = NULL; | ||
| 1310 | IAppHostElementCollection *pCollection = NULL; | ||
| 1311 | IAppHostElement *pElementHeaders = NULL; | ||
| 1312 | |||
| 1313 | int iAction = -1; | ||
| 1314 | BOOL fFound = FALSE; | ||
| 1315 | |||
| 1316 | //read web site key | ||
| 1317 | hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzSiteName); | ||
| 1318 | ExitOnFailure(hr, "Failed read header web site name"); | ||
| 1319 | |||
| 1320 | //read app key | ||
| 1321 | hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzAppName); | ||
| 1322 | ExitOnFailure(hr, "Failed read header appkey"); | ||
| 1323 | |||
| 1324 | //Construct config root path | ||
| 1325 | hr = StrAllocFormatted(&pwzConfigPath, L"%s/%s", IIS_CONFIG_APPHOST_ROOT, pwzSiteName); | ||
| 1326 | ExitOnFailure(hr, "failed to format web error config path"); | ||
| 1327 | |||
| 1328 | if (CSTR_EQUAL != ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, pwzAppName, -1, L"/", -1)) | ||
| 1329 | { | ||
| 1330 | hr = StrAllocConcat(&pwzConfigPath, L"/", 0); | ||
| 1331 | ExitOnFailure(hr, "failed to copy web error config path delim"); | ||
| 1332 | hr = StrAllocConcat(&pwzConfigPath, pwzAppName, 0); | ||
| 1333 | ExitOnFailure(hr, "failed to app name to web error config path"); | ||
| 1334 | } | ||
| 1335 | |||
| 1336 | //get admin handlers section at config path location tag | ||
| 1337 | hr = pAdminMgr->GetAdminSection(ScopeBSTR(IIS_CONFIG_HTTPPROTO_SECTION), pwzConfigPath, &pSection); | ||
| 1338 | ExitOnFailure(hr, "Failed get http protocol section"); | ||
| 1339 | |||
| 1340 | hr = pSection->GetElementByName(ScopeBSTR(IIS_CONFIG_HEADERS), &pElementHeaders); | ||
| 1341 | ExitOnFailure(hr, "Failed get http customHeaders section"); | ||
| 1342 | |||
| 1343 | hr = pElementHeaders->get_Collection(&pCollection); | ||
| 1344 | ExitOnFailure(hr, "Failed get http customHeaders collection"); | ||
| 1345 | |||
| 1346 | // Get filter action | ||
| 1347 | hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iAction); | ||
| 1348 | ExitOnFailure(hr, "Failed to read filter action"); | ||
| 1349 | while (IIS_HTTP_HEADER_END != iAction) | ||
| 1350 | { | ||
| 1351 | //Process property action | ||
| 1352 | if (IIS_HTTP_HEADER == iAction) | ||
| 1353 | { | ||
| 1354 | hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzHeaderName); | ||
| 1355 | ExitOnFailure(hr, "Fail to read httpHeader name"); | ||
| 1356 | |||
| 1357 | hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzHeaderValue); | ||
| 1358 | ExitOnFailure(hr, "Fail to read httpHeader value"); | ||
| 1359 | |||
| 1360 | hr = Iis7FindAppHostElementString(pCollection, IIS_CONFIG_ADD, IIS_CONFIG_NAME, pwzHeaderName, &pElement, NULL); | ||
| 1361 | ExitOnFailure(hr, "Failed get isapiCgiRestriction element"); | ||
| 1362 | fFound = (NULL != pElement); | ||
| 1363 | |||
| 1364 | if (!fFound) | ||
| 1365 | { | ||
| 1366 | //make a new element | ||
| 1367 | hr = pCollection->CreateNewElement(ScopeBSTR(IIS_CONFIG_ADD), &pElement); | ||
| 1368 | ExitOnFailure(hr, "Failed to create filter config element"); | ||
| 1369 | |||
| 1370 | hr = Iis7PutPropertyString(pElement, IIS_CONFIG_NAME, pwzHeaderName); | ||
| 1371 | ExitOnFailure(hr, "Failed to set header name"); | ||
| 1372 | } | ||
| 1373 | |||
| 1374 | hr = Iis7PutPropertyString(pElement, IIS_CONFIG_VALUE, pwzHeaderValue); | ||
| 1375 | ExitOnFailure(hr, "Failed to set header Value"); | ||
| 1376 | |||
| 1377 | if (!fFound) | ||
| 1378 | { | ||
| 1379 | hr = pCollection->AddElement(pElement); | ||
| 1380 | ExitOnFailure(hr, "Failed add http header"); | ||
| 1381 | } | ||
| 1382 | |||
| 1383 | } | ||
| 1384 | else | ||
| 1385 | { | ||
| 1386 | ExitOnFailure(hr = E_UNEXPECTED, "Unexpected IIS Config action specified for http header"); | ||
| 1387 | } | ||
| 1388 | |||
| 1389 | // Get AppExt action | ||
| 1390 | hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iAction); | ||
| 1391 | ExitOnFailure(hr, "Failed to read filter action"); | ||
| 1392 | } | ||
| 1393 | |||
| 1394 | LExit: | ||
| 1395 | ReleaseStr(pwzConfigPath); | ||
| 1396 | ReleaseStr(pwzSiteName); | ||
| 1397 | ReleaseStr(pwzAppName); | ||
| 1398 | ReleaseStr(pwzHeaderName); | ||
| 1399 | ReleaseStr(pwzHeaderValue); | ||
| 1400 | ReleaseObject(pElementHeaders); | ||
| 1401 | ReleaseObject(pElement); | ||
| 1402 | ReleaseObject(pSection); | ||
| 1403 | ReleaseObject(pCollection); | ||
| 1404 | |||
| 1405 | return hr; | ||
| 1406 | } | ||
| 1407 | |||
| 1408 | //------------------------------------------------------------------------------------------------- | ||
| 1409 | // IIS7FilterGlobal | ||
| 1410 | // Called by WriteIIS7ConfigChanges | ||
| 1411 | // Processes Filter CA Data | ||
| 1412 | // | ||
| 1413 | //------------------------------------------------------------------------------------------------- | ||
| 1414 | HRESULT IIS7FilterGlobal( | ||
| 1415 | __inout LPWSTR *ppwzCustomActionData, | ||
| 1416 | __in IAppHostWritableAdminManager *pAdminMgr | ||
| 1417 | ) | ||
| 1418 | { | ||
| 1419 | HRESULT hr = S_OK; | ||
| 1420 | int iAction = 0; | ||
| 1421 | |||
| 1422 | IAppHostElement *pSection = NULL; | ||
| 1423 | |||
| 1424 | hr = pAdminMgr->GetAdminSection(ScopeBSTR(IIS_CONFIG_ISAPI_SECTION), ScopeBSTR(IIS_CONFIG_APPHOST_ROOT), &pSection); | ||
| 1425 | ExitOnFailure(hr, "Failed get sites section"); | ||
| 1426 | |||
| 1427 | if (!pSection) | ||
| 1428 | { | ||
| 1429 | hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); | ||
| 1430 | ExitOnFailure(hr, "Failed get isapiFilters section object"); | ||
| 1431 | } | ||
| 1432 | |||
| 1433 | // Get filter action | ||
| 1434 | hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iAction); | ||
| 1435 | ExitOnFailure(hr, "Failed to read filter action"); | ||
| 1436 | |||
| 1437 | while (IIS_FILTER_END != iAction) | ||
| 1438 | { | ||
| 1439 | //Process property action | ||
| 1440 | switch (iAction) | ||
| 1441 | { | ||
| 1442 | case IIS_FILTER : | ||
| 1443 | { | ||
| 1444 | hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iAction); | ||
| 1445 | ExitOnFailure(hr, "Failed to read filter action"); | ||
| 1446 | |||
| 1447 | if (iAction == IIS_CREATE) | ||
| 1448 | { | ||
| 1449 | hr = CreateGlobalFilter(ppwzCustomActionData, pSection); | ||
| 1450 | } | ||
| 1451 | else | ||
| 1452 | { | ||
| 1453 | hr = DeleteGlobalFilter(ppwzCustomActionData, pSection); | ||
| 1454 | } | ||
| 1455 | break; | ||
| 1456 | } | ||
| 1457 | default: | ||
| 1458 | { | ||
| 1459 | ExitOnFailure(hr = E_UNEXPECTED, "Unexpected IIS Config action specified for global filter"); | ||
| 1460 | break; | ||
| 1461 | } | ||
| 1462 | } | ||
| 1463 | // Get AppExt action | ||
| 1464 | hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iAction); | ||
| 1465 | ExitOnFailure(hr, "Failed to read filter action"); | ||
| 1466 | |||
| 1467 | } | ||
| 1468 | |||
| 1469 | LExit: | ||
| 1470 | ReleaseObject(pSection); | ||
| 1471 | |||
| 1472 | return hr; | ||
| 1473 | } | ||
| 1474 | |||
| 1475 | static HRESULT CreateGlobalFilter( __inout LPWSTR *ppwzCustomActionData, IAppHostElement *pSection) | ||
| 1476 | { | ||
| 1477 | HRESULT hr = S_OK; | ||
| 1478 | |||
| 1479 | LPWSTR pwzFilterName = NULL; | ||
| 1480 | LPWSTR pwzSiteName = NULL; | ||
| 1481 | LPWSTR pwzFilterPath = NULL; | ||
| 1482 | int iLoadOrder = 0; | ||
| 1483 | DWORD cFilters = 0; | ||
| 1484 | |||
| 1485 | IAppHostElement *pElement = NULL; | ||
| 1486 | IAppHostElementCollection *pCollection = NULL; | ||
| 1487 | |||
| 1488 | hr = pSection->get_Collection(&pCollection); | ||
| 1489 | ExitOnFailure(hr, "Failed get filter collection"); | ||
| 1490 | |||
| 1491 | hr = pCollection->get_Count(&cFilters); | ||
| 1492 | ExitOnFailure(hr, "Failed get filter collection count"); | ||
| 1493 | |||
| 1494 | // Attempt to delete, we will we recreate with desired property values and order | ||
| 1495 | hr = DeleteCollectionElement(pCollection, IIS_CONFIG_FILTER, IIS_CONFIG_NAME, pwzFilterName); | ||
| 1496 | ExitOnFailure(hr, "Failed to delete filter"); | ||
| 1497 | |||
| 1498 | //make a new element | ||
| 1499 | hr = pCollection->CreateNewElement(ScopeBSTR(IIS_CONFIG_FILTER), &pElement); | ||
| 1500 | ExitOnFailure(hr, "Failed to create filter config element"); | ||
| 1501 | |||
| 1502 | //filter Name key | ||
| 1503 | hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzFilterName); | ||
| 1504 | ExitOnFailure(hr, "Failed to read filter name"); | ||
| 1505 | hr = Iis7PutPropertyString(pElement, IIS_CONFIG_NAME, pwzFilterName); | ||
| 1506 | ExitOnFailure(hr, "Failed to set filter name"); | ||
| 1507 | |||
| 1508 | //web site name | ||
| 1509 | hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzSiteName); | ||
| 1510 | ExitOnFailure(hr, "Failed to read filter site name"); | ||
| 1511 | |||
| 1512 | // filter path | ||
| 1513 | hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzFilterPath); | ||
| 1514 | ExitOnFailure(hr, "Failed to read filter path"); | ||
| 1515 | hr = Iis7PutPropertyString(pElement,IIS_CONFIG_PATH, pwzFilterPath); | ||
| 1516 | ExitOnFailure(hr, "Failed to set filter path"); | ||
| 1517 | |||
| 1518 | //filter load order | ||
| 1519 | hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iLoadOrder); | ||
| 1520 | ExitOnFailure(hr, "Failed to read filter load order"); | ||
| 1521 | |||
| 1522 | // put element in order in list | ||
| 1523 | int iPosition = -1; | ||
| 1524 | int icFilters = cFilters; | ||
| 1525 | switch (iLoadOrder) | ||
| 1526 | { | ||
| 1527 | case 0 : | ||
| 1528 | { | ||
| 1529 | iPosition = -1; | ||
| 1530 | break; | ||
| 1531 | } | ||
| 1532 | case -1 : | ||
| 1533 | { | ||
| 1534 | iPosition = icFilters; | ||
| 1535 | break; | ||
| 1536 | } | ||
| 1537 | case MSI_NULL_INTEGER : | ||
| 1538 | { | ||
| 1539 | iPosition = icFilters; | ||
| 1540 | break; | ||
| 1541 | } | ||
| 1542 | default: | ||
| 1543 | { | ||
| 1544 | if (iLoadOrder > icFilters) | ||
| 1545 | { | ||
| 1546 | iPosition = icFilters; | ||
| 1547 | } | ||
| 1548 | else | ||
| 1549 | { | ||
| 1550 | iPosition = iLoadOrder; | ||
| 1551 | } | ||
| 1552 | break; | ||
| 1553 | } | ||
| 1554 | } | ||
| 1555 | hr = pCollection->AddElement(pElement, iPosition); | ||
| 1556 | ExitOnFailure(hr, "Failed to add filter element"); | ||
| 1557 | |||
| 1558 | LExit: | ||
| 1559 | ReleaseStr(pwzFilterName); | ||
| 1560 | ReleaseStr(pwzSiteName); | ||
| 1561 | ReleaseStr(pwzFilterPath); | ||
| 1562 | ReleaseObject(pCollection); | ||
| 1563 | ReleaseObject(pElement); | ||
| 1564 | |||
| 1565 | return hr; | ||
| 1566 | } | ||
| 1567 | |||
| 1568 | static HRESULT DeleteGlobalFilter( __inout LPWSTR *ppwzCustomActionData, IAppHostElement *pSection) | ||
| 1569 | { | ||
| 1570 | HRESULT hr = S_OK; | ||
| 1571 | |||
| 1572 | LPWSTR pwzFilterName = NULL; | ||
| 1573 | LPWSTR pwzSiteName = NULL; | ||
| 1574 | |||
| 1575 | IAppHostElementCollection *pCollection = NULL; | ||
| 1576 | |||
| 1577 | hr = pSection->get_Collection(&pCollection); | ||
| 1578 | ExitOnFailure(hr, "Failed get filter collection"); | ||
| 1579 | |||
| 1580 | //filter Name key | ||
| 1581 | hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzFilterName); | ||
| 1582 | ExitOnFailure(hr, "Failed to read filter name"); | ||
| 1583 | |||
| 1584 | //web site name | ||
| 1585 | hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzSiteName); // TODO: unused? | ||
| 1586 | ExitOnFailure(hr, "Failed to read filter site name"); | ||
| 1587 | |||
| 1588 | DeleteCollectionElement(pCollection, IIS_CONFIG_FILTER, IIS_CONFIG_NAME, pwzFilterName); | ||
| 1589 | ExitOnFailure(hr, "Failed to delete filter %ls", pwzFilterName); | ||
| 1590 | |||
| 1591 | LExit: | ||
| 1592 | ReleaseStr(pwzFilterName); | ||
| 1593 | ReleaseStr(pwzSiteName); | ||
| 1594 | ReleaseObject(pCollection); | ||
| 1595 | |||
| 1596 | return hr; | ||
| 1597 | } | ||
| 1598 | |||
| 1599 | //------------------------------------------------------------------------------------------------- | ||
| 1600 | // IIS7FilterSite | ||
| 1601 | // Called by WriteIIS7ConfigChanges | ||
| 1602 | // Processes Filter CA Data | ||
| 1603 | // | ||
| 1604 | //------------------------------------------------------------------------------------------------- | ||
| 1605 | HRESULT IIS7FilterSite( | ||
| 1606 | __inout LPWSTR *ppwzCustomActionData, | ||
| 1607 | __in IAppHostWritableAdminManager *pAdminMgr | ||
| 1608 | ) | ||
| 1609 | { | ||
| 1610 | HRESULT hr = S_OK; | ||
| 1611 | int iAction = 0; | ||
| 1612 | |||
| 1613 | // Get filter action | ||
| 1614 | hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iAction); | ||
| 1615 | ExitOnFailure(hr, "Failed to read filter action"); | ||
| 1616 | |||
| 1617 | while (IIS_FILTER_END != iAction) | ||
| 1618 | { | ||
| 1619 | //Process property action | ||
| 1620 | switch (iAction) | ||
| 1621 | { | ||
| 1622 | case IIS_FILTER : | ||
| 1623 | { | ||
| 1624 | hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iAction); | ||
| 1625 | ExitOnFailure(hr, "Failed to read filter action"); | ||
| 1626 | |||
| 1627 | if (iAction == IIS_CREATE) | ||
| 1628 | { | ||
| 1629 | hr = CreateSiteFilter(ppwzCustomActionData, pAdminMgr); | ||
| 1630 | } | ||
| 1631 | else | ||
| 1632 | { | ||
| 1633 | hr = DeleteSiteFilter(ppwzCustomActionData, pAdminMgr); | ||
| 1634 | } | ||
| 1635 | break; | ||
| 1636 | } | ||
| 1637 | default: | ||
| 1638 | { | ||
| 1639 | ExitOnFailure(hr = E_UNEXPECTED, "Unexpected IIS Config action specified for global filter"); | ||
| 1640 | break; | ||
| 1641 | } | ||
| 1642 | } | ||
| 1643 | |||
| 1644 | // Get AppExt action | ||
| 1645 | hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iAction); | ||
| 1646 | ExitOnFailure(hr, "Failed to read filter action"); | ||
| 1647 | } | ||
| 1648 | |||
| 1649 | LExit: | ||
| 1650 | return hr; | ||
| 1651 | |||
| 1652 | } | ||
| 1653 | |||
| 1654 | static HRESULT CreateSiteFilter(__inout LPWSTR *ppwzCustomActionData, IAppHostWritableAdminManager *pAdminMgr) | ||
| 1655 | { | ||
| 1656 | HRESULT hr = S_OK; | ||
| 1657 | LPWSTR pwzFilterName = NULL; | ||
| 1658 | LPWSTR pwzSiteName = NULL; | ||
| 1659 | LPWSTR pwzFilterPath = NULL; | ||
| 1660 | LPWSTR pwzConfigPath = NULL; | ||
| 1661 | int iLoadOrder = 0; | ||
| 1662 | DWORD cFilters; | ||
| 1663 | |||
| 1664 | IAppHostElement *pElement = NULL; | ||
| 1665 | IAppHostElement *pSection = NULL; | ||
| 1666 | IAppHostElementCollection *pCollection = NULL; | ||
| 1667 | |||
| 1668 | //filter Name key | ||
| 1669 | hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzFilterName); | ||
| 1670 | ExitOnFailure(hr, "Failed to read filter name"); | ||
| 1671 | |||
| 1672 | //web site name | ||
| 1673 | hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzSiteName); | ||
| 1674 | ExitOnFailure(hr, "Failed to read filter site name"); | ||
| 1675 | |||
| 1676 | //Construct config root | ||
| 1677 | hr = StrAllocFormatted(&pwzConfigPath, L"%s/%s", IIS_CONFIG_APPHOST_ROOT, pwzSiteName); | ||
| 1678 | ExitOnFailure(hr, "failed to format filter config path"); | ||
| 1679 | |||
| 1680 | //get admin isapiFilters section at config path location tag | ||
| 1681 | hr = pAdminMgr->GetAdminSection(ScopeBSTR(IIS_CONFIG_ISAPI_SECTION), pwzConfigPath, &pSection); | ||
| 1682 | ExitOnFailure(hr, "Failed get isapiFilters section"); | ||
| 1683 | |||
| 1684 | hr = pSection->get_Collection(&pCollection); | ||
| 1685 | ExitOnFailure(hr, "Failed get filter collection"); | ||
| 1686 | |||
| 1687 | hr = pCollection->get_Count(&cFilters); | ||
| 1688 | ExitOnFailure(hr, "Failed get filter collection count"); | ||
| 1689 | |||
| 1690 | // Attempt to delete, we will we recreate with desired property values and order | ||
| 1691 | hr = DeleteCollectionElement(pCollection, IIS_CONFIG_FILTER, IIS_CONFIG_NAME, pwzFilterName); | ||
| 1692 | ExitOnFailure(hr, "Failed to delete filter"); | ||
| 1693 | |||
| 1694 | //make a new element | ||
| 1695 | hr = pCollection->CreateNewElement(ScopeBSTR(IIS_CONFIG_FILTER), &pElement); | ||
| 1696 | ExitOnFailure(hr, "Failed to create filter config element"); | ||
| 1697 | |||
| 1698 | hr = Iis7PutPropertyString(pElement,IIS_CONFIG_NAME, pwzFilterName); | ||
| 1699 | ExitOnFailure(hr, "Failed to set filter name"); | ||
| 1700 | |||
| 1701 | // filter path | ||
| 1702 | hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzFilterPath); | ||
| 1703 | ExitOnFailure(hr, "Failed to read filter path"); | ||
| 1704 | |||
| 1705 | hr = Iis7PutPropertyString(pElement, IIS_CONFIG_PATH, pwzFilterPath); | ||
| 1706 | ExitOnFailure(hr, "Failed to set filter path"); | ||
| 1707 | |||
| 1708 | //filter load order | ||
| 1709 | hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iLoadOrder); | ||
| 1710 | ExitOnFailure(hr, "Failed to read filter load order"); | ||
| 1711 | |||
| 1712 | // put element in order in list | ||
| 1713 | int iPosition = -1; | ||
| 1714 | int icFilters = cFilters; | ||
| 1715 | switch (iLoadOrder) | ||
| 1716 | { | ||
| 1717 | case 0 : | ||
| 1718 | { | ||
| 1719 | iPosition = -1; | ||
| 1720 | break; | ||
| 1721 | } | ||
| 1722 | case -1 : | ||
| 1723 | { | ||
| 1724 | iPosition = icFilters; | ||
| 1725 | break; | ||
| 1726 | } | ||
| 1727 | case MSI_NULL_INTEGER : | ||
| 1728 | { | ||
| 1729 | iPosition = icFilters; | ||
| 1730 | break; | ||
| 1731 | } | ||
| 1732 | default: | ||
| 1733 | { | ||
| 1734 | if (iLoadOrder > icFilters) | ||
| 1735 | { | ||
| 1736 | iPosition = icFilters; | ||
| 1737 | } | ||
| 1738 | else | ||
| 1739 | { | ||
| 1740 | iPosition = iLoadOrder; | ||
| 1741 | } | ||
| 1742 | break; | ||
| 1743 | } | ||
| 1744 | } | ||
| 1745 | |||
| 1746 | hr = pCollection->AddElement(pElement, iPosition); | ||
| 1747 | ExitOnFailure(hr, "Failed to add filter element"); | ||
| 1748 | |||
| 1749 | LExit: | ||
| 1750 | ReleaseStr(pwzFilterName); | ||
| 1751 | ReleaseStr(pwzSiteName); | ||
| 1752 | ReleaseStr(pwzFilterPath); | ||
| 1753 | ReleaseStr(pwzConfigPath); | ||
| 1754 | ReleaseObject(pElement); | ||
| 1755 | ReleaseObject(pSection); | ||
| 1756 | ReleaseObject(pCollection); | ||
| 1757 | |||
| 1758 | return hr; | ||
| 1759 | } | ||
| 1760 | |||
| 1761 | static HRESULT DeleteSiteFilter(__inout LPWSTR *ppwzCustomActionData, IAppHostWritableAdminManager *pAdminMgr) | ||
| 1762 | { | ||
| 1763 | HRESULT hr = S_OK; | ||
| 1764 | LPWSTR pwzFilterName = NULL; | ||
| 1765 | LPWSTR pwzSiteName = NULL; | ||
| 1766 | LPWSTR pwzConfigPath = NULL; | ||
| 1767 | |||
| 1768 | IAppHostElement *pSection = NULL; | ||
| 1769 | IAppHostElementCollection *pCollection = NULL; | ||
| 1770 | |||
| 1771 | //filter Name key | ||
| 1772 | hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzFilterName); | ||
| 1773 | ExitOnFailure(hr, "Failed to read filter name"); | ||
| 1774 | |||
| 1775 | //web site name | ||
| 1776 | hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzSiteName); | ||
| 1777 | ExitOnFailure(hr, "Failed to read filter site name"); | ||
| 1778 | |||
| 1779 | //Construct config root | ||
| 1780 | hr = StrAllocFormatted(&pwzConfigPath, L"%s/%s", IIS_CONFIG_APPHOST_ROOT, pwzSiteName); | ||
| 1781 | ExitOnFailure(hr, "failed to format filter config path"); | ||
| 1782 | |||
| 1783 | //get admin isapiFilters section at config path location tag | ||
| 1784 | hr = pAdminMgr->GetAdminSection(ScopeBSTR(IIS_CONFIG_ISAPI_SECTION), pwzConfigPath, &pSection); | ||
| 1785 | ExitOnFailure(hr, "Failed get isapiFilters section"); | ||
| 1786 | |||
| 1787 | hr = pSection->get_Collection(&pCollection); | ||
| 1788 | ExitOnFailure(hr, "Failed get filter collection"); | ||
| 1789 | |||
| 1790 | DeleteCollectionElement(pCollection, IIS_CONFIG_FILTER, IIS_CONFIG_NAME, pwzFilterName); | ||
| 1791 | ExitOnFailure(hr, "Failed to delete filter %ls", pwzFilterName); | ||
| 1792 | |||
| 1793 | LExit: | ||
| 1794 | ReleaseStr(pwzFilterName); | ||
| 1795 | ReleaseStr(pwzSiteName); | ||
| 1796 | ReleaseStr(pwzConfigPath); | ||
| 1797 | ReleaseObject(pSection); | ||
| 1798 | ReleaseObject(pCollection); | ||
| 1799 | |||
| 1800 | return hr; | ||
| 1801 | } | ||
| 1802 | |||
| 1803 | //------------------------------------------------------------------------------------------------- | ||
| 1804 | // IIS7Site | ||
| 1805 | // Called by WriteIIS7ConfigChanges | ||
| 1806 | // Processes WebSite CA Data | ||
| 1807 | // | ||
| 1808 | //------------------------------------------------------------------------------------------------- | ||
| 1809 | HRESULT IIS7Site( | ||
| 1810 | __inout LPWSTR *ppwzCustomActionData, | ||
| 1811 | __in IAppHostWritableAdminManager *pAdminMgr) | ||
| 1812 | { | ||
| 1813 | HRESULT hr = S_OK; | ||
| 1814 | int iAction = -1; | ||
| 1815 | int iData = 0; | ||
| 1816 | BOOL fFound = FALSE; | ||
| 1817 | |||
| 1818 | LPWSTR pwzSiteName = NULL; | ||
| 1819 | IAppHostElement *pSites = NULL; | ||
| 1820 | IAppHostElementCollection *pCollection = NULL; | ||
| 1821 | IAppHostElement *pSiteElem = NULL; | ||
| 1822 | IAppHostElement *pElement = NULL; | ||
| 1823 | |||
| 1824 | // Get site action | ||
| 1825 | hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iAction); | ||
| 1826 | ExitOnFailure(hr, "Failed to read site action"); | ||
| 1827 | |||
| 1828 | //get site name | ||
| 1829 | hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzSiteName); | ||
| 1830 | ExitOnFailure(hr, "Failed to read site key"); | ||
| 1831 | |||
| 1832 | //Get site if it exists | ||
| 1833 | hr = GetSiteElement(pAdminMgr, pwzSiteName, &pSiteElem, &fFound); | ||
| 1834 | ExitOnFailure(hr, "Failed to read sites from config"); | ||
| 1835 | |||
| 1836 | hr = pAdminMgr->GetAdminSection(ScopeBSTR(IIS_CONFIG_SITES_SECTION), ScopeBSTR(IIS_CONFIG_APPHOST_ROOT), &pSites); | ||
| 1837 | ExitOnFailure(hr, "Failed get sites section"); | ||
| 1838 | ExitOnNull(pSites, hr, ERROR_FILE_NOT_FOUND, "Failed get sites section object"); | ||
| 1839 | |||
| 1840 | hr = pSites->get_Collection( &pCollection); | ||
| 1841 | ExitOnFailure(hr, "Failed get site collection"); | ||
| 1842 | switch (iAction) | ||
| 1843 | { | ||
| 1844 | case IIS_DELETE : | ||
| 1845 | { | ||
| 1846 | if (fFound) | ||
| 1847 | { | ||
| 1848 | hr = DeleteCollectionElement(pCollection, IIS_CONFIG_SITE, IIS_CONFIG_NAME, pwzSiteName); | ||
| 1849 | ExitOnFailure(hr, "Failed to delete website"); | ||
| 1850 | } | ||
| 1851 | ExitFunction(); | ||
| 1852 | break; | ||
| 1853 | } | ||
| 1854 | case IIS_CREATE : | ||
| 1855 | { | ||
| 1856 | if (!fFound) | ||
| 1857 | { | ||
| 1858 | //Create the site | ||
| 1859 | hr = CreateSite(pCollection, pwzSiteName, &pSiteElem); | ||
| 1860 | ExitOnFailure(hr, "Failed to create site"); | ||
| 1861 | |||
| 1862 | } | ||
| 1863 | } | ||
| 1864 | } | ||
| 1865 | // | ||
| 1866 | //Set other Site properties | ||
| 1867 | // | ||
| 1868 | //set site Id | ||
| 1869 | hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iData); | ||
| 1870 | ExitOnFailure(hr, "Failed to read site Id"); | ||
| 1871 | if (iData != MSI_NULL_INTEGER && -1 != iData) | ||
| 1872 | { | ||
| 1873 | hr = Iis7PutPropertyInteger(pSiteElem, IIS_CONFIG_SITE_ID, iData); | ||
| 1874 | ExitOnFailure(hr, "Failed set site Id data"); | ||
| 1875 | } | ||
| 1876 | //Set Site AutoStart | ||
| 1877 | hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iData); | ||
| 1878 | ExitOnFailure(hr, "Failed to read site autostart"); | ||
| 1879 | if (MSI_NULL_INTEGER != iData) | ||
| 1880 | { | ||
| 1881 | hr = Iis7PutPropertyBool(pSiteElem, IIS_CONFIG_AUTOSTART, iData); | ||
| 1882 | ExitOnFailure(hr, "Failed set site config data"); | ||
| 1883 | } | ||
| 1884 | |||
| 1885 | //Set Site Connection timeout | ||
| 1886 | hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iData); | ||
| 1887 | ExitOnFailure(hr, "Failed to read site connection tomeout data"); | ||
| 1888 | if (MSI_NULL_INTEGER != iData) | ||
| 1889 | { | ||
| 1890 | // get limits element, get connectionTimeout property | ||
| 1891 | hr = pSiteElem->GetElementByName(ScopeBSTR(IIS_CONFIG_LIMITS), &pElement); | ||
| 1892 | ExitOnFailure(hr, "Failed to read limits from config"); | ||
| 1893 | //convert iData in seconds to timeSpan hh:mm:ss | ||
| 1894 | WCHAR wcTime[60]; | ||
| 1895 | *wcTime = '\0'; | ||
| 1896 | ConvSecToHMS( iData, wcTime, countof( wcTime)); | ||
| 1897 | |||
| 1898 | hr = Iis7PutPropertyString(pElement, IIS_CONFIG_CONNECTTIMEOUT, wcTime); | ||
| 1899 | ExitOnFailure(hr, "IIS: failed set connection timeout config data"); | ||
| 1900 | } | ||
| 1901 | |||
| 1902 | LExit: | ||
| 1903 | ReleaseStr(pwzSiteName); | ||
| 1904 | ReleaseObject(pSites); | ||
| 1905 | ReleaseObject(pCollection); | ||
| 1906 | ReleaseObject(pSiteElem); | ||
| 1907 | ReleaseObject(pElement); | ||
| 1908 | |||
| 1909 | return hr; | ||
| 1910 | } | ||
| 1911 | //------------------------------------------------------------------------------------------------- | ||
| 1912 | // IIS7Application | ||
| 1913 | // Processes Application CA Data | ||
| 1914 | // | ||
| 1915 | // | ||
| 1916 | //------------------------------------------------------------------------------------------------- | ||
| 1917 | |||
| 1918 | HRESULT IIS7Application( | ||
| 1919 | __inout LPWSTR *ppwzCustomActionData, | ||
| 1920 | __in IAppHostWritableAdminManager *pAdminMgr) | ||
| 1921 | { | ||
| 1922 | HRESULT hr = S_OK; | ||
| 1923 | |||
| 1924 | int iAction = -1; | ||
| 1925 | BOOL fSiteFound = FALSE; | ||
| 1926 | BOOL fAppFound = FALSE; | ||
| 1927 | |||
| 1928 | LPWSTR pwzSiteName = NULL; | ||
| 1929 | LPWSTR pwzAppPath = NULL; | ||
| 1930 | LPWSTR pwzAppPool = NULL; | ||
| 1931 | LPWSTR pwzLocationPath = NULL; | ||
| 1932 | IAppHostElement *pSiteElem = NULL; | ||
| 1933 | IAppHostElement *pAppElement = NULL; | ||
| 1934 | // Get Application action | ||
| 1935 | hr = WcaReadIntegerFromCaData( ppwzCustomActionData, &iAction); | ||
| 1936 | ExitOnFailure(hr, "Failed to read application action") | ||
| 1937 | //get site key name | ||
| 1938 | hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzSiteName); | ||
| 1939 | ExitOnFailure(hr, "Failed to read app site key"); | ||
| 1940 | //get application path | ||
| 1941 | hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzAppPath); | ||
| 1942 | ExitOnFailure(hr, "Failed to read app path key"); | ||
| 1943 | //get application Pool | ||
| 1944 | hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzAppPool); | ||
| 1945 | ExitOnFailure(hr, "Failed to read app pool key"); | ||
| 1946 | |||
| 1947 | //Get site if it exists | ||
| 1948 | hr = GetSiteElement(pAdminMgr, pwzSiteName, &pSiteElem, &fSiteFound); | ||
| 1949 | ExitOnFailure(hr, "Failed to read sites from config"); | ||
| 1950 | |||
| 1951 | switch (iAction) | ||
| 1952 | { | ||
| 1953 | case IIS_CREATE : | ||
| 1954 | { | ||
| 1955 | if (fSiteFound) | ||
| 1956 | { | ||
| 1957 | //have site get application collection | ||
| 1958 | hr = GetApplicationElement(pSiteElem, | ||
| 1959 | pwzAppPath, | ||
| 1960 | &pAppElement, | ||
| 1961 | &fAppFound); | ||
| 1962 | ExitOnFailure(hr, "Error reading application from config"); | ||
| 1963 | |||
| 1964 | if (!fAppFound) | ||
| 1965 | { | ||
| 1966 | //Create Application | ||
| 1967 | hr = CreateApplication(pSiteElem, pwzAppPath, &pAppElement); | ||
| 1968 | ExitOnFailure(hr, "Error creating application in config"); | ||
| 1969 | } | ||
| 1970 | //Update application properties: | ||
| 1971 | // | ||
| 1972 | //Set appPool | ||
| 1973 | hr = SetAppPool(pAppElement, pwzAppPool); | ||
| 1974 | ExitOnFailure(hr, "Unable to set appPool for application"); | ||
| 1975 | } | ||
| 1976 | else | ||
| 1977 | { | ||
| 1978 | hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); | ||
| 1979 | ExitOnFailure(hr, "Site not found for create application"); | ||
| 1980 | } | ||
| 1981 | break; | ||
| 1982 | } | ||
| 1983 | case IIS_DELETE : | ||
| 1984 | { | ||
| 1985 | if (fSiteFound) | ||
| 1986 | { | ||
| 1987 | //have site get application collection | ||
| 1988 | hr = GetApplicationElement( pSiteElem, | ||
| 1989 | pwzAppPath, | ||
| 1990 | &pAppElement, | ||
| 1991 | &fAppFound); | ||
| 1992 | ExitOnFailure(hr, "Error reading application from config") | ||
| 1993 | if (fAppFound) | ||
| 1994 | { | ||
| 1995 | //delete Application | ||
| 1996 | hr = DeleteApplication(pSiteElem, pwzAppPath); | ||
| 1997 | ExitOnFailure(hr, "Error deleating application from config") | ||
| 1998 | //Construct Location path | ||
| 1999 | // TODO: it seems odd that these are just | ||
| 2000 | // jammed together, need to determine if this requires a '\' | ||
| 2001 | hr = StrAllocString(&pwzLocationPath, pwzSiteName, 0); | ||
| 2002 | ExitOnFailure(hr, "failed to copy location config path web name"); | ||
| 2003 | hr = StrAllocConcat(&pwzLocationPath, pwzAppPath, 0); | ||
| 2004 | ExitOnFailure(hr, "failed to copy location config path appPath "); | ||
| 2005 | |||
| 2006 | // and delete location tag for this application | ||
| 2007 | hr = ClearLocationTag(pAdminMgr, pwzLocationPath); | ||
| 2008 | ExitOnFailure(hr, "failed to clear location tag for %ls", pwzLocationPath); | ||
| 2009 | } | ||
| 2010 | } | ||
| 2011 | break; | ||
| 2012 | } | ||
| 2013 | default: | ||
| 2014 | ExitOnFailure(hr = E_UNEXPECTED, "Unexpected IIS Config action specified for Application"); | ||
| 2015 | break; | ||
| 2016 | } | ||
| 2017 | |||
| 2018 | LExit: | ||
| 2019 | ReleaseStr(pwzSiteName); | ||
| 2020 | ReleaseStr(pwzAppPath); | ||
| 2021 | ReleaseStr(pwzAppPool); | ||
| 2022 | ReleaseStr(pwzLocationPath); | ||
| 2023 | ReleaseObject(pSiteElem); | ||
| 2024 | ReleaseObject(pAppElement); | ||
| 2025 | |||
| 2026 | return hr; | ||
| 2027 | } | ||
| 2028 | //------------------------------------------------------------------------------------------------- | ||
| 2029 | // IIS7VDir | ||
| 2030 | // Processes VDir CA Data | ||
| 2031 | // | ||
| 2032 | // | ||
| 2033 | //------------------------------------------------------------------------------------------------- | ||
| 2034 | HRESULT IIS7VDir( | ||
| 2035 | __inout LPWSTR *ppwzCustomActionData, | ||
| 2036 | __in IAppHostWritableAdminManager *pAdminMgr) | ||
| 2037 | { | ||
| 2038 | HRESULT hr = S_OK; | ||
| 2039 | |||
| 2040 | int iAction = -1; | ||
| 2041 | BOOL fSiteFound = FALSE; | ||
| 2042 | BOOL fAppFound = FALSE; | ||
| 2043 | |||
| 2044 | LPWSTR pwzSiteName = NULL; | ||
| 2045 | LPWSTR pwzVDirPath = NULL; | ||
| 2046 | LPWSTR pwzVDirPhyDir = NULL; | ||
| 2047 | LPCWSTR pwzVDirSubPath = NULL; | ||
| 2048 | |||
| 2049 | IAppHostElement *pSiteElem = NULL; | ||
| 2050 | IAppHostElement *pAppElement = NULL; | ||
| 2051 | IAppHostElementCollection *pElement = NULL; | ||
| 2052 | |||
| 2053 | // Get Application action | ||
| 2054 | hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iAction); | ||
| 2055 | ExitOnFailure(hr, "Failed to read VDir action"); | ||
| 2056 | |||
| 2057 | //get site key name | ||
| 2058 | hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzSiteName); | ||
| 2059 | ExitOnFailure(hr, "Failed to read site key"); | ||
| 2060 | //get VDir path | ||
| 2061 | hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzVDirPath); | ||
| 2062 | ExitOnFailure(hr, "Failed to read VDir key"); | ||
| 2063 | //get physical dir path | ||
| 2064 | hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzVDirPhyDir); | ||
| 2065 | ExitOnFailure(hr, "Failed to read VDirPath key"); | ||
| 2066 | |||
| 2067 | //Get site if it exists | ||
| 2068 | hr = GetSiteElement(pAdminMgr, pwzSiteName, &pSiteElem, &fSiteFound); | ||
| 2069 | ExitOnFailure(hr, "Failed to read sites from config"); | ||
| 2070 | |||
| 2071 | if (IIS_CREATE == iAction) | ||
| 2072 | { | ||
| 2073 | if (fSiteFound) | ||
| 2074 | { | ||
| 2075 | //have site get application | ||
| 2076 | hr = GetApplicationElementForVDir( pSiteElem, | ||
| 2077 | pwzVDirPath, | ||
| 2078 | &pAppElement, | ||
| 2079 | &pwzVDirSubPath, | ||
| 2080 | &fAppFound); | ||
| 2081 | ExitOnFailure(hr, "Error reading application element from config"); | ||
| 2082 | |||
| 2083 | if (!fAppFound) | ||
| 2084 | { | ||
| 2085 | // need application to add vDir | ||
| 2086 | hr = E_FILENOTFOUND; | ||
| 2087 | ExitOnFailure(hr, "Error application not found for create VDir"); | ||
| 2088 | } | ||
| 2089 | // | ||
| 2090 | // create the virDir | ||
| 2091 | // | ||
| 2092 | hr = CreateVdir(pAppElement, pwzVDirSubPath, pwzVDirPhyDir); | ||
| 2093 | ExitOnFailure(hr, "Failed to create vdir for application"); | ||
| 2094 | } | ||
| 2095 | else | ||
| 2096 | { | ||
| 2097 | hr = E_FILENOTFOUND; | ||
| 2098 | ExitOnFailure(hr, "IIS: site not found for create VDir"); | ||
| 2099 | } | ||
| 2100 | } | ||
| 2101 | else if (IIS_DELETE == iAction) | ||
| 2102 | { | ||
| 2103 | if (fSiteFound) | ||
| 2104 | { | ||
| 2105 | //have site get application | ||
| 2106 | hr = GetApplicationElementForVDir( pSiteElem, | ||
| 2107 | pwzVDirPath, | ||
| 2108 | &pAppElement, | ||
| 2109 | &pwzVDirSubPath, | ||
| 2110 | &fAppFound); | ||
| 2111 | ExitOnFailure(hr, "Error reading application from config") | ||
| 2112 | if (fAppFound) | ||
| 2113 | { | ||
| 2114 | //delete vdir | ||
| 2115 | hr = DeleteVdir(pAppElement, pwzVDirSubPath); | ||
| 2116 | ExitOnFailure(hr, "Unable to delete vdir for application"); | ||
| 2117 | } | ||
| 2118 | } | ||
| 2119 | } | ||
| 2120 | |||
| 2121 | LExit: | ||
| 2122 | ReleaseStr(pwzSiteName); | ||
| 2123 | ReleaseStr(pwzVDirPath); | ||
| 2124 | ReleaseStr(pwzVDirPhyDir); | ||
| 2125 | ReleaseObject(pSiteElem); | ||
| 2126 | ReleaseObject(pAppElement); | ||
| 2127 | ReleaseObject(pElement); | ||
| 2128 | |||
| 2129 | return hr; | ||
| 2130 | } | ||
| 2131 | |||
| 2132 | //------------------------------------------------------------------------------------------------- | ||
| 2133 | // IIS7Binding | ||
| 2134 | // Processes Bindings CA Data | ||
| 2135 | // | ||
| 2136 | // | ||
| 2137 | //------------------------------------------------------------------------------------------------- | ||
| 2138 | HRESULT IIS7Binding( | ||
| 2139 | __inout LPWSTR *ppwzCustomActionData, | ||
| 2140 | __in IAppHostWritableAdminManager *pAdminMgr) | ||
| 2141 | { | ||
| 2142 | HRESULT hr = S_OK; | ||
| 2143 | |||
| 2144 | int iAction = -1; | ||
| 2145 | BOOL fSiteFound = FALSE; | ||
| 2146 | |||
| 2147 | LPWSTR pwzSiteName = NULL; | ||
| 2148 | LPWSTR pwzProtocol = NULL; | ||
| 2149 | LPWSTR pwzInfo = NULL; | ||
| 2150 | |||
| 2151 | IAppHostElement *pSiteElem = NULL; | ||
| 2152 | |||
| 2153 | // Get Application action | ||
| 2154 | hr = WcaReadIntegerFromCaData( ppwzCustomActionData, &iAction); | ||
| 2155 | ExitOnFailure(hr, "Failed to read binding action"); | ||
| 2156 | |||
| 2157 | //get site key name | ||
| 2158 | hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzSiteName); | ||
| 2159 | ExitOnFailure(hr, "Failed to read binding site name key"); | ||
| 2160 | |||
| 2161 | //get binding protocol | ||
| 2162 | hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzProtocol); | ||
| 2163 | ExitOnFailure(hr, "Failed to read binding protocol"); | ||
| 2164 | |||
| 2165 | //get binding info | ||
| 2166 | hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzInfo); | ||
| 2167 | ExitOnFailure(hr, "Failed to read binding info"); | ||
| 2168 | |||
| 2169 | //Get site if it exists | ||
| 2170 | hr = GetSiteElement(pAdminMgr, pwzSiteName, &pSiteElem, &fSiteFound); | ||
| 2171 | ExitOnFailure(hr, "Failed to read sites from config"); | ||
| 2172 | |||
| 2173 | if (IIS_CREATE == iAction) | ||
| 2174 | { | ||
| 2175 | if (fSiteFound) | ||
| 2176 | { | ||
| 2177 | //add binding | ||
| 2178 | hr = CreateBinding(pSiteElem, pwzProtocol, pwzInfo); | ||
| 2179 | ExitOnFailure(hr, "Failed to create site binding"); | ||
| 2180 | } | ||
| 2181 | else | ||
| 2182 | { | ||
| 2183 | hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); | ||
| 2184 | ExitOnFailure(hr, "Site not found for create binding"); | ||
| 2185 | } | ||
| 2186 | } | ||
| 2187 | else if (IIS_DELETE == iAction) | ||
| 2188 | { | ||
| 2189 | if (fSiteFound) | ||
| 2190 | { | ||
| 2191 | //delete binding | ||
| 2192 | hr = DeleteBinding(pSiteElem, pwzProtocol, pwzInfo); | ||
| 2193 | ExitOnFailure(hr, "Failed to delete binding"); | ||
| 2194 | } | ||
| 2195 | } | ||
| 2196 | |||
| 2197 | LExit: | ||
| 2198 | ReleaseStr(pwzSiteName); | ||
| 2199 | ReleaseStr(pwzProtocol); | ||
| 2200 | ReleaseStr(pwzInfo); | ||
| 2201 | ReleaseObject(pSiteElem); | ||
| 2202 | |||
| 2203 | return hr; | ||
| 2204 | } | ||
| 2205 | //------------------------------------------------------------------------------------------------- | ||
| 2206 | // IIS7Binding | ||
| 2207 | // Processes WebLog CA Data | ||
| 2208 | // | ||
| 2209 | // | ||
| 2210 | //------------------------------------------------------------------------------------------------- | ||
| 2211 | HRESULT IIS7WebLog( | ||
| 2212 | __inout LPWSTR *ppwzCustomActionData, | ||
| 2213 | __in IAppHostWritableAdminManager *pAdminMgr) | ||
| 2214 | { | ||
| 2215 | HRESULT hr = S_OK; | ||
| 2216 | |||
| 2217 | BOOL fSiteFound = FALSE; | ||
| 2218 | |||
| 2219 | LPWSTR pwzSiteName = NULL; | ||
| 2220 | LPWSTR pwzLogFormat = NULL; | ||
| 2221 | |||
| 2222 | IAppHostElement *pSiteElem = NULL; | ||
| 2223 | |||
| 2224 | //get site key name | ||
| 2225 | hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzSiteName); | ||
| 2226 | ExitOnFailure(hr, "Failed to read web log site name key"); | ||
| 2227 | |||
| 2228 | //get log format | ||
| 2229 | hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzLogFormat); | ||
| 2230 | ExitOnFailure(hr, "Failed to read web log protocol"); | ||
| 2231 | |||
| 2232 | //Get site if it exists | ||
| 2233 | hr = GetSiteElement(pAdminMgr, pwzSiteName, &pSiteElem, &fSiteFound); | ||
| 2234 | ExitOnFailure(hr, "Failed to read web log sites from config"); | ||
| 2235 | |||
| 2236 | if (fSiteFound) | ||
| 2237 | { | ||
| 2238 | //add log format | ||
| 2239 | hr = CreateWebLog(pSiteElem, pwzLogFormat); | ||
| 2240 | ExitOnFailure(hr, "Failed to create weblog file format"); | ||
| 2241 | } | ||
| 2242 | else | ||
| 2243 | { | ||
| 2244 | hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); | ||
| 2245 | ExitOnFailure(hr, "Site not found for create weblog file format"); | ||
| 2246 | } | ||
| 2247 | |||
| 2248 | LExit: | ||
| 2249 | ReleaseStr(pwzSiteName); | ||
| 2250 | ReleaseStr(pwzLogFormat); | ||
| 2251 | ReleaseObject(pSiteElem); | ||
| 2252 | |||
| 2253 | return hr; | ||
| 2254 | } | ||
| 2255 | //------------------------------------------------------------------------------------------------- | ||
| 2256 | // IIS7AppPool | ||
| 2257 | // Processes AppPool CA Data | ||
| 2258 | // | ||
| 2259 | // | ||
| 2260 | //------------------------------------------------------------------------------------------------- | ||
| 2261 | HRESULT IIS7AppPool( | ||
| 2262 | __inout LPWSTR *ppwzCustomActionData, | ||
| 2263 | __in IAppHostWritableAdminManager *pAdminMgr | ||
| 2264 | ) | ||
| 2265 | { | ||
| 2266 | HRESULT hr = S_OK; | ||
| 2267 | |||
| 2268 | int iAction = -1; | ||
| 2269 | |||
| 2270 | LPWSTR pwzAppPoolName = NULL; | ||
| 2271 | |||
| 2272 | // Get AppPool action | ||
| 2273 | hr = WcaReadIntegerFromCaData( ppwzCustomActionData, &iAction); | ||
| 2274 | ExitOnFailure(hr, "Failed to read AppPool action"); | ||
| 2275 | |||
| 2276 | //get appPool name | ||
| 2277 | hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzAppPoolName); | ||
| 2278 | ExitOnFailure(hr, "Failed to read AppPool name key"); | ||
| 2279 | |||
| 2280 | switch (iAction) | ||
| 2281 | { | ||
| 2282 | case IIS_CREATE : | ||
| 2283 | { | ||
| 2284 | hr = CreateAppPool(ppwzCustomActionData, pAdminMgr, pwzAppPoolName); | ||
| 2285 | break; | ||
| 2286 | } | ||
| 2287 | case IIS_DELETE: | ||
| 2288 | { | ||
| 2289 | hr = DeleteAppPool(pAdminMgr, pwzAppPoolName); | ||
| 2290 | break; | ||
| 2291 | } | ||
| 2292 | default: | ||
| 2293 | ExitOnFailure(hr = E_UNEXPECTED, "Unexpected IIS Config action specified for appPool"); | ||
| 2294 | break; | ||
| 2295 | } | ||
| 2296 | |||
| 2297 | LExit: | ||
| 2298 | ReleaseStr(pwzAppPoolName); | ||
| 2299 | return hr; | ||
| 2300 | } | ||
| 2301 | |||
| 2302 | //------------------------------------------------------------------------------------------------- | ||
| 2303 | // IIS7AppExtension | ||
| 2304 | // Processes AppExtension (config handlers) CA Data | ||
| 2305 | // | ||
| 2306 | // | ||
| 2307 | //------------------------------------------------------------------------------------------------- | ||
| 2308 | HRESULT IIS7AppExtension( | ||
| 2309 | __inout LPWSTR *ppwzCustomActionData, | ||
| 2310 | __in IAppHostWritableAdminManager *pAdminMgr) | ||
| 2311 | { | ||
| 2312 | HRESULT hr = S_OK; | ||
| 2313 | |||
| 2314 | LPWSTR pwzWebName = NULL; | ||
| 2315 | LPWSTR pwzWebRoot = NULL; | ||
| 2316 | LPWSTR pwzData = NULL; | ||
| 2317 | LPWSTR pwzConfigPath = NULL; | ||
| 2318 | LPWSTR pwzHandlerName = NULL; | ||
| 2319 | LPWSTR pwzPath = NULL; | ||
| 2320 | int iAction = -1; | ||
| 2321 | |||
| 2322 | IAppHostElement *pSection = NULL; | ||
| 2323 | IAppHostElement *pElement = NULL; | ||
| 2324 | IAppHostElementCollection *pCollection = NULL; | ||
| 2325 | |||
| 2326 | BOOL fFound = FALSE; | ||
| 2327 | DWORD cHandlers = 1000; | ||
| 2328 | |||
| 2329 | //get web name | ||
| 2330 | hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzWebName); | ||
| 2331 | ExitOnFailure(hr, "Failed to read appExt Web name key"); | ||
| 2332 | |||
| 2333 | //get root name | ||
| 2334 | hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzWebRoot); | ||
| 2335 | ExitOnFailure(hr, "Failed to read appExt Web name key"); | ||
| 2336 | |||
| 2337 | //Construct config root | ||
| 2338 | hr = StrAllocFormatted(&pwzConfigPath, L"%s/%s", IIS_CONFIG_APPHOST_ROOT, pwzWebName); | ||
| 2339 | ExitOnFailure(hr, "failed to format appext config path"); | ||
| 2340 | // | ||
| 2341 | //Do not append trailing '/' for default vDir | ||
| 2342 | // | ||
| 2343 | if (CSTR_EQUAL != ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, pwzWebRoot, -1, L"/", -1)) | ||
| 2344 | { | ||
| 2345 | hr = StrAllocConcat(&pwzConfigPath, L"/", 0); | ||
| 2346 | ExitOnFailure(hr, "failed to copy appext config path delim"); | ||
| 2347 | hr = StrAllocConcat(&pwzConfigPath, pwzWebRoot, 0); | ||
| 2348 | ExitOnFailure(hr, "failed to copy appext config path root name"); | ||
| 2349 | } | ||
| 2350 | //get admin handlers section at config path location tag | ||
| 2351 | hr = pAdminMgr->GetAdminSection(ScopeBSTR(IIS_CONFIG_HANDLERS_SECTION), pwzConfigPath, &pSection); | ||
| 2352 | ExitOnFailure(hr, "Failed get appext section"); | ||
| 2353 | |||
| 2354 | if (!pSection) | ||
| 2355 | { | ||
| 2356 | hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); | ||
| 2357 | ExitOnFailure(hr, "Failed get appext section object"); | ||
| 2358 | } | ||
| 2359 | |||
| 2360 | // Get AppExt action | ||
| 2361 | hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iAction); | ||
| 2362 | ExitOnFailure(hr, "Failed to read appExt action"); | ||
| 2363 | |||
| 2364 | hr = pSection->get_Collection(&pCollection); | ||
| 2365 | ExitOnFailure(hr, "Failed get handlers collection for appext"); | ||
| 2366 | |||
| 2367 | while (IIS_APPEXT_END != iAction) | ||
| 2368 | { | ||
| 2369 | fFound = FALSE; | ||
| 2370 | |||
| 2371 | //Process property action | ||
| 2372 | switch (iAction) | ||
| 2373 | { | ||
| 2374 | case IIS_APPEXT : | ||
| 2375 | { | ||
| 2376 | // These IDs aren't really stable but this is stable enough to support repair since the MSI won't change | ||
| 2377 | hr = StrAllocFormatted(&pwzHandlerName, L"MsiCustom-%u", ++cHandlers); | ||
| 2378 | ExitOnFailure(hr, "Failed increment handler name"); | ||
| 2379 | |||
| 2380 | hr = Iis7FindAppHostElementString(pCollection, IIS_CONFIG_ADD, IIS_CONFIG_NAME, pwzHandlerName, &pElement, NULL); | ||
| 2381 | ExitOnFailure(hr, "Failed to find mimemap extension"); | ||
| 2382 | |||
| 2383 | fFound = (NULL != pElement); | ||
| 2384 | if (!fFound) | ||
| 2385 | { | ||
| 2386 | //create new handler element | ||
| 2387 | hr = pCollection->CreateNewElement(ScopeBSTR(IIS_CONFIG_ADD), &pElement); | ||
| 2388 | ExitOnFailure(hr, "Failed get create handler element for appext"); | ||
| 2389 | |||
| 2390 | hr = Iis7PutPropertyString(pElement, IIS_CONFIG_NAME, pwzHandlerName); | ||
| 2391 | ExitOnFailure(hr, "Failed set appext name property"); | ||
| 2392 | } | ||
| 2393 | |||
| 2394 | //BUGBUG: For compat we are assuming these are all ISAPI MODULES so we are | ||
| 2395 | //setting the modules property to IsapiModule. | ||
| 2396 | //Currently can't deal with handlers of different module types. | ||
| 2397 | hr = Iis7PutPropertyString(pElement, IIS_CONFIG_MODULES, L"IsapiModule"); | ||
| 2398 | ExitOnFailure(hr, "Failed set site appExt path property"); | ||
| 2399 | |||
| 2400 | //get extension (path) | ||
| 2401 | hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzData); | ||
| 2402 | ExitOnFailure(hr, "Failed to read appExt extension"); | ||
| 2403 | hr = StrAllocFormatted(&pwzPath, L"*.%s", pwzData); | ||
| 2404 | ExitOnFailure(hr, "Failed decorate appExt path"); | ||
| 2405 | //put property | ||
| 2406 | hr = Iis7PutPropertyString(pElement, IIS_CONFIG_PATH, pwzPath); | ||
| 2407 | ExitOnFailure(hr, "Failed set site appExt path property"); | ||
| 2408 | |||
| 2409 | //get executable | ||
| 2410 | hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzData); | ||
| 2411 | ExitOnFailure(hr, "Failed to read appExt executable"); | ||
| 2412 | //put property | ||
| 2413 | hr = Iis7PutPropertyString(pElement, IIS_CONFIG_EXECUTABLE, pwzData); | ||
| 2414 | ExitOnFailure(hr, "Failed set site appExt executable property"); | ||
| 2415 | |||
| 2416 | //get verbs | ||
| 2417 | hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzData); | ||
| 2418 | ExitOnFailure(hr, "Failed to read appExt verbs"); | ||
| 2419 | //put property | ||
| 2420 | hr = Iis7PutPropertyString(pElement, IIS_CONFIG_VERBS, pwzData); | ||
| 2421 | ExitOnFailure(hr, "Failed set site appExt verbs property"); | ||
| 2422 | |||
| 2423 | break; | ||
| 2424 | } | ||
| 2425 | default: | ||
| 2426 | { | ||
| 2427 | ExitOnFailure(hr = E_UNEXPECTED, "Unexpected IIS Config action specified for AppExt"); | ||
| 2428 | break; | ||
| 2429 | } | ||
| 2430 | } | ||
| 2431 | |||
| 2432 | if (!fFound) | ||
| 2433 | { | ||
| 2434 | // put handler element at beginning of list | ||
| 2435 | hr = pCollection->AddElement(pElement, 0); | ||
| 2436 | ExitOnFailure(hr, "Failed add handler element for appext"); | ||
| 2437 | } | ||
| 2438 | |||
| 2439 | ReleaseNullObject(pElement); | ||
| 2440 | |||
| 2441 | // Get AppExt action | ||
| 2442 | hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iAction); | ||
| 2443 | ExitOnFailure(hr, "Failed to read AppPool Property action"); | ||
| 2444 | } | ||
| 2445 | |||
| 2446 | LExit: | ||
| 2447 | ReleaseStr(pwzWebName); | ||
| 2448 | ReleaseStr(pwzWebRoot); | ||
| 2449 | ReleaseStr(pwzData); | ||
| 2450 | ReleaseStr(pwzConfigPath); | ||
| 2451 | ReleaseStr(pwzHandlerName); | ||
| 2452 | ReleaseStr(pwzPath); | ||
| 2453 | ReleaseObject(pSection); | ||
| 2454 | ReleaseObject(pElement); | ||
| 2455 | ReleaseObject(pCollection); | ||
| 2456 | |||
| 2457 | return hr; | ||
| 2458 | } | ||
| 2459 | |||
| 2460 | //------------------------------------------------------------------------------------------------- | ||
| 2461 | // IIS7MimeMap | ||
| 2462 | // Processes Mime Map (config handlers) CA Data | ||
| 2463 | // | ||
| 2464 | // | ||
| 2465 | //------------------------------------------------------------------------------------------------- | ||
| 2466 | HRESULT IIS7MimeMap( | ||
| 2467 | __inout LPWSTR *ppwzCustomActionData, | ||
| 2468 | __in IAppHostWritableAdminManager *pAdminMgr | ||
| 2469 | ) | ||
| 2470 | { | ||
| 2471 | HRESULT hr = S_OK; | ||
| 2472 | LPWSTR pwzConfigPath = NULL; | ||
| 2473 | LPWSTR pwzWebName = NULL; | ||
| 2474 | LPWSTR pwzWebRoot = NULL; | ||
| 2475 | LPWSTR pwzData = NULL; | ||
| 2476 | int iAction = -1; | ||
| 2477 | |||
| 2478 | IAppHostElement *pSection = NULL; | ||
| 2479 | IAppHostElement *pElement = NULL; | ||
| 2480 | IAppHostElementCollection *pCollection = NULL; | ||
| 2481 | |||
| 2482 | BOOL fFound = FALSE; | ||
| 2483 | |||
| 2484 | //get web name | ||
| 2485 | hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzWebName); | ||
| 2486 | ExitOnFailure(hr, "Failed to read mime map Web name key"); | ||
| 2487 | |||
| 2488 | //get vdir root name | ||
| 2489 | hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzWebRoot); | ||
| 2490 | ExitOnFailure(hr, "Failed to read vdir root name key"); | ||
| 2491 | |||
| 2492 | //Construct config root | ||
| 2493 | hr = StrAllocFormatted(&pwzConfigPath, L"%s/%s", IIS_CONFIG_APPHOST_ROOT, pwzWebName); | ||
| 2494 | ExitOnFailure(hr, "failed to format mime map config path web name"); | ||
| 2495 | // | ||
| 2496 | //Do not append trailing '/' for default vDir | ||
| 2497 | // | ||
| 2498 | if (CSTR_EQUAL != ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, pwzWebRoot, -1, L"/", -1)) | ||
| 2499 | { | ||
| 2500 | hr = StrAllocConcat(&pwzConfigPath, L"/", 0); | ||
| 2501 | ExitOnFailure(hr, "failed to copy appext config path delim"); | ||
| 2502 | hr = StrAllocConcat(&pwzConfigPath, pwzWebRoot, 0); | ||
| 2503 | ExitOnFailure(hr, "failed to copy appext config path root name"); | ||
| 2504 | } | ||
| 2505 | |||
| 2506 | //get admin section <staticContent> at config path location tag | ||
| 2507 | hr = pAdminMgr->GetAdminSection(ScopeBSTR(IIS_CONFIG_STATICCONTENT_SECTION), pwzConfigPath, &pSection); | ||
| 2508 | ExitOnFailure(hr, "Failed get staticContent section for mimemap"); | ||
| 2509 | |||
| 2510 | if (!pSection) | ||
| 2511 | { | ||
| 2512 | hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); | ||
| 2513 | ExitOnFailure(hr, "Failed get staticContent section object"); | ||
| 2514 | } | ||
| 2515 | |||
| 2516 | // Get mimemap action | ||
| 2517 | hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iAction); | ||
| 2518 | ExitOnFailure(hr, "Failed to read mimemap action"); | ||
| 2519 | |||
| 2520 | hr = pSection->get_Collection(&pCollection); | ||
| 2521 | ExitOnFailure(hr, "Failed get staticContent collection for mimemap"); | ||
| 2522 | |||
| 2523 | while (IIS_MIMEMAP_END != iAction) | ||
| 2524 | { | ||
| 2525 | //Process property action | ||
| 2526 | switch (iAction) | ||
| 2527 | { | ||
| 2528 | case IIS_MIMEMAP : | ||
| 2529 | { | ||
| 2530 | //get extension | ||
| 2531 | hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzData); | ||
| 2532 | ExitOnFailure(hr, "Failed to read mimemap extension"); | ||
| 2533 | |||
| 2534 | hr = Iis7FindAppHostElementString(pCollection, IIS_CONFIG_MIMEMAP, IIS_CONFIG_FILEEXT, pwzData, &pElement, NULL); | ||
| 2535 | ExitOnFailure(hr, "Failed to find mimemap extension"); | ||
| 2536 | fFound = (NULL != pElement); | ||
| 2537 | |||
| 2538 | if (!fFound) | ||
| 2539 | { | ||
| 2540 | //create new mimeMap element | ||
| 2541 | hr = pCollection->CreateNewElement(ScopeBSTR(IIS_CONFIG_MIMEMAP), &pElement); | ||
| 2542 | ExitOnFailure(hr, "Failed get create MimeMap element"); | ||
| 2543 | } | ||
| 2544 | |||
| 2545 | //put property | ||
| 2546 | hr = Iis7PutPropertyString(pElement, IIS_CONFIG_FILEEXT, pwzData); | ||
| 2547 | ExitOnFailure(hr, "Failed set mimemap extension property"); | ||
| 2548 | |||
| 2549 | //get type | ||
| 2550 | hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzData); | ||
| 2551 | ExitOnFailure(hr, "Failed to read mimemap type"); | ||
| 2552 | //put property | ||
| 2553 | hr = Iis7PutPropertyString(pElement, IIS_CONFIG_MIMETYPE, pwzData); | ||
| 2554 | ExitOnFailure(hr, "Failed set mimemap type property"); | ||
| 2555 | |||
| 2556 | break; | ||
| 2557 | } | ||
| 2558 | default: | ||
| 2559 | { | ||
| 2560 | ExitOnFailure(hr = E_UNEXPECTED, "Unexpected IIS Config action specified for mimeMap"); | ||
| 2561 | break; | ||
| 2562 | } | ||
| 2563 | } | ||
| 2564 | |||
| 2565 | if (!fFound) | ||
| 2566 | { | ||
| 2567 | // put mimeMap element at beginning of list | ||
| 2568 | hr = pCollection->AddElement(pElement, -1); | ||
| 2569 | ExitOnFailure(hr, "Failed add mimemap"); | ||
| 2570 | } | ||
| 2571 | |||
| 2572 | // Get AppExt action | ||
| 2573 | hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iAction); | ||
| 2574 | ExitOnFailure(hr, "Failed to read mimemap action"); | ||
| 2575 | |||
| 2576 | ReleaseNullObject(pElement); | ||
| 2577 | } | ||
| 2578 | |||
| 2579 | LExit: | ||
| 2580 | ReleaseStr(pwzConfigPath); | ||
| 2581 | ReleaseStr(pwzWebName); | ||
| 2582 | ReleaseStr(pwzWebRoot); | ||
| 2583 | ReleaseStr(pwzData); | ||
| 2584 | ReleaseObject(pSection); | ||
| 2585 | ReleaseObject(pElement); | ||
| 2586 | ReleaseObject(pCollection); | ||
| 2587 | |||
| 2588 | return hr; | ||
| 2589 | } | ||
| 2590 | |||
| 2591 | //------------------------------------------------------------------------------------------------- | ||
| 2592 | // IIS7DirProperties | ||
| 2593 | // ProcessesVdir Properties CA Data | ||
| 2594 | // | ||
| 2595 | // | ||
| 2596 | //------------------------------------------------------------------------------------------------- | ||
| 2597 | HRESULT IIS7DirProperties( | ||
| 2598 | __inout LPWSTR *ppwzCustomActionData, | ||
| 2599 | __in IAppHostWritableAdminManager *pAdminMgr | ||
| 2600 | ) | ||
| 2601 | { | ||
| 2602 | HRESULT hr = S_OK; | ||
| 2603 | WCHAR wcTime[60]; | ||
| 2604 | LPWSTR pwzConfigPath = NULL; | ||
| 2605 | LPWSTR pwzWebName = NULL; | ||
| 2606 | LPWSTR pwzWebRoot = NULL; | ||
| 2607 | LPWSTR pwzData = NULL; | ||
| 2608 | int iAction = -1; | ||
| 2609 | int iData = 0; | ||
| 2610 | DWORD dwData = 0; | ||
| 2611 | |||
| 2612 | IAppHostElement *pSection = NULL; | ||
| 2613 | IAppHostElement *pElement = NULL; | ||
| 2614 | IAppHostElementCollection *pCollection = NULL; | ||
| 2615 | |||
| 2616 | //get web name | ||
| 2617 | hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzWebName); | ||
| 2618 | ExitOnFailure(hr, "Failed to read DirProp Web name key"); | ||
| 2619 | |||
| 2620 | //get vdir root name | ||
| 2621 | hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzWebRoot); | ||
| 2622 | ExitOnFailure(hr, "Failed to read DirProp Web name key"); | ||
| 2623 | |||
| 2624 | //Construct config root | ||
| 2625 | hr = StrAllocFormatted(&pwzConfigPath, L"%s/%s", IIS_CONFIG_APPHOST_ROOT, pwzWebName); | ||
| 2626 | ExitOnFailure(hr, "failed to format mime map config path web name"); | ||
| 2627 | // | ||
| 2628 | //Do not append trailing '/' for default vDir | ||
| 2629 | // | ||
| 2630 | if (CSTR_EQUAL != ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, pwzWebRoot, -1, L"/", -1)) | ||
| 2631 | { | ||
| 2632 | hr = StrAllocConcat(&pwzConfigPath, L"/", 0); | ||
| 2633 | ExitOnFailure(hr, "failed to copy appext config path delim"); | ||
| 2634 | hr = StrAllocConcat(&pwzConfigPath, pwzWebRoot, 0); | ||
| 2635 | ExitOnFailure(hr, "failed to copy appext config path root name"); | ||
| 2636 | } | ||
| 2637 | |||
| 2638 | // Get DirProps action | ||
| 2639 | hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iAction); | ||
| 2640 | ExitOnFailure(hr, "Failed to read DirProps action"); | ||
| 2641 | |||
| 2642 | while (IIS_DIRPROP_END != iAction) | ||
| 2643 | { | ||
| 2644 | //Process property action | ||
| 2645 | switch (iAction) | ||
| 2646 | { | ||
| 2647 | case IIS_DIRPROP_ACCESS : | ||
| 2648 | { | ||
| 2649 | hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iData); | ||
| 2650 | ExitOnFailure(hr, "Failed to read DirProps access"); | ||
| 2651 | //iData contains bit flags for <handlers accessPolicy=""> | ||
| 2652 | //no translation required | ||
| 2653 | //get admin section at config path location tag | ||
| 2654 | hr = pAdminMgr->GetAdminSection(ScopeBSTR(IIS_CONFIG_HANDLERS_SECTION), pwzConfigPath, &pSection); | ||
| 2655 | ExitOnFailure(hr, "Failed get handlers section for DirProp"); | ||
| 2656 | if (!pSection) | ||
| 2657 | { | ||
| 2658 | hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); | ||
| 2659 | ExitOnFailure(hr, "Failed get handlers section object for DirProps"); | ||
| 2660 | } | ||
| 2661 | dwData = iData; | ||
| 2662 | hr = Iis7PutPropertyInteger( pSection, L"accessPolicy", dwData); | ||
| 2663 | ExitOnFailure(hr, "Failed set accessPolicy for DirProps"); | ||
| 2664 | ReleaseNullObject(pSection); | ||
| 2665 | break; | ||
| 2666 | } | ||
| 2667 | case IIS_DIRPROP_USER : | ||
| 2668 | { | ||
| 2669 | hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzData); | ||
| 2670 | ExitOnFailure(hr, "Failed to read DirProps user"); | ||
| 2671 | hr = pAdminMgr->GetAdminSection(ScopeBSTR(L"system.webServer/security/authentication/anonymousAuthentication"), pwzConfigPath, &pSection); | ||
| 2672 | ExitOnFailure(hr, "Failed get AnonymousAuthentication section for DirProp"); | ||
| 2673 | hr = Iis7PutPropertyString( pSection, IIS_CONFIG_USERNAME, pwzData); | ||
| 2674 | ExitOnFailure(hr, "Failed set accessPolicy for DirProps"); | ||
| 2675 | ReleaseNullObject(pSection); | ||
| 2676 | break; | ||
| 2677 | } | ||
| 2678 | case IIS_DIRPROP_PWD : | ||
| 2679 | { | ||
| 2680 | hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzData); | ||
| 2681 | ExitOnFailure(hr, "Failed to read DirProps pwd"); | ||
| 2682 | hr = pAdminMgr->GetAdminSection(ScopeBSTR(L"system.webServer/security/authentication/anonymousAuthentication"), pwzConfigPath, &pSection); | ||
| 2683 | ExitOnFailure(hr, "Failed get AnonymousAuthentication section for DirProp"); | ||
| 2684 | hr = Iis7PutPropertyString( pSection, IIS_CONFIG_PASSWORD, pwzData); | ||
| 2685 | ExitOnFailure(hr, "Failed set accessPolicy for DirProps"); | ||
| 2686 | ReleaseNullObject(pSection); | ||
| 2687 | break; | ||
| 2688 | } | ||
| 2689 | case IIS_DIRPROP_DEFDOCS : | ||
| 2690 | { | ||
| 2691 | hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzData); | ||
| 2692 | ExitOnFailure(hr, "Failed to read DirProps def doc"); | ||
| 2693 | hr = SetDirPropDefDoc(pAdminMgr, pwzConfigPath, pwzData); | ||
| 2694 | ExitOnFailure(hr, "Failed to set DirProps Default Documents"); | ||
| 2695 | break; | ||
| 2696 | } | ||
| 2697 | case IIS_DIRPROP_AUTH : | ||
| 2698 | { | ||
| 2699 | hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iData); | ||
| 2700 | ExitOnFailure(hr, "Failed to read DirProps auth"); | ||
| 2701 | //iData contains bit flags for /security/authentication/<...> | ||
| 2702 | // Anonymous = 1 | ||
| 2703 | // Basic = 2 | ||
| 2704 | // Windows = 4 | ||
| 2705 | // Digest =16 | ||
| 2706 | // Passport =64 *not supported | ||
| 2707 | //translation required from bit map to section | ||
| 2708 | // E.G security/authentication/windowsAuthentication [property enabled true|false] | ||
| 2709 | dwData= iData; | ||
| 2710 | hr = SetDirPropAuthentications(pAdminMgr, pwzConfigPath, dwData); | ||
| 2711 | ExitOnFailure(hr, "Failed set Authentication for DirProps"); | ||
| 2712 | break; | ||
| 2713 | } | ||
| 2714 | case IIS_DIRPROP_SSLFLAGS : | ||
| 2715 | { | ||
| 2716 | hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iData); | ||
| 2717 | ExitOnFailure(hr, "Failed to read DirProps sslFlags"); | ||
| 2718 | //iData contains bit flags for /security/access sslFlags | ||
| 2719 | //no translation required | ||
| 2720 | hr = pAdminMgr->GetAdminSection(ScopeBSTR(L"system.webServer/security/access"), pwzConfigPath, &pSection); | ||
| 2721 | ExitOnFailure(hr, "Failed get security/access section for DirProp"); | ||
| 2722 | dwData = iData; | ||
| 2723 | hr = Iis7PutPropertyInteger( pSection, L"sslFlags", dwData); | ||
| 2724 | ExitOnFailure(hr, "Failed set security/access for DirProps"); | ||
| 2725 | ReleaseNullObject(pSection); | ||
| 2726 | break; | ||
| 2727 | } | ||
| 2728 | case IIS_DIRPROP_AUTHPROVID : | ||
| 2729 | { | ||
| 2730 | hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzData); | ||
| 2731 | ExitOnFailure(hr, "Failed to read DirProps auth provider"); | ||
| 2732 | hr = SetDirPropAuthProvider(pAdminMgr, pwzConfigPath, pwzData); | ||
| 2733 | ExitOnFailure(hr, "Failed to set DirProps auth provider"); | ||
| 2734 | break; | ||
| 2735 | } | ||
| 2736 | case IIS_DIRPROP_ASPERROR: | ||
| 2737 | { | ||
| 2738 | hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iData); | ||
| 2739 | ExitOnFailure(hr, "Failed to read DirProps aspDetailedError"); | ||
| 2740 | hr = pAdminMgr->GetAdminSection(ScopeBSTR(IIS_CONFIG_ASP_SECTION), pwzConfigPath, &pSection); | ||
| 2741 | ExitOnFailure(hr, "Failed get asp section for DirProp"); | ||
| 2742 | hr = Iis7PutPropertyBool(pSection, IIS_CONFIG_SCRIPTERROR, iData); | ||
| 2743 | ExitOnFailure(hr, "Failed to set DirProps aspDetailedError"); | ||
| 2744 | ReleaseNullObject(pSection); | ||
| 2745 | break; | ||
| 2746 | } | ||
| 2747 | case IIS_DIRPROP_HTTPEXPIRES: | ||
| 2748 | { | ||
| 2749 | hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzData); | ||
| 2750 | ExitOnFailure(hr, "Failed to read DirProps httpExpires provider"); | ||
| 2751 | hr = pAdminMgr->GetAdminSection(ScopeBSTR(IIS_CONFIG_STATICCONTENT_SECTION), pwzConfigPath, &pSection); | ||
| 2752 | ExitOnFailure(hr, "Failed get staticContent section for DirProp"); | ||
| 2753 | hr = pSection->GetElementByName(ScopeBSTR(IIS_CONFIG_CLIENTCACHE), &pElement); | ||
| 2754 | ExitOnFailure(hr, "Failed to get clientCache element"); | ||
| 2755 | hr = Iis7PutPropertyString(pElement, IIS_CONFIG_HTTPEXPIRES, pwzData); | ||
| 2756 | ExitOnFailure(hr, "Failed to set clientCache httpExpires value"); | ||
| 2757 | hr = Iis7PutPropertyString(pElement, IIS_CONFIG_CACHECONTROLMODE, IIS_CONFIG_USEEXPIRES); | ||
| 2758 | ExitOnFailure(hr, "Failed to set clientCache cacheControlMode value"); | ||
| 2759 | ReleaseNullObject(pSection); | ||
| 2760 | ReleaseNullObject(pElement); | ||
| 2761 | break; | ||
| 2762 | } | ||
| 2763 | case IIS_DIRPROP_MAXAGE: | ||
| 2764 | { | ||
| 2765 | hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iData); | ||
| 2766 | ExitOnFailure(hr, "Failed to read DirProps httpExpires provider"); | ||
| 2767 | hr = pAdminMgr->GetAdminSection(ScopeBSTR(IIS_CONFIG_STATICCONTENT_SECTION), pwzConfigPath, &pSection); | ||
| 2768 | ExitOnFailure(hr, "Failed get staticContent section for DirProp"); | ||
| 2769 | hr = pSection->GetElementByName(ScopeBSTR(IIS_CONFIG_CLIENTCACHE), &pElement); | ||
| 2770 | ExitOnFailure(hr, "Failed to get clientCache element"); | ||
| 2771 | *wcTime = '\0'; | ||
| 2772 | ConvSecToDHMS(iData, wcTime, countof(wcTime)); | ||
| 2773 | hr = Iis7PutPropertyString(pElement, IIS_CONFIG_MAXAGE, wcTime); | ||
| 2774 | ExitOnFailure(hr, "Failed to set clientCache maxAge value"); | ||
| 2775 | hr = Iis7PutPropertyString(pElement, IIS_CONFIG_CACHECONTROLMODE, IIS_CONFIG_USEMAXAGE); | ||
| 2776 | ExitOnFailure(hr, "Failed to set clientCache cacheControlMode value"); | ||
| 2777 | ReleaseNullObject(pSection); | ||
| 2778 | ReleaseNullObject(pElement); | ||
| 2779 | break; | ||
| 2780 | } | ||
| 2781 | case IIS_DIRPROP_CACHECUST: | ||
| 2782 | { | ||
| 2783 | hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzData); | ||
| 2784 | ExitOnFailure(hr, "Failed to read DirProps cacheControlCustom"); | ||
| 2785 | hr = pAdminMgr->GetAdminSection(ScopeBSTR(IIS_CONFIG_STATICCONTENT_SECTION), pwzConfigPath, &pSection); | ||
| 2786 | ExitOnFailure(hr, "Failed get staticContent section for DirProp"); | ||
| 2787 | hr = pSection->GetElementByName(ScopeBSTR(IIS_CONFIG_CLIENTCACHE), &pElement); | ||
| 2788 | ExitOnFailure(hr, "Failed to get clientCache element"); | ||
| 2789 | hr = Iis7PutPropertyString(pElement, IIS_CONFIG_CACHECUST, pwzData); | ||
| 2790 | ExitOnFailure(hr, "Failed to set clientCache cacheControlCustom value"); | ||
| 2791 | ReleaseNullObject(pSection); | ||
| 2792 | ReleaseNullObject(pElement); | ||
| 2793 | break; | ||
| 2794 | } | ||
| 2795 | case IIS_DIRPROP_NOCUSTERROR: | ||
| 2796 | { | ||
| 2797 | //no value, if have ID tag write clear to system.webServer/httpErrors | ||
| 2798 | //error collection | ||
| 2799 | hr = pAdminMgr->GetAdminSection(ScopeBSTR(IIS_CONFIG_HTTPERRORS_SECTION), pwzConfigPath, &pSection); | ||
| 2800 | ExitOnFailure(hr, "Failed get httperrors section for DirProp"); | ||
| 2801 | hr = pSection->get_Collection(&pCollection); | ||
| 2802 | ExitOnFailure(hr, "Failed get error collection for DirProp"); | ||
| 2803 | hr = pCollection->CreateNewElement(ScopeBSTR(IIS_CONFIG_CLEAR), &pElement); | ||
| 2804 | ExitOnFailure(hr, "Failed to create clear element for error collection for DirProp"); | ||
| 2805 | hr = pCollection->AddElement(pElement); | ||
| 2806 | ExitOnFailure(hr, "Failed to add lear element for error collection for DirProp"); | ||
| 2807 | ReleaseNullObject(pSection); | ||
| 2808 | ReleaseNullObject(pElement); | ||
| 2809 | break; | ||
| 2810 | } | ||
| 2811 | case IIS_DIRPROP_LOGVISITS: | ||
| 2812 | { | ||
| 2813 | hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iData); | ||
| 2814 | ExitOnFailure(hr, "Failed to read DirProps logVisits"); | ||
| 2815 | hr = pAdminMgr->GetAdminSection(ScopeBSTR(IIS_CONFIG_HTTPLOGGING_SECTION), pwzConfigPath, &pSection); | ||
| 2816 | ExitOnFailure(hr, "Failed get httpLogging section for DirProp"); | ||
| 2817 | hr = Iis7PutPropertyBool(pSection, IIS_CONFIG_DONTLOG, iData); | ||
| 2818 | ExitOnFailure(hr, "Failed to set DirProps aspDetailedError"); | ||
| 2819 | ReleaseNullObject(pSection); | ||
| 2820 | break; | ||
| 2821 | } | ||
| 2822 | default: | ||
| 2823 | { | ||
| 2824 | ExitOnFailure(hr = E_UNEXPECTED, "Unexpected IIS Config action specified for WebDirProperties"); | ||
| 2825 | break; | ||
| 2826 | } | ||
| 2827 | } | ||
| 2828 | |||
| 2829 | // Get AppExt action | ||
| 2830 | hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iAction); | ||
| 2831 | ExitOnFailure(hr, "Failed to read DirProps Property action"); | ||
| 2832 | } | ||
| 2833 | LExit: | ||
| 2834 | ReleaseStr(pwzConfigPath); | ||
| 2835 | ReleaseStr(pwzWebName); | ||
| 2836 | ReleaseStr(pwzWebRoot); | ||
| 2837 | ReleaseStr(pwzData); | ||
| 2838 | ReleaseObject(pSection); | ||
| 2839 | ReleaseObject(pElement); | ||
| 2840 | ReleaseObject(pCollection); | ||
| 2841 | |||
| 2842 | return hr; | ||
| 2843 | } | ||
| 2844 | |||
| 2845 | //------------------------------------------------------------------------------------------------- | ||
| 2846 | // IIS7SslBinding | ||
| 2847 | // ProcessesVdir Properties CA Data | ||
| 2848 | // | ||
| 2849 | // | ||
| 2850 | //------------------------------------------------------------------------------------------------- | ||
| 2851 | HRESULT IIS7SslBinding( | ||
| 2852 | __inout LPWSTR *ppwzCustomActionData, | ||
| 2853 | __in IAppHostWritableAdminManager *pAdminMgr | ||
| 2854 | ) | ||
| 2855 | { | ||
| 2856 | HRESULT hr = S_OK; | ||
| 2857 | int iAction = -1; | ||
| 2858 | BOOL fSiteFound = FALSE; | ||
| 2859 | |||
| 2860 | LPWSTR pwzSiteName = NULL; | ||
| 2861 | LPWSTR pwzStoreName = NULL; | ||
| 2862 | LPWSTR pwzEncodedCertificateHash = NULL; | ||
| 2863 | |||
| 2864 | IAppHostElement *pSiteElem = NULL; | ||
| 2865 | |||
| 2866 | // Get Application action | ||
| 2867 | hr = WcaReadIntegerFromCaData( ppwzCustomActionData, &iAction); | ||
| 2868 | ExitOnFailure(hr, "Failed to read binding action"); | ||
| 2869 | |||
| 2870 | //get site key name | ||
| 2871 | hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzSiteName); | ||
| 2872 | ExitOnFailure(hr, "Failed to read binding site name key"); | ||
| 2873 | |||
| 2874 | //get binding protocol | ||
| 2875 | hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzStoreName); | ||
| 2876 | ExitOnFailure(hr, "Failed to read binding protocol"); | ||
| 2877 | |||
| 2878 | //get binding info | ||
| 2879 | hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzEncodedCertificateHash); | ||
| 2880 | ExitOnFailure(hr, "Failed to read binding info"); | ||
| 2881 | |||
| 2882 | //Get site if it exists | ||
| 2883 | hr = GetSiteElement(pAdminMgr, pwzSiteName, &pSiteElem, &fSiteFound); | ||
| 2884 | ExitOnFailure(hr, "Failed to read sites from config"); | ||
| 2885 | |||
| 2886 | if (IIS_CREATE == iAction) | ||
| 2887 | { | ||
| 2888 | if (fSiteFound) | ||
| 2889 | { | ||
| 2890 | //add SSL cert to binding | ||
| 2891 | hr = CreateSslBinding(pSiteElem, pwzStoreName, pwzEncodedCertificateHash); | ||
| 2892 | ExitOnFailure(hr, "Failed to create site binding"); | ||
| 2893 | } | ||
| 2894 | else | ||
| 2895 | { | ||
| 2896 | hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); | ||
| 2897 | ExitOnFailure(hr, "Site not found for create binding"); | ||
| 2898 | } | ||
| 2899 | } | ||
| 2900 | else if (IIS_DELETE == iAction) | ||
| 2901 | { | ||
| 2902 | if (fSiteFound) | ||
| 2903 | { | ||
| 2904 | //delete binding | ||
| 2905 | hr = DeleteSslBinding(pSiteElem, pwzStoreName, pwzEncodedCertificateHash); | ||
| 2906 | ExitOnFailure(hr, "Failed to delete binding"); | ||
| 2907 | } | ||
| 2908 | } | ||
| 2909 | |||
| 2910 | LExit: | ||
| 2911 | ReleaseStr(pwzSiteName); | ||
| 2912 | ReleaseStr(pwzStoreName); | ||
| 2913 | ReleaseStr(pwzEncodedCertificateHash); | ||
| 2914 | ReleaseObject(pSiteElem); | ||
| 2915 | |||
| 2916 | return hr; | ||
| 2917 | } | ||
| 2918 | |||
| 2919 | //------------------------------------------------------------------------------------------------- | ||
| 2920 | // Helper Functions | ||
| 2921 | // | ||
| 2922 | // | ||
| 2923 | // | ||
| 2924 | //------------------------------------------------------------------------------------------------- | ||
| 2925 | |||
| 2926 | static HRESULT GetNextAvailableSiteId( | ||
| 2927 | IAppHostElementCollection *pCollection, | ||
| 2928 | DWORD *plSiteId | ||
| 2929 | ) | ||
| 2930 | { | ||
| 2931 | HRESULT hr = S_OK; | ||
| 2932 | IAppHostElement *pElement = NULL; | ||
| 2933 | IAppHostProperty *pProperty = NULL; | ||
| 2934 | |||
| 2935 | DWORD cSites; | ||
| 2936 | DWORD plNextAvailSite = 0; | ||
| 2937 | VARIANT vPropValue; | ||
| 2938 | VARIANT vtIndex; | ||
| 2939 | |||
| 2940 | VariantInit(&vPropValue); | ||
| 2941 | VariantInit(&vtIndex); | ||
| 2942 | |||
| 2943 | *plSiteId = 0; | ||
| 2944 | |||
| 2945 | hr = pCollection->get_Count(&cSites); | ||
| 2946 | ExitOnFailure(hr, "Failed get sites collection count"); | ||
| 2947 | |||
| 2948 | vtIndex.vt = VT_UI4; | ||
| 2949 | for (DWORD i = 0; i < cSites; ++i) | ||
| 2950 | { | ||
| 2951 | vtIndex.ulVal = i; | ||
| 2952 | hr = pCollection->get_Item(vtIndex , &pElement); | ||
| 2953 | ExitOnFailure(hr, "Failed get sites collection item"); | ||
| 2954 | |||
| 2955 | hr = pElement->GetPropertyByName(ScopeBSTR(IIS_CONFIG_ID), &pProperty); | ||
| 2956 | ExitOnFailure(hr, "Failed get site property"); | ||
| 2957 | |||
| 2958 | hr = pProperty->get_Value(&vPropValue); | ||
| 2959 | ExitOnFailure(hr, "Failed get site property value"); | ||
| 2960 | |||
| 2961 | *plSiteId = vPropValue.lVal; | ||
| 2962 | if (*plSiteId > plNextAvailSite) | ||
| 2963 | { | ||
| 2964 | plNextAvailSite = *plSiteId; | ||
| 2965 | } | ||
| 2966 | ReleaseNullObject(pElement); | ||
| 2967 | ReleaseNullObject(pProperty); | ||
| 2968 | } | ||
| 2969 | *plSiteId = ++plNextAvailSite; | ||
| 2970 | |||
| 2971 | LExit: | ||
| 2972 | ReleaseVariant(vPropValue); | ||
| 2973 | ReleaseVariant(vtIndex); | ||
| 2974 | |||
| 2975 | ReleaseObject(pElement); | ||
| 2976 | ReleaseObject(pProperty); | ||
| 2977 | |||
| 2978 | return hr; | ||
| 2979 | } | ||
| 2980 | |||
| 2981 | static HRESULT GetSiteElement( | ||
| 2982 | IAppHostWritableAdminManager *pAdminMgr, | ||
| 2983 | LPCWSTR swSiteName, | ||
| 2984 | IAppHostElement **ppSiteElement, | ||
| 2985 | BOOL* fFound | ||
| 2986 | ) | ||
| 2987 | { | ||
| 2988 | HRESULT hr = S_OK; | ||
| 2989 | IAppHostElement *pSites = NULL; | ||
| 2990 | IAppHostElementCollection *pCollection = NULL; | ||
| 2991 | |||
| 2992 | *fFound = FALSE; | ||
| 2993 | |||
| 2994 | hr = pAdminMgr->GetAdminSection(ScopeBSTR(IIS_CONFIG_SITES_SECTION), ScopeBSTR(IIS_CONFIG_APPHOST_ROOT), &pSites); | ||
| 2995 | ExitOnFailure(hr, "Failed get sites section"); | ||
| 2996 | ExitOnNull(pSites, hr, ERROR_FILE_NOT_FOUND, "Failed get sites section object"); | ||
| 2997 | |||
| 2998 | hr = pSites->get_Collection(&pCollection); | ||
| 2999 | ExitOnFailure(hr, "Failed get sites collection"); | ||
| 3000 | |||
| 3001 | hr = Iis7FindAppHostElementString(pCollection, IIS_CONFIG_SITE, IIS_CONFIG_NAME, swSiteName, ppSiteElement, NULL); | ||
| 3002 | ExitOnFailure(hr, "Failed to find site %ls", swSiteName); | ||
| 3003 | |||
| 3004 | *fFound = ppSiteElement != NULL && *ppSiteElement != NULL; | ||
| 3005 | |||
| 3006 | LExit: | ||
| 3007 | ReleaseObject(pSites); | ||
| 3008 | ReleaseObject(pCollection); | ||
| 3009 | |||
| 3010 | return hr; | ||
| 3011 | } | ||
| 3012 | |||
| 3013 | static HRESULT GetApplicationElement( IAppHostElement *pSiteElement, | ||
| 3014 | LPCWSTR swAppPath, | ||
| 3015 | IAppHostElement **ppAppElement, | ||
| 3016 | BOOL* fFound) | ||
| 3017 | { | ||
| 3018 | HRESULT hr = S_OK; | ||
| 3019 | IAppHostElementCollection *pCollection = NULL; | ||
| 3020 | |||
| 3021 | *fFound = FALSE; | ||
| 3022 | |||
| 3023 | hr = pSiteElement->get_Collection( &pCollection); | ||
| 3024 | ExitOnFailure(hr, "Failed get site app collection"); | ||
| 3025 | |||
| 3026 | hr = Iis7FindAppHostElementString(pCollection, IIS_CONFIG_APPLICATION, IIS_CONFIG_PATH, swAppPath, ppAppElement, NULL); | ||
| 3027 | ExitOnFailure(hr, "Failed to find app %ls", swAppPath); | ||
| 3028 | |||
| 3029 | *fFound = ppAppElement != NULL && *ppAppElement != NULL; | ||
| 3030 | |||
| 3031 | LExit: | ||
| 3032 | ReleaseObject(pCollection); | ||
| 3033 | |||
| 3034 | return hr; | ||
| 3035 | } | ||
| 3036 | |||
| 3037 | static HRESULT GetApplicationElementForVDir( IAppHostElement *pSiteElement, | ||
| 3038 | LPCWSTR pwzVDirPath, | ||
| 3039 | IAppHostElement **ppAppElement, | ||
| 3040 | LPCWSTR *ppwzVDirSubPath, | ||
| 3041 | BOOL* fFound) | ||
| 3042 | { | ||
| 3043 | HRESULT hr = S_OK; | ||
| 3044 | IAppHostElementCollection *pCollection = NULL; | ||
| 3045 | LPWSTR pwzAppPath = NULL; | ||
| 3046 | *fFound = FALSE; | ||
| 3047 | *ppwzVDirSubPath = NULL; | ||
| 3048 | |||
| 3049 | hr = pSiteElement->get_Collection( &pCollection); | ||
| 3050 | ExitOnFailure(hr, "Failed get site app collection"); | ||
| 3051 | |||
| 3052 | // Start with full path | ||
| 3053 | int iLastPathIndex = lstrlenW(pwzVDirPath) - 1; | ||
| 3054 | hr = StrAllocString(&pwzAppPath, pwzVDirPath, 0); | ||
| 3055 | ExitOnFailure(hr, "Failed allocate application path"); | ||
| 3056 | |||
| 3057 | for (int iSubPathIndex = iLastPathIndex; (iSubPathIndex >= 0) && (!*fFound); --iSubPathIndex) | ||
| 3058 | { | ||
| 3059 | // We are looking at the full path, or at a directory boundary, or at the root | ||
| 3060 | if (iSubPathIndex == iLastPathIndex || | ||
| 3061 | '/' == pwzAppPath[iSubPathIndex] || | ||
| 3062 | 0 == iSubPathIndex) | ||
| 3063 | { | ||
| 3064 | // break the path if needed | ||
| 3065 | if ('/' == pwzAppPath[iSubPathIndex]) | ||
| 3066 | { | ||
| 3067 | pwzAppPath[iSubPathIndex] = '\0'; | ||
| 3068 | } | ||
| 3069 | |||
| 3070 | // Special case for root path, need an empty app path | ||
| 3071 | LPCWSTR pwzAppSearchPath = 0 == iSubPathIndex ? L"/" : pwzAppPath; | ||
| 3072 | |||
| 3073 | // Try to find an app with the specified path | ||
| 3074 | hr = Iis7FindAppHostElementString(pCollection, IIS_CONFIG_APPLICATION, IIS_CONFIG_PATH, pwzAppSearchPath, ppAppElement, NULL); | ||
| 3075 | ExitOnFailure(hr, "Failed to search for app %ls", pwzAppSearchPath); | ||
| 3076 | *fFound = ppAppElement != NULL && *ppAppElement != NULL; | ||
| 3077 | |||
| 3078 | if (*fFound) | ||
| 3079 | { | ||
| 3080 | // set return value for sub path | ||
| 3081 | // special case for app path == vdir path, need an empty subpath. | ||
| 3082 | *ppwzVDirSubPath = (iSubPathIndex == iLastPathIndex) ? L"/" : pwzVDirPath + iSubPathIndex; | ||
| 3083 | } | ||
| 3084 | } | ||
| 3085 | } | ||
| 3086 | |||
| 3087 | LExit: | ||
| 3088 | ReleaseObject(pCollection); | ||
| 3089 | ReleaseStr(pwzAppPath); | ||
| 3090 | |||
| 3091 | return hr; | ||
| 3092 | } | ||
| 3093 | |||
| 3094 | static HRESULT CreateSite( | ||
| 3095 | __in IAppHostElementCollection *pCollection, | ||
| 3096 | __in LPCWSTR swSiteName, | ||
| 3097 | __out IAppHostElement **pSiteElement | ||
| 3098 | ) | ||
| 3099 | { | ||
| 3100 | HRESULT hr = S_OK; | ||
| 3101 | IAppHostElement *pNewElement = NULL; | ||
| 3102 | |||
| 3103 | hr = pCollection->CreateNewElement(ScopeBSTR(IIS_CONFIG_SITE), &pNewElement); | ||
| 3104 | ExitOnFailure(hr, "Failed create site element"); | ||
| 3105 | |||
| 3106 | hr = Iis7PutPropertyString(pNewElement, IIS_CONFIG_NAME, swSiteName); | ||
| 3107 | ExitOnFailure(hr, "Failed set site name property"); | ||
| 3108 | |||
| 3109 | DWORD lSiteId = 0; | ||
| 3110 | hr = GetNextAvailableSiteId(pCollection, &lSiteId); | ||
| 3111 | ExitOnFailure(hr, "Failed get next site id"); | ||
| 3112 | |||
| 3113 | Iis7PutPropertyInteger(pNewElement, IIS_CONFIG_ID, lSiteId); | ||
| 3114 | ExitOnFailure(hr, "Failed set site id property"); | ||
| 3115 | |||
| 3116 | hr = pCollection->AddElement(pNewElement); | ||
| 3117 | ExitOnFailure(hr, "Failed add site element"); | ||
| 3118 | |||
| 3119 | *pSiteElement = pNewElement; | ||
| 3120 | pNewElement = NULL; | ||
| 3121 | |||
| 3122 | LExit: | ||
| 3123 | ReleaseObject(pNewElement); | ||
| 3124 | |||
| 3125 | return hr; | ||
| 3126 | } | ||
| 3127 | |||
| 3128 | static HRESULT CreateApplication( | ||
| 3129 | IAppHostElement *pSiteElement, | ||
| 3130 | LPCWSTR swAppPath, | ||
| 3131 | IAppHostElement **pAppElement | ||
| 3132 | ) | ||
| 3133 | { | ||
| 3134 | HRESULT hr = S_OK; | ||
| 3135 | IAppHostElement *pNewElement = NULL; | ||
| 3136 | IAppHostElementCollection *pCollection = NULL; | ||
| 3137 | |||
| 3138 | hr = pSiteElement->get_Collection(&pCollection); | ||
| 3139 | ExitOnFailure(hr, "Failed get application collection"); | ||
| 3140 | |||
| 3141 | hr = pCollection->CreateNewElement(ScopeBSTR(IIS_CONFIG_APPLICATION), &pNewElement); | ||
| 3142 | ExitOnFailure(hr, "Failed get application element"); | ||
| 3143 | |||
| 3144 | hr = Iis7PutPropertyString(pNewElement, IIS_CONFIG_PATH, swAppPath); | ||
| 3145 | ExitOnFailure(hr, "Failed set application path property"); | ||
| 3146 | |||
| 3147 | hr = pCollection->AddElement(pNewElement); | ||
| 3148 | ExitOnFailure(hr, "Failed add application to collection"); | ||
| 3149 | |||
| 3150 | *pAppElement = pNewElement; | ||
| 3151 | pNewElement = NULL; | ||
| 3152 | |||
| 3153 | LExit: | ||
| 3154 | ReleaseObject(pCollection); | ||
| 3155 | ReleaseObject(pNewElement); | ||
| 3156 | |||
| 3157 | return hr; | ||
| 3158 | } | ||
| 3159 | |||
| 3160 | static HRESULT DeleteApplication( | ||
| 3161 | IAppHostElement *pSiteElement, | ||
| 3162 | LPCWSTR swAppPath | ||
| 3163 | ) | ||
| 3164 | { | ||
| 3165 | HRESULT hr = S_OK; | ||
| 3166 | IAppHostElementCollection *pCollection = NULL; | ||
| 3167 | |||
| 3168 | hr = pSiteElement->get_Collection(&pCollection); | ||
| 3169 | ExitOnFailure(hr, "Failed get application collection"); | ||
| 3170 | |||
| 3171 | hr = DeleteCollectionElement(pCollection, IIS_CONFIG_APPLICATION, IIS_CONFIG_PATH, swAppPath); | ||
| 3172 | ExitOnFailure(hr, "Failed to delete website"); | ||
| 3173 | |||
| 3174 | LExit: | ||
| 3175 | ReleaseObject(pCollection); | ||
| 3176 | |||
| 3177 | return hr; | ||
| 3178 | } | ||
| 3179 | |||
| 3180 | static HRESULT SetAppPool( | ||
| 3181 | IAppHostElement *pAppElement, | ||
| 3182 | LPCWSTR pwzAppPool | ||
| 3183 | ) | ||
| 3184 | { | ||
| 3185 | HRESULT hr = S_OK; | ||
| 3186 | |||
| 3187 | if (*pwzAppPool != 0) | ||
| 3188 | { | ||
| 3189 | hr = Iis7PutPropertyString(pAppElement, IIS_CONFIG_APPPOOL, pwzAppPool); | ||
| 3190 | ExitOnFailure(hr, "Failed set application appPool property"); | ||
| 3191 | } | ||
| 3192 | LExit: | ||
| 3193 | return hr; | ||
| 3194 | } | ||
| 3195 | |||
| 3196 | static HRESULT CreateVdir( | ||
| 3197 | IAppHostElement *pAppElement, | ||
| 3198 | LPCWSTR pwzVDirPath, | ||
| 3199 | LPCWSTR pwzVDirPhyDir | ||
| 3200 | ) | ||
| 3201 | { | ||
| 3202 | HRESULT hr = S_OK; | ||
| 3203 | IAppHostElement *pElement = NULL; | ||
| 3204 | IAppHostElementCollection *pCollection = NULL; | ||
| 3205 | BOOL fFound; | ||
| 3206 | |||
| 3207 | hr = pAppElement->get_Collection(&pCollection); | ||
| 3208 | ExitOnFailure(hr, "Failed get application VDir collection"); | ||
| 3209 | |||
| 3210 | hr = Iis7FindAppHostElementString(pCollection, IIS_CONFIG_VDIR, IIS_CONFIG_PATH, pwzVDirPath, &pElement, NULL); | ||
| 3211 | ExitOnFailure(hr, "Failed while finding virtualDir"); | ||
| 3212 | fFound = (NULL != pElement); | ||
| 3213 | |||
| 3214 | if (!fFound) | ||
| 3215 | { | ||
| 3216 | hr = pCollection->CreateNewElement(ScopeBSTR(IIS_CONFIG_VDIR), &pElement); | ||
| 3217 | ExitOnFailure(hr, "Failed create application VDir collection"); | ||
| 3218 | |||
| 3219 | hr = Iis7PutPropertyString(pElement, IIS_CONFIG_PATH, pwzVDirPath); | ||
| 3220 | ExitOnFailure(hr, "Failed set VDir path property"); | ||
| 3221 | } | ||
| 3222 | |||
| 3223 | hr = Iis7PutPropertyString(pElement, IIS_CONFIG_PHYSPATH, pwzVDirPhyDir); | ||
| 3224 | ExitOnFailure(hr, "Failed set VDir phys path property"); | ||
| 3225 | |||
| 3226 | if (!fFound) | ||
| 3227 | { | ||
| 3228 | hr = pCollection->AddElement(pElement); | ||
| 3229 | ExitOnFailure(hr, "Failed add application VDir element"); | ||
| 3230 | } | ||
| 3231 | |||
| 3232 | LExit: | ||
| 3233 | ReleaseObject(pCollection); | ||
| 3234 | ReleaseObject(pElement); | ||
| 3235 | |||
| 3236 | return hr; | ||
| 3237 | } | ||
| 3238 | |||
| 3239 | static HRESULT DeleteVdir( | ||
| 3240 | IAppHostElement *pAppElement, | ||
| 3241 | LPCWSTR pwzVDirPath | ||
| 3242 | ) | ||
| 3243 | { | ||
| 3244 | HRESULT hr = S_OK; | ||
| 3245 | IAppHostElementCollection *pCollection = NULL; | ||
| 3246 | |||
| 3247 | hr = pAppElement->get_Collection(&pCollection); | ||
| 3248 | ExitOnFailure(hr, "Failed get application VDir collection"); | ||
| 3249 | |||
| 3250 | hr = DeleteCollectionElement(pCollection, IIS_CONFIG_VDIR, IIS_CONFIG_PATH, pwzVDirPath); | ||
| 3251 | ExitOnFailure(hr, "Failed to delete vdir"); | ||
| 3252 | |||
| 3253 | LExit: | ||
| 3254 | ReleaseObject(pCollection); | ||
| 3255 | |||
| 3256 | return hr; | ||
| 3257 | } | ||
| 3258 | |||
| 3259 | static HRESULT CreateBinding( | ||
| 3260 | IAppHostElement *pSiteElem, | ||
| 3261 | LPCWSTR pwzProtocol, | ||
| 3262 | LPCWSTR pwzInfo | ||
| 3263 | ) | ||
| 3264 | { | ||
| 3265 | HRESULT hr = S_OK; | ||
| 3266 | IAppHostChildElementCollection *pChildElems = NULL; | ||
| 3267 | IAppHostElement *pBindings = NULL; | ||
| 3268 | IAppHostElement *pBindingElement = NULL; | ||
| 3269 | IAppHostElementCollection *pCollection = NULL; | ||
| 3270 | |||
| 3271 | VARIANT vtProp; | ||
| 3272 | |||
| 3273 | VariantInit(&vtProp); | ||
| 3274 | |||
| 3275 | hr = pSiteElem->get_ChildElements(&pChildElems); | ||
| 3276 | ExitOnFailure(hr, "Failed get site child elements collection"); | ||
| 3277 | |||
| 3278 | vtProp.vt = VT_BSTR; | ||
| 3279 | vtProp.bstrVal = ::SysAllocString(IIS_CONFIG_BINDINGS); | ||
| 3280 | hr = pChildElems->get_Item(vtProp, &pBindings); | ||
| 3281 | ExitOnFailure(hr, "Failed get bindings element"); | ||
| 3282 | ReleaseVariant(vtProp); | ||
| 3283 | |||
| 3284 | hr = pBindings->get_Collection(&pCollection); | ||
| 3285 | ExitOnFailure(hr, "Failed get bindings collection"); | ||
| 3286 | |||
| 3287 | hr = pCollection->CreateNewElement(ScopeBSTR(IIS_CONFIG_BINDING), &pBindingElement); | ||
| 3288 | ExitOnFailure(hr, "Failed get binding element"); | ||
| 3289 | |||
| 3290 | hr = Iis7PutPropertyString(pBindingElement, IIS_CONFIG_PROTOCOL, pwzProtocol); | ||
| 3291 | ExitOnFailure(hr, "Failed set binding protocol property"); | ||
| 3292 | |||
| 3293 | hr = Iis7PutPropertyString(pBindingElement, IIS_CONFIG_BINDINGINFO, pwzInfo); | ||
| 3294 | ExitOnFailure(hr, "Failed set binding information property"); | ||
| 3295 | |||
| 3296 | hr = pCollection->AddElement(pBindingElement); | ||
| 3297 | if (hr == HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS)) | ||
| 3298 | { | ||
| 3299 | //Eat this error. Binding is there and nothing to repair since | ||
| 3300 | //identity == protocol + info so all is OK | ||
| 3301 | hr = S_OK; | ||
| 3302 | } | ||
| 3303 | else | ||
| 3304 | { | ||
| 3305 | ExitOnFailure(hr, "Failed add binding to site"); | ||
| 3306 | } | ||
| 3307 | |||
| 3308 | LExit: | ||
| 3309 | ReleaseVariant(vtProp); | ||
| 3310 | |||
| 3311 | ReleaseObject(pCollection); | ||
| 3312 | ReleaseObject(pChildElems); | ||
| 3313 | ReleaseObject(pBindingElement); | ||
| 3314 | ReleaseObject(pBindings); | ||
| 3315 | |||
| 3316 | return hr; | ||
| 3317 | } | ||
| 3318 | static HRESULT CreateWebLog( | ||
| 3319 | IAppHostElement *pSiteElem, | ||
| 3320 | LPCWSTR pwzFormat | ||
| 3321 | ) | ||
| 3322 | { | ||
| 3323 | HRESULT hr = S_OK; | ||
| 3324 | IAppHostChildElementCollection *pChildElems = NULL; | ||
| 3325 | IAppHostElement *pLogFile = NULL; | ||
| 3326 | |||
| 3327 | VARIANT vtProp; | ||
| 3328 | |||
| 3329 | VariantInit(&vtProp); | ||
| 3330 | |||
| 3331 | hr = pSiteElem->get_ChildElements(&pChildElems); | ||
| 3332 | ExitOnFailure(hr, "Failed get site child elements collection"); | ||
| 3333 | |||
| 3334 | vtProp.vt = VT_BSTR; | ||
| 3335 | vtProp.bstrVal = ::SysAllocString(IIS_CONFIG_WEBLOG); | ||
| 3336 | hr = pChildElems->get_Item(vtProp, &pLogFile); | ||
| 3337 | ExitOnFailure(hr, "Failed get logfile element"); | ||
| 3338 | ReleaseVariant(vtProp); | ||
| 3339 | |||
| 3340 | if (CSTR_EQUAL != ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, pwzFormat, -1, L"none", -1)) | ||
| 3341 | { | ||
| 3342 | hr = Iis7PutPropertyString(pLogFile, IIS_CONFIG_LOGFORMAT, pwzFormat); | ||
| 3343 | ExitOnFailure(hr, "Failed set logfile format property"); | ||
| 3344 | hr = Iis7PutPropertyString(pLogFile, IIS_CONFIG_ENABLED, IIS_CONFIG_TRUE); | ||
| 3345 | ExitOnFailure(hr, "Failed set logfile enabled property"); | ||
| 3346 | } | ||
| 3347 | else | ||
| 3348 | { | ||
| 3349 | hr = Iis7PutPropertyString(pLogFile, IIS_CONFIG_ENABLED, IIS_CONFIG_FALSE); | ||
| 3350 | ExitOnFailure(hr, "Failed set logfile enabled property"); | ||
| 3351 | } | ||
| 3352 | |||
| 3353 | LExit: | ||
| 3354 | ReleaseVariant(vtProp); | ||
| 3355 | |||
| 3356 | ReleaseObject(pLogFile); | ||
| 3357 | ReleaseObject(pChildElems); | ||
| 3358 | |||
| 3359 | return hr; | ||
| 3360 | } | ||
| 3361 | |||
| 3362 | static HRESULT DeleteBinding( | ||
| 3363 | IAppHostElement* /*pSiteElem*/, | ||
| 3364 | LPCWSTR /*pwzProtocol*/, | ||
| 3365 | LPCWSTR /*pwzInfo*/ | ||
| 3366 | ) | ||
| 3367 | { | ||
| 3368 | HRESULT hr = S_OK; | ||
| 3369 | // | ||
| 3370 | //this isn't supported right now, we should support this for the SiteSearch scenario | ||
| 3371 | return hr; | ||
| 3372 | } | ||
| 3373 | |||
| 3374 | struct SCA_SSLBINDINGINFO | ||
| 3375 | { | ||
| 3376 | IIS7_APPHOSTELEMENTCOMPARISON comparison; | ||
| 3377 | LPCWSTR pwzStoreName; | ||
| 3378 | LPCWSTR pwzEncodedCertificateHash; | ||
| 3379 | HRESULT hr; | ||
| 3380 | }; | ||
| 3381 | |||
| 3382 | static BOOL AddSslCertificateToBindingCallback(IAppHostElement *pBindingElement, LPVOID pContext) | ||
| 3383 | { | ||
| 3384 | HRESULT hr = S_OK; | ||
| 3385 | VARIANT vtProp; | ||
| 3386 | VariantInit(&vtProp); | ||
| 3387 | SCA_SSLBINDINGINFO* pBindingInfo = (SCA_SSLBINDINGINFO*)pContext; | ||
| 3388 | IAppHostMethodCollection *pAppHostMethodCollection = NULL; | ||
| 3389 | IAppHostMethod *pAddSslMethod = NULL; | ||
| 3390 | IAppHostMethodInstance *pAddSslMethodInstance = NULL; | ||
| 3391 | IAppHostElement *pAddSslInput = NULL; | ||
| 3392 | int iWsaError = 0; | ||
| 3393 | WSADATA wsaData = {}; | ||
| 3394 | BOOL fWsaInitialized = FALSE; | ||
| 3395 | |||
| 3396 | // IIS's AddSslCertificate doesn't initialize WinSock on 2008 before using it to parse the IP | ||
| 3397 | // Initialize before calling to workaround the failure. | ||
| 3398 | iWsaError = WSAStartup(MAKEWORD(2, 2), &wsaData); | ||
| 3399 | if (0 != iWsaError) | ||
| 3400 | { | ||
| 3401 | ExitOnWin32Error(iWsaError, hr, "Failed to initialize WinSock"); | ||
| 3402 | } | ||
| 3403 | |||
| 3404 | fWsaInitialized = TRUE; | ||
| 3405 | |||
| 3406 | if (Iis7IsMatchingAppHostElement(pBindingElement, &pBindingInfo->comparison)) | ||
| 3407 | { | ||
| 3408 | hr = pBindingElement->get_Methods(&pAppHostMethodCollection); | ||
| 3409 | ExitOnFailure(hr, "failed to get binding method collection"); | ||
| 3410 | |||
| 3411 | hr = Iis7FindAppHostMethod(pAppHostMethodCollection, L"AddSslCertificate", &pAddSslMethod, NULL); | ||
| 3412 | if (FAILED(hr)) | ||
| 3413 | { | ||
| 3414 | WcaLog(LOGMSG_STANDARD, "The AddSslCertificate method is not supported by the binding element, SSL certificate will not be associated with the website"); | ||
| 3415 | ExitFunction(); | ||
| 3416 | } | ||
| 3417 | |||
| 3418 | pAddSslMethod->CreateInstance(&pAddSslMethodInstance); | ||
| 3419 | ExitOnFailure(hr, "failed to create an instance of AddSslCertificate method"); | ||
| 3420 | |||
| 3421 | pAddSslMethodInstance->get_Input(&pAddSslInput); | ||
| 3422 | ExitOnFailure(hr, "failed to get input element of AddSslCertificate method"); | ||
| 3423 | |||
| 3424 | Iis7PutPropertyString(pAddSslInput, IIS_CONFIG_CERTIFICATESTORENAME, pBindingInfo->pwzStoreName); | ||
| 3425 | ExitOnFailure(hr, "failed to set certificateStoreName input parameter of AddSslCertificate method"); | ||
| 3426 | |||
| 3427 | Iis7PutPropertyString(pAddSslInput, IIS_CONFIG_CERTIFICATEHASH, pBindingInfo->pwzEncodedCertificateHash); | ||
| 3428 | ExitOnFailure(hr, "failed to set certificateHash input parameter of AddSslCertificate method"); | ||
| 3429 | |||
| 3430 | hr = pAddSslMethodInstance->Execute(); | ||
| 3431 | ExitOnFailure(hr, "failed to execute AddSslCertificate method"); | ||
| 3432 | } | ||
| 3433 | LExit: | ||
| 3434 | pBindingInfo->hr = hr; | ||
| 3435 | ReleaseObject(pAppHostMethodCollection); | ||
| 3436 | ReleaseObject(pAddSslMethod); | ||
| 3437 | ReleaseObject(pAddSslMethodInstance); | ||
| 3438 | ReleaseObject(pAddSslInput); | ||
| 3439 | if (fWsaInitialized) | ||
| 3440 | { | ||
| 3441 | WSACleanup(); | ||
| 3442 | } | ||
| 3443 | |||
| 3444 | return FAILED(hr); | ||
| 3445 | } | ||
| 3446 | |||
| 3447 | static HRESULT CreateSslBinding( IAppHostElement *pSiteElem, LPCWSTR pwzStoreName, LPCWSTR pwzEncodedCertificateHash) | ||
| 3448 | { | ||
| 3449 | HRESULT hr = S_OK; | ||
| 3450 | IAppHostChildElementCollection *pChildElems = NULL; | ||
| 3451 | IAppHostElement *pBindingsElement = NULL; | ||
| 3452 | IAppHostElementCollection *pBindingsCollection = NULL; | ||
| 3453 | SCA_SSLBINDINGINFO bindingInfo = {}; | ||
| 3454 | VARIANT vtProp; | ||
| 3455 | VariantInit(&vtProp); | ||
| 3456 | |||
| 3457 | hr = pSiteElem->get_ChildElements(&pChildElems); | ||
| 3458 | ExitOnFailure(hr, "Failed get site child elements collection"); | ||
| 3459 | |||
| 3460 | vtProp.vt = VT_BSTR; | ||
| 3461 | vtProp.bstrVal = ::SysAllocString(IIS_CONFIG_BINDINGS); | ||
| 3462 | hr = pChildElems->get_Item(vtProp, &pBindingsElement); | ||
| 3463 | ExitOnFailure(hr, "Failed get bindings element"); | ||
| 3464 | ReleaseVariant(vtProp); | ||
| 3465 | |||
| 3466 | hr = pBindingsElement->get_Collection(&pBindingsCollection); | ||
| 3467 | ExitOnFailure(hr, "Failed get bindings collection"); | ||
| 3468 | |||
| 3469 | bindingInfo.comparison.sczElementName = IIS_CONFIG_BINDING; | ||
| 3470 | bindingInfo.comparison.sczAttributeName = IIS_CONFIG_PROTOCOL; | ||
| 3471 | vtProp.vt = VT_BSTR; | ||
| 3472 | vtProp.bstrVal = ::SysAllocString(L"https"); | ||
| 3473 | bindingInfo.comparison.pvAttributeValue = &vtProp; | ||
| 3474 | bindingInfo.pwzStoreName = pwzStoreName; | ||
| 3475 | bindingInfo.pwzEncodedCertificateHash = pwzEncodedCertificateHash; | ||
| 3476 | |||
| 3477 | // Our current IISWebSiteCertificates schema does not allow specification of the website binding | ||
| 3478 | // to associate the certificate with. For now just associate it with all secure bindings. | ||
| 3479 | |||
| 3480 | hr = Iis7EnumAppHostElements(pBindingsCollection, AddSslCertificateToBindingCallback, &bindingInfo, NULL, NULL); | ||
| 3481 | ExitOnFailure(hr, "Failed to enumerate bindings collection"); | ||
| 3482 | hr = bindingInfo.hr; | ||
| 3483 | ExitOnFailure(hr, "Failed to add ssl binding"); | ||
| 3484 | |||
| 3485 | LExit: | ||
| 3486 | ReleaseVariant(vtProp); | ||
| 3487 | |||
| 3488 | ReleaseObject(pChildElems); | ||
| 3489 | ReleaseObject(pBindingsElement); | ||
| 3490 | ReleaseObject(pBindingsCollection); | ||
| 3491 | |||
| 3492 | return hr; | ||
| 3493 | } | ||
| 3494 | |||
| 3495 | static HRESULT DeleteSslBinding( | ||
| 3496 | IAppHostElement * /*pSiteElem*/, | ||
| 3497 | LPCWSTR /*pwzStoreName*/, | ||
| 3498 | LPCWSTR /*pwzEncodedCertificateHash*/ | ||
| 3499 | ) | ||
| 3500 | { | ||
| 3501 | HRESULT hr = S_OK; | ||
| 3502 | // | ||
| 3503 | //this isn't supported right now, we should support this for the SiteSearch scenario | ||
| 3504 | return hr; | ||
| 3505 | } | ||
| 3506 | |||
| 3507 | static HRESULT DeleteAppPool( IAppHostWritableAdminManager *pAdminMgr, | ||
| 3508 | LPCWSTR swAppPoolName) | ||
| 3509 | { | ||
| 3510 | HRESULT hr = S_OK; | ||
| 3511 | IAppHostElement *pAppPools = NULL; | ||
| 3512 | IAppHostElementCollection *pCollection = NULL; | ||
| 3513 | |||
| 3514 | hr = pAdminMgr->GetAdminSection(ScopeBSTR(IIS_CONFIG_APPPOOL_SECTION), ScopeBSTR(IIS_CONFIG_APPHOST_ROOT), &pAppPools); | ||
| 3515 | ExitOnFailure(hr, "Failed get AppPools section"); | ||
| 3516 | ExitOnNull(pAppPools, hr, E_UNEXPECTED, "Failed get appPools section object"); | ||
| 3517 | |||
| 3518 | hr = pAppPools->get_Collection( &pCollection); | ||
| 3519 | ExitOnFailure(hr, "Failed get AppPools collection"); | ||
| 3520 | |||
| 3521 | hr = DeleteCollectionElement(pCollection, IIS_CONFIG_ADD, IIS_CONFIG_NAME, swAppPoolName); | ||
| 3522 | ExitOnFailure(hr, "Failed to delete app pool %ls", swAppPoolName); | ||
| 3523 | |||
| 3524 | LExit: | ||
| 3525 | ReleaseObject(pAppPools); | ||
| 3526 | ReleaseObject(pCollection); | ||
| 3527 | |||
| 3528 | return hr; | ||
| 3529 | } | ||
| 3530 | |||
| 3531 | static HRESULT CreateAppPool( | ||
| 3532 | __inout LPWSTR *ppwzCustomActionData, | ||
| 3533 | IAppHostWritableAdminManager *pAdminMgr, | ||
| 3534 | LPCWSTR swAppPoolName | ||
| 3535 | ) | ||
| 3536 | { | ||
| 3537 | HRESULT hr = S_OK; | ||
| 3538 | IAppHostElement *pAppPools = NULL; | ||
| 3539 | IAppHostElement *pAppPoolElement = NULL; | ||
| 3540 | IAppHostElement *pElement = NULL; | ||
| 3541 | IAppHostElement *pElement2 = NULL; | ||
| 3542 | IAppHostElement *pElement3 = NULL; | ||
| 3543 | IAppHostElementCollection *pCollection = NULL; | ||
| 3544 | IAppHostElementCollection *pCollection2 = NULL; | ||
| 3545 | int iAction = -1; | ||
| 3546 | int iData = 0; | ||
| 3547 | LPWSTR pwzData = NULL; | ||
| 3548 | WCHAR wcData[512]; | ||
| 3549 | WCHAR wcTime[60]; | ||
| 3550 | BOOL fFound = FALSE; | ||
| 3551 | |||
| 3552 | hr = pAdminMgr->GetAdminSection(ScopeBSTR(IIS_CONFIG_APPPOOL_SECTION), ScopeBSTR(IIS_CONFIG_APPHOST_ROOT), &pAppPools); | ||
| 3553 | ExitOnFailure(hr, "Failed get AppPools section"); | ||
| 3554 | ExitOnNull(pAppPools, hr, ERROR_FILE_NOT_FOUND, "Failed get AppPools section object"); | ||
| 3555 | |||
| 3556 | hr = pAppPools->get_Collection( &pCollection); | ||
| 3557 | ExitOnFailure(hr, "Failed get AppPools collection"); | ||
| 3558 | |||
| 3559 | hr = Iis7FindAppHostElementString(pCollection, IIS_CONFIG_ADD, IIS_CONFIG_NAME, swAppPoolName, &pAppPoolElement, NULL); | ||
| 3560 | ExitOnFailure(hr, "Failed find AppPool element"); | ||
| 3561 | fFound = (NULL != pAppPoolElement); | ||
| 3562 | |||
| 3563 | if (!fFound) | ||
| 3564 | { | ||
| 3565 | hr = pCollection->CreateNewElement(ScopeBSTR(IIS_CONFIG_ADD), &pAppPoolElement); | ||
| 3566 | ExitOnFailure(hr, "Failed create AppPool element"); | ||
| 3567 | } | ||
| 3568 | |||
| 3569 | hr = Iis7PutPropertyString(pAppPoolElement, IIS_CONFIG_NAME, swAppPoolName); | ||
| 3570 | ExitOnFailure(hr, "Failed set AppPool name property"); | ||
| 3571 | |||
| 3572 | //For WiX II6 /ABO compat we will default managedPipelineMode="Classic" | ||
| 3573 | hr = Iis7PutPropertyString(pAppPoolElement, IIS_CONFIG_PIPELINEMODE, L"Classic"); | ||
| 3574 | ExitOnFailure(hr, "Failed set AppPool managedPipelineMode property"); | ||
| 3575 | //For WiX II6 /ABO compat we will be hardcoding autostart="true" | ||
| 3576 | hr = Iis7PutPropertyString(pAppPoolElement, IIS_CONFIG_APPPOOL_AUTO, L"true"); | ||
| 3577 | ExitOnFailure(hr, "Failed set AppPool autoStart property"); | ||
| 3578 | |||
| 3579 | if (!fFound) | ||
| 3580 | { | ||
| 3581 | hr = pCollection->AddElement(pAppPoolElement); | ||
| 3582 | ExitOnFailure(hr, "Failed to add appPool element"); | ||
| 3583 | } | ||
| 3584 | |||
| 3585 | // Get AppPool Property action | ||
| 3586 | hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iAction); | ||
| 3587 | ExitOnFailure(hr, "Failed to read AppPool Property action"); | ||
| 3588 | while (IIS_APPPOOL_END != iAction) | ||
| 3589 | { | ||
| 3590 | //Process property action | ||
| 3591 | switch (iAction) | ||
| 3592 | { | ||
| 3593 | case IIS_APPPOOL_RECYCLE_MIN : | ||
| 3594 | { | ||
| 3595 | // /recycling / periodicRestart | time | ||
| 3596 | hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iData); | ||
| 3597 | ExitOnFailure(hr, "Failed to read AppPool recycle min"); | ||
| 3598 | hr = pAppPoolElement->GetElementByName(ScopeBSTR(IIS_CONFIG_RECYCLING), &pElement); | ||
| 3599 | ExitOnFailure(hr, "Failed to get AppPool recycling element"); | ||
| 3600 | hr = pElement->GetElementByName(ScopeBSTR(IIS_CONFIG_PEROIDRESTART), &pElement2); | ||
| 3601 | ExitOnFailure(hr, "Failed to get AppPool periodicRestart element"); | ||
| 3602 | *wcTime = '\0'; | ||
| 3603 | ConvSecToHMS(iData * 60, wcTime, countof(wcTime)); | ||
| 3604 | hr = Iis7PutPropertyString(pElement2, IIS_CONFIG_TIME, wcTime); | ||
| 3605 | ExitOnFailure(hr, "Failed to set AppPool periodicRestart time value"); | ||
| 3606 | ReleaseNullObject(pElement); | ||
| 3607 | ReleaseNullObject(pElement2); | ||
| 3608 | break; | ||
| 3609 | } | ||
| 3610 | case IIS_APPPOOL_RECYCLE_REQ : | ||
| 3611 | { | ||
| 3612 | // /recycling / periodicRestart | requests | ||
| 3613 | hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iData); | ||
| 3614 | ExitOnFailure(hr, "Failed to read AppPool recycle req"); | ||
| 3615 | hr = pAppPoolElement->GetElementByName(ScopeBSTR(IIS_CONFIG_RECYCLING), &pElement); | ||
| 3616 | ExitOnFailure(hr, "Failed to get AppPool recycling element"); | ||
| 3617 | hr = pElement->GetElementByName(ScopeBSTR(IIS_CONFIG_PEROIDRESTART), &pElement2); | ||
| 3618 | ExitOnFailure(hr, "Failed to get AppPool periodicRestart element"); | ||
| 3619 | hr = Iis7PutPropertyInteger(pElement2, IIS_CONFIG_REQUESTS, iData); | ||
| 3620 | ExitOnFailure(hr, "Failed to set AppPool periodicRestart time value"); | ||
| 3621 | ReleaseNullObject(pElement); | ||
| 3622 | ReleaseNullObject(pElement2); | ||
| 3623 | break; | ||
| 3624 | } | ||
| 3625 | case IIS_APPPOOL_RECYCLE_TIMES : | ||
| 3626 | { | ||
| 3627 | // /recycling / periodicRestart | schedule | ||
| 3628 | hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzData); | ||
| 3629 | ExitOnFailure(hr, "Failed to read AppPool recycle times"); | ||
| 3630 | hr = pAppPoolElement->GetElementByName(ScopeBSTR(IIS_CONFIG_RECYCLING), &pElement); | ||
| 3631 | ExitOnFailure(hr, "Failed to get AppPool recycling element"); | ||
| 3632 | hr = pElement->GetElementByName(ScopeBSTR(IIS_CONFIG_PEROIDRESTART), &pElement2); | ||
| 3633 | ExitOnFailure(hr, "Failed to get AppPool periodicRestart element"); | ||
| 3634 | hr = pElement2->GetElementByName(ScopeBSTR(IIS_CONFIG_SCHEDULE), &pElement3); | ||
| 3635 | ExitOnFailure(hr, "Failed to get AppPool schedule element"); | ||
| 3636 | hr = pElement3->get_Collection(&pCollection2); | ||
| 3637 | ExitOnFailure(hr, "Failed to get AppPool schedule collection"); | ||
| 3638 | |||
| 3639 | WCHAR wcDelim[] = L","; | ||
| 3640 | const WCHAR *wszToken = NULL; | ||
| 3641 | WCHAR *wszNextToken = NULL; | ||
| 3642 | wszToken = wcstok_s( pwzData, wcDelim, &wszNextToken); | ||
| 3643 | |||
| 3644 | while (wszToken) | ||
| 3645 | { | ||
| 3646 | *wcData = '\0'; | ||
| 3647 | hr = ::StringCchCopyW(wcData, countof(wcData), wszToken); | ||
| 3648 | ExitOnFailure(hr, "failed to copy AppPool schedule"); | ||
| 3649 | hr = ::StringCchCatW(wcData, countof(wcData), L":00"); | ||
| 3650 | ExitOnFailure(hr, "failed to append AppPool schedule"); | ||
| 3651 | |||
| 3652 | hr = pCollection2->CreateNewElement(ScopeBSTR(IIS_CONFIG_ADD), &pElement3); | ||
| 3653 | ExitOnFailure(hr, "Failed to create AppPool schedule element"); | ||
| 3654 | |||
| 3655 | hr = Iis7PutPropertyString(pElement3, IIS_CONFIG_VALUE, wcData); | ||
| 3656 | ExitOnFailure(hr, "Failed to set AppPool schedule value"); | ||
| 3657 | |||
| 3658 | hr = pCollection2->AddElement(pElement3); | ||
| 3659 | if (hr == HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS)) | ||
| 3660 | { | ||
| 3661 | //Eat this error, recycle time already exists NBD | ||
| 3662 | hr = S_OK; | ||
| 3663 | } | ||
| 3664 | ExitOnFailure(hr, "Failed to add win auth providers element"); | ||
| 3665 | ReleaseNullObject(pElement3); | ||
| 3666 | wszToken = wcstok_s( NULL, wcDelim, &wszNextToken); | ||
| 3667 | } | ||
| 3668 | ReleaseNullObject(pElement); | ||
| 3669 | ReleaseNullObject(pElement2); | ||
| 3670 | ReleaseNullObject(pElement3); | ||
| 3671 | ReleaseNullObject(pCollection2); | ||
| 3672 | break; | ||
| 3673 | } | ||
| 3674 | case IIS_APPPOOL_RECYCLE_VIRMEM : | ||
| 3675 | { | ||
| 3676 | // /recycling / periodicRestart | memory | ||
| 3677 | hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iData); | ||
| 3678 | ExitOnFailure(hr, "Failed to read AppPool recycle vir memory"); | ||
| 3679 | hr = pAppPoolElement->GetElementByName(ScopeBSTR(IIS_CONFIG_RECYCLING), &pElement); | ||
| 3680 | ExitOnFailure(hr, "Failed to get AppPool recycling element"); | ||
| 3681 | hr = pElement->GetElementByName(ScopeBSTR(IIS_CONFIG_PEROIDRESTART), &pElement2); | ||
| 3682 | ExitOnFailure(hr, "Failed to get AppPool periodicRestart element"); | ||
| 3683 | hr = Iis7PutPropertyInteger(pElement2, IIS_CONFIG_MEMORY, iData); | ||
| 3684 | ExitOnFailure(hr, "Failed to set AppPool periodicRestart memory"); | ||
| 3685 | ReleaseNullObject(pElement); | ||
| 3686 | ReleaseNullObject(pElement2); | ||
| 3687 | break; | ||
| 3688 | } | ||
| 3689 | case IIS_APPPOOL_RECYCLE_PRIVMEM : | ||
| 3690 | { | ||
| 3691 | // /recycling / periodicRestart | privateMemory | ||
| 3692 | hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iData); | ||
| 3693 | ExitOnFailure(hr, "Failed to read AppPool recycle priv mem"); | ||
| 3694 | hr = pAppPoolElement->GetElementByName(ScopeBSTR(IIS_CONFIG_RECYCLING), &pElement); | ||
| 3695 | ExitOnFailure(hr, "Failed to get AppPool recycling element"); | ||
| 3696 | hr = pElement->GetElementByName(ScopeBSTR(IIS_CONFIG_PEROIDRESTART), &pElement2); | ||
| 3697 | ExitOnFailure(hr, "Failed to get AppPool periodicRestart element"); | ||
| 3698 | hr = Iis7PutPropertyInteger(pElement2, IIS_CONFIG_PRIVMEMORY, iData); | ||
| 3699 | ExitOnFailure(hr, "Failed to set AppPool periodicRestart private memory"); | ||
| 3700 | ReleaseNullObject(pElement); | ||
| 3701 | ReleaseNullObject(pElement2); | ||
| 3702 | break; | ||
| 3703 | } | ||
| 3704 | case IIS_APPPOOL_RECYCLE_IDLTIMEOUT : | ||
| 3705 | { | ||
| 3706 | // /processModel | idleTimeout | ||
| 3707 | hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iData); | ||
| 3708 | ExitOnFailure(hr, "Failed to read AppPool idle timeout"); | ||
| 3709 | hr = pAppPoolElement->GetElementByName(ScopeBSTR(IIS_CONFIG_PROCESSMODEL), &pElement); | ||
| 3710 | ExitOnFailure(hr, "Failed to get AppPool processModel element"); | ||
| 3711 | *wcTime = '\0'; | ||
| 3712 | ConvSecToHMS(iData * 60, wcTime, countof(wcTime)); | ||
| 3713 | hr = Iis7PutPropertyString(pElement, IIS_CONFIG_IDLETIMEOUT, wcTime); | ||
| 3714 | ExitOnFailure(hr, "Failed to set AppPool processModel idle timeout value"); | ||
| 3715 | ReleaseNullObject(pElement); | ||
| 3716 | break; | ||
| 3717 | } | ||
| 3718 | case IIS_APPPOOL_RECYCLE_QUEUELIMIT : | ||
| 3719 | { | ||
| 3720 | // /applicationPools | queueLength | ||
| 3721 | hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iData); | ||
| 3722 | ExitOnFailure(hr, "Failed to read AppPool recycle queue limit"); | ||
| 3723 | hr = Iis7PutPropertyInteger(pAppPoolElement, IIS_CONFIG_QUEUELENGTH, iData); | ||
| 3724 | ExitOnFailure(hr, "Failed to set AppPool recycle queue limit value"); | ||
| 3725 | break; | ||
| 3726 | } | ||
| 3727 | case IIS_APPPOOL_MAXPROCESS : | ||
| 3728 | { | ||
| 3729 | // /processModel | maxProcesses | ||
| 3730 | hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iData); | ||
| 3731 | ExitOnFailure(hr, "Failed to read AppPool max processes"); | ||
| 3732 | hr = pAppPoolElement->GetElementByName(ScopeBSTR(IIS_CONFIG_PROCESSMODEL), &pElement); | ||
| 3733 | ExitOnFailure(hr, "Failed to get AppPool processModel element"); | ||
| 3734 | hr = Iis7PutPropertyInteger(pElement, IIS_CONFIG_MAXWRKPROCESSES, iData); | ||
| 3735 | ExitOnFailure(hr, "Failed to set AppPool processModel maxProcesses value"); | ||
| 3736 | ReleaseNullObject(pElement); | ||
| 3737 | break; | ||
| 3738 | } | ||
| 3739 | case IIS_APPPOOL_IDENTITY : | ||
| 3740 | { | ||
| 3741 | //"LocalSystem" 0 | ||
| 3742 | //"LocalService" 1 | ||
| 3743 | //"NetworkService" 2 | ||
| 3744 | //"SpecificUser" 3 | ||
| 3745 | //"ApplicationPoolIdentity" 4 | ||
| 3746 | // /processModel | identityType | ||
| 3747 | hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iData); | ||
| 3748 | ExitOnFailure(hr, "Failed to read AppPool identity"); | ||
| 3749 | hr = pAppPoolElement->GetElementByName(ScopeBSTR(IIS_CONFIG_PROCESSMODEL), &pElement); | ||
| 3750 | ExitOnFailure(hr, "Failed to get AppPool processModel element"); | ||
| 3751 | if (iData == 0) | ||
| 3752 | { | ||
| 3753 | hr = Iis7PutPropertyString(pElement, IIS_CONFIG_IDENITITYTYPE, IIS_CONFIG_LOCALSYSTEM); | ||
| 3754 | } | ||
| 3755 | else if (iData == 1) | ||
| 3756 | { | ||
| 3757 | hr = Iis7PutPropertyString(pElement, IIS_CONFIG_IDENITITYTYPE, IIS_CONFIG_LOCALSERVICE); | ||
| 3758 | } | ||
| 3759 | else if (iData == 2) | ||
| 3760 | { | ||
| 3761 | hr = Iis7PutPropertyString(pElement, IIS_CONFIG_IDENITITYTYPE, IIS_CONFIG_NETWORKSERVICE); | ||
| 3762 | } | ||
| 3763 | else if (iData == 3) | ||
| 3764 | { | ||
| 3765 | hr = Iis7PutPropertyString(pElement, IIS_CONFIG_IDENITITYTYPE, IIS_CONFIG_SPECIFICUSER); | ||
| 3766 | } | ||
| 3767 | else if (iData == 4) | ||
| 3768 | { | ||
| 3769 | hr = Iis7PutPropertyString(pElement, IIS_CONFIG_IDENITITYTYPE, IIS_CONFIG_APPLICATIONPOOLIDENTITY); | ||
| 3770 | } | ||
| 3771 | ExitOnFailure(hr, "Failed to set AppPool processModel identityType value"); | ||
| 3772 | ReleaseNullObject(pElement); | ||
| 3773 | break; | ||
| 3774 | } | ||
| 3775 | case IIS_APPPOOL_USER : | ||
| 3776 | { | ||
| 3777 | // /processModel | userName | ||
| 3778 | hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzData); | ||
| 3779 | ExitOnFailure(hr, "Failed to read AppPool user"); | ||
| 3780 | hr = pAppPoolElement->GetElementByName(ScopeBSTR(IIS_CONFIG_PROCESSMODEL), &pElement); | ||
| 3781 | ExitOnFailure(hr, "Failed to get AppPool processModel element"); | ||
| 3782 | hr = Iis7PutPropertyString(pElement, IIS_CONFIG_USERNAME, pwzData); | ||
| 3783 | ExitOnFailure(hr, "Failed to set AppPool processModel username value"); | ||
| 3784 | ReleaseNullObject(pElement); | ||
| 3785 | break; | ||
| 3786 | } | ||
| 3787 | case IIS_APPPOOL_PWD : | ||
| 3788 | { | ||
| 3789 | // /processModel | password | ||
| 3790 | hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzData); | ||
| 3791 | ExitOnFailure(hr, "Failed to read AppPool pwd"); | ||
| 3792 | hr = pAppPoolElement->GetElementByName(ScopeBSTR(IIS_CONFIG_PROCESSMODEL), &pElement); | ||
| 3793 | ExitOnFailure(hr, "Failed to get AppPool processModel element"); | ||
| 3794 | hr = Iis7PutPropertyString(pElement, IIS_CONFIG_PASSWORD, pwzData); | ||
| 3795 | ExitOnFailure(hr, "Failed to set AppPool processModel password value"); | ||
| 3796 | ReleaseNullObject(pElement); | ||
| 3797 | break; | ||
| 3798 | } | ||
| 3799 | case IIS_APPPOOL_RECYCLE_CPU_PCT: | ||
| 3800 | { | ||
| 3801 | // /cpu | limit | ||
| 3802 | hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iData); | ||
| 3803 | ExitOnFailure(hr, "Failed to read cpu pct"); | ||
| 3804 | hr = pAppPoolElement->GetElementByName(ScopeBSTR(IIS_CONFIG_CPU), &pElement); | ||
| 3805 | ExitOnFailure(hr, "Failed to get AppPool cpu element"); | ||
| 3806 | // limit is maximum percentage of CPU time (in 1/1000ths of one percent) | ||
| 3807 | hr = Iis7PutPropertyInteger(pElement, IIS_CONFIG_LIMIT, iData * 1000); | ||
| 3808 | ExitOnFailure(hr, "Failed to set AppPool cpu limit"); | ||
| 3809 | ReleaseNullObject(pElement); | ||
| 3810 | break; | ||
| 3811 | } | ||
| 3812 | case IIS_APPPOOL_RECYCLE_CPU_REFRESH: | ||
| 3813 | { | ||
| 3814 | // /cpu | resetInterval | ||
| 3815 | hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iData); | ||
| 3816 | ExitOnFailure(hr, "Failed to read cpu refresh pwd"); | ||
| 3817 | hr = pAppPoolElement->GetElementByName(ScopeBSTR(IIS_CONFIG_CPU), &pElement); | ||
| 3818 | ExitOnFailure(hr, "Failed to get AppPool cpu element"); | ||
| 3819 | *wcTime = '\0'; | ||
| 3820 | ConvSecToHMS(iData * 60, wcTime, countof(wcTime)); | ||
| 3821 | hr = Iis7PutPropertyString(pElement, IIS_CONFIG_RESETINTERVAL, wcTime); | ||
| 3822 | ExitOnFailure(hr, "Failed to set AppPool cpu resetInterval value"); | ||
| 3823 | ReleaseNullObject(pElement); | ||
| 3824 | break; | ||
| 3825 | } | ||
| 3826 | case IIS_APPPOOL_RECYCLE_CPU_ACTION: | ||
| 3827 | { | ||
| 3828 | // /cpu | action | ||
| 3829 | //"NoAction" 0 | ||
| 3830 | //"KillW3wp" 1 | ||
| 3831 | hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iData); | ||
| 3832 | ExitOnFailure(hr, "Failed to read cpu action"); | ||
| 3833 | hr = pAppPoolElement->GetElementByName(ScopeBSTR(IIS_CONFIG_CPU), &pElement); | ||
| 3834 | ExitOnFailure(hr, "Failed to get AppPool cpu element"); | ||
| 3835 | if (iData) | ||
| 3836 | { | ||
| 3837 | hr = Iis7PutPropertyString(pElement, IIS_CONFIG_CPU_ACTION, IIS_CONFIG_KILLW3WP); | ||
| 3838 | } | ||
| 3839 | else | ||
| 3840 | { | ||
| 3841 | hr = Iis7PutPropertyString(pElement, IIS_CONFIG_CPU_ACTION, IIS_CONFIG_NOACTION); | ||
| 3842 | } | ||
| 3843 | ExitOnFailure(hr, "Failed to set AppPool cpu action value"); | ||
| 3844 | ReleaseNullObject(pElement); | ||
| 3845 | break; | ||
| 3846 | } | ||
| 3847 | case IIS_APPPOOL_32BIT: | ||
| 3848 | { | ||
| 3849 | hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iData); | ||
| 3850 | ExitOnFailure(hr, "Failed to read enable32BitAppOnWin64 value"); | ||
| 3851 | // enable32BitAppOnWin64 | ||
| 3852 | hr = Iis7PutPropertyBool(pAppPoolElement, IIS_CONFIG_ENABLE32, iData ? TRUE : FALSE); | ||
| 3853 | ExitOnFailure(hr, "Failed to set AppPool enable32BitAppOnWin64 value"); | ||
| 3854 | break; | ||
| 3855 | } | ||
| 3856 | case IIS_APPPOOL_MANAGED_PIPELINE_MODE: | ||
| 3857 | { | ||
| 3858 | // managedPipelineMode | ||
| 3859 | hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzData); | ||
| 3860 | ExitOnFailure(hr, "Failed to read AppPool managedRuntimeVersion"); | ||
| 3861 | hr = Iis7PutPropertyString(pAppPoolElement, IIS_CONFIG_PIPELINEMODE, pwzData); | ||
| 3862 | ExitOnFailure(hr, "Failed set AppPool managedPipelineMode property"); | ||
| 3863 | break; | ||
| 3864 | } | ||
| 3865 | case IIS_APPPOOL_MANAGED_RUNTIME_VERSION: | ||
| 3866 | { | ||
| 3867 | // managedRuntimeVersion | ||
| 3868 | hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzData); | ||
| 3869 | ExitOnFailure(hr, "Failed to read AppPool managedRuntimeVersion"); | ||
| 3870 | hr = Iis7PutPropertyString(pAppPoolElement, IIS_CONFIG_MANAGEDRUNTIMEVERSION, pwzData); | ||
| 3871 | ExitOnFailure(hr, "Failed set AppPool managedRuntimeVersion property"); | ||
| 3872 | break; | ||
| 3873 | } | ||
| 3874 | |||
| 3875 | default: | ||
| 3876 | ExitOnFailure(hr = E_UNEXPECTED, "Unexpected IIS Config action specified for AppPool"); | ||
| 3877 | break; | ||
| 3878 | |||
| 3879 | } | ||
| 3880 | // Get AppPool property action | ||
| 3881 | hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iAction); | ||
| 3882 | ExitOnFailure(hr, "Failed to read AppPool Property action"); | ||
| 3883 | } | ||
| 3884 | |||
| 3885 | LExit: | ||
| 3886 | ReleaseObject(pAppPools); | ||
| 3887 | ReleaseObject(pCollection); | ||
| 3888 | ReleaseObject(pCollection2); | ||
| 3889 | ReleaseObject(pAppPoolElement); | ||
| 3890 | ReleaseObject(pElement); | ||
| 3891 | ReleaseObject(pElement2); | ||
| 3892 | ReleaseObject(pElement3); | ||
| 3893 | |||
| 3894 | return hr; | ||
| 3895 | } | ||
| 3896 | |||
| 3897 | static HRESULT SetDirPropAuthentications(IAppHostWritableAdminManager *pAdminMgr, | ||
| 3898 | LPCWSTR wszConfigPath, | ||
| 3899 | DWORD dwData) | ||
| 3900 | { | ||
| 3901 | HRESULT hr = S_OK; | ||
| 3902 | IAppHostElement *pSection = NULL; | ||
| 3903 | |||
| 3904 | //dwData contains bit flags for /security/authentication/<...> | ||
| 3905 | // Anonymous = 1 | ||
| 3906 | // Basic = 2 | ||
| 3907 | // Windows = 4 | ||
| 3908 | // Digest =16 | ||
| 3909 | // Passport =64 *not supported | ||
| 3910 | //translation required from bit map to section name | ||
| 3911 | // E.G security/authentication/windowsAuthentication [property enabled true|false] | ||
| 3912 | |||
| 3913 | // AnonymousAuthentication = 1 | ||
| 3914 | hr = pAdminMgr->GetAdminSection(ScopeBSTR(L"system.webServer/security/authentication/anonymousAuthentication"), ScopeBSTR(wszConfigPath), &pSection); | ||
| 3915 | ExitOnFailure(hr, "Failed get AnonymousAuthentication section for DirProp"); | ||
| 3916 | if (!pSection) | ||
| 3917 | { | ||
| 3918 | hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); | ||
| 3919 | ExitOnFailure(hr, "Failed get AnonymousAuthentication section object for DirProps"); | ||
| 3920 | } | ||
| 3921 | |||
| 3922 | hr = Iis7PutPropertyBool(pSection, L"enabled", (BOOL)(dwData & 0x1)); | ||
| 3923 | ExitOnFailure(hr, "Failed set AnonymousAuthentication enabled for DirProps"); | ||
| 3924 | ReleaseNullObject(pSection); | ||
| 3925 | |||
| 3926 | // basicAuthentication = 2 | ||
| 3927 | hr = pAdminMgr->GetAdminSection(ScopeBSTR(L"system.webServer/security/authentication/basicAuthentication"), ScopeBSTR(wszConfigPath), &pSection); | ||
| 3928 | ExitOnFailure(hr, "Failed get basicAuthentication section for DirProp"); | ||
| 3929 | if (!pSection) | ||
| 3930 | { | ||
| 3931 | hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); | ||
| 3932 | ExitOnFailure(hr, "Failed get basicAuthentication section object for DirProps"); | ||
| 3933 | } | ||
| 3934 | |||
| 3935 | hr = Iis7PutPropertyBool(pSection, L"enabled", (BOOL)(dwData & 0x2)); | ||
| 3936 | ExitOnFailure(hr, "Failed set basicAuthentication enabled for DirProps"); | ||
| 3937 | ReleaseNullObject(pSection); | ||
| 3938 | |||
| 3939 | // WindowsAuthentication = 4 | ||
| 3940 | hr = pAdminMgr->GetAdminSection(ScopeBSTR(L"system.webServer/security/authentication/windowsAuthentication"), ScopeBSTR(wszConfigPath), &pSection); | ||
| 3941 | ExitOnFailure(hr, "Failed get windowsAuthentication section for DirProp"); | ||
| 3942 | if (!pSection) | ||
| 3943 | { | ||
| 3944 | hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); | ||
| 3945 | ExitOnFailure(hr, "Failed get windowsAuthentication section object for DirProps"); | ||
| 3946 | } | ||
| 3947 | |||
| 3948 | hr = Iis7PutPropertyBool(pSection, L"enabled", (BOOL)(dwData & 0x4)); | ||
| 3949 | ExitOnFailure(hr, "Failed set windowsAuthentication enabled for DirProps"); | ||
| 3950 | ReleaseNullObject(pSection); | ||
| 3951 | |||
| 3952 | // digestAuthentication = 16 | ||
| 3953 | hr = pAdminMgr->GetAdminSection(ScopeBSTR(L"system.webServer/security/authentication/digestAuthentication"), ScopeBSTR(wszConfigPath), &pSection); | ||
| 3954 | ExitOnFailure(hr, "Failed get digestAuthentication section for DirProp"); | ||
| 3955 | if (!pSection) | ||
| 3956 | { | ||
| 3957 | hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); | ||
| 3958 | ExitOnFailure(hr, "Failed get digestAuthentication section object for DirProps"); | ||
| 3959 | } | ||
| 3960 | |||
| 3961 | hr = Iis7PutPropertyBool(pSection, L"enabled", (BOOL)(dwData & 0x10)); | ||
| 3962 | ExitOnFailure(hr, "Failed set digestAuthentication enabled for DirProps"); | ||
| 3963 | ReleaseNullObject(pSection); | ||
| 3964 | |||
| 3965 | LExit: | ||
| 3966 | ReleaseObject(pSection); | ||
| 3967 | |||
| 3968 | return hr; | ||
| 3969 | } | ||
| 3970 | |||
| 3971 | static HRESULT SetDirPropAuthProvider(IAppHostWritableAdminManager *pAdminMgr, | ||
| 3972 | LPCWSTR wszConfigPath, | ||
| 3973 | __in LPWSTR wszData) | ||
| 3974 | { | ||
| 3975 | HRESULT hr = S_OK; | ||
| 3976 | IAppHostElement *pSection = NULL; | ||
| 3977 | IAppHostElement *pElement = NULL; | ||
| 3978 | IAppHostElement *pNewElement = NULL; | ||
| 3979 | IAppHostElementCollection *pCollection = NULL; | ||
| 3980 | |||
| 3981 | WCHAR wcDelim[] = L","; | ||
| 3982 | const WCHAR *wszToken = NULL; | ||
| 3983 | WCHAR *wszNextToken = NULL; | ||
| 3984 | |||
| 3985 | hr = pAdminMgr->GetAdminSection(ScopeBSTR(L"system.webServer/security/authentication/windowsAuthentication"), ScopeBSTR(wszConfigPath), &pSection); | ||
| 3986 | ExitOnFailure(hr, "Failed get windowsAuthentication section for DirProp providers"); | ||
| 3987 | |||
| 3988 | hr = pSection->GetElementByName(ScopeBSTR(L"providers"), &pElement); | ||
| 3989 | ExitOnFailure(hr, "Failed get win auth providers section"); | ||
| 3990 | |||
| 3991 | hr = pElement->get_Collection(&pCollection); | ||
| 3992 | ExitOnFailure(hr, "Failed get win auth providers collection"); | ||
| 3993 | |||
| 3994 | hr = pCollection->Clear(); | ||
| 3995 | ExitOnFailure(hr, "Failed to clear win auth providers collection"); | ||
| 3996 | |||
| 3997 | //Clear out inherited items - add clear | ||
| 3998 | hr = pCollection->CreateNewElement(ScopeBSTR(IIS_CONFIG_CLEAR), &pNewElement); | ||
| 3999 | ExitOnFailure(hr, "Failed to create win auth providers clear element"); | ||
| 4000 | hr = pCollection->AddElement(pNewElement); | ||
| 4001 | ExitOnFailure(hr, "Failed to add win auth providers clear element"); | ||
| 4002 | ReleaseNullObject(pNewElement); | ||
| 4003 | |||
| 4004 | wszToken = wcstok_s( wszData, wcDelim, &wszNextToken); | ||
| 4005 | for (int i = 0; (wszToken); ++i) | ||
| 4006 | { | ||
| 4007 | hr = pCollection->CreateNewElement(ScopeBSTR(IIS_CONFIG_ADD), &pNewElement); | ||
| 4008 | ExitOnFailure(hr, "Failed to create win auth providers element"); | ||
| 4009 | |||
| 4010 | hr = Iis7PutPropertyString( pNewElement, IIS_CONFIG_VALUE, wszToken); | ||
| 4011 | ExitOnFailure(hr, "Failed to set win auth providers value"); | ||
| 4012 | |||
| 4013 | hr = pCollection->AddElement(pNewElement, i); | ||
| 4014 | ExitOnFailure(hr, "Failed to add win auth providers element"); | ||
| 4015 | ReleaseNullObject(pNewElement); | ||
| 4016 | |||
| 4017 | wszToken = wcstok_s( NULL, wcDelim, &wszNextToken); | ||
| 4018 | } | ||
| 4019 | |||
| 4020 | LExit: | ||
| 4021 | ReleaseObject(pSection); | ||
| 4022 | ReleaseObject(pCollection); | ||
| 4023 | ReleaseObject(pElement); | ||
| 4024 | ReleaseObject(pNewElement); | ||
| 4025 | |||
| 4026 | return hr; | ||
| 4027 | } | ||
| 4028 | |||
| 4029 | static HRESULT SetDirPropDefDoc( | ||
| 4030 | IAppHostWritableAdminManager *pAdminMgr, | ||
| 4031 | LPCWSTR wszConfigPath, | ||
| 4032 | __in LPWSTR wszData) | ||
| 4033 | { | ||
| 4034 | HRESULT hr = S_OK; | ||
| 4035 | IAppHostElement *pSection = NULL; | ||
| 4036 | IAppHostElement *pElement = NULL; | ||
| 4037 | IAppHostElement *pNewElement = NULL; | ||
| 4038 | IAppHostElementCollection *pCollection = NULL; | ||
| 4039 | |||
| 4040 | WCHAR wcDelim[] = L","; | ||
| 4041 | const WCHAR *wszToken = NULL; | ||
| 4042 | WCHAR *wszNextToken = NULL; | ||
| 4043 | |||
| 4044 | hr = pAdminMgr->GetAdminSection(ScopeBSTR(IIS_CONFIG_DEFAULTDOC_SECTION), ScopeBSTR(wszConfigPath), &pSection); | ||
| 4045 | ExitOnFailure(hr, "Failed get defaultDocument section for DirProp"); | ||
| 4046 | |||
| 4047 | hr = pSection->GetElementByName(ScopeBSTR(L"files"), &pElement); | ||
| 4048 | ExitOnFailure(hr, "Failed get win files section"); | ||
| 4049 | |||
| 4050 | hr = pElement->get_Collection(&pCollection); | ||
| 4051 | ExitOnFailure(hr, "Failed get files collection"); | ||
| 4052 | |||
| 4053 | hr = pCollection->Clear(); | ||
| 4054 | ExitOnFailure(hr, "Failed clear files collection"); | ||
| 4055 | |||
| 4056 | //Clear out inherited items - add clear | ||
| 4057 | hr = pCollection->CreateNewElement(ScopeBSTR(IIS_CONFIG_CLEAR), &pNewElement); | ||
| 4058 | ExitOnFailure(hr, "Failed to create files clear element"); | ||
| 4059 | hr = pCollection->AddElement(pNewElement); | ||
| 4060 | ExitOnFailure(hr, "Failed to add files clear element"); | ||
| 4061 | |||
| 4062 | wszToken = wcstok_s( wszData, wcDelim, &wszNextToken); | ||
| 4063 | for (int i = 0; (wszToken); ++i) | ||
| 4064 | { | ||
| 4065 | hr = pCollection->CreateNewElement(ScopeBSTR(IIS_CONFIG_ADD), &pNewElement); | ||
| 4066 | ExitOnFailure(hr, "Failed to create win auth providers element"); | ||
| 4067 | |||
| 4068 | hr = Iis7PutPropertyString( pNewElement, IIS_CONFIG_VALUE, wszToken); | ||
| 4069 | ExitOnFailure(hr, "Failed to set win auth providers value"); | ||
| 4070 | |||
| 4071 | hr = pCollection->AddElement(pNewElement, i); | ||
| 4072 | ExitOnFailure(hr, "Failed to add defaultDocument Files element"); | ||
| 4073 | ReleaseNullObject(pNewElement); | ||
| 4074 | |||
| 4075 | wszToken = wcstok_s( NULL, wcDelim, &wszNextToken); | ||
| 4076 | } | ||
| 4077 | |||
| 4078 | LExit: | ||
| 4079 | ReleaseObject(pSection); | ||
| 4080 | ReleaseObject(pCollection); | ||
| 4081 | ReleaseObject(pNewElement); | ||
| 4082 | |||
| 4083 | return hr; | ||
| 4084 | } | ||
| 4085 | |||
| 4086 | static HRESULT ClearLocationTag( | ||
| 4087 | IAppHostWritableAdminManager *pAdminMgr, | ||
| 4088 | LPCWSTR swLocationPath | ||
| 4089 | ) | ||
| 4090 | { | ||
| 4091 | HRESULT hr = S_OK; | ||
| 4092 | IAppHostConfigManager *pConfigMgr = NULL; | ||
| 4093 | IAppHostConfigFile *pConfigFile = NULL; | ||
| 4094 | IAppHostConfigLocationCollection *pLocationCollection = NULL; | ||
| 4095 | IAppHostConfigLocation *pLocation = NULL; | ||
| 4096 | |||
| 4097 | DWORD dwCount = 0; | ||
| 4098 | BSTR bstrLocationPath = NULL; | ||
| 4099 | |||
| 4100 | hr = pAdminMgr->get_ConfigManager(&pConfigMgr); | ||
| 4101 | ExitOnFailure(hr, "Failed to get IIS ConfigManager interface"); | ||
| 4102 | |||
| 4103 | hr = pConfigMgr->GetConfigFile(ScopeBSTR(IIS_CONFIG_APPHOST_ROOT), &pConfigFile); | ||
| 4104 | ExitOnFailure(hr, "Failed to get IIS ConfigFile interface"); | ||
| 4105 | |||
| 4106 | hr = pConfigFile->get_Locations(&pLocationCollection); | ||
| 4107 | ExitOnFailure(hr, "Failed to get IIS location tag collection"); | ||
| 4108 | |||
| 4109 | hr = pLocationCollection->get_Count(&dwCount); | ||
| 4110 | ExitOnFailure(hr, "Failed to get IIS location collection count"); | ||
| 4111 | |||
| 4112 | VARIANT vtIndex; | ||
| 4113 | vtIndex.vt = VT_UI4; | ||
| 4114 | for (DWORD i = 0; i < dwCount; ++i) | ||
| 4115 | { | ||
| 4116 | vtIndex.ulVal = i; | ||
| 4117 | hr = pLocationCollection->get_Item(vtIndex, &pLocation); | ||
| 4118 | ExitOnFailure(hr, "Failed to get IIS location collection count"); | ||
| 4119 | |||
| 4120 | hr = pLocation->get_Path(&bstrLocationPath); | ||
| 4121 | if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, swLocationPath, -1, bstrLocationPath, -1)) | ||
| 4122 | { | ||
| 4123 | hr = pLocationCollection->DeleteLocation(vtIndex); | ||
| 4124 | ExitOnFailure(hr, "Failed to delete IIS location tag %ls",swLocationPath); | ||
| 4125 | break; | ||
| 4126 | } | ||
| 4127 | |||
| 4128 | ReleaseNullObject(pLocation); | ||
| 4129 | ::SysFreeString(bstrLocationPath); | ||
| 4130 | bstrLocationPath = NULL; | ||
| 4131 | } | ||
| 4132 | LExit: | ||
| 4133 | ReleaseObject(pConfigMgr); | ||
| 4134 | ReleaseObject(pConfigFile); | ||
| 4135 | ReleaseObject(pLocationCollection); | ||
| 4136 | ReleaseObject(pLocation); | ||
| 4137 | ReleaseBSTR(bstrLocationPath); | ||
| 4138 | |||
| 4139 | return hr; | ||
| 4140 | |||
| 4141 | } | ||
| 4142 | |||
| 4143 | static HRESULT DeleteCollectionElement( | ||
| 4144 | __in IAppHostElementCollection *pCollection, | ||
| 4145 | __in LPCWSTR pwzElementName, | ||
| 4146 | __in LPCWSTR pwzAttributeName, | ||
| 4147 | __in LPCWSTR pwzAttributeValue | ||
| 4148 | ) | ||
| 4149 | { | ||
| 4150 | HRESULT hr = S_OK; | ||
| 4151 | |||
| 4152 | DWORD dwIndex; | ||
| 4153 | VARIANT vtIndex; | ||
| 4154 | VariantInit(&vtIndex); | ||
| 4155 | |||
| 4156 | hr = Iis7FindAppHostElementString(pCollection, pwzElementName, pwzAttributeName, pwzAttributeValue, NULL, &dwIndex); | ||
| 4157 | ExitOnFailure(hr, "Failed while finding IAppHostElement %ls/@%ls=%ls", pwzElementName, pwzAttributeName, pwzAttributeValue); | ||
| 4158 | |||
| 4159 | if (MAXDWORD != dwIndex) | ||
| 4160 | { | ||
| 4161 | vtIndex.vt = VT_UI4; | ||
| 4162 | vtIndex.ulVal = dwIndex; | ||
| 4163 | hr = pCollection->DeleteElement(vtIndex); | ||
| 4164 | ExitOnFailure(hr, "Failed to delete IAppHostElement %ls/@%ls=%ls", pwzElementName, pwzAttributeName, pwzAttributeValue); | ||
| 4165 | } | ||
| 4166 | // else : nothing to do, already deleted | ||
| 4167 | LExit: | ||
| 4168 | ReleaseVariant(vtIndex); | ||
| 4169 | |||
| 4170 | return hr; | ||
| 4171 | } | ||
| 4172 | static void ConvSecToHMS( int Sec, __out_ecount(cchDest) LPWSTR wcTime, size_t cchDest) | ||
| 4173 | { | ||
| 4174 | int ZH, ZM, ZS = 0; | ||
| 4175 | |||
| 4176 | ZH = (Sec / 3600); | ||
| 4177 | Sec = Sec - ZH * 3600; | ||
| 4178 | ZM = (Sec / 60) ; | ||
| 4179 | Sec = Sec - ZM * 60; | ||
| 4180 | ZS = Sec ; | ||
| 4181 | |||
| 4182 | HRESULT hr = ::StringCchPrintfW(wcTime, cchDest, L"%02d:%02d:%02d", ZH, ZM, ZS); | ||
| 4183 | if (S_OK != hr) | ||
| 4184 | { | ||
| 4185 | *wcTime = '\0'; | ||
| 4186 | } | ||
| 4187 | } | ||
| 4188 | static void ConvSecToDHMS( unsigned int Sec, __out_ecount(cchDest) LPWSTR wcTime, size_t cchDest) | ||
| 4189 | { | ||
| 4190 | int ZD, ZH, ZM, ZS = 0; | ||
| 4191 | |||
| 4192 | ZD = Sec / 86400; | ||
| 4193 | Sec = Sec - ZD * 86400; | ||
| 4194 | ZH = (Sec / 3600); | ||
| 4195 | Sec = Sec - ZH * 3600; | ||
| 4196 | ZM = (Sec / 60) ; | ||
| 4197 | Sec = Sec - ZM * 60; | ||
| 4198 | ZS = Sec ; | ||
| 4199 | |||
| 4200 | HRESULT hr = ::StringCchPrintfW(wcTime, cchDest, L"%d.%02d:%02d:%02d", ZD, ZH, ZM, ZS); | ||
| 4201 | if (S_OK != hr) | ||
| 4202 | { | ||
| 4203 | *wcTime = '\0'; | ||
| 4204 | } | ||
| 4205 | } | ||
diff --git a/src/ca/scaexecIIS7.h b/src/ca/scaexecIIS7.h new file mode 100644 index 00000000..ec31f202 --- /dev/null +++ b/src/ca/scaexecIIS7.h | |||
| @@ -0,0 +1,5 @@ | |||
| 1 | #pragma once | ||
| 2 | // 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. | ||
| 3 | |||
| 4 | |||
| 5 | HRESULT IIS7ConfigChanges(MSIHANDLE hInstall, __inout LPWSTR pwzData); | ||
diff --git a/src/ca/scafilter.cpp b/src/ca/scafilter.cpp new file mode 100644 index 00000000..9d9014fd --- /dev/null +++ b/src/ca/scafilter.cpp | |||
| @@ -0,0 +1,510 @@ | |||
| 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 | #include "precomp.h" | ||
| 4 | |||
| 5 | // prototypes | ||
| 6 | static HRESULT ReadFilterLoadOrder( | ||
| 7 | __in IMSAdminBase* piMetabase, | ||
| 8 | __in LPCWSTR wzFilterRoot, | ||
| 9 | __out LPWSTR *ppwzLoadOrder | ||
| 10 | ); | ||
| 11 | static HRESULT AddFilterToLoadOrder( | ||
| 12 | __in LPCWSTR wzFilter, | ||
| 13 | __in int iLoadOrder, | ||
| 14 | __inout LPWSTR *ppwzLoadOrder | ||
| 15 | ); | ||
| 16 | static HRESULT RemoveFilterFromLoadOrder( | ||
| 17 | __in LPCWSTR wzFilter, | ||
| 18 | __inout LPWSTR *ppwzLoadOrder | ||
| 19 | ); | ||
| 20 | |||
| 21 | |||
| 22 | UINT __stdcall ScaFiltersRead( | ||
| 23 | __in IMSAdminBase* piMetabase, | ||
| 24 | __in SCA_WEB* pswList, | ||
| 25 | __in WCA_WRAPQUERY_HANDLE hWebBaseQuery, | ||
| 26 | __inout SCA_FILTER** ppsfList, | ||
| 27 | __inout LPWSTR *ppwzCustomActionData | ||
| 28 | ) | ||
| 29 | { | ||
| 30 | HRESULT hr = S_OK; | ||
| 31 | MSIHANDLE hRec; | ||
| 32 | INSTALLSTATE isInstalled = INSTALLSTATE_UNKNOWN; | ||
| 33 | INSTALLSTATE isAction = INSTALLSTATE_UNKNOWN; | ||
| 34 | |||
| 35 | LPWSTR pwzData = NULL; | ||
| 36 | |||
| 37 | SCA_FILTER* psf = NULL; | ||
| 38 | WCA_WRAPQUERY_HANDLE hWrapQuery = NULL; | ||
| 39 | |||
| 40 | hr = WcaBeginUnwrapQuery(&hWrapQuery, ppwzCustomActionData); | ||
| 41 | ExitOnFailure(hr, "Failed to unwrap query for ScaAppPoolRead"); | ||
| 42 | |||
| 43 | if (0 == WcaGetQueryRecords(hWrapQuery)) | ||
| 44 | { | ||
| 45 | WcaLog(LOGMSG_VERBOSE, "Skipping ScaFiltersRead() - no IIsFilter table"); | ||
| 46 | ExitFunction1(hr = S_FALSE); | ||
| 47 | } | ||
| 48 | |||
| 49 | // loop through all the filters | ||
| 50 | while (S_OK == (hr = WcaFetchWrappedRecord(hWrapQuery, &hRec))) | ||
| 51 | { | ||
| 52 | // Get the Component first. If the component is not being modified during | ||
| 53 | // this transaction, skip processing this whole record. | ||
| 54 | hr = WcaGetRecordString(hRec, fqComponent, &pwzData); | ||
| 55 | ExitOnFailure(hr, "failed to get IIsFilter.Component"); | ||
| 56 | |||
| 57 | hr = WcaGetRecordInteger(hRec, fqInstalled, (int *)&isInstalled); | ||
| 58 | ExitOnFailure(hr, "Failed to get Component installed state for IIs filter"); | ||
| 59 | |||
| 60 | hr = WcaGetRecordInteger(hRec, fqAction, (int *)&isAction); | ||
| 61 | ExitOnFailure(hr, "Failed to get Component action state for IIs filter"); | ||
| 62 | |||
| 63 | if (!WcaIsInstalling(isInstalled, isAction) && | ||
| 64 | !WcaIsReInstalling(isInstalled, isAction) && | ||
| 65 | !WcaIsUninstalling(isInstalled, isAction)) | ||
| 66 | { | ||
| 67 | continue; // skip this record. | ||
| 68 | } | ||
| 69 | |||
| 70 | hr = AddFilterToList(ppsfList); | ||
| 71 | ExitOnFailure(hr, "failed to add filter to list"); | ||
| 72 | |||
| 73 | psf = *ppsfList; | ||
| 74 | |||
| 75 | hr = ::StringCchCopyW(psf->wzComponent, countof(psf->wzComponent), pwzData); | ||
| 76 | ExitOnFailure(hr, "failed to copy component name: %ls", pwzData); | ||
| 77 | |||
| 78 | psf->isInstalled = isInstalled; | ||
| 79 | psf->isAction = isAction; | ||
| 80 | |||
| 81 | hr = WcaGetRecordString(hRec, fqWeb, &pwzData); | ||
| 82 | ExitOnFailure(hr, "Failed to get Web for VirtualDir"); | ||
| 83 | |||
| 84 | if (*pwzData) | ||
| 85 | { | ||
| 86 | hr = ScaWebsGetBase(piMetabase, pswList, pwzData, psf->wzWebBase, countof(psf->wzWebBase), hWebBaseQuery); | ||
| 87 | if (FAILED(hr) && WcaIsUninstalling(isInstalled, isAction)) | ||
| 88 | { | ||
| 89 | // If we're uninstalling, don't bother finding the existing web, just leave the filter root empty | ||
| 90 | hr = S_OK; | ||
| 91 | } | ||
| 92 | ExitOnFailure(hr, "Failed to get base of web for Filter"); | ||
| 93 | |||
| 94 | if (0 != lstrlenW(psf->wzWebBase)) | ||
| 95 | { | ||
| 96 | hr = ::StringCchPrintfW(psf->wzFilterRoot, countof(psf->wzFilterRoot), L"%s/Filters", psf->wzWebBase); | ||
| 97 | ExitOnFailure(hr, "Failed to allocate filter base string"); | ||
| 98 | } | ||
| 99 | } | ||
| 100 | else | ||
| 101 | { | ||
| 102 | hr = ::StringCchCopyW(psf->wzFilterRoot, countof(psf->wzFilterRoot), L"/LM/W3SVC/Filters"); | ||
| 103 | ExitOnFailure(hr, "Failed to allocate global filter base string"); | ||
| 104 | } | ||
| 105 | |||
| 106 | // filter key | ||
| 107 | hr = WcaGetRecordString(hRec, fqFilter, &pwzData); | ||
| 108 | ExitOnFailure(hr, "Failed to get Filter.Filter"); | ||
| 109 | hr = ::StringCchCopyW(psf->wzKey, countof(psf->wzKey), pwzData); | ||
| 110 | ExitOnFailure(hr, "Failed to copy key string to filter object"); | ||
| 111 | |||
| 112 | // filter path | ||
| 113 | hr = WcaGetRecordString(hRec, fqPath, &pwzData); | ||
| 114 | ExitOnFailure(hr, "Failed to get Filter.Path"); | ||
| 115 | hr = ::StringCchCopyW(psf->wzPath, countof(psf->wzPath), pwzData); | ||
| 116 | ExitOnFailure(hr, "Failed to copy path string to filter object"); | ||
| 117 | |||
| 118 | // filter description | ||
| 119 | hr = WcaGetRecordString(hRec, fqDescription, &pwzData); | ||
| 120 | ExitOnFailure(hr, "Failed to get Filter.Description"); | ||
| 121 | hr = ::StringCchCopyW(psf->wzDescription, countof(psf->wzDescription), pwzData); | ||
| 122 | ExitOnFailure(hr, "Failed to copy description string to filter object"); | ||
| 123 | |||
| 124 | // filter flags | ||
| 125 | hr = WcaGetRecordInteger(hRec, fqFlags, &psf->iFlags); | ||
| 126 | ExitOnFailure(hr, "Failed to get Filter.Flags"); | ||
| 127 | |||
| 128 | // filter load order | ||
| 129 | hr = WcaGetRecordInteger(hRec, fqLoadOrder, &psf->iLoadOrder); | ||
| 130 | ExitOnFailure(hr, "Failed to get Filter.LoadOrder"); | ||
| 131 | } | ||
| 132 | |||
| 133 | if (E_NOMOREITEMS == hr) | ||
| 134 | { | ||
| 135 | hr = S_OK; | ||
| 136 | } | ||
| 137 | ExitOnFailure(hr, "Failure while processing filters"); | ||
| 138 | |||
| 139 | LExit: | ||
| 140 | WcaFinishUnwrapQuery(hWrapQuery); | ||
| 141 | |||
| 142 | ReleaseStr(pwzData); | ||
| 143 | return hr; | ||
| 144 | } | ||
| 145 | |||
| 146 | |||
| 147 | HRESULT ScaFiltersInstall( | ||
| 148 | __in IMSAdminBase* piMetabase, | ||
| 149 | __in SCA_FILTER* psfList | ||
| 150 | ) | ||
| 151 | { | ||
| 152 | HRESULT hr = S_OK; | ||
| 153 | SCA_FILTER* psf = psfList; | ||
| 154 | LPCWSTR wzPreviousFilterRoot = NULL; | ||
| 155 | LPWSTR pwzLoadOrder = NULL; | ||
| 156 | |||
| 157 | while (psf) | ||
| 158 | { | ||
| 159 | if (WcaIsInstalling(psf->isInstalled, psf->isAction)) | ||
| 160 | { | ||
| 161 | if (!wzPreviousFilterRoot || CSTR_EQUAL != ::CompareStringW(LOCALE_INVARIANT, 0, wzPreviousFilterRoot, -1, psf->wzFilterRoot, -1)) | ||
| 162 | { | ||
| 163 | if (pwzLoadOrder) | ||
| 164 | { | ||
| 165 | hr = ScaWriteMetabaseValue(piMetabase, wzPreviousFilterRoot, L"", MD_FILTER_LOAD_ORDER, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, (LPVOID)pwzLoadOrder); | ||
| 166 | ExitOnFailure(hr, "Failed to write filter load order to metabase"); | ||
| 167 | |||
| 168 | ReleaseNullStr(pwzLoadOrder); | ||
| 169 | } | ||
| 170 | |||
| 171 | hr = ReadFilterLoadOrder(piMetabase, psf->wzFilterRoot, &pwzLoadOrder); | ||
| 172 | ExitOnFailure(hr, "Failed to read filter load order."); | ||
| 173 | |||
| 174 | wzPreviousFilterRoot = psf->wzFilterRoot; | ||
| 175 | } | ||
| 176 | |||
| 177 | hr = ScaCreateMetabaseKey(piMetabase, psf->wzFilterRoot, psf->wzKey); | ||
| 178 | ExitOnFailure(hr, "Failed to create key for filter '%ls'", psf->wzKey); | ||
| 179 | |||
| 180 | hr = ScaWriteMetabaseValue(piMetabase, psf->wzFilterRoot, psf->wzKey, MD_KEY_TYPE, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, (LPVOID)L"IIsFilter"); | ||
| 181 | ExitOnFailure(hr, "Failed to write key type for filter '%ls'", psf->wzKey); | ||
| 182 | |||
| 183 | // filter path | ||
| 184 | hr = ScaWriteMetabaseValue(piMetabase, psf->wzFilterRoot, psf->wzKey, MD_FILTER_IMAGE_PATH, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, (LPVOID)psf->wzPath); | ||
| 185 | ExitOnFailure(hr, "Failed to write Path for filter '%ls'", psf->wzKey); | ||
| 186 | |||
| 187 | // filter description | ||
| 188 | hr = ScaWriteMetabaseValue(piMetabase, psf->wzFilterRoot, psf->wzKey, MD_FILTER_DESCRIPTION, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, (LPVOID)psf->wzDescription); | ||
| 189 | ExitOnFailure(hr, "Failed to write Description for filter '%ls'", psf->wzKey); | ||
| 190 | |||
| 191 | // filter flags | ||
| 192 | if (MSI_NULL_INTEGER != psf->iFlags) | ||
| 193 | { | ||
| 194 | hr = ScaWriteMetabaseValue(piMetabase, psf->wzFilterRoot, psf->wzKey, MD_FILTER_FLAGS, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, (LPVOID)((DWORD_PTR)psf->iFlags)); | ||
| 195 | ExitOnFailure(hr, "Failed to write Flags for filter '%ls'", psf->wzKey); | ||
| 196 | } | ||
| 197 | |||
| 198 | // filter load order | ||
| 199 | if (MSI_NULL_INTEGER != psf->iLoadOrder) | ||
| 200 | { | ||
| 201 | hr = AddFilterToLoadOrder(psf->wzKey, psf->iLoadOrder, &pwzLoadOrder); | ||
| 202 | ExitOnFailure(hr, "Failed to add filter '%ls' to load order.", psf->wzKey); | ||
| 203 | } | ||
| 204 | } | ||
| 205 | |||
| 206 | psf = psf->psfNext; | ||
| 207 | } | ||
| 208 | |||
| 209 | if (pwzLoadOrder) | ||
| 210 | { | ||
| 211 | Assert(wzPreviousFilterRoot && *wzPreviousFilterRoot); | ||
| 212 | |||
| 213 | hr = ScaWriteMetabaseValue(piMetabase, wzPreviousFilterRoot, L"", MD_FILTER_LOAD_ORDER, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, (LPVOID)pwzLoadOrder); | ||
| 214 | ExitOnFailure(hr, "Failed to write filter load order to metabase"); | ||
| 215 | } | ||
| 216 | |||
| 217 | LExit: | ||
| 218 | ReleaseStr(pwzLoadOrder); | ||
| 219 | return hr; | ||
| 220 | } | ||
| 221 | |||
| 222 | |||
| 223 | HRESULT ScaFiltersUninstall( | ||
| 224 | __in IMSAdminBase* piMetabase, | ||
| 225 | __in SCA_FILTER* psfList | ||
| 226 | ) | ||
| 227 | { | ||
| 228 | HRESULT hr = S_OK; | ||
| 229 | SCA_FILTER* psf = psfList; | ||
| 230 | LPCWSTR wzPreviousFilterRoot = NULL; | ||
| 231 | LPWSTR pwzLoadOrder = NULL; | ||
| 232 | |||
| 233 | while (psf) | ||
| 234 | { | ||
| 235 | if (WcaIsUninstalling(psf->isInstalled, psf->isAction)) | ||
| 236 | { | ||
| 237 | if (!wzPreviousFilterRoot || CSTR_EQUAL != ::CompareStringW(LOCALE_INVARIANT, 0, wzPreviousFilterRoot, -1, psf->wzFilterRoot, -1)) | ||
| 238 | { | ||
| 239 | if (pwzLoadOrder) | ||
| 240 | { | ||
| 241 | hr = ScaWriteMetabaseValue(piMetabase, wzPreviousFilterRoot, L"", MD_FILTER_LOAD_ORDER, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, (LPVOID)pwzLoadOrder); | ||
| 242 | ExitOnFailure(hr, "Failed to write filter load order to metabase"); | ||
| 243 | |||
| 244 | ReleaseNullStr(pwzLoadOrder); | ||
| 245 | } | ||
| 246 | |||
| 247 | hr = ReadFilterLoadOrder(piMetabase, psf->wzFilterRoot, &pwzLoadOrder); | ||
| 248 | ExitOnFailure(hr, "Failed to read filter load order."); | ||
| 249 | |||
| 250 | wzPreviousFilterRoot = psf->wzFilterRoot; | ||
| 251 | } | ||
| 252 | |||
| 253 | hr = RemoveFilterFromLoadOrder(psf->wzKey, &pwzLoadOrder); | ||
| 254 | ExitOnFailure(hr, "Failed to remove filter '%ls' from load order", psf->wzKey); | ||
| 255 | |||
| 256 | // remove the filter from the load order and remove the filter's key | ||
| 257 | if (0 != lstrlenW(psf->wzFilterRoot)) | ||
| 258 | { | ||
| 259 | hr = ScaDeleteMetabaseKey(piMetabase, psf->wzFilterRoot, psf->wzKey); | ||
| 260 | ExitOnFailure(hr, "Failed to remove web '%ls' from metabase", psf->wzKey); | ||
| 261 | } | ||
| 262 | } | ||
| 263 | |||
| 264 | psf = psf->psfNext; | ||
| 265 | } | ||
| 266 | |||
| 267 | if (pwzLoadOrder) | ||
| 268 | { | ||
| 269 | Assert(wzPreviousFilterRoot && *wzPreviousFilterRoot); | ||
| 270 | |||
| 271 | hr = ScaWriteMetabaseValue(piMetabase, wzPreviousFilterRoot, L"", MD_FILTER_LOAD_ORDER, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, (LPVOID)pwzLoadOrder); | ||
| 272 | ExitOnFailure(hr, "Failed to write filter load order to metabase"); | ||
| 273 | } | ||
| 274 | |||
| 275 | LExit: | ||
| 276 | return hr; | ||
| 277 | } | ||
| 278 | |||
| 279 | |||
| 280 | void ScaFiltersFreeList( | ||
| 281 | __in SCA_FILTER* psfList | ||
| 282 | ) | ||
| 283 | { | ||
| 284 | SCA_FILTER* psfDelete = psfList; | ||
| 285 | while (psfList) | ||
| 286 | { | ||
| 287 | psfDelete = psfList; | ||
| 288 | psfList = psfList->psfNext; | ||
| 289 | |||
| 290 | MemFree(psfDelete); | ||
| 291 | } | ||
| 292 | } | ||
| 293 | |||
| 294 | HRESULT AddFilterToList( | ||
| 295 | __inout SCA_FILTER** ppsfList) | ||
| 296 | { | ||
| 297 | HRESULT hr = S_OK; | ||
| 298 | SCA_FILTER* psf = static_cast<SCA_FILTER*>(MemAlloc(sizeof(SCA_FILTER), TRUE)); | ||
| 299 | ExitOnNull(psf, hr, E_OUTOFMEMORY, "failed to add filter to filter list"); | ||
| 300 | |||
| 301 | psf->psfNext = *ppsfList; | ||
| 302 | *ppsfList = psf; | ||
| 303 | |||
| 304 | LExit: | ||
| 305 | return hr; | ||
| 306 | } | ||
| 307 | |||
| 308 | // private helper functions | ||
| 309 | |||
| 310 | |||
| 311 | static HRESULT ReadFilterLoadOrder( | ||
| 312 | __in IMSAdminBase* piMetabase, | ||
| 313 | __in LPCWSTR wzFilterRoot, | ||
| 314 | __out LPWSTR *ppwzLoadOrder | ||
| 315 | ) | ||
| 316 | { | ||
| 317 | HRESULT hr = S_OK; | ||
| 318 | METADATA_HANDLE mhRoot = NULL; | ||
| 319 | |||
| 320 | METADATA_RECORD mr; | ||
| 321 | DWORD dwRequired = 0; | ||
| 322 | DWORD cchData = 255; | ||
| 323 | |||
| 324 | ::ZeroMemory(&mr, sizeof(mr)); | ||
| 325 | mr.dwMDIdentifier = MD_FILTER_LOAD_ORDER; | ||
| 326 | mr.dwMDAttributes = METADATA_NO_ATTRIBUTES; | ||
| 327 | mr.dwMDUserType = IIS_MD_UT_SERVER; | ||
| 328 | mr.dwMDDataType = ALL_METADATA; | ||
| 329 | mr.dwMDDataLen = cchData; | ||
| 330 | mr.pbMDData = static_cast<BYTE*>(MemAlloc(mr.dwMDDataLen * sizeof(WCHAR), TRUE)); | ||
| 331 | ExitOnNull(mr.pbMDData, hr, E_OUTOFMEMORY, "failed to allocate memory for MDData in metadata record"); | ||
| 332 | |||
| 333 | hr = piMetabase->OpenKey(METADATA_MASTER_ROOT_HANDLE, wzFilterRoot, METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE, 10, &mhRoot); | ||
| 334 | for (int i = 30; i > 0 && HRESULT_FROM_WIN32(ERROR_PATH_BUSY) == hr; i--) | ||
| 335 | { | ||
| 336 | ::Sleep(1000); | ||
| 337 | WcaLog(LOGMSG_STANDARD, "Failed to open root key, retrying %d time(s)...", i); | ||
| 338 | hr = piMetabase->OpenKey(METADATA_MASTER_ROOT_HANDLE, wzFilterRoot, METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE, 10, &mhRoot); | ||
| 339 | } | ||
| 340 | |||
| 341 | if (SUCCEEDED(hr)) | ||
| 342 | { | ||
| 343 | hr = piMetabase->GetData(mhRoot, L"", &mr, &dwRequired); | ||
| 344 | if (HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER) == hr) | ||
| 345 | { | ||
| 346 | mr.dwMDDataLen = cchData = dwRequired; | ||
| 347 | |||
| 348 | LPVOID pv = MemReAlloc(mr.pbMDData, mr.dwMDDataLen * sizeof(WCHAR), TRUE); | ||
| 349 | ExitOnNull(pv, hr, E_OUTOFMEMORY, "failed to allocate memory for MDData in metadata record"); | ||
| 350 | mr.pbMDData = static_cast<BYTE*>(pv); | ||
| 351 | |||
| 352 | hr = piMetabase->GetData(mhRoot, L"", &mr, &dwRequired); | ||
| 353 | } | ||
| 354 | } | ||
| 355 | |||
| 356 | // The /Filters node or /Filters/FilterLoadOrder property might not exist (yet). | ||
| 357 | if (HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) == hr || MD_ERROR_DATA_NOT_FOUND == hr) | ||
| 358 | { | ||
| 359 | hr = S_OK; | ||
| 360 | } | ||
| 361 | ExitOnFailure(hr, "Failed to get filter load order."); | ||
| 362 | |||
| 363 | hr = StrAllocString(ppwzLoadOrder, reinterpret_cast<LPCWSTR>(mr.pbMDData), 0); | ||
| 364 | ExitOnFailure(hr, "Failed to allocate string for filter load order."); | ||
| 365 | |||
| 366 | LExit: | ||
| 367 | ReleaseMem(mr.pbMDData); | ||
| 368 | |||
| 369 | if (mhRoot) | ||
| 370 | { | ||
| 371 | piMetabase->CloseKey(mhRoot); | ||
| 372 | } | ||
| 373 | |||
| 374 | return hr; | ||
| 375 | } | ||
| 376 | |||
| 377 | |||
| 378 | static HRESULT AddFilterToLoadOrder( | ||
| 379 | __in LPCWSTR wzFilter, | ||
| 380 | __in int iLoadOrder, | ||
| 381 | __inout LPWSTR *ppwzLoadOrder | ||
| 382 | ) | ||
| 383 | { | ||
| 384 | HRESULT hr = S_OK; | ||
| 385 | LPCWSTR wzLoadOrder = *ppwzLoadOrder; | ||
| 386 | int cchFilter = lstrlenW(wzFilter); | ||
| 387 | LPWSTR pwzTemp = NULL; | ||
| 388 | |||
| 389 | // If the filter name ends with '\0' or ',' and | ||
| 390 | // the filter name begins at the beginning of the list or with ',' | ||
| 391 | // Then we've found the exact filter by name. | ||
| 392 | // | ||
| 393 | // If the filter isn't already in the load order, add it | ||
| 394 | if (wzLoadOrder && *wzLoadOrder) | ||
| 395 | { | ||
| 396 | LPCWSTR pwz = wcsstr(wzLoadOrder, wzFilter); | ||
| 397 | |||
| 398 | if (NULL != pwz && | ||
| 399 | (L'\0' == *(pwz + cchFilter) || L',' == *(pwz + cchFilter)) && | ||
| 400 | (pwz == wzLoadOrder || L',' == *(pwz - 1))) | ||
| 401 | { | ||
| 402 | // Filter already in the load order, no work to do. | ||
| 403 | } | ||
| 404 | else | ||
| 405 | { | ||
| 406 | pwz = NULL; | ||
| 407 | if (0 <= iLoadOrder) | ||
| 408 | { | ||
| 409 | pwz = wzLoadOrder; | ||
| 410 | for (int i = 0; i < iLoadOrder && pwz; ++i) | ||
| 411 | { | ||
| 412 | pwz = wcsstr(pwz, L","); | ||
| 413 | } | ||
| 414 | } | ||
| 415 | |||
| 416 | if (NULL == pwz) // put the filter at the end of the order | ||
| 417 | { | ||
| 418 | Assert(wzLoadOrder && *wzLoadOrder); | ||
| 419 | |||
| 420 | // tack on a comma since there are other filters in the order | ||
| 421 | hr = StrAllocConcat(ppwzLoadOrder, L",", 1); | ||
| 422 | ExitOnFailure(hr, "Failed to append a comma to filter load order."); | ||
| 423 | |||
| 424 | hr = StrAllocConcat(ppwzLoadOrder, wzFilter, cchFilter); | ||
| 425 | ExitOnFailure(hr, "Failed to append the filter on to the load order."); | ||
| 426 | } | ||
| 427 | else if (L',' == *pwz) // put the filter in the middle of the order | ||
| 428 | { | ||
| 429 | hr = StrAllocString(&pwzTemp, wzLoadOrder, pwz - wzLoadOrder + 1); | ||
| 430 | ExitOnFailure(hr, "Failed to copy first half of filter load order to temp string."); | ||
| 431 | |||
| 432 | hr = StrAllocConcat(&pwzTemp, wzFilter, 0); | ||
| 433 | ExitOnFailure(hr, "Failed to copy filter into load order."); | ||
| 434 | |||
| 435 | hr = StrAllocConcat(&pwzTemp, pwz, 0); | ||
| 436 | ExitOnFailure(hr, "Failed to copy remaining filter load order back onto load order."); | ||
| 437 | |||
| 438 | hr = StrAllocString(ppwzLoadOrder, pwzTemp, 0); | ||
| 439 | ExitOnFailure(hr, "Failed to copy temp string to load order string."); | ||
| 440 | } | ||
| 441 | else // put the filter at the beginning of the order | ||
| 442 | { | ||
| 443 | hr = StrAllocPrefix(ppwzLoadOrder, L",", 1); | ||
| 444 | ExitOnFailure(hr, "Failed to prepend a comma to filter load order."); | ||
| 445 | |||
| 446 | hr = StrAllocPrefix(ppwzLoadOrder, wzFilter, cchFilter); | ||
| 447 | ExitOnFailure(hr, "Failed to prepend the filter on to the load order."); | ||
| 448 | } | ||
| 449 | } | ||
| 450 | } | ||
| 451 | else | ||
| 452 | { | ||
| 453 | hr = StrAllocString(ppwzLoadOrder, wzFilter, cchFilter); | ||
| 454 | ExitOnFailure(hr, "Failed to add filter to load order."); | ||
| 455 | } | ||
| 456 | |||
| 457 | LExit: | ||
| 458 | ReleaseStr(pwzTemp); | ||
| 459 | return hr; | ||
| 460 | } | ||
| 461 | |||
| 462 | |||
| 463 | static HRESULT RemoveFilterFromLoadOrder( | ||
| 464 | __in LPCWSTR wzFilter, | ||
| 465 | __inout LPWSTR *ppwzLoadOrder | ||
| 466 | ) | ||
| 467 | { | ||
| 468 | HRESULT hr = S_OK; | ||
| 469 | int cchFilter = lstrlenW(wzFilter); | ||
| 470 | |||
| 471 | LPCWSTR pwzStart = NULL; | ||
| 472 | LPWSTR pwzFind = NULL; | ||
| 473 | |||
| 474 | pwzStart = pwzFind = *ppwzLoadOrder; | ||
| 475 | while (NULL != (pwzFind = wcsstr(pwzFind, wzFilter))) | ||
| 476 | { | ||
| 477 | // Make sure to only match [wzFilter] and NOT foo[wzFilter]bar | ||
| 478 | if (pwzFind == pwzStart || L',' == *(pwzFind - 1)) | ||
| 479 | { | ||
| 480 | int cchRemainder = lstrlenW(pwzFind) - cchFilter + 1; // add one to include the null terminator | ||
| 481 | |||
| 482 | if (L'\0' == *(pwzFind + cchFilter)) | ||
| 483 | { | ||
| 484 | if (pwzFind == pwzStart) | ||
| 485 | { | ||
| 486 | memmove(pwzFind, pwzFind + cchFilter, cchRemainder * sizeof(WCHAR)); // copy down the null terminator | ||
| 487 | } | ||
| 488 | else | ||
| 489 | { | ||
| 490 | memmove(pwzFind - 1, pwzFind + cchFilter, cchRemainder * sizeof(WCHAR)); // copy down the null terminator over top the trailing "," | ||
| 491 | } | ||
| 492 | } | ||
| 493 | else if (L',' == *(pwzFind + cchFilter)) | ||
| 494 | { | ||
| 495 | memmove(pwzFind, pwzFind + cchFilter + 1, (cchRemainder - 1) * sizeof(WCHAR)); // skip copying the "," | ||
| 496 | } | ||
| 497 | else // skip past the partial match | ||
| 498 | { | ||
| 499 | pwzFind = pwzFind + cchFilter; | ||
| 500 | } | ||
| 501 | } | ||
| 502 | else // skip past the partial match | ||
| 503 | { | ||
| 504 | pwzFind = pwzFind + cchFilter; | ||
| 505 | } | ||
| 506 | } | ||
| 507 | |||
| 508 | //LExit: | ||
| 509 | return hr; | ||
| 510 | } | ||
diff --git a/src/ca/scafilter.h b/src/ca/scafilter.h new file mode 100644 index 00000000..d072bf22 --- /dev/null +++ b/src/ca/scafilter.h | |||
| @@ -0,0 +1,46 @@ | |||
| 1 | #pragma once | ||
| 2 | // 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. | ||
| 3 | |||
| 4 | |||
| 5 | #include "scaweb.h" | ||
| 6 | |||
| 7 | enum eFilterQuery { fqWeb = 1, fqFilter, fqComponent , fqPath, fqDescription, fqFlags, fqLoadOrder, fqInstalled, fqAction }; | ||
| 8 | |||
| 9 | struct SCA_FILTER | ||
| 10 | { | ||
| 11 | // darwin information | ||
| 12 | WCHAR wzKey[MAX_DARWIN_KEY + 1]; | ||
| 13 | WCHAR wzComponent[MAX_DARWIN_KEY + 1]; | ||
| 14 | INSTALLSTATE isInstalled; | ||
| 15 | INSTALLSTATE isAction; | ||
| 16 | |||
| 17 | // metabase information | ||
| 18 | WCHAR wzWebKey[MAX_DARWIN_KEY + 1]; | ||
| 19 | WCHAR wzWebBase[METADATA_MAX_NAME_LEN + 1]; | ||
| 20 | WCHAR wzFilterRoot[METADATA_MAX_NAME_LEN + 1]; | ||
| 21 | |||
| 22 | // iis configuation information | ||
| 23 | WCHAR wzPath[MAX_PATH]; | ||
| 24 | WCHAR wzDescription[MAX_DARWIN_COLUMN + 1]; | ||
| 25 | int iFlags; | ||
| 26 | int iLoadOrder; | ||
| 27 | |||
| 28 | SCA_FILTER* psfNext; | ||
| 29 | }; | ||
| 30 | |||
| 31 | |||
| 32 | // prototypes | ||
| 33 | HRESULT AddFilterToList( | ||
| 34 | __in SCA_FILTER** ppsfList | ||
| 35 | ); | ||
| 36 | |||
| 37 | UINT __stdcall ScaFiltersRead(IMSAdminBase* piMetabase, | ||
| 38 | SCA_WEB* pswList, __in WCA_WRAPQUERY_HANDLE hWebBaseQuery, SCA_FILTER** ppsfList, | ||
| 39 | __inout LPWSTR *ppwzCustomActionData); | ||
| 40 | |||
| 41 | HRESULT ScaFiltersInstall(IMSAdminBase* piMetabase, SCA_FILTER* psfList); | ||
| 42 | |||
| 43 | HRESULT ScaFiltersUninstall(IMSAdminBase* piMetabase, SCA_FILTER* psfList); | ||
| 44 | |||
| 45 | void ScaFiltersFreeList(SCA_FILTER* psfList); | ||
| 46 | |||
diff --git a/src/ca/scafilter7.cpp b/src/ca/scafilter7.cpp new file mode 100644 index 00000000..dda91c4d --- /dev/null +++ b/src/ca/scafilter7.cpp | |||
| @@ -0,0 +1,284 @@ | |||
| 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 | #include "precomp.h" | ||
| 4 | |||
| 5 | static HRESULT WriteFilter(const SCA_FILTER* psf); | ||
| 6 | |||
| 7 | UINT __stdcall ScaFiltersRead7( | ||
| 8 | __in SCA_WEB7* pswList, | ||
| 9 | __in WCA_WRAPQUERY_HANDLE /*hWebBaseQuery*/, | ||
| 10 | __inout SCA_FILTER** ppsfList, | ||
| 11 | __inout LPWSTR *ppwzCustomActionData | ||
| 12 | ) | ||
| 13 | { | ||
| 14 | HRESULT hr = S_OK; | ||
| 15 | MSIHANDLE hRec; | ||
| 16 | INSTALLSTATE isInstalled = INSTALLSTATE_UNKNOWN; | ||
| 17 | INSTALLSTATE isAction = INSTALLSTATE_UNKNOWN; | ||
| 18 | SCA_FILTER* psf; | ||
| 19 | |||
| 20 | LPWSTR pwzData = NULL; | ||
| 21 | WCA_WRAPQUERY_HANDLE hWrapQuery = NULL; | ||
| 22 | hr = WcaBeginUnwrapQuery(&hWrapQuery, ppwzCustomActionData); | ||
| 23 | ExitOnFailure(hr, "Failed to unwrap query for ScaAppPoolRead"); | ||
| 24 | |||
| 25 | if (0 == WcaGetQueryRecords(hWrapQuery)) | ||
| 26 | { | ||
| 27 | WcaLog(LOGMSG_VERBOSE, "Skipping ScaFiltersRead() - no IIsFilter table"); | ||
| 28 | ExitFunction1(hr = S_FALSE); | ||
| 29 | } | ||
| 30 | |||
| 31 | // loop through all the filters | ||
| 32 | while (S_OK == (hr = WcaFetchWrappedRecord(hWrapQuery, &hRec))) | ||
| 33 | { | ||
| 34 | // Get the Component first. If the component is not being modified during | ||
| 35 | // this transaction, skip processing this whole record. | ||
| 36 | // get the darwin information | ||
| 37 | hr = WcaGetRecordString(hRec, fqComponent, &pwzData); | ||
| 38 | ExitOnFailure(hr, "failed to get IIsFilter.Component"); | ||
| 39 | |||
| 40 | hr = WcaGetRecordInteger(hRec, fqInstalled, (int *)&isInstalled); | ||
| 41 | ExitOnFailure(hr, "Failed to get Component installed state for IIs filter"); | ||
| 42 | |||
| 43 | hr = WcaGetRecordInteger(hRec, fqAction, (int *)&isAction); | ||
| 44 | ExitOnFailure(hr, "Failed to get Component action state for IIs filter"); | ||
| 45 | |||
| 46 | if (!WcaIsInstalling(isInstalled, isAction) && | ||
| 47 | !WcaIsReInstalling(isInstalled, isAction) && | ||
| 48 | !WcaIsUninstalling(isInstalled, isAction)) | ||
| 49 | { | ||
| 50 | continue; // skip this record. | ||
| 51 | } | ||
| 52 | |||
| 53 | hr = AddFilterToList(ppsfList); | ||
| 54 | ExitOnFailure(hr, "failed to add filter to list"); | ||
| 55 | |||
| 56 | psf = *ppsfList; | ||
| 57 | |||
| 58 | hr = ::StringCchCopyW(psf->wzComponent, countof(psf->wzComponent), pwzData); | ||
| 59 | ExitOnFailure(hr, "failed to copy component name: %ls", pwzData); | ||
| 60 | |||
| 61 | psf->isInstalled = isInstalled; | ||
| 62 | psf->isAction = isAction; | ||
| 63 | |||
| 64 | hr = WcaGetRecordString(hRec, fqWeb, &pwzData); | ||
| 65 | ExitOnFailure(hr, "Failed to get Web for VirtualDir"); | ||
| 66 | |||
| 67 | if (*pwzData) | ||
| 68 | { | ||
| 69 | hr = ScaWebsGetBase7(pswList, pwzData, psf->wzFilterRoot, countof(psf->wzFilterRoot)); | ||
| 70 | if (FAILED(hr)) | ||
| 71 | { | ||
| 72 | WcaLog(LOGMSG_VERBOSE, "Could not find site for filter: %ls. Result 0x%x ", psf->wzFilterRoot, hr); | ||
| 73 | hr = S_OK; | ||
| 74 | } | ||
| 75 | } | ||
| 76 | else | ||
| 77 | { | ||
| 78 | hr = ::StringCchCopyW(psf->wzFilterRoot, countof(psf->wzFilterRoot), L"/"); | ||
| 79 | ExitOnFailure(hr, "Failed to allocate global filter base string"); | ||
| 80 | } | ||
| 81 | |||
| 82 | // filter Name key | ||
| 83 | hr = WcaGetRecordString(hRec, fqFilter, &pwzData); | ||
| 84 | ExitOnFailure(hr, "Failed to get Filter.Filter"); | ||
| 85 | hr = ::StringCchCopyW(psf->wzKey, countof(psf->wzKey), pwzData); | ||
| 86 | ExitOnFailure(hr, "Failed to copy key string to filter object"); | ||
| 87 | |||
| 88 | // filter path | ||
| 89 | hr = WcaGetRecordString(hRec, fqPath, &pwzData); | ||
| 90 | ExitOnFailure(hr, "Failed to get Filter.Path"); | ||
| 91 | hr = ::StringCchCopyW(psf->wzPath, countof(psf->wzPath), pwzData); | ||
| 92 | ExitOnFailure(hr, "Failed to copy path string to filter object"); | ||
| 93 | |||
| 94 | // filter description -- not supported in iis 7 | ||
| 95 | hr = WcaGetRecordString(hRec, fqDescription, &pwzData); | ||
| 96 | ExitOnFailure(hr, "Failed to get Filter.Description"); | ||
| 97 | hr = ::StringCchCopyW(psf->wzDescription, countof(psf->wzDescription), pwzData); | ||
| 98 | ExitOnFailure(hr, "Failed to copy description string to filter object"); | ||
| 99 | |||
| 100 | // filter flags | ||
| 101 | //What are these | ||
| 102 | hr = WcaGetRecordInteger(hRec, fqFlags, &psf->iFlags); | ||
| 103 | ExitOnFailure(hr, "Failed to get Filter.Flags"); | ||
| 104 | |||
| 105 | // filter load order | ||
| 106 | hr = WcaGetRecordInteger(hRec, fqLoadOrder, &psf->iLoadOrder); | ||
| 107 | ExitOnFailure(hr, "Failed to get Filter.LoadOrder"); | ||
| 108 | } | ||
| 109 | |||
| 110 | if (E_NOMOREITEMS == hr) | ||
| 111 | { | ||
| 112 | hr = S_OK; | ||
| 113 | } | ||
| 114 | ExitOnFailure(hr, "Failure while processing filters"); | ||
| 115 | |||
| 116 | LExit: | ||
| 117 | WcaFinishUnwrapQuery(hWrapQuery); | ||
| 118 | |||
| 119 | ReleaseStr(pwzData); | ||
| 120 | |||
| 121 | return hr; | ||
| 122 | } | ||
| 123 | |||
| 124 | |||
| 125 | HRESULT ScaFiltersInstall7( | ||
| 126 | __in SCA_FILTER* psfList | ||
| 127 | ) | ||
| 128 | { | ||
| 129 | HRESULT hr = S_OK; | ||
| 130 | SCA_FILTER* psf = psfList; | ||
| 131 | |||
| 132 | if (!psf) | ||
| 133 | { | ||
| 134 | ExitFunction(); | ||
| 135 | } | ||
| 136 | //write global filters | ||
| 137 | hr = ScaWriteConfigID(IIS_FILTER_GLOBAL_BEGIN); | ||
| 138 | ExitOnFailure(hr, "Failed to write filter begin ID"); | ||
| 139 | while (psf) | ||
| 140 | { | ||
| 141 | if (WcaIsInstalling(psf->isInstalled, psf->isAction)) | ||
| 142 | { | ||
| 143 | if (0 == wcscmp(psf->wzFilterRoot, L"/")) | ||
| 144 | { | ||
| 145 | hr = WriteFilter(psf); | ||
| 146 | } | ||
| 147 | } | ||
| 148 | psf = psf->psfNext; | ||
| 149 | } | ||
| 150 | hr = ScaWriteConfigID(IIS_FILTER_END); | ||
| 151 | ExitOnFailure(hr, "Failed to write filter ID"); | ||
| 152 | |||
| 153 | psf = psfList; | ||
| 154 | |||
| 155 | //Write Web Site Filters | ||
| 156 | hr = ScaWriteConfigID(IIS_FILTER_BEGIN); | ||
| 157 | ExitOnFailure(hr, "Failed to write filter begin ID"); | ||
| 158 | while (psf) | ||
| 159 | { | ||
| 160 | if (WcaIsInstalling(psf->isInstalled, psf->isAction)) | ||
| 161 | { | ||
| 162 | if (0 != wcscmp(psf->wzFilterRoot, L"/")) | ||
| 163 | { | ||
| 164 | hr = WriteFilter(psf); | ||
| 165 | } | ||
| 166 | } | ||
| 167 | psf = psf->psfNext; | ||
| 168 | } | ||
| 169 | hr = ScaWriteConfigID(IIS_FILTER_END); | ||
| 170 | ExitOnFailure(hr, "Failed to write filter ID"); | ||
| 171 | |||
| 172 | LExit: | ||
| 173 | |||
| 174 | return hr; | ||
| 175 | } | ||
| 176 | static HRESULT WriteFilter(const SCA_FILTER* psf) | ||
| 177 | { | ||
| 178 | HRESULT hr = S_OK; | ||
| 179 | |||
| 180 | hr = ScaWriteConfigID(IIS_FILTER); | ||
| 181 | ExitOnFailure(hr, "Failed to write filter begin ID"); | ||
| 182 | |||
| 183 | hr = ScaWriteConfigID(IIS_CREATE); | ||
| 184 | ExitOnFailure(hr, "Failed to write filter create ID"); | ||
| 185 | |||
| 186 | //filter Name key | ||
| 187 | hr = ScaWriteConfigString(psf->wzKey); | ||
| 188 | ExitOnFailure(hr, "Failed to write key name for filter '%ls'", psf->wzKey); | ||
| 189 | |||
| 190 | //web site name | ||
| 191 | hr = ScaWriteConfigString(psf->wzFilterRoot); | ||
| 192 | ExitOnFailure(hr, "Failed to write filter web root "); | ||
| 193 | |||
| 194 | // filter path | ||
| 195 | hr = ScaWriteConfigString(psf->wzPath); | ||
| 196 | ExitOnFailure(hr, "Failed to write Path for filter '%ls'", psf->wzKey); | ||
| 197 | |||
| 198 | //filter load order | ||
| 199 | hr = ScaWriteConfigInteger(psf->iLoadOrder); | ||
| 200 | ExitOnFailure(hr, "Failed to write load order for filter '%ls'", psf->wzKey); | ||
| 201 | |||
| 202 | LExit: | ||
| 203 | return hr; | ||
| 204 | } | ||
| 205 | |||
| 206 | |||
| 207 | HRESULT ScaFiltersUninstall7( | ||
| 208 | __in SCA_FILTER* psfList | ||
| 209 | ) | ||
| 210 | { | ||
| 211 | HRESULT hr = S_OK; | ||
| 212 | SCA_FILTER* psf = psfList; | ||
| 213 | |||
| 214 | if (!psf) | ||
| 215 | { | ||
| 216 | ExitFunction1(hr = S_OK); | ||
| 217 | } | ||
| 218 | |||
| 219 | //Uninstall global filters | ||
| 220 | hr = ScaWriteConfigID(IIS_FILTER_GLOBAL_BEGIN); | ||
| 221 | ExitOnFailure(hr, "Failed to write filter begin ID"); | ||
| 222 | |||
| 223 | while (psf) | ||
| 224 | { | ||
| 225 | if (WcaIsUninstalling(psf->isInstalled, psf->isAction)) | ||
| 226 | { | ||
| 227 | if (0 == wcscmp(psf->wzFilterRoot, L"/")) | ||
| 228 | { | ||
| 229 | hr = ScaWriteConfigID(IIS_FILTER); | ||
| 230 | ExitOnFailure(hr, "Failed to write filter begin ID"); | ||
| 231 | |||
| 232 | hr = ScaWriteConfigID(IIS_DELETE); | ||
| 233 | ExitOnFailure(hr, "Failed to write filter create ID"); | ||
| 234 | |||
| 235 | //filter Name key | ||
| 236 | hr = ScaWriteConfigString(psf->wzKey); | ||
| 237 | ExitOnFailure(hr, "Failed to write key name for filter '%ls'", psf->wzKey); | ||
| 238 | |||
| 239 | //web site name | ||
| 240 | hr = ScaWriteConfigString(psf->wzFilterRoot); | ||
| 241 | ExitOnFailure(hr, "Failed to write filter web root "); | ||
| 242 | |||
| 243 | } | ||
| 244 | } | ||
| 245 | psf = psf->psfNext; | ||
| 246 | } | ||
| 247 | |||
| 248 | hr = ScaWriteConfigID(IIS_FILTER_END); | ||
| 249 | ExitOnFailure(hr, "Failed to write filter ID"); | ||
| 250 | |||
| 251 | psf = psfList; | ||
| 252 | |||
| 253 | //Uninstall website filters | ||
| 254 | hr = ScaWriteConfigID(IIS_FILTER_BEGIN); | ||
| 255 | ExitOnFailure(hr, "Failed to write filter begin ID"); | ||
| 256 | while (psf) | ||
| 257 | { | ||
| 258 | if (WcaIsUninstalling(psf->isInstalled, psf->isAction)) | ||
| 259 | { | ||
| 260 | if (0 != wcscmp(psf->wzFilterRoot, L"/")) | ||
| 261 | { | ||
| 262 | hr = ScaWriteConfigID(IIS_FILTER); | ||
| 263 | ExitOnFailure(hr, "Failed to write filter begin ID"); | ||
| 264 | |||
| 265 | hr = ScaWriteConfigID(IIS_DELETE); | ||
| 266 | ExitOnFailure(hr, "Failed to write filter create ID"); | ||
| 267 | |||
| 268 | //filter Name key | ||
| 269 | hr = ScaWriteConfigString(psf->wzKey); | ||
| 270 | ExitOnFailure(hr, "Failed to write key name for filter '%ls'", psf->wzKey); | ||
| 271 | |||
| 272 | //web site name | ||
| 273 | hr = ScaWriteConfigString(psf->wzFilterRoot); | ||
| 274 | ExitOnFailure(hr, "Failed to write filter web root "); | ||
| 275 | } | ||
| 276 | } | ||
| 277 | psf = psf->psfNext; | ||
| 278 | } | ||
| 279 | hr = ScaWriteConfigID(IIS_FILTER_END); | ||
| 280 | ExitOnFailure(hr, "Failed to write filter ID"); | ||
| 281 | |||
| 282 | LExit: | ||
| 283 | return hr; | ||
| 284 | } | ||
diff --git a/src/ca/scafilter7.h b/src/ca/scafilter7.h new file mode 100644 index 00000000..50ff6652 --- /dev/null +++ b/src/ca/scafilter7.h | |||
| @@ -0,0 +1,21 @@ | |||
| 1 | #pragma once | ||
| 2 | // 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. | ||
| 3 | |||
| 4 | |||
| 5 | #include "scaweb.h" | ||
| 6 | |||
| 7 | // prototypes | ||
| 8 | UINT __stdcall ScaFiltersRead7( | ||
| 9 | __in SCA_WEB7* pswList, | ||
| 10 | __in WCA_WRAPQUERY_HANDLE hWebBaseQuery, | ||
| 11 | __inout SCA_FILTER** ppsfList, | ||
| 12 | __inout LPWSTR *ppwzCustomActionData | ||
| 13 | ); | ||
| 14 | |||
| 15 | HRESULT ScaFiltersInstall7( | ||
| 16 | SCA_FILTER* psfList | ||
| 17 | ); | ||
| 18 | |||
| 19 | HRESULT ScaFiltersUninstall7( | ||
| 20 | SCA_FILTER* psfList | ||
| 21 | ); | ||
diff --git a/src/ca/scahttpheader.cpp b/src/ca/scahttpheader.cpp new file mode 100644 index 00000000..a8fea796 --- /dev/null +++ b/src/ca/scahttpheader.cpp | |||
| @@ -0,0 +1,323 @@ | |||
| 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 | #include "precomp.h" | ||
| 4 | |||
| 5 | enum eHttpHeaderQuery { hhqName = 1, hhqParentType, hhqParentValue, hhqValue, hhqAttributes}; | ||
| 6 | |||
| 7 | static HRESULT AddHttpHeaderToList( | ||
| 8 | __in SCA_HTTP_HEADER** ppshhList | ||
| 9 | ); | ||
| 10 | |||
| 11 | |||
| 12 | void ScaHttpHeaderFreeList( | ||
| 13 | __in SCA_HTTP_HEADER* pshhList | ||
| 14 | ) | ||
| 15 | { | ||
| 16 | SCA_HTTP_HEADER* pshhDelete = pshhList; | ||
| 17 | while (pshhList) | ||
| 18 | { | ||
| 19 | pshhDelete = pshhList; | ||
| 20 | pshhList = pshhList->pshhNext; | ||
| 21 | |||
| 22 | MemFree(pshhDelete); | ||
| 23 | } | ||
| 24 | } | ||
| 25 | |||
| 26 | |||
| 27 | HRESULT ScaHttpHeaderRead( | ||
| 28 | __in SCA_HTTP_HEADER** ppshhList, | ||
| 29 | __inout LPWSTR *ppwzCustomActionData | ||
| 30 | ) | ||
| 31 | { | ||
| 32 | Assert(ppshhList); | ||
| 33 | |||
| 34 | HRESULT hr = S_OK; | ||
| 35 | MSIHANDLE hRec; | ||
| 36 | LPWSTR pwzData = NULL; | ||
| 37 | SCA_HTTP_HEADER* pshh = NULL; | ||
| 38 | WCA_WRAPQUERY_HANDLE hWrapQuery = NULL; | ||
| 39 | |||
| 40 | hr = WcaBeginUnwrapQuery(&hWrapQuery, ppwzCustomActionData); | ||
| 41 | ExitOnFailure(hr, "Failed to unwrap query for ScaAppPoolRead"); | ||
| 42 | |||
| 43 | if (0 == WcaGetQueryRecords(hWrapQuery)) | ||
| 44 | { | ||
| 45 | WcaLog(LOGMSG_VERBOSE, "Skipping ScaHttpHeaderRead() - required tables not present."); | ||
| 46 | ExitFunction1(hr = S_FALSE); | ||
| 47 | } | ||
| 48 | |||
| 49 | // loop through all the HTTP headers | ||
| 50 | while (S_OK == (hr = WcaFetchWrappedRecord(hWrapQuery, &hRec))) | ||
| 51 | { | ||
| 52 | hr = AddHttpHeaderToList(ppshhList); | ||
| 53 | ExitOnFailure(hr, "failed to add http header to list"); | ||
| 54 | |||
| 55 | pshh = *ppshhList; | ||
| 56 | |||
| 57 | hr = WcaGetRecordInteger(hRec, hhqParentType, &(pshh->iParentType)); | ||
| 58 | ExitOnFailure(hr, "failed to get IIsHttpHeader.ParentType"); | ||
| 59 | |||
| 60 | hr = WcaGetRecordString(hRec, hhqParentValue, &pwzData); | ||
| 61 | ExitOnFailure(hr, "Failed to get IIsHttpHeader.ParentValue"); | ||
| 62 | hr = ::StringCchCopyW(pshh->wzParentValue, countof(pshh->wzParentValue), pwzData); | ||
| 63 | ExitOnFailure(hr, "Failed to copy IIsHttpHeader.ParentValue"); | ||
| 64 | |||
| 65 | hr = WcaGetRecordString(hRec, hhqName, &pwzData); | ||
| 66 | ExitOnFailure(hr, "Failed to get IIsHttpHeader.Name"); | ||
| 67 | hr = ::StringCchCopyW(pshh->wzName, countof(pshh->wzName), pwzData); | ||
| 68 | ExitOnFailure(hr, "Failed to copy IIsHttpHeader.Name"); | ||
| 69 | |||
| 70 | hr = WcaGetRecordString(hRec, hhqValue, &pwzData); | ||
| 71 | ExitOnFailure(hr, "Failed to get IIsHttpHeader.Value"); | ||
| 72 | hr = ::StringCchCopyW(pshh->wzValue, countof(pshh->wzValue), pwzData); | ||
| 73 | ExitOnFailure(hr, "Failed to copy IIsHttpHeader.Value"); | ||
| 74 | |||
| 75 | hr = WcaGetRecordInteger(hRec, hhqAttributes, &(pshh->iAttributes)); | ||
| 76 | ExitOnFailure(hr, "failed to get IIsHttpHeader.Attributes"); | ||
| 77 | } | ||
| 78 | |||
| 79 | if (E_NOMOREITEMS == hr) | ||
| 80 | { | ||
| 81 | hr = S_OK; | ||
| 82 | } | ||
| 83 | ExitOnFailure(hr, "Failure while processing web errors"); | ||
| 84 | |||
| 85 | LExit: | ||
| 86 | WcaFinishUnwrapQuery(hWrapQuery); | ||
| 87 | |||
| 88 | ReleaseStr(pwzData); | ||
| 89 | |||
| 90 | return hr; | ||
| 91 | } | ||
| 92 | |||
| 93 | |||
| 94 | HRESULT ScaGetHttpHeader( | ||
| 95 | __in int iParentType, | ||
| 96 | __in LPCWSTR wzParentValue, | ||
| 97 | __in SCA_HTTP_HEADER** ppshhList, | ||
| 98 | __out SCA_HTTP_HEADER** ppshhOut | ||
| 99 | ) | ||
| 100 | { | ||
| 101 | HRESULT hr = S_OK; | ||
| 102 | SCA_HTTP_HEADER* pshhAdd = NULL; | ||
| 103 | SCA_HTTP_HEADER* pshhLast = NULL; | ||
| 104 | |||
| 105 | *ppshhOut = NULL; | ||
| 106 | |||
| 107 | if (!*ppshhList) | ||
| 108 | { | ||
| 109 | return hr; | ||
| 110 | } | ||
| 111 | |||
| 112 | SCA_HTTP_HEADER* pshh = *ppshhList; | ||
| 113 | while (pshh) | ||
| 114 | { | ||
| 115 | if (iParentType == pshh->iParentType && CSTR_EQUAL == ::CompareStringW(LOCALE_SYSTEM_DEFAULT, 0, wzParentValue, -1, pshh->wzParentValue, -1)) | ||
| 116 | { | ||
| 117 | // Found a match, take this one out of the list and add it to the matched out list | ||
| 118 | pshhAdd = pshh; | ||
| 119 | |||
| 120 | if (pshhLast) | ||
| 121 | { | ||
| 122 | // If we're not at the beginning of the list tell the last node about it's new next (since we're taking away it's current next) | ||
| 123 | pshhLast->pshhNext = pshhAdd->pshhNext; | ||
| 124 | } | ||
| 125 | else | ||
| 126 | { | ||
| 127 | // If we are at the beginning (no pshhLast) update the beginning (since we're taking it) | ||
| 128 | *ppshhList = pshh->pshhNext; | ||
| 129 | } | ||
| 130 | pshh = pshh->pshhNext; // move on | ||
| 131 | |||
| 132 | // Add the one we've removed to the beginning of the out list | ||
| 133 | pshhAdd->pshhNext = *ppshhOut; | ||
| 134 | *ppshhOut = pshhAdd; | ||
| 135 | } | ||
| 136 | else | ||
| 137 | { | ||
| 138 | pshhLast = pshh; // remember the last we that didn't match | ||
| 139 | pshh = pshh->pshhNext; // move on | ||
| 140 | } | ||
| 141 | } | ||
| 142 | |||
| 143 | return hr; | ||
| 144 | } | ||
| 145 | |||
| 146 | |||
| 147 | HRESULT ScaWriteHttpHeader( | ||
| 148 | __in IMSAdminBase* piMetabase, | ||
| 149 | __in LPCWSTR wzRoot, | ||
| 150 | __in SCA_HTTP_HEADER* pshhList | ||
| 151 | ) | ||
| 152 | { | ||
| 153 | Assert(piMetabase && pshhList); | ||
| 154 | |||
| 155 | HRESULT hr = S_OK; | ||
| 156 | METADATA_RECORD mr = { 0 }; | ||
| 157 | DWORD cchData = 0; | ||
| 158 | LPWSTR pwzSearchKey = NULL; | ||
| 159 | LPWSTR pwz = NULL; | ||
| 160 | LPWSTR pwzHeaders = NULL; | ||
| 161 | LPWSTR pwzNewHeader = NULL; | ||
| 162 | DWORD dwFoundHeaderIndex = 0; | ||
| 163 | LPCWSTR wzFoundHeader = NULL; | ||
| 164 | BOOL fOldValueFound = FALSE; | ||
| 165 | |||
| 166 | ExitOnNull(wzRoot, hr, E_INVALIDARG, "Failed to write HTTP header, because no root was provided"); | ||
| 167 | |||
| 168 | Assert(*wzRoot); | ||
| 169 | |||
| 170 | // Check if HTTP header already exist here. | ||
| 171 | mr.dwMDIdentifier = MD_HTTP_CUSTOM; | ||
| 172 | mr.dwMDAttributes = METADATA_INHERIT; | ||
| 173 | mr.dwMDUserType = IIS_MD_UT_SERVER; | ||
| 174 | mr.dwMDDataType = ALL_METADATA; | ||
| 175 | mr.dwMDDataLen = cchData = 0; | ||
| 176 | mr.pbMDData = NULL; | ||
| 177 | |||
| 178 | hr = MetaGetValue(piMetabase, METADATA_MASTER_ROOT_HANDLE, wzRoot, &mr); | ||
| 179 | if (HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) == hr || MD_ERROR_DATA_NOT_FOUND == hr) | ||
| 180 | { | ||
| 181 | // | ||
| 182 | // If we don't have any HTTP Headers already, move up to get the parent headers. | ||
| 183 | // TODO: Make it configurable to not inherit HTTP Headers | ||
| 184 | // | ||
| 185 | hr = StrAllocConcat(&pwzSearchKey, wzRoot, 0); | ||
| 186 | ExitOnFailure(hr, "Failed to copy root string: %ls", wzRoot); | ||
| 187 | |||
| 188 | pwz = pwzSearchKey + lstrlenW(pwzSearchKey); | ||
| 189 | while (NULL == pwzHeaders) | ||
| 190 | { | ||
| 191 | // find the last slash | ||
| 192 | while (*pwz != '/' && pwz != pwzSearchKey) | ||
| 193 | { | ||
| 194 | --pwz; | ||
| 195 | } | ||
| 196 | |||
| 197 | if (pwz == pwzSearchKey) | ||
| 198 | { | ||
| 199 | break; | ||
| 200 | } | ||
| 201 | |||
| 202 | *pwz = L'\0'; | ||
| 203 | |||
| 204 | // Try here. If it's not found, keep walking up the path | ||
| 205 | hr = MetaGetValue(piMetabase, METADATA_MASTER_ROOT_HANDLE, pwzSearchKey, &mr); | ||
| 206 | if (HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) == hr || MD_ERROR_DATA_NOT_FOUND == hr) | ||
| 207 | { | ||
| 208 | hr = S_FALSE; | ||
| 209 | } | ||
| 210 | ExitOnFailure(hr, "Failed to find search for HTTP headers for web root: %ls while walking up the tree", wzRoot); | ||
| 211 | |||
| 212 | if (S_OK == hr) | ||
| 213 | { | ||
| 214 | hr = StrAllocString(&pwzHeaders, reinterpret_cast<LPWSTR>(mr.pbMDData), 0); | ||
| 215 | ExitOnFailure(hr, "Failed to allocate parent HTTP header string"); | ||
| 216 | break; | ||
| 217 | } | ||
| 218 | } | ||
| 219 | } | ||
| 220 | else | ||
| 221 | { | ||
| 222 | hr = StrAllocString(&pwzHeaders, reinterpret_cast<LPWSTR>(mr.pbMDData), 0); | ||
| 223 | ExitOnFailure(hr, "Failed to allocate HTTP header string"); | ||
| 224 | } | ||
| 225 | ExitOnFailure(hr, "Failed while searching for default HTTP headers to start with for web root: %ls", wzRoot); | ||
| 226 | |||
| 227 | // Loop through the HTTP headers | ||
| 228 | for (SCA_HTTP_HEADER* pshh = pshhList; pshh; pshh = pshh->pshhNext) | ||
| 229 | { | ||
| 230 | fOldValueFound = FALSE; // assume a HTTP Header match will not be found | ||
| 231 | |||
| 232 | hr = StrAllocFormatted(&pwzNewHeader, L"%s: ", pshh->wzName); | ||
| 233 | ExitOnFailure(hr, "Failed to allocate header name"); | ||
| 234 | |||
| 235 | if (NULL != pwzHeaders && *pwzHeaders) | ||
| 236 | { | ||
| 237 | // Try to find a matching header already in the list | ||
| 238 | hr = MultiSzFindSubstring(pwzHeaders, pwzNewHeader, &dwFoundHeaderIndex, &wzFoundHeader); | ||
| 239 | ExitOnFailure(hr, "Failed while searching for existing HTTP header."); | ||
| 240 | |||
| 241 | // If there was a substring HTTP header match, make sure the match was at the beginning | ||
| 242 | // of the string because that is the HTTP header name. | ||
| 243 | if (S_OK == hr) | ||
| 244 | { | ||
| 245 | DWORD cchMatch = lstrlenW(pwzNewHeader); | ||
| 246 | if (CSTR_EQUAL == ::CompareStringW(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE, pwzNewHeader, cchMatch, wzFoundHeader, cchMatch)) | ||
| 247 | { | ||
| 248 | fOldValueFound = TRUE; | ||
| 249 | break; | ||
| 250 | } | ||
| 251 | } | ||
| 252 | } | ||
| 253 | |||
| 254 | // Add the value on to the header name now. | ||
| 255 | hr = StrAllocConcat(&pwzNewHeader, pshh->wzValue, 0); | ||
| 256 | ExitOnFailure(hr, "Failed to add value on to HTTP header name."); | ||
| 257 | |||
| 258 | // If we have something to replace, replace it, otherwise, put it at the beginning (order shouldn't matter) | ||
| 259 | if (fOldValueFound) | ||
| 260 | { | ||
| 261 | if (NULL == pwzHeaders) | ||
| 262 | { | ||
| 263 | ExitOnFailure(hr = E_INVALIDARG, "While attempting to replace old HTTP header with new HTTP header, it was discovered that the old HTTP header was NULL!"); | ||
| 264 | } | ||
| 265 | hr = MultiSzReplaceString(&pwzHeaders, dwFoundHeaderIndex, pwzNewHeader); | ||
| 266 | ExitOnFailure(hr, "Failed to replace old HTTP header with new HTTP header"); | ||
| 267 | } | ||
| 268 | else | ||
| 269 | { | ||
| 270 | hr = MultiSzPrepend(&pwzHeaders, NULL, pwzNewHeader); | ||
| 271 | ExitOnFailure(hr, "Failed to prepend new HTTP header"); | ||
| 272 | } | ||
| 273 | } | ||
| 274 | |||
| 275 | // now write the HttpCustom to the metabase | ||
| 276 | hr = ScaWriteMetabaseValue(piMetabase, wzRoot, NULL, MD_HTTP_CUSTOM, METADATA_INHERIT, IIS_MD_UT_FILE, MULTISZ_METADATA, pwzHeaders); | ||
| 277 | ExitOnFailure(hr, "Failed to write HTTP Headers to metabase"); | ||
| 278 | |||
| 279 | LExit: | ||
| 280 | MetaFreeValue(&mr); | ||
| 281 | |||
| 282 | ReleaseStr(pwzNewHeader); | ||
| 283 | ReleaseStr(pwzHeaders); | ||
| 284 | ReleaseStr(pwzSearchKey); | ||
| 285 | |||
| 286 | return hr; | ||
| 287 | } | ||
| 288 | |||
| 289 | |||
| 290 | HRESULT ScaHttpHeaderCheckList( | ||
| 291 | __in SCA_HTTP_HEADER* pshhList | ||
| 292 | ) | ||
| 293 | { | ||
| 294 | if (!pshhList) | ||
| 295 | { | ||
| 296 | return S_OK; | ||
| 297 | } | ||
| 298 | |||
| 299 | while (pshhList) | ||
| 300 | { | ||
| 301 | WcaLog(LOGMSG_STANDARD, "Http Header: %ls for parent: %ls not used!", pshhList->wzName, pshhList->wzParentValue); | ||
| 302 | pshhList = pshhList->pshhNext; | ||
| 303 | } | ||
| 304 | |||
| 305 | return E_FAIL; | ||
| 306 | } | ||
| 307 | |||
| 308 | |||
| 309 | static HRESULT AddHttpHeaderToList( | ||
| 310 | __in SCA_HTTP_HEADER** ppshhList | ||
| 311 | ) | ||
| 312 | { | ||
| 313 | HRESULT hr = S_OK; | ||
| 314 | |||
| 315 | SCA_HTTP_HEADER* pshh = static_cast<SCA_HTTP_HEADER*>(MemAlloc(sizeof(SCA_HTTP_HEADER), TRUE)); | ||
| 316 | ExitOnNull(pshh, hr, E_OUTOFMEMORY, "failed to allocate memory for new http header list element"); | ||
| 317 | |||
| 318 | pshh->pshhNext = *ppshhList; | ||
| 319 | *ppshhList = pshh; | ||
| 320 | |||
| 321 | LExit: | ||
| 322 | return hr; | ||
| 323 | } | ||
diff --git a/src/ca/scahttpheader.h b/src/ca/scahttpheader.h new file mode 100644 index 00000000..a4c407a4 --- /dev/null +++ b/src/ca/scahttpheader.h | |||
| @@ -0,0 +1,40 @@ | |||
| 1 | #pragma once | ||
| 2 | // 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. | ||
| 3 | |||
| 4 | |||
| 5 | enum eHttpHeaderParentType { hhptVDir = 1, hhptWeb }; | ||
| 6 | |||
| 7 | struct SCA_HTTP_HEADER | ||
| 8 | { | ||
| 9 | int iParentType; | ||
| 10 | WCHAR wzParentValue[MAX_DARWIN_KEY + 1]; | ||
| 11 | |||
| 12 | WCHAR wzName[MAX_PATH]; | ||
| 13 | WCHAR wzValue[MAX_PATH]; | ||
| 14 | int iAttributes; | ||
| 15 | |||
| 16 | SCA_HTTP_HEADER* pshhNext; | ||
| 17 | }; | ||
| 18 | |||
| 19 | // prototypes | ||
| 20 | HRESULT ScaHttpHeaderRead( | ||
| 21 | __in SCA_HTTP_HEADER **ppshhList, | ||
| 22 | __inout LPWSTR *ppwzCustomActionData | ||
| 23 | ); | ||
| 24 | void ScaHttpHeaderFreeList( | ||
| 25 | __in SCA_HTTP_HEADER *pshhList | ||
| 26 | ); | ||
| 27 | HRESULT ScaHttpHeaderCheckList( | ||
| 28 | __in SCA_HTTP_HEADER* pshhList | ||
| 29 | ); | ||
| 30 | HRESULT ScaGetHttpHeader( | ||
| 31 | __in int iParentType, | ||
| 32 | __in LPCWSTR wzParentValue, | ||
| 33 | __in SCA_HTTP_HEADER** ppshhList, | ||
| 34 | __out SCA_HTTP_HEADER** ppshhOut | ||
| 35 | ); | ||
| 36 | HRESULT ScaWriteHttpHeader( | ||
| 37 | __in IMSAdminBase* piMetabase, | ||
| 38 | LPCWSTR wzRoot, | ||
| 39 | SCA_HTTP_HEADER* pshhList | ||
| 40 | ); | ||
diff --git a/src/ca/scahttpheader7.cpp b/src/ca/scahttpheader7.cpp new file mode 100644 index 00000000..645dd8d4 --- /dev/null +++ b/src/ca/scahttpheader7.cpp | |||
| @@ -0,0 +1,130 @@ | |||
| 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 | #include "precomp.h" | ||
| 4 | |||
| 5 | HRESULT ScaGetHttpHeader7( | ||
| 6 | __in int iParentType, | ||
| 7 | __in_z LPCWSTR wzParentValue, | ||
| 8 | __in SCA_HTTP_HEADER** ppshhList, | ||
| 9 | __out SCA_HTTP_HEADER** ppshhOut | ||
| 10 | ) | ||
| 11 | { | ||
| 12 | HRESULT hr = S_OK; | ||
| 13 | SCA_HTTP_HEADER* pshhAdd = NULL; | ||
| 14 | SCA_HTTP_HEADER* pshhLast = NULL; | ||
| 15 | |||
| 16 | *ppshhOut = NULL; | ||
| 17 | |||
| 18 | if (!*ppshhList) | ||
| 19 | { | ||
| 20 | return hr; | ||
| 21 | } | ||
| 22 | |||
| 23 | SCA_HTTP_HEADER* pshh = *ppshhList; | ||
| 24 | while (pshh) | ||
| 25 | { | ||
| 26 | if (iParentType == pshh->iParentType && 0 == wcscmp(wzParentValue, pshh->wzParentValue)) | ||
| 27 | { | ||
| 28 | // Found a match, take this one out of the list and add it to the matched out list | ||
| 29 | pshhAdd = pshh; | ||
| 30 | |||
| 31 | if (pshhLast) | ||
| 32 | { | ||
| 33 | // If we're not at the beginning of the list tell the last node about it's new next (since we're taking away it's current next) | ||
| 34 | pshhLast->pshhNext = pshhAdd->pshhNext; | ||
| 35 | } | ||
| 36 | else | ||
| 37 | { | ||
| 38 | // If we are at the beginning (no pshhLast) update the beginning (since we're taking it) | ||
| 39 | *ppshhList = pshh->pshhNext; | ||
| 40 | } | ||
| 41 | pshh = pshh->pshhNext; // move on | ||
| 42 | |||
| 43 | // Add the one we've removed to the beginning of the out list | ||
| 44 | pshhAdd->pshhNext = *ppshhOut; | ||
| 45 | *ppshhOut = pshhAdd; | ||
| 46 | } | ||
| 47 | else | ||
| 48 | { | ||
| 49 | pshhLast = pshh; // remember the last we that didn't match | ||
| 50 | pshh = pshh->pshhNext; // move on | ||
| 51 | } | ||
| 52 | } | ||
| 53 | |||
| 54 | return hr; | ||
| 55 | } | ||
| 56 | |||
| 57 | |||
| 58 | HRESULT ScaWriteHttpHeader7( | ||
| 59 | __in_z LPCWSTR wzWebName, | ||
| 60 | __in_z LPCWSTR wzRoot, | ||
| 61 | SCA_HTTP_HEADER* pshhList | ||
| 62 | ) | ||
| 63 | { | ||
| 64 | |||
| 65 | HRESULT hr = S_OK; | ||
| 66 | |||
| 67 | hr = ScaWriteConfigID(IIS_HTTP_HEADER_BEGIN); | ||
| 68 | ExitOnFailure(hr, "Fail to write httpHeader begin ID"); | ||
| 69 | |||
| 70 | hr = ScaWriteConfigString(wzWebName); | ||
| 71 | ExitOnFailure(hr, "Fail to write httpHeader Web Key"); | ||
| 72 | |||
| 73 | hr = ScaWriteConfigString(wzRoot); | ||
| 74 | ExitOnFailure(hr, "Fail to write httpHeader Vdir key"); | ||
| 75 | |||
| 76 | // Loop through the HTTP headers | ||
| 77 | for (SCA_HTTP_HEADER* pshh = pshhList; pshh; pshh = pshh->pshhNext) | ||
| 78 | { | ||
| 79 | hr = ScaWriteConfigID(IIS_HTTP_HEADER); | ||
| 80 | ExitOnFailure(hr, "Fail to write httpHeader ID"); | ||
| 81 | |||
| 82 | hr = ScaWriteConfigString(pshh->wzName); | ||
| 83 | ExitOnFailure(hr, "Fail to write httpHeader name"); | ||
| 84 | |||
| 85 | hr = ScaWriteConfigString(pshh->wzValue); | ||
| 86 | ExitOnFailure(hr, "Fail to write httpHeader value"); | ||
| 87 | } | ||
| 88 | |||
| 89 | hr = ScaWriteConfigID(IIS_HTTP_HEADER_END); | ||
| 90 | ExitOnFailure(hr, "Fail to write httpHeader end ID"); | ||
| 91 | |||
| 92 | LExit: | ||
| 93 | return hr; | ||
| 94 | } | ||
| 95 | |||
| 96 | |||
| 97 | HRESULT ScaHttpHeaderCheckList7( | ||
| 98 | __in SCA_HTTP_HEADER* pshhList | ||
| 99 | ) | ||
| 100 | { | ||
| 101 | if (!pshhList) | ||
| 102 | { | ||
| 103 | return S_OK; | ||
| 104 | } | ||
| 105 | |||
| 106 | while (pshhList) | ||
| 107 | { | ||
| 108 | WcaLog(LOGMSG_STANDARD, "Http Header: %ls for parent: %ls not used!", pshhList->wzName, pshhList->wzParentValue); | ||
| 109 | pshhList = pshhList->pshhNext; | ||
| 110 | } | ||
| 111 | |||
| 112 | return E_FAIL; | ||
| 113 | } | ||
| 114 | |||
| 115 | |||
| 116 | //static HRESULT AddHttpHeaderToList( | ||
| 117 | // __in SCA_HTTP_HEADER** ppshhList | ||
| 118 | // ) | ||
| 119 | //{ | ||
| 120 | // HRESULT hr = S_OK; | ||
| 121 | // | ||
| 122 | // SCA_HTTP_HEADER* pshh = static_cast<SCA_HTTP_HEADER*>(MemAlloc(sizeof(SCA_HTTP_HEADER), TRUE)); | ||
| 123 | // ExitOnNull(pshh, hr, E_OUTOFMEMORY, "failed to allocate memory for new http header list element"); | ||
| 124 | // | ||
| 125 | // pshh->pshhNext = *ppshhList; | ||
| 126 | // *ppshhList = pshh; | ||
| 127 | // | ||
| 128 | //LExit: | ||
| 129 | // return hr; | ||
| 130 | //} | ||
diff --git a/src/ca/scahttpheader7.h b/src/ca/scahttpheader7.h new file mode 100644 index 00000000..7a873c16 --- /dev/null +++ b/src/ca/scahttpheader7.h | |||
| @@ -0,0 +1,15 @@ | |||
| 1 | #pragma once | ||
| 2 | // 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. | ||
| 3 | |||
| 4 | |||
| 5 | HRESULT ScaGetHttpHeader7( | ||
| 6 | __in int iParentType, | ||
| 7 | __in_z LPCWSTR wzParentValue, | ||
| 8 | __in SCA_HTTP_HEADER** ppshhList, | ||
| 9 | __out SCA_HTTP_HEADER** ppshhOut | ||
| 10 | ); | ||
| 11 | HRESULT ScaWriteHttpHeader7( | ||
| 12 | __in_z LPCWSTR wzWebName, | ||
| 13 | __in_z LPCWSTR wzRoot, | ||
| 14 | SCA_HTTP_HEADER* pshhList | ||
| 15 | ); | ||
diff --git a/src/ca/scaiis.cpp b/src/ca/scaiis.cpp new file mode 100644 index 00000000..a29af1db --- /dev/null +++ b/src/ca/scaiis.cpp | |||
| @@ -0,0 +1,481 @@ | |||
| 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 | #include "precomp.h" | ||
| 4 | |||
| 5 | // globals | ||
| 6 | LPWSTR vpwzCustomActionData = NULL; | ||
| 7 | DWORD vdwCustomActionCost = 0; | ||
| 8 | |||
| 9 | HRESULT ScaMetabaseTransaction(__in_z LPCWSTR wzBackup) | ||
| 10 | { | ||
| 11 | HRESULT hr = S_OK; | ||
| 12 | |||
| 13 | // TODO: These functions have been reported to hang IIS (O11:51709). They may have been fixed in IIS6, but if not, need to be re-written the hard way | ||
| 14 | |||
| 15 | hr = WcaDoDeferredAction(L"StartMetabaseTransaction", wzBackup, COST_IIS_TRANSACTIONS); | ||
| 16 | ExitOnFailure(hr, "Failed to schedule StartMetabaseTransaction"); | ||
| 17 | |||
| 18 | hr = WcaDoDeferredAction(L"RollbackMetabaseTransaction", wzBackup, 0); // rollback cost is irrelevant | ||
| 19 | ExitOnFailure(hr, "Failed to schedule RollbackMetabaseTransaction"); | ||
| 20 | |||
| 21 | hr = WcaDoDeferredAction(L"CommitMetabaseTransaction", wzBackup, 0); // commit is free | ||
| 22 | ExitOnFailure(hr, "Failed to schedule StartMetabaseTransaction"); | ||
| 23 | |||
| 24 | LExit: | ||
| 25 | return hr; | ||
| 26 | } | ||
| 27 | |||
| 28 | |||
| 29 | HRESULT ScaCreateWeb(IMSAdminBase* piMetabase, LPCWSTR /*wzWeb*/, LPCWSTR wzWebBase) | ||
| 30 | { | ||
| 31 | Assert(piMetabase); | ||
| 32 | |||
| 33 | HRESULT hr = S_OK; | ||
| 34 | UINT ui = 0; | ||
| 35 | |||
| 36 | hr = ScaCreateMetabaseKey(piMetabase, wzWebBase, L""); | ||
| 37 | ExitOnFailure(hr, "Failed to create web"); | ||
| 38 | |||
| 39 | hr = ScaWriteMetabaseValue(piMetabase, wzWebBase, L"", MD_KEY_TYPE, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, (LPVOID)L"IIsWebServer"); | ||
| 40 | ExitOnFailure(hr, "Failed to set key type for web"); | ||
| 41 | |||
| 42 | hr = ScaCreateMetabaseKey(piMetabase, wzWebBase, L"Root"); | ||
| 43 | ExitOnFailure(hr, "Failed to create web root"); | ||
| 44 | |||
| 45 | hr = ScaWriteMetabaseValue(piMetabase, wzWebBase, L"Root", MD_KEY_TYPE, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, (LPVOID)L"IIsWebVirtualDir"); | ||
| 46 | ExitOnFailure(hr, "Failed to set key type for web root"); | ||
| 47 | |||
| 48 | ui = 0x4000003e; // 1073741886; // default directory browsing rights | ||
| 49 | hr = ScaWriteMetabaseValue(piMetabase, wzWebBase, L"Root", MD_DIRECTORY_BROWSING, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, (LPVOID)((DWORD_PTR)ui)); | ||
| 50 | ExitOnFailure(hr, "Failed to set directory browsing for web"); | ||
| 51 | |||
| 52 | hr = ScaCreateMetabaseKey(piMetabase, wzWebBase, L"Filters"); | ||
| 53 | ExitOnFailure(hr, "Failed to create web filters root"); | ||
| 54 | |||
| 55 | hr = ScaWriteMetabaseValue(piMetabase, wzWebBase, L"Filters", MD_KEY_TYPE, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, (LPVOID)L"IIsFilters"); | ||
| 56 | ExitOnFailure(hr, "Failed to set key for web filters root"); | ||
| 57 | |||
| 58 | hr = ScaWriteMetabaseValue(piMetabase, wzWebBase, L"Filters", MD_FILTER_LOAD_ORDER, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, (LPVOID)L""); | ||
| 59 | ExitOnFailure(hr, "Failed to set empty load order for web"); | ||
| 60 | |||
| 61 | LExit: | ||
| 62 | return hr; | ||
| 63 | } | ||
| 64 | |||
| 65 | |||
| 66 | HRESULT ScaDeleteApp(IMSAdminBase* piMetabase, LPCWSTR wzWebRoot) | ||
| 67 | { | ||
| 68 | Assert(piMetabase); | ||
| 69 | Unused(piMetabase); | ||
| 70 | |||
| 71 | HRESULT hr = S_OK; | ||
| 72 | WCHAR wzKey[METADATA_MAX_NAME_LEN]; | ||
| 73 | |||
| 74 | WCHAR* pwzCustomActionData = NULL; | ||
| 75 | |||
| 76 | hr = WcaWriteIntegerToCaData(MBA_DELETEAPP, &pwzCustomActionData); | ||
| 77 | ExitOnFailure(hr, "Failed to add metabase delete app directive to CustomActionData"); | ||
| 78 | |||
| 79 | hr = ::StringCchCopyW(wzKey, countof(wzKey), wzWebRoot); | ||
| 80 | ExitOnFailure(hr, "Failed to copy webroot string to key"); | ||
| 81 | hr = WcaWriteStringToCaData(wzKey, &pwzCustomActionData); | ||
| 82 | ExitOnFailure(hr, "Failed to add metabase key to CustomActionData"); | ||
| 83 | |||
| 84 | hr = ScaAddToIisConfiguration(pwzCustomActionData, COST_IIS_DELETEAPP); | ||
| 85 | ExitOnFailure(hr, "Failed to add ScaDeleteApp action data: %ls cost: %d", pwzCustomActionData, COST_IIS_DELETEAPP); | ||
| 86 | |||
| 87 | LExit: | ||
| 88 | ReleaseStr(pwzCustomActionData); | ||
| 89 | |||
| 90 | return hr; | ||
| 91 | } | ||
| 92 | |||
| 93 | |||
| 94 | HRESULT ScaCreateApp(IMSAdminBase* piMetabase, LPCWSTR wzWebRoot, | ||
| 95 | DWORD dwIsolation) | ||
| 96 | { | ||
| 97 | Assert(piMetabase); | ||
| 98 | Unused(piMetabase); | ||
| 99 | |||
| 100 | HRESULT hr = S_OK; | ||
| 101 | WCHAR wzKey[METADATA_MAX_NAME_LEN]; | ||
| 102 | BOOL fInProc = FALSE; | ||
| 103 | |||
| 104 | WCHAR* pwzCustomActionData = NULL; | ||
| 105 | |||
| 106 | hr = WcaWriteIntegerToCaData(MBA_CREATEAPP, &pwzCustomActionData); | ||
| 107 | ExitOnFailure(hr, "Failed to add metabase create app directive to CustomActionData"); | ||
| 108 | |||
| 109 | hr = ::StringCchCopyW(wzKey, countof(wzKey), wzWebRoot); | ||
| 110 | ExitOnFailure(hr, "Failed to copy webroot string to key"); | ||
| 111 | hr = WcaWriteStringToCaData(wzKey, &pwzCustomActionData); | ||
| 112 | ExitOnFailure(hr, "Failed to add metabase key to CustomActionData"); | ||
| 113 | |||
| 114 | if (0 == dwIsolation) | ||
| 115 | fInProc = TRUE; | ||
| 116 | else | ||
| 117 | fInProc = FALSE; | ||
| 118 | |||
| 119 | hr = WcaWriteIntegerToCaData(fInProc, &pwzCustomActionData); | ||
| 120 | ExitOnFailure(hr, "Failed to add isolation value to CustomActionData"); | ||
| 121 | |||
| 122 | hr = ScaAddToIisConfiguration(pwzCustomActionData, COST_IIS_CREATEAPP); | ||
| 123 | ExitOnFailure(hr, "Failed to add ScaCreateApp action data: %ls cost: %d", pwzCustomActionData, COST_IIS_CREATEAPP); | ||
| 124 | |||
| 125 | LExit: | ||
| 126 | ReleaseStr(pwzCustomActionData); | ||
| 127 | |||
| 128 | return hr; | ||
| 129 | } | ||
| 130 | |||
| 131 | |||
| 132 | HRESULT ScaCreateMetabaseKey(IMSAdminBase* piMetabase, LPCWSTR wzRootKey, | ||
| 133 | LPCWSTR wzSubKey) | ||
| 134 | { | ||
| 135 | Assert(piMetabase); | ||
| 136 | Unused(piMetabase); | ||
| 137 | |||
| 138 | HRESULT hr = S_OK; | ||
| 139 | WCHAR wzKey[METADATA_MAX_NAME_LEN]; | ||
| 140 | WCHAR* pwzCustomActionData = NULL; | ||
| 141 | |||
| 142 | hr = ::StringCchCopyW(wzKey, countof(wzKey), wzRootKey); | ||
| 143 | ExitOnFailure(hr, "Failed to copy root key string to key"); | ||
| 144 | if (L'/' != *(wzKey + lstrlenW(wzRootKey))) | ||
| 145 | { | ||
| 146 | hr = ::StringCchCatW(wzKey, countof(wzKey), L"/"); | ||
| 147 | ExitOnFailure(hr, "Failed to concatenate / to key string"); | ||
| 148 | } | ||
| 149 | if (wzSubKey && *wzSubKey) | ||
| 150 | { | ||
| 151 | if (L'/' == *wzSubKey) | ||
| 152 | { | ||
| 153 | hr = ::StringCchCatW(wzKey, countof(wzKey), wzSubKey + 1); | ||
| 154 | ExitOnFailure(hr, "Failed to concatenate subkey (minus slash) to key string"); | ||
| 155 | } | ||
| 156 | else | ||
| 157 | { | ||
| 158 | hr = ::StringCchCatW(wzKey, countof(wzKey), wzSubKey); | ||
| 159 | ExitOnFailure(hr, "Failed to concatenate subkey to key string"); | ||
| 160 | } | ||
| 161 | } | ||
| 162 | |||
| 163 | hr = WcaWriteIntegerToCaData(MBA_CREATEKEY, &pwzCustomActionData); | ||
| 164 | ExitOnFailure(hr, "Failed to add metabase delete key directive to CustomActionData"); | ||
| 165 | |||
| 166 | hr = WcaWriteStringToCaData(wzKey, &pwzCustomActionData); | ||
| 167 | ExitOnFailure(hr, "Failed to add metabase key to CustomActionData"); | ||
| 168 | |||
| 169 | hr = ScaAddToIisConfiguration(pwzCustomActionData, COST_IIS_CREATEKEY); | ||
| 170 | ExitOnFailure(hr, "Failed to add ScaCreateMetabaseKey action data: %ls cost: %d", pwzCustomActionData, COST_IIS_CREATEKEY); | ||
| 171 | |||
| 172 | LExit: | ||
| 173 | ReleaseStr(pwzCustomActionData); | ||
| 174 | |||
| 175 | return hr; | ||
| 176 | } | ||
| 177 | |||
| 178 | |||
| 179 | HRESULT ScaDeleteMetabaseKey(IMSAdminBase* piMetabase, LPCWSTR wzRootKey, | ||
| 180 | LPCWSTR wzSubKey) | ||
| 181 | { | ||
| 182 | Assert(piMetabase); | ||
| 183 | Unused(piMetabase); | ||
| 184 | |||
| 185 | HRESULT hr = S_OK; | ||
| 186 | WCHAR wzKey[METADATA_MAX_NAME_LEN]; | ||
| 187 | WCHAR* pwzCustomActionData = NULL; | ||
| 188 | |||
| 189 | hr = ::StringCchCopyW(wzKey, countof(wzKey), wzRootKey); | ||
| 190 | ExitOnFailure(hr, "Failed to copy root key string to key"); | ||
| 191 | if (L'/' != *(wzKey + lstrlenW(wzRootKey))) | ||
| 192 | { | ||
| 193 | hr = ::StringCchCatW(wzKey, countof(wzKey), L"/"); | ||
| 194 | ExitOnFailure(hr, "Failed to concatenate / to key string"); | ||
| 195 | } | ||
| 196 | if (*wzSubKey) | ||
| 197 | { | ||
| 198 | if (L'/' == *wzSubKey) | ||
| 199 | { | ||
| 200 | hr = ::StringCchCatW(wzKey, countof(wzKey), wzSubKey + 1); | ||
| 201 | ExitOnFailure(hr, "Failed to concatenate subkey (minus slash) to key string"); | ||
| 202 | } | ||
| 203 | else | ||
| 204 | { | ||
| 205 | hr = ::StringCchCatW(wzKey, countof(wzKey), wzSubKey); | ||
| 206 | ExitOnFailure(hr, "Failed to concatenate subkey to key string"); | ||
| 207 | } | ||
| 208 | } | ||
| 209 | |||
| 210 | hr = WcaWriteIntegerToCaData(MBA_DELETEKEY, &pwzCustomActionData); | ||
| 211 | ExitOnFailure(hr, "Failed to add metabase delete key directive to CustomActionData"); | ||
| 212 | |||
| 213 | hr = WcaWriteStringToCaData(wzKey, &pwzCustomActionData); | ||
| 214 | ExitOnFailure(hr, "Failed to add metabase key to CustomActionData"); | ||
| 215 | |||
| 216 | hr = ScaAddToIisConfiguration(pwzCustomActionData, COST_IIS_DELETEKEY); | ||
| 217 | ExitOnFailure(hr, "Failed to add ScaDeleteMetabaseKey action data: %ls cost: %d", pwzCustomActionData, COST_IIS_DELETEKEY); | ||
| 218 | |||
| 219 | LExit: | ||
| 220 | ReleaseStr(pwzCustomActionData); | ||
| 221 | |||
| 222 | return hr; | ||
| 223 | } | ||
| 224 | |||
| 225 | |||
| 226 | HRESULT ScaDeleteMetabaseValue(IMSAdminBase* piMetabase, LPCWSTR wzRootKey, | ||
| 227 | LPCWSTR wzSubKey, DWORD dwIdentifier, | ||
| 228 | DWORD dwDataType) | ||
| 229 | { | ||
| 230 | Assert(piMetabase); | ||
| 231 | Unused(piMetabase); | ||
| 232 | |||
| 233 | HRESULT hr = S_OK; | ||
| 234 | WCHAR wzKey[METADATA_MAX_NAME_LEN]; | ||
| 235 | WCHAR* pwzCustomActionData = NULL; | ||
| 236 | |||
| 237 | hr = ::StringCchCopyW(wzKey, countof(wzKey), wzRootKey); | ||
| 238 | ExitOnFailure(hr, "Failed to copy root key string to key"); | ||
| 239 | if (L'/' != *(wzKey + lstrlenW(wzRootKey))) | ||
| 240 | { | ||
| 241 | hr = ::StringCchCatW(wzKey, countof(wzKey), L"/"); | ||
| 242 | ExitOnFailure(hr, "Failed to concatenate / to key string"); | ||
| 243 | } | ||
| 244 | |||
| 245 | if (wzSubKey && *wzSubKey) | ||
| 246 | { | ||
| 247 | if (L'/' == *wzSubKey) | ||
| 248 | { | ||
| 249 | hr = ::StringCchCatW(wzKey, countof(wzKey), wzSubKey + 1); | ||
| 250 | ExitOnFailure(hr, "Failed to concatenate subkey (minus slash) to key string"); | ||
| 251 | } | ||
| 252 | else | ||
| 253 | { | ||
| 254 | hr = ::StringCchCatW(wzKey, countof(wzKey), wzSubKey); | ||
| 255 | ExitOnFailure(hr, "Failed to concatenate subkey to key string"); | ||
| 256 | } | ||
| 257 | } | ||
| 258 | |||
| 259 | hr = WcaWriteIntegerToCaData(MBA_DELETEVALUE, &pwzCustomActionData); | ||
| 260 | ExitOnFailure(hr, "Failed to add metabase write value directive to CustomActionData"); | ||
| 261 | |||
| 262 | hr = WcaWriteStringToCaData(wzKey, &pwzCustomActionData); | ||
| 263 | ExitOnFailure(hr, "Failed to add metabase key to CustomActionData"); | ||
| 264 | |||
| 265 | hr = WcaWriteIntegerToCaData(dwIdentifier, &pwzCustomActionData); | ||
| 266 | ExitOnFailure(hr, "Failed to add metabase identifier to CustomActionData"); | ||
| 267 | |||
| 268 | hr = WcaWriteIntegerToCaData(dwDataType, &pwzCustomActionData); | ||
| 269 | ExitOnFailure(hr, "Failed to add metabase data type to CustomActionData"); | ||
| 270 | |||
| 271 | hr = ScaAddToIisConfiguration(pwzCustomActionData, COST_IIS_DELETEVALUE); | ||
| 272 | ExitOnFailure(hr, "Failed to add ScaDeleteMetabaseValue action data: %ls, cost: %d", pwzCustomActionData, COST_IIS_DELETEVALUE); | ||
| 273 | |||
| 274 | LExit: | ||
| 275 | ReleaseStr(pwzCustomActionData); | ||
| 276 | |||
| 277 | return hr; | ||
| 278 | } | ||
| 279 | |||
| 280 | |||
| 281 | #pragma prefast(push) | ||
| 282 | #pragma prefast(disable:25120) // Disable "requires count parameter" warning - we do have a way to distinguish buffer sizes in all situations, | ||
| 283 | // it just depends on the dwDataType, and there's no way to annotate the situation in SAL | ||
| 284 | HRESULT ScaWriteMetabaseValue(IMSAdminBase* piMetabase, LPCWSTR wzRootKey, | ||
| 285 | LPCWSTR wzSubKey, DWORD dwIdentifier, | ||
| 286 | DWORD dwAttributes, DWORD dwUserType, | ||
| 287 | DWORD dwDataType, LPVOID pvData) | ||
| 288 | #pragma prefast(pop) | ||
| 289 | { | ||
| 290 | Assert(piMetabase && (pvData || (DWORD_METADATA == dwDataType))); // pvData may be 0 if it is DWORD data | ||
| 291 | Unused(piMetabase); | ||
| 292 | |||
| 293 | HRESULT hr = S_OK; | ||
| 294 | WCHAR wzKey[METADATA_MAX_NAME_LEN]; | ||
| 295 | WCHAR* pwzCustomActionData = NULL; | ||
| 296 | |||
| 297 | if (BINARY_METADATA == dwDataType) | ||
| 298 | { | ||
| 299 | ExitOnNull(pvData, hr, E_INVALIDARG, "Failed to write binary metadata - no data available to write"); | ||
| 300 | } | ||
| 301 | |||
| 302 | hr = ::StringCchCopyW(wzKey, countof(wzKey), wzRootKey); | ||
| 303 | ExitOnFailure(hr, "Failed to copy root key string to key"); | ||
| 304 | if (L'/' != *(wzKey + lstrlenW(wzRootKey))) | ||
| 305 | { | ||
| 306 | hr = ::StringCchCatW(wzKey, countof(wzKey), L"/"); | ||
| 307 | ExitOnFailure(hr, "Failed to concatenate / to key string"); | ||
| 308 | } | ||
| 309 | if (wzSubKey && *wzSubKey) | ||
| 310 | { | ||
| 311 | if (L'/' == *wzSubKey) | ||
| 312 | { | ||
| 313 | hr = ::StringCchCatW(wzKey, countof(wzKey), wzSubKey + 1); | ||
| 314 | ExitOnFailure(hr, "Failed to concatenate subkey (minus slash) to key string"); | ||
| 315 | } | ||
| 316 | else | ||
| 317 | { | ||
| 318 | hr = ::StringCchCatW(wzKey, countof(wzKey), wzSubKey); | ||
| 319 | ExitOnFailure(hr, "Failed to concatenate subkey to key string"); | ||
| 320 | } | ||
| 321 | } | ||
| 322 | |||
| 323 | hr = WcaWriteIntegerToCaData(MBA_WRITEVALUE, &pwzCustomActionData); | ||
| 324 | ExitOnFailure(hr, "Failed to add metabase write value directive to CustomActionData"); | ||
| 325 | |||
| 326 | hr = WcaWriteStringToCaData(wzKey, &pwzCustomActionData); | ||
| 327 | ExitOnFailure(hr, "Failed to add metabase key to CustomActionData"); | ||
| 328 | |||
| 329 | hr = WcaWriteIntegerToCaData(dwIdentifier, &pwzCustomActionData); | ||
| 330 | ExitOnFailure(hr, "Failed to add metabase identifier to CustomActionData"); | ||
| 331 | |||
| 332 | hr = WcaWriteIntegerToCaData(dwAttributes, &pwzCustomActionData); | ||
| 333 | ExitOnFailure(hr, "Failed to add metabase attributes to CustomActionData"); | ||
| 334 | |||
| 335 | hr = WcaWriteIntegerToCaData(dwUserType, &pwzCustomActionData); | ||
| 336 | ExitOnFailure(hr, "Failed to add metabase user type to CustomActionData"); | ||
| 337 | |||
| 338 | hr = WcaWriteIntegerToCaData(dwDataType, &pwzCustomActionData); | ||
| 339 | ExitOnFailure(hr, "Failed to add metabase data type to CustomActionData"); | ||
| 340 | |||
| 341 | switch (dwDataType) | ||
| 342 | { | ||
| 343 | case DWORD_METADATA: | ||
| 344 | hr = WcaWriteIntegerToCaData((DWORD)((DWORD_PTR)pvData), &pwzCustomActionData); | ||
| 345 | break; | ||
| 346 | case STRING_METADATA: | ||
| 347 | hr = WcaWriteStringToCaData((LPCWSTR)pvData, &pwzCustomActionData); | ||
| 348 | break; | ||
| 349 | case MULTISZ_METADATA: | ||
| 350 | { | ||
| 351 | // change NULLs to unprintable character to create a 'safe' MULTISZ string | ||
| 352 | LPWSTR pwz = (LPWSTR)pvData; | ||
| 353 | for (;;) | ||
| 354 | { | ||
| 355 | if ('\0' == *pwz) | ||
| 356 | { | ||
| 357 | *pwz = MAGIC_MULTISZ_CHAR; | ||
| 358 | if ('\0' == *(pwz + 1)) // second null back to back means end of string | ||
| 359 | break; | ||
| 360 | } | ||
| 361 | |||
| 362 | ++pwz; | ||
| 363 | } | ||
| 364 | |||
| 365 | hr = WcaWriteStringToCaData((LPCWSTR)pvData, &pwzCustomActionData); | ||
| 366 | } | ||
| 367 | break; | ||
| 368 | case BINARY_METADATA: | ||
| 369 | hr = WcaWriteStreamToCaData(((BLOB*) pvData)->pBlobData, ((BLOB*) pvData)->cbSize, &pwzCustomActionData); | ||
| 370 | break; | ||
| 371 | default: | ||
| 372 | hr = E_UNEXPECTED; | ||
| 373 | } | ||
| 374 | ExitOnFailure(hr, "Failed to add metabase data to CustomActionData"); | ||
| 375 | |||
| 376 | // TODO: maybe look the key up and make sure we're not just writing the same value that already there | ||
| 377 | |||
| 378 | hr = ScaAddToIisConfiguration(pwzCustomActionData, COST_IIS_WRITEVALUE); | ||
| 379 | ExitOnFailure(hr, "Failed to add ScaWriteMetabaseValue action data: %ls, cost: %d", pwzCustomActionData, COST_IIS_WRITEVALUE); | ||
| 380 | |||
| 381 | LExit: | ||
| 382 | ReleaseStr(pwzCustomActionData); | ||
| 383 | |||
| 384 | return hr; | ||
| 385 | } | ||
| 386 | |||
| 387 | |||
| 388 | HRESULT ScaAddToIisConfiguration(LPCWSTR pwzData, DWORD dwCost) | ||
| 389 | { | ||
| 390 | HRESULT hr = S_OK; | ||
| 391 | |||
| 392 | hr = WcaWriteStringToCaData(pwzData, &vpwzCustomActionData); | ||
| 393 | ExitOnFailure(hr, "failed to add to metabase configuration data string: %ls", pwzData); | ||
| 394 | |||
| 395 | vdwCustomActionCost += dwCost; | ||
| 396 | |||
| 397 | LExit: | ||
| 398 | return hr; | ||
| 399 | } | ||
| 400 | |||
| 401 | |||
| 402 | HRESULT ScaWriteConfigurationScript(__in LPCWSTR pwzCaScriptKey) | ||
| 403 | { | ||
| 404 | HRESULT hr = S_OK; | ||
| 405 | WCA_CASCRIPT_HANDLE hScript = NULL; | ||
| 406 | LPWSTR pwzHashString = NULL; | ||
| 407 | BYTE rgbActualHash[SHA1_HASH_LEN] = { }; | ||
| 408 | DWORD dwHashedBytes = SHA1_HASH_LEN; | ||
| 409 | |||
| 410 | // Create CaScript for communication with WriteMetabaseChanges | ||
| 411 | hr = WcaCaScriptCreate(WCA_ACTION_INSTALL, WCA_CASCRIPT_SCHEDULED, FALSE, pwzCaScriptKey, FALSE, &hScript); | ||
| 412 | ExitOnFailure(hr, "Failed to write ca script for WriteMetabaseChanges script."); | ||
| 413 | |||
| 414 | if (vpwzCustomActionData && *vpwzCustomActionData) | ||
| 415 | { | ||
| 416 | // Write the actual custom action data to the ca script | ||
| 417 | WcaCaScriptWriteString(hScript, vpwzCustomActionData); | ||
| 418 | |||
| 419 | hr = CrypHashBuffer((BYTE*)vpwzCustomActionData, sizeof(vpwzCustomActionData) * sizeof(WCHAR), PROV_RSA_AES, CALG_SHA1, rgbActualHash, dwHashedBytes); | ||
| 420 | ExitOnFailure(hr, "Failed to calculate hash of CustomAction data."); | ||
| 421 | |||
| 422 | hr = StrAlloc(&pwzHashString, ((dwHashedBytes * 2) + 1)); | ||
| 423 | ExitOnFailure(hr, "Failed to allocate string for script hash"); | ||
| 424 | |||
| 425 | hr = StrHexEncode(rgbActualHash, dwHashedBytes, pwzHashString, ((dwHashedBytes * 2) + 1)); | ||
| 426 | ExitOnFailure(hr, "Failed to convert hash bytes to string."); | ||
| 427 | |||
| 428 | WcaLog(LOGMSG_VERBOSE, "Custom action data hash: %ls", pwzHashString); | ||
| 429 | WcaLog(LOGMSG_TRACEONLY, "Custom action data being written to ca script: %ls", vpwzCustomActionData); | ||
| 430 | } | ||
| 431 | else | ||
| 432 | hr = S_FALSE; | ||
| 433 | |||
| 434 | LExit: | ||
| 435 | // Release the string | ||
| 436 | ReleaseStr(vpwzCustomActionData); | ||
| 437 | ReleaseStr(pwzHashString); | ||
| 438 | |||
| 439 | // Flush the ca script to disk as best we can | ||
| 440 | WcaCaScriptFlush(hScript); | ||
| 441 | |||
| 442 | WcaCaScriptClose(hScript, WCA_CASCRIPT_CLOSE_PRESERVE); | ||
| 443 | |||
| 444 | return hr; | ||
| 445 | } | ||
| 446 | |||
| 447 | |||
| 448 | HRESULT ScaLoadMetabase(IMSAdminBase** ppiMetabase) | ||
| 449 | { | ||
| 450 | HRESULT hr = S_OK; | ||
| 451 | UINT er = ERROR_SUCCESS; | ||
| 452 | |||
| 453 | // if IIS was uninstalled (thus no IID_IMSAdminBase) allow the | ||
| 454 | // user to still uninstall this package by clicking "Ignore" | ||
| 455 | do | ||
| 456 | { | ||
| 457 | hr = ::CoCreateInstance(CLSID_MSAdminBase, NULL, CLSCTX_ALL, IID_IMSAdminBase, (void**)ppiMetabase); | ||
| 458 | if (FAILED(hr)) | ||
| 459 | { | ||
| 460 | WcaLog(LOGMSG_STANDARD, "failed to get IID_IMSAdminBase Object"); | ||
| 461 | er = WcaErrorMessage(msierrIISCannotConnect, hr, INSTALLMESSAGE_ERROR | MB_ABORTRETRYIGNORE, 0); | ||
| 462 | switch (er) | ||
| 463 | { | ||
| 464 | case IDABORT: | ||
| 465 | ExitFunction(); // bail with the error result from the CoCreate to kick off a rollback | ||
| 466 | case IDRETRY: | ||
| 467 | hr = S_FALSE; // hit me, baby, one more time | ||
| 468 | break; | ||
| 469 | case IDIGNORE: | ||
| 470 | hr = S_OK; // pretend everything is okay and bail | ||
| 471 | break; | ||
| 472 | default: // For failure on uninstall continue | ||
| 473 | hr = S_OK; | ||
| 474 | break; | ||
| 475 | } | ||
| 476 | } | ||
| 477 | } while (S_FALSE == hr); | ||
| 478 | |||
| 479 | LExit: | ||
| 480 | return hr; | ||
| 481 | } | ||
diff --git a/src/ca/scaiis.h b/src/ca/scaiis.h new file mode 100644 index 00000000..4c743edf --- /dev/null +++ b/src/ca/scaiis.h | |||
| @@ -0,0 +1,33 @@ | |||
| 1 | #pragma once | ||
| 2 | // 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. | ||
| 3 | |||
| 4 | |||
| 5 | HRESULT ScaMetabaseTransaction(__in_z LPCWSTR wzBackup); | ||
| 6 | |||
| 7 | HRESULT ScaCreateWeb(IMSAdminBase* piMetabase, LPCWSTR wzWeb, LPCWSTR wzWebBase); | ||
| 8 | |||
| 9 | HRESULT ScaDeleteApp(IMSAdminBase* piMetabase, LPCWSTR wzWebRoot); | ||
| 10 | |||
| 11 | HRESULT ScaCreateApp(IMSAdminBase* piMetabase, LPCWSTR wzWebRoot, | ||
| 12 | DWORD dwIsolation); | ||
| 13 | |||
| 14 | HRESULT ScaCreateMetabaseKey(IMSAdminBase* piMetabase, LPCWSTR wzRootKey, | ||
| 15 | LPCWSTR wzSubKey); | ||
| 16 | |||
| 17 | HRESULT ScaDeleteMetabaseKey(IMSAdminBase* piMetabase, LPCWSTR wzRootKey, | ||
| 18 | LPCWSTR wzSubKey); | ||
| 19 | |||
| 20 | HRESULT ScaWriteMetabaseValue(IMSAdminBase* piMetabase, LPCWSTR wzRootKey, | ||
| 21 | LPCWSTR wzSubKey, DWORD dwIdentifier, | ||
| 22 | DWORD dwAttributes, DWORD dwUserType, | ||
| 23 | DWORD dwDataType, LPVOID pvData); | ||
| 24 | |||
| 25 | HRESULT ScaDeleteMetabaseValue(IMSAdminBase* piMetabase, LPCWSTR wzRootKey, | ||
| 26 | LPCWSTR wzSubKey, DWORD dwIdentifier, | ||
| 27 | DWORD dwDataType); | ||
| 28 | |||
| 29 | HRESULT ScaWriteConfigurationScript(LPCWSTR pwzCaScriptKey); | ||
| 30 | |||
| 31 | HRESULT ScaAddToIisConfiguration(LPCWSTR pwzData, DWORD dwCost); | ||
| 32 | |||
| 33 | HRESULT ScaLoadMetabase(IMSAdminBase** piMetabase); | ||
diff --git a/src/ca/scaiis7.cpp b/src/ca/scaiis7.cpp new file mode 100644 index 00000000..f0f4a629 --- /dev/null +++ b/src/ca/scaiis7.cpp | |||
| @@ -0,0 +1,74 @@ | |||
| 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 | #include "precomp.h" | ||
| 4 | |||
| 5 | #define COST_IIS_WRITEKEY 10 | ||
| 6 | |||
| 7 | HRESULT ScaIIS7ConfigTransaction(LPCWSTR wzBackup) | ||
| 8 | { | ||
| 9 | HRESULT hr = S_OK; | ||
| 10 | |||
| 11 | hr = WcaDoDeferredAction(L"StartIIS7ConfigTransaction", wzBackup, COST_IIS_TRANSACTIONS); | ||
| 12 | ExitOnFailure(hr, "Failed to schedule StartIIS7ConfigTransaction"); | ||
| 13 | |||
| 14 | hr = WcaDoDeferredAction(L"RollbackIIS7ConfigTransaction", wzBackup, 0); // rollback cost is irrelevant | ||
| 15 | ExitOnFailure(hr, "Failed to schedule RollbackIIS7ConfigTransaction"); | ||
| 16 | |||
| 17 | hr = WcaDoDeferredAction(L"CommitIIS7ConfigTransaction", wzBackup, 0); // commit is free | ||
| 18 | ExitOnFailure(hr, "Failed to schedule StartIIS7ConfigTransaction"); | ||
| 19 | |||
| 20 | LExit: | ||
| 21 | return hr; | ||
| 22 | } | ||
| 23 | |||
| 24 | HRESULT ScaWriteConfigString(const LPCWSTR wzValue) | ||
| 25 | { | ||
| 26 | HRESULT hr = S_OK; | ||
| 27 | WCHAR* pwzCustomActionData = NULL; | ||
| 28 | |||
| 29 | hr = WcaWriteStringToCaData(wzValue, &pwzCustomActionData); | ||
| 30 | ExitOnFailure(hr, "Failed to add metabase delete key directive to CustomActionData"); | ||
| 31 | |||
| 32 | hr = ScaAddToIisConfiguration(pwzCustomActionData, COST_IIS_WRITEKEY); | ||
| 33 | ExitOnFailure(hr, "Failed to add ScaWriteMetabaseValue action data: %ls, cost: %d", pwzCustomActionData, COST_IIS_WRITEKEY); | ||
| 34 | |||
| 35 | LExit: | ||
| 36 | ReleaseStr(pwzCustomActionData); | ||
| 37 | |||
| 38 | return hr; | ||
| 39 | } | ||
| 40 | |||
| 41 | HRESULT ScaWriteConfigInteger(DWORD dwValue) | ||
| 42 | { | ||
| 43 | HRESULT hr = S_OK; | ||
| 44 | WCHAR* pwzCustomActionData = NULL; | ||
| 45 | |||
| 46 | hr = WcaWriteIntegerToCaData(dwValue, &pwzCustomActionData); | ||
| 47 | ExitOnFailure(hr, "Failed to add metabase delete key directive to CustomActionData"); | ||
| 48 | |||
| 49 | hr = ScaAddToIisConfiguration(pwzCustomActionData, COST_IIS_WRITEKEY); | ||
| 50 | ExitOnFailure(hr, "Failed to add ScaWriteMetabaseValue action data: %ls, cost: %d", pwzCustomActionData, COST_IIS_WRITEKEY); | ||
| 51 | |||
| 52 | LExit: | ||
| 53 | ReleaseStr(pwzCustomActionData); | ||
| 54 | |||
| 55 | return hr; | ||
| 56 | } | ||
| 57 | |||
| 58 | HRESULT ScaWriteConfigID(IIS_CONFIG_ACTION emID) | ||
| 59 | { | ||
| 60 | HRESULT hr = S_OK; | ||
| 61 | WCHAR* pwzCustomActionData = NULL; | ||
| 62 | |||
| 63 | hr = WcaWriteIntegerToCaData(emID, &pwzCustomActionData); | ||
| 64 | ExitOnFailure(hr, "Failed to add metabase delete key directive to CustomActionData"); | ||
| 65 | |||
| 66 | hr = ScaAddToIisConfiguration(pwzCustomActionData, COST_IIS_WRITEKEY); | ||
| 67 | ExitOnFailure(hr, "Failed to add ScaWriteMetabaseValue action data: %ls, cost: %d", pwzCustomActionData, COST_IIS_WRITEKEY); | ||
| 68 | |||
| 69 | LExit: | ||
| 70 | ReleaseStr(pwzCustomActionData); | ||
| 71 | |||
| 72 | return hr; | ||
| 73 | } | ||
| 74 | |||
diff --git a/src/ca/scaiis7.h b/src/ca/scaiis7.h new file mode 100644 index 00000000..f398deca --- /dev/null +++ b/src/ca/scaiis7.h | |||
| @@ -0,0 +1,17 @@ | |||
| 1 | #pragma once | ||
| 2 | // 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. | ||
| 3 | |||
| 4 | |||
| 5 | HRESULT ScaScheduleIIS7Configuration(); | ||
| 6 | |||
| 7 | HRESULT ScaIIS7ConfigTransaction(__in_z LPCWSTR wzBackup); | ||
| 8 | |||
| 9 | HRESULT ScaCreateApp7(__in_z LPCWSTR wzWebRoot, DWORD dwIsolation); | ||
| 10 | |||
| 11 | HRESULT ScaDeleteConfigElement(IIS_CONFIG_ACTION emElement, LPCWSTR wzSubKey); | ||
| 12 | |||
| 13 | HRESULT ScaWriteConfigString(__in_z const LPCWSTR wzValue); | ||
| 14 | |||
| 15 | HRESULT ScaWriteConfigID(IIS_CONFIG_ACTION emID); | ||
| 16 | |||
| 17 | HRESULT ScaWriteConfigInteger(DWORD dwValue); | ||
diff --git a/src/ca/scamimemap.cpp b/src/ca/scamimemap.cpp new file mode 100644 index 00000000..8afe99f9 --- /dev/null +++ b/src/ca/scamimemap.cpp | |||
| @@ -0,0 +1,200 @@ | |||
| 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 | #include "precomp.h" | ||
| 4 | |||
| 5 | enum eMimeMapQuery { mmqMimeMap = 1, mmqParentType, mmqParentValue, | ||
| 6 | mmqMimeType, mmqExtension}; | ||
| 7 | |||
| 8 | // prototypes | ||
| 9 | static HRESULT AddMimeMapToList(SCA_MIMEMAP** ppsmmList); | ||
| 10 | |||
| 11 | |||
| 12 | void ScaMimeMapFreeList(SCA_MIMEMAP* psmmList) | ||
| 13 | { | ||
| 14 | SCA_MIMEMAP* psmmDelete = psmmList; | ||
| 15 | while (psmmList) | ||
| 16 | { | ||
| 17 | psmmDelete = psmmList; | ||
| 18 | psmmList = psmmList->psmmNext; | ||
| 19 | |||
| 20 | MemFree(psmmDelete); | ||
| 21 | } | ||
| 22 | } | ||
| 23 | |||
| 24 | |||
| 25 | HRESULT __stdcall ScaMimeMapRead( | ||
| 26 | SCA_MIMEMAP** ppsmmList, | ||
| 27 | __inout LPWSTR *ppwzCustomActionData | ||
| 28 | ) | ||
| 29 | { | ||
| 30 | HRESULT hr = S_OK; | ||
| 31 | MSIHANDLE hRec; | ||
| 32 | LPWSTR pwzData = NULL; | ||
| 33 | SCA_MIMEMAP* psmm; | ||
| 34 | WCA_WRAPQUERY_HANDLE hWrapQuery = NULL; | ||
| 35 | |||
| 36 | hr = WcaBeginUnwrapQuery(&hWrapQuery, ppwzCustomActionData); | ||
| 37 | ExitOnFailure(hr, "Failed to unwrap query for ScaMimeMapRead"); | ||
| 38 | |||
| 39 | if (0 == WcaGetQueryRecords(hWrapQuery)) | ||
| 40 | { | ||
| 41 | WcaLog(LOGMSG_VERBOSE, "Skipping ScaMimeMapRead() - required table not present"); | ||
| 42 | ExitFunction1(hr = S_FALSE); | ||
| 43 | } | ||
| 44 | |||
| 45 | // loop through all the mimemappings | ||
| 46 | while (S_OK == (hr = WcaFetchWrappedRecord(hWrapQuery, &hRec))) | ||
| 47 | { | ||
| 48 | hr = AddMimeMapToList(ppsmmList); | ||
| 49 | ExitOnFailure(hr, "failed to add mime map to list"); | ||
| 50 | |||
| 51 | psmm = *ppsmmList; | ||
| 52 | |||
| 53 | hr = WcaGetRecordString(hRec, mmqMimeMap, &pwzData); | ||
| 54 | ExitOnFailure(hr, "Failed to get MimeMap.MimeMap"); | ||
| 55 | hr = ::StringCchCopyW(psmm->wzMimeMap, countof(psmm->wzMimeMap), pwzData); | ||
| 56 | ExitOnFailure(hr, "Failed to copy mimemap string to mimemap object"); | ||
| 57 | |||
| 58 | hr = WcaGetRecordInteger(hRec, mmqParentType, &psmm->iParentType); | ||
| 59 | ExitOnFailure(hr, "Failed to get MimeMap.iParentType"); | ||
| 60 | |||
| 61 | hr = WcaGetRecordString(hRec, mmqParentValue, &pwzData); | ||
| 62 | ExitOnFailure(hr, "Failed to get MimeMap.ParentValue"); | ||
| 63 | hr = ::StringCchCopyW(psmm->wzParentValue, countof(psmm->wzParentValue), pwzData); | ||
| 64 | ExitOnFailure(hr, "Failed to copy parent value string to mimemap object"); | ||
| 65 | |||
| 66 | hr = WcaGetRecordString(hRec, mmqExtension, &pwzData); | ||
| 67 | ExitOnFailure(hr, "Failed to get MimeMap.Extension"); | ||
| 68 | hr = ::StringCchCopyW(psmm->wzExtension, countof(psmm->wzExtension), pwzData); | ||
| 69 | ExitOnFailure(hr, "Failed to copy extension string to mimemap object"); | ||
| 70 | |||
| 71 | hr = WcaGetRecordString(hRec, mmqMimeType, &pwzData); | ||
| 72 | ExitOnFailure(hr, "Failed to get MimeMap.MimeType"); | ||
| 73 | hr = ::StringCchCopyW(psmm->wzMimeType, countof(psmm->wzMimeType), pwzData); | ||
| 74 | ExitOnFailure(hr, "Failed to copy mimetype string to mimemap object"); | ||
| 75 | } | ||
| 76 | |||
| 77 | if (E_NOMOREITEMS == hr) | ||
| 78 | hr = S_OK; | ||
| 79 | ExitOnFailure(hr, "Failure while processing mimemappings"); | ||
| 80 | |||
| 81 | LExit: | ||
| 82 | WcaFinishUnwrapQuery(hWrapQuery); | ||
| 83 | |||
| 84 | ReleaseStr(pwzData); | ||
| 85 | |||
| 86 | return hr; | ||
| 87 | } | ||
| 88 | |||
| 89 | |||
| 90 | HRESULT ScaGetMimeMap(int iParentType, LPCWSTR wzParentValue, SCA_MIMEMAP **ppsmmList, SCA_MIMEMAP **ppsmmOut) | ||
| 91 | { | ||
| 92 | HRESULT hr = S_OK; | ||
| 93 | SCA_MIMEMAP* psmmAdd = NULL; | ||
| 94 | SCA_MIMEMAP* psmmLast = NULL; | ||
| 95 | |||
| 96 | *ppsmmOut = NULL; | ||
| 97 | |||
| 98 | if (!*ppsmmList) | ||
| 99 | return hr; | ||
| 100 | |||
| 101 | SCA_MIMEMAP* psmm = *ppsmmList; | ||
| 102 | while (psmm) | ||
| 103 | { | ||
| 104 | if (iParentType == psmm->iParentType && 0 == lstrcmpW(wzParentValue, psmm->wzParentValue)) | ||
| 105 | { | ||
| 106 | // Found a match, take this one out of the list and add it to the matched out list | ||
| 107 | psmmAdd = psmm; | ||
| 108 | |||
| 109 | if (psmmLast) | ||
| 110 | { | ||
| 111 | // If we're not at the beginning of the list tell the last node about it's new next (since we're taking away it's current next) | ||
| 112 | psmmLast->psmmNext = psmmAdd->psmmNext; | ||
| 113 | } | ||
| 114 | else | ||
| 115 | { | ||
| 116 | // If we are at the beginning (no psmmLast) update the beginning (since we're taking it) | ||
| 117 | *ppsmmList = psmm->psmmNext; | ||
| 118 | } | ||
| 119 | psmm = psmm->psmmNext; // move on | ||
| 120 | |||
| 121 | // Add the one we've removed to the beginning of the out list | ||
| 122 | psmmAdd->psmmNext = *ppsmmOut; | ||
| 123 | *ppsmmOut = psmmAdd; | ||
| 124 | } | ||
| 125 | else | ||
| 126 | { | ||
| 127 | psmmLast = psmm; // remember the last we that didn't match | ||
| 128 | psmm = psmm->psmmNext; // move on | ||
| 129 | } | ||
| 130 | } | ||
| 131 | |||
| 132 | return hr; | ||
| 133 | } | ||
| 134 | |||
| 135 | HRESULT ScaMimeMapCheckList(SCA_MIMEMAP* psmmList) | ||
| 136 | { | ||
| 137 | if (!psmmList) | ||
| 138 | return S_OK; | ||
| 139 | |||
| 140 | while (psmmList) | ||
| 141 | { | ||
| 142 | WcaLog(LOGMSG_STANDARD, "MimeMapping of %ls with ParentType=%d and ParentValue=%ls not used!", psmmList->wzMimeMap, psmmList->iParentType, psmmList->wzParentValue); | ||
| 143 | psmmList = psmmList->psmmNext; | ||
| 144 | } | ||
| 145 | |||
| 146 | return E_FAIL; | ||
| 147 | } | ||
| 148 | |||
| 149 | |||
| 150 | HRESULT ScaWriteMimeMap(IMSAdminBase* piMetabase, LPCWSTR wzRootOfWeb, | ||
| 151 | SCA_MIMEMAP* psmmList) | ||
| 152 | { | ||
| 153 | HRESULT hr = S_OK; | ||
| 154 | |||
| 155 | WCHAR wzMimeMap[8192]; | ||
| 156 | WCHAR *pwzNext = wzMimeMap; | ||
| 157 | const WCHAR *pwzMac = wzMimeMap + countof(wzMimeMap); // used to properly create the MULTI_SZ | ||
| 158 | |||
| 159 | // fill the MULTI_SZ wzMimeMap buffer for the MimeMap attribute | ||
| 160 | ::ZeroMemory(wzMimeMap, sizeof(wzMimeMap)); | ||
| 161 | |||
| 162 | for (SCA_MIMEMAP* psmm = psmmList; psmm; psmm = psmm->psmmNext) | ||
| 163 | { | ||
| 164 | hr = ::StringCchPrintfW(pwzNext, max(0, pwzMac - pwzNext), L"%s,%s", psmm->wzExtension, psmm->wzMimeType); | ||
| 165 | ExitOnFailure(hr, "Failed to set MimeMap string"); | ||
| 166 | |||
| 167 | pwzNext += lstrlenW(pwzNext) + 1; // reserve space for null | ||
| 168 | Assert(pwzNext <= pwzMac); | ||
| 169 | } | ||
| 170 | |||
| 171 | if (pwzNext != wzMimeMap) | ||
| 172 | { | ||
| 173 | // now write the CustomErrors to the metabase | ||
| 174 | hr = ScaWriteMetabaseValue(piMetabase, wzRootOfWeb, NULL, MD_MIME_MAP, METADATA_INHERIT, IIS_MD_UT_FILE, MULTISZ_METADATA, wzMimeMap); | ||
| 175 | ExitOnFailure(hr, "Failed to write MimeMap"); | ||
| 176 | } | ||
| 177 | else | ||
| 178 | { | ||
| 179 | WcaLog(LOGMSG_VERBOSE, "Skipping ScaWriteMimeMap() - no mappings found."); | ||
| 180 | ExitFunction1(hr = S_FALSE); | ||
| 181 | } | ||
| 182 | |||
| 183 | LExit: | ||
| 184 | return hr; | ||
| 185 | } | ||
| 186 | |||
| 187 | |||
| 188 | static HRESULT AddMimeMapToList(SCA_MIMEMAP** ppsmmList) | ||
| 189 | { | ||
| 190 | HRESULT hr = S_OK; | ||
| 191 | |||
| 192 | SCA_MIMEMAP* psmm = static_cast<SCA_MIMEMAP*>(MemAlloc(sizeof(SCA_MIMEMAP), TRUE)); | ||
| 193 | ExitOnNull(psmm, hr, E_OUTOFMEMORY, "failed to allocate memory for new mime map list element"); | ||
| 194 | |||
| 195 | psmm->psmmNext = *ppsmmList; | ||
| 196 | *ppsmmList = psmm; | ||
| 197 | |||
| 198 | LExit: | ||
| 199 | return hr; | ||
| 200 | } | ||
diff --git a/src/ca/scamimemap.h b/src/ca/scamimemap.h new file mode 100644 index 00000000..b50e82e9 --- /dev/null +++ b/src/ca/scamimemap.h | |||
| @@ -0,0 +1,33 @@ | |||
| 1 | #pragma once | ||
| 2 | // 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. | ||
| 3 | |||
| 4 | |||
| 5 | enum eMimeMapParentType { mmptVDir = 1, mmptWeb = 2 }; | ||
| 6 | |||
| 7 | struct SCA_MIMEMAP | ||
| 8 | { | ||
| 9 | // iis configuation information | ||
| 10 | WCHAR wzMimeMap[MAX_DARWIN_KEY + 1]; | ||
| 11 | int iParentType; | ||
| 12 | WCHAR wzParentValue[MAX_DARWIN_KEY + 1]; | ||
| 13 | WCHAR wzMimeType[MAX_DARWIN_KEY + 1]; | ||
| 14 | WCHAR wzExtension[MAX_DARWIN_KEY + 1]; | ||
| 15 | |||
| 16 | |||
| 17 | SCA_MIMEMAP* psmmNext; | ||
| 18 | }; | ||
| 19 | |||
| 20 | |||
| 21 | // prototypes | ||
| 22 | |||
| 23 | HRESULT __stdcall ScaMimeMapRead(SCA_MIMEMAP** ppsmmList, __inout LPWSTR *ppwzCustomActionData); | ||
| 24 | |||
| 25 | HRESULT ScaGetMimeMap(int iParentType, LPCWSTR wzParentValue, SCA_MIMEMAP **psmmList, SCA_MIMEMAP **ppsmmOut); | ||
| 26 | |||
| 27 | HRESULT ScaMimeMapCheckList(SCA_MIMEMAP* psmmList); | ||
| 28 | |||
| 29 | void ScaMimeMapFreeList(SCA_MIMEMAP* psmmList); | ||
| 30 | |||
| 31 | HRESULT ScaWriteMimeMap(IMSAdminBase* piMetabase, LPCWSTR wzRootOfWeb, | ||
| 32 | SCA_MIMEMAP* psmmList); | ||
| 33 | |||
diff --git a/src/ca/scamimemap7.cpp b/src/ca/scamimemap7.cpp new file mode 100644 index 00000000..f6689720 --- /dev/null +++ b/src/ca/scamimemap7.cpp | |||
| @@ -0,0 +1,68 @@ | |||
| 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 | #include "precomp.h" | ||
| 4 | |||
| 5 | // prototypes | ||
| 6 | HRESULT ScaWriteMimeMap7( | ||
| 7 | __in_z LPCWSTR wzWebName, | ||
| 8 | __in_z LPCWSTR wzRootOfWeb, | ||
| 9 | SCA_MIMEMAP* psmmList | ||
| 10 | ) | ||
| 11 | { | ||
| 12 | HRESULT hr = S_OK; | ||
| 13 | SCA_MIMEMAP* psmm; | ||
| 14 | |||
| 15 | //create the mimemap list for this vdir application | ||
| 16 | //all go to same web/root location tag | ||
| 17 | hr = ScaWriteConfigID(IIS_MIMEMAP_BEGIN); | ||
| 18 | ExitOnFailure(hr, "Failed to write mimemap begin id"); | ||
| 19 | hr = ScaWriteConfigString(wzWebName); //site name key | ||
| 20 | ExitOnFailure(hr, "Failed to write mimemap web key"); | ||
| 21 | hr = ScaWriteConfigString(wzRootOfWeb); //app path key | ||
| 22 | ExitOnFailure(hr, "Failed to write mimemap app key"); | ||
| 23 | |||
| 24 | psmm = psmmList; | ||
| 25 | |||
| 26 | while (psmm) | ||
| 27 | { | ||
| 28 | //create the Extension for this vdir application | ||
| 29 | hr = ScaWriteConfigID(IIS_MIMEMAP); | ||
| 30 | ExitOnFailure(hr, "Failed to write mimemap id"); | ||
| 31 | |||
| 32 | if (*psmm->wzExtension) | ||
| 33 | { | ||
| 34 | hr = ScaWriteConfigString(psmm->wzExtension); | ||
| 35 | } | ||
| 36 | else // blank means "*" (all) | ||
| 37 | { | ||
| 38 | hr = ScaWriteConfigString(L"*"); | ||
| 39 | } | ||
| 40 | ExitOnFailure(hr, "Failed to write mimemap extension"); | ||
| 41 | |||
| 42 | hr = ScaWriteConfigString(psmm->wzMimeType); | ||
| 43 | ExitOnFailure(hr, "Failed to write mimemap type"); | ||
| 44 | |||
| 45 | psmm = psmm->psmmNext; | ||
| 46 | } | ||
| 47 | |||
| 48 | hr = ScaWriteConfigID(IIS_MIMEMAP_END); | ||
| 49 | ExitOnFailure(hr, "Failed to write mimemap end id"); | ||
| 50 | |||
| 51 | LExit: | ||
| 52 | return hr; | ||
| 53 | } | ||
| 54 | |||
| 55 | |||
| 56 | //static HRESULT AddMimeMapToList(SCA_MIMEMAP** ppsmmList) | ||
| 57 | //{ | ||
| 58 | // HRESULT hr = S_OK; | ||
| 59 | // | ||
| 60 | // SCA_MIMEMAP* psmm = static_cast<SCA_MIMEMAP*>(MemAlloc(sizeof(SCA_MIMEMAP), TRUE)); | ||
| 61 | // ExitOnNull(psmm, hr, E_OUTOFMEMORY, "failed to allocate memory for new mime map list element"); | ||
| 62 | // | ||
| 63 | // psmm->psmmNext = *ppsmmList; | ||
| 64 | // *ppsmmList = psmm; | ||
| 65 | // | ||
| 66 | //LExit: | ||
| 67 | // return hr; | ||
| 68 | //} | ||
diff --git a/src/ca/scamimemap7.h b/src/ca/scamimemap7.h new file mode 100644 index 00000000..88fcdc39 --- /dev/null +++ b/src/ca/scamimemap7.h | |||
| @@ -0,0 +1,10 @@ | |||
| 1 | #pragma once | ||
| 2 | // 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. | ||
| 3 | |||
| 4 | |||
| 5 | HRESULT ScaWriteMimeMap7( | ||
| 6 | __in_z LPCWSTR wzWebName, | ||
| 7 | __in_z LPCWSTR wzRootOfWeb, | ||
| 8 | SCA_MIMEMAP* psmmList | ||
| 9 | ); | ||
| 10 | |||
diff --git a/src/ca/scaproperty.cpp b/src/ca/scaproperty.cpp new file mode 100644 index 00000000..d0e0d8a4 --- /dev/null +++ b/src/ca/scaproperty.cpp | |||
| @@ -0,0 +1,252 @@ | |||
| 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 | #include "precomp.h" | ||
| 4 | |||
| 5 | /*------------------------------------------------------------------ | ||
| 6 | IIsProperty table: | ||
| 7 | |||
| 8 | Property Component_ Attributes Value | ||
| 9 | s72 s72 i4 s255 | ||
| 10 | ------------------------------------------------------------------*/ | ||
| 11 | |||
| 12 | // sql queries | ||
| 13 | enum ePropertyQuery { pqProperty = 1, pqComponent, pqAttributes, pqValue, pqInstalled, pqAction }; | ||
| 14 | |||
| 15 | |||
| 16 | // prototypes | ||
| 17 | static HRESULT AddPropertyToList( | ||
| 18 | SCA_PROPERTY** ppspList | ||
| 19 | ); | ||
| 20 | |||
| 21 | |||
| 22 | // functions | ||
| 23 | void ScaPropertyFreeList( | ||
| 24 | SCA_PROPERTY* pspList | ||
| 25 | ) | ||
| 26 | { | ||
| 27 | SCA_PROPERTY* pspDelete = pspList; | ||
| 28 | while (pspList) | ||
| 29 | { | ||
| 30 | pspDelete = pspList; | ||
| 31 | pspList = pspList->pspNext; | ||
| 32 | |||
| 33 | MemFree(pspDelete); | ||
| 34 | } | ||
| 35 | } | ||
| 36 | |||
| 37 | |||
| 38 | HRESULT ScaPropertyRead( | ||
| 39 | SCA_PROPERTY** ppspList, | ||
| 40 | __inout LPWSTR *ppwzCustomActionData | ||
| 41 | ) | ||
| 42 | { | ||
| 43 | HRESULT hr = S_OK; | ||
| 44 | MSIHANDLE hRec; | ||
| 45 | |||
| 46 | LPWSTR pwzData = NULL; | ||
| 47 | SCA_PROPERTY* pss; | ||
| 48 | |||
| 49 | WCA_WRAPQUERY_HANDLE hWrapQuery = NULL; | ||
| 50 | |||
| 51 | ExitOnNull(ppspList, hr, E_INVALIDARG, "Failed to read property, because no property to read was provided"); | ||
| 52 | |||
| 53 | hr = WcaBeginUnwrapQuery(&hWrapQuery, ppwzCustomActionData); | ||
| 54 | ExitOnFailure(hr, "Failed to unwrap query for ScaAppPoolRead"); | ||
| 55 | |||
| 56 | if (0 == WcaGetQueryRecords(hWrapQuery)) | ||
| 57 | { | ||
| 58 | WcaLog(LOGMSG_VERBOSE, "Skipping ScaInstallProperty() - required table not present"); | ||
| 59 | ExitFunction1(hr = S_FALSE); | ||
| 60 | } | ||
| 61 | |||
| 62 | // loop through all the Settings | ||
| 63 | while (S_OK == (hr = WcaFetchWrappedRecord(hWrapQuery, &hRec))) | ||
| 64 | { | ||
| 65 | hr = AddPropertyToList(ppspList); | ||
| 66 | ExitOnFailure(hr, "failed to add property to list"); | ||
| 67 | |||
| 68 | pss = *ppspList; | ||
| 69 | |||
| 70 | hr = WcaGetRecordString(hRec, pqProperty, &pwzData); | ||
| 71 | ExitOnFailure(hr, "failed to get IIsProperty.Property"); | ||
| 72 | hr = ::StringCchCopyW(pss->wzProperty, countof(pss->wzProperty), pwzData); | ||
| 73 | ExitOnFailure(hr, "failed to copy Property name: %ls", pwzData); | ||
| 74 | |||
| 75 | hr = WcaGetRecordString(hRec, pqValue, &pwzData); | ||
| 76 | ExitOnFailure(hr, "failed to get IIsProperty.Value"); | ||
| 77 | hr = ::StringCchCopyW(pss->wzValue, countof(pss->wzValue), pwzData); | ||
| 78 | ExitOnFailure(hr, "failed to copy Property value: %ls", pwzData); | ||
| 79 | |||
| 80 | hr = WcaGetRecordInteger(hRec, pqAttributes, &pss->iAttributes); | ||
| 81 | ExitOnFailure(hr, "failed to get IIsProperty.Attributes"); | ||
| 82 | |||
| 83 | hr = WcaGetRecordString(hRec, pqComponent, &pwzData); | ||
| 84 | ExitOnFailure(hr, "failed to get IIsProperty.Component"); | ||
| 85 | hr = ::StringCchCopyW(pss->wzComponent, countof(pss->wzComponent), pwzData); | ||
| 86 | ExitOnFailure(hr, "failed to copy component name: %ls", pwzData); | ||
| 87 | |||
| 88 | hr = WcaGetRecordInteger(hRec, pqInstalled, (int *)&pss->isInstalled); | ||
| 89 | ExitOnFailure(hr, "Failed to get Component installed state for filter"); | ||
| 90 | |||
| 91 | hr = WcaGetRecordInteger(hRec, pqAction, (int *)&pss->isAction); | ||
| 92 | ExitOnFailure(hr, "Failed to get Component action state for filter"); | ||
| 93 | } | ||
| 94 | |||
| 95 | if (E_NOMOREITEMS == hr) | ||
| 96 | { | ||
| 97 | hr = S_OK; | ||
| 98 | } | ||
| 99 | ExitOnFailure(hr, "failure while processing IIsProperty table"); | ||
| 100 | |||
| 101 | LExit: | ||
| 102 | WcaFinishUnwrapQuery(hWrapQuery); | ||
| 103 | |||
| 104 | ReleaseStr(pwzData); | ||
| 105 | |||
| 106 | return hr; | ||
| 107 | } | ||
| 108 | |||
| 109 | |||
| 110 | HRESULT ScaPropertyInstall( | ||
| 111 | IMSAdminBase* piMetabase, | ||
| 112 | SCA_PROPERTY* pspList | ||
| 113 | ) | ||
| 114 | { | ||
| 115 | Assert(piMetabase); | ||
| 116 | |||
| 117 | HRESULT hr = S_OK; | ||
| 118 | |||
| 119 | for (SCA_PROPERTY* psp = pspList; psp; psp = psp->pspNext) | ||
| 120 | { | ||
| 121 | // if we are installing the web site | ||
| 122 | if (WcaIsInstalling(psp->isInstalled, psp->isAction)) | ||
| 123 | { | ||
| 124 | hr = ScaWriteProperty(piMetabase, psp); | ||
| 125 | ExitOnFailure(hr, "failed to write Property '%ls' to metabase", psp->wzProperty); | ||
| 126 | } | ||
| 127 | } | ||
| 128 | |||
| 129 | LExit: | ||
| 130 | return hr; | ||
| 131 | } | ||
| 132 | |||
| 133 | |||
| 134 | HRESULT ScaPropertyUninstall( | ||
| 135 | IMSAdminBase* piMetabase, | ||
| 136 | SCA_PROPERTY* pspList | ||
| 137 | ) | ||
| 138 | { | ||
| 139 | Assert(piMetabase); | ||
| 140 | |||
| 141 | HRESULT hr = S_OK; | ||
| 142 | |||
| 143 | for (SCA_PROPERTY* psp = pspList; psp; psp = psp->pspNext) | ||
| 144 | { | ||
| 145 | // if we are uninstalling the web site | ||
| 146 | if (WcaIsUninstalling(psp->isInstalled, psp->isAction)) | ||
| 147 | { | ||
| 148 | hr = ScaRemoveProperty(piMetabase, psp); | ||
| 149 | ExitOnFailure(hr, "Failed to remove Property '%ls' from metabase", psp->wzProperty); | ||
| 150 | } | ||
| 151 | } | ||
| 152 | |||
| 153 | LExit: | ||
| 154 | return hr; | ||
| 155 | } | ||
| 156 | |||
| 157 | |||
| 158 | HRESULT ScaWriteProperty( | ||
| 159 | IMSAdminBase* piMetabase, | ||
| 160 | SCA_PROPERTY* psp | ||
| 161 | ) | ||
| 162 | { | ||
| 163 | Assert(piMetabase); | ||
| 164 | |||
| 165 | HRESULT hr = S_OK; | ||
| 166 | DWORD dwValue; | ||
| 167 | LPWSTR wz = NULL; | ||
| 168 | |||
| 169 | ExitOnNull(psp, hr, E_INVALIDARG, "Failed to write property because no property to write was given"); | ||
| 170 | |||
| 171 | // | ||
| 172 | // Figure out what setting we're writing and write it | ||
| 173 | // | ||
| 174 | if (0 == lstrcmpW(psp->wzProperty, wzIISPROPERTY_IIS5_ISOLATION_MODE)) | ||
| 175 | { | ||
| 176 | dwValue = 1; | ||
| 177 | hr = ScaWriteMetabaseValue(piMetabase, L"/LM/W3SVC", NULL, MD_GLOBAL_STANDARD_APP_MODE_ENABLED, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, (LPVOID)((DWORD_PTR)dwValue)); | ||
| 178 | ExitOnFailure(hr, "failed to set IIs5IsolationMode"); | ||
| 179 | } | ||
| 180 | else if (0 == lstrcmpW(psp->wzProperty, wzIISPROPERTY_MAX_GLOBAL_BANDWIDTH)) | ||
| 181 | { | ||
| 182 | dwValue = wcstoul(psp->wzValue, &wz, 10) * 1024; // remember, the value shown is in kilobytes, the value saved is in bytes | ||
| 183 | hr = ScaWriteMetabaseValue(piMetabase, L"/LM/W3SVC", NULL, MD_MAX_GLOBAL_BANDWIDTH, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, (LPVOID)((DWORD_PTR)dwValue)); | ||
| 184 | ExitOnFailure(hr, "failed to set MaxGlobalBandwidth"); | ||
| 185 | } | ||
| 186 | else if (0 == lstrcmpW(psp->wzProperty, wzIISPROPERTY_LOG_IN_UTF8)) | ||
| 187 | { | ||
| 188 | dwValue = 1; | ||
| 189 | hr = ScaWriteMetabaseValue(piMetabase, L"/LM/W3SVC", NULL, MD_GLOBAL_LOG_IN_UTF_8, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, (LPVOID)((DWORD_PTR)dwValue)); | ||
| 190 | ExitOnFailure(hr, "failed to set LogInUTF8"); | ||
| 191 | } | ||
| 192 | else if (0 == lstrcmpW(psp->wzProperty, wzIISPROPERTY_ETAG_CHANGENUMBER)) | ||
| 193 | { | ||
| 194 | dwValue = wcstoul(psp->wzValue, &wz, 10); | ||
| 195 | hr = ScaWriteMetabaseValue(piMetabase, L"/LM/W3SVC", NULL, /*MD_ETAG_CHANGENUMBER*/ 2039, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, (LPVOID)((DWORD_PTR)dwValue)); | ||
| 196 | ExitOnFailure(hr, "failed to set EtagChangenumber"); | ||
| 197 | } | ||
| 198 | LExit: | ||
| 199 | return hr; | ||
| 200 | } | ||
| 201 | |||
| 202 | |||
| 203 | HRESULT ScaRemoveProperty( | ||
| 204 | IMSAdminBase* piMetabase, | ||
| 205 | SCA_PROPERTY* psp | ||
| 206 | ) | ||
| 207 | { | ||
| 208 | Assert(piMetabase); | ||
| 209 | |||
| 210 | HRESULT hr = S_OK; | ||
| 211 | DWORD dwValue; | ||
| 212 | |||
| 213 | ExitOnNull(psp, hr, E_INVALIDARG, "Failed to remove property because no property to remove was given"); | ||
| 214 | |||
| 215 | if (0 == lstrcmpW(psp->wzProperty, wzIISPROPERTY_IIS5_ISOLATION_MODE)) | ||
| 216 | { | ||
| 217 | dwValue = 0; | ||
| 218 | hr = ScaWriteMetabaseValue(piMetabase, L"/LM/W3SVC", NULL, MD_GLOBAL_STANDARD_APP_MODE_ENABLED, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, (LPVOID)((DWORD_PTR)dwValue)); | ||
| 219 | ExitOnFailure(hr, "failed to clear IIs5IsolationMode"); | ||
| 220 | } | ||
| 221 | else if (0 == lstrcmpW(psp->wzProperty, wzIISPROPERTY_MAX_GLOBAL_BANDWIDTH)) | ||
| 222 | { | ||
| 223 | dwValue = 0xFFFFFFFF; // This unchecks the box | ||
| 224 | hr = ScaWriteMetabaseValue(piMetabase, L"/LM/W3SVC", NULL, MD_MAX_GLOBAL_BANDWIDTH, METADATA_NO_ATTRIBUTES , IIS_MD_UT_SERVER, DWORD_METADATA, (LPVOID)((DWORD_PTR)dwValue)); | ||
| 225 | ExitOnFailure(hr, "failed to clear MaxGlobalBandwidth"); | ||
| 226 | } | ||
| 227 | else if (0 == lstrcmpW(psp->wzProperty, wzIISPROPERTY_LOG_IN_UTF8)) | ||
| 228 | { | ||
| 229 | dwValue = 0; | ||
| 230 | hr = ScaWriteMetabaseValue(piMetabase, L"/LM/W3SVC", NULL, MD_GLOBAL_LOG_IN_UTF_8, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, (LPVOID)((DWORD_PTR)dwValue)); | ||
| 231 | ExitOnFailure(hr, "failed to clear LogInUTF8"); | ||
| 232 | } | ||
| 233 | |||
| 234 | LExit: | ||
| 235 | return hr; | ||
| 236 | } | ||
| 237 | |||
| 238 | |||
| 239 | static HRESULT AddPropertyToList( | ||
| 240 | SCA_PROPERTY** ppspList | ||
| 241 | ) | ||
| 242 | { | ||
| 243 | HRESULT hr = S_OK; | ||
| 244 | SCA_PROPERTY* psp = static_cast<SCA_PROPERTY*>(MemAlloc(sizeof(SCA_PROPERTY), TRUE)); | ||
| 245 | ExitOnNull(psp, hr, E_OUTOFMEMORY, "failed to allocate memory for new property list element"); | ||
| 246 | |||
| 247 | psp->pspNext = *ppspList; | ||
| 248 | *ppspList = psp; | ||
| 249 | |||
| 250 | LExit: | ||
| 251 | return hr; | ||
| 252 | } | ||
diff --git a/src/ca/scaproperty.h b/src/ca/scaproperty.h new file mode 100644 index 00000000..21e7cfc7 --- /dev/null +++ b/src/ca/scaproperty.h | |||
| @@ -0,0 +1,54 @@ | |||
| 1 | #pragma once | ||
| 2 | // 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. | ||
| 3 | |||
| 4 | |||
| 5 | #define wzIISPROPERTY_IIS5_ISOLATION_MODE L"IIs5IsolationMode" | ||
| 6 | #define wzIISPROPERTY_MAX_GLOBAL_BANDWIDTH L"MaxGlobalBandwidth" | ||
| 7 | #define wzIISPROPERTY_LOG_IN_UTF8 L"LogInUTF8" | ||
| 8 | #define wzIISPROPERTY_ETAG_CHANGENUMBER L"ETagChangeNumber" | ||
| 9 | |||
| 10 | struct SCA_PROPERTY | ||
| 11 | { | ||
| 12 | // iis configuation information | ||
| 13 | WCHAR wzProperty[MAX_DARWIN_KEY + 1]; | ||
| 14 | WCHAR wzComponent[MAX_DARWIN_KEY + 1]; | ||
| 15 | INSTALLSTATE isInstalled; | ||
| 16 | INSTALLSTATE isAction; | ||
| 17 | INT iAttributes; | ||
| 18 | WCHAR wzValue[MAX_DARWIN_COLUMN + 1]; | ||
| 19 | |||
| 20 | SCA_PROPERTY *pspNext; | ||
| 21 | }; | ||
| 22 | |||
| 23 | |||
| 24 | // prototypes | ||
| 25 | |||
| 26 | HRESULT ScaPropertyRead( | ||
| 27 | SCA_PROPERTY** ppspList, | ||
| 28 | __inout LPWSTR *ppwzCustomActionData | ||
| 29 | ); | ||
| 30 | |||
| 31 | void ScaPropertyFreeList( | ||
| 32 | SCA_PROPERTY* pspList | ||
| 33 | ); | ||
| 34 | |||
| 35 | HRESULT ScaPropertyInstall( | ||
| 36 | IMSAdminBase* piMetabase, | ||
| 37 | SCA_PROPERTY* pspList | ||
| 38 | ); | ||
| 39 | |||
| 40 | HRESULT ScaPropertyUninstall( | ||
| 41 | IMSAdminBase* piMetabase, | ||
| 42 | SCA_PROPERTY* pspList | ||
| 43 | ); | ||
| 44 | |||
| 45 | HRESULT ScaWriteProperty( | ||
| 46 | IMSAdminBase* piMetabase, | ||
| 47 | SCA_PROPERTY* psp | ||
| 48 | ); | ||
| 49 | |||
| 50 | HRESULT ScaRemoveProperty( | ||
| 51 | IMSAdminBase* piMetabase, | ||
| 52 | SCA_PROPERTY* psp | ||
| 53 | ); | ||
| 54 | |||
diff --git a/src/ca/scaproperty7.cpp b/src/ca/scaproperty7.cpp new file mode 100644 index 00000000..d17eeb68 --- /dev/null +++ b/src/ca/scaproperty7.cpp | |||
| @@ -0,0 +1,108 @@ | |||
| 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 | #include "precomp.h" | ||
| 4 | |||
| 5 | HRESULT ScaPropertyInstall7( | ||
| 6 | SCA_PROPERTY* pspList | ||
| 7 | ) | ||
| 8 | { | ||
| 9 | HRESULT hr = S_OK; | ||
| 10 | |||
| 11 | for (SCA_PROPERTY* psp = pspList; psp; psp = psp->pspNext) | ||
| 12 | { | ||
| 13 | // if we are installing the web site | ||
| 14 | if (WcaIsInstalling(psp->isInstalled, psp->isAction)) | ||
| 15 | { | ||
| 16 | hr = ScaWriteProperty7(psp); | ||
| 17 | ExitOnFailure(hr, "failed to write Property '%ls' ", psp->wzProperty); | ||
| 18 | } | ||
| 19 | } | ||
| 20 | |||
| 21 | LExit: | ||
| 22 | return hr; | ||
| 23 | } | ||
| 24 | |||
| 25 | |||
| 26 | HRESULT ScaPropertyUninstall7( | ||
| 27 | SCA_PROPERTY* pspList | ||
| 28 | ) | ||
| 29 | { | ||
| 30 | HRESULT hr = S_OK; | ||
| 31 | |||
| 32 | for (SCA_PROPERTY* psp = pspList; psp; psp = psp->pspNext) | ||
| 33 | { | ||
| 34 | // if we are uninstalling the web site | ||
| 35 | if (WcaIsUninstalling(psp->isInstalled, psp->isAction)) | ||
| 36 | { | ||
| 37 | hr = ScaRemoveProperty7(psp); | ||
| 38 | ExitOnFailure(hr, "Failed to remove Property '%ls'", psp->wzProperty); | ||
| 39 | } | ||
| 40 | } | ||
| 41 | |||
| 42 | LExit: | ||
| 43 | return hr; | ||
| 44 | } | ||
| 45 | |||
| 46 | |||
| 47 | HRESULT ScaWriteProperty7( | ||
| 48 | const SCA_PROPERTY* psp | ||
| 49 | ) | ||
| 50 | { | ||
| 51 | HRESULT hr = S_OK; | ||
| 52 | DWORD dwValue; | ||
| 53 | LPWSTR wz = NULL; | ||
| 54 | |||
| 55 | ExitOnNull(psp, hr, E_INVALIDARG, "Failed to write property because no property to write was given"); | ||
| 56 | // | ||
| 57 | // Figure out what setting we're writing and write it | ||
| 58 | // | ||
| 59 | if (0 == wcscmp(psp->wzProperty, wzIISPROPERTY_IIS5_ISOLATION_MODE)) | ||
| 60 | { | ||
| 61 | // IIs5IsolationMode not supported | ||
| 62 | WcaLog(LOGMSG_VERBOSE, "Not supported by IIS7: IIs5IsolationMode, ignoring"); | ||
| 63 | } | ||
| 64 | else if (0 == wcscmp(psp->wzProperty, wzIISPROPERTY_MAX_GLOBAL_BANDWIDTH)) | ||
| 65 | { | ||
| 66 | dwValue = wcstoul(psp->wzValue, &wz, 10) * 1024; // remember, the value shown is in kilobytes, the value saved is in bytes | ||
| 67 | hr = ScaWriteConfigID(IIS_PROPERTY); | ||
| 68 | ExitOnFailure(hr, "failed to set Property ID"); | ||
| 69 | hr = ScaWriteConfigID(IIS_PROPERTY_MAXBAND); | ||
| 70 | ExitOnFailure(hr, "failed to set Property MSXBAND ID"); | ||
| 71 | hr = ScaWriteConfigInteger(dwValue); | ||
| 72 | ExitOnFailure(hr, "failed to set Property MSXBAND value"); | ||
| 73 | } | ||
| 74 | else if (0 == wcscmp(psp->wzProperty, wzIISPROPERTY_LOG_IN_UTF8)) | ||
| 75 | { | ||
| 76 | dwValue = 1; | ||
| 77 | hr = ScaWriteConfigID(IIS_PROPERTY); | ||
| 78 | ExitOnFailure(hr, "failed to set Property ID"); | ||
| 79 | hr = ScaWriteConfigID(IIS_PROPERTY_LOGUTF8); | ||
| 80 | ExitOnFailure(hr, "failed to set Property LOG ID"); | ||
| 81 | hr = ScaWriteConfigInteger(dwValue); | ||
| 82 | ExitOnFailure(hr, "failed to set Property Log value"); | ||
| 83 | } | ||
| 84 | else if (0 == wcscmp(psp->wzProperty, wzIISPROPERTY_ETAG_CHANGENUMBER)) | ||
| 85 | { | ||
| 86 | //EtagChangenumber not supported | ||
| 87 | WcaLog(LOGMSG_VERBOSE, "Not supported by IIS7: EtagChangenumber, ignoring"); | ||
| 88 | } | ||
| 89 | |||
| 90 | LExit: | ||
| 91 | return hr; | ||
| 92 | } | ||
| 93 | |||
| 94 | HRESULT ScaRemoveProperty7( | ||
| 95 | __in SCA_PROPERTY* /*psp*/ | ||
| 96 | ) | ||
| 97 | { | ||
| 98 | |||
| 99 | // NOP function for now | ||
| 100 | //The two global values being set by WebProperty: | ||
| 101 | // <iis:WebProperty Id="MaxGlobalBandwidth" Value="1024" /> | ||
| 102 | // <iis:WebProperty Id ="LogInUTF8" /> | ||
| 103 | // should should not be removed on uninstall. | ||
| 104 | |||
| 105 | HRESULT hr = S_OK; | ||
| 106 | |||
| 107 | return hr; | ||
| 108 | } | ||
diff --git a/src/ca/scaproperty7.h b/src/ca/scaproperty7.h new file mode 100644 index 00000000..bbf811e8 --- /dev/null +++ b/src/ca/scaproperty7.h | |||
| @@ -0,0 +1,26 @@ | |||
| 1 | #pragma once | ||
| 2 | // 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. | ||
| 3 | |||
| 4 | |||
| 5 | #define wzIISPROPERTY_IIS5_ISOLATION_MODE L"IIs5IsolationMode" | ||
| 6 | #define wzIISPROPERTY_MAX_GLOBAL_BANDWIDTH L"MaxGlobalBandwidth" | ||
| 7 | #define wzIISPROPERTY_LOG_IN_UTF8 L"LogInUTF8" | ||
| 8 | #define wzIISPROPERTY_ETAG_CHANGENUMBER L"ETagChangeNumber" | ||
| 9 | |||
| 10 | // prototypes | ||
| 11 | HRESULT ScaPropertyInstall7( | ||
| 12 | SCA_PROPERTY* pspList | ||
| 13 | ); | ||
| 14 | |||
| 15 | HRESULT ScaPropertyUninstall7( | ||
| 16 | SCA_PROPERTY* pspList | ||
| 17 | ); | ||
| 18 | |||
| 19 | HRESULT ScaWriteProperty7( | ||
| 20 | const SCA_PROPERTY* psp | ||
| 21 | ); | ||
| 22 | |||
| 23 | HRESULT ScaRemoveProperty7( | ||
| 24 | SCA_PROPERTY* psp | ||
| 25 | ); | ||
| 26 | |||
diff --git a/src/ca/scasched.cpp b/src/ca/scasched.cpp new file mode 100644 index 00000000..cdece45d --- /dev/null +++ b/src/ca/scasched.cpp | |||
| @@ -0,0 +1,823 @@ | |||
| 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 | #include "precomp.h" | ||
| 4 | |||
| 5 | const int ConfigureIIsCost = 8; | ||
| 6 | const int WriteMetabaseChangesCost = 20; | ||
| 7 | const int WriteIIS7ConfigChangesCost = 20; | ||
| 8 | |||
| 9 | // sql queries | ||
| 10 | LPCWSTR vcsUserDeferredQuery = L"SELECT `User`, `Component_`, `Name`, `Domain`, `Password` FROM `User`"; | ||
| 11 | |||
| 12 | LPCWSTR vcsWebSvcExtQuery = L"SELECT `Component_`, `File`, `Description`, `Group`, `Attributes` FROM `IIsWebServiceExtension`"; | ||
| 13 | |||
| 14 | LPCWSTR vcsAppPoolQuery = L"SELECT `AppPool`, `Name`, `Component_`, `Attributes`, `User_`, `RecycleMinutes`, `RecycleRequests`, `RecycleTimes`, `VirtualMemory`, `PrivateMemory`, `IdleTimeout`, `QueueLimit`, `CPUMon`, `MaxProc`, `ManagedRuntimeVersion`, `ManagedPipelineMode` FROM `IIsAppPool`"; | ||
| 15 | |||
| 16 | LPCWSTR vcsComponentAttrQuery = L"SELECT `Component`,`Attributes` FROM `Component`"; | ||
| 17 | |||
| 18 | LPCWSTR vcsMimeMapQuery = L"SELECT `MimeMap`, `ParentType`, `ParentValue`, `MimeType`, `Extension` FROM `IIsMimeMap`"; | ||
| 19 | |||
| 20 | LPCWSTR vcsHttpHeaderQuery = L"SELECT `Name`, `ParentType`, `ParentValue`, `Value`, `Attributes` FROM `IIsHttpHeader` ORDER BY `Sequence`"; | ||
| 21 | |||
| 22 | LPCWSTR vcsWebErrorQuery = | ||
| 23 | L"SELECT `ErrorCode`, `SubCode`, `ParentType`, `ParentValue`, `File`, `URL` " | ||
| 24 | L"FROM `IIsWebError` ORDER BY `ErrorCode`, `SubCode`"; | ||
| 25 | |||
| 26 | LPCWSTR vcsWebDirPropertiesQuery = L"SELECT `DirProperties`, `Access`, `Authorization`, `AnonymousUser_`, `IIsControlledPassword`, `LogVisits`, `Index`, `DefaultDoc`, `AspDetailedError`, `HttpExpires`, `CacheControlMaxAge`, `CacheControlCustom`, `NoCustomError`, `AccessSSLFlags`, `AuthenticationProviders` " | ||
| 27 | L"FROM `IIsWebDirProperties`"; | ||
| 28 | |||
| 29 | LPCWSTR vcsSslCertificateQuery = L"SELECT `Certificate`.`StoreName`, `CertificateHash`.`Hash`, `IIsWebSiteCertificates`.`Web_` FROM `Certificate`, `CertificateHash`, `IIsWebSiteCertificates` WHERE `Certificate`.`Certificate`=`CertificateHash`.`Certificate_` AND `CertificateHash`.`Certificate_`=`IIsWebSiteCertificates`.`Certificate_`"; | ||
| 30 | |||
| 31 | LPCWSTR vcsWebLogQuery = L"SELECT `Log`, `Format` " | ||
| 32 | L"FROM `IIsWebLog`"; | ||
| 33 | |||
| 34 | LPCWSTR vcsWebApplicationQuery = L"SELECT `Name`, `Isolation`, `AllowSessions`, `SessionTimeout`, " | ||
| 35 | L"`Buffer`, `ParentPaths`, `DefaultScript`, `ScriptTimeout`, " | ||
| 36 | L"`ServerDebugging`, `ClientDebugging`, `AppPool_`, `Application` " | ||
| 37 | L"FROM `IIsWebApplication`"; | ||
| 38 | |||
| 39 | LPCWSTR vcsWebAppExtensionQuery = L"SELECT `Extension`, `Verbs`, `Executable`, `Attributes`, `Application_` FROM `IIsWebApplicationExtension`"; | ||
| 40 | |||
| 41 | LPCWSTR vcsWebQuery = L"SELECT `Web`, `Component_`, `Id`, `Description`, `ConnectionTimeout`, `Directory_`, `State`, `Attributes`, `DirProperties_`, `Application_`, " | ||
| 42 | L"`Address`, `IP`, `Port`, `Header`, `Secure`, `Log_` FROM `IIsWebSite`, `IIsWebAddress` " | ||
| 43 | L"WHERE `KeyAddress_`=`Address` ORDER BY `Sequence`"; | ||
| 44 | |||
| 45 | LPCWSTR vcsWebAddressQuery = L"SELECT `Address`, `Web_`, `IP`, `Port`, `Header`, `Secure` " | ||
| 46 | L"FROM `IIsWebAddress`"; | ||
| 47 | |||
| 48 | LPCWSTR vcsWebBaseQuery = L"SELECT `Web`, `Id`, `IP`, `Port`, `Header`, `Secure`, `Description` " | ||
| 49 | L"FROM `IIsWebSite`, `IIsWebAddress` " | ||
| 50 | L"WHERE `KeyAddress_`=`Address`"; | ||
| 51 | |||
| 52 | LPCWSTR vcsWebDirQuery = L"SELECT `Web_`, `WebDir`, `Component_`, `Path`, `DirProperties_`, `Application_` " | ||
| 53 | L"FROM `IIsWebDir`"; | ||
| 54 | |||
| 55 | LPCWSTR vcsVDirQuery = L"SELECT `Web_`, `VirtualDir`, `Component_`, `Alias`, `Directory_`, `DirProperties_`, `Application_` " | ||
| 56 | L"FROM `IIsWebVirtualDir`"; | ||
| 57 | |||
| 58 | LPCWSTR vcsFilterQuery = L"SELECT `Web_`, `Name`, `Component_`, `Path`, `Description`, `Flags`, `LoadOrder` FROM `IIsFilter` ORDER BY `Web_`"; | ||
| 59 | |||
| 60 | LPCWSTR vcsPropertyQuery = L"SELECT `Property`, `Component_`, `Attributes`, `Value` " | ||
| 61 | L"FROM `IIsProperty`"; | ||
| 62 | |||
| 63 | #define IIS7CONDITION L"VersionNT >= 600" | ||
| 64 | #define USEIIS7CONDITION IIS7CONDITION L"AND NOT UseIis6Compatibility" | ||
| 65 | |||
| 66 | /******************************************************************** | ||
| 67 | ConfigureIIs - CUSTOM ACTION ENTRY POINT for installing IIs settings | ||
| 68 | |||
| 69 | ********************************************************************/ | ||
| 70 | extern "C" UINT __stdcall ConfigureIIs( | ||
| 71 | __in MSIHANDLE hInstall | ||
| 72 | ) | ||
| 73 | { | ||
| 74 | //AssertSz(FALSE, "debug ConfigureIIs here"); | ||
| 75 | HRESULT hr = S_OK; | ||
| 76 | UINT er = ERROR_SUCCESS; | ||
| 77 | LPWSTR pwzScriptKey = NULL; | ||
| 78 | LPWSTR pwzBackupId = NULL; | ||
| 79 | LPWSTR pwzCustomActionData = NULL; // CustomActionData for ConfigureIIs custom action | ||
| 80 | |||
| 81 | // initialize | ||
| 82 | hr = WcaInitialize(hInstall, "ConfigureIIs"); | ||
| 83 | ExitOnFailure(hr, "Failed to initialize"); | ||
| 84 | |||
| 85 | // check for the prerequsite tables | ||
| 86 | if (S_OK != WcaTableExists(L"IIsWebSite") && S_OK != WcaTableExists(L"IIsFilter") && S_OK != WcaTableExists(L"IIsProperty") && | ||
| 87 | S_OK != WcaTableExists(L"IIsWebServiceExtension") && S_OK != WcaTableExists(L"IIsAppPool")) | ||
| 88 | { | ||
| 89 | WcaLog(LOGMSG_VERBOSE, "skipping IIs CustomAction, no IIsWebSite table, no IIsFilter table, no IIsProperty table, no IIsWebServiceExtension, and no IIsAppPool table"); | ||
| 90 | ExitFunction1(hr = S_FALSE); | ||
| 91 | } | ||
| 92 | |||
| 93 | // Get a CaScript key | ||
| 94 | hr = WcaCaScriptCreateKey(&pwzScriptKey); | ||
| 95 | ExitOnFailure(hr, "Failed to get encoding key."); | ||
| 96 | |||
| 97 | // Generate a unique string to be used for this product's transaction | ||
| 98 | // This prevents a name collision when doing a major upgrade | ||
| 99 | hr = WcaGetProperty(L"ProductCode", &pwzBackupId); | ||
| 100 | ExitOnFailure(hr, "failed to get ProductCode"); | ||
| 101 | |||
| 102 | hr = StrAllocConcat(&pwzBackupId, L"ScaConfigureIIs", 0); | ||
| 103 | ExitOnFailure(hr, "failed to concat ScaConfigureIIs"); | ||
| 104 | |||
| 105 | // make sure the operations below are wrapped in a "transaction" | ||
| 106 | // use IIS7 transaction logic even if using Iis6 compat because Backup/Restore don't work with metabase compatibility | ||
| 107 | if (MSICONDITION_TRUE == ::MsiEvaluateConditionW(hInstall, IIS7CONDITION)) | ||
| 108 | { | ||
| 109 | hr = ScaIIS7ConfigTransaction(pwzBackupId); | ||
| 110 | MessageExitOnFailure(hr, msierrIISFailedSchedTransaction, "failed to start IIS7 transaction"); | ||
| 111 | } | ||
| 112 | else | ||
| 113 | { | ||
| 114 | hr = ScaMetabaseTransaction(pwzBackupId); | ||
| 115 | MessageExitOnFailure(hr, msierrIISFailedSchedTransaction, "failed to start IIS transaction"); | ||
| 116 | } | ||
| 117 | |||
| 118 | // Write the CaScript key to the ConfigureIIS custom action data | ||
| 119 | hr = WcaWriteStringToCaData(pwzScriptKey, &pwzCustomActionData); | ||
| 120 | ExitOnFailure(hr, "Failed to add encoding key to CustomActionData."); | ||
| 121 | |||
| 122 | // Wrap vcsUserDeferredQuery to send to deferred CA | ||
| 123 | if (S_OK == WcaTableExists(L"User")) | ||
| 124 | { | ||
| 125 | hr = WcaWrapQuery(vcsUserDeferredQuery, &pwzCustomActionData, efmcColumn3 | efmcColumn4 | efmcColumn5, 0xFFFFFFFF, 0xFFFFFFFF); | ||
| 126 | ExitOnFailure(hr, "Failed to wrap User query"); | ||
| 127 | } | ||
| 128 | else | ||
| 129 | { | ||
| 130 | hr = WcaWrapEmptyQuery(&pwzCustomActionData); | ||
| 131 | ExitOnFailure(hr, "Failed to wrap User empty query"); | ||
| 132 | } | ||
| 133 | |||
| 134 | // Wrap vcsWebSvcExtQuery to send to deferred CA | ||
| 135 | if (S_OK == WcaTableExists(L"IIsWebServiceExtension")) | ||
| 136 | { | ||
| 137 | hr = WcaWrapQuery(vcsWebSvcExtQuery, &pwzCustomActionData, efmcColumn2 | efmcColumn3 | efmcColumn4, 1, 0xFFFFFFFF); | ||
| 138 | ExitOnFailure(hr, "Failed to wrap IIsWebServiceExtension query"); | ||
| 139 | } | ||
| 140 | else | ||
| 141 | { | ||
| 142 | hr = WcaWrapEmptyQuery(&pwzCustomActionData); | ||
| 143 | ExitOnFailure(hr, "Failed to wrap IIsWebServiceExtension empty query"); | ||
| 144 | } | ||
| 145 | |||
| 146 | // Wrap vcsAppPoolQuery to send to deferred CA | ||
| 147 | if (S_OK == WcaTableExists(L"IIsAppPool")) | ||
| 148 | { | ||
| 149 | hr = WcaWrapQuery(vcsAppPoolQuery, &pwzCustomActionData, efmcColumn2 | efmcColumn15 | efmcColumn16, 3, 0xFFFFFFFF); | ||
| 150 | ExitOnFailure(hr, "Failed to wrap IIsAppPool query"); | ||
| 151 | |||
| 152 | hr = WcaWrapQuery(vcsComponentAttrQuery, &pwzCustomActionData, 0, 0xFFFFFFFF, 0xFFFFFFFF); | ||
| 153 | ExitOnFailure(hr, "Failed to wrap Component query"); | ||
| 154 | } | ||
| 155 | else | ||
| 156 | { | ||
| 157 | hr = WcaWrapEmptyQuery(&pwzCustomActionData); | ||
| 158 | ExitOnFailure(hr, "Failed to wrap IIsAppPool empty query"); | ||
| 159 | } | ||
| 160 | |||
| 161 | // Wrap vcsMimeMapQuery to send to deferred CA | ||
| 162 | if (S_OK == WcaTableExists(L"IIsMimeMap")) | ||
| 163 | { | ||
| 164 | hr = WcaWrapQuery(vcsMimeMapQuery, &pwzCustomActionData, efmcColumn4 | efmcColumn5, 0xFFFFFFFF, 0xFFFFFFFF); | ||
| 165 | ExitOnFailure(hr, "Failed to wrap IIsMimeMap query"); | ||
| 166 | } | ||
| 167 | else | ||
| 168 | { | ||
| 169 | hr = WcaWrapEmptyQuery(&pwzCustomActionData); | ||
| 170 | ExitOnFailure(hr, "Failed to wrap IIsMimeMap empty query"); | ||
| 171 | } | ||
| 172 | |||
| 173 | // Wrap vcsHttpHeaderQuery to send to deferred CA | ||
| 174 | if (S_OK == WcaTableExists(L"IIsHttpHeader")) | ||
| 175 | { | ||
| 176 | hr = WcaWrapQuery(vcsHttpHeaderQuery, &pwzCustomActionData, efmcColumn1 | efmcColumn4, 0xFFFFFFFF, 0xFFFFFFFF); | ||
| 177 | ExitOnFailure(hr, "Failed to wrap IIsHttpHeader query"); | ||
| 178 | } | ||
| 179 | else | ||
| 180 | { | ||
| 181 | hr = WcaWrapEmptyQuery(&pwzCustomActionData); | ||
| 182 | ExitOnFailure(hr, "Failed to wrap IIsHttpHeader empty query"); | ||
| 183 | } | ||
| 184 | |||
| 185 | // Wrap vcsWebErrorQuery to send to deferred CA | ||
| 186 | if (S_OK == WcaTableExists(L"IIsWebError")) | ||
| 187 | { | ||
| 188 | hr = WcaWrapQuery(vcsWebErrorQuery, &pwzCustomActionData, efmcColumn5 | efmcColumn6, 0xFFFFFFFF, 0xFFFFFFFF); | ||
| 189 | ExitOnFailure(hr, "Failed to wrap IIsWebError query"); | ||
| 190 | } | ||
| 191 | else | ||
| 192 | { | ||
| 193 | hr = WcaWrapEmptyQuery(&pwzCustomActionData); | ||
| 194 | ExitOnFailure(hr, "Failed to wrap IIsWebError empty query"); | ||
| 195 | } | ||
| 196 | |||
| 197 | // Wrap vcsWebDirPropertiesQuery to send to deferred CA | ||
| 198 | if (S_OK == WcaTableExists(L"IIsWebDirProperties")) | ||
| 199 | { | ||
| 200 | hr = WcaWrapQuery(vcsWebDirPropertiesQuery, &pwzCustomActionData, efmcColumn8 | efmcColumn10 | efmcColumn12 | efmcColumn15, 0xFFFFFFFF, 0xFFFFFFFF); | ||
| 201 | ExitOnFailure(hr, "Failed to wrap IIsWebDirProperties query"); | ||
| 202 | } | ||
| 203 | else | ||
| 204 | { | ||
| 205 | hr = WcaWrapEmptyQuery(&pwzCustomActionData); | ||
| 206 | ExitOnFailure(hr, "Failed to wrap IIsWebDirProperties empty query"); | ||
| 207 | } | ||
| 208 | |||
| 209 | // Wrap vcsSslCertificateQuery to send to deferred CA | ||
| 210 | if (S_OK == WcaTableExists(L"Certificate") && S_OK == WcaTableExists(L"CertificateHash") && S_OK == WcaTableExists(L"IIsWebSiteCertificates")) | ||
| 211 | { | ||
| 212 | hr = WcaWrapQuery(vcsSslCertificateQuery, &pwzCustomActionData, 0, 0xFFFFFFFF, 0xFFFFFFFF); | ||
| 213 | ExitOnFailure(hr, "Failed to wrap SslCertificate query"); | ||
| 214 | } | ||
| 215 | else | ||
| 216 | { | ||
| 217 | hr = WcaWrapEmptyQuery(&pwzCustomActionData); | ||
| 218 | ExitOnFailure(hr, "Failed to wrap SslCertificate empty query"); | ||
| 219 | } | ||
| 220 | |||
| 221 | // Wrap vcsWebLogQuery to send to deferred CA | ||
| 222 | if (S_OK == WcaTableExists(L"IIsWebLog")) | ||
| 223 | { | ||
| 224 | hr = WcaWrapQuery(vcsWebLogQuery, &pwzCustomActionData, efmcColumn2, 0xFFFFFFFF, 0xFFFFFFFF); | ||
| 225 | ExitOnFailure(hr, "Failed to wrap IIsWebLog query"); | ||
| 226 | } | ||
| 227 | else | ||
| 228 | { | ||
| 229 | hr = WcaWrapEmptyQuery(&pwzCustomActionData); | ||
| 230 | ExitOnFailure(hr, "Failed to wrap IIsWebLog empty query"); | ||
| 231 | } | ||
| 232 | |||
| 233 | // Wrap vcsWebApplicationQuery to send to deferred CA | ||
| 234 | if (S_OK == WcaTableExists(L"IIsWebApplication")) | ||
| 235 | { | ||
| 236 | hr = WcaWrapQuery(vcsWebApplicationQuery, &pwzCustomActionData, efmcColumn1, 0xFFFFFFFF, 0xFFFFFFFF); | ||
| 237 | ExitOnFailure(hr, "Failed to wrap IIsWebApplication query"); | ||
| 238 | } | ||
| 239 | else | ||
| 240 | { | ||
| 241 | hr = WcaWrapEmptyQuery(&pwzCustomActionData); | ||
| 242 | ExitOnFailure(hr, "Failed to wrap IIsWebApplication empty query"); | ||
| 243 | } | ||
| 244 | |||
| 245 | // Wrap vcsWebAppExtensionQuery to send to deferred CA | ||
| 246 | if (S_OK == WcaTableExists(L"IIsWebApplicationExtension")) | ||
| 247 | { | ||
| 248 | hr = WcaWrapQuery(vcsWebAppExtensionQuery, &pwzCustomActionData, efmcColumn2 | efmcColumn3, 0xFFFFFFFF, 0xFFFFFFFF); | ||
| 249 | ExitOnFailure(hr, "Failed to wrap IIsWebApplicationExtension query"); | ||
| 250 | } | ||
| 251 | else | ||
| 252 | { | ||
| 253 | hr = WcaWrapEmptyQuery(&pwzCustomActionData); | ||
| 254 | ExitOnFailure(hr, "Failed to wrap IIsWebApplicationExtension empty query"); | ||
| 255 | } | ||
| 256 | |||
| 257 | // Wrap vcsWebQuery, vcsWebAddressQuery, and vcsWebBaseQuery to send to deferred CA | ||
| 258 | if (S_OK == WcaTableExists(L"IIsWebAddress") && S_OK == WcaTableExists(L"IIsWebSite")) | ||
| 259 | { | ||
| 260 | hr = WcaWrapQuery(vcsWebQuery, &pwzCustomActionData, efmcColumn3 | efmcColumn4 | efmcColumn12 | efmcColumn13 | efmcColumn14, 2, 6); | ||
| 261 | ExitOnFailure(hr, "Failed to wrap IIsWebSite query"); | ||
| 262 | |||
| 263 | hr = WcaWrapQuery(vcsWebAddressQuery, &pwzCustomActionData, efmcColumn3 | efmcColumn4 | efmcColumn5, 0xFFFFFFFF, 0xFFFFFFFF); | ||
| 264 | ExitOnFailure(hr, "Failed to wrap IIsWebAddress query"); | ||
| 265 | |||
| 266 | hr = WcaWrapQuery(vcsWebBaseQuery, &pwzCustomActionData, efmcColumn2 | efmcColumn3 | efmcColumn4 | efmcColumn5 | efmcColumn7, 0xFFFFFFFF, 0xFFFFFFFF); | ||
| 267 | ExitOnFailure(hr, "Failed to wrap IIsWebBase query"); | ||
| 268 | } | ||
| 269 | else | ||
| 270 | { | ||
| 271 | hr = WcaWrapEmptyQuery(&pwzCustomActionData); | ||
| 272 | ExitOnFailure(hr, "Failed to wrap IIsWebSite empty query"); | ||
| 273 | |||
| 274 | hr = WcaWrapEmptyQuery(&pwzCustomActionData); | ||
| 275 | ExitOnFailure(hr, "Failed to wrap IIsWebAddress empty query"); | ||
| 276 | |||
| 277 | hr = WcaWrapEmptyQuery(&pwzCustomActionData); | ||
| 278 | ExitOnFailure(hr, "Failed to wrap IIsWebBase empty query"); | ||
| 279 | } | ||
| 280 | |||
| 281 | // Wrap vcsWebDirQuery to send to deferred CA | ||
| 282 | if (S_OK == WcaTableExists(L"IIsWebDir")) | ||
| 283 | { | ||
| 284 | hr = WcaWrapQuery(vcsWebDirQuery, &pwzCustomActionData, efmcColumn4, 3, 0xFFFFFFFF); | ||
| 285 | ExitOnFailure(hr, "Failed to wrap IIsWebDir query"); | ||
| 286 | } | ||
| 287 | else | ||
| 288 | { | ||
| 289 | hr = WcaWrapEmptyQuery(&pwzCustomActionData); | ||
| 290 | ExitOnFailure(hr, "Failed to wrap IIsWebDir empty query"); | ||
| 291 | } | ||
| 292 | |||
| 293 | // Wrap vcsVDirQuery to send to deferred CA | ||
| 294 | if (S_OK == WcaTableExists(L"IIsWebVirtualDir")) | ||
| 295 | { | ||
| 296 | hr = WcaWrapQuery(vcsVDirQuery, &pwzCustomActionData, efmcColumn4, 3, 5); | ||
| 297 | ExitOnFailure(hr, "Failed to wrap IIsWebVirtualDir query"); | ||
| 298 | } | ||
| 299 | else | ||
| 300 | { | ||
| 301 | hr = WcaWrapEmptyQuery(&pwzCustomActionData); | ||
| 302 | ExitOnFailure(hr, "Failed to wrap IIsWebVirtualDir empty query"); | ||
| 303 | } | ||
| 304 | |||
| 305 | // Wrap vcsFilterQuery to send to deferred CA | ||
| 306 | if (S_OK == WcaTableExists(L"IIsFilter")) | ||
| 307 | { | ||
| 308 | hr = WcaWrapQuery(vcsFilterQuery, &pwzCustomActionData, efmcColumn4 | efmcColumn5, 3, 0xFFFFFFFF); | ||
| 309 | ExitOnFailure(hr, "Failed to wrap IIsFilter query"); | ||
| 310 | } | ||
| 311 | else | ||
| 312 | { | ||
| 313 | hr = WcaWrapEmptyQuery(&pwzCustomActionData); | ||
| 314 | ExitOnFailure(hr, "Failed to wrap IIsFilter empty query"); | ||
| 315 | } | ||
| 316 | |||
| 317 | // Wrap vcsPropertyQuery to send to deferred CA | ||
| 318 | if (S_OK == WcaTableExists(L"IIsProperty")) | ||
| 319 | { | ||
| 320 | hr = WcaWrapQuery(vcsPropertyQuery, &pwzCustomActionData, efmcColumn4, 2, 0xFFFFFFFF); | ||
| 321 | ExitOnFailure(hr, "Failed to wrap IIsProperty query"); | ||
| 322 | } | ||
| 323 | else | ||
| 324 | { | ||
| 325 | hr = WcaWrapEmptyQuery(&pwzCustomActionData); | ||
| 326 | ExitOnFailure(hr, "Failed to wrap IIsProperty empty query"); | ||
| 327 | } | ||
| 328 | |||
| 329 | if (MSICONDITION_TRUE == ::MsiEvaluateConditionW(hInstall, USEIIS7CONDITION)) | ||
| 330 | { | ||
| 331 | // This must remain trace only, CA data may contain password | ||
| 332 | WcaLog(LOGMSG_TRACEONLY, "Custom Action Data for ConfigureIIS7Exec will be: %ls", pwzCustomActionData); | ||
| 333 | |||
| 334 | hr = WcaDoDeferredAction(L"ConfigureIIs7Exec", pwzCustomActionData, ConfigureIIsCost); | ||
| 335 | ExitOnFailure(hr, "Failed to schedule ConfigureIIs7Exec custom action"); | ||
| 336 | |||
| 337 | ReleaseNullStr(pwzCustomActionData); | ||
| 338 | |||
| 339 | // Write the CaScript key to the ConfigureIIS custom action data | ||
| 340 | hr = WcaWriteStringToCaData(pwzScriptKey, &pwzCustomActionData); | ||
| 341 | ExitOnFailure(hr, "Failed to add script key to CustomActionData."); | ||
| 342 | |||
| 343 | hr = WcaDoDeferredAction(L"WriteIIS7ConfigChanges", pwzCustomActionData, WriteIIS7ConfigChangesCost); | ||
| 344 | ExitOnFailure(hr, "Failed to schedule WriteMetabaseChanges custom action"); | ||
| 345 | } | ||
| 346 | else | ||
| 347 | { | ||
| 348 | // This must remain trace only, CA data may contain password | ||
| 349 | WcaLog(LOGMSG_TRACEONLY, "Custom Action Data for ConfigureIISExec will be: %ls", pwzCustomActionData); | ||
| 350 | |||
| 351 | hr = WcaDoDeferredAction(L"ConfigureIIsExec", pwzCustomActionData, ConfigureIIsCost); | ||
| 352 | ExitOnFailure(hr, "Failed to schedule ConfigureIISExec custom action"); | ||
| 353 | |||
| 354 | ReleaseNullStr(pwzCustomActionData); | ||
| 355 | |||
| 356 | // Write the CaScript key to the ConfigureIIS custom action data | ||
| 357 | hr = WcaWriteStringToCaData(pwzScriptKey, &pwzCustomActionData); | ||
| 358 | ExitOnFailure(hr, "Failed to add script key to CustomActionData."); | ||
| 359 | |||
| 360 | hr = WcaDoDeferredAction(L"WriteMetabaseChanges", pwzCustomActionData, WriteMetabaseChangesCost); | ||
| 361 | ExitOnFailure(hr, "Failed to schedule WriteMetabaseChanges custom action"); | ||
| 362 | } | ||
| 363 | |||
| 364 | LExit: | ||
| 365 | ReleaseStr(pwzScriptKey); | ||
| 366 | ReleaseStr(pwzBackupId); | ||
| 367 | ReleaseStr(pwzCustomActionData); | ||
| 368 | |||
| 369 | er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; | ||
| 370 | return WcaFinalize(er); | ||
| 371 | } | ||
| 372 | |||
| 373 | /******************************************************************** | ||
| 374 | ConfigureIIsExec - custom action for installing IIs settings - table | ||
| 375 | data will be wrapped and passed in from immediate CA | ||
| 376 | ReadIIsTables | ||
| 377 | |||
| 378 | ********************************************************************/ | ||
| 379 | extern "C" UINT __stdcall ConfigureIIsExec( | ||
| 380 | __in MSIHANDLE hInstall | ||
| 381 | ) | ||
| 382 | { | ||
| 383 | //AssertSz(FALSE, "debug ConfigureIIsExec here"); | ||
| 384 | HRESULT hr = S_OK; | ||
| 385 | UINT er = ERROR_SUCCESS; | ||
| 386 | |||
| 387 | BOOL fInitializedCom = FALSE; | ||
| 388 | IMSAdminBase* piMetabase = NULL; | ||
| 389 | |||
| 390 | SCA_WEB* pswList = NULL; | ||
| 391 | SCA_WEBDIR* pswdList = NULL; | ||
| 392 | SCA_VDIR* psvdList = NULL; | ||
| 393 | SCA_FILTER* psfList = NULL; | ||
| 394 | SCA_APPPOOL *psapList = NULL; | ||
| 395 | SCA_MIMEMAP* psmmList = NULL; | ||
| 396 | SCA_HTTP_HEADER* pshhList = NULL; | ||
| 397 | SCA_PROPERTY *pspList = NULL; | ||
| 398 | SCA_WEBSVCEXT* psWseList = NULL; | ||
| 399 | SCA_WEB_ERROR* psweList = NULL; | ||
| 400 | |||
| 401 | LPWSTR pwzScriptKey = NULL; | ||
| 402 | LPWSTR pwzCustomActionData = NULL; | ||
| 403 | |||
| 404 | WCA_WRAPQUERY_HANDLE hUserQuery = NULL; | ||
| 405 | WCA_WRAPQUERY_HANDLE hWebBaseQuery = NULL; | ||
| 406 | WCA_WRAPQUERY_HANDLE hWebDirPropQuery = NULL; | ||
| 407 | WCA_WRAPQUERY_HANDLE hSslCertQuery = NULL; | ||
| 408 | WCA_WRAPQUERY_HANDLE hWebLogQuery = NULL; | ||
| 409 | WCA_WRAPQUERY_HANDLE hWebAppQuery = NULL; | ||
| 410 | WCA_WRAPQUERY_HANDLE hWebAppExtQuery = NULL; | ||
| 411 | |||
| 412 | // initialize | ||
| 413 | hr = WcaInitialize(hInstall, "ConfigureIIsExec"); | ||
| 414 | ExitOnFailure(hr, "Failed to initialize"); | ||
| 415 | |||
| 416 | hr = WcaGetProperty(L"CustomActionData", &pwzCustomActionData); | ||
| 417 | ExitOnFailure(hr, "failed to get CustomActionData"); | ||
| 418 | |||
| 419 | // Get the CaScript key | ||
| 420 | hr = WcaReadStringFromCaData(&pwzCustomActionData, &pwzScriptKey); | ||
| 421 | ExitOnFailure(hr, "Failed to get CaScript key from custom action data"); | ||
| 422 | |||
| 423 | hr = ::CoInitialize(NULL); | ||
| 424 | ExitOnFailure(hr, "failed to initialize COM"); | ||
| 425 | fInitializedCom = TRUE; | ||
| 426 | |||
| 427 | // if IIS was uninstalled (thus no IID_IMSAdminBase) allow the | ||
| 428 | // user to still uninstall this package by clicking "Ignore" | ||
| 429 | do | ||
| 430 | { | ||
| 431 | hr = ::CoCreateInstance(CLSID_MSAdminBase, NULL, CLSCTX_ALL, IID_IMSAdminBase, (void**)&piMetabase); | ||
| 432 | if (FAILED(hr)) | ||
| 433 | { | ||
| 434 | WcaLog(LOGMSG_STANDARD, "failed to get IID_IMSAdminBase Object"); | ||
| 435 | er = WcaErrorMessage(msierrIISCannotConnect, hr, INSTALLMESSAGE_ERROR | MB_ABORTRETRYIGNORE, 0); | ||
| 436 | switch (er) | ||
| 437 | { | ||
| 438 | case IDABORT: | ||
| 439 | ExitFunction(); // bail with the error result from the CoCreate to kick off a rollback | ||
| 440 | case IDRETRY: | ||
| 441 | hr = S_FALSE; // hit me, baby, one more time | ||
| 442 | break; | ||
| 443 | case IDIGNORE: | ||
| 444 | __fallthrough; | ||
| 445 | default: | ||
| 446 | WcaLog(LOGMSG_STANDARD, "ignoring absent IIS"); | ||
| 447 | // We need to write the empty script to communicate to other deferred CA that there is noting to do. | ||
| 448 | hr = ScaWriteConfigurationScript(pwzScriptKey); | ||
| 449 | ExitOnFailure(hr, "failed to schedule metabase configuration"); | ||
| 450 | |||
| 451 | ExitFunction1(hr = S_OK); // pretend everything is okay | ||
| 452 | break; | ||
| 453 | } | ||
| 454 | } | ||
| 455 | } while (S_FALSE == hr); | ||
| 456 | |||
| 457 | // read the msi tables | ||
| 458 | hr = WcaBeginUnwrapQuery(&hUserQuery, &pwzCustomActionData); | ||
| 459 | ExitOnFailure(hr, "Failed to unwrap user query"); | ||
| 460 | |||
| 461 | hr = ScaWebSvcExtRead(&psWseList, &pwzCustomActionData); | ||
| 462 | MessageExitOnFailure(hr, msierrIISFailedReadWebSvcExt, "failed while processing WebServiceExtensions"); | ||
| 463 | |||
| 464 | hr = ScaAppPoolRead(&psapList, hUserQuery, &pwzCustomActionData); | ||
| 465 | MessageExitOnFailure(hr, msierrIISFailedReadAppPool, "failed while processing WebAppPools"); | ||
| 466 | |||
| 467 | // MimeMap, Error and HttpHeader need to be read before the virtual directory and web read | ||
| 468 | hr = ScaMimeMapRead(&psmmList, &pwzCustomActionData); | ||
| 469 | MessageExitOnFailure(hr, msierrIISFailedReadMimeMap, "failed while processing MimeMaps"); | ||
| 470 | |||
| 471 | hr = ScaHttpHeaderRead(&pshhList, &pwzCustomActionData); | ||
| 472 | MessageExitOnFailure(hr, msierrIISFailedReadHttpHeader, "failed while processing HttpHeaders"); | ||
| 473 | |||
| 474 | hr = ScaWebErrorRead(&psweList, &pwzCustomActionData); | ||
| 475 | MessageExitOnFailure(hr, msierrIISFailedReadWebError, "failed while processing WebErrors"); | ||
| 476 | |||
| 477 | hr = WcaBeginUnwrapQuery(&hWebDirPropQuery, &pwzCustomActionData); | ||
| 478 | ExitOnFailure(hr, "Failed to unwrap web dir properties query"); | ||
| 479 | |||
| 480 | hr = WcaBeginUnwrapQuery(&hSslCertQuery, &pwzCustomActionData); | ||
| 481 | ExitOnFailure(hr, "Failed to unwrap ssl certificate query"); | ||
| 482 | |||
| 483 | hr = WcaBeginUnwrapQuery(&hWebLogQuery, &pwzCustomActionData); | ||
| 484 | ExitOnFailure(hr, "Failed to unwrap web log query"); | ||
| 485 | |||
| 486 | hr = WcaBeginUnwrapQuery(&hWebAppQuery, &pwzCustomActionData); | ||
| 487 | ExitOnFailure(hr, "Failed to unwrap web application query"); | ||
| 488 | |||
| 489 | hr = WcaBeginUnwrapQuery(&hWebAppExtQuery, &pwzCustomActionData); | ||
| 490 | ExitOnFailure(hr, "Failed to unwrap web application extension query"); | ||
| 491 | |||
| 492 | hr = ScaWebsRead(piMetabase, &psmmList, &pswList, &pshhList, &psweList, hUserQuery, hWebDirPropQuery, hSslCertQuery, hWebLogQuery, hWebAppQuery, hWebAppExtQuery, &pwzCustomActionData); | ||
| 493 | MessageExitOnFailure(hr, msierrIISFailedReadWebSite, "failed while processing WebSites"); | ||
| 494 | |||
| 495 | hr = WcaBeginUnwrapQuery(&hWebBaseQuery, &pwzCustomActionData); | ||
| 496 | ExitOnFailure(hr, "Failed to unwrap web base query"); | ||
| 497 | |||
| 498 | hr = ScaWebDirsRead(piMetabase, pswList, hUserQuery, hWebBaseQuery, hWebDirPropQuery, hWebAppQuery, hWebAppExtQuery, &pwzCustomActionData, &pswdList); | ||
| 499 | MessageExitOnFailure(hr, msierrIISFailedReadWebDirs, "failed while processing WebDirs"); | ||
| 500 | |||
| 501 | hr = ScaVirtualDirsRead(piMetabase, pswList, &psvdList, &psmmList, &pshhList, &psweList, hUserQuery, hWebBaseQuery, hWebDirPropQuery, hWebAppQuery, hWebAppExtQuery, &pwzCustomActionData); | ||
| 502 | MessageExitOnFailure(hr, msierrIISFailedReadVDirs, "failed while processing WebVirtualDirs"); | ||
| 503 | |||
| 504 | hr = ScaFiltersRead(piMetabase, pswList, hWebBaseQuery, &psfList, &pwzCustomActionData); | ||
| 505 | MessageExitOnFailure(hr, msierrIISFailedReadFilters, "failed while processing WebFilters"); | ||
| 506 | |||
| 507 | hr = ScaPropertyRead(&pspList, &pwzCustomActionData); | ||
| 508 | MessageExitOnFailure(hr, msierrIISFailedReadProp, "failed while processing WebProperties"); | ||
| 509 | |||
| 510 | // do uninstall actions (order is important!) | ||
| 511 | hr = ScaPropertyUninstall(piMetabase, pspList); | ||
| 512 | MessageExitOnFailure(hr, msierrIISFailedSchedUninstallProp, "failed to uninstall IIS properties"); | ||
| 513 | |||
| 514 | hr = ScaFiltersUninstall(piMetabase, psfList); | ||
| 515 | MessageExitOnFailure(hr, msierrIISFailedSchedUninstallFilters, "failed to schedule uninstall of filters"); | ||
| 516 | |||
| 517 | hr = ScaVirtualDirsUninstall(piMetabase, psvdList); | ||
| 518 | MessageExitOnFailure(hr, msierrIISFailedSchedUninstallVDirs, "failed to schedule uninstall of virtual directories"); | ||
| 519 | |||
| 520 | hr = ScaWebDirsUninstall(piMetabase, pswdList); | ||
| 521 | MessageExitOnFailure(hr, msierrIISFailedSchedUninstallWebDirs, "failed to schedule uninstall of web directories"); | ||
| 522 | |||
| 523 | hr = ScaWebsUninstall(piMetabase, pswList); | ||
| 524 | MessageExitOnFailure(hr, msierrIISFailedSchedUninstallWebs, "failed to schedule uninstall of webs"); | ||
| 525 | |||
| 526 | hr = ScaAppPoolUninstall(piMetabase, psapList); | ||
| 527 | MessageExitOnFailure(hr, msierrIISFailedSchedUninstallAppPool, "failed to schedule uninstall of AppPools"); | ||
| 528 | |||
| 529 | |||
| 530 | // do install actions (order is important!) | ||
| 531 | // ScaWebSvcExtCommit contains both uninstall and install actions. | ||
| 532 | hr = ScaWebSvcExtCommit(piMetabase, psWseList); | ||
| 533 | MessageExitOnFailure(hr, msierrIISFailedSchedInstallWebSvcExt, "failed to schedule install/uninstall of WebSvcExt"); | ||
| 534 | |||
| 535 | hr = ScaAppPoolInstall(piMetabase, psapList); | ||
| 536 | MessageExitOnFailure(hr, msierrIISFailedSchedInstallAppPool, "failed to schedule install of AppPools"); | ||
| 537 | |||
| 538 | hr = ScaWebsInstall(piMetabase, pswList, psapList); | ||
| 539 | MessageExitOnFailure(hr, msierrIISFailedSchedInstallWebs, "failed to schedule install of webs"); | ||
| 540 | |||
| 541 | hr = ScaWebDirsInstall(piMetabase, pswdList, psapList); | ||
| 542 | MessageExitOnFailure(hr, msierrIISFailedSchedInstallWebDirs, "failed to schedule install of web directories"); | ||
| 543 | |||
| 544 | hr = ScaVirtualDirsInstall(piMetabase, psvdList, psapList); | ||
| 545 | MessageExitOnFailure(hr, msierrIISFailedSchedInstallVDirs, "failed to schedule install of virtual directories"); | ||
| 546 | |||
| 547 | hr = ScaFiltersInstall(piMetabase, psfList); | ||
| 548 | MessageExitOnFailure(hr, msierrIISFailedSchedInstallFilters, "failed to schedule install of filters"); | ||
| 549 | |||
| 550 | hr = ScaPropertyInstall(piMetabase, pspList); | ||
| 551 | MessageExitOnFailure(hr, msierrIISFailedSchedInstallProp, "failed to schedule install of properties"); | ||
| 552 | |||
| 553 | hr = ScaWriteConfigurationScript(pwzScriptKey); | ||
| 554 | ExitOnFailure(hr, "failed to schedule metabase configuration"); | ||
| 555 | |||
| 556 | LExit: | ||
| 557 | ReleaseStr(pwzScriptKey); | ||
| 558 | ReleaseStr(pwzCustomActionData); | ||
| 559 | |||
| 560 | WcaFinishUnwrapQuery(hUserQuery); | ||
| 561 | WcaFinishUnwrapQuery(hWebBaseQuery); | ||
| 562 | WcaFinishUnwrapQuery(hWebDirPropQuery); | ||
| 563 | WcaFinishUnwrapQuery(hSslCertQuery); | ||
| 564 | WcaFinishUnwrapQuery(hWebLogQuery); | ||
| 565 | WcaFinishUnwrapQuery(hWebAppQuery); | ||
| 566 | WcaFinishUnwrapQuery(hWebAppExtQuery); | ||
| 567 | |||
| 568 | if (psWseList) | ||
| 569 | { | ||
| 570 | ScaWebSvcExtFreeList(psWseList); | ||
| 571 | } | ||
| 572 | |||
| 573 | if (psfList) | ||
| 574 | { | ||
| 575 | ScaFiltersFreeList(psfList); | ||
| 576 | } | ||
| 577 | |||
| 578 | if (psvdList) | ||
| 579 | { | ||
| 580 | ScaVirtualDirsFreeList(psvdList); | ||
| 581 | } | ||
| 582 | |||
| 583 | if (pswdList) | ||
| 584 | { | ||
| 585 | ScaWebDirsFreeList(pswdList); | ||
| 586 | } | ||
| 587 | |||
| 588 | if (pswList) | ||
| 589 | { | ||
| 590 | ScaWebsFreeList(pswList); | ||
| 591 | } | ||
| 592 | |||
| 593 | if (psmmList) | ||
| 594 | { | ||
| 595 | ScaMimeMapCheckList(psmmList); | ||
| 596 | ScaMimeMapFreeList(psmmList); | ||
| 597 | } | ||
| 598 | |||
| 599 | if (pshhList) | ||
| 600 | { | ||
| 601 | ScaHttpHeaderCheckList(pshhList); | ||
| 602 | ScaHttpHeaderFreeList(pshhList); | ||
| 603 | } | ||
| 604 | |||
| 605 | if (psweList) | ||
| 606 | { | ||
| 607 | ScaWebErrorCheckList(psweList); | ||
| 608 | ScaWebErrorFreeList(psweList); | ||
| 609 | } | ||
| 610 | |||
| 611 | ReleaseObject(piMetabase); | ||
| 612 | |||
| 613 | if (fInitializedCom) | ||
| 614 | { | ||
| 615 | ::CoUninitialize(); | ||
| 616 | } | ||
| 617 | |||
| 618 | er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; | ||
| 619 | return WcaFinalize(er); | ||
| 620 | } | ||
| 621 | |||
| 622 | |||
| 623 | /******************************************************************** | ||
| 624 | ConfigureIIs - CUSTOM ACTION ENTRY POINT for installing IIs settings | ||
| 625 | |||
| 626 | ********************************************************************/ | ||
| 627 | extern "C" UINT __stdcall ConfigureIIs7Exec( | ||
| 628 | __in MSIHANDLE hInstall | ||
| 629 | ) | ||
| 630 | { | ||
| 631 | //AssertSz(FALSE, "debug ConfigureIIs7Exec here"); | ||
| 632 | HRESULT hr = S_OK; | ||
| 633 | UINT er = ERROR_SUCCESS; | ||
| 634 | |||
| 635 | LPWSTR pwzScriptKey = NULL; | ||
| 636 | LPWSTR pwzCustomActionData = NULL; | ||
| 637 | |||
| 638 | SCA_WEB7* pswList = NULL; | ||
| 639 | SCA_WEBDIR7* pswdList = NULL; | ||
| 640 | SCA_VDIR7* psvdList = NULL; | ||
| 641 | SCA_FILTER* psfList = NULL; | ||
| 642 | SCA_APPPOOL *psapList = NULL; | ||
| 643 | SCA_MIMEMAP* psmmList = NULL; | ||
| 644 | SCA_HTTP_HEADER* pshhList = NULL; | ||
| 645 | SCA_PROPERTY *pspList = NULL; | ||
| 646 | SCA_WEBSVCEXT* psWseList = NULL; | ||
| 647 | SCA_WEB_ERROR* psweList = NULL; | ||
| 648 | |||
| 649 | WCA_WRAPQUERY_HANDLE hUserQuery = NULL; | ||
| 650 | WCA_WRAPQUERY_HANDLE hWebBaseQuery = NULL; | ||
| 651 | WCA_WRAPQUERY_HANDLE hWebDirPropQuery = NULL; | ||
| 652 | WCA_WRAPQUERY_HANDLE hSslCertQuery = NULL; | ||
| 653 | WCA_WRAPQUERY_HANDLE hWebLogQuery = NULL; | ||
| 654 | WCA_WRAPQUERY_HANDLE hWebAppQuery = NULL; | ||
| 655 | WCA_WRAPQUERY_HANDLE hWebAppExtQuery = NULL; | ||
| 656 | |||
| 657 | // initialize | ||
| 658 | hr = WcaInitialize(hInstall, "ConfigureIIs7Exec"); | ||
| 659 | ExitOnFailure(hr, "Failed to initialize"); | ||
| 660 | |||
| 661 | hr = WcaGetProperty(L"CustomActionData", &pwzCustomActionData); | ||
| 662 | ExitOnFailure(hr, "failed to get CustomActionData"); | ||
| 663 | |||
| 664 | // Get the CaScript key | ||
| 665 | hr = WcaReadStringFromCaData(&pwzCustomActionData, &pwzScriptKey); | ||
| 666 | ExitOnFailure(hr, "Failed to get CaScript key from custom action data"); | ||
| 667 | |||
| 668 | // read the msi tables | ||
| 669 | hr = WcaBeginUnwrapQuery(&hUserQuery, &pwzCustomActionData); | ||
| 670 | ExitOnFailure(hr, "Failed to unwrap user query"); | ||
| 671 | |||
| 672 | hr = ScaWebSvcExtRead(&psWseList, &pwzCustomActionData); | ||
| 673 | MessageExitOnFailure(hr, msierrIISFailedReadWebSvcExt, "failed while processing WebServiceExtensions"); | ||
| 674 | |||
| 675 | hr = ScaAppPoolRead(&psapList, hUserQuery, &pwzCustomActionData); | ||
| 676 | MessageExitOnFailure(hr, msierrIISFailedReadAppPool, "failed while processing WebAppPools"); | ||
| 677 | |||
| 678 | // MimeMap, Error and HttpHeader need to be read before the virtual directory and web read | ||
| 679 | hr = ScaMimeMapRead(&psmmList, &pwzCustomActionData); | ||
| 680 | MessageExitOnFailure(hr, msierrIISFailedReadMimeMap, "failed while processing MimeMaps"); | ||
| 681 | |||
| 682 | hr = ScaHttpHeaderRead(&pshhList, &pwzCustomActionData); | ||
| 683 | MessageExitOnFailure(hr, msierrIISFailedReadHttpHeader, "failed while processing HttpHeaders"); | ||
| 684 | |||
| 685 | hr = ScaWebErrorRead(&psweList, &pwzCustomActionData); | ||
| 686 | MessageExitOnFailure(hr, msierrIISFailedReadWebError, "failed while processing WebErrors"); | ||
| 687 | |||
| 688 | hr = WcaBeginUnwrapQuery(&hWebDirPropQuery, &pwzCustomActionData); | ||
| 689 | ExitOnFailure(hr, "Failed to unwrap web dir properties query"); | ||
| 690 | |||
| 691 | hr = WcaBeginUnwrapQuery(&hSslCertQuery, &pwzCustomActionData); | ||
| 692 | ExitOnFailure(hr, "Failed to unwrap ssl certificate query"); | ||
| 693 | |||
| 694 | hr = WcaBeginUnwrapQuery(&hWebLogQuery, &pwzCustomActionData); | ||
| 695 | ExitOnFailure(hr, "Failed to unwrap web log query"); | ||
| 696 | |||
| 697 | hr = WcaBeginUnwrapQuery(&hWebAppQuery, &pwzCustomActionData); | ||
| 698 | ExitOnFailure(hr, "Failed to unwrap web application query"); | ||
| 699 | |||
| 700 | hr = WcaBeginUnwrapQuery(&hWebAppExtQuery, &pwzCustomActionData); | ||
| 701 | ExitOnFailure(hr, "Failed to unwrap web application extension query"); | ||
| 702 | |||
| 703 | hr = ScaWebsRead7(&pswList, &pshhList, &psweList, hUserQuery, hWebDirPropQuery, hSslCertQuery, hWebLogQuery, hWebAppQuery, hWebAppExtQuery, &pwzCustomActionData); | ||
| 704 | MessageExitOnFailure(hr, msierrIISFailedReadWebSite, "failed while processing WebSites"); | ||
| 705 | |||
| 706 | hr = WcaBeginUnwrapQuery(&hWebBaseQuery, &pwzCustomActionData); | ||
| 707 | ExitOnFailure(hr, "Failed to unwrap web base query"); | ||
| 708 | |||
| 709 | hr = ScaWebDirsRead7(pswList, hUserQuery, hWebBaseQuery, hWebDirPropQuery, hWebAppQuery, hWebAppExtQuery, &pwzCustomActionData, &pswdList); | ||
| 710 | MessageExitOnFailure(hr, msierrIISFailedReadWebDirs, "failed while processing WebDirs"); | ||
| 711 | |||
| 712 | hr = ScaVirtualDirsRead7(pswList, &psvdList, &psmmList, &pshhList, &psweList, hUserQuery, hWebBaseQuery, hWebDirPropQuery, hWebAppQuery, hWebAppExtQuery, &pwzCustomActionData); | ||
| 713 | MessageExitOnFailure(hr, msierrIISFailedReadVDirs, "failed while processing WebVirtualDirs"); | ||
| 714 | |||
| 715 | hr = ScaFiltersRead7(pswList, hWebBaseQuery, &psfList, &pwzCustomActionData); | ||
| 716 | MessageExitOnFailure(hr, msierrIISFailedReadFilters, "failed while processing WebFilters"); | ||
| 717 | |||
| 718 | hr = ScaPropertyRead(&pspList, &pwzCustomActionData); | ||
| 719 | MessageExitOnFailure(hr, msierrIISFailedReadProp, "failed while processing WebProperties"); | ||
| 720 | |||
| 721 | // do uninstall actions (order is important!) | ||
| 722 | hr = ScaPropertyUninstall7(pspList); | ||
| 723 | MessageExitOnFailure(hr, msierrIISFailedSchedUninstallProp, "failed to uninstall IIS properties"); | ||
| 724 | |||
| 725 | hr = ScaFiltersUninstall7(psfList); | ||
| 726 | MessageExitOnFailure(hr, msierrIISFailedSchedUninstallFilters, "failed to schedule uninstall of filters"); | ||
| 727 | |||
| 728 | hr = ScaVirtualDirsUninstall7(psvdList); | ||
| 729 | MessageExitOnFailure(hr, msierrIISFailedSchedUninstallVDirs, "failed to schedule uninstall of virtual directories"); | ||
| 730 | |||
| 731 | hr = ScaWebDirsUninstall7(pswdList); | ||
| 732 | MessageExitOnFailure(hr, msierrIISFailedSchedUninstallWebDirs, "failed to schedule uninstall of web directories"); | ||
| 733 | |||
| 734 | hr = ScaWebsUninstall7(pswList); | ||
| 735 | MessageExitOnFailure(hr, msierrIISFailedSchedUninstallWebs, "failed to schedule uninstall of webs"); | ||
| 736 | |||
| 737 | hr = ScaAppPoolUninstall7(psapList); | ||
| 738 | MessageExitOnFailure(hr, msierrIISFailedSchedUninstallAppPool, "failed to schedule uninstall of AppPools"); | ||
| 739 | |||
| 740 | |||
| 741 | // do install actions (order is important!) | ||
| 742 | // ScaWebSvcExtCommit contains both uninstall and install actions. | ||
| 743 | hr = ScaWebSvcExtCommit7(psWseList); | ||
| 744 | MessageExitOnFailure(hr, msierrIISFailedSchedInstallWebSvcExt, "failed to schedule install/uninstall of WebSvcExt"); | ||
| 745 | |||
| 746 | hr = ScaAppPoolInstall7(psapList); | ||
| 747 | MessageExitOnFailure(hr, msierrIISFailedSchedInstallAppPool, "failed to schedule install of AppPools"); | ||
| 748 | |||
| 749 | hr = ScaWebsInstall7(pswList, psapList); | ||
| 750 | MessageExitOnFailure(hr, msierrIISFailedSchedInstallWebs, "failed to schedule install of webs"); | ||
| 751 | |||
| 752 | hr = ScaWebDirsInstall7(pswdList, psapList); | ||
| 753 | MessageExitOnFailure(hr, msierrIISFailedSchedInstallWebDirs, "failed to schedule install of web directories"); | ||
| 754 | |||
| 755 | hr = ScaVirtualDirsInstall7(psvdList, psapList); | ||
| 756 | MessageExitOnFailure(hr, msierrIISFailedSchedInstallVDirs, "failed to schedule install of virtual directories"); | ||
| 757 | |||
| 758 | hr = ScaFiltersInstall7(psfList); | ||
| 759 | MessageExitOnFailure(hr, msierrIISFailedSchedInstallFilters, "failed to schedule install of filters"); | ||
| 760 | |||
| 761 | hr = ScaPropertyInstall7(pspList); | ||
| 762 | MessageExitOnFailure(hr, msierrIISFailedSchedInstallProp, "failed to schedule install of properties"); | ||
| 763 | |||
| 764 | hr = ScaWriteConfigurationScript(pwzScriptKey); | ||
| 765 | ExitOnFailure(hr, "failed to schedule metabase configuration"); | ||
| 766 | |||
| 767 | LExit: | ||
| 768 | ReleaseNullStr(pwzScriptKey); | ||
| 769 | ReleaseNullStr(pwzCustomActionData); | ||
| 770 | |||
| 771 | WcaFinishUnwrapQuery(hUserQuery); | ||
| 772 | WcaFinishUnwrapQuery(hWebBaseQuery); | ||
| 773 | WcaFinishUnwrapQuery(hWebDirPropQuery); | ||
| 774 | WcaFinishUnwrapQuery(hSslCertQuery); | ||
| 775 | WcaFinishUnwrapQuery(hWebLogQuery); | ||
| 776 | WcaFinishUnwrapQuery(hWebAppQuery); | ||
| 777 | WcaFinishUnwrapQuery(hWebAppExtQuery); | ||
| 778 | |||
| 779 | if (psWseList) | ||
| 780 | { | ||
| 781 | ScaWebSvcExtFreeList(psWseList); | ||
| 782 | } | ||
| 783 | |||
| 784 | if (psfList) | ||
| 785 | { | ||
| 786 | ScaFiltersFreeList(psfList); | ||
| 787 | } | ||
| 788 | |||
| 789 | if (psvdList) | ||
| 790 | { | ||
| 791 | ScaVirtualDirsFreeList7(psvdList); | ||
| 792 | } | ||
| 793 | |||
| 794 | if (pswdList) | ||
| 795 | { | ||
| 796 | ScaWebDirsFreeList7(pswdList); | ||
| 797 | } | ||
| 798 | |||
| 799 | if (pswList) | ||
| 800 | { | ||
| 801 | ScaWebsFreeList7(pswList); | ||
| 802 | } | ||
| 803 | |||
| 804 | if (psmmList) | ||
| 805 | { | ||
| 806 | ScaMimeMapFreeList(psmmList); | ||
| 807 | } | ||
| 808 | |||
| 809 | if (pshhList) | ||
| 810 | { | ||
| 811 | ScaHttpHeaderCheckList(pshhList); | ||
| 812 | ScaHttpHeaderFreeList(pshhList); | ||
| 813 | } | ||
| 814 | |||
| 815 | if (psweList) | ||
| 816 | { | ||
| 817 | ScaWebErrorCheckList(psweList); | ||
| 818 | ScaWebErrorFreeList(psweList); | ||
| 819 | } | ||
| 820 | |||
| 821 | er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; | ||
| 822 | return WcaFinalize(er); | ||
| 823 | } | ||
diff --git a/src/ca/scassl.cpp b/src/ca/scassl.cpp new file mode 100644 index 00000000..4a06b77e --- /dev/null +++ b/src/ca/scassl.cpp | |||
| @@ -0,0 +1,115 @@ | |||
| 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 | #include "precomp.h" | ||
| 4 | |||
| 5 | enum eSslCertificateQuery { scqStoreName = 1, scqHash, scqWeb }; | ||
| 6 | |||
| 7 | static HRESULT AddSslCertificateToList( | ||
| 8 | __in SCA_WEB_SSL_CERTIFICATE** ppswscList | ||
| 9 | ); | ||
| 10 | |||
| 11 | |||
| 12 | HRESULT ScaSslCertificateRead( | ||
| 13 | __in LPCWSTR wzWebId, | ||
| 14 | __in WCA_WRAPQUERY_HANDLE hSslCertQuery, | ||
| 15 | __inout SCA_WEB_SSL_CERTIFICATE** ppswscList | ||
| 16 | ) | ||
| 17 | { | ||
| 18 | HRESULT hr = S_OK; | ||
| 19 | |||
| 20 | MSIHANDLE hRec; | ||
| 21 | SCA_WEB_SSL_CERTIFICATE* pswsc = NULL; | ||
| 22 | LPWSTR pwzData = NULL; | ||
| 23 | |||
| 24 | WcaFetchWrappedReset(hSslCertQuery); | ||
| 25 | |||
| 26 | // Get the certificate information. | ||
| 27 | while (S_OK == (hr = WcaFetchWrappedRecordWhereString(hSslCertQuery, scqWeb, wzWebId, &hRec))) | ||
| 28 | { | ||
| 29 | hr = AddSslCertificateToList(ppswscList); | ||
| 30 | ExitOnFailure(hr, "failed to add ssl certificate to list"); | ||
| 31 | |||
| 32 | pswsc = *ppswscList; | ||
| 33 | |||
| 34 | hr = WcaGetRecordString(hRec, scqStoreName, &pwzData); | ||
| 35 | ExitOnFailure(hr, "Failed to get web ssl certificate store name."); | ||
| 36 | |||
| 37 | hr = ::StringCchCopyW(pswsc->wzStoreName, countof(pswsc->wzStoreName), pwzData); | ||
| 38 | ExitOnFailure(hr, "Failed to copy web ssl certificate store name."); | ||
| 39 | |||
| 40 | hr = WcaGetRecordString(hRec, scqHash, &pwzData); | ||
| 41 | ExitOnFailure(hr, "Failed to get hash for web ssl certificate."); | ||
| 42 | |||
| 43 | hr = StrHexDecode(pwzData, pswsc->rgbSHA1Hash, countof(pswsc->rgbSHA1Hash)); | ||
| 44 | ExitOnFailure(hr, "Failed to decode certificate hash for web: %ls, data: %ls", wzWebId, pwzData); | ||
| 45 | } | ||
| 46 | |||
| 47 | if (E_NOMOREITEMS == hr) | ||
| 48 | { | ||
| 49 | hr = S_OK; | ||
| 50 | } | ||
| 51 | ExitOnFailure(hr, "Failed to read IIsWebSiteCertificates table."); | ||
| 52 | |||
| 53 | LExit: | ||
| 54 | ReleaseStr(pwzData); | ||
| 55 | return hr; | ||
| 56 | } | ||
| 57 | |||
| 58 | |||
| 59 | HRESULT ScaSslCertificateWriteMetabase( | ||
| 60 | __in IMSAdminBase* piMetabase, | ||
| 61 | __in LPCWSTR wzWebBase, | ||
| 62 | __in SCA_WEB_SSL_CERTIFICATE* pswscList | ||
| 63 | ) | ||
| 64 | { | ||
| 65 | HRESULT hr = S_OK; | ||
| 66 | BLOB blob; | ||
| 67 | |||
| 68 | for (SCA_WEB_SSL_CERTIFICATE* pswsc = pswscList; pswsc; pswsc = pswsc->pNext) | ||
| 69 | { | ||
| 70 | // Write: /W3SVC/1:SslCertStoreName = "MY", "CA", "Root", etc. | ||
| 71 | hr = ScaWriteMetabaseValue(piMetabase, wzWebBase, L"", MD_SSL_CERT_STORE_NAME, METADATA_INHERIT, IIS_MD_UT_SERVER, STRING_METADATA, static_cast<LPVOID>(pswsc->wzStoreName)); | ||
| 72 | ExitOnFailure(hr, "Failed to write SslCertStoreName"); | ||
| 73 | |||
| 74 | // Write: /W3SVC/1:SslCertHash = <blob> | ||
| 75 | blob.pBlobData = pswsc->rgbSHA1Hash; | ||
| 76 | blob.cbSize = countof(pswsc->rgbSHA1Hash); | ||
| 77 | hr = ScaWriteMetabaseValue(piMetabase, wzWebBase, L"", MD_SSL_CERT_HASH, METADATA_INHERIT, IIS_MD_UT_SERVER, BINARY_METADATA, static_cast<LPVOID>(&blob)); | ||
| 78 | ExitOnFailure(hr, "Failed to write SslCertHash"); | ||
| 79 | } | ||
| 80 | |||
| 81 | LExit: | ||
| 82 | return hr; | ||
| 83 | } | ||
| 84 | |||
| 85 | |||
| 86 | void ScaSslCertificateFreeList( | ||
| 87 | __in SCA_WEB_SSL_CERTIFICATE* pswscList | ||
| 88 | ) | ||
| 89 | { | ||
| 90 | SCA_WEB_SSL_CERTIFICATE* pswscDelete = pswscList; | ||
| 91 | while (pswscList) | ||
| 92 | { | ||
| 93 | pswscDelete = pswscList; | ||
| 94 | pswscList = pswscList->pNext; | ||
| 95 | |||
| 96 | MemFree(pswscDelete); | ||
| 97 | } | ||
| 98 | } | ||
| 99 | |||
| 100 | |||
| 101 | static HRESULT AddSslCertificateToList( | ||
| 102 | __in SCA_WEB_SSL_CERTIFICATE** ppswscList | ||
| 103 | ) | ||
| 104 | { | ||
| 105 | HRESULT hr = S_OK; | ||
| 106 | |||
| 107 | SCA_WEB_SSL_CERTIFICATE* pswsc = static_cast<SCA_WEB_SSL_CERTIFICATE*>(MemAlloc(sizeof(SCA_WEB_SSL_CERTIFICATE), TRUE)); | ||
| 108 | ExitOnNull(pswsc, hr, E_OUTOFMEMORY, "failed to allocate memory for new SSL certificate list element"); | ||
| 109 | |||
| 110 | pswsc->pNext = *ppswscList; | ||
| 111 | *ppswscList = pswsc; | ||
| 112 | |||
| 113 | LExit: | ||
| 114 | return hr; | ||
| 115 | } | ||
diff --git a/src/ca/scassl.h b/src/ca/scassl.h new file mode 100644 index 00000000..df7c473d --- /dev/null +++ b/src/ca/scassl.h | |||
| @@ -0,0 +1,36 @@ | |||
| 1 | #pragma once | ||
| 2 | // 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. | ||
| 3 | |||
| 4 | |||
| 5 | #define MD_SSL_CERT_HASH ( IIS_MD_SSL_BASE+6 ) | ||
| 6 | #define MD_SSL_CERT_STORE_NAME ( IIS_MD_SSL_BASE+11 ) | ||
| 7 | //#define WIDE(x) WIDE2(x) | ||
| 8 | //#define WIDE2(x) L ## x | ||
| 9 | |||
| 10 | |||
| 11 | // structs | ||
| 12 | struct SCA_WEB_SSL_CERTIFICATE | ||
| 13 | { | ||
| 14 | WCHAR wzStoreName[65]; | ||
| 15 | BYTE rgbSHA1Hash[CB_CERTIFICATE_HASH]; | ||
| 16 | |||
| 17 | SCA_WEB_SSL_CERTIFICATE* pNext; | ||
| 18 | }; | ||
| 19 | |||
| 20 | |||
| 21 | // prototypes | ||
| 22 | HRESULT ScaSslCertificateRead( | ||
| 23 | __in LPCWSTR wzWebId, | ||
| 24 | __in WCA_WRAPQUERY_HANDLE hSslCertQuery, | ||
| 25 | __inout SCA_WEB_SSL_CERTIFICATE** ppswscList | ||
| 26 | ); | ||
| 27 | |||
| 28 | HRESULT ScaSslCertificateWriteMetabase( | ||
| 29 | __in IMSAdminBase* piMetabase, | ||
| 30 | __in LPCWSTR wzWebBase, | ||
| 31 | __in SCA_WEB_SSL_CERTIFICATE* pswscList | ||
| 32 | ); | ||
| 33 | |||
| 34 | void ScaSslCertificateFreeList( | ||
| 35 | __in SCA_WEB_SSL_CERTIFICATE* pswscList | ||
| 36 | ); | ||
diff --git a/src/ca/scassl7.cpp b/src/ca/scassl7.cpp new file mode 100644 index 00000000..47c16a9d --- /dev/null +++ b/src/ca/scassl7.cpp | |||
| @@ -0,0 +1,34 @@ | |||
| 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 | #include "precomp.h" | ||
| 4 | |||
| 5 | HRESULT ScaSslCertificateWrite7( | ||
| 6 | __in_z LPCWSTR wzWebBase, | ||
| 7 | __in SCA_WEB_SSL_CERTIFICATE* pswscList | ||
| 8 | ) | ||
| 9 | { | ||
| 10 | HRESULT hr = S_OK; | ||
| 11 | WCHAR wzEncodedCertificateHash[CB_CERTIFICATE_HASH * 2 + 1] = { 0 }; | ||
| 12 | |||
| 13 | for (SCA_WEB_SSL_CERTIFICATE* pswsc = pswscList; pswsc; pswsc = pswsc->pNext) | ||
| 14 | { | ||
| 15 | hr = ScaWriteConfigID(IIS_SSL_BINDING); | ||
| 16 | ExitOnFailure(hr, "Failed write SSL binding ID"); | ||
| 17 | hr = ScaWriteConfigID(IIS_CREATE); // Need to determine site action | ||
| 18 | ExitOnFailure(hr, "Failed write binding action"); | ||
| 19 | |||
| 20 | hr = ScaWriteConfigString(wzWebBase); //site name key | ||
| 21 | ExitOnFailure(hr, "Failed to write SSL website"); | ||
| 22 | hr = ScaWriteConfigString(pswsc->wzStoreName); //ssl store name | ||
| 23 | ExitOnFailure(hr, "Failed to write SSL store name"); | ||
| 24 | |||
| 25 | hr = StrHexEncode(pswsc->rgbSHA1Hash, countof(pswsc->rgbSHA1Hash), wzEncodedCertificateHash, countof(wzEncodedCertificateHash)); | ||
| 26 | ExitOnFailure(hr, "Failed to encode SSL hash"); | ||
| 27 | |||
| 28 | hr = ScaWriteConfigString(wzEncodedCertificateHash); //ssl hash | ||
| 29 | ExitOnFailure(hr, "Failed to write SSL hash"); | ||
| 30 | } | ||
| 31 | LExit: | ||
| 32 | |||
| 33 | return hr; | ||
| 34 | } | ||
diff --git a/src/ca/scassl7.h b/src/ca/scassl7.h new file mode 100644 index 00000000..1a4b09af --- /dev/null +++ b/src/ca/scassl7.h | |||
| @@ -0,0 +1,8 @@ | |||
| 1 | #pragma once | ||
| 2 | // 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. | ||
| 3 | |||
| 4 | |||
| 5 | HRESULT ScaSslCertificateWrite7( | ||
| 6 | __in_z LPCWSTR wzWebBase, | ||
| 7 | __in SCA_WEB_SSL_CERTIFICATE* pswscList | ||
| 8 | ); | ||
diff --git a/src/ca/scauser.cpp b/src/ca/scauser.cpp new file mode 100644 index 00000000..0b99edff --- /dev/null +++ b/src/ca/scauser.cpp | |||
| @@ -0,0 +1,91 @@ | |||
| 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 | #include "precomp.h" | ||
| 4 | |||
| 5 | LPCWSTR vcsUserQuery = L"SELECT `User`, `Component_`, `Name`, `Domain`, `Password` FROM `User` WHERE `User`=?"; | ||
| 6 | enum eUserQuery { vuqUser = 1, vuqComponent, vuqName, vuqDomain, vuqPassword }; | ||
| 7 | |||
| 8 | LPCWSTR vcsGroupQuery = L"SELECT `Group`, `Component_`, `Name`, `Domain` FROM `Group` WHERE `Group`=?"; | ||
| 9 | enum eGroupQuery { vgqGroup = 1, vgqComponent, vgqName, vgqDomain }; | ||
| 10 | |||
| 11 | LPCWSTR vcsUserGroupQuery = L"SELECT `User_`, `Group_` FROM `UserGroup` WHERE `User_`=?"; | ||
| 12 | enum eUserGroupQuery { vugqUser = 1, vugqGroup }; | ||
| 13 | |||
| 14 | LPCWSTR vActionableQuery = L"SELECT `User`,`Component_`,`Name`,`Domain`,`Password`,`Attributes` FROM `User` WHERE `Component_` IS NOT NULL"; | ||
| 15 | enum eActionableQuery { vaqUser = 1, vaqComponent, vaqName, vaqDomain, vaqPassword, vaqAttributes }; | ||
| 16 | |||
| 17 | HRESULT __stdcall ScaGetUserDeferred( | ||
| 18 | __in LPCWSTR wzUser, | ||
| 19 | __in WCA_WRAPQUERY_HANDLE hUserQuery, | ||
| 20 | __out SCA_USER* pscau | ||
| 21 | ) | ||
| 22 | { | ||
| 23 | if (!wzUser || !pscau) | ||
| 24 | { | ||
| 25 | return E_INVALIDARG; | ||
| 26 | } | ||
| 27 | |||
| 28 | HRESULT hr = S_OK; | ||
| 29 | MSIHANDLE hRec, hRecTest; | ||
| 30 | |||
| 31 | LPWSTR pwzData = NULL; | ||
| 32 | |||
| 33 | // clear struct and bail right away if no user key was passed to search for | ||
| 34 | ::ZeroMemory(pscau, sizeof(*pscau)); | ||
| 35 | if (!*wzUser) | ||
| 36 | { | ||
| 37 | ExitFunction1(hr = S_OK); | ||
| 38 | } | ||
| 39 | |||
| 40 | // Reset back to the first record | ||
| 41 | WcaFetchWrappedReset(hUserQuery); | ||
| 42 | |||
| 43 | hr = WcaFetchWrappedRecordWhereString(hUserQuery, vuqUser, wzUser, &hRec); | ||
| 44 | if (S_OK == hr) | ||
| 45 | { | ||
| 46 | hr = WcaFetchWrappedRecordWhereString(hUserQuery, vuqUser, wzUser, &hRecTest); | ||
| 47 | if (S_OK == hr) | ||
| 48 | { | ||
| 49 | AssertSz(FALSE, "Found multiple matching User rows"); | ||
| 50 | } | ||
| 51 | |||
| 52 | hr = WcaGetRecordString(hRec, vuqUser, &pwzData); | ||
| 53 | ExitOnFailure(hr, "Failed to get User.User"); | ||
| 54 | hr = ::StringCchCopyW(pscau->wzKey, countof(pscau->wzKey), pwzData); | ||
| 55 | ExitOnFailure(hr, "Failed to copy key string to user object (in deferred CA)"); | ||
| 56 | |||
| 57 | hr = WcaGetRecordString(hRec, vuqComponent, &pwzData); | ||
| 58 | ExitOnFailure(hr, "Failed to get User.Component_"); | ||
| 59 | hr = ::StringCchCopyW(pscau->wzComponent, countof(pscau->wzComponent), pwzData); | ||
| 60 | ExitOnFailure(hr, "Failed to copy component string to user object (in deferred CA)"); | ||
| 61 | |||
| 62 | hr = WcaGetRecordString(hRec, vuqName, &pwzData); | ||
| 63 | ExitOnFailure(hr, "Failed to get User.Name"); | ||
| 64 | hr = ::StringCchCopyW(pscau->wzName, countof(pscau->wzName), pwzData); | ||
| 65 | ExitOnFailure(hr, "Failed to copy name string to user object (in deferred CA)"); | ||
| 66 | |||
| 67 | hr = WcaGetRecordString(hRec, vuqDomain, &pwzData); | ||
| 68 | ExitOnFailure(hr, "Failed to get User.Domain"); | ||
| 69 | hr = ::StringCchCopyW(pscau->wzDomain, countof(pscau->wzDomain), pwzData); | ||
| 70 | ExitOnFailure(hr, "Failed to copy domain string to user object (in deferred CA)"); | ||
| 71 | |||
| 72 | hr = WcaGetRecordString(hRec, vuqPassword, &pwzData); | ||
| 73 | ExitOnFailure(hr, "Failed to get User.Password"); | ||
| 74 | hr = ::StringCchCopyW(pscau->wzPassword, countof(pscau->wzPassword), pwzData); | ||
| 75 | ExitOnFailure(hr, "Failed to copy password string to user object (in deferred CA)"); | ||
| 76 | } | ||
| 77 | else if (E_NOMOREITEMS == hr) | ||
| 78 | { | ||
| 79 | WcaLog(LOGMSG_STANDARD, "Error: Cannot locate User.User='%ls'", wzUser); | ||
| 80 | hr = E_FAIL; | ||
| 81 | } | ||
| 82 | else | ||
| 83 | { | ||
| 84 | ExitOnFailure(hr, "Error fetching single User row"); | ||
| 85 | } | ||
| 86 | |||
| 87 | LExit: | ||
| 88 | ReleaseStr(pwzData); | ||
| 89 | |||
| 90 | return hr; | ||
| 91 | } | ||
diff --git a/src/ca/scauser.h b/src/ca/scauser.h new file mode 100644 index 00000000..b2b94650 --- /dev/null +++ b/src/ca/scauser.h | |||
| @@ -0,0 +1,39 @@ | |||
| 1 | #pragma once | ||
| 2 | // 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. | ||
| 3 | |||
| 4 | // structs | ||
| 5 | struct SCA_GROUP | ||
| 6 | { | ||
| 7 | WCHAR wzKey[MAX_DARWIN_KEY + 1]; | ||
| 8 | WCHAR wzComponent[MAX_DARWIN_KEY + 1]; | ||
| 9 | |||
| 10 | WCHAR wzDomain[MAX_DARWIN_COLUMN + 1]; | ||
| 11 | WCHAR wzName[MAX_DARWIN_COLUMN + 1]; | ||
| 12 | |||
| 13 | SCA_GROUP *psgNext; | ||
| 14 | }; | ||
| 15 | |||
| 16 | struct SCA_USER | ||
| 17 | { | ||
| 18 | WCHAR wzKey[MAX_DARWIN_KEY + 1]; | ||
| 19 | WCHAR wzComponent[MAX_DARWIN_KEY + 1]; | ||
| 20 | INSTALLSTATE isInstalled; | ||
| 21 | INSTALLSTATE isAction; | ||
| 22 | |||
| 23 | WCHAR wzDomain[MAX_DARWIN_COLUMN + 1]; | ||
| 24 | WCHAR wzName[MAX_DARWIN_COLUMN + 1]; | ||
| 25 | WCHAR wzPassword[MAX_DARWIN_COLUMN + 1]; | ||
| 26 | INT iAttributes; | ||
| 27 | |||
| 28 | SCA_GROUP *psgGroups; | ||
| 29 | |||
| 30 | SCA_USER *psuNext; | ||
| 31 | }; | ||
| 32 | |||
| 33 | |||
| 34 | // prototypes | ||
| 35 | HRESULT __stdcall ScaGetUserDeferred( | ||
| 36 | __in LPCWSTR wzUser, | ||
| 37 | __in WCA_WRAPQUERY_HANDLE hUserQuery, | ||
| 38 | __out SCA_USER* pscau | ||
| 39 | ); | ||
diff --git a/src/ca/scavdir.cpp b/src/ca/scavdir.cpp new file mode 100644 index 00000000..d388ce97 --- /dev/null +++ b/src/ca/scavdir.cpp | |||
| @@ -0,0 +1,331 @@ | |||
| 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 | #include "precomp.h" | ||
| 4 | |||
| 5 | // prototypes | ||
| 6 | static HRESULT AddVirtualDirToList( | ||
| 7 | __in SCA_VDIR** psvdList | ||
| 8 | ); | ||
| 9 | |||
| 10 | |||
| 11 | HRESULT __stdcall ScaVirtualDirsRead( | ||
| 12 | __in IMSAdminBase* piMetabase, | ||
| 13 | __in SCA_WEB* pswList, | ||
| 14 | __in SCA_VDIR** ppsvdList, | ||
| 15 | __in SCA_MIMEMAP** ppsmmList, | ||
| 16 | __in SCA_HTTP_HEADER** ppshhList, | ||
| 17 | __in SCA_WEB_ERROR** ppsweList, | ||
| 18 | __in WCA_WRAPQUERY_HANDLE hUserQuery, | ||
| 19 | __in WCA_WRAPQUERY_HANDLE hWebBaseQuery, | ||
| 20 | __in WCA_WRAPQUERY_HANDLE hWebDirPropQuery, | ||
| 21 | __in WCA_WRAPQUERY_HANDLE hWebAppQuery, | ||
| 22 | __in WCA_WRAPQUERY_HANDLE hWebAppExtQuery, | ||
| 23 | __inout LPWSTR *ppwzCustomActionData | ||
| 24 | ) | ||
| 25 | { | ||
| 26 | Assert(piMetabase && ppsvdList); | ||
| 27 | |||
| 28 | HRESULT hr = S_OK; | ||
| 29 | MSIHANDLE hRec; | ||
| 30 | INSTALLSTATE isInstalled = INSTALLSTATE_UNKNOWN; | ||
| 31 | INSTALLSTATE isAction = INSTALLSTATE_UNKNOWN; | ||
| 32 | |||
| 33 | SCA_VDIR* pvdir = NULL; | ||
| 34 | LPWSTR pwzData = NULL; | ||
| 35 | |||
| 36 | WCA_WRAPQUERY_HANDLE hWrapQuery = NULL; | ||
| 37 | |||
| 38 | hr = WcaBeginUnwrapQuery(&hWrapQuery, ppwzCustomActionData); | ||
| 39 | ExitOnFailure(hr, "Failed to unwrap query for ScaAppPoolRead"); | ||
| 40 | |||
| 41 | if (0 == WcaGetQueryRecords(hWrapQuery)) | ||
| 42 | { | ||
| 43 | WcaLog(LOGMSG_VERBOSE, "Skipping ScaVirtualDirsRead() because IIsWebVirtualDir table not present"); | ||
| 44 | ExitFunction1(hr = S_FALSE); | ||
| 45 | } | ||
| 46 | |||
| 47 | // loop through all the vdirs | ||
| 48 | while (S_OK == (hr = WcaFetchWrappedRecord(hWrapQuery, &hRec))) | ||
| 49 | { | ||
| 50 | // Get the Component first. If there is a Component and it is not being modified during | ||
| 51 | // this transaction, skip processing this whole record. | ||
| 52 | hr = WcaGetRecordString(hRec, vdqComponent, &pwzData); | ||
| 53 | ExitOnFailure(hr, "failed to get IIsWebVirtualDir.Component"); | ||
| 54 | |||
| 55 | hr = WcaGetRecordInteger(hRec, vdqInstalled, (int *)&isInstalled); | ||
| 56 | ExitOnFailure(hr, "Failed to get Component installed state for virtual dir"); | ||
| 57 | |||
| 58 | hr = WcaGetRecordInteger(hRec, vdqAction, (int *)&isAction); | ||
| 59 | ExitOnFailure(hr, "Failed to get Component action state for virtual dir"); | ||
| 60 | |||
| 61 | if (!WcaIsInstalling(isInstalled, isAction) && | ||
| 62 | !WcaIsReInstalling(isInstalled, isAction) && | ||
| 63 | !WcaIsUninstalling(isInstalled, isAction)) | ||
| 64 | { | ||
| 65 | continue; // skip this record. | ||
| 66 | } | ||
| 67 | |||
| 68 | hr = AddVirtualDirToList(ppsvdList); | ||
| 69 | ExitOnFailure(hr, "failed to add virtual dir to list"); | ||
| 70 | |||
| 71 | pvdir = *ppsvdList; | ||
| 72 | |||
| 73 | hr = ::StringCchCopyW(pvdir->wzComponent, countof(pvdir->wzComponent), pwzData); | ||
| 74 | ExitOnFailure(hr, "failed to copy component name: %ls", pwzData); | ||
| 75 | |||
| 76 | pvdir->isInstalled = isInstalled; | ||
| 77 | pvdir->isAction = isAction; | ||
| 78 | |||
| 79 | // get the web key | ||
| 80 | hr = WcaGetRecordString(hRec, vdqWeb, &pwzData); | ||
| 81 | ExitOnFailure(hr, "Failed to get Web for VirtualDir"); | ||
| 82 | |||
| 83 | hr = ScaWebsGetBase(piMetabase, pswList, pwzData, pvdir->wzWebBase, countof(pvdir->wzWebBase), hWebBaseQuery); | ||
| 84 | if (WcaIsUninstalling(isInstalled, isAction)) | ||
| 85 | { | ||
| 86 | // If we're uninstalling, ignore any failure to find the existing web | ||
| 87 | hr = S_OK; | ||
| 88 | } | ||
| 89 | ExitOnFailure(hr, "Failed to get base of web: %ls for VirtualDir", pwzData); | ||
| 90 | |||
| 91 | hr = WcaGetRecordString(hRec, vdqAlias, &pwzData); | ||
| 92 | ExitOnFailure(hr, "Failed to get Alias for VirtualDir"); | ||
| 93 | |||
| 94 | if (0 != lstrlenW(pvdir->wzWebBase)) | ||
| 95 | { | ||
| 96 | hr = ::StringCchPrintfW(pvdir->wzVDirRoot, countof(pvdir->wzVDirRoot), L"%s/Root/%s", pvdir->wzWebBase, pwzData); | ||
| 97 | ExitOnFailure(hr, "Failed to set VDirRoot for VirtualDir"); | ||
| 98 | } | ||
| 99 | |||
| 100 | // get the vdir's directory | ||
| 101 | hr = WcaGetRecordString(hRec, vdqDirectory, &pwzData); | ||
| 102 | ExitOnFailure(hr, "Failed to get Directory for VirtualDir"); | ||
| 103 | |||
| 104 | // get the web's directory | ||
| 105 | if (INSTALLSTATE_SOURCE == pvdir->isAction) | ||
| 106 | { | ||
| 107 | hr = WcaGetRecordString(hRec, vdqSourcePath, &pwzData); | ||
| 108 | } | ||
| 109 | else | ||
| 110 | { | ||
| 111 | hr = WcaGetRecordString(hRec, vdqTargetPath, &pwzData); | ||
| 112 | } | ||
| 113 | ExitOnFailure(hr, "Failed to get Source/TargetPath for Directory"); | ||
| 114 | |||
| 115 | // remove trailing backslash(es) | ||
| 116 | while (lstrlenW(pwzData) > 0 && pwzData[lstrlenW(pwzData)-1] == L'\\') | ||
| 117 | { | ||
| 118 | pwzData[lstrlenW(pwzData)-1] = 0; | ||
| 119 | } | ||
| 120 | hr = ::StringCchCopyW(pvdir->wzDirectory, countof(pvdir->wzDirectory), pwzData); | ||
| 121 | ExitOnFailure(hr, "Failed to copy directory string to vdir object"); | ||
| 122 | |||
| 123 | // get the security information for this web | ||
| 124 | hr = WcaGetRecordString(hRec, vdqProperties, &pwzData); | ||
| 125 | ExitOnFailure(hr, "Failed to get web directory identifier for VirtualDir"); | ||
| 126 | if (*pwzData) | ||
| 127 | { | ||
| 128 | hr = ScaGetWebDirProperties(pwzData, hUserQuery, hWebDirPropQuery, &pvdir->swp); | ||
| 129 | ExitOnFailure(hr, "Failed to get web directory for VirtualDir"); | ||
| 130 | |||
| 131 | pvdir->fHasProperties = TRUE; | ||
| 132 | } | ||
| 133 | |||
| 134 | // get the application information for this web | ||
| 135 | hr = WcaGetRecordString(hRec, vdqApplication, &pwzData); | ||
| 136 | ExitOnFailure(hr, "Failed to get application identifier for VirtualDir"); | ||
| 137 | if (*pwzData) | ||
| 138 | { | ||
| 139 | hr = ScaGetWebApplication(NULL, pwzData, hWebAppQuery, hWebAppExtQuery, &pvdir->swapp); | ||
| 140 | ExitOnFailure(hr, "Failed to get application for VirtualDir"); | ||
| 141 | |||
| 142 | pvdir->fHasApplication = TRUE; | ||
| 143 | } | ||
| 144 | |||
| 145 | hr = WcaGetRecordString(hRec, vdqVDir, &pwzData); | ||
| 146 | ExitOnFailure(hr, "Failed to get VDir for VirtualDir"); | ||
| 147 | |||
| 148 | if (*pwzData && *ppsmmList) | ||
| 149 | { | ||
| 150 | hr = ScaGetMimeMap(mmptVDir, pwzData, ppsmmList, &pvdir->psmm); | ||
| 151 | ExitOnFailure(hr, "Failed to get mimemap for VirtualDir"); | ||
| 152 | } | ||
| 153 | |||
| 154 | if (*pwzData && *ppshhList) | ||
| 155 | { | ||
| 156 | hr = ScaGetHttpHeader(hhptVDir, pwzData, ppshhList, &pvdir->pshh); | ||
| 157 | ExitOnFailure(hr, "Failed to get custom HTTP headers for VirtualDir: %ls", pwzData); | ||
| 158 | } | ||
| 159 | |||
| 160 | if (*pwzData && *ppsweList) | ||
| 161 | { | ||
| 162 | hr = ScaGetWebError(weptVDir, pwzData, ppsweList, &pvdir->pswe); | ||
| 163 | ExitOnFailure(hr, "Failed to get custom web errors for VirtualDir: %ls", pwzData); | ||
| 164 | } | ||
| 165 | } | ||
| 166 | |||
| 167 | if (E_NOMOREITEMS == hr) | ||
| 168 | { | ||
| 169 | hr = S_OK; | ||
| 170 | } | ||
| 171 | ExitOnFailure(hr, "Failure while processing VirtualDirs"); | ||
| 172 | |||
| 173 | LExit: | ||
| 174 | WcaFinishUnwrapQuery(hWrapQuery); | ||
| 175 | |||
| 176 | ReleaseStr(pwzData); | ||
| 177 | return hr; | ||
| 178 | } | ||
| 179 | |||
| 180 | |||
| 181 | HRESULT ScaVirtualDirsInstall( | ||
| 182 | __in IMSAdminBase* piMetabase, | ||
| 183 | __in SCA_VDIR* psvdList, | ||
| 184 | __in SCA_APPPOOL * psapList | ||
| 185 | ) | ||
| 186 | { | ||
| 187 | Assert(piMetabase); | ||
| 188 | |||
| 189 | HRESULT hr = S_OK; | ||
| 190 | SCA_VDIR* psvd = psvdList; | ||
| 191 | int i; | ||
| 192 | |||
| 193 | while (psvd) | ||
| 194 | { | ||
| 195 | // On reinstall, we have to uninstall the old application, otherwise a duplicate will be created | ||
| 196 | if (WcaIsReInstalling(psvd->isInstalled, psvd->isAction)) | ||
| 197 | { | ||
| 198 | if (psvd->fHasApplication) | ||
| 199 | { | ||
| 200 | hr = ScaDeleteApp(piMetabase, psvd->wzVDirRoot); | ||
| 201 | ExitOnFailure(hr, "Failed to remove application for WebVDir as part of a reinstall"); | ||
| 202 | } | ||
| 203 | } | ||
| 204 | |||
| 205 | if (WcaIsInstalling(psvd->isInstalled, psvd->isAction)) | ||
| 206 | { | ||
| 207 | hr = ScaCreateMetabaseKey(piMetabase, psvd->wzVDirRoot, L""); | ||
| 208 | ExitOnFailure(hr, "Failed to create key for VirtualDir"); | ||
| 209 | hr = ScaWriteMetabaseValue(piMetabase, psvd->wzVDirRoot, L"", MD_KEY_TYPE, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, (LPVOID)L"IIsWebVirtualDir"); | ||
| 210 | ExitOnFailure(hr, "Failed to write key type for for VirtualDir"); | ||
| 211 | i = 0x4000003e; // 1073741886; // default directory browsing rights | ||
| 212 | hr = ScaWriteMetabaseValue(piMetabase, psvd->wzVDirRoot, L"", MD_DIRECTORY_BROWSING, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, (LPVOID)((DWORD_PTR)i)); | ||
| 213 | ExitOnFailure(hr, "Failed to set directory browsing for VirtualDir"); | ||
| 214 | |||
| 215 | hr = ScaWriteMetabaseValue(piMetabase, psvd->wzVDirRoot, L"", MD_VR_PATH, METADATA_INHERIT, IIS_MD_UT_FILE, STRING_METADATA, (LPVOID)psvd->wzDirectory); | ||
| 216 | ExitOnFailure(hr, "Failed to write Directory for VirtualDir"); | ||
| 217 | |||
| 218 | if (psvd->fHasProperties) | ||
| 219 | { | ||
| 220 | ScaWriteWebDirProperties(piMetabase, psvd->wzVDirRoot, &psvd->swp); | ||
| 221 | ExitOnFailure(hr, "Failed to write directory properties for VirtualDir"); | ||
| 222 | } | ||
| 223 | |||
| 224 | if (psvd->fHasApplication) | ||
| 225 | { | ||
| 226 | hr = ScaWriteWebApplication(piMetabase, psvd->wzVDirRoot, &psvd->swapp, psapList); | ||
| 227 | ExitOnFailure(hr, "Failed to write application for VirtualDir"); | ||
| 228 | } | ||
| 229 | |||
| 230 | if (psvd->psmm) | ||
| 231 | { | ||
| 232 | hr = ScaWriteMimeMap(piMetabase, psvd->wzVDirRoot, psvd->psmm); | ||
| 233 | ExitOnFailure(hr, "Failed to write mimemap for VirtualDir"); | ||
| 234 | } | ||
| 235 | |||
| 236 | if (psvd->pshh) | ||
| 237 | { | ||
| 238 | hr = ScaWriteHttpHeader(piMetabase, psvd->wzVDirRoot, psvd->pshh); | ||
| 239 | ExitOnFailure(hr, "Failed to write custom HTTP headers for VirtualDir"); | ||
| 240 | } | ||
| 241 | |||
| 242 | if (psvd->pswe) | ||
| 243 | { | ||
| 244 | hr = ScaWriteWebError(piMetabase, weptVDir, psvd->wzVDirRoot, psvd->pswe); | ||
| 245 | ExitOnFailure(hr, "Failed to write custom web errors for VirtualDir"); | ||
| 246 | } | ||
| 247 | } | ||
| 248 | |||
| 249 | psvd = psvd->psvdNext; | ||
| 250 | } | ||
| 251 | |||
| 252 | LExit: | ||
| 253 | return hr; | ||
| 254 | } | ||
| 255 | |||
| 256 | |||
| 257 | HRESULT ScaVirtualDirsUninstall( | ||
| 258 | __in IMSAdminBase* piMetabase, | ||
| 259 | __in SCA_VDIR* psvdList | ||
| 260 | ) | ||
| 261 | { | ||
| 262 | Assert(piMetabase); | ||
| 263 | |||
| 264 | HRESULT hr = S_OK; | ||
| 265 | SCA_VDIR* psvd = psvdList; | ||
| 266 | |||
| 267 | while (psvd) | ||
| 268 | { | ||
| 269 | if (WcaIsUninstalling(psvd->isInstalled, psvd->isAction)) | ||
| 270 | { | ||
| 271 | // delete the application for this virtual directory | ||
| 272 | if (psvd->fHasApplication) | ||
| 273 | { | ||
| 274 | hr = ScaDeleteApp(piMetabase, psvd->wzVDirRoot); | ||
| 275 | ExitOnFailure(hr, "Failed to remove application for WebVDir"); | ||
| 276 | } | ||
| 277 | |||
| 278 | if (0 != lstrlenW(psvd->wzVDirRoot)) | ||
| 279 | { | ||
| 280 | hr = ScaDeleteMetabaseKey(piMetabase, psvd->wzVDirRoot, L""); | ||
| 281 | ExitOnFailure(hr, "Failed to remove VirtualDir '%ls' from metabase", psvd->wzKey); | ||
| 282 | } | ||
| 283 | } | ||
| 284 | |||
| 285 | psvd = psvd->psvdNext; | ||
| 286 | } | ||
| 287 | |||
| 288 | LExit: | ||
| 289 | return hr; | ||
| 290 | } | ||
| 291 | |||
| 292 | |||
| 293 | void ScaVirtualDirsFreeList( | ||
| 294 | __in SCA_VDIR* psvdList | ||
| 295 | ) | ||
| 296 | { | ||
| 297 | SCA_VDIR* psvdDelete = psvdList; | ||
| 298 | while (psvdList) | ||
| 299 | { | ||
| 300 | psvdDelete = psvdList; | ||
| 301 | psvdList = psvdList->psvdNext; | ||
| 302 | |||
| 303 | if (psvdDelete->psmm) | ||
| 304 | { | ||
| 305 | ScaMimeMapFreeList(psvdDelete->psmm); | ||
| 306 | } | ||
| 307 | |||
| 308 | if (psvdDelete->pswe) | ||
| 309 | { | ||
| 310 | ScaWebErrorFreeList(psvdDelete->pswe); | ||
| 311 | } | ||
| 312 | |||
| 313 | MemFree(psvdDelete); | ||
| 314 | } | ||
| 315 | } | ||
| 316 | |||
| 317 | |||
| 318 | static HRESULT AddVirtualDirToList( | ||
| 319 | __in SCA_VDIR** ppsvdList | ||
| 320 | ) | ||
| 321 | { | ||
| 322 | HRESULT hr = S_OK; | ||
| 323 | SCA_VDIR* psvd = static_cast<SCA_VDIR*>(MemAlloc(sizeof(SCA_VDIR), TRUE)); | ||
| 324 | ExitOnNull(psvd, hr, E_OUTOFMEMORY, "failed to allocate memory for new vdir list element"); | ||
| 325 | |||
| 326 | psvd->psvdNext= *ppsvdList; | ||
| 327 | *ppsvdList = psvd; | ||
| 328 | |||
| 329 | LExit: | ||
| 330 | return hr; | ||
| 331 | } | ||
diff --git a/src/ca/scavdir.h b/src/ca/scavdir.h new file mode 100644 index 00000000..c7e9661b --- /dev/null +++ b/src/ca/scavdir.h | |||
| @@ -0,0 +1,71 @@ | |||
| 1 | #pragma once | ||
| 2 | // 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. | ||
| 3 | |||
| 4 | |||
| 5 | #include "scawebprop.h" | ||
| 6 | #include "scawebapp.h" | ||
| 7 | #include "scamimemap.h" | ||
| 8 | #include "scaapppool.h" | ||
| 9 | |||
| 10 | enum eVDirQuery { vdqWeb = 1, vdqVDir, vdqComponent , vdqAlias, vdqDirectory, vdqProperties, vdqApplication, vdqInstalled, vdqAction, vdqSourcePath, vdqTargetPath }; | ||
| 11 | |||
| 12 | struct SCA_VDIR | ||
| 13 | { | ||
| 14 | // darwin information | ||
| 15 | WCHAR wzKey[MAX_DARWIN_KEY + 1]; | ||
| 16 | WCHAR wzComponent[MAX_DARWIN_KEY + 1]; | ||
| 17 | INSTALLSTATE isInstalled; | ||
| 18 | INSTALLSTATE isAction; | ||
| 19 | |||
| 20 | // metabase information | ||
| 21 | WCHAR wzWebKey[MAX_DARWIN_KEY + 1]; | ||
| 22 | WCHAR wzWebBase[METADATA_MAX_NAME_LEN + 1]; | ||
| 23 | WCHAR wzVDirRoot[METADATA_MAX_NAME_LEN + 1]; | ||
| 24 | |||
| 25 | // iis configuation information | ||
| 26 | WCHAR wzDirectory[MAX_PATH]; | ||
| 27 | |||
| 28 | BOOL fHasProperties; | ||
| 29 | SCA_WEB_PROPERTIES swp; | ||
| 30 | |||
| 31 | BOOL fHasApplication; | ||
| 32 | SCA_WEB_APPLICATION swapp; | ||
| 33 | |||
| 34 | SCA_MIMEMAP* psmm; // mime mappings | ||
| 35 | SCA_HTTP_HEADER* pshh; // custom web errors | ||
| 36 | SCA_WEB_ERROR* pswe; // custom web errors | ||
| 37 | |||
| 38 | SCA_VDIR* psvdNext; | ||
| 39 | }; | ||
| 40 | |||
| 41 | |||
| 42 | // prototypes | ||
| 43 | HRESULT __stdcall ScaVirtualDirsRead( | ||
| 44 | __in IMSAdminBase* piMetabase, | ||
| 45 | __in SCA_WEB* pswList, | ||
| 46 | __in SCA_VDIR** ppsvdList, | ||
| 47 | __in SCA_MIMEMAP** ppsmmList, | ||
| 48 | __in SCA_HTTP_HEADER** ppshhList, | ||
| 49 | __in SCA_WEB_ERROR** ppsweList, | ||
| 50 | __in WCA_WRAPQUERY_HANDLE hUserQuery, | ||
| 51 | __in WCA_WRAPQUERY_HANDLE hWebBaseQuery, | ||
| 52 | __in WCA_WRAPQUERY_HANDLE hWebDirPropQuery, | ||
| 53 | __in WCA_WRAPQUERY_HANDLE hWebAppQuery, | ||
| 54 | __in WCA_WRAPQUERY_HANDLE hWebAppExtQuery, | ||
| 55 | __inout LPWSTR *ppwzCustomActionData | ||
| 56 | ); | ||
| 57 | |||
| 58 | HRESULT ScaVirtualDirsInstall( | ||
| 59 | __in IMSAdminBase* piMetabase, | ||
| 60 | __in SCA_VDIR* psvdList, | ||
| 61 | __in SCA_APPPOOL * psapList | ||
| 62 | ); | ||
| 63 | |||
| 64 | HRESULT ScaVirtualDirsUninstall( | ||
| 65 | __in IMSAdminBase* piMetabase, | ||
| 66 | __in SCA_VDIR* psvdList | ||
| 67 | ); | ||
| 68 | |||
| 69 | void ScaVirtualDirsFreeList( | ||
| 70 | __in SCA_VDIR* psvdList | ||
| 71 | ); | ||
diff --git a/src/ca/scavdir7.cpp b/src/ca/scavdir7.cpp new file mode 100644 index 00000000..3f675357 --- /dev/null +++ b/src/ca/scavdir7.cpp | |||
| @@ -0,0 +1,380 @@ | |||
| 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 | #include "precomp.h" | ||
| 4 | |||
| 5 | // prototypes | ||
| 6 | static HRESULT AddVirtualDirToList7( | ||
| 7 | __in SCA_VDIR7** psvdList | ||
| 8 | ); | ||
| 9 | |||
| 10 | |||
| 11 | HRESULT __stdcall ScaVirtualDirsRead7( | ||
| 12 | __in SCA_WEB7* pswList, | ||
| 13 | __in SCA_VDIR7** ppsvdList, | ||
| 14 | __in SCA_MIMEMAP** ppsmmList, | ||
| 15 | __in SCA_HTTP_HEADER** ppshhList, | ||
| 16 | __in SCA_WEB_ERROR** ppsweList, | ||
| 17 | __in WCA_WRAPQUERY_HANDLE hUserQuery, | ||
| 18 | __in WCA_WRAPQUERY_HANDLE /*hWebBaseQuery*/, | ||
| 19 | __in WCA_WRAPQUERY_HANDLE hWebDirPropQuery, | ||
| 20 | __in WCA_WRAPQUERY_HANDLE hWebAppQuery, | ||
| 21 | __in WCA_WRAPQUERY_HANDLE hWebAppExtQuery, | ||
| 22 | __inout LPWSTR *ppwzCustomActionData | ||
| 23 | ) | ||
| 24 | { | ||
| 25 | Assert(ppsvdList); | ||
| 26 | |||
| 27 | HRESULT hr = S_OK; | ||
| 28 | MSIHANDLE hRec; | ||
| 29 | |||
| 30 | SCA_VDIR7* pvdir = NULL; | ||
| 31 | LPWSTR pwzData = NULL; | ||
| 32 | WCA_WRAPQUERY_HANDLE hWrapQuery = NULL; | ||
| 33 | |||
| 34 | hr = WcaBeginUnwrapQuery(&hWrapQuery, ppwzCustomActionData); | ||
| 35 | ExitOnFailure(hr, "Failed to unwrap query for ScaAppPoolRead"); | ||
| 36 | |||
| 37 | if (0 == WcaGetQueryRecords(hWrapQuery)) | ||
| 38 | { | ||
| 39 | WcaLog(LOGMSG_VERBOSE, "Skipping ScaVirtualDirsRead() because IIsWebVirtualDir table not present"); | ||
| 40 | ExitFunction1(hr = S_FALSE); | ||
| 41 | } | ||
| 42 | |||
| 43 | // loop through all the vdirs | ||
| 44 | while (S_OK == (hr = WcaFetchWrappedRecord(hWrapQuery, &hRec))) | ||
| 45 | { | ||
| 46 | // Add this record's information into the list of things to process. | ||
| 47 | hr = AddVirtualDirToList7(ppsvdList); | ||
| 48 | ExitOnFailure(hr, "failed to add vdir to vdir list"); | ||
| 49 | |||
| 50 | pvdir = *ppsvdList; | ||
| 51 | |||
| 52 | // get the darwin information | ||
| 53 | hr = WcaGetRecordString(hRec, vdqComponent, &pwzData); | ||
| 54 | ExitOnFailure(hr, "failed to get IIsWebVirtualDir.Component"); | ||
| 55 | |||
| 56 | hr = WcaGetRecordInteger(hRec, vdqInstalled, (int *)&pvdir->isInstalled); | ||
| 57 | ExitOnFailure(hr, "Failed to get Component installed state for virtual dir"); | ||
| 58 | |||
| 59 | hr = WcaGetRecordInteger(hRec, vdqAction, (int *)&pvdir->isAction); | ||
| 60 | ExitOnFailure(hr, "Failed to get Component action state for virtual dir"); | ||
| 61 | |||
| 62 | // get vdir properties | ||
| 63 | hr = ::StringCchCopyW(pvdir->wzComponent, countof(pvdir->wzComponent), pwzData); | ||
| 64 | ExitOnFailure(hr, "failed to copy vdir component name: %ls", pwzData); | ||
| 65 | |||
| 66 | hr = WcaGetRecordString(hRec, vdqWeb, &pwzData); | ||
| 67 | ExitOnFailure(hr, "Failed to get Web for VirtualDir"); | ||
| 68 | |||
| 69 | hr = ScaWebsGetBase7(pswList, pwzData, pvdir->wzWebName , countof(pvdir->wzWebName)); | ||
| 70 | if (S_FALSE == hr) | ||
| 71 | { | ||
| 72 | hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND); | ||
| 73 | ExitOnFailure(hr, "Failed to get Web Base for VirtualDir"); | ||
| 74 | } | ||
| 75 | if (WcaIsUninstalling(pvdir->isInstalled, pvdir->isAction)) | ||
| 76 | { | ||
| 77 | // If we're uninstalling, ignore any failure to find the existing web | ||
| 78 | hr = S_OK; | ||
| 79 | } | ||
| 80 | |||
| 81 | hr = WcaGetRecordString(hRec, vdqAlias, &pwzData); | ||
| 82 | ExitOnFailure(hr, "Failed to get Alias for VirtualDir"); | ||
| 83 | |||
| 84 | hr = ::StringCchCopyW(pvdir->wzVDirRoot, countof(pvdir->wzVDirRoot), pwzData); | ||
| 85 | ExitOnFailure(hr, "Failed to set VDirRoot for VirtualDir"); | ||
| 86 | |||
| 87 | // get the vdir's directory | ||
| 88 | hr = WcaGetRecordString(hRec, vdqDirectory, &pwzData); | ||
| 89 | ExitOnFailure(hr, "Failed to get Directory for VirtualDir"); | ||
| 90 | |||
| 91 | // get the web's directory | ||
| 92 | if (INSTALLSTATE_SOURCE == pvdir->isAction) | ||
| 93 | { | ||
| 94 | hr = WcaGetRecordString(hRec, vdqSourcePath, &pwzData); | ||
| 95 | } | ||
| 96 | else | ||
| 97 | { | ||
| 98 | hr = WcaGetRecordString(hRec, vdqTargetPath, &pwzData); | ||
| 99 | } | ||
| 100 | ExitOnFailure(hr, "Failed to get Source/TargetPath for Directory"); | ||
| 101 | |||
| 102 | // remove trailing backslash(es) | ||
| 103 | while (lstrlenW(pwzData) > 0 && pwzData[lstrlenW(pwzData)-1] == L'\\') | ||
| 104 | { | ||
| 105 | pwzData[lstrlenW(pwzData)-1] = 0; | ||
| 106 | } | ||
| 107 | hr = ::StringCchCopyW(pvdir->wzDirectory, countof(pvdir->wzDirectory), pwzData); | ||
| 108 | ExitOnFailure(hr, "Failed to copy directory string to vdir object"); | ||
| 109 | |||
| 110 | // get the security information for this web | ||
| 111 | hr = WcaGetRecordString(hRec, vdqProperties, &pwzData); | ||
| 112 | ExitOnFailure(hr, "Failed to get web directory identifier for VirtualDir"); | ||
| 113 | if (*pwzData) | ||
| 114 | { | ||
| 115 | hr = ScaGetWebDirProperties(pwzData, hUserQuery, hWebDirPropQuery, &pvdir->swp); | ||
| 116 | ExitOnFailure(hr, "Failed to get web directory for VirtualDir"); | ||
| 117 | |||
| 118 | pvdir->fHasProperties = TRUE; | ||
| 119 | } | ||
| 120 | |||
| 121 | // get the application information for this web | ||
| 122 | hr = WcaGetRecordString(hRec, vdqApplication, &pwzData); | ||
| 123 | ExitOnFailure(hr, "Failed to get application identifier for VirtualDir"); | ||
| 124 | if (*pwzData) | ||
| 125 | { | ||
| 126 | hr = ScaGetWebApplication(NULL, pwzData, hWebAppQuery, hWebAppExtQuery, &pvdir->swapp); | ||
| 127 | ExitOnFailure(hr, "Failed to get application for VirtualDir"); | ||
| 128 | |||
| 129 | pvdir->fHasApplication = TRUE; | ||
| 130 | } | ||
| 131 | |||
| 132 | hr = WcaGetRecordString(hRec, vdqVDir, &pwzData); | ||
| 133 | ExitOnFailure(hr, "Failed to get VDir for VirtualDir"); | ||
| 134 | |||
| 135 | if (*pwzData && *ppsmmList) | ||
| 136 | { | ||
| 137 | hr = ScaGetMimeMap(mmptVDir, pwzData, ppsmmList, &pvdir->psmm); | ||
| 138 | ExitOnFailure(hr, "Failed to get mimemap for VirtualDir"); | ||
| 139 | } | ||
| 140 | |||
| 141 | if (*pwzData && *ppshhList) | ||
| 142 | { | ||
| 143 | hr = ScaGetHttpHeader(hhptVDir, pwzData, ppshhList, &pvdir->pshh); | ||
| 144 | ExitOnFailure(hr, "Failed to get custom HTTP headers for VirtualDir: %ls", pwzData); | ||
| 145 | } | ||
| 146 | |||
| 147 | if (*pwzData && *ppsweList) | ||
| 148 | { | ||
| 149 | hr = ScaGetWebError(weptVDir, pwzData, ppsweList, &pvdir->pswe); | ||
| 150 | ExitOnFailure(hr, "Failed to get custom web errors for VirtualDir: %ls", pwzData); | ||
| 151 | } | ||
| 152 | } | ||
| 153 | |||
| 154 | if (E_NOMOREITEMS == hr) | ||
| 155 | { | ||
| 156 | hr = S_OK; | ||
| 157 | } | ||
| 158 | ExitOnFailure(hr, "Failure while processing VirtualDirs"); | ||
| 159 | |||
| 160 | LExit: | ||
| 161 | WcaFinishUnwrapQuery(hWrapQuery); | ||
| 162 | |||
| 163 | ReleaseStr(pwzData); | ||
| 164 | |||
| 165 | return hr; | ||
| 166 | } | ||
| 167 | |||
| 168 | |||
| 169 | HRESULT ScaVirtualDirsInstall7( | ||
| 170 | __in SCA_VDIR7* psvdList, | ||
| 171 | __in SCA_APPPOOL * psapList | ||
| 172 | ) | ||
| 173 | { | ||
| 174 | HRESULT hr = S_OK; | ||
| 175 | SCA_VDIR7* psvd = psvdList; | ||
| 176 | LPWSTR wzPath = NULL; | ||
| 177 | WCHAR wzAppPoolName[MAX_PATH]; | ||
| 178 | while (psvd) | ||
| 179 | { | ||
| 180 | if (WcaIsInstalling(psvd->isInstalled, psvd->isAction)) | ||
| 181 | { | ||
| 182 | // First write all applications, this is necessary since vdirs must be nested under the applications. | ||
| 183 | if (psvd->fHasApplication) | ||
| 184 | { | ||
| 185 | //create the application for this vdir application | ||
| 186 | hr = ScaWriteConfigID(IIS_APPLICATION); | ||
| 187 | ExitOnFailure(hr, "Failed to write app ID"); | ||
| 188 | hr = ScaWriteConfigID(IIS_CREATE); | ||
| 189 | ExitOnFailure(hr, "Failed to write app action"); | ||
| 190 | #pragma prefast(suppress:26037, "Source string is null terminated - it is populated as target of ::StringCchCopyW") | ||
| 191 | hr = ScaWriteConfigString(psvd->wzWebName); //site name key | ||
| 192 | ExitOnFailure(hr, "Failed to write app web key"); | ||
| 193 | hr = StrAllocFormatted(&wzPath, L"/%s", psvd->wzVDirRoot); | ||
| 194 | ExitOnFailure(hr, "Failed to create app path"); | ||
| 195 | hr = ScaWriteConfigString(wzPath); // App Path | ||
| 196 | ExitOnFailure(hr, "Failed to write app path root "); | ||
| 197 | |||
| 198 | if (!*psvd->swapp.wzAppPool) | ||
| 199 | { | ||
| 200 | //This Application goes in default appPool | ||
| 201 | hr = ScaWriteConfigString(L""); // App Pool | ||
| 202 | } | ||
| 203 | else | ||
| 204 | { | ||
| 205 | //get apppool from WebApplication | ||
| 206 | #pragma prefast(suppress:26037, "Source string is null terminated - it is populated as target of ::StringCchCopyW") | ||
| 207 | hr = ScaFindAppPool7(psvd->swapp.wzAppPool, wzAppPoolName, countof(wzAppPoolName), psapList); | ||
| 208 | ExitOnFailure(hr, "Failed to read app pool from application"); | ||
| 209 | hr = ScaWriteConfigString(wzAppPoolName); // App Pool | ||
| 210 | ExitOnFailure(hr, "Failed to write appPool for vdir"); | ||
| 211 | |||
| 212 | } | ||
| 213 | } | ||
| 214 | } | ||
| 215 | |||
| 216 | psvd = psvd->psvdNext; | ||
| 217 | } | ||
| 218 | |||
| 219 | // Reset our linked list and write all the VDirs | ||
| 220 | psvd = psvdList; | ||
| 221 | while (psvd) | ||
| 222 | { | ||
| 223 | if (WcaIsInstalling(psvd->isInstalled, psvd->isAction)) | ||
| 224 | { | ||
| 225 | //create the Vdir | ||
| 226 | hr = ScaWriteConfigID(IIS_VDIR); | ||
| 227 | ExitOnFailure(hr, "Failed write VirDir ID") | ||
| 228 | hr = ScaWriteConfigID(IIS_CREATE); | ||
| 229 | ExitOnFailure(hr, "Failed write VirDir action") | ||
| 230 | #pragma prefast(suppress:26037, "Source string is null terminated - it is populated as target of ::StringCchCopyW") | ||
| 231 | hr = ScaWriteConfigString(psvd->wzWebName); //site name key | ||
| 232 | ExitOnFailure(hr, "Failed write VirDir web name"); | ||
| 233 | hr = StrAllocFormatted(&wzPath, L"/%s", psvd->wzVDirRoot); | ||
| 234 | ExitOnFailure(hr, "Failed to create vdir path"); | ||
| 235 | hr = ScaWriteConfigString(wzPath); //vdir path | ||
| 236 | ExitOnFailure(hr, "Failed write VirDir path") | ||
| 237 | #pragma prefast(suppress:26037, "Source string is null terminated - it is populated as target of ::StringCchCopyW") | ||
| 238 | hr = ScaWriteConfigString(psvd->wzDirectory); //physical dir | ||
| 239 | ExitOnFailure(hr, "Failed write VirDir dir"); | ||
| 240 | |||
| 241 | if (psvd->fHasProperties) | ||
| 242 | { | ||
| 243 | ScaWriteWebDirProperties7(psvd->wzWebName, psvd->wzVDirRoot, &psvd->swp); | ||
| 244 | ExitOnFailure(hr, "Failed to write directory properties for VirtualDir"); | ||
| 245 | } | ||
| 246 | |||
| 247 | if (psvd->fHasApplication) | ||
| 248 | { | ||
| 249 | hr = ScaWriteWebApplication7(psvd->wzWebName, psvd->wzVDirRoot, &psvd->swapp, psapList); | ||
| 250 | ExitOnFailure(hr, "Failed to write application for VirtualDir"); | ||
| 251 | } | ||
| 252 | |||
| 253 | if (psvd->psmm) | ||
| 254 | { | ||
| 255 | hr = ScaWriteMimeMap7(psvd->wzWebName, psvd->wzVDirRoot, psvd->psmm); | ||
| 256 | ExitOnFailure(hr, "Failed to write mimemap for VirtualDir"); | ||
| 257 | } | ||
| 258 | |||
| 259 | if (psvd->pshh) | ||
| 260 | { | ||
| 261 | hr = ScaWriteHttpHeader7(psvd->wzWebName, psvd->wzVDirRoot, psvd->pshh); | ||
| 262 | ExitOnFailure(hr, "Failed to write custom HTTP headers for VirtualDir"); | ||
| 263 | } | ||
| 264 | |||
| 265 | if (psvd->pswe) | ||
| 266 | { | ||
| 267 | hr = ScaWriteWebError7(psvd->wzWebName, psvd->wzVDirRoot, psvd->pswe); | ||
| 268 | ExitOnFailure(hr, "Failed to write custom web errors for VirtualDir"); | ||
| 269 | } | ||
| 270 | } | ||
| 271 | |||
| 272 | psvd = psvd->psvdNext; | ||
| 273 | } | ||
| 274 | |||
| 275 | LExit: | ||
| 276 | ReleaseStr(wzPath); | ||
| 277 | return hr; | ||
| 278 | } | ||
| 279 | |||
| 280 | |||
| 281 | HRESULT ScaVirtualDirsUninstall7( | ||
| 282 | __in SCA_VDIR7* psvdList | ||
| 283 | ) | ||
| 284 | { | ||
| 285 | |||
| 286 | HRESULT hr = S_OK; | ||
| 287 | SCA_VDIR7* psvd = psvdList; | ||
| 288 | LPWSTR wzPath = NULL; | ||
| 289 | |||
| 290 | while (psvd) | ||
| 291 | { | ||
| 292 | if (WcaIsUninstalling(psvd->isInstalled, psvd->isAction)) | ||
| 293 | { | ||
| 294 | //init path | ||
| 295 | hr = StrAllocFormatted(&wzPath, L"/%s", psvd->wzVDirRoot); | ||
| 296 | ExitOnFailure(hr, "Failed to create vdir path"); | ||
| 297 | |||
| 298 | if (psvd->fHasApplication) | ||
| 299 | { | ||
| 300 | //delete Application | ||
| 301 | hr = ScaWriteConfigID(IIS_APPLICATION); | ||
| 302 | ExitOnFailure(hr, "Failed to write app ID "); | ||
| 303 | hr = ScaWriteConfigID(IIS_DELETE); | ||
| 304 | ExitOnFailure(hr, "Failed to write delete app ID "); | ||
| 305 | #pragma prefast(suppress:26037, "Source string is null terminated - it is populated as target of ::StringCchCopyW") | ||
| 306 | hr = ScaWriteConfigString(psvd->wzWebName); //site name key | ||
| 307 | ExitOnFailure(hr, "Failed to write App site Name"); | ||
| 308 | #pragma prefast(suppress:26037, "Source string is null terminated - it is populated as target of ::StringCchCopyW") | ||
| 309 | hr = ScaWriteConfigString(wzPath); // App Path | ||
| 310 | ExitOnFailure(hr, "Failed to write app path root "); | ||
| 311 | hr = ScaWriteConfigString(L"NOP"); // App pool | ||
| 312 | ExitOnFailure(hr, "Failed to write app path app pool "); | ||
| 313 | } | ||
| 314 | else | ||
| 315 | { | ||
| 316 | //delete VDir | ||
| 317 | hr = ScaWriteConfigID(IIS_VDIR); | ||
| 318 | ExitOnFailure(hr, "Failed to write vDir ID "); | ||
| 319 | hr = ScaWriteConfigID(IIS_DELETE); | ||
| 320 | #pragma prefast(suppress:26037, "Source string is null terminated - it is populated as target of ::StringCchCopyW") | ||
| 321 | hr = ScaWriteConfigString(psvd->wzWebName); //site name key | ||
| 322 | ExitOnFailure(hr, "Failed to write App site Name"); | ||
| 323 | hr = ScaWriteConfigString(wzPath); // Vdir Path | ||
| 324 | ExitOnFailure(hr, "Failed to write app vdir "); | ||
| 325 | hr = ScaWriteConfigString(L"NOP"); // Phy Path | ||
| 326 | ExitOnFailure(hr, "Failed to write vdir path"); | ||
| 327 | } | ||
| 328 | |||
| 329 | ExitOnFailure(hr, "Failed to remove VirtualDir '%ls' from config", psvd->wzKey); | ||
| 330 | } | ||
| 331 | |||
| 332 | psvd = psvd->psvdNext; | ||
| 333 | } | ||
| 334 | |||
| 335 | LExit: | ||
| 336 | ReleaseStr(wzPath); | ||
| 337 | return hr; | ||
| 338 | } | ||
| 339 | |||
| 340 | |||
| 341 | void ScaVirtualDirsFreeList7( | ||
| 342 | __in SCA_VDIR7* psvdList | ||
| 343 | ) | ||
| 344 | { | ||
| 345 | SCA_VDIR7* psvdDelete = psvdList; | ||
| 346 | while (psvdList) | ||
| 347 | { | ||
| 348 | psvdDelete = psvdList; | ||
| 349 | psvdList = psvdList->psvdNext; | ||
| 350 | |||
| 351 | if (psvdDelete->psmm) | ||
| 352 | { | ||
| 353 | ScaMimeMapFreeList(psvdDelete->psmm); | ||
| 354 | } | ||
| 355 | |||
| 356 | if (psvdDelete->pswe) | ||
| 357 | { | ||
| 358 | ScaWebErrorFreeList(psvdDelete->pswe); | ||
| 359 | } | ||
| 360 | |||
| 361 | MemFree(psvdDelete); | ||
| 362 | } | ||
| 363 | } | ||
| 364 | |||
| 365 | |||
| 366 | static HRESULT AddVirtualDirToList7( | ||
| 367 | __in SCA_VDIR7** ppsvdList | ||
| 368 | ) | ||
| 369 | { | ||
| 370 | HRESULT hr = S_OK; | ||
| 371 | |||
| 372 | SCA_VDIR7* psvd = static_cast<SCA_VDIR7*>(MemAlloc(sizeof(SCA_VDIR7), TRUE)); | ||
| 373 | ExitOnNull(psvd, hr, E_OUTOFMEMORY, "failed to allocate memory for new vdir list element"); | ||
| 374 | |||
| 375 | psvd->psvdNext= *ppsvdList; | ||
| 376 | *ppsvdList = psvd; | ||
| 377 | |||
| 378 | LExit: | ||
| 379 | return hr; | ||
| 380 | } | ||
diff --git a/src/ca/scavdir7.h b/src/ca/scavdir7.h new file mode 100644 index 00000000..dba25431 --- /dev/null +++ b/src/ca/scavdir7.h | |||
| @@ -0,0 +1,66 @@ | |||
| 1 | #pragma once | ||
| 2 | // 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. | ||
| 3 | |||
| 4 | |||
| 5 | #include "scawebprop.h" | ||
| 6 | #include "scawebapp.h" | ||
| 7 | #include "scamimemap.h" | ||
| 8 | #include "scaapppool.h" | ||
| 9 | |||
| 10 | struct SCA_VDIR7 | ||
| 11 | { | ||
| 12 | // darwin information | ||
| 13 | WCHAR wzKey[MAX_DARWIN_KEY + 1]; | ||
| 14 | WCHAR wzComponent[MAX_DARWIN_KEY + 1]; | ||
| 15 | INSTALLSTATE isInstalled; | ||
| 16 | INSTALLSTATE isAction; | ||
| 17 | |||
| 18 | // metabase information | ||
| 19 | WCHAR wzWebKey[MAX_DARWIN_KEY + 1]; | ||
| 20 | WCHAR wzWebName[METADATA_MAX_NAME_LEN + 1]; | ||
| 21 | WCHAR wzVDirRoot[METADATA_MAX_NAME_LEN + 1]; | ||
| 22 | |||
| 23 | // iis configuation information | ||
| 24 | WCHAR wzDirectory[MAX_PATH]; | ||
| 25 | |||
| 26 | BOOL fHasProperties; | ||
| 27 | SCA_WEB_PROPERTIES swp; | ||
| 28 | |||
| 29 | BOOL fHasApplication; | ||
| 30 | SCA_WEB_APPLICATION swapp; | ||
| 31 | |||
| 32 | SCA_MIMEMAP* psmm; // mime mappings | ||
| 33 | SCA_HTTP_HEADER* pshh; // custom web errors | ||
| 34 | SCA_WEB_ERROR* pswe; // custom web errors | ||
| 35 | |||
| 36 | SCA_VDIR7* psvdNext; | ||
| 37 | }; | ||
| 38 | |||
| 39 | |||
| 40 | // prototypes | ||
| 41 | HRESULT __stdcall ScaVirtualDirsRead7( | ||
| 42 | __in SCA_WEB7* pswList, | ||
| 43 | __in SCA_VDIR7** ppsvdList, | ||
| 44 | __in SCA_MIMEMAP** ppsmmList, | ||
| 45 | __in SCA_HTTP_HEADER** ppshhList, | ||
| 46 | __in SCA_WEB_ERROR** ppsweList, | ||
| 47 | __in WCA_WRAPQUERY_HANDLE hUserQuery, | ||
| 48 | __in WCA_WRAPQUERY_HANDLE hWebBaseQuery, | ||
| 49 | __in WCA_WRAPQUERY_HANDLE hWebDirPropQuery, | ||
| 50 | __in WCA_WRAPQUERY_HANDLE hWebAppQuery, | ||
| 51 | __in WCA_WRAPQUERY_HANDLE hWebAppExtQuery, | ||
| 52 | __inout LPWSTR *ppwzCustomActionData | ||
| 53 | ); | ||
| 54 | |||
| 55 | HRESULT ScaVirtualDirsInstall7( | ||
| 56 | __in SCA_VDIR7* psvdList, | ||
| 57 | __in SCA_APPPOOL * psapList | ||
| 58 | ); | ||
| 59 | |||
| 60 | HRESULT ScaVirtualDirsUninstall7( | ||
| 61 | __in SCA_VDIR7* psvdList | ||
| 62 | ); | ||
| 63 | |||
| 64 | void ScaVirtualDirsFreeList7( | ||
| 65 | __in SCA_VDIR7* psvdList | ||
| 66 | ); | ||
diff --git a/src/ca/scaweb.cpp b/src/ca/scaweb.cpp new file mode 100644 index 00000000..0452fb0b --- /dev/null +++ b/src/ca/scaweb.cpp | |||
| @@ -0,0 +1,1187 @@ | |||
| 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 | #include "precomp.h" | ||
| 4 | |||
| 5 | //Adding this because delivery doesn't have the updated specstrings.h that windows build does | ||
| 6 | #ifndef __in_xcount | ||
| 7 | #define __in_xcount(size) | ||
| 8 | #endif | ||
| 9 | |||
| 10 | // sql queries | ||
| 11 | |||
| 12 | enum eWebBaseQuery { wbqWeb = 1, wbqId, wbqIP, wbqPort, wbqHeader, wbqSecure, wbqDescription }; | ||
| 13 | |||
| 14 | |||
| 15 | // prototypes for private helper functions | ||
| 16 | static SCA_WEB* NewWeb(); | ||
| 17 | static void FreeWeb(SCA_WEB *pswDelete); | ||
| 18 | static SCA_WEB* AddWebToList( | ||
| 19 | __in SCA_WEB* pswList, | ||
| 20 | __in SCA_WEB* psw | ||
| 21 | ); | ||
| 22 | static HRESULT ScaWebFindBase( | ||
| 23 | __in IMSAdminBase* piMetabase, | ||
| 24 | __in SCA_WEB* pswList, | ||
| 25 | __in_z LPCWSTR wzWeb, | ||
| 26 | __in int iSiteId, | ||
| 27 | __in_z LPCWSTR wzIP, | ||
| 28 | __in int iPort, | ||
| 29 | __in_z LPCWSTR wzHeader, | ||
| 30 | __in BOOL fSecure, | ||
| 31 | __in_z LPCWSTR wzDescription, | ||
| 32 | __out_ecount(cchWebBase) LPWSTR wzWebBase, | ||
| 33 | __in DWORD cchWebBase | ||
| 34 | ); | ||
| 35 | static HRESULT ScaWebFindFreeBase( | ||
| 36 | __in IMSAdminBase* piMetabase, | ||
| 37 | __in_xcount(unknown) SCA_WEB* pswList, | ||
| 38 | __in int iSiteId, | ||
| 39 | __in_z LPCWSTR wzDescription, | ||
| 40 | __out_ecount(cchWebBase) LPWSTR wzWebBase, | ||
| 41 | __in DWORD cchWebBase | ||
| 42 | ); | ||
| 43 | static HRESULT ScaWebWrite( | ||
| 44 | __in IMSAdminBase* piMetabase, | ||
| 45 | __in SCA_WEB* psw, | ||
| 46 | __in SCA_APPPOOL * psapList | ||
| 47 | ); | ||
| 48 | static HRESULT ScaWebRemove( | ||
| 49 | __in IMSAdminBase* piMetabase, | ||
| 50 | __in const SCA_WEB* psw); | ||
| 51 | static DWORD SiteIdFromDescription( | ||
| 52 | __in_z LPCWSTR wzDescription | ||
| 53 | ); | ||
| 54 | static void Sort( | ||
| 55 | __in_ecount(cArray) DWORD dwArray[], | ||
| 56 | __in int cArray | ||
| 57 | ); | ||
| 58 | |||
| 59 | |||
| 60 | HRESULT ScaWebsRead( | ||
| 61 | __in IMSAdminBase* piMetabase, | ||
| 62 | __in SCA_MIMEMAP** ppsmmList, | ||
| 63 | __in SCA_WEB** ppswList, | ||
| 64 | __in SCA_HTTP_HEADER** ppshhList, | ||
| 65 | __in SCA_WEB_ERROR** ppsweList, | ||
| 66 | __in WCA_WRAPQUERY_HANDLE hUserQuery, | ||
| 67 | __in WCA_WRAPQUERY_HANDLE hWebDirPropQuery, | ||
| 68 | __in WCA_WRAPQUERY_HANDLE hSslCertQuery, | ||
| 69 | __in WCA_WRAPQUERY_HANDLE hWebLogQuery, | ||
| 70 | __in WCA_WRAPQUERY_HANDLE hWebAppQuery, | ||
| 71 | __in WCA_WRAPQUERY_HANDLE hWebAppExtQuery, | ||
| 72 | __inout LPWSTR *ppwzCustomActionData | ||
| 73 | ) | ||
| 74 | { | ||
| 75 | Assert(piMetabase && ppswList); | ||
| 76 | |||
| 77 | HRESULT hr = S_OK; | ||
| 78 | |||
| 79 | MSIHANDLE hRec; | ||
| 80 | MSIHANDLE hRecAddresses; | ||
| 81 | |||
| 82 | SCA_WEB* psw = NULL; | ||
| 83 | LPWSTR pwzData = NULL; | ||
| 84 | int iSiteId; | ||
| 85 | |||
| 86 | DWORD dwLen = 0; | ||
| 87 | WCA_WRAPQUERY_HANDLE hQueryWebSite = NULL; | ||
| 88 | WCA_WRAPQUERY_HANDLE hQueryWebAddress = NULL; | ||
| 89 | |||
| 90 | hr = WcaBeginUnwrapQuery(&hQueryWebSite, ppwzCustomActionData); | ||
| 91 | ExitOnFailure(hr, "Failed to unwrap query for ScaWebsRead"); | ||
| 92 | |||
| 93 | hr = WcaBeginUnwrapQuery(&hQueryWebAddress, ppwzCustomActionData); | ||
| 94 | ExitOnFailure(hr, "Failed to unwrap query for ScaWebsRead"); | ||
| 95 | |||
| 96 | if (0 == WcaGetQueryRecords(hQueryWebSite)) | ||
| 97 | { | ||
| 98 | WcaLog(LOGMSG_VERBOSE, "Required tables not present"); | ||
| 99 | ExitFunction1(hr = S_FALSE); | ||
| 100 | } | ||
| 101 | |||
| 102 | // loop through all the webs | ||
| 103 | while (S_OK == (hr = WcaFetchWrappedRecord(hQueryWebSite, &hRec))) | ||
| 104 | { | ||
| 105 | psw = NewWeb(); | ||
| 106 | ExitOnNull(psw, hr, E_OUTOFMEMORY, "Failed to allocate memory for web object in memory"); | ||
| 107 | |||
| 108 | // get the darwin information | ||
| 109 | hr = WcaGetRecordString(hRec, wqWeb, &pwzData); | ||
| 110 | ExitOnFailure(hr, "Failed to get Web"); | ||
| 111 | hr = ::StringCchCopyW(psw->wzKey, countof(psw->wzKey), pwzData); | ||
| 112 | ExitOnFailure(hr, "Failed to copy key string to web object"); | ||
| 113 | |||
| 114 | if (*pwzData && *ppsmmList) | ||
| 115 | { | ||
| 116 | hr = ScaGetMimeMap(mmptWeb, pwzData, ppsmmList, &psw->psmm); | ||
| 117 | ExitOnFailure(hr, "Failed to get mimemap for VirtualDir"); | ||
| 118 | } | ||
| 119 | |||
| 120 | // get component install state | ||
| 121 | hr = WcaGetRecordString(hRec, wqComponent, &pwzData); | ||
| 122 | ExitOnFailure(hr, "Failed to get Component for Web"); | ||
| 123 | hr = ::StringCchCopyW(psw->wzComponent, countof(psw->wzComponent), pwzData); | ||
| 124 | ExitOnFailure(hr, "Failed to copy component string to web object"); | ||
| 125 | if (*(psw->wzComponent)) | ||
| 126 | { | ||
| 127 | psw->fHasComponent = TRUE; | ||
| 128 | |||
| 129 | hr = WcaGetRecordInteger(hRec, wqInstalled, (int *)&psw->isInstalled); | ||
| 130 | ExitOnFailure(hr, "Failed to get web Component's installed state"); | ||
| 131 | |||
| 132 | WcaGetRecordInteger(hRec, wqAction, (int *)&psw->isAction); | ||
| 133 | ExitOnFailure(hr, "Failed to get web Component's action state"); | ||
| 134 | |||
| 135 | if (!WcaIsInstalling(psw->isInstalled, psw->isAction) && !WcaIsUninstalling(psw->isInstalled, psw->isAction) | ||
| 136 | && !WcaIsReInstalling(psw->isInstalled, psw->isAction)) | ||
| 137 | { | ||
| 138 | FreeWeb(psw); | ||
| 139 | psw = NULL; | ||
| 140 | |||
| 141 | continue; // If we aren't acting on this component, skip it | ||
| 142 | } | ||
| 143 | } | ||
| 144 | |||
| 145 | hr = WcaGetRecordInteger(hRec, wqId, &iSiteId); | ||
| 146 | ExitOnFailure(hr, "Failed to get SiteId for Web"); | ||
| 147 | |||
| 148 | // Get the web's key address. | ||
| 149 | hr = WcaGetRecordString(hRec, wqAddress, &pwzData); | ||
| 150 | ExitOnFailure(hr, "Failed to get Address for Web"); | ||
| 151 | hr = ::StringCchCopyW(psw->swaKey.wzKey, countof(psw->swaKey.wzKey), pwzData); | ||
| 152 | ExitOnFailure(hr, "Failed to copy key string to web object"); | ||
| 153 | |||
| 154 | hr = WcaGetRecordString(hRec, wqIP, &pwzData); | ||
| 155 | ExitOnFailure(hr, "Failed to get IP for Web"); | ||
| 156 | hr = ::StringCchCopyW(psw->swaKey.wzIP, countof(psw->swaKey.wzIP), pwzData); | ||
| 157 | ExitOnFailure(hr, "Failed to copy IP string to web object"); | ||
| 158 | |||
| 159 | hr = WcaGetRecordString(hRec, wqPort, &pwzData); | ||
| 160 | ExitOnFailure(hr, "Failed to get Web Address port"); | ||
| 161 | psw->swaKey.iPort = wcstol(pwzData, NULL, 10); | ||
| 162 | |||
| 163 | hr = WcaGetRecordString(hRec, wqHeader, &pwzData); | ||
| 164 | ExitOnFailure(hr, "Failed to get Header for Web"); | ||
| 165 | hr = ::StringCchCopyW(psw->swaKey.wzHeader, countof(psw->swaKey.wzHeader), pwzData); | ||
| 166 | ExitOnFailure(hr, "Failed to copy header string to web object"); | ||
| 167 | |||
| 168 | hr = WcaGetRecordInteger(hRec, wqSecure, &psw->swaKey.fSecure); | ||
| 169 | ExitOnFailure(hr, "Failed to get if Web is secure"); | ||
| 170 | if (S_FALSE == hr) | ||
| 171 | { | ||
| 172 | psw->swaKey.fSecure = FALSE; | ||
| 173 | } | ||
| 174 | |||
| 175 | // Get the web's description. | ||
| 176 | hr = WcaGetRecordString(hRec, wqDescription, &pwzData); | ||
| 177 | ExitOnFailure(hr, "Failed to get Description for Web"); | ||
| 178 | hr = ::StringCchCopyW(psw->wzDescription, countof(psw->wzDescription), pwzData); | ||
| 179 | ExitOnFailure(hr, "Failed to copy description string to web object"); | ||
| 180 | |||
| 181 | // Try to find the web root in case it already exists. | ||
| 182 | dwLen = METADATA_MAX_NAME_LEN; | ||
| 183 | hr = ScaWebFindBase(piMetabase, *ppswList, | ||
| 184 | psw->wzKey, | ||
| 185 | iSiteId, | ||
| 186 | psw->swaKey.wzIP, | ||
| 187 | psw->swaKey.iPort, | ||
| 188 | psw->swaKey.wzHeader, | ||
| 189 | psw->swaKey.fSecure, | ||
| 190 | psw->wzDescription, | ||
| 191 | psw->wzWebBase, dwLen); | ||
| 192 | if (S_OK == hr) | ||
| 193 | { | ||
| 194 | psw->fBaseExists = TRUE; | ||
| 195 | } | ||
| 196 | else if (S_FALSE == hr) // didn't find the web site. | ||
| 197 | { | ||
| 198 | psw->fBaseExists = FALSE; | ||
| 199 | |||
| 200 | // If we're actually configuring the web site. | ||
| 201 | if (psw->fHasComponent) | ||
| 202 | { | ||
| 203 | if (WcaIsInstalling(psw->isInstalled, psw->isAction)) | ||
| 204 | { | ||
| 205 | hr = ScaWebFindFreeBase(piMetabase, *ppswList, iSiteId, psw->wzDescription, psw->wzWebBase, countof(psw->wzWebBase)); | ||
| 206 | ExitOnFailure(hr, "Failed to find free web root."); | ||
| 207 | } | ||
| 208 | else if (WcaIsUninstalling(psw->isInstalled, psw->isAction)) | ||
| 209 | { | ||
| 210 | WcaLog(LOGMSG_VERBOSE, "Web site: '%ls' was already removed, skipping.", psw->wzKey); | ||
| 211 | |||
| 212 | hr = S_OK; | ||
| 213 | continue; | ||
| 214 | } | ||
| 215 | } | ||
| 216 | } | ||
| 217 | ExitOnFailure(hr, "Failed to find web root"); | ||
| 218 | |||
| 219 | // get any extra web addresses | ||
| 220 | WcaFetchWrappedReset(hQueryWebAddress); | ||
| 221 | while (S_OK == (hr = WcaFetchWrappedRecordWhereString(hQueryWebAddress, 2, psw->wzKey, &hRecAddresses))) | ||
| 222 | { | ||
| 223 | if (MAX_ADDRESSES_PER_WEB <= psw->cExtraAddresses) | ||
| 224 | { | ||
| 225 | hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); | ||
| 226 | ExitOnFailure(hr, "Failure to get more extra web addresses, max exceeded."); | ||
| 227 | } | ||
| 228 | |||
| 229 | hr = WcaGetRecordString(hRecAddresses, waqAddress, &pwzData); | ||
| 230 | ExitOnFailure(hr, "Failed to get extra web Address"); | ||
| 231 | |||
| 232 | // if this isn't the key address add it | ||
| 233 | if (0 != lstrcmpW(pwzData, psw->swaKey.wzKey)) | ||
| 234 | { | ||
| 235 | hr = ::StringCchCopyW(psw->swaExtraAddresses[psw->cExtraAddresses].wzKey, countof(psw->swaExtraAddresses[psw->cExtraAddresses].wzKey), pwzData); | ||
| 236 | ExitOnFailure(hr, "Failed to copy extra addresses key string to web object"); | ||
| 237 | |||
| 238 | hr = WcaGetRecordString(hRecAddresses, waqIP, &pwzData); | ||
| 239 | ExitOnFailure(hr, "Failed to get extra web IP"); | ||
| 240 | hr = ::StringCchCopyW(psw->swaExtraAddresses[psw->cExtraAddresses].wzIP, countof(psw->swaExtraAddresses[psw->cExtraAddresses].wzIP), pwzData); | ||
| 241 | ExitOnFailure(hr, "Failed to copy extra addresses IP string to web object"); | ||
| 242 | |||
| 243 | hr = WcaGetRecordString(hRecAddresses, waqPort, &pwzData); | ||
| 244 | ExitOnFailure(hr, "Failed to get port for extra web IP"); | ||
| 245 | psw->swaExtraAddresses[psw->cExtraAddresses].iPort= wcstol(pwzData, NULL, 10); | ||
| 246 | |||
| 247 | hr = WcaGetRecordString(hRecAddresses, waqHeader, &pwzData); | ||
| 248 | ExitOnFailure(hr, "Failed to get header for extra web IP"); | ||
| 249 | hr = ::StringCchCopyW(psw->swaExtraAddresses[psw->cExtraAddresses].wzHeader, countof(psw->swaExtraAddresses[psw->cExtraAddresses].wzHeader), pwzData); | ||
| 250 | ExitOnFailure(hr, "Failed to copy extra addresses header string to web object"); | ||
| 251 | |||
| 252 | hr = WcaGetRecordInteger(hRecAddresses, waqSecure, &psw->swaExtraAddresses[psw->cExtraAddresses].fSecure); | ||
| 253 | ExitOnFailure(hr, "Failed to get if secure extra web IP"); | ||
| 254 | if (S_FALSE == hr) | ||
| 255 | psw->swaExtraAddresses[psw->cExtraAddresses].fSecure = FALSE; | ||
| 256 | |||
| 257 | ++psw->cExtraAddresses; | ||
| 258 | } | ||
| 259 | } | ||
| 260 | |||
| 261 | if (E_NOMOREITEMS == hr) | ||
| 262 | hr = S_OK; | ||
| 263 | ExitOnFailure(hr, "Failure occured while getting extra web addresses"); | ||
| 264 | |||
| 265 | hr = WcaGetRecordInteger(hRec, wqConnectionTimeout, &psw->iConnectionTimeout); | ||
| 266 | ExitOnFailure(hr, "Failed to get connection timeout for Web"); | ||
| 267 | |||
| 268 | if (psw->fHasComponent) // If we're installing it, it needs a dir | ||
| 269 | { | ||
| 270 | // get the web's directory | ||
| 271 | if (INSTALLSTATE_SOURCE == psw->isAction) | ||
| 272 | { | ||
| 273 | hr = WcaGetRecordString(hRec, wqSourcePath, &pwzData); | ||
| 274 | } | ||
| 275 | else | ||
| 276 | { | ||
| 277 | hr = WcaGetRecordString(hRec, wqTargetPath, &pwzData); | ||
| 278 | } | ||
| 279 | ExitOnFailure(hr, "Failed to get Source/TargetPath for Directory"); | ||
| 280 | |||
| 281 | // remove trailing backslashes | ||
| 282 | while (lstrlenW(pwzData) > 0 && pwzData[lstrlenW(pwzData)-1] == L'\\') | ||
| 283 | { | ||
| 284 | pwzData[lstrlenW(pwzData)-1] = 0; | ||
| 285 | } | ||
| 286 | hr = ::StringCchCopyW(psw->wzDirectory, countof(psw->wzDirectory), pwzData); | ||
| 287 | ExitOnFailure(hr, "Failed to copy directory string to web object"); | ||
| 288 | } | ||
| 289 | |||
| 290 | hr = WcaGetRecordInteger(hRec, wqState, &psw->iState); | ||
| 291 | ExitOnFailure(hr, "Failed to get state for Web"); | ||
| 292 | |||
| 293 | hr = WcaGetRecordInteger(hRec, wqAttributes, &psw->iAttributes); | ||
| 294 | ExitOnFailure(hr, "Failed to get attributes for Web"); | ||
| 295 | |||
| 296 | // get the dir properties for this web | ||
| 297 | hr = WcaGetRecordString(hRec, wqProperties, &pwzData); | ||
| 298 | ExitOnFailure(hr, "Failed to get directory property record for Web"); | ||
| 299 | if (*pwzData) | ||
| 300 | { | ||
| 301 | hr = ScaGetWebDirProperties(pwzData, hUserQuery, hWebDirPropQuery, &psw->swp); | ||
| 302 | ExitOnFailure(hr, "Failed to get directory properties for Web"); | ||
| 303 | |||
| 304 | psw->fHasProperties = TRUE; | ||
| 305 | } | ||
| 306 | |||
| 307 | // get the application information for this web | ||
| 308 | hr = WcaGetRecordString(hRec, wqApplication, &pwzData); | ||
| 309 | ExitOnFailure(hr, "Failed to get application identifier for Web"); | ||
| 310 | if (*pwzData) | ||
| 311 | { | ||
| 312 | hr = ScaGetWebApplication(NULL, pwzData, hWebAppQuery, hWebAppExtQuery, &psw->swapp); | ||
| 313 | ExitOnFailure(hr, "Failed to get application for Web"); | ||
| 314 | |||
| 315 | psw->fHasApplication = TRUE; | ||
| 316 | } | ||
| 317 | |||
| 318 | // get the SSL certificates | ||
| 319 | hr = ScaSslCertificateRead(psw->wzKey, hSslCertQuery, &(psw->pswscList)); | ||
| 320 | ExitOnFailure(hr, "Failed to get SSL Certificates."); | ||
| 321 | |||
| 322 | // get the custom headers | ||
| 323 | if (*ppshhList) | ||
| 324 | { | ||
| 325 | hr = ScaGetHttpHeader(hhptWeb, psw->wzKey, ppshhList, &(psw->pshhList)); | ||
| 326 | ExitOnFailure(hr, "Failed to get Custom HTTP Headers"); | ||
| 327 | } | ||
| 328 | |||
| 329 | // get the errors | ||
| 330 | if (*ppsweList) | ||
| 331 | { | ||
| 332 | hr = ScaGetWebError(weptWeb, psw->wzKey, ppsweList, &(psw->psweList)); | ||
| 333 | ExitOnFailure(hr, "Failed to get Custom Errors"); | ||
| 334 | } | ||
| 335 | |||
| 336 | // get the log information for this web | ||
| 337 | hr = WcaGetRecordString(hRec, wqLog, &pwzData); | ||
| 338 | ExitOnFailure(hr, "Failed to get log identifier for Web"); | ||
| 339 | if (*pwzData) | ||
| 340 | { | ||
| 341 | hr = ScaGetWebLog(piMetabase, pwzData, hWebLogQuery, &psw->swl); | ||
| 342 | ExitOnFailure(hr, "Failed to get Log for Web."); | ||
| 343 | |||
| 344 | psw->fHasLog = TRUE; | ||
| 345 | } | ||
| 346 | |||
| 347 | *ppswList = AddWebToList(*ppswList, psw); | ||
| 348 | psw = NULL; // set the web NULL so it doesn't accidentally get freed below | ||
| 349 | } | ||
| 350 | |||
| 351 | if (E_NOMOREITEMS == hr) | ||
| 352 | { | ||
| 353 | hr = S_OK; | ||
| 354 | } | ||
| 355 | |||
| 356 | LExit: | ||
| 357 | // if anything was left over after an error clean it all up | ||
| 358 | WcaFinishUnwrapQuery(hQueryWebSite); | ||
| 359 | WcaFinishUnwrapQuery(hQueryWebAddress); | ||
| 360 | |||
| 361 | if (psw) | ||
| 362 | { | ||
| 363 | ScaWebsFreeList(psw); | ||
| 364 | } | ||
| 365 | |||
| 366 | ReleaseStr(pwzData); | ||
| 367 | |||
| 368 | return hr; | ||
| 369 | } | ||
| 370 | |||
| 371 | |||
| 372 | HRESULT ScaWebsGetBase( | ||
| 373 | __in IMSAdminBase* piMetabase, | ||
| 374 | __in SCA_WEB* pswList, | ||
| 375 | __in LPCWSTR wzWeb, | ||
| 376 | __out_ecount(cchWebBase) LPWSTR wzWebBase, | ||
| 377 | __in DWORD cchWebBase, | ||
| 378 | __in WCA_WRAPQUERY_HANDLE hWrapQuery | ||
| 379 | ) | ||
| 380 | { | ||
| 381 | HRESULT hr = S_OK; | ||
| 382 | MSIHANDLE hRec; | ||
| 383 | |||
| 384 | int iSiteId; | ||
| 385 | WCHAR wzIP[MAX_PATH]; | ||
| 386 | int iPort = -1; | ||
| 387 | WCHAR wzHeader[MAX_PATH]; | ||
| 388 | BOOL fSecure = FALSE; | ||
| 389 | |||
| 390 | LPWSTR pwzData = NULL; | ||
| 391 | |||
| 392 | // get the web information | ||
| 393 | WcaFetchWrappedReset(hWrapQuery); | ||
| 394 | |||
| 395 | hr = WcaFetchWrappedRecordWhereString(hWrapQuery, 1, wzWeb, &hRec); | ||
| 396 | if (S_OK == hr) | ||
| 397 | { | ||
| 398 | // get the data to search for | ||
| 399 | hr = WcaGetRecordInteger(hRec, wbqId, &iSiteId); | ||
| 400 | ExitOnFailure(hr, "Failed to get SiteId for Web for VirtualDir"); | ||
| 401 | |||
| 402 | hr = WcaGetRecordString(hRec, wbqIP, &pwzData); | ||
| 403 | ExitOnFailure(hr, "Failed to get IP for Web for VirtualDir"); | ||
| 404 | hr = ::StringCchCopyW(wzIP, countof(wzIP), pwzData); | ||
| 405 | ExitOnFailure(hr, "Failed to copy IP for Web for VirtualDir"); | ||
| 406 | |||
| 407 | hr = WcaGetRecordString(hRec, wbqPort, &pwzData); | ||
| 408 | ExitOnFailure(hr, "Failed to get port for extra web IP"); | ||
| 409 | iPort = wcstol(pwzData, NULL, 10); | ||
| 410 | |||
| 411 | hr = WcaGetRecordString(hRec, wbqHeader, &pwzData); | ||
| 412 | ExitOnFailure(hr, "Failed to get Header for Web for VirtualDir"); | ||
| 413 | hr = ::StringCchCopyW(wzHeader, countof(wzHeader), pwzData); | ||
| 414 | ExitOnFailure(hr, "Failed to copy Header for Web for VirtualDir"); | ||
| 415 | |||
| 416 | hr = WcaGetRecordInteger(hRec, wbqSecure, &fSecure); | ||
| 417 | if (S_FALSE == hr) | ||
| 418 | fSecure = FALSE; | ||
| 419 | |||
| 420 | hr = WcaGetRecordString(hRec, wbqDescription, &pwzData); | ||
| 421 | ExitOnFailure(hr, "Failed to get Description for Web"); | ||
| 422 | |||
| 423 | // find the web or find the next free web location | ||
| 424 | hr = ScaWebFindBase(piMetabase, pswList, wzWeb, iSiteId, wzIP, iPort, wzHeader, fSecure, pwzData, wzWebBase, cchWebBase); | ||
| 425 | if (S_FALSE == hr) | ||
| 426 | hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); | ||
| 427 | ExitOnFailure(hr, "Failed to find Web base"); | ||
| 428 | } | ||
| 429 | else if (S_FALSE == hr) | ||
| 430 | hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND); | ||
| 431 | |||
| 432 | // Let's check that there isn't more than one record found - if there is, throw an assert like WcaFetchSingleRecord() would | ||
| 433 | HRESULT hrTemp = WcaFetchWrappedRecordWhereString(hWrapQuery, 1, wzWeb, &hRec); | ||
| 434 | if (SUCCEEDED(hrTemp)) | ||
| 435 | { | ||
| 436 | AssertSz(E_NOMOREITEMS == hrTemp, "ScaWebsGetBase found more than one record"); | ||
| 437 | } | ||
| 438 | |||
| 439 | LExit: | ||
| 440 | ReleaseStr(pwzData); | ||
| 441 | |||
| 442 | return hr; | ||
| 443 | } | ||
| 444 | |||
| 445 | |||
| 446 | HRESULT ScaWebsInstall( | ||
| 447 | __in IMSAdminBase* piMetabase, | ||
| 448 | __in SCA_WEB* pswList, | ||
| 449 | __in SCA_APPPOOL * psapList | ||
| 450 | ) | ||
| 451 | { | ||
| 452 | HRESULT hr = S_OK; | ||
| 453 | SCA_WEB* psw = pswList; | ||
| 454 | |||
| 455 | while (psw) | ||
| 456 | { | ||
| 457 | // if we are installing the web site | ||
| 458 | if (psw->fHasComponent && WcaIsInstalling(psw->isInstalled, psw->isAction)) | ||
| 459 | { | ||
| 460 | hr = ScaWebWrite(piMetabase, psw, psapList); | ||
| 461 | ExitOnFailure(hr, "failed to write web '%ls' to metabase", psw->wzKey); | ||
| 462 | } | ||
| 463 | |||
| 464 | psw = psw->pswNext; | ||
| 465 | } | ||
| 466 | |||
| 467 | LExit: | ||
| 468 | return hr; | ||
| 469 | } | ||
| 470 | |||
| 471 | |||
| 472 | HRESULT ScaWebsUninstall( | ||
| 473 | __in IMSAdminBase* piMetabase, | ||
| 474 | __in SCA_WEB* pswList | ||
| 475 | ) | ||
| 476 | { | ||
| 477 | HRESULT hr = S_OK; | ||
| 478 | SCA_WEB* psw = pswList; | ||
| 479 | |||
| 480 | while (psw) | ||
| 481 | { | ||
| 482 | // if we are uninstalling the web site | ||
| 483 | if (psw->fHasComponent && WcaIsUninstalling(psw->isInstalled, psw->isAction)) | ||
| 484 | { | ||
| 485 | hr = ScaWebRemove(piMetabase, psw); | ||
| 486 | ExitOnFailure(hr, "Failed to remove web '%ls' from metabase", psw->wzKey); | ||
| 487 | } | ||
| 488 | |||
| 489 | psw = psw->pswNext; | ||
| 490 | } | ||
| 491 | |||
| 492 | LExit: | ||
| 493 | return hr; | ||
| 494 | } | ||
| 495 | |||
| 496 | |||
| 497 | void ScaWebsFreeList( | ||
| 498 | __in SCA_WEB* pswList | ||
| 499 | ) | ||
| 500 | { | ||
| 501 | SCA_WEB* pswDelete = pswList; | ||
| 502 | while (pswList) | ||
| 503 | { | ||
| 504 | pswDelete = pswList; | ||
| 505 | pswList = pswList->pswNext; | ||
| 506 | |||
| 507 | // Free the SSL, headers and errors list first | ||
| 508 | FreeWeb(pswDelete); | ||
| 509 | } | ||
| 510 | } | ||
| 511 | |||
| 512 | |||
| 513 | // private helper functions | ||
| 514 | |||
| 515 | static void FreeWeb(SCA_WEB *pswDelete) | ||
| 516 | { | ||
| 517 | ScaSslCertificateFreeList(pswDelete->pswscList); | ||
| 518 | ScaHttpHeaderFreeList(pswDelete->pshhList); | ||
| 519 | ScaWebErrorFreeList(pswDelete->psweList); | ||
| 520 | MemFree(pswDelete); | ||
| 521 | } | ||
| 522 | |||
| 523 | static SCA_WEB* NewWeb() | ||
| 524 | { | ||
| 525 | SCA_WEB* psw = static_cast<SCA_WEB*>(MemAlloc(sizeof(SCA_WEB), TRUE)); | ||
| 526 | Assert(psw); | ||
| 527 | return psw; | ||
| 528 | } | ||
| 529 | |||
| 530 | |||
| 531 | static SCA_WEB* AddWebToList( | ||
| 532 | __in SCA_WEB* pswList, | ||
| 533 | __in SCA_WEB* psw | ||
| 534 | ) | ||
| 535 | { | ||
| 536 | if (pswList) | ||
| 537 | { | ||
| 538 | SCA_WEB* pswTemp = pswList; | ||
| 539 | while (pswTemp->pswNext) | ||
| 540 | { | ||
| 541 | pswTemp = pswTemp->pswNext; | ||
| 542 | } | ||
| 543 | |||
| 544 | pswTemp->pswNext = psw; | ||
| 545 | } | ||
| 546 | else | ||
| 547 | { | ||
| 548 | pswList = psw; | ||
| 549 | } | ||
| 550 | |||
| 551 | return pswList; | ||
| 552 | } | ||
| 553 | |||
| 554 | |||
| 555 | static HRESULT ScaWebFindBase( | ||
| 556 | __in IMSAdminBase* piMetabase, | ||
| 557 | __in SCA_WEB* pswList, | ||
| 558 | __in_z LPCWSTR wzWeb, | ||
| 559 | __in int iSiteId, | ||
| 560 | __in_z LPCWSTR wzIP, | ||
| 561 | __in int iPort, | ||
| 562 | __in_z LPCWSTR wzHeader, | ||
| 563 | __in BOOL fSecure, | ||
| 564 | __in_z LPCWSTR wzDescription, | ||
| 565 | __out_ecount(cchWebBase) LPWSTR wzWebBase, | ||
| 566 | __in DWORD cchWebBase | ||
| 567 | ) | ||
| 568 | { | ||
| 569 | Assert(piMetabase); | ||
| 570 | |||
| 571 | HRESULT hr = S_OK; | ||
| 572 | |||
| 573 | WCHAR wzKey[METADATA_MAX_NAME_LEN]; | ||
| 574 | WCHAR wzSubkey[METADATA_MAX_NAME_LEN]; | ||
| 575 | LPWSTR wzFoundKey = NULL; | ||
| 576 | |||
| 577 | METADATA_RECORD mr; | ||
| 578 | ::ZeroMemory(&mr, sizeof(mr)); | ||
| 579 | |||
| 580 | METADATA_RECORD mrCompare; | ||
| 581 | ::ZeroMemory(&mrCompare, sizeof(mrCompare)); | ||
| 582 | |||
| 583 | // try to find the web in memory first | ||
| 584 | for (SCA_WEB* psw = pswList; psw; psw = psw->pswNext) | ||
| 585 | { | ||
| 586 | if (0 == lstrcmpW(wzWeb, psw->wzKey)) | ||
| 587 | { | ||
| 588 | if ((0 == lstrcmpW(wzIP, psw->swaKey.wzIP) || 0 == lstrcmpW(wzIP, L"*") || 0 == lstrcmpW(psw->swaKey.wzIP, L"*")) && | ||
| 589 | iPort == psw->swaKey.iPort && | ||
| 590 | 0 == lstrcmpW(wzHeader, psw->swaKey.wzHeader) && | ||
| 591 | fSecure == psw->swaKey.fSecure) | ||
| 592 | { | ||
| 593 | if (0 == lstrlenW(psw->wzWebBase)) | ||
| 594 | { | ||
| 595 | WcaLog(LOGMSG_STANDARD, "A matching web object in memory was found, but the web object in memory has no associated base"); | ||
| 596 | ExitFunction1(hr = S_FALSE); | ||
| 597 | } | ||
| 598 | |||
| 599 | hr = ::StringCchCopyW(wzKey, countof(wzKey), psw->wzWebBase); | ||
| 600 | ExitOnFailure(hr, "Failed to copy web base into key."); | ||
| 601 | |||
| 602 | wzFoundKey = wzKey; | ||
| 603 | break; | ||
| 604 | } | ||
| 605 | else | ||
| 606 | { | ||
| 607 | WcaLog(LOGMSG_STANDARD, "Found web `%ls` but data did not match.", wzWeb); | ||
| 608 | hr = E_UNEXPECTED; | ||
| 609 | break; | ||
| 610 | } | ||
| 611 | } | ||
| 612 | } | ||
| 613 | ExitOnFailure(hr, "Failure occured while searching for web in memory"); | ||
| 614 | |||
| 615 | // If we didn't find a web in memory matching look in the metabase. | ||
| 616 | if (!wzFoundKey) | ||
| 617 | { | ||
| 618 | mr.dwMDIdentifier = MD_KEY_TYPE; | ||
| 619 | mr.dwMDAttributes = METADATA_INHERIT; | ||
| 620 | mr.dwMDUserType = IIS_MD_UT_SERVER; | ||
| 621 | mr.dwMDDataType = ALL_METADATA; | ||
| 622 | mr.dwMDDataLen = 0; | ||
| 623 | mr.pbMDData = NULL; | ||
| 624 | |||
| 625 | // If we're looking based on the old WebAddress detection (NULL) or the new | ||
| 626 | // Web description detection (-1) | ||
| 627 | if (MSI_NULL_INTEGER == iSiteId || -1 == iSiteId) | ||
| 628 | { | ||
| 629 | if (MSI_NULL_INTEGER == iSiteId) | ||
| 630 | { | ||
| 631 | mrCompare.dwMDIdentifier = (fSecure) ? MD_SECURE_BINDINGS : MD_SERVER_BINDINGS; | ||
| 632 | } | ||
| 633 | else | ||
| 634 | { | ||
| 635 | mrCompare.dwMDIdentifier = MD_SERVER_COMMENT; | ||
| 636 | } | ||
| 637 | mrCompare.dwMDAttributes = METADATA_INHERIT; | ||
| 638 | mrCompare.dwMDUserType = IIS_MD_UT_SERVER; | ||
| 639 | mrCompare.dwMDDataType = ALL_METADATA; | ||
| 640 | mrCompare.dwMDDataLen = 0; | ||
| 641 | mrCompare.pbMDData = NULL; | ||
| 642 | |||
| 643 | // Loop through the "web keys" looking for the "IIsWebServer" key that matches our search criteria. | ||
| 644 | for (DWORD dwIndex = 0; SUCCEEDED(hr); ++dwIndex) | ||
| 645 | { | ||
| 646 | hr = piMetabase->EnumKeys(METADATA_MASTER_ROOT_HANDLE, L"/LM/W3SVC", wzSubkey, dwIndex); | ||
| 647 | if (SUCCEEDED(hr)) | ||
| 648 | { | ||
| 649 | hr = ::StringCchPrintfW(wzKey, countof(wzKey), L"/LM/W3SVC/%s", wzSubkey); | ||
| 650 | ExitOnFailure(hr, "Failed to copy web subkey."); | ||
| 651 | |||
| 652 | hr = MetaGetValue(piMetabase, METADATA_MASTER_ROOT_HANDLE, wzKey, &mr); | ||
| 653 | if (MD_ERROR_DATA_NOT_FOUND == hr || HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) == hr) | ||
| 654 | { | ||
| 655 | hr = S_FALSE; // didn't find anything, try next one | ||
| 656 | continue; | ||
| 657 | } | ||
| 658 | ExitOnFailure(hr, "Failed to get key from metabase while searching for web servers"); | ||
| 659 | |||
| 660 | // If we have an IIsWebServer check to see if this is the site we are searching for. | ||
| 661 | if (0 == lstrcmpW(L"IIsWebServer", (LPCWSTR)mr.pbMDData)) | ||
| 662 | { | ||
| 663 | hr = MetaGetValue(piMetabase, METADATA_MASTER_ROOT_HANDLE, wzKey, &mrCompare); | ||
| 664 | if (MD_ERROR_DATA_NOT_FOUND == hr || NULL == mrCompare.pbMDData) | ||
| 665 | { | ||
| 666 | hr = S_FALSE; | ||
| 667 | continue; | ||
| 668 | } | ||
| 669 | ExitOnFailure(hr, "Failed to get address/description from metabase while searching for web servers"); | ||
| 670 | |||
| 671 | LPWSTR pwzExists = (LPWSTR)mrCompare.pbMDData; | ||
| 672 | if (MSI_NULL_INTEGER == iSiteId) | ||
| 673 | { | ||
| 674 | // Break down the address into its constituent parts (IP:Port:Header). | ||
| 675 | while (S_OK == hr && *pwzExists) | ||
| 676 | { | ||
| 677 | LPCWSTR pwzIPExists = pwzExists; | ||
| 678 | pwzExists = const_cast<LPWSTR>(wcsstr(pwzIPExists, L":")); | ||
| 679 | ExitOnNull(pwzExists, hr, E_INVALIDARG, "Invalid web address. IP was not separated by a colon."); | ||
| 680 | *pwzExists = L'\0'; | ||
| 681 | |||
| 682 | LPCWSTR pwzPortExists = pwzExists + 1; | ||
| 683 | pwzExists = const_cast<LPWSTR>(wcsstr(pwzPortExists, L":")); | ||
| 684 | ExitOnNull(pwzExists, hr, E_INVALIDARG, "Invalid web address. Port was not separated by a colon."); | ||
| 685 | *pwzExists = L'\0'; | ||
| 686 | int iPortExists = wcstol(pwzPortExists, NULL, 10); | ||
| 687 | |||
| 688 | LPCWSTR pwzHeaderExists = pwzExists + 1; | ||
| 689 | |||
| 690 | // compare the passed in address with the address listed for this web | ||
| 691 | if ((0 == lstrcmpW(wzIP, pwzIPExists) || 0 == lstrcmpW(wzIP, L"*")) && | ||
| 692 | iPort == iPortExists && | ||
| 693 | 0 == lstrcmpW(wzHeader, pwzHeaderExists)) | ||
| 694 | { | ||
| 695 | wzFoundKey = wzKey; | ||
| 696 | break; | ||
| 697 | } | ||
| 698 | |||
| 699 | // move to the next block of data, this may move beyond the available | ||
| 700 | // data and exit the while loop above. | ||
| 701 | pwzExists = const_cast<LPWSTR>(pwzHeaderExists + lstrlenW(pwzHeaderExists) + 1); | ||
| 702 | } | ||
| 703 | } | ||
| 704 | else | ||
| 705 | { | ||
| 706 | if (0 == lstrcmpW(wzDescription, pwzExists)) | ||
| 707 | { | ||
| 708 | wzFoundKey = wzKey; | ||
| 709 | } | ||
| 710 | } | ||
| 711 | |||
| 712 | // If we found the key we were looking for, no point in continuing to search. | ||
| 713 | if (wzFoundKey) | ||
| 714 | { | ||
| 715 | break; | ||
| 716 | } | ||
| 717 | } | ||
| 718 | } | ||
| 719 | } | ||
| 720 | |||
| 721 | if (E_NOMOREITEMS == hr) | ||
| 722 | { | ||
| 723 | Assert(!wzFoundKey); | ||
| 724 | hr = S_FALSE; | ||
| 725 | } | ||
| 726 | } | ||
| 727 | else // we're looking a specific SiteId | ||
| 728 | { | ||
| 729 | hr = ::StringCchPrintfW(wzKey, countof(wzKey), L"/LM/W3SVC/%d", iSiteId); | ||
| 730 | ExitOnFailure(hr, "Failed to allocate metabase key string."); | ||
| 731 | |||
| 732 | // if we have an IIsWebServer store the key | ||
| 733 | hr = MetaGetValue(piMetabase, METADATA_MASTER_ROOT_HANDLE, wzKey, &mr); | ||
| 734 | |||
| 735 | if (SUCCEEDED(hr) && NULL != mr.pbMDData && 0 == lstrcmpW(L"IIsWebServer", (LPCWSTR)mr.pbMDData)) | ||
| 736 | { | ||
| 737 | wzFoundKey = wzKey; | ||
| 738 | } | ||
| 739 | else if (MD_ERROR_DATA_NOT_FOUND == hr || NULL == mrCompare.pbMDData || NULL == mr.pbMDData) | ||
| 740 | { | ||
| 741 | hr = S_FALSE; | ||
| 742 | } | ||
| 743 | } | ||
| 744 | } | ||
| 745 | |||
| 746 | if (wzFoundKey) | ||
| 747 | { | ||
| 748 | Assert(S_OK == hr); | ||
| 749 | |||
| 750 | hr = ::StringCchCopyW(wzWebBase, cchWebBase, wzFoundKey); | ||
| 751 | ExitOnFailure(hr, "Buffer not larger enough for found base key."); | ||
| 752 | } | ||
| 753 | |||
| 754 | LExit: | ||
| 755 | MetaFreeValue(&mr); | ||
| 756 | MetaFreeValue(&mrCompare); | ||
| 757 | |||
| 758 | if (!wzFoundKey && SUCCEEDED(hr)) | ||
| 759 | { | ||
| 760 | hr = S_FALSE; | ||
| 761 | } | ||
| 762 | |||
| 763 | return hr; | ||
| 764 | } | ||
| 765 | |||
| 766 | |||
| 767 | static HRESULT ScaWebFindFreeBase( | ||
| 768 | __in IMSAdminBase* piMetabase, | ||
| 769 | __in_xcount(unknown) SCA_WEB* pswList, | ||
| 770 | __in int iSiteId, | ||
| 771 | __in_z LPCWSTR wzDescription, | ||
| 772 | __out_ecount(cchWebBase) LPWSTR wzWebBase, | ||
| 773 | __in DWORD cchWebBase | ||
| 774 | ) | ||
| 775 | { | ||
| 776 | Assert(piMetabase); | ||
| 777 | |||
| 778 | HRESULT hr = S_OK; | ||
| 779 | |||
| 780 | WCHAR wzKey[METADATA_MAX_NAME_LEN]; | ||
| 781 | WCHAR wzSubkey[METADATA_MAX_NAME_LEN]; | ||
| 782 | DWORD* prgdwSubKeys = NULL; | ||
| 783 | DWORD cSubKeys = 128; | ||
| 784 | DWORD cSubKeysFilled = 0; | ||
| 785 | |||
| 786 | DWORD dwKey; | ||
| 787 | |||
| 788 | METADATA_RECORD mr; | ||
| 789 | ::ZeroMemory(&mr, sizeof(METADATA_RECORD)); | ||
| 790 | mr.dwMDIdentifier = MD_KEY_TYPE; | ||
| 791 | mr.dwMDAttributes = 0; | ||
| 792 | mr.dwMDUserType = IIS_MD_UT_SERVER; | ||
| 793 | mr.dwMDDataType = STRING_METADATA; | ||
| 794 | mr.dwMDDataLen = 0; | ||
| 795 | mr.pbMDData = NULL; | ||
| 796 | |||
| 797 | if (MSI_NULL_INTEGER == iSiteId || -1 == iSiteId) | ||
| 798 | { | ||
| 799 | prgdwSubKeys = static_cast<DWORD*>(MemAlloc(cSubKeys * sizeof(DWORD), TRUE)); | ||
| 800 | ExitOnNull(prgdwSubKeys, hr, E_OUTOFMEMORY, "failed to allocate space for web site keys"); | ||
| 801 | |||
| 802 | // loop through the "web keys" looking for the "IIsWebServer" key that matches wzWeb | ||
| 803 | for (DWORD dwIndex = 0; SUCCEEDED(hr); ++dwIndex) | ||
| 804 | { | ||
| 805 | hr = piMetabase->EnumKeys(METADATA_MASTER_ROOT_HANDLE, L"/LM/W3SVC", wzSubkey, dwIndex); | ||
| 806 | if (SUCCEEDED(hr)) | ||
| 807 | { | ||
| 808 | hr = ::StringCchPrintfW(wzKey, countof(wzKey), L"/LM/W3SVC/%s", wzSubkey); | ||
| 809 | ExitOnFailure(hr, "Failed remember key."); | ||
| 810 | |||
| 811 | hr = MetaGetValue(piMetabase, METADATA_MASTER_ROOT_HANDLE, wzKey, &mr); | ||
| 812 | if (MD_ERROR_DATA_NOT_FOUND == hr || HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) == hr) | ||
| 813 | { | ||
| 814 | hr = S_FALSE; // didn't find anything, try next one | ||
| 815 | continue; | ||
| 816 | } | ||
| 817 | ExitOnFailure(hr, "Failed to get key from metabase while searching for free web root"); | ||
| 818 | |||
| 819 | // if we have a IIsWebServer get the address information | ||
| 820 | if (0 == lstrcmpW(L"IIsWebServer", (LPCWSTR)mr.pbMDData)) | ||
| 821 | { | ||
| 822 | if (cSubKeysFilled >= cSubKeys) | ||
| 823 | { | ||
| 824 | cSubKeys = cSubKeys * 2; | ||
| 825 | prgdwSubKeys = static_cast<DWORD*>(MemReAlloc(prgdwSubKeys, cSubKeys * sizeof(DWORD), FALSE)); | ||
| 826 | ExitOnNull(prgdwSubKeys, hr, E_OUTOFMEMORY, "failed to allocate space for web site keys"); | ||
| 827 | } | ||
| 828 | |||
| 829 | prgdwSubKeys[cSubKeysFilled] = wcstol(wzSubkey, NULL, 10); | ||
| 830 | ++cSubKeysFilled; | ||
| 831 | Sort(prgdwSubKeys, cSubKeysFilled); | ||
| 832 | } | ||
| 833 | } | ||
| 834 | } | ||
| 835 | |||
| 836 | if (E_NOMOREITEMS == hr) | ||
| 837 | { | ||
| 838 | hr = S_OK; | ||
| 839 | } | ||
| 840 | ExitOnFailure(hr, "Failed to find free web root"); | ||
| 841 | |||
| 842 | // Add all the webs created in memory. | ||
| 843 | CONST WCHAR *pcchSlash; | ||
| 844 | for (SCA_WEB* psw = pswList; psw; psw = psw->pswNext) | ||
| 845 | { | ||
| 846 | // Don't process webs that don't have a base | ||
| 847 | if (!*psw->wzWebBase) | ||
| 848 | { | ||
| 849 | continue; | ||
| 850 | } | ||
| 851 | |||
| 852 | // find the last slash in the web root because the root # is after it | ||
| 853 | pcchSlash = NULL; | ||
| 854 | for (CONST WCHAR *pcch = psw->wzWebBase; pcch && *pcch; ++pcch) | ||
| 855 | { | ||
| 856 | if (L'/' == *pcch) | ||
| 857 | { | ||
| 858 | pcchSlash = pcch; | ||
| 859 | } | ||
| 860 | } | ||
| 861 | // In case we don't find a slash, error out | ||
| 862 | ExitOnNull(pcchSlash, hr, E_INVALIDARG, "Failed to find a slash in the web root: %ls", psw->wzWebBase); | ||
| 863 | |||
| 864 | prgdwSubKeys[cSubKeysFilled] = wcstol(pcchSlash + 1, NULL, 10); | ||
| 865 | ++cSubKeysFilled; | ||
| 866 | Sort(prgdwSubKeys, cSubKeysFilled); | ||
| 867 | |||
| 868 | if (cSubKeysFilled >= cSubKeys) | ||
| 869 | { | ||
| 870 | cSubKeys = cSubKeys * 2; | ||
| 871 | prgdwSubKeys = static_cast<DWORD*>(MemReAlloc(prgdwSubKeys, cSubKeys * sizeof(DWORD), FALSE)); | ||
| 872 | ExitOnNull(prgdwSubKeys, hr, E_OUTOFMEMORY, "failed to allocate space for web site keys"); | ||
| 873 | } | ||
| 874 | } | ||
| 875 | |||
| 876 | // Find the lowest free web root. | ||
| 877 | dwKey = (-1 == iSiteId) ? SiteIdFromDescription(wzDescription) : 1; | ||
| 878 | for (DWORD i = 0; i < cSubKeysFilled; ++i) | ||
| 879 | { | ||
| 880 | if (dwKey == prgdwSubKeys[i]) | ||
| 881 | { | ||
| 882 | ++dwKey; | ||
| 883 | } | ||
| 884 | else if (dwKey < prgdwSubKeys[i]) | ||
| 885 | { | ||
| 886 | break; | ||
| 887 | } | ||
| 888 | } | ||
| 889 | } | ||
| 890 | else | ||
| 891 | { | ||
| 892 | dwKey = iSiteId; | ||
| 893 | } | ||
| 894 | |||
| 895 | hr = ::StringCchPrintfW(wzWebBase, cchWebBase, L"/LM/W3SVC/%u", dwKey); | ||
| 896 | ExitOnFailure(hr, "failed to format web base with key: %u", dwKey); | ||
| 897 | |||
| 898 | LExit: | ||
| 899 | MetaFreeValue(&mr); | ||
| 900 | |||
| 901 | if (prgdwSubKeys) | ||
| 902 | { | ||
| 903 | MemFree(prgdwSubKeys); | ||
| 904 | } | ||
| 905 | |||
| 906 | return hr; | ||
| 907 | } | ||
| 908 | |||
| 909 | |||
| 910 | static HRESULT ScaWebWrite( | ||
| 911 | __in IMSAdminBase* piMetabase, | ||
| 912 | __in SCA_WEB* psw, | ||
| 913 | __in SCA_APPPOOL * psapList) | ||
| 914 | { | ||
| 915 | HRESULT hr = S_OK; | ||
| 916 | |||
| 917 | UINT ui = 0; | ||
| 918 | WCHAR wzIP[64]; | ||
| 919 | WCHAR wzBindings[1024]; | ||
| 920 | WCHAR wzSecureBindings[1024]; | ||
| 921 | WCHAR* pcchNext; // used to properly create the MULTI_SZ | ||
| 922 | DWORD cchPcchNext; | ||
| 923 | WCHAR* pcchSecureNext ; // used to properly create the MULTI_SZ | ||
| 924 | DWORD cchPcchSecureNext; | ||
| 925 | |||
| 926 | // if the web root doesn't exist create it | ||
| 927 | if (!psw->fBaseExists) | ||
| 928 | { | ||
| 929 | hr = ScaCreateWeb(piMetabase, psw->wzKey, psw->wzWebBase); | ||
| 930 | ExitOnFailure(hr, "Failed to create web"); | ||
| 931 | } | ||
| 932 | else if (psw->iAttributes & SWATTRIB_NOCONFIGUREIFEXISTS) // if we're not supposed to configure existing webs, bail | ||
| 933 | { | ||
| 934 | Assert(psw->fBaseExists); | ||
| 935 | |||
| 936 | hr = S_FALSE; | ||
| 937 | WcaLog(LOGMSG_VERBOSE, "Skipping configuration of existing web: %ls", psw->wzKey); | ||
| 938 | ExitFunction(); | ||
| 939 | } | ||
| 940 | |||
| 941 | // put the secure and non-secure bindings together as MULTI_SZs | ||
| 942 | ::ZeroMemory(wzBindings, sizeof(wzBindings)); | ||
| 943 | pcchNext = wzBindings; | ||
| 944 | cchPcchNext = countof(wzBindings); | ||
| 945 | ::ZeroMemory(wzSecureBindings, sizeof(wzSecureBindings)); | ||
| 946 | pcchSecureNext = wzSecureBindings; | ||
| 947 | cchPcchSecureNext = countof(wzSecureBindings); | ||
| 948 | |||
| 949 | // set the IP address appropriately | ||
| 950 | if (0 == lstrcmpW(psw->swaKey.wzIP, L"*")) | ||
| 951 | { | ||
| 952 | ::ZeroMemory(wzIP, sizeof(wzIP)); | ||
| 953 | } | ||
| 954 | else | ||
| 955 | { | ||
| 956 | hr = ::StringCchCopyW(wzIP, countof(wzIP), psw->swaKey.wzIP); | ||
| 957 | ExitOnFailure(hr, "Failed to copy IP string"); | ||
| 958 | } | ||
| 959 | |||
| 960 | WCHAR wzBinding[256]; | ||
| 961 | hr = ::StringCchPrintfW(wzBinding, countof(wzBinding), L"%s:%d:%s", wzIP, psw->swaKey.iPort, psw->swaKey.wzHeader); | ||
| 962 | ExitOnFailure(hr, "Failed to format IP:Port:Header binding string"); | ||
| 963 | if (psw->swaKey.fSecure) | ||
| 964 | { | ||
| 965 | hr = ::StringCchCopyW(pcchSecureNext, cchPcchSecureNext, wzBinding); | ||
| 966 | ExitOnFailure(hr, "Failed to copy binding string to securenext string"); | ||
| 967 | pcchSecureNext += lstrlenW(wzBinding) + 1; | ||
| 968 | cchPcchSecureNext -= lstrlenW(wzBinding) + 1; | ||
| 969 | } | ||
| 970 | else | ||
| 971 | { | ||
| 972 | hr = ::StringCchCopyW(pcchNext, cchPcchNext, wzBinding); | ||
| 973 | ExitOnFailure(hr, "Failed to copy binding string to next string"); | ||
| 974 | pcchNext += lstrlenW(wzBinding) + 1; | ||
| 975 | cchPcchNext -= lstrlenW(wzBinding) + 1; | ||
| 976 | } | ||
| 977 | |||
| 978 | for (ui = 0; ui < psw->cExtraAddresses; ++ui) | ||
| 979 | { | ||
| 980 | // set the IP address appropriately | ||
| 981 | if (0 == lstrcmpW(psw->swaExtraAddresses[ui].wzIP, L"*")) | ||
| 982 | { | ||
| 983 | ::ZeroMemory(wzIP, sizeof(wzIP)); | ||
| 984 | } | ||
| 985 | else | ||
| 986 | { | ||
| 987 | hr = ::StringCchCopyW(wzIP, countof(wzIP), psw->swaExtraAddresses[ui].wzIP); | ||
| 988 | ExitOnFailure(hr, "Failed to copy extra addresses IP to IP string"); | ||
| 989 | } | ||
| 990 | |||
| 991 | hr = ::StringCchPrintfW(wzBinding, countof(wzBinding), L"%s:%d:%s", wzIP, psw->swaExtraAddresses[ui].iPort, psw->swaExtraAddresses[ui].wzHeader); | ||
| 992 | ExitOnFailure(hr, "Failed to format IP:Port:Header binding string for extra address"); | ||
| 993 | if (psw->swaExtraAddresses[ui].fSecure) | ||
| 994 | { | ||
| 995 | hr = ::StringCchCopyW(pcchSecureNext, cchPcchSecureNext, wzBinding); | ||
| 996 | ExitOnFailure(hr, "Failed to copy binding string to securenext string for extra address"); | ||
| 997 | pcchSecureNext += lstrlenW(wzBinding) + 1; | ||
| 998 | cchPcchSecureNext -= lstrlenW(wzBinding) + 1; | ||
| 999 | } | ||
| 1000 | else | ||
| 1001 | { | ||
| 1002 | hr = ::StringCchCopyW(pcchNext, cchPcchNext, wzBinding); | ||
| 1003 | ExitOnFailure(hr, "Failed to copy binding string to next string for extra address"); | ||
| 1004 | pcchNext += lstrlenW(wzBinding) + 1; | ||
| 1005 | cchPcchNext -= lstrlenW(wzBinding) + 1; | ||
| 1006 | } | ||
| 1007 | } | ||
| 1008 | |||
| 1009 | // Delete the existing secure bindings metabase value, as having one while SSLCertHash and SSLStoreName aren't both set correctly can result in | ||
| 1010 | // 0x80070520 (ERROR_NO_SUCH_LOGON_SESSION) errors in some situations on IIS7. Clearing this value first and then setting it after the install has completed | ||
| 1011 | // allows the two aforementioned properties to exist in an intermediate state without errors | ||
| 1012 | hr = ScaDeleteMetabaseValue(piMetabase, psw->wzWebBase, L"", MD_SECURE_BINDINGS, MULTISZ_METADATA); | ||
| 1013 | ExitOnFailure(hr, "Failed to temporarily delete secure bindings for Web"); | ||
| 1014 | |||
| 1015 | // now write the bindings to the metabase | ||
| 1016 | hr = ScaWriteMetabaseValue(piMetabase, psw->wzWebBase, L"", MD_SERVER_BINDINGS, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, MULTISZ_METADATA, wzBindings); | ||
| 1017 | ExitOnFailure(hr, "Failed to write server bindings for Web"); | ||
| 1018 | |||
| 1019 | // write the target path for the web's directory to the metabase | ||
| 1020 | hr = ScaWriteMetabaseValue(piMetabase, psw->wzWebBase, L"/Root", MD_VR_PATH, METADATA_INHERIT, IIS_MD_UT_FILE, STRING_METADATA, psw->wzDirectory); | ||
| 1021 | ExitOnFailure(hr, "Failed to write virtual root path for Web"); | ||
| 1022 | |||
| 1023 | // write the description for the web to the metabase | ||
| 1024 | hr = ScaWriteMetabaseValue(piMetabase, psw->wzWebBase, L"", MD_SERVER_COMMENT, METADATA_INHERIT, IIS_MD_UT_SERVER, STRING_METADATA, psw->wzDescription); | ||
| 1025 | ExitOnFailure(hr, "Failed to write description for Web"); | ||
| 1026 | |||
| 1027 | ui = psw->iConnectionTimeout; | ||
| 1028 | if (MSI_NULL_INTEGER != ui) | ||
| 1029 | { | ||
| 1030 | hr = ScaWriteMetabaseValue(piMetabase, psw->wzWebBase, L"", MD_CONNECTION_TIMEOUT, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, (LPVOID)((DWORD_PTR)ui)); | ||
| 1031 | ExitOnFailure(hr, "Failed to write connection timeout for Web"); | ||
| 1032 | } | ||
| 1033 | |||
| 1034 | ui = psw->iState; | ||
| 1035 | if (MSI_NULL_INTEGER != ui) | ||
| 1036 | { | ||
| 1037 | if (2 == ui) | ||
| 1038 | { | ||
| 1039 | ui = 1; | ||
| 1040 | hr = ScaWriteMetabaseValue(piMetabase, psw->wzWebBase, L"", MD_SERVER_AUTOSTART, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, (LPVOID)((DWORD_PTR)ui)); | ||
| 1041 | ExitOnFailure(hr, "Failed to write auto start flag for Web"); | ||
| 1042 | ui = 2; | ||
| 1043 | } | ||
| 1044 | |||
| 1045 | if (1 == ui || 2 == ui) | ||
| 1046 | { | ||
| 1047 | ui = 1; // start command | ||
| 1048 | hr = ScaWriteMetabaseValue(piMetabase, psw->wzWebBase, L"", MD_SERVER_COMMAND, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, (LPVOID)((DWORD_PTR)ui)); | ||
| 1049 | ExitOnFailure(hr, "Failed to start Web"); | ||
| 1050 | } | ||
| 1051 | else if (0 == ui) | ||
| 1052 | { | ||
| 1053 | ui = 2; // stop command | ||
| 1054 | hr = ScaWriteMetabaseValue(piMetabase, psw->wzWebBase, L"", MD_SERVER_COMMAND, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, (LPVOID)((DWORD_PTR)ui)); | ||
| 1055 | ExitOnFailure(hr, "Failed to stop Web"); | ||
| 1056 | } | ||
| 1057 | else | ||
| 1058 | { | ||
| 1059 | hr = E_UNEXPECTED; | ||
| 1060 | ExitOnFailure(hr, "Unexpected value for Web State"); | ||
| 1061 | } | ||
| 1062 | } | ||
| 1063 | |||
| 1064 | WCHAR wzRootOfWeb[METADATA_MAX_NAME_LEN]; | ||
| 1065 | hr = ::StringCchPrintfW(wzRootOfWeb, countof(wzRootOfWeb), L"%s/Root", psw->wzWebBase); | ||
| 1066 | ExitOnFailure(hr, "Failed to allocate WebBase/Root string for root of web"); | ||
| 1067 | |||
| 1068 | // write the web dirproperties information | ||
| 1069 | if (psw->fHasProperties) | ||
| 1070 | { | ||
| 1071 | hr = ScaWriteWebDirProperties(piMetabase, wzRootOfWeb, &psw->swp); | ||
| 1072 | ExitOnFailure(hr, "Failed to write web security information to metabase"); | ||
| 1073 | } | ||
| 1074 | |||
| 1075 | // write the application information | ||
| 1076 | if (psw->fHasApplication) | ||
| 1077 | { | ||
| 1078 | // On reinstall, we have to uninstall the old application, otherwise a duplicate will be created | ||
| 1079 | if (WcaIsReInstalling(psw->isInstalled, psw->isAction)) | ||
| 1080 | { | ||
| 1081 | hr = ScaDeleteApp(piMetabase, wzRootOfWeb); | ||
| 1082 | ExitOnFailure(hr, "Failed to remove application for WebDir as part of a reinstall"); | ||
| 1083 | } | ||
| 1084 | |||
| 1085 | hr = ScaWriteWebApplication(piMetabase, wzRootOfWeb, &psw->swapp, psapList); | ||
| 1086 | ExitOnFailure(hr, "Failed to write web application information to metabase"); | ||
| 1087 | } | ||
| 1088 | |||
| 1089 | // write the SSL certificate information | ||
| 1090 | if (psw->pswscList) | ||
| 1091 | { | ||
| 1092 | hr = ScaSslCertificateWriteMetabase(piMetabase, psw->wzWebBase, psw->pswscList); | ||
| 1093 | ExitOnFailure(hr, "Failed to write SSL certificates for Web site: %ls", psw->wzKey); | ||
| 1094 | } | ||
| 1095 | |||
| 1096 | hr = ScaWriteMetabaseValue(piMetabase, psw->wzWebBase, L"", MD_SECURE_BINDINGS, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, MULTISZ_METADATA, wzSecureBindings); | ||
| 1097 | ExitOnFailure(hr, "Failed to write secure bindings for Web"); | ||
| 1098 | |||
| 1099 | // write the headers | ||
| 1100 | if (psw->pshhList) | ||
| 1101 | { | ||
| 1102 | hr = ScaWriteHttpHeader(piMetabase, wzRootOfWeb, psw->pshhList); | ||
| 1103 | ExitOnFailure(hr, "Failed to write custom HTTP headers for Web site: %ls", psw->wzKey); | ||
| 1104 | } | ||
| 1105 | |||
| 1106 | // write the errors | ||
| 1107 | if (psw->psweList) | ||
| 1108 | { | ||
| 1109 | hr = ScaWriteWebError(piMetabase, weptWeb, psw->wzWebBase, psw->psweList); | ||
| 1110 | ExitOnFailure(hr, "Failed to write custom web errors for Web site: %ls", psw->wzKey); | ||
| 1111 | } | ||
| 1112 | |||
| 1113 | // write the mimetypes | ||
| 1114 | if (psw->psmm) | ||
| 1115 | { | ||
| 1116 | hr = ScaWriteMimeMap(piMetabase, wzRootOfWeb, psw->psmm); | ||
| 1117 | ExitOnFailure(hr, "Failed to write mimemap for Web site: %ls", psw->wzKey); | ||
| 1118 | } | ||
| 1119 | |||
| 1120 | // write the log information to the metabase | ||
| 1121 | if (psw->fHasLog) | ||
| 1122 | { | ||
| 1123 | hr = ScaWriteWebLog(piMetabase, psw->wzWebBase, &psw->swl); | ||
| 1124 | ExitOnFailure(hr, "Failed to write web log information to metabase"); | ||
| 1125 | } | ||
| 1126 | |||
| 1127 | LExit: | ||
| 1128 | return hr; | ||
| 1129 | } | ||
| 1130 | |||
| 1131 | |||
| 1132 | static HRESULT ScaWebRemove( | ||
| 1133 | __in IMSAdminBase* piMetabase, | ||
| 1134 | __in const SCA_WEB* psw | ||
| 1135 | ) | ||
| 1136 | { | ||
| 1137 | HRESULT hr = S_OK; | ||
| 1138 | |||
| 1139 | // simply remove the root key and everything else is pulled at the same time | ||
| 1140 | hr = ScaDeleteMetabaseKey(piMetabase, psw->wzWebBase, L""); | ||
| 1141 | ExitOnFailure(hr, "Failed to remove web '%ls' from metabase", psw->wzKey); | ||
| 1142 | |||
| 1143 | LExit: | ||
| 1144 | return hr; | ||
| 1145 | } | ||
| 1146 | |||
| 1147 | |||
| 1148 | static DWORD SiteIdFromDescription( | ||
| 1149 | __in_z LPCWSTR wzDescription | ||
| 1150 | ) | ||
| 1151 | { | ||
| 1152 | LPCWSTR pwz = wzDescription; | ||
| 1153 | DWORD dwSiteId = 0; | ||
| 1154 | while (pwz && *pwz) | ||
| 1155 | { | ||
| 1156 | WCHAR ch = *pwz & 0xdf; | ||
| 1157 | dwSiteId = (dwSiteId * 101) + ch; | ||
| 1158 | ++pwz; | ||
| 1159 | } | ||
| 1160 | |||
| 1161 | return (dwSiteId % INT_MAX) + 1; | ||
| 1162 | } | ||
| 1163 | |||
| 1164 | |||
| 1165 | // insertion sort | ||
| 1166 | static void Sort( | ||
| 1167 | __in_ecount(cArray) DWORD dwArray[], | ||
| 1168 | __in int cArray | ||
| 1169 | ) | ||
| 1170 | { | ||
| 1171 | int i, j; | ||
| 1172 | DWORD dwData; | ||
| 1173 | |||
| 1174 | for (i = 1; i < cArray; ++i) | ||
| 1175 | { | ||
| 1176 | dwData = dwArray[i]; | ||
| 1177 | |||
| 1178 | j = i - 1; | ||
| 1179 | while (0 <= j && dwArray[j] > dwData) | ||
| 1180 | { | ||
| 1181 | dwArray[j + 1] = dwArray[j]; | ||
| 1182 | j--; | ||
| 1183 | } | ||
| 1184 | |||
| 1185 | dwArray[j + 1] = dwData; | ||
| 1186 | } | ||
| 1187 | } | ||
diff --git a/src/ca/scaweb.h b/src/ca/scaweb.h new file mode 100644 index 00000000..294030b4 --- /dev/null +++ b/src/ca/scaweb.h | |||
| @@ -0,0 +1,123 @@ | |||
| 1 | #pragma once | ||
| 2 | // 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. | ||
| 3 | |||
| 4 | |||
| 5 | #include "scawebapp.h" | ||
| 6 | #include "scawebprop.h" | ||
| 7 | #include "scahttpheader.h" | ||
| 8 | #include "scaweberr.h" | ||
| 9 | #include "scassl.h" | ||
| 10 | #include "scaapppool.h" | ||
| 11 | #include "scaweblog.h" | ||
| 12 | #include "scamimemap.h" | ||
| 13 | |||
| 14 | // globals | ||
| 15 | #define MAX_ADDRESSES_PER_WEB 10 | ||
| 16 | |||
| 17 | enum eWebQuery { wqWeb = 1, wqComponent, wqId, wqDescription, wqConnectionTimeout, wqDirectory, | ||
| 18 | wqState, wqAttributes, wqProperties, wqApplication, wqAddress, wqIP, wqPort, wqHeader, wqSecure, wqLog, wqInstalled, wqAction, wqSourcePath, wqTargetPath}; | ||
| 19 | |||
| 20 | enum eWebAddressQuery { waqAddress = 1, waqWeb, waqIP, waqPort, waqHeader, waqSecure }; | ||
| 21 | |||
| 22 | enum SCA_WEB_ATTRIBUTES | ||
| 23 | { | ||
| 24 | SWATTRIB_NOCONFIGUREIFEXISTS = 2 | ||
| 25 | }; | ||
| 26 | |||
| 27 | // structs | ||
| 28 | struct SCA_WEB_ADDRESS | ||
| 29 | { | ||
| 30 | WCHAR wzKey [MAX_DARWIN_KEY + 1]; | ||
| 31 | |||
| 32 | WCHAR wzIP[MAX_DARWIN_COLUMN + 1]; | ||
| 33 | int iPort; | ||
| 34 | WCHAR wzHeader[MAX_DARWIN_COLUMN + 1]; | ||
| 35 | BOOL fSecure; | ||
| 36 | }; | ||
| 37 | |||
| 38 | struct SCA_WEB | ||
| 39 | { | ||
| 40 | // darwin information | ||
| 41 | WCHAR wzKey[MAX_DARWIN_KEY + 1]; | ||
| 42 | WCHAR wzComponent[MAX_DARWIN_KEY + 1]; | ||
| 43 | BOOL fHasComponent; | ||
| 44 | INSTALLSTATE isInstalled; | ||
| 45 | INSTALLSTATE isAction; | ||
| 46 | |||
| 47 | // metabase information | ||
| 48 | WCHAR wzWebBase[METADATA_MAX_NAME_LEN + 1]; | ||
| 49 | BOOL fBaseExists; | ||
| 50 | |||
| 51 | // iis configuation information | ||
| 52 | SCA_WEB_ADDRESS swaKey; | ||
| 53 | |||
| 54 | SCA_WEB_ADDRESS swaExtraAddresses[MAX_ADDRESSES_PER_WEB + 1]; | ||
| 55 | DWORD cExtraAddresses; | ||
| 56 | |||
| 57 | WCHAR wzDirectory[MAX_PATH]; | ||
| 58 | WCHAR wzDescription[MAX_DARWIN_COLUMN + 1]; | ||
| 59 | |||
| 60 | int iState; | ||
| 61 | int iAttributes; | ||
| 62 | |||
| 63 | BOOL fHasProperties; | ||
| 64 | SCA_WEB_PROPERTIES swp; | ||
| 65 | |||
| 66 | BOOL fHasApplication; | ||
| 67 | SCA_WEB_APPLICATION swapp; | ||
| 68 | |||
| 69 | BOOL fHasSecurity; | ||
| 70 | int dwAccessPermissions; | ||
| 71 | int iConnectionTimeout; | ||
| 72 | |||
| 73 | SCA_MIMEMAP* psmm; // mime mappings | ||
| 74 | SCA_WEB_SSL_CERTIFICATE* pswscList; | ||
| 75 | SCA_HTTP_HEADER* pshhList; | ||
| 76 | SCA_WEB_ERROR* psweList; | ||
| 77 | |||
| 78 | BOOL fHasLog; | ||
| 79 | SCA_WEB_LOG swl; | ||
| 80 | |||
| 81 | SCA_WEB* pswNext; | ||
| 82 | }; | ||
| 83 | |||
| 84 | |||
| 85 | // prototypes | ||
| 86 | HRESULT ScaWebsRead( | ||
| 87 | __in IMSAdminBase* piMetabase, | ||
| 88 | __in SCA_MIMEMAP** ppsmmList, | ||
| 89 | __in SCA_WEB** ppswList, | ||
| 90 | __in SCA_HTTP_HEADER** pshhList, | ||
| 91 | __in SCA_WEB_ERROR** psweList, | ||
| 92 | __in WCA_WRAPQUERY_HANDLE hUserQuery, | ||
| 93 | __in WCA_WRAPQUERY_HANDLE hWebDirPropQuery, | ||
| 94 | __in WCA_WRAPQUERY_HANDLE hSslCertQuery, | ||
| 95 | __in WCA_WRAPQUERY_HANDLE hWebLogQuery, | ||
| 96 | __in WCA_WRAPQUERY_HANDLE hWebAppQuery, | ||
| 97 | __in WCA_WRAPQUERY_HANDLE hWebAppExtQuery, | ||
| 98 | __inout LPWSTR *ppwzCustomActionData | ||
| 99 | ); | ||
| 100 | |||
| 101 | HRESULT ScaWebsGetBase( | ||
| 102 | __in IMSAdminBase* piMetabase, | ||
| 103 | __in SCA_WEB* pswList, | ||
| 104 | __in LPCWSTR wzWeb, | ||
| 105 | __out_ecount(cchWebBase) LPWSTR wzWebBase, | ||
| 106 | __in DWORD cchWebBase, | ||
| 107 | __in WCA_WRAPQUERY_HANDLE hWrapQuery | ||
| 108 | ); | ||
| 109 | |||
| 110 | HRESULT ScaWebsInstall( | ||
| 111 | __in IMSAdminBase* piMetabase, | ||
| 112 | __in SCA_WEB* pswList, | ||
| 113 | __in SCA_APPPOOL * psapList | ||
| 114 | ); | ||
| 115 | |||
| 116 | HRESULT ScaWebsUninstall( | ||
| 117 | __in IMSAdminBase* piMetabase, | ||
| 118 | __in SCA_WEB* pswList | ||
| 119 | ); | ||
| 120 | |||
| 121 | void ScaWebsFreeList( | ||
| 122 | __in SCA_WEB* pswHead | ||
| 123 | ); | ||
diff --git a/src/ca/scaweb7.cpp b/src/ca/scaweb7.cpp new file mode 100644 index 00000000..e1893782 --- /dev/null +++ b/src/ca/scaweb7.cpp | |||
| @@ -0,0 +1,952 @@ | |||
| 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 | #include "precomp.h" | ||
| 4 | |||
| 5 | //Adding this because delivery doesn't have the updated specstrings.h that windows build does | ||
| 6 | #ifndef __in_xcount | ||
| 7 | #define __in_xcount(size) | ||
| 8 | #endif | ||
| 9 | |||
| 10 | // prototypes for private helper functions | ||
| 11 | static SCA_WEB7* NewWeb7(); | ||
| 12 | static SCA_WEB7* AddWebToList7( | ||
| 13 | __in SCA_WEB7* pswList, | ||
| 14 | __in SCA_WEB7* psw | ||
| 15 | ); | ||
| 16 | |||
| 17 | static HRESULT ScaWebFindBase7( | ||
| 18 | __in SCA_WEB7* pswList, | ||
| 19 | LPCWSTR wzDescription | ||
| 20 | ); | ||
| 21 | |||
| 22 | static HRESULT ScaWebWrite7( | ||
| 23 | __in SCA_WEB7* psw, | ||
| 24 | __in SCA_APPPOOL * psapList | ||
| 25 | ); | ||
| 26 | |||
| 27 | static HRESULT ScaWebRemove7(__in const SCA_WEB7* psw); | ||
| 28 | |||
| 29 | |||
| 30 | HRESULT ScaWebsRead7( | ||
| 31 | __in SCA_WEB7** ppswList, | ||
| 32 | __in SCA_HTTP_HEADER** ppshhList, | ||
| 33 | __in SCA_WEB_ERROR** ppsweList, | ||
| 34 | __in WCA_WRAPQUERY_HANDLE hUserQuery, | ||
| 35 | __in WCA_WRAPQUERY_HANDLE hWebDirPropQuery, | ||
| 36 | __in WCA_WRAPQUERY_HANDLE hSslCertQuery, | ||
| 37 | __in WCA_WRAPQUERY_HANDLE hWebLogQuery, | ||
| 38 | __in WCA_WRAPQUERY_HANDLE hWebAppQuery, | ||
| 39 | __in WCA_WRAPQUERY_HANDLE hWebAppExtQuery, | ||
| 40 | __inout LPWSTR *ppwzCustomActionData | ||
| 41 | ) | ||
| 42 | { | ||
| 43 | Assert(ppswList); | ||
| 44 | WcaLog(LOGMSG_VERBOSE, "Entering ScaWebsRead7()"); | ||
| 45 | |||
| 46 | HRESULT hr = S_OK; | ||
| 47 | |||
| 48 | MSIHANDLE hRec; | ||
| 49 | MSIHANDLE hRecAddresses; | ||
| 50 | |||
| 51 | WCA_WRAPQUERY_HANDLE hQueryWebSite = NULL; | ||
| 52 | WCA_WRAPQUERY_HANDLE hQueryWebAddress = NULL; | ||
| 53 | |||
| 54 | SCA_WEB7* psw = NULL; | ||
| 55 | LPWSTR pwzData = NULL; | ||
| 56 | |||
| 57 | DWORD dwLen = 0; | ||
| 58 | errno_t error = EINVAL; | ||
| 59 | |||
| 60 | // check to see what tables are available | ||
| 61 | hr = WcaBeginUnwrapQuery(&hQueryWebSite, ppwzCustomActionData); | ||
| 62 | ExitOnFailure(hr, "Failed to unwrap query for ScaWebsRead"); | ||
| 63 | |||
| 64 | hr = WcaBeginUnwrapQuery(&hQueryWebAddress, ppwzCustomActionData); | ||
| 65 | ExitOnFailure(hr, "Failed to unwrap query for ScaWebsRead"); | ||
| 66 | |||
| 67 | |||
| 68 | if (0 == WcaGetQueryRecords(hQueryWebSite) || 0 == WcaGetQueryRecords(hQueryWebAddress)) | ||
| 69 | { | ||
| 70 | WcaLog(LOGMSG_VERBOSE, "Required tables not present"); | ||
| 71 | ExitFunction1(hr = S_FALSE); | ||
| 72 | } | ||
| 73 | |||
| 74 | // loop through all the webs | ||
| 75 | while (S_OK == (hr = WcaFetchWrappedRecord(hQueryWebSite, &hRec))) | ||
| 76 | { | ||
| 77 | psw = NewWeb7(); | ||
| 78 | if (!psw) | ||
| 79 | { | ||
| 80 | hr = E_OUTOFMEMORY; | ||
| 81 | break; | ||
| 82 | } | ||
| 83 | |||
| 84 | // get the darwin information | ||
| 85 | hr = WcaGetRecordString(hRec, wqWeb, &pwzData); | ||
| 86 | ExitOnFailure(hr, "Failed to get Web"); | ||
| 87 | hr = ::StringCchCopyW(psw->wzKey, countof(psw->wzKey), pwzData); | ||
| 88 | ExitOnFailure(hr, "Failed to copy key string to web object"); | ||
| 89 | |||
| 90 | // get component install state | ||
| 91 | hr = WcaGetRecordString(hRec, wqComponent, &pwzData); | ||
| 92 | ExitOnFailure(hr, "Failed to get Component for Web"); | ||
| 93 | hr = ::StringCchCopyW(psw->wzComponent, countof(psw->wzComponent), pwzData); | ||
| 94 | ExitOnFailure(hr, "Failed to copy component string to web object"); | ||
| 95 | if (*(psw->wzComponent)) | ||
| 96 | { | ||
| 97 | psw->fHasComponent = TRUE; | ||
| 98 | |||
| 99 | hr = WcaGetRecordInteger(hRec, wqInstalled, (int *)&psw->isInstalled); | ||
| 100 | ExitOnFailure(hr, "Failed to get web Component's installed state"); | ||
| 101 | |||
| 102 | WcaGetRecordInteger(hRec, wqAction, (int *)&psw->isAction); | ||
| 103 | ExitOnFailure(hr, "Failed to get web Component's action state"); | ||
| 104 | } | ||
| 105 | |||
| 106 | // Get the web's description. | ||
| 107 | hr = WcaGetRecordString(hRec, wqDescription, &pwzData); | ||
| 108 | ExitOnFailure(hr, "Failed to get Description for Web"); | ||
| 109 | hr = ::StringCchCopyW(psw->wzDescription, countof(psw->wzDescription), pwzData); | ||
| 110 | ExitOnFailure(hr, "Failed to copy description string to web object"); | ||
| 111 | |||
| 112 | //get web's site Id | ||
| 113 | hr = WcaGetRecordInteger(hRec, wqId, &psw->iSiteId); | ||
| 114 | ExitOnFailure(hr, "Failed to get SiteId for Web"); | ||
| 115 | |||
| 116 | // get the web's key address (Bindings) | ||
| 117 | hr = WcaGetRecordString(hRec, wqAddress, &pwzData); | ||
| 118 | ExitOnFailure(hr, "Failed to get Address for Web"); | ||
| 119 | hr = ::StringCchCopyW(psw->swaBinding.wzKey, countof(psw->swaBinding.wzKey), pwzData); | ||
| 120 | ExitOnFailure(hr, "Failed to copy web binding key"); | ||
| 121 | |||
| 122 | hr = WcaGetRecordString(hRec, wqIP, &pwzData); | ||
| 123 | ExitOnFailure(hr, "Failed to get IP for Web"); | ||
| 124 | hr = ::StringCchCopyW(psw->swaBinding.wzIP, countof(psw->swaBinding.wzIP), pwzData); | ||
| 125 | ExitOnFailure(hr, "Failed to copy web IP"); | ||
| 126 | |||
| 127 | hr = WcaGetRecordString(hRec, wqPort, &pwzData); | ||
| 128 | ExitOnFailure(hr, "Failed to get Web Address port"); | ||
| 129 | psw->swaBinding.iPort = wcstol(pwzData, NULL, 10); | ||
| 130 | |||
| 131 | hr = WcaGetRecordString(hRec, wqHeader, &pwzData); | ||
| 132 | ExitOnFailure(hr, "Failed to get Header for Web"); | ||
| 133 | hr = ::StringCchCopyW(psw->swaBinding.wzHeader, countof(psw->swaBinding.wzHeader), pwzData); | ||
| 134 | ExitOnFailure(hr, "Failed to copy web header"); | ||
| 135 | |||
| 136 | hr = WcaGetRecordInteger(hRec, wqSecure, &psw->swaBinding.fSecure); | ||
| 137 | ExitOnFailure(hr, "Failed to get if Web is secure"); | ||
| 138 | if (S_FALSE == hr) | ||
| 139 | { | ||
| 140 | psw->swaBinding.fSecure = FALSE; | ||
| 141 | } | ||
| 142 | |||
| 143 | // look to see if site exists | ||
| 144 | dwLen = METADATA_MAX_NAME_LEN; | ||
| 145 | hr = ScaWebFindBase7(*ppswList, psw->wzDescription); | ||
| 146 | |||
| 147 | // If we didn't find a web in memory, ignore it - during execute CA | ||
| 148 | // if the site truly does not exist then there will be an error. | ||
| 149 | if (S_OK == hr) | ||
| 150 | { | ||
| 151 | // site exists in config | ||
| 152 | psw->fBaseExists = TRUE; | ||
| 153 | } | ||
| 154 | else if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr) | ||
| 155 | { | ||
| 156 | hr = S_OK; | ||
| 157 | |||
| 158 | // site does not exists in config | ||
| 159 | psw->fBaseExists = FALSE; | ||
| 160 | } | ||
| 161 | ExitOnFailure(hr, "Failed to find web site"); | ||
| 162 | |||
| 163 | // get any extra web addresses | ||
| 164 | WcaFetchWrappedReset(hQueryWebAddress); | ||
| 165 | |||
| 166 | while (S_OK == (hr = WcaFetchWrappedRecordWhereString(hQueryWebAddress, 2, psw->wzKey, &hRecAddresses))) | ||
| 167 | { | ||
| 168 | if (MAX_ADDRESSES_PER_WEB <= psw->cExtraAddresses) | ||
| 169 | { | ||
| 170 | hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); | ||
| 171 | ExitOnFailure(hr, "Failure to get more extra web addresses, max exceeded."); | ||
| 172 | } | ||
| 173 | |||
| 174 | hr = WcaGetRecordString(hRecAddresses, waqAddress, &pwzData); | ||
| 175 | ExitOnFailure(hr, "Failed to get extra web Address"); | ||
| 176 | |||
| 177 | // if this isn't the key address add it | ||
| 178 | if (0 != lstrcmpW(pwzData, psw->swaBinding.wzKey)) | ||
| 179 | { | ||
| 180 | hr = ::StringCchCopyW(psw->swaExtraAddresses[psw->cExtraAddresses].wzKey, | ||
| 181 | countof(psw->swaExtraAddresses[psw->cExtraAddresses].wzKey), pwzData); | ||
| 182 | ExitOnFailure(hr, "Failed to copy web binding key"); | ||
| 183 | |||
| 184 | hr = WcaGetRecordString(hRecAddresses, waqIP, &pwzData); | ||
| 185 | ExitOnFailure(hr, "Failed to get extra web IP"); | ||
| 186 | hr = ::StringCchCopyW(psw->swaExtraAddresses[psw->cExtraAddresses].wzIP, countof(psw->swaExtraAddresses[psw->cExtraAddresses].wzIP), pwzData); | ||
| 187 | ExitOnFailure(hr, "Failed to copy web binding IP"); | ||
| 188 | |||
| 189 | hr = WcaGetRecordString(hRecAddresses, waqPort, &pwzData); | ||
| 190 | ExitOnFailure(hr, "Failed to get port for extra web IP"); | ||
| 191 | psw->swaExtraAddresses[psw->cExtraAddresses].iPort= wcstol(pwzData, NULL, 10); | ||
| 192 | |||
| 193 | // errno is set to ERANGE if overflow or underflow occurs | ||
| 194 | _get_errno(&error); | ||
| 195 | |||
| 196 | if (ERANGE == error) | ||
| 197 | { | ||
| 198 | hr = E_INVALIDARG; | ||
| 199 | ExitOnFailure(hr, "Failed to convert web Port address"); | ||
| 200 | } | ||
| 201 | |||
| 202 | hr = WcaGetRecordString(hRecAddresses, waqHeader, &pwzData); | ||
| 203 | ExitOnFailure(hr, "Failed to get header for extra web IP"); | ||
| 204 | hr = ::StringCchCopyW(psw->swaExtraAddresses[psw->cExtraAddresses].wzHeader, countof(psw->swaExtraAddresses[psw->cExtraAddresses].wzHeader), pwzData); | ||
| 205 | ExitOnFailure(hr, "Failed to copy web binding header"); | ||
| 206 | |||
| 207 | hr = WcaGetRecordInteger(hRecAddresses, waqSecure, &psw->swaExtraAddresses[psw->cExtraAddresses].fSecure); | ||
| 208 | ExitOnFailure(hr, "Failed to get if secure extra web IP"); | ||
| 209 | if (S_FALSE == hr) | ||
| 210 | { | ||
| 211 | psw->swaExtraAddresses[psw->cExtraAddresses].fSecure = FALSE; | ||
| 212 | } | ||
| 213 | |||
| 214 | ++psw->cExtraAddresses; | ||
| 215 | } | ||
| 216 | } | ||
| 217 | |||
| 218 | if (E_NOMOREITEMS == hr) | ||
| 219 | { | ||
| 220 | hr = S_OK; | ||
| 221 | } | ||
| 222 | ExitOnFailure(hr, "Failure occured while getting extra web addresses"); | ||
| 223 | |||
| 224 | // | ||
| 225 | // Connection time out | ||
| 226 | // | ||
| 227 | hr = WcaGetRecordInteger(hRec, wqConnectionTimeout, &psw->iConnectionTimeout); | ||
| 228 | ExitOnFailure(hr, "Failed to get connection timeout for Web"); | ||
| 229 | |||
| 230 | if (psw->fHasComponent) // If we're installing it, it needs a dir | ||
| 231 | { | ||
| 232 | // get the web's directory | ||
| 233 | if (INSTALLSTATE_SOURCE == psw->isAction) | ||
| 234 | { | ||
| 235 | hr = WcaGetRecordString(hRec, wqSourcePath, &pwzData); | ||
| 236 | } | ||
| 237 | else | ||
| 238 | { | ||
| 239 | hr = WcaGetRecordString(hRec, wqTargetPath, &pwzData); | ||
| 240 | } | ||
| 241 | ExitOnFailure(hr, "Failed to get Source/TargetPath for Directory"); | ||
| 242 | |||
| 243 | dwLen = lstrlenW(pwzData); | ||
| 244 | // remove trailing backslash | ||
| 245 | if (dwLen > 0 && pwzData[dwLen-1] == L'\\') | ||
| 246 | { | ||
| 247 | pwzData[dwLen-1] = 0; | ||
| 248 | } | ||
| 249 | hr = ::StringCchCopyW(psw->wzDirectory, countof(psw->wzDirectory), pwzData); | ||
| 250 | ExitOnFailure(hr, "Failed to copy web dir: '%ls'", pwzData); | ||
| 251 | |||
| 252 | } | ||
| 253 | |||
| 254 | hr = WcaGetRecordInteger(hRec, wqState, &psw->iState); | ||
| 255 | ExitOnFailure(hr, "Failed to get state for Web"); | ||
| 256 | |||
| 257 | hr = WcaGetRecordInteger(hRec, wqAttributes, &psw->iAttributes); | ||
| 258 | ExitOnFailure(hr, "Failed to get attributes for Web"); | ||
| 259 | |||
| 260 | // get the dir properties for this web | ||
| 261 | hr = WcaGetRecordString(hRec, wqProperties, &pwzData); | ||
| 262 | ExitOnFailure(hr, "Failed to get directory properties for Web"); | ||
| 263 | if (*pwzData) | ||
| 264 | { | ||
| 265 | hr = ScaGetWebDirProperties(pwzData, hUserQuery, hWebDirPropQuery, &psw->swp); | ||
| 266 | ExitOnFailure(hr, "Failed to get directory properties for Web"); | ||
| 267 | |||
| 268 | psw->fHasProperties = TRUE; | ||
| 269 | } | ||
| 270 | |||
| 271 | // get the application information for this web | ||
| 272 | hr = WcaGetRecordString(hRec, wqApplication, &pwzData); | ||
| 273 | ExitOnFailure(hr, "Failed to get application identifier for Web"); | ||
| 274 | if (*pwzData) | ||
| 275 | { | ||
| 276 | hr = ScaGetWebApplication(NULL, pwzData, hWebAppQuery, hWebAppExtQuery, &psw->swapp); | ||
| 277 | ExitOnFailure(hr, "Failed to get application for Web"); | ||
| 278 | |||
| 279 | psw->fHasApplication = TRUE; | ||
| 280 | } | ||
| 281 | |||
| 282 | // get the SSL certificates | ||
| 283 | hr = ScaSslCertificateRead(psw->wzKey, hSslCertQuery, &(psw->pswscList)); | ||
| 284 | ExitOnFailure(hr, "Failed to get SSL Certificates."); | ||
| 285 | |||
| 286 | // get the custom headers | ||
| 287 | if (*ppshhList) | ||
| 288 | { | ||
| 289 | hr = ScaGetHttpHeader(hhptWeb, psw->wzKey, ppshhList, &(psw->pshhList)); | ||
| 290 | ExitOnFailure(hr, "Failed to get Custom HTTP Headers"); | ||
| 291 | } | ||
| 292 | |||
| 293 | // get the errors | ||
| 294 | if (*ppsweList) | ||
| 295 | { | ||
| 296 | hr = ScaGetWebError(weptWeb, psw->wzKey, ppsweList, &(psw->psweList)); | ||
| 297 | ExitOnFailure(hr, "Failed to get Custom Errors"); | ||
| 298 | } | ||
| 299 | |||
| 300 | // get the log information for this web | ||
| 301 | hr = WcaGetRecordString(hRec, wqLog, &pwzData); | ||
| 302 | ExitOnFailure(hr, "Failed to get log identifier for Web"); | ||
| 303 | if (*pwzData) | ||
| 304 | { | ||
| 305 | hr = ScaGetWebLog7(pwzData, hWebLogQuery, &psw->swl); | ||
| 306 | ExitOnFailure(hr, "Failed to get Log for Web."); | ||
| 307 | psw->fHasLog = TRUE; | ||
| 308 | } | ||
| 309 | |||
| 310 | *ppswList = AddWebToList7(*ppswList, psw); | ||
| 311 | psw = NULL; // set the web NULL so it doesn't accidentally get freed below | ||
| 312 | } | ||
| 313 | |||
| 314 | if (E_NOMOREITEMS == hr) | ||
| 315 | { | ||
| 316 | hr = S_OK; | ||
| 317 | } | ||
| 318 | |||
| 319 | LExit: | ||
| 320 | // if anything was left over after an error clean it all up | ||
| 321 | WcaFinishUnwrapQuery(hQueryWebSite); | ||
| 322 | WcaFinishUnwrapQuery(hQueryWebAddress); | ||
| 323 | |||
| 324 | ScaWebsFreeList7(psw); | ||
| 325 | |||
| 326 | ReleaseStr(pwzData); | ||
| 327 | WcaLog(LOGMSG_VERBOSE, "Exiting ScaWebsRead7()"); | ||
| 328 | |||
| 329 | return hr; | ||
| 330 | } | ||
| 331 | |||
| 332 | BOOL CompareBinding( | ||
| 333 | __in IAppHostElement* pBinding, | ||
| 334 | __in LPVOID pContext | ||
| 335 | ) | ||
| 336 | { | ||
| 337 | BOOL fFound = FALSE; | ||
| 338 | HRESULT hr = S_OK; | ||
| 339 | LPWSTR pwzBindingInfo = NULL; | ||
| 340 | SCA_WEB7* psw = (SCA_WEB7*)pContext; | ||
| 341 | |||
| 342 | hr = Iis7GetPropertyString(pBinding, IIS_CONFIG_BINDINGINFO, &pwzBindingInfo); | ||
| 343 | ExitOnFailure(hr, "Failed to get bindinginfo for binding element"); | ||
| 344 | |||
| 345 | LPWSTR pwzExists = pwzBindingInfo; | ||
| 346 | // Break down the address into its constituent parts (IP:Port:Header). | ||
| 347 | // Taken from IIS6 CA code for compatibility | ||
| 348 | while (S_OK == hr && *pwzExists) | ||
| 349 | { | ||
| 350 | LPCWSTR pwzIPExists = pwzExists; | ||
| 351 | pwzExists = const_cast<LPWSTR>(wcsstr(pwzIPExists, L":")); | ||
| 352 | if (NULL == pwzExists) | ||
| 353 | { | ||
| 354 | ExitFunction(); | ||
| 355 | } | ||
| 356 | *pwzExists = L'\0'; | ||
| 357 | |||
| 358 | LPCWSTR pwzPortExists = pwzExists + 1; | ||
| 359 | pwzExists = const_cast<LPWSTR>(wcsstr(pwzPortExists, L":")); | ||
| 360 | if (NULL == pwzExists) | ||
| 361 | { | ||
| 362 | ExitFunction(); | ||
| 363 | } | ||
| 364 | *pwzExists = L'\0'; | ||
| 365 | int iPortExists = wcstol(pwzPortExists, NULL, 10); | ||
| 366 | |||
| 367 | LPCWSTR pwzHeaderExists = pwzExists + 1; | ||
| 368 | |||
| 369 | BOOL fIpMatches = (0 == lstrcmpW(psw->swaBinding.wzIP, pwzIPExists)); // Explicit IP match | ||
| 370 | fIpMatches |= (0 == lstrcmpW(psw->swaBinding.wzIP, L"*")); // Authored * matches any IP | ||
| 371 | fIpMatches |= ('\0' != psw->swaBinding.wzIP) && // Unauthored IP | ||
| 372 | (0 == lstrcmpW(pwzIPExists, L"*")); // matches the All Unassigned IP : '*' | ||
| 373 | |||
| 374 | // compare the passed in address with the address listed for this web | ||
| 375 | if (fIpMatches && psw->swaBinding.iPort == iPortExists && | ||
| 376 | 0 == lstrcmpW(psw->swaBinding.wzHeader, pwzHeaderExists)) | ||
| 377 | { | ||
| 378 | fFound = TRUE; | ||
| 379 | break; | ||
| 380 | } | ||
| 381 | |||
| 382 | // move to the next block of data, this may move beyond the available | ||
| 383 | // data and exit the while loop above. | ||
| 384 | pwzExists = const_cast<LPWSTR>(pwzHeaderExists + lstrlenW(pwzHeaderExists)); | ||
| 385 | } | ||
| 386 | |||
| 387 | LExit: | ||
| 388 | WcaLog(LOGMSG_VERBOSE, "Site with binding %ls %s a match", pwzBindingInfo, fFound ? "is" : "is not"); | ||
| 389 | ReleaseNullStr(pwzBindingInfo); | ||
| 390 | return fFound; | ||
| 391 | } | ||
| 392 | |||
| 393 | BOOL EnumSiteCompareBinding( | ||
| 394 | __in IAppHostElement* pSite, | ||
| 395 | __in LPVOID pContext | ||
| 396 | ) | ||
| 397 | { | ||
| 398 | BOOL fFound = FALSE; | ||
| 399 | HRESULT hr = S_OK; | ||
| 400 | SCA_WEB7* psw = (SCA_WEB7*)pContext; | ||
| 401 | IAppHostChildElementCollection *pSiteChildren = NULL; | ||
| 402 | IAppHostElement *pBindings = NULL; | ||
| 403 | IAppHostElementCollection *pBindingsCollection = NULL; | ||
| 404 | IAppHostElement *pBinding = NULL; | ||
| 405 | VARIANT vtProp; | ||
| 406 | VariantInit(&vtProp); | ||
| 407 | |||
| 408 | hr = pSite->get_ChildElements(&pSiteChildren); | ||
| 409 | ExitOnFailure(hr, "Failed get site child elements collection"); | ||
| 410 | |||
| 411 | vtProp.vt = VT_BSTR; | ||
| 412 | vtProp.bstrVal = ::SysAllocString(IIS_CONFIG_BINDINGS); | ||
| 413 | hr = pSiteChildren->get_Item(vtProp, &pBindings); | ||
| 414 | ExitOnFailure(hr, "Failed get bindings element"); | ||
| 415 | |||
| 416 | hr = pBindings->get_Collection(&pBindingsCollection); | ||
| 417 | ExitOnFailure(hr, "Failed get bindings collection"); | ||
| 418 | |||
| 419 | WcaLog(LOGMSG_VERBOSE, "Searching for site with binding %ls:%d:%ls", psw->swaBinding.wzIP, psw->swaBinding.iPort, psw->swaBinding.wzHeader); | ||
| 420 | |||
| 421 | hr = Iis7EnumAppHostElements(pBindingsCollection, CompareBinding, psw, &pBinding, NULL); | ||
| 422 | ExitOnFailure(hr, "Failed search bindings collection"); | ||
| 423 | |||
| 424 | fFound = NULL != pBinding; | ||
| 425 | LExit: | ||
| 426 | VariantClear(&vtProp); | ||
| 427 | ReleaseNullObject(pSiteChildren); | ||
| 428 | ReleaseNullObject(pBindings); | ||
| 429 | ReleaseNullObject(pBindingsCollection); | ||
| 430 | ReleaseNullObject(pBinding); | ||
| 431 | return fFound; | ||
| 432 | } | ||
| 433 | |||
| 434 | HRESULT ScaWebSearch7( | ||
| 435 | __in SCA_WEB7* psw, | ||
| 436 | __deref_out_z_opt LPWSTR* pswWeb, | ||
| 437 | __out_opt BOOL* pfFound | ||
| 438 | ) | ||
| 439 | { | ||
| 440 | HRESULT hr = S_OK; | ||
| 441 | BOOL fInitializedCom = FALSE; | ||
| 442 | BSTR bstrSites = NULL; | ||
| 443 | BSTR bstrAppHostRoot = NULL; | ||
| 444 | IAppHostAdminManager *pAdminMgr = NULL; | ||
| 445 | IAppHostElement *pSites = NULL; | ||
| 446 | IAppHostElementCollection *pCollection = NULL; | ||
| 447 | IAppHostElement *pSite = NULL; | ||
| 448 | |||
| 449 | if (NULL != pswWeb) | ||
| 450 | { | ||
| 451 | ReleaseNullStr(*pswWeb); | ||
| 452 | } | ||
| 453 | |||
| 454 | if (NULL != pfFound) | ||
| 455 | { | ||
| 456 | *pfFound = FALSE; | ||
| 457 | } | ||
| 458 | |||
| 459 | hr = ::CoInitialize(NULL); | ||
| 460 | ExitOnFailure(hr, "Failed to initialize COM"); | ||
| 461 | fInitializedCom = TRUE; | ||
| 462 | |||
| 463 | hr = CoCreateInstance(__uuidof(AppHostAdminManager), NULL, CLSCTX_INPROC_SERVER, __uuidof(IAppHostAdminManager), reinterpret_cast<void**> (&pAdminMgr)); | ||
| 464 | if (REGDB_E_CLASSNOTREG == hr) | ||
| 465 | { | ||
| 466 | WcaLog(LOGMSG_VERBOSE, "AppHostAdminManager was not registered, cannot find site."); | ||
| 467 | hr = S_OK; | ||
| 468 | ExitFunction(); | ||
| 469 | } | ||
| 470 | ExitOnFailure(hr, "Failed to CoCreate IAppHostAdminManager"); | ||
| 471 | |||
| 472 | bstrSites = ::SysAllocString(IIS_CONFIG_SITES_SECTION); | ||
| 473 | ExitOnNull(bstrSites, hr, E_OUTOFMEMORY, "Failed to allocate sites string."); | ||
| 474 | |||
| 475 | bstrAppHostRoot = ::SysAllocString(IIS_CONFIG_APPHOST_ROOT); | ||
| 476 | ExitOnNull(bstrAppHostRoot, hr, E_OUTOFMEMORY, "Failed to allocate host root string."); | ||
| 477 | |||
| 478 | hr = pAdminMgr->GetAdminSection(bstrSites, bstrAppHostRoot, &pSites); | ||
| 479 | ExitOnFailure(hr, "Failed get sites section"); | ||
| 480 | ExitOnNull(pSites, hr, ERROR_FILE_NOT_FOUND, "Failed get sites section object"); | ||
| 481 | |||
| 482 | hr = pSites->get_Collection(&pCollection); | ||
| 483 | ExitOnFailure(hr, "Failed get sites collection"); | ||
| 484 | |||
| 485 | // not explicitly doing a Description search | ||
| 486 | if (-1 != psw->iSiteId) | ||
| 487 | { | ||
| 488 | if (MSI_NULL_INTEGER == psw->iSiteId) | ||
| 489 | { | ||
| 490 | // Enumerate sites & determine if the binding matches | ||
| 491 | hr = Iis7EnumAppHostElements(pCollection, EnumSiteCompareBinding, psw, &pSite, NULL); | ||
| 492 | ExitOnFailure(hr, "Failed locate site by ID"); | ||
| 493 | } | ||
| 494 | else | ||
| 495 | { | ||
| 496 | // Find a site with ID matches | ||
| 497 | hr = Iis7FindAppHostElementInteger(pCollection, IIS_CONFIG_SITE, IIS_CONFIG_ID, psw->iSiteId, &pSite, NULL); | ||
| 498 | ExitOnFailure(hr, "Failed locate site by ID"); | ||
| 499 | } | ||
| 500 | } | ||
| 501 | |||
| 502 | if (NULL == pSite) | ||
| 503 | { | ||
| 504 | // Find a site with Name that matches | ||
| 505 | hr = Iis7FindAppHostElementString(pCollection, IIS_CONFIG_SITE, IIS_CONFIG_NAME, psw->wzDescription, &pSite, NULL); | ||
| 506 | ExitOnFailure(hr, "Failed locate site by ID"); | ||
| 507 | } | ||
| 508 | |||
| 509 | if (NULL != pSite) | ||
| 510 | { | ||
| 511 | if (NULL != pfFound) | ||
| 512 | { | ||
| 513 | *pfFound = TRUE; | ||
| 514 | } | ||
| 515 | |||
| 516 | if (NULL != pswWeb) | ||
| 517 | { | ||
| 518 | // We found a site, return its description | ||
| 519 | hr = Iis7GetPropertyString(pSite, IIS_CONFIG_NAME, pswWeb); | ||
| 520 | ExitOnFailure(hr, "Failed get site name"); | ||
| 521 | } | ||
| 522 | } | ||
| 523 | LExit: | ||
| 524 | ReleaseNullObject(pAdminMgr); | ||
| 525 | ReleaseNullObject(pSites); | ||
| 526 | ReleaseNullObject(pCollection); | ||
| 527 | ReleaseNullObject(pSite); | ||
| 528 | ReleaseBSTR(bstrAppHostRoot); | ||
| 529 | ReleaseBSTR(bstrSites); | ||
| 530 | |||
| 531 | if (fInitializedCom) | ||
| 532 | { | ||
| 533 | ::CoUninitialize(); | ||
| 534 | } | ||
| 535 | return hr; | ||
| 536 | } | ||
| 537 | |||
| 538 | |||
| 539 | HRESULT ScaWebsGetBase7( | ||
| 540 | __in SCA_WEB7* pswList, | ||
| 541 | __in LPCWSTR pswWebKey, | ||
| 542 | __out_ecount(cchDest) LPWSTR pswWeb, | ||
| 543 | __in DWORD_PTR cchDest | ||
| 544 | ) | ||
| 545 | { | ||
| 546 | HRESULT hr = S_OK; | ||
| 547 | BOOL fFound = FALSE; | ||
| 548 | SCA_WEB7* psw = pswList; | ||
| 549 | LPWSTR wzSiteName = NULL; | ||
| 550 | |||
| 551 | *pswWeb = '/0'; | ||
| 552 | |||
| 553 | //looking for psw->wzKey == pswWebKey | ||
| 554 | while(psw) | ||
| 555 | { | ||
| 556 | if (0 == wcscmp(pswWebKey, psw->wzKey)) | ||
| 557 | { | ||
| 558 | fFound = TRUE; | ||
| 559 | break; | ||
| 560 | } | ||
| 561 | psw = psw->pswNext; | ||
| 562 | } | ||
| 563 | |||
| 564 | if (!fFound) | ||
| 565 | { | ||
| 566 | ExitFunction1(hr = S_FALSE); | ||
| 567 | } | ||
| 568 | |||
| 569 | // Search if we're not installing the site | ||
| 570 | if (!psw->fHasComponent || (psw->iAttributes & SWATTRIB_NOCONFIGUREIFEXISTS)) | ||
| 571 | { | ||
| 572 | // We are not installing this website. Search for it in IIS config | ||
| 573 | hr = ScaWebSearch7(psw, &wzSiteName, NULL); | ||
| 574 | ExitOnFailure(hr, "Failed to search for Website"); | ||
| 575 | |||
| 576 | if (NULL != wzSiteName) | ||
| 577 | { | ||
| 578 | hr = ::StringCchCopyW(pswWeb, cchDest, wzSiteName); | ||
| 579 | ExitOnFailure(hr, "Failed to set Website description for located Website"); | ||
| 580 | } | ||
| 581 | } | ||
| 582 | |||
| 583 | if ('/0' == *pswWeb) | ||
| 584 | { | ||
| 585 | WcaLog(LOGMSG_VERBOSE, "Could not find Web: %ls, defaulting to %ls", psw->wzKey, psw->wzDescription); | ||
| 586 | // Default to the provided description, the Exec CA will locate by description | ||
| 587 | hr = ::StringCchCopyW(pswWeb, cchDest, psw->wzDescription); | ||
| 588 | ExitOnFailure(hr, "Failed to set Website description to default"); | ||
| 589 | } | ||
| 590 | LExit: | ||
| 591 | ReleaseNullStr(wzSiteName); | ||
| 592 | return hr; | ||
| 593 | } | ||
| 594 | |||
| 595 | HRESULT ScaWebsInstall7( | ||
| 596 | __in SCA_WEB7* pswList, | ||
| 597 | __in SCA_APPPOOL * psapList | ||
| 598 | ) | ||
| 599 | { | ||
| 600 | HRESULT hr = S_OK; | ||
| 601 | SCA_WEB7* psw = pswList; | ||
| 602 | |||
| 603 | while (psw) | ||
| 604 | { | ||
| 605 | // if we are installing the web site | ||
| 606 | if (psw->fHasComponent && WcaIsInstalling(psw->isInstalled, psw->isAction)) | ||
| 607 | { | ||
| 608 | hr = ScaWebWrite7(psw, psapList); | ||
| 609 | ExitOnFailure(hr, "failed to write web '%ls' to metabase", psw->wzKey); | ||
| 610 | } | ||
| 611 | |||
| 612 | psw = psw->pswNext; | ||
| 613 | } | ||
| 614 | |||
| 615 | LExit: | ||
| 616 | return hr; | ||
| 617 | } | ||
| 618 | |||
| 619 | |||
| 620 | HRESULT ScaWebsUninstall7( | ||
| 621 | __in SCA_WEB7* pswList | ||
| 622 | ) | ||
| 623 | { | ||
| 624 | HRESULT hr = S_OK; | ||
| 625 | SCA_WEB7* psw = pswList; | ||
| 626 | |||
| 627 | while (psw) | ||
| 628 | { | ||
| 629 | if (psw->fHasComponent && WcaIsUninstalling(psw->isInstalled, psw->isAction)) | ||
| 630 | { | ||
| 631 | // If someone | ||
| 632 | hr = ScaWebRemove7(psw); | ||
| 633 | ExitOnFailure(hr, "Failed to remove web '%ls' ", psw->wzKey); | ||
| 634 | } | ||
| 635 | |||
| 636 | psw = psw->pswNext; | ||
| 637 | } | ||
| 638 | |||
| 639 | LExit: | ||
| 640 | return hr; | ||
| 641 | } | ||
| 642 | |||
| 643 | |||
| 644 | void ScaWebsFreeList7(__in SCA_WEB7* pswList) | ||
| 645 | { | ||
| 646 | SCA_WEB7* pswDelete = pswList; | ||
| 647 | while (pswList) | ||
| 648 | { | ||
| 649 | pswDelete = pswList; | ||
| 650 | pswList = pswList->pswNext; | ||
| 651 | |||
| 652 | // Free the SSL, headers and errors list first | ||
| 653 | ScaSslCertificateFreeList(pswDelete->pswscList); | ||
| 654 | ScaHttpHeaderFreeList(pswDelete->pshhList); | ||
| 655 | ScaWebErrorFreeList(pswDelete->psweList); | ||
| 656 | |||
| 657 | MemFree(pswDelete); | ||
| 658 | } | ||
| 659 | } | ||
| 660 | |||
| 661 | |||
| 662 | // private helper functions | ||
| 663 | |||
| 664 | static SCA_WEB7* NewWeb7() | ||
| 665 | { | ||
| 666 | SCA_WEB7* psw = (SCA_WEB7*)MemAlloc(sizeof(SCA_WEB7), TRUE); | ||
| 667 | Assert(psw); | ||
| 668 | return psw; | ||
| 669 | } | ||
| 670 | |||
| 671 | |||
| 672 | static SCA_WEB7* AddWebToList7( | ||
| 673 | __in SCA_WEB7* pswList, | ||
| 674 | __in SCA_WEB7* psw | ||
| 675 | ) | ||
| 676 | { | ||
| 677 | if (pswList) | ||
| 678 | { | ||
| 679 | SCA_WEB7* pswTemp = pswList; | ||
| 680 | while (pswTemp->pswNext) | ||
| 681 | { | ||
| 682 | pswTemp = pswTemp->pswNext; | ||
| 683 | } | ||
| 684 | |||
| 685 | pswTemp->pswNext = psw; | ||
| 686 | } | ||
| 687 | else | ||
| 688 | { | ||
| 689 | pswList = psw; | ||
| 690 | } | ||
| 691 | |||
| 692 | return pswList; | ||
| 693 | } | ||
| 694 | |||
| 695 | |||
| 696 | static HRESULT ScaWebFindBase7( | ||
| 697 | __in SCA_WEB7* pswList, | ||
| 698 | __in_z LPCWSTR wzDescription | ||
| 699 | ) | ||
| 700 | { | ||
| 701 | HRESULT hr = S_OK; | ||
| 702 | BOOL fFound = FALSE; | ||
| 703 | |||
| 704 | // try to find the web in memory first | ||
| 705 | for (SCA_WEB7* psw = pswList; psw; psw = psw->pswNext) | ||
| 706 | { | ||
| 707 | if (0 == wcscmp(wzDescription, psw->wzDescription)) | ||
| 708 | { | ||
| 709 | fFound = TRUE; | ||
| 710 | break; | ||
| 711 | } | ||
| 712 | } | ||
| 713 | |||
| 714 | if (!fFound) | ||
| 715 | { | ||
| 716 | hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); | ||
| 717 | } | ||
| 718 | |||
| 719 | return hr; | ||
| 720 | } | ||
| 721 | |||
| 722 | |||
| 723 | static HRESULT ScaWebWrite7( | ||
| 724 | __in SCA_WEB7* psw, | ||
| 725 | __in SCA_APPPOOL * psapList | ||
| 726 | ) | ||
| 727 | { | ||
| 728 | HRESULT hr = S_OK; | ||
| 729 | |||
| 730 | BOOL fExists = FALSE; | ||
| 731 | UINT ui = 0; | ||
| 732 | WCHAR wzIP[64]; | ||
| 733 | WCHAR wzBinding[1024]; | ||
| 734 | WCHAR wzAppPoolName[MAX_PATH]; | ||
| 735 | |||
| 736 | // | ||
| 737 | // determine if site must be new | ||
| 738 | // | ||
| 739 | if (psw->iAttributes & SWATTRIB_NOCONFIGUREIFEXISTS) | ||
| 740 | { | ||
| 741 | // Check if site already exists. | ||
| 742 | hr = ScaWebSearch7(psw, NULL, &fExists); | ||
| 743 | ExitOnFailure(hr, "Failed to search for web: %ls", psw->wzKey); | ||
| 744 | |||
| 745 | if (fExists) | ||
| 746 | { | ||
| 747 | hr = S_FALSE; | ||
| 748 | WcaLog(LOGMSG_VERBOSE, "Skipping configuration of existing web: %ls", psw->wzKey); | ||
| 749 | ExitFunction(); | ||
| 750 | } | ||
| 751 | } | ||
| 752 | |||
| 753 | //create a site | ||
| 754 | hr = ScaWriteConfigID(IIS_SITE); | ||
| 755 | ExitOnFailure(hr, "Failed write site ID"); | ||
| 756 | |||
| 757 | hr = ScaWriteConfigID(IIS_CREATE); | ||
| 758 | ExitOnFailure(hr, "Failed write site ID create action"); | ||
| 759 | |||
| 760 | //Site Name | ||
| 761 | hr = ScaWriteConfigString(psw->wzDescription); //Site Name | ||
| 762 | ExitOnFailure(hr, "Failed write site desc"); | ||
| 763 | |||
| 764 | //Site Id -- value is MSI_NULL_INTEGER if not set in WIX | ||
| 765 | hr = ScaWriteConfigInteger(psw->iSiteId); //SiteID | ||
| 766 | ExitOnFailure(hr, "Failed write site id value"); | ||
| 767 | |||
| 768 | //Site Auto Start -- value is MSI_NULL_INTEGER if not set in WIX | ||
| 769 | hr = ScaWriteConfigInteger(psw->iState); // serverAutoStart | ||
| 770 | ExitOnFailure(hr, "Failed write site autostart"); | ||
| 771 | |||
| 772 | hr = ScaWriteConfigInteger(psw->iConnectionTimeout); //limits/connectionTimeout | ||
| 773 | ExitOnFailure(hr, "Failed write site timeout"); | ||
| 774 | |||
| 775 | //create default application | ||
| 776 | hr = ScaWriteConfigID(IIS_APPLICATION); | ||
| 777 | ExitOnFailure(hr, "Failed write app ID"); | ||
| 778 | hr = ScaWriteConfigID(IIS_CREATE); | ||
| 779 | ExitOnFailure(hr, "Failed write app action ID"); | ||
| 780 | hr = ScaWriteConfigString(psw->wzDescription); //site name key | ||
| 781 | ExitOnFailure(hr, "Failed write app desc"); | ||
| 782 | hr = ScaWriteConfigString(L"/"); // App Path (default) | ||
| 783 | ExitOnFailure(hr, "Failed write app def path /"); | ||
| 784 | |||
| 785 | if (psw->fHasApplication && *psw->swapp.wzAppPool) | ||
| 786 | { | ||
| 787 | hr = ScaFindAppPool7(psw->swapp.wzAppPool, wzAppPoolName, countof(wzAppPoolName), psapList); | ||
| 788 | ExitOnFailure(hr, "Failed to read app pool from application"); | ||
| 789 | |||
| 790 | hr = ScaWriteConfigString(wzAppPoolName); | ||
| 791 | ExitOnFailure(hr, "Failed write app appPool"); | ||
| 792 | } | ||
| 793 | else | ||
| 794 | { | ||
| 795 | hr = ScaWriteConfigString(L""); | ||
| 796 | ExitOnFailure(hr, "Failed write app appPool"); | ||
| 797 | } | ||
| 798 | |||
| 799 | //create vdir for default application | ||
| 800 | hr = ScaWriteConfigID(IIS_VDIR); | ||
| 801 | ExitOnFailure(hr, "Failed write vdir ID"); | ||
| 802 | hr = ScaWriteConfigID(IIS_CREATE); | ||
| 803 | ExitOnFailure(hr, "Failed write vdir action"); | ||
| 804 | hr = ScaWriteConfigString(psw->wzDescription); //site name key | ||
| 805 | ExitOnFailure(hr, "Failed write vdir desc"); | ||
| 806 | hr = ScaWriteConfigString(L"/"); //vdir path (default) | ||
| 807 | ExitOnFailure(hr, "Failed write vdir app"); | ||
| 808 | hr = ScaWriteConfigString(psw->wzDirectory); //physical dir | ||
| 809 | ExitOnFailure(hr, "Failed write vdir dir"); | ||
| 810 | |||
| 811 | //create bindings for site | ||
| 812 | hr = ScaWriteConfigID(IIS_BINDING); | ||
| 813 | ExitOnFailure(hr, "Failed write binding ID"); | ||
| 814 | hr = ScaWriteConfigID(IIS_CREATE); | ||
| 815 | ExitOnFailure(hr, "Failed write binding action ID"); | ||
| 816 | hr = ScaWriteConfigString(psw->wzDescription); //site name key | ||
| 817 | ExitOnFailure(hr, "Failed write binding site key"); | ||
| 818 | |||
| 819 | if (psw->swaBinding.fSecure) | ||
| 820 | { | ||
| 821 | hr = ScaWriteConfigString(L"https"); // binding protocol | ||
| 822 | ExitOnFailure(hr, "Failed write binding https"); | ||
| 823 | } | ||
| 824 | else | ||
| 825 | { | ||
| 826 | hr = ScaWriteConfigString(L"http"); // binding protocol | ||
| 827 | ExitOnFailure(hr, "Failed write binding http"); | ||
| 828 | } | ||
| 829 | |||
| 830 | // set the IP address appropriately | ||
| 831 | if (0 == wcscmp(psw->swaBinding.wzIP, L"*")) | ||
| 832 | { | ||
| 833 | ::ZeroMemory(wzIP, sizeof(wzIP)); | ||
| 834 | } | ||
| 835 | else | ||
| 836 | { | ||
| 837 | #pragma prefast(suppress:26037, "Source string is null terminated - it is populated as target of ::StringCchCopyW") | ||
| 838 | hr = ::StringCchCopyW(wzIP, countof(wzIP), psw->swaBinding.wzIP); | ||
| 839 | ExitOnFailure(hr, "Failed to copy IP string"); | ||
| 840 | } | ||
| 841 | |||
| 842 | hr = ::StringCchPrintfW(wzBinding, countof(wzBinding), L"%s:%d:%s", wzIP, psw->swaBinding.iPort, psw->swaBinding.wzHeader); | ||
| 843 | ExitOnFailure(hr, "Failed to format IP:Port:Header binding string"); | ||
| 844 | |||
| 845 | // write bindings CAData | ||
| 846 | hr = ScaWriteConfigString(wzBinding) ; //binding info | ||
| 847 | ExitOnFailure(hr, "Failed to create web bindings"); | ||
| 848 | |||
| 849 | for (ui = 0; (ui < MAX_ADDRESSES_PER_WEB) && (ui < psw->cExtraAddresses); ++ui) | ||
| 850 | { | ||
| 851 | // set the IP address appropriately | ||
| 852 | if (0 == wcscmp(psw->swaExtraAddresses[ui].wzIP, L"*")) | ||
| 853 | { | ||
| 854 | ::ZeroMemory(wzIP, sizeof(wzIP)); | ||
| 855 | } | ||
| 856 | else | ||
| 857 | { | ||
| 858 | #pragma prefast(suppress:26037, "Source string is null terminated - it is populated as target of ::StringCchCopyW") | ||
| 859 | hr = ::StringCchCopyW(wzIP, countof(wzIP), psw->swaExtraAddresses[ui].wzIP); | ||
| 860 | ExitOnFailure(hr, "Failed to copy web IP"); | ||
| 861 | } | ||
| 862 | hr = ::StringCchPrintfW(wzBinding, countof(wzBinding), L"%s:%d:%s", wzIP, psw->swaExtraAddresses[ui].iPort, psw->swaExtraAddresses[ui].wzHeader); | ||
| 863 | ExitOnFailure(hr, "Failed to copy web IP"); | ||
| 864 | |||
| 865 | //create bindings for site | ||
| 866 | hr = ScaWriteConfigID(IIS_BINDING); | ||
| 867 | ExitOnFailure(hr, "Failed write binding ID"); | ||
| 868 | hr = ScaWriteConfigID(IIS_CREATE); | ||
| 869 | ExitOnFailure(hr, "Failed write binding action"); | ||
| 870 | hr = ScaWriteConfigString(psw->wzDescription); //site name key | ||
| 871 | ExitOnFailure(hr, "Failed write binding web name"); | ||
| 872 | |||
| 873 | if (psw->swaExtraAddresses[ui].fSecure) | ||
| 874 | { | ||
| 875 | hr = ScaWriteConfigString(L"https"); // binding protocol | ||
| 876 | } | ||
| 877 | else | ||
| 878 | { | ||
| 879 | hr = ScaWriteConfigString(L"http"); // binding protocol | ||
| 880 | } | ||
| 881 | ExitOnFailure(hr, "Failed write binding http(s)"); | ||
| 882 | |||
| 883 | // write bindings CAData | ||
| 884 | hr = ScaWriteConfigString(wzBinding) ; //binding info | ||
| 885 | ExitOnFailure(hr, "Failed write binding info"); | ||
| 886 | } | ||
| 887 | |||
| 888 | // write the web dirproperties information | ||
| 889 | if (psw->fHasProperties) | ||
| 890 | { | ||
| 891 | // dir properties are for the default application of the web | ||
| 892 | // with location '/' | ||
| 893 | hr = ScaWriteWebDirProperties7(psw->wzDescription, L"/", &psw->swp); | ||
| 894 | ExitOnFailure(hr, "Failed to write web security information to metabase"); | ||
| 895 | } | ||
| 896 | |||
| 897 | //// write the application information | ||
| 898 | if (psw->fHasApplication) | ||
| 899 | { | ||
| 900 | hr = ScaWriteWebApplication7(psw->wzDescription, L"/", &psw->swapp, psapList); | ||
| 901 | ExitOnFailure(hr, "Failed to write web application information to metabase"); | ||
| 902 | } | ||
| 903 | |||
| 904 | // write the SSL certificate information | ||
| 905 | if (psw->pswscList) | ||
| 906 | { | ||
| 907 | hr = ScaSslCertificateWrite7(psw->wzDescription, psw->pswscList); | ||
| 908 | ExitOnFailure(hr, "Failed to write SSL certificates for Web site: %ls", psw->wzKey); | ||
| 909 | } | ||
| 910 | |||
| 911 | // write the headers | ||
| 912 | if (psw->pshhList) | ||
| 913 | { | ||
| 914 | hr = ScaWriteHttpHeader7(psw->wzDescription, L"/", psw->pshhList); | ||
| 915 | ExitOnFailure(hr, "Failed to write custom HTTP headers for Web site: %ls", psw->wzKey); | ||
| 916 | } | ||
| 917 | |||
| 918 | // write the errors | ||
| 919 | if (psw->psweList) | ||
| 920 | { | ||
| 921 | hr = ScaWriteWebError7(psw->wzDescription, L"/", psw->psweList); | ||
| 922 | ExitOnFailure(hr, "Failed to write custom web errors for Web site: %ls", psw->wzKey); | ||
| 923 | } | ||
| 924 | |||
| 925 | // write the log information to the metabase | ||
| 926 | if (psw->fHasLog) | ||
| 927 | { | ||
| 928 | hr = ScaWriteWebLog7(psw->wzDescription, &psw->swl); | ||
| 929 | ExitOnFailure(hr, "Failed to write web log information to metabase"); | ||
| 930 | } | ||
| 931 | |||
| 932 | LExit: | ||
| 933 | return hr; | ||
| 934 | } | ||
| 935 | |||
| 936 | |||
| 937 | static HRESULT ScaWebRemove7( | ||
| 938 | __in const SCA_WEB7* psw | ||
| 939 | ) | ||
| 940 | { | ||
| 941 | HRESULT hr = S_OK; | ||
| 942 | |||
| 943 | hr = ScaWriteConfigID(IIS_SITE); | ||
| 944 | ExitOnFailure(hr, "Failed write site ID"); | ||
| 945 | hr = ScaWriteConfigID(IIS_DELETE); | ||
| 946 | ExitOnFailure(hr, "Failed write site action"); | ||
| 947 | hr = ScaWriteConfigString(psw->wzDescription); //Site Name | ||
| 948 | ExitOnFailure(hr, "Failed write site name"); | ||
| 949 | |||
| 950 | LExit: | ||
| 951 | return hr; | ||
| 952 | } | ||
diff --git a/src/ca/scaweb7.h b/src/ca/scaweb7.h new file mode 100644 index 00000000..78946756 --- /dev/null +++ b/src/ca/scaweb7.h | |||
| @@ -0,0 +1,97 @@ | |||
| 1 | #pragma once | ||
| 2 | // 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. | ||
| 3 | |||
| 4 | |||
| 5 | #include "scawebapp.h" | ||
| 6 | #include "scawebprop.h" | ||
| 7 | #include "scahttpheader.h" | ||
| 8 | #include "scaweberr.h" | ||
| 9 | #include "scassl.h" | ||
| 10 | #include "scaapppool.h" | ||
| 11 | #include "scaweblog.h" | ||
| 12 | |||
| 13 | // globals | ||
| 14 | #define MAX_ADDRESSES_PER_WEB 10 | ||
| 15 | |||
| 16 | // structs | ||
| 17 | struct SCA_WEB7 | ||
| 18 | { | ||
| 19 | // darwin information | ||
| 20 | WCHAR wzKey[MAX_DARWIN_KEY + 1]; | ||
| 21 | WCHAR wzComponent[MAX_DARWIN_KEY + 1]; | ||
| 22 | BOOL fHasComponent; | ||
| 23 | INSTALLSTATE isInstalled; | ||
| 24 | INSTALLSTATE isAction; | ||
| 25 | |||
| 26 | int iSiteId; | ||
| 27 | |||
| 28 | // metabase information | ||
| 29 | WCHAR wzWebBase[METADATA_MAX_NAME_LEN + 1]; | ||
| 30 | BOOL fBaseExists; | ||
| 31 | |||
| 32 | // iis configuation information | ||
| 33 | SCA_WEB_ADDRESS swaBinding; | ||
| 34 | |||
| 35 | SCA_WEB_ADDRESS swaExtraAddresses[MAX_ADDRESSES_PER_WEB + 1]; | ||
| 36 | DWORD cExtraAddresses; | ||
| 37 | |||
| 38 | WCHAR wzDirectory[MAX_PATH]; | ||
| 39 | WCHAR wzDescription[MAX_DARWIN_COLUMN + 1]; | ||
| 40 | |||
| 41 | int iState; | ||
| 42 | int iAttributes; | ||
| 43 | |||
| 44 | BOOL fHasProperties; | ||
| 45 | SCA_WEB_PROPERTIES swp; | ||
| 46 | |||
| 47 | BOOL fHasApplication; | ||
| 48 | SCA_WEB_APPLICATION swapp; | ||
| 49 | |||
| 50 | BOOL fHasSecurity; | ||
| 51 | int dwAccessPermissions; | ||
| 52 | int iConnectionTimeout; | ||
| 53 | |||
| 54 | SCA_WEB_SSL_CERTIFICATE* pswscList; | ||
| 55 | SCA_HTTP_HEADER* pshhList; | ||
| 56 | SCA_WEB_ERROR* psweList; | ||
| 57 | |||
| 58 | BOOL fHasLog; | ||
| 59 | SCA_WEB_LOG swl; | ||
| 60 | |||
| 61 | SCA_WEB7* pswNext; | ||
| 62 | }; | ||
| 63 | |||
| 64 | |||
| 65 | // prototypes | ||
| 66 | HRESULT ScaWebsRead7( | ||
| 67 | __in SCA_WEB7** ppswList, | ||
| 68 | __in SCA_HTTP_HEADER** ppshhList, | ||
| 69 | __in SCA_WEB_ERROR** ppsweList, | ||
| 70 | __in WCA_WRAPQUERY_HANDLE hUserQuery, | ||
| 71 | __in WCA_WRAPQUERY_HANDLE hWebDirPropQuery, | ||
| 72 | __in WCA_WRAPQUERY_HANDLE hSslCertQuery, | ||
| 73 | __in WCA_WRAPQUERY_HANDLE hWebLogQuery, | ||
| 74 | __in WCA_WRAPQUERY_HANDLE hWebAppQuery, | ||
| 75 | __in WCA_WRAPQUERY_HANDLE hWebAppExtQuery, | ||
| 76 | __inout LPWSTR *ppwzCustomActionData | ||
| 77 | ); | ||
| 78 | |||
| 79 | HRESULT ScaWebsGetBase7( | ||
| 80 | __in SCA_WEB7* pswList, | ||
| 81 | __in LPCWSTR pswWebKey, | ||
| 82 | __out_ecount(cchDest) LPWSTR pswWeb, | ||
| 83 | __in DWORD_PTR cchDest | ||
| 84 | ); | ||
| 85 | |||
| 86 | HRESULT ScaWebsInstall7( | ||
| 87 | __in SCA_WEB7* pswList, | ||
| 88 | __in SCA_APPPOOL * psapList | ||
| 89 | ); | ||
| 90 | |||
| 91 | HRESULT ScaWebsUninstall7( | ||
| 92 | __in SCA_WEB7* pswList | ||
| 93 | ); | ||
| 94 | |||
| 95 | void ScaWebsFreeList7( | ||
| 96 | __in SCA_WEB7* pswHead | ||
| 97 | ); | ||
diff --git a/src/ca/scawebapp.cpp b/src/ca/scawebapp.cpp new file mode 100644 index 00000000..a7e9cf82 --- /dev/null +++ b/src/ca/scawebapp.cpp | |||
| @@ -0,0 +1,194 @@ | |||
| 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 | #include "precomp.h" | ||
| 4 | |||
| 5 | // sql queries | ||
| 6 | enum eWebApplicationQuery { wappqName = 1, wappqIsolation, wappqAllowSession, | ||
| 7 | wappqSessionTimeout, wappqBuffer, wappqParentPaths, | ||
| 8 | wappqDefaultScript, wappqScriptTimeout, | ||
| 9 | wappqServerDebugging, wappqClientDebugging, wappqAppPool, wappqApplication}; | ||
| 10 | |||
| 11 | |||
| 12 | HRESULT ScaGetWebApplication(MSIHANDLE /*hViewApplications*/, | ||
| 13 | LPCWSTR pwzApplication, | ||
| 14 | __in WCA_WRAPQUERY_HANDLE hWebAppQuery, | ||
| 15 | __in WCA_WRAPQUERY_HANDLE hWebAppExtQuery, | ||
| 16 | SCA_WEB_APPLICATION* pswapp) | ||
| 17 | { | ||
| 18 | HRESULT hr = S_OK; | ||
| 19 | |||
| 20 | MSIHANDLE hRec; | ||
| 21 | LPWSTR pwzData = NULL; | ||
| 22 | |||
| 23 | // Reset back to the first record | ||
| 24 | WcaFetchWrappedReset(hWebAppQuery); | ||
| 25 | |||
| 26 | // get the application information | ||
| 27 | hr = WcaFetchWrappedRecordWhereString(hWebAppQuery, wappqApplication, pwzApplication, &hRec); | ||
| 28 | if (S_OK == hr) | ||
| 29 | { | ||
| 30 | // application name | ||
| 31 | hr = WcaGetRecordString(hRec, wappqName, &pwzData); | ||
| 32 | ExitOnFailure(hr, "Failed to get Name of App"); | ||
| 33 | hr = ::StringCchCopyW(pswapp->wzName, countof(pswapp->wzName), pwzData); | ||
| 34 | if (HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER) == hr) | ||
| 35 | { | ||
| 36 | // The application name is sometimes truncated to IIS's supported length, so ignore insufficient buffer errors here | ||
| 37 | WcaLog(LOGMSG_VERBOSE, "Application name \"%ls\" truncated to fit IIS's supported %d-character length", pwzData, MAX_APP_NAME); | ||
| 38 | hr = S_OK; | ||
| 39 | } | ||
| 40 | ExitOnFailure(hr, "Failed to copy name string to webapp object"); | ||
| 41 | |||
| 42 | hr = WcaGetRecordInteger(hRec, wappqIsolation, &pswapp->iIsolation); | ||
| 43 | ExitOnFailure(hr, "Failed to get App isolation: '%ls'", pswapp->wzName); | ||
| 44 | |||
| 45 | hr = WcaGetRecordInteger(hRec, wappqAllowSession, &pswapp->fAllowSessionState); | ||
| 46 | |||
| 47 | hr = WcaGetRecordInteger(hRec, wappqSessionTimeout, &pswapp->iSessionTimeout); | ||
| 48 | |||
| 49 | hr = WcaGetRecordInteger(hRec, wappqBuffer, &pswapp->fBuffer); | ||
| 50 | |||
| 51 | hr = WcaGetRecordInteger(hRec, wappqParentPaths, &pswapp->fParentPaths); | ||
| 52 | |||
| 53 | hr = WcaGetRecordString(hRec, wappqDefaultScript, &pwzData); | ||
| 54 | ExitOnFailure(hr, "Failed to get default scripting language for App: '%ls'", pswapp->wzName); | ||
| 55 | hr = ::StringCchCopyW(pswapp->wzDefaultScript, countof(pswapp->wzDefaultScript), pwzData); | ||
| 56 | ExitOnFailure(hr, "Failed to copy default script string to webapp object"); | ||
| 57 | |||
| 58 | // asp script timeout | ||
| 59 | hr = WcaGetRecordInteger(hRec, wappqScriptTimeout, &pswapp->iScriptTimeout); | ||
| 60 | ExitOnFailure(hr, "Failed to get scripting timeout for App: '%ls'", pswapp->wzName); | ||
| 61 | |||
| 62 | // asp server-side script debugging | ||
| 63 | hr = WcaGetRecordInteger(hRec, wappqServerDebugging, &pswapp->fServerDebugging); | ||
| 64 | |||
| 65 | // asp client-side script debugging | ||
| 66 | hr = WcaGetRecordInteger(hRec, wappqClientDebugging, &pswapp->fClientDebugging); | ||
| 67 | |||
| 68 | hr = WcaGetRecordString(hRec, wappqAppPool, &pwzData); | ||
| 69 | ExitOnFailure(hr, "Failed to get AppPool for App: '%ls'", pswapp->wzName); | ||
| 70 | hr = ::StringCchCopyW(pswapp->wzAppPool, countof(pswapp->wzAppPool), pwzData); | ||
| 71 | ExitOnFailure(hr, "failed to copy AppPool: '%ls' for App: '%ls'", pwzData, pswapp->wzName); | ||
| 72 | |||
| 73 | // app extensions | ||
| 74 | hr = ScaWebAppExtensionsRead(pwzApplication, hWebAppExtQuery, &pswapp->pswappextList); | ||
| 75 | ExitOnFailure(hr, "Failed to read AppExtensions for App: '%ls'", pswapp->wzName); | ||
| 76 | |||
| 77 | hr = S_OK; | ||
| 78 | } | ||
| 79 | else if (E_NOMOREITEMS == hr) | ||
| 80 | { | ||
| 81 | WcaLog(LOGMSG_STANDARD, "Error: Cannot locate IIsWebApplication.Application='%ls'", pwzApplication); | ||
| 82 | hr = E_FAIL; | ||
| 83 | } | ||
| 84 | else | ||
| 85 | ExitOnFailure(hr, "Error matching Application rows"); | ||
| 86 | |||
| 87 | // Let's check that there isn't more than one record found - if there is, throw an assert like WcaFetchSingleRecord() would | ||
| 88 | HRESULT hrTemp = WcaFetchWrappedRecordWhereString(hWebAppQuery, wappqApplication, pwzApplication, &hRec); | ||
| 89 | if (SUCCEEDED(hrTemp)) | ||
| 90 | { | ||
| 91 | AssertSz(E_NOMOREITEMS == hrTemp, "ScaGetWebApplication found more than one record"); | ||
| 92 | } | ||
| 93 | |||
| 94 | LExit: | ||
| 95 | ReleaseStr(pwzData); | ||
| 96 | |||
| 97 | return hr; | ||
| 98 | } | ||
| 99 | |||
| 100 | |||
| 101 | HRESULT ScaWriteWebApplication(IMSAdminBase* piMetabase, LPCWSTR wzRootOfWeb, | ||
| 102 | SCA_WEB_APPLICATION* pswapp, SCA_APPPOOL * psapList) | ||
| 103 | { | ||
| 104 | HRESULT hr = S_OK; | ||
| 105 | WCHAR wzAppPoolName[MAX_PATH]; | ||
| 106 | |||
| 107 | hr = ScaCreateApp(piMetabase, wzRootOfWeb, pswapp->iIsolation); | ||
| 108 | ExitOnFailure(hr, "Failed to create ASP App"); | ||
| 109 | |||
| 110 | // Medium Isolation seems to have to be set through the metabase | ||
| 111 | if (2 == pswapp->iIsolation) | ||
| 112 | { | ||
| 113 | hr = ScaWriteMetabaseValue(piMetabase, wzRootOfWeb, NULL, MD_APP_ISOLATED, METADATA_INHERIT, IIS_MD_UT_WAM, DWORD_METADATA, (LPVOID)((DWORD_PTR)pswapp->iIsolation)); | ||
| 114 | ExitOnFailure(hr, "Failed to write isolation value for App: '%ls'", pswapp->wzName); | ||
| 115 | } | ||
| 116 | |||
| 117 | // application name | ||
| 118 | hr = ScaWriteMetabaseValue(piMetabase, wzRootOfWeb, NULL, MD_APP_FRIENDLY_NAME, METADATA_INHERIT, IIS_MD_UT_WAM, STRING_METADATA, pswapp->wzName); | ||
| 119 | ExitOnFailure(hr, "Failed to write Name of App: '%ls'", pswapp->wzName); | ||
| 120 | |||
| 121 | // allow session state | ||
| 122 | if (MSI_NULL_INTEGER != pswapp->fAllowSessionState) | ||
| 123 | { | ||
| 124 | hr = ScaWriteMetabaseValue(piMetabase, wzRootOfWeb, NULL, MD_ASP_ALLOWSESSIONSTATE, METADATA_INHERIT, ASP_MD_UT_APP, DWORD_METADATA, (LPVOID)((DWORD_PTR)pswapp->fAllowSessionState)); | ||
| 125 | ExitOnFailure(hr, "Failed to write allow session information for App: '%ls'", pswapp->wzName); | ||
| 126 | } | ||
| 127 | |||
| 128 | // session timeout | ||
| 129 | if (MSI_NULL_INTEGER != pswapp->iSessionTimeout) | ||
| 130 | { | ||
| 131 | hr = ScaWriteMetabaseValue(piMetabase, wzRootOfWeb, NULL, MD_ASP_SESSIONTIMEOUT, METADATA_INHERIT, ASP_MD_UT_APP, DWORD_METADATA, (LPVOID)((DWORD_PTR)pswapp->iSessionTimeout)); | ||
| 132 | ExitOnFailure(hr, "Failed to write session timeout for App: '%ls'", pswapp->wzName); | ||
| 133 | } | ||
| 134 | |||
| 135 | // asp buffering | ||
| 136 | if (MSI_NULL_INTEGER != pswapp->fBuffer) | ||
| 137 | { | ||
| 138 | hr = ScaWriteMetabaseValue(piMetabase, wzRootOfWeb, NULL, MD_ASP_BUFFERINGON, METADATA_INHERIT, ASP_MD_UT_APP, DWORD_METADATA, (LPVOID)((DWORD_PTR)pswapp->fBuffer)); | ||
| 139 | ExitOnFailure(hr, "Failed to write buffering flag for App: '%ls'", pswapp->wzName); | ||
| 140 | } | ||
| 141 | |||
| 142 | // asp parent paths | ||
| 143 | if (MSI_NULL_INTEGER != pswapp->fParentPaths) | ||
| 144 | { | ||
| 145 | hr = ScaWriteMetabaseValue(piMetabase, wzRootOfWeb, NULL, MD_ASP_ENABLEPARENTPATHS, METADATA_INHERIT, ASP_MD_UT_APP, DWORD_METADATA, (LPVOID)((DWORD_PTR)pswapp->fParentPaths)); | ||
| 146 | ExitOnFailure(hr, "Failed to write parent paths flag for App: '%ls'", pswapp->wzName); | ||
| 147 | } | ||
| 148 | |||
| 149 | // default scripting language | ||
| 150 | if (*pswapp->wzDefaultScript) | ||
| 151 | { | ||
| 152 | hr = ScaWriteMetabaseValue(piMetabase, wzRootOfWeb, NULL, MD_ASP_SCRIPTLANGUAGE, METADATA_INHERIT, ASP_MD_UT_APP, STRING_METADATA, pswapp->wzDefaultScript); | ||
| 153 | ExitOnFailure(hr, "Failed to write default scripting language for App: '%ls'", pswapp->wzName); | ||
| 154 | } | ||
| 155 | |||
| 156 | // asp script timeout | ||
| 157 | if (MSI_NULL_INTEGER != pswapp->iScriptTimeout) | ||
| 158 | { | ||
| 159 | hr = ScaWriteMetabaseValue(piMetabase, wzRootOfWeb, NULL, MD_ASP_SCRIPTTIMEOUT, METADATA_INHERIT, ASP_MD_UT_APP, DWORD_METADATA, (LPVOID)((DWORD_PTR)pswapp->iScriptTimeout)); | ||
| 160 | ExitOnFailure(hr, "Failed to write script timeout for App: '%ls'", pswapp->wzName); | ||
| 161 | } | ||
| 162 | |||
| 163 | // asp server-side script debugging | ||
| 164 | if (MSI_NULL_INTEGER != pswapp->fServerDebugging) | ||
| 165 | { | ||
| 166 | hr = ScaWriteMetabaseValue(piMetabase, wzRootOfWeb, NULL, MD_ASP_ENABLESERVERDEBUG, METADATA_INHERIT, ASP_MD_UT_APP, DWORD_METADATA, (LPVOID)((DWORD_PTR)pswapp->fServerDebugging)); | ||
| 167 | ExitOnFailure(hr, "Failed to write ASP server-side script debugging flag for App: '%ls'", pswapp->wzName); | ||
| 168 | } | ||
| 169 | |||
| 170 | // asp server-side script debugging | ||
| 171 | if (MSI_NULL_INTEGER != pswapp->fClientDebugging) | ||
| 172 | { | ||
| 173 | hr = ScaWriteMetabaseValue(piMetabase, wzRootOfWeb, NULL, MD_ASP_ENABLECLIENTDEBUG, METADATA_INHERIT, ASP_MD_UT_APP, DWORD_METADATA, (LPVOID)((DWORD_PTR)pswapp->fClientDebugging)); | ||
| 174 | ExitOnFailure(hr, "Failed to write ASP client-side script debugging flag for App: '%ls'", pswapp->wzName); | ||
| 175 | } | ||
| 176 | |||
| 177 | // AppPool | ||
| 178 | if (*pswapp->wzAppPool && NULL != psapList) | ||
| 179 | { | ||
| 180 | hr = ScaFindAppPool(piMetabase, pswapp->wzAppPool, wzAppPoolName, countof(wzAppPoolName), psapList); | ||
| 181 | ExitOnFailure(hr, "failed to find app pool: %ls", pswapp->wzAppPool); | ||
| 182 | hr = ScaWriteMetabaseValue(piMetabase, wzRootOfWeb, NULL, MD_APP_APPPOOL_ID, METADATA_INHERIT, IIS_MD_UT_SERVER, STRING_METADATA, wzAppPoolName); | ||
| 183 | ExitOnFailure(hr, "Failed to write default AppPool for App: '%ls'", pswapp->wzName); | ||
| 184 | } | ||
| 185 | |||
| 186 | if (pswapp->pswappextList) | ||
| 187 | { | ||
| 188 | hr = ScaWebAppExtensionsWrite(piMetabase, wzRootOfWeb, pswapp->pswappextList); | ||
| 189 | ExitOnFailure(hr, "Failed to write AppExtensions for App: '%ls'", pswapp->wzName); | ||
| 190 | } | ||
| 191 | |||
| 192 | LExit: | ||
| 193 | return hr; | ||
| 194 | } | ||
diff --git a/src/ca/scawebapp.h b/src/ca/scawebapp.h new file mode 100644 index 00000000..a4152116 --- /dev/null +++ b/src/ca/scawebapp.h | |||
| @@ -0,0 +1,42 @@ | |||
| 1 | #pragma once | ||
| 2 | // 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. | ||
| 3 | |||
| 4 | |||
| 5 | #include "scaapppool.h" | ||
| 6 | #include "scawebappext.h" | ||
| 7 | |||
| 8 | // global sql queries provided for optimization | ||
| 9 | extern LPCWSTR vcsWebApplicationQuery; | ||
| 10 | const int MAX_APP_NAME = 255; | ||
| 11 | |||
| 12 | // structs | ||
| 13 | struct SCA_WEB_APPLICATION | ||
| 14 | { | ||
| 15 | WCHAR wzName[MAX_APP_NAME + 1]; | ||
| 16 | |||
| 17 | int iIsolation; | ||
| 18 | BOOL fAllowSessionState; | ||
| 19 | int iSessionTimeout; | ||
| 20 | BOOL fBuffer; | ||
| 21 | BOOL fParentPaths; | ||
| 22 | |||
| 23 | WCHAR wzDefaultScript[MAX_DARWIN_COLUMN + 1]; | ||
| 24 | int iScriptTimeout; | ||
| 25 | BOOL fServerDebugging; | ||
| 26 | BOOL fClientDebugging; | ||
| 27 | WCHAR wzAppPool[MAX_DARWIN_COLUMN + 1]; | ||
| 28 | |||
| 29 | SCA_WEB_APPLICATION_EXTENSION* pswappextList; | ||
| 30 | }; | ||
| 31 | |||
| 32 | |||
| 33 | // prototypes | ||
| 34 | HRESULT ScaGetWebApplication(MSIHANDLE hViewApplications, | ||
| 35 | LPCWSTR pwzApplication, | ||
| 36 | __in WCA_WRAPQUERY_HANDLE hWebAppQuery, | ||
| 37 | __in WCA_WRAPQUERY_HANDLE hWebAppExtQuery, | ||
| 38 | SCA_WEB_APPLICATION* pswapp); | ||
| 39 | |||
| 40 | HRESULT ScaWriteWebApplication(IMSAdminBase* piMetabase, LPCWSTR wzRootOfWeb, | ||
| 41 | SCA_WEB_APPLICATION* pswapp, SCA_APPPOOL * psapList); | ||
| 42 | |||
diff --git a/src/ca/scawebapp7.cpp b/src/ca/scawebapp7.cpp new file mode 100644 index 00000000..94e6bb18 --- /dev/null +++ b/src/ca/scawebapp7.cpp | |||
| @@ -0,0 +1,120 @@ | |||
| 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 | #include "precomp.h" | ||
| 4 | HRESULT ScaWriteWebApplication7( | ||
| 5 | __in_z LPCWSTR wzWebName, | ||
| 6 | __in_z LPCWSTR wzRootOfWeb, | ||
| 7 | SCA_WEB_APPLICATION* pswapp, | ||
| 8 | SCA_APPPOOL * /*psapList*/ | ||
| 9 | ) | ||
| 10 | { | ||
| 11 | HRESULT hr = S_OK; | ||
| 12 | |||
| 13 | //all go to same web/root location tag | ||
| 14 | hr = ScaWriteConfigID(IIS_ASP_BEGIN); | ||
| 15 | ExitOnFailure(hr, "Failed to write WebApp ASP begin id"); | ||
| 16 | hr = ScaWriteConfigString(wzWebName); //site name key | ||
| 17 | ExitOnFailure(hr, "Failed to write app web key"); | ||
| 18 | hr = ScaWriteConfigString(wzRootOfWeb); //app path key | ||
| 19 | ExitOnFailure(hr, "Failed to write app web root"); | ||
| 20 | |||
| 21 | // IIS7 Not Supported: Isolation | ||
| 22 | if (MSI_NULL_INTEGER != pswapp->iIsolation) | ||
| 23 | { | ||
| 24 | WcaLog(LOGMSG_TRACEONLY, "Not supported by IIS7: Isolation Mode, ignoring"); | ||
| 25 | } | ||
| 26 | |||
| 27 | // allow session state | ||
| 28 | if (MSI_NULL_INTEGER != pswapp->fAllowSessionState) | ||
| 29 | { | ||
| 30 | //system.webServer/asp /session | allowSessionState | ||
| 31 | hr = ScaWriteConfigID(IIS_ASP_SESSIONSTATE); | ||
| 32 | ExitOnFailure(hr, "Failed to write WebApp ASP sessionstate id"); | ||
| 33 | hr = ScaWriteConfigInteger(pswapp->fAllowSessionState); | ||
| 34 | ExitOnFailure(hr, "Failed to write allow session information for App: '%ls'", pswapp->wzName); | ||
| 35 | } | ||
| 36 | |||
| 37 | // session timeout | ||
| 38 | if (MSI_NULL_INTEGER != pswapp->iSessionTimeout) | ||
| 39 | { | ||
| 40 | //system.webServer/asp /session | timeout | ||
| 41 | hr = ScaWriteConfigID(IIS_ASP_SESSIONTIMEOUT); | ||
| 42 | ExitOnFailure(hr, "Failed to write WebApp ASP sessiontimepot id"); | ||
| 43 | hr = ScaWriteConfigInteger(pswapp->iSessionTimeout); | ||
| 44 | ExitOnFailure(hr, "Failed to write session timeout for App: '%ls'", pswapp->wzName); | ||
| 45 | } | ||
| 46 | |||
| 47 | // asp buffering | ||
| 48 | if (MSI_NULL_INTEGER != pswapp->fBuffer) | ||
| 49 | { | ||
| 50 | //system.webServer/asp | bufferingOn | ||
| 51 | hr = ScaWriteConfigID(IIS_ASP_BUFFER); | ||
| 52 | ExitOnFailure(hr, "Failed to write WebApp ASP buffer id"); | ||
| 53 | hr = ScaWriteConfigInteger(pswapp->fBuffer); | ||
| 54 | ExitOnFailure(hr, "Failed to write buffering flag for App: '%ls'", pswapp->wzName); | ||
| 55 | } | ||
| 56 | |||
| 57 | // asp parent paths | ||
| 58 | if (MSI_NULL_INTEGER != pswapp->fParentPaths) | ||
| 59 | { | ||
| 60 | //system.webServer/asp | enableParentPaths | ||
| 61 | hr = ScaWriteConfigID(IIS_ASP_PARENTPATHS); | ||
| 62 | ExitOnFailure(hr, "Failed to write WebApp ASP parentpaths id"); | ||
| 63 | hr = ScaWriteConfigInteger(pswapp->fParentPaths); | ||
| 64 | ExitOnFailure(hr, "Failed to write parent paths flag for App: '%ls'", pswapp->wzName); | ||
| 65 | } | ||
| 66 | |||
| 67 | // default scripting language | ||
| 68 | if (*pswapp->wzDefaultScript) | ||
| 69 | { | ||
| 70 | //system.webServer/asp | scriptLanguage | ||
| 71 | hr = ScaWriteConfigID(IIS_ASP_SCRIPTLANG); | ||
| 72 | ExitOnFailure(hr, "Failed to write WebApp ASP script lang id"); | ||
| 73 | hr = ScaWriteConfigString(pswapp->wzDefaultScript); | ||
| 74 | ExitOnFailure(hr, "Failed to write default scripting language for App: '%ls'", pswapp->wzName); | ||
| 75 | } | ||
| 76 | |||
| 77 | // asp script timeout | ||
| 78 | if (MSI_NULL_INTEGER != pswapp->iScriptTimeout) | ||
| 79 | { | ||
| 80 | //system.webServer/asp /limits | scriptTimeout | ||
| 81 | hr = ScaWriteConfigID(IIS_ASP_SCRIPTTIMEOUT); | ||
| 82 | ExitOnFailure(hr, "Failed to write WebApp ASP script timeout id"); | ||
| 83 | hr = ScaWriteConfigInteger(pswapp->iScriptTimeout); | ||
| 84 | ExitOnFailure(hr, "Failed to write script timeout for App: '%ls'", pswapp->wzName); | ||
| 85 | } | ||
| 86 | |||
| 87 | // asp server-side script debugging | ||
| 88 | if (MSI_NULL_INTEGER != pswapp->fServerDebugging) | ||
| 89 | { | ||
| 90 | //system.webServer/asp | appAllowDebugging | ||
| 91 | hr = ScaWriteConfigID(IIS_ASP_SCRIPTSERVERDEBUG); | ||
| 92 | ExitOnFailure(hr, "Failed to write WebApp ASP script debug id"); | ||
| 93 | hr = ScaWriteConfigInteger(pswapp->fServerDebugging); | ||
| 94 | ExitOnFailure(hr, "Failed to write ASP server-side script debugging flag for App: '%ls'", pswapp->wzName); | ||
| 95 | } | ||
| 96 | |||
| 97 | // asp client-side script debugging | ||
| 98 | if (MSI_NULL_INTEGER != pswapp->fClientDebugging) | ||
| 99 | { | ||
| 100 | //system.webServer/asp | appAllowClientDebug | ||
| 101 | hr = ScaWriteConfigID(IIS_ASP_SCRIPTCLIENTDEBUG); | ||
| 102 | ExitOnFailure(hr, "Failed to write WebApp ASP script debug id"); | ||
| 103 | hr = ScaWriteConfigInteger(pswapp->fClientDebugging); | ||
| 104 | ExitOnFailure(hr, "Failed to write ASP client-side script debugging flag for App: '%ls'", pswapp->wzName); | ||
| 105 | } | ||
| 106 | |||
| 107 | //done with ASP application properties | ||
| 108 | hr = ScaWriteConfigID(IIS_ASP_END); | ||
| 109 | ExitOnFailure(hr, "Failed to write WebApp ASP begin id"); | ||
| 110 | |||
| 111 | //write out app estensions | ||
| 112 | if (pswapp->pswappextList) | ||
| 113 | { | ||
| 114 | hr = ScaWebAppExtensionsWrite7(wzWebName, wzRootOfWeb, pswapp->pswappextList); | ||
| 115 | ExitOnFailure(hr, "Failed to write AppExtensions for App: '%ls'", pswapp->wzName); | ||
| 116 | } | ||
| 117 | |||
| 118 | LExit: | ||
| 119 | return hr; | ||
| 120 | } | ||
diff --git a/src/ca/scawebapp7.h b/src/ca/scawebapp7.h new file mode 100644 index 00000000..e1d87f53 --- /dev/null +++ b/src/ca/scawebapp7.h | |||
| @@ -0,0 +1,10 @@ | |||
| 1 | #pragma once | ||
| 2 | // 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. | ||
| 3 | |||
| 4 | |||
| 5 | HRESULT ScaWriteWebApplication7( | ||
| 6 | __in_z LPCWSTR wzWebName, | ||
| 7 | __in_z LPCWSTR wzRootOfWeb, | ||
| 8 | SCA_WEB_APPLICATION* pswapp, | ||
| 9 | SCA_APPPOOL * psapList | ||
| 10 | ); | ||
diff --git a/src/ca/scawebappext.cpp b/src/ca/scawebappext.cpp new file mode 100644 index 00000000..cf3b9dd3 --- /dev/null +++ b/src/ca/scawebappext.cpp | |||
| @@ -0,0 +1,207 @@ | |||
| 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 | #include "precomp.h" | ||
| 4 | |||
| 5 | enum eWebAppExtensionQuery { wappextqExtension = 1, wappextqVerbs, wappextqExecutable, wappextqAttributes, wappextqApplication }; | ||
| 6 | |||
| 7 | // prototypes for private helper functions | ||
| 8 | static HRESULT NewAppExt( | ||
| 9 | __out SCA_WEB_APPLICATION_EXTENSION** ppswappext | ||
| 10 | ); | ||
| 11 | static SCA_WEB_APPLICATION_EXTENSION* AddAppExtToList( | ||
| 12 | __in SCA_WEB_APPLICATION_EXTENSION* pswappextList, | ||
| 13 | __in SCA_WEB_APPLICATION_EXTENSION* pswappext | ||
| 14 | ); | ||
| 15 | |||
| 16 | |||
| 17 | |||
| 18 | HRESULT ScaWebAppExtensionsRead( | ||
| 19 | __in LPCWSTR wzApplication, | ||
| 20 | __in WCA_WRAPQUERY_HANDLE hWebAppExtQuery, | ||
| 21 | __inout SCA_WEB_APPLICATION_EXTENSION** ppswappextList | ||
| 22 | ) | ||
| 23 | { | ||
| 24 | HRESULT hr = S_OK; | ||
| 25 | MSIHANDLE hRec; | ||
| 26 | |||
| 27 | SCA_WEB_APPLICATION_EXTENSION* pswappext = NULL; | ||
| 28 | LPWSTR pwzData = NULL; | ||
| 29 | |||
| 30 | // Reset back to the first record | ||
| 31 | WcaFetchWrappedReset(hWebAppExtQuery); | ||
| 32 | |||
| 33 | // get the application extension information | ||
| 34 | while (S_OK == (hr = WcaFetchWrappedRecordWhereString(hWebAppExtQuery, wappextqApplication, wzApplication, &hRec))) | ||
| 35 | { | ||
| 36 | hr = NewAppExt(&pswappext); | ||
| 37 | ExitOnFailure(hr, "failed to create new web app extension"); | ||
| 38 | |||
| 39 | // get the extension | ||
| 40 | hr = WcaGetRecordString(hRec, wappextqExtension, &pwzData); | ||
| 41 | ExitOnFailure(hr, "Failed to get Web Application Extension"); | ||
| 42 | hr = ::StringCchCopyW(pswappext->wzExtension, countof(pswappext->wzExtension), pwzData); | ||
| 43 | ExitOnFailure(hr, "Failed to copy extension string to webappext object"); | ||
| 44 | |||
| 45 | // application extension verbs | ||
| 46 | hr = WcaGetRecordString(hRec, wappextqVerbs, &pwzData); | ||
| 47 | ExitOnFailure(hr, "Failed to get Verbs for Application: '%ls'", wzApplication); | ||
| 48 | hr = ::StringCchCopyW(pswappext->wzVerbs, countof(pswappext->wzVerbs), pwzData); | ||
| 49 | ExitOnFailure(hr, "Failed to copy verbs string to webappext object"); | ||
| 50 | |||
| 51 | // extension executeable | ||
| 52 | hr = WcaGetRecordString(hRec, wappextqExecutable, &pwzData); | ||
| 53 | ExitOnFailure(hr, "Failed to get Executable for Application: '%ls'", wzApplication); | ||
| 54 | hr = ::StringCchCopyW(pswappext->wzExecutable, countof(pswappext->wzExecutable), pwzData); | ||
| 55 | ExitOnFailure(hr, "Failed to copy executable string to webappext object"); | ||
| 56 | |||
| 57 | hr = WcaGetRecordInteger(hRec, wappextqAttributes, &pswappext->iAttributes); | ||
| 58 | if (S_FALSE == hr) | ||
| 59 | { | ||
| 60 | pswappext->iAttributes = 0; | ||
| 61 | hr = S_OK; | ||
| 62 | } | ||
| 63 | ExitOnFailure(hr, "Failed to get App isolation"); | ||
| 64 | |||
| 65 | *ppswappextList = AddAppExtToList(*ppswappextList, pswappext); | ||
| 66 | pswappext = NULL; // set the appext NULL so it doesn't accidentally get freed below | ||
| 67 | } | ||
| 68 | |||
| 69 | if (E_NOMOREITEMS == hr) | ||
| 70 | { | ||
| 71 | hr = S_OK; | ||
| 72 | } | ||
| 73 | |||
| 74 | LExit: | ||
| 75 | // if anything was left over after an error clean it all up | ||
| 76 | if (pswappext) | ||
| 77 | { | ||
| 78 | ScaWebAppExtensionsFreeList(pswappext); | ||
| 79 | } | ||
| 80 | |||
| 81 | ReleaseStr(pwzData); | ||
| 82 | |||
| 83 | return hr; | ||
| 84 | } | ||
| 85 | |||
| 86 | |||
| 87 | |||
| 88 | HRESULT ScaWebAppExtensionsWrite( | ||
| 89 | __in IMSAdminBase* piMetabase, | ||
| 90 | __in LPCWSTR wzRootOfWeb, | ||
| 91 | __in SCA_WEB_APPLICATION_EXTENSION* pswappextList | ||
| 92 | ) | ||
| 93 | { | ||
| 94 | HRESULT hr = S_OK; | ||
| 95 | |||
| 96 | LPWSTR wzAppExt = NULL; | ||
| 97 | DWORD cchAppExt; | ||
| 98 | WCHAR wzAppExtension[1024]; | ||
| 99 | WCHAR wzAppExtensions[65536]; | ||
| 100 | SCA_WEB_APPLICATION_EXTENSION* pswappext = NULL; | ||
| 101 | |||
| 102 | if (!pswappextList) | ||
| 103 | { | ||
| 104 | ExitFunction(); | ||
| 105 | } | ||
| 106 | |||
| 107 | ::ZeroMemory(wzAppExtensions, sizeof(wzAppExtensions)); | ||
| 108 | wzAppExt = wzAppExtensions; | ||
| 109 | cchAppExt = countof(wzAppExtensions); | ||
| 110 | pswappext = pswappextList; | ||
| 111 | |||
| 112 | while (pswappext) | ||
| 113 | { | ||
| 114 | // if all (represented by "*" or blank) | ||
| 115 | if (0 == lstrcmpW(pswappext->wzExtension, L"*") || 0 == lstrlenW(pswappext->wzExtension)) | ||
| 116 | { | ||
| 117 | hr = ::StringCchPrintfW(wzAppExtension, countof(wzAppExtension), L"*,%s,%d", pswappext->wzExecutable, pswappext->iAttributes); | ||
| 118 | ExitOnFailure(hr, "Failed to format *,executable,attributes string"); | ||
| 119 | } | ||
| 120 | else | ||
| 121 | { | ||
| 122 | hr = ::StringCchPrintfW(wzAppExtension, countof(wzAppExtension), L".%s,%s,%d", pswappext->wzExtension, pswappext->wzExecutable, pswappext->iAttributes); | ||
| 123 | ExitOnFailure(hr, "Failed to format extension,executable,attributes string"); | ||
| 124 | } | ||
| 125 | |||
| 126 | // if verbs were specified and not the keyword "all" | ||
| 127 | if (pswappext->wzVerbs[0] && CSTR_EQUAL != CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, pswappext->wzVerbs, -1, L"all", -1)) | ||
| 128 | { | ||
| 129 | hr = ::StringCchCatW(wzAppExtension, countof(wzAppExtension), L","); | ||
| 130 | ExitOnFailure(hr, "Failed to concatenate comma to app extension string"); | ||
| 131 | hr = ::StringCchCatW(wzAppExtension, countof(wzAppExtension), pswappext->wzVerbs); | ||
| 132 | ExitOnFailure(hr, "Failed to concatenate verb to app extension string"); | ||
| 133 | } | ||
| 134 | |||
| 135 | hr = ::StringCchCopyW(wzAppExt, cchAppExt, wzAppExtension); | ||
| 136 | ExitOnFailure(hr, "Failed to copy app extension string"); | ||
| 137 | wzAppExt += lstrlenW(wzAppExtension) + 1; | ||
| 138 | cchAppExt -= lstrlenW(wzAppExtension) + 1; | ||
| 139 | pswappext = pswappext->pswappextNext; | ||
| 140 | } | ||
| 141 | |||
| 142 | if (*wzAppExtensions) | ||
| 143 | { | ||
| 144 | hr = ScaWriteMetabaseValue(piMetabase, wzRootOfWeb, NULL, MD_SCRIPT_MAPS, METADATA_INHERIT, IIS_MD_UT_FILE, MULTISZ_METADATA, wzAppExtensions); | ||
| 145 | ExitOnFailure(hr, "Failed to write AppExtension: '%ls'", wzAppExtension); | ||
| 146 | } | ||
| 147 | |||
| 148 | LExit: | ||
| 149 | return hr; | ||
| 150 | } | ||
| 151 | |||
| 152 | |||
| 153 | void ScaWebAppExtensionsFreeList( | ||
| 154 | __in SCA_WEB_APPLICATION_EXTENSION* pswappextList | ||
| 155 | ) | ||
| 156 | { | ||
| 157 | SCA_WEB_APPLICATION_EXTENSION* pswappextDelete = pswappextList; | ||
| 158 | while (pswappextList) | ||
| 159 | { | ||
| 160 | pswappextDelete = pswappextList; | ||
| 161 | pswappextList = pswappextList->pswappextNext; | ||
| 162 | |||
| 163 | MemFree(pswappextDelete); | ||
| 164 | } | ||
| 165 | } | ||
| 166 | |||
| 167 | |||
| 168 | |||
| 169 | // private helper functions | ||
| 170 | |||
| 171 | static HRESULT NewAppExt( | ||
| 172 | __out SCA_WEB_APPLICATION_EXTENSION** ppswappext | ||
| 173 | ) | ||
| 174 | { | ||
| 175 | HRESULT hr = S_OK; | ||
| 176 | SCA_WEB_APPLICATION_EXTENSION* pswappext = static_cast<SCA_WEB_APPLICATION_EXTENSION*>(MemAlloc(sizeof(SCA_WEB_APPLICATION_EXTENSION), TRUE)); | ||
| 177 | ExitOnNull(pswappext, hr, E_OUTOFMEMORY, "failed to allocate memory for new web app ext element"); | ||
| 178 | |||
| 179 | *ppswappext = pswappext; | ||
| 180 | |||
| 181 | LExit: | ||
| 182 | return hr; | ||
| 183 | } | ||
| 184 | |||
| 185 | |||
| 186 | static SCA_WEB_APPLICATION_EXTENSION* AddAppExtToList( | ||
| 187 | __in SCA_WEB_APPLICATION_EXTENSION* pswappextList, | ||
| 188 | __in SCA_WEB_APPLICATION_EXTENSION* pswappext | ||
| 189 | ) | ||
| 190 | { | ||
| 191 | if (pswappextList) | ||
| 192 | { | ||
| 193 | SCA_WEB_APPLICATION_EXTENSION* pswappextT = pswappextList; | ||
| 194 | while (pswappextT->pswappextNext) | ||
| 195 | { | ||
| 196 | pswappextT = pswappextT->pswappextNext; | ||
| 197 | } | ||
| 198 | |||
| 199 | pswappextT->pswappextNext = pswappext; | ||
| 200 | } | ||
| 201 | else | ||
| 202 | { | ||
| 203 | pswappextList = pswappext; | ||
| 204 | } | ||
| 205 | |||
| 206 | return pswappextList; | ||
| 207 | } | ||
diff --git a/src/ca/scawebappext.h b/src/ca/scawebappext.h new file mode 100644 index 00000000..71adfd00 --- /dev/null +++ b/src/ca/scawebappext.h | |||
| @@ -0,0 +1,32 @@ | |||
| 1 | #pragma once | ||
| 2 | // 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. | ||
| 3 | |||
| 4 | |||
| 5 | struct SCA_WEB_APPLICATION_EXTENSION | ||
| 6 | { | ||
| 7 | WCHAR wzExtension[MAX_DARWIN_COLUMN + 1]; | ||
| 8 | |||
| 9 | WCHAR wzVerbs[MAX_DARWIN_COLUMN + 1]; | ||
| 10 | WCHAR wzExecutable[MAX_DARWIN_COLUMN + 1]; | ||
| 11 | int iAttributes; | ||
| 12 | |||
| 13 | SCA_WEB_APPLICATION_EXTENSION* pswappextNext; | ||
| 14 | }; | ||
| 15 | |||
| 16 | |||
| 17 | // prototypes | ||
| 18 | HRESULT ScaWebAppExtensionsRead( | ||
| 19 | __in LPCWSTR wzApplication, | ||
| 20 | __in WCA_WRAPQUERY_HANDLE hWebAppExtQuery, | ||
| 21 | __inout SCA_WEB_APPLICATION_EXTENSION** ppswappextList | ||
| 22 | ); | ||
| 23 | |||
| 24 | HRESULT ScaWebAppExtensionsWrite( | ||
| 25 | __in IMSAdminBase* piMetabase, | ||
| 26 | __in LPCWSTR wzRootOfWeb, | ||
| 27 | __in SCA_WEB_APPLICATION_EXTENSION* pswappextList | ||
| 28 | ); | ||
| 29 | |||
| 30 | void ScaWebAppExtensionsFreeList( | ||
| 31 | __in SCA_WEB_APPLICATION_EXTENSION* pswappextList | ||
| 32 | ); | ||
diff --git a/src/ca/scawebappext7.cpp b/src/ca/scawebappext7.cpp new file mode 100644 index 00000000..50d3172f --- /dev/null +++ b/src/ca/scawebappext7.cpp | |||
| @@ -0,0 +1,61 @@ | |||
| 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 | #include "precomp.h" | ||
| 4 | |||
| 5 | HRESULT ScaWebAppExtensionsWrite7( | ||
| 6 | __in_z LPCWSTR wzWebName, | ||
| 7 | __in_z LPCWSTR wzRootOfWeb, | ||
| 8 | __in SCA_WEB_APPLICATION_EXTENSION* pswappextList | ||
| 9 | ) | ||
| 10 | { | ||
| 11 | HRESULT hr = S_OK; | ||
| 12 | SCA_WEB_APPLICATION_EXTENSION* pswappext = NULL; | ||
| 13 | |||
| 14 | if (!pswappextList) | ||
| 15 | { | ||
| 16 | ExitFunction1(hr = S_OK); | ||
| 17 | } | ||
| 18 | |||
| 19 | //create the Extension for this vdir application | ||
| 20 | //all go to same web/root location tag | ||
| 21 | hr = ScaWriteConfigID(IIS_APPEXT_BEGIN); | ||
| 22 | ExitOnFailure(hr, "Failed to write webappext begin id"); | ||
| 23 | hr = ScaWriteConfigString(wzWebName); //site name key | ||
| 24 | ExitOnFailure(hr, "Failed to write app web key"); | ||
| 25 | hr = ScaWriteConfigString(wzRootOfWeb); //app path key | ||
| 26 | ExitOnFailure(hr, "Failed to write app web key"); | ||
| 27 | |||
| 28 | pswappext = pswappextList; | ||
| 29 | |||
| 30 | while (pswappext) | ||
| 31 | { | ||
| 32 | //create the Extension for this vdir application | ||
| 33 | hr = ScaWriteConfigID(IIS_APPEXT); | ||
| 34 | ExitOnFailure(hr, "Failed to write webappext begin id"); | ||
| 35 | |||
| 36 | if (*pswappext->wzExtension) | ||
| 37 | { | ||
| 38 | hr = ScaWriteConfigString(pswappext->wzExtension); | ||
| 39 | } | ||
| 40 | else // blank means "*" (all) | ||
| 41 | { | ||
| 42 | hr = ScaWriteConfigString(L"*"); | ||
| 43 | } | ||
| 44 | ExitOnFailure(hr, "Failed to write extension"); | ||
| 45 | |||
| 46 | hr = ScaWriteConfigString(pswappext->wzExecutable); | ||
| 47 | ExitOnFailure(hr, "Failed to write extension executable"); | ||
| 48 | |||
| 49 | hr = ScaWriteConfigString(pswappext->wzVerbs); | ||
| 50 | ExitOnFailure(hr, "Failed to write extension verbs"); | ||
| 51 | |||
| 52 | pswappext = pswappext->pswappextNext; | ||
| 53 | } | ||
| 54 | |||
| 55 | hr = ScaWriteConfigID(IIS_APPEXT_END); | ||
| 56 | ExitOnFailure(hr, "Failed to write webappext begin id"); | ||
| 57 | |||
| 58 | LExit: | ||
| 59 | return hr; | ||
| 60 | } | ||
| 61 | |||
diff --git a/src/ca/scawebappext7.h b/src/ca/scawebappext7.h new file mode 100644 index 00000000..55c8b5fc --- /dev/null +++ b/src/ca/scawebappext7.h | |||
| @@ -0,0 +1,9 @@ | |||
| 1 | #pragma once | ||
| 2 | // 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. | ||
| 3 | |||
| 4 | |||
| 5 | HRESULT ScaWebAppExtensionsWrite7( | ||
| 6 | __in_z LPCWSTR wzWebName, | ||
| 7 | __in_z LPCWSTR wzRootOfWeb, | ||
| 8 | __in SCA_WEB_APPLICATION_EXTENSION* pswappextList | ||
| 9 | ); | ||
diff --git a/src/ca/scawebdir.cpp b/src/ca/scawebdir.cpp new file mode 100644 index 00000000..26a7b32b --- /dev/null +++ b/src/ca/scawebdir.cpp | |||
| @@ -0,0 +1,241 @@ | |||
| 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 | #include "precomp.h" | ||
| 4 | |||
| 5 | // sql queries | ||
| 6 | enum eWebDirQuery { wdqWeb = 1, wdqWebDir, wdqComponent , wdqPath, wdqProperties, wdqApplication, wdqInstalled, wdqAction }; | ||
| 7 | |||
| 8 | // prototypes | ||
| 9 | static void AddWebDirToList(SCA_WEBDIR** ppswdList, SCA_WEBDIR *pswd); | ||
| 10 | |||
| 11 | static SCA_WEBDIR* NewWebDir(); | ||
| 12 | static void FreeWebDir(SCA_WEBDIR *pswd); | ||
| 13 | |||
| 14 | |||
| 15 | UINT __stdcall ScaWebDirsRead( | ||
| 16 | __in IMSAdminBase* piMetabase, | ||
| 17 | __in SCA_WEB* pswList, | ||
| 18 | __in WCA_WRAPQUERY_HANDLE hUserQuery, | ||
| 19 | __in WCA_WRAPQUERY_HANDLE hWebBaseQuery, | ||
| 20 | __in WCA_WRAPQUERY_HANDLE hWebDirPropQuery, | ||
| 21 | __in WCA_WRAPQUERY_HANDLE hWebAppQuery, | ||
| 22 | __in WCA_WRAPQUERY_HANDLE hWebAppExtQuery, | ||
| 23 | __inout LPWSTR *ppwzCustomActionData, | ||
| 24 | __out SCA_WEBDIR** ppswdList | ||
| 25 | ) | ||
| 26 | { | ||
| 27 | Assert(piMetabase && ppswdList); | ||
| 28 | |||
| 29 | HRESULT hr = S_OK; | ||
| 30 | MSIHANDLE hRec; | ||
| 31 | |||
| 32 | LPWSTR pwzData = NULL; | ||
| 33 | SCA_WEBDIR* pswd; | ||
| 34 | WCA_WRAPQUERY_HANDLE hWrapQuery = NULL; | ||
| 35 | |||
| 36 | hr = WcaBeginUnwrapQuery(&hWrapQuery, ppwzCustomActionData); | ||
| 37 | ExitOnFailure(hr, "Failed to unwrap query for ScaWebDirsRead"); | ||
| 38 | |||
| 39 | if (0 == WcaGetQueryRecords(hWrapQuery)) | ||
| 40 | { | ||
| 41 | WcaLog(LOGMSG_VERBOSE, "Skipping ScaInstallWebDirs() because IIsWebDir table not present"); | ||
| 42 | ExitFunction1(hr = S_FALSE); | ||
| 43 | } | ||
| 44 | |||
| 45 | // loop through all the web directories | ||
| 46 | while (S_OK == (hr = WcaFetchWrappedRecord(hWrapQuery, &hRec))) | ||
| 47 | { | ||
| 48 | pswd = NewWebDir(); | ||
| 49 | ExitOnNull(pswd, hr, E_OUTOFMEMORY, "Failed to allocate memory for web dir object in memory"); | ||
| 50 | |||
| 51 | // get component install state | ||
| 52 | hr = WcaGetRecordString(hRec, wdqComponent, &pwzData); | ||
| 53 | ExitOnFailure(hr, "Failed to get Component for WebDirs"); | ||
| 54 | hr = ::StringCchCopyW(pswd->wzComponent, countof(pswd->wzComponent), pwzData); | ||
| 55 | ExitOnFailure(hr, "Failed to copy component string to webdir object"); | ||
| 56 | |||
| 57 | hr = WcaGetRecordInteger(hRec, wdqInstalled, (int *)&pswd->isInstalled); | ||
| 58 | ExitOnFailure(hr, "Failed to get Component installed state for webdir"); | ||
| 59 | |||
| 60 | hr = WcaGetRecordInteger(hRec, wdqAction, (int *)&pswd->isAction); | ||
| 61 | ExitOnFailure(hr, "Failed to get Component action state for webdir"); | ||
| 62 | |||
| 63 | // If this record has a component and no action is being taken for it, skip processing it entirely | ||
| 64 | if (0 < lstrlenW(pswd->wzComponent) && !WcaIsInstalling(pswd->isInstalled, pswd->isAction) | ||
| 65 | && !WcaIsUninstalling(pswd->isInstalled, pswd->isAction) && !WcaIsReInstalling(pswd->isInstalled, pswd->isAction)) | ||
| 66 | { | ||
| 67 | FreeWebDir(pswd); | ||
| 68 | pswd = NULL; | ||
| 69 | continue; | ||
| 70 | } | ||
| 71 | |||
| 72 | hr = WcaGetRecordString(hRec, wdqWeb, &pwzData); | ||
| 73 | ExitOnFailure(hr, "Failed to get Web for WebDir"); | ||
| 74 | |||
| 75 | hr = ScaWebsGetBase(piMetabase, pswList, pwzData, pswd->wzWebBase, countof(pswd->wzWebBase), hWebBaseQuery); | ||
| 76 | if (WcaIsUninstalling(pswd->isInstalled, pswd->isAction)) | ||
| 77 | { | ||
| 78 | // If we're uninstalling, ignore any failure to find the existing web | ||
| 79 | hr = S_OK; | ||
| 80 | } | ||
| 81 | |||
| 82 | ExitOnFailure(hr, "Failed to get base of web for WebDir"); | ||
| 83 | |||
| 84 | hr = WcaGetRecordString(hRec, wdqPath, &pwzData); | ||
| 85 | ExitOnFailure(hr, "Failed to get Path for WebDir"); | ||
| 86 | |||
| 87 | hr = ::StringCchPrintfW(pswd->wzWebDirRoot, countof(pswd->wzWebDirRoot), L"%s/Root/%s", pswd->wzWebBase, pwzData); | ||
| 88 | ExitOnFailure(hr, "Failed to format webdir root string"); | ||
| 89 | |||
| 90 | // get the directory properties for this web | ||
| 91 | hr = WcaGetRecordString(hRec, wdqProperties, &pwzData); | ||
| 92 | ExitOnFailure(hr, "Failed to get security identifier for WebDir"); | ||
| 93 | if (*pwzData) | ||
| 94 | { | ||
| 95 | hr = ScaGetWebDirProperties(pwzData, hUserQuery, hWebDirPropQuery, &pswd->swp); | ||
| 96 | ExitOnFailure(hr, "Failed to get properties for WebDir"); | ||
| 97 | |||
| 98 | pswd->fHasProperties = TRUE; | ||
| 99 | } | ||
| 100 | |||
| 101 | // get the application information for this web directory | ||
| 102 | hr = WcaGetRecordString(hRec, wdqApplication, &pwzData); | ||
| 103 | ExitOnFailure(hr, "Failed to get application identifier for WebDir"); | ||
| 104 | if (*pwzData) | ||
| 105 | { | ||
| 106 | hr = ScaGetWebApplication(NULL, pwzData, hWebAppQuery, hWebAppExtQuery, &pswd->swapp); | ||
| 107 | ExitOnFailure(hr, "Failed to get application for WebDir"); | ||
| 108 | |||
| 109 | pswd->fHasApplication = TRUE; | ||
| 110 | } | ||
| 111 | |||
| 112 | AddWebDirToList(ppswdList, pswd); | ||
| 113 | } | ||
| 114 | |||
| 115 | if (E_NOMOREITEMS == hr) | ||
| 116 | { | ||
| 117 | hr = S_OK; | ||
| 118 | } | ||
| 119 | ExitOnFailure(hr, "Failure while processing WebDirs"); | ||
| 120 | |||
| 121 | LExit: | ||
| 122 | WcaFinishUnwrapQuery(hWrapQuery); | ||
| 123 | |||
| 124 | ReleaseStr(pwzData); | ||
| 125 | |||
| 126 | return hr; | ||
| 127 | } | ||
| 128 | |||
| 129 | |||
| 130 | HRESULT ScaWebDirsInstall(IMSAdminBase* piMetabase, SCA_WEBDIR* pswdList, SCA_APPPOOL * psapList) | ||
| 131 | { | ||
| 132 | HRESULT hr = S_OK; | ||
| 133 | SCA_WEBDIR* pswd = pswdList; | ||
| 134 | int i; | ||
| 135 | |||
| 136 | while (pswd) | ||
| 137 | { | ||
| 138 | // On reinstall, we have to uninstall the old application, otherwise a duplicate will be created | ||
| 139 | if (WcaIsReInstalling(pswd->isInstalled, pswd->isAction)) | ||
| 140 | { | ||
| 141 | if (pswd->fHasApplication) | ||
| 142 | { | ||
| 143 | hr = ScaDeleteApp(piMetabase, pswd->wzWebDirRoot); | ||
| 144 | ExitOnFailure(hr, "Failed to remove application for WebDir as part of a reinstall"); | ||
| 145 | } | ||
| 146 | } | ||
| 147 | |||
| 148 | // if we are installing the web site | ||
| 149 | if (WcaIsInstalling(pswd->isInstalled, pswd->isAction)) | ||
| 150 | { | ||
| 151 | hr = ScaCreateMetabaseKey(piMetabase, pswd->wzWebDirRoot, L""); | ||
| 152 | ExitOnFailure(hr, "Failed to create key for WebDir"); | ||
| 153 | hr = ScaWriteMetabaseValue(piMetabase, pswd->wzWebDirRoot, L"", MD_KEY_TYPE, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, (LPVOID)L"IIsWebDirectory"); | ||
| 154 | ExitOnFailure(hr, "Failed to write key type for for WebDir"); | ||
| 155 | i = 0x4000003e; // 1073741886: default directory browsing rights | ||
| 156 | hr = ScaWriteMetabaseValue(piMetabase, pswd->wzWebDirRoot, L"", MD_DIRECTORY_BROWSING, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, (LPVOID)((DWORD_PTR)i)); | ||
| 157 | ExitOnFailure(hr, "Failed to set directory browsing for WebDir"); | ||
| 158 | |||
| 159 | // get the security information for this web | ||
| 160 | if (pswd->fHasProperties) | ||
| 161 | { | ||
| 162 | ScaWriteWebDirProperties(piMetabase, pswd->wzWebDirRoot, &pswd->swp); | ||
| 163 | ExitOnFailure(hr, "Failed to write properties for WebDir"); | ||
| 164 | } | ||
| 165 | |||
| 166 | // get the application information for this web directory | ||
| 167 | if (pswd->fHasApplication) | ||
| 168 | { | ||
| 169 | hr = ScaWriteWebApplication(piMetabase, pswd->wzWebDirRoot, &pswd->swapp, psapList); | ||
| 170 | ExitOnFailure(hr, "Failed to write application for WebDir"); | ||
| 171 | } | ||
| 172 | } | ||
| 173 | |||
| 174 | pswd = pswd->pswdNext; | ||
| 175 | } | ||
| 176 | |||
| 177 | LExit: | ||
| 178 | return hr; | ||
| 179 | } | ||
| 180 | |||
| 181 | |||
| 182 | HRESULT ScaWebDirsUninstall(IMSAdminBase* piMetabase, SCA_WEBDIR* pswdList) | ||
| 183 | { | ||
| 184 | Assert(piMetabase); | ||
| 185 | |||
| 186 | HRESULT hr = S_OK; | ||
| 187 | SCA_WEBDIR* pswd = pswdList; | ||
| 188 | |||
| 189 | while (pswd) | ||
| 190 | { | ||
| 191 | if (WcaIsUninstalling(pswd->isInstalled, pswd->isAction)) | ||
| 192 | { | ||
| 193 | // remove the application from this web directory | ||
| 194 | if (pswd->fHasApplication) | ||
| 195 | { | ||
| 196 | hr = ScaDeleteApp(piMetabase, pswd->wzWebDirRoot); | ||
| 197 | ExitOnFailure(hr, "Failed to remove application for WebDir"); | ||
| 198 | } | ||
| 199 | |||
| 200 | hr = ScaDeleteMetabaseKey(piMetabase, pswd->wzWebDirRoot, L""); | ||
| 201 | ExitOnFailure(hr, "Failed to remove WebDir '%ls' from metabase", pswd->wzKey); | ||
| 202 | } | ||
| 203 | |||
| 204 | pswd = pswd->pswdNext; | ||
| 205 | } | ||
| 206 | |||
| 207 | LExit: | ||
| 208 | return hr; | ||
| 209 | } | ||
| 210 | |||
| 211 | |||
| 212 | static SCA_WEBDIR* NewWebDir() | ||
| 213 | { | ||
| 214 | SCA_WEBDIR* pswd = static_cast<SCA_WEBDIR*>(MemAlloc(sizeof(SCA_WEBDIR), TRUE)); | ||
| 215 | Assert(pswd); | ||
| 216 | return pswd; | ||
| 217 | } | ||
| 218 | |||
| 219 | static void FreeWebDir(SCA_WEBDIR *pswd) | ||
| 220 | { | ||
| 221 | MemFree(pswd); | ||
| 222 | } | ||
| 223 | |||
| 224 | void ScaWebDirsFreeList(SCA_WEBDIR* pswdList) | ||
| 225 | { | ||
| 226 | SCA_WEBDIR* pswdDelete = pswdList; | ||
| 227 | while (pswdList) | ||
| 228 | { | ||
| 229 | pswdDelete = pswdList; | ||
| 230 | pswdList = pswdList->pswdNext; | ||
| 231 | |||
| 232 | FreeWebDir(pswdDelete); | ||
| 233 | } | ||
| 234 | } | ||
| 235 | |||
| 236 | |||
| 237 | static void AddWebDirToList(SCA_WEBDIR** ppswdList, SCA_WEBDIR *pswd) | ||
| 238 | { | ||
| 239 | pswd->pswdNext = *ppswdList; | ||
| 240 | *ppswdList = pswd; | ||
| 241 | } | ||
diff --git a/src/ca/scawebdir.h b/src/ca/scawebdir.h new file mode 100644 index 00000000..0b594532 --- /dev/null +++ b/src/ca/scawebdir.h | |||
| @@ -0,0 +1,57 @@ | |||
| 1 | #pragma once | ||
| 2 | // 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. | ||
| 3 | |||
| 4 | |||
| 5 | struct SCA_WEBDIR | ||
| 6 | { | ||
| 7 | // darwin information | ||
| 8 | WCHAR wzKey[MAX_DARWIN_KEY + 1]; | ||
| 9 | WCHAR wzComponent[MAX_DARWIN_KEY + 1]; | ||
| 10 | INSTALLSTATE isInstalled; | ||
| 11 | INSTALLSTATE isAction; | ||
| 12 | |||
| 13 | // metabase information | ||
| 14 | WCHAR wzWebKey[MAX_DARWIN_KEY + 1]; | ||
| 15 | WCHAR wzWebBase[METADATA_MAX_NAME_LEN + 1]; | ||
| 16 | WCHAR wzWebDirRoot[METADATA_MAX_NAME_LEN + 1]; | ||
| 17 | |||
| 18 | // iis configuation information | ||
| 19 | WCHAR wzDirectory[MAX_PATH]; | ||
| 20 | |||
| 21 | BOOL fHasProperties; | ||
| 22 | SCA_WEB_PROPERTIES swp; | ||
| 23 | |||
| 24 | BOOL fHasApplication; | ||
| 25 | SCA_WEB_APPLICATION swapp; | ||
| 26 | |||
| 27 | SCA_WEBDIR* pswdNext; | ||
| 28 | }; | ||
| 29 | |||
| 30 | |||
| 31 | // prototypes | ||
| 32 | UINT __stdcall ScaWebDirsRead( | ||
| 33 | __in IMSAdminBase* piMetabase, | ||
| 34 | __in SCA_WEB* pswList, | ||
| 35 | __in WCA_WRAPQUERY_HANDLE hUserQuery, | ||
| 36 | __in WCA_WRAPQUERY_HANDLE hWebBaseQuery, | ||
| 37 | __in WCA_WRAPQUERY_HANDLE hWebDirPropQuery, | ||
| 38 | __in WCA_WRAPQUERY_HANDLE hWebAppQuery, | ||
| 39 | __in WCA_WRAPQUERY_HANDLE hWebAppExtQuery, | ||
| 40 | __inout LPWSTR *ppwzCustomActionData, | ||
| 41 | __out SCA_WEBDIR** ppswdList | ||
| 42 | ); | ||
| 43 | |||
| 44 | HRESULT ScaWebDirsInstall( | ||
| 45 | __in IMSAdminBase* piMetabase, | ||
| 46 | __in SCA_WEBDIR* pswdList, | ||
| 47 | __in SCA_APPPOOL* psapList | ||
| 48 | ); | ||
| 49 | |||
| 50 | HRESULT ScaWebDirsUninstall( | ||
| 51 | __in IMSAdminBase* piMetabase, | ||
| 52 | __in SCA_WEBDIR* pswdList | ||
| 53 | ); | ||
| 54 | |||
| 55 | void ScaWebDirsFreeList( | ||
| 56 | __in SCA_WEBDIR* pswdList | ||
| 57 | ); | ||
diff --git a/src/ca/scawebdir7.cpp b/src/ca/scawebdir7.cpp new file mode 100644 index 00000000..5ead0470 --- /dev/null +++ b/src/ca/scawebdir7.cpp | |||
| @@ -0,0 +1,219 @@ | |||
| 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 | #include "precomp.h" | ||
| 4 | |||
| 5 | // sql queries | ||
| 6 | static LPCWSTR vcsWebDirQuery7 = L"SELECT `Web_`, `WebDir`, `Component_`, `Path`, `DirProperties_`, `Application_`" | ||
| 7 | L"FROM `IIsWebDir`"; | ||
| 8 | |||
| 9 | enum eWebDirQuery { wdqWeb = 1, wdqWebDir, wdqComponent , wdqPath, wdqProperties, wdqApplication, wdqInstalled, wdqAction }; | ||
| 10 | |||
| 11 | // prototypes | ||
| 12 | static HRESULT AddWebDirToList(SCA_WEBDIR7** ppswdList); | ||
| 13 | |||
| 14 | |||
| 15 | UINT __stdcall ScaWebDirsRead7( | ||
| 16 | __in SCA_WEB7* pswList, | ||
| 17 | __in WCA_WRAPQUERY_HANDLE hUserQuery, | ||
| 18 | __in WCA_WRAPQUERY_HANDLE /*hWebBaseQuery*/, | ||
| 19 | __in WCA_WRAPQUERY_HANDLE hWebDirPropQuery, | ||
| 20 | __in WCA_WRAPQUERY_HANDLE hWebAppQuery, | ||
| 21 | __in WCA_WRAPQUERY_HANDLE hWebAppExtQuery, | ||
| 22 | __inout LPWSTR *ppwzCustomActionData, | ||
| 23 | __out SCA_WEBDIR7** ppswdList | ||
| 24 | ) | ||
| 25 | { | ||
| 26 | HRESULT hr = S_OK; | ||
| 27 | MSIHANDLE hRec; | ||
| 28 | |||
| 29 | LPWSTR pwzData = NULL; | ||
| 30 | SCA_WEBDIR7* pswd; | ||
| 31 | WCA_WRAPQUERY_HANDLE hWrapQuery = NULL; | ||
| 32 | |||
| 33 | hr = WcaBeginUnwrapQuery(&hWrapQuery, ppwzCustomActionData); | ||
| 34 | ExitOnFailure(hr, "Failed to unwrap query for ScaWebDirsRead7"); | ||
| 35 | |||
| 36 | if (0 == WcaGetQueryRecords(hWrapQuery)) | ||
| 37 | { | ||
| 38 | WcaLog(LOGMSG_VERBOSE, "Skipping ScaInstallWebDirs7() because IIsWebDir table not present"); | ||
| 39 | ExitFunction1(hr = S_FALSE); | ||
| 40 | } | ||
| 41 | |||
| 42 | // loop through all the web directories | ||
| 43 | while (S_OK == (hr = WcaFetchWrappedRecord(hWrapQuery, &hRec))) | ||
| 44 | { | ||
| 45 | hr = AddWebDirToList(ppswdList); | ||
| 46 | ExitOnFailure(hr, "failed to add web dir to list"); | ||
| 47 | |||
| 48 | pswd = *ppswdList; | ||
| 49 | ExitOnNull(pswd, hr, E_INVALIDARG, "No web dir provided"); | ||
| 50 | |||
| 51 | // get component install state | ||
| 52 | hr = WcaGetRecordString(hRec, wdqComponent, &pwzData); | ||
| 53 | ExitOnFailure(hr, "Failed to get Component for WebDirs"); | ||
| 54 | hr = ::StringCchCopyW(pswd->wzComponent, countof(pswd->wzComponent), pwzData); | ||
| 55 | ExitOnFailure(hr, "Failed to copy component string to webdir object"); | ||
| 56 | |||
| 57 | hr = WcaGetRecordInteger(hRec, wdqInstalled, (int *)&pswd->isInstalled); | ||
| 58 | ExitOnFailure(hr, "Failed to get Component installed state for webdir"); | ||
| 59 | |||
| 60 | hr = WcaGetRecordInteger(hRec, wdqAction, (int *)&pswd->isAction); | ||
| 61 | ExitOnFailure(hr, "Failed to get Component action state for webdir"); | ||
| 62 | |||
| 63 | hr = WcaGetRecordString(hRec, wdqWeb, &pwzData); | ||
| 64 | ExitOnFailure(hr, "Failed to get Web for WebDir"); | ||
| 65 | |||
| 66 | // get the web key | ||
| 67 | hr = ScaWebsGetBase7(pswList, pwzData, pswd->wzWebSite, countof(pswd->wzWebSite)); | ||
| 68 | if (S_FALSE == hr) | ||
| 69 | { | ||
| 70 | hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND); | ||
| 71 | ExitOnFailure(hr, "Failed to get base of web for WebDir"); | ||
| 72 | } | ||
| 73 | ExitOnFailure(hr, "Failed to format webdir root string"); | ||
| 74 | |||
| 75 | hr = WcaGetRecordString(hRec, wdqPath, &pwzData); | ||
| 76 | ExitOnFailure(hr, "Failed to get Path for WebDir"); | ||
| 77 | |||
| 78 | hr = ::StringCchCopyW(pswd->wzPath, countof(pswd->wzPath), pwzData); | ||
| 79 | ExitOnFailure(hr, "Failed to copy path for WebDir"); | ||
| 80 | |||
| 81 | // get the directory properties for this web | ||
| 82 | hr = WcaGetRecordString(hRec, wdqProperties, &pwzData); | ||
| 83 | ExitOnFailure(hr, "Failed to get security identifier for WebDir"); | ||
| 84 | if (*pwzData) | ||
| 85 | { | ||
| 86 | hr = ScaGetWebDirProperties(pwzData, hUserQuery, hWebDirPropQuery, &pswd->swp); | ||
| 87 | ExitOnFailure(hr, "Failed to get properties for WebDir"); | ||
| 88 | |||
| 89 | pswd->fHasProperties = TRUE; | ||
| 90 | } | ||
| 91 | |||
| 92 | // get the application information for this web directory | ||
| 93 | hr = WcaGetRecordString(hRec, wdqApplication, &pwzData); | ||
| 94 | ExitOnFailure(hr, "Failed to get application identifier for WebDir"); | ||
| 95 | if (*pwzData) | ||
| 96 | { | ||
| 97 | hr = ScaGetWebApplication(NULL, pwzData, hWebAppQuery, hWebAppExtQuery, &pswd->swapp); | ||
| 98 | ExitOnFailure(hr, "Failed to get application for WebDir"); | ||
| 99 | |||
| 100 | pswd->fHasApplication = TRUE; | ||
| 101 | } | ||
| 102 | } | ||
| 103 | |||
| 104 | if (E_NOMOREITEMS == hr) | ||
| 105 | { | ||
| 106 | hr = S_OK; | ||
| 107 | } | ||
| 108 | ExitOnFailure(hr, "Failure while processing WebDirs"); | ||
| 109 | |||
| 110 | LExit: | ||
| 111 | WcaFinishUnwrapQuery(hWrapQuery); | ||
| 112 | |||
| 113 | ReleaseStr(pwzData); | ||
| 114 | |||
| 115 | return hr; | ||
| 116 | } | ||
| 117 | |||
| 118 | |||
| 119 | HRESULT ScaWebDirsInstall7(SCA_WEBDIR7* pswdList, SCA_APPPOOL * psapList) | ||
| 120 | { | ||
| 121 | HRESULT hr = S_OK; | ||
| 122 | SCA_WEBDIR7* pswd = pswdList; | ||
| 123 | |||
| 124 | while (pswd) | ||
| 125 | { | ||
| 126 | // if we are installing the web site | ||
| 127 | if (WcaIsInstalling(pswd->isInstalled, pswd->isAction)) | ||
| 128 | { | ||
| 129 | hr = ScaWriteConfigID(IIS_WEBDIR); | ||
| 130 | ExitOnFailure(hr, "Failed to write WebDir ID"); | ||
| 131 | |||
| 132 | hr = ScaWriteConfigID(IIS_CREATE); | ||
| 133 | ExitOnFailure(hr, "Failed to write WebDir action ID"); | ||
| 134 | |||
| 135 | hr = ScaWriteConfigString(pswd->wzWebSite); | ||
| 136 | ExitOnFailure(hr, "Failed to write WebDir site"); | ||
| 137 | |||
| 138 | hr = ScaWriteConfigString(pswd->wzPath); | ||
| 139 | ExitOnFailure(hr, "Failed to write WebDir path"); | ||
| 140 | |||
| 141 | // get the security information for this web | ||
| 142 | if (pswd->fHasProperties) | ||
| 143 | { | ||
| 144 | ScaWriteWebDirProperties7(pswd->wzWebSite, pswd->wzPath, &pswd->swp); | ||
| 145 | ExitOnFailure(hr, "Failed to write properties for WebDir"); | ||
| 146 | } | ||
| 147 | |||
| 148 | // get the application information for this web directory | ||
| 149 | if (pswd->fHasApplication) | ||
| 150 | { | ||
| 151 | hr = ScaWriteWebApplication7(pswd->wzWebSite, pswd->wzPath, &pswd->swapp, psapList); | ||
| 152 | ExitOnFailure(hr, "Failed to write application for WebDir"); | ||
| 153 | } | ||
| 154 | } | ||
| 155 | |||
| 156 | pswd = pswd->pswdNext; | ||
| 157 | } | ||
| 158 | |||
| 159 | LExit: | ||
| 160 | return hr; | ||
| 161 | } | ||
| 162 | |||
| 163 | |||
| 164 | HRESULT ScaWebDirsUninstall7(SCA_WEBDIR7* pswdList) | ||
| 165 | { | ||
| 166 | HRESULT hr = S_OK; | ||
| 167 | SCA_WEBDIR7* pswd = pswdList; | ||
| 168 | |||
| 169 | while (pswd) | ||
| 170 | { | ||
| 171 | if (WcaIsUninstalling(pswd->isInstalled, pswd->isAction)) | ||
| 172 | { | ||
| 173 | hr = ScaWriteConfigID(IIS_WEBDIR); | ||
| 174 | ExitOnFailure(hr, "Failed to write WebDir ID"); | ||
| 175 | |||
| 176 | hr = ScaWriteConfigID(IIS_DELETE); | ||
| 177 | ExitOnFailure(hr, "Failed to write WebDir action ID"); | ||
| 178 | |||
| 179 | hr = ScaWriteConfigString(pswd->wzWebSite); | ||
| 180 | ExitOnFailure(hr, "Failed to write WebDir site"); | ||
| 181 | |||
| 182 | hr = ScaWriteConfigString(pswd->wzPath); | ||
| 183 | ExitOnFailure(hr, "Failed to write WebDir path"); | ||
| 184 | } | ||
| 185 | |||
| 186 | pswd = pswd->pswdNext; | ||
| 187 | } | ||
| 188 | |||
| 189 | LExit: | ||
| 190 | return hr; | ||
| 191 | } | ||
| 192 | |||
| 193 | |||
| 194 | void ScaWebDirsFreeList7(SCA_WEBDIR7* pswdList) | ||
| 195 | { | ||
| 196 | SCA_WEBDIR7* pswdDelete = pswdList; | ||
| 197 | while (pswdList) | ||
| 198 | { | ||
| 199 | pswdDelete = pswdList; | ||
| 200 | pswdList = pswdList->pswdNext; | ||
| 201 | |||
| 202 | MemFree(pswdDelete); | ||
| 203 | } | ||
| 204 | } | ||
| 205 | |||
| 206 | |||
| 207 | static HRESULT AddWebDirToList(SCA_WEBDIR7** ppswdList) | ||
| 208 | { | ||
| 209 | HRESULT hr = S_OK; | ||
| 210 | |||
| 211 | SCA_WEBDIR7* pswd = static_cast<SCA_WEBDIR7*>(MemAlloc(sizeof(SCA_WEBDIR7), TRUE)); | ||
| 212 | ExitOnNull(pswd, hr, E_OUTOFMEMORY, "failed to allocate element for web dir list"); | ||
| 213 | |||
| 214 | pswd->pswdNext = *ppswdList; | ||
| 215 | *ppswdList = pswd; | ||
| 216 | |||
| 217 | LExit: | ||
| 218 | return hr; | ||
| 219 | } | ||
diff --git a/src/ca/scawebdir7.h b/src/ca/scawebdir7.h new file mode 100644 index 00000000..c5c87e17 --- /dev/null +++ b/src/ca/scawebdir7.h | |||
| @@ -0,0 +1,51 @@ | |||
| 1 | #pragma once | ||
| 2 | // 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. | ||
| 3 | |||
| 4 | |||
| 5 | struct SCA_WEBDIR7 | ||
| 6 | { | ||
| 7 | // darwin information | ||
| 8 | WCHAR wzKey[MAX_DARWIN_KEY + 1]; | ||
| 9 | WCHAR wzComponent[MAX_DARWIN_KEY + 1]; | ||
| 10 | INSTALLSTATE isInstalled; | ||
| 11 | INSTALLSTATE isAction; | ||
| 12 | |||
| 13 | |||
| 14 | // iis configuation information | ||
| 15 | WCHAR wzPath[MAX_PATH]; | ||
| 16 | WCHAR wzWebSite[MAX_PATH]; | ||
| 17 | |||
| 18 | BOOL fHasProperties; | ||
| 19 | SCA_WEB_PROPERTIES swp; | ||
| 20 | |||
| 21 | BOOL fHasApplication; | ||
| 22 | SCA_WEB_APPLICATION swapp; | ||
| 23 | |||
| 24 | SCA_WEBDIR7* pswdNext; | ||
| 25 | }; | ||
| 26 | |||
| 27 | |||
| 28 | // prototypes | ||
| 29 | UINT __stdcall ScaWebDirsRead7( | ||
| 30 | __in SCA_WEB7* pswList, | ||
| 31 | __in WCA_WRAPQUERY_HANDLE hUserQuery, | ||
| 32 | __in WCA_WRAPQUERY_HANDLE hWebBaseQuery, | ||
| 33 | __in WCA_WRAPQUERY_HANDLE hWebDirPropQuery, | ||
| 34 | __in WCA_WRAPQUERY_HANDLE hWebAppQuery, | ||
| 35 | __in WCA_WRAPQUERY_HANDLE hWebAppExtQuery, | ||
| 36 | __inout LPWSTR *ppwzCustomActionData, | ||
| 37 | __out SCA_WEBDIR7** ppswdList | ||
| 38 | ); | ||
| 39 | |||
| 40 | HRESULT ScaWebDirsInstall7( | ||
| 41 | __in SCA_WEBDIR7* pswdList, | ||
| 42 | __in SCA_APPPOOL* psapList | ||
| 43 | ); | ||
| 44 | |||
| 45 | HRESULT ScaWebDirsUninstall7( | ||
| 46 | __in SCA_WEBDIR7* pswdList | ||
| 47 | ); | ||
| 48 | |||
| 49 | void ScaWebDirsFreeList7( | ||
| 50 | __in SCA_WEBDIR7* pswdList | ||
| 51 | ); | ||
diff --git a/src/ca/scaweberr.cpp b/src/ca/scaweberr.cpp new file mode 100644 index 00000000..2441f006 --- /dev/null +++ b/src/ca/scaweberr.cpp | |||
| @@ -0,0 +1,371 @@ | |||
| 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 | #include "precomp.h" | ||
| 4 | |||
| 5 | enum eWebErrorQuery { weqErrorCode = 1, weqSubCode, weqParentType, weqParentValue, weqFile, weqURL }; | ||
| 6 | |||
| 7 | static HRESULT AddWebErrorToList(SCA_WEB_ERROR** ppsweList); | ||
| 8 | |||
| 9 | void ScaWebErrorFreeList(SCA_WEB_ERROR *psweList) | ||
| 10 | { | ||
| 11 | SCA_WEB_ERROR *psweDelete = psweList; | ||
| 12 | while (psweList) | ||
| 13 | { | ||
| 14 | psweDelete = psweList; | ||
| 15 | psweList = psweList->psweNext; | ||
| 16 | |||
| 17 | MemFree(psweDelete); | ||
| 18 | } | ||
| 19 | } | ||
| 20 | |||
| 21 | HRESULT ScaWebErrorRead( | ||
| 22 | SCA_WEB_ERROR **ppsweList, | ||
| 23 | __inout LPWSTR *ppwzCustomActionData | ||
| 24 | ) | ||
| 25 | { | ||
| 26 | // AssertSz(0, "Debug ScaWebErrorRead here"); | ||
| 27 | HRESULT hr = S_OK; | ||
| 28 | MSIHANDLE hRec; | ||
| 29 | LPWSTR pwzData = NULL; | ||
| 30 | SCA_WEB_ERROR* pswe; | ||
| 31 | WCA_WRAPQUERY_HANDLE hWrapQuery = NULL; | ||
| 32 | |||
| 33 | ExitOnNull(ppsweList, hr, E_INVALIDARG, "Failed to read web error, because no web error was provided to read"); | ||
| 34 | |||
| 35 | hr = WcaBeginUnwrapQuery(&hWrapQuery, ppwzCustomActionData); | ||
| 36 | ExitOnFailure(hr, "Failed to unwrap query for ScaAppPoolRead"); | ||
| 37 | |||
| 38 | if (0 == WcaGetQueryRecords(hWrapQuery)) | ||
| 39 | { | ||
| 40 | WcaLog(LOGMSG_VERBOSE, "Skipping ScaWebErrorRead() - required tables not present."); | ||
| 41 | ExitFunction1(hr = S_FALSE); | ||
| 42 | } | ||
| 43 | |||
| 44 | // loop through all the web errors | ||
| 45 | while (S_OK == (hr = WcaFetchWrappedRecord(hWrapQuery, &hRec))) | ||
| 46 | { | ||
| 47 | hr = AddWebErrorToList(ppsweList); | ||
| 48 | ExitOnFailure(hr, "failed to add web error to list"); | ||
| 49 | |||
| 50 | pswe = *ppsweList; | ||
| 51 | |||
| 52 | hr = WcaGetRecordInteger(hRec, weqErrorCode, &(pswe->iErrorCode)); | ||
| 53 | ExitOnFailure(hr, "failed to get IIsWebError.ErrorCode"); | ||
| 54 | |||
| 55 | hr = WcaGetRecordInteger(hRec, weqSubCode, &(pswe->iSubCode)); | ||
| 56 | ExitOnFailure(hr, "failed to get IIsWebError.SubCode"); | ||
| 57 | |||
| 58 | hr = WcaGetRecordInteger(hRec, weqParentType, &(pswe->iParentType)); | ||
| 59 | ExitOnFailure(hr, "failed to get IIsWebError.ParentType"); | ||
| 60 | |||
| 61 | hr = WcaGetRecordString(hRec, weqParentValue, &pwzData); | ||
| 62 | ExitOnFailure(hr, "Failed to get IIsWebError.ParentValue"); | ||
| 63 | hr = ::StringCchCopyW(pswe->wzParentValue, countof(pswe->wzParentValue), pwzData); | ||
| 64 | ExitOnFailure(hr, "Failed to copy IIsWebError.ParentValue"); | ||
| 65 | |||
| 66 | hr = WcaGetRecordString(hRec, weqFile, &pwzData); | ||
| 67 | ExitOnFailure(hr, "Failed to get IIsWebError.File"); | ||
| 68 | hr = ::StringCchCopyW(pswe->wzFile, countof(pswe->wzFile), pwzData); | ||
| 69 | ExitOnFailure(hr, "Failed to copy IIsWebError.File"); | ||
| 70 | |||
| 71 | hr = WcaGetRecordString(hRec, weqURL, &pwzData); | ||
| 72 | ExitOnFailure(hr, "Failed to get IIsWebError.URL"); | ||
| 73 | hr = ::StringCchCopyW(pswe->wzURL, countof(pswe->wzURL), pwzData); | ||
| 74 | ExitOnFailure(hr, "Failed to copy IIsWebError.URL"); | ||
| 75 | |||
| 76 | // If they've specified both a file and a URL, that's invalid | ||
| 77 | if (*(pswe->wzFile) && *(pswe->wzURL)) | ||
| 78 | ExitOnFailure(hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA), "Both File and URL specified for web error. File: %ls, URL: %ls", pswe->wzFile, pswe->wzURL); | ||
| 79 | } | ||
| 80 | |||
| 81 | if (E_NOMOREITEMS == hr) | ||
| 82 | { | ||
| 83 | hr = S_OK; | ||
| 84 | } | ||
| 85 | ExitOnFailure(hr, "Failure while processing web errors"); | ||
| 86 | |||
| 87 | LExit: | ||
| 88 | WcaFinishUnwrapQuery(hWrapQuery); | ||
| 89 | |||
| 90 | ReleaseStr(pwzData); | ||
| 91 | |||
| 92 | return hr; | ||
| 93 | } | ||
| 94 | |||
| 95 | HRESULT ScaGetWebError(int iParentType, LPCWSTR wzParentValue, SCA_WEB_ERROR **ppsweList, SCA_WEB_ERROR **ppsweOut) | ||
| 96 | { | ||
| 97 | HRESULT hr = S_OK; | ||
| 98 | SCA_WEB_ERROR* psweAdd = NULL; | ||
| 99 | SCA_WEB_ERROR* psweLast = NULL; | ||
| 100 | |||
| 101 | *ppsweOut = NULL; | ||
| 102 | |||
| 103 | if (!*ppsweList) | ||
| 104 | return hr; | ||
| 105 | |||
| 106 | SCA_WEB_ERROR* pswe = *ppsweList; | ||
| 107 | while (pswe) | ||
| 108 | { | ||
| 109 | if (iParentType == pswe->iParentType && 0 == lstrcmpW(wzParentValue, pswe->wzParentValue)) | ||
| 110 | { | ||
| 111 | // Found a match, take this one out of the list and add it to the matched out list | ||
| 112 | psweAdd = pswe; | ||
| 113 | |||
| 114 | if (psweLast) | ||
| 115 | { | ||
| 116 | // If we're not at the beginning of the list tell the last node about it's new next (since we're taking away it's current next) | ||
| 117 | psweLast->psweNext = psweAdd->psweNext; | ||
| 118 | } | ||
| 119 | else | ||
| 120 | { | ||
| 121 | // If we are at the beginning (no psweLast) update the beginning (since we're taking it) | ||
| 122 | *ppsweList = pswe->psweNext; | ||
| 123 | } | ||
| 124 | pswe = pswe->psweNext; // move on | ||
| 125 | |||
| 126 | // Add the one we've removed to the beginning of the out list | ||
| 127 | psweAdd->psweNext = *ppsweOut; | ||
| 128 | *ppsweOut = psweAdd; | ||
| 129 | } | ||
| 130 | else | ||
| 131 | { | ||
| 132 | psweLast = pswe; // remember the last we that didn't match | ||
| 133 | pswe = pswe->psweNext; // move on | ||
| 134 | } | ||
| 135 | } | ||
| 136 | |||
| 137 | return hr; | ||
| 138 | } | ||
| 139 | |||
| 140 | HRESULT ScaWriteWebError(IMSAdminBase* piMetabase, int iParentType, LPCWSTR wzRoot, SCA_WEB_ERROR* psweList) | ||
| 141 | { | ||
| 142 | // AssertSz(0, "Debug ScaWriteWebError here"); | ||
| 143 | Assert(*wzRoot && psweList); | ||
| 144 | |||
| 145 | HRESULT hr = S_OK; | ||
| 146 | |||
| 147 | DWORD cchData = 0; | ||
| 148 | LPWSTR pwzSearchKey = NULL; | ||
| 149 | LPWSTR pwz = NULL; | ||
| 150 | LPWSTR pwzErrors = NULL; | ||
| 151 | |||
| 152 | LPWSTR pwzCodeSubCode = NULL; | ||
| 153 | LPWSTR pwzAcceptableCodeSubCode = NULL; | ||
| 154 | LPCWSTR wzFoundCodeSubCode = NULL; | ||
| 155 | DWORD_PTR dwFoundCodeSubCodeIndex = 0xFFFFFFFF; | ||
| 156 | BOOL fOldValueFound = FALSE; | ||
| 157 | LPWSTR pwzAcceptableErrors = NULL; | ||
| 158 | |||
| 159 | LPWSTR pwzNewError = NULL; | ||
| 160 | |||
| 161 | METADATA_RECORD mr; | ||
| 162 | ::ZeroMemory(&mr, sizeof(mr)); | ||
| 163 | |||
| 164 | ExitOnNull(piMetabase, hr, E_INVALIDARG, "Failed to write web error, because no metabase was provided"); | ||
| 165 | ExitOnNull(wzRoot, hr, E_INVALIDARG, "Failed to write web error, because no root was provided"); | ||
| 166 | |||
| 167 | // get the set of all valid custom errors from the metabase | ||
| 168 | mr.dwMDIdentifier = MD_CUSTOM_ERROR_DESC; | ||
| 169 | mr.dwMDAttributes = METADATA_INHERIT; | ||
| 170 | mr.dwMDUserType = IIS_MD_UT_SERVER; | ||
| 171 | mr.dwMDDataType = ALL_METADATA; | ||
| 172 | mr.dwMDDataLen = cchData = 0; | ||
| 173 | mr.pbMDData = NULL; | ||
| 174 | |||
| 175 | hr = MetaGetValue(piMetabase, METADATA_MASTER_ROOT_HANDLE, L"/LM/W3SVC/Info", &mr); | ||
| 176 | ExitOnFailure(hr, "Unable to get set of acceptable error codes for this server."); | ||
| 177 | |||
| 178 | pwzAcceptableErrors = reinterpret_cast<LPWSTR>(mr.pbMDData); | ||
| 179 | |||
| 180 | // Check if web errors already exist here | ||
| 181 | mr.dwMDIdentifier = MD_CUSTOM_ERROR; | ||
| 182 | mr.dwMDAttributes = METADATA_INHERIT; | ||
| 183 | mr.dwMDUserType = IIS_MD_UT_SERVER; | ||
| 184 | mr.dwMDDataType = ALL_METADATA; | ||
| 185 | mr.dwMDDataLen = cchData = 0; | ||
| 186 | mr.pbMDData = NULL; | ||
| 187 | |||
| 188 | hr = MetaGetValue(piMetabase, METADATA_MASTER_ROOT_HANDLE, wzRoot, &mr); | ||
| 189 | if (HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) == hr || MD_ERROR_DATA_NOT_FOUND == hr) | ||
| 190 | { | ||
| 191 | // | ||
| 192 | // If we don't have one already, find an appropriate one to start with | ||
| 193 | // | ||
| 194 | |||
| 195 | // we can walk up key by key and look for custom errors to inherit | ||
| 196 | |||
| 197 | hr = StrAllocConcat(&pwzSearchKey, wzRoot, 0); | ||
| 198 | ExitOnFailure(hr, "Failed to copy root string: %ls", wzRoot); | ||
| 199 | |||
| 200 | pwz = pwzSearchKey + lstrlenW(pwzSearchKey); | ||
| 201 | |||
| 202 | while (NULL == pwzErrors) | ||
| 203 | { | ||
| 204 | // find the last slash | ||
| 205 | while (*pwz != '/' && pwz != pwzSearchKey) | ||
| 206 | pwz --; | ||
| 207 | |||
| 208 | if (pwz == pwzSearchKey) | ||
| 209 | break; | ||
| 210 | |||
| 211 | *pwz = L'\0'; | ||
| 212 | |||
| 213 | // Try here. If it's not found, keep walking up the path | ||
| 214 | hr = MetaGetValue(piMetabase, METADATA_MASTER_ROOT_HANDLE, pwzSearchKey, &mr); | ||
| 215 | if (HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) == hr || MD_ERROR_DATA_NOT_FOUND == hr) | ||
| 216 | hr = S_FALSE; | ||
| 217 | ExitOnFailure(hr, "failed to discover default error values to start with for web root: %ls while walking up the tree", wzRoot); | ||
| 218 | |||
| 219 | if (S_OK == hr) | ||
| 220 | { | ||
| 221 | pwzErrors = reinterpret_cast<LPWSTR>(mr.pbMDData); | ||
| 222 | break; | ||
| 223 | } | ||
| 224 | |||
| 225 | // Don't keep going if we're at the root | ||
| 226 | if (0 == lstrcmpW(pwz + 1, L"W3SVC")) | ||
| 227 | break; | ||
| 228 | } | ||
| 229 | } | ||
| 230 | else | ||
| 231 | { | ||
| 232 | pwzErrors = reinterpret_cast<LPWSTR>(mr.pbMDData); | ||
| 233 | } | ||
| 234 | ExitOnFailure(hr, "failed to discover default error values to start with for web root: %ls", wzRoot); | ||
| 235 | |||
| 236 | // The above code should have come up with some value to start pwzErrors off with. Make sure it did. | ||
| 237 | if (NULL == pwzErrors) | ||
| 238 | { | ||
| 239 | ExitOnFailure(hr = E_UNEXPECTED, "failed to discover default error values to start with for web root: %ls", wzRoot); | ||
| 240 | } | ||
| 241 | |||
| 242 | // Loop through the web errors | ||
| 243 | for (SCA_WEB_ERROR* pswe = psweList; pswe; pswe = pswe->psweNext) | ||
| 244 | { | ||
| 245 | // Assume that we will have to replace | ||
| 246 | fOldValueFound = TRUE; | ||
| 247 | |||
| 248 | // If the subcode is 0, that means "*" in MD_CUSTOM_ERROR (thus the special formatting logic) | ||
| 249 | if (0 == pswe->iSubCode) | ||
| 250 | { | ||
| 251 | hr = StrAllocFormatted(&pwzCodeSubCode, L"%d,*", pswe->iErrorCode); | ||
| 252 | ExitOnFailure(hr, "failed to create error code string while installing web error"); | ||
| 253 | } | ||
| 254 | else | ||
| 255 | { | ||
| 256 | hr = StrAllocFormatted(&pwzCodeSubCode, L"%d,%d", pswe->iErrorCode, pswe->iSubCode); | ||
| 257 | ExitOnFailure(hr, "failed to create error code,subcode string while installing web error"); | ||
| 258 | } | ||
| 259 | |||
| 260 | hr = MultiSzFindSubstring(pwzErrors, pwzCodeSubCode, &dwFoundCodeSubCodeIndex, &wzFoundCodeSubCode); | ||
| 261 | ExitOnFailure(hr, "failed to find existing error code,subcode: %ls", pwzCodeSubCode); | ||
| 262 | |||
| 263 | // If we didn't find this error code/sub code pair in the list already, make sure it's acceptable to add | ||
| 264 | if (S_FALSE == hr) | ||
| 265 | { | ||
| 266 | // | ||
| 267 | // Make sure this error code/sub code pair is in the "acceptable" list | ||
| 268 | // | ||
| 269 | |||
| 270 | // If the subcode is 0, that means "0" in MD_CUSTOM_ERROR_DESC (no special formatting logic needed) | ||
| 271 | hr = StrAllocFormatted(&pwzAcceptableCodeSubCode, L"%d,%d", pswe->iErrorCode, pswe->iSubCode); | ||
| 272 | ExitOnFailure(hr, "failed to create error code,subcode string while installing web error"); | ||
| 273 | |||
| 274 | // We don't care where it is, just whether it's there or not | ||
| 275 | hr = MultiSzFindSubstring(pwzAcceptableErrors, pwzAcceptableCodeSubCode, NULL, NULL); | ||
| 276 | ExitOnFailure(hr, "failed to find whether or not error code, subcode: %ls is supported", pwzCodeSubCode); | ||
| 277 | |||
| 278 | if (S_FALSE == hr) | ||
| 279 | { | ||
| 280 | WcaLog(LOGMSG_VERBOSE, "Skipping error code, subcode: %ls because it is not supported by the server.", pwzCodeSubCode); | ||
| 281 | continue; | ||
| 282 | } | ||
| 283 | |||
| 284 | // If we didn't find it (and its an acceptable error) then we have nothing to replace | ||
| 285 | fOldValueFound = FALSE; | ||
| 286 | } | ||
| 287 | |||
| 288 | // Set up the new error string if needed | ||
| 289 | if (*(pswe->wzFile)) | ||
| 290 | { | ||
| 291 | hr = StrAllocFormatted(&pwzNewError, L"%s,FILE,%s", pwzCodeSubCode, pswe->wzFile); | ||
| 292 | ExitOnFailure(hr, "failed to create new error code string with code,subcode: %ls, file: %ls", pwzCodeSubCode, pswe->wzFile); | ||
| 293 | } | ||
| 294 | else if (*(pswe->wzURL)) | ||
| 295 | { | ||
| 296 | hr = StrAllocFormatted(&pwzNewError, L"%s,URL,%s", pwzCodeSubCode, pswe->wzURL); | ||
| 297 | ExitOnFailure(hr, "failed to create new error code string with code,subcode: %ls, file: %ls", pwzCodeSubCode, pswe->wzFile); | ||
| 298 | } | ||
| 299 | else if (fOldValueFound) | ||
| 300 | { | ||
| 301 | // If no File or URL was specified, they want a default error so remove the old value from the MULTISZ and move on | ||
| 302 | hr = MultiSzRemoveString(&pwzErrors, dwFoundCodeSubCodeIndex); | ||
| 303 | ExitOnFailure(hr, "failed to remove string for error code sub code: %ls in order to make it 'default'", pwzCodeSubCode); | ||
| 304 | continue; | ||
| 305 | } | ||
| 306 | |||
| 307 | // If we have something to replace, replace it, otherwise, put it at the beginning (order shouldn't matter) | ||
| 308 | if (fOldValueFound) | ||
| 309 | { | ||
| 310 | hr = MultiSzReplaceString(&pwzErrors, dwFoundCodeSubCodeIndex, pwzNewError); | ||
| 311 | ExitOnFailure(hr, "failed to replace old error string with new error string for error code,subcode: %ls", pwzCodeSubCode); | ||
| 312 | } | ||
| 313 | else | ||
| 314 | { | ||
| 315 | hr = MultiSzPrepend(&pwzErrors, NULL, pwzNewError); | ||
| 316 | ExitOnFailure(hr, "failed to prepend new error string for error code,subcode: %ls", pwzCodeSubCode); | ||
| 317 | } | ||
| 318 | } | ||
| 319 | |||
| 320 | // now write the CustomErrors to the metabase | ||
| 321 | if (weptWeb == iParentType) | ||
| 322 | { | ||
| 323 | hr = ScaWriteMetabaseValue(piMetabase, wzRoot, L"/Root", MD_CUSTOM_ERROR, METADATA_INHERIT, IIS_MD_UT_FILE, MULTISZ_METADATA, pwzErrors); | ||
| 324 | ExitOnFailure(hr, "Failed to write Web Error to /Root"); | ||
| 325 | } | ||
| 326 | else | ||
| 327 | { | ||
| 328 | hr = ScaWriteMetabaseValue(piMetabase, wzRoot, NULL, MD_CUSTOM_ERROR, METADATA_INHERIT, IIS_MD_UT_FILE, MULTISZ_METADATA, pwzErrors); | ||
| 329 | ExitOnFailure(hr, "Failed to write Web Error"); | ||
| 330 | } | ||
| 331 | |||
| 332 | LExit: | ||
| 333 | ReleaseStr(pwzErrors); | ||
| 334 | ReleaseStr(pwzSearchKey); | ||
| 335 | ReleaseStr(pwzCodeSubCode); | ||
| 336 | ReleaseStr(pwzAcceptableCodeSubCode); | ||
| 337 | ReleaseStr(pwzAcceptableErrors); | ||
| 338 | |||
| 339 | return hr; | ||
| 340 | } | ||
| 341 | |||
| 342 | static HRESULT AddWebErrorToList(SCA_WEB_ERROR** ppsweList) | ||
| 343 | { | ||
| 344 | HRESULT hr = S_OK; | ||
| 345 | |||
| 346 | SCA_WEB_ERROR* pswe = static_cast<SCA_WEB_ERROR*>(MemAlloc(sizeof(SCA_WEB_ERROR), TRUE)); | ||
| 347 | ExitOnNull(pswe, hr, E_OUTOFMEMORY, "failed to allocate memory for new web error list element"); | ||
| 348 | |||
| 349 | pswe->psweNext = *ppsweList; | ||
| 350 | *ppsweList = pswe; | ||
| 351 | |||
| 352 | LExit: | ||
| 353 | return hr; | ||
| 354 | } | ||
| 355 | |||
| 356 | HRESULT ScaWebErrorCheckList(SCA_WEB_ERROR* psweList) | ||
| 357 | { | ||
| 358 | if (!psweList) | ||
| 359 | { | ||
| 360 | return S_OK; | ||
| 361 | } | ||
| 362 | |||
| 363 | while (psweList) | ||
| 364 | { | ||
| 365 | WcaLog(LOGMSG_STANDARD, "WebError code: %d subcode: %d for parent: %ls not used!", psweList->iErrorCode, psweList->iSubCode, psweList->wzParentValue); | ||
| 366 | psweList = psweList->psweNext; | ||
| 367 | } | ||
| 368 | |||
| 369 | return E_FAIL; | ||
| 370 | } | ||
| 371 | |||
diff --git a/src/ca/scaweberr.h b/src/ca/scaweberr.h new file mode 100644 index 00000000..ad8ff4f5 --- /dev/null +++ b/src/ca/scaweberr.h | |||
| @@ -0,0 +1,30 @@ | |||
| 1 | #pragma once | ||
| 2 | // 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. | ||
| 3 | |||
| 4 | |||
| 5 | enum eWebErrorParentType { weptVDir = 1, weptWeb }; | ||
| 6 | |||
| 7 | struct SCA_WEB_ERROR | ||
| 8 | { | ||
| 9 | int iErrorCode; | ||
| 10 | int iSubCode; | ||
| 11 | |||
| 12 | int iParentType; | ||
| 13 | WCHAR wzParentValue[MAX_DARWIN_KEY + 1]; | ||
| 14 | |||
| 15 | WCHAR wzFile[MAX_PATH]; | ||
| 16 | WCHAR wzURL[MAX_PATH]; // TODO: this needs to be bigger than MAX_PATH | ||
| 17 | |||
| 18 | SCA_WEB_ERROR *psweNext; | ||
| 19 | }; | ||
| 20 | |||
| 21 | // prototypes | ||
| 22 | HRESULT ScaWebErrorRead( | ||
| 23 | SCA_WEB_ERROR **ppsweList, | ||
| 24 | __inout LPWSTR *ppwzCustomActionData | ||
| 25 | ); | ||
| 26 | void ScaWebErrorFreeList(SCA_WEB_ERROR *psweList); | ||
| 27 | HRESULT ScaWebErrorCheckList(SCA_WEB_ERROR* psweList); | ||
| 28 | HRESULT ScaGetWebError(int iParentType, LPCWSTR wzParentValue, SCA_WEB_ERROR **ppsweList, SCA_WEB_ERROR **ppsweOut); | ||
| 29 | HRESULT ScaWriteWebError(IMSAdminBase* piMetabase, int iParentType, LPCWSTR wzRoot, SCA_WEB_ERROR* psweList); | ||
| 30 | |||
diff --git a/src/ca/scaweberr7.cpp b/src/ca/scaweberr7.cpp new file mode 100644 index 00000000..33c2f1bd --- /dev/null +++ b/src/ca/scaweberr7.cpp | |||
| @@ -0,0 +1,88 @@ | |||
| 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 | #include "precomp.h" | ||
| 4 | |||
| 5 | HRESULT ScaWriteWebError7( | ||
| 6 | __in_z LPCWSTR wzWebName, | ||
| 7 | __in_z LPCWSTR wzRoot, | ||
| 8 | SCA_WEB_ERROR* psweList | ||
| 9 | ) | ||
| 10 | { | ||
| 11 | HRESULT hr = S_OK; | ||
| 12 | |||
| 13 | hr = ScaWriteConfigID(IIS_WEBERROR_BEGIN); | ||
| 14 | ExitOnFailure(hr, "Fail to write webError begin ID"); | ||
| 15 | |||
| 16 | hr = ScaWriteConfigString(wzWebName); | ||
| 17 | ExitOnFailure(hr, "Fail to write webError Web Key"); | ||
| 18 | |||
| 19 | hr = ScaWriteConfigString(wzRoot); | ||
| 20 | ExitOnFailure(hr, "Fail to write webError Vdir key"); | ||
| 21 | |||
| 22 | // Loop through the HTTP headers | ||
| 23 | for (SCA_WEB_ERROR* pswe = psweList; pswe; pswe = pswe->psweNext) | ||
| 24 | { | ||
| 25 | hr = ScaWriteConfigID(IIS_WEBERROR); | ||
| 26 | ExitOnFailure(hr, "Fail to write webError ID"); | ||
| 27 | |||
| 28 | hr = ScaWriteConfigInteger(pswe->iErrorCode); | ||
| 29 | ExitOnFailure(hr, "Fail to write webError code"); | ||
| 30 | |||
| 31 | hr = ScaWriteConfigInteger(pswe->iSubCode); | ||
| 32 | ExitOnFailure(hr, "Fail to write webError subcode"); | ||
| 33 | |||
| 34 | //just write one | ||
| 35 | if (*(pswe->wzFile)) | ||
| 36 | { | ||
| 37 | hr = ScaWriteConfigString(pswe->wzFile); | ||
| 38 | ExitOnFailure(hr, "Fail to write webError file"); | ||
| 39 | hr = ScaWriteConfigInteger(0); | ||
| 40 | ExitOnFailure(hr, "Fail to write webError file code"); | ||
| 41 | } | ||
| 42 | else if (*(pswe->wzURL)) | ||
| 43 | { | ||
| 44 | hr = ScaWriteConfigString(pswe->wzURL); | ||
| 45 | ExitOnFailure(hr, "Fail to write webError URL"); | ||
| 46 | hr = ScaWriteConfigInteger(1); | ||
| 47 | ExitOnFailure(hr, "Fail to write webError URL code"); | ||
| 48 | } | ||
| 49 | } | ||
| 50 | |||
| 51 | hr = ScaWriteConfigID(IIS_WEBERROR_END); | ||
| 52 | ExitOnFailure(hr, "Fail to write httpHeader end ID"); | ||
| 53 | |||
| 54 | LExit: | ||
| 55 | return hr; | ||
| 56 | |||
| 57 | } | ||
| 58 | |||
| 59 | //static HRESULT AddWebErrorToList(SCA_WEB_ERROR** ppsweList) | ||
| 60 | //{ | ||
| 61 | // HRESULT hr = S_OK; | ||
| 62 | // | ||
| 63 | // SCA_WEB_ERROR* pswe = static_cast<SCA_WEB_ERROR*>(MemAlloc(sizeof(SCA_WEB_ERROR), TRUE)); | ||
| 64 | // ExitOnNull(pswe, hr, E_OUTOFMEMORY, "failed to allocate memory for new web error list element"); | ||
| 65 | // | ||
| 66 | // pswe->psweNext = *ppsweList; | ||
| 67 | // *ppsweList = pswe; | ||
| 68 | // | ||
| 69 | //LExit: | ||
| 70 | // return hr; | ||
| 71 | //} | ||
| 72 | |||
| 73 | HRESULT ScaWebErrorCheckList7(SCA_WEB_ERROR* psweList) | ||
| 74 | { | ||
| 75 | if (!psweList) | ||
| 76 | { | ||
| 77 | return S_OK; | ||
| 78 | } | ||
| 79 | |||
| 80 | while (psweList) | ||
| 81 | { | ||
| 82 | WcaLog(LOGMSG_STANDARD, "WebError code: %d subcode: %d for parent: %ls not used!", psweList->iErrorCode, psweList->iSubCode, psweList->wzParentValue); | ||
| 83 | psweList = psweList->psweNext; | ||
| 84 | } | ||
| 85 | |||
| 86 | return E_FAIL; | ||
| 87 | } | ||
| 88 | |||
diff --git a/src/ca/scaweberr7.h b/src/ca/scaweberr7.h new file mode 100644 index 00000000..62448211 --- /dev/null +++ b/src/ca/scaweberr7.h | |||
| @@ -0,0 +1,10 @@ | |||
| 1 | #pragma once | ||
| 2 | // 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. | ||
| 3 | |||
| 4 | |||
| 5 | HRESULT ScaWriteWebError7( | ||
| 6 | __in_z LPCWSTR wzWebName, | ||
| 7 | __in_z LPCWSTR wzRoot, | ||
| 8 | SCA_WEB_ERROR* psweList | ||
| 9 | ); | ||
| 10 | |||
diff --git a/src/ca/scaweblog.cpp b/src/ca/scaweblog.cpp new file mode 100644 index 00000000..01147848 --- /dev/null +++ b/src/ca/scaweblog.cpp | |||
| @@ -0,0 +1,177 @@ | |||
| 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 | #include "precomp.h" | ||
| 4 | |||
| 5 | enum eWebLogQuery { wlqLog = 1, wlqFormat }; | ||
| 6 | |||
| 7 | /* **************************************************************** | ||
| 8 | * LookupLogFormatGUID -Looks up a given IIS Log format type in | ||
| 9 | * the metabase and returns the GUID for it. | ||
| 10 | * ****************************************************************/ | ||
| 11 | static HRESULT LookupLogFormatGUID( | ||
| 12 | __in IMSAdminBase* piMetabase, | ||
| 13 | __in LPCWSTR wzLogFormat, | ||
| 14 | __out_ecount(cchGUID) LPWSTR wzGUID, | ||
| 15 | __in int cchGUID | ||
| 16 | ) | ||
| 17 | { | ||
| 18 | WCHAR wzKey[METADATA_MAX_NAME_LEN]; | ||
| 19 | HRESULT hr = S_OK; | ||
| 20 | |||
| 21 | METADATA_RECORD mrKeyType; | ||
| 22 | ::ZeroMemory(&mrKeyType, sizeof(mrKeyType)); | ||
| 23 | |||
| 24 | mrKeyType.dwMDIdentifier = MD_KEY_TYPE; | ||
| 25 | mrKeyType.dwMDAttributes = METADATA_NO_ATTRIBUTES; | ||
| 26 | mrKeyType.dwMDUserType = IIS_MD_UT_SERVER; | ||
| 27 | mrKeyType.dwMDDataType = ALL_METADATA; | ||
| 28 | mrKeyType.dwMDDataLen = 0; | ||
| 29 | mrKeyType.pbMDData = NULL; | ||
| 30 | |||
| 31 | METADATA_RECORD mrPluginId; | ||
| 32 | ::ZeroMemory(&mrPluginId, sizeof(mrPluginId)); | ||
| 33 | |||
| 34 | mrPluginId.dwMDIdentifier = MD_LOG_PLUGIN_MOD_ID; | ||
| 35 | mrPluginId.dwMDAttributes = METADATA_INHERIT; | ||
| 36 | mrPluginId.dwMDUserType = IIS_MD_UT_SERVER; | ||
| 37 | mrPluginId.dwMDDataType = ALL_METADATA; | ||
| 38 | mrPluginId.dwMDDataLen = 0; | ||
| 39 | mrPluginId.pbMDData = NULL; | ||
| 40 | |||
| 41 | hr = ::StringCchPrintfW(wzKey, countof(wzKey), L"/LM/Logging/%s", wzLogFormat); | ||
| 42 | ExitOnFailure(hr, "failed to format logging metabase key name"); | ||
| 43 | |||
| 44 | // verify that we have this log format available in IIS | ||
| 45 | hr = MetaGetValue(piMetabase, METADATA_MASTER_ROOT_HANDLE, wzKey, &mrKeyType); | ||
| 46 | ExitOnFailure(hr, "Failed to find specified Log format key in IIS for log format: %ls", wzLogFormat); | ||
| 47 | ExitOnNull(mrKeyType.pbMDData, hr, E_POINTER, "Request for Log format key in IIS for log format returned success, but value was NULL"); | ||
| 48 | |||
| 49 | if (0 != lstrcmpW(L"IIsLogModule", (LPCWSTR)mrKeyType.pbMDData)) | ||
| 50 | { | ||
| 51 | ExitOnFailure(hr = E_UNEXPECTED, "Found invalid log format in IIS: %ls", (LPCWSTR)mrKeyType.pbMDData); | ||
| 52 | } | ||
| 53 | |||
| 54 | // find the GUID for that log format | ||
| 55 | hr = MetaGetValue(piMetabase, METADATA_MASTER_ROOT_HANDLE, wzKey, &mrPluginId); | ||
| 56 | ExitOnFailure(hr, "Failed to retrieve IISLog format GUID. Key: %ls", wzKey); | ||
| 57 | ExitOnNull(mrPluginId.pbMDData, hr, E_POINTER, "Retrieval of IISLog format GUID returned success, but value was NULL"); | ||
| 58 | |||
| 59 | hr = ::StringCchCopyW(wzGUID, cchGUID, (LPCWSTR)mrPluginId.pbMDData); | ||
| 60 | ExitOnFailure(hr, "failed to copy metabase value: %ls", (LPCWSTR)mrPluginId.pbMDData); | ||
| 61 | |||
| 62 | LExit: | ||
| 63 | |||
| 64 | if (mrKeyType.pbMDData) | ||
| 65 | { | ||
| 66 | MetaFreeValue(&mrKeyType); | ||
| 67 | } | ||
| 68 | |||
| 69 | if (mrPluginId.pbMDData) | ||
| 70 | { | ||
| 71 | MetaFreeValue(&mrPluginId); | ||
| 72 | } | ||
| 73 | |||
| 74 | return hr; | ||
| 75 | } | ||
| 76 | |||
| 77 | |||
| 78 | /* **************************************************************** | ||
| 79 | * ScaGetWebLog -Retrieves Log table data for the specified Log key | ||
| 80 | * | ||
| 81 | * ****************************************************************/ | ||
| 82 | HRESULT ScaGetWebLog( | ||
| 83 | IMSAdminBase* piMetabase, | ||
| 84 | LPCWSTR wzLog, | ||
| 85 | __in WCA_WRAPQUERY_HANDLE hWebLogQuery, | ||
| 86 | SCA_WEB_LOG* pswl | ||
| 87 | ) | ||
| 88 | { | ||
| 89 | HRESULT hr = S_OK; | ||
| 90 | LPWSTR pwzData = NULL; | ||
| 91 | MSIHANDLE hRec; | ||
| 92 | |||
| 93 | if (0 == WcaGetQueryRecords(hWebLogQuery)) | ||
| 94 | { | ||
| 95 | WcaLog(LOGMSG_VERBOSE, "Skipping ScaGetWebLog() - no records to process"); | ||
| 96 | ExitFunction1(hr = S_FALSE); | ||
| 97 | } | ||
| 98 | |||
| 99 | WcaFetchWrappedReset(hWebLogQuery); | ||
| 100 | |||
| 101 | hr = WcaFetchWrappedRecordWhereString(hWebLogQuery, wlqLog, wzLog, &hRec); | ||
| 102 | if (E_NOMOREITEMS == hr) | ||
| 103 | { | ||
| 104 | ExitOnFailure(hr, "cannot locate IIsWebLog.Log='%ls'", wzLog); | ||
| 105 | } | ||
| 106 | HRESULT hrTemp = WcaFetchWrappedRecordWhereString(hWebLogQuery, wlqLog, wzLog, &hRec); | ||
| 107 | |||
| 108 | if (SUCCEEDED(hrTemp)) | ||
| 109 | { | ||
| 110 | ExitOnFailure(hr, "error - found multiple matching IIsWebLog rows"); | ||
| 111 | } | ||
| 112 | |||
| 113 | ::ZeroMemory(pswl, sizeof(SCA_WEB_LOG)); | ||
| 114 | |||
| 115 | // check that log key matches | ||
| 116 | hr = WcaGetRecordString(hRec, wlqLog, &pwzData); | ||
| 117 | ExitOnFailure(hr, "failed to get IIsWebLog.Log for Log: %ls", wzLog); | ||
| 118 | hr = ::StringCchCopyW(pswl->wzLog, countof(pswl->wzLog), pwzData); | ||
| 119 | ExitOnFailure(hr, "failed to copy log name: %ls", pwzData); | ||
| 120 | |||
| 121 | hr = WcaGetRecordString(hRec, wlqFormat, &pwzData); | ||
| 122 | ExitOnFailure(hr, "failed to get IIsWebLog.Format for Log:", wzLog); | ||
| 123 | hr = ::StringCchCopyW(pswl->wzFormat, countof(pswl->wzFormat), pwzData); | ||
| 124 | ExitOnFailure(hr, "failed to copy log format: %ls", pwzData); | ||
| 125 | |||
| 126 | // if they specified a log format, look up its GUID in the metabase | ||
| 127 | if (*pswl->wzFormat && 0 != lstrcmpW(pswl->wzFormat, L"none")) | ||
| 128 | { | ||
| 129 | hr = LookupLogFormatGUID(piMetabase, pswl->wzFormat, pswl->wzFormatGUID, countof(pswl->wzFormatGUID)); | ||
| 130 | ExitOnFailure(hr, "Failed to get Log Format GUID for Log: %ls", wzLog); | ||
| 131 | } | ||
| 132 | |||
| 133 | LExit: | ||
| 134 | ReleaseStr(pwzData); | ||
| 135 | |||
| 136 | return hr; | ||
| 137 | } | ||
| 138 | |||
| 139 | |||
| 140 | /* **************************************************************** | ||
| 141 | * ScaWriteWebLog -Writes the IIS log values to the metabase. | ||
| 142 | * | ||
| 143 | * ****************************************************************/ | ||
| 144 | HRESULT ScaWriteWebLog( | ||
| 145 | IMSAdminBase* piMetabase, | ||
| 146 | LPCWSTR wzWebBase, | ||
| 147 | SCA_WEB_LOG *pswl | ||
| 148 | ) | ||
| 149 | { | ||
| 150 | HRESULT hr = S_OK; | ||
| 151 | |||
| 152 | if (*pswl->wzFormat) | ||
| 153 | { | ||
| 154 | if (0 == lstrcmpW(pswl->wzFormat, L"none")) | ||
| 155 | { | ||
| 156 | // user wishes for Logging to be turned 'off' | ||
| 157 | hr = ScaWriteMetabaseValue(piMetabase, wzWebBase, L"", MD_LOG_TYPE, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, (LPVOID)((DWORD_PTR)0)); | ||
| 158 | ExitOnFailure(hr, "Failed to write Log Type for Web: %ls", wzWebBase); | ||
| 159 | } | ||
| 160 | else | ||
| 161 | { | ||
| 162 | Assert(*pswl->wzFormatGUID); | ||
| 163 | |||
| 164 | // write the GUID for the log format for the web to the metabase | ||
| 165 | hr = ScaWriteMetabaseValue(piMetabase, wzWebBase, L"", MD_LOG_PLUGIN_ORDER, METADATA_INHERIT, IIS_MD_UT_SERVER, STRING_METADATA, pswl->wzFormatGUID); | ||
| 166 | ExitOnFailure(hr, "Failed to write Log GUID for Web: %ls", wzWebBase); | ||
| 167 | |||
| 168 | hr = ScaWriteMetabaseValue(piMetabase, wzWebBase, L"", MD_LOG_TYPE, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, (LPVOID)((DWORD_PTR)1)); | ||
| 169 | ExitOnFailure(hr, "Failed to write Log Type for Web: %ls", wzWebBase); | ||
| 170 | } | ||
| 171 | } | ||
| 172 | |||
| 173 | LExit: | ||
| 174 | return hr; | ||
| 175 | } | ||
| 176 | |||
| 177 | |||
diff --git a/src/ca/scaweblog.h b/src/ca/scaweblog.h new file mode 100644 index 00000000..1a690cce --- /dev/null +++ b/src/ca/scaweblog.h | |||
| @@ -0,0 +1,27 @@ | |||
| 1 | #pragma once | ||
| 2 | // 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. | ||
| 3 | |||
| 4 | |||
| 5 | struct SCA_WEB_LOG | ||
| 6 | { | ||
| 7 | // iis configuation information | ||
| 8 | WCHAR wzLog[MAX_DARWIN_KEY + 1]; | ||
| 9 | |||
| 10 | // for specifying the log format | ||
| 11 | WCHAR wzFormat[MAX_DARWIN_KEY + 1]; | ||
| 12 | WCHAR wzFormatGUID[MAX_DARWIN_KEY + 1]; | ||
| 13 | }; | ||
| 14 | |||
| 15 | |||
| 16 | // prototypes | ||
| 17 | HRESULT ScaGetWebLog( | ||
| 18 | IMSAdminBase* piMetabase, | ||
| 19 | LPCWSTR wzLog, | ||
| 20 | __in WCA_WRAPQUERY_HANDLE hWebLogQuery, | ||
| 21 | SCA_WEB_LOG* pswl | ||
| 22 | ); | ||
| 23 | HRESULT ScaWriteWebLog( | ||
| 24 | IMSAdminBase* piMetabase, | ||
| 25 | LPCWSTR wzRootOfWeb, | ||
| 26 | SCA_WEB_LOG *pswl | ||
| 27 | ); | ||
diff --git a/src/ca/scaweblog7.cpp b/src/ca/scaweblog7.cpp new file mode 100644 index 00000000..c857c46f --- /dev/null +++ b/src/ca/scaweblog7.cpp | |||
| @@ -0,0 +1,120 @@ | |||
| 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 | #include "precomp.h" | ||
| 4 | // sql queries | ||
| 5 | LPCWSTR vcsWebLogQuery7 = L"SELECT `Log`, `Format` " | ||
| 6 | L"FROM `IIsWebLog` WHERE `Log`=?"; | ||
| 7 | |||
| 8 | enum eWebLogQuery { wlqLog = 1, wlqFormat }; | ||
| 9 | |||
| 10 | /* **************************************************************** | ||
| 11 | * ScaGetWebLog7 -Retrieves Log table data for the specified Log key | ||
| 12 | * | ||
| 13 | * ****************************************************************/ | ||
| 14 | HRESULT ScaGetWebLog7( | ||
| 15 | __in_z LPCWSTR wzLog, | ||
| 16 | __in WCA_WRAPQUERY_HANDLE hWebLogQuery, | ||
| 17 | __out SCA_WEB_LOG* pswl | ||
| 18 | ) | ||
| 19 | { | ||
| 20 | HRESULT hr = S_OK; | ||
| 21 | LPWSTR pwzData = NULL; | ||
| 22 | MSIHANDLE hRec; | ||
| 23 | |||
| 24 | if (0 == WcaGetQueryRecords(hWebLogQuery)) | ||
| 25 | { | ||
| 26 | WcaLog(LOGMSG_VERBOSE, "Skipping ScaGetWebLog() - no records to process"); | ||
| 27 | ExitFunction1(hr = S_FALSE); | ||
| 28 | } | ||
| 29 | |||
| 30 | WcaFetchWrappedReset(hWebLogQuery); | ||
| 31 | |||
| 32 | hr = WcaFetchWrappedRecordWhereString(hWebLogQuery, wlqLog, wzLog, &hRec); | ||
| 33 | if (E_NOMOREITEMS == hr) | ||
| 34 | { | ||
| 35 | ExitOnFailure(hr, "cannot locate IIsWebLog.Log='%ls'", wzLog); | ||
| 36 | } | ||
| 37 | HRESULT hrTemp = WcaFetchWrappedRecordWhereString(hWebLogQuery, wlqLog, wzLog, &hRec); | ||
| 38 | |||
| 39 | if (SUCCEEDED(hrTemp)) | ||
| 40 | { | ||
| 41 | ExitOnFailure(hr, "error - found multiple matching IIsWebLog rows"); | ||
| 42 | } | ||
| 43 | |||
| 44 | ::ZeroMemory(pswl, sizeof(SCA_WEB_LOG)); | ||
| 45 | |||
| 46 | // check that log key matches | ||
| 47 | hr = WcaGetRecordString(hRec, wlqLog, &pwzData); | ||
| 48 | ExitOnFailure(hr, "failed to get IIsWebLog.Log for Log: %ls", wzLog); | ||
| 49 | hr = ::StringCchCopyW(pswl->wzLog, countof(pswl->wzLog), pwzData); | ||
| 50 | ExitOnFailure(hr, "failed to copy log name: %ls", pwzData); | ||
| 51 | |||
| 52 | hr = WcaGetRecordString(hRec, wlqFormat, &pwzData); | ||
| 53 | ExitOnFailure(hr, "failed to get IIsWebLog.Format for Log:", wzLog); | ||
| 54 | |||
| 55 | //translate WIX log format name strings to IIS7 | ||
| 56 | if (0 == lstrcmpW(pwzData, L"Microsoft IIS Log File Format")) | ||
| 57 | { | ||
| 58 | hr = ::StringCchCopyW(pswl->wzFormat, countof(pswl->wzFormat), L"IIS"); | ||
| 59 | ExitOnFailure(hr, "failed to copy log format: %ls", pwzData); | ||
| 60 | } | ||
| 61 | else if (0 == lstrcmpW(pwzData, L"NCSA Common Log File Format")) | ||
| 62 | { | ||
| 63 | hr = ::StringCchCopyW(pswl->wzFormat, countof(pswl->wzFormat), L"NCSA"); | ||
| 64 | ExitOnFailure(hr, "failed to copy log format: %ls", pwzData); | ||
| 65 | } | ||
| 66 | else if (0 == lstrcmpW(pwzData, L"none")) | ||
| 67 | { | ||
| 68 | hr = ::StringCchCopyW(pswl->wzFormat, countof(pswl->wzFormat), L"none"); | ||
| 69 | ExitOnFailure(hr, "failed to copy log format: %ls", pwzData); | ||
| 70 | } | ||
| 71 | else if (0 == lstrcmpW(pwzData, L"ODBC Logging")) | ||
| 72 | { | ||
| 73 | hr = ::StringCchCopyW(pswl->wzFormat, countof(pswl->wzFormat), L"W3C"); | ||
| 74 | ExitOnFailure(hr, "failed to copy log format: %ls", pwzData); | ||
| 75 | } | ||
| 76 | else if (0 == lstrcmpW(pwzData, L"W3C Extended Log File Format")) | ||
| 77 | { | ||
| 78 | hr = ::StringCchCopyW(pswl->wzFormat, countof(pswl->wzFormat), L"W3C"); | ||
| 79 | ExitOnFailure(hr, "failed to copy log format: %ls", pwzData); | ||
| 80 | } | ||
| 81 | else | ||
| 82 | { | ||
| 83 | hr = HRESULT_FROM_WIN32(ERROR_INVALID_INDEX); | ||
| 84 | ExitOnFailure(hr, "Invalid log file format: %ls", pwzData); | ||
| 85 | } | ||
| 86 | |||
| 87 | LExit: | ||
| 88 | ReleaseStr(pwzData); | ||
| 89 | |||
| 90 | return hr; | ||
| 91 | } | ||
| 92 | |||
| 93 | |||
| 94 | /* **************************************************************** | ||
| 95 | * ScaWriteWebLog -Writes the IIS log values to the metabase. | ||
| 96 | * | ||
| 97 | * ****************************************************************/ | ||
| 98 | HRESULT ScaWriteWebLog7( | ||
| 99 | LPCWSTR wzWebBase, | ||
| 100 | const SCA_WEB_LOG *pswl | ||
| 101 | ) | ||
| 102 | { | ||
| 103 | HRESULT hr = S_OK; | ||
| 104 | |||
| 105 | if (*pswl->wzFormat) | ||
| 106 | { | ||
| 107 | //write pswl->wzFormat | ||
| 108 | hr = ScaWriteConfigID(IIS_WEBLOG); | ||
| 109 | ExitOnFailure(hr, "Failed to write log format id"); | ||
| 110 | hr = ScaWriteConfigString(wzWebBase); | ||
| 111 | ExitOnFailure(hr, "Failed to write log web key"); | ||
| 112 | hr = ScaWriteConfigString(pswl->wzFormat); | ||
| 113 | ExitOnFailure(hr, "Failed to write log format string"); | ||
| 114 | } | ||
| 115 | |||
| 116 | LExit: | ||
| 117 | return hr; | ||
| 118 | } | ||
| 119 | |||
| 120 | |||
diff --git a/src/ca/scaweblog7.h b/src/ca/scaweblog7.h new file mode 100644 index 00000000..f2bb60d7 --- /dev/null +++ b/src/ca/scaweblog7.h | |||
| @@ -0,0 +1,14 @@ | |||
| 1 | #pragma once | ||
| 2 | // 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. | ||
| 3 | |||
| 4 | |||
| 5 | HRESULT ScaGetWebLog7( | ||
| 6 | __in_z LPCWSTR wzLog, | ||
| 7 | __in WCA_WRAPQUERY_HANDLE hWebLogQuery, | ||
| 8 | __out SCA_WEB_LOG* pswl | ||
| 9 | ); | ||
| 10 | |||
| 11 | HRESULT ScaWriteWebLog7( | ||
| 12 | __in_z LPCWSTR wzRootOfWeb, | ||
| 13 | const SCA_WEB_LOG *pswl | ||
| 14 | ); | ||
diff --git a/src/ca/scawebprop.cpp b/src/ca/scawebprop.cpp new file mode 100644 index 00000000..b5e38467 --- /dev/null +++ b/src/ca/scawebprop.cpp | |||
| @@ -0,0 +1,301 @@ | |||
| 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 | #include "precomp.h" | ||
| 4 | |||
| 5 | // sql queries | ||
| 6 | enum eWebDirPropertiesQuery { wpqProperties = 1, wpqAccess, wpqAuthorization, wpqUser, wpqControlledPassword, wpqLogVisits, wpqIndex, wpqDefaultDoc, wpqAspDetailedError, wpqHttpExp, wpqCCMaxAge, wpqCCCustom, wpqNoCustomError, wpqAccessSSLFlags, wpqAuthenticationProviders }; | ||
| 7 | |||
| 8 | HRESULT ScaGetWebDirProperties( | ||
| 9 | __in LPCWSTR wzProperties, | ||
| 10 | __in WCA_WRAPQUERY_HANDLE hUserQuery, | ||
| 11 | __in WCA_WRAPQUERY_HANDLE hWebDirPropQuery, | ||
| 12 | __inout SCA_WEB_PROPERTIES* pswp | ||
| 13 | ) | ||
| 14 | { | ||
| 15 | Assert(*wzProperties && pswp); | ||
| 16 | |||
| 17 | HRESULT hr = S_OK; | ||
| 18 | MSIHANDLE hRec; | ||
| 19 | LPWSTR pwzData = NULL; | ||
| 20 | |||
| 21 | ExitOnNull(wzProperties, hr, E_INVALIDARG, "Failed to get web directory properties because no properties were provided to get"); | ||
| 22 | |||
| 23 | WcaFetchWrappedReset(hWebDirPropQuery); | ||
| 24 | |||
| 25 | hr = WcaFetchWrappedRecordWhereString(hWebDirPropQuery, 1, wzProperties, &hRec); | ||
| 26 | if (S_OK == hr) | ||
| 27 | { | ||
| 28 | hr = WcaGetRecordString(hRec, wpqProperties, &pwzData); | ||
| 29 | ExitOnFailure(hr, "Failed to get IIsWebDirProperties.DirProperties"); | ||
| 30 | hr = ::StringCchCopyW(pswp->wzKey, countof(pswp->wzKey), pwzData); | ||
| 31 | ExitOnFailure(hr, "Failed to copy key string to webdirproperties object"); | ||
| 32 | |||
| 33 | Assert(0 == lstrcmpW(pswp->wzKey, wzProperties)); | ||
| 34 | |||
| 35 | hr = WcaGetRecordInteger(hRec, wpqAccess, &pswp->iAccess); | ||
| 36 | ExitOnFailure(hr, "Failed to get access value"); | ||
| 37 | |||
| 38 | hr = WcaGetRecordInteger(hRec, wpqAuthorization, &pswp->iAuthorization); | ||
| 39 | ExitOnFailure(hr, "Failed to get authorization value"); | ||
| 40 | |||
| 41 | // if allow anonymous users | ||
| 42 | if (S_OK == hr && pswp->iAuthorization & 1) | ||
| 43 | { | ||
| 44 | // if there is an anonymous user specified | ||
| 45 | hr = WcaGetRecordString(hRec, wpqUser, &pwzData); | ||
| 46 | ExitOnFailure(hr, "Failed to get AnonymousUser_"); | ||
| 47 | if (pwzData && *pwzData) | ||
| 48 | { | ||
| 49 | hr = WcaGetRecordInteger(hRec, wpqControlledPassword, &pswp->fIIsControlledPassword); | ||
| 50 | ExitOnFailure(hr, "Failed to get IIsControlledPassword"); | ||
| 51 | if (S_FALSE == hr) | ||
| 52 | { | ||
| 53 | pswp->fIIsControlledPassword = FALSE; | ||
| 54 | hr = S_OK; | ||
| 55 | } | ||
| 56 | |||
| 57 | hr = ScaGetUserDeferred(pwzData, hUserQuery, &pswp->scau); | ||
| 58 | ExitOnFailure(hr, "Failed to get User information for Web"); | ||
| 59 | |||
| 60 | pswp->fHasUser = TRUE; | ||
| 61 | } | ||
| 62 | else | ||
| 63 | pswp->fHasUser = FALSE; | ||
| 64 | } | ||
| 65 | |||
| 66 | hr = WcaGetRecordInteger(hRec, wpqLogVisits, &pswp->fLogVisits); | ||
| 67 | ExitOnFailure(hr, "Failed to get IIsWebDirProperties.LogVisits"); | ||
| 68 | |||
| 69 | hr = WcaGetRecordInteger(hRec, wpqIndex, &pswp->fIndex); | ||
| 70 | ExitOnFailure(hr, "Failed to get IIsWebDirProperties.Index"); | ||
| 71 | |||
| 72 | hr = WcaGetRecordString(hRec, wpqDefaultDoc, &pwzData); | ||
| 73 | ExitOnFailure(hr, "Failed to get IIsWebDirProperties.DefaultDoc"); | ||
| 74 | if (pwzData && *pwzData) | ||
| 75 | { | ||
| 76 | pswp->fHasDefaultDoc = TRUE; | ||
| 77 | if (0 == lstrcmpW(L"-", pwzData)) // remove any existing default documents by setting them blank | ||
| 78 | { | ||
| 79 | pswp->wzDefaultDoc[0] = L'\0'; | ||
| 80 | } | ||
| 81 | else // set the default documents | ||
| 82 | { | ||
| 83 | hr = ::StringCchCopyW(pswp->wzDefaultDoc, countof(pswp->wzDefaultDoc), pwzData); | ||
| 84 | ExitOnFailure(hr, "Failed to copy default document string to webdirproperties object"); | ||
| 85 | } | ||
| 86 | } | ||
| 87 | else | ||
| 88 | { | ||
| 89 | pswp->fHasDefaultDoc = FALSE; | ||
| 90 | } | ||
| 91 | |||
| 92 | hr = WcaGetRecordInteger(hRec, wpqAspDetailedError, &pswp->fAspDetailedError); | ||
| 93 | ExitOnFailure(hr, "Failed to get IIsWebDirProperties.AspDetailedError"); | ||
| 94 | |||
| 95 | hr = WcaGetRecordString(hRec, wpqHttpExp, &pwzData); | ||
| 96 | ExitOnFailure(hr, "Failed to get IIsWebDirProperties.HttpExp"); | ||
| 97 | if (pwzData && *pwzData) | ||
| 98 | { | ||
| 99 | pswp->fHasHttpExp = TRUE; | ||
| 100 | if (0 == lstrcmpW(L"-", pwzData)) // remove any existing default expiration settings by setting them blank | ||
| 101 | { | ||
| 102 | pswp->wzHttpExp[0] = L'\0'; | ||
| 103 | } | ||
| 104 | else // set the expiration setting | ||
| 105 | { | ||
| 106 | hr = ::StringCchCopyW(pswp->wzHttpExp, countof(pswp->wzHttpExp), pwzData); | ||
| 107 | ExitOnFailure(hr, "Failed to copy http expiration string to webdirproperties object"); | ||
| 108 | } | ||
| 109 | } | ||
| 110 | else | ||
| 111 | { | ||
| 112 | pswp->fHasHttpExp = FALSE; | ||
| 113 | } | ||
| 114 | |||
| 115 | hr = WcaGetRecordInteger(hRec, wpqCCMaxAge, &pswp->iCacheControlMaxAge); | ||
| 116 | ExitOnFailure(hr, "failed to get IIsWebDirProperties.CacheControlMaxAge"); | ||
| 117 | |||
| 118 | hr = WcaGetRecordString(hRec, wpqCCCustom, &pwzData); | ||
| 119 | ExitOnFailure(hr, "Failed to get IIsWebDirProperties.CacheControlCustom"); | ||
| 120 | if (pwzData && *pwzData) | ||
| 121 | { | ||
| 122 | pswp->fHasCacheControlCustom = TRUE; | ||
| 123 | if (0 == lstrcmpW(L"-", pwzData)) // remove any existing default cache control custom settings by setting them blank | ||
| 124 | { | ||
| 125 | pswp->wzCacheControlCustom[0] = L'\0'; | ||
| 126 | } | ||
| 127 | else // set the custom cache control setting | ||
| 128 | { | ||
| 129 | hr = ::StringCchCopyW(pswp->wzCacheControlCustom, countof(pswp->wzCacheControlCustom), pwzData); | ||
| 130 | ExitOnFailure(hr, "Failed to copy cache control custom settings to webdirproperites object"); | ||
| 131 | } | ||
| 132 | } | ||
| 133 | else | ||
| 134 | { | ||
| 135 | pswp->fHasCacheControlCustom = FALSE; | ||
| 136 | } | ||
| 137 | |||
| 138 | hr = WcaGetRecordInteger(hRec, wpqNoCustomError, &pswp->fNoCustomError); | ||
| 139 | ExitOnFailure(hr, "failed to get IIsWebDirProperties.NoCustomError"); | ||
| 140 | if (MSI_NULL_INTEGER == pswp->fNoCustomError) | ||
| 141 | pswp->fNoCustomError = FALSE; | ||
| 142 | |||
| 143 | hr = WcaGetRecordInteger(hRec, wpqAccessSSLFlags, &pswp->iAccessSSLFlags); | ||
| 144 | ExitOnFailure(hr, "failed to get IIsWebDirProperties.AccessSSLFlags"); | ||
| 145 | |||
| 146 | hr = WcaGetRecordString(hRec, wpqAuthenticationProviders, &pwzData); | ||
| 147 | ExitOnFailure(hr, "Failed to get IIsWebDirProperties.AuthenticationProviders"); | ||
| 148 | if (pwzData && *pwzData) | ||
| 149 | { | ||
| 150 | hr = ::StringCchCopyW(pswp->wzAuthenticationProviders, countof(pswp->wzAuthenticationProviders), pwzData); | ||
| 151 | ExitOnFailure(hr, "Failed to copy authentication providers string to webdirproperties object"); | ||
| 152 | } | ||
| 153 | else | ||
| 154 | { | ||
| 155 | pswp->wzAuthenticationProviders[0] = L'\0'; | ||
| 156 | } | ||
| 157 | } | ||
| 158 | else if (E_NOMOREITEMS == hr) | ||
| 159 | { | ||
| 160 | WcaLog(LOGMSG_STANDARD, "Error: Cannot locate IIsWebDirProperties.DirProperties='%ls'", wzProperties); | ||
| 161 | hr = E_FAIL; | ||
| 162 | } | ||
| 163 | else | ||
| 164 | { | ||
| 165 | ExitOnFailure(hr, "Error getting appropriate webdirproperty"); | ||
| 166 | } | ||
| 167 | |||
| 168 | // Let's check that there isn't more than one record found - if there is, throw an assert like WcaFetchSingleRecord() would | ||
| 169 | HRESULT hrTemp = WcaFetchWrappedRecordWhereString(hWebDirPropQuery, 1, wzProperties, &hRec); | ||
| 170 | if (SUCCEEDED(hrTemp)) | ||
| 171 | { | ||
| 172 | AssertSz(E_NOMOREITEMS == hrTemp, "ScaGetWebDirProperties found more than one record"); | ||
| 173 | } | ||
| 174 | |||
| 175 | LExit: | ||
| 176 | ReleaseStr(pwzData); | ||
| 177 | |||
| 178 | return hr; | ||
| 179 | } | ||
| 180 | |||
| 181 | |||
| 182 | HRESULT ScaWriteWebDirProperties( | ||
| 183 | __in IMSAdminBase* piMetabase, | ||
| 184 | __in LPCWSTR wzRootOfWeb, | ||
| 185 | __inout SCA_WEB_PROPERTIES* pswp | ||
| 186 | ) | ||
| 187 | { | ||
| 188 | HRESULT hr = S_OK; | ||
| 189 | DWORD dw = 0; | ||
| 190 | WCHAR wz[METADATA_MAX_NAME_LEN + 1]; | ||
| 191 | |||
| 192 | // write the access permissions to the metabase | ||
| 193 | if (MSI_NULL_INTEGER != pswp->iAccess) | ||
| 194 | { | ||
| 195 | hr = ScaWriteMetabaseValue(piMetabase, wzRootOfWeb, NULL, MD_ACCESS_PERM, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, (LPVOID)((DWORD_PTR)pswp->iAccess)); | ||
| 196 | ExitOnFailure(hr, "Failed to write access permissions for Web"); | ||
| 197 | } | ||
| 198 | |||
| 199 | if (MSI_NULL_INTEGER != pswp->iAuthorization) | ||
| 200 | { | ||
| 201 | hr = ScaWriteMetabaseValue(piMetabase, wzRootOfWeb, NULL, MD_AUTHORIZATION, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, (LPVOID)((DWORD_PTR)pswp->iAuthorization)); | ||
| 202 | ExitOnFailure(hr, "Failed to write authorization for Web"); | ||
| 203 | } | ||
| 204 | |||
| 205 | if (pswp->fHasUser) | ||
| 206 | { | ||
| 207 | Assert(pswp->scau.wzName); | ||
| 208 | // write the user name | ||
| 209 | if (*pswp->scau.wzDomain) | ||
| 210 | { | ||
| 211 | hr = ::StringCchPrintfW(wz, countof(wz), L"%s\\%s", pswp->scau.wzDomain, pswp->scau.wzName); | ||
| 212 | ExitOnFailure(hr, "Failed to format domain\\username string"); | ||
| 213 | } | ||
| 214 | else | ||
| 215 | { | ||
| 216 | hr = ::StringCchCopyW(wz, countof(wz), pswp->scau.wzName); | ||
| 217 | ExitOnFailure(hr, "Failed to copy user name"); | ||
| 218 | } | ||
| 219 | hr = ScaWriteMetabaseValue(piMetabase, wzRootOfWeb, NULL, MD_ANONYMOUS_USER_NAME, METADATA_INHERIT, IIS_MD_UT_FILE, STRING_METADATA, (LPVOID)wz); | ||
| 220 | ExitOnFailure(hr, "Failed to write anonymous user name for Web"); | ||
| 221 | |||
| 222 | // write the password | ||
| 223 | hr = ScaWriteMetabaseValue(piMetabase, wzRootOfWeb, NULL, MD_ANONYMOUS_PWD, METADATA_INHERIT | METADATA_SECURE, IIS_MD_UT_FILE, STRING_METADATA, (LPVOID)pswp->scau.wzPassword); | ||
| 224 | ExitOnFailure(hr, "Failed to write anonymous user password for Web"); | ||
| 225 | |||
| 226 | // store whether IIs controls password | ||
| 227 | dw = (pswp->fIIsControlledPassword) ? TRUE : FALSE; | ||
| 228 | hr = ScaWriteMetabaseValue(piMetabase, wzRootOfWeb, NULL, MD_ANONYMOUS_USE_SUBAUTH, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, (LPVOID)((DWORD_PTR)dw)); | ||
| 229 | ExitOnFailure(hr, "Failed to write if IIs controls user password for Web"); | ||
| 230 | } | ||
| 231 | |||
| 232 | if (MSI_NULL_INTEGER != pswp->fLogVisits) | ||
| 233 | { | ||
| 234 | // The sense of this boolean value is reversed - it is "don't log", not "log visits." | ||
| 235 | dw = (pswp->fLogVisits) ? FALSE : TRUE; | ||
| 236 | hr = ScaWriteMetabaseValue(piMetabase, wzRootOfWeb, NULL, MD_DONT_LOG, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, (LPVOID)((DWORD_PTR)dw)); | ||
| 237 | ExitOnFailure(hr, "Failed to write authorization for Web"); | ||
| 238 | } | ||
| 239 | |||
| 240 | if (MSI_NULL_INTEGER != pswp->fIndex) | ||
| 241 | { | ||
| 242 | dw = (pswp->fIndex) ? TRUE : FALSE; | ||
| 243 | hr = ScaWriteMetabaseValue(piMetabase, wzRootOfWeb, NULL, MD_IS_CONTENT_INDEXED, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, (LPVOID)((DWORD_PTR)dw)); | ||
| 244 | ExitOnFailure(hr, "Failed to write authorization for Web"); | ||
| 245 | } | ||
| 246 | |||
| 247 | if (pswp->fHasDefaultDoc) | ||
| 248 | { | ||
| 249 | hr = ScaWriteMetabaseValue(piMetabase, wzRootOfWeb, NULL, MD_DEFAULT_LOAD_FILE, METADATA_INHERIT, IIS_MD_UT_FILE, STRING_METADATA, (LPVOID)pswp->wzDefaultDoc); | ||
| 250 | ExitOnFailure(hr, "Failed to write default documents for Web"); | ||
| 251 | } | ||
| 252 | |||
| 253 | if (MSI_NULL_INTEGER != pswp->fAspDetailedError) | ||
| 254 | { | ||
| 255 | dw = (pswp->fAspDetailedError) ? TRUE : FALSE; | ||
| 256 | hr = ScaWriteMetabaseValue(piMetabase, wzRootOfWeb, NULL, MD_ASP_SCRIPTERRORSSENTTOBROWSER, METADATA_INHERIT, ASP_MD_UT_APP, DWORD_METADATA, (LPVOID)((DWORD_PTR)dw)); | ||
| 257 | ExitOnFailure(hr, "Failed to write ASP script error for Web"); | ||
| 258 | } | ||
| 259 | |||
| 260 | if (pswp->fHasHttpExp) | ||
| 261 | { | ||
| 262 | hr = ScaWriteMetabaseValue(piMetabase, wzRootOfWeb, NULL, MD_HTTP_EXPIRES, METADATA_INHERIT, IIS_MD_UT_FILE, STRING_METADATA, (LPVOID)pswp->wzHttpExp); | ||
| 263 | ExitOnFailure(hr, "Failed to write HTTP Expiration for Web"); | ||
| 264 | } | ||
| 265 | |||
| 266 | if (MSI_NULL_INTEGER != pswp->iCacheControlMaxAge) | ||
| 267 | { | ||
| 268 | hr = ScaWriteMetabaseValue(piMetabase, wzRootOfWeb, NULL, MD_CC_MAX_AGE, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, (LPVOID)((DWORD_PTR)pswp->iCacheControlMaxAge)); | ||
| 269 | ExitOnFailure(hr, "Failed to write Cache Control Max Age for Web"); | ||
| 270 | } | ||
| 271 | |||
| 272 | if (pswp->fHasCacheControlCustom) | ||
| 273 | { | ||
| 274 | hr = ScaWriteMetabaseValue(piMetabase, wzRootOfWeb, NULL, MD_CC_OTHER, METADATA_INHERIT, IIS_MD_UT_FILE, STRING_METADATA, (LPVOID)pswp->wzCacheControlCustom); | ||
| 275 | ExitOnFailure(hr, "Failed to write Cache Control Custom for Web"); | ||
| 276 | } | ||
| 277 | |||
| 278 | if (pswp->fNoCustomError) | ||
| 279 | { | ||
| 280 | memset(wz, 0, sizeof(wz)); | ||
| 281 | hr = ScaWriteMetabaseValue(piMetabase, wzRootOfWeb, NULL, MD_CUSTOM_ERROR, METADATA_INHERIT, IIS_MD_UT_FILE, MULTISZ_METADATA, wz); | ||
| 282 | ExitOnFailure(hr, "Failed to write Custom Error for Web"); | ||
| 283 | } | ||
| 284 | |||
| 285 | if (MSI_NULL_INTEGER != pswp->iAccessSSLFlags) | ||
| 286 | { | ||
| 287 | hr = ScaWriteMetabaseValue(piMetabase, wzRootOfWeb, NULL, MD_SSL_ACCESS_PERM, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, (LPVOID)((DWORD_PTR)pswp->iAccessSSLFlags)); | ||
| 288 | ExitOnFailure(hr, "Failed to write AccessSSLFlags for Web"); | ||
| 289 | } | ||
| 290 | |||
| 291 | if (*pswp->wzAuthenticationProviders) | ||
| 292 | { | ||
| 293 | hr = ::StringCchCopyW(wz, countof(wz), pswp->wzAuthenticationProviders); | ||
| 294 | ExitOnFailure(hr, "Failed to copy authentication providers string"); | ||
| 295 | hr = ScaWriteMetabaseValue(piMetabase, wzRootOfWeb, NULL, MD_NTAUTHENTICATION_PROVIDERS, METADATA_INHERIT, IIS_MD_UT_FILE, STRING_METADATA, (LPVOID)wz); | ||
| 296 | ExitOnFailure(hr, "Failed to write AuthenticationProviders for Web"); | ||
| 297 | } | ||
| 298 | |||
| 299 | LExit: | ||
| 300 | return hr; | ||
| 301 | } | ||
diff --git a/src/ca/scawebprop.h b/src/ca/scawebprop.h new file mode 100644 index 00000000..7a3ae5c9 --- /dev/null +++ b/src/ca/scawebprop.h | |||
| @@ -0,0 +1,60 @@ | |||
| 1 | #pragma once | ||
| 2 | // 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. | ||
| 3 | |||
| 4 | |||
| 5 | #include "scauser.h" | ||
| 6 | |||
| 7 | // global sql queries provided for optimization | ||
| 8 | extern LPCWSTR vcsWebDirPropertiesQuery; | ||
| 9 | |||
| 10 | |||
| 11 | // structs | ||
| 12 | struct SCA_WEB_PROPERTIES | ||
| 13 | { | ||
| 14 | WCHAR wzKey[MAX_DARWIN_KEY + 1]; | ||
| 15 | |||
| 16 | int iAccess; | ||
| 17 | |||
| 18 | int iAuthorization; | ||
| 19 | BOOL fHasUser; | ||
| 20 | SCA_USER scau; | ||
| 21 | BOOL fIIsControlledPassword; | ||
| 22 | |||
| 23 | BOOL fLogVisits; | ||
| 24 | BOOL fIndex; | ||
| 25 | |||
| 26 | BOOL fHasDefaultDoc; | ||
| 27 | WCHAR wzDefaultDoc[MAX_DARWIN_COLUMN + 1]; | ||
| 28 | |||
| 29 | BOOL fHasHttpExp; | ||
| 30 | WCHAR wzHttpExp[MAX_DARWIN_COLUMN + 1]; | ||
| 31 | |||
| 32 | BOOL fAspDetailedError; | ||
| 33 | |||
| 34 | int iCacheControlMaxAge; | ||
| 35 | |||
| 36 | BOOL fHasCacheControlCustom; | ||
| 37 | WCHAR wzCacheControlCustom[MAX_DARWIN_COLUMN + 1]; | ||
| 38 | |||
| 39 | BOOL fNoCustomError; | ||
| 40 | |||
| 41 | int iAccessSSLFlags; | ||
| 42 | |||
| 43 | WCHAR wzAuthenticationProviders[MAX_DARWIN_COLUMN + 1]; | ||
| 44 | }; | ||
| 45 | |||
| 46 | |||
| 47 | // prototypes | ||
| 48 | HRESULT ScaGetWebDirProperties( | ||
| 49 | __in LPCWSTR pwzProperties, | ||
| 50 | __in WCA_WRAPQUERY_HANDLE hUserQuery, | ||
| 51 | __in WCA_WRAPQUERY_HANDLE hWebDirPropQuery, | ||
| 52 | __inout SCA_WEB_PROPERTIES* pswp | ||
| 53 | ); | ||
| 54 | |||
| 55 | HRESULT ScaWriteWebDirProperties( | ||
| 56 | __in IMSAdminBase* piMetabase, | ||
| 57 | __in LPCWSTR wzRootOfWeb, | ||
| 58 | __inout SCA_WEB_PROPERTIES* pswp | ||
| 59 | ); | ||
| 60 | |||
diff --git a/src/ca/scawebprop7.cpp b/src/ca/scawebprop7.cpp new file mode 100644 index 00000000..b8d99b0a --- /dev/null +++ b/src/ca/scawebprop7.cpp | |||
| @@ -0,0 +1,155 @@ | |||
| 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 | #include "precomp.h" | ||
| 4 | |||
| 5 | HRESULT ScaWriteWebDirProperties7( | ||
| 6 | __in_z LPCWSTR wzWebName, | ||
| 7 | __in_z LPCWSTR wzRootOfWeb, | ||
| 8 | __in const SCA_WEB_PROPERTIES* pswp | ||
| 9 | ) | ||
| 10 | { | ||
| 11 | HRESULT hr = S_OK; | ||
| 12 | WCHAR wz[METADATA_MAX_NAME_LEN + 1]; | ||
| 13 | |||
| 14 | //all go to same web/root location tag | ||
| 15 | hr = ScaWriteConfigID(IIS_DIRPROP_BEGIN); | ||
| 16 | ExitOnFailure(hr, "Failed to write DirProp begin id"); | ||
| 17 | hr = ScaWriteConfigString(wzWebName); //site name key | ||
| 18 | ExitOnFailure(hr, "Failed to write DirProp web key"); | ||
| 19 | hr = ScaWriteConfigString(wzRootOfWeb); //app path key | ||
| 20 | ExitOnFailure(hr, "Failed to write DirProp app key"); | ||
| 21 | |||
| 22 | // write the access permissions to the metabase | ||
| 23 | if (MSI_NULL_INTEGER != pswp->iAccess) | ||
| 24 | { | ||
| 25 | hr = ScaWriteConfigID(IIS_DIRPROP_ACCESS); | ||
| 26 | ExitOnFailure(hr, "Failed to write DirProp access id"); | ||
| 27 | hr = ScaWriteConfigInteger(pswp->iAccess); | ||
| 28 | ExitOnFailure(hr, "Failed to write access permissions for Web"); | ||
| 29 | } | ||
| 30 | |||
| 31 | if (MSI_NULL_INTEGER != pswp->iAuthorization) | ||
| 32 | { | ||
| 33 | hr = ScaWriteConfigID(IIS_DIRPROP_AUTH); | ||
| 34 | ExitOnFailure(hr, "Failed to write DirProp auth id"); | ||
| 35 | hr = ScaWriteConfigInteger(pswp->iAuthorization); | ||
| 36 | ExitOnFailure(hr, "Failed to write authorization for Web"); | ||
| 37 | } | ||
| 38 | |||
| 39 | if (pswp->fHasUser) | ||
| 40 | { | ||
| 41 | Assert(pswp->scau.wzName); | ||
| 42 | // write the user name | ||
| 43 | if (*pswp->scau.wzDomain) | ||
| 44 | { | ||
| 45 | hr = ::StringCchPrintfW(wz, countof(wz), L"%s\\%s", pswp->scau.wzDomain, pswp->scau.wzName); | ||
| 46 | ExitOnFailure(hr, "Failed to format domain\\username string"); | ||
| 47 | } | ||
| 48 | else | ||
| 49 | { | ||
| 50 | #pragma prefast(suppress:26037, "Source string is null terminated - it is populated as target of ::StringCchCopyW") | ||
| 51 | hr = ::StringCchCopyW(wz, countof(wz), pswp->scau.wzName); | ||
| 52 | ExitOnFailure(hr, "Failed to copy user name"); | ||
| 53 | } | ||
| 54 | hr = ScaWriteConfigID(IIS_DIRPROP_USER); | ||
| 55 | ExitOnFailure(hr, "Failed to write DirProp user id"); | ||
| 56 | hr = ScaWriteConfigString(wz); | ||
| 57 | ExitOnFailure(hr, "Failed to write anonymous user name for Web"); | ||
| 58 | |||
| 59 | // write the password | ||
| 60 | hr = ScaWriteConfigID(IIS_DIRPROP_PWD); | ||
| 61 | ExitOnFailure(hr, "Failed to write DirProp pwd id"); | ||
| 62 | hr = ScaWriteConfigString(pswp->scau.wzPassword); | ||
| 63 | ExitOnFailure(hr, "Failed to write anonymous user password for Web"); | ||
| 64 | |||
| 65 | if (pswp->fIIsControlledPassword) | ||
| 66 | { | ||
| 67 | //Not Supported by IIS7 : pswp->fIIsControlledPassword | ||
| 68 | WcaLog(LOGMSG_VERBOSE, "Not supported by IIS7: WebDirProperties.IIsControlledPassword, ignoring"); | ||
| 69 | } | ||
| 70 | } | ||
| 71 | |||
| 72 | if (MSI_NULL_INTEGER != pswp->fLogVisits) | ||
| 73 | { | ||
| 74 | hr = ScaWriteConfigID(IIS_DIRPROP_LOGVISITS); | ||
| 75 | ExitOnFailure(hr, "Failed to write DirProp logVisits id"); | ||
| 76 | hr = ScaWriteConfigInteger(pswp->fLogVisits ? FALSE : TRUE); // we capture "should log" but IIS7 wants "should not log" | ||
| 77 | ExitOnFailure(hr, "Failed to write DirProp logVisits"); | ||
| 78 | } | ||
| 79 | |||
| 80 | if (MSI_NULL_INTEGER != pswp->fIndex) | ||
| 81 | { | ||
| 82 | //Not Supported by IIS7 : pswp->fIndex | ||
| 83 | WcaLog(LOGMSG_VERBOSE, "Not supported by IIS7: WebDirProperties.Index, ignoring"); | ||
| 84 | } | ||
| 85 | |||
| 86 | if (pswp->fHasDefaultDoc) | ||
| 87 | { | ||
| 88 | hr = ScaWriteConfigID(IIS_DIRPROP_DEFDOCS); | ||
| 89 | ExitOnFailure(hr, "Failed to write DirProp defdocs id"); | ||
| 90 | hr = ScaWriteConfigString(pswp->wzDefaultDoc); | ||
| 91 | ExitOnFailure(hr, "Failed to write default documents for Web"); | ||
| 92 | } | ||
| 93 | |||
| 94 | if (MSI_NULL_INTEGER != pswp->fAspDetailedError) | ||
| 95 | { | ||
| 96 | hr = ScaWriteConfigID(IIS_DIRPROP_ASPERROR); | ||
| 97 | ExitOnFailure(hr, "Failed to write ASP script error id"); | ||
| 98 | hr = ScaWriteConfigInteger(pswp->fAspDetailedError); | ||
| 99 | ExitOnFailure(hr, "Failed to write ASP script error for Web"); | ||
| 100 | } | ||
| 101 | |||
| 102 | if (pswp->fHasHttpExp) | ||
| 103 | { | ||
| 104 | hr = ScaWriteConfigID(IIS_DIRPROP_HTTPEXPIRES); | ||
| 105 | ExitOnFailure(hr, "Failed to write DirProp HttpExpires id"); | ||
| 106 | hr = ScaWriteConfigString(pswp->wzHttpExp); | ||
| 107 | ExitOnFailure(hr, "Failed to write DirProp HttpExpires value"); | ||
| 108 | } | ||
| 109 | |||
| 110 | if (MSI_NULL_INTEGER != pswp->iCacheControlMaxAge) | ||
| 111 | { | ||
| 112 | hr = ScaWriteConfigID(IIS_DIRPROP_MAXAGE); | ||
| 113 | ExitOnFailure(hr, "Failed to write DirProp MaxAge id"); | ||
| 114 | hr = ScaWriteConfigInteger(pswp->iCacheControlMaxAge); | ||
| 115 | ExitOnFailure(hr, "Failed to write DirProp MaxAge value"); | ||
| 116 | } | ||
| 117 | |||
| 118 | if (pswp->fHasCacheControlCustom) | ||
| 119 | { | ||
| 120 | hr = ScaWriteConfigID(IIS_DIRPROP_CACHECUST); | ||
| 121 | ExitOnFailure(hr, "Failed to write DirProp Cache Control Custom id"); | ||
| 122 | hr = ScaWriteConfigString(pswp->wzCacheControlCustom); | ||
| 123 | ExitOnFailure(hr, "Failed to write Cache Control Custom for Web"); | ||
| 124 | } | ||
| 125 | |||
| 126 | if (pswp->fNoCustomError) | ||
| 127 | { | ||
| 128 | hr = ScaWriteConfigID(IIS_DIRPROP_NOCUSTERROR); | ||
| 129 | ExitOnFailure(hr, "Failed to write DirProp clear Cust Errors id"); | ||
| 130 | } | ||
| 131 | |||
| 132 | if (MSI_NULL_INTEGER != pswp->iAccessSSLFlags) | ||
| 133 | { | ||
| 134 | hr = ScaWriteConfigID(IIS_DIRPROP_SSLFLAGS); | ||
| 135 | ExitOnFailure(hr, "Failed to write DirProp sslFlags id"); | ||
| 136 | hr = ScaWriteConfigInteger(pswp->iAccessSSLFlags); | ||
| 137 | ExitOnFailure(hr, "Failed to write AccessSSLFlags for Web"); | ||
| 138 | } | ||
| 139 | |||
| 140 | if (*pswp->wzAuthenticationProviders) | ||
| 141 | { | ||
| 142 | hr = ::StringCchCopyW(wz, countof(wz), pswp->wzAuthenticationProviders); | ||
| 143 | ExitOnFailure(hr, "Failed to copy authentication providers string"); | ||
| 144 | hr = ScaWriteConfigID(IIS_DIRPROP_AUTHPROVID); | ||
| 145 | ExitOnFailure(hr, "Failed to write DirProp AuthProvid id"); | ||
| 146 | hr = ScaWriteConfigString(wz); | ||
| 147 | ExitOnFailure(hr, "Failed to write AuthenticationProviders for Web"); | ||
| 148 | } | ||
| 149 | //End of Dir Properties | ||
| 150 | hr = ScaWriteConfigID(IIS_DIRPROP_END); | ||
| 151 | ExitOnFailure(hr, "Failed to write DirProp end id"); | ||
| 152 | |||
| 153 | LExit: | ||
| 154 | return hr; | ||
| 155 | } | ||
diff --git a/src/ca/scawebprop7.h b/src/ca/scawebprop7.h new file mode 100644 index 00000000..a97e8679 --- /dev/null +++ b/src/ca/scawebprop7.h | |||
| @@ -0,0 +1,12 @@ | |||
| 1 | #pragma once | ||
| 2 | // 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. | ||
| 3 | |||
| 4 | |||
| 5 | #include "scauser.h" | ||
| 6 | |||
| 7 | HRESULT ScaWriteWebDirProperties7( | ||
| 8 | __in_z LPCWSTR wzwWebName, | ||
| 9 | __in_z LPCWSTR wzRootOfWeb, | ||
| 10 | const SCA_WEB_PROPERTIES* pswp | ||
| 11 | ); | ||
| 12 | |||
diff --git a/src/ca/scawebsvcext.cpp b/src/ca/scawebsvcext.cpp new file mode 100644 index 00000000..369e951b --- /dev/null +++ b/src/ca/scawebsvcext.cpp | |||
| @@ -0,0 +1,343 @@ | |||
| 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 | #include "precomp.h" | ||
| 4 | |||
| 5 | // sql queries | ||
| 6 | enum eWebSvcExtQuery { ldqComponent=1 , ldqFile, ldqDescription, ldqGroup, ldqAttributes, ldqInstalled, ldqAction }; | ||
| 7 | |||
| 8 | |||
| 9 | LPCWSTR vcsWebSvcExtRoot = L"/LM/W3SVC"; | ||
| 10 | |||
| 11 | // prototypes for private helper functions | ||
| 12 | static HRESULT AddWebSvcExtToList( | ||
| 13 | __in SCA_WEBSVCEXT** ppsWseList | ||
| 14 | ); | ||
| 15 | |||
| 16 | //static HRESULT ScaCheckWebSvcExtValue( | ||
| 17 | // __in IMSAdminBase* piMetabase, | ||
| 18 | // __in DWORD dwMDIdentifier | ||
| 19 | // ); | ||
| 20 | |||
| 21 | static HRESULT ScaWebSvcExtInstall( | ||
| 22 | __in LPWSTR *pwzWebSvcExtList, | ||
| 23 | __in DWORD_PTR *pcchWebSvcExtList, | ||
| 24 | __in SCA_WEBSVCEXT* psWseList | ||
| 25 | ); | ||
| 26 | |||
| 27 | static HRESULT ScaWebSvcExtUninstall( | ||
| 28 | __in LPWSTR *pwzWebSvcExtList, | ||
| 29 | __in const DWORD *pcchWebSvcExtList, | ||
| 30 | __in SCA_WEBSVCEXT* psWseList | ||
| 31 | ); | ||
| 32 | |||
| 33 | // functions | ||
| 34 | |||
| 35 | HRESULT __stdcall ScaWebSvcExtRead( | ||
| 36 | __in SCA_WEBSVCEXT** ppsWseList, | ||
| 37 | __inout LPWSTR *ppwzCustomActionData | ||
| 38 | ) | ||
| 39 | { | ||
| 40 | Assert(ppsWseList); | ||
| 41 | |||
| 42 | HRESULT hr = S_OK; | ||
| 43 | MSIHANDLE hRec; | ||
| 44 | LPWSTR pwzData = NULL; | ||
| 45 | INSTALLSTATE isInstalled = INSTALLSTATE_UNKNOWN; | ||
| 46 | INSTALLSTATE isAction = INSTALLSTATE_UNKNOWN; | ||
| 47 | SCA_WEBSVCEXT* psWebSvcExt = NULL; | ||
| 48 | WCA_WRAPQUERY_HANDLE hWrapQuery = NULL; | ||
| 49 | |||
| 50 | hr = WcaBeginUnwrapQuery(&hWrapQuery, ppwzCustomActionData); | ||
| 51 | ExitOnFailure(hr, "Failed to unwrap query for ScaWebSvcExtRead"); | ||
| 52 | |||
| 53 | if (0 == WcaGetQueryRecords(hWrapQuery)) | ||
| 54 | { | ||
| 55 | WcaLog(LOGMSG_VERBOSE, "Skipping ScaWebSvcExtRead() because IIsWebServiceExtension data not present"); | ||
| 56 | ExitFunction1(hr = S_FALSE); | ||
| 57 | } | ||
| 58 | |||
| 59 | // loop through all the web service extensions | ||
| 60 | while (S_OK == (hr = WcaFetchWrappedRecord(hWrapQuery, &hRec))) | ||
| 61 | { | ||
| 62 | // Get the Component first. If the Component is not being modified during | ||
| 63 | // this transaction, skip processing this whole record. | ||
| 64 | hr = WcaGetRecordString(hRec, ldqComponent, &pwzData); | ||
| 65 | ExitOnFailure(hr, "Failed to get Component for WebSvcExt"); | ||
| 66 | |||
| 67 | hr = WcaGetRecordInteger(hRec, ldqInstalled, (int *)&isInstalled); | ||
| 68 | ExitOnFailure(hr, "Failed to get Component installed state for WebSvcExt"); | ||
| 69 | |||
| 70 | hr = WcaGetRecordInteger(hRec, ldqAction, (int *)&isAction); | ||
| 71 | ExitOnFailure(hr, "Failed to get Component action state for WebSvcExt"); | ||
| 72 | |||
| 73 | if (!WcaIsInstalling(isInstalled, isAction) && | ||
| 74 | !WcaIsReInstalling(isInstalled, isAction) && | ||
| 75 | !WcaIsUninstalling(isInstalled, isAction)) | ||
| 76 | { | ||
| 77 | continue; // skip this record. | ||
| 78 | } | ||
| 79 | |||
| 80 | hr = AddWebSvcExtToList(ppsWseList); | ||
| 81 | ExitOnFailure(hr, "failed to add element to web svc ext list"); | ||
| 82 | |||
| 83 | psWebSvcExt = *ppsWseList; | ||
| 84 | Assert(psWebSvcExt); | ||
| 85 | |||
| 86 | psWebSvcExt->isInstalled = isInstalled; | ||
| 87 | psWebSvcExt->isAction = isAction; | ||
| 88 | |||
| 89 | hr = WcaGetRecordString(hRec, ldqFile, &pwzData); | ||
| 90 | ExitOnFailure(hr, "Failed to get File for WebSvcExt"); | ||
| 91 | hr = ::StringCchCopyW(psWebSvcExt->wzFile, countof(psWebSvcExt->wzFile), pwzData); | ||
| 92 | ExitOnFailure(hr, "Failed to copy File for WebSvcExt"); | ||
| 93 | |||
| 94 | hr = WcaGetRecordString(hRec, ldqDescription, &pwzData); | ||
| 95 | ExitOnFailure(hr, "Failed to get Description for WebSvcExt"); | ||
| 96 | hr = ::StringCchCopyW(psWebSvcExt->wzDescription, countof(psWebSvcExt->wzDescription), pwzData); | ||
| 97 | ExitOnFailure(hr, "Failed to copy Description for WebSvcExt"); | ||
| 98 | |||
| 99 | hr = WcaGetRecordString(hRec, ldqGroup, &pwzData); | ||
| 100 | ExitOnFailure(hr, "Failed to get Group for WebSvcExt"); | ||
| 101 | hr = ::StringCchCopyW(psWebSvcExt->wzGroup, countof(psWebSvcExt->wzGroup), pwzData); | ||
| 102 | ExitOnFailure(hr, "Failed to copy Group for WebSvcExt"); | ||
| 103 | |||
| 104 | hr = WcaGetRecordInteger(hRec, ldqAttributes, &psWebSvcExt->iAttributes); | ||
| 105 | ExitOnFailure(hr, "Failed to get Attributes for WebSvcExt"); | ||
| 106 | } | ||
| 107 | |||
| 108 | if (E_NOMOREITEMS == hr) | ||
| 109 | hr = S_OK; | ||
| 110 | ExitOnFailure(hr, "Failure while processing WebSvcExt"); | ||
| 111 | |||
| 112 | LExit: | ||
| 113 | WcaFinishUnwrapQuery(hWrapQuery); | ||
| 114 | |||
| 115 | ReleaseStr(pwzData); | ||
| 116 | |||
| 117 | return hr; | ||
| 118 | } | ||
| 119 | |||
| 120 | |||
| 121 | // Commit does both install and uninstall | ||
| 122 | HRESULT __stdcall ScaWebSvcExtCommit( | ||
| 123 | __in IMSAdminBase* piMetabase, | ||
| 124 | __in SCA_WEBSVCEXT* psWseList | ||
| 125 | ) | ||
| 126 | { | ||
| 127 | Assert(piMetabase); | ||
| 128 | |||
| 129 | HRESULT hr = S_OK; | ||
| 130 | METADATA_RECORD mr; | ||
| 131 | |||
| 132 | LPWSTR wzWebSvcExtList = NULL; | ||
| 133 | DWORD cbWebSvcExtList = 0; | ||
| 134 | DWORD_PTR cchWebSvcExtList = 0; | ||
| 135 | |||
| 136 | if (!psWseList) | ||
| 137 | { | ||
| 138 | WcaLog(LOGMSG_VERBOSE, "Skipping ScaWebSvcExtCommit() because there are no web service extensions in the list"); | ||
| 139 | ExitFunction(); | ||
| 140 | } | ||
| 141 | |||
| 142 | // Get current set of web service extensions. | ||
| 143 | ::ZeroMemory(&mr, sizeof(mr)); | ||
| 144 | mr.dwMDIdentifier = MD_WEB_SVC_EXT_RESTRICTION_LIST; | ||
| 145 | mr.dwMDAttributes = 0; | ||
| 146 | mr.dwMDUserType = IIS_MD_UT_SERVER; | ||
| 147 | mr.dwMDDataType = ALL_METADATA; | ||
| 148 | mr.pbMDData = NULL; | ||
| 149 | mr.dwMDDataLen = 0; | ||
| 150 | |||
| 151 | hr = piMetabase->GetData(METADATA_MASTER_ROOT_HANDLE, vcsWebSvcExtRoot, &mr, &cbWebSvcExtList); | ||
| 152 | if (MD_ERROR_DATA_NOT_FOUND == hr) | ||
| 153 | { | ||
| 154 | WcaLog(LOGMSG_VERBOSE, "Skipping ScaWebSvcExtCommit() because WebSvcExtRestrictionList value is not present"); | ||
| 155 | ExitFunction1(hr = S_FALSE); | ||
| 156 | } | ||
| 157 | else if (HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER) == hr) | ||
| 158 | { | ||
| 159 | // cchWebSvcExtList is returned in bytes. Convert to WCHAR size to call StrAlloc | ||
| 160 | cchWebSvcExtList = cbWebSvcExtList / sizeof(WCHAR); | ||
| 161 | hr = StrAlloc(&wzWebSvcExtList, cchWebSvcExtList); | ||
| 162 | ExitOnFailure(hr, "Failed allocating space for web service extensions"); | ||
| 163 | } | ||
| 164 | else | ||
| 165 | { | ||
| 166 | ExitOnFailure(hr, "Failed retrieving web service extensions"); | ||
| 167 | } | ||
| 168 | |||
| 169 | mr.pbMDData = (unsigned char*)wzWebSvcExtList; | ||
| 170 | mr.dwMDDataLen = cbWebSvcExtList; | ||
| 171 | |||
| 172 | hr = piMetabase->GetData(METADATA_MASTER_ROOT_HANDLE, vcsWebSvcExtRoot, &mr, &cbWebSvcExtList); | ||
| 173 | ExitOnFailure(hr, "Failed retrieving web service extensions"); | ||
| 174 | |||
| 175 | // Make changes to local copy of metabase | ||
| 176 | while (psWseList) | ||
| 177 | { | ||
| 178 | if (WcaIsInstalling(psWseList->isInstalled, psWseList->isAction)) | ||
| 179 | { | ||
| 180 | hr = ScaWebSvcExtInstall(&wzWebSvcExtList, &cchWebSvcExtList, psWseList); | ||
| 181 | ExitOnFailure(hr, "Failed to install Web Service extension"); | ||
| 182 | } | ||
| 183 | else if (WcaIsUninstalling(psWseList->isInstalled, psWseList->isAction)) | ||
| 184 | { | ||
| 185 | hr = ScaWebSvcExtUninstall(&wzWebSvcExtList, (DWORD *)&cchWebSvcExtList, psWseList); | ||
| 186 | ExitOnFailure(hr, "Failed to uninstall Web Service extension"); | ||
| 187 | } | ||
| 188 | |||
| 189 | psWseList = psWseList->psWseNext; | ||
| 190 | } | ||
| 191 | |||
| 192 | // Write Metabase | ||
| 193 | hr = ScaWriteMetabaseValue(piMetabase, vcsWebSvcExtRoot, NULL, MD_WEB_SVC_EXT_RESTRICTION_LIST, METADATA_INHERIT, IIS_MD_UT_FILE, MULTISZ_METADATA, wzWebSvcExtList); | ||
| 194 | ExitOnFailure(hr, "Failed to write WebServiceExtensions: '%ls'", wzWebSvcExtList); | ||
| 195 | |||
| 196 | LExit: | ||
| 197 | ReleaseStr(wzWebSvcExtList); | ||
| 198 | |||
| 199 | return hr; | ||
| 200 | } | ||
| 201 | |||
| 202 | |||
| 203 | static HRESULT ScaWebSvcExtInstall( | ||
| 204 | __in LPWSTR *ppwzWebSvcExtList, | ||
| 205 | __in DWORD_PTR *pcchWebSvcExtList, | ||
| 206 | __in SCA_WEBSVCEXT* psWseList | ||
| 207 | ) | ||
| 208 | { | ||
| 209 | Assert( ppwzWebSvcExtList && pcchWebSvcExtList && psWseList); | ||
| 210 | Assert(*ppwzWebSvcExtList); | ||
| 211 | |||
| 212 | HRESULT hr = S_OK; | ||
| 213 | |||
| 214 | LPWSTR pwzWebSvcExt = NULL; | ||
| 215 | int iAllow; | ||
| 216 | int iUiDeletable; | ||
| 217 | |||
| 218 | BOOL fAlreadyExists = FALSE; | ||
| 219 | DWORD_PTR dwIndex = 0xFFFFFFFF; | ||
| 220 | LPCWSTR wzFoundString = NULL; | ||
| 221 | |||
| 222 | // Check if it's already in there | ||
| 223 | hr = MultiSzFindSubstring(*ppwzWebSvcExtList, psWseList->wzFile, &dwIndex, &wzFoundString); | ||
| 224 | ExitOnFailure(hr, "failed to search for string:%ls in web service extension MULTISZ", psWseList->wzFile); | ||
| 225 | |||
| 226 | if (S_FALSE != hr && NULL != wcsstr(wzFoundString, psWseList->wzGroup) && NULL != wcsstr(wzFoundString, psWseList->wzDescription)) | ||
| 227 | { | ||
| 228 | fAlreadyExists = TRUE; | ||
| 229 | } | ||
| 230 | |||
| 231 | // Construct the single string in the format required for the WebSvc Ext list in metabase | ||
| 232 | iAllow = (psWseList->iAttributes & 1); | ||
| 233 | iUiDeletable = ((psWseList->iAttributes >> 1) & 1); | ||
| 234 | hr = StrAllocFormatted(&pwzWebSvcExt, L"%d,%s,%d,%s,%s", iAllow, psWseList->wzFile, iUiDeletable, psWseList->wzGroup, psWseList->wzDescription); | ||
| 235 | ExitOnFailure(hr, "Failure allocating space for web service extensions"); | ||
| 236 | |||
| 237 | if (fAlreadyExists) | ||
| 238 | { | ||
| 239 | hr = MultiSzReplaceString(ppwzWebSvcExtList, dwIndex, pwzWebSvcExt); | ||
| 240 | ExitOnFailure(hr, "failed to update web service extension string: %ls", pwzWebSvcExt); | ||
| 241 | } | ||
| 242 | else | ||
| 243 | { | ||
| 244 | hr = MultiSzPrepend(ppwzWebSvcExtList, pcchWebSvcExtList, pwzWebSvcExt); | ||
| 245 | ExitOnFailure(hr, "failed to prepend web service extension string: %ls", pwzWebSvcExt); | ||
| 246 | } | ||
| 247 | |||
| 248 | LExit: | ||
| 249 | ReleaseStr(pwzWebSvcExt); | ||
| 250 | |||
| 251 | return hr; | ||
| 252 | } | ||
| 253 | |||
| 254 | |||
| 255 | static HRESULT ScaWebSvcExtUninstall( | ||
| 256 | __in LPWSTR *ppwzWebSvcExtList, | ||
| 257 | __in const DWORD* /*pcchWebSvcExtList*/, | ||
| 258 | __in SCA_WEBSVCEXT* psWseList | ||
| 259 | ) | ||
| 260 | { | ||
| 261 | Assert(ppwzWebSvcExtList && *ppwzWebSvcExtList && psWseList); | ||
| 262 | Assert(*ppwzWebSvcExtList); | ||
| 263 | |||
| 264 | HRESULT hr = S_OK; | ||
| 265 | DWORD_PTR dwIndex = 0xFFFFFFFF; | ||
| 266 | LPCWSTR wzFoundString = NULL; | ||
| 267 | |||
| 268 | // Find the string to remove | ||
| 269 | hr = MultiSzFindSubstring(*ppwzWebSvcExtList, psWseList->wzFile, &dwIndex, &wzFoundString); | ||
| 270 | ExitOnFailure(hr, "failed to search for string:%ls in web service extension MULTISZ", psWseList->wzFile); | ||
| 271 | |||
| 272 | // If we found a match (ignoring the Allow and Deletable flags) | ||
| 273 | if (S_FALSE != hr && NULL != wcsstr(wzFoundString, psWseList->wzGroup) && NULL != wcsstr(wzFoundString, psWseList->wzDescription)) | ||
| 274 | { | ||
| 275 | hr = MultiSzRemoveString(ppwzWebSvcExtList, dwIndex); | ||
| 276 | ExitOnFailure(hr, "failed to remove string: %d from web service extension MULTISZ", dwIndex); | ||
| 277 | } | ||
| 278 | |||
| 279 | LExit: | ||
| 280 | return hr; | ||
| 281 | } | ||
| 282 | |||
| 283 | |||
| 284 | //static HRESULT ScaCheckWebSvcExtValue( | ||
| 285 | // __in IMSAdminBase* piMetabase, | ||
| 286 | // __in DWORD dwMDIdentifier | ||
| 287 | // ) | ||
| 288 | //{ | ||
| 289 | // if (!piMetabase) | ||
| 290 | // { | ||
| 291 | // return E_INVALIDARG; | ||
| 292 | // } | ||
| 293 | // | ||
| 294 | // HRESULT hr = S_OK; | ||
| 295 | // METADATA_RECORD mr = { 0 }; | ||
| 296 | // DWORD cch = 0; | ||
| 297 | // | ||
| 298 | // mr.dwMDIdentifier = dwMDIdentifier; | ||
| 299 | // mr.dwMDUserType = IIS_MD_UT_SERVER; | ||
| 300 | // | ||
| 301 | // hr = piMetabase->GetData(METADATA_MASTER_ROOT_HANDLE, vcsWebSvcExtRoot, &mr, &cch); | ||
| 302 | // if (HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER) == hr) | ||
| 303 | // { | ||
| 304 | // hr = S_OK; | ||
| 305 | // } | ||
| 306 | // else if (MD_ERROR_DATA_NOT_FOUND == hr) | ||
| 307 | // { | ||
| 308 | // hr = S_FALSE; | ||
| 309 | // } | ||
| 310 | // | ||
| 311 | // return hr; | ||
| 312 | //} | ||
| 313 | |||
| 314 | |||
| 315 | void ScaWebSvcExtFreeList( | ||
| 316 | __in SCA_WEBSVCEXT* psWseList | ||
| 317 | ) | ||
| 318 | { | ||
| 319 | SCA_WEBSVCEXT* psWseDelete = psWseList; | ||
| 320 | while (psWseList) | ||
| 321 | { | ||
| 322 | psWseDelete = psWseList; | ||
| 323 | psWseList = psWseList->psWseNext; | ||
| 324 | MemFree(psWseDelete); | ||
| 325 | } | ||
| 326 | } | ||
| 327 | |||
| 328 | |||
| 329 | static HRESULT AddWebSvcExtToList( | ||
| 330 | __in SCA_WEBSVCEXT** ppsWseList | ||
| 331 | ) | ||
| 332 | { | ||
| 333 | HRESULT hr = S_OK; | ||
| 334 | |||
| 335 | SCA_WEBSVCEXT* psWse = static_cast<SCA_WEBSVCEXT*>(MemAlloc(sizeof(SCA_WEBSVCEXT), TRUE)); | ||
| 336 | ExitOnNull(psWse, hr, E_OUTOFMEMORY, "failed to allocate element for web svc ext list"); | ||
| 337 | |||
| 338 | psWse->psWseNext = *ppsWseList; | ||
| 339 | *ppsWseList = psWse; | ||
| 340 | |||
| 341 | LExit: | ||
| 342 | return hr; | ||
| 343 | } | ||
diff --git a/src/ca/scawebsvcext.h b/src/ca/scawebsvcext.h new file mode 100644 index 00000000..4d225b09 --- /dev/null +++ b/src/ca/scawebsvcext.h | |||
| @@ -0,0 +1,35 @@ | |||
| 1 | #pragma once | ||
| 2 | // 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. | ||
| 3 | |||
| 4 | |||
| 5 | enum SCA_WEBSVCEXT_ATTRIBUTES { SWSEATTRIB_ALLOW = 1, SWSEATTRIB_UIDELETABLE = 2 }; | ||
| 6 | |||
| 7 | struct SCA_WEBSVCEXT | ||
| 8 | { | ||
| 9 | // darwin information | ||
| 10 | INSTALLSTATE isInstalled; | ||
| 11 | INSTALLSTATE isAction; | ||
| 12 | |||
| 13 | // iis configuation information | ||
| 14 | WCHAR wzFile[MAX_PATH + 1]; | ||
| 15 | WCHAR wzDescription[MAX_DARWIN_COLUMN + 1]; | ||
| 16 | WCHAR wzGroup[MAX_DARWIN_COLUMN + 1]; | ||
| 17 | |||
| 18 | int iAttributes; | ||
| 19 | |||
| 20 | SCA_WEBSVCEXT* psWseNext; | ||
| 21 | }; | ||
| 22 | |||
| 23 | HRESULT __stdcall ScaWebSvcExtRead( | ||
| 24 | __in SCA_WEBSVCEXT** ppsWseList, | ||
| 25 | __inout LPWSTR *ppwzCustomActionData | ||
| 26 | ); | ||
| 27 | |||
| 28 | HRESULT ScaWebSvcExtCommit( | ||
| 29 | __in IMSAdminBase* piMetabase, | ||
| 30 | __in SCA_WEBSVCEXT* psWseList | ||
| 31 | ); | ||
| 32 | |||
| 33 | void ScaWebSvcExtFreeList( | ||
| 34 | __in SCA_WEBSVCEXT* psWseList | ||
| 35 | ); | ||
diff --git a/src/ca/scawebsvcext7.cpp b/src/ca/scawebsvcext7.cpp new file mode 100644 index 00000000..dcf2f7f8 --- /dev/null +++ b/src/ca/scawebsvcext7.cpp | |||
| @@ -0,0 +1,106 @@ | |||
| 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 | #include "precomp.h" | ||
| 4 | |||
| 5 | static HRESULT ScaWebSvcExtInstall( | ||
| 6 | const SCA_WEBSVCEXT* psWseList | ||
| 7 | ); | ||
| 8 | |||
| 9 | static HRESULT ScaWebSvcExtUninstall( | ||
| 10 | const SCA_WEBSVCEXT* psWseList | ||
| 11 | ); | ||
| 12 | |||
| 13 | // functions | ||
| 14 | // Commit does both install and uninstall | ||
| 15 | HRESULT __stdcall ScaWebSvcExtCommit7( | ||
| 16 | __in SCA_WEBSVCEXT* psWseList | ||
| 17 | ) | ||
| 18 | { | ||
| 19 | HRESULT hr = S_OK; | ||
| 20 | |||
| 21 | if (!psWseList) | ||
| 22 | { | ||
| 23 | WcaLog(LOGMSG_VERBOSE, "Skipping ScaWebSvcExtCommit() because there are no web service extensions in the list"); | ||
| 24 | ExitFunction(); | ||
| 25 | } | ||
| 26 | |||
| 27 | // Make changes to local copy of metabase | ||
| 28 | while (psWseList) | ||
| 29 | { | ||
| 30 | if (WcaIsInstalling(psWseList->isInstalled, psWseList->isAction)) | ||
| 31 | { | ||
| 32 | hr = ScaWebSvcExtInstall(psWseList); | ||
| 33 | ExitOnFailure(hr, "Failed to install Web Service extension"); | ||
| 34 | } | ||
| 35 | else if (WcaIsUninstalling(psWseList->isInstalled, psWseList->isAction)) | ||
| 36 | { | ||
| 37 | hr = ScaWebSvcExtUninstall(psWseList); | ||
| 38 | ExitOnFailure(hr, "Failed to uninstall Web Service extension"); | ||
| 39 | } | ||
| 40 | |||
| 41 | psWseList = psWseList->psWseNext; | ||
| 42 | } | ||
| 43 | |||
| 44 | |||
| 45 | LExit: | ||
| 46 | |||
| 47 | return hr; | ||
| 48 | } | ||
| 49 | |||
| 50 | |||
| 51 | static HRESULT ScaWebSvcExtInstall( | ||
| 52 | const SCA_WEBSVCEXT* psWseList | ||
| 53 | ) | ||
| 54 | { | ||
| 55 | HRESULT hr = S_OK; | ||
| 56 | int iAllow; | ||
| 57 | |||
| 58 | //Write CAData actions | ||
| 59 | hr = ScaWriteConfigID(IIS_WEB_SVC_EXT); | ||
| 60 | ExitOnFailure(hr, "failed add web svc ext ID"); | ||
| 61 | hr = ScaWriteConfigID(IIS_CREATE); | ||
| 62 | ExitOnFailure(hr, "failed add web svc ext action"); | ||
| 63 | |||
| 64 | // write File path | ||
| 65 | hr = ScaWriteConfigString(psWseList->wzFile); | ||
| 66 | ExitOnFailure(hr, "failed add web svc ext file path"); | ||
| 67 | |||
| 68 | // write allowed | ||
| 69 | // unDeleatable n/a in IIS7 | ||
| 70 | iAllow = (psWseList->iAttributes & 1); | ||
| 71 | hr = ScaWriteConfigInteger(iAllow); | ||
| 72 | ExitOnFailure(hr, "failed add web svc ext Allowed"); | ||
| 73 | |||
| 74 | //write group | ||
| 75 | hr = ScaWriteConfigString(psWseList->wzGroup); | ||
| 76 | ExitOnFailure(hr, "failed add web svc ext group"); | ||
| 77 | |||
| 78 | //write description | ||
| 79 | hr = ScaWriteConfigString(psWseList->wzDescription); | ||
| 80 | ExitOnFailure(hr, "failed add web svc ext description"); | ||
| 81 | |||
| 82 | LExit: | ||
| 83 | |||
| 84 | return hr; | ||
| 85 | } | ||
| 86 | |||
| 87 | |||
| 88 | static HRESULT ScaWebSvcExtUninstall( | ||
| 89 | const SCA_WEBSVCEXT* psWseList | ||
| 90 | ) | ||
| 91 | { | ||
| 92 | HRESULT hr = S_OK; | ||
| 93 | |||
| 94 | //Write CAData actions | ||
| 95 | hr = ScaWriteConfigID(IIS_WEB_SVC_EXT); | ||
| 96 | ExitOnFailure(hr, "failed add web svc ext ID"); | ||
| 97 | hr = ScaWriteConfigID(IIS_DELETE); | ||
| 98 | ExitOnFailure(hr, "failed add web svc ext action"); | ||
| 99 | |||
| 100 | // write File path (Key) | ||
| 101 | hr = ScaWriteConfigString(psWseList->wzFile); | ||
| 102 | ExitOnFailure(hr, "failed add web svc ext file path"); | ||
| 103 | |||
| 104 | LExit: | ||
| 105 | return hr; | ||
| 106 | } | ||
diff --git a/src/ca/scawebsvcext7.h b/src/ca/scawebsvcext7.h new file mode 100644 index 00000000..1a686aed --- /dev/null +++ b/src/ca/scawebsvcext7.h | |||
| @@ -0,0 +1,8 @@ | |||
| 1 | #pragma once | ||
| 2 | // 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. | ||
| 3 | |||
| 4 | |||
| 5 | HRESULT ScaWebSvcExtCommit7( | ||
| 6 | __in SCA_WEBSVCEXT* psWseList | ||
| 7 | ); | ||
| 8 | |||
