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
71 size_t max_wrap_buf_size;
74 static size_t gensec_gssapi_max_input_size(struct gensec_security *gensec_security);
75 static size_t gensec_gssapi_max_wrapped_size(struct gensec_security *gensec_security);
77 static char *gssapi_error_string(TALLOC_CTX *mem_ctx,
78 OM_uint32 maj_stat, OM_uint32 min_stat)
80 OM_uint32 disp_min_stat, disp_maj_stat;
81 gss_buffer_desc maj_error_message;
82 gss_buffer_desc min_error_message;
83 OM_uint32 msg_ctx = 0;
87 maj_error_message.value = NULL;
88 min_error_message.value = NULL;
90 disp_maj_stat = gss_display_status(&disp_min_stat, maj_stat, GSS_C_GSS_CODE,
91 GSS_C_NULL_OID, &msg_ctx, &maj_error_message);
92 disp_maj_stat = gss_display_status(&disp_min_stat, min_stat, GSS_C_MECH_CODE,
93 GSS_C_NULL_OID, &msg_ctx, &min_error_message);
94 ret = talloc_asprintf(mem_ctx, "%s: %s", (char *)maj_error_message.value, (char *)min_error_message.value);
96 gss_release_buffer(&disp_min_stat, &maj_error_message);
97 gss_release_buffer(&disp_min_stat, &min_error_message);
103 static int gensec_gssapi_destory(struct gensec_gssapi_state *gensec_gssapi_state)
105 OM_uint32 maj_stat, min_stat;
107 if (gensec_gssapi_state->delegated_cred_handle != GSS_C_NO_CREDENTIAL) {
108 maj_stat = gss_release_cred(&min_stat,
109 &gensec_gssapi_state->delegated_cred_handle);
112 if (gensec_gssapi_state->gssapi_context != GSS_C_NO_CONTEXT) {
113 maj_stat = gss_delete_sec_context (&min_stat,
114 &gensec_gssapi_state->gssapi_context,
118 if (gensec_gssapi_state->server_name != GSS_C_NO_NAME) {
119 maj_stat = gss_release_name(&min_stat, &gensec_gssapi_state->server_name);
121 if (gensec_gssapi_state->client_name != GSS_C_NO_NAME) {
122 maj_stat = gss_release_name(&min_stat, &gensec_gssapi_state->client_name);
127 static NTSTATUS gensec_gssapi_start(struct gensec_security *gensec_security)
129 struct gensec_gssapi_state *gensec_gssapi_state;
132 gensec_gssapi_state = talloc(gensec_security, struct gensec_gssapi_state);
133 if (!gensec_gssapi_state) {
134 return NT_STATUS_NO_MEMORY;
137 gensec_gssapi_state->max_wrap_buf_size
138 = lp_parm_int(-1, "gensec_gssapi", "max wrap buf size", 65536);
140 gensec_gssapi_state->sasl = False;
141 gensec_gssapi_state->sasl_state = STAGE_GSS_NEG;
143 gensec_security->private_data = gensec_gssapi_state;
145 gensec_gssapi_state->gssapi_context = GSS_C_NO_CONTEXT;
146 gensec_gssapi_state->server_name = GSS_C_NO_NAME;
147 gensec_gssapi_state->client_name = GSS_C_NO_NAME;
149 /* TODO: Fill in channel bindings */
150 gensec_gssapi_state->input_chan_bindings = GSS_C_NO_CHANNEL_BINDINGS;
152 gensec_gssapi_state->want_flags = 0;
153 if (lp_parm_bool(-1, "gensec_gssapi", "mutual", True)) {
154 gensec_gssapi_state->want_flags |= GSS_C_MUTUAL_FLAG;
156 if (lp_parm_bool(-1, "gensec_gssapi", "delegation", True)) {
157 gensec_gssapi_state->want_flags |= GSS_C_DELEG_FLAG;
159 if (lp_parm_bool(-1, "gensec_gssapi", "sequence", True)) {
160 gensec_gssapi_state->want_flags |= GSS_C_SEQUENCE_FLAG;
163 gensec_gssapi_state->got_flags = 0;
165 gensec_gssapi_state->session_key = data_blob(NULL, 0);
166 gensec_gssapi_state->pac = data_blob(NULL, 0);
168 gensec_gssapi_state->delegated_cred_handle = GSS_C_NO_CREDENTIAL;
170 talloc_set_destructor(gensec_gssapi_state, gensec_gssapi_destory);
172 if (gensec_security->want_features & GENSEC_FEATURE_SIGN) {
173 gensec_gssapi_state->want_flags |= GSS_C_INTEG_FLAG;
175 if (gensec_security->want_features & GENSEC_FEATURE_SEAL) {
176 gensec_gssapi_state->want_flags |= GSS_C_CONF_FLAG;
178 if (gensec_security->want_features & GENSEC_FEATURE_DCE_STYLE) {
179 gensec_gssapi_state->want_flags |= GSS_C_DCE_STYLE;
182 gensec_gssapi_state->gss_oid = gss_mech_krb5;
184 ret = smb_krb5_init_context(gensec_gssapi_state,
185 &gensec_gssapi_state->smb_krb5_context);
187 DEBUG(1,("gensec_krb5_start: krb5_init_context failed (%s)\n",
188 error_message(ret)));
189 return NT_STATUS_INTERNAL_ERROR;
194 static NTSTATUS gensec_gssapi_server_start(struct gensec_security *gensec_security)
198 struct gensec_gssapi_state *gensec_gssapi_state;
199 struct cli_credentials *machine_account;
200 struct gssapi_creds_container *gcc;
202 nt_status = gensec_gssapi_start(gensec_security);
203 if (!NT_STATUS_IS_OK(nt_status)) {
207 gensec_gssapi_state = talloc_get_type(gensec_security->private_data, struct gensec_gssapi_state);
209 machine_account = gensec_get_credentials(gensec_security);
211 if (!machine_account) {
212 DEBUG(3, ("No machine account credentials specified\n"));
213 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
215 ret = cli_credentials_get_server_gss_creds(machine_account, &gcc);
217 DEBUG(1, ("Aquiring acceptor credentials failed: %s\n",
218 error_message(ret)));
219 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
223 gensec_gssapi_state->server_cred = gcc;
228 static NTSTATUS gensec_gssapi_sasl_server_start(struct gensec_security *gensec_security)
231 struct gensec_gssapi_state *gensec_gssapi_state;
232 nt_status = gensec_gssapi_server_start(gensec_security);
234 if (NT_STATUS_IS_OK(nt_status)) {
235 gensec_gssapi_state = talloc_get_type(gensec_security->private_data, struct gensec_gssapi_state);
236 gensec_gssapi_state->sasl = True;
241 static NTSTATUS gensec_gssapi_client_start(struct gensec_security *gensec_security)
243 struct gensec_gssapi_state *gensec_gssapi_state;
244 struct cli_credentials *creds = gensec_get_credentials(gensec_security);
247 gss_buffer_desc name_token;
249 OM_uint32 maj_stat, min_stat;
250 const char *hostname = gensec_get_target_hostname(gensec_security);
251 const char *principal;
252 struct gssapi_creds_container *gcc;
255 DEBUG(1, ("Could not determine hostname for target computer, cannot use kerberos\n"));
256 return NT_STATUS_INVALID_PARAMETER;
258 if (is_ipaddress(hostname)) {
259 DEBUG(2, ("Cannot do GSSAPI to an IP address\n"));
260 return NT_STATUS_INVALID_PARAMETER;
262 if (strcmp(hostname, "localhost") == 0) {
263 DEBUG(2, ("GSSAPI to 'localhost' does not make sense\n"));
264 return NT_STATUS_INVALID_PARAMETER;
267 if (((gensec_security->want_features & GENSEC_FEATURE_SIGN)
268 || (gensec_security->want_features & GENSEC_FEATURE_SEAL))
269 && (gensec_security->want_features & GENSEC_FEATURE_DCE_STYLE)
270 && !lp_parm_bool(-1, "gensec_gssapi", "dce_signseal",
271 cli_credentials_get_kerberos_state(creds) == CRED_MUST_USE_KERBEROS)) {
272 DEBUG(2, ("GSSAPI sign/seal disabled for DCE/RPC. "));
273 return NT_STATUS_INVALID_PARAMETER;
276 nt_status = gensec_gssapi_start(gensec_security);
277 if (!NT_STATUS_IS_OK(nt_status)) {
281 gensec_gssapi_state = talloc_get_type(gensec_security->private_data, struct gensec_gssapi_state);
283 principal = gensec_get_target_principal(gensec_security);
284 if (principal && lp_client_use_spnego_principal()) {
285 name_token.value = discard_const_p(uint8_t, principal);
286 name_token.length = strlen(principal);
288 name_type = GSS_C_NULL_OID;
290 principal = talloc_asprintf(gensec_gssapi_state, "%s@%s",
291 gensec_get_target_service(gensec_security),
294 name_token.value = discard_const_p(uint8_t, principal);
295 name_token.length = strlen(principal);
297 name_type = GSS_C_NT_HOSTBASED_SERVICE;
300 maj_stat = gss_import_name (&min_stat,
303 &gensec_gssapi_state->server_name);
305 DEBUG(2, ("GSS Import name of %s failed: %s\n",
306 (char *)name_token.value,
307 gssapi_error_string(gensec_gssapi_state, maj_stat, min_stat)));
308 return NT_STATUS_INVALID_PARAMETER;
311 ret = cli_credentials_get_client_gss_creds(creds, &gcc);
315 case KRB5_KDC_UNREACH:
316 DEBUG(3, ("Cannot reach a KDC we require\n"));
317 return NT_STATUS_INVALID_PARAMETER; /* Make SPNEGO ignore us, we can't go any further here */
319 DEBUG(1, ("Aquiring initiator credentails failed\n"));
320 return NT_STATUS_UNSUCCESSFUL;
323 gensec_gssapi_state->client_cred = gcc;
328 static NTSTATUS gensec_gssapi_sasl_client_start(struct gensec_security *gensec_security)
331 struct gensec_gssapi_state *gensec_gssapi_state;
332 nt_status = gensec_gssapi_client_start(gensec_security);
334 if (NT_STATUS_IS_OK(nt_status)) {
335 gensec_gssapi_state = talloc_get_type(gensec_security->private_data, struct gensec_gssapi_state);
336 gensec_gssapi_state->sasl = True;
343 * Check if the packet is one for this mechansim
345 * @param gensec_security GENSEC state
346 * @param in The request, as a DATA_BLOB
347 * @return Error, INVALID_PARAMETER if it's not a packet for us
348 * or NT_STATUS_OK if the packet is ok.
351 static NTSTATUS gensec_gssapi_magic(struct gensec_security *gensec_security,
354 if (gensec_gssapi_check_oid(in, GENSEC_OID_KERBEROS5)) {
357 return NT_STATUS_INVALID_PARAMETER;
363 * Next state function for the GSSAPI GENSEC mechanism
365 * @param gensec_gssapi_state GSSAPI State
366 * @param out_mem_ctx The TALLOC_CTX for *out to be allocated on
367 * @param in The request, as a DATA_BLOB
368 * @param out The reply, as an talloc()ed DATA_BLOB, on *out_mem_ctx
369 * @return Error, MORE_PROCESSING_REQUIRED if a reply is sent,
370 * or NT_STATUS_OK if the user is authenticated.
373 static NTSTATUS gensec_gssapi_update(struct gensec_security *gensec_security,
374 TALLOC_CTX *out_mem_ctx,
375 const DATA_BLOB in, DATA_BLOB *out)
377 struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
378 NTSTATUS nt_status = NT_STATUS_LOGON_FAILURE;
379 OM_uint32 maj_stat, min_stat;
381 gss_buffer_desc input_token, output_token;
383 input_token.length = in.length;
384 input_token.value = in.data;
386 switch (gensec_gssapi_state->sasl_state) {
389 switch (gensec_security->gensec_role) {
392 maj_stat = gss_init_sec_context(&min_stat,
393 gensec_gssapi_state->client_cred->creds,
394 &gensec_gssapi_state->gssapi_context,
395 gensec_gssapi_state->server_name,
396 discard_const_p(gss_OID_desc, gensec_gssapi_state->gss_oid),
397 gensec_gssapi_state->want_flags,
399 gensec_gssapi_state->input_chan_bindings,
403 &gensec_gssapi_state->got_flags, /* ret flags */
409 maj_stat = gss_accept_sec_context(&min_stat,
410 &gensec_gssapi_state->gssapi_context,
411 gensec_gssapi_state->server_cred->creds,
413 gensec_gssapi_state->input_chan_bindings,
414 &gensec_gssapi_state->client_name,
417 &gensec_gssapi_state->got_flags,
419 &gensec_gssapi_state->delegated_cred_handle);
420 gensec_gssapi_state->gss_oid = gss_oid_p;
424 return NT_STATUS_INVALID_PARAMETER;
428 if (maj_stat == GSS_S_COMPLETE) {
429 *out = data_blob_talloc(out_mem_ctx, output_token.value, output_token.length);
430 gss_release_buffer(&min_stat2, &output_token);
432 if (gensec_gssapi_state->got_flags & GSS_C_DELEG_FLAG) {
433 DEBUG(5, ("gensec_gssapi: credentials were delegated\n"));
435 DEBUG(5, ("gensec_gssapi: NO credentials were delegated\n"));
438 /* We may have been invoked as SASL, so there
439 * is more work to do */
440 if (gensec_gssapi_state->sasl) {
441 /* Due to a very subtle interaction
442 * with SASL and the LDAP libs, we
443 * must ensure the data pointer is
444 * != NULL, but the length is 0.
446 * This ensures we send a 'zero
447 * length' (rather than NULL) response
451 out->data = (uint8_t *)talloc_strdup(out_mem_ctx, "\0");
454 gensec_gssapi_state->sasl_state = STAGE_SASL_SSF_NEG;
455 return NT_STATUS_MORE_PROCESSING_REQUIRED;
457 gensec_gssapi_state->sasl_state = STAGE_DONE;
459 if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
460 DEBUG(5, ("GSSAPI Connection will be cryptographicly sealed\n"));
461 } else if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
462 DEBUG(5, ("GSSAPI Connection will be cryptographicly signed\n"));
464 DEBUG(5, ("GSSAPI Connection will have no cryptographic protection\n"));
469 } else if (maj_stat == GSS_S_CONTINUE_NEEDED) {
470 *out = data_blob_talloc(out_mem_ctx, output_token.value, output_token.length);
471 gss_release_buffer(&min_stat2, &output_token);
473 return NT_STATUS_MORE_PROCESSING_REQUIRED;
474 } else if ((gensec_gssapi_state->gss_oid->length == gss_mech_krb5->length)
475 && (memcmp(gensec_gssapi_state->gss_oid->elements, gss_mech_krb5->elements,
476 gensec_gssapi_state->gss_oid->length) == 0)) {
478 case KRB5_KDC_UNREACH:
479 DEBUG(3, ("Cannot reach a KDC we require: %s\n",
480 gssapi_error_string(gensec_gssapi_state, maj_stat, min_stat)));
481 return NT_STATUS_INVALID_PARAMETER; /* Make SPNEGO ignore us, we can't go any further here */
482 case KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN:
483 DEBUG(3, ("Server is not registered with our KDC: %s\n",
484 gssapi_error_string(gensec_gssapi_state, maj_stat, min_stat)));
485 return NT_STATUS_INVALID_PARAMETER; /* Make SPNEGO ignore us, we can't go any further here */
486 case KRB5KRB_AP_ERR_MSG_TYPE:
487 /* garbage input, possibly from the auto-mech detection */
488 return NT_STATUS_INVALID_PARAMETER;
490 DEBUG(1, ("GSS(krb5) Update failed: %s\n",
491 gssapi_error_string(out_mem_ctx, maj_stat, min_stat)));
495 DEBUG(1, ("GSS Update failed: %s\n",
496 gssapi_error_string(out_mem_ctx, maj_stat, min_stat)));
502 /* These last two stages are only done if we were invoked as SASL */
503 case STAGE_SASL_SSF_NEG:
505 switch (gensec_security->gensec_role) {
508 uint8_t maxlength_proposed[4];
509 uint8_t maxlength_accepted[4];
510 uint8_t security_supported;
513 input_token.length = in.length;
514 input_token.value = in.data;
516 /* As a client, we have just send a
517 * zero-length blob to the server (after the
518 * normal GSSAPI exchange), and it has replied
519 * with it's SASL negotiation */
521 maj_stat = gss_unwrap(&min_stat,
522 gensec_gssapi_state->gssapi_context,
527 if (GSS_ERROR(maj_stat)) {
528 DEBUG(1, ("gensec_gssapi_update: GSS UnWrap of SASL protection negotiation failed: %s\n",
529 gssapi_error_string(out_mem_ctx, maj_stat, min_stat)));
530 return NT_STATUS_ACCESS_DENIED;
533 if (output_token.length < 4) {
534 return NT_STATUS_INVALID_PARAMETER;
537 memcpy(maxlength_proposed, output_token.value, 4);
538 gss_release_buffer(&min_stat, &output_token);
540 /* first byte is the proposed security */
541 security_supported = maxlength_proposed[0];
542 maxlength_proposed[0] = '\0';
544 /* Rest is the proposed max wrap length */
545 gensec_gssapi_state->max_wrap_buf_size = MIN(RIVAL(maxlength_proposed, 0),
546 gensec_gssapi_state->max_wrap_buf_size);
547 gensec_gssapi_state->sasl_protection = 0;
548 if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
549 if (security_supported & NEG_SEAL) {
550 gensec_gssapi_state->sasl_protection |= NEG_SEAL;
552 } else if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
553 if (security_supported & NEG_SIGN) {
554 gensec_gssapi_state->sasl_protection |= NEG_SIGN;
556 } else if (security_supported & NEG_NONE) {
557 gensec_gssapi_state->sasl_protection |= NEG_NONE;
559 DEBUG(1, ("Remote server does not support unprotected connections"));
560 return NT_STATUS_ACCESS_DENIED;
563 /* Send back the negotiated max length */
565 RSIVAL(maxlength_accepted, 0, gensec_gssapi_state->max_wrap_buf_size);
567 maxlength_accepted[0] = gensec_gssapi_state->sasl_protection;
569 input_token.value = maxlength_accepted;
570 input_token.length = sizeof(maxlength_accepted);
572 maj_stat = gss_wrap(&min_stat,
573 gensec_gssapi_state->gssapi_context,
579 if (GSS_ERROR(maj_stat)) {
580 DEBUG(1, ("gensec_gssapi_wrap: GSS Wrap failed: %s\n",
581 gssapi_error_string(out_mem_ctx, maj_stat, min_stat)));
582 return NT_STATUS_ACCESS_DENIED;
585 *out = data_blob_talloc(out_mem_ctx, output_token.value, output_token.length);
586 gss_release_buffer(&min_stat, &output_token);
588 /* quirk: This changes the value that gensec_have_feature returns, to be that after SASL negotiation */
589 gensec_gssapi_state->sasl_state = STAGE_DONE;
591 if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
592 DEBUG(3, ("SASL/GSSAPI Connection to server will be cryptographicly sealed\n"));
593 } else if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
594 DEBUG(3, ("SASL/GSSAPI Connection to server will be cryptographicly signed\n"));
596 DEBUG(3, ("SASL/GSSAPI Connection to server will have no cryptographicly protection\n"));
603 uint8_t maxlength_proposed[4];
604 uint8_t security_supported = 0x0;
607 /* As a server, we have just been sent a zero-length blob (note this, but it isn't fatal) */
608 if (in.length != 0) {
609 DEBUG(1, ("SASL/GSSAPI: client sent non-zero length starting SASL negotiation!\n"));
612 /* Give the client some idea what we will support */
614 RSIVAL(maxlength_proposed, 0, gensec_gssapi_state->max_wrap_buf_size);
615 /* first byte is the proposed security */
616 maxlength_proposed[0] = '\0';
618 gensec_gssapi_state->sasl_protection = 0;
619 if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
620 security_supported |= NEG_SEAL;
622 if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
623 security_supported |= NEG_SIGN;
625 if (security_supported == 0) {
626 /* If we don't support anything, this must be 0 */
627 RSIVAL(maxlength_proposed, 0, 0x0);
630 /* TODO: We may not wish to support this */
631 security_supported |= NEG_NONE;
632 maxlength_proposed[0] = security_supported;
634 input_token.value = maxlength_proposed;
635 input_token.length = sizeof(maxlength_proposed);
637 maj_stat = gss_wrap(&min_stat,
638 gensec_gssapi_state->gssapi_context,
644 if (GSS_ERROR(maj_stat)) {
645 DEBUG(1, ("gensec_gssapi_wrap: GSS Wrap failed: %s\n",
646 gssapi_error_string(out_mem_ctx, maj_stat, min_stat)));
647 return NT_STATUS_ACCESS_DENIED;
650 *out = data_blob_talloc(out_mem_ctx, output_token.value, output_token.length);
651 gss_release_buffer(&min_stat, &output_token);
653 gensec_gssapi_state->sasl_state = STAGE_SASL_SSF_ACCEPT;
654 return NT_STATUS_MORE_PROCESSING_REQUIRED;
657 return NT_STATUS_INVALID_PARAMETER;
661 /* This is s server-only stage */
662 case STAGE_SASL_SSF_ACCEPT:
664 uint8_t maxlength_accepted[4];
665 uint8_t security_accepted;
668 input_token.length = in.length;
669 input_token.value = in.data;
671 maj_stat = gss_unwrap(&min_stat,
672 gensec_gssapi_state->gssapi_context,
677 if (GSS_ERROR(maj_stat)) {
678 DEBUG(1, ("gensec_gssapi_update: GSS UnWrap of SASL protection negotiation failed: %s\n",
679 gssapi_error_string(out_mem_ctx, maj_stat, min_stat)));
680 return NT_STATUS_ACCESS_DENIED;
683 if (output_token.length < 4) {
684 return NT_STATUS_INVALID_PARAMETER;
687 memcpy(maxlength_accepted, output_token.value, 4);
688 gss_release_buffer(&min_stat, &output_token);
690 /* first byte is the proposed security */
691 security_accepted = maxlength_accepted[0];
692 maxlength_accepted[0] = '\0';
694 /* Rest is the proposed max wrap length */
695 gensec_gssapi_state->max_wrap_buf_size = MIN(RIVAL(maxlength_accepted, 0),
696 gensec_gssapi_state->max_wrap_buf_size);
698 gensec_gssapi_state->sasl_protection = 0;
699 if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
700 if (security_accepted & NEG_SEAL) {
701 gensec_gssapi_state->sasl_protection |= NEG_SEAL;
703 } else if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
704 if (security_accepted & NEG_SIGN) {
705 gensec_gssapi_state->sasl_protection |= NEG_SIGN;
707 } else if (security_accepted & NEG_NONE) {
708 gensec_gssapi_state->sasl_protection |= NEG_NONE;
710 DEBUG(1, ("Remote client does not support unprotected connections, but we failed to negotiate anything better"));
711 return NT_STATUS_ACCESS_DENIED;
714 /* quirk: This changes the value that gensec_have_feature returns, to be that after SASL negotiation */
715 gensec_gssapi_state->sasl_state = STAGE_DONE;
716 if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
717 DEBUG(5, ("SASL/GSSAPI Connection from client will be cryptographicly sealed\n"));
718 } else if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
719 DEBUG(5, ("SASL/GSSAPI Connection from client will be cryptographicly signed\n"));
721 DEBUG(5, ("SASL/GSSAPI Connection from client will have no cryptographic protection\n"));
724 *out = data_blob(NULL, 0);
728 return NT_STATUS_INVALID_PARAMETER;
732 static NTSTATUS gensec_gssapi_wrap(struct gensec_security *gensec_security,
737 struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
738 OM_uint32 maj_stat, min_stat;
739 gss_buffer_desc input_token, output_token;
741 input_token.length = in->length;
742 input_token.value = in->data;
744 maj_stat = gss_wrap(&min_stat,
745 gensec_gssapi_state->gssapi_context,
746 gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL),
751 if (GSS_ERROR(maj_stat)) {
752 DEBUG(1, ("gensec_gssapi_wrap: GSS Wrap failed: %s\n",
753 gssapi_error_string(mem_ctx, maj_stat, min_stat)));
754 return NT_STATUS_ACCESS_DENIED;
757 *out = data_blob_talloc(mem_ctx, output_token.value, output_token.length);
758 gss_release_buffer(&min_stat, &output_token);
760 if (gensec_gssapi_state->sasl) {
761 size_t max_wrapped_size = gensec_gssapi_max_wrapped_size(gensec_security);
762 if (max_wrapped_size < out->length) {
763 DEBUG(1, ("gensec_gssapi_wrap: when wrapped, INPUT data (%u) is grew to be larger than SASL negotiated maximum output size (%u > %u)\n",
766 (unsigned int)max_wrapped_size));
767 return NT_STATUS_INVALID_PARAMETER;
771 if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)
773 return NT_STATUS_ACCESS_DENIED;
778 static NTSTATUS gensec_gssapi_unwrap(struct gensec_security *gensec_security,
783 struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
784 OM_uint32 maj_stat, min_stat;
785 gss_buffer_desc input_token, output_token;
788 input_token.length = in->length;
789 input_token.value = in->data;
791 if (gensec_gssapi_state->sasl) {
792 size_t max_wrapped_size = gensec_gssapi_max_wrapped_size(gensec_security);
793 if (max_wrapped_size < in->length) {
794 DEBUG(1, ("gensec_gssapi_unwrap: WRAPPED data is larger than SASL negotiated maximum size\n"));
795 return NT_STATUS_INVALID_PARAMETER;
799 maj_stat = gss_unwrap(&min_stat,
800 gensec_gssapi_state->gssapi_context,
805 if (GSS_ERROR(maj_stat)) {
806 DEBUG(1, ("gensec_gssapi_unwrap: GSS UnWrap failed: %s\n",
807 gssapi_error_string(mem_ctx, maj_stat, min_stat)));
808 return NT_STATUS_ACCESS_DENIED;
811 *out = data_blob_talloc(mem_ctx, output_token.value, output_token.length);
812 gss_release_buffer(&min_stat, &output_token);
814 if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)
816 return NT_STATUS_ACCESS_DENIED;
821 /* Find out the size of the signature, assuming (incorrectly) that it
822 * GSSAPI provides any guarantees as to it's size.
824 * This is needed by the DCE/RPC code, which uses AEAD
825 * (signed headers, including signature legnth and a sealed body)
827 static size_t gensec_gssapi_sig_size(struct gensec_security *gensec_security, size_t data_size)
829 struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
830 OM_uint32 maj_stat, min_stat;
831 OM_uint32 output_size;
832 if ((gensec_gssapi_state->gss_oid->length != gss_mech_krb5->length)
833 || (memcmp(gensec_gssapi_state->gss_oid->elements, gss_mech_krb5->elements,
834 gensec_gssapi_state->gss_oid->length) != 0)) {
835 DEBUG(1, ("NO sig size available for this mech\n"));
839 maj_stat = gsskrb5_wrap_size(&min_stat,
840 gensec_gssapi_state->gssapi_context,
841 gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL),
845 if (GSS_ERROR(maj_stat)) {
846 TALLOC_CTX *mem_ctx = talloc_new(NULL);
847 DEBUG(1, ("gensec_gssapi_sig_size: determinaing signature size with gsskrb5_wrap_size failed: %s\n",
848 gssapi_error_string(mem_ctx, maj_stat, min_stat)));
849 talloc_free(mem_ctx);
853 if (output_size < data_size) {
857 /* The difference between the max output and the max input must be the signature */
858 return output_size - data_size;
861 /* Find out the maximum input size negotiated on this connection */
863 static size_t gensec_gssapi_max_input_size(struct gensec_security *gensec_security)
865 struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
866 OM_uint32 maj_stat, min_stat;
867 OM_uint32 max_input_size;
869 maj_stat = gss_wrap_size_limit(&min_stat,
870 gensec_gssapi_state->gssapi_context,
871 gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL),
873 gensec_gssapi_state->max_wrap_buf_size,
875 if (GSS_ERROR(maj_stat)) {
876 TALLOC_CTX *mem_ctx = talloc_new(NULL);
877 DEBUG(1, ("gensec_gssapi_max_input_size: determinaing signature size with gss_wrap_size_limit failed: %s\n",
878 gssapi_error_string(mem_ctx, maj_stat, min_stat)));
879 talloc_free(mem_ctx);
883 return max_input_size;
886 /* Find out the maximum output size negotiated on this connection */
887 static size_t gensec_gssapi_max_wrapped_size(struct gensec_security *gensec_security)
889 struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
890 return gensec_gssapi_state->max_wrap_buf_size;
893 static NTSTATUS gensec_gssapi_seal_packet(struct gensec_security *gensec_security,
895 uint8_t *data, size_t length,
896 const uint8_t *whole_pdu, size_t pdu_length,
899 struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
900 OM_uint32 maj_stat, min_stat;
901 gss_buffer_desc input_token, output_token;
905 input_token.length = length;
906 input_token.value = data;
908 maj_stat = gss_wrap(&min_stat,
909 gensec_gssapi_state->gssapi_context,
910 gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL),
915 if (GSS_ERROR(maj_stat)) {
916 DEBUG(1, ("gensec_gssapi_seal_packet: GSS Wrap failed: %s\n",
917 gssapi_error_string(mem_ctx, maj_stat, min_stat)));
918 return NT_STATUS_ACCESS_DENIED;
921 sig_length = gensec_gssapi_sig_size(gensec_security, length);
923 /* Caller must pad to right boundary */
924 if (output_token.length != (length + sig_length)) {
925 DEBUG(1, ("gensec_gssapi_seal_packet: GSS Wrap length [%ld] does not match caller length [%ld] plus sig size [%ld] = [%ld]\n",
926 (long)output_token.length, (long)length, (long)sig_length, (long)(length + sig_length)));
927 return NT_STATUS_INTERNAL_ERROR;
930 memcpy(data, ((uint8_t *)output_token.value) + sig_length, length);
931 *sig = data_blob_talloc(mem_ctx, (uint8_t *)output_token.value, sig_length);
933 dump_data_pw("gensec_gssapi_seal_packet: sig\n", sig->data, sig->length);
934 dump_data_pw("gensec_gssapi_seal_packet: clear\n", data, length);
935 dump_data_pw("gensec_gssapi_seal_packet: sealed\n", ((uint8_t *)output_token.value) + sig_length, output_token.length - sig_length);
937 gss_release_buffer(&min_stat, &output_token);
939 if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)
941 return NT_STATUS_ACCESS_DENIED;
946 static NTSTATUS gensec_gssapi_unseal_packet(struct gensec_security *gensec_security,
948 uint8_t *data, size_t length,
949 const uint8_t *whole_pdu, size_t pdu_length,
950 const DATA_BLOB *sig)
952 struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
953 OM_uint32 maj_stat, min_stat;
954 gss_buffer_desc input_token, output_token;
959 dump_data_pw("gensec_gssapi_unseal_packet: sig\n", sig->data, sig->length);
961 in = data_blob_talloc(mem_ctx, NULL, sig->length + length);
963 memcpy(in.data, sig->data, sig->length);
964 memcpy(in.data + sig->length, data, length);
966 input_token.length = in.length;
967 input_token.value = in.data;
969 maj_stat = gss_unwrap(&min_stat,
970 gensec_gssapi_state->gssapi_context,
975 if (GSS_ERROR(maj_stat)) {
976 DEBUG(1, ("gensec_gssapi_unseal_packet: GSS UnWrap failed: %s\n",
977 gssapi_error_string(mem_ctx, maj_stat, min_stat)));
978 return NT_STATUS_ACCESS_DENIED;
981 if (output_token.length != length) {
982 return NT_STATUS_INTERNAL_ERROR;
985 memcpy(data, output_token.value, length);
987 gss_release_buffer(&min_stat, &output_token);
989 if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)
991 return NT_STATUS_ACCESS_DENIED;
996 static NTSTATUS gensec_gssapi_sign_packet(struct gensec_security *gensec_security,
998 const uint8_t *data, size_t length,
999 const uint8_t *whole_pdu, size_t pdu_length,
1002 struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
1003 OM_uint32 maj_stat, min_stat;
1004 gss_buffer_desc input_token, output_token;
1006 ssize_t sig_length = 0;
1008 input_token.length = length;
1009 input_token.value = discard_const_p(uint8_t *, data);
1011 maj_stat = gss_wrap(&min_stat,
1012 gensec_gssapi_state->gssapi_context,
1018 if (GSS_ERROR(maj_stat)) {
1019 DEBUG(1, ("GSS Wrap failed: %s\n",
1020 gssapi_error_string(mem_ctx, maj_stat, min_stat)));
1021 return NT_STATUS_ACCESS_DENIED;
1024 if (output_token.length < length) {
1025 return NT_STATUS_INTERNAL_ERROR;
1028 sig_length = gensec_gssapi_sig_size(gensec_security, length);
1030 /* Caller must pad to right boundary */
1031 if (output_token.length != (length + sig_length)) {
1032 DEBUG(1, ("gensec_gssapi_sign_packet: GSS Wrap length [%ld] does not match caller length [%ld] plus sig size [%ld] = [%ld]\n",
1033 (long)output_token.length, (long)length, (long)sig_length, (long)(length + sig_length)));
1034 return NT_STATUS_INTERNAL_ERROR;
1037 *sig = data_blob_talloc(mem_ctx, (uint8_t *)output_token.value, sig_length);
1039 dump_data_pw("gensec_gssapi_seal_packet: sig\n", sig->data, sig->length);
1041 gss_release_buffer(&min_stat, &output_token);
1043 return NT_STATUS_OK;
1046 static NTSTATUS gensec_gssapi_check_packet(struct gensec_security *gensec_security,
1047 TALLOC_CTX *mem_ctx,
1048 const uint8_t *data, size_t length,
1049 const uint8_t *whole_pdu, size_t pdu_length,
1050 const DATA_BLOB *sig)
1052 struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
1053 OM_uint32 maj_stat, min_stat;
1054 gss_buffer_desc input_token, output_token;
1056 gss_qop_t qop_state;
1059 dump_data_pw("gensec_gssapi_seal_packet: sig\n", sig->data, sig->length);
1061 in = data_blob_talloc(mem_ctx, NULL, sig->length + length);
1063 memcpy(in.data, sig->data, sig->length);
1064 memcpy(in.data + sig->length, data, length);
1066 input_token.length = in.length;
1067 input_token.value = in.data;
1069 maj_stat = gss_unwrap(&min_stat,
1070 gensec_gssapi_state->gssapi_context,
1075 if (GSS_ERROR(maj_stat)) {
1076 DEBUG(1, ("GSS UnWrap failed: %s\n",
1077 gssapi_error_string(mem_ctx, maj_stat, min_stat)));
1078 return NT_STATUS_ACCESS_DENIED;
1081 if (output_token.length != length) {
1082 return NT_STATUS_INTERNAL_ERROR;
1085 gss_release_buffer(&min_stat, &output_token);
1087 return NT_STATUS_OK;
1090 /* Try to figure out what features we actually got on the connection */
1091 static BOOL gensec_gssapi_have_feature(struct gensec_security *gensec_security,
1094 struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
1095 if (feature & GENSEC_FEATURE_SIGN) {
1096 /* If we are going GSSAPI SASL, then we honour the second negotiation */
1097 if (gensec_gssapi_state->sasl
1098 && gensec_gssapi_state->sasl_state == STAGE_DONE) {
1099 return ((gensec_gssapi_state->sasl_protection & NEG_SIGN)
1100 && (gensec_gssapi_state->got_flags & GSS_C_INTEG_FLAG));
1102 return gensec_gssapi_state->got_flags & GSS_C_INTEG_FLAG;
1104 if (feature & GENSEC_FEATURE_SEAL) {
1105 /* If we are going GSSAPI SASL, then we honour the second negotiation */
1106 if (gensec_gssapi_state->sasl
1107 && gensec_gssapi_state->sasl_state == STAGE_DONE) {
1108 return ((gensec_gssapi_state->sasl_protection & NEG_SEAL)
1109 && (gensec_gssapi_state->got_flags & GSS_C_CONF_FLAG));
1111 return gensec_gssapi_state->got_flags & GSS_C_CONF_FLAG;
1113 if (feature & GENSEC_FEATURE_SESSION_KEY) {
1114 /* Only for GSSAPI/Krb5 */
1115 if ((gensec_gssapi_state->gss_oid->length == gss_mech_krb5->length)
1116 && (memcmp(gensec_gssapi_state->gss_oid->elements, gss_mech_krb5->elements, gensec_gssapi_state->gss_oid->length) == 0)) {
1120 if (feature & GENSEC_FEATURE_DCE_STYLE) {
1121 return gensec_gssapi_state->got_flags & GSS_C_DCE_STYLE;
1123 /* We can always do async (rather than strict request/reply) packets. */
1124 if (feature & GENSEC_FEATURE_ASYNC_REPLIES) {
1131 * Extract the 'sesssion key' needed by SMB signing and ncacn_np
1132 * (for encrypting some passwords).
1134 * This breaks all the abstractions, but what do you expect...
1136 static NTSTATUS gensec_gssapi_session_key(struct gensec_security *gensec_security,
1137 DATA_BLOB *session_key)
1139 struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
1141 if (gensec_gssapi_state->session_key.data) {
1142 *session_key = gensec_gssapi_state->session_key;
1143 return NT_STATUS_OK;
1146 /* Ensure we only call this for GSSAPI/krb5, otherwise things
1147 * could get very ugly */
1148 if ((gensec_gssapi_state->gss_oid->length == gss_mech_krb5->length)
1149 && (memcmp(gensec_gssapi_state->gss_oid->elements, gss_mech_krb5->elements,
1150 gensec_gssapi_state->gss_oid->length) == 0)) {
1151 OM_uint32 maj_stat, min_stat;
1152 gss_buffer_desc skey;
1154 maj_stat = gsskrb5_get_initiator_subkey(&min_stat,
1155 gensec_gssapi_state->gssapi_context,
1158 if (maj_stat == 0) {
1159 DEBUG(10, ("Got KRB5 session key of length %d\n",
1161 gensec_gssapi_state->session_key = data_blob_talloc(gensec_gssapi_state,
1162 skey.value, skey.length);
1163 *session_key = gensec_gssapi_state->session_key;
1164 dump_data_pw("KRB5 Session Key:\n", session_key->data, session_key->length);
1166 gss_release_buffer(&min_stat, &skey);
1167 return NT_STATUS_OK;
1169 return NT_STATUS_NO_USER_SESSION_KEY;
1172 DEBUG(1, ("NO session key for this mech\n"));
1173 return NT_STATUS_NO_USER_SESSION_KEY;
1177 /* Get some basic (and authorization) information about the user on
1178 * this session. This uses either the PAC (if present) or a local
1179 * database lookup */
1180 static NTSTATUS gensec_gssapi_session_info(struct gensec_security *gensec_security,
1181 struct auth_session_info **_session_info)
1184 TALLOC_CTX *mem_ctx;
1185 struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
1186 struct auth_serversupplied_info *server_info = NULL;
1187 struct auth_session_info *session_info = NULL;
1188 struct PAC_LOGON_INFO *logon_info;
1189 OM_uint32 maj_stat, min_stat;
1190 gss_buffer_desc name_token;
1191 gss_buffer_desc pac;
1192 krb5_keyblock *keyblock;
1194 krb5_principal principal;
1195 char *principal_string;
1198 if ((gensec_gssapi_state->gss_oid->length != gss_mech_krb5->length)
1199 || (memcmp(gensec_gssapi_state->gss_oid->elements, gss_mech_krb5->elements,
1200 gensec_gssapi_state->gss_oid->length) != 0)) {
1201 DEBUG(1, ("NO session info available for this mech\n"));
1202 return NT_STATUS_INVALID_PARAMETER;
1205 mem_ctx = talloc_named(gensec_gssapi_state, 0, "gensec_gssapi_session_info context");
1206 NT_STATUS_HAVE_NO_MEMORY(mem_ctx);
1208 maj_stat = gss_display_name (&min_stat,
1209 gensec_gssapi_state->client_name,
1213 talloc_free(mem_ctx);
1214 return NT_STATUS_FOOBAR;
1217 principal_string = talloc_strndup(mem_ctx, name_token.value, name_token.length);
1219 gss_release_buffer(&min_stat, &name_token);
1221 if (!principal_string) {
1222 talloc_free(mem_ctx);
1223 return NT_STATUS_NO_MEMORY;
1226 maj_stat = gss_krb5_copy_service_keyblock(&min_stat,
1227 gensec_gssapi_state->gssapi_context,
1230 if (maj_stat == 0) {
1231 maj_stat = gsskrb5_extract_authtime_from_sec_context(&min_stat,
1232 gensec_gssapi_state->gssapi_context,
1236 if (maj_stat == 0) {
1237 maj_stat = gsskrb5_extract_authz_data_from_sec_context(&min_stat,
1238 gensec_gssapi_state->gssapi_context,
1239 KRB5_AUTHDATA_WIN2K_PAC,
1243 if (maj_stat == 0) {
1244 pac_blob = data_blob_talloc(mem_ctx, pac.value, pac.length);
1245 gss_release_buffer(&min_stat, &pac);
1248 /* IF we have the PAC - otherwise we need to get this
1249 * data from elsewere - local ldb, or (TODO) lookup of some
1252 if (maj_stat == 0) {
1253 krb5_error_code ret;
1255 ret = krb5_parse_name(gensec_gssapi_state->smb_krb5_context->krb5_context,
1256 principal_string, &principal);
1258 talloc_free(mem_ctx);
1259 return NT_STATUS_INVALID_PARAMETER;
1262 /* decode and verify the pac */
1263 nt_status = kerberos_pac_logon_info(mem_ctx, &logon_info, pac_blob,
1264 gensec_gssapi_state->smb_krb5_context->krb5_context,
1265 NULL, keyblock, principal, authtime, NULL);
1266 krb5_free_principal(gensec_gssapi_state->smb_krb5_context->krb5_context, principal);
1268 if (NT_STATUS_IS_OK(nt_status)) {
1269 union netr_Validation validation;
1270 validation.sam3 = &logon_info->info3;
1271 nt_status = make_server_info_netlogon_validation(gensec_gssapi_state,
1275 if (!NT_STATUS_IS_OK(nt_status)) {
1276 talloc_free(mem_ctx);
1285 DEBUG(1, ("Unable to use PAC, resorting to local user lookup!\n"));
1286 nt_status = sam_get_server_info_principal(mem_ctx, principal_string,
1289 if (!NT_STATUS_IS_OK(nt_status)) {
1290 talloc_free(mem_ctx);
1295 /* references the server_info into the session_info */
1296 nt_status = auth_generate_session_info(mem_ctx, server_info, &session_info);
1297 if (!NT_STATUS_IS_OK(nt_status)) {
1298 talloc_free(mem_ctx);
1302 nt_status = gensec_gssapi_session_key(gensec_security, &session_info->session_key);
1303 if (!NT_STATUS_IS_OK(nt_status)) {
1304 talloc_free(mem_ctx);
1308 if (!(gensec_gssapi_state->got_flags & GSS_C_DELEG_FLAG)) {
1309 DEBUG(10, ("gensec_gssapi: NO delegated credentials supplied by client\n"));
1311 krb5_error_code ret;
1312 DEBUG(10, ("gensec_gssapi: delegated credentials supplied by client\n"));
1313 session_info->credentials = cli_credentials_init(session_info);
1314 if (!session_info->credentials) {
1315 talloc_free(mem_ctx);
1316 return NT_STATUS_NO_MEMORY;
1319 cli_credentials_set_conf(session_info->credentials);
1321 ret = cli_credentials_set_client_gss_creds(session_info->credentials,
1322 gensec_gssapi_state->delegated_cred_handle,
1325 talloc_free(mem_ctx);
1326 return NT_STATUS_NO_MEMORY;
1328 /* It has been taken from this place... */
1329 gensec_gssapi_state->delegated_cred_handle = GSS_C_NO_CREDENTIAL;
1331 talloc_steal(gensec_gssapi_state, session_info);
1332 talloc_free(mem_ctx);
1333 *_session_info = session_info;
1335 return NT_STATUS_OK;
1338 static const char *gensec_gssapi_krb5_oids[] = {
1339 GENSEC_OID_KERBEROS5,
1340 GENSEC_OID_KERBEROS5_OLD,
1344 /* As a server, this could in theory accept any GSSAPI mech */
1345 static const struct gensec_security_ops gensec_gssapi_krb5_security_ops = {
1346 .name = "gssapi_krb5",
1347 .auth_type = DCERPC_AUTH_TYPE_KRB5,
1348 .oid = gensec_gssapi_krb5_oids,
1349 .client_start = gensec_gssapi_client_start,
1350 .server_start = gensec_gssapi_server_start,
1351 .magic = gensec_gssapi_magic,
1352 .update = gensec_gssapi_update,
1353 .session_key = gensec_gssapi_session_key,
1354 .session_info = gensec_gssapi_session_info,
1355 .sig_size = gensec_gssapi_sig_size,
1356 .sign_packet = gensec_gssapi_sign_packet,
1357 .check_packet = gensec_gssapi_check_packet,
1358 .seal_packet = gensec_gssapi_seal_packet,
1359 .unseal_packet = gensec_gssapi_unseal_packet,
1360 .wrap = gensec_gssapi_wrap,
1361 .unwrap = gensec_gssapi_unwrap,
1362 .have_feature = gensec_gssapi_have_feature,
1365 .priority = GENSEC_GSSAPI
1368 /* As a server, this could in theory accept any GSSAPI mech */
1369 static const struct gensec_security_ops gensec_gssapi_sasl_krb5_security_ops = {
1370 .name = "gssapi_krb5_sasl",
1371 .sasl_name = "GSSAPI",
1372 .client_start = gensec_gssapi_sasl_client_start,
1373 .server_start = gensec_gssapi_sasl_server_start,
1374 .update = gensec_gssapi_update,
1375 .session_key = gensec_gssapi_session_key,
1376 .session_info = gensec_gssapi_session_info,
1377 .max_input_size = gensec_gssapi_max_input_size,
1378 .max_wrapped_size = gensec_gssapi_max_wrapped_size,
1379 .wrap = gensec_gssapi_wrap,
1380 .unwrap = gensec_gssapi_unwrap,
1381 .have_feature = gensec_gssapi_have_feature,
1384 .priority = GENSEC_GSSAPI
1387 NTSTATUS gensec_gssapi_init(void)
1391 ret = gensec_register(&gensec_gssapi_krb5_security_ops);
1392 if (!NT_STATUS_IS_OK(ret)) {
1393 DEBUG(0,("Failed to register '%s' gensec backend!\n",
1394 gensec_gssapi_krb5_security_ops.name));
1398 ret = gensec_register(&gensec_gssapi_sasl_krb5_security_ops);
1399 if (!NT_STATUS_IS_OK(ret)) {
1400 DEBUG(0,("Failed to register '%s' gensec backend!\n",
1401 gensec_gssapi_sasl_krb5_security_ops.name));