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.

886 lines
26 KiB

  1. /*++
  2. Copyright (c) 2001 Microsoft Corporation
  3. Module Name:
  4. subauth.cxx
  5. Abstract:
  6. subauth
  7. Author:
  8. Larry Zhu (LZhu) December 1, 2001 Created
  9. Environment:
  10. User Mode
  11. Revision History:
  12. --*/
  13. #include "precomp.hxx"
  14. #pragma hdrstop
  15. #include <lmcons.h>
  16. #include <logonmsv.h>
  17. #include <lmaccess.h>
  18. #include <lmapibuf.h>
  19. #include "subauth.hxx"
  20. NTSTATUS
  21. NTAPI
  22. Msv1_0SubAuthenticationRoutineEx(
  23. IN NETLOGON_LOGON_INFO_CLASS LogonLevel,
  24. IN PVOID pLogonInformation,
  25. IN ULONG Flags,
  26. IN PUSER_ALL_INFORMATION pUserAll,
  27. IN SAM_HANDLE UserHandle,
  28. IN OUT PMSV1_0_VALIDATION_INFO pValidationInfo,
  29. OUT PULONG pActionsPerformed
  30. )
  31. {
  32. TNtStatus Status;
  33. DebugPrintf(SSPI_LOG, "Msv1_0SubAuthenticationRoutine in msvsubauth.dll: LogonLevel %#x, validating UserName %wZ, UserId %#x(%d)\n",
  34. LogonLevel, &pUserAll->UserName, pUserAll->UserId, pUserAll->UserId);
  35. Status DBGCHK = Msv1_0SubAuthenticationRoutine(
  36. LogonLevel,
  37. pLogonInformation,
  38. Flags,
  39. pUserAll,
  40. &pValidationInfo->WhichFields,
  41. &pValidationInfo->UserFlags,
  42. &pValidationInfo->Authoritative,
  43. &pValidationInfo->LogoffTime,
  44. &pValidationInfo->KickoffTime
  45. );
  46. if (NT_SUCCESS(Status))
  47. {
  48. pValidationInfo->UserId = pUserAll->UserId;
  49. *pActionsPerformed = MSV1_0_SUBAUTH_PASSWORD;
  50. }
  51. return Status;
  52. }
  53. NTSTATUS
  54. NTAPI
  55. Msv1_0SubAuthenticationRoutine(
  56. IN NETLOGON_LOGON_INFO_CLASS LogonLevel,
  57. IN PVOID pLogonInformation,
  58. IN ULONG Flags,
  59. IN PUSER_ALL_INFORMATION pUserAll,
  60. OUT PULONG pWhichFields,
  61. OUT PULONG pUserFlags,
  62. OUT PBOOLEAN Authoritative,
  63. OUT PLARGE_INTEGER pLogoffTime,
  64. OUT PLARGE_INTEGER pKickoffTime
  65. )
  66. {
  67. TNtStatus Status = STATUS_SUCCESS;
  68. ULONG UserAccountControl;
  69. LARGE_INTEGER LogonTime;
  70. LARGE_INTEGER PasswordDateSet;
  71. UNICODE_STRING LocalWorkstation;
  72. PNETLOGON_NETWORK_INFO LogonNetworkInfo;
  73. DebugPrintf(SSPI_LOG, "Msv1_0SubAuthenticationRoutine in msvsubauth.dll: LogonLevel %#x, validating UserName %wZ, UserId %#x(%d)\n",
  74. LogonLevel, &pUserAll->UserName, pUserAll->UserId, pUserAll->UserId);
  75. //
  76. // Check whether the SubAuthentication package supports this type
  77. // of logon.
  78. //
  79. *Authoritative = TRUE;
  80. *pUserFlags = 0;
  81. *pWhichFields = 0;
  82. (VOID) NtQuerySystemTime(&LogonTime);
  83. switch (LogonLevel)
  84. {
  85. case NetlogonInteractiveInformation:
  86. case NetlogonServiceInformation:
  87. //
  88. // This SubAuthentication package only supports network logons.
  89. //
  90. Status DBGCHK = STATUS_INVALID_INFO_CLASS;
  91. break;
  92. case NetlogonNetworkInformation:
  93. //
  94. // This SubAuthentication package doesn't support access via machine
  95. // accounts.
  96. //
  97. UserAccountControl = USER_NORMAL_ACCOUNT;
  98. //
  99. // Local user (Temp Duplicate) accounts are only used on the machine
  100. // being directly logged onto.
  101. // (Nor are interactive or service logons allowed to them.)
  102. //
  103. if ((Flags & MSV1_0_PASSTHRU) == 0)
  104. {
  105. UserAccountControl |= USER_TEMP_DUPLICATE_ACCOUNT;
  106. }
  107. LogonNetworkInfo = (PNETLOGON_NETWORK_INFO) pLogonInformation;
  108. break;
  109. default:
  110. *Authoritative = TRUE;
  111. Status DBGCHK = STATUS_INVALID_INFO_CLASS;
  112. }
  113. //
  114. // If the account type isn't allowed,
  115. // Treat this as though the User Account doesn't exist.
  116. //
  117. if (NT_SUCCESS(Status) && (UserAccountControl & pUserAll->UserAccountControl) == 0)
  118. {
  119. *Authoritative = FALSE;
  120. Status DBGCHK = STATUS_NO_SUCH_USER;
  121. }
  122. //
  123. // This SubAuthentication package doesn't allow guest logons.
  124. //
  125. if (NT_SUCCESS(Status) && (Flags & MSV1_0_GUEST_LOGON))
  126. {
  127. *Authoritative = FALSE;
  128. Status DBGCHK = STATUS_NO_SUCH_USER;
  129. }
  130. //
  131. // Ensure the account isn't locked out.
  132. //
  133. if (NT_SUCCESS(Status) && (pUserAll->UserId != DOMAIN_USER_RID_ADMIN &&
  134. (pUserAll->UserAccountControl & USER_ACCOUNT_AUTO_LOCKED)))
  135. {
  136. //
  137. // Since the UI strongly encourages admins to disable user
  138. // accounts rather than delete them. Treat disabled acccount as
  139. // non-authoritative allowing the search to continue for other
  140. // accounts by the same name.
  141. //
  142. if (pUserAll->UserAccountControl & USER_ACCOUNT_DISABLED)
  143. {
  144. *Authoritative = FALSE;
  145. }
  146. else
  147. {
  148. *Authoritative = TRUE;
  149. }
  150. Status DBGCHK = STATUS_ACCOUNT_LOCKED_OUT;
  151. }
  152. //
  153. // Check the password.
  154. //
  155. if (NT_SUCCESS(Status) && FALSE /* VALIDATE THE USER'S PASSWORD HERE */)
  156. {
  157. Status DBGCHK = STATUS_WRONG_PASSWORD;
  158. //
  159. // Since the UI strongly encourages admins to disable user
  160. // accounts rather than delete them. Treat disabled acccount as
  161. // non-authoritative allowing the search to continue for other
  162. // accounts by the same name.
  163. //
  164. if (pUserAll->UserAccountControl & USER_ACCOUNT_DISABLED)
  165. {
  166. *Authoritative = FALSE;
  167. }
  168. else
  169. {
  170. *Authoritative = TRUE;
  171. }
  172. }
  173. //
  174. // Prevent some things from effecting the Administrator user
  175. //
  176. if (NT_SUCCESS(Status))
  177. {
  178. if (pUserAll->UserId == DOMAIN_USER_RID_ADMIN)
  179. {
  180. //
  181. // The administrator account doesn't have a forced logoff time.
  182. //
  183. pLogoffTime->HighPart = 0x7FFFFFFF;
  184. pLogoffTime->LowPart = 0xFFFFFFFF;
  185. pKickoffTime->HighPart = 0x7FFFFFFF;
  186. pKickoffTime->LowPart = 0xFFFFFFFF;
  187. }
  188. else
  189. {
  190. //
  191. // Check if the account is disabled.
  192. //
  193. if (pUserAll->UserAccountControl & USER_ACCOUNT_DISABLED)
  194. {
  195. //
  196. // Since the UI strongly encourages admins to disable user
  197. // accounts rather than delete them. Treat disabled acccount as
  198. // non-authoritative allowing the search to continue for other
  199. // accounts by the same name.
  200. //
  201. *Authoritative = FALSE;
  202. Status DBGCHK = STATUS_ACCOUNT_DISABLED;
  203. }
  204. //
  205. // Check if the account has expired.
  206. //
  207. if (NT_SUCCESS(Status) && (pUserAll->AccountExpires.QuadPart != 0) &&
  208. (LogonTime.QuadPart >= pUserAll->AccountExpires.QuadPart))
  209. {
  210. *Authoritative = TRUE;
  211. Status DBGCHK = STATUS_ACCOUNT_EXPIRED;
  212. }
  213. //
  214. // The password is valid, check to see if the password is expired.
  215. // (SAM will have appropriately set PasswordMustChange to reflect
  216. // USER_DONT_EXPIRE_PASSWORD)
  217. //
  218. // If the password checked above is not the SAM password, you may
  219. // want to consider not checking the SAM password expiration times here.
  220. //
  221. if (NT_SUCCESS(Status) && (LogonTime.QuadPart >= pUserAll->PasswordMustChange.QuadPart))
  222. {
  223. if (pUserAll->PasswordLastSet.QuadPart == 0)
  224. {
  225. Status DBGCHK = STATUS_PASSWORD_MUST_CHANGE;
  226. }
  227. else
  228. {
  229. Status DBGCHK = STATUS_PASSWORD_EXPIRED;
  230. }
  231. *Authoritative = TRUE;
  232. }
  233. //
  234. // Validate the workstation the user logged on from.
  235. //
  236. // Ditch leading \\ on workstation name before passing it to SAM.
  237. //
  238. if (NT_SUCCESS(Status))
  239. {
  240. LocalWorkstation = LogonNetworkInfo->Identity.Workstation;
  241. if (LocalWorkstation.Length > 0 &&
  242. LocalWorkstation.Buffer[0] == L'\\' &&
  243. LocalWorkstation.Buffer[1] == L'\\')
  244. {
  245. LocalWorkstation.Buffer += 2;
  246. LocalWorkstation.Length -= 2 * sizeof(WCHAR);
  247. LocalWorkstation.MaximumLength -= 2 * sizeof(WCHAR);
  248. }
  249. //
  250. // To validate the user's logon hours as SAM does it, use this code,
  251. // otherwise, supply your own checks below this code.
  252. //
  253. Status DBGCHK = AccountRestrictions(
  254. pUserAll->UserId,
  255. &LocalWorkstation,
  256. (PUNICODE_STRING) &pUserAll->WorkStations,
  257. &pUserAll->LogonHours,
  258. pLogoffTime,
  259. pKickoffTime
  260. );
  261. }
  262. //
  263. // Validate if the user can log on from this workstation.
  264. // (Supply subauthentication package specific code here.)
  265. if (NT_SUCCESS(Status) && LogonNetworkInfo->Identity.Workstation.Buffer == NULL)
  266. {
  267. Status DBGCHK = STATUS_INVALID_WORKSTATION;
  268. *Authoritative = TRUE;
  269. }
  270. }
  271. }
  272. //
  273. // The user is valid.
  274. //
  275. if (NT_SUCCESS(Status))
  276. {
  277. *Authoritative = TRUE;
  278. Status DBGCHK = STATUS_SUCCESS;
  279. }
  280. return Status;
  281. }
  282. NTSTATUS
  283. SampMatchworkstation(
  284. IN PUNICODE_STRING pLogonWorkStation,
  285. IN PUNICODE_STRING pWorkStations
  286. )
  287. {
  288. TNtStatus NtStatus = STATUS_INVALID_WORKSTATION;
  289. PWCHAR pWorkStationName;
  290. UNICODE_STRING Unicode;
  291. UNICODE_STRING WorkStationsListCopy;
  292. PWCHAR pTmpBuffer;
  293. //
  294. // Local workstation is always allowed
  295. // If WorkStations field is 0 everybody is allowed
  296. //
  297. if ((pLogonWorkStation == NULL) ||
  298. (pLogonWorkStation->Length == 0) ||
  299. (pWorkStations->Length == 0))
  300. {
  301. return STATUS_SUCCESS;
  302. }
  303. //
  304. // WorkStationApiList points to our current location in the list of
  305. // WorkStations.
  306. //
  307. WorkStationsListCopy.Buffer = (PWSTR) new CHAR[pWorkStations->Length];
  308. NtStatus DBGCHK = WorkStationsListCopy.Buffer ? STATUS_SUCCESS : STATUS_NO_MEMORY;
  309. if (NT_SUCCESS(NtStatus))
  310. {
  311. WorkStationsListCopy.MaximumLength = pWorkStations->Length;
  312. RtlCopyMemory(WorkStationsListCopy.Buffer, pWorkStations->Buffer, pWorkStations->Length);
  313. //
  314. // wcstok requires a string the first time it's called, and NULL
  315. // for all subsequent calls. Use a temporary variable so we
  316. // can do this.
  317. //
  318. pTmpBuffer = WorkStationsListCopy.Buffer;
  319. while (pWorkStationName = wcstok(pTmpBuffer, L","))
  320. {
  321. pTmpBuffer = NULL;
  322. RtlInitUnicodeString(&Unicode, pWorkStationName);
  323. if (EqualComputerName(&Unicode, pLogonWorkStation))
  324. {
  325. NtStatus DBGCHK = STATUS_SUCCESS;
  326. break;
  327. }
  328. }
  329. }
  330. RtlFreeUnicodeString(&WorkStationsListCopy);
  331. return NtStatus;
  332. }
  333. NTSTATUS
  334. AccountRestrictions(
  335. IN ULONG UserRid,
  336. IN PUNICODE_STRING pLogonWorkStation,
  337. IN PUNICODE_STRING pWorkStations,
  338. IN PLOGON_HOURS pLogonHours,
  339. OUT PLARGE_INTEGER pLogoffTime,
  340. OUT PLARGE_INTEGER pKickoffTime
  341. )
  342. {
  343. TNtStatus NtStatus = STATUS_SUCCESS;
  344. static BOOLEAN GetForceLogoff = TRUE;
  345. static LARGE_INTEGER ForceLogoff = {0x7fffffff, 0xFFFFFFF};
  346. #define MILLISECONDS_PER_WEEK 7 * 24 * 60 * 60 * 1000
  347. SYSTEMTIME CurrentTimeFields;
  348. LARGE_INTEGER CurrentTime;
  349. LARGE_INTEGER CurrentUTCTime;
  350. LARGE_INTEGER MillisecondsIntoWeekXUnitsPerWeek;
  351. LARGE_INTEGER LargeUnitsIntoWeek;
  352. LARGE_INTEGER Delta100Ns;
  353. ULONG CurrentMsIntoWeek;
  354. ULONG LogoffMsIntoWeek;
  355. ULONG DeltaMs;
  356. ULONG MillisecondsPerUnit;
  357. ULONG CurrentUnitsIntoWeek;
  358. ULONG LogoffUnitsIntoWeek;
  359. USHORT i;
  360. TIME_ZONE_INFORMATION TimeZoneInformation;
  361. DWORD TimeZoneId;
  362. LARGE_INTEGER BiasIn100NsUnits;
  363. LONG BiasInMinutes;
  364. //
  365. // Only check for users other than the builtin ADMIN
  366. //
  367. if (UserRid != DOMAIN_USER_RID_ADMIN)
  368. {
  369. //
  370. // Scan to make sure the workstation being logged into is in the
  371. // list of valid workstations - or if the list of valid workstations
  372. // is null, which means that all are valid.
  373. //
  374. NtStatus DBGCHK = SampMatchworkstation(pLogonWorkStation, pWorkStations);
  375. if (NT_SUCCESS(NtStatus))
  376. {
  377. //
  378. // Check to make sure that the current time is a valid time to log
  379. // on in the LogonHours.
  380. //
  381. // We need to validate the time taking into account whether we are
  382. // in daylight savings time or standard time. Thus, if the logon
  383. // hours specify that we are able to log on between 9am and 5pm,
  384. // this means 9am to 5pm standard time during the standard time
  385. // period, and 9am to 5pm daylight savings time when in the
  386. // daylight savings time. Since the logon hours stored by SAM are
  387. // independent of daylight savings time, we need to add in the
  388. // difference between standard time and daylight savings time to
  389. // the current time before checking whether this time is a valid
  390. // time to log on. Since this difference (or bias as it is called)
  391. // is actually held in the form
  392. //
  393. // Standard time = Daylight savings time + Bias
  394. //
  395. // the Bias is a negative number. Thus we actually subtract the
  396. // signed Bias from the Current Time.
  397. //
  398. // First, get the Time Zone Information.
  399. //
  400. TimeZoneId = GetTimeZoneInformation(&TimeZoneInformation);
  401. //
  402. // Next, get the appropriate bias (signed integer in minutes) to subtract from
  403. // the Universal Time Convention (UTC) time returned by NtQuerySystemTime
  404. // to get the local time. The bias to be used depends whether we're
  405. // in Daylight Savings time or Standard Time as indicated by the
  406. // TimeZoneId parameter.
  407. //
  408. // local time = UTC time - bias in 100Ns units
  409. //
  410. switch (TimeZoneId)
  411. {
  412. case TIME_ZONE_ID_UNKNOWN:
  413. //
  414. // There is no differentiation between standard and
  415. // daylight savings time. Proceed as for Standard Time
  416. //
  417. BiasInMinutes = TimeZoneInformation.StandardBias;
  418. break;
  419. case TIME_ZONE_ID_STANDARD:
  420. BiasInMinutes = TimeZoneInformation.StandardBias;
  421. break;
  422. case TIME_ZONE_ID_DAYLIGHT:
  423. BiasInMinutes = TimeZoneInformation.DaylightBias;
  424. break;
  425. default:
  426. //
  427. // Something is wrong with the time zone information. Fail
  428. // the logon request.
  429. //
  430. NtStatus DBGCHK = STATUS_INVALID_LOGON_HOURS;
  431. break;
  432. }
  433. if (NT_SUCCESS(NtStatus))
  434. {
  435. //
  436. // Convert the Bias from minutes to 100ns units
  437. //
  438. BiasIn100NsUnits.QuadPart = ((LONGLONG)BiasInMinutes) * 60 * 10000000;
  439. //
  440. // Get the UTC time in 100Ns units used by Windows Nt. This
  441. // time is GMT.
  442. //
  443. NtStatus DBGCHK = NtQuerySystemTime(&CurrentUTCTime);
  444. }
  445. if (NT_SUCCESS(NtStatus))
  446. {
  447. CurrentTime.QuadPart = CurrentUTCTime.QuadPart -
  448. BiasIn100NsUnits.QuadPart;
  449. FileTimeToSystemTime((PFILETIME)&CurrentTime, &CurrentTimeFields);
  450. CurrentMsIntoWeek = (((( CurrentTimeFields.wDayOfWeek * 24 ) +
  451. CurrentTimeFields.wHour ) * 60 +
  452. CurrentTimeFields.wMinute ) * 60 +
  453. CurrentTimeFields.wSecond ) * 1000 +
  454. CurrentTimeFields.wMilliseconds;
  455. MillisecondsIntoWeekXUnitsPerWeek.QuadPart =
  456. ((LONGLONG)CurrentMsIntoWeek) *
  457. ((LONGLONG)pLogonHours->UnitsPerWeek);
  458. LargeUnitsIntoWeek.QuadPart =
  459. MillisecondsIntoWeekXUnitsPerWeek.QuadPart / ((ULONG) MILLISECONDS_PER_WEEK);
  460. CurrentUnitsIntoWeek = LargeUnitsIntoWeek.LowPart;
  461. if ( !( pLogonHours->LogonHours[ CurrentUnitsIntoWeek / 8] &
  462. ( 0x01 << ( CurrentUnitsIntoWeek % 8 ) ) ) )
  463. {
  464. NtStatus DBGCHK = STATUS_INVALID_LOGON_HOURS;
  465. }
  466. else
  467. {
  468. //
  469. // Determine the next time that the user is NOT supposed to be logged
  470. // in, and return that as LogoffTime.
  471. //
  472. i = 0;
  473. LogoffUnitsIntoWeek = CurrentUnitsIntoWeek;
  474. do
  475. {
  476. i++;
  477. LogoffUnitsIntoWeek = (LogoffUnitsIntoWeek + 1) % pLogonHours->UnitsPerWeek;
  478. }
  479. while ( (i <= pLogonHours->UnitsPerWeek) &&
  480. ( pLogonHours->LogonHours[LogoffUnitsIntoWeek / 8] & (0x01 << (LogoffUnitsIntoWeek % 8)) ) );
  481. if (i > pLogonHours->UnitsPerWeek)
  482. {
  483. //
  484. // All times are allowed, so there's no logoff
  485. // time. Return forever for both pLogoffTime and
  486. // KickoffTime.
  487. //
  488. pLogoffTime->HighPart = 0x7FFFFFFF;
  489. pLogoffTime->LowPart = 0xFFFFFFFF;
  490. pKickoffTime->HighPart = 0x7FFFFFFF;
  491. pKickoffTime->LowPart = 0xFFFFFFFF;
  492. }
  493. else
  494. {
  495. //
  496. // LogoffUnitsIntoWeek points at which time unit the
  497. // user is to log off. Calculate actual time from
  498. // the unit, and return it.
  499. //
  500. // CurrentTimeFields already holds the current
  501. // time for some time during this week; just adjust
  502. // to the logoff time during this week and convert
  503. // to time format.
  504. //
  505. MillisecondsPerUnit = MILLISECONDS_PER_WEEK / pLogonHours->UnitsPerWeek;
  506. LogoffMsIntoWeek = MillisecondsPerUnit * LogoffUnitsIntoWeek;
  507. if (LogoffMsIntoWeek < CurrentMsIntoWeek)
  508. {
  509. DeltaMs = MILLISECONDS_PER_WEEK - (CurrentMsIntoWeek - LogoffMsIntoWeek) ;
  510. }
  511. else
  512. {
  513. DeltaMs = LogoffMsIntoWeek - CurrentMsIntoWeek;
  514. }
  515. Delta100Ns.QuadPart = (LONGLONG) DeltaMs * 10000;
  516. pLogoffTime->QuadPart = CurrentUTCTime.QuadPart + Delta100Ns.QuadPart;
  517. //
  518. // Grab the domain's ForceLogoff time.
  519. //
  520. if (GetForceLogoff)
  521. {
  522. NET_API_STATUS NetStatus;
  523. LPUSER_MODALS_INFO_0 UserModals0;
  524. NetStatus = NetUserModalsGet(NULL,
  525. 0,
  526. (PBYTE *)&UserModals0);
  527. if (NetStatus == 0)
  528. {
  529. GetForceLogoff = FALSE;
  530. ForceLogoff = NetpSecondsToDeltaTime(UserModals0->usrmod0_force_logoff);
  531. NetApiBufferFree(UserModals0);
  532. }
  533. }
  534. //
  535. // Subtract Domain->ForceLogoff from LogoffTime, and return
  536. // that as KickoffTime. Note that Domain->ForceLogoff is a
  537. // negative delta. If its magnitude is sufficiently large
  538. // (in fact, larger than the difference between LogoffTime
  539. // and the largest positive large integer), we'll get overflow
  540. // resulting in a KickOffTime that is negative. In this
  541. // case, reset the KickOffTime to this largest positive
  542. // large integer (i.e. "never") value.
  543. //
  544. pKickoffTime->QuadPart = pLogoffTime->QuadPart - ForceLogoff.QuadPart;
  545. if (pKickoffTime->QuadPart < 0)
  546. {
  547. pKickoffTime->HighPart = 0x7FFFFFFF;
  548. pKickoffTime->LowPart = 0xFFFFFFFF;
  549. }
  550. }
  551. }
  552. }
  553. }
  554. }
  555. else
  556. {
  557. //
  558. // Never kick administrators off
  559. //
  560. pLogoffTime->HighPart = 0x7FFFFFFF;
  561. pLogoffTime->LowPart = 0xFFFFFFFF;
  562. pKickoffTime->HighPart = 0x7FFFFFFF;
  563. pKickoffTime->LowPart = 0xFFFFFFFF;
  564. }
  565. return NtStatus;
  566. }
  567. LARGE_INTEGER
  568. NetpSecondsToDeltaTime(
  569. IN ULONG Seconds
  570. )
  571. {
  572. LARGE_INTEGER DeltaTime;
  573. LARGE_INTEGER LargeSeconds;
  574. LARGE_INTEGER Answer;
  575. //
  576. // Special case TIMEQ_FOREVER (return a full scale negative)
  577. //
  578. if (Seconds == TIMEQ_FOREVER)
  579. {
  580. DeltaTime.LowPart = 0;
  581. DeltaTime.HighPart = (LONG) 0x80000000;
  582. }
  583. else
  584. {
  585. //
  586. // Convert seconds to 100ns units simply by multiplying by 10000000.
  587. //
  588. // Convert to delta time by negating.
  589. //
  590. LargeSeconds.LowPart = Seconds;
  591. LargeSeconds.HighPart = 0;
  592. Answer.QuadPart = LargeSeconds.QuadPart * 10000000;
  593. if (Answer.QuadPart < 0)
  594. {
  595. DeltaTime.LowPart = 0;
  596. DeltaTime.HighPart = (LONG) 0x80000000;
  597. }
  598. else
  599. {
  600. DeltaTime.QuadPart = -Answer.QuadPart;
  601. }
  602. }
  603. return DeltaTime;
  604. }
  605. BOOLEAN
  606. EqualComputerName(
  607. IN PUNICODE_STRING pString1,
  608. IN PUNICODE_STRING pString2
  609. )
  610. {
  611. WCHAR szComputer1[CNLEN + 1] = {0};
  612. WCHAR szComputer2[CNLEN + 1] = {0};
  613. CHAR szOemComputer1[CNLEN + 1] = {0};
  614. CHAR szOemComputer2[CNLEN + 1] = {0};
  615. //
  616. // Make sure the names are not too long
  617. //
  618. if ((pString1->Length > CNLEN*sizeof(WCHAR)) ||
  619. (pString2->Length > CNLEN*sizeof(WCHAR)))
  620. {
  621. return FALSE;
  622. }
  623. //
  624. // Copy them to null terminated strings
  625. //
  626. RtlCopyMemory(
  627. szComputer1,
  628. pString1->Buffer,
  629. pString1->Length
  630. );
  631. szComputer1[pString1->Length/sizeof(WCHAR)] = L'\0';
  632. RtlCopyMemory(
  633. szComputer2,
  634. pString2->Buffer,
  635. pString2->Length
  636. );
  637. szComputer2[pString2->Length/sizeof(WCHAR)] = L'\0';
  638. //
  639. // Convert the computer names to OEM
  640. //
  641. if (!CharToOemW(
  642. szComputer1,
  643. szOemComputer1
  644. ))
  645. {
  646. return FALSE;
  647. }
  648. if (!CharToOemW(
  649. szComputer2,
  650. szOemComputer2
  651. ))
  652. {
  653. return FALSE;
  654. }
  655. //
  656. // Do a case insensitive comparison of the oem computer names.
  657. //
  658. if (_stricmp(szOemComputer1, szOemComputer2) == 0)
  659. {
  660. return TRUE;
  661. }
  662. else
  663. {
  664. return FALSE;
  665. }
  666. }
  667. NTSTATUS NTAPI
  668. Msv1_0SubAuthenticationRoutineGeneric(
  669. IN PVOID SubmitBuffer,
  670. IN ULONG SubmitBufferLength,
  671. OUT PULONG ReturnBufferLength,
  672. OUT PVOID *ReturnBuffer
  673. )
  674. {
  675. TNtStatus Status;
  676. SspiPrint(SSPI_LOG, TEXT("Msv1_0SubAuthenticationRoutineGeneric\n"));
  677. Status DBGCHK = (ReturnBufferLength && ReturnBuffer ) ? STATUS_SUCCESS : STATUS_INVALID_PARAMETER;
  678. if (NT_SUCCESS(Status))
  679. {
  680. *ReturnBuffer = LocalAlloc(0, SubmitBufferLength);
  681. if (*ReturnBuffer)
  682. {
  683. *ReturnBufferLength = SubmitBufferLength;
  684. RtlCopyMemory(*ReturnBuffer, SubmitBuffer, SubmitBufferLength);
  685. }
  686. else
  687. {
  688. *ReturnBufferLength = 0;
  689. }
  690. SspiPrintHex(SSPI_LOG, TEXT("SubauthInfo"), SubmitBufferLength, SubmitBuffer);
  691. }
  692. return Status;
  693. }
  694. NTSTATUS
  695. NTAPI
  696. Msv1_0SubAuthenticationFilter(
  697. IN NETLOGON_LOGON_INFO_CLASS LogonLevel,
  698. IN PVOID pLogonInformation,
  699. IN ULONG Flags,
  700. IN PUSER_ALL_INFORMATION pUserAll,
  701. OUT PULONG pWhichFields,
  702. OUT PULONG pUserFlags,
  703. OUT PBOOLEAN pAuthoritative,
  704. OUT PLARGE_INTEGER pLogoffTime,
  705. OUT PLARGE_INTEGER pKickoffTime
  706. )
  707. {
  708. return Msv1_0SubAuthenticationRoutine(
  709. LogonLevel,
  710. pLogonInformation,
  711. Flags,
  712. pUserAll,
  713. pWhichFields,
  714. pUserFlags,
  715. pAuthoritative,
  716. pLogoffTime,
  717. pKickoffTime
  718. );
  719. }