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.

1479 lines
38 KiB

  1. /*++
  2. Copyright (c) 1993, 1994 Microsoft Corporation
  3. Module Name:
  4. credentl.c
  5. Abstract:
  6. This module contains credential management routines supported by
  7. NetWare Workstation service.
  8. Author:
  9. Rita Wong (ritaw) 15-Feb-1993
  10. Revision History:
  11. 13-Apr-1994 Added change password code written by ColinW, AndyHe,
  12. TerenceS, and RitaW.
  13. --*/
  14. #include <nw.h>
  15. #include <nwreg.h>
  16. #include <nwlsa.h>
  17. #include <nwauth.h>
  18. #include <nwxchg.h>
  19. #include <nwapi.h>
  20. //-------------------------------------------------------------------//
  21. // //
  22. // Global variables //
  23. // //
  24. //-------------------------------------------------------------------//
  25. //
  26. // Variables to coordinate reading of user logon credential from the
  27. // registry if the user logged on before the workstation is started.
  28. //
  29. STATIC BOOL NwLogonNotifiedRdr;
  30. STATIC
  31. DWORD
  32. NwpRegisterLogonProcess(
  33. OUT PHANDLE LsaHandle,
  34. OUT PULONG AuthPackageId
  35. );
  36. STATIC
  37. VOID
  38. NwpGetServiceCredentials(
  39. IN HANDLE LsaHandle,
  40. IN ULONG AuthPackageId
  41. );
  42. STATIC
  43. DWORD
  44. NwpGetCredentialInLsa(
  45. IN HANDLE LsaHandle,
  46. IN ULONG AuthPackageId,
  47. IN PLUID LogonId,
  48. OUT LPWSTR *UserName,
  49. OUT LPWSTR *Password
  50. );
  51. STATIC
  52. VOID
  53. NwpGetInteractiveCredentials(
  54. IN HANDLE LsaHandle,
  55. IN ULONG AuthPackageId
  56. );
  57. DWORD
  58. NwrLogonUser(
  59. IN LPWSTR Reserved OPTIONAL,
  60. IN PLUID LogonId,
  61. IN LPWSTR UserName,
  62. IN LPWSTR Password OPTIONAL,
  63. IN LPWSTR PreferredServerName OPTIONAL,
  64. IN LPWSTR NdsPreferredServerName OPTIONAL,
  65. OUT LPWSTR LogonCommand OPTIONAL,
  66. IN DWORD LogonCommandLength,
  67. IN DWORD PrintOption
  68. )
  69. /*++
  70. Routine Description:
  71. This function logs on the user to NetWare network. It passes the
  72. user logon credential to the redirector to be used as the default
  73. credential when attaching to any server.
  74. Arguments:
  75. Reserved - Must be NULL.
  76. UserName - Specifies the name of the user who logged on.
  77. Password - Specifies the password of the user who logged on.
  78. PreferredServerName - Specifies the user's preferred server.
  79. LogonCommand - Receives the string which is the command to execute
  80. on the command prompt for the user if logon is successful.
  81. Return Value:
  82. NO_ERROR or error from redirector.
  83. --*/
  84. {
  85. DWORD status;
  86. LUID SystemId = SYSTEM_LUID ;
  87. UNREFERENCED_PARAMETER(Reserved);
  88. EnterCriticalSection(&NwLoggedOnCritSec);
  89. status = NwRdrLogonUser(
  90. LogonId,
  91. UserName,
  92. wcslen(UserName) * sizeof(WCHAR),
  93. Password,
  94. (ARGUMENT_PRESENT(Password) ?
  95. wcslen(Password) * sizeof(WCHAR) :
  96. 0),
  97. PreferredServerName,
  98. (ARGUMENT_PRESENT(PreferredServerName) ?
  99. wcslen(PreferredServerName) * sizeof(WCHAR) :
  100. 0),
  101. NdsPreferredServerName,
  102. (ARGUMENT_PRESENT(NdsPreferredServerName) ?
  103. wcslen(NdsPreferredServerName) * sizeof(WCHAR) :
  104. 0),
  105. PrintOption
  106. );
  107. if (status == NO_ERROR || status == NW_PASSWORD_HAS_EXPIRED) {
  108. NwLogonNotifiedRdr = TRUE;
  109. if (RtlEqualLuid(LogonId, &SystemId))
  110. GatewayLoggedOn = TRUE ;
  111. }
  112. LeaveCriticalSection(&NwLoggedOnCritSec);
  113. if (ARGUMENT_PRESENT(LogonCommand) && (LogonCommandLength >= sizeof(WCHAR))) {
  114. LogonCommand[0] = 0;
  115. }
  116. return status;
  117. }
  118. DWORD
  119. NwrLogoffUser(
  120. IN LPWSTR Reserved OPTIONAL,
  121. IN PLUID LogonId
  122. )
  123. /*++
  124. Routine Description:
  125. This function tells the redirector to log off the interactive
  126. user.
  127. Arguments:
  128. Reserved - Must be NULL.
  129. LogonId - PLUID identifying the logged on process. if NULL, then gateway.
  130. Return Value:
  131. --*/
  132. {
  133. DWORD status = NO_ERROR ;
  134. LUID SystemId = SYSTEM_LUID ;
  135. UNREFERENCED_PARAMETER(Reserved);
  136. EnterCriticalSection(&NwLoggedOnCritSec);
  137. if (GatewayLoggedOn || !RtlEqualLuid(LogonId, &SystemId))
  138. status = NwRdrLogoffUser(LogonId);
  139. if (status == NO_ERROR && RtlEqualLuid(LogonId, &SystemId))
  140. GatewayLoggedOn = FALSE ;
  141. LeaveCriticalSection(&NwLoggedOnCritSec);
  142. return status ;
  143. }
  144. DWORD
  145. NwrSetInfo(
  146. IN LPWSTR Reserved OPTIONAL,
  147. IN DWORD PrintOption,
  148. IN LPWSTR PreferredServerName OPTIONAL
  149. )
  150. /*++
  151. Routine Description:
  152. This function sets the preferred server and print option in
  153. the redirector for the interactive user.
  154. Arguments:
  155. Reserved - Must be NULL.
  156. PreferredServerName - Specifies the user's preferred server.
  157. PrintOption - Specifies the user's print option flag
  158. Return Value:
  159. NO_ERROR or error from redirector.
  160. --*/
  161. {
  162. DWORD err;
  163. UNREFERENCED_PARAMETER(Reserved);
  164. err = NwRdrSetInfo(
  165. PrintOption,
  166. NwPacketBurstSize, // just reset to current
  167. PreferredServerName,
  168. (PreferredServerName != NULL ?
  169. wcslen( PreferredServerName) * sizeof( WCHAR ) : 0 ),
  170. NwProviderName, // just reset to current
  171. wcslen( NwProviderName ) * sizeof( WCHAR )
  172. );
  173. return err;
  174. }
  175. DWORD
  176. NwrSetLogonScript(
  177. IN LPWSTR Reserved OPTIONAL,
  178. IN DWORD ScriptOptions
  179. )
  180. /*++
  181. Routine Description:
  182. This function sets logon script related info. Currently, all that is
  183. supported is to turn the Run Logon Scripts Synchronously flag on and off.
  184. We do this using the global flag and not per user because at NPLogonNotify
  185. time we dont have per user registry yet. And rather than turn on & leave
  186. on, we turn on as need so that users that dont run NW scripts dont need
  187. wait.
  188. Arguments:
  189. Reserved - Must be NULL.
  190. ScriptOptions - options for logon scripts.
  191. Return Value:
  192. Win32 error from calls made.
  193. --*/
  194. {
  195. DWORD dwSync, err = NO_ERROR ;
  196. HKEY hKeyWinLogon = NULL, hKeyNWC = NULL ;
  197. UNREFERENCED_PARAMETER(Reserved);
  198. if (!IsTerminalServer()) {
  199. // Setting global flags isn't multi-user, see userinit.c for multi-user implementation
  200. //
  201. // *** Note that in this function we intentionally do not impersonate ***
  202. // *** since we are modifying registry under \SOFTWARE & \SYSTEM. ***
  203. //
  204. //
  205. // Check the parameters.
  206. //
  207. if (ScriptOptions == SYNC_LOGONSCRIPT) {
  208. dwSync = 1 ; // this is value WinLogon needs to sync login scripts.
  209. } else if (ScriptOptions == RESET_SYNC_LOGONSCRIPT) {
  210. dwSync = 0 ;
  211. } else {
  212. return(ERROR_INVALID_PARAMETER) ;
  213. }
  214. //
  215. //
  216. // Open HKEY_LOCAL_MACHINE\System\CurrentVersion\Services\NwcWorkstation
  217. // \Parameters. We use this location to record the fact we temporarily
  218. // turned on the Sync Scripts Flag.
  219. //
  220. err = RegOpenKeyExW(
  221. HKEY_LOCAL_MACHINE,
  222. NW_WORKSTATION_REGKEY,
  223. 0,
  224. KEY_READ | KEY_WRITE, // desired access
  225. &hKeyNWC) ;
  226. if ( err ) {
  227. return err ;
  228. }
  229. //
  230. // We are resetting. Check if we turned the flag on. If no, then leave
  231. // it be.
  232. //
  233. if (ScriptOptions == RESET_SYNC_LOGONSCRIPT) {
  234. DWORD dwType, dwValue = 0 ;
  235. DWORD dwSize = sizeof(dwValue) ;
  236. err = RegQueryValueExW(
  237. hKeyNWC,
  238. NW_SYNCLOGONSCRIPT_VALUENAME,
  239. NULL,
  240. &dwType, // ignored
  241. (LPBYTE) &dwValue,
  242. &dwSize) ;
  243. if ((err != NO_ERROR) || (dwValue == 0)) {
  244. //
  245. // value not there or zero. ie. assume we didnt set. quit now.
  246. //
  247. goto ExitPoint ;
  248. }
  249. }
  250. //
  251. //
  252. // Open HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion
  253. // \WinLogon.
  254. //
  255. err = RegOpenKeyExW(
  256. HKEY_LOCAL_MACHINE,
  257. WINLOGON_REGKEY,
  258. 0,
  259. KEY_READ | KEY_WRITE, // desired access
  260. &hKeyWinLogon) ;
  261. if ( err ) {
  262. goto ExitPoint ;
  263. }
  264. //
  265. // We are setting. Check if flag is already on. If yes, then leave
  266. // it be.
  267. //
  268. if (ScriptOptions == SYNC_LOGONSCRIPT) {
  269. DWORD dwType, dwValue = 0 ;
  270. DWORD dwSize = sizeof(dwValue) ;
  271. err = RegQueryValueExW(
  272. hKeyWinLogon,
  273. SYNCLOGONSCRIPT_VALUENAME,
  274. NULL,
  275. &dwType, // ignored
  276. (LPBYTE) &dwValue,
  277. &dwSize) ;
  278. if ((err == NO_ERROR) && (dwValue == 1)) {
  279. //
  280. // already on. nothing to do. just return.
  281. //
  282. goto ExitPoint ;
  283. }
  284. }
  285. //
  286. // Write out value to make logon scripts synchronous. Or to reset it.
  287. //
  288. err = RegSetValueExW(
  289. hKeyWinLogon,
  290. SYNCLOGONSCRIPT_VALUENAME,
  291. 0,
  292. REG_DWORD,
  293. (LPBYTE) &dwSync, // either 1 or 0.
  294. sizeof(dwSync)) ;
  295. if (err == NO_ERROR) {
  296. DWORD dwValue = (ScriptOptions == SYNC_LOGONSCRIPT) ? 1 : 0 ;
  297. //
  298. // We have successfully set WinLogon flag. Record (or clear)
  299. // our own flag.
  300. //
  301. err = RegSetValueExW(
  302. hKeyNWC,
  303. NW_SYNCLOGONSCRIPT_VALUENAME,
  304. 0,
  305. REG_DWORD,
  306. (LPBYTE) &dwValue,
  307. sizeof(dwValue)) ;
  308. }
  309. } //if IsTerminalServer()
  310. ExitPoint:
  311. if (hKeyWinLogon)
  312. (void) RegCloseKey( hKeyWinLogon );
  313. if (hKeyNWC)
  314. (void) RegCloseKey( hKeyNWC );
  315. return err;
  316. }
  317. DWORD
  318. NwrValidateUser(
  319. IN LPWSTR Reserved OPTIONAL,
  320. IN LPWSTR PreferredServerName
  321. )
  322. /*++
  323. Routine Description:
  324. This function checks whether the user can be authenticated
  325. successfully on the given server.
  326. Arguments:
  327. Reserved - Must be NULL.
  328. PreferredServerName - Specifies the user's preferred server.
  329. Return Value:
  330. NO_ERROR or error that occurred during authentication.
  331. --*/
  332. {
  333. DWORD status ;
  334. UNREFERENCED_PARAMETER(Reserved);
  335. if ( ( PreferredServerName != NULL )
  336. && ( *PreferredServerName != 0 )
  337. )
  338. {
  339. //
  340. // Impersonate the client
  341. //
  342. if ((status = NwImpersonateClient()) != NO_ERROR)
  343. {
  344. return status ;
  345. }
  346. status = NwConnectToServer( PreferredServerName ) ;
  347. (void) NwRevertToSelf() ;
  348. return status ;
  349. }
  350. return NO_ERROR;
  351. }
  352. VOID
  353. NwInitializeLogon(
  354. VOID
  355. )
  356. /*++
  357. Routine Description:
  358. This function initializes the data in the workstation which handles
  359. user logon. It is called by the initialization thread.
  360. Arguments:
  361. None.
  362. Return Value:
  363. None.
  364. --*/
  365. {
  366. //
  367. // Initialize logon flag. When the redirector LOGON FsCtl has been
  368. // called, this flag will be set to TRUE. Initialize the
  369. // critical section to serialize access to NwLogonNotifiedRdr flag.
  370. //
  371. NwLogonNotifiedRdr = FALSE;
  372. }
  373. VOID
  374. NwGetLogonCredential(
  375. VOID
  376. )
  377. /*++
  378. Routine Description:
  379. This function reads the user and service logon IDs from the registry so
  380. that it can get the credentials from LSA.
  381. It handles the case where the user has logged on before the workstation
  382. is started. This function is called by the initialization thread
  383. after opening up the RPC interface so that if user logon is happening
  384. concurrently, the provider is given a chance to call the NwrLogonUser API
  385. first, making it no longer necessary for the workstation to also
  386. retrieve the credential from the registry.
  387. Arguments:
  388. None.
  389. Return Value:
  390. None.
  391. --*/
  392. {
  393. DWORD status;
  394. HANDLE LsaHandle;
  395. ULONG AuthPackageId = 0;
  396. EnterCriticalSection(&NwLoggedOnCritSec);
  397. if (NwLogonNotifiedRdr) {
  398. //
  399. // Logon credential's already made known to the redirector by
  400. // the provider calling the NwrLogonUser API.
  401. //
  402. #if DBG
  403. IF_DEBUG(LOGON) {
  404. KdPrint(("\nNWWORKSTATION: Redirector already has logon credential\n"));
  405. }
  406. #endif
  407. LeaveCriticalSection(&NwLoggedOnCritSec);
  408. return;
  409. }
  410. #if DBG
  411. IF_DEBUG(LOGON) {
  412. KdPrint(("NWWORKSTATION: Main init--NwGetLogonCredential\n"));
  413. }
  414. #endif
  415. status = NwpRegisterLogonProcess(&LsaHandle, &AuthPackageId);
  416. if (status != NO_ERROR) {
  417. LeaveCriticalSection(&NwLoggedOnCritSec);
  418. return;
  419. }
  420. //
  421. // Tell the redirector about service credentials
  422. //
  423. NwpGetServiceCredentials(LsaHandle, AuthPackageId);
  424. //
  425. // Tell the redirector about interactive credentials
  426. //
  427. NwpGetInteractiveCredentials(LsaHandle, AuthPackageId);
  428. (void) LsaDeregisterLogonProcess(LsaHandle);
  429. LeaveCriticalSection(&NwLoggedOnCritSec);
  430. }
  431. STATIC
  432. VOID
  433. NwpGetServiceCredentials(
  434. IN HANDLE LsaHandle,
  435. IN ULONG AuthPackageId
  436. )
  437. /*++
  438. Routine Description:
  439. This function reads the service logon IDs from the registry
  440. so that it can get the service credentials from LSA. It then
  441. notifies the redirector of the service logons.
  442. Arguments:
  443. LsaHandle - Supplies the handle to LSA.
  444. AuthPackageId - Supplies the NetWare authentication package ID.
  445. Return Value:
  446. None.
  447. --*/
  448. {
  449. DWORD status;
  450. LONG RegError;
  451. LPWSTR UserName = NULL;
  452. LPWSTR Password = NULL;
  453. HKEY ServiceLogonKey;
  454. DWORD Index = 0;
  455. WCHAR LogonIdKey[NW_MAX_LOGON_ID_LEN];
  456. LUID LogonId;
  457. RegError = RegOpenKeyExW(
  458. HKEY_LOCAL_MACHINE,
  459. NW_SERVICE_LOGON_REGKEY,
  460. REG_OPTION_NON_VOLATILE,
  461. KEY_READ,
  462. &ServiceLogonKey
  463. );
  464. if (RegError == ERROR_SUCCESS) {
  465. do {
  466. RegError = RegEnumKeyW(
  467. ServiceLogonKey,
  468. Index,
  469. LogonIdKey,
  470. sizeof(LogonIdKey) / sizeof(WCHAR)
  471. );
  472. if (RegError == ERROR_SUCCESS) {
  473. //
  474. // Got a logon id key.
  475. //
  476. NwWStrToLuid(LogonIdKey, &LogonId);
  477. status = NwpGetCredentialInLsa(
  478. LsaHandle,
  479. AuthPackageId,
  480. &LogonId,
  481. &UserName,
  482. &Password
  483. );
  484. if (status == NO_ERROR) {
  485. (void) NwRdrLogonUser(
  486. &LogonId,
  487. UserName,
  488. wcslen(UserName) * sizeof(WCHAR),
  489. Password,
  490. wcslen(Password) * sizeof(WCHAR),
  491. NULL,
  492. 0,
  493. NULL,
  494. 0,
  495. NW_PRINT_OPTION_DEFAULT
  496. );
  497. //
  498. // Freeing the UserName pointer frees both the
  499. // username and password buffers.
  500. //
  501. (void) LsaFreeReturnBuffer((PVOID) UserName);
  502. }
  503. }
  504. else if (RegError != ERROR_NO_MORE_ITEMS) {
  505. KdPrint(("NWWORKSTATION: NwpGetServiceCredentials failed to enum logon IDs RegError=%lu\n",
  506. RegError));
  507. }
  508. Index++;
  509. } while (RegError == ERROR_SUCCESS);
  510. (void) RegCloseKey(ServiceLogonKey);
  511. }
  512. }
  513. STATIC
  514. VOID
  515. NwpGetInteractiveCredentials(
  516. IN HANDLE LsaHandle,
  517. IN ULONG AuthPackageId
  518. )
  519. /*++
  520. Routine Description:
  521. This function reads the interactive logon IDs from the registry
  522. so that it can get the interactive credentials from LSA. It then
  523. notifies the redirector of the interactive logons.
  524. Arguments:
  525. LsaHandle - Supplies the handle to LSA.
  526. AuthPackageId - Supplies the NetWare authentication package ID.
  527. Return Value:
  528. None.
  529. --*/
  530. {
  531. DWORD status;
  532. LONG RegError;
  533. LPWSTR UserName = NULL;
  534. LPWSTR Password = NULL;
  535. HKEY InteractiveLogonKey;
  536. DWORD Index = 0;
  537. WCHAR LogonIdName[NW_MAX_LOGON_ID_LEN];
  538. LUID LogonId;
  539. DWORD PrintOption;
  540. HKEY WkstaOptionKey = NULL;
  541. HKEY CurrentUserOptionKey = NULL;
  542. HKEY OneLogonKey;
  543. LPWSTR UserSid = NULL;
  544. PDWORD pPrintOption = NULL;
  545. LPWSTR PreferredServer = NULL;
  546. LPWSTR NdsPreferredServer = NULL;
  547. RegError = RegOpenKeyExW(
  548. HKEY_LOCAL_MACHINE,
  549. NW_INTERACTIVE_LOGON_REGKEY,
  550. REG_OPTION_NON_VOLATILE,
  551. KEY_READ,
  552. &InteractiveLogonKey
  553. );
  554. if (RegError == ERROR_SUCCESS) {
  555. do {
  556. RegError = RegEnumKeyW(
  557. InteractiveLogonKey,
  558. Index,
  559. LogonIdName,
  560. sizeof(LogonIdName) / sizeof(WCHAR)
  561. );
  562. if (RegError == ERROR_SUCCESS) {
  563. //
  564. // Got a logon id key.
  565. //
  566. NwWStrToLuid(LogonIdName, &LogonId);
  567. status = NwpGetCredentialInLsa(
  568. LsaHandle,
  569. AuthPackageId,
  570. &LogonId,
  571. &UserName,
  572. &Password
  573. );
  574. if (status == NO_ERROR) {
  575. UserSid = NULL;
  576. //
  577. // Open the <LogonIdName> key under Logon
  578. //
  579. RegError = RegOpenKeyExW(
  580. InteractiveLogonKey,
  581. LogonIdName,
  582. REG_OPTION_NON_VOLATILE,
  583. KEY_READ,
  584. &OneLogonKey
  585. );
  586. if ( RegError != ERROR_SUCCESS ) {
  587. KdPrint(("NWWORKSTATION: NwpGetInteractiveLogonCredential: RegOpenKeyExW failed, Not interactive Logon: Error %d\n", GetLastError()));
  588. }
  589. else {
  590. //
  591. // Read the SID value.
  592. //
  593. status = NwReadRegValue(
  594. OneLogonKey,
  595. NW_SID_VALUENAME,
  596. (LPWSTR *) &UserSid
  597. );
  598. (void) RegCloseKey(OneLogonKey);
  599. if ( status != NO_ERROR ) {
  600. KdPrint(("NWWORKSTATION: NwpGetInteractiveLogonCredential: Could not read SID from reg %lu\n", status));
  601. UserSid = NULL;
  602. }
  603. }
  604. if ( UserSid ) {
  605. PrintOption = NW_PRINT_OPTION_DEFAULT;
  606. PreferredServer = NULL;
  607. //
  608. // Open HKEY_LOCAL_MACHINE\System\CurrentControlSet
  609. // \Services\NWCWorkstation\Parameters\Option
  610. //
  611. RegError = RegOpenKeyExW(
  612. HKEY_LOCAL_MACHINE,
  613. NW_WORKSTATION_OPTION_REGKEY,
  614. REG_OPTION_NON_VOLATILE, // options
  615. KEY_READ, // desired access
  616. &WkstaOptionKey
  617. );
  618. if (RegError != ERROR_SUCCESS) {
  619. KdPrint(("NWWORKSTATION: NwpGetInteractiveCredentials: RegOpenKeyExW Parameter\\Option returns unexpected error %lu!!\n",
  620. RegError));
  621. goto NoOption;
  622. }
  623. //
  624. // Open the <UserSid> key under Option
  625. //
  626. RegError = RegOpenKeyExW(
  627. WkstaOptionKey,
  628. UserSid,
  629. REG_OPTION_NON_VOLATILE,
  630. KEY_READ,
  631. &CurrentUserOptionKey
  632. );
  633. if (RegError != ERROR_SUCCESS) {
  634. KdPrint(("NWWORKSTATION: NwpGetInteractiveCredentials: RegOpenKeyExW Parameter\\Option\\SID returns unexpected error %lu!!\n",
  635. RegError));
  636. (void) RegCloseKey(WkstaOptionKey);
  637. goto NoOption;
  638. }
  639. //
  640. // Read the preferred server value.
  641. //
  642. status = NwReadRegValue(
  643. CurrentUserOptionKey,
  644. NW_SERVER_VALUENAME,
  645. &PreferredServer
  646. );
  647. if (status != NO_ERROR) {
  648. KdPrint(("NWWORKSTATION: NwpGetInteractiveCredentials: Could not read preferred server from reg %lu\n", status));
  649. PreferredServer = NULL;
  650. }
  651. //
  652. // Read the preferred NDS server value (if one exists).
  653. //
  654. status = NwReadRegValue(
  655. CurrentUserOptionKey,
  656. NW_NDS_SERVER_VALUENAME,
  657. &NdsPreferredServer
  658. );
  659. if (status != NO_ERROR) {
  660. #if DBG
  661. IF_DEBUG(LOGON) {
  662. KdPrint(("NWWORKSTATION: NwGetLogonCredential: Could not read preferred NDS server from reg %lu\n", status));
  663. }
  664. #endif
  665. NdsPreferredServer = NULL;
  666. }
  667. //
  668. // Read the print option value.
  669. //
  670. status = NwReadRegValue(
  671. CurrentUserOptionKey,
  672. NW_PRINTOPTION_VALUENAME,
  673. (LPWSTR *) &pPrintOption
  674. );
  675. if (status != NO_ERROR) {
  676. #if DBG
  677. IF_DEBUG(LOGON) {
  678. KdPrint(("NWWORKSTATION: NwGetLogonCredential: Could not read print option from reg %lu\n", status));
  679. }
  680. #endif
  681. PrintOption = NW_PRINT_OPTION_DEFAULT;
  682. }
  683. else {
  684. if ( pPrintOption != NULL ) {
  685. PrintOption = *pPrintOption;
  686. (void) LocalFree((HLOCAL) pPrintOption);
  687. pPrintOption = NULL;
  688. }
  689. else {
  690. PrintOption = NW_PRINT_OPTION_DEFAULT;
  691. }
  692. }
  693. (void) RegCloseKey(CurrentUserOptionKey);
  694. (void) RegCloseKey(WkstaOptionKey);
  695. NoOption:
  696. (void) NwRdrLogonUser(
  697. &LogonId,
  698. UserName,
  699. wcslen(UserName) * sizeof(WCHAR),
  700. Password,
  701. wcslen(Password) * sizeof(WCHAR),
  702. PreferredServer,
  703. ((PreferredServer != NULL) ?
  704. wcslen(PreferredServer) * sizeof(WCHAR) :
  705. 0),
  706. NdsPreferredServer,
  707. ((NdsPreferredServer != NULL) ?
  708. wcslen(NdsPreferredServer) * sizeof(WCHAR) :
  709. 0),
  710. PrintOption
  711. );
  712. //
  713. // Freeing the UserName pointer frees both the
  714. // username and password buffers.
  715. //
  716. (void) LsaFreeReturnBuffer((PVOID) UserName);
  717. if (UserSid != NULL) {
  718. (void) LocalFree((HLOCAL) UserSid);
  719. UserSid = NULL;
  720. }
  721. if (PreferredServer != NULL) {
  722. (void) LocalFree((HLOCAL) PreferredServer);
  723. PreferredServer = NULL;
  724. }
  725. }
  726. }
  727. }
  728. else if (RegError != ERROR_NO_MORE_ITEMS) {
  729. KdPrint(("NWWORKSTATION: NwpGetInteractiveCredentials failed to enum logon IDs RegError=%lu\n",
  730. RegError));
  731. }
  732. Index++;
  733. } while (RegError == ERROR_SUCCESS);
  734. (void) RegCloseKey(InteractiveLogonKey);
  735. }
  736. }
  737. DWORD
  738. NwGatewayLogon(
  739. VOID
  740. )
  741. /*++
  742. Routine Description:
  743. This function reads the gateway logon credential from the registry,
  744. LSA secret, and does the gateway logon.
  745. Arguments:
  746. None.
  747. Return Value:
  748. NO_ERROR or reason for failure.
  749. --*/
  750. {
  751. DWORD status = NO_ERROR;
  752. LONG RegError;
  753. LUID LogonId = SYSTEM_LUID ;
  754. DWORD GatewayEnabled, RegValueType, GatewayEnabledSize ;
  755. HKEY WkstaKey = NULL;
  756. LPWSTR GatewayAccount = NULL;
  757. PUNICODE_STRING Password = NULL;
  758. PUNICODE_STRING OldPassword = NULL;
  759. //
  760. // Open HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services
  761. // \NWCWorkstation\Parameters
  762. //
  763. RegError = RegOpenKeyExW(
  764. HKEY_LOCAL_MACHINE,
  765. NW_WORKSTATION_REGKEY,
  766. REG_OPTION_NON_VOLATILE, // options
  767. KEY_READ, // desired access
  768. &WkstaKey
  769. );
  770. if (RegError != ERROR_SUCCESS) {
  771. return RegError;
  772. }
  773. //
  774. // Check to see if it is enabled
  775. //
  776. RegValueType = REG_DWORD ;
  777. GatewayEnabled = 0 ;
  778. GatewayEnabledSize = sizeof(GatewayEnabled) ;
  779. RegError = RegQueryValueExW(
  780. WkstaKey,
  781. NW_GATEWAY_ENABLE,
  782. NULL,
  783. &RegValueType,
  784. (LPBYTE)&GatewayEnabled,
  785. &GatewayEnabledSize) ;
  786. if (status != NO_ERROR || GatewayEnabled == 0) {
  787. goto CleanExit;
  788. }
  789. //
  790. // Read the gateway account from the registry.
  791. //
  792. status = NwReadRegValue(
  793. WkstaKey,
  794. NW_GATEWAYACCOUNT_VALUENAME,
  795. &GatewayAccount
  796. );
  797. if (status != NO_ERROR) {
  798. goto CleanExit;
  799. }
  800. //
  801. // Read the password from its secret object in LSA.
  802. //
  803. status = NwGetPassword(
  804. GATEWAY_USER,
  805. &Password, // Must be freed with LsaFreeMemory
  806. &OldPassword // Must be freed with LsaFreeMemory
  807. );
  808. if (status != NO_ERROR) {
  809. goto CleanExit;
  810. }
  811. EnterCriticalSection(&NwLoggedOnCritSec);
  812. status = NwRdrLogonUser(
  813. &LogonId,
  814. GatewayAccount,
  815. ((GatewayAccount != NULL) ?
  816. wcslen(GatewayAccount) * sizeof(WCHAR) :
  817. 0),
  818. Password->Buffer,
  819. Password->Length,
  820. NULL,
  821. 0,
  822. NULL,
  823. 0,
  824. NwGatewayPrintOption );
  825. if (status == NO_ERROR)
  826. GatewayLoggedOn = TRUE ;
  827. LeaveCriticalSection(&NwLoggedOnCritSec);
  828. if (status != NO_ERROR)
  829. {
  830. //
  831. // log the error in the event log
  832. //
  833. WCHAR Number[16] ;
  834. LPWSTR InsertStrings[1] ;
  835. wsprintfW(Number, L"%d", status) ;
  836. InsertStrings[0] = Number ;
  837. NwLogEvent(EVENT_NWWKSTA_GATEWAY_LOGON_FAILED,
  838. 1,
  839. InsertStrings,
  840. 0) ;
  841. }
  842. else
  843. {
  844. //
  845. // create the gateway redirections if any. not fatal if error.
  846. // the function will log any errors to event log.
  847. //
  848. if (Password->Length)
  849. {
  850. LPWSTR Passwd = (LPWSTR) LocalAlloc(LPTR,
  851. Password->Length + sizeof(WCHAR)) ;
  852. if (Passwd)
  853. {
  854. wcsncpy(Passwd,
  855. Password->Buffer,
  856. Password->Length / sizeof(WCHAR)) ;
  857. (void) NwCreateRedirections(GatewayAccount,
  858. Passwd) ;
  859. RtlZeroMemory((LPBYTE)Passwd,
  860. Password->Length) ;
  861. (void) LocalFree((HLOCAL)Passwd);
  862. }
  863. }
  864. else
  865. {
  866. (void) NwCreateRedirections(GatewayAccount,
  867. NULL) ;
  868. }
  869. }
  870. CleanExit:
  871. if (Password != NULL) {
  872. if (Password->Buffer)
  873. RtlZeroMemory(Password->Buffer, Password->Length) ;
  874. (void) LsaFreeMemory((PVOID) Password);
  875. }
  876. if (OldPassword != NULL) {
  877. if (OldPassword->Buffer)
  878. RtlZeroMemory(OldPassword->Buffer, OldPassword->Length) ;
  879. (void) LsaFreeMemory((PVOID) OldPassword);
  880. }
  881. if (GatewayAccount != NULL) {
  882. (void) LocalFree((HLOCAL) GatewayAccount);
  883. }
  884. (void) RegCloseKey(WkstaKey);
  885. return status ;
  886. }
  887. DWORD
  888. NwGatewayLogoff(
  889. VOID
  890. )
  891. /*++
  892. Routine Description:
  893. This function logs off the gateway account.
  894. Arguments:
  895. None.
  896. Return Value:
  897. NO_ERROR or reason for failure.
  898. --*/
  899. {
  900. DWORD status = NO_ERROR;
  901. LUID LogonId = SYSTEM_LUID ;
  902. EnterCriticalSection(&NwLoggedOnCritSec);
  903. if (GatewayLoggedOn)
  904. {
  905. status = NwRdrLogoffUser(&LogonId);
  906. if (status == NO_ERROR)
  907. GatewayLoggedOn = FALSE ;
  908. }
  909. LeaveCriticalSection(&NwLoggedOnCritSec);
  910. return status ;
  911. }
  912. STATIC
  913. DWORD
  914. NwpRegisterLogonProcess(
  915. OUT PHANDLE LsaHandle,
  916. OUT PULONG AuthPackageId
  917. )
  918. /*++
  919. Routine Description:
  920. This function registers the workstation service as a logon process
  921. so that it can call LSA to retrieve user credentials.
  922. Arguments:
  923. LsaHandle - Receives the handle to LSA.
  924. AuthPackageId - Receives the NetWare authentication package ID.
  925. Return Value:
  926. NO_ERROR or reason for failure.
  927. --*/
  928. {
  929. DWORD status = NO_ERROR;
  930. NTSTATUS ntstatus;
  931. STRING InputString;
  932. LSA_OPERATIONAL_MODE SecurityMode = 0;
  933. //
  934. // Register this process as a logon process so that we can call
  935. // NetWare authentication package.
  936. //
  937. RtlInitString(&InputString, "Client Service for NetWare");
  938. ntstatus = LsaRegisterLogonProcess(
  939. &InputString,
  940. LsaHandle,
  941. &SecurityMode
  942. );
  943. if (! NT_SUCCESS(ntstatus)) {
  944. KdPrint(("NWPROVAU: NwInitializeLogon: LsaRegisterLogonProcess returns x%08lx\n",
  945. ntstatus));
  946. return RtlNtStatusToDosError(ntstatus);
  947. }
  948. //
  949. // Look up the Netware authentication package
  950. //
  951. RtlInitString(&InputString, NW_AUTH_PACKAGE_NAME);
  952. ntstatus = LsaLookupAuthenticationPackage(
  953. *LsaHandle,
  954. &InputString,
  955. AuthPackageId
  956. );
  957. if (! NT_SUCCESS(ntstatus)) {
  958. KdPrint(("NWPROVAU: NwpSetCredential: LsaLookupAuthenticationPackage returns x%08lx\n",
  959. ntstatus));
  960. (void) LsaDeregisterLogonProcess(*LsaHandle);
  961. }
  962. status = RtlNtStatusToDosError(ntstatus);
  963. return status;
  964. }
  965. STATIC
  966. DWORD
  967. NwpGetCredentialInLsa(
  968. IN HANDLE LsaHandle,
  969. IN ULONG AuthPackageId,
  970. IN PLUID LogonId,
  971. OUT LPWSTR *UserName,
  972. OUT LPWSTR *Password
  973. )
  974. /*++
  975. Routine Description:
  976. This function retrieves the username and password information
  977. from LSA given the logon ID.
  978. Arguments:
  979. LsaHandle - Supplies the handle to LSA.
  980. AuthPackageId - Supplies the NetWare authentication package ID.
  981. LogonId - Supplies the logon ID.
  982. UserName - Receives a pointer to the username.
  983. Password - Receives a pointer to the password.
  984. Return Value:
  985. NO_ERROR or reason for failure.
  986. --*/
  987. {
  988. DWORD status;
  989. NTSTATUS ntstatus;
  990. NTSTATUS AuthPackageStatus;
  991. NWAUTH_GET_CREDENTIAL_REQUEST GetCredRequest;
  992. PNWAUTH_GET_CREDENTIAL_RESPONSE GetCredResponse;
  993. ULONG ResponseLength;
  994. UNICODE_STRING PasswordStr;
  995. //
  996. // Ask authentication package for credential.
  997. //
  998. GetCredRequest.MessageType = NwAuth_GetCredential;
  999. RtlCopyLuid(&GetCredRequest.LogonId, LogonId);
  1000. ntstatus = LsaCallAuthenticationPackage(
  1001. LsaHandle,
  1002. AuthPackageId,
  1003. &GetCredRequest,
  1004. sizeof(GetCredRequest),
  1005. (PVOID *) &GetCredResponse,
  1006. &ResponseLength,
  1007. &AuthPackageStatus
  1008. );
  1009. if (NT_SUCCESS(ntstatus)) {
  1010. ntstatus = AuthPackageStatus;
  1011. }
  1012. if (! NT_SUCCESS(ntstatus)) {
  1013. KdPrint(("NWPROVAU: NwpGetCredentialInLsa: LsaCallAuthenticationPackage returns x%08lx\n",
  1014. ntstatus));
  1015. status = RtlNtStatusToDosError(ntstatus);
  1016. }
  1017. else {
  1018. *UserName = GetCredResponse->UserName;
  1019. *Password = GetCredResponse->Password;
  1020. //
  1021. // Decode the password.
  1022. //
  1023. RtlInitUnicodeString(&PasswordStr, GetCredResponse->Password);
  1024. RtlRunDecodeUnicodeString(NW_ENCODE_SEED, &PasswordStr);
  1025. status = NO_ERROR;
  1026. }
  1027. return status;
  1028. }
  1029. DWORD
  1030. NwrChangePassword(
  1031. IN LPWSTR Reserved OPTIONAL,
  1032. IN DWORD UserLuid,
  1033. IN LPWSTR UserName,
  1034. IN LPWSTR OldPassword,
  1035. IN LPWSTR NewPassword,
  1036. IN LPWSTR TreeName
  1037. )
  1038. /*++
  1039. Routine Description:
  1040. This function changes the password for the specified user on
  1041. the list of servers. If we encounter a failure on changing
  1042. password for a particular server, we:
  1043. 1) Send the new password over to the server to verify if it is
  1044. already the current password.
  1045. 2) If not, return ERROR_INVALID_PASSWORD and the index into
  1046. the Servers array indicating the server which failed so that
  1047. we can prompt the user to enter an alternate old password.
  1048. When the password has been changed successfully on a server, we
  1049. notify the redirector so that the cached credential can be updated.
  1050. NOTE: All errors returned from this routine, except for the fatal
  1051. ERROR_NOT_ENOUGH_MEMORY error, indicates that the password
  1052. could not be changed on a particular server indexed by
  1053. LastProcessed. The client-side continues to call us with
  1054. the remaining list of servers.
  1055. If you add to this routine to return other fatal errors,
  1056. please make sure the client-side code aborts from calling
  1057. us with the rest of the servers on getting those errors.
  1058. Arguments:
  1059. Reserved - Must be NULL.
  1060. Return Value:
  1061. ERROR_BAD_NETPATH - Could not connect to the server indexed by
  1062. LastProcessed.
  1063. ERROR_BAD_USERNAME - The username could not be found on the server
  1064. indexed by LastProcessed.
  1065. ERROR_INVALID_PASSWORD - The change password operation failed on
  1066. the server indexed by LastProcessed.
  1067. ERROR_NOT_ENOUGH_MEMORY - Out of memory error. This fatal error
  1068. will terminate the client-side from trying to process password
  1069. change request on the remaining servers.
  1070. --*/
  1071. {
  1072. DWORD status;
  1073. NTSTATUS ntstatus;
  1074. HANDLE hNwRdr = NULL;
  1075. UNICODE_STRING UserNameStr;
  1076. UNICODE_STRING OldPasswordStr;
  1077. UNICODE_STRING NewPasswordStr;
  1078. UNICODE_STRING TreeNameStr;
  1079. BOOL fImpersonateClient = FALSE;
  1080. UNREFERENCED_PARAMETER( Reserved ) ;
  1081. UNREFERENCED_PARAMETER( UserLuid ) ;
  1082. RtlInitUnicodeString( &UserNameStr, UserName );
  1083. RtlInitUnicodeString( &OldPasswordStr, OldPassword );
  1084. RtlRunDecodeUnicodeString( NW_ENCODE_SEED2, &OldPasswordStr );
  1085. RtlInitUnicodeString( &NewPasswordStr, NewPassword );
  1086. RtlRunDecodeUnicodeString( NW_ENCODE_SEED2, &NewPasswordStr );
  1087. RtlInitUnicodeString( &TreeNameStr, TreeName );
  1088. //
  1089. // Impersonate the client
  1090. //
  1091. if ((status = NwImpersonateClient()) != NO_ERROR)
  1092. {
  1093. goto ErrorExit;
  1094. }
  1095. fImpersonateClient = TRUE;
  1096. //
  1097. // Open a NDS tree connection handle to \\treename
  1098. //
  1099. ntstatus = NwNdsOpenTreeHandle( &TreeNameStr, &hNwRdr );
  1100. if ( ntstatus != STATUS_SUCCESS )
  1101. {
  1102. status = RtlNtStatusToDosError(ntstatus);
  1103. goto ErrorExit;
  1104. }
  1105. (void) NwRevertToSelf() ;
  1106. fImpersonateClient = FALSE;
  1107. ntstatus = NwNdsChangePassword( hNwRdr,
  1108. &TreeNameStr,
  1109. &UserNameStr,
  1110. &OldPasswordStr,
  1111. &NewPasswordStr );
  1112. if ( ntstatus != NO_ERROR )
  1113. {
  1114. status = RtlNtStatusToDosError(ntstatus);
  1115. goto ErrorExit;
  1116. }
  1117. CloseHandle( hNwRdr );
  1118. hNwRdr = NULL;
  1119. return NO_ERROR ;
  1120. ErrorExit:
  1121. if ( fImpersonateClient )
  1122. (void) NwRevertToSelf() ;
  1123. if ( hNwRdr )
  1124. CloseHandle( hNwRdr );
  1125. hNwRdr = NULL;
  1126. return status;
  1127. }