@joebigelow / wix / commits / 95a5a8f9

Import implementation of IisCA from old repo's scasched/scaexec.

Sean Hall committed Dec 16, 2018 at 21:19 UTC 95a5a8f9efef02ddcec5b3f69be99a00d71a802a
81 files changed +18951 -3
appveyor.cmd
+1 -1
@@ -5,7 +5,7 @@ nuget restore
5
6 msbuild -p:Configuration=Release -t:Restore
7
8 -rem msbuild -p:Configuration=Release src\test\WixToolsetTest.Iis\WixToolsetTest.Iis.csproj
8 +msbuild -p:Configuration=Release src\test\WixToolsetTest.Iis\WixToolsetTest.Iis.csproj
9
10 msbuild -p:Configuration=Release -t:Pack src\wixext\WixToolset.Iis.wixext.csproj
11
src/ca/CustomMsiErrors.h new
+48
@@ -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
src/ca/caSuffix.h new
+11
@@ -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
src/ca/iisca.def
+24 -1
@@ -4,4 +4,27 @@
4 LIBRARY "iisca"
5
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
src/ca/iisca.vcxproj
+78 -1
@@ -38,7 +38,7 @@
38 </ImportGroup>
39
40 <PropertyGroup>
41 - <ProjectAdditionalLinkLibraries>msi.lib</ProjectAdditionalLinkLibraries>
41 + <ProjectAdditionalLinkLibraries>crypt32.lib;msi.lib;Ws2_32.lib</ProjectAdditionalLinkLibraries>
42 </PropertyGroup>
43
44 <ItemGroup>
@@ -46,10 +46,87 @@
46 <PrecompiledHeader>Create</PrecompiledHeader>
47 </ClCompile>
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" />
87 </ItemGroup>
88
89 <ItemGroup>
90 + <ClInclude Include="caSuffix.h" />
91 + <ClInclude Include="CustomMsiErrors.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" />
130 </ItemGroup>
131
132 <ItemGroup>
src/ca/precomp.h
+54
@@ -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.
3
4
5 +#if _WIN32_MSI < 150
6 +#define _WIN32_MSI 150
7 +#endif
8 +
9 #include <windows.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
19
20 #define MAXUINT USHRT_MAX
21 #include <Setup.Configuration.h>
22
23 #include "wcautil.h"
24 +#include "wcawow64.h"
25 +#include "wcawrapquery.h"
26 +
27 +#include "certutil.h"
28 +#include "cryputil.h"
29 #include "fileutil.h"
30 +#include "iis7util.h"
31 +#include "memutil.h"
32 +#include "metautil.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"
src/ca/sca.h new
+124
@@ -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 +};
src/ca/scaapppool.cpp new
+594
@@ -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 +}
src/ca/scaapppool.h new
+88
@@ -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 + );
src/ca/scaapppool7.cpp new
+401
@@ -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 +}
src/ca/scaapppool7.h new
+36
@@ -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 + );
src/ca/scacert.cpp new
+1479
@@ -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 +*/
src/ca/scacert.h new
+22
@@ -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 +};
src/ca/scacertexec.cpp new
+404
@@ -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 +}
src/ca/scacost.h new
+15
@@ -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;
src/ca/scaexec.cpp new
+1184
@@ -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 +}
src/ca/scaexecIIS7.cpp new
+4205
@@ -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 +}
src/ca/scaexecIIS7.h new
+5
@@ -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);
src/ca/scafilter.cpp new
+510
@@ -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 +}
src/ca/scafilter.h new
+46
@@ -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 +
src/ca/scafilter7.cpp new
+284
@@ -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 +}
src/ca/scafilter7.h new
+21
@@ -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 + );
src/ca/scahttpheader.cpp new
+323
@@ -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 +}
src/ca/scahttpheader.h new
+40
@@ -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 + );
src/ca/scahttpheader7.cpp new
+130
@@ -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 +//}
src/ca/scahttpheader7.h new
+15
@@ -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 + );
src/ca/scaiis.cpp new
+481
@@ -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 +}
src/ca/scaiis.h new
+33
@@ -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);
src/ca/scaiis7.cpp new
+74
@@ -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 +
src/ca/scaiis7.h new
+17
@@ -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);
src/ca/scamimemap.cpp new
+200
@@ -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 +}
src/ca/scamimemap.h new
+33
@@ -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 +
src/ca/scamimemap7.cpp new
+68
@@ -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 +//}
src/ca/scamimemap7.h new
+10
@@ -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 +
src/ca/scaproperty.cpp new
+252
@@ -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 +}
src/ca/scaproperty.h new
+54
@@ -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 +
src/ca/scaproperty7.cpp new
+108
@@ -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 +}
src/ca/scaproperty7.h new
+26
@@ -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 +
src/ca/scasched.cpp new
+823
@@ -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 +}
src/ca/scassl.cpp new
+115
@@ -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 +}
src/ca/scassl.h new
+36
@@ -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 + );
src/ca/scassl7.cpp new
+34
@@ -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 +}
src/ca/scassl7.h new
+8
@@ -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 + );
src/ca/scauser.cpp new
+91
@@ -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 +}
src/ca/scauser.h new
+39
@@ -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 + );
src/ca/scavdir.cpp new
+331
@@ -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 +}
src/ca/scavdir.h new
+71
@@ -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 + );
src/ca/scavdir7.cpp new
+380
@@ -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 +}
src/ca/scavdir7.h new
+66
@@ -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 + );
src/ca/scaweb.cpp new
+1187
@@ -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 +}
src/ca/scaweb.h new
+123
@@ -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 + );
src/ca/scaweb7.cpp new
+952
@@ -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 +}
src/ca/scaweb7.h new
+97
@@ -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 + );
src/ca/scawebapp.cpp new
+194
@@ -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 +}
src/ca/scawebapp.h new
+42
@@ -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 +
src/ca/scawebapp7.cpp new
+120
@@ -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 +}
src/ca/scawebapp7.h new
+10
@@ -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 + );
src/ca/scawebappext.cpp new
+207
@@ -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 +}
src/ca/scawebappext.h new
+32
@@ -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 + );
src/ca/scawebappext7.cpp new
+61
@@ -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 +
src/ca/scawebappext7.h new
+9
@@ -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 + );
src/ca/scawebdir.cpp new
+241
@@ -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 +}
src/ca/scawebdir.h new
+57
@@ -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 + );
src/ca/scawebdir7.cpp new
+219
@@ -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 +}
src/ca/scawebdir7.h new
+51
@@ -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 + );
src/ca/scaweberr.cpp new
+371
@@ -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 +
src/ca/scaweberr.h new
+30
@@ -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 +
src/ca/scaweberr7.cpp new
+88
@@ -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 +
src/ca/scaweberr7.h new
+10
@@ -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 +
src/ca/scaweblog.cpp new
+177
@@ -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 +
src/ca/scaweblog.h new
+27
@@ -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 + );
src/ca/scaweblog7.cpp new
+120
@@ -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 +
src/ca/scaweblog7.h new
+14
@@ -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 + );
src/ca/scawebprop.cpp new
+301
@@ -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 +}
src/ca/scawebprop.h new
+60
@@ -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 +
src/ca/scawebprop7.cpp new
+155
@@ -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 +}
src/ca/scawebprop7.h new
+12
@@ -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 +
src/ca/scawebsvcext.cpp new
+343
@@ -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 +}
src/ca/scawebsvcext.h new
+35
@@ -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 + );
src/ca/scawebsvcext7.cpp new
+106
@@ -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 +}
src/ca/scawebsvcext7.h new
+8
@@ -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 +