diff options
Diffstat (limited to 'src/ext/Util/ca')
-rw-r--r-- | src/ext/Util/ca/CustomMsiErrors.h | 6 | ||||
-rw-r--r-- | src/ext/Util/ca/sca.h | 12 | ||||
-rw-r--r-- | src/ext/Util/ca/scacost.h | 2 | ||||
-rw-r--r-- | src/ext/Util/ca/scaexec.cpp | 628 | ||||
-rw-r--r-- | src/ext/Util/ca/scagroup.cpp | 503 | ||||
-rw-r--r-- | src/ext/Util/ca/scagroup.h | 47 | ||||
-rw-r--r-- | src/ext/Util/ca/scanet.cpp | 50 | ||||
-rw-r--r-- | src/ext/Util/ca/scanet.h | 4 | ||||
-rw-r--r-- | src/ext/Util/ca/scasched.cpp | 47 | ||||
-rw-r--r-- | src/ext/Util/ca/scauser.cpp | 83 | ||||
-rw-r--r-- | src/ext/Util/ca/scauser.h | 20 | ||||
-rw-r--r-- | src/ext/Util/ca/utilca.def | 4 | ||||
-rw-r--r-- | src/ext/Util/ca/utilca.vcxproj | 4 |
13 files changed, 1306 insertions, 104 deletions
diff --git a/src/ext/Util/ca/CustomMsiErrors.h b/src/ext/Util/ca/CustomMsiErrors.h index 3218b61b..ac0c549f 100644 --- a/src/ext/Util/ca/CustomMsiErrors.h +++ b/src/ext/Util/ca/CustomMsiErrors.h | |||
@@ -29,4 +29,8 @@ | |||
29 | #define msierrUSRFailedUserCreateExists 26404 | 29 | #define msierrUSRFailedUserCreateExists 26404 |
30 | #define msierrUSRFailedGrantLogonAsService 26405 | 30 | #define msierrUSRFailedGrantLogonAsService 26405 |
31 | 31 | ||
32 | //Last available is 26450 \ No newline at end of file | 32 | #define msierrGRPFailedGroupCreate 26421 |
33 | #define msierrGRPFailedGroupGroupAdd 26422 | ||
34 | #define msierrGRPFailedGroupCreateExists 26423 | ||
35 | |||
36 | //Last available is 26450 | ||
diff --git a/src/ext/Util/ca/sca.h b/src/ext/Util/ca/sca.h index 84f5ffd9..0e25a19a 100644 --- a/src/ext/Util/ca/sca.h +++ b/src/ext/Util/ca/sca.h | |||
@@ -18,3 +18,15 @@ enum SCAU_ATTRIBUTES | |||
18 | SCAU_NON_VITAL = 0x00000400, | 18 | SCAU_NON_VITAL = 0x00000400, |
19 | SCAU_REMOVE_COMMENT = 0x00000800, | 19 | SCAU_REMOVE_COMMENT = 0x00000800, |
20 | }; | 20 | }; |
21 | |||
22 | // group creation attributes definitions | ||
23 | enum SCAG_ATTRIBUTES | ||
24 | { | ||
25 | SCAG_FAIL_IF_EXISTS = 0x00000001, | ||
26 | SCAG_UPDATE_IF_EXISTS = 0x00000002, | ||
27 | |||
28 | SCAG_DONT_REMOVE_ON_UNINSTALL = 0x00000004, | ||
29 | SCAG_DONT_CREATE_GROUP = 0x00000008, | ||
30 | SCAG_NON_VITAL = 0x00000010, | ||
31 | SCAG_REMOVE_COMMENT = 0x00000020, | ||
32 | }; | ||
diff --git a/src/ext/Util/ca/scacost.h b/src/ext/Util/ca/scacost.h index 5b215035..978e40bc 100644 --- a/src/ext/Util/ca/scacost.h +++ b/src/ext/Util/ca/scacost.h | |||
@@ -9,6 +9,8 @@ const UINT COST_SMB_CREATESMB = 10000; | |||
9 | const UINT COST_SMB_DROPSMB = 5000; | 9 | const UINT COST_SMB_DROPSMB = 5000; |
10 | const UINT COST_USER_ADD = 10000; | 10 | const UINT COST_USER_ADD = 10000; |
11 | const UINT COST_USER_DELETE = 10000; | 11 | const UINT COST_USER_DELETE = 10000; |
12 | const UINT COST_GROUP_ADD = 10000; | ||
13 | const UINT COST_GROUP_DELETE = 10000; | ||
12 | 14 | ||
13 | const UINT COST_PERFMONMANIFEST_REGISTER = 1000; | 15 | const UINT COST_PERFMONMANIFEST_REGISTER = 1000; |
14 | const UINT COST_PERFMONMANIFEST_UNREGISTER = 1000; | 16 | const UINT COST_PERFMONMANIFEST_UNREGISTER = 1000; |
diff --git a/src/ext/Util/ca/scaexec.cpp b/src/ext/Util/ca/scaexec.cpp index 8579b8bb..5a750c6b 100644 --- a/src/ext/Util/ca/scaexec.cpp +++ b/src/ext/Util/ca/scaexec.cpp | |||
@@ -291,6 +291,145 @@ LExit: | |||
291 | return hr; | 291 | return hr; |
292 | } | 292 | } |
293 | 293 | ||
294 | static HRESULT AddGroupToGroup( | ||
295 | __in LPWSTR wzMember, | ||
296 | __in LPCWSTR wzMemberDomain, | ||
297 | __in LPCWSTR wzGroup, | ||
298 | __in LPCWSTR wzGroupDomain | ||
299 | ) | ||
300 | { | ||
301 | Assert(wzMember && *wzMember && wzMemberDomain && wzGroup && *wzGroup && wzGroupDomain); | ||
302 | |||
303 | HRESULT hr = S_OK; | ||
304 | IADsGroup* pGroup = NULL; | ||
305 | BSTR bstrMember = NULL; | ||
306 | BSTR bstrGroup = NULL; | ||
307 | LPWSTR pwzMember = NULL; | ||
308 | LPWSTR pwzServerName = NULL; | ||
309 | LOCALGROUP_MEMBERS_INFO_3 lgmi {}; | ||
310 | |||
311 | GetDomainServerName(wzGroupDomain, &pwzServerName); | ||
312 | |||
313 | // Try adding it to the local group | ||
314 | if (wzMemberDomain) | ||
315 | { | ||
316 | hr = StrAllocFormatted(&pwzMember, L"%s\\%s", wzMemberDomain, wzMember); | ||
317 | ExitOnFailure(hr, "failed to allocate group domain string"); | ||
318 | } | ||
319 | |||
320 | lgmi.lgrmi3_domainandname = (NULL == pwzMember ? wzMember : pwzMember); | ||
321 | NET_API_STATUS ui = ::NetLocalGroupAddMembers(pwzServerName, wzGroup, 3, reinterpret_cast<LPBYTE>(&lgmi), 1); | ||
322 | hr = HRESULT_FROM_WIN32(ui); | ||
323 | if (HRESULT_FROM_WIN32(ERROR_MEMBER_IN_ALIAS) == hr) // if they're already a member of the group don't report an error | ||
324 | { | ||
325 | hr = S_OK; | ||
326 | } | ||
327 | |||
328 | // | ||
329 | // If we failed, try active directory | ||
330 | // | ||
331 | if (FAILED(hr)) | ||
332 | { | ||
333 | WcaLog(LOGMSG_VERBOSE, "Failed to add group: %ls, domain %ls to group: %ls, domain: %ls with error 0x%x. Attempting to use Active Directory", wzMember, wzMemberDomain, wzGroup, wzGroupDomain, hr); | ||
334 | |||
335 | hr = UserCreateADsPath(wzMemberDomain, wzMember, &bstrMember); | ||
336 | ExitOnFailure(hr, "failed to create group ADsPath for group: %ls domain: %ls", wzMember, wzMemberDomain); | ||
337 | |||
338 | hr = UserCreateADsPath(wzGroupDomain, wzGroup, &bstrGroup); | ||
339 | ExitOnFailure(hr, "failed to create group ADsPath for group: %ls domain: %ls", wzGroup, wzGroupDomain); | ||
340 | |||
341 | hr = ::ADsGetObject(bstrGroup, IID_IADsGroup, reinterpret_cast<void**>(&pGroup)); | ||
342 | ExitOnFailure(hr, "Failed to get group '%ls'.", reinterpret_cast<WCHAR*>(bstrGroup)); | ||
343 | |||
344 | hr = pGroup->Add(bstrMember); | ||
345 | if ((HRESULT_FROM_WIN32(ERROR_OBJECT_ALREADY_EXISTS) == hr) || (HRESULT_FROM_WIN32(ERROR_MEMBER_IN_ALIAS) == hr)) | ||
346 | hr = S_OK; | ||
347 | |||
348 | ExitOnFailure(hr, "Failed to add group %ls to group '%ls'.", reinterpret_cast<WCHAR*>(bstrMember), reinterpret_cast<WCHAR*>(bstrGroup)); | ||
349 | } | ||
350 | |||
351 | LExit: | ||
352 | ReleaseStr(pwzServerName); | ||
353 | ReleaseStr(pwzMember); | ||
354 | ReleaseBSTR(bstrMember); | ||
355 | ReleaseBSTR(bstrGroup); | ||
356 | ReleaseObject(pGroup); | ||
357 | |||
358 | return hr; | ||
359 | } | ||
360 | |||
361 | static HRESULT RemoveGroupFromGroup( | ||
362 | __in LPWSTR wzMember, | ||
363 | __in LPCWSTR wzMemberDomain, | ||
364 | __in LPCWSTR wzGroup, | ||
365 | __in LPCWSTR wzGroupDomain | ||
366 | ) | ||
367 | { | ||
368 | Assert(wzMember && *wzMember && wzMemberDomain && wzGroup && *wzGroup && wzGroupDomain); | ||
369 | |||
370 | HRESULT hr = S_OK; | ||
371 | IADsGroup* pGroup = NULL; | ||
372 | BSTR bstrMember = NULL; | ||
373 | BSTR bstrGroup = NULL; | ||
374 | LPWSTR pwzMember = NULL; | ||
375 | LPWSTR pwzServerName = NULL; | ||
376 | LOCALGROUP_MEMBERS_INFO_3 lgmi {}; | ||
377 | |||
378 | GetDomainServerName(wzGroupDomain, &pwzServerName, DS_WRITABLE_REQUIRED); | ||
379 | |||
380 | // Try removing it from the local group | ||
381 | if (wzMemberDomain) | ||
382 | { | ||
383 | hr = StrAllocFormatted(&pwzMember, L"%s\\%s", wzMemberDomain, wzMember); | ||
384 | ExitOnFailure(hr, "failed to allocate group domain string"); | ||
385 | } | ||
386 | |||
387 | lgmi.lgrmi3_domainandname = (NULL == pwzMember ? wzMember : pwzMember); | ||
388 | NET_API_STATUS ui = ::NetLocalGroupDelMembers(pwzServerName, wzGroup, 3, reinterpret_cast<LPBYTE>(&lgmi), 1); | ||
389 | hr = HRESULT_FROM_WIN32(ui); | ||
390 | if (HRESULT_FROM_WIN32(ERROR_MEMBER_NOT_IN_ALIAS) == hr | ||
391 | || HRESULT_FROM_WIN32(NERR_GroupNotFound) == hr | ||
392 | || HRESULT_FROM_WIN32(ERROR_NO_SUCH_MEMBER) == hr) // if they're already not a member of the group, or the group doesn't exist, don't report an error | ||
393 | { | ||
394 | hr = S_OK; | ||
395 | } | ||
396 | |||
397 | // | ||
398 | // If we failed, try active directory | ||
399 | // | ||
400 | if (FAILED(hr)) | ||
401 | { | ||
402 | WcaLog(LOGMSG_VERBOSE, "Failed to remove group: %ls, domain %ls from group: %ls, domain: %ls with error 0x%x. Attempting to use Active Directory", wzMember, wzMemberDomain, wzGroup, wzGroupDomain, hr); | ||
403 | |||
404 | hr = UserCreateADsPath(wzMemberDomain, wzMember, &bstrMember); | ||
405 | ExitOnFailure(hr, "failed to create group ADsPath in order to remove group: %ls domain: %ls from a group", wzMember, wzMemberDomain); | ||
406 | |||
407 | hr = UserCreateADsPath(wzGroupDomain, wzGroup, &bstrGroup); | ||
408 | ExitOnFailure(hr, "failed to create group ADsPath in order to remove group from group: %ls domain: %ls", wzGroup, wzGroupDomain); | ||
409 | |||
410 | hr = ::ADsGetObject(bstrGroup, IID_IADsGroup, reinterpret_cast<void**>(&pGroup)); | ||
411 | if ((HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr)) // if parent group not found, no need to remove membership from group | ||
412 | { | ||
413 | hr = S_OK; | ||
414 | ExitFunction(); | ||
415 | } | ||
416 | ExitOnFailure(hr, "Failed to get group '%ls'.", reinterpret_cast<WCHAR*>(bstrGroup)); | ||
417 | |||
418 | hr = pGroup->Remove(bstrMember); | ||
419 | if ((HRESULT_FROM_WIN32(ERROR_MEMBER_NOT_IN_ALIAS) == hr)) // if already not a member, no need to worry about error | ||
420 | hr = S_OK; | ||
421 | ExitOnFailure(hr, "Failed to remove group %ls from group '%ls'.", reinterpret_cast<WCHAR*>(bstrMember), reinterpret_cast<WCHAR*>(bstrGroup)); | ||
422 | } | ||
423 | |||
424 | LExit: | ||
425 | ReleaseStr(pwzServerName); | ||
426 | ReleaseStr(pwzMember); | ||
427 | ReleaseBSTR(bstrMember); | ||
428 | ReleaseBSTR(bstrGroup); | ||
429 | ReleaseObject(pGroup); | ||
430 | |||
431 | return hr; | ||
432 | } | ||
294 | 433 | ||
295 | static HRESULT GetUserHasRight( | 434 | static HRESULT GetUserHasRight( |
296 | __in LSA_HANDLE hPolicy, | 435 | __in LSA_HANDLE hPolicy, |
@@ -590,6 +729,15 @@ static HRESULT SetUserComment(__in LPWSTR pwzServerName, __in LPWSTR pwzName, __ | |||
590 | return HRESULT_FROM_WIN32(er); | 729 | return HRESULT_FROM_WIN32(er); |
591 | } | 730 | } |
592 | 731 | ||
732 | static HRESULT SetGroupComment(__in LPWSTR pwzServerName, __in LPWSTR pwzName, __in LPWSTR pwzComment) | ||
733 | { | ||
734 | _LOCALGROUP_INFO_1002 groupInfo1002 {}; | ||
735 | |||
736 | groupInfo1002.lgrpi1002_comment = pwzComment; | ||
737 | NET_API_STATUS er = ::NetLocalGroupSetInfo(pwzServerName, pwzName, 1002, reinterpret_cast<LPBYTE>(&groupInfo1002), NULL); | ||
738 | return HRESULT_FROM_WIN32(er); | ||
739 | } | ||
740 | |||
593 | static HRESULT SetUserFlags(__in LPWSTR pwzServerName, __in LPWSTR pwzName, __in DWORD flags) | 741 | static HRESULT SetUserFlags(__in LPWSTR pwzServerName, __in LPWSTR pwzName, __in DWORD flags) |
594 | { | 742 | { |
595 | NET_API_STATUS er = NERR_Success; | 743 | NET_API_STATUS er = NERR_Success; |
@@ -693,6 +841,76 @@ LExit: | |||
693 | return hr; | 841 | return hr; |
694 | } | 842 | } |
695 | 843 | ||
844 | static HRESULT RemoveGroupInternal( | ||
845 | LPWSTR wzGroupCaData, | ||
846 | LPWSTR wzDomain, | ||
847 | LPWSTR wzName, | ||
848 | int iAttributes | ||
849 | ) | ||
850 | { | ||
851 | HRESULT hr = S_OK; | ||
852 | |||
853 | LPWSTR pwz = NULL; | ||
854 | LPWSTR pwzGroup = NULL; | ||
855 | LPWSTR pwzGroupDomain = NULL; | ||
856 | LPWSTR pwzServerName = NULL; | ||
857 | |||
858 | // | ||
859 | // Remove the Group if the group was created by us. | ||
860 | // | ||
861 | if (!(SCAG_DONT_CREATE_GROUP & iAttributes)) | ||
862 | { | ||
863 | GetDomainServerName(wzDomain, &pwzServerName, DS_WRITABLE_REQUIRED); | ||
864 | |||
865 | NET_API_STATUS er = ::NetLocalGroupDel(pwzServerName, wzName); | ||
866 | hr = HRESULT_FROM_WIN32(er); | ||
867 | if (HRESULT_FROM_WIN32(ERROR_NO_SUCH_ALIAS) == hr | ||
868 | || HRESULT_FROM_WIN32(NERR_GroupNotFound) == hr) // we wanted to delete it.. and the group doesn't exist.. solved. | ||
869 | { | ||
870 | hr = S_OK; | ||
871 | } | ||
872 | ExitOnFailure(hr, "failed to delete group: %ls", wzName); | ||
873 | } | ||
874 | else | ||
875 | { | ||
876 | // | ||
877 | // Remove the group from other groups | ||
878 | // | ||
879 | pwz = wzGroupCaData; | ||
880 | while (S_OK == (hr = WcaReadStringFromCaData(&pwz, &pwzGroup))) | ||
881 | { | ||
882 | hr = WcaReadStringFromCaData(&pwz, &pwzGroupDomain); | ||
883 | |||
884 | if (FAILED(hr)) | ||
885 | { | ||
886 | WcaLogError(hr, "failed to get domain for group: %ls, continuing anyway.", pwzGroup); | ||
887 | } | ||
888 | else | ||
889 | { | ||
890 | hr = RemoveGroupFromGroup(wzName, wzDomain, pwzGroup, pwzGroupDomain); | ||
891 | if (FAILED(hr)) | ||
892 | { | ||
893 | WcaLogError(hr, "failed to remove group: %ls from group %ls, continuing anyway.", wzName, pwzGroup); | ||
894 | } | ||
895 | } | ||
896 | } | ||
897 | |||
898 | if (E_NOMOREITEMS == hr) // if there are no more items, all is well | ||
899 | { | ||
900 | hr = S_OK; | ||
901 | } | ||
902 | |||
903 | ExitOnFailure(hr, "failed to get next group from which to remove group:%ls", wzName); | ||
904 | } | ||
905 | LExit: | ||
906 | ReleaseStr(pwzServerName); | ||
907 | ReleaseStr(pwzGroup); | ||
908 | ReleaseStr(pwzGroupDomain); | ||
909 | |||
910 | return hr; | ||
911 | } | ||
912 | |||
913 | |||
696 | /******************************************************************** | 914 | /******************************************************************** |
697 | CreateUser - CUSTOM ACTION ENTRY POINT for creating users | 915 | CreateUser - CUSTOM ACTION ENTRY POINT for creating users |
698 | 916 | ||
@@ -1173,3 +1391,413 @@ LExit: | |||
1173 | 1391 | ||
1174 | return WcaFinalize(er); | 1392 | return WcaFinalize(er); |
1175 | } | 1393 | } |
1394 | |||
1395 | /******************************************************************** | ||
1396 | CreateGroup - CUSTOM ACTION ENTRY POINT for creating groups | ||
1397 | |||
1398 | Input: deferred CustomActionData - GroupName\tDomain\tComment\tAttributes | ||
1399 | * *****************************************************************/ | ||
1400 | extern "C" UINT __stdcall CreateGroup( | ||
1401 | __in MSIHANDLE hInstall | ||
1402 | ) | ||
1403 | { | ||
1404 | //AssertSz(0, "Debug CreateGroup"); | ||
1405 | |||
1406 | HRESULT hr = S_OK; | ||
1407 | NET_API_STATUS er = ERROR_SUCCESS; | ||
1408 | |||
1409 | LPWSTR pwzData = NULL; | ||
1410 | LPWSTR pwz = NULL; | ||
1411 | LPWSTR pwzName = NULL; | ||
1412 | LPWSTR pwzDomain = NULL; | ||
1413 | LPWSTR pwzComment = NULL; | ||
1414 | LPWSTR pwzScriptKey = NULL; | ||
1415 | LPWSTR pwzGroup = NULL; | ||
1416 | LPWSTR pwzGroupDomain = NULL; | ||
1417 | int iAttributes = 0; | ||
1418 | BOOL fInitializedCom = FALSE; | ||
1419 | |||
1420 | LOCALGROUP_INFO_1* pGroupInfo1 = NULL; | ||
1421 | |||
1422 | WCA_CASCRIPT_HANDLE hRollbackScript = NULL; | ||
1423 | int iRollbackAttributes = 0; | ||
1424 | |||
1425 | DWORD dw; | ||
1426 | LPWSTR pwzServerName = NULL; | ||
1427 | |||
1428 | hr = WcaInitialize(hInstall, "CreateGroup"); | ||
1429 | ExitOnFailure(hr, "failed to initialize"); | ||
1430 | |||
1431 | hr = ::CoInitialize(NULL); | ||
1432 | ExitOnFailure(hr, "failed to initialize COM"); | ||
1433 | fInitializedCom = TRUE; | ||
1434 | |||
1435 | hr = WcaGetProperty(L"CustomActionData", &pwzData); | ||
1436 | ExitOnFailure(hr, "failed to get CustomActionData"); | ||
1437 | |||
1438 | WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %ls", pwzData); | ||
1439 | |||
1440 | // | ||
1441 | // Read in the CustomActionData | ||
1442 | // | ||
1443 | pwz = pwzData; | ||
1444 | hr = WcaReadStringFromCaData(&pwz, &pwzName); | ||
1445 | ExitOnFailure(hr, "failed to read group name from custom action data"); | ||
1446 | |||
1447 | hr = WcaReadStringFromCaData(&pwz, &pwzDomain); | ||
1448 | ExitOnFailure(hr, "failed to read domain from custom action data"); | ||
1449 | |||
1450 | hr = WcaReadStringFromCaData(&pwz, &pwzComment); | ||
1451 | ExitOnFailure(hr, "failed to read group comment from custom action data"); | ||
1452 | |||
1453 | hr = WcaReadIntegerFromCaData(&pwz, &iAttributes); | ||
1454 | ExitOnFailure(hr, "failed to read attributes from custom action data"); | ||
1455 | |||
1456 | hr = WcaReadStringFromCaData(&pwz, &pwzScriptKey); | ||
1457 | ExitOnFailure(hr, "failed to read encoding key from custom action data"); | ||
1458 | |||
1459 | if (!(SCAG_DONT_CREATE_GROUP & iAttributes)) | ||
1460 | { | ||
1461 | hr = GetDomainServerName(pwzDomain, &pwzServerName, DS_WRITABLE_REQUIRED); | ||
1462 | ExitOnFailure(hr, "failed to find Domain %ls.", pwzDomain); | ||
1463 | |||
1464 | // Set the group's comment | ||
1465 | if (SCAG_REMOVE_COMMENT & iAttributes) | ||
1466 | { | ||
1467 | StrAllocString(&pwzComment, L"", 0); | ||
1468 | } | ||
1469 | |||
1470 | // | ||
1471 | // Create the Group | ||
1472 | // | ||
1473 | LOCALGROUP_INFO_1 groupInfo1; | ||
1474 | groupInfo1.lgrpi1_name = pwzName; | ||
1475 | groupInfo1.lgrpi1_comment = pwzComment; | ||
1476 | er = ::NetLocalGroupAdd(pwzServerName, 1, reinterpret_cast<LPBYTE>(&groupInfo1), &dw); | ||
1477 | hr = HRESULT_FROM_WIN32(er); | ||
1478 | |||
1479 | if (HRESULT_FROM_WIN32(ERROR_ALIAS_EXISTS) == hr | ||
1480 | || HRESULT_FROM_WIN32(NERR_GroupExists) == hr) | ||
1481 | { | ||
1482 | if (SCAG_FAIL_IF_EXISTS & iAttributes) | ||
1483 | { | ||
1484 | MessageExitOnFailure(hr, msierrGRPFailedGroupCreateExists, "Group (%ls) was not supposed to exist, but does", pwzName); | ||
1485 | } | ||
1486 | |||
1487 | hr = S_OK; // Make sure that we don't report this situation as an error | ||
1488 | // if we fall through the tests that follow. | ||
1489 | |||
1490 | if (SCAG_UPDATE_IF_EXISTS & iAttributes) | ||
1491 | { | ||
1492 | er = ::NetLocalGroupGetInfo(pwzServerName, pwzName, 1, reinterpret_cast<LPBYTE*>(&pGroupInfo1)); | ||
1493 | hr = HRESULT_FROM_WIN32(er); | ||
1494 | if (S_OK == hr) | ||
1495 | { | ||
1496 | // There is no rollback scheduled if the key is empty. | ||
1497 | // Best effort to get original configuration and save it in the script so rollback can restore it. | ||
1498 | if (*pwzScriptKey) | ||
1499 | { | ||
1500 | // Try to open the rollback script | ||
1501 | hr = WcaCaScriptOpen(WCA_ACTION_INSTALL, WCA_CASCRIPT_ROLLBACK, FALSE, pwzScriptKey, &hRollbackScript); | ||
1502 | |||
1503 | if (hRollbackScript && INVALID_HANDLE_VALUE != hRollbackScript->hScriptFile) | ||
1504 | { | ||
1505 | WcaCaScriptClose(hRollbackScript, WCA_CASCRIPT_CLOSE_PRESERVE); | ||
1506 | } | ||
1507 | else | ||
1508 | { | ||
1509 | hRollbackScript = NULL; | ||
1510 | hr = WcaCaScriptCreate(WCA_ACTION_INSTALL, WCA_CASCRIPT_ROLLBACK, FALSE, pwzScriptKey, FALSE, &hRollbackScript); | ||
1511 | ExitOnFailure(hr, "Failed to open rollback CustomAction script."); | ||
1512 | |||
1513 | iRollbackAttributes = 0; | ||
1514 | |||
1515 | hr = WcaCaScriptWriteString(hRollbackScript, pGroupInfo1->lgrpi1_comment); | ||
1516 | ExitOnFailure(hr, "Failed to add rollback comment to rollback script."); | ||
1517 | |||
1518 | if (!pGroupInfo1->lgrpi1_comment || !*pGroupInfo1->lgrpi1_comment) | ||
1519 | { | ||
1520 | iRollbackAttributes |= SCAG_REMOVE_COMMENT; | ||
1521 | } | ||
1522 | |||
1523 | hr = WcaCaScriptWriteNumber(hRollbackScript, iRollbackAttributes); | ||
1524 | ExitOnFailure(hr, "Failed to add rollback attributes to rollback script."); | ||
1525 | |||
1526 | // Nudge the system to get all our rollback data written to disk. | ||
1527 | WcaCaScriptFlush(hRollbackScript); | ||
1528 | } | ||
1529 | } | ||
1530 | } | ||
1531 | |||
1532 | if (S_OK == hr) | ||
1533 | { | ||
1534 | if (SCAG_REMOVE_COMMENT & iAttributes) | ||
1535 | { | ||
1536 | hr = SetGroupComment(pwzServerName, pwzName, L""); | ||
1537 | if (FAILED(hr)) | ||
1538 | { | ||
1539 | WcaLogError(hr, "failed to clear comment for group %ls\\%ls, continuing anyway.", pwzServerName, pwzName); | ||
1540 | hr = S_OK; | ||
1541 | } | ||
1542 | } | ||
1543 | else if (pwzComment && *pwzComment) | ||
1544 | { | ||
1545 | hr = SetGroupComment(pwzServerName, pwzName, pwzComment); | ||
1546 | if (FAILED(hr)) | ||
1547 | { | ||
1548 | WcaLogError(hr, "failed to set comment to %ls for group %ls\\%ls, continuing anyway.", pwzComment, pwzServerName, pwzName); | ||
1549 | hr = S_OK; | ||
1550 | } | ||
1551 | } | ||
1552 | } | ||
1553 | } | ||
1554 | } | ||
1555 | MessageExitOnFailure(hr, msierrGRPFailedGroupCreate, "failed to create group: %ls", pwzName); | ||
1556 | |||
1557 | // | ||
1558 | // Add the groups to groups | ||
1559 | // | ||
1560 | while (S_OK == (hr = WcaReadStringFromCaData(&pwz, &pwzGroup))) | ||
1561 | { | ||
1562 | hr = WcaReadStringFromCaData(&pwz, &pwzGroupDomain); | ||
1563 | ExitOnFailure(hr, "failed to get domain for group: %ls", pwzGroup); | ||
1564 | |||
1565 | WcaLog(LOGMSG_STANDARD, "Adding group %ls\\%ls to group %ls\\%ls", pwzDomain, pwzName, pwzGroupDomain, pwzGroup); | ||
1566 | hr = AddGroupToGroup(pwzName, pwzDomain, pwzGroup, pwzGroupDomain); | ||
1567 | MessageExitOnFailure(hr, msierrUSRFailedUserGroupAdd, "failed to add group: %ls to group %ls", pwzName, pwzGroup); | ||
1568 | } | ||
1569 | if (E_NOMOREITEMS == hr) // if there are no more items, all is well | ||
1570 | { | ||
1571 | hr = S_OK; | ||
1572 | } | ||
1573 | ExitOnFailure(hr, "failed to get next group in which to include group: %ls", pwzName); | ||
1574 | } | ||
1575 | |||
1576 | LExit: | ||
1577 | WcaCaScriptClose(hRollbackScript, WCA_CASCRIPT_CLOSE_PRESERVE); | ||
1578 | |||
1579 | if (pGroupInfo1) | ||
1580 | { | ||
1581 | ::NetApiBufferFree((LPVOID)pGroupInfo1); | ||
1582 | } | ||
1583 | |||
1584 | ReleaseStr(pwzData); | ||
1585 | ReleaseStr(pwzName); | ||
1586 | ReleaseStr(pwzDomain); | ||
1587 | ReleaseStr(pwzComment); | ||
1588 | ReleaseStr(pwzScriptKey); | ||
1589 | ReleaseStr(pwzGroup); | ||
1590 | ReleaseStr(pwzGroupDomain); | ||
1591 | |||
1592 | if (fInitializedCom) | ||
1593 | { | ||
1594 | ::CoUninitialize(); | ||
1595 | } | ||
1596 | |||
1597 | if (SCAG_NON_VITAL & iAttributes) | ||
1598 | { | ||
1599 | er = ERROR_SUCCESS; | ||
1600 | } | ||
1601 | else if (FAILED(hr)) | ||
1602 | { | ||
1603 | er = ERROR_INSTALL_FAILURE; | ||
1604 | } | ||
1605 | |||
1606 | return WcaFinalize(er); | ||
1607 | } | ||
1608 | |||
1609 | |||
1610 | /******************************************************************** | ||
1611 | CreateGroupRollback - CUSTOM ACTION ENTRY POINT for CreateGroup rollback | ||
1612 | |||
1613 | * *****************************************************************/ | ||
1614 | extern "C" UINT __stdcall CreateGroupRollback( | ||
1615 | MSIHANDLE hInstall | ||
1616 | ) | ||
1617 | { | ||
1618 | //AssertSz(0, "Debug CreateGroupRollback"); | ||
1619 | |||
1620 | HRESULT hr = S_OK; | ||
1621 | UINT er = ERROR_SUCCESS; | ||
1622 | |||
1623 | LPWSTR pwzData = NULL; | ||
1624 | LPWSTR pwz = NULL; | ||
1625 | LPWSTR pwzScriptKey = NULL; | ||
1626 | LPWSTR pwzName = NULL; | ||
1627 | LPWSTR pwzDomain = NULL; | ||
1628 | LPWSTR pwzComment = NULL; | ||
1629 | int iAttributes = 0; | ||
1630 | BOOL fInitializedCom = FALSE; | ||
1631 | |||
1632 | WCA_CASCRIPT_HANDLE hRollbackScript = NULL; | ||
1633 | LPWSTR pwzRollbackData = NULL; | ||
1634 | int iOriginalAttributes = 0; | ||
1635 | LPWSTR pwzOriginalComment = NULL; | ||
1636 | |||
1637 | hr = WcaInitialize(hInstall, "CreateGroupRollback"); | ||
1638 | ExitOnFailure(hr, "failed to initialize"); | ||
1639 | |||
1640 | hr = ::CoInitialize(NULL); | ||
1641 | ExitOnFailure(hr, "failed to initialize COM"); | ||
1642 | fInitializedCom = TRUE; | ||
1643 | |||
1644 | hr = WcaGetProperty(L"CustomActionData", &pwzData); | ||
1645 | ExitOnFailure(hr, "failed to get CustomActionData"); | ||
1646 | |||
1647 | WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %ls", pwzData); | ||
1648 | |||
1649 | // | ||
1650 | // Read in the CustomActionData | ||
1651 | // | ||
1652 | pwz = pwzData; | ||
1653 | hr = WcaReadStringFromCaData(&pwz, &pwzScriptKey); | ||
1654 | ExitOnFailure(hr, "failed to read encoding key from custom action data"); | ||
1655 | |||
1656 | hr = WcaReadStringFromCaData(&pwz, &pwzName); | ||
1657 | ExitOnFailure(hr, "failed to read name from custom action data"); | ||
1658 | |||
1659 | hr = WcaReadStringFromCaData(&pwz, &pwzDomain); | ||
1660 | ExitOnFailure(hr, "failed to read domain from custom action data"); | ||
1661 | |||
1662 | hr = WcaReadStringFromCaData(&pwz, &pwzComment); | ||
1663 | ExitOnFailure(hr, "failed to read comment from custom action data"); | ||
1664 | |||
1665 | hr = WcaReadIntegerFromCaData(&pwz, &iAttributes); | ||
1666 | ExitOnFailure(hr, "failed to read attributes from custom action data"); | ||
1667 | |||
1668 | // Best effort to read original configuration from CreateUser. | ||
1669 | hr = WcaCaScriptOpen(WCA_ACTION_INSTALL, WCA_CASCRIPT_ROLLBACK, FALSE, pwzScriptKey, &hRollbackScript); | ||
1670 | if (FAILED(hr)) | ||
1671 | { | ||
1672 | WcaLogError(hr, "Failed to open rollback CustomAction script, continuing anyway."); | ||
1673 | } | ||
1674 | else | ||
1675 | { | ||
1676 | hr = WcaCaScriptReadAsCustomActionData(hRollbackScript, &pwzRollbackData); | ||
1677 | if (FAILED(hr)) | ||
1678 | { | ||
1679 | WcaLogError(hr, "Failed to read rollback script into CustomAction data, continuing anyway."); | ||
1680 | } | ||
1681 | else | ||
1682 | { | ||
1683 | WcaLog(LOGMSG_TRACEONLY, "Rollback Data: %ls", pwzRollbackData); | ||
1684 | |||
1685 | pwz = pwzRollbackData; | ||
1686 | hr = WcaReadStringFromCaData(&pwz, &pwzOriginalComment); | ||
1687 | if (FAILED(hr)) | ||
1688 | { | ||
1689 | WcaLogError(hr, "failed to read comment from rollback data, continuing anyway"); | ||
1690 | } | ||
1691 | else | ||
1692 | { | ||
1693 | pwzComment = pwzOriginalComment; | ||
1694 | } | ||
1695 | hr = WcaReadIntegerFromCaData(&pwz, &iOriginalAttributes); | ||
1696 | if (FAILED(hr)) | ||
1697 | { | ||
1698 | WcaLogError(hr, "failed to read attributes from rollback data, continuing anyway"); | ||
1699 | } | ||
1700 | else | ||
1701 | { | ||
1702 | iAttributes |= iOriginalAttributes; | ||
1703 | } | ||
1704 | } | ||
1705 | } | ||
1706 | |||
1707 | hr = RemoveGroupInternal(pwz, pwzDomain, pwzName, iAttributes); | ||
1708 | |||
1709 | LExit: | ||
1710 | WcaCaScriptClose(hRollbackScript, WCA_CASCRIPT_CLOSE_DELETE); | ||
1711 | |||
1712 | ReleaseStr(pwzData); | ||
1713 | ReleaseStr(pwzName); | ||
1714 | ReleaseStr(pwzDomain); | ||
1715 | ReleaseStr(pwzComment); | ||
1716 | ReleaseStr(pwzScriptKey); | ||
1717 | ReleaseStr(pwzRollbackData); | ||
1718 | ReleaseStr(pwzOriginalComment); | ||
1719 | |||
1720 | if (fInitializedCom) | ||
1721 | { | ||
1722 | ::CoUninitialize(); | ||
1723 | } | ||
1724 | |||
1725 | if (FAILED(hr)) | ||
1726 | { | ||
1727 | er = ERROR_INSTALL_FAILURE; | ||
1728 | } | ||
1729 | |||
1730 | return WcaFinalize(er); | ||
1731 | } | ||
1732 | |||
1733 | |||
1734 | /******************************************************************** | ||
1735 | RemoveGroup - CUSTOM ACTION ENTRY POINT for removing groups | ||
1736 | |||
1737 | Input: deferred CustomActionData - Name\tDomain | ||
1738 | * *****************************************************************/ | ||
1739 | extern "C" UINT __stdcall RemoveGroup( | ||
1740 | MSIHANDLE hInstall | ||
1741 | ) | ||
1742 | { | ||
1743 | //AssertSz(0, "Debug RemoveGroup"); | ||
1744 | |||
1745 | HRESULT hr = S_OK; | ||
1746 | UINT er = ERROR_SUCCESS; | ||
1747 | |||
1748 | LPWSTR pwzData = NULL; | ||
1749 | LPWSTR pwz = NULL; | ||
1750 | LPWSTR pwzName = NULL; | ||
1751 | LPWSTR pwzDomain = NULL; | ||
1752 | LPWSTR pwzComment = NULL; | ||
1753 | int iAttributes = 0; | ||
1754 | BOOL fInitializedCom = FALSE; | ||
1755 | |||
1756 | hr = WcaInitialize(hInstall, "RemoveGroup"); | ||
1757 | ExitOnFailure(hr, "failed to initialize"); | ||
1758 | |||
1759 | hr = ::CoInitialize(NULL); | ||
1760 | ExitOnFailure(hr, "failed to initialize COM"); | ||
1761 | fInitializedCom = TRUE; | ||
1762 | |||
1763 | hr = WcaGetProperty(L"CustomActionData", &pwzData); | ||
1764 | ExitOnFailure(hr, "failed to get CustomActionData"); | ||
1765 | |||
1766 | WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %ls", pwzData); | ||
1767 | |||
1768 | // | ||
1769 | // Read in the CustomActionData | ||
1770 | // | ||
1771 | pwz = pwzData; | ||
1772 | hr = WcaReadStringFromCaData(&pwz, &pwzName); | ||
1773 | ExitOnFailure(hr, "failed to read name from custom action data"); | ||
1774 | |||
1775 | hr = WcaReadStringFromCaData(&pwz, &pwzDomain); | ||
1776 | ExitOnFailure(hr, "failed to read domain from custom action data"); | ||
1777 | |||
1778 | hr = WcaReadStringFromCaData(&pwz, &pwzComment); | ||
1779 | ExitOnFailure(hr, "failed to read comment from custom action data"); | ||
1780 | |||
1781 | hr = WcaReadIntegerFromCaData(&pwz, &iAttributes); | ||
1782 | ExitOnFailure(hr, "failed to read attributes from custom action data"); | ||
1783 | |||
1784 | hr = RemoveGroupInternal(pwz, pwzDomain, pwzName, iAttributes); | ||
1785 | |||
1786 | LExit: | ||
1787 | ReleaseStr(pwzData); | ||
1788 | ReleaseStr(pwzName); | ||
1789 | ReleaseStr(pwzDomain); | ||
1790 | ReleaseStr(pwzComment); | ||
1791 | |||
1792 | if (fInitializedCom) | ||
1793 | { | ||
1794 | ::CoUninitialize(); | ||
1795 | } | ||
1796 | |||
1797 | if (FAILED(hr)) | ||
1798 | { | ||
1799 | er = ERROR_INSTALL_FAILURE; | ||
1800 | } | ||
1801 | |||
1802 | return WcaFinalize(er); | ||
1803 | } | ||
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 | } | ||
diff --git a/src/ext/Util/ca/scagroup.h b/src/ext/Util/ca/scagroup.h new file mode 100644 index 00000000..8666d852 --- /dev/null +++ b/src/ext/Util/ca/scagroup.h | |||
@@ -0,0 +1,47 @@ | |||
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 | enum GROUP_EXISTS | ||
5 | { | ||
6 | GROUP_EXISTS_YES, | ||
7 | GROUP_EXISTS_NO, | ||
8 | GROUP_EXISTS_INDETERMINATE | ||
9 | }; | ||
10 | |||
11 | // structs | ||
12 | struct SCA_GROUP | ||
13 | { | ||
14 | WCHAR wzKey[MAX_DARWIN_KEY + 1]; | ||
15 | WCHAR wzComponent[MAX_DARWIN_KEY + 1]; | ||
16 | INSTALLSTATE isInstalled; | ||
17 | INSTALLSTATE isAction; | ||
18 | |||
19 | WCHAR wzDomain[MAX_DARWIN_COLUMN + 1]; | ||
20 | WCHAR wzName[MAX_DARWIN_COLUMN + 1]; | ||
21 | WCHAR wzComment[MAX_DARWIN_COLUMN + 1]; | ||
22 | INT iAttributes; | ||
23 | |||
24 | SCA_GROUP* psgGroups; | ||
25 | |||
26 | SCA_GROUP *psgNext; | ||
27 | }; | ||
28 | |||
29 | // prototypes | ||
30 | HRESULT __stdcall ScaGetGroup( | ||
31 | __in LPCWSTR wzGroup, | ||
32 | __out SCA_GROUP* pscag | ||
33 | ); | ||
34 | HRESULT __stdcall ScaGetGroupDeferred( | ||
35 | __in LPCWSTR wzGroup, | ||
36 | __in WCA_WRAPQUERY_HANDLE hGroupQuery, | ||
37 | __out SCA_GROUP* pscag | ||
38 | ); | ||
39 | void ScaGroupFreeList( | ||
40 | __in SCA_GROUP* psgList | ||
41 | ); | ||
42 | HRESULT ScaGroupRead( | ||
43 | __inout SCA_GROUP** ppsgList | ||
44 | ); | ||
45 | HRESULT ScaGroupExecute( | ||
46 | __in SCA_GROUP*psgList | ||
47 | ); | ||
diff --git a/src/ext/Util/ca/scanet.cpp b/src/ext/Util/ca/scanet.cpp new file mode 100644 index 00000000..11ee487d --- /dev/null +++ b/src/ext/Util/ca/scanet.cpp | |||
@@ -0,0 +1,50 @@ | |||
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 | |||
7 | HRESULT GetDomainServerName(LPCWSTR pwzDomain, LPWSTR* ppwzServerName, ULONG flags) | ||
8 | { | ||
9 | DWORD er = ERROR_SUCCESS; | ||
10 | PDOMAIN_CONTROLLER_INFOW pDomainControllerInfo = NULL; | ||
11 | HRESULT hr = S_OK; | ||
12 | |||
13 | if (pwzDomain && *pwzDomain) | ||
14 | { | ||
15 | er = ::DsGetDcNameW(NULL, pwzDomain, NULL, NULL, flags, &pDomainControllerInfo); | ||
16 | if (RPC_S_SERVER_UNAVAILABLE == er) | ||
17 | { | ||
18 | // MSDN says, if we get the above error code, try again with the "DS_FORCE_REDISCOVERY" flag | ||
19 | er = ::DsGetDcNameW(NULL, pwzDomain, NULL, NULL, flags | DS_FORCE_REDISCOVERY, &pDomainControllerInfo); | ||
20 | } | ||
21 | |||
22 | if (ERROR_SUCCESS == er && pDomainControllerInfo->DomainControllerName) | ||
23 | { | ||
24 | // Skip the \\ prefix if present. | ||
25 | if ('\\' == *pDomainControllerInfo->DomainControllerName && '\\' == *pDomainControllerInfo->DomainControllerName + 1) | ||
26 | { | ||
27 | hr = StrAllocString(ppwzServerName, pDomainControllerInfo->DomainControllerName + 2, 0); | ||
28 | ExitOnFailure(hr, "failed to allocate memory for string"); | ||
29 | } | ||
30 | else | ||
31 | { | ||
32 | hr = StrAllocString(ppwzServerName, pDomainControllerInfo->DomainControllerName, 0); | ||
33 | ExitOnFailure(hr, "failed to allocate memory for string"); | ||
34 | } | ||
35 | } | ||
36 | else | ||
37 | { | ||
38 | StrAllocString(ppwzServerName, pwzDomain, 0); | ||
39 | hr = HRESULT_FROM_WIN32(er); | ||
40 | ExitOnFailure(hr, "failed to contact domain %ls", pwzDomain); | ||
41 | } | ||
42 | } | ||
43 | |||
44 | LExit: | ||
45 | if (pDomainControllerInfo) | ||
46 | { | ||
47 | ::NetApiBufferFree((LPVOID)pDomainControllerInfo); | ||
48 | } | ||
49 | return hr; | ||
50 | } | ||
diff --git a/src/ext/Util/ca/scanet.h b/src/ext/Util/ca/scanet.h new file mode 100644 index 00000000..1fee61f8 --- /dev/null +++ b/src/ext/Util/ca/scanet.h | |||
@@ -0,0 +1,4 @@ | |||
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 | HRESULT GetDomainServerName(LPCWSTR pwzDomain, LPWSTR* ppwzServerName, ULONG flags = 0); | ||
diff --git a/src/ext/Util/ca/scasched.cpp b/src/ext/Util/ca/scasched.cpp index d81b1f14..1351fbfd 100644 --- a/src/ext/Util/ca/scasched.cpp +++ b/src/ext/Util/ca/scasched.cpp | |||
@@ -124,4 +124,49 @@ LExit: | |||
124 | 124 | ||
125 | er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; | 125 | er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; |
126 | return WcaFinalize(er); | 126 | return WcaFinalize(er); |
127 | } \ No newline at end of file | 127 | } |
128 | |||
129 | /******************************************************************** | ||
130 | ConfigureGroups - CUSTOM ACTION ENTRY POINT for installing groups | ||
131 | |||
132 | ********************************************************************/ | ||
133 | extern "C" UINT __stdcall ConfigureGroups( | ||
134 | __in MSIHANDLE hInstall | ||
135 | ) | ||
136 | { | ||
137 | //AssertSz(0, "Debug ConfigureGroups"); | ||
138 | |||
139 | HRESULT hr = S_OK; | ||
140 | UINT er = ERROR_SUCCESS; | ||
141 | |||
142 | BOOL fInitializedCom = FALSE; | ||
143 | SCA_GROUP* psgList = NULL; | ||
144 | |||
145 | // initialize | ||
146 | hr = WcaInitialize(hInstall, "ConfigureGroups"); | ||
147 | ExitOnFailure(hr, "Failed to initialize"); | ||
148 | |||
149 | hr = ::CoInitialize(NULL); | ||
150 | ExitOnFailure(hr, "failed to initialize COM"); | ||
151 | fInitializedCom = TRUE; | ||
152 | |||
153 | hr = ScaGroupRead(&psgList); | ||
154 | ExitOnFailure(hr, "failed to read Wix4Group,Wix6Group table(s)"); | ||
155 | |||
156 | hr = ScaGroupExecute(psgList); | ||
157 | ExitOnFailure(hr, "failed to add/remove Group actions"); | ||
158 | |||
159 | LExit: | ||
160 | if (psgList) | ||
161 | { | ||
162 | ScaGroupFreeList(psgList); | ||
163 | } | ||
164 | |||
165 | if (fInitializedCom) | ||
166 | { | ||
167 | ::CoUninitialize(); | ||
168 | } | ||
169 | |||
170 | er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; | ||
171 | return WcaFinalize(er); | ||
172 | } | ||
diff --git a/src/ext/Util/ca/scauser.cpp b/src/ext/Util/ca/scauser.cpp index 79da155f..21911e48 100644 --- a/src/ext/Util/ca/scauser.cpp +++ b/src/ext/Util/ca/scauser.cpp | |||
@@ -5,9 +5,6 @@ | |||
5 | LPCWSTR vcsUserQuery = L"SELECT `User`, `Component_`, `Name`, `Domain`, `Comment`, `Password` FROM `Wix4User` WHERE `User`=?"; | 5 | LPCWSTR vcsUserQuery = L"SELECT `User`, `Component_`, `Name`, `Domain`, `Comment`, `Password` FROM `Wix4User` WHERE `User`=?"; |
6 | enum eUserQuery { vuqUser = 1, vuqComponent, vuqName, vuqDomain, vuqComment, vuqPassword }; | 6 | enum eUserQuery { vuqUser = 1, vuqComponent, vuqName, vuqDomain, vuqComment, vuqPassword }; |
7 | 7 | ||
8 | LPCWSTR vcsGroupQuery = L"SELECT `Group`, `Component_`, `Name`, `Domain` FROM `Wix4Group` WHERE `Group`=?"; | ||
9 | enum eGroupQuery { vgqGroup = 1, vgqComponent, vgqName, vgqDomain }; | ||
10 | |||
11 | LPCWSTR vcsUserGroupQuery = L"SELECT `User_`, `Group_` FROM `Wix4UserGroup` WHERE `User_`=?"; | 8 | LPCWSTR vcsUserGroupQuery = L"SELECT `User_`, `Group_` FROM `Wix4UserGroup` WHERE `User_`=?"; |
12 | enum eUserGroupQuery { vugqUser = 1, vugqGroup }; | 9 | enum eUserGroupQuery { vugqUser = 1, vugqGroup }; |
13 | 10 | ||
@@ -185,71 +182,6 @@ LExit: | |||
185 | return hr; | 182 | return hr; |
186 | } | 183 | } |
187 | 184 | ||
188 | |||
189 | HRESULT __stdcall ScaGetGroup( | ||
190 | __in LPCWSTR wzGroup, | ||
191 | __out SCA_GROUP* pscag | ||
192 | ) | ||
193 | { | ||
194 | if (!wzGroup || !pscag) | ||
195 | { | ||
196 | return E_INVALIDARG; | ||
197 | } | ||
198 | |||
199 | HRESULT hr = S_OK; | ||
200 | PMSIHANDLE hView, hRec; | ||
201 | |||
202 | LPWSTR pwzData = NULL; | ||
203 | |||
204 | hRec = ::MsiCreateRecord(1); | ||
205 | hr = WcaSetRecordString(hRec, 1, wzGroup); | ||
206 | ExitOnFailure(hr, "Failed to look up Group"); | ||
207 | |||
208 | hr = WcaOpenView(vcsGroupQuery, &hView); | ||
209 | ExitOnFailure(hr, "Failed to open view on Wix4Group table"); | ||
210 | hr = WcaExecuteView(hView, hRec); | ||
211 | ExitOnFailure(hr, "Failed to execute view on Wix4Group table"); | ||
212 | |||
213 | hr = WcaFetchSingleRecord(hView, &hRec); | ||
214 | if (S_OK == hr) | ||
215 | { | ||
216 | hr = WcaGetRecordString(hRec, vgqGroup, &pwzData); | ||
217 | ExitOnFailure(hr, "Failed to get Wix4Group.Group."); | ||
218 | hr = ::StringCchCopyW(pscag->wzKey, countof(pscag->wzKey), pwzData); | ||
219 | ExitOnFailure(hr, "Failed to copy Wix4Group.Group."); | ||
220 | |||
221 | hr = WcaGetRecordString(hRec, vgqComponent, &pwzData); | ||
222 | ExitOnFailure(hr, "Failed to get Wix4Group.Component_"); | ||
223 | hr = ::StringCchCopyW(pscag->wzComponent, countof(pscag->wzComponent), pwzData); | ||
224 | ExitOnFailure(hr, "Failed to copy Wix4Group.Component_."); | ||
225 | |||
226 | hr = WcaGetRecordFormattedString(hRec, vgqName, &pwzData); | ||
227 | ExitOnFailure(hr, "Failed to get Wix4Group.Name"); | ||
228 | hr = ::StringCchCopyW(pscag->wzName, countof(pscag->wzName), pwzData); | ||
229 | ExitOnFailure(hr, "Failed to copy Wix4Group.Name."); | ||
230 | |||
231 | hr = WcaGetRecordFormattedString(hRec, vgqDomain, &pwzData); | ||
232 | ExitOnFailure(hr, "Failed to get Wix4Group.Domain"); | ||
233 | hr = ::StringCchCopyW(pscag->wzDomain, countof(pscag->wzDomain), pwzData); | ||
234 | ExitOnFailure(hr, "Failed to copy Wix4Group.Domain."); | ||
235 | } | ||
236 | else if (E_NOMOREITEMS == hr) | ||
237 | { | ||
238 | WcaLog(LOGMSG_STANDARD, "Error: Cannot locate Wix4Group.Group='%ls'", wzGroup); | ||
239 | hr = E_FAIL; | ||
240 | } | ||
241 | else | ||
242 | { | ||
243 | ExitOnFailure(hr, "Error or found multiple matching Wix4Group rows"); | ||
244 | } | ||
245 | |||
246 | LExit: | ||
247 | ReleaseStr(pwzData); | ||
248 | |||
249 | return hr; | ||
250 | } | ||
251 | |||
252 | |||
253 | void ScaUserFreeList( | 185 | void ScaUserFreeList( |
254 | __in SCA_USER* psuList | 186 | __in SCA_USER* psuList |
255 | ) | 187 | ) |
@@ -266,21 +198,6 @@ void ScaUserFreeList( | |||
266 | } | 198 | } |
267 | 199 | ||
268 | 200 | ||
269 | void ScaGroupFreeList( | ||
270 | __in SCA_GROUP* psgList | ||
271 | ) | ||
272 | { | ||
273 | SCA_GROUP* psgDelete = psgList; | ||
274 | while (psgList) | ||
275 | { | ||
276 | psgDelete = psgList; | ||
277 | psgList = psgList->psgNext; | ||
278 | |||
279 | MemFree(psgDelete); | ||
280 | } | ||
281 | } | ||
282 | |||
283 | |||
284 | HRESULT ScaUserRead( | 201 | HRESULT ScaUserRead( |
285 | __out SCA_USER** ppsuList | 202 | __out SCA_USER** ppsuList |
286 | ) | 203 | ) |
diff --git a/src/ext/Util/ca/scauser.h b/src/ext/Util/ca/scauser.h index 3da847b5..de690086 100644 --- a/src/ext/Util/ca/scauser.h +++ b/src/ext/Util/ca/scauser.h | |||
@@ -1,6 +1,6 @@ | |||
1 | #pragma once | 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. | 2 | // Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. |
3 | 3 | #include "scagroup.h" | |
4 | 4 | ||
5 | enum USER_EXISTS | 5 | enum USER_EXISTS |
6 | { | 6 | { |
@@ -9,17 +9,6 @@ enum USER_EXISTS | |||
9 | USER_EXISTS_INDETERMINATE | 9 | USER_EXISTS_INDETERMINATE |
10 | }; | 10 | }; |
11 | 11 | ||
12 | // structs | ||
13 | struct SCA_GROUP | ||
14 | { | ||
15 | WCHAR wzKey[MAX_DARWIN_KEY + 1]; | ||
16 | WCHAR wzComponent[MAX_DARWIN_KEY + 1]; | ||
17 | |||
18 | WCHAR wzDomain[MAX_DARWIN_COLUMN + 1]; | ||
19 | WCHAR wzName[MAX_DARWIN_COLUMN + 1]; | ||
20 | |||
21 | SCA_GROUP *psgNext; | ||
22 | }; | ||
23 | 12 | ||
24 | struct SCA_USER | 13 | struct SCA_USER |
25 | { | 14 | { |
@@ -50,16 +39,9 @@ HRESULT __stdcall ScaGetUserDeferred( | |||
50 | __in WCA_WRAPQUERY_HANDLE hUserQuery, | 39 | __in WCA_WRAPQUERY_HANDLE hUserQuery, |
51 | __out SCA_USER* pscau | 40 | __out SCA_USER* pscau |
52 | ); | 41 | ); |
53 | HRESULT __stdcall ScaGetGroup( | ||
54 | __in LPCWSTR wzGroup, | ||
55 | __out SCA_GROUP* pscag | ||
56 | ); | ||
57 | void ScaUserFreeList( | 42 | void ScaUserFreeList( |
58 | __in SCA_USER* psuList | 43 | __in SCA_USER* psuList |
59 | ); | 44 | ); |
60 | void ScaGroupFreeList( | ||
61 | __in SCA_GROUP* psgList | ||
62 | ); | ||
63 | HRESULT ScaUserRead( | 45 | HRESULT ScaUserRead( |
64 | __inout SCA_USER** ppsuList | 46 | __inout SCA_USER** ppsuList |
65 | ); | 47 | ); |
diff --git a/src/ext/Util/ca/utilca.def b/src/ext/Util/ca/utilca.def index 96545566..18a19d12 100644 --- a/src/ext/Util/ca/utilca.def +++ b/src/ext/Util/ca/utilca.def | |||
@@ -43,6 +43,9 @@ EXPORTS | |||
43 | UnregisterPerfmon | 43 | UnregisterPerfmon |
44 | CreateSmb | 44 | CreateSmb |
45 | DropSmb | 45 | DropSmb |
46 | CreateGroup | ||
47 | CreateGroupRollback | ||
48 | RemoveGroup | ||
46 | CreateUser | 49 | CreateUser |
47 | CreateUserRollback | 50 | CreateUserRollback |
48 | RemoveUser | 51 | RemoveUser |
@@ -51,6 +54,7 @@ EXPORTS | |||
51 | ConfigurePerfmonUninstall | 54 | ConfigurePerfmonUninstall |
52 | ConfigureSmbInstall | 55 | ConfigureSmbInstall |
53 | ConfigureSmbUninstall | 56 | ConfigureSmbUninstall |
57 | ConfigureGroups | ||
54 | ConfigureUsers | 58 | ConfigureUsers |
55 | InstallPerfCounterData | 59 | InstallPerfCounterData |
56 | UninstallPerfCounterData | 60 | UninstallPerfCounterData |
diff --git a/src/ext/Util/ca/utilca.vcxproj b/src/ext/Util/ca/utilca.vcxproj index 758f075c..5dbe2792 100644 --- a/src/ext/Util/ca/utilca.vcxproj +++ b/src/ext/Util/ca/utilca.vcxproj | |||
@@ -61,7 +61,9 @@ | |||
61 | <ClCompile Include="RemoveRegistryKeysEx.cpp" /> | 61 | <ClCompile Include="RemoveRegistryKeysEx.cpp" /> |
62 | <ClCompile Include="RestartManager.cpp" /> | 62 | <ClCompile Include="RestartManager.cpp" /> |
63 | <ClCompile Include="scaexec.cpp" /> | 63 | <ClCompile Include="scaexec.cpp" /> |
64 | <ClCompile Include="scagroup.cpp" /> | ||
64 | <ClCompile Include="scamanifest.cpp" /> | 65 | <ClCompile Include="scamanifest.cpp" /> |
66 | <ClCompile Include="scanet.cpp" /> | ||
65 | <ClCompile Include="scaperf.cpp" /> | 67 | <ClCompile Include="scaperf.cpp" /> |
66 | <ClCompile Include="scaperfexec.cpp" /> | 68 | <ClCompile Include="scaperfexec.cpp" /> |
67 | <ClCompile Include="scasched.cpp" /> | 69 | <ClCompile Include="scasched.cpp" /> |
@@ -84,6 +86,8 @@ | |||
84 | <ClInclude Include="precomp.h" /> | 86 | <ClInclude Include="precomp.h" /> |
85 | <ClInclude Include="sca.h" /> | 87 | <ClInclude Include="sca.h" /> |
86 | <ClInclude Include="scacost.h" /> | 88 | <ClInclude Include="scacost.h" /> |
89 | <ClInclude Include="scagroup.h" /> | ||
90 | <ClInclude Include="scanet.h" /> | ||
87 | <ClInclude Include="scasmb.h" /> | 91 | <ClInclude Include="scasmb.h" /> |
88 | <ClInclude Include="scasmbexec.h" /> | 92 | <ClInclude Include="scasmbexec.h" /> |
89 | <ClInclude Include="scauser.h" /> | 93 | <ClInclude Include="scauser.h" /> |