Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

5269 lines
157 KiB

  1. /*++
  2. Copyright (c) 1998 Microsoft Corporation
  3. Module Name:
  4. checker.cxx
  5. Abstract:
  6. IIS Services IISADMIN Extension
  7. Unicode Metadata Sink.
  8. Author:
  9. Michael W. Thomas 11-19-98
  10. --*/
  11. #include <cominc.hxx>
  12. #include <lmaccess.h>
  13. #include <lmserver.h>
  14. #include <lmapibuf.h>
  15. #include <lmerr.h>
  16. #include <ntlsa.h>
  17. #include <time.h>
  18. #include <ntsam.h>
  19. #include <netlib.h>
  20. #include <resource.h>
  21. #define SECURITY_WIN32
  22. #define ISSP_LEVEL 32
  23. #define ISSP_MODE 1
  24. #include <sspi.h>
  25. #include <sspi.h>
  26. #include <eventlog.hxx>
  27. #include "extend.h"
  28. #include <comadmin.h>
  29. #include <sddl.h>
  30. #include "wmrgexp.h"
  31. typedef TCHAR USERNAME_STRING_TYPE[MAX_PATH];
  32. typedef TCHAR PASSWORD_STRING_TYPE[LM20_PWLEN+1];
  33. const LPCWSTR ROOTMDPath = L"/LM/W3SVC";
  34. #define IIS_WP_GROUP L"IIS_WPG"
  35. #ifndef ARRAYSIZE
  36. #define ARRAYSIZE(_a) (sizeof((_a))/sizeof(*(_a)))
  37. #endif
  38. typedef enum
  39. {
  40. GUFM_SUCCESS,
  41. GUFM_NO_PATH,
  42. GUFM_NO_PASSWORD,
  43. GUFM_NO_USER_ID
  44. } GUFM_RETURN;
  45. typedef struct _COM_APP_THREAD_STRUCT
  46. {
  47. USERNAME_STRING_TYPE ustWamUserName;
  48. PASSWORD_STRING_TYPE pstWamUserPass;
  49. } COM_APP_THREAD_STRUCT;
  50. BOOL ValidatePassword(IN LPCTSTR UserName,IN LPCTSTR Domain,IN LPCTSTR Password);
  51. void InitLsaString(PLSA_UNICODE_STRING LsaString,LPWSTR String);
  52. DWORD GetPrincipalSID (LPCTSTR Principal,PSID *Sid,BOOL *pbWellKnownSID);
  53. DWORD OpenPolicy(LPTSTR ServerName,DWORD DesiredAccess,PLSA_HANDLE PolicyHandle);
  54. DWORD AddRightToUserAccount(LPCTSTR szAccountName, LPTSTR PrivilegeName);
  55. DWORD DoesUserHaveThisRight(LPCTSTR szAccountName, LPTSTR PrivilegeName,BOOL *fHaveThatRight);
  56. HRESULT UpdateComApplications(LPCTSTR szWamUserName,LPCTSTR szWamUserPass);
  57. DWORD UpdateComApplicationsThread(PVOID pv);
  58. int IsDomainController(void);
  59. BOOL WaitForDCAvailability(void);
  60. HRESULT UpdateAdminAcl(IMDCOM *pcCom, LPCWSTR szPath, LPCWSTR szAccountName);
  61. BOOL MakeSureUserGetsCreated(LPTSTR pszAnonyName,LPTSTR pszAnonyPass,DWORD dwUserCommentResourceId,DWORD dwUserFullNameResourceId,BOOL fSpecicaliWamAccount);
  62. // these two lines for logging event about account recreation
  63. EVENT_LOG *g_eventLogForAccountRecreation = NULL;
  64. BOOL CreateEventLogObject();
  65. VOID
  66. UpdateUserRights(
  67. LPCTSTR account,
  68. LPTSTR pstrRights[],
  69. DWORD dwNofRights)
  70. {
  71. DWORD status;
  72. BOOL fPresence;
  73. for (DWORD i=0;i<dwNofRights;i++)
  74. {
  75. status = DoesUserHaveThisRight(account,pstrRights[i],&fPresence);
  76. if (!NT_SUCCESS(status))
  77. {
  78. DBGPRINTF(( DBG_CONTEXT,"[UpdateAnonymousUser] DoesUserHaveThisRight returned err=0x%0X for account %s right %s\n",status,account,pstrRights[i]));
  79. }
  80. else
  81. {
  82. if (!fPresence)
  83. {
  84. status = AddRightToUserAccount(account,pstrRights[i]);
  85. if (!NT_SUCCESS(status))
  86. {
  87. DBGPRINTF(( DBG_CONTEXT,"[UpdateAnonymousUser] AddRightToUserAccount returned err=0x%0X for account %s right %s\n",status,account,pstrRights[i]));
  88. }
  89. }
  90. }
  91. }
  92. }
  93. DWORD
  94. AddRightToUserAccount(
  95. LPCTSTR szAccountName,
  96. LPTSTR PrivilegeName)
  97. {
  98. NTSTATUS status;
  99. LSA_UNICODE_STRING UserRightString;
  100. LSA_HANDLE PolicyHandle = NULL;
  101. PSID pSID = NULL;
  102. BOOL bWellKnownSID = FALSE;
  103. // Create a LSA_UNICODE_STRING for the privilege name.
  104. InitLsaString(&UserRightString, PrivilegeName);
  105. // get the sid of szAccountName
  106. status = GetPrincipalSID ((LPTSTR)szAccountName, &pSID, &bWellKnownSID);
  107. if (status != ERROR_SUCCESS)
  108. {
  109. DBGPRINTF(( DBG_CONTEXT,"[AddRightToUserAccount] GetPrincipalSID returned err=0x%0X\n",status));
  110. return (status);
  111. }
  112. status = OpenPolicy(NULL, POLICY_ALL_ACCESS,&PolicyHandle);
  113. if ( status == NERR_Success )
  114. {
  115. status = LsaAddAccountRights (
  116. PolicyHandle,
  117. pSID,
  118. &UserRightString,
  119. 1);
  120. }
  121. if (PolicyHandle)
  122. {
  123. LsaClose(PolicyHandle);
  124. }
  125. if (pSID)
  126. {
  127. if (bWellKnownSID)
  128. {
  129. FreeSid (pSID);
  130. }
  131. else
  132. {
  133. free (pSID);
  134. }
  135. }
  136. return status;
  137. }
  138. DWORD
  139. DoesUserHaveThisRight(
  140. LPCTSTR szAccountName,
  141. LPTSTR PrivilegeName,
  142. BOOL *fHaveThatRight)
  143. {
  144. BOOL fEnabled = FALSE;
  145. NTSTATUS status;
  146. LSA_UNICODE_STRING UserRightString;
  147. LSA_HANDLE PolicyHandle = NULL;
  148. PSID pSID = NULL;
  149. BOOL bWellKnownSID = FALSE;
  150. *fHaveThatRight = FALSE;
  151. // Create a LSA_UNICODE_STRING for the privilege name.
  152. InitLsaString(&UserRightString, PrivilegeName);
  153. // get the sid of szAccountName
  154. status = GetPrincipalSID ((LPTSTR)szAccountName, &pSID, &bWellKnownSID);
  155. if (status != ERROR_SUCCESS)
  156. {
  157. return status;
  158. }
  159. status = OpenPolicy(NULL, POLICY_ALL_ACCESS,&PolicyHandle);
  160. if ( status == NERR_Success )
  161. {
  162. UINT i;
  163. LSA_UNICODE_STRING *rgUserRights = NULL;
  164. ULONG cRights;
  165. status = LsaEnumerateAccountRights(
  166. PolicyHandle,
  167. pSID,
  168. &rgUserRights,
  169. &cRights);
  170. if (status==STATUS_OBJECT_NAME_NOT_FOUND)
  171. {
  172. // no rights/privileges for this account
  173. status = ERROR_SUCCESS;
  174. fEnabled = FALSE;
  175. }
  176. else if (!NT_SUCCESS(status))
  177. {
  178. //iisDebugOut((LOG_TYPE_ERROR, _T("DoesUserHaveBasicRights:GetPrincipalSID:Failed to enumerate rights: status 0x%08lx\n"), status));
  179. goto DoesUserHaveBasicRights_Exit;
  180. }
  181. for(i=0; i < cRights; i++)
  182. {
  183. if ( RtlEqualUnicodeString(&rgUserRights[i],&UserRightString,FALSE) )
  184. {
  185. fEnabled = TRUE;
  186. break;
  187. }
  188. }
  189. if (rgUserRights)
  190. {
  191. LsaFreeMemory(rgUserRights);
  192. }
  193. }
  194. DoesUserHaveBasicRights_Exit:
  195. if (PolicyHandle)
  196. {
  197. LsaClose(PolicyHandle);
  198. }
  199. if (pSID)
  200. {
  201. if (bWellKnownSID)
  202. {
  203. FreeSid (pSID);
  204. }
  205. else
  206. {
  207. free (pSID);
  208. }
  209. }
  210. *fHaveThatRight = fEnabled;
  211. return status;
  212. }
  213. DWORD
  214. GetCurrentUserSID(
  215. PSID *Sid)
  216. {
  217. DWORD dwReturn = ERROR_SUCCESS;
  218. TOKEN_USER *tokenUser = NULL;
  219. HANDLE tokenHandle = NULL;
  220. DWORD tokenSize = 0 ;
  221. DWORD sidLength = 0;
  222. if ( !Sid )
  223. {
  224. dwReturn = ERROR_BAD_ARGUMENTS;
  225. goto exit;
  226. }
  227. *Sid = NULL;
  228. if ( !OpenProcessToken( GetCurrentProcess(), TOKEN_QUERY, &tokenHandle ) )
  229. {
  230. dwReturn = GetLastError();
  231. goto exit;
  232. }
  233. if ( !GetTokenInformation( tokenHandle, TokenUser, tokenUser, 0, &tokenSize ) )
  234. {
  235. if ( GetLastError() != ERROR_INSUFFICIENT_BUFFER )
  236. {
  237. dwReturn = GetLastError();
  238. goto exit;
  239. }
  240. }
  241. else
  242. {
  243. dwReturn = (DWORD)E_UNEXPECTED;
  244. goto exit;
  245. }
  246. tokenUser = (TOKEN_USER *)malloc( tokenSize );
  247. if ( !tokenUser )
  248. {
  249. dwReturn = ERROR_OUTOFMEMORY;
  250. goto exit;
  251. }
  252. if ( !GetTokenInformation( tokenHandle, TokenUser, tokenUser, tokenSize, &tokenSize ) )
  253. {
  254. dwReturn = GetLastError();
  255. goto exit;
  256. }
  257. sidLength = GetLengthSid( tokenUser->User.Sid );
  258. *Sid = (PSID)malloc( sidLength );
  259. if ( !*Sid )
  260. {
  261. dwReturn = ERROR_OUTOFMEMORY;
  262. goto exit;
  263. }
  264. memcpy( *Sid, tokenUser->User.Sid, sidLength );
  265. exit:
  266. if (tokenHandle)
  267. {
  268. CloseHandle (tokenHandle);
  269. tokenHandle = NULL;
  270. }
  271. if (tokenUser)
  272. {
  273. free(tokenUser);
  274. tokenUser = NULL;
  275. }
  276. return dwReturn;
  277. }
  278. DWORD
  279. CreateNewSD(
  280. SECURITY_DESCRIPTOR **SD)
  281. {
  282. PACL dacl;
  283. DWORD sidLength;
  284. PSID sid = NULL;
  285. PSID groupSID;
  286. PSID ownerSID;
  287. DWORD returnValue;
  288. *SD = NULL;
  289. returnValue = GetCurrentUserSID (&sid);
  290. if (returnValue != ERROR_SUCCESS)
  291. {
  292. if (sid)
  293. {
  294. free(sid);
  295. }
  296. return returnValue;
  297. }
  298. sidLength = GetLengthSid (sid);
  299. *SD = (SECURITY_DESCRIPTOR *) malloc (
  300. (sizeof (ACL)+sizeof (ACCESS_ALLOWED_ACE)+sidLength) +
  301. (2 * sidLength) +
  302. sizeof (SECURITY_DESCRIPTOR));
  303. if (!*SD)
  304. {
  305. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  306. return GetLastError();
  307. }
  308. groupSID = (SID *) (*SD + 1);
  309. ownerSID = (SID *) (((BYTE *) groupSID) + sidLength);
  310. dacl = (ACL *) (((BYTE *) ownerSID) + sidLength);
  311. if (!InitializeSecurityDescriptor (*SD, SECURITY_DESCRIPTOR_REVISION))
  312. {
  313. free (*SD);
  314. free (sid);
  315. return GetLastError();
  316. }
  317. if (!InitializeAcl (dacl,
  318. sizeof (ACL)+sizeof (ACCESS_ALLOWED_ACE)+sidLength,
  319. ACL_REVISION2))
  320. {
  321. free (*SD);
  322. free (sid);
  323. return GetLastError();
  324. }
  325. if (!AddAccessAllowedAce (dacl,
  326. ACL_REVISION2,
  327. COM_RIGHTS_EXECUTE,
  328. sid))
  329. {
  330. free (*SD);
  331. free (sid);
  332. return GetLastError();
  333. }
  334. if (!SetSecurityDescriptorDacl (*SD, TRUE, dacl, FALSE))
  335. {
  336. free (*SD);
  337. free (sid);
  338. return GetLastError();
  339. }
  340. memcpy (groupSID, sid, sidLength);
  341. if (!SetSecurityDescriptorGroup (*SD, groupSID, FALSE))
  342. {
  343. free (*SD);
  344. free (sid);
  345. return GetLastError();
  346. }
  347. memcpy (ownerSID, sid, sidLength);
  348. if (!SetSecurityDescriptorOwner (*SD, ownerSID, FALSE))
  349. {
  350. free (*SD);
  351. free (sid);
  352. return GetLastError();
  353. }
  354. if (sid)
  355. free(sid);
  356. return ERROR_SUCCESS;
  357. }
  358. DWORD
  359. GetNamedValueSD (
  360. HKEY RootKey,
  361. LPTSTR KeyName,
  362. LPTSTR ValueName,
  363. SECURITY_DESCRIPTOR **SD,
  364. BOOL *NewSD)
  365. {
  366. DWORD returnValue;
  367. HKEY registryKey;
  368. DWORD valueType;
  369. DWORD valueSize = 0;
  370. *NewSD = FALSE;
  371. //
  372. // Get the security descriptor from the named value. If it doesn't
  373. // exist, create a fresh one.
  374. //
  375. returnValue = RegOpenKeyEx (RootKey, KeyName, 0, KEY_ALL_ACCESS, &registryKey);
  376. if (returnValue != ERROR_SUCCESS)
  377. {
  378. if (returnValue == ERROR_FILE_NOT_FOUND)
  379. {
  380. *SD = NULL;
  381. returnValue = CreateNewSD (SD);
  382. if (returnValue != ERROR_SUCCESS)
  383. {
  384. if (*SD)
  385. {
  386. free(*SD);
  387. }
  388. return returnValue;
  389. }
  390. *NewSD = TRUE;
  391. return ERROR_SUCCESS;
  392. }
  393. else
  394. {
  395. return returnValue;
  396. }
  397. }
  398. returnValue = RegQueryValueEx (registryKey, ValueName, NULL, &valueType, NULL, &valueSize);
  399. if (returnValue && returnValue != ERROR_INSUFFICIENT_BUFFER)
  400. {
  401. *SD = NULL;
  402. returnValue = CreateNewSD (SD);
  403. if (returnValue != ERROR_SUCCESS)
  404. {
  405. if (*SD)
  406. {
  407. free(*SD);
  408. }
  409. return returnValue;
  410. }
  411. *NewSD = TRUE;
  412. }
  413. else
  414. {
  415. *SD = (SECURITY_DESCRIPTOR *) malloc (valueSize);
  416. if (!*SD)
  417. {
  418. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  419. return GetLastError();
  420. }
  421. returnValue = RegQueryValueEx (registryKey,
  422. ValueName,
  423. NULL,
  424. &valueType,
  425. (LPBYTE) *SD,
  426. &valueSize);
  427. if (returnValue)
  428. {
  429. if (*SD)
  430. free (*SD);
  431. *SD = NULL;
  432. returnValue = CreateNewSD (SD);
  433. if (returnValue != ERROR_SUCCESS)
  434. {
  435. if (*SD)
  436. {
  437. free(*SD);
  438. }
  439. return returnValue;
  440. }
  441. *NewSD = TRUE;
  442. }
  443. }
  444. RegCloseKey (registryKey);
  445. return ERROR_SUCCESS;
  446. }
  447. DWORD
  448. GetPrincipalSID(
  449. LPCTSTR Principal,
  450. PSID *Sid,
  451. BOOL *pbWellKnownSID)
  452. {
  453. HRESULT hr = S_OK;
  454. DWORD returnValue=ERROR_SUCCESS;
  455. SID_IDENTIFIER_AUTHORITY SidIdentifierNTAuthority = SECURITY_NT_AUTHORITY;
  456. SID_IDENTIFIER_AUTHORITY SidIdentifierWORLDAuthority = SECURITY_WORLD_SID_AUTHORITY;
  457. PSID_IDENTIFIER_AUTHORITY pSidIdentifierAuthority = NULL;
  458. BYTE Count = 0;
  459. DWORD dwRID[8];
  460. TCHAR pszPrincipal[MAX_PATH];
  461. *pbWellKnownSID = TRUE;
  462. memset(&(dwRID[0]), 0, 8 * sizeof(DWORD));
  463. DBG_ASSERT(wcslen(Principal) < MAX_PATH);
  464. hr = StringCchCopy(pszPrincipal, ARRAYSIZE(pszPrincipal), Principal);
  465. if ( FAILED(hr) )
  466. {
  467. return HRESULTTOWIN32( hr );
  468. }
  469. _wcslwr(pszPrincipal);
  470. if ( wcsstr(pszPrincipal, TEXT("administrators")) != NULL )
  471. {
  472. // Administrators group
  473. pSidIdentifierAuthority = &SidIdentifierNTAuthority;
  474. Count = 2;
  475. dwRID[0] = SECURITY_BUILTIN_DOMAIN_RID;
  476. dwRID[1] = DOMAIN_ALIAS_RID_ADMINS;
  477. }
  478. else if ( wcsstr(pszPrincipal, TEXT("system")) != NULL)
  479. {
  480. // SYSTEM
  481. pSidIdentifierAuthority = &SidIdentifierNTAuthority;
  482. Count = 1;
  483. dwRID[0] = SECURITY_LOCAL_SYSTEM_RID;
  484. }
  485. else if ( wcsstr(pszPrincipal, TEXT("interactive")) != NULL)
  486. {
  487. // INTERACTIVE
  488. pSidIdentifierAuthority = &SidIdentifierNTAuthority;
  489. Count = 1;
  490. dwRID[0] = SECURITY_INTERACTIVE_RID;
  491. }
  492. else if ( wcsstr(pszPrincipal, TEXT("everyone")) != NULL)
  493. {
  494. // Everyone
  495. pSidIdentifierAuthority = &SidIdentifierWORLDAuthority;
  496. Count = 1;
  497. dwRID[0] = SECURITY_WORLD_RID;
  498. }
  499. else
  500. {
  501. *pbWellKnownSID = FALSE;
  502. }
  503. // IVANPASH
  504. // Going through the above code *pbWellKnownSID and pSidIdentifierAuthority
  505. // will always be in sync, but still there is warning on /W4
  506. // so I added initializing pSidIdentifierAuthority to NULL and the
  507. // additional check for pSidIdentifierAuthority in this if to make cl and prefast happy.
  508. if ( *pbWellKnownSID && pSidIdentifierAuthority )
  509. {
  510. if ( !AllocateAndInitializeSid( pSidIdentifierAuthority,
  511. (BYTE)Count,
  512. dwRID[0],
  513. dwRID[1],
  514. dwRID[2],
  515. dwRID[3],
  516. dwRID[4],
  517. dwRID[5],
  518. dwRID[6],
  519. dwRID[7],
  520. Sid) )
  521. {
  522. returnValue = GetLastError();
  523. }
  524. }
  525. else
  526. {
  527. // get regular account sid
  528. DWORD sidSize;
  529. TCHAR refDomain [256];
  530. DWORD refDomainSize;
  531. SID_NAME_USE snu;
  532. sidSize = 0;
  533. refDomainSize = 255;
  534. LookupAccountName (NULL,
  535. pszPrincipal,
  536. *Sid,
  537. &sidSize,
  538. refDomain,
  539. &refDomainSize,
  540. &snu);
  541. returnValue = GetLastError();
  542. if (returnValue == ERROR_INSUFFICIENT_BUFFER)
  543. {
  544. *Sid = (PSID) malloc (sidSize);
  545. if (!*Sid)
  546. {
  547. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  548. return GetLastError();
  549. }
  550. refDomainSize = 255;
  551. if (!LookupAccountName (NULL,
  552. pszPrincipal,
  553. *Sid,
  554. &sidSize,
  555. refDomain,
  556. &refDomainSize,
  557. &snu))
  558. {
  559. free( *Sid );
  560. *Sid = NULL;
  561. returnValue = GetLastError();
  562. }
  563. else
  564. {
  565. returnValue = ERROR_SUCCESS;
  566. }
  567. }
  568. }
  569. return returnValue;
  570. }
  571. DWORD
  572. CopyACL(
  573. PACL OldACL,
  574. PACL NewACL)
  575. {
  576. ACL_SIZE_INFORMATION aclSizeInfo;
  577. LPVOID ace;
  578. ACE_HEADER *aceHeader;
  579. ULONG i;
  580. GetAclInformation (OldACL,
  581. (LPVOID) &aclSizeInfo,
  582. (DWORD) sizeof (aclSizeInfo),
  583. AclSizeInformation);
  584. //
  585. // Copy all of the ACEs to the new ACL
  586. //
  587. for (i = 0; i < aclSizeInfo.AceCount; i++)
  588. {
  589. //
  590. // Get the ACE and header info
  591. //
  592. if (!GetAce (OldACL, i, &ace))
  593. return GetLastError();
  594. aceHeader = (ACE_HEADER *) ace;
  595. //
  596. // Add the ACE to the new list
  597. //
  598. if (!AddAce (NewACL, ACL_REVISION, 0xffffffff, ace, aceHeader->AceSize))
  599. return GetLastError();
  600. }
  601. return ERROR_SUCCESS;
  602. }
  603. DWORD
  604. AddAccessAllowedACEToACL(
  605. PACL *Acl,
  606. DWORD PermissionMask,
  607. LPTSTR Principal)
  608. {
  609. ACL_SIZE_INFORMATION aclSizeInfo;
  610. int aclSize;
  611. DWORD returnValue = ERROR_SUCCESS;
  612. PSID principalSID = NULL;
  613. PACL oldACL;
  614. PACL newACL;
  615. BOOL bWellKnownSID = FALSE;
  616. oldACL = *Acl;
  617. returnValue = GetPrincipalSID (Principal, &principalSID, &bWellKnownSID);
  618. if (returnValue != ERROR_SUCCESS)
  619. {
  620. return returnValue;
  621. }
  622. GetAclInformation (oldACL,
  623. (LPVOID) &aclSizeInfo,
  624. (DWORD) sizeof (ACL_SIZE_INFORMATION),
  625. AclSizeInformation);
  626. aclSize = aclSizeInfo.AclBytesInUse +
  627. sizeof (ACL) + sizeof (ACCESS_ALLOWED_ACE) +
  628. GetLengthSid (principalSID) - sizeof (DWORD);
  629. newACL = (PACL) new BYTE [aclSize];
  630. if ( newACL == NULL )
  631. {
  632. returnValue = ERROR_OUTOFMEMORY;
  633. goto cleanup;
  634. }
  635. if (!InitializeAcl (newACL, aclSize, ACL_REVISION))
  636. {
  637. returnValue = GetLastError();
  638. goto cleanup;
  639. }
  640. returnValue = CopyACL (oldACL, newACL);
  641. if (returnValue != ERROR_SUCCESS)
  642. {
  643. goto cleanup;
  644. }
  645. if (!AddAccessAllowedAce (newACL, ACL_REVISION2, PermissionMask, principalSID))
  646. {
  647. returnValue = GetLastError();
  648. goto cleanup;
  649. }
  650. *Acl = newACL;
  651. newACL = NULL;
  652. cleanup:
  653. // BugFix: 57654 Whistler
  654. // Prefix bug leaking memory in error condition.
  655. // By setting the newACL to NULL above if we have
  656. // relinquished the memory to *Acl, we avoid releasing
  657. // memory we have passed back to the caller.
  658. // EBK 5/5/2000
  659. if (newACL)
  660. {
  661. delete [] newACL;
  662. newACL = NULL;
  663. }
  664. if (principalSID)
  665. {
  666. if (bWellKnownSID)
  667. {
  668. FreeSid (principalSID);
  669. }
  670. else
  671. {
  672. free (principalSID);
  673. }
  674. }
  675. return returnValue;
  676. }
  677. DWORD
  678. RemovePrincipalFromACL (
  679. PACL Acl,
  680. LPTSTR Principal)
  681. {
  682. ACL_SIZE_INFORMATION aclSizeInfo;
  683. ULONG i;
  684. LPVOID ace;
  685. ACCESS_ALLOWED_ACE *accessAllowedAce;
  686. ACCESS_DENIED_ACE *accessDeniedAce;
  687. SYSTEM_AUDIT_ACE *systemAuditAce;
  688. PSID principalSID = NULL;
  689. DWORD returnValue = ERROR_SUCCESS;
  690. ACE_HEADER *aceHeader;
  691. BOOL bWellKnownSID = FALSE;
  692. returnValue = GetPrincipalSID (Principal, &principalSID, &bWellKnownSID);
  693. if (returnValue != ERROR_SUCCESS)
  694. {
  695. return returnValue;
  696. }
  697. GetAclInformation (Acl,
  698. (LPVOID) &aclSizeInfo,
  699. (DWORD) sizeof (ACL_SIZE_INFORMATION),
  700. AclSizeInformation);
  701. for (i = 0; i < aclSizeInfo.AceCount; i++)
  702. {
  703. if (!GetAce (Acl, i, &ace))
  704. {
  705. returnValue = GetLastError();
  706. break;
  707. }
  708. aceHeader = (ACE_HEADER *) ace;
  709. if (aceHeader->AceType == ACCESS_ALLOWED_ACE_TYPE)
  710. {
  711. accessAllowedAce = (ACCESS_ALLOWED_ACE *) ace;
  712. if (EqualSid (principalSID, (PSID) &accessAllowedAce->SidStart))
  713. {
  714. DeleteAce (Acl, i);
  715. break;
  716. }
  717. }
  718. else if (aceHeader->AceType == ACCESS_DENIED_ACE_TYPE)
  719. {
  720. accessDeniedAce = (ACCESS_DENIED_ACE *) ace;
  721. if (EqualSid (principalSID, (PSID) &accessDeniedAce->SidStart))
  722. {
  723. DeleteAce (Acl, i);
  724. break;
  725. }
  726. }
  727. else if (aceHeader->AceType == SYSTEM_AUDIT_ACE_TYPE)
  728. {
  729. systemAuditAce = (SYSTEM_AUDIT_ACE *) ace;
  730. if (EqualSid (principalSID, (PSID) &systemAuditAce->SidStart))
  731. {
  732. DeleteAce (Acl, i);
  733. break;
  734. }
  735. }
  736. }
  737. if (principalSID)
  738. {
  739. if (bWellKnownSID)
  740. {
  741. FreeSid (principalSID);
  742. }
  743. else
  744. {
  745. free (principalSID);
  746. }
  747. }
  748. return returnValue;
  749. }
  750. DWORD
  751. MakeSDAbsolute(
  752. PSECURITY_DESCRIPTOR OldSD,
  753. PSECURITY_DESCRIPTOR *NewSD)
  754. {
  755. PSECURITY_DESCRIPTOR sd = NULL;
  756. DWORD descriptorSize;
  757. DWORD daclSize;
  758. DWORD saclSize;
  759. DWORD ownerSIDSize;
  760. DWORD groupSIDSize;
  761. PACL dacl = NULL;
  762. PACL sacl = NULL;
  763. PSID ownerSID = NULL;
  764. PSID groupSID = NULL;
  765. BOOL present;
  766. BOOL systemDefault;
  767. //
  768. // Get SACL
  769. //
  770. if (!GetSecurityDescriptorSacl (OldSD, &present, &sacl, &systemDefault))
  771. {
  772. return GetLastError();
  773. }
  774. if (sacl && present)
  775. {
  776. saclSize = sacl->AclSize;
  777. }
  778. else
  779. {
  780. saclSize = 0;
  781. }
  782. //
  783. // Get DACL
  784. //
  785. if (!GetSecurityDescriptorDacl (OldSD, &present, &dacl, &systemDefault))
  786. return GetLastError();
  787. if (dacl && present)
  788. {
  789. daclSize = dacl->AclSize;
  790. }
  791. else
  792. {
  793. daclSize = 0;
  794. }
  795. //
  796. // Get Owner
  797. //
  798. if (!GetSecurityDescriptorOwner (OldSD, &ownerSID, &systemDefault))
  799. {
  800. return GetLastError();
  801. }
  802. ownerSIDSize = GetLengthSid (ownerSID);
  803. //
  804. // Get Group
  805. //
  806. if (!GetSecurityDescriptorGroup (OldSD, &groupSID, &systemDefault))
  807. {
  808. return GetLastError();
  809. }
  810. groupSIDSize = GetLengthSid (groupSID);
  811. //
  812. // Do the conversion
  813. //
  814. descriptorSize = 0;
  815. MakeAbsoluteSD (OldSD, sd, &descriptorSize, dacl, &daclSize, sacl,
  816. &saclSize, ownerSID, &ownerSIDSize, groupSID,
  817. &groupSIDSize);
  818. sd = (PSECURITY_DESCRIPTOR) new BYTE [SECURITY_DESCRIPTOR_MIN_LENGTH];
  819. if (!sd)
  820. {
  821. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  822. return GetLastError();
  823. }
  824. if (!InitializeSecurityDescriptor (sd, SECURITY_DESCRIPTOR_REVISION))
  825. return GetLastError();
  826. if (!MakeAbsoluteSD (OldSD, sd, &descriptorSize, dacl, &daclSize, sacl,
  827. &saclSize, ownerSID, &ownerSIDSize, groupSID,
  828. &groupSIDSize))
  829. {
  830. return GetLastError();
  831. }
  832. *NewSD = sd;
  833. return ERROR_SUCCESS;
  834. }
  835. DWORD
  836. SetNamedValueSD(
  837. HKEY RootKey,
  838. LPTSTR KeyName,
  839. LPTSTR ValueName,
  840. SECURITY_DESCRIPTOR *SD)
  841. {
  842. DWORD returnValue;
  843. DWORD disposition;
  844. HKEY registryKey;
  845. //
  846. // Create new key or open existing key
  847. //
  848. returnValue = RegCreateKeyEx (RootKey,
  849. KeyName,
  850. 0,
  851. TEXT(""),
  852. 0,
  853. KEY_ALL_ACCESS,
  854. NULL,
  855. &registryKey,
  856. &disposition);
  857. if (returnValue != ERROR_SUCCESS)
  858. {
  859. return returnValue;
  860. }
  861. //
  862. // Write the security descriptor
  863. //
  864. returnValue = RegSetValueEx (registryKey,
  865. ValueName,
  866. 0,
  867. REG_BINARY,
  868. (LPBYTE) SD,
  869. GetSecurityDescriptorLength (SD));
  870. if (returnValue != ERROR_SUCCESS)
  871. {
  872. return returnValue;
  873. }
  874. RegCloseKey (registryKey);
  875. return ERROR_SUCCESS;
  876. }
  877. DWORD
  878. RemovePrincipalFromNamedValueSD (
  879. HKEY RootKey,
  880. LPTSTR KeyName,
  881. LPTSTR ValueName,
  882. LPTSTR Principal)
  883. {
  884. DWORD returnValue = ERROR_SUCCESS;
  885. SECURITY_DESCRIPTOR *sd = NULL;
  886. SECURITY_DESCRIPTOR *sdSelfRelative = NULL;
  887. SECURITY_DESCRIPTOR *sdAbsolute = NULL;
  888. DWORD secDescSize;
  889. BOOL present;
  890. BOOL defaultDACL;
  891. PACL dacl = NULL;
  892. BOOL newSD = FALSE;
  893. BOOL fFreeAbsolute = TRUE;
  894. returnValue = GetNamedValueSD (RootKey, KeyName, ValueName, &sd, &newSD);
  895. //
  896. // Get security descriptor from registry or create a new one
  897. //
  898. if (returnValue != ERROR_SUCCESS)
  899. {
  900. return returnValue;
  901. }
  902. if (!GetSecurityDescriptorDacl (sd, &present, &dacl, &defaultDACL))
  903. {
  904. returnValue = GetLastError();
  905. goto Cleanup;
  906. }
  907. //
  908. // If the security descriptor is new, add the required Principals to it
  909. //
  910. if (newSD)
  911. {
  912. AddAccessAllowedACEToACL (&dacl, COM_RIGHTS_EXECUTE, TEXT("SYSTEM"));
  913. AddAccessAllowedACEToACL (&dacl, COM_RIGHTS_EXECUTE, TEXT("INTERACTIVE"));
  914. }
  915. //
  916. // Remove the Principal that the caller wants removed
  917. //
  918. returnValue = RemovePrincipalFromACL (dacl, Principal);
  919. if (returnValue != ERROR_SUCCESS)
  920. {
  921. goto Cleanup;
  922. }
  923. //
  924. // Make the security descriptor absolute if it isn't new
  925. //
  926. if (!newSD)
  927. {
  928. MakeSDAbsolute ((PSECURITY_DESCRIPTOR) sd, (PSECURITY_DESCRIPTOR *) &sdAbsolute);
  929. fFreeAbsolute = TRUE;
  930. }
  931. else
  932. {
  933. sdAbsolute = sd;
  934. fFreeAbsolute = FALSE;
  935. }
  936. //
  937. // Set the discretionary ACL on the security descriptor
  938. //
  939. if (!SetSecurityDescriptorDacl (sdAbsolute, TRUE, dacl, FALSE))
  940. {
  941. returnValue = GetLastError();
  942. goto Cleanup;
  943. }
  944. //
  945. // Make the security descriptor self-relative so that we can
  946. // store it in the registry
  947. //
  948. secDescSize = 0;
  949. MakeSelfRelativeSD (sdAbsolute, sdSelfRelative, &secDescSize);
  950. sdSelfRelative = (SECURITY_DESCRIPTOR *) malloc (secDescSize);
  951. if (!sdSelfRelative)
  952. {
  953. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  954. returnValue = GetLastError();
  955. goto Cleanup;
  956. }
  957. if (!MakeSelfRelativeSD (sdAbsolute, sdSelfRelative, &secDescSize))
  958. {
  959. returnValue = GetLastError();
  960. goto Cleanup;
  961. }
  962. //
  963. // Store the security descriptor in the registry
  964. //
  965. SetNamedValueSD (RootKey, KeyName, ValueName, sdSelfRelative);
  966. Cleanup:
  967. if (sd)
  968. {
  969. free (sd);
  970. }
  971. if (sdSelfRelative)
  972. {
  973. free (sdSelfRelative);
  974. }
  975. if (fFreeAbsolute && sdAbsolute)
  976. {
  977. free (sdAbsolute);
  978. }
  979. return returnValue;
  980. }
  981. DWORD
  982. AddAccessDeniedACEToACL(
  983. PACL *Acl,
  984. DWORD PermissionMask,
  985. LPTSTR Principal)
  986. {
  987. ACL_SIZE_INFORMATION aclSizeInfo;
  988. int aclSize;
  989. DWORD returnValue = ERROR_SUCCESS;
  990. PSID principalSID = NULL;
  991. PACL oldACL;
  992. PACL newACL;
  993. BOOL bWellKnownSID = FALSE;
  994. oldACL = *Acl;
  995. returnValue = GetPrincipalSID (Principal, &principalSID, &bWellKnownSID);
  996. if (returnValue != ERROR_SUCCESS)
  997. {
  998. return returnValue;
  999. }
  1000. GetAclInformation (oldACL,
  1001. (LPVOID) &aclSizeInfo,
  1002. (DWORD) sizeof (ACL_SIZE_INFORMATION),
  1003. AclSizeInformation);
  1004. aclSize = aclSizeInfo.AclBytesInUse +
  1005. sizeof (ACL) + sizeof (ACCESS_DENIED_ACE) +
  1006. GetLengthSid (principalSID) - sizeof (DWORD);
  1007. newACL = (PACL) new BYTE [aclSize];
  1008. if ( newACL == NULL )
  1009. {
  1010. returnValue = ERROR_OUTOFMEMORY;
  1011. goto cleanup;
  1012. }
  1013. if (!InitializeAcl (newACL, aclSize, ACL_REVISION))
  1014. {
  1015. returnValue = GetLastError();
  1016. goto cleanup;
  1017. }
  1018. if (!AddAccessDeniedAce (newACL, ACL_REVISION2, PermissionMask, principalSID))
  1019. {
  1020. returnValue = GetLastError();
  1021. goto cleanup;
  1022. }
  1023. returnValue = CopyACL (oldACL, newACL);
  1024. if (returnValue != ERROR_SUCCESS)
  1025. {
  1026. goto cleanup;
  1027. }
  1028. *Acl = newACL;
  1029. newACL = NULL;
  1030. cleanup:
  1031. // BugFix: 57654 Whistler
  1032. // Prefix bug leaking memory in error condition.
  1033. // By setting the newACL to NULL above if we have
  1034. // relinquished the memory to *Acl, we avoid releasing
  1035. // memory we have passed back to the caller.
  1036. // EBK 5/5/2000
  1037. if (newACL)
  1038. {
  1039. delete[] newACL;
  1040. newACL = NULL;
  1041. }
  1042. if (principalSID)
  1043. {
  1044. if (bWellKnownSID)
  1045. {
  1046. FreeSid (principalSID);
  1047. }
  1048. else
  1049. {
  1050. free (principalSID);
  1051. }
  1052. }
  1053. return returnValue;
  1054. }
  1055. DWORD
  1056. AddPrincipalToNamedValueSD(
  1057. HKEY RootKey,
  1058. LPTSTR KeyName,
  1059. LPTSTR ValueName,
  1060. LPTSTR Principal,
  1061. BOOL Permit)
  1062. {
  1063. DWORD returnValue = ERROR_SUCCESS;
  1064. SECURITY_DESCRIPTOR *sd = NULL;
  1065. SECURITY_DESCRIPTOR *sdSelfRelative = NULL;
  1066. SECURITY_DESCRIPTOR *sdAbsolute = NULL;
  1067. DWORD secDescSize;
  1068. BOOL present;
  1069. BOOL defaultDACL;
  1070. PACL dacl;
  1071. BOOL newSD = FALSE;
  1072. BOOL fFreeAbsolute = TRUE;
  1073. returnValue = GetNamedValueSD (RootKey, KeyName, ValueName, &sd, &newSD);
  1074. //
  1075. // Get security descriptor from registry or create a new one
  1076. //
  1077. if (returnValue != ERROR_SUCCESS)
  1078. {
  1079. return returnValue;
  1080. }
  1081. if (!GetSecurityDescriptorDacl (sd, &present, &dacl, &defaultDACL))
  1082. {
  1083. returnValue = GetLastError();
  1084. goto Cleanup;
  1085. }
  1086. if (newSD)
  1087. {
  1088. AddAccessAllowedACEToACL (&dacl, COM_RIGHTS_EXECUTE, TEXT("SYSTEM"));
  1089. AddAccessAllowedACEToACL (&dacl, COM_RIGHTS_EXECUTE, TEXT("INTERACTIVE"));
  1090. }
  1091. //
  1092. // Add the Principal that the caller wants added
  1093. //
  1094. if (Permit)
  1095. {
  1096. returnValue = AddAccessAllowedACEToACL (&dacl, COM_RIGHTS_EXECUTE, Principal);
  1097. }
  1098. else
  1099. {
  1100. returnValue = AddAccessDeniedACEToACL (&dacl, GENERIC_ALL, Principal);
  1101. }
  1102. if (returnValue != ERROR_SUCCESS)
  1103. {
  1104. goto Cleanup;
  1105. }
  1106. //
  1107. // Make the security descriptor absolute if it isn't new
  1108. //
  1109. if (!newSD)
  1110. {
  1111. MakeSDAbsolute ((PSECURITY_DESCRIPTOR) sd, (PSECURITY_DESCRIPTOR *) &sdAbsolute);
  1112. fFreeAbsolute = TRUE;
  1113. }
  1114. else
  1115. {
  1116. sdAbsolute = sd;
  1117. fFreeAbsolute = FALSE;
  1118. }
  1119. //
  1120. // Set the discretionary ACL on the security descriptor
  1121. //
  1122. if (!SetSecurityDescriptorDacl (sdAbsolute, TRUE, dacl, FALSE))
  1123. {
  1124. returnValue = GetLastError();
  1125. goto Cleanup;
  1126. }
  1127. //
  1128. // Make the security descriptor self-relative so that we can
  1129. // store it in the registry
  1130. //
  1131. secDescSize = 0;
  1132. MakeSelfRelativeSD (sdAbsolute, sdSelfRelative, &secDescSize);
  1133. sdSelfRelative = (SECURITY_DESCRIPTOR *) malloc (secDescSize);
  1134. if (!sdSelfRelative)
  1135. {
  1136. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  1137. returnValue = GetLastError();
  1138. goto Cleanup;
  1139. }
  1140. if (!MakeSelfRelativeSD (sdAbsolute, sdSelfRelative, &secDescSize))
  1141. {
  1142. returnValue = GetLastError();
  1143. goto Cleanup;
  1144. }
  1145. //
  1146. // Store the security descriptor in the registry
  1147. //
  1148. SetNamedValueSD (RootKey, KeyName, ValueName, sdSelfRelative);
  1149. Cleanup:
  1150. if (sd)
  1151. {
  1152. free (sd);
  1153. }
  1154. if (sdSelfRelative)
  1155. {
  1156. free (sdSelfRelative);
  1157. }
  1158. if (fFreeAbsolute && sdAbsolute)
  1159. {
  1160. free (sdAbsolute);
  1161. }
  1162. return returnValue;
  1163. }
  1164. DWORD
  1165. ChangeDCOMAccessACL(
  1166. LPTSTR Principal,
  1167. BOOL SetPrincipal,
  1168. BOOL Permit)
  1169. {
  1170. DWORD err;
  1171. if (SetPrincipal)
  1172. {
  1173. // There is not need to check the return value of RemovePrincipalFromNamedValueSD,
  1174. // because its failure is not important (for example DefaultAccessPermission might
  1175. // not exist). The important call that must succeed is AddPrincipalToNamedValueSD
  1176. RemovePrincipalFromNamedValueSD (HKEY_LOCAL_MACHINE,
  1177. TEXT("Software\\Microsoft\\OLE"),
  1178. TEXT("DefaultAccessPermission"),
  1179. Principal);
  1180. err = AddPrincipalToNamedValueSD (HKEY_LOCAL_MACHINE,
  1181. TEXT("Software\\Microsoft\\OLE"),
  1182. TEXT("DefaultAccessPermission"),
  1183. Principal,
  1184. Permit);
  1185. }
  1186. else
  1187. {
  1188. err = RemovePrincipalFromNamedValueSD (HKEY_LOCAL_MACHINE,
  1189. TEXT("Software\\Microsoft\\OLE"),
  1190. TEXT("DefaultAccessPermission"),
  1191. Principal);
  1192. }
  1193. return err;
  1194. }
  1195. DWORD
  1196. ChangeDCOMLaunchACL(
  1197. LPTSTR Principal,
  1198. BOOL SetPrincipal,
  1199. BOOL Permit)
  1200. {
  1201. TCHAR keyName [256] = TEXT("Software\\Microsoft\\OLE");
  1202. DWORD err;
  1203. if (SetPrincipal)
  1204. {
  1205. // There is not need to check the return value of RemovePrincipalFromNamedValueSD,
  1206. // because its failure is not important (for example DefaultAccessPermission might
  1207. // not exist). The important call that must succeed is AddPrincipalToNamedValueSD
  1208. RemovePrincipalFromNamedValueSD (HKEY_LOCAL_MACHINE,
  1209. keyName,
  1210. TEXT("DefaultLaunchPermission"),
  1211. Principal);
  1212. err = AddPrincipalToNamedValueSD (HKEY_LOCAL_MACHINE,
  1213. keyName,
  1214. TEXT("DefaultLaunchPermission"),
  1215. Principal,
  1216. Permit);
  1217. }
  1218. else
  1219. {
  1220. err = RemovePrincipalFromNamedValueSD (HKEY_LOCAL_MACHINE,
  1221. keyName,
  1222. TEXT("DefaultLaunchPermission"),
  1223. Principal);
  1224. }
  1225. return err;
  1226. }
  1227. GUFM_RETURN
  1228. GetUserFromMetabase(
  1229. IMDCOM *pcCom,
  1230. LPWSTR pszPath,
  1231. DWORD dwUserMetaId,
  1232. DWORD dwPasswordMetaId,
  1233. USERNAME_STRING_TYPE ustUserBuf,
  1234. PASSWORD_STRING_TYPE pstPasswordBuf)
  1235. {
  1236. HRESULT hresTemp;
  1237. GUFM_RETURN gufmReturn = GUFM_SUCCESS;
  1238. METADATA_RECORD mdrData;
  1239. DWORD dwRequiredDataLen;
  1240. METADATA_HANDLE mhOpenHandle;
  1241. hresTemp = pcCom->ComMDOpenMetaObject(METADATA_MASTER_ROOT_HANDLE,
  1242. pszPath,
  1243. METADATA_PERMISSION_READ,
  1244. OPEN_TIMEOUT_VALUE,
  1245. &mhOpenHandle);
  1246. if (FAILED(hresTemp))
  1247. {
  1248. gufmReturn = GUFM_NO_PATH;
  1249. }
  1250. else
  1251. {
  1252. MD_SET_DATA_RECORD_EXT(&mdrData,
  1253. dwUserMetaId,
  1254. METADATA_NO_ATTRIBUTES,
  1255. ALL_METADATA,
  1256. STRING_METADATA,
  1257. MAX_PATH * sizeof(TCHAR),
  1258. (PBYTE)ustUserBuf)
  1259. hresTemp = pcCom->ComMDGetMetaData(mhOpenHandle,
  1260. NULL,
  1261. &mdrData,
  1262. &dwRequiredDataLen);
  1263. if (FAILED(hresTemp) || (ustUserBuf[0] == (TCHAR)'\0'))
  1264. {
  1265. gufmReturn = GUFM_NO_USER_ID;
  1266. }
  1267. else
  1268. {
  1269. MD_SET_DATA_RECORD_EXT(&mdrData,
  1270. dwPasswordMetaId,
  1271. METADATA_NO_ATTRIBUTES,
  1272. ALL_METADATA,
  1273. STRING_METADATA,
  1274. (LM20_PWLEN+1) * sizeof(TCHAR),
  1275. (PBYTE)pstPasswordBuf)
  1276. hresTemp = pcCom->ComMDGetMetaData(mhOpenHandle,
  1277. NULL,
  1278. &mdrData,
  1279. &dwRequiredDataLen);
  1280. if (FAILED(hresTemp))
  1281. {
  1282. gufmReturn = GUFM_NO_PASSWORD;
  1283. }
  1284. }
  1285. pcCom->ComMDCloseMetaObject(mhOpenHandle);
  1286. }
  1287. return gufmReturn;
  1288. }
  1289. BOOL
  1290. WritePasswordToMetabase(
  1291. IMDCOM *pcCom,
  1292. LPWSTR pszPath,
  1293. DWORD dwPasswordMetaId,
  1294. PASSWORD_STRING_TYPE pstPasswordBuf)
  1295. {
  1296. HRESULT hresReturn;
  1297. METADATA_RECORD mdrData;
  1298. METADATA_HANDLE mhOpenHandle;
  1299. hresReturn = pcCom->ComMDOpenMetaObject(METADATA_MASTER_ROOT_HANDLE,
  1300. pszPath,
  1301. METADATA_PERMISSION_WRITE,
  1302. OPEN_TIMEOUT_VALUE,
  1303. &mhOpenHandle);
  1304. if (SUCCEEDED(hresReturn))
  1305. {
  1306. MD_SET_DATA_RECORD_EXT(&mdrData,
  1307. dwPasswordMetaId,
  1308. METADATA_INHERIT | METADATA_SECURE,
  1309. IIS_MD_UT_FILE,
  1310. STRING_METADATA,
  1311. sizeof(pstPasswordBuf),
  1312. (PBYTE)pstPasswordBuf)
  1313. hresReturn = pcCom->ComMDSetMetaData(mhOpenHandle,
  1314. NULL,
  1315. &mdrData);
  1316. pcCom->ComMDCloseMetaObject(mhOpenHandle);
  1317. }
  1318. return SUCCEEDED(hresReturn);
  1319. }
  1320. BOOL
  1321. DoesUserExist(
  1322. LPWSTR strUsername,
  1323. BOOL *fDisabled)
  1324. {
  1325. BYTE *pBuffer;
  1326. INT err = NERR_Success;
  1327. BOOL fReturn = FALSE;
  1328. *fDisabled = FALSE;
  1329. err = NetUserGetInfo( NULL, strUsername, 3, &pBuffer );
  1330. if ( err == NERR_Success )
  1331. {
  1332. *fDisabled = !!(((PUSER_INFO_3)pBuffer)->usri3_flags & UF_ACCOUNTDISABLE);
  1333. NetApiBufferFree( pBuffer );
  1334. fReturn = TRUE;
  1335. }
  1336. return( fReturn );
  1337. }
  1338. NET_API_STATUS
  1339. NetpNtStatusToApiStatus (
  1340. IN NTSTATUS NtStatus)
  1341. /*++
  1342. Routine Description:
  1343. This function takes an NT status code and maps it to the appropriate
  1344. LAN Man error code.
  1345. Arguments:
  1346. NtStatus - Supplies the NT status.
  1347. Return Value:
  1348. Returns the appropriate LAN Man error code for the NT status.
  1349. --*/
  1350. {
  1351. NET_API_STATUS error;
  1352. //
  1353. // A small optimization for the most common case.
  1354. //
  1355. if ( NtStatus == STATUS_SUCCESS )
  1356. {
  1357. return NERR_Success;
  1358. }
  1359. switch ( NtStatus )
  1360. {
  1361. case STATUS_BUFFER_TOO_SMALL :
  1362. return NERR_BufTooSmall;
  1363. case STATUS_FILES_OPEN :
  1364. return NERR_OpenFiles;
  1365. case STATUS_CONNECTION_IN_USE :
  1366. return NERR_DevInUse;
  1367. case STATUS_INVALID_LOGON_HOURS :
  1368. return NERR_InvalidLogonHours;
  1369. case STATUS_INVALID_WORKSTATION :
  1370. return NERR_InvalidWorkstation;
  1371. case STATUS_PASSWORD_EXPIRED :
  1372. return NERR_PasswordExpired;
  1373. case STATUS_ACCOUNT_EXPIRED :
  1374. return NERR_AccountExpired;
  1375. case STATUS_REDIRECTOR_NOT_STARTED :
  1376. return NERR_NetNotStarted;
  1377. case STATUS_GROUP_EXISTS:
  1378. return NERR_GroupExists;
  1379. case STATUS_INTERNAL_DB_CORRUPTION:
  1380. return NERR_InvalidDatabase;
  1381. case STATUS_INVALID_ACCOUNT_NAME:
  1382. return NERR_BadUsername;
  1383. case STATUS_INVALID_DOMAIN_ROLE:
  1384. case STATUS_INVALID_SERVER_STATE:
  1385. case STATUS_BACKUP_CONTROLLER:
  1386. return NERR_NotPrimary;
  1387. case STATUS_INVALID_DOMAIN_STATE:
  1388. return NERR_ACFNotLoaded;
  1389. case STATUS_MEMBER_IN_GROUP:
  1390. return NERR_UserInGroup;
  1391. case STATUS_MEMBER_NOT_IN_GROUP:
  1392. return NERR_UserNotInGroup;
  1393. case STATUS_NONE_MAPPED:
  1394. case STATUS_NO_SUCH_GROUP:
  1395. return NERR_GroupNotFound;
  1396. case STATUS_SPECIAL_GROUP:
  1397. case STATUS_MEMBERS_PRIMARY_GROUP:
  1398. return NERR_SpeGroupOp;
  1399. case STATUS_USER_EXISTS:
  1400. return NERR_UserExists;
  1401. case STATUS_NO_SUCH_USER:
  1402. return NERR_UserNotFound;
  1403. case STATUS_PRIVILEGE_NOT_HELD:
  1404. return ERROR_ACCESS_DENIED;
  1405. case STATUS_LOGON_SERVER_CONFLICT:
  1406. return NERR_LogonServerConflict;
  1407. case STATUS_TIME_DIFFERENCE_AT_DC:
  1408. return NERR_TimeDiffAtDC;
  1409. case STATUS_SYNCHRONIZATION_REQUIRED:
  1410. return NERR_SyncRequired;
  1411. case STATUS_WRONG_PASSWORD_CORE:
  1412. return NERR_BadPasswordCore;
  1413. case STATUS_DOMAIN_CONTROLLER_NOT_FOUND:
  1414. return NERR_DCNotFound;
  1415. case STATUS_PASSWORD_RESTRICTION:
  1416. return NERR_PasswordTooShort;
  1417. case STATUS_ALREADY_DISCONNECTED:
  1418. return NERR_Success;
  1419. default:
  1420. //
  1421. // Use the system routine to do the mapping to ERROR_ codes.
  1422. //
  1423. #ifndef WIN32_CHICAGO
  1424. error = RtlNtStatusToDosError( NtStatus );
  1425. if ( error != (NET_API_STATUS)NtStatus )
  1426. {
  1427. return error;
  1428. }
  1429. #endif // WIN32_CHICAGO
  1430. //
  1431. // Could not map the NT status to anything appropriate.
  1432. //
  1433. return NERR_InternalError;
  1434. }
  1435. } // NetpNtStatusToApiStatus
  1436. NET_API_STATUS
  1437. UaspGetDomainId(
  1438. IN LPCWSTR ServerName OPTIONAL,
  1439. OUT PSAM_HANDLE SamServerHandle OPTIONAL,
  1440. OUT PPOLICY_ACCOUNT_DOMAIN_INFO * AccountDomainInfo
  1441. )
  1442. /*++
  1443. Routine Description:
  1444. Return a domain ID of the account domain of a server.
  1445. Arguments:
  1446. ServerName - A pointer to a string containing the name of the
  1447. Domain Controller (DC) to query. A NULL pointer
  1448. or string specifies the local machine.
  1449. SamServerHandle - Returns the SAM connection handle if the caller wants it.
  1450. DomainId - Receives a pointer to the domain ID.
  1451. Caller must deallocate buffer using NetpMemoryFree.
  1452. Return Value:
  1453. Error code for the operation.
  1454. --*/
  1455. {
  1456. NET_API_STATUS NetStatus;
  1457. NTSTATUS Status;
  1458. SAM_HANDLE LocalSamHandle = NULL;
  1459. ACCESS_MASK LSADesiredAccess;
  1460. LSA_HANDLE LSAPolicyHandle = NULL;
  1461. OBJECT_ATTRIBUTES LSAObjectAttributes;
  1462. UNICODE_STRING ServerNameString;
  1463. //
  1464. // Connect to the SAM server
  1465. //
  1466. RtlInitUnicodeString( &ServerNameString, ServerName );
  1467. Status = SamConnect(
  1468. &ServerNameString,
  1469. &LocalSamHandle,
  1470. SAM_SERVER_LOOKUP_DOMAIN,
  1471. NULL);
  1472. if ( !NT_SUCCESS(Status))
  1473. {
  1474. LocalSamHandle = NULL;
  1475. NetStatus = NetpNtStatusToApiStatus( Status );
  1476. goto Cleanup;
  1477. }
  1478. //
  1479. // Open LSA to read account domain info.
  1480. //
  1481. if ( AccountDomainInfo != NULL)
  1482. {
  1483. //
  1484. // set desired access mask.
  1485. //
  1486. LSADesiredAccess = POLICY_VIEW_LOCAL_INFORMATION;
  1487. InitializeObjectAttributes( &LSAObjectAttributes,
  1488. NULL, // Name
  1489. 0, // Attributes
  1490. NULL, // Root
  1491. NULL ); // Security Descriptor
  1492. Status = LsaOpenPolicy( &ServerNameString,
  1493. &LSAObjectAttributes,
  1494. LSADesiredAccess,
  1495. &LSAPolicyHandle );
  1496. if( !NT_SUCCESS(Status) )
  1497. {
  1498. NetStatus = NetpNtStatusToApiStatus( Status );
  1499. goto Cleanup;
  1500. }
  1501. //
  1502. // now read account domain info from LSA.
  1503. //
  1504. Status = LsaQueryInformationPolicy(
  1505. LSAPolicyHandle,
  1506. PolicyAccountDomainInformation,
  1507. (PVOID *) AccountDomainInfo );
  1508. if( !NT_SUCCESS(Status) )
  1509. {
  1510. NetStatus = NetpNtStatusToApiStatus( Status );
  1511. goto Cleanup;
  1512. }
  1513. }
  1514. //
  1515. // Return the SAM connection handle to the caller if he wants it.
  1516. // Otherwise, disconnect from SAM.
  1517. //
  1518. if ( ARGUMENT_PRESENT( SamServerHandle ) )
  1519. {
  1520. *SamServerHandle = LocalSamHandle;
  1521. LocalSamHandle = NULL;
  1522. }
  1523. NetStatus = NERR_Success;
  1524. //
  1525. // Cleanup locally used resources
  1526. //
  1527. Cleanup:
  1528. if ( LocalSamHandle != NULL )
  1529. {
  1530. (VOID) SamCloseHandle( LocalSamHandle );
  1531. }
  1532. if( LSAPolicyHandle != NULL )
  1533. {
  1534. LsaClose( LSAPolicyHandle );
  1535. }
  1536. return NetStatus;
  1537. } // UaspGetDomainId
  1538. NET_API_STATUS
  1539. SampCreateFullSid(
  1540. IN PSID DomainSid,
  1541. IN ULONG Rid,
  1542. OUT PSID *AccountSid)
  1543. /*++
  1544. Routine Description:
  1545. This function creates a domain account sid given a domain sid and
  1546. the relative id of the account within the domain.
  1547. The returned Sid may be freed with LocalFree.
  1548. --*/
  1549. {
  1550. NET_API_STATUS NetStatus;
  1551. NTSTATUS IgnoreStatus;
  1552. UCHAR AccountSubAuthorityCount;
  1553. ULONG AccountSidLength;
  1554. PULONG RidLocation;
  1555. //
  1556. // Calculate the size of the new sid
  1557. //
  1558. AccountSubAuthorityCount = *RtlSubAuthorityCountSid(DomainSid) + (UCHAR)1;
  1559. AccountSidLength = RtlLengthRequiredSid(AccountSubAuthorityCount);
  1560. //
  1561. // Allocate space for the account sid
  1562. //
  1563. *AccountSid = LocalAlloc(LMEM_ZEROINIT,AccountSidLength);
  1564. if (*AccountSid == NULL)
  1565. {
  1566. NetStatus = ERROR_NOT_ENOUGH_MEMORY;
  1567. }
  1568. else
  1569. {
  1570. //
  1571. // Copy the domain sid into the first part of the account sid
  1572. //
  1573. IgnoreStatus = RtlCopySid(AccountSidLength, *AccountSid, DomainSid);
  1574. ASSERT(NT_SUCCESS(IgnoreStatus));
  1575. //
  1576. // Increment the account sid sub-authority count
  1577. //
  1578. *RtlSubAuthorityCountSid(*AccountSid) = AccountSubAuthorityCount;
  1579. //
  1580. // Add the rid as the final sub-authority
  1581. //
  1582. RidLocation = RtlSubAuthoritySid(*AccountSid, AccountSubAuthorityCount-1);
  1583. *RidLocation = Rid;
  1584. NetStatus = NERR_Success;
  1585. }
  1586. return(NetStatus);
  1587. }
  1588. BOOL
  1589. GetGuestUserNameForDomain_FastWay(
  1590. LPTSTR szDomainToLookUp,
  1591. LPTSTR lpGuestUsrName,
  1592. DWORD cchGuestUsrName)
  1593. {
  1594. HRESULT hr = S_OK;
  1595. BOOL fReturn = FALSE;
  1596. NET_API_STATUS NetStatus;
  1597. SAM_HANDLE SamServerHandle = NULL; // for UaspGetDomainId()
  1598. PPOLICY_ACCOUNT_DOMAIN_INFO pAccountDomainInfo = NULL;
  1599. PSID pAccountSid = NULL;
  1600. PSID pDomainSid = NULL;
  1601. SID_NAME_USE sidNameUse = SidTypeUser; // for LookupAccountSid()
  1602. TCHAR szUserName[UNLEN+1];
  1603. DWORD cbName = UNLEN+1;
  1604. TCHAR szReferencedDomainName[UNLEN+1]; // use UNLEN because DNLEN is too small
  1605. DWORD cbReferencedDomainName = sizeof(szReferencedDomainName);
  1606. // make sure not to return back gobble-d-gook
  1607. *lpGuestUsrName = TEXT('\0');
  1608. //
  1609. // Get the Sid for the specified Domain
  1610. //
  1611. // szDomainToLookUp=NULL for local machine
  1612. NetStatus = UaspGetDomainId( szDomainToLookUp,&SamServerHandle,&pAccountDomainInfo );
  1613. if ( NetStatus != NERR_Success )
  1614. {
  1615. goto GetGuestUserNameForDomain_FastWay_Exit;
  1616. }
  1617. pDomainSid = pAccountDomainInfo->DomainSid;
  1618. //
  1619. // Use the Domain Sid and the well known Guest RID to create the Real Guest Sid
  1620. //
  1621. // Well-known users ...
  1622. // DOMAIN_USER_RID_ADMIN (0x000001F4L)
  1623. // DOMAIN_USER_RID_GUEST (0x000001F5L)
  1624. NetStatus = NERR_InternalError;
  1625. NetStatus = SampCreateFullSid(pDomainSid, DOMAIN_USER_RID_GUEST, &pAccountSid);
  1626. if ( NetStatus != NERR_Success )
  1627. {
  1628. goto GetGuestUserNameForDomain_FastWay_Exit;
  1629. }
  1630. //
  1631. // Check if the SID is valid
  1632. //
  1633. if (0 == IsValidSid(pAccountSid))
  1634. {
  1635. goto GetGuestUserNameForDomain_FastWay_Exit;
  1636. }
  1637. //
  1638. // Retrieve the UserName for the specified SID
  1639. //
  1640. *szUserName = TEXT('\0');
  1641. *szReferencedDomainName = TEXT('\0');
  1642. // szDomainToLookUp=NULL for local machine
  1643. if (!LookupAccountSid(szDomainToLookUp,
  1644. pAccountSid,
  1645. szUserName,
  1646. &cbName,
  1647. szReferencedDomainName,
  1648. &cbReferencedDomainName,
  1649. &sidNameUse))
  1650. {
  1651. goto GetGuestUserNameForDomain_FastWay_Exit;
  1652. }
  1653. // Return the guest user name that we got.
  1654. hr = StringCchCopy(lpGuestUsrName, cchGuestUsrName, szUserName);
  1655. if ( FAILED(hr) )
  1656. {
  1657. *lpGuestUsrName = TEXT('\0');
  1658. goto GetGuestUserNameForDomain_FastWay_Exit;
  1659. }
  1660. // Wow, after all that, we must have succeeded
  1661. fReturn = TRUE;
  1662. GetGuestUserNameForDomain_FastWay_Exit:
  1663. // Free the Domain info if we got some
  1664. if (pAccountDomainInfo)
  1665. {
  1666. NetpMemoryFree(pAccountDomainInfo);
  1667. }
  1668. // Free the sid if we had allocated one
  1669. if (pAccountSid)
  1670. {
  1671. LocalFree(pAccountSid);
  1672. }
  1673. return fReturn;
  1674. }
  1675. BOOL
  1676. GetGuestUserName_SlowWay(
  1677. LPWSTR lpGuestUsrName,
  1678. DWORD cchGuestUsrName)
  1679. {
  1680. HRESULT hr = S_OK;
  1681. LPWSTR ServerName = NULL; // default to local machine
  1682. DWORD Level = 1; // to retrieve info of all local and global normal user accounts
  1683. DWORD Index = 0;
  1684. DWORD EntriesRequested = 5;
  1685. DWORD PreferredMaxLength = 1024;
  1686. DWORD ReturnedEntryCount = 0;
  1687. PVOID SortedBuffer = NULL;
  1688. NET_DISPLAY_USER *p = NULL;
  1689. DWORD i=0;
  1690. int err = 0;
  1691. BOOL fStatus = TRUE;
  1692. while (fStatus)
  1693. {
  1694. err = NetQueryDisplayInformation(ServerName,
  1695. Level,
  1696. Index,
  1697. EntriesRequested,
  1698. PreferredMaxLength,
  1699. &ReturnedEntryCount,
  1700. &SortedBuffer);
  1701. if (err == NERR_Success)
  1702. {
  1703. fStatus = FALSE;
  1704. }
  1705. if (err == NERR_Success || err == ERROR_MORE_DATA)
  1706. {
  1707. p = (NET_DISPLAY_USER *)SortedBuffer;
  1708. i = 0;
  1709. while (i < ReturnedEntryCount && (p[i].usri1_user_id != DOMAIN_USER_RID_GUEST))
  1710. {
  1711. i++;
  1712. }
  1713. if (i == ReturnedEntryCount)
  1714. {
  1715. if (err == ERROR_MORE_DATA)
  1716. {
  1717. // need to get more entries
  1718. Index = p[i-1].usri1_next_index;
  1719. }
  1720. }
  1721. else
  1722. {
  1723. hr = StringCchCopyW(lpGuestUsrName, cchGuestUsrName, p[i].usri1_name);
  1724. if ( FAILED(hr) )
  1725. {
  1726. NetApiBufferFree(SortedBuffer);
  1727. SortedBuffer = NULL;
  1728. *lpGuestUsrName = TEXT('\0');
  1729. return FALSE;
  1730. }
  1731. fStatus = FALSE;
  1732. }
  1733. }
  1734. else
  1735. {
  1736. if ( SortedBuffer != NULL )
  1737. {
  1738. NetApiBufferFree(SortedBuffer);
  1739. SortedBuffer = NULL;
  1740. }
  1741. return FALSE;
  1742. }
  1743. NetApiBufferFree(SortedBuffer);
  1744. SortedBuffer = NULL;
  1745. }
  1746. return TRUE;
  1747. }
  1748. BOOL
  1749. GetGuestUserName(
  1750. LPTSTR lpOutGuestUsrName,
  1751. DWORD cchOutGuestUsrName)
  1752. {
  1753. HRESULT hr = S_OK;
  1754. TCHAR szGuestUsrName[UNLEN+1];
  1755. LPTSTR pszComputerName = NULL;
  1756. // try to retrieve the guest username the fast way
  1757. // meaning = lookup the domain sid, and the well known guest rid, to get the guest sid.
  1758. // then look it up. The reason for this function is that on large domains with mega users
  1759. // the account can be quickly looked up.
  1760. if (!GetGuestUserNameForDomain_FastWay(pszComputerName, szGuestUsrName, UNLEN+1))
  1761. {
  1762. // if the fast way failed for some reason, then let's do it
  1763. // the slow way, since this way always used to work, only on large domains (1 mil users)
  1764. // it could take 24hrs (since this function actually enumerates thru the domain)
  1765. if (!GetGuestUserName_SlowWay(szGuestUsrName, UNLEN+1))
  1766. {
  1767. return FALSE;
  1768. }
  1769. }
  1770. // Return back the username
  1771. hr = StringCchCopyW(lpOutGuestUsrName, cchOutGuestUsrName, szGuestUsrName);
  1772. if ( FAILED(hr) )
  1773. {
  1774. return FALSE;
  1775. }
  1776. return TRUE;
  1777. }
  1778. int
  1779. GetGuestGrpName(
  1780. LPTSTR lpGuestGrpName)
  1781. {
  1782. LPCTSTR ServerName = NULL; // local machine
  1783. DWORD cbName = UNLEN+1; // use UNLEN because DNLEN is too small
  1784. TCHAR ReferencedDomainName[UNLEN+1];
  1785. DWORD cbReferencedDomainName = sizeof(ReferencedDomainName) / sizeof(TCHAR);
  1786. SID_NAME_USE sidNameUse = SidTypeUser;
  1787. SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
  1788. PSID GuestsSid = NULL;
  1789. AllocateAndInitializeSid(&NtAuthority,
  1790. 2,
  1791. SECURITY_BUILTIN_DOMAIN_RID,
  1792. DOMAIN_ALIAS_RID_GUESTS,
  1793. 0,
  1794. 0,
  1795. 0,
  1796. 0,
  1797. 0,
  1798. 0,
  1799. &GuestsSid);
  1800. LookupAccountSid(ServerName,
  1801. GuestsSid,
  1802. lpGuestGrpName,
  1803. &cbName,
  1804. ReferencedDomainName,
  1805. &cbReferencedDomainName,
  1806. &sidNameUse);
  1807. if (GuestsSid)
  1808. {
  1809. FreeSid(GuestsSid);
  1810. }
  1811. return 0;
  1812. }
  1813. INT
  1814. RegisterAccountToLocalGroup(
  1815. LPCTSTR szAccountName,
  1816. LPCTSTR szLocalGroupName,
  1817. BOOL fAction)
  1818. {
  1819. HRESULT hr = S_OK;
  1820. int err;
  1821. PSID pSID = NULL;
  1822. BOOL bWellKnownSID = FALSE;
  1823. TCHAR szLocalizedLocalGroupName[GNLEN + 1] = TEXT( "\0" ) ;
  1824. WCHAR wszLocalGroupName[_MAX_PATH];
  1825. LOCALGROUP_MEMBERS_INFO_0 buf;
  1826. // get the sid of szAccountName
  1827. err = GetPrincipalSID ((LPTSTR)szAccountName, &pSID, &bWellKnownSID);
  1828. if (err != ERROR_SUCCESS)
  1829. {
  1830. return (err);
  1831. }
  1832. // Get the localized LocalGroupName
  1833. if (_wcsicmp(szLocalGroupName, TEXT("Guests")) == 0)
  1834. {
  1835. GetGuestGrpName(szLocalizedLocalGroupName);
  1836. }
  1837. else
  1838. {
  1839. hr = StringCchCopy(szLocalizedLocalGroupName, ARRAYSIZE(szLocalizedLocalGroupName), szLocalGroupName);
  1840. if ( FAILED(hr) )
  1841. {
  1842. err = (INT)HRESULTTOWIN32(hr);
  1843. goto exit;
  1844. }
  1845. }
  1846. // transfer szLocalGroupName to WCHAR
  1847. hr = StringCchCopyW(wszLocalGroupName, ARRAYSIZE(wszLocalGroupName), szLocalizedLocalGroupName);
  1848. if ( FAILED(hr) )
  1849. {
  1850. err = (INT)HRESULTTOWIN32(hr);
  1851. goto exit;
  1852. }
  1853. buf.lgrmi0_sid = pSID;
  1854. if (fAction)
  1855. {
  1856. err = NetLocalGroupAddMembers(NULL, wszLocalGroupName, 0, (LPBYTE)&buf, 1);
  1857. }
  1858. else
  1859. {
  1860. err = NetLocalGroupDelMembers(NULL, wszLocalGroupName, 0, (LPBYTE)&buf, 1);
  1861. }
  1862. exit:
  1863. if (pSID)
  1864. {
  1865. if (bWellKnownSID)
  1866. {
  1867. FreeSid (pSID);
  1868. }
  1869. else
  1870. {
  1871. free (pSID);
  1872. }
  1873. }
  1874. return (err);
  1875. }
  1876. void
  1877. InitLsaString(
  1878. PLSA_UNICODE_STRING LsaString,
  1879. LPWSTR String)
  1880. {
  1881. DWORD StringLength;
  1882. if (String == NULL)
  1883. {
  1884. LsaString->Buffer = NULL;
  1885. LsaString->Length = 0;
  1886. LsaString->MaximumLength = 0;
  1887. return;
  1888. }
  1889. StringLength = (DWORD)wcslen(String);
  1890. LsaString->Buffer = String;
  1891. LsaString->Length = (USHORT) StringLength * sizeof(WCHAR);
  1892. LsaString->MaximumLength=(USHORT)(StringLength+1) * sizeof(WCHAR);
  1893. }
  1894. DWORD
  1895. OpenPolicy(
  1896. LPTSTR ServerName,
  1897. DWORD DesiredAccess,
  1898. PLSA_HANDLE PolicyHandle)
  1899. {
  1900. DWORD Error;
  1901. LSA_OBJECT_ATTRIBUTES ObjectAttributes;
  1902. LSA_UNICODE_STRING ServerString;
  1903. PLSA_UNICODE_STRING Server = NULL;
  1904. SECURITY_QUALITY_OF_SERVICE QualityOfService;
  1905. QualityOfService.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
  1906. QualityOfService.ImpersonationLevel = SecurityImpersonation;
  1907. QualityOfService.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
  1908. QualityOfService.EffectiveOnly = FALSE;
  1909. //
  1910. // The two fields that must be set are length and the quality of service.
  1911. //
  1912. ObjectAttributes.Length = sizeof(LSA_OBJECT_ATTRIBUTES);
  1913. ObjectAttributes.RootDirectory = NULL;
  1914. ObjectAttributes.ObjectName = NULL;
  1915. ObjectAttributes.Attributes = 0;
  1916. ObjectAttributes.SecurityDescriptor = NULL;
  1917. ObjectAttributes.SecurityQualityOfService = &QualityOfService;
  1918. if (ServerName != NULL)
  1919. {
  1920. //
  1921. // Make a LSA_UNICODE_STRING out of the LPWSTR passed in
  1922. //
  1923. InitLsaString(&ServerString,ServerName);
  1924. Server = &ServerString;
  1925. }
  1926. //
  1927. // Attempt to open the policy for all access
  1928. //
  1929. Error = LsaOpenPolicy(Server,&ObjectAttributes,DesiredAccess,PolicyHandle);
  1930. return(Error);
  1931. }
  1932. INT
  1933. RegisterAccountUserRights(
  1934. LPCTSTR szAccountName,
  1935. BOOL fAction,
  1936. BOOL fSpecicaliWamAccount)
  1937. {
  1938. int err;
  1939. PSID pSID = NULL;
  1940. BOOL bWellKnownSID = FALSE;
  1941. LSA_UNICODE_STRING UserRightString;
  1942. LSA_HANDLE PolicyHandle = NULL;
  1943. // get the sid of szAccountName
  1944. err = GetPrincipalSID ((LPTSTR)szAccountName, &pSID, &bWellKnownSID);
  1945. if (err != ERROR_SUCCESS)
  1946. {
  1947. return (err);
  1948. }
  1949. err = OpenPolicy(NULL, POLICY_ALL_ACCESS,&PolicyHandle);
  1950. if ( err == NERR_Success )
  1951. {
  1952. if (fAction)
  1953. {
  1954. // defined in ntsecapi.h and ntlsa.h
  1955. //#define SE_INTERACTIVE_LOGON_NAME TEXT("SeInteractiveLogonRight")
  1956. //#define SE_NETWORK_LOGON_NAME TEXT("SeNetworkLogonRight")
  1957. //#define SE_BATCH_LOGON_NAME TEXT("SeBatchLogonRight")
  1958. //#define SE_SERVICE_LOGON_NAME TEXT("SeServiceLogonRight")
  1959. // Defined in winnt.h
  1960. //#define SE_CREATE_TOKEN_NAME TEXT("SeCreateTokenPrivilege")
  1961. //#define SE_ASSIGNPRIMARYTOKEN_NAME TEXT("SeAssignPrimaryTokenPrivilege")
  1962. //#define SE_LOCK_MEMORY_NAME TEXT("SeLockMemoryPrivilege")
  1963. //#define SE_INCREASE_QUOTA_NAME TEXT("SeIncreaseQuotaPrivilege")
  1964. //#define SE_UNSOLICITED_INPUT_NAME TEXT("SeUnsolicitedInputPrivilege")
  1965. //#define SE_MACHINE_ACCOUNT_NAME TEXT("SeMachineAccountPrivilege")
  1966. //#define SE_TCB_NAME TEXT("SeTcbPrivilege")
  1967. //#define SE_SECURITY_NAME TEXT("SeSecurityPrivilege")
  1968. //#define SE_TAKE_OWNERSHIP_NAME TEXT("SeTakeOwnershipPrivilege")
  1969. //#define SE_LOAD_DRIVER_NAME TEXT("SeLoadDriverPrivilege")
  1970. //#define SE_SYSTEM_PROFILE_NAME TEXT("SeSystemProfilePrivilege")
  1971. //#define SE_SYSTEMTIME_NAME TEXT("SeSystemtimePrivilege")
  1972. //#define SE_PROF_SINGLE_PROCESS_NAME TEXT("SeProfileSingleProcessPrivilege")
  1973. //#define SE_INC_BASE_PRIORITY_NAME TEXT("SeIncreaseBasePriorityPrivilege")
  1974. //#define SE_CREATE_PAGEFILE_NAME TEXT("SeCreatePagefilePrivilege")
  1975. //#define SE_CREATE_PERMANENT_NAME TEXT("SeCreatePermanentPrivilege")
  1976. //#define SE_BACKUP_NAME TEXT("SeBackupPrivilege")
  1977. //#define SE_RESTORE_NAME TEXT("SeRestorePrivilege")
  1978. //#define SE_SHUTDOWN_NAME TEXT("SeShutdownPrivilege")
  1979. //#define SE_DEBUG_NAME TEXT("SeDebugPrivilege")
  1980. //#define SE_AUDIT_NAME TEXT("SeAuditPrivilege")
  1981. //#define SE_SYSTEM_ENVIRONMENT_NAME TEXT("SeSystemEnvironmentPrivilege")
  1982. //#define SE_CHANGE_NOTIFY_NAME TEXT("SeChangeNotifyPrivilege")
  1983. //#define SE_REMOTE_SHUTDOWN_NAME TEXT("SeRemoteShutdownPrivilege")
  1984. //#define SE_UNDOCK_NAME TEXT("SeUndockPrivilege")
  1985. //#define SE_SYNC_AGENT_NAME TEXT("SeSyncAgentPrivilege")
  1986. //#define SE_ENABLE_DELEGATION_NAME TEXT("SeEnableDelegationPrivilege")
  1987. if (fSpecicaliWamAccount)
  1988. {
  1989. // no interactive logon for iwam!
  1990. InitLsaString(&UserRightString, SE_NETWORK_LOGON_NAME);
  1991. err = LsaAddAccountRights(PolicyHandle, pSID, &UserRightString, 1);
  1992. InitLsaString(&UserRightString, SE_BATCH_LOGON_NAME);
  1993. err = LsaAddAccountRights(PolicyHandle, pSID, &UserRightString, 1);
  1994. }
  1995. else
  1996. {
  1997. InitLsaString(&UserRightString, SE_INTERACTIVE_LOGON_NAME);
  1998. err = LsaAddAccountRights(PolicyHandle, pSID, &UserRightString, 1);
  1999. InitLsaString(&UserRightString, SE_NETWORK_LOGON_NAME);
  2000. err = LsaAddAccountRights(PolicyHandle, pSID, &UserRightString, 1);
  2001. InitLsaString(&UserRightString, SE_BATCH_LOGON_NAME);
  2002. err = LsaAddAccountRights(PolicyHandle, pSID, &UserRightString, 1);
  2003. }
  2004. }
  2005. else
  2006. {
  2007. InitLsaString(&UserRightString, SE_INTERACTIVE_LOGON_NAME);
  2008. err = LsaRemoveAccountRights(PolicyHandle, pSID, FALSE, &UserRightString,1);
  2009. InitLsaString(&UserRightString, SE_NETWORK_LOGON_NAME);
  2010. err = LsaRemoveAccountRights(PolicyHandle, pSID, FALSE, &UserRightString,1);
  2011. InitLsaString(&UserRightString, SE_BATCH_LOGON_NAME);
  2012. err = LsaRemoveAccountRights(PolicyHandle, pSID, FALSE, &UserRightString,1);
  2013. }
  2014. LsaClose(PolicyHandle);
  2015. }
  2016. if (pSID)
  2017. {
  2018. if (bWellKnownSID)
  2019. {
  2020. FreeSid (pSID);
  2021. }
  2022. else
  2023. {
  2024. free (pSID);
  2025. }
  2026. }
  2027. return (err);
  2028. }
  2029. int
  2030. ChangeUserPassword(
  2031. IN LPTSTR szUserName,
  2032. IN LPTSTR szNewPassword)
  2033. {
  2034. HRESULT hr = S_OK;
  2035. int iReturn = TRUE;
  2036. USER_INFO_1003 pi1003;
  2037. NET_API_STATUS nas;
  2038. TCHAR szRawComputerName[CNLEN + 10];
  2039. DWORD dwLen = CNLEN + 10;
  2040. TCHAR szComputerName[CNLEN + 10];
  2041. TCHAR szCopyOfUserName[UNLEN+10];
  2042. TCHAR szTempFullUserName[(CNLEN + 10) + (UNLEN+1)];
  2043. LPTSTR pch = NULL;
  2044. hr = StringCchCopy(szCopyOfUserName, ARRAYSIZE(szCopyOfUserName), szUserName);
  2045. if ( FAILED(hr) )
  2046. {
  2047. iReturn = FALSE;
  2048. goto ChangeUserPassword_Exit;
  2049. }
  2050. //iisDebugOut((LOG_TYPE_TRACE_WIN32_API, _T("ChangeUserPassword().Start.name=%s,pass=%s"),szCopyOfUserName,szNewPassword));
  2051. if ( !GetComputerName( szRawComputerName, &dwLen ))
  2052. {
  2053. iReturn = FALSE;
  2054. goto ChangeUserPassword_Exit;
  2055. }
  2056. // Make a copy to be sure not to move the pointer around.
  2057. hr = StringCchCopy(szTempFullUserName, ARRAYSIZE(szTempFullUserName), szCopyOfUserName);
  2058. if ( FAILED(hr) )
  2059. {
  2060. iReturn = FALSE;
  2061. goto ChangeUserPassword_Exit;
  2062. }
  2063. // Check if there is a "\" in there.
  2064. pch = wcschr(szTempFullUserName, '\\');
  2065. if (pch)
  2066. {
  2067. // szCopyOfUserName should now go from something like this:
  2068. // mycomputer\myuser
  2069. // to this myuser
  2070. hr = StringCchCopy(szCopyOfUserName, ARRAYSIZE(szCopyOfUserName), pch+1);
  2071. if ( FAILED(hr) )
  2072. {
  2073. iReturn = FALSE;
  2074. goto ChangeUserPassword_Exit;
  2075. }
  2076. // trim off the '\' character to leave just the domain\computername so we can check against it.
  2077. *pch = '\0';
  2078. // compare the szTempFullUserName with the local computername.
  2079. if (0 == _wcsicmp(szRawComputerName, szTempFullUserName))
  2080. {
  2081. // the computername\username has a hardcoded computername in it.
  2082. // lets try to get only the username
  2083. // look szCopyOfusername is already set
  2084. }
  2085. else
  2086. {
  2087. // the local computer machine name
  2088. // and the specified username are different, so get out
  2089. // and don't even try to change this user\password since
  2090. // it's probably a domain\username
  2091. // return true -- saying that we did in fact change the passoword.
  2092. // we really didn't but we can't
  2093. iReturn = TRUE;
  2094. goto ChangeUserPassword_Exit;
  2095. }
  2096. }
  2097. // Make sure the computername has a \\ in front of it
  2098. if ( szRawComputerName[0] != '\\' )
  2099. {
  2100. hr = StringCchCopyW(szComputerName, ARRAYSIZE(szComputerName), L"\\\\");
  2101. if ( FAILED(hr) )
  2102. {
  2103. iReturn = FALSE;
  2104. goto ChangeUserPassword_Exit;
  2105. }
  2106. }
  2107. hr = StringCchCatW(szComputerName, ARRAYSIZE(szComputerName), szRawComputerName);
  2108. if ( FAILED(hr) )
  2109. {
  2110. iReturn = FALSE;
  2111. goto ChangeUserPassword_Exit;
  2112. }
  2113. //
  2114. // administrative over-ride of existing password
  2115. //
  2116. // by this time szCopyOfUserName
  2117. // should not look like mycomputername\username but it should look like username.
  2118. pi1003.usri1003_password = szNewPassword;
  2119. nas = NetUserSetInfo(
  2120. szComputerName, // computer name
  2121. szCopyOfUserName, // username
  2122. 1003, // info level
  2123. (LPBYTE)&pi1003, // new info
  2124. NULL
  2125. );
  2126. if(nas != NERR_Success)
  2127. {
  2128. iReturn = FALSE;
  2129. goto ChangeUserPassword_Exit;
  2130. }
  2131. ChangeUserPassword_Exit:
  2132. //iisDebugOut((LOG_TYPE_TRACE_WIN32_API, _T("ChangeUserPassword().End.Ret=%d"),iReturn));
  2133. return iReturn;
  2134. }
  2135. //
  2136. // Create InternetGuest Account
  2137. //
  2138. BOOL
  2139. CreateUser(
  2140. LPCTSTR szUsername,
  2141. LPCTSTR szPassword,
  2142. LPCTSTR szComment,
  2143. LPCTSTR szFullName,
  2144. BOOL fSpecialiWamAccount)
  2145. {
  2146. INT err = NERR_Success;
  2147. BYTE *pBuffer;
  2148. WCHAR defGuest[UNLEN+1];
  2149. TCHAR defGuestGroup[GNLEN+1];
  2150. WCHAR wchGuestGroup[GNLEN+1];
  2151. WCHAR wchUsername[UNLEN+1];
  2152. WCHAR wchPassword[LM20_PWLEN+1];
  2153. BOOL fRet;
  2154. fRet = GetGuestUserName(defGuest, UNLEN+1);
  2155. if ( !fRet )
  2156. {
  2157. return FALSE;
  2158. }
  2159. GetGuestGrpName(defGuestGroup);
  2160. SecureZeroMemory((PVOID)wchUsername, sizeof(wchUsername));
  2161. SecureZeroMemory((PVOID)wchPassword, sizeof(wchPassword));
  2162. wcsncpy(wchGuestGroup, defGuestGroup, GNLEN);
  2163. wcsncpy(wchUsername, szUsername, UNLEN);
  2164. wcsncpy(wchPassword, szPassword, LM20_PWLEN);
  2165. err = NetUserGetInfo( NULL, defGuest, 3, &pBuffer );
  2166. if ( err == NERR_Success )
  2167. {
  2168. WCHAR wchComment[MAXCOMMENTSZ+1];
  2169. WCHAR wchFullName[UNLEN+1];
  2170. memset((PVOID)wchComment, 0, sizeof(wchComment));
  2171. memset((PVOID)wchFullName, 0, sizeof(wchFullName));
  2172. wcsncpy(wchComment, szComment, MAXCOMMENTSZ);
  2173. wcsncpy(wchFullName, szFullName, UNLEN);
  2174. USER_INFO_3 *lpui3 = (USER_INFO_3 *)pBuffer;
  2175. lpui3->usri3_name = wchUsername;
  2176. lpui3->usri3_password = wchPassword;
  2177. lpui3->usri3_flags &= ~ UF_ACCOUNTDISABLE;
  2178. lpui3->usri3_flags |= UF_DONT_EXPIRE_PASSWD;
  2179. lpui3->usri3_acct_expires = TIMEQ_FOREVER;
  2180. lpui3->usri3_comment = wchComment;
  2181. lpui3->usri3_usr_comment = wchComment;
  2182. lpui3->usri3_full_name = wchFullName;
  2183. lpui3->usri3_primary_group_id = DOMAIN_GROUP_RID_USERS;
  2184. DWORD parm_err;
  2185. err = NetUserAdd( NULL, 3, pBuffer, &parm_err );
  2186. if ( err != NERR_Success )
  2187. {
  2188. if ( err == NERR_UserExists )
  2189. {
  2190. // see if we can just change the password.
  2191. if (TRUE == ChangeUserPassword((LPTSTR) szUsername, (LPTSTR) szPassword))
  2192. {
  2193. err = NERR_Success;
  2194. }
  2195. }
  2196. }
  2197. NetApiBufferFree( pBuffer );
  2198. }
  2199. if ( err == NERR_Success )
  2200. {
  2201. // add it to the guests or IIS_WPG group
  2202. if (fSpecialiWamAccount)
  2203. {
  2204. RegisterAccountToLocalGroup(szUsername, IIS_WP_GROUP, TRUE);
  2205. }
  2206. else
  2207. {
  2208. RegisterAccountToLocalGroup(szUsername, TEXT("Guests"), TRUE);
  2209. }
  2210. // add certain user rights to this account
  2211. RegisterAccountUserRights(szUsername, TRUE, fSpecialiWamAccount);
  2212. }
  2213. return err == NERR_Success;
  2214. }
  2215. INT
  2216. DeleteGuestUser(
  2217. LPCTSTR szUsername)
  2218. {
  2219. INT err = NERR_Success;
  2220. BOOL fDisabled;
  2221. WCHAR wchUsername[UNLEN+1];
  2222. wcsncpy(wchUsername, szUsername, UNLEN);
  2223. if (FALSE == DoesUserExist(wchUsername,&fDisabled))
  2224. {
  2225. return err;
  2226. }
  2227. // remove it from the guests group
  2228. RegisterAccountToLocalGroup(szUsername, TEXT("Guests"), FALSE);
  2229. // remove certain user rights of this account
  2230. RegisterAccountUserRights(szUsername, FALSE, TRUE);
  2231. err = ::NetUserDel( TEXT(""), wchUsername );
  2232. return err;
  2233. }
  2234. #define MAX_REALISTIC_RESOURCE_LEN MAX_PATH
  2235. BOOL
  2236. CreateUserAccount(
  2237. LPTSTR pszAnonyName,
  2238. LPTSTR pszAnonyPass,
  2239. DWORD dwUserCommentResourceId,
  2240. DWORD dwUserFullNameResourceId,
  2241. BOOL fSpecicaliWamAccount)
  2242. {
  2243. BOOL fReturn = FALSE;
  2244. WCHAR pszComment[MAX_REALISTIC_RESOURCE_LEN];
  2245. WCHAR pszFullName[MAX_REALISTIC_RESOURCE_LEN];
  2246. HMODULE hBinary;
  2247. //
  2248. // First Load the Resources
  2249. //
  2250. hBinary = GetModuleHandle(TEXT("svcext"));
  2251. if (hBinary != NULL)
  2252. {
  2253. fReturn = LoadString(hBinary,
  2254. dwUserCommentResourceId,
  2255. pszComment,
  2256. MAX_REALISTIC_RESOURCE_LEN);
  2257. if (fReturn)
  2258. {
  2259. fReturn = LoadString(hBinary,
  2260. dwUserFullNameResourceId,
  2261. pszFullName,
  2262. MAX_REALISTIC_RESOURCE_LEN);
  2263. }
  2264. }
  2265. if (fReturn)
  2266. {
  2267. fReturn = CreateUser(pszAnonyName,
  2268. pszAnonyPass,
  2269. pszComment,
  2270. pszFullName,
  2271. fSpecicaliWamAccount
  2272. );
  2273. }
  2274. if (fReturn)
  2275. {
  2276. ChangeDCOMLaunchACL(pszAnonyName,
  2277. TRUE,
  2278. TRUE);
  2279. /* removed when fixing bug 355249
  2280. ChangeDCOMAccessACL(pszAnonyName,
  2281. TRUE,
  2282. TRUE);
  2283. */
  2284. }
  2285. return fReturn;
  2286. }
  2287. typedef void (*P_SslGenerateRandomBits)( PUCHAR pRandomData, LONG size );
  2288. P_SslGenerateRandomBits ProcSslGenerateRandomBits = NULL;
  2289. BOOL
  2290. ValidatePassword(
  2291. IN LPCTSTR UserName,
  2292. IN LPCTSTR Domain,
  2293. IN LPCTSTR Password)
  2294. /*++
  2295. Routine Description:
  2296. Uses SSPI to validate the specified password
  2297. Arguments:
  2298. UserName - Supplies the user name
  2299. Domain - Supplies the user's domain
  2300. Password - Supplies the password
  2301. Return Value:
  2302. TRUE if the password is valid.
  2303. FALSE otherwise.
  2304. --*/
  2305. {
  2306. SECURITY_STATUS SecStatus;
  2307. SECURITY_STATUS AcceptStatus;
  2308. SECURITY_STATUS InitStatus;
  2309. CredHandle ClientCredHandle;
  2310. CredHandle ServerCredHandle;
  2311. BOOL ClientCredAllocated = FALSE;
  2312. BOOL ServerCredAllocated = FALSE;
  2313. CtxtHandle ClientContextHandle;
  2314. CtxtHandle ServerContextHandle;
  2315. TimeStamp Lifetime;
  2316. ULONG ContextAttributes;
  2317. PSecPkgInfo PackageInfo = NULL;
  2318. ULONG ClientFlags;
  2319. ULONG ServerFlags;
  2320. TCHAR TargetName[100];
  2321. SEC_WINNT_AUTH_IDENTITY_W AuthIdentity;
  2322. BOOL Validated = FALSE;
  2323. SecBufferDesc NegotiateDesc;
  2324. SecBuffer NegotiateBuffer;
  2325. SecBufferDesc ChallengeDesc;
  2326. SecBuffer ChallengeBuffer;
  2327. SecBufferDesc AuthenticateDesc;
  2328. SecBuffer AuthenticateBuffer;
  2329. AuthIdentity.User = (LPWSTR)UserName;
  2330. AuthIdentity.UserLength = lstrlenW(UserName);
  2331. AuthIdentity.Domain = (LPWSTR)Domain;
  2332. AuthIdentity.DomainLength = lstrlenW(Domain);
  2333. AuthIdentity.Password = (LPWSTR)Password;
  2334. AuthIdentity.PasswordLength = lstrlenW(Password);
  2335. AuthIdentity.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;
  2336. NegotiateBuffer.pvBuffer = NULL;
  2337. ChallengeBuffer.pvBuffer = NULL;
  2338. AuthenticateBuffer.pvBuffer = NULL;
  2339. //
  2340. // Get info about the security packages.
  2341. //
  2342. SecStatus = QuerySecurityPackageInfo( TEXT("NTLM"), &PackageInfo );
  2343. if ( SecStatus != STATUS_SUCCESS )
  2344. {
  2345. goto error_exit;
  2346. }
  2347. //
  2348. // Acquire a credential handle for the server side
  2349. //
  2350. SecStatus = AcquireCredentialsHandle(
  2351. NULL,
  2352. TEXT("NTLM"),
  2353. SECPKG_CRED_INBOUND,
  2354. NULL,
  2355. &AuthIdentity,
  2356. NULL,
  2357. NULL,
  2358. &ServerCredHandle,
  2359. &Lifetime );
  2360. if ( SecStatus != STATUS_SUCCESS )
  2361. {
  2362. goto error_exit;
  2363. }
  2364. ServerCredAllocated = TRUE;
  2365. //
  2366. // Acquire a credential handle for the client side
  2367. //
  2368. SecStatus = AcquireCredentialsHandle(
  2369. NULL, // New principal
  2370. TEXT("NTLM"),
  2371. SECPKG_CRED_OUTBOUND,
  2372. NULL,
  2373. &AuthIdentity,
  2374. NULL,
  2375. NULL,
  2376. &ClientCredHandle,
  2377. &Lifetime );
  2378. if ( SecStatus != STATUS_SUCCESS )
  2379. {
  2380. goto error_exit;
  2381. }
  2382. ClientCredAllocated = TRUE;
  2383. //
  2384. // Get the NegotiateMessage (ClientSide)
  2385. //
  2386. NegotiateDesc.ulVersion = 0;
  2387. NegotiateDesc.cBuffers = 1;
  2388. NegotiateDesc.pBuffers = &NegotiateBuffer;
  2389. NegotiateBuffer.cbBuffer = PackageInfo->cbMaxToken;
  2390. NegotiateBuffer.BufferType = SECBUFFER_TOKEN;
  2391. NegotiateBuffer.pvBuffer = LocalAlloc( 0, NegotiateBuffer.cbBuffer );
  2392. if ( NegotiateBuffer.pvBuffer == NULL )
  2393. {
  2394. goto error_exit;
  2395. }
  2396. ClientFlags = ISC_REQ_MUTUAL_AUTH | ISC_REQ_REPLAY_DETECT;
  2397. InitStatus = InitializeSecurityContext(
  2398. &ClientCredHandle,
  2399. NULL, // No Client context yet
  2400. NULL,
  2401. ClientFlags,
  2402. 0, // Reserved 1
  2403. SECURITY_NATIVE_DREP,
  2404. NULL, // No initial input token
  2405. 0, // Reserved 2
  2406. &ClientContextHandle,
  2407. &NegotiateDesc,
  2408. &ContextAttributes,
  2409. &Lifetime );
  2410. if ( !NT_SUCCESS(InitStatus) )
  2411. {
  2412. goto error_exit;
  2413. }
  2414. //
  2415. // Get the ChallengeMessage (ServerSide)
  2416. //
  2417. NegotiateBuffer.BufferType |= SECBUFFER_READONLY;
  2418. ChallengeDesc.ulVersion = 0;
  2419. ChallengeDesc.cBuffers = 1;
  2420. ChallengeDesc.pBuffers = &ChallengeBuffer;
  2421. ChallengeBuffer.cbBuffer = PackageInfo->cbMaxToken;
  2422. ChallengeBuffer.BufferType = SECBUFFER_TOKEN;
  2423. ChallengeBuffer.pvBuffer = LocalAlloc( 0, ChallengeBuffer.cbBuffer );
  2424. if ( ChallengeBuffer.pvBuffer == NULL )
  2425. {
  2426. goto error_exit;
  2427. }
  2428. ServerFlags = ASC_REQ_EXTENDED_ERROR;
  2429. AcceptStatus = AcceptSecurityContext(
  2430. &ServerCredHandle,
  2431. NULL, // No Server context yet
  2432. &NegotiateDesc,
  2433. ServerFlags,
  2434. SECURITY_NATIVE_DREP,
  2435. &ServerContextHandle,
  2436. &ChallengeDesc,
  2437. &ContextAttributes,
  2438. &Lifetime );
  2439. if ( !NT_SUCCESS(AcceptStatus) )
  2440. {
  2441. goto error_exit;
  2442. }
  2443. if (InitStatus != STATUS_SUCCESS)
  2444. {
  2445. //
  2446. // Get the AuthenticateMessage (ClientSide)
  2447. //
  2448. ChallengeBuffer.BufferType |= SECBUFFER_READONLY;
  2449. AuthenticateDesc.ulVersion = 0;
  2450. AuthenticateDesc.cBuffers = 1;
  2451. AuthenticateDesc.pBuffers = &AuthenticateBuffer;
  2452. AuthenticateBuffer.cbBuffer = PackageInfo->cbMaxToken;
  2453. AuthenticateBuffer.BufferType = SECBUFFER_TOKEN;
  2454. AuthenticateBuffer.pvBuffer = LocalAlloc( 0, AuthenticateBuffer.cbBuffer );
  2455. if ( AuthenticateBuffer.pvBuffer == NULL )
  2456. {
  2457. goto error_exit;
  2458. }
  2459. SecStatus = InitializeSecurityContext(
  2460. NULL,
  2461. &ClientContextHandle,
  2462. TargetName,
  2463. 0,
  2464. 0, // Reserved 1
  2465. SECURITY_NATIVE_DREP,
  2466. &ChallengeDesc,
  2467. 0, // Reserved 2
  2468. &ClientContextHandle,
  2469. &AuthenticateDesc,
  2470. &ContextAttributes,
  2471. &Lifetime );
  2472. if ( !NT_SUCCESS(SecStatus) )
  2473. {
  2474. goto error_exit;
  2475. }
  2476. if (AcceptStatus != STATUS_SUCCESS)
  2477. {
  2478. //
  2479. // Finally authenticate the user (ServerSide)
  2480. //
  2481. AuthenticateBuffer.BufferType |= SECBUFFER_READONLY;
  2482. SecStatus = AcceptSecurityContext(
  2483. NULL,
  2484. &ServerContextHandle,
  2485. &AuthenticateDesc,
  2486. ServerFlags,
  2487. SECURITY_NATIVE_DREP,
  2488. &ServerContextHandle,
  2489. NULL,
  2490. &ContextAttributes,
  2491. &Lifetime );
  2492. if ( !NT_SUCCESS(SecStatus) )
  2493. {
  2494. goto error_exit;
  2495. }
  2496. Validated = TRUE;
  2497. }
  2498. }
  2499. error_exit:
  2500. if (ServerCredAllocated)
  2501. {
  2502. FreeCredentialsHandle( &ServerCredHandle );
  2503. }
  2504. if (ClientCredAllocated)
  2505. {
  2506. FreeCredentialsHandle( &ClientCredHandle );
  2507. }
  2508. //
  2509. // Final Cleanup
  2510. //
  2511. if ( NegotiateBuffer.pvBuffer != NULL )
  2512. {
  2513. (VOID) LocalFree( NegotiateBuffer.pvBuffer );
  2514. }
  2515. if ( ChallengeBuffer.pvBuffer != NULL )
  2516. {
  2517. (VOID) LocalFree( ChallengeBuffer.pvBuffer );
  2518. }
  2519. if ( AuthenticateBuffer.pvBuffer != NULL )
  2520. {
  2521. (VOID) LocalFree( AuthenticateBuffer.pvBuffer );
  2522. }
  2523. return(Validated);
  2524. }
  2525. DWORD
  2526. ChangeAppIDAccessACL(
  2527. LPTSTR AppID,
  2528. LPTSTR Principal,
  2529. BOOL SetPrincipal,
  2530. BOOL Permit)
  2531. {
  2532. HRESULT hr = S_OK;
  2533. TCHAR keyName [256];
  2534. DWORD err;
  2535. hr = StringCchCopy( keyName, ARRAYSIZE(keyName), TEXT("APPID\\") );
  2536. if ( FAILED(hr) )
  2537. {
  2538. return HRESULTTOWIN32( hr );
  2539. }
  2540. hr = StringCchCat( keyName, ARRAYSIZE(keyName), AppID );
  2541. if ( FAILED(hr) )
  2542. {
  2543. return HRESULTTOWIN32( hr );
  2544. }
  2545. if (SetPrincipal)
  2546. {
  2547. // There is not need to check the return value of RemovePrincipalFromNamedValueSD,
  2548. // because its failure is not important (for example DefaultAccessPermission might
  2549. // not exist). The important call that must succeed is AddPrincipalToNamedValueSD
  2550. RemovePrincipalFromNamedValueSD (HKEY_CLASSES_ROOT,
  2551. keyName,
  2552. TEXT("AccessPermission"),
  2553. Principal);
  2554. err = AddPrincipalToNamedValueSD (HKEY_CLASSES_ROOT,
  2555. keyName,
  2556. TEXT("AccessPermission"),
  2557. Principal,
  2558. Permit);
  2559. }
  2560. else
  2561. {
  2562. err = RemovePrincipalFromNamedValueSD (HKEY_CLASSES_ROOT,
  2563. keyName,
  2564. TEXT("AccessPermission"),
  2565. Principal);
  2566. }
  2567. return err;
  2568. }
  2569. DWORD
  2570. ChangeAppIDLaunchACL(
  2571. LPTSTR AppID,
  2572. LPTSTR Principal,
  2573. BOOL SetPrincipal,
  2574. BOOL Permit)
  2575. {
  2576. HRESULT hr = S_OK;
  2577. TCHAR keyName [256];
  2578. DWORD err;
  2579. hr = StringCchCopy( keyName, ARRAYSIZE(keyName), TEXT("APPID\\") );
  2580. if ( FAILED(hr) )
  2581. {
  2582. return HRESULTTOWIN32( hr );
  2583. }
  2584. hr = StringCchCat( keyName, ARRAYSIZE(keyName), AppID );
  2585. if ( FAILED(hr) )
  2586. {
  2587. return HRESULTTOWIN32( hr );
  2588. }
  2589. if (SetPrincipal)
  2590. {
  2591. // There is not need to check the return value of RemovePrincipalFromNamedValueSD,
  2592. // because its failure is not important (for example DefaultAccessPermission might
  2593. // not exist). The important call that must succeed is AddPrincipalToNamedValueSD
  2594. RemovePrincipalFromNamedValueSD (HKEY_CLASSES_ROOT,
  2595. keyName,
  2596. TEXT("LaunchPermission"),
  2597. Principal);
  2598. err = AddPrincipalToNamedValueSD (HKEY_CLASSES_ROOT,
  2599. keyName,
  2600. TEXT("LaunchPermission"),
  2601. Principal,
  2602. Permit);
  2603. }
  2604. else
  2605. {
  2606. err = RemovePrincipalFromNamedValueSD (HKEY_CLASSES_ROOT,
  2607. keyName,
  2608. TEXT("LaunchPermission"),
  2609. Principal);
  2610. }
  2611. return err;
  2612. }
  2613. //
  2614. // Function will open the metabase and check the iusr_ and iwam_ usernames.
  2615. // it will check if the names are still valid and if the passwords are still valid.
  2616. //
  2617. VOID
  2618. UpdateAnonymousUser(
  2619. IMDCOM *pcCom,
  2620. LPTSTR pszPath,
  2621. DWORD dwUserMetaId,
  2622. DWORD dwPasswordMetaId,
  2623. DWORD dwUserCommentResourceId,
  2624. DWORD dwUserFullNameResourceId,
  2625. LPTSTR pszDefaultUserNamePrefix,
  2626. USERNAME_STRING_TYPE ustSyncName,
  2627. PASSWORD_STRING_TYPE pstSyncPass,
  2628. BOOL fPerformPasswordValidate)
  2629. {
  2630. HRESULT hr = S_OK;
  2631. USERNAME_STRING_TYPE ustAnonyName = L"\0";
  2632. PASSWORD_STRING_TYPE pstAnonyPass = L"\0";
  2633. GUFM_RETURN gufmTemp;
  2634. BOOL fRet;
  2635. BOOL fExistence;
  2636. BOOL fDisabled;
  2637. BOOL fUpdateComApplications = FALSE;
  2638. LPTSTR pstrRightsFor_IUSR[] =
  2639. {
  2640. L"SeInteractiveLogonRight",
  2641. L"SeNetworkLogonRight",
  2642. L"SeBatchLogonRight"
  2643. };
  2644. LPTSTR pstrRightsFor_IWAM[] =
  2645. {
  2646. L"SeNetworkLogonRight",
  2647. L"SeBatchLogonRight",
  2648. L"SeAssignPrimaryTokenPrivilege",
  2649. L"SeIncreaseQuotaPrivilege"
  2650. };
  2651. //
  2652. // Get the WAM username and password
  2653. //
  2654. gufmTemp = GetUserFromMetabase(pcCom,
  2655. pszPath,
  2656. dwUserMetaId,
  2657. dwPasswordMetaId,
  2658. ustAnonyName,
  2659. pstAnonyPass);
  2660. //
  2661. // If the metabase path doesn't exist, then
  2662. // service doesn't exist, punt
  2663. // If ID doesn't exist in the metabase, then punt, assume they
  2664. // don't want an anonymous User. We may want to revisit this.
  2665. //
  2666. //
  2667. if ((gufmTemp != GUFM_NO_PATH) && (gufmTemp != GUFM_NO_USER_ID))
  2668. {
  2669. BOOL fCreateAccount = FALSE;
  2670. //
  2671. // See if this is our default account. Otherwise do nothing.
  2672. //
  2673. if (_wcsnicmp(pszDefaultUserNamePrefix,
  2674. ustAnonyName,
  2675. wcslen(pszDefaultUserNamePrefix)) == 0)
  2676. {
  2677. // Check if this user actually exists...
  2678. fExistence = DoesUserExist(ustAnonyName,&fDisabled);
  2679. if (fExistence)
  2680. {
  2681. if (fDisabled)
  2682. {
  2683. fCreateAccount = FALSE;
  2684. if (!g_eventLogForAccountRecreation)
  2685. {
  2686. CreateEventLogObject ();
  2687. }
  2688. if (g_eventLogForAccountRecreation)
  2689. {
  2690. CHAR szAnsiUserName[MAX_PATH];
  2691. const CHAR *pszUserNames[1];
  2692. if (! WideCharToMultiByte(CP_ACP,
  2693. 0,
  2694. ustAnonyName,
  2695. -1,
  2696. szAnsiUserName,
  2697. MAX_PATH-1,
  2698. NULL,
  2699. NULL))
  2700. {
  2701. SecureZeroMemory(szAnsiUserName, sizeof(szAnsiUserName));
  2702. }
  2703. pszUserNames[0] = szAnsiUserName;
  2704. g_eventLogForAccountRecreation->LogEvent(
  2705. INET_SVC_ACCOUNT_DISABLED,
  2706. 1,
  2707. pszUserNames,
  2708. 0 );
  2709. }
  2710. }
  2711. else
  2712. {
  2713. if (gufmTemp != GUFM_NO_PASSWORD)
  2714. {
  2715. DBG_ASSERT(gufmTemp == GUFM_SUCCESS);
  2716. if (fPerformPasswordValidate)
  2717. {
  2718. BOOL fCheckPassword = TRUE;
  2719. //
  2720. // Make sure this is the same password as other
  2721. // instances of this account. If not, set it.
  2722. //
  2723. if ((pstSyncPass[0] != (TCHAR)'\0') &&
  2724. (_wcsicmp(ustSyncName, ustAnonyName) == 0))
  2725. {
  2726. if (wcscmp(pstSyncPass,
  2727. pstAnonyPass) != 0)
  2728. {
  2729. //
  2730. // Passwords are different.
  2731. //
  2732. if (WritePasswordToMetabase(pcCom,
  2733. pszPath,
  2734. dwPasswordMetaId,
  2735. pstSyncPass))
  2736. {
  2737. // We already checked there is enough speace in pstAnonyPass
  2738. hr = StringCchCopy( pstAnonyPass, ARRAYSIZE(pstAnonyPass), pstSyncPass );
  2739. DBG_ASSERT( SUCCEEDED(hr) );
  2740. }
  2741. else
  2742. {
  2743. fCheckPassword = FALSE;
  2744. }
  2745. }
  2746. }
  2747. if (fCheckPassword)
  2748. {
  2749. if (ValidatePassword(ustAnonyName,
  2750. TEXT(""),
  2751. pstAnonyPass))
  2752. {
  2753. // thats a good case account is ok, do nothing there
  2754. }
  2755. else
  2756. {
  2757. // we comment out DeleteGuestUser because we try to change pswd on that user
  2758. // DeleteGuestUser(ustAnonyName);
  2759. fCreateAccount = TRUE;
  2760. }
  2761. }
  2762. }
  2763. //
  2764. // Set the sync password here
  2765. //
  2766. hr = StringCbCopy( pstSyncPass, sizeof(PASSWORD_STRING_TYPE), pstAnonyPass );
  2767. DBG_ASSERT( SUCCEEDED(hr) );
  2768. hr = StringCbCopy( ustSyncName, sizeof(USERNAME_STRING_TYPE), ustAnonyName );
  2769. DBG_ASSERT( SUCCEEDED(hr) );
  2770. }
  2771. }
  2772. }
  2773. else
  2774. {
  2775. fCreateAccount = TRUE;
  2776. }
  2777. if (fCreateAccount)
  2778. {
  2779. //
  2780. // The user does not exist, so let's create it.
  2781. // Make sure there's a password first.
  2782. //
  2783. if (fCreateAccount)
  2784. {
  2785. if (MD_WAM_USER_NAME == dwUserMetaId)
  2786. {
  2787. fRet = MakeSureUserGetsCreated(ustAnonyName,pstAnonyPass,dwUserCommentResourceId,dwUserFullNameResourceId,TRUE);
  2788. if( fRet )
  2789. {
  2790. fUpdateComApplications = TRUE;
  2791. }
  2792. }
  2793. else
  2794. {
  2795. fRet = MakeSureUserGetsCreated(ustAnonyName,pstAnonyPass,dwUserCommentResourceId,dwUserFullNameResourceId,FALSE);
  2796. }
  2797. if (!g_eventLogForAccountRecreation)
  2798. {
  2799. CreateEventLogObject ();
  2800. }
  2801. if (g_eventLogForAccountRecreation)
  2802. {
  2803. CHAR szAnsiUserName[MAX_PATH];
  2804. const CHAR *pszUserNames[1];
  2805. if (! WideCharToMultiByte(CP_ACP,
  2806. 0,
  2807. ustAnonyName,
  2808. -1,
  2809. szAnsiUserName,
  2810. MAX_PATH-1,
  2811. NULL,
  2812. NULL))
  2813. {
  2814. SecureZeroMemory(szAnsiUserName, sizeof(szAnsiUserName));
  2815. }
  2816. pszUserNames[0] = szAnsiUserName;
  2817. // if succeded to recreate an account then log an event
  2818. if (fRet)
  2819. {
  2820. g_eventLogForAccountRecreation->LogEvent(
  2821. INET_SVC_ACCOUNT_RECREATED,
  2822. 1,
  2823. pszUserNames,
  2824. 0 );
  2825. }
  2826. else
  2827. {
  2828. // if the creation of the account failed, then log that too.
  2829. g_eventLogForAccountRecreation->LogEvent(
  2830. INET_SVC_ACCOUNT_CREATE_FAILED,
  2831. 1,
  2832. pszUserNames,
  2833. 0 );
  2834. }
  2835. }
  2836. if (dwUserMetaId == MD_WAM_USER_NAME)
  2837. {
  2838. ChangeAppIDLaunchACL(TEXT("{9209B1A6-964A-11D0-9372-00A0C9034910}"),
  2839. ustAnonyName,
  2840. TRUE,
  2841. TRUE);
  2842. ChangeAppIDAccessACL(TEXT("{9209B1A6-964A-11D0-9372-00A0C9034910}"),
  2843. ustAnonyName,
  2844. TRUE,
  2845. TRUE);
  2846. }
  2847. } // fCreateAccount == TRUE
  2848. } // fCreateAccount == TRUE
  2849. //
  2850. // check if user has enough rights otherwise add some (bug 361833)
  2851. //
  2852. if (wcscmp(pszDefaultUserNamePrefix,TEXT("IUSR_")) == 0)
  2853. {
  2854. UpdateUserRights (ustAnonyName,pstrRightsFor_IUSR,sizeof(pstrRightsFor_IUSR)/sizeof(LPTSTR));
  2855. }
  2856. else if (wcscmp(pszDefaultUserNamePrefix,TEXT("IWAM_")) == 0)
  2857. {
  2858. UpdateUserRights (ustAnonyName,pstrRightsFor_IWAM,sizeof(pstrRightsFor_IWAM)/sizeof(LPTSTR));
  2859. }
  2860. // Update the com applications with the new wam user information
  2861. if( fUpdateComApplications )
  2862. {
  2863. DWORD dwThreadID = 0;
  2864. HANDLE hThread = NULL;
  2865. COM_APP_THREAD_STRUCT * pUpdateComAppInfo = NULL;
  2866. pUpdateComAppInfo = new COM_APP_THREAD_STRUCT;
  2867. if (pUpdateComAppInfo)
  2868. {
  2869. if ( wcslen(ustAnonyName) < (sizeof(pUpdateComAppInfo->ustWamUserName) / sizeof(WCHAR)) )
  2870. {
  2871. hr = StringCchCopy(pUpdateComAppInfo->ustWamUserName, ARRAYSIZE(pUpdateComAppInfo->ustWamUserName), ustAnonyName);
  2872. DBG_ASSERT( SUCCEEDED(hr) );
  2873. if ( wcslen(pstAnonyPass) < (sizeof(pUpdateComAppInfo->pstWamUserPass) / sizeof(WCHAR)) )
  2874. {
  2875. StringCchCopy(pUpdateComAppInfo->pstWamUserPass, ARRAYSIZE(pUpdateComAppInfo->pstWamUserPass), pstAnonyPass);
  2876. hThread = CreateThread(NULL,
  2877. 0,
  2878. UpdateComApplicationsThread,
  2879. (PVOID) pUpdateComAppInfo,
  2880. 0,
  2881. &dwThreadID);
  2882. if (hThread != NULL)
  2883. {
  2884. CloseHandle(hThread);
  2885. }
  2886. else
  2887. {
  2888. if (pUpdateComAppInfo)
  2889. {
  2890. delete pUpdateComAppInfo;
  2891. pUpdateComAppInfo=NULL;
  2892. }
  2893. }
  2894. }
  2895. }
  2896. }
  2897. }
  2898. }
  2899. else
  2900. {
  2901. // This is not one of our accouts.
  2902. // in other words -- it doesn't start with
  2903. // iusr_ or iwam_
  2904. //
  2905. // however there is a problem here.
  2906. //
  2907. // on machines that are made to be replica domain controllers or
  2908. // backup domain controllers, when dcpromo is run to create those types
  2909. // of machines, all the local accounts are wiped out.
  2910. //
  2911. // this is fine if the usernames are iusr_ or iwam_, since they are just
  2912. // re-created in the above code (or the user is warned that they were unable
  2913. // to be crated). however in the case where these are
  2914. // user created accounts, the user has no way of knowing that
  2915. // they're iusr/iwam accounts have been hosed.
  2916. //
  2917. // the code here is just to warn the user of that fact.
  2918. if (TRUE == IsDomainController())
  2919. {
  2920. // check if they are valid.
  2921. // Check if this user actually exists...
  2922. fExistence = DoesUserExist(ustAnonyName,&fDisabled);
  2923. if (!fExistence)
  2924. {
  2925. if (!fDisabled)
  2926. {
  2927. // the user doesn't exist
  2928. // log SOMETHING at least
  2929. if (!g_eventLogForAccountRecreation)
  2930. {
  2931. CreateEventLogObject ();
  2932. }
  2933. if (g_eventLogForAccountRecreation)
  2934. {
  2935. CHAR szAnsiUserName[MAX_PATH];
  2936. const CHAR *pszUserNames[1];
  2937. if (! WideCharToMultiByte(CP_ACP,
  2938. 0,
  2939. ustAnonyName,
  2940. -1,
  2941. szAnsiUserName,
  2942. MAX_PATH-1,
  2943. NULL,
  2944. NULL))
  2945. {
  2946. SecureZeroMemory(szAnsiUserName, sizeof(szAnsiUserName));
  2947. }
  2948. pszUserNames[0] = szAnsiUserName;
  2949. g_eventLogForAccountRecreation->LogEvent(
  2950. INET_SVC_ACCOUNT_NOT_EXIST,
  2951. 1,
  2952. pszUserNames,
  2953. 0 );
  2954. }
  2955. }
  2956. }
  2957. }
  2958. }
  2959. }
  2960. }
  2961. HRESULT
  2962. CreateGroup(
  2963. LPWSTR szGroupName,
  2964. LPWSTR szGroupComment)
  2965. {
  2966. HRESULT hr = S_OK;
  2967. NET_API_STATUS dwRes;
  2968. LOCALGROUP_INFO_1 MyLocalGroup;
  2969. const DWORD dwMaxCount = 20;
  2970. DWORD dwCount = 0;
  2971. MyLocalGroup.lgrpi1_name = szGroupName;
  2972. MyLocalGroup.lgrpi1_comment = szGroupComment;
  2973. do
  2974. {
  2975. dwRes = NetLocalGroupAdd(NULL, 1, (LPBYTE)&MyLocalGroup, NULL);
  2976. if(dwRes != NERR_Success &&
  2977. dwRes != NERR_GroupExists &&
  2978. dwRes != ERROR_ALIAS_EXISTS)
  2979. {
  2980. hr = HRESULT_FROM_WIN32(dwRes);
  2981. //
  2982. // if this is a domain controller.
  2983. // we have to wait for the domain controller
  2984. // replication to be finished, otherwise The CreateUserAccount
  2985. // call will fail
  2986. //
  2987. // if we failed to create the user
  2988. // it could be because this is a DC and we need
  2989. // to wait for the sysvol to be ready.
  2990. Sleep(10000);
  2991. WaitForDCAvailability();
  2992. }
  2993. else
  2994. {
  2995. hr = S_OK;
  2996. }
  2997. }
  2998. while ((FAILED(hr)) && (++dwCount < dwMaxCount));
  2999. return hr;
  3000. }
  3001. VOID
  3002. UpdateUsers(
  3003. BOOL fRestore /* = FALSE */)
  3004. {
  3005. HRESULT hresTemp;
  3006. IMDCOM *pcCom;
  3007. BOOL fPerformUpdate = TRUE;
  3008. BOOL fPerformPasswordValidate = FALSE;
  3009. HKEY hkRegistryKey = NULL;
  3010. DWORD dwRegReturn;
  3011. DWORD dwBuffer;
  3012. DWORD dwSize;
  3013. DWORD dwType;
  3014. HRESULT hr;
  3015. //
  3016. // First get the metabase interface
  3017. //
  3018. dwRegReturn = RegOpenKey(HKEY_LOCAL_MACHINE,
  3019. L"SOFTWARE\\Microsoft\\InetStp",
  3020. &hkRegistryKey);
  3021. if (dwRegReturn == ERROR_SUCCESS)
  3022. {
  3023. dwSize = sizeof(dwBuffer);
  3024. dwRegReturn = RegQueryValueEx(hkRegistryKey,
  3025. L"DisableUserAccountRestore",
  3026. NULL,
  3027. &dwType,
  3028. (BYTE *)&dwBuffer,
  3029. &dwSize);
  3030. if ((dwRegReturn == ERROR_SUCCESS) && dwType == (REG_DWORD))
  3031. {
  3032. fPerformUpdate = FALSE;
  3033. }
  3034. if (fPerformUpdate)
  3035. {
  3036. // we are doing the check to see if the user exists...
  3037. // see if we need to verify that the password is ssynced as well...
  3038. dwRegReturn = RegQueryValueEx(hkRegistryKey,
  3039. L"EnableUserAccountRestorePassSync",
  3040. NULL,
  3041. &dwType,
  3042. (BYTE *)&dwBuffer,
  3043. &dwSize);
  3044. if ((dwRegReturn == ERROR_SUCCESS) && dwType == (REG_DWORD))
  3045. {
  3046. fPerformPasswordValidate = TRUE;
  3047. }
  3048. }
  3049. RegCloseKey( hkRegistryKey );
  3050. }
  3051. if( fRestore )
  3052. {
  3053. fPerformPasswordValidate = TRUE;
  3054. }
  3055. if (fPerformUpdate)
  3056. {
  3057. hresTemp = CoCreateInstance(CLSID_MDCOM,
  3058. NULL,
  3059. CLSCTX_SERVER,
  3060. IID_IMDCOM,
  3061. (void**) &pcCom);
  3062. if (SUCCEEDED(hresTemp))
  3063. {
  3064. //
  3065. // Make sure the IIS_WPG group exists
  3066. //
  3067. hr = CreateGroup(IIS_WP_GROUP, L"IIS Worker Process Group");
  3068. DBGPRINTF((DBG_CONTEXT, "Called into CreateGroup, hr %x\n", hr));
  3069. LPTSTR pstrRightsFor_IIS_WPG[] = { L"SeBatchLogonRight", L"SeImpersonatePrivilege" };
  3070. UpdateUserRights(IIS_WP_GROUP,pstrRightsFor_IIS_WPG,sizeof(pstrRightsFor_IIS_WPG)/sizeof(LPTSTR));
  3071. PASSWORD_STRING_TYPE pstAnonyPass;
  3072. USERNAME_STRING_TYPE ustAnonyName;
  3073. pstAnonyPass[0] = (TCHAR)'\0';
  3074. ustAnonyName[0] = (TCHAR)'\0';
  3075. UpdateAnonymousUser(pcCom,
  3076. TEXT("LM/W3SVC"),
  3077. MD_WAM_USER_NAME,
  3078. MD_WAM_PWD,
  3079. IDS_WAMUSER_COMMENT,
  3080. IDS_WAMUSER_FULLNAME,
  3081. TEXT("IWAM_"),
  3082. ustAnonyName,
  3083. pstAnonyPass,
  3084. fPerformPasswordValidate);
  3085. pstAnonyPass[0] = (TCHAR)'\0';
  3086. ustAnonyName[0] = (TCHAR)'\0';
  3087. UpdateAnonymousUser(pcCom,
  3088. TEXT("LM/W3SVC"),
  3089. MD_ANONYMOUS_USER_NAME,
  3090. MD_ANONYMOUS_PWD,
  3091. IDS_USER_COMMENT,
  3092. IDS_USER_FULLNAME,
  3093. TEXT("IUSR_"),
  3094. ustAnonyName,
  3095. pstAnonyPass,
  3096. fPerformPasswordValidate);
  3097. //
  3098. // At this point pstAnonyPass should contain the web server password.
  3099. //
  3100. UpdateAnonymousUser(pcCom,
  3101. TEXT("LM/MSFTPSVC"),
  3102. MD_ANONYMOUS_USER_NAME,
  3103. MD_ANONYMOUS_PWD,
  3104. IDS_USER_COMMENT,
  3105. IDS_USER_FULLNAME,
  3106. TEXT("IUSR_"),
  3107. ustAnonyName,
  3108. pstAnonyPass,
  3109. fPerformPasswordValidate);
  3110. hr = UpdateAdminAcl(pcCom,
  3111. L"/",
  3112. IIS_WP_GROUP);
  3113. DBGPRINTF((DBG_CONTEXT, "Called into UpdateAdminAcl, hr %x\n", hr));
  3114. hr = UpdateAdminAcl(pcCom,
  3115. L"/",
  3116. L"NT Authority\\Network Service");
  3117. DBGPRINTF((DBG_CONTEXT, "Called into UpdateAdminAcl, hr %x\n", hr));
  3118. hr = UpdateAdminAcl(pcCom,
  3119. L"/",
  3120. L"NT Authority\\Local Service");
  3121. DBGPRINTF((DBG_CONTEXT, "Called into UpdateAdminAcl, hr %x\n", hr));
  3122. pcCom->Release();
  3123. }
  3124. }
  3125. if (g_eventLogForAccountRecreation)
  3126. {
  3127. delete g_eventLogForAccountRecreation;
  3128. g_eventLogForAccountRecreation = NULL;
  3129. }
  3130. }
  3131. void
  3132. DumpAdminACL(
  3133. PSECURITY_DESCRIPTOR pSD)
  3134. {
  3135. HRESULT hr = S_OK;
  3136. BOOL b = FALSE;
  3137. BOOL bDaclPresent = FALSE;
  3138. BOOL bDaclDefaulted = FALSE;
  3139. PACL pDacl = NULL;
  3140. ACCESS_ALLOWED_ACE* pAce;
  3141. DBGPRINTF((DBG_CONTEXT, "Dumping AdminAcl %p\n", pSD));
  3142. b = GetSecurityDescriptorDacl(pSD, &bDaclPresent, &pDacl, &bDaclDefaulted);
  3143. if (b)
  3144. {
  3145. DBGPRINTF((DBG_CONTEXT, "DumpAdminACL:ACE count: %d\n", (int)pDacl->AceCount));
  3146. // now check if SID's ACE is there
  3147. for (int i = 0; i < pDacl->AceCount; i++)
  3148. {
  3149. if (!GetAce(pDacl, i, (LPVOID *) &pAce))
  3150. {
  3151. DBGPRINTF((DBG_CONTEXT, "DumpAdminACL:GetAce failed with 0x%x\n", GetLastError()));
  3152. continue;
  3153. }
  3154. if (IsValidSid( (PSID) &(pAce->SidStart) ) )
  3155. {
  3156. LPTSTR pszSid;
  3157. LPCTSTR ServerName = NULL; // local machine
  3158. DWORD cbName = UNLEN+1;
  3159. TCHAR ReferencedDomainName[200];
  3160. DWORD cbReferencedDomainName = sizeof(ReferencedDomainName);
  3161. SID_NAME_USE sidNameUse = SidTypeUser;
  3162. TCHAR szUserName[UNLEN + 1];
  3163. // dump out the sid in string format
  3164. if ( ConvertSidToStringSid( (PSID)&(pAce->SidStart), &pszSid ) )
  3165. {
  3166. hr = StringCchCopy(szUserName, ARRAYSIZE(szUserName), L"(unknown...)");
  3167. DBG_ASSERT( SUCCEEDED(hr) );
  3168. if (LookupAccountSid(ServerName, (PSID) &(pAce->SidStart), szUserName, &cbName, ReferencedDomainName, &cbReferencedDomainName, &sidNameUse))
  3169. {
  3170. // echo to logfile
  3171. DBGPRINTF((DBG_CONTEXT, "DumpAdminACL:Sid[%i]=%S,%S,0x%x,0x%x,0x%x,0x%x\n",i,
  3172. pszSid,
  3173. szUserName,
  3174. pAce->Header.AceType,
  3175. pAce->Header.AceFlags,
  3176. pAce->Header.AceSize,
  3177. pAce->Mask
  3178. ));
  3179. }
  3180. else
  3181. {
  3182. DBGPRINTF((DBG_CONTEXT, "DumpAdminACL:Sid[%i]=%S='%S'\n",i,pszSid,szUserName));
  3183. }
  3184. LocalFree(LocalHandle(pszSid));
  3185. }
  3186. }
  3187. else
  3188. {
  3189. DBGPRINTF((DBG_CONTEXT, "DumpAdminACL:IsValidSid failed with 0x%x\n", GetLastError()));
  3190. }
  3191. }
  3192. }
  3193. }
  3194. BOOL
  3195. MakeAbsoluteCopyFromRelative(
  3196. PSECURITY_DESCRIPTOR psdOriginal,
  3197. PSECURITY_DESCRIPTOR* ppsdNew)
  3198. {
  3199. // we have to find out whether the original is already self-relative
  3200. SECURITY_DESCRIPTOR_CONTROL sdc = 0;
  3201. PSECURITY_DESCRIPTOR psdAbsoluteCopy = NULL;
  3202. DWORD dwRevision = 0;
  3203. DWORD cb = 0;
  3204. PACL Dacl = NULL;
  3205. PACL Sacl = NULL;
  3206. PSID Owner = NULL;
  3207. PSID Group = NULL;
  3208. DWORD dwDaclSize = 0;
  3209. DWORD dwSaclSize = 0;
  3210. DWORD dwOwnerSize = 0;
  3211. DWORD dwPrimaryGroupSize = 0;
  3212. if( !IsValidSecurityDescriptor( psdOriginal ) )
  3213. {
  3214. goto cleanup;
  3215. }
  3216. if( !GetSecurityDescriptorControl( psdOriginal, &sdc, &dwRevision ) )
  3217. {
  3218. goto cleanup;
  3219. }
  3220. if( sdc & SE_SELF_RELATIVE )
  3221. {
  3222. // the original is in self-relative format, build an absolute copy
  3223. // get required buffer size
  3224. cb = 0;
  3225. MakeAbsoluteSD(
  3226. psdOriginal, // address of self-relative SD
  3227. psdAbsoluteCopy, // address of absolute SD
  3228. &cb, // address of size of absolute SD
  3229. NULL, // address of discretionary ACL
  3230. &dwDaclSize, // address of size of discretionary ACL
  3231. NULL, // address of system ACL
  3232. &dwSaclSize, // address of size of system ACL
  3233. NULL, // address of owner SID
  3234. &dwOwnerSize, // address of size of owner SID
  3235. NULL, // address of primary-group SID
  3236. &dwPrimaryGroupSize // address of size of group SID
  3237. );
  3238. // alloc the memory
  3239. psdAbsoluteCopy = (PSECURITY_DESCRIPTOR) malloc( cb );
  3240. Dacl = (PACL) malloc( dwDaclSize );
  3241. Sacl = (PACL) malloc( dwSaclSize );
  3242. Owner = (PSID) malloc( dwOwnerSize );
  3243. Group = (PSID) malloc( dwPrimaryGroupSize );
  3244. if(NULL == psdAbsoluteCopy ||
  3245. NULL == Dacl ||
  3246. NULL == Sacl ||
  3247. NULL == Owner ||
  3248. NULL == Group )
  3249. {
  3250. goto cleanup;
  3251. }
  3252. // make the copy
  3253. if( !MakeAbsoluteSD(
  3254. psdOriginal, // address of self-relative SD
  3255. psdAbsoluteCopy, // address of absolute SD
  3256. &cb, // address of size of absolute SD
  3257. Dacl, // address of discretionary ACL
  3258. &dwDaclSize, // address of size of discretionary ACL
  3259. Sacl, // address of system ACL
  3260. &dwSaclSize, // address of size of system ACL
  3261. Owner, // address of owner SID
  3262. &dwOwnerSize, // address of size of owner SID
  3263. Group, // address of primary-group SID
  3264. &dwPrimaryGroupSize // address of size of group SID
  3265. ) )
  3266. {
  3267. goto cleanup;
  3268. }
  3269. }
  3270. else
  3271. {
  3272. // the original is in absolute format, fail
  3273. goto cleanup;
  3274. }
  3275. // paranoia check
  3276. if( !IsValidSecurityDescriptor( psdAbsoluteCopy ) )
  3277. {
  3278. goto cleanup;
  3279. }
  3280. if( !IsValidSecurityDescriptor( psdOriginal ) )
  3281. {
  3282. goto cleanup;
  3283. }
  3284. *ppsdNew = psdAbsoluteCopy;
  3285. return(TRUE);
  3286. cleanup:
  3287. if( Dacl != NULL )
  3288. {
  3289. free((PVOID) Dacl );
  3290. Dacl = NULL;
  3291. }
  3292. if( Sacl != NULL )
  3293. {
  3294. free((PVOID) Sacl );
  3295. Sacl = NULL;
  3296. }
  3297. if( Owner != NULL )
  3298. {
  3299. free((PVOID) Owner );
  3300. Owner = NULL;
  3301. }
  3302. if( Group != NULL )
  3303. {
  3304. free((PVOID) Group );
  3305. Group = NULL;
  3306. }
  3307. if( psdAbsoluteCopy != NULL )
  3308. {
  3309. free((PVOID) psdAbsoluteCopy );
  3310. psdAbsoluteCopy = NULL;
  3311. }
  3312. *ppsdNew = NULL;
  3313. return (FALSE);
  3314. }
  3315. BOOL
  3316. AddUserAccessToSD(
  3317. IN PSECURITY_DESCRIPTOR pSd,
  3318. IN PSID pSid,
  3319. IN DWORD NewAccess,
  3320. IN UCHAR TheAceType,
  3321. OUT PSECURITY_DESCRIPTOR *ppSdNew)
  3322. {
  3323. ULONG i;
  3324. BOOL bReturn = FALSE;
  3325. BOOL Result;
  3326. BOOL DaclPresent;
  3327. BOOL DaclDefaulted;
  3328. DWORD Length;
  3329. DWORD NewAclLength;
  3330. ACCESS_ALLOWED_ACE* OldAce;
  3331. PACE_HEADER NewAce = NULL;
  3332. ACL_SIZE_INFORMATION AclInfo;
  3333. PACL Dacl = NULL;
  3334. PACL NewDacl = NULL;
  3335. PACL NewAceDacl = NULL;
  3336. PSECURITY_DESCRIPTOR NewSD = NULL;
  3337. PSECURITY_DESCRIPTOR OldSD = NULL;
  3338. PSECURITY_DESCRIPTOR outpSD = NULL;
  3339. DWORD cboutpSD = 0;
  3340. BOOL fAceForGroupPresent = FALSE;
  3341. DWORD dwMask;
  3342. OldSD = pSd;
  3343. // only do if the ace is allowed/denied
  3344. if (ACCESS_ALLOWED_ACE_TYPE != TheAceType && ACCESS_DENIED_ACE_TYPE != TheAceType)
  3345. {
  3346. goto Exit;
  3347. }
  3348. // Convert SecurityDescriptor to absolute format. It generates
  3349. // a new SecurityDescriptor for its output which we must free.
  3350. if ( !MakeAbsoluteCopyFromRelative(OldSD, &NewSD) )
  3351. {
  3352. goto Exit;
  3353. }
  3354. // Must get DACL pointer from new (absolute) SD
  3355. if(!GetSecurityDescriptorDacl(NewSD,&DaclPresent,&Dacl,&DaclDefaulted))
  3356. {
  3357. goto Exit;
  3358. }
  3359. // If no DACL, no need to add the user since no DACL
  3360. // means all accesss
  3361. if( !DaclPresent )
  3362. {
  3363. bReturn = TRUE;
  3364. goto Exit;
  3365. }
  3366. // Code can return DaclPresent, but a NULL which means
  3367. // a NULL Dacl is present. This allows all access to the object.
  3368. if( Dacl == NULL )
  3369. {
  3370. bReturn = TRUE;
  3371. goto Exit;
  3372. }
  3373. // Get the current ACL's size
  3374. if( !GetAclInformation(Dacl,&AclInfo,sizeof(AclInfo),AclSizeInformation) )
  3375. {
  3376. goto Exit;
  3377. }
  3378. // Check if access is already there
  3379. // --------------------------------
  3380. // Check to see if this SID already exists in there
  3381. // if it does (and it has the right access we want) then forget it, we don't have to do anything more.
  3382. for (i = 0; i < AclInfo.AceCount; i++)
  3383. {
  3384. ACE_HEADER *pAceHeader;
  3385. ACCESS_ALLOWED_ACE* pAce = NULL;
  3386. if (!GetAce(Dacl, i, (LPVOID *) &pAce))
  3387. {
  3388. goto Exit;
  3389. }
  3390. pAceHeader = (ACE_HEADER *)pAce;
  3391. // check if group sid is already there
  3392. if (EqualSid((PSID) &(pAce->SidStart), pSid))
  3393. {
  3394. if (pAceHeader->AceType == ACCESS_ALLOWED_ACE_TYPE)
  3395. {
  3396. // If the correct access is present, return success
  3397. if ((pAce->Mask & NewAccess) == NewAccess)
  3398. {
  3399. bReturn = TRUE;
  3400. goto Exit;
  3401. }
  3402. else
  3403. {
  3404. // the ace that exist doesn't have the permissions that we want.
  3405. // If an ACE for our SID exists, we just need to bump
  3406. // up the access level instead of creating a new ACE
  3407. fAceForGroupPresent = TRUE;
  3408. }
  3409. }
  3410. break;
  3411. }
  3412. }
  3413. // If we have to create a new ACE
  3414. // (because our user isn't listed in the existing ACL)
  3415. // then let's Create a new ACL to put the new access allowed ACE on
  3416. // --------------------------------
  3417. if (!fAceForGroupPresent)
  3418. {
  3419. NewAclLength = sizeof(ACL) +
  3420. sizeof(ACCESS_ALLOWED_ACE) - sizeof(ULONG) +
  3421. GetLengthSid( pSid );
  3422. NewAceDacl = (PACL) LocalAlloc( LMEM_FIXED, NewAclLength );
  3423. if ( NewAceDacl == NULL )
  3424. {
  3425. goto Exit;
  3426. }
  3427. if(!InitializeAcl( NewAceDacl, NewAclLength, ACL_REVISION ))
  3428. {
  3429. goto Exit;
  3430. }
  3431. if (ACCESS_DENIED_ACE_TYPE == TheAceType)
  3432. {
  3433. Result = AddAccessDeniedAce(NewAceDacl,ACL_REVISION,NewAccess,pSid);
  3434. }
  3435. else
  3436. {
  3437. Result = AddAccessAllowedAce(NewAceDacl,ACL_REVISION,NewAccess,pSid);
  3438. }
  3439. if( !Result )
  3440. {
  3441. goto Exit;
  3442. }
  3443. // Grab the 1st ace from the Newly created Dacl
  3444. if(!GetAce( NewAceDacl, 0, (void **)&NewAce ))
  3445. {
  3446. goto Exit;
  3447. }
  3448. // add CONTAINER_INHERIT_ACE TO AceFlags
  3449. //NewAce->AceFlags |= CONTAINER_INHERIT_ACE;
  3450. Length = AclInfo.AclBytesInUse + NewAce->AceSize;
  3451. }
  3452. else
  3453. {
  3454. Length = AclInfo.AclBytesInUse;
  3455. }
  3456. // Allocate new DACL
  3457. NewDacl = (PACL) LocalAlloc( LMEM_FIXED, Length );
  3458. if(NewDacl == NULL)
  3459. {
  3460. goto Exit;
  3461. }
  3462. if(!InitializeAcl( NewDacl, Length, ACL_REVISION ))
  3463. {
  3464. goto Exit;
  3465. }
  3466. // Insert new ACE at the front of the new DACL
  3467. if (!fAceForGroupPresent)
  3468. {
  3469. if(!AddAce( NewDacl, ACL_REVISION, 0, NewAce, NewAce->AceSize ))
  3470. {
  3471. goto Exit;
  3472. }
  3473. }
  3474. // ----------------------------------------
  3475. // Read thru the old Dacl and get the ACE's
  3476. // add it to the new Dacl
  3477. // ----------------------------------------
  3478. for ( i = 0; i < AclInfo.AceCount; i++ )
  3479. {
  3480. ACE_HEADER *pAceHeader;
  3481. Result = GetAce( Dacl, i, (LPVOID*) &OldAce );
  3482. if( !Result )
  3483. {
  3484. goto Exit;
  3485. }
  3486. pAceHeader = (ACE_HEADER *)OldAce;
  3487. // If an ACE for our SID exists, we just need to bump
  3488. // up the access level instead of creating a new ACE
  3489. //
  3490. if (pAceHeader->AceType == ACCESS_ALLOWED_ACE_TYPE)
  3491. {
  3492. dwMask = OldAce->Mask;
  3493. if (fAceForGroupPresent)
  3494. {
  3495. if (EqualSid((PSID) &(OldAce->SidStart), pSid))
  3496. {
  3497. dwMask = NewAccess | OldAce->Mask;
  3498. }
  3499. }
  3500. // now add ace to new dacl
  3501. Result = AddAccessAllowedAceEx(NewDacl, ACL_REVISION, OldAce->Header.AceFlags,dwMask,(PSID) &(OldAce->SidStart));
  3502. if( !Result )
  3503. {
  3504. goto Exit;
  3505. }
  3506. }
  3507. else
  3508. {
  3509. // copy denied or audit ace.
  3510. if (!AddAce(NewDacl, ACL_REVISION, 0xFFFFFFFF,OldAce, pAceHeader->AceSize ))
  3511. {
  3512. goto Exit;
  3513. }
  3514. }
  3515. }
  3516. // Set new DACL for Security Descriptor
  3517. if(!SetSecurityDescriptorDacl(NewSD,TRUE,NewDacl,FALSE))
  3518. {
  3519. goto Exit;
  3520. }
  3521. // The new SD is in absolute format. change it to Relative before we pass it back
  3522. cboutpSD = 0;
  3523. MakeSelfRelativeSD(NewSD, outpSD, &cboutpSD);
  3524. outpSD = (PSECURITY_DESCRIPTOR)GlobalAlloc(GPTR, cboutpSD);
  3525. if ( !outpSD )
  3526. {
  3527. goto Exit;
  3528. }
  3529. if (!MakeSelfRelativeSD(NewSD, outpSD, &cboutpSD))
  3530. {
  3531. goto Exit;
  3532. }
  3533. // The new SD is passed back in relative format,
  3534. *ppSdNew = outpSD;
  3535. bReturn = TRUE;
  3536. Exit:
  3537. if (NewSD)
  3538. {
  3539. free( NewSD );
  3540. NewSD = NULL;
  3541. }
  3542. if (NewDacl)
  3543. {
  3544. LocalFree( NewDacl );
  3545. NewDacl = NULL;
  3546. }
  3547. if (NewAceDacl)
  3548. {
  3549. LocalFree( NewAceDacl );
  3550. NewAceDacl = NULL;
  3551. }
  3552. return bReturn;
  3553. }
  3554. HRESULT
  3555. UpdateAdminAcl(
  3556. IMDCOM * pcCom,
  3557. LPCWSTR szPath,
  3558. LPCWSTR szAccountName)
  3559. /*++
  3560. Routine Description:
  3561. After DCPromo, need to update the AdminAcl in the metabase
  3562. --*/
  3563. {
  3564. METADATA_HANDLE hMetabase = NULL;
  3565. METADATA_RECORD mdrAdminAcl;
  3566. BUFFER buffSid;
  3567. BUFFER buffDomainName;
  3568. PSECURITY_DESCRIPTOR pOldSd = NULL;
  3569. PSECURITY_DESCRIPTOR pNewSd = NULL;
  3570. HRESULT hr;
  3571. DWORD dwMDGetDataLen;
  3572. DWORD cbSid;
  3573. DWORD cchDomainName;
  3574. SID_NAME_USE peUse;
  3575. DWORD AccessMask = ( MD_ACR_READ |
  3576. MD_ACR_UNSECURE_PROPS_READ |
  3577. MD_ACR_ENUM_KEYS );
  3578. hr = pcCom->ComMDOpenMetaObject( METADATA_MASTER_ROOT_HANDLE,
  3579. szPath,
  3580. METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE,
  3581. OPEN_TIMEOUT_VALUE,
  3582. &hMetabase
  3583. );
  3584. if( FAILED(hr) )
  3585. {
  3586. DBGPRINTF((DBG_CONTEXT, "Error opening metabase path %S, hr %x\n", szPath, hr));
  3587. goto cleanup;
  3588. }
  3589. MD_SET_DATA_RECORD_EXT( &mdrAdminAcl,
  3590. MD_ADMIN_ACL,
  3591. METADATA_INHERIT | METADATA_SECURE | METADATA_REFERENCE,
  3592. IIS_MD_UT_SERVER,
  3593. BINARY_METADATA,
  3594. 0,
  3595. NULL
  3596. );
  3597. hr = pcCom->ComMDGetMetaData(hMetabase,
  3598. NULL,
  3599. &mdrAdminAcl,
  3600. &dwMDGetDataLen);
  3601. if (FAILED(hr))
  3602. {
  3603. DBGPRINTF((DBG_CONTEXT, "Error retrieving data, hr %x\n", hr));
  3604. goto cleanup;
  3605. }
  3606. pOldSd = (PSECURITY_DESCRIPTOR)mdrAdminAcl.pbMDData;
  3607. //
  3608. // obtain the logon sid of the user/group
  3609. //
  3610. cbSid = buffSid.QuerySize();
  3611. cchDomainName = buffDomainName.QuerySize() / sizeof(WCHAR);
  3612. while(!LookupAccountName(NULL,
  3613. szAccountName,
  3614. buffSid.QueryPtr(),
  3615. &cbSid,
  3616. (LPWSTR)buffDomainName.QueryPtr(),
  3617. &cchDomainName,
  3618. &peUse))
  3619. {
  3620. if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
  3621. {
  3622. DBGPRINTF((DBG_CONTEXT, "Error retrieving account %S, hr %x\n", szAccountName, hr));
  3623. hr = HRESULT_FROM_WIN32(GetLastError());
  3624. goto cleanup;
  3625. }
  3626. if (!buffSid.Resize(cbSid) ||
  3627. !buffDomainName.Resize(cchDomainName * sizeof(WCHAR)))
  3628. {
  3629. hr = HRESULT_FROM_WIN32(GetLastError());
  3630. goto cleanup;
  3631. }
  3632. }
  3633. DumpAdminACL(pOldSd);
  3634. if (!AddUserAccessToSD(pOldSd,
  3635. buffSid.QueryPtr(),
  3636. AccessMask,
  3637. ACCESS_ALLOWED_ACE_TYPE,
  3638. &pNewSd))
  3639. {
  3640. hr = HRESULT_FROM_WIN32(GetLastError());
  3641. DBGPRINTF((DBG_CONTEXT, "Error adding user to AdminAcl, hr %x\n", hr));
  3642. goto cleanup;
  3643. }
  3644. if (pNewSd)
  3645. {
  3646. DumpAdminACL(pNewSd);
  3647. DWORD dwNewSd = GetSecurityDescriptorLength(pNewSd);
  3648. MD_SET_DATA_RECORD_EXT( &mdrAdminAcl,
  3649. MD_ADMIN_ACL,
  3650. METADATA_INHERIT | METADATA_SECURE | METADATA_REFERENCE,
  3651. IIS_MD_UT_SERVER,
  3652. BINARY_METADATA,
  3653. dwNewSd,
  3654. pNewSd
  3655. );
  3656. hr = pcCom->ComMDSetMetaData(hMetabase,
  3657. NULL,
  3658. &mdrAdminAcl);
  3659. if (FAILED(hr))
  3660. {
  3661. DBGPRINTF((DBG_CONTEXT, "Error setting adminacl, hr %x\n", hr));
  3662. goto cleanup;
  3663. }
  3664. }
  3665. cleanup:
  3666. if (pNewSd)
  3667. {
  3668. GlobalFree(pNewSd);
  3669. pNewSd = NULL;
  3670. }
  3671. if (hMetabase)
  3672. {
  3673. // Done with the metabase
  3674. pcCom->ComMDCloseMetaObject(hMetabase);
  3675. hMetabase = NULL;
  3676. }
  3677. return hr;
  3678. }
  3679. HRESULT
  3680. UpdateComApplications(
  3681. LPCTSTR szWamUserName,
  3682. LPCTSTR szWamUserPass)
  3683. /*++
  3684. Routine Description:
  3685. If the IWAM account has been modified, it is necessary to update the
  3686. the out of process com+ applications with the correct account
  3687. information. This routine will collect all the com+ applications and
  3688. reset the activation information.
  3689. Arguments:
  3690. szWamUserName - the new user name
  3691. szWamUserPass - the new user password
  3692. Note:
  3693. This routine is a royal pain in the butt. I take back
  3694. all the good things I may have said about com automation.
  3695. Return Value:
  3696. HRESULT - Return value from failed API call
  3697. - E_OUTOFMEMORY
  3698. - S_OK - everything worked
  3699. - S_FALSE - encountered a non-fatal error, unable
  3700. to reset at least one application.
  3701. --*/
  3702. {
  3703. HRESULT hr = S_OK;
  3704. BOOL fNoErrors = TRUE;
  3705. METADATA_HANDLE hMetabase = NULL;
  3706. WCHAR * pwszDataPaths = NULL;
  3707. DWORD cchDataPaths = 0;
  3708. BOOL fTryAgain;
  3709. DWORD cMaxApplications;
  3710. WCHAR * pwszCurrentPath;
  3711. STACK_BUFFER( bufMDPath, 64 );
  3712. WCHAR * pwszMDPath = NULL;
  3713. DWORD dwMDPathLen;
  3714. SAFEARRAY * psaApplications = NULL;
  3715. SAFEARRAYBOUND rgsaBound[1];
  3716. DWORD cApplications;
  3717. VARIANT varAppKey;
  3718. LONG rgIndices[1];
  3719. METADATA_RECORD mdrAppIsolated;
  3720. METADATA_RECORD mdrAppPackageId;
  3721. METADATA_RECORD mdrWamClsid;
  3722. DWORD dwAppIsolated;
  3723. WCHAR wszAppPackageId[ 40 ];
  3724. WCHAR wszWamClsid[ 40 ];
  3725. DWORD dwMDGetDataLen = 0;
  3726. ICOMAdminCatalog * pComCatalog = NULL;
  3727. ICatalogCollection *pComAppCollection = NULL;
  3728. ICatalogObject * pComApp = NULL;
  3729. LONG nAppsInCollection;
  3730. LONG iCurrentApp;
  3731. LONG nChanges;
  3732. BOOL fAppCreated = FALSE;
  3733. VARIANT varOldAppIdentity;
  3734. VARIANT varNewAppIdentity;
  3735. VARIANT varNewAppPassword;
  3736. IMDCOM * pcCom = NULL;
  3737. BSTR bstrApplications = NULL;
  3738. BSTR bstrIdentity = NULL;
  3739. BSTR bstrPassword = NULL;
  3740. DWORD cbMDPath;
  3741. // This is built unicode right now. Since all the com apis I need
  3742. // are unicode only I'm using wide characters here. I should get
  3743. // plenty of compiler errors if _UNICODE isn't defined, but just
  3744. // in case....
  3745. // DBG_ASSERT( sizeof(TCHAR) == sizeof(WCHAR) );
  3746. DBGPRINTF(( DBG_CONTEXT,
  3747. "Updating activation identity for out of process apps.\n"
  3748. ));
  3749. // Init variants
  3750. VariantInit( &varAppKey );
  3751. VariantInit( &varOldAppIdentity );
  3752. VariantInit( &varNewAppIdentity );
  3753. VariantInit( &varNewAppPassword );
  3754. // Allocate the BSTRs
  3755. bstrApplications = SysAllocString( L"Applications" );
  3756. if ( bstrApplications == NULL )
  3757. {
  3758. hr = E_OUTOFMEMORY;
  3759. DBGERROR(( DBG_CONTEXT,
  3760. "Out of memory allocating BSTR\n"
  3761. ));
  3762. goto cleanup;
  3763. }
  3764. bstrIdentity = SysAllocString( L"Identity" );
  3765. if ( bstrIdentity == NULL )
  3766. {
  3767. hr = E_OUTOFMEMORY;
  3768. DBGERROR(( DBG_CONTEXT,
  3769. "Out of memory allocating BSTR\n"
  3770. ));
  3771. goto cleanup;
  3772. }
  3773. bstrPassword = SysAllocString( L"Password" );
  3774. if ( bstrPassword == NULL )
  3775. {
  3776. hr = E_OUTOFMEMORY;
  3777. DBGERROR(( DBG_CONTEXT,
  3778. "Out of memory allocating BSTR\n"
  3779. ));
  3780. goto cleanup;
  3781. }
  3782. hr = CoCreateInstance(CLSID_MDCOM,
  3783. NULL,
  3784. CLSCTX_SERVER,
  3785. IID_IMDCOM,
  3786. (void**) &pcCom);
  3787. if( FAILED(hr) )
  3788. {
  3789. DBGERROR(( DBG_CONTEXT,
  3790. "Failed CoCreateInstance CLSID_MDCOM (%08x)\n",
  3791. hr
  3792. ));
  3793. goto cleanup;
  3794. }
  3795. //
  3796. // Get the applications to be reset by querying the metabase paths
  3797. //
  3798. hr = pcCom->ComMDOpenMetaObject( METADATA_MASTER_ROOT_HANDLE,
  3799. ROOTMDPath,
  3800. METADATA_PERMISSION_READ,
  3801. OPEN_TIMEOUT_VALUE,
  3802. &hMetabase
  3803. );
  3804. if( FAILED(hr) )
  3805. {
  3806. DBGERROR(( DBG_CONTEXT,
  3807. "Failed to open metabase (%08x)\n",
  3808. hr
  3809. ));
  3810. goto cleanup;
  3811. }
  3812. // Get the data paths string
  3813. fTryAgain = TRUE;
  3814. do
  3815. {
  3816. hr = pcCom->ComMDGetMetaDataPaths( hMetabase,
  3817. NULL,
  3818. MD_APP_PACKAGE_ID,
  3819. STRING_METADATA,
  3820. cchDataPaths,
  3821. pwszDataPaths,
  3822. &cchDataPaths
  3823. );
  3824. if( HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER) == hr )
  3825. {
  3826. delete[] pwszDataPaths;
  3827. pwszDataPaths = NULL;
  3828. pwszDataPaths = new WCHAR[cchDataPaths];
  3829. if( !pwszDataPaths )
  3830. {
  3831. hr = E_OUTOFMEMORY;
  3832. goto cleanup;
  3833. }
  3834. }
  3835. else
  3836. {
  3837. fTryAgain = FALSE;
  3838. }
  3839. }
  3840. while( fTryAgain );
  3841. //
  3842. // Done with the metabase for now
  3843. //
  3844. pcCom->ComMDCloseMetaObject(hMetabase);
  3845. hMetabase = NULL;
  3846. if( FAILED(hr) )
  3847. {
  3848. DBGERROR(( DBG_CONTEXT,
  3849. "Failed to find metadata (%08x) Data(%d)\n",
  3850. hr,
  3851. MD_APP_PACKAGE_ID
  3852. ));
  3853. goto cleanup;
  3854. }
  3855. else if (pwszDataPaths == NULL)
  3856. {
  3857. //
  3858. // If we found no isolated apps, make the path list an empty multisz
  3859. //
  3860. cchDataPaths = 1;
  3861. pwszDataPaths = new WCHAR[cchDataPaths];
  3862. if( !pwszDataPaths )
  3863. {
  3864. hr = E_OUTOFMEMORY;
  3865. goto cleanup;
  3866. }
  3867. pwszDataPaths[0] = L'\0';
  3868. }
  3869. // Determine the maximum number of applications
  3870. cMaxApplications = 1; // The pooled application
  3871. for( pwszCurrentPath = pwszDataPaths;
  3872. *pwszCurrentPath != L'\0';
  3873. pwszCurrentPath += wcslen(pwszCurrentPath) + 1
  3874. )
  3875. {
  3876. cMaxApplications++;
  3877. }
  3878. //
  3879. // Build a key array and load the com applications.
  3880. //
  3881. // Create an array to hold the keys
  3882. rgsaBound[0].cElements = cMaxApplications;
  3883. rgsaBound[0].lLbound = 0;
  3884. psaApplications = SafeArrayCreate( VT_VARIANT, 1, rgsaBound );
  3885. if( psaApplications == NULL )
  3886. {
  3887. hr = E_OUTOFMEMORY;
  3888. goto cleanup;
  3889. }
  3890. // Set the out of process pool application key
  3891. varAppKey.vt = VT_BSTR;
  3892. varAppKey.bstrVal = SysAllocString( W3_OOP_POOL_PACKAGE_ID );
  3893. if( !varAppKey.bstrVal )
  3894. {
  3895. hr = E_OUTOFMEMORY;
  3896. goto cleanup;
  3897. }
  3898. rgIndices[0] = 0;
  3899. hr = SafeArrayPutElement( psaApplications, rgIndices, &varAppKey );
  3900. if( FAILED(hr) )
  3901. {
  3902. DBGERROR(( DBG_CONTEXT,
  3903. "Failed setting an element in a safe array (%08x)\n",
  3904. hr
  3905. ));
  3906. goto cleanup;
  3907. }
  3908. // For each of the application paths determine if an out of process
  3909. // application is defined there and set the appropriate key into
  3910. // our array
  3911. MD_SET_DATA_RECORD_EXT( &mdrAppIsolated,
  3912. MD_APP_ISOLATED,
  3913. METADATA_NO_ATTRIBUTES,
  3914. ALL_METADATA,
  3915. DWORD_METADATA,
  3916. sizeof(DWORD),
  3917. (PBYTE)&dwAppIsolated
  3918. );
  3919. MD_SET_DATA_RECORD_EXT( &mdrAppPackageId,
  3920. MD_APP_PACKAGE_ID,
  3921. METADATA_NO_ATTRIBUTES,
  3922. ALL_METADATA,
  3923. STRING_METADATA,
  3924. sizeof(wszAppPackageId),
  3925. (PBYTE)wszAppPackageId
  3926. );
  3927. wszAppPackageId[0] = L'\0';
  3928. MD_SET_DATA_RECORD_EXT( &mdrWamClsid,
  3929. MD_APP_WAM_CLSID,
  3930. METADATA_NO_ATTRIBUTES,
  3931. ALL_METADATA,
  3932. STRING_METADATA,
  3933. sizeof(wszWamClsid),
  3934. (PBYTE)wszWamClsid
  3935. );
  3936. wszWamClsid[0] = L'\0';
  3937. // Go through each data path and set it into our array if
  3938. // it is an isolated application
  3939. cApplications = 1; // Actual # of applications - 1 for pool
  3940. for( pwszCurrentPath = pwszDataPaths;
  3941. *pwszCurrentPath != L'\0';
  3942. pwszCurrentPath += wcslen(pwszCurrentPath) + 1
  3943. )
  3944. {
  3945. if( hMetabase != NULL )
  3946. {
  3947. pcCom->ComMDCloseMetaObject(hMetabase);
  3948. hMetabase = NULL;
  3949. }
  3950. //
  3951. // 20 is the size of L"/LM/W3SVC"
  3952. //
  3953. cbMDPath = (DWORD)(wcslen( pwszCurrentPath ) * sizeof( WCHAR )) + 20;
  3954. if ( !bufMDPath.Resize( cbMDPath ) )
  3955. {
  3956. hr = E_OUTOFMEMORY;
  3957. goto cleanup;
  3958. }
  3959. pwszMDPath = ( WCHAR* )bufMDPath.QueryPtr();
  3960. hr = StringCbCopyW( pwszMDPath, cbMDPath, ROOTMDPath );
  3961. if ( FAILED(hr) )
  3962. {
  3963. goto cleanup;
  3964. }
  3965. hr = StringCbCopyW( pwszMDPath, cbMDPath, pwszCurrentPath );
  3966. if ( FAILED(hr) )
  3967. {
  3968. goto cleanup;
  3969. }
  3970. //
  3971. // Get rid of the trailing '/' or '\\'
  3972. //
  3973. dwMDPathLen = (DWORD)wcslen( pwszMDPath );
  3974. if( pwszMDPath[ dwMDPathLen - 1 ] == L'\\' ||
  3975. pwszMDPath[ dwMDPathLen - 1 ] == L'/' )
  3976. {
  3977. pwszMDPath[ dwMDPathLen - 1 ] = L'\0';
  3978. }
  3979. hr = pcCom->ComMDOpenMetaObject( METADATA_MASTER_ROOT_HANDLE,
  3980. pwszMDPath,
  3981. METADATA_PERMISSION_READ,
  3982. OPEN_TIMEOUT_VALUE,
  3983. &hMetabase
  3984. );
  3985. if( FAILED(hr) )
  3986. {
  3987. DBGERROR(( DBG_CONTEXT,
  3988. "Failed to open metabase (%08x)\n",
  3989. hr
  3990. ));
  3991. goto cleanup;
  3992. }
  3993. hr = pcCom->ComMDGetMetaData( hMetabase,
  3994. NULL,
  3995. &mdrAppIsolated,
  3996. &dwMDGetDataLen
  3997. );
  3998. if( FAILED(hr) )
  3999. {
  4000. DBGERROR(( DBG_CONTEXT,
  4001. "Failed to get data from the metabase (%08x)"
  4002. " Path(%S) Data(%d)\n",
  4003. hr,
  4004. pwszMDPath,
  4005. mdrAppIsolated.dwMDIdentifier
  4006. ));
  4007. fNoErrors = FALSE;
  4008. continue;
  4009. }
  4010. // Is the application out of process
  4011. if( dwAppIsolated == 1 )
  4012. {
  4013. // Get the application id
  4014. hr = pcCom->ComMDGetMetaData( hMetabase,
  4015. NULL,
  4016. &mdrAppPackageId,
  4017. &dwMDGetDataLen
  4018. );
  4019. if( FAILED(hr) )
  4020. {
  4021. DBGERROR(( DBG_CONTEXT,
  4022. "Failed to get data from the metabase (%08x)"
  4023. " Path(%S) Data(%d)\n",
  4024. hr,
  4025. pwszMDPath,
  4026. mdrAppPackageId.dwMDIdentifier
  4027. ));
  4028. fNoErrors = FALSE;
  4029. continue;
  4030. }
  4031. // Get the wam class id
  4032. hr = pcCom->ComMDGetMetaData( hMetabase,
  4033. NULL,
  4034. &mdrWamClsid,
  4035. &dwMDGetDataLen
  4036. );
  4037. if( FAILED(hr) )
  4038. {
  4039. DBGERROR(( DBG_CONTEXT,
  4040. "Failed to get data from the metabase (%08x)"
  4041. " Path(%S) Data(%d)\n",
  4042. hr,
  4043. pwszMDPath,
  4044. mdrWamClsid.dwMDIdentifier
  4045. ));
  4046. fNoErrors = FALSE;
  4047. continue;
  4048. }
  4049. //
  4050. // Close meta object since we may need to write to it after we
  4051. // create a new COM+ application.
  4052. //
  4053. pcCom->ComMDCloseMetaObject(hMetabase);
  4054. hMetabase = NULL;
  4055. if ( g_pfnCreateCOMPlusApplication )
  4056. {
  4057. hr = g_pfnCreateCOMPlusApplication( pwszMDPath,
  4058. wszAppPackageId,
  4059. wszWamClsid,
  4060. &fAppCreated );
  4061. }
  4062. else
  4063. {
  4064. hr = E_FAIL;
  4065. }
  4066. if( FAILED( hr ) )
  4067. {
  4068. fNoErrors = FALSE;
  4069. continue;
  4070. }
  4071. if( fAppCreated )
  4072. {
  4073. //
  4074. // We don't need to fix the password for this
  4075. // COM+ application
  4076. //
  4077. continue;
  4078. }
  4079. // Add the application id to the array
  4080. VariantClear( &varAppKey );
  4081. varAppKey.vt = VT_BSTR;
  4082. varAppKey.bstrVal = SysAllocString( wszAppPackageId );
  4083. if( !varAppKey.bstrVal )
  4084. {
  4085. hr = E_OUTOFMEMORY;
  4086. goto cleanup;
  4087. }
  4088. rgIndices[0]++;
  4089. hr = SafeArrayPutElement( psaApplications,
  4090. rgIndices,
  4091. &varAppKey
  4092. );
  4093. if( FAILED(hr) )
  4094. {
  4095. DBGERROR(( DBG_CONTEXT,
  4096. "Failed to set safe array element (%08x)\n",
  4097. hr
  4098. ));
  4099. VariantClear( &varAppKey );
  4100. rgIndices[0]--;
  4101. fNoErrors = FALSE;
  4102. continue;
  4103. }
  4104. cApplications++;
  4105. }
  4106. }
  4107. //
  4108. // IVANPASH: BUG #524473
  4109. // Close meta object, because if W3SVC is starting it will keep SCM locked
  4110. // until it finishes, but it will be blocked by us from accessing /LM/W3SVC.
  4111. // and we will be blocked in the CoCreate for the COM+ Catalog waiting for
  4112. // SCM to unlock to start the service and SCM is waiting for W3SVC.
  4113. //
  4114. if( hMetabase != NULL )
  4115. {
  4116. pcCom->ComMDCloseMetaObject(hMetabase);
  4117. hMetabase = NULL;
  4118. }
  4119. // Shrink the size of the safe-array if necessary
  4120. if( cApplications < cMaxApplications )
  4121. {
  4122. rgsaBound[0].cElements = cApplications;
  4123. hr = SafeArrayRedim( psaApplications, rgsaBound );
  4124. if( FAILED(hr) )
  4125. {
  4126. DBGERROR(( DBG_CONTEXT,
  4127. "Failed to redim safe array (%08x)\n",
  4128. hr
  4129. ));
  4130. goto cleanup;
  4131. }
  4132. }
  4133. //
  4134. // For each application reset the activation identity
  4135. //
  4136. // Use our key array to get the application collection
  4137. DBG_ASSERT( hMetabase == NULL );
  4138. hr = CoCreateInstance( CLSID_COMAdminCatalog,
  4139. NULL,
  4140. CLSCTX_SERVER,
  4141. IID_ICOMAdminCatalog,
  4142. (void**)&pComCatalog
  4143. );
  4144. if( FAILED(hr) )
  4145. {
  4146. DBGERROR(( DBG_CONTEXT,
  4147. "Failed to create COM catalog (%08x)\n",
  4148. hr
  4149. ));
  4150. goto cleanup;
  4151. }
  4152. hr = pComCatalog->GetCollection( bstrApplications,
  4153. (IDispatch **)&pComAppCollection
  4154. );
  4155. if( FAILED(hr) )
  4156. {
  4157. DBGERROR(( DBG_CONTEXT,
  4158. "Failed to get Applications collection (%08x)\n",
  4159. hr
  4160. ));
  4161. goto cleanup;
  4162. }
  4163. hr = pComAppCollection->PopulateByKey( psaApplications );
  4164. if( FAILED(hr) )
  4165. {
  4166. DBGERROR(( DBG_CONTEXT,
  4167. "Failed to populate Applications collection (%08x)\n",
  4168. hr
  4169. ));
  4170. goto cleanup;
  4171. }
  4172. // Iterate over the application collection and update all the
  4173. // applications that use IWAM.
  4174. hr = pComAppCollection->get_Count( &nAppsInCollection );
  4175. if( FAILED(hr) )
  4176. {
  4177. DBGERROR(( DBG_CONTEXT,
  4178. "Failed to get Applications count (%08x)\n",
  4179. hr
  4180. ));
  4181. goto cleanup;
  4182. }
  4183. // Init our new app identity and password.
  4184. varNewAppIdentity.vt = VT_BSTR;
  4185. varNewAppIdentity.bstrVal = SysAllocString( szWamUserName );
  4186. if( !varNewAppIdentity.bstrVal )
  4187. {
  4188. hr = E_OUTOFMEMORY;
  4189. goto cleanup;
  4190. }
  4191. varNewAppPassword.vt = VT_BSTR;
  4192. varNewAppPassword.bstrVal = SysAllocString( szWamUserPass );
  4193. if( !varNewAppPassword.bstrVal )
  4194. {
  4195. hr = E_OUTOFMEMORY;
  4196. goto cleanup;
  4197. }
  4198. for( iCurrentApp = 0; iCurrentApp < nAppsInCollection; ++iCurrentApp )
  4199. {
  4200. if( pComApp )
  4201. {
  4202. pComApp->Release();
  4203. pComApp = NULL;
  4204. }
  4205. if( varOldAppIdentity.vt != VT_EMPTY )
  4206. {
  4207. VariantClear( &varOldAppIdentity );
  4208. }
  4209. hr = pComAppCollection->get_Item( iCurrentApp,
  4210. (IDispatch **)&pComApp );
  4211. if( FAILED(hr) )
  4212. {
  4213. DBGERROR(( DBG_CONTEXT,
  4214. "Failed to get item from Applications collection (%08x)\n",
  4215. hr
  4216. ));
  4217. fNoErrors = FALSE;
  4218. continue;
  4219. }
  4220. // If the user has set this to something other than the IWAM_
  4221. // user, then we will respect that and not reset the identiy.
  4222. hr = pComApp->get_Value( bstrIdentity, &varOldAppIdentity );
  4223. if( FAILED(hr) )
  4224. {
  4225. DBGERROR(( DBG_CONTEXT,
  4226. "Failed to get Identify from Application (%08x)\n",
  4227. hr
  4228. ));
  4229. fNoErrors = FALSE;
  4230. continue;
  4231. }
  4232. DBG_ASSERT( varOldAppIdentity.vt == VT_BSTR );
  4233. if( varOldAppIdentity.vt == VT_BSTR )
  4234. {
  4235. if( memcmp( L"IWAM_", varOldAppIdentity.bstrVal, 10 ) == 0 )
  4236. {
  4237. hr = pComApp->put_Value( bstrIdentity, varNewAppIdentity );
  4238. if( FAILED(hr) )
  4239. {
  4240. DBGERROR(( DBG_CONTEXT,
  4241. "Failed to set new Identify (%08x)\n",
  4242. hr
  4243. ));
  4244. fNoErrors = FALSE;
  4245. continue;
  4246. }
  4247. hr = pComApp->put_Value( bstrPassword, varNewAppPassword );
  4248. if( FAILED(hr) )
  4249. {
  4250. DBGERROR(( DBG_CONTEXT,
  4251. "Failed to set new Password (%08x)\n",
  4252. hr
  4253. ));
  4254. fNoErrors = FALSE;
  4255. continue;
  4256. }
  4257. }
  4258. else
  4259. {
  4260. DBGINFO(( DBG_CONTEXT,
  4261. "Unrecognized application identity (%S)\n",
  4262. varOldAppIdentity.bstrVal
  4263. ));
  4264. }
  4265. }
  4266. }
  4267. hr = pComAppCollection->SaveChanges( &nChanges );
  4268. if( FAILED(hr) )
  4269. {
  4270. DBGERROR(( DBG_CONTEXT,
  4271. "Failed to save changes (%08x)\n",
  4272. hr
  4273. ));
  4274. goto cleanup;
  4275. }
  4276. cleanup:
  4277. if( hMetabase != NULL )
  4278. {
  4279. pcCom->ComMDCloseMetaObject(hMetabase);
  4280. hMetabase = NULL;
  4281. }
  4282. if( psaApplications != NULL )
  4283. {
  4284. SafeArrayDestroy( psaApplications );
  4285. }
  4286. if( pComCatalog != NULL )
  4287. {
  4288. pComCatalog->Release();
  4289. }
  4290. if( pComAppCollection != NULL )
  4291. {
  4292. pComAppCollection->Release();
  4293. }
  4294. if( pComApp != NULL )
  4295. {
  4296. pComApp->Release();
  4297. }
  4298. if( varAppKey.vt != VT_EMPTY )
  4299. {
  4300. VariantClear( &varAppKey );
  4301. }
  4302. if( varOldAppIdentity.vt != VT_EMPTY )
  4303. {
  4304. VariantClear( &varOldAppIdentity );
  4305. }
  4306. if( varNewAppIdentity.vt != VT_EMPTY )
  4307. {
  4308. VariantClear( &varNewAppIdentity );
  4309. }
  4310. if( varNewAppPassword.vt != VT_EMPTY )
  4311. {
  4312. VariantClear( &varNewAppPassword );
  4313. }
  4314. delete [] pwszDataPaths;
  4315. if ( bstrApplications != NULL)
  4316. {
  4317. SysFreeString( bstrApplications );
  4318. bstrApplications = NULL;
  4319. }
  4320. if ( bstrIdentity != NULL)
  4321. {
  4322. SysFreeString( bstrIdentity );
  4323. bstrIdentity = NULL;
  4324. }
  4325. if ( bstrPassword != NULL)
  4326. {
  4327. SysFreeString( bstrPassword );
  4328. bstrPassword = NULL;
  4329. }
  4330. if( pcCom != NULL )
  4331. {
  4332. pcCom->Release();
  4333. }
  4334. // return
  4335. if( FAILED(hr) )
  4336. {
  4337. return hr;
  4338. }
  4339. else if( fNoErrors == FALSE )
  4340. {
  4341. return S_FALSE;
  4342. }
  4343. else
  4344. {
  4345. return S_OK;
  4346. }
  4347. }
  4348. int
  4349. IsDomainController(void)
  4350. {
  4351. int iReturn = FALSE;
  4352. OSVERSIONINFOEX VerInfo;
  4353. ZeroMemory(&VerInfo, sizeof VerInfo);
  4354. VerInfo.dwOSVersionInfoSize = sizeof VerInfo;
  4355. if (GetVersionEx(reinterpret_cast<OSVERSIONINFO *>(&VerInfo)))
  4356. {
  4357. if (VER_NT_DOMAIN_CONTROLLER == VerInfo.wProductType)
  4358. {
  4359. iReturn = TRUE;
  4360. }
  4361. }
  4362. return iReturn;
  4363. }
  4364. BOOL
  4365. MakeSureUserGetsCreated(
  4366. LPTSTR pszAnonyName,
  4367. LPTSTR pszAnonyPass,
  4368. DWORD dwUserCommentResourceId,
  4369. DWORD dwUserFullNameResourceId,
  4370. BOOL fSpecicaliWamAccount)
  4371. {
  4372. BOOL bReturn = FALSE;
  4373. const DWORD dwMaxCount = 20;
  4374. DWORD dwCount = 0;
  4375. do
  4376. {
  4377. bReturn = CreateUserAccount(pszAnonyName,pszAnonyPass,dwUserCommentResourceId,dwUserFullNameResourceId,fSpecicaliWamAccount);
  4378. if (!bReturn)
  4379. {
  4380. // if this is a domain controller.
  4381. // we have to wait for the domain controller
  4382. // replication to be finished, otherwise The CreateUserAccount
  4383. // call will fail
  4384. //
  4385. // if we failed to create the user
  4386. // it could be because this is a DC and we need
  4387. // to wait for the sysvol to be ready.
  4388. Sleep(10000);
  4389. WaitForDCAvailability();
  4390. }
  4391. }
  4392. while ((!bReturn) && (++dwCount < dwMaxCount));
  4393. return bReturn;
  4394. }
  4395. BOOL
  4396. WaitForDCAvailability(void)
  4397. {
  4398. BOOL bRetVal = FALSE;
  4399. DWORD dwResult;
  4400. DWORD dwCount = 0;
  4401. DWORD dwMaxWait = 60000; // 1 minute max wait
  4402. HKEY hKeyNetLogonParams;
  4403. if (FALSE == IsDomainController())
  4404. {
  4405. // not a domain controller
  4406. // so we don't have to worry about replication delays...
  4407. return TRUE;
  4408. }
  4409. dwResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE,TEXT("SYSTEM\\CurrentControlSet\\Services\\netlogon\\parameters"),0,KEY_READ,&hKeyNetLogonParams );
  4410. if ( dwResult == ERROR_SUCCESS )
  4411. {
  4412. //
  4413. // value exists
  4414. //
  4415. DWORD dwSysVolReady = 0;
  4416. DWORD dwSize = sizeof( DWORD );
  4417. DWORD dwType = REG_DWORD;
  4418. dwResult = RegQueryValueEx( hKeyNetLogonParams,TEXT("SysVolReady"),0,&dwType,(LPBYTE) &dwSysVolReady,&dwSize );
  4419. if ( dwResult == ERROR_SUCCESS )
  4420. {
  4421. //
  4422. // SysVolReady?
  4423. //
  4424. if ( dwSysVolReady == 0 )
  4425. {
  4426. HANDLE hEvent;
  4427. //
  4428. // wait for SysVol to become ready
  4429. //
  4430. hEvent = CreateEvent( 0, TRUE, FALSE, TEXT("IISSysVolReadyEvent") );
  4431. if ( hEvent )
  4432. {
  4433. dwResult = RegNotifyChangeKeyValue( hKeyNetLogonParams, FALSE, REG_NOTIFY_CHANGE_LAST_SET, hEvent, TRUE );
  4434. if ( dwResult == ERROR_SUCCESS )
  4435. {
  4436. const DWORD dwMaxCount = 3;
  4437. do
  4438. {
  4439. //
  4440. // wait for SysVolReady to change
  4441. // hEvent is signaled for any changes in hKeyNetLogonParams
  4442. // not just the SysVolReady value.
  4443. //
  4444. WaitForSingleObject (hEvent, dwMaxWait / dwMaxCount );
  4445. dwResult = RegQueryValueEx( hKeyNetLogonParams,TEXT("SysVolReady"),0,&dwType,(LPBYTE) &dwSysVolReady,&dwSize );
  4446. }
  4447. while ( dwSysVolReady == 0 && ++dwCount < dwMaxCount );
  4448. if ( dwSysVolReady )
  4449. {
  4450. bRetVal = TRUE;
  4451. }
  4452. }
  4453. CloseHandle( hEvent );
  4454. }
  4455. }
  4456. else
  4457. {
  4458. // sysvol is ready
  4459. bRetVal = TRUE;
  4460. }
  4461. }
  4462. else
  4463. {
  4464. //
  4465. // value is non-existent, SysVol is assumed to be ready
  4466. //
  4467. if ( dwResult == ERROR_FILE_NOT_FOUND )
  4468. {
  4469. bRetVal = TRUE;
  4470. }
  4471. }
  4472. RegCloseKey( hKeyNetLogonParams );
  4473. }
  4474. else
  4475. {
  4476. // error opening regkey, maybe it's not even there
  4477. bRetVal = TRUE;
  4478. }
  4479. return bRetVal;
  4480. }
  4481. DWORD
  4482. UpdateComApplicationsThread(
  4483. PVOID pv)
  4484. {
  4485. HRESULT hr = S_OK;
  4486. COM_APP_THREAD_STRUCT *pUpdateComAppInfo = (COM_APP_THREAD_STRUCT *) pv;
  4487. BOOL fComInitialized = FALSE;
  4488. if ( pUpdateComAppInfo == NULL )
  4489. {
  4490. goto exit;
  4491. }
  4492. hr = CoInitializeEx( NULL, COINIT_MULTITHREADED );
  4493. if ( FAILED( hr ) )
  4494. {
  4495. goto exit;
  4496. }
  4497. fComInitialized = TRUE;
  4498. hr = UpdateComApplications( pUpdateComAppInfo->ustWamUserName,
  4499. pUpdateComAppInfo->pstWamUserPass );
  4500. exit:
  4501. if( hr != S_OK )
  4502. {
  4503. if( !g_eventLogForAccountRecreation )
  4504. {
  4505. CreateEventLogObject();
  4506. }
  4507. if ( g_eventLogForAccountRecreation )
  4508. {
  4509. g_eventLogForAccountRecreation->LogEvent( INET_SVC_ACCOUNT_COMUPDATE_FAILED,
  4510. 0,
  4511. NULL,
  4512. hr );
  4513. }
  4514. }
  4515. if ( pUpdateComAppInfo != NULL )
  4516. {
  4517. // erase the memory that we held the username/password in.
  4518. SecureZeroMemory( (PVOID)pUpdateComAppInfo->ustWamUserName,
  4519. sizeof(pUpdateComAppInfo->ustWamUserName) );
  4520. SecureZeroMemory( (PVOID)pUpdateComAppInfo->pstWamUserPass,
  4521. sizeof(pUpdateComAppInfo->pstWamUserPass) );
  4522. delete pUpdateComAppInfo;
  4523. pUpdateComAppInfo = NULL;
  4524. }
  4525. if ( fComInitialized )
  4526. {
  4527. CoUninitialize();
  4528. }
  4529. return 0;
  4530. }