s3:gse: We need to use the users realm in the target_principal
[Samba.git] / source3 / librpc / crypto / gse.c
blobd0ae53c406adfb6ceb6478941ce30e3a9da65129
1 /*
2 * GSSAPI Security Extensions
3 * RPC Pipe client and server routines
4 * Copyright (C) Simo Sorce 2010.
5 * Copyright (C) Andrew Bartlett 2004-2011.
6 * Copyright (C) Stefan Metzmacher <metze@samba.org> 2004-2005
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 3 of the License, or
11 * (at your option) any later version.
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.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, see <http://www.gnu.org/licenses/>.
22 /* We support only GSSAPI/KRB5 here */
24 #include "includes.h"
25 #include "gse.h"
26 #include "libads/kerberos_proto.h"
27 #include "auth/common_auth.h"
28 #include "auth/gensec/gensec.h"
29 #include "auth/gensec/gensec_internal.h"
30 #include "auth/credentials/credentials.h"
31 #include "../librpc/gen_ndr/dcerpc.h"
33 #if defined(HAVE_KRB5)
35 #include "auth/kerberos/pac_utils.h"
36 #include "auth/kerberos/gssapi_helper.h"
37 #include "gse_krb5.h"
39 static char *gse_errstr(TALLOC_CTX *mem_ctx, OM_uint32 maj, OM_uint32 min);
40 static size_t gensec_gse_sig_size(struct gensec_security *gensec_security,
41 size_t data_size);
43 struct gse_context {
44 gss_ctx_id_t gssapi_context;
45 gss_name_t server_name;
46 gss_name_t client_name;
47 OM_uint32 gss_want_flags, gss_got_flags;
48 size_t max_wrap_buf_size;
49 size_t sig_size;
51 gss_cred_id_t delegated_cred_handle;
53 NTTIME expire_time;
55 /* gensec_gse only */
56 krb5_context k5ctx;
57 krb5_ccache ccache;
58 krb5_keytab keytab;
60 gss_OID_desc gss_mech;
61 gss_cred_id_t creds;
63 gss_OID ret_mech;
66 /* free non talloc dependent contexts */
67 static int gse_context_destructor(void *ptr)
69 struct gse_context *gse_ctx;
70 OM_uint32 gss_min;
72 gse_ctx = talloc_get_type_abort(ptr, struct gse_context);
73 if (gse_ctx->k5ctx) {
74 if (gse_ctx->ccache) {
75 krb5_cc_close(gse_ctx->k5ctx, gse_ctx->ccache);
76 gse_ctx->ccache = NULL;
78 if (gse_ctx->keytab) {
79 krb5_kt_close(gse_ctx->k5ctx, gse_ctx->keytab);
80 gse_ctx->keytab = NULL;
82 krb5_free_context(gse_ctx->k5ctx);
83 gse_ctx->k5ctx = NULL;
85 if (gse_ctx->gssapi_context != GSS_C_NO_CONTEXT) {
86 (void)gss_delete_sec_context(&gss_min,
87 &gse_ctx->gssapi_context,
88 GSS_C_NO_BUFFER);
90 if (gse_ctx->server_name) {
91 (void)gss_release_name(&gss_min,
92 &gse_ctx->server_name);
94 if (gse_ctx->client_name) {
95 (void)gss_release_name(&gss_min,
96 &gse_ctx->client_name);
98 if (gse_ctx->creds) {
99 (void)gss_release_cred(&gss_min,
100 &gse_ctx->creds);
102 if (gse_ctx->delegated_cred_handle) {
103 (void)gss_release_cred(&gss_min,
104 &gse_ctx->delegated_cred_handle);
107 /* MIT and Heimdal differ as to if you can call
108 * gss_release_oid() on this OID, generated by
109 * gss_{accept,init}_sec_context(). However, as long as the
110 * oid is gss_mech_krb5 (which it always is at the moment),
111 * then this is a moot point, as both declare this particular
112 * OID static, and so no memory is lost. This assert is in
113 * place to ensure that the programmer who wishes to extend
114 * this code to EAP or other GSS mechanisms determines an
115 * implementation-dependent way of releasing any dynamically
116 * allocated OID */
117 SMB_ASSERT(smb_gss_oid_equal(&gse_ctx->gss_mech, GSS_C_NO_OID) ||
118 smb_gss_oid_equal(&gse_ctx->gss_mech, gss_mech_krb5));
120 return 0;
123 static NTSTATUS gse_context_init(TALLOC_CTX *mem_ctx,
124 bool do_sign, bool do_seal,
125 const char *ccache_name,
126 uint32_t add_gss_c_flags,
127 struct gse_context **_gse_ctx)
129 struct gse_context *gse_ctx;
130 krb5_error_code k5ret;
131 NTSTATUS status;
133 gse_ctx = talloc_zero(mem_ctx, struct gse_context);
134 if (!gse_ctx) {
135 return NT_STATUS_NO_MEMORY;
137 talloc_set_destructor((TALLOC_CTX *)gse_ctx, gse_context_destructor);
139 gse_ctx->expire_time = GENSEC_EXPIRE_TIME_INFINITY;
140 gse_ctx->max_wrap_buf_size = UINT16_MAX;
142 memcpy(&gse_ctx->gss_mech, gss_mech_krb5, sizeof(gss_OID_desc));
144 gse_ctx->gss_want_flags = GSS_C_MUTUAL_FLAG |
145 GSS_C_DELEG_FLAG |
146 GSS_C_DELEG_POLICY_FLAG |
147 GSS_C_REPLAY_FLAG |
148 GSS_C_SEQUENCE_FLAG;
149 if (do_sign) {
150 gse_ctx->gss_want_flags |= GSS_C_INTEG_FLAG;
152 if (do_seal) {
153 gse_ctx->gss_want_flags |= GSS_C_INTEG_FLAG;
154 gse_ctx->gss_want_flags |= GSS_C_CONF_FLAG;
157 gse_ctx->gss_want_flags |= add_gss_c_flags;
159 /* Initialize Kerberos Context */
160 initialize_krb5_error_table();
162 k5ret = krb5_init_context(&gse_ctx->k5ctx);
163 if (k5ret) {
164 DEBUG(0, ("Failed to initialize kerberos context! (%s)\n",
165 error_message(k5ret)));
166 status = NT_STATUS_INTERNAL_ERROR;
167 goto err_out;
170 if (!ccache_name) {
171 ccache_name = krb5_cc_default_name(gse_ctx->k5ctx);
173 k5ret = krb5_cc_resolve(gse_ctx->k5ctx, ccache_name,
174 &gse_ctx->ccache);
175 if (k5ret) {
176 DEBUG(1, ("Failed to resolve credential cache! (%s)\n",
177 error_message(k5ret)));
178 status = NT_STATUS_INTERNAL_ERROR;
179 goto err_out;
182 /* TODO: Should we enforce a enc_types list ?
183 ret = krb5_set_default_tgs_ktypes(gse_ctx->k5ctx, enc_types);
186 *_gse_ctx = gse_ctx;
187 return NT_STATUS_OK;
189 err_out:
190 TALLOC_FREE(gse_ctx);
191 return status;
194 static NTSTATUS gse_init_client(TALLOC_CTX *mem_ctx,
195 bool do_sign, bool do_seal,
196 const char *ccache_name,
197 const char *server,
198 const char *service,
199 const char *realm,
200 const char *username,
201 const char *password,
202 uint32_t add_gss_c_flags,
203 struct gse_context **_gse_ctx)
205 struct gse_context *gse_ctx;
206 OM_uint32 gss_maj, gss_min;
207 gss_buffer_desc name_buffer = GSS_C_EMPTY_BUFFER;
208 gss_OID_set_desc mech_set;
209 #ifdef HAVE_GSS_KRB5_CRED_NO_CI_FLAGS_X
210 gss_buffer_desc empty_buffer = GSS_C_EMPTY_BUFFER;
211 gss_OID oid = discard_const(GSS_KRB5_CRED_NO_CI_FLAGS_X);
212 #endif
213 NTSTATUS status;
215 if (!server || !service) {
216 return NT_STATUS_INVALID_PARAMETER;
219 status = gse_context_init(mem_ctx, do_sign, do_seal,
220 ccache_name, add_gss_c_flags,
221 &gse_ctx);
222 if (!NT_STATUS_IS_OK(status)) {
223 return NT_STATUS_NO_MEMORY;
226 /* Guess the realm based on the supplied service, and avoid the GSS libs
227 doing DNS lookups which may fail.
229 TODO: Loop with the KDC on some more combinations (local
230 realm in particular), possibly falling back to
231 GSS_C_NT_HOSTBASED_SERVICE
233 name_buffer.value =
234 smb_krb5_get_principal_from_service_hostname(gse_ctx,
235 service,
236 server,
237 realm);
238 if (!name_buffer.value) {
239 status = NT_STATUS_NO_MEMORY;
240 goto err_out;
242 name_buffer.length = strlen((char *)name_buffer.value);
243 gss_maj = gss_import_name(&gss_min, &name_buffer,
244 GSS_C_NT_USER_NAME,
245 &gse_ctx->server_name);
246 if (gss_maj) {
247 DEBUG(5, ("gss_import_name failed for %s, with [%s]\n",
248 (char *)name_buffer.value,
249 gse_errstr(gse_ctx, gss_maj, gss_min)));
250 status = NT_STATUS_INTERNAL_ERROR;
251 goto err_out;
254 /* TODO: get krb5 ticket using username/password, if no valid
255 * one already available in ccache */
257 mech_set.count = 1;
258 mech_set.elements = &gse_ctx->gss_mech;
260 gss_maj = gss_acquire_cred(&gss_min,
261 GSS_C_NO_NAME,
262 GSS_C_INDEFINITE,
263 &mech_set,
264 GSS_C_INITIATE,
265 &gse_ctx->creds,
266 NULL, NULL);
267 if (gss_maj) {
268 DEBUG(5, ("gss_acquire_creds failed for GSS_C_NO_NAME with [%s] -"
269 "the caller may retry after a kinit.\n",
270 gse_errstr(gse_ctx, gss_maj, gss_min)));
271 status = NT_STATUS_INTERNAL_ERROR;
272 goto err_out;
275 #ifdef HAVE_GSS_KRB5_CRED_NO_CI_FLAGS_X
277 * Don't force GSS_C_CONF_FLAG and GSS_C_INTEG_FLAG.
279 * This allows us to disable SIGN and SEAL for
280 * AUTH_LEVEL_CONNECT and AUTH_LEVEL_INTEGRITY.
282 * https://groups.yahoo.com/neo/groups/cat-ietf/conversations/topics/575
283 * http://krbdev.mit.edu/rt/Ticket/Display.html?id=6938
285 gss_maj = gss_set_cred_option(&gss_min, &gse_ctx->creds,
286 oid,
287 &empty_buffer);
288 if (gss_maj) {
289 DEBUG(0, ("gss_set_cred_option(GSS_KRB5_CRED_NO_CI_FLAGS_X), "
290 "failed with [%s]\n",
291 gse_errstr(gse_ctx, gss_maj, gss_min)));
292 status = NT_STATUS_INTERNAL_ERROR;
293 goto err_out;
295 #endif
297 *_gse_ctx = gse_ctx;
298 TALLOC_FREE(name_buffer.value);
299 return NT_STATUS_OK;
301 err_out:
302 TALLOC_FREE(name_buffer.value);
303 TALLOC_FREE(gse_ctx);
304 return status;
307 static NTSTATUS gse_get_client_auth_token(TALLOC_CTX *mem_ctx,
308 struct gse_context *gse_ctx,
309 const DATA_BLOB *token_in,
310 DATA_BLOB *token_out)
312 OM_uint32 gss_maj, gss_min;
313 gss_buffer_desc in_data;
314 gss_buffer_desc out_data;
315 DATA_BLOB blob = data_blob_null;
316 NTSTATUS status;
317 OM_uint32 time_rec = 0;
318 struct timeval tv;
320 in_data.value = token_in->data;
321 in_data.length = token_in->length;
323 gss_maj = gss_init_sec_context(&gss_min,
324 gse_ctx->creds,
325 &gse_ctx->gssapi_context,
326 gse_ctx->server_name,
327 &gse_ctx->gss_mech,
328 gse_ctx->gss_want_flags,
329 0, GSS_C_NO_CHANNEL_BINDINGS,
330 &in_data, NULL, &out_data,
331 &gse_ctx->gss_got_flags, &time_rec);
332 switch (gss_maj) {
333 case GSS_S_COMPLETE:
334 /* we are done with it */
335 tv = timeval_current_ofs(time_rec, 0);
336 gse_ctx->expire_time = timeval_to_nttime(&tv);
338 status = NT_STATUS_OK;
339 break;
340 case GSS_S_CONTINUE_NEEDED:
341 /* we will need a third leg */
342 status = NT_STATUS_MORE_PROCESSING_REQUIRED;
343 break;
344 default:
345 if ((gss_maj == GSS_S_FAILURE) &&
346 (gss_min == KRB5KRB_AP_ERR_TKT_EXPIRED)) {
347 DBG_NOTICE("Ticket expired\n");
348 } else {
349 DBG_ERR("gss_init_sec_context failed with [%s]\n",
350 gse_errstr(talloc_tos(), gss_maj, gss_min));
352 status = NT_STATUS_INTERNAL_ERROR;
353 goto done;
356 /* we may be told to return nothing */
357 if (out_data.length) {
358 blob = data_blob_talloc(mem_ctx, out_data.value, out_data.length);
359 if (!blob.data) {
360 status = NT_STATUS_NO_MEMORY;
363 gss_maj = gss_release_buffer(&gss_min, &out_data);
366 done:
367 *token_out = blob;
368 return status;
371 static NTSTATUS gse_init_server(TALLOC_CTX *mem_ctx,
372 bool do_sign, bool do_seal,
373 uint32_t add_gss_c_flags,
374 struct gse_context **_gse_ctx)
376 struct gse_context *gse_ctx;
377 OM_uint32 gss_maj, gss_min;
378 krb5_error_code ret;
379 NTSTATUS status;
381 status = gse_context_init(mem_ctx, do_sign, do_seal,
382 NULL, add_gss_c_flags, &gse_ctx);
383 if (!NT_STATUS_IS_OK(status)) {
384 return NT_STATUS_NO_MEMORY;
387 ret = gse_krb5_get_server_keytab(gse_ctx->k5ctx,
388 &gse_ctx->keytab);
389 if (ret) {
390 status = NT_STATUS_INTERNAL_ERROR;
391 goto done;
394 #ifdef HAVE_GSS_KRB5_IMPORT_CRED
396 /* This creates a GSSAPI cred_id_t with the keytab set */
397 gss_maj = gss_krb5_import_cred(&gss_min, NULL, NULL, gse_ctx->keytab,
398 &gse_ctx->creds);
400 if (gss_maj != 0
401 && gss_maj != (GSS_S_CALL_BAD_STRUCTURE|GSS_S_BAD_NAME)) {
402 DEBUG(0, ("gss_krb5_import_cred failed with [%s]\n",
403 gse_errstr(gse_ctx, gss_maj, gss_min)));
404 status = NT_STATUS_INTERNAL_ERROR;
405 goto done;
407 /* This is the error the MIT krb5 1.9 gives when it
408 * implements the function, but we do not specify the
409 * principal. However, when we specify the principal
410 * as host$@REALM the GSS acceptor fails with 'wrong
411 * principal in request'. Work around the issue by
412 * falling back to the alternate approach below. */
413 } else if (gss_maj == (GSS_S_CALL_BAD_STRUCTURE|GSS_S_BAD_NAME))
414 #endif
415 /* FIXME!!!
416 * This call sets the default keytab for the whole server, not
417 * just for this context. Need to find a way that does not alter
418 * the state of the whole server ... */
420 const char *ktname;
421 gss_OID_set_desc mech_set;
423 ret = smb_krb5_kt_get_name(gse_ctx, gse_ctx->k5ctx,
424 gse_ctx->keytab, &ktname);
425 if (ret) {
426 status = NT_STATUS_INTERNAL_ERROR;
427 goto done;
430 ret = gsskrb5_register_acceptor_identity(ktname);
431 if (ret) {
432 status = NT_STATUS_INTERNAL_ERROR;
433 goto done;
436 mech_set.count = 1;
437 mech_set.elements = &gse_ctx->gss_mech;
439 gss_maj = gss_acquire_cred(&gss_min,
440 GSS_C_NO_NAME,
441 GSS_C_INDEFINITE,
442 &mech_set,
443 GSS_C_ACCEPT,
444 &gse_ctx->creds,
445 NULL, NULL);
447 if (gss_maj) {
448 DEBUG(0, ("gss_acquire_creds failed with [%s]\n",
449 gse_errstr(gse_ctx, gss_maj, gss_min)));
450 status = NT_STATUS_INTERNAL_ERROR;
451 goto done;
455 status = NT_STATUS_OK;
457 done:
458 if (!NT_STATUS_IS_OK(status)) {
459 TALLOC_FREE(gse_ctx);
462 *_gse_ctx = gse_ctx;
463 return status;
466 static NTSTATUS gse_get_server_auth_token(TALLOC_CTX *mem_ctx,
467 struct gse_context *gse_ctx,
468 const DATA_BLOB *token_in,
469 DATA_BLOB *token_out)
471 OM_uint32 gss_maj, gss_min;
472 gss_buffer_desc in_data;
473 gss_buffer_desc out_data;
474 DATA_BLOB blob = data_blob_null;
475 NTSTATUS status;
476 OM_uint32 time_rec = 0;
477 struct timeval tv;
479 in_data.value = token_in->data;
480 in_data.length = token_in->length;
482 gss_maj = gss_accept_sec_context(&gss_min,
483 &gse_ctx->gssapi_context,
484 gse_ctx->creds,
485 &in_data,
486 GSS_C_NO_CHANNEL_BINDINGS,
487 &gse_ctx->client_name,
488 &gse_ctx->ret_mech,
489 &out_data,
490 &gse_ctx->gss_got_flags,
491 &time_rec,
492 &gse_ctx->delegated_cred_handle);
493 switch (gss_maj) {
494 case GSS_S_COMPLETE:
495 /* we are done with it */
496 tv = timeval_current_ofs(time_rec, 0);
497 gse_ctx->expire_time = timeval_to_nttime(&tv);
499 status = NT_STATUS_OK;
500 break;
501 case GSS_S_CONTINUE_NEEDED:
502 /* we will need a third leg */
503 status = NT_STATUS_MORE_PROCESSING_REQUIRED;
504 break;
505 default:
506 DEBUG(1, ("gss_accept_sec_context failed with [%s]\n",
507 gse_errstr(talloc_tos(), gss_maj, gss_min)));
509 if (gse_ctx->gssapi_context) {
510 gss_delete_sec_context(&gss_min,
511 &gse_ctx->gssapi_context,
512 GSS_C_NO_BUFFER);
516 * If we got an output token, make Windows aware of it
517 * by telling it that more processing is needed
519 if (out_data.length > 0) {
520 status = NT_STATUS_MORE_PROCESSING_REQUIRED;
521 /* Fall through to handle the out token */
522 } else {
523 status = NT_STATUS_LOGON_FAILURE;
524 goto done;
528 /* we may be told to return nothing */
529 if (out_data.length) {
530 blob = data_blob_talloc(mem_ctx, out_data.value, out_data.length);
531 if (!blob.data) {
532 status = NT_STATUS_NO_MEMORY;
534 gss_maj = gss_release_buffer(&gss_min, &out_data);
538 done:
539 *token_out = blob;
540 return status;
543 static char *gse_errstr(TALLOC_CTX *mem_ctx, OM_uint32 maj, OM_uint32 min)
545 OM_uint32 gss_min, gss_maj;
546 gss_buffer_desc msg_min;
547 gss_buffer_desc msg_maj;
548 OM_uint32 msg_ctx = 0;
550 char *errstr = NULL;
552 ZERO_STRUCT(msg_min);
553 ZERO_STRUCT(msg_maj);
555 gss_maj = gss_display_status(&gss_min, maj, GSS_C_GSS_CODE,
556 GSS_C_NO_OID, &msg_ctx, &msg_maj);
557 if (gss_maj) {
558 goto done;
560 errstr = talloc_strndup(mem_ctx,
561 (char *)msg_maj.value,
562 msg_maj.length);
563 if (!errstr) {
564 goto done;
566 gss_maj = gss_display_status(&gss_min, min, GSS_C_MECH_CODE,
567 (gss_OID)discard_const(gss_mech_krb5),
568 &msg_ctx, &msg_min);
569 if (gss_maj) {
570 goto done;
573 errstr = talloc_strdup_append_buffer(errstr, ": ");
574 if (!errstr) {
575 goto done;
577 errstr = talloc_strndup_append_buffer(errstr,
578 (char *)msg_min.value,
579 msg_min.length);
580 if (!errstr) {
581 goto done;
584 done:
585 if (msg_min.value) {
586 gss_maj = gss_release_buffer(&gss_min, &msg_min);
588 if (msg_maj.value) {
589 gss_maj = gss_release_buffer(&gss_min, &msg_maj);
591 return errstr;
594 static NTSTATUS gensec_gse_client_start(struct gensec_security *gensec_security)
596 struct gse_context *gse_ctx;
597 struct cli_credentials *creds = gensec_get_credentials(gensec_security);
598 NTSTATUS nt_status;
599 OM_uint32 want_flags = 0;
600 bool do_sign = false, do_seal = false;
601 const char *hostname = gensec_get_target_hostname(gensec_security);
602 const char *service = gensec_get_target_service(gensec_security);
603 const char *username = cli_credentials_get_username(creds);
604 const char *password = cli_credentials_get_password(creds);
605 const char *realm = cli_credentials_get_realm(creds);
607 if (!hostname) {
608 DEBUG(1, ("Could not determine hostname for target computer, cannot use kerberos\n"));
609 return NT_STATUS_INVALID_PARAMETER;
611 if (is_ipaddress(hostname)) {
612 DEBUG(2, ("Cannot do GSE to an IP address\n"));
613 return NT_STATUS_INVALID_PARAMETER;
615 if (strcmp(hostname, "localhost") == 0) {
616 DEBUG(2, ("GSE to 'localhost' does not make sense\n"));
617 return NT_STATUS_INVALID_PARAMETER;
620 if (gensec_security->want_features & GENSEC_FEATURE_SESSION_KEY) {
621 do_sign = true;
623 if (gensec_security->want_features & GENSEC_FEATURE_SIGN) {
624 do_sign = true;
626 if (gensec_security->want_features & GENSEC_FEATURE_SEAL) {
627 do_seal = true;
629 if (gensec_security->want_features & GENSEC_FEATURE_DCE_STYLE) {
630 want_flags |= GSS_C_DCE_STYLE;
633 nt_status = gse_init_client(gensec_security, do_sign, do_seal, NULL,
634 hostname, service, realm,
635 username, password, want_flags,
636 &gse_ctx);
637 if (!NT_STATUS_IS_OK(nt_status)) {
638 return nt_status;
640 gensec_security->private_data = gse_ctx;
641 return NT_STATUS_OK;
644 static NTSTATUS gensec_gse_server_start(struct gensec_security *gensec_security)
646 struct gse_context *gse_ctx;
647 NTSTATUS nt_status;
648 OM_uint32 want_flags = 0;
649 bool do_sign = false, do_seal = false;
651 if (gensec_security->want_features & GENSEC_FEATURE_SIGN) {
652 do_sign = true;
654 if (gensec_security->want_features & GENSEC_FEATURE_SEAL) {
655 do_seal = true;
657 if (gensec_security->want_features & GENSEC_FEATURE_DCE_STYLE) {
658 want_flags |= GSS_C_DCE_STYLE;
661 nt_status = gse_init_server(gensec_security, do_sign, do_seal, want_flags,
662 &gse_ctx);
663 if (!NT_STATUS_IS_OK(nt_status)) {
664 return nt_status;
666 gensec_security->private_data = gse_ctx;
667 return NT_STATUS_OK;
671 * Next state function for the GSE GENSEC mechanism
673 * @param gensec_gse_state GSE State
674 * @param mem_ctx The TALLOC_CTX for *out to be allocated on
675 * @param in The request, as a DATA_BLOB
676 * @param out The reply, as an talloc()ed DATA_BLOB, on *mem_ctx
677 * @return Error, MORE_PROCESSING_REQUIRED if a reply is sent,
678 * or NT_STATUS_OK if the user is authenticated.
681 static NTSTATUS gensec_gse_update(struct gensec_security *gensec_security,
682 TALLOC_CTX *mem_ctx,
683 struct tevent_context *ev,
684 const DATA_BLOB in, DATA_BLOB *out)
686 NTSTATUS status;
687 struct gse_context *gse_ctx =
688 talloc_get_type_abort(gensec_security->private_data,
689 struct gse_context);
691 switch (gensec_security->gensec_role) {
692 case GENSEC_CLIENT:
693 status = gse_get_client_auth_token(mem_ctx, gse_ctx,
694 &in, out);
695 break;
696 case GENSEC_SERVER:
697 status = gse_get_server_auth_token(mem_ctx, gse_ctx,
698 &in, out);
699 break;
701 if (!NT_STATUS_IS_OK(status)) {
702 return status;
705 return NT_STATUS_OK;
708 static NTSTATUS gensec_gse_wrap(struct gensec_security *gensec_security,
709 TALLOC_CTX *mem_ctx,
710 const DATA_BLOB *in,
711 DATA_BLOB *out)
713 struct gse_context *gse_ctx =
714 talloc_get_type_abort(gensec_security->private_data,
715 struct gse_context);
716 OM_uint32 maj_stat, min_stat;
717 gss_buffer_desc input_token, output_token;
718 int conf_state;
719 input_token.length = in->length;
720 input_token.value = in->data;
722 maj_stat = gss_wrap(&min_stat,
723 gse_ctx->gssapi_context,
724 gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL),
725 GSS_C_QOP_DEFAULT,
726 &input_token,
727 &conf_state,
728 &output_token);
729 if (GSS_ERROR(maj_stat)) {
730 DEBUG(0, ("gensec_gse_wrap: GSS Wrap failed: %s\n",
731 gse_errstr(talloc_tos(), maj_stat, min_stat)));
732 return NT_STATUS_ACCESS_DENIED;
735 *out = data_blob_talloc(mem_ctx, output_token.value, output_token.length);
736 gss_release_buffer(&min_stat, &output_token);
738 if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)
739 && !conf_state) {
740 return NT_STATUS_ACCESS_DENIED;
742 return NT_STATUS_OK;
745 static NTSTATUS gensec_gse_unwrap(struct gensec_security *gensec_security,
746 TALLOC_CTX *mem_ctx,
747 const DATA_BLOB *in,
748 DATA_BLOB *out)
750 struct gse_context *gse_ctx =
751 talloc_get_type_abort(gensec_security->private_data,
752 struct gse_context);
753 OM_uint32 maj_stat, min_stat;
754 gss_buffer_desc input_token, output_token;
755 int conf_state;
756 gss_qop_t qop_state;
757 input_token.length = in->length;
758 input_token.value = in->data;
760 maj_stat = gss_unwrap(&min_stat,
761 gse_ctx->gssapi_context,
762 &input_token,
763 &output_token,
764 &conf_state,
765 &qop_state);
766 if (GSS_ERROR(maj_stat)) {
767 DEBUG(0, ("gensec_gse_unwrap: GSS UnWrap failed: %s\n",
768 gse_errstr(talloc_tos(), maj_stat, min_stat)));
769 return NT_STATUS_ACCESS_DENIED;
772 *out = data_blob_talloc(mem_ctx, output_token.value, output_token.length);
773 gss_release_buffer(&min_stat, &output_token);
775 if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)
776 && !conf_state) {
777 return NT_STATUS_ACCESS_DENIED;
779 return NT_STATUS_OK;
782 static NTSTATUS gensec_gse_seal_packet(struct gensec_security *gensec_security,
783 TALLOC_CTX *mem_ctx,
784 uint8_t *data, size_t length,
785 const uint8_t *whole_pdu, size_t pdu_length,
786 DATA_BLOB *sig)
788 struct gse_context *gse_ctx =
789 talloc_get_type_abort(gensec_security->private_data,
790 struct gse_context);
791 bool hdr_signing = false;
792 size_t sig_size = 0;
793 NTSTATUS status;
795 if (gensec_security->want_features & GENSEC_FEATURE_SIGN_PKT_HEADER) {
796 hdr_signing = true;
799 sig_size = gensec_gse_sig_size(gensec_security, length);
801 status = gssapi_seal_packet(gse_ctx->gssapi_context,
802 &gse_ctx->gss_mech,
803 hdr_signing, sig_size,
804 data, length,
805 whole_pdu, pdu_length,
806 mem_ctx, sig);
807 if (!NT_STATUS_IS_OK(status)) {
808 DEBUG(0, ("gssapi_seal_packet(hdr_signing=%u,sig_size=%zu,"
809 "data=%zu,pdu=%zu) failed: %s\n",
810 hdr_signing, sig_size, length, pdu_length,
811 nt_errstr(status)));
812 return status;
815 return NT_STATUS_OK;
818 static NTSTATUS gensec_gse_unseal_packet(struct gensec_security *gensec_security,
819 uint8_t *data, size_t length,
820 const uint8_t *whole_pdu, size_t pdu_length,
821 const DATA_BLOB *sig)
823 struct gse_context *gse_ctx =
824 talloc_get_type_abort(gensec_security->private_data,
825 struct gse_context);
826 bool hdr_signing = false;
827 NTSTATUS status;
829 if (gensec_security->want_features & GENSEC_FEATURE_SIGN_PKT_HEADER) {
830 hdr_signing = true;
833 status = gssapi_unseal_packet(gse_ctx->gssapi_context,
834 &gse_ctx->gss_mech,
835 hdr_signing,
836 data, length,
837 whole_pdu, pdu_length,
838 sig);
839 if (!NT_STATUS_IS_OK(status)) {
840 DEBUG(0, ("gssapi_unseal_packet(hdr_signing=%u,sig_size=%zu,"
841 "data=%zu,pdu=%zu) failed: %s\n",
842 hdr_signing, sig->length, length, pdu_length,
843 nt_errstr(status)));
844 return status;
847 return NT_STATUS_OK;
850 static NTSTATUS gensec_gse_sign_packet(struct gensec_security *gensec_security,
851 TALLOC_CTX *mem_ctx,
852 const uint8_t *data, size_t length,
853 const uint8_t *whole_pdu, size_t pdu_length,
854 DATA_BLOB *sig)
856 struct gse_context *gse_ctx =
857 talloc_get_type_abort(gensec_security->private_data,
858 struct gse_context);
859 bool hdr_signing = false;
860 NTSTATUS status;
862 if (gensec_security->want_features & GENSEC_FEATURE_SIGN_PKT_HEADER) {
863 hdr_signing = true;
866 status = gssapi_sign_packet(gse_ctx->gssapi_context,
867 &gse_ctx->gss_mech,
868 hdr_signing,
869 data, length,
870 whole_pdu, pdu_length,
871 mem_ctx, sig);
872 if (!NT_STATUS_IS_OK(status)) {
873 DEBUG(0, ("gssapi_sign_packet(hdr_signing=%u,"
874 "data=%zu,pdu=%zu) failed: %s\n",
875 hdr_signing, length, pdu_length,
876 nt_errstr(status)));
877 return status;
880 return NT_STATUS_OK;
883 static NTSTATUS gensec_gse_check_packet(struct gensec_security *gensec_security,
884 const uint8_t *data, size_t length,
885 const uint8_t *whole_pdu, size_t pdu_length,
886 const DATA_BLOB *sig)
888 struct gse_context *gse_ctx =
889 talloc_get_type_abort(gensec_security->private_data,
890 struct gse_context);
891 bool hdr_signing = false;
892 NTSTATUS status;
894 if (gensec_security->want_features & GENSEC_FEATURE_SIGN_PKT_HEADER) {
895 hdr_signing = true;
898 status = gssapi_check_packet(gse_ctx->gssapi_context,
899 &gse_ctx->gss_mech,
900 hdr_signing,
901 data, length,
902 whole_pdu, pdu_length,
903 sig);
904 if (!NT_STATUS_IS_OK(status)) {
905 DEBUG(0, ("gssapi_check_packet(hdr_signing=%u,sig_size=%zu"
906 "data=%zu,pdu=%zu) failed: %s\n",
907 hdr_signing, sig->length, length, pdu_length,
908 nt_errstr(status)));
909 return status;
912 return NT_STATUS_OK;
915 /* Try to figure out what features we actually got on the connection */
916 static bool gensec_gse_have_feature(struct gensec_security *gensec_security,
917 uint32_t feature)
919 struct gse_context *gse_ctx =
920 talloc_get_type_abort(gensec_security->private_data,
921 struct gse_context);
923 if (feature & GENSEC_FEATURE_SESSION_KEY) {
924 return gse_ctx->gss_got_flags & GSS_C_INTEG_FLAG;
926 if (feature & GENSEC_FEATURE_SIGN) {
927 return gse_ctx->gss_got_flags & GSS_C_INTEG_FLAG;
929 if (feature & GENSEC_FEATURE_SEAL) {
930 return gse_ctx->gss_got_flags & GSS_C_CONF_FLAG;
932 if (feature & GENSEC_FEATURE_DCE_STYLE) {
933 return gse_ctx->gss_got_flags & GSS_C_DCE_STYLE;
935 if (feature & GENSEC_FEATURE_NEW_SPNEGO) {
936 NTSTATUS status;
937 uint32_t keytype;
939 if (!(gse_ctx->gss_got_flags & GSS_C_INTEG_FLAG)) {
940 return false;
943 status = gssapi_get_session_key(talloc_tos(),
944 gse_ctx->gssapi_context, NULL, &keytype);
946 * We should do a proper sig on the mechListMic unless
947 * we know we have to be backwards compatible with
948 * earlier windows versions.
950 * Negotiating a non-krb5
951 * mech for example should be regarded as having
952 * NEW_SPNEGO
954 if (NT_STATUS_IS_OK(status)) {
955 switch (keytype) {
956 case ENCTYPE_DES_CBC_CRC:
957 case ENCTYPE_DES_CBC_MD5:
958 case ENCTYPE_ARCFOUR_HMAC:
959 case ENCTYPE_DES3_CBC_SHA1:
960 return false;
963 return true;
965 /* We can always do async (rather than strict request/reply) packets. */
966 if (feature & GENSEC_FEATURE_ASYNC_REPLIES) {
967 return true;
969 if (feature & GENSEC_FEATURE_SIGN_PKT_HEADER) {
970 if (gensec_security->want_features & GENSEC_FEATURE_SEAL) {
971 return true;
974 if (gensec_security->want_features & GENSEC_FEATURE_SIGN) {
975 return true;
978 return false;
980 return false;
983 static NTTIME gensec_gse_expire_time(struct gensec_security *gensec_security)
985 struct gse_context *gse_ctx =
986 talloc_get_type_abort(gensec_security->private_data,
987 struct gse_context);
989 return gse_ctx->expire_time;
993 * Extract the 'sesssion key' needed by SMB signing and ncacn_np
994 * (for encrypting some passwords).
996 * This breaks all the abstractions, but what do you expect...
998 static NTSTATUS gensec_gse_session_key(struct gensec_security *gensec_security,
999 TALLOC_CTX *mem_ctx,
1000 DATA_BLOB *session_key)
1002 struct gse_context *gse_ctx =
1003 talloc_get_type_abort(gensec_security->private_data,
1004 struct gse_context);
1006 return gssapi_get_session_key(mem_ctx, gse_ctx->gssapi_context, session_key, NULL);
1009 /* Get some basic (and authorization) information about the user on
1010 * this session. This uses either the PAC (if present) or a local
1011 * database lookup */
1012 static NTSTATUS gensec_gse_session_info(struct gensec_security *gensec_security,
1013 TALLOC_CTX *mem_ctx,
1014 struct auth_session_info **_session_info)
1016 struct gse_context *gse_ctx =
1017 talloc_get_type_abort(gensec_security->private_data,
1018 struct gse_context);
1019 NTSTATUS nt_status;
1020 TALLOC_CTX *tmp_ctx;
1021 struct auth_session_info *session_info = NULL;
1022 OM_uint32 maj_stat, min_stat;
1023 DATA_BLOB pac_blob, *pac_blob_ptr = NULL;
1025 gss_buffer_desc name_token;
1026 char *principal_string;
1028 tmp_ctx = talloc_named(mem_ctx, 0, "gensec_gse_session_info context");
1029 NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);
1031 maj_stat = gss_display_name(&min_stat,
1032 gse_ctx->client_name,
1033 &name_token,
1034 NULL);
1035 if (GSS_ERROR(maj_stat)) {
1036 DEBUG(1, ("GSS display_name failed: %s\n",
1037 gse_errstr(talloc_tos(), maj_stat, min_stat)));
1038 talloc_free(tmp_ctx);
1039 return NT_STATUS_FOOBAR;
1042 principal_string = talloc_strndup(tmp_ctx,
1043 (const char *)name_token.value,
1044 name_token.length);
1046 gss_release_buffer(&min_stat, &name_token);
1048 if (!principal_string) {
1049 talloc_free(tmp_ctx);
1050 return NT_STATUS_NO_MEMORY;
1053 nt_status = gssapi_obtain_pac_blob(tmp_ctx, gse_ctx->gssapi_context,
1054 gse_ctx->client_name,
1055 &pac_blob);
1057 /* IF we have the PAC - otherwise we need to get this
1058 * data from elsewere
1060 if (NT_STATUS_IS_OK(nt_status)) {
1061 pac_blob_ptr = &pac_blob;
1063 nt_status = gensec_generate_session_info_pac(tmp_ctx,
1064 gensec_security,
1065 NULL,
1066 pac_blob_ptr, principal_string,
1067 gensec_get_remote_address(gensec_security),
1068 &session_info);
1069 if (!NT_STATUS_IS_OK(nt_status)) {
1070 talloc_free(tmp_ctx);
1071 return nt_status;
1074 nt_status = gensec_gse_session_key(gensec_security, session_info,
1075 &session_info->session_key);
1076 if (!NT_STATUS_IS_OK(nt_status)) {
1077 talloc_free(tmp_ctx);
1078 return nt_status;
1081 *_session_info = talloc_move(mem_ctx, &session_info);
1082 talloc_free(tmp_ctx);
1084 return NT_STATUS_OK;
1087 static size_t gensec_gse_max_input_size(struct gensec_security *gensec_security)
1089 struct gse_context *gse_ctx =
1090 talloc_get_type_abort(gensec_security->private_data,
1091 struct gse_context);
1092 OM_uint32 maj_stat, min_stat;
1093 OM_uint32 max_input_size;
1095 maj_stat = gss_wrap_size_limit(&min_stat,
1096 gse_ctx->gssapi_context,
1097 gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL),
1098 GSS_C_QOP_DEFAULT,
1099 gse_ctx->max_wrap_buf_size,
1100 &max_input_size);
1101 if (GSS_ERROR(maj_stat)) {
1102 TALLOC_CTX *mem_ctx = talloc_new(NULL);
1103 DEBUG(1, ("gensec_gssapi_max_input_size: determining signature size with gss_wrap_size_limit failed: %s\n",
1104 gse_errstr(mem_ctx, maj_stat, min_stat)));
1105 talloc_free(mem_ctx);
1106 return 0;
1109 return max_input_size;
1112 /* Find out the maximum output size negotiated on this connection */
1113 static size_t gensec_gse_max_wrapped_size(struct gensec_security *gensec_security)
1115 struct gse_context *gse_ctx =
1116 talloc_get_type_abort(gensec_security->private_data,
1117 struct gse_context);
1118 return gse_ctx->max_wrap_buf_size;
1121 static size_t gensec_gse_sig_size(struct gensec_security *gensec_security,
1122 size_t data_size)
1124 struct gse_context *gse_ctx =
1125 talloc_get_type_abort(gensec_security->private_data,
1126 struct gse_context);
1128 if (gse_ctx->sig_size > 0) {
1129 return gse_ctx->sig_size;
1132 gse_ctx->sig_size = gssapi_get_sig_size(gse_ctx->gssapi_context,
1133 &gse_ctx->gss_mech,
1134 gse_ctx->gss_got_flags,
1135 data_size);
1136 return gse_ctx->sig_size;
1139 static const char *gensec_gse_krb5_oids[] = {
1140 GENSEC_OID_KERBEROS5_OLD,
1141 GENSEC_OID_KERBEROS5,
1142 NULL
1145 const struct gensec_security_ops gensec_gse_krb5_security_ops = {
1146 .name = "gse_krb5",
1147 .auth_type = DCERPC_AUTH_TYPE_KRB5,
1148 .oid = gensec_gse_krb5_oids,
1149 .client_start = gensec_gse_client_start,
1150 .server_start = gensec_gse_server_start,
1151 .magic = gensec_magic_check_krb5_oid,
1152 .update = gensec_gse_update,
1153 .session_key = gensec_gse_session_key,
1154 .session_info = gensec_gse_session_info,
1155 .sig_size = gensec_gse_sig_size,
1156 .sign_packet = gensec_gse_sign_packet,
1157 .check_packet = gensec_gse_check_packet,
1158 .seal_packet = gensec_gse_seal_packet,
1159 .unseal_packet = gensec_gse_unseal_packet,
1160 .max_input_size = gensec_gse_max_input_size,
1161 .max_wrapped_size = gensec_gse_max_wrapped_size,
1162 .wrap = gensec_gse_wrap,
1163 .unwrap = gensec_gse_unwrap,
1164 .have_feature = gensec_gse_have_feature,
1165 .expire_time = gensec_gse_expire_time,
1166 .enabled = true,
1167 .kerberos = true,
1168 .priority = GENSEC_GSSAPI
1171 #endif /* HAVE_KRB5 */