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;
51 static char *gssapi_error_string(TALLOC_CTX *mem_ctx,
52 OM_uint32 maj_stat, OM_uint32 min_stat)
54 OM_uint32 disp_min_stat, disp_maj_stat;
55 gss_buffer_desc maj_error_message;
56 gss_buffer_desc min_error_message;
57 OM_uint32 msg_ctx = 0;
61 maj_error_message.value = NULL;
62 min_error_message.value = NULL;
64 disp_maj_stat = gss_display_status(&disp_min_stat, maj_stat, GSS_C_GSS_CODE,
65 GSS_C_NULL_OID, &msg_ctx, &maj_error_message);
66 disp_maj_stat = gss_display_status(&disp_min_stat, min_stat, GSS_C_MECH_CODE,
67 GSS_C_NULL_OID, &msg_ctx, &min_error_message);
68 ret = talloc_asprintf(mem_ctx, "%s: %s", (char *)maj_error_message.value, (char *)min_error_message.value);
70 gss_release_buffer(&disp_min_stat, &maj_error_message);
71 gss_release_buffer(&disp_min_stat, &min_error_message);
77 static int gensec_gssapi_destory(void *ptr)
79 struct gensec_gssapi_state *gensec_gssapi_state = ptr;
80 OM_uint32 maj_stat, min_stat;
82 if (gensec_gssapi_state->cred != GSS_C_NO_CREDENTIAL) {
83 maj_stat = gss_release_cred(&min_stat,
84 &gensec_gssapi_state->cred);
87 if (gensec_gssapi_state->gssapi_context != GSS_C_NO_CONTEXT) {
88 maj_stat = gss_delete_sec_context (&min_stat,
89 &gensec_gssapi_state->gssapi_context,
93 if (gensec_gssapi_state->server_name != GSS_C_NO_NAME) {
94 maj_stat = gss_release_name(&min_stat, &gensec_gssapi_state->server_name);
96 if (gensec_gssapi_state->client_name != GSS_C_NO_NAME) {
97 maj_stat = gss_release_name(&min_stat, &gensec_gssapi_state->client_name);
102 static NTSTATUS gensec_gssapi_start(struct gensec_security *gensec_security)
104 struct gensec_gssapi_state *gensec_gssapi_state;
107 gensec_gssapi_state = talloc(gensec_security, struct gensec_gssapi_state);
108 if (!gensec_gssapi_state) {
109 return NT_STATUS_NO_MEMORY;
112 gensec_security->private_data = gensec_gssapi_state;
114 gensec_gssapi_state->gssapi_context = GSS_C_NO_CONTEXT;
115 gensec_gssapi_state->server_name = GSS_C_NO_NAME;
116 gensec_gssapi_state->client_name = GSS_C_NO_NAME;
118 /* TODO: Fill in channel bindings */
119 gensec_gssapi_state->input_chan_bindings = GSS_C_NO_CHANNEL_BINDINGS;
121 gensec_gssapi_state->want_flags = GSS_C_MUTUAL_FLAG;
122 gensec_gssapi_state->got_flags = 0;
124 gensec_gssapi_state->session_key = data_blob(NULL, 0);
125 gensec_gssapi_state->pac = data_blob(NULL, 0);
127 gensec_gssapi_state->cred = GSS_C_NO_CREDENTIAL;
129 talloc_set_destructor(gensec_gssapi_state, gensec_gssapi_destory);
131 if (gensec_security->want_features & GENSEC_FEATURE_SIGN) {
132 gensec_gssapi_state->want_flags |= GSS_C_INTEG_FLAG;
134 if (gensec_security->want_features & GENSEC_FEATURE_SEAL) {
135 gensec_gssapi_state->want_flags |= GSS_C_CONF_FLAG;
137 if (gensec_security->want_features & GENSEC_FEATURE_DCE_STYLE) {
138 gensec_gssapi_state->want_flags |= GSS_C_DCE_STYLE;
141 gensec_gssapi_state->gss_oid = gss_mech_krb5;
143 ret = smb_krb5_init_context(gensec_gssapi_state,
144 &gensec_gssapi_state->smb_krb5_context);
146 DEBUG(1,("gensec_krb5_start: krb5_init_context failed (%s)\n",
147 error_message(ret)));
148 return NT_STATUS_INTERNAL_ERROR;
153 static NTSTATUS gensec_gssapi_server_start(struct gensec_security *gensec_security)
156 OM_uint32 maj_stat, min_stat;
158 const char *principal;
159 struct gensec_gssapi_state *gensec_gssapi_state;
160 struct cli_credentials *machine_account;
162 nt_status = gensec_gssapi_start(gensec_security);
163 if (!NT_STATUS_IS_OK(nt_status)) {
167 gensec_gssapi_state = gensec_security->private_data;
169 machine_account = gensec_get_credentials(gensec_security);
171 if (!machine_account) {
172 DEBUG(3, ("No machine account credentials specified\n"));
173 return NT_STATUS_INVALID_PARAMETER;
175 ret = cli_credentials_get_keytab(machine_account, &gensec_gssapi_state->keytab);
177 DEBUG(3, ("Could not create memory keytab!\n"));
178 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
182 principal = cli_credentials_get_principal(machine_account,
185 /* This might have been explicity set to NULL, ie use what the client calls us */
187 gss_buffer_desc name_token;
189 name_token.value = discard_const_p(uint8_t, principal);
190 name_token.length = strlen(principal);
192 maj_stat = gss_import_name (&min_stat,
195 &gensec_gssapi_state->server_name);
198 DEBUG(2, ("GSS Import name of %s failed: %s\n",
199 (char *)name_token.value,
200 gssapi_error_string(gensec_gssapi_state, maj_stat, min_stat)));
201 return NT_STATUS_UNSUCCESSFUL;
204 gensec_gssapi_state->server_name = GSS_C_NO_NAME;
207 maj_stat = gsskrb5_acquire_cred(&min_stat,
208 gensec_gssapi_state->keytab->keytab, NULL,
209 gensec_gssapi_state->server_name,
213 &gensec_gssapi_state->cred,
217 DEBUG(1, ("Aquiring acceptor credentails failed: %s\n",
218 gssapi_error_string(gensec_gssapi_state, maj_stat, min_stat)));
219 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
226 static NTSTATUS gensec_gssapi_client_start(struct gensec_security *gensec_security)
228 struct gensec_gssapi_state *gensec_gssapi_state;
229 struct cli_credentials *creds = gensec_get_credentials(gensec_security);
230 struct ccache_container *ccache;
233 gss_buffer_desc name_token;
235 OM_uint32 maj_stat, min_stat;
236 const char *hostname = gensec_get_target_hostname(gensec_security);
237 const char *principal;
240 DEBUG(1, ("Could not determine hostname for target computer, cannot use kerberos\n"));
241 return NT_STATUS_INVALID_PARAMETER;
243 if (is_ipaddress(hostname)) {
244 DEBUG(2, ("Cannot do GSSAPI to an IP address\n"));
245 return NT_STATUS_INVALID_PARAMETER;
247 if (strequal(hostname, "localhost")) {
248 DEBUG(2, ("GSSAPI to 'localhost' does not make sense\n"));
249 return NT_STATUS_INVALID_PARAMETER;
252 nt_status = gensec_gssapi_start(gensec_security);
253 if (!NT_STATUS_IS_OK(nt_status)) {
257 gensec_gssapi_state = gensec_security->private_data;
259 ret = cli_credentials_get_ccache(creds,
262 DEBUG(1, ("Failed to get CCACHE for gensec_gssapi: %s\n", error_message(ret)));
263 return NT_STATUS_UNSUCCESSFUL;
266 principal = cli_credentials_get_principal(creds,
267 gensec_gssapi_state);
268 name_token.value = discard_const_p(uint8_t, principal);
269 name_token.length = strlen(principal);
271 maj_stat = gss_import_name (&min_stat,
274 &gensec_gssapi_state->client_name);
276 DEBUG(2, ("GSS Import name of %s failed: %s\n",
277 (char *)name_token.value,
278 gssapi_error_string(gensec_gssapi_state, maj_stat, min_stat)));
279 return NT_STATUS_INVALID_PARAMETER;
282 principal = gensec_get_target_principal(gensec_security);
283 if (principal && lp_client_use_spnego_principal()) {
284 name_token.value = discard_const_p(uint8_t, principal);
285 name_token.length = strlen(principal);
287 name_type = GSS_C_NULL_OID;
289 principal = talloc_asprintf(gensec_gssapi_state, "%s@%s",
290 gensec_get_target_service(gensec_security),
293 name_token.value = discard_const_p(uint8_t, principal);
294 name_token.length = strlen(principal);
296 name_type = GSS_C_NT_HOSTBASED_SERVICE;
299 maj_stat = gss_import_name (&min_stat,
302 &gensec_gssapi_state->server_name);
304 DEBUG(2, ("GSS Import name of %s failed: %s\n",
305 (char *)name_token.value,
306 gssapi_error_string(gensec_gssapi_state, maj_stat, min_stat)));
307 return NT_STATUS_INVALID_PARAMETER;
310 maj_stat = gsskrb5_acquire_cred(&min_stat,
311 NULL, ccache->ccache,
312 gensec_gssapi_state->client_name,
316 &gensec_gssapi_state->cred,
321 case KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN:
322 DEBUG(3, ("Server [%s] is not registered with our KDC: %s\n",
323 hostname, gssapi_error_string(gensec_gssapi_state, maj_stat, min_stat)));
324 return NT_STATUS_INVALID_PARAMETER; /* Make SPNEGO ignore us, we can't go any further here */
326 DEBUG(1, ("Aquiring initiator credentails failed: %s\n",
327 gssapi_error_string(gensec_gssapi_state, maj_stat, min_stat)));
328 return NT_STATUS_UNSUCCESSFUL;
337 * Check if the packet is one for this mechansim
339 * @param gensec_security GENSEC state
340 * @param in The request, as a DATA_BLOB
341 * @return Error, INVALID_PARAMETER if it's not a packet for us
342 * or NT_STATUS_OK if the packet is ok.
345 static NTSTATUS gensec_gssapi_magic(struct gensec_security *gensec_security,
348 if (gensec_gssapi_check_oid(in, GENSEC_OID_KERBEROS5)) {
351 return NT_STATUS_INVALID_PARAMETER;
357 * Next state function for the GSSAPI GENSEC mechanism
359 * @param gensec_gssapi_state GSSAPI State
360 * @param out_mem_ctx The TALLOC_CTX for *out to be allocated on
361 * @param in The request, as a DATA_BLOB
362 * @param out The reply, as an talloc()ed DATA_BLOB, on *out_mem_ctx
363 * @return Error, MORE_PROCESSING_REQUIRED if a reply is sent,
364 * or NT_STATUS_OK if the user is authenticated.
367 static NTSTATUS gensec_gssapi_update(struct gensec_security *gensec_security,
368 TALLOC_CTX *out_mem_ctx,
369 const DATA_BLOB in, DATA_BLOB *out)
371 struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
372 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
373 OM_uint32 maj_stat, min_stat;
375 gss_buffer_desc input_token, output_token;
377 input_token.length = in.length;
378 input_token.value = in.data;
380 switch (gensec_security->gensec_role) {
383 maj_stat = gss_init_sec_context(&min_stat,
384 gensec_gssapi_state->cred,
385 &gensec_gssapi_state->gssapi_context,
386 gensec_gssapi_state->server_name,
387 discard_const_p(gss_OID_desc, gensec_gssapi_state->gss_oid),
388 gensec_gssapi_state->want_flags,
390 gensec_gssapi_state->input_chan_bindings,
394 &gensec_gssapi_state->got_flags, /* ret flags */
400 maj_stat = gss_accept_sec_context(&min_stat,
401 &gensec_gssapi_state->gssapi_context,
402 gensec_gssapi_state->cred,
404 gensec_gssapi_state->input_chan_bindings,
405 &gensec_gssapi_state->client_name,
408 &gensec_gssapi_state->got_flags,
411 gensec_gssapi_state->gss_oid = gss_oid_p;
415 return NT_STATUS_INVALID_PARAMETER;
419 if (maj_stat == GSS_S_COMPLETE) {
420 *out = data_blob_talloc(out_mem_ctx, output_token.value, output_token.length);
421 gss_release_buffer(&min_stat2, &output_token);
424 } else if (maj_stat == GSS_S_CONTINUE_NEEDED) {
425 *out = data_blob_talloc(out_mem_ctx, output_token.value, output_token.length);
426 gss_release_buffer(&min_stat2, &output_token);
428 return NT_STATUS_MORE_PROCESSING_REQUIRED;
429 } else if ((gensec_gssapi_state->gss_oid->length == gss_mech_krb5->length)
430 && (memcmp(gensec_gssapi_state->gss_oid->elements, gss_mech_krb5->elements,
431 gensec_gssapi_state->gss_oid->length) == 0)) {
433 case KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN:
434 DEBUG(3, ("Server is not registered with our KDC: %s\n",
435 gssapi_error_string(gensec_gssapi_state, maj_stat, min_stat)));
436 return NT_STATUS_INVALID_PARAMETER; /* Make SPNEGO ignore us, we can't go any further here */
437 case KRB5KRB_AP_ERR_MSG_TYPE:
438 /* garbage input, possibly from the auto-mech detection */
439 return NT_STATUS_INVALID_PARAMETER;
441 DEBUG(1, ("GSS(krb5) Update failed: %s\n",
442 gssapi_error_string(out_mem_ctx, maj_stat, min_stat)));
446 DEBUG(1, ("GSS Update failed: %s\n",
447 gssapi_error_string(out_mem_ctx, maj_stat, min_stat)));
452 static NTSTATUS gensec_gssapi_wrap(struct gensec_security *gensec_security,
457 struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
458 OM_uint32 maj_stat, min_stat;
459 gss_buffer_desc input_token, output_token;
461 input_token.length = in->length;
462 input_token.value = in->data;
464 maj_stat = gss_wrap(&min_stat,
465 gensec_gssapi_state->gssapi_context,
466 gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL),
471 if (GSS_ERROR(maj_stat)) {
472 DEBUG(1, ("gensec_gssapi_wrap: GSS Wrap failed: %s\n",
473 gssapi_error_string(mem_ctx, maj_stat, min_stat)));
474 return NT_STATUS_ACCESS_DENIED;
477 *out = data_blob_talloc(mem_ctx, output_token.value, output_token.length);
478 gss_release_buffer(&min_stat, &output_token);
480 if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)
482 return NT_STATUS_ACCESS_DENIED;
487 static NTSTATUS gensec_gssapi_unwrap(struct gensec_security *gensec_security,
492 struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
493 OM_uint32 maj_stat, min_stat;
494 gss_buffer_desc input_token, output_token;
497 input_token.length = in->length;
498 input_token.value = in->data;
500 maj_stat = gss_unwrap(&min_stat,
501 gensec_gssapi_state->gssapi_context,
506 if (GSS_ERROR(maj_stat)) {
507 DEBUG(1, ("gensec_gssapi_unwrap: GSS UnWrap failed: %s\n",
508 gssapi_error_string(mem_ctx, maj_stat, min_stat)));
509 return NT_STATUS_ACCESS_DENIED;
512 *out = data_blob_talloc(mem_ctx, output_token.value, output_token.length);
513 gss_release_buffer(&min_stat, &output_token);
515 if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)
517 return NT_STATUS_ACCESS_DENIED;
522 static size_t gensec_gssapi_sig_size(struct gensec_security *gensec_security, size_t data_size)
524 struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
525 OM_uint32 maj_stat, min_stat;
526 OM_uint32 output_size;
527 if ((gensec_gssapi_state->gss_oid->length != gss_mech_krb5->length)
528 || (memcmp(gensec_gssapi_state->gss_oid->elements, gss_mech_krb5->elements,
529 gensec_gssapi_state->gss_oid->length) != 0)) {
530 DEBUG(1, ("NO sig size available for this mech\n"));
534 maj_stat = gsskrb5_wrap_size(&min_stat,
535 gensec_gssapi_state->gssapi_context,
536 gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL),
540 if (GSS_ERROR(maj_stat)) {
541 TALLOC_CTX *mem_ctx = talloc_new(NULL);
542 DEBUG(1, ("gensec_gssapi_seal_packet: determinaing signature size with gss_wrap_size_limit failed: %s\n",
543 gssapi_error_string(mem_ctx, maj_stat, min_stat)));
544 talloc_free(mem_ctx);
548 if (output_size < data_size) {
552 /* The difference between the max output and the max input must be the signature */
553 return output_size - data_size;
556 static NTSTATUS gensec_gssapi_seal_packet(struct gensec_security *gensec_security,
558 uint8_t *data, size_t length,
559 const uint8_t *whole_pdu, size_t pdu_length,
562 struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
563 OM_uint32 maj_stat, min_stat;
564 gss_buffer_desc input_token, output_token;
568 input_token.length = length;
569 input_token.value = data;
571 maj_stat = gss_wrap(&min_stat,
572 gensec_gssapi_state->gssapi_context,
573 gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL),
578 if (GSS_ERROR(maj_stat)) {
579 DEBUG(1, ("gensec_gssapi_seal_packet: GSS Wrap failed: %s\n",
580 gssapi_error_string(mem_ctx, maj_stat, min_stat)));
581 return NT_STATUS_ACCESS_DENIED;
584 sig_length = gensec_gssapi_sig_size(gensec_security, length);
586 /* Caller must pad to right boundary */
587 if (output_token.length != (length + sig_length)) {
588 DEBUG(1, ("gensec_gssapi_seal_packet: GSS Wrap length [%d] does not match caller length [%d] plus sig size [%d] = [%d]\n",
589 output_token.length, length, sig_length, length + sig_length));
590 return NT_STATUS_INTERNAL_ERROR;
593 memcpy(data, ((uint8_t *)output_token.value) + sig_length, length);
594 *sig = data_blob_talloc(mem_ctx, (uint8_t *)output_token.value, sig_length);
596 dump_data_pw("gensec_gssapi_seal_packet: sig\n", sig->data, sig->length);
597 dump_data_pw("gensec_gssapi_seal_packet: clear\n", data, length);
598 dump_data_pw("gensec_gssapi_seal_packet: sealed\n", ((uint8_t *)output_token.value) + sig_length, output_token.length - sig_length);
600 gss_release_buffer(&min_stat, &output_token);
602 if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)
604 return NT_STATUS_ACCESS_DENIED;
609 static NTSTATUS gensec_gssapi_unseal_packet(struct gensec_security *gensec_security,
611 uint8_t *data, size_t length,
612 const uint8_t *whole_pdu, size_t pdu_length,
613 const DATA_BLOB *sig)
615 struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
616 OM_uint32 maj_stat, min_stat;
617 gss_buffer_desc input_token, output_token;
622 dump_data_pw("gensec_gssapi_unseal_packet: sig\n", sig->data, sig->length);
624 in = data_blob_talloc(mem_ctx, NULL, sig->length + length);
626 memcpy(in.data, sig->data, sig->length);
627 memcpy(in.data + sig->length, data, length);
629 input_token.length = in.length;
630 input_token.value = in.data;
632 maj_stat = gss_unwrap(&min_stat,
633 gensec_gssapi_state->gssapi_context,
638 if (GSS_ERROR(maj_stat)) {
639 DEBUG(1, ("gensec_gssapi_unseal_packet: GSS UnWrap failed: %s\n",
640 gssapi_error_string(mem_ctx, maj_stat, min_stat)));
641 return NT_STATUS_ACCESS_DENIED;
644 if (output_token.length != length) {
645 return NT_STATUS_INTERNAL_ERROR;
648 memcpy(data, output_token.value, length);
650 gss_release_buffer(&min_stat, &output_token);
652 if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)
654 return NT_STATUS_ACCESS_DENIED;
659 static NTSTATUS gensec_gssapi_sign_packet(struct gensec_security *gensec_security,
661 const uint8_t *data, size_t length,
662 const uint8_t *whole_pdu, size_t pdu_length,
665 struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
666 OM_uint32 maj_stat, min_stat;
667 gss_buffer_desc input_token, output_token;
669 ssize_t sig_length = 0;
671 input_token.length = length;
672 input_token.value = discard_const_p(uint8_t *, data);
674 maj_stat = gss_wrap(&min_stat,
675 gensec_gssapi_state->gssapi_context,
681 if (GSS_ERROR(maj_stat)) {
682 DEBUG(1, ("GSS Wrap failed: %s\n",
683 gssapi_error_string(mem_ctx, maj_stat, min_stat)));
684 return NT_STATUS_ACCESS_DENIED;
687 if (output_token.length < length) {
688 return NT_STATUS_INTERNAL_ERROR;
691 sig_length = gensec_gssapi_sig_size(gensec_security, length);
693 /* Caller must pad to right boundary */
694 if (output_token.length != (length + sig_length)) {
695 DEBUG(1, ("gensec_gssapi_sign_packet: GSS Wrap length [%d] does not match caller length [%d] plus sig size [%d] = [%d]\n",
696 output_token.length, length, sig_length, length + sig_length));
697 return NT_STATUS_INTERNAL_ERROR;
700 *sig = data_blob_talloc(mem_ctx, (uint8_t *)output_token.value, sig_length);
702 dump_data_pw("gensec_gssapi_seal_packet: sig\n", sig->data, sig->length);
704 gss_release_buffer(&min_stat, &output_token);
709 static NTSTATUS gensec_gssapi_check_packet(struct gensec_security *gensec_security,
711 const uint8_t *data, size_t length,
712 const uint8_t *whole_pdu, size_t pdu_length,
713 const DATA_BLOB *sig)
715 struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
716 OM_uint32 maj_stat, min_stat;
717 gss_buffer_desc input_token, output_token;
722 dump_data_pw("gensec_gssapi_seal_packet: sig\n", sig->data, sig->length);
724 in = data_blob_talloc(mem_ctx, NULL, sig->length + length);
726 memcpy(in.data, sig->data, sig->length);
727 memcpy(in.data + sig->length, data, length);
729 input_token.length = in.length;
730 input_token.value = in.data;
732 maj_stat = gss_unwrap(&min_stat,
733 gensec_gssapi_state->gssapi_context,
738 if (GSS_ERROR(maj_stat)) {
739 DEBUG(1, ("GSS UnWrap failed: %s\n",
740 gssapi_error_string(mem_ctx, maj_stat, min_stat)));
741 return NT_STATUS_ACCESS_DENIED;
744 if (output_token.length != length) {
745 return NT_STATUS_INTERNAL_ERROR;
748 gss_release_buffer(&min_stat, &output_token);
753 static BOOL gensec_gssapi_have_feature(struct gensec_security *gensec_security,
756 struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
757 if (feature & GENSEC_FEATURE_SIGN) {
758 return gensec_gssapi_state->got_flags & GSS_C_INTEG_FLAG;
760 if (feature & GENSEC_FEATURE_SEAL) {
761 return gensec_gssapi_state->got_flags & GSS_C_CONF_FLAG;
763 if (feature & GENSEC_FEATURE_SESSION_KEY) {
764 if ((gensec_gssapi_state->gss_oid->length == gss_mech_krb5->length)
765 && (memcmp(gensec_gssapi_state->gss_oid->elements, gss_mech_krb5->elements, gensec_gssapi_state->gss_oid->length) == 0)) {
769 if (feature & GENSEC_FEATURE_DCE_STYLE) {
770 return gensec_gssapi_state->got_flags & GSS_C_DCE_STYLE;
772 if (feature & GENSEC_FEATURE_ASYNC_REPLIES) {
778 static NTSTATUS gensec_gssapi_session_key(struct gensec_security *gensec_security,
779 DATA_BLOB *session_key)
781 struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
783 if (gensec_gssapi_state->session_key.data) {
784 *session_key = gensec_gssapi_state->session_key;
788 /* Ensure we only call this for GSSAPI/krb5, otherwise things could get very ugly */
789 if ((gensec_gssapi_state->gss_oid->length == gss_mech_krb5->length)
790 && (memcmp(gensec_gssapi_state->gss_oid->elements, gss_mech_krb5->elements,
791 gensec_gssapi_state->gss_oid->length) == 0)) {
792 OM_uint32 maj_stat, min_stat;
793 gss_buffer_desc skey;
795 maj_stat = gsskrb5_get_initiator_subkey(&min_stat,
796 gensec_gssapi_state->gssapi_context,
800 DEBUG(10, ("Got KRB5 session key of length %d\n",
802 gensec_gssapi_state->session_key = data_blob_talloc(gensec_gssapi_state,
803 skey.value, skey.length);
804 *session_key = gensec_gssapi_state->session_key;
805 dump_data_pw("KRB5 Session Key:\n", session_key->data, session_key->length);
807 gss_release_buffer(&min_stat, &skey);
810 return NT_STATUS_NO_USER_SESSION_KEY;
813 DEBUG(1, ("NO session key for this mech\n"));
814 return NT_STATUS_NO_USER_SESSION_KEY;
817 static NTSTATUS gensec_gssapi_session_info(struct gensec_security *gensec_security,
818 struct auth_session_info **_session_info)
822 struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
823 struct auth_serversupplied_info *server_info = NULL;
824 struct auth_session_info *session_info = NULL;
825 struct PAC_LOGON_INFO *logon_info;
826 OM_uint32 maj_stat, min_stat;
827 gss_buffer_desc name_token;
829 krb5_keyblock *keyblock;
831 krb5_principal principal;
832 char *principal_string;
834 DATA_BLOB unwrapped_pac;
836 if ((gensec_gssapi_state->gss_oid->length != gss_mech_krb5->length)
837 || (memcmp(gensec_gssapi_state->gss_oid->elements, gss_mech_krb5->elements,
838 gensec_gssapi_state->gss_oid->length) != 0)) {
839 DEBUG(1, ("NO session info available for this mech\n"));
840 return NT_STATUS_INVALID_PARAMETER;
843 mem_ctx = talloc_named(gensec_gssapi_state, 0, "gensec_gssapi_session_info context");
844 NT_STATUS_HAVE_NO_MEMORY(mem_ctx);
846 maj_stat = gss_display_name (&min_stat,
847 gensec_gssapi_state->client_name,
851 return NT_STATUS_FOOBAR;
854 principal_string = talloc_strndup(mem_ctx, name_token.value, name_token.length);
856 gss_release_buffer(&min_stat, &name_token);
858 if (!principal_string) {
859 talloc_free(mem_ctx);
860 return NT_STATUS_NO_MEMORY;
863 maj_stat = gss_krb5_copy_service_keyblock(&min_stat,
864 gensec_gssapi_state->gssapi_context,
868 maj_stat = gsskrb5_extract_authtime_from_sec_context(&min_stat,
869 gensec_gssapi_state->gssapi_context,
874 maj_stat = gsskrb5_extract_authz_data_from_sec_context(&min_stat,
875 gensec_gssapi_state->gssapi_context,
876 KRB5_AUTHDATA_IF_RELEVANT,
881 pac_blob = data_blob_talloc(mem_ctx, pac.value, pac.length);
882 gss_release_buffer(&min_stat, &pac);
884 if (!unwrap_pac(mem_ctx, &pac_blob, &unwrapped_pac)) {
885 /* No pac actually present */
890 /* IF we have the PAC - otherwise we need to get this
891 * data from elsewere - local ldb, or (TODO) lookup of some
897 ret = krb5_parse_name(gensec_gssapi_state->smb_krb5_context->krb5_context,
898 principal_string, &principal);
900 talloc_free(mem_ctx);
901 return NT_STATUS_INVALID_PARAMETER;
904 /* decode and verify the pac */
905 nt_status = kerberos_pac_logon_info(mem_ctx, &logon_info, unwrapped_pac,
906 gensec_gssapi_state->smb_krb5_context->krb5_context,
907 NULL, keyblock, principal, authtime);
908 krb5_free_principal(gensec_gssapi_state->smb_krb5_context->krb5_context, principal);
910 if (NT_STATUS_IS_OK(nt_status)) {
911 union netr_Validation validation;
912 validation.sam3 = &logon_info->info3;
913 nt_status = make_server_info_netlogon_validation(gensec_gssapi_state,
917 if (!NT_STATUS_IS_OK(nt_status)) {
918 talloc_free(mem_ctx);
927 DEBUG(1, ("Unable to use PAC, resorting to local user lookup!\n"));
928 nt_status = sam_get_server_info_principal(mem_ctx, principal_string,
931 if (!NT_STATUS_IS_OK(nt_status)) {
932 talloc_free(mem_ctx);
937 /* references the server_info into the session_info */
938 nt_status = auth_generate_session_info(gensec_gssapi_state, server_info, &session_info);
939 talloc_free(mem_ctx);
940 talloc_free(server_info);
941 NT_STATUS_NOT_OK_RETURN(nt_status);
943 nt_status = gensec_gssapi_session_key(gensec_security, &session_info->session_key);
944 NT_STATUS_NOT_OK_RETURN(nt_status);
946 *_session_info = session_info;
951 static const char *gensec_gssapi_krb5_oids[] = {
952 GENSEC_OID_KERBEROS5,
953 GENSEC_OID_KERBEROS5_OLD,
957 /* As a server, this could in theory accept any GSSAPI mech */
958 static const struct gensec_security_ops gensec_gssapi_krb5_security_ops = {
959 .name = "gssapi_krb5",
960 .auth_type = DCERPC_AUTH_TYPE_KRB5,
961 .oid = gensec_gssapi_krb5_oids,
962 .client_start = gensec_gssapi_client_start,
963 .server_start = gensec_gssapi_server_start,
964 .magic = gensec_gssapi_magic,
965 .update = gensec_gssapi_update,
966 .session_key = gensec_gssapi_session_key,
967 .session_info = gensec_gssapi_session_info,
968 .sig_size = gensec_gssapi_sig_size,
969 .sign_packet = gensec_gssapi_sign_packet,
970 .check_packet = gensec_gssapi_check_packet,
971 .seal_packet = gensec_gssapi_seal_packet,
972 .unseal_packet = gensec_gssapi_unseal_packet,
973 .wrap = gensec_gssapi_wrap,
974 .unwrap = gensec_gssapi_unwrap,
975 .have_feature = gensec_gssapi_have_feature,
979 NTSTATUS gensec_gssapi_init(void)
983 ret = gensec_register(&gensec_gssapi_krb5_security_ops);
984 if (!NT_STATUS_IS_OK(ret)) {
985 DEBUG(0,("Failed to register '%s' gensec backend!\n",
986 gensec_gssapi_krb5_security_ops.name));