2 Unix SMB/CIFS implementation.
4 Kerberos backend for GENSEC
6 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2005
7 Copyright (C) Stefan Metzmacher <metze@samba.org> 2004-2005
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 #include "system/kerberos.h"
27 #include "auth/kerberos/kerberos.h"
28 #include "librpc/gen_ndr/ndr_krb5pac.h"
29 #include "auth/auth.h"
30 #include "lib/ldb/include/ldb.h"
31 #include "auth/auth_sam.h"
33 enum gensec_gssapi_sasl_state
37 STAGE_SASL_SSF_ACCEPT,
45 struct gensec_gssapi_state {
46 gss_ctx_id_t gssapi_context;
47 struct gss_channel_bindings_struct *input_chan_bindings;
48 gss_name_t server_name;
49 gss_name_t client_name;
50 OM_uint32 want_flags, got_flags;
51 const gss_OID_desc *gss_oid;
53 DATA_BLOB session_key;
56 struct smb_krb5_context *smb_krb5_context;
57 struct gssapi_creds_container *client_cred;
58 struct gssapi_creds_container *server_cred;
60 gss_cred_id_t delegated_cred_handle;
62 BOOL sasl; /* We have two different mechs in this file: One
63 * for SASL wrapped GSSAPI and another for normal
65 enum gensec_gssapi_sasl_state sasl_state;
66 uint8_t sasl_protection; /* What was negotiated at the SASL
67 * layer, independent of the GSSAPI
71 static char *gssapi_error_string(TALLOC_CTX *mem_ctx,
72 OM_uint32 maj_stat, OM_uint32 min_stat)
74 OM_uint32 disp_min_stat, disp_maj_stat;
75 gss_buffer_desc maj_error_message;
76 gss_buffer_desc min_error_message;
77 OM_uint32 msg_ctx = 0;
81 maj_error_message.value = NULL;
82 min_error_message.value = NULL;
84 disp_maj_stat = gss_display_status(&disp_min_stat, maj_stat, GSS_C_GSS_CODE,
85 GSS_C_NULL_OID, &msg_ctx, &maj_error_message);
86 disp_maj_stat = gss_display_status(&disp_min_stat, min_stat, GSS_C_MECH_CODE,
87 GSS_C_NULL_OID, &msg_ctx, &min_error_message);
88 ret = talloc_asprintf(mem_ctx, "%s: %s", (char *)maj_error_message.value, (char *)min_error_message.value);
90 gss_release_buffer(&disp_min_stat, &maj_error_message);
91 gss_release_buffer(&disp_min_stat, &min_error_message);
97 static int gensec_gssapi_destory(void *ptr)
99 struct gensec_gssapi_state *gensec_gssapi_state = ptr;
100 OM_uint32 maj_stat, min_stat;
102 if (gensec_gssapi_state->delegated_cred_handle != GSS_C_NO_CREDENTIAL) {
103 maj_stat = gss_release_cred(&min_stat,
104 &gensec_gssapi_state->delegated_cred_handle);
107 if (gensec_gssapi_state->gssapi_context != GSS_C_NO_CONTEXT) {
108 maj_stat = gss_delete_sec_context (&min_stat,
109 &gensec_gssapi_state->gssapi_context,
113 if (gensec_gssapi_state->server_name != GSS_C_NO_NAME) {
114 maj_stat = gss_release_name(&min_stat, &gensec_gssapi_state->server_name);
116 if (gensec_gssapi_state->client_name != GSS_C_NO_NAME) {
117 maj_stat = gss_release_name(&min_stat, &gensec_gssapi_state->client_name);
122 static NTSTATUS gensec_gssapi_start(struct gensec_security *gensec_security)
124 struct gensec_gssapi_state *gensec_gssapi_state;
127 gensec_gssapi_state = talloc(gensec_security, struct gensec_gssapi_state);
128 if (!gensec_gssapi_state) {
129 return NT_STATUS_NO_MEMORY;
132 gensec_gssapi_state->sasl = False;
133 gensec_gssapi_state->sasl_state = STAGE_GSS_NEG;
135 gensec_security->private_data = gensec_gssapi_state;
137 gensec_gssapi_state->gssapi_context = GSS_C_NO_CONTEXT;
138 gensec_gssapi_state->server_name = GSS_C_NO_NAME;
139 gensec_gssapi_state->client_name = GSS_C_NO_NAME;
141 /* TODO: Fill in channel bindings */
142 gensec_gssapi_state->input_chan_bindings = GSS_C_NO_CHANNEL_BINDINGS;
144 gensec_gssapi_state->want_flags = 0;
145 if (lp_parm_bool(-1, "gensec_gssapi", "mutual", True)) {
146 gensec_gssapi_state->want_flags |= GSS_C_MUTUAL_FLAG;
148 if (lp_parm_bool(-1, "gensec_gssapi", "delegation", True)) {
149 gensec_gssapi_state->want_flags |= GSS_C_DELEG_FLAG;
151 if (lp_parm_bool(-1, "gensec_gssapi", "sequence", True)) {
152 gensec_gssapi_state->want_flags |= GSS_C_SEQUENCE_FLAG;
155 gensec_gssapi_state->got_flags = 0;
157 gensec_gssapi_state->session_key = data_blob(NULL, 0);
158 gensec_gssapi_state->pac = data_blob(NULL, 0);
160 gensec_gssapi_state->delegated_cred_handle = GSS_C_NO_CREDENTIAL;
162 talloc_set_destructor(gensec_gssapi_state, gensec_gssapi_destory);
164 if (gensec_security->want_features & GENSEC_FEATURE_SIGN) {
165 gensec_gssapi_state->want_flags |= GSS_C_INTEG_FLAG;
167 if (gensec_security->want_features & GENSEC_FEATURE_SEAL) {
168 gensec_gssapi_state->want_flags |= GSS_C_CONF_FLAG;
170 if (gensec_security->want_features & GENSEC_FEATURE_DCE_STYLE) {
171 gensec_gssapi_state->want_flags |= GSS_C_DCE_STYLE;
174 gensec_gssapi_state->gss_oid = gss_mech_krb5;
176 ret = smb_krb5_init_context(gensec_gssapi_state,
177 &gensec_gssapi_state->smb_krb5_context);
179 DEBUG(1,("gensec_krb5_start: krb5_init_context failed (%s)\n",
180 error_message(ret)));
181 return NT_STATUS_INTERNAL_ERROR;
186 static NTSTATUS gensec_gssapi_server_start(struct gensec_security *gensec_security)
190 struct gensec_gssapi_state *gensec_gssapi_state;
191 struct cli_credentials *machine_account;
192 struct gssapi_creds_container *gcc;
194 nt_status = gensec_gssapi_start(gensec_security);
195 if (!NT_STATUS_IS_OK(nt_status)) {
199 gensec_gssapi_state = talloc_get_type(gensec_security->private_data, struct gensec_gssapi_state);
201 machine_account = gensec_get_credentials(gensec_security);
203 if (!machine_account) {
204 DEBUG(3, ("No machine account credentials specified\n"));
205 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
207 ret = cli_credentials_get_server_gss_creds(machine_account, &gcc);
209 DEBUG(1, ("Aquiring acceptor credentials failed: %s\n",
210 error_message(ret)));
211 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
215 gensec_gssapi_state->server_cred = gcc;
220 static NTSTATUS gensec_gssapi_sasl_server_start(struct gensec_security *gensec_security)
223 struct gensec_gssapi_state *gensec_gssapi_state;
224 nt_status = gensec_gssapi_server_start(gensec_security);
226 if (NT_STATUS_IS_OK(nt_status)) {
227 gensec_gssapi_state = talloc_get_type(gensec_security->private_data, struct gensec_gssapi_state);
228 gensec_gssapi_state->sasl = True;
233 static NTSTATUS gensec_gssapi_client_start(struct gensec_security *gensec_security)
235 struct gensec_gssapi_state *gensec_gssapi_state;
236 struct cli_credentials *creds = gensec_get_credentials(gensec_security);
239 gss_buffer_desc name_token;
241 OM_uint32 maj_stat, min_stat;
242 const char *hostname = gensec_get_target_hostname(gensec_security);
243 const char *principal;
244 struct gssapi_creds_container *gcc;
247 DEBUG(1, ("Could not determine hostname for target computer, cannot use kerberos\n"));
248 return NT_STATUS_INVALID_PARAMETER;
250 if (is_ipaddress(hostname)) {
251 DEBUG(2, ("Cannot do GSSAPI to an IP address\n"));
252 return NT_STATUS_INVALID_PARAMETER;
254 if (strequal(hostname, "localhost")) {
255 DEBUG(2, ("GSSAPI to 'localhost' does not make sense\n"));
256 return NT_STATUS_INVALID_PARAMETER;
259 nt_status = gensec_gssapi_start(gensec_security);
260 if (!NT_STATUS_IS_OK(nt_status)) {
264 gensec_gssapi_state = talloc_get_type(gensec_security->private_data, struct gensec_gssapi_state);
266 principal = gensec_get_target_principal(gensec_security);
267 if (principal && lp_client_use_spnego_principal()) {
268 name_token.value = discard_const_p(uint8_t, principal);
269 name_token.length = strlen(principal);
271 name_type = GSS_C_NULL_OID;
273 principal = talloc_asprintf(gensec_gssapi_state, "%s@%s",
274 gensec_get_target_service(gensec_security),
277 name_token.value = discard_const_p(uint8_t, principal);
278 name_token.length = strlen(principal);
280 name_type = GSS_C_NT_HOSTBASED_SERVICE;
283 maj_stat = gss_import_name (&min_stat,
286 &gensec_gssapi_state->server_name);
288 DEBUG(2, ("GSS Import name of %s failed: %s\n",
289 (char *)name_token.value,
290 gssapi_error_string(gensec_gssapi_state, maj_stat, min_stat)));
291 return NT_STATUS_INVALID_PARAMETER;
294 ret = cli_credentials_get_client_gss_creds(creds, &gcc);
298 case KRB5_KDC_UNREACH:
299 DEBUG(3, ("Cannot reach a KDC we require\n"));
300 return NT_STATUS_INVALID_PARAMETER; /* Make SPNEGO ignore us, we can't go any further here */
302 DEBUG(1, ("Aquiring initiator credentails failed\n"));
303 return NT_STATUS_UNSUCCESSFUL;
306 gensec_gssapi_state->client_cred = gcc;
311 static NTSTATUS gensec_gssapi_sasl_client_start(struct gensec_security *gensec_security)
314 struct gensec_gssapi_state *gensec_gssapi_state;
315 nt_status = gensec_gssapi_client_start(gensec_security);
317 if (NT_STATUS_IS_OK(nt_status)) {
318 gensec_gssapi_state = talloc_get_type(gensec_security->private_data, struct gensec_gssapi_state);
319 gensec_gssapi_state->sasl = True;
326 * Check if the packet is one for this mechansim
328 * @param gensec_security GENSEC state
329 * @param in The request, as a DATA_BLOB
330 * @return Error, INVALID_PARAMETER if it's not a packet for us
331 * or NT_STATUS_OK if the packet is ok.
334 static NTSTATUS gensec_gssapi_magic(struct gensec_security *gensec_security,
337 if (gensec_gssapi_check_oid(in, GENSEC_OID_KERBEROS5)) {
340 return NT_STATUS_INVALID_PARAMETER;
346 * Next state function for the GSSAPI GENSEC mechanism
348 * @param gensec_gssapi_state GSSAPI State
349 * @param out_mem_ctx The TALLOC_CTX for *out to be allocated on
350 * @param in The request, as a DATA_BLOB
351 * @param out The reply, as an talloc()ed DATA_BLOB, on *out_mem_ctx
352 * @return Error, MORE_PROCESSING_REQUIRED if a reply is sent,
353 * or NT_STATUS_OK if the user is authenticated.
356 static NTSTATUS gensec_gssapi_update(struct gensec_security *gensec_security,
357 TALLOC_CTX *out_mem_ctx,
358 const DATA_BLOB in, DATA_BLOB *out)
360 struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
361 NTSTATUS nt_status = NT_STATUS_LOGON_FAILURE;
362 OM_uint32 maj_stat, min_stat;
364 gss_buffer_desc input_token, output_token;
366 input_token.length = in.length;
367 input_token.value = in.data;
369 switch (gensec_gssapi_state->sasl_state) {
372 switch (gensec_security->gensec_role) {
375 maj_stat = gss_init_sec_context(&min_stat,
376 gensec_gssapi_state->client_cred->creds,
377 &gensec_gssapi_state->gssapi_context,
378 gensec_gssapi_state->server_name,
379 discard_const_p(gss_OID_desc, gensec_gssapi_state->gss_oid),
380 gensec_gssapi_state->want_flags,
382 gensec_gssapi_state->input_chan_bindings,
386 &gensec_gssapi_state->got_flags, /* ret flags */
392 maj_stat = gss_accept_sec_context(&min_stat,
393 &gensec_gssapi_state->gssapi_context,
394 gensec_gssapi_state->server_cred->creds,
396 gensec_gssapi_state->input_chan_bindings,
397 &gensec_gssapi_state->client_name,
400 &gensec_gssapi_state->got_flags,
402 &gensec_gssapi_state->delegated_cred_handle);
403 gensec_gssapi_state->gss_oid = gss_oid_p;
407 return NT_STATUS_INVALID_PARAMETER;
411 if (maj_stat == GSS_S_COMPLETE) {
412 *out = data_blob_talloc(out_mem_ctx, output_token.value, output_token.length);
413 gss_release_buffer(&min_stat2, &output_token);
415 if (gensec_gssapi_state->got_flags & GSS_C_DELEG_FLAG) {
416 DEBUG(5, ("gensec_gssapi: credentials were delegated\n"));
418 DEBUG(5, ("gensec_gssapi: NO credentials were delegated\n"));
421 /* We may have been invoked as SASL, so there
422 * is more work to do */
423 if (gensec_gssapi_state->sasl) {
424 /* Due to a very subtle interaction
425 * with SASL and the LDAP libs, we
426 * must ensure the data pointer is
427 * != NULL, but the length is 0.
429 * This ensures we send a 'zero
430 * length' (rather than NULL) response
434 out->data = (uint8_t *)talloc_strdup(out_mem_ctx, "\0");
437 gensec_gssapi_state->sasl_state = STAGE_SASL_SSF_NEG;
438 return NT_STATUS_MORE_PROCESSING_REQUIRED;
440 gensec_gssapi_state->sasl_state = STAGE_DONE;
442 if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
443 DEBUG(3, ("GSSAPI Connection will be cryptographicly sealed\n"));
444 } else if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
445 DEBUG(3, ("GSSAPI Connection will be cryptographicly signed\n"));
447 DEBUG(3, ("GSSAPI Connection will have no cryptographicly protection\n"));
452 } else if (maj_stat == GSS_S_CONTINUE_NEEDED) {
453 *out = data_blob_talloc(out_mem_ctx, output_token.value, output_token.length);
454 gss_release_buffer(&min_stat2, &output_token);
456 return NT_STATUS_MORE_PROCESSING_REQUIRED;
457 } else if ((gensec_gssapi_state->gss_oid->length == gss_mech_krb5->length)
458 && (memcmp(gensec_gssapi_state->gss_oid->elements, gss_mech_krb5->elements,
459 gensec_gssapi_state->gss_oid->length) == 0)) {
461 case KRB5_KDC_UNREACH:
462 DEBUG(3, ("Cannot reach a KDC we require: %s\n",
463 gssapi_error_string(gensec_gssapi_state, maj_stat, min_stat)));
464 return NT_STATUS_INVALID_PARAMETER; /* Make SPNEGO ignore us, we can't go any further here */
465 case KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN:
466 DEBUG(3, ("Server is not registered with our KDC: %s\n",
467 gssapi_error_string(gensec_gssapi_state, maj_stat, min_stat)));
468 return NT_STATUS_INVALID_PARAMETER; /* Make SPNEGO ignore us, we can't go any further here */
469 case KRB5KRB_AP_ERR_MSG_TYPE:
470 /* garbage input, possibly from the auto-mech detection */
471 return NT_STATUS_INVALID_PARAMETER;
473 DEBUG(1, ("GSS(krb5) Update failed: %s\n",
474 gssapi_error_string(out_mem_ctx, maj_stat, min_stat)));
478 DEBUG(1, ("GSS Update failed: %s\n",
479 gssapi_error_string(out_mem_ctx, maj_stat, min_stat)));
484 /* These last two stages are only done if we were invoked as SASL */
485 case STAGE_SASL_SSF_NEG:
487 switch (gensec_security->gensec_role) {
490 uint8_t maxlength_proposed[4];
491 uint8_t security_supported;
494 input_token.length = in.length;
495 input_token.value = in.data;
497 maj_stat = gss_unwrap(&min_stat,
498 gensec_gssapi_state->gssapi_context,
503 if (GSS_ERROR(maj_stat)) {
504 DEBUG(1, ("gensec_gssapi_update: GSS UnWrap of SASL protection negotiation failed: %s\n",
505 gssapi_error_string(out_mem_ctx, maj_stat, min_stat)));
506 return NT_STATUS_ACCESS_DENIED;
509 if (output_token.length < 4) {
510 return NT_STATUS_INVALID_PARAMETER;
513 memcpy(maxlength_proposed, output_token.value, 4);
514 gss_release_buffer(&min_stat, &output_token);
516 /* first byte is the proposed security */
517 security_supported = maxlength_proposed[0];
518 maxlength_proposed[0] = '\0';
519 gensec_gssapi_state->sasl_protection = 0;
520 if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
521 if (security_supported & NEG_SEAL) {
522 gensec_gssapi_state->sasl_protection |= NEG_SEAL;
524 } else if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
525 if (security_supported & NEG_SIGN) {
526 gensec_gssapi_state->sasl_protection |= NEG_SIGN;
528 } else if (security_supported & NEG_NONE) {
529 gensec_gssapi_state->sasl_protection |= NEG_NONE;
531 DEBUG(1, ("Remote server does not support unprotected connections"));
532 return NT_STATUS_ACCESS_DENIED;
535 /* We just accept their max length, and send
536 * it back with the SASL flags */
537 maxlength_proposed[0] = gensec_gssapi_state->sasl_protection;
539 input_token.value = maxlength_proposed;
540 input_token.length = sizeof(maxlength_proposed);
542 maj_stat = gss_wrap(&min_stat,
543 gensec_gssapi_state->gssapi_context,
549 if (GSS_ERROR(maj_stat)) {
550 DEBUG(1, ("gensec_gssapi_wrap: GSS Wrap failed: %s\n",
551 gssapi_error_string(out_mem_ctx, maj_stat, min_stat)));
552 return NT_STATUS_ACCESS_DENIED;
555 *out = data_blob_talloc(out_mem_ctx, output_token.value, output_token.length);
556 gss_release_buffer(&min_stat, &output_token);
558 /* quirk: This changes the value that gensec_have_feature returns, to be that after SASL negotiation */
559 gensec_gssapi_state->sasl_state = STAGE_DONE;
561 if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
562 DEBUG(3, ("SASL/GSSAPI Connection to server will be cryptographicly sealed\n"));
563 } else if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
564 DEBUG(3, ("SASL/GSSAPI Connection to server will be cryptographicly signed\n"));
566 DEBUG(3, ("SASL/GSSAPI Connection to server will have no cryptographicly protection\n"));
573 uint8_t maxlength_proposed[4];
574 uint8_t security_supported = 0x0;
577 /* TODO: Need some better ideas for this */
578 RSIVAL(maxlength_proposed, 0, 0xFFFFFF);
579 /* first byte is the proposed security */
580 maxlength_proposed[0] = '\0';
582 gensec_gssapi_state->sasl_protection = 0;
583 if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
584 security_supported |= NEG_SEAL;
586 if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
587 security_supported |= NEG_SIGN;
589 if (security_supported == 0) {
590 /* If we don't support anything, this must be 0 */
591 RSIVAL(maxlength_proposed, 0, 0x0);
594 /* TODO: We may not wish to support this */
595 security_supported |= NEG_NONE;
598 maxlength_proposed[0] = security_supported;
600 input_token.value = maxlength_proposed;
601 input_token.length = sizeof(maxlength_proposed);
603 maj_stat = gss_wrap(&min_stat,
604 gensec_gssapi_state->gssapi_context,
610 if (GSS_ERROR(maj_stat)) {
611 DEBUG(1, ("gensec_gssapi_wrap: GSS Wrap failed: %s\n",
612 gssapi_error_string(out_mem_ctx, maj_stat, min_stat)));
613 return NT_STATUS_ACCESS_DENIED;
616 *out = data_blob_talloc(out_mem_ctx, output_token.value, output_token.length);
617 gss_release_buffer(&min_stat, &output_token);
619 gensec_gssapi_state->sasl_state = STAGE_SASL_SSF_ACCEPT;
620 return NT_STATUS_MORE_PROCESSING_REQUIRED;
623 return NT_STATUS_INVALID_PARAMETER;
627 /* This is s server-only stage */
628 case STAGE_SASL_SSF_ACCEPT:
630 uint8_t maxlength_proposed[4];
631 uint8_t security_proposed;
634 input_token.length = in.length;
635 input_token.value = in.data;
637 maj_stat = gss_unwrap(&min_stat,
638 gensec_gssapi_state->gssapi_context,
643 if (GSS_ERROR(maj_stat)) {
644 DEBUG(1, ("gensec_gssapi_update: GSS UnWrap of SASL protection negotiation failed: %s\n",
645 gssapi_error_string(out_mem_ctx, maj_stat, min_stat)));
646 return NT_STATUS_ACCESS_DENIED;
649 if (output_token.length < 4) {
650 return NT_STATUS_INVALID_PARAMETER;
653 memcpy(maxlength_proposed, output_token.value, 4);
654 gss_release_buffer(&min_stat, &output_token);
656 /* first byte is the proposed security */
657 /* TODO: We should do something with the rest, but for now... */
658 security_proposed = maxlength_proposed[0];
660 maxlength_proposed[0] = 0x0;
661 gensec_gssapi_state->sasl_protection = 0;
662 if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
663 if (security_proposed & NEG_SEAL) {
664 gensec_gssapi_state->sasl_protection |= NEG_SEAL;
666 } else if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
667 if (security_proposed & NEG_SIGN) {
668 gensec_gssapi_state->sasl_protection |= NEG_SIGN;
670 } else if (security_proposed & NEG_NONE) {
671 gensec_gssapi_state->sasl_protection |= NEG_NONE;
673 DEBUG(1, ("Remote client does not support unprotected connections, but we failed to negotiate anything better"));
674 return NT_STATUS_ACCESS_DENIED;
677 /* quirk: This changes the value that gensec_have_feature returns, to be that after SASL negotiation */
678 gensec_gssapi_state->sasl_state = STAGE_DONE;
679 if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
680 DEBUG(3, ("SASL/GSSAPI Connection from client will be cryptographicly sealed\n"));
681 } else if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
682 DEBUG(3, ("SASL/GSSAPI Connection from client will be cryptographicly signed\n"));
684 DEBUG(3, ("SASL/GSSAPI Connection from client will have no cryptographicly protection\n"));
687 *out = data_blob(NULL, 0);
691 return NT_STATUS_INVALID_PARAMETER;
695 static NTSTATUS gensec_gssapi_wrap(struct gensec_security *gensec_security,
700 struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
701 OM_uint32 maj_stat, min_stat;
702 gss_buffer_desc input_token, output_token;
704 input_token.length = in->length;
705 input_token.value = in->data;
707 maj_stat = gss_wrap(&min_stat,
708 gensec_gssapi_state->gssapi_context,
709 gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL),
714 if (GSS_ERROR(maj_stat)) {
715 DEBUG(1, ("gensec_gssapi_wrap: GSS Wrap failed: %s\n",
716 gssapi_error_string(mem_ctx, maj_stat, min_stat)));
717 return NT_STATUS_ACCESS_DENIED;
720 *out = data_blob_talloc(mem_ctx, output_token.value, output_token.length);
721 gss_release_buffer(&min_stat, &output_token);
723 if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)
725 return NT_STATUS_ACCESS_DENIED;
730 static NTSTATUS gensec_gssapi_unwrap(struct gensec_security *gensec_security,
735 struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
736 OM_uint32 maj_stat, min_stat;
737 gss_buffer_desc input_token, output_token;
740 input_token.length = in->length;
741 input_token.value = in->data;
743 maj_stat = gss_unwrap(&min_stat,
744 gensec_gssapi_state->gssapi_context,
749 if (GSS_ERROR(maj_stat)) {
750 DEBUG(1, ("gensec_gssapi_unwrap: GSS UnWrap failed: %s\n",
751 gssapi_error_string(mem_ctx, maj_stat, min_stat)));
752 return NT_STATUS_ACCESS_DENIED;
755 *out = data_blob_talloc(mem_ctx, output_token.value, output_token.length);
756 gss_release_buffer(&min_stat, &output_token);
758 if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)
760 return NT_STATUS_ACCESS_DENIED;
765 /* Find out the size of the signature, assuming (incorrectly) that it
766 * GSSAPI provides any guarantees as to it's size.
768 * This is needed by the DCE/RPC code, which uses AEAD
769 * (signed headers, including signature legnth and a sealed body)
771 static size_t gensec_gssapi_sig_size(struct gensec_security *gensec_security, size_t data_size)
773 struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
774 OM_uint32 maj_stat, min_stat;
775 OM_uint32 output_size;
776 if ((gensec_gssapi_state->gss_oid->length != gss_mech_krb5->length)
777 || (memcmp(gensec_gssapi_state->gss_oid->elements, gss_mech_krb5->elements,
778 gensec_gssapi_state->gss_oid->length) != 0)) {
779 DEBUG(1, ("NO sig size available for this mech\n"));
783 maj_stat = gsskrb5_wrap_size(&min_stat,
784 gensec_gssapi_state->gssapi_context,
785 gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL),
789 if (GSS_ERROR(maj_stat)) {
790 TALLOC_CTX *mem_ctx = talloc_new(NULL);
791 DEBUG(1, ("gensec_gssapi_seal_packet: determinaing signature size with gss_wrap_size_limit failed: %s\n",
792 gssapi_error_string(mem_ctx, maj_stat, min_stat)));
793 talloc_free(mem_ctx);
797 if (output_size < data_size) {
801 /* The difference between the max output and the max input must be the signature */
802 return output_size - data_size;
805 static NTSTATUS gensec_gssapi_seal_packet(struct gensec_security *gensec_security,
807 uint8_t *data, size_t length,
808 const uint8_t *whole_pdu, size_t pdu_length,
811 struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
812 OM_uint32 maj_stat, min_stat;
813 gss_buffer_desc input_token, output_token;
817 input_token.length = length;
818 input_token.value = data;
820 maj_stat = gss_wrap(&min_stat,
821 gensec_gssapi_state->gssapi_context,
822 gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL),
827 if (GSS_ERROR(maj_stat)) {
828 DEBUG(1, ("gensec_gssapi_seal_packet: GSS Wrap failed: %s\n",
829 gssapi_error_string(mem_ctx, maj_stat, min_stat)));
830 return NT_STATUS_ACCESS_DENIED;
833 sig_length = gensec_gssapi_sig_size(gensec_security, length);
835 /* Caller must pad to right boundary */
836 if (output_token.length != (length + sig_length)) {
837 DEBUG(1, ("gensec_gssapi_seal_packet: GSS Wrap length [%ld] does not match caller length [%ld] plus sig size [%ld] = [%ld]\n",
838 (long)output_token.length, (long)length, (long)sig_length, (long)(length + sig_length)));
839 return NT_STATUS_INTERNAL_ERROR;
842 memcpy(data, ((uint8_t *)output_token.value) + sig_length, length);
843 *sig = data_blob_talloc(mem_ctx, (uint8_t *)output_token.value, sig_length);
845 dump_data_pw("gensec_gssapi_seal_packet: sig\n", sig->data, sig->length);
846 dump_data_pw("gensec_gssapi_seal_packet: clear\n", data, length);
847 dump_data_pw("gensec_gssapi_seal_packet: sealed\n", ((uint8_t *)output_token.value) + sig_length, output_token.length - sig_length);
849 gss_release_buffer(&min_stat, &output_token);
851 if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)
853 return NT_STATUS_ACCESS_DENIED;
858 static NTSTATUS gensec_gssapi_unseal_packet(struct gensec_security *gensec_security,
860 uint8_t *data, size_t length,
861 const uint8_t *whole_pdu, size_t pdu_length,
862 const DATA_BLOB *sig)
864 struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
865 OM_uint32 maj_stat, min_stat;
866 gss_buffer_desc input_token, output_token;
871 dump_data_pw("gensec_gssapi_unseal_packet: sig\n", sig->data, sig->length);
873 in = data_blob_talloc(mem_ctx, NULL, sig->length + length);
875 memcpy(in.data, sig->data, sig->length);
876 memcpy(in.data + sig->length, data, length);
878 input_token.length = in.length;
879 input_token.value = in.data;
881 maj_stat = gss_unwrap(&min_stat,
882 gensec_gssapi_state->gssapi_context,
887 if (GSS_ERROR(maj_stat)) {
888 DEBUG(1, ("gensec_gssapi_unseal_packet: GSS UnWrap failed: %s\n",
889 gssapi_error_string(mem_ctx, maj_stat, min_stat)));
890 return NT_STATUS_ACCESS_DENIED;
893 if (output_token.length != length) {
894 return NT_STATUS_INTERNAL_ERROR;
897 memcpy(data, output_token.value, length);
899 gss_release_buffer(&min_stat, &output_token);
901 if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)
903 return NT_STATUS_ACCESS_DENIED;
908 static NTSTATUS gensec_gssapi_sign_packet(struct gensec_security *gensec_security,
910 const uint8_t *data, size_t length,
911 const uint8_t *whole_pdu, size_t pdu_length,
914 struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
915 OM_uint32 maj_stat, min_stat;
916 gss_buffer_desc input_token, output_token;
918 ssize_t sig_length = 0;
920 input_token.length = length;
921 input_token.value = discard_const_p(uint8_t *, data);
923 maj_stat = gss_wrap(&min_stat,
924 gensec_gssapi_state->gssapi_context,
930 if (GSS_ERROR(maj_stat)) {
931 DEBUG(1, ("GSS Wrap failed: %s\n",
932 gssapi_error_string(mem_ctx, maj_stat, min_stat)));
933 return NT_STATUS_ACCESS_DENIED;
936 if (output_token.length < length) {
937 return NT_STATUS_INTERNAL_ERROR;
940 sig_length = gensec_gssapi_sig_size(gensec_security, length);
942 /* Caller must pad to right boundary */
943 if (output_token.length != (length + sig_length)) {
944 DEBUG(1, ("gensec_gssapi_sign_packet: GSS Wrap length [%ld] does not match caller length [%ld] plus sig size [%ld] = [%ld]\n",
945 (long)output_token.length, (long)length, (long)sig_length, (long)(length + sig_length)));
946 return NT_STATUS_INTERNAL_ERROR;
949 *sig = data_blob_talloc(mem_ctx, (uint8_t *)output_token.value, sig_length);
951 dump_data_pw("gensec_gssapi_seal_packet: sig\n", sig->data, sig->length);
953 gss_release_buffer(&min_stat, &output_token);
958 static NTSTATUS gensec_gssapi_check_packet(struct gensec_security *gensec_security,
960 const uint8_t *data, size_t length,
961 const uint8_t *whole_pdu, size_t pdu_length,
962 const DATA_BLOB *sig)
964 struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
965 OM_uint32 maj_stat, min_stat;
966 gss_buffer_desc input_token, output_token;
971 dump_data_pw("gensec_gssapi_seal_packet: sig\n", sig->data, sig->length);
973 in = data_blob_talloc(mem_ctx, NULL, sig->length + length);
975 memcpy(in.data, sig->data, sig->length);
976 memcpy(in.data + sig->length, data, length);
978 input_token.length = in.length;
979 input_token.value = in.data;
981 maj_stat = gss_unwrap(&min_stat,
982 gensec_gssapi_state->gssapi_context,
987 if (GSS_ERROR(maj_stat)) {
988 DEBUG(1, ("GSS UnWrap failed: %s\n",
989 gssapi_error_string(mem_ctx, maj_stat, min_stat)));
990 return NT_STATUS_ACCESS_DENIED;
993 if (output_token.length != length) {
994 return NT_STATUS_INTERNAL_ERROR;
997 gss_release_buffer(&min_stat, &output_token);
1002 /* Try to figure out what features we actually got on the connection */
1003 static BOOL gensec_gssapi_have_feature(struct gensec_security *gensec_security,
1006 struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
1007 if (feature & GENSEC_FEATURE_SIGN) {
1008 /* If we are going GSSAPI SASL, then we honour the second negotiation */
1009 if (gensec_gssapi_state->sasl
1010 && gensec_gssapi_state->sasl_state == STAGE_DONE) {
1011 return ((gensec_gssapi_state->sasl_protection & NEG_SIGN)
1012 && (gensec_gssapi_state->got_flags & GSS_C_INTEG_FLAG));
1014 return gensec_gssapi_state->got_flags & GSS_C_INTEG_FLAG;
1016 if (feature & GENSEC_FEATURE_SEAL) {
1017 /* If we are going GSSAPI SASL, then we honour the second negotiation */
1018 if (gensec_gssapi_state->sasl
1019 && gensec_gssapi_state->sasl_state == STAGE_DONE) {
1020 return ((gensec_gssapi_state->sasl_protection & NEG_SEAL)
1021 && (gensec_gssapi_state->got_flags & GSS_C_CONF_FLAG));
1023 return gensec_gssapi_state->got_flags & GSS_C_CONF_FLAG;
1025 if (feature & GENSEC_FEATURE_SESSION_KEY) {
1026 /* Only for GSSAPI/Krb5 */
1027 if ((gensec_gssapi_state->gss_oid->length == gss_mech_krb5->length)
1028 && (memcmp(gensec_gssapi_state->gss_oid->elements, gss_mech_krb5->elements, gensec_gssapi_state->gss_oid->length) == 0)) {
1032 if (feature & GENSEC_FEATURE_DCE_STYLE) {
1033 return gensec_gssapi_state->got_flags & GSS_C_DCE_STYLE;
1035 /* We can always do async (rather than strict request/reply) packets. */
1036 if (feature & GENSEC_FEATURE_ASYNC_REPLIES) {
1043 * Extract the 'sesssion key' needed by SMB signing and ncacn_np
1044 * (for encrypting some passwords).
1046 * This breaks all the abstractions, but what do you expect...
1048 static NTSTATUS gensec_gssapi_session_key(struct gensec_security *gensec_security,
1049 DATA_BLOB *session_key)
1051 struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
1053 if (gensec_gssapi_state->session_key.data) {
1054 *session_key = gensec_gssapi_state->session_key;
1055 return NT_STATUS_OK;
1058 /* Ensure we only call this for GSSAPI/krb5, otherwise things
1059 * could get very ugly */
1060 if ((gensec_gssapi_state->gss_oid->length == gss_mech_krb5->length)
1061 && (memcmp(gensec_gssapi_state->gss_oid->elements, gss_mech_krb5->elements,
1062 gensec_gssapi_state->gss_oid->length) == 0)) {
1063 OM_uint32 maj_stat, min_stat;
1064 gss_buffer_desc skey;
1066 maj_stat = gsskrb5_get_initiator_subkey(&min_stat,
1067 gensec_gssapi_state->gssapi_context,
1070 if (maj_stat == 0) {
1071 DEBUG(10, ("Got KRB5 session key of length %d\n",
1073 gensec_gssapi_state->session_key = data_blob_talloc(gensec_gssapi_state,
1074 skey.value, skey.length);
1075 *session_key = gensec_gssapi_state->session_key;
1076 dump_data_pw("KRB5 Session Key:\n", session_key->data, session_key->length);
1078 gss_release_buffer(&min_stat, &skey);
1079 return NT_STATUS_OK;
1081 return NT_STATUS_NO_USER_SESSION_KEY;
1084 DEBUG(1, ("NO session key for this mech\n"));
1085 return NT_STATUS_NO_USER_SESSION_KEY;
1089 /* Get some basic (and authorization) information about the user on
1090 * this session. This uses either the PAC (if present) or a local
1091 * database lookup */
1092 static NTSTATUS gensec_gssapi_session_info(struct gensec_security *gensec_security,
1093 struct auth_session_info **_session_info)
1096 TALLOC_CTX *mem_ctx;
1097 struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
1098 struct auth_serversupplied_info *server_info = NULL;
1099 struct auth_session_info *session_info = NULL;
1100 struct PAC_LOGON_INFO *logon_info;
1101 OM_uint32 maj_stat, min_stat;
1102 gss_buffer_desc name_token;
1103 gss_buffer_desc pac;
1104 krb5_keyblock *keyblock;
1106 krb5_principal principal;
1107 char *principal_string;
1110 if ((gensec_gssapi_state->gss_oid->length != gss_mech_krb5->length)
1111 || (memcmp(gensec_gssapi_state->gss_oid->elements, gss_mech_krb5->elements,
1112 gensec_gssapi_state->gss_oid->length) != 0)) {
1113 DEBUG(1, ("NO session info available for this mech\n"));
1114 return NT_STATUS_INVALID_PARAMETER;
1117 mem_ctx = talloc_named(gensec_gssapi_state, 0, "gensec_gssapi_session_info context");
1118 NT_STATUS_HAVE_NO_MEMORY(mem_ctx);
1120 maj_stat = gss_display_name (&min_stat,
1121 gensec_gssapi_state->client_name,
1125 talloc_free(mem_ctx);
1126 return NT_STATUS_FOOBAR;
1129 principal_string = talloc_strndup(mem_ctx, name_token.value, name_token.length);
1131 gss_release_buffer(&min_stat, &name_token);
1133 if (!principal_string) {
1134 talloc_free(mem_ctx);
1135 return NT_STATUS_NO_MEMORY;
1138 maj_stat = gss_krb5_copy_service_keyblock(&min_stat,
1139 gensec_gssapi_state->gssapi_context,
1142 if (maj_stat == 0) {
1143 maj_stat = gsskrb5_extract_authtime_from_sec_context(&min_stat,
1144 gensec_gssapi_state->gssapi_context,
1148 if (maj_stat == 0) {
1149 maj_stat = gsskrb5_extract_authz_data_from_sec_context(&min_stat,
1150 gensec_gssapi_state->gssapi_context,
1151 KRB5_AUTHDATA_WIN2K_PAC,
1155 if (maj_stat == 0) {
1156 pac_blob = data_blob_talloc(mem_ctx, pac.value, pac.length);
1157 gss_release_buffer(&min_stat, &pac);
1160 /* IF we have the PAC - otherwise we need to get this
1161 * data from elsewere - local ldb, or (TODO) lookup of some
1164 if (maj_stat == 0) {
1165 krb5_error_code ret;
1167 ret = krb5_parse_name(gensec_gssapi_state->smb_krb5_context->krb5_context,
1168 principal_string, &principal);
1170 talloc_free(mem_ctx);
1171 return NT_STATUS_INVALID_PARAMETER;
1174 /* decode and verify the pac */
1175 nt_status = kerberos_pac_logon_info(mem_ctx, &logon_info, pac_blob,
1176 gensec_gssapi_state->smb_krb5_context->krb5_context,
1177 NULL, keyblock, principal, authtime, NULL);
1178 krb5_free_principal(gensec_gssapi_state->smb_krb5_context->krb5_context, principal);
1180 if (NT_STATUS_IS_OK(nt_status)) {
1181 union netr_Validation validation;
1182 validation.sam3 = &logon_info->info3;
1183 nt_status = make_server_info_netlogon_validation(gensec_gssapi_state,
1187 if (!NT_STATUS_IS_OK(nt_status)) {
1188 talloc_free(mem_ctx);
1197 DEBUG(1, ("Unable to use PAC, resorting to local user lookup!\n"));
1198 nt_status = sam_get_server_info_principal(mem_ctx, principal_string,
1201 if (!NT_STATUS_IS_OK(nt_status)) {
1202 talloc_free(mem_ctx);
1207 /* references the server_info into the session_info */
1208 nt_status = auth_generate_session_info(mem_ctx, server_info, &session_info);
1209 if (!NT_STATUS_IS_OK(nt_status)) {
1210 talloc_free(mem_ctx);
1214 nt_status = gensec_gssapi_session_key(gensec_security, &session_info->session_key);
1215 if (!NT_STATUS_IS_OK(nt_status)) {
1216 talloc_free(mem_ctx);
1220 if (!(gensec_gssapi_state->got_flags & GSS_C_DELEG_FLAG)) {
1221 DEBUG(10, ("gensec_gssapi: NO delegated credentials supplied by client\n"));
1223 krb5_error_code ret;
1224 DEBUG(10, ("gensec_gssapi: delegated credentials supplied by client\n"));
1225 session_info->credentials = cli_credentials_init(session_info);
1226 if (!session_info->credentials) {
1227 talloc_free(mem_ctx);
1228 return NT_STATUS_NO_MEMORY;
1231 cli_credentials_set_conf(session_info->credentials);
1233 ret = cli_credentials_set_client_gss_creds(session_info->credentials,
1234 gensec_gssapi_state->delegated_cred_handle,
1237 talloc_free(mem_ctx);
1238 return NT_STATUS_NO_MEMORY;
1240 /* It has been taken from this place... */
1241 gensec_gssapi_state->delegated_cred_handle = GSS_C_NO_CREDENTIAL;
1243 talloc_steal(gensec_gssapi_state, session_info);
1244 talloc_free(mem_ctx);
1245 *_session_info = session_info;
1247 return NT_STATUS_OK;
1250 static const char *gensec_gssapi_krb5_oids[] = {
1251 GENSEC_OID_KERBEROS5,
1252 GENSEC_OID_KERBEROS5_OLD,
1256 /* As a server, this could in theory accept any GSSAPI mech */
1257 static const struct gensec_security_ops gensec_gssapi_krb5_security_ops = {
1258 .name = "gssapi_krb5",
1259 .auth_type = DCERPC_AUTH_TYPE_KRB5,
1260 .oid = gensec_gssapi_krb5_oids,
1261 .client_start = gensec_gssapi_client_start,
1262 .server_start = gensec_gssapi_server_start,
1263 .magic = gensec_gssapi_magic,
1264 .update = gensec_gssapi_update,
1265 .session_key = gensec_gssapi_session_key,
1266 .session_info = gensec_gssapi_session_info,
1267 .sig_size = gensec_gssapi_sig_size,
1268 .sign_packet = gensec_gssapi_sign_packet,
1269 .check_packet = gensec_gssapi_check_packet,
1270 .seal_packet = gensec_gssapi_seal_packet,
1271 .unseal_packet = gensec_gssapi_unseal_packet,
1272 .wrap = gensec_gssapi_wrap,
1273 .unwrap = gensec_gssapi_unwrap,
1274 .have_feature = gensec_gssapi_have_feature,
1279 /* As a server, this could in theory accept any GSSAPI mech */
1280 static const struct gensec_security_ops gensec_gssapi_sasl_krb5_security_ops = {
1281 .name = "gssapi_krb5_sasl",
1282 .sasl_name = "GSSAPI",
1283 .client_start = gensec_gssapi_sasl_client_start,
1284 .server_start = gensec_gssapi_sasl_server_start,
1285 .update = gensec_gssapi_update,
1286 .session_key = gensec_gssapi_session_key,
1287 .session_info = gensec_gssapi_session_info,
1288 .wrap = gensec_gssapi_wrap,
1289 .unwrap = gensec_gssapi_unwrap,
1290 .have_feature = gensec_gssapi_have_feature,
1295 NTSTATUS gensec_gssapi_init(void)
1299 ret = gensec_register(&gensec_gssapi_krb5_security_ops);
1300 if (!NT_STATUS_IS_OK(ret)) {
1301 DEBUG(0,("Failed to register '%s' gensec backend!\n",
1302 gensec_gssapi_krb5_security_ops.name));
1306 ret = gensec_register(&gensec_gssapi_sasl_krb5_security_ops);
1307 if (!NT_STATUS_IS_OK(ret)) {
1308 DEBUG(0,("Failed to register '%s' gensec backend!\n",
1309 gensec_gssapi_sasl_krb5_security_ops.name));