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

Generated on Wed Oct 22 14:05:06 2003 for D-BUS by doxygen1.3-rc3