6ecd29bf340ce09ba8ecc6a8ac764f4963a3d9ef
[nivanova/samba-autobuild/.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                                             TALLOC_CTX *mem_ctx, 
1042                                             uint8_t *data, size_t length, 
1043                                             const uint8_t *whole_pdu, size_t pdu_length,
1044                                             const DATA_BLOB *sig)
1045 {
1046         struct gensec_gssapi_state *gensec_gssapi_state
1047                 = talloc_get_type(gensec_security->private_data, struct gensec_gssapi_state);
1048         OM_uint32 maj_stat, min_stat;
1049         gss_buffer_desc input_token, output_token;
1050         int conf_state;
1051         gss_qop_t qop_state;
1052         DATA_BLOB in;
1053
1054         dump_data_pw("gensec_gssapi_unseal_packet: sig\n", sig->data, sig->length);
1055
1056         in = data_blob_talloc(mem_ctx, NULL, sig->length + length);
1057
1058         memcpy(in.data, sig->data, sig->length);
1059         memcpy(in.data + sig->length, data, length);
1060
1061         input_token.length = in.length;
1062         input_token.value = in.data;
1063         
1064         maj_stat = gss_unwrap(&min_stat, 
1065                               gensec_gssapi_state->gssapi_context, 
1066                               &input_token,
1067                               &output_token, 
1068                               &conf_state,
1069                               &qop_state);
1070         if (GSS_ERROR(maj_stat)) {
1071                 DEBUG(1, ("gensec_gssapi_unseal_packet: GSS UnWrap failed: %s\n", 
1072                           gssapi_error_string(mem_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid)));
1073                 return NT_STATUS_ACCESS_DENIED;
1074         }
1075
1076         if (output_token.length != length) {
1077                 return NT_STATUS_INTERNAL_ERROR;
1078         }
1079
1080         memcpy(data, output_token.value, length);
1081
1082         gss_release_buffer(&min_stat, &output_token);
1083         
1084         if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)
1085             && !conf_state) {
1086                 return NT_STATUS_ACCESS_DENIED;
1087         }
1088         return NT_STATUS_OK;
1089 }
1090
1091 static NTSTATUS gensec_gssapi_sign_packet(struct gensec_security *gensec_security, 
1092                                           TALLOC_CTX *mem_ctx, 
1093                                           const uint8_t *data, size_t length, 
1094                                           const uint8_t *whole_pdu, size_t pdu_length, 
1095                                           DATA_BLOB *sig)
1096 {
1097         struct gensec_gssapi_state *gensec_gssapi_state
1098                 = talloc_get_type(gensec_security->private_data, struct gensec_gssapi_state);
1099         OM_uint32 maj_stat, min_stat;
1100         gss_buffer_desc input_token, output_token;
1101
1102         if (gensec_security->want_features & GENSEC_FEATURE_SIGN_PKT_HEADER) {
1103                 input_token.length = pdu_length;
1104                 input_token.value = discard_const_p(uint8_t *, whole_pdu);
1105         } else {
1106                 input_token.length = length;
1107                 input_token.value = discard_const_p(uint8_t *, data);
1108         }
1109
1110         maj_stat = gss_get_mic(&min_stat,
1111                             gensec_gssapi_state->gssapi_context,
1112                             GSS_C_QOP_DEFAULT,
1113                             &input_token,
1114                             &output_token);
1115         if (GSS_ERROR(maj_stat)) {
1116                 DEBUG(1, ("GSS GetMic failed: %s\n",
1117                           gssapi_error_string(mem_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid)));
1118                 return NT_STATUS_ACCESS_DENIED;
1119         }
1120
1121         *sig = data_blob_talloc(mem_ctx, (uint8_t *)output_token.value, output_token.length);
1122
1123         dump_data_pw("gensec_gssapi_seal_packet: sig\n", sig->data, sig->length);
1124
1125         gss_release_buffer(&min_stat, &output_token);
1126
1127         return NT_STATUS_OK;
1128 }
1129
1130 static NTSTATUS gensec_gssapi_check_packet(struct gensec_security *gensec_security, 
1131                                            TALLOC_CTX *mem_ctx, 
1132                                            const uint8_t *data, size_t length, 
1133                                            const uint8_t *whole_pdu, size_t pdu_length, 
1134                                            const DATA_BLOB *sig)
1135 {
1136         struct gensec_gssapi_state *gensec_gssapi_state
1137                 = talloc_get_type(gensec_security->private_data, struct gensec_gssapi_state);
1138         OM_uint32 maj_stat, min_stat;
1139         gss_buffer_desc input_token;
1140         gss_buffer_desc input_message;
1141         gss_qop_t qop_state;
1142
1143         dump_data_pw("gensec_gssapi_seal_packet: sig\n", sig->data, sig->length);
1144
1145         if (gensec_security->want_features & GENSEC_FEATURE_SIGN_PKT_HEADER) {
1146                 input_message.length = pdu_length;
1147                 input_message.value = discard_const(whole_pdu);
1148         } else {
1149                 input_message.length = length;
1150                 input_message.value = discard_const(data);
1151         }
1152
1153         input_token.length = sig->length;
1154         input_token.value = sig->data;
1155
1156         maj_stat = gss_verify_mic(&min_stat,
1157                               gensec_gssapi_state->gssapi_context, 
1158                               &input_message,
1159                               &input_token,
1160                               &qop_state);
1161         if (GSS_ERROR(maj_stat)) {
1162                 DEBUG(1, ("GSS VerifyMic failed: %s\n",
1163                           gssapi_error_string(mem_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid)));
1164                 return NT_STATUS_ACCESS_DENIED;
1165         }
1166
1167         return NT_STATUS_OK;
1168 }
1169
1170 /* Try to figure out what features we actually got on the connection */
1171 static bool gensec_gssapi_have_feature(struct gensec_security *gensec_security, 
1172                                        uint32_t feature) 
1173 {
1174         struct gensec_gssapi_state *gensec_gssapi_state
1175                 = talloc_get_type(gensec_security->private_data, struct gensec_gssapi_state);
1176         if (feature & GENSEC_FEATURE_SIGN) {
1177                 /* If we are going GSSAPI SASL, then we honour the second negotiation */
1178                 if (gensec_gssapi_state->sasl 
1179                     && gensec_gssapi_state->sasl_state == STAGE_DONE) {
1180                         return ((gensec_gssapi_state->sasl_protection & NEG_SIGN) 
1181                                 && (gensec_gssapi_state->got_flags & GSS_C_INTEG_FLAG));
1182                 }
1183                 return gensec_gssapi_state->got_flags & GSS_C_INTEG_FLAG;
1184         }
1185         if (feature & GENSEC_FEATURE_SEAL) {
1186                 /* If we are going GSSAPI SASL, then we honour the second negotiation */
1187                 if (gensec_gssapi_state->sasl 
1188                     && gensec_gssapi_state->sasl_state == STAGE_DONE) {
1189                         return ((gensec_gssapi_state->sasl_protection & NEG_SEAL) 
1190                                  && (gensec_gssapi_state->got_flags & GSS_C_CONF_FLAG));
1191                 }
1192                 return gensec_gssapi_state->got_flags & GSS_C_CONF_FLAG;
1193         }
1194         if (feature & GENSEC_FEATURE_SESSION_KEY) {
1195                 /* Only for GSSAPI/Krb5 */
1196                 if (gss_oid_equal(gensec_gssapi_state->gss_oid, gss_mech_krb5)) {
1197                         return true;
1198                 }
1199         }
1200         if (feature & GENSEC_FEATURE_DCE_STYLE) {
1201                 return gensec_gssapi_state->got_flags & GSS_C_DCE_STYLE;
1202         }
1203         if (feature & GENSEC_FEATURE_NEW_SPNEGO) {
1204                 NTSTATUS status;
1205
1206                 if (!(gensec_gssapi_state->got_flags & GSS_C_INTEG_FLAG)) {
1207                         return false;
1208                 }
1209
1210                 if (gensec_setting_bool(gensec_security->settings, "gensec_gssapi", "force_new_spnego", false)) {
1211                         return true;
1212                 }
1213                 if (gensec_setting_bool(gensec_security->settings, "gensec_gssapi", "disable_new_spnego", false)) {
1214                         return false;
1215                 }
1216
1217                 status = gensec_gssapi_init_lucid(gensec_gssapi_state);
1218                 if (!NT_STATUS_IS_OK(status)) {
1219                         return false;
1220                 }
1221
1222                 if (gensec_gssapi_state->lucid->protocol == 1) {
1223                         return true;
1224                 }
1225
1226                 return false;
1227         }
1228         /* We can always do async (rather than strict request/reply) packets.  */
1229         if (feature & GENSEC_FEATURE_ASYNC_REPLIES) {
1230                 return true;
1231         }
1232         return false;
1233 }
1234
1235 /*
1236  * Extract the 'sesssion key' needed by SMB signing and ncacn_np 
1237  * (for encrypting some passwords).
1238  * 
1239  * This breaks all the abstractions, but what do you expect...
1240  */
1241 static NTSTATUS gensec_gssapi_session_key(struct gensec_security *gensec_security, 
1242                                           DATA_BLOB *session_key) 
1243 {
1244         struct gensec_gssapi_state *gensec_gssapi_state
1245                 = talloc_get_type(gensec_security->private_data, struct gensec_gssapi_state);
1246         OM_uint32 maj_stat, min_stat;
1247         krb5_keyblock *subkey;
1248
1249         if (gensec_gssapi_state->sasl_state != STAGE_DONE) {
1250                 return NT_STATUS_NO_USER_SESSION_KEY;
1251         }
1252
1253         if (gensec_gssapi_state->session_key.data) {
1254                 *session_key = gensec_gssapi_state->session_key;
1255                 return NT_STATUS_OK;
1256         }
1257
1258         maj_stat = gsskrb5_get_subkey(&min_stat,
1259                                       gensec_gssapi_state->gssapi_context,
1260                                       &subkey);
1261         if (maj_stat != 0) {
1262                 DEBUG(1, ("NO session key for this mech\n"));
1263                 return NT_STATUS_NO_USER_SESSION_KEY;
1264         }
1265         
1266         DEBUG(10, ("Got KRB5 session key of length %d%s\n",
1267                    (int)KRB5_KEY_LENGTH(subkey),
1268                    (gensec_gssapi_state->sasl_state == STAGE_DONE)?" (done)":""));
1269         *session_key = data_blob_talloc(gensec_gssapi_state,
1270                                         KRB5_KEY_DATA(subkey), KRB5_KEY_LENGTH(subkey));
1271         krb5_free_keyblock(gensec_gssapi_state->smb_krb5_context->krb5_context, subkey);
1272         gensec_gssapi_state->session_key = *session_key;
1273         dump_data_pw("KRB5 Session Key:\n", session_key->data, session_key->length);
1274
1275         return NT_STATUS_OK;
1276 }
1277
1278 /* Get some basic (and authorization) information about the user on
1279  * this session.  This uses either the PAC (if present) or a local
1280  * database lookup */
1281 static NTSTATUS gensec_gssapi_session_info(struct gensec_security *gensec_security,
1282                                            struct auth_session_info **_session_info) 
1283 {
1284         NTSTATUS nt_status;
1285         TALLOC_CTX *mem_ctx;
1286         struct gensec_gssapi_state *gensec_gssapi_state
1287                 = talloc_get_type(gensec_security->private_data, struct gensec_gssapi_state);
1288         struct auth_user_info_dc *user_info_dc = NULL;
1289         struct auth_session_info *session_info = NULL;
1290         OM_uint32 maj_stat, min_stat;
1291         DATA_BLOB pac_blob;
1292         struct PAC_SIGNATURE_DATA *pac_srv_sig = NULL;
1293         struct PAC_SIGNATURE_DATA *pac_kdc_sig = NULL;
1294         
1295         if ((gensec_gssapi_state->gss_oid->length != gss_mech_krb5->length)
1296             || (memcmp(gensec_gssapi_state->gss_oid->elements, gss_mech_krb5->elements, 
1297                        gensec_gssapi_state->gss_oid->length) != 0)) {
1298                 DEBUG(1, ("NO session info available for this mech\n"));
1299                 return NT_STATUS_INVALID_PARAMETER;
1300         }
1301                 
1302         mem_ctx = talloc_named(gensec_gssapi_state, 0, "gensec_gssapi_session_info context"); 
1303         NT_STATUS_HAVE_NO_MEMORY(mem_ctx);
1304
1305         nt_status = gssapi_obtain_pac_blob(mem_ctx,  gensec_gssapi_state->gssapi_context,
1306                                            gensec_gssapi_state->client_name,
1307                                            &pac_blob);
1308         
1309         /* IF we have the PAC - otherwise we need to get this
1310          * data from elsewere - local ldb, or (TODO) lookup of some
1311          * kind... 
1312          */
1313         if (NT_STATUS_IS_OK(nt_status)) {
1314                 pac_srv_sig = talloc(mem_ctx, struct PAC_SIGNATURE_DATA);
1315                 if (!pac_srv_sig) {
1316                         talloc_free(mem_ctx);
1317                         return NT_STATUS_NO_MEMORY;
1318                 }
1319                 pac_kdc_sig = talloc(mem_ctx, struct PAC_SIGNATURE_DATA);
1320                 if (!pac_kdc_sig) {
1321                         talloc_free(mem_ctx);
1322                         return NT_STATUS_NO_MEMORY;
1323                 }
1324
1325                 nt_status = kerberos_pac_blob_to_user_info_dc(mem_ctx,
1326                                                               pac_blob,
1327                                                               gensec_gssapi_state->smb_krb5_context->krb5_context,
1328                                                               &user_info_dc,
1329                                                               pac_srv_sig,
1330                                                               pac_kdc_sig);
1331                 if (!NT_STATUS_IS_OK(nt_status)) {
1332                         talloc_free(mem_ctx);
1333                         return nt_status;
1334                 }
1335         } else {
1336                 gss_buffer_desc name_token;
1337                 char *principal_string;
1338
1339                 maj_stat = gss_display_name (&min_stat,
1340                                              gensec_gssapi_state->client_name,
1341                                              &name_token,
1342                                              NULL);
1343                 if (GSS_ERROR(maj_stat)) {
1344                         DEBUG(1, ("GSS display_name failed: %s\n", 
1345                                   gssapi_error_string(mem_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid)));
1346                         talloc_free(mem_ctx);
1347                         return NT_STATUS_FOOBAR;
1348                 }
1349                 
1350                 principal_string = talloc_strndup(mem_ctx, 
1351                                                   (const char *)name_token.value, 
1352                                                   name_token.length);
1353                 
1354                 gss_release_buffer(&min_stat, &name_token);
1355                 
1356                 if (!principal_string) {
1357                         talloc_free(mem_ctx);
1358                         return NT_STATUS_NO_MEMORY;
1359                 }
1360
1361                 if (gensec_security->auth_context && 
1362                     !gensec_setting_bool(gensec_security->settings, "gensec", "require_pac", false)) {
1363                         DEBUG(1, ("Unable to find PAC, resorting to local user lookup: %s\n",
1364                                   gssapi_error_string(mem_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid)));
1365                         nt_status = gensec_security->auth_context->get_user_info_dc_principal(mem_ctx,
1366                                                                                              gensec_security->auth_context, 
1367                                                                                              principal_string,
1368                                                                                              NULL,
1369                                                                                              &user_info_dc);
1370                         
1371                         if (!NT_STATUS_IS_OK(nt_status)) {
1372                                 talloc_free(mem_ctx);
1373                                 return nt_status;
1374                         }
1375                 } else {
1376                         DEBUG(1, ("Unable to find PAC in ticket from %s, failing to allow access: %s\n",
1377                                   principal_string,
1378                                   gssapi_error_string(mem_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid)));
1379                         return NT_STATUS_ACCESS_DENIED;
1380                 }
1381         }
1382
1383         /* references the user_info_dc into the session_info */
1384         nt_status = gensec_generate_session_info(mem_ctx, gensec_security,
1385                                                  user_info_dc, &session_info);
1386         if (!NT_STATUS_IS_OK(nt_status)) {
1387                 talloc_free(mem_ctx);
1388                 return nt_status;
1389         }
1390
1391         nt_status = gensec_gssapi_session_key(gensec_security, &session_info->session_key);
1392         if (!NT_STATUS_IS_OK(nt_status)) {
1393                 talloc_free(mem_ctx);
1394                 return nt_status;
1395         }
1396
1397         /* Allow torture tests to check the PAC signatures */
1398         if (session_info->torture) {
1399                 session_info->torture->pac_srv_sig = talloc_steal(session_info->torture, pac_srv_sig);
1400                 session_info->torture->pac_kdc_sig = talloc_steal(session_info->torture, pac_kdc_sig);
1401         }
1402
1403         if (!(gensec_gssapi_state->got_flags & GSS_C_DELEG_FLAG)) {
1404                 DEBUG(10, ("gensec_gssapi: NO delegated credentials supplied by client\n"));
1405         } else {
1406                 krb5_error_code ret;
1407                 const char *error_string;
1408
1409                 DEBUG(10, ("gensec_gssapi: delegated credentials supplied by client\n"));
1410                 session_info->credentials = cli_credentials_init(session_info);
1411                 if (!session_info->credentials) {
1412                         talloc_free(mem_ctx);
1413                         return NT_STATUS_NO_MEMORY;
1414                 }
1415
1416                 cli_credentials_set_conf(session_info->credentials, gensec_security->settings->lp_ctx);
1417                 /* Just so we don't segfault trying to get at a username */
1418                 cli_credentials_set_anonymous(session_info->credentials);
1419                 
1420                 ret = cli_credentials_set_client_gss_creds(session_info->credentials, 
1421                                                            gensec_security->settings->lp_ctx,
1422                                                            gensec_gssapi_state->delegated_cred_handle,
1423                                                            CRED_SPECIFIED, &error_string);
1424                 if (ret) {
1425                         talloc_free(mem_ctx);
1426                         DEBUG(2,("Failed to get gss creds: %s\n", error_string));
1427                         return NT_STATUS_NO_MEMORY;
1428                 }
1429                 
1430                 /* This credential handle isn't useful for password authentication, so ensure nobody tries to do that */
1431                 cli_credentials_set_kerberos_state(session_info->credentials, CRED_MUST_USE_KERBEROS);
1432
1433                 /* It has been taken from this place... */
1434                 gensec_gssapi_state->delegated_cred_handle = GSS_C_NO_CREDENTIAL;
1435         }
1436         talloc_steal(gensec_gssapi_state, session_info);
1437         talloc_free(mem_ctx);
1438         *_session_info = session_info;
1439
1440         return NT_STATUS_OK;
1441 }
1442
1443 static size_t gensec_gssapi_sig_size(struct gensec_security *gensec_security, size_t data_size)
1444 {
1445         struct gensec_gssapi_state *gensec_gssapi_state
1446                 = talloc_get_type(gensec_security->private_data, struct gensec_gssapi_state);
1447         NTSTATUS status;
1448
1449         if (gensec_gssapi_state->sig_size) {
1450                 return gensec_gssapi_state->sig_size;
1451         }
1452
1453         if (gensec_gssapi_state->got_flags & GSS_C_CONF_FLAG) {
1454                 gensec_gssapi_state->sig_size = 45;
1455         } else {
1456                 gensec_gssapi_state->sig_size = 37;
1457         }
1458
1459         status = gensec_gssapi_init_lucid(gensec_gssapi_state);
1460         if (!NT_STATUS_IS_OK(status)) {
1461                 return gensec_gssapi_state->sig_size;
1462         }
1463
1464         if (gensec_gssapi_state->lucid->protocol == 1) {
1465                 if (gensec_gssapi_state->got_flags & GSS_C_CONF_FLAG) {
1466                         /*
1467                          * TODO: windows uses 76 here, but we don't know
1468                          *       gss_wrap works with aes keys yet
1469                          */
1470                         gensec_gssapi_state->sig_size = 76;
1471                 } else {
1472                         gensec_gssapi_state->sig_size = 28;
1473                 }
1474         } else if (gensec_gssapi_state->lucid->protocol == 0) {
1475                 switch (gensec_gssapi_state->lucid->rfc1964_kd.ctx_key.type) {
1476                 case KEYTYPE_DES:
1477                 case KEYTYPE_ARCFOUR:
1478                 case KEYTYPE_ARCFOUR_56:
1479                         if (gensec_gssapi_state->got_flags & GSS_C_CONF_FLAG) {
1480                                 gensec_gssapi_state->sig_size = 45;
1481                         } else {
1482                                 gensec_gssapi_state->sig_size = 37;
1483                         }
1484                         break;
1485                 case KEYTYPE_DES3:
1486                         if (gensec_gssapi_state->got_flags & GSS_C_CONF_FLAG) {
1487                                 gensec_gssapi_state->sig_size = 57;
1488                         } else {
1489                                 gensec_gssapi_state->sig_size = 49;
1490                         }
1491                         break;
1492                 }
1493         }
1494
1495         return gensec_gssapi_state->sig_size;
1496 }
1497
1498 static const char *gensec_gssapi_krb5_oids[] = { 
1499         GENSEC_OID_KERBEROS5_OLD,
1500         GENSEC_OID_KERBEROS5,
1501         NULL 
1502 };
1503
1504 static const char *gensec_gssapi_spnego_oids[] = { 
1505         GENSEC_OID_SPNEGO,
1506         NULL 
1507 };
1508
1509 /* As a server, this could in theory accept any GSSAPI mech */
1510 static const struct gensec_security_ops gensec_gssapi_spnego_security_ops = {
1511         .name           = "gssapi_spnego",
1512         .sasl_name      = "GSS-SPNEGO",
1513         .auth_type      = DCERPC_AUTH_TYPE_SPNEGO,
1514         .oid            = gensec_gssapi_spnego_oids,
1515         .client_start   = gensec_gssapi_client_start,
1516         .server_start   = gensec_gssapi_server_start,
1517         .magic          = gensec_gssapi_magic,
1518         .update         = gensec_gssapi_update,
1519         .session_key    = gensec_gssapi_session_key,
1520         .session_info   = gensec_gssapi_session_info,
1521         .sign_packet    = gensec_gssapi_sign_packet,
1522         .check_packet   = gensec_gssapi_check_packet,
1523         .seal_packet    = gensec_gssapi_seal_packet,
1524         .unseal_packet  = gensec_gssapi_unseal_packet,
1525         .wrap           = gensec_gssapi_wrap,
1526         .unwrap         = gensec_gssapi_unwrap,
1527         .have_feature   = gensec_gssapi_have_feature,
1528         .enabled        = false,
1529         .kerberos       = true,
1530         .priority       = GENSEC_GSSAPI
1531 };
1532
1533 /* As a server, this could in theory accept any GSSAPI mech */
1534 static const struct gensec_security_ops gensec_gssapi_krb5_security_ops = {
1535         .name           = "gssapi_krb5",
1536         .auth_type      = DCERPC_AUTH_TYPE_KRB5,
1537         .oid            = gensec_gssapi_krb5_oids,
1538         .client_start   = gensec_gssapi_client_start,
1539         .server_start   = gensec_gssapi_server_start,
1540         .magic          = gensec_gssapi_magic,
1541         .update         = gensec_gssapi_update,
1542         .session_key    = gensec_gssapi_session_key,
1543         .session_info   = gensec_gssapi_session_info,
1544         .sig_size       = gensec_gssapi_sig_size,
1545         .sign_packet    = gensec_gssapi_sign_packet,
1546         .check_packet   = gensec_gssapi_check_packet,
1547         .seal_packet    = gensec_gssapi_seal_packet,
1548         .unseal_packet  = gensec_gssapi_unseal_packet,
1549         .wrap           = gensec_gssapi_wrap,
1550         .unwrap         = gensec_gssapi_unwrap,
1551         .have_feature   = gensec_gssapi_have_feature,
1552         .enabled        = true,
1553         .kerberos       = true,
1554         .priority       = GENSEC_GSSAPI
1555 };
1556
1557 /* As a server, this could in theory accept any GSSAPI mech */
1558 static const struct gensec_security_ops gensec_gssapi_sasl_krb5_security_ops = {
1559         .name             = "gssapi_krb5_sasl",
1560         .sasl_name        = "GSSAPI",
1561         .client_start     = gensec_gssapi_sasl_client_start,
1562         .server_start     = gensec_gssapi_sasl_server_start,
1563         .update           = gensec_gssapi_update,
1564         .session_key      = gensec_gssapi_session_key,
1565         .session_info     = gensec_gssapi_session_info,
1566         .max_input_size   = gensec_gssapi_max_input_size,
1567         .max_wrapped_size = gensec_gssapi_max_wrapped_size,
1568         .wrap             = gensec_gssapi_wrap,
1569         .unwrap           = gensec_gssapi_unwrap,
1570         .have_feature     = gensec_gssapi_have_feature,
1571         .enabled          = true,
1572         .kerberos         = true,
1573         .priority         = GENSEC_GSSAPI
1574 };
1575
1576 _PUBLIC_ NTSTATUS gensec_gssapi_init(void)
1577 {
1578         NTSTATUS ret;
1579
1580         ret = gensec_register(&gensec_gssapi_spnego_security_ops);
1581         if (!NT_STATUS_IS_OK(ret)) {
1582                 DEBUG(0,("Failed to register '%s' gensec backend!\n",
1583                         gensec_gssapi_spnego_security_ops.name));
1584                 return ret;
1585         }
1586
1587         ret = gensec_register(&gensec_gssapi_krb5_security_ops);
1588         if (!NT_STATUS_IS_OK(ret)) {
1589                 DEBUG(0,("Failed to register '%s' gensec backend!\n",
1590                         gensec_gssapi_krb5_security_ops.name));
1591                 return ret;
1592         }
1593
1594         ret = gensec_register(&gensec_gssapi_sasl_krb5_security_ops);
1595         if (!NT_STATUS_IS_OK(ret)) {
1596                 DEBUG(0,("Failed to register '%s' gensec backend!\n",
1597                         gensec_gssapi_sasl_krb5_security_ops.name));
1598                 return ret;
1599         }
1600
1601         return ret;
1602 }