diff options
Diffstat (limited to '')
| -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 | } | ||
