18#include <boost/foreach.hpp>
29using namespace std::chrono;
46 if (!
cfg_.getClientKeyTab().empty()) {
47 char* krb5_client_ktname = getenv(
"KRB5_CLIENT_KTNAME");
48 if (krb5_client_ktname) {
53 setenv(
"KRB5_CLIENT_KTNAME",
cfg_.getClientKeyTab().c_str(), 1);
55 if (!
cfg_.getCredsCache().empty()) {
56 char* krb5ccname = getenv(
"KRB5CCNAME");
62 setenv(
"KRB5CCNAME",
cfg_.getCredsCache().c_str(), 1);
72 cfg_.buildServerRevMap(d2_config);
78 for (
auto const& server :
cfg_.getServerList()) {
85 uint32_t max_tkey_lifetime =
cfg_.getMaxKeyLifetime();
86 if (max_tkey_lifetime > 0) {
89 max_tkey_lifetime * 1000,
101 for (
auto const& server :
cfg_.getServerList()) {
105 if (server->getTimer()) {
106 server->getTimer()->cancel();
107 server->getTimer().reset();
110 for (
auto const& key :
keys_) {
111 key->getTKeyExchange().reset();
119 }
catch (
const std::exception& ex) {
132 if (!
cfg_.getClientKeyTab().empty()) {
136 unsetenv(
"KRB5_CLIENT_KTNAME");
139 if (!
cfg_.getCredsCache().empty()) {
143 unsetenv(
"KRB5CCNAME");
150 time_point<std::chrono::system_clock> now) {
152 stats_mgr.
addValue(
"gss-tsig-key-created",
153 static_cast<int64_t
>(1));
156 "gss-tsig-key-created"),
157 static_cast<int64_t
>(1));
169 mkey->setParentID(server->getID());
170 mkey->setInception(now);
171 mkey->setExpire(now + seconds(server->getKeyLifetime()));
172 static_cast<void>(
keys_.insert(mkey));
174 if (!server->getGssReplayFlag()) {
175 flags &= ~GSS_C_REPLAY_FLAG;
177 if (server->getGssSequenceFlag()) {
178 flags |= GSS_C_SEQUENCE_FLAG;
182 server->getExchangeTimeout(),
186 if (mkey->getTKeyExchange()) {
187 mkey->getTKeyExchange()->doExchange();
194 for (
auto const& server :
cfg_.getServerList()) {
206 auto const now = system_clock::now();
207 const std::chrono::seconds retry_dur(server->getRetryInterval());
208 const std::chrono::seconds rekey_dur(server->getRekeyInterval());
210 auto const& range = idx.equal_range(server->getID());
212 BOOST_FOREACH(
auto const& key, range) {
213 lock_guard<mutex> lock(*key->mutex_);
214 if (!newest || (newest->getInception() < key->getInception())) {
218 if (now >= key->getExpire()) {
227 switch (newest->getStatus()) {
241 ((now + retry_dur >= newest->getExpire()) ||
242 (now >= newest->getInception() + rekey_dur))) {
250 }
catch (
const std::exception& ex) {
253 .arg(server->getID())
258 .arg(server->getID());
260 auto timer = server->getTimer();
266 if (retry || !newest) {
268 server->getRetryInterval() * 1000,
271 .arg(server->getID())
272 .arg(server->getRetryInterval());
276 auto const rekey_date = newest->getInception() + rekey_dur;
277 const std::chrono::system_clock::duration rekey_interval(rekey_date - now);
279 (duration_cast<nanoseconds>(rekey_interval).count() + 999999) / 1000000;
280 if (interval < server->getRetryInterval()) {
281 interval = server->getRetryInterval();
286 .arg(server->getID())
287 .arg(interval / 1000);
292 return (
cfg_.getServer(
id));
297 bool& useGssTsig,
bool& fallback) {
306 fallback = server->getFallback();
307 auto now = system_clock::now();
309 auto const& range = idx.equal_range(server->getID());
311 BOOST_FOREACH(
auto const& key, range) {
312 lock_guard<mutex> lock(*key->mutex_);
314 if (now >= key->getExpire()) {
323 .arg(candidate->getKeyNameStr());
333 if (it ==
keys_.cend()) {
342 auto now = system_clock::now();
343 std::chrono::seconds max_age(
cfg_.getMaxKeyLifetime() * 3);
344 list<ManagedKeyPtr> to_purge;
345 for (
auto const& key :
keys_) {
346 lock_guard<mutex> lock(*key->mutex_);
347 if (key->getExpire() + max_age < now) {
348 to_purge.push_back(key);
353 if (to_purge.empty()) {
358 for (
auto const& key : to_purge) {
359 auto it =
keys_.find(key->getKeyNameStr());
360 if (it !=
keys_.end()) {
361 key->getTKeyExchange().reset();
368 .arg(to_purge.size());
388 << command->str() <<
"' command");
394 <<
"' command are not a map");
401 << command->str() <<
"' command");
407 << command->str() <<
"' command");
410 id = server_id->stringValue();
411 server =
cfg_.getServer(
id);
412 }
catch (
const std::exception& ex) {
421 msg <<
"GSS-TSIG server[" <<
id <<
"] ";
432 auto const& range = idx.equal_range(server->getID());
433 BOOST_FOREACH(
auto const& key, range) {
434 keys->add(key->toElement());
436 desc->set(
"keys", keys);
449 args->set(
"gss-tsig-servers", servers);
454 for (
auto const& server :
cfg_.getServerList()) {
457 auto const& range = idx.equal_range(server->getID());
458 BOOST_FOREACH(
auto const& key, range) {
459 keys->add(key->toElement());
461 desc->set(
"keys", keys);
462 key_count += keys->size();
467 msg << servers->size() <<
" GSS-TSIG servers";
469 if (servers->empty()) {
472 msg <<
" and " << key_count <<
" keys";
487 args->set(
"gss-tsig-servers", servers);
488 args->set(
"gss-tsig-keys", keys);
491 for (
auto const& server :
cfg_.getServerList()) {
496 for (
auto const& key :
keys_) {
501 msg << servers->size() <<
" GSS-TSIG servers and "
502 << keys->size() <<
" keys";
504 if (servers->empty() && keys->empty()) {
529 << command->str() <<
"' command");
535 <<
"' command are not a map");
542 << command->str() <<
"' command");
548 << command->str() <<
"' command");
551 name = key_name->stringValue();
553 }
catch (
const std::exception& ex) {
562 msg <<
"GSS-TSIG key '" <<
name <<
"' ";
593 << command->str() <<
"' command");
599 <<
"' command are not a map");
606 << command->str() <<
"' command");
612 << command->str() <<
"' command");
615 name = key_name->stringValue();
617 }
catch (
const std::exception& ex) {
626 msg <<
"GSS-TSIG key '" <<
name <<
"' ";
633 bool can_expire =
true;
635 lock_guard<mutex> lock(*key->mutex_);
643 msg <<
"can't be expired";
670 << command->str() <<
"' command");
676 <<
"' command are not a map");
683 << command->str() <<
"' command");
689 << command->str() <<
"' command");
692 name = key_name->stringValue();
694 }
catch (
const std::exception& ex) {
703 msg <<
"GSS-TSIG key '" <<
name <<
"' ";
712 if (it !=
keys_.end()) {
713 key->getTKeyExchange().reset();
737 << command->str() <<
"' command");
743 <<
"' command are not a map");
750 << command->str() <<
"' command");
756 << command->str() <<
"' command");
759 id = server_id->stringValue();
760 }
catch (
const std::exception& ex) {
769 auto now = system_clock::now();
770 list<ManagedKeyPtr> to_purge;
772 auto const& range = idx.equal_range(
id);
773 BOOST_FOREACH(
auto const& key, range) {
774 lock_guard<mutex> lock(*key->mutex_);
775 auto status = key->getStatus();
781 if (now < key->getExpire()) {
786 to_purge.push_back(key);
789 to_purge.push_back(key);
795 for (
auto const& key : to_purge) {
796 auto it =
keys_.find(key->getKeyNameStr());
797 if (it !=
keys_.end()) {
798 key->getTKeyExchange().reset();
804 msg << to_purge.size() <<
" purged keys for GSS-TSIG server[" <<
id <<
"]";
806 if (to_purge.empty()) {
819 auto now = system_clock::now();
820 list<ManagedKeyPtr> to_purge;
821 for (
auto const& key :
keys_) {
822 lock_guard<mutex> lock(*key->mutex_);
823 auto status = key->getStatus();
829 if (now < key->getExpire()) {
834 to_purge.push_back(key);
837 to_purge.push_back(key);
843 for (
auto const& key : to_purge) {
844 auto it =
keys_.find(key->getKeyNameStr());
845 if (it !=
keys_.end()) {
846 key->getTKeyExchange().reset();
852 msg << to_purge.size() <<
" purged GSS-TSIG keys";
854 if (to_purge.empty()) {
879 << command->str() <<
"' command");
885 <<
"' command are not a map");
892 << command->str() <<
"' command");
898 << command->str() <<
"' command");
901 id = server_id->stringValue();
902 server =
cfg_.getServer(
id);
903 }
catch (
const std::exception& ex) {
912 msg <<
"GSS-TSIG server[" <<
id <<
"] ";
919 auto now = system_clock::now();
939 if (command_name !=
"status-get") {
945 if (!response || (response->getType() !=
Element::map)) {
950 if (!resp_args || (resp_args->getType() !=
Element::map)) {
954 ElementPtr mutable_resp_args = boost::const_pointer_cast<Element>(resp_args);
static ElementPtr create(const Position &pos=ZERO_POSITION())
Create a NullElement.
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::system_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.