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.

426 lines
10 KiB

  1. ///////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright (c) 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. // The dns domain name.
  40. //////////
  41. const LSA_UNICODE_STRING* theDnsDomainName;
  42. //////////
  43. // Role of the local machine.
  44. //////////
  45. IAS_ROLE ourRole;
  46. //////////
  47. // Name of the guest account for the default domain.
  48. //////////
  49. WCHAR theGuestAccount[DNLEN + UNLEN + 2];
  50. //////////
  51. // Change event and notification thread.
  52. //////////
  53. HANDLE theChangeEvent, theNotificationThread;
  54. //////////
  55. // Flag to bring down the notification thread.
  56. //////////
  57. BOOL theShutdownFlag;
  58. CRITICAL_SECTION critSec;
  59. PPOLICY_DNS_DOMAIN_INFO ppdi;
  60. ///////////////////////////////////////////////////////////////////////////////
  61. //
  62. // FUNCTION
  63. //
  64. // IASQueryPrimaryDomain
  65. //
  66. // DESCRIPTION
  67. //
  68. // Reads the primary domain info and determines role of the local computer.
  69. //
  70. // NOTES
  71. //
  72. // This method is intentionally not synchronized. This method is
  73. // called *very* rarely and worst case a few packets will get
  74. // discarded because the new domain name hasn't been updated yet.
  75. //
  76. ///////////////////////////////////////////////////////////////////////////////
  77. DWORD
  78. WINAPI
  79. IASQueryPrimaryDomain( VOID )
  80. {
  81. NTSTATUS status;
  82. DWORD result;
  83. LSA_HANDLE hLsa;
  84. WCHAR accountName[DNLEN + UNLEN + 2], *userName;
  85. ULONG guestRid;
  86. SAM_HANDLE hGuest;
  87. PUSER_ACCOUNT_NAME_INFORMATION uani;
  88. PPOLICY_DNS_DOMAIN_INFO newDomainInfo;
  89. //////////
  90. // Open a handle to the LSA.
  91. //////////
  92. status = LsaOpenPolicy(
  93. NULL,
  94. &theObjectAttributes,
  95. POLICY_VIEW_LOCAL_INFORMATION,
  96. &hLsa
  97. );
  98. if (!NT_SUCCESS(status)) { goto exit; }
  99. EnterCriticalSection(&critSec);
  100. //////////
  101. // Get the primary domain information.
  102. //////////
  103. newDomainInfo = 0;
  104. status = LsaQueryInformationPolicy(
  105. hLsa,
  106. PolicyDnsDomainInformation,
  107. (PVOID*)&newDomainInfo
  108. );
  109. if (!NT_SUCCESS(status)) { goto close_lsa; }
  110. // We're done with the info buffer.
  111. if (ppdi != 0)
  112. {
  113. LsaFreeMemory(ppdi);
  114. }
  115. ppdi = newDomainInfo;
  116. //////////
  117. // Save the primary domain name and determine our role.
  118. //////////
  119. if (ppdi->Sid == NULL)
  120. {
  121. thePrimaryDomain[0] = L'\0';
  122. // No primary domain, so we must be standalone.
  123. ourRole = IAS_ROLE_STANDALONE;
  124. IASTraceString("Role: Standalone");
  125. }
  126. else
  127. {
  128. wcsncpy(thePrimaryDomain, ppdi->Name.Buffer, DNLEN);
  129. if (RtlEqualSid(ppdi->Sid, theAccountDomainSid))
  130. {
  131. // Account domain and primary domain are the same, so we must be DC.
  132. ourRole = IAS_ROLE_DC;
  133. IASTraceString("Role: Domain Controller");
  134. }
  135. else
  136. {
  137. ourRole = IAS_ROLE_MEMBER;
  138. IASTraceString("Role: Domain member");
  139. }
  140. }
  141. _wcsupr(thePrimaryDomain);
  142. IASTracePrintf("Primary domain: %S", thePrimaryDomain);
  143. theDnsDomainName = &(ppdi->DnsDomainName);
  144. if (theDnsDomainName->Buffer != NULL)
  145. {
  146. IASTracePrintf("Dns Domain name: %S", theDnsDomainName->Buffer);
  147. }
  148. //////////
  149. // Determine the default domain.
  150. //////////
  151. if (ourProductType == IAS_PRODUCT_WORKSTATION)
  152. {
  153. // For Workstation, the default domain is always the local domain.
  154. theDefaultDomain = theAccountDomain;
  155. }
  156. else if (ourRole == IAS_ROLE_STANDALONE)
  157. {
  158. // For Standalone there's nowhere to go besides local.
  159. theDefaultDomain = theAccountDomain;
  160. }
  161. else if (theRegistryDomain[0] != L'\0')
  162. {
  163. // For Server, a registry entry always takes precedence.
  164. theDefaultDomain = theRegistryDomain;
  165. }
  166. else
  167. {
  168. // Everyone else defaults to the primary domain.
  169. theDefaultDomain = thePrimaryDomain;
  170. }
  171. IASTracePrintf("Default domain: %S", theDefaultDomain);
  172. //////////
  173. // Now that we know the default domain we can determine the guest account.
  174. //////////
  175. wcscpy(accountName, theDefaultDomain);
  176. wcscat(accountName, L"\\");
  177. // If we can't read the guest account name, we'll assume it's "Guest".
  178. userName = accountName + wcslen(accountName);
  179. wcscpy(userName, L"Guest");
  180. guestRid = DOMAIN_USER_RID_GUEST;
  181. result = IASSamOpenUser(
  182. theDefaultDomain,
  183. NULL,
  184. USER_READ_GENERAL,
  185. 0,
  186. &guestRid,
  187. NULL,
  188. &hGuest
  189. );
  190. if (result != ERROR_SUCCESS)
  191. {
  192. // keep status with a succesfull value
  193. // we do not want to prevent IAS from starting because of this error
  194. goto set_guest_account;
  195. }
  196. status = SamQueryInformationUser(
  197. hGuest,
  198. UserAccountNameInformation,
  199. (PVOID*)&uani
  200. );
  201. if (!NT_SUCCESS(status)) { goto close_guest; }
  202. // Overwrite the default Guest name with the real one.
  203. wcsncpy(userName, uani->UserName.Buffer, UNLEN);
  204. SamFreeMemory(uani);
  205. close_guest:
  206. SamCloseHandle(hGuest);
  207. set_guest_account:
  208. // Copy the local buffer into the global buffer.
  209. wcscpy(theGuestAccount, accountName);
  210. IASTracePrintf("Guest account: %S", theGuestAccount);
  211. // Ignore any errors that occurred reading the guest account.
  212. status = NO_ERROR;
  213. close_lsa:
  214. LeaveCriticalSection(&critSec);
  215. LsaClose(hLsa);
  216. exit:
  217. return RtlNtStatusToDosError(status);
  218. }
  219. ///////////////////////////////////////////////////////////////////////////////
  220. //
  221. // FUNCTION
  222. //
  223. // NotificationProc
  224. //
  225. // DESCRIPTION
  226. //
  227. // Entry point for notification thread.
  228. //
  229. ///////////////////////////////////////////////////////////////////////////////
  230. DWORD
  231. WINAPI
  232. NotificationProc(PVOID lpArg)
  233. {
  234. DWORD status;
  235. while (1)
  236. {
  237. status = WaitForSingleObject(
  238. theChangeEvent,
  239. INFINITE
  240. );
  241. // If we had an error or the shutdown flag is set, then we'll exit.
  242. if ((status != WAIT_OBJECT_0) || theShutdownFlag) { break; }
  243. IASTraceString("Received domain name change notification.");
  244. // Otherwise, read the new domain info.
  245. IASQueryPrimaryDomain();
  246. }
  247. return 0;
  248. }
  249. ///////////////////////////////////////////////////////////////////////////////
  250. //
  251. // FUNCTION
  252. //
  253. // IASDynamicInfoInitialize
  254. //
  255. // DESCRIPTION
  256. //
  257. // Initializes the dynamic data defined above and creates a thread to
  258. // wait for change notifications.
  259. //
  260. ///////////////////////////////////////////////////////////////////////////////
  261. DWORD
  262. WINAPI
  263. IASDynamicInfoInitialize( VOID )
  264. {
  265. DWORD status, threadID;
  266. if (!InitializeCriticalSectionAndSpinCount(&critSec, 0x00001000))
  267. {
  268. return GetLastError();
  269. }
  270. do
  271. {
  272. //////////
  273. // Read the initial state of the info.
  274. //////////
  275. status = IASQueryPrimaryDomain();
  276. if (status != NO_ERROR)
  277. {
  278. break;
  279. }
  280. //////////
  281. // Set up the thread that handles dynamic changes.
  282. //////////
  283. // Get a notification event.
  284. status = NetRegisterDomainNameChangeNotification(&theChangeEvent);
  285. if (status != NERR_Success)
  286. {
  287. break;
  288. }
  289. // Reset the shutdown flag.
  290. theShutdownFlag = FALSE;
  291. // Create a thread to wait on the event.
  292. theNotificationThread = CreateThread(
  293. NULL,
  294. 0,
  295. NotificationProc,
  296. NULL,
  297. 0,
  298. &threadID
  299. );
  300. if (!theNotificationThread)
  301. {
  302. NetUnregisterDomainNameChangeNotification(theChangeEvent);
  303. theChangeEvent = NULL;
  304. status = GetLastError();
  305. break;
  306. }
  307. status = NO_ERROR;
  308. }
  309. while(FALSE);
  310. if (status != NO_ERROR)
  311. {
  312. DeleteCriticalSection(&critSec);
  313. if (ppdi != 0)
  314. {
  315. LsaFreeMemory(ppdi);
  316. ppdi = 0;
  317. }
  318. }
  319. return status;
  320. }
  321. ///////////////////////////////////////////////////////////////////////////////
  322. //
  323. // FUNCTION
  324. //
  325. // IASDynamicInfoShutdown
  326. //
  327. // DESCRIPTION
  328. //
  329. // Shuts down the notifation thread.
  330. //
  331. ///////////////////////////////////////////////////////////////////////////////
  332. VOID
  333. WINAPI
  334. IASDynamicInfoShutdown( VOID )
  335. {
  336. // Set the shutdown flag.
  337. theShutdownFlag = TRUE;
  338. // Bring down the thread.
  339. SetEvent(theChangeEvent);
  340. WaitForSingleObject(
  341. theNotificationThread,
  342. INFINITE
  343. );
  344. // Unregister the notification.
  345. NetUnregisterDomainNameChangeNotification(theChangeEvent);
  346. theChangeEvent = NULL;
  347. // Close the thread handle.
  348. CloseHandle(theNotificationThread);
  349. theNotificationThread = NULL;
  350. // Critical section not useful anymore
  351. DeleteCriticalSection(&critSec);
  352. // We're done with the info buffer.
  353. if (ppdi != 0)
  354. {
  355. LsaFreeMemory(ppdi);
  356. ppdi = 0;
  357. }
  358. theDnsDomainName = 0;
  359. }