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.

2930 lines
82 KiB

  1. /*++
  2. Copyright (c) 1993, 1994 Microsoft Corporation
  3. Module Name:
  4. logon.c
  5. Abstract:
  6. This module contains NetWare credential management code.
  7. Author:
  8. Rita Wong (ritaw) 15-Feb-1993
  9. Revision History:
  10. Yi-Hsin Sung (yihsins) 10-July-1993
  11. Moved all dialog handling to nwdlg.c
  12. Tommy Evans (tommye) 05-05-2000
  13. Merged with code from Anoop (anoopa) to fix problem with
  14. username/password not being stored correctly in the LOGON
  15. list.
  16. --*/
  17. #include <nwclient.h>
  18. #include <ntmsv1_0.h>
  19. #include <nwsnames.h>
  20. #include <nwcanon.h>
  21. #include <validc.h>
  22. #include <nwevent.h>
  23. #include <nwdlg.h>
  24. #include <nwreg.h>
  25. #include <nwlsa.h>
  26. #include <nwauth.h>
  27. #include <nwapi.h>
  28. #include <nwmisc.h>
  29. #include <ndsapi32.h>
  30. //-------------------------------------------------------------------//
  31. // //
  32. // Local Function Prototypes //
  33. // //
  34. //-------------------------------------------------------------------//
  35. VOID
  36. NwpInitializeRegistry(
  37. IN LPWSTR NewUserSid,
  38. OUT LPWSTR PreferredServer,
  39. IN DWORD PreferredServerSize,
  40. OUT LPWSTR NdsPreferredServer,
  41. IN DWORD NdsPreferredServerSize,
  42. OUT PDWORD LogonScriptOptions,
  43. OUT PDWORD PrintOption
  44. );
  45. DWORD
  46. NwpReadRegInfo(
  47. IN HKEY WkstaKey,
  48. IN LPWSTR CurrentUserSid,
  49. OUT LPWSTR PreferredServer,
  50. IN DWORD PreferredServerSize,
  51. OUT LPWSTR NdsPreferredServer,
  52. IN DWORD NdsPreferredServerSize,
  53. OUT PDWORD PrintOption
  54. );
  55. DWORD
  56. NwpGetCurrentUser(
  57. OUT LPWSTR *SidString,
  58. OUT LPWSTR *UserName
  59. );
  60. DWORD
  61. NwpGetUserSid(
  62. IN PLUID LogonId,
  63. OUT LPWSTR *UserSidString
  64. );
  65. BOOL
  66. NwpPollWorkstationStart(
  67. VOID
  68. );
  69. VOID
  70. NwpSaveServiceCredential(
  71. IN PLUID LogonId,
  72. IN LPWSTR UserName,
  73. IN LPWSTR Password
  74. );
  75. DWORD
  76. NwpSetCredentialInLsa(
  77. IN PLUID LogonId,
  78. IN LPWSTR UserName,
  79. IN LPWSTR Password
  80. );
  81. NTSTATUS NwNdsOpenRdrHandle(
  82. OUT PHANDLE phNwRdrHandle
  83. );
  84. DWORD
  85. NwpReadLogonScriptOptions(
  86. IN LPWSTR CurrentUserSid,
  87. OUT PDWORD pLogonScriptOptions,
  88. OUT PDWORD pPreferredServerExists
  89. );
  90. LPWSTR
  91. NwpConstructLogonScript(
  92. IN DWORD LogonScriptOptions
  93. );
  94. VOID
  95. NwpSelectServers(
  96. IN HWND DialogHandle,
  97. IN PCHANGE_PW_DLG_PARAM Credential
  98. );
  99. ////////////////////////////////////////////////////////////////////////////
  100. DWORD
  101. APIENTRY
  102. NPLogonNotify(
  103. PLUID lpLogonId,
  104. LPCWSTR lpAuthentInfoType,
  105. LPVOID lpAuthentInfo,
  106. LPCWSTR lpPreviousAuthentInfoType,
  107. LPVOID lpPreviousAuthentInfo,
  108. LPWSTR lpStationName,
  109. LPVOID StationHandle,
  110. LPWSTR *lpLogonScript
  111. )
  112. /*++
  113. Routine Description:
  114. This function is called by Winlogon after the interactive
  115. user has successfully logged on to the local machine. We
  116. are given the username and password, which
  117. are displayed in the NetWare specific logon dialog if
  118. needed.
  119. Arguments:
  120. lpLogonId - Ignored.
  121. lpAuthentInfoType - Supplies a string which if is
  122. L"MSV1_0:Interactive" means that the user has been logged
  123. on by the Microsoft primary authenticator.
  124. lpAuthentInfo - Supplies a pointer to the credentials which
  125. the user was logged on with.
  126. lpPreviousAuthentInfoType - Ignored.
  127. lpPreviousAuthentInfo - Ignored.
  128. lpStationName - Supplies a string which if it is L"WinSta_0"
  129. means that Winlogon logged on the user.
  130. StationHandle - Supplies the handle to the window which to display
  131. our specific dialog.
  132. lpLogonScripts - Receives a pointer to memory allocated by this
  133. routine which contains a MULTI_SZ string of a program to run on
  134. the command line with arguments, e.g. L"myprogram\0arg1\0arg2\0".
  135. This memory must be freed by the caller with LocalFree.
  136. Return Value:
  137. WN_SUCCESS - Successfully saved default credentials.
  138. WN_NOT_SUPPORTED - Primary authenticator is not Microsoft or
  139. is not interactive via Winlogon.
  140. ERROR_FILE_NOT_FOUND - Could not get our own provider DLL handle.
  141. --*/
  142. {
  143. DWORD status = NO_ERROR;
  144. INT_PTR Result = FALSE;
  145. LPWSTR NewUserSid = NULL;
  146. BOOL LogonAttempted = FALSE;
  147. PMSV1_0_INTERACTIVE_LOGON NewLogonInfo =
  148. (PMSV1_0_INTERACTIVE_LOGON) lpAuthentInfo;
  149. WCHAR NwpServerBuffer[MAX_PATH + 1];
  150. WCHAR NwpNdsServerBuffer[MAX_PATH + 1];
  151. WCHAR NwpUserNameBuffer[NW_MAX_USERNAME_LEN + 1];
  152. WCHAR NwpPasswordBuffer[NW_MAX_PASSWORD_LEN + 1];
  153. DWORD NwpPrintOption = NW_PRINT_OPTION_DEFAULT;
  154. DWORD NwpLogonScriptOptions = NW_LOGONSCRIPT_DEFAULT ;
  155. BOOL cPasswordDlgClickOK = 0;
  156. BOOL ServiceLogin = FALSE ;
  157. BOOL NoLoginScript = FALSE ;
  158. DBG_UNREFERENCED_PARAMETER(lpPreviousAuthentInfoType);
  159. DBG_UNREFERENCED_PARAMETER(lpPreviousAuthentInfo);
  160. #if DBG
  161. IF_DEBUG(LOGON) {
  162. KdPrint(("\nNWPROVAU: NPLogonNotify\n"));
  163. }
  164. #endif
  165. RpcTryExcept {
  166. if (_wcsicmp(lpAuthentInfoType, L"MSV1_0:Interactive") != 0)
  167. {
  168. //
  169. // We only handle a logon where Microsoft is the primary
  170. // authenticator and it is an interactive logon via Winlogon.
  171. //
  172. status = WN_NOT_SUPPORTED;
  173. goto EndOfTry;
  174. }
  175. if (_wcsicmp(lpStationName, L"SvcCtl") == 0)
  176. {
  177. ServiceLogin = TRUE ;
  178. }
  179. //
  180. // Initialize credential variables
  181. //
  182. NwpServerBuffer[0] = NW_INVALID_SERVER_CHAR;
  183. NwpServerBuffer[1] = 0;
  184. NwpNdsServerBuffer[0] = NW_INVALID_SERVER_CHAR;
  185. NwpNdsServerBuffer[1] = 0;
  186. RtlZeroMemory(NwpPasswordBuffer, sizeof(NwpPasswordBuffer));
  187. if (NewLogonInfo->Password.Buffer != NULL) {
  188. //
  189. // check for max length to avoid overflowing.
  190. //
  191. if (NewLogonInfo->Password.Length >
  192. (sizeof(NwpPasswordBuffer) - sizeof(WCHAR))) {
  193. status = ERROR_INVALID_PARAMETER ;
  194. goto EndOfTry;
  195. }
  196. wcsncpy(
  197. NwpPasswordBuffer,
  198. NewLogonInfo->Password.Buffer,
  199. NewLogonInfo->Password.Length / sizeof(WCHAR)
  200. );
  201. }
  202. RtlZeroMemory(NwpUserNameBuffer, sizeof(NwpUserNameBuffer));
  203. if (NewLogonInfo->UserName.Buffer != NULL) {
  204. //
  205. // check for max length to avoid overflowing.
  206. //
  207. if (NewLogonInfo->UserName.Length >
  208. (sizeof(NwpUserNameBuffer) - sizeof(WCHAR))) {
  209. status = ERROR_INVALID_PARAMETER ;
  210. goto EndOfTry;
  211. }
  212. wcsncpy(
  213. NwpUserNameBuffer,
  214. NewLogonInfo->UserName.Buffer,
  215. NewLogonInfo->UserName.Length / sizeof(WCHAR)
  216. );
  217. }
  218. #if DBG
  219. IF_DEBUG(LOGON) {
  220. KdPrint(("\tMessageType : %lu\n", NewLogonInfo->MessageType));
  221. KdPrint(("\tLogonDomainName : %ws\n", NewLogonInfo->LogonDomainName.Buffer));
  222. KdPrint(("\tUserName : %ws\n", NwpUserNameBuffer));
  223. KdPrint(("\tPassword : %ws\n", NwpPasswordBuffer));
  224. }
  225. #endif
  226. //
  227. // if Interactive login, get user related info
  228. //
  229. if (!ServiceLogin)
  230. {
  231. //
  232. // Get the user SID so that the user Netware username and
  233. // preferred server is saved under a SID key rather than the
  234. // LogonDomain*UserName key. We do this by making ourselves
  235. // a logon process, and call the special MSV1.0 GetUserInfo
  236. // interface.
  237. //
  238. status = NwpGetUserSid(lpLogonId, &NewUserSid);
  239. if (status != NO_ERROR) {
  240. goto EndOfTry;
  241. }
  242. //
  243. // Initialize the registry:
  244. // 1) Delete the CurrentUser value if it exists (was not clean up
  245. // previously because user did not log off--rebooted machine).
  246. // 2) Read the current user's PreferredServer and PrintOption
  247. // value so that we can display the user's original
  248. // preferred server.
  249. //
  250. NwpInitializeRegistry( NewUserSid,
  251. NwpServerBuffer,
  252. sizeof( NwpServerBuffer ) /
  253. sizeof( NwpServerBuffer[0]),
  254. NwpNdsServerBuffer,
  255. sizeof( NwpNdsServerBuffer ) /
  256. sizeof( NwpNdsServerBuffer[0]),
  257. &NwpLogonScriptOptions,
  258. &NwpPrintOption );
  259. }
  260. //
  261. // Poll until the NetWare workstation has started, then validate
  262. // the user credential.
  263. //
  264. if ( !NwpPollWorkstationStart() )
  265. {
  266. status = WN_NO_NETWORK;
  267. KdPrint(("NWPROVAU: The Workstation Service is not running, give up\n", status));
  268. goto EndOfTry;
  269. }
  270. //
  271. // If service login, notify the redir with the username/passwd/
  272. // LUID triplet and save the logon ID in the registry so that
  273. // workstation can pick up if stopped and restarted.
  274. //
  275. if (ServiceLogin)
  276. {
  277. NwpSaveServiceCredential(
  278. lpLogonId,
  279. NwpUserNameBuffer,
  280. NwpPasswordBuffer
  281. );
  282. (void) NwrLogonUser(
  283. NULL,
  284. lpLogonId,
  285. NwpUserNameBuffer,
  286. NwpPasswordBuffer,
  287. NULL,
  288. NULL,
  289. NULL,
  290. 0,
  291. NW_PRINT_OPTION_DEFAULT //Terminal Server addition
  292. );
  293. } else {
  294. //
  295. // We need to save the user credentials at least once so that
  296. // the CURRENTUSER Value is stored in the registry.
  297. // This must be done before any RPC calls but after polling
  298. // workstation start.
  299. //
  300. NwpSaveLogonCredential(
  301. NewUserSid,
  302. lpLogonId,
  303. NwpUserNameBuffer,
  304. NwpPasswordBuffer,
  305. NULL // Don't save the preferred server
  306. );
  307. if (*NwpServerBuffer != NW_INVALID_SERVER_CHAR ) {
  308. //
  309. // Preferred server exists. So, try to log the user on.
  310. //
  311. INT nResult;
  312. while (1)
  313. {
  314. WCHAR *DefaultTree = NULL ;
  315. WCHAR *DefaultContext = NULL;
  316. WCHAR *PreferredServer = NULL;
  317. PROMPTDLGPARAM PasswdPromptParam;
  318. #if DBG
  319. IF_DEBUG(LOGON) {
  320. KdPrint(("\tNwrLogonUser\n"));
  321. KdPrint(("\tUserName : %ws\n", NwpUserNameBuffer));
  322. KdPrint(("\tServer : %ws\n", NwpServerBuffer));
  323. }
  324. #endif
  325. //
  326. // make sure user is logged off
  327. //
  328. (void) NwrLogoffUser(NULL, lpLogonId) ;
  329. status = NwrLogonUser(
  330. NULL,
  331. lpLogonId,
  332. NwpUserNameBuffer,
  333. NwpPasswordBuffer,
  334. NwpServerBuffer, // now either TREE or SERVER
  335. NwpNdsServerBuffer, // Preferred Nds server if one exists
  336. NULL,
  337. 0,
  338. NwpPrintOption //***Terminal Server Added parameter
  339. );
  340. //
  341. // tommye
  342. //
  343. // If the error is NO_SUCH_USER, see if the user name has any
  344. // periods in it - if so, then we need to escape them (\.) and
  345. // try the login again.
  346. //
  347. if (status == ERROR_NO_SUCH_USER) {
  348. WCHAR EscapedName[NW_MAX_USERNAME_LEN * 2];
  349. PWSTR pChar = NwpUserNameBuffer;
  350. int i = 0;
  351. BOOL bEscaped = FALSE;
  352. RtlZeroMemory(EscapedName, sizeof(EscapedName));
  353. do {
  354. if (*pChar == L'.') {
  355. EscapedName[i++] = '\\';
  356. bEscaped = TRUE;
  357. }
  358. EscapedName[i++] = *pChar;
  359. } while (*pChar++);
  360. // Try the login again
  361. if (bEscaped) {
  362. status = NwrLogonUser(
  363. NULL,
  364. lpLogonId,
  365. EscapedName,
  366. NwpPasswordBuffer,
  367. NwpServerBuffer, // now either TREE or SERVER
  368. NwpNdsServerBuffer, // Preferred Nds server if one exists
  369. NULL,
  370. 0,
  371. NwpPrintOption //***Terminal Server Added parameter
  372. );
  373. if (status != ERROR_NO_SUCH_USER) { // if we matched a username, copy that name into buffer
  374. //
  375. // check for max length to avoid overflowing.
  376. //
  377. if (i < (sizeof(NwpUserNameBuffer))) {
  378. wcsncpy(
  379. NwpUserNameBuffer,
  380. EscapedName,
  381. i
  382. );
  383. }
  384. }
  385. }
  386. }
  387. if (status != ERROR_INVALID_PASSWORD)
  388. break ;
  389. PasswdPromptParam.UserName = NwpUserNameBuffer;
  390. PasswdPromptParam.ServerName = NwpServerBuffer ;
  391. PasswdPromptParam.Password = NwpPasswordBuffer;
  392. PasswdPromptParam.PasswordSize = sizeof(NwpPasswordBuffer)/
  393. sizeof(NwpPasswordBuffer[0]) ;
  394. Result = DialogBoxParamW(
  395. hmodNW,
  396. MAKEINTRESOURCEW(DLG_PASSWORD_PROMPT),
  397. (HWND) StationHandle,
  398. (DLGPROC) NwpPasswdPromptDlgProc,
  399. (LPARAM) &PasswdPromptParam
  400. );
  401. if (Result == -1 || Result == IDCANCEL)
  402. {
  403. status = ERROR_INVALID_PASSWORD ;
  404. break ;
  405. }
  406. else
  407. {
  408. cPasswordDlgClickOK++;
  409. }
  410. }
  411. if (status == NW_PASSWORD_HAS_EXPIRED)
  412. {
  413. WCHAR szNumber[16] ;
  414. DWORD status1, dwMsgId, dwGraceLogins = 0 ;
  415. LPWSTR apszInsertStrings[3] ;
  416. //
  417. // get the grace login count
  418. //
  419. status1 = NwGetGraceLoginCount(
  420. NwpServerBuffer,
  421. NwpUserNameBuffer,
  422. &dwGraceLogins) ;
  423. //
  424. // if hit error, just dont use the number
  425. //
  426. if (status1 == NO_ERROR)
  427. {
  428. //
  429. // tommye - MCS bug 251 - changed from SETPASS
  430. // message (IDS_PASSWORD_EXPIRED) to
  431. // Ctrl+Alt+Del message.
  432. //
  433. dwMsgId = IDS_PASSWORD_HAS_EXPIRED0; // use setpass.exe
  434. wsprintfW(szNumber, L"%ld", dwGraceLogins) ;
  435. }
  436. else
  437. {
  438. //
  439. // tommye - MCS bug 251 - changed from SETPASS
  440. // message (IDS_PASSWORD_EXPIRED1) to
  441. // Ctrl+Alt+Del message.
  442. //
  443. dwMsgId = IDS_PASSWORD_HAS_EXPIRED2 ; // use setpass.exe
  444. }
  445. apszInsertStrings[0] = NwpServerBuffer ;
  446. apszInsertStrings[1] = szNumber ;
  447. apszInsertStrings[2] = NULL ;
  448. //
  449. // put up message on password expiry
  450. //
  451. (void) NwpMessageBoxIns(
  452. (HWND) StationHandle,
  453. IDS_NETWARE_TITLE,
  454. dwMsgId,
  455. apszInsertStrings,
  456. MB_OK | MB_SETFOREGROUND |
  457. MB_ICONINFORMATION );
  458. status = NO_ERROR ;
  459. }
  460. if ( status != NO_ERROR )
  461. {
  462. WCHAR *pszErrorLocation = NwpServerBuffer ;
  463. DWORD dwMsgId = IDS_LOGIN_FAILURE_WARNING;
  464. if (status == ERROR_ACCOUNT_RESTRICTION)
  465. {
  466. dwMsgId = IDS_LOGIN_ACC_RESTRICTION;
  467. }
  468. if (status == ERROR_SHARING_PAUSED)
  469. {
  470. status = IDS_LOGIN_DISABLED;
  471. }
  472. if (*NwpServerBuffer == L'*')
  473. {
  474. //
  475. // Format into nicer string for user
  476. //
  477. WCHAR *pszTmp = LocalAlloc(LMEM_ZEROINIT,
  478. (wcslen(NwpServerBuffer)+2) *
  479. sizeof(WCHAR)) ;
  480. if (pszTmp)
  481. {
  482. pszErrorLocation = pszTmp ;
  483. //
  484. // This code formats the NDS
  485. // tree UNC to: Tree(Context)
  486. //
  487. wcscpy(pszErrorLocation, NwpServerBuffer+1) ;
  488. if (pszTmp = wcschr(pszErrorLocation, L'\\'))
  489. {
  490. *pszTmp = L'(' ;
  491. wcscat(pszErrorLocation, L")") ;
  492. }
  493. }
  494. }
  495. nResult = NwpMessageBoxError(
  496. (HWND) StationHandle,
  497. IDS_AUTH_FAILURE_TITLE,
  498. dwMsgId,
  499. status,
  500. pszErrorLocation,
  501. MB_YESNO | MB_ICONEXCLAMATION );
  502. if (pszErrorLocation != NwpServerBuffer)
  503. {
  504. (void) LocalFree(pszErrorLocation) ;
  505. }
  506. //
  507. // User chose not to select another preferred server,
  508. // hence just return success.
  509. //
  510. if ( nResult == IDNO ) {
  511. status = NO_ERROR;
  512. NoLoginScript = TRUE;
  513. }
  514. }
  515. //
  516. // The user might have changed the password in the password
  517. // prompt dialog. Hence, we need to save the credentials
  518. // ( the password ) again. Although the user might choose
  519. // to select another server, he might canceled out of the
  520. // login dialog. We must save logon credentials here no matter
  521. // what.
  522. //
  523. NwpSaveLogonCredential(
  524. NewUserSid,
  525. lpLogonId,
  526. NwpUserNameBuffer,
  527. NwpPasswordBuffer,
  528. NwpServerBuffer
  529. );
  530. }
  531. //
  532. // Only prompt user with the NetWare login dialog if
  533. // no preferred server was found or an error occurred
  534. // while authenticating the user.
  535. //
  536. if ( ( status != NO_ERROR)
  537. || (*NwpServerBuffer == NW_INVALID_SERVER_CHAR)
  538. )
  539. {
  540. LOGINDLGPARAM LoginParam;
  541. if ( cPasswordDlgClickOK > 0 )
  542. {
  543. // Password might have changed in the password prompt
  544. // dialog. We want to always first use the NT password
  545. // when validating a user on a server. Hence,
  546. // we need to copy back the original NT password into
  547. // NwpPasswordBuffer.
  548. RtlZeroMemory(NwpPasswordBuffer, sizeof(NwpPasswordBuffer));
  549. if (NewLogonInfo->Password.Buffer != NULL)
  550. {
  551. wcsncpy(
  552. NwpPasswordBuffer,
  553. NewLogonInfo->Password.Buffer,
  554. NewLogonInfo->Password.Length / sizeof(WCHAR)
  555. );
  556. }
  557. }
  558. LoginParam.UserName = NwpUserNameBuffer;
  559. LoginParam.ServerName = NwpServerBuffer ;
  560. LoginParam.Password = NwpPasswordBuffer;
  561. LoginParam.NewUserSid = NewUserSid;
  562. LoginParam.pLogonId = lpLogonId;
  563. LoginParam.ServerNameSize = sizeof( NwpServerBuffer ) /
  564. sizeof( NwpServerBuffer[0]);
  565. LoginParam.PasswordSize = sizeof( NwpPasswordBuffer ) /
  566. sizeof( NwpPasswordBuffer[0]);
  567. LoginParam.LogonScriptOptions = NwpLogonScriptOptions;
  568. LoginParam.PrintOption = NwpPrintOption;
  569. Result = DialogBoxParamW(
  570. hmodNW,
  571. MAKEINTRESOURCEW(DLG_NETWARE_LOGIN),
  572. (HWND) StationHandle,
  573. (DLGPROC) NwpLoginDlgProc,
  574. (LPARAM) &LoginParam
  575. );
  576. if (Result == -1) {
  577. status = GetLastError();
  578. KdPrint(("NWPROVAU: DialogBox failed %lu\n", status));
  579. goto EndOfTry;
  580. }
  581. }
  582. }
  583. EndOfTry: ;
  584. }
  585. RpcExcept(1) {
  586. #if DBG
  587. DWORD XceptCode;
  588. XceptCode = RpcExceptionCode();
  589. IF_DEBUG(LOGON) {
  590. KdPrint(("NWPROVAU: NPLogonNotify: Exception code is x%08lx\n", XceptCode));
  591. }
  592. status = NwpMapRpcError(XceptCode);
  593. #else
  594. status = NwpMapRpcError(RpcExceptionCode());
  595. #endif
  596. }
  597. RpcEndExcept;
  598. if (!ServiceLogin && !NoLoginScript) {
  599. DWORD fPServer = 0;
  600. NwpReadLogonScriptOptions( NewUserSid,
  601. &NwpLogonScriptOptions,
  602. &fPServer );
  603. if ( fPServer && ( NwpLogonScriptOptions & NW_LOGONSCRIPT_ENABLED ) )
  604. {
  605. *lpLogonScript = NwpConstructLogonScript( NwpLogonScriptOptions );
  606. //
  607. // set scripts to run synchronously. ignore error if we cant.
  608. // not a disaster.
  609. //
  610. (void) NwrSetLogonScript(NULL, SYNC_LOGONSCRIPT) ;
  611. }
  612. else
  613. {
  614. *lpLogonScript = LocalAlloc(LMEM_ZEROINIT, sizeof(WCHAR));
  615. }
  616. }
  617. else
  618. *lpLogonScript = NULL;
  619. if (NewUserSid != NULL) {
  620. (void) LocalFree((HLOCAL) NewUserSid);
  621. }
  622. //
  623. // Clear the password
  624. //
  625. RtlZeroMemory(NwpPasswordBuffer, sizeof(NwpPasswordBuffer));
  626. if (status == WN_NO_NETWORK) {
  627. //
  628. // We don't care if the workstation has not started because
  629. // we tuck the logon credential in the registry to be picked
  630. // up by the workstation when it starts up. If we return
  631. // ERROR_NO_NETWORK, MPR will poll us forever, causing us
  632. // to continuously display the login dialog over and over
  633. // again.
  634. //
  635. status = NO_ERROR;
  636. }
  637. if (status != NO_ERROR) {
  638. SetLastError(status);
  639. }
  640. return status;
  641. }
  642. DWORD
  643. APIENTRY
  644. NPPasswordChangeNotify(
  645. LPCWSTR lpAuthentInfoType,
  646. LPVOID lpAuthentInfo,
  647. LPCWSTR lpPreviousAuthentInfoType,
  648. LPVOID lpPreviousAuthentInfo,
  649. LPWSTR lpStationName,
  650. LPVOID StationHandle,
  651. DWORD dwChangeInfo
  652. )
  653. /*++
  654. Routine Description:
  655. This function is called after the interactive user has selected to
  656. change the password for the local logon via the Ctrl-Alt-Del dialog.
  657. It is also called when the user cannot login because the password
  658. has expired and must be changed.
  659. Arguments:
  660. lpAuthentInfoType - Supplies a string which if is
  661. L"MSV1_0:Interactive" means that the user has been logged
  662. on by the Microsoft primary authenticator.
  663. lpAuthentInfo - Supplies a pointer to the credentials to
  664. change to.
  665. lpPreviousAuthentInfoType - Supplies a pointer to the old
  666. credentials.
  667. lpPreviousAuthentInfo - Ignored.
  668. lpStationName - Supplies a string which if it is L"WinSta_0"
  669. means that Winlogon logged on the user.
  670. StationHandle - Supplies the handle to the window which to display
  671. our specific dialog.
  672. dwChangeInfo - Ignored.
  673. Return Value:
  674. WN_SUCCESS - successful operation.
  675. WN_NOT_SUPPORTED - Only support change password if MS v1.0 is
  676. the primary authenticator and is done through Winlogon.
  677. WN_NO_NETWORK - Workstation service did not start.
  678. --*/
  679. {
  680. DWORD status = NO_ERROR;
  681. CHANGE_PW_DLG_PARAM Credential;
  682. LPBYTE lpBuffer = NULL;
  683. PMSV1_0_INTERACTIVE_LOGON NewCredential =
  684. (PMSV1_0_INTERACTIVE_LOGON) lpAuthentInfo;
  685. PMSV1_0_INTERACTIVE_LOGON OldCredential =
  686. (PMSV1_0_INTERACTIVE_LOGON) lpPreviousAuthentInfo;
  687. DBG_UNREFERENCED_PARAMETER(lpPreviousAuthentInfoType);
  688. DBG_UNREFERENCED_PARAMETER(dwChangeInfo);
  689. RtlZeroMemory(&Credential, sizeof(CHANGE_PW_DLG_PARAM));
  690. RpcTryExcept {
  691. if ((_wcsicmp(lpAuthentInfoType, L"MSV1_0:Interactive") != 0) ||
  692. (_wcsicmp(lpStationName, L"WinSta0") != 0)) {
  693. //
  694. // We only handle a logon where Microsoft is the primary
  695. // authenticator and it is an interactive logon via Winlogon.
  696. //
  697. status = WN_NOT_SUPPORTED;
  698. goto EndOfTry;
  699. }
  700. if (NewCredential == NULL || OldCredential == NULL) {
  701. //
  702. // Credentials not given to us by Winlogon or
  703. // user did not type the old and new passwords.
  704. //
  705. #if DBG
  706. IF_DEBUG(LOGON) {
  707. KdPrint(("NWPROVAU: PasswordChangeNotify got NULL for new and old credential pointers\n"));
  708. }
  709. #endif
  710. (void) NwpMessageBoxError(
  711. (HWND) StationHandle,
  712. IDS_CHANGE_PASSWORD_TITLE,
  713. IDS_BAD_PASSWORDS,
  714. 0,
  715. NULL,
  716. MB_OK | MB_ICONSTOP
  717. );
  718. status = WN_NOT_SUPPORTED;
  719. goto EndOfTry;
  720. }
  721. lpBuffer = LocalAlloc( LMEM_ZEROINIT,
  722. ( NW_MAX_USERNAME_LEN + 3 +
  723. ( 2 * NW_MAX_PASSWORD_LEN ) ) *
  724. sizeof(WCHAR) );
  725. if (lpBuffer == NULL) {
  726. status = ERROR_NOT_ENOUGH_MEMORY;
  727. goto EndOfTry;
  728. }
  729. Credential.UserName = (LPWSTR) lpBuffer;
  730. lpBuffer += (NW_MAX_USERNAME_LEN + 1) * sizeof(WCHAR);
  731. Credential.OldPassword = (LPWSTR) lpBuffer;
  732. lpBuffer += (NW_MAX_PASSWORD_LEN + 1) * sizeof(WCHAR);
  733. Credential.NewPassword = (LPWSTR) lpBuffer;
  734. if (NewCredential->UserName.Length == 0) {
  735. //
  736. // UserName is not specified. Try to get interactive user's name.
  737. //
  738. DWORD CharNeeded = NW_MAX_USERNAME_LEN + 1;
  739. #if DBG
  740. IF_DEBUG(LOGON) {
  741. KdPrint(("NWPROVAU: PasswordChangeNotify got empty string for username\n"));
  742. }
  743. #endif
  744. if (! GetUserNameW(Credential.UserName, &CharNeeded)) {
  745. //
  746. // Could not get interactive user's name. Give up.
  747. //
  748. (void) NwpMessageBoxError(
  749. (HWND) StationHandle,
  750. IDS_CHANGE_PASSWORD_TITLE,
  751. 0,
  752. ERROR_BAD_USERNAME,
  753. NULL,
  754. MB_OK | MB_ICONSTOP
  755. );
  756. }
  757. }
  758. else {
  759. wcsncpy(
  760. Credential.UserName,
  761. NewCredential->UserName.Buffer,
  762. NewCredential->UserName.Length / sizeof(WCHAR)
  763. );
  764. }
  765. if (OldCredential->Password.Length > 0)
  766. {
  767. wcsncpy(
  768. Credential.OldPassword,
  769. OldCredential->Password.Buffer,
  770. OldCredential->Password.Length / sizeof(WCHAR)
  771. );
  772. }
  773. else
  774. {
  775. Credential.OldPassword[0] = 0;
  776. }
  777. if (NewCredential->Password.Length > 0)
  778. {
  779. wcsncpy(
  780. Credential.NewPassword,
  781. NewCredential->Password.Buffer,
  782. NewCredential->Password.Length / sizeof(WCHAR)
  783. );
  784. }
  785. else
  786. {
  787. Credential.NewPassword[0] = 0;
  788. }
  789. //
  790. // Encode the passwords.
  791. //
  792. {
  793. UCHAR EncodeSeed = NW_ENCODE_SEED2;
  794. UNICODE_STRING PasswordStr;
  795. RtlInitUnicodeString(&PasswordStr, Credential.OldPassword);
  796. RtlRunEncodeUnicodeString(&EncodeSeed, &PasswordStr);
  797. RtlInitUnicodeString(&PasswordStr, Credential.NewPassword);
  798. RtlRunEncodeUnicodeString(&EncodeSeed, &PasswordStr);
  799. }
  800. NwpSelectServers(StationHandle, &Credential);
  801. EndOfTry: ;
  802. }
  803. RpcExcept(1) {
  804. #if DBG
  805. DWORD XceptCode;
  806. XceptCode = RpcExceptionCode();
  807. IF_DEBUG(LOGON) {
  808. KdPrint(("NWPROVAU: NPPasswordChangeNotify: Exception code is x%08lx\n", XceptCode));
  809. }
  810. status = NwpMapRpcError(XceptCode);
  811. #else
  812. status = NwpMapRpcError(RpcExceptionCode());
  813. #endif
  814. }
  815. RpcEndExcept;
  816. if (lpBuffer != NULL) {
  817. LocalFree(lpBuffer);
  818. }
  819. if (status != NO_ERROR) {
  820. SetLastError(status);
  821. }
  822. return status;
  823. }
  824. VOID
  825. NwpInitializeRegistry(
  826. IN LPWSTR NewUserSid,
  827. OUT LPWSTR PreferredServer,
  828. IN DWORD PreferredServerSize,
  829. OUT LPWSTR NdsPreferredServer,
  830. IN DWORD NdsPreferredServerSize,
  831. OUT PDWORD pLogonScriptOptions,
  832. OUT PDWORD PrintOption
  833. )
  834. /*++
  835. Routine Description:
  836. This routine initializes the registry before putting up the
  837. logon dialog.
  838. 1) Deletes the CurrentUser value if it was not cleaned up from
  839. the last logoff.
  840. 2) Reads the current user's original PreferredServer value
  841. 3) Reads the current user's PrintOption value
  842. Arguments:
  843. NewUserSid - Supplies the newly logged on user's SID in string format
  844. which is the key name to find the password and preferred server.
  845. Return Value:
  846. None.
  847. --*/
  848. {
  849. LONG RegError;
  850. HKEY WkstaKey;
  851. //NwDeleteCurrentUser(); //Commented out for Multi-user code merge
  852. //
  853. // Open HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services
  854. // \NWCWorkstation\Parameters\Option
  855. //
  856. RegError = RegOpenKeyExW(
  857. HKEY_LOCAL_MACHINE,
  858. NW_WORKSTATION_OPTION_REGKEY,
  859. REG_OPTION_NON_VOLATILE,
  860. KEY_READ,
  861. &WkstaKey
  862. );
  863. if (RegError != NO_ERROR) {
  864. KdPrint(("NWPROVAU: NwpInitializeRegistry open NWCWorkstation\\Parameters\\Option key unexpected error %lu!\n", RegError));
  865. return;
  866. }
  867. //
  868. // Get user's preferred server information.
  869. //
  870. (void) NwpReadRegInfo(WkstaKey,
  871. NewUserSid,
  872. PreferredServer,
  873. PreferredServerSize,
  874. NdsPreferredServer,
  875. NdsPreferredServerSize,
  876. PrintOption
  877. );
  878. (void) RegCloseKey(WkstaKey);
  879. (void) NwpReadLogonScriptOptions( NewUserSid, pLogonScriptOptions, NULL );
  880. }
  881. DWORD
  882. NwpReadRegInfo(
  883. IN HKEY WkstaKey,
  884. IN LPWSTR CurrentUserSid,
  885. OUT LPWSTR PreferredServer,
  886. IN DWORD PreferredServerSize,
  887. OUT LPWSTR NdsPreferredServer,
  888. IN DWORD NdsPreferredServerSize,
  889. OUT PDWORD PrintOption
  890. )
  891. /*++
  892. Routine Description:
  893. This routine reads the user's preferred server and print option
  894. from the registry.
  895. Arguments:
  896. WkstaKey - Supplies the handle to the parameters key under the NetWare
  897. workstation service key.
  898. CurrentUserSid - Supplies the SID string of the user whose information
  899. to read.
  900. PreferredServer - Receives the user's preferred server.
  901. PrintOption - Receives the user's print option.
  902. Return Value:
  903. None.
  904. --*/
  905. {
  906. LONG RegError;
  907. HKEY UserKey;
  908. DWORD ValueType;
  909. DWORD BytesNeeded;
  910. //
  911. // Open current user's key to read the original preferred server.
  912. //
  913. RegError = RegOpenKeyExW(
  914. WkstaKey,
  915. CurrentUserSid,
  916. REG_OPTION_NON_VOLATILE,
  917. KEY_READ,
  918. &UserKey
  919. );
  920. if (RegError != NO_ERROR) {
  921. if ( (RegError == ERROR_FILE_NOT_FOUND) ||
  922. (RegError == ERROR_PATH_NOT_FOUND) ) {
  923. //
  924. // If key doesnt exist assume first time. Use default
  925. // if present.
  926. //
  927. LONG RegError1 ;
  928. HKEY WkstaParamKey ;
  929. DWORD Disposition, dwScriptOptions,
  930. dwScriptOptionsSize = sizeof(dwScriptOptions);
  931. //
  932. // Open HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services
  933. // \NWCWorkstation\Parameters
  934. //
  935. RegError1 = RegOpenKeyExW(
  936. HKEY_LOCAL_MACHINE,
  937. NW_WORKSTATION_REGKEY,
  938. REG_OPTION_NON_VOLATILE,
  939. KEY_READ,
  940. &WkstaParamKey
  941. );
  942. if (RegError1 != NO_ERROR) {
  943. return (DWORD) RegError; // return original error
  944. }
  945. BytesNeeded = PreferredServerSize;
  946. RegError1 = RegQueryValueExW(
  947. WkstaParamKey,
  948. NW_DEFAULTSERVER_VALUENAME,
  949. NULL,
  950. &ValueType,
  951. (LPBYTE) PreferredServer,
  952. &BytesNeeded
  953. );
  954. if (RegError1 != NO_ERROR) {
  955. (void) RegCloseKey(WkstaParamKey);
  956. PreferredServer[0] = NW_INVALID_SERVER_CHAR;
  957. PreferredServer[1] = 0;
  958. return (DWORD) RegError; // return original error
  959. }
  960. RegError1 = RegQueryValueExW(
  961. WkstaParamKey,
  962. NW_DEFAULTSCRIPTOPTIONS_VALUENAME,
  963. NULL,
  964. &ValueType,
  965. (LPBYTE) &dwScriptOptions,
  966. &dwScriptOptionsSize
  967. );
  968. (void) RegCloseKey(WkstaParamKey);
  969. if (RegError1 != NO_ERROR) {
  970. dwScriptOptions = NW_LOGONSCRIPT_ENABLED |
  971. NW_LOGONSCRIPT_4X_ENABLED ;
  972. }
  973. //
  974. // We have a default. now write out the info for the current
  975. // user now. Note we also write out the login script option.
  976. // Errors here are not reported.
  977. //
  978. //
  979. // Create the key under NWCWorkstation\Parameters\Option\<usersid>
  980. //
  981. RegError = RegCreateKeyExW(
  982. WkstaKey,
  983. CurrentUserSid,
  984. 0,
  985. WIN31_CLASS,
  986. REG_OPTION_NON_VOLATILE,
  987. KEY_WRITE | WRITE_DAC,
  988. NULL, // security attr
  989. &UserKey,
  990. &Disposition
  991. );
  992. if (RegError == NO_ERROR) {
  993. RegError = NwLibSetEverybodyPermission( UserKey,
  994. KEY_SET_VALUE );
  995. if ( RegError == NO_ERROR )
  996. {
  997. //
  998. // Write the PreferredServer. Errors ignored.
  999. //
  1000. RegError = RegSetValueExW(
  1001. UserKey,
  1002. NW_SERVER_VALUENAME,
  1003. 0,
  1004. REG_SZ,
  1005. (LPVOID) PreferredServer,
  1006. (wcslen(PreferredServer) + 1) * sizeof(WCHAR)
  1007. );
  1008. (void) RegCloseKey(UserKey) ;
  1009. (void) NwpSaveLogonScriptOptions(
  1010. CurrentUserSid,
  1011. dwScriptOptions
  1012. ) ;
  1013. }
  1014. else {
  1015. (void) RegCloseKey(UserKey) ;
  1016. }
  1017. }
  1018. *PrintOption = NW_PRINT_OPTION_DEFAULT;
  1019. return NO_ERROR;
  1020. }
  1021. return (DWORD) RegError;
  1022. }
  1023. //
  1024. // Read PreferredServer value
  1025. //
  1026. BytesNeeded = PreferredServerSize;
  1027. RegError = RegQueryValueExW(
  1028. UserKey,
  1029. NW_SERVER_VALUENAME,
  1030. NULL,
  1031. &ValueType,
  1032. (LPBYTE) PreferredServer,
  1033. &BytesNeeded
  1034. );
  1035. ASSERT(BytesNeeded <= PreferredServerSize);
  1036. if (RegError != NO_ERROR) {
  1037. #if DBG
  1038. IF_DEBUG(LOGON) {
  1039. KdPrint(("NWPROVAU: Attempt to read original preferred server failed %lu\n",
  1040. RegError));
  1041. }
  1042. #endif
  1043. PreferredServer[0] = NW_INVALID_SERVER_CHAR; // Display login dialog
  1044. PreferredServer[1] = 0;
  1045. goto CleanExit;
  1046. }
  1047. //
  1048. // Read NdsPreferredServer value
  1049. //
  1050. BytesNeeded = NdsPreferredServerSize;
  1051. RegError = RegQueryValueExW(
  1052. UserKey,
  1053. NW_NDS_SERVER_VALUENAME,
  1054. NULL,
  1055. &ValueType,
  1056. (LPBYTE) NdsPreferredServer,
  1057. &BytesNeeded
  1058. );
  1059. ASSERT(BytesNeeded <= NdsPreferredServerSize);
  1060. if (RegError != NO_ERROR) {
  1061. #if DBG
  1062. IF_DEBUG(LOGON) {
  1063. KdPrint(("NWPROVAU: Attempt to read NDS preferred server failed %lu\n",
  1064. RegError));
  1065. }
  1066. #endif
  1067. NdsPreferredServer[0] = 0;
  1068. NdsPreferredServer[1] = 0;
  1069. goto CleanExit;
  1070. }
  1071. CleanExit:
  1072. //
  1073. // Read PrintOption value into NwpPrintOption.
  1074. //
  1075. BytesNeeded = sizeof(PrintOption);
  1076. RegError = RegQueryValueExW(
  1077. UserKey,
  1078. NW_PRINTOPTION_VALUENAME,
  1079. NULL,
  1080. &ValueType,
  1081. (LPBYTE) PrintOption,
  1082. &BytesNeeded
  1083. );
  1084. if (RegError != NO_ERROR ) {
  1085. #if DBG
  1086. IF_DEBUG(LOGON) {
  1087. KdPrint(("NWPROVAU: Attempt to read original print option failed %lu\n", RegError));
  1088. }
  1089. #endif
  1090. *PrintOption = NW_PRINT_OPTION_DEFAULT;
  1091. }
  1092. (void) RegCloseKey(UserKey);
  1093. return NO_ERROR;
  1094. }
  1095. DWORD
  1096. NwpReadLogonScriptOptions(
  1097. IN LPWSTR CurrentUserSid,
  1098. OUT PDWORD pLogonScriptOptions,
  1099. OUT PDWORD pPreferredServerExists
  1100. )
  1101. /*++
  1102. Routine Description:
  1103. This routine reads the user's logon script options from the registry.
  1104. Arguments:
  1105. CurrentUserSid - Supplies the SID string of the user whose information
  1106. to read.
  1107. pLogonScriptOptions - Receives the user's script options
  1108. pPreferredServerExists - Prefered server specified
  1109. Return Value:
  1110. None.
  1111. --*/
  1112. {
  1113. LONG RegError;
  1114. HKEY UserKey;
  1115. DWORD ValueType;
  1116. DWORD BytesNeeded;
  1117. HKEY WkstaKey;
  1118. WCHAR PreferredServer[MAX_PATH + 1];
  1119. //
  1120. // initialize output values
  1121. //
  1122. *pLogonScriptOptions = NW_LOGONSCRIPT_DEFAULT;
  1123. if (pPreferredServerExists)
  1124. *pPreferredServerExists = 0 ;
  1125. //
  1126. // Open HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services
  1127. // \NWCWorkstation\Parameters\Option
  1128. //
  1129. RegError = RegOpenKeyExW(
  1130. HKEY_LOCAL_MACHINE,
  1131. NW_WORKSTATION_OPTION_REGKEY,
  1132. REG_OPTION_NON_VOLATILE,
  1133. KEY_READ,
  1134. &WkstaKey
  1135. );
  1136. if (RegError != NO_ERROR) {
  1137. KdPrint(("NWPROVAU: NwpReadLogonScriptOptions open NWCWorkstation\\Parameters\\Option key unexpected error %lu!\n", RegError));
  1138. return (DWORD) RegError;
  1139. }
  1140. //
  1141. // Open current user's key
  1142. //
  1143. RegError = RegOpenKeyExW(
  1144. WkstaKey,
  1145. CurrentUserSid,
  1146. REG_OPTION_NON_VOLATILE,
  1147. KEY_READ,
  1148. &UserKey
  1149. );
  1150. if (RegError != NO_ERROR) {
  1151. #if DBG
  1152. IF_DEBUG(LOGON) {
  1153. KdPrint(("NWPROVAU: Open of CurrentUser %ws existing key failed %lu\n",
  1154. CurrentUserSid, RegError));
  1155. }
  1156. #endif
  1157. (void) RegCloseKey(WkstaKey);
  1158. return (DWORD) RegError;
  1159. }
  1160. //
  1161. // Read LogonScriptOption value
  1162. //
  1163. BytesNeeded = sizeof(*pLogonScriptOptions);
  1164. RegError = RegQueryValueExW(
  1165. UserKey,
  1166. NW_LOGONSCRIPT_VALUENAME,
  1167. NULL,
  1168. &ValueType,
  1169. (LPBYTE) pLogonScriptOptions,
  1170. &BytesNeeded
  1171. );
  1172. if (RegError != NO_ERROR ) {
  1173. #if DBG
  1174. IF_DEBUG(LOGON) {
  1175. KdPrint(("NWPROVAU: Attempt to read original logon script option failed %lu\n", RegError));
  1176. }
  1177. #endif
  1178. // leave *pLogonScriptOptions as 0
  1179. }
  1180. if ( pPreferredServerExists != NULL ) {
  1181. //
  1182. // Read PreferredServer value
  1183. //
  1184. BytesNeeded = sizeof( PreferredServer );
  1185. RegError = RegQueryValueExW(
  1186. UserKey,
  1187. NW_SERVER_VALUENAME,
  1188. NULL,
  1189. &ValueType,
  1190. (LPBYTE) PreferredServer,
  1191. &BytesNeeded
  1192. );
  1193. ASSERT(BytesNeeded <= sizeof(PreferredServer));
  1194. if (RegError != NO_ERROR) {
  1195. #if DBG
  1196. IF_DEBUG(LOGON) {
  1197. KdPrint(("NWPROVAU: Attempt to read original preferred server failed %lu\n",
  1198. RegError));
  1199. }
  1200. #endif
  1201. *pPreferredServerExists = FALSE;
  1202. }
  1203. else {
  1204. if ( lstrcmp( PreferredServer, L"" ) )
  1205. *pPreferredServerExists = TRUE;
  1206. else
  1207. *pPreferredServerExists = FALSE;
  1208. }
  1209. }
  1210. (void) RegCloseKey(UserKey);
  1211. (void) RegCloseKey(WkstaKey);
  1212. return NO_ERROR;
  1213. }
  1214. LPWSTR
  1215. NwpConstructLogonScript(
  1216. IN DWORD LogonScriptOptions
  1217. )
  1218. /*++
  1219. Routine Description:
  1220. This routine constructs the multi-string for the logon script,
  1221. based on the options
  1222. Arguments:
  1223. LogonScriptOptions - Logon Script options
  1224. Return Value:
  1225. Allocated multi-string
  1226. --*/
  1227. {
  1228. LPWSTR pLogonScript;
  1229. DWORD BytesNeeded;
  1230. #define NW_NETWARE_SCRIPT_NAME L"nwscript.exe"
  1231. #define NW_NETWARE_DEBUG_NAME L"ntsd "
  1232. if ( !( LogonScriptOptions & NW_LOGONSCRIPT_ENABLED ) ) {
  1233. return NULL;
  1234. }
  1235. BytesNeeded = MAX_PATH * sizeof(WCHAR);
  1236. if (pLogonScript = LocalAlloc( LMEM_ZEROINIT, BytesNeeded))
  1237. {
  1238. DWORD dwSkipBytes = 0 ;
  1239. UINT retval ;
  1240. #if DBG
  1241. //
  1242. // if have exact match then start under NTSD.
  1243. //
  1244. if ( LogonScriptOptions == (NW_LOGONSCRIPT_ENABLED |
  1245. NW_LOGONSCRIPT_4X_ENABLED |
  1246. NW_LOGONSCRIPT_DEBUG) ) {
  1247. retval = GetSystemDirectory(pLogonScript,
  1248. BytesNeeded );
  1249. if (retval == 0) {
  1250. (void)LocalFree(pLogonScript) ;
  1251. return(NULL) ;
  1252. }
  1253. wcscat( pLogonScript, L"\\" );
  1254. wcscat( pLogonScript, NW_NETWARE_DEBUG_NAME );
  1255. dwSkipBytes = (retval * sizeof(WCHAR)) +
  1256. sizeof(NW_NETWARE_DEBUG_NAME) ;
  1257. BytesNeeded -= dwSkipBytes ;
  1258. }
  1259. #endif
  1260. retval = GetSystemDirectory(pLogonScript + (dwSkipBytes/sizeof(WCHAR)),
  1261. BytesNeeded );
  1262. if (retval == 0) {
  1263. (void)LocalFree(pLogonScript) ;
  1264. return(NULL) ;
  1265. }
  1266. wcscat( pLogonScript, L"\\" );
  1267. wcscat( pLogonScript, NW_NETWARE_SCRIPT_NAME );
  1268. }
  1269. return (pLogonScript);
  1270. }
  1271. DWORD
  1272. NwpSaveLogonScriptOptions(
  1273. IN LPWSTR CurrentUserSid,
  1274. IN DWORD LogonScriptOptions
  1275. )
  1276. /*++
  1277. Routine Description:
  1278. This routine saves the logon script options in the registry.
  1279. Arguments:
  1280. CurrentUserSid - Supplies the user's SID string
  1281. LogonScriptOptions - Logon script options
  1282. Return Value:
  1283. Error from registry
  1284. --*/
  1285. {
  1286. LONG RegError;
  1287. HKEY WkstaOptionKey;
  1288. HKEY CurrentUserOptionKey;
  1289. // Open HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services
  1290. // \NWCWorkstation\Parameters\Option
  1291. //
  1292. RegError = RegOpenKeyExW(
  1293. HKEY_LOCAL_MACHINE,
  1294. NW_WORKSTATION_OPTION_REGKEY,
  1295. REG_OPTION_NON_VOLATILE,
  1296. KEY_WRITE | KEY_CREATE_SUB_KEY | DELETE,
  1297. &WkstaOptionKey
  1298. );
  1299. if (RegError != NO_ERROR) {
  1300. KdPrint(("NWPROVAU: NwpSaveLogonScriptOptions open NWCWorkstation\\Parameters\\Option key unexpected error %lu!\n", RegError));
  1301. return RegError;
  1302. }
  1303. //
  1304. // Open the <NewUser> key under Option
  1305. //
  1306. RegError = RegOpenKeyExW(
  1307. WkstaOptionKey,
  1308. CurrentUserSid,
  1309. REG_OPTION_NON_VOLATILE,
  1310. KEY_WRITE,
  1311. &CurrentUserOptionKey
  1312. );
  1313. (void) RegCloseKey(WkstaOptionKey);
  1314. if (RegError != NO_ERROR) {
  1315. KdPrint(("NWPROVAU: NwpSaveLogonScriptOptions failed to save options %lu\n", RegError));
  1316. return RegError;
  1317. }
  1318. //
  1319. // Write the options
  1320. //
  1321. RegError = RegSetValueExW(
  1322. CurrentUserOptionKey,
  1323. NW_LOGONSCRIPT_VALUENAME,
  1324. 0,
  1325. REG_DWORD,
  1326. (LPVOID) &LogonScriptOptions,
  1327. sizeof(LogonScriptOptions)
  1328. );
  1329. (void) RegCloseKey(CurrentUserOptionKey);
  1330. if (RegError != NO_ERROR) {
  1331. KdPrint(("NWPROVAU: NwpSaveLogonScriptOptions failed to save options %lu\n", RegError));
  1332. }
  1333. return RegError;
  1334. }
  1335. VOID
  1336. NwpSaveLogonCredential(
  1337. IN LPWSTR NewUserSid,
  1338. IN PLUID LogonId,
  1339. IN LPWSTR UserName,
  1340. IN LPWSTR Password,
  1341. IN LPWSTR PreferredServer OPTIONAL
  1342. )
  1343. /*++
  1344. Routine Description:
  1345. This routine saves the user logon credential in the registry
  1346. and LSA's memory. This is normally called when NwrLogonUser is
  1347. successful.
  1348. Arguments:
  1349. NewUserSid - Supplies the newly logged on user's SID string to be
  1350. set as the CurrentUser value as well as the name of the key for
  1351. the user's preferred server.
  1352. LogonId - Supplies the user's logon ID. If NULL is specified,
  1353. just read the existing logon ID from the registry rather
  1354. than save a new one.
  1355. UserName - Supplies the name of the user.
  1356. Password - Supplies the password which the user wants to use on
  1357. the NetWare network.
  1358. PreferredServer - Supplies the name of the preferred server.
  1359. Return Value:
  1360. Error from redirector if login is rejected.
  1361. --*/
  1362. {
  1363. DWORD status;
  1364. LONG RegError;
  1365. HKEY WkstaOptionKey;
  1366. HKEY NewUserOptionKey;
  1367. #define SIZE_OF_LOGONID_TOKEN_INFORMATION sizeof( ULONG )
  1368. HKEY InteractiveLogonKey;
  1369. HKEY LogonIdKey;
  1370. DWORD Disposition;
  1371. WCHAR LogonIdKeyName[NW_MAX_LOGON_ID_LEN];
  1372. HANDLE TokenHandle;
  1373. UCHAR TokenInformation[ SIZE_OF_LOGONID_TOKEN_INFORMATION ];
  1374. ULONG ReturnLength;
  1375. ULONG WinStationId = 0L;
  1376. #if DBG
  1377. IF_DEBUG(LOGON) {
  1378. KdPrint(("NWPROVAU: NwpSaveLogonCredential: %ws, %ws, %ws, %ws\n",
  1379. NewUserSid, UserName, Password, PreferredServer));
  1380. }
  1381. #endif
  1382. // Open HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services
  1383. // \NWCWorkstation\Parameters\Option
  1384. //
  1385. RegError = RegOpenKeyExW(
  1386. HKEY_LOCAL_MACHINE,
  1387. NW_WORKSTATION_OPTION_REGKEY,
  1388. REG_OPTION_NON_VOLATILE,
  1389. KEY_WRITE | KEY_CREATE_SUB_KEY | DELETE,
  1390. &WkstaOptionKey
  1391. );
  1392. if (RegError != NO_ERROR) {
  1393. KdPrint(("NWPROVAU: NwpSaveLogonCredential open NWCWorkstation\\Parameters\\Option key unexpected error %lu!\n", RegError));
  1394. return;
  1395. }
  1396. //
  1397. // Open the <NewUser> key under Option
  1398. //
  1399. RegError = RegOpenKeyExW(
  1400. WkstaOptionKey,
  1401. NewUserSid,
  1402. REG_OPTION_NON_VOLATILE,
  1403. KEY_WRITE,
  1404. &NewUserOptionKey
  1405. );
  1406. if (RegError == ERROR_FILE_NOT_FOUND)
  1407. {
  1408. DWORD Disposition;
  1409. //
  1410. // Create <NewUser> key under NWCWorkstation\Parameters\Option
  1411. //
  1412. RegError = RegCreateKeyExW(
  1413. WkstaOptionKey,
  1414. NewUserSid,
  1415. 0,
  1416. WIN31_CLASS,
  1417. REG_OPTION_NON_VOLATILE,
  1418. KEY_WRITE | WRITE_DAC,
  1419. NULL, // security attr
  1420. &NewUserOptionKey,
  1421. &Disposition
  1422. );
  1423. if (RegError != NO_ERROR) {
  1424. KdPrint(("NWPROVAU: NwpSaveLogonCredential create Option\\%ws key unexpected error %lu!\n", NewUserSid, RegError));
  1425. (void) RegCloseKey(WkstaOptionKey);
  1426. return;
  1427. }
  1428. RegError = NwLibSetEverybodyPermission( NewUserOptionKey,
  1429. KEY_SET_VALUE );
  1430. if ( RegError != NO_ERROR )
  1431. {
  1432. KdPrint(("NWPROVAU: NwpSaveLogonCredential set security on Option\\%ws key unexpected error %lu!\n", NewUserSid, RegError));
  1433. (void) RegCloseKey(WkstaOptionKey);
  1434. return;
  1435. }
  1436. }
  1437. else if (RegError != NO_ERROR)
  1438. {
  1439. KdPrint(("NWPROVAU: NwpSaveLogonCredential open Option\\%ws unexpected error %lu!\n", NewUserSid, RegError));
  1440. (void) RegCloseKey(WkstaOptionKey);
  1441. return;
  1442. }
  1443. (void) RegCloseKey(WkstaOptionKey);
  1444. //
  1445. // Successfully opened or created an existing user entry.
  1446. // We will now save the credential in LSA.
  1447. //
  1448. status = NwpSetCredentialInLsa(
  1449. LogonId,
  1450. UserName,
  1451. Password
  1452. );
  1453. if (status != NO_ERROR) {
  1454. //
  1455. // Could not save new credential.
  1456. //
  1457. KdPrint(("NWPROVAU: NwpSaveLogonCredential failed to set credential %lu\n", status));
  1458. }
  1459. //
  1460. // If PreferredServer is not supplied, then that means we don't want to
  1461. // save the preferred server into the registry.
  1462. //
  1463. if (ARGUMENT_PRESENT(PreferredServer))
  1464. {
  1465. //
  1466. // Write the PreferredServer
  1467. //
  1468. RegError = RegSetValueExW(
  1469. NewUserOptionKey,
  1470. NW_SERVER_VALUENAME,
  1471. 0,
  1472. REG_SZ,
  1473. (LPVOID) PreferredServer,
  1474. (wcslen(PreferredServer) + 1) * sizeof(WCHAR)
  1475. );
  1476. if (RegError != NO_ERROR) {
  1477. KdPrint(("NWPROVAU: NwpSaveLogonCredential failed to save PreferredServer %ws %lu\n", PreferredServer, RegError));
  1478. }
  1479. }
  1480. (void) RegCloseKey(NewUserOptionKey);
  1481. //
  1482. // Write the logon ID to the registry.
  1483. // This replaces the single user CURRENTUSER stuff
  1484. //
  1485. // Open HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services
  1486. // \NWCWorkstation\Parameters\InteractiveLogon, create if does not exist
  1487. //
  1488. RegError = RegCreateKeyExW(
  1489. HKEY_LOCAL_MACHINE,
  1490. NW_INTERACTIVE_LOGON_REGKEY,
  1491. 0,
  1492. WIN31_CLASS,
  1493. REG_OPTION_NON_VOLATILE,
  1494. KEY_WRITE,
  1495. NULL, // security attr
  1496. &InteractiveLogonKey,
  1497. &Disposition
  1498. );
  1499. if (RegError != NO_ERROR) {
  1500. KdPrint(("NWPROVAU: NwpSaveLogonCredential open NWCWorkstation\\Parameters\\InteractiveLogon key unexpected error %lu!\n", RegError));
  1501. return;
  1502. }
  1503. NwLuidToWStr(LogonId, LogonIdKeyName);
  1504. //
  1505. // Create the logon ID key under ServiceLogon
  1506. //
  1507. RegError = RegCreateKeyExW(
  1508. InteractiveLogonKey,
  1509. LogonIdKeyName,
  1510. 0,
  1511. WIN31_CLASS,
  1512. REG_OPTION_NON_VOLATILE,
  1513. KEY_WRITE,
  1514. NULL, // security attr
  1515. &LogonIdKey,
  1516. &Disposition
  1517. );
  1518. if (RegError != NO_ERROR) {
  1519. KdPrint(("NWPROVAU: NwpSaveInteractiveCredential create NWCWorkstation\\Parameters\\InteractiveLogon\\<LogonId> key unexpected error %lu!\n", RegError));
  1520. RegCloseKey(InteractiveLogonKey);
  1521. return;
  1522. }
  1523. // We can use OpenProcessToken because this thread is a client
  1524. // I.E. It should be WinLogon
  1525. if ( !OpenProcessToken( GetCurrentProcess(),
  1526. TOKEN_READ,
  1527. &TokenHandle ))
  1528. {
  1529. KdPrint(("NWPROVAU: NwpSaveLogonCredential OpenThreadToken failed: Error %d\n", GetLastError()));
  1530. goto NoWinStation;
  1531. }
  1532. // notice that we've allocated enough space for the
  1533. // TokenInformation structure. so if we fail, we
  1534. // return a NULL pointer indicating failure
  1535. if ( !GetTokenInformation( TokenHandle,
  1536. TokenSessionId,
  1537. TokenInformation,
  1538. sizeof( TokenInformation ),
  1539. &ReturnLength ))
  1540. {
  1541. KdPrint(("NWPROVAU NwpSaveLogonCredential: GetTokenInformation failed: Error %d\n",
  1542. GetLastError()));
  1543. CloseHandle( TokenHandle );
  1544. goto NoWinStation;
  1545. }
  1546. WinStationId = *(PULONG)TokenInformation;
  1547. CloseHandle( TokenHandle );
  1548. NoWinStation:
  1549. //
  1550. // Write the WinStation ID to the registry.
  1551. //
  1552. RegError = RegSetValueExW(
  1553. LogonIdKey,
  1554. NW_WINSTATION_VALUENAME,
  1555. 0,
  1556. REG_BINARY,
  1557. (LPVOID) &WinStationId,
  1558. sizeof(WinStationId)
  1559. );
  1560. if (RegError != NO_ERROR) {
  1561. KdPrint(("NWPROVAU: NwpSaveLogonCredential failed to save Winstation ID %lu\n", RegError));
  1562. }
  1563. RegError = RegSetValueExW(
  1564. LogonIdKey,
  1565. NW_SID_VALUENAME,
  1566. 0,
  1567. REG_SZ,
  1568. (LPVOID) NewUserSid,
  1569. (wcslen(NewUserSid) + 1) * sizeof(WCHAR)
  1570. );
  1571. if (RegError != NO_ERROR) {
  1572. KdPrint(("NWPROVAU: NwpSaveLogonCredential failed to save NewUser %ws %lu\n", NewUserSid, RegError));
  1573. }
  1574. RegCloseKey(LogonIdKey);
  1575. RegCloseKey(InteractiveLogonKey);
  1576. }
  1577. VOID
  1578. NwpSaveLogonCredentialMultiUser(
  1579. IN LPWSTR NewUserSid,
  1580. IN PLUID LogonId,
  1581. IN LPWSTR UserName,
  1582. IN LPWSTR Password,
  1583. IN LPWSTR PreferredServer OPTIONAL
  1584. )
  1585. {
  1586. DWORD status;
  1587. LONG RegError;
  1588. HKEY WkstaOptionKey;
  1589. HKEY NewUserOptionKey;
  1590. #define SIZE_OF_LOGONID_TOKEN_INFORMATION sizeof( ULONG )
  1591. HKEY InteractiveLogonKey;
  1592. HKEY LogonIdKey;
  1593. DWORD Disposition;
  1594. WCHAR LogonIdKeyName[NW_MAX_LOGON_ID_LEN];
  1595. HANDLE TokenHandle;
  1596. UCHAR TokenInformation[ SIZE_OF_LOGONID_TOKEN_INFORMATION ];
  1597. ULONG ReturnLength;
  1598. ULONG WinStationId = 0L;
  1599. // Open HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services
  1600. // \NWCWorkstation\Parameters\Option
  1601. //
  1602. RegError = RegOpenKeyExW(
  1603. HKEY_LOCAL_MACHINE,
  1604. NW_WORKSTATION_OPTION_REGKEY,
  1605. REG_OPTION_NON_VOLATILE,
  1606. KEY_WRITE | KEY_CREATE_SUB_KEY | DELETE,
  1607. &WkstaOptionKey
  1608. );
  1609. if (RegError != NO_ERROR) {
  1610. KdPrint(("NWPROVAU: NwpSaveLogonCredential open NWCWorkstation\\Parameters\\Option key unexpected error %lu!\n", RegError));
  1611. return;
  1612. }
  1613. //
  1614. // Open the <NewUser> key under Option
  1615. //
  1616. RegError = RegOpenKeyExW(
  1617. WkstaOptionKey,
  1618. NewUserSid,
  1619. REG_OPTION_NON_VOLATILE,
  1620. KEY_WRITE,
  1621. &NewUserOptionKey
  1622. );
  1623. if (RegError == ERROR_FILE_NOT_FOUND)
  1624. {
  1625. DWORD Disposition;
  1626. //
  1627. // Create <NewUser> key under NWCWorkstation\Parameters\Option
  1628. //
  1629. RegError = RegCreateKeyExW(
  1630. WkstaOptionKey,
  1631. NewUserSid,
  1632. 0,
  1633. WIN31_CLASS,
  1634. REG_OPTION_NON_VOLATILE,
  1635. KEY_WRITE | WRITE_DAC,
  1636. NULL, // security attr
  1637. &NewUserOptionKey,
  1638. &Disposition
  1639. );
  1640. if (RegError != NO_ERROR) {
  1641. KdPrint(("NWPROVAU: NwpSaveLogonCredential create Option\\%ws key unexpected error %lu!\n", NewUserSid, RegError));
  1642. (void) RegCloseKey(WkstaOptionKey);
  1643. return;
  1644. }
  1645. RegError = NwLibSetEverybodyPermission( NewUserOptionKey,
  1646. KEY_SET_VALUE );
  1647. if ( RegError != NO_ERROR )
  1648. {
  1649. KdPrint(("NWPROVAU: NwpSaveLogonCredential set security on Option\\%ws key unexpected error %lu!\n", NewUserSid, RegError));
  1650. (void) RegCloseKey(WkstaOptionKey);
  1651. return;
  1652. }
  1653. }
  1654. else if (RegError != NO_ERROR)
  1655. {
  1656. KdPrint(("NWPROVAU: NwpSaveLogonCredential open Option\\%ws unexpected error %lu!\n", NewUserSid, RegError));
  1657. (void) RegCloseKey(WkstaOptionKey);
  1658. return;
  1659. }
  1660. (void) RegCloseKey(WkstaOptionKey);
  1661. //
  1662. // Successfully opened or created an existing user entry.
  1663. // We will now save the credential in LSA.
  1664. //
  1665. status = NwpSetCredentialInLsa(
  1666. LogonId,
  1667. UserName,
  1668. Password
  1669. );
  1670. if (status != NO_ERROR) {
  1671. //
  1672. // Could not save new credential.
  1673. //
  1674. KdPrint(("NWPROVAU: NwpSaveLogonCredential failed to set credential %lu\n", status));
  1675. }
  1676. //
  1677. // If PreferredServer is not supplied, then that means we don't want to
  1678. // save the preferred server into the registry.
  1679. //
  1680. if (ARGUMENT_PRESENT(PreferredServer))
  1681. {
  1682. //
  1683. // Write the PreferredServer
  1684. //
  1685. RegError = RegSetValueExW(
  1686. NewUserOptionKey,
  1687. NW_SERVER_VALUENAME,
  1688. 0,
  1689. REG_SZ,
  1690. (LPVOID) PreferredServer,
  1691. (wcslen(PreferredServer) + 1) * sizeof(WCHAR)
  1692. );
  1693. if (RegError != NO_ERROR) {
  1694. KdPrint(("NWPROVAU: NwpSaveLogonCredential failed to save PreferredServer %ws %lu\n", PreferredServer, RegError));
  1695. }
  1696. }
  1697. (void) RegCloseKey(NewUserOptionKey);
  1698. //
  1699. // Write the logon ID to the registry.
  1700. // This replaces the single user CURRENTUSER stuff
  1701. //
  1702. // Open HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services
  1703. // \NWCWorkstation\Parameters\InteractiveLogon, create if does not exist
  1704. //
  1705. RegError = RegCreateKeyExW(
  1706. HKEY_LOCAL_MACHINE,
  1707. NW_INTERACTIVE_LOGON_REGKEY,
  1708. 0,
  1709. WIN31_CLASS,
  1710. REG_OPTION_NON_VOLATILE,
  1711. KEY_WRITE,
  1712. NULL, // security attr
  1713. &InteractiveLogonKey,
  1714. &Disposition
  1715. );
  1716. if (RegError != NO_ERROR) {
  1717. KdPrint(("NWPROVAU: NwpSaveLogonCredential open NWCWorkstation\\Parameters\\InteractiveLogon key unexpected error %lu!\n", RegError));
  1718. return;
  1719. }
  1720. NwLuidToWStr(LogonId, LogonIdKeyName);
  1721. //
  1722. // Create the logon ID key under ServiceLogon
  1723. //
  1724. RegError = RegCreateKeyExW(
  1725. InteractiveLogonKey,
  1726. LogonIdKeyName,
  1727. 0,
  1728. WIN31_CLASS,
  1729. REG_OPTION_NON_VOLATILE,
  1730. KEY_WRITE,
  1731. NULL, // security attr
  1732. &LogonIdKey,
  1733. &Disposition
  1734. );
  1735. if (RegError != NO_ERROR) {
  1736. KdPrint(("NWPROVAU: NwpSaveInteractiveCredential create NWCWorkstation\\Parameters\\InteractiveLogon\\<LogonId> key unexpected error %lu!\n", RegError));
  1737. RegCloseKey(InteractiveLogonKey);
  1738. return;
  1739. }
  1740. // We can use OpenProcessToken because this thread is a client
  1741. // I.E. It should be WinLogon
  1742. if ( !OpenProcessToken( GetCurrentProcess(),
  1743. TOKEN_READ,
  1744. &TokenHandle ))
  1745. {
  1746. KdPrint(("NWPROVAU: NwpSaveLogonCredential OpenThreadToken failed: Error %d\n", GetLastError()));
  1747. goto NoWinStation;
  1748. }
  1749. // notice that we've allocated enough space for the
  1750. // TokenInformation structure. so if we fail, we
  1751. // return a NULL pointer indicating failure
  1752. if ( !GetTokenInformation( TokenHandle,
  1753. TokenSessionId,
  1754. TokenInformation,
  1755. sizeof( TokenInformation ),
  1756. &ReturnLength ))
  1757. {
  1758. KdPrint(("NWPROVAU NwpSaveLogonCredential: GetTokenInformation failed: Error %d\n",
  1759. GetLastError()));
  1760. CloseHandle( TokenHandle );
  1761. goto NoWinStation;
  1762. }
  1763. WinStationId = *(PULONG)TokenInformation;
  1764. CloseHandle( TokenHandle );
  1765. NoWinStation:
  1766. //
  1767. // Write the WinStation ID to the registry.
  1768. //
  1769. RegError = RegSetValueExW(
  1770. LogonIdKey,
  1771. NW_WINSTATION_VALUENAME,
  1772. 0,
  1773. REG_BINARY,
  1774. (LPVOID) &WinStationId,
  1775. sizeof(WinStationId)
  1776. );
  1777. if (RegError != NO_ERROR) {
  1778. KdPrint(("NWPROVAU: NwpSaveLogonCredential failed to save Winstation ID %lu\n", RegError));
  1779. }
  1780. RegError = RegSetValueExW(
  1781. LogonIdKey,
  1782. NW_SID_VALUENAME,
  1783. 0,
  1784. REG_SZ,
  1785. (LPVOID) NewUserSid,
  1786. (wcslen(NewUserSid) + 1) * sizeof(WCHAR)
  1787. );
  1788. if (RegError != NO_ERROR) {
  1789. KdPrint(("NWPROVAU: NwpSaveLogonCredential failed to save NewUser %ws %lu\n", NewUserSid, RegError));
  1790. }
  1791. RegCloseKey(LogonIdKey);
  1792. RegCloseKey(InteractiveLogonKey);
  1793. }
  1794. VOID
  1795. NwpSaveServiceCredential(
  1796. IN PLUID LogonId,
  1797. IN LPWSTR UserName,
  1798. IN LPWSTR Password
  1799. )
  1800. /*++
  1801. Routine Description:
  1802. This routine saves the service logon ID in the registry and
  1803. the credential in LSA's memory.
  1804. Arguments:
  1805. LogonId - Supplies the service's logon ID.
  1806. UserName - Supplies the name of the service.
  1807. Password - Supplies the password of the service.
  1808. Return Value:
  1809. None.
  1810. --*/
  1811. {
  1812. DWORD status;
  1813. LONG RegError;
  1814. HKEY ServiceLogonKey;
  1815. HKEY LogonIdKey;
  1816. DWORD Disposition;
  1817. WCHAR LogonIdKeyName[NW_MAX_LOGON_ID_LEN];
  1818. //
  1819. // Write the logon ID to the registry.
  1820. //
  1821. // Open HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services
  1822. // \NWCWorkstation\Parameters\ServiceLogon, create if does not exist
  1823. //
  1824. RegError = RegCreateKeyExW(
  1825. HKEY_LOCAL_MACHINE,
  1826. NW_SERVICE_LOGON_REGKEY,
  1827. 0,
  1828. WIN31_CLASS,
  1829. REG_OPTION_NON_VOLATILE,
  1830. KEY_WRITE,
  1831. NULL, // security attr
  1832. &ServiceLogonKey,
  1833. &Disposition
  1834. );
  1835. if (RegError != NO_ERROR) {
  1836. KdPrint(("NWPROVAU: NwpSaveServiceCredential open NWCWorkstation\\Parameters\\ServiceLogon key unexpected error %lu!\n", RegError));
  1837. return;
  1838. }
  1839. NwLuidToWStr(LogonId, LogonIdKeyName);
  1840. //
  1841. // Create the logon ID key under ServiceLogon
  1842. //
  1843. RegError = RegCreateKeyExW(
  1844. ServiceLogonKey,
  1845. LogonIdKeyName,
  1846. 0,
  1847. WIN31_CLASS,
  1848. REG_OPTION_NON_VOLATILE,
  1849. KEY_WRITE,
  1850. NULL, // security attr
  1851. &LogonIdKey,
  1852. &Disposition
  1853. );
  1854. RegCloseKey(ServiceLogonKey);
  1855. if (RegError != NO_ERROR) {
  1856. KdPrint(("NWPROVAU: NwpSaveServiceCredential create NWCWorkstation\\Parameters\\ServiceLogon\\<LogonId> key unexpected error %lu!\n", RegError));
  1857. return;
  1858. }
  1859. RegCloseKey(LogonIdKey);
  1860. //
  1861. // Save the service logon credential in LSA.
  1862. //
  1863. status = NwpSetCredentialInLsa(
  1864. LogonId,
  1865. UserName,
  1866. Password
  1867. );
  1868. if (status != NO_ERROR) {
  1869. //
  1870. // Could not save new credential.
  1871. //
  1872. KdPrint(("NWPROVAU: NwpSaveServiceCredential failed to set credential %lu\n", status));
  1873. }
  1874. }
  1875. DWORD
  1876. NwpGetUserSid(
  1877. IN PLUID LogonId,
  1878. OUT LPWSTR *UserSidString
  1879. )
  1880. /*++
  1881. Routine Description:
  1882. This routine looks up the SID of a user given the user's logon ID.
  1883. It does this by making the current process a logon process and then
  1884. call to LSA to get the user SID.
  1885. Arguments:
  1886. LogonId - Supplies the logon ID of the user to lookup the SID.
  1887. UserSidString - Receives a pointer to a buffer allocated by this routine
  1888. which contains the user SID in string form. This must be freed with
  1889. LocalFree when done.
  1890. Return Value:
  1891. NO_ERROR or reason for failure.
  1892. --*/
  1893. {
  1894. DWORD status;
  1895. NTSTATUS ntstatus;
  1896. NTSTATUS AuthPackageStatus;
  1897. STRING InputString;
  1898. LSA_OPERATIONAL_MODE SecurityMode = 0;
  1899. HANDLE LsaHandle;
  1900. ULONG AuthPackageId;
  1901. MSV1_0_GETUSERINFO_REQUEST UserInfoRequest;
  1902. PMSV1_0_GETUSERINFO_RESPONSE UserInfoResponse = NULL;
  1903. ULONG UserInfoResponseLength;
  1904. //
  1905. // Register this process as a logon process so that we can call
  1906. // MS V 1.0 authentication package.
  1907. //
  1908. RtlInitString(&InputString, "Microsoft NetWare Credential Manager");
  1909. ntstatus = LsaRegisterLogonProcess(
  1910. &InputString,
  1911. &LsaHandle,
  1912. &SecurityMode
  1913. );
  1914. if (! NT_SUCCESS(ntstatus)) {
  1915. KdPrint(("NWPROVAU: LsaRegisterLogonProcess returns x%08lx\n",
  1916. ntstatus));
  1917. return RtlNtStatusToDosError(ntstatus);
  1918. }
  1919. //
  1920. // Look up the MS V1.0 authentication package
  1921. //
  1922. RtlInitString(&InputString, MSV1_0_PACKAGE_NAME);
  1923. ntstatus = LsaLookupAuthenticationPackage(
  1924. LsaHandle,
  1925. &InputString,
  1926. &AuthPackageId
  1927. );
  1928. if (! NT_SUCCESS(ntstatus)) {
  1929. KdPrint(("NWPROVAU: LsaLookupAuthenticationPackage returns x%08lx\n",
  1930. ntstatus));
  1931. status = RtlNtStatusToDosError(ntstatus);
  1932. goto CleanExit;
  1933. }
  1934. //
  1935. // Ask authentication package for user information.
  1936. //
  1937. UserInfoRequest.MessageType = MsV1_0GetUserInfo;
  1938. RtlCopyLuid(&UserInfoRequest.LogonId, LogonId);
  1939. ntstatus = LsaCallAuthenticationPackage(
  1940. LsaHandle,
  1941. AuthPackageId,
  1942. &UserInfoRequest,
  1943. sizeof(MSV1_0_GETUSERINFO_REQUEST),
  1944. (PVOID *) &UserInfoResponse,
  1945. &UserInfoResponseLength,
  1946. &AuthPackageStatus
  1947. );
  1948. if (NT_SUCCESS(ntstatus)) {
  1949. ntstatus = AuthPackageStatus;
  1950. }
  1951. if (! NT_SUCCESS(ntstatus)) {
  1952. KdPrint(("NWPROVAU: LsaCallAuthenticationPackage returns x%08lx\n",
  1953. ntstatus));
  1954. status = RtlNtStatusToDosError(ntstatus);
  1955. goto CleanExit;
  1956. }
  1957. //
  1958. // Convert the SID to string. This routine also allocates the
  1959. // output buffer.
  1960. //
  1961. status = NwpConvertSid(
  1962. UserInfoResponse->UserSid,
  1963. UserSidString
  1964. );
  1965. CleanExit:
  1966. if (UserInfoResponse != NULL) {
  1967. (void) LsaFreeReturnBuffer((PVOID) UserInfoResponse);
  1968. }
  1969. (void) LsaDeregisterLogonProcess(LsaHandle);
  1970. return status;
  1971. }
  1972. DWORD
  1973. NwpConvertSid(
  1974. IN PSID Sid,
  1975. OUT LPWSTR *UserSidString
  1976. )
  1977. {
  1978. NTSTATUS ntstatus;
  1979. UNICODE_STRING SidString;
  1980. //
  1981. // Initialize output pointer
  1982. //
  1983. *UserSidString = NULL;
  1984. ntstatus = RtlConvertSidToUnicodeString(
  1985. &SidString,
  1986. Sid,
  1987. TRUE // Allocate destination string
  1988. );
  1989. if (ntstatus != STATUS_SUCCESS) {
  1990. KdPrint(("NWPROVAU: RtlConvertSidToUnicodeString returns %08lx\n",
  1991. ntstatus));
  1992. return RtlNtStatusToDosError(ntstatus);
  1993. }
  1994. //
  1995. // Create the buffer to return the SID string
  1996. //
  1997. if ((*UserSidString = (LPVOID) LocalAlloc(
  1998. LMEM_ZEROINIT,
  1999. SidString.Length + sizeof(WCHAR)
  2000. )) == NULL) {
  2001. RtlFreeUnicodeString(&SidString);
  2002. return ERROR_NOT_ENOUGH_MEMORY;
  2003. }
  2004. memcpy(*UserSidString, SidString.Buffer, SidString.Length);
  2005. RtlFreeUnicodeString(&SidString);
  2006. #if DBG
  2007. IF_DEBUG(LOGON) {
  2008. KdPrint(("NWPROVAU: NwpConvertSid got %ws\n", *UserSidString));
  2009. }
  2010. #endif
  2011. return NO_ERROR;
  2012. }
  2013. BOOL
  2014. NwpPollWorkstationStart(
  2015. VOID
  2016. )
  2017. /*++
  2018. Routine Description:
  2019. This routine polls for the workstation to complete starting.
  2020. It gives up after 90 seconds.
  2021. Arguments:
  2022. None.
  2023. Return Value:
  2024. Returns TRUE if the NetWare workstation is running; FALSE otherwise.
  2025. --*/
  2026. {
  2027. DWORD err;
  2028. SC_HANDLE ScManager = NULL;
  2029. SC_HANDLE Service = NULL;
  2030. SERVICE_STATUS ServiceStatus;
  2031. DWORD TryCount = 0;
  2032. BOOL Started = FALSE;
  2033. if ((ScManager = OpenSCManager(
  2034. NULL,
  2035. NULL,
  2036. SC_MANAGER_CONNECT
  2037. )) == (SC_HANDLE) NULL) {
  2038. err = GetLastError();
  2039. KdPrint(("NWPROVAU: NwpPollWorkstationStart: OpenSCManager failed %lu\n",
  2040. err));
  2041. goto CleanExit;
  2042. }
  2043. if ((Service = OpenService(
  2044. ScManager,
  2045. NW_WORKSTATION_SERVICE,
  2046. SERVICE_QUERY_STATUS | SERVICE_QUERY_CONFIG
  2047. )) == (SC_HANDLE) NULL) {
  2048. err = GetLastError();
  2049. (void) CloseServiceHandle(ScManager);
  2050. KdPrint(("NWPROVAU: NwpPollWorkstationStart: OpenService failed %lu\n",
  2051. err));
  2052. goto CleanExit;
  2053. }
  2054. do {
  2055. if (! QueryServiceStatus(
  2056. Service,
  2057. &ServiceStatus
  2058. )) {
  2059. err = GetLastError();
  2060. KdPrint(("NWPROVAU: NwpPollWorkstationStart: QueryServiceStatus failed %lu\n",
  2061. err));
  2062. goto CleanExit;
  2063. }
  2064. if ( (ServiceStatus.dwCurrentState == SERVICE_RUNNING) ||
  2065. (ServiceStatus.dwCurrentState == SERVICE_CONTINUE_PENDING) ||
  2066. (ServiceStatus.dwCurrentState == SERVICE_PAUSE_PENDING) ||
  2067. (ServiceStatus.dwCurrentState == SERVICE_PAUSED) ) {
  2068. Started = TRUE;
  2069. }
  2070. else if (ServiceStatus.dwCurrentState == SERVICE_START_PENDING ||
  2071. (ServiceStatus.dwCurrentState == SERVICE_STOPPED &&
  2072. ServiceStatus.dwWin32ExitCode == ERROR_SERVICE_NEVER_STARTED)) {
  2073. //
  2074. // If workstation is stopped and never started before but it's
  2075. // not auto-start, don't poll.
  2076. //
  2077. if (TryCount == 0 &&
  2078. ServiceStatus.dwCurrentState == SERVICE_STOPPED &&
  2079. ServiceStatus.dwWin32ExitCode == ERROR_SERVICE_NEVER_STARTED) {
  2080. BYTE OutBuffer[sizeof(QUERY_SERVICE_CONFIGW) + 256];
  2081. DWORD BytesNeeded;
  2082. if (QueryServiceConfigW(
  2083. Service,
  2084. (LPQUERY_SERVICE_CONFIGW) OutBuffer,
  2085. sizeof(OutBuffer),
  2086. &BytesNeeded
  2087. )) {
  2088. if (((LPQUERY_SERVICE_CONFIGW) OutBuffer)->dwStartType !=
  2089. SERVICE_AUTO_START) {
  2090. #if DBG
  2091. IF_DEBUG(LOGON) {
  2092. KdPrint(("NWPROVAU: NwpPollWorkstationStart: Not waiting for the workstation to start\n"));
  2093. }
  2094. #endif
  2095. goto CleanExit;
  2096. }
  2097. }
  2098. else {
  2099. err = GetLastError();
  2100. KdPrint(("NWPROVAU: QueryServiceConfig failed %lu, BytesNeeded %lu\n",
  2101. err, BytesNeeded));
  2102. }
  2103. }
  2104. //
  2105. // Wait only if the workstation is start pending, or it has not
  2106. // been attempted to start before.
  2107. //
  2108. Sleep(5000); // Sleep for 5 seconds before rechecking.
  2109. TryCount++;
  2110. }
  2111. else {
  2112. goto CleanExit;
  2113. }
  2114. } while (! Started && TryCount < 18);
  2115. if (Started) {
  2116. #if DBG
  2117. IF_DEBUG(LOGON) {
  2118. KdPrint(("NWPROVAU: NetWare workstation is started after we've polled %lu times\n",
  2119. TryCount));
  2120. }
  2121. #endif
  2122. }
  2123. CleanExit:
  2124. if (ScManager != NULL) {
  2125. (void) CloseServiceHandle(ScManager);
  2126. }
  2127. if (Service != NULL) {
  2128. (void) CloseServiceHandle(Service);
  2129. }
  2130. return Started;
  2131. }
  2132. DWORD
  2133. NwpSetCredentialInLsa(
  2134. IN PLUID LogonId,
  2135. IN LPWSTR UserName,
  2136. IN LPWSTR Password
  2137. )
  2138. /*++
  2139. Routine Description:
  2140. This routine calls to the NetWare authentication package to save
  2141. the user credential.
  2142. Arguments:
  2143. LogonId - Supplies the logon ID of the user.
  2144. UserName - Supplies the username.
  2145. Password - Supplies the password.
  2146. Return Value:
  2147. NO_ERROR or reason for failure.
  2148. --*/
  2149. {
  2150. DWORD status;
  2151. NTSTATUS ntstatus;
  2152. NTSTATUS AuthPackageStatus;
  2153. STRING InputString;
  2154. LSA_OPERATIONAL_MODE SecurityMode = 0;
  2155. HANDLE LsaHandle;
  2156. ULONG AuthPackageId;
  2157. NWAUTH_SET_CREDENTIAL_REQUEST SetCredRequest;
  2158. PCHAR DummyOutput;
  2159. ULONG DummyOutputLength;
  2160. UNICODE_STRING PasswordStr;
  2161. UCHAR EncodeSeed = NW_ENCODE_SEED;
  2162. //
  2163. // Register this process as a logon process so that we can call
  2164. // NetWare authentication package.
  2165. //
  2166. RtlInitString(&InputString, "Microsoft NetWare Credential Manager");
  2167. ntstatus = LsaRegisterLogonProcess(
  2168. &InputString,
  2169. &LsaHandle,
  2170. &SecurityMode
  2171. );
  2172. if (! NT_SUCCESS(ntstatus)) {
  2173. KdPrint(("NWPROVAU: NwpSetCredential: LsaRegisterLogonProcess returns x%08lx\n",
  2174. ntstatus));
  2175. return RtlNtStatusToDosError(ntstatus);
  2176. }
  2177. //
  2178. // Look up the NetWare authentication package
  2179. //
  2180. RtlInitString(&InputString, NW_AUTH_PACKAGE_NAME);
  2181. ntstatus = LsaLookupAuthenticationPackage(
  2182. LsaHandle,
  2183. &InputString,
  2184. &AuthPackageId
  2185. );
  2186. if (! NT_SUCCESS(ntstatus)) {
  2187. KdPrint(("NWPROVAU: NwpSetCredential: LsaLookupAuthenticationPackage returns x%08lx\n",
  2188. ntstatus));
  2189. status = RtlNtStatusToDosError(ntstatus);
  2190. goto CleanExit;
  2191. }
  2192. //
  2193. // Ask authentication package for user information.
  2194. //
  2195. SetCredRequest.MessageType = NwAuth_SetCredential;
  2196. RtlCopyLuid(&SetCredRequest.LogonId, LogonId);
  2197. wcscpy(SetCredRequest.UserName, UserName);
  2198. wcscpy(SetCredRequest.Password, Password);
  2199. //
  2200. // Encode the password.
  2201. //
  2202. RtlInitUnicodeString(&PasswordStr, SetCredRequest.Password);
  2203. RtlRunEncodeUnicodeString(&EncodeSeed, &PasswordStr);
  2204. ntstatus = LsaCallAuthenticationPackage(
  2205. LsaHandle,
  2206. AuthPackageId,
  2207. &SetCredRequest,
  2208. sizeof(SetCredRequest),
  2209. (PVOID *) &DummyOutput,
  2210. &DummyOutputLength,
  2211. &AuthPackageStatus
  2212. );
  2213. if (NT_SUCCESS(ntstatus)) {
  2214. ntstatus = AuthPackageStatus;
  2215. }
  2216. if (! NT_SUCCESS(ntstatus)) {
  2217. KdPrint(("NWPROVAU: NwpSetCredential: LsaCallAuthenticationPackage returns x%08lx\n",
  2218. ntstatus));
  2219. status = RtlNtStatusToDosError(ntstatus);
  2220. }
  2221. else {
  2222. status = NO_ERROR;
  2223. }
  2224. CleanExit:
  2225. (void) LsaDeregisterLogonProcess(LsaHandle);
  2226. return status;
  2227. }
  2228. NTSTATUS NwNdsOpenRdrHandle(
  2229. OUT PHANDLE phNwRdrHandle
  2230. )
  2231. {
  2232. NTSTATUS ntstatus;
  2233. IO_STATUS_BLOCK IoStatusBlock;
  2234. OBJECT_ATTRIBUTES ObjectAttributes;
  2235. ACCESS_MASK DesiredAccess = SYNCHRONIZE | GENERIC_READ;
  2236. WCHAR NameStr[] = L"\\Device\\NwRdr\\*";
  2237. UNICODE_STRING uOpenName;
  2238. //
  2239. // Prepare the open name.
  2240. //
  2241. RtlInitUnicodeString( &uOpenName, NameStr );
  2242. //
  2243. // Set up the object attributes.
  2244. //
  2245. InitializeObjectAttributes(
  2246. &ObjectAttributes,
  2247. &uOpenName,
  2248. OBJ_CASE_INSENSITIVE,
  2249. NULL,
  2250. NULL );
  2251. ntstatus = NtOpenFile(
  2252. phNwRdrHandle,
  2253. DesiredAccess,
  2254. &ObjectAttributes,
  2255. &IoStatusBlock,
  2256. FILE_SHARE_VALID_FLAGS,
  2257. FILE_SYNCHRONOUS_IO_NONALERT );
  2258. if ( !NT_ERROR(ntstatus) &&
  2259. !NT_INFORMATION(ntstatus) &&
  2260. !NT_WARNING(ntstatus)) {
  2261. return IoStatusBlock.Status;
  2262. }
  2263. return ntstatus;
  2264. }
  2265. VOID
  2266. NwpSelectServers(
  2267. IN HWND DialogHandle,
  2268. IN PCHANGE_PW_DLG_PARAM Credential
  2269. )
  2270. /*++
  2271. Routine Description:
  2272. This routine displays the dialog for user to select individual trees
  2273. to change password on. It then changes the password on the selected
  2274. list. After the password has been changed, it displays a dialog which lists
  2275. the 3.X bindery servers where the change could not be made.
  2276. Arguments:
  2277. DialogHandle - Supplies the handle to display dialog.
  2278. Credential - Provides on input the old and new passwords, and
  2279. the logged in user's name. Other field are ignored
  2280. on input and consecuently used within this function.
  2281. Return Value:
  2282. None.
  2283. --*/
  2284. {
  2285. INT_PTR Result;
  2286. Credential->TreeList = NULL;
  2287. Credential->UserList = NULL;
  2288. Credential->Entries = 0;
  2289. Credential->ChangedOne = FALSE;
  2290. Result = DialogBoxParamW( hmodNW,
  2291. MAKEINTRESOURCEW(DLG_PW_SELECT_SERVERS),
  2292. (HWND) DialogHandle,
  2293. (DLGPROC) NwpSelectServersDlgProc,
  2294. (LPARAM) Credential );
  2295. if ( Result == IDOK )
  2296. {
  2297. //
  2298. // Display list of trees (if any) for which password was changed.
  2299. //
  2300. DialogBoxParamW( hmodNW,
  2301. MAKEINTRESOURCEW(DLG_PW_CHANGED),
  2302. (HWND) DialogHandle,
  2303. (DLGPROC) NwpChangePasswordSuccessDlgProc,
  2304. (LPARAM) Credential );
  2305. if ( Credential->TreeList != NULL )
  2306. {
  2307. LocalFree( Credential->TreeList );
  2308. }
  2309. //
  2310. // Display a dialog to tell users to use SetPass if they have an
  2311. // account on a NetWare 3.X server.
  2312. //
  2313. NwpMessageBoxError( DialogHandle,
  2314. IDS_NETWARE_TITLE,
  2315. IDS_CHANGE_PASSWORD_INFO,
  2316. 0,
  2317. NULL,
  2318. MB_OK );
  2319. }
  2320. }