Files
simplewall/src/profile.c
T
2025-02-12 15:15:47 +05:00

1835 lines
39 KiB
C

// simplewall
// Copyright (c) 2016-2024 Henry++
#include "global.h"
_Success_ (return)
BOOLEAN _app_getappinfo (
_In_ PITEM_APP ptr_app,
_In_ ENUM_INFO_DATA info_data,
_Out_writes_bytes_all_ (length) PVOID buffer,
_In_ ULONG_PTR length
)
{
RtlZeroMemory (buffer, length);
switch (info_data)
{
case INFO_PATH:
{
PVOID ptr;
if (length != sizeof (PVOID))
return FALSE;
if (ptr_app->real_path)
{
ptr = _r_obj_reference (ptr_app->real_path);
RtlCopyMemory (buffer, &ptr, length);
return TRUE;
}
break;
}
case INFO_DISPLAY_NAME:
{
PVOID ptr;
if (length != sizeof (PVOID))
return FALSE;
if (ptr_app->display_name)
{
ptr = _r_obj_reference (ptr_app->display_name);
RtlCopyMemory (buffer, &ptr, length);
return TRUE;
}
else if (ptr_app->original_path)
{
ptr = _r_obj_reference (ptr_app->original_path);
RtlCopyMemory (buffer, &ptr, length);
return TRUE;
}
break;
}
case INFO_HASH:
{
PVOID ptr;
if (length != sizeof (PVOID))
return FALSE;
if (ptr_app->hash)
{
ptr = _r_obj_reference (ptr_app->hash);
RtlCopyMemory (buffer, &ptr, length);
return TRUE;
}
break;
}
case INFO_TIMESTAMP:
{
if (length != sizeof (LONG64))
return FALSE;
RtlCopyMemory (buffer, &ptr_app->timestamp, length);
return TRUE;
}
case INFO_TIMER:
{
if (length != sizeof (LONG64))
return FALSE;
RtlCopyMemory (buffer, &ptr_app->timer, length);
return TRUE;
}
case INFO_LISTVIEW_ID:
{
INT listview_id;
if (length != sizeof (INT))
return FALSE;
listview_id = _app_listview_getbytype (ptr_app->type);
RtlCopyMemory (buffer, &listview_id, length);
return TRUE;
}
case INFO_IS_ENABLED:
{
BOOLEAN is_enabled;
if (length != sizeof (BOOLEAN))
return FALSE;
is_enabled = !!ptr_app->is_enabled;
RtlCopyMemory (buffer, &is_enabled, length);
return TRUE;
}
case INFO_IS_SILENT:
{
BOOLEAN is_silent;
if (length != sizeof (BOOLEAN))
return FALSE;
is_silent = !!ptr_app->is_silent;
RtlCopyMemory (buffer, &is_silent, length);
return TRUE;
}
case INFO_IS_UNDELETABLE:
{
BOOLEAN is_undeletable;
if (length != sizeof (BOOLEAN))
return FALSE;
is_undeletable = !!ptr_app->is_undeletable;
RtlCopyMemory (buffer, &is_undeletable, length);
return TRUE;
}
}
return FALSE;
}
_Success_ (return)
BOOLEAN _app_getappinfobyhash (
_In_ ULONG_PTR app_hash,
_In_ ENUM_INFO_DATA info_data,
_Out_writes_bytes_all_ (length) PVOID buffer,
_In_ ULONG_PTR length
)
{
PITEM_APP ptr_app;
BOOLEAN is_success;
RtlZeroMemory (buffer, length);
ptr_app = _app_getappitem (app_hash);
if (!ptr_app)
return FALSE;
is_success = _app_getappinfo (ptr_app, info_data, buffer, length);
_r_obj_dereference (ptr_app);
return is_success;
}
VOID _app_setappinfo (
_In_ PITEM_APP ptr_app,
_In_ ENUM_INFO_DATA info_data,
_In_opt_ PVOID value
)
{
switch (info_data)
{
case INFO_BYTES_DATA:
{
_r_obj_movereference (&ptr_app->bytes, value);
break;
}
case INFO_COMMENT:
{
_r_obj_movereference (&ptr_app->comment, value);
break;
}
case INFO_HASH:
{
_r_obj_movereference (&ptr_app->hash, value);
break;
}
case INFO_TIMESTAMP:
{
if (!value)
break;
ptr_app->timestamp = *((PLONG64)value);
break;
}
case INFO_TIMER:
{
HANDLE engine_handle;
LONG64 timestamp;
if (!value)
break;
timestamp = *((PLONG64)value);
// check timer expiration
if (timestamp <= _r_unixtime_now ())
{
engine_handle = _wfp_getenginehandle ();
_wfp_destroyfilters_array (engine_handle, ptr_app->guids, DBG_ARG);
_r_obj_cleararray (ptr_app->guids);
ptr_app->timer = 0;
ptr_app->is_enabled = FALSE;
}
else
{
ptr_app->timer = timestamp;
ptr_app->is_enabled = TRUE;
}
_app_listview_updateitemby_param (_r_app_gethwnd (), ptr_app->app_hash, TRUE);
break;
}
case INFO_DISABLE:
{
HANDLE engine_handle;
ptr_app->is_enabled = FALSE;
engine_handle = _wfp_getenginehandle ();
_wfp_destroyfilters_array (engine_handle, ptr_app->guids, DBG_ARG);
_r_obj_cleararray (ptr_app->guids);
_app_listview_updateitemby_param (_r_app_gethwnd (), ptr_app->app_hash, TRUE);
break;
}
case INFO_IS_ENABLED:
{
ptr_app->is_enabled = (PtrToInt (value) ? TRUE : FALSE);
_app_listview_updateitemby_param (_r_app_gethwnd (), ptr_app->app_hash, TRUE);
break;
}
case INFO_IS_SILENT:
{
ptr_app->is_silent = (PtrToInt (value) ? TRUE : FALSE);
if (ptr_app->is_silent)
_app_notify_freeobject (NULL, ptr_app);
break;
}
case INFO_IS_UNDELETABLE:
{
ptr_app->is_undeletable = (PtrToInt (value) ? TRUE : FALSE);
break;
}
}
}
VOID _app_setappinfobyhash (
_In_ ULONG_PTR app_hash,
_In_ ENUM_INFO_DATA info_data,
_In_opt_ PVOID value
)
{
PITEM_APP ptr_app;
ptr_app = _app_getappitem (app_hash);
if (!ptr_app)
return;
_app_setappinfo (ptr_app, info_data, value);
_r_obj_dereference (ptr_app);
}
_Success_ (return)
BOOLEAN _app_getruleinfo (
_In_ PITEM_RULE ptr_rule,
_In_ ENUM_INFO_DATA info_data,
_Out_writes_bytes_all_ (length) PVOID buffer,
_In_ ULONG_PTR length
)
{
RtlZeroMemory (buffer, length);
switch (info_data)
{
case INFO_LISTVIEW_ID:
{
INT listview_id;
if (length != sizeof (INT))
return FALSE;
listview_id = _app_listview_getbytype (ptr_rule->type);
RtlCopyMemory (buffer, &listview_id, length);
return TRUE;
}
case INFO_IS_READONLY:
{
INT is_readonly;
if (length != sizeof (INT))
return FALSE;
is_readonly = !!ptr_rule->is_readonly;
RtlCopyMemory (buffer, &is_readonly, length);
return TRUE;
}
}
return FALSE;
}
_Success_ (return)
BOOLEAN _app_getruleinfobyid (
_In_ ULONG_PTR index,
_In_ ENUM_INFO_DATA info_data,
_Out_writes_bytes_all_ (length) PVOID buffer,
_In_ ULONG_PTR length
)
{
PITEM_RULE ptr_rule;
BOOLEAN is_success;
ptr_rule = _app_getrulebyid (index);
if (!ptr_rule)
return FALSE;
is_success = _app_getruleinfo (ptr_rule, info_data, buffer, length);
_r_obj_dereference (ptr_rule);
return is_success;
}
_Success_ (return != 0)
ULONG_PTR _app_addapplication (
_In_opt_ HWND hwnd,
_In_ ENUM_TYPE_DATA type,
_In_ PR_STRING path,
_In_opt_ PR_STRING display_name,
_In_opt_ PR_STRING real_path
)
{
WCHAR path_full[1024];
R_STRINGREF path_sr;
PITEM_APP ptr_app;
ULONG_PTR app_hash;
BOOLEAN is_ntoskrnl;
if (_r_obj_isstringempty2 (path))
return 0;
if (_app_isappvalidpath (path) && _r_fs_isdirectory (&path->sr))
return 0;
_r_obj_initializestringref2 (&path_sr, &path->sr);
// prevent possible duplicate apps entries with short path (issue #640)
if (_r_str_findchar (&path_sr, L'~', FALSE) != SIZE_MAX)
{
if (GetLongPathNameW (path_sr.buffer, path_full, RTL_NUMBER_OF (path_full)))
_r_obj_initializestringref (&path_sr, path_full);
}
app_hash = _r_str_gethash2 (&path_sr, TRUE);
if (_app_isappfound (app_hash))
return app_hash; // already exists
ptr_app = _r_obj_allocate (sizeof (ITEM_APP), &_app_dereferenceapp);
is_ntoskrnl = (app_hash == config.ntoskrnl_hash);
ptr_app->app_hash = app_hash;
if (type == DATA_UNKNOWN)
{
if (_r_str_isstartswith2 (&path_sr, L"S-1-", TRUE)) // uwp (win8+)
type = DATA_APP_UWP;
}
if (type == DATA_APP_SERVICE || type == DATA_APP_UWP)
{
ptr_app->type = type;
if (display_name)
ptr_app->display_name = _r_obj_reference (display_name);
if (real_path)
ptr_app->real_path = _r_obj_reference (real_path);
}
else if (_r_str_isstartswith2 (&path_sr, L"\\device\\", TRUE)) // device path
{
ptr_app->type = DATA_APP_DEVICE;
ptr_app->real_path = _r_obj_createstring2 (&path_sr);
}
else
{
if (!is_ntoskrnl && _r_str_findchar (&path_sr, OBJ_NAME_PATH_SEPARATOR, FALSE) == SIZE_MAX)
{
ptr_app->type = DATA_APP_PICO;
}
else
{
ptr_app->type = PathIsNetworkPathW (path_sr.buffer) ? DATA_APP_NETWORK : DATA_APP_REGULAR;
}
if (is_ntoskrnl)
{
ptr_app->real_path = _r_obj_createstring2 (&config.ntoskrnl_path->sr);
}
else
{
ptr_app->real_path = _r_obj_createstring2 (&path_sr);
}
}
ptr_app->original_path = _r_obj_createstring2 (&path_sr);
// fix "System" lowercase
if (is_ntoskrnl)
{
_r_str_tolower (&ptr_app->original_path->sr);
ptr_app->original_path->buffer[0] = _r_str_upper (ptr_app->original_path->buffer[0]);
}
//if (ptr_app->type == DATA_APP_REGULAR || ptr_app->type == DATA_APP_DEVICE || ptr_app->type == DATA_APP_NETWORK)
{
ptr_app->short_name = _r_path_getbasenamestring (&path_sr);
}
ptr_app->guids = _r_obj_createarray (sizeof (GUID), 4, NULL); // initialize array
ptr_app->timestamp = _r_unixtime_now ();
// insert object into the table
//
//_r_queuedlock_acquireexclusive (&lock_apps);
_r_obj_addhashtablepointer (apps_table, app_hash, ptr_app);
//_r_queuedlock_releaseexclusive (&lock_apps);
// insert item
if (hwnd)
_app_listview_addappitem (hwnd, ptr_app);
// queue file information
if (!_r_obj_isstringempty (ptr_app->real_path))
_app_getfileinformation (ptr_app->real_path, app_hash, ptr_app->type, _app_listview_getbytype (ptr_app->type));
return app_hash;
}
PITEM_RULE _app_addrule (
_In_opt_ PR_STRING name,
_In_opt_ PR_STRING rule_remote,
_In_opt_ PR_STRING rule_local,
_In_ FWP_DIRECTION direction,
_In_ FWP_ACTION_TYPE action,
_In_ UINT8 protocol,
_In_ ADDRESS_FAMILY af
)
{
PITEM_RULE ptr_rule;
ptr_rule = _r_obj_allocate (sizeof (ITEM_RULE), &_app_dereferencerule);
ptr_rule->apps = _r_obj_createhashtable (sizeof (SHORT), 4, NULL); // initialize hashtable
ptr_rule->guids = _r_obj_createarray (sizeof (GUID), 4, NULL); // initialize array
ptr_rule->type = DATA_RULE_USER;
// set rule name
if (name)
{
ptr_rule->name = _r_obj_reference (name);
if (_r_str_getlength2 (&ptr_rule->name->sr) > RULE_NAME_CCH_MAX)
_r_str_setlength (&ptr_rule->name->sr, RULE_NAME_CCH_MAX * sizeof (WCHAR));
}
// set rule destination
if (rule_remote)
{
ptr_rule->rule_remote = _r_obj_reference (rule_remote);
if (_r_str_getlength2 (&ptr_rule->rule_remote->sr) > RULE_RULE_CCH_MAX)
_r_str_setlength (&ptr_rule->rule_remote->sr, RULE_RULE_CCH_MAX * sizeof (WCHAR));
}
// set rule source
if (rule_local)
{
ptr_rule->rule_local = _r_obj_reference (rule_local);
if (_r_str_getlength2 (&ptr_rule->rule_local->sr) > RULE_RULE_CCH_MAX)
_r_str_setlength (&ptr_rule->rule_local->sr, RULE_RULE_CCH_MAX * sizeof (WCHAR));
}
// set configuration
ptr_rule->direction = direction;
ptr_rule->action = action;
ptr_rule->protocol = protocol;
ptr_rule->af = af;
ptr_rule->protocol_str = _app_db_getprotoname (protocol, af, FALSE);
return ptr_rule;
}
_Ret_maybenull_
PITEM_RULE_CONFIG _app_addruleconfigtable (
_In_ PR_HASHTABLE hashtable,
_In_ ULONG_PTR rule_hash,
_In_ PR_STRING rule_name,
_In_ BOOLEAN is_enabled
)
{
ITEM_RULE_CONFIG entry = {0};
entry.name = _r_obj_reference (rule_name);
entry.is_enabled = is_enabled;
return _r_obj_addhashtableitem (hashtable, rule_hash, &entry);
}
_Ret_maybenull_
PITEM_APP _app_getappitem (
_In_ ULONG_PTR app_hash
)
{
PITEM_APP ptr_app;
_r_queuedlock_acquireshared (&lock_apps);
ptr_app = _r_obj_findhashtablepointer (apps_table, app_hash);
_r_queuedlock_releaseshared (&lock_apps);
return ptr_app;
}
_Ret_maybenull_
PITEM_RULE _app_getrulebyid (
_In_ ULONG_PTR index
)
{
PITEM_RULE ptr_rule;
_r_queuedlock_acquireshared (&lock_rules);
if (index < _r_obj_getlistsize (rules_list))
{
ptr_rule = _r_obj_getlistitem (rules_list, index);
}
else
{
ptr_rule = NULL;
}
_r_queuedlock_releaseshared (&lock_rules);
if (ptr_rule)
return _r_obj_reference (ptr_rule);
return NULL;
}
_Ret_maybenull_
PITEM_RULE _app_getrulebyhash (
_In_ ULONG_PTR rule_hash
)
{
PITEM_RULE ptr_rule;
if (!rule_hash)
return NULL;
_r_queuedlock_acquireshared (&lock_rules);
for (ULONG_PTR i = 0; i < _r_obj_getlistsize (rules_list); i++)
{
ptr_rule = _r_obj_getlistitem (rules_list, i);
if (ptr_rule)
{
if (ptr_rule->is_readonly)
{
if (_r_str_gethash2 (&ptr_rule->name->sr, TRUE) == rule_hash)
{
_r_queuedlock_releaseshared (&lock_rules);
return _r_obj_reference (ptr_rule);
}
}
}
}
_r_queuedlock_releaseshared (&lock_rules);
return NULL;
}
_Ret_maybenull_
PITEM_RULE_CONFIG _app_getruleconfigitem (
_In_ ULONG_PTR rule_hash
)
{
PITEM_RULE_CONFIG ptr_rule_config;
_r_queuedlock_acquireshared (&lock_rules_config);
ptr_rule_config = _r_obj_findhashtable (rules_config, rule_hash);
_r_queuedlock_releaseshared (&lock_rules_config);
return ptr_rule_config;
}
_Ret_maybenull_
PITEM_LOG _app_getlogitem (
_In_ ULONG_PTR log_hash
)
{
PITEM_LOG ptr_log;
_r_queuedlock_acquireshared (&lock_loglist);
ptr_log = _r_obj_findhashtablepointer (log_table, log_hash);
_r_queuedlock_releaseshared (&lock_loglist);
return ptr_log;
}
_Success_ (return != 0)
ULONG_PTR _app_getlogapp (
_In_ ULONG_PTR index
)
{
PITEM_LOG ptr_log;
ULONG_PTR app_hash;
ptr_log = _app_getlogitem (index);
if (ptr_log)
{
app_hash = ptr_log->app_hash;
_r_obj_dereference (ptr_log);
return app_hash;
}
return 0;
}
COLORREF _app_getappcolor (
_In_ INT listview_id,
_In_ ULONG_PTR app_hash,
_In_ BOOLEAN is_systemapp,
_In_ BOOLEAN is_validconnection
)
{
PITEM_APP ptr_app;
ULONG_PTR color_hash = 0;
BOOLEAN is_profilelist;
BOOLEAN is_networklist;
ptr_app = _app_getappitem (app_hash);
is_profilelist = (listview_id >= IDC_APPS_PROFILE && listview_id <= IDC_RULES_CUSTOM);
is_networklist = (listview_id == IDC_NETWORK || listview_id == IDC_LOG);
if (ptr_app && !is_networklist)
{
if (_r_config_getboolean (L"IsHighlightInvalid", TRUE, L"colors") && !_app_isappexists (ptr_app))
{
color_hash = config.color_invalid;
goto CleanupExit;
}
}
if (_r_config_getboolean (L"IsHighlightConnection", TRUE, L"colors") && is_validconnection)
{
color_hash = config.color_network;
goto CleanupExit;
}
if (_r_config_getboolean (L"IsHighlightSigned", TRUE, L"colors") && _app_isappsigned (app_hash))
{
color_hash = config.color_signed;
goto CleanupExit;
}
if (ptr_app)
{
if (!is_profilelist && (_r_config_getboolean (L"IsHighlightSpecial", TRUE, L"colors") && _app_isapphaverule (app_hash, FALSE)))
{
color_hash = config.color_special;
goto CleanupExit;
}
if (_r_config_getboolean (L"IsHighlightPico", TRUE, L"colors") && ptr_app->type == DATA_APP_PICO)
{
color_hash = config.color_pico;
goto CleanupExit;
}
if (_r_config_getboolean (L"IsHighlightUndelete", TRUE, L"colors") && ptr_app->is_undeletable)
{
color_hash = config.color_nonremovable;
goto CleanupExit;
}
}
if (_r_config_getboolean (L"IsHighlightSystem", TRUE, L"colors") && is_systemapp)
{
color_hash = config.color_system;
goto CleanupExit;
}
CleanupExit:
if (ptr_app)
_r_obj_dereference (ptr_app);
if (color_hash)
return _app_getcolorvalue (color_hash);
return 0;
}
VOID _app_deleteappitem (
_In_ HWND hwnd,
_In_ ENUM_TYPE_DATA type,
_In_ ULONG_PTR id_code
)
{
INT listview_id;
INT item_id;
listview_id = _app_listview_getbytype (type);
if (!listview_id)
return;
item_id = _app_listview_finditem (hwnd, listview_id, id_code);
if (item_id != INT_ERROR)
_r_listview_deleteitem (hwnd, listview_id, item_id);
}
VOID _app_freeapplication (
_In_opt_ HWND hwnd,
_In_ ULONG_PTR app_hash
)
{
PITEM_RULE ptr_rule;
_r_queuedlock_acquireshared (&lock_rules);
for (ULONG_PTR i = 0; i < _r_obj_getlistsize (rules_list); i++)
{
ptr_rule = _r_obj_getlistitem (rules_list, i);
if (!ptr_rule)
continue;
if (ptr_rule->type != DATA_RULE_USER)
continue;
if (hwnd)
_app_ruleremoveapp (hwnd, i, ptr_rule, app_hash);
}
_r_queuedlock_releaseshared (&lock_rules);
_r_obj_removehashtableitem (apps_table, app_hash);
}
VOID _app_getcount (
_Out_ PITEM_STATUS status
)
{
PITEM_APP ptr_app = NULL;
PITEM_RULE ptr_rule;
ULONG_PTR enum_key = 0;
BOOLEAN is_used;
RtlZeroMemory (status, sizeof (ITEM_STATUS));
_r_queuedlock_acquireshared (&lock_apps);
while (_r_obj_enumhashtablepointer (apps_table, &ptr_app, NULL, &enum_key))
{
is_used = _app_isappused (ptr_app);
if (_app_istimerset (ptr_app))
status->apps_timer_count += 1;
if (!ptr_app->is_undeletable && (!_app_isappexists (ptr_app) || !is_used) && !(ptr_app->type == DATA_APP_SERVICE || ptr_app->type == DATA_APP_UWP))
status->apps_unused_count += 1;
if (is_used)
status->apps_count += 1;
}
_r_queuedlock_releaseshared (&lock_apps);
_r_queuedlock_acquireshared (&lock_rules);
for (ULONG_PTR i = 0; i < _r_obj_getlistsize (rules_list); i++)
{
ptr_rule = _r_obj_getlistitem (rules_list, i);
if (!ptr_rule)
continue;
if (ptr_rule->type == DATA_RULE_USER)
{
if (ptr_rule->is_enabled && !_r_obj_isempty (ptr_rule->apps))
status->rules_global_count += 1;
if (ptr_rule->is_readonly)
{
status->rules_predefined_count += 1;
}
else
{
status->rules_user_count += 1;
}
status->rules_count += 1;
}
}
_r_queuedlock_releaseshared (&lock_rules);
}
COLORREF _app_getrulecolor (
_In_ INT listview_id,
_In_ ULONG_PTR rule_idx
)
{
PITEM_RULE ptr_rule;
ULONG_PTR color_hash = 0;
ptr_rule = _app_getrulebyid (rule_idx);
if (!ptr_rule)
return 0;
if (_r_config_getboolean (L"IsHighlightInvalid", TRUE, L"colors") && ptr_rule->is_enabled && ptr_rule->is_haveerrors)
{
color_hash = config.color_invalid;
}
else if (_r_config_getboolean (L"IsHighlightSpecial", TRUE, L"colors") && (ptr_rule->is_forservices || !_r_obj_isempty (ptr_rule->apps)))
{
color_hash = config.color_special;
}
_r_obj_dereference (ptr_rule);
if (color_hash)
return _app_getcolorvalue (color_hash);
return 0;
}
VOID _app_setappiteminfo (
_In_ HWND hwnd,
_In_ INT listview_id,
_In_ INT item_id,
_In_ PITEM_APP ptr_app
)
{
_r_listview_setitem (hwnd, listview_id, item_id, 0, LPSTR_TEXTCALLBACK, I_IMAGECALLBACK, I_GROUPIDCALLBACK, I_DEFAULT);
_r_listview_setitemcheck (hwnd, listview_id, item_id, !!ptr_app->is_enabled);
}
VOID _app_setruleiteminfo (
_In_ HWND hwnd,
_In_ INT listview_id,
_In_ INT item_id,
_In_ PITEM_RULE ptr_rule,
_In_ BOOLEAN include_apps
)
{
ULONG_PTR enum_key = 0;
ULONG_PTR hash_code;
_r_listview_setitem (hwnd, listview_id, item_id, 0, LPSTR_TEXTCALLBACK, I_IMAGECALLBACK, I_GROUPIDCALLBACK, I_DEFAULT);
_r_listview_setitemcheck (hwnd, listview_id, item_id, !!ptr_rule->is_enabled);
if (!include_apps)
return;
while (_r_obj_enumhashtable (ptr_rule->apps, NULL, &hash_code, &enum_key))
{
_app_listview_updateitemby_param (hwnd, hash_code, TRUE);
}
}
VOID _app_ruleenable (
_Inout_ PITEM_RULE ptr_rule,
_In_ BOOLEAN is_enable,
_In_ BOOLEAN is_createconfig
)
{
PITEM_RULE_CONFIG ptr_config;
ULONG_PTR rule_hash;
ptr_rule->is_enabled = is_enable;
if (!ptr_rule->is_readonly || !ptr_rule->name)
return;
rule_hash = _r_str_gethash2 (&ptr_rule->name->sr, TRUE);
if (!rule_hash)
return;
ptr_config = _app_getruleconfigitem (rule_hash);
if (ptr_config)
{
ptr_config->is_enabled = is_enable;
}
else
{
if (is_createconfig)
{
_r_queuedlock_acquireexclusive (&lock_rules_config);
ptr_config = _app_addruleconfigtable (rules_config, rule_hash, ptr_rule->name, is_enable);
_r_queuedlock_releaseexclusive (&lock_rules_config);
}
}
}
VOID _app_ruleremoveapp (
_In_opt_ HWND hwnd,
_In_ ULONG_PTR item_id,
_In_ PITEM_RULE ptr_rule,
_In_ ULONG_PTR app_hash
)
{
if (!ptr_rule->apps)
return;
if (!_r_obj_removehashtableitem (ptr_rule->apps, app_hash))
return;
if (ptr_rule->is_enabled && _r_obj_isempty (ptr_rule->apps))
{
ptr_rule->is_enabled = FALSE;
ptr_rule->is_haveerrors = FALSE;
if (hwnd)
{
if (item_id != SIZE_MAX)
_app_listview_updateitemby_param (hwnd, item_id, FALSE);
}
}
}
BOOLEAN _app_ruleblocklistsetchange (
_Inout_ PITEM_RULE ptr_rule,
_In_ LONG new_state
)
{
BOOLEAN is_block;
if (new_state == INT_ERROR)
return FALSE; // don't change
if (new_state == 0 && !ptr_rule->is_enabled)
return FALSE; // not changed
is_block = (ptr_rule->action == FWP_ACTION_BLOCK);
if (new_state == 1 && ptr_rule->is_enabled && !is_block)
return FALSE; // not changed
if (new_state == 2 && ptr_rule->is_enabled && is_block)
return FALSE; // not changed
ptr_rule->action = (new_state != 1) ? FWP_ACTION_BLOCK : FWP_ACTION_PERMIT;
ptr_rule->is_enabled_default = ptr_rule->is_enabled; // set default value for rule
ptr_rule->is_enabled = (new_state != 0);
return TRUE;
}
BOOLEAN _app_ruleblocklistsetstate (
_Inout_ PITEM_RULE ptr_rule,
_In_ LONG spy_state,
_In_ LONG update_state,
_In_ LONG extra_state
)
{
if (ptr_rule->type != DATA_RULE_BLOCKLIST || _r_obj_isstringempty (ptr_rule->name))
return FALSE;
if (_r_str_isstartswith2 (&ptr_rule->name->sr, L"spy_", TRUE))
{
return _app_ruleblocklistsetchange (ptr_rule, spy_state);
}
else if (_r_str_isstartswith2 (&ptr_rule->name->sr, L"update_", TRUE))
{
return _app_ruleblocklistsetchange (ptr_rule, update_state);
}
else if (_r_str_isstartswith2 (&ptr_rule->name->sr, L"extra_", TRUE))
{
return _app_ruleblocklistsetchange (ptr_rule, extra_state);
}
// fallback: block rules with other names by default!
return _app_ruleblocklistsetchange (ptr_rule, 2);
}
VOID _app_ruleblocklistset (
_In_opt_ HWND hwnd,
_In_ LONG spy_state,
_In_ LONG update_state,
_In_ LONG extra_state,
_In_ BOOLEAN is_instantapply
)
{
PR_LIST rules;
PITEM_RULE ptr_rule;
HANDLE hengine;
ULONG_PTR changes_count = 0;
rules = _r_obj_createlist (6, &_r_obj_dereference);
_r_queuedlock_acquireshared (&lock_rules);
for (ULONG_PTR i = 0; i < _r_obj_getlistsize (rules_list); i++)
{
ptr_rule = _r_obj_getlistitem (rules_list, i);
if (!ptr_rule)
continue;
if (ptr_rule->type != DATA_RULE_BLOCKLIST)
continue;
if (!_app_ruleblocklistsetstate (ptr_rule, spy_state, update_state, extra_state))
continue;
_app_ruleenable (ptr_rule, !!ptr_rule->is_enabled, FALSE);
changes_count += 1;
if (hwnd)
_app_listview_updateitemby_param (hwnd, i, FALSE);
if (is_instantapply)
_r_obj_addlistitem (rules, _r_obj_reference (ptr_rule)); // dereference later!
}
_r_queuedlock_releaseshared (&lock_rules);
if (changes_count)
{
if (hwnd)
_app_listview_updateby_id (hwnd, DATA_RULE_BLOCKLIST, PR_UPDATE_TYPE | PR_UPDATE_NORESIZE);
if (is_instantapply)
{
if (rules->count)
{
if (_wfp_isfiltersinstalled ())
{
hengine = _wfp_getenginehandle ();
_wfp_create4filters (hengine, rules, DBG_ARG, FALSE);
}
}
}
_app_profile_save (hwnd); // required!
}
_r_obj_dereference (rules);
}
_Ret_maybenull_
PR_STRING _app_appexpandrules (
_In_ ULONG_PTR app_hash,
_In_ LPWSTR delimeter
)
{
R_STRINGBUILDER buffer;
R_STRINGREF delimeter_sr;
PR_STRING string;
PITEM_RULE ptr_rule;
_r_obj_initializestringbuilder (&buffer, 256);
_r_obj_initializestringref (&delimeter_sr, delimeter);
_r_queuedlock_acquireshared (&lock_rules);
for (ULONG_PTR i = 0; i < _r_obj_getlistsize (rules_list); i++)
{
ptr_rule = _r_obj_getlistitem (rules_list, i);
if (!ptr_rule)
continue;
if (ptr_rule->is_enabled && ptr_rule->type == DATA_RULE_USER && !_r_obj_isstringempty (ptr_rule->name) && _r_obj_findhashtable (ptr_rule->apps, app_hash))
{
_r_obj_appendstringbuilder2 (&buffer, &ptr_rule->name->sr);
if (ptr_rule->is_readonly)
_r_obj_appendstringbuilder (&buffer, SZ_RULE_INTERNAL_MENU);
_r_obj_appendstringbuilder2 (&buffer, &delimeter_sr);
}
}
_r_queuedlock_releaseshared (&lock_rules);
string = _r_obj_finalstringbuilder (&buffer);
_r_str_trimstring (&string->sr, &delimeter_sr, 0);
if (!_r_obj_isstringempty2 (string))
return string;
_r_obj_deletestringbuilder (&buffer);
return NULL;
}
_Ret_maybenull_
PR_STRING _app_rulesexpandapps (
_In_ PITEM_RULE ptr_rule,
_In_ BOOLEAN is_fordisplay,
_In_ LPWSTR delimeter
)
{
R_STRINGREF delimeter_sr;
R_STRINGBUILDER sr;
PITEM_APP ptr_app;
PR_STRING string;
ULONG_PTR enum_key = 0;
ULONG_PTR hash_code;
_r_obj_initializestringbuilder (&sr, 256);
_r_obj_initializestringref (&delimeter_sr, delimeter);
if (is_fordisplay && ptr_rule->is_forservices)
{
string = _r_obj_concatstrings (
4,
PROC_SYSTEM_NAME,
delimeter,
_r_obj_getstring (config.svchost_path),
delimeter
);
_r_obj_appendstringbuilder2 (&sr, &string->sr);
_r_obj_dereference (string);
}
while (_r_obj_enumhashtable (ptr_rule->apps, NULL, &hash_code, &enum_key))
{
ptr_app = _app_getappitem (hash_code);
if (!ptr_app)
continue;
string = NULL;
if (is_fordisplay)
{
if (ptr_app->type == DATA_APP_UWP)
{
if (ptr_app->display_name)
string = _r_path_compact (&ptr_app->display_name->sr, 64);
}
}
if (!string)
{
if (is_fordisplay)
{
if (ptr_app->original_path)
string = _r_path_compact (&ptr_app->original_path->sr, 64);
}
}
if (!string)
string = _r_obj_referencesafe (ptr_app->original_path);
if (string)
{
_r_obj_appendstringbuilder2 (&sr, &string->sr);
_r_obj_appendstringbuilder2 (&sr, &delimeter_sr);
_r_obj_dereference (string);
}
_r_obj_dereference (ptr_app);
}
string = _r_obj_finalstringbuilder (&sr);
_r_str_trimstring (&string->sr, &delimeter_sr, PR_TRIM_END_ONLY);
if (!_r_obj_isstringempty2 (string))
return string;
_r_obj_deletestringbuilder (&sr);
return NULL;
}
_Ret_maybenull_
PR_STRING _app_rulesexpandrules (
_In_opt_ PR_STRING rule,
_In_ LPWSTR delimeter
)
{
R_STRINGBUILDER sb;
R_STRINGREF delimeter_sr;
R_STRINGREF remaining_part;
R_STRINGREF first_part;
PR_STRING string;
if (_r_obj_isstringempty (rule))
return NULL;
_r_obj_initializestringbuilder (&sb, 256);
_r_obj_initializestringref (&delimeter_sr, delimeter);
_r_obj_initializestringref2 (&remaining_part, &rule->sr);
while (remaining_part.length != 0)
{
_r_str_splitatchar (&remaining_part, DIVIDER_RULE[0], &first_part, &remaining_part);
_r_obj_appendstringbuilder2 (&sb, &first_part);
_r_obj_appendstringbuilder2 (&sb, &delimeter_sr);
}
string = _r_obj_finalstringbuilder (&sb);
_r_str_trimstring (&string->sr, &delimeter_sr, 0);
if (!_r_obj_isstringempty2 (string))
return string;
_r_obj_deletestringbuilder (&sb);
return NULL;
}
BOOLEAN _app_isappfromsystem (
_In_opt_ PR_STRING path,
_In_ ULONG_PTR app_hash
)
{
if (_app_issystemhash (app_hash))
return TRUE;
if (path)
{
if (_r_str_isstartswith (&path->sr, &config.windows_dir, TRUE))
return TRUE;
}
return FALSE;
}
BOOLEAN _app_isapphavedrive (
_In_ INT letter
)
{
PITEM_APP ptr_app = NULL;
ULONG_PTR enum_key = 0;
INT drive_id;
_r_queuedlock_acquireshared (&lock_apps);
while (_r_obj_enumhashtablepointer (apps_table, &ptr_app, NULL, &enum_key))
{
if (_r_obj_isstringempty (ptr_app->original_path))
continue;
if (ptr_app->type == DATA_APP_REGULAR)
{
drive_id = PathGetDriveNumberW (ptr_app->original_path->buffer);
}
else
{
drive_id = INT_ERROR;
}
if (ptr_app->type == DATA_APP_DEVICE || (drive_id != INT_ERROR && drive_id == letter))
{
if (ptr_app->is_enabled || _app_isapphaverule (ptr_app->app_hash, FALSE))
{
_r_queuedlock_releaseshared (&lock_apps);
return TRUE;
}
}
}
_r_queuedlock_releaseshared (&lock_apps);
return FALSE;
}
BOOLEAN _app_isapphaverule (
_In_ ULONG_PTR app_hash,
_In_ BOOLEAN is_countdisabled
)
{
PITEM_RULE ptr_rule;
_r_queuedlock_acquireshared (&lock_rules);
for (ULONG_PTR i = 0; i < _r_obj_getlistsize (rules_list); i++)
{
ptr_rule = _r_obj_getlistitem (rules_list, i);
if (ptr_rule)
{
if (ptr_rule->type == DATA_RULE_USER && (is_countdisabled || ptr_rule->is_enabled))
{
if (_r_obj_findhashtable (ptr_rule->apps, app_hash))
{
_r_queuedlock_releaseshared (&lock_rules);
return TRUE;
}
}
}
}
_r_queuedlock_releaseshared (&lock_rules);
return FALSE;
}
BOOLEAN _app_isappexists (
_In_ PITEM_APP ptr_app
)
{
if (ptr_app->is_undeletable)
return TRUE;
if (ptr_app->is_enabled && ptr_app->is_haveerrors)
return FALSE;
switch (ptr_app->type)
{
case DATA_APP_REGULAR:
{
if (ptr_app->real_path && !_r_fs_exists (&ptr_app->real_path->sr))
return FALSE;
return TRUE;
}
case DATA_APP_DEVICE:
case DATA_APP_NETWORK:
case DATA_APP_SERVICE:
case DATA_APP_UWP:
case DATA_APP_PICO:
{
return TRUE; // service and UWP is already undeletable
}
}
return FALSE;
}
BOOLEAN _app_isappfound (
_In_ ULONG_PTR app_hash
)
{
BOOLEAN is_found;
_r_queuedlock_acquireshared (&lock_apps);
is_found = (_r_obj_findhashtable (apps_table, app_hash) != NULL);
_r_queuedlock_releaseshared (&lock_apps);
return is_found;
}
BOOLEAN _app_isappunused (
_In_ PITEM_APP ptr_app
)
{
if (ptr_app->is_undeletable)
return FALSE;
if (!_app_isappexists (ptr_app))
return TRUE;
if (!_app_isappused (ptr_app))
return TRUE;
return FALSE;
}
BOOLEAN _app_isappused (
_In_ PITEM_APP ptr_app
)
{
if (ptr_app->is_enabled || ptr_app->is_silent || ptr_app->is_undeletable)
return TRUE;
if (_app_isapphaverule (ptr_app->app_hash, TRUE))
return TRUE;
return FALSE;
}
BOOLEAN _app_issystemhash (
_In_ ULONG_PTR app_hash
)
{
return (app_hash == config.ntoskrnl_hash || app_hash == config.svchost_hash);
}
BOOLEAN _app_isrulesupportedbyos (
_In_ PR_STRINGREF os_version
)
{
static PR_STRING version_string = NULL;
PR_STRING current_version;
PR_STRING new_version;
current_version = _InterlockedCompareExchangePointer (&version_string, NULL, NULL);
if (!current_version)
{
new_version = _r_format_string (L"%d.%d", NtCurrentPeb ()->OSMajorVersion, NtCurrentPeb ()->OSMinorVersion);
current_version = _InterlockedCompareExchangePointer (&version_string, new_version, NULL);
if (!current_version)
{
current_version = new_version;
}
else
{
_r_obj_dereference (new_version);
}
}
return (_r_str_versioncompare (&current_version->sr, os_version) != INT_ERROR);
}
VOID _app_profile_initialize ()
{
R_STRINGREF profile_sr = PR_STRINGREF_INIT (XML_PROFILE_FILE);
R_STRINGREF profile_bak_sr = PR_STRINGREF_INIT (XML_PROFILE_FILE L".bak");
R_STRINGREF profile_internal_sr = PR_STRINGREF_INIT (XML_PROFILE_INTERNAL);
R_STRINGREF separator_sr = PR_STRINGREF_INIT (L"\\");
PR_STRING path;
path = _r_app_getprofiledirectory ();
_r_obj_movereference (&profile_info.profile_path, _r_obj_concatstringrefs (3, &path->sr, &separator_sr, &profile_sr));
_r_obj_movereference (&profile_info.profile_path_backup, _r_obj_concatstringrefs (3, &path->sr, &separator_sr, &profile_bak_sr));
_r_obj_movereference (&profile_info.profile_path_internal, _r_obj_concatstringrefs (3, &path->sr, &separator_sr, &profile_internal_sr));
}
NTSTATUS _app_profile_load_fromresource (
_In_ LPCWSTR resource_name,
_Out_ PDB_INFORMATION out_buffer
)
{
PDB_INFORMATION db_info;
R_STORAGE bytes;
NTSTATUS status;
db_info = out_buffer;
status = _app_db_initialize (db_info, TRUE);
if (NT_SUCCESS (status))
{
status = _r_res_loadresource (_r_sys_getimagebase (), RT_RCDATA, resource_name, 0, &bytes);
if (NT_SUCCESS (status))
status = _app_db_openfrombuffer (db_info, &bytes, XML_VERSION_MAXIMUM, XML_TYPE_PROFILE_INTERNAL);
}
return status;
}
VOID _app_profile_load_fallback ()
{
ULONG_PTR app_hash;
if (!_app_isappfound (config.my_hash))
{
app_hash = _app_addapplication (NULL, DATA_UNKNOWN, config.my_path, NULL, NULL);
if (app_hash)
_app_setappinfobyhash (app_hash, INFO_IS_ENABLED, IntToPtr (TRUE));
}
_app_setappinfobyhash (config.my_hash, INFO_IS_UNDELETABLE, IntToPtr (TRUE));
// disable deletion for this shit ;)
if (!_r_config_getboolean (L"IsInternalRulesDisabled", FALSE, NULL))
{
if (!_app_isappfound (config.ntoskrnl_hash) && !_r_obj_isstringempty (config.system_path))
_app_addapplication (NULL, DATA_UNKNOWN, config.system_path, NULL, NULL);
if (!_app_isappfound (config.svchost_hash) && !_r_obj_isstringempty (config.svchost_path))
_app_addapplication (NULL, DATA_UNKNOWN, config.svchost_path, NULL, NULL);
_app_setappinfobyhash (config.ntoskrnl_hash, INFO_IS_UNDELETABLE, IntToPtr (TRUE));
_app_setappinfobyhash (config.svchost_hash, INFO_IS_UNDELETABLE, IntToPtr (TRUE));
}
}
VOID _app_profile_load_internal (
_In_opt_ HWND hwnd,
_In_ PR_STRING path,
_In_ LPCWSTR resource_name,
_Out_ PLONG64 out_timestamp
)
{
DB_INFORMATION db_info_buffer;
DB_INFORMATION db_info_file;
PDB_INFORMATION db_info;
BOOLEAN is_loadfromresource;
LONG64 timestamp = 0;
NTSTATUS status_file;
NTSTATUS status_res;
NTSTATUS status;
status_file = _app_db_initialize (&db_info_file, TRUE);
if (_r_fs_exists (&path->sr))
{
if (NT_SUCCESS (status_file))
status_file = _app_db_openfromfile (&db_info_file, path, XML_VERSION_MAXIMUM, XML_TYPE_PROFILE_INTERNAL);
}
else
{
status_file = STATUS_OBJECT_PATH_NOT_FOUND;
}
status_res = _app_profile_load_fromresource (resource_name, &db_info_buffer);
// NOTE: prefer new profile version for 3.4+
if (!NT_SUCCESS (status_file))
{
is_loadfromresource = TRUE;
}
else
{
is_loadfromresource = (db_info_file.version < db_info_buffer.version) || (db_info_file.timestamp < db_info_buffer.timestamp);
}
db_info = is_loadfromresource ? &db_info_buffer : &db_info_file;
status = is_loadfromresource ? status_res : status_file;
if (NT_SUCCESS (status))
{
if (_app_db_parse (db_info, XML_TYPE_PROFILE_INTERNAL))
timestamp = db_info->timestamp;
}
else
{
if (status != STATUS_OBJECT_NAME_NOT_FOUND && status != STATUS_OBJECT_PATH_NOT_FOUND)
{
if (hwnd)
_r_show_errormessage (hwnd, L"Could not load internal profile!", status, NULL, ET_NATIVE);
_r_log (LOG_LEVEL_ERROR, NULL, L"_app_profile_load_internal", status, NULL);
}
}
*out_timestamp = timestamp;
_app_db_destroy (&db_info_buffer);
_app_db_destroy (&db_info_file);
}
VOID _app_profile_refresh (
_In_opt_ HWND hwnd
)
{
// clear apps
_r_queuedlock_acquireexclusive (&lock_apps);
_r_obj_clearhashtable (apps_table);
_r_queuedlock_releaseexclusive (&lock_apps);
// clear rules
_r_queuedlock_acquireexclusive (&lock_rules);
_r_obj_clearlist (rules_list);
_r_queuedlock_releaseexclusive (&lock_rules);
// clear rules config
_r_queuedlock_acquireexclusive (&lock_rules_config);
_r_obj_clearhashtable (rules_config);
_r_queuedlock_releaseexclusive (&lock_rules_config);
if (!hwnd)
hwnd = _r_app_gethwnd ();
// generate services list
_app_package_getserviceslist (hwnd);
// generate uwp packages list (win8+)
if (_r_sys_isosversiongreaterorequal (WINDOWS_8))
_app_package_getpackageslist (hwnd);
}
NTSTATUS _app_profile_load (
_In_opt_ HWND hwnd,
_In_opt_ PR_STRING path_custom
)
{
DB_INFORMATION db_info;
NTSTATUS status;
BOOLEAN is_update;
status = _app_db_initialize (&db_info, TRUE);
if (!NT_SUCCESS (status))
{
if (hwnd)
_r_show_errormessage (hwnd, L"Could not intitialize profile!", status, NULL, ET_WINDOWS);
_r_log (LOG_LEVEL_ERROR, NULL, L"_app_db_initialize", status, NULL);
goto CleanupExit;
}
if (path_custom)
{
status = _app_db_openfromfile (&db_info, path_custom, XML_VERSION_MINIMAL, XML_TYPE_PROFILE);
}
else
{
_r_queuedlock_acquireshared (&lock_profile);
status = _app_db_openfromfile (&db_info, profile_info.profile_path, XML_VERSION_MINIMAL, XML_TYPE_PROFILE);
if (!NT_SUCCESS (status))
status = _app_db_openfromfile (&db_info, profile_info.profile_path_backup, XML_VERSION_MINIMAL, XML_TYPE_PROFILE);
_r_queuedlock_releaseshared (&lock_profile);
}
CleanupExit:
is_update = (NT_SUCCESS (status) || !path_custom);
if (is_update)
{
if (hwnd)
_app_listview_clearitems (hwnd);
_app_profile_refresh (hwnd);
}
if (NT_SUCCESS (status))
{
_app_db_parse (&db_info, XML_TYPE_PROFILE);
}
else
{
if (status != STATUS_OBJECT_NAME_NOT_FOUND && status != STATUS_OBJECT_PATH_NOT_FOUND)
{
if (hwnd)
_r_show_errormessage (hwnd, L"Could not load profile!", status, NULL, ET_NATIVE);
_r_log (LOG_LEVEL_ERROR, NULL, L"_app_profile_load", status, NULL);
}
}
if (is_update)
{
// load internal rules (new!)
if (!_r_config_getboolean (L"IsInternalRulesDisabled", FALSE, NULL))
_app_profile_load_internal (hwnd, profile_info.profile_path_internal, MAKEINTRESOURCE (IDR_PROFILE_INTERNAL), &profile_info.profile_internal_timestamp);
_app_profile_load_fallback ();
if (hwnd)
_app_listview_additems (hwnd);
}
_app_db_destroy (&db_info);
return status;
}
NTSTATUS _app_profile_save (
_In_opt_ HWND hwnd
)
{
DB_INFORMATION db_info;
LONG64 timestamp;
NTSTATUS status;
BOOLEAN is_backuprequired = FALSE;
status = _app_db_initialize (&db_info, FALSE);
if (!NT_SUCCESS (status))
{
if (hwnd)
_r_show_errormessage (hwnd, L"Could not intitialize profile!", status, NULL, ET_WINDOWS);
_r_log (LOG_LEVEL_ERROR, NULL, L"_app_db_initialize", status, NULL);
return status;
}
timestamp = _r_unixtime_now ();
if (_r_config_getboolean (L"IsBackupProfile", TRUE, NULL))
{
if (!_r_fs_exists (&profile_info.profile_path_backup->sr))
is_backuprequired = TRUE;
if (!is_backuprequired)
{
if (timestamp - _r_config_getlong64 (L"BackupTimestamp", 0, NULL) >= _r_config_getlong64 (L"BackupPeriod", BACKUP_HOURS_PERIOD, NULL))
is_backuprequired = TRUE;
}
}
_r_queuedlock_acquireexclusive (&lock_profile);
status = _app_db_savetofile (&db_info, profile_info.profile_path, XML_VERSION_MAXIMUM, XML_TYPE_PROFILE, timestamp);
_r_queuedlock_releaseexclusive (&lock_profile);
if (!NT_SUCCESS (status))
{
if (hwnd)
_r_show_errormessage (hwnd, L"Could not save profile!", status, NULL, ET_NATIVE);
_r_log (LOG_LEVEL_ERROR, NULL, L"_app_db_savetofile", status, profile_info.profile_path->buffer);
}
_app_db_destroy (&db_info);
// make backup
if (is_backuprequired)
{
_r_fs_copyfile (&profile_info.profile_path->sr, &profile_info.profile_path_backup->sr, FALSE);
_r_config_setlong64 (L"BackupTimestamp", timestamp, NULL);
}
return status;
}