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