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.

1314 lines
41 KiB

  1. /*++
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. credman.cxx
  5. Abstract:
  6. WNet Credential Management API functions
  7. Author:
  8. Dan Lafferty (danl) 07-Dec-1992
  9. Environment:
  10. User Mode - Win32
  11. Revision History:
  12. 05-May-1999 jschwart
  13. Make provider addition/removal dynamic
  14. 19-Apr-1994 danl
  15. Fix timeout logic where we would ignore the
  16. provider-supplied timeout if the timeout was smaller than the default.
  17. Now, if all the providers know their timeouts, the larger of those
  18. timeouts is used. Even if smaller than the default.
  19. 09-Jun-1993 danl
  20. Fixed MaxWait in MprCheckTimeout() so that now it is passed in.
  21. Until now, it was left uninitialized.
  22. 07-Apr-1993 danl
  23. Initialize the pointer to the logon script to NULL prior to passing
  24. it to the provider to fill in. We are expecting it to be NULL if
  25. they don't have a logon script.
  26. 18-Jan-1993 danl
  27. WNetLogonNotify: If the provider returns an error that mpr
  28. doesn't understand, it should discontinue calling that provider.
  29. This is accomplished by setting the ContinueFlag for that provider
  30. to FALSE.
  31. 07-Dec-1992 danl
  32. Created
  33. --*/
  34. //
  35. // INCLUDES
  36. //
  37. #include "precomp.hxx"
  38. #include <tstr.h> // WCSSIZE
  39. //
  40. // DEFINES
  41. //
  42. typedef struct _RETRY_INFO {
  43. DWORD ProviderIndex;
  44. DWORD Status;
  45. DWORD ProviderWait;
  46. BOOL ContinueFlag;
  47. LPWSTR LogonScript;
  48. } RETRY_INFO, *LPRETRY_INFO;
  49. //
  50. // LOCAL FUNCTIONS
  51. //
  52. DWORD
  53. MprMakeRetryArray(
  54. LPCWSTR lpPrimaryAuthenticator,
  55. LPDWORD lpNumProviders,
  56. LPRETRY_INFO *lpRetryArray,
  57. LPDWORD lpRegMaxWait
  58. );
  59. VOID
  60. MprUpdateTimeout(
  61. LPRETRY_INFO RetryArray,
  62. LPPROVIDER Provider,
  63. DWORD RegMaxWait,
  64. LPDWORD pMaxWait,
  65. DWORD StartTime,
  66. DWORD CallStatus
  67. );
  68. VOID
  69. MprCheckTimeout(
  70. BOOL *ContinueFlag,
  71. DWORD StartTime,
  72. DWORD MaxWait,
  73. LPDWORD lpStatus
  74. );
  75. DWORD APIENTRY
  76. WNetLogonNotify(
  77. LPCWSTR lpPrimaryAuthenticator,
  78. PLUID lpLogonId,
  79. LPCWSTR lpAuthentInfoType,
  80. LPVOID lpAuthentInfo,
  81. LPCWSTR lpPreviousAuthentInfoType, // may be NULL
  82. LPVOID lpPreviousAuthentInfo, // may be NULL
  83. LPWSTR lpStationName,
  84. LPVOID StationHandle,
  85. LPWSTR *lpLogonScripts
  86. )
  87. /*++
  88. Description:
  89. This function provides notification to provider dll's that must handle
  90. log-on events.
  91. Each Credential Manager Provider is allowed to return
  92. a single command line string which will execute a logon script.
  93. WNetLogonNotify gathers these strings into a MULTI_SZ string buffer.
  94. (Meaning each string is NULL terminated, and the set of strings is
  95. NULL terminated - thus making the last string doubly NULL terminated).
  96. !! IMPORTANT !!
  97. The caller of this function is responsible for freeing the
  98. buffer pointed to by *lpLogonScripts. The windows API function
  99. LocalFree() should be used to do this.
  100. Arguments:
  101. lpPrimaryAuthenticator - This is a pointer to a string that identifies
  102. the primary authenticator. The router uses this information to
  103. skip the credential manager identified by this string. Since it
  104. is the primary, it has already handled the logon. This string is
  105. obtained from the "\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\
  106. Services\*(keyname)\NetworkProvider\Name" registry value.
  107. lpLogonId - The logon ID of the session currently being logged on.
  108. lpAuthentInfoType - This points to a string that identifies the
  109. AuthentInfo structure type.
  110. When Microsoft is the primary authenticator, the values that may
  111. be expected here are the ones described for the lpAuthentInfoType
  112. parameter to NPLogonNotify().
  113. lpAuthentInfo - This points to a structure that contains the
  114. credentials used to successfully log the user on via the
  115. primary authenticator. The structures that may be specified when
  116. using Micosoft's primary authenticator are:
  117. When Microsoft is the primary authenticator, the structures that
  118. may be expected here are the ones described for the lpAuthentInfo
  119. parameter to NPLogonNotify().
  120. lpPreviousAuthentInfoType - This is pointer to a string that identifies
  121. the PreviousAuthentInfo structure. If this pointer is NULL, then
  122. no PreviousAuthentInfo is available.
  123. The values that may be expected here are the same as the values that
  124. may be expected for the lpAuthentInfoType parameter.
  125. lpPreviousAuthentInfo - If the user was forced to change the password
  126. prioir to logging on, this points to a AuthentInfo structure that
  127. will contain the credential information used prior to the password
  128. change. If the user was not forced to change the password prior
  129. to logging on, then this pointer is NULL.
  130. The structures that may be expected here are the same as the
  131. structures that may be expected for the lpAuthentInfo parameter.
  132. lpStationName - This parameter contains the name of the station the
  133. user has logged onto. This may be used to determine whether or
  134. not interaction with the user to obtain additional (provider-specific)
  135. credentials is possible. This information will also have a bearing
  136. on the meaning and use of the StationHandle parameter.
  137. When Microsoft is the primary authenticator, the values that
  138. may be expected here are the ones described for the lpStationName
  139. parameter to NPLogonNotify().
  140. StationHandle - Is a 32-bit value whose meaning is dependent upon the
  141. name (and consequently, the type) of station being logged onto.
  142. When Microsoft is the primary authenticator, the values that
  143. may be expected here are the ones described for the lpStationHandle
  144. parameter to NPLogonNotify().
  145. lpLogonScripts - This is a pointer to a location where a pointer to
  146. a MULTI_SZ string may be returned. Each null terminated
  147. string in the MULTI_SZ string is assumed to contain the name
  148. of a program to execute and parameters to pass to the program.
  149. The memory allocated to hold the returned string must be
  150. deallocatable by the calling routine. The caller of this
  151. routine is responsible for freeing the memory used to house
  152. this string when it is no longer needed.
  153. Return Value:
  154. --*/
  155. {
  156. DWORD status = WN_SUCCESS;
  157. DWORD numProviders;
  158. LPPROVIDER provider;
  159. BOOL fcnSupported = FALSE; // Is fcn supported by a provider?
  160. DWORD i;
  161. BOOL ContinueFlag;
  162. LPRETRY_INFO RetryArray;
  163. DWORD RegMaxWait=0;
  164. DWORD MaxWait=0;
  165. DWORD StartTime;
  166. DWORD scriptSize=0;
  167. LPWSTR pScript;
  168. MprCheckProviders();
  169. CProviderSharedLock PLock;
  170. INIT_IF_NECESSARY(CREDENTIAL_LEVEL,status);
  171. MPR_LOG0(TRACE,"Entered WNetLogonNotify\n");
  172. //
  173. // Now create an array of information about the providers so that we
  174. // can retry until timeout, or all providers are functional.
  175. // Note: The Status field in each retry array element is initialized
  176. // WN_NO_NETWORK.
  177. //
  178. __try {
  179. *lpLogonScripts = NULL;
  180. status = MprMakeRetryArray(
  181. lpPrimaryAuthenticator,
  182. &numProviders,
  183. &RetryArray,
  184. &RegMaxWait);
  185. }
  186. __except(EXCEPTION_EXECUTE_HANDLER) {
  187. status = GetExceptionCode();
  188. if (status != EXCEPTION_ACCESS_VIOLATION) {
  189. MPR_LOG(ERROR,"WNetLogonNotify:Unexpected Exception 0x%lx\n",status);
  190. }
  191. status = WN_BAD_POINTER;
  192. }
  193. if ((status != WN_SUCCESS) || (numProviders == 0)) {
  194. MPR_LOG2(TRACE,"WNetLogonNotify: Error - status=%d, numProviders=%d\n",
  195. status,numProviders);
  196. return(status);
  197. }
  198. //
  199. // Initialize the timer.
  200. //
  201. if (RegMaxWait != 0) {
  202. MaxWait = RegMaxWait;
  203. }
  204. StartTime = GetTickCount();
  205. //
  206. // Loop through the list of providers notifying each one in turn.
  207. // If the underlying service or driver is not available for the
  208. // provider such that it cannot complete this call, then we will
  209. // wait for it to become available.
  210. //
  211. do {
  212. ContinueFlag = FALSE;
  213. for (i=0; i<numProviders; i++) {
  214. //
  215. // Call the appropriate provider's API entry point
  216. //
  217. provider = GlobalProviderInfo + RetryArray[i].ProviderIndex;
  218. if ((RetryArray[i].ContinueFlag) &&
  219. (provider->LogonNotify != NULL)) {
  220. fcnSupported = TRUE;
  221. RetryArray[i].LogonScript = NULL;
  222. __try {
  223. MPR_LOG(TRACE,"Calling (%ws) LogonNotify function\n",
  224. provider->Resource.lpProvider);
  225. status = provider->LogonNotify(
  226. lpLogonId,
  227. lpAuthentInfoType,
  228. lpAuthentInfo,
  229. lpPreviousAuthentInfoType,
  230. lpPreviousAuthentInfo,
  231. lpStationName,
  232. StationHandle,
  233. (LPWSTR *)&(RetryArray[i].LogonScript));
  234. }
  235. __except(EXCEPTION_EXECUTE_HANDLER) {
  236. status = GetExceptionCode();
  237. if (status != EXCEPTION_ACCESS_VIOLATION) {
  238. MPR_LOG(ERROR,"WNetLogonNotify:Unexpected Exception "
  239. "0x%lx\n",status);
  240. }
  241. status = WN_BAD_POINTER;
  242. }
  243. switch (status) {
  244. case WN_SUCCESS:
  245. //
  246. // Because this provider may have put up dialogs, and
  247. // taken a long time to complete, we want to skip the
  248. // timeout check and try all the providers once more.
  249. // We force the index to 0 in order to assure that all
  250. // providers will be tried again prior to checking for
  251. // a timeout.
  252. //
  253. RetryArray[i].Status = WN_SUCCESS;
  254. RetryArray[i].ContinueFlag = FALSE;
  255. if (RetryArray[i].LogonScript != NULL) {
  256. scriptSize += WCSSIZE(RetryArray[i].LogonScript);
  257. }
  258. ContinueFlag = FALSE;
  259. i=0;
  260. break;
  261. case WN_NO_NETWORK:
  262. case WN_FUNCTION_BUSY:
  263. //
  264. // The provider is not ready to be notified (its underlying
  265. // driver or service is not running yet). Attempt to
  266. // find out how long to wait, or if it will ever start.
  267. // This function will update MaxWait if the provider can
  268. // give us a wait hint.
  269. //
  270. MprUpdateTimeout(
  271. &(RetryArray[i]),
  272. provider,
  273. RegMaxWait,
  274. &MaxWait,
  275. StartTime,
  276. status);
  277. break;
  278. default:
  279. RetryArray[i].Status = status;
  280. RetryArray[i].ContinueFlag = FALSE;
  281. break;
  282. } // End Switch (Get providers timeouts).
  283. ContinueFlag |= RetryArray[i].ContinueFlag;
  284. } // end check to see if function is supported.
  285. } // end for i<numProviders.
  286. //
  287. // Check to see if the timeout has expired.
  288. //
  289. MprCheckTimeout(&ContinueFlag, StartTime, MaxWait, &status);
  290. } while (ContinueFlag);
  291. if (fcnSupported == FALSE) {
  292. //
  293. // No providers in the list support the API function. Therefore,
  294. // we assume that no networks are installed.
  295. //
  296. MPR_LOG0(TRACE,"WNetLogonNotify: Function Not Supported\n");
  297. status = WN_NOT_SUPPORTED;
  298. }
  299. //
  300. // Handle normal errors passed back from the provider
  301. //
  302. if (status == WN_SUCCESS){
  303. if (scriptSize != 0) {
  304. //
  305. // There must be some logon scripts. Allocate memory for them.
  306. //
  307. *lpLogonScripts = (LPWSTR)LocalAlloc(
  308. LMEM_FIXED,
  309. scriptSize+sizeof(WCHAR));
  310. if (*lpLogonScripts != NULL) {
  311. //
  312. // Copy the logon scripts into the new buffer.
  313. //
  314. pScript = *lpLogonScripts;
  315. for (i=0;i<numProviders ;i++) {
  316. if ((RetryArray[i].Status == WN_SUCCESS) &&
  317. (RetryArray[i].LogonScript != NULL)) {
  318. wcscpy(pScript, RetryArray[i].LogonScript);
  319. //
  320. // Update the pointer to point beyond the last null
  321. // terminator.
  322. //
  323. pScript += (wcslen(pScript) + 1);
  324. }
  325. }
  326. //
  327. // Add the double NULL terminator.
  328. //
  329. *pScript = L'\0';
  330. }
  331. else {
  332. //
  333. // The allocation failed. (ERROR LOG?)
  334. //
  335. MPR_LOG0(ERROR,"Logon scripts will be lost - could not "
  336. "allocate memory\n");
  337. }
  338. }
  339. }
  340. else {
  341. SetLastError(status);
  342. }
  343. if (RetryArray != NULL) {
  344. LocalFree(RetryArray);
  345. }
  346. MPR_LOG1(TRACE,"Leaving WNetLogonNotify status = %d\n",status);
  347. return(status);
  348. }
  349. DWORD APIENTRY
  350. WNetPasswordChangeNotify(
  351. LPCWSTR lpPrimaryAuthenticator,
  352. LPCWSTR lpAuthentInfoType,
  353. LPVOID lpAuthentInfo,
  354. LPCWSTR lpPreviousAuthentInfoType,
  355. LPVOID lpPreviousAuthentInfo,
  356. LPWSTR lpStationName,
  357. LPVOID StationHandle,
  358. DWORD dwChangeInfo
  359. )
  360. /*++
  361. Description:
  362. This function is used to notify credential managers of a password
  363. change for an account.
  364. Arguments:
  365. lpPrimaryAuthenticator - This is a pointer to a string that identifies
  366. the primary authenticator. Credential Manager does not need the
  367. password notification since it already handled the change.
  368. This string is obtained from the "\HKEY_LOCAL_MACHINE\SYSTEM\
  369. CurrentControlSet\Services\*(keyname)\NetworkProvider\Name" registry
  370. value.
  371. lpAuthentInfoType - This points to a string that identifies the
  372. AuthentInfo structure type.
  373. When Microsoft is the primary authenticator, the values that
  374. may be expected here are the ones described for the
  375. lpAuthentInfoType parameter to NPLogonNotify().
  376. lpAuthentInfo - This points to a structure that contains the
  377. new credentials.
  378. When Microsoft is the primary authenticator, the structures that
  379. may be expected here are the ones described for the lpAuthentInfo
  380. parameter to NPLogonNotify().
  381. lpPreviousAuthentInfoType - This points to the string that identifies
  382. the PreviousAuthentInfo structure type.
  383. The values that may be expected here are the same as the values that
  384. may be expected for the lpAuthentInfoType parameter.
  385. lpPreviousAuthentInfo - This points to an AuthentInfo structure that
  386. contains the previous credential information. (old password and such).
  387. The structures that may be expected here are the same as the
  388. structures that may be expected for the lpAuthentInfo parameter.
  389. lpStationName - This parameter contains the name of the station the
  390. user performed the authentication information change from.
  391. This may be used to determine whether or not interaction with the
  392. user to obtain additional (provider-specific) information is possible.
  393. This information will also have a bearing on the meaning and use of
  394. the StationHandle parameter.
  395. When Microsoft is the primary authenticator, the values that
  396. may be expected here are the ones described for the lpStationName
  397. parameter to NPLogonNotify().
  398. StationHandle - Is a 32-bit value whose meaning is dependent upon the
  399. name (and consequently, the type) of station being logged onto.
  400. When Microsoft is the primary authenticator, the values that
  401. may be expected here are the ones described for the lpStationHandle
  402. parameter to NPLogonNotify().
  403. dwChangeInfo - This is a set of flags that provide information about the
  404. change. Currently the following possible values are defined:
  405. WN_VALID_LOGON_ACCOUNT - If this flag is set, then the
  406. password (or, more accurately, the authentication
  407. information) that was changed will affect future
  408. logons. Some authentication information changes
  409. will only affect connections made in untrusted
  410. domains. These are accounts that the user cannot
  411. use to logon to this machine anyway. In these
  412. cases, this flag will not be set.
  413. Return Value:
  414. Note:
  415. --*/
  416. {
  417. DWORD status = WN_SUCCESS;
  418. LPDWORD indexArray;
  419. DWORD localArray[DEFAULT_MAX_PROVIDERS];
  420. DWORD numProviders;
  421. LPPROVIDER provider;
  422. BOOL fcnSupported = FALSE; // Is fcn supported by a provider?
  423. DWORD i,j;
  424. DWORD primaryIndex;
  425. BOOL oneSuccess=FALSE;
  426. MprCheckProviders();
  427. CProviderSharedLock PLock;
  428. INIT_IF_NECESSARY(CREDENTIAL_LEVEL,status);
  429. //
  430. // Find the list of providers to call for this request.
  431. //
  432. indexArray = localArray;
  433. //
  434. // If there are no active providers, MprFindCallOrder returns
  435. // WN_NO_NETWORK.
  436. //
  437. status = MprFindCallOrder(
  438. NULL,
  439. &indexArray,
  440. &numProviders,
  441. CREDENTIAL_TYPE);
  442. if (status != WN_SUCCESS) {
  443. return(status);
  444. }
  445. __try {
  446. //
  447. // Remove the primary authenticator from the list.
  448. //
  449. if (MprGetProviderIndex((LPTSTR)lpPrimaryAuthenticator,&primaryIndex)) {
  450. for (i=0; i<numProviders ;i++ ) {
  451. if (indexArray[i] == primaryIndex) {
  452. numProviders--;
  453. j=i;
  454. i++;
  455. for (; j<numProviders; i++,j++) {
  456. indexArray[j] = indexArray[i];
  457. }
  458. break;
  459. }
  460. }
  461. }
  462. }
  463. __except(EXCEPTION_EXECUTE_HANDLER) {
  464. status = GetExceptionCode();
  465. if (status != EXCEPTION_ACCESS_VIOLATION) {
  466. MPR_LOG(ERROR,"WNetChangePassword:Unexpected Exception 0x%lx\n",status);
  467. }
  468. status = WN_BAD_POINTER;
  469. }
  470. //
  471. // If there are no credential managers aside from the primary, the
  472. // return with success.
  473. //
  474. if (numProviders == 0) {
  475. if (indexArray != localArray) {
  476. LocalFree(indexArray);
  477. }
  478. return(WN_SUCCESS);
  479. }
  480. //
  481. // Loop through the list of providers notifying each one.
  482. //
  483. for (i=0; i<numProviders; i++) {
  484. //
  485. // Call the appropriate provider's API entry point
  486. //
  487. provider = GlobalProviderInfo + indexArray[i];
  488. if (provider->PasswordChangeNotify != NULL) {
  489. fcnSupported = TRUE;
  490. __try {
  491. MPR_LOG(TRACE,"Calling (%ws) ChangePasswordNotify function\n",
  492. provider->Resource.lpProvider);
  493. status = provider->PasswordChangeNotify(
  494. lpAuthentInfoType,
  495. lpAuthentInfo,
  496. lpPreviousAuthentInfoType,
  497. lpPreviousAuthentInfo,
  498. lpStationName,
  499. StationHandle,
  500. dwChangeInfo);
  501. }
  502. __except(EXCEPTION_EXECUTE_HANDLER) {
  503. status = GetExceptionCode();
  504. if (status != EXCEPTION_ACCESS_VIOLATION) {
  505. MPR_LOG(ERROR,"WNetChangePassword:Unexpected Exception 0x%lx\n",status);
  506. }
  507. status = WN_BAD_POINTER;
  508. }
  509. if (status == WN_SUCCESS) {
  510. //
  511. // If the call was successful, then we indicate that at least
  512. // one of the calls was successful.
  513. //
  514. oneSuccess = TRUE;
  515. }
  516. }
  517. }
  518. if (fcnSupported == FALSE) {
  519. //
  520. // No providers in the list support the API function. Therefore,
  521. // we assume that no networks are installed.
  522. //
  523. status = WN_NOT_SUPPORTED;
  524. }
  525. //
  526. // If memory was allocated by MprFindCallOrder, free it.
  527. //
  528. if (indexArray != localArray) {
  529. LocalFree(indexArray);
  530. }
  531. //
  532. // Handle normal errors passed back from the provider
  533. //
  534. if (oneSuccess == TRUE) {
  535. status = WN_SUCCESS;
  536. }
  537. else {
  538. SetLastError(status);
  539. }
  540. return(status);
  541. }
  542. #ifdef REMOVE
  543. DWORD APIENTRY
  544. WNetLogoffNotify(
  545. HWND hwndOwner,
  546. LPCWSTR lpPrimaryAuthenticator,
  547. PLUID lpLogonId,
  548. WN_OPERATION_TYPE OperationType
  549. )
  550. /*++
  551. Description:
  552. This function provides log-off notification to credential managers.
  553. Arguments:
  554. hwndOwner - Identifies the owner window.
  555. lpPrimaryAuthenticator - This is a pointer to a string that identifies
  556. the primary authenticator. Credential Manager does not need the
  557. password notification since it already handled the change.
  558. lpLogonId - The logon ID of the session currently being logged on.
  559. OperationType - The type of operation. This indicates whether the
  560. function call is from an interactive program (winlogon), or a
  561. background program (service controller). User dialogs should not
  562. be displayed if the call was from a background process.
  563. Return Value:
  564. WN_SUCCESS - This is returned if we are able to successfully notify at
  565. least one of the providers which has registered an entry point for
  566. the Logoff event.
  567. WN_NO_NETWORK - This is returned if there are no providers, or if
  568. there is only one provider, but its supporting service/driver is
  569. not available.
  570. WN_BAD_POINTER - This is returned if one of the pointer parameters
  571. is bad and causes an exception.
  572. WN_NOT_SUPPORTED - This is returned if none of the active providers
  573. support this function.
  574. system errors such as ERROR_OUT_OF_MEMORY are also reported.
  575. Note:
  576. --*/
  577. {
  578. DWORD status = WN_SUCCESS;
  579. LPDWORD indexArray;
  580. DWORD localArray[DEFAULT_MAX_PROVIDERS];
  581. DWORD numProviders;
  582. LPPROVIDER provider;
  583. BOOL fcnSupported = FALSE; // Is fcn supported by a provider?
  584. DWORD i,j;
  585. DWORD primaryIndex;
  586. BOOL oneSuccess=FALSE;
  587. MprCheckProviders();
  588. CProviderSharedLock PLock;
  589. INIT_IF_NECESSARY(CREDENTIAL_LEVEL,status);
  590. //
  591. // Find the list of providers to call for this request.
  592. //
  593. indexArray = localArray;
  594. //
  595. // If there are no active providers, MprFindCallOrder returns
  596. // WN_NO_NETWORK.
  597. //
  598. status = MprFindCallOrder(
  599. NULL,
  600. &indexArray,
  601. &numProviders,
  602. CREDENTIAL_TYPE);
  603. if (status != WN_SUCCESS) {
  604. return(status);
  605. }
  606. try {
  607. //
  608. // Remove the primary authenticator from the list.
  609. //
  610. if (MprGetProviderIndex((LPTSTR)lpPrimaryAuthenticator,&primaryIndex)) {
  611. for (i=0; i<numProviders ;i++ ) {
  612. if (indexArray[i] == primaryIndex) {
  613. numProviders--;
  614. j=i;
  615. i++;
  616. for (; j<numProviders; i++,j++) {
  617. indexArray[j] = indexArray[i];
  618. }
  619. break;
  620. }
  621. }
  622. }
  623. }
  624. except(EXCEPTION_EXECUTE_HANDLER) {
  625. status = GetExceptionCode();
  626. if (status != EXCEPTION_ACCESS_VIOLATION) {
  627. MPR_LOG(ERROR,"WNetChangePassword:Unexpected Exception 0x%lx\n",status);
  628. }
  629. status = WN_BAD_POINTER;
  630. }
  631. //
  632. // If there are no credential managers aside from the primary, the
  633. // return with success.
  634. //
  635. if (numProviders == 0) {
  636. if (indexArray != localArray) {
  637. LocalFree(indexArray);
  638. }
  639. return(WN_SUCCESS);
  640. }
  641. //
  642. // Loop through the list of providers notifying each one.
  643. //
  644. for (i=0; i<numProviders; i++) {
  645. //
  646. // Call the appropriate provider's API entry point
  647. //
  648. provider = GlobalProviderInfo + indexArray[i];
  649. if ((provider->InitClass & CREDENTIAL_TYPE) &&
  650. (provider->LogoffNotify != NULL)) {
  651. fcnSupported = TRUE;
  652. try {
  653. status = provider->LogoffNotify(
  654. hwndOwner,
  655. lpLogonId,
  656. OperationType);
  657. }
  658. except(EXCEPTION_EXECUTE_HANDLER) {
  659. status = GetExceptionCode();
  660. if (status != EXCEPTION_ACCESS_VIOLATION) {
  661. MPR_LOG(ERROR,"WNetLogoffNotify:Unexpected Exception 0x%lx\n",status);
  662. }
  663. status = WN_BAD_POINTER;
  664. }
  665. if (status == WN_SUCCESS) {
  666. //
  667. // If the call was successful, then we indicate that at least
  668. // one of the calls was successful.
  669. //
  670. oneSuccess = TRUE;
  671. }
  672. }
  673. }
  674. if (fcnSupported == FALSE) {
  675. //
  676. // No providers in the list support the API function. Therefore,
  677. // we assume that no networks are installed.
  678. //
  679. status = WN_NOT_SUPPORTED;
  680. }
  681. //
  682. // If memory was allocated by MprFindCallOrder, free it.
  683. //
  684. if (indexArray != localArray) {
  685. LocalFree(indexArray);
  686. }
  687. //
  688. // Handle normal errors passed back from the provider
  689. //
  690. if (oneSuccess == TRUE) {
  691. status = WN_SUCCESS;
  692. }
  693. else {
  694. SetLastError(status);
  695. }
  696. return(status);
  697. }
  698. #endif // REMOVE
  699. DWORD
  700. MprMakeRetryArray(
  701. LPCWSTR lpPrimaryAuthenticator,
  702. LPDWORD lpNumProviders,
  703. LPRETRY_INFO *lpRetryArray,
  704. LPDWORD lpRegMaxWait
  705. )
  706. /*++
  707. Routine Description:
  708. This function returns with an array of RETRY_INFO structures. There is
  709. one array element for each credential manager provider that is NOT
  710. the current primary authenticator. The structures contain such information
  711. as the provider index in the global array of provider information, a
  712. location for the provider's timeout value, status and continue flag.
  713. This function will also attempt to obtain the WaitTimeout from the
  714. registry if it exists.
  715. IMPORTANT!
  716. This function allocates memory for lpRetryArray. The caller is
  717. expected to free this memory with LocalFree(). If an error is
  718. returned, or if the data at lpNumProviders is 0, then memory is
  719. not allocated.
  720. Arguments:
  721. lpPrimaryAuthenticator - This is a pointer to a string that identifies
  722. the primary authenticator. The router uses this information to
  723. skip the credential manager identified by this string. Since it
  724. is the primary, it has already handled the logon.
  725. lpNumProviders - This is a pointer to a location where the number of
  726. providers in the lpRetryArray are stored.
  727. lpRetryArray - This is an array of RETRY_INFO structures. There is one
  728. element in the array for each Credential Manager provider that is
  729. not the current PrimaryAuthenticator. The status in the array is
  730. initialized to WN_NO_NETWORK.
  731. lpRegMaxWait - This is a pointer to the location to where the Maximum
  732. Wait Timeout from the registry is to be placed. If there is no
  733. MaxWait value in the registry, zero is returned.
  734. Return Value:
  735. WN_SUCCESS is returned if we successfully created an array of
  736. RetryInfo structures, or if there are no credential manager providers.
  737. If we are unable to allocate memory for the RetryInfo structures,
  738. then the failure from LocalAlloc is returned.
  739. --*/
  740. {
  741. DWORD status;
  742. DWORD i,j;
  743. HKEY providerKeyHandle;
  744. DWORD primaryIndex;
  745. DWORD ValueType;
  746. DWORD Temp;
  747. DWORD numProviders;
  748. LPDWORD indexArray;
  749. DWORD localArray[DEFAULT_MAX_PROVIDERS];
  750. ASSERT(MPRProviderLock.Have());
  751. //
  752. // Find the list of providers to call for this request.
  753. //
  754. indexArray = localArray;
  755. //
  756. // If there are no active providers, or none of the active providers are
  757. // in this InitClass MprFindCallOrder returns WN_NO_NETWORK.
  758. //
  759. status = MprFindCallOrder(
  760. NULL,
  761. &indexArray,
  762. &numProviders,
  763. CREDENTIAL_TYPE);
  764. if ((status != WN_SUCCESS) || (numProviders == 0)) {
  765. //
  766. // If there aren't any credential managers, then just return.
  767. //
  768. MPR_LOG0(TRACE,"MprMakeRetryArray: There aren't any Credential Managers\n");
  769. *lpNumProviders = 0;
  770. return(WN_SUCCESS);
  771. }
  772. *lpNumProviders = numProviders;
  773. //
  774. // Remove the primary authenticator from the list.
  775. //
  776. if (MprGetProviderIndex((LPTSTR)lpPrimaryAuthenticator,&primaryIndex)) {
  777. for (i=0; i<numProviders ;i++ ) {
  778. if (indexArray[i] == primaryIndex) {
  779. numProviders--;
  780. j=i;
  781. i++;
  782. for (; j<numProviders; i++,j++) {
  783. indexArray[j] = indexArray[i];
  784. }
  785. break;
  786. }
  787. }
  788. //
  789. // If there are no credential managers aside from the primary, the
  790. // return with success.
  791. //
  792. *lpNumProviders = numProviders;
  793. if (numProviders == 0) {
  794. if (indexArray != localArray) {
  795. LocalFree(indexArray);
  796. }
  797. MPR_LOG0(TRACE,"MprMakeRetryArray: There aren't any "
  798. "Credential Managers aside from the Primary\n");
  799. return(WN_SUCCESS);
  800. }
  801. }
  802. //
  803. // At this point the indexArray only contains indices for Credential
  804. // Manager providers that are not the primary authenticator.
  805. //
  806. //
  807. // Now create an array of information about the providers so that we
  808. // can retry until timeout, or all providers are functional. This
  809. // memory is expected to be initialized to zero when allocated.
  810. //
  811. *lpRetryArray = (LPRETRY_INFO)LocalAlloc(LPTR, sizeof(RETRY_INFO) * numProviders);
  812. if (*lpRetryArray == NULL) {
  813. return(GetLastError());
  814. }
  815. for (i=0; i<numProviders; i++) {
  816. (*lpRetryArray)[i].Status = WN_NO_NETWORK;
  817. (*lpRetryArray)[i].ProviderIndex = indexArray[i];
  818. (*lpRetryArray)[i].ContinueFlag = TRUE;
  819. }
  820. if (indexArray != localArray) {
  821. LocalFree(indexArray);
  822. }
  823. //
  824. // Read the MaxWait value that is stored in the registry.
  825. // If it is not there or if the value is less than our default
  826. // maximum value, then use the default instead.
  827. //
  828. if(!MprOpenKey(
  829. HKEY_LOCAL_MACHINE, // hKey
  830. NET_PROVIDER_KEY, // lpSubKey
  831. &providerKeyHandle, // Newly Opened Key Handle
  832. DA_READ)) { // Desired Access
  833. MPR_LOG(ERROR,"MprCreateConnectionArray: MprOpenKey (%ws) Error\n",
  834. NET_PROVIDER_KEY);
  835. *lpRegMaxWait = 0;
  836. return(WN_SUCCESS);
  837. }
  838. MPR_LOG(TRACE,"OpenKey %ws\n",NET_PROVIDER_KEY);
  839. Temp = sizeof(*lpRegMaxWait);
  840. status = RegQueryValueEx(
  841. providerKeyHandle,
  842. RESTORE_WAIT_VALUE,
  843. NULL,
  844. &ValueType,
  845. (LPBYTE)lpRegMaxWait,
  846. &Temp);
  847. if (status != NO_ERROR) {
  848. *lpRegMaxWait = 0;
  849. }
  850. RegCloseKey(providerKeyHandle);
  851. return(WN_SUCCESS);
  852. }
  853. VOID
  854. MprUpdateTimeout(
  855. LPRETRY_INFO RetryInfo,
  856. LPPROVIDER Provider,
  857. DWORD RegMaxWait,
  858. LPDWORD pMaxWait,
  859. DWORD StartTime,
  860. DWORD CallStatus
  861. )
  862. /*++
  863. Routine Description:
  864. This function attempts to get timeout information from the provider.
  865. If the provider will never start, the ContinueFlag in the RetryInfo is
  866. set to FALSE. If the provider tells us how long we should wait, then
  867. MaxWait is updated if that time is longer than the current MaxWait.
  868. Arguments:
  869. RetryInfo - This is a pointer to a structure that contains retry
  870. information for a particular provider.
  871. Provider - This is a pointer to a structure that contains dll
  872. entry points for a particular provider.
  873. RegMaxWait - This is the default timeout. It is either the hard-coded
  874. timeout, or the timeout in the registry.
  875. pMaxWait - This is a pointer to a value that is the maximum amount of
  876. time that the router will wait for the provider to be ready to receive
  877. the function call.
  878. StartTime - This is the clock tick time that we started the operation with.
  879. CallStatus - This is the status from the most recent function call to the
  880. provider.
  881. Return Value:
  882. none
  883. --*/
  884. {
  885. DWORD ElapsedTime;
  886. DWORD CurrentTime;
  887. DWORD providerStatus;
  888. PF_NPGetCaps pGetCaps;
  889. MPR_LOG0(TRACE,"Entering MprUpdateTimeout\n");
  890. ASSERT(MPRProviderLock.Have());
  891. //
  892. // First try the credential manager's GetCaps function.
  893. // if it doesn't exist, then use the network provider's
  894. // function.
  895. //
  896. pGetCaps = Provider->GetAuthentCaps;
  897. if (pGetCaps == NULL) {
  898. pGetCaps = Provider->GetCaps;
  899. }
  900. //
  901. // If this is the first pass through, we don't have the
  902. // wait times figured out for each provider. Do that
  903. // now.
  904. //
  905. if (RetryInfo->ProviderWait == 0) {
  906. MPR_LOG1(TRACE,"Call GetCaps to get (%ws)provider start timeout\n",
  907. Provider->Resource.lpProvider);
  908. if (pGetCaps != NULL) {
  909. providerStatus = pGetCaps(WNNC_START);
  910. switch (providerStatus) {
  911. case PROVIDER_WILL_NOT_START:
  912. MPR_LOG0(TRACE,"Provider will not start\n");
  913. RetryInfo->ContinueFlag = FALSE;
  914. RetryInfo->Status = CallStatus;
  915. break;
  916. case NO_TIME_ESTIMATE:
  917. MPR_LOG0(TRACE,"No Time estimate for Provider start\n");
  918. if (RegMaxWait != 0) {
  919. RetryInfo->ProviderWait = RegMaxWait;
  920. }
  921. else {
  922. RetryInfo->ProviderWait = DEFAULT_WAIT_TIME;
  923. }
  924. if (*pMaxWait < RetryInfo->ProviderWait) {
  925. *pMaxWait = RetryInfo->ProviderWait;
  926. }
  927. break;
  928. default:
  929. MPR_LOG1(TRACE,"Time estimate for Provider start = %d\n",
  930. providerStatus);
  931. //
  932. // In this case, the providerStatus is actually
  933. // the amount of time we should wait for this
  934. // provider. We set MaxWait to the longest of
  935. // the times specified by the providers.
  936. //
  937. if ((providerStatus <= MAX_ALLOWED_WAIT_TIME) &&
  938. (providerStatus > *pMaxWait)) {
  939. *pMaxWait = providerStatus;
  940. }
  941. RetryInfo->ProviderWait = *pMaxWait;
  942. break;
  943. }
  944. }
  945. else {
  946. MPR_LOG0(TRACE,"There is no GetCaps function. So we cannot "
  947. "obtain the provider start timeout\n");
  948. RetryInfo->ContinueFlag = FALSE;
  949. RetryInfo->Status = CallStatus;
  950. }
  951. }
  952. //
  953. // If the status for this provider has just changed to
  954. // WN_FUNCTION_BUSY from some other status, then calculate
  955. // a timeout time by getting the provider's new timeout
  956. // and adding that to the elapsed time since start. This
  957. // gives a total elapsed time until timeout - which can
  958. // be compared with the current MaxWait.
  959. //
  960. if ((CallStatus == WN_FUNCTION_BUSY) &&
  961. (RetryInfo->Status == WN_NO_NETWORK)) {
  962. MPR_LOG1(TRACE,"Provider status just changed to FUNCTION_BUSY "
  963. "from some other status - Call GetCaps to get (%ws)provider "
  964. " start timeout\n",
  965. Provider->Resource.lpProvider);
  966. if (pGetCaps != NULL) {
  967. providerStatus = pGetCaps(WNNC_START);
  968. switch (providerStatus) {
  969. case PROVIDER_WILL_NOT_START:
  970. MPR_LOG0(TRACE,"Provider will not start - bizzare case\n");
  971. //
  972. // This is bizzare to find the status = BUSY,
  973. // and then have the Provider not starting.
  974. //
  975. RetryInfo->ContinueFlag = FALSE;
  976. break;
  977. case NO_TIME_ESTIMATE:
  978. MPR_LOG0(TRACE,"No Time estimate for Provider start\n");
  979. //
  980. // No need to alter the timeout for this one.
  981. //
  982. break;
  983. default:
  984. MPR_LOG1(TRACE,"Time estimate for Provider start = %d\n",
  985. providerStatus);
  986. //
  987. // Make sure this new timeout information will take
  988. // less than the maximum allowed time for
  989. // providers.
  990. //
  991. if (providerStatus <= MAX_ALLOWED_WAIT_TIME) {
  992. CurrentTime = GetTickCount();
  993. //
  994. // Determine how much time has elapsed since
  995. // we started.
  996. //
  997. ElapsedTime = CurrentTime - StartTime;
  998. //
  999. // Add the Elapsed time to the new timeout
  1000. // we just received from the provider to come
  1001. // up with a timeout value that can be
  1002. // compared with MaxWait.
  1003. //
  1004. providerStatus += ElapsedTime;
  1005. //
  1006. // If the new timeout is larger than MaxWait,
  1007. // then use the new timeout.
  1008. //
  1009. if (providerStatus > *pMaxWait) {
  1010. *pMaxWait = providerStatus;
  1011. }
  1012. } // EndIf (Make sure time out is < max allowed).
  1013. break;
  1014. } // End Switch (changed status).
  1015. }
  1016. } // End If (change state from NO_NET to BUSY)
  1017. //
  1018. // Store the status (either NO_NET or BUSY) with the
  1019. // retry info.
  1020. //
  1021. RetryInfo->Status = CallStatus;
  1022. MPR_LOG0(TRACE,"Leaving MprUpdateTimeout\n");
  1023. return;
  1024. }
  1025. VOID
  1026. MprCheckTimeout(
  1027. BOOL *ContinueFlag,
  1028. DWORD StartTime,
  1029. DWORD MaxWait,
  1030. LPDWORD lpStatus
  1031. )
  1032. /*++
  1033. Routine Description:
  1034. This function checks to see if a timeout occured.
  1035. Arguments:
  1036. ContinueFlag - This is a pointer to the location of the continue flag.
  1037. This is set to FALSE if a timeout occured.
  1038. StartTime - This is the tick count at the beginning of the operation.
  1039. lpStatus - This is a pointer to the current status for the operation.
  1040. This is updated only if a timeout occurs.
  1041. Return Value:
  1042. none
  1043. --*/
  1044. {
  1045. DWORD CurrentTime;
  1046. DWORD ElapsedTime;
  1047. MPR_LOG0(TRACE,"Entering MprCheckTimeout\n");
  1048. if (*ContinueFlag) {
  1049. //
  1050. // Determine what the elapsed time from the start is.
  1051. //
  1052. CurrentTime = GetTickCount();
  1053. ElapsedTime = CurrentTime - StartTime;
  1054. //
  1055. // If a timeout occured, then don't continue. Otherwise, sleep
  1056. // for a bit and loop again through all providers.
  1057. //
  1058. if (ElapsedTime > MaxWait) {
  1059. MPR_LOG0(TRACE,"WNetLogonNotify:Timed out while waiting "
  1060. "for Credential Managers\n");
  1061. *ContinueFlag = FALSE;
  1062. *lpStatus = ERROR_SERVICE_REQUEST_TIMEOUT;
  1063. }
  1064. else {
  1065. Sleep(2000);
  1066. }
  1067. }
  1068. MPR_LOG0(TRACE,"Leaving MprCheckTimeout\n");
  1069. }