Kea 3.3.3
gss_tsig_impl.cc
Go to the documentation of this file.
1// Copyright (C) 2021-2026 Internet Systems Consortium, Inc. ("ISC")
2//
3// This Source Code Form is subject to the terms of the Mozilla Public
4// License, v. 2.0. If a copy of the MPL was not distributed with this
5// file, You can obtain one at http://mozilla.org/MPL/2.0/.
6
7#include <config.h>
8
12#include <stats/stats_mgr.h>
13
14#include <cstdlib>
15#include <list>
16#include <sstream>
17
18#include <boost/foreach.hpp>
19
20using namespace isc;
21using namespace isc::asiolink;
22using namespace isc::config;
23using namespace isc::d2;
24using namespace isc::data;
25using namespace isc::hooks;
26using namespace isc::log;
27using namespace isc::stats;
28using namespace std;
29using namespace std::chrono;
30
31namespace isc {
32namespace gss_tsig {
33
37
39 stop();
40 io_service_->stopAndPoll();
41}
42
43void
45 cfg_.configure(config);
46 if (!cfg_.getClientKeyTab().empty()) {
47 char* krb5_client_ktname = getenv("KRB5_CLIENT_KTNAME");
48 if (krb5_client_ktname) {
49 krb5_client_ktname_prev_.reset(new string(krb5_client_ktname));
50 } else {
52 }
53 setenv("KRB5_CLIENT_KTNAME", cfg_.getClientKeyTab().c_str(), 1);
54 }
55 if (!cfg_.getCredsCache().empty()) {
56 char* krb5ccname = getenv("KRB5CCNAME");
57 if (krb5ccname) {
58 krb5ccname_prev_.reset(new string(krb5ccname));
59 } else {
60 krb5ccname_prev_.reset();
61 }
62 setenv("KRB5CCNAME", cfg_.getCredsCache().c_str(), 1);
63 }
64 StatsMgr& stats_mgr = StatsMgr::instance();
65 for (auto const& name : DnsServer::STAT_NAMES) {
66 stats_mgr.setValue(name, static_cast<int64_t>(0));
67 }
68}
69
70void
72 cfg_.buildServerRevMap(d2_config);
73}
74
75void
78 for (auto const& server : cfg_.getServerList()) {
79 if (!server) {
80 continue;
81 }
82 server->getTimer().reset(new IntervalTimer(io_service_));
83 }
85 uint32_t max_tkey_lifetime = cfg_.getMaxKeyLifetime();
86 if (max_tkey_lifetime > 0) {
88 purge_timer_->setup([this]() { purgeKeys(); },
89 max_tkey_lifetime * 1000,
91 }
92}
93
94void
97 if (purge_timer_) {
98 purge_timer_->cancel();
99 purge_timer_.reset();
100 }
101 for (auto const& server : cfg_.getServerList()) {
102 if (!server) {
103 continue;
104 }
105 if (server->getTimer()) {
106 server->getTimer()->cancel();
107 server->getTimer().reset();
108 }
109 }
110 for (auto const& key : keys_) {
111 key->getTKeyExchange().reset();
112 }
113 keys_.clear();
114 cfg_.clearServers();
115 // Run cancelled callbacks.
116 if (io_service_) {
117 try {
118 io_service_->poll();
119 } catch (const std::exception& ex) {
121 .arg(ex.what());
122 } catch (...) {
124 }
125 }
126 // Remove statistics.
127 StatsMgr& stats_mgr = StatsMgr::instance();
128 for (auto const& name : DnsServer::STAT_NAMES) {
129 stats_mgr.del(name);
130 }
131 // Restore environment variables.
132 if (!cfg_.getClientKeyTab().empty()) {
134 setenv("KRB5_CLIENT_KTNAME", krb5_client_ktname_prev_->c_str(), 1);
135 } else {
136 unsetenv("KRB5_CLIENT_KTNAME");
137 }
138 }
139 if (!cfg_.getCredsCache().empty()) {
140 if (krb5ccname_prev_) {
141 setenv("KRB5CCNAME", krb5ccname_prev_->c_str(), 1);
142 } else {
143 unsetenv("KRB5CCNAME");
144 }
145 }
146}
147
148void
150 time_point<std::chrono::system_clock> now) {
151 StatsMgr& stats_mgr = StatsMgr::instance();
152 stats_mgr.addValue("gss-tsig-key-created",
153 static_cast<int64_t>(1));
154 stats_mgr.addValue(StatsMgr::generateName("server",
155 server->getID(),
156 "gss-tsig-key-created"),
157 static_cast<int64_t>(1));
158 string name;
159 for (;;) {
160 name = ManagedKey::genName(server->getKeyNameSuffix());
161 if (keys_.count(name) == 0) {
162 break;
163 }
164 // Very unlikely but possible name collision.
165 // Try another name.
166 }
168 ManagedKeyPtr mkey(new ManagedKey(name));
169 mkey->setParentID(server->getID());
170 mkey->setInception(now);
171 mkey->setExpire(now + seconds(server->getKeyLifetime()));
172 static_cast<void>(keys_.insert(mkey));
173 OM_uint32 flags = TKeyExchange::TKEY_EXCHANGE_FLAGS;
174 if (!server->getGssReplayFlag()) {
175 flags &= ~GSS_C_REPLAY_FLAG;
176 }
177 if (server->getGssSequenceFlag()) {
178 flags |= GSS_C_SEQUENCE_FLAG;
179 }
180 mkey->getTKeyExchange().reset(new TKeyExchange(io_service_, server, mkey,
181 mkey.get(),
182 server->getExchangeTimeout(),
183 flags));
184
185 io_service_->post([mkey]() {
186 if (mkey->getTKeyExchange()) {
187 mkey->getTKeyExchange()->doExchange();
188 }
189 });
190}
191
192void
194 for (auto const& server : cfg_.getServerList()) {
195 processServerKeys(server, rekey);
196 }
197}
198
199void
201 if (!server) {
202 return;
203 }
204 bool retry = false;
205 ManagedKeyPtr newest;
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());
209 auto const& idx = keys_.get<GssTsigKeyServerTag>();
210 auto const& range = idx.equal_range(server->getID());
211 try {
212 BOOST_FOREACH(auto const& key, range) {
213 lock_guard<mutex> lock(*key->mutex_);
214 if (!newest || (newest->getInception() < key->getInception())) {
215 newest = key;
216 }
217 if (key->getStatus() == ManagedKey::USABLE) {
218 if (now >= key->getExpire()) {
219 key->setStatus(ManagedKey::EXPIRED);
220 }
221 }
222 }
223 // Rekey if no key or the newest key is not usable but ready.
224 if (!newest) {
225 rekey = true;
226 } else {
227 switch (newest->getStatus()) {
229 // Lost some race, check again later.
230 retry = true;
231 break;
233 break;
234 default:
235 rekey = true;
236 break;
237 }
238 }
239 // Rekey too if the newest key is usable but soon to expire.
240 if (!rekey &&
241 ((now + retry_dur >= newest->getExpire()) ||
242 (now >= newest->getInception() + rekey_dur))) {
243 rekey = true;
244 }
245 // Create and setup a new GSS-TSIG key.
246 if (rekey) {
247 createKey(server, now);
248 retry = true;
249 }
250 } catch (const std::exception& ex) {
251 retry = true;
253 .arg(server->getID())
254 .arg(ex.what());
255 } catch (...) {
256 retry = true;
258 .arg(server->getID());
259 }
260 auto timer = server->getTimer();
261 if (!timer) {
262 return;
263 }
264 timer->cancel();
265 // Schedule a retry.
266 if (retry || !newest) {
267 timer->setup([this, server]() { processServerKeys(server); },
268 server->getRetryInterval() * 1000,
271 .arg(server->getID())
272 .arg(server->getRetryInterval());
273 return;
274 }
275 // Schedule a rekey.
276 auto const rekey_date = newest->getInception() + rekey_dur;
277 const std::chrono::system_clock::duration rekey_interval(rekey_date - now);
278 auto interval =
279 (duration_cast<nanoseconds>(rekey_interval).count() + 999999) / 1000000;
280 if (interval < server->getRetryInterval()) {
281 interval = server->getRetryInterval();
282 }
283 timer->setup([this, server]() { processServerKeys(server); },
284 interval, IntervalTimer::ONE_SHOT);
286 .arg(server->getID())
287 .arg(interval / 1000);
288}
289
291GssTsigImpl::getServer(const std::string& id) const {
292 return (cfg_.getServer(id));
293}
294
297 bool& useGssTsig, bool& fallback) {
298 DnsServerPtr server = cfg_.getServer(server_info);
299 if (!server) {
301 useGssTsig = false;
302 fallback = false;
303 return (ManagedKeyPtr());
304 }
305 useGssTsig = true;
306 fallback = server->getFallback();
307 auto now = system_clock::now();
308 auto const& idx = keys_.get<GssTsigKeyServerTag>();
309 auto const& range = idx.equal_range(server->getID());
310 ManagedKeyPtr candidate;
311 BOOST_FOREACH(auto const& key, range) {
312 lock_guard<mutex> lock(*key->mutex_);
313 if (key->getStatus() == ManagedKey::USABLE) {
314 if (now >= key->getExpire()) {
315 key->setStatus(ManagedKey::EXPIRED);
316 continue;
317 }
318 candidate = key;
319 }
320 }
321 if (candidate) {
323 .arg(candidate->getKeyNameStr());
324 return (candidate);
325 }
327 return (ManagedKeyPtr());
328}
329
331GssTsigImpl::findKey(const std::string& name) const {
332 auto const& it = keys_.find(name);
333 if (it == keys_.cend()) {
334 return (ManagedKeyPtr());
335 }
336 return (*it);
337}
338
339void
341 // Build the list of keys to remove.
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);
349 }
350 }
351
352 // Return now if there is no key to remove.
353 if (to_purge.empty()) {
354 return;
355 }
356
357 // Remove all elements of the list.
358 for (auto const& key : to_purge) {
359 auto it = keys_.find(key->getKeyNameStr());
360 if (it != keys_.end()) {
361 key->getTKeyExchange().reset();
362 keys_.erase(it);
363 }
364 }
365
368 .arg(to_purge.size());
369}
370
371void
373 ConstElementPtr response;
374 string id;
375 DnsServerPtr server;
376 try {
377 // Command is always provided.
378 ConstElementPtr command;
379 handle.getArgument("command", command);
380
381 // Retrieve arguments.
382 ConstElementPtr args;
383 static_cast<void>(parseCommand(args, command));
384
385 // Arguments are required.
386 if (!args) {
387 isc_throw(BadValue, "arguments not found in the '"
388 << command->str() << "' command");
389 }
390
391 // Arguments must be a map.
392 if (args->getType() != Element::map) {
393 isc_throw(BadValue, "arguments in the '" << command->str()
394 << "' command are not a map");
395 }
396
397 // server-id is mandatory.
398 ConstElementPtr server_id = args->get("server-id");
399 if (!server_id) {
400 isc_throw(BadValue, "'server-id' is mandatory for the '"
401 << command->str() << "' command");
402 }
403
404 // server-id must be a string.
405 if (server_id->getType() != Element::string) {
406 isc_throw(BadValue, "'server-id' must be a string in the '"
407 << command->str() << "' command");
408 }
409
410 id = server_id->stringValue();
411 server = cfg_.getServer(id);
412 } catch (const std::exception& ex) {
413 // There was an error while parsing command arguments.
414 // Return an error status code to notify the user.
415 response = createAnswer(CONTROL_RESULT_ERROR, ex.what());
416 handle.setArgument("response", response);
417 return;
418 }
419
420 ostringstream msg;
421 msg << "GSS-TSIG server[" << id << "] ";
422
423 // No server.
424 if (!server) {
425 msg << "not found";
426 response = createAnswer(CONTROL_RESULT_EMPTY, msg.str());
427 } else {
428 msg << "found";
429 ElementPtr desc = server->toElement();
431 auto const& idx = keys_.get<GssTsigKeyServerTag>();
432 auto const& range = idx.equal_range(server->getID());
433 BOOST_FOREACH(auto const& key, range) {
434 keys->add(key->toElement());
435 }
436 desc->set("keys", keys);
437 response = createAnswer(CONTROL_RESULT_SUCCESS, msg.str(), desc);
438 }
439 handle.setArgument("response", response);
440}
441
442void
444 ConstElementPtr response;
445 // Create a list where we're going to store servers' information.
447 // Create arguments map and add server list.
449 args->set("gss-tsig-servers", servers);
450 auto const& idx = keys_.get<GssTsigKeyServerTag>();
451 size_t key_count(0);
452
453 // Iterate over servers.
454 for (auto const& server : cfg_.getServerList()) {
455 ElementPtr desc = server->toElement();
457 auto const& range = idx.equal_range(server->getID());
458 BOOST_FOREACH(auto const& key, range) {
459 keys->add(key->toElement());
460 }
461 desc->set("keys", keys);
462 key_count += keys->size();
463 servers->add(desc);
464 }
465
466 ostringstream msg;
467 msg << servers->size() << " GSS-TSIG servers";
468
469 if (servers->empty()) {
470 response = createAnswer(CONTROL_RESULT_EMPTY, msg.str(), args);
471 } else {
472 msg << " and " << key_count << " keys";
473 response = createAnswer(CONTROL_RESULT_SUCCESS, msg.str(), args);
474 }
475 handle.setArgument("response", response);
476}
477
478void
480 ConstElementPtr response;
481 // Create a list where we're going to store servers' ID.
483 // Create a list where we're going to store keys' name.
485 // Create arguments map and add server and key lists.
487 args->set("gss-tsig-servers", servers);
488 args->set("gss-tsig-keys", keys);
489
490 // Iterate over servers.
491 for (auto const& server : cfg_.getServerList()) {
492 servers->add(Element::create(server->getID()));
493 }
494
495 // Iterate over keys.
496 for (auto const& key : keys_) {
497 keys->add(Element::create(key->getKeyNameStr()));
498 }
499
500 ostringstream msg;
501 msg << servers->size() << " GSS-TSIG servers and "
502 << keys->size() << " keys";
503
504 if (servers->empty() && keys->empty()) {
505 response = createAnswer(CONTROL_RESULT_EMPTY, msg.str(), args);
506 } else {
507 response = createAnswer(CONTROL_RESULT_SUCCESS, msg.str(), args);
508 }
509 handle.setArgument("response", response);
510}
511
512void
514 ConstElementPtr response;
515 string name;
516 ManagedKeyPtr key;
517 try {
518 // Command is always provided.
519 ConstElementPtr command;
520 handle.getArgument("command", command);
521
522 // Retrieve arguments.
523 ConstElementPtr args;
524 static_cast<void>(parseCommand(args, command));
525
526 // Arguments are required.
527 if (!args) {
528 isc_throw(BadValue, "arguments not found in the '"
529 << command->str() << "' command");
530 }
531
532 // Arguments must be a map.
533 if (args->getType() != Element::map) {
534 isc_throw(BadValue, "arguments in the '" << command->str()
535 << "' command are not a map");
536 }
537
538 // key-name is mandatory.
539 ConstElementPtr key_name = args->get("key-name");
540 if (!key_name) {
541 isc_throw(BadValue, "'key-name' is mandatory for the '"
542 << command->str() << "' command");
543 }
544
545 // key-name must be a string.
546 if (key_name->getType() != Element::string) {
547 isc_throw(BadValue, "'key-name' must be a string in the '"
548 << command->str() << "' command");
549 }
550
551 name = key_name->stringValue();
552 key = findKey(name);
553 } catch (const std::exception& ex) {
554 // There was an error while parsing command arguments.
555 // Return an error status code to notify the user.
556 response = createAnswer(CONTROL_RESULT_ERROR, ex.what());
557 handle.setArgument("response", response);
558 return;
559 }
560
561 ostringstream msg;
562 msg << "GSS-TSIG key '" << name << "' ";
563
564 // No key.
565 if (!key) {
566 msg << "not found";
567 response = createAnswer(CONTROL_RESULT_EMPTY, msg.str());
568 } else {
569 msg << "found";
570 ConstElementPtr desc = key->toElement();
571 response = createAnswer(CONTROL_RESULT_SUCCESS, msg.str(), desc);
572 }
573 handle.setArgument("response", response);
574}
575
576void
578 ConstElementPtr response;
579 string name;
580 ManagedKeyPtr key;
581 try {
582 // Command is always provided.
583 ConstElementPtr command;
584 handle.getArgument("command", command);
585
586 // Retrieve arguments.
587 ConstElementPtr args;
588 static_cast<void>(parseCommand(args, command));
589
590 // Arguments are required.
591 if (!args) {
592 isc_throw(BadValue, "arguments not found in the '"
593 << command->str() << "' command");
594 }
595
596 // Arguments must be a map.
597 if (args->getType() != Element::map) {
598 isc_throw(BadValue, "arguments in the '" << command->str()
599 << "' command are not a map");
600 }
601
602 // key-name is mandatory.
603 ConstElementPtr key_name = args->get("key-name");
604 if (!key_name) {
605 isc_throw(BadValue, "'key-name' is mandatory for the '"
606 << command->str() << "' command");
607 }
608
609 // key-name must be a string.
610 if (key_name->getType() != Element::string) {
611 isc_throw(BadValue, "'key-name' must be a string in the '"
612 << command->str() << "' command");
613 }
614
615 name = key_name->stringValue();
616 key = findKey(name);
617 } catch (const std::exception& ex) {
618 // There was an error while parsing command arguments.
619 // Return an error status code to notify the user.
620 response = createAnswer(CONTROL_RESULT_ERROR, ex.what());
621 handle.setArgument("response", response);
622 return;
623 }
624
625 ostringstream msg;
626 msg << "GSS-TSIG key '" << name << "' ";
627
628 // No key.
629 if (!key) {
630 msg << "not found";
631 response = createAnswer(CONTROL_RESULT_EMPTY, msg.str());
632 } else {
633 bool can_expire = true;
634 {
635 lock_guard<mutex> lock(*key->mutex_);
636 if (key->getStatus() >= ManagedKey::EXPIRED) {
637 can_expire = false;
638 } else {
639 key->setStatus(ManagedKey::EXPIRED);
640 }
641 }
642 if (!can_expire) {
643 msg << "can't be expired";
644 response = createAnswer(CONTROL_RESULT_EMPTY, msg.str());
645 } else {
646 msg << "expired";
647 response = createAnswer(CONTROL_RESULT_SUCCESS, msg.str());
648 }
649 }
650 handle.setArgument("response", response);
651}
652
653void
655 ConstElementPtr response;
656 string name;
657 ManagedKeyPtr key;
658 try {
659 // Command is always provided.
660 ConstElementPtr command;
661 handle.getArgument("command", command);
662
663 // Retrieve arguments.
664 ConstElementPtr args;
665 static_cast<void>(parseCommand(args, command));
666
667 // Arguments are required.
668 if (!args) {
669 isc_throw(BadValue, "arguments not found in the '"
670 << command->str() << "' command");
671 }
672
673 // Arguments must be a map.
674 if (args->getType() != Element::map) {
675 isc_throw(BadValue, "arguments in the '" << command->str()
676 << "' command are not a map");
677 }
678
679 // key-name is mandatory.
680 ConstElementPtr key_name = args->get("key-name");
681 if (!key_name) {
682 isc_throw(BadValue, "'key-name' is mandatory for the '"
683 << command->str() << "' command");
684 }
685
686 // key-name must be a string.
687 if (key_name->getType() != Element::string) {
688 isc_throw(BadValue, "'key-name' must be a string in the '"
689 << command->str() << "' command");
690 }
691
692 name = key_name->stringValue();
693 key = findKey(name);
694 } catch (const std::exception& ex) {
695 // There was an error while parsing command arguments.
696 // Return an error status code to notify the user.
697 response = createAnswer(CONTROL_RESULT_ERROR, ex.what());
698 handle.setArgument("response", response);
699 return;
700 }
701
702 ostringstream msg;
703 msg << "GSS-TSIG key '" << name << "' ";
704
705 // No key.
706 if (!key) {
707 msg << "not found";
708 response = createAnswer(CONTROL_RESULT_EMPTY, msg.str());
709 } else {
710 msg << "deleted";
711 auto it = keys_.find(name);
712 if (it != keys_.end()) {
713 key->getTKeyExchange().reset();
714 keys_.erase(it);
715 }
716 response = createAnswer(CONTROL_RESULT_SUCCESS, msg.str());
717 }
718 handle.setArgument("response", response);
719}
720
721void
723 ConstElementPtr response;
724 string id;
725 try {
726 // Command is always provided.
727 ConstElementPtr command;
728 handle.getArgument("command", command);
729
730 // Retrieve arguments.
731 ConstElementPtr args;
732 static_cast<void>(parseCommand(args, command));
733
734 // Arguments are required.
735 if (!args) {
736 isc_throw(BadValue, "arguments not found in the '"
737 << command->str() << "' command");
738 }
739
740 // Arguments must be a map.
741 if (args->getType() != Element::map) {
742 isc_throw(BadValue, "arguments in the '" << command->str()
743 << "' command are not a map");
744 }
745
746 // server-id is mandatory.
747 ConstElementPtr server_id = args->get("server-id");
748 if (!server_id) {
749 isc_throw(BadValue, "'server-id' is mandatory for the '"
750 << command->str() << "' command");
751 }
752
753 // server-id must be a string.
754 if (server_id->getType() != Element::string) {
755 isc_throw(BadValue, "'server-id' must be a string in the '"
756 << command->str() << "' command");
757 }
758
759 id = server_id->stringValue();
760 } catch (const std::exception& ex) {
761 // There was an error while parsing command arguments.
762 // Return an error status code to notify the user.
763 response = createAnswer(CONTROL_RESULT_ERROR, ex.what());
764 handle.setArgument("response", response);
765 return;
766 }
767
768 // Build the list of keys to remove.
769 auto now = system_clock::now();
770 list<ManagedKeyPtr> to_purge;
771 auto const& idx = keys_.get<GssTsigKeyServerTag>();
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();
776 switch (status) {
778 // skip
779 break;
781 if (now < key->getExpire()) {
782 // skip
783 break;
784 }
785 key->setStatus(ManagedKey::EXPIRED);
786 to_purge.push_back(key);
787 break;
788 default:
789 to_purge.push_back(key);
790 break;
791 }
792 }
793
794 // Remove all elements of the list.
795 for (auto const& key : to_purge) {
796 auto it = keys_.find(key->getKeyNameStr());
797 if (it != keys_.end()) {
798 key->getTKeyExchange().reset();
799 keys_.erase(it);
800 }
801 }
802
803 ostringstream msg;
804 msg << to_purge.size() << " purged keys for GSS-TSIG server[" << id << "]";
805
806 if (to_purge.empty()) {
807 response = createAnswer(CONTROL_RESULT_EMPTY, msg.str());
808 } else {
809 response = createAnswer(CONTROL_RESULT_SUCCESS, msg.str());
810 }
811 handle.setArgument("response", response);
812}
813
814void
816 ConstElementPtr response;
817
818 // Build the list of keys to remove.
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();
824 switch (status) {
826 // skip
827 break;
829 if (now < key->getExpire()) {
830 // skip
831 break;
832 }
833 key->setStatus(ManagedKey::EXPIRED);
834 to_purge.push_back(key);
835 break;
836 default:
837 to_purge.push_back(key);
838 break;
839 }
840 }
841
842 // Remove all elements of the list.
843 for (auto const& key : to_purge) {
844 auto it = keys_.find(key->getKeyNameStr());
845 if (it != keys_.end()) {
846 key->getTKeyExchange().reset();
847 keys_.erase(it);
848 }
849 }
850
851 ostringstream msg;
852 msg << to_purge.size() << " purged GSS-TSIG keys";
853
854 if (to_purge.empty()) {
855 response = createAnswer(CONTROL_RESULT_EMPTY, msg.str());
856 } else {
857 response = createAnswer(CONTROL_RESULT_SUCCESS, msg.str());
858 }
859 handle.setArgument("response", response);
860}
861
862void
864 ConstElementPtr response;
865 string id;
866 DnsServerPtr server;
867 try {
868 // Command is always provided.
869 ConstElementPtr command;
870 handle.getArgument("command", command);
871
872 // Retrieve arguments.
873 ConstElementPtr args;
874 static_cast<void>(parseCommand(args, command));
875
876 // Arguments are required.
877 if (!args) {
878 isc_throw(BadValue, "arguments not found in the '"
879 << command->str() << "' command");
880 }
881
882 // Arguments must be a map.
883 if (args->getType() != Element::map) {
884 isc_throw(BadValue, "arguments in the '" << command->str()
885 << "' command are not a map");
886 }
887
888 // server-id is mandatory.
889 ConstElementPtr server_id = args->get("server-id");
890 if (!server_id) {
891 isc_throw(BadValue, "'server-id' is mandatory for the '"
892 << command->str() << "' command");
893 }
894
895 // server-id must be a string.
896 if (server_id->getType() != Element::string) {
897 isc_throw(BadValue, "'server-id' must be a string in the '"
898 << command->str() << "' command");
899 }
900
901 id = server_id->stringValue();
902 server = cfg_.getServer(id);
903 } catch (const std::exception& ex) {
904 // There was an error while parsing command arguments.
905 // Return an error status code to notify the user.
906 response = createAnswer(CONTROL_RESULT_ERROR, ex.what());
907 handle.setArgument("response", response);
908 return;
909 }
910
911 ostringstream msg;
912 msg << "GSS-TSIG server[" << id << "] ";
913
914 // No server.
915 if (!server) {
916 msg << "not found";
917 response = createAnswer(CONTROL_RESULT_EMPTY, msg.str());
918 } else {
919 auto now = system_clock::now();
920 createKey(server, now);
921 msg << "rekeyed";
922 response = createAnswer(CONTROL_RESULT_SUCCESS, msg.str());
923 }
924 handle.setArgument("response", response);
925}
926
927void
929 io_service_->post([this]() { processAllServersKeys(true); });
931 handle.setArgument("response", response);
932}
933
934void
936 // Filter command names.
937 string command_name;
938 handle.getArgument("name", command_name);
939 if (command_name != "status-get") {
940 return;
941 }
942 // Get the response.
943 ConstElementPtr response;
944 handle.getArgument("response", response);
945 if (!response || (response->getType() != Element::map)) {
946 return;
947 }
948 // Get the arguments item from the response.
949 ConstElementPtr resp_args = response->get("arguments");
950 if (!resp_args || (resp_args->getType() != Element::map)) {
951 return;
952 }
953 // Add the gss-tsig entry.
954 ElementPtr mutable_resp_args = boost::const_pointer_cast<Element>(resp_args);
955 mutable_resp_args->set("gss-tsig", Element::create(true));
956}
957
958} // end of namespace isc::gss_tsig
959} // end of namespace isc
static ElementPtr create(const Position &pos=ZERO_POSITION())
Create a NullElement.
Definition data.cc:300
@ map
Definition data.h:160
@ string
Definition data.h:157
static ElementPtr createMap(const Position &pos=ZERO_POSITION())
Creates an empty MapElement type ElementPtr.
Definition data.cc:355
static ElementPtr createList(const Position &pos=ZERO_POSITION())
Creates an empty ListElement type ElementPtr.
Definition data.cc:350
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
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.
void stop()
Stop method.
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.
Managed GSS-TSIG key.
Definition managed_key.h:25
static std::string genName(const std::string &server)
Create a random name from a suffix.
@ EXPIRED
Expired (no longer usable).
Definition managed_key.h:36
@ NOT_READY
Not yet ready (not yet usable).
Definition managed_key.h:34
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.
Definition macros.h:32
#define LOG_INFO(LOGGER, MESSAGE)
Macro to conveniently test info output and log it.
Definition macros.h:20
#define LOG_DEBUG(LOGGER, LEVEL, MESSAGE)
Macro to conveniently test debug output and log it.
Definition macros.h:14
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.
Definition d2_config.h:554
boost::shared_ptr< D2CfgContext > D2CfgContextPtr
Pointer to a configuration context.
Definition d2_cfg_mgr.h:32
boost::shared_ptr< const Element > ConstElementPtr
Definition data.h:30
boost::shared_ptr< Element > ElementPtr
Definition data.h:29
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.