diff options
Diffstat (limited to 'src/ext/Util/ca/scagroup.cpp')
-rw-r--r-- | src/ext/Util/ca/scagroup.cpp | 503 |
1 files changed, 503 insertions, 0 deletions
diff --git a/src/ext/Util/ca/scagroup.cpp b/src/ext/Util/ca/scagroup.cpp new file mode 100644 index 00000000..c484c1d2 --- /dev/null +++ b/src/ext/Util/ca/scagroup.cpp | |||
@@ -0,0 +1,503 @@ | |||
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 | #include "scanet.h" | ||
5 | |||
6 | LPCWSTR vcsGroupQuery = L"SELECT `Group`, `Component_`, `Name`, `Domain` FROM `Wix4Group` WHERE `Group`=?"; | ||
7 | enum eGroupQuery { vgqGroup = 1, vgqComponent, vgqName, vgqDomain }; | ||
8 | |||
9 | LPCWSTR vcsGroupGroupQuery = L"SELECT `Parent_`, `Child_` FROM `Wix6GroupGroup` WHERE `Child_`=?"; | ||
10 | enum eGroupGroupQuery { vggqParent = 1, vggqChild }; | ||
11 | |||
12 | LPCWSTR vActionableGroupQuery = L"SELECT `Group`,`Component_`,`Name`,`Domain`,`Comment`,`Attributes` FROM `Wix4Group`,`Wix6Group` WHERE `Component_` IS NOT NULL AND `Group`=`Group_`"; | ||
13 | enum eActionableGroupQuery { vagqGroup = 1, vagqComponent, vagqName, vagqDomain, vagqComment, vagqAttributes }; | ||
14 | |||
15 | static HRESULT AddGroupToList( | ||
16 | __inout SCA_GROUP** ppsgList | ||
17 | ); | ||
18 | |||
19 | |||
20 | HRESULT __stdcall ScaGetGroup( | ||
21 | __in LPCWSTR wzGroup, | ||
22 | __out SCA_GROUP* pscag | ||
23 | ) | ||
24 | { | ||
25 | if (!wzGroup || *wzGroup==0 || !pscag) | ||
26 | { | ||
27 | return E_INVALIDARG; | ||
28 | } | ||
29 | |||
30 | HRESULT hr = S_OK; | ||
31 | PMSIHANDLE hView, hRec; | ||
32 | |||
33 | LPWSTR pwzData = NULL; | ||
34 | |||
35 | hRec = ::MsiCreateRecord(1); | ||
36 | hr = WcaSetRecordString(hRec, 1, wzGroup); | ||
37 | ExitOnFailure(hr, "Failed to look up Group"); | ||
38 | |||
39 | hr = WcaOpenView(vcsGroupQuery, &hView); | ||
40 | ExitOnFailure(hr, "Failed to open view on Wix4Group table"); | ||
41 | hr = WcaExecuteView(hView, hRec); | ||
42 | ExitOnFailure(hr, "Failed to execute view on Wix4Group table"); | ||
43 | |||
44 | hr = WcaFetchSingleRecord(hView, &hRec); | ||
45 | if (S_OK == hr) | ||
46 | { | ||
47 | hr = WcaGetRecordString(hRec, vgqGroup, &pwzData); | ||
48 | ExitOnFailure(hr, "Failed to get Wix4Group.Group"); | ||
49 | hr = ::StringCchCopyW(pscag->wzKey, countof(pscag->wzKey), pwzData); | ||
50 | ExitOnFailure(hr, "Failed to copy key string to group object"); | ||
51 | |||
52 | hr = WcaGetRecordString(hRec, vgqComponent, &pwzData); | ||
53 | ExitOnFailure(hr, "Failed to get Wix4Group.Component_"); | ||
54 | hr = ::StringCchCopyW(pscag->wzComponent, countof(pscag->wzComponent), pwzData); | ||
55 | ExitOnFailure(hr, "Failed to copy component string to group object"); | ||
56 | |||
57 | hr = WcaGetRecordFormattedString(hRec, vgqName, &pwzData); | ||
58 | ExitOnFailure(hr, "Failed to get Wix4Group.Name"); | ||
59 | hr = ::StringCchCopyW(pscag->wzName, countof(pscag->wzName), pwzData); | ||
60 | ExitOnFailure(hr, "Failed to copy name string to group object"); | ||
61 | |||
62 | hr = WcaGetRecordFormattedString(hRec, vgqDomain, &pwzData); | ||
63 | ExitOnFailure(hr, "Failed to get Wix4Group.Domain"); | ||
64 | hr = ::StringCchCopyW(pscag->wzDomain, countof(pscag->wzDomain), pwzData); | ||
65 | ExitOnFailure(hr, "Failed to copy domain string to group object"); | ||
66 | } | ||
67 | else if (E_NOMOREITEMS == hr) | ||
68 | { | ||
69 | WcaLog(LOGMSG_STANDARD, "Error: Cannot locate Wix4Group.Group='%ls'", wzGroup); | ||
70 | hr = E_FAIL; | ||
71 | } | ||
72 | else | ||
73 | { | ||
74 | ExitOnFailure(hr, "Error or found multiple matching Wix4Group rows"); | ||
75 | } | ||
76 | |||
77 | LExit: | ||
78 | ReleaseStr(pwzData); | ||
79 | |||
80 | return hr; | ||
81 | } | ||
82 | |||
83 | HRESULT __stdcall ScaGetGroupDeferred( | ||
84 | __in LPCWSTR wzGroup, | ||
85 | __in WCA_WRAPQUERY_HANDLE hGroupQuery, | ||
86 | __out SCA_USER* pscag | ||
87 | ) | ||
88 | { | ||
89 | if (!wzGroup || !pscag) | ||
90 | { | ||
91 | return E_INVALIDARG; | ||
92 | } | ||
93 | |||
94 | HRESULT hr = S_OK; | ||
95 | MSIHANDLE hRec, hRecTest; | ||
96 | |||
97 | LPWSTR pwzData = NULL; | ||
98 | |||
99 | // clear struct and bail right away if no group key was passed to search for | ||
100 | ::ZeroMemory(pscag, sizeof(*pscag)); | ||
101 | if (!*wzGroup) | ||
102 | { | ||
103 | ExitFunction1(hr = S_OK); | ||
104 | } | ||
105 | |||
106 | // Reset back to the first record | ||
107 | WcaFetchWrappedReset(hGroupQuery); | ||
108 | |||
109 | hr = WcaFetchWrappedRecordWhereString(hGroupQuery, vgqGroup, wzGroup, &hRec); | ||
110 | if (S_OK == hr) | ||
111 | { | ||
112 | hr = WcaFetchWrappedRecordWhereString(hGroupQuery, vgqGroup, wzGroup, &hRecTest); | ||
113 | if (S_OK == hr) | ||
114 | { | ||
115 | AssertSz(FALSE, "Found multiple matching Wix4Group rows"); | ||
116 | } | ||
117 | |||
118 | hr = WcaGetRecordString(hRec, vgqGroup, &pwzData); | ||
119 | ExitOnFailure(hr, "Failed to get Wix4Group.Group"); | ||
120 | hr = ::StringCchCopyW(pscag->wzKey, countof(pscag->wzKey), pwzData); | ||
121 | ExitOnFailure(hr, "Failed to copy key string to group object (in deferred CA)"); | ||
122 | |||
123 | hr = WcaGetRecordString(hRec, vgqComponent, &pwzData); | ||
124 | ExitOnFailure(hr, "Failed to get Wix4Group.Component_"); | ||
125 | hr = ::StringCchCopyW(pscag->wzComponent, countof(pscag->wzComponent), pwzData); | ||
126 | ExitOnFailure(hr, "Failed to copy component string to group object (in deferred CA)"); | ||
127 | |||
128 | hr = WcaGetRecordString(hRec, vgqName, &pwzData); | ||
129 | ExitOnFailure(hr, "Failed to get Wix4Group.Name"); | ||
130 | hr = ::StringCchCopyW(pscag->wzName, countof(pscag->wzName), pwzData); | ||
131 | ExitOnFailure(hr, "Failed to copy name string to group object (in deferred CA)"); | ||
132 | |||
133 | hr = WcaGetRecordString(hRec, vgqDomain, &pwzData); | ||
134 | ExitOnFailure(hr, "Failed to get Wix4Group.Domain"); | ||
135 | hr = ::StringCchCopyW(pscag->wzDomain, countof(pscag->wzDomain), pwzData); | ||
136 | ExitOnFailure(hr, "Failed to copy domain string to group object (in deferred CA)"); | ||
137 | } | ||
138 | else if (E_NOMOREITEMS == hr) | ||
139 | { | ||
140 | WcaLog(LOGMSG_STANDARD, "Error: Cannot locate Wix4Group.Group='%ls'", wzGroup); | ||
141 | hr = E_FAIL; | ||
142 | } | ||
143 | else | ||
144 | { | ||
145 | ExitOnFailure(hr, "Error fetching single Wix4Group row"); | ||
146 | } | ||
147 | |||
148 | LExit: | ||
149 | ReleaseStr(pwzData); | ||
150 | |||
151 | return hr; | ||
152 | } | ||
153 | |||
154 | void ScaGroupFreeList( | ||
155 | __in SCA_GROUP* psgList | ||
156 | ) | ||
157 | { | ||
158 | SCA_GROUP* psgDelete = psgList; | ||
159 | while (psgList) | ||
160 | { | ||
161 | psgDelete = psgList; | ||
162 | psgList = psgList->psgNext; | ||
163 | |||
164 | MemFree(psgDelete); | ||
165 | } | ||
166 | } | ||
167 | |||
168 | |||
169 | HRESULT ScaGroupRead( | ||
170 | __out SCA_GROUP** ppsgList | ||
171 | ) | ||
172 | { | ||
173 | //Assert(FALSE); | ||
174 | Assert(ppsgList); | ||
175 | |||
176 | HRESULT hr = S_OK; | ||
177 | UINT er = ERROR_SUCCESS; | ||
178 | PMSIHANDLE hView, hRec, hGroupRec, hGroupGroupView; | ||
179 | |||
180 | LPWSTR pwzData = NULL; | ||
181 | |||
182 | BOOL fGroupGroupExists = FALSE; | ||
183 | |||
184 | SCA_GROUP *psg = NULL; | ||
185 | |||
186 | INSTALLSTATE isInstalled, isAction; | ||
187 | |||
188 | if (S_OK != WcaTableExists(L"Wix4Group")) | ||
189 | { | ||
190 | WcaLog(LOGMSG_VERBOSE, "Wix4Group Table does not exist, exiting"); | ||
191 | ExitFunction1(hr = S_FALSE); | ||
192 | } | ||
193 | if (S_OK != WcaTableExists(L"Wix6Group")) | ||
194 | { | ||
195 | WcaLog(LOGMSG_VERBOSE, "Wix6Group Table does not exist, exiting"); | ||
196 | ExitFunction1(hr = S_FALSE); | ||
197 | } | ||
198 | |||
199 | if (S_OK == WcaTableExists(L"Wix6GroupGroup")) | ||
200 | { | ||
201 | fGroupGroupExists = TRUE; | ||
202 | } | ||
203 | |||
204 | // | ||
205 | // loop through all the groups | ||
206 | // | ||
207 | hr = WcaOpenExecuteView(vActionableGroupQuery, &hView); | ||
208 | ExitOnFailure(hr, "failed to open view on Wix4Group,Wix6Group table(s)"); | ||
209 | while (S_OK == (hr = WcaFetchRecord(hView, &hRec))) | ||
210 | { | ||
211 | hr = WcaGetRecordString(hRec, vagqComponent, &pwzData); | ||
212 | ExitOnFailure(hr, "failed to get Wix4Group.Component"); | ||
213 | |||
214 | er = ::MsiGetComponentStateW(WcaGetInstallHandle(), pwzData, &isInstalled, &isAction); | ||
215 | hr = HRESULT_FROM_WIN32(er); | ||
216 | ExitOnFailure(hr, "failed to get Component state for Wix4Group"); | ||
217 | |||
218 | // don't bother if we aren't installing or uninstalling this component | ||
219 | if (WcaIsInstalling(isInstalled, isAction) || WcaIsUninstalling(isInstalled, isAction)) | ||
220 | { | ||
221 | // | ||
222 | // Add the group to the list and populate it's values | ||
223 | // | ||
224 | hr = AddGroupToList(ppsgList); | ||
225 | ExitOnFailure(hr, "failed to add group to list"); | ||
226 | |||
227 | psg = *ppsgList; | ||
228 | |||
229 | psg->isInstalled = isInstalled; | ||
230 | psg->isAction = isAction; | ||
231 | hr = ::StringCchCopyW(psg->wzComponent, countof(psg->wzComponent), pwzData); | ||
232 | ExitOnFailure(hr, "failed to copy component name: %ls", pwzData); | ||
233 | |||
234 | hr = WcaGetRecordString(hRec, vagqGroup, &pwzData); | ||
235 | ExitOnFailure(hr, "failed to get Wix4Group.Group"); | ||
236 | hr = ::StringCchCopyW(psg->wzKey, countof(psg->wzKey), pwzData); | ||
237 | ExitOnFailure(hr, "failed to copy group key: %ls", pwzData); | ||
238 | |||
239 | hr = WcaGetRecordFormattedString(hRec, vagqName, &pwzData); | ||
240 | ExitOnFailure(hr, "failed to get Wix4Group.Name"); | ||
241 | hr = ::StringCchCopyW(psg->wzName, countof(psg->wzName), pwzData); | ||
242 | ExitOnFailure(hr, "failed to copy group name: %ls", pwzData); | ||
243 | |||
244 | hr = WcaGetRecordFormattedString(hRec, vagqDomain, &pwzData); | ||
245 | ExitOnFailure(hr, "failed to get Wix4Group.Domain"); | ||
246 | hr = ::StringCchCopyW(psg->wzDomain, countof(psg->wzDomain), pwzData); | ||
247 | ExitOnFailure(hr, "failed to copy group domain: %ls", pwzData); | ||
248 | hr = WcaGetRecordFormattedString(hRec, vagqComment, &pwzData); | ||
249 | ExitOnFailure(hr, "failed to get Wix6Group.Comment"); | ||
250 | hr = ::StringCchCopyW(psg->wzComment, countof(psg->wzComment), pwzData); | ||
251 | ExitOnFailure(hr, "failed to copy group comment: %ls", pwzData); | ||
252 | |||
253 | hr = WcaGetRecordInteger(hRec, vagqAttributes, &psg->iAttributes); | ||
254 | ExitOnFailure(hr, "failed to get Wix6Group.Attributes"); | ||
255 | |||
256 | // Check if this group is to be added to any other groups | ||
257 | if (fGroupGroupExists) | ||
258 | { | ||
259 | hGroupRec = ::MsiCreateRecord(1); | ||
260 | hr = WcaSetRecordString(hGroupRec, 1, psg->wzKey); | ||
261 | ExitOnFailure(hr, "Failed to create group record for querying Wix6GroupGroup table"); | ||
262 | |||
263 | hr = WcaOpenExecuteView(vcsGroupGroupQuery, &hGroupGroupView); | ||
264 | ExitOnFailure(hr, "Failed to open view on Wix6GroupGroup table for group %ls", psg->wzKey);/* | ||
265 | hr = WcaExecuteView(hGroupGroupView, hGroupRec); | ||
266 | ExitOnFailure(hr, "Failed to execute view on Wix6GroupGroup table for group: %ls", psg->wzKey);*/ | ||
267 | |||
268 | while (S_OK == (hr = WcaFetchRecord(hGroupGroupView, &hRec))) | ||
269 | { | ||
270 | hr = WcaGetRecordString(hRec, vggqParent, &pwzData); | ||
271 | ExitOnFailure(hr, "failed to get Wix6GroupGroup.Parent"); | ||
272 | |||
273 | hr = AddGroupToList(&(psg->psgGroups)); | ||
274 | ExitOnFailure(hr, "failed to add group to list"); | ||
275 | |||
276 | hr = ScaGetGroup(pwzData, psg->psgGroups); | ||
277 | ExitOnFailure(hr, "failed to get information for group: %ls", pwzData); | ||
278 | } | ||
279 | |||
280 | if (E_NOMOREITEMS == hr) | ||
281 | { | ||
282 | hr = S_OK; | ||
283 | } | ||
284 | ExitOnFailure(hr, "failed to enumerate selected rows from Wix4UserGroup table"); | ||
285 | } | ||
286 | } | ||
287 | } | ||
288 | |||
289 | if (E_NOMOREITEMS == hr) | ||
290 | { | ||
291 | hr = S_OK; | ||
292 | } | ||
293 | ExitOnFailure(hr, "failed to enumerate selected rows from Wix4Group table"); | ||
294 | |||
295 | LExit: | ||
296 | ReleaseStr(pwzData); | ||
297 | |||
298 | return hr; | ||
299 | } | ||
300 | |||
301 | /* **************************************************************** | ||
302 | ScaGroupExecute - Schedules group account creation or removal based on | ||
303 | component state. | ||
304 | |||
305 | ******************************************************************/ | ||
306 | HRESULT ScaGroupExecute( | ||
307 | __in SCA_GROUP *psgList | ||
308 | ) | ||
309 | { | ||
310 | HRESULT hr = S_OK; | ||
311 | DWORD er = 0; | ||
312 | |||
313 | LPWSTR pwzBaseScriptKey = NULL; | ||
314 | DWORD cScriptKey = 0; | ||
315 | |||
316 | LOCALGROUP_INFO_0 *pGroupInfo = NULL; | ||
317 | LPWSTR pwzScriptKey = NULL; | ||
318 | LPWSTR pwzActionData = NULL; | ||
319 | LPWSTR pwzRollbackData = NULL; | ||
320 | LPWSTR pwzServerName = NULL; | ||
321 | |||
322 | // Get the base script key for this CustomAction. | ||
323 | hr = WcaCaScriptCreateKey(&pwzBaseScriptKey); | ||
324 | ExitOnFailure(hr, "Failed to get encoding key."); | ||
325 | |||
326 | // Loop through all the users to be configured. | ||
327 | for (SCA_GROUP *psg = psgList; psg; psg = psg->psgNext) | ||
328 | { | ||
329 | GROUP_EXISTS geGroupExists = GROUP_EXISTS_INDETERMINATE; | ||
330 | |||
331 | // Always put the Group Name, Domain, and Comment on the front of the CustomAction data. | ||
332 | // The attributes will be added when we have finished adjusting them. Sometimes we'll | ||
333 | // add more data. | ||
334 | Assert(psg->wzName); | ||
335 | hr = WcaWriteStringToCaData(psg->wzName, &pwzActionData); | ||
336 | ExitOnFailure(hr, "Failed to add group name to custom action data: %ls", psg->wzName); | ||
337 | hr = WcaWriteStringToCaData(psg->wzDomain, &pwzActionData); | ||
338 | ExitOnFailure(hr, "Failed to add group domain to custom action data: %ls", psg->wzDomain); | ||
339 | hr = WcaWriteStringToCaData(psg->wzComment, &pwzActionData); | ||
340 | ExitOnFailure(hr, "Failed to add group comment to custom action data: %ls", psg->wzComment); | ||
341 | |||
342 | // Check to see if the group already exists since we have to be very careful when adding | ||
343 | // and removing groups. Note: MSDN says that it is safe to call these APIs from any | ||
344 | // user, so we should be safe calling it during immediate mode. | ||
345 | |||
346 | LPCWSTR wzDomain = psg->wzDomain; | ||
347 | hr = GetDomainServerName(wzDomain, &pwzServerName); | ||
348 | |||
349 | er = ::NetLocalGroupGetInfo(pwzServerName, psg->wzName, 0, reinterpret_cast<LPBYTE*>(&pGroupInfo)); | ||
350 | if (NERR_Success == er) | ||
351 | { | ||
352 | geGroupExists = GROUP_EXISTS_YES; | ||
353 | } | ||
354 | else if (NERR_GroupNotFound == er) | ||
355 | { | ||
356 | geGroupExists = GROUP_EXISTS_NO; | ||
357 | } | ||
358 | else | ||
359 | { | ||
360 | geGroupExists = GROUP_EXISTS_INDETERMINATE; | ||
361 | hr = HRESULT_FROM_WIN32(er); | ||
362 | WcaLog(LOGMSG_VERBOSE, "Failed to check existence of domain: %ls, group: %ls (error code 0x%x) - continuing", wzDomain, psg->wzName, hr); | ||
363 | hr = S_OK; | ||
364 | er = ERROR_SUCCESS; | ||
365 | } | ||
366 | |||
367 | if (WcaIsInstalling(psg->isInstalled, psg->isAction)) | ||
368 | { | ||
369 | // If the group exists, check to see if we are supposed to fail if the group exists before | ||
370 | // the install. | ||
371 | if (GROUP_EXISTS_YES == geGroupExists) | ||
372 | { | ||
373 | // Re-installs will always fail if we don't remove the check for "fail if exists". | ||
374 | if (WcaIsReInstalling(psg->isInstalled, psg->isAction)) | ||
375 | { | ||
376 | psg->iAttributes &= ~SCAG_FAIL_IF_EXISTS; | ||
377 | |||
378 | // If install would create the group, re-install should be able to update the group. | ||
379 | if (!(psg->iAttributes & SCAG_DONT_CREATE_GROUP)) | ||
380 | { | ||
381 | psg->iAttributes |= SCAG_UPDATE_IF_EXISTS; | ||
382 | } | ||
383 | } | ||
384 | |||
385 | if (SCAG_FAIL_IF_EXISTS & psg->iAttributes | ||
386 | && !(SCAG_UPDATE_IF_EXISTS & psg->iAttributes)) | ||
387 | { | ||
388 | hr = HRESULT_FROM_WIN32(NERR_GroupExists); | ||
389 | MessageExitOnFailure(hr, msierrGRPFailedGroupCreateExists, "Failed to create group: %ls because group already exists.", psg->wzName); | ||
390 | } | ||
391 | } | ||
392 | |||
393 | hr = WcaWriteIntegerToCaData(psg->iAttributes, &pwzActionData); | ||
394 | ExitOnFailure(hr, "failed to add group attributes to custom action data for group: %ls", psg->wzKey); | ||
395 | |||
396 | // Rollback only if the group already exists, we couldn't determine if the group exists, or we are going to create the group | ||
397 | if ((GROUP_EXISTS_YES == geGroupExists) | ||
398 | || (GROUP_EXISTS_INDETERMINATE == geGroupExists) | ||
399 | || !(psg->iAttributes & SCAG_DONT_CREATE_GROUP)) | ||
400 | { | ||
401 | ++cScriptKey; | ||
402 | hr = StrAllocFormatted(&pwzScriptKey, L"%ls%u", pwzBaseScriptKey, cScriptKey); | ||
403 | ExitOnFailure(hr, "Failed to create encoding key."); | ||
404 | |||
405 | // Write the script key to CustomActionData for install and rollback so information can be passed to rollback. | ||
406 | hr = WcaWriteStringToCaData(pwzScriptKey, &pwzActionData); | ||
407 | ExitOnFailure(hr, "Failed to add encoding key to custom action data."); | ||
408 | |||
409 | hr = WcaWriteStringToCaData(pwzScriptKey, &pwzRollbackData); | ||
410 | ExitOnFailure(hr, "Failed to add encoding key to rollback custom action data."); | ||
411 | |||
412 | INT iRollbackUserAttributes = psg->iAttributes; | ||
413 | |||
414 | // If the user already exists, ensure this is accounted for in rollback | ||
415 | if (GROUP_EXISTS_YES == geGroupExists) | ||
416 | { | ||
417 | iRollbackUserAttributes |= SCAG_DONT_CREATE_GROUP; | ||
418 | } | ||
419 | else | ||
420 | { | ||
421 | iRollbackUserAttributes &= ~SCAG_DONT_CREATE_GROUP; | ||
422 | } | ||
423 | |||
424 | hr = WcaWriteStringToCaData(psg->wzName, &pwzRollbackData); | ||
425 | ExitOnFailure(hr, "Failed to add group name to rollback custom action data: %ls", psg->wzName); | ||
426 | hr = WcaWriteStringToCaData(psg->wzDomain, &pwzRollbackData); | ||
427 | ExitOnFailure(hr, "Failed to add group domain to rollback custom action data: %ls", psg->wzDomain); | ||
428 | hr = WcaWriteIntegerToCaData(iRollbackUserAttributes, &pwzRollbackData); | ||
429 | ExitOnFailure(hr, "failed to add group attributes to rollback custom action data for group: %ls", psg->wzKey); | ||
430 | |||
431 | hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"CreateGroupRollback"), pwzRollbackData, COST_GROUP_DELETE); | ||
432 | ExitOnFailure(hr, "failed to schedule CreateGroupRollback"); | ||
433 | } | ||
434 | else | ||
435 | { | ||
436 | // Write empty script key to CustomActionData since there is no rollback. | ||
437 | hr = WcaWriteStringToCaData(L"", &pwzActionData); | ||
438 | ExitOnFailure(hr, "Failed to add empty encoding key to custom action data."); | ||
439 | } | ||
440 | |||
441 | // | ||
442 | // Schedule the creation now. | ||
443 | // | ||
444 | hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"CreateGroup"), pwzActionData, COST_GROUP_ADD); | ||
445 | ExitOnFailure(hr, "failed to schedule CreateGroup"); | ||
446 | } | ||
447 | else if (((GROUP_EXISTS_YES == geGroupExists) | ||
448 | || (GROUP_EXISTS_INDETERMINATE == geGroupExists)) | ||
449 | && WcaIsUninstalling(psg->isInstalled, psg->isAction) | ||
450 | && !(psg->iAttributes & SCAG_DONT_REMOVE_ON_UNINSTALL)) | ||
451 | { | ||
452 | hr = WcaWriteIntegerToCaData(psg->iAttributes, &pwzActionData); | ||
453 | ExitOnFailure(hr, "failed to add group attributes to custom action data for group: %ls", psg->wzKey); | ||
454 | |||
455 | // Schedule the removal because the group exists and we don't have any flags set | ||
456 | // that say not to remove the group on uninstall. | ||
457 | // | ||
458 | // Note: We can't rollback the removal of a group which is why RemoveGroup is a commit | ||
459 | // CustomAction. | ||
460 | hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"RemoveGroup"), pwzActionData, COST_GROUP_DELETE); | ||
461 | ExitOnFailure(hr, "failed to schedule RemoveGroup"); | ||
462 | } | ||
463 | |||
464 | ReleaseNullStr(pwzScriptKey); | ||
465 | ReleaseNullStr(pwzActionData); | ||
466 | ReleaseNullStr(pwzRollbackData); | ||
467 | ReleaseNullStr(pwzServerName); | ||
468 | if (pGroupInfo) | ||
469 | { | ||
470 | ::NetApiBufferFree(static_cast<LPVOID>(pGroupInfo)); | ||
471 | pGroupInfo = NULL; | ||
472 | } | ||
473 | } | ||
474 | |||
475 | LExit: | ||
476 | ReleaseStr(pwzBaseScriptKey); | ||
477 | ReleaseStr(pwzScriptKey); | ||
478 | ReleaseStr(pwzActionData); | ||
479 | ReleaseStr(pwzRollbackData); | ||
480 | ReleaseStr(pwzServerName); | ||
481 | if (pGroupInfo) | ||
482 | { | ||
483 | ::NetApiBufferFree(static_cast<LPVOID>(pGroupInfo)); | ||
484 | pGroupInfo = NULL; | ||
485 | } | ||
486 | |||
487 | return hr; | ||
488 | } | ||
489 | |||
490 | static HRESULT AddGroupToList( | ||
491 | __inout SCA_GROUP** ppsgList | ||
492 | ) | ||
493 | { | ||
494 | HRESULT hr = S_OK; | ||
495 | SCA_GROUP* psg = static_cast<SCA_GROUP*>(MemAlloc(sizeof(SCA_GROUP), TRUE)); | ||
496 | ExitOnNull(psg, hr, E_OUTOFMEMORY, "failed to allocate memory for new group list element"); | ||
497 | |||
498 | psg->psgNext = *ppsgList; | ||
499 | *ppsgList = psg; | ||
500 | |||
501 | LExit: | ||
502 | return hr; | ||
503 | } | ||