]>
Commit | Line | Data |
---|---|---|
b08f1315 OM |
1 | /* |
2 | * This file is part of PowerDNS or dnsdist. | |
3 | * Copyright -- PowerDNS.COM B.V. and its contributors | |
4 | * | |
5 | * This program is free software; you can redistribute it and/or modify | |
6 | * it under the terms of version 2 of the GNU General Public License as | |
7 | * published by the Free Software Foundation. | |
8 | * | |
9 | * In addition, for the avoidance of any doubt, permission is granted to | |
10 | * link this program with OpenSSL and to (re)distribute the binaries | |
11 | * produced as the result of such linking. | |
12 | * | |
13 | * This program is distributed in the hope that it will be useful, | |
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | * GNU General Public License for more details. | |
17 | * | |
18 | * You should have received a copy of the GNU General Public License | |
19 | * along with this program; if not, write to the Free Software | |
20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |
21 | */ | |
22 | ||
23 | #include "gss_context.hh" | |
b08f1315 OM |
24 | #include "logger.hh" |
25 | ||
26 | #ifndef ENABLE_GSS_TSIG | |
27 | ||
0b0882f5 | 28 | std::tuple<size_t, size_t, size_t> GssContext::getCounts() { return std::tuple<size_t, size_t, size_t>(0, 0, 0); } |
b08f1315 OM |
29 | bool GssContext::supported() { return false; } |
30 | GssContext::GssContext() : | |
31 | d_error(GSS_CONTEXT_UNSUPPORTED), d_type(GSS_CONTEXT_NONE) {} | |
8b428a6b | 32 | GssContext::GssContext(const DNSName& /* label */) : |
b08f1315 | 33 | d_error(GSS_CONTEXT_UNSUPPORTED), d_type(GSS_CONTEXT_NONE) {} |
8b428a6b FM |
34 | void GssContext::setLocalPrincipal(const std::string& /* name */) {} |
35 | bool GssContext::getLocalPrincipal(std::string& /* name */) { return false; } | |
36 | void GssContext::setPeerPrincipal(const std::string& /* name */) {} | |
37 | bool GssContext::getPeerPrincipal(std::string& /* name */) { return false; } | |
38 | void GssContext::generateLabel(const std::string& /* suffix */) {} | |
39 | void GssContext::setLabel(const DNSName& /* label */) {} | |
40 | bool GssContext::init(const std::string& /* input */, std::string& /* output */) { return false; } | |
41 | bool GssContext::accept(const std::string& /* input */, std::string& /* output */) { return false; } | |
b08f1315 OM |
42 | bool GssContext::destroy() { return false; } |
43 | bool GssContext::expired() { return false; } | |
44 | bool GssContext::valid() { return false; } | |
8b428a6b FM |
45 | bool GssContext::sign(const std::string& /* input */, std::string& /* output */) { return false; } |
46 | bool GssContext::verify(const std::string& /* input */, const std::string& /* signature */) { return false; } | |
b08f1315 OM |
47 | GssContextError GssContext::getError() { return GSS_CONTEXT_UNSUPPORTED; } |
48 | ||
49 | #else | |
50 | ||
15e39ee4 OM |
51 | #include <unordered_map> |
52 | ||
53 | #include "lock.hh" | |
54 | ||
5e8d94f1 PD |
55 | #define TSIG_GSS_EXPIRE_INTERVAL 60 |
56 | ||
b08f1315 OM |
57 | class GssCredential : boost::noncopyable |
58 | { | |
59 | public: | |
60 | GssCredential(const std::string& name, const gss_cred_usage_t usage) : | |
dd0ef5ed | 61 | d_nameS(name), d_usage(usage) |
b08f1315 OM |
62 | { |
63 | gss_buffer_desc buffer; | |
64 | ||
65 | if (!name.empty()) { | |
66 | buffer.length = name.size(); | |
67 | buffer.value = const_cast<void*>(static_cast<const void*>(name.c_str())); | |
dd0ef5ed OM |
68 | OM_uint32 min; |
69 | auto maj = gss_import_name(&min, &buffer, (gss_OID)GSS_KRB5_NT_PRINCIPAL_NAME, &d_name); | |
70 | if (maj != GSS_S_COMPLETE) { | |
b08f1315 OM |
71 | d_name = GSS_C_NO_NAME; |
72 | d_valid = false; | |
73 | return; | |
74 | } | |
75 | } | |
76 | ||
77 | renew(); | |
78 | }; | |
79 | ||
80 | ~GssCredential() | |
81 | { | |
5e8d94f1 | 82 | OM_uint32 tmp_min __attribute__((unused)); |
dd0ef5ed | 83 | if (d_cred != GSS_C_NO_CREDENTIAL) { |
5e8d94f1 | 84 | (void)gss_release_cred(&tmp_min, &d_cred); |
dd0ef5ed OM |
85 | } |
86 | if (d_name != GSS_C_NO_NAME) { | |
5e8d94f1 | 87 | (void)gss_release_name(&tmp_min, &d_name); |
dd0ef5ed | 88 | } |
b08f1315 OM |
89 | }; |
90 | ||
91 | bool expired() const | |
92 | { | |
dd0ef5ed | 93 | if (d_expires == -1) { |
b08f1315 | 94 | return false; |
dd0ef5ed | 95 | } |
b08f1315 OM |
96 | return time(nullptr) > d_expires; |
97 | } | |
98 | ||
99 | bool renew() | |
100 | { | |
5e8d94f1 | 101 | OM_uint32 time_rec, tmp_maj, tmp_min __attribute__((unused)); |
dd0ef5ed | 102 | tmp_maj = gss_acquire_cred(&tmp_min, d_name, GSS_C_INDEFINITE, GSS_C_NO_OID_SET, d_usage, &d_cred, nullptr, &time_rec); |
b08f1315 | 103 | |
dd0ef5ed | 104 | if (tmp_maj != GSS_S_COMPLETE) { |
b08f1315 | 105 | d_valid = false; |
5e8d94f1 | 106 | (void)gss_release_name(&tmp_min, &d_name); |
b08f1315 OM |
107 | d_name = GSS_C_NO_NAME; |
108 | return false; | |
109 | } | |
110 | ||
111 | d_valid = true; | |
112 | ||
dd0ef5ed OM |
113 | // We do not want forever, but a good time |
114 | if (time_rec == GSS_C_INDEFINITE) { | |
115 | time_rec = 24 * 60 * 60; | |
b08f1315 | 116 | } |
dd0ef5ed | 117 | d_expires = time(nullptr) + time_rec; |
b08f1315 OM |
118 | |
119 | return true; | |
120 | } | |
121 | ||
122 | bool valid() | |
123 | { | |
124 | return d_valid && !expired(); | |
125 | } | |
126 | ||
b08f1315 | 127 | std::string d_nameS; |
b08f1315 | 128 | gss_cred_usage_t d_usage; |
dd0ef5ed OM |
129 | gss_name_t d_name{GSS_C_NO_NAME}; |
130 | gss_cred_id_t d_cred{GSS_C_NO_CREDENTIAL}; | |
5e8d94f1 | 131 | time_t d_expires{time(nullptr) + 60}; // partly initialized will be cleaned up |
dd0ef5ed OM |
132 | bool d_valid{false}; |
133 | }; // GssCredential | |
b08f1315 | 134 | |
dd0ef5ed OM |
135 | static LockGuarded<std::unordered_map<std::string, std::shared_ptr<GssCredential>>> s_gss_accept_creds; |
136 | static LockGuarded<std::unordered_map<std::string, std::shared_ptr<GssCredential>>> s_gss_init_creds; | |
b08f1315 OM |
137 | |
138 | class GssSecContext : boost::noncopyable | |
139 | { | |
140 | public: | |
5e8d94f1 | 141 | GssSecContext(std::shared_ptr<GssCredential> cred) |
b08f1315 OM |
142 | { |
143 | if (!cred->valid()) { | |
dd0ef5ed | 144 | throw PDNSException("Invalid credential " + cred->d_nameS); |
b08f1315 | 145 | } |
8690b6ff | 146 | d_cred = std::move(cred); |
b08f1315 OM |
147 | } |
148 | ||
149 | ~GssSecContext() | |
150 | { | |
151 | OM_uint32 tmp_maj __attribute__((unused)), tmp_min __attribute__((unused)); | |
152 | if (d_ctx != GSS_C_NO_CONTEXT) { | |
153 | tmp_maj = gss_delete_sec_context(&tmp_min, &d_ctx, GSS_C_NO_BUFFER); | |
154 | } | |
155 | if (d_peer_name != GSS_C_NO_NAME) { | |
156 | tmp_maj = gss_release_name(&tmp_min, &(d_peer_name)); | |
157 | } | |
158 | } | |
159 | ||
b08f1315 | 160 | std::shared_ptr<GssCredential> d_cred; |
dd0ef5ed OM |
161 | GssContextType d_type{GSS_CONTEXT_NONE}; |
162 | gss_ctx_id_t d_ctx{GSS_C_NO_CONTEXT}; | |
163 | gss_name_t d_peer_name{GSS_C_NO_NAME}; | |
164 | time_t d_expires{time(nullptr) + 60}; // partly initialized wil be cleaned up | |
b08f1315 OM |
165 | |
166 | enum | |
167 | { | |
168 | GssStateInitial, | |
169 | GssStateNegotiate, | |
170 | GssStateComplete, | |
171 | GssStateError | |
5e8d94f1 | 172 | } d_state{GssStateInitial}; |
dd0ef5ed OM |
173 | }; // GssSecContext |
174 | ||
175 | static LockGuarded<std::unordered_map<DNSName, std::shared_ptr<GssSecContext>>> s_gss_sec_context; | |
176 | ||
177 | template <typename T> | |
178 | static void doExpire(T& m, time_t now) | |
179 | { | |
180 | auto lock = m.lock(); | |
181 | for (auto i = lock->begin(); i != lock->end();) { | |
182 | if (now > i->second->d_expires) { | |
183 | i = lock->erase(i); | |
184 | } | |
185 | else { | |
186 | ++i; | |
187 | } | |
188 | } | |
189 | } | |
b08f1315 | 190 | |
dd0ef5ed OM |
191 | static void expire() |
192 | { | |
193 | static time_t s_last_expired; | |
194 | time_t now = time(nullptr); | |
5e8d94f1 | 195 | if (now - s_last_expired < TSIG_GSS_EXPIRE_INTERVAL) { |
dd0ef5ed OM |
196 | return; |
197 | } | |
198 | s_last_expired = now; | |
199 | doExpire(s_gss_init_creds, now); | |
200 | doExpire(s_gss_accept_creds, now); | |
201 | doExpire(s_gss_sec_context, now); | |
202 | } | |
b08f1315 OM |
203 | |
204 | bool GssContext::supported() { return true; } | |
205 | ||
206 | void GssContext::initialize() | |
207 | { | |
208 | d_peerPrincipal = ""; | |
209 | d_localPrincipal = ""; | |
210 | d_error = GSS_CONTEXT_NO_ERROR; | |
211 | d_type = GSS_CONTEXT_NONE; | |
212 | } | |
213 | ||
214 | GssContext::GssContext() | |
215 | { | |
216 | initialize(); | |
217 | generateLabel("pdns.tsig."); | |
218 | } | |
219 | ||
220 | GssContext::GssContext(const DNSName& label) | |
221 | { | |
222 | initialize(); | |
223 | setLabel(label); | |
224 | } | |
225 | ||
226 | void GssContext::generateLabel(const std::string& suffix) | |
227 | { | |
228 | std::ostringstream oss; | |
229 | oss << std::hex << time(nullptr) << "." << suffix; | |
230 | setLabel(DNSName(oss.str())); | |
231 | } | |
232 | ||
233 | void GssContext::setLabel(const DNSName& label) | |
234 | { | |
235 | d_label = label; | |
236 | auto lock = s_gss_sec_context.lock(); | |
dd0ef5ed OM |
237 | auto it = lock->find(d_label); |
238 | if (it != lock->end()) { | |
239 | d_secctx = it->second; | |
240 | d_type = d_secctx->d_type; | |
b08f1315 OM |
241 | } |
242 | } | |
243 | ||
244 | bool GssContext::expired() | |
245 | { | |
dd0ef5ed | 246 | return (!d_secctx || (d_secctx->d_expires > -1 && d_secctx->d_expires < time(nullptr))); |
b08f1315 OM |
247 | } |
248 | ||
249 | bool GssContext::valid() | |
250 | { | |
dd0ef5ed | 251 | return (d_secctx && !expired() && d_secctx->d_state == GssSecContext::GssStateComplete); |
b08f1315 OM |
252 | } |
253 | ||
254 | bool GssContext::init(const std::string& input, std::string& output) | |
255 | { | |
dd0ef5ed OM |
256 | expire(); |
257 | ||
b08f1315 OM |
258 | OM_uint32 tmp_maj __attribute__((unused)), tmp_min __attribute__((unused)); |
259 | OM_uint32 maj, min; | |
260 | gss_buffer_desc recv_tok, send_tok, buffer; | |
261 | OM_uint32 flags; | |
262 | OM_uint32 expires; | |
263 | ||
b08f1315 OM |
264 | if (d_label.empty()) { |
265 | d_error = GSS_CONTEXT_INVALID; | |
266 | return false; | |
267 | } | |
268 | ||
269 | d_type = GSS_CONTEXT_INIT; | |
dd0ef5ed | 270 | std::shared_ptr<GssCredential> cred; |
b08f1315 OM |
271 | { |
272 | auto lock = s_gss_init_creds.lock(); | |
dd0ef5ed OM |
273 | auto it = lock->find(d_localPrincipal); |
274 | if (it == lock->end()) { | |
275 | it = lock->emplace(d_localPrincipal, std::make_shared<GssCredential>(d_localPrincipal, GSS_C_INITIATE)).first; | |
b08f1315 | 276 | } |
dd0ef5ed | 277 | cred = it->second; |
b08f1315 OM |
278 | } |
279 | ||
280 | // see if we can find a context in non-completed state | |
dd0ef5ed OM |
281 | if (d_secctx) { |
282 | if (d_secctx->d_state != GssSecContext::GssStateNegotiate) { | |
b08f1315 OM |
283 | d_error = GSS_CONTEXT_INVALID; |
284 | return false; | |
285 | } | |
286 | } | |
287 | else { | |
288 | // make context | |
289 | auto lock = s_gss_sec_context.lock(); | |
dd0ef5ed OM |
290 | d_secctx = std::make_shared<GssSecContext>(cred); |
291 | d_secctx->d_state = GssSecContext::GssStateNegotiate; | |
292 | d_secctx->d_type = d_type; | |
293 | (*lock)[d_label] = d_secctx; | |
b08f1315 OM |
294 | } |
295 | ||
296 | recv_tok.length = input.size(); | |
297 | recv_tok.value = const_cast<void*>(static_cast<const void*>(input.c_str())); | |
298 | ||
299 | if (!d_peerPrincipal.empty()) { | |
300 | buffer.value = const_cast<void*>(static_cast<const void*>(d_peerPrincipal.c_str())); | |
301 | buffer.length = d_peerPrincipal.size(); | |
dd0ef5ed | 302 | maj = gss_import_name(&min, &buffer, (gss_OID)GSS_KRB5_NT_PRINCIPAL_NAME, &(d_secctx->d_peer_name)); |
b08f1315 OM |
303 | if (maj != GSS_S_COMPLETE) { |
304 | processError("gss_import_name", maj, min); | |
305 | return false; | |
306 | } | |
307 | } | |
308 | ||
dd0ef5ed | 309 | maj = gss_init_sec_context(&min, cred->d_cred, &d_secctx->d_ctx, d_secctx->d_peer_name, GSS_C_NO_OID, GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG, GSS_C_INDEFINITE, GSS_C_NO_CHANNEL_BINDINGS, &recv_tok, nullptr, &send_tok, &flags, &expires); |
b08f1315 OM |
310 | |
311 | if (send_tok.length > 0) { | |
312 | output.assign(static_cast<char*>(send_tok.value), send_tok.length); | |
313 | tmp_maj = gss_release_buffer(&tmp_min, &send_tok); | |
314 | } | |
315 | ||
316 | if (maj == GSS_S_COMPLETE) { | |
dd0ef5ed OM |
317 | // We do not want forever |
318 | if (expires == GSS_C_INDEFINITE) { | |
319 | expires = 60; | |
b08f1315 | 320 | } |
dd0ef5ed OM |
321 | d_secctx->d_expires = time(nullptr) + expires; |
322 | d_secctx->d_state = GssSecContext::GssStateComplete; | |
b08f1315 OM |
323 | return true; |
324 | } | |
325 | else if (maj != GSS_S_CONTINUE_NEEDED) { | |
326 | processError("gss_init_sec_context", maj, min); | |
327 | } | |
328 | ||
329 | return (maj == GSS_S_CONTINUE_NEEDED); | |
330 | } | |
331 | ||
332 | bool GssContext::accept(const std::string& input, std::string& output) | |
333 | { | |
dd0ef5ed OM |
334 | expire(); |
335 | ||
b08f1315 OM |
336 | OM_uint32 tmp_maj __attribute__((unused)), tmp_min __attribute__((unused)); |
337 | OM_uint32 maj, min; | |
338 | gss_buffer_desc recv_tok, send_tok; | |
339 | OM_uint32 flags; | |
340 | OM_uint32 expires; | |
341 | ||
b08f1315 OM |
342 | if (d_label.empty()) { |
343 | d_error = GSS_CONTEXT_INVALID; | |
344 | return false; | |
345 | } | |
346 | ||
347 | d_type = GSS_CONTEXT_ACCEPT; | |
dd0ef5ed | 348 | std::shared_ptr<GssCredential> cred; |
b08f1315 OM |
349 | { |
350 | auto lock = s_gss_accept_creds.lock(); | |
dd0ef5ed OM |
351 | auto it = lock->find(d_localPrincipal); |
352 | if (it == lock->end()) { | |
353 | it = lock->emplace(d_localPrincipal, std::make_shared<GssCredential>(d_localPrincipal, GSS_C_ACCEPT)).first; | |
b08f1315 | 354 | } |
dd0ef5ed | 355 | cred = it->second; |
b08f1315 OM |
356 | } |
357 | ||
358 | // see if we can find a context in non-completed state | |
dd0ef5ed OM |
359 | if (d_secctx) { |
360 | if (d_secctx->d_state != GssSecContext::GssStateNegotiate) { | |
b08f1315 OM |
361 | d_error = GSS_CONTEXT_INVALID; |
362 | return false; | |
363 | } | |
364 | } | |
365 | else { | |
366 | // make context | |
367 | auto lock = s_gss_sec_context.lock(); | |
dd0ef5ed OM |
368 | d_secctx = std::make_shared<GssSecContext>(cred); |
369 | d_secctx->d_state = GssSecContext::GssStateNegotiate; | |
370 | d_secctx->d_type = d_type; | |
371 | (*lock)[d_label] = d_secctx; | |
b08f1315 OM |
372 | } |
373 | ||
374 | recv_tok.length = input.size(); | |
375 | recv_tok.value = const_cast<void*>(static_cast<const void*>(input.c_str())); | |
376 | ||
dd0ef5ed | 377 | maj = gss_accept_sec_context(&min, &d_secctx->d_ctx, cred->d_cred, &recv_tok, GSS_C_NO_CHANNEL_BINDINGS, &d_secctx->d_peer_name, nullptr, &send_tok, &flags, &expires, nullptr); |
b08f1315 OM |
378 | |
379 | if (send_tok.length > 0) { | |
380 | output.assign(static_cast<char*>(send_tok.value), send_tok.length); | |
381 | tmp_maj = gss_release_buffer(&tmp_min, &send_tok); | |
382 | } | |
383 | ||
384 | if (maj == GSS_S_COMPLETE) { | |
dd0ef5ed OM |
385 | // We do not want forever |
386 | if (expires == GSS_C_INDEFINITE) { | |
387 | expires = 60; | |
b08f1315 | 388 | } |
dd0ef5ed OM |
389 | d_secctx->d_expires = time(nullptr) + expires; |
390 | d_secctx->d_state = GssSecContext::GssStateComplete; | |
b08f1315 OM |
391 | return true; |
392 | } | |
393 | else if (maj != GSS_S_CONTINUE_NEEDED) { | |
394 | processError("gss_accept_sec_context", maj, min); | |
395 | } | |
396 | return (maj == GSS_S_CONTINUE_NEEDED); | |
397 | }; | |
398 | ||
399 | bool GssContext::sign(const std::string& input, std::string& output) | |
400 | { | |
401 | OM_uint32 tmp_maj __attribute__((unused)), tmp_min __attribute__((unused)); | |
402 | OM_uint32 maj, min; | |
403 | ||
404 | gss_buffer_desc recv_tok = GSS_C_EMPTY_BUFFER; | |
405 | gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER; | |
406 | ||
407 | recv_tok.length = input.size(); | |
408 | recv_tok.value = const_cast<void*>(static_cast<const void*>(input.c_str())); | |
409 | ||
dd0ef5ed | 410 | maj = gss_get_mic(&min, d_secctx->d_ctx, GSS_C_QOP_DEFAULT, &recv_tok, &send_tok); |
b08f1315 OM |
411 | |
412 | if (send_tok.length > 0) { | |
413 | output.assign(static_cast<char*>(send_tok.value), send_tok.length); | |
414 | tmp_maj = gss_release_buffer(&tmp_min, &send_tok); | |
415 | } | |
416 | ||
417 | if (maj != GSS_S_COMPLETE) { | |
418 | processError("gss_get_mic", maj, min); | |
419 | } | |
420 | ||
421 | return (maj == GSS_S_COMPLETE); | |
422 | } | |
423 | ||
424 | bool GssContext::verify(const std::string& input, const std::string& signature) | |
425 | { | |
426 | OM_uint32 maj, min; | |
427 | ||
428 | gss_buffer_desc recv_tok = GSS_C_EMPTY_BUFFER; | |
429 | gss_buffer_desc sign_tok = GSS_C_EMPTY_BUFFER; | |
430 | ||
431 | recv_tok.length = input.size(); | |
dd0ef5ed | 432 | recv_tok.value = const_cast<void*>(static_cast<const void*>(input.c_str())); |
b08f1315 | 433 | sign_tok.length = signature.size(); |
dd0ef5ed | 434 | sign_tok.value = const_cast<void*>(static_cast<const void*>(signature.c_str())); |
b08f1315 | 435 | |
dd0ef5ed | 436 | maj = gss_verify_mic(&min, d_secctx->d_ctx, &recv_tok, &sign_tok, nullptr); |
b08f1315 OM |
437 | |
438 | if (maj != GSS_S_COMPLETE) { | |
439 | processError("gss_get_mic", maj, min); | |
440 | } | |
441 | ||
442 | return (maj == GSS_S_COMPLETE); | |
443 | } | |
444 | ||
445 | bool GssContext::destroy() | |
446 | { | |
dd0ef5ed OM |
447 | if (d_label.empty()) { |
448 | return false; | |
449 | } | |
450 | auto lock = s_gss_sec_context.lock(); | |
451 | return lock->erase(d_label) == 1; | |
b08f1315 OM |
452 | } |
453 | ||
454 | void GssContext::setLocalPrincipal(const std::string& name) | |
455 | { | |
456 | d_localPrincipal = name; | |
457 | } | |
458 | ||
459 | bool GssContext::getLocalPrincipal(std::string& name) | |
460 | { | |
461 | name = d_localPrincipal; | |
462 | return name.size() > 0; | |
463 | } | |
464 | ||
465 | void GssContext::setPeerPrincipal(const std::string& name) | |
466 | { | |
467 | d_peerPrincipal = name; | |
468 | } | |
469 | ||
470 | bool GssContext::getPeerPrincipal(std::string& name) | |
471 | { | |
472 | gss_buffer_desc value; | |
473 | OM_uint32 maj, min; | |
474 | ||
dd0ef5ed OM |
475 | if (d_secctx->d_peer_name != GSS_C_NO_NAME) { |
476 | maj = gss_display_name(&min, d_secctx->d_peer_name, &value, nullptr); | |
b08f1315 OM |
477 | if (maj == GSS_S_COMPLETE && value.length > 0) { |
478 | name.assign(static_cast<char*>(value.value), value.length); | |
479 | maj = gss_release_buffer(&min, &value); | |
480 | return true; | |
481 | } | |
482 | else { | |
483 | return false; | |
484 | } | |
485 | } | |
486 | else { | |
487 | return false; | |
488 | } | |
489 | } | |
490 | ||
dd0ef5ed OM |
491 | std::tuple<size_t, size_t, size_t> GssContext::getCounts() |
492 | { | |
0b0882f5 | 493 | return {s_gss_init_creds.lock()->size(), s_gss_accept_creds.lock()->size(), s_gss_sec_context.lock()->size()}; |
dd0ef5ed OM |
494 | } |
495 | ||
b08f1315 OM |
496 | void GssContext::processError(const std::string& method, OM_uint32 maj, OM_uint32 min) |
497 | { | |
498 | OM_uint32 tmp_min; | |
499 | gss_buffer_desc msg; | |
500 | OM_uint32 msg_ctx; | |
501 | ||
502 | msg_ctx = 0; | |
503 | while (1) { | |
504 | ostringstream oss; | |
6688c8c6 OM |
505 | if (gss_display_status(&tmp_min, maj, GSS_C_GSS_CODE, GSS_C_NULL_OID, &msg_ctx, &msg) == GSS_S_COMPLETE) { |
506 | oss << method << ": " << msg.value; | |
f13cde2a OM |
507 | } |
508 | else { | |
6688c8c6 OM |
509 | oss << method << ": ?"; |
510 | } | |
511 | if (msg.length != 0) { | |
512 | gss_release_buffer(&tmp_min, &msg); | |
513 | } | |
b08f1315 OM |
514 | d_gss_errors.push_back(oss.str()); |
515 | if (!msg_ctx) | |
516 | break; | |
517 | } | |
518 | msg_ctx = 0; | |
519 | while (1) { | |
520 | ostringstream oss; | |
f13cde2a | 521 | if (gss_display_status(&tmp_min, min, GSS_C_MECH_CODE, GSS_C_NULL_OID, &msg_ctx, &msg) == GSS_S_COMPLETE) { |
6688c8c6 | 522 | oss << method << ": " << msg.value; |
f13cde2a OM |
523 | } |
524 | else { | |
6688c8c6 OM |
525 | oss << method << ": ?"; |
526 | } | |
527 | if (msg.length != 0) { | |
528 | gss_release_buffer(&tmp_min, &msg); | |
529 | } | |
b08f1315 OM |
530 | d_gss_errors.push_back(oss.str()); |
531 | if (!msg_ctx) | |
532 | break; | |
533 | } | |
534 | } | |
535 | ||
536 | #endif | |
537 | ||
538 | bool gss_add_signature(const DNSName& context, const std::string& message, std::string& mac) | |
539 | { | |
540 | string tmp_mac; | |
541 | GssContext gssctx(context); | |
542 | if (!gssctx.valid()) { | |
543 | g_log << Logger::Error << "GSS context '" << context << "' is not valid" << endl; | |
544 | for (const string& error : gssctx.getErrorStrings()) { | |
545 | g_log << Logger::Error << "GSS error: " << error << endl; | |
546 | ; | |
547 | } | |
548 | return false; | |
549 | } | |
550 | ||
551 | if (!gssctx.sign(message, tmp_mac)) { | |
552 | g_log << Logger::Error << "Could not sign message using GSS context '" << context << "'" << endl; | |
553 | for (const string& error : gssctx.getErrorStrings()) { | |
554 | g_log << Logger::Error << "GSS error: " << error << endl; | |
555 | ; | |
556 | } | |
557 | return false; | |
558 | } | |
3b45a434 | 559 | mac = std::move(tmp_mac); |
b08f1315 OM |
560 | return true; |
561 | } | |
562 | ||
563 | bool gss_verify_signature(const DNSName& context, const std::string& message, const std::string& mac) | |
564 | { | |
565 | GssContext gssctx(context); | |
566 | if (!gssctx.valid()) { | |
567 | g_log << Logger::Error << "GSS context '" << context << "' is not valid" << endl; | |
568 | for (const string& error : gssctx.getErrorStrings()) { | |
569 | g_log << Logger::Error << "GSS error: " << error << endl; | |
570 | ; | |
571 | } | |
572 | return false; | |
573 | } | |
574 | ||
575 | if (!gssctx.verify(message, mac)) { | |
576 | g_log << Logger::Error << "Could not verify message using GSS context '" << context << "'" << endl; | |
577 | for (const string& error : gssctx.getErrorStrings()) { | |
578 | g_log << Logger::Error << "GSS error: " << error << endl; | |
579 | ; | |
580 | } | |
581 | return false; | |
582 | } | |
583 | return true; | |
584 | } |