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.
28 #define DBGC_CLASS DBGC_AUTH
30 enum spnego_state_position
{
41 enum spnego_message_type expected_packet
;
42 enum spnego_state_position state_position
;
43 struct gensec_security
*sub_sec_security
;
46 static NTSTATUS
gensec_spnego_client_start(struct gensec_security
*gensec_security
)
48 struct spnego_state
*spnego_state
;
50 spnego_state
= talloc_p(gensec_security
, struct spnego_state
);
52 return NT_STATUS_NO_MEMORY
;
55 spnego_state
->expected_packet
= SPNEGO_NEG_TOKEN_INIT
;
56 spnego_state
->state_position
= SPNEGO_CLIENT_START
;
57 spnego_state
->sub_sec_security
= NULL
;
59 gensec_security
->private_data
= spnego_state
;
63 static NTSTATUS
gensec_spnego_server_start(struct gensec_security
*gensec_security
)
65 struct spnego_state
*spnego_state
;
67 spnego_state
= talloc_p(gensec_security
, struct spnego_state
);
69 return NT_STATUS_NO_MEMORY
;
72 spnego_state
->expected_packet
= SPNEGO_NEG_TOKEN_INIT
;
73 spnego_state
->state_position
= SPNEGO_SERVER_START
;
74 spnego_state
->sub_sec_security
= NULL
;
76 gensec_security
->private_data
= spnego_state
;
81 wrappers for the spnego_*() functions
83 static NTSTATUS
gensec_spnego_unseal_packet(struct gensec_security
*gensec_security
,
85 uint8_t *data
, size_t length
,
86 const uint8_t *whole_pdu
, size_t pdu_length
,
89 struct spnego_state
*spnego_state
= gensec_security
->private_data
;
91 if (spnego_state
->state_position
!= SPNEGO_DONE
92 && spnego_state
->state_position
!= SPNEGO_FALLBACK
) {
93 return NT_STATUS_INVALID_PARAMETER
;
96 return gensec_unseal_packet(spnego_state
->sub_sec_security
,
99 whole_pdu
, pdu_length
,
103 static NTSTATUS
gensec_spnego_check_packet(struct gensec_security
*gensec_security
,
105 const uint8_t *data
, size_t length
,
106 const uint8_t *whole_pdu
, size_t pdu_length
,
107 const DATA_BLOB
*sig
)
109 struct spnego_state
*spnego_state
= gensec_security
->private_data
;
111 if (spnego_state
->state_position
!= SPNEGO_DONE
112 && spnego_state
->state_position
!= SPNEGO_FALLBACK
) {
113 return NT_STATUS_INVALID_PARAMETER
;
116 return gensec_check_packet(spnego_state
->sub_sec_security
,
119 whole_pdu
, pdu_length
,
123 static NTSTATUS
gensec_spnego_seal_packet(struct gensec_security
*gensec_security
,
125 uint8_t *data
, size_t length
,
126 const uint8_t *whole_pdu
, size_t pdu_length
,
129 struct spnego_state
*spnego_state
= gensec_security
->private_data
;
131 if (spnego_state
->state_position
!= SPNEGO_DONE
132 && spnego_state
->state_position
!= SPNEGO_FALLBACK
) {
133 return NT_STATUS_INVALID_PARAMETER
;
136 return gensec_seal_packet(spnego_state
->sub_sec_security
,
139 whole_pdu
, pdu_length
,
143 static NTSTATUS
gensec_spnego_sign_packet(struct gensec_security
*gensec_security
,
145 const uint8_t *data
, size_t length
,
146 const uint8_t *whole_pdu
, size_t pdu_length
,
149 struct spnego_state
*spnego_state
= gensec_security
->private_data
;
151 if (spnego_state
->state_position
!= SPNEGO_DONE
152 && spnego_state
->state_position
!= SPNEGO_FALLBACK
) {
153 return NT_STATUS_INVALID_PARAMETER
;
156 return gensec_sign_packet(spnego_state
->sub_sec_security
,
159 whole_pdu
, pdu_length
,
163 static size_t gensec_spnego_sig_size(struct gensec_security
*gensec_security
)
165 struct spnego_state
*spnego_state
= gensec_security
->private_data
;
167 if (spnego_state
->state_position
!= SPNEGO_DONE
168 && spnego_state
->state_position
!= SPNEGO_FALLBACK
) {
172 return gensec_sig_size(spnego_state
->sub_sec_security
);
175 static NTSTATUS
gensec_spnego_session_key(struct gensec_security
*gensec_security
,
176 DATA_BLOB
*session_key
)
178 struct spnego_state
*spnego_state
= gensec_security
->private_data
;
179 if (!spnego_state
->sub_sec_security
) {
180 return NT_STATUS_INVALID_PARAMETER
;
183 return gensec_session_key(spnego_state
->sub_sec_security
,
187 static NTSTATUS
gensec_spnego_session_info(struct gensec_security
*gensec_security
,
188 struct auth_session_info
**session_info
)
190 struct spnego_state
*spnego_state
= gensec_security
->private_data
;
191 if (!spnego_state
->sub_sec_security
) {
192 return NT_STATUS_INVALID_PARAMETER
;
195 return gensec_session_info(spnego_state
->sub_sec_security
,
199 /** Fallback to another GENSEC mechanism, based on magic strings
201 * This is the 'fallback' case, where we don't get SPNEGO, and have to
202 * try all the other options (and hope they all have a magic string
206 static NTSTATUS
gensec_spnego_server_try_fallback(struct gensec_security
*gensec_security
,
207 struct spnego_state
*spnego_state
,
208 TALLOC_CTX
*out_mem_ctx
,
209 const DATA_BLOB in
, DATA_BLOB
*out
)
213 const struct gensec_security_ops
**all_ops
= gensec_security_all(&num_ops
);
214 for (i
=0; i
< num_ops
; i
++) {
216 if (!all_ops
[i
]->oid
) {
219 nt_status
= gensec_subcontext_start(gensec_security
,
220 &spnego_state
->sub_sec_security
);
221 if (!NT_STATUS_IS_OK(nt_status
)) {
224 /* select the sub context */
225 nt_status
= gensec_start_mech_by_oid(spnego_state
->sub_sec_security
,
227 if (!NT_STATUS_IS_OK(nt_status
)) {
228 gensec_end(&spnego_state
->sub_sec_security
);
231 nt_status
= gensec_update(spnego_state
->sub_sec_security
,
232 out_mem_ctx
, in
, out
);
233 if (NT_STATUS_EQUAL(nt_status
, NT_STATUS_MORE_PROCESSING_REQUIRED
)) {
234 spnego_state
->state_position
= SPNEGO_FALLBACK
;
237 gensec_end(&spnego_state
->sub_sec_security
);
239 DEBUG(1, ("Failed to parse SPNEGO request\n"));
240 return NT_STATUS_INVALID_PARAMETER
;
244 static NTSTATUS
gensec_spnego_parse_negTokenInit(struct gensec_security
*gensec_security
,
245 struct spnego_state
*spnego_state
,
246 TALLOC_CTX
*out_mem_ctx
,
247 const char **mechType
,
248 const DATA_BLOB unwrapped_in
, DATA_BLOB
*unwrapped_out
)
252 DATA_BLOB null_data_blob
= data_blob(NULL
,0);
254 for (i
=0; mechType
&& mechType
[i
]; i
++) {
255 nt_status
= gensec_subcontext_start(gensec_security
,
256 &spnego_state
->sub_sec_security
);
257 if (!NT_STATUS_IS_OK(nt_status
)) {
260 /* select the sub context */
261 nt_status
= gensec_start_mech_by_oid(spnego_state
->sub_sec_security
,
263 if (!NT_STATUS_IS_OK(nt_status
)) {
264 gensec_end(&spnego_state
->sub_sec_security
);
269 nt_status
= gensec_update(spnego_state
->sub_sec_security
,
274 /* only get the helping start blob for the first OID */
275 nt_status
= gensec_update(spnego_state
->sub_sec_security
,
280 if (!NT_STATUS_EQUAL(nt_status
, NT_STATUS_MORE_PROCESSING_REQUIRED
) && !NT_STATUS_IS_OK(nt_status
)) {
281 DEBUG(1, ("SPNEGO(%s) NEG_TOKEN_INIT failed: %s\n",
282 spnego_state
->sub_sec_security
->ops
->name
, nt_errstr(nt_status
)));
283 gensec_end(&spnego_state
->sub_sec_security
);
287 if (!mechType
|| !mechType
[i
]) {
288 DEBUG(1, ("SPNEGO: Could not find a suitable mechtype in NEG_TOKEN_INIT\n"));
290 return NT_STATUS_INVALID_PARAMETER
;
293 /** create a client negTokenInit
295 * This is the case, where the client is the first one who sends data
298 static NTSTATUS
gensec_spnego_client_negTokenInit(struct gensec_security
*gensec_security
,
299 struct spnego_state
*spnego_state
,
300 TALLOC_CTX
*out_mem_ctx
,
301 const DATA_BLOB in
, DATA_BLOB
*out
)
303 DATA_BLOB null_data_blob
= data_blob(NULL
,0);
305 const char **mechTypes
= NULL
;
306 DATA_BLOB unwrapped_out
= data_blob(NULL
,0);
308 mechTypes
= gensec_security_oids(out_mem_ctx
, OID_SPNEGO
);
311 DEBUG(1, ("no GENSEC OID backends available\n"));
312 return NT_STATUS_INVALID_PARAMETER
;
315 nt_status
= gensec_subcontext_start(gensec_security
,
316 &spnego_state
->sub_sec_security
);
317 if (!NT_STATUS_IS_OK(nt_status
)) {
320 /* select our preferred mech */
321 nt_status
= gensec_start_mech_by_oid(spnego_state
->sub_sec_security
,
323 if (!NT_STATUS_IS_OK(nt_status
)) {
324 gensec_end(&spnego_state
->sub_sec_security
);
327 nt_status
= gensec_update(spnego_state
->sub_sec_security
,
328 out_mem_ctx
, in
, &unwrapped_out
);
329 if (NT_STATUS_EQUAL(nt_status
, NT_STATUS_MORE_PROCESSING_REQUIRED
)) {
330 struct spnego_data spnego_out
;
331 spnego_out
.type
= SPNEGO_NEG_TOKEN_INIT
;
332 spnego_out
.negTokenInit
.mechTypes
= mechTypes
;
333 spnego_out
.negTokenInit
.reqFlags
= 0;
334 spnego_out
.negTokenInit
.mechListMIC
= null_data_blob
;
335 spnego_out
.negTokenInit
.mechToken
= unwrapped_out
;
337 if (spnego_write_data(out_mem_ctx
, out
, &spnego_out
) == -1) {
338 DEBUG(1, ("Failed to write SPNEGO reply to NEG_TOKEN_INIT\n"));
339 return NT_STATUS_INVALID_PARAMETER
;
343 spnego_state
->expected_packet
= SPNEGO_NEG_TOKEN_TARG
;
344 spnego_state
->state_position
= SPNEGO_CLIENT_TARG
;
347 gensec_end(&spnego_state
->sub_sec_security
);
349 DEBUG(1, ("Failed to setup SPNEGO netTokenInit request\n"));
350 return NT_STATUS_INVALID_PARAMETER
;
354 /** create a client negTokenTarg
356 * This is the case, where the client is the first one who sends data
359 static NTSTATUS
gensec_spnego_server_negTokenTarg(struct gensec_security
*gensec_security
,
360 struct spnego_state
*spnego_state
,
361 TALLOC_CTX
*out_mem_ctx
,
363 const DATA_BLOB unwrapped_out
, DATA_BLOB
*out
)
365 struct spnego_data spnego_out
;
366 DATA_BLOB null_data_blob
= data_blob(NULL
, 0);
369 spnego_out
.type
= SPNEGO_NEG_TOKEN_TARG
;
370 spnego_out
.negTokenTarg
.responseToken
= unwrapped_out
;
371 spnego_out
.negTokenTarg
.mechListMIC
= null_data_blob
;
373 if (NT_STATUS_EQUAL(nt_status
, NT_STATUS_MORE_PROCESSING_REQUIRED
)) {
374 spnego_out
.negTokenTarg
.supportedMech
375 = spnego_state
->sub_sec_security
->ops
->oid
;
376 spnego_out
.negTokenTarg
.negResult
= SPNEGO_ACCEPT_INCOMPLETE
;
377 spnego_state
->state_position
= SPNEGO_SERVER_TARG
;
378 } else if (NT_STATUS_IS_OK(nt_status
)) {
379 spnego_out
.negTokenTarg
.supportedMech
= NULL
;
380 spnego_out
.negTokenTarg
.negResult
= SPNEGO_ACCEPT_COMPLETED
;
381 spnego_state
->state_position
= SPNEGO_DONE
;
383 spnego_out
.negTokenTarg
.supportedMech
= NULL
;
384 spnego_out
.negTokenTarg
.negResult
= SPNEGO_REJECT
;
385 DEBUG(1, ("SPNEGO login failed: %s\n", nt_errstr(nt_status
)));
386 spnego_state
->state_position
= SPNEGO_DONE
;
389 if (spnego_write_data(out_mem_ctx
, out
, &spnego_out
) == -1) {
390 DEBUG(1, ("Failed to write SPNEGO reply to NEG_TOKEN_TARG\n"));
391 return NT_STATUS_INVALID_PARAMETER
;
394 spnego_state
->expected_packet
= SPNEGO_NEG_TOKEN_TARG
;
400 static NTSTATUS
gensec_spnego_update(struct gensec_security
*gensec_security
, TALLOC_CTX
*out_mem_ctx
,
401 const DATA_BLOB in
, DATA_BLOB
*out
)
403 struct spnego_state
*spnego_state
= gensec_security
->private_data
;
404 DATA_BLOB null_data_blob
= data_blob(NULL
, 0);
405 DATA_BLOB unwrapped_out
= data_blob(NULL
, 0);
406 struct spnego_data spnego_out
;
407 struct spnego_data spnego
;
411 *out
= data_blob(NULL
, 0);
414 out_mem_ctx
= spnego_state
;
417 /* and switch into the state machine */
419 switch (spnego_state
->state_position
) {
420 case SPNEGO_FALLBACK
:
421 return gensec_update(spnego_state
->sub_sec_security
,
422 out_mem_ctx
, in
, out
);
423 case SPNEGO_SERVER_START
:
428 len
= spnego_read_data(in
, &spnego
);
430 return gensec_spnego_server_try_fallback(gensec_security
, spnego_state
, out_mem_ctx
, in
, out
);
432 /* client sent NegTargetInit, we send NegTokenTarg */
434 /* OK, so it's real SPNEGO, check the packet's the one we expect */
435 if (spnego
.type
!= spnego_state
->expected_packet
) {
436 DEBUG(1, ("Invalid SPNEGO request: %d, expected %d\n", spnego
.type
,
437 spnego_state
->expected_packet
));
438 dump_data(1, (const char *)in
.data
, in
.length
);
439 spnego_free_data(&spnego
);
440 return NT_STATUS_INVALID_PARAMETER
;
443 nt_status
= gensec_spnego_parse_negTokenInit(gensec_security
,
446 spnego
.negTokenInit
.mechTypes
,
447 spnego
.negTokenInit
.mechToken
,
450 nt_status
= gensec_spnego_server_negTokenTarg(gensec_security
,
457 spnego_free_data(&spnego
);
461 const char **mechlist
= gensec_security_oids(out_mem_ctx
, OID_SPNEGO
);
463 spnego_out
.type
= SPNEGO_NEG_TOKEN_INIT
;
464 spnego_out
.negTokenInit
.mechTypes
= mechlist
;
465 spnego_out
.negTokenInit
.reqFlags
= 0;
466 spnego_out
.negTokenInit
.mechListMIC
= null_data_blob
;
467 spnego_out
.negTokenInit
.mechToken
= unwrapped_out
;
469 if (spnego_write_data(out_mem_ctx
, out
, &spnego_out
) == -1) {
470 DEBUG(1, ("Failed to write SPNEGO reply to NEG_TOKEN_INIT\n"));
471 return NT_STATUS_INVALID_PARAMETER
;
475 spnego_state
->expected_packet
= SPNEGO_NEG_TOKEN_TARG
;
476 spnego_state
->state_position
= SPNEGO_SERVER_TARG
;
478 return NT_STATUS_MORE_PROCESSING_REQUIRED
;
482 case SPNEGO_CLIENT_START
:
484 /* The server offers a list of mechanisms */
486 char *my_mechs
[] = {NULL
, NULL
};
487 NTSTATUS nt_status
= NT_STATUS_INVALID_PARAMETER
;
490 /* client to produce negTokenInit */
491 return gensec_spnego_client_negTokenInit(gensec_security
, spnego_state
, out_mem_ctx
, in
, out
);
494 len
= spnego_read_data(in
, &spnego
);
497 DEBUG(1, ("Invalid SPNEGO request:\n"));
498 dump_data(1, (const char *)in
.data
, in
.length
);
499 return NT_STATUS_INVALID_PARAMETER
;
502 /* OK, so it's real SPNEGO, check the packet's the one we expect */
503 if (spnego
.type
!= spnego_state
->expected_packet
) {
504 DEBUG(1, ("Invalid SPNEGO request: %d, expected %d\n", spnego
.type
,
505 spnego_state
->expected_packet
));
506 dump_data(1, (const char *)in
.data
, in
.length
);
507 spnego_free_data(&spnego
);
508 return NT_STATUS_INVALID_PARAMETER
;
511 if (spnego
.negTokenInit
.targetPrincipal
) {
512 DEBUG(5, ("Server claims it's principal name is %s\n", spnego
.negTokenInit
.targetPrincipal
));
513 nt_status
= gensec_set_target_principal(gensec_security
,
514 spnego
.negTokenInit
.targetPrincipal
);
515 if (!NT_STATUS_IS_OK(nt_status
)) {
516 spnego_free_data(&spnego
);
521 nt_status
= gensec_spnego_parse_negTokenInit(gensec_security
,
524 spnego
.negTokenInit
.mechTypes
,
525 spnego
.negTokenInit
.mechToken
,
528 if (!NT_STATUS_EQUAL(nt_status
, NT_STATUS_MORE_PROCESSING_REQUIRED
) && !NT_STATUS_IS_OK(nt_status
)) {
529 spnego_free_data(&spnego
);
534 my_mechs
[0] = spnego_state
->sub_sec_security
->ops
->oid
;
536 spnego_out
.type
= SPNEGO_NEG_TOKEN_INIT
;
537 spnego_out
.negTokenInit
.mechTypes
= my_mechs
;
538 spnego_out
.negTokenInit
.reqFlags
= 0;
539 spnego_out
.negTokenInit
.mechListMIC
= null_data_blob
;
540 spnego_out
.negTokenInit
.mechToken
= unwrapped_out
;
542 if (spnego_write_data(out_mem_ctx
, out
, &spnego_out
) == -1) {
543 DEBUG(1, ("Failed to write SPNEGO reply to NEG_TOKEN_INIT\n"));
544 return NT_STATUS_INVALID_PARAMETER
;
548 spnego_state
->expected_packet
= SPNEGO_NEG_TOKEN_TARG
;
549 spnego_state
->state_position
= SPNEGO_CLIENT_TARG
;
551 return NT_STATUS_MORE_PROCESSING_REQUIRED
;
553 case SPNEGO_SERVER_TARG
:
557 return NT_STATUS_INVALID_PARAMETER
;
560 len
= spnego_read_data(in
, &spnego
);
563 DEBUG(1, ("Invalid SPNEGO request:\n"));
564 dump_data(1, (const char *)in
.data
, in
.length
);
565 return NT_STATUS_INVALID_PARAMETER
;
568 /* OK, so it's real SPNEGO, check the packet's the one we expect */
569 if (spnego
.type
!= spnego_state
->expected_packet
) {
570 DEBUG(1, ("Invalid SPNEGO request: %d, expected %d\n", spnego
.type
,
571 spnego_state
->expected_packet
));
572 dump_data(1, (const char *)in
.data
, in
.length
);
573 spnego_free_data(&spnego
);
574 return NT_STATUS_INVALID_PARAMETER
;
577 nt_status
= gensec_update(spnego_state
->sub_sec_security
,
579 spnego
.negTokenTarg
.responseToken
,
582 nt_status
= gensec_spnego_server_negTokenTarg(gensec_security
,
589 spnego_free_data(&spnego
);
593 case SPNEGO_CLIENT_TARG
:
597 return NT_STATUS_INVALID_PARAMETER
;
600 len
= spnego_read_data(in
, &spnego
);
603 DEBUG(1, ("Invalid SPNEGO request:\n"));
604 dump_data(1, (const char *)in
.data
, in
.length
);
605 return NT_STATUS_INVALID_PARAMETER
;
608 /* OK, so it's real SPNEGO, check the packet's the one we expect */
609 if (spnego
.type
!= spnego_state
->expected_packet
) {
610 DEBUG(1, ("Invalid SPNEGO request: %d, expected %d\n", spnego
.type
,
611 spnego_state
->expected_packet
));
612 dump_data(1, (const char *)in
.data
, in
.length
);
613 spnego_free_data(&spnego
);
614 return NT_STATUS_INVALID_PARAMETER
;
617 if (spnego
.negTokenTarg
.negResult
== SPNEGO_REJECT
) {
618 return NT_STATUS_ACCESS_DENIED
;
621 nt_status
= gensec_update(spnego_state
->sub_sec_security
,
623 spnego
.negTokenTarg
.responseToken
,
627 if (NT_STATUS_IS_OK(nt_status
)
628 && (spnego
.negTokenTarg
.negResult
!= SPNEGO_ACCEPT_COMPLETED
)) {
629 DEBUG(1,("gensec_update ok but not accepted\n"));
630 nt_status
= NT_STATUS_INVALID_PARAMETER
;
633 spnego_free_data(&spnego
);
635 if (NT_STATUS_EQUAL(nt_status
, NT_STATUS_MORE_PROCESSING_REQUIRED
)) {
637 spnego_out
.type
= SPNEGO_NEG_TOKEN_TARG
;
638 spnego_out
.negTokenTarg
.negResult
= SPNEGO_NONE_RESULT
;
639 spnego_out
.negTokenTarg
.supportedMech
= NULL
;
640 spnego_out
.negTokenTarg
.responseToken
= unwrapped_out
;
641 spnego_out
.negTokenTarg
.mechListMIC
= null_data_blob
;
643 if (spnego_write_data(out_mem_ctx
, out
, &spnego_out
) == -1) {
644 DEBUG(1, ("Failed to write SPNEGO reply to NEG_TOKEN_TARG\n"));
645 return NT_STATUS_INVALID_PARAMETER
;
648 spnego_state
->state_position
= SPNEGO_CLIENT_TARG
;
649 } else if (NT_STATUS_IS_OK(nt_status
)) {
650 /* all done - server has accepted, and we agree */
652 if (unwrapped_out
.length
) {
653 spnego_out
.type
= SPNEGO_NEG_TOKEN_TARG
;
654 spnego_out
.negTokenTarg
.negResult
= SPNEGO_NONE_RESULT
;
655 spnego_out
.negTokenTarg
.supportedMech
= NULL
;
656 spnego_out
.negTokenTarg
.responseToken
= unwrapped_out
;
657 spnego_out
.negTokenTarg
.mechListMIC
= null_data_blob
;
659 if (spnego_write_data(out_mem_ctx
, out
, &spnego_out
) == -1) {
660 DEBUG(1, ("Failed to write SPNEGO reply to NEG_TOKEN_TARG\n"));
661 return NT_STATUS_INVALID_PARAMETER
;
664 *out
= null_data_blob
;
667 spnego_state
->state_position
= SPNEGO_DONE
;
669 DEBUG(1, ("SPNEGO(%s) login failed: %s\n",
670 spnego_state
->sub_sec_security
->ops
->name
,
671 nt_errstr(nt_status
)));
678 return NT_STATUS_INVALID_PARAMETER
;
681 static void gensec_spnego_end(struct gensec_security
*gensec_security
)
683 struct spnego_state
*spnego_state
= gensec_security
->private_data
;
685 if (spnego_state
->sub_sec_security
) {
686 gensec_end(&spnego_state
->sub_sec_security
);
689 talloc_free(spnego_state
);
691 gensec_security
->private_data
= NULL
;
694 static const struct gensec_security_ops gensec_spnego_security_ops
= {
696 .sasl_name
= "GSS-SPNEGO",
697 .auth_type
= DCERPC_AUTH_TYPE_SPNEGO
,
699 .client_start
= gensec_spnego_client_start
,
700 .server_start
= gensec_spnego_server_start
,
701 .update
= gensec_spnego_update
,
702 .seal_packet
= gensec_spnego_seal_packet
,
703 .sign_packet
= gensec_spnego_sign_packet
,
704 .sig_size
= gensec_spnego_sig_size
,
705 .check_packet
= gensec_spnego_check_packet
,
706 .unseal_packet
= gensec_spnego_unseal_packet
,
707 .session_key
= gensec_spnego_session_key
,
708 .session_info
= gensec_spnego_session_info
,
709 .end
= gensec_spnego_end
712 NTSTATUS
gensec_spnego_init(void)
715 ret
= register_backend("gensec", &gensec_spnego_security_ops
);
716 if (!NT_STATUS_IS_OK(ret
)) {
717 DEBUG(0,("Failed to register '%s' gensec backend!\n",
718 gensec_spnego_security_ops
.name
));