Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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