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