1 /* ------------------------------------------------------------------------- 2 * 3 * contrib/sepgsql/proc.c 4 * 5 * Routines corresponding to procedure 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_namespace.h" 20 #include "catalog/pg_proc.h" 21 #include "catalog/pg_type.h" 22 #include "commands/seclabel.h" 23 #include "lib/stringinfo.h" 24 #include "utils/builtins.h" 25 #include "utils/fmgroids.h" 26 #include "utils/lsyscache.h" 27 #include "utils/snapmgr.h" 28 #include "utils/syscache.h" 29 30 #include "sepgsql.h" 31 32 /* 33 * sepgsql_proc_post_create 34 * 35 * This routine assigns a default security label on a newly defined 36 * procedure. 37 */ 38 void 39 sepgsql_proc_post_create(Oid functionId) 40 { 41 Relation rel; 42 ScanKeyData skey; 43 SysScanDesc sscan; 44 HeapTuple tuple; 45 char *nsp_name; 46 char *scontext; 47 char *tcontext; 48 char *ncontext; 49 uint32 required; 50 int i; 51 StringInfoData audit_name; 52 ObjectAddress object; 53 Form_pg_proc proForm; 54 55 /* 56 * Fetch namespace of the new procedure. Because pg_proc entry is not 57 * visible right now, we need to scan the catalog using SnapshotSelf. 58 */ 59 rel = table_open(ProcedureRelationId, AccessShareLock); 60 61 ScanKeyInit(&skey, 62 Anum_pg_proc_oid, 63 BTEqualStrategyNumber, F_OIDEQ, 64 ObjectIdGetDatum(functionId)); 65 66 sscan = systable_beginscan(rel, ProcedureOidIndexId, true, 67 SnapshotSelf, 1, &skey); 68 69 tuple = systable_getnext(sscan); 70 if (!HeapTupleIsValid(tuple)) 71 elog(ERROR, "could not find tuple for function %u", functionId); 72 73 proForm = (Form_pg_proc) GETSTRUCT(tuple); 74 75 /* 76 * check db_schema:{add_name} permission of the namespace 77 */ 78 object.classId = NamespaceRelationId; 79 object.objectId = proForm->pronamespace; 80 object.objectSubId = 0; 81 sepgsql_avc_check_perms(&object, 82 SEPG_CLASS_DB_SCHEMA, 83 SEPG_DB_SCHEMA__ADD_NAME, 84 getObjectIdentity(&object), 85 true); 86 87 /* 88 * XXX - db_language:{implement} also should be checked here 89 */ 90 91 92 /* 93 * Compute a default security label when we create a new procedure object 94 * under the specified namespace. 95 */ 96 scontext = sepgsql_get_client_label(); 97 tcontext = sepgsql_get_label(NamespaceRelationId, 98 proForm->pronamespace, 0); 99 ncontext = sepgsql_compute_create(scontext, tcontext, 100 SEPG_CLASS_DB_PROCEDURE, 101 NameStr(proForm->proname)); 102 103 /* 104 * check db_procedure:{create (install)} permission 105 */ 106 initStringInfo(&audit_name); 107 nsp_name = get_namespace_name(proForm->pronamespace); 108 appendStringInfo(&audit_name, "%s(", 109 quote_qualified_identifier(nsp_name, NameStr(proForm->proname))); 110 for (i = 0; i < proForm->pronargs; i++) 111 { 112 if (i > 0) 113 appendStringInfoChar(&audit_name, ','); 114 115 object.classId = TypeRelationId; 116 object.objectId = proForm->proargtypes.values[i]; 117 object.objectSubId = 0; 118 appendStringInfoString(&audit_name, getObjectIdentity(&object)); 119 } 120 appendStringInfoChar(&audit_name, ')'); 121 122 required = SEPG_DB_PROCEDURE__CREATE; 123 if (proForm->proleakproof) 124 required |= SEPG_DB_PROCEDURE__INSTALL; 125 126 sepgsql_avc_check_perms_label(ncontext, 127 SEPG_CLASS_DB_PROCEDURE, 128 required, 129 audit_name.data, 130 true); 131 132 /* 133 * Assign the default security label on a new procedure 134 */ 135 object.classId = ProcedureRelationId; 136 object.objectId = functionId; 137 object.objectSubId = 0; 138 SetSecurityLabel(&object, SEPGSQL_LABEL_TAG, ncontext); 139 140 /* 141 * Cleanup 142 */ 143 systable_endscan(sscan); 144 table_close(rel, AccessShareLock); 145 146 pfree(audit_name.data); 147 pfree(tcontext); 148 pfree(ncontext); 149 } 150 151 /* 152 * sepgsql_proc_drop 153 * 154 * It checks privileges to drop the supplied function. 155 */ 156 void 157 sepgsql_proc_drop(Oid functionId) 158 { 159 ObjectAddress object; 160 char *audit_name; 161 162 /* 163 * check db_schema:{remove_name} permission 164 */ 165 object.classId = NamespaceRelationId; 166 object.objectId = get_func_namespace(functionId); 167 object.objectSubId = 0; 168 audit_name = getObjectIdentity(&object); 169 170 sepgsql_avc_check_perms(&object, 171 SEPG_CLASS_DB_SCHEMA, 172 SEPG_DB_SCHEMA__REMOVE_NAME, 173 audit_name, 174 true); 175 pfree(audit_name); 176 177 /* 178 * check db_procedure:{drop} permission 179 */ 180 object.classId = ProcedureRelationId; 181 object.objectId = functionId; 182 object.objectSubId = 0; 183 audit_name = getObjectIdentity(&object); 184 185 sepgsql_avc_check_perms(&object, 186 SEPG_CLASS_DB_PROCEDURE, 187 SEPG_DB_PROCEDURE__DROP, 188 audit_name, 189 true); 190 pfree(audit_name); 191 } 192 193 /* 194 * sepgsql_proc_relabel 195 * 196 * It checks privileges to relabel the supplied function 197 * by the `seclabel'. 198 */ 199 void 200 sepgsql_proc_relabel(Oid functionId, const char *seclabel) 201 { 202 ObjectAddress object; 203 char *audit_name; 204 205 object.classId = ProcedureRelationId; 206 object.objectId = functionId; 207 object.objectSubId = 0; 208 audit_name = getObjectIdentity(&object); 209 210 /* 211 * check db_procedure:{setattr relabelfrom} permission 212 */ 213 sepgsql_avc_check_perms(&object, 214 SEPG_CLASS_DB_PROCEDURE, 215 SEPG_DB_PROCEDURE__SETATTR | 216 SEPG_DB_PROCEDURE__RELABELFROM, 217 audit_name, 218 true); 219 220 /* 221 * check db_procedure:{relabelto} permission 222 */ 223 sepgsql_avc_check_perms_label(seclabel, 224 SEPG_CLASS_DB_PROCEDURE, 225 SEPG_DB_PROCEDURE__RELABELTO, 226 audit_name, 227 true); 228 pfree(audit_name); 229 } 230 231 /* 232 * sepgsql_proc_setattr 233 * 234 * It checks privileges to alter the supplied function. 235 */ 236 void 237 sepgsql_proc_setattr(Oid functionId) 238 { 239 Relation rel; 240 ScanKeyData skey; 241 SysScanDesc sscan; 242 HeapTuple oldtup; 243 HeapTuple newtup; 244 Form_pg_proc oldform; 245 Form_pg_proc newform; 246 uint32 required; 247 ObjectAddress object; 248 char *audit_name; 249 250 /* 251 * Fetch newer catalog 252 */ 253 rel = table_open(ProcedureRelationId, AccessShareLock); 254 255 ScanKeyInit(&skey, 256 Anum_pg_proc_oid, 257 BTEqualStrategyNumber, F_OIDEQ, 258 ObjectIdGetDatum(functionId)); 259 260 sscan = systable_beginscan(rel, ProcedureOidIndexId, true, 261 SnapshotSelf, 1, &skey); 262 newtup = systable_getnext(sscan); 263 if (!HeapTupleIsValid(newtup)) 264 elog(ERROR, "could not find tuple for function %u", functionId); 265 newform = (Form_pg_proc) GETSTRUCT(newtup); 266 267 /* 268 * Fetch older catalog 269 */ 270 oldtup = SearchSysCache1(PROCOID, ObjectIdGetDatum(functionId)); 271 if (!HeapTupleIsValid(oldtup)) 272 elog(ERROR, "cache lookup failed for function %u", functionId); 273 oldform = (Form_pg_proc) GETSTRUCT(oldtup); 274 275 /* 276 * Does this ALTER command takes operation to namespace? 277 */ 278 if (newform->pronamespace != oldform->pronamespace) 279 { 280 sepgsql_schema_remove_name(oldform->pronamespace); 281 sepgsql_schema_add_name(oldform->pronamespace); 282 } 283 if (strcmp(NameStr(newform->proname), NameStr(oldform->proname)) != 0) 284 sepgsql_schema_rename(oldform->pronamespace); 285 286 /* 287 * check db_procedure:{setattr (install)} permission 288 */ 289 required = SEPG_DB_PROCEDURE__SETATTR; 290 if (!oldform->proleakproof && newform->proleakproof) 291 required |= SEPG_DB_PROCEDURE__INSTALL; 292 293 object.classId = ProcedureRelationId; 294 object.objectId = functionId; 295 object.objectSubId = 0; 296 audit_name = getObjectIdentity(&object); 297 298 sepgsql_avc_check_perms(&object, 299 SEPG_CLASS_DB_PROCEDURE, 300 required, 301 audit_name, 302 true); 303 /* cleanups */ 304 pfree(audit_name); 305 306 ReleaseSysCache(oldtup); 307 systable_endscan(sscan); 308 table_close(rel, AccessShareLock); 309 } 310 311 /* 312 * sepgsql_proc_execute 313 * 314 * It checks privileges to execute the supplied function 315 */ 316 void 317 sepgsql_proc_execute(Oid functionId) 318 { 319 ObjectAddress object; 320 char *audit_name; 321 322 /* 323 * check db_procedure:{execute} permission 324 */ 325 object.classId = ProcedureRelationId; 326 object.objectId = functionId; 327 object.objectSubId = 0; 328 audit_name = getObjectIdentity(&object); 329 sepgsql_avc_check_perms(&object, 330 SEPG_CLASS_DB_PROCEDURE, 331 SEPG_DB_PROCEDURE__EXECUTE, 332 audit_name, 333 true); 334 pfree(audit_name); 335 } 336