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