windows-nt/Source/XPSP1/NT/net/upnp/tools/isapictl/isapictl.cpp
2020-09-26 16:20:57 +08:00

806 lines
20 KiB
C++

#include <pch.h>
#pragma hdrstop
#include <httpext.h>
#include <httpfilt.h>
#include <wininet.h>
#include <msxml.h>
#include <oleauto.h>
#include "ssdpapi.h"
#include "ncbase.h"
#include "updiag.h"
#include "ncxml.h"
BOOL g_fInited = FALSE;
HANDLE g_hMapFile = NULL;
SHARED_DATA * g_pdata = NULL;
HANDLE g_hEvent = NULL;
HANDLE g_hEventRet = NULL;
HANDLE g_hMutex = NULL;
BOOL g_fTurnOff = FALSE;
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD dwReason, LPVOID lpv)
{
return TRUE;
}
BOOL FInit()
{
SECURITY_ATTRIBUTES sa = {0};
SECURITY_DESCRIPTOR sd = {0};
InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION);
SetSecurityDescriptorDacl(&sd, TRUE, NULL, FALSE);
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
sa.bInheritHandle = FALSE;
sa.lpSecurityDescriptor = &sd;
InitializeDebugging();
TraceTag(ttidIsapiCtl, "Initializing...");
g_hEvent = CreateEvent(&sa, FALSE, FALSE, c_szSharedEvent);
if (g_hEvent)
{
if (GetLastError() != ERROR_ALREADY_EXISTS)
{
TraceTag(ttidIsapiCtl, "Event wasn't already created!");
goto cleanup;
}
else
{
TraceTag(ttidIsapiCtl, "Created event...");
}
}
else
{
TraceTag(ttidIsapiCtl, "Could not create event! Error = %d.",
GetLastError());
goto cleanup;
}
g_hEventRet = CreateEvent(&sa, FALSE, FALSE, c_szSharedEventRet);
if (g_hEventRet)
{
if (GetLastError() != ERROR_ALREADY_EXISTS)
{
TraceTag(ttidIsapiCtl, "Return event wasn't already created!");
goto cleanup;
}
else
{
TraceTag(ttidIsapiCtl, "Created return event...");
}
}
else
{
TraceTag(ttidIsapiCtl, "Could not create return event! Error = %d.",
GetLastError());
goto cleanup;
}
g_hMutex = CreateMutex(&sa, FALSE, c_szSharedMutex);
if (g_hMutex)
{
if (GetLastError() != ERROR_ALREADY_EXISTS)
{
TraceTag(ttidIsapiCtl, "Mutex wasn't already created!");
goto cleanup;
}
else
{
TraceTag(ttidIsapiCtl, "Created mutex...");
}
}
else
{
TraceTag(ttidIsapiCtl, "Could not create event! Error = %d.",
GetLastError());
goto cleanup;
}
g_hMapFile = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, c_szSharedData);
if (g_hMapFile)
{
TraceTag(ttidIsapiCtl, "Opened file mapping...");
g_pdata = (SHARED_DATA *)MapViewOfFile(g_hMapFile, FILE_MAP_ALL_ACCESS,
0, 0, 0);
if (g_pdata)
{
TraceTag(ttidIsapiCtl, "Shared data successful at 0x%08X.", g_pdata);
TraceTag(ttidIsapiCtl, "ISAPICTL is initialized.");
g_fInited = TRUE;
return TRUE;
}
else
{
TraceTag(ttidIsapiCtl, "Failed to map file. Error %d.", GetLastError());
goto cleanup;
}
}
else
{
TraceTag(ttidIsapiCtl, "Failed to open file mapping. Error %d.", GetLastError());
goto cleanup;
}
cleanup:
if (g_pdata)
{
UnmapViewOfFile((LPVOID)g_pdata);
}
if (g_hMapFile)
{
CloseHandle(g_hMapFile);
}
if (g_hEvent)
{
CloseHandle(g_hEvent);
}
if (g_hEventRet)
{
CloseHandle(g_hEvent);
}
if (g_hMutex)
{
CloseHandle(g_hMutex);
}
return FALSE;
}
BOOL WINAPI GetExtensionVersion(HSE_VERSION_INFO * pver)
{
if (!g_fInited && !g_fTurnOff)
{
if (!FInit())
{
TraceTag(ttidIsapiCtl, "Failed to initialize. Aborting!");
SsdpCleanup();
g_fTurnOff = TRUE;
TraceTag(ttidIsapiCtl, "Turning off.");
//return FALSE;
}
}
pver->dwExtensionVersion = MAKELONG(1, 0);
lstrcpyA(pver->lpszExtensionDesc, "UPnP ISAPI Control Extension");
TraceTag(ttidIsapiCtl, "ISAPICTL: Extension version: %s.",
pver->lpszExtensionDesc);
return TRUE;
}
HRESULT
HrParseHeader(
IXMLDOMNode * pxdnHeader)
{
HRESULT hr = S_OK;
IXMLDOMNode * pxdnChild = NULL;
hr = pxdnHeader->get_firstChild(&pxdnChild);
while (SUCCEEDED(hr) && pxdnChild)
{
IXMLDOMNode * pxdnNextSibling = NULL;
BSTR bstrBaseName = NULL;
hr = pxdnChild->get_baseName(&bstrBaseName);
if (SUCCEEDED(hr) && bstrBaseName)
{
if (wcscmp(bstrBaseName, L"sequenceNumber") == 0)
{
TraceTag(ttidIsapiCtl,
"HrParseHeader(): "
"Parsing sequence number node");
BSTR bstrSeqNumberText = NULL;
hr = pxdnChild->get_text(&bstrSeqNumberText);
if (SUCCEEDED(hr) && bstrSeqNumberText)
{
LONG lSeqNumber = _wtol(bstrSeqNumberText);
g_pdata->dwSeqNumber = (DWORD) lSeqNumber;
TraceTag(ttidIsapiCtl,
"HrParseHeader(): "
"Sequence number is %d\n",
g_pdata->dwSeqNumber);
SysFreeString(bstrSeqNumberText);
}
else
{
if (SUCCEEDED(hr))
{
hr = E_FAIL;
}
TraceTag(ttidIsapiCtl,
"HrParseHeader(): "
"Failed to get sequence number text");
}
}
else if (wcscmp(bstrBaseName, L"SID") == 0)
{
TraceTag(ttidIsapiCtl,
"HrParseHeader(): "
"Parsing SID node");
BSTR bstrSIDText = NULL;
hr = pxdnChild->get_text(&bstrSIDText);
if (SUCCEEDED(hr) && bstrSIDText)
{
DWORD cch;
cch = SysStringLen(bstrSIDText)+1;
WideCharToMultiByte(CP_ACP, 0, bstrSIDText,
cch,
(LPSTR)g_pdata->szSID,
cch, NULL, NULL);
TraceTag(ttidIsapiCtl,
"HrParseHeader(): "
"SID is %s\n",
g_pdata->szSID);
SysFreeString(bstrSIDText);
}
else
{
if (SUCCEEDED(hr))
{
hr = E_FAIL;
}
TraceTag(ttidIsapiCtl,
"HrParseHeader(): "
"Failed to get SID text");
}
}
else
{
// Found an unknown node. This SOAP request is not valid.
TraceTag(ttidIsapiCtl,
"HrParseHeader(): "
"Found unknown node \"%S\"",
bstrBaseName);
hr = E_FAIL;
}
SysFreeString(bstrBaseName);
}
else
{
if (SUCCEEDED(hr))
{
hr = E_FAIL;
}
TraceError("HrParseHeader(): "
"Failed to get node base name",
hr);
}
if (SUCCEEDED(hr))
{
hr = pxdnChild->get_nextSibling(&pxdnNextSibling);
pxdnChild->Release();
pxdnChild = pxdnNextSibling;
}
else
{
pxdnChild->Release();
pxdnChild = NULL;
}
};
if (SUCCEEDED(hr))
{
// Last success return code out of the loop would have
// been S_FALSE.
hr = S_OK;
}
TraceError("HrParseHeader(): "
"Exiting",
hr);
return hr;
}
HRESULT
HrParseBody(
IXMLDOMNode * pxdnBody)
{
HRESULT hr = S_OK;
// Find the action node. This is the first child of the <Body> node.
IXMLDOMNode * pxdnAction = NULL;
hr = pxdnBody->get_firstChild(&pxdnAction);
if (SUCCEEDED(hr) && pxdnAction)
{
BSTR bstrActionName = NULL;
hr = pxdnAction->get_baseName(&bstrActionName);
if (SUCCEEDED(hr) && bstrActionName)
{
// Copy the action name into the shared data.
DWORD cch;
cch = SysStringLen(bstrActionName) + 1;
WideCharToMultiByte(CP_ACP, 0, bstrActionName,
cch,
(LPSTR)g_pdata->szAction,
cch, NULL, NULL);
// Copy each of the action arguments into the shared data.
IXMLDOMNode * pxdnArgument = NULL;
hr = pxdnAction->get_firstChild(&pxdnArgument);
while (SUCCEEDED(hr) && pxdnArgument)
{
BSTR bstrArgText = NULL;
hr = pxdnArgument->get_text(&bstrArgText);
if (SUCCEEDED(hr) && bstrArgText)
{
DWORD cch;
cch = SysStringLen(bstrArgText) + 1;
WideCharToMultiByte(CP_ACP, 0, bstrArgText,
cch,
(LPSTR)g_pdata->rgArgs[g_pdata->cArgs].szValue,
cch, NULL, NULL);
g_pdata->cArgs++;
SysFreeString(bstrArgText);
}
else
{
if (SUCCEEDED(hr))
{
hr = E_FAIL;
}
TraceError("HrParseBody(): "
"Failed to get argument text",
hr);
}
if (SUCCEEDED(hr))
{
IXMLDOMNode * pxdnNextArgument = NULL;
hr = pxdnArgument->get_nextSibling(&pxdnNextArgument);
pxdnArgument->Release();
pxdnArgument = pxdnNextArgument;
}
else
{
pxdnArgument->Release();
pxdnArgument = NULL;
}
}
if (SUCCEEDED(hr))
{
hr = S_OK;
}
SysFreeString(bstrActionName);
}
else
{
if (SUCCEEDED(hr))
{
hr = E_FAIL;
}
TraceError("HrParseBody(): "
"Failed to get action name",
hr);
}
pxdnAction->Release();
}
else
{
if (SUCCEEDED(hr))
{
hr = E_FAIL;
}
TraceError("HrParseBody(): "
"Failed to get action node",
hr);
}
TraceError("HrParseBody(): "
"Exiting",
hr);
return hr;
}
HRESULT
HrParseAction(
IXMLDOMNode * pxdnSOAPEnvelope)
{
HRESULT hr = S_OK;
IXMLDOMNode * pxdnChild = NULL;
hr = pxdnSOAPEnvelope->get_firstChild(&pxdnChild);
while (SUCCEEDED(hr) && pxdnChild)
{
IXMLDOMNode * pxdnNextSibling = NULL;
BSTR bstrBaseName = NULL;
hr = pxdnChild->get_baseName(&bstrBaseName);
if (SUCCEEDED(hr) && bstrBaseName)
{
if (wcscmp(bstrBaseName, L"Header") == 0)
{
TraceTag(ttidIsapiCtl,
"HrParseAction(): "
"Parsing Header node");
hr = HrParseHeader(pxdnChild);
}
else if (wcscmp(bstrBaseName, L"Body") == 0)
{
TraceTag(ttidIsapiCtl,
"HrParseAction(): "
"Parsing Body node");
hr = HrParseBody(pxdnChild);
}
else
{
// Found an unknown node. This SOAP request is not valid.
TraceTag(ttidIsapiCtl,
"HrParseAction(): "
"Found unknown node \"%S\"",
bstrBaseName);
hr = E_FAIL;
}
SysFreeString(bstrBaseName);
}
else
{
if (SUCCEEDED(hr))
{
hr = E_FAIL;
}
TraceError("HrParseAction(): "
"Failed to get node base name",
hr);
}
if (SUCCEEDED(hr))
{
hr = pxdnChild->get_nextSibling(&pxdnNextSibling);
pxdnChild->Release();
pxdnChild = pxdnNextSibling;
}
else
{
pxdnChild->Release();
pxdnChild = NULL;
}
};
if (SUCCEEDED(hr))
{
// Last success return code out of the loop would have
// been S_FALSE.
hr = S_OK;
}
TraceError("HrParseAction(): "
"Exiting",
hr);
return hr;
}
HRESULT HrLoadArgsFromXml(LPCWSTR szXml)
{
VARIANT_BOOL vbSuccess;
HRESULT hr = S_OK;
IXMLDOMDocument * pxmlDoc;
IXMLDOMNodeList * pNodeList = NULL;
IXMLDOMNode * pNode = NULL;
IXMLDOMNode * pNext = NULL;
hr = CoCreateInstance(CLSID_DOMDocument30, NULL, CLSCTX_INPROC_SERVER,
IID_IXMLDOMDocument, (LPVOID *)&pxmlDoc);
if (SUCCEEDED(hr))
{
hr = pxmlDoc->put_async(VARIANT_FALSE);
if (SUCCEEDED(hr))
{
hr = pxmlDoc->loadXML((BSTR)szXml, &vbSuccess);
if (SUCCEEDED(hr))
{
IXMLDOMElement * pxde;
hr = pxmlDoc->get_documentElement(&pxde);
if (S_OK == hr)
{
hr = HrParseAction(pxde);
ReleaseObj(pxde);
}
}
}
ReleaseObj(pxmlDoc);
}
TraceError("HrLoadArgsFromXml", hr);
return hr;
}
DWORD DwProcessXoapRequest(LPSTR szUri, DWORD cbData, LPBYTE pbData)
{
LPSTR szData = (LPSTR)pbData;
UPNP_PROPERTY * rgProps;
DWORD cProps;
DWORD dwReturn = 0;
HRESULT hr;
// Must acquire shared-memory mutex first
//
if (WAIT_OBJECT_0 == WaitForSingleObject(g_hMutex, INFINITE))
{
TraceTag(ttidIsapiCtl, "Acquired mutex...");
ZeroMemory(g_pdata, sizeof(SHARED_DATA));
LPSTR szAnsi;
LPWSTR wszXmlBody;
szAnsi = new CHAR[cbData + 1];
CopyMemory(szAnsi, pbData, cbData);
szAnsi[cbData] = 0;
wszXmlBody = WszFromSz(szAnsi);
TraceTag(ttidIsapiCtl, "URI = %s: Data = %s.", szUri, szAnsi);
delete [] szAnsi;
hr = HrLoadArgsFromXml(wszXmlBody);
TraceError("DwProcessXoapRequest: HrLoadArgsFromXml", hr);
// Done with changes to shared memory
TraceTag(ttidIsapiCtl, "Releasing mutex...");
ReleaseMutex(g_hMutex);
if (S_OK == hr)
{
// Copy in event source URI
lstrcpyA(g_pdata->szEventSource, szUri);
TraceTag(ttidIsapiCtl, "Setting event...");
// Now tell the device we're ready for it to process
SetEvent(g_hEvent);
TraceTag(ttidIsapiCtl, "Waiting for return event...");
// Immediately wait on event again for return response
if (WAIT_OBJECT_0 == WaitForSingleObject(g_hEventRet, INFINITE))
{
dwReturn = g_pdata->dwReturn;
TraceTag(ttidIsapiCtl, "Setting return value to %d.", dwReturn);
}
}
else
{
// On failure, we don't even need to signal the device. This
// XOAP request wasn't properly formed or we couldn't process
// it anyway
//
TraceError("DwProcessXoapRequest - failed to load args from XML", hr);
dwReturn = DwWin32ErrorFromHr(hr);
}
// And we're done!
}
return dwReturn;
}
HRESULT HrComposeXoapResponse(DWORD dwValue, LPSTR *pszOut)
{
HRESULT hr = S_OK;
LPSTR szOut;
CHAR szBuffer[1024];
Assert(pszOut);
// $ BUGBUG SPATHER Response should be namespace-qualified.
wsprintfA(szBuffer,
"<SOAP:Envelope xmlns:SOAP=\"urn:schemas-xmlsoap-org:soap.v1\">\r\n"
" <SOAP:Body>\r\n"
" <%sResponse>\r\n"
" <return>%d</return>\r\n"
" </%sResponse>\r\n"
" </SOAP:Body>\r\n"
"</SOAP:Envelope>",
g_pdata->szAction,
dwValue,
g_pdata->szAction);
szOut = SzaDupSza(szBuffer);
if (szOut)
{
*pszOut = szOut;
}
else
{
hr = E_OUTOFMEMORY;
}
TraceError("HrComposeXoapResponse", hr);
return hr;
}
DWORD WINAPI HttpExtensionProc(LPEXTENSION_CONTROL_BLOCK pecb)
{
DWORD hseStatus = HSE_STATUS_SUCCESS;
if (g_fInited)
{
DWORD dwReturn;
HRESULT hr;
if (!lstrcmpiA(pecb->lpszMethod, "M-POST"))
{
LPSTR szResponse;
DWORD cbResponse;
// This was a post request so it's a XOAP control request
TraceTag(ttidIsapiCtl, "Received 'M-POST' request");
// The URI of the event source will be the query string
dwReturn = DwProcessXoapRequest(pecb->lpszQueryString,
pecb->cbAvailable,
pecb->lpbData);
// Send XOAP response with dwReturn
TraceTag(ttidIsapiCtl, "Sending XOAP response for %d.", dwReturn);
hr = HrComposeXoapResponse(dwReturn, &szResponse);
if (S_OK == hr)
{
cbResponse = lstrlenA(szResponse);
TraceTag(ttidIsapiCtl, "Writing XOAP response: %s.", szResponse);
pecb->WriteClient(pecb->ConnID, (LPVOID)szResponse,
&cbResponse, 0);
free(szResponse);
}
}
else if (!lstrcmpiA(pecb->lpszMethod, "POST"))
{
HSE_SEND_HEADER_EX_INFO hse;
LPSTR szResponse = "";
DWORD cbResponse;
LPSTR szStatus = "405 Method Not Allowed";
DWORD cbStatus;
TraceTag(ttidIsapiCtl, "Received 'POST' request");
TraceTag(ttidIsapiCtl, "Data = %s.", pecb->lpbData);
ZeroMemory(&hse, sizeof(HSE_SEND_HEADER_EX_INFO));
cbResponse = lstrlenA(szResponse);
cbStatus = lstrlenA(szStatus);
hse.pszStatus = szStatus;// here you should print "405 Method Not Allowed"
hse.pszHeader = szResponse; // this one should be empty for http errors
hse.cchStatus = cbStatus;
hse.cchHeader = cbResponse;
hse.fKeepConn = FALSE;
pecb->dwHttpStatusCode = HTTP_STATUS_BAD_METHOD;
pecb->ServerSupportFunction(pecb->ConnID,
HSE_REQ_SEND_RESPONSE_HEADER_EX,
(LPVOID)&hse,
NULL,
NULL);
}
else
{
TraceTag(ttidIsapiCtl, "Data = %s.", pecb->lpbData);
pecb->dwHttpStatusCode = HTTP_STATUS_BAD_METHOD;
TraceTag(ttidIsapiCtl, "ISAPICTL: Received bad method '%s' request.",
pecb->lpszMethod);
hseStatus = HSE_STATUS_ERROR;
}
}
else
{
TraceTag(ttidIsapiCtl, "Not initialized!");
}
return hseStatus;
}
BOOL WINAPI TerminateExtension(DWORD dwFlags)
{
TraceTag(ttidIsapiCtl, "TerminateExtension: Exiting...");
if (g_pdata)
{
UnmapViewOfFile((LPVOID)g_pdata);
}
if (g_hMapFile)
{
CloseHandle(g_hMapFile);
}
if (g_hEvent)
{
CloseHandle(g_hEvent);
}
if (g_hEventRet)
{
CloseHandle(g_hEvent);
}
if (g_hMutex)
{
CloseHandle(g_hMutex);
}
return TRUE;
}