Main Page   Modules   Data Structures   File List   Data Fields   Related Pages  

config-parser.c

00001 /* -*- mode: C; c-file-style: "gnu" -*- */
00002 /* config-parser.c  XML-library-agnostic configuration file parser
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 #include "config-parser.h"
00024 #include "test.h"
00025 #include "utils.h"
00026 #include "policy.h"
00027 #include <dbus/dbus-list.h>
00028 #include <dbus/dbus-internals.h>
00029 #include <string.h>
00030 
00031 typedef enum
00032 {
00033   ELEMENT_NONE,
00034   ELEMENT_BUSCONFIG,
00035   ELEMENT_INCLUDE,
00036   ELEMENT_USER,
00037   ELEMENT_LISTEN,
00038   ELEMENT_AUTH,
00039   ELEMENT_POLICY,
00040   ELEMENT_LIMIT,
00041   ELEMENT_ALLOW,
00042   ELEMENT_DENY,
00043   ELEMENT_FORK,
00044   ELEMENT_PIDFILE,
00045   ELEMENT_SERVICEDIR,
00046   ELEMENT_INCLUDEDIR,
00047   ELEMENT_TYPE
00048 } ElementType;
00049 
00050 typedef enum
00051 {
00052   /* we ignore policies for unknown groups/users */
00053   POLICY_IGNORED,
00054 
00055   /* non-ignored */
00056   POLICY_DEFAULT,
00057   POLICY_MANDATORY,
00058   POLICY_USER,
00059   POLICY_GROUP
00060 } PolicyType;
00061 
00062 typedef struct
00063 {
00064   ElementType type;
00065 
00066   unsigned int had_content : 1;
00067 
00068   union
00069   {
00070     struct
00071     {
00072       unsigned int ignore_missing : 1;
00073     } include;
00074 
00075     struct
00076     {
00077       PolicyType type;
00078       unsigned long gid_or_uid;      
00079     } policy;
00080 
00081     struct
00082     {
00083       char *name;
00084       long value;
00085     } limit;
00086     
00087   } d;
00088 
00089 } Element;
00090 
00094 struct BusConfigParser
00095 {
00096   int refcount;        
00098   DBusString basedir;  
00100   DBusList *stack;     
00102   char *user;          
00104   char *bus_type;          
00106   DBusList *listen_on; 
00108   DBusList *mechanisms; 
00110   DBusList *service_dirs; 
00112   BusPolicy *policy;     
00114   BusLimits limits;      
00116   char *pidfile;         
00118   unsigned int fork : 1; 
00120   unsigned int is_toplevel : 1; 
00121 };
00122 
00123 static const char*
00124 element_type_to_name (ElementType type)
00125 {
00126   switch (type)
00127     {
00128     case ELEMENT_NONE:
00129       return NULL;
00130     case ELEMENT_BUSCONFIG:
00131       return "busconfig";
00132     case ELEMENT_INCLUDE:
00133       return "include";
00134     case ELEMENT_USER:
00135       return "user";
00136     case ELEMENT_LISTEN:
00137       return "listen";
00138     case ELEMENT_AUTH:
00139       return "auth";
00140     case ELEMENT_POLICY:
00141       return "policy";
00142     case ELEMENT_LIMIT:
00143       return "limit";
00144     case ELEMENT_ALLOW:
00145       return "allow";
00146     case ELEMENT_DENY:
00147       return "deny";
00148     case ELEMENT_FORK:
00149       return "fork";
00150     case ELEMENT_PIDFILE:
00151       return "pidfile";
00152     case ELEMENT_SERVICEDIR:
00153       return "servicedir";
00154     case ELEMENT_INCLUDEDIR:
00155       return "includedir";
00156     case ELEMENT_TYPE:
00157       return "type";
00158     }
00159 
00160   _dbus_assert_not_reached ("bad element type");
00161 
00162   return NULL;
00163 }
00164 
00165 static Element*
00166 push_element (BusConfigParser *parser,
00167               ElementType      type)
00168 {
00169   Element *e;
00170 
00171   _dbus_assert (type != ELEMENT_NONE);
00172   
00173   e = dbus_new0 (Element, 1);
00174   if (e == NULL)
00175     return NULL;
00176 
00177   if (!_dbus_list_append (&parser->stack, e))
00178     {
00179       dbus_free (e);
00180       return NULL;
00181     }
00182   
00183   e->type = type;
00184 
00185   return e;
00186 }
00187 
00188 static void
00189 element_free (Element *e)
00190 {
00191   if (e->type == ELEMENT_LIMIT)
00192     dbus_free (e->d.limit.name);
00193   
00194   dbus_free (e);
00195 }
00196 
00197 static void
00198 pop_element (BusConfigParser *parser)
00199 {
00200   Element *e;
00201 
00202   e = _dbus_list_pop_last (&parser->stack);
00203   
00204   element_free (e);
00205 }
00206 
00207 static Element*
00208 peek_element (BusConfigParser *parser)
00209 {
00210   Element *e;
00211 
00212   e = _dbus_list_get_last (&parser->stack);
00213 
00214   return e;
00215 }
00216 
00217 static ElementType
00218 top_element_type (BusConfigParser *parser)
00219 {
00220   Element *e;
00221 
00222   e = _dbus_list_get_last (&parser->stack);
00223 
00224   if (e)
00225     return e->type;
00226   else
00227     return ELEMENT_NONE;
00228 }
00229 
00230 static dbus_bool_t
00231 merge_included (BusConfigParser *parser,
00232                 BusConfigParser *included,
00233                 DBusError       *error)
00234 {
00235   DBusList *link;
00236 
00237   if (!bus_policy_merge (parser->policy,
00238                          included->policy))
00239     {
00240       BUS_SET_OOM (error);
00241       return FALSE;
00242     }
00243   
00244   if (included->user != NULL)
00245     {
00246       dbus_free (parser->user);
00247       parser->user = included->user;
00248       included->user = NULL;
00249     }
00250 
00251   if (included->bus_type != NULL)
00252     {
00253       dbus_free (parser->bus_type);
00254       parser->bus_type = included->bus_type;
00255       included->bus_type = NULL;
00256     }
00257   
00258   if (included->fork)
00259     parser->fork = TRUE;
00260 
00261   if (included->pidfile != NULL)
00262     {
00263       dbus_free (parser->pidfile);
00264       parser->pidfile = included->pidfile;
00265       included->pidfile = NULL;
00266     }
00267   
00268   while ((link = _dbus_list_pop_first_link (&included->listen_on)))
00269     _dbus_list_append_link (&parser->listen_on, link);
00270 
00271   while ((link = _dbus_list_pop_first_link (&included->mechanisms)))
00272     _dbus_list_append_link (&parser->mechanisms, link);
00273 
00274   while ((link = _dbus_list_pop_first_link (&included->service_dirs)))
00275     _dbus_list_append_link (&parser->service_dirs, link);
00276   
00277   return TRUE;
00278 }
00279 
00280 BusConfigParser*
00281 bus_config_parser_new (const DBusString *basedir,
00282                        dbus_bool_t       is_toplevel)
00283 {
00284   BusConfigParser *parser;
00285 
00286   parser = dbus_new0 (BusConfigParser, 1);
00287   if (parser == NULL)
00288     return NULL;
00289 
00290   parser->is_toplevel = !!is_toplevel;
00291   
00292   if (!_dbus_string_init (&parser->basedir))
00293     {
00294       dbus_free (parser);
00295       return NULL;
00296     }
00297 
00298   if (((parser->policy = bus_policy_new ()) == NULL) ||
00299       !_dbus_string_copy (basedir, 0, &parser->basedir, 0))
00300     {
00301       if (parser->policy)
00302         bus_policy_unref (parser->policy);
00303       
00304       _dbus_string_free (&parser->basedir);
00305       dbus_free (parser);
00306       return NULL;
00307     }
00308 
00309   /* Make up some numbers! woot! */
00310   parser->limits.max_incoming_bytes = _DBUS_ONE_MEGABYTE * 63;
00311   parser->limits.max_outgoing_bytes = _DBUS_ONE_MEGABYTE * 63;
00312   parser->limits.max_message_size = _DBUS_ONE_MEGABYTE * 32;
00313 
00314   /* Making this long means the user has to wait longer for an error
00315    * message if something screws up, but making it too short means
00316    * they might see a false failure.
00317    */
00318   parser->limits.activation_timeout = 25000; /* 25 seconds */
00319 
00320   /* Making this long risks making a DOS attack easier, but too short
00321    * and legitimate auth will fail.  If interactive auth (ask user for
00322    * password) is allowed, then potentially it has to be quite long.
00323    */
00324   parser->limits.auth_timeout = 30000; /* 30 seconds */
00325 
00326   parser->limits.max_incomplete_connections = 32;
00327   parser->limits.max_connections_per_user = 128;
00328 
00329   /* Note that max_completed_connections / max_connections_per_user
00330    * is the number of users that would have to work together to
00331    * DOS all the other users.
00332    */
00333   parser->limits.max_completed_connections = 1024;
00334 
00335   parser->limits.max_pending_activations = 256;
00336   parser->limits.max_services_per_connection = 256;
00337 
00338   parser->limits.max_match_rules_per_connection = 128;
00339   
00340   parser->refcount = 1;
00341 
00342   return parser;
00343 }
00344 
00345 void
00346 bus_config_parser_ref (BusConfigParser *parser)
00347 {
00348   _dbus_assert (parser->refcount > 0);
00349 
00350   parser->refcount += 1;
00351 }
00352 
00353 void
00354 bus_config_parser_unref (BusConfigParser *parser)
00355 {
00356   _dbus_assert (parser->refcount > 0);
00357 
00358   parser->refcount -= 1;
00359 
00360   if (parser->refcount == 0)
00361     {
00362       while (parser->stack != NULL)
00363         pop_element (parser);
00364 
00365       dbus_free (parser->user);
00366       dbus_free (parser->bus_type);
00367       dbus_free (parser->pidfile);
00368       
00369       _dbus_list_foreach (&parser->listen_on,
00370                           (DBusForeachFunction) dbus_free,
00371                           NULL);
00372 
00373       _dbus_list_clear (&parser->listen_on);
00374 
00375       _dbus_list_foreach (&parser->service_dirs,
00376                           (DBusForeachFunction) dbus_free,
00377                           NULL);
00378 
00379       _dbus_list_clear (&parser->service_dirs);
00380 
00381       _dbus_list_foreach (&parser->mechanisms,
00382                           (DBusForeachFunction) dbus_free,
00383                           NULL);
00384 
00385       _dbus_list_clear (&parser->mechanisms);
00386       
00387       _dbus_string_free (&parser->basedir);
00388 
00389       if (parser->policy)
00390         bus_policy_unref (parser->policy);
00391       
00392       dbus_free (parser);
00393     }
00394 }
00395 
00396 dbus_bool_t
00397 bus_config_parser_check_doctype (BusConfigParser   *parser,
00398                                  const char        *doctype,
00399                                  DBusError         *error)
00400 {
00401   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00402 
00403   if (strcmp (doctype, "busconfig") != 0)
00404     {
00405       dbus_set_error (error,
00406                       DBUS_ERROR_FAILED,
00407                       "Configuration file has the wrong document type %s",
00408                       doctype);
00409       return FALSE;
00410     }
00411   else
00412     return TRUE;
00413 }
00414 
00415 typedef struct
00416 {
00417   const char  *name;
00418   const char **retloc;
00419 } LocateAttr;
00420 
00421 static dbus_bool_t
00422 locate_attributes (BusConfigParser  *parser,
00423                    const char       *element_name,
00424                    const char      **attribute_names,
00425                    const char      **attribute_values,
00426                    DBusError        *error,
00427                    const char       *first_attribute_name,
00428                    const char      **first_attribute_retloc,
00429                    ...)
00430 {
00431   va_list args;
00432   const char *name;
00433   const char **retloc;
00434   int n_attrs;
00435 #define MAX_ATTRS 24
00436   LocateAttr attrs[MAX_ATTRS];
00437   dbus_bool_t retval;
00438   int i;
00439 
00440   _dbus_assert (first_attribute_name != NULL);
00441   _dbus_assert (first_attribute_retloc != NULL);
00442 
00443   retval = TRUE;
00444 
00445   n_attrs = 1;
00446   attrs[0].name = first_attribute_name;
00447   attrs[0].retloc = first_attribute_retloc;
00448   *first_attribute_retloc = NULL;
00449 
00450   va_start (args, first_attribute_retloc);
00451 
00452   name = va_arg (args, const char*);
00453   retloc = va_arg (args, const char**);
00454 
00455   while (name != NULL)
00456     {
00457       _dbus_assert (retloc != NULL);
00458       _dbus_assert (n_attrs < MAX_ATTRS);
00459 
00460       attrs[n_attrs].name = name;
00461       attrs[n_attrs].retloc = retloc;
00462       n_attrs += 1;
00463       *retloc = NULL;
00464 
00465       name = va_arg (args, const char*);
00466       retloc = va_arg (args, const char**);
00467     }
00468 
00469   va_end (args);
00470 
00471   if (!retval)
00472     return retval;
00473 
00474   i = 0;
00475   while (attribute_names[i])
00476     {
00477       int j;
00478       dbus_bool_t found;
00479       
00480       found = FALSE;
00481       j = 0;
00482       while (j < n_attrs)
00483         {
00484           if (strcmp (attrs[j].name, attribute_names[i]) == 0)
00485             {
00486               retloc = attrs[j].retloc;
00487 
00488               if (*retloc != NULL)
00489                 {
00490                   dbus_set_error (error, DBUS_ERROR_FAILED,
00491                                   "Attribute \"%s\" repeated twice on the same <%s> element",
00492                                   attrs[j].name, element_name);
00493                   retval = FALSE;
00494                   goto out;
00495                 }
00496 
00497               *retloc = attribute_values[i];
00498               found = TRUE;
00499             }
00500 
00501           ++j;
00502         }
00503 
00504       if (!found)
00505         {
00506           dbus_set_error (error, DBUS_ERROR_FAILED,
00507                           "Attribute \"%s\" is invalid on <%s> element in this context",
00508                           attribute_names[i], element_name);
00509           retval = FALSE;
00510           goto out;
00511         }
00512 
00513       ++i;
00514     }
00515 
00516  out:
00517   return retval;
00518 }
00519 
00520 static dbus_bool_t
00521 check_no_attributes (BusConfigParser  *parser,
00522                      const char       *element_name,
00523                      const char      **attribute_names,
00524                      const char      **attribute_values,
00525                      DBusError        *error)
00526 {
00527   if (attribute_names[0] != NULL)
00528     {
00529       dbus_set_error (error, DBUS_ERROR_FAILED,
00530                       "Attribute \"%s\" is invalid on <%s> element in this context",
00531                       attribute_names[0], element_name);
00532       return FALSE;
00533     }
00534 
00535   return TRUE;
00536 }
00537 
00538 static dbus_bool_t
00539 start_busconfig_child (BusConfigParser   *parser,
00540                        const char        *element_name,
00541                        const char       **attribute_names,
00542                        const char       **attribute_values,
00543                        DBusError         *error)
00544 {
00545   if (strcmp (element_name, "user") == 0)
00546     {
00547       if (!check_no_attributes (parser, "user", attribute_names, attribute_values, error))
00548         return FALSE;
00549 
00550       if (push_element (parser, ELEMENT_USER) == NULL)
00551         {
00552           BUS_SET_OOM (error);
00553           return FALSE;
00554         }
00555 
00556       return TRUE;
00557     }
00558   else if (strcmp (element_name, "type") == 0)
00559     {
00560       if (!check_no_attributes (parser, "type", attribute_names, attribute_values, error))
00561         return FALSE;
00562 
00563       if (push_element (parser, ELEMENT_TYPE) == NULL)
00564         {
00565           BUS_SET_OOM (error);
00566           return FALSE;
00567         }
00568 
00569       return TRUE;
00570     }
00571   else if (strcmp (element_name, "fork") == 0)
00572     {
00573       if (!check_no_attributes (parser, "fork", attribute_names, attribute_values, error))
00574         return FALSE;
00575 
00576       if (push_element (parser, ELEMENT_FORK) == NULL)
00577         {
00578           BUS_SET_OOM (error);
00579           return FALSE;
00580         }
00581 
00582       parser->fork = TRUE;
00583       
00584       return TRUE;
00585     }
00586   else if (strcmp (element_name, "pidfile") == 0)
00587     {
00588       if (!check_no_attributes (parser, "pidfile", attribute_names, attribute_values, error))
00589         return FALSE;
00590 
00591       if (push_element (parser, ELEMENT_PIDFILE) == NULL)
00592         {
00593           BUS_SET_OOM (error);
00594           return FALSE;
00595         }
00596 
00597       return TRUE;
00598     }
00599   else if (strcmp (element_name, "listen") == 0)
00600     {
00601       if (!check_no_attributes (parser, "listen", attribute_names, attribute_values, error))
00602         return FALSE;
00603 
00604       if (push_element (parser, ELEMENT_LISTEN) == NULL)
00605         {
00606           BUS_SET_OOM (error);
00607           return FALSE;
00608         }
00609 
00610       return TRUE;
00611     }
00612   else if (strcmp (element_name, "auth") == 0)
00613     {
00614       if (!check_no_attributes (parser, "auth", attribute_names, attribute_values, error))
00615         return FALSE;
00616 
00617       if (push_element (parser, ELEMENT_AUTH) == NULL)
00618         {
00619           BUS_SET_OOM (error);
00620           return FALSE;
00621         }
00622 
00623       return TRUE;
00624     }
00625   else if (strcmp (element_name, "includedir") == 0)
00626     {
00627       if (!check_no_attributes (parser, "includedir", attribute_names, attribute_values, error))
00628         return FALSE;
00629 
00630       if (push_element (parser, ELEMENT_INCLUDEDIR) == NULL)
00631         {
00632           BUS_SET_OOM (error);
00633           return FALSE;
00634         }
00635 
00636       return TRUE;
00637     }
00638   else if (strcmp (element_name, "servicedir") == 0)
00639     {
00640       if (!check_no_attributes (parser, "servicedir", attribute_names, attribute_values, error))
00641         return FALSE;
00642 
00643       if (push_element (parser, ELEMENT_SERVICEDIR) == NULL)
00644         {
00645           BUS_SET_OOM (error);
00646           return FALSE;
00647         }
00648 
00649       return TRUE;
00650     }
00651   else if (strcmp (element_name, "include") == 0)
00652     {
00653       Element *e;
00654       const char *ignore_missing;
00655 
00656       if ((e = push_element (parser, ELEMENT_INCLUDE)) == NULL)
00657         {
00658           BUS_SET_OOM (error);
00659           return FALSE;
00660         }
00661 
00662       e->d.include.ignore_missing = FALSE;
00663 
00664       if (!locate_attributes (parser, "include",
00665                               attribute_names,
00666                               attribute_values,
00667                               error,
00668                               "ignore_missing", &ignore_missing,
00669                               NULL))
00670         return FALSE;
00671 
00672       if (ignore_missing != NULL)
00673         {
00674           if (strcmp (ignore_missing, "yes") == 0)
00675             e->d.include.ignore_missing = TRUE;
00676           else if (strcmp (ignore_missing, "no") == 0)
00677             e->d.include.ignore_missing = FALSE;
00678           else
00679             {
00680               dbus_set_error (error, DBUS_ERROR_FAILED,
00681                               "ignore_missing attribute must have value \"yes\" or \"no\"");
00682               return FALSE;
00683             }
00684         }
00685 
00686       return TRUE;
00687     }
00688   else if (strcmp (element_name, "policy") == 0)
00689     {
00690       Element *e;
00691       const char *context;
00692       const char *user;
00693       const char *group;
00694 
00695       if ((e = push_element (parser, ELEMENT_POLICY)) == NULL)
00696         {
00697           BUS_SET_OOM (error);
00698           return FALSE;
00699         }
00700 
00701       e->d.policy.type = POLICY_IGNORED;
00702       
00703       if (!locate_attributes (parser, "policy",
00704                               attribute_names,
00705                               attribute_values,
00706                               error,
00707                               "context", &context,
00708                               "user", &user,
00709                               "group", &group,
00710                               NULL))
00711         return FALSE;
00712 
00713       if (((context && user) ||
00714            (context && group)) ||
00715           (user && group) ||
00716           !(context || user || group))
00717         {
00718           dbus_set_error (error, DBUS_ERROR_FAILED,
00719                           "<policy> element must have exactly one of (context|user|group) attributes");
00720           return FALSE;
00721         }
00722 
00723       if (context != NULL)
00724         {
00725           if (strcmp (context, "default") == 0)
00726             {
00727               e->d.policy.type = POLICY_DEFAULT;
00728             }
00729           else if (strcmp (context, "mandatory") == 0)
00730             {
00731               e->d.policy.type = POLICY_MANDATORY;
00732             }
00733           else
00734             {
00735               dbus_set_error (error, DBUS_ERROR_FAILED,
00736                               "context attribute on <policy> must have the value \"default\" or \"mandatory\", not \"%s\"",
00737                               context);
00738               return FALSE;
00739             }
00740         }
00741       else if (user != NULL)
00742         {
00743           DBusString username;
00744           _dbus_string_init_const (&username, user);
00745 
00746           if (_dbus_get_user_id (&username,
00747                                  &e->d.policy.gid_or_uid))
00748             e->d.policy.type = POLICY_USER;
00749           else
00750             _dbus_warn ("Unknown username \"%s\" in message bus configuration file\n",
00751                         user);
00752         }
00753       else if (group != NULL)
00754         {
00755           DBusString group_name;
00756           _dbus_string_init_const (&group_name, group);
00757 
00758           if (_dbus_get_group_id (&group_name,
00759                                   &e->d.policy.gid_or_uid))
00760             e->d.policy.type = POLICY_GROUP;
00761           else
00762             _dbus_warn ("Unknown group \"%s\" in message bus configuration file\n",
00763                         group);          
00764         }
00765       else
00766         {
00767           _dbus_assert_not_reached ("all <policy> attributes null and we didn't set error");
00768         }
00769       
00770       return TRUE;
00771     }
00772   else if (strcmp (element_name, "limit") == 0)
00773     {
00774       Element *e;
00775       const char *name;
00776 
00777       if ((e = push_element (parser, ELEMENT_LIMIT)) == NULL)
00778         {
00779           BUS_SET_OOM (error);
00780           return FALSE;
00781         }
00782       
00783       if (!locate_attributes (parser, "limit",
00784                               attribute_names,
00785                               attribute_values,
00786                               error,
00787                               "name", &name,
00788                               NULL))
00789         return FALSE;
00790 
00791       if (name == NULL)
00792         {
00793           dbus_set_error (error, DBUS_ERROR_FAILED,
00794                           "<limit> element must have a \"name\" attribute");
00795           return FALSE;
00796         }
00797 
00798       e->d.limit.name = _dbus_strdup (name);
00799       if (e->d.limit.name == NULL)
00800         {
00801           BUS_SET_OOM (error);
00802           return FALSE;
00803         }
00804 
00805       return TRUE;
00806     }
00807   else
00808     {
00809       dbus_set_error (error, DBUS_ERROR_FAILED,
00810                       "Element <%s> not allowed inside <%s> in configuration file",
00811                       element_name, "busconfig");
00812       return FALSE;
00813     }
00814 }
00815 
00816 static int
00817 message_type_from_string (const char *type_str)
00818 {
00819   if (strcmp (type_str, "method_call") == 0)
00820     return DBUS_MESSAGE_TYPE_METHOD_CALL;
00821   if (strcmp (type_str, "method_return") == 0)
00822     return DBUS_MESSAGE_TYPE_METHOD_RETURN;
00823   else if (strcmp (type_str, "signal") == 0)
00824     return DBUS_MESSAGE_TYPE_SIGNAL;
00825   else if (strcmp (type_str, "error") == 0)
00826     return DBUS_MESSAGE_TYPE_ERROR;
00827   else
00828     return DBUS_MESSAGE_TYPE_INVALID;
00829 }
00830 
00831 static dbus_bool_t
00832 append_rule_from_element (BusConfigParser   *parser,
00833                           const char        *element_name,
00834                           const char       **attribute_names,
00835                           const char       **attribute_values,
00836                           dbus_bool_t        allow,
00837                           DBusError         *error)
00838 {
00839   const char *send_interface;
00840   const char *send_member;
00841   const char *send_error;
00842   const char *send_destination;
00843   const char *send_path;
00844   const char *send_type;
00845   const char *receive_interface;
00846   const char *receive_member;
00847   const char *receive_error;
00848   const char *receive_sender;
00849   const char *receive_path;
00850   const char *receive_type;
00851   const char *eavesdrop;
00852   const char *own;
00853   const char *user;
00854   const char *group;
00855   BusPolicyRule *rule;
00856   
00857   if (!locate_attributes (parser, element_name,
00858                           attribute_names,
00859                           attribute_values,
00860                           error,
00861                           "send_interface", &send_interface,
00862                           "send_member", &send_member,
00863                           "send_error", &send_error,
00864                           "send_destination", &send_destination,
00865                           "send_path", &send_path,
00866                           "send_type", &send_type,
00867                           "receive_interface", &receive_interface,
00868                           "receive_member", &receive_member,
00869                           "receive_error", &receive_error,
00870                           "receive_sender", &receive_sender,
00871                           "receive_path", &receive_path,
00872                           "receive_type", &receive_type,
00873                           "eavesdrop", &eavesdrop,
00874                           "own", &own,
00875                           "user", &user,
00876                           "group", &group,
00877                           NULL))
00878     return FALSE;
00879 
00880   if (!(send_interface || send_member || send_error || send_destination ||
00881         send_type || send_path ||
00882         receive_interface || receive_member || receive_error || receive_sender ||
00883         receive_type || receive_path || eavesdrop ||
00884         own || user || group))
00885     {
00886       dbus_set_error (error, DBUS_ERROR_FAILED,
00887                       "Element <%s> must have one or more attributes",
00888                       element_name);
00889       return FALSE;
00890     }
00891 
00892   if ((send_member && (send_interface == NULL && send_path == NULL)) ||
00893       (receive_member && (receive_interface == NULL && receive_path == NULL)))
00894     {
00895       dbus_set_error (error, DBUS_ERROR_FAILED,
00896                       "On element <%s>, if you specify a member you must specify an interface or a path. Keep in mind that not all messages have an interface field.",
00897                       element_name);
00898       return FALSE;
00899     }
00900   
00901   /* Allowed combinations of elements are:
00902    *
00903    *   base, must be all send or all receive:
00904    *     nothing
00905    *     interface
00906    *     interface + member
00907    *     error
00908    * 
00909    *   base send_ can combine with send_destination, send_path, send_type
00910    *   base receive_ with receive_sender, receive_path, receive_type, eavesdrop
00911    *
00912    *   user, group, own must occur alone
00913    *
00914    * Pretty sure the below stuff is broken, FIXME think about it more.
00915    */
00916 
00917   if (((send_interface && send_error) ||
00918        (send_interface && receive_interface) ||
00919        (send_interface && receive_member) ||
00920        (send_interface && receive_error) ||
00921        (send_interface && receive_sender) ||
00922        (send_interface && eavesdrop) ||
00923        (send_interface && own) ||
00924        (send_interface && user) ||
00925        (send_interface && group)) ||
00926 
00927       ((send_member && send_error) ||
00928        (send_member && receive_interface) ||
00929        (send_member && receive_member) ||
00930        (send_member && receive_error) ||
00931        (send_member && receive_sender) ||
00932        (send_member && eavesdrop) ||
00933        (send_member && own) ||
00934        (send_member && user) ||
00935        (send_member && group)) ||
00936       
00937       ((send_error && receive_interface) ||
00938        (send_error && receive_member) ||
00939        (send_error && receive_error) ||
00940        (send_error && receive_sender) ||
00941        (send_error && eavesdrop) ||
00942        (send_error && own) ||
00943        (send_error && user) ||
00944        (send_error && group)) ||
00945 
00946       ((send_destination && receive_interface) ||
00947        (send_destination && receive_member) ||
00948        (send_destination && receive_error) ||
00949        (send_destination && receive_sender) ||
00950        (send_destination && eavesdrop) ||
00951        (send_destination && own) ||
00952        (send_destination && user) ||
00953        (send_destination && group)) ||
00954 
00955       ((send_type && receive_interface) ||
00956        (send_type && receive_member) ||
00957        (send_type && receive_error) ||
00958        (send_type && receive_sender) ||
00959        (send_type && eavesdrop) ||
00960        (send_type && own) ||
00961        (send_type && user) ||
00962        (send_type && group)) ||
00963 
00964       ((send_path && receive_interface) ||
00965        (send_path && receive_member) ||
00966        (send_path && receive_error) ||
00967        (send_path && receive_sender) ||
00968        (send_path && eavesdrop) ||
00969        (send_path && own) ||
00970        (send_path && user) ||
00971        (send_path && group)) ||
00972       
00973       ((receive_interface && receive_error) ||
00974        (receive_interface && own) ||
00975        (receive_interface && user) ||
00976        (receive_interface && group)) ||
00977 
00978       ((receive_member && receive_error) ||
00979        (receive_member && own) ||
00980        (receive_member && user) ||
00981        (receive_member && group)) ||
00982       
00983       ((receive_error && own) ||
00984        (receive_error && user) ||
00985        (receive_error && group)) ||
00986 
00987       ((eavesdrop && own) ||
00988        (eavesdrop && user) ||
00989        (eavesdrop && group)) ||
00990       
00991       ((own && user) ||
00992        (own && group)) ||
00993 
00994       ((user && group)))
00995     {
00996       dbus_set_error (error, DBUS_ERROR_FAILED,
00997                       "Invalid combination of attributes on element <%s>",
00998                       element_name);
00999       return FALSE;
01000     }
01001   
01002   rule = NULL;
01003 
01004   /* In BusPolicyRule, NULL represents wildcard.
01005    * In the config file, '*' represents it.
01006    */
01007 #define IS_WILDCARD(str) ((str) && ((str)[0]) == '*' && ((str)[1]) == '\0')
01008 
01009   if (send_interface || send_member || send_error || send_destination ||
01010       send_path || send_type)
01011     {
01012       int message_type;
01013       
01014       if (IS_WILDCARD (send_interface))
01015         send_interface = NULL;
01016       if (IS_WILDCARD (send_member))
01017         send_member = NULL;
01018       if (IS_WILDCARD (send_error))
01019         send_error = NULL;
01020       if (IS_WILDCARD (send_destination))
01021         send_destination = NULL;
01022       if (IS_WILDCARD (send_path))
01023         send_path = NULL;
01024       if (IS_WILDCARD (send_type))
01025         send_type = NULL;
01026 
01027       message_type = DBUS_MESSAGE_TYPE_INVALID;
01028       if (send_type != NULL)
01029         {
01030           message_type = message_type_from_string (send_type);
01031           if (message_type == DBUS_MESSAGE_TYPE_INVALID)
01032             {
01033               dbus_set_error (error, DBUS_ERROR_FAILED,
01034                               "Bad message type \"%s\"",
01035                               send_type);
01036               return FALSE;
01037             }
01038         }
01039       
01040       rule = bus_policy_rule_new (BUS_POLICY_RULE_SEND, allow); 
01041       if (rule == NULL)
01042         goto nomem;
01043       
01044       rule->d.send.message_type = message_type;
01045       rule->d.send.path = _dbus_strdup (send_path);
01046       rule->d.send.interface = _dbus_strdup (send_interface);
01047       rule->d.send.member = _dbus_strdup (send_member);
01048       rule->d.send.error = _dbus_strdup (send_error);
01049       rule->d.send.destination = _dbus_strdup (send_destination);
01050       if (send_path && rule->d.send.path == NULL)
01051         goto nomem;
01052       if (send_interface && rule->d.send.interface == NULL)
01053         goto nomem;
01054       if (send_member && rule->d.send.member == NULL)
01055         goto nomem;
01056       if (send_error && rule->d.send.error == NULL)
01057         goto nomem;
01058       if (send_destination && rule->d.send.destination == NULL)
01059         goto nomem;
01060     }
01061   else if (receive_interface || receive_member || receive_error || receive_sender ||
01062            receive_path || receive_type || eavesdrop)
01063     {
01064       int message_type;
01065       
01066       if (IS_WILDCARD (receive_interface))
01067         receive_interface = NULL;
01068       if (IS_WILDCARD (receive_member))
01069         receive_member = NULL;
01070       if (IS_WILDCARD (receive_error))
01071         receive_error = NULL;
01072       if (IS_WILDCARD (receive_sender))
01073         receive_sender = NULL;
01074       if (IS_WILDCARD (receive_path))
01075         receive_path = NULL;
01076       if (IS_WILDCARD (receive_type))
01077         receive_type = NULL;
01078 
01079       message_type = DBUS_MESSAGE_TYPE_INVALID;
01080       if (receive_type != NULL)
01081         {
01082           message_type = message_type_from_string (receive_type);
01083           if (message_type == DBUS_MESSAGE_TYPE_INVALID)
01084             {
01085               dbus_set_error (error, DBUS_ERROR_FAILED,
01086                               "Bad message type \"%s\"",
01087                               receive_type);
01088               return FALSE;
01089             }
01090         }
01091 
01092 
01093       if (eavesdrop &&
01094           !(strcmp (eavesdrop, "true") == 0 ||
01095             strcmp (eavesdrop, "false") == 0))
01096         {
01097           dbus_set_error (error, DBUS_ERROR_FAILED,
01098                           "Bad value \"%s\" for eavesdrop attribute, must be true or false",
01099                           eavesdrop);
01100           return FALSE;
01101         }
01102       
01103       rule = bus_policy_rule_new (BUS_POLICY_RULE_RECEIVE, allow); 
01104       if (rule == NULL)
01105         goto nomem;
01106 
01107       if (eavesdrop)
01108         rule->d.receive.eavesdrop = (strcmp (eavesdrop, "true") == 0);
01109       
01110       rule->d.receive.message_type = message_type;
01111       rule->d.receive.path = _dbus_strdup (receive_path);
01112       rule->d.receive.interface = _dbus_strdup (receive_interface);
01113       rule->d.receive.member = _dbus_strdup (receive_member);
01114       rule->d.receive.error = _dbus_strdup (receive_error);
01115       rule->d.receive.origin = _dbus_strdup (receive_sender);
01116       if (receive_path && rule->d.receive.path == NULL)
01117         goto nomem;
01118       if (receive_interface && rule->d.receive.interface == NULL)
01119         goto nomem;
01120       if (receive_member && rule->d.receive.member == NULL)
01121         goto nomem;
01122       if (receive_error && rule->d.receive.error == NULL)
01123         goto nomem;
01124       if (receive_sender && rule->d.receive.origin == NULL)
01125         goto nomem;
01126     }
01127   else if (own)
01128     {
01129       rule = bus_policy_rule_new (BUS_POLICY_RULE_OWN, allow); 
01130       if (rule == NULL)
01131         goto nomem;
01132 
01133       if (IS_WILDCARD (own))
01134         own = NULL;
01135       
01136       rule->d.own.service_name = _dbus_strdup (own);
01137       if (own && rule->d.own.service_name == NULL)
01138         goto nomem;
01139     }
01140   else if (user)
01141     {      
01142       if (IS_WILDCARD (user))
01143         {
01144           rule = bus_policy_rule_new (BUS_POLICY_RULE_USER, allow); 
01145           if (rule == NULL)
01146             goto nomem;
01147 
01148           rule->d.user.uid = DBUS_UID_UNSET;
01149         }
01150       else
01151         {
01152           DBusString username;
01153           dbus_uid_t uid;
01154           
01155           _dbus_string_init_const (&username, user);
01156       
01157           if (_dbus_get_user_id (&username, &uid))
01158             {
01159               rule = bus_policy_rule_new (BUS_POLICY_RULE_USER, allow); 
01160               if (rule == NULL)
01161                 goto nomem;
01162 
01163               rule->d.user.uid = uid;
01164             }
01165           else
01166             {
01167               _dbus_warn ("Unknown username \"%s\" on element <%s>\n",
01168                           user, element_name);
01169             }
01170         }
01171     }
01172   else if (group)
01173     {
01174       if (IS_WILDCARD (group))
01175         {
01176           rule = bus_policy_rule_new (BUS_POLICY_RULE_GROUP, allow); 
01177           if (rule == NULL)
01178             goto nomem;
01179 
01180           rule->d.group.gid = DBUS_GID_UNSET;
01181         }
01182       else
01183         {
01184           DBusString groupname;
01185           dbus_gid_t gid;
01186           
01187           _dbus_string_init_const (&groupname, group);
01188           
01189           if (_dbus_get_user_id (&groupname, &gid))
01190             {
01191               rule = bus_policy_rule_new (BUS_POLICY_RULE_GROUP, allow); 
01192               if (rule == NULL)
01193                 goto nomem;
01194 
01195               rule->d.group.gid = gid;
01196             }
01197           else
01198             {
01199               _dbus_warn ("Unknown group \"%s\" on element <%s>\n",
01200                           group, element_name);
01201             }
01202         }
01203     }
01204   else
01205     _dbus_assert_not_reached ("Did not handle some combination of attributes on <allow> or <deny>");
01206 
01207   if (rule != NULL)
01208     {
01209       Element *pe;
01210       
01211       pe = peek_element (parser);      
01212       _dbus_assert (pe != NULL);
01213       _dbus_assert (pe->type == ELEMENT_POLICY);
01214 
01215       switch (pe->d.policy.type)
01216         {
01217         case POLICY_IGNORED:
01218           /* drop the rule on the floor */
01219           break;
01220           
01221         case POLICY_DEFAULT:
01222           if (!bus_policy_append_default_rule (parser->policy, rule))
01223             goto nomem;
01224           break;
01225         case POLICY_MANDATORY:
01226           if (!bus_policy_append_mandatory_rule (parser->policy, rule))
01227             goto nomem;
01228           break;
01229         case POLICY_USER:
01230           if (!BUS_POLICY_RULE_IS_PER_CLIENT (rule))
01231             {
01232               dbus_set_error (error, DBUS_ERROR_FAILED,
01233                               "<%s> rule cannot be per-user because it has bus-global semantics",
01234                               element_name);
01235               goto failed;
01236             }
01237           
01238           if (!bus_policy_append_user_rule (parser->policy, pe->d.policy.gid_or_uid,
01239                                             rule))
01240             goto nomem;
01241           break;
01242         case POLICY_GROUP:
01243           if (!BUS_POLICY_RULE_IS_PER_CLIENT (rule))
01244             {
01245               dbus_set_error (error, DBUS_ERROR_FAILED,
01246                               "<%s> rule cannot be per-group because it has bus-global semantics",
01247                               element_name);
01248               goto failed;
01249             }
01250           
01251           if (!bus_policy_append_group_rule (parser->policy, pe->d.policy.gid_or_uid,
01252                                              rule))
01253             goto nomem;
01254           break;
01255         }
01256       
01257       bus_policy_rule_unref (rule);
01258       rule = NULL;
01259     }
01260   
01261   return TRUE;
01262 
01263  nomem:
01264   BUS_SET_OOM (error);
01265  failed:
01266   if (rule)
01267     bus_policy_rule_unref (rule);
01268   return FALSE;
01269 }
01270 
01271 static dbus_bool_t
01272 start_policy_child (BusConfigParser   *parser,
01273                     const char        *element_name,
01274                     const char       **attribute_names,
01275                     const char       **attribute_values,
01276                     DBusError         *error)
01277 {
01278   if (strcmp (element_name, "allow") == 0)
01279     {
01280       if (!append_rule_from_element (parser, element_name,
01281                                      attribute_names, attribute_values,
01282                                      TRUE, error))
01283         return FALSE;
01284       
01285       if (push_element (parser, ELEMENT_ALLOW) == NULL)
01286         {
01287           BUS_SET_OOM (error);
01288           return FALSE;
01289         }
01290       
01291       return TRUE;
01292     }
01293   else if (strcmp (element_name, "deny") == 0)
01294     {
01295       if (!append_rule_from_element (parser, element_name,
01296                                      attribute_names, attribute_values,
01297                                      FALSE, error))
01298         return FALSE;
01299       
01300       if (push_element (parser, ELEMENT_DENY) == NULL)
01301         {
01302           BUS_SET_OOM (error);
01303           return FALSE;
01304         }
01305       
01306       return TRUE;
01307     }
01308   else
01309     {
01310       dbus_set_error (error, DBUS_ERROR_FAILED,
01311                       "Element <%s> not allowed inside <%s> in configuration file",
01312                       element_name, "policy");
01313       return FALSE;
01314     }
01315 }
01316 
01317 dbus_bool_t
01318 bus_config_parser_start_element (BusConfigParser   *parser,
01319                                  const char        *element_name,
01320                                  const char       **attribute_names,
01321                                  const char       **attribute_values,
01322                                  DBusError         *error)
01323 {
01324   ElementType t;
01325 
01326   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
01327 
01328   /* printf ("START: %s\n", element_name); */
01329   
01330   t = top_element_type (parser);
01331 
01332   if (t == ELEMENT_NONE)
01333     {
01334       if (strcmp (element_name, "busconfig") == 0)
01335         {
01336           if (!check_no_attributes (parser, "busconfig", attribute_names, attribute_values, error))
01337             return FALSE;
01338           
01339           if (push_element (parser, ELEMENT_BUSCONFIG) == NULL)
01340             {
01341               BUS_SET_OOM (error);
01342               return FALSE;
01343             }
01344 
01345           return TRUE;
01346         }
01347       else
01348         {
01349           dbus_set_error (error, DBUS_ERROR_FAILED,
01350                           "Unknown element <%s> at root of configuration file",
01351                           element_name);
01352           return FALSE;
01353         }
01354     }
01355   else if (t == ELEMENT_BUSCONFIG)
01356     {
01357       return start_busconfig_child (parser, element_name,
01358                                     attribute_names, attribute_values,
01359                                     error);
01360     }
01361   else if (t == ELEMENT_POLICY)
01362     {
01363       return start_policy_child (parser, element_name,
01364                                  attribute_names, attribute_values,
01365                                  error);
01366     }
01367   else
01368     {
01369       dbus_set_error (error, DBUS_ERROR_FAILED,
01370                       "Element <%s> is not allowed in this context",
01371                       element_name);
01372       return FALSE;
01373     }  
01374 }
01375 
01376 static dbus_bool_t
01377 set_limit (BusConfigParser *parser,
01378            const char      *name,
01379            long             value,
01380            DBusError       *error)
01381 {
01382   dbus_bool_t must_be_positive;
01383   dbus_bool_t must_be_int;
01384 
01385   must_be_int = FALSE;
01386   must_be_positive = FALSE;
01387   
01388   if (strcmp (name, "max_incoming_bytes") == 0)
01389     {
01390       must_be_positive = TRUE;
01391       parser->limits.max_incoming_bytes = value;
01392     }
01393   else if (strcmp (name, "max_outgoing_bytes") == 0)
01394     {
01395       must_be_positive = TRUE;
01396       parser->limits.max_outgoing_bytes = value;
01397     }
01398   else if (strcmp (name, "max_message_size") == 0)
01399     {
01400       must_be_positive = TRUE;
01401       parser->limits.max_message_size = value;
01402     }
01403   else if (strcmp (name, "activation_timeout") == 0)
01404     {
01405       must_be_positive = TRUE;
01406       must_be_int = TRUE;
01407       parser->limits.activation_timeout = value;
01408     }
01409   else if (strcmp (name, "auth_timeout") == 0)
01410     {
01411       must_be_positive = TRUE;
01412       must_be_int = TRUE;
01413       parser->limits.auth_timeout = value;
01414     }
01415   else if (strcmp (name, "max_completed_connections") == 0)
01416     {
01417       must_be_positive = TRUE;
01418       must_be_int = TRUE;
01419       parser->limits.max_completed_connections = value;
01420     }
01421   else if (strcmp (name, "max_incomplete_connections") == 0)
01422     {
01423       must_be_positive = TRUE;
01424       must_be_int = TRUE;
01425       parser->limits.max_incomplete_connections = value;
01426     }
01427   else if (strcmp (name, "max_connections_per_user") == 0)
01428     {
01429       must_be_positive = TRUE;
01430       must_be_int = TRUE;
01431       parser->limits.max_connections_per_user = value;
01432     }
01433   else if (strcmp (name, "max_pending_activations") == 0)
01434     {
01435       must_be_positive = TRUE;
01436       must_be_int = TRUE;
01437       parser->limits.max_pending_activations = value;
01438     }
01439   else if (strcmp (name, "max_services_per_connection") == 0)
01440     {
01441       must_be_positive = TRUE;
01442       must_be_int = TRUE;
01443       parser->limits.max_services_per_connection = value;
01444     }
01445   else
01446     {
01447       dbus_set_error (error, DBUS_ERROR_FAILED,
01448                       "There is no limit called \"%s\"\n",
01449                       name);
01450       return FALSE;
01451     }
01452   
01453   if (must_be_positive && value < 0)
01454     {
01455       dbus_set_error (error, DBUS_ERROR_FAILED,
01456                       "<limit name=\"%s\"> must be a positive number\n",
01457                       name);
01458       return FALSE;
01459     }
01460 
01461   if (must_be_int &&
01462       (value < _DBUS_INT_MIN || value > _DBUS_INT_MAX))
01463     {
01464       dbus_set_error (error, DBUS_ERROR_FAILED,
01465                       "<limit name=\"%s\"> value is too large\n",
01466                       name);
01467       return FALSE;
01468     }
01469 
01470   return TRUE;  
01471 }
01472 
01473 dbus_bool_t
01474 bus_config_parser_end_element (BusConfigParser   *parser,
01475                                const char        *element_name,
01476                                DBusError         *error)
01477 {
01478   ElementType t;
01479   const char *n;
01480   Element *e;
01481 
01482   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
01483 
01484   /* printf ("END: %s\n", element_name); */
01485   
01486   t = top_element_type (parser);
01487 
01488   if (t == ELEMENT_NONE)
01489     {
01490       /* should probably be an assertion failure but
01491        * being paranoid about XML parsers
01492        */
01493       dbus_set_error (error, DBUS_ERROR_FAILED,
01494                       "XML parser ended element with no element on the stack");
01495       return FALSE;
01496     }
01497 
01498   n = element_type_to_name (t);
01499   _dbus_assert (n != NULL);
01500   if (strcmp (n, element_name) != 0)
01501     {
01502       /* should probably be an assertion failure but
01503        * being paranoid about XML parsers
01504        */
01505       dbus_set_error (error, DBUS_ERROR_FAILED,
01506                       "XML element <%s> ended but topmost element on the stack was <%s>",
01507                       element_name, n);
01508       return FALSE;
01509     }
01510 
01511   e = peek_element (parser);
01512   _dbus_assert (e != NULL);
01513 
01514   switch (e->type)
01515     {
01516     case ELEMENT_NONE:
01517       _dbus_assert_not_reached ("element in stack has no type");
01518       break;
01519 
01520     case ELEMENT_INCLUDE:
01521     case ELEMENT_USER:
01522     case ELEMENT_TYPE:
01523     case ELEMENT_LISTEN:
01524     case ELEMENT_PIDFILE:
01525     case ELEMENT_AUTH:
01526     case ELEMENT_SERVICEDIR:
01527     case ELEMENT_INCLUDEDIR:
01528     case ELEMENT_LIMIT:
01529       if (!e->had_content)
01530         {
01531           dbus_set_error (error, DBUS_ERROR_FAILED,
01532                           "XML element <%s> was expected to have content inside it",
01533                           element_type_to_name (e->type));
01534           return FALSE;
01535         }
01536 
01537       if (e->type == ELEMENT_LIMIT)
01538         {
01539           if (!set_limit (parser, e->d.limit.name, e->d.limit.value,
01540                           error))
01541             return FALSE;
01542         }
01543       break;
01544 
01545     case ELEMENT_BUSCONFIG:
01546     case ELEMENT_POLICY:
01547     case ELEMENT_ALLOW:
01548     case ELEMENT_DENY:
01549     case ELEMENT_FORK:
01550       break;
01551     }
01552 
01553   pop_element (parser);
01554 
01555   return TRUE;
01556 }
01557 
01558 static dbus_bool_t
01559 all_whitespace (const DBusString *str)
01560 {
01561   int i;
01562 
01563   _dbus_string_skip_white (str, 0, &i);
01564 
01565   return i == _dbus_string_get_length (str);
01566 }
01567 
01568 static dbus_bool_t
01569 make_full_path (const DBusString *basedir,
01570                 const DBusString *filename,
01571                 DBusString       *full_path)
01572 {
01573   if (_dbus_path_is_absolute (filename))
01574     {
01575       return _dbus_string_copy (filename, 0, full_path, 0);
01576     }
01577   else
01578     {
01579       if (!_dbus_string_copy (basedir, 0, full_path, 0))
01580         return FALSE;
01581       
01582       if (!_dbus_concat_dir_and_file (full_path, filename))
01583         return FALSE;
01584 
01585       return TRUE;
01586     }
01587 }
01588 
01589 static dbus_bool_t
01590 include_file (BusConfigParser   *parser,
01591               const DBusString  *filename,
01592               dbus_bool_t        ignore_missing,
01593               DBusError         *error)
01594 {
01595   /* FIXME good test case for this would load each config file in the
01596    * test suite both alone, and as an include, and check
01597    * that the result is the same
01598    */
01599   BusConfigParser *included;
01600   DBusError tmp_error;
01601         
01602   dbus_error_init (&tmp_error);
01603   included = bus_config_load (filename, FALSE, &tmp_error);
01604   if (included == NULL)
01605     {
01606       _DBUS_ASSERT_ERROR_IS_SET (&tmp_error);
01607 
01608       if (dbus_error_has_name (&tmp_error, DBUS_ERROR_FILE_NOT_FOUND) &&
01609           ignore_missing)
01610         {
01611           dbus_error_free (&tmp_error);
01612           return TRUE;
01613         }
01614       else
01615         {
01616           dbus_move_error (&tmp_error, error);
01617           return FALSE;
01618         }
01619     }
01620   else
01621     {
01622       _DBUS_ASSERT_ERROR_IS_CLEAR (&tmp_error);
01623 
01624       if (!merge_included (parser, included, error))
01625         {
01626           bus_config_parser_unref (included);
01627           return FALSE;
01628         }
01629 
01630       bus_config_parser_unref (included);
01631       return TRUE;
01632     }
01633 }
01634 
01635 static dbus_bool_t
01636 include_dir (BusConfigParser   *parser,
01637              const DBusString  *dirname,
01638              DBusError         *error)
01639 {
01640   DBusString filename;
01641   dbus_bool_t retval;
01642   DBusError tmp_error;
01643   DBusDirIter *dir;
01644   
01645   if (!_dbus_string_init (&filename))
01646     {
01647       BUS_SET_OOM (error);
01648       return FALSE;
01649     }
01650 
01651   retval = FALSE;
01652   
01653   dir = _dbus_directory_open (dirname, error);
01654 
01655   if (dir == NULL)
01656     goto failed;
01657 
01658   dbus_error_init (&tmp_error);
01659   while (_dbus_directory_get_next_file (dir, &filename, &tmp_error))
01660     {
01661       DBusString full_path;
01662 
01663       if (!_dbus_string_init (&full_path))
01664         {
01665           BUS_SET_OOM (error);
01666           goto failed;
01667         }
01668 
01669       if (!_dbus_string_copy (dirname, 0, &full_path, 0))
01670         {
01671           BUS_SET_OOM (error);
01672           _dbus_string_free (&full_path);
01673           goto failed;
01674         }      
01675 
01676       if (!_dbus_concat_dir_and_file (&full_path, &filename))
01677         {
01678           BUS_SET_OOM (error);
01679           _dbus_string_free (&full_path);
01680           goto failed;
01681         }
01682       
01683       if (_dbus_string_ends_with_c_str (&full_path, ".conf"))
01684         {
01685           if (!include_file (parser, &full_path, TRUE, error))
01686             {
01687               _dbus_string_free (&full_path);
01688               goto failed;
01689             }
01690         }
01691 
01692       _dbus_string_free (&full_path);
01693     }
01694 
01695   if (dbus_error_is_set (&tmp_error))
01696     {
01697       dbus_move_error (&tmp_error, error);
01698       goto failed;
01699     }
01700   
01701   retval = TRUE;
01702   
01703  failed:
01704   _dbus_string_free (&filename);
01705   
01706   if (dir)
01707     _dbus_directory_close (dir);
01708 
01709   return retval;
01710 }
01711 
01712 dbus_bool_t
01713 bus_config_parser_content (BusConfigParser   *parser,
01714                            const DBusString  *content,
01715                            DBusError         *error)
01716 {
01717   Element *e;
01718 
01719   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
01720 
01721 #if 0
01722   {
01723     const char *c_str;
01724     
01725     _dbus_string_get_const_data (content, &c_str);
01726 
01727     printf ("CONTENT %d bytes: %s\n", _dbus_string_get_length (content), c_str);
01728   }
01729 #endif
01730   
01731   e = peek_element (parser);
01732   if (e == NULL)
01733     {
01734       dbus_set_error (error, DBUS_ERROR_FAILED,
01735                       "Text content outside of any XML element in configuration file");
01736       return FALSE;
01737     }
01738   else if (e->had_content)
01739     {
01740       _dbus_assert_not_reached ("Element had multiple content blocks");
01741       return FALSE;
01742     }
01743 
01744   switch (top_element_type (parser))
01745     {
01746     case ELEMENT_NONE:
01747       _dbus_assert_not_reached ("element at top of stack has no type");
01748       return FALSE;
01749 
01750     case ELEMENT_BUSCONFIG:
01751     case ELEMENT_POLICY:
01752     case ELEMENT_ALLOW:
01753     case ELEMENT_DENY:
01754     case ELEMENT_FORK:
01755       if (all_whitespace (content))
01756         return TRUE;
01757       else
01758         {
01759           dbus_set_error (error, DBUS_ERROR_FAILED,
01760                           "No text content expected inside XML element %s in configuration file",
01761                           element_type_to_name (top_element_type (parser)));
01762           return FALSE;
01763         }
01764 
01765     case ELEMENT_PIDFILE:
01766       {
01767         char *s;
01768 
01769         e->had_content = TRUE;
01770         
01771         if (!_dbus_string_copy_data (content, &s))
01772           goto nomem;
01773           
01774         dbus_free (parser->pidfile);
01775         parser->pidfile = s;
01776       }
01777       break;
01778 
01779     case ELEMENT_INCLUDE:
01780       {
01781         DBusString full_path;
01782         
01783         e->had_content = TRUE;
01784 
01785         if (!_dbus_string_init (&full_path))
01786           goto nomem;
01787         
01788         if (!make_full_path (&parser->basedir, content, &full_path))
01789           {
01790             _dbus_string_free (&full_path);
01791             goto nomem;
01792           }
01793         
01794         if (!include_file (parser, &full_path,
01795                            e->d.include.ignore_missing, error))
01796           {
01797             _dbus_string_free (&full_path);
01798             return FALSE;
01799           }
01800 
01801         _dbus_string_free (&full_path);
01802       }
01803       break;
01804 
01805     case ELEMENT_INCLUDEDIR:
01806       {
01807         DBusString full_path;
01808         
01809         e->had_content = TRUE;
01810 
01811         if (!_dbus_string_init (&full_path))
01812           goto nomem;
01813         
01814         if (!make_full_path (&parser->basedir, content, &full_path))
01815           {
01816             _dbus_string_free (&full_path);
01817             goto nomem;
01818           }
01819         
01820         if (!include_dir (parser, &full_path, error))
01821           {
01822             _dbus_string_free (&full_path);
01823             return FALSE;
01824           }
01825 
01826         _dbus_string_free (&full_path);
01827       }
01828       break;
01829       
01830     case ELEMENT_USER:
01831       {
01832         char *s;
01833 
01834         e->had_content = TRUE;
01835         
01836         if (!_dbus_string_copy_data (content, &s))
01837           goto nomem;
01838           
01839         dbus_free (parser->user);
01840         parser->user = s;
01841       }
01842       break;
01843 
01844     case ELEMENT_TYPE:
01845       {
01846         char *s;
01847 
01848         e->had_content = TRUE;
01849 
01850         if (!_dbus_string_copy_data (content, &s))
01851           goto nomem;
01852         
01853         dbus_free (parser->bus_type);
01854         parser->bus_type = s;
01855       }
01856       break;
01857       
01858     case ELEMENT_LISTEN:
01859       {
01860         char *s;
01861 
01862         e->had_content = TRUE;
01863         
01864         if (!_dbus_string_copy_data (content, &s))
01865           goto nomem;
01866 
01867         if (!_dbus_list_append (&parser->listen_on,
01868                                 s))
01869           {
01870             dbus_free (s);
01871             goto nomem;
01872           }
01873       }
01874       break;
01875 
01876     case ELEMENT_AUTH:
01877       {
01878         char *s;
01879         
01880         e->had_content = TRUE;
01881 
01882         if (!_dbus_string_copy_data (content, &s))
01883           goto nomem;
01884 
01885         if (!_dbus_list_append (&parser->mechanisms,
01886                                 s))
01887           {
01888             dbus_free (s);
01889             goto nomem;
01890           }
01891       }
01892       break;
01893 
01894     case ELEMENT_SERVICEDIR:
01895       {
01896         char *s;
01897         DBusString full_path;
01898         
01899         e->had_content = TRUE;
01900 
01901         if (!_dbus_string_init (&full_path))
01902           goto nomem;
01903         
01904         if (!make_full_path (&parser->basedir, content, &full_path))
01905           {
01906             _dbus_string_free (&full_path);
01907             goto nomem;
01908           }
01909         
01910         if (!_dbus_string_copy_data (&full_path, &s))
01911           {
01912             _dbus_string_free (&full_path);
01913             goto nomem;
01914           }
01915 
01916         if (!_dbus_list_append (&parser->service_dirs, s))
01917           {
01918             _dbus_string_free (&full_path);
01919             dbus_free (s);
01920             goto nomem;
01921           }
01922 
01923         _dbus_string_free (&full_path);
01924       }
01925       break;
01926 
01927     case ELEMENT_LIMIT:
01928       {
01929         long val;
01930 
01931         e->had_content = TRUE;
01932 
01933         val = 0;
01934         if (!_dbus_string_parse_int (content, 0, &val, NULL))
01935           {
01936             dbus_set_error (error, DBUS_ERROR_FAILED,
01937                             "<limit name=\"%s\"> element has invalid value (could not parse as integer)",
01938                             e->d.limit.name);
01939             return FALSE;
01940           }
01941 
01942         e->d.limit.value = val;
01943 
01944         _dbus_verbose ("Loaded value %ld for limit %s\n",
01945                        e->d.limit.value,
01946                        e->d.limit.name);
01947       }
01948       break;
01949     }
01950 
01951   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
01952   return TRUE;
01953 
01954  nomem:
01955   BUS_SET_OOM (error);
01956   return FALSE;
01957 }
01958 
01959 dbus_bool_t
01960 bus_config_parser_finished (BusConfigParser   *parser,
01961                             DBusError         *error)
01962 {
01963   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
01964 
01965   if (parser->stack != NULL)
01966     {
01967       dbus_set_error (error, DBUS_ERROR_FAILED,
01968                       "Element <%s> was not closed in configuration file",
01969                       element_type_to_name (top_element_type (parser)));
01970 
01971       return FALSE;
01972     }
01973 
01974   if (parser->is_toplevel && parser->listen_on == NULL)
01975     {
01976       dbus_set_error (error, DBUS_ERROR_FAILED,
01977                       "Configuration file needs one or more <listen> elements giving addresses"); 
01978       return FALSE;
01979     }
01980   
01981   return TRUE;
01982 }
01983 
01984 const char*
01985 bus_config_parser_get_user (BusConfigParser *parser)
01986 {
01987   return parser->user;
01988 }
01989 
01990 const char*
01991 bus_config_parser_get_type (BusConfigParser *parser)
01992 {
01993   return parser->bus_type;
01994 }
01995 
01996 DBusList**
01997 bus_config_parser_get_addresses (BusConfigParser *parser)
01998 {
01999   return &parser->listen_on;
02000 }
02001 
02002 DBusList**
02003 bus_config_parser_get_mechanisms (BusConfigParser *parser)
02004 {
02005   return &parser->mechanisms;
02006 }
02007 
02008 DBusList**
02009 bus_config_parser_get_service_dirs (BusConfigParser *parser)
02010 {
02011   return &parser->service_dirs;
02012 }
02013 
02014 dbus_bool_t
02015 bus_config_parser_get_fork (BusConfigParser   *parser)
02016 {
02017   return parser->fork;
02018 }
02019 
02020 const char *
02021 bus_config_parser_get_pidfile (BusConfigParser   *parser)
02022 {
02023   return parser->pidfile;
02024 }
02025 
02026 BusPolicy*
02027 bus_config_parser_steal_policy (BusConfigParser *parser)
02028 {
02029   BusPolicy *policy;
02030 
02031   _dbus_assert (parser->policy != NULL); /* can only steal the policy 1 time */
02032   
02033   policy = parser->policy;
02034 
02035   parser->policy = NULL;
02036 
02037   return policy;
02038 }
02039 
02040 /* Overwrite any limits that were set in the configuration file */
02041 void
02042 bus_config_parser_get_limits (BusConfigParser *parser,
02043                               BusLimits       *limits)
02044 {
02045   *limits = parser->limits;
02046 }
02047 
02048 #ifdef DBUS_BUILD_TESTS
02049 #include <stdio.h>
02050 
02051 typedef enum
02052 {
02053   VALID,
02054   INVALID,
02055   UNKNOWN
02056 } Validity;
02057 
02058 static dbus_bool_t
02059 do_load (const DBusString *full_path,
02060          Validity          validity,
02061          dbus_bool_t       oom_possible)
02062 {
02063   BusConfigParser *parser;
02064   DBusError error;
02065 
02066   dbus_error_init (&error);
02067 
02068   parser = bus_config_load (full_path, TRUE, &error);
02069   if (parser == NULL)
02070     {
02071       _DBUS_ASSERT_ERROR_IS_SET (&error);
02072 
02073       if (oom_possible &&
02074           dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY))
02075         {
02076           _dbus_verbose ("Failed to load valid file due to OOM\n");
02077           dbus_error_free (&error);
02078           return TRUE;
02079         }
02080       else if (validity == VALID)
02081         {
02082           _dbus_warn ("Failed to load valid file but still had memory: %s\n",
02083                       error.message);
02084 
02085           dbus_error_free (&error);
02086           return FALSE;
02087         }
02088       else
02089         {
02090           dbus_error_free (&error);
02091           return TRUE;
02092         }
02093     }
02094   else
02095     {
02096       _DBUS_ASSERT_ERROR_IS_CLEAR (&error);
02097 
02098       bus_config_parser_unref (parser);
02099 
02100       if (validity == INVALID)
02101         {
02102           _dbus_warn ("Accepted invalid file\n");
02103           return FALSE;
02104         }
02105 
02106       return TRUE;
02107     }
02108 }
02109 
02110 typedef struct
02111 {
02112   const DBusString *full_path;
02113   Validity          validity;
02114 } LoaderOomData;
02115 
02116 static dbus_bool_t
02117 check_loader_oom_func (void *data)
02118 {
02119   LoaderOomData *d = data;
02120 
02121   return do_load (d->full_path, d->validity, TRUE);
02122 }
02123 
02124 static dbus_bool_t
02125 process_test_subdir (const DBusString *test_base_dir,
02126                      const char       *subdir,
02127                      Validity          validity)
02128 {
02129   DBusString test_directory;
02130   DBusString filename;
02131   DBusDirIter *dir;
02132   dbus_bool_t retval;
02133   DBusError error;
02134 
02135   retval = FALSE;
02136   dir = NULL;
02137 
02138   if (!_dbus_string_init (&test_directory))
02139     _dbus_assert_not_reached ("didn't allocate test_directory\n");
02140 
02141   _dbus_string_init_const (&filename, subdir);
02142 
02143   if (!_dbus_string_copy (test_base_dir, 0,
02144                           &test_directory, 0))
02145     _dbus_assert_not_reached ("couldn't copy test_base_dir to test_directory");
02146 
02147   if (!_dbus_concat_dir_and_file (&test_directory, &filename))
02148     _dbus_assert_not_reached ("couldn't allocate full path");
02149 
02150   _dbus_string_free (&filename);
02151   if (!_dbus_string_init (&filename))
02152     _dbus_assert_not_reached ("didn't allocate filename string\n");
02153 
02154   dbus_error_init (&error);
02155   dir = _dbus_directory_open (&test_directory, &error);
02156   if (dir == NULL)
02157     {
02158       _dbus_warn ("Could not open %s: %s\n",
02159                   _dbus_string_get_const_data (&test_directory),
02160                   error.message);
02161       dbus_error_free (&error);
02162       goto failed;
02163     }
02164 
02165   printf ("Testing:\n");
02166 
02167  next:
02168   while (_dbus_directory_get_next_file (dir, &filename, &error))
02169     {
02170       DBusString full_path;
02171       LoaderOomData d;
02172 
02173       if (!_dbus_string_init (&full_path))
02174         _dbus_assert_not_reached ("couldn't init string");
02175 
02176       if (!_dbus_string_copy (&test_directory, 0, &full_path, 0))
02177         _dbus_assert_not_reached ("couldn't copy dir to full_path");
02178 
02179       if (!_dbus_concat_dir_and_file (&full_path, &filename))
02180         _dbus_assert_not_reached ("couldn't concat file to dir");
02181 
02182       if (!_dbus_string_ends_with_c_str (&full_path, ".conf"))
02183         {
02184           _dbus_verbose ("Skipping non-.conf file %s\n",
02185                          _dbus_string_get_const_data (&filename));
02186           _dbus_string_free (&full_path);
02187           goto next;
02188         }
02189 
02190       printf ("    %s\n", _dbus_string_get_const_data (&filename));
02191 
02192       _dbus_verbose (" expecting %s\n",
02193                      validity == VALID ? "valid" :
02194                      (validity == INVALID ? "invalid" :
02195                       (validity == UNKNOWN ? "unknown" : "???")));
02196 
02197       d.full_path = &full_path;
02198       d.validity = validity;
02199       if (!_dbus_test_oom_handling ("config-loader", check_loader_oom_func, &d))
02200         _dbus_assert_not_reached ("test failed");
02201 
02202       _dbus_string_free (&full_path);
02203     }
02204 
02205   if (dbus_error_is_set (&error))
02206     {
02207       _dbus_warn ("Could not get next file in %s: %s\n",
02208                   _dbus_string_get_const_data (&test_directory),
02209                   error.message);
02210       dbus_error_free (&error);
02211       goto failed;
02212     }
02213 
02214   retval = TRUE;
02215 
02216  failed:
02217 
02218   if (dir)
02219     _dbus_directory_close (dir);
02220   _dbus_string_free (&test_directory);
02221   _dbus_string_free (&filename);
02222 
02223   return retval;
02224 }
02225 
02226 dbus_bool_t
02227 bus_config_parser_test (const DBusString *test_data_dir)
02228 {
02229   if (test_data_dir == NULL ||
02230       _dbus_string_get_length (test_data_dir) == 0)
02231     {
02232       printf ("No test data\n");
02233       return TRUE;
02234     }
02235 
02236   if (!process_test_subdir (test_data_dir, "valid-config-files", VALID))
02237     return FALSE;
02238 
02239   return TRUE;
02240 }
02241 
02242 #endif /* DBUS_BUILD_TESTS */
02243 

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