auth_config.cc 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. // Copyright (C) 2010 Internet Systems Consortium, Inc. ("ISC")
  2. //
  3. // Permission to use, copy, modify, and/or distribute this software for any
  4. // purpose with or without fee is hereby granted, provided that the above
  5. // copyright notice and this permission notice appear in all copies.
  6. //
  7. // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
  8. // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  9. // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
  10. // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  11. // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  12. // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  13. // PERFORMANCE OF THIS SOFTWARE.
  14. #include <dns/name.h>
  15. #include <dns/rrclass.h>
  16. #include <cc/data.h>
  17. #include <datasrc/memory_datasrc.h>
  18. #include <datasrc/zonetable.h>
  19. #include <datasrc/factory.h>
  20. #include <auth/auth_srv.h>
  21. #include <auth/auth_config.h>
  22. #include <auth/common.h>
  23. #include <server_common/portconfig.h>
  24. #include <boost/foreach.hpp>
  25. #include <boost/shared_ptr.hpp>
  26. #include <boost/scoped_ptr.hpp>
  27. #include <set>
  28. #include <string>
  29. #include <utility>
  30. #include <vector>
  31. using namespace std;
  32. using namespace isc::dns;
  33. using namespace isc::data;
  34. using namespace isc::datasrc;
  35. using namespace isc::server_common::portconfig;
  36. namespace {
  37. /// A derived \c AuthConfigParser for the version value
  38. /// (which is not used at this moment)
  39. class VersionConfig : public AuthConfigParser {
  40. public:
  41. VersionConfig() {}
  42. virtual void build(ConstElementPtr) {};
  43. virtual void commit() {};
  44. };
  45. /// A derived \c AuthConfigParser class for the "statistics-internal"
  46. /// configuration identifier.
  47. class StatisticsIntervalConfig : public AuthConfigParser {
  48. public:
  49. StatisticsIntervalConfig(AuthSrv& server) :
  50. server_(server), interval_(0)
  51. {}
  52. virtual void build(ConstElementPtr config_value) {
  53. const int32_t config_interval = config_value->intValue();
  54. if (config_interval < 0) {
  55. isc_throw(AuthConfigError, "Negative statistics interval value: "
  56. << config_interval);
  57. }
  58. if (config_interval > 86400) {
  59. isc_throw(AuthConfigError, "Statistics interval value "
  60. << config_interval
  61. << " must be equal to or shorter than 86400");
  62. }
  63. interval_ = config_interval;
  64. }
  65. virtual void commit() {
  66. // setStatisticsTimerInterval() is not 100% exception free. But
  67. // exceptions should happen only in a very rare situation, so we
  68. // let them be thrown and subsequently regard them as a fatal error.
  69. server_.setStatisticsTimerInterval(interval_);
  70. }
  71. private:
  72. AuthSrv& server_;
  73. uint32_t interval_;
  74. };
  75. /// A special parser for testing: it throws from commit() despite the
  76. /// suggested convention of the class interface.
  77. class ThrowerCommitConfig : public AuthConfigParser {
  78. public:
  79. virtual void build(ConstElementPtr) {} // ignore param, do nothing
  80. virtual void commit() {
  81. throw 10;
  82. }
  83. };
  84. /**
  85. * \brief Configuration parser for listen_on.
  86. *
  87. * It parses and sets the listening addresses of the server.
  88. *
  89. * It acts in unusual way. Since actually binding (changing) the sockets
  90. * is an operation that is expected to throw often, it shouldn't happen
  91. * in commit. Thefere we do it in build. But if the config is not committed
  92. * then, we would have it wrong. So we store the old addresses and if
  93. * commit is not called before destruction of the object, we return the
  94. * old addresses (which is the same kind of dangerous operation, but it is
  95. * expected that if we just managed to bind some and had the old ones binded
  96. * before, it should work).
  97. *
  98. * We might do something better in future (like open only the ports that are
  99. * extra, put them in in commit and close the old ones), but that's left out
  100. * for now.
  101. */
  102. class ListenAddressConfig : public AuthConfigParser {
  103. public:
  104. ListenAddressConfig(AuthSrv& server) :
  105. server_(server)
  106. { }
  107. ~ ListenAddressConfig() {
  108. if (rollbackAddresses_.get() != NULL) {
  109. server_.setListenAddresses(*rollbackAddresses_);
  110. }
  111. }
  112. private:
  113. typedef auto_ptr<AddressList> AddrListPtr;
  114. public:
  115. virtual void build(ConstElementPtr config) {
  116. AddressList newAddresses = parseAddresses(config, "listen_on");
  117. AddrListPtr old(new AddressList(server_.getListenAddresses()));
  118. server_.setListenAddresses(newAddresses);
  119. /*
  120. * Set the rollback addresses only after successful setting of the
  121. * new addresses, so we don't try to rollback if the setup is
  122. * unsuccessful (the above can easily throw).
  123. */
  124. rollbackAddresses_ = old;
  125. }
  126. virtual void commit() {
  127. rollbackAddresses_.release();
  128. }
  129. private:
  130. AuthSrv& server_;
  131. /**
  132. * This is the old address list, if we expect to roll back. When we commit,
  133. * this is set to NULL.
  134. */
  135. AddrListPtr rollbackAddresses_;
  136. };
  137. } // end of unnamed namespace
  138. AuthConfigParser*
  139. createAuthConfigParser(AuthSrv& server, const std::string& config_id) {
  140. // For the initial implementation we use a naive if-else blocks for
  141. // simplicity. In future we'll probably generalize it using map-like
  142. // data structure, and may even provide external register interface so
  143. // that it can be dynamically customized.
  144. if (config_id == "statistics-interval") {
  145. return (new StatisticsIntervalConfig(server));
  146. } else if (config_id == "listen_on") {
  147. return (new ListenAddressConfig(server));
  148. } else if (config_id == "_commit_throw") {
  149. // This is for testing purpose only and should not appear in the
  150. // actual configuration syntax. While this could crash the caller
  151. // as a result, the server implementation is expected to perform
  152. // syntax level validation and should be safe in practice. In future,
  153. // we may introduce dynamic registration of configuration parsers,
  154. // and then this test can be done in a cleaner and safer way.
  155. return (new ThrowerCommitConfig());
  156. } else if (config_id == "version") {
  157. // Currently, the version identifier is ignored, but it should
  158. // later be used to mark backwards incompatible changes in the
  159. // config data
  160. return (new VersionConfig());
  161. } else if (config_id == "datasources") {
  162. // TODO: Ignored for now, since the value is probably used by
  163. // other modules. Once they have been removed from there, remove
  164. // it from here and the spec file.
  165. // We need to return something. The VersionConfig is empty now,
  166. // so we may abuse that one, as it is a short-term solution only.
  167. return (new VersionConfig());
  168. } else {
  169. isc_throw(AuthConfigError, "Unknown configuration identifier: " <<
  170. config_id);
  171. }
  172. }
  173. void
  174. configureAuthServer(AuthSrv& server, ConstElementPtr config_set) {
  175. if (!config_set) {
  176. isc_throw(AuthConfigError,
  177. "Null pointer is passed to configuration parser");
  178. }
  179. typedef boost::shared_ptr<AuthConfigParser> ParserPtr;
  180. vector<ParserPtr> parsers;
  181. typedef pair<string, ConstElementPtr> ConfigPair;
  182. try {
  183. BOOST_FOREACH(ConfigPair config_pair, config_set->mapValue()) {
  184. // We should eventually integrate the sqlite3 DB configuration to
  185. // this framework, but to minimize diff we begin with skipping that
  186. // part.
  187. if (config_pair.first == "database_file") {
  188. continue;
  189. }
  190. ParserPtr parser(createAuthConfigParser(server,
  191. config_pair.first));
  192. parser->build(config_pair.second);
  193. parsers.push_back(parser);
  194. }
  195. } catch (const AuthConfigError& ex) {
  196. throw; // simply rethrowing it
  197. } catch (const isc::Exception& ex) {
  198. isc_throw(AuthConfigError, "Server configuration failed: " <<
  199. ex.what());
  200. }
  201. try {
  202. BOOST_FOREACH(ParserPtr parser, parsers) {
  203. parser->commit();
  204. }
  205. } catch (...) {
  206. throw FatalError("Unrecoverable error: "
  207. "a configuration parser threw in commit");
  208. }
  209. }