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.

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