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