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
+