Source code of Windows XP (NT5)
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.

1154 lines
28 KiB

  1. /*++
  2. Copyright (c) 1995 Microsoft Corporation
  3. Module Name:
  4. security.c
  5. Abstract:
  6. Routines to deal with security, user accounts, etc.
  7. Externally exposed routines:
  8. SignalLsa
  9. CreateSamEvent
  10. WaitForSam
  11. SetAccountsDomainSid
  12. CreateLocalAdminAccount
  13. CreateLocalUserAccount
  14. SetLocalUserPassword
  15. Author:
  16. Ted Miller (tedm) 5-Apr-1995
  17. adapted from legacy\dll\security.c
  18. Revision History:
  19. --*/
  20. #include "setupp.h"
  21. #include <Lmaccess.h>
  22. #pragma hdrstop
  23. PCWSTR SamEventName = L"\\SAM_SERVICE_STARTED";
  24. PCWSTR SsiAccountNamePostfix = L"$";
  25. PCWSTR SsiSecretName = L"$MACHINE.ACC";
  26. #define DOMAIN_NAME_MAX 33
  27. #define PASSWORD_MAX 14
  28. //
  29. // Constants used for logging that are specific to this source file.
  30. //
  31. PCWSTR szLsaOpenPolicy = L"LsaOpenPolicy";
  32. PCWSTR szLsaSetInformationPolicy = L"LsaSetInformationPolicy";
  33. PCWSTR szLsaQueryInformationPolicy = L"LsaQueryInformationPolicy";
  34. PCWSTR szNtSetEvent = L"NtSetEvent";
  35. PCWSTR szNtCreateEvent = L"NtCreateEvent";
  36. PCWSTR szSamConnect = L"SamConnect";
  37. PCWSTR szGetAccountsDomainName = L"GetAccountsDomainName";
  38. PCWSTR szSamLookupDomainInSamServer = L"SamLookupDomainInSamServer";
  39. PCWSTR szSamOpenDomain = L"SamOpenDomain";
  40. PCWSTR szSamEnumerateUsersInDomain = L"SamEnumerateUsersInDomain";
  41. PCWSTR szSamOpenUser = L"SamOpenUser";
  42. PCWSTR szSamChangePasswordUser = L"SamChangePasswordUser";
  43. PCWSTR szSamCreateUserInDomain = L"SamCreateUserInDomain";
  44. PCWSTR szSamQueryInformationUser = L"SamQueryInformationUser";
  45. PCWSTR szSamSetInformationUser = L"SamSetInformationUser";
  46. PCWSTR szMyAddLsaSecretObject = L"MyAddLsaSecretObject";
  47. VOID
  48. SetupLsaInitObjectAttributes(
  49. IN OUT POBJECT_ATTRIBUTES ObjectAttributes,
  50. IN OUT PSECURITY_QUALITY_OF_SERVICE SecurityQualityOfService
  51. );
  52. BOOL
  53. GetAccountsDomainName(
  54. IN LSA_HANDLE hPolicy, OPTIONAL
  55. OUT PWSTR Name,
  56. IN DWORD NameBufferSize
  57. );
  58. LSA_HANDLE
  59. OpenLsaPolicy(
  60. VOID
  61. );
  62. PSID
  63. CreateSidFromSidAndRid(
  64. IN PSID DomainSid,
  65. IN DWORD Rid
  66. );
  67. NTSTATUS
  68. MyAddLsaSecretObject(
  69. IN PCWSTR Password
  70. );
  71. BOOL
  72. SetAccountsDomainSid(
  73. IN DWORD Seed,
  74. IN PCWSTR DomainName
  75. )
  76. /*++
  77. Routine Description:
  78. Routine to set the sid of the AccountDomain.
  79. Arguments:
  80. Seed - The seed is used to generate a unique Sid. The seed should
  81. be generated by looking at the systemtime before and after
  82. a dialog and subtracting the milliseconds field.
  83. DomainName - supplies name to give to local domain
  84. Return value:
  85. Boolean value indicating outcome.
  86. --*/
  87. {
  88. PSID Sid;
  89. PSID SidPrimary ;
  90. OBJECT_ATTRIBUTES ObjectAttributes;
  91. SECURITY_QUALITY_OF_SERVICE SecurityQualityOfService;
  92. LSA_HANDLE PolicyHandle = NULL;
  93. PPOLICY_ACCOUNT_DOMAIN_INFO PolicyCurrentAccountDomainInfo = NULL;
  94. NTSTATUS Status;
  95. BOOL bResult;
  96. //
  97. //
  98. // Open the LSA Policy object to set the account domain sid. The access
  99. // mask needed for this is POLICY_TRUST_ADMIN.
  100. //
  101. SetupLsaInitObjectAttributes(&ObjectAttributes,&SecurityQualityOfService);
  102. Status = LsaOpenPolicy(NULL,&ObjectAttributes,MAXIMUM_ALLOWED,&PolicyHandle);
  103. if(!NT_SUCCESS(Status)) {
  104. SetuplogError(
  105. LogSevError,
  106. SETUPLOG_USE_MESSAGEID,
  107. MSG_LOG_SETACCOUNTDOMAINSID, NULL,
  108. SETUPLOG_USE_MESSAGEID,
  109. MSG_LOG_X_RETURNED_NTSTATUS,
  110. szLsaOpenPolicy,
  111. Status,
  112. NULL,NULL);
  113. return(FALSE);
  114. }
  115. Status = LsaQueryInformationPolicy(
  116. PolicyHandle,
  117. PolicyAccountDomainInformation,
  118. &PolicyCurrentAccountDomainInfo
  119. );
  120. if(NT_SUCCESS(Status)) {
  121. RtlInitUnicodeString(&PolicyCurrentAccountDomainInfo->DomainName,DomainName);
  122. Status = LsaSetInformationPolicy(
  123. PolicyHandle,
  124. PolicyAccountDomainInformation,
  125. (PVOID) PolicyCurrentAccountDomainInfo
  126. );
  127. LsaFreeMemory( PolicyCurrentAccountDomainInfo );
  128. }
  129. if(NT_SUCCESS(Status)) {
  130. bResult = TRUE;
  131. } else {
  132. bResult = FALSE;
  133. SetuplogError(
  134. LogSevError,
  135. SETUPLOG_USE_MESSAGEID,
  136. MSG_LOG_SETACCOUNTDOMAINSID, NULL,
  137. SETUPLOG_USE_MESSAGEID,
  138. MSG_LOG_X_RETURNED_NTSTATUS,
  139. szLsaSetInformationPolicy,
  140. Status,
  141. NULL,NULL);
  142. }
  143. LsaClose(PolicyHandle);
  144. return(bResult);
  145. }
  146. VOID
  147. SetupLsaInitObjectAttributes(
  148. IN OUT POBJECT_ATTRIBUTES ObjectAttributes,
  149. IN OUT PSECURITY_QUALITY_OF_SERVICE SecurityQualityOfService
  150. )
  151. /*++
  152. Routine Description:
  153. This function initializes the given Object Attributes structure, including
  154. Security Quality Of Service. Memory must be allcated for both
  155. ObjectAttributes and Security QOS by the caller. Borrowed from
  156. lsa
  157. Arguments:
  158. ObjectAttributes - Pointer to Object Attributes to be initialized.
  159. SecurityQualityOfService - Pointer to Security QOS to be initialized.
  160. Return Value:
  161. None.
  162. --*/
  163. {
  164. SecurityQualityOfService->Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
  165. SecurityQualityOfService->ImpersonationLevel = SecurityImpersonation;
  166. SecurityQualityOfService->ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
  167. SecurityQualityOfService->EffectiveOnly = FALSE;
  168. InitializeObjectAttributes(ObjectAttributes,NULL,0,NULL,NULL);
  169. //
  170. // The InitializeObjectAttributes macro presently stores NULL for
  171. // the SecurityQualityOfService field, so we must manually copy that
  172. // structure for now.
  173. //
  174. ObjectAttributes->SecurityQualityOfService = SecurityQualityOfService;
  175. }
  176. BOOL
  177. CreateLocalUserAccount(
  178. IN PCWSTR UserName,
  179. IN PCWSTR Password,
  180. IN PSID* PointerToUserSid OPTIONAL
  181. )
  182. /*++
  183. Routine Description:
  184. Routine to add a local user account to the AccountDomain. This account
  185. is created with the password indicated.
  186. Arguments:
  187. UserName - supplies name for user account
  188. Password - supplies initial password for user account.
  189. PointerToUserSid - If this argument is present, then on return it will contain the
  190. pointer to the user sid. It is the responsibility of the caller
  191. to free the Sid, using MyFree.
  192. Return value:
  193. Boolean value indicating outcome.
  194. --*/
  195. {
  196. return (NT_SUCCESS(CreateLocalAdminAccount(UserName,
  197. Password,
  198. PointerToUserSid
  199. )
  200. )
  201. );
  202. }
  203. NTSTATUS
  204. CreateLocalAdminAccountEx(
  205. IN PCWSTR UserName,
  206. IN PCWSTR Password,
  207. IN PCWSTR Description,
  208. IN PSID* PointerToUserSid OPTIONAL
  209. )
  210. /*++
  211. Routine Description:
  212. Routine to add a local user account to the AccountDomain. This account
  213. has ADMINISTRATOR priveledges and is created with the password indicated.
  214. Arguments:
  215. UserName - supplies name for user account
  216. Password - supplies initial password for user account.
  217. Description - Description that appears in user manager.
  218. PointerToUserSid - If this argument is present, then on return it will contain the
  219. pointer to the user sid. It is the responsibility of the caller
  220. to free the Sid, using MyFree.
  221. Return value:
  222. Boolean value indicating outcome.
  223. --*/
  224. {
  225. OBJECT_ATTRIBUTES ObjectAttributes;
  226. SECURITY_QUALITY_OF_SERVICE SecurityQualityOfService;
  227. UNICODE_STRING UnicodeString;
  228. SAM_HANDLE ServerHandle;
  229. SAM_HANDLE DomainHandle;
  230. SAM_HANDLE UserHandle;
  231. SAM_HANDLE AliasHandle;
  232. SAM_HANDLE BuiltinDomainHandle;
  233. WCHAR AccountsDomainName[DOMAIN_NAME_MAX];
  234. NTSTATUS Status;
  235. PSID BuiltinDomainId;
  236. PSID UserSid;
  237. ULONG User_RID;
  238. PUSER_CONTROL_INFORMATION UserControlInfo;
  239. USER_SET_PASSWORD_INFORMATION UserPasswordInfo;
  240. LSA_HANDLE PolicyHandle = NULL;
  241. PPOLICY_ACCOUNT_DOMAIN_INFO PolicyCurrentAccountDomainInfo = NULL;
  242. USER_ADMIN_COMMENT_INFORMATION AdminCommentInfo;
  243. //
  244. // Use SamConnect to connect to the local domain ("") and get a handle
  245. // to the local sam server.
  246. //
  247. SetupLsaInitObjectAttributes(&ObjectAttributes,&SecurityQualityOfService);
  248. RtlInitUnicodeString(&UnicodeString,L"");
  249. Status = SamConnect(
  250. &UnicodeString,
  251. &ServerHandle,
  252. SAM_SERVER_CONNECT | SAM_SERVER_LOOKUP_DOMAIN,
  253. &ObjectAttributes
  254. );
  255. if(!NT_SUCCESS(Status)) {
  256. goto err0;
  257. }
  258. //
  259. // Use the LSA to retrieve the name of the Accounts domain.
  260. //
  261. if(!GetAccountsDomainName(NULL,AccountsDomainName,DOMAIN_NAME_MAX)) {
  262. goto err1;
  263. }
  264. //
  265. // Open the AccountDomain. First find the Sid for this
  266. // in the Sam and then open the domain using this sid
  267. //
  268. //
  269. // Open the LSA Policy object to set the account domain sid.
  270. //
  271. SetupLsaInitObjectAttributes(&ObjectAttributes,&SecurityQualityOfService);
  272. Status = LsaOpenPolicy(NULL,&ObjectAttributes,MAXIMUM_ALLOWED,&PolicyHandle);
  273. if(NT_SUCCESS(Status)) {
  274. Status = LsaQueryInformationPolicy(
  275. PolicyHandle,
  276. PolicyAccountDomainInformation,
  277. &PolicyCurrentAccountDomainInfo
  278. );
  279. if(NT_SUCCESS(Status)) {
  280. Status = SamOpenDomain(
  281. ServerHandle,
  282. DOMAIN_READ | DOMAIN_LIST_ACCOUNTS | DOMAIN_LOOKUP |
  283. DOMAIN_READ_PASSWORD_PARAMETERS | DOMAIN_CREATE_USER,
  284. PolicyCurrentAccountDomainInfo->DomainSid,
  285. &DomainHandle
  286. );
  287. }
  288. LsaClose( PolicyHandle );
  289. }
  290. if (!NT_SUCCESS(Status)) {
  291. goto err2;
  292. }
  293. //
  294. // Use SamCreateUserInDomain to create a new user with the username
  295. // specified. This user account is created disabled with the
  296. // password not required.
  297. //
  298. RtlInitUnicodeString(&UnicodeString,UserName);
  299. Status = SamCreateUserInDomain(
  300. DomainHandle,
  301. &UnicodeString,
  302. //USER_READ_ACCOUNT | USER_WRITE_ACCOUNT | USER_FORCE_PASSWORD_CHANGE,
  303. USER_ALL_ACCESS,
  304. &UserHandle,
  305. &User_RID
  306. );
  307. if(!NT_SUCCESS(Status)) {
  308. goto err3;
  309. }
  310. //
  311. // Query all the default control information about the user added
  312. //
  313. Status = SamQueryInformationUser(UserHandle,UserControlInformation,&UserControlInfo);
  314. if(!NT_SUCCESS(Status)) {
  315. goto err4;
  316. }
  317. //
  318. // If the password is a Null password, make sure the
  319. // password_not required bit is set before the null
  320. // password is set.
  321. //
  322. if(!Password[0]) {
  323. UserControlInfo->UserAccountControl |= USER_PASSWORD_NOT_REQUIRED;
  324. Status = SamSetInformationUser(UserHandle,UserControlInformation,UserControlInfo);
  325. if(!NT_SUCCESS(Status)) {
  326. goto err5;
  327. }
  328. }
  329. //
  330. // Set the password ( NULL or non NULL )
  331. //
  332. RtlInitUnicodeString(&UserPasswordInfo.Password,Password);
  333. UserPasswordInfo.PasswordExpired = FALSE;
  334. Status = SamSetInformationUser(UserHandle,UserSetPasswordInformation,&UserPasswordInfo);
  335. if(!NT_SUCCESS(Status)) {
  336. goto err5;
  337. }
  338. //
  339. // Set the information bits - User Password not required is cleared
  340. // The normal account bit is enabled and the account disabled bit
  341. // is also reset
  342. //
  343. UserControlInfo->UserAccountControl &= ~USER_PASSWORD_NOT_REQUIRED;
  344. UserControlInfo->UserAccountControl &= ~USER_ACCOUNT_DISABLED;
  345. UserControlInfo->UserAccountControl |= USER_NORMAL_ACCOUNT;
  346. Status = SamSetInformationUser(UserHandle,UserControlInformation,UserControlInfo);
  347. if(!NT_SUCCESS(Status)) {
  348. goto err5;
  349. }
  350. // Set the description is one is given
  351. //
  352. if ( Description[0])
  353. {
  354. // Convert description to unicode string
  355. //
  356. RtlInitUnicodeString(&AdminCommentInfo.AdminComment,Description);
  357. // We do not care if this fails and therefore will not set the status
  358. //
  359. SamSetInformationUser(UserHandle,UserAdminCommentInformation,&AdminCommentInfo);
  360. }
  361. //
  362. // If this is a non-standlone server we're done.
  363. //
  364. if(ISDC(ProductType)) {
  365. Status = STATUS_SUCCESS;
  366. goto err5;
  367. }
  368. //
  369. // Finally add this to the administrators alias in the BuiltIn Domain
  370. //
  371. RtlInitUnicodeString(&UnicodeString,L"Builtin");
  372. Status = SamLookupDomainInSamServer(ServerHandle,&UnicodeString,&BuiltinDomainId);
  373. if(!NT_SUCCESS(Status)) {
  374. goto err5;
  375. }
  376. Status = SamOpenDomain(
  377. ServerHandle,
  378. DOMAIN_READ | DOMAIN_ADMINISTER_SERVER | DOMAIN_EXECUTE,
  379. BuiltinDomainId,
  380. &BuiltinDomainHandle
  381. );
  382. if(!NT_SUCCESS(Status)) {
  383. goto err6;
  384. }
  385. UserSid = CreateSidFromSidAndRid(PolicyCurrentAccountDomainInfo->DomainSid,User_RID);
  386. if(!UserSid) {
  387. goto err7;
  388. }
  389. Status = SamOpenAlias(BuiltinDomainHandle,ALIAS_ADD_MEMBER,DOMAIN_ALIAS_RID_ADMINS,&AliasHandle);
  390. if(!NT_SUCCESS(Status)) {
  391. goto err8;
  392. }
  393. Status = SamAddMemberToAlias(AliasHandle,UserSid);
  394. if(!NT_SUCCESS(Status)) {
  395. goto err9;
  396. }
  397. MYASSERT(NT_SUCCESS(Status));
  398. err9:
  399. SamCloseHandle(AliasHandle);
  400. err8:
  401. if(NT_SUCCESS(Status) && (PointerToUserSid != NULL )) {
  402. *PointerToUserSid = UserSid;
  403. } else {
  404. MyFree(UserSid);
  405. }
  406. err7:
  407. SamCloseHandle(BuiltinDomainHandle);
  408. err6:
  409. SamFreeMemory(BuiltinDomainId);
  410. err5:
  411. SamFreeMemory(UserControlInfo);
  412. err4:
  413. SamCloseHandle(UserHandle);
  414. err3:
  415. SamCloseHandle(DomainHandle);
  416. err2:
  417. LsaFreeMemory( PolicyCurrentAccountDomainInfo );
  418. err1:
  419. SamCloseHandle(ServerHandle);
  420. err0:
  421. return(Status);
  422. }
  423. NTSTATUS
  424. CreateLocalAdminAccount(
  425. IN PCWSTR UserName,
  426. IN PCWSTR Password,
  427. IN PSID* PointerToUserSid OPTIONAL
  428. )
  429. /*++
  430. Routine Description:
  431. Please see CreateLocalAdminAccountEx description.
  432. --*/
  433. {
  434. return ( CreateLocalAdminAccountEx(UserName, Password, L"", PointerToUserSid) );
  435. }
  436. BOOL
  437. GetAccountsDomainName(
  438. IN LSA_HANDLE PolicyHandle, OPTIONAL
  439. OUT PWSTR Name,
  440. IN DWORD NameBufferSize
  441. )
  442. {
  443. POLICY_ACCOUNT_DOMAIN_INFO *pPadi;
  444. NTSTATUS Status ;
  445. BOOL PolicyOpened;
  446. PolicyOpened = FALSE;
  447. if(PolicyHandle == NULL) {
  448. if((PolicyHandle = OpenLsaPolicy()) == NULL) {
  449. return(FALSE);
  450. }
  451. PolicyOpened = TRUE;
  452. }
  453. Status = LsaQueryInformationPolicy(PolicyHandle,PolicyAccountDomainInformation,&pPadi);
  454. if(NT_SUCCESS(Status)) {
  455. if(NameBufferSize <= (pPadi->DomainName.Length/sizeof(WCHAR))) {
  456. Status = STATUS_BUFFER_TOO_SMALL;
  457. } else {
  458. wcsncpy(Name,pPadi->DomainName.Buffer,pPadi->DomainName.Length/sizeof(WCHAR));
  459. Name[pPadi->DomainName.Length/sizeof(WCHAR)] = 0;
  460. }
  461. LsaFreeMemory(pPadi);
  462. }
  463. if(PolicyOpened) {
  464. LsaClose(PolicyHandle);
  465. }
  466. return(NT_SUCCESS(Status));
  467. }
  468. LSA_HANDLE
  469. OpenLsaPolicy(
  470. VOID
  471. )
  472. {
  473. OBJECT_ATTRIBUTES ObjectAttributes;
  474. SECURITY_QUALITY_OF_SERVICE SecurityQualityOfService;
  475. LSA_HANDLE PolicyHandle;
  476. NTSTATUS Status;
  477. PolicyHandle = NULL;
  478. SetupLsaInitObjectAttributes(&ObjectAttributes,&SecurityQualityOfService);
  479. Status = LsaOpenPolicy(NULL,&ObjectAttributes,GENERIC_EXECUTE,&PolicyHandle);
  480. return(NT_SUCCESS(Status) ? PolicyHandle : NULL);
  481. }
  482. PSID
  483. CreateSidFromSidAndRid(
  484. IN PSID DomainSid,
  485. IN DWORD Rid
  486. )
  487. /*++
  488. Routine Description:
  489. This function creates a domain account sid given a domain sid and
  490. the relative id of the account within the domain.
  491. Arguments:
  492. DomainSid - supplies sid for domain of account
  493. Rid - supplies relative id of account
  494. Return Value:
  495. Pointer to Sid, or NULL on failure.
  496. The returned Sid must be freed with MyFree.
  497. --*/
  498. {
  499. NTSTATUS Status;
  500. PSID AccountSid;
  501. UCHAR AccountSubAuthorityCount;
  502. ULONG AccountSidLength;
  503. PULONG RidLocation;
  504. AccountSubAuthorityCount = *RtlSubAuthorityCountSid(DomainSid) + (UCHAR)1;
  505. AccountSidLength = RtlLengthRequiredSid(AccountSubAuthorityCount);
  506. if(AccountSid = (PSID)MyMalloc(AccountSidLength)) {
  507. //
  508. // Copy the domain sid into the first part of the account sid
  509. //
  510. Status = RtlCopySid(AccountSidLength, AccountSid, DomainSid);
  511. //
  512. // Increment the account sid sub-authority count
  513. //
  514. *RtlSubAuthorityCountSid(AccountSid) = AccountSubAuthorityCount;
  515. //
  516. // Add the rid as the final sub-authority
  517. //
  518. RidLocation = RtlSubAuthoritySid(AccountSid, AccountSubAuthorityCount - 1);
  519. *RidLocation = Rid;
  520. }
  521. return(AccountSid);
  522. }
  523. BOOL
  524. SetLocalUserPassword(
  525. IN PCWSTR AccountName,
  526. IN PCWSTR OldPassword,
  527. IN PCWSTR NewPassword
  528. )
  529. /*++
  530. Routine Description:
  531. Change the password for the local user account.
  532. Arguments:
  533. Return value:
  534. Boolean value indicating outcome.
  535. --*/
  536. {
  537. NTSTATUS Status;
  538. BOOL b;
  539. UNICODE_STRING UnicodeString;
  540. UNICODE_STRING OtherUnicodeString;
  541. SECURITY_QUALITY_OF_SERVICE SecurityQualityOfService;
  542. OBJECT_ATTRIBUTES ObjectAttributes;
  543. WCHAR AccountsDomainName[DOMAIN_NAME_MAX];
  544. SAM_HANDLE ServerHandle;
  545. SAM_HANDLE DomainHandle;
  546. SAM_HANDLE UserHandle;
  547. BOOL UserFound;
  548. SAM_ENUMERATE_HANDLE EnumerationContext;
  549. SAM_RID_ENUMERATION *SamRidEnumeration;
  550. UINT i;
  551. UINT CountOfEntries;
  552. ULONG UserRid;
  553. LSA_HANDLE PolicyHandle = NULL;
  554. PPOLICY_ACCOUNT_DOMAIN_INFO PolicyCurrentAccountDomainInfo = NULL;
  555. b = FALSE;
  556. //
  557. // Use SamConnect to connect to the local domain ("") and get a handle
  558. // to the local sam server
  559. //
  560. SetupLsaInitObjectAttributes(&ObjectAttributes,&SecurityQualityOfService);
  561. RtlInitUnicodeString(&UnicodeString,L"");
  562. Status = SamConnect(
  563. &UnicodeString,
  564. &ServerHandle,
  565. SAM_SERVER_CONNECT | SAM_SERVER_LOOKUP_DOMAIN,
  566. &ObjectAttributes
  567. );
  568. if(!NT_SUCCESS(Status)) {
  569. SetuplogError(
  570. LogSevWarning,
  571. SETUPLOG_USE_MESSAGEID,
  572. MSG_LOG_CHANGING_PW_FAIL,
  573. AccountName, NULL,
  574. SETUPLOG_USE_MESSAGEID,
  575. MSG_LOG_X_RETURNED_NTSTATUS,
  576. szSamConnect,
  577. Status,
  578. NULL,NULL);
  579. goto err0;
  580. }
  581. //
  582. // Use the LSA to retrieve the name of the Accounts domain.
  583. //
  584. if(!GetAccountsDomainName(NULL,AccountsDomainName,DOMAIN_NAME_MAX)) {
  585. SetuplogError(
  586. LogSevWarning,
  587. SETUPLOG_USE_MESSAGEID,
  588. MSG_LOG_CHANGING_PW_FAIL,
  589. AccountName, NULL,
  590. SETUPLOG_USE_MESSAGEID,
  591. MSG_LOG_X_RETURNED_STRING,
  592. szGetAccountsDomainName,
  593. szFALSE,
  594. NULL,NULL);
  595. goto err1;
  596. }
  597. //
  598. // Open the AccountDomain. First find the Sid for this
  599. // in the Sam and then open the domain using this sid.
  600. //
  601. //
  602. // Get the AccountDomainSid from the Lsa
  603. //
  604. //
  605. //
  606. // Open the LSA Policy object to set the account domain sid.
  607. //
  608. SetupLsaInitObjectAttributes(&ObjectAttributes,&SecurityQualityOfService);
  609. Status = LsaOpenPolicy(NULL,&ObjectAttributes,MAXIMUM_ALLOWED,&PolicyHandle);
  610. if(NT_SUCCESS(Status)) {
  611. Status = LsaQueryInformationPolicy(
  612. PolicyHandle,
  613. PolicyAccountDomainInformation,
  614. &PolicyCurrentAccountDomainInfo
  615. );
  616. if(NT_SUCCESS(Status)) {
  617. Status = SamOpenDomain(
  618. ServerHandle,
  619. DOMAIN_READ | DOMAIN_LIST_ACCOUNTS | DOMAIN_LOOKUP |
  620. DOMAIN_READ_PASSWORD_PARAMETERS,
  621. PolicyCurrentAccountDomainInfo->DomainSid,
  622. &DomainHandle
  623. );
  624. LsaFreeMemory( PolicyCurrentAccountDomainInfo );
  625. }
  626. LsaClose( PolicyHandle );
  627. }
  628. if(!NT_SUCCESS(Status)) {
  629. SetuplogError(
  630. LogSevWarning,
  631. SETUPLOG_USE_MESSAGEID,
  632. MSG_LOG_CHANGING_PW_FAIL,
  633. AccountName, NULL,
  634. SETUPLOG_USE_MESSAGEID,
  635. MSG_LOG_X_PARAM_RETURNED_NTSTATUS,
  636. szSamOpenDomain,
  637. Status,
  638. AccountsDomainName,
  639. NULL,NULL);
  640. goto err2;
  641. }
  642. //
  643. // Find the account name in this domain - and extract the rid.
  644. //
  645. UserFound = FALSE;
  646. EnumerationContext = 0;
  647. RtlInitUnicodeString(&UnicodeString,AccountName);
  648. do {
  649. Status = SamEnumerateUsersInDomain(
  650. DomainHandle,
  651. &EnumerationContext,
  652. 0L,
  653. &SamRidEnumeration,
  654. 0L,
  655. &CountOfEntries
  656. );
  657. if(!NT_SUCCESS(Status) && (Status != STATUS_MORE_ENTRIES)) {
  658. SetuplogError(
  659. LogSevWarning,
  660. SETUPLOG_USE_MESSAGEID,
  661. MSG_LOG_CHANGING_PW_FAIL,
  662. AccountName, NULL,
  663. SETUPLOG_USE_MESSAGEID,
  664. MSG_LOG_X_RETURNED_NTSTATUS,
  665. szSamEnumerateUsersInDomain,
  666. Status,
  667. NULL,NULL);
  668. goto err3;
  669. }
  670. //
  671. // go through the the SamRidEnumeration buffer for count entries.
  672. //
  673. for(i = 0; (i<CountOfEntries) && !UserFound; i++ ) {
  674. if(RtlEqualUnicodeString(&UnicodeString,&SamRidEnumeration[i].Name,TRUE)) {
  675. UserRid = SamRidEnumeration[i].RelativeId;
  676. UserFound = TRUE;
  677. }
  678. }
  679. SamFreeMemory(SamRidEnumeration);
  680. } while((Status == STATUS_MORE_ENTRIES) && !UserFound);
  681. if(!UserFound) {
  682. SetuplogError(
  683. LogSevWarning,
  684. SETUPLOG_USE_MESSAGEID,
  685. MSG_LOG_CHANGING_PW_FAIL,
  686. AccountName,NULL,
  687. SETUPLOG_USE_MESSAGEID,
  688. MSG_LOG_USERNOTFOUND,
  689. NULL,NULL);
  690. goto err3;
  691. }
  692. //
  693. // Open the user
  694. //
  695. Status = SamOpenUser(
  696. DomainHandle,
  697. USER_READ_ACCOUNT | USER_WRITE_ACCOUNT | USER_CHANGE_PASSWORD | USER_FORCE_PASSWORD_CHANGE,
  698. UserRid,
  699. &UserHandle
  700. );
  701. if(!NT_SUCCESS(Status)) {
  702. SetuplogError(
  703. LogSevWarning,
  704. SETUPLOG_USE_MESSAGEID,
  705. MSG_LOG_CHANGING_PW_FAIL,
  706. AccountName, NULL,
  707. SETUPLOG_USE_MESSAGEID,
  708. MSG_LOG_X_RETURNED_NTSTATUS,
  709. szSamOpenUser,
  710. Status,
  711. NULL,NULL);
  712. goto err3;
  713. }
  714. //
  715. // Use SAM API to change the password for this Account.
  716. //
  717. RtlInitUnicodeString(&UnicodeString,OldPassword);
  718. RtlInitUnicodeString(&OtherUnicodeString,NewPassword);
  719. Status = SamChangePasswordUser(UserHandle,&UnicodeString,&OtherUnicodeString);
  720. if(!NT_SUCCESS(Status)) {
  721. SetuplogError(
  722. LogSevWarning,
  723. SETUPLOG_USE_MESSAGEID,
  724. MSG_LOG_CHANGING_PW_FAIL,
  725. AccountName, NULL,
  726. SETUPLOG_USE_MESSAGEID,
  727. MSG_LOG_X_RETURNED_NTSTATUS,
  728. szSamChangePasswordUser,
  729. Status,
  730. NULL,NULL);
  731. goto err4;
  732. }
  733. b = TRUE;
  734. err4:
  735. SamCloseHandle(UserHandle);
  736. err3:
  737. SamCloseHandle(DomainHandle);
  738. err2:
  739. err1:
  740. SamCloseHandle(ServerHandle);
  741. err0:
  742. return(b);
  743. }
  744. VOID
  745. GenerateRandomPassword(
  746. OUT PWSTR Password
  747. )
  748. {
  749. static DWORD Seed = 98725757;
  750. static PCWSTR UsableChars = L"ABCDEFGHIJKLMOPQRSTUVWYZabcdefghijklmopqrstuvwyz0123456789";
  751. UINT UsableCount;
  752. UINT i;
  753. UsableCount = lstrlen(UsableChars);
  754. Seed ^= GetCurrentTime();
  755. for(i=0; i<PASSWORD_MAX; i++) {
  756. Password[i] = UsableChars[RtlRandom(&Seed) % UsableCount];
  757. }
  758. Password[i] = 0;
  759. }
  760. NTSTATUS
  761. MyAddLsaSecretObject(
  762. IN PCWSTR Password
  763. )
  764. /*++
  765. Routine Description:
  766. Create the Secret Object necessary to support a machine account
  767. on an NT domain.
  768. Arguments:
  769. Password - supplies password to machine account
  770. Return value:
  771. NT Status code indicating outcome.
  772. --*/
  773. {
  774. UNICODE_STRING SecretName;
  775. UNICODE_STRING UnicodePassword;
  776. NTSTATUS Status;
  777. LSA_HANDLE LsaHandle;
  778. LSA_HANDLE SecretHandle;
  779. OBJECT_ATTRIBUTES ObjAttr;
  780. RtlInitUnicodeString(&SecretName,SsiSecretName) ;
  781. RtlInitUnicodeString(&UnicodePassword,Password);
  782. InitializeObjectAttributes(&ObjAttr,NULL,0,NULL,NULL);
  783. Status = LsaOpenPolicy(NULL,&ObjAttr,MAXIMUM_ALLOWED,&LsaHandle);
  784. if(NT_SUCCESS(Status)) {
  785. Status = LsaCreateSecret(LsaHandle,&SecretName,SECRET_ALL_ACCESS,&SecretHandle);
  786. if(NT_SUCCESS(Status)) {
  787. Status = LsaSetSecret(SecretHandle,&UnicodePassword,&UnicodePassword);
  788. LsaClose(SecretHandle);
  789. }
  790. LsaClose(LsaHandle);
  791. }
  792. return(Status);
  793. }
  794. BOOL
  795. AdjustPrivilege(
  796. IN PCWSTR Privilege,
  797. IN BOOL Enable
  798. )
  799. /*++
  800. Routine Description:
  801. This routine enables or disable a priviliege of the current process.
  802. Arguments:
  803. Privilege - String with the name of the privilege to be adjusted.
  804. Enable - TRUE if the privilege is to be enabled.
  805. FALSE if the privilege is to be disabled.
  806. Return Value:
  807. Returns TRUE if the privilege could be adjusted.
  808. Returns FALSE, otherwise.
  809. --*/
  810. {
  811. HANDLE TokenHandle;
  812. LUID_AND_ATTRIBUTES LuidAndAttributes;
  813. TOKEN_PRIVILEGES TokenPrivileges;
  814. if( !OpenProcessToken( GetCurrentProcess(),
  815. TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
  816. &TokenHandle ) ) {
  817. SetupDebugPrint1(L"SYSSETUP: OpenProcessToken() failed. Error = %d \n", GetLastError() );
  818. return( FALSE );
  819. }
  820. if( !LookupPrivilegeValue( NULL,
  821. Privilege,
  822. &( LuidAndAttributes.Luid ) ) ) {
  823. SetupDebugPrint1(L"SYSSETUP: LookupPrivilegeValue failed, Error = %d \n", GetLastError() );
  824. CloseHandle( TokenHandle );
  825. return( FALSE );
  826. }
  827. if( Enable ) {
  828. LuidAndAttributes.Attributes |= SE_PRIVILEGE_ENABLED;
  829. } else {
  830. LuidAndAttributes.Attributes &= ~SE_PRIVILEGE_ENABLED;
  831. }
  832. TokenPrivileges.PrivilegeCount = 1;
  833. TokenPrivileges.Privileges[0] = LuidAndAttributes;
  834. if( !AdjustTokenPrivileges( TokenHandle,
  835. FALSE,
  836. &TokenPrivileges,
  837. 0,
  838. NULL,
  839. NULL ) ) {
  840. SetupDebugPrint1(L"SYSSETUP: AdjustTokenPrivileges failed, Error = %d \n", GetLastError() );
  841. CloseHandle( TokenHandle );
  842. return( FALSE );
  843. }
  844. CloseHandle( TokenHandle );
  845. return( TRUE );
  846. }
  847. NTSTATUS
  848. DisableLocalUserAccount(
  849. PWSTR AccountName
  850. )
  851. /*++
  852. Routine Description:
  853. This routine disables the local administrator account.
  854. Arguments:
  855. AccountName - Name of the local account to be disabled.
  856. Return Value:
  857. NTSTATUS, depending on the outcome of the operations.
  858. --*/
  859. {
  860. LONG rc;
  861. PUSER_INFO_1 ui1;
  862. // Get the info.
  863. rc = NetUserGetInfo( NULL,
  864. AccountName,
  865. 1,
  866. (PBYTE *)(&ui1) );
  867. if( rc == NO_ERROR ) {
  868. // set the disable flag and store the info back out.
  869. ui1->usri1_flags |= UF_ACCOUNTDISABLE;
  870. rc = NetUserSetInfo( NULL,
  871. AccountName,
  872. 1,
  873. (PBYTE)ui1,
  874. NULL );
  875. NetApiBufferFree((PVOID)ui1);
  876. }
  877. return rc;
  878. }
  879. NTSTATUS
  880. DisableLocalAdminAccount(
  881. VOID
  882. )
  883. /*++
  884. Routine Description:
  885. This routine disables the local administrator account.
  886. Arguments:
  887. None.
  888. Return Value:
  889. NTSTATUS, depending on the outcome of the operations.
  890. --*/
  891. {
  892. NTSTATUS Status = STATUS_SUCCESS;
  893. WCHAR AdminAccountName[MAX_PATH];
  894. GetAdminAccountName( AdminAccountName );
  895. Status = DisableLocalUserAccount( AdminAccountName );
  896. return Status;
  897. }