00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011 #include "postgres.h"
00012
00013 #include "catalog/dependency.h"
00014 #include "catalog/objectaccess.h"
00015 #include "catalog/pg_class.h"
00016 #include "catalog/pg_database.h"
00017 #include "catalog/pg_namespace.h"
00018 #include "catalog/pg_proc.h"
00019 #include "commands/seclabel.h"
00020 #include "executor/executor.h"
00021 #include "fmgr.h"
00022 #include "miscadmin.h"
00023 #include "tcop/utility.h"
00024 #include "utils/guc.h"
00025
00026 #include "sepgsql.h"
00027
00028 PG_MODULE_MAGIC;
00029
00030
00031
00032
00033 void _PG_init(void);
00034
00035
00036
00037
00038 static object_access_hook_type next_object_access_hook = NULL;
00039 static ExecutorCheckPerms_hook_type next_exec_check_perms_hook = NULL;
00040 static ProcessUtility_hook_type next_ProcessUtility_hook = NULL;
00041
00042
00043
00044
00045 typedef struct
00046 {
00047 NodeTag cmdtype;
00048
00049
00050
00051
00052
00053 const char *createdb_dtemplate;
00054 } sepgsql_context_info_t;
00055
00056 static sepgsql_context_info_t sepgsql_context_info;
00057
00058
00059
00060
00061 static bool sepgsql_permissive;
00062
00063 bool
00064 sepgsql_get_permissive(void)
00065 {
00066 return sepgsql_permissive;
00067 }
00068
00069
00070
00071
00072 static bool sepgsql_debug_audit;
00073
00074 bool
00075 sepgsql_get_debug_audit(void)
00076 {
00077 return sepgsql_debug_audit;
00078 }
00079
00080
00081
00082
00083
00084
00085
00086 static void
00087 sepgsql_object_access(ObjectAccessType access,
00088 Oid classId,
00089 Oid objectId,
00090 int subId,
00091 void *arg)
00092 {
00093 if (next_object_access_hook)
00094 (*next_object_access_hook) (access, classId, objectId, subId, arg);
00095
00096 switch (access)
00097 {
00098 case OAT_POST_CREATE:
00099 {
00100 ObjectAccessPostCreate *pc_arg = arg;
00101 bool is_internal;
00102
00103 is_internal = pc_arg ? pc_arg->is_internal : false;
00104
00105 switch (classId)
00106 {
00107 case DatabaseRelationId:
00108 Assert(!is_internal);
00109 sepgsql_database_post_create(objectId,
00110 sepgsql_context_info.createdb_dtemplate);
00111 break;
00112
00113 case NamespaceRelationId:
00114 Assert(!is_internal);
00115 sepgsql_schema_post_create(objectId);
00116 break;
00117
00118 case RelationRelationId:
00119 if (subId == 0)
00120 {
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130 if (is_internal)
00131 break;
00132
00133 sepgsql_relation_post_create(objectId);
00134 }
00135 else
00136 sepgsql_attribute_post_create(objectId, subId);
00137 break;
00138
00139 case ProcedureRelationId:
00140 Assert(!is_internal);
00141 sepgsql_proc_post_create(objectId);
00142 break;
00143
00144 default:
00145
00146 break;
00147 }
00148 }
00149 break;
00150
00151 case OAT_DROP:
00152 {
00153 ObjectAccessDrop *drop_arg = (ObjectAccessDrop *) arg;
00154
00155
00156
00157
00158
00159
00160 if ((drop_arg->dropflags & PERFORM_DELETION_INTERNAL) != 0)
00161 break;
00162
00163 switch (classId)
00164 {
00165 case DatabaseRelationId:
00166 sepgsql_database_drop(objectId);
00167 break;
00168
00169 case NamespaceRelationId:
00170 sepgsql_schema_drop(objectId);
00171 break;
00172
00173 case RelationRelationId:
00174 if (subId == 0)
00175 sepgsql_relation_drop(objectId);
00176 else
00177 sepgsql_attribute_drop(objectId, subId);
00178 break;
00179
00180 case ProcedureRelationId:
00181 sepgsql_proc_drop(objectId);
00182 break;
00183
00184 default:
00185
00186 break;
00187 }
00188 }
00189 break;
00190
00191 case OAT_POST_ALTER:
00192 {
00193 ObjectAccessPostAlter *pa_arg = arg;
00194 bool is_internal = pa_arg->is_internal;
00195
00196 switch (classId)
00197 {
00198 case DatabaseRelationId:
00199 Assert(!is_internal);
00200 sepgsql_database_setattr(objectId);
00201 break;
00202
00203 case NamespaceRelationId:
00204 Assert(!is_internal);
00205 sepgsql_schema_setattr(objectId);
00206 break;
00207
00208 case RelationRelationId:
00209 if (subId == 0)
00210 {
00211
00212
00213
00214
00215
00216
00217
00218 if (is_internal)
00219 break;
00220
00221 sepgsql_relation_setattr(objectId);
00222 }
00223 else
00224 sepgsql_attribute_setattr(objectId, subId);
00225 break;
00226
00227 case ProcedureRelationId:
00228 Assert(!is_internal);
00229 sepgsql_proc_setattr(objectId);
00230 break;
00231
00232 default:
00233
00234 break;
00235 }
00236 }
00237 break;
00238
00239 case OAT_NAMESPACE_SEARCH:
00240 {
00241 ObjectAccessNamespaceSearch *ns_arg = arg;
00242
00243
00244
00245
00246
00247 if (!ns_arg->result)
00248 break;
00249
00250 Assert(classId == NamespaceRelationId);
00251 Assert(ns_arg->result);
00252 ns_arg->result
00253 = sepgsql_schema_search(objectId,
00254 ns_arg->ereport_on_violation);
00255 }
00256 break;
00257
00258 case OAT_FUNCTION_EXECUTE:
00259 {
00260 Assert(classId == ProcedureRelationId);
00261 sepgsql_proc_execute(objectId);
00262 }
00263 break;
00264
00265 default:
00266 elog(ERROR, "unexpected object access type: %d", (int) access);
00267 break;
00268 }
00269 }
00270
00271
00272
00273
00274
00275
00276 static bool
00277 sepgsql_exec_check_perms(List *rangeTabls, bool abort)
00278 {
00279
00280
00281
00282
00283 if (next_exec_check_perms_hook &&
00284 !(*next_exec_check_perms_hook) (rangeTabls, abort))
00285 return false;
00286
00287 if (!sepgsql_dml_privileges(rangeTabls, abort))
00288 return false;
00289
00290 return true;
00291 }
00292
00293
00294
00295
00296
00297
00298
00299 static void
00300 sepgsql_utility_command(Node *parsetree,
00301 const char *queryString,
00302 ProcessUtilityContext context,
00303 ParamListInfo params,
00304 DestReceiver *dest,
00305 char *completionTag)
00306 {
00307 sepgsql_context_info_t saved_context_info = sepgsql_context_info;
00308 ListCell *cell;
00309
00310 PG_TRY();
00311 {
00312
00313
00314
00315
00316
00317 sepgsql_context_info.cmdtype = nodeTag(parsetree);
00318
00319 switch (nodeTag(parsetree))
00320 {
00321 case T_CreatedbStmt:
00322
00323
00324
00325
00326
00327 foreach(cell, ((CreatedbStmt *) parsetree)->options)
00328 {
00329 DefElem *defel = (DefElem *) lfirst(cell);
00330
00331 if (strcmp(defel->defname, "template") == 0)
00332 {
00333 sepgsql_context_info.createdb_dtemplate
00334 = strVal(defel->arg);
00335 break;
00336 }
00337 }
00338 break;
00339
00340 case T_LoadStmt:
00341
00342
00343
00344
00345
00346 if (sepgsql_getenforce())
00347 {
00348 ereport(ERROR,
00349 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
00350 errmsg("SELinux: LOAD is not permitted")));
00351 }
00352 break;
00353 default:
00354
00355
00356
00357
00358
00359
00360
00361 break;
00362 }
00363
00364 if (next_ProcessUtility_hook)
00365 (*next_ProcessUtility_hook) (parsetree, queryString,
00366 context, params,
00367 dest, completionTag);
00368 else
00369 standard_ProcessUtility(parsetree, queryString,
00370 context, params,
00371 dest, completionTag);
00372 }
00373 PG_CATCH();
00374 {
00375 sepgsql_context_info = saved_context_info;
00376 PG_RE_THROW();
00377 }
00378 PG_END_TRY();
00379 sepgsql_context_info = saved_context_info;
00380 }
00381
00382
00383
00384
00385 void
00386 _PG_init(void)
00387 {
00388
00389
00390
00391
00392 if (IsUnderPostmaster)
00393 ereport(ERROR,
00394 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
00395 errmsg("sepgsql must be loaded via shared_preload_libraries")));
00396
00397
00398
00399
00400
00401
00402 if (is_selinux_enabled() < 1)
00403 {
00404 sepgsql_set_mode(SEPGSQL_MODE_DISABLED);
00405 return;
00406 }
00407
00408
00409
00410
00411
00412
00413
00414 DefineCustomBoolVariable("sepgsql.permissive",
00415 "Turn on/off permissive mode in SE-PostgreSQL",
00416 NULL,
00417 &sepgsql_permissive,
00418 false,
00419 PGC_SIGHUP,
00420 GUC_NOT_IN_SAMPLE,
00421 NULL,
00422 NULL,
00423 NULL);
00424
00425
00426
00427
00428
00429
00430
00431
00432 DefineCustomBoolVariable("sepgsql.debug_audit",
00433 "Turn on/off debug audit messages",
00434 NULL,
00435 &sepgsql_debug_audit,
00436 false,
00437 PGC_USERSET,
00438 GUC_NOT_IN_SAMPLE,
00439 NULL,
00440 NULL,
00441 NULL);
00442
00443
00444 sepgsql_avc_init();
00445
00446
00447 sepgsql_init_client_label();
00448
00449
00450 register_label_provider(SEPGSQL_LABEL_TAG,
00451 sepgsql_object_relabel);
00452
00453
00454 next_object_access_hook = object_access_hook;
00455 object_access_hook = sepgsql_object_access;
00456
00457
00458 next_exec_check_perms_hook = ExecutorCheckPerms_hook;
00459 ExecutorCheckPerms_hook = sepgsql_exec_check_perms;
00460
00461
00462 next_ProcessUtility_hook = ProcessUtility_hook;
00463 ProcessUtility_hook = sepgsql_utility_command;
00464
00465
00466 memset(&sepgsql_context_info, 0, sizeof(sepgsql_context_info));
00467 }