1 /* -------------------------------------------------------------------------
3 * contrib/sepgsql/hooks.c
5 * Entrypoints of the hooks in PostgreSQL, and dispatches the callbacks.
7 * Copyright (c) 2010-2019, PostgreSQL Global Development Group
9 * -------------------------------------------------------------------------
13 #include "catalog/dependency.h"
14 #include "catalog/objectaccess.h"
15 #include "catalog/pg_class.h"
16 #include "catalog/pg_database.h"
17 #include "catalog/pg_namespace.h"
18 #include "catalog/pg_proc.h"
19 #include "commands/seclabel.h"
20 #include "executor/executor.h"
22 #include "miscadmin.h"
24 #include "tcop/utility.h"
25 #include "utils/guc.h"
26 #include "utils/queryenvironment.h"
36 * Saved hook entries (if stacked)
38 static object_access_hook_type next_object_access_hook = NULL;
39 static ExecutorCheckPerms_hook_type next_exec_check_perms_hook = NULL;
40 static ProcessUtility_hook_type next_ProcessUtility_hook = NULL;
43 * Contextual information on DDL commands
50 * Name of the template database given by users on CREATE DATABASE
51 * command. Elsewhere (including the case of default) NULL.
53 const char *createdb_dtemplate;
54 } sepgsql_context_info_t;
56 static sepgsql_context_info_t sepgsql_context_info;
59 * GUC: sepgsql.permissive = (on|off)
61 static bool sepgsql_permissive;
64 sepgsql_get_permissive(void)
66 return sepgsql_permissive;
70 * GUC: sepgsql.debug_audit = (on|off)
72 static bool sepgsql_debug_audit;
75 sepgsql_get_debug_audit(void)
77 return sepgsql_debug_audit;
81 * sepgsql_object_access
83 * Entrypoint of the object_access_hook. This routine performs as
84 * a dispatcher of invocation based on access type and object classes.
87 sepgsql_object_access(ObjectAccessType access,
93 if (next_object_access_hook)
94 (*next_object_access_hook) (access, classId, objectId, subId, arg);
100 ObjectAccessPostCreate *pc_arg = arg;
103 is_internal = pc_arg ? pc_arg->is_internal : false;
107 case DatabaseRelationId:
108 Assert(!is_internal);
109 sepgsql_database_post_create(objectId,
110 sepgsql_context_info.createdb_dtemplate);
113 case NamespaceRelationId:
114 Assert(!is_internal);
115 sepgsql_schema_post_create(objectId);
118 case RelationRelationId:
122 * The cases in which we want to apply permission
123 * checks on creation of a new relation correspond
124 * to direct user invocation. For internal uses,
125 * that is creation of toast tables, index rebuild
126 * or ALTER TABLE commands, we need neither
127 * assignment of security labels nor permission
133 sepgsql_relation_post_create(objectId);
136 sepgsql_attribute_post_create(objectId, subId);
139 case ProcedureRelationId:
140 Assert(!is_internal);
141 sepgsql_proc_post_create(objectId);
145 /* Ignore unsupported object classes */
153 ObjectAccessDrop *drop_arg = (ObjectAccessDrop *) arg;
156 * No need to apply permission checks on object deletion due
157 * to internal cleanups; such as removal of temporary database
158 * object on session closed.
160 if ((drop_arg->dropflags & PERFORM_DELETION_INTERNAL) != 0)
165 case DatabaseRelationId:
166 sepgsql_database_drop(objectId);
169 case NamespaceRelationId:
170 sepgsql_schema_drop(objectId);
173 case RelationRelationId:
175 sepgsql_relation_drop(objectId);
177 sepgsql_attribute_drop(objectId, subId);
180 case ProcedureRelationId:
181 sepgsql_proc_drop(objectId);
185 /* Ignore unsupported object classes */
193 ObjectAccessPostAlter *pa_arg = arg;
194 bool is_internal = pa_arg->is_internal;
198 case DatabaseRelationId:
199 Assert(!is_internal);
200 sepgsql_database_setattr(objectId);
203 case NamespaceRelationId:
204 Assert(!is_internal);
205 sepgsql_schema_setattr(objectId);
208 case RelationRelationId:
212 * A case when we don't want to apply permission
213 * check is that relation is internally altered
214 * without user's intention. E.g, no need to check
215 * on toast table/index to be renamed at end of
216 * the table rewrites.
221 sepgsql_relation_setattr(objectId);
224 sepgsql_attribute_setattr(objectId, subId);
227 case ProcedureRelationId:
228 Assert(!is_internal);
229 sepgsql_proc_setattr(objectId);
233 /* Ignore unsupported object classes */
239 case OAT_NAMESPACE_SEARCH:
241 ObjectAccessNamespaceSearch *ns_arg = arg;
244 * If stacked extension already decided not to allow users to
245 * search this schema, we just stick with that decision.
250 Assert(classId == NamespaceRelationId);
251 Assert(ns_arg->result);
253 = sepgsql_schema_search(objectId,
254 ns_arg->ereport_on_violation);
258 case OAT_FUNCTION_EXECUTE:
260 Assert(classId == ProcedureRelationId);
261 sepgsql_proc_execute(objectId);
266 elog(ERROR, "unexpected object access type: %d", (int) access);
272 * sepgsql_exec_check_perms
274 * Entrypoint of DML permissions
277 sepgsql_exec_check_perms(List *rangeTabls, bool abort)
280 * If security provider is stacking and one of them replied 'false' at
281 * least, we don't need to check any more.
283 if (next_exec_check_perms_hook &&
284 !(*next_exec_check_perms_hook) (rangeTabls, abort))
287 if (!sepgsql_dml_privileges(rangeTabls, abort))
294 * sepgsql_utility_command
296 * It tries to rough-grained control on utility commands; some of them can
297 * break whole of the things if nefarious user would use.
300 sepgsql_utility_command(PlannedStmt *pstmt,
301 const char *queryString,
302 ProcessUtilityContext context,
303 ParamListInfo params,
304 QueryEnvironment *queryEnv,
308 Node *parsetree = pstmt->utilityStmt;
309 sepgsql_context_info_t saved_context_info = sepgsql_context_info;
315 * Check command tag to avoid nefarious operations, and save the
316 * current contextual information to determine whether we should apply
317 * permission checks here, or not.
319 sepgsql_context_info.cmdtype = nodeTag(parsetree);
321 switch (nodeTag(parsetree))
326 * We hope to reference name of the source database, but it
327 * does not appear in system catalog. So, we save it here.
329 foreach(cell, ((CreatedbStmt *) parsetree)->options)
331 DefElem *defel = (DefElem *) lfirst(cell);
333 if (strcmp(defel->defname, "template") == 0)
335 sepgsql_context_info.createdb_dtemplate
336 = strVal(defel->arg);
345 * We reject LOAD command across the board on enforcing mode,
346 * because a binary module can arbitrarily override hooks.
348 if (sepgsql_getenforce())
351 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
352 errmsg("SELinux: LOAD is not permitted")));
358 * Right now we don't check any other utility commands,
359 * because it needs more detailed information to make access
360 * control decision here, but we don't want to have two parse
361 * and analyze routines individually.
366 if (next_ProcessUtility_hook)
367 (*next_ProcessUtility_hook) (pstmt, queryString,
368 context, params, queryEnv,
369 dest, completionTag);
371 standard_ProcessUtility(pstmt, queryString,
372 context, params, queryEnv,
373 dest, completionTag);
377 sepgsql_context_info = saved_context_info;
381 sepgsql_context_info = saved_context_info;
385 * Module load/unload callback
391 * We allow to load the SE-PostgreSQL module on single-user-mode or
392 * shared_preload_libraries settings only.
394 if (IsUnderPostmaster)
396 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
397 errmsg("sepgsql must be loaded via shared_preload_libraries")));
400 * Check availability of SELinux on the platform. If disabled, we cannot
401 * activate any SE-PostgreSQL features, and we have to skip rest of
404 if (is_selinux_enabled() < 1)
406 sepgsql_set_mode(SEPGSQL_MODE_DISABLED);
411 * sepgsql.permissive = (on|off)
413 * This variable controls performing mode of SE-PostgreSQL on user's
416 DefineCustomBoolVariable("sepgsql.permissive",
417 "Turn on/off permissive mode in SE-PostgreSQL",
428 * sepgsql.debug_audit = (on|off)
430 * This variable allows users to turn on/off audit logs on access control
431 * decisions, independent from auditallow/auditdeny setting in the
432 * security policy. We intend to use this option for debugging purpose.
434 DefineCustomBoolVariable("sepgsql.debug_audit",
435 "Turn on/off debug audit messages",
437 &sepgsql_debug_audit,
445 /* Initialize userspace access vector cache */
448 /* Initialize security label of the client and related stuff */
449 sepgsql_init_client_label();
451 /* Security label provider hook */
452 register_label_provider(SEPGSQL_LABEL_TAG,
453 sepgsql_object_relabel);
455 /* Object access hook */
456 next_object_access_hook = object_access_hook;
457 object_access_hook = sepgsql_object_access;
459 /* DML permission check */
460 next_exec_check_perms_hook = ExecutorCheckPerms_hook;
461 ExecutorCheckPerms_hook = sepgsql_exec_check_perms;
463 /* ProcessUtility hook */
464 next_ProcessUtility_hook = ProcessUtility_hook;
465 ProcessUtility_hook = sepgsql_utility_command;
467 /* init contextual info */
468 memset(&sepgsql_context_info, 0, sizeof(sepgsql_context_info));