Merge branch 'master' of ssh://git.samba.org/data/git/samba
[metze/samba/wip.git] / source4 / auth / gensec / spnego.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    RFC2478 Compliant SPNEGO implementation
5    
6    Copyright (C) Jim McDonough <jmcd@us.ibm.com>      2003
7    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2005
8    Copyright (C) Stefan Metzmacher <metze@samba.org>  2004-2008
9
10    This program is free software; you can redistribute it and/or modify
11    it under the terms of the GNU General Public License as published by
12    the Free Software Foundation; either version 3 of the License, or
13    (at your option) any later version.
14    
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License for more details.
19
20    
21    You should have received a copy of the GNU General Public License
22    along with this program.  If not, see <http://www.gnu.org/licenses/>.
23 */
24
25 #include "includes.h"
26 #include "../libcli/auth/spnego.h"
27 #include "librpc/gen_ndr/ndr_dcerpc.h"
28 #include "auth/credentials/credentials.h"
29 #include "auth/gensec/gensec.h"
30 #include "auth/gensec/gensec_proto.h"
31 #include "param/param.h"
32
33 enum spnego_state_position {
34         SPNEGO_SERVER_START,
35         SPNEGO_CLIENT_START,
36         SPNEGO_SERVER_TARG,
37         SPNEGO_CLIENT_TARG,
38         SPNEGO_FALLBACK,
39         SPNEGO_DONE
40 };
41
42 struct spnego_state {
43         enum spnego_message_type expected_packet;
44         enum spnego_state_position state_position;
45         struct gensec_security *sub_sec_security;
46         bool no_response_expected;
47
48         const char *neg_oid;
49
50         DATA_BLOB mech_types;
51 };
52
53
54 static NTSTATUS gensec_spnego_client_start(struct gensec_security *gensec_security)
55 {
56         struct spnego_state *spnego_state;
57
58         spnego_state = talloc(gensec_security, struct spnego_state);
59         if (!spnego_state) {
60                 return NT_STATUS_NO_MEMORY;
61         }
62
63         spnego_state->expected_packet = SPNEGO_NEG_TOKEN_INIT;
64         spnego_state->state_position = SPNEGO_CLIENT_START;
65         spnego_state->sub_sec_security = NULL;
66         spnego_state->no_response_expected = false;
67         spnego_state->mech_types = data_blob(NULL, 0);
68
69         gensec_security->private_data = spnego_state;
70         return NT_STATUS_OK;
71 }
72
73 static NTSTATUS gensec_spnego_server_start(struct gensec_security *gensec_security)
74 {
75         struct spnego_state *spnego_state;
76
77         spnego_state = talloc(gensec_security, struct spnego_state);            
78         if (!spnego_state) {
79                 return NT_STATUS_NO_MEMORY;
80         }
81
82         spnego_state->expected_packet = SPNEGO_NEG_TOKEN_INIT;
83         spnego_state->state_position = SPNEGO_SERVER_START;
84         spnego_state->sub_sec_security = NULL;
85         spnego_state->no_response_expected = false;
86         spnego_state->mech_types = data_blob(NULL, 0);
87
88         gensec_security->private_data = spnego_state;
89         return NT_STATUS_OK;
90 }
91
92 /*
93   wrappers for the spnego_*() functions
94 */
95 static NTSTATUS gensec_spnego_unseal_packet(struct gensec_security *gensec_security, 
96                                             TALLOC_CTX *mem_ctx, 
97                                             uint8_t *data, size_t length, 
98                                             const uint8_t *whole_pdu, size_t pdu_length, 
99                                             const DATA_BLOB *sig)
100 {
101         struct spnego_state *spnego_state = (struct spnego_state *)gensec_security->private_data;
102
103         if (spnego_state->state_position != SPNEGO_DONE 
104             && spnego_state->state_position != SPNEGO_FALLBACK) {
105                 return NT_STATUS_INVALID_PARAMETER;
106         }
107         
108         return gensec_unseal_packet(spnego_state->sub_sec_security, 
109                                     mem_ctx, 
110                                     data, length, 
111                                     whole_pdu, pdu_length,
112                                     sig); 
113 }
114
115 static NTSTATUS gensec_spnego_check_packet(struct gensec_security *gensec_security, 
116                                            TALLOC_CTX *mem_ctx, 
117                                            const uint8_t *data, size_t length, 
118                                            const uint8_t *whole_pdu, size_t pdu_length, 
119                                            const DATA_BLOB *sig)
120 {
121         struct spnego_state *spnego_state = (struct spnego_state *)gensec_security->private_data;
122
123         if (spnego_state->state_position != SPNEGO_DONE 
124             && spnego_state->state_position != SPNEGO_FALLBACK) {
125                 return NT_STATUS_INVALID_PARAMETER;
126         }
127         
128         return gensec_check_packet(spnego_state->sub_sec_security, 
129                                    mem_ctx, 
130                                    data, length, 
131                                    whole_pdu, pdu_length,
132                                    sig);
133 }
134
135 static NTSTATUS gensec_spnego_seal_packet(struct gensec_security *gensec_security, 
136                                           TALLOC_CTX *mem_ctx, 
137                                           uint8_t *data, size_t length, 
138                                           const uint8_t *whole_pdu, size_t pdu_length, 
139                                           DATA_BLOB *sig)
140 {
141         struct spnego_state *spnego_state = (struct spnego_state *)gensec_security->private_data;
142
143         if (spnego_state->state_position != SPNEGO_DONE 
144             && spnego_state->state_position != SPNEGO_FALLBACK) {
145                 return NT_STATUS_INVALID_PARAMETER;
146         }
147         
148         return gensec_seal_packet(spnego_state->sub_sec_security, 
149                                   mem_ctx, 
150                                   data, length, 
151                                   whole_pdu, pdu_length,
152                                   sig);
153 }
154
155 static NTSTATUS gensec_spnego_sign_packet(struct gensec_security *gensec_security, 
156                                           TALLOC_CTX *mem_ctx, 
157                                           const uint8_t *data, size_t length, 
158                                           const uint8_t *whole_pdu, size_t pdu_length, 
159                                           DATA_BLOB *sig)
160 {
161         struct spnego_state *spnego_state = (struct spnego_state *)gensec_security->private_data;
162
163         if (spnego_state->state_position != SPNEGO_DONE 
164             && spnego_state->state_position != SPNEGO_FALLBACK) {
165                 return NT_STATUS_INVALID_PARAMETER;
166         }
167         
168         return gensec_sign_packet(spnego_state->sub_sec_security, 
169                                   mem_ctx, 
170                                   data, length, 
171                                   whole_pdu, pdu_length,
172                                   sig);
173 }
174
175 static NTSTATUS gensec_spnego_wrap(struct gensec_security *gensec_security, 
176                                    TALLOC_CTX *mem_ctx, 
177                                    const DATA_BLOB *in, 
178                                    DATA_BLOB *out)
179 {
180         struct spnego_state *spnego_state = (struct spnego_state *)gensec_security->private_data;
181
182         if (spnego_state->state_position != SPNEGO_DONE 
183             && spnego_state->state_position != SPNEGO_FALLBACK) {
184                 DEBUG(1, ("gensec_spnego_wrap: wrong state for wrap\n"));
185                 return NT_STATUS_INVALID_PARAMETER;
186         }
187         
188         return gensec_wrap(spnego_state->sub_sec_security, 
189                            mem_ctx, in, out);
190 }
191
192 static NTSTATUS gensec_spnego_unwrap(struct gensec_security *gensec_security, 
193                                      TALLOC_CTX *mem_ctx, 
194                                      const DATA_BLOB *in, 
195                                      DATA_BLOB *out)
196 {
197         struct spnego_state *spnego_state = (struct spnego_state *)gensec_security->private_data;
198
199         if (spnego_state->state_position != SPNEGO_DONE 
200             && spnego_state->state_position != SPNEGO_FALLBACK) {
201                 DEBUG(1, ("gensec_spnego_unwrap: wrong state for unwrap\n"));
202                 return NT_STATUS_INVALID_PARAMETER;
203         }
204         
205         return gensec_unwrap(spnego_state->sub_sec_security, 
206                              mem_ctx, in, out);
207 }
208
209 static NTSTATUS gensec_spnego_wrap_packets(struct gensec_security *gensec_security, 
210                                            TALLOC_CTX *mem_ctx, 
211                                            const DATA_BLOB *in, 
212                                            DATA_BLOB *out,
213                                            size_t *len_processed) 
214 {
215         struct spnego_state *spnego_state = (struct spnego_state *)gensec_security->private_data;
216
217         if (spnego_state->state_position != SPNEGO_DONE 
218             && spnego_state->state_position != SPNEGO_FALLBACK) {
219                 DEBUG(1, ("gensec_spnego_wrap: wrong state for wrap\n"));
220                 return NT_STATUS_INVALID_PARAMETER;
221         }
222         
223         return gensec_wrap_packets(spnego_state->sub_sec_security, 
224                                    mem_ctx, in, out,
225                                    len_processed);
226 }
227
228 static NTSTATUS gensec_spnego_packet_full_request(struct gensec_security *gensec_security, 
229                                                 DATA_BLOB blob, size_t *size)
230 {
231         struct spnego_state *spnego_state = (struct spnego_state *)gensec_security->private_data;
232
233         if (spnego_state->state_position != SPNEGO_DONE 
234             && spnego_state->state_position != SPNEGO_FALLBACK) {
235                 DEBUG(1, ("gensec_spnego_unwrap: wrong state for unwrap\n"));
236                 return NT_STATUS_INVALID_PARAMETER;
237         }
238         
239         return gensec_packet_full_request(spnego_state->sub_sec_security, 
240                                           blob, size);
241 }
242
243 static NTSTATUS gensec_spnego_unwrap_packets(struct gensec_security *gensec_security, 
244                                              TALLOC_CTX *mem_ctx, 
245                                              const DATA_BLOB *in, 
246                                              DATA_BLOB *out,
247                                              size_t *len_processed) 
248 {
249         struct spnego_state *spnego_state = (struct spnego_state *)gensec_security->private_data;
250
251         if (spnego_state->state_position != SPNEGO_DONE 
252             && spnego_state->state_position != SPNEGO_FALLBACK) {
253                 DEBUG(1, ("gensec_spnego_unwrap: wrong state for unwrap\n"));
254                 return NT_STATUS_INVALID_PARAMETER;
255         }
256         
257         return gensec_unwrap_packets(spnego_state->sub_sec_security, 
258                                      mem_ctx, in, out,
259                                      len_processed);
260 }
261
262 static size_t gensec_spnego_sig_size(struct gensec_security *gensec_security, size_t data_size) 
263 {
264         struct spnego_state *spnego_state = (struct spnego_state *)gensec_security->private_data;
265
266         if (spnego_state->state_position != SPNEGO_DONE 
267             && spnego_state->state_position != SPNEGO_FALLBACK) {
268                 return 0;
269         }
270         
271         return gensec_sig_size(spnego_state->sub_sec_security, data_size);
272 }
273
274 static size_t gensec_spnego_max_input_size(struct gensec_security *gensec_security) 
275 {
276         struct spnego_state *spnego_state = (struct spnego_state *)gensec_security->private_data;
277
278         if (spnego_state->state_position != SPNEGO_DONE 
279             && spnego_state->state_position != SPNEGO_FALLBACK) {
280                 return 0;
281         }
282         
283         return gensec_max_input_size(spnego_state->sub_sec_security);
284 }
285
286 static size_t gensec_spnego_max_wrapped_size(struct gensec_security *gensec_security) 
287 {
288         struct spnego_state *spnego_state = (struct spnego_state *)gensec_security->private_data;
289
290         if (spnego_state->state_position != SPNEGO_DONE 
291             && spnego_state->state_position != SPNEGO_FALLBACK) {
292                 return 0;
293         }
294         
295         return gensec_max_wrapped_size(spnego_state->sub_sec_security);
296 }
297
298 static NTSTATUS gensec_spnego_session_key(struct gensec_security *gensec_security, 
299                                           DATA_BLOB *session_key)
300 {
301         struct spnego_state *spnego_state = (struct spnego_state *)gensec_security->private_data;
302         if (!spnego_state->sub_sec_security) {
303                 return NT_STATUS_INVALID_PARAMETER;
304         }
305         
306         return gensec_session_key(spnego_state->sub_sec_security, 
307                                   session_key);
308 }
309
310 static NTSTATUS gensec_spnego_session_info(struct gensec_security *gensec_security,
311                                                                       struct auth_session_info **session_info) 
312 {
313         struct spnego_state *spnego_state = (struct spnego_state *)gensec_security->private_data;
314         if (!spnego_state->sub_sec_security) {
315                 return NT_STATUS_INVALID_PARAMETER;
316         }
317         
318         return gensec_session_info(spnego_state->sub_sec_security, 
319                                    session_info);
320 }
321
322 /** Fallback to another GENSEC mechanism, based on magic strings 
323  *
324  * This is the 'fallback' case, where we don't get SPNEGO, and have to
325  * try all the other options (and hope they all have a magic string
326  * they check)
327 */
328
329 static NTSTATUS gensec_spnego_server_try_fallback(struct gensec_security *gensec_security, 
330                                                   struct spnego_state *spnego_state,
331                                                   TALLOC_CTX *out_mem_ctx, 
332                                                   const DATA_BLOB in, DATA_BLOB *out) 
333 {
334         int i,j;
335         struct gensec_security_ops **all_ops
336                 = gensec_security_mechs(gensec_security, out_mem_ctx);
337         for (i=0; all_ops[i]; i++) {
338                 bool is_spnego;
339                 NTSTATUS nt_status;
340
341                 if (gensec_security != NULL && 
342                                 !gensec_security_ops_enabled(all_ops[i], gensec_security))
343                     continue;
344
345                 if (!all_ops[i]->oid) {
346                         continue;
347                 }
348
349                 is_spnego = false;
350                 for (j=0; all_ops[i]->oid[j]; j++) {
351                         if (strcasecmp(GENSEC_OID_SPNEGO,all_ops[i]->oid[j]) == 0) {
352                                 is_spnego = true;
353                         }
354                 }
355                 if (is_spnego) {
356                         continue;
357                 }
358
359                 if (!all_ops[i]->magic) {
360                         continue;
361                 }
362
363                 nt_status = all_ops[i]->magic(gensec_security, &in);
364                 if (!NT_STATUS_IS_OK(nt_status)) {
365                         continue;
366                 }
367
368                 spnego_state->state_position = SPNEGO_FALLBACK;
369
370                 nt_status = gensec_subcontext_start(spnego_state, 
371                                                     gensec_security, 
372                                                     &spnego_state->sub_sec_security);
373
374                 if (!NT_STATUS_IS_OK(nt_status)) {
375                         return nt_status;
376                 }
377                 /* select the sub context */
378                 nt_status = gensec_start_mech_by_ops(spnego_state->sub_sec_security,
379                                                      all_ops[i]);
380                 if (!NT_STATUS_IS_OK(nt_status)) {
381                         return nt_status;
382                 }
383                 nt_status = gensec_update(spnego_state->sub_sec_security,
384                                           out_mem_ctx, in, out);
385                 return nt_status;
386         }
387         DEBUG(1, ("Failed to parse SPNEGO request\n"));
388         return NT_STATUS_INVALID_PARAMETER;
389         
390 }
391
392 /* 
393    Parse the netTokenInit, either from the client, to the server, or
394    from the server to the client.
395 */
396
397 static NTSTATUS gensec_spnego_parse_negTokenInit(struct gensec_security *gensec_security,
398                                                  struct spnego_state *spnego_state, 
399                                                  TALLOC_CTX *out_mem_ctx, 
400                                                  const char **mechType,
401                                                  const DATA_BLOB unwrapped_in, DATA_BLOB *unwrapped_out) 
402 {
403         int i;
404         NTSTATUS nt_status = NT_STATUS_INVALID_PARAMETER;
405         DATA_BLOB null_data_blob = data_blob(NULL,0);
406         bool ok;
407
408         const struct gensec_security_ops_wrapper *all_sec
409                 = gensec_security_by_oid_list(gensec_security, 
410                                               out_mem_ctx, 
411                                               mechType,
412                                               GENSEC_OID_SPNEGO);
413
414         ok = spnego_write_mech_types(spnego_state,
415                                      mechType,
416                                      &spnego_state->mech_types);
417         if (!ok) {
418                 DEBUG(1, ("SPNEGO: Failed to write mechTypes\n"));
419                 return NT_STATUS_NO_MEMORY;
420         }
421
422         if (spnego_state->state_position == SPNEGO_SERVER_START) {
423                 for (i=0; all_sec && all_sec[i].op; i++) {
424                         /* optomisitic token */
425                         if (strcmp(all_sec[i].oid, mechType[0]) == 0) {
426                                 nt_status = gensec_subcontext_start(spnego_state,
427                                                                     gensec_security,
428                                                                     &spnego_state->sub_sec_security);
429                                 if (!NT_STATUS_IS_OK(nt_status)) {
430                                         return nt_status;
431                                 }
432                                 /* select the sub context */
433                                 nt_status = gensec_start_mech_by_ops(spnego_state->sub_sec_security,
434                                                                      all_sec[i].op);
435                                 if (!NT_STATUS_IS_OK(nt_status)) {
436                                         talloc_free(spnego_state->sub_sec_security);
437                                         spnego_state->sub_sec_security = NULL;
438                                         break;
439                                 }
440                                 
441                                 nt_status = gensec_update(spnego_state->sub_sec_security,
442                                                           out_mem_ctx, 
443                                                           unwrapped_in,
444                                                           unwrapped_out);
445                                 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_INVALID_PARAMETER) || 
446                                     NT_STATUS_EQUAL(nt_status, NT_STATUS_CANT_ACCESS_DOMAIN_INFO)) {
447                                         /* Pretend we never started it (lets the first run find some incompatible demand) */
448                                         
449                                         DEBUG(1, ("SPNEGO(%s) NEG_TOKEN_INIT failed to parse contents: %s\n", 
450                                                   spnego_state->sub_sec_security->ops->name, nt_errstr(nt_status)));
451                                         talloc_free(spnego_state->sub_sec_security);
452                                         spnego_state->sub_sec_security = NULL;
453                                         break;
454                                 }
455
456                                 spnego_state->neg_oid = all_sec[i].oid;
457                                 break;
458                         }
459                 }
460         }
461         
462         /* Having tried any optomisitc token from the client (if we
463          * were the server), if we didn't get anywhere, walk our list
464          * in our preference order */
465         
466         if (!spnego_state->sub_sec_security) {
467                 for (i=0; all_sec && all_sec[i].op; i++) {
468                         nt_status = gensec_subcontext_start(spnego_state,
469                                                             gensec_security,
470                                                             &spnego_state->sub_sec_security);
471                         if (!NT_STATUS_IS_OK(nt_status)) {
472                                 return nt_status;
473                         }
474                         /* select the sub context */
475                         nt_status = gensec_start_mech_by_ops(spnego_state->sub_sec_security,
476                                                              all_sec[i].op);
477                         if (!NT_STATUS_IS_OK(nt_status)) {
478                                 talloc_free(spnego_state->sub_sec_security);
479                                 spnego_state->sub_sec_security = NULL;
480                                 continue;
481                         }
482                         
483                         spnego_state->neg_oid = all_sec[i].oid;
484
485                         /* only get the helping start blob for the first OID */
486                         nt_status = gensec_update(spnego_state->sub_sec_security,
487                                                   out_mem_ctx, 
488                                                   null_data_blob, 
489                                                   unwrapped_out);
490
491                         /* it is likely that a NULL input token will
492                          * not be liked by most server mechs, but if
493                          * we are in the client, we want the first
494                          * update packet to be able to abort the use
495                          * of this mech */
496                         if (spnego_state->state_position != SPNEGO_SERVER_START) {
497                                 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_INVALID_PARAMETER) || 
498                                     NT_STATUS_EQUAL(nt_status, NT_STATUS_CANT_ACCESS_DOMAIN_INFO)) {
499                                         /* Pretend we never started it (lets the first run find some incompatible demand) */
500                                         
501                                         DEBUG(1, ("SPNEGO(%s) NEG_TOKEN_INIT failed to parse: %s\n", 
502                                                   spnego_state->sub_sec_security->ops->name, nt_errstr(nt_status)));
503                                         talloc_free(spnego_state->sub_sec_security);
504                                         spnego_state->sub_sec_security = NULL;
505                                         continue;
506                                 }
507                         }
508
509                         break;
510                 }
511         }
512
513         if (spnego_state->sub_sec_security) {
514                 /* it is likely that a NULL input token will
515                  * not be liked by most server mechs, but this
516                  * does the right thing in the CIFS client.
517                  * just push us along the merry-go-round
518                  * again, and hope for better luck next
519                  * time */
520                 
521                 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_INVALID_PARAMETER)) {
522                         *unwrapped_out = data_blob(NULL, 0);
523                         nt_status = NT_STATUS_MORE_PROCESSING_REQUIRED;
524                 }
525                 
526                 if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_INVALID_PARAMETER) 
527                     && !NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED) 
528                     && !NT_STATUS_IS_OK(nt_status)) {
529                         DEBUG(1, ("SPNEGO(%s) NEG_TOKEN_INIT failed: %s\n", 
530                                   spnego_state->sub_sec_security->ops->name, nt_errstr(nt_status)));
531                         talloc_free(spnego_state->sub_sec_security);
532                         spnego_state->sub_sec_security = NULL;
533                         
534                         /* We started the mech correctly, and the
535                          * input from the other side was valid.
536                          * Return the error (say bad password, invalid
537                          * ticket) */
538                         return nt_status;
539                 }
540         
541                 
542                 return nt_status; /* OK, INVALID_PARAMETER ore MORE PROCESSING */
543         }
544
545         DEBUG(1, ("SPNEGO: Could not find a suitable mechtype in NEG_TOKEN_INIT\n"));
546         /* we could re-negotiate here, but it would only work
547          * if the client or server lied about what it could
548          * support the first time.  Lets keep this code to
549          * reality */
550
551         return nt_status;
552 }
553
554 /** create a negTokenInit 
555  *
556  * This is the same packet, no matter if the client or server sends it first, but it is always the first packet
557 */
558 static NTSTATUS gensec_spnego_create_negTokenInit(struct gensec_security *gensec_security, 
559                                                   struct spnego_state *spnego_state,
560                                                   TALLOC_CTX *out_mem_ctx, 
561                                                   const DATA_BLOB in, DATA_BLOB *out) 
562 {
563         int i;
564         NTSTATUS nt_status = NT_STATUS_INVALID_PARAMETER;
565         DATA_BLOB null_data_blob = data_blob(NULL,0);
566         const char **mechTypes = NULL;
567         DATA_BLOB unwrapped_out = data_blob(NULL, 0);
568         const struct gensec_security_ops_wrapper *all_sec;
569         const char *principal = NULL;
570
571         mechTypes = gensec_security_oids(gensec_security, 
572                                          out_mem_ctx, GENSEC_OID_SPNEGO);
573
574         all_sec = gensec_security_by_oid_list(gensec_security, 
575                                               out_mem_ctx, 
576                                               mechTypes,
577                                               GENSEC_OID_SPNEGO);
578         for (i=0; all_sec && all_sec[i].op; i++) {
579                 struct spnego_data spnego_out;
580                 const char **send_mech_types;
581                 bool ok;
582
583                 nt_status = gensec_subcontext_start(spnego_state,
584                                                     gensec_security,
585                                                     &spnego_state->sub_sec_security);
586                 if (!NT_STATUS_IS_OK(nt_status)) {
587                         return nt_status;
588                 }
589                 /* select the sub context */
590                 nt_status = gensec_start_mech_by_ops(spnego_state->sub_sec_security,
591                                                      all_sec[i].op);
592                 if (!NT_STATUS_IS_OK(nt_status)) {
593                         talloc_free(spnego_state->sub_sec_security);
594                         spnego_state->sub_sec_security = NULL;
595                         continue;
596                 }
597
598                 /* In the client, try and produce the first (optimistic) packet */
599                 if (spnego_state->state_position == SPNEGO_CLIENT_START) {
600                         nt_status = gensec_update(spnego_state->sub_sec_security,
601                                                   out_mem_ctx, 
602                                                   null_data_blob,
603                                                   &unwrapped_out);
604                         
605                         if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED) 
606                             && !NT_STATUS_IS_OK(nt_status)) {
607                                 DEBUG(1, ("SPNEGO(%s) creating NEG_TOKEN_INIT failed: %s\n", 
608                                           spnego_state->sub_sec_security->ops->name, nt_errstr(nt_status)));
609                                 talloc_free(spnego_state->sub_sec_security);
610                                 spnego_state->sub_sec_security = NULL;
611                                 /* Pretend we never started it (lets the first run find some incompatible demand) */
612                                 
613                                 continue;
614                         }
615                 }
616
617                 spnego_out.type = SPNEGO_NEG_TOKEN_INIT;
618
619                 send_mech_types = gensec_security_oids_from_ops_wrapped(out_mem_ctx,
620                                                                         &all_sec[i]);
621
622                 ok = spnego_write_mech_types(spnego_state,
623                                              send_mech_types,
624                                              &spnego_state->mech_types);
625                 if (!ok) {
626                         DEBUG(1, ("SPNEGO: Failed to write mechTypes\n"));
627                         return NT_STATUS_NO_MEMORY;
628                 }
629
630                 /* List the remaining mechs as options */
631                 spnego_out.negTokenInit.mechTypes = send_mech_types;
632                 spnego_out.negTokenInit.reqFlags = null_data_blob;
633                 spnego_out.negTokenInit.reqFlagsPadding = 0;
634                 
635                 if (spnego_state->state_position == SPNEGO_SERVER_START) {
636                         /* server credentials */
637                         struct cli_credentials *creds = gensec_get_credentials(gensec_security);
638                         if (creds) {
639                                 principal = cli_credentials_get_principal(creds, out_mem_ctx);
640                         }
641                 }
642                 if (principal) {
643                         spnego_out.negTokenInit.mechListMIC
644                                 = data_blob_string_const(principal);
645                 } else {
646                         spnego_out.negTokenInit.mechListMIC = null_data_blob;
647                 }
648
649                 spnego_out.negTokenInit.mechToken = unwrapped_out;
650                 
651                 if (spnego_write_data(out_mem_ctx, out, &spnego_out) == -1) {
652                         DEBUG(1, ("Failed to write NEG_TOKEN_INIT\n"));
653                                 return NT_STATUS_INVALID_PARAMETER;
654                 }
655                 
656                 /* set next state */
657                 spnego_state->neg_oid = all_sec[i].oid;
658                 
659                 if (NT_STATUS_IS_OK(nt_status)) {
660                         spnego_state->no_response_expected = true;
661                 }
662
663                 return NT_STATUS_MORE_PROCESSING_REQUIRED;
664         } 
665         talloc_free(spnego_state->sub_sec_security);
666         spnego_state->sub_sec_security = NULL;
667
668         DEBUG(1, ("Failed to setup SPNEGO negTokenInit request: %s\n", nt_errstr(nt_status)));
669         return NT_STATUS_INVALID_PARAMETER;
670 }
671
672
673 /** create a server negTokenTarg 
674  *
675  * This is the case, where the client is the first one who sends data
676 */
677
678 static NTSTATUS gensec_spnego_server_negTokenTarg(struct gensec_security *gensec_security, 
679                                                   struct spnego_state *spnego_state,
680                                                   TALLOC_CTX *out_mem_ctx, 
681                                                   NTSTATUS nt_status,
682                                                   const DATA_BLOB unwrapped_out,
683                                                   DATA_BLOB mech_list_mic,
684                                                   DATA_BLOB *out)
685 {
686         struct spnego_data spnego_out;
687         DATA_BLOB null_data_blob = data_blob(NULL, 0);
688
689         /* compose reply */
690         spnego_out.type = SPNEGO_NEG_TOKEN_TARG;
691         spnego_out.negTokenTarg.responseToken = unwrapped_out;
692         spnego_out.negTokenTarg.mechListMIC = null_data_blob;
693         spnego_out.negTokenTarg.supportedMech = NULL;
694
695         if (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {   
696                 spnego_out.negTokenTarg.supportedMech = spnego_state->neg_oid;
697                 spnego_out.negTokenTarg.negResult = SPNEGO_ACCEPT_INCOMPLETE;
698                 spnego_state->state_position = SPNEGO_SERVER_TARG;
699         } else if (NT_STATUS_IS_OK(nt_status)) {
700                 if (unwrapped_out.data) {
701                         spnego_out.negTokenTarg.supportedMech = spnego_state->neg_oid;
702                 }
703                 spnego_out.negTokenTarg.negResult = SPNEGO_ACCEPT_COMPLETED;
704                 spnego_out.negTokenTarg.mechListMIC = mech_list_mic;
705                 spnego_state->state_position = SPNEGO_DONE;
706         } else {
707                 spnego_out.negTokenTarg.negResult = SPNEGO_REJECT;
708                 DEBUG(2, ("SPNEGO login failed: %s\n", nt_errstr(nt_status)));
709                 spnego_state->state_position = SPNEGO_DONE;
710         }
711
712         if (spnego_write_data(out_mem_ctx, out, &spnego_out) == -1) {
713                 DEBUG(1, ("Failed to write SPNEGO reply to NEG_TOKEN_TARG\n"));
714                 return NT_STATUS_INVALID_PARAMETER;
715         }
716
717         spnego_state->expected_packet = SPNEGO_NEG_TOKEN_TARG;
718
719         return nt_status;
720 }
721
722
723 static NTSTATUS gensec_spnego_update(struct gensec_security *gensec_security, TALLOC_CTX *out_mem_ctx, 
724                                      const DATA_BLOB in, DATA_BLOB *out) 
725 {
726         struct spnego_state *spnego_state = (struct spnego_state *)gensec_security->private_data;
727         DATA_BLOB null_data_blob = data_blob(NULL, 0);
728         DATA_BLOB mech_list_mic = data_blob(NULL, 0);
729         DATA_BLOB unwrapped_out = data_blob(NULL, 0);
730         struct spnego_data spnego_out;
731         struct spnego_data spnego;
732
733         ssize_t len;
734
735         *out = data_blob(NULL, 0);
736
737         if (!out_mem_ctx) {
738                 out_mem_ctx = spnego_state;
739         }
740
741         /* and switch into the state machine */
742
743         switch (spnego_state->state_position) {
744         case SPNEGO_FALLBACK:
745                 return gensec_update(spnego_state->sub_sec_security,
746                                      out_mem_ctx, in, out);
747         case SPNEGO_SERVER_START:
748         {
749                 NTSTATUS nt_status;
750                 if (in.length) {
751
752                         len = spnego_read_data(gensec_security, in, &spnego);
753                         if (len == -1) {
754                                 return gensec_spnego_server_try_fallback(gensec_security, spnego_state, 
755                                                                          out_mem_ctx, in, out);
756                         }
757                         /* client sent NegTargetInit, we send NegTokenTarg */
758
759                         /* OK, so it's real SPNEGO, check the packet's the one we expect */
760                         if (spnego.type != spnego_state->expected_packet) {
761                                 DEBUG(1, ("Invalid SPNEGO request: %d, expected %d\n", spnego.type, 
762                                           spnego_state->expected_packet));
763                                 dump_data(1, in.data, in.length);
764                                 spnego_free_data(&spnego);
765                                 return NT_STATUS_INVALID_PARAMETER;
766                         }
767                         
768                         nt_status = gensec_spnego_parse_negTokenInit(gensec_security,
769                                                                      spnego_state,
770                                                                      out_mem_ctx, 
771                                                                      spnego.negTokenInit.mechTypes,
772                                                                      spnego.negTokenInit.mechToken, 
773                                                                      &unwrapped_out);
774                         
775                         nt_status = gensec_spnego_server_negTokenTarg(gensec_security,
776                                                                       spnego_state,
777                                                                       out_mem_ctx,
778                                                                       nt_status,
779                                                                       unwrapped_out,
780                                                                       null_data_blob,
781                                                                       out);
782                         
783                         spnego_free_data(&spnego);
784                         
785                         return nt_status;
786                 } else {
787                         nt_status = gensec_spnego_create_negTokenInit(gensec_security, spnego_state, 
788                                                                       out_mem_ctx, in, out);
789                         spnego_state->state_position = SPNEGO_SERVER_START;
790                         spnego_state->expected_packet = SPNEGO_NEG_TOKEN_INIT;
791                         return nt_status;
792                 }
793         }
794         
795         case SPNEGO_CLIENT_START:
796         {
797                 /* The server offers a list of mechanisms */
798                 
799                 const char *my_mechs[] = {NULL, NULL};
800                 NTSTATUS nt_status = NT_STATUS_INVALID_PARAMETER;
801
802                 if (!in.length) {
803                         /* client to produce negTokenInit */
804                         nt_status = gensec_spnego_create_negTokenInit(gensec_security, spnego_state, 
805                                                                  out_mem_ctx, in, out);
806                         spnego_state->state_position = SPNEGO_CLIENT_TARG;
807                         spnego_state->expected_packet = SPNEGO_NEG_TOKEN_TARG;
808                         return nt_status;
809                 }
810                 
811                 len = spnego_read_data(gensec_security, in, &spnego);
812                 
813                 if (len == -1) {
814                         DEBUG(1, ("Invalid SPNEGO request:\n"));
815                         dump_data(1, in.data, in.length);
816                         return NT_STATUS_INVALID_PARAMETER;
817                 }
818                 
819                 /* OK, so it's real SPNEGO, check the packet's the one we expect */
820                 if (spnego.type != spnego_state->expected_packet) {
821                         DEBUG(1, ("Invalid SPNEGO request: %d, expected %d\n", spnego.type, 
822                                   spnego_state->expected_packet));
823                         dump_data(1, in.data, in.length);
824                         spnego_free_data(&spnego);
825                         return NT_STATUS_INVALID_PARAMETER;
826                 }
827
828                 if (spnego.negTokenInit.targetPrincipal) {
829                         DEBUG(5, ("Server claims it's principal name is %s\n", spnego.negTokenInit.targetPrincipal));
830                         if (lpcfg_client_use_spnego_principal(gensec_security->settings->lp_ctx)) {
831                                 gensec_set_target_principal(gensec_security, spnego.negTokenInit.targetPrincipal);
832                         }
833                 }
834
835                 nt_status = gensec_spnego_parse_negTokenInit(gensec_security,
836                                                              spnego_state,
837                                                              out_mem_ctx, 
838                                                              spnego.negTokenInit.mechTypes,
839                                                              spnego.negTokenInit.mechToken, 
840                                                              &unwrapped_out);
841
842                 if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED) && !NT_STATUS_IS_OK(nt_status)) {
843                         spnego_free_data(&spnego);
844                         return nt_status;
845                 }
846
847                 my_mechs[0] = spnego_state->neg_oid;
848                 /* compose reply */
849                 spnego_out.type = SPNEGO_NEG_TOKEN_INIT;
850                 spnego_out.negTokenInit.mechTypes = my_mechs;
851                 spnego_out.negTokenInit.reqFlags = null_data_blob;
852                 spnego_out.negTokenInit.reqFlagsPadding = 0;
853                 spnego_out.negTokenInit.mechListMIC = null_data_blob;
854                 spnego_out.negTokenInit.mechToken = unwrapped_out;
855                 
856                 if (spnego_write_data(out_mem_ctx, out, &spnego_out) == -1) {
857                         DEBUG(1, ("Failed to write SPNEGO reply to NEG_TOKEN_INIT\n"));
858                                 return NT_STATUS_INVALID_PARAMETER;
859                 }
860                 
861                 /* set next state */
862                 spnego_state->expected_packet = SPNEGO_NEG_TOKEN_TARG;
863                 spnego_state->state_position = SPNEGO_CLIENT_TARG;
864
865                 if (NT_STATUS_IS_OK(nt_status)) {
866                         spnego_state->no_response_expected = true;
867                 }
868                 
869                 spnego_free_data(&spnego);
870                 return NT_STATUS_MORE_PROCESSING_REQUIRED;
871         }
872         case SPNEGO_SERVER_TARG:
873         {
874                 NTSTATUS nt_status;
875                 bool new_spnego = false;
876
877                 if (!in.length) {
878                         return NT_STATUS_INVALID_PARAMETER;
879                 }
880                 
881                 len = spnego_read_data(gensec_security, in, &spnego);
882                 
883                 if (len == -1) {
884                         DEBUG(1, ("Invalid SPNEGO request:\n"));
885                         dump_data(1, in.data, in.length);
886                         return NT_STATUS_INVALID_PARAMETER;
887                 }
888                 
889                 /* OK, so it's real SPNEGO, check the packet's the one we expect */
890                 if (spnego.type != spnego_state->expected_packet) {
891                         DEBUG(1, ("Invalid SPNEGO request: %d, expected %d\n", spnego.type, 
892                                   spnego_state->expected_packet));
893                         dump_data(1, in.data, in.length);
894                         spnego_free_data(&spnego);
895                         return NT_STATUS_INVALID_PARAMETER;
896                 }
897
898                 if (!spnego_state->sub_sec_security) {
899                         DEBUG(1, ("SPNEGO: Did not setup a mech in NEG_TOKEN_INIT\n"));
900                         spnego_free_data(&spnego);
901                         return NT_STATUS_INVALID_PARAMETER;
902                 }
903
904                 nt_status = gensec_update(spnego_state->sub_sec_security,
905                                           out_mem_ctx, 
906                                           spnego.negTokenTarg.responseToken,
907                                           &unwrapped_out);
908                 if (NT_STATUS_IS_OK(nt_status) && spnego.negTokenTarg.mechListMIC.length > 0) {
909                         new_spnego = true;
910                         nt_status = gensec_check_packet(spnego_state->sub_sec_security,
911                                                         out_mem_ctx,
912                                                         spnego_state->mech_types.data,
913                                                         spnego_state->mech_types.length,
914                                                         spnego_state->mech_types.data,
915                                                         spnego_state->mech_types.length,
916                                                         &spnego.negTokenTarg.mechListMIC);
917                         if (!NT_STATUS_IS_OK(nt_status)) {
918                                 DEBUG(2,("GENSEC SPNEGO: failed to verify mechListMIC: %s\n",
919                                         nt_errstr(nt_status)));
920                         }
921                 }
922                 if (NT_STATUS_IS_OK(nt_status) && new_spnego) {
923                         nt_status = gensec_sign_packet(spnego_state->sub_sec_security,
924                                                        out_mem_ctx,
925                                                        spnego_state->mech_types.data,
926                                                        spnego_state->mech_types.length,
927                                                        spnego_state->mech_types.data,
928                                                        spnego_state->mech_types.length,
929                                                        &mech_list_mic);
930                         if (!NT_STATUS_IS_OK(nt_status)) {
931                                 DEBUG(2,("GENSEC SPNEGO: failed to sign mechListMIC: %s\n",
932                                         nt_errstr(nt_status)));
933                         }
934                 }
935
936                 nt_status = gensec_spnego_server_negTokenTarg(gensec_security,
937                                                               spnego_state,
938                                                               out_mem_ctx, 
939                                                               nt_status,
940                                                               unwrapped_out,
941                                                               mech_list_mic,
942                                                               out);
943                 
944                 spnego_free_data(&spnego);
945                 
946                 return nt_status;
947         }
948         case SPNEGO_CLIENT_TARG:
949         {
950                 NTSTATUS nt_status;
951                 if (!in.length) {
952                         return NT_STATUS_INVALID_PARAMETER;
953                 }
954                 
955                 len = spnego_read_data(gensec_security, in, &spnego);
956                 
957                 if (len == -1) {
958                         DEBUG(1, ("Invalid SPNEGO request:\n"));
959                         dump_data(1, in.data, in.length);
960                         return NT_STATUS_INVALID_PARAMETER;
961                 }
962                 
963                 /* OK, so it's real SPNEGO, check the packet's the one we expect */
964                 if (spnego.type != spnego_state->expected_packet) {
965                         DEBUG(1, ("Invalid SPNEGO request: %d, expected %d\n", spnego.type, 
966                                   spnego_state->expected_packet));
967                         dump_data(1, in.data, in.length);
968                         spnego_free_data(&spnego);
969                         return NT_STATUS_INVALID_PARAMETER;
970                 }
971         
972                 if (spnego.negTokenTarg.negResult == SPNEGO_REJECT) {
973                         spnego_free_data(&spnego);
974                         return NT_STATUS_ACCESS_DENIED;
975                 }
976
977                 /* Server didn't like our choice of mech, and chose something else */
978                 if ((spnego.negTokenTarg.negResult == SPNEGO_ACCEPT_INCOMPLETE) &&
979                     spnego.negTokenTarg.supportedMech &&
980                     strcmp(spnego.negTokenTarg.supportedMech, spnego_state->neg_oid) != 0) {
981                         DEBUG(3,("GENSEC SPNEGO: client preferred mech (%s) not accepted, server wants: %s\n",
982                                  gensec_get_name_by_oid(gensec_security, spnego.negTokenTarg.supportedMech), 
983                                  gensec_get_name_by_oid(gensec_security, spnego_state->neg_oid)));
984                         
985                         talloc_free(spnego_state->sub_sec_security);
986                         nt_status = gensec_subcontext_start(spnego_state,
987                                                             gensec_security,
988                                                             &spnego_state->sub_sec_security);
989                         if (!NT_STATUS_IS_OK(nt_status)) {
990                                 spnego_free_data(&spnego);
991                                 return nt_status;
992                         }
993                         /* select the sub context */
994                         nt_status = gensec_start_mech_by_oid(spnego_state->sub_sec_security,
995                                                              spnego.negTokenTarg.supportedMech);
996                         if (!NT_STATUS_IS_OK(nt_status)) {
997                                 spnego_free_data(&spnego);
998                                 return nt_status;
999                         }
1000
1001                         nt_status = gensec_update(spnego_state->sub_sec_security,
1002                                                   out_mem_ctx, 
1003                                                   spnego.negTokenTarg.responseToken,
1004                                                   &unwrapped_out);
1005                         spnego_state->neg_oid = talloc_strdup(spnego_state, spnego.negTokenTarg.supportedMech);
1006                 } else if (spnego_state->no_response_expected) {
1007                         if (spnego.negTokenTarg.negResult != SPNEGO_ACCEPT_COMPLETED) {
1008                                 DEBUG(3,("GENSEC SPNEGO: client GENSEC accepted, but server rejected (bad password?)\n"));
1009                                 nt_status = NT_STATUS_INVALID_PARAMETER;
1010                         } else if (spnego.negTokenTarg.responseToken.length) {
1011                                 DEBUG(2,("GENSEC SPNEGO: client GENSEC accepted, but server continued negotiation!\n"));
1012                                 nt_status = NT_STATUS_INVALID_PARAMETER;
1013                         } else {
1014                                 nt_status = NT_STATUS_OK;
1015                         }
1016                         if (NT_STATUS_IS_OK(nt_status) && spnego.negTokenTarg.mechListMIC.length > 0) {
1017                                 nt_status = gensec_check_packet(spnego_state->sub_sec_security,
1018                                                                 out_mem_ctx,
1019                                                                 spnego_state->mech_types.data,
1020                                                                 spnego_state->mech_types.length,
1021                                                                 spnego_state->mech_types.data,
1022                                                                 spnego_state->mech_types.length,
1023                                                                 &spnego.negTokenTarg.mechListMIC);
1024                                 if (!NT_STATUS_IS_OK(nt_status)) {
1025                                         DEBUG(2,("GENSEC SPNEGO: failed to verify mechListMIC: %s\n",
1026                                                 nt_errstr(nt_status)));
1027                                 }
1028                         }
1029                 } else {
1030                         bool new_spnego = false;
1031
1032                         nt_status = gensec_update(spnego_state->sub_sec_security,
1033                                                   out_mem_ctx, 
1034                                                   spnego.negTokenTarg.responseToken, 
1035                                                   &unwrapped_out);
1036
1037                         if (NT_STATUS_IS_OK(nt_status)
1038                             && spnego.negTokenTarg.negResult != SPNEGO_ACCEPT_COMPLETED) {
1039                                 new_spnego = gensec_have_feature(spnego_state->sub_sec_security,
1040                                                                  GENSEC_FEATURE_NEW_SPNEGO);
1041                         }
1042                         if (NT_STATUS_IS_OK(nt_status) && new_spnego) {
1043                                 nt_status = gensec_sign_packet(spnego_state->sub_sec_security,
1044                                                                out_mem_ctx,
1045                                                                spnego_state->mech_types.data,
1046                                                                spnego_state->mech_types.length,
1047                                                                spnego_state->mech_types.data,
1048                                                                spnego_state->mech_types.length,
1049                                                                &mech_list_mic);
1050                                 if (!NT_STATUS_IS_OK(nt_status)) {
1051                                         DEBUG(2,("GENSEC SPNEGO: failed to sign mechListMIC: %s\n",
1052                                                 nt_errstr(nt_status)));
1053                                 }
1054                         }
1055                         if (NT_STATUS_IS_OK(nt_status)) {
1056                                 spnego_state->no_response_expected = true;
1057                         }
1058                 } 
1059                 
1060                 spnego_free_data(&spnego);
1061
1062                 if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)
1063                         && !NT_STATUS_IS_OK(nt_status)) {
1064                         DEBUG(1, ("SPNEGO(%s) login failed: %s\n", 
1065                                   spnego_state->sub_sec_security->ops->name, 
1066                                   nt_errstr(nt_status)));
1067                         return nt_status;
1068                 }
1069
1070                 if (unwrapped_out.length || mech_list_mic.length) {
1071                         /* compose reply */
1072                         spnego_out.type = SPNEGO_NEG_TOKEN_TARG;
1073                         spnego_out.negTokenTarg.negResult = SPNEGO_NONE_RESULT;
1074                         spnego_out.negTokenTarg.supportedMech = NULL;
1075                         spnego_out.negTokenTarg.responseToken = unwrapped_out;
1076                         spnego_out.negTokenTarg.mechListMIC = mech_list_mic;
1077                         
1078                         if (spnego_write_data(out_mem_ctx, out, &spnego_out) == -1) {
1079                                 DEBUG(1, ("Failed to write SPNEGO reply to NEG_TOKEN_TARG\n"));
1080                                 return NT_STATUS_INVALID_PARAMETER;
1081                         }
1082                 
1083                         spnego_state->state_position = SPNEGO_CLIENT_TARG;
1084                         nt_status = NT_STATUS_MORE_PROCESSING_REQUIRED;
1085                 } else {
1086
1087                         /* all done - server has accepted, and we agree */
1088                         *out = null_data_blob;
1089
1090                         if (spnego.negTokenTarg.negResult != SPNEGO_ACCEPT_COMPLETED) {
1091                                 /* unless of course it did not accept */
1092                                 DEBUG(1,("gensec_update ok but not accepted\n"));
1093                                 nt_status = NT_STATUS_INVALID_PARAMETER;
1094                         }
1095                 
1096                         spnego_state->state_position = SPNEGO_DONE;
1097                 }
1098
1099                 return nt_status;
1100         }
1101         case SPNEGO_DONE:
1102                 /* We should not be called after we are 'done' */
1103                 return NT_STATUS_INVALID_PARAMETER;
1104         }
1105         return NT_STATUS_INVALID_PARAMETER;
1106 }
1107
1108 static void gensec_spnego_want_feature(struct gensec_security *gensec_security,
1109                                        uint32_t feature)
1110 {
1111         struct spnego_state *spnego_state = (struct spnego_state *)gensec_security->private_data;
1112
1113         if (!spnego_state || !spnego_state->sub_sec_security) {
1114                 gensec_security->want_features |= feature;
1115                 return;
1116         }
1117
1118         gensec_want_feature(spnego_state->sub_sec_security,
1119                             feature);
1120 }
1121
1122 static bool gensec_spnego_have_feature(struct gensec_security *gensec_security,
1123                                        uint32_t feature) 
1124 {
1125         struct spnego_state *spnego_state = (struct spnego_state *)gensec_security->private_data;
1126         if (!spnego_state->sub_sec_security) {
1127                 return false;
1128         }
1129         
1130         return gensec_have_feature(spnego_state->sub_sec_security, 
1131                                    feature);
1132 }
1133
1134 static const char *gensec_spnego_oids[] = { 
1135         GENSEC_OID_SPNEGO,
1136         NULL 
1137 };
1138
1139 static const struct gensec_security_ops gensec_spnego_security_ops = {
1140         .name             = "spnego",
1141         .sasl_name        = "GSS-SPNEGO",
1142         .auth_type        = DCERPC_AUTH_TYPE_SPNEGO,
1143         .oid              = gensec_spnego_oids,
1144         .client_start     = gensec_spnego_client_start,
1145         .server_start     = gensec_spnego_server_start,
1146         .update           = gensec_spnego_update,
1147         .seal_packet      = gensec_spnego_seal_packet,
1148         .sign_packet      = gensec_spnego_sign_packet,
1149         .sig_size         = gensec_spnego_sig_size,
1150         .max_wrapped_size = gensec_spnego_max_wrapped_size,
1151         .max_input_size   = gensec_spnego_max_input_size,
1152         .check_packet     = gensec_spnego_check_packet,
1153         .unseal_packet    = gensec_spnego_unseal_packet,
1154         .packet_full_request = gensec_spnego_packet_full_request,
1155         .wrap             = gensec_spnego_wrap,
1156         .unwrap           = gensec_spnego_unwrap,
1157         .wrap_packets     = gensec_spnego_wrap_packets,
1158         .unwrap_packets   = gensec_spnego_unwrap_packets,
1159         .session_key      = gensec_spnego_session_key,
1160         .session_info     = gensec_spnego_session_info,
1161         .want_feature     = gensec_spnego_want_feature,
1162         .have_feature     = gensec_spnego_have_feature,
1163         .enabled          = true,
1164         .priority         = GENSEC_SPNEGO
1165 };
1166
1167 _PUBLIC_ NTSTATUS gensec_spnego_init(void)
1168 {
1169         NTSTATUS ret;
1170         ret = gensec_register(&gensec_spnego_security_ops);
1171         if (!NT_STATUS_IS_OK(ret)) {
1172                 DEBUG(0,("Failed to register '%s' gensec backend!\n",
1173                         gensec_spnego_security_ops.name));
1174                 return ret;
1175         }
1176
1177         return ret;
1178 }