awa_unit_2.4.0_59135a52/ada-security/src/security-permissions.adb

  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
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
-----------------------------------------------------------------------
--  security-permissions -- Definition of permissions
--  Copyright (C) 2010, 2011, 2016, 2017, 2018 Stephane Carrez
--  Written by Stephane Carrez (Stephane.Carrez@gmail.com)
--
--  Licensed under the Apache License, Version 2.0 (the "License");
--  you may not use this file except in compliance with the License.
--  You may obtain a copy of the License at
--
--      http://www.apache.org/licenses/LICENSE-2.0
--
--  Unless required by applicable law or agreed to in writing, software
--  distributed under the License is distributed on an "AS IS" BASIS,
--  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
--  See the License for the specific language governing permissions and
--  limitations under the License.
-----------------------------------------------------------------------

with Ada.Containers.Indefinite_Hashed_Maps;
with Ada.Strings.Hash;

with Util.Strings.Tokenizers;
with Util.Log.Loggers;

--  The <b>Security.Permissions</b> package defines the different permissions that can be
--  checked by the access control manager.
package body Security.Permissions is

   function Occurrence (List : in String; Of_Char : in Character) return Natural;

   --  The logger
   Log : constant Util.Log.Loggers.Logger := Util.Log.Loggers.Create ("Security.Permissions");

   --  A global map to translate a string to a permission index.
   package Permission_Maps is
     new Ada.Containers.Indefinite_Hashed_Maps (Key_Type        => String,
                                                Element_Type    => Permission_Index,
                                                Hash            => Ada.Strings.Hash,
                                                Equivalent_Keys => "=",
                                                "="             => "=");

   protected type Global_Index is
      --  Get the permission index
      function Get_Permission_Index (Name : in String) return Permission_Index;

      --  Get the last permission index registered in the global permission map.
      function Get_Last_Permission_Index return Permission_Index;

      --  Get the permission name associated with the index.
      function Get_Name (Index : in Permission_Index) return String;

      procedure Add_Permission (Name  : in String;
                                Index : out Permission_Index);
   private
      Map        : Permission_Maps.Map;
      Next_Index : Permission_Index := NONE + 1;
   end Global_Index;

   protected body Global_Index is
      function Get_Permission_Index (Name : in String) return Permission_Index is
         Pos : constant Permission_Maps.Cursor := Map.Find (Name);
      begin
         if Permission_Maps.Has_Element (Pos) then
            return Permission_Maps.Element (Pos);
         else
            raise Invalid_Name with "There is no permission '" & Name & "'";
         end if;
      end Get_Permission_Index;

      --  ------------------------------
      --  Get the last permission index registered in the global permission map.
      --  ------------------------------
      function Get_Last_Permission_Index return Permission_Index is
      begin
         return Next_Index - 1;
      end Get_Last_Permission_Index;

      procedure Add_Permission (Name  : in String;
                                Index : out Permission_Index) is
         Pos : constant Permission_Maps.Cursor := Map.Find (Name);
      begin
         if Permission_Maps.Has_Element (Pos) then
            Index := Permission_Maps.Element (Pos);
         else
            Index := Next_Index;
            Log.Debug ("Creating permission index {1} for {0}",
                       Name, Permission_Index'Image (Index));
            Map.Insert (Name, Index);
            if Next_Index = Permission_Index'Last then
               Log.Error ("Too many permission instantiated. "
                          & "Increase Security.Permissions.MAX_PERMISSION");
            else
               Next_Index := Next_Index + 1;
            end if;
         end if;
      end Add_Permission;

      --  ------------------------------
      --  Get the permission name associated with the index.
      --  ------------------------------
      function Get_Name (Index : in Permission_Index) return String is
         Iter : Permission_Maps.Cursor := Map.First;
      begin
         while Permission_Maps.Has_Element (Iter) loop
            if Permission_Maps.Element (Iter) = Index then
               return Permission_Maps.Key (Iter);
            end if;
            Permission_Maps.Next (Iter);
         end loop;
         return "";
      end Get_Name;

   end Global_Index;

   Permission_Indexes : Global_Index;

   --  ------------------------------
   --  Get the permission index associated with the name.
   --  ------------------------------
   function Get_Permission_Index (Name : in String) return Permission_Index is
   begin
      return Permission_Indexes.Get_Permission_Index (Name);
   end Get_Permission_Index;

   function Occurrence (List : in String; Of_Char : in Character) return Natural is
      Count : Natural := 0;
   begin
      if List'Length > 0 then
         Count := 1;
         for C of List loop
            if C = Of_Char then
               Count := Count + 1;
            end if;
         end loop;
      end if;
      return Count;
   end Occurrence;

   --  ------------------------------
   --  Get the list of permissions whose name is given in the string with separated comma.
   --  ------------------------------
   function Get_Permission_Array (List : in String) return Permission_Index_Array is
      procedure Process (Name : in String;
                         Done : out Boolean);

      Result : Permission_Index_Array (1 .. Occurrence (List, ','));
      Count  : Natural := 0;

      procedure Process (Name : in String;
                         Done : out Boolean) is
      begin
         Done := False;
         Result (Count + 1) := Get_Permission_Index (Name);
         Count := Count + 1;

      exception
         when Invalid_Name =>
            Log.Info ("Permission {0} does not exist", Name);

      end Process;
   begin
      Util.Strings.Tokenizers.Iterate_Tokens (Content => List,
                                              Pattern => ",",
                                              Process => Process'Access,
                                              Going   => Ada.Strings.Forward);
      return Result (1 .. Count);
   end Get_Permission_Array;

   --  ------------------------------
   --  Get the permission name given the index.
   --  ------------------------------
   function Get_Name (Index : in Permission_Index) return String is
   begin
      return Permission_Indexes.Get_Name (Index);
   end Get_Name;

   --  ------------------------------
   --  Get the last permission index registered in the global permission map.
   --  ------------------------------
   function Get_Last_Permission_Index return Permission_Index is
   begin
      return Permission_Indexes.Get_Last_Permission_Index;
   end Get_Last_Permission_Index;

   --  ------------------------------
   --  Add the permission name and allocate a unique permission index.
   --  ------------------------------
   procedure Add_Permission (Name  : in String;
                             Index : out Permission_Index) is
   begin
      Permission_Indexes.Add_Permission (Name, Index);
   end Add_Permission;

   --  ------------------------------
   --  Check if the permission index set contains the given permission index.
   --  ------------------------------
   function Has_Permission (Set   : in Permission_Index_Set;
                            Index : in Permission_Index) return Boolean is
      use Interfaces;
   begin
      return (Set (Natural (Index / 8)) and Shift_Left (1, Natural (Index mod 8))) /= 0;
   end Has_Permission;

   --  ------------------------------
   --  Add the permission index to the set.
   --  ------------------------------
   procedure Add_Permission (Set   : in out Permission_Index_Set;
                             Index : in Permission_Index) is
      use Interfaces;
      Pos : constant Natural := Natural (Index / 8);
   begin
      Set (Pos) := Set (Pos) or Shift_Left (1, Natural (Index mod 8));
   end Add_Permission;

   package body Definition is
      P : Permission_Index;

      function Permission return Permission_Index is
      begin
         return P;
      end Permission;

   begin
      Add_Permission (Name => Name, Index => P);
   end Definition;

end Security.Permissions;