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.

1262 lines
30 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. security.c
  5. Abstract:
  6. Helpers for NT security API.
  7. Author:
  8. Jim Schmidt (jimschm) 05-Feb-1997
  9. Revision History:
  10. ovidiut 14-Mar-2000 Updated CreateLocalAccount for encrypted password feature
  11. jimschm 02-Jun-1999 Added SetRegKeySecurity
  12. jimschm 18-Mar-1998 Updated CreateLocalAccount for random password
  13. feature. Added password change if account
  14. already exists.
  15. --*/
  16. #include "pch.h"
  17. #include "migmainp.h"
  18. #include "security.h"
  19. #include "encrypt.h"
  20. #include <ntdsapi.h>
  21. #include <dsgetdc.h>
  22. #ifndef UNICODE
  23. #error UNICODE definition required for account lookup code
  24. #endif
  25. #define UNDOCUMENTED_UI_FLAG 0x0200
  26. //
  27. // NT 5 - net share-specific flag
  28. //
  29. DWORD
  30. ConvertNetRightsToAccessMask (
  31. IN DWORD Flags
  32. )
  33. /*++
  34. Routine Description:
  35. Routine that converts LAN Man flags into NT security flags.
  36. Arguments:
  37. Flags - Access flags used with NetAccess* APIs
  38. Return value:
  39. A DWORD containing the NT security flags.
  40. --*/
  41. {
  42. DWORD OutFlags;
  43. if (Flags == ACCESS_READ) {
  44. //
  45. // Read only permissions
  46. //
  47. OutFlags = FILE_GENERIC_READ|FILE_GENERIC_EXECUTE;
  48. } else if (Flags == ACCESS_WRITE) {
  49. //
  50. // Change only permission
  51. //
  52. OutFlags = FILE_GENERIC_WRITE|DELETE;
  53. } else if (Flags == (ACCESS_READ|ACCESS_WRITE)) {
  54. //
  55. // Full control permissions
  56. //
  57. OutFlags = FILE_ALL_ACCESS|UNDOCUMENTED_UI_FLAG;
  58. } else {
  59. //
  60. // Unsupported options... disable the share
  61. //
  62. OutFlags = 0;
  63. DEBUGMSG ((DBG_VERBOSE, "Unsupported permission %u was translated to disable permission", Flags));
  64. }
  65. return OutFlags;
  66. }
  67. DWORD
  68. AddAclMember (
  69. IN OUT PGROWBUFFER GrowBuf,
  70. IN PCTSTR UserOrGroup,
  71. IN DWORD Attributes
  72. )
  73. /*++
  74. Routine Description:
  75. Appends user/group account, attributes and enable flag to a list
  76. of members. This funciton is used to build a list of members which
  77. is passed to CreateAclFromMemberList to create an ACL.
  78. Arguments:
  79. GrowBuf - A GROWBUFFER variable that is zero-initialized
  80. UserOrGroup - String specifying user name or group
  81. Attributes - A list of access rights (a combination of flags
  82. from NetAccess* APIs). Currently the only flags
  83. that are used are:
  84. 0 - Deny all access
  85. ACCESS_READ - Read-Only access
  86. ACCESS_WRITE - Change-Only access
  87. ACCESS_READ|ACCESS_WRITE - Full access
  88. Return value:
  89. The number of bytes needed to store UserOrGroup, Attributes and Enabled,
  90. or zero if the function fails. GrowBuf may be expanded to hold the
  91. new data.
  92. GrowBuf must be freed by the caller after the ACL is generated.
  93. --*/
  94. {
  95. DWORD Size;
  96. PACLMEMBER AclMemberPtr;
  97. TCHAR RealName[MAX_USER_NAME];
  98. DWORD OriginalAttribs;
  99. BOOL Everyone;
  100. PCTSTR p;
  101. p = _tcschr (UserOrGroup, TEXT('\\'));
  102. if (p) {
  103. UserOrGroup = _tcsinc (p);
  104. }
  105. if (StringMatch (UserOrGroup, TEXT("*"))) {
  106. _tcssafecpy (RealName, g_EveryoneStr, MAX_USER_NAME);
  107. } else {
  108. _tcssafecpy (RealName, UserOrGroup, MAX_USER_NAME);
  109. }
  110. Everyone = StringIMatch (RealName, g_EveryoneStr);
  111. Size = SizeOfString (RealName) + sizeof (ACLMEMBER);
  112. AclMemberPtr = (PACLMEMBER) GrowBuffer (GrowBuf, Size);
  113. OriginalAttribs = Attributes;
  114. if (!Attributes && !Everyone) {
  115. Attributes = ACCESS_READ|ACCESS_WRITE;
  116. }
  117. AclMemberPtr->Attribs = ConvertNetRightsToAccessMask (Attributes);
  118. AclMemberPtr->Enabled = Everyone || OriginalAttribs != 0;
  119. AclMemberPtr->Failed = FALSE;
  120. StringCopy (AclMemberPtr->UserOrGroup, RealName);
  121. return Size;
  122. }
  123. PACL
  124. CreateAclFromMemberList (
  125. PBYTE AclMemberList,
  126. DWORD MemberCount
  127. )
  128. /*++
  129. Routine Description:
  130. CreateAclFromMemberList takes a member list (prepared by AddAclMember)
  131. and generates an ACL.
  132. Arguments:
  133. AclMemberList - A pointer to the buffer maintained by AddAclMember. This
  134. is usually the Buf member of a GROWBUFFER variable.
  135. MemberCount - The number of members in AclMemberList (i.e. the number of
  136. AddAclMember calls)
  137. Return value:
  138. A pointer to a MemAlloc'd ACL, or NULL if an error occurred. Call
  139. FreeMemberListAcl to free a non-NULL return value.
  140. --*/
  141. {
  142. PACLMEMBER AclMemberPtr;
  143. DWORD AllowedAceCount;
  144. DWORD DeniedAceCount;
  145. DWORD d;
  146. PACL Acl = NULL;
  147. DWORD AclSize;
  148. BOOL b = FALSE;
  149. UINT SidSize = 0;
  150. __try {
  151. //
  152. // Create SID array for all members
  153. //
  154. AclMemberPtr = (PACLMEMBER) AclMemberList;
  155. AllowedAceCount = 0;
  156. DeniedAceCount = 0;
  157. for (d = 0 ; d < MemberCount ; d++) {
  158. AclMemberPtr->Sid = GetSidForUser (AclMemberPtr->UserOrGroup);
  159. if (!AclMemberPtr->Sid) {
  160. // Mark an error
  161. AclMemberPtr->Failed = TRUE;
  162. } else {
  163. // Found SID, adjust ace count and sid size
  164. if (AclMemberPtr->Enabled) {
  165. AllowedAceCount++;
  166. } else {
  167. DeniedAceCount++;
  168. }
  169. SidSize += GetLengthSid (AclMemberPtr->Sid);
  170. }
  171. GetNextAclMember (&AclMemberPtr);
  172. }
  173. //
  174. // Calculate size of ACL (an ACL struct plus the ACEs) and allocate it.
  175. //
  176. // We subtract a DWORD from the struct size because the actual size of all
  177. // SidStart members is given by SidSize.
  178. //
  179. AclSize = sizeof (ACL) +
  180. AllowedAceCount * (sizeof (ACCESS_ALLOWED_ACE) - sizeof (DWORD)) +
  181. DeniedAceCount * (sizeof (ACCESS_DENIED_ACE) - sizeof (DWORD)) +
  182. SidSize;
  183. Acl = (PACL) MemAlloc (g_hHeap, 0, AclSize);
  184. if (!Acl) {
  185. LOG ((LOG_ERROR, "Couldn't allocate an ACL"));
  186. __leave;
  187. }
  188. //
  189. // Create the ACL
  190. //
  191. if (!InitializeAcl (Acl, AclSize, ACL_REVISION)) {
  192. LOG ((LOG_ERROR, "Couldn't initialize ACL"));
  193. __leave;
  194. }
  195. //
  196. // Add the access-denied ACLs first
  197. //
  198. AclMemberPtr = (PACLMEMBER) AclMemberList;
  199. for (d = 0 ; d < MemberCount ; d++) {
  200. if (AclMemberPtr->Failed) {
  201. continue;
  202. }
  203. if (!AclMemberPtr->Enabled) {
  204. if (!AddAccessDeniedAce (
  205. Acl,
  206. ACL_REVISION,
  207. AclMemberPtr->Attribs,
  208. AclMemberPtr->Sid
  209. )) {
  210. LOG ((
  211. LOG_ERROR,
  212. "Couldn't add denied ACE for %s",
  213. AclMemberPtr->UserOrGroup
  214. ));
  215. }
  216. }
  217. GetNextAclMember (&AclMemberPtr);
  218. }
  219. //
  220. // Add the access-enabled ACLs last
  221. //
  222. // Reset the SID pointer because CreateAclFromMemberList is the
  223. // only ones who uses this member
  224. //
  225. AclMemberPtr = (PACLMEMBER) AclMemberList;
  226. for (d = 0 ; d < MemberCount ; d++) {
  227. if (AclMemberPtr->Failed) {
  228. continue;
  229. }
  230. //
  231. // Add member to list
  232. //
  233. if (AclMemberPtr->Enabled) {
  234. if (!AddAccessAllowedAce (
  235. Acl,
  236. ACL_REVISION,
  237. AclMemberPtr->Attribs,
  238. AclMemberPtr->Sid
  239. )) {
  240. LOG ((
  241. LOG_ERROR,
  242. "Couldn't add allowed ACE for %s",
  243. AclMemberPtr->UserOrGroup
  244. ));
  245. }
  246. }
  247. AclMemberPtr->Sid = NULL;
  248. GetNextAclMember (&AclMemberPtr);
  249. }
  250. b = TRUE;
  251. }
  252. __finally {
  253. if (!b) {
  254. if (Acl) {
  255. MemFree (g_hHeap, 0, Acl);
  256. }
  257. Acl = NULL;
  258. }
  259. }
  260. return Acl;
  261. }
  262. VOID
  263. FreeMemberListAcl (
  264. PACL Acl
  265. )
  266. /*++
  267. Routine Description:
  268. Routine to free the value returned by CreateAclFromMemberList
  269. Arguments:
  270. Acl - The return value of CreateAclFromMemberList
  271. Return value:
  272. none
  273. --*/
  274. {
  275. if (Acl) {
  276. MemFree (g_hHeap, 0, (LPVOID) Acl);
  277. }
  278. }
  279. VOID
  280. GetNextAclMember (
  281. PACLMEMBER *AclMemberPtrToPtr
  282. )
  283. /*++
  284. Routine Description:
  285. GetNextAclMember adjusts an ACLMEMBER pointer to point to the next
  286. member. Each member is a variable-length structure, so this funciton
  287. is required to walk the structure array.
  288. Arguments:
  289. AclMemberPtrToPtr - A pointer to a PACLMEMBER variable.
  290. Return value:
  291. none
  292. --*/
  293. {
  294. *AclMemberPtrToPtr = (PACLMEMBER) ((PBYTE) (*AclMemberPtrToPtr) +
  295. sizeof (ACLMEMBER) +
  296. SizeOfString ((*AclMemberPtrToPtr)->UserOrGroup)
  297. );
  298. }
  299. LONG
  300. CreateLocalAccount (
  301. IN PACCOUNTPROPERTIES Properties,
  302. IN PCWSTR User OPTIONAL
  303. )
  304. /*++
  305. Routine Description:
  306. CreateLocalAccount creates an account for a local user
  307. Arguments:
  308. Properties - Specifies a set of attributes for a user
  309. User - An optional name to override Properties->User
  310. Return value:
  311. A Win32 error code
  312. --*/
  313. {
  314. USER_INFO_3 ui;
  315. PUSER_INFO_3 ExistingInfo;
  316. DWORD rc;
  317. LONG ErrParam;
  318. PCWSTR UnicodeUser;
  319. PCWSTR UnicodePassword;
  320. PCWSTR UnicodeFullName;
  321. PCWSTR UnicodeComment;
  322. //
  323. // Create local account
  324. //
  325. if (!User) {
  326. User = Properties->User;
  327. }
  328. UnicodeUser = CreateUnicode (User);
  329. UnicodePassword = CreateUnicode (Properties->Password);
  330. UnicodeComment = CreateUnicode (Properties->AdminComment);
  331. UnicodeFullName = CreateUnicode (Properties->FullName);
  332. ZeroMemory (&ui, sizeof (ui));
  333. ui.usri3_name = (PWSTR) UnicodeUser;
  334. ui.usri3_password = (PWSTR) UnicodePassword;
  335. ui.usri3_comment = (PWSTR) UnicodeComment;
  336. ui.usri3_full_name = (PWSTR) UnicodeFullName;
  337. ui.usri3_priv = USER_PRIV_USER; // do not change
  338. ui.usri3_flags = UF_SCRIPT|UF_NORMAL_ACCOUNT;
  339. ui.usri3_acct_expires = TIMEQ_FOREVER;
  340. ui.usri3_max_storage = USER_MAXSTORAGE_UNLIMITED;
  341. ui.usri3_primary_group_id = DOMAIN_GROUP_RID_USERS;
  342. ui.usri3_max_storage = USER_MAXSTORAGE_UNLIMITED;
  343. ui.usri3_acct_expires = TIMEQ_FOREVER;
  344. ui.usri3_password_expired = (INT) g_ConfigOptions.ForcePasswordChange;
  345. rc = NetUserAdd (NULL, 3, (PBYTE) &ui, &ErrParam);
  346. if (rc == ERROR_SUCCESS) {
  347. if (Properties->PasswordAttribs & PASSWORD_ATTR_ENCRYPTED) {
  348. //
  349. // change user's password using encrypted password APIs
  350. //
  351. rc = SetLocalUserEncryptedPassword (
  352. User,
  353. Properties->Password,
  354. FALSE,
  355. Properties->EncryptedPassword,
  356. TRUE
  357. );
  358. if (rc != ERROR_SUCCESS) {
  359. if (rc == ERROR_PASSWORD_RESTRICTION) {
  360. LOG ((
  361. LOG_WARNING,
  362. "Unable to set supplied password on user %s because a password rule has been violated.",
  363. User
  364. ));
  365. } else if (rc == ERROR_INVALID_PARAMETER) {
  366. LOG ((
  367. LOG_WARNING,
  368. "Illegal encrypted password supplied for user %s.",
  369. User
  370. ));
  371. } else {
  372. LOG ((
  373. LOG_WARNING,
  374. "Unable to set password on user %s, rc=%u",
  375. User,
  376. rc
  377. ));
  378. rc = ERROR_INVALID_PARAMETER;
  379. }
  380. }
  381. }
  382. } else if (rc == NERR_UserExists) {
  383. //
  384. // Try to change password if user already exists and this is the intent
  385. //
  386. DEBUGMSG ((DBG_WARNING, "User %s already exists", User));
  387. if ((Properties->PasswordAttribs & PASSWORD_ATTR_DONT_CHANGE_IF_EXIST) == 0) {
  388. if (Properties->PasswordAttribs & PASSWORD_ATTR_ENCRYPTED) {
  389. rc = SetLocalUserEncryptedPassword (
  390. User,
  391. Properties->Password,
  392. FALSE,
  393. Properties->EncryptedPassword,
  394. TRUE
  395. );
  396. if (rc != ERROR_SUCCESS) {
  397. if (rc == ERROR_PASSWORD_RESTRICTION) {
  398. LOG ((
  399. LOG_WARNING,
  400. "Unable to set supplied password on user %s because a password rule has been violated.",
  401. User
  402. ));
  403. } else if (rc == ERROR_INVALID_PARAMETER) {
  404. LOG ((
  405. LOG_WARNING,
  406. "Illegal encrypted password supplied for user %s.",
  407. User
  408. ));
  409. } else {
  410. LOG ((
  411. LOG_WARNING,
  412. "Unable to set password on user %s, rc=%u",
  413. User,
  414. rc
  415. ));
  416. rc = ERROR_INVALID_PARAMETER;
  417. }
  418. }
  419. } else {
  420. rc = NetUserGetInfo (NULL, User, 3, (PBYTE *) &ExistingInfo);
  421. if (rc == ERROR_SUCCESS) {
  422. ExistingInfo->usri3_password = ui.usri3_password;
  423. ExistingInfo->usri3_comment = ui.usri3_comment;
  424. ExistingInfo->usri3_full_name = ui.usri3_full_name;
  425. ExistingInfo->usri3_flags = ui.usri3_flags;
  426. ExistingInfo->usri3_password_expired = ui.usri3_password_expired;
  427. rc = NetUserSetInfo (NULL, User, 3, (PBYTE) ExistingInfo, &ErrParam);
  428. NetApiBufferFree ((PVOID) ExistingInfo);
  429. if (rc != ERROR_SUCCESS) {
  430. LOG ((LOG_WARNING, "NetUserSetInfo failed for %s. rc=%u.", User, rc));
  431. rc = ERROR_INVALID_PARAMETER;
  432. }
  433. } else {
  434. LOG ((LOG_WARNING, "NetUserGetInfo failed for %s. rc=%u.", User, rc));
  435. rc = ERROR_INVALID_PARAMETER;
  436. }
  437. }
  438. } else {
  439. rc = ERROR_SUCCESS;
  440. }
  441. } else {
  442. LOG ((LOG_ERROR, "NetUserAdd failed for %s. ErrParam=%i.", User, ErrParam));
  443. }
  444. DestroyUnicode (UnicodeUser);
  445. DestroyUnicode (UnicodePassword);
  446. DestroyUnicode (UnicodeComment);
  447. DestroyUnicode (UnicodeFullName);
  448. return rc;
  449. }
  450. VOID
  451. ClearAdminPassword (
  452. VOID
  453. )
  454. {
  455. ACCOUNTPROPERTIES Properties;
  456. Properties.Password = L"";
  457. Properties.AdminComment = L"";
  458. Properties.User = g_AdministratorStr;
  459. Properties.FullName = g_AdministratorStr;
  460. CreateLocalAccount (&Properties, NULL);
  461. }
  462. BOOL
  463. AddSidToLocalGroup (
  464. PSID Sid,
  465. PCWSTR Group
  466. )
  467. /*++
  468. Routine Description:
  469. Routine that adds the supplied SID to the Administrators group.
  470. Arguments:
  471. Sid - A valid security id for the user to be added to the
  472. Administrators group
  473. Group - Specifies the group name to join the user to
  474. Return value:
  475. TRUE if the member was added successfully
  476. --*/
  477. {
  478. LOCALGROUP_MEMBERS_INFO_0 lgrmi0;
  479. DWORD rc;
  480. lgrmi0.lgrmi0_sid = Sid;
  481. rc = NetLocalGroupAddMembers (
  482. NULL,
  483. Group,
  484. 0, // level 0
  485. (PBYTE) &lgrmi0,
  486. 1 // member count
  487. );
  488. return rc == ERROR_SUCCESS;
  489. }
  490. NTSTATUS
  491. pGetPrimaryDomainInfo (
  492. POLICY_PRIMARY_DOMAIN_INFO **PrimaryInfoPtr
  493. )
  494. /*++
  495. Routine Description:
  496. Private function that retrieves the primary domain info.
  497. Arguments:
  498. PrimaryInfoPtr - Pointer to a variable to receive the address
  499. of the POLICY_PRIMARY_DOMAIN_INFO structure
  500. allocated by the Lsa APIs. Free memory by
  501. calling LsaFreeMemory.
  502. Return value:
  503. NT status code indicating outcome
  504. --*/
  505. {
  506. LSA_HANDLE policyHandle;
  507. NTSTATUS status;
  508. //
  509. // Open local LSA policy to retrieve domain name
  510. //
  511. status = OpenPolicy (
  512. NULL, // local target machine
  513. POLICY_VIEW_LOCAL_INFORMATION, // Access type
  514. &policyHandle // resultant policy handle
  515. );
  516. if (status == ERROR_SUCCESS) {
  517. //
  518. // Query LSA Primary domain info
  519. //
  520. status = LsaQueryInformationPolicy (
  521. policyHandle,
  522. PolicyPrimaryDomainInformation,
  523. (PVOID *) PrimaryInfoPtr
  524. );
  525. LsaClose (policyHandle);
  526. }
  527. return status;
  528. }
  529. BOOL
  530. GetPrimaryDomainName (
  531. OUT PTSTR DomainName
  532. )
  533. {
  534. NTSTATUS status;
  535. POLICY_PRIMARY_DOMAIN_INFO *PrimaryInfo;
  536. PCTSTR TcharName;
  537. status = pGetPrimaryDomainInfo (&PrimaryInfo);
  538. if (status == ERROR_SUCCESS) {
  539. TcharName = ConvertWtoT (PrimaryInfo->Name.Buffer);
  540. MYASSERT (TcharName);
  541. StringCopy (DomainName, TcharName);
  542. FreeWtoT (TcharName);
  543. LsaFreeMemory (PrimaryInfo);
  544. }
  545. ELSE_DEBUGMSG ((DBG_WARNING, "Can't get primary domain info. rc=%u", status));
  546. return status == ERROR_SUCCESS;
  547. }
  548. BOOL
  549. GetPrimaryDomainSid (
  550. OUT PBYTE DomainSid,
  551. IN UINT MaxBytes
  552. )
  553. {
  554. NTSTATUS status;
  555. POLICY_PRIMARY_DOMAIN_INFO *PrimaryInfo;
  556. UINT Size;
  557. status = pGetPrimaryDomainInfo (&PrimaryInfo);
  558. if (status == ERROR_SUCCESS) {
  559. Size = GetLengthSid (PrimaryInfo->Sid);
  560. if (MaxBytes < Size) {
  561. status = ERROR_INSUFFICIENT_BUFFER;
  562. } else {
  563. CopyMemory (DomainSid, PrimaryInfo->Sid, Size);
  564. }
  565. LsaFreeMemory (PrimaryInfo);
  566. }
  567. ELSE_DEBUGMSG ((DBG_WARNING, "Can't get primary domain SID. rc=%u", status));
  568. return status == ERROR_SUCCESS;
  569. }
  570. BOOL
  571. IsMemberOfDomain (
  572. VOID
  573. )
  574. /*++
  575. Routine Description:
  576. Determines if the machine is participating in a domain, or if it is
  577. only participating in a workgroup. This determination is done by
  578. obtaining the primary domain information, looking for the server's
  579. SID. If the SID is NULL, the machine is not in a domain.
  580. Arguments:
  581. none
  582. Return value:
  583. TRUE if the machine is in a domain, FALSE if its in a workgroup.
  584. --*/
  585. {
  586. NET_API_STATUS rc;
  587. PWSTR WorkgroupOrDomain = NULL;
  588. NETSETUP_JOIN_STATUS Type;
  589. rc = NetGetJoinInformation (NULL, &WorkgroupOrDomain, &Type);
  590. DEBUGMSG ((DBG_VERBOSE, "NetGetJoinInformation: name=%s, type=%u", WorkgroupOrDomain, Type));
  591. if (WorkgroupOrDomain) {
  592. NetApiBufferFree (WorkgroupOrDomain);
  593. }
  594. if (rc != ERROR_SUCCESS) {
  595. LOG ((LOG_ERROR, "NetGetJoinInformation failed: error %u", rc));
  596. }
  597. return rc == ERROR_SUCCESS && Type == NetSetupDomainName;
  598. #if 0
  599. POLICY_PRIMARY_DOMAIN_INFO *PrimaryInfo;
  600. BOOL b;
  601. NTSTATUS rc;
  602. rc = pGetPrimaryDomainInfo (&PrimaryInfo);
  603. if (rc == ERROR_SUCCESS) {
  604. b = PrimaryInfo->Sid != NULL;
  605. } else {
  606. b = FALSE;
  607. SetLastError (rc);
  608. LOG ((LOG_ERROR, "Can't get domain security info"));
  609. }
  610. // Domain name is in PrimaryInfo->Name.Buffer
  611. LsaFreeMemory (PrimaryInfo) ;
  612. return b;
  613. #endif
  614. }
  615. LONG
  616. GetAnyDC (
  617. IN PCWSTR Domain,
  618. IN PWSTR ServerBuf,
  619. IN BOOL GetNewServer
  620. )
  621. /*++
  622. Routine Description:
  623. Gets the list of all domain controllers and randomly chooses one. If
  624. the listed DC is not online, other listed DCs are queried until an
  625. alive DC is found.
  626. Arguments:
  627. Domain - The name of the domain to find DCs for
  628. ServerBuf - A buffer to hold the name of the server
  629. Return value:
  630. NT status code indicating outcome.
  631. --*/
  632. {
  633. DWORD rc;
  634. PDOMAIN_CONTROLLER_INFO dci;
  635. DWORD Flags = DS_IS_FLAT_NAME;
  636. //
  637. // This API is fast because its WINS based...
  638. //
  639. rc = DsGetDcName (
  640. NULL, // computer to remote to
  641. Domain,
  642. NULL, // Domain GUID
  643. NULL, // Site GUID
  644. Flags | (GetNewServer ? DS_FORCE_REDISCOVERY : 0),
  645. &dci
  646. );
  647. if (rc == NO_ERROR) {
  648. StringCopyW (ServerBuf, dci->DomainControllerAddress);
  649. NetApiBufferFree (dci);
  650. DEBUGMSG ((DBG_VERBOSE, "Found server %s for the %s domain", ServerBuf, Domain));
  651. return rc;
  652. }
  653. return rc;
  654. }
  655. VOID
  656. InitLsaString (
  657. OUT PLSA_UNICODE_STRING LsaString,
  658. IN PWSTR String
  659. )
  660. /*++
  661. Routine Description:
  662. LSA uses a special Pascal-style string structure. This
  663. routine assigns String to a member of LsaString, and computes
  664. its length and maximum length.
  665. Arguments:
  666. LsaString - A pointer to the structure to receive a pointer
  667. to the nul-terminated string, the length in bytes
  668. (excluding the nul), and the maximum length including
  669. the nul.
  670. Return value:
  671. none
  672. --*/
  673. {
  674. USHORT StringLength;
  675. if (!String) {
  676. ZeroMemory (LsaString, sizeof (LSA_UNICODE_STRING));
  677. return;
  678. }
  679. StringLength = ByteCountW (String);
  680. LsaString->Buffer = String;
  681. LsaString->Length = StringLength;
  682. LsaString->MaximumLength = StringLength + sizeof(WCHAR);
  683. }
  684. NTSTATUS
  685. OpenPolicy (
  686. IN PWSTR ServerName,
  687. IN DWORD DesiredAccess,
  688. OUT PLSA_HANDLE policyHandle
  689. )
  690. /*++
  691. Routine Description:
  692. A wrapper to simplify LsaOpenPolicy
  693. Arguments:
  694. ServerName - Supplies the server to open the policy on. Specify
  695. NULL for local machine.
  696. DesiredAccess - The access flags passed to the LSA API
  697. policyHandle - Receives the policy handle if successful
  698. Return value:
  699. NT status code indicating outcome
  700. --*/
  701. {
  702. LSA_OBJECT_ATTRIBUTES objectAttributes;
  703. LSA_UNICODE_STRING ServerString;
  704. PLSA_UNICODE_STRING Server;
  705. //
  706. // Always initialize the object attributes to all zeroes
  707. //
  708. ZeroMemory (&objectAttributes, sizeof(objectAttributes));
  709. if (ServerName != NULL) {
  710. //
  711. // Make a LSA_UNICODE_STRING out of the PWSTR passed in
  712. //
  713. InitLsaString (&ServerString, ServerName);
  714. Server = &ServerString;
  715. } else {
  716. Server = NULL;
  717. }
  718. //
  719. // Attempt to open the policy
  720. //
  721. return LsaOpenPolicy (
  722. Server,
  723. &objectAttributes,
  724. DesiredAccess,
  725. policyHandle
  726. );
  727. }
  728. BOOL
  729. IsDomainController(
  730. IN PWSTR Server,
  731. OUT PBOOL DomainControllerFlag
  732. )
  733. /*++
  734. Routine Description:
  735. Queries if the machine is a server or workstation via
  736. the NetServerGetInfo API.
  737. Arguments:
  738. Server - The machine to query, or NULL for the local machine
  739. DomainControllerFlag - Receives TRUE if the machine is a
  740. domain controller, or FALSE if the
  741. machine is a workstation.
  742. Return value:
  743. TRUE if the API was successful, or FALSE if not. GetLastError
  744. gives failure code.
  745. --*/
  746. {
  747. PSERVER_INFO_101 si101;
  748. NET_API_STATUS nas;
  749. nas = NetServerGetInfo(
  750. Server,
  751. 101, // info-level
  752. (PBYTE *) &si101
  753. );
  754. if (nas != NO_ERROR) {
  755. SetLastError (nas);
  756. return FALSE;
  757. }
  758. if ((si101->sv101_type & SV_TYPE_DOMAIN_CTRL) ||
  759. (si101->sv101_type & SV_TYPE_DOMAIN_BAKCTRL)) {
  760. //
  761. // We are dealing with a DC
  762. //
  763. *DomainControllerFlag = TRUE;
  764. } else {
  765. *DomainControllerFlag = FALSE;
  766. }
  767. NetApiBufferFree (si101);
  768. return TRUE;
  769. }
  770. DWORD
  771. pConvertFlagsToRights (
  772. DWORD Flags
  773. )
  774. {
  775. while (Flags > 0x0f) {
  776. Flags >>= 4;
  777. }
  778. if (Flags & 0x01) {
  779. return 0;
  780. }
  781. if (Flags == 0x02) {
  782. return ACCESS_READ;
  783. }
  784. if (Flags == 0x04) {
  785. return ACCESS_WRITE;
  786. }
  787. if ((Flags & 0x06) == 0x06) {
  788. return ACCESS_READ|ACCESS_WRITE;
  789. }
  790. DEBUGMSG ((DBG_WHOOPS, "Undefined access flags specified: 0x%X", Flags));
  791. return 0;
  792. }
  793. DWORD
  794. SetRegKeySecurity (
  795. IN PCTSTR KeyStr,
  796. IN DWORD DaclFlags, OPTIONAL
  797. IN PSID Owner, OPTIONAL
  798. IN PSID PrimaryGroup, OPTIONAL
  799. IN BOOL Recursive
  800. )
  801. /*++
  802. Routine Description:
  803. SetRegKeySecurity updates the security of a registry key, or an entire
  804. registry node. The caller can change the DACL, owner or primary group.
  805. Change of the SACL is intentionally not implemented.
  806. Arguments:
  807. KeyStr - Specifies the key to modify the permissions. If Recursive
  808. is set to TRUE, this key will be updated along with all
  809. subkeys.
  810. DaclFlags - Specifies zero or more SF_* flags, indicating how access to
  811. the key should be set.
  812. Owner - Specifies the SID of the new owner.
  813. PrimaryGroup - Specifies the SID of the primary group.
  814. Recursive - Specifies TRUE to apply the security to the key and all of
  815. its subkeys, or FALSE to update the key only, leaving the
  816. subkeys alone.
  817. Return Value:
  818. A Win32 status code.
  819. --*/
  820. {
  821. DWORD rc = ERROR_SUCCESS;
  822. SECURITY_DESCRIPTOR sd;
  823. GROWBUFFER AclMemberList = GROWBUF_INIT;
  824. HKEY Key = NULL;
  825. REGSAM OldSam;
  826. DWORD AclMembers = 0;
  827. PACL Acl = NULL;
  828. SECURITY_INFORMATION WhatToSet = 0;
  829. REGTREE_ENUM e;
  830. LONG rc2;
  831. _try {
  832. //
  833. // Open key with full permission
  834. //
  835. OldSam = SetRegOpenAccessMode (KEY_ALL_ACCESS);
  836. Key = OpenRegKeyStr (KeyStr);
  837. if (!Key) {
  838. rc = GetLastError();
  839. __leave;
  840. }
  841. //
  842. // Prepare a security descriptor
  843. //
  844. InitializeSecurityDescriptor (&sd, SECURITY_DESCRIPTOR_REVISION);
  845. if (Owner) {
  846. if (!SetSecurityDescriptorOwner (&sd, Owner, FALSE)) {
  847. rc = GetLastError();
  848. __leave;
  849. }
  850. WhatToSet |= OWNER_SECURITY_INFORMATION;
  851. }
  852. if (PrimaryGroup) {
  853. if (!SetSecurityDescriptorGroup (&sd, PrimaryGroup, FALSE)) {
  854. rc = GetLastError();
  855. __leave;
  856. }
  857. WhatToSet |= GROUP_SECURITY_INFORMATION;
  858. }
  859. //
  860. // Add the DACL
  861. //
  862. if (DaclFlags & SF_EVERYONE_MASK) {
  863. AddAclMember (
  864. &AclMemberList,
  865. g_EveryoneStr,
  866. pConvertFlagsToRights (DaclFlags & SF_EVERYONE_MASK)
  867. );
  868. AclMembers++;
  869. }
  870. if (DaclFlags & SF_ADMINISTRATORS_MASK) {
  871. AddAclMember (
  872. &AclMemberList,
  873. g_AdministratorsGroupStr,
  874. pConvertFlagsToRights (DaclFlags & SF_ADMINISTRATORS_MASK)
  875. );
  876. AclMembers++;
  877. }
  878. if (AclMembers) {
  879. Acl = CreateAclFromMemberList (AclMemberList.Buf, AclMembers);
  880. if (!Acl) {
  881. rc = GetLastError();
  882. __leave;
  883. }
  884. WhatToSet |= DACL_SECURITY_INFORMATION;
  885. }
  886. //
  887. // Set the security
  888. //
  889. if (Recursive) {
  890. DEBUGMSG_IF ((
  891. rc != ERROR_SUCCESS,
  892. DBG_WARNING,
  893. "RegSetKeySecurity failed for %s with rc=%u",
  894. KeyStr,
  895. rc
  896. ));
  897. if (EnumFirstRegKeyInTree (&e, KeyStr)) {
  898. do {
  899. rc2 = RegSetKeySecurity (e.CurrentKey->KeyHandle, WhatToSet, &sd);
  900. if (rc2 != ERROR_SUCCESS) {
  901. rc = (DWORD) rc2;
  902. }
  903. DEBUGMSG_IF ((
  904. rc2 != ERROR_SUCCESS,
  905. DBG_WARNING,
  906. "RegSetKeySecurity failed for %s with rc=%u",
  907. e.FullKeyName,
  908. rc2
  909. ));
  910. } while (EnumNextRegKeyInTree (&e));
  911. }
  912. } else {
  913. rc = (DWORD) RegSetKeySecurity (Key, WhatToSet, &sd);
  914. }
  915. }
  916. __finally {
  917. FreeGrowBuffer (&AclMemberList);
  918. if (Key) {
  919. CloseRegKey (Key);
  920. }
  921. SetRegOpenAccessMode (OldSam);
  922. if (Acl) {
  923. FreeMemberListAcl (Acl);
  924. }
  925. }
  926. return rc;
  927. }