summaryrefslogtreecommitdiffstats
path: root/private/nw/svcdlls/nwwks/client/provider.c
diff options
context:
space:
mode:
Diffstat (limited to 'private/nw/svcdlls/nwwks/client/provider.c')
-rw-r--r--private/nw/svcdlls/nwwks/client/provider.c3051
1 files changed, 3051 insertions, 0 deletions
diff --git a/private/nw/svcdlls/nwwks/client/provider.c b/private/nw/svcdlls/nwwks/client/provider.c
new file mode 100644
index 000000000..4f8bf2c30
--- /dev/null
+++ b/private/nw/svcdlls/nwwks/client/provider.c
@@ -0,0 +1,3051 @@
+/*++
+
+Copyright (c) 1993 Microsoft Corporation
+
+Module Name:
+
+ provider.c
+
+Abstract:
+
+ This module contains NetWare Network Provider code. It is the
+ client-side wrapper for APIs supported by the Workstation service.
+
+Author:
+
+ Rita Wong (ritaw) 15-Feb-1993
+
+Revision History:
+
+ Yi-Hsin Sung (yihsins) 10-July-1993
+ Moved all dialog handling to nwdlg.c
+
+--*/
+
+#include <nwclient.h>
+#include <nwsnames.h>
+#include <nwcanon.h>
+#include <validc.h>
+#include <nwevent.h>
+#include <ntmsv1_0.h>
+#include <nwdlg.h>
+#include <nwreg.h>
+#include <nwauth.h>
+#include <mpr.h> // WNFMT_ manifests
+#include <nwmisc.h>
+
+#ifndef NT1057
+#include <nwutil.h>
+#endif
+
+//-------------------------------------------------------------------//
+// //
+// Local Function Prototypes //
+// //
+//-------------------------------------------------------------------//
+
+STATIC
+BOOL
+NwpWorkstationStarted(
+ VOID
+ );
+
+STATIC
+DWORD
+NwpMapNameToUNC(
+ IN LPWSTR pszName,
+ OUT LPWSTR *ppszUNC
+ );
+
+STATIC
+VOID
+NwpGetUncInfo(
+ IN LPWSTR lpstrUnc,
+ OUT WORD * slashCount,
+ OUT BOOL * isNdsUnc
+ );
+
+STATIC
+DWORD
+NwpGetUncObjectName(
+ IN LPWSTR ContainerName
+ );
+
+//-------------------------------------------------------------------//
+// //
+// Global variables //
+// //
+//-------------------------------------------------------------------//
+
+#if DBG
+DWORD NwProviderTrace = 0;
+#endif
+
+
+DWORD
+APIENTRY
+NPGetCaps(
+ IN DWORD QueryVal
+ )
+/*++
+
+Routine Description:
+
+ This function returns the functionality supported by this network
+ provider.
+
+Arguments:
+
+ QueryVal - Supplies a value which determines the type of information
+ queried regarding the network provider's support in this area.
+
+Return Value:
+
+ Returns a value which indicates the level of support given by this
+ provider.
+
+--*/
+{
+
+#if DBG
+ IF_DEBUG(INIT) {
+ KdPrint(("\nNWPROVAU: NPGetCaps %lu\n", QueryVal));
+ }
+#endif
+
+ switch (QueryVal) {
+
+ case WNNC_SPEC_VERSION:
+ return 0x00040000;
+
+ case WNNC_NET_TYPE:
+ return WNNC_NET_NETWARE ;
+
+ case WNNC_USER:
+ return WNNC_USR_GETUSER;
+
+ case WNNC_CONNECTION:
+ return (WNNC_CON_ADDCONNECTION |
+ WNNC_CON_ADDCONNECTION3 |
+ WNNC_CON_CANCELCONNECTION |
+ WNNC_CON_GETPERFORMANCE |
+ WNNC_CON_GETCONNECTIONS);
+
+ case WNNC_ENUMERATION:
+ return ( WNNC_ENUM_GLOBAL |
+ WNNC_ENUM_CONTEXT |
+ WNNC_ENUM_LOCAL );
+
+ case WNNC_START:
+ if (NwpWorkstationStarted()) {
+ return 1;
+ }
+ else {
+ return 0xffffffff; // don't know
+ }
+
+ case WNNC_DIALOG:
+ return WNNC_DLG_FORMATNETWORKNAME
+#ifdef NT1057
+ ;
+#else
+ | WNNC_DLG_GETRESOURCEPARENT | WNNC_DLG_GETRESOURCEINFORMATION;
+#endif
+
+ //
+ // The rest are not supported by the NetWare provider
+ //
+ default:
+ return 0;
+ }
+
+}
+
+#define NW_EVENT_MESSAGE_FILE L"nwevent.dll"
+
+
+
+DWORD
+APIENTRY
+NPGetUser(
+ LPWSTR lpName,
+ LPWSTR lpUserName,
+ LPDWORD lpUserNameLen
+ )
+/*++
+
+Routine Description:
+
+ This is used to determine either the current default username, or the
+ username used to establish a network connection.
+
+Arguments:
+
+ lpName - Contains the name of the local device the caller is interested
+ in, or a network name that the user has made a connection to. This
+ may be NULL or the empty string if the caller is interested in the
+ name of the user currently logged on to the system. If a network
+ name is passed in, and the user is connected to that resource using
+ different names, it is possible that a provider cannont resolve
+ which username to return. In this case the provider may make an
+ arbitrary choice amonst the possible usernames.
+
+ lpUserName - Points to a buffer to receive the user name. this should
+ be a name that can be passed into the NPAddConnection or
+ NPAddConnection3 function to re-establish the connection with the
+ same user name.
+
+ lpBufferSize - This is used to specify the size (in characters) of the
+ buffer passed in. If the call fails because the buffer is not big
+ enough, this location will be used to return the required buffer size.
+
+Return Value:
+
+ WN_SUCCESS - If the call is successful. Otherwise, an error code is,
+ returned, which may include:
+
+ WN_NOT_CONNECTED - lpName not a redirected device nor a connected network
+ name.
+
+ WN_MORE_DATA - The buffer is too small.
+
+ WN_NO_NETWORK - Network not present.
+
+--*/
+{
+ DWORD status;
+ DWORD dwUserNameBufferSize = *lpUserNameLen * sizeof(WCHAR);
+ DWORD CharsRequired = 0;
+
+ if (lpName == NULL)
+ {
+ return WN_NOT_CONNECTED;
+ }
+
+ RtlZeroMemory( lpUserName, dwUserNameBufferSize );
+
+#if DBG
+ IF_DEBUG(CONNECT)
+ {
+ KdPrint(("\nNWPROVAU: NPGetUser %ws\n", lpName));
+ }
+#endif
+
+ RpcTryExcept
+ {
+ status = NwrGetUser(
+ NULL,
+ lpName,
+ (LPBYTE) lpUserName,
+ dwUserNameBufferSize,
+ &CharsRequired
+ );
+
+ if (status == WN_MORE_DATA)
+ {
+ //
+ // Output buffer too small.
+ //
+ *lpUserNameLen = CharsRequired;
+ }
+ }
+ RpcExcept(1)
+ {
+ status = NwpMapRpcError(RpcExceptionCode());
+ }
+ RpcEndExcept
+
+ if (status != NO_ERROR)
+ {
+ SetLastError(status);
+ }
+
+ return status;
+}
+
+
+DWORD
+APIENTRY
+NPAddConnection(
+ LPNETRESOURCEW lpNetResource,
+ LPWSTR lpPassword,
+ LPWSTR lpUserName
+ )
+/*++
+
+Routine Description:
+
+ This function creates a remote connection.
+
+Arguments:
+
+ lpNetResource - Supplies the NETRESOURCE structure which specifies
+ the local DOS device to map, the remote resource to connect to
+ and other attributes related to the connection.
+
+ lpPassword - Supplies the password to connect with.
+
+ lpUserName - Supplies the username to connect with.
+
+Return Value:
+
+ NO_ERROR - Successful.
+
+ WN_BAD_VALUE - Invalid value specifed in lpNetResource.
+
+ WN_BAD_NETNAME - Invalid remote resource name.
+
+ WN_BAD_LOCALNAME - Invalid local DOS device name.
+
+ WN_BAD_PASSWORD - Invalid password.
+
+ WN_ALREADY_CONNECTED - Local DOS device name is already in use.
+
+ Other network errors.
+
+--*/
+{
+ DWORD status = NO_ERROR;
+ LPWSTR pszRemoteName = NULL;
+
+ UCHAR EncodeSeed = NW_ENCODE_SEED3;
+ UNICODE_STRING PasswordStr;
+
+ LPWSTR CachedUserName = NULL ;
+ LPWSTR CachedPassword = NULL ;
+
+ PasswordStr.Length = 0;
+
+ status = NwpMapNameToUNC(
+ lpNetResource->lpRemoteName,
+ &pszRemoteName );
+
+ if (status != NO_ERROR)
+ {
+ SetLastError(status);
+ return status;
+ }
+
+#if DBG
+ IF_DEBUG(CONNECT) {
+ KdPrint(("\nNWPROVAU: NPAddConnection %ws\n", pszRemoteName));
+ }
+#endif
+
+ RpcTryExcept
+ {
+ if (lpNetResource->dwType != RESOURCETYPE_ANY &&
+ lpNetResource->dwType != RESOURCETYPE_DISK &&
+ lpNetResource->dwType != RESOURCETYPE_PRINT)
+ {
+ status = WN_BAD_VALUE;
+ }
+ else
+ {
+#ifdef NT1057
+ //
+ // no credentials specified, see if we have cached credentials
+ //
+ if (!lpPassword && !lpUserName)
+ {
+ (void) NwpRetrieveCachedCredentials(
+ pszRemoteName,
+ &CachedUserName,
+ &CachedPassword) ;
+
+ //
+ // these values will be NULL still if nothing found
+ //
+ lpPassword = CachedPassword ;
+ lpUserName = CachedUserName ;
+ }
+#endif
+
+ //
+ // Encode password.
+ //
+ RtlInitUnicodeString(&PasswordStr, lpPassword);
+ RtlRunEncodeUnicodeString(&EncodeSeed, &PasswordStr);
+
+ status = NwrCreateConnection(
+ NULL,
+ lpNetResource->lpLocalName,
+ pszRemoteName,
+ lpNetResource->dwType,
+ lpPassword,
+ lpUserName
+ );
+
+ if (CachedUserName)
+ {
+ (void)LocalFree((HLOCAL)CachedUserName);
+ }
+
+ if (CachedPassword)
+ {
+ RtlZeroMemory(CachedPassword,
+ wcslen(CachedPassword) *
+ sizeof(WCHAR)) ;
+ (void)LocalFree((HLOCAL)CachedPassword);
+ }
+ }
+ }
+ RpcExcept(1)
+ {
+ status = NwpMapRpcError(RpcExceptionCode());
+ }
+ RpcEndExcept
+
+ if (PasswordStr.Length != 0 && !CachedPassword)
+ {
+ //
+ // Restore password to original state
+ //
+ RtlRunDecodeUnicodeString(NW_ENCODE_SEED3, &PasswordStr);
+ }
+
+ if (status == ERROR_SHARING_PAUSED)
+ {
+ HMODULE MessageDll;
+ WCHAR Buffer[1024];
+ DWORD MessageLength;
+ DWORD err;
+ HKEY hkey;
+ LPWSTR pszProviderName = NULL;
+
+ //
+ // Load the netware message file DLL
+ //
+ MessageDll = LoadLibraryW(NW_EVENT_MESSAGE_FILE);
+
+ if (MessageDll == NULL)
+ {
+ goto ExitPoint ;
+ }
+
+ //
+ // Read the Network Provider Name.
+ //
+ // Open HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services
+ // \NWCWorkstation\networkprovider
+ //
+ err = RegOpenKeyExW(
+ HKEY_LOCAL_MACHINE,
+ NW_WORKSTATION_PROVIDER_PATH,
+ REG_OPTION_NON_VOLATILE, // options
+ KEY_READ, // desired access
+ &hkey
+ );
+
+ if ( !err )
+ {
+ //
+ // ignore the return code. if fail, pszProviderName is NULL
+ //
+ err = NwReadRegValue(
+ hkey,
+ NW_PROVIDER_VALUENAME,
+ &pszProviderName // free with LocalFree
+ );
+
+ RegCloseKey( hkey );
+ }
+
+ if (err)
+ {
+ (void) FreeLibrary(MessageDll);
+ goto ExitPoint ;
+ }
+
+ RtlZeroMemory(Buffer, sizeof(Buffer)) ;
+
+ //
+ // Get string from message file
+ //
+ MessageLength = FormatMessageW(
+ FORMAT_MESSAGE_FROM_HMODULE,
+ (LPVOID) MessageDll,
+ NW_LOGIN_DISABLED,
+ 0,
+ Buffer,
+ sizeof(Buffer) / sizeof(WCHAR),
+ NULL
+ );
+
+ if (MessageLength != 0)
+ {
+ status = WN_EXTENDED_ERROR ;
+ WNetSetLastErrorW(NW_LOGIN_DISABLED,
+ Buffer,
+ pszProviderName) ;
+ }
+
+ (void) LocalFree( (HLOCAL) pszProviderName );
+ (void) FreeLibrary(MessageDll);
+
+ }
+
+ExitPoint:
+
+ if (status != NO_ERROR)
+ {
+ SetLastError(status);
+ }
+
+ LocalFree( (HLOCAL) pszRemoteName );
+ return status;
+}
+
+
+DWORD
+APIENTRY
+NPAddConnection3(
+ HWND hwndOwner,
+ LPNETRESOURCEW lpNetResource,
+ LPWSTR lpPassword,
+ LPWSTR lpUserName,
+ DWORD dwConnFlags
+ )
+/*++
+
+Routine Description:
+
+ This function creates a remote connection.
+
+Arguments:
+
+ hwndOwner - Owner window handle for dialog boxes
+
+ lpNetResource - Supplies the NETRESOURCE structure which specifies
+ the local DOS device to map, the remote resource to connect to
+ and other attributes related to the connection.
+
+ lpPassword - Supplies the password to connect with.
+
+ lpUserName - Supplies the username to connect with.
+
+ dwConnFlags - CONNECT_UPDATE_PROFILE...
+
+Return Value:
+
+ NO_ERROR - Successful.
+
+ WN_BAD_VALUE - Invalid value specifed in lpNetResource.
+
+ WN_BAD_NETNAME - Invalid remote resource name.
+
+ WN_BAD_LOCALNAME - Invalid local DOS device name.
+
+ WN_BAD_PASSWORD - Invalid password.
+
+ WN_ALREADY_CONNECTED - Local DOS device name is already in use.
+
+ Other network errors.
+
+--*/
+{
+ DWORD err = NO_ERROR;
+ LPWSTR UserName = NULL;
+ LPWSTR Password = NULL;
+
+ if ( ( dwConnFlags & CONNECT_PROMPT )
+ && !( dwConnFlags & CONNECT_INTERACTIVE )
+ )
+ {
+ return WN_BAD_VALUE;
+ }
+
+ if ( !(dwConnFlags & CONNECT_PROMPT ))
+ {
+ err = NPAddConnection( lpNetResource,
+ lpPassword,
+ lpUserName );
+
+ if ( ( err == NO_ERROR )
+ || !( dwConnFlags & CONNECT_INTERACTIVE ) // Cannot popup dialog
+ )
+ {
+ return err;
+ }
+ }
+
+ for (;;)
+ {
+ if ( ( err != NO_ERROR ) // CONNECT_PROMPT
+ && ( err != WN_BAD_PASSWORD )
+ && ( err != WN_ACCESS_DENIED )
+ && ( err != ERROR_NO_SUCH_USER )
+ )
+ {
+ // Errors not related to access problems
+ break;
+ }
+
+ if ( UserName )
+ {
+ (void) LocalFree( UserName );
+ UserName = NULL;
+ }
+
+ if ( Password )
+ {
+ memset( Password, 0, wcslen(Password) * sizeof(WCHAR));
+ (void) LocalFree( Password );
+ Password = NULL;
+ }
+
+ //
+ // Put up dialog to get username
+ // and password.
+ //
+ err = NwpGetUserCredential( hwndOwner,
+ lpNetResource->lpRemoteName,
+ err,
+ lpUserName,
+ &UserName,
+ &Password );
+
+ if ( err != NO_ERROR )
+ break;
+
+ err = NPAddConnection( lpNetResource,
+ Password,
+ UserName );
+
+ if ( err == NO_ERROR )
+ {
+#if 0
+ if ( (UserName != NULL) && (Password != NULL))
+ {
+ // Checking UserName and Password is to make sure that
+ // we have prompted for password
+ (VOID) NwpCacheCredentials( lpNetResource->lpRemoteName,
+ UserName,
+ Password ) ;
+ }
+#endif
+ break;
+ }
+ }
+
+ if ( UserName )
+ (void) LocalFree( UserName );
+
+ if ( Password )
+ {
+ memset( Password, 0, wcslen(Password) * sizeof(WCHAR));
+ (void) LocalFree( Password );
+ }
+
+ return err;
+}
+
+
+
+DWORD
+APIENTRY
+NPCancelConnection(
+ LPWSTR lpName,
+ BOOL fForce
+ )
+/*++
+
+Routine Description:
+
+ This function deletes a remote connection.
+
+Arguments:
+
+ lpName - Supplies the local DOS device, or the remote resource name
+ if it is a UNC connection to delete.
+
+ fForce - Supplies the force level to break the connection. TRUE means
+ to forcefully delete the connection, FALSE means end the connection
+ only if there are no opened files.
+
+Return Value:
+
+ NO_ERROR - Successful.
+
+ WN_BAD_NETNAME - Invalid remote resource name.
+
+ WN_NOT_CONNECTED - Connection could not be found.
+
+ WN_OPEN_FILES - fForce is FALSE and there are opened files on the
+ connection.
+
+ Other network errors.
+
+--*/
+{
+ DWORD status = NO_ERROR;
+ LPWSTR pszName = NULL;
+
+ //
+ // We only need to map remote resource name
+ //
+
+ if ( NwLibValidateLocalName( lpName ) != NO_ERROR )
+ {
+ status = NwpMapNameToUNC(
+ lpName,
+ &pszName
+ );
+
+ if (status != NO_ERROR) {
+ SetLastError(status);
+ return status;
+ }
+ }
+
+#if DBG
+ IF_DEBUG(CONNECT) {
+ KdPrint(("\nNWPROVAU: NPCancelConnection %ws, Force %u\n",
+ pszName? pszName : lpName, fForce));
+ }
+#endif
+
+ RpcTryExcept {
+
+ status = NwrDeleteConnection(
+ NULL,
+ pszName? pszName : lpName,
+ (DWORD) fForce
+ );
+
+ }
+ RpcExcept(1) {
+ status = NwpMapRpcError(RpcExceptionCode());
+ }
+ RpcEndExcept
+
+ if (status != NO_ERROR) {
+ SetLastError(status);
+ }
+
+ LocalFree( (HLOCAL) pszName );
+ return status;
+
+}
+
+
+
+DWORD
+APIENTRY
+NPGetConnection(
+ LPWSTR lpLocalName,
+ LPWSTR lpRemoteName,
+ LPDWORD lpnBufferLen
+ )
+/*++
+
+Routine Description:
+
+ This function returns the remote resource name for a given local
+ DOS device.
+
+Arguments:
+
+ lpLocalName - Supplies the local DOS device to look up.
+
+ lpRemoteName - Output buffer to receive the remote resource name
+ mapped to lpLocalName.
+
+ lpnBufferLen - On input, supplies length of the lpRemoteName buffer
+ in number of characters. On output, if error returned is
+ WN_MORE_DATA, receives the number of characters required of
+ the output buffer to hold the output string.
+
+Return Value:
+
+ NO_ERROR - Successful.
+
+ WN_BAD_LOCALNAME - Invalid local DOS device.
+
+ WN_NOT_CONNECTED - Connection could not be found.
+
+ WN_MORE_DATA - Output buffer is too small.
+
+ Other network errors.
+
+--*/
+{
+
+ DWORD status = NO_ERROR;
+ DWORD CharsRequired;
+
+#if DBG
+ IF_DEBUG(CONNECT) {
+ KdPrint(("\nNWPROVAU: NPGetConnection %ws\n", lpLocalName));
+ }
+#endif
+
+ RpcTryExcept {
+
+ if (lpRemoteName && *lpnBufferLen)
+ *lpRemoteName = 0 ;
+
+ status = NwrQueryServerResource(
+ NULL,
+ lpLocalName,
+ (*lpnBufferLen == 0? NULL : lpRemoteName),
+ *lpnBufferLen,
+ &CharsRequired
+ );
+
+ if (status == ERROR_INSUFFICIENT_BUFFER)
+ status = WN_MORE_DATA;
+
+ if (status == WN_MORE_DATA) {
+ *lpnBufferLen = CharsRequired;
+ }
+
+ }
+ RpcExcept(1) {
+ status = NwpMapRpcError(RpcExceptionCode());
+ }
+ RpcEndExcept
+
+ if (status != NO_ERROR) {
+ SetLastError(status);
+ }
+
+#if DBG
+ IF_DEBUG(CONNECT) {
+ KdPrint(("\nNWPROVAU: NPGetConnection returns %lu\n", status));
+ if (status == NO_ERROR) {
+ KdPrint((" %ws, BufferLen %lu, CharsRequired %lu\n", lpRemoteName, *lpnBufferLen, CharsRequired));
+
+ }
+ }
+#endif
+
+ return status;
+}
+
+
+DWORD
+APIENTRY
+NPGetConnectionPerformance(
+ LPCWSTR lpRemoteName,
+ LPNETCONNECTINFOSTRUCT lpNetConnectInfo
+ )
+/*++
+
+Routine Description:
+
+ This function returns information about the expected performance of a
+ connection used to access a network resource. The request can only be
+ for a network resource to which there is currently a connection.
+
+Arguments:
+
+ lpRemoteName - Contains the local name or remote name for a resource
+ for which a connection exists.
+
+ lpNetConnectInfo - This is a pointer to a NETCONNECTINFOSTRUCT structure
+ which is to be filled if the connection performance
+ of connection lpRemoteName can be determined.
+
+Return Value:
+
+ NO_ERROR - Successful.
+
+ WN_NOT_CONNECTED - Connection could not be found.
+
+ WN_NONETWORK - Network is not present.
+
+ Other network errors.
+
+--*/
+{
+ DWORD status = NO_ERROR;
+ LPWSTR pszRemoteName;
+
+ if ( lpNetConnectInfo == NULL )
+ {
+ status = ERROR_INVALID_PARAMETER;
+ SetLastError(status);
+ return status;
+ }
+
+ pszRemoteName = (LPWSTR) LocalAlloc( LMEM_ZEROINIT,
+ ( wcslen(lpRemoteName) + 1 ) *
+ sizeof(WCHAR) );
+
+ if ( pszRemoteName == NULL )
+ {
+ status = ERROR_NOT_ENOUGH_MEMORY;
+ SetLastError(status);
+ return status;
+ }
+
+ wcscpy( pszRemoteName, lpRemoteName );
+ _wcsupr( pszRemoteName );
+
+#if DBG
+ IF_DEBUG(CONNECT) {
+ KdPrint(("\nNWPROVAU: NPGetConnectionPerformance %ws\n", pszRemoteName));
+ }
+#endif
+
+ RpcTryExcept {
+
+ status = NwrGetConnectionPerformance(
+ NULL,
+ pszRemoteName,
+ (LPBYTE) lpNetConnectInfo,
+ sizeof(NETCONNECTINFOSTRUCT) );
+
+ }
+ RpcExcept(1)
+ {
+ status = NwpMapRpcError(RpcExceptionCode());
+ }
+ RpcEndExcept
+
+ if (status != NO_ERROR)
+ {
+ SetLastError(status);
+ }
+
+ LocalFree( (HLOCAL) pszRemoteName );
+ return status;
+}
+
+
+
+DWORD
+APIENTRY
+NPGetUniversalName(
+#ifdef NT1057
+ LPWSTR lpLocalPath,
+#else
+ LPCWSTR lpLocalPath,
+#endif
+ DWORD dwInfoLevel,
+ LPVOID lpBuffer,
+ LPDWORD lpBufferSize
+ )
+/*++
+
+Routine Description:
+
+ This function returns the universal resource name for a given local
+ path.
+
+Arguments:
+
+ lpLocalPath - Supplies the local DOS Path to look up.
+
+ dwInfoLevel - Info level requested.
+
+ lpBuffer - Output buffer to receive the appropruatye structure.
+
+ lpBufferLen - On input, supplies length of the buffer in number of
+ bytes. On output, if error returned is WN_MORE_DATA, receives
+ the number of bytes required of the output buffer.
+
+Return Value:
+
+ NO_ERROR - Successful.
+
+ WN_BAD_LOCALNAME - Invalid local DOS device.
+
+ WN_NOT_CONNECTED - Connection could not be found.
+
+ WN_MORE_DATA - Output buffer is too small.
+
+ Other network errors.
+
+--*/
+{
+
+ DWORD status = NO_ERROR;
+ DWORD dwCharsRequired = MAX_PATH + 1 ;
+ DWORD dwBytesNeeded ;
+ DWORD dwLocalLength ;
+ LPWSTR lpRemoteBuffer ;
+ WCHAR szDrive[3] ;
+
+ //
+ // check for bad info level
+ //
+ if ((dwInfoLevel != UNIVERSAL_NAME_INFO_LEVEL) &&
+ (dwInfoLevel != REMOTE_NAME_INFO_LEVEL))
+ {
+ return WN_BAD_VALUE ;
+ }
+
+ //
+ // check for bad pointers
+ //
+ if (!lpLocalPath || !lpBuffer || !lpBufferSize)
+ {
+ return WN_BAD_POINTER ;
+ }
+
+ //
+ // local path must at least have "X:"
+ //
+ if (((dwLocalLength = wcslen(lpLocalPath)) < 2) ||
+ (lpLocalPath[1] != L':') ||
+ ((dwLocalLength > 2) && (lpLocalPath[2] != L'\\')))
+ {
+ return WN_BAD_VALUE ;
+ }
+
+ //
+ // preallocate some memory
+ //
+ if (!(lpRemoteBuffer = (LPWSTR) LocalAlloc(
+ LPTR,
+ dwCharsRequired * sizeof(WCHAR))))
+ {
+ status = GetLastError() ;
+ goto ErrorExit ;
+ }
+
+ szDrive[2] = 0 ;
+ wcsncpy(szDrive, lpLocalPath, 2) ;
+
+ //
+ // get the remote path by calling the existing API
+ //
+ status = NPGetConnection(
+ szDrive,
+ lpRemoteBuffer,
+ &dwCharsRequired) ;
+
+ if (status == WN_MORE_DATA)
+ {
+ //
+ // reallocate the correct size
+ //
+
+ if (!(lpRemoteBuffer = (LPWSTR) LocalReAlloc(
+ (HLOCAL) lpRemoteBuffer,
+ dwCharsRequired * sizeof(WCHAR),
+ LMEM_MOVEABLE)))
+ {
+ status = GetLastError() ;
+ goto ErrorExit ;
+ }
+
+ status = NPGetConnection(
+ szDrive,
+ lpRemoteBuffer,
+ &dwCharsRequired) ;
+ }
+
+ if (status != WN_SUCCESS)
+ {
+ goto ErrorExit ;
+ }
+
+ //
+ // at minimum we will need this size of the UNC name
+ // the -2 is because we loose the drive letter & colon.
+ //
+ dwBytesNeeded = (wcslen(lpRemoteBuffer) +
+ dwLocalLength - 2 + 1) * sizeof(WCHAR) ;
+
+ switch (dwInfoLevel)
+ {
+ case UNIVERSAL_NAME_INFO_LEVEL:
+ {
+ LPUNIVERSAL_NAME_INFO lpUniversalNameInfo ;
+
+ //
+ // calculate how many bytes we really need
+ //
+ dwBytesNeeded += sizeof(UNIVERSAL_NAME_INFO) ;
+
+ if (*lpBufferSize < dwBytesNeeded)
+ {
+ *lpBufferSize = dwBytesNeeded ;
+ status = WN_MORE_DATA ;
+ break ;
+ }
+
+ //
+ // now we are all set. just stick the data in the buffer
+ //
+ lpUniversalNameInfo = (LPUNIVERSAL_NAME_INFO) lpBuffer ;
+
+ lpUniversalNameInfo->lpUniversalName = (LPWSTR)
+ (((LPBYTE)lpBuffer) + sizeof(UNIVERSAL_NAME_INFO)) ;
+ wcscpy(lpUniversalNameInfo->lpUniversalName,
+ lpRemoteBuffer) ;
+ wcscat(lpUniversalNameInfo->lpUniversalName,
+ lpLocalPath+2) ;
+
+ break ;
+ }
+
+ case REMOTE_NAME_INFO_LEVEL :
+ {
+ LPREMOTE_NAME_INFO lpRemoteNameInfo ;
+
+ //
+ // calculate how many bytes we really need
+ //
+ dwBytesNeeded *= 2 ; // essentially twice the info + terminator
+ dwBytesNeeded += (sizeof(REMOTE_NAME_INFO) + sizeof(WCHAR)) ;
+
+ if (*lpBufferSize < dwBytesNeeded)
+ {
+ *lpBufferSize = dwBytesNeeded ;
+ status = WN_MORE_DATA ;
+ break ;
+ }
+
+ //
+ // now we are all set. just stick the data in the buffer
+ //
+ lpRemoteNameInfo = (LPREMOTE_NAME_INFO) lpBuffer ;
+
+ lpRemoteNameInfo->lpUniversalName = (LPWSTR)
+ (((LPBYTE)lpBuffer) + sizeof(REMOTE_NAME_INFO)) ;
+ wcscpy(lpRemoteNameInfo->lpUniversalName,
+ lpRemoteBuffer) ;
+ wcscat(lpRemoteNameInfo->lpUniversalName,
+ lpLocalPath+2) ;
+
+ lpRemoteNameInfo->lpConnectionName =
+ lpRemoteNameInfo->lpUniversalName +
+ wcslen(lpRemoteNameInfo->lpUniversalName) + 1 ;
+ wcscpy(lpRemoteNameInfo->lpConnectionName,
+ lpRemoteBuffer) ;
+
+ lpRemoteNameInfo->lpRemainingPath =
+ lpRemoteNameInfo->lpConnectionName +
+ wcslen(lpRemoteNameInfo->lpConnectionName) + 1 ;
+ wcscpy(lpRemoteNameInfo->lpRemainingPath,
+ lpLocalPath+2) ;
+
+ break ;
+ }
+
+ default:
+ //
+ // yikes!
+ //
+ status = WN_BAD_VALUE ;
+ ASSERT(FALSE);
+ }
+
+ErrorExit:
+
+ if (lpRemoteBuffer)
+ {
+ (void) LocalFree((HLOCAL)lpRemoteBuffer) ;
+ }
+ return status;
+}
+
+
+
+DWORD
+APIENTRY
+NPOpenEnum(
+ DWORD dwScope,
+ DWORD dwType,
+ DWORD dwUsage,
+ LPNETRESOURCEW lpNetResource,
+ LPHANDLE lphEnum
+ )
+/*++
+
+Routine Description:
+
+ This function initiates an enumeration of either connections, or
+ browsing of network resource.
+
+Arguments:
+
+ dwScope - Supplies the category of enumeration to do--either
+ connection or network browsing.
+
+ dwType - Supplies the type of resource to get--either disk,
+ print, or it does not matter.
+
+ dwUsage - Supplies the object type to get--either container,
+ or connectable usage.
+
+ lpNetResource - Supplies, in the lpRemoteName field, the container
+ name to enumerate under.
+
+ lphEnum - Receives the resumable context handle to be used on all
+ subsequent calls to get the list of objects under the container.
+
+Return Value:
+
+ NO_ERROR - Successful.
+
+ WN_BAD_VALUE - Either the dwScope, dwType, or the dwUsage specified
+ is not acceptable.
+
+ WN_BAD_NETNAME - Invalid remote resource name.
+
+ WN_NOT_CONTAINER - Remote resource name is not a container.
+
+ Other network errors.
+
+--*/
+{
+ DWORD status = NO_ERROR;
+
+#if DBG
+ IF_DEBUG(ENUM)
+ {
+ KdPrint(("\nNWPROVAU: NPOpenEnum\n"));
+ }
+#endif
+
+
+ RpcTryExcept
+ {
+ if ( ( dwType & RESOURCETYPE_DISK ) ||
+ ( dwType & RESOURCETYPE_PRINT ) ||
+ ( dwType == RESOURCETYPE_ANY ) )
+ {
+ switch ( dwScope )
+ {
+ case RESOURCE_CONNECTED:
+
+ status = NwrOpenEnumConnections( NULL,
+ dwType,
+ (LPNWWKSTA_CONTEXT_HANDLE) lphEnum );
+ break;
+
+ case RESOURCE_CONTEXT:
+
+ status = NwrOpenEnumContextInfo( NULL,
+ dwType,
+ (LPNWWKSTA_CONTEXT_HANDLE) lphEnum );
+ break;
+
+ case RESOURCE_GLOBALNET:
+
+ if ( lpNetResource == NULL )
+ {
+ //
+ // Enumerating servers and NDS trees
+ //
+ if ( dwUsage & RESOURCEUSAGE_CONTAINER || dwUsage == 0 )
+ {
+ status = NwrOpenEnumServersAndNdsTrees( NULL,
+ (LPNWWKSTA_CONTEXT_HANDLE) lphEnum );
+ }
+ else
+ {
+ //
+ // There is no such thing as a connectable server
+ // object.
+ //
+ status = WN_BAD_VALUE;
+ }
+ }
+ else
+ {
+ BOOL IsEnumVolumes = TRUE;
+ LPWSTR pszRemoteName = NULL;
+ WORD slashCount;
+ BOOL isNdsUnc;
+
+ NwpGetUncInfo( lpNetResource->lpRemoteName,
+ &slashCount,
+ &isNdsUnc );
+
+ //
+ // Either enumerating volumes, directories, or NDS subtrees
+ //
+
+ if ( dwUsage & RESOURCEUSAGE_CONNECTABLE ||
+ dwUsage & RESOURCEUSAGE_CONTAINER ||
+ dwUsage == 0 )
+ {
+ LPWSTR tempStrPtr = lpNetResource->lpRemoteName;
+ DWORD dwClassType = 0;
+
+ if ( tempStrPtr[0] == L' ' &&
+ tempStrPtr[1] == L'\\' &&
+ tempStrPtr[2] == L'\\' )
+ tempStrPtr = &tempStrPtr[1];
+
+ if ( lpNetResource->dwDisplayType == RESOURCEDISPLAYTYPE_TREE )
+ {
+ if ( ( dwType == RESOURCETYPE_ANY ) ||
+ ( ( dwType & RESOURCETYPE_DISK ) &&
+ ( dwType & RESOURCETYPE_PRINT ) ) )
+ {
+ status = NwrOpenEnumNdsSubTrees_Any( NULL,
+ tempStrPtr,
+ NULL,
+ (LPNWWKSTA_CONTEXT_HANDLE) lphEnum );
+ }
+ else if ( dwType & RESOURCETYPE_DISK )
+ {
+ status = NwrOpenEnumNdsSubTrees_Disk( NULL,
+ tempStrPtr,
+ NULL,
+ (LPNWWKSTA_CONTEXT_HANDLE) lphEnum );
+ }
+ else if ( dwType & RESOURCETYPE_PRINT )
+ {
+ status = NwrOpenEnumNdsSubTrees_Print( NULL,
+ tempStrPtr,
+ NULL,
+ (LPNWWKSTA_CONTEXT_HANDLE) lphEnum );
+ }
+ else
+ {
+ KdPrint(("NWOpenEnum: Unhandled dwType %lu\n", dwType));
+ }
+ }
+ else if (
+ ( slashCount < 4 ) &&
+ ( ( dwType == RESOURCETYPE_ANY ) ||
+ ( ( dwType & RESOURCETYPE_DISK ) &&
+ ( dwType & RESOURCETYPE_PRINT ) ) ) &&
+ ( ( status = NwrOpenEnumNdsSubTrees_Any( NULL,
+ tempStrPtr,
+ &dwClassType,
+ (LPNWWKSTA_CONTEXT_HANDLE) lphEnum ) )
+ ==NO_ERROR )
+ )
+ {
+ status = NO_ERROR;
+ }
+ else if (
+ ( slashCount < 4 ) &&
+ ( dwType & RESOURCETYPE_DISK ) &&
+ ( ( status = NwrOpenEnumNdsSubTrees_Disk( NULL,
+ tempStrPtr,
+ &dwClassType,
+ (LPNWWKSTA_CONTEXT_HANDLE) lphEnum ) )
+ ==NO_ERROR )
+ )
+ {
+ status = NO_ERROR;
+ }
+ else if (
+ ( slashCount < 4 ) &&
+ ( dwType & RESOURCETYPE_PRINT ) &&
+ ( ( status = NwrOpenEnumNdsSubTrees_Print( NULL,
+ tempStrPtr,
+ &dwClassType,
+ (LPNWWKSTA_CONTEXT_HANDLE) lphEnum ) )
+ ==NO_ERROR )
+ )
+ {
+ status = NO_ERROR;
+ }
+ else if (
+ (slashCount < 4
+ &&
+ (status == ERROR_NETWORK_ACCESS_DENIED
+ ||
+ status == ERROR_GEN_FAILURE
+ ||
+ status == ERROR_ACCESS_DENIED
+ ||
+ status == ERROR_BAD_NETPATH
+ ||
+ status == WN_BAD_NETNAME
+ ||
+ status == ERROR_INVALID_NAME))
+ ||
+ ( slashCount > 3 && status == NO_ERROR )
+ )
+ {
+ if (( status == ERROR_NETWORK_ACCESS_DENIED ) &&
+ ( dwClassType == CLASS_TYPE_NCP_SERVER ))
+ {
+ status = NO_ERROR;
+ isNdsUnc = TRUE;
+ IsEnumVolumes = TRUE;
+ }
+ else if ( ( status == ERROR_NETWORK_ACCESS_DENIED ) &&
+ ( ( dwClassType == CLASS_TYPE_VOLUME ) ||
+ ( dwClassType == CLASS_TYPE_DIRECTORY_MAP ) ) )
+ {
+ status = NO_ERROR;
+ isNdsUnc = TRUE;
+ IsEnumVolumes = FALSE;
+ }
+ else
+ {
+ //
+ // A third backslash means that we want to
+ // enumerate the directories.
+ //
+
+ if ( isNdsUnc && slashCount > 3 )
+ IsEnumVolumes = FALSE;
+
+ if ( !isNdsUnc && slashCount > 2 )
+ IsEnumVolumes = FALSE;
+
+ if ( lpNetResource->dwDisplayType == RESOURCEDISPLAYTYPE_SHARE )
+ IsEnumVolumes = FALSE;
+ }
+
+ status = NwpMapNameToUNC( tempStrPtr,
+ &pszRemoteName );
+
+ if ( status == NO_ERROR )
+ {
+ if ( IsEnumVolumes )
+ {
+ LPWSTR pszServerName = pszRemoteName;
+
+ // BUGBUG - The following 10 lines are a hack to
+ // allow the provider to browse past the CN=<server>
+ // object in an NDS tree.
+ if ( slashCount == 3 && isNdsUnc == TRUE )
+ {
+ pszServerName = (LPWSTR)
+ NwpGetUncObjectName( pszRemoteName );
+
+ if ( pszServerName == NULL )
+ pszServerName = pszRemoteName;
+ }
+ else if ( dwUsage & RESOURCEUSAGE_ATTACHED )
+ {
+#ifndef NT1057
+ // This is a bindery server.
+ // Return WN_NOT_AUTHENTICATED if
+ // we are not already attached so
+ // that clients ( explorer ) will
+ // do NPAddConnection3 to make
+ // a connection to the server.
+ BOOL fAttached;
+ BOOL fAuthenticated;
+
+ status = NwIsServerOrTreeAttached(
+ pszServerName + 2,
+ &fAttached,
+ &fAuthenticated );
+
+ if ( status != NO_ERROR )
+ break;
+
+ if ( !fAttached || !fAuthenticated)
+ {
+ // See if the server belongs to
+ // our provider.
+ status = NwrOpenEnumVolumes(
+ NULL,
+ pszServerName,
+ (LPNWWKSTA_CONTEXT_HANDLE) lphEnum );
+
+ if ( status == NO_ERROR )
+ {
+ // The server belongs to us.
+ // Close the handle and
+ // return not attached if
+ // callee passed in dwUsage
+ // flag:
+ // RESOURCEUSAGE_ATTACHED.
+ // Note: handle will be null
+ // after return from
+ // NwrCloseEnum
+
+ NwrCloseEnum( (LPNWWKSTA_CONTEXT_HANDLE) lphEnum );
+
+ status = WN_NOT_AUTHENTICATED;
+ }
+ else
+ {
+ // else the server does not
+ // belong to us.
+ status = WN_BAD_NETNAME;
+ }
+ break;
+ }
+#endif
+ } // else, this is a bindery server and
+ // client does not care whether we
+ // are bindery authenticated.
+
+ if ( ( dwType == RESOURCETYPE_ANY ) ||
+ ( ( dwType & RESOURCETYPE_DISK ) &&
+ ( dwType & RESOURCETYPE_PRINT ) ) )
+ {
+ status = NwrOpenEnumVolumesQueues(
+ NULL,
+ pszServerName,
+ (LPNWWKSTA_CONTEXT_HANDLE) lphEnum );
+ }
+ else if ( dwType & RESOURCETYPE_DISK )
+ {
+ status = NwrOpenEnumVolumes(
+ NULL,
+ pszServerName,
+ (LPNWWKSTA_CONTEXT_HANDLE) lphEnum );
+ }
+ else if ( dwType & RESOURCETYPE_PRINT )
+ {
+ status = NwrOpenEnumQueues(
+ NULL,
+ pszServerName,
+ (LPNWWKSTA_CONTEXT_HANDLE) lphEnum );
+ }
+ }
+ else
+ {
+ LPWSTR CachedUserName = NULL ;
+ LPWSTR CachedPassword = NULL ;
+
+#ifdef NT1057 // Make OpenEnum not interactive on SUR
+ (void) NwpRetrieveCachedCredentials( pszRemoteName,
+ &CachedUserName,
+ &CachedPassword );
+
+#endif
+ status = NwrOpenEnumDirectories(
+ NULL,
+ pszRemoteName,
+ CachedUserName,
+ CachedPassword,
+ (LPNWWKSTA_CONTEXT_HANDLE) lphEnum );
+
+#ifndef NT1057 // Make OpenEnum not interactive on SUR
+ if ( (status == ERROR_INVALID_PASSWORD)
+ || (status == ERROR_NO_SUCH_USER )
+ )
+ {
+ status = WN_NOT_AUTHENTICATED;
+ break;
+ }
+
+#else
+ if ( CachedUserName )
+ {
+ (void) LocalFree( (HLOCAL) CachedUserName );
+ }
+
+ if ( CachedPassword )
+ {
+ RtlZeroMemory( CachedPassword,
+ wcslen(CachedPassword) *
+ sizeof( WCHAR ) );
+
+ (void) LocalFree( ( HLOCAL ) CachedPassword );
+ }
+
+ if ( ( status == ERROR_INVALID_PASSWORD ) ||
+ ( status == ERROR_NO_SUCH_USER ) )
+ {
+ LPWSTR UserName;
+ LPWSTR Password;
+ LPWSTR TmpPtr;
+
+ //
+ // Put up dialog to get username
+ // and password.
+ //
+ status = NwpGetUserCredential( NULL,
+ tempStrPtr,
+ status,
+ NULL,
+ &UserName,
+ &Password);
+
+ if ( status == NO_ERROR )
+ {
+ status = NwrOpenEnumDirectories(
+ NULL,
+ pszRemoteName,
+ UserName,
+ Password,
+ (LPNWWKSTA_CONTEXT_HANDLE) lphEnum );
+
+ if ( status == NO_ERROR )
+ {
+ status = NwpCacheCredentials(
+ pszRemoteName,
+ UserName,
+ Password ) ;
+ }
+
+ (void) LocalFree( UserName );
+
+ //
+ // Clear the password
+ //
+ TmpPtr = Password;
+ while ( *TmpPtr != 0 )
+ *TmpPtr++ = 0;
+
+ (void) LocalFree( Password );
+ }
+ else if ( status == ERROR_WINDOW_NOT_DIALOG )
+ {
+ //
+ // Caller is not a GUI app.
+ //
+ status = ERROR_INVALID_PASSWORD;
+ }
+ else if ( status == WN_CANCEL )
+ {
+ //
+ // Cancel was pressed but we still
+ // have to return success or MPR
+ // will popup the error. Return
+ // a bogus enum handle.
+ //
+ *lphEnum = (HANDLE) 0xFFFFFFFF;
+ status = NO_ERROR;
+ }
+ }
+#endif
+ }
+ }
+ else
+ {
+ status = WN_BAD_NETNAME;
+ }
+ }
+ }
+ else
+ {
+ status = WN_BAD_VALUE;
+ }
+
+ if ( pszRemoteName != NULL )
+ LocalFree( (HLOCAL) pszRemoteName );
+ }
+
+ break;
+
+ default:
+ KdPrint(("NWPROVIDER: Invalid dwScope %lu\n", dwScope));
+ status = WN_BAD_VALUE;
+ } // end switch
+ }
+ else
+ {
+ status = WN_BAD_VALUE;
+ }
+ }
+ RpcExcept( 1 )
+ {
+ status = NwpMapRpcError(RpcExceptionCode());
+ }
+ RpcEndExcept
+
+ if ( status == ERROR_FILE_NOT_FOUND )
+ status = WN_BAD_NETNAME;
+
+ if ( status != NO_ERROR )
+ {
+ SetLastError( status );
+ }
+
+ return status;
+}
+
+
+DWORD
+APIENTRY
+NPEnumResource(
+ HANDLE hEnum,
+ LPDWORD lpcCount,
+ LPVOID lpBuffer,
+ LPDWORD lpBufferSize
+ )
+/*++
+
+Routine Description:
+
+ This function returns a lists of objects within the container
+ specified by the enumeration context handle.
+
+Arguments:
+
+ hEnum - Supplies the resumable enumeration context handle.
+
+ NOTE: If this value is 0xFFFFFFFF, it is not a context
+ handle and this routine is required to return
+ WN_NO_MORE_ENTRIES. This hack is to handle the
+ case where the user cancelled out of the network
+ credential dialog on NwrOpenEnumDirectories and we
+ cannot return an error there or we generate an error
+ popup.
+
+ lpcCount - On input, supplies the number of entries to get.
+ On output, if NO_ERROR is returned, receives the number
+ of entries NETRESOURCE returned in lpBuffer.
+
+ lpBuffer - Receives an array of NETRESOURCE entries, each
+ entry describes an object within the container.
+
+ lpBufferSize - On input, supplies the size of lpBuffer in
+ bytes. On output, if WN_MORE_DATA is returned, receives
+ the number of bytes needed in the buffer to get the
+ next entry.
+
+Return Value:
+
+
+ NO_ERROR - Successfully returned at least one entry.
+
+ WN_NO_MORE_ENTRIES - Reached the end of enumeration and nothing
+ is returned.
+
+ WN_MORE_DATA - lpBuffer is too small to even get one entry.
+
+ WN_BAD_HANDLE - The enumeration handle is invalid.
+
+ Other network errors.
+
+--*/
+{
+ DWORD status = NO_ERROR;
+ DWORD BytesNeeded = 0;
+ DWORD EntriesRead = 0;
+
+#if DBG
+ IF_DEBUG(ENUM) {
+ KdPrint(("\nNWPROVAU: NPEnumResource\n"));
+ }
+#endif
+
+ RpcTryExcept {
+
+ if (hEnum == (HANDLE) 0xFFFFFFFF) {
+ status = WN_NO_MORE_ENTRIES;
+ goto EndOfTry;
+ }
+
+ status = NwrEnum(
+ (NWWKSTA_CONTEXT_HANDLE) hEnum,
+ *lpcCount,
+ (LPBYTE) lpBuffer,
+ *lpBufferSize,
+ &BytesNeeded,
+ &EntriesRead
+ );
+
+ if (status == WN_MORE_DATA) {
+
+ //
+ // Output buffer too small to fit a single entry.
+ //
+ *lpBufferSize = BytesNeeded;
+ }
+ else if (status == NO_ERROR) {
+ *lpcCount = EntriesRead;
+ }
+
+EndOfTry: ;
+
+ }
+ RpcExcept(1) {
+ status = NwpMapRpcError(RpcExceptionCode());
+ }
+ RpcEndExcept
+
+ if (status != NO_ERROR && status != WN_NO_MORE_ENTRIES) {
+ SetLastError(status);
+ }
+ else
+ {
+
+ //
+ // Convert offsets of strings to pointers
+ //
+ if (EntriesRead > 0) {
+
+ DWORD i;
+ LPNETRESOURCEW NetR;
+
+
+ NetR = lpBuffer;
+
+ for (i = 0; i < EntriesRead; i++, NetR++) {
+
+ if (NetR->lpLocalName != NULL) {
+ NetR->lpLocalName = (LPWSTR) ((DWORD) lpBuffer +
+ (DWORD) NetR->lpLocalName);
+ }
+
+ NetR->lpRemoteName = (LPWSTR) ((DWORD) lpBuffer +
+ (DWORD) NetR->lpRemoteName);
+
+ if (NetR->lpComment != NULL) {
+ NetR->lpComment = (LPWSTR) ((DWORD) lpBuffer +
+ (DWORD) NetR->lpComment);
+ }
+
+ if (NetR->lpProvider != NULL) {
+ NetR->lpProvider = (LPWSTR) ((DWORD) lpBuffer +
+ (DWORD) NetR->lpProvider);
+ }
+ }
+ }
+ }
+
+ return status;
+}
+
+
+DWORD
+APIENTRY
+NPGetResourceInformation(
+ LPNETRESOURCEW lpNetResource,
+ LPVOID lpBuffer,
+ LPDWORD cbBuffer,
+ LPWSTR * lplpSystem
+ )
+/*++
+
+Routine Description:
+
+ This function returns an object which details information
+ about a specified network resource.
+
+Arguments:
+
+ lpNetResource - This specifies the network resource for which the
+ information is required. The lpRemoteName field of the NETRESOURCE
+ specifies the remote name of the network resource whose information
+ is required. If the calling program knows the values for the
+ lpProvider and dwType fields, then it should fill them in, otherwise,
+ it should set them to NULL. All other fields in the NETRESOURCE are
+ ignored and are not initialized.
+
+ lpBuffer - A pointer to the buffer to receive the result, which is
+ returned as a single NETRESOURCE entry representing the parent
+ resource. The lpRemoteName, lpProvider, dwType, and dwUsage fields
+ are returned, all other fields being set to NULL. The remote name
+ returned should be in the same syntax as that returned from an
+ enumeration, so that the caller can do a case sensitive string
+ compare to determine whether an enumerated resource is this resource.
+ If the provider owns a parent of the network resource, (in other
+ words is known to be the correct network to respond to this request),
+ then lpProvider should be filled in with a non-null entry. If it is
+ known that a network owns a parent of the resource, but that the
+ resource itself is not valid, then lpProvider is returned as a
+ non-null value together with a return status of WN_BAD_VALUE. dwScope
+ is returned as RESOURCE_CONTEXT if the network resource is part of
+ the user's network context, otherwise it is returned as zero.
+
+ cbBuffer - This specifies the size in bytes of the buffer passed to the
+ function call. If the result is WN_MORE_DATA, this will contain the
+ buffer size required (in bytes) to hold the NETRESOURCE information.
+
+ lplpSystem - Returned pointer to a string in the buffer pointed to by
+ lpBuffer that specifies the part of the resource that is accessed
+ through resource type specific system APIs rather than WNet APIs.
+ For example, if the input remote resource name was
+ "\\server\share\dir", then lpRemoteName is returned pointing to
+ "\\server\share" and lplpSystem points to "\dir", both strings
+ being stored in the buffer pointed to by lpBuffer.
+
+Return Value:
+
+
+ WN_SUCCESS - If the call is successful.
+
+ WN_MORE_DATA - If input buffer is too small.
+
+ WN_BAD_VALUE - Invalid dwScope or dwUsage or dwType, or bad combination
+ of parameters is specified (e.g. lpRemoteName does not correspond
+ to dwType).
+
+ WN_BAD_NETNAME - The resource is not recognized by this provider.
+
+--*/
+{
+ DWORD status;
+ LPWSTR pszRemoteName = NULL;
+ DWORD BytesNeeded = 0;
+ DWORD SystemOffset = 0;
+
+ *lplpSystem = NULL;
+
+ status = NwpMapNameToUNC( lpNetResource->lpRemoteName, &pszRemoteName );
+
+ if (status != NO_ERROR)
+ {
+ SetLastError(status);
+ return status;
+ }
+
+#if DBG
+ IF_DEBUG(CONNECT)
+ {
+ KdPrint(("\nNWPROVAU: NPGetResourceInformation %ws\n", pszRemoteName));
+ }
+#endif
+
+ RpcTryExcept
+ {
+ if (lpNetResource->dwType != RESOURCETYPE_ANY &&
+ lpNetResource->dwType != RESOURCETYPE_DISK &&
+ lpNetResource->dwType != RESOURCETYPE_PRINT)
+ {
+ status = WN_BAD_VALUE;
+ }
+ else
+ {
+ status = NwrGetResourceInformation(
+ NULL,
+ pszRemoteName,
+ lpNetResource->dwType,
+ (LPBYTE) lpBuffer,
+ *cbBuffer,
+ &BytesNeeded,
+ &SystemOffset
+ );
+
+ if (status == WN_MORE_DATA)
+ {
+ //
+ // Output buffer too small.
+ //
+ *cbBuffer = BytesNeeded;
+ }
+ }
+ }
+ RpcExcept(1)
+ {
+ status = NwpMapRpcError(RpcExceptionCode());
+ }
+ RpcEndExcept
+ if ( pszRemoteName )
+ LocalFree( (HLOCAL) pszRemoteName );
+
+ if (status != NO_ERROR)
+ {
+ SetLastError(status);
+ }
+ else
+ {
+ //
+ // Convert offsets of strings to pointers
+ //
+ DWORD i;
+ LPNETRESOURCEW NetR = lpBuffer;
+
+ if (NetR->lpLocalName != NULL)
+ {
+ NetR->lpLocalName = (LPWSTR) ((DWORD) lpBuffer +
+ (DWORD) NetR->lpLocalName);
+ }
+
+ NetR->lpRemoteName = (LPWSTR) ((DWORD) lpBuffer +
+ (DWORD) NetR->lpRemoteName);
+
+ if (NetR->lpComment != NULL)
+ {
+ NetR->lpComment = (LPWSTR) ((DWORD) lpBuffer +
+ (DWORD) NetR->lpComment);
+ }
+
+ if (NetR->lpProvider != NULL)
+ {
+ NetR->lpProvider = (LPWSTR) ((DWORD) lpBuffer +
+ (DWORD) NetR->lpProvider);
+ }
+
+ if (SystemOffset != 0)
+ {
+ *lplpSystem = (LPWSTR) ((DWORD) lpBuffer + SystemOffset);
+ }
+ }
+
+ return status;
+}
+
+
+
+DWORD
+APIENTRY
+NPGetResourceParent(
+ LPNETRESOURCEW lpNetResource,
+ LPVOID lpBuffer,
+ LPDWORD cbBuffer
+ )
+/*++
+
+Routine Description:
+
+ This function returns an object which details information
+ about the parent of a specified network resource.
+
+Arguments:
+
+ lpNetResource - This specifies the network resource for which the
+ parent name is required. The NETRESOURCE could have been obtained via
+ previous NPEnumResource, or constructed by the caller. The lpRemoteName
+ field of the NETRESOURCE specifies the remote name of the network
+ resouce whose parent name is required. If the calling program knows
+ the values for the lpProvider and dwType fields, then it can fill
+ them in, otherwise, they are set to NULL. If the lpProvider field is
+ not NULL, then the network provider DLL can assume that the resource
+ is owned by its network, but if it is NULL, then it must assume
+ that the resource could be for some other network and do whatever
+ checking is neccessary to ensure that the result returned is accurate.
+ For example, if being asked for the parent of a server, and the server
+ is not part of a workgroup, the the network provider DLL should check
+ to ensure that the server is part of its network and, if so, return
+ its provider name. All other fields in the NETRESOURCE are ignored and
+ are not initialized.
+
+ lpBuffer - A pointer to the buffer to receive the result, which is
+ returned as a single NETRESOURCE entry representing the parent
+ resource. The lpRemoteName, lpProvider, dwType, and dwUsage fields
+ are returned, all other fields being set to NULL. lpProvider should
+ be set to NULL if the provider has only done a syntactic check (i.e.
+ does not know that the resource is specific to its network). If the
+ provider owns a parent of the network resource, (in other words is
+ known to be the correct network to respond to this request), then
+ lpProvider should be filled in with a non-null entry, even if the
+ return is WN_BAD_VALUE. The remote name returned should be in the
+ same syntax as that returned from an enumeration, so that the caller
+ can do a case sensitive string compare to determine whether an
+ enumerated resource is this resource. If a resource has no browse
+ parent on the network, the lpRemoteName is returned as NULL. The
+ RESOURCEUSAGE_CONNECTABLE value in the dwUsage field does not
+ indicate that the resource can currently be connected to, but that
+ the resource is connectable when it is available on the network.
+
+ cbBuffer - This specifies the size in bytes of the buffer passed to the
+ function call. If the result is WN_MORE_DATA, this will contain the
+ buffer size required (in bytes) to hold the NETRESOURCE information.
+
+Return Value:
+
+ WN_SUCCESS - If the call is successful.
+
+ WN_MORE_DATA - If input buffer is too small.
+
+ WN_BAD_VALUE - Invalid dwScope or dwUsage or dwType, or bad combination
+ of parameters is specified (e.g. lpRemoteName does not correspond
+ to dwType).
+
+--*/
+{
+ DWORD status;
+ LPWSTR pszRemoteName = NULL;
+ DWORD BytesNeeded = 0;
+
+ status = NwpMapNameToUNC( lpNetResource->lpRemoteName, &pszRemoteName );
+
+ if (status != NO_ERROR)
+ {
+ SetLastError(status);
+ return status;
+ }
+
+#if DBG
+ IF_DEBUG(CONNECT)
+ {
+ KdPrint(("\nNWPROVAU: NPGetResourceParent %ws\n", pszRemoteName));
+ }
+#endif
+
+ RpcTryExcept
+ {
+ if (lpNetResource->dwType != RESOURCETYPE_ANY &&
+ lpNetResource->dwType != RESOURCETYPE_DISK &&
+ lpNetResource->dwType != RESOURCETYPE_PRINT)
+ {
+ status = WN_BAD_VALUE;
+ }
+ else
+ {
+ status = NwrGetResourceParent(
+ NULL,
+ pszRemoteName,
+ lpNetResource->dwType,
+ (LPBYTE) lpBuffer,
+ *cbBuffer,
+ &BytesNeeded
+ );
+
+ if (status == WN_MORE_DATA)
+ {
+ //
+ // Output buffer too small.
+ //
+ *cbBuffer = BytesNeeded;
+ }
+ }
+ }
+ RpcExcept(1)
+ {
+ status = NwpMapRpcError(RpcExceptionCode());
+ }
+ RpcEndExcept
+ if ( pszRemoteName )
+ LocalFree( (HLOCAL) pszRemoteName );
+
+
+ if (status != NO_ERROR)
+ {
+ SetLastError(status);
+ }
+ else
+ {
+ //
+ // Convert offsets of strings to pointers
+ //
+ DWORD i;
+ LPNETRESOURCEW NetR = lpBuffer;
+
+ if (NetR->lpLocalName != NULL)
+ {
+ NetR->lpLocalName = (LPWSTR) ((DWORD) lpBuffer +
+ (DWORD) NetR->lpLocalName);
+ }
+
+ NetR->lpRemoteName = (LPWSTR) ((DWORD) lpBuffer +
+ (DWORD) NetR->lpRemoteName);
+
+ if (NetR->lpComment != NULL)
+ {
+ NetR->lpComment = (LPWSTR) ((DWORD) lpBuffer +
+ (DWORD) NetR->lpComment);
+ }
+
+ if (NetR->lpProvider != NULL)
+ {
+ NetR->lpProvider = (LPWSTR) ((DWORD) lpBuffer +
+ (DWORD) NetR->lpProvider);
+ }
+ }
+
+ return status;
+}
+
+
+
+DWORD
+APIENTRY
+NwEnumConnections(
+ HANDLE hEnum,
+ LPDWORD lpcCount,
+ LPVOID lpBuffer,
+ LPDWORD lpBufferSize,
+ BOOL fImplicitConnections
+ )
+/*++
+
+Routine Description:
+
+ This function returns a lists of connections.
+
+Arguments:
+
+ hEnum - Supplies the resumable enumeration context handle.
+
+ NOTE: If this value is 0xFFFFFFFF, it is not a context
+ handle and this routine is required to return
+ WN_NO_MORE_ENTRIES. This hack is to handle the
+ case where the user cancelled out of the network
+ credential dialog on NwrOpenEnumDirectories and we
+ cannot return an error there or we generate an error
+ popup.
+
+ lpcCount - On input, supplies the number of entries to get.
+ On output, if NO_ERROR is returned, receives the number
+ of entries NETRESOURCE returned in lpBuffer.
+
+ lpBuffer - Receives an array of NETRESOURCE entries, each
+ entry describes an object within the container.
+
+ lpBufferSize - On input, supplies the size of lpBuffer in
+ bytes. On output, if WN_MORE_DATA is returned, receives
+ the number of bytes needed in the buffer to get the
+ next entry.
+
+ fImplicitConnections - TRUE is we also want all implicit connections,
+ FALSE otherwise.
+
+Return Value:
+
+
+ NO_ERROR - Successfully returned at least one entry.
+
+ WN_NO_MORE_ENTRIES - Reached the end of enumeration and nothing
+ is returned.
+
+ WN_MORE_DATA - lpBuffer is too small to even get one entry.
+
+ WN_BAD_HANDLE - The enumeration handle is invalid.
+
+ Other network errors.
+
+--*/
+{
+ DWORD status = NO_ERROR;
+ DWORD BytesNeeded = 0;
+ DWORD EntriesRead = 0;
+
+#if DBG
+ IF_DEBUG(ENUM) {
+ KdPrint(("\nNWPROVAU: NPEnumResource\n"));
+ }
+#endif
+
+ RpcTryExcept {
+
+ if (hEnum == (HANDLE) 0xFFFFFFFF) {
+ status = WN_NO_MORE_ENTRIES;
+ goto EndOfTry;
+ }
+
+ status = NwrEnumConnections(
+ (NWWKSTA_CONTEXT_HANDLE) hEnum,
+ *lpcCount,
+ (LPBYTE) lpBuffer,
+ *lpBufferSize,
+ &BytesNeeded,
+ &EntriesRead,
+ fImplicitConnections
+ );
+
+ if (status == WN_MORE_DATA) {
+
+ //
+ // Output buffer too small to fit a single entry.
+ //
+ *lpBufferSize = BytesNeeded;
+ }
+ else if (status == NO_ERROR) {
+ *lpcCount = EntriesRead;
+ }
+
+EndOfTry: ;
+
+ }
+ RpcExcept(1) {
+ status = NwpMapRpcError(RpcExceptionCode());
+ }
+ RpcEndExcept
+
+ if (status != NO_ERROR && status != WN_NO_MORE_ENTRIES) {
+ SetLastError(status);
+ }
+
+ //
+ // Convert offsets of strings to pointers
+ //
+ if (EntriesRead > 0) {
+
+ DWORD i;
+ LPNETRESOURCEW NetR;
+
+
+ NetR = lpBuffer;
+
+ for (i = 0; i < EntriesRead; i++, NetR++) {
+
+ if (NetR->lpLocalName != NULL) {
+ NetR->lpLocalName = (LPWSTR) ((DWORD) lpBuffer +
+ (DWORD) NetR->lpLocalName);
+ }
+
+ NetR->lpRemoteName = (LPWSTR) ((DWORD) lpBuffer +
+ (DWORD) NetR->lpRemoteName);
+
+ if (NetR->lpComment != NULL) {
+ NetR->lpComment = (LPWSTR) ((DWORD) lpBuffer +
+ (DWORD) NetR->lpComment);
+ }
+
+ if (NetR->lpProvider != NULL) {
+ NetR->lpProvider = (LPWSTR) ((DWORD) lpBuffer +
+ (DWORD) NetR->lpProvider);
+ }
+ }
+ }
+
+ return status;
+}
+
+
+DWORD
+APIENTRY
+NPCloseEnum(
+ HANDLE hEnum
+ )
+/*++
+
+Routine Description:
+
+ This function closes the enumeration context handle.
+
+Arguments:
+
+ hEnum - Supplies the enumeration context handle.
+
+ NOTE: If this value is 0xFFFFFFFF, it is not a context
+ handle. Just return success.
+
+Return Value:
+
+ NO_ERROR - Successfully returned at least one entry.
+
+ WN_BAD_HANDLE - The enumeration handle is invalid.
+
+--*/
+{
+ DWORD status = NO_ERROR;
+
+#if DBG
+ IF_DEBUG(ENUM) {
+ KdPrint(("\nNWPROVAU: NPCloseEnum\n"));
+ }
+#endif
+
+ RpcTryExcept
+ {
+ if (hEnum == (HANDLE) 0xFFFFFFFF) {
+ status = NO_ERROR;
+ }
+ else {
+ status = NwrCloseEnum(
+ (LPNWWKSTA_CONTEXT_HANDLE) &hEnum
+ );
+ }
+ }
+ RpcExcept(1) {
+ status = NwpMapRpcError(RpcExceptionCode());
+ }
+ RpcEndExcept
+
+ if (status != NO_ERROR) {
+ SetLastError(status);
+ }
+ return status;
+}
+
+
+DWORD
+APIENTRY
+NPFormatNetworkName(
+ LPWSTR lpRemoteName,
+ LPWSTR lpFormattedName,
+ LPDWORD lpnLength,
+ DWORD dwFlags,
+ DWORD dwAveCharPerLine
+ )
+/*++
+
+Routine Description:
+
+ This function takes a fully-qualified UNC name and formats it
+ into a shorter form for display. Only the name of the object
+ within the container is returned for display.
+
+ We only support formatting of the remote resource name to the
+ abbreviated form for display during enumeration where the container
+ name is displayed prior to the object within it.
+
+Arguments:
+
+ lpRemoteName - Supplies the fully-qualified UNC name.
+
+ lpFormatedName - Output buffer to receive the formatted name.
+
+ lpnLength - On input, supplies the length of the lpFormattedName
+ buffer in characters. On output, if WN_MORE_DATA is returned,
+ receives the length in number of characters required of the
+ output buffer to hold the formatted name.
+
+ dwFlags - Supplies a bitwise set of flags indicating the type
+ of formatting required on lpRemoteName.
+
+ dwAveCharPerLine - Ignored.
+
+Return Value:
+
+ NO_ERROR - Successfully returned at least one entry.
+
+ WN_MORE_DATA - lpFormattedName buffer is too small.
+
+ WN_BAD_VALUE - lpRemoteName is NULL.
+
+ ERROR_NOT_SUPPORTED - dwFlags that does not contain the
+ WNFMT_INENUM bit.
+
+--*/
+{
+ DWORD status = NO_ERROR;
+
+ LPWSTR NextBackSlash;
+ LPWSTR Source;
+ DWORD SourceLen;
+
+#if DBG
+ IF_DEBUG(OTHER)
+ KdPrint(("\nNWPROVAU: NPFormatNetworkName\n"));
+#endif
+
+ if (lpRemoteName == NULL)
+ {
+ status = WN_BAD_VALUE;
+ goto CleanExit;
+ }
+
+ if (dwFlags & WNFMT_INENUM)
+ {
+ BYTE i;
+ WORD length = wcslen( lpRemoteName );
+ WORD slashCount = 0;
+ WORD dotCount = 0;
+ WORD Start = 0;
+ WORD End = length;
+ BOOL isNdsUnc = FALSE;
+
+ for ( i = 0; i < length; i++ )
+ {
+ if ( lpRemoteName[i] == L'\\' )
+ {
+ slashCount++;
+ if ( i + 1 < length )
+ {
+ Start = i + 1;
+ }
+ }
+
+ if ( ( lpRemoteName[i] == L'.' ) ||
+ ( lpRemoteName[i] == L'=' ) )
+ isNdsUnc = TRUE;
+
+ if ( dotCount < 1 && isNdsUnc && lpRemoteName[i] == L'.' )
+ {
+ End = i - 1;
+ dotCount++;
+ }
+ }
+
+ if ( i > length )
+ End = length - 1;
+
+ if ( slashCount > 3 || ( isNdsUnc != TRUE && slashCount != 3 && dotCount == 0 ) )
+ End = i - 1;
+
+ Source = &lpRemoteName[Start];
+ SourceLen = End - Start + 1;
+
+ if ( SourceLen + 1 > *lpnLength )
+ {
+ *lpnLength = SourceLen + 1;
+ status = WN_MORE_DATA;
+ }
+ else
+ {
+ wcsncpy( lpFormattedName, Source, SourceLen );
+ lpFormattedName[SourceLen] = 0x00000000;
+ status = NO_ERROR;
+ }
+ }
+ else if ( dwFlags & WNFMT_MULTILINE )
+ {
+
+ DWORD i, j, k = 0;
+ DWORD nLastBackSlash = 0;
+ DWORD BytesNeeded = ( wcslen( lpRemoteName ) + 1 +
+ 2 * wcslen( lpRemoteName ) / dwAveCharPerLine
+ ) * sizeof( WCHAR);
+
+ if ( *lpnLength < (BytesNeeded/sizeof(WCHAR)) )
+ {
+ *lpnLength = BytesNeeded/sizeof(WCHAR);
+ status = WN_MORE_DATA;
+ goto CleanExit;
+ }
+
+ for ( i = 0, j = 0; lpRemoteName[i] != 0; i++, j++ )
+ {
+ if ( lpRemoteName[i] == L'\\' )
+ nLastBackSlash = i;
+
+ if ( k == dwAveCharPerLine )
+ {
+ if ( lpRemoteName[i] != L'\\' )
+ {
+ DWORD m, n;
+ for ( n = nLastBackSlash, m = ++j ; n <= i ; n++, m-- )
+ {
+ lpFormattedName[m] = lpFormattedName[m-1];
+ }
+ lpFormattedName[m] = L'\n';
+ k = i - nLastBackSlash - 1;
+ }
+ else
+ {
+ lpFormattedName[j++] = L'\n';
+ k = 0;
+ }
+ }
+
+ lpFormattedName[j] = lpRemoteName[i];
+ k++;
+ }
+
+ lpFormattedName[j] = 0;
+
+ }
+ else if ( dwFlags & WNFMT_ABBREVIATED )
+ {
+ //
+ // we dont support abbreviated form for now because we look bad
+ // in comdlg (fileopen) if we do.
+ //
+
+ DWORD nLength;
+ nLength = wcslen( lpRemoteName ) + 1 ;
+ if (nLength > *lpnLength)
+ {
+ *lpnLength = nLength;
+ status = WN_MORE_DATA;
+ goto CleanExit;
+ }
+ else
+ {
+ wcscpy( lpFormattedName, lpRemoteName );
+ }
+
+#if 0
+ DWORD i, j, k;
+ DWORD BytesNeeded = dwAveCharPerLine * sizeof( WCHAR);
+ DWORD nLength;
+
+ if ( *lpnLength < BytesNeeded )
+ {
+ *lpnLength = BytesNeeded;
+ status = WN_MORE_DATA;
+ goto CleanExit;
+ }
+
+ nLength = wcslen( lpRemoteName );
+ if ( ( nLength + 1) <= dwAveCharPerLine )
+ {
+ wcscpy( lpFormattedName, lpRemoteName );
+ }
+ else
+ {
+ lpFormattedName[0] = lpRemoteName[0];
+ lpFormattedName[1] = lpRemoteName[1];
+
+ for ( i = 2; lpRemoteName[i] != L'\\'; i++ )
+ lpFormattedName[i] = lpRemoteName[i];
+
+ for ( j = dwAveCharPerLine-1, k = nLength; j >= (i+3); j--, k-- )
+ {
+ lpFormattedName[j] = lpRemoteName[k];
+ if ( lpRemoteName[k] == L'\\' )
+ {
+ j--;
+ break;
+ }
+ }
+
+ lpFormattedName[j] = lpFormattedName[j-1] = lpFormattedName[j-2] = L'.';
+
+ for ( k = i; k < (j-2); k++ )
+ lpFormattedName[k] = lpRemoteName[k];
+
+ }
+
+#endif
+
+ }
+ else // some unknown flags
+ {
+ status = ERROR_NOT_SUPPORTED;
+ }
+
+CleanExit:
+
+ if (status != NO_ERROR)
+ SetLastError(status);
+
+ return status;
+}
+
+
+STATIC
+BOOL
+NwpWorkstationStarted(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ This function queries the service controller to see if the
+ NetWare workstation service has started. If in doubt, it returns
+ FALSE.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Returns TRUE if the NetWare workstation service has started,
+ FALSE otherwise.
+
+--*/
+{
+ SC_HANDLE ScManager;
+ SC_HANDLE Service;
+ SERVICE_STATUS ServiceStatus;
+ BOOL IsStarted = FALSE;
+
+ ScManager = OpenSCManagerW(
+ NULL,
+ NULL,
+ SC_MANAGER_CONNECT
+ );
+
+ if (ScManager == NULL) {
+ return FALSE;
+ }
+
+ Service = OpenServiceW(
+ ScManager,
+ NW_WORKSTATION_SERVICE,
+ SERVICE_QUERY_STATUS
+ );
+
+ if (Service == NULL) {
+ CloseServiceHandle(ScManager);
+ return FALSE;
+ }
+
+ if (! QueryServiceStatus(Service, &ServiceStatus)) {
+ CloseServiceHandle(ScManager);
+ CloseServiceHandle(Service);
+ return FALSE;
+ }
+
+
+ if ( (ServiceStatus.dwCurrentState == SERVICE_RUNNING) ||
+ (ServiceStatus.dwCurrentState == SERVICE_CONTINUE_PENDING) ||
+ (ServiceStatus.dwCurrentState == SERVICE_PAUSE_PENDING) ||
+ (ServiceStatus.dwCurrentState == SERVICE_PAUSED) ) {
+
+ IsStarted = TRUE;
+ }
+
+ CloseServiceHandle(ScManager);
+ CloseServiceHandle(Service);
+
+ return IsStarted;
+}
+
+
+
+DWORD
+NwpMapNameToUNC(
+ IN LPWSTR pszName,
+ OUT LPWSTR *ppszUNC
+ )
+/*++
+
+Routine Description:
+
+ This routine validates the given name as a netwarepath or UNC path.
+ If it is a netware path, this routine will convert the
+ Netware path name to UNC name.
+
+Arguments:
+
+ pszName - Supplies the netware name or UNC name
+ ppszUNC - Points to the converted UNC name
+
+Return Value:
+
+ NO_ERROR or the error that occurred.
+
+--*/
+{
+ DWORD err = NO_ERROR;
+
+ LPWSTR pszSrc = pszName;
+ LPWSTR pszDest;
+
+ BOOL fSlash = FALSE;
+ BOOL fColon = FALSE;
+ DWORD nServerLen = 0;
+ DWORD nVolLen = 0;
+ BOOL fFirstToken = TRUE;
+
+ *ppszUNC = NULL;
+
+#if DBG
+ IF_DEBUG(CONNECT)
+ KdPrint(("NwpMapNameToUNC: Source = %ws\n", pszName ));
+#endif
+
+
+ //
+ // Check if the given name is a valid UNC name
+ //
+ err = NwLibCanonRemoteName( NULL, // "\\Server" is valid UNC path
+ pszName,
+ ppszUNC,
+ NULL );
+
+ //
+ // The given name is a valid UNC name, so return success!
+ //
+ if ( err == NO_ERROR )
+ return err;
+
+ //
+ // The name cannot be NULL or empty string
+ //
+ if ( pszName == NULL || *pszName == 0)
+ return WN_BAD_NETNAME;
+
+ //
+ // Allocate the buffer to store the mapped UNC name
+ // We allocate 3 extra characters, two for the backslashes in front
+ // and one for the ease of parsing below.
+ //
+ if ((*ppszUNC = (LPVOID) LocalAlloc(
+ LMEM_ZEROINIT,
+ (wcslen( pszName) + 4) * sizeof( WCHAR)
+ )) == NULL )
+ {
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ wcscpy( *ppszUNC, L"\\\\" );
+ pszDest = *ppszUNC + 2; // Skip past two backslashes
+
+ //
+ // Parse the given string and put the converted string into *ppszUNC
+ // In the converted string, we will substitute 0 for all slashes
+ // for the time being.
+ //
+ for ( ; *pszSrc != 0; pszSrc++ )
+ {
+ if ( ( *pszSrc == L'/' )
+ || ( *pszSrc == L'\\' )
+ )
+ {
+ //
+ // Two consecutive backslashes are bad
+ //
+ if ( (*(pszSrc+1) == L'/') || (*(pszSrc+1) == L'\\'))
+ {
+ LocalFree( *ppszUNC );
+ *ppszUNC = NULL;
+ return WN_BAD_NETNAME;
+ }
+
+ if ( !fSlash )
+ fSlash = TRUE;
+
+ *pszDest++ = 0;
+ }
+ else if ( (*pszSrc == L':') && fSlash && !fColon )
+ {
+ fColon = TRUE;
+ if ( *(pszSrc+1) != 0 )
+ *pszDest++ = 0;
+
+ }
+ else
+ {
+ *pszDest++ = *pszSrc;
+ if (( fSlash ) && ( !fColon))
+ nVolLen++;
+ else if ( !fSlash )
+ nServerLen++;
+ }
+ }
+
+ //
+ // Note: *ppszUNC is already terminated with two '\0' because we initialized
+ // the whole buffer to zero.
+ //
+
+ if ( ( nServerLen == 0 )
+ || ( fSlash && nVolLen == 0 )
+ || ( fSlash && nVolLen != 0 && !fColon )
+ )
+ {
+ LocalFree( *ppszUNC );
+ *ppszUNC = NULL;
+ return WN_BAD_NETNAME;
+ }
+
+ //
+ // At this point, we know the name is a valid Netware syntax
+ // i.e. SERVER[/VOL:/dir]
+ // We now need to validate that all the characters used in the
+ // servername, volume, directory are valid characters
+ //
+
+ pszDest = *ppszUNC + 2; // Skip past the first two backslashes
+ while ( *pszDest != 0 )
+ {
+ DWORD nLen = wcslen( pszDest );
+
+ if ( ( fFirstToken && !IS_VALID_SERVER_TOKEN( pszDest, nLen ))
+ || ( !fFirstToken && !IS_VALID_TOKEN( pszDest, nLen ))
+ )
+ {
+ LocalFree( *ppszUNC );
+ *ppszUNC = NULL;
+ return WN_BAD_NETNAME;
+ }
+
+ fFirstToken = FALSE;
+ pszDest += nLen + 1;
+ }
+
+ //
+ // The netware name is valid! Convert 0 back to backslash in
+ // converted string.
+ //
+
+ pszDest = *ppszUNC + 2; // Skip past the first two backslashes
+ while ( *pszDest != 0 )
+ {
+ if ( (*(pszDest+1) == 0 ) && (*(pszDest+2) != 0 ) )
+ {
+ *(pszDest+1) = L'\\';
+ }
+ pszDest++;
+ }
+
+#if DBG
+ IF_DEBUG(CONNECT)
+ KdPrint(("NwpMapNameToUNC: Destination = %ws\n", *ppszUNC ));
+#endif
+ return NO_ERROR;
+}
+
+
+STATIC
+VOID
+NwpGetUncInfo(
+ IN LPWSTR lpstrUnc,
+ OUT WORD * slashCount,
+ OUT BOOL * isNdsUnc
+ )
+{
+ BYTE i;
+ WORD length = wcslen( lpstrUnc );
+
+ *isNdsUnc = FALSE;
+ *slashCount = 0;
+
+ for ( i = 0; i < length; i++ )
+ {
+ if ( ( lpstrUnc[i] == L'.' ) && ( *slashCount == 3 ) )
+ {
+ *isNdsUnc = TRUE;
+ }
+
+ if ( lpstrUnc[i] == L'\\' )
+ {
+ *slashCount += 1;
+ }
+ }
+}
+
+
+STATIC
+DWORD
+NwpGetUncObjectName(
+ IN LPWSTR ContainerName
+)
+{
+ WORD length = 2;
+ WORD totalLength = wcslen( ContainerName );
+
+ if ( totalLength < 2 )
+ return 0;
+
+ while ( length < totalLength )
+ {
+ if ( ContainerName[length] == L'.' )
+ ContainerName[length] = L'\0';
+
+ length++;
+ }
+
+ length = 2;
+
+ while ( length < totalLength && ContainerName[length] != L'\\' )
+ {
+ length++;
+ }
+
+ if ( ( ContainerName[length + 1] == L'C' ||
+ ContainerName[length + 1] == L'c' ) &&
+ ( ContainerName[length + 2] == L'N' ||
+ ContainerName[length + 2] == L'n' ) &&
+ ContainerName[length + 3] == L'=' )
+ {
+ ContainerName[length + 2] = L'\\';
+ ContainerName[length + 3] = L'\\';
+
+ return (DWORD) (ContainerName + length + 2);
+ }
+
+ ContainerName[length - 1] = L'\\';
+
+ return (DWORD) (ContainerName + length - 1);
+}
+
+
+STATIC
+WORD
+NwpGetSlashCount(
+ IN LPWSTR lpstrUnc
+ )
+{
+ WORD count = 0;
+ BYTE i;
+ WORD length = wcslen( lpstrUnc );
+
+ for ( i = 0; i < length; i++ )
+ {
+ if ( lpstrUnc[i] == L'\\' )
+ {
+ count++;
+ }
+ }
+
+ return count;
+}
+
+
+DWORD
+NwpMapRpcError(
+ IN DWORD RpcError
+ )
+/*++
+
+Routine Description:
+
+ This routine maps the RPC error into a more meaningful windows
+ error for the caller.
+
+Arguments:
+
+ RpcError - Supplies the exception error raised by RPC
+
+Return Value:
+
+ Returns the mapped error.
+
+--*/
+{
+
+ switch (RpcError) {
+
+ case RPC_S_UNKNOWN_IF:
+ case RPC_S_SERVER_UNAVAILABLE:
+ return WN_NO_NETWORK;
+
+ case RPC_S_INVALID_BINDING:
+ case RPC_X_SS_IN_NULL_CONTEXT:
+ case RPC_X_SS_CONTEXT_DAMAGED:
+ case RPC_X_SS_HANDLES_MISMATCH:
+ case ERROR_INVALID_HANDLE:
+ return ERROR_INVALID_HANDLE;
+
+ case RPC_X_NULL_REF_POINTER:
+ return ERROR_INVALID_PARAMETER;
+
+ case EXCEPTION_ACCESS_VIOLATION:
+ return ERROR_INVALID_ADDRESS;
+
+ default:
+ return RpcError;
+ }
+}
+
+DWORD
+NwRegisterGatewayShare(
+ IN LPWSTR ShareName,
+ IN LPWSTR DriveName
+ )
+/*++
+
+Routine Description:
+
+ This routine remembers that a gateway share has been created so
+ that it can be cleanup up when NWCS is uninstalled.
+
+Arguments:
+
+ ShareName - name of share
+ DriveName - name of drive that is shared
+
+Return Status:
+
+ Win32 error of any failure.
+
+--*/
+{
+ return ( NwpRegisterGatewayShare(ShareName, DriveName) ) ;
+}
+
+DWORD
+NwCleanupGatewayShares(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ This routine cleans up all persistent share info and also tidies
+ up the registry for NWCS. Later is not needed in uninstall, but is
+ there so we have a single routine that cvompletely disables the
+ gateway.
+
+Arguments:
+
+ None.
+
+Return Status:
+
+ Win32 error for failed APIs.
+
+--*/
+{
+ return ( NwpCleanupGatewayShares() ) ;
+}
+
+DWORD
+NwClearGatewayShare(
+ IN LPWSTR ShareName
+ )
+/*++
+
+Routine Description:
+
+ This routine deletes a specific share from the remembered gateway
+ shares in the registry.
+
+Arguments:
+
+ ShareName - share value to delete
+
+Return Status:
+
+ Win32 status code.
+
+--*/
+{
+ return ( NwpClearGatewayShare( ShareName ) ) ;
+}