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

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