2 Unix SMB/CIFS implementation.
4 RFC2478 Compliant SPNEGO implementation
6 Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2003
7 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004
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 "auth/auth.h"
29 #define DBGC_CLASS DBGC_AUTH
31 enum spnego_state_position {
42 enum spnego_message_type expected_packet;
43 enum spnego_state_position state_position;
44 struct gensec_security *sub_sec_security;
48 static NTSTATUS gensec_spnego_client_start(struct gensec_security *gensec_security)
50 struct spnego_state *spnego_state;
52 spnego_state = talloc_p(gensec_security, struct spnego_state);
54 return NT_STATUS_NO_MEMORY;
57 spnego_state->expected_packet = SPNEGO_NEG_TOKEN_INIT;
58 spnego_state->state_position = SPNEGO_CLIENT_START;
59 spnego_state->sub_sec_security = NULL;
61 gensec_security->private_data = spnego_state;
65 static NTSTATUS gensec_spnego_server_start(struct gensec_security *gensec_security)
67 struct spnego_state *spnego_state;
69 spnego_state = talloc_p(gensec_security, struct spnego_state);
71 return NT_STATUS_NO_MEMORY;
74 spnego_state->expected_packet = SPNEGO_NEG_TOKEN_INIT;
75 spnego_state->state_position = SPNEGO_SERVER_START;
76 spnego_state->sub_sec_security = NULL;
78 gensec_security->private_data = spnego_state;
83 wrappers for the spnego_*() functions
85 static NTSTATUS gensec_spnego_unseal_packet(struct gensec_security *gensec_security,
87 uint8_t *data, size_t length,
88 const uint8_t *whole_pdu, size_t pdu_length,
91 struct spnego_state *spnego_state = gensec_security->private_data;
93 if (spnego_state->state_position != SPNEGO_DONE
94 && spnego_state->state_position != SPNEGO_FALLBACK) {
95 return NT_STATUS_INVALID_PARAMETER;
98 return gensec_unseal_packet(spnego_state->sub_sec_security,
101 whole_pdu, pdu_length,
105 static NTSTATUS gensec_spnego_check_packet(struct gensec_security *gensec_security,
107 const uint8_t *data, size_t length,
108 const uint8_t *whole_pdu, size_t pdu_length,
109 const DATA_BLOB *sig)
111 struct spnego_state *spnego_state = gensec_security->private_data;
113 if (spnego_state->state_position != SPNEGO_DONE
114 && spnego_state->state_position != SPNEGO_FALLBACK) {
115 return NT_STATUS_INVALID_PARAMETER;
118 return gensec_check_packet(spnego_state->sub_sec_security,
121 whole_pdu, pdu_length,
125 static NTSTATUS gensec_spnego_seal_packet(struct gensec_security *gensec_security,
127 uint8_t *data, size_t length,
128 const uint8_t *whole_pdu, size_t pdu_length,
131 struct spnego_state *spnego_state = gensec_security->private_data;
133 if (spnego_state->state_position != SPNEGO_DONE
134 && spnego_state->state_position != SPNEGO_FALLBACK) {
135 return NT_STATUS_INVALID_PARAMETER;
138 return gensec_seal_packet(spnego_state->sub_sec_security,
141 whole_pdu, pdu_length,
145 static NTSTATUS gensec_spnego_sign_packet(struct gensec_security *gensec_security,
147 const uint8_t *data, size_t length,
148 const uint8_t *whole_pdu, size_t pdu_length,
151 struct spnego_state *spnego_state = gensec_security->private_data;
153 if (spnego_state->state_position != SPNEGO_DONE
154 && spnego_state->state_position != SPNEGO_FALLBACK) {
155 return NT_STATUS_INVALID_PARAMETER;
158 return gensec_sign_packet(spnego_state->sub_sec_security,
161 whole_pdu, pdu_length,
165 static NTSTATUS gensec_spnego_wrap(struct gensec_security *gensec_security,
170 struct spnego_state *spnego_state = gensec_security->private_data;
172 if (spnego_state->state_position != SPNEGO_DONE
173 && spnego_state->state_position != SPNEGO_FALLBACK) {
174 DEBUG(1, ("gensec_spnego_wrap: wrong state for wrap\n"));
175 return NT_STATUS_INVALID_PARAMETER;
178 return gensec_wrap(spnego_state->sub_sec_security,
182 static NTSTATUS gensec_spnego_unwrap(struct gensec_security *gensec_security,
187 struct spnego_state *spnego_state = gensec_security->private_data;
189 if (spnego_state->state_position != SPNEGO_DONE
190 && spnego_state->state_position != SPNEGO_FALLBACK) {
191 DEBUG(1, ("gensec_spnego_unwrap: wrong state for unwrap\n"));
192 return NT_STATUS_INVALID_PARAMETER;
195 return gensec_unwrap(spnego_state->sub_sec_security,
199 static size_t gensec_spnego_sig_size(struct gensec_security *gensec_security)
201 struct spnego_state *spnego_state = gensec_security->private_data;
203 if (spnego_state->state_position != SPNEGO_DONE
204 && spnego_state->state_position != SPNEGO_FALLBACK) {
208 return gensec_sig_size(spnego_state->sub_sec_security);
211 static NTSTATUS gensec_spnego_session_key(struct gensec_security *gensec_security,
212 DATA_BLOB *session_key)
214 struct spnego_state *spnego_state = gensec_security->private_data;
215 if (!spnego_state->sub_sec_security) {
216 return NT_STATUS_INVALID_PARAMETER;
219 return gensec_session_key(spnego_state->sub_sec_security,
223 static NTSTATUS gensec_spnego_session_info(struct gensec_security *gensec_security,
224 struct auth_session_info **session_info)
226 struct spnego_state *spnego_state = gensec_security->private_data;
227 if (!spnego_state->sub_sec_security) {
228 return NT_STATUS_INVALID_PARAMETER;
231 return gensec_session_info(spnego_state->sub_sec_security,
235 /** Fallback to another GENSEC mechanism, based on magic strings
237 * This is the 'fallback' case, where we don't get SPNEGO, and have to
238 * try all the other options (and hope they all have a magic string
242 static NTSTATUS gensec_spnego_server_try_fallback(struct gensec_security *gensec_security,
243 struct spnego_state *spnego_state,
244 TALLOC_CTX *out_mem_ctx,
245 const DATA_BLOB in, DATA_BLOB *out)
249 const struct gensec_security_ops **all_ops = gensec_security_all(&num_ops);
250 for (i=0; i < num_ops; i++) {
252 if (!all_ops[i]->oid) {
255 if (strcasecmp(GENSEC_OID_SPNEGO,all_ops[i]->oid) == 0) {
259 nt_status = gensec_subcontext_start(spnego_state,
261 &spnego_state->sub_sec_security);
262 if (!NT_STATUS_IS_OK(nt_status)) {
265 /* select the sub context */
266 nt_status = gensec_start_mech_by_oid(spnego_state->sub_sec_security,
268 if (!NT_STATUS_IS_OK(nt_status)) {
269 talloc_free(spnego_state->sub_sec_security);
270 spnego_state->sub_sec_security = NULL;
273 nt_status = gensec_update(spnego_state->sub_sec_security,
274 out_mem_ctx, in, out);
275 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
276 spnego_state->state_position = SPNEGO_FALLBACK;
279 talloc_free(spnego_state->sub_sec_security);
280 spnego_state->sub_sec_security = NULL;
282 DEBUG(1, ("Failed to parse SPNEGO request\n"));
283 return NT_STATUS_INVALID_PARAMETER;
287 static NTSTATUS gensec_spnego_parse_negTokenInit(struct gensec_security *gensec_security,
288 struct spnego_state *spnego_state,
289 TALLOC_CTX *out_mem_ctx,
290 const char **mechType,
291 const DATA_BLOB unwrapped_in, DATA_BLOB *unwrapped_out)
295 DATA_BLOB null_data_blob = data_blob(NULL,0);
297 for (i=0; mechType && mechType[i]; i++) {
298 nt_status = gensec_subcontext_start(spnego_state,
300 &spnego_state->sub_sec_security);
301 if (!NT_STATUS_IS_OK(nt_status)) {
304 /* select the sub context */
305 nt_status = gensec_start_mech_by_oid(spnego_state->sub_sec_security,
307 if (!NT_STATUS_IS_OK(nt_status)) {
308 talloc_free(spnego_state->sub_sec_security);
309 spnego_state->sub_sec_security = NULL;
314 nt_status = gensec_update(spnego_state->sub_sec_security,
319 /* only get the helping start blob for the first OID */
320 nt_status = gensec_update(spnego_state->sub_sec_security,
325 if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED) && !NT_STATUS_IS_OK(nt_status)) {
326 DEBUG(1, ("SPNEGO(%s) NEG_TOKEN_INIT failed: %s\n",
327 spnego_state->sub_sec_security->ops->name, nt_errstr(nt_status)));
328 talloc_free(spnego_state->sub_sec_security);
329 spnego_state->sub_sec_security = NULL;
333 if (!mechType || !mechType[i]) {
334 DEBUG(1, ("SPNEGO: Could not find a suitable mechtype in NEG_TOKEN_INIT\n"));
336 return NT_STATUS_INVALID_PARAMETER;
339 /** create a client negTokenInit
341 * This is the case, where the client is the first one who sends data
344 static NTSTATUS gensec_spnego_client_negTokenInit(struct gensec_security *gensec_security,
345 struct spnego_state *spnego_state,
346 TALLOC_CTX *out_mem_ctx,
347 const DATA_BLOB in, DATA_BLOB *out)
349 DATA_BLOB null_data_blob = data_blob(NULL,0);
351 const char **mechTypes = NULL;
352 DATA_BLOB unwrapped_out = data_blob(NULL,0);
354 mechTypes = gensec_security_oids(out_mem_ctx, GENSEC_OID_SPNEGO);
357 DEBUG(1, ("no GENSEC OID backends available\n"));
358 return NT_STATUS_INVALID_PARAMETER;
361 nt_status = gensec_subcontext_start(spnego_state,
363 &spnego_state->sub_sec_security);
364 if (!NT_STATUS_IS_OK(nt_status)) {
367 /* select our preferred mech */
368 nt_status = gensec_start_mech_by_oid(spnego_state->sub_sec_security,
370 if (!NT_STATUS_IS_OK(nt_status)) {
371 talloc_free(spnego_state->sub_sec_security);
372 spnego_state->sub_sec_security = NULL;
375 nt_status = gensec_update(spnego_state->sub_sec_security,
376 out_mem_ctx, in, &unwrapped_out);
377 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
378 struct spnego_data spnego_out;
379 spnego_out.type = SPNEGO_NEG_TOKEN_INIT;
380 spnego_out.negTokenInit.mechTypes = mechTypes;
381 spnego_out.negTokenInit.reqFlags = 0;
382 spnego_out.negTokenInit.mechListMIC = null_data_blob;
383 spnego_out.negTokenInit.mechToken = unwrapped_out;
385 if (spnego_write_data(out_mem_ctx, out, &spnego_out) == -1) {
386 DEBUG(1, ("Failed to write SPNEGO reply to NEG_TOKEN_INIT\n"));
387 return NT_STATUS_INVALID_PARAMETER;
391 spnego_state->expected_packet = SPNEGO_NEG_TOKEN_TARG;
392 spnego_state->state_position = SPNEGO_CLIENT_TARG;
395 talloc_free(spnego_state->sub_sec_security);
396 spnego_state->sub_sec_security = NULL;
398 DEBUG(1, ("Failed to setup SPNEGO negTokenInit request: %s\n", nt_errstr(nt_status)));
399 return NT_STATUS_INVALID_PARAMETER;
403 /** create a client negTokenTarg
405 * This is the case, where the client is the first one who sends data
408 static NTSTATUS gensec_spnego_server_negTokenTarg(struct gensec_security *gensec_security,
409 struct spnego_state *spnego_state,
410 TALLOC_CTX *out_mem_ctx,
412 const DATA_BLOB unwrapped_out, DATA_BLOB *out)
414 struct spnego_data spnego_out;
415 DATA_BLOB null_data_blob = data_blob(NULL, 0);
418 spnego_out.type = SPNEGO_NEG_TOKEN_TARG;
419 spnego_out.negTokenTarg.responseToken = unwrapped_out;
420 spnego_out.negTokenTarg.mechListMIC = null_data_blob;
421 spnego_out.negTokenTarg.supportedMech = NULL;
423 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
424 spnego_out.negTokenTarg.supportedMech
425 = spnego_state->sub_sec_security->ops->oid;
426 spnego_out.negTokenTarg.negResult = SPNEGO_ACCEPT_INCOMPLETE;
427 spnego_state->state_position = SPNEGO_SERVER_TARG;
428 } else if (NT_STATUS_IS_OK(nt_status)) {
429 if (unwrapped_out.data) {
430 spnego_out.negTokenTarg.supportedMech
431 = spnego_state->sub_sec_security->ops->oid;
433 spnego_out.negTokenTarg.negResult = SPNEGO_ACCEPT_COMPLETED;
434 spnego_state->state_position = SPNEGO_DONE;
436 spnego_out.negTokenTarg.negResult = SPNEGO_REJECT;
437 DEBUG(2, ("SPNEGO login failed: %s\n", nt_errstr(nt_status)));
438 spnego_state->state_position = SPNEGO_DONE;
441 if (spnego_write_data(out_mem_ctx, out, &spnego_out) == -1) {
442 DEBUG(1, ("Failed to write SPNEGO reply to NEG_TOKEN_TARG\n"));
443 return NT_STATUS_INVALID_PARAMETER;
446 spnego_state->expected_packet = SPNEGO_NEG_TOKEN_TARG;
452 static NTSTATUS gensec_spnego_update(struct gensec_security *gensec_security, TALLOC_CTX *out_mem_ctx,
453 const DATA_BLOB in, DATA_BLOB *out)
455 struct spnego_state *spnego_state = gensec_security->private_data;
456 DATA_BLOB null_data_blob = data_blob(NULL, 0);
457 DATA_BLOB unwrapped_out = data_blob(NULL, 0);
458 struct spnego_data spnego_out;
459 struct spnego_data spnego;
463 *out = data_blob(NULL, 0);
466 out_mem_ctx = spnego_state;
469 /* and switch into the state machine */
471 switch (spnego_state->state_position) {
472 case SPNEGO_FALLBACK:
473 return gensec_update(spnego_state->sub_sec_security,
474 out_mem_ctx, in, out);
475 case SPNEGO_SERVER_START:
480 len = spnego_read_data(in, &spnego);
482 return gensec_spnego_server_try_fallback(gensec_security, spnego_state, out_mem_ctx, in, out);
484 /* client sent NegTargetInit, we send NegTokenTarg */
486 /* OK, so it's real SPNEGO, check the packet's the one we expect */
487 if (spnego.type != spnego_state->expected_packet) {
488 DEBUG(1, ("Invalid SPNEGO request: %d, expected %d\n", spnego.type,
489 spnego_state->expected_packet));
490 dump_data(1, in.data, in.length);
491 spnego_free_data(&spnego);
492 return NT_STATUS_INVALID_PARAMETER;
495 nt_status = gensec_spnego_parse_negTokenInit(gensec_security,
498 spnego.negTokenInit.mechTypes,
499 spnego.negTokenInit.mechToken,
502 nt_status = gensec_spnego_server_negTokenTarg(gensec_security,
509 spnego_free_data(&spnego);
513 const char **mechlist = gensec_security_oids(out_mem_ctx, GENSEC_OID_SPNEGO);
515 spnego_out.type = SPNEGO_NEG_TOKEN_INIT;
516 spnego_out.negTokenInit.mechTypes = mechlist;
517 spnego_out.negTokenInit.reqFlags = 0;
518 spnego_out.negTokenInit.mechListMIC
519 = data_blob_string_const(gensec_get_target_principal(gensec_security));
520 spnego_out.negTokenInit.mechToken = unwrapped_out;
522 if (spnego_write_data(out_mem_ctx, out, &spnego_out) == -1) {
523 DEBUG(1, ("Failed to write SPNEGO reply to NEG_TOKEN_INIT\n"));
524 return NT_STATUS_INVALID_PARAMETER;
528 spnego_state->expected_packet = SPNEGO_NEG_TOKEN_TARG;
529 spnego_state->state_position = SPNEGO_SERVER_TARG;
531 return NT_STATUS_MORE_PROCESSING_REQUIRED;
535 case SPNEGO_CLIENT_START:
537 /* The server offers a list of mechanisms */
539 const char *my_mechs[] = {NULL, NULL};
540 NTSTATUS nt_status = NT_STATUS_INVALID_PARAMETER;
543 /* client to produce negTokenInit */
544 return gensec_spnego_client_negTokenInit(gensec_security, spnego_state,
545 out_mem_ctx, in, out);
548 len = spnego_read_data(in, &spnego);
551 DEBUG(1, ("Invalid SPNEGO request:\n"));
552 dump_data(1, in.data, in.length);
553 return NT_STATUS_INVALID_PARAMETER;
556 /* OK, so it's real SPNEGO, check the packet's the one we expect */
557 if (spnego.type != spnego_state->expected_packet) {
558 DEBUG(1, ("Invalid SPNEGO request: %d, expected %d\n", spnego.type,
559 spnego_state->expected_packet));
560 dump_data(1, in.data, in.length);
561 spnego_free_data(&spnego);
562 return NT_STATUS_INVALID_PARAMETER;
565 if (spnego.negTokenInit.targetPrincipal) {
566 DEBUG(5, ("Server claims it's principal name is %s\n", spnego.negTokenInit.targetPrincipal));
567 nt_status = gensec_set_target_principal(gensec_security,
568 spnego.negTokenInit.targetPrincipal);
569 if (!NT_STATUS_IS_OK(nt_status)) {
570 spnego_free_data(&spnego);
575 nt_status = gensec_spnego_parse_negTokenInit(gensec_security,
578 spnego.negTokenInit.mechTypes,
579 spnego.negTokenInit.mechToken,
582 if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED) && !NT_STATUS_IS_OK(nt_status)) {
583 spnego_free_data(&spnego);
588 my_mechs[0] = spnego_state->sub_sec_security->ops->oid;
590 spnego_out.type = SPNEGO_NEG_TOKEN_INIT;
591 spnego_out.negTokenInit.mechTypes = my_mechs;
592 spnego_out.negTokenInit.reqFlags = 0;
593 spnego_out.negTokenInit.mechListMIC = null_data_blob;
594 spnego_out.negTokenInit.mechToken = unwrapped_out;
596 if (spnego_write_data(out_mem_ctx, out, &spnego_out) == -1) {
597 DEBUG(1, ("Failed to write SPNEGO reply to NEG_TOKEN_INIT\n"));
598 return NT_STATUS_INVALID_PARAMETER;
602 spnego_state->expected_packet = SPNEGO_NEG_TOKEN_TARG;
603 spnego_state->state_position = SPNEGO_CLIENT_TARG;
605 return NT_STATUS_MORE_PROCESSING_REQUIRED;
607 case SPNEGO_SERVER_TARG:
611 return NT_STATUS_INVALID_PARAMETER;
614 len = spnego_read_data(in, &spnego);
617 DEBUG(1, ("Invalid SPNEGO request:\n"));
618 dump_data(1, in.data, in.length);
619 return NT_STATUS_INVALID_PARAMETER;
622 /* OK, so it's real SPNEGO, check the packet's the one we expect */
623 if (spnego.type != spnego_state->expected_packet) {
624 DEBUG(1, ("Invalid SPNEGO request: %d, expected %d\n", spnego.type,
625 spnego_state->expected_packet));
626 dump_data(1, in.data, in.length);
627 spnego_free_data(&spnego);
628 return NT_STATUS_INVALID_PARAMETER;
631 nt_status = gensec_update(spnego_state->sub_sec_security,
633 spnego.negTokenTarg.responseToken,
636 nt_status = gensec_spnego_server_negTokenTarg(gensec_security,
643 spnego_free_data(&spnego);
647 case SPNEGO_CLIENT_TARG:
651 return NT_STATUS_INVALID_PARAMETER;
654 len = spnego_read_data(in, &spnego);
657 DEBUG(1, ("Invalid SPNEGO request:\n"));
658 dump_data(1, in.data, in.length);
659 return NT_STATUS_INVALID_PARAMETER;
662 /* OK, so it's real SPNEGO, check the packet's the one we expect */
663 if (spnego.type != spnego_state->expected_packet) {
664 DEBUG(1, ("Invalid SPNEGO request: %d, expected %d\n", spnego.type,
665 spnego_state->expected_packet));
666 dump_data(1, in.data, in.length);
667 spnego_free_data(&spnego);
668 return NT_STATUS_INVALID_PARAMETER;
671 if (spnego.negTokenTarg.negResult == SPNEGO_REJECT) {
672 return NT_STATUS_ACCESS_DENIED;
675 nt_status = gensec_update(spnego_state->sub_sec_security,
677 spnego.negTokenTarg.responseToken,
681 if (NT_STATUS_IS_OK(nt_status)
682 && (spnego.negTokenTarg.negResult != SPNEGO_ACCEPT_COMPLETED)) {
683 DEBUG(1,("gensec_update ok but not accepted\n"));
684 nt_status = NT_STATUS_INVALID_PARAMETER;
687 spnego_free_data(&spnego);
689 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
691 spnego_out.type = SPNEGO_NEG_TOKEN_TARG;
692 spnego_out.negTokenTarg.negResult = SPNEGO_NONE_RESULT;
693 spnego_out.negTokenTarg.supportedMech = NULL;
694 spnego_out.negTokenTarg.responseToken = unwrapped_out;
695 spnego_out.negTokenTarg.mechListMIC = null_data_blob;
697 if (spnego_write_data(out_mem_ctx, out, &spnego_out) == -1) {
698 DEBUG(1, ("Failed to write SPNEGO reply to NEG_TOKEN_TARG\n"));
699 return NT_STATUS_INVALID_PARAMETER;
702 spnego_state->state_position = SPNEGO_CLIENT_TARG;
703 } else if (NT_STATUS_IS_OK(nt_status)) {
704 /* all done - server has accepted, and we agree */
706 if (unwrapped_out.length) {
707 spnego_out.type = SPNEGO_NEG_TOKEN_TARG;
708 spnego_out.negTokenTarg.negResult = SPNEGO_NONE_RESULT;
709 spnego_out.negTokenTarg.supportedMech = NULL;
710 spnego_out.negTokenTarg.responseToken = unwrapped_out;
711 spnego_out.negTokenTarg.mechListMIC = null_data_blob;
713 if (spnego_write_data(out_mem_ctx, out, &spnego_out) == -1) {
714 DEBUG(1, ("Failed to write SPNEGO reply to NEG_TOKEN_TARG\n"));
715 return NT_STATUS_INVALID_PARAMETER;
718 *out = null_data_blob;
721 spnego_state->state_position = SPNEGO_DONE;
723 DEBUG(1, ("SPNEGO(%s) login failed: %s\n",
724 spnego_state->sub_sec_security->ops->name,
725 nt_errstr(nt_status)));
732 return NT_STATUS_INVALID_PARAMETER;
735 static BOOL gensec_spnego_have_feature(struct gensec_security *gensec_security,
738 struct spnego_state *spnego_state = gensec_security->private_data;
739 if (!spnego_state->sub_sec_security) {
743 return gensec_have_feature(spnego_state->sub_sec_security,
747 static const struct gensec_security_ops gensec_spnego_security_ops = {
749 .sasl_name = "GSS-SPNEGO",
750 .auth_type = DCERPC_AUTH_TYPE_SPNEGO,
751 .oid = GENSEC_OID_SPNEGO,
752 .client_start = gensec_spnego_client_start,
753 .server_start = gensec_spnego_server_start,
754 .update = gensec_spnego_update,
755 .seal_packet = gensec_spnego_seal_packet,
756 .sign_packet = gensec_spnego_sign_packet,
757 .sig_size = gensec_spnego_sig_size,
758 .check_packet = gensec_spnego_check_packet,
759 .unseal_packet = gensec_spnego_unseal_packet,
760 .wrap = gensec_spnego_wrap,
761 .unwrap = gensec_spnego_unwrap,
762 .session_key = gensec_spnego_session_key,
763 .session_info = gensec_spnego_session_info,
764 .have_feature = gensec_spnego_have_feature
767 NTSTATUS gensec_spnego_init(void)
770 ret = gensec_register(&gensec_spnego_security_ops);
771 if (!NT_STATUS_IS_OK(ret)) {
772 DEBUG(0,("Failed to register '%s' gensec backend!\n",
773 gensec_spnego_security_ops.name));