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.

794 lines
21 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. userdir.cxx
  5. Abstract:
  6. This file contains the API entry points for the following functions:
  7. WNetGetUserW
  8. WNetGetDirectoryTypeW
  9. WNetDirectoryNotifyW
  10. WNetGetHomeDirectoryW
  11. Author:
  12. Dan Lafferty (danl) 17-Oct-1991
  13. Environment:
  14. User Mode - Win32
  15. Revision History:
  16. 05-May-1999 jschwart
  17. Make provider addition/removal dynamic
  18. 12-Jul-1995 anirudhs
  19. Add WNetGetHomeDirectory.
  20. 17-Jun-1994 danl
  21. WNetGetDirectoryTypeW: Cache the drive letter and provider index
  22. to make file manager faster.
  23. 27-May-1994 danl
  24. WNetGetDirectoryTypeW & WNetDirectoryNotifyW: If no provider
  25. claims the connection in question, then we try all providers.
  26. The actual rule is that we need to pass it to the lanman
  27. provider anyway (so it can check for a share). But to play
  28. completely fair, we'll pass it to everyone.
  29. 28-Aug-1992 danl
  30. When GetUsername returns the name, it didn't handle the case where
  31. the buffer was too small. (This may have been a bug in GetUserName).
  32. Now this code copies it into a temp buffer (MAX_PATH) and determines
  33. the size.
  34. 03-Aug-1992 danl
  35. WNetGetUser now calls GetUsername when the device name parameter
  36. is NULL.
  37. 17-Oct-1991 danl
  38. Created
  39. --*/
  40. //
  41. // INCLUDES
  42. //
  43. #include "precomp.hxx"
  44. #include <tstring.h> // STRCPY
  45. //
  46. // DEFINES
  47. //
  48. DWORD
  49. WNetGetUserW (
  50. IN LPCWSTR lpName,
  51. OUT LPWSTR lpUserName,
  52. IN OUT LPDWORD lpBufferSize
  53. )
  54. /*++
  55. Routine Description:
  56. Returns the user name that is associated with making a particular
  57. connection. If no connection is specified, the current username
  58. for the process is returned.
  59. Arguments:
  60. lpName - This is a pointer to a device name string. If NULL, the
  61. username for the current user of this process is returned.
  62. lpUserName - This is a pointer to the buffer that will receive the
  63. username string.
  64. lpBufferSize - This is the size (in characters) of the buffer that
  65. will receive the username.
  66. Return Value:
  67. Note:
  68. --*/
  69. {
  70. DWORD status = WN_SUCCESS;
  71. DWORD indexArray[DEFAULT_MAX_PROVIDERS];
  72. LPDWORD index = indexArray;
  73. DWORD numProviders;
  74. DWORD statusFlag = 0; // used to indicate major error types
  75. BOOL fcnSupported = FALSE; // Is fcn supported by a provider?
  76. DWORD i;
  77. WCHAR pDriveLetter[4];
  78. UINT uDriveType;
  79. DWORD providerIndex; // ignored
  80. //
  81. // If the device or network name is NULL then we
  82. // will return the name of the current user.
  83. //
  84. __try
  85. {
  86. if (IS_EMPTY_STRING(lpName)) {
  87. //
  88. // GetUserName modifies *lpBufferSize on success -- we don't
  89. //
  90. DWORD dwTempSize = *lpBufferSize;
  91. lpName = NULL;
  92. if (!GetUserName(lpUserName, &dwTempSize))
  93. {
  94. status = GetLastError();
  95. MPR_LOG(ERROR,"WNetGetUserW: GetUserName Failed %d\n",status);
  96. if (status == ERROR_INSUFFICIENT_BUFFER)
  97. {
  98. *lpBufferSize = dwTempSize;
  99. status = WN_MORE_DATA;
  100. }
  101. }
  102. }
  103. else {
  104. //
  105. // As long as we're already in a try-except block,
  106. // try setting up the check to see if lpName is
  107. // a local drive.
  108. //
  109. pDriveLetter[0] = lpName[0];
  110. pDriveLetter[1] = lpName[1];
  111. }
  112. }
  113. __except(EXCEPTION_EXECUTE_HANDLER) {
  114. status = GetExceptionCode();
  115. if (status != EXCEPTION_ACCESS_VIOLATION) {
  116. MPR_LOG(ERROR,"WNetGetUser:Unexpected Exception 0x%lx\n",status);
  117. }
  118. status = WN_BAD_POINTER;
  119. }
  120. if (lpName == NULL || status != WN_SUCCESS) {
  121. goto CleanExit;
  122. }
  123. pDriveLetter[2] = L'\\';
  124. pDriveLetter[3] = L'\0';
  125. uDriveType = GetDriveType(pDriveLetter);
  126. //
  127. // Eliminate all cases of drives that aren't connected to
  128. // a network resource. Note that network provider names
  129. // and UNC shares return DRIVE_NO_ROOT_DIR, so we need to
  130. // make sure it's a valid drive name in that case.
  131. //
  132. if (uDriveType == DRIVE_REMOVABLE ||
  133. uDriveType == DRIVE_FIXED ||
  134. uDriveType == DRIVE_CDROM ||
  135. uDriveType == DRIVE_RAMDISK ||
  136. (uDriveType == DRIVE_NO_ROOT_DIR && pDriveLetter[1] == L':'))
  137. {
  138. status = WN_NOT_CONNECTED;
  139. goto CleanExit;
  140. }
  141. {
  142. MprCheckProviders();
  143. CProviderSharedLock PLock;
  144. //
  145. // If the device or network name is the name of a network
  146. // provider, then we will return the name of the current user.
  147. // Only a Level 1 init is needed for MprGetProviderIndex
  148. //
  149. if (!(GlobalInitLevel & FIRST_LEVEL)) {
  150. status = MprLevel1Init();
  151. if (status != WN_SUCCESS) {
  152. return(status);
  153. }
  154. }
  155. if (MprGetProviderIndex(lpName, &providerIndex))
  156. {
  157. lpName = NULL;
  158. if (!GetUserName(lpUserName, lpBufferSize))
  159. {
  160. status = GetLastError();
  161. MPR_LOG(ERROR,"WNetGetUserW: GetUserName Failed %d\n",status);
  162. if (status == ERROR_INSUFFICIENT_BUFFER)
  163. {
  164. status = WN_MORE_DATA;
  165. }
  166. }
  167. }
  168. if (lpName == NULL || status != WN_SUCCESS) {
  169. goto CleanExit;
  170. }
  171. //
  172. // Find the list of providers to call for this request.
  173. // If there are no active providers, MprFindCallOrder returns
  174. // WN_NO_NETWORK.
  175. //
  176. INIT_IF_NECESSARY(NETWORK_LEVEL,status);
  177. status = MprFindCallOrder(
  178. NULL,
  179. &index,
  180. &numProviders,
  181. NETWORK_TYPE);
  182. if (status != WN_SUCCESS) {
  183. goto CleanExit;
  184. }
  185. //
  186. // if none of them are started, return error
  187. //
  188. if (!MprNetIsAvailable())
  189. {
  190. status = WN_NO_NETWORK;
  191. goto CleanExit;
  192. }
  193. //
  194. // Loop through the list of providers until one answers the request,
  195. // or the list is exhausted.
  196. //
  197. for (i=0; i<numProviders; i++) {
  198. //
  199. // Call the appropriate providers API entry point
  200. //
  201. LPPROVIDER provider = &GlobalProviderInfo[ index[i] ];
  202. if (provider->GetUser != NULL) {
  203. fcnSupported = TRUE;
  204. __try {
  205. status = provider->GetUser(
  206. (LPWSTR) lpName,
  207. lpUserName,
  208. lpBufferSize);
  209. }
  210. __except(EXCEPTION_EXECUTE_HANDLER) {
  211. status = GetExceptionCode();
  212. if (status != EXCEPTION_ACCESS_VIOLATION) {
  213. MPR_LOG(ERROR,"WNetGetUser:Unexpected Exception 0x%lx\n",status);
  214. }
  215. status = WN_BAD_POINTER;
  216. }
  217. //
  218. // WN_CONNECTED_OTHER_PASSWORD_DEFAULT will be returned when user X mapped a
  219. // drive as user Y and the credentials for user Y were stored in CredMan when
  220. // the connection was made. Since the username is correctly filled in with
  221. // user Y in this case, simply massage the return code to success.
  222. //
  223. if (status == WN_CONNECTED_OTHER_PASSWORD_DEFAULT)
  224. {
  225. status = WN_SUCCESS;
  226. }
  227. if (status == WN_NO_NETWORK) {
  228. statusFlag |= NO_NET;
  229. }
  230. else if ((status == WN_NOT_CONNECTED) ||
  231. (status == WN_BAD_LOCALNAME)){
  232. statusFlag |= BAD_NAME;
  233. }
  234. else {
  235. //
  236. // If it wasn't one of those errors, then the provider
  237. // must have accepted responsibility for the request.
  238. // so we exit and process the results. Note that the
  239. // statusFlag is cleared because we want to ignore other
  240. // error information that we gathered up until now.
  241. //
  242. statusFlag = 0;
  243. break;
  244. }
  245. }
  246. }
  247. }
  248. if (fcnSupported == FALSE) {
  249. //
  250. // No providers in the list support the API function. Therefore,
  251. // we assume that no networks are installed.
  252. //
  253. status = WN_NOT_SUPPORTED;
  254. }
  255. //
  256. // Handle special errors.
  257. //
  258. if (statusFlag == (NO_NET | BAD_NAME)) {
  259. //
  260. // Check to see if there was a mix of special errors that occured.
  261. // If so, pass back the combined error message. Otherwise, let the
  262. // last error returned get passed back.
  263. //
  264. status = WN_NO_NET_OR_BAD_PATH;
  265. }
  266. CleanExit:
  267. //
  268. // If memory was allocated by MprFindCallOrder, free it.
  269. //
  270. if (index != indexArray) {
  271. LocalFree(index);
  272. }
  273. if (status != WN_SUCCESS){
  274. SetLastError(status);
  275. }
  276. return(status);
  277. }
  278. DWORD
  279. WNetGetDirectoryTypeW (
  280. IN LPTSTR lpName,
  281. OUT LPINT lpType,
  282. IN BOOL bFlushCache
  283. )
  284. /*++
  285. Routine Description:
  286. Arguments:
  287. Return Value:
  288. Note:
  289. --*/
  290. {
  291. DWORD status = WN_SUCCESS;
  292. LPDWORD index;
  293. DWORD indexArray[DEFAULT_MAX_PROVIDERS];
  294. DWORD numProviders = 0;
  295. DWORD providerIndex;
  296. DWORD statusFlag = 0; // used to indicate major error types
  297. WCHAR lpDriveName[4];
  298. UINT uDriveType;
  299. index = indexArray;
  300. //
  301. // Probe the drive letter portion of the lpName.
  302. //
  303. __try {
  304. lpDriveName[0] = lpName[0];
  305. lpDriveName[1] = lpName[1];
  306. }
  307. __except(EXCEPTION_EXECUTE_HANDLER) {
  308. status = GetExceptionCode();
  309. if (status != EXCEPTION_ACCESS_VIOLATION) {
  310. MPR_LOG(ERROR,"WNetGetDirectoryType:Unexpected Exception 0x%lx\n",status);
  311. }
  312. status = WN_BAD_POINTER;
  313. }
  314. if (status != WN_SUCCESS) {
  315. return(status);
  316. }
  317. lpDriveName[2] = L'\\';
  318. lpDriveName[3] = L'\0';
  319. uDriveType = GetDriveType(lpDriveName);
  320. if (uDriveType == DRIVE_REMOVABLE ||
  321. uDriveType == DRIVE_FIXED ||
  322. uDriveType == DRIVE_CDROM ||
  323. uDriveType == DRIVE_RAMDISK)
  324. {
  325. *lpType = 0; // 0 means a non-network drive
  326. return WN_SUCCESS;
  327. }
  328. MprCheckProviders();
  329. CProviderSharedLock PLock;
  330. INIT_IF_NECESSARY(NETWORK_LEVEL,status);
  331. //
  332. // Find the Provider Index associated with the drive letter in
  333. // the pathname (lpszName).
  334. // NOTE: This function handles exceptions.
  335. //
  336. status = MprFindProviderForPath(lpName, &providerIndex);
  337. if (status != WN_SUCCESS) {
  338. MPR_LOG1(ERROR,"WNetGetDirectoryType: Couldn't find provider for this "
  339. "path. Error = %d\n",status);
  340. //
  341. // Find the list of providers to call for this request.
  342. // Since no provider claimed this path, then
  343. // we need to at least try the lanman provider.
  344. // Actually we'll give them all a chance.
  345. //
  346. status = MprFindCallOrder(
  347. NULL,
  348. &index,
  349. &numProviders,
  350. NETWORK_TYPE);
  351. if (status != WN_SUCCESS) {
  352. return(status);
  353. }
  354. }
  355. else {
  356. numProviders = 1;
  357. index[0] = providerIndex;
  358. }
  359. //
  360. // Loop through the list of providers until one answers the request,
  361. // or the list is exhausted.
  362. //
  363. BOOL fcnSupported = FALSE; // Is fcn supported by a provider?
  364. for (DWORD i=0; i<numProviders; i++) {
  365. //
  366. // Call the appropriate provider's API entry point
  367. //
  368. LPPROVIDER provider = &GlobalProviderInfo[ index[i] ];
  369. if (provider->GetDirectoryType != NULL) {
  370. fcnSupported = TRUE;
  371. __try {
  372. status = provider->GetDirectoryType(
  373. lpName,
  374. lpType,
  375. bFlushCache) ;
  376. }
  377. __except(EXCEPTION_EXECUTE_HANDLER) {
  378. status = GetExceptionCode();
  379. if (status != EXCEPTION_ACCESS_VIOLATION) {
  380. MPR_LOG(ERROR,"WNetGetDirectoryType:Unexpected Exception 0x%lx\n",status);
  381. }
  382. status = WN_BAD_POINTER;
  383. }
  384. if (status == WN_NO_NETWORK) {
  385. statusFlag |= NO_NET;
  386. }
  387. else if ((status == WN_NOT_CONNECTED) ||
  388. (status == WN_BAD_LOCALNAME)){
  389. statusFlag |= BAD_NAME;
  390. }
  391. else {
  392. //
  393. // If it wasn't one of those errors, then the provider
  394. // must have accepted responsibility for the request.
  395. // so we exit and process the results. Note that the
  396. // statusFlag is cleared because we want to ignore other
  397. // error information that we gathered up until now.
  398. //
  399. statusFlag = 0;
  400. break;
  401. }
  402. }
  403. }
  404. if (fcnSupported == FALSE) {
  405. //
  406. // No providers in the list support the API function. Therefore,
  407. // we assume that no networks are installed.
  408. //
  409. status = WN_NOT_SUPPORTED;
  410. }
  411. //
  412. // If memory was allocated by MprFindCallOrder, free it.
  413. //
  414. if (index != indexArray) {
  415. LocalFree(index);
  416. }
  417. //
  418. // Handle special errors.
  419. //
  420. if (statusFlag == (NO_NET | BAD_NAME)) {
  421. //
  422. // Check to see if there was a mix of special errors that occured.
  423. // If so, pass back the combined error message. Otherwise, let the
  424. // last error returned get passed back.
  425. //
  426. status = WN_NO_NET_OR_BAD_PATH;
  427. }
  428. if (status != WN_SUCCESS){
  429. SetLastError(status);
  430. }
  431. return(status);
  432. }
  433. DWORD
  434. WNetDirectoryNotifyW (
  435. IN HWND hwnd,
  436. IN LPTSTR lpDir,
  437. IN DWORD dwOper
  438. )
  439. /*++
  440. Routine Description:
  441. Arguments:
  442. Return Value:
  443. Note:
  444. --*/
  445. {
  446. DWORD providerIndex;
  447. DWORD status;
  448. LPDWORD index;
  449. DWORD indexArray[DEFAULT_MAX_PROVIDERS];
  450. DWORD numProviders;
  451. LPPROVIDER provider;
  452. DWORD statusFlag = 0; // used to indicate major error types
  453. BOOL fcnSupported = FALSE; // Is fcn supported by a provider?
  454. DWORD i;
  455. MprCheckProviders();
  456. CProviderSharedLock PLock;
  457. INIT_IF_NECESSARY(NETWORK_LEVEL,status);
  458. index = indexArray;
  459. //
  460. // Find the Provider Index associated with the drive letter in
  461. // the pathname (lpszName).
  462. // NOTE: This function handles exceptions.
  463. //
  464. status = MprFindProviderForPath(lpDir, &providerIndex);
  465. if (status != WN_SUCCESS) {
  466. MPR_LOG1(TRACE,"WNetDirectoryNotify: Couldn't find provider for this "
  467. "path. Error = %d\n",status);
  468. //
  469. // Find the list of providers to call for this request.
  470. // Since no provider claimed this path, then
  471. // we need to at least try the lanman provider.
  472. // Actually we'll give them all a chance.
  473. //
  474. status = MprFindCallOrder(
  475. NULL,
  476. &index,
  477. &numProviders,
  478. NETWORK_TYPE);
  479. if (status != WN_SUCCESS) {
  480. MPR_LOG(ERROR,"WNetDirectoryNotifyW: FindCallOrder Failed\n",0);
  481. return(status);
  482. }
  483. }
  484. else {
  485. numProviders = 1;
  486. index[0] = providerIndex;
  487. }
  488. //
  489. // Loop through the list of providers until one answers the request,
  490. // or the list is exhausted.
  491. //
  492. for (i=0; i<numProviders; i++) {
  493. //
  494. // Call the appropriate provider's API entry point
  495. //
  496. provider = GlobalProviderInfo + index[i];
  497. if (provider->DirectoryNotify != NULL) {
  498. fcnSupported = TRUE;
  499. __try {
  500. status = provider->DirectoryNotify(
  501. hwnd,
  502. lpDir,
  503. dwOper);
  504. }
  505. __except(EXCEPTION_EXECUTE_HANDLER) {
  506. status = GetExceptionCode();
  507. if (status != EXCEPTION_ACCESS_VIOLATION) {
  508. MPR_LOG(ERROR,"WNetDirectoryNotify:Unexpected Exception 0x%lx\n",status);
  509. }
  510. status = WN_BAD_POINTER;
  511. }
  512. if (status == WN_NO_NETWORK) {
  513. statusFlag |= NO_NET;
  514. }
  515. else if ((status == WN_NOT_CONNECTED) ||
  516. (status == WN_BAD_LOCALNAME)){
  517. statusFlag |= BAD_NAME;
  518. }
  519. else {
  520. //
  521. // If it wasn't one of those errors, then the provider
  522. // must have accepted responsibility for the request.
  523. // so we exit and process the results. Note that the
  524. // statusFlag is cleared because we want to ignore other
  525. // error information that we gathered up until now.
  526. //
  527. statusFlag = 0;
  528. break;
  529. }
  530. }
  531. }
  532. if (fcnSupported == FALSE) {
  533. //
  534. // No providers in the list support the API function. Therefore,
  535. // we assume that no networks are installed.
  536. //
  537. status = WN_NOT_SUPPORTED;
  538. }
  539. //
  540. // If memory was allocated by MprFindCallOrder, free it.
  541. //
  542. if (index != indexArray) {
  543. LocalFree(index);
  544. }
  545. //
  546. // Handle special errors.
  547. //
  548. if (statusFlag == (NO_NET | BAD_NAME)) {
  549. //
  550. // Check to see if there was a mix of special errors that occured.
  551. // If so, pass back the combined error message. Otherwise, let the
  552. // last error returned get passed back.
  553. //
  554. status = WN_NO_NET_OR_BAD_PATH;
  555. }
  556. //
  557. // Handle normal errors passed back from the provider
  558. //
  559. if (status != WN_SUCCESS){
  560. MPR_LOG(TRACE,"WNetDirectoryNotifyW: Call Failed %d\n",status);
  561. SetLastError(status);
  562. }
  563. return(status);
  564. }
  565. DWORD
  566. WNetGetHomeDirectoryW (
  567. IN LPCWSTR lpProviderName,
  568. OUT LPWSTR lpDirectory,
  569. IN OUT LPDWORD lpBufferSize
  570. )
  571. /*++
  572. Routine Description:
  573. Returns the user's home directory.
  574. Arguments:
  575. lpProviderName - Specifies the name of the network provider for which the
  576. home directory is retrieved. This parameter exists for Win95 compati-
  577. bility, and is ignored.
  578. lpDirectory - Buffer in which to return the directory path. This will be
  579. in either UNC or drive-relative form.
  580. lpBufferSize - Specifies the size of the lpDirectory buffer, in characters.
  581. If the call fails because the buffer is not big enough, this will be
  582. set to the required buffer size.
  583. Return Value:
  584. WN_SUCCESS - successful
  585. WN_MORE_DATA - buffer not large enough
  586. WN_NOT_SUPPORTED - user doesn't have a home directory
  587. Note:
  588. This is an unpublished function, so it doesn't catch exceptions.
  589. The path is obtained from environment variables and equals
  590. %HOMESHARE%%HOMEPATH% if the %HOMESHARE% variable is set, else
  591. %HOMEDIR%%HOMEPATH% .
  592. --*/
  593. {
  594. //
  595. // If HOMESHARE is set, use it in preference to HOMEDRIVE
  596. //
  597. LPWSTR ExpandString = L"%HOMEDRIVE%%HOMEPATH%";
  598. if (GetEnvironmentVariable(L"HOMESHARE", NULL, 0))
  599. {
  600. ExpandString = L"%HOMESHARE%%HOMEPATH%";
  601. }
  602. //
  603. // Expand the environment variables into the buffer
  604. //
  605. DWORD cchReturned = ExpandEnvironmentStrings(
  606. ExpandString,
  607. lpDirectory,
  608. *lpBufferSize
  609. );
  610. if (cchReturned == 0)
  611. {
  612. // ExpandEnvironmentStrings failed
  613. return GetLastError();
  614. }
  615. if (cchReturned > *lpBufferSize)
  616. {
  617. // Buffer too small; cchReturned is the required size
  618. *lpBufferSize = cchReturned;
  619. return WN_MORE_DATA;
  620. }
  621. //
  622. // Fail if HOMEDRIVE or HOMEPATH is not set - detected by the result
  623. // string beginning with %HOMEDRIVE% or ending with %HOMEPATH%
  624. //
  625. if (wcsncmp(lpDirectory, L"%HOMEPATH%", sizeof("%HOMEPATH%") - 1) == 0 ||
  626. (cchReturned > sizeof("%HOMEPATH%") &&
  627. wcscmp(&lpDirectory[cchReturned-sizeof("%HOMEPATH%")], L"%HOMEPATH%") == 0))
  628. {
  629. return WN_NOT_SUPPORTED;
  630. }
  631. return WN_SUCCESS;
  632. }