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.

862 lines
20 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. support.cxx
  5. Abstract:
  6. Contains functions that are used by all MPR API.
  7. MprFindCallOrder
  8. MprInitIndexArray
  9. MprDeleteIndexArray
  10. MprDeviceType
  11. MprGetProviderIndex
  12. MprFindProviderByName
  13. MprFindProviderByType
  14. MprEnterLoadLibCritSect
  15. MprLeaveLoadLibCritSect
  16. MprGetUserName
  17. Author:
  18. Dan Lafferty (danl) 09-Oct-1991
  19. Environment:
  20. User Mode -Win32
  21. Notes:
  22. Revision History:
  23. 05-May-1999 jschwart
  24. Make provider addition/removal dynamic
  25. 15-Jan-1996 anirudhs
  26. Add MprGetUserName.
  27. 22-Jan-1993 danl
  28. FindCallOrder: This code was going through the global array of
  29. providers, rather than looking at only "Active" providers. It should
  30. have been using the GlobalIndexArray which is an array of the indices
  31. for the "Active" providers only.
  32. 02-Nov-1992 danl
  33. Fail with NO_NETWORK if there are no providers.
  34. 09-Oct-1991 danl
  35. created
  36. --*/
  37. //
  38. // INCLUDES
  39. //
  40. #include "precomp.hxx"
  41. #include <string.h> // memcmp
  42. #include <tstring.h> // STRCMP
  43. #include <debugfmt.h> // FORMAT_LPTSTR
  44. #include <lmcons.h> // NET_API_FUNCTION
  45. #include <lmerr.h> // NET_API_STATUS
  46. //
  47. // EXTERNALS
  48. //
  49. extern DWORD GlobalNumActiveProviders;
  50. extern CRITICAL_SECTION MprInitCritSec;
  51. #define DEFAULT_ERROR_BUF_SIZE 1024
  52. //
  53. // MprLoadLibSemaphore global var is used to protect the DLL
  54. // handle and Entry point addresses for delayed loading of MPRUI.DLL.
  55. // It is initialized at process attach time.
  56. //
  57. HANDLE MprLoadLibSemaphore = NULL ;
  58. //
  59. // This is where the pointer to the array of provider indices is stored.
  60. //
  61. /* static */ LPDWORD GlobalIndexArray;
  62. DWORD
  63. MprFindCallOrder(
  64. IN LPTSTR NameInfo,
  65. IN OUT LPDWORD *IndexArrayPtr,
  66. OUT LPDWORD IndexArrayCount,
  67. IN DWORD InitClass
  68. )
  69. /*++
  70. Routine Description:
  71. This function determines the proper order in which to call the
  72. various providers.
  73. This order is based on the ordered list that is stored in the
  74. registry.
  75. Because the provider structures are kept in an array, the indices can
  76. be used to index into that array.
  77. IMPORTANT! : Memory may be allocated for this array, so it
  78. is the responsibility of the caller to free the memory when it is
  79. finished.
  80. Arguments:
  81. NameInfo - This is a pointer to a string that is most likely to
  82. contain the name of the network resource being addressed. If a
  83. NULL pointer, or a pointer to a NULL string is passed in, this
  84. information will be ignored. (Note: Currently this information is
  85. not used).
  86. IndexArrayPtr - This is a pointer to a location where the pointer to
  87. the array of indices resides. On entry, the pointer in this
  88. location points to an array allocated by the caller. This array
  89. is expected to be DEFAULT_MAX_PROVIDERS long. If a larger array
  90. is required, this function will allocate space for it and
  91. replace this pointer with the new one.
  92. IndexArrayCount - This is a pointer to a location where the number of
  93. elements in the returned array is to be placed.
  94. InitClass - This indicates what type of providers we want listed in the
  95. array. The choices are either CREDENTIAL_TYPE or NETWORK_TYPE
  96. providers.
  97. Return Value:
  98. WN_SUCCESS - If the operation was successful.
  99. WN_OUT_OF_MEMORY - If this function was unable to allocate memory for
  100. the return buffer.
  101. WN_NO_NETWORK - If there are no providers available, or none of the
  102. providers support this InitClass.
  103. --*/
  104. {
  105. DWORD i,j;
  106. UNREFERENCED_PARAMETER(NameInfo);
  107. //
  108. // If there are no Providers, then return WN_NO_NETWORK
  109. //
  110. ASSERT(MPR_IS_INITIALIZED(NETWORK) || MPR_IS_INITIALIZED(CREDENTIAL));
  111. ASSERT(MPRProviderLock.Have());
  112. if (GlobalNumActiveProviders == 0) {
  113. return(WN_NO_NETWORK);
  114. }
  115. //
  116. // We cannot interact with active provider information unless we
  117. // have obtained synchronized access. Otherwise we would risk
  118. // trying to read data while it is being modified.
  119. //
  120. EnterCriticalSection(&MprInitCritSec);
  121. if (GlobalNumActiveProviders > DEFAULT_MAX_PROVIDERS) {
  122. *IndexArrayPtr = (LPDWORD) LocalAlloc(LPTR,
  123. GlobalNumProviders*sizeof(DWORD));
  124. if (*IndexArrayPtr == NULL) {
  125. MPR_LOG1(ERROR,"FindCallOrder: LocalAlloc Failed %d\n",GetLastError());
  126. LeaveCriticalSection(&MprInitCritSec);
  127. return (WN_OUT_OF_MEMORY);
  128. }
  129. }
  130. //
  131. // Fill in the array with the order that was obtained from the ordered
  132. // list at initialization time. (Stored in GlobalIndexArray).
  133. //
  134. MPR_LOG0(TRACE,"CallOrder - \n");
  135. for( i=j=0; i<GlobalNumActiveProviders; i++) {
  136. if (GlobalProviderInfo[GlobalIndexArray[i]].InitClass & InitClass) {
  137. (*IndexArrayPtr)[j] = GlobalIndexArray[i];
  138. j++;
  139. }
  140. MPR_LOG1(TRACE,"\tprovider index: %d \n",GlobalIndexArray[i]);
  141. }
  142. MPR_LOG0(TRACE,"\n");
  143. LeaveCriticalSection(&MprInitCritSec);
  144. if (j == 0) {
  145. return(WN_NO_NETWORK);
  146. }
  147. *IndexArrayCount = j;
  148. return(WN_SUCCESS);
  149. }
  150. //+-------------------------------------------------------------------------
  151. //
  152. // Function: CRoutedOperation::FindCallOrder (static)
  153. //
  154. // Purpose: This function determines the proper order in which to call the
  155. // various providers.
  156. // This order is based on the ordered list that is stored in the
  157. // registry.
  158. //
  159. // Arguments:
  160. //
  161. // NameInfo - This is a pointer to a string that is most likely to
  162. // contain the name of the network resource being addressed. If a
  163. // NULL pointer, or a pointer to a NULL string is passed in, this
  164. // information will be ignored.
  165. //
  166. // ProviderArray - This is a pointer to an array of LPPROVIDERs.
  167. // This array is expected to be GlobalNumProviders long.
  168. //
  169. // ProviderArrayCount - This is a pointer to a location where the number of
  170. // elements in the returned array is to be placed.
  171. //
  172. // InitClass - This indicates what type of providers we want listed in the
  173. // array. The choices are either CREDENTIAL_TYPE or NETWORK_TYPE
  174. // providers.
  175. //
  176. // Return Value:
  177. //
  178. // WN_SUCCESS - If the operation was successful.
  179. //
  180. // WN_NO_NETWORK - If there are no providers available, or none of the
  181. // providers support this InitClass.
  182. //
  183. //
  184. // History: 08-Apr-96 AnirudhS Created from MprFindCallOrder
  185. //
  186. // Notes: CODEWORK This should replace MprFindCallOrder.
  187. //
  188. //--------------------------------------------------------------------------
  189. DWORD CRoutedOperation::FindCallOrder(
  190. IN const UNICODE_STRING * NameInfo,
  191. OUT LPPROVIDER ProviderArray[],
  192. OUT LPDWORD ProviderArrayCount,
  193. IN DWORD InitClass
  194. )
  195. {
  196. //
  197. // If there are no Providers, then return WN_NO_NETWORK
  198. //
  199. ASSERT(MPR_IS_INITIALIZED(NETWORK) || MPR_IS_INITIALIZED(CREDENTIAL));
  200. ASSERT(MPRProviderLock.Have());
  201. if (GlobalNumActiveProviders == 0)
  202. {
  203. return WN_NO_NETWORK;
  204. }
  205. //
  206. // We cannot interact with active provider information unless we
  207. // have obtained synchronized access. Otherwise we would risk
  208. // trying to read data while it is being modified.
  209. //
  210. EnterCriticalSection(&MprInitCritSec);
  211. //
  212. // If a provider previously responded for the specified path, put it
  213. // first in the array.
  214. //
  215. DWORD j = 0; // index into ProviderArray
  216. LPPROVIDER CachedProvider = _PathCache.FindEntry(NameInfo);
  217. if (CachedProvider != NULL && (CachedProvider->InitClass & InitClass))
  218. {
  219. ProviderArray[j] = CachedProvider;
  220. j++;
  221. }
  222. //
  223. // Fill in the array with the order that was obtained from the ordered
  224. // list at initialization time. (Stored in GlobalIndexArray).
  225. //
  226. for (DWORD i=0; i<GlobalNumActiveProviders; i++)
  227. {
  228. LPPROVIDER Provider = &GlobalProviderInfo[GlobalIndexArray[i]];
  229. if ((Provider->InitClass & InitClass) &&
  230. Provider != CachedProvider)
  231. {
  232. ProviderArray[j] = Provider;
  233. j++;
  234. }
  235. }
  236. LeaveCriticalSection(&MprInitCritSec);
  237. if (j == 0)
  238. {
  239. return WN_NO_NETWORK;
  240. }
  241. *ProviderArrayCount = j;
  242. return WN_SUCCESS;
  243. }
  244. VOID
  245. MprInitIndexArray(
  246. LPDWORD IndexArray,
  247. DWORD NumEntries
  248. )
  249. /*++
  250. Routine Description:
  251. This function stores data from the passed in IndexArray in a global
  252. IndexArray. If a global index array already exists when this function
  253. is called, then the two arrays need to be merged. This function also
  254. updates the GlobalNumActiveProviders.
  255. NOTE: The array of provider structures is always created in the
  256. order specified by the ordered provider list. Therefore, it is reasonable
  257. to merge these lists by putting the array of indices in increasing order.
  258. It is expected that the MprInitCritSec lock is held prior to entering
  259. this function.
  260. This function will free the memory pointed to by IndexArray, if it is
  261. no longer needed.
  262. Arguments:
  263. IndexArray - This is a pointer to an array of DWORDs which are indices
  264. to the various providers. The buffer for this array is always
  265. large enough to hold indices for all providers; active, or inactive.
  266. NumEntries - This contains the number of entries in the IndexArray.
  267. Return Value:
  268. none
  269. --*/
  270. {
  271. DWORD newNumEntries=0;
  272. DWORD dest,s1,s2; // index for Destination, Source1, and Source2.
  273. DWORD tempBuffer[16];
  274. LPDWORD tempArray;
  275. if (NumEntries == 0) {
  276. return;
  277. }
  278. if (GlobalIndexArray == NULL) {
  279. GlobalNumActiveProviders = NumEntries;
  280. GlobalIndexArray = IndexArray;
  281. }
  282. else {
  283. //
  284. // An list already exists. Therefore we need to create a new
  285. // list of ordered indices.
  286. //
  287. //
  288. // Copy the GlobalIndexArray data into a temporary buffer. We
  289. // will try to use a buffer on the stack. If that isn't large
  290. // enough, we will try to allocate a buffer.
  291. //
  292. tempArray = tempBuffer;
  293. if (GlobalNumProviders > 16) {
  294. tempArray = (LPDWORD)LocalAlloc(LPTR, GlobalNumProviders);
  295. if (tempArray == NULL) {
  296. MPR_LOG1(ERROR,"MprInitIndexArray: LocalAlloc failed %d\n",GetLastError());
  297. LocalFree(IndexArray);
  298. return;
  299. }
  300. }
  301. memcpy(tempArray, GlobalIndexArray, GlobalNumActiveProviders*sizeof(DWORD));
  302. //
  303. // Now copy an ordered list of indices into the GlobalIndexArray.
  304. // We assume that the two seperate lists are already ordered in
  305. // ascending order. Therefore, we compare elements in both lists
  306. // one at a time - incrementing the index only for the array
  307. // containing the element that we move to the GlobalIndexArray.
  308. //
  309. dest=s1=s2=0;
  310. while ((s1 < GlobalNumActiveProviders) &&
  311. (s2 < NumEntries)) {
  312. if (tempArray[s1] < IndexArray[s2]) {
  313. GlobalIndexArray[dest] = tempArray[s1++];
  314. }
  315. else if (tempArray[s1] > IndexArray[s2]) {
  316. GlobalIndexArray[dest] = IndexArray[s2++];
  317. }
  318. else {
  319. GlobalIndexArray[dest] = IndexArray[s2];
  320. s1++;
  321. s2++;
  322. }
  323. dest++;
  324. }
  325. //
  326. // One of the arrays has reached its limit. Therefore, the elements
  327. // from the remaining array must be moved.
  328. //
  329. if (s1 < GlobalNumActiveProviders) {
  330. do {
  331. GlobalIndexArray[dest++] = tempArray[s1++];
  332. } while (s1 < GlobalNumActiveProviders);
  333. }
  334. else if (s2 < NumEntries) {
  335. do {
  336. GlobalIndexArray[dest++] = IndexArray[s2++];
  337. } while (s2 < NumEntries);
  338. }
  339. GlobalNumActiveProviders = dest;
  340. //
  341. // If we had to allocate a temporary buffer, then free it here.
  342. //
  343. if (tempArray != tempBuffer) {
  344. LocalFree(tempArray);
  345. }
  346. LocalFree(IndexArray);
  347. }
  348. return;
  349. }
  350. VOID
  351. MprDeleteIndexArray(
  352. VOID
  353. )
  354. /*++
  355. Routine Description:
  356. This function frees up global resources used in the support routines.
  357. Arguments:
  358. none
  359. Return Value:
  360. none
  361. --*/
  362. {
  363. LocalFree(GlobalIndexArray);
  364. GlobalIndexArray = NULL;
  365. return;
  366. }
  367. DWORD
  368. MprDeviceType(
  369. IN LPCTSTR DeviceName
  370. )
  371. /*++
  372. Routine Description:
  373. This function determines if the device name is for a redirected device
  374. (port or drive), or if it is a name of a remote share point.
  375. Arguments:
  376. DeviceName - This is the name that is passed in. It is either the
  377. name of a redirected device (ie. c: lpt2: lpt3:) or it is
  378. the name of a share point (\\cyclops\scratch).
  379. Return Value:
  380. REDIR_DEVICE - The name is for a redirected device
  381. REMOTE_NAME - The name is that of a remote connection.
  382. --*/
  383. {
  384. if (memcmp(DeviceName, TEXT("\\\\"), 2*sizeof(TCHAR)) == 0) {
  385. return(REMOTE_NAME);
  386. }
  387. if ((STRLEN(DeviceName) == 2) &&
  388. (DeviceName[1] == TEXT(':'))) {
  389. if ((TEXT('a') <= DeviceName[0]) && (DeviceName[0] <= TEXT('z'))) {
  390. return(REDIR_DEVICE);
  391. }
  392. else if ((TEXT('A') <= DeviceName[0]) && (DeviceName[0] <= TEXT('Z'))) {
  393. return(REDIR_DEVICE);
  394. }
  395. }
  396. else if (STRLEN(DeviceName) > 3) {
  397. if (STRNICMP(DeviceName, TEXT("LPT"), 3) == 0) {
  398. return(REDIR_DEVICE);
  399. }
  400. if (STRNICMP(DeviceName, TEXT("COM"), 3) == 0) {
  401. return(REDIR_DEVICE);
  402. }
  403. }
  404. return(REMOTE_NAME);
  405. }
  406. BOOL
  407. MprGetProviderIndex(
  408. IN LPCTSTR ProviderName,
  409. OUT LPDWORD IndexPtr
  410. )
  411. /*++
  412. Routine Description:
  413. This function looks in the provider database for a Provider name that
  414. will match the name passed in. When it is found, the index to that
  415. provider is stored in the location pointed to by IndexPtr.
  416. Arguments:
  417. ProviderName - This is a pointer to a string that contains the
  418. name which identifies a provider.
  419. IndexPtr - This is a pointer to a location where the index for the
  420. provider information is to be placed.
  421. Return Value:
  422. TRUE - The operation was successful.
  423. FALSE - A failure occured. IndexPtr is not updated.
  424. --*/
  425. {
  426. LPPROVIDER lpProvider;
  427. DWORD i;
  428. ASSERT_INITIALIZED(FIRST);
  429. //
  430. // Point to the top of the array of provider structures.
  431. //
  432. lpProvider = GlobalProviderInfo;
  433. //
  434. // Loop through each provider in the database until the list is
  435. // exhausted, or until a match with the provider name is found.
  436. //
  437. for(i=0; i<GlobalNumProviders; i++,lpProvider++) {
  438. if (lpProvider->Resource.lpProvider != NULL) {
  439. if(STRICMP(lpProvider->Resource.lpProvider, ProviderName) == 0) {
  440. //
  441. // A match is found, return the pointer to the provider
  442. // structure.
  443. //
  444. *IndexPtr = i;
  445. return(TRUE);
  446. }
  447. }
  448. }
  449. //
  450. // The list of provider structures was exhausted and no provider match
  451. // was found. Return a NULL pointer.
  452. //
  453. return(FALSE);
  454. }
  455. LPPROVIDER
  456. MprFindProviderByName(
  457. IN LPCWSTR ProviderName
  458. )
  459. /*++
  460. Routine Description:
  461. This function searches the provider database for the first provider
  462. whose provider name matches the name passed in, and returns a pointer
  463. to the provider structure.
  464. Arguments:
  465. ProviderName - The provider name to look for.
  466. Return Value:
  467. Pointer to the provider structure if a match was found, NULL if not.
  468. --*/
  469. {
  470. ASSERT(ProviderName != NULL);
  471. ASSERT_INITIALIZED(FIRST);
  472. for (LPPROVIDER lpProvider = GlobalProviderInfo;
  473. lpProvider < GlobalProviderInfo + GlobalNumProviders;
  474. lpProvider++)
  475. {
  476. if (lpProvider->Resource.lpProvider != NULL &&
  477. STRICMP(lpProvider->Resource.lpProvider, ProviderName) == 0)
  478. {
  479. return lpProvider;
  480. }
  481. }
  482. return NULL;
  483. }
  484. LPPROVIDER
  485. MprFindProviderByType(
  486. IN DWORD ProviderType
  487. )
  488. /*++
  489. Routine Description:
  490. This function searches the provider database for the first provider
  491. whose provider type matches the type passed in, and returns a pointer
  492. to the provider structure.
  493. Arguments:
  494. ProviderType - The network type to look for. Only the HIWORD is used;
  495. the LOWORD is ignored.
  496. Return Value:
  497. Pointer to the provider structure if a match was found, NULL if not.
  498. --*/
  499. {
  500. ASSERT(MPR_IS_INITIALIZED(NETWORK) || MPR_IS_INITIALIZED(CREDENTIAL));
  501. ASSERT(MPRProviderLock.Have());
  502. for (LPPROVIDER lpProvider = GlobalProviderInfo;
  503. lpProvider < GlobalProviderInfo + GlobalNumProviders;
  504. lpProvider++)
  505. {
  506. //
  507. // if (HIWORD(lpProvider->Type) == HIWORD(ProviderType))
  508. //
  509. if (((lpProvider->Type ^ ProviderType) & 0xFFFF0000) == 0 &&
  510. (lpProvider->InitClass & NETWORK_TYPE) != 0)
  511. {
  512. return lpProvider;
  513. }
  514. }
  515. return NULL;
  516. }
  517. DWORD
  518. MprEnterLoadLibCritSect (
  519. VOID
  520. )
  521. /*++
  522. Routine Description:
  523. This function enters the critical section defined by
  524. MprLoadLibrarySemaphore.
  525. Arguments:
  526. none
  527. Return Value:
  528. 0 - The operation was successful.
  529. error code otherwise.
  530. --*/
  531. #define LOADLIBRARY_TIMEOUT 10000L
  532. {
  533. switch( WaitForSingleObject( MprLoadLibSemaphore, LOADLIBRARY_TIMEOUT ))
  534. {
  535. case 0:
  536. return 0 ;
  537. case WAIT_TIMEOUT:
  538. return WN_FUNCTION_BUSY ;
  539. case 0xFFFFFFFF:
  540. return (GetLastError()) ;
  541. default:
  542. return WN_WINDOWS_ERROR ;
  543. }
  544. }
  545. DWORD
  546. MprLeaveLoadLibCritSect (
  547. VOID
  548. )
  549. /*++
  550. Routine Description:
  551. This function leaves the critical section defined by
  552. MprLoadLibrarySemaphore.
  553. Arguments:
  554. none
  555. Return Value:
  556. 0 - The operation was successful.
  557. error code otherwise.
  558. --*/
  559. {
  560. if (!ReleaseSemaphore( MprLoadLibSemaphore, 1, NULL ))
  561. return (GetLastError()) ;
  562. return 0 ;
  563. }
  564. VOID
  565. MprClearString (
  566. LPWSTR lpString
  567. )
  568. /*++
  569. Routine Description:
  570. This function clears the string by setting it to all zero.
  571. Arguments:
  572. lpString - string to NULL out
  573. Return Value:
  574. none
  575. --*/
  576. {
  577. DWORD dwLen ;
  578. if (lpString)
  579. {
  580. dwLen = wcslen(lpString) ;
  581. memset(lpString, 0, dwLen * sizeof(WCHAR)) ;
  582. }
  583. }
  584. DWORD
  585. MprFindProviderForPath(
  586. IN LPWSTR lpPathName,
  587. OUT LPDWORD lpProviderIndex
  588. )
  589. /*++
  590. Routine Description:
  591. This function attempts to find the provider index for the provider that is
  592. responsible for the pathname that is passed in. Only the drive letter is
  593. examined. Then MprGetConnection is called to find the provider for that
  594. drive.
  595. Arguments:
  596. lpPathName - This is a pointer to the pathname string. It is expected to
  597. be of the format <drive:><path>. (ie. f:\nt\system32>.
  598. lpProviderIndex - This is a pointer to the location where the provider index
  599. is to be returned. If an error is returned, this index is garbage.
  600. Return Value:
  601. WN_SUCCESS - If the operation is successful. In this case the provider
  602. index will always be correct.
  603. otherwise - An error occured, the provider index will not be correct.
  604. --*/
  605. {
  606. DWORD status=WN_SUCCESS;
  607. WCHAR lpDriveName[3];
  608. WCHAR lpRemoteName[MAX_PATH];
  609. DWORD bufSize = MAX_PATH * sizeof(WCHAR);
  610. //
  611. // Get the drive letter out of the lpDriveName.
  612. //
  613. __try {
  614. if (lpPathName[1] != L':') {
  615. return(WN_BAD_VALUE);
  616. }
  617. lpDriveName[0] = lpPathName[0];
  618. lpDriveName[1] = lpPathName[1];
  619. lpDriveName[2] = L'\0';
  620. }
  621. __except(EXCEPTION_EXECUTE_HANDLER) {
  622. status = GetExceptionCode();
  623. if (status != EXCEPTION_ACCESS_VIOLATION) {
  624. MPR_LOG(ERROR,"WNetGetPropertyText:Unexpected Exception "
  625. "0x%lx\n",status);
  626. }
  627. status = WN_BAD_POINTER;
  628. }
  629. if (status != WN_SUCCESS) {
  630. return(status);
  631. }
  632. //
  633. // Find out which provider owns the drive by calling MprGetConnection.
  634. //
  635. status = MprGetConnection(
  636. lpDriveName,
  637. lpRemoteName,
  638. &bufSize,
  639. lpProviderIndex);
  640. return(status);
  641. }