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
,
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
);
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
,
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
234 smb_krb5_get_principal_from_service_hostname(gse_ctx
,
238 if (!name_buffer
.value
) {
239 status
= NT_STATUS_NO_MEMORY
;
242 name_buffer
.length
= strlen((char *)name_buffer
.value
);
243 gss_maj
= gss_import_name(&gss_min
, &name_buffer
,
245 &gse_ctx
->server_name
);
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
;
254 /* TODO: get krb5 ticket using username/password, if no valid
255 * one already available in ccache */
258 mech_set
.elements
= &gse_ctx
->gss_mech
;
260 gss_maj
= gss_acquire_cred(&gss_min
,
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
;
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
,
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
;
298 TALLOC_FREE(name_buffer
.value
);
302 TALLOC_FREE(name_buffer
.value
);
303 TALLOC_FREE(gse_ctx
);
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
;
317 OM_uint32 time_rec
= 0;
320 in_data
.value
= token_in
->data
;
321 in_data
.length
= token_in
->length
;
323 gss_maj
= gss_init_sec_context(&gss_min
,
325 &gse_ctx
->gssapi_context
,
326 gse_ctx
->server_name
,
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
);
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
;
340 case GSS_S_CONTINUE_NEEDED
:
341 /* we will need a third leg */
342 status
= NT_STATUS_MORE_PROCESSING_REQUIRED
;
345 if ((gss_maj
== GSS_S_FAILURE
) &&
346 (gss_min
== KRB5KRB_AP_ERR_TKT_EXPIRED
)) {
347 DBG_NOTICE("Ticket expired\n");
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
;
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
);
360 status
= NT_STATUS_NO_MEMORY
;
363 gss_maj
= gss_release_buffer(&gss_min
, &out_data
);
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
;
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
,
390 status
= NT_STATUS_INTERNAL_ERROR
;
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
,
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
;
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
))
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 ... */
421 gss_OID_set_desc mech_set
;
423 ret
= smb_krb5_kt_get_name(gse_ctx
, gse_ctx
->k5ctx
,
424 gse_ctx
->keytab
, &ktname
);
426 status
= NT_STATUS_INTERNAL_ERROR
;
430 ret
= gsskrb5_register_acceptor_identity(ktname
);
432 status
= NT_STATUS_INTERNAL_ERROR
;
437 mech_set
.elements
= &gse_ctx
->gss_mech
;
439 gss_maj
= gss_acquire_cred(&gss_min
,
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
;
455 status
= NT_STATUS_OK
;
458 if (!NT_STATUS_IS_OK(status
)) {
459 TALLOC_FREE(gse_ctx
);
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
;
476 OM_uint32 time_rec
= 0;
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
,
486 GSS_C_NO_CHANNEL_BINDINGS
,
487 &gse_ctx
->client_name
,
490 &gse_ctx
->gss_got_flags
,
492 &gse_ctx
->delegated_cred_handle
);
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
;
501 case GSS_S_CONTINUE_NEEDED
:
502 /* we will need a third leg */
503 status
= NT_STATUS_MORE_PROCESSING_REQUIRED
;
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
,
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 */
523 status
= NT_STATUS_LOGON_FAILURE
;
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
);
532 status
= NT_STATUS_NO_MEMORY
;
534 gss_maj
= gss_release_buffer(&gss_min
, &out_data
);
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;
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
);
560 errstr
= talloc_strndup(mem_ctx
,
561 (char *)msg_maj
.value
,
566 gss_maj
= gss_display_status(&gss_min
, min
, GSS_C_MECH_CODE
,
567 (gss_OID
)discard_const(gss_mech_krb5
),
573 errstr
= talloc_strdup_append_buffer(errstr
, ": ");
577 errstr
= talloc_strndup_append_buffer(errstr
,
578 (char *)msg_min
.value
,
586 gss_maj
= gss_release_buffer(&gss_min
, &msg_min
);
589 gss_maj
= gss_release_buffer(&gss_min
, &msg_maj
);
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
);
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
);
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
) {
623 if (gensec_security
->want_features
& GENSEC_FEATURE_SIGN
) {
626 if (gensec_security
->want_features
& GENSEC_FEATURE_SEAL
) {
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
,
637 if (!NT_STATUS_IS_OK(nt_status
)) {
640 gensec_security
->private_data
= gse_ctx
;
644 static NTSTATUS
gensec_gse_server_start(struct gensec_security
*gensec_security
)
646 struct gse_context
*gse_ctx
;
648 OM_uint32 want_flags
= 0;
649 bool do_sign
= false, do_seal
= false;
651 if (gensec_security
->want_features
& GENSEC_FEATURE_SIGN
) {
654 if (gensec_security
->want_features
& GENSEC_FEATURE_SEAL
) {
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
,
663 if (!NT_STATUS_IS_OK(nt_status
)) {
666 gensec_security
->private_data
= gse_ctx
;
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
,
683 struct tevent_context
*ev
,
684 const DATA_BLOB in
, DATA_BLOB
*out
)
687 struct gse_context
*gse_ctx
=
688 talloc_get_type_abort(gensec_security
->private_data
,
691 switch (gensec_security
->gensec_role
) {
693 status
= gse_get_client_auth_token(mem_ctx
, gse_ctx
,
697 status
= gse_get_server_auth_token(mem_ctx
, gse_ctx
,
701 if (!NT_STATUS_IS_OK(status
)) {
708 static NTSTATUS
gensec_gse_wrap(struct gensec_security
*gensec_security
,
713 struct gse_context
*gse_ctx
=
714 talloc_get_type_abort(gensec_security
->private_data
,
716 OM_uint32 maj_stat
, min_stat
;
717 gss_buffer_desc input_token
, output_token
;
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
),
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
)
740 return NT_STATUS_ACCESS_DENIED
;
745 static NTSTATUS
gensec_gse_unwrap(struct gensec_security
*gensec_security
,
750 struct gse_context
*gse_ctx
=
751 talloc_get_type_abort(gensec_security
->private_data
,
753 OM_uint32 maj_stat
, min_stat
;
754 gss_buffer_desc input_token
, output_token
;
757 input_token
.length
= in
->length
;
758 input_token
.value
= in
->data
;
760 maj_stat
= gss_unwrap(&min_stat
,
761 gse_ctx
->gssapi_context
,
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
)
777 return NT_STATUS_ACCESS_DENIED
;
782 static NTSTATUS
gensec_gse_seal_packet(struct gensec_security
*gensec_security
,
784 uint8_t *data
, size_t length
,
785 const uint8_t *whole_pdu
, size_t pdu_length
,
788 struct gse_context
*gse_ctx
=
789 talloc_get_type_abort(gensec_security
->private_data
,
791 bool hdr_signing
= false;
795 if (gensec_security
->want_features
& GENSEC_FEATURE_SIGN_PKT_HEADER
) {
799 sig_size
= gensec_gse_sig_size(gensec_security
, length
);
801 status
= gssapi_seal_packet(gse_ctx
->gssapi_context
,
803 hdr_signing
, sig_size
,
805 whole_pdu
, pdu_length
,
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
,
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
,
826 bool hdr_signing
= false;
829 if (gensec_security
->want_features
& GENSEC_FEATURE_SIGN_PKT_HEADER
) {
833 status
= gssapi_unseal_packet(gse_ctx
->gssapi_context
,
837 whole_pdu
, pdu_length
,
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
,
850 static NTSTATUS
gensec_gse_sign_packet(struct gensec_security
*gensec_security
,
852 const uint8_t *data
, size_t length
,
853 const uint8_t *whole_pdu
, size_t pdu_length
,
856 struct gse_context
*gse_ctx
=
857 talloc_get_type_abort(gensec_security
->private_data
,
859 bool hdr_signing
= false;
862 if (gensec_security
->want_features
& GENSEC_FEATURE_SIGN_PKT_HEADER
) {
866 status
= gssapi_sign_packet(gse_ctx
->gssapi_context
,
870 whole_pdu
, pdu_length
,
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
,
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
,
891 bool hdr_signing
= false;
894 if (gensec_security
->want_features
& GENSEC_FEATURE_SIGN_PKT_HEADER
) {
898 status
= gssapi_check_packet(gse_ctx
->gssapi_context
,
902 whole_pdu
, pdu_length
,
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
,
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
,
919 struct gse_context
*gse_ctx
=
920 talloc_get_type_abort(gensec_security
->private_data
,
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
) {
939 if (!(gse_ctx
->gss_got_flags
& GSS_C_INTEG_FLAG
)) {
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
954 if (NT_STATUS_IS_OK(status
)) {
956 case ENCTYPE_DES_CBC_CRC
:
957 case ENCTYPE_DES_CBC_MD5
:
958 case ENCTYPE_ARCFOUR_HMAC
:
959 case ENCTYPE_DES3_CBC_SHA1
:
965 /* We can always do async (rather than strict request/reply) packets. */
966 if (feature
& GENSEC_FEATURE_ASYNC_REPLIES
) {
969 if (feature
& GENSEC_FEATURE_SIGN_PKT_HEADER
) {
970 if (gensec_security
->want_features
& GENSEC_FEATURE_SEAL
) {
974 if (gensec_security
->want_features
& GENSEC_FEATURE_SIGN
) {
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
,
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
,
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
);
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
,
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
,
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
,
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
,
1066 pac_blob_ptr
, principal_string
,
1067 gensec_get_remote_address(gensec_security
),
1069 if (!NT_STATUS_IS_OK(nt_status
)) {
1070 talloc_free(tmp_ctx
);
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
);
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
),
1099 gse_ctx
->max_wrap_buf_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
);
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
,
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
,
1134 gse_ctx
->gss_got_flags
,
1136 return gse_ctx
->sig_size
;
1139 static const char *gensec_gse_krb5_oids
[] = {
1140 GENSEC_OID_KERBEROS5_OLD
,
1141 GENSEC_OID_KERBEROS5
,
1145 const struct gensec_security_ops gensec_gse_krb5_security_ops
= {
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
,
1168 .priority
= GENSEC_GSSAPI
1171 #endif /* HAVE_KRB5 */