123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255 |
- // Copyright (C) 2010 Internet Systems Consortium, Inc. ("ISC")
- //
- // Permission to use, copy, modify, and/or distribute this software for any
- // purpose with or without fee is hereby granted, provided that the above
- // copyright notice and this permission notice appear in all copies.
- //
- // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
- // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
- // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
- // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
- // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
- // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- // PERFORMANCE OF THIS SOFTWARE.
- #include <set>
- #include <string>
- #include <utility>
- #include <vector>
- #include <boost/foreach.hpp>
- #include <boost/shared_ptr.hpp>
- #include <dns/name.h>
- #include <dns/rrclass.h>
- #include <cc/data.h>
- #include <datasrc/memory_datasrc.h>
- #include <datasrc/zonetable.h>
- #include <auth/auth_srv.h>
- #include <auth/config.h>
- #include <auth/common.h>
- using namespace std;
- using boost::shared_ptr;
- using namespace isc::dns;
- using namespace isc::data;
- using namespace isc::datasrc;
- namespace {
- // Forward declaration
- AuthConfigParser*
- createAuthConfigParser(AuthSrv& server, const std::string& config_id,
- bool internal);
- /// A derived \c AuthConfigParser class for the "datasources" configuration
- /// identifier.
- class DatasourcesConfig : public AuthConfigParser {
- public:
- DatasourcesConfig(AuthSrv& server) : server_(server) {}
- virtual void build(ConstElementPtr config_value);
- virtual void commit();
- private:
- AuthSrv& server_;
- vector<shared_ptr<AuthConfigParser> > datasources_;
- set<string> configured_sources_;
- };
- void
- DatasourcesConfig::build(ConstElementPtr config_value) {
- BOOST_FOREACH(ConstElementPtr datasrc_elem, config_value->listValue()) {
- // The caller is supposed to perform syntax-level checks, but we'll
- // do minimum level of validation ourselves so that we won't crash due
- // to a buggy application.
- ConstElementPtr datasrc_type = datasrc_elem->get("type");
- if (!datasrc_type) {
- isc_throw(AuthConfigError, "Missing data source type");
- }
- if (configured_sources_.find(datasrc_type->stringValue()) !=
- configured_sources_.end()) {
- isc_throw(AuthConfigError, "Data source type '" <<
- datasrc_type->stringValue() << "' already configured");
- }
-
- shared_ptr<AuthConfigParser> datasrc_config =
- shared_ptr<AuthConfigParser>(
- createAuthConfigParser(server_, string("datasources/") +
- datasrc_type->stringValue(),
- true));
- datasrc_config->build(datasrc_elem);
- datasources_.push_back(datasrc_config);
- configured_sources_.insert(datasrc_type->stringValue());
- }
- }
- void
- DatasourcesConfig::commit() {
- // XXX a short term workaround: clear all data sources and then reset
- // to new ones so that we can remove data sources that don't exist in
- // the new configuration and have been used in the server.
- // This could be inefficient and requires knowledge about
- // server implementation details, and isn't scalable wrt the number of
- // data source types, and should eventually be improved.
- // Currently memory data source for class IN is the only possibility.
- server_.setMemoryDataSrc(RRClass::IN(), AuthSrv::MemoryDataSrcPtr());
- BOOST_FOREACH(shared_ptr<AuthConfigParser> datasrc_config, datasources_) {
- datasrc_config->commit();
- }
- }
- /// A derived \c AuthConfigParser class for the memory type datasource
- /// configuration. It does not correspond to the configuration syntax;
- /// it's instantiated for internal use.
- class MemoryDatasourceConfig : public AuthConfigParser {
- public:
- MemoryDatasourceConfig(AuthSrv& server) :
- server_(server),
- rrclass_(0) // XXX: dummy initial value
- {}
- virtual void build(ConstElementPtr config_value);
- virtual void commit() {
- server_.setMemoryDataSrc(rrclass_, memory_datasrc_);
- }
- private:
- AuthSrv& server_;
- RRClass rrclass_;
- AuthSrv::MemoryDataSrcPtr memory_datasrc_;
- };
- void
- MemoryDatasourceConfig::build(ConstElementPtr config_value) {
- // XXX: apparently we cannot retrieve the default RR class from the
- // module spec. As a temporary workaround we hardcode the default value.
- ConstElementPtr rrclass_elem = config_value->get("class");
- rrclass_ = RRClass(rrclass_elem ? rrclass_elem->stringValue() : "IN");
- // We'd eventually optimize building zones (in case of reloading) by
- // selectively loading fresh zones. Right now we simply check the
- // RR class is supported by the server implementation.
- server_.getMemoryDataSrc(rrclass_);
- memory_datasrc_ = AuthSrv::MemoryDataSrcPtr(new MemoryDataSrc());
- ConstElementPtr zones_config = config_value->get("zones");
- if (!zones_config) {
- // XXX: Like the RR class, we cannot retrieve the default value here,
- // so we assume an empty zone list in this case.
- return;
- }
- BOOST_FOREACH(ConstElementPtr zone_config, zones_config->listValue()) {
- ConstElementPtr origin = zone_config->get("origin");
- if (!origin) {
- isc_throw(AuthConfigError, "Missing zone origin");
- }
- ConstElementPtr file = zone_config->get("file");
- if (!file) {
- isc_throw(AuthConfigError, "Missing zone file for zone: "
- << origin->str());
- }
- shared_ptr<MemoryZone> new_zone(new MemoryZone(rrclass_,
- Name(origin->stringValue())));
- const result::Result result = memory_datasrc_->addZone(new_zone);
- if (result == result::EXIST) {
- isc_throw(AuthConfigError, "zone "<< origin->str()
- << " already exists");
- }
- /*
- * TODO: Once we have better reloading of configuration (something
- * else than throwing everything away and loading it again), we will
- * need the load method to be split into some kind of build and
- * commit/abort parts.
- */
- new_zone->load(file->stringValue());
- }
- }
- /// A special parser for testing: it throws from commit() despite the
- /// suggested convention of the class interface.
- class ThrowerCommitConfig : public AuthConfigParser {
- public:
- virtual void build(ConstElementPtr) {} // ignore param, do nothing
- virtual void commit() {
- throw 10;
- }
- };
- // This is a generalized version of create function that can create
- // an AuthConfigParser object for "internal" use.
- AuthConfigParser*
- createAuthConfigParser(AuthSrv& server, const std::string& config_id,
- bool internal)
- {
- // For the initial implementation we use a naive if-else blocks for
- // simplicity. In future we'll probably generalize it using map-like
- // data structure, and may even provide external register interface so
- // that it can be dynamically customized.
- if (config_id == "datasources") {
- return (new DatasourcesConfig(server));
- } else if (internal && config_id == "datasources/memory") {
- return (new MemoryDatasourceConfig(server));
- } else if (config_id == "_commit_throw") {
- // This is for testing purpose only and should not appear in the
- // actual configuration syntax. While this could crash the caller
- // as a result, the server implementation is expected to perform
- // syntax level validation and should be safe in practice. In future,
- // we may introduce dynamic registration of configuration parsers,
- // and then this test can be done in a cleaner and safer way.
- return (new ThrowerCommitConfig());
- } else {
- isc_throw(AuthConfigError, "Unknown configuration identifier: " <<
- config_id);
- }
- }
- } // end of unnamed namespace
- AuthConfigParser*
- createAuthConfigParser(AuthSrv& server, const std::string& config_id) {
- return (createAuthConfigParser(server, config_id, false));
- }
- void
- configureAuthServer(AuthSrv& server, ConstElementPtr config_set) {
- if (!config_set) {
- isc_throw(AuthConfigError,
- "Null pointer is passed to configuration parser");
- }
- typedef shared_ptr<AuthConfigParser> ParserPtr;
- vector<ParserPtr> parsers;
- typedef pair<string, ConstElementPtr> ConfigPair;
- try {
- BOOST_FOREACH(ConfigPair config_pair, config_set->mapValue()) {
- // We should eventually integrate the sqlite3 DB configuration to
- // this framework, but to minimize diff we begin with skipping that
- // part.
- if (config_pair.first == "database_file") {
- continue;
- }
- ParserPtr parser(createAuthConfigParser(server,
- config_pair.first));
- parser->build(config_pair.second);
- parsers.push_back(parser);
- }
- } catch (const AuthConfigError& ex) {
- throw ex; // simply rethrowing it
- } catch (const isc::Exception& ex) {
- isc_throw(AuthConfigError, "Server configuration failed: " <<
- ex.what());
- }
- try {
- BOOST_FOREACH(ParserPtr parser, parsers) {
- parser->commit();
- }
- } catch (...) {
- throw FatalError("Unrecoverable error: "
- "a configuration parser threw in commit");
- }
- }
|