13#include <boost/foreach.hpp>
27using namespace std::chrono;
44 if (!
cfg_.getClientKeyTab().empty()) {
45 char* krb5_client_ktname = getenv(
"KRB5_CLIENT_KTNAME");
46 if (krb5_client_ktname) {
51 setenv(
"KRB5_CLIENT_KTNAME",
cfg_.getClientKeyTab().c_str(), 1);
53 if (!
cfg_.getCredsCache().empty()) {
54 char* krb5ccname = getenv(
"KRB5CCNAME");
60 setenv(
"KRB5CCNAME",
cfg_.getCredsCache().c_str(), 1);
70 cfg_.buildServerRevMap(d2_config);
76 for (
auto const& server :
cfg_.getServerList()) {
83 uint32_t max_tkey_lifetime =
cfg_.getMaxKeyLifetime();
84 if (max_tkey_lifetime > 0) {
87 max_tkey_lifetime * 1000,
99 for (
auto const& server :
cfg_.getServerList()) {
103 if (server->getTimer()) {
104 server->getTimer()->cancel();
105 server->getTimer().reset();
108 for (
auto const& key :
keys_) {
109 key->getTKeyExchange().reset();
117 }
catch (
const std::exception& ex) {
130 if (!
cfg_.getClientKeyTab().empty()) {
134 unsetenv(
"KRB5_CLIENT_KTNAME");
137 if (!
cfg_.getCredsCache().empty()) {
141 unsetenv(
"KRB5CCNAME");
148 time_point<std::chrono::system_clock> now) {
150 stats_mgr.
addValue(
"gss-tsig-key-created",
151 static_cast<int64_t
>(1));
154 "gss-tsig-key-created"),
155 static_cast<int64_t
>(1));
167 mkey->setParentID(server->getID());
168 mkey->setInception(now);
169 mkey->setExpire(now + seconds(server->getKeyLifetime()));
170 static_cast<void>(
keys_.insert(mkey));
172 if (!server->getGssReplayFlag()) {
173 flags &= ~GSS_C_REPLAY_FLAG;
175 if (server->getGssSequenceFlag()) {
176 flags |= GSS_C_SEQUENCE_FLAG;
180 server->getExchangeTimeout(),
184 if (mkey->getTKeyExchange()) {
185 mkey->getTKeyExchange()->doExchange();
192 for (
auto const& server :
cfg_.getServerList()) {
204 auto const now = system_clock::now();
205 const std::chrono::seconds retry_dur(server->getRetryInterval());
206 const std::chrono::seconds rekey_dur(server->getRekeyInterval());
208 auto const& range = idx.equal_range(server->getID());
210 BOOST_FOREACH(
auto const& key, range) {
211 lock_guard<mutex> lock(*key->mutex_);
212 if (!newest || (newest->getInception() < key->getInception())) {
216 if (now >= key->getExpire()) {
225 switch (newest->getStatus()) {
239 ((now + retry_dur >= newest->getExpire()) ||
240 (now >= newest->getInception() + rekey_dur))) {
248 }
catch (
const std::exception& ex) {
251 .arg(server->getID())
256 .arg(server->getID());
258 auto timer = server->getTimer();
264 if (retry || !newest) {
266 server->getRetryInterval() * 1000,
269 .arg(server->getID())
270 .arg(server->getRetryInterval());
274 auto const rekey_date = newest->getInception() + rekey_dur;
275 const std::chrono::system_clock::duration rekey_interval(rekey_date - now);
277 (duration_cast<nanoseconds>(rekey_interval).count() + 999999) / 1000000;
278 if (interval < server->getRetryInterval()) {
279 interval = server->getRetryInterval();
284 .arg(server->getID())
285 .arg(interval / 1000);
290 return (
cfg_.getServer(
id));
295 bool& useGssTsig,
bool& fallback) {
304 fallback = server->getFallback();
305 auto now = system_clock::now();
307 auto const& range = idx.equal_range(server->getID());
309 BOOST_FOREACH(
auto const& key, range) {
310 lock_guard<mutex> lock(*key->mutex_);
312 if (now >= key->getExpire()) {
321 .arg(candidate->getKeyNameStr());
331 if (it ==
keys_.cend()) {
340 auto now = system_clock::now();
341 std::chrono::seconds max_age(
cfg_.getMaxKeyLifetime() * 3);
342 list<ManagedKeyPtr> to_purge;
343 for (
auto const& key :
keys_) {
344 lock_guard<mutex> lock(*key->mutex_);
345 if (key->getExpire() + max_age < now) {
346 to_purge.push_back(key);
351 if (to_purge.empty()) {
356 for (
auto const& key : to_purge) {
357 auto it =
keys_.find(key->getKeyNameStr());
358 if (it !=
keys_.end()) {
359 key->getTKeyExchange().reset();
366 .arg(to_purge.size());
386 << command->str() <<
"' command");
392 <<
"' command are not a map");
399 << command->str() <<
"' command");
405 << command->str() <<
"' command");
408 id = server_id->stringValue();
409 server =
cfg_.getServer(
id);
410 }
catch (
const std::exception& ex) {
419 msg <<
"GSS-TSIG server[" <<
id <<
"] ";
430 auto const& range = idx.equal_range(server->getID());
431 BOOST_FOREACH(
auto const& key, range) {
432 keys->add(key->toElement());
434 desc->set(
"keys", keys);
447 args->set(
"gss-tsig-servers", servers);
452 for (
auto const& server :
cfg_.getServerList()) {
455 auto const& range = idx.equal_range(server->getID());
456 BOOST_FOREACH(
auto const& key, range) {
457 keys->add(key->toElement());
459 desc->set(
"keys", keys);
460 key_count += keys->size();
465 msg << servers->size() <<
" GSS-TSIG servers";
467 if (servers->empty()) {
470 msg <<
" and " << key_count <<
" keys";
485 args->set(
"gss-tsig-servers", servers);
486 args->set(
"gss-tsig-keys", keys);
489 for (
auto const& server :
cfg_.getServerList()) {
494 for (
auto const& key :
keys_) {
499 msg << servers->size() <<
" GSS-TSIG servers and "
500 << keys->size() <<
" keys";
502 if (servers->empty() && keys->empty()) {
527 << command->str() <<
"' command");
533 <<
"' command are not a map");
540 << command->str() <<
"' command");
546 << command->str() <<
"' command");
549 name = key_name->stringValue();
551 }
catch (
const std::exception& ex) {
560 msg <<
"GSS-TSIG key '" <<
name <<
"' ";
591 << command->str() <<
"' command");
597 <<
"' command are not a map");
604 << command->str() <<
"' command");
610 << command->str() <<
"' command");
613 name = key_name->stringValue();
615 }
catch (
const std::exception& ex) {
624 msg <<
"GSS-TSIG key '" <<
name <<
"' ";
631 bool can_expire =
true;
633 lock_guard<mutex> lock(*key->mutex_);
641 msg <<
"can't be expired";
668 << command->str() <<
"' command");
674 <<
"' command are not a map");
681 << command->str() <<
"' command");
687 << command->str() <<
"' command");
690 name = key_name->stringValue();
692 }
catch (
const std::exception& ex) {
701 msg <<
"GSS-TSIG key '" <<
name <<
"' ";
710 if (it !=
keys_.end()) {
711 key->getTKeyExchange().reset();
735 << command->str() <<
"' command");
741 <<
"' command are not a map");
748 << command->str() <<
"' command");
754 << command->str() <<
"' command");
757 id = server_id->stringValue();
758 }
catch (
const std::exception& ex) {
767 auto now = system_clock::now();
768 list<ManagedKeyPtr> to_purge;
770 auto const& range = idx.equal_range(
id);
771 BOOST_FOREACH(
auto const& key, range) {
772 lock_guard<mutex> lock(*key->mutex_);
773 auto status = key->getStatus();
779 if (now < key->getExpire()) {
784 to_purge.push_back(key);
787 to_purge.push_back(key);
793 for (
auto const& key : to_purge) {
794 auto it =
keys_.find(key->getKeyNameStr());
795 if (it !=
keys_.end()) {
796 key->getTKeyExchange().reset();
802 msg << to_purge.size() <<
" purged keys for GSS-TSIG server[" <<
id <<
"]";
804 if (to_purge.empty()) {
817 auto now = system_clock::now();
818 list<ManagedKeyPtr> to_purge;
819 for (
auto const& key :
keys_) {
820 lock_guard<mutex> lock(*key->mutex_);
821 auto status = key->getStatus();
827 if (now < key->getExpire()) {
832 to_purge.push_back(key);
835 to_purge.push_back(key);
841 for (
auto const& key : to_purge) {
842 auto it =
keys_.find(key->getKeyNameStr());
843 if (it !=
keys_.end()) {
844 key->getTKeyExchange().reset();
850 msg << to_purge.size() <<
" purged GSS-TSIG keys";
852 if (to_purge.empty()) {
877 << command->str() <<
"' command");
883 <<
"' command are not a map");
890 << command->str() <<
"' command");
896 << command->str() <<
"' command");
899 id = server_id->stringValue();
900 server =
cfg_.getServer(
id);
901 }
catch (
const std::exception& ex) {
910 msg <<
"GSS-TSIG server[" <<
id <<
"] ";
917 auto now = system_clock::now();
937 if (command_name !=
"status-get") {
943 if (!response || (response->getType() !=
Element::map)) {
948 if (!resp_args || (resp_args->getType() !=
Element::map)) {
952 ElementPtr mutable_resp_args = boost::const_pointer_cast<Element>(resp_args);
static ElementPtr create(const Position &pos=ZERO_POSITION())
static ElementPtr createMap(const Position &pos=ZERO_POSITION())
Creates an empty MapElement type ElementPtr.
static ElementPtr createList(const Position &pos=ZERO_POSITION())
Creates an empty ListElement type ElementPtr.
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
The IOService class is a wrapper for the ASIO io_context class.
The IntervalTimer class is a wrapper for the ASIO boost::asio::deadline_timer class.
static const std::list< std::string > STAT_NAMES
Server TKEY exchange statistics names.
void rekeyAllHandler(isc::hooks::CalloutHandle &handle)
The gss-tsig-rekey-all command handler.
std::unique_ptr< std::string > krb5_client_ktname_prev_
The previous value of client key table environment variable.
isc::asiolink::IOServicePtr io_service_
The hook I/O service.
GssTsigImpl()
Constructor.
void purgeAllHandler(isc::hooks::CalloutHandle &handle)
The gss-tsig-purge-all command handler.
void finishConfigure(isc::d2::D2CfgContextPtr d2_config)
Finish configure.
GssTsigCfg cfg_
GSS-TSIG hook configuration.
void commandProcessed(isc::hooks::CalloutHandle &handle)
The command_processed handler.
void start()
Start method.
void keyExpireHandler(isc::hooks::CalloutHandle &handle)
The gss-tsig-key-expire command handler.
void purgeHandler(isc::hooks::CalloutHandle &handle)
The gss-tsig-purge command handler.
void rekeyHandler(isc::hooks::CalloutHandle &handle)
The gss-tsig-rekey command handler.
void getAllHandler(isc::hooks::CalloutHandle &handle) const
The gss-tsig-get-all command handler.
void configure(isc::data::ConstElementPtr config)
Configure.
void keyDelHandler(isc::hooks::CalloutHandle &handle)
The gss-tsig-key-del command handler.
DnsServerPtr getServer(const std::string &id) const
Get the DNS server from its ID.
void processAllServersKeys(bool rekey=false)
Process GSS-TSIG keys for all servers.
ManagedKeyList keys_
Map of GSS-TSIG keys by name.
ManagedKeyPtr findKey(const d2::DnsServerInfoPtr &server_info, bool &useGssTsig, bool &fallback)
Find a GSS-TSIG key by server info.
void purgeKeys()
Purge very old GSS-TSIG keys.
void processServerKeys(DnsServerPtr server, bool rekey=false)
Process GSS-TSIG keys for a specific server.
std::unique_ptr< std::string > krb5ccname_prev_
The previous value of credential cache environment variable.
void keyGetHandler(isc::hooks::CalloutHandle &handle) const
The gss-tsig-key-get command handler.
isc::asiolink::IntervalTimerPtr purge_timer_
The purge periodic timer.
virtual ~GssTsigImpl()
Destructor.
void listHandler(isc::hooks::CalloutHandle &handle) const
The gss-tsig-list command handler.
void getHandler(isc::hooks::CalloutHandle &handle) const
The gss-tsig-get command handler.
void createKey(DnsServerPtr server, std::chrono::time_point< std::chrono::system_clock > now)
Create new GSS-TSIG key.
static std::string genName(const std::string &server)
Create a random name from a suffix.
@ EXPIRED
Expired (no longer usable).
@ NOT_READY
Not yet ready (not yet usable).
The TKeyExchange class handles communication with the DNS server.
static const OM_uint32 TKEY_EXCHANGE_FLAGS
The default TKEY exchange flags.
Per-packet callout handle.
void getArgument(const std::string &name, T &value) const
Get argument.
void setArgument(const std::string &name, T value)
Set argument.
Statistics Manager class.
static StatsMgr & instance()
Statistics Manager accessor method.
static std::string generateName(const std::string &context, Type index, const std::string &stat_name)
Generates statistic name in a given context.
This file contains several functions and constants that are used for handling commands and responses ...
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
bool del(const std::string &name)
Removes specified statistic.
void setValue(const std::string &name, const int64_t value)
Records absolute integer observation.
void addValue(const std::string &name, const int64_t value)
Records incremental integer observation.
int rekey(CalloutHandle &handle)
The gss-tsig-rekey command.
#define LOG_ERROR(LOGGER, MESSAGE)
Macro to conveniently test error output and log it.
#define LOG_INFO(LOGGER, MESSAGE)
Macro to conveniently test info output and log it.
#define LOG_DEBUG(LOGGER, LEVEL, MESSAGE)
Macro to conveniently test debug output and log it.
const int CONTROL_RESULT_EMPTY
Status code indicating that the specified command was completed correctly, but failed to produce any ...
const int CONTROL_RESULT_ERROR
Status code indicating a general failure.
std::string parseCommand(ConstElementPtr &arg, ConstElementPtr command)
Parses the given command into a string containing the actual command and an ElementPtr containing the...
ConstElementPtr createAnswer()
Creates a standard config/command level success answer message (i.e.
const int CONTROL_RESULT_SUCCESS
Status code indicating a successful operation.
boost::shared_ptr< DnsServerInfo > DnsServerInfoPtr
Defines a pointer for DnsServerInfo instances.
boost::shared_ptr< D2CfgContext > D2CfgContextPtr
Pointer to a configuration context.
boost::shared_ptr< const Element > ConstElementPtr
boost::shared_ptr< Element > ElementPtr
const isc::log::MessageID GSS_TSIG_MANAGER_STOP_GENERAL_ERROR
const isc::log::MessageID START_REKEY_TIMER
const isc::log::MessageID KEY_LOOKUP_DISABLED
const isc::log::MessageID GSS_TSIG_NEW_KEY
boost::shared_ptr< DnsServer > DnsServerPtr
A pointer to a DNS server.
const isc::log::MessageID GSS_TSIG_MANAGER_STOP_ERROR
const isc::log::MessageID GSS_TSIG_OLD_KEY_REMOVED
const isc::log::MessageID KEY_LOOKUP_NONE
const isc::log::MessageID KEY_LOOKUP_FOUND
const isc::log::MessageID GSS_TSIG_MANAGER_STARTED
const isc::log::MessageID KEY_PROCESSING_FAILED_UNSPECIFIED_ERROR
const isc::log::MessageID START_RETRY_TIMER
boost::shared_ptr< ManagedKey > ManagedKeyPtr
Type of pointer to a Managed GSS-TSIG key.
const isc::log::MessageID KEY_PROCESSING_FAILED
isc::log::Logger gss_tsig_logger("gss-tsig-hooks")
const isc::log::MessageID GSS_TSIG_MANAGER_STOPPED
const int DBGLVL_TRACE_BASIC
Trace basic operations.
Defines the logger used by the top-level component of kea-lfc.
Tag for the server ID index for searching GSS-TSIG key.