Main Page   Modules   Data Structures   File List   Data Fields   Related Pages  

policy.c

00001 /* -*- mode: C; c-file-style: "gnu" -*- */
00002 /* policy.c  Bus security policy
00003  *
00004  * Copyright (C) 2003  Red Hat, Inc.
00005  *
00006  * Licensed under the Academic Free License version 1.2
00007  * 
00008  * This program is free software; you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published by
00010  * the Free Software Foundation; either version 2 of the License, or
00011  * (at your option) any later version.
00012  *
00013  * This program is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  * GNU General Public License for more details.
00017  * 
00018  * You should have received a copy of the GNU General Public License
00019  * along with this program; if not, write to the Free Software
00020  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00021  *
00022  */
00023 
00024 #include "policy.h"
00025 #include "services.h"
00026 #include "test.h"
00027 #include "utils.h"
00028 #include <dbus/dbus-list.h>
00029 #include <dbus/dbus-hash.h>
00030 #include <dbus/dbus-internals.h>
00031 
00032 BusPolicyRule*
00033 bus_policy_rule_new (BusPolicyRuleType type,
00034                      dbus_bool_t       allow)
00035 {
00036   BusPolicyRule *rule;
00037 
00038   rule = dbus_new0 (BusPolicyRule, 1);
00039   if (rule == NULL)
00040     return NULL;
00041 
00042   rule->type = type;
00043   rule->refcount = 1;
00044   rule->allow = allow;
00045 
00046   switch (rule->type)
00047     {
00048     case BUS_POLICY_RULE_USER:
00049       rule->d.user.uid = DBUS_UID_UNSET;
00050       break;
00051     case BUS_POLICY_RULE_GROUP:
00052       rule->d.group.gid = DBUS_GID_UNSET;
00053       break;
00054     case BUS_POLICY_RULE_SEND:
00055       rule->d.send.message_type = DBUS_MESSAGE_TYPE_INVALID;
00056       break;
00057     case BUS_POLICY_RULE_RECEIVE:
00058       rule->d.receive.message_type = DBUS_MESSAGE_TYPE_INVALID;
00059       break;
00060     case BUS_POLICY_RULE_OWN:
00061       break;
00062     }
00063   
00064   return rule;
00065 }
00066 
00067 void
00068 bus_policy_rule_ref (BusPolicyRule *rule)
00069 {
00070   _dbus_assert (rule->refcount > 0);
00071 
00072   rule->refcount += 1;
00073 }
00074 
00075 void
00076 bus_policy_rule_unref (BusPolicyRule *rule)
00077 {
00078   _dbus_assert (rule->refcount > 0);
00079 
00080   rule->refcount -= 1;
00081   
00082   if (rule->refcount == 0)
00083     {
00084       switch (rule->type)
00085         {
00086         case BUS_POLICY_RULE_SEND:
00087           dbus_free (rule->d.send.path);
00088           dbus_free (rule->d.send.interface);
00089           dbus_free (rule->d.send.member);
00090           dbus_free (rule->d.send.error);
00091           dbus_free (rule->d.send.destination);
00092           break;
00093         case BUS_POLICY_RULE_RECEIVE:
00094           dbus_free (rule->d.receive.path);
00095           dbus_free (rule->d.receive.interface);
00096           dbus_free (rule->d.receive.member);
00097           dbus_free (rule->d.receive.error);
00098           dbus_free (rule->d.receive.origin);
00099           break;
00100         case BUS_POLICY_RULE_OWN:
00101           dbus_free (rule->d.own.service_name);
00102           break;
00103         case BUS_POLICY_RULE_USER:
00104           break;
00105         case BUS_POLICY_RULE_GROUP:
00106           break;
00107         }
00108       
00109       dbus_free (rule);
00110     }
00111 }
00112 
00113 struct BusPolicy
00114 {
00115   int refcount;
00116 
00117   DBusList *default_rules;       
00118   DBusList *mandatory_rules;     
00119   DBusHashTable *rules_by_uid;   
00120   DBusHashTable *rules_by_gid;   
00121 };
00122 
00123 static void
00124 free_rule_func (void *data,
00125                 void *user_data)
00126 {
00127   BusPolicyRule *rule = data;
00128 
00129   bus_policy_rule_unref (rule);
00130 }
00131 
00132 static void
00133 free_rule_list_func (void *data)
00134 {
00135   DBusList **list = data;
00136 
00137   if (list == NULL) /* DBusHashTable is on crack */
00138     return;
00139   
00140   _dbus_list_foreach (list, free_rule_func, NULL);
00141   
00142   _dbus_list_clear (list);
00143 
00144   dbus_free (list);
00145 }
00146 
00147 BusPolicy*
00148 bus_policy_new (void)
00149 {
00150   BusPolicy *policy;
00151 
00152   policy = dbus_new0 (BusPolicy, 1);
00153   if (policy == NULL)
00154     return NULL;
00155 
00156   policy->refcount = 1;
00157   
00158   policy->rules_by_uid = _dbus_hash_table_new (DBUS_HASH_ULONG,
00159                                                NULL,
00160                                                free_rule_list_func);
00161   if (policy->rules_by_uid == NULL)
00162     goto failed;
00163 
00164   policy->rules_by_gid = _dbus_hash_table_new (DBUS_HASH_ULONG,
00165                                                NULL,
00166                                                free_rule_list_func);
00167   if (policy->rules_by_gid == NULL)
00168     goto failed;
00169   
00170   return policy;
00171   
00172  failed:
00173   bus_policy_unref (policy);
00174   return NULL;
00175 }
00176 
00177 void
00178 bus_policy_ref (BusPolicy *policy)
00179 {
00180   _dbus_assert (policy->refcount > 0);
00181 
00182   policy->refcount += 1;
00183 }
00184 
00185 void
00186 bus_policy_unref (BusPolicy *policy)
00187 {
00188   _dbus_assert (policy->refcount > 0);
00189 
00190   policy->refcount -= 1;
00191 
00192   if (policy->refcount == 0)
00193     {
00194       _dbus_list_foreach (&policy->default_rules, free_rule_func, NULL);
00195       _dbus_list_clear (&policy->default_rules);
00196 
00197       _dbus_list_foreach (&policy->mandatory_rules, free_rule_func, NULL);
00198       _dbus_list_clear (&policy->mandatory_rules);
00199       
00200       if (policy->rules_by_uid)
00201         {
00202           _dbus_hash_table_unref (policy->rules_by_uid);
00203           policy->rules_by_uid = NULL;
00204         }
00205 
00206       if (policy->rules_by_gid)
00207         {
00208           _dbus_hash_table_unref (policy->rules_by_gid);
00209           policy->rules_by_gid = NULL;
00210         }
00211       
00212       dbus_free (policy);
00213     }
00214 }
00215 
00216 static dbus_bool_t
00217 add_list_to_client (DBusList        **list,
00218                     BusClientPolicy  *client)
00219 {
00220   DBusList *link;
00221 
00222   link = _dbus_list_get_first_link (list);
00223   while (link != NULL)
00224     {
00225       BusPolicyRule *rule = link->data;
00226       link = _dbus_list_get_next_link (list, link);
00227 
00228       switch (rule->type)
00229         {
00230         case BUS_POLICY_RULE_USER:
00231         case BUS_POLICY_RULE_GROUP:
00232           /* These aren't per-connection policies */
00233           break;
00234 
00235         case BUS_POLICY_RULE_OWN:
00236         case BUS_POLICY_RULE_SEND:
00237         case BUS_POLICY_RULE_RECEIVE:
00238           /* These are per-connection */
00239           if (!bus_client_policy_append_rule (client, rule))
00240             return FALSE;
00241           break;
00242         }
00243     }
00244   
00245   return TRUE;
00246 }
00247 
00248 BusClientPolicy*
00249 bus_policy_create_client_policy (BusPolicy      *policy,
00250                                  DBusConnection *connection,
00251                                  DBusError      *error)
00252 {
00253   BusClientPolicy *client;
00254   unsigned long uid;
00255 
00256   _dbus_assert (dbus_connection_get_is_authenticated (connection));
00257   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00258   
00259   client = bus_client_policy_new ();
00260   if (client == NULL)
00261     goto nomem;
00262 
00263   if (!add_list_to_client (&policy->default_rules,
00264                            client))
00265     goto nomem;
00266 
00267   /* we avoid the overhead of looking up user's groups
00268    * if we don't have any group rules anyway
00269    */
00270   if (_dbus_hash_table_get_n_entries (policy->rules_by_gid) > 0)
00271     {
00272       unsigned long *groups;
00273       int n_groups;
00274       int i;
00275       
00276       if (!bus_connection_get_groups (connection, &groups, &n_groups, error))
00277         goto failed;
00278       
00279       i = 0;
00280       while (i < n_groups)
00281         {
00282           DBusList **list;
00283           
00284           list = _dbus_hash_table_lookup_ulong (policy->rules_by_gid,
00285                                                 groups[i]);
00286           
00287           if (list != NULL)
00288             {
00289               if (!add_list_to_client (list, client))
00290                 {
00291                   dbus_free (groups);
00292                   goto nomem;
00293                 }
00294             }
00295           
00296           ++i;
00297         }
00298 
00299       dbus_free (groups);
00300     }
00301 
00302   if (!dbus_connection_get_unix_user (connection, &uid))
00303     {
00304       dbus_set_error (error, DBUS_ERROR_FAILED,
00305                       "No user ID known for connection, cannot determine security policy\n");
00306       goto failed;
00307     }
00308 
00309   if (_dbus_hash_table_get_n_entries (policy->rules_by_uid) > 0)
00310     {
00311       DBusList **list;
00312       
00313       list = _dbus_hash_table_lookup_ulong (policy->rules_by_uid,
00314                                             uid);
00315 
00316       if (list != NULL)
00317         {
00318           if (!add_list_to_client (list, client))
00319             goto nomem;
00320         }
00321     }
00322 
00323   if (!add_list_to_client (&policy->mandatory_rules,
00324                            client))
00325     goto nomem;
00326 
00327   bus_client_policy_optimize (client);
00328   
00329   return client;
00330 
00331  nomem:
00332   BUS_SET_OOM (error);
00333  failed:
00334   _DBUS_ASSERT_ERROR_IS_SET (error);
00335   if (client)
00336     bus_client_policy_unref (client);
00337   return NULL;
00338 }
00339 
00340 static dbus_bool_t
00341 list_allows_user (dbus_bool_t           def,
00342                   DBusList            **list,
00343                   unsigned long         uid,
00344                   const unsigned long  *group_ids,
00345                   int                   n_group_ids)
00346 {
00347   DBusList *link;
00348   dbus_bool_t allowed;
00349   
00350   allowed = def;
00351 
00352   link = _dbus_list_get_first_link (list);
00353   while (link != NULL)
00354     {
00355       BusPolicyRule *rule = link->data;
00356       link = _dbus_list_get_next_link (list, link);
00357       
00358       if (rule->type == BUS_POLICY_RULE_USER)
00359         {
00360           _dbus_verbose ("List %p user rule uid="DBUS_UID_FORMAT"\n",
00361                          list, rule->d.user.uid);
00362           
00363           if (rule->d.user.uid == DBUS_UID_UNSET)
00364             ; /* '*' wildcard */
00365           else if (rule->d.user.uid != uid)
00366             continue;
00367         }
00368       else if (rule->type == BUS_POLICY_RULE_GROUP)
00369         {
00370           _dbus_verbose ("List %p group rule uid="DBUS_UID_FORMAT"\n",
00371                          list, rule->d.user.uid);
00372           
00373           if (rule->d.group.gid == DBUS_GID_UNSET)
00374             ;  /* '*' wildcard */
00375           else
00376             {
00377               int i;
00378               
00379               i = 0;
00380               while (i < n_group_ids)
00381                 {
00382                   if (rule->d.group.gid == group_ids[i])
00383                     break;
00384                   ++i;
00385                 }
00386               
00387               if (i == n_group_ids)
00388                 continue;
00389             }
00390         }
00391       else
00392         continue;
00393 
00394       allowed = rule->allow;
00395     }
00396   
00397   return allowed;
00398 }
00399 
00400 dbus_bool_t
00401 bus_policy_allow_user (BusPolicy        *policy,
00402                        DBusUserDatabase *user_database,
00403                        unsigned long     uid)
00404 {
00405   dbus_bool_t allowed;
00406   unsigned long *group_ids;
00407   int n_group_ids;
00408 
00409   /* On OOM or error we always reject the user */
00410   if (!_dbus_user_database_get_groups (user_database,
00411                                        uid, &group_ids, &n_group_ids, NULL))
00412     {
00413       _dbus_verbose ("Did not get any groups for UID %lu\n",
00414                      uid);
00415       return FALSE;
00416     }
00417   
00418   allowed = FALSE;
00419 
00420   allowed = list_allows_user (allowed,
00421                               &policy->default_rules,
00422                               uid,
00423                               group_ids, n_group_ids);
00424 
00425   allowed = list_allows_user (allowed,
00426                               &policy->mandatory_rules,
00427                               uid,
00428                               group_ids, n_group_ids);
00429 
00430   dbus_free (group_ids);
00431 
00432   _dbus_verbose ("UID %lu allowed = %d\n", uid, allowed);
00433   
00434   return allowed;
00435 }
00436 
00437 dbus_bool_t
00438 bus_policy_append_default_rule (BusPolicy      *policy,
00439                                 BusPolicyRule  *rule)
00440 {
00441   if (!_dbus_list_append (&policy->default_rules, rule))
00442     return FALSE;
00443 
00444   bus_policy_rule_ref (rule);
00445 
00446   return TRUE;
00447 }
00448 
00449 dbus_bool_t
00450 bus_policy_append_mandatory_rule (BusPolicy      *policy,
00451                                   BusPolicyRule  *rule)
00452 {
00453   if (!_dbus_list_append (&policy->mandatory_rules, rule))
00454     return FALSE;
00455 
00456   bus_policy_rule_ref (rule);
00457 
00458   return TRUE;
00459 }
00460 
00461 static DBusList**
00462 get_list (DBusHashTable *hash,
00463           unsigned long  key)
00464 {
00465   DBusList **list;
00466 
00467   list = _dbus_hash_table_lookup_ulong (hash, key);
00468 
00469   if (list == NULL)
00470     {
00471       list = dbus_new0 (DBusList*, 1);
00472       if (list == NULL)
00473         return NULL;
00474 
00475       if (!_dbus_hash_table_insert_ulong (hash, key, list))
00476         {
00477           dbus_free (list);
00478           return NULL;
00479         }
00480     }
00481 
00482   return list;
00483 }
00484 
00485 dbus_bool_t
00486 bus_policy_append_user_rule (BusPolicy      *policy,
00487                              dbus_uid_t      uid,
00488                              BusPolicyRule  *rule)
00489 {
00490   DBusList **list;
00491 
00492   list = get_list (policy->rules_by_uid, uid);
00493 
00494   if (list == NULL)
00495     return FALSE;
00496 
00497   if (!_dbus_list_append (list, rule))
00498     return FALSE;
00499 
00500   bus_policy_rule_ref (rule);
00501 
00502   return TRUE;
00503 }
00504 
00505 dbus_bool_t
00506 bus_policy_append_group_rule (BusPolicy      *policy,
00507                               dbus_gid_t      gid,
00508                               BusPolicyRule  *rule)
00509 {
00510   DBusList **list;
00511 
00512   list = get_list (policy->rules_by_gid, gid);
00513 
00514   if (list == NULL)
00515     return FALSE;
00516 
00517   if (!_dbus_list_append (list, rule))
00518     return FALSE;
00519 
00520   bus_policy_rule_ref (rule);
00521 
00522   return TRUE;
00523 }
00524 
00525 static dbus_bool_t
00526 append_copy_of_policy_list (DBusList **list,
00527                             DBusList **to_append)
00528 {
00529   DBusList *link;
00530   DBusList *tmp_list;
00531 
00532   tmp_list = NULL;
00533 
00534   /* Preallocate all our links */
00535   link = _dbus_list_get_first_link (to_append);
00536   while (link != NULL)
00537     {
00538       if (!_dbus_list_append (&tmp_list, link->data))
00539         {
00540           _dbus_list_clear (&tmp_list);
00541           return FALSE;
00542         }
00543       
00544       link = _dbus_list_get_next_link (to_append, link);
00545     }
00546 
00547   /* Now append them */
00548   while ((link = _dbus_list_pop_first_link (&tmp_list)))
00549     {
00550       bus_policy_rule_ref (link->data);
00551       _dbus_list_append_link (list, link);
00552     }
00553 
00554   return TRUE;
00555 }
00556 
00557 static dbus_bool_t
00558 merge_id_hash (DBusHashTable *dest,
00559                DBusHashTable *to_absorb)
00560 {
00561   DBusHashIter iter;
00562   
00563   _dbus_hash_iter_init (to_absorb, &iter);
00564   while (_dbus_hash_iter_next (&iter))
00565     {
00566       unsigned long id = _dbus_hash_iter_get_ulong_key (&iter);
00567       DBusList **list = _dbus_hash_iter_get_value (&iter);
00568       DBusList **target = get_list (dest, id);
00569 
00570       if (target == NULL)
00571         return FALSE;
00572 
00573       if (!append_copy_of_policy_list (target, list))
00574         return FALSE;
00575     }
00576 
00577   return TRUE;
00578 }
00579 
00580 dbus_bool_t
00581 bus_policy_merge (BusPolicy *policy,
00582                   BusPolicy *to_absorb)
00583 {
00584   /* Not properly atomic, but as used for configuration files
00585    * we don't rely on it.
00586    */  
00587   if (!append_copy_of_policy_list (&policy->default_rules,
00588                                    &to_absorb->default_rules))
00589     return FALSE;
00590   
00591   if (!append_copy_of_policy_list (&policy->mandatory_rules,
00592                                    &to_absorb->mandatory_rules))
00593     return FALSE;
00594 
00595   if (!merge_id_hash (policy->rules_by_uid,
00596                       to_absorb->rules_by_uid))
00597     return FALSE;
00598   
00599   if (!merge_id_hash (policy->rules_by_gid,
00600                       to_absorb->rules_by_gid))
00601     return FALSE;
00602 
00603   return TRUE;
00604 }
00605 
00606 struct BusClientPolicy
00607 {
00608   int refcount;
00609 
00610   DBusList *rules;
00611 };
00612 
00613 BusClientPolicy*
00614 bus_client_policy_new (void)
00615 {
00616   BusClientPolicy *policy;
00617 
00618   policy = dbus_new0 (BusClientPolicy, 1);
00619   if (policy == NULL)
00620     return NULL;
00621 
00622   policy->refcount = 1;
00623 
00624   return policy;
00625 }
00626 
00627 void
00628 bus_client_policy_ref (BusClientPolicy *policy)
00629 {
00630   _dbus_assert (policy->refcount > 0);
00631 
00632   policy->refcount += 1;
00633 }
00634 
00635 static void
00636 rule_unref_foreach (void *data,
00637                     void *user_data)
00638 {
00639   BusPolicyRule *rule = data;
00640 
00641   bus_policy_rule_unref (rule);
00642 }
00643 
00644 void
00645 bus_client_policy_unref (BusClientPolicy *policy)
00646 {
00647   _dbus_assert (policy->refcount > 0);
00648 
00649   policy->refcount -= 1;
00650 
00651   if (policy->refcount == 0)
00652     {
00653       _dbus_list_foreach (&policy->rules,
00654                           rule_unref_foreach,
00655                           NULL);
00656 
00657       _dbus_list_clear (&policy->rules);
00658       
00659       dbus_free (policy);
00660     }
00661 }
00662 
00663 static void
00664 remove_rules_by_type_up_to (BusClientPolicy   *policy,
00665                             BusPolicyRuleType  type,
00666                             DBusList          *up_to)
00667 {
00668   DBusList *link;
00669 
00670   link = _dbus_list_get_first_link (&policy->rules);
00671   while (link != up_to)
00672     {
00673       BusPolicyRule *rule = link->data;
00674       DBusList *next = _dbus_list_get_next_link (&policy->rules, link);
00675 
00676       if (rule->type == type)
00677         {
00678           _dbus_list_remove_link (&policy->rules, link);
00679           bus_policy_rule_unref (rule);
00680         }
00681       
00682       link = next;
00683     }
00684 }
00685 
00686 void
00687 bus_client_policy_optimize (BusClientPolicy *policy)
00688 {
00689   DBusList *link;
00690 
00691   /* The idea here is that if we have:
00692    * 
00693    * <allow send_interface="foo.bar"/>
00694    * <deny send_interface="*"/>
00695    *
00696    * (for example) the deny will always override the allow.  So we
00697    * delete the allow. Ditto for deny followed by allow, etc. This is
00698    * a dumb thing to put in a config file, but the <include> feature
00699    * of files allows for an "inheritance and override" pattern where
00700    * it could make sense. If an included file wants to "start over"
00701    * with a blanket deny, no point keeping the rules from the parent
00702    * file.
00703    */
00704 
00705   _dbus_verbose ("Optimizing policy with %d rules\n",
00706                  _dbus_list_get_length (&policy->rules));
00707   
00708   link = _dbus_list_get_first_link (&policy->rules);
00709   while (link != NULL)
00710     {
00711       BusPolicyRule *rule;
00712       DBusList *next;
00713       dbus_bool_t remove_preceding;
00714 
00715       next = _dbus_list_get_next_link (&policy->rules, link);
00716       rule = link->data;
00717       
00718       remove_preceding = FALSE;
00719 
00720       _dbus_assert (rule != NULL);
00721       
00722       switch (rule->type)
00723         {
00724         case BUS_POLICY_RULE_SEND:
00725           remove_preceding =
00726             rule->d.send.message_type == DBUS_MESSAGE_TYPE_INVALID &&
00727             rule->d.send.path == NULL &&
00728             rule->d.send.interface == NULL &&
00729             rule->d.send.member == NULL &&
00730             rule->d.send.error == NULL &&
00731             rule->d.send.destination == NULL;
00732           break;
00733         case BUS_POLICY_RULE_RECEIVE:
00734           remove_preceding =
00735             rule->d.receive.message_type == DBUS_MESSAGE_TYPE_INVALID &&
00736             rule->d.receive.path == NULL &&
00737             rule->d.receive.interface == NULL &&
00738             rule->d.receive.member == NULL &&
00739             rule->d.receive.error == NULL &&
00740             rule->d.receive.origin == NULL;
00741           break;
00742         case BUS_POLICY_RULE_OWN:
00743           remove_preceding =
00744             rule->d.own.service_name == NULL;
00745           break;
00746         case BUS_POLICY_RULE_USER:
00747         case BUS_POLICY_RULE_GROUP:
00748           _dbus_assert_not_reached ("invalid rule");
00749           break;
00750         }
00751 
00752       if (remove_preceding)
00753         remove_rules_by_type_up_to (policy, rule->type,
00754                                     link);
00755       
00756       link = next;
00757     }
00758 
00759   _dbus_verbose ("After optimization, policy has %d rules\n",
00760                  _dbus_list_get_length (&policy->rules));
00761 }
00762 
00763 dbus_bool_t
00764 bus_client_policy_append_rule (BusClientPolicy *policy,
00765                                BusPolicyRule   *rule)
00766 {
00767   _dbus_verbose ("Appending rule %p with type %d to policy %p\n",
00768                  rule, rule->type, policy);
00769   
00770   if (!_dbus_list_append (&policy->rules, rule))
00771     return FALSE;
00772 
00773   bus_policy_rule_ref (rule);
00774 
00775   return TRUE;
00776 }
00777 
00778 dbus_bool_t
00779 bus_client_policy_check_can_send (BusClientPolicy *policy,
00780                                   BusRegistry     *registry,
00781                                   DBusConnection  *receiver,
00782                                   DBusMessage     *message)
00783 {
00784   DBusList *link;
00785   dbus_bool_t allowed;
00786   
00787   /* policy->rules is in the order the rules appeared
00788    * in the config file, i.e. last rule that applies wins
00789    */
00790 
00791   _dbus_verbose ("  (policy) checking send rules\n");
00792   
00793   allowed = FALSE;
00794   link = _dbus_list_get_first_link (&policy->rules);
00795   while (link != NULL)
00796     {
00797       BusPolicyRule *rule = link->data;
00798 
00799       link = _dbus_list_get_next_link (&policy->rules, link);
00800       
00801       /* Rule is skipped if it specifies a different
00802        * message name from the message, or a different
00803        * destination from the message
00804        */
00805       
00806       if (rule->type != BUS_POLICY_RULE_SEND)
00807         {
00808           _dbus_verbose ("  (policy) skipping non-send rule\n");
00809           continue;
00810         }
00811 
00812       if (rule->d.send.message_type != DBUS_MESSAGE_TYPE_INVALID)
00813         {
00814           if (dbus_message_get_type (message) != rule->d.send.message_type)
00815             {
00816               _dbus_verbose ("  (policy) skipping rule for different message type\n");
00817               continue;
00818             }
00819         }
00820       
00821       if (rule->d.send.path != NULL)
00822         {
00823           if (dbus_message_get_path (message) != NULL &&
00824               strcmp (dbus_message_get_path (message),
00825                       rule->d.send.path) != 0)
00826             {
00827               _dbus_verbose ("  (policy) skipping rule for different path\n");
00828               continue;
00829             }
00830         }
00831       
00832       if (rule->d.send.interface != NULL)
00833         {
00834           if (dbus_message_get_interface (message) != NULL &&
00835               strcmp (dbus_message_get_interface (message),
00836                       rule->d.send.interface) != 0)
00837             {
00838               _dbus_verbose ("  (policy) skipping rule for different interface\n");
00839               continue;
00840             }
00841         }
00842 
00843       if (rule->d.send.member != NULL)
00844         {
00845           if (dbus_message_get_member (message) != NULL &&
00846               strcmp (dbus_message_get_member (message),
00847                       rule->d.send.member) != 0)
00848             {
00849               _dbus_verbose ("  (policy) skipping rule for different member\n");
00850               continue;
00851             }
00852         }
00853 
00854       if (rule->d.send.error != NULL)
00855         {
00856           if (dbus_message_get_error_name (message) != NULL &&
00857               strcmp (dbus_message_get_error_name (message),
00858                       rule->d.send.error) != 0)
00859             {
00860               _dbus_verbose ("  (policy) skipping rule for different error name\n");
00861               continue;
00862             }
00863         }
00864       
00865       if (rule->d.send.destination != NULL)
00866         {
00867           /* receiver can be NULL for messages that are sent to the
00868            * message bus itself, we check the strings in that case as
00869            * built-in services don't have a DBusConnection but messages
00870            * to them have a destination service name.
00871            */
00872           if (receiver == NULL)
00873             {
00874               if (!dbus_message_has_destination (message,
00875                                                  rule->d.send.destination))
00876                 {
00877                   _dbus_verbose ("  (policy) skipping rule because message dest is not %s\n",
00878                                  rule->d.send.destination);
00879                   continue;
00880                 }
00881             }
00882           else
00883             {
00884               DBusString str;
00885               BusService *service;
00886               
00887               _dbus_string_init_const (&str, rule->d.send.destination);
00888               
00889               service = bus_registry_lookup (registry, &str);
00890               if (service == NULL)
00891                 {
00892                   _dbus_verbose ("  (policy) skipping rule because dest %s doesn't exist\n",
00893                                  rule->d.send.destination);
00894                   continue;
00895                 }
00896 
00897               if (!bus_service_has_owner (service, receiver))
00898                 {
00899                   _dbus_verbose ("  (policy) skipping rule because dest %s isn't owned by receiver\n",
00900                                  rule->d.send.destination);
00901                   continue;
00902                 }
00903             }
00904         }
00905 
00906       /* Use this rule */
00907       allowed = rule->allow;
00908 
00909       _dbus_verbose ("  (policy) used rule, allow now = %d\n",
00910                      allowed);
00911     }
00912 
00913   return allowed;
00914 }
00915 
00916 dbus_bool_t
00917 bus_client_policy_check_can_receive (BusClientPolicy *policy,
00918                                      BusRegistry     *registry,
00919                                      DBusConnection  *sender,
00920                                      DBusConnection  *addressed_recipient,
00921                                      DBusConnection  *proposed_recipient,
00922                                      DBusMessage     *message)
00923 {
00924   DBusList *link;
00925   dbus_bool_t allowed;
00926   dbus_bool_t eavesdropping;
00927   
00928   /* NULL sender, proposed_recipient means the bus driver.  NULL
00929    * addressed_recipient means the message didn't specify an explicit
00930    * target. If proposed_recipient is NULL, then addressed_recipient
00931    * is also NULL but is implicitly the bus driver.
00932    */
00933 
00934   _dbus_assert (proposed_recipient == NULL ||
00935                 (dbus_message_get_destination (message) == NULL ||
00936                  addressed_recipient != NULL));
00937   
00938   eavesdropping =
00939     (proposed_recipient == NULL || /* explicitly to bus driver */
00940      (addressed_recipient && addressed_recipient != proposed_recipient)); /* explicitly to a different recipient */
00941   
00942   /* policy->rules is in the order the rules appeared
00943    * in the config file, i.e. last rule that applies wins
00944    */
00945 
00946   _dbus_verbose ("  (policy) checking receive rules, eavesdropping = %d\n", eavesdropping);
00947   
00948   allowed = FALSE;
00949   link = _dbus_list_get_first_link (&policy->rules);
00950   while (link != NULL)
00951     {
00952       BusPolicyRule *rule = link->data;
00953 
00954       link = _dbus_list_get_next_link (&policy->rules, link);      
00955       
00956       if (rule->type != BUS_POLICY_RULE_RECEIVE)
00957         {
00958           _dbus_verbose ("  (policy) skipping non-receive rule\n");
00959           continue;
00960         }
00961 
00962       if (rule->d.receive.message_type != DBUS_MESSAGE_TYPE_INVALID)
00963         {
00964           if (dbus_message_get_type (message) != rule->d.receive.message_type)
00965             {
00966               _dbus_verbose ("  (policy) skipping rule for different message type\n");
00967               continue;
00968             }
00969         }
00970 
00971       /* for allow, eavesdrop=false means the rule doesn't apply when
00972        * eavesdropping. eavesdrop=true means always allow.
00973        */
00974       if (eavesdropping && rule->allow && !rule->d.receive.eavesdrop)
00975         {
00976           _dbus_verbose ("  (policy) skipping allow rule since it doesn't apply to eavesdropping\n");
00977           continue;
00978         }
00979 
00980       /* for deny, eavesdrop=true means the rule applies only when
00981        * eavesdropping; eavesdrop=false means always deny.
00982        */
00983       if (!eavesdropping && !rule->allow && rule->d.receive.eavesdrop)
00984         {
00985           _dbus_verbose ("  (policy) skipping deny rule since it only applies to eavesdropping\n");
00986           continue;
00987         }
00988       
00989       if (rule->d.receive.path != NULL)
00990         {
00991           if (dbus_message_get_path (message) != NULL &&
00992               strcmp (dbus_message_get_path (message),
00993                       rule->d.receive.path) != 0)
00994             {
00995               _dbus_verbose ("  (policy) skipping rule for different path\n");
00996               continue;
00997             }
00998         }
00999       
01000       if (rule->d.receive.interface != NULL)
01001         {
01002           if (dbus_message_get_interface (message) != NULL &&
01003               strcmp (dbus_message_get_interface (message),
01004                       rule->d.receive.interface) != 0)
01005             {
01006               _dbus_verbose ("  (policy) skipping rule for different interface\n");
01007               continue;
01008             }
01009         }      
01010 
01011       if (rule->d.receive.member != NULL)
01012         {
01013           if (dbus_message_get_member (message) != NULL &&
01014               strcmp (dbus_message_get_member (message),
01015                       rule->d.receive.member) != 0)
01016             {
01017               _dbus_verbose ("  (policy) skipping rule for different member\n");
01018               continue;
01019             }
01020         }
01021 
01022       if (rule->d.receive.error != NULL)
01023         {
01024           if (dbus_message_get_error_name (message) != NULL &&
01025               strcmp (dbus_message_get_error_name (message),
01026                       rule->d.receive.error) != 0)
01027             {
01028               _dbus_verbose ("  (policy) skipping rule for different error name\n");
01029               continue;
01030             }
01031         }
01032       
01033       if (rule->d.receive.origin != NULL)
01034         {          
01035           /* sender can be NULL for messages that originate from the
01036            * message bus itself, we check the strings in that case as
01037            * built-in services don't have a DBusConnection but will
01038            * still set the sender on their messages.
01039            */
01040           if (sender == NULL)
01041             {
01042               if (!dbus_message_has_sender (message,
01043                                             rule->d.receive.origin))
01044                 {
01045                   _dbus_verbose ("  (policy) skipping rule because message sender is not %s\n",
01046                                  rule->d.receive.origin);
01047                   continue;
01048                 }
01049             }
01050           else
01051             {
01052               BusService *service;
01053               DBusString str;
01054 
01055               _dbus_string_init_const (&str, rule->d.receive.origin);
01056               
01057               service = bus_registry_lookup (registry, &str);
01058               
01059               if (service == NULL)
01060                 {
01061                   _dbus_verbose ("  (policy) skipping rule because origin %s doesn't exist\n",
01062                                  rule->d.receive.origin);
01063                   continue;
01064                 }
01065 
01066               if (!bus_service_has_owner (service, sender))
01067                 {
01068                   _dbus_verbose ("  (policy) skipping rule because origin %s isn't owned by sender\n",
01069                                  rule->d.receive.origin);
01070                   continue;
01071                 }
01072             }
01073         }
01074       
01075       /* Use this rule */
01076       allowed = rule->allow;
01077 
01078       _dbus_verbose ("  (policy) used rule, allow now = %d\n",
01079                      allowed);
01080     }
01081 
01082   return allowed;
01083 }
01084 
01085 dbus_bool_t
01086 bus_client_policy_check_can_own (BusClientPolicy  *policy,
01087                                  DBusConnection   *connection,
01088                                  const DBusString *service_name)
01089 {
01090   DBusList *link;
01091   dbus_bool_t allowed;
01092   
01093   /* policy->rules is in the order the rules appeared
01094    * in the config file, i.e. last rule that applies wins
01095    */
01096 
01097   allowed = FALSE;
01098   link = _dbus_list_get_first_link (&policy->rules);
01099   while (link != NULL)
01100     {
01101       BusPolicyRule *rule = link->data;
01102 
01103       link = _dbus_list_get_next_link (&policy->rules, link);
01104       
01105       /* Rule is skipped if it specifies a different service name from
01106        * the desired one.
01107        */
01108       
01109       if (rule->type != BUS_POLICY_RULE_OWN)
01110         continue;
01111 
01112       if (rule->d.own.service_name != NULL)
01113         {
01114           if (!_dbus_string_equal_c_str (service_name,
01115                                          rule->d.own.service_name))
01116             continue;
01117         }
01118 
01119       /* Use this rule */
01120       allowed = rule->allow;
01121     }
01122 
01123   return allowed;
01124 }
01125 
01126 #ifdef DBUS_BUILD_TESTS
01127 
01128 dbus_bool_t
01129 bus_policy_test (const DBusString *test_data_dir)
01130 {
01131   /* This doesn't do anything for now because I decided to do it in
01132    * dispatch.c instead by having some of the clients in dispatch.c
01133    * have particular policies applied to them.
01134    */
01135   
01136   return TRUE;
01137 }
01138 
01139 #endif /* DBUS_BUILD_TESTS */

Generated on Mon Sep 29 21:31:02 2003 for D-BUS by doxygen1.2.15