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 */
26 #include "libads/kerberos_proto.h"
27 #include "auth/common_auth.h"
28 #include "auth/gensec/gensec.h"
29 #include "auth/credentials/credentials.h"
30 #include "../librpc/gen_ndr/dcerpc.h"
32 #if defined(HAVE_KRB5) && defined(HAVE_GSS_WRAP_IOV)
37 #ifndef GSS_C_DCE_STYLE
38 #define GSS_C_DCE_STYLE 0x1000
41 #ifndef GSS_KRB5_INQ_SSPI_SESSION_KEY_OID
42 #define GSS_KRB5_INQ_SSPI_SESSION_KEY_OID_LENGTH 11
43 #define GSS_KRB5_INQ_SSPI_SESSION_KEY_OID "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x05"
46 gss_OID_desc gse_sesskey_inq_oid = {
47 GSS_KRB5_INQ_SSPI_SESSION_KEY_OID_LENGTH,
48 (void *)GSS_KRB5_INQ_SSPI_SESSION_KEY_OID
51 #ifndef GSS_KRB5_SESSION_KEY_ENCTYPE_OID
52 #define GSS_KRB5_SESSION_KEY_ENCTYPE_OID_LENGTH 10
53 #define GSS_KRB5_SESSION_KEY_ENCTYPE_OID "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x04"
56 gss_OID_desc gse_sesskeytype_oid = {
57 GSS_KRB5_SESSION_KEY_ENCTYPE_OID_LENGTH,
58 (void *)GSS_KRB5_SESSION_KEY_ENCTYPE_OID
61 #define GSE_EXTRACT_RELEVANT_AUTHZ_DATA_OID_LENGTH 12
62 /* EXTRACTION OID AUTHZ ID */
63 #define GSE_EXTRACT_RELEVANT_AUTHZ_DATA_OID "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x0a" "\x01"
65 gss_OID_desc gse_authz_data_oid = {
66 GSE_EXTRACT_RELEVANT_AUTHZ_DATA_OID_LENGTH,
67 (void *)GSE_EXTRACT_RELEVANT_AUTHZ_DATA_OID
70 static char *gse_errstr(TALLOC_CTX *mem_ctx, OM_uint32 maj, OM_uint32 min);
77 gss_ctx_id_t gssapi_context;
79 gss_OID_desc gss_mech;
80 OM_uint32 gss_want_flags;
82 gss_name_t server_name;
85 OM_uint32 gss_got_flags;
86 gss_cred_id_t delegated_cred_handle;
87 gss_name_t client_name;
90 #ifndef HAVE_GSS_OID_EQUAL
92 static bool gss_oid_equal(const gss_OID o1, const gss_OID o2)
97 if ((o1 == NULL && o2 != NULL) || (o1 != NULL && o2 == NULL)) {
100 if (o1->length != o2->length) {
103 return memcmp(o1->elements, o2->elements, o1->length) == false;
108 /* free non talloc dependent contexts */
109 static int gse_context_destructor(void *ptr)
111 struct gse_context *gse_ctx;
112 OM_uint32 gss_min, gss_maj;
114 gse_ctx = talloc_get_type_abort(ptr, struct gse_context);
115 if (gse_ctx->k5ctx) {
116 if (gse_ctx->ccache) {
117 krb5_cc_close(gse_ctx->k5ctx, gse_ctx->ccache);
118 gse_ctx->ccache = NULL;
120 if (gse_ctx->keytab) {
121 krb5_kt_close(gse_ctx->k5ctx, gse_ctx->keytab);
122 gse_ctx->keytab = NULL;
124 krb5_free_context(gse_ctx->k5ctx);
125 gse_ctx->k5ctx = NULL;
127 if (gse_ctx->gssapi_context != GSS_C_NO_CONTEXT) {
128 gss_maj = gss_delete_sec_context(&gss_min,
129 &gse_ctx->gssapi_context,
132 if (gse_ctx->server_name) {
133 gss_maj = gss_release_name(&gss_min,
134 &gse_ctx->server_name);
136 if (gse_ctx->client_name) {
137 gss_maj = gss_release_name(&gss_min,
138 &gse_ctx->client_name);
140 if (gse_ctx->creds) {
141 gss_maj = gss_release_cred(&gss_min,
144 if (gse_ctx->delegated_cred_handle) {
145 gss_maj = gss_release_cred(&gss_min,
146 &gse_ctx->delegated_cred_handle);
149 /* MIT and Heimdal differ as to if you can call
150 * gss_release_oid() on this OID, generated by
151 * gss_{accept,init}_sec_context(). However, as long as the
152 * oid is gss_mech_krb5 (which it always is at the moment),
153 * then this is a moot point, as both declare this particular
154 * OID static, and so no memory is lost. This assert is in
155 * place to ensure that the programmer who wishes to extend
156 * this code to EAP or other GSS mechanisms determines an
157 * implementation-dependent way of releasing any dynamically
159 SMB_ASSERT(gss_oid_equal(&gse_ctx->gss_mech, GSS_C_NO_OID) || gss_oid_equal(&gse_ctx->gss_mech, gss_mech_krb5));
164 static NTSTATUS gse_context_init(TALLOC_CTX *mem_ctx,
165 bool do_sign, bool do_seal,
166 const char *ccache_name,
167 uint32_t add_gss_c_flags,
168 struct gse_context **_gse_ctx)
170 struct gse_context *gse_ctx;
171 krb5_error_code k5ret;
174 gse_ctx = talloc_zero(mem_ctx, struct gse_context);
176 return NT_STATUS_NO_MEMORY;
178 talloc_set_destructor((TALLOC_CTX *)gse_ctx, gse_context_destructor);
180 memcpy(&gse_ctx->gss_mech, gss_mech_krb5, sizeof(gss_OID_desc));
182 gse_ctx->gss_want_flags = GSS_C_MUTUAL_FLAG |
184 GSS_C_DELEG_POLICY_FLAG |
188 gse_ctx->gss_want_flags |= GSS_C_INTEG_FLAG;
191 gse_ctx->gss_want_flags |= GSS_C_CONF_FLAG;
194 gse_ctx->gss_want_flags |= add_gss_c_flags;
196 /* Initialize Kerberos Context */
197 initialize_krb5_error_table();
199 k5ret = krb5_init_context(&gse_ctx->k5ctx);
201 DEBUG(0, ("Failed to initialize kerberos context! (%s)\n",
202 error_message(k5ret)));
203 status = NT_STATUS_INTERNAL_ERROR;
208 ccache_name = krb5_cc_default_name(gse_ctx->k5ctx);
210 k5ret = krb5_cc_resolve(gse_ctx->k5ctx, ccache_name,
213 DEBUG(1, ("Failed to resolve credential cache! (%s)\n",
214 error_message(k5ret)));
215 status = NT_STATUS_INTERNAL_ERROR;
219 /* TODO: Should we enforce a enc_types list ?
220 ret = krb5_set_default_tgs_ktypes(gse_ctx->k5ctx, enc_types);
227 TALLOC_FREE(gse_ctx);
231 static NTSTATUS gse_init_client(TALLOC_CTX *mem_ctx,
232 bool do_sign, bool do_seal,
233 const char *ccache_name,
236 const char *username,
237 const char *password,
238 uint32_t add_gss_c_flags,
239 struct gse_context **_gse_ctx)
241 struct gse_context *gse_ctx;
242 OM_uint32 gss_maj, gss_min;
243 gss_buffer_desc name_buffer = {0, NULL};
244 gss_OID_set_desc mech_set;
247 if (!server || !service) {
248 return NT_STATUS_INVALID_PARAMETER;
251 status = gse_context_init(mem_ctx, do_sign, do_seal,
252 ccache_name, add_gss_c_flags,
254 if (!NT_STATUS_IS_OK(status)) {
255 return NT_STATUS_NO_MEMORY;
258 /* Guess the realm based on the supplied service, and avoid the GSS libs
259 doing DNS lookups which may fail.
261 TODO: Loop with the KDC on some more combinations (local
262 realm in particular), possibly falling back to
263 GSS_C_NT_HOSTBASED_SERVICE
265 name_buffer.value = kerberos_get_principal_from_service_hostname(gse_ctx,
267 if (!name_buffer.value) {
268 status = NT_STATUS_NO_MEMORY;
271 name_buffer.length = strlen((char *)name_buffer.value);
272 gss_maj = gss_import_name(&gss_min, &name_buffer,
274 &gse_ctx->server_name);
276 DEBUG(0, ("gss_import_name failed for %s, with [%s]\n",
277 (char *)name_buffer.value,
278 gse_errstr(gse_ctx, gss_maj, gss_min)));
279 status = NT_STATUS_INTERNAL_ERROR;
283 /* TODO: get krb5 ticket using username/password, if no valid
284 * one already available in ccache */
287 mech_set.elements = &gse_ctx->gss_mech;
289 gss_maj = gss_acquire_cred(&gss_min,
297 DEBUG(0, ("gss_acquire_creds failed for %s, with [%s]\n",
298 (char *)name_buffer.value,
299 gse_errstr(gse_ctx, gss_maj, gss_min)));
300 status = NT_STATUS_INTERNAL_ERROR;
305 TALLOC_FREE(name_buffer.value);
309 TALLOC_FREE(name_buffer.value);
310 TALLOC_FREE(gse_ctx);
314 static NTSTATUS gse_get_client_auth_token(TALLOC_CTX *mem_ctx,
315 struct gse_context *gse_ctx,
316 const DATA_BLOB *token_in,
317 DATA_BLOB *token_out)
319 OM_uint32 gss_maj, gss_min;
320 gss_buffer_desc in_data;
321 gss_buffer_desc out_data;
322 DATA_BLOB blob = data_blob_null;
325 in_data.value = token_in->data;
326 in_data.length = token_in->length;
328 gss_maj = gss_init_sec_context(&gss_min,
330 &gse_ctx->gssapi_context,
331 gse_ctx->server_name,
333 gse_ctx->gss_want_flags,
334 0, GSS_C_NO_CHANNEL_BINDINGS,
335 &in_data, NULL, &out_data,
336 &gse_ctx->gss_got_flags, NULL);
339 /* we are done with it */
340 status = NT_STATUS_OK;
342 case GSS_S_CONTINUE_NEEDED:
343 /* we will need a third leg */
344 status = NT_STATUS_MORE_PROCESSING_REQUIRED;
347 DEBUG(0, ("gss_init_sec_context failed with [%s]\n",
348 gse_errstr(talloc_tos(), gss_maj, gss_min)));
349 status = NT_STATUS_INTERNAL_ERROR;
353 blob = data_blob_talloc(mem_ctx, out_data.value, out_data.length);
355 status = NT_STATUS_NO_MEMORY;
358 gss_maj = gss_release_buffer(&gss_min, &out_data);
365 static NTSTATUS gse_init_server(TALLOC_CTX *mem_ctx,
366 bool do_sign, bool do_seal,
367 uint32_t add_gss_c_flags,
368 struct gse_context **_gse_ctx)
370 struct gse_context *gse_ctx;
371 OM_uint32 gss_maj, gss_min;
375 status = gse_context_init(mem_ctx, do_sign, do_seal,
376 NULL, add_gss_c_flags, &gse_ctx);
377 if (!NT_STATUS_IS_OK(status)) {
378 return NT_STATUS_NO_MEMORY;
381 ret = gse_krb5_get_server_keytab(gse_ctx->k5ctx,
384 status = NT_STATUS_INTERNAL_ERROR;
388 #ifdef HAVE_GSS_KRB5_IMPORT_CRED
390 /* This creates a GSSAPI cred_id_t with the keytab set */
391 gss_maj = gss_krb5_import_cred(&gss_min, NULL, NULL, gse_ctx->keytab,
395 && gss_maj != (GSS_S_CALL_BAD_STRUCTURE|GSS_S_BAD_NAME)) {
396 DEBUG(0, ("gss_krb5_import_cred failed with [%s]\n",
397 gse_errstr(gse_ctx, gss_maj, gss_min)));
398 status = NT_STATUS_INTERNAL_ERROR;
401 /* This is the error the MIT krb5 1.9 gives when it
402 * implements the function, but we do not specify the
403 * principal. However, when we specify the principal
404 * as host$@REALM the GSS acceptor fails with 'wrong
405 * principal in request'. Work around the issue by
406 * falling back to the alternate approach below. */
407 } else if (gss_maj == (GSS_S_CALL_BAD_STRUCTURE|GSS_S_BAD_NAME))
410 * This call sets the default keytab for the whole server, not
411 * just for this context. Need to find a way that does not alter
412 * the state of the whole server ... */
415 gss_OID_set_desc mech_set;
417 ret = smb_krb5_keytab_name(gse_ctx, gse_ctx->k5ctx,
418 gse_ctx->keytab, &ktname);
420 status = NT_STATUS_INTERNAL_ERROR;
424 ret = gsskrb5_register_acceptor_identity(ktname);
426 status = NT_STATUS_INTERNAL_ERROR;
431 mech_set.elements = &gse_ctx->gss_mech;
433 gss_maj = gss_acquire_cred(&gss_min,
442 DEBUG(0, ("gss_acquire_creds failed with [%s]\n",
443 gse_errstr(gse_ctx, gss_maj, gss_min)));
444 status = NT_STATUS_INTERNAL_ERROR;
449 status = NT_STATUS_OK;
452 if (!NT_STATUS_IS_OK(status)) {
453 TALLOC_FREE(gse_ctx);
460 static NTSTATUS gse_get_server_auth_token(TALLOC_CTX *mem_ctx,
461 struct gse_context *gse_ctx,
462 const DATA_BLOB *token_in,
463 DATA_BLOB *token_out)
465 OM_uint32 gss_maj, gss_min;
466 gss_buffer_desc in_data;
467 gss_buffer_desc out_data;
468 DATA_BLOB blob = data_blob_null;
471 in_data.value = token_in->data;
472 in_data.length = token_in->length;
474 gss_maj = gss_accept_sec_context(&gss_min,
475 &gse_ctx->gssapi_context,
478 GSS_C_NO_CHANNEL_BINDINGS,
479 &gse_ctx->client_name,
482 &gse_ctx->gss_got_flags, NULL,
483 &gse_ctx->delegated_cred_handle);
486 /* we are done with it */
487 status = NT_STATUS_OK;
489 case GSS_S_CONTINUE_NEEDED:
490 /* we will need a third leg */
491 status = NT_STATUS_MORE_PROCESSING_REQUIRED;
494 DEBUG(0, ("gss_init_sec_context failed with [%s]\n",
495 gse_errstr(talloc_tos(), gss_maj, gss_min)));
497 if (gse_ctx->gssapi_context) {
498 gss_delete_sec_context(&gss_min,
499 &gse_ctx->gssapi_context,
503 status = NT_STATUS_INTERNAL_ERROR;
507 /* we may be told to return nothing */
508 if (out_data.length) {
509 blob = data_blob_talloc(mem_ctx, out_data.value, out_data.length);
511 status = NT_STATUS_NO_MEMORY;
513 gss_maj = gss_release_buffer(&gss_min, &out_data);
522 static NTSTATUS gse_verify_server_auth_flags(struct gse_context *gse_ctx)
524 if (memcmp(gse_ctx->ret_mech,
525 gss_mech_krb5, sizeof(gss_OID_desc)) != 0) {
526 return NT_STATUS_ACCESS_DENIED;
529 /* GSS_C_MUTUAL_FLAG */
530 if (gse_ctx->gss_want_flags & GSS_C_MUTUAL_FLAG) {
531 if (!(gse_ctx->gss_got_flags & GSS_C_MUTUAL_FLAG)) {
532 return NT_STATUS_ACCESS_DENIED;
536 /* GSS_C_DELEG_FLAG */
537 /* GSS_C_DELEG_POLICY_FLAG */
538 /* GSS_C_REPLAY_FLAG */
539 /* GSS_C_SEQUENCE_FLAG */
541 /* GSS_C_INTEG_FLAG */
542 if (gse_ctx->gss_want_flags & GSS_C_INTEG_FLAG) {
543 if (!(gse_ctx->gss_got_flags & GSS_C_INTEG_FLAG)) {
544 return NT_STATUS_ACCESS_DENIED;
548 /* GSS_C_CONF_FLAG */
549 if (gse_ctx->gss_want_flags & GSS_C_CONF_FLAG) {
550 if (!(gse_ctx->gss_got_flags & GSS_C_CONF_FLAG)) {
551 return NT_STATUS_ACCESS_DENIED;
558 static char *gse_errstr(TALLOC_CTX *mem_ctx, OM_uint32 maj, OM_uint32 min)
560 OM_uint32 gss_min, gss_maj;
561 gss_buffer_desc msg_min;
562 gss_buffer_desc msg_maj;
563 OM_uint32 msg_ctx = 0;
567 ZERO_STRUCT(msg_min);
568 ZERO_STRUCT(msg_maj);
570 gss_maj = gss_display_status(&gss_min, maj, GSS_C_GSS_CODE,
571 GSS_C_NO_OID, &msg_ctx, &msg_maj);
575 errstr = talloc_strndup(mem_ctx,
576 (char *)msg_maj.value,
581 gss_maj = gss_display_status(&gss_min, min, GSS_C_MECH_CODE,
582 (gss_OID)discard_const(gss_mech_krb5),
588 errstr = talloc_strdup_append_buffer(errstr, ": ");
592 errstr = talloc_strndup_append_buffer(errstr,
593 (char *)msg_min.value,
601 gss_maj = gss_release_buffer(&gss_min, &msg_min);
604 gss_maj = gss_release_buffer(&gss_min, &msg_maj);
609 static DATA_BLOB gse_get_session_key(TALLOC_CTX *mem_ctx,
610 struct gse_context *gse_ctx)
612 OM_uint32 gss_min, gss_maj;
613 gss_buffer_set_t set = GSS_C_NO_BUFFER_SET;
616 gss_maj = gss_inquire_sec_context_by_oid(
617 &gss_min, gse_ctx->gssapi_context,
618 &gse_sesskey_inq_oid, &set);
620 DEBUG(0, ("gss_inquire_sec_context_by_oid failed [%s]\n",
621 gse_errstr(talloc_tos(), gss_maj, gss_min)));
622 return data_blob_null;
625 if ((set == GSS_C_NO_BUFFER_SET) ||
627 (memcmp(set->elements[1].value,
628 gse_sesskeytype_oid.elements,
629 gse_sesskeytype_oid.length) != 0)) {
630 #ifdef HAVE_GSSKRB5_GET_SUBKEY
631 krb5_keyblock *subkey;
632 gss_maj = gsskrb5_get_subkey(&gss_min,
633 gse_ctx->gssapi_context,
636 DEBUG(1, ("NO session key for this mech\n"));
637 return data_blob_null;
639 ret = data_blob_talloc(mem_ctx,
640 KRB5_KEY_DATA(subkey), KRB5_KEY_LENGTH(subkey));
641 krb5_free_keyblock(NULL /* should be krb5_context */, subkey);
644 DEBUG(0, ("gss_inquire_sec_context_by_oid returned unknown "
645 "OID for data in results:\n"));
646 dump_data(1, (uint8_t *)set->elements[1].value,
647 set->elements[1].length);
648 return data_blob_null;
652 ret = data_blob_talloc(mem_ctx, set->elements[0].value,
653 set->elements[0].length);
655 gss_maj = gss_release_buffer_set(&gss_min, &set);
659 static size_t gse_get_signature_length(struct gse_context *gse_ctx,
660 bool seal, size_t payload_size)
662 OM_uint32 gss_min, gss_maj;
663 gss_iov_buffer_desc iov[2];
667 * gss_wrap_iov_length() only needs the type and length
669 iov[0].type = GSS_IOV_BUFFER_TYPE_HEADER;
670 iov[0].buffer.value = NULL;
671 iov[0].buffer.length = 0;
672 iov[1].type = GSS_IOV_BUFFER_TYPE_DATA;
673 iov[1].buffer.value = NULL;
674 iov[1].buffer.length = payload_size;
676 gss_maj = gss_wrap_iov_length(&gss_min, gse_ctx->gssapi_context,
677 seal, GSS_C_QOP_DEFAULT,
680 DEBUG(0, ("gss_wrap_iov_length failed with [%s]\n",
681 gse_errstr(talloc_tos(), gss_maj, gss_min)));
685 return iov[0].buffer.length;
688 static NTSTATUS gse_seal(TALLOC_CTX *mem_ctx, struct gse_context *gse_ctx,
689 DATA_BLOB *data, DATA_BLOB *signature)
691 OM_uint32 gss_min, gss_maj;
692 gss_iov_buffer_desc iov[2];
693 int req_seal = 1; /* setting to 1 means we request sign+seal */
697 /* allocate the memory ourselves so we do not need to talloc_memdup */
698 signature->length = gse_get_signature_length(gse_ctx, true, data->length);
699 if (!signature->length) {
700 return NT_STATUS_INTERNAL_ERROR;
702 signature->data = (uint8_t *)talloc_size(mem_ctx, signature->length);
703 if (!signature->data) {
704 return NT_STATUS_NO_MEMORY;
706 iov[0].type = GSS_IOV_BUFFER_TYPE_HEADER;
707 iov[0].buffer.value = signature->data;
708 iov[0].buffer.length = signature->length;
710 /* data is encrypted in place, which is ok */
711 iov[1].type = GSS_IOV_BUFFER_TYPE_DATA;
712 iov[1].buffer.value = data->data;
713 iov[1].buffer.length = data->length;
715 gss_maj = gss_wrap_iov(&gss_min, gse_ctx->gssapi_context,
716 req_seal, GSS_C_QOP_DEFAULT,
719 DEBUG(0, ("gss_wrap_iov failed with [%s]\n",
720 gse_errstr(talloc_tos(), gss_maj, gss_min)));
721 status = NT_STATUS_ACCESS_DENIED;
726 DEBUG(0, ("gss_wrap_iov says data was not sealed!\n"));
727 status = NT_STATUS_ACCESS_DENIED;
731 status = NT_STATUS_OK;
733 DEBUG(10, ("Sealed %d bytes, and got %d bytes header/signature.\n",
734 (int)iov[1].buffer.length, (int)iov[0].buffer.length));
740 static NTSTATUS gse_unseal(TALLOC_CTX *mem_ctx, struct gse_context *gse_ctx,
741 DATA_BLOB *data, const DATA_BLOB *signature)
743 OM_uint32 gss_min, gss_maj;
744 gss_iov_buffer_desc iov[2];
748 iov[0].type = GSS_IOV_BUFFER_TYPE_HEADER;
749 iov[0].buffer.value = signature->data;
750 iov[0].buffer.length = signature->length;
752 /* data is decrypted in place, which is ok */
753 iov[1].type = GSS_IOV_BUFFER_TYPE_DATA;
754 iov[1].buffer.value = data->data;
755 iov[1].buffer.length = data->length;
757 gss_maj = gss_unwrap_iov(&gss_min, gse_ctx->gssapi_context,
758 &sealed, NULL, iov, 2);
760 DEBUG(0, ("gss_unwrap_iov failed with [%s]\n",
761 gse_errstr(talloc_tos(), gss_maj, gss_min)));
762 status = NT_STATUS_ACCESS_DENIED;
767 DEBUG(0, ("gss_unwrap_iov says data is not sealed!\n"));
768 status = NT_STATUS_ACCESS_DENIED;
772 status = NT_STATUS_OK;
774 DEBUG(10, ("Unsealed %d bytes, with %d bytes header/signature.\n",
775 (int)iov[1].buffer.length, (int)iov[0].buffer.length));
781 static NTSTATUS gse_sign(TALLOC_CTX *mem_ctx, struct gse_context *gse_ctx,
782 DATA_BLOB *data, DATA_BLOB *signature)
784 OM_uint32 gss_min, gss_maj;
785 gss_buffer_desc in_data = { 0, NULL };
786 gss_buffer_desc out_data = { 0, NULL};
789 in_data.value = data->data;
790 in_data.length = data->length;
792 gss_maj = gss_get_mic(&gss_min, gse_ctx->gssapi_context,
794 &in_data, &out_data);
796 DEBUG(0, ("gss_get_mic failed with [%s]\n",
797 gse_errstr(talloc_tos(), gss_maj, gss_min)));
798 status = NT_STATUS_ACCESS_DENIED;
802 *signature = data_blob_talloc(mem_ctx,
803 out_data.value, out_data.length);
804 if (!signature->data) {
805 status = NT_STATUS_NO_MEMORY;
809 status = NT_STATUS_OK;
812 if (out_data.value) {
813 gss_maj = gss_release_buffer(&gss_min, &out_data);
818 static NTSTATUS gse_sigcheck(TALLOC_CTX *mem_ctx, struct gse_context *gse_ctx,
819 const DATA_BLOB *data, const DATA_BLOB *signature)
821 OM_uint32 gss_min, gss_maj;
822 gss_buffer_desc in_data = { 0, NULL };
823 gss_buffer_desc in_token = { 0, NULL};
826 in_data.value = data->data;
827 in_data.length = data->length;
828 in_token.value = signature->data;
829 in_token.length = signature->length;
831 gss_maj = gss_verify_mic(&gss_min, gse_ctx->gssapi_context,
832 &in_data, &in_token, NULL);
834 DEBUG(0, ("gss_verify_mic failed with [%s]\n",
835 gse_errstr(talloc_tos(), gss_maj, gss_min)));
836 status = NT_STATUS_ACCESS_DENIED;
840 status = NT_STATUS_OK;
846 static NTSTATUS gensec_gse_client_start(struct gensec_security *gensec_security)
848 struct gse_context *gse_ctx;
849 struct cli_credentials *creds = gensec_get_credentials(gensec_security);
851 OM_uint32 want_flags = 0;
852 bool do_sign = false, do_seal = false;
853 const char *hostname = gensec_get_target_hostname(gensec_security);
854 const char *service = gensec_get_target_service(gensec_security);
855 const char *username = cli_credentials_get_username(creds);
856 const char *password = cli_credentials_get_password(creds);
859 DEBUG(1, ("Could not determine hostname for target computer, cannot use kerberos\n"));
860 return NT_STATUS_INVALID_PARAMETER;
862 if (is_ipaddress(hostname)) {
863 DEBUG(2, ("Cannot do GSE to an IP address\n"));
864 return NT_STATUS_INVALID_PARAMETER;
866 if (strcmp(hostname, "localhost") == 0) {
867 DEBUG(2, ("GSE to 'localhost' does not make sense\n"));
868 return NT_STATUS_INVALID_PARAMETER;
871 if (gensec_security->want_features & GENSEC_FEATURE_SIGN) {
874 if (gensec_security->want_features & GENSEC_FEATURE_SEAL) {
877 if (gensec_security->want_features & GENSEC_FEATURE_DCE_STYLE) {
878 want_flags |= GSS_C_DCE_STYLE;
881 nt_status = gse_init_client(gensec_security, do_sign, do_seal, NULL,
883 username, password, want_flags,
885 if (!NT_STATUS_IS_OK(nt_status)) {
888 gensec_security->private_data = gse_ctx;
892 static NTSTATUS gensec_gse_server_start(struct gensec_security *gensec_security)
894 struct gse_context *gse_ctx;
896 OM_uint32 want_flags = 0;
897 bool do_sign = false, do_seal = false;
899 if (gensec_security->want_features & GENSEC_FEATURE_SIGN) {
902 if (gensec_security->want_features & GENSEC_FEATURE_SEAL) {
905 if (gensec_security->want_features & GENSEC_FEATURE_DCE_STYLE) {
906 want_flags |= GSS_C_DCE_STYLE;
909 nt_status = gse_init_server(gensec_security, do_sign, do_seal, want_flags,
911 if (!NT_STATUS_IS_OK(nt_status)) {
914 gensec_security->private_data = gse_ctx;
919 * Check if the packet is one for this mechansim
921 * @param gensec_security GENSEC state
922 * @param in The request, as a DATA_BLOB
923 * @return Error, INVALID_PARAMETER if it's not a packet for us
924 * or NT_STATUS_OK if the packet is ok.
927 static NTSTATUS gensec_gse_magic(struct gensec_security *gensec_security,
930 if (gensec_gssapi_check_oid(in, GENSEC_OID_KERBEROS5)) {
933 return NT_STATUS_INVALID_PARAMETER;
939 * Next state function for the GSE GENSEC mechanism
941 * @param gensec_gse_state GSE State
942 * @param mem_ctx The TALLOC_CTX for *out to be allocated on
943 * @param in The request, as a DATA_BLOB
944 * @param out The reply, as an talloc()ed DATA_BLOB, on *mem_ctx
945 * @return Error, MORE_PROCESSING_REQUIRED if a reply is sent,
946 * or NT_STATUS_OK if the user is authenticated.
949 static NTSTATUS gensec_gse_update(struct gensec_security *gensec_security,
951 struct tevent_context *ev,
952 const DATA_BLOB in, DATA_BLOB *out)
955 struct gse_context *gse_ctx =
956 talloc_get_type_abort(gensec_security->private_data,
959 switch (gensec_security->gensec_role) {
961 status = gse_get_client_auth_token(mem_ctx, gse_ctx,
965 status = gse_get_server_auth_token(mem_ctx, gse_ctx,
969 if (!NT_STATUS_IS_OK(status)) {
973 if (gensec_security->gensec_role == GENSEC_SERVER) {
974 return gse_verify_server_auth_flags(gse_ctx);
980 static NTSTATUS gensec_gse_wrap(struct gensec_security *gensec_security,
985 struct gse_context *gse_ctx =
986 talloc_get_type_abort(gensec_security->private_data,
988 OM_uint32 maj_stat, min_stat;
989 gss_buffer_desc input_token, output_token;
991 input_token.length = in->length;
992 input_token.value = in->data;
994 maj_stat = gss_wrap(&min_stat,
995 gse_ctx->gssapi_context,
996 gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL),
1001 if (GSS_ERROR(maj_stat)) {
1002 DEBUG(0, ("gensec_gse_wrap: GSS Wrap failed: %s\n",
1003 gse_errstr(talloc_tos(), maj_stat, min_stat)));
1004 return NT_STATUS_ACCESS_DENIED;
1007 *out = data_blob_talloc(mem_ctx, output_token.value, output_token.length);
1008 gss_release_buffer(&min_stat, &output_token);
1010 if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)
1012 return NT_STATUS_ACCESS_DENIED;
1014 return NT_STATUS_OK;
1017 static NTSTATUS gensec_gse_unwrap(struct gensec_security *gensec_security,
1018 TALLOC_CTX *mem_ctx,
1019 const DATA_BLOB *in,
1022 struct gse_context *gse_ctx =
1023 talloc_get_type_abort(gensec_security->private_data,
1024 struct gse_context);
1025 OM_uint32 maj_stat, min_stat;
1026 gss_buffer_desc input_token, output_token;
1028 gss_qop_t qop_state;
1029 input_token.length = in->length;
1030 input_token.value = in->data;
1032 maj_stat = gss_unwrap(&min_stat,
1033 gse_ctx->gssapi_context,
1038 if (GSS_ERROR(maj_stat)) {
1039 DEBUG(0, ("gensec_gse_unwrap: GSS UnWrap failed: %s\n",
1040 gse_errstr(talloc_tos(), maj_stat, min_stat)));
1041 return NT_STATUS_ACCESS_DENIED;
1044 *out = data_blob_talloc(mem_ctx, output_token.value, output_token.length);
1045 gss_release_buffer(&min_stat, &output_token);
1047 if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)
1049 return NT_STATUS_ACCESS_DENIED;
1051 return NT_STATUS_OK;
1054 static NTSTATUS gensec_gse_seal_packet(struct gensec_security *gensec_security,
1055 TALLOC_CTX *mem_ctx,
1056 uint8_t *data, size_t length,
1057 const uint8_t *whole_pdu, size_t pdu_length,
1060 struct gse_context *gse_ctx =
1061 talloc_get_type_abort(gensec_security->private_data,
1062 struct gse_context);
1063 DATA_BLOB payload = data_blob_const(data, length);
1064 return gse_seal(mem_ctx, gse_ctx, &payload, sig);
1067 static NTSTATUS gensec_gse_unseal_packet(struct gensec_security *gensec_security,
1068 uint8_t *data, size_t length,
1069 const uint8_t *whole_pdu, size_t pdu_length,
1070 const DATA_BLOB *sig)
1072 struct gse_context *gse_ctx =
1073 talloc_get_type_abort(gensec_security->private_data,
1074 struct gse_context);
1075 DATA_BLOB payload = data_blob_const(data, length);
1076 return gse_unseal(talloc_tos() /* unused */, gse_ctx, &payload, sig);
1079 static NTSTATUS gensec_gse_sign_packet(struct gensec_security *gensec_security,
1080 TALLOC_CTX *mem_ctx,
1081 const uint8_t *data, size_t length,
1082 const uint8_t *whole_pdu, size_t pdu_length,
1085 struct gse_context *gse_ctx =
1086 talloc_get_type_abort(gensec_security->private_data,
1087 struct gse_context);
1088 DATA_BLOB payload = data_blob_const(data, length);
1089 return gse_sign(mem_ctx, gse_ctx, &payload, sig);
1092 static NTSTATUS gensec_gse_check_packet(struct gensec_security *gensec_security,
1093 const uint8_t *data, size_t length,
1094 const uint8_t *whole_pdu, size_t pdu_length,
1095 const DATA_BLOB *sig)
1097 struct gse_context *gse_ctx =
1098 talloc_get_type_abort(gensec_security->private_data,
1099 struct gse_context);
1100 DATA_BLOB payload = data_blob_const(data, length);
1101 return gse_sigcheck(NULL, gse_ctx, &payload, sig);
1104 /* Try to figure out what features we actually got on the connection */
1105 static bool gensec_gse_have_feature(struct gensec_security *gensec_security,
1108 struct gse_context *gse_ctx =
1109 talloc_get_type_abort(gensec_security->private_data,
1110 struct gse_context);
1112 if (feature & GENSEC_FEATURE_SIGN) {
1113 return gse_ctx->gss_got_flags & GSS_C_INTEG_FLAG;
1115 if (feature & GENSEC_FEATURE_SEAL) {
1116 return gse_ctx->gss_got_flags & GSS_C_CONF_FLAG;
1118 if (feature & GENSEC_FEATURE_SESSION_KEY) {
1119 /* Only for GSE/Krb5 */
1120 if (gss_oid_equal(gse_ctx->ret_mech, gss_mech_krb5)) {
1124 if (feature & GENSEC_FEATURE_DCE_STYLE) {
1125 return gse_ctx->gss_got_flags & GSS_C_DCE_STYLE;
1127 /* We can always do async (rather than strict request/reply) packets. */
1128 if (feature & GENSEC_FEATURE_ASYNC_REPLIES) {
1135 * Extract the 'sesssion key' needed by SMB signing and ncacn_np
1136 * (for encrypting some passwords).
1138 * This breaks all the abstractions, but what do you expect...
1140 static NTSTATUS gensec_gse_session_key(struct gensec_security *gensec_security,
1141 TALLOC_CTX *mem_ctx,
1142 DATA_BLOB *session_key_out)
1144 struct gse_context *gse_ctx =
1145 talloc_get_type_abort(gensec_security->private_data,
1146 struct gse_context);
1148 DATA_BLOB session_key = gse_get_session_key(mem_ctx, gse_ctx);
1149 if (session_key.data == NULL) {
1150 return NT_STATUS_NO_USER_SESSION_KEY;
1153 *session_key_out = session_key;
1155 return NT_STATUS_OK;
1158 /* Get some basic (and authorization) information about the user on
1159 * this session. This uses either the PAC (if present) or a local
1160 * database lookup */
1161 static NTSTATUS gensec_gse_session_info(struct gensec_security *gensec_security,
1162 TALLOC_CTX *mem_ctx,
1163 struct auth_session_info **_session_info)
1165 struct gse_context *gse_ctx =
1166 talloc_get_type_abort(gensec_security->private_data,
1167 struct gse_context);
1169 TALLOC_CTX *tmp_ctx;
1170 struct auth_session_info *session_info = NULL;
1171 OM_uint32 maj_stat, min_stat;
1172 DATA_BLOB pac_blob, *pac_blob_ptr = NULL;
1174 gss_buffer_desc name_token;
1175 char *principal_string;
1177 tmp_ctx = talloc_named(mem_ctx, 0, "gensec_gse_session_info context");
1178 NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);
1180 maj_stat = gss_display_name(&min_stat,
1181 gse_ctx->client_name,
1184 if (GSS_ERROR(maj_stat)) {
1185 DEBUG(1, ("GSS display_name failed: %s\n",
1186 gse_errstr(talloc_tos(), maj_stat, min_stat)));
1187 talloc_free(tmp_ctx);
1188 return NT_STATUS_FOOBAR;
1191 principal_string = talloc_strndup(tmp_ctx,
1192 (const char *)name_token.value,
1195 gss_release_buffer(&min_stat, &name_token);
1197 if (!principal_string) {
1198 talloc_free(tmp_ctx);
1199 return NT_STATUS_NO_MEMORY;
1202 nt_status = gssapi_obtain_pac_blob(tmp_ctx, gse_ctx->gssapi_context,
1203 gse_ctx->client_name,
1206 /* IF we have the PAC - otherwise we need to get this
1207 * data from elsewere
1209 if (NT_STATUS_IS_OK(nt_status)) {
1210 pac_blob_ptr = &pac_blob;
1212 nt_status = gensec_generate_session_info_pac(tmp_ctx,
1215 pac_blob_ptr, principal_string,
1216 gensec_get_remote_address(gensec_security),
1218 if (!NT_STATUS_IS_OK(nt_status)) {
1219 talloc_free(tmp_ctx);
1223 nt_status = gensec_gse_session_key(gensec_security, session_info,
1224 &session_info->session_key);
1225 if (!NT_STATUS_IS_OK(nt_status)) {
1226 talloc_free(tmp_ctx);
1230 *_session_info = talloc_move(mem_ctx, &session_info);
1231 talloc_free(tmp_ctx);
1233 return NT_STATUS_OK;
1236 static size_t gensec_gse_sig_size(struct gensec_security *gensec_security,
1239 struct gse_context *gse_ctx =
1240 talloc_get_type_abort(gensec_security->private_data,
1241 struct gse_context);
1243 return gse_get_signature_length(gse_ctx,
1244 gensec_security->want_features & GENSEC_FEATURE_SEAL,
1248 static const char *gensec_gse_krb5_oids[] = {
1249 GENSEC_OID_KERBEROS5_OLD,
1250 GENSEC_OID_KERBEROS5,
1254 const struct gensec_security_ops gensec_gse_krb5_security_ops = {
1256 .auth_type = DCERPC_AUTH_TYPE_KRB5,
1257 .oid = gensec_gse_krb5_oids,
1258 .client_start = gensec_gse_client_start,
1259 .server_start = gensec_gse_server_start,
1260 .magic = gensec_gse_magic,
1261 .update = gensec_gse_update,
1262 .session_key = gensec_gse_session_key,
1263 .session_info = gensec_gse_session_info,
1264 .sig_size = gensec_gse_sig_size,
1265 .sign_packet = gensec_gse_sign_packet,
1266 .check_packet = gensec_gse_check_packet,
1267 .seal_packet = gensec_gse_seal_packet,
1268 .unseal_packet = gensec_gse_unseal_packet,
1269 .wrap = gensec_gse_wrap,
1270 .unwrap = gensec_gse_unwrap,
1271 .have_feature = gensec_gse_have_feature,
1274 .priority = GENSEC_GSSAPI
1277 #endif /* HAVE_KRB5 && HAVE_GSS_WRAP_IOV */