589 lines
20 KiB
C++
589 lines
20 KiB
C++
/*
|
|
* Copyright (c) 2020 Huawei Technologies Co.,Ltd.
|
|
*
|
|
* openGauss is licensed under Mulan PSL v2.
|
|
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
|
* You may obtain a copy of Mulan PSL v2 at:
|
|
*
|
|
* http://license.coscl.org.cn/MulanPSL2
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
|
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
|
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
|
* See the Mulan PSL v2 for more details.
|
|
* ---------------------------------------------------------------------------------------
|
|
*
|
|
* gs_policy_utils.cpp
|
|
* Utility functions for dealing with auditing policy, like filters, label object.
|
|
*
|
|
*
|
|
* IDENTIFICATION
|
|
* src/gausskernel/securityg/gs_policy/gs_policy_util.cpp
|
|
*
|
|
* ---------------------------------------------------------------------------------------
|
|
*/
|
|
|
|
#include <sys/types.h>
|
|
#include <sys/socket.h>
|
|
#include <netdb.h>
|
|
#include <arpa/inet.h>
|
|
#include <ifaddrs.h>
|
|
#include <netinet/in.h>
|
|
#include "gs_policy/gs_policy_utils.h"
|
|
#include "gs_policy/policy_common.h"
|
|
#include "postgres.h"
|
|
#include "nodes/parsenodes.h"
|
|
#include "nodes/pg_list.h"
|
|
#include "utils/builtins.h"
|
|
#include "utils/timestamp.h"
|
|
#include "utils/fmgroids.h"
|
|
#include "utils/lsyscache.h"
|
|
#include "utils/syscache.h"
|
|
#include "utils/snapmgr.h"
|
|
#include "utils/acl.h"
|
|
#include "storage/lock/lock.h"
|
|
#include "access/xact.h"
|
|
#include "access/heapam.h"
|
|
#include "access/genam.h"
|
|
#include "access/sysattr.h"
|
|
#include "gs_policy/gs_vector.h"
|
|
#include "iprange/iprange.h"
|
|
#include "pgaudit.h"
|
|
#include "commands/dbcommands.h"
|
|
|
|
GsSaveManagementEvent gs_save_mng_event_hook = NULL;
|
|
GsSendManagementEvent gs_send_mng_event_hook = NULL;
|
|
|
|
void save_manage_message(const char* message)
|
|
{
|
|
if (gs_save_mng_event_hook != NULL) {
|
|
gs_save_mng_event_hook(message);
|
|
}
|
|
}
|
|
|
|
void send_manage_message(AuditResult result_type)
|
|
{
|
|
if (gs_send_mng_event_hook != NULL) {
|
|
gs_send_mng_event_hook(result_type);
|
|
}
|
|
}
|
|
|
|
bool GsPolicyStruct::operator == (const GsPolicyStruct &arg) const
|
|
{
|
|
return strcasecmp(m_name.c_str(), arg.m_name.c_str()) == 0;
|
|
}
|
|
|
|
bool GsPolicyStruct::operator < (const GsPolicyStruct &arg) const
|
|
{
|
|
/* compare by name */
|
|
return strcasecmp(m_name.c_str(), arg.m_name.c_str()) < 0;
|
|
}
|
|
|
|
int GsPolicyStruct::operator - (const GsPolicyStruct &arg) const
|
|
{
|
|
if (*this < arg) {
|
|
return -1;
|
|
} else if (arg < *this) {
|
|
return 1;
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
bool PgPolicyFiltersStruct::operator == (const PgPolicyFiltersStruct &arg) const
|
|
{
|
|
if (*this < arg) {
|
|
return false;
|
|
} else if (arg < *this) {
|
|
return false;
|
|
} else {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
bool PgPolicyFiltersStruct::operator < (const PgPolicyFiltersStruct &arg) const
|
|
{
|
|
int res = strcasecmp(m_type.c_str(), arg.m_type.c_str());
|
|
if (res < 0) {
|
|
return true;
|
|
}
|
|
if (res > 0) {
|
|
return false;
|
|
}
|
|
res = strcasecmp(m_label_name.c_str(), arg.m_label_name.c_str());
|
|
if (res < 0) {
|
|
return true;
|
|
}
|
|
if (res > 0) {
|
|
return false;
|
|
}
|
|
return m_policy_oid < arg.m_policy_oid;
|
|
}
|
|
|
|
int PgPolicyFiltersStruct::operator - (const PgPolicyFiltersStruct &arg) const
|
|
{
|
|
if (*this < arg) {
|
|
return -1;
|
|
} else if (arg < *this) {
|
|
return 1;
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
bool PgPolicyPrivilegesAccessStruct::operator == (const PgPolicyPrivilegesAccessStruct &arg) const
|
|
{
|
|
return (strcasecmp(m_type.c_str(), arg.m_type.c_str()) == 0) &&
|
|
(strcasecmp(m_label_name.c_str(), arg.m_label_name.c_str()) == 0);
|
|
}
|
|
|
|
bool PgPolicyPrivilegesAccessStruct::operator < (const PgPolicyPrivilegesAccessStruct &arg) const
|
|
{
|
|
int res = strcasecmp(m_type.c_str(), arg.m_type.c_str());
|
|
if (res < 0) {
|
|
return true;
|
|
}
|
|
if (res > 0) {
|
|
return false;
|
|
}
|
|
return strcasecmp(m_label_name.c_str(), arg.m_label_name.c_str()) < 0;
|
|
}
|
|
|
|
int PgPolicyPrivilegesAccessStruct::operator - (const PgPolicyPrivilegesAccessStruct &arg) const
|
|
{
|
|
if (*this < arg) {
|
|
return -1;
|
|
} else if (arg < *this) {
|
|
return 1;
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/* Process new filters from parser tree and tranform them into string */
|
|
bool process_new_filters(const List *policy_filters, gs_stl::gs_string *flat_tree)
|
|
{
|
|
if (!policy_filters)
|
|
return true;
|
|
flat_tree->clear();
|
|
ListCell *policy_filter_item = NULL;
|
|
gs_stl::gs_vector<PolicyFilterNode *> nodes;
|
|
|
|
foreach(policy_filter_item, policy_filters) {
|
|
PolicyFilterNode *root = (PolicyFilterNode *) lfirst(policy_filter_item);
|
|
nodes.push_back(root);
|
|
while (nodes.size() > 0) {
|
|
PolicyFilterNode* n = nodes.back();
|
|
nodes.pop_back();
|
|
/* operator type node */
|
|
if (!strcmp(n->node_type, "op")) {
|
|
if (!strcmp(n->op_value, "and")) {
|
|
(void)flat_tree->append("*");
|
|
} else if (!strcmp(n->op_value, "or")) {
|
|
(void)flat_tree->append("+");
|
|
} else { /* unsupported operator */
|
|
return false;
|
|
}
|
|
nodes.push_back((PolicyFilterNode *)n->right);
|
|
nodes.push_back((PolicyFilterNode *)n->left);
|
|
} else if (!strcmp(n->node_type, "filter")) { /* value type node */
|
|
if (n->has_not_operator == true) {
|
|
(void)flat_tree->append("!");
|
|
}
|
|
(void)flat_tree->append(n->filter_type);
|
|
(void)flat_tree->append("[");
|
|
List *filter_item_objects = (List *) n->values;
|
|
ListCell *filter_obj = NULL;
|
|
foreach(filter_obj, filter_item_objects) {
|
|
const char *filter_value = (const char *)(((Value*)lfirst(filter_obj))->val.str);
|
|
if (!verify_ip_role_app(n->filter_type, filter_value, flat_tree)) {
|
|
return false;
|
|
}
|
|
(void)flat_tree->append(",");
|
|
}
|
|
if (flat_tree->back() == ',') {
|
|
flat_tree->pop_back();
|
|
}
|
|
(void)flat_tree->append("]");
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool scan_to_delete_from_relation(long long row_id, Relation relation, unsigned int index_id)
|
|
{
|
|
if (relation == NULL) {
|
|
return false;
|
|
}
|
|
ScanKeyData skey;
|
|
/* Find the row to delete. */
|
|
ScanKeyInit(&skey,
|
|
ObjectIdAttributeNumber,
|
|
BTEqualStrategyNumber, F_OIDEQ,
|
|
ObjectIdGetDatum(row_id));
|
|
|
|
SysScanDesc tgscan = systable_beginscan(relation, index_id, true, SnapshotNow, 1, &skey);
|
|
|
|
HeapTuple tup = systable_getnext(tgscan);
|
|
if (!HeapTupleIsValid(tup)) {
|
|
systable_endscan(tgscan);
|
|
return false;
|
|
}
|
|
/* Delete the label tuple */
|
|
simple_heap_delete(relation, &tup->t_self);
|
|
|
|
systable_endscan(tgscan);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool remove_filters(const filters_set filters_to_remove, Relation relation, filters_set *existing_filters,
|
|
unsigned int index_id, gs_stl::gs_string *err_msg)
|
|
{
|
|
bool ret = false;
|
|
for (filters_set::const_iterator it = filters_to_remove.begin(); it != filters_to_remove.end(); ++it) {
|
|
/* first validate that this filter exists */
|
|
filters_set::const_iterator i_it = existing_filters->find(*it);
|
|
if (i_it != existing_filters->end()) {
|
|
if (!scan_to_delete_from_relation(i_it->m_id, relation, index_id)) {
|
|
*err_msg = "System error - failed to delete filter";
|
|
ret = false;
|
|
break;
|
|
}
|
|
(void)existing_filters->erase(i_it);
|
|
ret = true;
|
|
} else {
|
|
*err_msg = "No such filter can be found";
|
|
ret = false;
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
bool remove_filters(const filters_set filters_to_remove, unsigned int relation_id, unsigned int index_id,
|
|
gs_stl::gs_string *err_msg)
|
|
{
|
|
bool ret = false;
|
|
Relation relation = heap_open(relation_id, RowExclusiveLock);
|
|
if (relation) {
|
|
for (filters_set::const_iterator it = filters_to_remove.begin(); it != filters_to_remove.end(); ++it) {
|
|
if (!scan_to_delete_from_relation(it->m_id, relation, index_id)) {
|
|
*err_msg = "System error - failed to delete filter";
|
|
ret = false;
|
|
break;
|
|
}
|
|
ret = true;
|
|
}
|
|
heap_close(relation, RowExclusiveLock);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
void construct_resource_name(const RangeVar *rel, gs_stl::gs_string *target_name_s)
|
|
{
|
|
if (rel->catalogname) {
|
|
(void)target_name_s->append((const char *)rel->catalogname);
|
|
target_name_s->push_back('.');
|
|
}
|
|
if (rel->schemaname) {
|
|
(void)target_name_s->append((const char *)rel->schemaname);
|
|
target_name_s->push_back('.');
|
|
}
|
|
if (rel->relname) {
|
|
(void)target_name_s->append(rel->relname);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Check if current app is valid or not.
|
|
*/
|
|
bool verify_app_filter(const char* obj_value)
|
|
{
|
|
if (strlen(obj_value) == 0) {
|
|
ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("app: [%s] is invalid", obj_value)));
|
|
return false;
|
|
}
|
|
|
|
/* The first character id numbers or dollar */
|
|
char c = obj_value[0];
|
|
if ((c >= '0' && c <= '9') || c == '$') {
|
|
ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("app: [%s] is invalid", obj_value)));
|
|
return false;
|
|
}
|
|
|
|
int len = strlen(obj_value);
|
|
for (int i = 0; i < len; i++) {
|
|
c = obj_value[i];
|
|
if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_' || c == '$') {
|
|
continue;
|
|
} else {
|
|
ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("app: [%s] is invalid", obj_value)));
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Check the effective of the filter information.
|
|
* @ obj_type : filter type, which inlcudes IP, ROLES, and APPS.
|
|
* @ obj_value : the actual filter information.
|
|
* @ return_value : record about the filter information.
|
|
*/
|
|
bool verify_ip_role_app(const char* obj_type, const char* obj_value, gs_stl::gs_string *return_value)
|
|
{
|
|
if (!strcasecmp(obj_type, "ip")) {
|
|
const char* check_value = obj_value;
|
|
if (!IPRange::is_range_valid(check_value)) {
|
|
ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("ip range: [%s] is invalid, please identify", obj_value)));
|
|
return false;
|
|
}
|
|
(void)return_value->append(check_value);
|
|
return true;
|
|
} else if (!strcasecmp(obj_type, "roles")) {
|
|
Oid uid = get_role_oid(obj_value, true);
|
|
if (!OidIsValid(uid)) {
|
|
ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("role: [%s] is invalid", obj_value)));
|
|
return false;
|
|
}
|
|
char buffer[64]; /* buffer to store the oid int as string. 64 is the max length of oid. */
|
|
int nRet = snprintf_s(buffer, sizeof(buffer), sizeof(buffer) - 1, "%d", uid);
|
|
securec_check_ss(nRet, "\0", "\0");
|
|
(void)return_value->append(buffer);
|
|
return true;
|
|
} else if (!strcasecmp(obj_type, "app")) {
|
|
bool is_valid_app = verify_app_filter(obj_value);
|
|
if (!is_valid_app) {
|
|
return false;
|
|
}
|
|
}
|
|
(void)return_value->append(obj_value);
|
|
return true;
|
|
}
|
|
|
|
static bool add_privileges_access(const char *action_type, const char *label_name,
|
|
privileges_access_set *actions, const policy_labels_map *existing_labels, const GsPolicyStruct *policy,
|
|
gs_stl::gs_string *err_msg)
|
|
{
|
|
PgPolicyPrivilegesAccessStruct item;
|
|
item.m_type = action_type;
|
|
item.m_label_name = label_name;
|
|
item.m_policy_oid = policy->m_id;
|
|
/* validate that such label exists */
|
|
if (existing_labels->find(label_name) == existing_labels->end()) {
|
|
err_msg->clear();
|
|
(void)err_msg->append("Trying to add/remove privilege/access [");
|
|
(void)err_msg->append(action_type);
|
|
(void)err_msg->append("] to non-existing label [");
|
|
(void)err_msg->append(label_name);
|
|
(void)err_msg->append("]");
|
|
return false;
|
|
}
|
|
(void)actions->insert(item);
|
|
return true;
|
|
}
|
|
|
|
bool handle_target(ListCell *target,
|
|
int opt_type,
|
|
bool is_add,
|
|
gs_stl::gs_string *err_msg,
|
|
privileges_access_set *access_to_add, privileges_access_set *access_to_remove,
|
|
privileges_access_set *privs_to_add, privileges_access_set *privs_to_remove,
|
|
const policy_labels_map *existing_labels,
|
|
const GsPolicyStruct *policy, const char *acc_action_type)
|
|
{
|
|
bool ret = false;
|
|
switch (opt_type) {
|
|
case POLICY_OPT_PRIVILEGES: {
|
|
RangeVar *rel = (RangeVar*)lfirst(target);
|
|
gs_stl::gs_string target_name_s;
|
|
construct_resource_name((const RangeVar*)rel, &target_name_s);
|
|
if (is_add) {
|
|
ret = add_privileges_access(acc_action_type, target_name_s.c_str(), privs_to_add,
|
|
existing_labels, policy, err_msg);
|
|
} else {
|
|
ret = add_privileges_access(acc_action_type, target_name_s.c_str(), privs_to_remove, existing_labels,
|
|
policy, err_msg);
|
|
}
|
|
}
|
|
break;
|
|
case POLICY_OPT_ACCESS: {
|
|
RangeVar *rel = (RangeVar*)lfirst(target);
|
|
gs_stl::gs_string target_name_s;
|
|
construct_resource_name((const RangeVar*)rel, &target_name_s);
|
|
if (is_add) {
|
|
ret = add_privileges_access(acc_action_type, target_name_s.c_str(), access_to_add, existing_labels,
|
|
policy, err_msg);
|
|
} else {
|
|
ret = add_privileges_access(acc_action_type, target_name_s.c_str(), access_to_remove, existing_labels,
|
|
policy, err_msg);
|
|
}
|
|
}
|
|
break;
|
|
// : this is not handled here...
|
|
default:
|
|
break;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
static bool parse_values(const gs_stl::gs_string logical_expr_str, int *offset, const char* obj_type)
|
|
{
|
|
std::size_t found = gs_stl::gs_string::npos;
|
|
char buff[512] = {0};
|
|
size_t limit_pos = logical_expr_str.find(']', *offset);
|
|
gs_stl::gs_string tmp_res;
|
|
bool parsed = true;
|
|
bool filter_valid = false;
|
|
int nRet;
|
|
/* not finding last ']' means error */
|
|
if (limit_pos == gs_stl::gs_string::npos) {
|
|
ereport(ERROR,
|
|
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
|
|
errmsg("filter: [%s] is invalid", logical_expr_str.c_str())));
|
|
return false;
|
|
}
|
|
while ((found = logical_expr_str.find(',', *offset)) != gs_stl::gs_string::npos && found < limit_pos) {
|
|
nRet = snprintf_s(buff, sizeof(buff), sizeof(buff) - 1, "%.*s", (int)(found - *offset),
|
|
logical_expr_str.c_str() + *offset);
|
|
securec_check_ss(nRet, "\0", "\0");
|
|
filter_valid = verify_ip_role_app(obj_type, buff, &tmp_res);
|
|
parsed = parsed && filter_valid;
|
|
*offset = found + 1;
|
|
}
|
|
|
|
if (*offset < (int)limit_pos) {
|
|
nRet = snprintf_s(buff, sizeof(buff), sizeof(buff) - 1, "%.*s", (int)(limit_pos - *offset),
|
|
logical_expr_str.c_str() + *offset);
|
|
securec_check_ss(nRet, "\0", "\0");
|
|
filter_valid = verify_ip_role_app(obj_type, buff, &tmp_res);
|
|
parsed = parsed && filter_valid;
|
|
*offset = limit_pos + 1;
|
|
return parsed;
|
|
}
|
|
/* getting here means error */
|
|
ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("filter: [%s] is invalid", logical_expr_str.c_str())));
|
|
return false;
|
|
}
|
|
|
|
/* Parses & validates (recursively) polish-notation format string into logical tree */
|
|
bool validate_logical_expression(const gs_stl::gs_string logical_expr_str, int *offset)
|
|
{
|
|
int logical_expr_len = logical_expr_str.size();
|
|
|
|
while (*offset < logical_expr_len) {
|
|
/* AND/OR node */
|
|
if ((logical_expr_str[*offset] == '*') || (logical_expr_str[*offset] == '+')) {
|
|
(*offset)++;
|
|
return (validate_logical_expression(logical_expr_str, offset) /* go left */
|
|
&& validate_logical_expression(logical_expr_str, offset)); /* go right */
|
|
} else if (logical_expr_str[*offset] == '!') { /* NOT operator */
|
|
(*offset)++;
|
|
} else if (logical_expr_str[*offset] == 'i') { /* IP filter node */
|
|
*offset += 3; /* 3 : skip 'ip[' */
|
|
return parse_values(logical_expr_str, offset, "ip");
|
|
} else if (logical_expr_str[*offset] == 'r') { /* ROLE filter node */
|
|
*offset += 6; /* 6 : skip 'roles[' */
|
|
return parse_values(logical_expr_str, offset, "roles");
|
|
} else if (logical_expr_str[*offset] == 'a') { /* APPLICATION filter node */
|
|
*offset += 4; /* 4 : skip 'app[' */
|
|
return parse_values(logical_expr_str, offset, "app");
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool get_ip_address(gs_stl::gs_string *ipaddress)
|
|
{
|
|
struct ifaddrs *if_addr_struct = NULL;
|
|
struct ifaddrs *ifa = NULL;
|
|
void *tmp_addr_ptr = NULL;
|
|
|
|
if (getifaddrs(&if_addr_struct) != 0) {
|
|
return false;
|
|
}
|
|
|
|
for (ifa = if_addr_struct; ifa != NULL; ifa = ifa->ifa_next) {
|
|
if (ifa->ifa_addr == NULL || ifa->ifa_addr->sa_family != AF_INET) {
|
|
continue;
|
|
}
|
|
|
|
/* is a valid IP4 Address */
|
|
tmp_addr_ptr = &((struct sockaddr_in *)ifa->ifa_addr)->sin_addr;
|
|
|
|
char buff[128] = { 0 }; /* 128 is the max length of ipaddress */
|
|
(void)inet_ntop(AF_INET, tmp_addr_ptr, buff, sizeof(buff));
|
|
if (!strncasecmp(buff, "127.0.0", strlen("127.0.0"))) {
|
|
continue;
|
|
}
|
|
*ipaddress = buff;
|
|
}
|
|
if (if_addr_struct != NULL) {
|
|
freeifaddrs(if_addr_struct);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void get_session_ip(char *session_ip, int len)
|
|
{
|
|
if (len < MAX_IP_LEN) {
|
|
ereport(ERROR,
|
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("length of session ip buffer should more than 128")));
|
|
}
|
|
struct sockaddr* remote_addr = (struct sockaddr *)&u_sess->proc_cxt.MyProcPort->raddr.addr;
|
|
errno_t rc = EOK;
|
|
/* parse the remote ip address */
|
|
if (AF_UNIX == remote_addr->sa_family) {
|
|
char *localstr = "local";
|
|
rc = memcpy_s(session_ip, len, localstr, strlen(localstr));
|
|
securec_check(rc, "\0", "\0");
|
|
} else {
|
|
get_client_ip(remote_addr, session_ip);
|
|
}
|
|
}
|
|
|
|
void get_client_ip(const struct sockaddr* remote_addr, char *ip_str)
|
|
{
|
|
/* parse the remote ip address */
|
|
if (AF_INET6 == remote_addr->sa_family) {
|
|
(void)inet_ntop(AF_INET6, &((struct sockaddr_in6*)remote_addr)->sin6_addr, ip_str, MAX_IP_LEN - 1);
|
|
} else if (AF_INET == remote_addr->sa_family) {
|
|
(void)inet_ntop(AF_INET, &((struct sockaddr_in*)remote_addr)->sin_addr, ip_str, MAX_IP_LEN - 1);
|
|
}
|
|
}
|
|
|
|
bool is_database_valid(const char* dbname)
|
|
{
|
|
if (dbname == NULL) {
|
|
return false;
|
|
}
|
|
Oid db_oid = get_database_oid(dbname, false);
|
|
if (OidIsValid(db_oid)) {
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
ResourceOwnerData* create_temp_resourceowner()
|
|
{
|
|
ResourceOwner tmpOwner = ResourceOwnerCreate(t_thrd.utils_cxt.CurrentResourceOwner,
|
|
"CheckUserOid", MEMORY_CONTEXT_SECURITY);
|
|
ResourceOwner currentOwner = t_thrd.utils_cxt.CurrentResourceOwner;
|
|
t_thrd.utils_cxt.CurrentResourceOwner = tmpOwner;
|
|
return currentOwner;
|
|
}
|
|
|
|
void release_temp_resourceowner(ResourceOwnerData* resource_owner)
|
|
{
|
|
ResourceOwner tmpOwner = t_thrd.utils_cxt.CurrentResourceOwner;
|
|
ResourceOwnerRelease(tmpOwner, RESOURCE_RELEASE_BEFORE_LOCKS, true, true);
|
|
ResourceOwnerRelease(tmpOwner, RESOURCE_RELEASE_LOCKS, true, true);
|
|
ResourceOwnerRelease(tmpOwner, RESOURCE_RELEASE_AFTER_LOCKS, true, true);
|
|
t_thrd.utils_cxt.CurrentResourceOwner = resource_owner;
|
|
ResourceOwnerDelete(tmpOwner);
|
|
}
|