Index: trac/env.py
===================================================================
--- trac/env.py	(revision 8199)
+++ trac/env.py	(working copy)
@@ -36,9 +36,34 @@
 from trac.versioncontrol import RepositoryManager
 from trac.web.href import Href
 
-__all__ = ['Environment', 'IEnvironmentSetupParticipant', 'open_environment']
+__all__ = ['Environment', 'IEnvironmentSetupParticipant', 'open_environment', 
+           'IConfigurationProvider']
 
 
+class IConfigurationProvider(Interface):
+    """Extension point interface for components that want to provide configuration
+    settings."""
+
+    def sections():
+        """Return a list of section names."""
+
+    def has_section(section):
+        """Returns True if option exists in section."""
+
+    def options(section):
+        """Return a list of `(name, value)` tuples for every option in the
+        specified section."""
+
+    def has_option(section, option):
+        """Returns True if option exists in section."""
+
+    def get(section, option):
+        """Return the value of the specified option.
+        
+        Valid default input is a string. Returns a string.
+        """
+
+
 class IEnvironmentSetupParticipant(Interface):
     """Extension point interface for components that need to participate in the
     creation and upgrading of Trac environments, for example to create
@@ -74,6 +99,7 @@
      * wiki and ticket attachments.
     """   
     setup_participants = ExtensionPoint(IEnvironmentSetupParticipant)
+    config_provider = ExtensionPoint(IConfigurationProvider)
 
     shared_plugins_dir = PathOption('inherit', 'plugins_dir', '',
         """Path of the directory containing additional plugins.
@@ -210,6 +236,7 @@
         if create:
             for setup_participant in self.setup_participants:
                 setup_participant.environment_created()
+        self.config.config_provider.extend(self.config_provider)
 
     def component_activated(self, component):
         """Initialize additional member variables for components.
Index: trac/config.py
===================================================================
--- trac/config.py	(revision 8199)
+++ trac/config.py	(working copy)
@@ -43,6 +43,7 @@
         self.filename = filename
         self.parser = ConfigParser()
         self.parent = None
+        self.config_provider = []
         self._lastmtime = 0
         self._sections = {}
         self.parse_if_needed()
@@ -145,6 +146,8 @@
         while parent:
             sections |= set(parent.parser.sections())
             parent = parent.parent
+        for provider in self.config_provider:
+            sections |= set(provider.sections())
         return sorted(sections)
 
     def has_option(self, section, option):
@@ -162,6 +165,10 @@
             for parent_option, val in self.parent.options(section):
                 if parent_option == option:
                     return True
+        # check additional provider
+        for provider in self.config_provider:
+            if provider.has_option(section, option):
+                return True
         # Check the registry
         if (section, option) in Option.registry:
             return True
@@ -253,7 +260,11 @@
         if self.config.parser.has_option(self.name, name):
             return True
         if self.config.parent:
-            return name in self.config.parent[self.name]
+            if name in self.config.parent[self.name]:
+                return True
+        for provider in self.config.config_provider:
+            if provider.has_option(self.name, name):
+                return True
         return False
 
     def __iter__(self):
@@ -265,21 +276,39 @@
         if self.config.parent:
             for option in self.config.parent[self.name]:
                 if option.lower() not in options:
+                    options.add(option.lower())
                     yield option
+        for provider in self.config.config_provider:
+            if provider.has_section(self.name):
+                for option in provider.options(self.name):
+                    if option.lower() not in options:
+                        options.add(option.lower())
+                        yield option
 
     def __repr__(self):
         return '<Section [%s]>' % (self.name)
+    
+    def _get(self, name):
+        if self.config.parser.has_option(self.name, name):
+            return self.config.parser.get(self.name, name)
+        elif self.config.parent:
+            return self.config.parent[self.name]._get(name)
+        return None
+        
 
     def get(self, name, default=''):
         """Return the value of the specified option.
         
         Valid default input is a string. Returns a string.
         """
-        if self.config.parser.has_option(self.name, name):
-            value = self.config.parser.get(self.name, name)
-        elif self.config.parent:
-            value = self.config.parent[self.name].get(name, default)
-        else:
+        value = self._get(name)
+
+        if not value:
+            for provider in self.config.config_provider:
+                if provider.has_option(self.name, name):
+                    value = provider.get(self.name, name)
+        
+        if not value:
             option = Option.registry.get((self.name, name))
             if option:
                 value = option.default or default
Index: trac/tests/config.py
===================================================================
--- trac/tests/config.py	(revision 8199)
+++ trac/tests/config.py	(working copy)
@@ -244,6 +244,35 @@
         finally:
             os.remove(sitename)
 
+    def test_with_provider(self):
+        class mock_provider(object):
+            def sections(self):
+                return ['a', 'b']
+            def options(self, section):
+                if section == 'a':
+                    return ['option_a']
+                if section == 'b':
+                    return ['option_b']
+                else:
+                    return None
+            def has_section(self, section):
+                return section in self.sections()
+            def has_option(self, section, option):
+                return ((section == 'a' and option == 'option_a')
+                        or (section == 'b' and option == 'option_b'))
+            def get(self, section, option):
+                if section == 'a' and option == 'option_a':
+                    return 'y'
+                if section == 'b' and option == 'option_b':
+                    return 'z'
+        provider = mock_provider()
+        self._write(['[a]', 'option = x'])
+        config = self._read()
+        config.config_provider.append(provider)
+        self.assertEquals('x', config.get('a', 'option'))
+        self.assertEquals('y', config.get('a', 'option_a'))
+        self.assertEquals('z', config.get('b', 'option_b'))
+        self.assertEquals([('option', u'x'), ('option_a', u'y')], list(config.options('a')))
 
 def suite():
     return unittest.makeSuite(ConfigurationTestCase, 'test')

