main
cpp 597 lines 20 KB
Raw
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 Helper functions to maintain a list of file shares to create / remove
8
9 ********************************************************************/
10 SCA_SMB* NewSmb()
11 {
12 SCA_SMB* pss = (SCA_SMB*)MemAlloc(sizeof(SCA_SMB), TRUE);
13 Assert(pss);
14 return pss;
15 }
16
17
18 SCA_SMB_EX_USER_PERMS* NewExUserPermsSmb()
19 {
20 SCA_SMB_EX_USER_PERMS* pExUserPerms = (SCA_SMB_EX_USER_PERMS*)MemAlloc(sizeof(SCA_SMB_EX_USER_PERMS), TRUE);
21 Assert(pExUserPerms);
22 return pExUserPerms;
23 }
24
25
26 SCA_SMB* AddSmbToList(SCA_SMB* pssList, SCA_SMB* pss)
27 {
28 if (pssList)
29 {
30 SCA_SMB* pssT = pssList;
31 while (pssT->pssNext)
32 {
33 pssT = pssT->pssNext;
34 }
35
36 pssT->pssNext = pss;
37 }
38 else
39 {
40 pssList = pss;
41 }
42
43 return pssList;
44 }
45
46
47 SCA_SMB_EX_USER_PERMS* AddExUserPermsSmbToList(
48 SCA_SMB_EX_USER_PERMS* pExUserPermsList,
49 SCA_SMB_EX_USER_PERMS* pExUserPerms
50 )
51 {
52 SCA_SMB_EX_USER_PERMS* pExUserPermsTemp = pExUserPermsList;
53 if (pExUserPermsList)
54 {
55 while (pExUserPermsTemp->pExUserPermsNext)
56 {
57 pExUserPermsTemp = pExUserPermsTemp->pExUserPermsNext;
58 }
59
60 pExUserPermsTemp->pExUserPermsNext = pExUserPerms;
61 }
62 else
63 {
64 pExUserPermsList = pExUserPerms;
65 }
66
67 return pExUserPermsList;
68 }
69
70 void ScaSmbFreeList(SCA_SMB* pssList)
71 {
72 SCA_SMB* pssDelete = pssList;
73 while (pssList)
74 {
75 pssDelete = pssList;
76 pssList = pssList->pssNext;
77
78 MemFree(pssDelete);
79 }
80 }
81
82 void ScaExUserPermsSmbFreeList(SCA_SMB_EX_USER_PERMS* pExUserPermsList)
83 {
84 SCA_SMB_EX_USER_PERMS* pExUserPermsDelete = pExUserPermsList;
85 while (pExUserPermsList)
86 {
87 pExUserPermsDelete = pExUserPermsList;
88 pExUserPermsList = pExUserPermsList->pExUserPermsNext;
89
90 MemFree(pExUserPermsDelete);
91 }
92 }
93
94 // sql query constants
95 LPCWSTR vcsSmbQuery = L"SELECT `FileShare`, `ShareName`, `Component_`, `Description`, `Directory_` FROM `Wix4FileShare`";
96
97 enum eSmbQuery {
98 ssqFileShare = 1,
99 ssqShareName,
100 ssqComponent,
101 ssqDescription,
102 ssqDirectory,
103 };
104
105
106 /********************************************************************
107 ScaSmbRead - read all of the information from the msi tables and
108 return a list of file share jobs to be done.
109
110 ********************************************************************/
111 HRESULT ScaSmbRead(SCA_SMB** ppssList)
112 {
113 HRESULT hr = S_OK;
114 UINT er = ERROR_SUCCESS;
115 PMSIHANDLE hView, hRec;
116
117 LPWSTR pwzData = NULL;
118
119 SCA_SMB* pss = NULL;
120 BOOL bUserPermissionsTableExists = FALSE;
121
122 if (S_OK != WcaTableExists(L"Wix4FileShare"))
123 {
124 WcaLog(LOGMSG_VERBOSE, "Skipping ScaSmbCreateShare() - Wix4FileShare table not present");
125 ExitFunction1(hr = S_FALSE);
126 }
127
128 if (S_OK == WcaTableExists(L"Wix4FileSharePermissions"))
129 {
130 bUserPermissionsTableExists = TRUE;
131 }
132 else
133 {
134 WcaLog(LOGMSG_VERBOSE, "No Additional Permissions - Wix4FileSharePermissions table not present");
135 }
136
137 WcaLog(LOGMSG_VERBOSE, "Reading File Share Tables");
138
139 // loop through all the fileshares
140 hr = WcaOpenExecuteView(vcsSmbQuery, &hView);
141 ExitOnFailure(hr, "Failed to open view on Wix4FileShare table");
142 while (S_OK == (hr = WcaFetchRecord(hView, &hRec)))
143 {
144 pss = NewSmb();
145 if (!pss)
146 {
147 hr = E_OUTOFMEMORY;
148 break;
149 }
150 Assert(pss);
151 ::ZeroMemory(pss, sizeof(*pss));
152
153 hr = WcaGetRecordString(hRec, ssqFileShare, &pwzData);
154 ExitOnFailure(hr, "Failed to get Wix4FileShare.FileShare");
155 hr = ::StringCchCopyW(pss->wzId, countof(pss->wzId), pwzData);
156 ExitOnFailure(hr, "Failed to copy ID string to smb object");
157
158 hr = WcaGetRecordFormattedString(hRec, ssqShareName, &pwzData);
159 ExitOnFailure(hr, "Failed to get Wix4FileShare.ShareName");
160 hr = ::StringCchCopyW(pss->wzShareName, countof(pss->wzShareName), pwzData);
161 ExitOnFailure(hr, "Failed to copy share name string to smb object");
162
163 hr = WcaGetRecordString(hRec, ssqComponent, &pwzData);
164 ExitOnFailure(hr, "Failed to get Component for Wix4FileShare: '%ls'", pss->wzShareName);
165 hr = ::StringCchCopyW(pss->wzComponent, countof(pss->wzComponent), pwzData);
166 ExitOnFailure(hr, "Failed to copy component string to smb object");
167
168 hr = WcaGetRecordFormattedString(hRec, ssqDescription, &pwzData);
169 ExitOnFailure(hr, "Failed to get Share Description for Wix4FileShare: '%ls'", pss->wzShareName);
170 hr = ::StringCchCopyW(pss->wzDescription, countof(pss->wzDescription), pwzData);
171 ExitOnFailure(hr, "Failed to copy description string to smb object");
172
173 // get component install state
174 er = ::MsiGetComponentStateW(WcaGetInstallHandle(), pss->wzComponent, &pss->isInstalled, &pss->isAction);
175 hr = HRESULT_FROM_WIN32(er);
176 ExitOnFailure(hr, "Failed to get Component state for Wix4FileShare");
177
178 // get the share's directory
179 hr = WcaGetRecordString(hRec, ssqDirectory, &pwzData);
180 ExitOnFailure(hr, "Failed to get directory for Wix4FileShare: '%ls'", pss->wzShareName);
181
182 WCHAR wzPath[MAX_PATH];
183 DWORD dwLen;
184 dwLen = countof(wzPath);
185 // review: relevant for file shares?
186 if (INSTALLSTATE_SOURCE == pss->isAction)
187 {
188 er = ::MsiGetSourcePathW(WcaGetInstallHandle(), pwzData, wzPath, &dwLen);
189 }
190 else
191 {
192 er = ::MsiGetTargetPathW(WcaGetInstallHandle(), pwzData, wzPath, &dwLen);
193 }
194 hr = HRESULT_FROM_WIN32(er);
195 ExitOnFailure(hr, "Failed to get Source/TargetPath for Directory");
196
197 // If the path is to the root of a drive, then it needs a trailing backslash.
198 // Otherwise, it can't have a trailing backslash.
199 if (3 < dwLen)
200 {
201 if (wzPath[dwLen - 1] == L'\\')
202 {
203 wzPath[dwLen - 1] = 0;
204 }
205 }
206 else if (2 == dwLen && wzPath[1] == L':')
207 {
208 wzPath[2] = L'\\';
209 wzPath[3] = 0;
210 }
211
212 hr = ::StringCchCopyW(pss->wzDirectory, countof(pss->wzDirectory), wzPath);
213 ExitOnFailure(hr, "Failed to copy directory string to smb object");
214
215 // Check to see if additional user & permissions are specified for this share
216 if (bUserPermissionsTableExists)
217 {
218 hr = ScaSmbExPermsRead(pss);
219 ExitOnFailure(hr, "Failed to get Additional File Share Permissions");
220 }
221
222 *ppssList = AddSmbToList(*ppssList, pss);
223 pss = NULL; // set the smb NULL so it doesn't accidentally get freed below
224 }
225
226 if (E_NOMOREITEMS == hr)
227 {
228 hr = S_OK;
229 }
230 ExitOnFailure(hr, "Failure occured while processing Wix4FileShare table");
231
232 LExit:
233 // if anything was left over after an error clean it all up
234 if (pss)
235 {
236 ScaSmbFreeList(pss);
237 }
238
239 ReleaseStr(pwzData);
240
241 return hr;
242 }
243
244
245 /********************************************************************
246 RetrieveSMBShareUserPermList - retrieve SMB Share's user permission list
247
248 ********************************************************************/
249 HRESULT RetrieveFileShareUserPerm(SCA_SMB* pss, SCA_SMB_EX_USER_PERMS** ppExUserPermsList, DWORD *pUserPermsCount)
250 {
251 HRESULT hr = S_OK;
252 SHARE_INFO_502* psi = NULL;
253 NET_API_STATUS s;
254 BOOL bValid, bDaclDefaulted;
255 PACL acl = NULL;
256 PEXPLICIT_ACCESSW pEA = NULL;
257 ULONG nCount = 0;
258 DWORD er = ERROR_SUCCESS;
259 PSID pSID = NULL;
260 DWORD nUserNameSize = MAX_DARWIN_COLUMN;
261 DWORD nDomainNameSize = MAX_DARWIN_COLUMN;
262 SID_NAME_USE peUse;
263 DWORD dwCounter = 0;
264 SCA_SMB_EX_USER_PERMS* pExUserPermsList = NULL;
265 DWORD dwUserPermsCount = 0;
266
267 *pUserPermsCount = 0;
268 s = ::NetShareGetInfo(NULL, pss->wzShareName, 502, (LPBYTE*)&psi);
269 WcaLog(LOGMSG_VERBOSE, "retrieving permissions on existing file share.");
270 if (NERR_NetNameNotFound == s)
271 {
272 WcaLog(LOGMSG_VERBOSE, "File share has already been removed.");
273 ExitFunction1(hr = S_OK);
274 }
275 else if (NERR_Success != s || psi == NULL)
276 {
277 hr = E_FAIL;
278 ExitOnFailure(hr, "Failed to get share information with return code: %d", s);
279 }
280 if (!::GetSecurityDescriptorDacl(psi->shi502_security_descriptor, &bValid, &acl, &bDaclDefaulted) || !bValid)
281 {
282 ExitOnLastError(hr, "Failed to get acl from security descriptor");
283 }
284
285 er = ::GetExplicitEntriesFromAclW(acl, &nCount, &pEA);
286 hr = HRESULT_FROM_WIN32(er);
287 ExitOnFailure(hr, "Failed to get access entries from acl for file share %ls", pss->wzShareName);
288 for (dwCounter = 0; dwCounter < nCount; ++dwCounter)
289 {
290 if (TRUSTEE_IS_SID == pEA[dwCounter].Trustee.TrusteeForm)
291 {
292 SCA_SMB_EX_USER_PERMS* pExUserPerms = NewExUserPermsSmb();
293 ::ZeroMemory(pExUserPerms, sizeof(*pExUserPerms));
294 pExUserPermsList = AddExUserPermsSmbToList(pExUserPermsList, pExUserPerms);
295 pSID = (PSID)(pEA[dwCounter].Trustee.ptstrName);
296 if (!::LookupAccountSidW(NULL, pSID, pExUserPerms->scau.wzName, &nUserNameSize, pExUserPerms->scau.wzDomain, &nDomainNameSize, &peUse))
297 {
298 hr = E_FAIL;
299 ExitOnFailure(hr, "Failed to get account name from SID");
300 }
301 pExUserPerms->nPermissions = pEA[dwCounter].grfAccessPermissions;
302 pExUserPerms->accessMode = pEA[dwCounter].grfAccessMode;
303 ++dwUserPermsCount;
304 nUserNameSize = MAX_DARWIN_COLUMN;
305 nDomainNameSize = MAX_DARWIN_COLUMN;
306 }
307 }
308 *ppExUserPermsList = pExUserPermsList;
309 *pUserPermsCount = dwUserPermsCount;
310
311 LExit:
312 if (psi)
313 {
314 ::NetApiBufferFree(psi);
315 }
316
317 if (pEA)
318 {
319 ::LocalFree(pEA);
320 }
321
322 return hr;
323 }
324
325
326 /********************************************************************
327 SchedCreateSmb - schedule one instance of a file share creation
328
329 ********************************************************************/
330 HRESULT SchedCreateSmb(SCA_SMB* pss)
331 {
332 HRESULT hr = S_OK;
333
334 WCHAR wzDomainUser[255]; // "domain\user"
335 SCA_SMB_EX_USER_PERMS* pExUserPermsList = NULL;
336 int nCounter = 0;
337 WCHAR* pwzRollbackCustomActionData = NULL;
338 WCHAR* pwzCustomActionData = NULL;
339
340 hr = WcaWriteStringToCaData(pss->wzShareName, &pwzRollbackCustomActionData);
341 ExitOnFailure(hr, "failed to add ShareName to CustomActionData");
342
343 hr = WcaWriteStringToCaData(pss->wzShareName, &pwzCustomActionData);
344 ExitOnFailure(hr, "failed to add ShareName to CustomActionData");
345
346 hr = WcaWriteStringToCaData(pss->wzDescription, &pwzCustomActionData);
347 ExitOnFailure(hr, "Failed to add server name to CustomActionData");
348
349 hr = WcaWriteStringToCaData(pss->wzDirectory, &pwzCustomActionData);
350 ExitOnFailure(hr, "Failed to add full path instance to CustomActionData");
351
352 hr = WcaWriteStringToCaData(pss->fUseIntegratedAuth ? L"1" : L"0", &pwzCustomActionData);
353 ExitOnFailure(hr, "Failed to add server name to CustomActionData");
354
355 hr = WcaWriteIntegerToCaData(pss->nUserPermissionCount, &pwzCustomActionData);
356 ExitOnFailure(hr, "Failed to add additional user permission count to CustomActionData");
357
358 if (pss->nUserPermissionCount > 0)
359 {
360 nCounter = 0;
361 for (pExUserPermsList = pss->pExUserPerms; pExUserPermsList; pExUserPermsList = pExUserPermsList->pExUserPermsNext)
362 {
363 Assert(nCounter < pss->nUserPermissionCount);
364
365 hr = UserBuildDomainUserName(wzDomainUser, countof(wzDomainUser), pExUserPermsList->scau.wzName, pExUserPermsList->scau.wzDomain);
366 ExitOnFailure(hr, "Failed to build user and domain name for CustomActionData");
367 hr = WcaWriteStringToCaData(wzDomainUser, &pwzCustomActionData);
368 ExitOnFailure(hr, "Failed to add server Domain\\UserName to CustomActionData");
369
370 hr = WcaWriteIntegerToCaData((int)pExUserPermsList->accessMode, &pwzCustomActionData);
371 ExitOnFailure(hr, "Failed to add access mode to CustomActionData");
372
373 hr = WcaWriteIntegerToCaData(pExUserPermsList->nPermissions, &pwzCustomActionData);
374 ExitOnFailure(hr, "Failed to add permissions to CustomActionData");
375 ++nCounter;
376 }
377 Assert(nCounter == pss->nUserPermissionCount);
378 }
379
380 // Schedule the rollback first
381 hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"CreateSmbRollback"), pwzRollbackCustomActionData, COST_SMB_DROPSMB);
382 ExitOnFailure(hr, "Failed to schedule DropSmb action");
383
384 hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"CreateSmb"), pwzCustomActionData, COST_SMB_CREATESMB);
385 ExitOnFailure(hr, "Failed to schedule CreateSmb action");
386
387 LExit:
388 ReleaseStr(pwzRollbackCustomActionData);
389 ReleaseStr(pwzCustomActionData);
390
391 if (pExUserPermsList)
392 {
393 ScaExUserPermsSmbFreeList(pExUserPermsList);
394 }
395
396 return hr;
397 }
398
399
400 /********************************************************************
401 ScaSmbInstall - for every file share, schedule the create custom action
402
403 ********************************************************************/
404 HRESULT ScaSmbInstall(SCA_SMB* pssList)
405 {
406 HRESULT hr = S_FALSE; // assume nothing will be done
407 SCA_SMB* pss = NULL;
408
409 for (pss = pssList; pss; pss = pss->pssNext)
410 {
411 // if installing this component
412 if (WcaIsInstalling(pss->isInstalled, pss->isAction) )
413 {
414 hr = SchedCreateSmb(pss);
415 ExitOnFailure(hr, "Failed to schedule the creation of the fileshare: %ls", pss->wzShareName);
416 }
417 }
418
419 LExit:
420 return hr;
421 }
422
423
424 /********************************************************************
425 SchedDropSmb - schedule one instance of a file share removal
426
427 ********************************************************************/
428 HRESULT SchedDropSmb(SCA_SMB* pss)
429 {
430 HRESULT hr = S_OK;
431
432 WCHAR* pwzCustomActionData = NULL;
433 WCHAR* pwzRollbackCustomActionData = NULL;
434 SCA_SMB_EX_USER_PERMS *pExUserPermsList = NULL;
435 SCA_SMB_EX_USER_PERMS *pExUserPerm = NULL;
436 WCHAR wzDomainUser[255]; // "domain\user"
437 DWORD dwUserPermsCount = 0;
438
439 // roll back DropSmb
440 hr = WcaWriteStringToCaData(pss->wzShareName, &pwzRollbackCustomActionData);
441 ExitOnFailure(hr, "failed to add ShareName to CustomActionData");
442
443 hr = WcaWriteStringToCaData(pss->wzDescription, &pwzRollbackCustomActionData);
444 ExitOnFailure(hr, "Failed to add server name to CustomActionData");
445
446 hr = WcaWriteStringToCaData(pss->wzDirectory, &pwzRollbackCustomActionData);
447 ExitOnFailure(hr, "Failed to add full path instance to CustomActionData");
448
449 hr = WcaWriteStringToCaData(L"1", &pwzRollbackCustomActionData);
450 ExitOnFailure(hr, "Failed to add useintegrated flag to CustomActionData");
451
452 hr = RetrieveFileShareUserPerm(pss, &pExUserPermsList, &dwUserPermsCount);
453 ExitOnFailure(hr, "Failed to retrieve SMBShare's user permissions");
454
455 hr = WcaWriteIntegerToCaData((int)dwUserPermsCount, &pwzRollbackCustomActionData);
456 ExitOnFailure(hr, "Failed to add additional user permission count to CustomActionData");
457
458 for (pExUserPerm = pExUserPermsList; pExUserPerm; pExUserPerm = pExUserPerm->pExUserPermsNext)
459 {
460 hr = UserBuildDomainUserName(wzDomainUser, countof(wzDomainUser), pExUserPerm->scau.wzName, pExUserPerm->scau.wzDomain);
461 ExitOnFailure(hr, "Failed to build user and domain name for CustomActionData");
462 hr = WcaWriteStringToCaData(wzDomainUser, &pwzRollbackCustomActionData);
463 ExitOnFailure(hr, "Failed to add server Domain\\UserName to CustomActionData");
464
465 hr = WcaWriteIntegerToCaData((int)pExUserPerm->accessMode, &pwzRollbackCustomActionData);
466 ExitOnFailure(hr, "Failed to add access mode to CustomActionData");
467
468 hr = WcaWriteIntegerToCaData(pExUserPerm->nPermissions, &pwzRollbackCustomActionData);
469 ExitOnFailure(hr, "Failed to add permissions to CustomActionData");
470 }
471
472 hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"DropSmbRollback"), pwzRollbackCustomActionData, COST_SMB_CREATESMB);
473 ExitOnFailure(hr, "Failed to schedule DropSmbRollback action");
474
475 // DropSMB
476 hr = WcaWriteStringToCaData(pss->wzShareName, &pwzCustomActionData);
477 ExitOnFailure(hr, "failed to add ShareName to CustomActionData");
478
479 hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"DropSmb"), pwzCustomActionData, COST_SMB_DROPSMB);
480 ExitOnFailure(hr, "Failed to schedule DropSmb action");
481
482 LExit:
483 ReleaseStr(pwzCustomActionData);
484
485 if (pExUserPermsList)
486 {
487 ScaExUserPermsSmbFreeList(pExUserPermsList);
488 }
489
490 return hr;
491
492 }
493
494
495 /********************************************************************
496 ScaSmbUninstall - for every file share, schedule the drop custom action
497
498 ********************************************************************/
499 HRESULT ScaSmbUninstall(SCA_SMB* pssList)
500 {
501 HRESULT hr = S_FALSE; // assume nothing will be done
502 SCA_SMB* pss = NULL;
503
504 for (pss = pssList; pss; pss = pss->pssNext)
505 {
506 // if uninstalling this component
507 if (WcaIsUninstalling(pss->isInstalled, pss->isAction) )
508 {
509 hr = SchedDropSmb(pss);
510 ExitOnFailure(hr, "Failed to remove file share %ls", pss->wzShareName);
511 }
512 }
513
514 LExit:
515 return hr;
516 }
517
518 LPCWSTR vcsSmbExUserPermsQuery = L"SELECT `FileShare_`,`User_`,`Permissions` "
519 L"FROM `Wix4FileSharePermissions` WHERE `FileShare_`=?";
520
521 enum eSmbUserPermsQuery {
522 ssupqFileShare = 1,
523 ssupqUser,
524 ssupqPermissions
525
526 };
527
528
529 /********************************************************************
530 ScaSmbExPermsRead - for Every entry in File Permissions table add a
531 User Name & Permissions structure to the List
532
533 ********************************************************************/
534 HRESULT ScaSmbExPermsRead(SCA_SMB* pss)
535 {
536 HRESULT hr = S_OK;
537 PMSIHANDLE hView, hRec;
538
539 LPWSTR pwzData = NULL;
540 SCA_SMB_EX_USER_PERMS* pExUserPermsList = pss->pExUserPerms;
541 SCA_SMB_EX_USER_PERMS* pExUserPerms = NULL;
542 int nCounter = 0;
543
544 hRec = ::MsiCreateRecord(1);
545 hr = WcaSetRecordString(hRec, 1, pss->wzId);
546 ExitOnFailure(hr, "Failed to look up FileShare");
547
548 hr = WcaOpenView(vcsSmbExUserPermsQuery, &hView);
549 ExitOnFailure(hr, "Failed to open view on Wix4FileSharePermissions table");
550 hr = WcaExecuteView(hView, hRec);
551 ExitOnFailure(hr, "Failed to execute view on Wix4FileSharePermissions table");
552
553 // loop through all User/Permissions paris returned
554 while (S_OK == (hr = WcaFetchRecord(hView, &hRec)))
555 {
556 pExUserPerms = NewExUserPermsSmb();
557 if (!pExUserPerms)
558 {
559 hr = E_OUTOFMEMORY;
560 break;
561 }
562 Assert(pExUserPerms);
563 ::ZeroMemory(pExUserPerms, sizeof(*pExUserPerms));
564
565 hr = WcaGetRecordString(hRec, ssupqUser, &pwzData);
566 ExitOnFailure(hr, "Failed to get Wix4FileSharePermissions.User");
567 hr = ScaGetUser(pwzData, &pExUserPerms->scau);
568 ExitOnFailure(hr, "Failed to get user information for fileshare: '%ls'", pss->wzShareName);
569
570 hr = WcaGetRecordInteger(hRec, ssupqPermissions, &pExUserPerms->nPermissions);
571 ExitOnFailure(hr, "Failed to get Wix4FileSharePermissions.Permissions");
572 pExUserPerms->accessMode = SET_ACCESS; // we only support SET_ACCESS here
573
574 pExUserPermsList = AddExUserPermsSmbToList(pExUserPermsList, pExUserPerms);
575 ++nCounter;
576 pExUserPerms = NULL; // set the smb NULL so it doesn't accidentally get freed below
577 }
578
579 if (E_NOMOREITEMS == hr)
580 {
581 hr = S_OK;
582 pss->pExUserPerms = pExUserPermsList;
583 pss->nUserPermissionCount = nCounter;
584 }
585 ExitOnFailure(hr, "Failure occured while processing FileShare table");
586
587 LExit:
588 // if anything was left over after an error clean it all up
589 if (pExUserPerms)
590 {
591 ScaExUserPermsSmbFreeList(pExUserPerms);
592 }
593
594 ReleaseStr(pwzData);
595
596 return hr;
597 }