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