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