(linenum→info "unix/slp.c:2238")

dbus/1.0.2/bus/config-parser.c

    1: /* -*- mode: C; c-file-style: "gnu" -*- */
    2: /* config-parser.c  XML-library-agnostic configuration file parser
    3:  *
    4:  * Copyright (C) 2003, 2004 Red Hat, Inc.
    5:  *
    6:  * Licensed under the Academic Free License version 2.1
    7:  *
    8:  * This program is free software; you can redistribute it and/or modify
    9:  * it under the terms of the GNU General Public License as published by
   10:  * the Free Software Foundation; either version 2 of the License, or
   11:  * (at your option) any later version.
   12:  *
   13:  * This program is distributed in the hope that it will be useful,
   14:  * but WITHOUT ANY WARRANTY; without even the implied warranty of
   15:  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   16:  * GNU General Public License for more details.
   17:  *
   18:  * You should have received a copy of the GNU General Public License
   19:  * along with this program; if not, write to the Free Software
   20:  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   21:  *
   22:  */
   23: #include "config-parser.h"
   24: #include "test.h"
   25: #include "utils.h"
   26: #include "policy.h"
   27: #include "selinux.h"
   28: #include <dbus/dbus-list.h>
   29: #include <dbus/dbus-internals.h>
   30: #include <string.h>
   31: 
   32: typedef enum
   33: {
   34:   ELEMENT_NONE,
   35:   ELEMENT_BUSCONFIG,
   36:   ELEMENT_INCLUDE,
   37:   ELEMENT_USER,
   38:   ELEMENT_LISTEN,
   39:   ELEMENT_AUTH,
   40:   ELEMENT_POLICY,
   41:   ELEMENT_LIMIT,
   42:   ELEMENT_ALLOW,
   43:   ELEMENT_DENY,
   44:   ELEMENT_FORK,
   45:   ELEMENT_PIDFILE,
   46:   ELEMENT_SERVICEDIR,
   47:   ELEMENT_INCLUDEDIR,
   48:   ELEMENT_TYPE,
   49:   ELEMENT_SELINUX,
   50:   ELEMENT_ASSOCIATE,
   51:   ELEMENT_STANDARD_SESSION_SERVICEDIRS
   52: } ElementType;
   53: 
   54: typedef enum
   55: {
   56:   /* we ignore policies for unknown groups/users */
   57:   POLICY_IGNORED,
   58: 
   59:   /* non-ignored */
   60:   POLICY_DEFAULT,
   61:   POLICY_MANDATORY,
   62:   POLICY_USER,
   63:   POLICY_GROUP,
   64:   POLICY_CONSOLE
   65: } PolicyType;
   66: 
   67: typedef struct
   68: {
   69:   ElementType type;
   70: 
   71:   unsigned int had_content : 1;
   72: 
   73:   union
   74:   {
   75:     struct
   76:     {
   77:       unsigned int ignore_missing : 1;
   78:       unsigned int if_selinux_enabled : 1;
   79:       unsigned int selinux_root_relative : 1;
   80:     } include;
   81: 
   82:     struct
   83:     {
   84:       PolicyType type;
   85:       unsigned long gid_uid_or_at_console;      
   86:     } policy;
   87: 
   88:     struct
   89:     {
   90:       char *name;
   91:       long value;
   92:     } limit;
   93:     
   94:   } d;
   95: 
   96: } Element;
   97: 
   98: /**
   99:  * Parser for bus configuration file. 
  100:  */
  101: struct BusConfigParser
  102: {
  103:   int refcount;        /**< Reference count */
  104: 
  105:   DBusString basedir;  /**< Directory we resolve paths relative to */
  106:   
  107:   DBusList *stack;     /**< stack of Element */
  108: 
  109:   char *user;          /**< user to run as */
  110: 
  111:   char *bus_type;          /**< Message bus type */
  112:   
  113:   DBusList *listen_on; /**< List of addresses to listen to */
  114: 
  115:   DBusList *mechanisms; /**< Auth mechanisms */
  116: 
  117:   DBusList *service_dirs; /**< Directories to look for services in */
  118: 
  119:   DBusList *conf_dirs;   /**< Directories to look for policy configuration in */
  120: 
  121:   BusPolicy *policy;     /**< Security policy */
  122: 
  123:   BusLimits limits;      /**< Limits */
  124: 
  125:   char *pidfile;         /**< PID file */
  126: 
  127:   DBusList *included_files;  /**< Included files stack */
  128: 
  129:   DBusHashTable *service_context_table; /**< Map service names to SELinux contexts */
  130: 
  131:   unsigned int fork : 1; /**< TRUE to fork into daemon mode */
  132: 
  133:   unsigned int is_toplevel : 1; /**< FALSE if we are a sub-config-file inside another one */
  134: };
  135: 
  136: static const char*
  137: element_type_to_name (ElementType type)
  138: {
  139:   switch (type)
  140:     {
  141:     case ELEMENT_NONE:
  142:       return NULL;
  143:     case ELEMENT_BUSCONFIG:
  144:       return "busconfig";
  145:     case ELEMENT_INCLUDE:
  146:       return "include";
  147:     case ELEMENT_USER:
  148:       return "user";
  149:     case ELEMENT_LISTEN:
  150:       return "listen";
  151:     case ELEMENT_AUTH:
  152:       return "auth";
  153:     case ELEMENT_POLICY:
  154:       return "policy";
  155:     case ELEMENT_LIMIT:
  156:       return "limit";
  157:     case ELEMENT_ALLOW:
  158:       return "allow";
  159:     case ELEMENT_DENY:
  160:       return "deny";
  161:     case ELEMENT_FORK:
  162:       return "fork";
  163:     case ELEMENT_PIDFILE:
  164:       return "pidfile";
  165:     case ELEMENT_STANDARD_SESSION_SERVICEDIRS:
  166:       return "standard_session_servicedirs";
  167:     case ELEMENT_SERVICEDIR:
  168:       return "servicedir";
  169:     case ELEMENT_INCLUDEDIR:
  170:       return "includedir";
  171:     case ELEMENT_TYPE:
  172:       return "type";
  173:     case ELEMENT_SELINUX:
  174:       return "selinux";
  175:     case ELEMENT_ASSOCIATE:
  176:       return "associate";
  177:     }
  178: 
  179:   _dbus_assert_not_reached ("bad element type");
  180: 
  181:   return NULL;
  182: }
  183: 
  184: static Element*
  185: push_element (BusConfigParser *parser,
  186:               ElementType      type)
  187: {
  188:   Element *e;
  189: 
  190:   _dbus_assert (type != ELEMENT_NONE);
  191:   
  192:   e = dbus_new0 (Element, 1);
  193:   if (e == NULL)
  194:     return NULL;
  195: 
  196:   if (!_dbus_list_append (&parser->stack, e))
  197:     {
  198:       dbus_free (e);
  199:       return NULL;
  200:     }
  201:   
  202:   e->type = type;
  203: 
  204:   return e;
  205: }
  206: 
  207: static void
  208: element_free (Element *e)
  209: {
  210:   if (e->type == ELEMENT_LIMIT)
  211:     dbus_free (e->d.limit.name);
  212:   
  213:   dbus_free (e);
  214: }
  215: 
  216: static void
  217: pop_element (BusConfigParser *parser)
  218: {
  219:   Element *e;
  220: 
  221:   e = _dbus_list_pop_last (&parser->stack);
  222:   
  223:   element_free (e);
  224: }
  225: 
  226: static Element*
  227: peek_element (BusConfigParser *parser)
  228: {
  229:   Element *e;
  230: 
  231:   e = _dbus_list_get_last (&parser->stack);
  232: 
  233:   return e;
  234: }
  235: 
  236: static ElementType
  237: top_element_type (BusConfigParser *parser)
  238: {
  239:   Element *e;
  240: 
  241:   e = _dbus_list_get_last (&parser->stack);
  242: 
  243:   if (e)
  244:     return e->type;
  245:   else
  246:     return ELEMENT_NONE;
  247: }
  248: 
  249: static dbus_bool_t
  250: merge_service_context_hash (DBusHashTable *dest,
  251:                             DBusHashTable *from)
  252: {
  253:   DBusHashIter iter;
  254:   char *service_copy;
  255:   char *context_copy;
  256: 
  257:   service_copy = NULL;
  258:   context_copy = NULL;
  259: 
  260:   _dbus_hash_iter_init (from, &iter);
  261:   while (_dbus_hash_iter_next (&iter))
  262:     {
  263:       const char *service = _dbus_hash_iter_get_string_key (&iter);
  264:       const char *context = _dbus_hash_iter_get_value (&iter);
  265: 
  266:       service_copy = _dbus_strdup (service);
  267:       if (service_copy == NULL)
  268:         goto fail;
  269:       context_copy = _dbus_strdup (context);
  270:       if (context_copy == NULL)
  271:         goto fail; 
  272:       
  273:       if (!_dbus_hash_table_insert_string (dest, service_copy, context_copy))
  274:         goto fail;
  275: 
  276:       service_copy = NULL;
  277:       context_copy = NULL;    
  278:     }
  279: 
  280:   return TRUE;
  281: 
  282:  fail:
  283:   if (service_copy)
  284:     dbus_free (service_copy);
  285: 
  286:   if (context_copy)
  287:     dbus_free (context_copy);
  288: 
  289:   return FALSE;
  290: }
  291: 
  292: static dbus_bool_t
  293: service_dirs_find_dir (DBusList **service_dirs,
  294:                        const char *dir)
  295: {
  296:   DBusList *link;
  297: 
  298:   _dbus_assert (dir != NULL);
  299: 
  300:   for (link = *service_dirs; link; link = _dbus_list_get_next_link(service_dirs, link))
  301:     {
  302:       const char *link_dir;
  303:       
  304:       link_dir = (const char *)link->data;
  305:       if (strcmp (dir, link_dir) == 0)
  306:         return TRUE;
  307:     }
  308: 
  309:   return FALSE;
  310: }
  311: 
  312: static dbus_bool_t
  313: service_dirs_append_unique_or_free (DBusList **service_dirs,
  314:                                     char *dir)
  315: {
  316:   if (!service_dirs_find_dir (service_dirs, dir))
  317:     return _dbus_list_append (service_dirs, dir);  
  318: 
  319:   dbus_free (dir);
  320:   return TRUE;
  321: }
  322: 
  323: static void 
  324: service_dirs_append_link_unique_or_free (DBusList **service_dirs,
  325:                                          DBusList *dir_link)
  326: {
  327:   if (!service_dirs_find_dir (service_dirs, dir_link->data))
  328:     {
  329:       _dbus_list_append_link (service_dirs, dir_link);
  330:     }
  331:   else
  332:     {
  333:       dbus_free (dir_link->data);
  334:       _dbus_list_free_link (dir_link);
  335:     }
  336: }
  337: 
  338: static dbus_bool_t
  339: merge_included (BusConfigParser *parser,
  340:                 BusConfigParser *included,
  341:                 DBusError       *error)
  342: {
  343:   DBusList *link;
  344: 
  345:   if (!bus_policy_merge (parser->policy,
  346:                          included->policy))
  347:     {
  348:       BUS_SET_OOM (error);
  349:       return FALSE;
  350:     }
  351: 
  352:   if (!merge_service_context_hash (parser->service_context_table,
  353:                                    included->service_context_table))
  354:     {
  355:       BUS_SET_OOM (error);
  356:       return FALSE;
  357:     }
  358:   
  359:   if (included->user != NULL)
  360:     {
  361:       dbus_free (parser->user);
  362:       parser->user = included->user;
  363:       included->user = NULL;
  364:     }
  365: 
  366:   if (included->bus_type != NULL)
  367:     {
  368:       dbus_free (parser->bus_type);
  369:       parser->bus_type = included->bus_type;
  370:       included->bus_type = NULL;
  371:     }
  372:   
  373:   if (included->fork)
  374:     parser->fork = TRUE;
  375: 
  376:   if (included->pidfile != NULL)
  377:     {
  378:       dbus_free (parser->pidfile);
  379:       parser->pidfile = included->pidfile;
  380:       included->pidfile = NULL;
  381:     }
  382:   
  383:   while ((link = _dbus_list_pop_first_link (&included->listen_on)))
  384:     _dbus_list_append_link (&parser->listen_on, link);
  385: 
  386:   while ((link = _dbus_list_pop_first_link (&included->mechanisms)))
  387:     _dbus_list_append_link (&parser->mechanisms, link);
  388: 
  389:   while ((link = _dbus_list_pop_first_link (&included->service_dirs)))
  390:     service_dirs_append_link_unique_or_free (&parser->service_dirs, link);
  391: 
  392:   while ((link = _dbus_list_pop_first_link (&included->conf_dirs)))
  393:     _dbus_list_append_link (&parser->conf_dirs, link);
  394:   
  395:   return TRUE;
  396: }
  397: 
  398: static dbus_bool_t
  399: seen_include (BusConfigParser  *parser,
  400:               const DBusString *file)
  401: {
  402:   DBusList *iter;
  403: 
  404:   iter = parser->included_files;
  405:   while (iter != NULL)
  406:     {
  407:       if (! strcmp (_dbus_string_get_const_data (file), iter->data))
  408:         return TRUE;
  409: 
  410:       iter = _dbus_list_get_next_link (&parser->included_files, iter);
  411:     }
  412: 
  413:   return FALSE;
  414: }
  415: 
  416: BusConfigParser*
  417: bus_config_parser_new (const DBusString      *basedir,
  418:                        dbus_bool_t            is_toplevel,
  419:                        const BusConfigParser *parent)
  420: {
  421:   BusConfigParser *parser;
  422: 
  423:   parser = dbus_new0 (BusConfigParser, 1);
  424:   if (parser == NULL)
  425:     return NULL;
  426: 
  427:   parser->is_toplevel = !!is_toplevel;
  428:   
  429:   if (!_dbus_string_init (&parser->basedir))
  430:     {
  431:       dbus_free (parser);
  432:       return NULL;
  433:     }
  434: 
  435:   if (((parser->policy = bus_policy_new ()) == NULL) ||
  436:       !_dbus_string_copy (basedir, 0, &parser->basedir, 0) ||
  437:       ((parser->service_context_table = _dbus_hash_table_new (DBUS_HASH_STRING,
  438:                                                               dbus_free,
  439:                                                               dbus_free)) == NULL))
  440:     {
  441:       if (parser->policy)
  442:         bus_policy_unref (parser->policy);
  443:       
  444:       _dbus_string_free (&parser->basedir);
  445: 
  446:       dbus_free (parser);
  447:       return NULL;
  448:     }
  449: 
  450:   if (parent != NULL)
  451:     {
  452:       /* Initialize the parser's limits from the parent. */
  453:       parser->limits = parent->limits;
  454: 
  455:       /* Use the parent's list of included_files to avoid
  456:          circular inclusions. */
  457:       parser->included_files = parent->included_files;
  458:     }
  459:   else
  460:     {
  461: 
  462:       /* Make up some numbers! woot! */
  463:       parser->limits.max_incoming_bytes = _DBUS_ONE_MEGABYTE * 63;
  464:       parser->limits.max_outgoing_bytes = _DBUS_ONE_MEGABYTE * 63;
  465:       parser->limits.max_message_size = _DBUS_ONE_MEGABYTE * 32;
  466:       
  467:       /* Making this long means the user has to wait longer for an error
  468:        * message if something screws up, but making it too short means
  469:        * they might see a false failure.
  470:        */
  471:       parser->limits.activation_timeout = 25000; /* 25 seconds */
  472: 
  473:       /* Making this long risks making a DOS attack easier, but too short
  474:        * and legitimate auth will fail.  If interactive auth (ask user for
  475:        * password) is allowed, then potentially it has to be quite long.
  476:        */
  477:       parser->limits.auth_timeout = 30000; /* 30 seconds */
  478:       
  479:       parser->limits.max_incomplete_connections = 32;
  480:       parser->limits.max_connections_per_user = 128;
  481:       
  482:       /* Note that max_completed_connections / max_connections_per_user
  483:        * is the number of users that would have to work together to
  484:        * DOS all the other users.
  485:        */
  486:       parser->limits.max_completed_connections = 1024;
  487:       
  488:       parser->limits.max_pending_activations = 256;
  489:       parser->limits.max_services_per_connection = 256;
  490:       
  491:       parser->limits.max_match_rules_per_connection = 512;
  492:       
  493:       parser->limits.reply_timeout = 5 * 60 * 1000; /* 5 minutes */
  494:       parser->limits.max_replies_per_connection = 32;
  495:     }
  496:       
  497:   parser->refcount = 1;
  498:       
  499:   return parser;
  500: }
  501: 
  502: BusConfigParser *
  503: bus_config_parser_ref (BusConfigParser *parser)
  504: {
  505:   _dbus_assert (parser->refcount > 0);
  506: 
  507:   parser->refcount += 1;
  508: 
  509:   return parser;
  510: }
  511: 
  512: void
  513: bus_config_parser_unref (BusConfigParser *parser)
  514: {
  515:   _dbus_assert (parser->refcount > 0);
  516: 
  517:   parser->refcount -= 1;
  518: 
  519:   if (parser->refcount == 0)
  520:     {
  521:       while (parser->stack != NULL)
  522:         pop_element (parser);
  523: 
  524:       dbus_free (parser->user);
  525:       dbus_free (parser->bus_type);
  526:       dbus_free (parser->pidfile);
  527:       
  528:       _dbus_list_foreach (&parser->listen_on,
  529:                           (DBusForeachFunction) dbus_free,
  530:                           NULL);
  531: 
  532:       _dbus_list_clear (&parser->listen_on);
  533: 
  534:       _dbus_list_foreach (&parser->service_dirs,
  535:                           (DBusForeachFunction) dbus_free,
  536:                           NULL);
  537: 
  538:       _dbus_list_clear (&parser->service_dirs);
  539: 
  540:       _dbus_list_foreach (&parser->conf_dirs,
  541:                           (DBusForeachFunction) dbus_free,
  542:                           NULL);
  543: 
  544:       _dbus_list_clear (&parser->conf_dirs);
  545: 
  546:       _dbus_list_foreach (&parser->mechanisms,
  547:                           (DBusForeachFunction) dbus_free,
  548:                           NULL);
  549: 
  550:       _dbus_list_clear (&parser->mechanisms);
  551:       
  552:       _dbus_string_free (&parser->basedir);
  553: 
  554:       if (parser->policy)
  555:         bus_policy_unref (parser->policy);
  556: 
  557:       if (parser->service_context_table)
  558:         _dbus_hash_table_unref (parser->service_context_table);
  559:       
  560:       dbus_free (parser);
  561:     }
  562: }
  563: 
  564: dbus_bool_t
  565: bus_config_parser_check_doctype (BusConfigParser   *parser,
  566:                                  const char        *doctype,
  567:                                  DBusError         *error)
  568: {
  569:   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
  570: 
  571:   if (strcmp (doctype, "busconfig") != 0)
  572:     {
  573:       dbus_set_error (error,
  574:                       DBUS_ERROR_FAILED,
  575:                       "Configuration file has the wrong document type %s",
  576:                       doctype);
  577:       return FALSE;
  578:     }
  579:   else
  580:     return TRUE;
  581: }
  582: 
  583: typedef struct
  584: {
  585:   const char  *name;
  586:   const char **retloc;
  587: } LocateAttr;
  588: 
  589: static dbus_bool_t
  590: locate_attributes (BusConfigParser  *parser,
  591:                    const char       *element_name,
  592:                    const char      **attribute_names,
  593:                    const char      **attribute_values,
  594:                    DBusError        *error,
  595:                    const char       *first_attribute_name,
  596:                    const char      **first_attribute_retloc,
  597:                    ...)
  598: {
  599:   va_list args;
  600:   const char *name;
  601:   const char **retloc;
  602:   int n_attrs;
  603: #define MAX_ATTRS 24
  604:   LocateAttr attrs[MAX_ATTRS];
  605:   dbus_bool_t retval;
  606:   int i;
  607: 
  608:   _dbus_assert (first_attribute_name != NULL);
  609:   _dbus_assert (first_attribute_retloc != NULL);
  610: 
  611:   retval = TRUE;
  612: 
  613:   n_attrs = 1;
  614:   attrs[0].name = first_attribute_name;
  615:   attrs[0].retloc = first_attribute_retloc;
  616:   *first_attribute_retloc = NULL;
  617: 
  618:   va_start (args, first_attribute_retloc);
  619: 
  620:   name = va_arg (args, const char*);
  621:   retloc = va_arg (args, const char**);
  622: 
  623:   while (name != NULL)
  624:     {
  625:       _dbus_assert (retloc != NULL);
  626:       _dbus_assert (n_attrs < MAX_ATTRS);
  627: 
  628:       attrs[n_attrs].name = name;
  629: