/*++ Copyright (c) 1991 Microsoft Corporation Module Name: userdir.cxx Abstract: This file contains the API entry points for the following functions: WNetGetUserW WNetGetDirectoryTypeW WNetDirectoryNotifyW WNetGetHomeDirectoryW Author: Dan Lafferty (danl) 17-Oct-1991 Environment: User Mode - Win32 Revision History: 05-May-1999 jschwart Make provider addition/removal dynamic 12-Jul-1995 anirudhs Add WNetGetHomeDirectory. 17-Jun-1994 danl WNetGetDirectoryTypeW: Cache the drive letter and provider index to make file manager faster. 27-May-1994 danl WNetGetDirectoryTypeW & WNetDirectoryNotifyW: If no provider claims the connection in question, then we try all providers. The actual rule is that we need to pass it to the lanman provider anyway (so it can check for a share). But to play completely fair, we'll pass it to everyone. 28-Aug-1992 danl When GetUsername returns the name, it didn't handle the case where the buffer was too small. (This may have been a bug in GetUserName). Now this code copies it into a temp buffer (MAX_PATH) and determines the size. 03-Aug-1992 danl WNetGetUser now calls GetUsername when the device name parameter is NULL. 17-Oct-1991 danl Created --*/ // // INCLUDES // #include "precomp.hxx" #include // STRCPY // // DEFINES // DWORD WNetGetUserW ( IN LPCWSTR lpName, OUT LPWSTR lpUserName, IN OUT LPDWORD lpBufferSize ) /*++ Routine Description: Returns the user name that is associated with making a particular connection. If no connection is specified, the current username for the process is returned. Arguments: lpName - This is a pointer to a device name string. If NULL, the username for the current user of this process is returned. lpUserName - This is a pointer to the buffer that will receive the username string. lpBufferSize - This is the size (in characters) of the buffer that will receive the username. Return Value: Note: --*/ { DWORD status = WN_SUCCESS; DWORD indexArray[DEFAULT_MAX_PROVIDERS]; LPDWORD index = indexArray; DWORD numProviders; DWORD statusFlag = 0; // used to indicate major error types BOOL fcnSupported = FALSE; // Is fcn supported by a provider? DWORD i; WCHAR pDriveLetter[4]; UINT uDriveType; DWORD providerIndex; // ignored // // If the device or network name is NULL then we // will return the name of the current user. // __try { if (IS_EMPTY_STRING(lpName)) { // // GetUserName modifies *lpBufferSize on success -- we don't // DWORD dwTempSize = *lpBufferSize; lpName = NULL; if (!GetUserName(lpUserName, &dwTempSize)) { status = GetLastError(); MPR_LOG(ERROR,"WNetGetUserW: GetUserName Failed %d\n",status); if (status == ERROR_INSUFFICIENT_BUFFER) { *lpBufferSize = dwTempSize; status = WN_MORE_DATA; } } } else { // // As long as we're already in a try-except block, // try setting up the check to see if lpName is // a local drive. // pDriveLetter[0] = lpName[0]; pDriveLetter[1] = lpName[1]; } } __except(EXCEPTION_EXECUTE_HANDLER) { status = GetExceptionCode(); if (status != EXCEPTION_ACCESS_VIOLATION) { MPR_LOG(ERROR,"WNetGetUser:Unexpected Exception 0x%lx\n",status); } status = WN_BAD_POINTER; } if (lpName == NULL || status != WN_SUCCESS) { goto CleanExit; } pDriveLetter[2] = L'\\'; pDriveLetter[3] = L'\0'; uDriveType = GetDriveType(pDriveLetter); // // Eliminate all cases of drives that aren't connected to // a network resource. Note that network provider names // and UNC shares return DRIVE_NO_ROOT_DIR, so we need to // make sure it's a valid drive name in that case. // if (uDriveType == DRIVE_REMOVABLE || uDriveType == DRIVE_FIXED || uDriveType == DRIVE_CDROM || uDriveType == DRIVE_RAMDISK || (uDriveType == DRIVE_NO_ROOT_DIR && pDriveLetter[1] == L':')) { status = WN_NOT_CONNECTED; goto CleanExit; } { MprCheckProviders(); CProviderSharedLock PLock; // // If the device or network name is the name of a network // provider, then we will return the name of the current user. // Only a Level 1 init is needed for MprGetProviderIndex // if (!(GlobalInitLevel & FIRST_LEVEL)) { status = MprLevel1Init(); if (status != WN_SUCCESS) { return(status); } } if (MprGetProviderIndex(lpName, &providerIndex)) { lpName = NULL; if (!GetUserName(lpUserName, lpBufferSize)) { status = GetLastError(); MPR_LOG(ERROR,"WNetGetUserW: GetUserName Failed %d\n",status); if (status == ERROR_INSUFFICIENT_BUFFER) { status = WN_MORE_DATA; } } } if (lpName == NULL || status != WN_SUCCESS) { goto CleanExit; } // // Find the list of providers to call for this request. // If there are no active providers, MprFindCallOrder returns // WN_NO_NETWORK. // INIT_IF_NECESSARY(NETWORK_LEVEL,status); status = MprFindCallOrder( NULL, &index, &numProviders, NETWORK_TYPE); if (status != WN_SUCCESS) { goto CleanExit; } // // if none of them are started, return error // if (!MprNetIsAvailable()) { status = WN_NO_NETWORK; goto CleanExit; } // // Loop through the list of providers until one answers the request, // or the list is exhausted. // for (i=0; iGetUser != NULL) { fcnSupported = TRUE; __try { status = provider->GetUser( (LPWSTR) lpName, lpUserName, lpBufferSize); } __except(EXCEPTION_EXECUTE_HANDLER) { status = GetExceptionCode(); if (status != EXCEPTION_ACCESS_VIOLATION) { MPR_LOG(ERROR,"WNetGetUser:Unexpected Exception 0x%lx\n",status); } status = WN_BAD_POINTER; } // // WN_CONNECTED_OTHER_PASSWORD_DEFAULT will be returned when user X mapped a // drive as user Y and the credentials for user Y were stored in CredMan when // the connection was made. Since the username is correctly filled in with // user Y in this case, simply massage the return code to success. // if (status == WN_CONNECTED_OTHER_PASSWORD_DEFAULT) { status = WN_SUCCESS; } if (status == WN_NO_NETWORK) { statusFlag |= NO_NET; } else if ((status == WN_NOT_CONNECTED) || (status == WN_BAD_LOCALNAME)){ statusFlag |= BAD_NAME; } else { // // If it wasn't one of those errors, then the provider // must have accepted responsibility for the request. // so we exit and process the results. Note that the // statusFlag is cleared because we want to ignore other // error information that we gathered up until now. // statusFlag = 0; break; } } } } if (fcnSupported == FALSE) { // // No providers in the list support the API function. Therefore, // we assume that no networks are installed. // status = WN_NOT_SUPPORTED; } // // Handle special errors. // if (statusFlag == (NO_NET | BAD_NAME)) { // // Check to see if there was a mix of special errors that occured. // If so, pass back the combined error message. Otherwise, let the // last error returned get passed back. // status = WN_NO_NET_OR_BAD_PATH; } CleanExit: // // If memory was allocated by MprFindCallOrder, free it. // if (index != indexArray) { LocalFree(index); } if (status != WN_SUCCESS){ SetLastError(status); } return(status); } DWORD WNetGetDirectoryTypeW ( IN LPTSTR lpName, OUT LPINT lpType, IN BOOL bFlushCache ) /*++ Routine Description: Arguments: Return Value: Note: --*/ { DWORD status = WN_SUCCESS; LPDWORD index; DWORD indexArray[DEFAULT_MAX_PROVIDERS]; DWORD numProviders = 0; DWORD providerIndex; DWORD statusFlag = 0; // used to indicate major error types WCHAR lpDriveName[4]; UINT uDriveType; index = indexArray; // // Probe the drive letter portion of the lpName. // __try { lpDriveName[0] = lpName[0]; lpDriveName[1] = lpName[1]; } __except(EXCEPTION_EXECUTE_HANDLER) { status = GetExceptionCode(); if (status != EXCEPTION_ACCESS_VIOLATION) { MPR_LOG(ERROR,"WNetGetDirectoryType:Unexpected Exception 0x%lx\n",status); } status = WN_BAD_POINTER; } if (status != WN_SUCCESS) { return(status); } lpDriveName[2] = L'\\'; lpDriveName[3] = L'\0'; uDriveType = GetDriveType(lpDriveName); if (uDriveType == DRIVE_REMOVABLE || uDriveType == DRIVE_FIXED || uDriveType == DRIVE_CDROM || uDriveType == DRIVE_RAMDISK) { *lpType = 0; // 0 means a non-network drive return WN_SUCCESS; } MprCheckProviders(); CProviderSharedLock PLock; INIT_IF_NECESSARY(NETWORK_LEVEL,status); // // Find the Provider Index associated with the drive letter in // the pathname (lpszName). // NOTE: This function handles exceptions. // status = MprFindProviderForPath(lpName, &providerIndex); if (status != WN_SUCCESS) { MPR_LOG1(ERROR,"WNetGetDirectoryType: Couldn't find provider for this " "path. Error = %d\n",status); // // Find the list of providers to call for this request. // Since no provider claimed this path, then // we need to at least try the lanman provider. // Actually we'll give them all a chance. // status = MprFindCallOrder( NULL, &index, &numProviders, NETWORK_TYPE); if (status != WN_SUCCESS) { return(status); } } else { numProviders = 1; index[0] = providerIndex; } // // Loop through the list of providers until one answers the request, // or the list is exhausted. // BOOL fcnSupported = FALSE; // Is fcn supported by a provider? for (DWORD i=0; iGetDirectoryType != NULL) { fcnSupported = TRUE; __try { status = provider->GetDirectoryType( lpName, lpType, bFlushCache) ; } __except(EXCEPTION_EXECUTE_HANDLER) { status = GetExceptionCode(); if (status != EXCEPTION_ACCESS_VIOLATION) { MPR_LOG(ERROR,"WNetGetDirectoryType:Unexpected Exception 0x%lx\n",status); } status = WN_BAD_POINTER; } if (status == WN_NO_NETWORK) { statusFlag |= NO_NET; } else if ((status == WN_NOT_CONNECTED) || (status == WN_BAD_LOCALNAME)){ statusFlag |= BAD_NAME; } else { // // If it wasn't one of those errors, then the provider // must have accepted responsibility for the request. // so we exit and process the results. Note that the // statusFlag is cleared because we want to ignore other // error information that we gathered up until now. // statusFlag = 0; break; } } } if (fcnSupported == FALSE) { // // No providers in the list support the API function. Therefore, // we assume that no networks are installed. // status = WN_NOT_SUPPORTED; } // // If memory was allocated by MprFindCallOrder, free it. // if (index != indexArray) { LocalFree(index); } // // Handle special errors. // if (statusFlag == (NO_NET | BAD_NAME)) { // // Check to see if there was a mix of special errors that occured. // If so, pass back the combined error message. Otherwise, let the // last error returned get passed back. // status = WN_NO_NET_OR_BAD_PATH; } if (status != WN_SUCCESS){ SetLastError(status); } return(status); } DWORD WNetDirectoryNotifyW ( IN HWND hwnd, IN LPTSTR lpDir, IN DWORD dwOper ) /*++ Routine Description: Arguments: Return Value: Note: --*/ { DWORD providerIndex; DWORD status; LPDWORD index; DWORD indexArray[DEFAULT_MAX_PROVIDERS]; DWORD numProviders; LPPROVIDER provider; DWORD statusFlag = 0; // used to indicate major error types BOOL fcnSupported = FALSE; // Is fcn supported by a provider? DWORD i; MprCheckProviders(); CProviderSharedLock PLock; INIT_IF_NECESSARY(NETWORK_LEVEL,status); index = indexArray; // // Find the Provider Index associated with the drive letter in // the pathname (lpszName). // NOTE: This function handles exceptions. // status = MprFindProviderForPath(lpDir, &providerIndex); if (status != WN_SUCCESS) { MPR_LOG1(TRACE,"WNetDirectoryNotify: Couldn't find provider for this " "path. Error = %d\n",status); // // Find the list of providers to call for this request. // Since no provider claimed this path, then // we need to at least try the lanman provider. // Actually we'll give them all a chance. // status = MprFindCallOrder( NULL, &index, &numProviders, NETWORK_TYPE); if (status != WN_SUCCESS) { MPR_LOG(ERROR,"WNetDirectoryNotifyW: FindCallOrder Failed\n",0); return(status); } } else { numProviders = 1; index[0] = providerIndex; } // // Loop through the list of providers until one answers the request, // or the list is exhausted. // for (i=0; iDirectoryNotify != NULL) { fcnSupported = TRUE; __try { status = provider->DirectoryNotify( hwnd, lpDir, dwOper); } __except(EXCEPTION_EXECUTE_HANDLER) { status = GetExceptionCode(); if (status != EXCEPTION_ACCESS_VIOLATION) { MPR_LOG(ERROR,"WNetDirectoryNotify:Unexpected Exception 0x%lx\n",status); } status = WN_BAD_POINTER; } if (status == WN_NO_NETWORK) { statusFlag |= NO_NET; } else if ((status == WN_NOT_CONNECTED) || (status == WN_BAD_LOCALNAME)){ statusFlag |= BAD_NAME; } else { // // If it wasn't one of those errors, then the provider // must have accepted responsibility for the request. // so we exit and process the results. Note that the // statusFlag is cleared because we want to ignore other // error information that we gathered up until now. // statusFlag = 0; break; } } } if (fcnSupported == FALSE) { // // No providers in the list support the API function. Therefore, // we assume that no networks are installed. // status = WN_NOT_SUPPORTED; } // // If memory was allocated by MprFindCallOrder, free it. // if (index != indexArray) { LocalFree(index); } // // Handle special errors. // if (statusFlag == (NO_NET | BAD_NAME)) { // // Check to see if there was a mix of special errors that occured. // If so, pass back the combined error message. Otherwise, let the // last error returned get passed back. // status = WN_NO_NET_OR_BAD_PATH; } // // Handle normal errors passed back from the provider // if (status != WN_SUCCESS){ MPR_LOG(TRACE,"WNetDirectoryNotifyW: Call Failed %d\n",status); SetLastError(status); } return(status); } DWORD WNetGetHomeDirectoryW ( IN LPCWSTR lpProviderName, OUT LPWSTR lpDirectory, IN OUT LPDWORD lpBufferSize ) /*++ Routine Description: Returns the user's home directory. Arguments: lpProviderName - Specifies the name of the network provider for which the home directory is retrieved. This parameter exists for Win95 compati- bility, and is ignored. lpDirectory - Buffer in which to return the directory path. This will be in either UNC or drive-relative form. lpBufferSize - Specifies the size of the lpDirectory buffer, in characters. If the call fails because the buffer is not big enough, this will be set to the required buffer size. Return Value: WN_SUCCESS - successful WN_MORE_DATA - buffer not large enough WN_NOT_SUPPORTED - user doesn't have a home directory Note: This is an unpublished function, so it doesn't catch exceptions. The path is obtained from environment variables and equals %HOMESHARE%%HOMEPATH% if the %HOMESHARE% variable is set, else %HOMEDIR%%HOMEPATH% . --*/ { // // If HOMESHARE is set, use it in preference to HOMEDRIVE // LPWSTR ExpandString = L"%HOMEDRIVE%%HOMEPATH%"; if (GetEnvironmentVariable(L"HOMESHARE", NULL, 0)) { ExpandString = L"%HOMESHARE%%HOMEPATH%"; } // // Expand the environment variables into the buffer // DWORD cchReturned = ExpandEnvironmentStrings( ExpandString, lpDirectory, *lpBufferSize ); if (cchReturned == 0) { // ExpandEnvironmentStrings failed return GetLastError(); } if (cchReturned > *lpBufferSize) { // Buffer too small; cchReturned is the required size *lpBufferSize = cchReturned; return WN_MORE_DATA; } // // Fail if HOMEDRIVE or HOMEPATH is not set - detected by the result // string beginning with %HOMEDRIVE% or ending with %HOMEPATH% // if (wcsncmp(lpDirectory, L"%HOMEPATH%", sizeof("%HOMEPATH%") - 1) == 0 || (cchReturned > sizeof("%HOMEPATH%") && wcscmp(&lpDirectory[cchReturned-sizeof("%HOMEPATH%")], L"%HOMEPATH%") == 0)) { return WN_NOT_SUPPORTED; } return WN_SUCCESS; }