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.

424 lines
14 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. CHGPSW.CPP
  5. Abstract:
  6. Handler for the CHANGE button on the properties dialog,
  7. used to change the user's domain password.
  8. Author:
  9. 990917 johnhaw Created.
  10. georgema 000310 updated
  11. georgema 000501 used to be EXE, changed to CPL
  12. Comments:
  13. Environment:
  14. WinXP
  15. Revision History:
  16. --*/
  17. // test/dev switch variables
  18. #include "switches.h"
  19. //////////////////////////////////////////////////////////////////////////////
  20. //
  21. // Include files
  22. //
  23. #include <stdlib.h>
  24. #include <nt.h>
  25. #include <ntrtl.h>
  26. #include <nturtl.h>
  27. #include <windows.h>
  28. #include <winbase.h>
  29. #include <lmaccess.h>
  30. #include <lmerr.h>
  31. #include <scuisupp.h>
  32. #include <wincrui.h>
  33. #include <comctrlp.h>
  34. #include <tchar.h>
  35. #include <shfusion.h>
  36. #include "switches.h"
  37. #include "Dlg.h"
  38. #include "Res.h"
  39. #include "KRDlg.h"
  40. #include "keymgr.h"
  41. #include "testaudit.h"
  42. #include "pswutil.h"
  43. //////////////////////////////////////////////////////////////////////////////
  44. //
  45. // C_ChangePasswordDlg
  46. //
  47. // Constructor.
  48. //
  49. // parameters:
  50. // hwndParent parent window for the dialog (may be NULL)
  51. // hInstance instance handle of the parent window (may be NULL)
  52. // lIDD dialog template id
  53. // pfnDlgProc pointer to the function that will process messages for
  54. // the dialog. if it is NULL, the default dialog proc
  55. // will be used.
  56. //
  57. // returns:
  58. // Nothing.
  59. //
  60. //////////////////////////////////////////////////////////////////////////////
  61. C_ChangePasswordDlg::C_ChangePasswordDlg(
  62. HWND hwndParent,
  63. HINSTANCE hInstance,
  64. LONG lIDD,
  65. DLGPROC pfnDlgProc // = NULL
  66. )
  67. : C_Dlg(hwndParent, hInstance, lIDD, pfnDlgProc)
  68. {
  69. m_hInst = hInstance;
  70. } // C_ChangePasswordDlg::C_ChangePasswordDlg
  71. //////////////////////////////////////////////////////////////////////////////
  72. //
  73. // OnInitDialog
  74. //
  75. // Dialog control and data initialization.
  76. //
  77. // parameters:
  78. // hwndDlg window handle of the dialog box
  79. // hwndFocus window handle of the control that will receive focus
  80. //
  81. // returns:
  82. // TRUE if the system should set the default keyboard focus
  83. // FALSE if the keyboard focus is set by this app
  84. //
  85. //////////////////////////////////////////////////////////////////////////////
  86. BOOL
  87. C_ChangePasswordDlg::OnInitDialog(
  88. HWND hwndDlg,
  89. HWND hwndFocus
  90. )
  91. {
  92. // To economize on memory, szMsg buffer is sized considerably longer than the MAX_STRING_SIZE
  93. // that would be expected for its normal use for short messages. In one instance, it is being
  94. // used to hold a username (line 139). It is, therefore considerably longer than otherwise needed.
  95. // This size mismatch is benignly not reflected in code which uses counted string functions to
  96. // copy/cat into this buffer. This is the result of the buffer length having been changed after
  97. // the surrounding code was originally written.
  98. TCHAR szMsg[CRED_MAX_USERNAME_LENGTH + 1];
  99. TCHAR szTitle[MAX_STRING_SIZE + 1];
  100. CREDENTIAL *pOldCred = NULL;
  101. BOOL bResult;
  102. TCHAR *pC;
  103. C_Dlg::OnInitDialog(hwndDlg, hwndFocus);
  104. SetFocus (GetDlgItem ( hwndDlg, IDC_OLD_PASSWORD));
  105. m_hDlg = hwndDlg;
  106. // read the currently selected credential, read the cred to get the username,
  107. // extract the domain, and set the text to show the affected domain.
  108. bResult = CredRead(g_szTargetName,CRED_TYPE_DOMAIN_PASSWORD,0,&pOldCred);
  109. if (bResult != TRUE)
  110. {
  111. LoadString ( m_hInst, IDS_PSWFAILED, szMsg, MAX_STRING_SIZE );
  112. LoadString ( m_hInst, IDS_APP_NAME, szTitle, MAX_STRING_SIZE );
  113. MessageBox ( m_hDlg, szMsg, szTitle, MB_OK );
  114. EndDialog(IDOK);
  115. return TRUE;
  116. }
  117. // Get the domain and user names from the username string in the credential
  118. // handle domain\user, domain.etc.etc\user, [email protected]
  119. _tcsncpy(m_szFullUsername,pOldCred->UserName,UNLEN + UNLEN + 1 + 1 );
  120. m_szFullUsername[UNLEN + UNLEN + 1] = 0;
  121. _tcsncpy(szMsg,pOldCred->UserName,CRED_MAX_USERNAME_LENGTH); // scratch buff
  122. szMsg[CRED_MAX_USERNAME_LENGTH] = 0;
  123. pC = _tcschr(szMsg,((TCHAR)'\\'));
  124. if (NULL != pC)
  125. {
  126. // name is format domain\something
  127. *pC = 0;
  128. _tcsncpy(m_szDomain,szMsg,UNLEN);
  129. m_szDomain[UNLEN - 1] = 0;
  130. _tcsncpy(m_szUsername, (pC + 1), UNLEN);
  131. m_szUsername[UNLEN - 1] = 0;
  132. }
  133. else
  134. {
  135. // see if name@something
  136. pC = _tcschr(szMsg,((TCHAR)'@'));
  137. if (NULL == pC)
  138. {
  139. LoadString ( m_hInst, IDS_DOMAINFAILED, szMsg, CRED_MAX_USERNAME_LENGTH);
  140. LoadString ( m_hInst, IDS_APP_NAME, szTitle, MAX_STRING_SIZE );
  141. MessageBox ( m_hDlg, szMsg, szTitle, MB_OK );
  142. if (pOldCred) CredFree(pOldCred);
  143. return TRUE; // don't call EndDialog()
  144. }
  145. *pC = 0;
  146. _tcsncpy(m_szDomain,(pC + 1),UNLEN);
  147. m_szDomain[UNLEN - 1] = 0;
  148. _tcsncpy(m_szUsername, szMsg,UNLEN);
  149. m_szUsername[UNLEN - 1] = 0;
  150. }
  151. if (pOldCred) CredFree(pOldCred);
  152. if (0 != LoadString(g_hInstance,IDS_CPLABEL,szTitle,MAX_STRING_SIZE))
  153. {
  154. INT iLen = MAX_STRING_SIZE - _tcslen(szTitle);
  155. if (iLen > 0)
  156. {
  157. // this will change your password for the domain <appendedname>
  158. // GMBUG: this may localize inconsistently. Should use positional
  159. // parameters.
  160. _tcsncat(szTitle,m_szDomain,iLen);
  161. szTitle[MAX_STRING_SIZE - 1] = 0;
  162. }
  163. SetDlgItemText(m_hwnd,IDC_CPLABEL,szTitle);
  164. }
  165. return TRUE;
  166. } // C_ChangePasswordDlg::OnInitDialog
  167. //////////////////////////////////////////////////////////////////////////////
  168. //
  169. // OnCommand
  170. //
  171. // Route WM_COMMAND message to appropriate handlers.
  172. //
  173. // parameters:
  174. // wNotifyCode code describing action that has occured
  175. // wSenderId id of the control sending the message, if the message
  176. // is from a dialog
  177. // hwndSender window handle of the window sending the message if the
  178. // message is not from a dialog
  179. //
  180. // returns:
  181. // TRUE if the message was processed completely
  182. // FALSE if Windows is to process the message
  183. //
  184. //////////////////////////////////////////////////////////////////////////////
  185. BOOL
  186. C_ChangePasswordDlg::OnCommand(
  187. WORD wNotifyCode,
  188. WORD wSenderId,
  189. HWND hwndSender
  190. )
  191. {
  192. // Was the message handled?
  193. //
  194. BOOL fHandled = FALSE;
  195. switch (wSenderId)
  196. {
  197. case IDOK:
  198. if (BN_CLICKED == wNotifyCode)
  199. {
  200. OnOK( );
  201. fHandled = TRUE;
  202. }
  203. break;
  204. case IDCANCEL:
  205. if (BN_CLICKED == wNotifyCode)
  206. {
  207. EndDialog(IDCANCEL);
  208. fHandled = TRUE;
  209. }
  210. break;
  211. } // switch
  212. return fHandled;
  213. } // C_ChangePasswordDlg::OnCommand
  214. ////////////////////////////////////////////////////////////////////////////
  215. //
  216. // OnOK
  217. //
  218. // Validate user name, synthesize computer name, and destroy dialog.
  219. //
  220. // parameters:
  221. // None.
  222. //
  223. // returns:
  224. // Nothing.
  225. //
  226. //////////////////////////////////////////////////////////////////////////////
  227. void
  228. C_ChangePasswordDlg::OnOK( )
  229. {
  230. TCHAR szMsg[CRED_MAX_USERNAME_LENGTH];
  231. TCHAR szTitle[MAX_STRING_SIZE];
  232. ULONG Error = 0;
  233. BOOL bResult;
  234. ASSERT(::IsWindow(m_hwnd));
  235. // get old and new passwords from the dialog box
  236. GetDlgItemText ( m_hDlg, IDC_OLD_PASSWORD, m_szOldPassword, PWLEN );
  237. GetDlgItemText ( m_hDlg, IDC_NEW_PASSWORD, m_szNewPassword, PWLEN );
  238. GetDlgItemText ( m_hDlg, IDC_CONFIRM_PASSWORD, m_szConfirmPassword, PWLEN );
  239. if ( wcslen ( m_szOldPassword ) == 0 && wcslen ( m_szNewPassword ) ==0 && wcslen (m_szConfirmPassword) == 0 )
  240. {
  241. // must have something filled in
  242. return;
  243. }
  244. else if ( wcscmp ( m_szNewPassword, m_szConfirmPassword) != 0 )
  245. {
  246. LoadString ( m_hInst, IDS_NEWPASSWORDNOTCONFIRMED, szMsg, CRED_MAX_USERNAME_LENGTH );
  247. LoadString ( m_hInst, IDS_APP_NAME, szTitle, MAX_STRING_SIZE );
  248. MessageBox ( m_hDlg, szMsg, szTitle, MB_OK );
  249. return; // don't call EndDialog()
  250. }
  251. else
  252. {
  253. HCURSOR hCursor, hOldCursor;
  254. hOldCursor = NULL;
  255. hCursor = ::LoadCursor ( m_hInst, IDC_WAIT );
  256. if ( hCursor )
  257. {
  258. hOldCursor = ::SetCursor ( hCursor );
  259. }
  260. // let's try changing it
  261. // The targetname is not used. Only the domain name the username, and
  262. // old/new passwords are used
  263. #ifdef LOUDLY
  264. OutputDebugString(L"Changing password on the domain :");
  265. OutputDebugString(m_szDomain);
  266. OutputDebugString(L" for ");
  267. OutputDebugString(m_szUsername);
  268. OutputDebugString(L" to ");
  269. OutputDebugString(m_szNewPassword);
  270. OutputDebugString(L"\n");
  271. #endif
  272. // gm: pass full username and crack it in NetUserChangePasswordEy, so that routine can
  273. // decide whether we are facing a Kerberos domain
  274. Error = NetUserChangePasswordEy ( NULL, m_szFullUsername, m_szOldPassword, m_szNewPassword );
  275. if ( hOldCursor )
  276. ::SetCursor ( hOldCursor );
  277. }
  278. if ( Error == NERR_Success )
  279. {
  280. #ifdef LOUDLY
  281. OutputDebugString(L"Remote password set succeeded\n");
  282. #endif
  283. // Store the new credential in the keyring. It will overlay
  284. // a previous version if present
  285. // Note that the user must have knowledge of and actually type in
  286. // the old password as well as the new password. If the user
  287. // elects to update only the local cache, the old password
  288. // information is not actually used.
  289. // CredWriteDomainCredentials() is used
  290. // m_szDomain holds the domain name
  291. // m_szUsername holds the username
  292. // m_szNewPassword holds the password
  293. CREDENTIAL stCredential;
  294. UINT cbPassword;
  295. memcpy((void *)&stCredential,(void *)g_pExistingCred,sizeof(CREDENTIAL));
  296. // password length does not include zero term
  297. cbPassword = _tcslen(m_szNewPassword) * sizeof(TCHAR);
  298. // Form the domain\username composite username
  299. stCredential.Type = CRED_TYPE_DOMAIN_PASSWORD;
  300. stCredential.TargetName = g_szTargetName;
  301. stCredential.CredentialBlob = (unsigned char *)m_szNewPassword;
  302. stCredential.CredentialBlobSize = cbPassword;
  303. stCredential.UserName = m_szFullUsername;
  304. stCredential.Persist = g_dwPersist;
  305. bResult = CredWrite(&stCredential,0);
  306. if (bResult)
  307. {
  308. LoadString ( m_hInst, IDS_DOMAINCHANGE, szMsg, CRED_MAX_USERNAME_LENGTH );
  309. LoadString ( m_hInst, IDS_APP_NAME, szTitle, MAX_STRING_SIZE );
  310. MessageBox ( m_hDlg, szMsg, szTitle, MB_OK );
  311. }
  312. else
  313. {
  314. LoadString ( m_hInst, IDS_LOCALFAILED, szMsg, CRED_MAX_USERNAME_LENGTH );
  315. LoadString ( m_hInst, IDS_APP_NAME, szTitle, MAX_STRING_SIZE );
  316. MessageBox ( m_hDlg, szMsg, szTitle, MB_OK );
  317. }
  318. // BUGBUG - what to do if the local update operation fails?
  319. // This is not a very big failure, as the first prompt would
  320. // ripple through all domain\username matching creds on the
  321. // keyring and update them later. You're pretty much stuck
  322. // here, since the domain probably will not let you reset the
  323. // psw to the old value.
  324. }
  325. else
  326. {
  327. // Attempt to be specific about failure to change the psw on the
  328. // remote system
  329. #ifdef LOUDLY
  330. OutputDebugString(L"Remote password set failed\n");
  331. #endif
  332. if (Error == ERROR_INVALID_PASSWORD)
  333. {
  334. LoadString ( m_hInst, IDS_CP_INVPSW, szMsg, CRED_MAX_USERNAME_LENGTH );
  335. LoadString ( m_hInst, IDS_APP_NAME, szTitle, MAX_STRING_SIZE );
  336. MessageBox ( m_hDlg, szMsg, szTitle, MB_OK );
  337. }
  338. else if (Error == NERR_UserNotFound)
  339. {
  340. LoadString ( m_hInst, IDS_CP_NOUSER, szMsg, CRED_MAX_USERNAME_LENGTH );
  341. LoadString ( m_hInst, IDS_APP_NAME, szTitle, MAX_STRING_SIZE );
  342. MessageBox ( m_hDlg, szMsg, szTitle, MB_OK );
  343. }
  344. else if (Error == NERR_PasswordTooShort)
  345. {
  346. LoadString ( m_hInst, IDS_CP_BADPSW, szMsg, CRED_MAX_USERNAME_LENGTH );
  347. LoadString ( m_hInst, IDS_APP_NAME, szTitle, MAX_STRING_SIZE );
  348. MessageBox ( m_hDlg, szMsg, szTitle, MB_OK );
  349. }
  350. else if (Error == NERR_InvalidComputer)
  351. {
  352. LoadString ( m_hInst, IDS_CP_NOSVR, szMsg, CRED_MAX_USERNAME_LENGTH );
  353. LoadString ( m_hInst, IDS_APP_NAME, szTitle, MAX_STRING_SIZE );
  354. MessageBox ( m_hDlg, szMsg, szTitle, MB_OK );
  355. }
  356. else if (Error == NERR_NotPrimary)
  357. {
  358. LoadString ( m_hInst, IDS_CP_NOTALLOWED, szMsg, CRED_MAX_USERNAME_LENGTH );
  359. LoadString ( m_hInst, IDS_APP_NAME, szTitle, MAX_STRING_SIZE );
  360. MessageBox ( m_hDlg, szMsg, szTitle, MB_OK );
  361. }
  362. else
  363. {
  364. // Reaching here signifies a failure to set the remote domain
  365. // password for more general reasons
  366. LoadString ( m_hInst, IDS_DOMAINFAILED, szMsg, CRED_MAX_USERNAME_LENGTH );
  367. LoadString ( m_hInst, IDS_APP_NAME, szTitle, MAX_STRING_SIZE );
  368. MessageBox ( m_hDlg, szMsg, szTitle, MB_OK );
  369. }
  370. }
  371. // clean any psw buffers, release the old cred, and go.
  372. SecureZeroMemory(m_szOldPassword,sizeof(m_szOldPassword));
  373. SecureZeroMemory(m_szNewPassword,sizeof(m_szNewPassword));
  374. SecureZeroMemory(m_szConfirmPassword,sizeof(m_szConfirmPassword));
  375. EndDialog(IDOK);
  376. } // C_ChangePasswordDlg::OnOK
  377. //
  378. ///// End of file: krDlg.cpp ///////////////////////////////////////////////