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.

692 lines
16 KiB

  1. /*
  2. * PerSeat.cpp
  3. *
  4. * Author: BreenH
  5. *
  6. * The Per-Seat licensing policy.
  7. */
  8. /*
  9. * Includes
  10. */
  11. #include "precomp.h"
  12. #include "lscore.h"
  13. #include "session.h"
  14. #include "perseat.h"
  15. #include "lctrace.h"
  16. #include "util.h"
  17. #include <tserrs.h>
  18. #define ISSUE_LICENSE_WARNING_PERIOD 15 // days to expiration when warning should be issued
  19. // Size of strings to be displayed to user
  20. #define MAX_MESSAGE_SIZE 512
  21. #define MAX_TITLE_SIZE 256
  22. /*
  23. * extern globals
  24. */
  25. extern "C"
  26. extern HANDLE hModuleWin;
  27. /*
  28. * Class Implementation
  29. */
  30. /*
  31. * Creation Functions
  32. */
  33. CPerSeatPolicy::CPerSeatPolicy(
  34. ) : CPolicy()
  35. {
  36. }
  37. CPerSeatPolicy::~CPerSeatPolicy(
  38. )
  39. {
  40. }
  41. /*
  42. * Administrative Functions
  43. */
  44. ULONG
  45. CPerSeatPolicy::GetFlags(
  46. )
  47. {
  48. return(LC_FLAG_INTERNAL_POLICY | LC_FLAG_REQUIRE_APP_COMPAT);
  49. }
  50. ULONG
  51. CPerSeatPolicy::GetId(
  52. )
  53. {
  54. return(2);
  55. }
  56. NTSTATUS
  57. CPerSeatPolicy::GetInformation(
  58. LPLCPOLICYINFOGENERIC lpPolicyInfo
  59. )
  60. {
  61. NTSTATUS Status;
  62. ASSERT(lpPolicyInfo != NULL);
  63. if (lpPolicyInfo->ulVersion == LCPOLICYINFOTYPE_V1)
  64. {
  65. int retVal;
  66. LPLCPOLICYINFO_V1 lpPolicyInfoV1 = (LPLCPOLICYINFO_V1)lpPolicyInfo;
  67. LPWSTR pName;
  68. LPWSTR pDescription;
  69. ASSERT(lpPolicyInfoV1->lpPolicyName == NULL);
  70. ASSERT(lpPolicyInfoV1->lpPolicyDescription == NULL);
  71. //
  72. // The strings loaded in this fashion are READ-ONLY. They are also
  73. // NOT NULL terminated. Allocate and zero out a buffer, then copy the
  74. // string over.
  75. //
  76. retVal = LoadString(
  77. (HINSTANCE)hModuleWin,
  78. IDS_LSCORE_PERSEAT_NAME,
  79. (LPWSTR)(&pName),
  80. 0
  81. );
  82. if (retVal != 0)
  83. {
  84. lpPolicyInfoV1->lpPolicyName = (LPWSTR)LocalAlloc(LPTR, (retVal + 1) * sizeof(WCHAR));
  85. if (lpPolicyInfoV1->lpPolicyName != NULL)
  86. {
  87. lstrcpynW(lpPolicyInfoV1->lpPolicyName, pName, retVal + 1);
  88. }
  89. else
  90. {
  91. Status = STATUS_NO_MEMORY;
  92. goto V1error;
  93. }
  94. }
  95. else
  96. {
  97. Status = STATUS_INTERNAL_ERROR;
  98. goto V1error;
  99. }
  100. retVal = LoadString(
  101. (HINSTANCE)hModuleWin,
  102. IDS_LSCORE_PERSEAT_DESC,
  103. (LPWSTR)(&pDescription),
  104. 0
  105. );
  106. if (retVal != 0)
  107. {
  108. lpPolicyInfoV1->lpPolicyDescription = (LPWSTR)LocalAlloc(LPTR, (retVal + 1) * sizeof(WCHAR));
  109. if (lpPolicyInfoV1->lpPolicyDescription != NULL)
  110. {
  111. lstrcpynW(lpPolicyInfoV1->lpPolicyDescription, pDescription, retVal + 1);
  112. }
  113. else
  114. {
  115. Status = STATUS_NO_MEMORY;
  116. goto V1error;
  117. }
  118. }
  119. else
  120. {
  121. Status = STATUS_INTERNAL_ERROR;
  122. goto V1error;
  123. }
  124. Status = STATUS_SUCCESS;
  125. goto exit;
  126. V1error:
  127. //
  128. // An error occurred loading/copying the strings.
  129. //
  130. if (lpPolicyInfoV1->lpPolicyName != NULL)
  131. {
  132. LocalFree(lpPolicyInfoV1->lpPolicyName);
  133. lpPolicyInfoV1->lpPolicyName = NULL;
  134. }
  135. if (lpPolicyInfoV1->lpPolicyDescription != NULL)
  136. {
  137. LocalFree(lpPolicyInfoV1->lpPolicyDescription);
  138. lpPolicyInfoV1->lpPolicyDescription = NULL;
  139. }
  140. }
  141. else
  142. {
  143. Status = STATUS_REVISION_MISMATCH;
  144. }
  145. exit:
  146. return(Status);
  147. }
  148. /*
  149. * Loading and Activation Functions
  150. */
  151. NTSTATUS
  152. CPerSeatPolicy::Activate(
  153. BOOL fStartup,
  154. ULONG *pulAlternatePolicy
  155. )
  156. {
  157. UNREFERENCED_PARAMETER(fStartup);
  158. if (NULL != pulAlternatePolicy)
  159. {
  160. // don't set an explicit alternate policy
  161. *pulAlternatePolicy = ULONG_MAX;
  162. }
  163. return(StartCheckingGracePeriod());
  164. }
  165. NTSTATUS
  166. CPerSeatPolicy::Deactivate(
  167. BOOL fShutdown
  168. )
  169. {
  170. if (!fShutdown)
  171. {
  172. return(StopCheckingGracePeriod());
  173. }
  174. else
  175. {
  176. return STATUS_SUCCESS;
  177. }
  178. }
  179. /*
  180. * Licensing Functions
  181. */
  182. NTSTATUS
  183. CPerSeatPolicy::Connect(
  184. CSession& Session,
  185. UINT32 &dwClientError
  186. )
  187. {
  188. LICENSE_STATUS LsStatus = LICENSE_STATUS_OK;
  189. LPBYTE lpReplyBuffer;
  190. LPBYTE lpRequestBuffer;
  191. NTSTATUS Status = STATUS_SUCCESS;
  192. ULONG cbReplyBuffer;
  193. ULONG cbRequestBuffer;
  194. ULONG cbReturned;
  195. BOOL fExtendedError = FALSE;
  196. //
  197. // Check for client redirected to session 0
  198. //
  199. if (Session.IsSessionZero())
  200. {
  201. // Allow client to connect unlicensed
  202. return CPolicy::Connect(Session,dwClientError);
  203. }
  204. lpRequestBuffer = NULL;
  205. lpReplyBuffer = (LPBYTE)LocalAlloc(LPTR, LC_POLICY_PS_DEFAULT_LICENSE_SIZE);
  206. if (lpReplyBuffer != NULL)
  207. {
  208. cbReplyBuffer = LC_POLICY_PS_DEFAULT_LICENSE_SIZE;
  209. }
  210. else
  211. {
  212. Status = STATUS_NO_MEMORY;
  213. goto errorexit;
  214. }
  215. LsStatus = AcceptProtocolContext(
  216. Session.GetLicenseContext()->hProtocolLibContext,
  217. 0,
  218. NULL,
  219. &cbRequestBuffer,
  220. &lpRequestBuffer,
  221. &fExtendedError
  222. );
  223. while(LsStatus == LICENSE_STATUS_CONTINUE)
  224. {
  225. cbReturned = 0;
  226. ASSERT(cbRequestBuffer > 0);
  227. Status = _IcaStackIoControl(
  228. Session.GetIcaStack(),
  229. IOCTL_ICA_STACK_REQUEST_CLIENT_LICENSE,
  230. lpRequestBuffer,
  231. cbRequestBuffer,
  232. lpReplyBuffer,
  233. cbReplyBuffer,
  234. &cbReturned
  235. );
  236. if (Status != STATUS_SUCCESS)
  237. {
  238. if (Status == STATUS_BUFFER_TOO_SMALL)
  239. {
  240. TRACEPRINT((LCTRACETYPE_WARNING, "CPerSeatPolicy::Connect: Reallocating license buffer: %lu, %lu", cbReplyBuffer, cbReturned));
  241. LocalFree(lpReplyBuffer);
  242. lpReplyBuffer = (LPBYTE)LocalAlloc(LPTR, cbReturned);
  243. if (lpReplyBuffer != NULL)
  244. {
  245. cbReplyBuffer = cbReturned;
  246. }
  247. else
  248. {
  249. Status = STATUS_NO_MEMORY;
  250. goto errorexit;
  251. }
  252. Status = _IcaStackIoControl(
  253. Session.GetIcaStack(),
  254. IOCTL_ICA_STACK_GET_LICENSE_DATA,
  255. NULL,
  256. 0,
  257. lpReplyBuffer,
  258. cbReplyBuffer,
  259. &cbReturned
  260. );
  261. if (Status != STATUS_SUCCESS)
  262. {
  263. goto errorexit;
  264. }
  265. }
  266. else
  267. {
  268. goto errorexit;
  269. }
  270. }
  271. if (cbReturned != 0)
  272. {
  273. if (lpRequestBuffer != NULL)
  274. {
  275. LocalFree(lpRequestBuffer);
  276. lpRequestBuffer = NULL;
  277. cbRequestBuffer = 0;
  278. }
  279. LsStatus = AcceptProtocolContext(
  280. Session.GetLicenseContext()->hProtocolLibContext,
  281. cbReturned,
  282. lpReplyBuffer,
  283. &cbRequestBuffer,
  284. &lpRequestBuffer,
  285. &fExtendedError
  286. );
  287. }
  288. }
  289. cbReturned = 0;
  290. if ((LsStatus == LICENSE_STATUS_ISSUED_LICENSE) || (LsStatus == LICENSE_STATUS_OK))
  291. {
  292. Status = _IcaStackIoControl(
  293. Session.GetIcaStack(),
  294. IOCTL_ICA_STACK_SEND_CLIENT_LICENSE,
  295. lpRequestBuffer,
  296. cbRequestBuffer,
  297. NULL,
  298. 0,
  299. &cbReturned
  300. );
  301. if (Status == STATUS_SUCCESS)
  302. {
  303. ULONG ulLicenseResult;
  304. ulLicenseResult = LICENSE_PROTOCOL_SUCCESS;
  305. Status = _IcaStackIoControl(
  306. Session.GetIcaStack(),
  307. IOCTL_ICA_STACK_LICENSE_PROTOCOL_COMPLETE,
  308. &ulLicenseResult,
  309. sizeof(ULONG),
  310. NULL,
  311. 0,
  312. &cbReturned
  313. );
  314. }
  315. }
  316. else if (LsStatus != LICENSE_STATUS_SERVER_ABORT)
  317. {
  318. DWORD dwClientResponse;
  319. LICENSE_STATUS LsStatusT;
  320. UINT32 uiExtendedErrorInfo = TS_ERRINFO_NOERROR;
  321. if (AllowLicensingGracePeriodConnection())
  322. {
  323. dwClientResponse = LICENSE_RESPONSE_VALID_CLIENT;
  324. }
  325. else
  326. {
  327. dwClientResponse = LICENSE_RESPONSE_INVALID_CLIENT;
  328. uiExtendedErrorInfo = LsStatusToClientError(LsStatus);
  329. }
  330. if (lpRequestBuffer != NULL)
  331. {
  332. LocalFree(lpRequestBuffer);
  333. lpRequestBuffer = NULL;
  334. cbRequestBuffer = 0;
  335. }
  336. LsStatusT = ConstructProtocolResponse(
  337. Session.GetLicenseContext()->hProtocolLibContext,
  338. dwClientResponse,
  339. uiExtendedErrorInfo,
  340. &cbRequestBuffer,
  341. &lpRequestBuffer,
  342. fExtendedError
  343. );
  344. if (LsStatusT == LICENSE_STATUS_OK)
  345. {
  346. Status = _IcaStackIoControl(
  347. Session.GetIcaStack(),
  348. IOCTL_ICA_STACK_SEND_CLIENT_LICENSE,
  349. lpRequestBuffer,
  350. cbRequestBuffer,
  351. NULL,
  352. 0,
  353. &cbReturned
  354. );
  355. }
  356. else
  357. {
  358. Status = STATUS_CTX_LICENSE_CLIENT_INVALID;
  359. goto errorexit;
  360. }
  361. if (Status == STATUS_SUCCESS)
  362. {
  363. if (dwClientResponse == LICENSE_RESPONSE_VALID_CLIENT)
  364. {
  365. ULONG ulLicenseResult;
  366. //
  367. // Grace period allowed client to connect
  368. // Tell the stack that the licensing protocol has completed
  369. //
  370. ulLicenseResult = LICENSE_PROTOCOL_SUCCESS;
  371. Status = _IcaStackIoControl(
  372. Session.GetIcaStack(),
  373. IOCTL_ICA_STACK_LICENSE_PROTOCOL_COMPLETE,
  374. &ulLicenseResult,
  375. sizeof(ULONG),
  376. NULL,
  377. 0,
  378. &cbReturned
  379. );
  380. }
  381. else
  382. {
  383. //
  384. // If all IO works correctly, adjust the status to reflect
  385. // that the connection attempt is failing.
  386. //
  387. Status = STATUS_CTX_LICENSE_CLIENT_INVALID;
  388. }
  389. }
  390. }
  391. else
  392. {
  393. TRACEPRINT((LCTRACETYPE_ERROR, "Connect: LsStatus: %d", LsStatus));
  394. Status = STATUS_CTX_LICENSE_CLIENT_INVALID;
  395. }
  396. errorexit:
  397. if (Status != STATUS_SUCCESS)
  398. {
  399. if ((LsStatus != LICENSE_STATUS_OK) && (LsStatus != LICENSE_STATUS_CONTINUE))
  400. {
  401. dwClientError = LsStatusToClientError(LsStatus);
  402. }
  403. else
  404. {
  405. dwClientError = NtStatusToClientError(Status);
  406. }
  407. }
  408. if (lpRequestBuffer != NULL)
  409. {
  410. LocalFree(lpRequestBuffer);
  411. }
  412. if (lpReplyBuffer != NULL)
  413. {
  414. LocalFree(lpReplyBuffer);
  415. }
  416. return(Status);
  417. }
  418. NTSTATUS
  419. CPerSeatPolicy::MarkLicense(
  420. CSession& Session
  421. )
  422. {
  423. LICENSE_STATUS Status;
  424. Status = MarkLicenseFlags(
  425. Session.GetLicenseContext()->hProtocolLibContext,
  426. MARK_FLAG_USER_AUTHENTICATED);
  427. return (Status == LICENSE_STATUS_OK
  428. ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL);
  429. }
  430. NTSTATUS
  431. CPerSeatPolicy::Logon(
  432. CSession& Session
  433. )
  434. {
  435. NTSTATUS Status;
  436. PTCHAR
  437. ptszMsgText = NULL,
  438. ptszMsgTitle = NULL;
  439. if (!Session.IsSessionZero()
  440. && !Session.IsUserHelpAssistant())
  441. {
  442. Status = GetLlsLicense(Session);
  443. }
  444. else
  445. {
  446. Status = STATUS_SUCCESS;
  447. goto done;
  448. }
  449. if (Status != STATUS_SUCCESS)
  450. {
  451. // TODO: put up new error message - can't logon
  452. // also useful when we do post-logon licensing
  453. //
  454. // NB: eventually this should be done through client-side
  455. // error reporting
  456. }
  457. else
  458. {
  459. ULONG_PTR
  460. dwDaysLeftPtr;
  461. DWORD
  462. dwDaysLeft,
  463. cchMsgText;
  464. BOOL
  465. fTemporary;
  466. LICENSE_STATUS
  467. LsStatus;
  468. int
  469. ret,
  470. cchMsgTitle;
  471. WINSTATION_APIMSG
  472. WMsg;
  473. //
  474. // Allocate memory
  475. //
  476. ptszMsgText = (PTCHAR) LocalAlloc(LPTR, MAX_MESSAGE_SIZE * sizeof(TCHAR));
  477. if (NULL == ptszMsgText) {
  478. Status = STATUS_NO_MEMORY;
  479. goto done;
  480. }
  481. ptszMsgTitle = (PTCHAR) LocalAlloc(LPTR, MAX_TITLE_SIZE * sizeof(TCHAR));
  482. if (NULL == ptszMsgTitle) {
  483. Status = STATUS_NO_MEMORY;
  484. goto done;
  485. }
  486. ptszMsgText[0] = L'\0';
  487. ptszMsgTitle[0] = L'\0';
  488. //
  489. // check whether to give an expiration warning
  490. //
  491. LsStatus = DaysToExpiration(
  492. Session.GetLicenseContext()->hProtocolLibContext,
  493. &dwDaysLeft, &fTemporary);
  494. if ((LICENSE_STATUS_OK != LsStatus) || (!fTemporary))
  495. {
  496. goto done;
  497. }
  498. if ((dwDaysLeft == 0xFFFFFFFF) ||
  499. (dwDaysLeft > ISSUE_LICENSE_WARNING_PERIOD))
  500. {
  501. goto done;
  502. }
  503. //
  504. // Display an expiration warning
  505. //
  506. cchMsgTitle = LoadString((HINSTANCE)hModuleWin,
  507. STR_TEMP_LICENSE_MSG_TITLE,
  508. ptszMsgTitle, MAX_TITLE_SIZE );
  509. if (0 == cchMsgTitle)
  510. {
  511. goto done;
  512. }
  513. ret = LoadString((HINSTANCE)hModuleWin,
  514. STR_TEMP_LICENSE_EXPIRATION_MSG,
  515. ptszMsgText, MAX_MESSAGE_SIZE );
  516. if (0 == ret)
  517. {
  518. goto done;
  519. }
  520. dwDaysLeftPtr = dwDaysLeft;
  521. cchMsgText = FormatMessage(FORMAT_MESSAGE_FROM_STRING
  522. | FORMAT_MESSAGE_ARGUMENT_ARRAY,
  523. ptszMsgText,
  524. 0,
  525. 0,
  526. ptszMsgText,
  527. MAX_MESSAGE_SIZE,
  528. (va_list * )&dwDaysLeftPtr );
  529. if (0 == cchMsgText)
  530. {
  531. goto done;
  532. }
  533. WMsg.u.SendMessage.pTitle = ptszMsgTitle;
  534. WMsg.u.SendMessage.TitleLength = (cchMsgTitle + 1) * sizeof(TCHAR);
  535. WMsg.u.SendMessage.pMessage = ptszMsgText;
  536. WMsg.u.SendMessage.MessageLength = (cchMsgText + 1) * sizeof(TCHAR);
  537. WMsg.u.SendMessage.Style = MB_OK;
  538. WMsg.u.SendMessage.Timeout = 60;
  539. WMsg.u.SendMessage.DoNotWait = TRUE;
  540. WMsg.u.SendMessage.DoNotWaitForCorrectDesktop = FALSE;
  541. WMsg.u.SendMessage.pResponse = NULL;
  542. WMsg.ApiNumber = SMWinStationDoMessage;
  543. WMsg.u.SendMessage.hEvent = NULL;
  544. WMsg.u.SendMessage.pStatus = NULL;
  545. WMsg.u.SendMessage.pResponse = NULL;
  546. Session.SendWinStationCommand( &WMsg );
  547. }
  548. done:
  549. if ((STATUS_SUCCESS == Status)
  550. && (Session.GetLicenseContext()->hProtocolLibContext != NULL))
  551. {
  552. if (!Session.IsUserHelpAssistant())
  553. {
  554. //
  555. // Mark the license to show user has logged on
  556. //
  557. MarkLicense(Session);
  558. }
  559. }
  560. if (ptszMsgText != NULL) {
  561. LocalFree(ptszMsgText);
  562. ptszMsgText = NULL;
  563. }
  564. if (ptszMsgTitle != NULL) {
  565. LocalFree(ptszMsgTitle);
  566. ptszMsgTitle = NULL;
  567. }
  568. return(Status);
  569. }
  570. NTSTATUS
  571. CPerSeatPolicy::Reconnect(
  572. CSession& Session,
  573. CSession& TemporarySession
  574. )
  575. {
  576. UNREFERENCED_PARAMETER(Session);
  577. if (TemporarySession.GetLicenseContext()->hProtocolLibContext != NULL)
  578. {
  579. //
  580. // Mark the license to show user has logged on
  581. //
  582. MarkLicense(TemporarySession);
  583. }
  584. return(STATUS_SUCCESS);
  585. }