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 "system/network.h"
28 #include "auth/kerberos/kerberos.h"
29 #include "librpc/gen_ndr/ndr_krb5pac.h"
30 #include "auth/auth.h"
32 struct gensec_gssapi_state {
33 gss_ctx_id_t gssapi_context;
34 struct gss_channel_bindings_struct *input_chan_bindings;
35 gss_name_t server_name;
36 gss_name_t client_name;
37 OM_uint32 want_flags, got_flags;
38 const gss_OID_desc *gss_oid;
40 DATA_BLOB session_key;
43 struct smb_krb5_context *smb_krb5_context;
45 const char *ccache_name;
46 struct keytab_container *keytab;
47 struct gssapi_creds_container *client_cred;
50 gss_cred_id_t delegated_cred_handle;
53 static char *gssapi_error_string(TALLOC_CTX *mem_ctx,
54 OM_uint32 maj_stat, OM_uint32 min_stat)
56 OM_uint32 disp_min_stat, disp_maj_stat;
57 gss_buffer_desc maj_error_message;
58 gss_buffer_desc min_error_message;
59 OM_uint32 msg_ctx = 0;
63 maj_error_message.value = NULL;
64 min_error_message.value = NULL;
66 disp_maj_stat = gss_display_status(&disp_min_stat, maj_stat, GSS_C_GSS_CODE,
67 GSS_C_NULL_OID, &msg_ctx, &maj_error_message);
68 disp_maj_stat = gss_display_status(&disp_min_stat, min_stat, GSS_C_MECH_CODE,
69 GSS_C_NULL_OID, &msg_ctx, &min_error_message);
70 ret = talloc_asprintf(mem_ctx, "%s: %s", (char *)maj_error_message.value, (char *)min_error_message.value);
72 gss_release_buffer(&disp_min_stat, &maj_error_message);
73 gss_release_buffer(&disp_min_stat, &min_error_message);
79 static int gensec_gssapi_destory(void *ptr)
81 struct gensec_gssapi_state *gensec_gssapi_state = ptr;
82 OM_uint32 maj_stat, min_stat;
84 if (gensec_gssapi_state->cred != GSS_C_NO_CREDENTIAL) {
85 maj_stat = gss_release_cred(&min_stat,
86 &gensec_gssapi_state->cred);
88 if (gensec_gssapi_state->delegated_cred_handle != GSS_C_NO_CREDENTIAL) {
89 maj_stat = gss_release_cred(&min_stat,
90 &gensec_gssapi_state->delegated_cred_handle);
93 if (gensec_gssapi_state->gssapi_context != GSS_C_NO_CONTEXT) {
94 maj_stat = gss_delete_sec_context (&min_stat,
95 &gensec_gssapi_state->gssapi_context,
99 if (gensec_gssapi_state->server_name != GSS_C_NO_NAME) {
100 maj_stat = gss_release_name(&min_stat, &gensec_gssapi_state->server_name);
102 if (gensec_gssapi_state->client_name != GSS_C_NO_NAME) {
103 maj_stat = gss_release_name(&min_stat, &gensec_gssapi_state->client_name);
108 static NTSTATUS gensec_gssapi_start(struct gensec_security *gensec_security)
110 struct gensec_gssapi_state *gensec_gssapi_state;
113 gensec_gssapi_state = talloc(gensec_security, struct gensec_gssapi_state);
114 if (!gensec_gssapi_state) {
115 return NT_STATUS_NO_MEMORY;
118 gensec_security->private_data = gensec_gssapi_state;
120 gensec_gssapi_state->gssapi_context = GSS_C_NO_CONTEXT;
121 gensec_gssapi_state->server_name = GSS_C_NO_NAME;
122 gensec_gssapi_state->client_name = GSS_C_NO_NAME;
124 /* TODO: Fill in channel bindings */
125 gensec_gssapi_state->input_chan_bindings = GSS_C_NO_CHANNEL_BINDINGS;
127 gensec_gssapi_state->want_flags = GSS_C_MUTUAL_FLAG | GSS_C_DELEG_FLAG;
128 gensec_gssapi_state->got_flags = 0;
130 gensec_gssapi_state->session_key = data_blob(NULL, 0);
131 gensec_gssapi_state->pac = data_blob(NULL, 0);
133 gensec_gssapi_state->cred = GSS_C_NO_CREDENTIAL;
134 gensec_gssapi_state->delegated_cred_handle = GSS_C_NO_CREDENTIAL;
136 talloc_set_destructor(gensec_gssapi_state, gensec_gssapi_destory);
138 if (gensec_security->want_features & GENSEC_FEATURE_SIGN) {
139 gensec_gssapi_state->want_flags |= GSS_C_INTEG_FLAG;
141 if (gensec_security->want_features & GENSEC_FEATURE_SEAL) {
142 gensec_gssapi_state->want_flags |= GSS_C_CONF_FLAG;
144 if (gensec_security->want_features & GENSEC_FEATURE_DCE_STYLE) {
145 gensec_gssapi_state->want_flags |= GSS_C_DCE_STYLE;
148 gensec_gssapi_state->gss_oid = gss_mech_krb5;
150 ret = smb_krb5_init_context(gensec_gssapi_state,
151 &gensec_gssapi_state->smb_krb5_context);
153 DEBUG(1,("gensec_krb5_start: krb5_init_context failed (%s)\n",
154 error_message(ret)));
155 return NT_STATUS_INTERNAL_ERROR;
160 static NTSTATUS gensec_gssapi_server_start(struct gensec_security *gensec_security)
163 OM_uint32 maj_stat, min_stat;
165 const char *principal;
166 struct gensec_gssapi_state *gensec_gssapi_state;
167 struct cli_credentials *machine_account;
169 nt_status = gensec_gssapi_start(gensec_security);
170 if (!NT_STATUS_IS_OK(nt_status)) {
174 gensec_gssapi_state = gensec_security->private_data;
176 machine_account = gensec_get_credentials(gensec_security);
178 if (!machine_account) {
179 DEBUG(3, ("No machine account credentials specified\n"));
180 return NT_STATUS_INVALID_PARAMETER;
182 ret = cli_credentials_get_keytab(machine_account, &gensec_gssapi_state->keytab);
184 DEBUG(3, ("Could not create memory keytab!\n"));
185 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
189 principal = cli_credentials_get_principal(machine_account,
192 /* This might have been explicity set to NULL, ie use what the client calls us */
194 gss_buffer_desc name_token;
196 name_token.value = discard_const_p(uint8_t, principal);
197 name_token.length = strlen(principal);
199 maj_stat = gss_import_name (&min_stat,
202 &gensec_gssapi_state->server_name);
205 DEBUG(2, ("GSS Import name of %s failed: %s\n",
206 (char *)name_token.value,
207 gssapi_error_string(gensec_gssapi_state, maj_stat, min_stat)));
208 return NT_STATUS_UNSUCCESSFUL;
211 gensec_gssapi_state->server_name = GSS_C_NO_NAME;
214 maj_stat = gsskrb5_acquire_cred(&min_stat,
215 gensec_gssapi_state->keytab->keytab,
216 gensec_gssapi_state->server_name,
220 &gensec_gssapi_state->cred,
224 DEBUG(1, ("Aquiring acceptor credentails failed: %s\n",
225 gssapi_error_string(gensec_gssapi_state, maj_stat, min_stat)));
226 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
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 = gensec_security->private_data;
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;
313 * Check if the packet is one for this mechansim
315 * @param gensec_security GENSEC state
316 * @param in The request, as a DATA_BLOB
317 * @return Error, INVALID_PARAMETER if it's not a packet for us
318 * or NT_STATUS_OK if the packet is ok.
321 static NTSTATUS gensec_gssapi_magic(struct gensec_security *gensec_security,
324 if (gensec_gssapi_check_oid(in, GENSEC_OID_KERBEROS5)) {
327 return NT_STATUS_INVALID_PARAMETER;
333 * Next state function for the GSSAPI GENSEC mechanism
335 * @param gensec_gssapi_state GSSAPI State
336 * @param out_mem_ctx The TALLOC_CTX for *out to be allocated on
337 * @param in The request, as a DATA_BLOB
338 * @param out The reply, as an talloc()ed DATA_BLOB, on *out_mem_ctx
339 * @return Error, MORE_PROCESSING_REQUIRED if a reply is sent,
340 * or NT_STATUS_OK if the user is authenticated.
343 static NTSTATUS gensec_gssapi_update(struct gensec_security *gensec_security,
344 TALLOC_CTX *out_mem_ctx,
345 const DATA_BLOB in, DATA_BLOB *out)
347 struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
348 NTSTATUS nt_status = NT_STATUS_LOGON_FAILURE;
349 OM_uint32 maj_stat, min_stat;
351 gss_buffer_desc input_token, output_token;
353 input_token.length = in.length;
354 input_token.value = in.data;
356 switch (gensec_security->gensec_role) {
359 maj_stat = gss_init_sec_context(&min_stat,
360 gensec_gssapi_state->client_cred->creds,
361 &gensec_gssapi_state->gssapi_context,
362 gensec_gssapi_state->server_name,
363 discard_const_p(gss_OID_desc, gensec_gssapi_state->gss_oid),
364 gensec_gssapi_state->want_flags,
366 gensec_gssapi_state->input_chan_bindings,
370 &gensec_gssapi_state->got_flags, /* ret flags */
376 maj_stat = gss_accept_sec_context(&min_stat,
377 &gensec_gssapi_state->gssapi_context,
378 gensec_gssapi_state->cred,
380 gensec_gssapi_state->input_chan_bindings,
381 &gensec_gssapi_state->client_name,
384 &gensec_gssapi_state->got_flags,
386 &gensec_gssapi_state->delegated_cred_handle);
387 gensec_gssapi_state->gss_oid = gss_oid_p;
391 return NT_STATUS_INVALID_PARAMETER;
395 if (maj_stat == GSS_S_COMPLETE) {
396 *out = data_blob_talloc(out_mem_ctx, output_token.value, output_token.length);
397 gss_release_buffer(&min_stat2, &output_token);
399 if (gensec_gssapi_state->got_flags & GSS_C_DELEG_FLAG) {
400 DEBUG(5, ("gensec_gssapi: credentials were delegated\n"));
402 DEBUG(5, ("gensec_gssapi: NO credentials were delegated\n"));
406 } else if (maj_stat == GSS_S_CONTINUE_NEEDED) {
407 *out = data_blob_talloc(out_mem_ctx, output_token.value, output_token.length);
408 gss_release_buffer(&min_stat2, &output_token);
410 return NT_STATUS_MORE_PROCESSING_REQUIRED;
411 } else if ((gensec_gssapi_state->gss_oid->length == gss_mech_krb5->length)
412 && (memcmp(gensec_gssapi_state->gss_oid->elements, gss_mech_krb5->elements,
413 gensec_gssapi_state->gss_oid->length) == 0)) {
415 case KRB5_KDC_UNREACH:
416 DEBUG(3, ("Cannot reach a KDC we require: %s\n",
417 gssapi_error_string(gensec_gssapi_state, maj_stat, min_stat)));
418 return NT_STATUS_INVALID_PARAMETER; /* Make SPNEGO ignore us, we can't go any further here */
419 case KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN:
420 DEBUG(3, ("Server is not registered with our KDC: %s\n",
421 gssapi_error_string(gensec_gssapi_state, maj_stat, min_stat)));
422 return NT_STATUS_INVALID_PARAMETER; /* Make SPNEGO ignore us, we can't go any further here */
423 case KRB5KRB_AP_ERR_MSG_TYPE:
424 /* garbage input, possibly from the auto-mech detection */
425 return NT_STATUS_INVALID_PARAMETER;
427 DEBUG(1, ("GSS(krb5) Update failed: %s\n",
428 gssapi_error_string(out_mem_ctx, maj_stat, min_stat)));
432 DEBUG(1, ("GSS Update failed: %s\n",
433 gssapi_error_string(out_mem_ctx, maj_stat, min_stat)));
438 static NTSTATUS gensec_gssapi_wrap(struct gensec_security *gensec_security,
443 struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
444 OM_uint32 maj_stat, min_stat;
445 gss_buffer_desc input_token, output_token;
447 input_token.length = in->length;
448 input_token.value = in->data;
450 maj_stat = gss_wrap(&min_stat,
451 gensec_gssapi_state->gssapi_context,
452 gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL),
457 if (GSS_ERROR(maj_stat)) {
458 DEBUG(1, ("gensec_gssapi_wrap: GSS Wrap failed: %s\n",
459 gssapi_error_string(mem_ctx, maj_stat, min_stat)));
460 return NT_STATUS_ACCESS_DENIED;
463 *out = data_blob_talloc(mem_ctx, output_token.value, output_token.length);
464 gss_release_buffer(&min_stat, &output_token);
466 if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)
468 return NT_STATUS_ACCESS_DENIED;
473 static NTSTATUS gensec_gssapi_unwrap(struct gensec_security *gensec_security,
478 struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
479 OM_uint32 maj_stat, min_stat;
480 gss_buffer_desc input_token, output_token;
483 input_token.length = in->length;
484 input_token.value = in->data;
486 maj_stat = gss_unwrap(&min_stat,
487 gensec_gssapi_state->gssapi_context,
492 if (GSS_ERROR(maj_stat)) {
493 DEBUG(1, ("gensec_gssapi_unwrap: GSS UnWrap failed: %s\n",
494 gssapi_error_string(mem_ctx, maj_stat, min_stat)));
495 return NT_STATUS_ACCESS_DENIED;
498 *out = data_blob_talloc(mem_ctx, output_token.value, output_token.length);
499 gss_release_buffer(&min_stat, &output_token);
501 if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)
503 return NT_STATUS_ACCESS_DENIED;
508 static size_t gensec_gssapi_sig_size(struct gensec_security *gensec_security, size_t data_size)
510 struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
511 OM_uint32 maj_stat, min_stat;
512 OM_uint32 output_size;
513 if ((gensec_gssapi_state->gss_oid->length != gss_mech_krb5->length)
514 || (memcmp(gensec_gssapi_state->gss_oid->elements, gss_mech_krb5->elements,
515 gensec_gssapi_state->gss_oid->length) != 0)) {
516 DEBUG(1, ("NO sig size available for this mech\n"));
520 maj_stat = gsskrb5_wrap_size(&min_stat,
521 gensec_gssapi_state->gssapi_context,
522 gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL),
526 if (GSS_ERROR(maj_stat)) {
527 TALLOC_CTX *mem_ctx = talloc_new(NULL);
528 DEBUG(1, ("gensec_gssapi_seal_packet: determinaing signature size with gss_wrap_size_limit failed: %s\n",
529 gssapi_error_string(mem_ctx, maj_stat, min_stat)));
530 talloc_free(mem_ctx);
534 if (output_size < data_size) {
538 /* The difference between the max output and the max input must be the signature */
539 return output_size - data_size;
542 static NTSTATUS gensec_gssapi_seal_packet(struct gensec_security *gensec_security,
544 uint8_t *data, size_t length,
545 const uint8_t *whole_pdu, size_t pdu_length,
548 struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
549 OM_uint32 maj_stat, min_stat;
550 gss_buffer_desc input_token, output_token;
554 input_token.length = length;
555 input_token.value = data;
557 maj_stat = gss_wrap(&min_stat,
558 gensec_gssapi_state->gssapi_context,
559 gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL),
564 if (GSS_ERROR(maj_stat)) {
565 DEBUG(1, ("gensec_gssapi_seal_packet: GSS Wrap failed: %s\n",
566 gssapi_error_string(mem_ctx, maj_stat, min_stat)));
567 return NT_STATUS_ACCESS_DENIED;
570 sig_length = gensec_gssapi_sig_size(gensec_security, length);
572 /* Caller must pad to right boundary */
573 if (output_token.length != (length + sig_length)) {
574 DEBUG(1, ("gensec_gssapi_seal_packet: GSS Wrap length [%d] does not match caller length [%d] plus sig size [%d] = [%d]\n",
575 output_token.length, length, sig_length, length + sig_length));
576 return NT_STATUS_INTERNAL_ERROR;
579 memcpy(data, ((uint8_t *)output_token.value) + sig_length, length);
580 *sig = data_blob_talloc(mem_ctx, (uint8_t *)output_token.value, sig_length);
582 dump_data_pw("gensec_gssapi_seal_packet: sig\n", sig->data, sig->length);
583 dump_data_pw("gensec_gssapi_seal_packet: clear\n", data, length);
584 dump_data_pw("gensec_gssapi_seal_packet: sealed\n", ((uint8_t *)output_token.value) + sig_length, output_token.length - sig_length);
586 gss_release_buffer(&min_stat, &output_token);
588 if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)
590 return NT_STATUS_ACCESS_DENIED;
595 static NTSTATUS gensec_gssapi_unseal_packet(struct gensec_security *gensec_security,
597 uint8_t *data, size_t length,
598 const uint8_t *whole_pdu, size_t pdu_length,
599 const DATA_BLOB *sig)
601 struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
602 OM_uint32 maj_stat, min_stat;
603 gss_buffer_desc input_token, output_token;
608 dump_data_pw("gensec_gssapi_unseal_packet: sig\n", sig->data, sig->length);
610 in = data_blob_talloc(mem_ctx, NULL, sig->length + length);
612 memcpy(in.data, sig->data, sig->length);
613 memcpy(in.data + sig->length, data, length);
615 input_token.length = in.length;
616 input_token.value = in.data;
618 maj_stat = gss_unwrap(&min_stat,
619 gensec_gssapi_state->gssapi_context,
624 if (GSS_ERROR(maj_stat)) {
625 DEBUG(1, ("gensec_gssapi_unseal_packet: GSS UnWrap failed: %s\n",
626 gssapi_error_string(mem_ctx, maj_stat, min_stat)));
627 return NT_STATUS_ACCESS_DENIED;
630 if (output_token.length != length) {
631 return NT_STATUS_INTERNAL_ERROR;
634 memcpy(data, output_token.value, length);
636 gss_release_buffer(&min_stat, &output_token);
638 if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)
640 return NT_STATUS_ACCESS_DENIED;
645 static NTSTATUS gensec_gssapi_sign_packet(struct gensec_security *gensec_security,
647 const uint8_t *data, size_t length,
648 const uint8_t *whole_pdu, size_t pdu_length,
651 struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
652 OM_uint32 maj_stat, min_stat;
653 gss_buffer_desc input_token, output_token;
655 ssize_t sig_length = 0;
657 input_token.length = length;
658 input_token.value = discard_const_p(uint8_t *, data);
660 maj_stat = gss_wrap(&min_stat,
661 gensec_gssapi_state->gssapi_context,
667 if (GSS_ERROR(maj_stat)) {
668 DEBUG(1, ("GSS Wrap failed: %s\n",
669 gssapi_error_string(mem_ctx, maj_stat, min_stat)));
670 return NT_STATUS_ACCESS_DENIED;
673 if (output_token.length < length) {
674 return NT_STATUS_INTERNAL_ERROR;
677 sig_length = gensec_gssapi_sig_size(gensec_security, length);
679 /* Caller must pad to right boundary */
680 if (output_token.length != (length + sig_length)) {
681 DEBUG(1, ("gensec_gssapi_sign_packet: GSS Wrap length [%d] does not match caller length [%d] plus sig size [%d] = [%d]\n",
682 output_token.length, length, sig_length, length + sig_length));
683 return NT_STATUS_INTERNAL_ERROR;
686 *sig = data_blob_talloc(mem_ctx, (uint8_t *)output_token.value, sig_length);
688 dump_data_pw("gensec_gssapi_seal_packet: sig\n", sig->data, sig->length);
690 gss_release_buffer(&min_stat, &output_token);
695 static NTSTATUS gensec_gssapi_check_packet(struct gensec_security *gensec_security,
697 const uint8_t *data, size_t length,
698 const uint8_t *whole_pdu, size_t pdu_length,
699 const DATA_BLOB *sig)
701 struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
702 OM_uint32 maj_stat, min_stat;
703 gss_buffer_desc input_token, output_token;
708 dump_data_pw("gensec_gssapi_seal_packet: sig\n", sig->data, sig->length);
710 in = data_blob_talloc(mem_ctx, NULL, sig->length + length);
712 memcpy(in.data, sig->data, sig->length);
713 memcpy(in.data + sig->length, data, length);
715 input_token.length = in.length;
716 input_token.value = in.data;
718 maj_stat = gss_unwrap(&min_stat,
719 gensec_gssapi_state->gssapi_context,
724 if (GSS_ERROR(maj_stat)) {
725 DEBUG(1, ("GSS UnWrap failed: %s\n",
726 gssapi_error_string(mem_ctx, maj_stat, min_stat)));
727 return NT_STATUS_ACCESS_DENIED;
730 if (output_token.length != length) {
731 return NT_STATUS_INTERNAL_ERROR;
734 gss_release_buffer(&min_stat, &output_token);
739 static BOOL gensec_gssapi_have_feature(struct gensec_security *gensec_security,
742 struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
743 if (feature & GENSEC_FEATURE_SIGN) {
744 return gensec_gssapi_state->got_flags & GSS_C_INTEG_FLAG;
746 if (feature & GENSEC_FEATURE_SEAL) {
747 return gensec_gssapi_state->got_flags & GSS_C_CONF_FLAG;
749 if (feature & GENSEC_FEATURE_SESSION_KEY) {
750 if ((gensec_gssapi_state->gss_oid->length == gss_mech_krb5->length)
751 && (memcmp(gensec_gssapi_state->gss_oid->elements, gss_mech_krb5->elements, gensec_gssapi_state->gss_oid->length) == 0)) {
755 if (feature & GENSEC_FEATURE_DCE_STYLE) {
756 return gensec_gssapi_state->got_flags & GSS_C_DCE_STYLE;
758 if (feature & GENSEC_FEATURE_ASYNC_REPLIES) {
764 static NTSTATUS gensec_gssapi_session_key(struct gensec_security *gensec_security,
765 DATA_BLOB *session_key)
767 struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
769 if (gensec_gssapi_state->session_key.data) {
770 *session_key = gensec_gssapi_state->session_key;
774 /* Ensure we only call this for GSSAPI/krb5, otherwise things could get very ugly */
775 if ((gensec_gssapi_state->gss_oid->length == gss_mech_krb5->length)
776 && (memcmp(gensec_gssapi_state->gss_oid->elements, gss_mech_krb5->elements,
777 gensec_gssapi_state->gss_oid->length) == 0)) {
778 OM_uint32 maj_stat, min_stat;
779 gss_buffer_desc skey;
781 maj_stat = gsskrb5_get_initiator_subkey(&min_stat,
782 gensec_gssapi_state->gssapi_context,
786 DEBUG(10, ("Got KRB5 session key of length %d\n",
788 gensec_gssapi_state->session_key = data_blob_talloc(gensec_gssapi_state,
789 skey.value, skey.length);
790 *session_key = gensec_gssapi_state->session_key;
791 dump_data_pw("KRB5 Session Key:\n", session_key->data, session_key->length);
793 gss_release_buffer(&min_stat, &skey);
796 return NT_STATUS_NO_USER_SESSION_KEY;
799 DEBUG(1, ("NO session key for this mech\n"));
800 return NT_STATUS_NO_USER_SESSION_KEY;
803 static NTSTATUS gensec_gssapi_session_info(struct gensec_security *gensec_security,
804 struct auth_session_info **_session_info)
808 struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
809 struct auth_serversupplied_info *server_info = NULL;
810 struct auth_session_info *session_info = NULL;
811 struct PAC_LOGON_INFO *logon_info;
812 OM_uint32 maj_stat, min_stat;
813 gss_buffer_desc name_token;
815 krb5_keyblock *keyblock;
817 krb5_principal principal;
818 char *principal_string;
821 if ((gensec_gssapi_state->gss_oid->length != gss_mech_krb5->length)
822 || (memcmp(gensec_gssapi_state->gss_oid->elements, gss_mech_krb5->elements,
823 gensec_gssapi_state->gss_oid->length) != 0)) {
824 DEBUG(1, ("NO session info available for this mech\n"));
825 return NT_STATUS_INVALID_PARAMETER;
828 mem_ctx = talloc_named(gensec_gssapi_state, 0, "gensec_gssapi_session_info context");
829 NT_STATUS_HAVE_NO_MEMORY(mem_ctx);
831 maj_stat = gss_display_name (&min_stat,
832 gensec_gssapi_state->client_name,
836 return NT_STATUS_FOOBAR;
839 principal_string = talloc_strndup(mem_ctx, name_token.value, name_token.length);
841 gss_release_buffer(&min_stat, &name_token);
843 if (!principal_string) {
844 talloc_free(mem_ctx);
845 return NT_STATUS_NO_MEMORY;
848 maj_stat = gss_krb5_copy_service_keyblock(&min_stat,
849 gensec_gssapi_state->gssapi_context,
853 maj_stat = gsskrb5_extract_authtime_from_sec_context(&min_stat,
854 gensec_gssapi_state->gssapi_context,
859 maj_stat = gsskrb5_extract_authz_data_from_sec_context(&min_stat,
860 gensec_gssapi_state->gssapi_context,
861 KRB5_AUTHDATA_WIN2K_PAC,
866 pac_blob = data_blob_talloc(mem_ctx, pac.value, pac.length);
867 gss_release_buffer(&min_stat, &pac);
870 /* IF we have the PAC - otherwise we need to get this
871 * data from elsewere - local ldb, or (TODO) lookup of some
877 ret = krb5_parse_name(gensec_gssapi_state->smb_krb5_context->krb5_context,
878 principal_string, &principal);
880 talloc_free(mem_ctx);
881 return NT_STATUS_INVALID_PARAMETER;
884 /* decode and verify the pac */
885 nt_status = kerberos_pac_logon_info(mem_ctx, &logon_info, pac_blob,
886 gensec_gssapi_state->smb_krb5_context->krb5_context,
887 NULL, keyblock, principal, authtime);
888 krb5_free_principal(gensec_gssapi_state->smb_krb5_context->krb5_context, principal);
890 if (NT_STATUS_IS_OK(nt_status)) {
891 union netr_Validation validation;
892 validation.sam3 = &logon_info->info3;
893 nt_status = make_server_info_netlogon_validation(gensec_gssapi_state,
897 if (!NT_STATUS_IS_OK(nt_status)) {
898 talloc_free(mem_ctx);
907 DEBUG(1, ("Unable to use PAC, resorting to local user lookup!\n"));
908 nt_status = sam_get_server_info_principal(mem_ctx, principal_string,
911 if (!NT_STATUS_IS_OK(nt_status)) {
912 talloc_free(mem_ctx);
917 /* references the server_info into the session_info */
918 nt_status = auth_generate_session_info(gensec_gssapi_state, server_info, &session_info);
919 talloc_free(mem_ctx);
920 talloc_free(server_info);
921 NT_STATUS_NOT_OK_RETURN(nt_status);
923 nt_status = gensec_gssapi_session_key(gensec_security, &session_info->session_key);
924 NT_STATUS_NOT_OK_RETURN(nt_status);
926 if (!(gensec_gssapi_state->got_flags & GSS_C_DELEG_FLAG)) {
927 DEBUG(10, ("gensec_gssapi: NO delegated credentials supplied by client"));
930 DEBUG(10, ("gensec_gssapi: delegated credentials supplied by client\n"));
931 session_info->credentials = cli_credentials_init(session_info);
932 if (!session_info->credentials) {
933 return NT_STATUS_NO_MEMORY;
936 cli_credentials_set_conf(session_info->credentials);
938 ret = cli_credentials_set_client_gss_creds(session_info->credentials,
939 gensec_gssapi_state->delegated_cred_handle,
942 return NT_STATUS_NO_MEMORY;
944 /* It has been taken from this place... */
945 gensec_gssapi_state->delegated_cred_handle = GSS_C_NO_CREDENTIAL;
947 *_session_info = session_info;
952 static const char *gensec_gssapi_krb5_oids[] = {
953 GENSEC_OID_KERBEROS5,
954 GENSEC_OID_KERBEROS5_OLD,
958 /* As a server, this could in theory accept any GSSAPI mech */
959 static const struct gensec_security_ops gensec_gssapi_krb5_security_ops = {
960 .name = "gssapi_krb5",
961 .auth_type = DCERPC_AUTH_TYPE_KRB5,
962 .oid = gensec_gssapi_krb5_oids,
963 .client_start = gensec_gssapi_client_start,
964 .server_start = gensec_gssapi_server_start,
965 .magic = gensec_gssapi_magic,
966 .update = gensec_gssapi_update,
967 .session_key = gensec_gssapi_session_key,
968 .session_info = gensec_gssapi_session_info,
969 .sig_size = gensec_gssapi_sig_size,
970 .sign_packet = gensec_gssapi_sign_packet,
971 .check_packet = gensec_gssapi_check_packet,
972 .seal_packet = gensec_gssapi_seal_packet,
973 .unseal_packet = gensec_gssapi_unseal_packet,
974 .wrap = gensec_gssapi_wrap,
975 .unwrap = gensec_gssapi_unwrap,
976 .have_feature = gensec_gssapi_have_feature,
980 NTSTATUS gensec_gssapi_init(void)
984 ret = gensec_register(&gensec_gssapi_krb5_security_ops);
985 if (!NT_STATUS_IS_OK(ret)) {
986 DEBUG(0,("Failed to register '%s' gensec backend!\n",
987 gensec_gssapi_krb5_security_ops.name));