mirror of https://github.com/lianthony/NT4.0
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.
2510 lines
63 KiB
2510 lines
63 KiB
/*++
|
|
|
|
Copyright (c) 1994 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
Nspsvc.c
|
|
|
|
Abstract:
|
|
|
|
This module contains support for the Name Space Provider APIs
|
|
GetService() & SetService(). This is a wrapper that uses the
|
|
newer enumeration APIs to emulate these 1.1 functions
|
|
|
|
Author:
|
|
|
|
Chuck Y Chan (ChuckC) 25-May-1994
|
|
|
|
Revision History:
|
|
Arnold Miller <arnoldm) 10-April-1996 Put into winsock2
|
|
|
|
--*/
|
|
|
|
#ifdef CHICAGO
|
|
#undef UNICODE
|
|
#else
|
|
#define UNICODE
|
|
#define _UNICODE
|
|
#endif
|
|
|
|
#include "winsockp.h"
|
|
#ifdef CHICAGO
|
|
#include "imported.h"
|
|
#endif
|
|
#include <nspmisc.h>
|
|
#include <rpc.h>
|
|
#include <stdlib.h>
|
|
#include <align.h>
|
|
|
|
|
|
AFPROTOCOLS afp = {AF_INET, IPPROTO_UDP};
|
|
|
|
extern GUID HostnameGuid, AddressGuid;
|
|
|
|
#define LKXBUFSIZE (sizeof(WSAQUERYSET) + 500) // Is 500 bytes enough?
|
|
|
|
//
|
|
// Forward declare
|
|
//
|
|
|
|
INT
|
|
APIENTRY
|
|
SetServiceWorker (
|
|
IN DWORD dwNameSpace,
|
|
IN DWORD dwOperation,
|
|
IN DWORD dwFlags,
|
|
IN LPSERVICE_INFO lpServiceInfo,
|
|
IN LPSERVICE_ASYNC_INFO lpServiceAsyncInfo,
|
|
IN BOOL fUnicodeCaller,
|
|
IN OUT LPDWORD lpdwStatusFlags
|
|
) ;
|
|
|
|
INT
|
|
APIENTRY
|
|
GetServiceWorker (
|
|
IN DWORD dwNameSpace,
|
|
IN LPGUID lpGuid,
|
|
IN LPTSTR lpServiceName,
|
|
IN DWORD dwProperties,
|
|
IN OUT LPVOID lpBuffer,
|
|
IN OUT LPDWORD lpdwBufferSize,
|
|
IN LPSERVICE_ASYNC_INFO lpServiceAsyncInfo,
|
|
IN BOOL fUnicodeCaller
|
|
) ;
|
|
|
|
DWORD
|
|
APIENTRY
|
|
PackBlobWorker(
|
|
IN LPTSTR lpTypeName,
|
|
IN DWORD dwValueCount,
|
|
IN PSERVICE_TYPE_VALUE_ABS Values,
|
|
OUT PBYTE *lppBuffer,
|
|
OUT DWORD *lpdBufferSize,
|
|
IN BOOL fIsAnsi
|
|
);
|
|
|
|
|
|
#if defined(UNICODE)
|
|
DWORD
|
|
AllocateUnicodeString (
|
|
IN LPSTR lpAnsi,
|
|
IN OUT LPTSTR *lppUnicode
|
|
) ;
|
|
#endif
|
|
|
|
DWORD
|
|
PackBuffer (
|
|
IN DWORD dwNameSpace,
|
|
IN LPGUID lpServiceType,
|
|
IN LPSERVICE_INFO lpServiceInfo,
|
|
IN BOOL fUnicodeCaller,
|
|
IN LPTSTR lpServiceName,
|
|
IN OUT LPBYTE *lppStart,
|
|
IN OUT LPBYTE *lppEnd,
|
|
IN OUT LPDWORD lpdwBytesTooFew
|
|
);
|
|
|
|
VOID
|
|
PackString(
|
|
IN LPTSTR lpSource,
|
|
IN LPBYTE lpStartVar,
|
|
IN OUT LPBYTE *lppEnd,
|
|
IN OUT LPBYTE *lppDest,
|
|
IN OUT LPDWORD lpdwBytesTooFew,
|
|
IN BOOL fConvertToAnsi
|
|
) ;
|
|
|
|
INT
|
|
SSRegistrySettings(
|
|
IN DWORD dwOperation,
|
|
IN LPTSTR lpServiceTypeName,
|
|
IN LPGUID lpServiceType
|
|
);
|
|
|
|
VOID
|
|
FreeAllocatedClassInfo(BOOL fUnicodeCaller,
|
|
DWORD dwNumberOf,
|
|
LPWSANSCLASSINFO lpcli);
|
|
//
|
|
// Utility functions
|
|
//
|
|
|
|
//
|
|
// Do the registry add or delete for a SetService call
|
|
//
|
|
|
|
INT
|
|
SSRegistrySettings(
|
|
IN DWORD dwOperation,
|
|
IN LPTSTR lpServiceTypeName,
|
|
IN LPGUID lpServiceType
|
|
)
|
|
{
|
|
HKEY hKey;
|
|
DWORD dwDisposition;
|
|
INT err;
|
|
|
|
#ifdef CHICAGO
|
|
//
|
|
// Try to load RPCRT4.DL
|
|
//
|
|
|
|
if(!DemandLoadRpcrt4())
|
|
{
|
|
return(ERROR_PROC_NOT_FOUND); // bugbug?
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// Open the key that stores the name space provider info.
|
|
//
|
|
|
|
err = RegCreateKeyEx(
|
|
HKEY_LOCAL_MACHINE,
|
|
NSP_SERVICE_KEY_NAME,
|
|
0,
|
|
TEXT(""),
|
|
REG_OPTION_NON_VOLATILE,
|
|
KEY_READ | KEY_WRITE,
|
|
NULL,
|
|
&hKey,
|
|
&dwDisposition
|
|
);
|
|
|
|
if(err == ERROR_SUCCESS)
|
|
{
|
|
if (dwOperation == SERVICE_ADD_TYPE)
|
|
{
|
|
//
|
|
// if adding a type, create the key if need & set a <GUID>
|
|
// value to have a { XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX }
|
|
// representation of the GUID.
|
|
//
|
|
|
|
HKEY hKeyService = NULL ;
|
|
LPTSTR lpGuidString = NULL, lpTmpString = NULL ;
|
|
|
|
//
|
|
// Open the key corresponding to the service (create if not there).
|
|
//
|
|
|
|
err = RegCreateKeyEx(
|
|
hKey,
|
|
lpServiceTypeName,
|
|
0,
|
|
TEXT(""),
|
|
REG_OPTION_NON_VOLATILE,
|
|
KEY_READ | KEY_WRITE,
|
|
NULL,
|
|
&hKeyService,
|
|
&dwDisposition
|
|
);
|
|
|
|
if(err == ERROR_SUCCESS)
|
|
{
|
|
//
|
|
// Convert the GUID to string
|
|
//
|
|
|
|
#ifdef CHICAGO
|
|
err = lpUuidToString(
|
|
#else
|
|
|
|
err = UuidToString(
|
|
#endif
|
|
lpServiceType,
|
|
&lpTmpString) ;
|
|
|
|
if (err == NO_ERROR)
|
|
{
|
|
//
|
|
// add the braces before & after
|
|
//
|
|
|
|
if (lpGuidString = ALLOCATE_HEAP((_tcslen(lpTmpString) + 3)
|
|
* sizeof(TCHAR)))
|
|
{
|
|
_tcscpy(lpGuidString, TEXT("{")) ;
|
|
_tcscat(lpGuidString, lpTmpString) ;
|
|
_tcscat(lpGuidString, TEXT("}")) ;
|
|
|
|
//
|
|
// write it out
|
|
//
|
|
err = RegSetValueEx(
|
|
hKeyService,
|
|
TEXT("GUID"),
|
|
0,
|
|
REG_SZ,
|
|
(LPBYTE) lpGuidString,
|
|
(_tcslen(lpGuidString) + 1) * sizeof(TCHAR)) ;
|
|
|
|
(void) FREE_HEAP(lpGuidString) ;
|
|
}
|
|
else
|
|
{
|
|
err = GetLastError() ;
|
|
}
|
|
|
|
#ifdef CHICAGO
|
|
(void) lpRpcStringFree(&lpTmpString) ;
|
|
#else
|
|
(void) RpcStringFree(&lpTmpString) ;
|
|
#endif
|
|
}
|
|
|
|
(void) RegCloseKey(hKeyService) ;
|
|
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// deleting the sevice type.just nuke the key
|
|
//
|
|
err = RegDeleteKey(
|
|
hKey,
|
|
lpServiceTypeName) ;
|
|
}
|
|
}
|
|
(void) RegCloseKey(hKey) ;
|
|
}
|
|
return(err);
|
|
}
|
|
|
|
|
|
// Convert a SERVICE_ADDRESSES structure into a CSADDR_INFO structure.
|
|
// This will allocate whatever memory is required leaving the caller to
|
|
// free it. A return value of NULL indicates a memory allocation error
|
|
//
|
|
|
|
CSADDR_INFO *
|
|
SrvAddrsToCsAddrs(
|
|
PSERVICE_ADDRESSES psa,
|
|
PDWORD pdwNumberOfCsAddrs)
|
|
{
|
|
DWORD dwTotalSize;
|
|
DWORD dwX;
|
|
PCSADDR_INFO pcsa;
|
|
|
|
//
|
|
// first compute the size of the memory buffer we will need
|
|
//
|
|
|
|
*pdwNumberOfCsAddrs = psa->dwAddressCount;
|
|
|
|
//
|
|
// Account for all of the fixed-sized structures
|
|
//
|
|
dwTotalSize = sizeof(CSADDR_INFO) * psa->dwAddressCount;
|
|
|
|
pcsa = (PCSADDR_INFO)ALLOCATE_HEAP(dwTotalSize);
|
|
if(pcsa)
|
|
{
|
|
//
|
|
// ready to repack the information.
|
|
// BUGBUG. Don't know what to put in the iProtocol field
|
|
// of the CSADDR_INFO since there is no universal value
|
|
// for the "default" protocol.
|
|
//
|
|
|
|
PCSADDR_INFO pcsa1 = pcsa;
|
|
|
|
memset(pcsa, 0, dwTotalSize);
|
|
|
|
//
|
|
// convert each SERVICE_ADDRESS to a CSADD_ADDR / SOCKET_ADDR pair.
|
|
// Note BUGBUG above!
|
|
//
|
|
|
|
for(dwX = 0; dwX < psa->dwAddressCount; dwX++)
|
|
{
|
|
PSOCKET_ADDRESS psocka = &pcsa1->LocalAddr;
|
|
|
|
// pcsa1->iSocketType = (int)psa->Addresses[dwX].dwAddressType;
|
|
psocka->iSockaddrLength = (int)psa->Addresses[dwX].dwAddressLength;
|
|
psocka->lpSockaddr = (LPSOCKADDR)psa->Addresses[dwX].lpAddress;
|
|
psocka->lpSockaddr->sa_family =
|
|
(USHORT)psa->Addresses[dwX].dwAddressType;
|
|
pcsa1++;
|
|
}
|
|
}
|
|
return(pcsa);
|
|
}
|
|
|
|
//
|
|
// And the reverse: convert a CSADDR_INFO structure into a
|
|
// SERVICE_ADDRESSES
|
|
//
|
|
|
|
PSERVICE_ADDRESSES
|
|
CsAddrsToSrvAddrs(
|
|
LPCSADDR_INFO pcsadr,
|
|
DWORD dwNumberOfCsAddr)
|
|
{
|
|
DWORD dwTotalSize;
|
|
DWORD dwX;
|
|
PSERVICE_ADDRESSES psas;
|
|
|
|
//
|
|
// Compute the total memory size needed.
|
|
//
|
|
|
|
if(dwNumberOfCsAddr == 0)
|
|
{
|
|
return(NULL);
|
|
}
|
|
dwTotalSize = sizeof(SERVICE_ADDRESSES) +
|
|
(sizeof(SERVICE_ADDRESS) * (dwNumberOfCsAddr - 1));
|
|
|
|
|
|
psas = (PSERVICE_ADDRESSES)ALLOCATE_HEAP(dwTotalSize);
|
|
if(psas)
|
|
{
|
|
//
|
|
// The buffer is allocated with the SERVICE_ADDRESSES structure
|
|
// first, followed by the requisite number of SERVICE_ADDRESS
|
|
// structures.
|
|
//
|
|
|
|
PSERVICE_ADDRESS psa = &psas->Addresses[0];
|
|
|
|
|
|
psas->dwAddressCount = dwNumberOfCsAddr;
|
|
for(dwX = 0; dwX < dwNumberOfCsAddr; dwX++)
|
|
{
|
|
psa->dwAddressType = pcsadr[dwX].RemoteAddr.lpSockaddr->sa_family;
|
|
psa->dwAddressFlags = 0;
|
|
psa->dwAddressLength = pcsadr[dwX].RemoteAddr.iSockaddrLength;
|
|
psa->dwPrincipalLength = 0;
|
|
psa->lpPrincipal = 0;
|
|
psa->lpAddress = (PBYTE)pcsadr[dwX].RemoteAddr.lpSockaddr;
|
|
psa++;
|
|
}
|
|
}
|
|
return(psas);
|
|
}
|
|
|
|
//
|
|
// Convert a SERVICE_TYPE_VALUE into a CLASSINFO structure. This is
|
|
// straight-forward requiring only switching around a few values.
|
|
// returns a pointer to the structure allocated using LocalAlloc.
|
|
//
|
|
|
|
LPWSANSCLASSINFO
|
|
ServiceTypeToClassInfo(
|
|
BOOL fUnicodeCaller,
|
|
DWORD dwNumberOf,
|
|
PSERVICE_TYPE_VALUE_ABS pstv)
|
|
{
|
|
LPWSANSCLASSINFO lpci, lpci1;
|
|
DWORD dwSaveNumber = dwNumberOf;
|
|
|
|
lpci = ALLOCATE_HEAP(sizeof(WSANSCLASSINFO) * dwNumberOf);
|
|
if(lpci1 = lpci)
|
|
{
|
|
memset(lpci, 0, sizeof(WSANSCLASSINFO) * dwNumberOf);
|
|
while(dwNumberOf--)
|
|
{
|
|
#ifdef UNICODE
|
|
if(!fUnicodeCaller)
|
|
{
|
|
if(AllocateUnicodeString((PCHAR)pstv->lpValueName,
|
|
&lpci1->lpszName) != NO_ERROR)
|
|
{
|
|
FreeAllocatedClassInfo(fUnicodeCaller,
|
|
dwSaveNumber,
|
|
lpci);
|
|
lpci = 0;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
lpci1->lpszName = pstv->lpValueName;
|
|
}
|
|
lpci1->dwNameSpace = pstv->dwNameSpace;
|
|
lpci1->dwValueType = pstv->dwValueType;
|
|
lpci1->dwValueSize = pstv->dwValueSize;
|
|
lpci1->lpValue = pstv->lpValue;
|
|
lpci1++;
|
|
pstv++;
|
|
}
|
|
}
|
|
return(lpci);
|
|
}
|
|
|
|
//
|
|
// Free an allocated class info
|
|
//
|
|
VOID
|
|
FreeAllocatedClassInfo(BOOL fUnicodeCaller,
|
|
DWORD dwNumberOf,
|
|
LPWSANSCLASSINFO lpci)
|
|
{
|
|
LPWSANSCLASSINFO lpci1 = lpci;
|
|
|
|
#ifdef UNICODE
|
|
if(!fUnicodeCaller)
|
|
{
|
|
while(dwNumberOf--)
|
|
{
|
|
FREE_HEAP(lpci1->lpszName);
|
|
lpci1++;
|
|
}
|
|
}
|
|
#endif
|
|
FREE_HEAP(lpci);
|
|
}
|
|
|
|
//
|
|
// Actual WSA functions
|
|
//
|
|
|
|
#if defined(UNICODE)
|
|
|
|
INT
|
|
APIENTRY
|
|
SetServiceA (
|
|
IN DWORD dwNameSpace,
|
|
IN DWORD dwOperation,
|
|
IN DWORD dwFlags,
|
|
IN LPSERVICE_INFOA lpServiceInfo,
|
|
IN LPSERVICE_ASYNC_INFO lpServiceAsyncInfo,
|
|
IN OUT LPDWORD lpdwStatusFlags
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
ANSI version of SetService
|
|
|
|
Arguments:
|
|
|
|
See Unicode version of SetService
|
|
|
|
Return Value:
|
|
|
|
See Unicode version of SetService
|
|
|
|
--*/
|
|
|
|
{
|
|
LPWSTR lpUnicodeServiceName = NULL ;
|
|
LPWSTR lpUnicodeComment = NULL ;
|
|
LPWSTR lpUnicodeLocale = NULL ;
|
|
LPWSTR lpUnicodeMachineName = NULL ;
|
|
|
|
DWORD err = NO_ERROR ;
|
|
INT res = 0 ;
|
|
|
|
LPSERVICE_INFOW lpUnicodeServiceInfo = NULL ;
|
|
|
|
//
|
|
// check parameters. majority are checked in the worker,
|
|
// but we need access the structure below to map to Unicode,
|
|
// so we check it here.
|
|
//
|
|
if (!lpServiceInfo)
|
|
{
|
|
SetLastError(ERROR_INVALID_PARAMETER) ;
|
|
return -1 ;
|
|
}
|
|
|
|
//
|
|
// allocate the necessary memory for the unicode buffer
|
|
//
|
|
lpUnicodeServiceInfo =
|
|
(LPSERVICE_INFOW) ALLOCATE_HEAP(sizeof(SERVICE_INFOW)) ;
|
|
if (!lpUnicodeServiceInfo)
|
|
{
|
|
goto ExitPoint ;
|
|
}
|
|
|
|
//
|
|
// allocate the necessary memory for the service name string
|
|
//
|
|
if (err = AllocateUnicodeString(lpServiceInfo->lpServiceName,
|
|
&lpUnicodeServiceName))
|
|
{
|
|
goto ExitPoint ;
|
|
}
|
|
|
|
//
|
|
// allocate the necessary memory for the service comment string
|
|
//
|
|
if (err = AllocateUnicodeString(lpServiceInfo->lpComment,
|
|
&lpUnicodeComment))
|
|
{
|
|
goto ExitPoint ;
|
|
}
|
|
|
|
//
|
|
// allocate the necessary memory for the locale string
|
|
//
|
|
if (err = AllocateUnicodeString(lpServiceInfo->lpLocale,
|
|
&lpUnicodeLocale))
|
|
{
|
|
goto ExitPoint ;
|
|
}
|
|
|
|
|
|
//
|
|
// allocate the necessary memory for the machine name string
|
|
//
|
|
if (err = AllocateUnicodeString(lpServiceInfo->lpMachineName,
|
|
&lpUnicodeMachineName))
|
|
{
|
|
goto ExitPoint ;
|
|
}
|
|
|
|
//
|
|
// setup the Unicode Structure
|
|
//
|
|
lpUnicodeServiceInfo->lpServiceType = lpServiceInfo->lpServiceType ;
|
|
lpUnicodeServiceInfo->lpServiceName = lpUnicodeServiceName ;
|
|
lpUnicodeServiceInfo->lpComment = lpUnicodeComment ;
|
|
lpUnicodeServiceInfo->lpLocale = lpUnicodeLocale ;
|
|
lpUnicodeServiceInfo->dwDisplayHint = lpServiceInfo->dwDisplayHint ;
|
|
lpUnicodeServiceInfo->dwVersion = lpServiceInfo->dwVersion ;
|
|
lpUnicodeServiceInfo->dwTime = lpServiceInfo->dwTime ;
|
|
lpUnicodeServiceInfo->lpMachineName = lpUnicodeMachineName ;
|
|
lpUnicodeServiceInfo->lpServiceAddress = lpServiceInfo->lpServiceAddress ;
|
|
lpUnicodeServiceInfo->ServiceSpecificInfo.cbSize =
|
|
lpServiceInfo->ServiceSpecificInfo.cbSize ;
|
|
lpUnicodeServiceInfo->ServiceSpecificInfo.pBlobData =
|
|
lpServiceInfo->ServiceSpecificInfo.pBlobData ;
|
|
|
|
//
|
|
// call the worker routine
|
|
//
|
|
res = SetServiceWorker (dwNameSpace,
|
|
dwOperation,
|
|
dwFlags,
|
|
lpUnicodeServiceInfo,
|
|
lpServiceAsyncInfo,
|
|
FALSE, // BLOB is not Unicode
|
|
lpdwStatusFlags ) ;
|
|
|
|
ExitPoint:
|
|
|
|
if (lpUnicodeServiceName)
|
|
FREE_HEAP(lpUnicodeServiceName) ;
|
|
if (lpUnicodeComment)
|
|
FREE_HEAP(lpUnicodeComment) ;
|
|
if (lpUnicodeLocale)
|
|
FREE_HEAP(lpUnicodeLocale) ;
|
|
if (lpUnicodeMachineName)
|
|
FREE_HEAP(lpUnicodeMachineName) ;
|
|
|
|
if (lpUnicodeServiceInfo)
|
|
FREE_HEAP(lpUnicodeServiceInfo) ;
|
|
|
|
//
|
|
// if this routine hit an error, set it as last error. else
|
|
// rely on the worker routine to set it.
|
|
//
|
|
if (err)
|
|
{
|
|
SetLastError(err) ;
|
|
res = -1 ;
|
|
}
|
|
|
|
return(res) ;
|
|
}
|
|
|
|
#else // defined(UNICODE)
|
|
|
|
INT
|
|
APIENTRY
|
|
SetServiceW (
|
|
IN DWORD dwNameSpace,
|
|
IN DWORD dwOperation,
|
|
IN DWORD dwFlags,
|
|
IN LPSERVICE_INFOW lpServiceInfo,
|
|
IN LPSERVICE_ASYNC_INFO lpServiceAsyncInfo,
|
|
IN OUT LPDWORD lpdwStatusFlags
|
|
)
|
|
{
|
|
|
|
SetLastError( ERROR_NOT_SUPPORTED );
|
|
return -1;
|
|
|
|
} // SetServiceW
|
|
|
|
#endif // defined(UNICODE)
|
|
|
|
INT
|
|
APIENTRY
|
|
SetService (
|
|
IN DWORD dwNameSpace,
|
|
IN DWORD dwOperation,
|
|
IN DWORD dwFlags,
|
|
IN LPSERVICE_INFO lpServiceInfo,
|
|
IN LPSERVICE_ASYNC_INFO lpServiceAsyncInfo,
|
|
IN OUT LPDWORD lpdwStatusFlags
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Unicode version of SetService. This function is called to
|
|
set information about a network service.
|
|
|
|
Arguments:
|
|
|
|
dwNameSpace - Name space affected by the operation. NS_DEFAULT
|
|
is used to mean all default name spaces.
|
|
|
|
dwOperation - Operation to perform, like SERVICE_REGISTER,
|
|
SERVICE_DEREGISTER.
|
|
|
|
dwFlags - flags for the opertation, like SERVICE_FLAG_DEFER
|
|
|
|
dwServiceInfo - pointer to SERVICE_INFO structure containing the
|
|
information to set.
|
|
|
|
lpServiceAsyncInfo - currently must ne NULL.
|
|
|
|
lpdwStatusFlags - used to return info bits about the operation.
|
|
|
|
Return Value:
|
|
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
INT res ;
|
|
|
|
//
|
|
// call the worker routine
|
|
//
|
|
res = SetServiceWorker (dwNameSpace,
|
|
dwOperation,
|
|
dwFlags,
|
|
lpServiceInfo,
|
|
lpServiceAsyncInfo,
|
|
#if defined(UNICODE)
|
|
TRUE, // BLOB is Unicode
|
|
#else
|
|
FALSE,
|
|
#endif
|
|
lpdwStatusFlags ) ;
|
|
|
|
return res ;
|
|
}
|
|
|
|
#if defined (UNICODE)
|
|
|
|
INT
|
|
APIENTRY
|
|
GetServiceA (
|
|
IN DWORD dwNameSpace,
|
|
IN LPGUID lpGuid,
|
|
IN LPSTR lpServiceName,
|
|
IN DWORD dwProperties,
|
|
IN OUT LPVOID lpBuffer,
|
|
IN OUT LPDWORD lpdwBufferSize,
|
|
IN LPSERVICE_ASYNC_INFO lpServiceAsyncInfo
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
ANSI verson of GetService. Obtains information about the service.
|
|
If dwNameSpace is NS_DEFAULT,may return >1 NS_SERVICE_INFO structures,
|
|
one for each name space.
|
|
|
|
Arguments:
|
|
|
|
See GetServiceW.
|
|
|
|
Return Value:
|
|
|
|
See GetServiceW.
|
|
|
|
--*/
|
|
|
|
{
|
|
INT res ;
|
|
DWORD err ;
|
|
LPWSTR lpUnicodeServiceName = NULL ;
|
|
|
|
//
|
|
// allocate the necessary memory for the service name string
|
|
//
|
|
if (err = AllocateUnicodeString(lpServiceName,
|
|
&lpUnicodeServiceName))
|
|
{
|
|
res = -1 ;
|
|
goto ExitPoint ;
|
|
}
|
|
|
|
res = GetServiceWorker ( dwNameSpace,
|
|
lpGuid,
|
|
lpUnicodeServiceName,
|
|
dwProperties,
|
|
lpBuffer,
|
|
lpdwBufferSize,
|
|
lpServiceAsyncInfo,
|
|
FALSE ) ; // we dont want Unicode Blob
|
|
ExitPoint:
|
|
|
|
if (lpUnicodeServiceName)
|
|
FREE_HEAP(lpUnicodeServiceName) ;
|
|
|
|
return res ;
|
|
}
|
|
|
|
#else // defined(UNICODE)
|
|
|
|
INT
|
|
APIENTRY
|
|
GetServiceW (
|
|
IN DWORD dwNameSpace,
|
|
IN LPGUID lpGuid,
|
|
IN LPWSTR lpServiceName,
|
|
IN DWORD dwProperties,
|
|
IN OUT LPVOID lpBuffer,
|
|
IN OUT LPDWORD lpdwBufferSize,
|
|
IN LPSERVICE_ASYNC_INFO lpServiceAsyncInfo
|
|
)
|
|
{
|
|
|
|
SetLastError( ERROR_NOT_SUPPORTED );
|
|
return -1;
|
|
|
|
} // GetServiceW
|
|
|
|
#endif // defined(UNICODE)
|
|
|
|
INT
|
|
APIENTRY
|
|
GetService (
|
|
IN DWORD dwNameSpace,
|
|
IN LPGUID lpGuid,
|
|
IN LPTSTR lpServiceName,
|
|
IN DWORD dwProperties,
|
|
IN OUT LPVOID lpBuffer,
|
|
IN OUT LPDWORD lpdwBufferSize,
|
|
IN LPSERVICE_ASYNC_INFO lpServiceAsyncInfo
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Unicode verson of GetService. Obtains information about the service.
|
|
If dwNameSpace is NS_DEFAULT,may return >1 NS_SERVICE_INFO structures,
|
|
one for each name space.
|
|
|
|
Arguments:
|
|
|
|
dwNameSpace - name spaces to query. if NS_DEFAULT, then all default
|
|
name spaces.
|
|
|
|
lpGuid - GUID defining type of service to query
|
|
|
|
lpServiceName - name of service instance to query
|
|
|
|
dwProperties - what properties to ask for
|
|
|
|
lpBuffer - return buffer to be filled with NS_SERVICE_INFO
|
|
structures
|
|
|
|
lpdwBufferSize - on input, size of buffer. used to return required
|
|
size if buffer too small.
|
|
|
|
lpServiceAsyncInfo - currently must be NULL.
|
|
|
|
Return Value:
|
|
|
|
number of structures returned if successful. zero if no matching
|
|
structure returned. -1 if an error occured.
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
INT res ;
|
|
|
|
res = GetServiceWorker ( dwNameSpace,
|
|
lpGuid,
|
|
lpServiceName,
|
|
dwProperties,
|
|
lpBuffer,
|
|
lpdwBufferSize,
|
|
lpServiceAsyncInfo,
|
|
#if defined(UNICODE)
|
|
TRUE ) ; // yes, we want Unicode Blob
|
|
#else
|
|
FALSE ) ; // no Unicode Blob
|
|
#endif
|
|
return res ;
|
|
}
|
|
|
|
//
|
|
// Worker routines
|
|
//
|
|
|
|
|
|
#if OLDXBYY
|
|
|
|
INT
|
|
APIENTRY
|
|
SetServiceWorker (
|
|
IN DWORD dwNameSpace,
|
|
IN DWORD dwOperation,
|
|
IN DWORD dwFlags,
|
|
IN LPSERVICE_INFO lpServiceInfo,
|
|
IN LPSERVICE_ASYNC_INFO lpServiceAsyncInfo,
|
|
IN BOOL fUnicodeCaller,
|
|
IN OUT LPDWORD lpdwStatusFlags
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Worker function for SetService.
|
|
|
|
Arguments:
|
|
|
|
As SetServiceW, except that fUnicodeCaller has been added
|
|
which tells us if the call originated as Unicode or Ansi. We
|
|
need distinguish because of the BLOB data which we cannot interpret.
|
|
|
|
Return Value:
|
|
|
|
Zero if no error. SOCKET_ERROR otherwise. Caller may issue
|
|
WSAGetLastError() to get more detailed error info.
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD err = NO_ERROR ;
|
|
BOOL fOneSucceeded = FALSE ;
|
|
LPBYTE lpTmpBlobData = NULL ;
|
|
DWORD dwTmpBlobDataSize ;
|
|
PLIST_ENTRY listEntry;
|
|
SERVICE_INFO TmpSvcInfo ;
|
|
|
|
//
|
|
// check parameters.
|
|
// we currently dont support async operation.
|
|
//
|
|
|
|
if ( ARGUMENT_PRESENT( lpServiceAsyncInfo ) )
|
|
{
|
|
SetLastError( ERROR_NOT_SUPPORTED );
|
|
return -1;
|
|
}
|
|
|
|
if ( !ARGUMENT_PRESENT( lpServiceInfo ) ||
|
|
!ARGUMENT_PRESENT( lpdwStatusFlags ) )
|
|
{
|
|
SetLastError( ERROR_INVALID_PARAMETER );
|
|
return -1;
|
|
}
|
|
|
|
*lpdwStatusFlags = 0 ;
|
|
|
|
//
|
|
// If our NSP internal structures have not yet been initialized,
|
|
// initialize them now.
|
|
//
|
|
|
|
if ( !NspInitialized )
|
|
{
|
|
err = InitializeNsp( );
|
|
if ( err != NO_ERROR )
|
|
{
|
|
SetLastError( err );
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
//
|
|
// we make a copy of the structure since we may modify it.
|
|
//
|
|
|
|
memcpy(&TmpSvcInfo,lpServiceInfo,sizeof(TmpSvcInfo)) ;
|
|
|
|
//
|
|
// the only operation where we take explicit action is ADD_TYPE and
|
|
// DELETE_TYPE. everything else gets done by providers.
|
|
//
|
|
|
|
if ((dwOperation == SERVICE_ADD_TYPE) ||
|
|
(dwOperation == SERVICE_DELETE_TYPE))
|
|
{
|
|
LPTSTR lpServiceTypeName = NULL ;
|
|
#ifndef CHICAGO
|
|
LPSERVICE_TYPE_INFO lpServiceTypeInfo ;
|
|
#endif
|
|
LPSERVICE_TYPE_INFO_ABS lpSvcTypeInfoAbs ;
|
|
|
|
//
|
|
// make sure Blob has valid data
|
|
//
|
|
if ((TmpSvcInfo.ServiceSpecificInfo.cbSize == 0) ||
|
|
(TmpSvcInfo.ServiceSpecificInfo.pBlobData == NULL))
|
|
{
|
|
SetLastError( ERROR_INVALID_PARAMETER );
|
|
return -1;
|
|
}
|
|
|
|
//
|
|
// get the name of the service type being added.
|
|
// if not unicode caller, we need convert to unicode.
|
|
//
|
|
|
|
lpSvcTypeInfoAbs = (LPSERVICE_TYPE_INFO_ABS)
|
|
TmpSvcInfo.ServiceSpecificInfo.pBlobData ;
|
|
#if defined(UNICODE)
|
|
if (fUnicodeCaller)
|
|
{
|
|
#endif
|
|
lpServiceTypeName = lpSvcTypeInfoAbs->lpTypeName ;
|
|
#if defined(UNICODE)
|
|
}
|
|
else
|
|
{
|
|
err = AllocateUnicodeString(
|
|
((LPSERVICE_TYPE_INFO_ABSA)lpSvcTypeInfoAbs)->lpTypeName,
|
|
&lpServiceTypeName) ;
|
|
if (err != NO_ERROR)
|
|
{
|
|
SetLastError(err) ;
|
|
return -1 ;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// make sure the service type name is not empty
|
|
//
|
|
if ( lpServiceTypeName &&
|
|
*lpServiceTypeName != 0 )
|
|
{
|
|
err = SSRegistrySettings(
|
|
dwOperation,
|
|
lpServiceTypeName,
|
|
TmpSvcInfo.lpServiceType);
|
|
}
|
|
else
|
|
{
|
|
err = ERROR_INVALID_PARAMETER ;
|
|
}
|
|
|
|
if ( err != NO_ERROR )
|
|
{
|
|
SetLastError(err) ;
|
|
#if defined(UNICODE)
|
|
if (!fUnicodeCaller)
|
|
(void) FREE_HEAP(lpServiceTypeName) ;
|
|
#endif
|
|
return -1;
|
|
}
|
|
|
|
//
|
|
// bail out if have error here
|
|
//
|
|
|
|
if ( err != NO_ERROR )
|
|
{
|
|
#if defined(UNICODE)
|
|
if (!fUnicodeCaller)
|
|
(void) FREE_HEAP(lpServiceTypeName) ;
|
|
#endif
|
|
SetLastError(err) ;
|
|
return -1;
|
|
}
|
|
|
|
|
|
//
|
|
// For ADD and DELETE type, the blob may contain pointers.
|
|
// We convert this to be self relative before passing on to
|
|
// providers.
|
|
//
|
|
err = PackBlobWorker(
|
|
lpSvcTypeInfoAbs->lpTypeName,
|
|
lpSvcTypeInfoAbs->dwValueCount,
|
|
lpSvcTypeInfoAbs->Values,
|
|
&lpTmpBlobData,
|
|
&dwTmpBlobDataSize,
|
|
!fUnicodeCaller) ;
|
|
|
|
//
|
|
// overwrite the pointers in our private copy
|
|
//
|
|
|
|
if (err == NO_ERROR)
|
|
{
|
|
TmpSvcInfo.ServiceSpecificInfo.pBlobData =
|
|
lpTmpBlobData ;
|
|
TmpSvcInfo.ServiceSpecificInfo.cbSize =
|
|
dwTmpBlobDataSize ;
|
|
}
|
|
|
|
//
|
|
// if not unicode, we allocated this string.
|
|
// free it now as we are done with it.
|
|
//
|
|
#if defined(UNICODE)
|
|
if (!fUnicodeCaller)
|
|
(void) FREE_HEAP(lpServiceTypeName) ;
|
|
lpServiceTypeName = NULL ;
|
|
#endif
|
|
|
|
//
|
|
// cleanup, & exit if error
|
|
//
|
|
|
|
if ( err != NO_ERROR )
|
|
{
|
|
SetLastError(err) ;
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Loop through our name spaces, performing the operation
|
|
// requested. This loop only goes thru more than one iteration if
|
|
// the nameSpace is 0 (Default NameSpaces).
|
|
//
|
|
|
|
for ( listEntry = NameSpaceListHead.Flink;
|
|
listEntry != &NameSpaceListHead;
|
|
listEntry = listEntry->Flink )
|
|
{
|
|
PNAME_SPACE_INFO lpNameSpace;
|
|
DWORD error ;
|
|
|
|
lpNameSpace = CONTAINING_RECORD(
|
|
listEntry,
|
|
NAME_SPACE_INFO,
|
|
NameSpaceListEntry
|
|
);
|
|
|
|
//
|
|
// Determine whether we should make use of this name space
|
|
// provider.
|
|
//
|
|
|
|
if ( !IsValidNameSpace( dwNameSpace, lpNameSpace ) )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// make sure function is supported.
|
|
//
|
|
|
|
if (lpNameSpace->SetServiceProc == NULL)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
error = lpNameSpace->SetServiceProc(dwOperation,
|
|
dwFlags,
|
|
fUnicodeCaller,
|
|
&TmpSvcInfo) ;
|
|
if (error != NO_ERROR)
|
|
{
|
|
*lpdwStatusFlags |= SET_SERVICE_PARTIAL_SUCCESS ;
|
|
SetLastError(error) ;
|
|
}
|
|
else
|
|
{
|
|
fOneSucceeded = TRUE ;
|
|
}
|
|
}
|
|
|
|
if (lpTmpBlobData)
|
|
(void) FREE_HEAP(lpTmpBlobData) ;
|
|
|
|
return (fOneSucceeded ? 0 : -1) ;
|
|
|
|
}
|
|
|
|
INT
|
|
APIENTRY
|
|
GetServiceWorker (
|
|
IN DWORD dwNameSpace,
|
|
IN LPGUID lpGuid,
|
|
IN LPTSTR lpServiceName,
|
|
IN DWORD dwProperties,
|
|
IN OUT LPVOID lpBuffer,
|
|
IN OUT LPDWORD lpdwBufferSize,
|
|
IN LPSERVICE_ASYNC_INFO lpServiceAsyncInfo,
|
|
IN BOOL fUnicodeCaller
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Worker function for GetService.
|
|
|
|
Arguments:
|
|
|
|
As GetServiceW, except that fUnicodeCaller has been added
|
|
which tells us if the call originated as Unicode or Ansi. We
|
|
need distinguish because of the BLOB data which we cannot interpret.
|
|
|
|
Return Value:
|
|
|
|
Number of NS_SERVICE_INFO structures obtained if no error.
|
|
SOCKET_ERROR otherwise. Caller may issue WSAGetLastError()
|
|
to get more detailed error info.
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD err = NO_ERROR ;
|
|
INT cEntries = 0 ;
|
|
PLIST_ENTRY listEntry;
|
|
DWORD dwBytesTooFew, dwTmpBufferSize ;
|
|
BYTE DummyBuffer[1] ;
|
|
LPBYTE lpStart, lpEnd ;
|
|
LPSERVICE_INFO lpServiceInfo = NULL ;
|
|
BOOL fMatchingNspCalled = FALSE ;
|
|
|
|
//
|
|
// we currently dont support async operation
|
|
//
|
|
|
|
if ( ARGUMENT_PRESENT( lpServiceAsyncInfo ) )
|
|
{
|
|
SetLastError( ERROR_NOT_SUPPORTED );
|
|
return -1;
|
|
}
|
|
|
|
//
|
|
// check the other parameters
|
|
//
|
|
|
|
if ( !ARGUMENT_PRESENT( lpGuid ) ||
|
|
!ARGUMENT_PRESENT( lpdwBufferSize ) ||
|
|
!ARGUMENT_PRESENT( lpServiceName ) )
|
|
{
|
|
SetLastError( ERROR_INVALID_PARAMETER );
|
|
return -1;
|
|
}
|
|
|
|
//
|
|
// If our NSP internal structures have not yet been initialized,
|
|
// initialize them now.
|
|
//
|
|
|
|
if ( !NspInitialized )
|
|
{
|
|
err = InitializeNsp();
|
|
|
|
if ( err != NO_ERROR )
|
|
{
|
|
SetLastError( err );
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
//
|
|
// if buffer is NULL, user is just asking for size.
|
|
// set BufferSize to 0 and proceed. we will find the size.
|
|
//
|
|
|
|
if ( !ARGUMENT_PRESENT( lpBuffer ) )
|
|
{
|
|
lpBuffer = &DummyBuffer[0] ;
|
|
*lpdwBufferSize = 0 ;
|
|
}
|
|
|
|
//
|
|
// allocate tmp buffer. make the tmp buffer at least as big as user's
|
|
// buffer and no less than 4K.
|
|
//
|
|
|
|
dwTmpBufferSize = (*lpdwBufferSize < 4096) ? 4096 : *lpdwBufferSize ;
|
|
lpServiceInfo = (LPSERVICE_INFO) ALLOCATE_HEAP(dwTmpBufferSize) ;
|
|
|
|
if (!lpServiceInfo)
|
|
{
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY) ;
|
|
return(-1) ;
|
|
}
|
|
|
|
//
|
|
// init variables & pointers in the buffer.
|
|
//
|
|
dwBytesTooFew = 0 ;
|
|
lpStart = (LPBYTE) lpBuffer ;
|
|
lpEnd = (LPBYTE) ROUND_DOWN_POINTER((LPBYTE)lpBuffer + *lpdwBufferSize,
|
|
ALIGN_LPDWORD) ;
|
|
|
|
//
|
|
// Loop through our name spaces, performing the operation
|
|
// requested. This loop only goes thru more than one iteration if
|
|
// the NameSpace is 'Default NameSpaces'. We dont stop on errors,
|
|
// but continue to get as many as we can.
|
|
//
|
|
|
|
for ( listEntry = NameSpaceListHead.Flink;
|
|
listEntry != &NameSpaceListHead;
|
|
listEntry = listEntry->Flink )
|
|
{
|
|
PNAME_SPACE_INFO lpNameSpace;
|
|
DWORD error ;
|
|
|
|
lpNameSpace = CONTAINING_RECORD(
|
|
listEntry,
|
|
NAME_SPACE_INFO,
|
|
NameSpaceListEntry
|
|
);
|
|
|
|
//
|
|
// Determine whether we should make use of this name space
|
|
// provider.
|
|
//
|
|
|
|
if ( !IsValidNameSpace( dwNameSpace, lpNameSpace ) )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// make sure function is supported.
|
|
//
|
|
|
|
if (lpNameSpace->GetServiceProc == NULL)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
fMatchingNspCalled = TRUE ;
|
|
|
|
error = lpNameSpace->GetServiceProc(lpGuid,
|
|
(LPWSTR)lpServiceName,
|
|
dwProperties,
|
|
fUnicodeCaller,
|
|
lpServiceInfo,
|
|
&dwTmpBufferSize) ;
|
|
if (error != NO_ERROR)
|
|
{
|
|
SetLastError(error) ;
|
|
}
|
|
else
|
|
{
|
|
|
|
err = PackBuffer ( lpNameSpace->NameSpace,
|
|
lpGuid,
|
|
lpServiceInfo,
|
|
fUnicodeCaller,
|
|
lpServiceName,
|
|
&lpStart,
|
|
&lpEnd,
|
|
&dwBytesTooFew ) ;
|
|
|
|
if (err == NO_ERROR)
|
|
{
|
|
//
|
|
// successfully found one. increment count
|
|
//
|
|
cEntries++ ;
|
|
}
|
|
else if (err == ERROR_INSUFFICIENT_BUFFER)
|
|
{
|
|
//
|
|
// continue. not interesting error to report right now.
|
|
// we will check for dwBytesTooFew > 0 later.
|
|
//
|
|
}
|
|
else
|
|
{
|
|
SetLastError(err) ;
|
|
}
|
|
}
|
|
|
|
} // for all namespaces
|
|
|
|
(void) FREE_HEAP(lpServiceInfo) ;
|
|
|
|
//
|
|
// if the buffer is not big enough, set the number of bytes required
|
|
// and return -1.
|
|
//
|
|
if (dwBytesTooFew)
|
|
{
|
|
SetLastError(ERROR_INSUFFICIENT_BUFFER) ;
|
|
*lpdwBufferSize += dwBytesTooFew ;
|
|
return -1 ;
|
|
}
|
|
|
|
//
|
|
// no matching provider was called. set the error since no-one
|
|
// else would have done so.
|
|
//
|
|
if (!fMatchingNspCalled)
|
|
SetLastError(ERROR_SERVICE_NOT_FOUND) ;
|
|
|
|
return cEntries ;
|
|
}
|
|
|
|
#else // OLDXBY
|
|
|
|
INT
|
|
APIENTRY
|
|
SetServiceWorker (
|
|
IN DWORD dwNameSpace,
|
|
IN DWORD dwOperation,
|
|
IN DWORD dwFlags,
|
|
IN LPSERVICE_INFO lpServiceInfo,
|
|
IN LPSERVICE_ASYNC_INFO lpServiceAsyncInfo,
|
|
IN BOOL fUnicodeCaller,
|
|
IN OUT LPDWORD lpdwStatusFlags
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Worker function for SetService.
|
|
|
|
Arguments:
|
|
|
|
As SetServiceW, except that fUnicodeCaller has been added
|
|
which tells us if the call originated as Unicode or Ansi. We
|
|
need distinguish because of the BLOB data which we cannot interpret.
|
|
|
|
Return Value:
|
|
|
|
Zero if no error. SOCKET_ERROR otherwise. Caller may issue
|
|
WSAGetLastError() to get more detailed error info.
|
|
|
|
--*/
|
|
|
|
{
|
|
INT err = NO_ERROR, err1 ;
|
|
BOOL fOneSucceeded = FALSE ;
|
|
PLIST_ENTRY listEntry;
|
|
SERVICE_INFO TmpSvcInfo ;
|
|
LPCSADDR_INFO pcsadr;
|
|
WSAQUERYSET wsaq;
|
|
WSAVERSION wsaver;
|
|
WSADATA wsaData;
|
|
DWORD dwType;
|
|
|
|
//
|
|
// check parameters.
|
|
// we currently dont support async operation.
|
|
//
|
|
|
|
if ( ARGUMENT_PRESENT( lpServiceAsyncInfo ) )
|
|
{
|
|
SetLastError( ERROR_NOT_SUPPORTED );
|
|
return -1;
|
|
}
|
|
|
|
if ( !ARGUMENT_PRESENT( lpServiceInfo ) ||
|
|
!ARGUMENT_PRESENT( lpdwStatusFlags ) )
|
|
{
|
|
SetLastError( ERROR_INVALID_PARAMETER );
|
|
return -1;
|
|
}
|
|
|
|
*lpdwStatusFlags = 0 ;
|
|
|
|
//
|
|
// we make a copy of the structure since we may modify it.
|
|
//
|
|
|
|
memcpy(&TmpSvcInfo,lpServiceInfo,sizeof(TmpSvcInfo)) ;
|
|
|
|
//
|
|
// Note, this call goes to the wsock32 routine first, so the
|
|
// version must be the 1.1 WINSOCK. Pretty hokey, but that's
|
|
// the way it is.
|
|
//
|
|
WSAStartup(0x101, &wsaData);
|
|
|
|
//
|
|
// the only operation where we take explicit action is ADD_TYPE and
|
|
// DELETE_TYPE. everything else gets done by providers.
|
|
//
|
|
|
|
switch(dwOperation)
|
|
{
|
|
case SERVICE_ADD_TYPE:
|
|
case SERVICE_DELETE_TYPE:
|
|
|
|
{
|
|
HKEY hKey ;
|
|
LPTSTR lpServiceTypeName = NULL ;
|
|
LPSERVICE_TYPE_INFO lpServiceTypeInfo ;
|
|
DWORD dwDisposition = 0 ;
|
|
LPSERVICE_TYPE_INFO_ABS lpSvcTypeInfoAbs ;
|
|
|
|
//
|
|
// make sure Blob has valid data
|
|
//
|
|
if ((TmpSvcInfo.ServiceSpecificInfo.cbSize == 0) ||
|
|
(TmpSvcInfo.ServiceSpecificInfo.pBlobData == NULL))
|
|
{
|
|
SetLastError( ERROR_INVALID_PARAMETER );
|
|
err = -1;
|
|
goto OuttaHere;
|
|
}
|
|
|
|
//
|
|
// get the name of the service type being added.
|
|
// if not unicode caller, we need convert to unicode.
|
|
//
|
|
|
|
lpSvcTypeInfoAbs = (LPSERVICE_TYPE_INFO_ABS)
|
|
TmpSvcInfo.ServiceSpecificInfo.pBlobData ;
|
|
#if defined(UNICODE)
|
|
if (fUnicodeCaller)
|
|
{
|
|
#endif
|
|
lpServiceTypeName = lpSvcTypeInfoAbs->lpTypeName ;
|
|
#if defined(UNICODE)
|
|
}
|
|
else
|
|
{
|
|
err = AllocateUnicodeString(
|
|
((LPSERVICE_TYPE_INFO_ABSA)lpSvcTypeInfoAbs)->lpTypeName,
|
|
&lpServiceTypeName) ;
|
|
if (err != NO_ERROR)
|
|
{
|
|
SetLastError(err) ;
|
|
err = -1;
|
|
goto OuttaHere;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// make sure the service type name is not empty
|
|
//
|
|
if ( !lpServiceTypeName ||
|
|
*lpServiceTypeName == 0 )
|
|
{
|
|
err = ERROR_INVALID_PARAMETER ;
|
|
}
|
|
else
|
|
{
|
|
err = SSRegistrySettings(dwOperation,
|
|
lpServiceTypeName,
|
|
TmpSvcInfo.lpServiceType);
|
|
}
|
|
|
|
if ( err != NO_ERROR )
|
|
{
|
|
SetLastError(err) ;
|
|
#if defined(UNICODE)
|
|
if (!fUnicodeCaller)
|
|
(void) FREE_HEAP(lpServiceTypeName) ;
|
|
#endif
|
|
err = -1;
|
|
goto OuttaHere;
|
|
}
|
|
|
|
if (dwOperation == SERVICE_ADD_TYPE)
|
|
{
|
|
LPWSANSCLASSINFO lpcli;
|
|
WSASERVICECLASSINFO wsacl;
|
|
|
|
lpcli = ServiceTypeToClassInfo(
|
|
fUnicodeCaller,
|
|
lpSvcTypeInfoAbs->dwValueCount,
|
|
lpSvcTypeInfoAbs->Values);
|
|
|
|
if(lpcli)
|
|
{
|
|
wsacl.lpServiceClassId = TmpSvcInfo.lpServiceType;
|
|
wsacl.lpszServiceClassName = lpServiceTypeName;
|
|
wsacl.dwCount = lpSvcTypeInfoAbs->dwValueCount;
|
|
wsacl.lpClassInfos = lpcli;
|
|
err = WSAInstallServiceClass(&wsacl);
|
|
FreeAllocatedClassInfo(fUnicodeCaller,
|
|
lpSvcTypeInfoAbs->dwValueCount,
|
|
lpcli);
|
|
if(err != NO_ERROR)
|
|
{
|
|
err = GetLastError();
|
|
}
|
|
}
|
|
}
|
|
|
|
else
|
|
{
|
|
//
|
|
// need to uninstall the information
|
|
//
|
|
|
|
err = WSARemoveServiceClass(TmpSvcInfo.lpServiceType);
|
|
if(err != NO_ERROR)
|
|
{
|
|
err = GetLastError();
|
|
}
|
|
|
|
}
|
|
#if defined(UNICODE)
|
|
if (!fUnicodeCaller)
|
|
(void) FREE_HEAP(lpServiceTypeName) ;
|
|
#endif
|
|
|
|
if ( err != NO_ERROR )
|
|
{
|
|
SetLastError(err) ;
|
|
err = -1;
|
|
}
|
|
goto OuttaHere;
|
|
}
|
|
|
|
//
|
|
// Not ADD_TYPE or DELETE_TYPE. Do the others by issuing
|
|
// a WSASetService call.
|
|
|
|
case SERVICE_REGISTER:
|
|
|
|
dwType = RNRSERVICE_REGISTER;
|
|
break;
|
|
|
|
case SERVICE_DEREGISTER:
|
|
|
|
dwType = RNRSERVICE_DEREGISTER;
|
|
break;
|
|
|
|
default:
|
|
goto OuttaHere;
|
|
} // switch
|
|
|
|
memset(&wsaq, 0, sizeof(wsaq));
|
|
if(dwOperation == SERVICE_REGISTER)
|
|
{
|
|
//
|
|
// registration includes addresses that must be
|
|
// coerced from SERVICE_ADDRESSES to CSADDR_INFO.
|
|
//
|
|
|
|
pcsadr = SrvAddrsToCsAddrs(lpServiceInfo->lpServiceAddress,
|
|
&wsaq.dwNumberOfCsAddrs);
|
|
|
|
}
|
|
else
|
|
{
|
|
pcsadr = 0;
|
|
}
|
|
|
|
wsaq.lpcsaBuffer = pcsadr;
|
|
|
|
wsaq.dwSize = sizeof(wsaq);
|
|
wsaq.lpszServiceInstanceName = lpServiceInfo->lpServiceName;
|
|
wsaq.lpServiceClassId = lpServiceInfo->lpServiceType;
|
|
wsaq.lpszComment = lpServiceInfo->lpComment;
|
|
wsaq.dwNameSpace = dwNameSpace;
|
|
if(lpServiceInfo->dwVersion)
|
|
{
|
|
wsaq.lpVersion = &wsaver;
|
|
wsaver.dwVersion = lpServiceInfo->dwVersion;
|
|
wsaver.ecHow = COMP_EQUAL;
|
|
}
|
|
|
|
//
|
|
// BUGBUG. Locale, display hint, time, and machine name are lost
|
|
// N.B. dwFlags ignored.
|
|
//
|
|
|
|
|
|
err = WSASetService(&wsaq,
|
|
dwType,
|
|
0);
|
|
if(pcsadr)
|
|
{
|
|
FREE_HEAP(pcsadr);
|
|
}
|
|
|
|
OuttaHere:
|
|
err1 = GetLastError();
|
|
WSACleanup();
|
|
SetLastError(err1);
|
|
return(err);
|
|
}
|
|
|
|
INT
|
|
APIENTRY
|
|
GetServiceWorker (
|
|
IN DWORD dwNameSpace,
|
|
IN LPGUID lpGuid,
|
|
IN LPTSTR lpServiceName,
|
|
IN DWORD dwProperties,
|
|
IN OUT LPVOID lpBuffer,
|
|
IN OUT LPDWORD lpdwBufferSize,
|
|
IN LPSERVICE_ASYNC_INFO lpServiceAsyncInfo,
|
|
IN BOOL fUnicodeCaller
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Worker function for GetService.
|
|
|
|
Arguments:
|
|
|
|
As GetServiceW, except that fUnicodeCaller has been added
|
|
which tells us if the call originated as Unicode or Ansi. We
|
|
need distinguish because of the BLOB data which we cannot interpret.
|
|
|
|
Return Value:
|
|
|
|
Number of NS_SERVICE_INFO structures obtained if no error.
|
|
SOCKET_ERROR otherwise. Caller may issue WSAGetLastError()
|
|
to get more detailed error info.
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD err = NO_ERROR ;
|
|
DWORD dwBytesTooFew, dwTmpBufferSize, dwTempSize ;
|
|
BYTE DummyBuffer[sizeof(WSAQUERYSET)] ;
|
|
LPBYTE lpStart, lpEnd ;
|
|
BOOL fMatchingNspCalled = FALSE ;
|
|
PWSAQUERYSET pwsaq;
|
|
HANDLE hLookup = 0;
|
|
BOOL fGotAtLeastOne = FALSE;
|
|
SERVICE_INFO si;
|
|
DWORD cEntries = 0;
|
|
WSADATA wsaData;
|
|
|
|
//
|
|
// we currently dont support async operation
|
|
//
|
|
|
|
if ( ARGUMENT_PRESENT( lpServiceAsyncInfo ) )
|
|
{
|
|
SetLastError( ERROR_NOT_SUPPORTED );
|
|
return -1;
|
|
}
|
|
|
|
//
|
|
// check the other parameters
|
|
//
|
|
|
|
if ( !ARGUMENT_PRESENT( lpGuid ) ||
|
|
!ARGUMENT_PRESENT( lpdwBufferSize ) ||
|
|
!ARGUMENT_PRESENT( lpServiceName ) )
|
|
{
|
|
SetLastError( ERROR_INVALID_PARAMETER );
|
|
return -1;
|
|
}
|
|
|
|
//
|
|
// if buffer is NULL, user is just asking for size.
|
|
// set BufferSize to 0 and proceed. we will find the size.
|
|
//
|
|
|
|
if ( !ARGUMENT_PRESENT( lpBuffer ) )
|
|
{
|
|
lpBuffer = &DummyBuffer[0] ;
|
|
*lpdwBufferSize = 0 ;
|
|
}
|
|
|
|
//
|
|
// allocate tmp buffer.
|
|
//
|
|
|
|
dwTmpBufferSize = *lpdwBufferSize + sizeof(WSAQUERYSETW);
|
|
dwTmpBufferSize = max(dwTmpBufferSize, 4096); // be generous
|
|
// to avoid overflow
|
|
pwsaq = (PWSAQUERYSET)ALLOCATE_HEAP(dwTmpBufferSize) ;
|
|
|
|
if (!pwsaq)
|
|
{
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY) ;
|
|
return(-1) ;
|
|
}
|
|
|
|
memset(pwsaq, 0, dwTmpBufferSize);
|
|
|
|
//
|
|
// init variables & pointers in the buffer.
|
|
//
|
|
dwBytesTooFew = 0 ;
|
|
lpStart = (LPBYTE) lpBuffer ;
|
|
lpEnd = (LPBYTE) ROUND_DOWN_POINTER((LPBYTE)lpBuffer + *lpdwBufferSize,
|
|
ALIGN_LPDWORD) ;
|
|
|
|
//
|
|
// Get it started with a call to WSALookupServiceBegin
|
|
//
|
|
|
|
pwsaq->dwSize = sizeof(*pwsaq);
|
|
pwsaq->lpszServiceInstanceName = lpServiceName;
|
|
pwsaq->lpServiceClassId = lpGuid;
|
|
pwsaq->dwNameSpace = dwNameSpace;
|
|
|
|
|
|
//
|
|
// Note, this call goes to the wsock32 routine first, so the
|
|
// version must be the 1.1 WINSOCK. Pretty hokey, but that's
|
|
// the way it is.
|
|
//
|
|
WSAStartup(0x101, &wsaData);
|
|
|
|
//
|
|
// BUGBUG. Can't do the RES_SERVICE stuff just yet
|
|
//
|
|
|
|
#ifdef CHICAGO
|
|
err = (*ws2_WSALookupServiceBegin)(
|
|
#else
|
|
err = WSALookupServiceBegin(pwsaq,
|
|
#endif
|
|
LUP_RETURN_VERSION |
|
|
LUP_RETURN_COMMENT |
|
|
LUP_RETURN_ADDR,
|
|
&hLookup);
|
|
|
|
memset(&si, 0, sizeof(si));
|
|
|
|
while(err == NO_ERROR)
|
|
{
|
|
//
|
|
// The lookup is primed. Fetch actual matches. For each match,
|
|
// construct a SERVICE_INFO and use the 1.1 Packing routines
|
|
//
|
|
|
|
dwTempSize = dwTmpBufferSize;
|
|
#ifdef CHICAGO
|
|
err = (*ws2_WSALookupServiceNext)(
|
|
#else
|
|
err = WSALookupServiceNext(
|
|
#endif
|
|
hLookup,
|
|
0,
|
|
&dwTempSize,
|
|
pwsaq);
|
|
|
|
//
|
|
// if it worked, pack it in. Since the allocated buffer is quite large,
|
|
// it is unlikely it overflowed
|
|
|
|
|
|
if(err == NO_ERROR)
|
|
{
|
|
//
|
|
// got some. Build a ServiceInfo structure so that
|
|
// the 1.1 Packing routines work
|
|
//
|
|
|
|
fGotAtLeastOne = TRUE;
|
|
|
|
|
|
si.lpServiceAddress = CsAddrsToSrvAddrs(
|
|
pwsaq->lpcsaBuffer,
|
|
pwsaq->dwNumberOfCsAddrs);
|
|
|
|
si.lpComment = pwsaq->lpszComment;
|
|
if(pwsaq->lpVersion)
|
|
{
|
|
si.dwVersion = pwsaq->lpVersion->dwVersion;
|
|
}
|
|
else
|
|
{
|
|
si.dwVersion = 0;
|
|
}
|
|
|
|
err = PackBuffer ( pwsaq->dwNameSpace,
|
|
lpGuid,
|
|
&si,
|
|
fUnicodeCaller,
|
|
lpServiceName,
|
|
&lpStart,
|
|
&lpEnd,
|
|
&dwBytesTooFew ) ;
|
|
|
|
if(si.lpServiceAddress)
|
|
{
|
|
FREE_HEAP(si.lpServiceAddress);
|
|
}
|
|
|
|
if(err == NO_ERROR)
|
|
{
|
|
cEntries++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
int err1 = GetLastError();
|
|
|
|
if((err1 == NO_DATA)
|
|
||
|
|
(err1 = WSA_E_NO_MORE))
|
|
{
|
|
err = NO_ERROR;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
if(hLookup)
|
|
{
|
|
if(err != NO_ERROR)
|
|
{
|
|
err = GetLastError();
|
|
}
|
|
#ifdef CHICAGO
|
|
(*ws2_WSALookupServiceEnd)(hLookup);
|
|
#else
|
|
WSALookupServiceEnd(hLookup);
|
|
#endif
|
|
SetLastError(err);
|
|
}
|
|
|
|
WSACleanup();
|
|
|
|
FREE_HEAP(pwsaq) ;
|
|
|
|
//
|
|
// if the buffer is not big enough, set the number of bytes required
|
|
// and return -1.
|
|
//
|
|
if (dwBytesTooFew)
|
|
{
|
|
SetLastError(ERROR_INSUFFICIENT_BUFFER) ;
|
|
*lpdwBufferSize += dwBytesTooFew ;
|
|
return(-1) ;
|
|
}
|
|
|
|
return cEntries ;
|
|
}
|
|
|
|
#endif // OLDXBY
|
|
|
|
DWORD
|
|
PackBuffer (
|
|
IN DWORD dwNameSpace,
|
|
IN LPGUID lpServiceType,
|
|
IN LPSERVICE_INFO lpServiceInfo,
|
|
IN BOOL fUnicodeCaller,
|
|
IN LPTSTR lpServiceName,
|
|
IN OUT LPBYTE *lppStart,
|
|
IN OUT LPBYTE *lppEnd,
|
|
IN OUT LPDWORD lpdwBytesTooFew
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Pack a buffer with fixed size structure at front & variable size
|
|
data at end.
|
|
|
|
Arguments:
|
|
|
|
dwNameSpace - part of info in structure
|
|
|
|
lpServiceType - part of info in structure
|
|
|
|
lpServiceInfo - part of info in structure
|
|
|
|
fUnicodeCaller - was the caller calling W or A version?
|
|
|
|
lpServiceName - part of info in structure
|
|
|
|
lppStart - starting point to store fixed structure
|
|
|
|
lppEnd - just past end of buffer. this pointer is
|
|
moved back before variable data is packed.
|
|
|
|
lpdwBytesTooFew - count of bytes too few. this is always
|
|
incremented as it may already contain value from
|
|
earlier calls.
|
|
|
|
Return Value:
|
|
|
|
NO_ERROR if successful. Win32 error otherwise.
|
|
|
|
--*/
|
|
|
|
{
|
|
LPNS_SERVICE_INFO lpNsServiceInfoNew = (LPNS_SERVICE_INFO) *lppStart ;
|
|
LPSERVICE_INFO lpServiceInfoNew = &(lpNsServiceInfoNew->ServiceInfo) ;
|
|
DWORD Length ;
|
|
|
|
LPBYTE lpTmpComment = NULL,
|
|
lpTmpLocale = NULL,
|
|
lpTmpMachinename = NULL,
|
|
lpTmpName = NULL,
|
|
lpEnd = *lppEnd,
|
|
lpStartVar = *lppStart + sizeof(*lpNsServiceInfoNew) ;
|
|
|
|
//
|
|
// figure out whether we have enough room for structure
|
|
//
|
|
if (lpStartVar > lpEnd)
|
|
{
|
|
*lpdwBytesTooFew += ((LPBYTE)lpStartVar) - ((LPBYTE)lpEnd) ;
|
|
lpStartVar = lpEnd ;
|
|
}
|
|
else
|
|
{
|
|
lpNsServiceInfoNew->dwNameSpace = dwNameSpace ;
|
|
}
|
|
*lppStart = lpStartVar ;
|
|
|
|
//
|
|
// figure out whether we have enough room for the GUID
|
|
//
|
|
if (lpStartVar + sizeof(GUID) > lpEnd)
|
|
{
|
|
*lpdwBytesTooFew += (((LPBYTE)lpStartVar + sizeof(GUID))
|
|
- ((LPBYTE)lpEnd)) ;
|
|
lpEnd = lpStartVar ;
|
|
}
|
|
else
|
|
{
|
|
lpEnd -= sizeof(GUID) ;
|
|
RtlCopyMemory(lpEnd, lpServiceType, sizeof(GUID)) ;
|
|
lpServiceInfoNew->lpServiceType = (LPGUID) lpEnd ;
|
|
}
|
|
|
|
//
|
|
// ditto for each of the strings. the PackString function
|
|
// does not return errors. it merely increments BytesTooFew as need.
|
|
//
|
|
PackString(lpServiceInfo->lpComment,
|
|
lpStartVar,
|
|
&lpEnd,
|
|
&lpTmpComment,
|
|
lpdwBytesTooFew,
|
|
!fUnicodeCaller) ; // convert to ansi if caller not unicode
|
|
|
|
PackString(lpServiceInfo->lpLocale,
|
|
lpStartVar,
|
|
&lpEnd,
|
|
&lpTmpLocale,
|
|
lpdwBytesTooFew,
|
|
!fUnicodeCaller) ; // convert to ansi if caller not unicode
|
|
|
|
PackString(lpServiceInfo->lpMachineName,
|
|
lpStartVar,
|
|
&lpEnd,
|
|
&lpTmpMachinename,
|
|
lpdwBytesTooFew,
|
|
!fUnicodeCaller) ; // convert to ansi if caller not unicode
|
|
|
|
PackString(lpServiceName,
|
|
lpStartVar,
|
|
&lpEnd,
|
|
&lpTmpName,
|
|
lpdwBytesTooFew,
|
|
!fUnicodeCaller) ; // convert to ansi if caller not unicode
|
|
|
|
//
|
|
// figure out whether we have enough room for the service address
|
|
//
|
|
if (lpServiceInfo->lpServiceAddress)
|
|
{
|
|
DWORD AddressCount =
|
|
lpServiceInfo->lpServiceAddress->dwAddressCount ;
|
|
LPSERVICE_ADDRESS lpAddress =
|
|
&(lpServiceInfo->lpServiceAddress->Addresses[0]) ;
|
|
LPSERVICE_ADDRESS lpTmpAddress ;
|
|
LPSERVICE_ADDRESSES lpTmpServiceAddress ;
|
|
|
|
//
|
|
// make sure we have enough space for the structure &
|
|
// the variable array at the end
|
|
//
|
|
Length = sizeof(SERVICE_ADDRESSES) +
|
|
((AddressCount ? (AddressCount - 1) : 0) *
|
|
sizeof(SERVICE_ADDRESS)) ;
|
|
|
|
if ((lpStartVar + Length) > lpEnd)
|
|
{
|
|
//
|
|
// not enough space.
|
|
//
|
|
*lpdwBytesTooFew += (((LPBYTE)lpStartVar + Length) -
|
|
((LPBYTE)lpEnd)) ;
|
|
lpEnd = lpStartVar ;
|
|
}
|
|
else
|
|
{
|
|
lpEnd -= Length ;
|
|
lpTmpServiceAddress = (LPSERVICE_ADDRESSES) lpEnd ;
|
|
lpTmpServiceAddress->dwAddressCount = AddressCount ;
|
|
|
|
lpTmpAddress =
|
|
(LPSERVICE_ADDRESS) &(lpTmpServiceAddress->Addresses[0]) ;
|
|
}
|
|
|
|
//
|
|
// for each variable array, make sure we have enough for the
|
|
// thang it points to.
|
|
//
|
|
while(AddressCount--)
|
|
{
|
|
DWORD AddressLength = ROUND_UP_COUNT(lpAddress->dwAddressLength,
|
|
ALIGN_DWORD) ;
|
|
|
|
DWORD PrincipalLength = ROUND_UP_COUNT(lpAddress->dwPrincipalLength,
|
|
ALIGN_DWORD) ;
|
|
|
|
if ((lpStartVar + AddressLength + PrincipalLength) > lpEnd)
|
|
{
|
|
//
|
|
// not enough space.
|
|
//
|
|
*lpdwBytesTooFew += (((LPBYTE)lpStartVar +
|
|
AddressLength +
|
|
PrincipalLength) -
|
|
(LPBYTE)lpEnd) ;
|
|
lpEnd = lpStartVar ;
|
|
}
|
|
else
|
|
{
|
|
lpTmpAddress->dwAddressType = lpAddress->dwAddressType ;
|
|
lpTmpAddress->dwAddressFlags = lpAddress->dwAddressFlags ;
|
|
|
|
//
|
|
// copy address data
|
|
//
|
|
|
|
lpTmpAddress->dwAddressLength = lpAddress->dwAddressLength ;
|
|
lpEnd -= AddressLength ;
|
|
RtlCopyMemory(lpEnd,
|
|
(LPBYTE)lpAddress->lpAddress,
|
|
lpAddress->dwAddressLength) ;
|
|
lpTmpAddress->lpAddress = lpEnd ;
|
|
|
|
//
|
|
// copy principal data
|
|
//
|
|
|
|
lpTmpAddress->dwPrincipalLength = lpAddress->dwPrincipalLength ;
|
|
lpEnd -= PrincipalLength ;
|
|
if (lpAddress->lpPrincipal)
|
|
{
|
|
RtlCopyMemory(lpEnd,
|
|
(LPBYTE)lpAddress->lpPrincipal,
|
|
lpAddress->dwPrincipalLength) ;
|
|
lpTmpAddress->lpPrincipal = lpEnd ;
|
|
}
|
|
else
|
|
lpTmpAddress->lpPrincipal = NULL ;
|
|
|
|
lpTmpAddress++ ;
|
|
}
|
|
|
|
lpAddress++ ;
|
|
}
|
|
|
|
lpServiceInfoNew->lpServiceAddress = *lpdwBytesTooFew ? NULL :
|
|
lpTmpServiceAddress ;
|
|
}
|
|
|
|
//
|
|
// figure out whether we have enough room for the Blob
|
|
//
|
|
if (Length = ROUND_UP_COUNT(lpServiceInfo->ServiceSpecificInfo.cbSize,
|
|
ALIGN_DWORD))
|
|
{
|
|
if ((lpStartVar + Length) > lpEnd)
|
|
{
|
|
//
|
|
// not enough space.
|
|
//
|
|
*lpdwBytesTooFew += (((LPBYTE)lpStartVar + Length) -
|
|
((LPBYTE)lpEnd)) ;
|
|
lpEnd = lpStartVar ;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// NOTE/WARNING: Blob most NOT contain pointers!!!
|
|
//
|
|
lpEnd -= Length ;
|
|
RtlCopyMemory(lpEnd,
|
|
lpServiceInfo->ServiceSpecificInfo.pBlobData,
|
|
Length) ;
|
|
|
|
lpServiceInfoNew->ServiceSpecificInfo.cbSize =
|
|
lpServiceInfo->ServiceSpecificInfo.cbSize ;
|
|
|
|
lpServiceInfoNew->ServiceSpecificInfo.pBlobData = lpEnd ;
|
|
}
|
|
}
|
|
|
|
if (*lpdwBytesTooFew > 0)
|
|
{
|
|
//
|
|
// buffer is not big enough. dont copy any data
|
|
//
|
|
*lppEnd = lpEnd ;
|
|
return ERROR_INSUFFICIENT_BUFFER ;
|
|
}
|
|
|
|
//
|
|
// copy the rest of the data over to the user's buffer
|
|
//
|
|
|
|
//
|
|
// these are DWORDs & are easy to copy
|
|
//
|
|
lpServiceInfoNew->dwDisplayHint = lpServiceInfo->dwDisplayHint ;
|
|
lpServiceInfoNew->dwVersion = lpServiceInfo->dwVersion ;
|
|
lpServiceInfoNew->dwTime = lpServiceInfo->dwTime ;
|
|
|
|
//
|
|
// setup strings (already packed at end)
|
|
//
|
|
lpServiceInfoNew->lpServiceName = (LPTSTR) lpTmpName ;
|
|
lpServiceInfoNew->lpComment = (LPTSTR) lpTmpComment ;
|
|
lpServiceInfoNew->lpLocale = (LPTSTR) lpTmpLocale ;
|
|
lpServiceInfoNew->lpMachineName = (LPTSTR) lpTmpMachinename ;
|
|
|
|
*lppEnd = lpEnd ;
|
|
|
|
return NO_ERROR ;
|
|
}
|
|
|
|
VOID
|
|
PackString(
|
|
LPTSTR lpSource,
|
|
LPBYTE lpStartVar,
|
|
LPBYTE *lppEnd,
|
|
LPBYTE *lppDest,
|
|
LPDWORD lpdwBytesTooFew,
|
|
BOOL fConvertToAnsi
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Packs a single string at the end of a buffer.
|
|
|
|
Arguments:
|
|
|
|
lpSource - source string to copy
|
|
|
|
lpStartVar - start of buffer, lppEnd cannot be backed up
|
|
beyond this.
|
|
|
|
lppEnd - points just past end of buffer. back up before
|
|
using. if not enough room (ie. gone < lpStartVar)
|
|
then set to lpStartVar.
|
|
|
|
lppDest - if enough room, on exit set to *lppEnd. If not,
|
|
set to NULL.
|
|
|
|
lpdwBytesTooFew - count of bytes too few. this is always
|
|
incremented as it may already contain value from
|
|
earlier calls.
|
|
|
|
fCovertToAnsi - convert copy to Ansi
|
|
|
|
Return Value:
|
|
|
|
NO_ERROR if successful. Win32 error otherwise.
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD Length ;
|
|
|
|
//
|
|
// init return to NULL.
|
|
//
|
|
*lppDest = NULL ;
|
|
|
|
//
|
|
// if NULL, nothing more to do.
|
|
//
|
|
if (!lpSource)
|
|
{
|
|
return ;
|
|
}
|
|
|
|
//
|
|
// find length. we word align because we dont know if next item
|
|
// after this string needs to be aligned.
|
|
//
|
|
|
|
Length = (_tcslen(lpSource) + 1) *
|
|
(fConvertToAnsi ? sizeof(CHAR) : sizeof(WCHAR)) ;
|
|
|
|
Length = ROUND_UP_COUNT(Length, ALIGN_DWORD) ;
|
|
|
|
if ((lpStartVar + Length) > *lppEnd)
|
|
{
|
|
//
|
|
// not enough space. calculate how many bytes short &
|
|
// set the end marker to where the variable section
|
|
// is (ie. buffer fully used) so that further calculations
|
|
// are correct.
|
|
//
|
|
*lpdwBytesTooFew += ((LPBYTE)lpStartVar + Length) -
|
|
((LPBYTE)*lppEnd) ;
|
|
*lppEnd = lpStartVar ;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// we have required space. move pointer back & copy the data.
|
|
//
|
|
*lppEnd -= Length ;
|
|
*lppDest = *lppEnd ;
|
|
|
|
#if defined(UNICODE)
|
|
if (fConvertToAnsi)
|
|
{
|
|
UNICODE_STRING UnicodeString ;
|
|
ANSI_STRING AnsiString ;
|
|
NTSTATUS NtStatus ;
|
|
|
|
AnsiString.MaximumLength = (USHORT) Length ;
|
|
AnsiString.Length = 0 ;
|
|
AnsiString.Buffer = *lppDest ;
|
|
|
|
RtlInitUnicodeString(&UnicodeString,lpSource) ;
|
|
|
|
NtStatus = RtlUnicodeStringToAnsiString(&AnsiString,
|
|
&UnicodeString,
|
|
FALSE) ; // dont alloc
|
|
if (!NT_SUCCESS(NtStatus))
|
|
{
|
|
//
|
|
// shouldnt happen. if error, just null string out
|
|
//
|
|
**lppDest = 0 ;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
#endif // defined(UNICODE
|
|
_tcscpy((LPTSTR)*lppDest, lpSource) ;
|
|
#if defined(UNICODE)
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
|
|
|
|
#if OLDXBYY
|
|
|
|
//
|
|
// The string handling function table. This is used to switch to either ANSI
|
|
// or Unicode string functions. Note, the order of the values is very
|
|
// important.
|
|
//
|
|
|
|
typedef LPWSTR (_CRTAPI1 *LPCOPYFUNCTION)(LPVOID,LPVOID) ;
|
|
typedef size_t (_CRTAPI1 *LPLENGTHFUNCTION)(LPVOID) ;
|
|
|
|
#ifdef CHICAGO
|
|
|
|
char * MyStrCpy( char * d, char * s )
|
|
{
|
|
return FSTRCPY( d, s );
|
|
}
|
|
|
|
size_t MyStrLen( char * s )
|
|
{
|
|
return FSTRLEN( s );
|
|
}
|
|
|
|
#undef _tcscpy
|
|
#undef _tcslen
|
|
#define _tcscpy MyStrCpy
|
|
#define _tcslen MyStrLen
|
|
#endif // CHICAGO
|
|
|
|
DWORD
|
|
APIENTRY
|
|
PackBlobWorker(
|
|
LPTSTR lpTypeName,
|
|
DWORD dwValueCount,
|
|
PSERVICE_TYPE_VALUE_ABS Values,
|
|
PBYTE *lppBuffer,
|
|
DWORD *lpdBufferSize,
|
|
BOOL fIsAnsi
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Takes the data describing a service and packs it into a blob. It uses
|
|
an intermdiate structure, SERVICE_TYPE_VALUES_ABS that is easier
|
|
to construct than the blob-based structure. This is called from
|
|
the external APIs and works with either Unicode or ANSI strings.
|
|
|
|
Author:
|
|
|
|
Credit for this function goes to Arnold Miller.
|
|
|
|
--*/
|
|
|
|
{
|
|
PBYTE pBuffer, ptr;
|
|
DWORD dwSize, dwIndex;
|
|
size_t Length;
|
|
PSERVICE_TYPE_INFO psi;
|
|
PSERVICE_TYPE_VALUE pv1;
|
|
PSERVICE_TYPE_VALUE_ABS pv;
|
|
DWORD dwType = (fIsAnsi ? 0 : 1);
|
|
#ifndef CHICAGO
|
|
LPCOPYFUNCTION pfnCopy = (fIsAnsi ? (LPCOPYFUNCTION) strcpy : (LPCOPYFUNCTION) _tcscpy);
|
|
LPLENGTHFUNCTION pfnLength = (fIsAnsi ? (LPLENGTHFUNCTION) strlen : (LPLENGTHFUNCTION) _tcslen);
|
|
#else
|
|
LPCOPYFUNCTION pfnCopy = (fIsAnsi ? (LPCOPYFUNCTION) MyStrCpy : (LPCOPYFUNCTION) _tcscpy);
|
|
LPLENGTHFUNCTION pfnLength = (fIsAnsi ? (LPLENGTHFUNCTION) MyStrLen : (LPLENGTHFUNCTION) _tcslen);
|
|
#endif
|
|
//
|
|
// N.B. dwType is the type of string. It's also the log(2) of the
|
|
// size that we use as the left-shift value. The index we compute
|
|
// must match the order of the pointers in apfnCopy and apfnLength above.
|
|
//
|
|
|
|
//
|
|
// compute size of fixed areas
|
|
//
|
|
|
|
Length = pfnLength(lpTypeName);
|
|
|
|
Length = ROUND_UP_COUNT((Length + 1) << dwType, ALIGN_DWORD);
|
|
|
|
dwSize = Length + sizeof(SERVICE_TYPE_INFO) +
|
|
(sizeof(SERVICE_TYPE_VALUE) * (dwValueCount - 1));
|
|
|
|
//
|
|
// Now we have to compute the size needed by the type names and values.
|
|
//
|
|
|
|
for(dwIndex = 0, pv = Values;
|
|
dwIndex < dwValueCount;
|
|
dwIndex++, pv++)
|
|
{
|
|
DWORD dwSS;
|
|
|
|
dwSS = pfnLength(pv->lpValueName);
|
|
|
|
dwSize += ROUND_UP_COUNT(pv->dwValueSize, ALIGN_DWORD) +
|
|
ROUND_UP_COUNT((dwSS + 1) << dwType ,
|
|
ALIGN_DWORD);
|
|
}
|
|
|
|
//
|
|
// got the total needed size.
|
|
//
|
|
|
|
*lpdBufferSize = dwSize; // assume we succeed
|
|
|
|
pBuffer = (PBYTE)
|
|
ALLOCATE_HEAP(dwSize);
|
|
|
|
if(!pBuffer)
|
|
{
|
|
return(GetLastError()) ;
|
|
}
|
|
|
|
//
|
|
// Got a buffer. Nothing can fail now, can fail now, can fail now ...
|
|
//
|
|
|
|
*lppBuffer = pBuffer;
|
|
|
|
//
|
|
// now cast into the buffer
|
|
//
|
|
|
|
//
|
|
// The SERVICE_TYPE_INFO starts at the beginning.
|
|
//
|
|
|
|
psi = (PSERVICE_TYPE_INFO)pBuffer;
|
|
|
|
//
|
|
// Find the first SERVICE_TYPE_VALUE
|
|
//
|
|
|
|
pv1 = (PSERVICE_TYPE_VALUE)&psi->Values[0];
|
|
|
|
//
|
|
// now the string space. It is after all of the structures
|
|
//
|
|
|
|
ptr = (PBYTE)(pv1 + dwValueCount);
|
|
|
|
//
|
|
// fill in the SERVICE_TYPE_INFO
|
|
//
|
|
|
|
psi->dwTypeNameOffset = (DWORD)(ptr - pBuffer);
|
|
psi->dwValueCount = dwValueCount;
|
|
|
|
//
|
|
// copy the service name into the string space.
|
|
//
|
|
|
|
pfnCopy(ptr, lpTypeName);
|
|
|
|
ptr += Length;
|
|
|
|
//
|
|
// now do the service type values
|
|
//
|
|
|
|
for(dwIndex = 0, pv = Values;
|
|
dwIndex < dwValueCount;
|
|
dwIndex++, pv++, pv1++)
|
|
{
|
|
pv1->dwNameSpace = pv->dwNameSpace;
|
|
pv1->dwValueType = pv->dwValueType;
|
|
pv1->dwValueSize = pv->dwValueSize;
|
|
|
|
//
|
|
// we allocated sufficient space to DWORD align everything. So we are
|
|
// careful to actually do that.
|
|
//
|
|
|
|
//
|
|
// first, do the value
|
|
//
|
|
|
|
pv1->dwValueOffset = (DWORD)(ptr - pBuffer);
|
|
memcpy(ptr, pv->lpValue, pv->dwValueSize);
|
|
ptr += ROUND_UP_COUNT(pv->dwValueSize, ALIGN_DWORD);
|
|
|
|
//
|
|
// now the name
|
|
//
|
|
|
|
pv1->dwValueNameOffset = (DWORD)(ptr - pBuffer);
|
|
|
|
pfnCopy(ptr, pv->lpValueName);
|
|
|
|
//
|
|
// We already computed this, it's too bad we couldn't have saved it. On
|
|
// the assumption there aren't very many of these to do, this wasteful
|
|
// immplementation is probably a good trade-off, however. The only
|
|
// way to save them, and to make it extensible, would have been to
|
|
// allocate a buffer of the proper size and use that as an arrary
|
|
// of Length values. This would have been worth it if we believe that
|
|
// callers had enough values to marshall to make it worthwhile.
|
|
//
|
|
|
|
Length = pfnLength(pv->lpValueName);
|
|
|
|
Length = ROUND_UP_COUNT((Length + 1) << dwType,
|
|
ALIGN_DWORD);
|
|
|
|
ptr += Length;
|
|
}
|
|
|
|
return(NO_ERROR);
|
|
}
|
|
|
|
#endif // OLDXBYY
|
|
|