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.
651 lines
16 KiB
651 lines
16 KiB
#include <nt.h>
|
|
#include <ntrtl.h>
|
|
#include <nturtl.h>
|
|
#include <stdio.h>
|
|
#include <windows.h>
|
|
#include <winbase.h>
|
|
#include <lmcons.h>
|
|
#include <lmalert.h>
|
|
#include <ntiodump.h>
|
|
#define INITGUID
|
|
#include <dbgeng.h>
|
|
#include <guiddef.h>
|
|
#include <cmnutil.hpp>
|
|
#include "extsfns.h"
|
|
#include <lmuse.h>
|
|
#include <lmerr.h>
|
|
#include <strsafe.h>
|
|
#include "inetupld.h"
|
|
|
|
PSTR g_AppName;
|
|
PSTR g_ArchiveShare = NULL;
|
|
//
|
|
// Outputcallbacks for ticket
|
|
//
|
|
class DumpChkOutputCallbacks : public IDebugOutputCallbacks
|
|
{
|
|
public:
|
|
// IUnknown.
|
|
STDMETHOD(QueryInterface)(
|
|
THIS_
|
|
IN REFIID InterfaceId,
|
|
OUT PVOID* Interface
|
|
);
|
|
STDMETHOD_(ULONG, AddRef)(
|
|
THIS
|
|
);
|
|
STDMETHOD_(ULONG, Release)(
|
|
THIS
|
|
);
|
|
// IDebugOutputCallbacks.
|
|
STDMETHOD(Output)(
|
|
THIS_
|
|
IN ULONG Mask,
|
|
IN PCSTR Text
|
|
);
|
|
};
|
|
|
|
STDMETHODIMP
|
|
DumpChkOutputCallbacks::QueryInterface(
|
|
THIS_
|
|
IN REFIID InterfaceId,
|
|
OUT PVOID* Interface
|
|
)
|
|
{
|
|
*Interface = NULL;
|
|
|
|
if (IsEqualIID(InterfaceId, IID_IUnknown) ||
|
|
IsEqualIID(InterfaceId, IID_IDebugOutputCallbacks))
|
|
{
|
|
*Interface = (IDebugOutputCallbacks *)this;
|
|
AddRef();
|
|
return S_OK;
|
|
}
|
|
else
|
|
{
|
|
return E_NOINTERFACE;
|
|
}
|
|
}
|
|
|
|
STDMETHODIMP_(ULONG)
|
|
DumpChkOutputCallbacks::AddRef(
|
|
THIS
|
|
)
|
|
{
|
|
// This class is designed to be static so
|
|
// there's no true refcount.
|
|
return 1;
|
|
}
|
|
|
|
STDMETHODIMP_(ULONG)
|
|
DumpChkOutputCallbacks::Release(
|
|
THIS
|
|
)
|
|
{
|
|
// This class is designed to be static so
|
|
// there's no true refcount.
|
|
return 0;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
DumpChkOutputCallbacks::Output(
|
|
THIS_
|
|
IN ULONG Mask,
|
|
IN PCSTR Text
|
|
)
|
|
{
|
|
if (Text) fputs(Text, stdout);
|
|
fflush(stdout);
|
|
return S_OK;
|
|
}
|
|
|
|
DumpChkOutputCallbacks g_OutputCallback;
|
|
|
|
|
|
|
|
DWORD WINAPI
|
|
DisplayStatus(
|
|
LPVOID Context
|
|
)
|
|
{
|
|
POCA_UPLOADFILE pUpload = (POCA_UPLOADFILE) Context;
|
|
DWORD percent;
|
|
while (1)
|
|
{
|
|
percent = pUpload->GetPercentComplete();
|
|
if (percent > 100)
|
|
{
|
|
fprintf(stderr, "Upload complete. \n");
|
|
return 1;
|
|
}
|
|
fprintf(stderr, "Uploading: %02ld%% done.\r", percent);
|
|
Sleep(700);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
void
|
|
UploadDumpFile(
|
|
PSTR DumpFile,
|
|
PSTR SR
|
|
)
|
|
{
|
|
HRESULT Hr = S_OK;
|
|
WCHAR wszLocalDump[MAX_PATH] = {0};
|
|
WCHAR wszRemoteName[MAX_PATH] = {0};
|
|
WCHAR ResultUrl[MAX_PATH];
|
|
WCHAR IsapiUrl[MAX_PATH];
|
|
POCA_UPLOADFILE pUpload;
|
|
HANDLE hThread = NULL;
|
|
DWORD dwThreadId;
|
|
PSTR FileExtension;
|
|
|
|
FileExtension = DumpFile + strlen(DumpFile) - 4;
|
|
if (_stricmp(FileExtension, ".cab"))
|
|
{
|
|
fprintf(stderr, "Please upload only the cab dump files.\n");
|
|
return;
|
|
}
|
|
if (!OcaUpldCreate(&pUpload))
|
|
{
|
|
fprintf(stderr, "Cannot create UPLOAD object\n");
|
|
return;
|
|
}
|
|
|
|
if (!MultiByteToWideChar(CP_ACP,0, DumpFile, strlen(DumpFile), wszLocalDump,
|
|
MAX_PATH))
|
|
{
|
|
fprintf(stderr, "Cannot conver %s to widechar\n", DumpFile);
|
|
Hr = E_FAIL;
|
|
}
|
|
|
|
if (SUCCEEDED(Hr))
|
|
{
|
|
if ((Hr = pUpload->InitializeSession(L"910", wszLocalDump)) != S_OK )
|
|
{
|
|
fprintf(stderr, "Initilaize Upload session failed %lx.\n", Hr);
|
|
}
|
|
}
|
|
if (SUCCEEDED(Hr))
|
|
{
|
|
if ((Hr = StringCbPrintfW(wszRemoteName, sizeof(wszRemoteName), L"/OCA/%S.cab", SR)) != S_OK)
|
|
{
|
|
fprintf(stderr, "Error in generating remote file name %lx \n", Hr);
|
|
}
|
|
}
|
|
|
|
if (SUCCEEDED(Hr))
|
|
{
|
|
hThread = CreateThread(NULL, 0, &DisplayStatus, (PVOID) pUpload,
|
|
0, &dwThreadId);
|
|
|
|
if ((Hr = pUpload->SendFile(wszRemoteName, FALSE)) != S_OK)
|
|
{
|
|
fprintf(stderr, "Send dumpfile failed %lx.\n", Hr);
|
|
}
|
|
pUpload->UnInitialize();
|
|
}
|
|
|
|
if (Hr == S_OK)
|
|
{
|
|
if ((Hr = StringCbPrintfW(IsapiUrl,sizeof( IsapiUrl ),
|
|
L"/isapi/oca_extension.dll?id=%S.cab&Type=%ld&SR=%S",
|
|
SR,
|
|
8,
|
|
SR)) != S_OK)
|
|
{
|
|
fprintf(stderr, "Cannot build IsapiUrl string. %lx\n", Hr);
|
|
}
|
|
}
|
|
|
|
if (SUCCEEDED(Hr))
|
|
{
|
|
|
|
Hr = pUpload->GetUrlPageData(IsapiUrl, ResultUrl, sizeof(ResultUrl));
|
|
|
|
Sleep(700);// To let DisplayStatus finish
|
|
if (Hr != S_OK)
|
|
{
|
|
fprintf(stderr, "Cannot isapi return URL %lx\n", Hr);
|
|
} else
|
|
{
|
|
fprintf(stderr, "File succesfully uploaded as %s.cab\n", SR);
|
|
fprintf(stderr, "Received response URL: %ws\n", ResultUrl);
|
|
}
|
|
|
|
}
|
|
|
|
if (hThread && hThread != INVALID_HANDLE_VALUE)
|
|
{
|
|
TerminateThread(hThread, 1);
|
|
CloseHandle(hThread);
|
|
}
|
|
pUpload->UnInitialize();
|
|
pUpload->Release();
|
|
return;
|
|
}
|
|
|
|
void
|
|
Usage(void)
|
|
{
|
|
fprintf(stderr, "Usage: %s [-i <imgpath>] [-y <sympath>] -s SR [-d <dumpfile>]\n", g_AppName);
|
|
}
|
|
|
|
HRESULT GetPasswdInput(
|
|
LPWSTR wszPwd,
|
|
ULONG PwdSize)
|
|
{
|
|
int err;
|
|
DWORD mode;
|
|
WCHAR Buff[51];
|
|
|
|
fprintf(stdout, "Enter Password to connect to archive server: ");
|
|
|
|
GetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), &mode);
|
|
SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE),
|
|
(~(ENABLE_ECHO_INPUT)) & mode);
|
|
|
|
if (scanf("%50ws", Buff) == 0)
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), mode);
|
|
fprintf(stdout, "\n");
|
|
return StringCbCopyW(wszPwd, PwdSize, Buff);
|
|
}
|
|
|
|
|
|
//
|
|
// This add access to Share
|
|
//
|
|
HRESULT
|
|
NetworkAccessShare(
|
|
PSTR szShare,
|
|
LPWSTR szPassword
|
|
)
|
|
{
|
|
USE_INFO_2 UseInfo;
|
|
WCHAR wszShare[MAX_PATH], wszDomain[MAX_PATH], *pDir;
|
|
|
|
|
|
if (MultiByteToWideChar(CP_ACP, 0, szShare, strlen(szShare)+1,
|
|
wszShare, sizeof(wszShare)/sizeof(WCHAR)) == FALSE)
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
StringCbCopyW(wszDomain, sizeof(wszDomain), &wszShare[2]);
|
|
pDir = wcsrchr(wszDomain, L'\\');
|
|
if (pDir == NULL)
|
|
{
|
|
// bad share name
|
|
return FALSE;
|
|
}
|
|
*pDir = 0;
|
|
|
|
UseInfo.ui2_local = NULL;
|
|
UseInfo.ui2_remote = wszShare;
|
|
UseInfo.ui2_password = szPassword;
|
|
UseInfo.ui2_username = L"OcaArchive";
|
|
UseInfo.ui2_domainname = wszDomain;
|
|
UseInfo.ui2_asg_type = 0;
|
|
UseInfo.ui2_status = 0;
|
|
if (NetUseAdd(NULL, 2, (LPBYTE) &UseInfo, NULL) != NERR_Success)
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
//
|
|
// Deletes any access granted to a remote share
|
|
//
|
|
HRESULT
|
|
NetworkDeleteShare(
|
|
void
|
|
)
|
|
{
|
|
WCHAR wszShare[MAX_PATH];
|
|
|
|
|
|
if (g_ArchiveShare == NULL)
|
|
{
|
|
return S_OK;
|
|
}
|
|
if (MultiByteToWideChar(CP_ACP, 0, g_ArchiveShare, strlen(g_ArchiveShare)+1,
|
|
wszShare, sizeof(wszShare)/sizeof(WCHAR)) == FALSE)
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
if (NetUseDel(NULL, wszShare, USE_NOFORCE) != NERR_Success)
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
//
|
|
// This grants users archive access to OCA share for archiving dumps
|
|
//
|
|
BOOL
|
|
AddArchiveAccess(
|
|
PDEBUG_CLIENT4 Client,
|
|
PDEBUG_CONTROL3 DebugControl,
|
|
ULONG Qualifier
|
|
)
|
|
{
|
|
HMODULE Ext = NULL;
|
|
EXT_TRIAGE_FOLLOWUP fnGetFollowup;
|
|
DEBUG_TRIAGE_FOLLOWUP_INFO Info;
|
|
CHAR szShare[MAX_PATH];
|
|
WCHAR Passwd[100];
|
|
PSTR szLookup1 = "debugger-params!archshare-k-full";
|
|
PSTR szLookup2 = "debugger-params!archshare-k-mini";
|
|
PSTR szLookup;
|
|
|
|
if (DebugControl->GetExtensionFunction(0, "GetTriageFollowupFromSymbol",
|
|
(FARPROC*)&fnGetFollowup) != S_OK)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
if (Qualifier == DEBUG_DUMP_FULL)
|
|
{
|
|
szLookup = szLookup1;
|
|
} else
|
|
{
|
|
szLookup = szLookup2;
|
|
}
|
|
|
|
Info.SizeOfStruct = sizeof(Info);
|
|
Info.OwnerName = szShare;
|
|
Info.OwnerNameSize = sizeof(szShare);
|
|
|
|
if ((*fnGetFollowup)((PDEBUG_CLIENT) Client, szLookup, &Info) <= TRIAGE_FOLLOWUP_IGNORE)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
if (GetPasswdInput(Passwd, sizeof(Passwd)) != S_OK)
|
|
{
|
|
return FALSE;
|
|
}
|
|
//
|
|
// Grant Access to szShare
|
|
//
|
|
if (NetworkAccessShare(szShare, Passwd) != S_OK)
|
|
{
|
|
return FALSE;
|
|
}
|
|
g_ArchiveShare = szShare;
|
|
return TRUE;
|
|
}
|
|
|
|
HRESULT
|
|
CreateCabinetFromDump(
|
|
PCSTR DumpFile,
|
|
PSTR CabFile,
|
|
ULONG cbCabFile
|
|
)
|
|
{
|
|
HRESULT Status;
|
|
CHAR TempFile[MAX_PATH];
|
|
PSTR Tail;
|
|
|
|
Tail = strrchr(DumpFile, '\\');
|
|
if (Tail == NULL) {
|
|
Tail = (PSTR) DumpFile;
|
|
} else {
|
|
++Tail;
|
|
}
|
|
if (!GetTempPathA(cbCabFile, CabFile)) {
|
|
StringCbCopy(CabFile, cbCabFile, ".\\");
|
|
}
|
|
|
|
// Use the CAB name as the dump file name so the
|
|
// name in the CAB will match.
|
|
StringCbCat(CabFile, cbCabFile, Tail);
|
|
StringCbCat(CabFile, cbCabFile, ".cab" );
|
|
|
|
fprintf(stdout, "\nCreating %s, this could take some time...\n", CabFile);
|
|
fflush(stdout);
|
|
if ((Status = CreateDumpCab(CabFile)) != S_OK) {
|
|
fprintf(stderr, "Unable to create CAB, %s\n", FormatStatusCode(Status));
|
|
return Status;
|
|
}
|
|
else {
|
|
//
|
|
// add dump file.
|
|
//
|
|
Status = AddToDumpCab(DumpFile);
|
|
CloseDumpCab();
|
|
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
typedef HRESULT (WINAPI * RETRIVETICKET)(
|
|
PSTR szSR,
|
|
PSTR szPath,
|
|
PDEBUG_CONTROL3 DebugControl
|
|
);
|
|
|
|
HRESULT
|
|
RetriveSrTicket(
|
|
PTSTR szSR
|
|
)
|
|
{
|
|
HRESULT Hr = S_OK;
|
|
IDebugClient4 *DebugClient;
|
|
IDebugControl3 *DebugControl;
|
|
HMODULE Ext = NULL;
|
|
RETRIVETICKET fnTicket;
|
|
|
|
if ((Hr = DebugCreate(__uuidof(IDebugClient),
|
|
(void **)&DebugClient)) != S_OK) {
|
|
fprintf(stderr, "Cannot initialize DebugClient\n");
|
|
return Hr;
|
|
}
|
|
if ((DebugClient->QueryInterface(__uuidof(IDebugControl3),
|
|
(void **)&DebugControl) != S_OK)) {
|
|
fprintf(stderr, "QueryInterface failed for DebugClient\n");
|
|
return Hr;
|
|
}
|
|
DebugClient->SetOutputCallbacks(&g_OutputCallback);
|
|
|
|
Ext = LoadLibrary("winext\\ext.dll");
|
|
if (!Ext) {
|
|
fprintf(stderr,"Cannot load ext.dll.\n");
|
|
Hr = E_FAIL;
|
|
} else {
|
|
|
|
fnTicket = (RETRIVETICKET) GetProcAddress(Ext, "_EFN_FindSrInfo");
|
|
if (!fnTicket) {
|
|
fprintf(stderr, "Cannot find _EFN_FindSrInfo\n");
|
|
Hr = E_FAIL;
|
|
} else {
|
|
Hr = fnTicket(szSR, NULL, DebugControl);
|
|
}
|
|
}
|
|
|
|
|
|
DebugControl->Release();
|
|
DebugClient->Release();
|
|
return Hr;
|
|
}
|
|
|
|
HRESULT
|
|
AddSrTicket(
|
|
PTSTR szSR,
|
|
PTSTR szDumpFile,
|
|
PTSTR szSymbolPath,
|
|
PTSTR szImagePath
|
|
)
|
|
{
|
|
HRESULT Hr = E_FAIL;
|
|
IDebugClient4 *DebugClient;
|
|
IDebugControl3 *DebugControl;
|
|
IDebugSymbols2 *DebugSymbols;
|
|
IDebugSystemObjects3 *DebugSysObjects;
|
|
RETRIVETICKET fnTicket;
|
|
CHAR Buffer[MAX_PATH*2];
|
|
CHAR szCabFile[MAX_PATH];
|
|
|
|
if ((Hr = DebugCreate(__uuidof(IDebugClient),
|
|
(void **)&DebugClient)) != S_OK) {
|
|
fprintf(stderr, "Cannot initialize DebugClient\n");
|
|
return Hr;
|
|
}
|
|
|
|
if ((DebugClient->QueryInterface(__uuidof(IDebugControl3),
|
|
(void **)&DebugControl) != S_OK) ||
|
|
(DebugClient->QueryInterface(__uuidof(IDebugSymbols2),
|
|
(void **)&DebugSymbols) != S_OK) ||
|
|
(DebugClient->QueryInterface(__uuidof(IDebugSystemObjects3),
|
|
(void **)&DebugSysObjects) != S_OK)) {
|
|
fprintf(stderr, "QueryInterface failed for DebugClient\n");
|
|
return Hr;
|
|
}
|
|
|
|
DebugClient->SetOutputCallbacks(&g_OutputCallback);
|
|
StringCbPrintf(Buffer, sizeof(Buffer),"Loading dump file %s\n", szDumpFile);
|
|
g_OutputCallback.Output(-1, Buffer);
|
|
if ((Hr = DebugClient->OpenDumpFile(szDumpFile)) != S_OK) {
|
|
fprintf(stderr, "**** DebugClient cannot open DumpFile - error %lx\n", Hr);
|
|
if (Hr == HRESULT_FROM_WIN32(ERROR_FILE_CORRUPT)) {
|
|
fprintf(stderr, "DumpFile is corrupt\n");
|
|
|
|
}
|
|
return Hr;
|
|
}
|
|
if (szSymbolPath) {
|
|
DebugSymbols->SetSymbolPath(szSymbolPath);
|
|
}
|
|
if (szImagePath) {
|
|
DebugSymbols->SetImagePath(szImagePath);
|
|
}
|
|
|
|
DebugControl->WaitForEvent(DEBUG_WAIT_DEFAULT, INFINITE);
|
|
|
|
DebugControl->Execute(DEBUG_OUTCTL_ALL_CLIENTS, "version", DEBUG_EXECUTE_DEFAULT);
|
|
|
|
ULONG Class, Qual;
|
|
if ((Hr = DebugControl->GetDebuggeeType(&Class, &Qual)) != S_OK) {
|
|
Class = Qual = 0;
|
|
}
|
|
if (Class == DEBUG_CLASS_USER_WINDOWS) {
|
|
//
|
|
// User Mode dump
|
|
//
|
|
|
|
fprintf(stderr, "Usermode dumps are not handled\n");
|
|
|
|
} else {
|
|
//
|
|
// Kernel Mode dump
|
|
//
|
|
CHAR ExtensionCmd[100];
|
|
|
|
DebugControl->Execute(DEBUG_OUTCTL_ALL_CLIENTS, "!analyze -v", DEBUG_EXECUTE_DEFAULT);
|
|
|
|
if (DebugControl->GetExtensionFunction(0, "FindSrInfo",
|
|
(FARPROC*)&fnTicket) != S_OK) {
|
|
fnTicket = NULL;
|
|
}
|
|
if (!fnTicket) {
|
|
g_OutputCallback.Output(0, "Cannot find _EFN_FindSrInfo\n");
|
|
Hr = E_FAIL;
|
|
} else {
|
|
g_OutputCallback.Output(0, "Checking if SR exists in DB\n");
|
|
Hr = fnTicket(szSR, NULL, DebugControl);
|
|
}
|
|
// StringCchPrintf(ExtensionCmd, sizeof(ExtensionCmd), "!ticket %s", szSR);
|
|
// if (DebugControl->Execute(DEBUG_OUTCTL_ALL_CLIENTS, ExtensionCmd, DEBUG_EXECUTE_DEFAULT) == S_FALSE)
|
|
if (Hr == S_FALSE) {
|
|
|
|
if (_stricmp(szDumpFile + strlen(szDumpFile) - 4, ".cab")) {
|
|
if ((Hr = CreateCabinetFromDump(szDumpFile, szCabFile,
|
|
sizeof(szCabFile))) != S_OK) {
|
|
g_OutputCallback.Output(0,"Could not cab the dump file\n");
|
|
}
|
|
} else {
|
|
StringCbCopy(szCabFile, sizeof(szCabFile), szDumpFile);
|
|
}
|
|
|
|
|
|
g_OutputCallback.Output(0,"... uploading dump file to the server\n");
|
|
UploadDumpFile(szCabFile, szSR);
|
|
|
|
if (strcmp(szCabFile, szDumpFile)) {
|
|
DeleteFile(szCabFile);
|
|
}
|
|
}
|
|
}
|
|
DebugSysObjects->Release();
|
|
DebugControl->Release();
|
|
DebugSymbols->Release();
|
|
DebugClient->Release();
|
|
return S_OK;
|
|
}
|
|
|
|
void
|
|
__cdecl
|
|
main (
|
|
int Argc,
|
|
PCHAR *Argv
|
|
)
|
|
|
|
{
|
|
LONG arg;
|
|
PCHAR DumpFileName = NULL;
|
|
PCHAR SymbolPath = NULL;
|
|
PCHAR ImagePath = NULL;
|
|
PCHAR SR = NULL;
|
|
|
|
g_AppName = Argv[0];
|
|
|
|
for (arg = 1; arg < Argc; arg++) {
|
|
if (Argv[arg][0] == '-' || Argv[arg][0] == '/') {
|
|
switch (Argv[arg][1]) {
|
|
case 'd':
|
|
case 'D':
|
|
if (++arg < Argc) {
|
|
DumpFileName = Argv[arg];
|
|
}
|
|
break;
|
|
case 's':
|
|
case 'S':
|
|
if (++arg < Argc) {
|
|
SR = Argv[arg];
|
|
}
|
|
break;
|
|
case 'i':
|
|
case 'I':
|
|
if (++arg < Argc) {
|
|
ImagePath = Argv[arg];
|
|
}
|
|
break;
|
|
case 'y':
|
|
case 'Y':
|
|
if (++arg < Argc) {
|
|
SymbolPath = Argv[arg];
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!SR) {
|
|
Usage();
|
|
return;
|
|
} else if (!DumpFileName) {
|
|
RetriveSrTicket(SR);
|
|
return;
|
|
}
|
|
if (SymbolPath == NULL) {
|
|
SymbolPath = "SRV*";
|
|
}
|
|
AddSrTicket(SR, DumpFileName, SymbolPath, ImagePath);
|
|
return;
|
|
}
|