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.

552 lines
17 KiB

  1. /*++
  2. Copyright (c) 1994 Microsoft Corporation
  3. Module Name:
  4. password.c
  5. Abstract:
  6. functions to display & set the password policy for this workstation
  7. Author:
  8. Bob Watson (a-robw)
  9. Revision History:
  10. 23 Dec 94
  11. --*/
  12. #include <nt.h>
  13. #include <ntrtl.h>
  14. #include <nturtl.h>
  15. #include <ntsam.h>
  16. #include <windows.h>
  17. #include <tchar.h>
  18. #include <stdlib.h>
  19. #include <stdio.h>
  20. #include <c2dll.h>
  21. #include <c2inc.h>
  22. #include <c2utils.h>
  23. #include "c2funcs.h"
  24. #include "c2funres.h"
  25. // define action codes here. They are only meaningful in the
  26. // context of this module.
  27. #define AC_PW_LENGTH_NOCHANGE 0
  28. #define AC_PW_LENGTH_UPDATE 1
  29. #define SECURE C2DLL_C2
  30. static
  31. LONG
  32. GetWorkstationMinPasswordLength (
  33. )
  34. {
  35. SAM_HANDLE hsamObject;
  36. SAM_HANDLE hsamDomain;
  37. PSID psidDomain;
  38. SAM_ENUMERATE_HANDLE hSamEnum;
  39. PSAM_RID_ENUMERATION pRidEnum;
  40. PVOID pvEnumBuffer;
  41. ULONG ulEnumCount;
  42. LONG lRetPwLen = -1; // init to error value
  43. NTSTATUS ntstat;
  44. PDOMAIN_PASSWORD_INFORMATION pdpiData;
  45. SET_WAIT_CURSOR;
  46. // connect to SAM on this machine
  47. ntstat = SamConnect((PUNICODE_STRING)NULL, &hsamObject,
  48. SAM_SERVER_ALL_ACCESS, (POBJECT_ATTRIBUTES)NULL);
  49. if (ntstat == STATUS_SUCCESS) {
  50. // Ask SAM for the domains on this server.
  51. hSamEnum = 0;
  52. ntstat = SamEnumerateDomainsInSamServer(
  53. hsamObject,
  54. &hSamEnum,
  55. &pvEnumBuffer,
  56. 1024,
  57. &ulEnumCount);
  58. if ((ntstat == STATUS_SUCCESS) || (ntstat == STATUS_MORE_ENTRIES)) {
  59. // look up only the first entry
  60. pRidEnum = (PSAM_RID_ENUMERATION) pvEnumBuffer;
  61. // get SID of domain
  62. ntstat = SamLookupDomainInSamServer (
  63. hsamObject,
  64. &pRidEnum->Name,
  65. &psidDomain);
  66. if (ntstat == STATUS_SUCCESS) {
  67. // open handle to this domain
  68. ntstat = SamOpenDomain (
  69. hsamObject,
  70. DOMAIN_EXECUTE,
  71. psidDomain,
  72. &hsamDomain);
  73. if (ntstat == STATUS_SUCCESS) {
  74. // get password policy for this domain
  75. pdpiData = NULL;
  76. ntstat = SamQueryInformationDomain (
  77. hsamDomain,
  78. DomainPasswordInformation,
  79. (PVOID *)&pdpiData);
  80. if (ntstat == STATUS_SUCCESS) {
  81. // evaluate password length here
  82. lRetPwLen = (LONG)pdpiData->MinPasswordLength;
  83. ntstat = SamFreeMemory (pdpiData);
  84. }
  85. // close handle
  86. SamCloseHandle (hsamDomain);
  87. }
  88. }
  89. SamFreeMemory(pvEnumBuffer);
  90. }
  91. SamCloseHandle (hsamObject);
  92. } else {
  93. lRetPwLen = -1;
  94. }
  95. SetLastError (RtlNtStatusToDosError(ntstat));
  96. SET_ARROW_CURSOR;
  97. return lRetPwLen;
  98. }
  99. static
  100. BOOL
  101. SetWorkstationMinPasswordLength (
  102. LONG lMinLength
  103. )
  104. {
  105. SAM_HANDLE hsamObject;
  106. SAM_HANDLE hsamDomain;
  107. PSID psidDomain;
  108. SAM_ENUMERATE_HANDLE hSamEnum;
  109. PSAM_RID_ENUMERATION pRidEnum;
  110. PVOID pvEnumBuffer;
  111. ULONG ulEnumCount;
  112. BOOL bReturn = FALSE; // assume error until everything works
  113. NTSTATUS ntstat;
  114. PDOMAIN_PASSWORD_INFORMATION pdpiData;
  115. SET_WAIT_CURSOR;
  116. // connect to SAM on this machine
  117. if (EnableSecurityPriv()) {
  118. ntstat = SamConnect((PUNICODE_STRING)NULL, &hsamObject,
  119. STANDARD_RIGHTS_WRITE | SAM_SERVER_ALL_ACCESS,
  120. (POBJECT_ATTRIBUTES)NULL);
  121. if (ntstat == STATUS_SUCCESS) {
  122. // Ask SAM for the domains on this server.
  123. hSamEnum = 0;
  124. ntstat = SamEnumerateDomainsInSamServer(
  125. hsamObject,
  126. &hSamEnum,
  127. &pvEnumBuffer,
  128. 1024,
  129. &ulEnumCount);
  130. if ((ntstat == STATUS_SUCCESS) || (ntstat == STATUS_MORE_ENTRIES)) {
  131. // look up only the first entry
  132. pRidEnum = (PSAM_RID_ENUMERATION) pvEnumBuffer;
  133. // get SID of domain
  134. ntstat = SamLookupDomainInSamServer (
  135. hsamObject,
  136. &pRidEnum->Name,
  137. &psidDomain);
  138. if (ntstat == STATUS_SUCCESS) {
  139. // open handle to this domain
  140. ntstat = SamOpenDomain (
  141. hsamObject,
  142. STANDARD_RIGHTS_WRITE |
  143. DOMAIN_READ_PASSWORD_PARAMETERS |
  144. DOMAIN_LIST_ACCOUNTS |
  145. DOMAIN_LOOKUP |
  146. DOMAIN_WRITE_PASSWORD_PARAMS,
  147. psidDomain,
  148. &hsamDomain);
  149. if (ntstat == STATUS_SUCCESS) {
  150. // get password policy for this domain
  151. pdpiData = NULL;
  152. ntstat = SamQueryInformationDomain (
  153. hsamDomain,
  154. DomainPasswordInformation,
  155. (PVOID *)&pdpiData);
  156. if (ntstat == STATUS_SUCCESS) {
  157. // evaluate password length here
  158. lMinLength &= 0x000000FF; // make it reallly short
  159. pdpiData->MinPasswordLength = (USHORT)lMinLength;
  160. ntstat = SamSetInformationDomain (
  161. hsamDomain,
  162. DomainPasswordInformation,
  163. (PVOID)pdpiData);
  164. if (ntstat == STATUS_SUCCESS) {
  165. bReturn = TRUE;
  166. }
  167. ntstat = SamFreeMemory (pdpiData);
  168. }
  169. // close handle
  170. SamCloseHandle (hsamDomain);
  171. }
  172. }
  173. SamFreeMemory(pvEnumBuffer);
  174. }
  175. SamCloseHandle (hsamObject);
  176. }
  177. SetLastError (RtlNtStatusToDosError(ntstat));
  178. }
  179. SET_ARROW_CURSOR;
  180. return bReturn;
  181. }
  182. BOOL CALLBACK
  183. C2PasswordLengthDlgProc(
  184. IN HWND hDlg, // window handle of the dialog box
  185. IN UINT message, // type of message
  186. IN WPARAM wParam,
  187. IN LPARAM lParam
  188. )
  189. /*++
  190. Routine Description:
  191. Window procedure for Password Length Dialog Box
  192. Arguments:
  193. Standard DlgProc arguments
  194. ReturnValue:
  195. TRUE the message was handled by this routine
  196. FALSE DefDialogProc should handle the message
  197. --*/
  198. {
  199. static PLONG plNewLength; // save address of caller's data block
  200. DWORD dwLogSetting = 0;
  201. int nButton;
  202. int nState;
  203. LONG lPasswordLength;
  204. TCHAR szPasswordLength[4];
  205. switch (message) {
  206. case WM_INITDIALOG:
  207. // save the pointer to the new value
  208. plNewLength = (PLONG)lParam;
  209. // set the correct radio button
  210. lPasswordLength = GetWorkstationMinPasswordLength();
  211. if (lPasswordLength > 0) {
  212. nButton = IDC_MIN_PASSWORD_LENGTH;
  213. EnableWindow (GetDlgItem(hDlg, IDC_PASSWORD_LENGTH_EDIT), TRUE);
  214. _stprintf (szPasswordLength, TEXT("%2d"), lPasswordLength);
  215. SetDlgItemText (hDlg, IDC_PASSWORD_LENGTH_EDIT, szPasswordLength);
  216. } else {
  217. nButton = IDC_ALLOW_BLANK_PASSWORD;
  218. EnableWindow (GetDlgItem(hDlg, IDC_PASSWORD_LENGTH_EDIT), FALSE);
  219. }
  220. CheckRadioButton (hDlg,
  221. IDC_ALLOW_BLANK_PASSWORD,
  222. IDC_MIN_PASSWORD_LENGTH,
  223. nButton);
  224. // set text limits on edit boxes
  225. SendDlgItemMessage (hDlg, IDC_PASSWORD_LENGTH_EDIT, EM_LIMITTEXT,
  226. (WPARAM)2, 0);
  227. SetFocus (GetDlgItem (hDlg, IDOK)); // set focus to OK Button
  228. return FALSE; // we don't want Windows to set the focus
  229. case WM_COMMAND:
  230. switch (LOWORD(wParam)){
  231. case IDOK:
  232. if (HIWORD(wParam) == BN_CLICKED) {
  233. if (IsDlgButtonChecked (hDlg, IDC_ALLOW_BLANK_PASSWORD) == CHECKED) {
  234. *plNewLength = 0;
  235. EndDialog (hDlg, (int)LOWORD(wParam));
  236. } else {
  237. GetDlgItemText (hDlg, IDC_PASSWORD_LENGTH_EDIT,
  238. szPasswordLength, 4);
  239. lPasswordLength = _tcstol(szPasswordLength, NULL, 10);
  240. // make sure it's a valid length
  241. if ((lPasswordLength > 0) && (lPasswordLength <= 14)) {
  242. *plNewLength = lPasswordLength;
  243. // then there's text so exit
  244. EndDialog (hDlg, (int)LOWORD(wParam));
  245. } else {
  246. // an incorrect entry is in the edit box so display message
  247. MessageBeep (MB_ICONASTERISK);
  248. DisplayDllMessageBox (hDlg,
  249. IDS_PASSWORD_INVALID_LEN,
  250. IDS_PASSWORD_CAPTION,
  251. MBOK_INFO);
  252. SetFocus (GetDlgItem (hDlg, IDC_PASSWORD_LENGTH_EDIT));
  253. }
  254. }
  255. return TRUE;
  256. } else {
  257. return FALSE;
  258. }
  259. case IDCANCEL:
  260. if (HIWORD(wParam) == BN_CLICKED) {
  261. // exit and return button that caused exit
  262. EndDialog (hDlg, (int)LOWORD(wParam));
  263. return TRUE;
  264. } else {
  265. return FALSE;
  266. }
  267. case IDC_C2:
  268. if (HIWORD(wParam) == BN_CLICKED) {
  269. nState = ENABLED;
  270. CheckRadioButton (hDlg,
  271. IDC_ALLOW_BLANK_PASSWORD,
  272. IDC_MIN_PASSWORD_LENGTH,
  273. IDC_MIN_PASSWORD_LENGTH);
  274. // en/disable edit windows
  275. EnableWindow (GetDlgItem(hDlg,
  276. IDC_PASSWORD_LENGTH_EDIT), TRUE);
  277. // if there is no text in both of the edit fields
  278. // then display information message
  279. lPasswordLength = SendDlgItemMessage (hDlg, IDC_PASSWORD_LENGTH_EDIT,
  280. WM_GETTEXTLENGTH, 0, 0);
  281. if (lPasswordLength == 0) {
  282. // no value so use 6 for starters
  283. SetDlgItemText (hDlg, IDC_PASSWORD_LENGTH_EDIT,
  284. TEXT("6"));
  285. SetFocus (GetDlgItem (hDlg, IDC_PASSWORD_LENGTH_EDIT));
  286. }
  287. return TRUE;
  288. } else {
  289. return FALSE;
  290. }
  291. case IDC_ALLOW_BLANK_PASSWORD:
  292. case IDC_MIN_PASSWORD_LENGTH:
  293. // check correct button
  294. CheckRadioButton (hDlg,
  295. IDC_ALLOW_BLANK_PASSWORD,
  296. IDC_MIN_PASSWORD_LENGTH,
  297. LOWORD(wParam));
  298. // enable or disable the edit window
  299. if (LOWORD(wParam) == IDC_MIN_PASSWORD_LENGTH) {
  300. nState = ENABLED;
  301. } else {
  302. nState = DISABLED;
  303. }
  304. EnableWindow (GetDlgItem(hDlg,
  305. IDC_PASSWORD_LENGTH_EDIT), nState);
  306. return TRUE;
  307. case IDC_HELP:
  308. PostMessage (GetParent(hDlg), UM_SHOW_CONTEXT_HELP, 0, 0);
  309. return TRUE;
  310. default:
  311. return FALSE;
  312. }
  313. default:
  314. return (FALSE); // Didn't process the message
  315. }
  316. }
  317. LONG
  318. C2QueryPasswordLength (
  319. IN LPARAM lParam
  320. )
  321. /*++
  322. Routine Description:
  323. Function called to find out the current state of this configuration
  324. item. This function reads the current state of the item and
  325. sets the C2 Compliance flag and the Status string to reflect
  326. the current value of the configuration item.
  327. Arguments:
  328. Pointer to the Dll data block passed as an LPARAM.
  329. ReturnValue:
  330. ERROR_SUCCESS if the function succeeds otherwise a
  331. WIN32 error is returned if an error occurs
  332. --*/
  333. {
  334. PC2DLL_DATA pC2Data;
  335. LONG lPasswordLength;
  336. if (lParam != 0) {
  337. pC2Data = (PC2DLL_DATA)lParam;
  338. lPasswordLength = GetWorkstationMinPasswordLength();
  339. if (lPasswordLength > 0) {
  340. pC2Data->lC2Compliance = SECURE;
  341. _stprintf (pC2Data->szStatusName,
  342. GetStringResource (GetDllInstance(), IDS_PASSWORD_NOT_BLANK),
  343. lPasswordLength);
  344. } else if (lPasswordLength == 0) {
  345. pC2Data->lC2Compliance = C2DLL_NOT_SECURE;
  346. _stprintf (pC2Data->szStatusName,
  347. GetStringResource (GetDllInstance(), IDS_PASSWORD_CAN_BE_BLANK));
  348. } else {
  349. pC2Data->lC2Compliance = C2DLL_NOT_SECURE;
  350. _stprintf (pC2Data->szStatusName,
  351. GetStringResource (GetDllInstance(), IDS_UNABLE_READ));
  352. }
  353. } else {
  354. return ERROR_BAD_ARGUMENTS;
  355. }
  356. return ERROR_SUCCESS;
  357. }
  358. LONG
  359. C2SetPasswordLength (
  360. IN LPARAM lParam
  361. )
  362. /*++
  363. Routine Description:
  364. Function called to change the current state of this configuration
  365. item based on an action code passed in the DLL data block. If
  366. this function successfully sets the state of the configuration
  367. item, then the C2 Compliance flag and the Status string to reflect
  368. the new value of the configuration item.
  369. Arguments:
  370. Pointer to the Dll data block passed as an LPARAM.
  371. ReturnValue:
  372. ERROR_SUCCESS if the function succeeds otherwise a
  373. WIN32 error is returned if an error occurs
  374. --*/
  375. {
  376. PC2DLL_DATA pC2Data;
  377. LONG lPasswordLength = 0;
  378. if (lParam != 0) {
  379. pC2Data = (PC2DLL_DATA)lParam;
  380. if (pC2Data->lActionCode == AC_PW_LENGTH_UPDATE) {
  381. if (SetWorkstationMinPasswordLength (pC2Data->lActionValue)) {
  382. lPasswordLength = pC2Data->lActionValue;
  383. if (lPasswordLength > 0) {
  384. pC2Data->lC2Compliance = SECURE;
  385. _stprintf (pC2Data->szStatusName,
  386. GetStringResource (GetDllInstance(), IDS_PASSWORD_NOT_BLANK),
  387. lPasswordLength);
  388. } else {
  389. pC2Data->lC2Compliance = C2DLL_NOT_SECURE;
  390. _stprintf (pC2Data->szStatusName,
  391. GetStringResource (GetDllInstance(), IDS_PASSWORD_CAN_BE_BLANK));
  392. }
  393. } else {
  394. DisplayDllMessageBox (
  395. pC2Data->hWnd,
  396. IDS_PASSWORD_ERROR_NO_SET,
  397. IDS_PASSWORD_CAPTION,
  398. MBOK_EXCLAIM);
  399. }
  400. pC2Data->lActionCode = 0;
  401. pC2Data->lActionValue = 0;
  402. }
  403. } else {
  404. return ERROR_BAD_ARGUMENTS;
  405. }
  406. return ERROR_SUCCESS;
  407. }
  408. LONG
  409. C2DisplayPasswordLength (
  410. IN LPARAM lParam
  411. )
  412. /*++
  413. Routine Description:
  414. Function called to display more information on the configuration
  415. item and provide the user with the option to change the current
  416. setting (if appropriate). If the User "OK's" out of the UI,
  417. then the action code field in the DLL data block is set to the
  418. appropriate (and configuration item-specific) action code so the
  419. "Set" function can be called to perform the desired action. If
  420. the user Cancels out of the UI, then the Action code field is
  421. set to 0 (no action) and no action is performed.
  422. Arguments:
  423. Pointer to the Dll data block passed as an LPARAM.
  424. ReturnValue:
  425. ERROR_SUCCESS if the function succeeds otherwise a
  426. WIN32 error is returned if an error occurs
  427. --*/
  428. {
  429. PC2DLL_DATA pC2Data;
  430. LONG lNewValue = 0;
  431. if (lParam != 0) {
  432. pC2Data = (PC2DLL_DATA)lParam;
  433. if (DialogBoxParam (
  434. GetDllInstance(),
  435. MAKEINTRESOURCE (IDD_PASSWORD_LENGTH),
  436. pC2Data->hWnd,
  437. C2PasswordLengthDlgProc,
  438. (LPARAM)&lNewValue) == IDOK) {
  439. pC2Data->lActionValue = lNewValue;
  440. pC2Data->lActionCode = AC_PW_LENGTH_UPDATE;
  441. } else {
  442. // no action
  443. pC2Data->lActionCode = AC_PW_LENGTH_NOCHANGE;
  444. }
  445. } else {
  446. return ERROR_BAD_ARGUMENTS;
  447. }
  448. return ERROR_SUCCESS;
  449. }
  450. 
  451.