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