1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125
|
--Copyright 2000 mag@lme.linux.hu under the GPL
--This implements mandatory access control in a postgresql database;
--You should insert language PL/pgTCL in the database first:
--
--CREATE FUNCTION "pltcl_call_handler" ( ) RETURNS opaque AS '/usr/lib/postgresql/lib/pltcl.so' LANGUAGE 'C';
--CREATE TRUSTED PROCEDURAL LANGUAGE 'pltcl' HANDLER "pltcl_call_handler" LANCOMPILER 'PL/pgTCL';
--teszt=> select usename,usesysid from pg_user;
--usename |usesysid
----------+--------
--postgres| 31
--mag | 32
--teszt | 33
--thedba | 34
--teszt3 | 35
--(5 rows)
--Everything which should be in pg_user
drop table user_labels;
create table user_labels (usesysid int4, hsl int, nhc name[],mac_read bool);
create unique index user_labels_ui on user_labels(usesysid);
insert into user_labels values (32,2,'{ilyen,olyan}','f');
insert into user_labels values (33,2,'{ilyen}','f');
insert into user_labels values (34,2,'{ilyen}','t');
insert into user_labels values (35,2,'{olyan}','f');
--The example table: the labels and one data field
drop table data;
create table data (hsl int, nhc name[], data text);
insert into data values (3,'{ilyen}', 'ez ilyen s harom');
insert into data values (3,'{olyan,amolyan}', 'ez olyan, amolyan s harom');
insert into data values (2,'{olyan}', 'ez olyan s ketto');
insert into data values (2,'{ilyen}', 'ez ilyen s ketto');
insert into data values (2,'{olyan}', 'ez olyan s ketto');
insert into data values (3,'{olyan}', 'ez olyan s harom');
insert into data values (3,'{olyan,ilyen}', 'ez ilyen,olyan s harom');
insert into data values (2,'{olyan,ilyen}', 'ez ilyen,olyan s ketto');
create table data (hsl int, nhc name[], data text);
--drop function my_in_array(_name,name);
--create function my_in_array(_name,name) returns text as '
-- set o [split $1 "}{," ]
-- set s "\\"$2\\""
-- set had [lsearch $o $s]
-- return "$s $o $had"
--' language 'pltcl';
-- Checking non-hierarchical categories: objects nhc and subjects nhc
drop function my_nhc_check(_name,_name);
create function my_nhc_check(_name,_name) returns bool as '
set o [split $2 "}{," ]
set s [split $1 "}{," ]
set ss [lrange $s 1 [expr [llength $s] - 2]]
set had 1
foreach h $ss {
set had "[expr ([lsearch $o $h] != -1) && $had]"
}
return "$had"
' language 'pltcl';
--select a.nhc as subject, b.nhc as object,my_nhc_check(a.nhc,b.nhc),b.data from user_labels a, data b;
--we have an operator for this, as well
drop operator ~ (_name,_name);
create operator ~ (LEFTARG=_name,RIGHTARG=_name,PROCEDURE=my_nhc_check);
vacuum;
--mac_check for selects. Does not look at mac-read capability yet.
create function mac_check(int,_name) returns bool as '
select 1::bool
where
$1 <=(select hsl from user_labels u
where pg_get_userbyid(u.usesysid)=getpgusername())
and $2 ~ (select nhc from user_labels s
where pg_get_userbyid(s.usesysid)=getpgusername())
' language 'SQL';
--In postgresql we have very little space to play with rewrite rules.
--But it is enough for our goals.
drop rule "_RETdata";
create rule "_RETdata" as on select to data do instead select OLD.hsl,OLD.nhc,OLD.data where mac_check(OLD.hsl,OLD.nhc);
--This is the trigger procedure for insert,update,and delete
drop function mac_trigger();
create function mac_trigger() returns opaque as '
DECLARE
myhsl int;
mynhc _name;
BEGIN
select hsl into myhsl from user_labels u where pg_get_userbyid(u.usesysid)=getpgusername();
select nhc into mynhc from user_labels u where pg_get_userbyid(u.usesysid)=getpgusername();
if TG_OP = ''INSERT'' then
if NEW.nhc ~ mynhc and NEW.hsl >= myhsl then
return NEW;
end if;
return NULL;
end if;
if TG_OP = ''UPDATE'' then
if OLD.nhc ~ mynhc and OLD.hsl <= myhsl and
NEW.nhc ~ mynhc and NEW.hsl >= myhsl then
return NEW;
end if;
return NULL;
end if;
if TG_OP = ''DELETE'' then
if OLD.nhc ~ mynhc and OLD.hsl <= myhsl then
return OLD;
end if;
return NULL;
end if;
return NULL;
END;
' language 'plpgsql';
--And here we implement it on our example data
drop trigger data_mac on data;
CREATE TRIGGER data_mac
BEFORE INSERT OR UPDATE OR DELETE ON data FOR EACH ROW
EXECUTE PROCEDURE mac_trigger();
--Here should come the functional check.
insert into data values (1,'{ilyen}','Az j ilyen');
delete from data where hsl=4 and nhc='{ilyen}' and data='Az \xfaj ilyen';
|