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