Files
mirror-processhacker/2.x/trunk/plugins/ProcessActions/procdb.c
T
wj32 45ddf659b9 missing #include
git-svn-id: svn://svn.code.sf.net/p/processhacker/code@3639 21ef857c-d57f-4fe0-8362-d861dc6d29cd
2010-09-17 04:19:32 +00:00

638 lines
16 KiB
C

#include <phdk.h>
#define PA_PROCDB_PRIVATE
#include "procdb.h"
#include <mxml.h>
#include <shlobj.h>
PPH_LIST PaProcDbList;
PPH_STRING PaProcDbFileName;
static CHAR *PaControlStrings[] =
{
NULL,
"disabled",
"runonce",
"runperiod"
};
static CHAR *PaSelectorStrings[] =
{
NULL,
"processname",
"filename"
};
static CHAR *PaActionStrings[] =
{
NULL,
"setpriorityclass",
"setaffinitymask",
"terminate",
"suspend"
};
VOID PaProcDbInitialization()
{
PaProcDbList = PhCreateList(10);
PaProcDbFileName = PhGetKnownLocation(CSIDL_APPDATA, L"\\Process Hacker 2\\procdb.xml");
if (PaProcDbFileName)
{
PaLoadProcDb(PaProcDbFileName->Buffer);
}
}
PPA_PROCDB_ENTRY PaAllocateProcDbEntry()
{
PPA_PROCDB_ENTRY entry;
entry = PhAllocate(sizeof(PA_PROCDB_ENTRY));
memset(entry, 0, sizeof(PA_PROCDB_ENTRY));
entry->Actions = PhCreateList(2);
return entry;
}
VOID PaFreeProcDbEntry(
__inout PPA_PROCDB_ENTRY Entry
)
{
ULONG i;
PaDeleteProcDbSelector(&Entry->Selector);
for (i = 0; i < Entry->Actions->Count; i++)
{
PaFreeProcDbAction(Entry->Actions->Items[i]);
}
PhDereferenceObject(Entry->Actions);
PhFree(Entry);
}
VOID PaDeleteProcDbSelector(
__inout PPA_PROCDB_SELECTOR Selector
)
{
switch (Selector->Type)
{
case SelectorProcessName:
PhDereferenceObject(Selector->u.ProcessName.Name);
break;
case SelectorFileName:
PhDereferenceObject(Selector->u.FileName.Name);
break;
default:
assert(FALSE);
break;
}
}
PPA_PROCDB_ACTION PaAllocateProcDbAction(
__in_opt PPA_PROCDB_ACTION Action
)
{
PPA_PROCDB_ACTION action;
action = PhAllocate(sizeof(PA_PROCDB_ACTION));
if (Action)
memcpy(action, Action, sizeof(PA_PROCDB_ACTION));
else
memset(action, 0, sizeof(PA_PROCDB_ACTION));
return action;
}
VOID PaFreeProcDbAction(
__inout PPA_PROCDB_ACTION Action
)
{
PaDeleteProcDbAction(Action);
PhFree(Action);
}
VOID PaDeleteProcDbAction(
__inout PPA_PROCDB_ACTION Action
)
{
switch (Action->Type)
{
case ActionSetPriorityClass:
break;
case ActionSetAffinityMask:
break;
case ActionTerminate:
break;
default:
assert(FALSE);
break;
}
}
PPH_STRING PaFormatProcDbEntry(
__in PPA_PROCDB_ENTRY Entry
)
{
PH_STRING_BUILDER sb;
ULONG i;
PhInitializeStringBuilder(&sb, 64);
if (Entry->Control.Type == ControlDisabled)
PhAppendStringBuilder2(&sb, L"(Disabled) ");
switch (Entry->Selector.Type)
{
case SelectorProcessName:
PhAppendStringBuilder(&sb, Entry->Selector.u.ProcessName.Name);
break;
case SelectorFileName:
PhAppendStringBuilder(&sb, Entry->Selector.u.FileName.Name);
break;
default:
assert(FALSE);
break;
}
if (Entry->Actions->Count != 0)
{
PhAppendStringBuilder2(&sb, L": ");
for (i = 0; i < Entry->Actions->Count; i++)
{
PPA_PROCDB_ACTION action = Entry->Actions->Items[i];
switch (action->Type)
{
case ActionSetPriorityClass:
PhAppendStringBuilder2(&sb, L"set priority class; ");
break;
case ActionSetAffinityMask:
PhAppendStringBuilder2(&sb, L"set affinity mask; ");
break;
case ActionTerminate:
PhAppendStringBuilder2(&sb, L"terminate; ");
break;
}
}
PhRemoveStringBuilder(&sb, sb.String->Length / 2 - 2, 2);
}
return PhFinalStringBuilderString(&sb);
}
VOID PaClearProcDb()
{
ULONG i;
for (i = 0; i < PaProcDbList->Count; i++)
{
PaFreeProcDbEntry(PaProcDbList->Items[i]);
}
PhClearList(PaProcDbList);
}
PPH_STRING PaGetOpaqueXmlNodeText(
__in mxml_node_t *node
)
{
if (node->child && node->child->type == MXML_OPAQUE && node->child->value.opaque)
{
return PhCreateStringFromAnsi(node->child->value.opaque);
}
else
{
return PhCreateString(L"");
}
}
mxml_type_t PapProcDbLoadCallback(
__in mxml_node_t *node
)
{
return MXML_OPAQUE;
}
static ULONG LookupStringAnsi(
__in PSTR *Array,
__in ULONG SizeOfArray,
__in PSTR String
)
{
ULONG i;
// The first element of the array is skipped because
// it should contain an invalid value (like NULL).
for (i = 1; i < SizeOfArray / sizeof(PSTR); i++)
{
if (STR_EQUAL(Array[i], String))
return i;
}
return 0;
}
static PSTR LookupIntegerAnsi(
__in PSTR *Array,
__in ULONG SizeOfArray,
__in ULONG Integer
)
{
if (Integer >= SizeOfArray / sizeof(PSTR))
return NULL;
return Array[Integer];
}
static ULONG GetAttributeValue(
__in mxml_node_t *Node,
__in PSTR AttributeName,
__in PSTR *Array,
__in ULONG SizeOfArray
)
{
PSTR attributeValue;
attributeValue = (PSTR)mxmlElementGetAttr(Node, AttributeName);
if (!attributeValue)
return 0;
return LookupStringAnsi(Array, SizeOfArray, attributeValue);
}
NTSTATUS PaLoadProcDb(
__in PWSTR FileName
)
{
NTSTATUS status;
HANDLE fileHandle;
mxml_node_t *topNode;
mxml_node_t *currentNode;
status = PhCreateFileWin32(
&fileHandle,
FileName,
FILE_GENERIC_READ,
0,
FILE_SHARE_READ | FILE_SHARE_DELETE,
FILE_OPEN,
FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT
);
if (!NT_SUCCESS(status))
return status;
topNode = mxmlLoadFd(NULL, fileHandle, PapProcDbLoadCallback);
NtClose(fileHandle);
if (!topNode)
return STATUS_FILE_CORRUPT_ERROR;
if (!topNode->child)
{
mxmlDelete(topNode);
return STATUS_FILE_CORRUPT_ERROR;
}
PaClearProcDb();
currentNode = topNode->child;
while (currentNode)
{
if (currentNode->type == MXML_ELEMENT)
{
mxml_node_t *childNode;
mxml_node_t *childNode2;
PPA_PROCDB_ENTRY entry;
PA_PROCDB_CONTROL control;
PA_PROCDB_SELECTOR selector;
PA_PROCDB_ACTION action;
// Control
childNode = mxmlFindElement(currentNode, currentNode, "control", NULL, NULL, MXML_DESCEND);
if (!childNode)
goto ContinueEntryLoop;
control.Type = GetAttributeValue(childNode, "type", PaControlStrings, sizeof(PaControlStrings));
if (!control.Type)
goto ContinueEntryLoop;
// Selector
childNode = mxmlFindElement(currentNode, currentNode, "selector", NULL, NULL, MXML_DESCEND);
if (!childNode)
goto ContinueEntryLoop;
selector.Type = GetAttributeValue(childNode, "type", PaSelectorStrings, sizeof(PaSelectorStrings));
if (!selector.Type)
goto ContinueEntryLoop;
switch (selector.Type)
{
case SelectorProcessName:
childNode2 = mxmlFindElement(childNode, childNode, "name", NULL, NULL, MXML_DESCEND);
if (childNode2)
selector.u.ProcessName.Name = PaGetOpaqueXmlNodeText(childNode2);
else
goto ContinueEntryLoop;
case SelectorFileName:
childNode2 = mxmlFindElement(childNode, childNode, "name", NULL, NULL, MXML_DESCEND);
if (childNode2)
selector.u.FileName.Name = PaGetOpaqueXmlNodeText(childNode2);
else
goto ContinueEntryLoop;
}
entry = PaAllocateProcDbEntry();
entry->Control = control;
entry->Selector = selector;
// Actions
childNode = currentNode->child;
while (childNode)
{
if (!STR_IEQUAL(childNode->value.element.name, "action"))
goto ContinueActionLoop;
action.Type = GetAttributeValue(childNode, "type", PaActionStrings, sizeof(PaActionStrings));
if (!action.Type)
goto ContinueActionLoop;
switch (action.Type)
{
case ActionSetPriorityClass:
{
PPH_STRING valueString;
ULONG64 valueInteger;
childNode2 = mxmlFindElement(childNode, childNode, "priorityclasswin32", NULL, NULL, MXML_DESCEND);
if (childNode2)
{
valueString = PaGetOpaqueXmlNodeText(childNode2);
valueInteger = 0;
PhStringToInteger64(&valueString->sr, 0, &valueInteger);
PhDereferenceObject(valueString);
action.u.SetPriorityClass.PriorityClassWin32 = (ULONG)valueInteger;
}
else
{
goto ContinueActionLoop;
}
}
break;
case ActionSetAffinityMask:
{
PPH_STRING valueString;
ULONG64 valueInteger;
childNode2 = mxmlFindElement(childNode, childNode, "affinitymask", NULL, NULL, MXML_DESCEND);
if (childNode2)
{
valueString = PaGetOpaqueXmlNodeText(childNode2);
valueInteger = 0;
PhStringToInteger64(&valueString->sr, 0, &valueInteger);
PhDereferenceObject(valueString);
action.u.SetAffinityMask.AffinityMask = (ULONG_PTR)valueInteger;
}
else
{
goto ContinueActionLoop;
}
}
break;
}
PhAddItemList(entry->Actions, PaAllocateProcDbAction(&action));
ContinueActionLoop:
childNode = childNode->next;
}
PhAddItemList(PaProcDbList, entry);
}
ContinueEntryLoop:
currentNode = currentNode->next;
}
mxmlDelete(topNode);
return STATUS_SUCCESS;
}
mxml_node_t *PapCreateNodeWithOpaque(
__inout mxml_node_t *ParentNode,
__in PSTR Name,
__in PPH_STRINGREF String
)
{
mxml_node_t *newNode;
mxml_node_t *textNode;
PPH_ANSI_STRING ansiString;
ansiString = PhCreateAnsiStringFromUnicodeEx(String->Buffer, String->Length);
newNode = mxmlNewElement(ParentNode, Name);
textNode = mxmlNewOpaque(newNode, ansiString->Buffer);
PhDereferenceObject(ansiString);
return newNode;
}
char *PapProcDbSaveCallback(
__in mxml_node_t *node,
__in int position
)
{
if (STR_IEQUAL(node->value.element.name, "entry"))
{
switch (position)
{
case MXML_WS_BEFORE_OPEN:
case MXML_WS_BEFORE_CLOSE:
return " ";
case MXML_WS_AFTER_OPEN:
case MXML_WS_AFTER_CLOSE:
return "\n";
}
}
if (
STR_IEQUAL(node->value.element.name, "control") ||
STR_IEQUAL(node->value.element.name, "selector") ||
STR_IEQUAL(node->value.element.name, "action")
)
{
switch (position)
{
case MXML_WS_BEFORE_OPEN:
case MXML_WS_BEFORE_CLOSE:
return " ";
case MXML_WS_AFTER_OPEN:
case MXML_WS_AFTER_CLOSE:
return "\n";
}
}
else if (STR_IEQUAL(node->value.element.name, "database"))
{
if (position == MXML_WS_AFTER_OPEN)
return "\n";
}
else
{
if (position == MXML_WS_BEFORE_OPEN)
return " ";
else if (position == MXML_WS_AFTER_CLOSE)
return "\n";
}
return NULL;
}
NTSTATUS PaSaveProcDb(
__in PWSTR FileName
)
{
NTSTATUS status;
HANDLE fileHandle;
mxml_node_t *topNode;
ULONG i;
topNode = mxmlNewElement(MXML_NO_PARENT, "database");
for (i = 0; i < PaProcDbList->Count; i++)
{
PPA_PROCDB_ENTRY entry;
mxml_node_t *entryNode;
mxml_node_t *childNode;
ULONG j;
entry = PaProcDbList->Items[i];
entryNode = mxmlNewElement(topNode, "entry");
// Control
childNode = mxmlNewElement(entryNode, "control");
mxmlElementSetAttr(childNode, "type",
LookupIntegerAnsi(PaControlStrings, sizeof(PaControlStrings), entry->Control.Type));
// Selector
childNode = mxmlNewElement(entryNode, "selector");
mxmlElementSetAttr(childNode, "type",
LookupIntegerAnsi(PaSelectorStrings, sizeof(PaSelectorStrings), entry->Selector.Type));
switch (entry->Selector.Type)
{
case SelectorProcessName:
PapCreateNodeWithOpaque(childNode, "name", &entry->Selector.u.ProcessName.Name->sr);
break;
case SelectorFileName:
PapCreateNodeWithOpaque(childNode, "name", &entry->Selector.u.FileName.Name->sr);
break;
}
// Actions
for (j = 0; j < entry->Actions->Count; j++)
{
PPA_PROCDB_ACTION action = entry->Actions->Items[j];
childNode = mxmlNewElement(entryNode, "action");
mxmlElementSetAttr(childNode, "type",
LookupIntegerAnsi(PaActionStrings, sizeof(PaActionStrings), action->Type));
switch (action->Type)
{
case ActionSetPriorityClass:
{
WCHAR buffer[PH_INT32_STR_LEN_1];
PH_STRINGREF stringRef;
_snwprintf(buffer, PH_INT32_STR_LEN, L"0x%x", action->u.SetPriorityClass.PriorityClassWin32);
PhInitializeStringRef(&stringRef, buffer);
PapCreateNodeWithOpaque(childNode, "priorityclasswin32", &stringRef);
}
break;
case ActionSetAffinityMask:
{
WCHAR buffer[PH_INT64_STR_LEN_1];
PH_STRINGREF stringRef;
_snwprintf(buffer, PH_INT64_STR_LEN, L"0x%Ix", action->u.SetAffinityMask.AffinityMask);
PhInitializeStringRef(&stringRef, buffer);
PapCreateNodeWithOpaque(childNode, "affinitymask", &stringRef);
}
break;
}
}
}
// Create the directory if it does not exist.
{
PPH_STRING fullPath;
ULONG indexOfFileName;
PPH_STRING directoryName;
fullPath = PhGetFullPath(FileName, &indexOfFileName);
if (fullPath)
{
if (indexOfFileName != -1)
{
directoryName = PhSubstring(fullPath, 0, indexOfFileName);
SHCreateDirectoryEx(NULL, directoryName->Buffer, NULL);
PhDereferenceObject(directoryName);
}
PhDereferenceObject(fullPath);
}
}
status = PhCreateFileWin32(
&fileHandle,
FileName,
FILE_GENERIC_WRITE,
0,
FILE_SHARE_READ,
FILE_OVERWRITE_IF,
FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT
);
if (!NT_SUCCESS(status))
{
mxmlDelete(topNode);
return status;
}
mxmlSaveFd(topNode, fileHandle, PapProcDbSaveCallback);
mxmlDelete(topNode);
NtClose(fileHandle);
return STATUS_SUCCESS;
}