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.

363 lines
8.4 KiB

  1. ///////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright (c) 1998, Microsoft Corp. All rights reserved.
  4. //
  5. // FILE
  6. //
  7. // dyninfo.c
  8. //
  9. // SYNOPSIS
  10. //
  11. // Defines and initializes global variables containing dynamic configuration
  12. // information.
  13. //
  14. // MODIFICATION HISTORY
  15. //
  16. // 08/15/1998 Original version.
  17. // 03/23/1999 Changes to ezsam API.
  18. //
  19. ///////////////////////////////////////////////////////////////////////////////
  20. #include <nt.h>
  21. #include <ntrtl.h>
  22. #include <nturtl.h>
  23. #include <ntlsa.h>
  24. #include <windows.h>
  25. #include <lm.h>
  26. #include <statinfo.h>
  27. #include <ezsam.h>
  28. #include <dyninfo.h>
  29. #include <iastrace.h>
  30. //////////
  31. // The primary domain.
  32. //////////
  33. WCHAR thePrimaryDomain[DNLEN + 1];
  34. //////////
  35. // The default domain.
  36. //////////
  37. PCWSTR theDefaultDomain;
  38. //////////
  39. // Role of the local machine.
  40. //////////
  41. IAS_ROLE ourRole;
  42. //////////
  43. // Name of the guest account for the default domain.
  44. //////////
  45. WCHAR theGuestAccount[DNLEN + UNLEN + 2];
  46. //////////
  47. // Change event and notification thread.
  48. //////////
  49. HANDLE theChangeEvent, theNotificationThread;
  50. //////////
  51. // Flag to bring down the notification thread.
  52. //////////
  53. BOOL theShutdownFlag;
  54. ///////////////////////////////////////////////////////////////////////////////
  55. //
  56. // FUNCTION
  57. //
  58. // IASQueryPrimaryDomain
  59. //
  60. // DESCRIPTION
  61. //
  62. // Reads the primary domain info and determines role of the local computer.
  63. //
  64. // NOTES
  65. //
  66. // This method is intentionally not synchronized. This method is
  67. // called *very* rarely and worst case a few packets will get
  68. // discarded because the new domain name hasn't been updated yet.
  69. //
  70. ///////////////////////////////////////////////////////////////////////////////
  71. DWORD
  72. WINAPI
  73. IASQueryPrimaryDomain( VOID )
  74. {
  75. NTSTATUS status;
  76. DWORD result;
  77. LSA_HANDLE hLsa;
  78. PPOLICY_PRIMARY_DOMAIN_INFO ppdi;
  79. WCHAR accountName[DNLEN + UNLEN + 2], *userName;
  80. ULONG guestRid;
  81. SAM_HANDLE hGuest;
  82. PUSER_ACCOUNT_NAME_INFORMATION uani;
  83. //////////
  84. // Open a handle to the LSA.
  85. //////////
  86. status = LsaOpenPolicy(
  87. NULL,
  88. &theObjectAttributes,
  89. POLICY_VIEW_LOCAL_INFORMATION,
  90. &hLsa
  91. );
  92. if (!NT_SUCCESS(status)) { goto exit; }
  93. //////////
  94. // Get the primary domain information.
  95. //////////
  96. status = LsaQueryInformationPolicy(
  97. hLsa,
  98. PolicyPrimaryDomainInformation,
  99. (PVOID*)&ppdi
  100. );
  101. if (!NT_SUCCESS(status)) { goto close_lsa; }
  102. //////////
  103. // Save the primary domain name and determine our role.
  104. //////////
  105. if (ppdi->Sid == NULL)
  106. {
  107. thePrimaryDomain[0] = L'\0';
  108. // No primary domain, so we must be standalone.
  109. ourRole = IAS_ROLE_STANDALONE;
  110. IASTraceString("Role: Standalone");
  111. }
  112. else
  113. {
  114. wcsncpy(thePrimaryDomain, ppdi->Name.Buffer, DNLEN);
  115. if (RtlEqualSid(ppdi->Sid, theAccountDomainSid))
  116. {
  117. // Account domain and primary domain are the same, so we must be DC.
  118. ourRole = IAS_ROLE_DC;
  119. IASTraceString("Role: Domain Controller");
  120. }
  121. else
  122. {
  123. ourRole = IAS_ROLE_MEMBER;
  124. IASTraceString("Role: Domain member");
  125. }
  126. }
  127. _wcsupr(thePrimaryDomain);
  128. IASTracePrintf("Primary domain: %S", thePrimaryDomain);
  129. // We're done with the info buffer.
  130. LsaFreeMemory(ppdi);
  131. //////////
  132. // Determine the default domain.
  133. //////////
  134. if (ourProductType == IAS_PRODUCT_WORKSTATION)
  135. {
  136. // For Workstation, the default domain is always the local domain.
  137. theDefaultDomain = theAccountDomain;
  138. }
  139. else if (ourRole == IAS_ROLE_STANDALONE)
  140. {
  141. // For Standalone there's nowhere to go besides local.
  142. theDefaultDomain = theAccountDomain;
  143. }
  144. else if (theRegistryDomain[0] != L'\0')
  145. {
  146. // For Server, a registry entry always takes precedence.
  147. theDefaultDomain = theRegistryDomain;
  148. }
  149. else
  150. {
  151. // Everyone else defaults to the primary domain.
  152. theDefaultDomain = thePrimaryDomain;
  153. }
  154. IASTracePrintf("Default domain: %S", theDefaultDomain);
  155. //////////
  156. // Now that we know the default domain we can determine the guest account.
  157. //////////
  158. wcscpy(accountName, theDefaultDomain);
  159. wcscat(accountName, L"\\");
  160. // If we can't read the guest account name, we'll assume it's "Guest".
  161. userName = accountName + wcslen(accountName);
  162. wcscpy(userName, L"Guest");
  163. guestRid = DOMAIN_USER_RID_GUEST;
  164. result = IASSamOpenUser(
  165. theDefaultDomain,
  166. NULL,
  167. USER_READ_GENERAL,
  168. 0,
  169. &guestRid,
  170. NULL,
  171. &hGuest
  172. );
  173. if (result != ERROR_SUCCESS)
  174. {
  175. // keep status with a succesfull value
  176. // we do not want to prevent IAS from starting because of this error
  177. goto set_guest_account;
  178. }
  179. status = SamQueryInformationUser(
  180. hGuest,
  181. UserAccountNameInformation,
  182. (PVOID*)&uani
  183. );
  184. if (!NT_SUCCESS(status)) { goto close_guest; }
  185. // Overwrite the default Guest name with the real one.
  186. wcsncpy(userName, uani->UserName.Buffer, UNLEN);
  187. SamFreeMemory(uani);
  188. close_guest:
  189. SamCloseHandle(hGuest);
  190. set_guest_account:
  191. // Copy the local buffer into the global buffer.
  192. wcscpy(theGuestAccount, accountName);
  193. IASTracePrintf("Guest account: %S", theGuestAccount);
  194. // Ignore any errors that occurred reading the guest account.
  195. status = NO_ERROR;
  196. close_lsa:
  197. LsaClose(hLsa);
  198. exit:
  199. return RtlNtStatusToDosError(status);
  200. }
  201. ///////////////////////////////////////////////////////////////////////////////
  202. //
  203. // FUNCTION
  204. //
  205. // NotificationProc
  206. //
  207. // DESCRIPTION
  208. //
  209. // Entry point for notification thread.
  210. //
  211. ///////////////////////////////////////////////////////////////////////////////
  212. DWORD
  213. WINAPI
  214. NotificationProc(PVOID lpArg)
  215. {
  216. DWORD status;
  217. while (1)
  218. {
  219. status = WaitForSingleObject(
  220. theChangeEvent,
  221. INFINITE
  222. );
  223. // If we had an error or the shutdown flag is set, then we'll exit.
  224. if ((status != WAIT_OBJECT_0) || theShutdownFlag) { break; }
  225. IASTraceString("Received domain name change notification.");
  226. // Otherwise, read the new domain info.
  227. IASQueryPrimaryDomain();
  228. }
  229. return 0;
  230. }
  231. ///////////////////////////////////////////////////////////////////////////////
  232. //
  233. // FUNCTION
  234. //
  235. // IASDynamicInfoInitialize
  236. //
  237. // DESCRIPTION
  238. //
  239. // Initializes the dynamic data defined above and creates a thread to
  240. // wait for change notifications.
  241. //
  242. ///////////////////////////////////////////////////////////////////////////////
  243. DWORD
  244. WINAPI
  245. IASDynamicInfoInitialize( VOID )
  246. {
  247. DWORD status, threadID;
  248. //////////
  249. // Read the initial state of the info.
  250. //////////
  251. status = IASQueryPrimaryDomain();
  252. if (status != NO_ERROR) { return status; }
  253. //////////
  254. // Set up the thread that handles dynamic changes.
  255. //////////
  256. // Get a notification event.
  257. status = NetRegisterDomainNameChangeNotification(&theChangeEvent);
  258. if (status != NERR_Success) { return status; }
  259. // Reset the shutdown flag.
  260. theShutdownFlag = FALSE;
  261. // Create a thread to wait on the event.
  262. theNotificationThread = CreateThread(
  263. NULL,
  264. 0,
  265. NotificationProc,
  266. NULL,
  267. 0,
  268. &threadID
  269. );
  270. if (!theNotificationThread)
  271. {
  272. NetUnregisterDomainNameChangeNotification(theChangeEvent);
  273. theChangeEvent = NULL;
  274. return GetLastError();
  275. }
  276. return NO_ERROR;
  277. }
  278. ///////////////////////////////////////////////////////////////////////////////
  279. //
  280. // FUNCTION
  281. //
  282. // IASDynamicInfoShutdown
  283. //
  284. // DESCRIPTION
  285. //
  286. // Shuts down the notifation thread.
  287. //
  288. ///////////////////////////////////////////////////////////////////////////////
  289. VOID
  290. WINAPI
  291. IASDynamicInfoShutdown( VOID )
  292. {
  293. // Set the shutdown flag.
  294. theShutdownFlag = TRUE;
  295. // Bring down the thread.
  296. SetEvent(theChangeEvent);
  297. WaitForSingleObject(
  298. theNotificationThread,
  299. INFINITE
  300. );
  301. // Unregister the notification.
  302. NetUnregisterDomainNameChangeNotification(theChangeEvent);
  303. theChangeEvent = NULL;
  304. // Close the thread handle.
  305. CloseHandle(theNotificationThread);
  306. theNotificationThread = NULL;
  307. }