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/krb5pac.h"
29 #include "auth/auth.h"
30 #include "lib/ldb/include/ldb.h"
31 #include "auth/auth_sam.h"
32 #include "librpc/rpc/dcerpc.h"
34 enum gensec_gssapi_sasl_state
38 STAGE_SASL_SSF_ACCEPT,
46 struct gensec_gssapi_state {
47 gss_ctx_id_t gssapi_context;
48 struct gss_channel_bindings_struct *input_chan_bindings;
49 gss_name_t server_name;
50 gss_name_t client_name;
51 OM_uint32 want_flags, got_flags;
52 const gss_OID_desc *gss_oid;
54 DATA_BLOB session_key;
57 struct smb_krb5_context *smb_krb5_context;
58 struct gssapi_creds_container *client_cred;
59 struct gssapi_creds_container *server_cred;
61 gss_cred_id_t delegated_cred_handle;
63 BOOL sasl; /* We have two different mechs in this file: One
64 * for SASL wrapped GSSAPI and another for normal
66 enum gensec_gssapi_sasl_state sasl_state;
67 uint8_t sasl_protection; /* What was negotiated at the SASL
68 * layer, independent of the GSSAPI
72 static char *gssapi_error_string(TALLOC_CTX *mem_ctx,
73 OM_uint32 maj_stat, OM_uint32 min_stat)
75 OM_uint32 disp_min_stat, disp_maj_stat;
76 gss_buffer_desc maj_error_message;
77 gss_buffer_desc min_error_message;
78 OM_uint32 msg_ctx = 0;
82 maj_error_message.value = NULL;
83 min_error_message.value = NULL;
85 disp_maj_stat = gss_display_status(&disp_min_stat, maj_stat, GSS_C_GSS_CODE,
86 GSS_C_NULL_OID, &msg_ctx, &maj_error_message);
87 disp_maj_stat = gss_display_status(&disp_min_stat, min_stat, GSS_C_MECH_CODE,
88 GSS_C_NULL_OID, &msg_ctx, &min_error_message);
89 ret = talloc_asprintf(mem_ctx, "%s: %s", (char *)maj_error_message.value, (char *)min_error_message.value);
91 gss_release_buffer(&disp_min_stat, &maj_error_message);
92 gss_release_buffer(&disp_min_stat, &min_error_message);
98 static int gensec_gssapi_destory(struct gensec_gssapi_state *gensec_gssapi_state)
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 (strcmp(hostname, "localhost") == 0) {
255 DEBUG(2, ("GSSAPI to 'localhost' does not make sense\n"));
256 return NT_STATUS_INVALID_PARAMETER;
259 if (((gensec_security->want_features & GENSEC_FEATURE_SIGN)
260 || (gensec_security->want_features & GENSEC_FEATURE_SEAL))
261 && (gensec_security->want_features & GENSEC_FEATURE_DCE_STYLE)
262 && !lp_parm_bool(-1, "gensec_gssapi", "dce_signseal",
263 cli_credentials_get_kerberos_state(creds) == CRED_MUST_USE_KERBEROS)) {
264 DEBUG(2, ("GSSAPI sign/seal disabled for DCE/RPC. "));
265 return NT_STATUS_INVALID_PARAMETER;
268 nt_status = gensec_gssapi_start(gensec_security);
269 if (!NT_STATUS_IS_OK(nt_status)) {
273 gensec_gssapi_state = talloc_get_type(gensec_security->private_data, struct gensec_gssapi_state);
275 principal = gensec_get_target_principal(gensec_security);
276 if (principal && lp_client_use_spnego_principal()) {
277 name_token.value = discard_const_p(uint8_t, principal);
278 name_token.length = strlen(principal);
280 name_type = GSS_C_NULL_OID;
282 principal = talloc_asprintf(gensec_gssapi_state, "%s@%s",
283 gensec_get_target_service(gensec_security),
286 name_token.value = discard_const_p(uint8_t, principal);
287 name_token.length = strlen(principal);
289 name_type = GSS_C_NT_HOSTBASED_SERVICE;
292 maj_stat = gss_import_name (&min_stat,
295 &gensec_gssapi_state->server_name);
297 DEBUG(2, ("GSS Import name of %s failed: %s\n",
298 (char *)name_token.value,
299 gssapi_error_string(gensec_gssapi_state, maj_stat, min_stat)));
300 return NT_STATUS_INVALID_PARAMETER;
303 ret = cli_credentials_get_client_gss_creds(creds, &gcc);
307 case KRB5_KDC_UNREACH:
308 DEBUG(3, ("Cannot reach a KDC we require\n"));
309 return NT_STATUS_INVALID_PARAMETER; /* Make SPNEGO ignore us, we can't go any further here */
311 DEBUG(1, ("Aquiring initiator credentails failed\n"));
312 return NT_STATUS_UNSUCCESSFUL;
315 gensec_gssapi_state->client_cred = gcc;
320 static NTSTATUS gensec_gssapi_sasl_client_start(struct gensec_security *gensec_security)
323 struct gensec_gssapi_state *gensec_gssapi_state;
324 nt_status = gensec_gssapi_client_start(gensec_security);
326 if (NT_STATUS_IS_OK(nt_status)) {
327 gensec_gssapi_state = talloc_get_type(gensec_security->private_data, struct gensec_gssapi_state);
328 gensec_gssapi_state->sasl = True;
335 * Check if the packet is one for this mechansim
337 * @param gensec_security GENSEC state
338 * @param in The request, as a DATA_BLOB
339 * @return Error, INVALID_PARAMETER if it's not a packet for us
340 * or NT_STATUS_OK if the packet is ok.
343 static NTSTATUS gensec_gssapi_magic(struct gensec_security *gensec_security,
346 if (gensec_gssapi_check_oid(in, GENSEC_OID_KERBEROS5)) {
349 return NT_STATUS_INVALID_PARAMETER;
355 * Next state function for the GSSAPI GENSEC mechanism
357 * @param gensec_gssapi_state GSSAPI State
358 * @param out_mem_ctx The TALLOC_CTX for *out to be allocated on
359 * @param in The request, as a DATA_BLOB
360 * @param out The reply, as an talloc()ed DATA_BLOB, on *out_mem_ctx
361 * @return Error, MORE_PROCESSING_REQUIRED if a reply is sent,
362 * or NT_STATUS_OK if the user is authenticated.
365 static NTSTATUS gensec_gssapi_update(struct gensec_security *gensec_security,
366 TALLOC_CTX *out_mem_ctx,
367 const DATA_BLOB in, DATA_BLOB *out)
369 struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
370 NTSTATUS nt_status = NT_STATUS_LOGON_FAILURE;
371 OM_uint32 maj_stat, min_stat;
373 gss_buffer_desc input_token, output_token;
375 input_token.length = in.length;
376 input_token.value = in.data;
378 switch (gensec_gssapi_state->sasl_state) {
381 switch (gensec_security->gensec_role) {
384 maj_stat = gss_init_sec_context(&min_stat,
385 gensec_gssapi_state->client_cred->creds,
386 &gensec_gssapi_state->gssapi_context,
387 gensec_gssapi_state->server_name,
388 discard_const_p(gss_OID_desc, gensec_gssapi_state->gss_oid),
389 gensec_gssapi_state->want_flags,
391 gensec_gssapi_state->input_chan_bindings,
395 &gensec_gssapi_state->got_flags, /* ret flags */
401 maj_stat = gss_accept_sec_context(&min_stat,
402 &gensec_gssapi_state->gssapi_context,
403 gensec_gssapi_state->server_cred->creds,
405 gensec_gssapi_state->input_chan_bindings,
406 &gensec_gssapi_state->client_name,
409 &gensec_gssapi_state->got_flags,
411 &gensec_gssapi_state->delegated_cred_handle);
412 gensec_gssapi_state->gss_oid = gss_oid_p;
416 return NT_STATUS_INVALID_PARAMETER;
420 if (maj_stat == GSS_S_COMPLETE) {
421 *out = data_blob_talloc(out_mem_ctx, output_token.value, output_token.length);
422 gss_release_buffer(&min_stat2, &output_token);
424 if (gensec_gssapi_state->got_flags & GSS_C_DELEG_FLAG) {
425 DEBUG(5, ("gensec_gssapi: credentials were delegated\n"));
427 DEBUG(5, ("gensec_gssapi: NO credentials were delegated\n"));
430 /* We may have been invoked as SASL, so there
431 * is more work to do */
432 if (gensec_gssapi_state->sasl) {
433 /* Due to a very subtle interaction
434 * with SASL and the LDAP libs, we
435 * must ensure the data pointer is
436 * != NULL, but the length is 0.
438 * This ensures we send a 'zero
439 * length' (rather than NULL) response
443 out->data = (uint8_t *)talloc_strdup(out_mem_ctx, "\0");
446 gensec_gssapi_state->sasl_state = STAGE_SASL_SSF_NEG;
447 return NT_STATUS_MORE_PROCESSING_REQUIRED;
449 gensec_gssapi_state->sasl_state = STAGE_DONE;
451 if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
452 DEBUG(5, ("GSSAPI Connection will be cryptographicly sealed\n"));
453 } else if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
454 DEBUG(5, ("GSSAPI Connection will be cryptographicly signed\n"));
456 DEBUG(5, ("GSSAPI Connection will have no cryptographic protection\n"));
461 } else if (maj_stat == GSS_S_CONTINUE_NEEDED) {
462 *out = data_blob_talloc(out_mem_ctx, output_token.value, output_token.length);
463 gss_release_buffer(&min_stat2, &output_token);
465 return NT_STATUS_MORE_PROCESSING_REQUIRED;
466 } else if ((gensec_gssapi_state->gss_oid->length == gss_mech_krb5->length)
467 && (memcmp(gensec_gssapi_state->gss_oid->elements, gss_mech_krb5->elements,
468 gensec_gssapi_state->gss_oid->length) == 0)) {
470 case KRB5_KDC_UNREACH:
471 DEBUG(3, ("Cannot reach a KDC we require: %s\n",
472 gssapi_error_string(gensec_gssapi_state, maj_stat, min_stat)));
473 return NT_STATUS_INVALID_PARAMETER; /* Make SPNEGO ignore us, we can't go any further here */
474 case KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN:
475 DEBUG(3, ("Server is not registered with our KDC: %s\n",
476 gssapi_error_string(gensec_gssapi_state, maj_stat, min_stat)));
477 return NT_STATUS_INVALID_PARAMETER; /* Make SPNEGO ignore us, we can't go any further here */
478 case KRB5KRB_AP_ERR_MSG_TYPE:
479 /* garbage input, possibly from the auto-mech detection */
480 return NT_STATUS_INVALID_PARAMETER;
482 DEBUG(1, ("GSS(krb5) Update failed: %s\n",
483 gssapi_error_string(out_mem_ctx, maj_stat, min_stat)));
487 DEBUG(1, ("GSS Update failed: %s\n",
488 gssapi_error_string(out_mem_ctx, maj_stat, min_stat)));
493 /* These last two stages are only done if we were invoked as SASL */
494 case STAGE_SASL_SSF_NEG:
496 switch (gensec_security->gensec_role) {
499 uint8_t maxlength_proposed[4];
500 uint8_t security_supported;
503 input_token.length = in.length;
504 input_token.value = in.data;
506 maj_stat = gss_unwrap(&min_stat,
507 gensec_gssapi_state->gssapi_context,
512 if (GSS_ERROR(maj_stat)) {
513 DEBUG(1, ("gensec_gssapi_update: GSS UnWrap of SASL protection negotiation failed: %s\n",
514 gssapi_error_string(out_mem_ctx, maj_stat, min_stat)));
515 return NT_STATUS_ACCESS_DENIED;
518 if (output_token.length < 4) {
519 return NT_STATUS_INVALID_PARAMETER;
522 memcpy(maxlength_proposed, output_token.value, 4);
523 gss_release_buffer(&min_stat, &output_token);
525 /* first byte is the proposed security */
526 security_supported = maxlength_proposed[0];
527 maxlength_proposed[0] = '\0';
528 gensec_gssapi_state->sasl_protection = 0;
529 if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
530 if (security_supported & NEG_SEAL) {
531 gensec_gssapi_state->sasl_protection |= NEG_SEAL;
533 } else if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
534 if (security_supported & NEG_SIGN) {
535 gensec_gssapi_state->sasl_protection |= NEG_SIGN;
537 } else if (security_supported & NEG_NONE) {
538 gensec_gssapi_state->sasl_protection |= NEG_NONE;
540 DEBUG(1, ("Remote server does not support unprotected connections"));
541 return NT_STATUS_ACCESS_DENIED;
544 /* We just accept their max length, and send
545 * it back with the SASL flags */
546 maxlength_proposed[0] = gensec_gssapi_state->sasl_protection;
548 input_token.value = maxlength_proposed;
549 input_token.length = sizeof(maxlength_proposed);
551 maj_stat = gss_wrap(&min_stat,
552 gensec_gssapi_state->gssapi_context,
558 if (GSS_ERROR(maj_stat)) {
559 DEBUG(1, ("gensec_gssapi_wrap: GSS Wrap failed: %s\n",
560 gssapi_error_string(out_mem_ctx, maj_stat, min_stat)));
561 return NT_STATUS_ACCESS_DENIED;
564 *out = data_blob_talloc(out_mem_ctx, output_token.value, output_token.length);
565 gss_release_buffer(&min_stat, &output_token);
567 /* quirk: This changes the value that gensec_have_feature returns, to be that after SASL negotiation */
568 gensec_gssapi_state->sasl_state = STAGE_DONE;
570 if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
571 DEBUG(3, ("SASL/GSSAPI Connection to server will be cryptographicly sealed\n"));
572 } else if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
573 DEBUG(3, ("SASL/GSSAPI Connection to server will be cryptographicly signed\n"));
575 DEBUG(3, ("SASL/GSSAPI Connection to server will have no cryptographicly protection\n"));
582 uint8_t maxlength_proposed[4];
583 uint8_t security_supported = 0x0;
586 /* TODO: Need some better ideas for this */
587 RSIVAL(maxlength_proposed, 0, 0xFFFFFF);
588 /* first byte is the proposed security */
589 maxlength_proposed[0] = '\0';
591 gensec_gssapi_state->sasl_protection = 0;
592 if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
593 security_supported |= NEG_SEAL;
595 if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
596 security_supported |= NEG_SIGN;
598 if (security_supported == 0) {
599 /* If we don't support anything, this must be 0 */
600 RSIVAL(maxlength_proposed, 0, 0x0);
603 /* TODO: We may not wish to support this */
604 security_supported |= NEG_NONE;
607 maxlength_proposed[0] = security_supported;
609 input_token.value = maxlength_proposed;
610 input_token.length = sizeof(maxlength_proposed);
612 maj_stat = gss_wrap(&min_stat,
613 gensec_gssapi_state->gssapi_context,
619 if (GSS_ERROR(maj_stat)) {
620 DEBUG(1, ("gensec_gssapi_wrap: GSS Wrap failed: %s\n",
621 gssapi_error_string(out_mem_ctx, maj_stat, min_stat)));
622 return NT_STATUS_ACCESS_DENIED;
625 *out = data_blob_talloc(out_mem_ctx, output_token.value, output_token.length);
626 gss_release_buffer(&min_stat, &output_token);
628 gensec_gssapi_state->sasl_state = STAGE_SASL_SSF_ACCEPT;
629 return NT_STATUS_MORE_PROCESSING_REQUIRED;
632 return NT_STATUS_INVALID_PARAMETER;
636 /* This is s server-only stage */
637 case STAGE_SASL_SSF_ACCEPT:
639 uint8_t maxlength_proposed[4];
640 uint8_t security_proposed;
643 input_token.length = in.length;
644 input_token.value = in.data;
646 maj_stat = gss_unwrap(&min_stat,
647 gensec_gssapi_state->gssapi_context,
652 if (GSS_ERROR(maj_stat)) {
653 DEBUG(1, ("gensec_gssapi_update: GSS UnWrap of SASL protection negotiation failed: %s\n",
654 gssapi_error_string(out_mem_ctx, maj_stat, min_stat)));
655 return NT_STATUS_ACCESS_DENIED;
658 if (output_token.length < 4) {
659 return NT_STATUS_INVALID_PARAMETER;
662 memcpy(maxlength_proposed, output_token.value, 4);
663 gss_release_buffer(&min_stat, &output_token);
665 /* first byte is the proposed security */
666 /* TODO: We should do something with the rest, but for now... */
667 security_proposed = maxlength_proposed[0];
669 maxlength_proposed[0] = 0x0;
670 gensec_gssapi_state->sasl_protection = 0;
671 if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
672 if (security_proposed & NEG_SEAL) {
673 gensec_gssapi_state->sasl_protection |= NEG_SEAL;
675 } else if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
676 if (security_proposed & NEG_SIGN) {
677 gensec_gssapi_state->sasl_protection |= NEG_SIGN;
679 } else if (security_proposed & NEG_NONE) {
680 gensec_gssapi_state->sasl_protection |= NEG_NONE;
682 DEBUG(1, ("Remote client does not support unprotected connections, but we failed to negotiate anything better"));
683 return NT_STATUS_ACCESS_DENIED;
686 /* quirk: This changes the value that gensec_have_feature returns, to be that after SASL negotiation */
687 gensec_gssapi_state->sasl_state = STAGE_DONE;
688 if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
689 DEBUG(5, ("SASL/GSSAPI Connection from client will be cryptographicly sealed\n"));
690 } else if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
691 DEBUG(5, ("SASL/GSSAPI Connection from client will be cryptographicly signed\n"));
693 DEBUG(5, ("SASL/GSSAPI Connection from client will have no cryptographic protection\n"));
696 *out = data_blob(NULL, 0);
700 return NT_STATUS_INVALID_PARAMETER;
704 static NTSTATUS gensec_gssapi_wrap(struct gensec_security *gensec_security,
709 struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
710 OM_uint32 maj_stat, min_stat;
711 gss_buffer_desc input_token, output_token;
713 input_token.length = in->length;
714 input_token.value = in->data;
716 maj_stat = gss_wrap(&min_stat,
717 gensec_gssapi_state->gssapi_context,
718 gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL),
723 if (GSS_ERROR(maj_stat)) {
724 DEBUG(1, ("gensec_gssapi_wrap: GSS Wrap failed: %s\n",
725 gssapi_error_string(mem_ctx, maj_stat, min_stat)));
726 return NT_STATUS_ACCESS_DENIED;
729 *out = data_blob_talloc(mem_ctx, output_token.value, output_token.length);
730 gss_release_buffer(&min_stat, &output_token);
732 if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)
734 return NT_STATUS_ACCESS_DENIED;
739 static NTSTATUS gensec_gssapi_unwrap(struct gensec_security *gensec_security,
744 struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
745 OM_uint32 maj_stat, min_stat;
746 gss_buffer_desc input_token, output_token;
749 input_token.length = in->length;
750 input_token.value = in->data;
752 maj_stat = gss_unwrap(&min_stat,
753 gensec_gssapi_state->gssapi_context,
758 if (GSS_ERROR(maj_stat)) {
759 DEBUG(1, ("gensec_gssapi_unwrap: GSS UnWrap failed: %s\n",
760 gssapi_error_string(mem_ctx, maj_stat, min_stat)));
761 return NT_STATUS_ACCESS_DENIED;
764 *out = data_blob_talloc(mem_ctx, output_token.value, output_token.length);
765 gss_release_buffer(&min_stat, &output_token);
767 if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)
769 return NT_STATUS_ACCESS_DENIED;
774 /* Find out the size of the signature, assuming (incorrectly) that it
775 * GSSAPI provides any guarantees as to it's size.
777 * This is needed by the DCE/RPC code, which uses AEAD
778 * (signed headers, including signature legnth and a sealed body)
780 static size_t gensec_gssapi_sig_size(struct gensec_security *gensec_security, size_t data_size)
782 struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
783 OM_uint32 maj_stat, min_stat;
784 OM_uint32 output_size;
785 if ((gensec_gssapi_state->gss_oid->length != gss_mech_krb5->length)
786 || (memcmp(gensec_gssapi_state->gss_oid->elements, gss_mech_krb5->elements,
787 gensec_gssapi_state->gss_oid->length) != 0)) {
788 DEBUG(1, ("NO sig size available for this mech\n"));
792 maj_stat = gsskrb5_wrap_size(&min_stat,
793 gensec_gssapi_state->gssapi_context,
794 gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL),
798 if (GSS_ERROR(maj_stat)) {
799 TALLOC_CTX *mem_ctx = talloc_new(NULL);
800 DEBUG(1, ("gensec_gssapi_seal_packet: determinaing signature size with gss_wrap_size_limit failed: %s\n",
801 gssapi_error_string(mem_ctx, maj_stat, min_stat)));
802 talloc_free(mem_ctx);
806 if (output_size < data_size) {
810 /* The difference between the max output and the max input must be the signature */
811 return output_size - data_size;
814 static NTSTATUS gensec_gssapi_seal_packet(struct gensec_security *gensec_security,
816 uint8_t *data, size_t length,
817 const uint8_t *whole_pdu, size_t pdu_length,
820 struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
821 OM_uint32 maj_stat, min_stat;
822 gss_buffer_desc input_token, output_token;
826 input_token.length = length;
827 input_token.value = data;
829 maj_stat = gss_wrap(&min_stat,
830 gensec_gssapi_state->gssapi_context,
831 gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL),
836 if (GSS_ERROR(maj_stat)) {
837 DEBUG(1, ("gensec_gssapi_seal_packet: GSS Wrap failed: %s\n",
838 gssapi_error_string(mem_ctx, maj_stat, min_stat)));
839 return NT_STATUS_ACCESS_DENIED;
842 sig_length = gensec_gssapi_sig_size(gensec_security, length);
844 /* Caller must pad to right boundary */
845 if (output_token.length != (length + sig_length)) {
846 DEBUG(1, ("gensec_gssapi_seal_packet: GSS Wrap length [%ld] does not match caller length [%ld] plus sig size [%ld] = [%ld]\n",
847 (long)output_token.length, (long)length, (long)sig_length, (long)(length + sig_length)));
848 return NT_STATUS_INTERNAL_ERROR;
851 memcpy(data, ((uint8_t *)output_token.value) + sig_length, length);
852 *sig = data_blob_talloc(mem_ctx, (uint8_t *)output_token.value, sig_length);
854 dump_data_pw("gensec_gssapi_seal_packet: sig\n", sig->data, sig->length);
855 dump_data_pw("gensec_gssapi_seal_packet: clear\n", data, length);
856 dump_data_pw("gensec_gssapi_seal_packet: sealed\n", ((uint8_t *)output_token.value) + sig_length, output_token.length - sig_length);
858 gss_release_buffer(&min_stat, &output_token);
860 if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)
862 return NT_STATUS_ACCESS_DENIED;
867 static NTSTATUS gensec_gssapi_unseal_packet(struct gensec_security *gensec_security,
869 uint8_t *data, size_t length,
870 const uint8_t *whole_pdu, size_t pdu_length,
871 const DATA_BLOB *sig)
873 struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
874 OM_uint32 maj_stat, min_stat;
875 gss_buffer_desc input_token, output_token;
880 dump_data_pw("gensec_gssapi_unseal_packet: sig\n", sig->data, sig->length);
882 in = data_blob_talloc(mem_ctx, NULL, sig->length + length);
884 memcpy(in.data, sig->data, sig->length);
885 memcpy(in.data + sig->length, data, length);
887 input_token.length = in.length;
888 input_token.value = in.data;
890 maj_stat = gss_unwrap(&min_stat,
891 gensec_gssapi_state->gssapi_context,
896 if (GSS_ERROR(maj_stat)) {
897 DEBUG(1, ("gensec_gssapi_unseal_packet: GSS UnWrap failed: %s\n",
898 gssapi_error_string(mem_ctx, maj_stat, min_stat)));
899 return NT_STATUS_ACCESS_DENIED;
902 if (output_token.length != length) {
903 return NT_STATUS_INTERNAL_ERROR;
906 memcpy(data, output_token.value, length);
908 gss_release_buffer(&min_stat, &output_token);
910 if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)
912 return NT_STATUS_ACCESS_DENIED;
917 static NTSTATUS gensec_gssapi_sign_packet(struct gensec_security *gensec_security,
919 const uint8_t *data, size_t length,
920 const uint8_t *whole_pdu, size_t pdu_length,
923 struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
924 OM_uint32 maj_stat, min_stat;
925 gss_buffer_desc input_token, output_token;
927 ssize_t sig_length = 0;
929 input_token.length = length;
930 input_token.value = discard_const_p(uint8_t *, data);
932 maj_stat = gss_wrap(&min_stat,
933 gensec_gssapi_state->gssapi_context,
939 if (GSS_ERROR(maj_stat)) {
940 DEBUG(1, ("GSS Wrap failed: %s\n",
941 gssapi_error_string(mem_ctx, maj_stat, min_stat)));
942 return NT_STATUS_ACCESS_DENIED;
945 if (output_token.length < length) {
946 return NT_STATUS_INTERNAL_ERROR;
949 sig_length = gensec_gssapi_sig_size(gensec_security, length);
951 /* Caller must pad to right boundary */
952 if (output_token.length != (length + sig_length)) {
953 DEBUG(1, ("gensec_gssapi_sign_packet: GSS Wrap length [%ld] does not match caller length [%ld] plus sig size [%ld] = [%ld]\n",
954 (long)output_token.length, (long)length, (long)sig_length, (long)(length + sig_length)));
955 return NT_STATUS_INTERNAL_ERROR;
958 *sig = data_blob_talloc(mem_ctx, (uint8_t *)output_token.value, sig_length);
960 dump_data_pw("gensec_gssapi_seal_packet: sig\n", sig->data, sig->length);
962 gss_release_buffer(&min_stat, &output_token);
967 static NTSTATUS gensec_gssapi_check_packet(struct gensec_security *gensec_security,
969 const uint8_t *data, size_t length,
970 const uint8_t *whole_pdu, size_t pdu_length,
971 const DATA_BLOB *sig)
973 struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
974 OM_uint32 maj_stat, min_stat;
975 gss_buffer_desc input_token, output_token;
980 dump_data_pw("gensec_gssapi_seal_packet: sig\n", sig->data, sig->length);
982 in = data_blob_talloc(mem_ctx, NULL, sig->length + length);
984 memcpy(in.data, sig->data, sig->length);
985 memcpy(in.data + sig->length, data, length);
987 input_token.length = in.length;
988 input_token.value = in.data;
990 maj_stat = gss_unwrap(&min_stat,
991 gensec_gssapi_state->gssapi_context,
996 if (GSS_ERROR(maj_stat)) {
997 DEBUG(1, ("GSS UnWrap failed: %s\n",
998 gssapi_error_string(mem_ctx, maj_stat, min_stat)));
999 return NT_STATUS_ACCESS_DENIED;
1002 if (output_token.length != length) {
1003 return NT_STATUS_INTERNAL_ERROR;
1006 gss_release_buffer(&min_stat, &output_token);
1008 return NT_STATUS_OK;
1011 /* Try to figure out what features we actually got on the connection */
1012 static BOOL gensec_gssapi_have_feature(struct gensec_security *gensec_security,
1015 struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
1016 if (feature & GENSEC_FEATURE_SIGN) {
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_SIGN)
1021 && (gensec_gssapi_state->got_flags & GSS_C_INTEG_FLAG));
1023 return gensec_gssapi_state->got_flags & GSS_C_INTEG_FLAG;
1025 if (feature & GENSEC_FEATURE_SEAL) {
1026 /* If we are going GSSAPI SASL, then we honour the second negotiation */
1027 if (gensec_gssapi_state->sasl
1028 && gensec_gssapi_state->sasl_state == STAGE_DONE) {
1029 return ((gensec_gssapi_state->sasl_protection & NEG_SEAL)
1030 && (gensec_gssapi_state->got_flags & GSS_C_CONF_FLAG));
1032 return gensec_gssapi_state->got_flags & GSS_C_CONF_FLAG;
1034 if (feature & GENSEC_FEATURE_SESSION_KEY) {
1035 /* Only for GSSAPI/Krb5 */
1036 if ((gensec_gssapi_state->gss_oid->length == gss_mech_krb5->length)
1037 && (memcmp(gensec_gssapi_state->gss_oid->elements, gss_mech_krb5->elements, gensec_gssapi_state->gss_oid->length) == 0)) {
1041 if (feature & GENSEC_FEATURE_DCE_STYLE) {
1042 return gensec_gssapi_state->got_flags & GSS_C_DCE_STYLE;
1044 /* We can always do async (rather than strict request/reply) packets. */
1045 if (feature & GENSEC_FEATURE_ASYNC_REPLIES) {
1052 * Extract the 'sesssion key' needed by SMB signing and ncacn_np
1053 * (for encrypting some passwords).
1055 * This breaks all the abstractions, but what do you expect...
1057 static NTSTATUS gensec_gssapi_session_key(struct gensec_security *gensec_security,
1058 DATA_BLOB *session_key)
1060 struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
1062 if (gensec_gssapi_state->session_key.data) {
1063 *session_key = gensec_gssapi_state->session_key;
1064 return NT_STATUS_OK;
1067 /* Ensure we only call this for GSSAPI/krb5, otherwise things
1068 * could get very ugly */
1069 if ((gensec_gssapi_state->gss_oid->length == gss_mech_krb5->length)
1070 && (memcmp(gensec_gssapi_state->gss_oid->elements, gss_mech_krb5->elements,
1071 gensec_gssapi_state->gss_oid->length) == 0)) {
1072 OM_uint32 maj_stat, min_stat;
1073 gss_buffer_desc skey;
1075 maj_stat = gsskrb5_get_initiator_subkey(&min_stat,
1076 gensec_gssapi_state->gssapi_context,
1079 if (maj_stat == 0) {
1080 DEBUG(10, ("Got KRB5 session key of length %d\n",
1082 gensec_gssapi_state->session_key = data_blob_talloc(gensec_gssapi_state,
1083 skey.value, skey.length);
1084 *session_key = gensec_gssapi_state->session_key;
1085 dump_data_pw("KRB5 Session Key:\n", session_key->data, session_key->length);
1087 gss_release_buffer(&min_stat, &skey);
1088 return NT_STATUS_OK;
1090 return NT_STATUS_NO_USER_SESSION_KEY;
1093 DEBUG(1, ("NO session key for this mech\n"));
1094 return NT_STATUS_NO_USER_SESSION_KEY;
1098 /* Get some basic (and authorization) information about the user on
1099 * this session. This uses either the PAC (if present) or a local
1100 * database lookup */
1101 static NTSTATUS gensec_gssapi_session_info(struct gensec_security *gensec_security,
1102 struct auth_session_info **_session_info)
1105 TALLOC_CTX *mem_ctx;
1106 struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
1107 struct auth_serversupplied_info *server_info = NULL;
1108 struct auth_session_info *session_info = NULL;
1109 struct PAC_LOGON_INFO *logon_info;
1110 OM_uint32 maj_stat, min_stat;
1111 gss_buffer_desc name_token;
1112 gss_buffer_desc pac;
1113 krb5_keyblock *keyblock;
1115 krb5_principal principal;
1116 char *principal_string;
1119 if ((gensec_gssapi_state->gss_oid->length != gss_mech_krb5->length)
1120 || (memcmp(gensec_gssapi_state->gss_oid->elements, gss_mech_krb5->elements,
1121 gensec_gssapi_state->gss_oid->length) != 0)) {
1122 DEBUG(1, ("NO session info available for this mech\n"));
1123 return NT_STATUS_INVALID_PARAMETER;
1126 mem_ctx = talloc_named(gensec_gssapi_state, 0, "gensec_gssapi_session_info context");
1127 NT_STATUS_HAVE_NO_MEMORY(mem_ctx);
1129 maj_stat = gss_display_name (&min_stat,
1130 gensec_gssapi_state->client_name,
1134 talloc_free(mem_ctx);
1135 return NT_STATUS_FOOBAR;
1138 principal_string = talloc_strndup(mem_ctx, name_token.value, name_token.length);
1140 gss_release_buffer(&min_stat, &name_token);
1142 if (!principal_string) {
1143 talloc_free(mem_ctx);
1144 return NT_STATUS_NO_MEMORY;
1147 maj_stat = gss_krb5_copy_service_keyblock(&min_stat,
1148 gensec_gssapi_state->gssapi_context,
1151 if (maj_stat == 0) {
1152 maj_stat = gsskrb5_extract_authtime_from_sec_context(&min_stat,
1153 gensec_gssapi_state->gssapi_context,
1157 if (maj_stat == 0) {
1158 maj_stat = gsskrb5_extract_authz_data_from_sec_context(&min_stat,
1159 gensec_gssapi_state->gssapi_context,
1160 KRB5_AUTHDATA_WIN2K_PAC,
1164 if (maj_stat == 0) {
1165 pac_blob = data_blob_talloc(mem_ctx, pac.value, pac.length);
1166 gss_release_buffer(&min_stat, &pac);
1169 /* IF we have the PAC - otherwise we need to get this
1170 * data from elsewere - local ldb, or (TODO) lookup of some
1173 if (maj_stat == 0) {
1174 krb5_error_code ret;
1176 ret = krb5_parse_name(gensec_gssapi_state->smb_krb5_context->krb5_context,
1177 principal_string, &principal);
1179 talloc_free(mem_ctx);
1180 return NT_STATUS_INVALID_PARAMETER;
1183 /* decode and verify the pac */
1184 nt_status = kerberos_pac_logon_info(mem_ctx, &logon_info, pac_blob,
1185 gensec_gssapi_state->smb_krb5_context->krb5_context,
1186 NULL, keyblock, principal, authtime, NULL);
1187 krb5_free_principal(gensec_gssapi_state->smb_krb5_context->krb5_context, principal);
1189 if (NT_STATUS_IS_OK(nt_status)) {
1190 union netr_Validation validation;
1191 validation.sam3 = &logon_info->info3;
1192 nt_status = make_server_info_netlogon_validation(gensec_gssapi_state,
1196 if (!NT_STATUS_IS_OK(nt_status)) {
1197 talloc_free(mem_ctx);
1206 DEBUG(1, ("Unable to use PAC, resorting to local user lookup!\n"));
1207 nt_status = sam_get_server_info_principal(mem_ctx, principal_string,
1210 if (!NT_STATUS_IS_OK(nt_status)) {
1211 talloc_free(mem_ctx);
1216 /* references the server_info into the session_info */
1217 nt_status = auth_generate_session_info(mem_ctx, server_info, &session_info);
1218 if (!NT_STATUS_IS_OK(nt_status)) {
1219 talloc_free(mem_ctx);
1223 nt_status = gensec_gssapi_session_key(gensec_security, &session_info->session_key);
1224 if (!NT_STATUS_IS_OK(nt_status)) {
1225 talloc_free(mem_ctx);
1229 if (!(gensec_gssapi_state->got_flags & GSS_C_DELEG_FLAG)) {
1230 DEBUG(10, ("gensec_gssapi: NO delegated credentials supplied by client\n"));
1232 krb5_error_code ret;
1233 DEBUG(10, ("gensec_gssapi: delegated credentials supplied by client\n"));
1234 session_info->credentials = cli_credentials_init(session_info);
1235 if (!session_info->credentials) {
1236 talloc_free(mem_ctx);
1237 return NT_STATUS_NO_MEMORY;
1240 cli_credentials_set_conf(session_info->credentials);
1242 ret = cli_credentials_set_client_gss_creds(session_info->credentials,
1243 gensec_gssapi_state->delegated_cred_handle,
1246 talloc_free(mem_ctx);
1247 return NT_STATUS_NO_MEMORY;
1249 /* It has been taken from this place... */
1250 gensec_gssapi_state->delegated_cred_handle = GSS_C_NO_CREDENTIAL;
1252 talloc_steal(gensec_gssapi_state, session_info);
1253 talloc_free(mem_ctx);
1254 *_session_info = session_info;
1256 return NT_STATUS_OK;
1259 static const char *gensec_gssapi_krb5_oids[] = {
1260 GENSEC_OID_KERBEROS5,
1261 GENSEC_OID_KERBEROS5_OLD,
1265 /* As a server, this could in theory accept any GSSAPI mech */
1266 static const struct gensec_security_ops gensec_gssapi_krb5_security_ops = {
1267 .name = "gssapi_krb5",
1268 .auth_type = DCERPC_AUTH_TYPE_KRB5,
1269 .oid = gensec_gssapi_krb5_oids,
1270 .client_start = gensec_gssapi_client_start,
1271 .server_start = gensec_gssapi_server_start,
1272 .magic = gensec_gssapi_magic,
1273 .update = gensec_gssapi_update,
1274 .session_key = gensec_gssapi_session_key,
1275 .session_info = gensec_gssapi_session_info,
1276 .sig_size = gensec_gssapi_sig_size,
1277 .sign_packet = gensec_gssapi_sign_packet,
1278 .check_packet = gensec_gssapi_check_packet,
1279 .seal_packet = gensec_gssapi_seal_packet,
1280 .unseal_packet = gensec_gssapi_unseal_packet,
1281 .wrap = gensec_gssapi_wrap,
1282 .unwrap = gensec_gssapi_unwrap,
1283 .have_feature = gensec_gssapi_have_feature,
1288 /* As a server, this could in theory accept any GSSAPI mech */
1289 static const struct gensec_security_ops gensec_gssapi_sasl_krb5_security_ops = {
1290 .name = "gssapi_krb5_sasl",
1291 .sasl_name = "GSSAPI",
1292 .client_start = gensec_gssapi_sasl_client_start,
1293 .server_start = gensec_gssapi_sasl_server_start,
1294 .update = gensec_gssapi_update,
1295 .session_key = gensec_gssapi_session_key,
1296 .session_info = gensec_gssapi_session_info,
1297 .wrap = gensec_gssapi_wrap,
1298 .unwrap = gensec_gssapi_unwrap,
1299 .have_feature = gensec_gssapi_have_feature,
1304 NTSTATUS gensec_gssapi_init(void)
1308 ret = gensec_register(&gensec_gssapi_krb5_security_ops);
1309 if (!NT_STATUS_IS_OK(ret)) {
1310 DEBUG(0,("Failed to register '%s' gensec backend!\n",
1311 gensec_gssapi_krb5_security_ops.name));
1315 ret = gensec_register(&gensec_gssapi_sasl_krb5_security_ops);
1316 if (!NT_STATUS_IS_OK(ret)) {
1317 DEBUG(0,("Failed to register '%s' gensec backend!\n",
1318 gensec_gssapi_sasl_krb5_security_ops.name));