diff options
author | Sean Hall <r.sean.hall@gmail.com> | 2018-12-15 21:46:30 -0600 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-12-15 21:46:30 -0600 |
commit | f7020c0d16baf2b960e7123e233e20c519f6a340 (patch) | |
tree | d2cd464ee15b2b3f304ff780c531b39bb292d331 /src/ca/scaexec.cpp | |
parent | 6ed8d107e6edf16956c778bda3573f8d7a7690fc (diff) | |
download | wix-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.cpp | 807 |
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 | * ****************************************************************/ | ||
13 | extern "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 | |||
90 | LExit: | ||
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 | * ****************************************************************/ | ||
116 | extern "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 | |||
146 | LExit: | ||
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 | |||
158 | static 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 | |||
221 | LExit: | ||
222 | ReleaseObject(pGroup); | ||
223 | ReleaseBSTR(bstrUser); | ||
224 | ReleaseBSTR(bstrGroup); | ||
225 | |||
226 | return hr; | ||
227 | } | ||
228 | |||
229 | static 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 | |||
287 | LExit: | ||
288 | ReleaseObject(pGroup); | ||
289 | ReleaseBSTR(bstrUser); | ||
290 | ReleaseBSTR(bstrGroup); | ||
291 | |||
292 | return hr; | ||
293 | } | ||
294 | |||
295 | |||
296 | static 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 | |||
346 | LExit: | ||
347 | if (hPolicy) | ||
348 | { | ||
349 | ::LsaClose(hPolicy); | ||
350 | } | ||
351 | |||
352 | ReleaseSid(psid); | ||
353 | ReleaseStr(pwzUser); | ||
354 | return hr; | ||
355 | } | ||
356 | |||
357 | |||
358 | static 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 | |||
419 | static 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 | * *****************************************************************/ | ||
474 | extern "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 | |||
616 | LExit: | ||
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 | * *****************************************************************/ | ||
657 | extern "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 | |||
786 | LExit: | ||
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 | } | ||