access._pike
Go to the documentation of this file.
1 /* Copyright (C) 2000-2004 Thomas Bopp, Thorsten Hampel, Ludger Merkens
2  *
3  * This program is free software; you can redistribute it and/or modify
4  * it under the terms of the GNU General Public License as published by
5  * the Free Software Foundation; either version 2 of the License, or
6  * (at your option) any later version.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program; if not, write to the Free Software
15  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16  *
17  * $Id: access.pike,v 1.2 2009/08/04 15:39:31 nicke Exp $
18  */
19 #include <assert.h>
20 #include <macros.h>
21 #include <attributes.h>
22 #include <access.h>
23 #include <roles.h>
24 #include <database.h>
25 #include <classes.h>
26 #include <events.h>
27 //!
28 //! basic access functions...
29 //! the permissions of other objects on this object are stored
30 //! inside mSanction mapping. Each Entry in the mapping is an integer
31 //! (32 bits) and each bit represents one permission for the sanctioned
32 //! object. The first 16 bits are reserved for the system and include
33 //! standard checks that are done inside system code. The other 16 bits
34 //! are free for users to use in their own code.
35 class access {
36 public:
37 
38 
39 
40 
41 
42 private mapping mSanction; /*the right i have for this object */
43 private mapping mMetaSanction; /*the meta rights-to give away rights*/
44 private mapping mDataStorage;
45 
46 private object oCreator;
47  object|function oAcquire;
48 
49 int get_object_class();
50 object get_environment();
51 string get_identifier();
52 void update_path();
53  void require_save(void|string ident, void|string index);
54 
55 /**
56  * Initialize the access mappings for object, set acquiring to 0 and
57  * set the creator of this object.
58  *
59  */
60 final void
61 private:
62 init_access()
63 {
64  mSanction = ([ ]);
65  mMetaSanction = ([ ]);
66  mDataStorage = ([ ]);
67 
68  oAcquire = 0;
69  oCreator = geteuid();
70  if ( !objectp(oCreator) )
71  oCreator = this_user();
72 
73  if ( objectp(oCreator) )
74  mSanction = ([ oCreator : SANCTION_ALL ]);
75 }
76 
77 public:
78 
79 /**
80  * Set the object to acquire access from. That is not only the ACL of this
81  * object is used, but also the ACL of the object acquired from is used
82  * for access lookup.
83  *
84  * @param o - the object that variables and access is acquired from
85  * @see get_acquire
86  */
87 final bool
88 set_acquire(function|object acquire)
89 {
90  object acq;
91 
92  if ( !_SECURITY->access_acquire(0, this_object(), CALLER, acquire) )
93  return false;
94 
95  if ( functionp(acquire) )
96  acq = acquire();
97  else
98  acq = acquire;
99 
100  while ( objectp(acq) ) {
101  if ( functionp(acq->get_object) )
102  acq = acq->get_object();
103  if ( acq == this_object() )
104  THROW("Acquire ended up in loop !", E_ERROR);
105  acq = acq->get_acquire();
106  }
107 
108  oAcquire = acquire;
109  require_save(STORE_ACCESS);
110  return true;
111 }
112 
113 /**
114  * Turn on access acquiring from the object's environment. You can turn this
115  * off again by calling set_acquire(0);
116  *
117  * @see set_acquire
118  * @see get_acquire
119  *
120  * @return 1 on success, 0 on failure
121  */
122 final bool
123 set_acquire_from_environment()
124 {
125  return set_acquire( this_object()->get_environment );
126 }
127 
128 /**
129  * Return the acquiring object or function. If acquiring is turned of for this
130  * object it returns 0.
131  *
132  * @return the object permissions and variables are acquired
133  * @see set_acquire
134  */
135 final object|function
136 get_acquire()
137 {
138  return oAcquire;
139 }
140 
141 /**
142  * Return the acquiring object. If acquiring is turned of for this
143  * object it returns 0.
144  *
145  * @return the object permissions and variables are acquired
146  * @see set_acquire
147  */
148 final object
149 resolve_acquire()
150 {
151  if ( functionp(oAcquire) )
152  return oAcquire();
153  return oAcquire;
154 }
155 
156 
157 
158 
159 /**
160  * Get the sanction integer for a given object.
161  *
162  * @param obj - the object
163  * @return the sanction status for obj
164  * @see set_sanction
165  */
166 final int
167 query_sanction(object obj)
168 {
169  return mSanction[obj];
170 }
171 
172 /**
173  * Returns the sanction mapping of this object, if the caller is privileged
174  * the pointer will be returned, otherwise a copy.
175  *
176  * @return the sanction mapping
177  * @see set_sanction
178  */
179 final mapping
180 get_sanction()
181 {
182  if ( _SECURITY->trust(CALLER) )
183  return mSanction;
184  return copy_value(mSanction);
185 }
186 
187 /**
188  * The indices of the sanction mapping are returned. The sanction map is
189  * in the form ([ object: access-bits, ])
190  *
191  * @return all objects in sanction array
192  */
193 final array
194 query_sanctioned_objs()
195 {
196  return indices(mSanction);
197 }
198 
199 /**
200  * Get the meta-sanction mapping. Meta sanction contains access to
201  * give access permissions to other users or groups.
202  *
203  * @return copy of the meta sanction mapping
204  * @see query_meta_sanction
205  */
206 final mapping
207 get_meta_sanction()
208 {
209  return copy_value(mMetaSanction);
210 }
211 
212 /**
213  * Return the meta sanction access bit for a given object (group or user).
214  *
215  * @param obj - the possible sanctioned object
216  * @return the meta sanction permissions of obj on this
217  * @see set_meta_sanction
218  */
219 final int
220 query_meta_sanction(object obj)
221 {
222  return mMetaSanction[obj];
223 }
224 
225 /**
226  * Set the meta access permissions for a group or a user.
227  *
228  * @param obj - the object to sanction
229  * @param permission - meta sanction permissions
230  * @see query_meta_sanction
231  */
232 protected:
233 final void
234 set_meta_sanction(object obj, int permission)
235 {
236  mMetaSanction[obj] = permission;
237  require_save(STORE_ACCESS);
238 }
239 
240 public:
241 
242 /**
243  * Set the access permissions for a given group or user to 'permission'.
244  *
245  * @param obj - object to sanction
246  * @param permission - new permissions for that object
247  * @see get_sanction
248  */
249 protected:
250 final void
251 set_sanction(object obj, int permission)
252 {
253  ASSERTINFO(_SECURITY->valid_proxy(obj), "set_sanction on invalid proxy!");
254  ASSERTINFO(mappingp(mSanction), "Mapping not initialized....");
255 
256  if ( permission == 0 )
257  m_delete(mSanction, obj);
258  else
259  mSanction[obj] = permission;
260  require_save(STORE_ACCESS);
261 }
262 
263 public:
264 
265 /**
266  * This function returns whether a user or group has access permissions
267  * for 'accessBit'. The function also follows the acquiring path and
268  * calls try_access_object() in acquired objects too.
269  *
270  * @param user - who wants to access the object (user or group)
271  * @param accessBit - the Bit to check
272  * @param bool meta - check for meta access ?
273  * @return ACCESS_DENIED or ACCESS_GRANTED or event ACCESS_BLOCKED
274  * @see try_access_object_group
275  */
276 final int
277 try_access_object(object user, int accessBit, bool meta)
278 {
279  object obj = 0;
280  ASSERTINFO(_SECURITY->valid_proxy(user), "Access on non-proxy !");
281 
282  SECURITY_LOG("Sanction of user is:" + mSanction[user]+"(accBit="+accessBit+")");
283  if ( mSanction[user] & (accessBit << SANCTION_SHIFT_DENY) ) {
284  SECURITY_LOG("Access blocked !");
285  return ACCESS_BLOCKED;
286  }
287  if ( user == oCreator )
288  return ACCESS_GRANTED;
289 
290  {
291  SECURITY_LOG("Sanction of user does match !");
292  if ( !meta || (mMetaSanction[user] & accessBit) )
293  return ACCESS_GRANTED;
294  }
295  /* the object must not be sanctioned at all
296  * if the acquiring object gives permission to the user -> ok */
297  if ( objectp(oAcquire) )
298  obj = oAcquire;
299  else if ( functionp(oAcquire) )
300  obj = oAcquire();
301  /* it is not possible to block access from acquiring objects ! */
302  if ( objectp(obj) ) {
303  SECURITY_LOG("Using acquiring path to "+obj->get_object_id());
304  return obj->try_access_object(user, accessBit, meta) == ACCESS_GRANTED?
305  ACCESS_GRANTED : ACCESS_DENIED;
306  }
307 
308  return ACCESS_DENIED;
309 }
310 
311 /**
312  * Try to access the object by a group. The function recursively tries
313  * parent groups of the initial group. If one group succeeds, the call
314  * returns ACCESS_GRANTED.
315  *
316  * @param grp - the group that wants to write
317  * @return if successfull or not
318  * @see try_access_object
319  */
320 final int
321 try_access_object_group(object grp, int accessBit, bool meta)
322 {
323  object obj = 0;
324  int result;
325 
326  SECURITY_LOG("Group ["+grp->get_identifier()+"] access ("+
327  accessBit+") on "+get_identifier()+": sanction is "+
328  mSanction[grp]);
329 
330  if ( mSanction[grp] & (accessBit << SANCTION_SHIFT_DENY) )
331  return ACCESS_BLOCKED;
332 
333  if ( (mSanction[grp] & accessBit) )
334  {
335  if ( !meta || (mMetaSanction[grp] & accessBit) )
336  return ACCESS_GRANTED;
337  }
338 
339  array grp_groups = grp->get_groups();
340  // LOG("Indirect group checking ... ");
341  if ( arrayp(grp_groups) ) {
342  foreach( grp_groups, object member ) {
343  if ( objectp(member) && _SECURITY->valid_group(member) ) {
344  LOG("Accessing with " + master()->describe_object(member));
345  result = try_access_object_group(member, accessBit, meta);
346  if ( result == ACCESS_GRANTED )
347  return ACCESS_GRANTED;
348  }
349  }
350  }
351 
352  if ( objectp(oAcquire) )
353  obj = oAcquire;
354  else if ( functionp(oAcquire) )
355  obj = oAcquire();
356  if ( objectp(obj) ) {
357  return obj->try_access_object_group(grp, accessBit, meta);
358  }
359 
360  return ACCESS_DENIED;
361 }
362 
363 
364 
365 
366 
367 /**
368  * Return all owners of this object.
369  * Owners are groups/users that have sanction permission to the
370  * object, eg are able to give permissions to other objects.
371  *
372  * @return a list of owners
373  */
374 final array
375 query_owner()
376 {
377  int i;
378  array ind;
379  array owner;
380 
381  ind = indices(mSanction);
382  for ( i = sizeof(ind) - 1, owner = ({ }); i >= 0; i-- ) {
383  if ( mSanction[ind[i]] & SANCTION_SANCTION ) {
384  owner += ({ ind[i] });
385  }
386  }
387  return owner;
388 }
389 
390 /**
391  * Set the creator of the object. This is usually only done when
392  * the object was created, but for export functionality there is
393  * the possibility to change the creator later on. Apart from that the
394  * creator is the person calling the factory to create an instance.
395  *
396  * @param cr - the creator
397  * @see get_creator
398  */
399 final void
400 set_creator(object cr)
401 {
402  object caller = CALLER;
403  if ( !objectp(caller) )
404  caller = this_object();
405 
406  //! Remove second line - security hole: Only factories are able to set permissions
407  if ( objectp(oCreator) && !_Server->is_a_factory(CALLER) )
408  //!_SECURITY->access_set_creator(0, this_object(), caller) )
409  THROW("Unauthorized call to set_creator() by " +
410  master()->describe_object(caller)+" !", E_ACCESS);
411  oCreator = cr;
412  update_path();
413  require_save(STORE_ACCESS);
414 }
415 
416 /**
417  * Get the creator of the object. If no creator is set the root user
418  * is returned.
419  *
420  * @return the creator of the object
421  * @see set_creator
422  */
423 final object
424 get_creator()
425 {
426  if ( !objectp(oCreator) )
427  return _ROOT;
428  return oCreator;
429 }
430 
431 
432 /**
433  * Add a functionpair for storage and retrieval of data. Database
434  * uses this to call the functions on loading and saving the object.
435  *
436 private:
437  * @param retrieve_func - function to retrieve the object data
438 private:
439  * @param restore_func - function to be called in the object for restoring
440  * @return false or true (failed or not)
441  * @see get_data_storage
442  */
443 protected:
444  bool
445 private:
446 add_data_storage(string ident, function retrieve_func,
447 private:
448  function restore_func, int|void indexed)
449 {
450  if ( !mappingp(mDataStorage) )
451  THROW("Data Storage not initialized !", E_ERROR);
452  if ( strlen(ident)>15)
453  THROW("add_data_storage(): Illegal IDENT-Length > 15", E_ERROR);
454  if ( stringp(mDataStorage[ident]) )
455  THROW(sprintf("Data Storage %s already defined !",ident), E_ERROR);
456 
457  mDataStorage[ident] = ({ retrieve_func, restore_func, indexed });
458  return true;
459 }
460 
461 public:
462 
463 /**
464  * Get the data storage mapping, but only the _Database object is able
465  * to call this functions.
466  *
467  * @return the storage functions pairs (mapping)
468  * @see add_data_storage
469  */
470 final mapping get_data_storage()
471 {
472  ASSERTINFO(CALLER == _Persistence,"Unauthorized call to get_data_storage()");
473  return mDataStorage;
474 }
475 
476 /**
477  * The database object calls this function upon loading the object to
478  * restore the access data (ACLs)
479  *
480  * @param str - serialized access string
481  * @see unserialize_data
482  */
483 final void
484 private:
485 restore_access_data(mixed data, string|void index)
486 {
487  ASSERTINFO(CALLER == _Database, "Invalid call to restore_access_data()");
488 
489  if (!zero_type(index))
490  {
491  switch(index) {
492  case "Sanction" : mSanction = data; break;
493  case "MetaSanction" : mMetaSanction = data; break;
494  case "Creator" : oCreator = data; break;
495  case "Acquire" : oAcquire = data; break;
496  }
497  }
498  else {
499  if ( mappingp(data->Sanction) )
500  mSanction = data["Sanction"];
501  if ( mappingp(data->MetaSanction) )
502  mMetaSanction = data["MetaSanction"];
503  oCreator = data["Creator"];
504  oAcquire = data["Acquire"];
505  }
506 }
507 
508 public:
509 
510 /**
511  * The function retrieves the relevant access data to be saved in database.
512  * Only the _Database object is able to call this function.
513  *
514  * @return array of access data to be saved
515 private:
516  * @see restore_access_data
517  */
518 final mixed
519 private:
520 retrieve_access_data(string|void index)
521 {
522  if ( CALLER != _Database )
523  return 0;
524  /* this data has to be stored */
525  if (!zero_type(index))
526  {
527  switch(index) {
528  case "Sanction" : return mSanction;
529  case "MetaSanction" : return mMetaSanction;
530  case "Creator" : return oCreator;
531  case "Acquire" : return oAcquire;
532  }
533  }
534  else
535  {
536  return ([
537  "Sanction":mSanction,
538  "MetaSanction":mMetaSanction,
539  "Creator":oCreator,
540  "Acquire":oAcquire,
541  ]);
542  }
543 }
544 
545 public:
546 
547 
548 
549 };