1 /* ------------------------------------------------------------------------- 2 * 3 * contrib/sepgsql/schema.c 4 * 5 * Routines corresponding to schema objects 6 * 7 * Copyright (c) 2010-2019, PostgreSQL Global Development Group 8 * 9 * ------------------------------------------------------------------------- 10 */ 11 #include "postgres.h" 12 13 #include "access/genam.h" 14 #include "access/htup_details.h" 15 #include "access/sysattr.h" 16 #include "access/table.h" 17 #include "catalog/dependency.h" 18 #include "catalog/indexing.h" 19 #include "catalog/pg_database.h" 20 #include "catalog/pg_namespace.h" 21 #include "commands/seclabel.h" 22 #include "lib/stringinfo.h" 23 #include "miscadmin.h" 24 #include "utils/builtins.h" 25 #include "utils/fmgroids.h" 26 #include "utils/lsyscache.h" 27 #include "utils/snapmgr.h" 28 29 #include "sepgsql.h" 30 31 /* 32 * sepgsql_schema_post_create 33 * 34 * This routine assigns a default security label on a newly defined 35 * schema. 36 */ 37 void 38 sepgsql_schema_post_create(Oid namespaceId) 39 { 40 Relation rel; 41 ScanKeyData skey; 42 SysScanDesc sscan; 43 HeapTuple tuple; 44 char *tcontext; 45 char *ncontext; 46 const char *nsp_name; 47 ObjectAddress object; 48 Form_pg_namespace nspForm; 49 StringInfoData audit_name; 50 51 /* 52 * Compute a default security label when we create a new schema object 53 * under the working database. 54 * 55 * XXX - uncoming version of libselinux supports to take object name to 56 * handle special treatment on default security label; such as special 57 * label on "pg_temp" schema. 58 */ 59 rel = table_open(NamespaceRelationId, AccessShareLock); 60 61 ScanKeyInit(&skey, 62 Anum_pg_namespace_oid, 63 BTEqualStrategyNumber, F_OIDEQ, 64 ObjectIdGetDatum(namespaceId)); 65 66 sscan = systable_beginscan(rel, NamespaceOidIndexId, true, 67 SnapshotSelf, 1, &skey); 68 tuple = systable_getnext(sscan); 69 if (!HeapTupleIsValid(tuple)) 70 elog(ERROR, "could not find tuple for namespace %u", namespaceId); 71 72 nspForm = (Form_pg_namespace) GETSTRUCT(tuple); 73 nsp_name = NameStr(nspForm->nspname); 74 if (strncmp(nsp_name, "pg_temp_", 8) == 0) 75 nsp_name = "pg_temp"; 76 else if (strncmp(nsp_name, "pg_toast_temp_", 14) == 0) 77 nsp_name = "pg_toast_temp"; 78 79 tcontext = sepgsql_get_label(DatabaseRelationId, MyDatabaseId, 0); 80 ncontext = sepgsql_compute_create(sepgsql_get_client_label(), 81 tcontext, 82 SEPG_CLASS_DB_SCHEMA, 83 nsp_name); 84 85 /* 86 * check db_schema:{create} 87 */ 88 initStringInfo(&audit_name); 89 appendStringInfo(&audit_name, "%s", quote_identifier(nsp_name)); 90 sepgsql_avc_check_perms_label(ncontext, 91 SEPG_CLASS_DB_SCHEMA, 92 SEPG_DB_SCHEMA__CREATE, 93 audit_name.data, 94 true); 95 systable_endscan(sscan); 96 table_close(rel, AccessShareLock); 97 98 /* 99 * Assign the default security label on a new procedure 100 */ 101 object.classId = NamespaceRelationId; 102 object.objectId = namespaceId; 103 object.objectSubId = 0; 104 SetSecurityLabel(&object, SEPGSQL_LABEL_TAG, ncontext); 105 106 pfree(ncontext); 107 pfree(tcontext); 108 } 109 110 /* 111 * sepgsql_schema_drop 112 * 113 * It checks privileges to drop the supplied schema object. 114 */ 115 void 116 sepgsql_schema_drop(Oid namespaceId) 117 { 118 ObjectAddress object; 119 char *audit_name; 120 121 /* 122 * check db_schema:{drop} permission 123 */ 124 object.classId = NamespaceRelationId; 125 object.objectId = namespaceId; 126 object.objectSubId = 0; 127 audit_name = getObjectIdentity(&object); 128 129 sepgsql_avc_check_perms(&object, 130 SEPG_CLASS_DB_SCHEMA, 131 SEPG_DB_SCHEMA__DROP, 132 audit_name, 133 true); 134 pfree(audit_name); 135 } 136 137 /* 138 * sepgsql_schema_relabel 139 * 140 * It checks privileges to relabel the supplied schema 141 * by the `seclabel'. 142 */ 143 void 144 sepgsql_schema_relabel(Oid namespaceId, const char *seclabel) 145 { 146 ObjectAddress object; 147 char *audit_name; 148 149 object.classId = NamespaceRelationId; 150 object.objectId = namespaceId; 151 object.objectSubId = 0; 152 audit_name = getObjectIdentity(&object); 153 154 /* 155 * check db_schema:{setattr relabelfrom} permission 156 */ 157 sepgsql_avc_check_perms(&object, 158 SEPG_CLASS_DB_SCHEMA, 159 SEPG_DB_SCHEMA__SETATTR | 160 SEPG_DB_SCHEMA__RELABELFROM, 161 audit_name, 162 true); 163 164 /* 165 * check db_schema:{relabelto} permission 166 */ 167 sepgsql_avc_check_perms_label(seclabel, 168 SEPG_CLASS_DB_SCHEMA, 169 SEPG_DB_SCHEMA__RELABELTO, 170 audit_name, 171 true); 172 pfree(audit_name); 173 } 174 175 /* 176 * sepgsql_schema_check_perms 177 * 178 * utility routine to check db_schema:{xxx} permissions 179 */ 180 static bool 181 check_schema_perms(Oid namespaceId, uint32 required, bool abort_on_violation) 182 { 183 ObjectAddress object; 184 char *audit_name; 185 bool result; 186 187 object.classId = NamespaceRelationId; 188 object.objectId = namespaceId; 189 object.objectSubId = 0; 190 audit_name = getObjectIdentity(&object); 191 192 result = sepgsql_avc_check_perms(&object, 193 SEPG_CLASS_DB_SCHEMA, 194 required, 195 audit_name, 196 abort_on_violation); 197 pfree(audit_name); 198 199 return result; 200 } 201 202 /* db_schema:{setattr} permission */ 203 void 204 sepgsql_schema_setattr(Oid namespaceId) 205 { 206 check_schema_perms(namespaceId, SEPG_DB_SCHEMA__SETATTR, true); 207 } 208 209 /* db_schema:{search} permission */ 210 bool 211 sepgsql_schema_search(Oid namespaceId, bool abort_on_violation) 212 { 213 return check_schema_perms(namespaceId, 214 SEPG_DB_SCHEMA__SEARCH, 215 abort_on_violation); 216 } 217 218 void 219 sepgsql_schema_add_name(Oid namespaceId) 220 { 221 check_schema_perms(namespaceId, SEPG_DB_SCHEMA__ADD_NAME, true); 222 } 223 224 void 225 sepgsql_schema_remove_name(Oid namespaceId) 226 { 227 check_schema_perms(namespaceId, SEPG_DB_SCHEMA__REMOVE_NAME, true); 228 } 229 230 void 231 sepgsql_schema_rename(Oid namespaceId) 232 { 233 check_schema_perms(namespaceId, 234 SEPG_DB_SCHEMA__ADD_NAME | 235 SEPG_DB_SCHEMA__REMOVE_NAME, 236 true); 237 } 238