aboutsummaryrefslogtreecommitdiff
path: root/src/ca/scaexec.cpp
diff options
context:
space:
mode:
authorSean Hall <r.sean.hall@gmail.com>2018-12-15 21:46:30 -0600
committerGitHub <noreply@github.com>2018-12-15 21:46:30 -0600
commitf7020c0d16baf2b960e7123e233e20c519f6a340 (patch)
treed2cd464ee15b2b3f304ff780c531b39bb292d331 /src/ca/scaexec.cpp
parent6ed8d107e6edf16956c778bda3573f8d7a7690fc (diff)
downloadwix-f7020c0d16baf2b960e7123e233e20c519f6a340.tar.gz
wix-f7020c0d16baf2b960e7123e233e20c519f6a340.tar.bz2
wix-f7020c0d16baf2b960e7123e233e20c519f6a340.zip
Import implementation of UtilCA from old repo's WixCA/scasched/scaexec. (#3)
Diffstat (limited to 'src/ca/scaexec.cpp')
-rw-r--r--src/ca/scaexec.cpp807
1 files changed, 807 insertions, 0 deletions
diff --git a/src/ca/scaexec.cpp b/src/ca/scaexec.cpp
new file mode 100644
index 00000000..ab9e6599
--- /dev/null
+++ b/src/ca/scaexec.cpp
@@ -0,0 +1,807 @@
1// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
3#include "precomp.h"
4
5
6/********************************************************************
7 * CreateSmb - CUSTOM ACTION ENTRY POINT for creating fileshares
8 *
9 * Input: deferred CustomActionData -
10 * wzFsKey\twzShareDesc\twzFullPath\tfIntegratedAuth\twzUserName\tnPermissions\twzUserName\tnPermissions...
11 *
12 * ****************************************************************/
13extern "C" UINT __stdcall CreateSmb(MSIHANDLE hInstall)
14{
15//AssertSz(0, "debug CreateSmb");
16 UINT er = ERROR_SUCCESS;
17 HRESULT hr = S_OK;
18
19 LPWSTR pwzData = NULL;
20 LPWSTR pwz = NULL;
21 LPWSTR pwzFsKey = NULL;
22 LPWSTR pwzShareDesc = NULL;
23 LPWSTR pwzDirectory = NULL;
24 int iAccessMode = 0;
25 DWORD nExPermissions = 0;
26 BOOL fIntegratedAuth;
27 LPWSTR pwzExUser = NULL;
28 SCA_SMBP ssp = {0};
29 DWORD dwExUserPerms = 0;
30 DWORD dwCounter = 0;
31 SCA_SMBP_USER_PERMS* pUserPermsList = NULL;
32
33 hr = WcaInitialize(hInstall, "CreateSmb");
34 ExitOnFailure(hr, "failed to initialize");
35
36 hr = WcaGetProperty( L"CustomActionData", &pwzData);
37 ExitOnFailure(hr, "failed to get CustomActionData");
38
39 WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %ls", pwzData);
40
41 pwz = pwzData;
42 hr = WcaReadStringFromCaData(&pwz, &pwzFsKey); // share name
43 ExitOnFailure(hr, "failed to read share name");
44 hr = WcaReadStringFromCaData(&pwz, &pwzShareDesc); // share description
45 ExitOnFailure(hr, "failed to read share name");
46 hr = WcaReadStringFromCaData(&pwz, &pwzDirectory); // full path to share
47 ExitOnFailure(hr, "failed to read share name");
48 hr = WcaReadIntegerFromCaData(&pwz, reinterpret_cast<int *>(&fIntegratedAuth));
49 ExitOnFailure(hr, "failed to read integrated authentication");
50
51 hr = WcaReadIntegerFromCaData(&pwz, reinterpret_cast<int *>(&dwExUserPerms));
52 ExitOnFailure(hr, "failed to read count of permissions to set");
53 if(dwExUserPerms > 0)
54 {
55 pUserPermsList = static_cast<SCA_SMBP_USER_PERMS*>(MemAlloc(sizeof(SCA_SMBP_USER_PERMS)*dwExUserPerms, TRUE));
56 ExitOnNull(pUserPermsList, hr, E_OUTOFMEMORY, "failed to allocate memory for permissions structure");
57
58 //Pull out all of the ExUserPerm strings
59 for (dwCounter = 0; dwCounter < dwExUserPerms; ++dwCounter)
60 {
61 hr = WcaReadStringFromCaData(&pwz, &pwzExUser); // user account
62 ExitOnFailure(hr, "failed to read user account");
63 pUserPermsList[dwCounter].wzUser = pwzExUser;
64 pwzExUser = NULL;
65
66 hr = WcaReadIntegerFromCaData(&pwz, &iAccessMode);
67 ExitOnFailure(hr, "failed to read access mode");
68 pUserPermsList[dwCounter].accessMode = (ACCESS_MODE)iAccessMode;
69 iAccessMode = 0;
70
71 hr = WcaReadIntegerFromCaData(&pwz, reinterpret_cast<int *>(&nExPermissions));
72 ExitOnFailure(hr, "failed to read count of permissions");
73 pUserPermsList[dwCounter].nPermissions = nExPermissions;
74 nExPermissions = 0;
75 }
76 }
77
78 ssp.wzKey = pwzFsKey;
79 ssp.wzDescription = pwzShareDesc;
80 ssp.wzDirectory = pwzDirectory;
81 ssp.fUseIntegratedAuth = fIntegratedAuth;
82 ssp.dwUserPermissionCount = dwExUserPerms;
83 ssp.pUserPerms = pUserPermsList;
84
85 hr = ScaEnsureSmbExists(&ssp);
86 MessageExitOnFailure(hr, msierrSMBFailedCreate, "failed to create share: '%ls'", pwzFsKey);
87
88 hr = WcaProgressMessage(COST_SMB_CREATESMB, FALSE);
89
90LExit:
91 ReleaseStr(pwzFsKey);
92 ReleaseStr(pwzShareDesc);
93 ReleaseStr(pwzDirectory);
94 ReleaseStr(pwzData);
95
96 if (pUserPermsList)
97 {
98 MemFree(pUserPermsList);
99 }
100
101 if (FAILED(hr))
102 {
103 er = ERROR_INSTALL_FAILURE;
104 }
105 return WcaFinalize(er);
106}
107
108
109
110/********************************************************************
111 DropSmb - CUSTOM ACTION ENTRY POINT for creating fileshares
112
113 Input: deferred CustomActionData - wzFsKey\twzShareDesc\twzFullPath\tnPermissions\tfIntegratedAuth\twzUserName\twzPassword
114
115 * ****************************************************************/
116extern "C" UINT __stdcall DropSmb(MSIHANDLE hInstall)
117{
118 //AssertSz(0, "debug DropSmb");
119 UINT er = ERROR_SUCCESS;
120 HRESULT hr = S_OK;
121
122 LPWSTR pwzData = NULL;
123 LPWSTR pwz = NULL;
124 LPWSTR pwzFsKey = NULL;
125 SCA_SMBP ssp = {0};
126
127 hr = WcaInitialize(hInstall, "DropSmb");
128 ExitOnFailure(hr, "failed to initialize");
129
130 hr = WcaGetProperty( L"CustomActionData", &pwzData);
131 ExitOnFailure(hr, "failed to get CustomActionData");
132
133 WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %ls", pwzData);
134
135 pwz = pwzData;
136 hr = WcaReadStringFromCaData(&pwz, &pwzFsKey); // share name
137 ExitOnFailure(hr, "failed to read share name");
138
139 ssp.wzKey = pwzFsKey;
140
141 hr = ScaDropSmb(&ssp);
142 MessageExitOnFailure(hr, msierrSMBFailedDrop, "failed to delete share: '%ls'", pwzFsKey);
143
144 hr = WcaProgressMessage(COST_SMB_DROPSMB, FALSE);
145
146LExit:
147 ReleaseStr(pwzFsKey);
148 ReleaseStr(pwzData);
149
150 if (FAILED(hr))
151 {
152 er = ERROR_INSTALL_FAILURE;
153 }
154 return WcaFinalize(er);
155}
156
157
158static HRESULT AddUserToGroup(
159 __in LPWSTR wzUser,
160 __in LPCWSTR wzUserDomain,
161 __in LPCWSTR wzGroup,
162 __in LPCWSTR wzGroupDomain
163 )
164{
165 Assert(wzUser && *wzUser && wzUserDomain && wzGroup && *wzGroup && wzGroupDomain);
166
167 HRESULT hr = S_OK;
168 IADsGroup *pGroup = NULL;
169 BSTR bstrUser = NULL;
170 BSTR bstrGroup = NULL;
171 LPCWSTR wz = NULL;
172 LPWSTR pwzUser = NULL;
173 LOCALGROUP_MEMBERS_INFO_3 lgmi;
174
175 if (*wzGroupDomain)
176 {
177 wz = wzGroupDomain;
178 }
179
180 // Try adding it to the global group first
181 UINT ui = ::NetGroupAddUser(wz, wzGroup, wzUser);
182 if (NERR_GroupNotFound == ui)
183 {
184 // Try adding it to the local group
185 if (wzUserDomain)
186 {
187 hr = StrAllocFormatted(&pwzUser, L"%s\\%s", wzUserDomain, wzUser);
188 ExitOnFailure(hr, "failed to allocate user domain string");
189 }
190
191 lgmi.lgrmi3_domainandname = (NULL == pwzUser ? wzUser : pwzUser);
192 ui = ::NetLocalGroupAddMembers(wz, wzGroup, 3 , reinterpret_cast<LPBYTE>(&lgmi), 1);
193 }
194 hr = HRESULT_FROM_WIN32(ui);
195 if (HRESULT_FROM_WIN32(ERROR_MEMBER_IN_ALIAS) == hr) // if they're already a member of the group don't report an error
196 hr = S_OK;
197
198 //
199 // If we failed, try active directory
200 //
201 if (FAILED(hr))
202 {
203 WcaLog(LOGMSG_VERBOSE, "Failed to add user: %ls, domain %ls to group: %ls, domain: %ls with error 0x%x. Attempting to use Active Directory", wzUser, wzUserDomain, wzGroup, wzGroupDomain, hr);
204
205 hr = UserCreateADsPath(wzUserDomain, wzUser, &bstrUser);
206 ExitOnFailure(hr, "failed to create user ADsPath for user: %ls domain: %ls", wzUser, wzUserDomain);
207
208 hr = UserCreateADsPath(wzGroupDomain, wzGroup, &bstrGroup);
209 ExitOnFailure(hr, "failed to create group ADsPath for group: %ls domain: %ls", wzGroup, wzGroupDomain);
210
211 hr = ::ADsGetObject(bstrGroup,IID_IADsGroup, reinterpret_cast<void**>(&pGroup));
212 ExitOnFailure(hr, "Failed to get group '%ls'.", reinterpret_cast<WCHAR*>(bstrGroup) );
213
214 hr = pGroup->Add(bstrUser);
215 if ((HRESULT_FROM_WIN32(ERROR_OBJECT_ALREADY_EXISTS) == hr) || (HRESULT_FROM_WIN32(ERROR_MEMBER_IN_ALIAS) == hr))
216 hr = S_OK;
217
218 ExitOnFailure(hr, "Failed to add user %ls to group '%ls'.", reinterpret_cast<WCHAR*>(bstrUser), reinterpret_cast<WCHAR*>(bstrGroup) );
219 }
220
221LExit:
222 ReleaseObject(pGroup);
223 ReleaseBSTR(bstrUser);
224 ReleaseBSTR(bstrGroup);
225
226 return hr;
227}
228
229static HRESULT RemoveUserFromGroup(
230 __in LPWSTR wzUser,
231 __in LPCWSTR wzUserDomain,
232 __in LPCWSTR wzGroup,
233 __in LPCWSTR wzGroupDomain
234 )
235{
236 Assert(wzUser && *wzUser && wzUserDomain && wzGroup && *wzGroup && wzGroupDomain);
237
238 HRESULT hr = S_OK;
239 IADsGroup *pGroup = NULL;
240 BSTR bstrUser = NULL;
241 BSTR bstrGroup = NULL;
242 LPCWSTR wz = NULL;
243 LPWSTR pwzUser = NULL;
244 LOCALGROUP_MEMBERS_INFO_3 lgmi;
245
246 if (*wzGroupDomain)
247 {
248 wz = wzGroupDomain;
249 }
250
251 // Try removing it from the global group first
252 UINT ui = ::NetGroupDelUser(wz, wzGroup, wzUser);
253 if (NERR_GroupNotFound == ui)
254 {
255 // Try removing it from the local group
256 if (wzUserDomain)
257 {
258 hr = StrAllocFormatted(&pwzUser, L"%s\\%s", wzUserDomain, wzUser);
259 ExitOnFailure(hr, "failed to allocate user domain string");
260 }
261
262 lgmi.lgrmi3_domainandname = (NULL == pwzUser ? wzUser : pwzUser);
263 ui = ::NetLocalGroupDelMembers(wz, wzGroup, 3 , reinterpret_cast<LPBYTE>(&lgmi), 1);
264 }
265 hr = HRESULT_FROM_WIN32(ui);
266
267 //
268 // If we failed, try active directory
269 //
270 if (FAILED(hr))
271 {
272 WcaLog(LOGMSG_VERBOSE, "Failed to remove user: %ls, domain %ls from group: %ls, domain: %ls with error 0x%x. Attempting to use Active Directory", wzUser, wzUserDomain, wzGroup, wzGroupDomain, hr);
273
274 hr = UserCreateADsPath(wzUserDomain, wzUser, &bstrUser);
275 ExitOnFailure(hr, "failed to create user ADsPath in order to remove user: %ls domain: %ls from a group", wzUser, wzUserDomain);
276
277 hr = UserCreateADsPath(wzGroupDomain, wzGroup, &bstrGroup);
278 ExitOnFailure(hr, "failed to create group ADsPath in order to remove user from group: %ls domain: %ls", wzGroup, wzGroupDomain);
279
280 hr = ::ADsGetObject(bstrGroup,IID_IADsGroup, reinterpret_cast<void**>(&pGroup));
281 ExitOnFailure(hr, "Failed to get group '%ls'.", reinterpret_cast<WCHAR*>(bstrGroup) );
282
283 hr = pGroup->Remove(bstrUser);
284 ExitOnFailure(hr, "Failed to remove user %ls from group '%ls'.", reinterpret_cast<WCHAR*>(bstrUser), reinterpret_cast<WCHAR*>(bstrGroup) );
285 }
286
287LExit:
288 ReleaseObject(pGroup);
289 ReleaseBSTR(bstrUser);
290 ReleaseBSTR(bstrGroup);
291
292 return hr;
293}
294
295
296static HRESULT ModifyUserLocalServiceRight(
297 __in_opt LPCWSTR wzDomain,
298 __in LPCWSTR wzName,
299 __in BOOL fAdd
300 )
301{
302 HRESULT hr = S_OK;
303 NTSTATUS nt = 0;
304
305 LPWSTR pwzUser = NULL;
306 PSID psid = NULL;
307 LSA_HANDLE hPolicy = NULL;
308 LSA_OBJECT_ATTRIBUTES ObjectAttributes = { 0 };
309 LSA_UNICODE_STRING lucPrivilege = { 0 };
310
311 if (wzDomain && *wzDomain)
312 {
313 hr = StrAllocFormatted(&pwzUser, L"%s\\%s", wzDomain, wzName);
314 ExitOnFailure(hr, "Failed to allocate user with domain string");
315 }
316 else
317 {
318 hr = StrAllocString(&pwzUser, wzName, 0);
319 ExitOnFailure(hr, "Failed to allocate string from user name.");
320 }
321
322 hr = AclGetAccountSid(NULL, pwzUser, &psid);
323 ExitOnFailure(hr, "Failed to get SID for user: %ls", pwzUser);
324
325 nt = ::LsaOpenPolicy(NULL, &ObjectAttributes, POLICY_ALL_ACCESS, &hPolicy);
326 hr = HRESULT_FROM_WIN32(::LsaNtStatusToWinError(nt));
327 ExitOnFailure(hr, "Failed to open LSA policy store.");
328
329 lucPrivilege.Buffer = L"SeServiceLogonRight";
330 lucPrivilege.Length = static_cast<USHORT>(lstrlenW(lucPrivilege.Buffer) * sizeof(WCHAR));
331 lucPrivilege.MaximumLength = (lucPrivilege.Length + 1) * sizeof(WCHAR);
332
333 if (fAdd)
334 {
335 nt = ::LsaAddAccountRights(hPolicy, psid, &lucPrivilege, 1);
336 hr = HRESULT_FROM_WIN32(::LsaNtStatusToWinError(nt));
337 ExitOnFailure(hr, "Failed to add 'logon as service' bit to user: %ls", pwzUser);
338 }
339 else
340 {
341 nt = ::LsaRemoveAccountRights(hPolicy, psid, FALSE, &lucPrivilege, 1);
342 hr = HRESULT_FROM_WIN32(::LsaNtStatusToWinError(nt));
343 ExitOnFailure(hr, "Failed to remove 'logon as service' bit from user: %ls", pwzUser);
344 }
345
346LExit:
347 if (hPolicy)
348 {
349 ::LsaClose(hPolicy);
350 }
351
352 ReleaseSid(psid);
353 ReleaseStr(pwzUser);
354 return hr;
355}
356
357
358static HRESULT ModifyUserLocalBatchRight(
359 __in_opt LPCWSTR wzDomain,
360 __in LPCWSTR wzName,
361 __in BOOL fAdd
362 )
363{
364 HRESULT hr = S_OK;
365 NTSTATUS nt = 0;
366
367 LPWSTR pwzUser = NULL;
368 PSID psid = NULL;
369 LSA_HANDLE hPolicy = NULL;
370 LSA_OBJECT_ATTRIBUTES ObjectAttributes = { 0 };
371 LSA_UNICODE_STRING lucPrivilege = { 0 };
372
373 if (wzDomain && *wzDomain)
374 {
375 hr = StrAllocFormatted(&pwzUser, L"%s\\%s", wzDomain, wzName);
376 ExitOnFailure(hr, "Failed to allocate user with domain string");
377 }
378 else
379 {
380 hr = StrAllocString(&pwzUser, wzName, 0);
381 ExitOnFailure(hr, "Failed to allocate string from user name.");
382 }
383
384 hr = AclGetAccountSid(NULL, pwzUser, &psid);
385 ExitOnFailure(hr, "Failed to get SID for user: %ls", pwzUser);
386
387 nt = ::LsaOpenPolicy(NULL, &ObjectAttributes, POLICY_ALL_ACCESS, &hPolicy);
388 hr = HRESULT_FROM_WIN32(::LsaNtStatusToWinError(nt));
389 ExitOnFailure(hr, "Failed to open LSA policy store.");
390
391 lucPrivilege.Buffer = L"SeBatchLogonRight";
392 lucPrivilege.Length = static_cast<USHORT>(lstrlenW(lucPrivilege.Buffer) * sizeof(WCHAR));
393 lucPrivilege.MaximumLength = (lucPrivilege.Length + 1) * sizeof(WCHAR);
394
395 if (fAdd)
396 {
397 nt = ::LsaAddAccountRights(hPolicy, psid, &lucPrivilege, 1);
398 hr = HRESULT_FROM_WIN32(::LsaNtStatusToWinError(nt));
399 ExitOnFailure(hr, "Failed to add 'logon as batch job' bit to user: %ls", pwzUser);
400 }
401 else
402 {
403 nt = ::LsaRemoveAccountRights(hPolicy, psid, FALSE, &lucPrivilege, 1);
404 hr = HRESULT_FROM_WIN32(::LsaNtStatusToWinError(nt));
405 ExitOnFailure(hr, "Failed to remove 'logon as batch job' bit from user: %ls", pwzUser);
406 }
407
408 LExit:
409 if (hPolicy)
410 {
411 ::LsaClose(hPolicy);
412 }
413
414 ReleaseSid(psid);
415 ReleaseStr(pwzUser);
416 return hr;
417}
418
419static void SetUserPasswordAndAttributes(
420 __in USER_INFO_1* puserInfo,
421 __in LPWSTR wzPassword,
422 __in int iAttributes
423 )
424{
425 Assert(puserInfo);
426
427 // Set the User's password
428 puserInfo->usri1_password = wzPassword;
429
430 // Apply the Attributes
431 if (SCAU_DONT_EXPIRE_PASSWRD & iAttributes)
432 {
433 puserInfo->usri1_flags |= UF_DONT_EXPIRE_PASSWD;
434 }
435 else
436 {
437 puserInfo->usri1_flags &= ~UF_DONT_EXPIRE_PASSWD;
438 }
439
440 if (SCAU_PASSWD_CANT_CHANGE & iAttributes)
441 {
442 puserInfo->usri1_flags |= UF_PASSWD_CANT_CHANGE;
443 }
444 else
445 {
446 puserInfo->usri1_flags &= ~UF_PASSWD_CANT_CHANGE;
447 }
448
449 if (SCAU_DISABLE_ACCOUNT & iAttributes)
450 {
451 puserInfo->usri1_flags |= UF_ACCOUNTDISABLE;
452 }
453 else
454 {
455 puserInfo->usri1_flags &= ~UF_ACCOUNTDISABLE;
456 }
457
458 if (SCAU_PASSWD_CHANGE_REQD_ON_LOGIN & iAttributes) // TODO: for some reason this doesn't work
459 {
460 puserInfo->usri1_flags |= UF_PASSWORD_EXPIRED;
461 }
462 else
463 {
464 puserInfo->usri1_flags &= ~UF_PASSWORD_EXPIRED;
465 }
466}
467
468
469/********************************************************************
470 CreateUser - CUSTOM ACTION ENTRY POINT for creating users
471
472 Input: deferred CustomActionData - UserName\tDomain\tPassword\tAttributes\tGroupName\tDomain\tGroupName\tDomain...
473 * *****************************************************************/
474extern "C" UINT __stdcall CreateUser(
475 __in MSIHANDLE hInstall
476 )
477{
478 //AssertSz(0, "Debug CreateUser");
479
480 HRESULT hr = S_OK;
481 UINT er = ERROR_SUCCESS;
482
483 LPWSTR pwzData = NULL;
484 LPWSTR pwz = NULL;
485 LPWSTR pwzName = NULL;
486 LPWSTR pwzDomain = NULL;
487 LPWSTR pwzPassword = NULL;
488 LPWSTR pwzGroup = NULL;
489 LPWSTR pwzGroupDomain = NULL;
490 PDOMAIN_CONTROLLER_INFOW pDomainControllerInfo = NULL;
491 int iAttributes = 0;
492 BOOL fInitializedCom = FALSE;
493
494 USER_INFO_1 userInfo;
495 USER_INFO_1* puserInfo = NULL;
496 DWORD dw;
497 LPCWSTR wz = NULL;
498
499 hr = WcaInitialize(hInstall, "CreateUser");
500 ExitOnFailure(hr, "failed to initialize");
501
502 hr = ::CoInitialize(NULL);
503 ExitOnFailure(hr, "failed to initialize COM");
504 fInitializedCom = TRUE;
505
506 hr = WcaGetProperty( L"CustomActionData", &pwzData);
507 ExitOnFailure(hr, "failed to get CustomActionData");
508
509 WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %ls", pwzData);
510
511 //
512 // Read in the CustomActionData
513 //
514 pwz = pwzData;
515 hr = WcaReadStringFromCaData(&pwz, &pwzName);
516 ExitOnFailure(hr, "failed to read user name from custom action data");
517
518 hr = WcaReadStringFromCaData(&pwz, &pwzDomain);
519 ExitOnFailure(hr, "failed to read domain from custom action data");
520
521 hr = WcaReadIntegerFromCaData(&pwz, &iAttributes);
522 ExitOnFailure(hr, "failed to read attributes from custom action data");
523
524 hr = WcaReadStringFromCaData(&pwz, &pwzPassword);
525 ExitOnFailure(hr, "failed to read password from custom action data");
526
527 if (!(SCAU_DONT_CREATE_USER & iAttributes))
528 {
529 ::ZeroMemory(&userInfo, sizeof(USER_INFO_1));
530 userInfo.usri1_name = pwzName;
531 userInfo.usri1_priv = USER_PRIV_USER;
532 userInfo.usri1_flags = UF_SCRIPT;
533 userInfo.usri1_home_dir = NULL;
534 userInfo.usri1_comment = NULL;
535 userInfo.usri1_script_path = NULL;
536
537 SetUserPasswordAndAttributes(&userInfo, pwzPassword, iAttributes);
538
539 //
540 // Create the User
541 //
542 if (pwzDomain && *pwzDomain)
543 {
544 er = ::DsGetDcNameW( NULL, (LPCWSTR)pwzDomain, NULL, NULL, NULL, &pDomainControllerInfo );
545 if (RPC_S_SERVER_UNAVAILABLE == er)
546 {
547 // MSDN says, if we get the above error code, try again with the "DS_FORCE_REDISCOVERY" flag
548 er = ::DsGetDcNameW( NULL, (LPCWSTR)pwzDomain, NULL, NULL, DS_FORCE_REDISCOVERY, &pDomainControllerInfo );
549 }
550 if (ERROR_SUCCESS == er)
551 {
552 wz = pDomainControllerInfo->DomainControllerName + 2; //Add 2 so that we don't get the \\ prefix
553 }
554 else
555 {
556 wz = pwzDomain;
557 }
558 }
559
560 er = ::NetUserAdd(wz, 1, reinterpret_cast<LPBYTE>(&userInfo), &dw);
561 if (NERR_UserExists == er)
562 {
563 if (SCAU_UPDATE_IF_EXISTS & iAttributes)
564 {
565 er = ::NetUserGetInfo(wz, pwzName, 1, reinterpret_cast<LPBYTE*>(&puserInfo));
566 if (NERR_Success == er)
567 {
568 // Change the existing user's password and attributes again then try
569 // to update user with this new data
570 SetUserPasswordAndAttributes(puserInfo, pwzPassword, iAttributes);
571
572 er = ::NetUserSetInfo(wz, pwzName, 1, reinterpret_cast<LPBYTE>(puserInfo), &dw);
573 }
574 }
575 else if (!(SCAU_FAIL_IF_EXISTS & iAttributes))
576 {
577 er = NERR_Success;
578 }
579 }
580 else if (NERR_PasswordTooShort == er || NERR_PasswordTooLong == er)
581 {
582 MessageExitOnFailure(hr = HRESULT_FROM_WIN32(er), msierrUSRFailedUserCreatePswd, "failed to create user: %ls due to invalid password.", pwzName);
583 }
584 MessageExitOnFailure(hr = HRESULT_FROM_WIN32(er), msierrUSRFailedUserCreate, "failed to create user: %ls", pwzName);
585 }
586
587 if (SCAU_ALLOW_LOGON_AS_SERVICE & iAttributes)
588 {
589 hr = ModifyUserLocalServiceRight(pwzDomain, pwzName, TRUE);
590 MessageExitOnFailure(hr, msierrUSRFailedGrantLogonAsService, "Failed to grant logon as service rights to user: %ls", pwzName);
591 }
592
593 if (SCAU_ALLOW_LOGON_AS_BATCH & iAttributes)
594 {
595 hr = ModifyUserLocalBatchRight(pwzDomain, pwzName, TRUE);
596 MessageExitOnFailure(hr, msierrUSRFailedGrantLogonAsService, "Failed to grant logon as batch job rights to user: %ls", pwzName);
597 }
598
599 //
600 // Add the users to groups
601 //
602 while (S_OK == (hr = WcaReadStringFromCaData(&pwz, &pwzGroup)))
603 {
604 hr = WcaReadStringFromCaData(&pwz, &pwzGroupDomain);
605 ExitOnFailure(hr, "failed to get domain for group: %ls", pwzGroup);
606
607 hr = AddUserToGroup(pwzName, pwzDomain, pwzGroup, pwzGroupDomain);
608 MessageExitOnFailure(hr, msierrUSRFailedUserGroupAdd, "failed to add user: %ls to group %ls", pwzName, pwzGroup);
609 }
610 if (E_NOMOREITEMS == hr) // if there are no more items, all is well
611 {
612 hr = S_OK;
613 }
614 ExitOnFailure(hr, "failed to get next group in which to include user:%ls", pwzName);
615
616LExit:
617 if (puserInfo)
618 {
619 ::NetApiBufferFree((LPVOID)puserInfo);
620 }
621
622 if (pDomainControllerInfo)
623 {
624 ::NetApiBufferFree((LPVOID)pDomainControllerInfo);
625 }
626
627 ReleaseStr(pwzData);
628 ReleaseStr(pwzName);
629 ReleaseStr(pwzDomain);
630 ReleaseStr(pwzPassword);
631 ReleaseStr(pwzGroup);
632 ReleaseStr(pwzGroupDomain);
633
634 if (fInitializedCom)
635 {
636 ::CoUninitialize();
637 }
638
639 if (SCAU_NON_VITAL & iAttributes)
640 {
641 er = ERROR_SUCCESS;
642 }
643 else if (FAILED(hr))
644 {
645 er = ERROR_INSTALL_FAILURE;
646 }
647
648 return WcaFinalize(er);
649}
650
651
652/********************************************************************
653 RemoveUser - CUSTOM ACTION ENTRY POINT for removing users
654
655 Input: deferred CustomActionData - Name\tDomain
656 * *****************************************************************/
657extern "C" UINT __stdcall RemoveUser(
658 MSIHANDLE hInstall
659 )
660{
661 //AssertSz(0, "Debug RemoveAccount");
662
663 HRESULT hr = S_OK;
664 UINT er = ERROR_SUCCESS;
665
666 LPWSTR pwzData = NULL;
667 LPWSTR pwz = NULL;
668 LPWSTR pwzName = NULL;
669 LPWSTR pwzDomain= NULL;
670 LPWSTR pwzGroup = NULL;
671 LPWSTR pwzGroupDomain = NULL;
672 int iAttributes = 0;
673 LPCWSTR wz = NULL;
674 PDOMAIN_CONTROLLER_INFOW pDomainControllerInfo = NULL;
675 BOOL fInitializedCom = FALSE;
676
677 hr = WcaInitialize(hInstall, "RemoveUser");
678 ExitOnFailure(hr, "failed to initialize");
679
680 hr = ::CoInitialize(NULL);
681 ExitOnFailure(hr, "failed to initialize COM");
682 fInitializedCom = TRUE;
683
684 hr = WcaGetProperty(L"CustomActionData", &pwzData);
685 ExitOnFailure(hr, "failed to get CustomActionData");
686
687 WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %ls", pwzData);
688
689 //
690 // Read in the CustomActionData
691 //
692 pwz = pwzData;
693 hr = WcaReadStringFromCaData(&pwz, &pwzName);
694 ExitOnFailure(hr, "failed to read name from custom action data");
695
696 hr = WcaReadStringFromCaData(&pwz, &pwzDomain);
697 ExitOnFailure(hr, "failed to read domain from custom action data");
698
699 hr = WcaReadIntegerFromCaData(&pwz, &iAttributes);
700 ExitOnFailure(hr, "failed to read attributes from custom action data");
701
702 //
703 // Remove the logon as service privilege.
704 //
705 if (SCAU_ALLOW_LOGON_AS_SERVICE & iAttributes)
706 {
707 hr = ModifyUserLocalServiceRight(pwzDomain, pwzName, FALSE);
708 if (FAILED(hr))
709 {
710 WcaLogError(hr, "Failed to remove logon as service right from user, continuing...");
711 hr = S_OK;
712 }
713 }
714
715 if (SCAU_ALLOW_LOGON_AS_BATCH & iAttributes)
716 {
717 hr = ModifyUserLocalBatchRight(pwzDomain, pwzName, FALSE);
718 if (FAILED(hr))
719 {
720 WcaLogError(hr, "Failed to remove logon as batch job right from user, continuing...");
721 hr = S_OK;
722 }
723 }
724
725 //
726 // Remove the User Account if the user was created by us.
727 //
728 if (!(SCAU_DONT_CREATE_USER & iAttributes))
729 {
730 if (pwzDomain && *pwzDomain)
731 {
732 er = ::DsGetDcNameW( NULL, (LPCWSTR)pwzDomain, NULL, NULL, NULL, &pDomainControllerInfo );
733 if (RPC_S_SERVER_UNAVAILABLE == er)
734 {
735 // MSDN says, if we get the above error code, try again with the "DS_FORCE_REDISCOVERY" flag
736 er = ::DsGetDcNameW( NULL, (LPCWSTR)pwzDomain, NULL, NULL, DS_FORCE_REDISCOVERY, &pDomainControllerInfo );
737 }
738 if (ERROR_SUCCESS == er)
739 {
740 wz = pDomainControllerInfo->DomainControllerName + 2; //Add 2 so that we don't get the \\ prefix
741 }
742 else
743 {
744 wz = pwzDomain;
745 }
746 }
747
748 er = ::NetUserDel(wz, pwzName);
749 if (NERR_UserNotFound == er)
750 {
751 er = NERR_Success;
752 }
753 ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "failed to delete user account: %ls", pwzName);
754 }
755 else
756 {
757 //
758 // Remove the user from the groups
759 //
760 while (S_OK == (hr = WcaReadStringFromCaData(&pwz, &pwzGroup)))
761 {
762 hr = WcaReadStringFromCaData(&pwz, &pwzGroupDomain);
763
764 if (FAILED(hr))
765 {
766 WcaLogError(hr, "failed to get domain for group: %ls, continuing anyway.", pwzGroup);
767 }
768 else
769 {
770 hr = RemoveUserFromGroup(pwzName, pwzDomain, pwzGroup, pwzGroupDomain);
771 if (FAILED(hr))
772 {
773 WcaLogError(hr, "failed to remove user: %ls from group %ls, continuing anyway.", pwzName, pwzGroup);
774 }
775 }
776 }
777
778 if (E_NOMOREITEMS == hr) // if there are no more items, all is well
779 {
780 hr = S_OK;
781 }
782
783 ExitOnFailure(hr, "failed to get next group from which to remove user:%ls", pwzName);
784 }
785
786LExit:
787 if (pDomainControllerInfo)
788 {
789 ::NetApiBufferFree(static_cast<LPVOID>(pDomainControllerInfo));
790 }
791
792 ReleaseStr(pwzData);
793 ReleaseStr(pwzName);
794 ReleaseStr(pwzDomain);
795
796 if (fInitializedCom)
797 {
798 ::CoUninitialize();
799 }
800
801 if (FAILED(hr))
802 {
803 er = ERROR_INSTALL_FAILURE;
804 }
805
806 return WcaFinalize(er);
807}