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/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"
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
,
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
;
51 gss_cred_id_t delegated_cred_handle
;
60 gss_OID_desc gss_mech
;
66 /* free non talloc dependent contexts */
67 static int gse_context_destructor(void *ptr
)
69 struct gse_context
*gse_ctx
;
72 gse_ctx
= talloc_get_type_abort(ptr
, struct gse_context
);
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
,
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
);
99 (void)gss_release_cred(&gss_min
,
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
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
));
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
;
133 gse_ctx
= talloc_zero(mem_ctx
, struct gse_context
);
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
|
146 GSS_C_DELEG_POLICY_FLAG
|
150 gse_ctx
->gss_want_flags
|= GSS_C_INTEG_FLAG
;
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
);
164 DEBUG(0, ("Failed to initialize kerberos context! (%s)\n",
165 error_message(k5ret
)));
166 status
= NT_STATUS_INTERNAL_ERROR
;
171 ccache_name
= krb5_cc_default_name(gse_ctx
->k5ctx
);
173 k5ret
= krb5_cc_resolve(gse_ctx
->k5ctx
, ccache_name
,
176 DEBUG(1, ("Failed to resolve credential cache! (%s)\n",
177 error_message(k5ret
)));
178 status
= NT_STATUS_INTERNAL_ERROR
;
182 /* TODO: Should we enforce a enc_types list ?
183 ret = krb5_set_default_tgs_ktypes(gse_ctx->k5ctx, enc_types);
190 TALLOC_FREE(gse_ctx
);
194 static NTSTATUS
gse_init_client(TALLOC_CTX
*mem_ctx
,
195 bool do_sign
, bool do_seal
,
196 const char *ccache_name
,
199 const char *username
,
200 const char *password
,
201 uint32_t add_gss_c_flags
,
202 struct gse_context
**_gse_ctx
)
204 struct gse_context
*gse_ctx
;
205 OM_uint32 gss_maj
, gss_min
;
206 gss_buffer_desc name_buffer
= GSS_C_EMPTY_BUFFER
;
207 gss_OID_set_desc mech_set
;
208 #ifdef HAVE_GSS_KRB5_CRED_NO_CI_FLAGS_X
209 gss_buffer_desc empty_buffer
= GSS_C_EMPTY_BUFFER
;
213 if (!server
|| !service
) {
214 return NT_STATUS_INVALID_PARAMETER
;
217 status
= gse_context_init(mem_ctx
, do_sign
, do_seal
,
218 ccache_name
, add_gss_c_flags
,
220 if (!NT_STATUS_IS_OK(status
)) {
221 return NT_STATUS_NO_MEMORY
;
224 /* Guess the realm based on the supplied service, and avoid the GSS libs
225 doing DNS lookups which may fail.
227 TODO: Loop with the KDC on some more combinations (local
228 realm in particular), possibly falling back to
229 GSS_C_NT_HOSTBASED_SERVICE
231 name_buffer
.value
= kerberos_get_principal_from_service_hostname(
232 gse_ctx
, service
, server
, lp_realm());
233 if (!name_buffer
.value
) {
234 status
= NT_STATUS_NO_MEMORY
;
237 name_buffer
.length
= strlen((char *)name_buffer
.value
);
238 gss_maj
= gss_import_name(&gss_min
, &name_buffer
,
240 &gse_ctx
->server_name
);
242 DEBUG(5, ("gss_import_name failed for %s, with [%s]\n",
243 (char *)name_buffer
.value
,
244 gse_errstr(gse_ctx
, gss_maj
, gss_min
)));
245 status
= NT_STATUS_INTERNAL_ERROR
;
249 /* TODO: get krb5 ticket using username/password, if no valid
250 * one already available in ccache */
253 mech_set
.elements
= &gse_ctx
->gss_mech
;
255 gss_maj
= gss_acquire_cred(&gss_min
,
263 DEBUG(5, ("gss_acquire_creds failed for GSS_C_NO_NAME with [%s] -"
264 "the caller may retry after a kinit.\n",
265 gse_errstr(gse_ctx
, gss_maj
, gss_min
)));
266 status
= NT_STATUS_INTERNAL_ERROR
;
270 #ifdef HAVE_GSS_KRB5_CRED_NO_CI_FLAGS_X
272 * Don't force GSS_C_CONF_FLAG and GSS_C_INTEG_FLAG.
274 * This allows us to disable SIGN and SEAL for
275 * AUTH_LEVEL_CONNECT and AUTH_LEVEL_INTEGRITY.
277 * https://groups.yahoo.com/neo/groups/cat-ietf/conversations/topics/575
278 * http://krbdev.mit.edu/rt/Ticket/Display.html?id=6938
280 gss_maj
= gss_set_cred_option(&gss_min
, &gse_ctx
->creds
,
281 GSS_KRB5_CRED_NO_CI_FLAGS_X
,
284 DEBUG(0, ("gss_set_cred_option(GSS_KRB5_CRED_NO_CI_FLAGS_X), "
285 "failed with [%s]\n",
286 gse_errstr(gse_ctx
, gss_maj
, gss_min
)));
287 status
= NT_STATUS_INTERNAL_ERROR
;
293 TALLOC_FREE(name_buffer
.value
);
297 TALLOC_FREE(name_buffer
.value
);
298 TALLOC_FREE(gse_ctx
);
302 static NTSTATUS
gse_get_client_auth_token(TALLOC_CTX
*mem_ctx
,
303 struct gse_context
*gse_ctx
,
304 const DATA_BLOB
*token_in
,
305 DATA_BLOB
*token_out
)
307 OM_uint32 gss_maj
, gss_min
;
308 gss_buffer_desc in_data
;
309 gss_buffer_desc out_data
;
310 DATA_BLOB blob
= data_blob_null
;
312 OM_uint32 time_rec
= 0;
315 in_data
.value
= token_in
->data
;
316 in_data
.length
= token_in
->length
;
318 gss_maj
= gss_init_sec_context(&gss_min
,
320 &gse_ctx
->gssapi_context
,
321 gse_ctx
->server_name
,
323 gse_ctx
->gss_want_flags
,
324 0, GSS_C_NO_CHANNEL_BINDINGS
,
325 &in_data
, NULL
, &out_data
,
326 &gse_ctx
->gss_got_flags
, &time_rec
);
329 /* we are done with it */
330 tv
= timeval_current_ofs(time_rec
, 0);
331 gse_ctx
->expire_time
= timeval_to_nttime(&tv
);
333 status
= NT_STATUS_OK
;
335 case GSS_S_CONTINUE_NEEDED
:
336 /* we will need a third leg */
337 status
= NT_STATUS_MORE_PROCESSING_REQUIRED
;
340 DEBUG(0, ("gss_init_sec_context failed with [%s]\n",
341 gse_errstr(talloc_tos(), gss_maj
, gss_min
)));
342 status
= NT_STATUS_INTERNAL_ERROR
;
346 /* we may be told to return nothing */
347 if (out_data
.length
) {
348 blob
= data_blob_talloc(mem_ctx
, out_data
.value
, out_data
.length
);
350 status
= NT_STATUS_NO_MEMORY
;
353 gss_maj
= gss_release_buffer(&gss_min
, &out_data
);
361 static NTSTATUS
gse_init_server(TALLOC_CTX
*mem_ctx
,
362 bool do_sign
, bool do_seal
,
363 uint32_t add_gss_c_flags
,
364 struct gse_context
**_gse_ctx
)
366 struct gse_context
*gse_ctx
;
367 OM_uint32 gss_maj
, gss_min
;
371 status
= gse_context_init(mem_ctx
, do_sign
, do_seal
,
372 NULL
, add_gss_c_flags
, &gse_ctx
);
373 if (!NT_STATUS_IS_OK(status
)) {
374 return NT_STATUS_NO_MEMORY
;
377 ret
= gse_krb5_get_server_keytab(gse_ctx
->k5ctx
,
380 status
= NT_STATUS_INTERNAL_ERROR
;
384 #ifdef HAVE_GSS_KRB5_IMPORT_CRED
386 /* This creates a GSSAPI cred_id_t with the keytab set */
387 gss_maj
= gss_krb5_import_cred(&gss_min
, NULL
, NULL
, gse_ctx
->keytab
,
391 && gss_maj
!= (GSS_S_CALL_BAD_STRUCTURE
|GSS_S_BAD_NAME
)) {
392 DEBUG(0, ("gss_krb5_import_cred failed with [%s]\n",
393 gse_errstr(gse_ctx
, gss_maj
, gss_min
)));
394 status
= NT_STATUS_INTERNAL_ERROR
;
397 /* This is the error the MIT krb5 1.9 gives when it
398 * implements the function, but we do not specify the
399 * principal. However, when we specify the principal
400 * as host$@REALM the GSS acceptor fails with 'wrong
401 * principal in request'. Work around the issue by
402 * falling back to the alternate approach below. */
403 } else if (gss_maj
== (GSS_S_CALL_BAD_STRUCTURE
|GSS_S_BAD_NAME
))
406 * This call sets the default keytab for the whole server, not
407 * just for this context. Need to find a way that does not alter
408 * the state of the whole server ... */
411 gss_OID_set_desc mech_set
;
413 ret
= smb_krb5_keytab_name(gse_ctx
, gse_ctx
->k5ctx
,
414 gse_ctx
->keytab
, &ktname
);
416 status
= NT_STATUS_INTERNAL_ERROR
;
420 ret
= gsskrb5_register_acceptor_identity(ktname
);
422 status
= NT_STATUS_INTERNAL_ERROR
;
427 mech_set
.elements
= &gse_ctx
->gss_mech
;
429 gss_maj
= gss_acquire_cred(&gss_min
,
438 DEBUG(0, ("gss_acquire_creds failed with [%s]\n",
439 gse_errstr(gse_ctx
, gss_maj
, gss_min
)));
440 status
= NT_STATUS_INTERNAL_ERROR
;
445 status
= NT_STATUS_OK
;
448 if (!NT_STATUS_IS_OK(status
)) {
449 TALLOC_FREE(gse_ctx
);
456 static NTSTATUS
gse_get_server_auth_token(TALLOC_CTX
*mem_ctx
,
457 struct gse_context
*gse_ctx
,
458 const DATA_BLOB
*token_in
,
459 DATA_BLOB
*token_out
)
461 OM_uint32 gss_maj
, gss_min
;
462 gss_buffer_desc in_data
;
463 gss_buffer_desc out_data
;
464 DATA_BLOB blob
= data_blob_null
;
466 OM_uint32 time_rec
= 0;
469 in_data
.value
= token_in
->data
;
470 in_data
.length
= token_in
->length
;
472 gss_maj
= gss_accept_sec_context(&gss_min
,
473 &gse_ctx
->gssapi_context
,
476 GSS_C_NO_CHANNEL_BINDINGS
,
477 &gse_ctx
->client_name
,
480 &gse_ctx
->gss_got_flags
,
482 &gse_ctx
->delegated_cred_handle
);
485 /* we are done with it */
486 tv
= timeval_current_ofs(time_rec
, 0);
487 gse_ctx
->expire_time
= timeval_to_nttime(&tv
);
489 status
= NT_STATUS_OK
;
491 case GSS_S_CONTINUE_NEEDED
:
492 /* we will need a third leg */
493 status
= NT_STATUS_MORE_PROCESSING_REQUIRED
;
496 DEBUG(1, ("gss_accept_sec_context failed with [%s]\n",
497 gse_errstr(talloc_tos(), gss_maj
, gss_min
)));
499 if (gse_ctx
->gssapi_context
) {
500 gss_delete_sec_context(&gss_min
,
501 &gse_ctx
->gssapi_context
,
506 * If we got an output token, make Windows aware of it
507 * by telling it that more processing is needed
509 if (out_data
.length
> 0) {
510 status
= NT_STATUS_MORE_PROCESSING_REQUIRED
;
511 /* Fall through to handle the out token */
513 status
= NT_STATUS_LOGON_FAILURE
;
518 /* we may be told to return nothing */
519 if (out_data
.length
) {
520 blob
= data_blob_talloc(mem_ctx
, out_data
.value
, out_data
.length
);
522 status
= NT_STATUS_NO_MEMORY
;
524 gss_maj
= gss_release_buffer(&gss_min
, &out_data
);
533 static char *gse_errstr(TALLOC_CTX
*mem_ctx
, OM_uint32 maj
, OM_uint32 min
)
535 OM_uint32 gss_min
, gss_maj
;
536 gss_buffer_desc msg_min
;
537 gss_buffer_desc msg_maj
;
538 OM_uint32 msg_ctx
= 0;
542 ZERO_STRUCT(msg_min
);
543 ZERO_STRUCT(msg_maj
);
545 gss_maj
= gss_display_status(&gss_min
, maj
, GSS_C_GSS_CODE
,
546 GSS_C_NO_OID
, &msg_ctx
, &msg_maj
);
550 errstr
= talloc_strndup(mem_ctx
,
551 (char *)msg_maj
.value
,
556 gss_maj
= gss_display_status(&gss_min
, min
, GSS_C_MECH_CODE
,
557 (gss_OID
)discard_const(gss_mech_krb5
),
563 errstr
= talloc_strdup_append_buffer(errstr
, ": ");
567 errstr
= talloc_strndup_append_buffer(errstr
,
568 (char *)msg_min
.value
,
576 gss_maj
= gss_release_buffer(&gss_min
, &msg_min
);
579 gss_maj
= gss_release_buffer(&gss_min
, &msg_maj
);
584 static NTSTATUS
gensec_gse_client_start(struct gensec_security
*gensec_security
)
586 struct gse_context
*gse_ctx
;
587 struct cli_credentials
*creds
= gensec_get_credentials(gensec_security
);
589 OM_uint32 want_flags
= 0;
590 bool do_sign
= false, do_seal
= false;
591 const char *hostname
= gensec_get_target_hostname(gensec_security
);
592 const char *service
= gensec_get_target_service(gensec_security
);
593 const char *username
= cli_credentials_get_username(creds
);
594 const char *password
= cli_credentials_get_password(creds
);
597 DEBUG(1, ("Could not determine hostname for target computer, cannot use kerberos\n"));
598 return NT_STATUS_INVALID_PARAMETER
;
600 if (is_ipaddress(hostname
)) {
601 DEBUG(2, ("Cannot do GSE to an IP address\n"));
602 return NT_STATUS_INVALID_PARAMETER
;
604 if (strcmp(hostname
, "localhost") == 0) {
605 DEBUG(2, ("GSE to 'localhost' does not make sense\n"));
606 return NT_STATUS_INVALID_PARAMETER
;
609 if (gensec_security
->want_features
& GENSEC_FEATURE_SESSION_KEY
) {
612 if (gensec_security
->want_features
& GENSEC_FEATURE_SIGN
) {
615 if (gensec_security
->want_features
& GENSEC_FEATURE_SEAL
) {
618 if (gensec_security
->want_features
& GENSEC_FEATURE_DCE_STYLE
) {
619 want_flags
|= GSS_C_DCE_STYLE
;
622 nt_status
= gse_init_client(gensec_security
, do_sign
, do_seal
, NULL
,
624 username
, password
, want_flags
,
626 if (!NT_STATUS_IS_OK(nt_status
)) {
629 gensec_security
->private_data
= gse_ctx
;
633 static NTSTATUS
gensec_gse_server_start(struct gensec_security
*gensec_security
)
635 struct gse_context
*gse_ctx
;
637 OM_uint32 want_flags
= 0;
638 bool do_sign
= false, do_seal
= false;
640 if (gensec_security
->want_features
& GENSEC_FEATURE_SIGN
) {
643 if (gensec_security
->want_features
& GENSEC_FEATURE_SEAL
) {
646 if (gensec_security
->want_features
& GENSEC_FEATURE_DCE_STYLE
) {
647 want_flags
|= GSS_C_DCE_STYLE
;
650 nt_status
= gse_init_server(gensec_security
, do_sign
, do_seal
, want_flags
,
652 if (!NT_STATUS_IS_OK(nt_status
)) {
655 gensec_security
->private_data
= gse_ctx
;
660 * Next state function for the GSE GENSEC mechanism
662 * @param gensec_gse_state GSE State
663 * @param mem_ctx The TALLOC_CTX for *out to be allocated on
664 * @param in The request, as a DATA_BLOB
665 * @param out The reply, as an talloc()ed DATA_BLOB, on *mem_ctx
666 * @return Error, MORE_PROCESSING_REQUIRED if a reply is sent,
667 * or NT_STATUS_OK if the user is authenticated.
670 static NTSTATUS
gensec_gse_update(struct gensec_security
*gensec_security
,
672 struct tevent_context
*ev
,
673 const DATA_BLOB in
, DATA_BLOB
*out
)
676 struct gse_context
*gse_ctx
=
677 talloc_get_type_abort(gensec_security
->private_data
,
680 switch (gensec_security
->gensec_role
) {
682 status
= gse_get_client_auth_token(mem_ctx
, gse_ctx
,
686 status
= gse_get_server_auth_token(mem_ctx
, gse_ctx
,
690 if (!NT_STATUS_IS_OK(status
)) {
697 static NTSTATUS
gensec_gse_wrap(struct gensec_security
*gensec_security
,
702 struct gse_context
*gse_ctx
=
703 talloc_get_type_abort(gensec_security
->private_data
,
705 OM_uint32 maj_stat
, min_stat
;
706 gss_buffer_desc input_token
, output_token
;
708 input_token
.length
= in
->length
;
709 input_token
.value
= in
->data
;
711 maj_stat
= gss_wrap(&min_stat
,
712 gse_ctx
->gssapi_context
,
713 gensec_have_feature(gensec_security
, GENSEC_FEATURE_SEAL
),
718 if (GSS_ERROR(maj_stat
)) {
719 DEBUG(0, ("gensec_gse_wrap: GSS Wrap failed: %s\n",
720 gse_errstr(talloc_tos(), maj_stat
, min_stat
)));
721 return NT_STATUS_ACCESS_DENIED
;
724 *out
= data_blob_talloc(mem_ctx
, output_token
.value
, output_token
.length
);
725 gss_release_buffer(&min_stat
, &output_token
);
727 if (gensec_have_feature(gensec_security
, GENSEC_FEATURE_SEAL
)
729 return NT_STATUS_ACCESS_DENIED
;
734 static NTSTATUS
gensec_gse_unwrap(struct gensec_security
*gensec_security
,
739 struct gse_context
*gse_ctx
=
740 talloc_get_type_abort(gensec_security
->private_data
,
742 OM_uint32 maj_stat
, min_stat
;
743 gss_buffer_desc input_token
, output_token
;
746 input_token
.length
= in
->length
;
747 input_token
.value
= in
->data
;
749 maj_stat
= gss_unwrap(&min_stat
,
750 gse_ctx
->gssapi_context
,
755 if (GSS_ERROR(maj_stat
)) {
756 DEBUG(0, ("gensec_gse_unwrap: GSS UnWrap failed: %s\n",
757 gse_errstr(talloc_tos(), maj_stat
, min_stat
)));
758 return NT_STATUS_ACCESS_DENIED
;
761 *out
= data_blob_talloc(mem_ctx
, output_token
.value
, output_token
.length
);
762 gss_release_buffer(&min_stat
, &output_token
);
764 if (gensec_have_feature(gensec_security
, GENSEC_FEATURE_SEAL
)
766 return NT_STATUS_ACCESS_DENIED
;
771 static NTSTATUS
gensec_gse_seal_packet(struct gensec_security
*gensec_security
,
773 uint8_t *data
, size_t length
,
774 const uint8_t *whole_pdu
, size_t pdu_length
,
777 struct gse_context
*gse_ctx
=
778 talloc_get_type_abort(gensec_security
->private_data
,
780 bool hdr_signing
= false;
784 if (gensec_security
->want_features
& GENSEC_FEATURE_SIGN_PKT_HEADER
) {
788 sig_size
= gensec_gse_sig_size(gensec_security
, length
);
790 status
= gssapi_seal_packet(gse_ctx
->gssapi_context
,
792 hdr_signing
, sig_size
,
794 whole_pdu
, pdu_length
,
796 if (!NT_STATUS_IS_OK(status
)) {
797 DEBUG(0, ("gssapi_seal_packet(hdr_signing=%u,sig_size=%zu,"
798 "data=%zu,pdu=%zu) failed: %s\n",
799 hdr_signing
, sig_size
, length
, pdu_length
,
807 static NTSTATUS
gensec_gse_unseal_packet(struct gensec_security
*gensec_security
,
808 uint8_t *data
, size_t length
,
809 const uint8_t *whole_pdu
, size_t pdu_length
,
810 const DATA_BLOB
*sig
)
812 struct gse_context
*gse_ctx
=
813 talloc_get_type_abort(gensec_security
->private_data
,
815 bool hdr_signing
= false;
818 if (gensec_security
->want_features
& GENSEC_FEATURE_SIGN_PKT_HEADER
) {
822 status
= gssapi_unseal_packet(gse_ctx
->gssapi_context
,
826 whole_pdu
, pdu_length
,
828 if (!NT_STATUS_IS_OK(status
)) {
829 DEBUG(0, ("gssapi_unseal_packet(hdr_signing=%u,sig_size=%zu,"
830 "data=%zu,pdu=%zu) failed: %s\n",
831 hdr_signing
, sig
->length
, length
, pdu_length
,
839 static NTSTATUS
gensec_gse_sign_packet(struct gensec_security
*gensec_security
,
841 const uint8_t *data
, size_t length
,
842 const uint8_t *whole_pdu
, size_t pdu_length
,
845 struct gse_context
*gse_ctx
=
846 talloc_get_type_abort(gensec_security
->private_data
,
848 bool hdr_signing
= false;
851 if (gensec_security
->want_features
& GENSEC_FEATURE_SIGN_PKT_HEADER
) {
855 status
= gssapi_sign_packet(gse_ctx
->gssapi_context
,
859 whole_pdu
, pdu_length
,
861 if (!NT_STATUS_IS_OK(status
)) {
862 DEBUG(0, ("gssapi_sign_packet(hdr_signing=%u,"
863 "data=%zu,pdu=%zu) failed: %s\n",
864 hdr_signing
, length
, pdu_length
,
872 static NTSTATUS
gensec_gse_check_packet(struct gensec_security
*gensec_security
,
873 const uint8_t *data
, size_t length
,
874 const uint8_t *whole_pdu
, size_t pdu_length
,
875 const DATA_BLOB
*sig
)
877 struct gse_context
*gse_ctx
=
878 talloc_get_type_abort(gensec_security
->private_data
,
880 bool hdr_signing
= false;
883 if (gensec_security
->want_features
& GENSEC_FEATURE_SIGN_PKT_HEADER
) {
887 status
= gssapi_check_packet(gse_ctx
->gssapi_context
,
891 whole_pdu
, pdu_length
,
893 if (!NT_STATUS_IS_OK(status
)) {
894 DEBUG(0, ("gssapi_check_packet(hdr_signing=%u,sig_size=%zu"
895 "data=%zu,pdu=%zu) failed: %s\n",
896 hdr_signing
, sig
->length
, length
, pdu_length
,
904 /* Try to figure out what features we actually got on the connection */
905 static bool gensec_gse_have_feature(struct gensec_security
*gensec_security
,
908 struct gse_context
*gse_ctx
=
909 talloc_get_type_abort(gensec_security
->private_data
,
912 if (feature
& GENSEC_FEATURE_SESSION_KEY
) {
913 return gse_ctx
->gss_got_flags
& GSS_C_INTEG_FLAG
;
915 if (feature
& GENSEC_FEATURE_SIGN
) {
916 return gse_ctx
->gss_got_flags
& GSS_C_INTEG_FLAG
;
918 if (feature
& GENSEC_FEATURE_SEAL
) {
919 return gse_ctx
->gss_got_flags
& GSS_C_CONF_FLAG
;
921 if (feature
& GENSEC_FEATURE_DCE_STYLE
) {
922 return gse_ctx
->gss_got_flags
& GSS_C_DCE_STYLE
;
924 if (feature
& GENSEC_FEATURE_NEW_SPNEGO
) {
928 if (!(gse_ctx
->gss_got_flags
& GSS_C_INTEG_FLAG
)) {
932 status
= gssapi_get_session_key(talloc_tos(),
933 gse_ctx
->gssapi_context
, NULL
, &keytype
);
935 * We should do a proper sig on the mechListMic unless
936 * we know we have to be backwards compatible with
937 * earlier windows versions.
939 * Negotiating a non-krb5
940 * mech for example should be regarded as having
943 if (NT_STATUS_IS_OK(status
)) {
945 case ENCTYPE_DES_CBC_CRC
:
946 case ENCTYPE_DES_CBC_MD5
:
947 case ENCTYPE_ARCFOUR_HMAC
:
948 case ENCTYPE_DES3_CBC_SHA1
:
954 /* We can always do async (rather than strict request/reply) packets. */
955 if (feature
& GENSEC_FEATURE_ASYNC_REPLIES
) {
958 if (feature
& GENSEC_FEATURE_SIGN_PKT_HEADER
) {
959 if (gensec_security
->want_features
& GENSEC_FEATURE_SEAL
) {
963 if (gensec_security
->want_features
& GENSEC_FEATURE_SIGN
) {
972 static NTTIME
gensec_gse_expire_time(struct gensec_security
*gensec_security
)
974 struct gse_context
*gse_ctx
=
975 talloc_get_type_abort(gensec_security
->private_data
,
978 return gse_ctx
->expire_time
;
982 * Extract the 'sesssion key' needed by SMB signing and ncacn_np
983 * (for encrypting some passwords).
985 * This breaks all the abstractions, but what do you expect...
987 static NTSTATUS
gensec_gse_session_key(struct gensec_security
*gensec_security
,
989 DATA_BLOB
*session_key
)
991 struct gse_context
*gse_ctx
=
992 talloc_get_type_abort(gensec_security
->private_data
,
995 return gssapi_get_session_key(mem_ctx
, gse_ctx
->gssapi_context
, session_key
, NULL
);
998 /* Get some basic (and authorization) information about the user on
999 * this session. This uses either the PAC (if present) or a local
1000 * database lookup */
1001 static NTSTATUS
gensec_gse_session_info(struct gensec_security
*gensec_security
,
1002 TALLOC_CTX
*mem_ctx
,
1003 struct auth_session_info
**_session_info
)
1005 struct gse_context
*gse_ctx
=
1006 talloc_get_type_abort(gensec_security
->private_data
,
1007 struct gse_context
);
1009 TALLOC_CTX
*tmp_ctx
;
1010 struct auth_session_info
*session_info
= NULL
;
1011 OM_uint32 maj_stat
, min_stat
;
1012 DATA_BLOB pac_blob
, *pac_blob_ptr
= NULL
;
1014 gss_buffer_desc name_token
;
1015 char *principal_string
;
1017 tmp_ctx
= talloc_named(mem_ctx
, 0, "gensec_gse_session_info context");
1018 NT_STATUS_HAVE_NO_MEMORY(tmp_ctx
);
1020 maj_stat
= gss_display_name(&min_stat
,
1021 gse_ctx
->client_name
,
1024 if (GSS_ERROR(maj_stat
)) {
1025 DEBUG(1, ("GSS display_name failed: %s\n",
1026 gse_errstr(talloc_tos(), maj_stat
, min_stat
)));
1027 talloc_free(tmp_ctx
);
1028 return NT_STATUS_FOOBAR
;
1031 principal_string
= talloc_strndup(tmp_ctx
,
1032 (const char *)name_token
.value
,
1035 gss_release_buffer(&min_stat
, &name_token
);
1037 if (!principal_string
) {
1038 talloc_free(tmp_ctx
);
1039 return NT_STATUS_NO_MEMORY
;
1042 nt_status
= gssapi_obtain_pac_blob(tmp_ctx
, gse_ctx
->gssapi_context
,
1043 gse_ctx
->client_name
,
1046 /* IF we have the PAC - otherwise we need to get this
1047 * data from elsewere
1049 if (NT_STATUS_IS_OK(nt_status
)) {
1050 pac_blob_ptr
= &pac_blob
;
1052 nt_status
= gensec_generate_session_info_pac(tmp_ctx
,
1055 pac_blob_ptr
, principal_string
,
1056 gensec_get_remote_address(gensec_security
),
1058 if (!NT_STATUS_IS_OK(nt_status
)) {
1059 talloc_free(tmp_ctx
);
1063 nt_status
= gensec_gse_session_key(gensec_security
, session_info
,
1064 &session_info
->session_key
);
1065 if (!NT_STATUS_IS_OK(nt_status
)) {
1066 talloc_free(tmp_ctx
);
1070 *_session_info
= talloc_move(mem_ctx
, &session_info
);
1071 talloc_free(tmp_ctx
);
1073 return NT_STATUS_OK
;
1076 static size_t gensec_gse_max_input_size(struct gensec_security
*gensec_security
)
1078 struct gse_context
*gse_ctx
=
1079 talloc_get_type_abort(gensec_security
->private_data
,
1080 struct gse_context
);
1081 OM_uint32 maj_stat
, min_stat
;
1082 OM_uint32 max_input_size
;
1084 maj_stat
= gss_wrap_size_limit(&min_stat
,
1085 gse_ctx
->gssapi_context
,
1086 gensec_have_feature(gensec_security
, GENSEC_FEATURE_SEAL
),
1088 gse_ctx
->max_wrap_buf_size
,
1090 if (GSS_ERROR(maj_stat
)) {
1091 TALLOC_CTX
*mem_ctx
= talloc_new(NULL
);
1092 DEBUG(1, ("gensec_gssapi_max_input_size: determining signature size with gss_wrap_size_limit failed: %s\n",
1093 gse_errstr(mem_ctx
, maj_stat
, min_stat
)));
1094 talloc_free(mem_ctx
);
1098 return max_input_size
;
1101 /* Find out the maximum output size negotiated on this connection */
1102 static size_t gensec_gse_max_wrapped_size(struct gensec_security
*gensec_security
)
1104 struct gse_context
*gse_ctx
=
1105 talloc_get_type_abort(gensec_security
->private_data
,
1106 struct gse_context
);
1107 return gse_ctx
->max_wrap_buf_size
;
1110 static size_t gensec_gse_sig_size(struct gensec_security
*gensec_security
,
1113 struct gse_context
*gse_ctx
=
1114 talloc_get_type_abort(gensec_security
->private_data
,
1115 struct gse_context
);
1117 if (gse_ctx
->sig_size
> 0) {
1118 return gse_ctx
->sig_size
;
1121 gse_ctx
->sig_size
= gssapi_get_sig_size(gse_ctx
->gssapi_context
,
1123 gse_ctx
->gss_want_flags
,
1125 return gse_ctx
->sig_size
;
1128 static const char *gensec_gse_krb5_oids
[] = {
1129 GENSEC_OID_KERBEROS5_OLD
,
1130 GENSEC_OID_KERBEROS5
,
1134 const struct gensec_security_ops gensec_gse_krb5_security_ops
= {
1136 .auth_type
= DCERPC_AUTH_TYPE_KRB5
,
1137 .oid
= gensec_gse_krb5_oids
,
1138 .client_start
= gensec_gse_client_start
,
1139 .server_start
= gensec_gse_server_start
,
1140 .magic
= gensec_magic_check_krb5_oid
,
1141 .update
= gensec_gse_update
,
1142 .session_key
= gensec_gse_session_key
,
1143 .session_info
= gensec_gse_session_info
,
1144 .sig_size
= gensec_gse_sig_size
,
1145 .sign_packet
= gensec_gse_sign_packet
,
1146 .check_packet
= gensec_gse_check_packet
,
1147 .seal_packet
= gensec_gse_seal_packet
,
1148 .unseal_packet
= gensec_gse_unseal_packet
,
1149 .max_input_size
= gensec_gse_max_input_size
,
1150 .max_wrapped_size
= gensec_gse_max_wrapped_size
,
1151 .wrap
= gensec_gse_wrap
,
1152 .unwrap
= gensec_gse_unwrap
,
1153 .have_feature
= gensec_gse_have_feature
,
1154 .expire_time
= gensec_gse_expire_time
,
1157 .priority
= GENSEC_GSSAPI
1160 #endif /* HAVE_KRB5 */