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.
 
 
 
 
 
 

1727 lines
47 KiB

/*++
Copyright (c) 1989-1999 Microsoft Corporation
Module Name:
smbmrxnp.c
Abstract:
This module implements the routines required for interaction with network
provider router interface in NT
Notes:
This module has been builkt and tested only in UNICODE environment
--*/
#include <windows.h>
#include <windef.h>
#include <winbase.h>
#include <winsvc.h>
#include <winnetwk.h>
#include <npapi.h>
#include <lmwksta.h>
#include <devioctl.h>
// include files from the smb inc directory
#include <smbmrx.h>
#ifndef UNICODE_STRING
typedef struct _UNICODE_STRING {
USHORT Length;
USHORT MaximumLength;
PWSTR Buffer;
} UNICODE_STRING;
typedef UNICODE_STRING *PUNICODE_STRING;
#endif
#ifndef FILE_FULL_EA_INFORMATION
typedef struct _FILE_FULL_EA_INFORMATION {
ULONG NextEntryOffset;
UCHAR Flags;
UCHAR EaNameLength;
USHORT EaValueLength;
CHAR EaName[1];
} FILE_FULL_EA_INFORMATION, *PFILE_FULL_EA_INFORMATION;
#endif
#define MAX_EA_NAME_LEN sizeof("UserName\0")
#define MAX_CONNECT_INFO_SIZE \
3 * sizeof(FILE_FULL_EA_INFORMATION) + \
sizeof(SMBMRX_CONNECTINFO) + \
4 * MAX_PATH + \
3 * MAX_EA_NAME_LEN
typedef struct _SMBMRXNP_ENUMERATION_HANDLE_ {
INT LastIndex;
} SMBMRXNP_ENUMERATION_HANDLE,
*PSMBMRXNP_ENUMERATION_HANDLE;
#ifdef DBG
#define DbgP(_x_) DbgPrint _x_
#else
#define DbgP(_x_)
#endif
ULONG _cdecl DbgPrint( LPTSTR Format, ... );
#define TRACE_TAG L"SMBMRXNP: "
// The debug level for this module
// the SMB mini redirector and provider name. The original constants
// are defined in smbmrx.h
UNICODE_STRING SmbMRxDeviceName = {
sizeof(DD_SMBMRX_FS_DEVICE_NAME_U),
sizeof(DD_SMBMRX_FS_DEVICE_NAME_U),
DD_SMBMRX_FS_DEVICE_NAME_U
};
UNICODE_STRING SmbMrxProviderName = {
sizeof(SMBMRX_PROVIDER_NAME_U),
sizeof(SMBMRX_PROVIDER_NAME_U),
SMBMRX_PROVIDER_NAME_U
};
DWORD
OpenSharedMemory(
PHANDLE phMutex,
PHANDLE phMemory,
PVOID *pMemory
)
/*++
Routine Description:
This routine opens the shared memory for exclusive manipulation
Arguments:
phMutex - the mutex handle
phMemory - the memory handle
pMemory - a ptr. to the shared memory which is set if successful
Return Value:
WN_SUCCESS -- if successful
--*/
{
DWORD dwStatus;
DbgP((TEXT("OpenSharedMemory\n")));
*phMutex = 0;
*phMemory = 0;
*pMemory = NULL;
*phMutex = OpenMutex(SYNCHRONIZE,
FALSE,
SMBMRXNP_MUTEX_NAME);
if (*phMutex == NULL)
{
dwStatus = GetLastError();
DbgP((TEXT("OpenSharedMemory: OpenMutex failed\n")));
goto OpenSharedMemoryAbort1;
}
DbgP((TEXT("OpenSharedMemory: Calling WaitForSingleObject\n")));
WaitForSingleObject(*phMutex, INFINITE);
*phMemory = OpenFileMapping(FILE_MAP_WRITE,
FALSE,
SMBMRXNP_SHARED_MEMORY_NAME);
if (*phMemory == NULL)
{
dwStatus = GetLastError();
DbgP((TEXT("OpenSharedMemory: OpenFileMapping failed\n")));
goto OpenSharedMemoryAbort2;
}
*pMemory = MapViewOfFile(*phMemory, FILE_MAP_WRITE, 0, 0, 0);
if (*pMemory == NULL)
{
dwStatus = GetLastError();
DbgP((TEXT("OpenSharedMemory: MapViewOfFile failed\n")));
goto OpenSharedMemoryAbort3;
}
DbgP((TEXT("OpenSharedMemory: return ERROR_SUCCESS\n")));
return ERROR_SUCCESS;
OpenSharedMemoryAbort3:
CloseHandle(*phMemory);
OpenSharedMemoryAbort2:
ReleaseMutex(*phMutex);
CloseHandle(*phMutex);
*phMutex = NULL;
OpenSharedMemoryAbort1:
DbgP((TEXT("OpenSharedMemory: return dwStatus: %d\n"), dwStatus));
return dwStatus;
}
VOID
CloseSharedMemory(
PHANDLE hMutex,
PHANDLE hMemory,
PVOID *pMemory )
/*++
Routine Description:
This routine relinquishes control of the shared memory after exclusive
manipulation
Arguments:
hMutex - the mutex handle
hMemory - the memory handle
pMemory - a ptr. to the shared memory which is set if successful
Return Value:
--*/
{
DbgP((TEXT("CloseSharedMemory\n")));
if (*pMemory)
{
UnmapViewOfFile(*pMemory);
*pMemory = NULL;
}
if (*hMemory)
{
CloseHandle(*hMemory);
*hMemory = 0;
}
if (*hMutex)
{
if (ReleaseMutex(*hMutex) == FALSE)
{
DbgP((TEXT("CloseSharedMemory: ReleaseMutex error: %d\n"), GetLastError()));
}
CloseHandle(*hMutex);
*hMutex = 0;
}
DbgP((TEXT("CloseSharedMemory: Return\n")));
}
DWORD APIENTRY
NPGetCaps(
DWORD nIndex )
/*++
Routine Description:
This routine returns the capabilities of the SMB Mini redirector
network provider implementation
Arguments:
nIndex - category of capabilities desired
Return Value:
the appropriate capabilities
--*/
{
switch (nIndex)
{
case WNNC_SPEC_VERSION:
return WNNC_SPEC_VERSION51;
case WNNC_NET_TYPE:
return WNNC_NET_RDR2_SAMPLE;
case WNNC_DRIVER_VERSION:
#define WNNC_DRIVER(major,minor) (major*0x00010000 + minor)
return WNNC_DRIVER(1, 0);
case WNNC_CONNECTION:
return WNNC_CON_GETCONNECTIONS | WNNC_CON_CANCELCONNECTION |
WNNC_CON_ADDCONNECTION | WNNC_CON_ADDCONNECTION3;
case WNNC_ENUMERATION:
return WNNC_ENUM_LOCAL;
case WNNC_START:
case WNNC_USER:
case WNNC_DIALOG:
case WNNC_ADMIN:
default:
return 0;
}
}
DWORD APIENTRY
NPLogonNotify(
PLUID lpLogonId,
LPCWSTR lpAuthentInfoType,
LPVOID lpAuthentInfo,
LPCWSTR lpPreviousAuthentInfoType,
LPVOID lpPreviousAuthentInfo,
LPWSTR lpStationName,
LPVOID StationHandle,
LPWSTR *lpLogonScript)
/*++
Routine Description:
This routine handles the logon notifications
Arguments:
lpLogonId -- the associated LUID
lpAuthenInfoType - the authentication information type
lpAuthenInfo - the authentication Information
lpPreviousAuthentInfoType - the previous aunthentication information type
lpPreviousAuthentInfo - the previous authentication information
lpStationName - the logon station name
LPVOID - logon station handle
lpLogonScript - the logon script to be executed.
Return Value:
WN_SUCCESS
Notes:
This capability has not been implemented in the sample.
--*/
{
*lpLogonScript = NULL;
return WN_SUCCESS;
}
DWORD APIENTRY
NPPasswordChangeNotify (
LPCWSTR lpAuthentInfoType,
LPVOID lpAuthentInfo,
LPCWSTR lpPreviousAuthentInfoType,
LPVOID lpPreviousAuthentInfo,
LPWSTR lpStationName,
LPVOID StationHandle,
DWORD dwChangeInfo )
/*++
Routine Description:
This routine handles the password change notifications
Arguments:
lpAuthenInfoType - the authentication information type
lpAuthenInfo - the authentication Information
lpPreviousAuthentInfoType - the previous aunthentication information type
lpPreviousAuthentInfo - the previous authentication information
lpStationName - the logon station name
LPVOID - logon station handle
dwChangeInfo - the password change information.
Return Value:
WN_NOT_SUPPORTED
Notes:
This capability has not been implemented in the sample.
--*/
{
SetLastError(WN_NOT_SUPPORTED);
return WN_NOT_SUPPORTED;
}
DWORD APIENTRY
NPOpenEnum(
DWORD dwScope,
DWORD dwType,
DWORD dwUsage,
LPNETRESOURCE lpNetResource,
LPHANDLE lphEnum )
/*++
Routine Description:
This routine opens a handle for enumeration of resources. The only capability
implemented in the sample is for enumerating connected shares
Arguments:
dwScope - the scope of enumeration
dwType - the type of resources to be enumerated
dwUsage - the usage parameter
lpNetResource - a pointer to the desired NETRESOURCE struct.
lphEnum - aptr. for passing nack the enumeration handle
Return Value:
WN_SUCCESS if successful, otherwise the appropriate error
Notes:
The sample only supports the notion of enumerating connected shares
The handle passed back is merely the index of the last entry returned
--*/
{
DWORD Status = 0;
DbgP((TEXT("NPOpenEnum\n")));
*lphEnum = NULL;
switch (dwScope)
{
case RESOURCE_CONNECTED:
{
*lphEnum = LocalAlloc(
LMEM_ZEROINIT,
sizeof(SMBMRXNP_ENUMERATION_HANDLE));
if (*lphEnum != NULL)
{
Status = WN_SUCCESS;
}
else
{
Status = WN_OUT_OF_MEMORY;
}
break;
}
break;
case RESOURCE_CONTEXT:
default:
Status = WN_NOT_SUPPORTED;
break;
}
DbgP((TEXT("NPOpenEnum returning Status %lx\n"),Status));
return(Status);
}
DWORD APIENTRY
NPEnumResource(
HANDLE hEnum,
LPDWORD lpcCount,
LPVOID lpBuffer,
LPDWORD lpBufferSize)
/*++
Routine Description:
This routine uses the handle obtained by a call to NPOpenEnum for
enuerating the connected shares
Arguments:
hEnum - the enumeration handle
lpcCount - the number of resources returned
lpBuffer - the buffere for passing back the entries
lpBufferSize - the size of the buffer
Return Value:
WN_SUCCESS if successful, otherwise the appropriate error
WN_NO_MORE_ENTRIES - if the enumeration has exhausted the entries
WN_MORE_DATA - if nmore data is available
Notes:
The sample only supports the notion of enumerating connected shares
The handle passed back is merely the index of the last entry returned
--*/
{
DWORD Status = WN_SUCCESS;
LPNETRESOURCEW pBufferResource;
DWORD StringOffset;
DWORD AvailableBufferSize;
HANDLE hMutex, hMemory;
PSMBMRXNP_ENUMERATION_HANDLE pEnumHandle;
PSMBMRXNP_SHARED_MEMORY pSharedMemory;
DbgP((TEXT("NPEnumResource\n")));
DbgP((TEXT("NPEnumResource Count Requested %d\n"),*lpcCount));
AvailableBufferSize = *lpBufferSize;
StringOffset = *lpBufferSize;
pBufferResource = (LPNETRESOURCEW)lpBuffer;
pEnumHandle = (PSMBMRXNP_ENUMERATION_HANDLE)hEnum;
*lpcCount = 0;
if (pEnumHandle->LastIndex >= SMBMRXNP_MAX_DEVICES)
{
return WN_NO_MORE_ENTRIES;
}
Status = OpenSharedMemory(
&hMutex,
&hMemory,
(PVOID)&pSharedMemory);
if (Status == WN_SUCCESS)
{
INT Index;
PSMBMRXNP_NETRESOURCE pNetResource;
DbgP((TEXT("NPEnumResource: Highest Index %d Number Of resources %d\n"),
pSharedMemory->HighestIndexInUse,pSharedMemory->NumberOfResourcesInUse));
for (Index = pEnumHandle->LastIndex; Index <= pSharedMemory->HighestIndexInUse; Index++) {
pNetResource = &pSharedMemory->NetResources[Index];
DbgP((TEXT("NPEnumResource: Examining Index %d\n"),Index));
if (pNetResource->InUse)
{
DWORD ResourceSize;
ResourceSize = sizeof(NETRESOURCE) +
pNetResource->LocalNameLength + sizeof(WCHAR) +
pNetResource->RemoteNameLength + sizeof(WCHAR) +
SmbMrxProviderName.Length + sizeof(WCHAR);
if (AvailableBufferSize >= ResourceSize)
{
*lpcCount = *lpcCount + 1;
AvailableBufferSize -= ResourceSize;
pBufferResource->dwScope = RESOURCE_CONNECTED;
pBufferResource->dwType = pNetResource->dwType;
pBufferResource->dwDisplayType = pNetResource->dwDisplayType;
pBufferResource->dwUsage = pNetResource->dwUsage;
DbgP((TEXT("NPEnumResource: Copying local name Index %d\n"),Index));
// set up the strings in the resource
StringOffset -= (pNetResource->LocalNameLength + sizeof(WCHAR));
pBufferResource->lpLocalName = (PWCHAR)((PBYTE)lpBuffer + StringOffset);
CopyMemory(pBufferResource->lpLocalName,
pNetResource->LocalName,
pNetResource->LocalNameLength);
pBufferResource->lpLocalName[
pNetResource->LocalNameLength/sizeof(WCHAR)] = L'\0';
DbgP((TEXT("NPEnumResource: Copying remote name Index %d\n"),Index));
StringOffset -= (pNetResource->RemoteNameLength + sizeof(WCHAR));
pBufferResource->lpRemoteName = (PWCHAR)((PBYTE)lpBuffer + StringOffset);
CopyMemory(pBufferResource->lpRemoteName,
pNetResource->RemoteName,
pNetResource->RemoteNameLength);
pBufferResource->lpRemoteName[
pNetResource->RemoteNameLength/sizeof(WCHAR)] = L'\0';
DbgP((TEXT("NPEnumResource: Copying provider name Index %d\n"),Index));
StringOffset -= (SmbMrxProviderName.Length + sizeof(WCHAR));
pBufferResource->lpProvider = (PWCHAR)((PBYTE)lpBuffer + StringOffset);
CopyMemory(pBufferResource->lpProvider,
SmbMrxProviderName.Buffer,
SmbMrxProviderName.Length);
pBufferResource->lpProvider[
SmbMrxProviderName.Length/sizeof(WCHAR)] = L'\0';
pBufferResource->lpComment = NULL;
pBufferResource++;
}
else
{
DbgP((TEXT("NPEnumResource: Buffer Overflow Index %d\n"),Index));
Status = WN_MORE_DATA;
break;
}
}
}
pEnumHandle->LastIndex = Index;
if ((Status == WN_SUCCESS) &&
(pEnumHandle->LastIndex > pSharedMemory->HighestIndexInUse) &&
(*lpcCount == 0))
{
Status = WN_NO_MORE_ENTRIES;
}
CloseSharedMemory(
&hMutex,
&hMemory,
(PVOID)&pSharedMemory);
}
DbgP((TEXT("NPEnumResource returning Count %d\n"),*lpcCount));
DbgP((TEXT("NPEnumResource returning Status %lx\n"),Status));
return Status;
}
DWORD APIENTRY
NPCloseEnum(
HANDLE hEnum )
/*++
Routine Description:
This routine closes the handle for enumeration of resources.
Arguments:
hEnum - the enumeration handle
Return Value:
WN_SUCCESS if successful, otherwise the appropriate error
Notes:
The sample only supports the notion of enumerating connected shares
--*/
{
DbgP((TEXT("NPCloseEnum\n")));
LocalFree(hEnum);
return WN_SUCCESS;
}
ULONG
SendToMiniRdr(
IN ULONG IoctlCode,
IN PVOID InputDataBuf,
IN ULONG InputDataLen,
IN PVOID OutputDataBuf,
IN PULONG pOutputDataLen)
/*++
Routine Description:
This routine sends a device ioctl to the Mini Rdr.
Arguments:
IoctlCode - Function code for the Mini Rdr driver
InputDataBuf - Input buffer pointer
InputDataLen - Lenth of the input buffer
OutputDataBuf - Output buffer pointer
pOutputDataLen - Pointer to the length of the output buffer
Return Value:
WN_SUCCESS if successful, otherwise the appropriate error
Notes:
--*/
{
HANDLE DeviceHandle; // The mini rdr device handle
ULONG BytesRet;
BOOL rc;
ULONG Status;
Status = WN_SUCCESS;
// Grab a handle to the redirector device object
DeviceHandle = CreateFile(
DD_SMBMRX_USERMODE_DEV_NAME,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
(LPSECURITY_ATTRIBUTES)NULL,
OPEN_EXISTING,
0,
(HANDLE) NULL );
if ( INVALID_HANDLE_VALUE != DeviceHandle )
{
rc = DeviceIoControl( DeviceHandle,
IoctlCode,
InputDataBuf,
InputDataLen,
OutputDataBuf,
*pOutputDataLen,
pOutputDataLen,
NULL );
if ( !rc )
{
DbgP(( L"SendToMiniRdr - returning error from DeviceIoctl\n" ));
Status = GetLastError( );
}
else
{
DbgP(( L"SendToMiniRdr - The DeviceIoctl call succeded\n" ));
}
CloseHandle(DeviceHandle);
}
else
{
Status = GetLastError( );
DbgP(( L"SendToMiniRdr - error %lx opening device \n", Status ));
}
return Status;
}
ULONG FillInEaBuffer( LPTSTR pUserName, LPTSTR pPassword, PBYTE pEaData )
{
PFILE_FULL_EA_INFORMATION thisEa = (PFILE_FULL_EA_INFORMATION) pEaData;
PBYTE valuePtr = pEaData;
PWKSTA_INFO_100 WkStaInfo;
ULONG status;
PWCHAR pDomain;
// get the domain that this workstation is a member of
status = NetWkstaGetInfo( NULL, 100, (PBYTE *) &WkStaInfo );
if ( status == ERROR_SUCCESS )
{
pDomain = WkStaInfo->wki100_langroup;
}
else
{
pDomain = NULL;
}
DbgP((L"FillInEaBuffer - domain name=%s\n", pDomain));
thisEa->EaValueLength = 0;
thisEa->NextEntryOffset = 0;
// Set the user name EA
if ( pUserName )
{
thisEa->Flags = 0;
thisEa->EaNameLength = sizeof("UserName");
CopyMemory( thisEa->EaName, "UserName\0", thisEa->EaNameLength + 1 );
valuePtr = (PBYTE) thisEa->EaName + thisEa->EaNameLength + 1;
thisEa->EaValueLength = (USHORT)( *pUserName ? lstrlenW( pUserName ) : 1 ) * sizeof( WCHAR );
CopyMemory( valuePtr, pUserName, thisEa->EaValueLength );
thisEa->NextEntryOffset = (ULONG)(((PBYTE) valuePtr + thisEa->EaValueLength ) -
(PBYTE) thisEa);
thisEa->NextEntryOffset = ((thisEa->NextEntryOffset + 3) / sizeof(LONG)) * sizeof(LONG);
}
// Set the password EA.
if ( pPassword )
{
thisEa = (PFILE_FULL_EA_INFORMATION) ((PBYTE) thisEa + thisEa->NextEntryOffset);
thisEa->Flags = 0;
thisEa->EaNameLength = sizeof("Password");
CopyMemory( thisEa->EaName, "Password\0", thisEa->EaNameLength + 1 );
valuePtr = (PBYTE) thisEa->EaName + thisEa->EaNameLength + 1;
thisEa->EaValueLength = (USHORT)( *pPassword ? lstrlenW( pPassword ) : 1 ) * sizeof( WCHAR );
CopyMemory( valuePtr, pPassword, thisEa->EaValueLength );
thisEa->NextEntryOffset = (ULONG)(((PBYTE) valuePtr + thisEa->EaValueLength ) -
(PBYTE) thisEa);
thisEa->NextEntryOffset = ((thisEa->NextEntryOffset + 3) / sizeof(LONG)) * sizeof(LONG);
}
// Set the domain EA
if ( pDomain )
{
thisEa = (PFILE_FULL_EA_INFORMATION) ((PBYTE) thisEa + thisEa->NextEntryOffset);
thisEa->Flags = 0;
thisEa->EaNameLength = sizeof("Domain");
RtlCopyMemory( thisEa->EaName, "Domain\0", thisEa->EaNameLength + 1 );
valuePtr = (PBYTE) thisEa->EaName + thisEa->EaNameLength + 1;
thisEa->EaValueLength = (USHORT)( *pDomain ? lstrlenW( pDomain ) : 1 ) * sizeof( WCHAR );
RtlCopyMemory( valuePtr, pDomain, thisEa->EaValueLength );
thisEa->NextEntryOffset = 0;
}
thisEa->NextEntryOffset = 0;
return (ULONG)(((PBYTE) valuePtr + thisEa->EaValueLength) - (PBYTE) pEaData);
}
DWORD APIENTRY
NPAddConnection(
LPNETRESOURCE lpNetResource,
LPWSTR lpPassword,
LPWSTR lpUserName )
/*++
Routine Description:
This routine adds a connection to the list of connections associated
with this network provider
Arguments:
lpNetResource - the NETRESOURCE struct
lpPassword - the password
lpUserName - the user name
Return Value:
WN_SUCCESS if successful, otherwise the appropriate error
Notes:
--*/
{
return NPAddConnection3(NULL, lpNetResource, lpPassword, lpUserName, 0);
}
DWORD APIENTRY
NPAddConnection3(
HWND hwndOwner,
LPNETRESOURCE lpNetResource,
LPWSTR lpPassword,
LPWSTR lpUserName,
DWORD dwFlags )
/*++
Routine Description:
This routine adds a connection to the list of connections associated
with this network provider
Arguments:
hwndOwner - the owner handle
lpNetResource - the NETRESOURCE struct
lpPassword - the password
lpUserName - the user name
dwFlags - flags for the connection
Return Value:
WN_SUCCESS if successful, otherwise the appropriate error
Notes:
The current sample does not handle explicitly passesd in credentials. Normally
the credential information is passed in as EA parameters to the associated
mini redirector for further manipulation
--*/
{
DWORD Status = 0;
UNICODE_STRING ConnectionName;
PWCHAR pLocalName,pRemoteName;
USHORT LocalNameLength,RemoteNameLength;
HANDLE hConnection;
ULONG TransferBytes;
WCHAR NullStr[] = L"\0\0";
PWCHAR pUserName;
PWCHAR pPassword;
PWKSTA_USER_INFO_0 WkStaUserInfo;
PSMBMRX_CONNECTINFO ConnectInfo;
DbgP((TEXT("NPAddConnection3: Incoming UserName - %s, Password - %s\n"),
lpUserName, lpPassword ));
// if no user specified, get the current logged on user
if ( lpUserName == NULL )
{
Status = NetWkstaUserGetInfo( NULL, 0, (PBYTE *)&WkStaUserInfo );
if ( Status == ERROR_SUCCESS )
{
pUserName = WkStaUserInfo->wkui0_username;
}
else
{
pUserName = NullStr;
}
}
else
{
pUserName = lpUserName;
}
if ( lpPassword == NULL )
{
pPassword = NullStr; // use default password
pPassword[1] = '\0'; // reset empty flag
}
else if ( *lpPassword == L'\0' )
{
pPassword = NullStr;
pPassword[1] = '1'; // flag the password as "Empty"
}
else
{
pPassword = lpPassword;
}
Status = ERROR_SUCCESS;
DbgP((TEXT("NPAddConnection3: Outgoing UserName - %s, Password - %s\n"),
lpUserName, lpPassword ));
// The SMB mini supports only DISK type resources. The other resources
// are not supported.
if ((lpNetResource->lpRemoteName == NULL) ||
(lpNetResource->lpRemoteName[0] != L'\\') ||
(lpNetResource->lpRemoteName[1] != L'\\') ||
(lpNetResource->dwType != RESOURCETYPE_DISK))
{
return WN_BAD_NETNAME;
}
//
// The remote name is in the UNC format \\Server\Share. This name
// needs to be translated to an appropriate NT name in order to
// issue the request to the underlying mini redirector to create the
// connection.
//
// The NT style name is of the form
//
// \device\smbminiredirector\;<DriveLetter>:\Server\Share
//
// The additional ; is required by the new RDR for extensibility.
//
pLocalName = lpNetResource->lpLocalName;
pRemoteName = lpNetResource->lpRemoteName;
// skip past the first back slash since the name to be appended for the
// NT name does not require this.
pRemoteName++;
if (pLocalName != NULL) {
LocalNameLength = wcslen(pLocalName) * sizeof(WCHAR);
} else {
LocalNameLength = 0;
}
RemoteNameLength = (wcslen(pRemoteName) - 1) * sizeof(WCHAR);
ConnectionName.MaximumLength = (USHORT)(SmbMRxDeviceName.Length +
(USHORT)RemoteNameLength +
((pLocalName != NULL)
? (LocalNameLength + sizeof(WCHAR)) : 0) + // space for ;
sizeof(WCHAR));
ConnectionName.Length = ConnectionName.MaximumLength;
ConnectionName.Buffer = LocalAlloc( LMEM_ZEROINIT,
ConnectionName.Length + sizeof(WCHAR));
if (ConnectionName.Buffer == NULL)
{
return GetLastError();
}
// Copy the name into the buffer
CopyMemory( ConnectionName.Buffer,
SmbMRxDeviceName.Buffer,
SmbMRxDeviceName.Length);
wcscat(ConnectionName.Buffer, L"\\");
wcscat(ConnectionName.Buffer, L";");
if (pLocalName != NULL)
{
wcscat(ConnectionName.Buffer, pLocalName);
}
wcscat(ConnectionName.Buffer, pRemoteName);
ConnectInfo = (PSMBMRX_CONNECTINFO) LocalAlloc( LMEM_ZEROINIT, MAX_CONNECT_INFO_SIZE );
if ( ConnectInfo )
{
ConnectInfo->ConnectionNameOffset = 0;
ConnectInfo->ConnectionNameLength = ConnectionName.Length;
CopyMemory( ConnectInfo->InfoArea, ConnectionName.Buffer, ConnectionName.Length );
ConnectInfo->EaDataOffset = ConnectInfo->ConnectionNameOffset +
ConnectInfo->ConnectionNameLength;
// check for the "no password" flag
if ( pPassword[0] == L'\0' && pPassword[1] == L'1' )
{
pPassword = NULL;
}
ConnectInfo->EaDataLength = FillInEaBuffer( pUserName,
pPassword,
(PBYTE) ConnectInfo->InfoArea +
ConnectInfo->EaDataOffset );
TransferBytes = 0;
Status = SendToMiniRdr( IOCTL_SMBMRX_ADDCONN,
ConnectInfo,
MAX_CONNECT_INFO_SIZE,
NULL,
&TransferBytes );
LocalFree( ConnectInfo );
}
else
{
Status = WN_OUT_OF_MEMORY;
}
if ((Status == WN_SUCCESS) && (pLocalName != NULL))
{
WCHAR TempBuf[64];
if (!QueryDosDeviceW(
pLocalName,
TempBuf,
64))
{
if (GetLastError() != ERROR_FILE_NOT_FOUND)
{
//
// Most likely failure occurred because our output
// buffer is too small. It still means someone already
// has an existing symbolic link for this device.
//
Status = ERROR_ALREADY_ASSIGNED;
}
else
{
//
// ERROR_FILE_NOT_FOUND (translated from OBJECT_NAME_NOT_FOUND)
// means it does not exist and we can redirect this device.
//
// Create a symbolic link object to the device we are redirecting
//
if (!DefineDosDeviceW(
DDD_RAW_TARGET_PATH |
DDD_NO_BROADCAST_SYSTEM,
pLocalName,
ConnectionName.Buffer))
{
Status = GetLastError();
}
else
{
Status = WN_SUCCESS;
}
}
}
else
{
//
// QueryDosDevice successfully an existing symbolic link--
// somebody is already using this device.
//
Status = ERROR_ALREADY_ASSIGNED;
}
}
else
{
DbgP((TEXT("SendToMiniRdr returned %lx\n"),Status));
}
if (Status == WN_SUCCESS)
{
INT Index;
HANDLE hMutex, hMemory;
BOOLEAN FreeEntryFound = FALSE;
PSMBMRXNP_SHARED_MEMORY pSharedMemory;
// The connection was established and the local device mapping
// added. Include this in the list of mapped devices.
Status = OpenSharedMemory(
&hMutex,
&hMemory,
(PVOID)&pSharedMemory);
if (Status == WN_SUCCESS)
{
DbgP((TEXT("NPAddConnection3: Highest Index %d Number Of resources %d\n"),
pSharedMemory->HighestIndexInUse,pSharedMemory->NumberOfResourcesInUse));
Index = 0;
while (Index < pSharedMemory->HighestIndexInUse)
{
if (!pSharedMemory->NetResources[Index].InUse)
{
FreeEntryFound = TRUE;
break;
}
Index++;
}
if (!FreeEntryFound &&
(pSharedMemory->HighestIndexInUse < SMBMRXNP_MAX_DEVICES))
{
pSharedMemory->HighestIndexInUse += 1;
Index = pSharedMemory->HighestIndexInUse;
FreeEntryFound = TRUE;
}
if (FreeEntryFound)
{
PSMBMRXNP_NETRESOURCE pSmbMrxNetResource;
pSharedMemory->NumberOfResourcesInUse += 1;
pSmbMrxNetResource = &pSharedMemory->NetResources[Index];
pSmbMrxNetResource->InUse = TRUE;
pSmbMrxNetResource->dwScope = lpNetResource->dwScope;
pSmbMrxNetResource->dwType = lpNetResource->dwType;
pSmbMrxNetResource->dwDisplayType = lpNetResource->dwDisplayType;
pSmbMrxNetResource->dwUsage = RESOURCEUSAGE_CONNECTABLE;
pSmbMrxNetResource->LocalNameLength = LocalNameLength;
pSmbMrxNetResource->RemoteNameLength = wcslen(lpNetResource->lpRemoteName) * sizeof(WCHAR);
pSmbMrxNetResource->ConnectionNameLength = ConnectionName.Length;
// Copy the local name
CopyMemory( pSmbMrxNetResource->LocalName,
lpNetResource->lpLocalName,
pSmbMrxNetResource->LocalNameLength);
// Copy the remote name
CopyMemory( pSmbMrxNetResource->RemoteName,
lpNetResource->lpRemoteName,
pSmbMrxNetResource->RemoteNameLength);
// Copy the connection name
CopyMemory( pSmbMrxNetResource->ConnectionName,
ConnectionName.Buffer,
pSmbMrxNetResource->ConnectionNameLength);
//
// Copy the Auth info
//
// WARNING : security hole using shared memory..Developers must use alternate methods to maintain use table.
//
lstrcpyn( pSmbMrxNetResource->UserName, pUserName, MAX_PATH);
if ( *pPassword )
{
lstrcpyn( pSmbMrxNetResource->Password, pPassword, MAX_PATH);
}
else
{
CopyMemory( pSmbMrxNetResource->Password, pPassword, 3 * sizeof(WCHAR) );
}
}
else
{
Status = WN_NO_MORE_DEVICES;
}
CloseSharedMemory( &hMutex,
&hMemory,
(PVOID)&pSharedMemory);
}
else
{
DbgP((TEXT("NpAddConnection3: OpenSharedMemory returned %lx\n"),Status));
}
}
return Status;
}
DWORD APIENTRY
NPCancelConnection(
LPWSTR lpName,
BOOL fForce )
/*++
Routine Description:
This routine cancels ( deletes ) a connection from the list of connections
associated with this network provider
Arguments:
lpName - name of the connection
fForce - forcefully delete the connection
Return Value:
WN_SUCCESS if successful, otherwise the appropriate error
Notes:
--*/
{
BOOL bLocalName = TRUE;
DWORD Status = 0;
UNICODE_STRING Name;
HANDLE hMutex, hMemory;
PSMBMRXNP_SHARED_MEMORY pSharedMemory;
if (*lpName == L'\\' && *(lpName + 1) == L'\\')
{
bLocalName = FALSE;
}
DbgP((TEXT("NPCancelConnection\n")));
DbgP((TEXT("NPCancelConnection: ConnectionName: %S\n"), lpName));
Name.MaximumLength = Name.Length = wcslen(lpName) * sizeof(WCHAR);
Name.Buffer = lpName;
Status = OpenSharedMemory( &hMutex,
&hMemory,
(PVOID)&pSharedMemory);
if (Status == WN_SUCCESS)
{
INT Index;
BOOL EntryFound = FALSE;
PSMBMRXNP_NETRESOURCE pNetResource;
DbgP((TEXT("NPCancelConnection: Highest Index %d Number Of resources %d\n"),
pSharedMemory->HighestIndexInUse,pSharedMemory->NumberOfResourcesInUse));
for (Index = 0; Index <= pSharedMemory->HighestIndexInUse; Index++)
{
pNetResource = &pSharedMemory->NetResources[Index];
if (pNetResource->InUse)
{
UNICODE_STRING EntryName;
if (bLocalName)
{
EntryName.MaximumLength = pNetResource->LocalNameLength;
EntryName.Length = EntryName.MaximumLength;
EntryName.Buffer = pNetResource->LocalName;
}
else
{
EntryName.MaximumLength = pNetResource->RemoteNameLength;
EntryName.Length = EntryName.MaximumLength;
EntryName.Buffer = pNetResource->RemoteName;
}
DbgP((TEXT("NPCancelConnection: Name %S EntryName %S\n"),
lpName,EntryName.Buffer));
DbgP((TEXT("NPCancelConnection: Name Length %d Entry Name Length %d\n"),
Name.Length,EntryName.Length));
if (Name.Length == EntryName.Length)
{
if ( _wcsnicmp(Name.Buffer, EntryName.Buffer, Name.Length) == 0 )
{
EntryFound = TRUE;
break;
}
}
}
}
if (EntryFound)
{
PWCHAR pUserName;
PWCHAR pPassword;
PSMBMRX_CONNECTINFO ConnectInfo;
UNICODE_STRING ConnectionName;
ULONG TransferBytes;
DbgP((TEXT("NPCancelConnection: Connection Found:\n")));
ConnectionName.Length = pNetResource->ConnectionNameLength;
ConnectionName.MaximumLength = ConnectionName.Length;
ConnectionName.Buffer = pNetResource->ConnectionName;
pUserName = pNetResource->UserName;
pPassword = pNetResource->Password;
ConnectInfo = (PSMBMRX_CONNECTINFO) LocalAlloc( LMEM_ZEROINIT, MAX_CONNECT_INFO_SIZE );
if ( ConnectInfo )
{
ConnectInfo->ConnectionNameOffset = 0;
ConnectInfo->ConnectionNameLength = ConnectionName.Length;
CopyMemory( ConnectInfo->InfoArea, ConnectionName.Buffer, ConnectionName.Length );
ConnectInfo->EaDataOffset = ConnectInfo->ConnectionNameOffset +
ConnectInfo->ConnectionNameLength;
// check for the "no password" flag
if ( pPassword[0] == L'\0' && pPassword[1] == L'1' )
{
pPassword = NULL;
}
ConnectInfo->EaDataLength = FillInEaBuffer( pUserName,
pPassword,
(PBYTE) ConnectInfo->InfoArea +
ConnectInfo->EaDataOffset );
TransferBytes = 0;
Status = SendToMiniRdr( IOCTL_SMBMRX_DELCONN,
ConnectInfo,
MAX_CONNECT_INFO_SIZE,
NULL,
&TransferBytes );
LocalFree( ConnectInfo );
}
else
{
Status = WN_OUT_OF_MEMORY;
}
DbgP((TEXT("NPCancelConnection: SendToMiniRdr returned Status %lx\n"),Status));
if ( bLocalName )
{
if (DefineDosDevice(DDD_REMOVE_DEFINITION | DDD_RAW_TARGET_PATH | DDD_EXACT_MATCH_ON_REMOVE,
lpName,
pNetResource->ConnectionName) == FALSE)
{
DbgP((TEXT("RemoveDosDevice: DefineDosDevice error: %d\n"), GetLastError()));
Status = GetLastError();
}
else
{
pNetResource->InUse = FALSE;
if (Index == pSharedMemory->HighestIndexInUse)
{
pSharedMemory->HighestIndexInUse -= 1;
pSharedMemory->NumberOfResourcesInUse -= 1;
}
}
}
}
CloseSharedMemory( &hMutex,
&hMemory,
(PVOID)&pSharedMemory);
}
return Status;
}
DWORD APIENTRY
NPGetConnection(
LPWSTR lpLocalName,
LPWSTR lpRemoteName,
LPDWORD lpBufferSize )
/*++
Routine Description:
This routine returns the information associated with a connection
Arguments:
lpLocalName - local name associated with the connection
lpRemoteName - the remote name associated with the connection
lpBufferSize - the remote name buffer size
Return Value:
WN_SUCCESS if successful, otherwise the appropriate error
Notes:
--*/
{
DWORD Status = 0;
UNICODE_STRING Name;
HANDLE hMutex, hMemory;
PSMBMRXNP_SHARED_MEMORY pSharedMemory;
Name.MaximumLength = Name.Length = wcslen(lpLocalName) * sizeof(WCHAR);
Name.Buffer = lpLocalName;
Status = OpenSharedMemory( &hMutex,
&hMemory,
(PVOID)&pSharedMemory);
if (Status == WN_SUCCESS)
{
INT Index;
BOOL EntryFound = FALSE;
PSMBMRXNP_NETRESOURCE pNetResource;
for (Index = 0; Index <= pSharedMemory->HighestIndexInUse; Index++)
{
pNetResource = &pSharedMemory->NetResources[Index];
if (pNetResource->InUse)
{
UNICODE_STRING EntryName;
EntryName.MaximumLength = pNetResource->LocalNameLength;
EntryName.Length = EntryName.MaximumLength;
EntryName.Buffer = pNetResource->LocalName;
if (Name.Length == EntryName.Length)
{
if ( wcsncmp( Name.Buffer, EntryName.Buffer, Name.Length/sizeof(WCHAR)) == 0 )
{
EntryFound = TRUE;
break;
}
}
}
}
if (EntryFound)
{
if (*lpBufferSize < pNetResource->RemoteNameLength)
{
*lpBufferSize = pNetResource->RemoteNameLength;
Status = ERROR_BUFFER_OVERFLOW;
}
else
{
*lpBufferSize = pNetResource->RemoteNameLength;
CopyMemory( lpRemoteName,
pNetResource->RemoteName,
pNetResource->RemoteNameLength);
Status = WN_SUCCESS;
}
}
else
{
Status = ERROR_NO_NET_OR_BAD_PATH;
}
CloseSharedMemory( &hMutex, &hMemory, (PVOID)&pSharedMemory);
}
return Status;
}
DWORD APIENTRY
NPGetResourceParent(
LPNETRESOURCE lpNetResource,
LPVOID lpBuffer,
LPDWORD lpBufferSize )
/*++
Routine Description:
This routine returns the parent of a given resource
Arguments:
lpNetResource - the NETRESOURCE struct
lpBuffer - the buffer for passing back the parent information
lpBufferSize - the buffer size
Return Value:
WN_NOT_SUPPORTED
Notes:
The current sample does not handle this call.
--*/
{
return WN_NOT_SUPPORTED;
}
DWORD APIENTRY
NPGetResourceInformation(
LPNETRESOURCE lpNetResource,
LPVOID lpBuffer,
LPDWORD lpBufferSize,
LPWSTR *lplpSystem )
/*++
Routine Description:
This routine returns the information associated net resource
Arguments:
lpNetResource - the NETRESOURCE struct
lpBuffer - the buffer for passing back the parent information
lpBufferSize - the buffer size
lplpSystem -
Return Value:
Notes:
--*/
{
DWORD dwStatus = 0;
LPNETRESOURCE pOutNetResource;
DbgP((TEXT("NPGetResourceInformation\n")));
return dwStatus;
}
DWORD APIENTRY
NPGetUniversalName(
LPCWSTR lpLocalPath,
DWORD dwInfoLevel,
LPVOID lpBuffer,
LPDWORD lpBufferSize )
/*++
Routine Description:
This routine returns the information associated net resource
Arguments:
lpLocalPath - the local path name
dwInfoLevel - the desired info level
lpBuffer - the buffer for the univeral name
lpBufferSize - the buffer size
Return Value:
WN_SUCCESS if successful
Notes:
--*/
{
DWORD dwStatus;
DWORD BufferRequired = 0;
DWORD UniversalNameLength = 0;
DWORD RemoteNameLength = 0;
DWORD RemainingPathLength = 0;
LPWSTR pDriveLetter,
pRemainingPath,
SourceStrings[3];
WCHAR RemoteName[MAX_PATH],
LocalPath[MAX_PATH],
UniversalName[MAX_PATH],
ReplacedChar;
DbgP((TEXT("NPGetUniversalName: lpLocalPath: %S InfoLevel: %d\n"), lpLocalPath, dwInfoLevel));
if (dwInfoLevel != UNIVERSAL_NAME_INFO_LEVEL &&
dwInfoLevel != REMOTE_NAME_INFO_LEVEL)
{
DbgP((TEXT("NPGetUniversalName: bad dwInfoLevel value: %d\n"), dwInfoLevel));
return WN_BAD_LEVEL;
}
lstrcpynW(LocalPath, lpLocalPath, MAX_PATH);
pDriveLetter = LocalPath;
if (pRemainingPath = wcschr(pDriveLetter, L':'))
{
ReplacedChar = *(++pRemainingPath);
*pRemainingPath = L'\0';
}
RemoteNameLength = MAX_PATH;
if ((dwStatus = NPGetConnection(pDriveLetter, RemoteName, &RemoteNameLength)) != WN_SUCCESS)
{
DbgP((TEXT("NPGetUniversalName: NPGetConnection return dwStatus: %d\n"), dwStatus));
return dwStatus;
}
if (pRemainingPath)
{
*pRemainingPath = ReplacedChar;
}
DbgP((TEXT("NPGetUniversalName: pRemainingPath: %S RemoteName: %S\n"), pRemainingPath, RemoteName));
lstrcpynW(UniversalName, RemoteName, MAX_PATH);
if (pRemainingPath)
{
wcsncat(UniversalName, pRemainingPath, MAX_PATH - RemoteNameLength/sizeof(WCHAR) - 1);
UniversalName[MAX_PATH-1] = L'\0';
}
DbgP((TEXT("NPGetUniversalName: UniversalName: %S\n"), UniversalName));
// Determine if the provided buffer is large enough.
UniversalNameLength = (wcslen(UniversalName) + 1) * sizeof(WCHAR);
BufferRequired = UniversalNameLength;
if (dwInfoLevel == UNIVERSAL_NAME_INFO_LEVEL)
{
BufferRequired += sizeof(UNIVERSAL_NAME_INFO);
}
else
{
RemoteNameLength = (wcslen(RemoteName) + 1) * sizeof(WCHAR);
BufferRequired += sizeof(REMOTE_NAME_INFO) + RemoteNameLength;
if (pRemainingPath)
{
RemainingPathLength = (wcslen(pRemainingPath) + 1) * sizeof(WCHAR);
BufferRequired += RemainingPathLength;
}
}
if (*lpBufferSize < BufferRequired)
{
DbgP((TEXT("NPGetUniversalName: WN_MORE_DATA BufferRequired: %d\n"), BufferRequired));
*lpBufferSize = BufferRequired;
return WN_MORE_DATA;
}
if (dwInfoLevel == UNIVERSAL_NAME_INFO_LEVEL)
{
LPUNIVERSAL_NAME_INFOW pUniversalNameInfo;
pUniversalNameInfo = (LPUNIVERSAL_NAME_INFOW)lpBuffer;
pUniversalNameInfo->lpUniversalName = (PWCHAR)((PBYTE)lpBuffer + sizeof(UNIVERSAL_NAME_INFOW));
CopyMemory( pUniversalNameInfo->lpUniversalName,
UniversalName,
UniversalNameLength);
}
else
{
LPREMOTE_NAME_INFOW pRemoteNameInfo;
pRemoteNameInfo = (LPREMOTE_NAME_INFOW)lpBuffer;
pRemoteNameInfo->lpUniversalName = (PWCHAR)((PBYTE)lpBuffer + sizeof(REMOTE_NAME_INFOW));
pRemoteNameInfo->lpConnectionName = pRemoteNameInfo->lpUniversalName + UniversalNameLength;
pRemoteNameInfo->lpRemainingPath = pRemoteNameInfo->lpConnectionName + RemoteNameLength;
CopyMemory( pRemoteNameInfo->lpUniversalName,
UniversalName,
UniversalNameLength);
CopyMemory( pRemoteNameInfo->lpConnectionName,
RemoteName,
RemoteNameLength);
CopyMemory( pRemoteNameInfo->lpRemainingPath,
pRemainingPath,
RemainingPathLength);
}
DbgP((TEXT("NPGetUniversalName: WN_SUCCESS\n")));
return WN_SUCCESS;
}
int _cdecl _vsnwprintf( wchar_t *buffer, size_t count, wchar_t *format, va_list arg_ptr);
// Format and write debug information to OutputDebugString
ULONG
_cdecl
DbgPrint(
LPTSTR Format,
...
)
{
ULONG rc = 0;
TCHAR szbuffer[256];
va_list marker;
va_start( marker, Format );
{
rc = _vsnwprintf( szbuffer, 254, Format, marker );
szbuffer[255] = (TCHAR)0;
OutputDebugString( TRACE_TAG );
OutputDebugString( szbuffer );
}
return rc;
}