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.

406 lines
9.6 KiB

  1. ///////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright (c) 1998, Microsoft Corp. All rights reserved.
  4. //
  5. // FILE
  6. //
  7. // ezlogon.c
  8. //
  9. // SYNOPSIS
  10. //
  11. // Defines the IAS wrapper around LsaLogonUser
  12. //
  13. // MODIFICATION HISTORY
  14. //
  15. // 08/15/1998 Original version.
  16. // 09/09/1998 Fix AV when logon domain doesn't match user domain.
  17. // 10/02/1998 NULL out handle when LsaLogonUser fails.
  18. // 10/11/1998 Use SubStatus for STATUS_ACCOUNT_RESTRICTION.
  19. // 10/22/1998 PIAS_LOGON_HOURS is now a mandatory parameter.
  20. // 01/28/1999 Remove LogonDomainName check.
  21. // 04/19/1999 Add IASPurgeTicketCache.
  22. //
  23. ///////////////////////////////////////////////////////////////////////////////
  24. #include <nt.h>
  25. #include <ntrtl.h>
  26. #include <nturtl.h>
  27. #include <ntlsa.h>
  28. #include <kerberos.h>
  29. #include <windows.h>
  30. #include <ezlogon.h>
  31. #include <iaslsa.h>
  32. #include <iastrace.h>
  33. CONST CHAR LOGON_PROCESS_NAME[] = "IAS";
  34. CONST CHAR TOKEN_SOURCE_NAME[TOKEN_SOURCE_LENGTH] = "IAS";
  35. // Number of milliseconds in a week.
  36. #define MSEC_PER_WEEK (1000 * 60 * 60 * 24 * 7)
  37. //////////
  38. // Misc. global variables used for logons.
  39. //////////
  40. LSA_HANDLE theLogonProcess; // The handle for the logon process.
  41. ULONG theMSV1_0_Package; // The MSV1_0 authentication package.
  42. ULONG theKerberosPackage; // The Kerberos authentication package.
  43. STRING theOriginName; // The origin of the logon requests.
  44. TOKEN_SOURCE theSourceContext; // The source context of the logon requests.
  45. /////////////////////////////////////////////////////////////////////////////// //
  46. // FUNCTION
  47. //
  48. // IASLogonInitialize
  49. //
  50. // DESCRIPTION
  51. //
  52. // Registers the logon process.
  53. //
  54. ///////////////////////////////////////////////////////////////////////////////
  55. DWORD
  56. WINAPI
  57. IASLogonInitialize( VOID )
  58. {
  59. DWORD status;
  60. BOOLEAN wasEnabled;
  61. LSA_STRING processName, packageName;
  62. LSA_OPERATIONAL_MODE opMode;
  63. //////////
  64. // Enable SE_TCB_PRIVILEGE.
  65. //////////
  66. status = RtlAdjustPrivilege(
  67. SE_TCB_PRIVILEGE,
  68. TRUE,
  69. FALSE,
  70. &wasEnabled
  71. );
  72. if (!NT_SUCCESS(status)) { goto exit; }
  73. //////////
  74. // Register as a logon process.
  75. //////////
  76. RtlInitString(
  77. &processName,
  78. LOGON_PROCESS_NAME
  79. );
  80. status = LsaRegisterLogonProcess(
  81. &processName,
  82. &theLogonProcess,
  83. &opMode
  84. );
  85. if (!NT_SUCCESS(status)) { goto exit; }
  86. //////////
  87. // Lookup the MSV1_0 authentication package.
  88. //////////
  89. RtlInitString(
  90. &packageName,
  91. MSV1_0_PACKAGE_NAME
  92. );
  93. status = LsaLookupAuthenticationPackage(
  94. theLogonProcess,
  95. &packageName,
  96. &theMSV1_0_Package
  97. );
  98. if (!NT_SUCCESS(status)) { goto deregister; }
  99. //////////
  100. // Lookup the Kerberos authentication package.
  101. //////////
  102. RtlInitString(
  103. &packageName,
  104. MICROSOFT_KERBEROS_NAME_A
  105. );
  106. status = LsaLookupAuthenticationPackage(
  107. theLogonProcess,
  108. &packageName,
  109. &theKerberosPackage
  110. );
  111. if (!NT_SUCCESS(status)) { goto deregister; }
  112. //////////
  113. // Initialize the source context.
  114. //////////
  115. memcpy(theSourceContext.SourceName,
  116. TOKEN_SOURCE_NAME,
  117. TOKEN_SOURCE_LENGTH);
  118. status = NtAllocateLocallyUniqueId(
  119. &theSourceContext.SourceIdentifier
  120. );
  121. if (!NT_SUCCESS(status)) { goto deregister; }
  122. return NO_ERROR;
  123. deregister:
  124. LsaDeregisterLogonProcess(theLogonProcess);
  125. theLogonProcess = NULL;
  126. exit:
  127. return RtlNtStatusToDosError(status);
  128. }
  129. /////////////////////////////////////////////////////////////////////////////// //
  130. // FUNCTION
  131. //
  132. // IASLogonShutdown
  133. //
  134. // DESCRIPTION
  135. //
  136. // Deregisters the logon process.
  137. //
  138. ///////////////////////////////////////////////////////////////////////////////
  139. VOID
  140. WINAPI
  141. IASLogonShutdown( VOID )
  142. {
  143. LsaDeregisterLogonProcess(theLogonProcess);
  144. theLogonProcess = NULL;
  145. }
  146. /////////////////////////////////////////////////////////////////////////////// //
  147. // FUNCTION
  148. //
  149. // IASInitAuthInfo
  150. //
  151. // DESCRIPTION
  152. //
  153. // Initializes the fields common to all MSV1_0_LM20* structs.
  154. //
  155. ///////////////////////////////////////////////////////////////////////////////
  156. VOID
  157. WINAPI
  158. IASInitAuthInfo(
  159. IN PVOID AuthInfo,
  160. IN DWORD FixedLength,
  161. IN PCWSTR UserName,
  162. IN PCWSTR Domain,
  163. OUT PBYTE* Data
  164. )
  165. {
  166. PMSV1_0_LM20_LOGON logon;
  167. // Zero out the fixed data.
  168. memset(AuthInfo, 0, FixedLength);
  169. // Set Data to point just past the fixed struct.
  170. *Data = FixedLength + (PBYTE)AuthInfo;
  171. // This cast is safe since all LM20 structs have the same initial fields.
  172. logon = (PMSV1_0_LM20_LOGON)AuthInfo;
  173. // We always do Network logons.
  174. logon->MessageType = MsV1_0NetworkLogon;
  175. // Copy in the strings common to all logons.
  176. IASInitUnicodeString(logon->LogonDomainName, *Data, Domain);
  177. IASInitUnicodeString(logon->UserName, *Data, UserName);
  178. IASInitUnicodeString(logon->Workstation, *Data, L"");
  179. }
  180. /////////////////////////////////////////////////////////////////////////////// //
  181. // FUNCTION
  182. //
  183. // IASLogonUser
  184. //
  185. // DESCRIPTION
  186. //
  187. // Wrapper around LsaLogonUser.
  188. //
  189. ///////////////////////////////////////////////////////////////////////////////
  190. DWORD
  191. WINAPI
  192. IASLogonUser(
  193. IN PVOID AuthInfo,
  194. IN ULONG AuthInfoLength,
  195. OUT PMSV1_0_LM20_LOGON_PROFILE *Profile,
  196. OUT PHANDLE Token
  197. )
  198. {
  199. NTSTATUS status, SubStatus;
  200. PMSV1_0_LM20_LOGON_PROFILE ProfileBuffer;
  201. ULONG ProfileBufferLength;
  202. LUID LogonId;
  203. QUOTA_LIMITS Quotas;
  204. // Make sure the OUT arguments are NULL.
  205. *Token = NULL;
  206. ProfileBuffer = NULL;
  207. status = LsaLogonUser(
  208. theLogonProcess,
  209. &theOriginName,
  210. Network,
  211. theMSV1_0_Package,
  212. AuthInfo,
  213. AuthInfoLength,
  214. NULL,
  215. &theSourceContext,
  216. &ProfileBuffer,
  217. &ProfileBufferLength,
  218. &LogonId,
  219. Token,
  220. &Quotas,
  221. &SubStatus
  222. );
  223. if (!NT_SUCCESS(status))
  224. {
  225. // For account restrictions, we can get a more descriptive error
  226. // from the SubStatus.
  227. if (status == STATUS_ACCOUNT_RESTRICTION && !NT_SUCCESS(SubStatus))
  228. {
  229. status = SubStatus;
  230. }
  231. // Sometimes LsaLogonUser returns an invalid handle value on failure.
  232. *Token = NULL;
  233. }
  234. if (Profile)
  235. {
  236. // Return the profile if requested ...
  237. *Profile = ProfileBuffer;
  238. }
  239. else if (ProfileBuffer)
  240. {
  241. // ... otherwise free it.
  242. LsaFreeReturnBuffer(ProfileBuffer);
  243. }
  244. return RtlNtStatusToDosError(status);
  245. }
  246. /////////////////////////////////////////////////////////////////////////////// //
  247. // FUNCTION
  248. //
  249. // IASCheckAccountRestrictions
  250. //
  251. // DESCRIPTION
  252. //
  253. // Checks whether an account can be used for logon.
  254. //
  255. ///////////////////////////////////////////////////////////////////////////////
  256. DWORD
  257. WINAPI
  258. IASCheckAccountRestrictions(
  259. IN PLARGE_INTEGER AccountExpires,
  260. IN PIAS_LOGON_HOURS LogonHours
  261. )
  262. {
  263. LARGE_INTEGER now;
  264. TIME_ZONE_INFORMATION tzi;
  265. SYSTEMTIME st;
  266. DWORD unit;
  267. GetSystemTimeAsFileTime(
  268. (LPFILETIME)&now
  269. );
  270. // An expiration time of zero means 'never'.
  271. if (AccountExpires->QuadPart != 0 &&
  272. AccountExpires->QuadPart < now.QuadPart)
  273. {
  274. return ERROR_ACCOUNT_EXPIRED;
  275. }
  276. // If LogonHours is empty, then we're done.
  277. if (LogonHours->UnitsPerWeek == 0)
  278. {
  279. return NO_ERROR;
  280. }
  281. // The LogonHours array does not account for bias.
  282. switch (GetTimeZoneInformation(&tzi))
  283. {
  284. case TIME_ZONE_ID_UNKNOWN:
  285. case TIME_ZONE_ID_STANDARD:
  286. // Bias is in minutes.
  287. now.QuadPart -= 60 * 10000000 * (LONGLONG)tzi.StandardBias;
  288. break;
  289. case TIME_ZONE_ID_DAYLIGHT:
  290. // Bias is in minutes.
  291. now.QuadPart -= 60 * 10000000 * (LONGLONG)tzi.DaylightBias;
  292. break;
  293. default:
  294. return ERROR_INVALID_LOGON_HOURS;
  295. }
  296. FileTimeToSystemTime(
  297. (LPFILETIME)&now,
  298. &st
  299. );
  300. // Number of milliseconds into the week.
  301. unit = st.wMilliseconds +
  302. st.wSecond * 1000 +
  303. st.wMinute * 1000 * 60 +
  304. st.wHour * 1000 * 60 * 60 +
  305. st.wDayOfWeek * 1000 * 60 * 60 * 24;
  306. // Convert this to 'units'.
  307. unit /= (MSEC_PER_WEEK / (DWORD)LogonHours->UnitsPerWeek);
  308. // Test the appropriate bit.
  309. if ((LogonHours->LogonHours[unit / 8 ] & (1 << (unit % 8))) == 0)
  310. {
  311. return ERROR_INVALID_LOGON_HOURS;
  312. }
  313. return NO_ERROR;
  314. }
  315. /////////////////////////////////////////////////////////////////////////////// //
  316. // FUNCTION
  317. //
  318. // IASPurgeTicketCache
  319. //
  320. // DESCRIPTION
  321. //
  322. // Purges the Kerberos ticket cache.
  323. //
  324. ///////////////////////////////////////////////////////////////////////////////
  325. DWORD
  326. WINAPI
  327. IASPurgeTicketCache( VOID )
  328. {
  329. KERB_PURGE_TKT_CACHE_REQUEST request;
  330. NTSTATUS status, subStatus;
  331. PVOID response;
  332. ULONG responseLength;
  333. memset(&request, 0, sizeof(request));
  334. request.MessageType = KerbPurgeTicketCacheMessage;
  335. response = NULL;
  336. responseLength = 0;
  337. subStatus = 0;
  338. status = LsaCallAuthenticationPackage(
  339. theLogonProcess,
  340. theKerberosPackage,
  341. &request,
  342. sizeof(request),
  343. &response,
  344. &responseLength,
  345. &subStatus
  346. );
  347. if (NT_SUCCESS(status))
  348. {
  349. LsaFreeReturnBuffer(response);
  350. }
  351. return RtlNtStatusToDosError(status);
  352. }