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.
 
 
 
 
 
 

6405 lines
217 KiB

/*++
Copyright (c) 1999 Microsoft Corporation
Module Name:
provider.c
Abstract:
This module contains WebDav's Network Provider code. It is the client-side
wrapper for APIs supported by the Dav Client service.
Author:
Rohan Kumar 01-Dec-1999
Revision History:
--*/
#include "pch.h"
#pragma hdrstop
#include <global.h>
#define SECURITY_WIN32
#include <security.h>
#include <wincred.h>
#include <wincred.h>
#include <npapi.h>
//
// Local Function Prototypes.
//
BOOL
DavWorkstationStarted(
VOID
);
DWORD
DavMapRpcErrorToProviderError(
IN DWORD RpcError
);
DWORD
DavBindTheRpcHandle(
handle_t *dav_binding_h
);
DAV_REMOTENAME_TYPE
DavParseRemoteName (
IN LPWSTR RemoteName,
OUT LPWSTR CanonName,
IN DWORD CanonNameSize,
OUT PULONG PathStart
);
BOOL
DavServerExists(
IN PWCHAR PathName,
OUT PWCHAR Server
);
BOOL
DavShareExists(
PWCHAR PathName
);
BOOL
DavConnectionExists(
PWCHAR ConnName
);
DWORD
DavDisplayTypeToUsage(
DWORD dwDisplayType
);
typedef
DWORD
(WINAPI
*PFN_CREDUI_PROMPTFORCREDENTIALS)(
PCREDUI_INFOW pUiInfo,
PCWSTR pszTargetName,
PCtxtHandle pContext,
DWORD dwAuthError,
PWSTR pszUserName,
ULONG ulUserNameMaxChars,
PWSTR pszPassword,
ULONG ulPasswordMaxChars,
PBOOL pfSave,
DWORD dwFlags
);
typedef
DWORD
(WINAPI
*PFN_CREDUI_CMDLINE_PROMPTFORCREDENTIALS)(
PCWSTR pszTargetName,
PCtxtHandle pContext,
DWORD dwAuthError,
PWSTR UserName,
ULONG ulUserMaxChars,
PWSTR pszPassword,
ULONG ulPasswordMaxChars,
PBOOL pfSave,
DWORD dwFlags
);
typedef
void
(WINAPI
*PFN_CREDUI_CONFIRMCREDENTIALS)(
PCWSTR pszTargetName,
BOOL bConfirm
);
HMODULE
DavInitCredUI(
PWCHAR RemoteName,
WCHAR ServerName[CRED_MAX_STRING_LENGTH + 1],
PFN_CREDUI_CONFIRMCREDENTIALS *pfnCredUIConfirmCredentials,
PFN_CREDUI_PROMPTFORCREDENTIALS *pfnCredUIPromptForCredentials,
PFN_CREDUI_CMDLINE_PROMPTFORCREDENTIALS *pfnCredUICmdlinePromptForCredentials
);
ULONG
DavCheckAndConvertHttpUrlToUncName(
IN PWCHAR RemoteName,
OUT PWCHAR *UncRemoteName,
OUT PBOOLEAN MemoryAllocated,
IN BOOLEAN AddDummyShare,
OUT PDAV_REMOTENAME_TYPE pRemoteType,
OUT PULONG pPathStart,
IN BOOLEAN bCanonicalize
);
ULONG
DavCheckResourceType(
IN DWORD dwType
);
ULONG
DavCheckLocalName(
IN PWCHAR LocalName
);
VOID
DavDisplayNetResource(
LPNETRESOURCE netRes,
LPWSTR dispMesg
);
VOID
DavDisplayEnumNode(
PDAV_ENUMNODE enumNode,
LPWSTR dispMesg
);
VOID
DavDebugBreakPoint(
VOID
);
DWORD
DavGetTheLockOwnerOfTheFile(
IN PWCHAR FileName,
OUT PWCHAR LockOwnerName,
IN OUT PULONG LockOwnerNameLengthInBytes
);
//
// Implementation of functions begins here.
//
DWORD
APIENTRY
NPGetCaps(
IN DWORD QueryVal
)
/*++
Routine Description:
This function returns the functionality supported by the DAV 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_DEBUG_PRINT(DEBUG_ENTRY, ("NPGetCaps: QueryVal = %d\n", QueryVal));
//
// Some of the flags are commented out, since they are not supported.
//
switch (QueryVal) {
case WNNC_SPEC_VERSION:
return WNNC_SPEC_VERSION51;
case WNNC_NET_TYPE:
return WNNC_NET_DAV;
case WNNC_DRIVER_VERSION:
return 0x00010000; // driver version 1.0
case WNNC_USER:
return WNNC_USR_GETUSER;
case WNNC_CONNECTION:
return ( WNNC_CON_ADDCONNECTION |
WNNC_CON_ADDCONNECTION3 |
//
// Not supported for now.
//
//WNNC_CON_GETPERFORMANCE |
//
// DEFERRED connections are not supported for now.
//
//WNNC_CON_DEFER |
WNNC_CON_GETCONNECTIONS |
WNNC_CON_CANCELCONNECTION );
case WNNC_ENUMERATION:
return ( WNNC_ENUM_GLOBAL |
WNNC_ENUM_LOCAL |
//
// We are not supporting this option since we have no concept
// of DOMAIN in DAV. Hence cannot show any thing in
// "network neighbourhood" view.
//
// WNNC_ENUM_CONTEXT |
WNNC_ENUM_SHAREABLE );
case WNNC_START:
if ( DavWorkstationStarted() ) {
return 1;
}
else {
return 0xffffffff; // don't know
}
case WNNC_DIALOG:
return ( WNNC_DLG_GETRESOURCEPARENT |
//
//This flag is Obselete and is not supported.
//
//WNNC_DLG_DEVICEMODE |
//
// Both of these Dialog options are not supported for now.
//
//WNNC_DLG_PROPERTYDIALOG |
//WNNC_DLG_SEARCHDIALOG |
WNNC_DLG_FORMATNETWORKNAME |
WNNC_DLG_GETRESOURCEINFORMATION );
case WNNC_ADMIN:
return 0;
//
// None of functions given below are supported.
//
//( WNNC_ADM_GETDIRECTORYTYPE |
//WNNC_ADM_DIRECTORYNOTIFY );
case WNNC_CONNECTION_FLAGS:
return ( WNNC_CF_DEFAULT |
//
// DEFERRED Connections are not supported for now.
//
//CONNECT_DEFERRED |
CONNECT_COMMANDLINE |
CONNECT_CMD_SAVECRED );
//
// The rest are not supported by the DAV provider.
//
default:
return 0;
}
}
DWORD
NPGetUser(
IN LPTSTR lpName,
OUT LPTSTR lpUserName,
IN OUT LPDWORD lpBufferSize
)
/*++
Routine Description:
This function determines the user name that created the connection.
Arguments:
lpName - Name of the local drive or the remote name that the user has made
a connection to. If NULL, return currently logged on user.
lpUserName - The buffer to be filled in with the requested user name.
lpBufferSize - Contains the length (in chars not bytes )of the lpUserName
buffer. If the length is insufficient, this place is used to
inform the user the actual length needed.
Return Value:
WN_SUCCESS - Successful. OR
The appropriate network error code.
--*/
{
DWORD NPStatus = WN_SUCCESS;
handle_t dav_binding_h;
BOOL getUser = FALSE, bindRpcHandle = FALSE;
DWORD NumOfChars = 0;
BOOLEAN didAllocate = FALSE, getLogonUserName = FALSE, doRpcCall = FALSE;
PWCHAR ConnectionName = NULL, LocalUserName = NULL;
ULONG LocalUserNameLengthInBytes = 0;
DWORD npStatus = ERROR_SUCCESS;
DAV_REMOTENAME_TYPE remNameType = DAV_REMOTENAME_TYPE_INVALID;
IF_DEBUG_PRINT(DEBUG_ENTRY, ("NPGetUser Entered.\n"));
//
// If the WebClient service is not running we bail out right away.
//
if ( !DavWorkstationStarted() ) {
IF_DEBUG_PRINT(DEBUG_ERRORS,
("ERROR: NPGetUser/DavWorkstationStarted. "
"Service NOT Running\n"));
NPStatus = WN_NOT_CONNECTED;
goto EXIT_THE_FUNCTION;
}
//
// Checking for invalid parameters.
//
if (lpBufferSize == NULL || (lpUserName == NULL && *lpBufferSize != 0) ) {
NPStatus = ERROR_INVALID_PARAMETER;
IF_DEBUG_PRINT(DEBUG_ERRORS,
("ERROR: NPGetUser. Invalid parameters. NPStatus = %08lx\n",
NPStatus));
goto EXIT_THE_FUNCTION;
}
//
// Check if the given connectin name (lpName) is L"" or NULL, in which case we
// returns user-id of the logon user.
//
if (lpName != NULL && lpName[0] != L'\0') {
if (DavCheckLocalName(lpName) != WN_SUCCESS) {
//
// Check if it is a valid format remote connection: it can be a
// URL form string or can be a UNC format string.
//
NPStatus = DavCheckAndConvertHttpUrlToUncName(lpName,
&(ConnectionName),
&(didAllocate),
FALSE,
&remNameType,
NULL,
TRUE);
if (NPStatus != ERROR_SUCCESS) {
IF_DEBUG_PRINT(DEBUG_ERRORS,
("ERROR: NPGetUser/DavCheckAndConvertHttpUrlToUncName."
" NPStatus = %08lx\n", NPStatus));
if (NPStatus == WN_BAD_NETNAME) {
NPStatus = WN_NOT_CONNECTED;
}
goto EXIT_THE_FUNCTION;
}
//
// Connection names are allowed only to shares or sub-directories
// inside them. So RemoteName should have atleast \\server\share
// part in it.
//
if (remNameType != DAV_REMOTENAME_TYPE_SHARE &&
remNameType != DAV_REMOTENAME_TYPE_PATH) {
IF_DEBUG_PRINT(DEBUG_ERRORS,
("ERROR: NPGetUser/DavCheckAndConvertHttpUrlToUncName."
" remNameType = %d\n", remNameType));
NPStatus = WN_NOT_CONNECTED;
goto EXIT_THE_FUNCTION;
}
//
// Given connection is a valid format remote connection name and
// this connection name is converted to a UNC name.
//
doRpcCall = TRUE;
} else {
//
// Given connection is a valid format local DOS-device name.
//
ConnectionName = lpName;
doRpcCall = TRUE;
}
} else {
//
// Connection name (lpName) passed to this function is L"" or NULL in which
// case we returns user-id of the logon-user.
//
getLogonUserName = TRUE;
}
if (doRpcCall == TRUE) {
ASSERT(ConnectionName != NULL);
NPStatus = DavBindTheRpcHandle( &(dav_binding_h) );
if (NPStatus != ERROR_SUCCESS) {
IF_DEBUG_PRINT(DEBUG_ERRORS,
("ERROR: NPGetUser/DavBindTheRpcHandle. "
"NPStatus = %08lx\n", NPStatus));
NPStatus = WN_NO_NETWORK;
goto EXIT_THE_FUNCTION;
}
bindRpcHandle = TRUE;
RpcTryExcept {
NPStatus = DavrGetUser(dav_binding_h, ConnectionName, &(LocalUserName));
if (NPStatus != WN_SUCCESS) {
IF_DEBUG_PRINT(DEBUG_ERRORS,
("ERROR: NPGetUser/DavrGetUser(1). NPStatus = %08lx\n",
NPStatus));
if (NPStatus == ERROR_NOT_FOUND || NPStatus == NERR_UseNotFound) {
NPStatus = WN_NOT_CONNECTED;
}
if (NPStatus == ERROR_INSUFFICIENT_BUFFER) {
NPStatus = WN_MORE_DATA;
}
goto EXIT_THE_FUNCTION;
} else {
//
// NPStatus == WN_SUCCESS. We are done. Exit.
//
LocalUserNameLengthInBytes = ( (1 + wcslen(LocalUserName)) * sizeof(WCHAR) );
if ( *lpBufferSize < LocalUserNameLengthInBytes ) {
IF_DEBUG_PRINT(DEBUG_ERRORS, ("ERROR: NPGetUser: WStatus = WN_MORE_DATA\n"));
*lpBufferSize = LocalUserNameLengthInBytes;
NPStatus = WN_MORE_DATA;
goto EXIT_THE_FUNCTION;
}
wcscpy(lpUserName, LocalUserName);
//
// The memory for LocalUserName was allocated by the RPC client stub
// based on the string returned by the RPC server. We need to free
// it now since we're done using it.
//
MIDL_user_free(LocalUserName);
LocalUserName = NULL;
goto EXIT_THE_FUNCTION;
}
} RpcExcept (I_RpcExceptionFilter(RpcExceptionCode())) {
RPC_STATUS RpcStatus;
RpcStatus = RpcExceptionCode();
IF_DEBUG_PRINT(DEBUG_ERRORS, ("ERROR: NPGetUser/DavrGetUser."
" RpcExceptionCode = %d\n", RpcStatus));
NPStatus = DavMapRpcErrorToProviderError(RpcStatus);
goto EXIT_THE_FUNCTION;
}
RpcEndExcept
}
//
// We should come here only in case when logged-on user name is to be
// returned.
//
if (getLogonUserName == FALSE) {
//
// Neither the connection exist, nor this function call is called with
// null connection parameter in which case it should return logon-userid
// So we quit here with error WN_NOT_CONNECTED.
//
NPStatus = WN_NOT_CONNECTED;
goto EXIT_THE_FUNCTION;
}
ASSERT(getLogonUserName == TRUE);
//
// Get the required length for storing the name of the currently logged on
// user.
//
NumOfChars = 0;
getUser = GetUserName( NULL, &NumOfChars );
npStatus = GetLastError();
if (getUser != FALSE || npStatus != ERROR_INSUFFICIENT_BUFFER) {
NPStatus = npStatus;
IF_DEBUG_PRINT(DEBUG_ERRORS,
("ERROR: NPGetUser/GetUserName. NPStatus = %08lx\n",
NPStatus));
goto EXIT_THE_FUNCTION;
}
//
// Check to see if the buffer passed-in is of the required length. (It also
// includes the null terminator).
//
if ( *lpBufferSize < NumOfChars || lpUserName == NULL ) {
NPStatus = WN_MORE_DATA;
*lpBufferSize = NumOfChars;
IF_DEBUG_PRINT(DEBUG_ERRORS, ("ERROR: NPGetUser: WStatus = WN_MORE_DATA\n"));
goto EXIT_THE_FUNCTION;
}
//
// Now, get the user name.
//
getUser = GetUserName( lpUserName, lpBufferSize);
if (!getUser) {
NPStatus = GetLastError();
IF_DEBUG_PRINT(DEBUG_ERRORS,
("ERROR: NPGetUser/GetUserName. NPStatus = %08lx\n",
NPStatus));
goto EXIT_THE_FUNCTION;
}
NPStatus = WN_SUCCESS;
EXIT_THE_FUNCTION:
if (bindRpcHandle) {
RpcBindingFree( &(dav_binding_h) );
bindRpcHandle = FALSE;
}
IF_DEBUG_PRINT(DEBUG_EXIT, ("NPGetUser: NPStatus = %d\n", NPStatus));
if(didAllocate == TRUE && ConnectionName != NULL) {
LocalFree((HLOCAL)ConnectionName);
didAllocate = FALSE;
ConnectionName = NULL;
}
//
// The memory for LocalUserName was allocated by the RPC client stub
// based on the string returned by the RPC server. We need to free
// it now if we came down an error path after calling the server.
//
if (LocalUserName != NULL) {
MIDL_user_free(LocalUserName);
LocalUserName = NULL;
}
return NPStatus;
}
DWORD
NPGetConnection(
LPWSTR lpLocalName,
LPWSTR lpRemoteName,
LPDWORD lpBufferSize
)
/*++
Routine Description:
This function determines the remote name associated with the local name
passed in.
Arguments:
lpLocalName - Name of the local drive redirected to the remote name.
lpRemoteName - The remote name to find.
lpBufferSize - Contains the length (in chars not bytes ) of the lpRemoteName
buffer. If the length is insufficient, this place is used to
inform the user the actual length needed.
Return Value:
WN_SUCCESS - Successful. OR
WN_NOT_CONNECTED - The device specified by lpLocalName is not redirected by
this provider.
WN_MORE_DATA - The buffer is too small.
WN_NO_NETWORK - Network is not present.
--*/
{
DWORD NPStatus = WN_SUCCESS, WStatus = ERROR_SUCCESS;
PWCHAR DeviceName = NULL;
DWORD DeviceNameLen = 0, LengthWritten = 0, LocalBufLen = 0, ReqLen = 0;
PWCHAR ServerStart = NULL, SymLink = NULL, LocalAllocBuf = NULL;
WCHAR LocalBuf[MAX_PATH + 1] = L"";
DWORD LocalBufMaxLen = sizeof(LocalBuf)/sizeof(WCHAR);
IF_DEBUG_PRINT(DEBUG_ENTRY, ("NPGetConnection: LocalName = %ws\n", lpLocalName));
//
// If the WebClient service is not running we bail out right away.
//
if ( !DavWorkstationStarted() ) {
IF_DEBUG_PRINT(DEBUG_ERRORS,
("ERROR: NPGetConnection/DavWorkstationStarted. "
"Service NOT Running\n"));
NPStatus = WN_NO_NETWORK;
goto EXIT_THE_FUNCTION;
}
if ( lpLocalName == NULL || lpBufferSize == NULL || (lpRemoteName == NULL && *lpBufferSize != 0) ) {
NPStatus = WN_BAD_VALUE;
IF_DEBUG_PRINT(DEBUG_ERRORS,
("ERROR: NPGetConnection. Invalid parameters. NPStatus = %d\n",
NPStatus));
goto EXIT_THE_FUNCTION;
}
//
// Initialize some local variables.
//
DeviceName = DD_DAV_DEVICE_NAME_U;
DeviceNameLen = DeviceName == NULL ? 0: wcslen(DD_DAV_DEVICE_NAME_U);
LocalBufLen = 0;
SymLink = NULL;
LengthWritten = 0;
ServerStart = NULL;
ReqLen = 0;
//
// Make sure that WebDAV redirector has valid device name set =
// DD_DAV_DEVICE_NAME_U != L""
//
if (DeviceNameLen == 0) {
NPStatus = WN_NOT_CONNECTED;
IF_DEBUG_PRINT(DEBUG_ERRORS,
("ERROR: NPGetConnection. DeviceName=NULL. NPStatus=%d\n", NPStatus));
//
// This should never happen. Break here and investigate.
//
ASSERT(FALSE);
goto EXIT_THE_FUNCTION;
}
//
// Find out from QueryDosDevice, the information about symlink associated
// to it. This call will fail for bad lpLocalName, or for non-existent
// lpLocalName devices. When successful, it will tell the length of buffer
// required to contain symbolic link of the given local device (lpLocalName).
//
//
// We are going to use a local buffer to get the symbolic link. It that
// buffer falls short, then we will try allocating buffer and use them.
//
SymLink = LocalBuf;
LocalBufLen = LocalBufMaxLen;
do {
LengthWritten = QueryDosDeviceW(lpLocalName, SymLink, LocalBufLen);
if ( LengthWritten == 0 ) {
WStatus = GetLastError();
if (WStatus != ERROR_INSUFFICIENT_BUFFER) {
NPStatus = WN_NOT_CONNECTED;
IF_DEBUG_PRINT(DEBUG_ERRORS,
("ERROR: NPGetConnection/QueryDosDevice. GLE=%d, NPStatus=%d\n",
WStatus, NPStatus));
goto EXIT_THE_FUNCTION;
}
//
// Allocate the buffer to hold the symlink to be returned from
// QueryDosDevice call.
//
//
// We are going to allocate more buffer to contain the symbolic link.
// We don't want to allocate more and more and more - so putting a cap
// on max-size that can be allocated or else some error in API QueryDosDevice
// can take this API in trouble.
//
if (LocalBufLen > (MAX_PATH * 10)) {
NPStatus = WN_OUT_OF_MEMORY;
IF_DEBUG_PRINT(DEBUG_ERRORS,
("ERROR: NPGetConnection/LocalAlloc. NPStatus=%d\n",
NPStatus));
ASSERT(FALSE);
goto EXIT_THE_FUNCTION;
}
if (LocalAllocBuf != NULL) {
LocalFree((HLOCAL)LocalAllocBuf);
LocalAllocBuf = NULL;
}
//
// Add MAX_PATH to length of buffer used in last call of QueryDosDevice.
// Allocate buffer of new length and use it in next call of
// QueryDosDevice.
//
LocalBufLen += MAX_PATH;
LocalAllocBuf = LocalAlloc ( (LMEM_FIXED | LMEM_ZEROINIT),
(LocalBufLen * sizeof(WCHAR)) );
if (LocalAllocBuf == NULL) {
NPStatus = WN_OUT_OF_MEMORY;
IF_DEBUG_PRINT(DEBUG_ERRORS,
("ERROR: NPGetConnection/LocalAlloc. NPStatus=%d\n",
NPStatus));
goto EXIT_THE_FUNCTION;
}
SymLink = LocalAllocBuf;
}
} while (LengthWritten == 0);
//
// Check if the given local-name belongs to our device DD_DAV_DEVICE_NAME_U.
// SymLink should be of form (an example):
// \Device\WebDavRedirector\;Z:0000000000000e197\webdav-server\dav-share
// And DeviceName is of form (an example): \Device\WebDavRedirector.
//
if (_wcsnicmp(SymLink, DeviceName, DeviceNameLen) != 0) {
NPStatus = WN_NOT_CONNECTED;
IF_DEBUG_PRINT(DEBUG_ERRORS,
("ERROR: NPGetConnection. Non-DAV device. SymLink=%ws, "
"NPStatus=%d\n", SymLink, NPStatus));
goto EXIT_THE_FUNCTION;
}
//
// Check if local-drive letter in symbolic mapping is same as the
// lpLocalName given to this function.
//
// \Device\WebDavRedirector\;Z:0000000000000e197\webdav-server\dav-share
// And
// lpLocalNname is (in example): Z:
//
if (_wcsnicmp((PWCHAR)(SymLink + DeviceNameLen + 2), lpLocalName, 2) != 0) {
NPStatus = WN_NOT_CONNECTED;
IF_DEBUG_PRINT(DEBUG_ERRORS,
("ERROR: NPGetConnection. SymLink has different drive name. "
"SymLink=%ws, NPStatus=%d\n", SymLink, NPStatus));
goto EXIT_THE_FUNCTION;
}
//
// The control comes here when symbolic-link returned by QueryDosDevice
// belongs to our device and is associated to the local device given in
// this function (lpLocalName).
//
IF_DEBUG_PRINT(DEBUG_MISC,
("ERROR: NPGetConnection. WebDAV symlink FOUND. SymLink=%ws\n",
SymLink));
//
// Now get remote-name stored in symbolic link.
// Example SymLink: \Device\WebDavRedirector\;Z:0000000000000e197\webdav-server\dav-share
// ^
// |
// ServerStart
// This example has remote name = \\webdav-server\dav-share.
//
// Note: an extra L'\' is added in front of "ServerStart" to make it
// valid UNC remote-name.
//
ServerStart = wcschr((PWCHAR)(SymLink + DeviceNameLen + 2), L'\\');
if (ServerStart == NULL) {
NPStatus = WN_NOT_CONNECTED;
IF_DEBUG_PRINT(DEBUG_ERRORS,
("ERROR: NPGetConnection. SymLink do not has remote name. "
"SymLink=%ws, NPStatus=%d\n", SymLink, NPStatus));
goto EXIT_THE_FUNCTION;
}
//
// Symbolic string returned by QueryDosDevice function is a double-null
// terminated string. So subtract 1 from LengthWritten to get length of Symbolic
// string with only 1 null termination character.
//
ReqLen = (LengthWritten - 1) - (DWORD)(ServerStart - SymLink) + 1; // +1 for extra L'\'
if (*lpBufferSize < ReqLen) {
//
// Passed length is shorter than required to store remote name.
//
NPStatus = WN_MORE_DATA;
*lpBufferSize = ReqLen;
IF_DEBUG_PRINT(DEBUG_ERRORS,
("ERROR: NPGetConnection. RequiredLen=%d, NPStatus=%d\n",
ReqLen, NPStatus));
goto EXIT_THE_FUNCTION;
}
//
// Given buffer is enough to contain buffer.
//
wsprintf(lpRemoteName, L"\\%s", ServerStart);
NPStatus = WN_SUCCESS;
IF_DEBUG_PRINT(DEBUG_MISC , ("NPGetConnection: lpRemoteName = %ws\n", lpRemoteName));
EXIT_THE_FUNCTION:
if (LocalAllocBuf != NULL ) {
LocalFree((HLOCAL)LocalAllocBuf);
LocalAllocBuf = NULL;
}
IF_DEBUG_PRINT(DEBUG_EXIT, ("NPGetConnection: NPStatus = %d\n", NPStatus));
return NPStatus;
}
DWORD
APIENTRY
NPAddConnection3(
HWND hwndOwner,
LPNETRESOURCE lpNetResource,
LPTSTR lpPassword,
LPTSTR lpUserName,
DWORD dwFlags
)
/*++
Routine Description:
This function is used to redirect (connect) a local device to a network
resource.
Arguments:
hwndOwner - A handle to a window which should be the owner for any messages
or dialogs. This is only valid if CONNECT_INTERACTIVE is set in
dwFlags, and should only be used to produce dialogs needed for
authentication.
lpNetResource - Specifies the network resource to connect to. This structure
is defined the section describing Enumeration APIs. The
following fields must be set when making a connection, the
others are ignored.
lpRemoteName - Specifies the network resource to connect to.
lpLocalName - This specifies the name of a local device to
be redirected, such as "F:" or "LPT1". The
string is treated in a case insensitive manner,
and may be the empty string (or NULL pointer)
in which case a connection to the network
resource is made without making a redirection.
dwType - Specifies the type of resource to connect to. It
can be RESOURCETYPE_DISK, RESOURCETYPE_PRINT, or
RESOURCETYPE_ANY. The value RESOURCETYPE_ANY is
used if the caller does not care or does not know.
lpPassword - Specifies the password to be used in making the connection,
normally the password associated with lpUserName. The NULL
value may be passed in to indicate to the function to use the
default password. An empty string may be used to indicate no
password.
lpUserName - This specifies the username used to make the connection. If
NULL, the default username (currently logged on user) will be
applied. This is used when the user wishes to connect to a
resource, but has a different user name or account assigned to
him for that resource.
dwFlags - Any combination of the following values:
CONNECT_TEMPORARY - The connection is being established for
browsing purposes and will probably be
released quickly.
CONNECT_INTERACTIVE - May have interaction with the user for
authentication purposes.
CONNECT_PROMPT - Do no use any defaults for usernames or passwords
without offering user the chance to supply an
alternative. This flag is only valid if
CONNECT_INTERACTIVE is set.
CONNECT_DEFERRED - Do not perform any remote network operations to
make the network connection; instead, restore
the connection in a "disconnected state".
Attempt the actual connection only when some
process attempts to use it. If this bit is set,
the caller must supply lpLocalName. This feature
is used to speed the restoring of network
connections at logon. A provider that supports
it should return the WNNC_CON_DEFERRED bit in
NPGetCaps.
The provider should ignore any other bits of dwFlags that may be
set.
Return Value:
WN_SUCCESS - The call is successful. Otherwise, the an error code is
returned, which may include:
WN_BAD_NETNAME - lpRemoteName in the lpNetResource structure is not
acceptable to this provider.
WN_BAD_LOCALNAME - lpLocalName in lpNetResource is invalid.
WN_BAD_PASSWORD - Invalid password.
WN_ALREADY_CONNECTED - lpLocalName already connected.
WN_ACCESS_DENIED - Access denied.
WN_NO_NETWORK - Network is not present.
WN_CANCEL - The attempt to make the connection was cancelled by the user via
a dialog box displayed by the provider.
--*/
{
DWORD NPStatus = WN_SUCCESS;
PWCHAR RemoteName = NULL;
BOOLEAN didAllocate = FALSE;
handle_t dav_binding_h;
BOOL bindRpcHandle = FALSE;
WCHAR UIServerName[CRED_MAX_STRING_LENGTH + 1] = L"";
PFN_CREDUI_CONFIRMCREDENTIALS pfnCredUIConfirmCredentials = NULL;
PFN_CREDUI_PROMPTFORCREDENTIALS pfnCredUIPromptForCredentials = NULL;
PFN_CREDUI_CMDLINE_PROMPTFORCREDENTIALS pfnCredUICmdlinePromptForCredentials = NULL;
HMODULE hCredUI = NULL;
CREDUI_INFOW uiInfo = { sizeof(uiInfo), hwndOwner, NULL };
DWORD dwCreduiFlags = 0;
PWCHAR szCaption = NULL, szMessage = NULL, Password = NULL, UserName = NULL;
SIZE_T szCaptionLength = 0, szMessageLength =0;
DAV_REMOTENAME_TYPE remNameType = DAV_REMOTENAME_TYPE_INVALID;
if ( lpNetResource == NULL ) {
NPStatus = ERROR_INVALID_PARAMETER;
goto EXIT_THE_FUNCTION;
}
IF_DEBUG_PRINT(DEBUG_ENTRY,
("Entering NPAddConnection3. LocalName = %ws, RemoteName = %ws,"
" dwFlags = %08lx\n",
lpNetResource->lpLocalName, lpNetResource->lpRemoteName, dwFlags));
//
// If the WebClient service is not running we bail out right away.
//
if ( !DavWorkstationStarted() ) {
IF_DEBUG_PRINT(DEBUG_ERRORS,
("ERROR: NPAddConnection3/DavWorkstationStarted. "
"Service NOT Running\n"));
NPStatus = WN_NO_NETWORK;
goto EXIT_THE_FUNCTION;
}
//
// Check if dwType is set and is set to some valid value.
// It can be only of type RESOURCETYPE_DISK for our provider.
//
NPStatus = DavCheckResourceType(lpNetResource->dwType);
if (NPStatus != WN_SUCCESS) {
IF_DEBUG_PRINT(DEBUG_ERRORS,
("ERROR: NPAddConnection3. NPStatus=%d.\n", NPStatus));
goto EXIT_THE_FUNCTION;
}
if (lpNetResource->lpLocalName != NULL &&
lpNetResource->lpLocalName[0] != L'\0' &&
lpNetResource->dwType != RESOURCETYPE_DISK) {
NPStatus = WN_BAD_DEV_TYPE;
IF_DEBUG_PRINT(DEBUG_ERRORS,
("ERROR: NPAddConnection3(2). NPStatus=%d.\n", NPStatus));
goto EXIT_THE_FUNCTION;
}
NPStatus = DavCheckAndConvertHttpUrlToUncName(lpNetResource->lpRemoteName,
&(RemoteName),
&(didAllocate),
FALSE,
&remNameType,
NULL,
TRUE);
if (NPStatus != ERROR_SUCCESS) {
IF_DEBUG_PRINT(DEBUG_ERRORS,
("ERROR: NPAddConnection3/DavCheckAndConvertHttpUrlToUncName."
" NPStatus = %08lx\n", NPStatus));
goto EXIT_THE_FUNCTION;
}
if (remNameType != DAV_REMOTENAME_TYPE_SHARE &&
remNameType != DAV_REMOTENAME_TYPE_PATH) {
IF_DEBUG_PRINT(DEBUG_ERRORS,
("ERROR: NPAddConnection3/DavCheckAndConvertHttpUrlToUncName."
" remNameType = %d\n", remNameType));
NPStatus = WN_BAD_NETNAME;
goto EXIT_THE_FUNCTION;
}
IF_DEBUG_PRINT(DEBUG_MISC, ("NPAddConnection3: RemoteName = %ws\n", RemoteName));
NPStatus = DavBindTheRpcHandle( &(dav_binding_h) );
if (NPStatus != ERROR_SUCCESS) {
IF_DEBUG_PRINT(DEBUG_MISC,
("ERROR: NPAddConnection3/DavBindTheRpcHandle. "
"NPStatus = %08lx\n", NPStatus));
NPStatus = WN_NO_NETWORK;
goto EXIT_THE_FUNCTION;
}
bindRpcHandle = TRUE;
RpcTryExcept {
NPStatus = DavrCreateConnection(dav_binding_h,
lpNetResource->lpLocalName,
RemoteName,
lpNetResource->dwType,
lpPassword,
lpUserName);
if (NPStatus == NO_ERROR) {
//
// If default credentials were used, return WN_CONNECTED_OTHER_PASSWORD_DEFAULT
// to let the MPR know we used the default credentials to connect.
//
if (lpUserName == NULL && lpPassword == NULL) {
NPStatus = WN_CONNECTED_OTHER_PASSWORD_DEFAULT;
} else {
NPStatus = WN_SUCCESS;
}
goto EXIT_THE_FUNCTION;
} else {
IF_DEBUG_PRINT(DEBUG_ERRORS,
("ERROR: NPAddConnection3/DavrCreateConnection. "
"NPStatus = %08lx\n", NPStatus));
}
} RpcExcept (I_RpcExceptionFilter(RpcExceptionCode())) {
RPC_STATUS RpcStatus;
RpcStatus = RpcExceptionCode();
IF_DEBUG_PRINT(DEBUG_ERRORS, ("ERROR: NPAddConnection3/DavrCreateConnection."
" RpcExceptionCode = %d\n", RpcStatus));
NPStatus = DavMapRpcErrorToProviderError(RpcStatus);
goto EXIT_THE_FUNCTION;
}
RpcEndExcept
//
// If the error returned was not one of the following, we return the error
// and don't query for the users credentials.
//
if ( NPStatus != ERROR_ACCESS_DENIED &&
NPStatus != ERROR_LOGON_FAILURE &&
NPStatus != ERROR_INVALID_PASSWORD ) {
goto EXIT_THE_FUNCTION;
}
//
// If the CONNECT_INTERACTIVE flag was not specified, then we don't pop up
// the UI.
//
if ( !(dwFlags & CONNECT_INTERACTIVE) ) {
goto EXIT_THE_FUNCTION;
}
if (lpUserName != NULL && (wcslen(lpUserName) > CREDUI_MAX_USERNAME_LENGTH) ) {
NPStatus = WN_BAD_USER;
goto EXIT_THE_FUNCTION;
}
ZeroMemory( UIServerName, ((CRED_MAX_STRING_LENGTH + 1) * sizeof(WCHAR)) );
hCredUI = DavInitCredUI(RemoteName,
UIServerName,
&(pfnCredUIConfirmCredentials),
&(pfnCredUIPromptForCredentials),
&(pfnCredUICmdlinePromptForCredentials));
if (hCredUI == NULL) {
NPStatus = GetLastError();
IF_DEBUG_PRINT(DEBUG_ERRORS,
("ERROR: NPAddConnection3/DavInitCredUI = %d\n", NPStatus));
goto EXIT_THE_FUNCTION;
}
//
// We need to allocate memory for a few things.
//
Password = LocalAlloc((LMEM_FIXED | LMEM_ZEROINIT),
(CREDUI_MAX_PASSWORD_LENGTH + 1) * sizeof(WCHAR));
if (Password == NULL) {
NPStatus = GetLastError();
IF_DEBUG_PRINT(DEBUG_ERRORS,
("ERROR: NPAddConnection3/LocalAlloc = %d\n", NPStatus));
goto EXIT_THE_FUNCTION;
}
UserName = LocalAlloc((LMEM_FIXED | LMEM_ZEROINIT),
(CREDUI_MAX_USERNAME_LENGTH + 1) * sizeof(WCHAR));
if (UserName == NULL) {
NPStatus = GetLastError();
IF_DEBUG_PRINT(DEBUG_ERRORS,
("ERROR: NPAddConnection3/LocalAlloc = %d\n", NPStatus));
goto EXIT_THE_FUNCTION;
}
//
// The extra bytes are for the WCHARS "Connect to " and the L'\0' at
// the end. See the wcsncpy (szCaption) below for understanding this.
//
szCaptionLength = ( ( wcslen(UIServerName) +
wcslen(L"Connect to ") +
1 ) * sizeof(WCHAR) );
szCaption = LocalAlloc((LMEM_FIXED | LMEM_ZEROINIT), szCaptionLength);
if (szCaption == NULL) {
NPStatus = GetLastError();
IF_DEBUG_PRINT(DEBUG_ERRORS,
("ERROR: NPAddConnection3/LocalAlloc = %d\n", NPStatus));
goto EXIT_THE_FUNCTION;
}
//
// The extra 30 bytes is for the 14 WCHARS "Connecting to " and the L'\0' at
// the end. See the wcsncpy (szMessage) below for understanding this.
//
szMessageLength = ( ( wcslen(UIServerName) +
wcslen(L"Connecting to ") +
1) * sizeof(WCHAR) );
szMessage = LocalAlloc((LMEM_FIXED | LMEM_ZEROINIT), szMessageLength);
if (szMessage == NULL) {
NPStatus = GetLastError();
IF_DEBUG_PRINT(DEBUG_ERRORS,
("ERROR: NPAddConnection3/LocalAlloc = %d\n", NPStatus));
goto EXIT_THE_FUNCTION;
}
//
// Copy the caption.
//
wcscpy( szCaption, L"Connect to ");
wcscat( szCaption, UIServerName);
//
// Copy the message.
//
wcscpy( szMessage, L"Connecting to ");
wcscat( szMessage, UIServerName);
//
// Set the message and caption copied above in the uiInfo field.
//
uiInfo.pszMessageText = szMessage;
uiInfo.pszCaptionText = szCaption;
if (lpUserName != NULL) {
wcsncpy( UserName, lpUserName, wcslen(lpUserName) );
}
//
// We loop till the user hits the cancel button or the credentials are
// valid and the connection gets created.
//
for ( ; ; ) {
BOOL fCredWritten = FALSE;
DWORD dwAuthErr = NPStatus;
LPWSTR lpNewPassword = NULL;
Password[0] = L'\0';
//
// Require confirmation of the stored credentials.
//
dwCreduiFlags = CREDUI_FLAGS_EXPECT_CONFIRMATION;
if (dwFlags & CONNECT_COMMANDLINE) {
//
// Set the appropriate flags to set the behavior of the common UI.
//
//
// CredMgr does not (yet) know how to handle certificates.
//
dwCreduiFlags |= CREDUI_FLAGS_EXCLUDE_CERTIFICATES;
//
// Ensure that the username syntax is correct.
//
dwCreduiFlags |= CREDUI_FLAGS_VALIDATE_USERNAME;
//
// If the caller wants to save both username and password,
// create an enterprise peristed cred.
//
if ( dwFlags & CONNECT_CMD_SAVECRED ) {
dwCreduiFlags |= CREDUI_FLAGS_PERSIST;
} else {
dwCreduiFlags |= CREDUI_FLAGS_DO_NOT_PERSIST;
}
IF_DEBUG_PRINT(DEBUG_MISC,
("NPAddConnection3: pfnCredUICmdlinePromptForCredentials."
" RemoteName = %ws\n", RemoteName));
NPStatus = pfnCredUICmdlinePromptForCredentials(UIServerName,
NULL,
0,
UserName,
CREDUI_MAX_USERNAME_LENGTH,
Password,
CREDUI_MAX_PASSWORD_LENGTH,
&fCredWritten,
dwCreduiFlags);
} else {
IF_DEBUG_PRINT(DEBUG_MISC,
("NPAddConnection3: pfnCredUIPromptForCredentials."
" RemoteName = %ws\n", RemoteName));
NPStatus = pfnCredUIPromptForCredentials(&(uiInfo),
UIServerName,
NULL,
0,
UserName,
CREDUI_MAX_USERNAME_LENGTH,
Password,
CREDUI_MAX_PASSWORD_LENGTH,
&fCredWritten,
dwCreduiFlags);
}
if (NPStatus != ERROR_SUCCESS) {
SetLastError(NPStatus);
goto EXIT_THE_FUNCTION;
} else {
lpUserName = (L'\0' == UserName[0]) ? NULL : UserName;
lpNewPassword = (L'\0' == Password[0]) ? NULL : Password;
}
//
// Try to connect to the server again with the new credentials the user
// entered.
//
RpcTryExcept {
NPStatus = DavrCreateConnection(dav_binding_h,
lpNetResource->lpLocalName,
RemoteName,
lpNetResource->dwType,
lpNewPassword,
lpUserName);
if (NPStatus != NO_ERROR) {
IF_DEBUG_PRINT(DEBUG_ERRORS,
("ERROR: NPAddConnection3/DavrCreateConnection(2). "
"NPStatus = %08lx\n", NPStatus));
//
// Report cred as not working.
//
pfnCredUIConfirmCredentials(UIServerName, FALSE);
SetLastError(NPStatus);
} else {
//
// Since we succeeded, we can/should confirm these credentials.
//
NPStatus = WN_SUCCESS;
pfnCredUIConfirmCredentials(UIServerName, TRUE);
//
// If the credentials were not stored in credman, tell MPR so it
// can prompt the user when restoring peristent connections. If
// the credentials were stored in credman, tell MPR that the
// default credential was used.
//
if (fCredWritten) {
NPStatus = WN_CONNECTED_OTHER_PASSWORD_DEFAULT;
} else if ( (lpPassword == NULL) || (wcscmp(lpPassword, lpNewPassword) != 0) ) {
NPStatus = WN_CONNECTED_OTHER_PASSWORD;
}
goto EXIT_THE_FUNCTION;
}
} RpcExcept (I_RpcExceptionFilter(RpcExceptionCode())) {
RPC_STATUS RpcStatus;
RpcStatus = RpcExceptionCode();
IF_DEBUG_PRINT(DEBUG_ERRORS, ("ERROR: NPAddConnection3/DavrCreateConnection."
" RpcExceptionCode = %d\n", RpcStatus));
NPStatus = DavMapRpcErrorToProviderError(RpcStatus);
//
// Report cred as not working.
//
pfnCredUIConfirmCredentials(UIServerName, FALSE);
goto EXIT_THE_FUNCTION;
}
RpcEndExcept
//
// For command line prompting, only prompt once.
//
if ( dwFlags & CONNECT_COMMANDLINE ) {
break;
}
} // end of for loop.
EXIT_THE_FUNCTION:
if (bindRpcHandle) {
RpcBindingFree( &(dav_binding_h) );
bindRpcHandle = FALSE;
}
//
// If RemoteName != NULL && didAllocate == TRUE, then we did allocate memory
// for the RemoteName field.
//
if (RemoteName && didAllocate) {
LocalFree(RemoteName);
RemoteName = NULL;
}
if (hCredUI) {
FreeLibrary(hCredUI);
hCredUI = NULL;
}
//
// Clear the password from memory before freeing it.
//
if (Password != NULL) {
SecureZeroMemory(Password, ((CREDUI_MAX_PASSWORD_LENGTH + 1) * sizeof(WCHAR)));
LocalFree(Password);
Password = NULL;
}
if (UserName != NULL) {
LocalFree(UserName);
UserName = NULL;
}
if (szCaption != NULL) {
LocalFree(szCaption);
szCaption = NULL;
}
if (szMessage != NULL) {
LocalFree(szMessage);
szMessage = NULL;
}
IF_DEBUG_PRINT(DEBUG_EXIT, ("NPAddConnection3: NPStatus = %d\n", NPStatus));
return NPStatus;
}
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:
WN_SUCCESS - 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.
WN_ACCESS_DENIED - Unable to connect with the given credentials.
--*/
{
DWORD NPStatus = WN_SUCCESS;
NPStatus = NPAddConnection3(NULL,
lpNetResource,
lpPassword,
lpUserName,
0);
if (NPStatus != WN_SUCCESS) {
IF_DEBUG_PRINT(DEBUG_ERRORS,
("ERROR: NPAddConnection/NPAddConnection3. "
"NPStatus = %08lx\n", NPStatus));
}
return NPStatus;
}
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 NPStatus;
PWCHAR RemoteName = NULL;
BOOLEAN didAllocate = FALSE;
BOOL bindRpcHandle = FALSE;
handle_t dav_binding_h;
DAV_REMOTENAME_TYPE remNameType = DAV_REMOTENAME_TYPE_INVALID;
IF_DEBUG_PRINT(DEBUG_ENTRY,
( "NPCancelConnection: Name = %ws, Force = %s\n",
lpName, (fForce == 0 ? "FALSE" : "TRUE") ));
//
// If the WebClient service is not running we bail out right away.
//
if ( !DavWorkstationStarted() ) {
IF_DEBUG_PRINT(DEBUG_ERRORS,
("ERROR: NPCancelConnection/DavWorkstationStarted. "
"Service NOT Running\n"));
NPStatus = WN_NO_NETWORK;
goto EXIT_THE_FUNCTION;
}
if ( lpName == NULL || lpName[0] == L'\0' ) {
IF_DEBUG_PRINT(DEBUG_ERRORS,
("ERROR: NPCancelConnection. lpName is not valid"));
NPStatus = ERROR_INVALID_PARAMETER;
goto EXIT_THE_FUNCTION;
}
//
// If the name supplied is a local name then the second char will be a L':'.
// If its not a local name, then we should check to see if the remote name
// is of the form http:. If it is, we convert it to the UNC format and send
// it to the RPC server.
//
if (DavCheckLocalName(lpName) != WN_SUCCESS ) {
NPStatus = DavCheckAndConvertHttpUrlToUncName(lpName,
&(RemoteName),
&(didAllocate),
FALSE /*TRUE*/,
&remNameType,
NULL,
TRUE);
if (NPStatus != ERROR_SUCCESS) {
IF_DEBUG_PRINT(DEBUG_ERRORS,
("ERROR: NPCancelConnection/DavCheckAndConvertHttpUrlToUncName."
" NPStatus = %08lx\n", NPStatus));
goto EXIT_THE_FUNCTION;
}
if (remNameType != DAV_REMOTENAME_TYPE_SHARE &&
remNameType != DAV_REMOTENAME_TYPE_PATH) {
IF_DEBUG_PRINT(DEBUG_ERRORS,
("ERROR: NPCancelConnection/DavCheckAndConvertHttpUrlToUncName."
" remNameType=%d\n", remNameType));
NPStatus = WN_BAD_NETNAME;
goto EXIT_THE_FUNCTION;
}
} else {
//
// If we are removing a local name, set the RemoteName value to be the
// local name.
//
RemoteName = lpName;
}
IF_DEBUG_PRINT(DEBUG_MISC, ("NPCancelConnection: RemoteName = %ws\n", RemoteName));
NPStatus = DavBindTheRpcHandle( &(dav_binding_h) );
if (NPStatus != ERROR_SUCCESS) {
IF_DEBUG_PRINT(DEBUG_ERRORS,
("ERROR: NPAddConnection/DavBindTheRpcHandle. "
"NPStatus = %08lx\n", NPStatus));
NPStatus = WN_NO_NETWORK;
goto EXIT_THE_FUNCTION;
}
bindRpcHandle = TRUE;
RpcTryExcept {
NPStatus = DavrDeleteConnection(dav_binding_h, RemoteName, fForce);
if (NPStatus != NO_ERROR) {
IF_DEBUG_PRINT(DEBUG_ERRORS,
("ERROR: NPCancelConnection/DavDeleteConnection. "
"NPStatus = %08lx\n", NPStatus));
if (NPStatus == ERROR_NOT_FOUND || NPStatus == NERR_UseNotFound) {
NPStatus = WN_NOT_CONNECTED;
}
goto EXIT_THE_FUNCTION;
} else {
NPStatus = WN_SUCCESS;
goto EXIT_THE_FUNCTION;
}
} RpcExcept (I_RpcExceptionFilter(RpcExceptionCode())) {
RPC_STATUS RpcStatus;
RpcStatus = RpcExceptionCode();
IF_DEBUG_PRINT(DEBUG_ERRORS, ("ERROR: NPCancelConnection/DavrDeleteConnection."
" RpcExceptionCode = %d\n", RpcStatus));
NPStatus = DavMapRpcErrorToProviderError(RpcStatus);
goto EXIT_THE_FUNCTION;
}
RpcEndExcept
EXIT_THE_FUNCTION:
if (bindRpcHandle) {
RpcBindingFree( &(dav_binding_h) );
bindRpcHandle = FALSE;
}
//
// If RemoteName != NULL && didAllocate == TRUE, then we did allocate memory
// for the RemoteName field.
//
if (RemoteName && didAllocate) {
LocalFree(RemoteName);
RemoteName = NULL;
}
IF_DEBUG_PRINT(DEBUG_EXIT, ("NPCancelConnection: NPStatus = %d\n", NPStatus));
return NPStatus;
}
DWORD
NPOpenEnum(
IN DWORD dwScope,
IN DWORD dwType,
IN DWORD dwUsage,
IN LPNETRESOURCE lpNetResource,
OUT LPHANDLE lphEnum
)
/*++
Routine Description:
This API is used to Open an enumeration of network resources or existing
connections.
Arguments:
dwScope - Determines the scope of the enumeration. This can be one of:
RESOURCE_CONNECTED - All currently connected resources.
RESOURCE_GLOBALNET - All resources on the network.
RESOURCE_CONTEXT - The resources associated with the user's
current and default network context. Used for
a "Network Neighbourhood" view.
dwType - Used to specify the type of resources of interest. This is a
bitmask which may be any combination of:
RESOURCETYPE_DISK - All disk resources.
RESOURCETYPE_PRINT - All print resources.
RESOURCEUSAGE_ATTACHED - Specifies that the function should fail if
the caller is not authenticated (even if
the network permits enumeration without
authentication).
If dwType is 0, or is just RESOURCEUSAGE_ATTACHED, all types of
resources are returned. If a provider does not have the capability
to distinguish between print and disk resources at a level,
it may return all resources.
dwUsage - Used to specify the usage of resources of interested. This is a
bitmask which may be any combination of:
RESOURCEUSAGE_CONNECTABLE - All connectable resources.
RESOURCEUSAGE_CONTAINER - All container resources.
The bitmask may be 0 to match all. This parameter may be ignored
if dwScope is not RESOURCE_GLOBALNET.
lpNetResource - This specifies the container to perform the enumeration. The
NETRESOURCE could have been obtained via a previous
NPEnumResource, or constructed by the caller or NULL. If it
is NULL, or if the lpRemoteName field of the NETRESOURCE is
NULL, the provider should enumerate the top level of its
network. (Note: This means that a provider cannot use an
lpRemoteName of NULL to represent any network resource.) A
caller would normally start off by calling NPOpenEnum with
this parameter set to NULL, and then use the returned
results for further enumeration. If the calling program
knows exactly the provider and remote path to enumerate from,
it may build its own NETRESOURCE structure to pass in,
filling in the lpProvider and lpRemoteName fields. Note that
if dwScope is RESOURCE_CONNECTED or RESOURCE_CONTEXT this
parameter will be NULL.
lphEnum - If function call is successful, a handle will be returned here
that can then be used for enumeration.
Return Value:
WN_SUCCESS- If the call is successful. Otherwise, an error code is returned,
which may include:
WN_NOT_SUPPORTED - The provider does not support the type of enumeration
being requested, or the specific network resource cannot
be browsed.
WN_NOT_CONTAINER - lpNetResource does not point to a container.
WN_BAD_VALUE - Invalid dwScope or dwUsage or dwType, or bad combination of
parameters is specified.
WN_NO_NETWORK - Network is not present.
--*/
{
DWORD NPStatus = WN_SUCCESS;
PDAV_ENUMNODE DavEnumNode = NULL;
BOOL isThisDavServer = FALSE, bRetEnumNode = FALSE;
LPNETRESOURCEW lpNROut = NULL;
ULONG RemoteNameSizeInBytes = 0;
PWCHAR RemoteName = NULL, pRemoteName = NULL;
BOOLEAN didAllocate = FALSE;
DAV_REMOTENAME_TYPE remNameType = DAV_REMOTENAME_TYPE_INVALID;
IF_DEBUG_PRINT(DEBUG_ENTRY,
("NPOpenEnum: Entered. dwScope=0x%x, dwType=0x%x "
"dwUsage=0x%x, lpNetResource=0x%x\n",
dwScope, dwType, dwUsage, lpNetResource));
DavDisplayNetResource(lpNetResource, L"lpNetResource in NPOpenEnum");
//
// If the WebClient service is not running we bail out right away.
//
if ( !DavWorkstationStarted() ) {
IF_DEBUG_PRINT(DEBUG_ERRORS,
("ERROR: NPOpenEnum/DavWorkstationStarted. "
"Service NOT Running\n"));
NPStatus = WN_NO_NETWORK;
goto EXIT_THE_FUNCTION;
}
//
// We need to perform some basic checks before moving ahead.
//
if (lphEnum == NULL) {
NPStatus = WN_BAD_VALUE;
IF_DEBUG_PRINT(DEBUG_ERRORS,
("ERROR: NPOpenEnum: lphEnum == NULL. NPStatus = %d\n",
NPStatus));
goto EXIT_THE_FUNCTION;
}
//
// Validate dwType parameter - it can have RESOURCEUSAGE_ATTACHED in addition
// to its standard set of values - but currently RESOURCEUSAGE_ATTACHED is
// a NO-OP for us.
//
if (dwType == 0 || dwType == RESOURCEUSAGE_ATTACHED ) {
dwType = RESOURCETYPE_DISK;
}
if ( dwType & ~RESOURCETYPE_DISK ) {
NPStatus = WN_BAD_VALUE;
IF_DEBUG_PRINT(DEBUG_ERRORS, ("ERROR: NPOpenEnum: Invalid dwType."
"NPStatus=%d\n", NPStatus));
goto EXIT_THE_FUNCTION;
}
DavEnumNode = LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT, sizeof(DAV_ENUMNODE));
if (DavEnumNode == NULL) {
NPStatus = GetLastError();
IF_DEBUG_PRINT(DEBUG_ERRORS, ("ERROR: NPOpenEnum/LocalAlloc: NPStatus"
" = %08lx\n", NPStatus));
goto EXIT_THE_FUNCTION;
}
bRetEnumNode = FALSE;
switch (dwScope) {
case RESOURCE_CONNECTED: {
//
// We are looking for current uses.
//
IF_DEBUG_PRINT(DEBUG_MISC, ("NPOpenEnum: RESOURCE_CONNECTED\n"));
//
// lpNetResource should be == NULL for this dwScope.
//
if (lpNetResource != NULL) {
NPStatus = WN_BAD_VALUE;
IF_DEBUG_PRINT(DEBUG_ERRORS,
("ERROR: NPOpenEnum: RESOURCE_CONNECTED. lpNetRes != NULL."
"NPStatus = %d\n", NPStatus));
goto EXIT_THE_FUNCTION;
}
bRetEnumNode = TRUE;
DavEnumNode->DavEnumNodeType = DAV_ENUMNODE_TYPE_USE;
pRemoteName = NULL;
break;
}
case RESOURCE_CONTEXT: {
//
// We are looking for servers in the domain. We don't support this
// search in the DAV NP since there is no way of enumerating the DAV
// servers in the domain. DAV doesn't even support the domain concept.
//
NPStatus = WN_NOT_SUPPORTED;
IF_DEBUG_PRINT(DEBUG_ERRORS,
("ERROR: NPOpenEnum: RESOURCE_CONTEXT not supported."
" NPStatus = %d\n",
NPStatus));
goto EXIT_THE_FUNCTION;
break;
}
case RESOURCE_SHAREABLE: {
//
// We are looking for shareable resources. lpNetResource should contain
// lpRemoteName for a server in UNC/URL form. In this case, enumerate
// shares under this server.
//
IF_DEBUG_PRINT(DEBUG_MISC, ("NPOpenEnum: RESOURCE_SHAREABLE\n"));
if ( lpNetResource == NULL || lpNetResource->lpRemoteName == NULL ) {
NPStatus = WN_BAD_VALUE;
IF_DEBUG_PRINT(DEBUG_ERRORS,
("ERROR: NPOpenEnum: RESOURCE_SHAREABLE. Bad parameter "
"lpNetResource or lpRemoteName == NULL. NPStatus = %d\n", NPStatus));
goto EXIT_THE_FUNCTION;
}
//
// Need to convert lpRemoteName to UNC form if possible. This
// can be a URL name originally.
//
NPStatus = DavCheckAndConvertHttpUrlToUncName(lpNetResource->lpRemoteName,
&(RemoteName),
&(didAllocate),
FALSE,
&remNameType,
NULL,
TRUE);
if (NPStatus != ERROR_SUCCESS || remNameType != DAV_REMOTENAME_TYPE_SERVER) {
NPStatus = WN_BAD_NETNAME;
IF_DEBUG_PRINT(DEBUG_ERRORS,
("ERROR: NPOpenEnum: RESOURCE_SHAREABLE. lpRemoteName != SERVER."
" NPStatus = %d\n",NPStatus));
goto EXIT_THE_FUNCTION;
}
//
// We need to check if the given server is a DAV server.
//
if (DavServerExists(RemoteName, NULL) != TRUE) {
NPStatus = WN_BAD_NETNAME;
IF_DEBUG_PRINT(DEBUG_ERRORS,
("ERROR: NPOpenEnum: RESOURCE_SHAREABLE. Server does not exist."
"NPStatus = %d\n", NPStatus));
goto EXIT_THE_FUNCTION;
}
//
// RemoteName is a valid server name in UNC form (\\server)
//
pRemoteName = RemoteName;
bRetEnumNode = TRUE;
DavEnumNode->DavEnumNodeType = DAV_ENUMNODE_TYPE_SHARE;
break;
}
case RESOURCE_GLOBALNET: {
//
// Only - RemoteName == UNC/URL-server or RemoteName == UNC/URL-share or
// RemoteName == UNC/URL-path are supported in this scope. In this cases,
// shares under this RemoteName are enumerated. Top level (when RemoteName
// == NULL or non-UNC-URL entity) is not supported.
//
//
// Look for the combination of all bits and substitute "All" for them.
// Ignore bits we don't know about.
// Note: RESOURCEUSAGE_ATTACHED is a no-op for us.
//
IF_DEBUG_PRINT(DEBUG_MISC, ("NPOpenEnum: RESOURCE_GLOBALNET\n"));
//
// Check for presence of valid flags. If dwUsage is 0 we set it to
// RESOURCEUSAGE_ALL since thats what is implied by the caller.
//
if (dwUsage == 0) {
dwUsage = RESOURCEUSAGE_ALL;
}
//
// We return WN_BAD_VALUE if the caller gave us a dwUsage value which
// we do not support.
//
if ( !( dwUsage & (RESOURCEUSAGE_ALL | RESOURCEUSAGE_CONNECTABLE | RESOURCEUSAGE_CONTAINER) ) ) {
NPStatus = WN_BAD_VALUE;
IF_DEBUG_PRINT(DEBUG_ERRORS,
("ERROR: NPOpenEnum: RESOURCE_GLOBALNET - dwUsage invalid value."
"NPStatus = %d\n", NPStatus));
goto EXIT_THE_FUNCTION;
}
//
// Only RESOURCEUSAGE_CONNECTABLE & RESOURCEUSAGE_CONTAINER are
// supported, hence filter out flags which are not related to these.
//
#if 0
if (dwUsage & RESOURCEUSAGE_ALL) {
dwUsage |= (RESOURCEUSAGE_CONNECTABLE | RESOURCEUSAGE_CONTAINER);
}
#endif
dwUsage &= (RESOURCEUSAGE_CONNECTABLE | RESOURCEUSAGE_CONTAINER);
//
// We are looking for global resources out on the net. Since we do NOT
// have a concept of domains in the DAV NP, the top level resources in
// the network are servers. Our hierarchy is
// 1. Entire Network ===> 2. Web Client Network ===> 3. Servers ===>
// 4. Shares.
//
if ( lpNetResource == NULL || lpNetResource->lpRemoteName == NULL ) {
//
// We have been asked to enumerate the top level containers in the
// network. In the DAV NP, these are the DAV servers we know about.
// The caller should have set the dwUsage to RESOURCEUSAGE_CONTAINER
// since its asking us to enumerate the container types.
//
if ( (dwUsage & RESOURCEUSAGE_CONTAINER) == 0 ) {
NPStatus = WN_BAD_VALUE;
IF_DEBUG_PRINT(DEBUG_ERRORS,
("ERROR: NPOpenEnum: RESOURCE_GLOBALNET. "
"(dwUsage & RESOURCEUSAGE_CONTAINER)."
"NPStatus = %d\n", NPStatus));
goto EXIT_THE_FUNCTION;
}
//
// At top level, therefore enumerating domains. If the user asked
// for connectable, well, there aint none. We don't support the
// concept of enumerating domains in the DAV NP. Rather we will return
// the list of servers that are access from this client.
//
pRemoteName = NULL;
bRetEnumNode = TRUE;
DavEnumNode->DavEnumNodeType = DAV_ENUMNODE_TYPE_SERVER;
} else {
//
// If we come here, it implies that we have a name. At this point we
// assume that we have been given a server and have been asked to
// enumerate the shares exposed by the server.
//
//
// Since we have been asked to enumerate the shares, the dwUsage
// value should have the RESOURCEUSAGE_CONNECTABLE flag set.
//
if ( (dwUsage & RESOURCEUSAGE_CONNECTABLE) == 0 ) {
NPStatus = WN_BAD_VALUE;
IF_DEBUG_PRINT(DEBUG_ERRORS,
("ERROR: NPOpenEnum: RESOURCE_GLOBALNET. "
"(dwUsage & RESOURCEUSAGE_CONNECTABLE)."
"NPStatus = %d\n", NPStatus));
goto EXIT_THE_FUNCTION;
}
//
// We are assured of lpRemoteName != NULL. Check that the given
// lpNetResource is a CONTAINER. It has to be a container since we
// assume that its a server. Remember that below we are checking the
// dwUsage values of the lpNetResource.
//
if ( (lpNetResource->dwUsage != 0) &&
((lpNetResource->dwUsage & RESOURCEUSAGE_CONTAINER) != RESOURCEUSAGE_CONTAINER) ) {
NPStatus = WN_NOT_CONTAINER;
IF_DEBUG_PRINT(DEBUG_ERRORS,
("ERROR: NPOpenEnum: RESOURCE_GLOBALNET. lpNetRes != CONTAINER."
"NPStatus = %d\n", NPStatus));
goto EXIT_THE_FUNCTION;
}
NPStatus = WN_SUCCESS;
NPStatus = DavCheckAndConvertHttpUrlToUncName(lpNetResource->lpRemoteName,
&(RemoteName),
&(didAllocate),
FALSE,
&remNameType,
NULL,
TRUE);
if ( NPStatus != ERROR_SUCCESS || remNameType != DAV_REMOTENAME_TYPE_SERVER ) {
IF_DEBUG_PRINT(DEBUG_ERRORS,
("ERROR: NPOpenEnum/DavCheckAndConvertHttpUrlToUncName "
"RESOURCE_GLOBALNET. NPStatus = %u\n", NPStatus));
NPStatus = WN_BAD_NETNAME;
goto EXIT_THE_FUNCTION;
}
//
// RemoteName is UNC here - it is of form UNC-server.
// We support both CONTAINERS (sub-directories) and CONNECTABLES (sub-dir)
// on all these remote forms.
//
ASSERT(RemoteName != NULL);
//
// Check if the server given in RemoteName is a valid DAV server.
//
if (DavServerExists(RemoteName, NULL) != TRUE ) {
NPStatus = WN_BAD_NETNAME;
IF_DEBUG_PRINT(DEBUG_ERRORS,
("ERROR: NPOpenEnum/DavServerExists. RESOURCE_GLOBALNET."
"NPStatus = %u\n", NPStatus));
goto EXIT_THE_FUNCTION;
}
bRetEnumNode = TRUE;
DavEnumNode->DavEnumNodeType = DAV_ENUMNODE_TYPE_SHARE;
pRemoteName = RemoteName;
}
break;
}
default: {
NPStatus = WN_BAD_VALUE;
IF_DEBUG_PRINT(DEBUG_ERRORS, ("ERROR: NPOpenEnum: default: InvPar dwScope\n"));
goto EXIT_THE_FUNCTION;
}
};
//
// If the EnumNodeType is not one of DAV_ENUMNODE_TYPE_SHARE OR
// DAV_ENUMNODE_TYPE_USE, then we return WN_NOT_SUPPORTED. The only kind
// of enumeration we support in the DAV NP is USE and SHAREs on a server.
//
if ( (DavEnumNode->DavEnumNodeType != DAV_ENUMNODE_TYPE_SHARE) &&
(DavEnumNode->DavEnumNodeType != DAV_ENUMNODE_TYPE_SERVER) &&
(DavEnumNode->DavEnumNodeType != DAV_ENUMNODE_TYPE_USE) &&
(bRetEnumNode == TRUE) ) {
bRetEnumNode = FALSE;
NPStatus = WN_NOT_SUPPORTED;
IF_DEBUG_PRINT(DEBUG_ERRORS, ("ERROR: NPOpenEnum: WN_NOT_SUPPORTED!!!\n"));
goto EXIT_THE_FUNCTION;
}
//
// We are returning valid handle to object DAV_ENUMNODE.
//
ASSERT(bRetEnumNode == TRUE);
DavEnumNode->dwScope = dwScope;
DavEnumNode->dwType = dwType;
DavEnumNode->dwUsage = dwUsage;
DavEnumNode->Done = FALSE;
DavEnumNode->Index = 0;
//
// If the lpNetResource is not NULL, then we create a copy of it and store
// it in the DavEnumNode
//
if (lpNetResource != NULL) {
//
// Allocate memory for the lpNetResource for this DavEnumNode.
//
lpNROut = LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT, sizeof(NETRESOURCEW));
if (lpNROut == NULL) {
NPStatus = GetLastError();
IF_DEBUG_PRINT(DEBUG_ERRORS, ("ERROR: NPOpenEnum/LocalAlloc: NPStatus"
" = %08lx\n", NPStatus));
bRetEnumNode = FALSE;
goto EXIT_THE_FUNCTION;
}
lpNROut->dwScope = lpNetResource->dwScope;
lpNROut->dwType = lpNetResource->dwType;
lpNROut->dwDisplayType = lpNetResource->dwDisplayType;
lpNROut->dwUsage = lpNetResource->dwUsage;
//
// If the lpRemoteName field is not NULL, then we copy the name into the
// structure that we are creating. lpRemoteName field in lpNROut will
// always point to a valid UNC form or a valid non-UNC form. For this,
// we are creating this name from the remotename we got from function
// DavCheckAndConvertHttpUrlToUncName.
//
if (pRemoteName != NULL && didAllocate == FALSE) {
//
// We need to copy the remote name since thats all what we are
// interested in.
//
RemoteNameSizeInBytes = ( ( wcslen(pRemoteName) + 1 ) * sizeof(WCHAR) );
lpNROut->lpRemoteName = LocalAlloc((LMEM_FIXED | LMEM_ZEROINIT),
RemoteNameSizeInBytes);
if (lpNROut->lpRemoteName == NULL) {
NPStatus = GetLastError();
IF_DEBUG_PRINT(DEBUG_ERRORS, ("ERROR: NPOpenEnum/LocalAlloc: NPStatus"
" = %08lx\n", NPStatus));
bRetEnumNode = FALSE;
goto EXIT_THE_FUNCTION;
}
//
// Finally copy the remote name from the lpNetResource.
//
wcscpy(lpNROut->lpRemoteName, pRemoteName);
IF_DEBUG_PRINT(DEBUG_MISC,
("NPOpenEnum: lpNROut->lpRemoteName = %ws\n",
lpNROut->lpRemoteName));
} else if (pRemoteName != NULL && didAllocate == TRUE) {
lpNROut->lpRemoteName = pRemoteName;
didAllocate = FALSE;
IF_DEBUG_PRINT(DEBUG_MISC,
("NPOpenEnum: lpNROut->lpRemoteName(2) = %ws\n",
lpNROut->lpRemoteName));
}
DavEnumNode->lpNetResource = lpNROut;
}
//
// Set DavEnumNode to be the handle. We will get called back in
// NpEnumResource with this value.
//
*lphEnum = (HANDLE)DavEnumNode;
NPStatus = WN_SUCCESS;
DavDisplayEnumNode(DavEnumNode, L"DavEnumNode in NPOpenEnum");
IF_DEBUG_PRINT(DEBUG_MISC, ("NPOpenEnum: DavEnumNode = %08lx\n", DavEnumNode));
EXIT_THE_FUNCTION:
//
// If we did not succeed, then we should be freeing the memory if we
// allocated any. Also, set *lphEnum to NULL just to be on the safe side.
//
if (NPStatus != WN_SUCCESS || bRetEnumNode == FALSE) {
if (lpNROut) {
if (lpNROut->lpRemoteName) {
LocalFree(lpNROut->lpRemoteName);
lpNROut->lpRemoteName = NULL;
}
LocalFree(lpNROut);
lpNROut = NULL;
}
if (DavEnumNode) {
LocalFree(DavEnumNode);
DavEnumNode = NULL;
}
if (lphEnum) {
*lphEnum = NULL;
}
}
if (didAllocate == TRUE && RemoteName != NULL) {
LocalFree(RemoteName);
RemoteName = NULL;
didAllocate = FALSE;
}
IF_DEBUG_PRINT(DEBUG_EXIT, ("NPOpenEnum: NPStatus = %d\n", NPStatus));
DavDebugBreakPoint();
return NPStatus;
}
DWORD
NPEnumResource(
HANDLE hEnum,
LPDWORD lpcCount,
LPVOID lpBuffer,
LPDWORD lpBufferSize
)
/*++
Routine Description:
Perform an enumeration based on handle returned by NPOpenEnum.
Arguments:
hEnum - This must be a handle obtained from NPOpenEnum call.
lpcCount - Specifies the number of entries requested. It may be 0xFFFFFFFF
to request as many as possible. On successful call, this location
will receive the number of entries actually read.
lpBuffer - A pointer to the buffer to receive the enumeration result, which
are returned as an array of NETRESOURCE entries. The buffer is
valid until the next call using hEnum.
lpBufferSize - This specifies the size in bytes of the buffer passed to the
function call on entry. On exit, if the buffer is too small
for even one entry, this will contain the number of bytes
needed to read one entry. The value is only set if the
return code is WN_MORE_DATA.
Return Value:
WN_SUCCESS - If the call is successful, the caller may continue to call
NPEnumResource to continue the enumeration.
WN_NO_MORE_ENTRIES - No more entries found, the enumeration completed
successfully (the contents of the return buffer is
undefined).
WN_MORE_DATA - The buffer is too small even for one entry.
WN_BAD_HANDLE - hEnum is not a valid handle.
WN_NO_NETWORK - Network is not present. This condition is checked for before
hEnum is tested for validity.
--*/
{
DWORD NPStatus = WN_SUCCESS;
PDAV_ENUMNODE DavEnumNode = NULL;
BOOL SrvExists = FALSE, RpcBindSucceeded = FALSE;
handle_t dav_binding_h = NULL;
DWORD cRequested = 0, Index = 0, EntryLengthNeededInBytes = 0, BufferSizeRemaining = 0;
LPNETRESOURCEW lpNROut = NULL;
PWCHAR lpszNext = NULL;
BOOLEAN AreWeDone = FALSE;
PWCHAR FromEnd = NULL;
DWORD LocalNameLength = 0, RemoteNameLength = 0, DisplayNameLength = 0;
PWCHAR LocalName = NULL;
PWCHAR RemoteName = NULL, ServerName = NULL;
DWORD ServerNameMaxLen = 0;
BOOLEAN ServerNameAllocated = FALSE;
IF_DEBUG_PRINT(DEBUG_ENTRY, ("NPEnumResource: Entered.\n"));
//
// If the WebClient service is not running we bail out right away.
//
if ( !DavWorkstationStarted() ) {
IF_DEBUG_PRINT(DEBUG_ERRORS,
("ERROR: NPEnumResource/DavWorkstationStarted. "
"Service NOT Running\n"));
NPStatus = WN_NO_NETWORK;
goto EXIT_THE_FUNCTION;
}
if ( lpcCount == NULL || lpBufferSize == NULL || (lpBuffer == NULL && *lpBufferSize != 0)) {
IF_DEBUG_PRINT(DEBUG_ERRORS, ("ERROR: NPEnumResource: Invalid Parameter\n"));
NPStatus = WN_BAD_VALUE;
goto EXIT_THE_FUNCTION;
}
if ( hEnum == NULL ) {
IF_DEBUG_PRINT(DEBUG_ERRORS, ("ERROR: NPEnumResource: Invalid Handle\n"));
NPStatus = WN_BAD_HANDLE;
goto EXIT_THE_FUNCTION;
}
IF_DEBUG_PRINT(DEBUG_MISC, ("NPEnumResource: hEnum = %08lx\n", hEnum));
IF_DEBUG_PRINT(DEBUG_MISC, ("NPEnumResource: Count = %u\n", *lpcCount));
DavEnumNode = (PDAV_ENUMNODE)hEnum;
DavDisplayEnumNode(DavEnumNode, L"DavEnumNode in NPEnumResources");
if ( DavEnumNode->Done == TRUE ) {
IF_DEBUG_PRINT(DEBUG_MISC, ("NPEnumResource: Done == TRUE\n"));
NPStatus = WN_NO_MORE_ENTRIES;
goto EXIT_THE_FUNCTION;
}
BufferSizeRemaining = *lpBufferSize;
lpNROut = (LPNETRESOURCEW)lpBuffer;
lpszNext = (LPWSTR)(lpNROut + 1);
FromEnd = (PWCHAR) ( ( (PBYTE)lpNROut ) + BufferSizeRemaining );
cRequested = *lpcCount;
*lpcCount = 0;
if ( (DavEnumNode->DavEnumNodeType == DAV_ENUMNODE_TYPE_SERVER) &&
(DavEnumNode->lpNetResource == NULL ||
DavEnumNode->lpNetResource->lpRemoteName == NULL) ) {
//
// Return the list of servers that are accessed from this machine.
// Make sure that only servers accessed from a user's view
// should be shown.
NPStatus = DavBindTheRpcHandle( &(dav_binding_h) );
if (NPStatus != ERROR_SUCCESS) {
IF_DEBUG_PRINT(DEBUG_ERRORS,
("ERROR: NPEnumResource/DavBindTheRpcHandle. "
"NPStatus = %08lx\n", NPStatus));
NPStatus = WN_NO_NETWORK;
goto EXIT_THE_FUNCTION;
}
RpcBindSucceeded = TRUE;
do {
//
// If we have already filled in the requested number, we are done.
// If NumRequested was 0xFFFFFFFF then we try to return as many
// entries as we can.
//
if ( cRequested != ((DWORD)-1 )&& *lpcCount >= cRequested ) {
NPStatus = WN_SUCCESS;
DavEnumNode->Done = TRUE;
goto EXIT_THE_FUNCTION;
}
Index = DavEnumNode->Index;
RpcTryExcept {
NPStatus = DavrEnumServers(dav_binding_h, &(Index), &(RemoteName), &(AreWeDone));
if (NPStatus != NO_ERROR) {
IF_DEBUG_PRINT(DEBUG_ERRORS,
("ERROR: NPEnumResource/DavrEnumServers. NPStatus = "
"%08lx\n", NPStatus));
goto EXIT_THE_FUNCTION;
}
} RpcExcept (I_RpcExceptionFilter(RpcExceptionCode())) {
RPC_STATUS RpcStatus;
RpcStatus = RpcExceptionCode();
IF_DEBUG_PRINT(DEBUG_ERRORS, ("ERROR: NPEnumResource/DavrEnumServers."
" RpcExceptionCode = %d\n", RpcStatus));
NPStatus = DavMapRpcErrorToProviderError(RpcStatus);
goto EXIT_THE_FUNCTION;
}
RpcEndExcept
//
// Don't change the if below to if (AreWeDone) because the RPC call
// can fill in some +ve value in AreWeDone. So the check should be
// if ( AreWeDone == TRUE ).
//
if ( AreWeDone == TRUE ) {
if ( *lpcCount == 0 ) {
//
// No net uses at all.
//
NPStatus = WN_NO_MORE_ENTRIES;
DavEnumNode->Done = TRUE;
} else {
NPStatus = WN_SUCCESS;
DavEnumNode->Done = TRUE;
}
goto EXIT_THE_FUNCTION;
}
IF_DEBUG_PRINT(DEBUG_MISC, ("NPEnumResource: ServerName = %ws\n", RemoteName));
RemoteNameLength = wcslen(RemoteName) + 1;
DisplayNameLength = wcslen(DavClientDisplayName) + 1;
//
// We need to see if the (remaining) buffer size is large enough to
// hold this entry.
//
//
// Calculate the total length needed for this entry in bytes.
//
EntryLengthNeededInBytes = ( sizeof(NETRESOURCEW) +
( RemoteNameLength * sizeof(WCHAR) ) +
( DisplayNameLength * sizeof(WCHAR) ) );
//
// If the value of BufferSizeRemaining is less than the value of
// EntryLengthNeededInBytes for this entry we do one of two things.
// If we have already filled atleast one entry into the buffer,
// we return success, but if we could not even fill in one entry,
// we return WN_MORE_DATA with BufferSize set to the size in bytes
// needed to fill in this entry.
//
if ( BufferSizeRemaining < EntryLengthNeededInBytes ) {
if ( *lpcCount == 0 ) {
IF_DEBUG_PRINT(DEBUG_ERRORS,
("ERROR: NPEnumResource: NPStatus = WN_MORE_DATA. "
"Supplied=%d, Required=%d\n",
BufferSizeRemaining, EntryLengthNeededInBytes));
NPStatus = WN_MORE_DATA;
*lpBufferSize = EntryLengthNeededInBytes;
goto EXIT_THE_FUNCTION;
} else {
NPStatus = WN_SUCCESS;
goto EXIT_THE_FUNCTION;
}
}
//
// If we've come till here, it means that the BufferSizeRemaining
// is large enough to hold this entry. So fill it in the buffer.
//
ZeroMemory(lpNROut, sizeof(NETRESOURCEW));
lpNROut->lpComment = NULL;
lpNROut->dwScope = RESOURCE_GLOBALNET;
//
// Fill in the DisplayName.
//
FromEnd -= DisplayNameLength;
wcscpy(FromEnd, DavClientDisplayName);
lpNROut->lpProvider = FromEnd;
//
// When we are enumerating servers, we don't have a LocalName.
//
lpNROut->lpLocalName = NULL;
//
// Fill in the RemoteName.
//
FromEnd -= RemoteNameLength;
wcscpy(FromEnd, RemoteName);
lpNROut->lpRemoteName = FromEnd;
lpNROut->dwType = RESOURCETYPE_DISK;
lpNROut->dwDisplayType = RESOURCEDISPLAYTYPE_SERVER;
lpNROut->dwUsage = DavDisplayTypeToUsage(lpNROut->dwDisplayType);
BufferSizeRemaining -= EntryLengthNeededInBytes;
//
// Note: Do not change Index, it is updated inside the rpc
// function (DavrEnumServers).
//
DavEnumNode->Index = Index;
//
// Increment the count of the number of items returned.
//
(*lpcCount)++;
DavDisplayNetResource(lpNROut, L"lpNROut in NPEnumResources(0)");
//
// lpNROut now needs to point to the next item in the array.
//
lpNROut = (LPNETRESOURCE)lpszNext;
lpszNext = (PWCHAR)(lpNROut + 1);
//
// The memory for RemoteName was allocated by the RPC client stub
// based on the string returned by the RPC server. We need to free
// it now since we're done using it.
//
MIDL_user_free(RemoteName);
RemoteName = NULL;
} while (TRUE);
} else if (DavEnumNode->DavEnumNodeType == DAV_ENUMNODE_TYPE_SHARE &&
DavEnumNode->lpNetResource != NULL &&
DavEnumNode->lpNetResource->lpRemoteName != NULL) {
//
// Return list of shares for given UNC server name.
//
//
// Allocate Memory for ServerName
//
ServerNameMaxLen = (MAX_PATH + 1);
ServerName = LocalAlloc(LPTR, (ServerNameMaxLen * sizeof(WCHAR)));
if (ServerName == NULL ) {
NPStatus = GetLastError();
IF_DEBUG_PRINT(DEBUG_ERRORS,
("ERROR: NPEnumResource/LocalAlloc. NPStatus = %08lx\n", NPStatus));
goto EXIT_THE_FUNCTION;
}
ServerNameAllocated = TRUE;
//
// Note: The remotename here is already converted to valid UNC
// form in NPOpenEnum function.
//
SrvExists = DavServerExists(DavEnumNode->lpNetResource->lpRemoteName,
ServerName);
if ( !SrvExists ) {
NPStatus = WN_BAD_HANDLE;
IF_DEBUG_PRINT(DEBUG_ERRORS,
("ERROR: NPEnumResource/DavServerExists.NPStatus = %d\n",
NPStatus));
goto EXIT_THE_FUNCTION;
}
ServerName[(ServerNameMaxLen - 1)] = L'\0';
NPStatus = DavBindTheRpcHandle( &(dav_binding_h) );
if (NPStatus != ERROR_SUCCESS) {
IF_DEBUG_PRINT(DEBUG_ERRORS,
("ERROR: NPEnumResource/DavBindTheRpcHandle. NPStatus = %08lx\n",
NPStatus));
NPStatus = WN_NO_NETWORK;
goto EXIT_THE_FUNCTION;
}
RpcBindSucceeded = TRUE;
do {
//
// If we have already filled in the requested number, we are done.
// If NumRequested was 0xFFFFFFFF then we try to return as many
// entries as we can.
//
if ( cRequested != ((DWORD)-1 )&& *lpcCount >= cRequested ) {
NPStatus = WN_SUCCESS;
DavEnumNode->Done = TRUE;
goto EXIT_THE_FUNCTION;
}
Index = DavEnumNode->Index;
//
// BUGBUG: We can support enumeration of resources on server. Beside this
// , we can also support the enumeration of the shares - but we are not doing that
// for now.
//
RpcTryExcept {
NPStatus = DavrEnumShares(dav_binding_h, &(Index), ServerName, &(RemoteName), &(AreWeDone));
if (NPStatus != NO_ERROR) {
IF_DEBUG_PRINT(DEBUG_ERRORS,
("ERROR: NPEnumResource/DavrEnumShares. NPStatus = "
"%08lx\n", NPStatus));
goto EXIT_THE_FUNCTION;
}
} RpcExcept (I_RpcExceptionFilter(RpcExceptionCode())) {
RPC_STATUS RpcStatus;
RpcStatus = RpcExceptionCode();
IF_DEBUG_PRINT(DEBUG_ERRORS, ("ERROR: NPEnumResource/DavrEnumShares."
" RpcExceptionCode = %d\n", RpcStatus));
NPStatus = DavMapRpcErrorToProviderError(RpcStatus);
goto EXIT_THE_FUNCTION;
}
RpcEndExcept
//
// Don't change the if below to if (AreWeDone) because the RPC call
// can fill in some +ve value in AreWeDone. So the check should be
// if ( AreWeDone == TRUE ).
//
if ( AreWeDone == TRUE ) {
if ( *lpcCount == 0 ) {
//
// No net uses at all.
//
NPStatus = WN_NO_MORE_ENTRIES;
DavEnumNode->Done = TRUE;
} else {
NPStatus = WN_SUCCESS;
DavEnumNode->Done = TRUE;
}
goto EXIT_THE_FUNCTION;
}
IF_DEBUG_PRINT(DEBUG_MISC, ("NPEnumResource: ShareName = %ws\n", RemoteName));
RemoteNameLength = wcslen(RemoteName) + 1;
DisplayNameLength = wcslen(DavClientDisplayName) + 1;
//
// We need to see if the (remaining) buffer size is large enough to
// hold this entry.
//
//
// Calculate the total length needed for this entry in bytes.
//
EntryLengthNeededInBytes = ( sizeof(NETRESOURCEW) +
( RemoteNameLength * sizeof(WCHAR) ) +
( DisplayNameLength * sizeof(WCHAR) ) );
//
// If the value of BufferSizeRemaining is less than the value of
// EntryLengthNeededInBytes for this entry we do one of two things.
// If we have already filled atleast one entry into the buffer,
// we return success, but if we could not even fill in one entry,
// we return WN_MORE_DATA with BufferSize set to the size in bytes
// needed to fill in this entry.
//
if ( BufferSizeRemaining < EntryLengthNeededInBytes ) {
if ( *lpcCount == 0 ) {
IF_DEBUG_PRINT(DEBUG_ERRORS,
("ERROR: NPEnumResource: NPStatus = WN_MORE_DATA."
"Supplied=%d, Required=%d\n",
BufferSizeRemaining, EntryLengthNeededInBytes));
NPStatus = WN_MORE_DATA;
*lpBufferSize = EntryLengthNeededInBytes;
goto EXIT_THE_FUNCTION;
} else {
NPStatus = WN_SUCCESS;
goto EXIT_THE_FUNCTION;
}
}
//
// If we've come till here, it means that the BufferSizeRemaining
// is large enough to hold this entry. So fill it in the buffer.
//
ZeroMemory(lpNROut, sizeof(NETRESOURCEW));
lpNROut->lpComment = NULL;
lpNROut->dwScope = RESOURCE_SHAREABLE;
//
// Fill in the DisplayName.
//
FromEnd -= DisplayNameLength;
wcscpy(FromEnd, DavClientDisplayName);
lpNROut->lpProvider = FromEnd;
//
// When we are enumerating shares, we don't have a LocalName.
//
lpNROut->lpLocalName = NULL;
//
// Fill in the RemoteName.
//
FromEnd -= RemoteNameLength;
wcscpy(FromEnd, RemoteName);
lpNROut->lpRemoteName = FromEnd;
lpNROut->dwType = RESOURCETYPE_DISK;
lpNROut->dwDisplayType = RESOURCEDISPLAYTYPE_SHARE;
lpNROut->dwUsage = DavDisplayTypeToUsage(lpNROut->dwDisplayType);
BufferSizeRemaining -= EntryLengthNeededInBytes;
//
// Increment the index to point to the next entry to be returned.
//
(DavEnumNode->Index)++;
//
// Increment the count of the number of items returned.
//
(*lpcCount)++;
DavDisplayNetResource(lpNROut, L"lpNROut in NPEnumResources(1)");
//
// lpNROut now needs to point to the next item in the array.
//
lpNROut = (LPNETRESOURCE)lpszNext;
lpszNext = (PWCHAR)(lpNROut + 1);
//
// The memory for RemoteName was allocated by the RPC client stub
// based on the string returned by the RPC server. We need to free
// it now since we're done using it.
//
MIDL_user_free(RemoteName);
RemoteName = NULL;
} while (TRUE);
} else if (DavEnumNode->DavEnumNodeType == DAV_ENUMNODE_TYPE_USE) {
//
// Allocate Memory for ServerName
//
ServerNameMaxLen = (MAX_PATH + 1);
ServerName = LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT, ServerNameMaxLen*sizeof(WCHAR));
if (ServerName == NULL ) {
NPStatus = GetLastError();
IF_DEBUG_PRINT(DEBUG_ERRORS,
("ERROR: NPEnumResource/LocalAlloc. NPStatus = %08lx\n", NPStatus));
goto EXIT_THE_FUNCTION;
}
ServerNameAllocated = TRUE;
NPStatus = DavBindTheRpcHandle( &(dav_binding_h) );
if (NPStatus != ERROR_SUCCESS) {
IF_DEBUG_PRINT(DEBUG_ERRORS,
("ERROR: NPEnumResource/DavBindTheRpcHandle. "
"NPStatus = %08lx\n", NPStatus));
NPStatus = WN_NO_NETWORK;
goto EXIT_THE_FUNCTION;
}
RpcBindSucceeded = TRUE;
do {
//
// If we have already filled in the requested number, we are done.
// If NumRequested was 0xFFFFFFFF then we try to return as many
// entries as we can.
//
if ( cRequested != ((DWORD)-1) && *lpcCount >= cRequested ) {
NPStatus = WN_SUCCESS;
DavEnumNode->Done = TRUE;
goto EXIT_THE_FUNCTION;
}
Index = DavEnumNode->Index;
RpcTryExcept {
NPStatus = DavrEnumNetUses(dav_binding_h, &(Index), &(LocalName), &(RemoteName), &(AreWeDone));
if (NPStatus != NO_ERROR) {
IF_DEBUG_PRINT(DEBUG_ERRORS,
("ERROR: NPEnumResource/DavrEnumNetUses. NPStatus = "
"%08lx\n", NPStatus));
goto EXIT_THE_FUNCTION;
}
} RpcExcept (I_RpcExceptionFilter(RpcExceptionCode())) {
RPC_STATUS RpcStatus;
RpcStatus = RpcExceptionCode();
IF_DEBUG_PRINT(DEBUG_ERRORS, ("ERROR: NPEnumResource/DavrEnumNetUses."
" RpcExceptionCode = %d\n", RpcStatus));
NPStatus = DavMapRpcErrorToProviderError(RpcStatus);
goto EXIT_THE_FUNCTION;
}
RpcEndExcept
//
// Don't change the if below to if (AreWeDone) because the RPC call
// can fill in some +ve value in AreWeDone. So the check should be
// if ( AreWeDone == TRUE ).
//
if ( AreWeDone == TRUE ) {
if ( *lpcCount == 0 ) {
//
// No net uses at all.
//
NPStatus = WN_NO_MORE_ENTRIES;
DavEnumNode->Done = TRUE;
} else {
NPStatus = WN_SUCCESS;
DavEnumNode->Done = TRUE;
}
goto EXIT_THE_FUNCTION;
}
IF_DEBUG_PRINT(DEBUG_MISC,
("NPEnumResource: LocalName = %ws, RemoteName = %ws\n",
LocalName, RemoteName));
//
// The LocalName may or may not exist. If the user does
// net use \\server\share, there is no local name.
//
if (LocalName == NULL) {
LocalNameLength = 0;
} else {
LocalNameLength = wcslen(LocalName) + 1;
if (LocalNameLength == 1) {
LocalNameLength = 0;
}
}
RemoteNameLength = wcslen(RemoteName) + 1;
DisplayNameLength = wcslen(DavClientDisplayName) + 1;
//
// We need to see if the (remaining) buffer size is large enough to
// hold this entry.
//
//
// Calculate the total length needed for this entry in bytes.
//
EntryLengthNeededInBytes = ( sizeof(NETRESOURCEW) +
( LocalNameLength * sizeof(WCHAR) ) +
( RemoteNameLength * sizeof(WCHAR) ) +
( DisplayNameLength * sizeof(WCHAR) ) );
//
// If the value of BufferSizeRemaining is less than the value of
// EntryLengthNeededInBytes for this entry we do one of two things.
// If we have already filled atleast one entry into the buffer,
// we return success, but if we could not even fill in one entry,
// we return WN_MORE_DATA with BufferSize set to the size in bytes
// needed to fill in this entry.
//
if ( BufferSizeRemaining < EntryLengthNeededInBytes ) {
if ( *lpcCount == 0 ) {
IF_DEBUG_PRINT(DEBUG_ERRORS,
("ERROR: NPEnumResource: NPStatus = WN_MORE_DATA\n"));
NPStatus = WN_MORE_DATA;
*lpBufferSize = EntryLengthNeededInBytes;
goto EXIT_THE_FUNCTION;
} else {
NPStatus = WN_SUCCESS;
goto EXIT_THE_FUNCTION;
}
}
ZeroMemory(lpNROut, sizeof(NETRESOURCEW));
//
// If we've come till here, it means that the BufferSizeRemaining
// is large enough to hold this entry. So fill it in the buffer.
//
lpNROut->lpComment = NULL;
lpNROut->dwScope = RESOURCE_CONNECTED;
//
// Fill in the DisplayName.
//
FromEnd -= DisplayNameLength;
wcscpy(FromEnd, DavClientDisplayName);
lpNROut->lpProvider = FromEnd;
//
// Fill in the LocalName if one exists.
//
if ( LocalNameLength != 0 ) {
FromEnd -= LocalNameLength;
wcscpy(FromEnd, LocalName);
lpNROut->lpLocalName = FromEnd;
}
//
// Fill in the RemoteName.
//
FromEnd -= RemoteNameLength;
wcscpy(FromEnd, RemoteName);
lpNROut->lpRemoteName = FromEnd;
lpNROut->dwType = RESOURCETYPE_DISK;
lpNROut->dwDisplayType = RESOURCEDISPLAYTYPE_SHARE;
lpNROut->dwUsage = DavDisplayTypeToUsage(lpNROut->dwDisplayType);
BufferSizeRemaining -= EntryLengthNeededInBytes;
//
// Increment the index to point to the next entry to be returned.
//
(DavEnumNode->Index)++;
//
// Increment the count of the number of items returned.
//
(*lpcCount)++;
DavDisplayNetResource(lpNROut, L"lpNROut in NPEnumResources(1)");
//
// lpNROut now needs to point to the next item in the array.
//
lpNROut = (LPNETRESOURCE)lpszNext;
lpszNext = (PWCHAR)(lpNROut + 1);
//
// The memory for RemoteName was allocated by the RPC client stub
// based on the string returned by the RPC server. We need to free
// it now since we're done using it.
//
MIDL_user_free(RemoteName);
RemoteName = NULL;
MIDL_user_free(LocalName);
LocalName = NULL;
} while ( TRUE );
} else {
IF_DEBUG_PRINT(DEBUG_ERRORS,
("ERROR: NPEnumResource: DavEnumNodeType = %d\n",
DavEnumNode->DavEnumNodeType));
NPStatus = WN_BAD_HANDLE;
goto EXIT_THE_FUNCTION;
}
EXIT_THE_FUNCTION:
//
// If RPC binding was successfully done, we need to free it now.
//
if (RpcBindSucceeded) {
RpcBindingFree( &(dav_binding_h) );
RpcBindSucceeded = FALSE;
}
if (ServerNameAllocated == TRUE && ServerName != NULL) {
LocalFree((HLOCAL)ServerName);
ServerName = NULL;
ServerNameAllocated = FALSE;
}
//
// The memory for RemoteName was allocated by the RPC client stub
// based on the string returned by the RPC server. We need to free
// it now if we came down an error path after calling the server.
//
if (RemoteName != NULL) {
MIDL_user_free(RemoteName);
RemoteName = NULL;
}
//
// The memory for LocalName was allocated by the RPC client stub
// based on the string returned by the RPC server. We need to free
// it now if we came down an error path after calling the server.
//
if (LocalName != NULL) {
MIDL_user_free(LocalName);
LocalName = NULL;
}
IF_DEBUG_PRINT(DEBUG_EXIT, ("NPEnumResource: NPStatus = %d\n", NPStatus));
DavDebugBreakPoint();
return NPStatus;
}
DWORD
NPCloseEnum (
HANDLE hEnum
)
/*++
Routine Description:
This routine closes an enumeration and frees up the resources.
Arguments:
hEnum - This must be a handle obtained from NPOpenEnum call.
Return Value:
WN_SUCCESS - If the call is successful. Otherwise, an error code is returned,
which may include:
WN_NO_NETWORK - Network is not present. This condition is checked for before
hEnum is tested for validity.
WN_BAD_HANDLE - hEnum is not a valid handle.
--*/
{
DWORD NPStatus = WN_SUCCESS;
PDAV_ENUMNODE DavEnumNode;
HLOCAL Handle;
IF_DEBUG_PRINT(DEBUG_ENTRY, ("NPCloseEnum: hEnum = %08lx\n", hEnum));
DavEnumNode = (PDAV_ENUMNODE)hEnum;
DavDisplayEnumNode(DavEnumNode, L"DavEnumNode in NPCloseEnum");
//
// If the hEnum sent in was NULL, we return right away.
//
if (DavEnumNode == NULL) {
return NPStatus;
}
if (DavEnumNode->lpNetResource) {
if (DavEnumNode->lpNetResource->lpRemoteName) {
//
// Free the memory we allocated for the RemoteName in NPOpenEnum.
//
Handle = LocalFree(DavEnumNode->lpNetResource->lpRemoteName);
if (Handle != NULL) {
NPStatus = GetLastError();
IF_DEBUG_PRINT(DEBUG_ERRORS, ("ERROR: NPCloseEnum/LocalFree: NPStatus ="
" %08lx\n", NPStatus));
}
DavEnumNode->lpNetResource->lpRemoteName = NULL;
}
//
// Free the memory we allocated for the NetResource in NPOpenEnum.
//
Handle = LocalFree(DavEnumNode->lpNetResource);
if (Handle != NULL) {
NPStatus = GetLastError();
IF_DEBUG_PRINT(DEBUG_ERRORS, ("ERROR: NPCloseEnum/LocalFree: NPStatus ="
" %08lx\n", NPStatus));
}
DavEnumNode->lpNetResource = NULL;
}
//
// Finally, free the DavEnumNode.
//
Handle = LocalFree(DavEnumNode);
if (Handle != NULL) {
NPStatus = GetLastError();
IF_DEBUG_PRINT(DEBUG_ERRORS, ("ERROR: NPCloseEnum/LocalFree: NPStatus ="
" %08lx\n", NPStatus));
}
DavEnumNode = NULL;
IF_DEBUG_PRINT(DEBUG_EXIT, ("NPCloseEnum: NPStatus = %d\n", NPStatus));
DavDebugBreakPoint();
return NPStatus;
}
DWORD
NPGetResourceInformation(
LPNETRESOURCE lpNetResource,
LPVOID lpBuffer,
LPDWORD lpcbBuffer,
LPTSTR *lplpSystem
)
/*++
Routine Description:
NPGetResourceInformation determines whether this provider is the right
provider to respond to a request for a specified network resource, and
returns information about the resource's type. This routine closes an
enumeration and frees up the resources.
Arguments:
lpNetResource - Specifies the network resource for which information is
required. The lpRemoteName field specifies the remote name
of the resource. The calling program should fill in the
values for the lpProvider and dwType fields if it knows
them; otherwise, it should set them to NULL. All other
fields in the NETRESOURCE are ignored and are not initialized.
If the lpRemoteName string contains a portion that is
accessed through WNet APIs and a portion that is accessed
through other system APIs specific to the resource type,
the function should only return information about the
network portion of the resource (except for lplpSystem as
described below). For example, if the resource is
"\\server\share\dir1\dir2" where "\\server\share" is
accessed through WNet APIs and "\dir1\dir2" is accessed
through file system APIs, the provider should verify that it
is the right provider for "\\server\share", but need not
check whether "\dir1\dir2" actually exists.
lpBuffer - A pointer to the buffer to receive the result. The first field in
the result is a single NETRESOURCE structure (and associated
strings) representing that portion of the input resource that is
accessed through WNet APIs, rather than system APIs specific to
the resource type. (For example, if the input remote resource
name was "\\server\share\dir1\dir2", then the output NETRESOURCE
contains information about the resource "\\server\share"). The
lpRemoteName, lpProvider, dwType, dwDisplayType and dwUsage
fields are returned, all other fields being set to NULL.
lpRemoteName should be returned in the same syntax as that
returned from an enumeration by the NPEnumResource function, so
that the caller can perform a case sensitive string comparison to
determine whether the output network resource is the same as one
returned by NPEnumResource. The provider should not do purely
syntactic checking to determine whether it owns the resource, as
this could produce incorrect results when two networks are running
on the client and the provider doing syntactic checking is called
first.
lpcbBuffer - Points to a location that specifies the size, in bytes, of the
buffer pointed to by lpBuffer. If the buffer is too small for
the result, the function places the required buffer size at
this location and returns the error WN_MORE_DATA.
lplpSystem - On a successful return, points to a string in the output buffer
that specifies the part of the resource that is accessed through
system APIs specific to the resource type rather than WNet APIs.
If there is no such part, lplpSystem is set to NULL. 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. Otherwise, an error code is returned,
which may include:
WN_MORE_DATA - Input buffer is too small.
WN_BAD_NETNAME - The resource is not recognized by this provider.
WN_BAD_VALUE - Invalid dwUsage or dwType.
WN_BAD_DEV_TYPE - The caller passed in a non-zero dwType that does not match
the actual type of the network resource.
WN_NOT_AUTHENTICATED - The caller has not been authenticated to the network.
WN_ACCESS_DENIED - The caller has been authenticated to the network, but
does not have sufficient permissions (access rights).
--*/
{
ULONG NPStatus = WN_SUCCESS;
BOOL fExists = FALSE;
DWORD iBackslash = 0;
LPNETRESOURCEW lpNROut = NULL;
LPWSTR lpszNext = NULL;
DWORD cbNeeded = 0, dwDisplayType = 0, cbProvider = 0, cbRemote = 0;
PWCHAR RemoteName = NULL;
BOOLEAN didAllocate = FALSE;
DAV_REMOTENAME_TYPE remNameType = DAV_REMOTENAME_TYPE_INVALID;
PWCHAR PathPtr = NULL;
DWORD cbPath = 0;
IF_DEBUG_PRINT(DEBUG_ENTRY, ("NPGetResourceInformation.\n"));
DavDisplayNetResource(lpNetResource, L"lpNetResource in NPGetResourceInformation");
//
// If the WebClient service is not running we bail out right away.
//
if ( !DavWorkstationStarted() ) {
IF_DEBUG_PRINT(DEBUG_ERRORS,
("ERROR: NPGetResourceInformation/DavWorkstationStarted. "
"Service NOT Running\n"));
NPStatus = WN_NO_NETWORK;
goto EXIT_THE_FUNCTION;
}
//
// Validate the parameters passed to the function.
//
if ( lpNetResource == NULL ||
lpNetResource->lpRemoteName == NULL ||
lpcbBuffer == NULL ||
lplpSystem == NULL ||
(lpBuffer == NULL && *lpcbBuffer != 0) ) {
NPStatus = WN_BAD_VALUE;
IF_DEBUG_PRINT(DEBUG_ERRORS,
("ERROR: NPGetResourceInformation(1). NPStatus = %d.\n",
NPStatus));
goto EXIT_THE_FUNCTION;
}
//
// Check if dwType is set and is set to some valid value.
// It can be only of type RESOURCETYPE_DISK for our provider.
//
NPStatus = DavCheckResourceType(lpNetResource->dwType);
if (NPStatus != WN_SUCCESS) {
IF_DEBUG_PRINT(DEBUG_ERRORS,
("ERROR: NPGetResourceInformation(2). NPStatus=%d.\n", NPStatus));
goto EXIT_THE_FUNCTION;
}
//
// Initialize local variables.
//
cbNeeded = sizeof(NETRESOURCEW);
lpNROut = (LPNETRESOURCEW)lpBuffer;
lpszNext = lpBuffer == NULL? NULL : (LPWSTR)(lpNROut + 1);
IF_DEBUG_PRINT(DEBUG_MISC,
("NPGetResourceInformation: lpRemoteName = %ws.\n",
lpNetResource->lpRemoteName));
//
// Check remote name passed to this function - and convert it to UNC name
// if it is in URL form. After converting to UNC name - canonicalize it
// which checks for validity of UNC name more strictly.
//
NPStatus = DavCheckAndConvertHttpUrlToUncName(lpNetResource->lpRemoteName,
&(RemoteName),
&(didAllocate),
FALSE,
&remNameType,
&(iBackslash),
TRUE);
if (NPStatus != ERROR_SUCCESS) {
IF_DEBUG_PRINT(DEBUG_ERRORS,
("ERROR: NPGetResourceInformation/DavCheckAndConvertHttpUrlToUncName."
" NPStatus = %08lx\n", NPStatus));
goto EXIT_THE_FUNCTION;
}
NPStatus = WN_SUCCESS;
IF_DEBUG_PRINT(DEBUG_MISC,
("NPGetResourceInformation: RemoteName = %ws, NameType=%d\n",
RemoteName, remNameType));
//
// Remote name is successfully converted to a valid UNC form. It is either a
// UNC-server name (this is added with DUMMY share), or UNC-share name or UNC-path name.
//
//
// Set a few default values.
//
if ( *lpcbBuffer >= cbNeeded ) {
ZeroMemory(lpNROut, sizeof(NETRESOURCEW));
}
*lplpSystem = NULL;
switch (remNameType) {
case DAV_REMOTENAME_TYPE_SERVER: {
//
// RemoteName = \\server
//
fExists = DavServerExists(RemoteName, NULL);
dwDisplayType = RESOURCEDISPLAYTYPE_SERVER;
break;
}
case DAV_REMOTENAME_TYPE_PATH: {
//
// RemoteName = \\server\share\path
//
//
// Set the lplpSystem pointer.
//
PathPtr = (RemoteName + iBackslash);
cbPath = ( ( 1 + wcslen(PathPtr) ) * sizeof(WCHAR) );
cbNeeded += cbPath;
if (*lpcbBuffer >= cbNeeded ) {
*lplpSystem = lpszNext;
wcscpy(*lplpSystem, PathPtr);
lpszNext += ( cbPath / sizeof(WCHAR));
}
//
// Fall through.
//
}
case DAV_REMOTENAME_TYPE_SHARE: {
//
// RemoteName = \\server\share
//
//
// Control comes here for both cases - when remote name is of type
// UNC-share or UNC-path AND
// when remote name is or type UNC-server. DUMMYShare is added to it
// above - making it of UNC-share form (\\server\DUMMYShare).
//
fExists = DavShareExists(RemoteName);
dwDisplayType = RESOURCEDISPLAYTYPE_SHARE;
break;
}
default:{
//
// Control should not come here. DavCheckAndConvertHttpUrlToUncName
// returns successful only for valid cases considered above.
//
ASSERT(FALSE);
IF_DEBUG_PRINT(DEBUG_ERRORS, ("ERROR: NPGetResourceInformation: Invalid "
"DavRemoteNameType = %d\n", remNameType));
NPStatus = WN_BAD_NETNAME;
goto EXIT_THE_FUNCTION;
}
}
//
// UNC - server/share do not exists - quit with error.
//
if (fExists == FALSE) {
if (remNameType == DAV_REMOTENAME_TYPE_SERVER) {
IF_DEBUG_PRINT(DEBUG_ERRORS, ("ERROR: NPGetResourceInformation: Server in"
" path %ws does not do DAV\n", RemoteName));
} else {
//
// remNameType = DAV_REMOTENAME_TYPE_SHARE
//
IF_DEBUG_PRINT(DEBUG_ERRORS, ("ERROR: NPGetResourceInformation: Share in"
" path %ws does not exist\n", RemoteName));
}
NPStatus = WN_BAD_NETNAME;
goto EXIT_THE_FUNCTION;
}
//
// Server/Share given in lpRemoteName exists.
//
//
// Set the lpProvider pointer.
//
cbProvider = ( (1 + wcslen(DavClientDisplayName) ) * sizeof(WCHAR) );
cbNeeded += cbProvider;
if (*lpcbBuffer >= cbNeeded ) {
lpNROut->lpProvider = lpszNext;
wcscpy(lpNROut->lpProvider, DavClientDisplayName);
lpszNext += ( cbProvider / sizeof(WCHAR) );
}
//
// Set the lpRemoteName pointer. If iBackslash (=offset of \dir portion in
// \\server\share\dir...) is > 0, then the lpRemoteName that was sent has
// the form \\server\share\dir... .
// If it is = 0, then the RemoteName form is \\server\share or \\server.
//
if (iBackslash > 0) {
//
// RemoteName = \\server\share\dir
// ^
// |
// iBackslash
cbRemote = ( (1 + iBackslash) * sizeof(WCHAR) );
cbNeeded += cbRemote;
if ( *lpcbBuffer >= cbNeeded ) {
lpNROut->lpRemoteName = lpszNext;
RtlCopyMemory( lpNROut->lpRemoteName, RemoteName, (iBackslash * sizeof(WCHAR)) );
lpNROut->lpRemoteName[iBackslash] = L'\0';
lpszNext += ( cbRemote / sizeof(WCHAR) );
}
} else {
//
// RemoteName = \\server\share or \\server
//
cbRemote = ( ( 1 + wcslen(RemoteName) ) * sizeof(WCHAR) );
cbNeeded += cbRemote;
if (*lpcbBuffer >= cbNeeded ) {
lpNROut->lpRemoteName = lpszNext;
wcscpy(lpNROut->lpRemoteName, RemoteName);
lpszNext += ( cbRemote / sizeof(WCHAR) );
}
}
if ( *lpcbBuffer >= cbNeeded ) {
//
// All data is filled and supplied buffer is long enough to contain it.
//
lpNROut->dwType = RESOURCETYPE_DISK;
lpNROut->dwDisplayType = dwDisplayType;
lpNROut->dwUsage = DavDisplayTypeToUsage(lpNROut->dwDisplayType);
NPStatus = WN_SUCCESS;
DavDisplayNetResource(lpNROut, L"lpNROut in NPGetResourceInformation");
goto EXIT_THE_FUNCTION;
} else {
IF_DEBUG_PRINT(DEBUG_ERRORS,
("ERROR: NPGetResourceInformation: Need more "
"buffer space. Supplied = %d, Required = %d\n",
*lpcbBuffer, cbNeeded));
*lpcbBuffer = cbNeeded;
NPStatus = WN_MORE_DATA;
goto EXIT_THE_FUNCTION;
}
EXIT_THE_FUNCTION:
//
// If RemoteName != NULL && didAllocate == TRUE, then we did allocate memory
// for the RemoteName field.
//
if (RemoteName != NULL && didAllocate == TRUE) {
LocalFree(RemoteName);
RemoteName = NULL;
didAllocate = FALSE;
}
IF_DEBUG_PRINT(DEBUG_EXIT, ("NPGetResourceInformation: NPStatus = %d\n", NPStatus));
DavDebugBreakPoint();
return NPStatus;
}
DWORD
NPGetResourceParent(
LPNETRESOURCE lpNetResource,
LPVOID lpBuffer,
LPDWORD lpcbBuffer
)
/*++
Routine Description:
NPGetResourceParent returns the parent of a specified network resource in
the browse hierarchy. This function is typically called for resources that
were returned by the same provider from prior calls to NPEnumResource or
NPGetResourceInformation.
Arguments:
lpNetResource - This specifies the network resource whose parent name is
required. The NETRESOURCE could have been obtained via a
previous call to NPEnumResource or NPGetResourceInformation,
or constructed by the caller. The lpRemoteName field
specifies the remote name of the network resource whose
parent is required. The lpProvider field specifies the
provider to call. This must be supplied. The dwType field is
filled in if the calling program knows its value, otherwise
it is set to NULL. All other fields in the NETRESOURCE are
ignored and are not initialized.
lpBuffer - Points to a buffer to receive the result, which is a single
NETRESOURCE structure representing the parent resource. The
lpRemoteName, lpProvider, dwType, dwDisplayType and dwUsage
fields are returned; all other fields are set to NULL. The output
lpRemoteName should be in the same syntax as that returned from
an enumeration by NPEnumResource, so that the caller can perform
a case sensitive string comparison to determine whether the
parent resource is the same as one returned by NPEnumResource.
If the input resource syntactically has a parent, the provider
can return it, without determining whether the input resource or
its parent actually exist. If a resource has no browse parent on
the network, then lpRemoteName is returned as NULL. The
RESOURCEUSAGE_CONNECTABLE bit in the returned dwUsage field does
not necessarily indicate that the resource can currently be
connected to, only that the resource is connectable when it is
available on the network.
lpcbBuffer - Points to a location that specifies the size, in bytes, of the
buffer pointed to by lpBuffer. If the buffer is too small for
the result, the function places the required buffer size at
this location and returns the error WN_MORE_DATA.
Return Value:
WN_SUCCESS - If the call is successful.
WN_MORE_DATA - If input buffer is too small.
WN_BAD_NETNAME - This provider does not own the resource specified by
lpNetResource (or the resource is syntactically invalid).
WN_BAD_VALUE - Invalid dwUsage or dwType, or bad combination of parameters
is specified (e.g. lpRemoteName is syntactically invalid for
dwType).
WN_NOT_AUTHENTICATED - The caller has not been authenticated to the network.
WN_ACCESS_DENIED - The caller has been authenticated to the network, but
does not have sufficient permissions (access rights).
--*/
{
ULONG NPStatus = WN_SUCCESS;
ULONG iBackslash = 0;
LPNETRESOURCEW lpNROut = NULL;
LPWSTR lpszNext = NULL;
DWORD cbNeeded = 0, dwDisplayType = 0, cbProvider = 0;
PWCHAR RemoteName = NULL;
BOOLEAN didAllocate = FALSE;
DAV_REMOTENAME_TYPE remNameType = DAV_REMOTENAME_TYPE_INVALID;
IF_DEBUG_PRINT(DEBUG_ENTRY, ("NPGetResourceParent\n"));
DavDisplayNetResource(lpNetResource, L"lpNetResource in NPGetResourceParent");
//
// If the WebClient service is not running we bail out right away.
//
if ( !DavWorkstationStarted() ) {
IF_DEBUG_PRINT(DEBUG_ERRORS,
("ERROR: NPGetResourceParent/DavWorkstationStarted. "
"Service NOT Running\n"));
NPStatus = WN_NO_NETWORK;
goto EXIT_THE_FUNCTION;
}
//
// Check for validity of the parameters passed to this function.
//
if (lpNetResource == NULL ||
lpNetResource->lpRemoteName == NULL ||
lpcbBuffer == NULL ||
(lpBuffer == NULL && *lpcbBuffer != 0)) {
NPStatus = WN_BAD_VALUE;
IF_DEBUG_PRINT(DEBUG_ERRORS,
("ERROR: NPGetResourceParent(1). NPStatus = %08lx\n",
NPStatus));
goto EXIT_THE_FUNCTION;
}
//
// Check if dwType is set and is set to some valid value.
// It can be only of type RESOURCETYPE_DISK for our provider.
//
NPStatus = DavCheckResourceType(lpNetResource->dwType);
if (NPStatus != WN_SUCCESS) {
IF_DEBUG_PRINT(DEBUG_ERRORS,
("ERROR: NPGetResourceParent(2). NPStatus=%d.\n", NPStatus));
goto EXIT_THE_FUNCTION;
}
//
// Initialize local variables.
//
cbNeeded = sizeof(NETRESOURCEW);
lpNROut = (LPNETRESOURCEW)lpBuffer;
lpszNext = lpNROut == NULL ? NULL : (LPWSTR)(lpNROut + 1);
//
// Check remote name passed to this function - and convert it to UNC name
// if it is in URL form. After converting to UNC name - canonicalize it
// which checks for validity of UNC name more strictly.
//
NPStatus = DavCheckAndConvertHttpUrlToUncName(lpNetResource->lpRemoteName,
&(RemoteName),
&(didAllocate),
FALSE,
&remNameType,
&(iBackslash),
TRUE);
if (NPStatus != ERROR_SUCCESS) {
IF_DEBUG_PRINT(DEBUG_ERRORS,
("ERROR: NPGetResourceParent/DavCheckAndConvertHttpUrlToUncName."
" NPStatus = %08lx\n", NPStatus));
goto EXIT_THE_FUNCTION;
}
NPStatus = WN_SUCCESS;
IF_DEBUG_PRINT(DEBUG_MISC,
("NPGetResourceParent : RemoteName = %ws.\n", RemoteName));
//
// Remote name is successfully converted to a valid UNC form. It is either a
// UNC-server name, or UNC-share name or UNC-path name.
//
//
// Set a few default values.
//
if ( *lpcbBuffer >= cbNeeded ) {
ZeroMemory(lpNROut, sizeof(NETRESOURCEW));
}
switch (remNameType) {
case DAV_REMOTENAME_TYPE_SERVER: {
//
// There is no domain concept for DAV servers. So return NULL for lpRemoteName
// to indicate that server is the top level resource of this provider.
//
lpNROut->lpRemoteName = NULL;
dwDisplayType = RESOURCEDISPLAYTYPE_NETWORK;
break;
}
case DAV_REMOTENAME_TYPE_SHARE: {
//
// RemoteName = \\server\share(\)
//
DWORD Count = 0, cbRemote = 0;
PWCHAR Ptr1 = NULL;
Ptr1 = wcschr (&(RemoteName[2]), L'\\');
//
// A trick: Share name here can be DAV_DUMMY_SHARE. If that is the case,
// then \\server\DAV_DUMMY_SHARE is actually <==> \\server in which
// case, it has no parent.
//
if (_wcsnicmp( (Ptr1 + 1),
DAV_DUMMY_SHARE,
wcslen(DAV_DUMMY_SHARE) ) == 0) {
IF_DEBUG_PRINT(DEBUG_MISC,
("NPGetResourceParent. RemoteName has DUMMYShare = %ws\n",
RemoteName));
lpNROut->lpRemoteName = NULL;
dwDisplayType = RESOURCEDISPLAYTYPE_NETWORK;
break;
}
//
// Copy the lpRemoteName.
//
Count = (DWORD) ( Ptr1 - RemoteName );
cbRemote = (Count + 1) * sizeof(WCHAR);
cbNeeded += cbRemote;
if (*lpcbBuffer >= cbNeeded ) {
lpNROut->lpRemoteName = lpszNext;
RtlCopyMemory( lpNROut->lpRemoteName, RemoteName, Count * sizeof(WCHAR) );
lpNROut->lpRemoteName[Count] = L'\0';
lpszNext += ( cbRemote / sizeof(WCHAR) );
}
dwDisplayType = RESOURCEDISPLAYTYPE_SERVER;
break;
}
case DAV_REMOTENAME_TYPE_PATH: {
//
// RemoteName = \\server\share\path\...
// OR
// RemoteName = \\server\share\path\...\
//
DWORD Count = 0, cbRemote = 0;
PWCHAR Ptr1 = NULL, Ptr2 = NULL, Ptr3 = NULL;
BOOLEAN LastCharIsWack = FALSE;
PWCHAR ResourceStart = NULL;
Ptr3 = &(RemoteName[0]);
while (Ptr3[0] != L'\0') {
if (Ptr3[0] == L'\\') {
Ptr1 = Ptr2;
Ptr2 = Ptr3;
Count++;
}
Ptr3++;
}
if (Ptr2[1] == L'\0') {
LastCharIsWack = TRUE;
ResourceStart = Ptr1;
} else {
ResourceStart = Ptr2;
}
//
// After this while loop:
// \\server\share\pathname\
// ^ ^
// | |
// Ptr1 Ptr2
// Ptr2 points to last L'\', while Ptr1 points to second last L'\'.
// And Count = Number of L'\' in the RemoteName.
//
if ((Count < 5) || (Count == 5 && LastCharIsWack == TRUE)) {
dwDisplayType = RESOURCEDISPLAYTYPE_SHARE;
} else {
dwDisplayType = RESOURCEDISPLAYTYPE_DIRECTORY;
}
//
// Copy the lpRemoteName.
//
Count = (DWORD) ( ResourceStart - RemoteName);
cbRemote = (Count + 1) * sizeof(WCHAR);
cbNeeded += cbRemote;
if ( *lpcbBuffer >= cbNeeded ) {
lpNROut->lpRemoteName = lpszNext;
RtlCopyMemory( lpNROut->lpRemoteName, RemoteName, Count * sizeof(WCHAR) );
lpNROut->lpRemoteName[Count] = L'\0';
lpszNext += ( cbRemote / sizeof(WCHAR) );
}
break;
}
default:{
//
// Control should not come here - DavCheckAnd... API returns successfully
// only for valid cases considered above.
//
ASSERT(FALSE);
IF_DEBUG_PRINT(DEBUG_ERRORS,
("ERROR: NPGetResourceParent: Invalid "
"DavRemoteNameType = %d\n", remNameType));
NPStatus = WN_BAD_NETNAME;
goto EXIT_THE_FUNCTION;
}
}
//
// Set the lpProvider pointer.
//
cbProvider = ( (1 + wcslen(DavClientDisplayName) ) * sizeof(WCHAR) );
cbNeeded += cbProvider;
if ( *lpcbBuffer >= cbNeeded ) {
lpNROut->lpProvider = lpszNext;
wcscpy(lpNROut->lpProvider, DavClientDisplayName);
lpszNext += ( cbProvider / sizeof(WCHAR) );
}
//
// If supplied buffer is long enough to contain whole data then return success.
//
if ( *lpcbBuffer >= cbNeeded ) {
lpNROut->dwType = RESOURCETYPE_DISK;
lpNROut->dwDisplayType = dwDisplayType;
lpNROut->dwUsage = DavDisplayTypeToUsage(lpNROut->dwDisplayType);
NPStatus = WN_SUCCESS;
DavDisplayNetResource(lpNetResource, L"lpNROut in NPGetResourceParent");
goto EXIT_THE_FUNCTION;
} else {
IF_DEBUG_PRINT(DEBUG_ERRORS,
("ERROR: NPGetResourceParent: Need more "
"buffer space. Supplied = %d, Required = %d\n",
*lpcbBuffer, cbNeeded));
*lpcbBuffer = cbNeeded;
NPStatus = WN_MORE_DATA;
goto EXIT_THE_FUNCTION;
}
EXIT_THE_FUNCTION:
//
// If RemoteName != NULL && didAllocate == TRUE, then we did allocate memory
// for the RemoteName field.
//
if (RemoteName != NULL && didAllocate == TRUE) {
LocalFree(RemoteName);
RemoteName = NULL;
didAllocate = FALSE;
}
IF_DEBUG_PRINT(DEBUG_EXIT, ("NPGetResourceParent: NPStatus = %d\n", NPStatus));
DavDebugBreakPoint();
return NPStatus;
}
DWORD
NPGetUniversalName(
IN LPCWSTR lpLocalPath,
IN DWORD dwInfoLevel,
OUT LPVOID lpBuffer,
IN OUT LPDWORD lpBufferSize
)
/*++
Routine Description:
This function returns the UNC name of the network resource associated with
a redirected local device.
Arguments:
lpLocalPath - Specifies the name of the redirected local drive, like
W:\bar\foo1.txt
dwInfoLevel - UniversalName or RemoteName (See the def of WNetGetUniversalName).
lpBuffer - The NameInfo is filled in if the call is successful.
lpBufferSize - Contains the size of the buffer lpBuffer. If the call fails
with WN_MORE_DATA, this contains the size of buffer needed.
Return Value:
WN_SUCCESS - Success.
WN_NOT_CONNECTED - lpLocalPath is not a redirected local path.
WN_BAD_VALUE -
WN_MORE_DATA - Buffer was too small.
WN_OUT_OF_MEMORY - Cannot allocate buffer due memory shortage.
WN_NET_ERROR - Other network error.
--*/
{
DWORD NPStatus = WN_SUCCESS;
DWORD cbNeeded = 0, LocalPathLen = 0, UncNameLen = 0, RemoteNameLen = 0;
WCHAR localDrive[3]=L"";
WCHAR CanonName[MAX_PATH+1]=L"";
ULONG CanonNameSize = sizeof(CanonName);
ULONG CanonNameLen = 0;
ULONG CanonNameMaxLen = sizeof(CanonName)/sizeof(WCHAR);
NET_API_STATUS NetApiStatus = NERR_Success;
LPUNIVERSAL_NAME_INFO lpUNOut = NULL;
LPREMOTE_NAME_INFO lpRNOut = NULL;
PWCHAR lpszNext = NULL, RemoteName = NULL;
BOOLEAN didAllocate = FALSE;
DWORD PathType = 0;
IF_DEBUG_PRINT(DEBUG_ENTRY,
("NPGetUniversalName: lpLocalPath = %ws, dwInfoLevel = %d"
"lpBuffer=0x%x, lpBufferSize=0x%x, *lpBufferSize=%d\n",
lpLocalPath, dwInfoLevel, lpBuffer, lpBufferSize,
lpBufferSize == NULL?-1:*lpBufferSize));
//
// Initialize local variables
//
didAllocate = FALSE;
lpRNOut = NULL;
lpUNOut = NULL;
lpszNext = NULL;
RemoteName = NULL;
//
// If the WebClient service is not running we bail out right away.
//
if ( !DavWorkstationStarted() ) {
IF_DEBUG_PRINT(DEBUG_ERRORS,
("ERROR: NPGetUniversalName/DavWorkstationStarted. "
"Service NOT Running\n"));
NPStatus = WN_NO_NETWORK;
goto EXIT_THE_FUNCTION;
}
//
// Check for bad info level.
//
if ( (dwInfoLevel != UNIVERSAL_NAME_INFO_LEVEL) && (dwInfoLevel != REMOTE_NAME_INFO_LEVEL) ) {
NPStatus = WN_BAD_VALUE;
IF_DEBUG_PRINT(DEBUG_ERRORS, ("ERROR: NPGetUniversalName: Bad InfoLevel\n"));
goto EXIT_THE_FUNCTION;
}
//
// Check for validity of the parameters passed to this function.
//
if ( lpLocalPath == NULL || lpBufferSize == NULL || (lpBuffer == NULL && *lpBufferSize != 0) ) {
NPStatus = WN_BAD_VALUE;
IF_DEBUG_PRINT(DEBUG_ERRORS, ("ERROR: NPGetUniversalName: Bad Pointers\n"));
goto EXIT_THE_FUNCTION;
}
//
// Local path must at least have "X:".
//
LocalPathLen = wcslen(lpLocalPath) + 1;
if ( (LocalPathLen < 3) ||
(lpLocalPath[1] != L':') ||
((LocalPathLen > 3) && (lpLocalPath[2] != L'\\')) ) {
NPStatus = WN_BAD_LOCALNAME;
IF_DEBUG_PRINT(DEBUG_ERRORS, ("ERROR: NPGetUniversalName: Bad LocalPath\n"));
goto EXIT_THE_FUNCTION;
}
//
// Canonicalize the local path to take care of invalid forms +
// macros expansion like '.' and '..'
//
PathType = 0;
NetApiStatus = I_NetPathCanonicalize(NULL,
(PWCHAR)lpLocalPath,
CanonName,
CanonNameSize,
NULL,
&PathType,
0);
if ( (NetApiStatus != NERR_Success) ||
( (PathType != ITYPE_DEVICE_DISK) && // lpLocalPath=C:
( !(PathType & ITYPE_PATH) || // lpLocalPath=C:\abc\..\asds
!(PathType & ITYPE_DPATH) )
) ) {
IF_DEBUG_PRINT(DEBUG_ERRORS,
("ERROR: NPGetUniversalName/I_NetPathCanonicalize: "
"NetApiStatus = %08lx\n", NetApiStatus));
NPStatus = WN_BAD_LOCALNAME;
goto EXIT_THE_FUNCTION;
}
CanonName[CanonNameMaxLen-1] = L'\0';
CanonNameLen = wcslen(CanonName) + 1;
//
// Now onwards, use Canonicalized name instead of lpLocalPath to return more meaningful
// values.
//
localDrive[0]=CanonName[0];
localDrive[1]=CanonName[1];
localDrive[2]=L'\0';
IF_DEBUG_PRINT(DEBUG_MISC, ("ERROR: NPGetUniversalName/I_NetPathCanonicalize: "
"CanonName= %ws, LocalDrive=%ws\n", CanonName, localDrive));
//
// Use the available buffer for storing remote name for now. We will allocate
// local copy of remote name later if required.
//
RemoteNameLen = (*lpBufferSize)/sizeof(WCHAR);
NPStatus = NPGetConnection(localDrive, lpBuffer, &RemoteNameLen);
if (NPStatus != WN_MORE_DATA && NPStatus != WN_SUCCESS) {
//
// The local drive is not valid for our provider - or some other error occured.
// Return error.
//
IF_DEBUG_PRINT(DEBUG_ERRORS, ("ERROR: NPGetUniversalName/NPGetConnection: "
"NPStatus = %08lx\n", NPStatus));
goto EXIT_THE_FUNCTION;
}
if ( NPStatus == WN_SUCCESS ) {
RemoteNameLen = wcslen(lpBuffer) + 1;
IF_DEBUG_PRINT(DEBUG_MISC,
("ERROR: NPGetUniversalName/NPGetConnection: "
"RemoteUncName = %ws, RemoteNameLen = %d\n",
lpBuffer, RemoteNameLen));
}
//
// NPStatus = WN_SUCCESS OR NPStatus = WN_MORE_DATA. In either case cbRemote will
// have the sizeof(RemoteName-for-local-drive) for given local drive.
//
//
// UNC path = "RemoteName-for-local-drive" + "RemainingPath-in-local-path"
// Where RemainingPath-in-local-path is path remaining after removing local-drive
// portion (ex. "C:") from the local-path.
// So len(UNC Path) = len(RemoteName) + (CanonNameLen-2).
// Where subtract=2 denote removing local-drive portion (ex "C:" from localpath).
// Subtract 1 from RemoteNameLen to remove NULL character from RemoteName,
// a NULL character is already accounted in CanonName
//
UncNameLen = (RemoteNameLen - 1) + (CanonNameLen - 2);
switch (dwInfoLevel) {
case UNIVERSAL_NAME_INFO_LEVEL: {
cbNeeded = sizeof(UNIVERSAL_NAME_INFO);
lpUNOut = (LPUNIVERSAL_NAME_INFO)lpBuffer;
lpszNext = lpBuffer == NULL ? NULL:(LPWSTR)(lpUNOut + 1);
//
// Calculate the bytes we really need = sizeof(STRUCTURE) + sizeof(UNC Path).
//
cbNeeded += ((UncNameLen)*sizeof(WCHAR));
IF_DEBUG_PRINT(DEBUG_MISC, ("ERROR: NPGetUniversalName: BufReq=%d\n", cbNeeded));
//
// If the number of bytes that were passed in is not sufficient, we
// return WN_MORE_DATA.
//
if (*lpBufferSize < cbNeeded) {
*lpBufferSize = cbNeeded;
NPStatus = WN_MORE_DATA;
goto EXIT_THE_FUNCTION;
}
//
// Create local copy of remote name. Deallocate it in the end.
//
ASSERT (RemoteName == NULL);
RemoteName = (PWCHAR) LocalAlloc( (LMEM_FIXED | LMEM_ZEROINIT),
(RemoteNameLen * sizeof(WCHAR)) ) ;
if (RemoteName == NULL) {
NPStatus = GetLastError();
IF_DEBUG_PRINT(DEBUG_ERRORS,
("ERROR: NPGetUniversalName/LocalAlloc. NPStatus = %08lx\n",
NPStatus));
goto EXIT_THE_FUNCTION;
}
didAllocate = TRUE;
wcscpy(RemoteName, lpBuffer);
ZeroMemory(lpUNOut,sizeof(UNIVERSAL_NAME_INFO));
//
// Now, we have enough buffer, copy the information into the buffer.
//
lpUNOut->lpUniversalName = lpszNext;
wcscpy(lpUNOut->lpUniversalName, RemoteName);
//
// We concatenate the name afterthe drive letter to the RemoteBuffer
// we copied above.
//
wcscat( lpUNOut->lpUniversalName, (CanonName + 2) );
NPStatus = WN_SUCCESS;
break;
}
case REMOTE_NAME_INFO_LEVEL: {
cbNeeded = sizeof(REMOTE_NAME_INFO);
lpRNOut = (LPREMOTE_NAME_INFO)lpBuffer;
lpszNext = lpBuffer == NULL ? NULL:(LPWSTR)(lpRNOut + 1);
//
// Calculate the bytes we really need = sizeof(STRUCTURE) + sizeof(UNC Path) +
// sizeof(ConnectionPath) + sizeof(RemainingPath).
//
cbNeeded += ( ( UncNameLen + // UNC Path
RemoteNameLen + // ConnectionPath
(CanonNameLen - 2) ) * sizeof(WCHAR) ); // RemainingPath
IF_DEBUG_PRINT(DEBUG_MISC, ("ERROR: NPGetUniversalName: BufReq=%d\n", cbNeeded));
//
// If the number of bytes that were passed in is not sufficient, we
// return WN_MORE_DATA.
//
if (*lpBufferSize < cbNeeded) {
*lpBufferSize = cbNeeded;
NPStatus = WN_MORE_DATA;
goto EXIT_THE_FUNCTION;
}
//
// Create local copy of remote name. Deallocate it in the end.
//
ASSERT (RemoteName == NULL);
RemoteName = (PWCHAR) LocalAlloc( LMEM_FIXED | LMEM_ZEROINIT,
RemoteNameLen*sizeof(WCHAR)) ;
if (RemoteName == NULL) {
NPStatus = GetLastError();
IF_DEBUG_PRINT(DEBUG_ERRORS,
("ERROR: NPGetUniversalName/LocalAlloc. NPStatus = %08lx\n",
NPStatus));
goto EXIT_THE_FUNCTION;
}
didAllocate = TRUE;
wcscpy(RemoteName, lpBuffer);
ZeroMemory(lpRNOut,sizeof(REMOTE_NAME_INFO));
//
// Now, we have enough buffer, copy the information into the buffer.
//
lpRNOut->lpUniversalName = lpszNext;
lpszNext += UncNameLen;
wcscpy(lpRNOut->lpUniversalName, RemoteName);
//
// We concatenate the name afterthe drive letter to the RemoteBuffer
// we copied above.
//
wcscat( lpRNOut->lpUniversalName, (CanonName + 2) );
//
// Copy the connection name.
//
lpRNOut->lpConnectionName = lpszNext;
lpszNext += RemoteNameLen;
wcscpy(lpRNOut->lpConnectionName, RemoteName);
//
// Copy the remaining path.
//
lpRNOut->lpRemainingPath = lpszNext;
wcscpy( lpRNOut->lpRemainingPath, (CanonName+ 2) );
NPStatus = WN_SUCCESS;
break;
}
default: {
//
// We should never come here since we make this check above.
//
NPStatus = WN_BAD_VALUE ;
IF_DEBUG_PRINT(DEBUG_ERRORS, ("ERROR: NPGetUniversalName: Bad InfoLevel\n"));
ASSERT(FALSE);
goto EXIT_THE_FUNCTION;
}
}
EXIT_THE_FUNCTION:
if (RemoteName != NULL && didAllocate == TRUE) {
LocalFree(RemoteName);
didAllocate = FALSE;
RemoteName = NULL;
}
return NPStatus;
}
DWORD
NPFormatNetworkName(
LPWSTR lpRemoteName,
LPWSTR lpFormattedName,
LPDWORD lpnLength,
DWORD dwFlags,
DWORD dwAveCharPerLine
)
/*++
Routine Description:
This API allows the provider to trim or modify network names before they are
presented to the user.
Arguments:
lpRemoteName - Network name to be formatted.
lpFormattedName - Pointer to string buffer that will receive the formatted
name.
lpnLength - Pointer to DWORD that specifies the size of the buffer (in
characters) passed in. If the result is WN_MORE_DATA, this will
contain the buffer size required (in characters).
dwFlags - Bitfield indicating the type of format being requested. Can be one
of:
WNFMT_MULTILINE (0x01) - The provider should place the '\n'
character where line breaks should appear
in the name. The full name should be
expressed.
WNFMT_ABBREVIATED (0x02) - The provider should ellipsize or
otherwise shorten the network name such
that the most useful information will be
available to the user in the space
provided.
In addition, the following flags may be 'or'ed in and act as
modifiers to the above flags:
WNFMT_INENUM (0x10) - The network name is being presented in the
context of an enumeration where the
"container" of this object is presented
immediately prior to this object. This may
allow network providers to remove redundant
information from the formatted name,
providing a less cluttered display for the
user.
dwAveCharPerLine - This is the average number of characters that will fit on
a single line where the network name is being presented.
Specifically, this value is defined as the width of the
control divided by the tmAveCharWidth of the TEXTMETRIC
structure from the font used for display in the control.
Return Value:
WN_SUCCESS - If the call is successful.
WN_MORE_DATA - If input buffer is too small.
All other errors will be ignored by the caller and the unformatted network
name will be used.
--*/
{
DWORD NPStatus = WN_SUCCESS;
ULONG NameLength = 0;
LPWSTR pszCopyFrom = NULL, pszThird = NULL;
IF_DEBUG_PRINT(DEBUG_ENTRY,
("NPFormatNetworkName: RemoteName = %ws\n",
lpRemoteName));
//
// We do some checks before proceeding further.
//
if ( (dwFlags & WNFMT_MULTILINE) && (dwFlags & WNFMT_ABBREVIATED) ) {
NPStatus = WN_BAD_VALUE;
goto EXIT_THE_FUNCTION;
}
if ( lpRemoteName == NULL || lpnLength == NULL || (lpFormattedName == NULL && (*lpnLength != 0)) ) {
NPStatus = WN_BAD_VALUE;
goto EXIT_THE_FUNCTION;
}
pszCopyFrom = lpRemoteName;
if ( (dwFlags & WNFMT_ABBREVIATED) && (dwFlags & WNFMT_INENUM) ) {
if (lpRemoteName[0] == L'\\' && lpRemoteName[1] == L'\\') {
pszThird = wcschr( (lpRemoteName + 2), L'\\' );
if (pszThird != NULL) {
//
// In the form "\\server\share" => get the share name.
//
pszCopyFrom = (pszThird + 1);
} else {
//
// In the form "\\server" => get rid of "\\".
//
pszCopyFrom = (lpRemoteName + 2);
}
}
}
//
// Check to see if the supplied buffer is of the required size. If not
// return WN_MORE_DATA and fill lpnLength with the needed size in the number
// of chars.
//
NameLength = ( wcslen(pszCopyFrom) + 1 );
if (NameLength > *lpnLength) {
*lpnLength = NameLength;
NPStatus = WN_MORE_DATA;
goto EXIT_THE_FUNCTION;
}
//
// If we've come, we're ready to copy the name.
//
wcsncpy(lpFormattedName, pszCopyFrom, NameLength);
IF_DEBUG_PRINT(DEBUG_MISC,
("NPFormatNetworkName: lpFormattedName = %ws\n",
lpFormattedName));
NPStatus = WN_SUCCESS;
EXIT_THE_FUNCTION:
IF_DEBUG_PRINT(DEBUG_EXIT, ("NPFormatNetworkName: NPStatus = %d\n", NPStatus));
return NPStatus;
}
DWORD
DavMapRpcErrorToProviderError(
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:
case ERROR_UNEXP_NET_ERR:
case EPT_S_NOT_REGISTERED:
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:
case ERROR_INVALID_PARAMETER:
return WN_BAD_VALUE;
case ERROR_NOACCESS:
case EXCEPTION_ACCESS_VIOLATION:
return ERROR_INVALID_ADDRESS;
case ERROR_OPEN_FILES:
return WN_OPEN_FILES;
case ERROR_ALREADY_ASSIGNED:
return WN_ALREADY_CONNECTED;
case ERROR_REM_NOT_LIST:
return WN_BAD_NETNAME;
case ERROR_BAD_DEVICE:
return WN_BAD_LOCALNAME;
case ERROR_INVALID_PASSWORD:
return WN_BAD_PASSWORD;
case ERROR_NOT_FOUND:
return WN_NOT_CONNECTED;
default:
return RpcError;
}
}
DWORD
DavBindTheRpcHandle(
handle_t *dav_binding_h
)
/*++
Routine Description:
This routine binds the RPC handle to the local server.
Arguments:
dav_binding_h - The pointer to the handle that will be bound to the server
in this routine.
Return Value:
ERROR_SUCCESS or the appropriate Win32 error code.
--*/
{
DWORD WStatus = ERROR_SUCCESS;
handle_t Handle;
//
// Binds the RPC handle to the DAV RPC server.
//
WStatus = NetpBindRpc(NULL,
L"DAV RPC SERVICE",
NULL,
&(Handle));
if (WStatus != RPC_S_OK) {
IF_DEBUG_PRINT(DEBUG_ERRORS,
("ERROR: DavBindTheRpcHandle/NetpBindRpc. "
"WStatus = %08lx\n", WStatus));
goto EXIT_THE_FUNCTION;
}
//
// Set the handle that was passed into the function.
//
*dav_binding_h = Handle;
EXIT_THE_FUNCTION:
return WStatus;
}
BOOL
DavWorkstationStarted(
VOID
)
/*++
Routine Description:
This function queries the service controller to see if the Dav client
service has started. If in doubt, it returns FALSE.
Arguments:
None.
Return Value:
Returns TRUE if the DAV client service has started, FALSE otherwise.
--*/
{
DWORD WStatus;
SC_HANDLE ScManager;
SC_HANDLE Service;
SERVICE_STATUS ServiceStatus;
BOOL IsStarted = FALSE;
ScManager = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
if (ScManager == NULL) {
WStatus = GetLastError();
IF_DEBUG_PRINT(DEBUG_ERRORS,
("ERROR: DavWorkstationStarted/OpenSCManagerW. "
"WStatus = %08lx\n", WStatus));
return FALSE;
}
Service = OpenServiceW(ScManager, SERVICE_DAVCLIENT, SERVICE_QUERY_STATUS);
if (Service == NULL) {
WStatus = GetLastError();
IF_DEBUG_PRINT(DEBUG_ERRORS,
("ERROR: DavWorkstationStarted/OpenServiceW. "
"WStatus = %08lx\n", WStatus));
CloseServiceHandle(ScManager);
return FALSE;
}
if ( !QueryServiceStatus(Service, &ServiceStatus) ) {
WStatus = GetLastError();
IF_DEBUG_PRINT(DEBUG_ERRORS,
("ERROR: DavWorkstationStarted/QueryServiceStatus. "
"WStatus = %08lx\n", WStatus));
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) ) {
IF_DEBUG_PRINT(DEBUG_MISC, ("DavWorkstationStarted. WebClient Running!!!\n"));
IsStarted = TRUE;
} else {
IF_DEBUG_PRINT(DEBUG_MISC, ("DavWorkstationStarted. WebClient Stopped!!!\n"));
}
CloseServiceHandle(ScManager);
CloseServiceHandle(Service);
return IsStarted;
}
DAV_REMOTENAME_TYPE
DavParseRemoteName (
IN LPWSTR RemoteName,
OUT LPWSTR CanonName,
IN DWORD CanonNameSize,
OUT PULONG PathStart
)
/*++
Routine Description:
This function canonicalizes a remote resource name and determines its type.
Arguments:
RemoteName - Remote resource name to be parsed: Expects UNC name here.
CanonName - Buffer for canonicalized name, assumed to be MAX_PATH characters
long.
CanonNameSize - Size, in bytes, of output buffer.
PathStart - Set to the offset, in characters, of the start
of the "\path" portion (in the DAV_REMOTENAME_TYPE_PATH case)
within CanonName. Not set in other cases. Otherwise set to 0.
Return Value:
If RemoteName is like Then return
--------------------- ------------
workgroup DAV_REMOTENAME_TYPE_WORKGROUP
\\server DAV_REMOTENAME_TYPE_SERVER
\\server\share DAV_REMOTENAME_TYPE_SHARE
\\server\share\path DAV_REMOTENAME_TYPE_PATH
(other) DAV_REMOTENAME_TYPE_INVALID
--*/
{
NET_API_STATUS NetApiStatus = NERR_Success;
DWORD PathType = 0;
PWCHAR wszDummy = NULL;
ULONG ReqLen = 0;
IF_DEBUG_PRINT(DEBUG_ENTRY, ("DavParseRemoteName: RemoteName = %ws\n", RemoteName));
NetApiStatus = I_NetPathType(NULL, RemoteName, &PathType, 0);
if (NetApiStatus != NERR_Success) {
IF_DEBUG_PRINT(DEBUG_ERRORS, ("ERROR: DavParseRemoteName/I_NetPathType: "
"NetApiStatus = %08lx\n", NetApiStatus));
return DAV_REMOTENAME_TYPE_INVALID;
}
if ( PathStart != NULL) {
*PathStart = 0;
}
//
// I_NetPathType doesn't give us quite as fine a classification of path
// types as we need, so we still need to do a little more parsing.
//
switch (PathType) {
case ITYPE_PATH_RELND:
IF_DEBUG_PRINT(DEBUG_MISC, ("DavParseRemoteName: ITYPE_PATH_RELND\n"));
//
// A driveless relative path. A valid workgroup or domain name would be
// classified as such, but it still needs to be validated as a workgroup
// name.
//
NetApiStatus = I_NetNameCanonicalize(NULL,
RemoteName,
CanonName,
CanonNameSize,
NAMETYPE_WORKGROUP,
0);
if (NetApiStatus == NERR_Success) {
return DAV_REMOTENAME_TYPE_WORKGROUP;
} else {
IF_DEBUG_PRINT(DEBUG_ERRORS, ("ERROR: DavParseRemoteName/I_NetNameCanonicalize: "
"NetApiStatus = %08lx\n", NetApiStatus));
return DAV_REMOTENAME_TYPE_INVALID;
}
break;
case ITYPE_UNC_COMPNAME:
IF_DEBUG_PRINT(DEBUG_MISC, ("DavParseRemoteName: ITYPE_UNC_COMPNAME\n"));
//
// A UNC computername, "\\server".
//
//
// HACK: I_NetPathCanonicalize likes "\\server\share" but not
// "\\server", so append a dummy share name to canonicalize.
// We assume that the CanonName buffer will still be big
// enough (which it will, in the calls made from this file).
//
ReqLen = wcslen(RemoteName) + 2 + 1;
wszDummy = (PWCHAR) LocalAlloc( (LMEM_FIXED | LMEM_ZEROINIT),
(ReqLen * sizeof(WCHAR)) );
if (wszDummy == NULL) {
ULONG WStatus = GetLastError();
IF_DEBUG_PRINT(DEBUG_ERRORS,
("ERROR: DavParseRemoteName/LocalAlloc. WStatus = %08lx\n",
WStatus));
return DAV_REMOTENAME_TYPE_INVALID;
}
wcscpy(wszDummy, RemoteName);
wcscat(wszDummy, L"\\a");
PathType = ITYPE_UNC;
NetApiStatus = I_NetPathCanonicalize(NULL,
wszDummy,
CanonName,
CanonNameSize,
NULL,
&PathType,
0);
if(wszDummy) {
LocalFree((HLOCAL)wszDummy);
wszDummy = NULL;
}
if (NetApiStatus != NERR_Success) {
IF_DEBUG_PRINT(DEBUG_ERRORS, ("ERROR: DavParseRemoteName/I_NetPathCanonicalize: "
"NetApiStatus = %08lx\n", NetApiStatus));
return DAV_REMOTENAME_TYPE_INVALID;
}
CanonName[(CanonNameSize/sizeof(WCHAR))-1]=L'\0';
//
// Remove the dummy portion added to remote name = L"\a".
//
CanonName[ wcslen(CanonName) - 2 ] = L'\0';
return DAV_REMOTENAME_TYPE_SERVER;
break;
case ITYPE_UNC: {
PWCHAR pShareStart = NULL;
PWCHAR pPathStart = NULL;
IF_DEBUG_PRINT(DEBUG_MISC, ("DavParseRemoteName: ITYPE_UNC\n"));
//
// A UNC path, either "\\server\share" or "\\server\share\path".
// Canonicalize and determine which one.
//
PathType = ITYPE_UNC;
NetApiStatus = I_NetPathCanonicalize(NULL,
RemoteName,
CanonName,
CanonNameSize,
NULL,
&PathType,
0);
if (NetApiStatus != NERR_Success) {
IF_DEBUG_PRINT(DEBUG_ERRORS, ("ERROR: DavParseRemoteName/I_NetPathCanonicalize: "
"NetApiStatus = %08lx\n", NetApiStatus));
return DAV_REMOTENAME_TYPE_INVALID;
}
CanonName[(CanonNameSize/sizeof(WCHAR))-1]=L'\0';
pShareStart = wcschr( (CanonName + 2), DAV_PATH_SEPARATOR );
//
// Look for a fourth slash. Also, if the form is \\server\share\,
// we will have 4 slashes but no extra path. Hence the extra check
// is made.
//
pPathStart = wcschr( (pShareStart + 1), DAV_PATH_SEPARATOR );
if ( pPathStart != NULL && *(pPathStart + 1) != L'\0') {
if(PathStart) {
*PathStart = (ULONG)(pPathStart - CanonName);
}
return DAV_REMOTENAME_TYPE_PATH;
} else {
if(PathStart) {
*PathStart = 0;
}
return DAV_REMOTENAME_TYPE_SHARE;
}
break;
}
default: {
IF_DEBUG_PRINT(DEBUG_ERRORS, ("ERROR: DavParseRemoteName: Invalid PathType\n"));
return DAV_REMOTENAME_TYPE_INVALID;
break;
}
} // end switch(PathType);
}
BOOL
DavServerExists(
IN PWCHAR PathName,
OUT PWCHAR Server
)
/*++
Routine Description:
This function figures out if the Server in the PathName is a valid DAV
server.
Arguments:
PathName - A UNC path (\\server\share\dir....). Assuming that it is a valid string.
It can be of form \\server OR \\server\share OR \\server\share\dir...
Server - If non NULL, the server in the PathName is filled in on return.
Return Value:
TRUE - Valid DAV server and
FALSE - Its not.
--*/
{
DWORD NPStatus = WN_SUCCESS;
handle_t dav_binding_h;
BOOLEAN serverExists = FALSE, RpcBindingSucceeded = FALSE;
ULONG iBackslash = 0;
ULONG_PTR ServerLength = 0;
PWCHAR ServerName = NULL;
PWCHAR Ptr1 = NULL, Ptr2 = NULL;
IF_DEBUG_PRINT(DEBUG_ENTRY, ("DavServerExists: PathName = %ws\n", PathName));
serverExists = FALSE;
//
// The PathName is of the form \\server or \\server\share or \\server\share\path.
//
ASSERT(PathName[0] == L'\\' && PathName[1] == L'\\');
Ptr1 = Ptr2 = &(PathName[2]);
while(Ptr2[0] != L'\\' && Ptr2[0] != L'\0') {
Ptr2++;
}
ServerLength = (ULONG_PTR) ( (Ptr2 - Ptr1) + 1 );
ServerName = (PWCHAR) LocalAlloc( (LMEM_FIXED | LMEM_ZEROINIT),
(ServerLength * sizeof(WCHAR)) );
if (ServerName == NULL) {
ULONG WStatus = GetLastError();
IF_DEBUG_PRINT(DEBUG_ERRORS,
("ERROR: DavServerExists/LocalAlloc. WStatus = %08lx\n",
WStatus));
goto EXIT_THE_FUNCTION;
}
//
// Copy the chars that make the ServerName.
//
RtlCopyMemory(ServerName, Ptr1, (ServerLength-1) * sizeof(WCHAR));
ServerName[ServerLength-1] = L'\0';
//
// We now need to RPC the server name into the DAV service process which
// figures out if this server is a valid DAV server.
//
NPStatus = DavBindTheRpcHandle( &(dav_binding_h) );
if (NPStatus != ERROR_SUCCESS) {
IF_DEBUG_PRINT(DEBUG_ERRORS,
("ERROR: DavServerExists/DavBindTheRpcHandle. "
"NPStatus = %08lx\n", NPStatus));
NPStatus = WN_NO_NETWORK;
goto EXIT_THE_FUNCTION;
}
RpcBindingSucceeded = TRUE;
RpcTryExcept {
NPStatus = DavrDoesServerDoDav(dav_binding_h, ServerName, &serverExists);
if (NPStatus != NO_ERROR) {
IF_DEBUG_PRINT(DEBUG_ERRORS,
("ERROR: DavServerExists/DavrDoesServerDoDav. "
"NPStatus = %08lx\n", NPStatus));
SetLastError(NPStatus);
serverExists = FALSE;
}
} RpcExcept (I_RpcExceptionFilter(RpcExceptionCode())) {
RPC_STATUS RpcStatus;
RpcStatus = RpcExceptionCode();
IF_DEBUG_PRINT(DEBUG_ERRORS, ("ERROR: DavServerExists/DavrDoesServerDoDav."
" RpcExceptionCode = %d\n", RpcStatus));
NPStatus = DavMapRpcErrorToProviderError(RpcStatus);
serverExists = FALSE;
goto EXIT_THE_FUNCTION;
}
RpcEndExcept
IF_DEBUG_PRINT(DEBUG_MISC, ("DavServerExists: serverExists = %d\n", serverExists));
EXIT_THE_FUNCTION:
if (ServerName != NULL) {
//
// If the Server is not NULL, then we need to copy the ServerName.
//
if (Server != NULL) {
wcscpy(Server, ServerName);
}
LocalFree(ServerName);
ServerName = NULL;
}
if (RpcBindingSucceeded) {
RpcBindingFree( &(dav_binding_h) );
RpcBindingSucceeded = FALSE;
}
return serverExists;
}
BOOL
DavShareExists(
PWCHAR PathName
)
/*++
Routine Description:
This function figures out if the Share in the PathName is a valid DAV
share.
Arguments:
PathName - A UNC path (\\server\share\dir....) : Assuming that this is valid.
Return Value:
TRUE - Valid DAV share and
FALSE - Its not.
--*/
{
DWORD NPStatus = WN_SUCCESS;
BOOLEAN shareExists = FALSE, RpcBindingSucceeded = FALSE;
handle_t dav_binding_h;
PWCHAR ServerName = NULL, ShareName = NULL;
PWCHAR serverStart = NULL, shareStart = NULL, shareEnd = NULL;
DWORD count = 0;
ULONG_PTR ServerLength = 0, ShareLength = 0;
IF_DEBUG_PRINT(DEBUG_ENTRY, ("DavShareExists: PathName = %ws\n", PathName));
ASSERT(PathName[0]==L'\\' && PathName[1]==L'\\');
serverStart = &(PathName[2]);
shareExists = FALSE;
//
// The PathName could be of the following forms.
// 1. \\server\share OR
// 2. \\server\share\path
// We need to extract the share name from the path and find out if its a
// valid share.
//
shareStart = wcschr(serverStart ,L'\\');
ASSERT(shareStart != NULL);
//
// Copy the ServerName to local copy. Last char is for L'\0' char.
//
ServerLength = (ULONG_PTR)(shareStart - serverStart) + 1;
ServerName = (PWCHAR) LocalAlloc( (LMEM_FIXED | LMEM_ZEROINIT),
(ServerLength * sizeof(WCHAR)) );
if (ServerName == NULL) {
NPStatus = GetLastError();
IF_DEBUG_PRINT(DEBUG_ERRORS,
("ERROR: DavShareExists/LocalAlloc. NPStatus = %08lx\n",
NPStatus));
goto EXIT_THE_FUNCTION;
}
//
// Copy the chars that make the ServerName.
//
RtlCopyMemory(ServerName, serverStart, (ServerLength-1) * sizeof(WCHAR));
ServerName[ServerLength-1] = L'\0';
IF_DEBUG_PRINT(DEBUG_MISC, ("DavShareExists: ServerName = %ws\n", ServerName));
//
// \\server\share\path
// ^
// |
// shareStart
shareStart++;
//
// We need to find out if the PathName is of the form
// 1. \\server\share OR
// 2. \\server\share\path
// If it is of form 1, then wcschr(shareStart, L'\\'); should return NULL
// and if it is of form 2 wcschr(shareStart, L'\\'); points to the 4th L'\\'.
//
shareEnd = shareStart+1;
while(shareEnd[0] != L'\\' && shareEnd[0] != L'\0') {
shareEnd++;
}
ShareLength = (ULONG_PTR)(shareEnd - shareStart) + 1;
ShareName = (PWCHAR) LocalAlloc( (LMEM_FIXED | LMEM_ZEROINIT),
(ShareLength * sizeof(WCHAR)) );
if (ShareName == NULL) {
NPStatus = GetLastError();
IF_DEBUG_PRINT(DEBUG_ERRORS,
("ERROR: DavShareExists/LocalAlloc. NPStatus = %08lx\n",
NPStatus));
goto EXIT_THE_FUNCTION;
}
//
// Copy the chars that make the ShareName.
//
RtlCopyMemory(ShareName, shareStart, (ShareLength-1) * sizeof(WCHAR));
ShareName[ShareLength-1]=L'\0';
IF_DEBUG_PRINT(DEBUG_MISC, ("DavShareExists: ShareName = %ws\n", ShareName));
//
// If the share is DAV_DUMMY_SHARE, then we just need to check if server is a
// valid DAV server. If it is a DAV server, then return SUCCESS as
// DAV_DUMMY_SHARE is only name given to root level of DAV server.
//
if ( _wcsicmp(ShareName, DAV_DUMMY_SHARE) == 0 ) {
IF_DEBUG_PRINT(DEBUG_MISC, ("DavShareExists: DUMMY_SHARE. ShareName=%ws\n",
ShareName));
if (DavServerExists(PathName, NULL) == TRUE) {
shareExists = TRUE;
NPStatus = WN_SUCCESS;
goto EXIT_THE_FUNCTION;
} else {
shareExists = FALSE;
NPStatus = WN_SUCCESS;
IF_DEBUG_PRINT(DEBUG_MISC, ("DavShareExists/DavServerExists: DUMMY_SHARE."
"Server do not exist=%ws\n", PathName));
goto EXIT_THE_FUNCTION;
}
}
//
// We now need to RPC the server name and the share name into the DAV
// service process which figures out if this share is valid share of the
// server.
//
NPStatus = DavBindTheRpcHandle( &(dav_binding_h) );
if (NPStatus != ERROR_SUCCESS) {
IF_DEBUG_PRINT(DEBUG_ERRORS,
("ERROR: DavShareExists/DavBindTheRpcHandle. "
"NPStatus = %08lx\n", NPStatus));
NPStatus = WN_NO_NETWORK;
goto EXIT_THE_FUNCTION;
}
RpcBindingSucceeded = TRUE;
RpcTryExcept {
NPStatus = DavrIsValidShare(dav_binding_h, ServerName, ShareName, &shareExists);
if (NPStatus != NO_ERROR) {
IF_DEBUG_PRINT(DEBUG_ERRORS,
("ERROR: DavShareExists/DavrIsValidShare. "
"NPStatus = %08lx\n", NPStatus));
SetLastError(NPStatus);
shareExists = FALSE;
}
} RpcExcept (I_RpcExceptionFilter(RpcExceptionCode())) {
RPC_STATUS RpcStatus;
RpcStatus = RpcExceptionCode();
IF_DEBUG_PRINT(DEBUG_ERRORS, ("ERROR: DavShareExists/DavrIsValidShare."
" RpcExceptionCode = %d\n", RpcStatus));
NPStatus = DavMapRpcErrorToProviderError(RpcStatus);
shareExists = FALSE;
goto EXIT_THE_FUNCTION;
}
RpcEndExcept
IF_DEBUG_PRINT(DEBUG_MISC, ("DavShareExists: shareExists = %d\n", shareExists));
EXIT_THE_FUNCTION:
if (ServerName) {
LocalFree(ServerName);
ServerName = NULL;
}
if (ShareName) {
LocalFree(ShareName);
ShareName = NULL;
}
if (RpcBindingSucceeded) {
RpcBindingFree( &(dav_binding_h) );
RpcBindingSucceeded = FALSE;
}
return shareExists;
}
HMODULE
DavInitCredUI(
PWCHAR RemoteName,
WCHAR ServerName[CRED_MAX_STRING_LENGTH + 1],
PFN_CREDUI_CONFIRMCREDENTIALS *pfnCredUIConfirmCredentials,
PFN_CREDUI_PROMPTFORCREDENTIALS *pfnCredUIPromptForCredentials,
PFN_CREDUI_CMDLINE_PROMPTFORCREDENTIALS *pfnCredUICmdlinePromptForCredentials
)
/*++
Routine Description:
This function initializes the credential management stuff.
Arguments:
RemoteName - RemoteName to be mapped.
ServerName - On return, contains the ServerName which is a part of the
RemoteName.
pfnCredUIGetPassword - On return contains a pointer to the
"CredUIGetPasswordW" function of credui.dll.
Return Value:
Handle returned by LoadLibrary or NULL.
--*/
{
PWCHAR StartName = NULL, EndName = NULL;
DWORD NameLength = 0;
HMODULE hCredUI = NULL;
//
// Assume the first 2 characters are path separators (L'\\').
//
StartName = RemoteName + 2;
EndName = wcschr(StartName, L'\\');
//
// If EndName is NULL, it implies that the RemoteName is of the form
// \\server.
//
if (EndName == NULL) {
EndName = StartName + wcslen(StartName);
}
NameLength = (DWORD)(EndName - StartName);
if ( (NameLength == 0) || (NameLength > CRED_MAX_STRING_LENGTH) ) {
//
// The server is either an empty string or has more than the maximum
// number of characters we support:
//
SetLastError(WN_BAD_NETNAME);
return NULL;
}
wcsncpy(ServerName, StartName, NameLength);
ServerName[NameLength] = L'\0';
//
// Load the DLL here and find the function we need.
//
hCredUI = LoadLibraryW(L"credui.dll");
if (hCredUI != NULL) {
*pfnCredUIConfirmCredentials = (PFN_CREDUI_CONFIRMCREDENTIALS)
GetProcAddress(hCredUI, "CredUIConfirmCredentialsW");
*pfnCredUIPromptForCredentials = (PFN_CREDUI_PROMPTFORCREDENTIALS)
GetProcAddress(hCredUI, "CredUIPromptForCredentialsW");
*pfnCredUICmdlinePromptForCredentials = (PFN_CREDUI_CMDLINE_PROMPTFORCREDENTIALS)
GetProcAddress(hCredUI, "CredUICmdLinePromptForCredentialsW");
if (*pfnCredUIConfirmCredentials == NULL ||
*pfnCredUIPromptForCredentials == NULL ||
*pfnCredUICmdlinePromptForCredentials == NULL ) {
FreeLibrary(hCredUI);
hCredUI = NULL;
}
}
return hCredUI;
}
DWORD
DavDisplayTypeToUsage(
DWORD dwDisplayType
)
/*++
Routine Description:
This routine maps the display type to usage type.
Arguments:
dwDisplayType - The display type to be mapped.
Return Value:
The Usage Type or 0 if none matches.
--*/
{
switch (dwDisplayType) {
case RESOURCEDISPLAYTYPE_NETWORK:
case RESOURCEDISPLAYTYPE_DOMAIN:
case RESOURCEDISPLAYTYPE_SERVER:
return RESOURCEUSAGE_CONTAINER;
case RESOURCEDISPLAYTYPE_SHARE:
return RESOURCEUSAGE_CONNECTABLE | RESOURCEUSAGE_NOLOCALDEVICE;
case RESOURCEDISPLAYTYPE_SHAREADMIN:
return RESOURCEUSAGE_NOLOCALDEVICE;
default:
break;
}
return 0L;
}
ULONG
DavCheckResourceType(
IN DWORD dwType
)
/*++
Routine Description:
This routine checks for valid resource types allowed for our provider.
Currently only RESOURCETYPE_DISK is valid for our resources.
Arguments:
dwType - Supplies the resource type to be checked for the validity.
Return Value:
WN_SUCCESS or the appropriate Win32/WNet error code.
--*/
{
//
// Check if dwType is set and is set to some valid value. It can be only of
// type RESOURCETYPE_DISK for our provider.
//
if ( (dwType != RESOURCETYPE_ANY) &&
(dwType & ~(RESOURCETYPE_PRINT | RESOURCETYPE_DISK)) ){
return WN_BAD_VALUE;
}
if (dwType == RESOURCETYPE_ANY || (dwType & RESOURCETYPE_DISK) ) {
return WN_SUCCESS;
} else {
return WN_BAD_DEV_TYPE;
}
}
ULONG
DavCheckLocalName(
IN PWCHAR LocalName
)
/*++
Routine Description:
This only handles NULL, empty string, and L"X:" formats.
Arguments:
LocalName - Supplies the local device name to map to the created tree
connection. Only drive letter device names are accepted. (No
LPT or COM).
Return Value:
WN_SUCCESS or the appropriate Win32/WNet error code.
--*/
{
DWORD LocalNameLength;
LocalNameLength = ( LocalName == NULL ) ? 0 : wcslen( LocalName );
if (LocalNameLength != 2 || !iswalpha(*LocalName) || LocalName[1] != L':') {
return WN_BAD_LOCALNAME;
}
return WN_SUCCESS;
}
ULONG
DavCheckAndConvertHttpUrlToUncName(
IN PWCHAR RemoteName,
OUT PWCHAR *UncRemoteName,
OUT PBOOLEAN MemoryAllocated,
IN BOOLEAN AddDummyShare,
OUT PDAV_REMOTENAME_TYPE premNameType,
OUT LPDWORD pathOffset,
IN BOOLEAN bCanonicalize
)
/*++
Routine Description:
This routine checks to see if the name is valid (atleast 3 chars long). It
then converts a Http URL (if the remote name was one) into a UNC name. Its
possible that the NP APIs get called with the URLs as RemoteNames. We need
to convert them to UNC before proceeding further. It also adds a dummy share
DavWWWRoot if one was not supplied with the request. This is because its
possible to map a drive to the root of the DAV server.
Arguments:
RemoteName - The Http URL that came in. An important thing to note is that
this need not be a HTTP URL. If its not, then we don't do any
conversion.
UncRemoteName - The UNC name that is returned to the caller. The returned
name will have the format \\server\share.
MemoryAllocated - TRUE if memory was allocated for the returned UNC name.
AddDummyShare - If TRUE, and the RemoteName is \\server or http://server,
a dummy share DavWWWRoot is added to the UNC name.
premNameType - Pointer to location to receive the type of UNC path returned by
I_NetPathType/Canonicalization. If NULL, no value is set.
This has meaning only when Canonicalization is done.
pathOffset - Offset of "\path" in remotename when remotename is of type
\\server\share\path... . Otherwise it is zero. If NULL, no value
is set. This has meaning only when Canonicalization is done.
bCanonicalize - IF TRUE, the remote name returned from URL to UNC will be
canonicalized before return.
Return Value:
ERROR_SUCCESS or the appropriate Win32 error code.
Notes:
This function returns WN_BAD_NETNAME also for remotes names which are
correct in syntax but have length > MAX_PATH.
--*/
{
ULONG WStatus = ERROR_SUCCESS;
PWCHAR ReturnedUncName = NULL, TempName = NULL, SrvName = NULL;
PWCHAR CanonicalName = NULL, ColonPtr = NULL;
BOOLEAN didAllocate = FALSE;
ULONG ReturnedUncNameLen = 0, index = 0, DummyShareNameLen = 0, CanonicalNameMaxLen = 0;
if (MemoryAllocated == NULL || UncRemoteName == NULL) {
WStatus = WN_BAD_VALUE;
IF_DEBUG_PRINT(DEBUG_ERRORS,
("ERROR: DavCheckAndConvertHttpUrlToUncName: (MemoryAllocated"
" == NULL || UncRemoteName == NULL)\n"));
goto EXIT_THE_FUNCTION;
}
*UncRemoteName = NULL;
*MemoryAllocated = FALSE;
if(pathOffset != NULL) {
*pathOffset = 0;
}
//
// 1. First we will check if this is a URL form remotename. If this is, then
// we will convert it to UNC name.
// 2. After converting to UNC name, we will add DummyShare name depending on
// parameter value passed to this function.
// 3. After this, we will canonicalize the converted UNC name depending on
// the parameter value passed to this function.
//
//
// If RemoteName is NULL, we have nothing to do.
//
if (RemoteName == NULL) {
WStatus = WN_BAD_NETNAME;
IF_DEBUG_PRINT(DEBUG_ERRORS,
("ERROR: DavCheckAndConvertHttpUrlToUncName: RemoteName == NULL\n"));
goto EXIT_THE_FUNCTION;
}
//
// The remote name must be atleast 3 chars long. It cannot be \\.
//
if ( wcslen(RemoteName) < 3 ) {
IF_DEBUG_PRINT(DEBUG_ERRORS,
("ERROR: DavCheckAndConvertHttpUrlToUncName: wcslen(RemoteName) < 3\n"));
WStatus = WN_BAD_NETNAME;
goto EXIT_THE_FUNCTION;
}
//
// Check to see if the remote name being suppiled is http:.
//
//
// We could get the names in the following formats.
// 1. http://servername/sharename OR
// 2. \\http://servername/sharename OR
// 3. http://servername OR
// 4. \\http://servername
// 5. \\servername.....
//
SrvName = NULL;
ColonPtr = wcschr(RemoteName, L':');
if( (ColonPtr != NULL) &&
( (ColonPtr - RemoteName == 4) || (ColonPtr - RemoteName == 6)) ) {
if( (RemoteName[0] == L'\\') && (RemoteName[1] == L'\\') &&
(_wcsnicmp((RemoteName + 2), L"http:", 5) == 0) ) {
//
// RemoteName is \\HTTP name. \\http://server....
//
SrvName = (RemoteName + 7);
} else if (_wcsnicmp(RemoteName, L"http:", 5) == 0) {
//
// RemoteName is HTTP name. http://server....
//
SrvName = (RemoteName + 5);
} else {
IF_DEBUG_PRINT(DEBUG_ERRORS,
("ERROR: DavCheckAndConvertHttpUrlToUncName(1): Invalid URL string\n"));
WStatus = WN_BAD_NETNAME;
goto EXIT_THE_FUNCTION;
}
} else if (RemoteName[0] == L'\\' && RemoteName[1] == L'\\') {
//
// RemoteName is UNC name
//
SrvName = RemoteName;
} else {
//
// RemoteName is neither "http://..." name NOR UNC name.
//
IF_DEBUG_PRINT(DEBUG_ERRORS,
("ERROR: DavCheckAndConvertHttpUrlToUncName(1): Invalid remote string\n"));
WStatus = WN_BAD_NETNAME;
goto EXIT_THE_FUNCTION;
}
ASSERT (SrvName != NULL);
//
// SrvName is pointing to start of servername portion. Servername portion
// can be of type L"\\..." or L"//...".
//
//
// Our parsing code below that converts the supplied http name into
// a UNC name looks at the first charactter to decide the format.
// We need to add the additional \\ in front of http to fool shell
// into sending the http name to us.
//
ReturnedUncNameLen = wcslen( SrvName ) ;
if ( ( ReturnedUncNameLen < 3 ) ||
( SrvName[0] != L'\\' && SrvName[0] != L'/' ) ||
( SrvName[1] != L'\\' && SrvName[1] != L'/' ) ) {
//
// The following cases will be eliminated here.
// 1. http:// 2. http:/aaa 3. \aaa 4. aaaa
//
IF_DEBUG_PRINT(DEBUG_ERRORS,
("ERROR: DavCheckAndConvertSrvNameUrlToUncName(2): Invalid URL string\n"));
WStatus = WN_BAD_NETNAME;
goto EXIT_THE_FUNCTION;
}
//
// We will allocate space for DAV_DUMMY_SHARE in this name so that
// if we are to add the Dummy name later, we don't have to reallocate memory
// for new name with Dummy share. String that will be added = L"\dummyshare"
//
if (AddDummyShare == TRUE) {
DummyShareNameLen = 1 + wcslen (DAV_DUMMY_SHARE);
}
ReturnedUncName = LocalAlloc( (LMEM_FIXED | LMEM_ZEROINIT),
( (ReturnedUncNameLen +
DummyShareNameLen +
1) * sizeof(WCHAR) ) );
if (ReturnedUncName == NULL) {
WStatus = GetLastError();
IF_DEBUG_PRINT(DEBUG_ERRORS,
("ERROR: DavCheckAndConvertSrvNameUrlToUncName/LocalAlloc. "
"WStatus = %08lx\n", WStatus));
goto EXIT_THE_FUNCTION;
}
//
// We need to keep track of the fact that we allocated memory in this
// routine.
//
didAllocate = TRUE;
//
// Copy the name in the UNC format. Replace '/' by '\'.
//
for (index = 0; index < ReturnedUncNameLen; index++) {
if (SrvName[index] == L'/') {
ReturnedUncName[index] = L'\\';
} else {
ReturnedUncName[index] = SrvName[index];
}
}
ReturnedUncName[ReturnedUncNameLen] = L'\0';
//
// If the final char of the RemoteName is a '\' or a '/' remove it. For
// some reason, the DAV servers do not like a / at the end.
//
if ( ReturnedUncName[ReturnedUncNameLen - 1] == L'/' ||
ReturnedUncName[ReturnedUncNameLen - 1] == L'\\' ) {
ReturnedUncName[ReturnedUncNameLen - 1] = L'\0';
ReturnedUncNameLen--;
}
if ( ReturnedUncNameLen < 3) {
//
// The following cases will be eliminated here.
// 1. http:/// 2. \\\
//
IF_DEBUG_PRINT(DEBUG_ERRORS,
("ERROR: DavCheckAndConvertHttpUrlToUncName(3): Invalid remote string\n"));
WStatus = WN_BAD_NETNAME;
goto EXIT_THE_FUNCTION;
}
//
// At this point, any URL remotename is already converted to UNC name.
//
//
// Add the dummy share only if we were asked to.
//
if (AddDummyShare == TRUE) {
//
// If the format is \\server, we need to add a dummy share just to get
// through the file system since it does not understand a CreateFile on a
// server name. This is valid in case of a DAV server since \\server maps
// to the root http://www.foo.com/.
//
TempName = wcschr( &(ReturnedUncName[2]), L'\\' );
if (TempName == NULL) {
//
// We need to add a dummy share. We are assuming that space for
// storing DAV_DUMMY_SHARE name is already allocated above.
//
ReturnedUncName[ReturnedUncNameLen] = L'\\';
ReturnedUncName[ReturnedUncNameLen+1] = L'\0';
wcscpy( &(ReturnedUncName[ReturnedUncNameLen+1]), DAV_DUMMY_SHARE );
ReturnedUncNameLen += DummyShareNameLen;
ReturnedUncName[ReturnedUncNameLen] = L'\0';
}
}
IF_DEBUG_PRINT(DEBUG_MISC,
("DavCheckAndConvertSrvNameUrlToUncName: RemoteName = %ws\n",
ReturnedUncName));
//
// At this point, any URL remotename is already converted to UNC name +
// DAV_DUMMY_SHARE is added to the remote name (if asked so).
//
if (bCanonicalize == TRUE) {
DAV_REMOTENAME_TYPE nameType = DAV_REMOTENAME_TYPE_INVALID;
//
// Allocate another buffer to contain canonicalize name
//
CanonicalName = NULL;
CanonicalNameMaxLen = MAX_PATH + 1;
CanonicalName = LocalAlloc( (LMEM_FIXED | LMEM_ZEROINIT),
( CanonicalNameMaxLen * sizeof(WCHAR) ) );
if (CanonicalName == NULL) {
WStatus = GetLastError();
IF_DEBUG_PRINT(DEBUG_ERRORS,
("ERROR: DavCheckAndConvertSrvNameUrlToUncName/LocalAlloc. "
"WStatus = %08lx\n", WStatus));
goto EXIT_THE_FUNCTION;
}
nameType = DavParseRemoteName (ReturnedUncName,
CanonicalName,
(CanonicalNameMaxLen * sizeof(WCHAR)),
pathOffset);
CanonicalName[(CanonicalNameMaxLen - 1)] = L'\0';
//
// We will allow only UNC names of type UNC-server, UNC-share or
// UNC-path to pass from this function. All other type of names returned
// from canonicalization will rejected (function will return failure
// status) as INVALID_NAMES.
//
if (nameType != DAV_REMOTENAME_TYPE_SERVER &&
nameType != DAV_REMOTENAME_TYPE_SHARE &&
nameType != DAV_REMOTENAME_TYPE_PATH) {
WStatus = WN_BAD_NETNAME;
IF_DEBUG_PRINT(DEBUG_ERRORS,
("ERROR: DavCheckAndConvertSrvNameUrlToUncName/DavParseRemoteName. "
"nameType = %d\n", nameType));
goto EXIT_THE_FUNCTION;
}
//
// Free the previous buffer allocate in ReturnedUncName and point
// this variable to new canonical name just allocated here.
//
LocalFree((HLOCAL)ReturnedUncName);
ReturnedUncName = NULL;
ReturnedUncNameLen = 0;
didAllocate = FALSE;
ReturnedUncName = CanonicalName;
ReturnedUncNameLen = wcslen(CanonicalName);
didAllocate = TRUE;
CanonicalName = NULL;
if (premNameType != NULL) {
*premNameType = nameType;
}
}
if ( ReturnedUncNameLen > MAX_PATH ) {
WStatus = WN_BAD_NETNAME;
IF_DEBUG_PRINT(DEBUG_ERRORS,
("ERROR: DavCheckAndConvertSrvNameUrlToUncName. ReturnedUncNameLen=%d ",
ReturnedUncNameLen));
goto EXIT_THE_FUNCTION;
}
*UncRemoteName = ReturnedUncName;
*MemoryAllocated = didAllocate;
WStatus = ERROR_SUCCESS;
EXIT_THE_FUNCTION:
if (WStatus != ERROR_SUCCESS) {
if (ReturnedUncName && didAllocate) {
LocalFree(ReturnedUncName);
ReturnedUncName = NULL;
didAllocate = FALSE;
}
if (CanonicalName != NULL) {
LocalFree(CanonicalName);
CanonicalName = NULL;
}
}
return WStatus;
}
DWORD
WINAPI
DavWinlogonLogonUserEvent(
LPVOID lpParam
)
/*++
Routine Description:
The routine is called by winlogon when a user logs on to the system.
Arguments:
lpParam - This is of no interest to us.
Returns:
ERROR_SUCCESS if all went well, otherwise the appropriate error code.
--*/
{
ULONG WStatus = ERROR_SUCCESS;
BOOL bindRpcHandle = FALSE;
handle_t dav_binding_h;
IF_DEBUG_PRINT(DEBUG_ENTRY, ("DavWinlogonLogonUserEvent: Entered\n"));
//
// If the WebClient service is not running we bail out right away.
//
if ( !DavWorkstationStarted() ) {
IF_DEBUG_PRINT(DEBUG_ERRORS,
("ERROR: DavWinlogonLogonUserEvent/DavWorkstationStarted. "
"Service NOT Running\n"));
WStatus = WN_NO_NETWORK;
goto EXIT_THE_FUNCTION;
}
WStatus = DavBindTheRpcHandle( &(dav_binding_h) );
if (WStatus != ERROR_SUCCESS) {
IF_DEBUG_PRINT(DEBUG_ERRORS,
("ERROR: DavWinlogonLogonUserEvent/DavBindTheRpcHandle. "
"WStatus = %08lx\n", WStatus));
WStatus = WN_NO_NETWORK;
goto EXIT_THE_FUNCTION;
}
bindRpcHandle = TRUE;
RpcTryExcept {
WStatus = DavrWinlogonLogonEvent(dav_binding_h);
if (WStatus != NO_ERROR) {
IF_DEBUG_PRINT(DEBUG_ERRORS,
("ERROR: DavWinlogonLogonUserEvent/DavrWinlogonLogonEvent. "
"WStatus = %08lx\n", WStatus));
SetLastError(WStatus);
goto EXIT_THE_FUNCTION;
}
} RpcExcept (I_RpcExceptionFilter(RpcExceptionCode())) {
RPC_STATUS RpcStatus;
RpcStatus = RpcExceptionCode();
IF_DEBUG_PRINT(DEBUG_ERRORS,
("ERROR: DavWinlogonLogonUserEvent/DavrWinlogonLogonEvent. "
" RpcExceptionCode = %d\n", RpcStatus));
WStatus = DavMapRpcErrorToProviderError(RpcStatus);
goto EXIT_THE_FUNCTION;
}
RpcEndExcept
EXIT_THE_FUNCTION:
if (bindRpcHandle) {
RpcBindingFree( &(dav_binding_h) );
}
return WStatus;
}
DWORD
WINAPI
DavWinlogonLogoffUserEvent(
LPVOID lpParam
)
/*++
Routine Description:
The routine is called by winlogon when a user logs off the system.
Arguments:
lpParam - This is of no interest to us.
Returns:
ERROR_SUCCESS if all went well, otherwise the appropriate error code.
Notes:
--*/
{
ULONG WStatus = ERROR_SUCCESS;
BOOL bindRpcHandle = FALSE;
handle_t dav_binding_h;
IF_DEBUG_PRINT(DEBUG_ENTRY, ("DavWinlogonLogoffUserEvent: Entered\n"));
//
// If the WebClient service is not running we bail out right away.
//
if ( !DavWorkstationStarted() ) {
IF_DEBUG_PRINT(DEBUG_ERRORS,
("ERROR: DavWinlogonLogoffUserEvent/DavWorkstationStarted. "
"Service NOT Running\n"));
WStatus = WN_NO_NETWORK;
goto EXIT_THE_FUNCTION;
}
WStatus = DavBindTheRpcHandle( &(dav_binding_h) );
if (WStatus != ERROR_SUCCESS) {
IF_DEBUG_PRINT(DEBUG_ERRORS,
("ERROR: DavWinlogonLogoffUserEvent/DavBindTheRpcHandle. "
"WStatus = %08lx\n", WStatus));
WStatus = WN_NO_NETWORK;
goto EXIT_THE_FUNCTION;
}
bindRpcHandle = TRUE;
RpcTryExcept {
WStatus = DavrWinlogonLogoffEvent(dav_binding_h);
if (WStatus != NO_ERROR) {
IF_DEBUG_PRINT(DEBUG_ERRORS,
("ERROR: DavWinlogonLogoffUserEvent/DavrWinlogonLogoffEvent. "
"WStatus = %08lx\n", WStatus));
SetLastError(WStatus);
goto EXIT_THE_FUNCTION;
}
} RpcExcept (I_RpcExceptionFilter(RpcExceptionCode())) {
RPC_STATUS RpcStatus;
RpcStatus = RpcExceptionCode();
IF_DEBUG_PRINT(DEBUG_ERRORS,
("ERROR: DavWinlogonLogoffUserEvent/DavrWinlogonLogoffEvent. "
" RpcExceptionCode = %d\n", RpcStatus));
WStatus = DavMapRpcErrorToProviderError(RpcStatus);
goto EXIT_THE_FUNCTION;
}
RpcEndExcept
EXIT_THE_FUNCTION:
if (bindRpcHandle) {
RpcBindingFree( &(dav_binding_h) );
}
return WStatus;
}
VOID
DavDisplayNetResource(
LPNETRESOURCE netRes,
LPWSTR dispMesg
)
/*++
Routine Description:
The routine prints out the contents of an NetResource and a display message.
Arguments:
netRes - The NetResource whose contents will be printed out.
dispMesg - The caller can use this to identify itself.
Returns:
None.
--*/
{
if(dispMesg != NULL ) {
IF_DEBUG_PRINT(DEBUG_ENTRY, ("DavDisplayNetResource: Entered: %ws\n", dispMesg));
}
IF_DEBUG_PRINT(DEBUG_MISC, ("netRes = 0x%x\n", netRes));
if (netRes == NULL) {
return;
}
IF_DEBUG_PRINT(DEBUG_MISC,
("netRes->[dwScope = 0x%x , dwType = 0x%x ,"
" dwUsage = 0x%x , dwDisplayType = 0x%x]\n",
netRes->dwScope, netRes->dwType, netRes->dwUsage,
netRes->dwDisplayType));
IF_DEBUG_PRINT(DEBUG_MISC,
("netRes->[dwLocalName = %ws , dwRemoteName = %ws ,"
" dwComment = %ws , dwProvider = %ws]\n",
netRes->lpLocalName, netRes->lpRemoteName, netRes->lpComment,
netRes->lpProvider));
return;
}
VOID
DavDisplayEnumNode(
PDAV_ENUMNODE enumNode,
LPWSTR dispMesg
)
/*++
Routine Description:
The routine prints out the contents of an enumNode and a display message.
Arguments:
enumNode - The enumNode whose contents will be printed out.
dispMesg - The caller can use this to identify itself.
Returns:
None.
--*/
{
if(dispMesg != NULL ) {
IF_DEBUG_PRINT(DEBUG_ENTRY, ("DavDisplayEnumNode: Entered: %ws\n", dispMesg));
}
IF_DEBUG_PRINT(DEBUG_MISC, ("enumNode = 0x%x\n", enumNode));
if (enumNode == NULL) {
return;
}
IF_DEBUG_PRINT(DEBUG_MISC,
("enumNode->[dwScope = 0x%x , dwType = 0x%x ,"
" dwUsage = 0x%x , DavEnumNodeType = %d ,"
" Done = %d , Index = %d]\n",
enumNode->dwScope, enumNode->dwType, enumNode->dwUsage,
enumNode->DavEnumNodeType, enumNode->Done,
enumNode->Index));
DavDisplayNetResource(enumNode->lpNetResource, L"lpNetResource in enumNode");
return;
}
VOID DavDebugBreakPoint(
VOID
)
/*++
Routine Description:
The routine is used for debugging purposes to add breakpoints where needed.
Arguments:
None.
Returns:
None.
--*/
{
IF_DEBUG_PRINT(DEBUG_ENTRY, ("DavDebugBreakPoint.\n"));
return;
}
DWORD
APIENTRY
DavGetDiskSpaceUsage(
LPWSTR lptzLocation,
DWORD *lpdwSize,
ULARGE_INTEGER *lpMaxSpace,
ULARGE_INTEGER *lpUsedSpace
)
/*++
Routine Description:
Finds out the amount of disk being consumed by wininet urlcache due to
Webdav.
Arguments:
lptzLocation - Buffer to return Cache location string. As much of the
location string as can fit in the buffer is returned.
lpdwSize - Size of the cache location buffer. On return this will contain
the actual size of the location string.
lpMaxSpace - Size of disk Quota set for webdav.
lpUsedSpace - Size of disk consumed by the urlcache used by webdav.
Return Value:
Win32 error code.
--*/
{
DWORD dwError;
BOOL bindRpcHandle = FALSE;
handle_t dav_binding_h;
WCHAR Buffer[MAX_PATH];
DWORD dwSize;
dwError = DavBindTheRpcHandle( &(dav_binding_h) );
if (dwError != ERROR_SUCCESS) {
IF_DEBUG_PRINT(DEBUG_ERRORS,
("ERROR: DavrDiskSpaceUsage/DavBindTheRpcHandle. "
"dwError = %08lx\n", dwError));
goto EXIT_THE_FUNCTION;
}
bindRpcHandle = TRUE;
RpcTryExcept {
dwError = DavrGetDiskSpaceUsage(dav_binding_h, Buffer, MAX_PATH, &dwSize, lpMaxSpace, lpUsedSpace);
if (dwError == ERROR_SUCCESS) {
memset(lptzLocation, 0, *lpdwSize);
memcpy(lptzLocation, Buffer, min(*lpdwSize, dwSize));
*lpdwSize = dwSize;
}
} RpcExcept (I_RpcExceptionFilter(RpcExceptionCode())) {
RPC_STATUS RpcStatus;
RpcStatus = RpcExceptionCode();
IF_DEBUG_PRINT(DEBUG_ERRORS, ("ERROR: DavrGetDiskSpaceUsage/DavrGetDiskSpaceUsage."
" RpcExceptionCode = %d\n", RpcStatus));
dwError = DavMapRpcErrorToProviderError(RpcStatus);
goto EXIT_THE_FUNCTION;
}
RpcEndExcept
EXIT_THE_FUNCTION:
if (bindRpcHandle) {
RpcBindingFree( &(dav_binding_h) );
bindRpcHandle = FALSE;
}
return dwError;
}
DWORD
APIENTRY
DavFreeUsedDiskSpace(
DWORD dwPercent
)
/*++
Routine Description:
Frees up dwPercent of the local persistent cache.
Arguments:
dwPercent - A number between 0 and 100.
Returns:
ERROR_SUCCESS if successful, else returns the win32 errorcode.
--*/
{
DWORD dwError;
BOOL bindRpcHandle = FALSE;
handle_t dav_binding_h;
dwError = DavBindTheRpcHandle( &(dav_binding_h) );
if (dwError != ERROR_SUCCESS) {
IF_DEBUG_PRINT(DEBUG_ERRORS,
("ERROR: DavFreeUsedDiskSpace/DavBindTheRpcHandle. "
"dwError = %08lx\n", dwError));
goto EXIT_THE_FUNCTION;
}
bindRpcHandle = TRUE;
RpcTryExcept {
DavrFreeUsedDiskSpace(dav_binding_h, dwPercent);
} RpcExcept (I_RpcExceptionFilter(RpcExceptionCode())) {
RPC_STATUS RpcStatus;
RpcStatus = RpcExceptionCode();
IF_DEBUG_PRINT(DEBUG_ERRORS, ("ERROR: DavFreeUsedDiskSpace/DavrFreeUsedDiskSpace."
" RpcExceptionCode = %d\n", RpcStatus));
dwError = DavMapRpcErrorToProviderError(RpcStatus);
goto EXIT_THE_FUNCTION;
}
RpcEndExcept
EXIT_THE_FUNCTION:
if (bindRpcHandle) {
RpcBindingFree( &(dav_binding_h) );
bindRpcHandle = FALSE;
}
return dwError;
}
DWORD
DavGetTheLockOwnerOfTheFile(
IN PWCHAR FileName,
OUT PWCHAR LockOwnerName,
IN OUT PULONG LockOwnerNameLengthInBytes
)
/*++
Routine Description:
This routine is called by applications to find out who owns the LOCK on
a particular file. When the CreateFile call fails with ERROR_LOCK_VIOLATION
applications can call this API to find out who the owner is and display
that information to the user.
Arguments:
FileName - The name of the file which is LOCKed on the server. The caller
fills in this value. This should be a NULL terminated string. So,
((1 + wcslen(FileName)) * sizeof(WCHAR)) should give the length
of the FileName (including the final L'\0' char) in bytes.
LockOwnerName - On success, the API fills in the name of the person who owns
the LOCK on the file. The caller is responsible for
allocating memory for this pointer.
LockOwnerNameLengthInBytes - Contains the length of the LockOwnerName
buffer in bytes. If the buffer length is not
enough to fill in the LockOwners name, the
return value is ERROR_INSUFFICIENT_BUFFER
and this pointer contains the size of the
buffer needed.
Returns:
ERROR_SUCCESS - The call was successful. The LockOwnerName buffer contains
the name of the person who owns the lock.
ERROR_INSUFFICIENT_BUFFER - The LockOwnerName buffer was not of the
required length. LockOwnerNameLengthInBytes
contains the length in bytes needed to hold
this buffer.
Some other Win32 error code.
--*/
{
ULONG WStatus = ERROR_SUCCESS;
BOOL bindRpcHandle = FALSE;
handle_t dav_binding_h;
PWCHAR OutputBuffer = NULL;
ULONG OutputBufferLengthInBytes = 0, count = 0;
//
// Perform some basic checks first.
//
if (FileName == NULL) {
WStatus = ERROR_INVALID_PARAMETER;
goto EXIT_THE_FUNCTION;
}
if ( (LockOwnerName == NULL) && (*LockOwnerNameLengthInBytes != 0) ) {
WStatus = ERROR_INVALID_PARAMETER;
goto EXIT_THE_FUNCTION;
}
WStatus = DavBindTheRpcHandle( &(dav_binding_h) );
if (WStatus != ERROR_SUCCESS) {
IF_DEBUG_PRINT(DEBUG_ERRORS,
("ERROR: DavGetTheLockOwnerOfTheFile/DavBindTheRpcHandle. "
"WStatus = %08lx\n", WStatus));
WStatus = WN_NO_NETWORK;
goto EXIT_THE_FUNCTION;
}
bindRpcHandle = TRUE;
RpcTryExcept {
WStatus = DavrGetTheLockOwnerOfTheFile(dav_binding_h, FileName, &(OutputBuffer));
if (WStatus != NO_ERROR) {
//
// We have supplied a buffer that should be big enough for any
// LockOwner string. Hence we should never get back the following
// error code.
//
ASSERT(WStatus != ERROR_INSUFFICIENT_BUFFER);
IF_DEBUG_PRINT(DEBUG_ERRORS,
("ERROR: DavGetTheLockOwnerOfTheFile/DavrGetTheLockOwnerOfTheFile. "
"WStatus = %08lx\n", WStatus));
SetLastError(WStatus);
goto EXIT_THE_FUNCTION;
}
} RpcExcept (I_RpcExceptionFilter(RpcExceptionCode())) {
RPC_STATUS RpcStatus;
RpcStatus = RpcExceptionCode();
IF_DEBUG_PRINT(DEBUG_ERRORS,
("ERROR: DavGetTheLockOwnerOfTheFile/DavrGetTheLockOwnerOfTheFile. "
" RpcExceptionCode = %d\n", RpcStatus));
WStatus = DavMapRpcErrorToProviderError(RpcStatus);
goto EXIT_THE_FUNCTION;
}
RpcEndExcept
OutputBufferLengthInBytes = ( (1 + wcslen(OutputBuffer)) * sizeof(WCHAR) );
//
// Make sure that the buffer supplied by the caller is large enough to hold
// the LockOwner string. If its not, fill in the needed bytes in the
// LockOwnerNameLengthInBytes pointer and retrun the error code
// ERROR_INSUFFICIENT_BUFFER.
//
if ( (LockOwnerName == NULL) || (OutputBufferLengthInBytes > *LockOwnerNameLengthInBytes) ) {
WStatus = ERROR_INSUFFICIENT_BUFFER;
*LockOwnerNameLengthInBytes = OutputBufferLengthInBytes;
goto EXIT_THE_FUNCTION;
}
//
// Copy the LockOwner in the LockOwnerName buffer supplied by the
// caller.
//
wcsncpy(LockOwnerName, OutputBuffer, OutputBufferLengthInBytes);
WStatus = ERROR_SUCCESS;
EXIT_THE_FUNCTION:
if (bindRpcHandle) {
RpcBindingFree( &(dav_binding_h) );
}
//
// The memory for OutputBuffer was allocated by the RPC client stub
// based on the string returned by the RPC server. We need to free
// it now if we came down an error path after calling the server.
//
if (OutputBuffer != NULL) {
MIDL_user_free(OutputBuffer);
OutputBuffer = NULL;
}
return WStatus;
}
//
// The functions below are a part of the NP spec but have NOT been implemented
// by the DAV NP. We do not claim to support these in the NPGetCaps function.
//
#if 0
DWORD
NPGetPropertyText(
DWORD iButtonDlg,
DWORD nPropSel,
LPTSTR lpFileName,
LPTSTR lpButtonName,
DWORD cchButtonName,
DWORD nType
)
/*++
Routine Description:
This function is used to determine the names of buttons added to a property
dialog for some particular resources. It is called every time such a dialog
is brought up, and prior to displaying the dialog. If the user clicks a
button added through this API by the Winnet provider, NPPropertyDialog will
be called with the appropriate parameters.
Arguments:
iButtonDlg - Indicates the index (starting at 0) of the button. The File
Manager will support at most 6 buttons. The parameter is
numbered 1-6 for each of the possible buttons if only one file
is selected, or 11-16 if multiple files are selected.
nPropSel - Specifies what items the property dialog focuses on. It can be
one of the following values:
WNPS_FILE (0) - Single file.
WNPS_DIR (1) - Single directory.
WNPS_MULT (2) - Multiple selection of files and/or directories.
lpFileName - Specifies the names of the item or items to be viewed or edited
by the dialog. Currently, the items are files (and directories),
so the item names are file names. These will be unambiguous,
contain no wildcard characters and will be fully qualified
(e.g., C:\LOCAL\FOO.BAR). Multiple filenames will be separated
with spaces. Any filename may be quoted (e.g., "C:\My File") in
which case it will be treated as a single name. The caret
character '^' may also be used as the quotation mechanism for
single characters (e.g., C:\My^"File, "C:\My^"File" both refer
to the file C:\My"File).
lpButtonName - Points to a buffer where the Winnet provider should copy the
name of the property button. On success, the buffer pointed
to by lpButtonName will contain the name of the property
button. If this buffer, on exit, contains the empty string,
then the corresponding button and all succeeding buttons will
be removed from the dialog box. The network provider cannot
"skip" a button.
cchButtonName - Specifies the size of the lpButtonName buffer in characters.
nType - Specifies the item type. Currently, only WNTYPE_FILE will be used.
Return Value:
WN_SUCCESS - If the call is successful and lpButtonName can be used.
WN_OUT_OF_MEMORY - Couldn't load string from resources.
WN_MORE_DATA - The given buffer is too small to fit the text of the button.
WN_BAD_VALUE - The lpFileName parameter takes an unexpected form.
WN_NOT_SUPPORTED - Property dialogs are not supported for the given object
type (nType).
--*/
{
IF_DEBUG_PRINT(DEBUG_ENTRY, ("NPGetPropertyText Entered.\n"));
return WN_NOT_SUPPORTED;
}
DWORD
NPPropertyDialog(
HWND hwndParent,
DWORD iButtonDlg,
DWORD nPropSel,
LPTSTR lpFileName,
DWORD nType
)
/*++
Routine Description:
This function is called out to when the user clicks a button added through
the NPGetPropertyText API. Currently, this will only be called for file and
directory network properties.
Arguments:
hwndParent - Specifies the parent window which should own the file property
dialog.
iButtonDlg - Indicates the index (starting at 0) of the button that was
pressed.
nPropSel - Specifies what items the property dialog should act on. It can be
one of the following values:
WNPS_FILE (0) - Single file.
WNPS_DIR (1) - Single directory.
WNPS_MULT (2) - Multiple selection of files and/or directories.
lpFileName - Points to the names of the items that the property dialog
should act on. See the NPGetPropertyText API for a description
of the format of what lpFileName points to.
nType - Specifies the item type. Currently, only WNTYPE_FILE will be used.
Return Value:
WN_SUCCESS - If the call is successful. Otherwise, the an error code is
returned which can be one of the following:
WN_BAD_VALUE - Some parameter takes an unexpected form or value.
WN_OUT_OF_MEMORY - Not enough memory to display the dialog.
WN_NET_ERROR - Some other network error occurred.
--*/
{
IF_DEBUG_PRINT(DEBUG_ENTRY, ("NPPropertyDialog Entered.\n"));
return WN_NET_ERROR;
}
DWORD
NPSearchDialog(
HWND hParent,
LPNETRESOURCE lpNetResource,
LPVOID lpBuffer,
DWORD cbBuffer,
LPDWORD lpnFlags
)
/*++
Routine Description:
This dialog allows network provider to supply its own form of browsing and
search beyond the hierarchical view presented in the Connection Dialog.
Arguments:
hwnd - Specifies the handle of the window that will be used as the dialog
box's parent.
lpNetResource - Specifies the currently selected item in the Network
connections dialog. A provider may choose to ignore this
field.
lpBuffer - Pointer to buffer that will receive the result of the search.
cbBuffer - DWORD that will specify size of buffer passed in.
lpnFlags - Pointer to a DWORD of flags which the provider can set to force
certain actions after the dialog is dismissed. It can be one of:
WNSRCH_REFRESH_FIRST_LEVEL - Forces MPR to collapse then expand
(and refresh) the first level below
this provider after the dialog is
dismissed.
Return Value:
WN_SUCCESS - If the call is successful.
WN_CANCEL - If user cancelled the operation.
WN_MORE_DATA - If input buffer is too small.
--*/
{
IF_DEBUG_PRINT(DEBUG_ENTRY, ("NPSearchDialog Entered.\n"));
return WN_CANCEL;
}
DWORD
NPGetDirectoryType (
LPTSTR lpName,
LPINT lpType,
BOOL bFlushCache
)
/*++
Routine Description:
This function is used by the file manager to determine the type of a
network directory.
Arguments:
lpName - This parameter points to the fully qualified name of the directory.
The network provider returns the type to the word pointed to by
lpType. If the value returned in lpType is 0 or if the network
provider returns an error, the File Manager displays the directory
as a "normal" directory.
lpType - This is defined by the network provider and is used to modify the
display of the drive tree in the File Manager. In this way, the
network provider can show special directories to the user.
bFlushCache - This is set to TRUE when the File Manager call MPR to get the
directory type for the first time while repainting a window on
Refresh. Subsequently, it will be FALSE. This gives a provider
the opportunity to optimize performance if it wishes to just
read the data for a drive once and cache it until the next
Refresh.
Return Value:
WN_SUCCESS - If the call is successful.
WN_NOT_SUPPORTED - This function is not supported.
--*/
{
IF_DEBUG_PRINT(DEBUG_ENTRY, ("NPGetDirectoryType Entered.\n"));
return WN_NOT_SUPPORTED;
}
DWORD
NPDirectoryNotify(
HWND hwnd,
LPTSTR lpDir,
DWORD dwOper
)
/*++
Routine Description:
This function is used by the File Manager to notify the network provider of
certain directory operations. This function can be used to perform special
behaviour for certain directories.
Arguments:
hwnd - Specifies an owner window handle in the event the network provider
needs to interact with the user.
lpDir - This points to the fully qualified name of the directory.
dwOper - Indicates the operation. If dwOper is WNDN_MKDIR (1), then the File
Manager is about to create a directory with the given name. If
dwOper WNDN_RMDIR (2), the File Manager is about the remove the
directory. dwOper may also be WNDN_MVDIR (3) to indicate that the
directory is about to be renamed.
Return Value:
WN_SUCCESS - If the call is successful. This indicates to the caller that it
should continue and perform the operation. Otherwise, the
appropriate code is returned, which may include:
WN_CANCELLED - The provider would have handled the operation, but the user
cancelled it. The caller should NOT perform the operation.
WN_CONTINUE - The network provider handled the operation, the caller should
proceed normally but do not perform the operation.
WN_NOT_SUPPORTED - The network does not have special directory handling,
this is treated as WN_SUCCESS.
--*/
{
IF_DEBUG_PRINT(DEBUG_ENTRY, ("NPDirectoryNotify Entered.\n"));
return WN_NOT_SUPPORTED;
}
DWORD
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. The information
returned may be an estimate. Note that if the network cannot obtain
information about the resource on the network, then it can return
information about the network adaptor and its associated performance,
setting dwFlags accordingly.
Arguments:
lpRemoteName - Contains the local name or remote name for a resource for
which a connection exists.
lpNetConnectInfo - This is is a pointer to a NETCONNECTINFOSTRUCT structure
which is filled in by the net provider if the provider
has a connection to the network resource. With the
exception of the cbStructure field, all other fields are
zero filled before MPR.DLL passes the request on to the
net providers, and the provider only has to write to
fields for which it has information available. Also, for
rate values, a value of 1 means that the performance is
better than can be represented in the unit.
Return Value:
WN_SUCCESS - If the call is successful. Otherwise, the an error code is
returned, which may include:
WN_NOT_CONNECTED - lpRemoteName is not a connected network resource.
WN_NO_NETWORK - Network is not present.
--*/
{
IF_DEBUG_PRINT(DEBUG_ENTRY, ("NPGetConnectionPerformance Entered.\n"));
//
// BUGBUG: why is this function supported at all ?? It can result in error
// if a connection is created and checked for its existence.
//
// LOOK HERE: Not supported for now: return WN_NOT_CONNECTED;
return WN_NOT_SUPPORTED;
}
#endif // #if 0