1042 lines
25 KiB
C
1042 lines
25 KiB
C
|
|
|||
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1995 Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
nspatalk.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
Contains support for the winsock 1.x Name Space Provider for Appletalk.
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
Sue Adams (suea) 10-Mar-1995
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
#include "nspatalk.h"
|
|||
|
|
|||
|
#define ADSP_BIT 0x0001 // Bitmask used internally to store the
|
|||
|
#define PAP_BIT 0x0002 // protocols requested by the caller
|
|||
|
|
|||
|
|
|||
|
INT
|
|||
|
APIENTRY
|
|||
|
NPLoadNameSpaces(
|
|||
|
IN OUT LPDWORD lpdwVersion,
|
|||
|
IN OUT LPNS_ROUTINE nsrBuffer,
|
|||
|
IN OUT LPDWORD lpdwBufferLength
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine returns name space info and functions supported in this
|
|||
|
dll.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
lpdwVersion - dll version
|
|||
|
|
|||
|
nsrBuffer - on return, this will be filled with an array of
|
|||
|
NS_ROUTINE structures
|
|||
|
|
|||
|
lpdwBufferLength - on input, the number of bytes contained in the buffer
|
|||
|
pointed to by nsrBuffer. On output, the minimum number of bytes
|
|||
|
to pass for the nsrBuffer to retrieve all the requested info
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
The number of NS_ROUTINE structures returned, or SOCKET_ERROR (-1) if
|
|||
|
the nsrBuffer is too small. Use GetLastError() to retrieve the
|
|||
|
error code.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
DWORD err;
|
|||
|
DWORD dwLengthNeeded;
|
|||
|
|
|||
|
*lpdwVersion = DLL_VERSION;
|
|||
|
|
|||
|
//
|
|||
|
// Check to see if the buffer is large enough
|
|||
|
//
|
|||
|
dwLengthNeeded = sizeof(NS_ROUTINE) + 4 * sizeof(LPFN_NSPAPI);
|
|||
|
|
|||
|
if ( ( *lpdwBufferLength < dwLengthNeeded )
|
|||
|
|| ( nsrBuffer == NULL )
|
|||
|
)
|
|||
|
{
|
|||
|
*lpdwBufferLength = dwLengthNeeded;
|
|||
|
SetLastError( ERROR_INSUFFICIENT_BUFFER );
|
|||
|
return (DWORD) SOCKET_ERROR;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// We only support 1 name space, so fill in the NS_ROUTINE.
|
|||
|
//
|
|||
|
nsrBuffer->dwFunctionCount = 3;
|
|||
|
nsrBuffer->alpfnFunctions = (LPFN_NSPAPI *)
|
|||
|
((BYTE *) nsrBuffer + sizeof(NS_ROUTINE));
|
|||
|
(nsrBuffer->alpfnFunctions)[NSPAPI_GET_ADDRESS_BY_NAME] =
|
|||
|
(LPFN_NSPAPI) NbpGetAddressByName;
|
|||
|
(nsrBuffer->alpfnFunctions)[NSPAPI_GET_SERVICE] = NULL;
|
|||
|
(nsrBuffer->alpfnFunctions)[NSPAPI_SET_SERVICE] =
|
|||
|
(LPFN_NSPAPI) NbpSetService;
|
|||
|
(nsrBuffer->alpfnFunctions)[3] = NULL;
|
|||
|
|
|||
|
nsrBuffer->dwNameSpace = NS_NBP;
|
|||
|
nsrBuffer->dwPriority = NS_STANDARD_PRIORITY;
|
|||
|
|
|||
|
return 1; // number of namespaces
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
INT
|
|||
|
NbpGetAddressByName(
|
|||
|
IN LPGUID lpServiceType,
|
|||
|
IN LPWSTR lpServiceName,
|
|||
|
IN LPDWORD lpdwProtocols,
|
|||
|
IN DWORD dwResolution,
|
|||
|
IN OUT LPVOID lpCsAddrBuffer,
|
|||
|
IN OUT LPDWORD lpdwBufferLength,
|
|||
|
IN OUT LPWSTR lpAliasBuffer,
|
|||
|
IN OUT LPDWORD lpdwAliasBufferLength,
|
|||
|
IN HANDLE hCancellationEvent
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine returns address information about a specific service.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
lpServiceType - pointer to the GUID for the service type
|
|||
|
|
|||
|
lpServiceName - unique string representing the service name.
|
|||
|
|
|||
|
lpdwProtocols - a zero terminated array of protocol ids. This parameter
|
|||
|
is optional; if lpdwProtocols is NULL, information on all available
|
|||
|
Protocols is returned
|
|||
|
|
|||
|
dwResolution - can be one of the following values:RES_SERVICE
|
|||
|
|
|||
|
lpCsAddrBuffer - on return, will be filled with CSADDR_INFO structures
|
|||
|
|
|||
|
lpdwBufferLength - on input, the number of bytes contained in the buffer
|
|||
|
pointed to by lpCsAddrBuffer. On output, the minimum number of bytes
|
|||
|
to pass for the lpCsAddrBuffer to retrieve all the requested info
|
|||
|
|
|||
|
lpAliasBuffer - not used
|
|||
|
|
|||
|
lpdwAliasBufferLength - not used
|
|||
|
|
|||
|
hCancellationEvent - the event which signals us to cancel the request
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
The number of CSADDR_INFO structures returned, or SOCKET_ERROR (-1) if
|
|||
|
the lpCsAddrBuffer is too small. Use GetLastError() to retrieve the
|
|||
|
error code.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
DWORD err;
|
|||
|
WSH_NBP_NAME NbpLookupName;
|
|||
|
DWORD cAddress = 0; // Count of the number of address returned
|
|||
|
// in lpCsAddrBuffer
|
|||
|
DWORD cProtocols = 0; // Count of the number of protocols contained
|
|||
|
// in lpdwProtocols + 1 ( for zero terminate )
|
|||
|
DWORD nProt = ADSP_BIT | PAP_BIT;
|
|||
|
|
|||
|
if ( ARGUMENT_PRESENT( lpdwAliasBufferLength )
|
|||
|
&& ARGUMENT_PRESENT( lpAliasBuffer )
|
|||
|
)
|
|||
|
{
|
|||
|
if ( *lpdwAliasBufferLength >= sizeof(WCHAR) )
|
|||
|
*lpAliasBuffer = 0;
|
|||
|
}
|
|||
|
|
|||
|
//DebugBreak();
|
|||
|
|
|||
|
//
|
|||
|
// Check for invalid parameters
|
|||
|
//
|
|||
|
if ( ( lpServiceType == NULL )
|
|||
|
|| ( (lpServiceName == NULL) && (dwResolution != RES_SERVICE) )
|
|||
|
|| ( lpdwBufferLength == NULL )
|
|||
|
)
|
|||
|
{
|
|||
|
SetLastError( ERROR_INVALID_PARAMETER );
|
|||
|
return SOCKET_ERROR;
|
|||
|
}
|
|||
|
|
|||
|
// The size of the user's buffer will dictate also how many
|
|||
|
// tuples can be returned from the NBP lookup in case they
|
|||
|
// are querying using wildcards.
|
|||
|
if ( *lpdwBufferLength < (sizeof(WSH_LOOKUP_NAME) + sizeof(WSH_NBP_TUPLE)) )
|
|||
|
{
|
|||
|
SetLastError( ERROR_INSUFFICIENT_BUFFER );
|
|||
|
return SOCKET_ERROR;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// If an array of protocol ids is passed in, check to see if
|
|||
|
// the ADSP or PAP protocol is requested. If not, return 0 since
|
|||
|
// we only support these 2.
|
|||
|
//
|
|||
|
if ( lpdwProtocols != NULL )
|
|||
|
{
|
|||
|
INT i = -1;
|
|||
|
|
|||
|
nProt = 0;
|
|||
|
while ( lpdwProtocols[++i] != 0 )
|
|||
|
{
|
|||
|
if ( lpdwProtocols[i] == ATPROTO_ADSP )
|
|||
|
nProt |= ADSP_BIT;
|
|||
|
|
|||
|
if ( lpdwProtocols[i] == ATPROTO_PAP )
|
|||
|
nProt |= PAP_BIT;
|
|||
|
}
|
|||
|
|
|||
|
if ( nProt == 0 )
|
|||
|
return 0; // No address found
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// If this is a service asking what local address to use when
|
|||
|
// bind()-ing its appletalk socket, return the generic Appletalk
|
|||
|
// socket address.
|
|||
|
//
|
|||
|
if ((dwResolution & RES_SERVICE) != 0)
|
|||
|
{
|
|||
|
err = FillBufferWithCsAddr( NULL,
|
|||
|
nProt,
|
|||
|
lpCsAddrBuffer,
|
|||
|
lpdwBufferLength,
|
|||
|
&cAddress );
|
|||
|
|
|||
|
if ( err )
|
|||
|
{
|
|||
|
SetLastError( err );
|
|||
|
return SOCKET_ERROR;
|
|||
|
}
|
|||
|
|
|||
|
return cAddress;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// This is a client trying to do an NBP lookup on an Appletalk
|
|||
|
// named entity to find out what remote address to connect() to.
|
|||
|
//
|
|||
|
err = GetNameInNbpFormat(lpServiceType,
|
|||
|
lpServiceName,
|
|||
|
&NbpLookupName);
|
|||
|
if (err)
|
|||
|
{
|
|||
|
KdPrint(("GetNameInNbpFormat failed with error %d for name %ws\n", err, lpServiceName ));
|
|||
|
SetLastError(err);
|
|||
|
return SOCKET_ERROR;
|
|||
|
}
|
|||
|
|
|||
|
err = NbpLookupAddress( &NbpLookupName,
|
|||
|
nProt,
|
|||
|
lpCsAddrBuffer,
|
|||
|
lpdwBufferLength,
|
|||
|
&cAddress );
|
|||
|
#if DBG
|
|||
|
if ( err == NO_ERROR )
|
|||
|
{
|
|||
|
KdPrint(("NbpGetAddrByName:Successfully got %d address for %ws from NBP.\n",
|
|||
|
cAddress, lpServiceName ));
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
KdPrint(("NbpGetAddrByName:Failed with err %d when getting address for %ws from NBP.\n", err, lpServiceName ));
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
if ( err )
|
|||
|
{
|
|||
|
SetLastError( err );
|
|||
|
return SOCKET_ERROR;
|
|||
|
}
|
|||
|
|
|||
|
return cAddress;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
GetNameInNbpFormat(
|
|||
|
IN LPGUID pServiceType,
|
|||
|
IN LPWSTR pServiceName,
|
|||
|
IN OUT PWSH_NBP_NAME pNbpName
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine description:
|
|||
|
|
|||
|
Convert pServiceType and pServiceName to system ANSI strings in
|
|||
|
the pLookupName structure so they can be used to do NBP lookup.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
|
|||
|
Return value:
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
INT err;
|
|||
|
WCHAR wtypeBuf[MAX_ENTITY + 1];
|
|||
|
CHAR entityBuf[(MAX_ENTITY + 1) * 2]; // potentially all multibyte
|
|||
|
PWCHAR pColon, pAtSign, pType = wtypeBuf, pObject = pServiceName, pZone = L"*";
|
|||
|
|
|||
|
// Parse the service name for "object:type@zone" form. If we find a
|
|||
|
// ':' there must also be a '@' (and vice-versa).
|
|||
|
// If there is a type in the servicename string, we will still convert
|
|||
|
// the LPGUID to a string. If the types don't match return an error.
|
|||
|
// So, we will accept the following forms for the service name:
|
|||
|
// object OR object:type@zone. If just object is given, then the zone
|
|||
|
// used will be the default zone "*". Wildcards are acceptible for
|
|||
|
// NBP Lookup, but not for NBP (De)Register. No checking is done for that.
|
|||
|
//
|
|||
|
pColon = wcschr(pServiceName, L':');
|
|||
|
pAtSign = wcschr(pServiceName, L'@');
|
|||
|
|
|||
|
if ( ((pColon != NULL) && (pAtSign == NULL)) ||
|
|||
|
((pAtSign != NULL) && (pColon == NULL)) ||
|
|||
|
(pColon > pAtSign) )
|
|||
|
{
|
|||
|
return(ERROR_INVALID_PARAMETER);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// By default we only use our own local zone
|
|||
|
//
|
|||
|
if (pAtSign != NULL)
|
|||
|
{
|
|||
|
pZone = pAtSign + 1;
|
|||
|
if ((wcslen(pZone) == 0) ||
|
|||
|
(wcslen(pZone) > MAX_ENTITY))
|
|||
|
{
|
|||
|
return ERROR_INVALID_PARAMETER;
|
|||
|
}
|
|||
|
}
|
|||
|
if (WideCharToMultiByte(CP_ACP,
|
|||
|
0,
|
|||
|
pZone,
|
|||
|
-1, // says that wchar string is null terminated
|
|||
|
entityBuf,
|
|||
|
sizeof(entityBuf),
|
|||
|
NULL,
|
|||
|
NULL) == 0)
|
|||
|
{
|
|||
|
DBGPRINT(("GetNameInNbpFormat FAILED wctomb %ws\n", pZone));
|
|||
|
|
|||
|
return GetLastError();
|
|||
|
}
|
|||
|
pNbpName->ZoneNameLen = strlen( entityBuf );
|
|||
|
memcpy( pNbpName->ZoneName,
|
|||
|
entityBuf,
|
|||
|
pNbpName->ZoneNameLen );
|
|||
|
|
|||
|
if (pAtSign != NULL)
|
|||
|
{
|
|||
|
// change the @ to a null so the type will be null terminated
|
|||
|
*pAtSign = 0;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Convert the Type string
|
|||
|
//
|
|||
|
|
|||
|
err = GetNameByType(pServiceType, wtypeBuf, sizeof(wtypeBuf));
|
|||
|
if (err != NO_ERROR)
|
|||
|
{
|
|||
|
// Appletalk type can be 32 chars max, so if this
|
|||
|
// fails with buffer too small error it couldn't be
|
|||
|
// used on appletalk anyway
|
|||
|
return err;
|
|||
|
}
|
|||
|
|
|||
|
// If there was a type name in the ServiceName, then it better match
|
|||
|
// what the LPGUID resolved to.
|
|||
|
if (pColon != NULL)
|
|||
|
{
|
|||
|
pType = pColon + 1;
|
|||
|
if ((wcslen(pType) == 0) ||
|
|||
|
// (wcscmp(pType, wtypeBuf) != 0) ||
|
|||
|
(wcslen(pType) > MAX_ENTITY))
|
|||
|
{
|
|||
|
return ERROR_INVALID_PARAMETER;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (WideCharToMultiByte(CP_ACP,
|
|||
|
0,
|
|||
|
pType,
|
|||
|
-1, // says that wchar string is null terminated
|
|||
|
entityBuf,
|
|||
|
sizeof(entityBuf),
|
|||
|
NULL,
|
|||
|
NULL) == 0)
|
|||
|
{
|
|||
|
DBGPRINT(("GetNameInNbpFormat FAILED wctomb %ws\n", pType));
|
|||
|
|
|||
|
return GetLastError();
|
|||
|
}
|
|||
|
pNbpName->TypeNameLen = strlen( entityBuf );
|
|||
|
memcpy( pNbpName->TypeName,
|
|||
|
entityBuf,
|
|||
|
pNbpName->TypeNameLen );
|
|||
|
|
|||
|
if (pColon != NULL)
|
|||
|
{
|
|||
|
// change the colon to a null so the object will be null terminated
|
|||
|
*pColon = 0;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Convert the Object string
|
|||
|
//
|
|||
|
if ((wcslen(pObject) == 0) ||
|
|||
|
(wcslen(pObject) > MAX_ENTITY))
|
|||
|
{
|
|||
|
return ERROR_INVALID_PARAMETER;
|
|||
|
}
|
|||
|
if (WideCharToMultiByte(CP_ACP,
|
|||
|
0,
|
|||
|
pServiceName,
|
|||
|
-1, // says that wchar string is null terminated
|
|||
|
entityBuf,
|
|||
|
sizeof(entityBuf),
|
|||
|
NULL,
|
|||
|
NULL) == 0)
|
|||
|
{
|
|||
|
DBGPRINT(("GetNameInNbpFormat FAILED wctomb %ws\n", pServiceName));
|
|||
|
|
|||
|
return GetLastError();
|
|||
|
}
|
|||
|
pNbpName->ObjectNameLen = strlen( entityBuf );
|
|||
|
memcpy( pNbpName->ObjectName,
|
|||
|
entityBuf,
|
|||
|
pNbpName->ObjectNameLen );
|
|||
|
|
|||
|
|
|||
|
return STATUS_SUCCESS;
|
|||
|
|
|||
|
} // GetNameInNbpFormat
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
NbpLookupAddress(
|
|||
|
IN PWSH_NBP_NAME pNbpLookupName,
|
|||
|
IN DWORD nProt,
|
|||
|
IN OUT LPVOID lpCsAddrBuffer,
|
|||
|
IN OUT LPDWORD lpdwBufferLength,
|
|||
|
OUT LPDWORD lpcAddress
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine uses NBP requests to find the address of the given service
|
|||
|
name/type.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
pNbpLookupName - NBP name to lookup
|
|||
|
|
|||
|
nProt - ADSP_BIT | PAP_BIT
|
|||
|
|
|||
|
lpCsAddrBuffer - on return, will be filled with CSADDR_INFO structures
|
|||
|
|
|||
|
lpdwBufferLength - on input, the number of bytes contained in the buffer
|
|||
|
pointed to by lpCsAddrBuffer. On output, the minimum number of bytes
|
|||
|
to pass for the lpCsAddrBuffer to retrieve all the requested info
|
|||
|
|
|||
|
hCancellationEvent - the event which signals us to cancel the request???
|
|||
|
|
|||
|
lpcAddress - on output, the number of CSADDR_INFO structures returned
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Win32 error code.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
DWORD err = NO_ERROR;
|
|||
|
NTSTATUS ntstatus;
|
|||
|
|
|||
|
WSADATA wsaData;
|
|||
|
SOCKET socketNbp;
|
|||
|
SOCKADDR_AT socketAddr = {AF_APPLETALK, 0, 0, 0};
|
|||
|
PWSH_LOOKUP_NAME pWshLookupName;
|
|||
|
PWSH_ATALK_ADDRESS pWshATAddr;
|
|||
|
PBYTE pTmp = lpCsAddrBuffer;
|
|||
|
DWORD templen = *lpdwBufferLength;
|
|||
|
DWORD bufsize;
|
|||
|
PBYTE buf = NULL;
|
|||
|
|
|||
|
int i;
|
|||
|
|
|||
|
*lpcAddress = 0;
|
|||
|
|
|||
|
//
|
|||
|
// Initialize the socket interface
|
|||
|
//
|
|||
|
err = WSAStartup( WSOCK_VER_REQD, &wsaData );
|
|||
|
if ( err )
|
|||
|
{
|
|||
|
return err;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Open an Appletalk datagram socket
|
|||
|
// ISSUE: should we use DDPPROTO_NBP, or just a random
|
|||
|
// dynamic DDP socket? Or an ADSP socket since we know
|
|||
|
// that works and has been tested...Does it really matter
|
|||
|
// since this only defines what devicename will be opened
|
|||
|
// in the appletalk driver i.e. \\device\\atalkddp\2 .
|
|||
|
//
|
|||
|
socketNbp = socket( AF_APPLETALK, SOCK_DGRAM, DDPPROTO_NBP);
|
|||
|
if ( socketNbp == INVALID_SOCKET )
|
|||
|
{
|
|||
|
err = WSAGetLastError();
|
|||
|
(VOID) WSACleanup();
|
|||
|
return err;
|
|||
|
}
|
|||
|
|
|||
|
do
|
|||
|
{
|
|||
|
//
|
|||
|
// Bind the socket (this does not actually go thru
|
|||
|
// the WSHAtalk helper dll, it goes thru AFD which
|
|||
|
// Ioctls appletalk directly. The node and net values
|
|||
|
// are ignored, and socket 0 means give me a dynamic
|
|||
|
// socket number)
|
|||
|
//
|
|||
|
if ( bind( socketNbp,
|
|||
|
(PSOCKADDR) &socketAddr,
|
|||
|
sizeof( SOCKADDR_AT)) == SOCKET_ERROR )
|
|||
|
{
|
|||
|
err = WSAGetLastError();
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Determine how many CSADDR_INFO structures could fit
|
|||
|
// into this buffer, then allocate a buffer to use for
|
|||
|
// the NBP lookup that can hold this many returned tuples
|
|||
|
//
|
|||
|
|
|||
|
bufsize = sizeof(WSH_LOOKUP_NAME) +
|
|||
|
( (*lpdwBufferLength / (sizeof(CSADDR_INFO) + (2*sizeof(SOCKADDR_AT)))) *
|
|||
|
sizeof(WSH_NBP_TUPLE) );
|
|||
|
|
|||
|
if ((buf = LocalAlloc(LMEM_ZEROINIT, bufsize)) == NULL)
|
|||
|
{
|
|||
|
err = GetLastError();
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
// copy the NBP name to look for into the buffer
|
|||
|
pWshLookupName = (PWSH_LOOKUP_NAME)buf;
|
|||
|
pWshLookupName->LookupTuple.NbpName = *pNbpLookupName;
|
|||
|
|
|||
|
//
|
|||
|
// Send the Nbp lookup request
|
|||
|
//
|
|||
|
if (getsockopt( socketNbp,
|
|||
|
SOL_APPLETALK,
|
|||
|
SO_LOOKUP_NAME,
|
|||
|
buf,
|
|||
|
&bufsize) != NO_ERROR)
|
|||
|
{
|
|||
|
err = WSAGetLastError();
|
|||
|
if (err == WSAENOBUFS)
|
|||
|
{
|
|||
|
// this assumes that getsockopt will NOT
|
|||
|
// put the required number of bytes into the
|
|||
|
// bufsize parameter on error
|
|||
|
*lpdwBufferLength = 2 * *lpdwBufferLength;
|
|||
|
}
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
if (pWshLookupName->NoTuples == 0)
|
|||
|
{
|
|||
|
// didn't find anything matching this NBP entity name
|
|||
|
*lpdwBufferLength = 0;
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
// point to the returned tuples
|
|||
|
pWshATAddr = (PWSH_ATALK_ADDRESS)(pWshLookupName + 1);
|
|||
|
for ( i = 0; i < (INT)pWshLookupName->NoTuples; i++ )
|
|||
|
{
|
|||
|
DWORD cAddr, bytesWritten;
|
|||
|
|
|||
|
socketAddr.sat_net = pWshATAddr->Network;
|
|||
|
socketAddr.sat_node = pWshATAddr->Node;
|
|||
|
socketAddr.sat_socket = pWshATAddr->Socket;
|
|||
|
err = FillBufferWithCsAddr( &socketAddr,
|
|||
|
nProt,
|
|||
|
// USE LOCALS TO KEEP TRACK OF BUF POSITION AND COUNT LEFT
|
|||
|
pTmp,
|
|||
|
&templen,
|
|||
|
&cAddr);
|
|||
|
|
|||
|
if (err != NO_ERROR)
|
|||
|
{
|
|||
|
// Fill in how many bytes the buffer should have been to
|
|||
|
// hold all the returned addresses
|
|||
|
*lpdwBufferLength = templen * pWshLookupName->NoTuples;
|
|||
|
break; // from for and then from while
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
pTmp += sizeof(CSADDR_INFO) * cAddr;
|
|||
|
templen -= (sizeof(CSADDR_INFO) + (2 * sizeof(SOCKADDR_AT))) * cAddr;
|
|||
|
*lpcAddress += cAddr; // running count of CSADDR_INFOs in buffer
|
|||
|
(PWSH_NBP_TUPLE)pWshATAddr ++; // get next NBP tuple
|
|||
|
}
|
|||
|
}
|
|||
|
} while (FALSE);
|
|||
|
|
|||
|
//
|
|||
|
// Clean up the socket interface
|
|||
|
//
|
|||
|
|
|||
|
if (buf != NULL)
|
|||
|
{
|
|||
|
LocalFree(buf);
|
|||
|
}
|
|||
|
closesocket( socketNbp );
|
|||
|
(VOID) WSACleanup();
|
|||
|
|
|||
|
return err;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
DWORD
|
|||
|
FillBufferWithCsAddr(
|
|||
|
IN PSOCKADDR_AT pAddress, // if NULL, then return generic appletalk socket address for RemoteAddr
|
|||
|
IN DWORD nProt,
|
|||
|
IN OUT LPVOID lpCsAddrBuffer,
|
|||
|
IN OUT LPDWORD lpdwBufferLength,
|
|||
|
OUT LPDWORD pcAddress
|
|||
|
)
|
|||
|
{
|
|||
|
DWORD nAddrCount = 0;
|
|||
|
CSADDR_INFO *pCsAddr;
|
|||
|
SOCKADDR_AT *pAddrLocal, *pAddrRemote;
|
|||
|
DWORD i;
|
|||
|
LPBYTE pBuffer;
|
|||
|
|
|||
|
if ( nProt & ADSP_BIT )
|
|||
|
nAddrCount ++;
|
|||
|
|
|||
|
if ( nProt & PAP_BIT )
|
|||
|
nAddrCount++;
|
|||
|
|
|||
|
|
|||
|
if ( *lpdwBufferLength <
|
|||
|
nAddrCount * ( sizeof( CSADDR_INFO) + 2*sizeof( SOCKADDR_AT)))
|
|||
|
{
|
|||
|
*lpdwBufferLength = nAddrCount *
|
|||
|
( sizeof( CSADDR_INFO) + 2*sizeof( SOCKADDR_AT));
|
|||
|
return ERROR_INSUFFICIENT_BUFFER;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
pBuffer = ((LPBYTE) lpCsAddrBuffer) + *lpdwBufferLength -
|
|||
|
(2*sizeof( SOCKADDR_AT) * nAddrCount);
|
|||
|
|
|||
|
for ( i = 0, pCsAddr = (CSADDR_INFO *)lpCsAddrBuffer;
|
|||
|
(i < nAddrCount) && ( nProt != 0 );
|
|||
|
i++, pCsAddr++ )
|
|||
|
{
|
|||
|
if ( nProt & ADSP_BIT )
|
|||
|
{
|
|||
|
pCsAddr->iSocketType = SOCK_RDM;
|
|||
|
pCsAddr->iProtocol = ATPROTO_ADSP;
|
|||
|
nProt &= ~ADSP_BIT;
|
|||
|
}
|
|||
|
else if ( nProt & PAP_BIT )
|
|||
|
{
|
|||
|
pCsAddr->iSocketType = SOCK_RDM;
|
|||
|
pCsAddr->iProtocol = ATPROTO_PAP;
|
|||
|
nProt &= ~PAP_BIT;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
pCsAddr->LocalAddr.iSockaddrLength = sizeof( SOCKADDR_AT );
|
|||
|
pCsAddr->RemoteAddr.iSockaddrLength = sizeof( SOCKADDR_AT );
|
|||
|
pCsAddr->LocalAddr.lpSockaddr = (LPSOCKADDR) pBuffer;
|
|||
|
pCsAddr->RemoteAddr.lpSockaddr =
|
|||
|
(LPSOCKADDR) ( pBuffer + sizeof(SOCKADDR_AT));
|
|||
|
pBuffer += 2 * sizeof( SOCKADDR_AT );
|
|||
|
|
|||
|
pAddrLocal = (SOCKADDR_AT *) pCsAddr->LocalAddr.lpSockaddr;
|
|||
|
pAddrRemote = (SOCKADDR_AT *) pCsAddr->RemoteAddr.lpSockaddr;
|
|||
|
|
|||
|
pAddrLocal->sat_family = AF_APPLETALK;
|
|||
|
pAddrRemote->sat_family = AF_APPLETALK;
|
|||
|
|
|||
|
//
|
|||
|
// The default local sockaddr for ADSP and PAP is
|
|||
|
// sa_family = AF_APPLETALK and all other bytes = 0.
|
|||
|
//
|
|||
|
|
|||
|
pAddrLocal->sat_net = 0;
|
|||
|
pAddrLocal->sat_node = 0;
|
|||
|
pAddrLocal->sat_socket = 0;
|
|||
|
|
|||
|
//
|
|||
|
// If pAddress is NULL, i.e. we are doing RES_SERVICE,
|
|||
|
// just make all bytes in remote address zero.
|
|||
|
//
|
|||
|
|
|||
|
if ( pAddress == NULL )
|
|||
|
{
|
|||
|
pAddrRemote->sat_net = 0;
|
|||
|
pAddrRemote->sat_node = 0;
|
|||
|
pAddrRemote->sat_socket = 0;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
pAddrRemote->sat_net = pAddress->sat_net;
|
|||
|
pAddrRemote->sat_node = pAddress->sat_node;
|
|||
|
pAddrRemote->sat_socket = pAddress->sat_socket;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
*pcAddress = nAddrCount;
|
|||
|
return NO_ERROR;
|
|||
|
} // FillBufferWithCSAddr
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
NbpSetService (
|
|||
|
IN DWORD dwOperation,
|
|||
|
IN DWORD dwFlags,
|
|||
|
IN BOOL fUnicodeBlob,
|
|||
|
IN LPSERVICE_INFO lpServiceInfo
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine registers or deregisters the given service type/name on NBP.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
dwOperation - Either SERVICE_REGISTER or SERVICE_DEREGISTER
|
|||
|
|
|||
|
dwFlags - ignored
|
|||
|
|
|||
|
fUnicodeBlob - ignored
|
|||
|
|
|||
|
lpServiceInfo - Pointer to a SERVICE_INFO structure containing all info
|
|||
|
about the service.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Win32 error code.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NTSTATUS err = STATUS_SUCCESS;
|
|||
|
SOCKADDR_AT sockAddr;
|
|||
|
WSH_NBP_NAME nbpName;
|
|||
|
DWORD i;
|
|||
|
INT nNBP = -1;
|
|||
|
|
|||
|
UNREFERENCED_PARAMETER( dwFlags );
|
|||
|
UNREFERENCED_PARAMETER( fUnicodeBlob );
|
|||
|
|
|||
|
DBGPRINT(("NbpSetService entered...\n"));
|
|||
|
|
|||
|
//
|
|||
|
// Check for invalid parameters
|
|||
|
//
|
|||
|
if ( ( lpServiceInfo == NULL )
|
|||
|
|| ( lpServiceInfo->lpServiceType == NULL )
|
|||
|
|| ( lpServiceInfo->lpServiceName == NULL ) )
|
|||
|
{
|
|||
|
return ERROR_INVALID_PARAMETER;
|
|||
|
}
|
|||
|
|
|||
|
if ( lpServiceInfo->lpServiceAddress == NULL )
|
|||
|
return ERROR_INCORRECT_ADDRESS;
|
|||
|
|
|||
|
switch (dwOperation)
|
|||
|
{
|
|||
|
case SERVICE_REGISTER:
|
|||
|
case SERVICE_DEREGISTER:
|
|||
|
{
|
|||
|
//
|
|||
|
// Check to see if the service address array contains NBP address,
|
|||
|
// we will only use the first NBP address contained in the array.
|
|||
|
//
|
|||
|
|
|||
|
for ( i = 0; i < lpServiceInfo->lpServiceAddress->dwAddressCount; i++)
|
|||
|
{
|
|||
|
if ( lpServiceInfo->lpServiceAddress->Addresses[i].dwAddressType == AF_APPLETALK )
|
|||
|
{
|
|||
|
sockAddr = *(PSOCKADDR_AT)(lpServiceInfo->lpServiceAddress->Addresses[i].lpAddress);
|
|||
|
nNBP = (INT) i;
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// If we cannot find a atalk address in the user's array, return error
|
|||
|
//
|
|||
|
if ( nNBP == -1 )
|
|||
|
{
|
|||
|
DBGPRINT(("NbpSetService: no Appletalk addresses in lpServiceInfo!\n"));
|
|||
|
return ERROR_INCORRECT_ADDRESS;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Convert the service type and name into NBP form
|
|||
|
//
|
|||
|
err = GetNameInNbpFormat(lpServiceInfo->lpServiceType,
|
|||
|
lpServiceInfo->lpServiceName,
|
|||
|
&nbpName);
|
|||
|
if (err != NO_ERROR)
|
|||
|
{
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
err = NbpRegDeregService(dwOperation, &nbpName, &sockAddr);
|
|||
|
break;
|
|||
|
}
|
|||
|
case SERVICE_FLUSH:
|
|||
|
case SERVICE_ADD_TYPE:
|
|||
|
case SERVICE_DELETE_TYPE:
|
|||
|
//
|
|||
|
// This is a no-op in our provider, so just return success
|
|||
|
//
|
|||
|
return NO_ERROR;
|
|||
|
|
|||
|
default:
|
|||
|
//
|
|||
|
// We can probably say all other operations which we have no
|
|||
|
// knowledge of are ignored by us. So, just return success.
|
|||
|
//
|
|||
|
return NO_ERROR;
|
|||
|
}
|
|||
|
|
|||
|
return err;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
DWORD
|
|||
|
NbpRegDeregService(
|
|||
|
IN DWORD dwOperation,
|
|||
|
IN PWSH_NBP_NAME pNbpName,
|
|||
|
IN PSOCKADDR_AT pSockAddr
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine registers or deregisters the given service on NBP.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
dwOperation - either SERVICE_REGISTER or SERVICE_DEREGISTER
|
|||
|
|
|||
|
pNbpName - points to NBP name to register (zone should be "*")
|
|||
|
|
|||
|
pSockAddr - socket address on which to register name
|
|||
|
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Win32 error.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
int status;
|
|||
|
BYTE EaBuffer[sizeof(FILE_FULL_EA_INFORMATION) +
|
|||
|
TDI_TRANSPORT_ADDRESS_LENGTH + 1 +
|
|||
|
sizeof(TA_APPLETALK_ADDRESS)];
|
|||
|
PFILE_FULL_EA_INFORMATION pEaBuf = (PFILE_FULL_EA_INFORMATION)EaBuffer;
|
|||
|
TA_APPLETALK_ADDRESS Ta;
|
|||
|
OBJECT_ATTRIBUTES ObjAttr;
|
|||
|
UNICODE_STRING DeviceName;
|
|||
|
IO_STATUS_BLOCK IoStsBlk;
|
|||
|
|
|||
|
NBP_TUPLE nbpTuple;
|
|||
|
SOCKET bogusSocket = 0;
|
|||
|
HANDLE AtalkAddressHandle = NULL, eventHandle = NULL;
|
|||
|
PTDI_ACTION_HEADER tdiAction;
|
|||
|
ULONG tdiActionLength;
|
|||
|
BOOLEAN freeTdiAction = FALSE, closeEventHandle = FALSE;
|
|||
|
PNBP_REGDEREG_ACTION nbpAction;
|
|||
|
PVOID completionApc = NULL;
|
|||
|
PVOID apcContext = NULL;
|
|||
|
|
|||
|
DBGPRINT(("NbpRegDeregService entered...\n"));
|
|||
|
DebugBreak();
|
|||
|
|
|||
|
// Dosn't matter what protocol or socket we open, we just want a
|
|||
|
// device handle into the stack.
|
|||
|
RtlInitUnicodeString(&DeviceName, WSH_ATALK_ADSPRDM);
|
|||
|
|
|||
|
InitializeObjectAttributes(&ObjAttr, &DeviceName, 0, NULL, NULL);
|
|||
|
|
|||
|
// Initialize the EA Buffer
|
|||
|
pEaBuf->NextEntryOffset = 0;
|
|||
|
pEaBuf->Flags = 0;
|
|||
|
pEaBuf->EaValueLength = sizeof(TA_APPLETALK_ADDRESS);
|
|||
|
pEaBuf->EaNameLength = TDI_TRANSPORT_ADDRESS_LENGTH;
|
|||
|
RtlCopyMemory(pEaBuf->EaName,TdiTransportAddress,
|
|||
|
TDI_TRANSPORT_ADDRESS_LENGTH + 1);
|
|||
|
Ta.TAAddressCount = 1;
|
|||
|
Ta.Address[0].AddressType = TDI_ADDRESS_TYPE_APPLETALK;
|
|||
|
Ta.Address[0].AddressLength = sizeof(TDI_ADDRESS_APPLETALK);
|
|||
|
|
|||
|
// Open dynamic socket - note we will be using up one extra socket for the
|
|||
|
// duration we have the device handle open in this routine.
|
|||
|
Ta.Address[0].Address[0].Socket = 0;
|
|||
|
Ta.Address[0].Address[0].Network = 0;
|
|||
|
Ta.Address[0].Address[0].Node = 0;
|
|||
|
|
|||
|
RtlCopyMemory(&pEaBuf->EaName[TDI_TRANSPORT_ADDRESS_LENGTH + 1], &Ta, sizeof(Ta));
|
|||
|
|
|||
|
// Open a handle to appletalk stack DDP device
|
|||
|
status = NtCreateFile(
|
|||
|
&AtalkAddressHandle,
|
|||
|
GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
|
|||
|
&ObjAttr,
|
|||
|
&IoStsBlk,
|
|||
|
NULL, // Don't Care
|
|||
|
0, // Don't Care
|
|||
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|||
|
FILE_CREATE,
|
|||
|
0,
|
|||
|
&EaBuffer,
|
|||
|
sizeof(EaBuffer));
|
|||
|
|
|||
|
if (!NT_SUCCESS(status))
|
|||
|
{
|
|||
|
DBGPRINT(("NbpRegDeregService: NtCreateFile failed (0x%x)\n", status));
|
|||
|
return WSHNtStatusToWinsockErr(status);
|
|||
|
}
|
|||
|
|
|||
|
do
|
|||
|
{
|
|||
|
status = NtCreateEvent(
|
|||
|
&eventHandle,
|
|||
|
EVENT_ALL_ACCESS,
|
|||
|
NULL,
|
|||
|
SynchronizationEvent,
|
|||
|
FALSE
|
|||
|
);
|
|||
|
|
|||
|
if ( !NT_SUCCESS(status) )
|
|||
|
{
|
|||
|
DBGPRINT(("NbpRegDeregService: Create event failed (%d)\n", status));
|
|||
|
break;
|
|||
|
}
|
|||
|
else
|
|||
|
closeEventHandle = TRUE;
|
|||
|
|
|||
|
tdiActionLength = sizeof(NBP_REGDEREG_ACTION);
|
|||
|
tdiAction = RtlAllocateHeap( RtlProcessHeap( ), 0, tdiActionLength );
|
|||
|
if ( tdiAction == NULL )
|
|||
|
{
|
|||
|
status = STATUS_NO_MEMORY;
|
|||
|
DBGPRINT(("NbpRegDeregService: Could not allocate tdiAction\n"));
|
|||
|
break;
|
|||
|
}
|
|||
|
else
|
|||
|
freeTdiAction = TRUE;
|
|||
|
|
|||
|
tdiAction->TransportId = MATK;
|
|||
|
|
|||
|
tdiAction->ActionCode = (dwOperation == SERVICE_REGISTER) ?
|
|||
|
COMMON_ACTION_NBPREGISTER_BY_ADDR :
|
|||
|
COMMON_ACTION_NBPREMOVE_BY_ADDR;
|
|||
|
|
|||
|
nbpAction = (PNBP_REGDEREG_ACTION)tdiAction;
|
|||
|
|
|||
|
//
|
|||
|
// Copy the nbp tuple info to the proper place
|
|||
|
//
|
|||
|
|
|||
|
nbpAction->Params.RegisterTuple.Address.Network = pSockAddr->sat_net;
|
|||
|
nbpAction->Params.RegisterTuple.Address.Node = pSockAddr->sat_node;
|
|||
|
nbpAction->Params.RegisterTuple.Address.Socket = pSockAddr->sat_socket;
|
|||
|
nbpAction->Params.RegisterTuple.Enumerator = 0;
|
|||
|
nbpAction->Params.RegisterTuple.NbpName = *((PNBP_NAME)pNbpName);
|
|||
|
|
|||
|
//
|
|||
|
// Convert the tuple to MAC code page
|
|||
|
//
|
|||
|
|
|||
|
if (!WshNbpNameToMacCodePage(
|
|||
|
(PWSH_NBP_NAME)&nbpAction->Params.RegisterTuple.NbpName))
|
|||
|
{
|
|||
|
status = STATUS_INVALID_PARAMETER;
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
status = NtDeviceIoControlFile(
|
|||
|
AtalkAddressHandle,
|
|||
|
eventHandle,
|
|||
|
completionApc,
|
|||
|
apcContext,
|
|||
|
&IoStsBlk,
|
|||
|
IOCTL_TDI_ACTION,
|
|||
|
NULL, // Input buffer
|
|||
|
0, // Length of input buffer
|
|||
|
tdiAction,
|
|||
|
tdiActionLength
|
|||
|
);
|
|||
|
|
|||
|
if ( status == STATUS_PENDING )
|
|||
|
{
|
|||
|
status = NtWaitForSingleObject( eventHandle, FALSE, NULL );
|
|||
|
ASSERT( NT_SUCCESS(status) );
|
|||
|
status = IoStsBlk.Status;
|
|||
|
}
|
|||
|
|
|||
|
if (status != NO_ERROR)
|
|||
|
{
|
|||
|
DBGPRINT(("NbpRegDeregService: DevIoctl SO_(DE)REGISTER_NAME failed (0x%x)\n", status));
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
} while (0);
|
|||
|
|
|||
|
if (closeEventHandle)
|
|||
|
NtClose(eventHandle);
|
|||
|
|
|||
|
if (freeTdiAction)
|
|||
|
RtlFreeHeap( RtlProcessHeap( ), 0, tdiAction );
|
|||
|
|
|||
|
NtClose(AtalkAddressHandle);
|
|||
|
|
|||
|
return WSHNtStatusToWinsockErr(status);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|