gensec: move event context from gensec_*_init() to gensec_update()
[samba.git] / source4 / auth / gensec / gensec_gssapi.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    Kerberos backend for GENSEC
5    
6    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2005
7    Copyright (C) Stefan Metzmacher <metze@samba.org> 2004-2005
8
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 3 of the License, or
12    (at your option) any later version.
13    
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.
18
19    
20    You should have received a copy of the GNU General Public License
21    along with this program.  If not, see <http://www.gnu.org/licenses/>.
22 */
23
24 #include "includes.h"
25 #include "lib/events/events.h"
26 #include "system/kerberos.h"
27 #include "auth/kerberos/kerberos.h"
28 #include "librpc/gen_ndr/krb5pac.h"
29 #include "auth/auth.h"
30 #include <ldb.h>
31 #include "auth/auth_sam.h"
32 #include "librpc/rpc/dcerpc.h"
33 #include "auth/credentials/credentials.h"
34 #include "auth/credentials/credentials_krb5.h"
35 #include "auth/gensec/gensec.h"
36 #include "auth/gensec/gensec_proto.h"
37 #include "auth/gensec/gensec_toplevel_proto.h"
38 #include "param/param.h"
39 #include "auth/session_proto.h"
40 #include <gssapi/gssapi.h>
41 #include <gssapi/gssapi_krb5.h>
42 #include <gssapi/gssapi_spnego.h>
43 #include "auth/gensec/gensec_gssapi.h"
44 #include "lib/util/util_net.h"
45
46 _PUBLIC_ NTSTATUS gensec_gssapi_init(void);
47
48 static size_t gensec_gssapi_max_input_size(struct gensec_security *gensec_security);
49 static size_t gensec_gssapi_max_wrapped_size(struct gensec_security *gensec_security);
50
51 static int gensec_gssapi_destructor(struct gensec_gssapi_state *gensec_gssapi_state)
52 {
53         OM_uint32 maj_stat, min_stat;
54         
55         if (gensec_gssapi_state->delegated_cred_handle != GSS_C_NO_CREDENTIAL) {
56                 maj_stat = gss_release_cred(&min_stat, 
57                                             &gensec_gssapi_state->delegated_cred_handle);
58         }
59
60         if (gensec_gssapi_state->gssapi_context != GSS_C_NO_CONTEXT) {
61                 maj_stat = gss_delete_sec_context (&min_stat,
62                                                    &gensec_gssapi_state->gssapi_context,
63                                                    GSS_C_NO_BUFFER);
64         }
65
66         if (gensec_gssapi_state->server_name != GSS_C_NO_NAME) {
67                 maj_stat = gss_release_name(&min_stat, &gensec_gssapi_state->server_name);
68         }
69         if (gensec_gssapi_state->client_name != GSS_C_NO_NAME) {
70                 maj_stat = gss_release_name(&min_stat, &gensec_gssapi_state->client_name);
71         }
72
73         if (gensec_gssapi_state->lucid) {
74                 gss_krb5_free_lucid_sec_context(&min_stat, gensec_gssapi_state->lucid);
75         }
76
77         return 0;
78 }
79
80 static NTSTATUS gensec_gssapi_init_lucid(struct gensec_gssapi_state *gensec_gssapi_state)
81 {
82         OM_uint32 maj_stat, min_stat;
83
84         if (gensec_gssapi_state->lucid) {
85                 return NT_STATUS_OK;
86         }
87
88         maj_stat = gss_krb5_export_lucid_sec_context(&min_stat,
89                                                      &gensec_gssapi_state->gssapi_context,
90                                                      1,
91                                                      (void **)&gensec_gssapi_state->lucid);
92         if (maj_stat != GSS_S_COMPLETE) {
93                 DEBUG(0,("gensec_gssapi_init_lucid: %s\n",
94                         gssapi_error_string(gensec_gssapi_state,
95                                             maj_stat, min_stat,
96                                             gensec_gssapi_state->gss_oid)));
97                 return NT_STATUS_INTERNAL_ERROR;
98         }
99
100         if (gensec_gssapi_state->lucid->version != 1) {
101                 DEBUG(0,("gensec_gssapi_init_lucid: lucid version[%d] != 1\n",
102                         gensec_gssapi_state->lucid->version));
103                 gss_krb5_free_lucid_sec_context(&min_stat, gensec_gssapi_state->lucid);
104                 gensec_gssapi_state->lucid = NULL;
105                 return NT_STATUS_INTERNAL_ERROR;
106         }
107
108         return NT_STATUS_OK;
109 }
110
111 static NTSTATUS gensec_gssapi_start(struct gensec_security *gensec_security)
112 {
113         struct gensec_gssapi_state *gensec_gssapi_state;
114         krb5_error_code ret;
115         const char *realm;
116
117         gensec_gssapi_state = talloc_zero(gensec_security, struct gensec_gssapi_state);
118         if (!gensec_gssapi_state) {
119                 return NT_STATUS_NO_MEMORY;
120         }
121
122         gensec_security->private_data = gensec_gssapi_state;
123
124         gensec_gssapi_state->gssapi_context = GSS_C_NO_CONTEXT;
125
126         /* TODO: Fill in channel bindings */
127         gensec_gssapi_state->input_chan_bindings = GSS_C_NO_CHANNEL_BINDINGS;
128
129         gensec_gssapi_state->server_name = GSS_C_NO_NAME;
130         gensec_gssapi_state->client_name = GSS_C_NO_NAME;
131         
132         gensec_gssapi_state->want_flags = 0;
133
134         if (gensec_setting_bool(gensec_security->settings, "gensec_gssapi", "delegation_by_kdc_policy", true)) {
135                 gensec_gssapi_state->want_flags |= GSS_C_DELEG_POLICY_FLAG;
136         }
137         if (gensec_setting_bool(gensec_security->settings, "gensec_gssapi", "mutual", true)) {
138                 gensec_gssapi_state->want_flags |= GSS_C_MUTUAL_FLAG;
139         }
140         if (gensec_setting_bool(gensec_security->settings, "gensec_gssapi", "delegation", true)) {
141                 gensec_gssapi_state->want_flags |= GSS_C_DELEG_FLAG;
142         }
143         if (gensec_setting_bool(gensec_security->settings, "gensec_gssapi", "replay", true)) {
144                 gensec_gssapi_state->want_flags |= GSS_C_REPLAY_FLAG;
145         }
146         if (gensec_setting_bool(gensec_security->settings, "gensec_gssapi", "sequence", true)) {
147                 gensec_gssapi_state->want_flags |= GSS_C_SEQUENCE_FLAG;
148         }
149
150         if (gensec_security->want_features & GENSEC_FEATURE_SIGN) {
151                 gensec_gssapi_state->want_flags |= GSS_C_INTEG_FLAG;
152         }
153         if (gensec_security->want_features & GENSEC_FEATURE_SEAL) {
154                 gensec_gssapi_state->want_flags |= GSS_C_CONF_FLAG;
155         }
156         if (gensec_security->want_features & GENSEC_FEATURE_DCE_STYLE) {
157                 gensec_gssapi_state->want_flags |= GSS_C_DCE_STYLE;
158         }
159
160         gensec_gssapi_state->got_flags = 0;
161
162         switch (gensec_security->ops->auth_type) {
163         case DCERPC_AUTH_TYPE_SPNEGO:
164                 gensec_gssapi_state->gss_oid = gss_mech_spnego;
165                 break;
166         case DCERPC_AUTH_TYPE_KRB5:
167         default:
168                 gensec_gssapi_state->gss_oid = gss_mech_krb5;
169                 break;
170         }
171
172         ret = smb_krb5_init_context(gensec_gssapi_state,
173                                     NULL,
174                                     gensec_security->settings->lp_ctx,
175                                     &gensec_gssapi_state->smb_krb5_context);
176         if (ret) {
177                 DEBUG(1,("gensec_krb5_start: krb5_init_context failed (%s)\n",
178                          error_message(ret)));
179                 talloc_free(gensec_gssapi_state);
180                 return NT_STATUS_INTERNAL_ERROR;
181         }
182
183         gensec_gssapi_state->client_cred = NULL;
184         gensec_gssapi_state->server_cred = NULL;
185
186         gensec_gssapi_state->lucid = NULL;
187
188         gensec_gssapi_state->delegated_cred_handle = GSS_C_NO_CREDENTIAL;
189
190         gensec_gssapi_state->sasl = false;
191         gensec_gssapi_state->sasl_state = STAGE_GSS_NEG;
192         gensec_gssapi_state->sasl_protection = 0;
193
194         gensec_gssapi_state->max_wrap_buf_size
195                 = gensec_setting_int(gensec_security->settings, "gensec_gssapi", "max wrap buf size", 65536);
196         gensec_gssapi_state->gss_exchange_count = 0;
197         gensec_gssapi_state->sig_size = 0;
198
199         talloc_set_destructor(gensec_gssapi_state, gensec_gssapi_destructor);
200
201         realm = lpcfg_realm(gensec_security->settings->lp_ctx);
202         if (realm != NULL) {
203                 ret = gsskrb5_set_default_realm(realm);
204                 if (ret) {
205                         DEBUG(1,("gensec_krb5_start: gsskrb5_set_default_realm failed\n"));
206                         talloc_free(gensec_gssapi_state);
207                         return NT_STATUS_INTERNAL_ERROR;
208                 }
209         }
210
211         /* don't do DNS lookups of any kind, it might/will fail for a netbios name */
212         ret = gsskrb5_set_dns_canonicalize(gensec_setting_bool(gensec_security->settings, "krb5", "set_dns_canonicalize", false));
213         if (ret) {
214                 DEBUG(1,("gensec_krb5_start: gsskrb5_set_dns_canonicalize failed\n"));
215                 talloc_free(gensec_gssapi_state);
216                 return NT_STATUS_INTERNAL_ERROR;
217         }
218
219         return NT_STATUS_OK;
220 }
221
222 static NTSTATUS gensec_gssapi_server_start(struct gensec_security *gensec_security)
223 {
224         NTSTATUS nt_status;
225         int ret;
226         struct gensec_gssapi_state *gensec_gssapi_state;
227         struct cli_credentials *machine_account;
228         struct gssapi_creds_container *gcc;
229
230         nt_status = gensec_gssapi_start(gensec_security);
231         if (!NT_STATUS_IS_OK(nt_status)) {
232                 return nt_status;
233         }
234
235         gensec_gssapi_state = talloc_get_type(gensec_security->private_data, struct gensec_gssapi_state);
236
237         machine_account = gensec_get_credentials(gensec_security);
238         
239         if (!machine_account) {
240                 DEBUG(3, ("No machine account credentials specified\n"));
241                 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
242         } else {
243                 ret = cli_credentials_get_server_gss_creds(machine_account, 
244                                                            gensec_security->settings->lp_ctx, &gcc);
245                 if (ret) {
246                         DEBUG(1, ("Aquiring acceptor credentials failed: %s\n", 
247                                   error_message(ret)));
248                         return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
249                 }
250         }
251
252         gensec_gssapi_state->server_cred = gcc;
253         return NT_STATUS_OK;
254
255 }
256
257 static NTSTATUS gensec_gssapi_sasl_server_start(struct gensec_security *gensec_security)
258 {
259         NTSTATUS nt_status;
260         struct gensec_gssapi_state *gensec_gssapi_state;
261         nt_status = gensec_gssapi_server_start(gensec_security);
262
263         if (NT_STATUS_IS_OK(nt_status)) {
264                 gensec_gssapi_state = talloc_get_type(gensec_security->private_data, struct gensec_gssapi_state);
265                 gensec_gssapi_state->sasl = true;
266         }
267         return nt_status;
268 }
269
270 static NTSTATUS gensec_gssapi_client_creds(struct gensec_security *gensec_security,
271                                            struct tevent_context *ev)
272 {
273         struct gensec_gssapi_state *gensec_gssapi_state;
274         struct gssapi_creds_container *gcc;
275         struct cli_credentials *creds = gensec_get_credentials(gensec_security);
276         const char *error_string;
277         int ret;
278
279         gensec_gssapi_state = talloc_get_type(gensec_security->private_data, struct gensec_gssapi_state);
280
281         /* Only run this the first time the update() call is made */
282         if (gensec_gssapi_state->client_cred) {
283                 return NT_STATUS_OK;
284         }
285
286         ret = cli_credentials_get_client_gss_creds(creds,
287                                                    ev,
288                                                    gensec_security->settings->lp_ctx, &gcc, &error_string);
289         switch (ret) {
290         case 0:
291                 break;
292         case EINVAL:
293                 DEBUG(3, ("Cannot obtain client GSS credentials we need to contact %s : %s\n", gensec_gssapi_state->target_principal, error_string));
294                 return NT_STATUS_INVALID_PARAMETER;
295         case KRB5KDC_ERR_PREAUTH_FAILED:
296         case KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN:
297                 DEBUG(1, ("Wrong username or password: %s\n", error_string));
298                 return NT_STATUS_LOGON_FAILURE;
299         case KRB5_KDC_UNREACH:
300                 DEBUG(3, ("Cannot reach a KDC we require to contact %s : %s\n", gensec_gssapi_state->target_principal, error_string));
301                 return NT_STATUS_NO_LOGON_SERVERS;
302         case KRB5_CC_NOTFOUND:
303         case KRB5_CC_END:
304                 DEBUG(2, ("Error obtaining ticket we require to contact %s: (possibly due to clock skew between us and the KDC) %s\n", gensec_gssapi_state->target_principal, error_string));
305                 return NT_STATUS_TIME_DIFFERENCE_AT_DC;
306         default:
307                 DEBUG(1, ("Aquiring initiator credentials failed: %s\n", error_string));
308                 return NT_STATUS_UNSUCCESSFUL;
309         }
310
311         gensec_gssapi_state->client_cred = gcc;
312         if (!talloc_reference(gensec_gssapi_state, gcc)) {
313                 return NT_STATUS_NO_MEMORY;
314         }
315
316         return NT_STATUS_OK;
317 }
318
319 static NTSTATUS gensec_gssapi_client_start(struct gensec_security *gensec_security)
320 {
321         struct gensec_gssapi_state *gensec_gssapi_state;
322         struct cli_credentials *creds = gensec_get_credentials(gensec_security);
323         NTSTATUS nt_status;
324         gss_buffer_desc name_token;
325         gss_OID name_type;
326         OM_uint32 maj_stat, min_stat;
327         const char *hostname = gensec_get_target_hostname(gensec_security);
328
329         if (!hostname) {
330                 DEBUG(1, ("Could not determine hostname for target computer, cannot use kerberos\n"));
331                 return NT_STATUS_INVALID_PARAMETER;
332         }
333         if (is_ipaddress(hostname)) {
334                 DEBUG(2, ("Cannot do GSSAPI to an IP address\n"));
335                 return NT_STATUS_INVALID_PARAMETER;
336         }
337         if (strcmp(hostname, "localhost") == 0) {
338                 DEBUG(2, ("GSSAPI to 'localhost' does not make sense\n"));
339                 return NT_STATUS_INVALID_PARAMETER;
340         }
341
342         nt_status = gensec_gssapi_start(gensec_security);
343         if (!NT_STATUS_IS_OK(nt_status)) {
344                 return nt_status;
345         }
346
347         gensec_gssapi_state = talloc_get_type(gensec_security->private_data, struct gensec_gssapi_state);
348
349         if (cli_credentials_get_impersonate_principal(creds)) {
350                 gensec_gssapi_state->want_flags &= ~(GSS_C_DELEG_FLAG|GSS_C_DELEG_POLICY_FLAG);
351         }
352
353         gensec_gssapi_state->target_principal = gensec_get_target_principal(gensec_security);
354         if (gensec_gssapi_state->target_principal) {
355                 name_type = GSS_C_NULL_OID;
356         } else {
357                 gensec_gssapi_state->target_principal = talloc_asprintf(gensec_gssapi_state, "%s/%s@%s",
358                                             gensec_get_target_service(gensec_security), 
359                                             hostname, lpcfg_realm(gensec_security->settings->lp_ctx));
360
361                 name_type = GSS_C_NT_USER_NAME;
362         }
363         name_token.value  = discard_const_p(uint8_t, gensec_gssapi_state->target_principal);
364         name_token.length = strlen(gensec_gssapi_state->target_principal);
365
366
367         maj_stat = gss_import_name (&min_stat,
368                                     &name_token,
369                                     name_type,
370                                     &gensec_gssapi_state->server_name);
371         if (maj_stat) {
372                 DEBUG(2, ("GSS Import name of %s failed: %s\n",
373                           (char *)name_token.value,
374                           gssapi_error_string(gensec_gssapi_state, maj_stat, min_stat, gensec_gssapi_state->gss_oid)));
375                 return NT_STATUS_INVALID_PARAMETER;
376         }
377
378         return NT_STATUS_OK;
379 }
380
381 static NTSTATUS gensec_gssapi_sasl_client_start(struct gensec_security *gensec_security)
382 {
383         NTSTATUS nt_status;
384         struct gensec_gssapi_state *gensec_gssapi_state;
385         nt_status = gensec_gssapi_client_start(gensec_security);
386
387         if (NT_STATUS_IS_OK(nt_status)) {
388                 gensec_gssapi_state = talloc_get_type(gensec_security->private_data, struct gensec_gssapi_state);
389                 gensec_gssapi_state->sasl = true;
390         }
391         return nt_status;
392 }
393
394
395 /**
396  * Check if the packet is one for this mechansim
397  * 
398  * @param gensec_security GENSEC state
399  * @param in The request, as a DATA_BLOB
400  * @return Error, INVALID_PARAMETER if it's not a packet for us
401  *                or NT_STATUS_OK if the packet is ok. 
402  */
403
404 static NTSTATUS gensec_gssapi_magic(struct gensec_security *gensec_security, 
405                                     const DATA_BLOB *in) 
406 {
407         if (gensec_gssapi_check_oid(in, GENSEC_OID_KERBEROS5)) {
408                 return NT_STATUS_OK;
409         } else {
410                 return NT_STATUS_INVALID_PARAMETER;
411         }
412 }
413
414
415 /**
416  * Next state function for the GSSAPI GENSEC mechanism
417  * 
418  * @param gensec_gssapi_state GSSAPI State
419  * @param out_mem_ctx The TALLOC_CTX for *out to be allocated on
420  * @param in The request, as a DATA_BLOB
421  * @param out The reply, as an talloc()ed DATA_BLOB, on *out_mem_ctx
422  * @return Error, MORE_PROCESSING_REQUIRED if a reply is sent, 
423  *                or NT_STATUS_OK if the user is authenticated. 
424  */
425
426 static NTSTATUS gensec_gssapi_update(struct gensec_security *gensec_security, 
427                                      TALLOC_CTX *out_mem_ctx,
428                                      struct tevent_context *ev,
429                                      const DATA_BLOB in, DATA_BLOB *out)
430 {
431         struct gensec_gssapi_state *gensec_gssapi_state
432                 = talloc_get_type(gensec_security->private_data, struct gensec_gssapi_state);
433         NTSTATUS nt_status = NT_STATUS_LOGON_FAILURE;
434         OM_uint32 maj_stat, min_stat;
435         OM_uint32 min_stat2;
436         gss_buffer_desc input_token, output_token;
437         gss_OID gss_oid_p = NULL;
438         input_token.length = in.length;
439         input_token.value = in.data;
440
441         switch (gensec_gssapi_state->sasl_state) {
442         case STAGE_GSS_NEG:
443         {
444                 switch (gensec_security->gensec_role) {
445                 case GENSEC_CLIENT:
446                 {
447                         struct gsskrb5_send_to_kdc send_to_kdc;
448                         krb5_error_code ret;
449
450                         nt_status = gensec_gssapi_client_creds(gensec_security, ev);
451                         if (!NT_STATUS_IS_OK(nt_status)) {
452                                 return nt_status;
453                         }
454
455                         send_to_kdc.func = smb_krb5_send_and_recv_func;
456                         send_to_kdc.ptr = ev;
457
458                         min_stat = gsskrb5_set_send_to_kdc(&send_to_kdc);
459                         if (min_stat) {
460                                 DEBUG(1,("gensec_krb5_start: gsskrb5_set_send_to_kdc failed\n"));
461                                 return NT_STATUS_INTERNAL_ERROR;
462                         }
463
464                         maj_stat = gss_init_sec_context(&min_stat, 
465                                                         gensec_gssapi_state->client_cred->creds,
466                                                         &gensec_gssapi_state->gssapi_context, 
467                                                         gensec_gssapi_state->server_name, 
468                                                         gensec_gssapi_state->gss_oid,
469                                                         gensec_gssapi_state->want_flags, 
470                                                         0, 
471                                                         gensec_gssapi_state->input_chan_bindings,
472                                                         &input_token, 
473                                                         &gss_oid_p,
474                                                         &output_token, 
475                                                         &gensec_gssapi_state->got_flags, /* ret flags */
476                                                         NULL);
477                         if (gss_oid_p) {
478                                 gensec_gssapi_state->gss_oid = gss_oid_p;
479                         }
480
481                         send_to_kdc.func = smb_krb5_send_and_recv_func;
482                         send_to_kdc.ptr = NULL;
483
484                         ret = gsskrb5_set_send_to_kdc(&send_to_kdc);
485                         if (ret) {
486                                 DEBUG(1,("gensec_krb5_start: gsskrb5_set_send_to_kdc failed\n"));
487                                 return NT_STATUS_INTERNAL_ERROR;
488                         }
489
490                         break;
491                 }
492                 case GENSEC_SERVER:
493                 {
494                         maj_stat = gss_accept_sec_context(&min_stat, 
495                                                           &gensec_gssapi_state->gssapi_context, 
496                                                           gensec_gssapi_state->server_cred->creds,
497                                                           &input_token, 
498                                                           gensec_gssapi_state->input_chan_bindings,
499                                                           &gensec_gssapi_state->client_name, 
500                                                           &gss_oid_p,
501                                                           &output_token, 
502                                                           &gensec_gssapi_state->got_flags, 
503                                                           NULL, 
504                                                           &gensec_gssapi_state->delegated_cred_handle);
505                         if (gss_oid_p) {
506                                 gensec_gssapi_state->gss_oid = gss_oid_p;
507                         }
508                         break;
509                 }
510                 default:
511                         return NT_STATUS_INVALID_PARAMETER;
512                         
513                 }
514
515                 gensec_gssapi_state->gss_exchange_count++;
516
517                 if (maj_stat == GSS_S_COMPLETE) {
518                         *out = data_blob_talloc(out_mem_ctx, output_token.value, output_token.length);
519                         gss_release_buffer(&min_stat2, &output_token);
520                         
521                         if (gensec_gssapi_state->got_flags & GSS_C_DELEG_FLAG) {
522                                 DEBUG(5, ("gensec_gssapi: credentials were delegated\n"));
523                         } else {
524                                 DEBUG(5, ("gensec_gssapi: NO credentials were delegated\n"));
525                         }
526
527                         /* We may have been invoked as SASL, so there
528                          * is more work to do */
529                         if (gensec_gssapi_state->sasl) {
530                                 gensec_gssapi_state->sasl_state = STAGE_SASL_SSF_NEG;
531                                 return NT_STATUS_MORE_PROCESSING_REQUIRED;
532                         } else {
533                                 gensec_gssapi_state->sasl_state = STAGE_DONE;
534
535                                 if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
536                                         DEBUG(5, ("GSSAPI Connection will be cryptographically sealed\n"));
537                                 } else if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
538                                         DEBUG(5, ("GSSAPI Connection will be cryptographically signed\n"));
539                                 } else {
540                                         DEBUG(5, ("GSSAPI Connection will have no cryptographic protection\n"));
541                                 }
542
543                                 return NT_STATUS_OK;
544                         }
545                 } else if (maj_stat == GSS_S_CONTINUE_NEEDED) {
546                         *out = data_blob_talloc(out_mem_ctx, output_token.value, output_token.length);
547                         gss_release_buffer(&min_stat2, &output_token);
548                         
549                         return NT_STATUS_MORE_PROCESSING_REQUIRED;
550                 } else if (maj_stat == GSS_S_CONTEXT_EXPIRED) {
551                         gss_cred_id_t creds;
552                         gss_name_t name;
553                         gss_buffer_desc buffer;
554                         OM_uint32 lifetime = 0;
555                         gss_cred_usage_t usage;
556                         const char *role = NULL;
557                         DEBUG(0, ("GSS %s Update(krb5)(%d) Update failed, credentials expired during GSSAPI handshake!\n",
558                                   role,
559                                   gensec_gssapi_state->gss_exchange_count));
560
561                         
562                         switch (gensec_security->gensec_role) {
563                         case GENSEC_CLIENT:
564                                 creds = gensec_gssapi_state->client_cred->creds;
565                                 role = "client";
566                         case GENSEC_SERVER:
567                                 creds = gensec_gssapi_state->server_cred->creds;
568                                 role = "server";
569                         }
570
571                         maj_stat = gss_inquire_cred(&min_stat, 
572                                                     creds,
573                                                     &name, &lifetime, &usage, NULL);
574
575                         if (maj_stat == GSS_S_COMPLETE) {
576                                 const char *usage_string;
577                                 switch (usage) {
578                                 case GSS_C_BOTH:
579                                         usage_string = "GSS_C_BOTH";
580                                         break;
581                                 case GSS_C_ACCEPT:
582                                         usage_string = "GSS_C_ACCEPT";
583                                         break;
584                                 case GSS_C_INITIATE:
585                                         usage_string = "GSS_C_INITIATE";
586                                         break;
587                                 }
588                                 maj_stat = gss_display_name(&min_stat, name, &buffer, NULL);
589                                 if (maj_stat) {
590                                         buffer.value = NULL;
591                                         buffer.length = 0;
592                                 }
593                                 if (lifetime > 0) {
594                                         DEBUG(0, ("GSSAPI gss_inquire_cred indicates expiry of %*.*s in %u sec for %s\n", 
595                                                   (int)buffer.length, (int)buffer.length, (char *)buffer.value, 
596                                                   lifetime, usage_string));
597                                 } else {
598                                         DEBUG(0, ("GSSAPI gss_inquire_cred indicates %*.*s has already expired for %s\n", 
599                                                   (int)buffer.length, (int)buffer.length, (char *)buffer.value, 
600                                                   usage_string));
601                                 }
602                                 gss_release_buffer(&min_stat, &buffer);
603                                 gss_release_name(&min_stat, &name);
604                         } else if (maj_stat != GSS_S_COMPLETE) {
605                                 DEBUG(0, ("inquiry of credential lifefime via GSSAPI gss_inquire_cred failed: %s\n",
606                                           gssapi_error_string(out_mem_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid)));
607                         }
608                         return NT_STATUS_INVALID_PARAMETER;
609                 } else if (gss_oid_equal(gensec_gssapi_state->gss_oid, gss_mech_krb5)) {
610                         switch (min_stat) {
611                         case KRB5KRB_AP_ERR_TKT_NYV:
612                                 DEBUG(1, ("Error with ticket to contact %s: possible clock skew between us and the KDC or target server: %s\n",
613                                           gensec_gssapi_state->target_principal,
614                                           gssapi_error_string(out_mem_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid)));
615                                 return NT_STATUS_TIME_DIFFERENCE_AT_DC; /* Make SPNEGO ignore us, we can't go any further here */
616                         case KRB5KRB_AP_ERR_TKT_EXPIRED:
617                                 DEBUG(1, ("Error with ticket to contact %s: ticket is expired, possible clock skew between us and the KDC or target server: %s\n",
618                                           gensec_gssapi_state->target_principal,
619                                           gssapi_error_string(out_mem_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid)));
620                                 return NT_STATUS_INVALID_PARAMETER; /* Make SPNEGO ignore us, we can't go any further here */
621                         case KRB5_KDC_UNREACH:
622                                 DEBUG(3, ("Cannot reach a KDC we require in order to obtain a ticetk to %s: %s\n",
623                                           gensec_gssapi_state->target_principal,
624                                           gssapi_error_string(out_mem_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid)));
625                                 return NT_STATUS_NO_LOGON_SERVERS; /* Make SPNEGO ignore us, we can't go any further here */
626                         case KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN:
627                                 DEBUG(3, ("Server %s is not registered with our KDC: %s\n",
628                                           gensec_gssapi_state->target_principal,
629                                           gssapi_error_string(out_mem_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid)));
630                                 return NT_STATUS_INVALID_PARAMETER; /* Make SPNEGO ignore us, we can't go any further here */
631                         case KRB5KRB_AP_ERR_MSG_TYPE:
632                                 /* garbage input, possibly from the auto-mech detection */
633                                 return NT_STATUS_INVALID_PARAMETER;
634                         default:
635                                 DEBUG(1, ("GSS %s Update(krb5)(%d) Update failed: %s\n",
636                                           gensec_security->gensec_role == GENSEC_CLIENT ? "client" : "server",
637                                           gensec_gssapi_state->gss_exchange_count,
638                                           gssapi_error_string(out_mem_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid)));
639                                 return nt_status;
640                         }
641                 } else {
642                         DEBUG(1, ("GSS %s Update(%d) failed: %s\n",
643                                   gensec_security->gensec_role == GENSEC_CLIENT ? "client" : "server",
644                                   gensec_gssapi_state->gss_exchange_count,
645                                   gssapi_error_string(out_mem_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid)));
646                         return nt_status;
647                 }
648                 break;
649         }
650
651         /* These last two stages are only done if we were invoked as SASL */
652         case STAGE_SASL_SSF_NEG:
653         {
654                 switch (gensec_security->gensec_role) {
655                 case GENSEC_CLIENT:
656                 {
657                         uint8_t maxlength_proposed[4]; 
658                         uint8_t maxlength_accepted[4]; 
659                         uint8_t security_supported;
660                         int conf_state;
661                         gss_qop_t qop_state;
662                         input_token.length = in.length;
663                         input_token.value = in.data;
664
665                         /* As a client, we have just send a
666                          * zero-length blob to the server (after the
667                          * normal GSSAPI exchange), and it has replied
668                          * with it's SASL negotiation */
669                         
670                         maj_stat = gss_unwrap(&min_stat, 
671                                               gensec_gssapi_state->gssapi_context, 
672                                               &input_token,
673                                               &output_token, 
674                                               &conf_state,
675                                               &qop_state);
676                         if (GSS_ERROR(maj_stat)) {
677                                 DEBUG(1, ("gensec_gssapi_update: GSS UnWrap of SASL protection negotiation failed: %s\n", 
678                                           gssapi_error_string(out_mem_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid)));
679                                 return NT_STATUS_ACCESS_DENIED;
680                         }
681                         
682                         if (output_token.length < 4) {
683                                 return NT_STATUS_INVALID_PARAMETER;
684                         }
685
686                         memcpy(maxlength_proposed, output_token.value, 4);
687                         gss_release_buffer(&min_stat, &output_token);
688
689                         /* first byte is the proposed security */
690                         security_supported = maxlength_proposed[0];
691                         maxlength_proposed[0] = '\0';
692                         
693                         /* Rest is the proposed max wrap length */
694                         gensec_gssapi_state->max_wrap_buf_size = MIN(RIVAL(maxlength_proposed, 0), 
695                                                                      gensec_gssapi_state->max_wrap_buf_size);
696                         gensec_gssapi_state->sasl_protection = 0;
697                         if (security_supported & NEG_SEAL) {
698                                 if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
699                                         gensec_gssapi_state->sasl_protection |= NEG_SEAL;
700                                 }
701                         }
702                         if (security_supported & NEG_SIGN) {
703                                 if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
704                                         gensec_gssapi_state->sasl_protection |= NEG_SIGN;
705                                 }
706                         }
707                         if (security_supported & NEG_NONE) {
708                                 gensec_gssapi_state->sasl_protection |= NEG_NONE;
709                         }
710                         if (gensec_gssapi_state->sasl_protection == 0) {
711                                 DEBUG(1, ("Remote server does not support unprotected connections\n"));
712                                 return NT_STATUS_ACCESS_DENIED;
713                         }
714
715                         /* Send back the negotiated max length */
716
717                         RSIVAL(maxlength_accepted, 0, gensec_gssapi_state->max_wrap_buf_size);
718
719                         maxlength_accepted[0] = gensec_gssapi_state->sasl_protection;
720                         
721                         input_token.value = maxlength_accepted;
722                         input_token.length = sizeof(maxlength_accepted);
723
724                         maj_stat = gss_wrap(&min_stat, 
725                                             gensec_gssapi_state->gssapi_context, 
726                                             false,
727                                             GSS_C_QOP_DEFAULT,
728                                             &input_token,
729                                             &conf_state,
730                                             &output_token);
731                         if (GSS_ERROR(maj_stat)) {
732                                 DEBUG(1, ("GSS Update(SSF_NEG): GSS Wrap failed: %s\n", 
733                                           gssapi_error_string(out_mem_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid)));
734                                 return NT_STATUS_ACCESS_DENIED;
735                         }
736                         
737                         *out = data_blob_talloc(out_mem_ctx, output_token.value, output_token.length);
738                         gss_release_buffer(&min_stat, &output_token);
739
740                         /* quirk:  This changes the value that gensec_have_feature returns, to be that after SASL negotiation */
741                         gensec_gssapi_state->sasl_state = STAGE_DONE;
742
743                         if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
744                                 DEBUG(3, ("SASL/GSSAPI Connection to server will be cryptographically sealed\n"));
745                         } else if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
746                                 DEBUG(3, ("SASL/GSSAPI Connection to server will be cryptographically signed\n"));
747                         } else {
748                                 DEBUG(3, ("SASL/GSSAPI Connection to server will have no cryptographically protection\n"));
749                         }
750
751                         return NT_STATUS_OK;
752                 }
753                 case GENSEC_SERVER:
754                 {
755                         uint8_t maxlength_proposed[4]; 
756                         uint8_t security_supported = 0x0;
757                         int conf_state;
758
759                         /* As a server, we have just been sent a zero-length blob (note this, but it isn't fatal) */
760                         if (in.length != 0) {
761                                 DEBUG(1, ("SASL/GSSAPI: client sent non-zero length starting SASL negotiation!\n"));
762                         }
763                         
764                         /* Give the client some idea what we will support */
765                           
766                         RSIVAL(maxlength_proposed, 0, gensec_gssapi_state->max_wrap_buf_size);
767                         /* first byte is the proposed security */
768                         maxlength_proposed[0] = '\0';
769                         
770                         gensec_gssapi_state->sasl_protection = 0;
771                         if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
772                                 security_supported |= NEG_SEAL;
773                         } 
774                         if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
775                                 security_supported |= NEG_SIGN;
776                         }
777                         if (security_supported == 0) {
778                                 /* If we don't support anything, this must be 0 */
779                                 RSIVAL(maxlength_proposed, 0, 0x0);
780                         }
781
782                         /* TODO:  We may not wish to support this */
783                         security_supported |= NEG_NONE;
784                         maxlength_proposed[0] = security_supported;
785                         
786                         input_token.value = maxlength_proposed;
787                         input_token.length = sizeof(maxlength_proposed);
788
789                         maj_stat = gss_wrap(&min_stat, 
790                                             gensec_gssapi_state->gssapi_context, 
791                                             false,
792                                             GSS_C_QOP_DEFAULT,
793                                             &input_token,
794                                             &conf_state,
795                                             &output_token);
796                         if (GSS_ERROR(maj_stat)) {
797                                 DEBUG(1, ("GSS Update(SSF_NEG): GSS Wrap failed: %s\n", 
798                                           gssapi_error_string(out_mem_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid)));
799                                 return NT_STATUS_ACCESS_DENIED;
800                         }
801                         
802                         *out = data_blob_talloc(out_mem_ctx, output_token.value, output_token.length);
803                         gss_release_buffer(&min_stat, &output_token);
804
805                         gensec_gssapi_state->sasl_state = STAGE_SASL_SSF_ACCEPT;
806                         return NT_STATUS_MORE_PROCESSING_REQUIRED;
807                 }
808                 default:
809                         return NT_STATUS_INVALID_PARAMETER;
810                         
811                 }
812         }
813         /* This is s server-only stage */
814         case STAGE_SASL_SSF_ACCEPT:
815         {
816                 uint8_t maxlength_accepted[4]; 
817                 uint8_t security_accepted;
818                 int conf_state;
819                 gss_qop_t qop_state;
820                 input_token.length = in.length;
821                 input_token.value = in.data;
822                         
823                 maj_stat = gss_unwrap(&min_stat, 
824                                       gensec_gssapi_state->gssapi_context, 
825                                       &input_token,
826                                       &output_token, 
827                                       &conf_state,
828                                       &qop_state);
829                 if (GSS_ERROR(maj_stat)) {
830                         DEBUG(1, ("gensec_gssapi_update: GSS UnWrap of SASL protection negotiation failed: %s\n", 
831                                   gssapi_error_string(out_mem_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid)));
832                         return NT_STATUS_ACCESS_DENIED;
833                 }
834                         
835                 if (output_token.length < 4) {
836                         return NT_STATUS_INVALID_PARAMETER;
837                 }
838
839                 memcpy(maxlength_accepted, output_token.value, 4);
840                 gss_release_buffer(&min_stat, &output_token);
841                 
842                 /* first byte is the proposed security */
843                 security_accepted = maxlength_accepted[0];
844                 maxlength_accepted[0] = '\0';
845
846                 /* Rest is the proposed max wrap length */
847                 gensec_gssapi_state->max_wrap_buf_size = MIN(RIVAL(maxlength_accepted, 0), 
848                                                              gensec_gssapi_state->max_wrap_buf_size);
849
850                 gensec_gssapi_state->sasl_protection = 0;
851                 if (security_accepted & NEG_SEAL) {
852                         if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
853                                 DEBUG(1, ("Remote client wanted seal, but gensec refused\n"));
854                                 return NT_STATUS_ACCESS_DENIED;
855                         }
856                         gensec_gssapi_state->sasl_protection |= NEG_SEAL;
857                 }
858                 if (security_accepted & NEG_SIGN) {
859                         if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
860                                 DEBUG(1, ("Remote client wanted sign, but gensec refused\n"));
861                                 return NT_STATUS_ACCESS_DENIED;
862                         }
863                         gensec_gssapi_state->sasl_protection |= NEG_SIGN;
864                 }
865                 if (security_accepted & NEG_NONE) {
866                         gensec_gssapi_state->sasl_protection |= NEG_NONE;
867                 }
868
869                 /* quirk:  This changes the value that gensec_have_feature returns, to be that after SASL negotiation */
870                 gensec_gssapi_state->sasl_state = STAGE_DONE;
871                 if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
872                         DEBUG(5, ("SASL/GSSAPI Connection from client will be cryptographically sealed\n"));
873                 } else if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
874                         DEBUG(5, ("SASL/GSSAPI Connection from client will be cryptographically signed\n"));
875                 } else {
876                         DEBUG(5, ("SASL/GSSAPI Connection from client will have no cryptographic protection\n"));
877                 }
878
879                 *out = data_blob(NULL, 0);
880                 return NT_STATUS_OK;    
881         }
882         default:
883                 return NT_STATUS_INVALID_PARAMETER;
884         }
885 }
886
887 static NTSTATUS gensec_gssapi_wrap(struct gensec_security *gensec_security, 
888                                    TALLOC_CTX *mem_ctx, 
889                                    const DATA_BLOB *in, 
890                                    DATA_BLOB *out)
891 {
892         struct gensec_gssapi_state *gensec_gssapi_state
893                 = talloc_get_type(gensec_security->private_data, struct gensec_gssapi_state);
894         OM_uint32 maj_stat, min_stat;
895         gss_buffer_desc input_token, output_token;
896         int conf_state;
897         input_token.length = in->length;
898         input_token.value = in->data;
899
900         maj_stat = gss_wrap(&min_stat, 
901                             gensec_gssapi_state->gssapi_context, 
902                             gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL),
903                             GSS_C_QOP_DEFAULT,
904                             &input_token,
905                             &conf_state,
906                             &output_token);
907         if (GSS_ERROR(maj_stat)) {
908                 DEBUG(1, ("gensec_gssapi_wrap: GSS Wrap failed: %s\n", 
909                           gssapi_error_string(mem_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid)));
910                 return NT_STATUS_ACCESS_DENIED;
911         }
912
913         *out = data_blob_talloc(mem_ctx, output_token.value, output_token.length);
914         gss_release_buffer(&min_stat, &output_token);
915
916         if (gensec_gssapi_state->sasl) {
917                 size_t max_wrapped_size = gensec_gssapi_max_wrapped_size(gensec_security);
918                 if (max_wrapped_size < out->length) {
919                         DEBUG(1, ("gensec_gssapi_wrap: when wrapped, INPUT data (%u) is grew to be larger than SASL negotiated maximum output size (%u > %u)\n",
920                                   (unsigned)in->length, 
921                                   (unsigned)out->length, 
922                                   (unsigned int)max_wrapped_size));
923                         return NT_STATUS_INVALID_PARAMETER;
924                 }
925         }
926         
927         if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)
928             && !conf_state) {
929                 return NT_STATUS_ACCESS_DENIED;
930         }
931         return NT_STATUS_OK;
932 }
933
934 static NTSTATUS gensec_gssapi_unwrap(struct gensec_security *gensec_security, 
935                                      TALLOC_CTX *mem_ctx, 
936                                      const DATA_BLOB *in, 
937                                      DATA_BLOB *out)
938 {
939         struct gensec_gssapi_state *gensec_gssapi_state
940                 = talloc_get_type(gensec_security->private_data, struct gensec_gssapi_state);
941         OM_uint32 maj_stat, min_stat;
942         gss_buffer_desc input_token, output_token;
943         int conf_state;
944         gss_qop_t qop_state;
945         input_token.length = in->length;
946         input_token.value = in->data;
947         
948         if (gensec_gssapi_state->sasl) {
949                 size_t max_wrapped_size = gensec_gssapi_max_wrapped_size(gensec_security);
950                 if (max_wrapped_size < in->length) {
951                         DEBUG(1, ("gensec_gssapi_unwrap: WRAPPED data is larger than SASL negotiated maximum size\n"));
952                         return NT_STATUS_INVALID_PARAMETER;
953                 }
954         }
955         
956         maj_stat = gss_unwrap(&min_stat, 
957                               gensec_gssapi_state->gssapi_context, 
958                               &input_token,
959                               &output_token, 
960                               &conf_state,
961                               &qop_state);
962         if (GSS_ERROR(maj_stat)) {
963                 DEBUG(1, ("gensec_gssapi_unwrap: GSS UnWrap failed: %s\n", 
964                           gssapi_error_string(mem_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid)));
965                 return NT_STATUS_ACCESS_DENIED;
966         }
967
968         *out = data_blob_talloc(mem_ctx, output_token.value, output_token.length);
969         gss_release_buffer(&min_stat, &output_token);
970         
971         if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)
972             && !conf_state) {
973                 return NT_STATUS_ACCESS_DENIED;
974         }
975         return NT_STATUS_OK;
976 }
977
978 /* Find out the maximum input size negotiated on this connection */
979
980 static size_t gensec_gssapi_max_input_size(struct gensec_security *gensec_security) 
981 {
982         struct gensec_gssapi_state *gensec_gssapi_state
983                 = talloc_get_type(gensec_security->private_data, struct gensec_gssapi_state);
984         OM_uint32 maj_stat, min_stat;
985         OM_uint32 max_input_size;
986
987         maj_stat = gss_wrap_size_limit(&min_stat, 
988                                        gensec_gssapi_state->gssapi_context,
989                                        gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL),
990                                        GSS_C_QOP_DEFAULT,
991                                        gensec_gssapi_state->max_wrap_buf_size,
992                                        &max_input_size);
993         if (GSS_ERROR(maj_stat)) {
994                 TALLOC_CTX *mem_ctx = talloc_new(NULL); 
995                 DEBUG(1, ("gensec_gssapi_max_input_size: determinaing signature size with gss_wrap_size_limit failed: %s\n", 
996                           gssapi_error_string(mem_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid)));
997                 talloc_free(mem_ctx);
998                 return 0;
999         }
1000
1001         return max_input_size;
1002 }
1003
1004 /* Find out the maximum output size negotiated on this connection */
1005 static size_t gensec_gssapi_max_wrapped_size(struct gensec_security *gensec_security) 
1006 {
1007         struct gensec_gssapi_state *gensec_gssapi_state = talloc_get_type(gensec_security->private_data, struct gensec_gssapi_state);;
1008         return gensec_gssapi_state->max_wrap_buf_size;
1009 }
1010
1011 static NTSTATUS gensec_gssapi_seal_packet(struct gensec_security *gensec_security, 
1012                                           TALLOC_CTX *mem_ctx, 
1013                                           uint8_t *data, size_t length, 
1014                                           const uint8_t *whole_pdu, size_t pdu_length, 
1015                                           DATA_BLOB *sig)
1016 {
1017         struct gensec_gssapi_state *gensec_gssapi_state
1018                 = talloc_get_type(gensec_security->private_data, struct gensec_gssapi_state);
1019         OM_uint32 maj_stat, min_stat;
1020         gss_buffer_desc input_token, output_token;
1021         int conf_state;
1022         ssize_t sig_length;
1023
1024         input_token.length = length;
1025         input_token.value = data;
1026         
1027         maj_stat = gss_wrap(&min_stat, 
1028                             gensec_gssapi_state->gssapi_context,
1029                             gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL),
1030                             GSS_C_QOP_DEFAULT,
1031                             &input_token,
1032                             &conf_state,
1033                             &output_token);
1034         if (GSS_ERROR(maj_stat)) {
1035                 DEBUG(1, ("gensec_gssapi_seal_packet: GSS Wrap failed: %s\n", 
1036                           gssapi_error_string(mem_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid)));
1037                 return NT_STATUS_ACCESS_DENIED;
1038         }
1039
1040         if (output_token.length < input_token.length) {
1041                 DEBUG(1, ("gensec_gssapi_seal_packet: GSS Wrap length [%ld] *less* than caller length [%ld]\n", 
1042                           (long)output_token.length, (long)length));
1043                 return NT_STATUS_INTERNAL_ERROR;
1044         }
1045         sig_length = output_token.length - input_token.length;
1046
1047         memcpy(data, ((uint8_t *)output_token.value) + sig_length, length);
1048         *sig = data_blob_talloc(mem_ctx, (uint8_t *)output_token.value, sig_length);
1049
1050         dump_data_pw("gensec_gssapi_seal_packet: sig\n", sig->data, sig->length);
1051         dump_data_pw("gensec_gssapi_seal_packet: clear\n", data, length);
1052         dump_data_pw("gensec_gssapi_seal_packet: sealed\n", ((uint8_t *)output_token.value) + sig_length, output_token.length - sig_length);
1053
1054         gss_release_buffer(&min_stat, &output_token);
1055
1056         if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)
1057             && !conf_state) {
1058                 return NT_STATUS_ACCESS_DENIED;
1059         }
1060         return NT_STATUS_OK;
1061 }
1062
1063 static NTSTATUS gensec_gssapi_unseal_packet(struct gensec_security *gensec_security, 
1064                                             uint8_t *data, size_t length, 
1065                                             const uint8_t *whole_pdu, size_t pdu_length,
1066                                             const DATA_BLOB *sig)
1067 {
1068         struct gensec_gssapi_state *gensec_gssapi_state
1069                 = talloc_get_type(gensec_security->private_data, struct gensec_gssapi_state);
1070         OM_uint32 maj_stat, min_stat;
1071         gss_buffer_desc input_token, output_token;
1072         int conf_state;
1073         gss_qop_t qop_state;
1074         DATA_BLOB in;
1075
1076         dump_data_pw("gensec_gssapi_unseal_packet: sig\n", sig->data, sig->length);
1077
1078         in = data_blob_talloc(gensec_security, NULL, sig->length + length);
1079
1080         memcpy(in.data, sig->data, sig->length);
1081         memcpy(in.data + sig->length, data, length);
1082
1083         input_token.length = in.length;
1084         input_token.value = in.data;
1085         
1086         maj_stat = gss_unwrap(&min_stat, 
1087                               gensec_gssapi_state->gssapi_context, 
1088                               &input_token,
1089                               &output_token, 
1090                               &conf_state,
1091                               &qop_state);
1092         talloc_free(in.data);
1093         if (GSS_ERROR(maj_stat)) {
1094                 char *error_string = gssapi_error_string(NULL, maj_stat, min_stat, gensec_gssapi_state->gss_oid);
1095                 DEBUG(1, ("gensec_gssapi_unseal_packet: GSS UnWrap failed: %s\n", 
1096                           error_string));
1097                 talloc_free(error_string);
1098                 return NT_STATUS_ACCESS_DENIED;
1099         }
1100
1101         if (output_token.length != length) {
1102                 return NT_STATUS_INTERNAL_ERROR;
1103         }
1104
1105         memcpy(data, output_token.value, length);
1106
1107         gss_release_buffer(&min_stat, &output_token);
1108         
1109         if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)
1110             && !conf_state) {
1111                 return NT_STATUS_ACCESS_DENIED;
1112         }
1113         return NT_STATUS_OK;
1114 }
1115
1116 static NTSTATUS gensec_gssapi_sign_packet(struct gensec_security *gensec_security, 
1117                                           TALLOC_CTX *mem_ctx, 
1118                                           const uint8_t *data, size_t length, 
1119                                           const uint8_t *whole_pdu, size_t pdu_length, 
1120                                           DATA_BLOB *sig)
1121 {
1122         struct gensec_gssapi_state *gensec_gssapi_state
1123                 = talloc_get_type(gensec_security->private_data, struct gensec_gssapi_state);
1124         OM_uint32 maj_stat, min_stat;
1125         gss_buffer_desc input_token, output_token;
1126
1127         if (gensec_security->want_features & GENSEC_FEATURE_SIGN_PKT_HEADER) {
1128                 input_token.length = pdu_length;
1129                 input_token.value = discard_const_p(uint8_t *, whole_pdu);
1130         } else {
1131                 input_token.length = length;
1132                 input_token.value = discard_const_p(uint8_t *, data);
1133         }
1134
1135         maj_stat = gss_get_mic(&min_stat,
1136                             gensec_gssapi_state->gssapi_context,
1137                             GSS_C_QOP_DEFAULT,
1138                             &input_token,
1139                             &output_token);
1140         if (GSS_ERROR(maj_stat)) {
1141                 DEBUG(1, ("GSS GetMic failed: %s\n",
1142                           gssapi_error_string(mem_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid)));
1143                 return NT_STATUS_ACCESS_DENIED;
1144         }
1145
1146         *sig = data_blob_talloc(mem_ctx, (uint8_t *)output_token.value, output_token.length);
1147
1148         dump_data_pw("gensec_gssapi_seal_packet: sig\n", sig->data, sig->length);
1149
1150         gss_release_buffer(&min_stat, &output_token);
1151
1152         return NT_STATUS_OK;
1153 }
1154
1155 static NTSTATUS gensec_gssapi_check_packet(struct gensec_security *gensec_security, 
1156                                            const uint8_t *data, size_t length, 
1157                                            const uint8_t *whole_pdu, size_t pdu_length, 
1158                                            const DATA_BLOB *sig)
1159 {
1160         struct gensec_gssapi_state *gensec_gssapi_state
1161                 = talloc_get_type(gensec_security->private_data, struct gensec_gssapi_state);
1162         OM_uint32 maj_stat, min_stat;
1163         gss_buffer_desc input_token;
1164         gss_buffer_desc input_message;
1165         gss_qop_t qop_state;
1166
1167         dump_data_pw("gensec_gssapi_seal_packet: sig\n", sig->data, sig->length);
1168
1169         if (gensec_security->want_features & GENSEC_FEATURE_SIGN_PKT_HEADER) {
1170                 input_message.length = pdu_length;
1171                 input_message.value = discard_const(whole_pdu);
1172         } else {
1173                 input_message.length = length;
1174                 input_message.value = discard_const(data);
1175         }
1176
1177         input_token.length = sig->length;
1178         input_token.value = sig->data;
1179
1180         maj_stat = gss_verify_mic(&min_stat,
1181                               gensec_gssapi_state->gssapi_context, 
1182                               &input_message,
1183                               &input_token,
1184                               &qop_state);
1185         if (GSS_ERROR(maj_stat)) {
1186                 char *error_string = gssapi_error_string(NULL, maj_stat, min_stat, gensec_gssapi_state->gss_oid);
1187                 DEBUG(1, ("GSS VerifyMic failed: %s\n", error_string));
1188                 talloc_free(error_string);
1189
1190                 return NT_STATUS_ACCESS_DENIED;
1191         }
1192
1193         return NT_STATUS_OK;
1194 }
1195
1196 /* Try to figure out what features we actually got on the connection */
1197 static bool gensec_gssapi_have_feature(struct gensec_security *gensec_security, 
1198                                        uint32_t feature) 
1199 {
1200         struct gensec_gssapi_state *gensec_gssapi_state
1201                 = talloc_get_type(gensec_security->private_data, struct gensec_gssapi_state);
1202         if (feature & GENSEC_FEATURE_SIGN) {
1203                 /* If we are going GSSAPI SASL, then we honour the second negotiation */
1204                 if (gensec_gssapi_state->sasl 
1205                     && gensec_gssapi_state->sasl_state == STAGE_DONE) {
1206                         return ((gensec_gssapi_state->sasl_protection & NEG_SIGN) 
1207                                 && (gensec_gssapi_state->got_flags & GSS_C_INTEG_FLAG));
1208                 }
1209                 return gensec_gssapi_state->got_flags & GSS_C_INTEG_FLAG;
1210         }
1211         if (feature & GENSEC_FEATURE_SEAL) {
1212                 /* If we are going GSSAPI SASL, then we honour the second negotiation */
1213                 if (gensec_gssapi_state->sasl 
1214                     && gensec_gssapi_state->sasl_state == STAGE_DONE) {
1215                         return ((gensec_gssapi_state->sasl_protection & NEG_SEAL) 
1216                                  && (gensec_gssapi_state->got_flags & GSS_C_CONF_FLAG));
1217                 }
1218                 return gensec_gssapi_state->got_flags & GSS_C_CONF_FLAG;
1219         }
1220         if (feature & GENSEC_FEATURE_SESSION_KEY) {
1221                 /* Only for GSSAPI/Krb5 */
1222                 if (gss_oid_equal(gensec_gssapi_state->gss_oid, gss_mech_krb5)) {
1223                         return true;
1224                 }
1225         }
1226         if (feature & GENSEC_FEATURE_DCE_STYLE) {
1227                 return gensec_gssapi_state->got_flags & GSS_C_DCE_STYLE;
1228         }
1229         if (feature & GENSEC_FEATURE_NEW_SPNEGO) {
1230                 NTSTATUS status;
1231
1232                 if (!(gensec_gssapi_state->got_flags & GSS_C_INTEG_FLAG)) {
1233                         return false;
1234                 }
1235
1236                 if (gensec_setting_bool(gensec_security->settings, "gensec_gssapi", "force_new_spnego", false)) {
1237                         return true;
1238                 }
1239                 if (gensec_setting_bool(gensec_security->settings, "gensec_gssapi", "disable_new_spnego", false)) {
1240                         return false;
1241                 }
1242
1243                 status = gensec_gssapi_init_lucid(gensec_gssapi_state);
1244                 if (!NT_STATUS_IS_OK(status)) {
1245                         return false;
1246                 }
1247
1248                 if (gensec_gssapi_state->lucid->protocol == 1) {
1249                         return true;
1250                 }
1251
1252                 return false;
1253         }
1254         /* We can always do async (rather than strict request/reply) packets.  */
1255         if (feature & GENSEC_FEATURE_ASYNC_REPLIES) {
1256                 return true;
1257         }
1258         return false;
1259 }
1260
1261 /*
1262  * Extract the 'sesssion key' needed by SMB signing and ncacn_np 
1263  * (for encrypting some passwords).
1264  * 
1265  * This breaks all the abstractions, but what do you expect...
1266  */
1267 static NTSTATUS gensec_gssapi_session_key(struct gensec_security *gensec_security, 
1268                                           TALLOC_CTX *mem_ctx,
1269                                           DATA_BLOB *session_key) 
1270 {
1271         struct gensec_gssapi_state *gensec_gssapi_state
1272                 = talloc_get_type(gensec_security->private_data, struct gensec_gssapi_state);
1273         OM_uint32 maj_stat, min_stat;
1274         krb5_keyblock *subkey;
1275
1276         if (gensec_gssapi_state->sasl_state != STAGE_DONE) {
1277                 return NT_STATUS_NO_USER_SESSION_KEY;
1278         }
1279
1280         maj_stat = gsskrb5_get_subkey(&min_stat,
1281                                       gensec_gssapi_state->gssapi_context,
1282                                       &subkey);
1283         if (maj_stat != 0) {
1284                 DEBUG(1, ("NO session key for this mech\n"));
1285                 return NT_STATUS_NO_USER_SESSION_KEY;
1286         }
1287         
1288         DEBUG(10, ("Got KRB5 session key of length %d%s\n",
1289                    (int)KRB5_KEY_LENGTH(subkey),
1290                    (gensec_gssapi_state->sasl_state == STAGE_DONE)?" (done)":""));
1291         *session_key = data_blob_talloc(mem_ctx,
1292                                         KRB5_KEY_DATA(subkey), KRB5_KEY_LENGTH(subkey));
1293         krb5_free_keyblock(gensec_gssapi_state->smb_krb5_context->krb5_context, subkey);
1294         dump_data_pw("KRB5 Session Key:\n", session_key->data, session_key->length);
1295
1296         return NT_STATUS_OK;
1297 }
1298
1299 /* Get some basic (and authorization) information about the user on
1300  * this session.  This uses either the PAC (if present) or a local
1301  * database lookup */
1302 static NTSTATUS gensec_gssapi_session_info(struct gensec_security *gensec_security,
1303                                            TALLOC_CTX *mem_ctx_out,
1304                                            struct auth_session_info **_session_info) 
1305 {
1306         NTSTATUS nt_status;
1307         TALLOC_CTX *mem_ctx;
1308         struct gensec_gssapi_state *gensec_gssapi_state
1309                 = talloc_get_type(gensec_security->private_data, struct gensec_gssapi_state);
1310         struct auth_user_info_dc *user_info_dc = NULL;
1311         struct auth_session_info *session_info = NULL;
1312         OM_uint32 maj_stat, min_stat;
1313         DATA_BLOB pac_blob;
1314         struct PAC_SIGNATURE_DATA *pac_srv_sig = NULL;
1315         struct PAC_SIGNATURE_DATA *pac_kdc_sig = NULL;
1316         
1317         if ((gensec_gssapi_state->gss_oid->length != gss_mech_krb5->length)
1318             || (memcmp(gensec_gssapi_state->gss_oid->elements, gss_mech_krb5->elements, 
1319                        gensec_gssapi_state->gss_oid->length) != 0)) {
1320                 DEBUG(1, ("NO session info available for this mech\n"));
1321                 return NT_STATUS_INVALID_PARAMETER;
1322         }
1323                 
1324         mem_ctx = talloc_named(mem_ctx_out, 0, "gensec_gssapi_session_info context");
1325         NT_STATUS_HAVE_NO_MEMORY(mem_ctx);
1326
1327         nt_status = gssapi_obtain_pac_blob(mem_ctx,  gensec_gssapi_state->gssapi_context,
1328                                            gensec_gssapi_state->client_name,
1329                                            &pac_blob);
1330         
1331         /* IF we have the PAC - otherwise we need to get this
1332          * data from elsewere - local ldb, or (TODO) lookup of some
1333          * kind... 
1334          */
1335         if (NT_STATUS_IS_OK(nt_status)) {
1336                 pac_srv_sig = talloc(mem_ctx, struct PAC_SIGNATURE_DATA);
1337                 if (!pac_srv_sig) {
1338                         talloc_free(mem_ctx);
1339                         return NT_STATUS_NO_MEMORY;
1340                 }
1341                 pac_kdc_sig = talloc(mem_ctx, struct PAC_SIGNATURE_DATA);
1342                 if (!pac_kdc_sig) {
1343                         talloc_free(mem_ctx);
1344                         return NT_STATUS_NO_MEMORY;
1345                 }
1346
1347                 nt_status = kerberos_pac_blob_to_user_info_dc(mem_ctx,
1348                                                               pac_blob,
1349                                                               gensec_gssapi_state->smb_krb5_context->krb5_context,
1350                                                               &user_info_dc,
1351                                                               pac_srv_sig,
1352                                                               pac_kdc_sig);
1353                 if (!NT_STATUS_IS_OK(nt_status)) {
1354                         talloc_free(mem_ctx);
1355                         return nt_status;
1356                 }
1357         } else {
1358                 gss_buffer_desc name_token;
1359                 char *principal_string;
1360
1361                 maj_stat = gss_display_name (&min_stat,
1362                                              gensec_gssapi_state->client_name,
1363                                              &name_token,
1364                                              NULL);
1365                 if (GSS_ERROR(maj_stat)) {
1366                         DEBUG(1, ("GSS display_name failed: %s\n", 
1367                                   gssapi_error_string(mem_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid)));
1368                         talloc_free(mem_ctx);
1369                         return NT_STATUS_FOOBAR;
1370                 }
1371                 
1372                 principal_string = talloc_strndup(mem_ctx, 
1373                                                   (const char *)name_token.value, 
1374                                                   name_token.length);
1375                 
1376                 gss_release_buffer(&min_stat, &name_token);
1377                 
1378                 if (!principal_string) {
1379                         talloc_free(mem_ctx);
1380                         return NT_STATUS_NO_MEMORY;
1381                 }
1382
1383                 if (gensec_security->auth_context && 
1384                     !gensec_setting_bool(gensec_security->settings, "gensec", "require_pac", false)) {
1385                         DEBUG(1, ("Unable to find PAC, resorting to local user lookup: %s\n",
1386                                   gssapi_error_string(mem_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid)));
1387                         nt_status = gensec_security->auth_context->get_user_info_dc_principal(mem_ctx,
1388                                                                                              gensec_security->auth_context, 
1389                                                                                              principal_string,
1390                                                                                              NULL,
1391                                                                                              &user_info_dc);
1392                         
1393                         if (!NT_STATUS_IS_OK(nt_status)) {
1394                                 talloc_free(mem_ctx);
1395                                 return nt_status;
1396                         }
1397                 } else {
1398                         DEBUG(1, ("Unable to find PAC in ticket from %s, failing to allow access: %s\n",
1399                                   principal_string,
1400                                   gssapi_error_string(mem_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid)));
1401                         return NT_STATUS_ACCESS_DENIED;
1402                 }
1403         }
1404
1405         /* references the user_info_dc into the session_info */
1406         nt_status = gensec_generate_session_info(mem_ctx, gensec_security,
1407                                                  user_info_dc, &session_info);
1408         if (!NT_STATUS_IS_OK(nt_status)) {
1409                 talloc_free(mem_ctx);
1410                 return nt_status;
1411         }
1412
1413         nt_status = gensec_gssapi_session_key(gensec_security, session_info, &session_info->session_key);
1414         if (!NT_STATUS_IS_OK(nt_status)) {
1415                 talloc_free(mem_ctx);
1416                 return nt_status;
1417         }
1418
1419         /* Allow torture tests to check the PAC signatures */
1420         if (session_info->torture) {
1421                 session_info->torture->pac_srv_sig = talloc_steal(session_info->torture, pac_srv_sig);
1422                 session_info->torture->pac_kdc_sig = talloc_steal(session_info->torture, pac_kdc_sig);
1423         }
1424
1425         if (!(gensec_gssapi_state->got_flags & GSS_C_DELEG_FLAG)) {
1426                 DEBUG(10, ("gensec_gssapi: NO delegated credentials supplied by client\n"));
1427         } else {
1428                 krb5_error_code ret;
1429                 const char *error_string;
1430
1431                 DEBUG(10, ("gensec_gssapi: delegated credentials supplied by client\n"));
1432                 session_info->credentials = cli_credentials_init(session_info);
1433                 if (!session_info->credentials) {
1434                         talloc_free(mem_ctx);
1435                         return NT_STATUS_NO_MEMORY;
1436                 }
1437
1438                 cli_credentials_set_conf(session_info->credentials, gensec_security->settings->lp_ctx);
1439                 /* Just so we don't segfault trying to get at a username */
1440                 cli_credentials_set_anonymous(session_info->credentials);
1441                 
1442                 ret = cli_credentials_set_client_gss_creds(session_info->credentials, 
1443                                                            gensec_security->settings->lp_ctx,
1444                                                            gensec_gssapi_state->delegated_cred_handle,
1445                                                            CRED_SPECIFIED, &error_string);
1446                 if (ret) {
1447                         talloc_free(mem_ctx);
1448                         DEBUG(2,("Failed to get gss creds: %s\n", error_string));
1449                         return NT_STATUS_NO_MEMORY;
1450                 }
1451                 
1452                 /* This credential handle isn't useful for password authentication, so ensure nobody tries to do that */
1453                 cli_credentials_set_kerberos_state(session_info->credentials, CRED_MUST_USE_KERBEROS);
1454
1455                 /* It has been taken from this place... */
1456                 gensec_gssapi_state->delegated_cred_handle = GSS_C_NO_CREDENTIAL;
1457         }
1458         *_session_info = talloc_steal(mem_ctx_out, session_info);
1459         talloc_free(mem_ctx);
1460
1461         return NT_STATUS_OK;
1462 }
1463
1464 static size_t gensec_gssapi_sig_size(struct gensec_security *gensec_security, size_t data_size)
1465 {
1466         struct gensec_gssapi_state *gensec_gssapi_state
1467                 = talloc_get_type(gensec_security->private_data, struct gensec_gssapi_state);
1468         NTSTATUS status;
1469
1470         if (gensec_gssapi_state->sig_size) {
1471                 return gensec_gssapi_state->sig_size;
1472         }
1473
1474         if (gensec_gssapi_state->got_flags & GSS_C_CONF_FLAG) {
1475                 gensec_gssapi_state->sig_size = 45;
1476         } else {
1477                 gensec_gssapi_state->sig_size = 37;
1478         }
1479
1480         status = gensec_gssapi_init_lucid(gensec_gssapi_state);
1481         if (!NT_STATUS_IS_OK(status)) {
1482                 return gensec_gssapi_state->sig_size;
1483         }
1484
1485         if (gensec_gssapi_state->lucid->protocol == 1) {
1486                 if (gensec_gssapi_state->got_flags & GSS_C_CONF_FLAG) {
1487                         /*
1488                          * TODO: windows uses 76 here, but we don't know
1489                          *       gss_wrap works with aes keys yet
1490                          */
1491                         gensec_gssapi_state->sig_size = 76;
1492                 } else {
1493                         gensec_gssapi_state->sig_size = 28;
1494                 }
1495         } else if (gensec_gssapi_state->lucid->protocol == 0) {
1496                 switch (gensec_gssapi_state->lucid->rfc1964_kd.ctx_key.type) {
1497                 case KEYTYPE_DES:
1498                 case KEYTYPE_ARCFOUR:
1499                 case KEYTYPE_ARCFOUR_56:
1500                         if (gensec_gssapi_state->got_flags & GSS_C_CONF_FLAG) {
1501                                 gensec_gssapi_state->sig_size = 45;
1502                         } else {
1503                                 gensec_gssapi_state->sig_size = 37;
1504                         }
1505                         break;
1506                 case KEYTYPE_DES3:
1507                         if (gensec_gssapi_state->got_flags & GSS_C_CONF_FLAG) {
1508                                 gensec_gssapi_state->sig_size = 57;
1509                         } else {
1510                                 gensec_gssapi_state->sig_size = 49;
1511                         }
1512                         break;
1513                 }
1514         }
1515
1516         return gensec_gssapi_state->sig_size;
1517 }
1518
1519 static const char *gensec_gssapi_krb5_oids[] = { 
1520         GENSEC_OID_KERBEROS5_OLD,
1521         GENSEC_OID_KERBEROS5,
1522         NULL 
1523 };
1524
1525 static const char *gensec_gssapi_spnego_oids[] = { 
1526         GENSEC_OID_SPNEGO,
1527         NULL 
1528 };
1529
1530 /* As a server, this could in theory accept any GSSAPI mech */
1531 static const struct gensec_security_ops gensec_gssapi_spnego_security_ops = {
1532         .name           = "gssapi_spnego",
1533         .sasl_name      = "GSS-SPNEGO",
1534         .auth_type      = DCERPC_AUTH_TYPE_SPNEGO,
1535         .oid            = gensec_gssapi_spnego_oids,
1536         .client_start   = gensec_gssapi_client_start,
1537         .server_start   = gensec_gssapi_server_start,
1538         .magic          = gensec_gssapi_magic,
1539         .update         = gensec_gssapi_update,
1540         .session_key    = gensec_gssapi_session_key,
1541         .session_info   = gensec_gssapi_session_info,
1542         .sign_packet    = gensec_gssapi_sign_packet,
1543         .check_packet   = gensec_gssapi_check_packet,
1544         .seal_packet    = gensec_gssapi_seal_packet,
1545         .unseal_packet  = gensec_gssapi_unseal_packet,
1546         .wrap           = gensec_gssapi_wrap,
1547         .unwrap         = gensec_gssapi_unwrap,
1548         .have_feature   = gensec_gssapi_have_feature,
1549         .enabled        = false,
1550         .kerberos       = true,
1551         .priority       = GENSEC_GSSAPI
1552 };
1553
1554 /* As a server, this could in theory accept any GSSAPI mech */
1555 static const struct gensec_security_ops gensec_gssapi_krb5_security_ops = {
1556         .name           = "gssapi_krb5",
1557         .auth_type      = DCERPC_AUTH_TYPE_KRB5,
1558         .oid            = gensec_gssapi_krb5_oids,
1559         .client_start   = gensec_gssapi_client_start,
1560         .server_start   = gensec_gssapi_server_start,
1561         .magic          = gensec_gssapi_magic,
1562         .update         = gensec_gssapi_update,
1563         .session_key    = gensec_gssapi_session_key,
1564         .session_info   = gensec_gssapi_session_info,
1565         .sig_size       = gensec_gssapi_sig_size,
1566         .sign_packet    = gensec_gssapi_sign_packet,
1567         .check_packet   = gensec_gssapi_check_packet,
1568         .seal_packet    = gensec_gssapi_seal_packet,
1569         .unseal_packet  = gensec_gssapi_unseal_packet,
1570         .wrap           = gensec_gssapi_wrap,
1571         .unwrap         = gensec_gssapi_unwrap,
1572         .have_feature   = gensec_gssapi_have_feature,
1573         .enabled        = true,
1574         .kerberos       = true,
1575         .priority       = GENSEC_GSSAPI
1576 };
1577
1578 /* As a server, this could in theory accept any GSSAPI mech */
1579 static const struct gensec_security_ops gensec_gssapi_sasl_krb5_security_ops = {
1580         .name             = "gssapi_krb5_sasl",
1581         .sasl_name        = "GSSAPI",
1582         .client_start     = gensec_gssapi_sasl_client_start,
1583         .server_start     = gensec_gssapi_sasl_server_start,
1584         .update           = gensec_gssapi_update,
1585         .session_key      = gensec_gssapi_session_key,
1586         .session_info     = gensec_gssapi_session_info,
1587         .max_input_size   = gensec_gssapi_max_input_size,
1588         .max_wrapped_size = gensec_gssapi_max_wrapped_size,
1589         .wrap             = gensec_gssapi_wrap,
1590         .unwrap           = gensec_gssapi_unwrap,
1591         .have_feature     = gensec_gssapi_have_feature,
1592         .enabled          = true,
1593         .kerberos         = true,
1594         .priority         = GENSEC_GSSAPI
1595 };
1596
1597 _PUBLIC_ NTSTATUS gensec_gssapi_init(void)
1598 {
1599         NTSTATUS ret;
1600
1601         ret = gensec_register(&gensec_gssapi_spnego_security_ops);
1602         if (!NT_STATUS_IS_OK(ret)) {
1603                 DEBUG(0,("Failed to register '%s' gensec backend!\n",
1604                         gensec_gssapi_spnego_security_ops.name));
1605                 return ret;
1606         }
1607
1608         ret = gensec_register(&gensec_gssapi_krb5_security_ops);
1609         if (!NT_STATUS_IS_OK(ret)) {
1610                 DEBUG(0,("Failed to register '%s' gensec backend!\n",
1611                         gensec_gssapi_krb5_security_ops.name));
1612                 return ret;
1613         }
1614
1615         ret = gensec_register(&gensec_gssapi_sasl_krb5_security_ops);
1616         if (!NT_STATUS_IS_OK(ret)) {
1617                 DEBUG(0,("Failed to register '%s' gensec backend!\n",
1618                         gensec_gssapi_sasl_krb5_security_ops.name));
1619                 return ret;
1620         }
1621
1622         return ret;
1623 }