5df4de3287d2d21df2d879ef20c0c11bc8be9bcd
[metze/samba/wip.git] / source3 / librpc / crypto / gse.c
1 /*
2  *  GSSAPI Security Extensions
3  *  RPC Pipe client and server routines
4  *  Copyright (C) Simo Sorce 2010.
5  *  Copyright (C) Andrew Bartlett 2004-2011.
6  *  Copyright (C) Stefan Metzmacher <metze@samba.org> 2004-2005
7  *
8  *  This program is free software; you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License as published by
10  *  the Free Software Foundation; either version 3 of the License, or
11  *  (at your option) any later version.
12  *
13  *  This program is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *  GNU General Public License for more details.
17  *
18  *  You should have received a copy of the GNU General Public License
19  *  along with this program; if not, see <http://www.gnu.org/licenses/>.
20  */
21
22 /* We support only GSSAPI/KRB5 here */
23
24 #include "includes.h"
25 #include <tevent.h>
26 #include "lib/util/tevent_ntstatus.h"
27 #include "gse.h"
28 #include "libads/kerberos_proto.h"
29 #include "auth/common_auth.h"
30 #include "auth/gensec/gensec.h"
31 #include "auth/gensec/gensec_internal.h"
32 #include "auth/credentials/credentials.h"
33 #include "../librpc/gen_ndr/dcerpc.h"
34
35 #if defined(HAVE_KRB5)
36
37 #include "auth/kerberos/pac_utils.h"
38 #include "auth/kerberos/gssapi_helper.h"
39 #include "gse_krb5.h"
40
41 static char *gse_errstr(TALLOC_CTX *mem_ctx, OM_uint32 maj, OM_uint32 min);
42 static size_t gensec_gse_sig_size(struct gensec_security *gensec_security,
43                                   size_t data_size);
44
45 struct gse_context {
46         gss_ctx_id_t gssapi_context;
47         gss_name_t server_name;
48         gss_name_t client_name;
49         OM_uint32 gss_want_flags, gss_got_flags;
50         size_t max_wrap_buf_size;
51         size_t sig_size;
52
53         gss_cred_id_t delegated_cred_handle;
54
55         NTTIME expire_time;
56
57         /* gensec_gse only */
58         krb5_context k5ctx;
59         krb5_ccache ccache;
60         krb5_keytab keytab;
61
62         gss_OID_desc gss_mech;
63         gss_cred_id_t creds;
64
65         gss_OID ret_mech;
66 };
67
68 /* free non talloc dependent contexts */
69 static int gse_context_destructor(void *ptr)
70 {
71         struct gse_context *gse_ctx;
72         OM_uint32 gss_min;
73
74         gse_ctx = talloc_get_type_abort(ptr, struct gse_context);
75         if (gse_ctx->k5ctx) {
76                 if (gse_ctx->ccache) {
77                         krb5_cc_close(gse_ctx->k5ctx, gse_ctx->ccache);
78                         gse_ctx->ccache = NULL;
79                 }
80                 if (gse_ctx->keytab) {
81                         krb5_kt_close(gse_ctx->k5ctx, gse_ctx->keytab);
82                         gse_ctx->keytab = NULL;
83                 }
84                 krb5_free_context(gse_ctx->k5ctx);
85                 gse_ctx->k5ctx = NULL;
86         }
87         if (gse_ctx->gssapi_context != GSS_C_NO_CONTEXT) {
88                 (void)gss_delete_sec_context(&gss_min,
89                                                  &gse_ctx->gssapi_context,
90                                                  GSS_C_NO_BUFFER);
91         }
92         if (gse_ctx->server_name) {
93                 (void)gss_release_name(&gss_min,
94                                            &gse_ctx->server_name);
95         }
96         if (gse_ctx->client_name) {
97                 (void)gss_release_name(&gss_min,
98                                            &gse_ctx->client_name);
99         }
100         if (gse_ctx->creds) {
101                 (void)gss_release_cred(&gss_min,
102                                            &gse_ctx->creds);
103         }
104         if (gse_ctx->delegated_cred_handle) {
105                 (void)gss_release_cred(&gss_min,
106                                            &gse_ctx->delegated_cred_handle);
107         }
108
109         /* MIT and Heimdal differ as to if you can call
110          * gss_release_oid() on this OID, generated by
111          * gss_{accept,init}_sec_context().  However, as long as the
112          * oid is gss_mech_krb5 (which it always is at the moment),
113          * then this is a moot point, as both declare this particular
114          * OID static, and so no memory is lost.  This assert is in
115          * place to ensure that the programmer who wishes to extend
116          * this code to EAP or other GSS mechanisms determines an
117          * implementation-dependent way of releasing any dynamically
118          * allocated OID */
119         SMB_ASSERT(smb_gss_oid_equal(&gse_ctx->gss_mech, GSS_C_NO_OID) ||
120                    smb_gss_oid_equal(&gse_ctx->gss_mech, gss_mech_krb5));
121
122         return 0;
123 }
124
125 static NTSTATUS gse_setup_server_principal(TALLOC_CTX *mem_ctx,
126                                            const char *target_principal,
127                                            const char *service,
128                                            const char *hostname,
129                                            const char *realm,
130                                            char **pserver_principal,
131                                            gss_name_t *pserver_name)
132 {
133         char *server_principal = NULL;
134         gss_buffer_desc name_token;
135         gss_OID name_type;
136         OM_uint32 maj_stat, min_stat = 0;
137
138         if (target_principal != NULL) {
139                 server_principal = talloc_strdup(mem_ctx, target_principal);
140                 name_type = GSS_C_NULL_OID;
141         } else {
142                 server_principal = talloc_asprintf(mem_ctx,
143                                                    "%s/%s@%s",
144                                                    service,
145                                                    hostname,
146                                                    realm);
147                 name_type = GSS_C_NT_USER_NAME;
148         }
149         if (server_principal == NULL) {
150                 return NT_STATUS_NO_MEMORY;
151         }
152
153         name_token.value = (uint8_t *)server_principal;
154         name_token.length = strlen(server_principal);
155
156         maj_stat = gss_import_name(&min_stat,
157                                    &name_token,
158                                    name_type,
159                                    pserver_name);
160         if (maj_stat) {
161                 DBG_WARNING("GSS Import name of %s failed: %s\n",
162                             server_principal,
163                             gse_errstr(mem_ctx, maj_stat, min_stat));
164                 TALLOC_FREE(server_principal);
165                 return NT_STATUS_INVALID_PARAMETER;
166         }
167
168         *pserver_principal = server_principal;
169
170         return NT_STATUS_OK;
171 }
172
173 static NTSTATUS gse_context_init(TALLOC_CTX *mem_ctx,
174                                  bool do_sign, bool do_seal,
175                                  const char *ccache_name,
176                                  uint32_t add_gss_c_flags,
177                                  struct gse_context **_gse_ctx)
178 {
179         struct gse_context *gse_ctx;
180         krb5_error_code k5ret;
181         NTSTATUS status;
182
183         gse_ctx = talloc_zero(mem_ctx, struct gse_context);
184         if (!gse_ctx) {
185                 return NT_STATUS_NO_MEMORY;
186         }
187         talloc_set_destructor((TALLOC_CTX *)gse_ctx, gse_context_destructor);
188
189         gse_ctx->expire_time = GENSEC_EXPIRE_TIME_INFINITY;
190         gse_ctx->max_wrap_buf_size = UINT16_MAX;
191
192         memcpy(&gse_ctx->gss_mech, gss_mech_krb5, sizeof(gss_OID_desc));
193
194         gse_ctx->gss_want_flags = GSS_C_MUTUAL_FLAG |
195                                 GSS_C_DELEG_POLICY_FLAG |
196                                 GSS_C_REPLAY_FLAG |
197                                 GSS_C_SEQUENCE_FLAG;
198         if (do_sign) {
199                 gse_ctx->gss_want_flags |= GSS_C_INTEG_FLAG;
200         }
201         if (do_seal) {
202                 gse_ctx->gss_want_flags |= GSS_C_INTEG_FLAG;
203                 gse_ctx->gss_want_flags |= GSS_C_CONF_FLAG;
204         }
205
206         gse_ctx->gss_want_flags |= add_gss_c_flags;
207
208         /* Initialize Kerberos Context */
209         k5ret = smb_krb5_init_context_common(&gse_ctx->k5ctx);
210         if (k5ret) {
211                 DBG_ERR("kerberos init context failed (%s)\n",
212                         error_message(k5ret));
213                 status = NT_STATUS_INTERNAL_ERROR;
214                 goto err_out;
215         }
216
217         if (!ccache_name) {
218                 ccache_name = krb5_cc_default_name(gse_ctx->k5ctx);
219         }
220         k5ret = krb5_cc_resolve(gse_ctx->k5ctx, ccache_name,
221                                 &gse_ctx->ccache);
222         if (k5ret) {
223                 DEBUG(1, ("Failed to resolve credential cache '%s'! (%s)\n",
224                           ccache_name, error_message(k5ret)));
225                 status = NT_STATUS_INTERNAL_ERROR;
226                 goto err_out;
227         }
228
229         /* TODO: Should we enforce a enc_types list ?
230         ret = krb5_set_default_tgs_ktypes(gse_ctx->k5ctx, enc_types);
231         */
232
233         *_gse_ctx = gse_ctx;
234         return NT_STATUS_OK;
235
236 err_out:
237         if (gse_ctx->k5ctx) {
238                 krb5_free_context(gse_ctx->k5ctx);
239         }
240
241         TALLOC_FREE(gse_ctx);
242         return status;
243 }
244
245 static NTSTATUS gse_init_client(TALLOC_CTX *mem_ctx,
246                                 bool do_sign, bool do_seal,
247                                 const char *ccache_name,
248                                 const char *server,
249                                 const char *service,
250                                 const char *realm,
251                                 const char *username,
252                                 const char *password,
253                                 uint32_t add_gss_c_flags,
254                                 struct gse_context **_gse_ctx)
255 {
256         struct gse_context *gse_ctx;
257         OM_uint32 gss_maj, gss_min;
258 #ifdef HAVE_GSS_KRB5_CRED_NO_CI_FLAGS_X
259         gss_buffer_desc empty_buffer = GSS_C_EMPTY_BUFFER;
260         gss_OID oid = discard_const(GSS_KRB5_CRED_NO_CI_FLAGS_X);
261 #endif
262         NTSTATUS status;
263
264         if (!server || !service) {
265                 return NT_STATUS_INVALID_PARAMETER;
266         }
267
268         status = gse_context_init(mem_ctx, do_sign, do_seal,
269                                   ccache_name, add_gss_c_flags,
270                                   &gse_ctx);
271         if (!NT_STATUS_IS_OK(status)) {
272                 return NT_STATUS_NO_MEMORY;
273         }
274
275         /* TODO: get krb5 ticket using username/password, if no valid
276          * one already available in ccache */
277
278         gss_maj = smb_gss_krb5_import_cred(&gss_min,
279                                            gse_ctx->k5ctx,
280                                            gse_ctx->ccache,
281                                            NULL, /* keytab_principal */
282                                            NULL, /* keytab */
283                                            &gse_ctx->creds);
284         if (gss_maj) {
285                 char *ccache = NULL;
286                 int kret;
287
288                 kret = krb5_cc_get_full_name(gse_ctx->k5ctx,
289                                              gse_ctx->ccache,
290                                              &ccache);
291                 if (kret != 0) {
292                         ccache = NULL;
293                 }
294
295                 DEBUG(5, ("smb_gss_krb5_import_cred ccache[%s] failed with [%s] -"
296                           "the caller may retry after a kinit.\n",
297                           ccache, gse_errstr(gse_ctx, gss_maj, gss_min)));
298                 SAFE_FREE(ccache);
299                 status = NT_STATUS_INTERNAL_ERROR;
300                 goto err_out;
301         }
302
303 #ifdef HAVE_GSS_KRB5_CRED_NO_CI_FLAGS_X
304         /*
305          * Don't force GSS_C_CONF_FLAG and GSS_C_INTEG_FLAG.
306          *
307          * This allows us to disable SIGN and SEAL for
308          * AUTH_LEVEL_CONNECT and AUTH_LEVEL_INTEGRITY.
309          *
310          * https://groups.yahoo.com/neo/groups/cat-ietf/conversations/topics/575
311          * http://krbdev.mit.edu/rt/Ticket/Display.html?id=6938
312          */
313         gss_maj = gss_set_cred_option(&gss_min, &gse_ctx->creds,
314                                       oid,
315                                       &empty_buffer);
316         if (gss_maj) {
317                 DEBUG(0, ("gss_set_cred_option(GSS_KRB5_CRED_NO_CI_FLAGS_X), "
318                           "failed with [%s]\n",
319                           gse_errstr(gse_ctx, gss_maj, gss_min)));
320                 status = NT_STATUS_INTERNAL_ERROR;
321                 goto err_out;
322         }
323 #endif
324
325         *_gse_ctx = gse_ctx;
326         return NT_STATUS_OK;
327
328 err_out:
329         TALLOC_FREE(gse_ctx);
330         return status;
331 }
332
333 static NTSTATUS gse_get_client_auth_token(TALLOC_CTX *mem_ctx,
334                                           struct gensec_security *gensec_security,
335                                           const DATA_BLOB *token_in,
336                                           DATA_BLOB *token_out)
337 {
338         struct gse_context *gse_ctx =
339                 talloc_get_type_abort(gensec_security->private_data,
340                                       struct gse_context);
341         OM_uint32 gss_maj = 0;
342         OM_uint32 gss_min;
343         gss_buffer_desc in_data;
344         gss_buffer_desc out_data;
345         DATA_BLOB blob = data_blob_null;
346         NTSTATUS status;
347         OM_uint32 time_rec = 0;
348         struct timeval tv;
349         struct cli_credentials *cli_creds = gensec_get_credentials(gensec_security);
350         const char *target_principal = gensec_get_target_principal(gensec_security);
351         const char *hostname = gensec_get_target_hostname(gensec_security);
352         const char *service = gensec_get_target_service(gensec_security);
353         const char *client_realm = cli_credentials_get_realm(cli_creds);
354         char *server_principal = NULL;
355         char *server_realm = NULL;
356         bool fallback = false;
357         OM_uint32 time_req = 0;
358
359         time_req = gensec_setting_int(gensec_security->settings,
360                                       "gensec_gssapi",
361                                       "requested_life_time",
362                                       time_req);
363
364         in_data.value = token_in->data;
365         in_data.length = token_in->length;
366
367         /*
368          * With credentials for administrator@FOREST1.EXAMPLE.COM this patch
369          * changes the target_principal for the ldap service of host
370          * dc2.forest2.example.com from
371          *
372          *   ldap/dc2.forest2.example.com@FOREST1.EXAMPLE.COM
373          *
374          * to
375          *
376          *   ldap/dc2.forest2.example.com@FOREST2.EXAMPLE.COM
377          *
378          * Typically ldap/dc2.forest2.example.com@FOREST1.EXAMPLE.COM should be
379          * used in order to allow the KDC of FOREST1.EXAMPLE.COM to generate a
380          * referral ticket for krbtgt/FOREST2.EXAMPLE.COM@FOREST1.EXAMPLE.COM.
381          *
382          * The problem is that KDCs only return such referral tickets if
383          * there's a forest trust between FOREST1.EXAMPLE.COM and
384          * FOREST2.EXAMPLE.COM. If there's only an external domain trust
385          * between FOREST1.EXAMPLE.COM and FOREST2.EXAMPLE.COM the KDC of
386          * FOREST1.EXAMPLE.COM will respond with S_PRINCIPAL_UNKNOWN when being
387          * asked for ldap/dc2.forest2.example.com@FOREST1.EXAMPLE.COM.
388          *
389          * In the case of an external trust the client can still ask explicitly
390          * for krbtgt/FOREST2.EXAMPLE.COM@FOREST1.EXAMPLE.COM and the KDC of
391          * FOREST1.EXAMPLE.COM will generate it.
392          *
393          * From there the client can use the
394          * krbtgt/FOREST2.EXAMPLE.COM@FOREST1.EXAMPLE.COM ticket and ask a KDC
395          * of FOREST2.EXAMPLE.COM for a service ticket for
396          * ldap/dc2.forest2.example.com@FOREST2.EXAMPLE.COM.
397          *
398          * With Heimdal we'll get the fallback on S_PRINCIPAL_UNKNOWN behavior
399          * when we pass ldap/dc2.forest2.example.com@FOREST2.EXAMPLE.COM as
400          * target principal. As _krb5_get_cred_kdc_any() first calls
401          * get_cred_kdc_referral() (which always starts with the client realm)
402          * and falls back to get_cred_kdc_capath() (which starts with the given
403          * realm).
404          *
405          * MIT krb5 only tries the given realm of the target principal, if we
406          * want to autodetect support for transitive forest trusts, would have
407          * to do the fallback ourself.
408          */
409 #ifndef SAMBA4_USES_HEIMDAL
410         if (gse_ctx->server_name == NULL) {
411                 OM_uint32 gss_min2 = 0;
412
413                 status = gse_setup_server_principal(mem_ctx,
414                                                     target_principal,
415                                                     service,
416                                                     hostname,
417                                                     client_realm,
418                                                     &server_principal,
419                                                     &gse_ctx->server_name);
420                 if (!NT_STATUS_IS_OK(status)) {
421                         return status;
422                 }
423
424                 gss_maj = gss_init_sec_context(&gss_min,
425                                                gse_ctx->creds,
426                                                &gse_ctx->gssapi_context,
427                                                gse_ctx->server_name,
428                                                &gse_ctx->gss_mech,
429                                                gse_ctx->gss_want_flags,
430                                                time_req,
431                                                GSS_C_NO_CHANNEL_BINDINGS,
432                                                &in_data,
433                                                NULL,
434                                                &out_data,
435                                                &gse_ctx->gss_got_flags,
436                                                &time_rec);
437                 if (gss_maj != GSS_S_FAILURE) {
438                         goto init_sec_context_done;
439                 }
440                 if (gss_min != (OM_uint32)KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN) {
441                         goto init_sec_context_done;
442                 }
443                 if (target_principal != NULL) {
444                         goto init_sec_context_done;
445                 }
446
447                 fallback = true;
448                 TALLOC_FREE(server_principal);
449                 gss_release_name(&gss_min2, &gse_ctx->server_name);
450         }
451 #endif /* !SAMBA4_USES_HEIMDAL */
452
453         if (gse_ctx->server_name == NULL) {
454                 server_realm = smb_krb5_get_realm_from_hostname(mem_ctx,
455                                                                 hostname,
456                                                                 client_realm);
457                 if (server_realm == NULL) {
458                         return NT_STATUS_NO_MEMORY;
459                 }
460
461                 if (fallback &&
462                     strequal(client_realm, server_realm)) {
463                         goto init_sec_context_done;
464                 }
465
466                 status = gse_setup_server_principal(mem_ctx,
467                                                     target_principal,
468                                                     service,
469                                                     hostname,
470                                                     server_realm,
471                                                     &server_principal,
472                                                     &gse_ctx->server_name);
473                 TALLOC_FREE(server_realm);
474                 if (!NT_STATUS_IS_OK(status)) {
475                         return status;
476                 }
477
478                 TALLOC_FREE(server_principal);
479         }
480
481         gss_maj = gss_init_sec_context(&gss_min,
482                                         gse_ctx->creds,
483                                         &gse_ctx->gssapi_context,
484                                         gse_ctx->server_name,
485                                         &gse_ctx->gss_mech,
486                                         gse_ctx->gss_want_flags,
487                                         time_req, GSS_C_NO_CHANNEL_BINDINGS,
488                                         &in_data, NULL, &out_data,
489                                         &gse_ctx->gss_got_flags, &time_rec);
490         goto init_sec_context_done;
491         /* JUMP! */
492 init_sec_context_done:
493
494         switch (gss_maj) {
495         case GSS_S_COMPLETE:
496                 /* we are done with it */
497                 tv = timeval_current_ofs(time_rec, 0);
498                 gse_ctx->expire_time = timeval_to_nttime(&tv);
499
500                 status = NT_STATUS_OK;
501                 break;
502         case GSS_S_CONTINUE_NEEDED:
503                 /* we will need a third leg */
504                 status = NT_STATUS_MORE_PROCESSING_REQUIRED;
505                 break;
506         case GSS_S_CONTEXT_EXPIRED:
507                 /* Make SPNEGO ignore us, we can't go any further here */
508                 DBG_NOTICE("Context expired\n");
509                 status = NT_STATUS_INVALID_PARAMETER;
510                 goto done;
511         case GSS_S_FAILURE:
512                 switch (gss_min) {
513                 case (OM_uint32)KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN:
514                         DBG_NOTICE("Server principal not found\n");
515                         /* Make SPNEGO ignore us, we can't go any further here */
516                         status = NT_STATUS_INVALID_PARAMETER;
517                         goto done;
518                 case (OM_uint32)KRB5KRB_AP_ERR_TKT_EXPIRED:
519                         DBG_NOTICE("Ticket expired\n");
520                         /* Make SPNEGO ignore us, we can't go any further here */
521                         status = NT_STATUS_INVALID_PARAMETER;
522                         goto done;
523                 case (OM_uint32)KRB5KRB_AP_ERR_TKT_NYV:
524                         DBG_NOTICE("Clockskew\n");
525                         /* Make SPNEGO ignore us, we can't go any further here */
526                         status = NT_STATUS_TIME_DIFFERENCE_AT_DC;
527                         goto done;
528                 case (OM_uint32)KRB5_KDC_UNREACH:
529                         DBG_NOTICE("KDC unreachable\n");
530                         /* Make SPNEGO ignore us, we can't go any further here */
531                         status = NT_STATUS_NO_LOGON_SERVERS;
532                         goto done;
533                 case (OM_uint32)KRB5KRB_AP_ERR_MSG_TYPE:
534                         /* Garbage input, possibly from the auto-mech detection */
535                         status = NT_STATUS_INVALID_PARAMETER;
536                         goto done;
537                 case (OM_uint32)KRB5KDC_ERR_ETYPE_NOSUPP:
538                         status = NT_STATUS_KDC_UNKNOWN_ETYPE;
539                         goto done;
540                 default:
541                         DBG_ERR("gss_init_sec_context failed with [%s](%u)\n",
542                                 gse_errstr(talloc_tos(), gss_maj, gss_min),
543                                 gss_min);
544                         status = NT_STATUS_LOGON_FAILURE;
545                         goto done;
546                 }
547                 break;
548         default:
549                 DBG_ERR("gss_init_sec_context failed with [%s]\n",
550                         gse_errstr(talloc_tos(), gss_maj, gss_min));
551                 status = NT_STATUS_INTERNAL_ERROR;
552                 goto done;
553         }
554
555         /* we may be told to return nothing */
556         if (out_data.length) {
557                 blob = data_blob_talloc(mem_ctx, out_data.value, out_data.length);
558                 if (!blob.data) {
559                         status = NT_STATUS_NO_MEMORY;
560                 }
561
562                 gss_release_buffer(&gss_min, &out_data);
563         }
564
565 done:
566         *token_out = blob;
567         return status;
568 }
569
570 static NTSTATUS gse_init_server(TALLOC_CTX *mem_ctx,
571                                 bool do_sign, bool do_seal,
572                                 uint32_t add_gss_c_flags,
573                                 struct gse_context **_gse_ctx)
574 {
575         struct gse_context *gse_ctx;
576         OM_uint32 gss_maj, gss_min;
577         krb5_error_code ret;
578         NTSTATUS status;
579         bool disable_transited_check =
580                 lp_kerberos_acceptor_disable_transited_check();
581
582         status = gse_context_init(mem_ctx, do_sign, do_seal,
583                                   NULL, add_gss_c_flags, &gse_ctx);
584         if (!NT_STATUS_IS_OK(status)) {
585                 return NT_STATUS_NO_MEMORY;
586         }
587
588         ret = gse_krb5_get_server_keytab(gse_ctx->k5ctx,
589                                          &gse_ctx->keytab);
590         if (ret) {
591                 status = NT_STATUS_INTERNAL_ERROR;
592                 goto done;
593         }
594
595         /* This creates a GSSAPI cred_id_t with the keytab set */
596         gss_maj = smb_gss_krb5_import_cred(&gss_min, gse_ctx->k5ctx,
597                                            NULL, NULL, gse_ctx->keytab,
598                                            &gse_ctx->creds);
599
600         if (gss_maj != 0) {
601                 DEBUG(0, ("smb_gss_krb5_import_cred failed with [%s]\n",
602                           gse_errstr(gse_ctx, gss_maj, gss_min)));
603                 status = NT_STATUS_INTERNAL_ERROR;
604                 goto done;
605         }
606
607         gss_maj = smb_gss_krb5_prepare_acceptor_cred(&gss_min,
608                                                      disable_transited_check,
609                                                      &gse_ctx->creds);
610
611         if (gss_maj != 0) {
612                 DEBUG(0, ("smb_gss_krb5_prepare_acceptor_cred failed with [%s]\n",
613                           gse_errstr(gse_ctx, gss_maj, gss_min)));
614                 status = NT_STATUS_INTERNAL_ERROR;
615                 goto done;
616         }
617
618         status = NT_STATUS_OK;
619
620 done:
621         if (!NT_STATUS_IS_OK(status)) {
622                 TALLOC_FREE(gse_ctx);
623         }
624
625         *_gse_ctx = gse_ctx;
626         return status;
627 }
628
629 static NTSTATUS gse_get_server_auth_token(TALLOC_CTX *mem_ctx,
630                                           struct gensec_security *gensec_security,
631                                           const DATA_BLOB *token_in,
632                                           DATA_BLOB *token_out)
633 {
634         struct gse_context *gse_ctx =
635                 talloc_get_type_abort(gensec_security->private_data,
636                                       struct gse_context);
637         OM_uint32 gss_maj, gss_min;
638         gss_buffer_desc in_data;
639         gss_buffer_desc out_data;
640         DATA_BLOB blob = data_blob_null;
641         NTSTATUS status;
642         OM_uint32 time_rec = 0;
643         struct timeval tv;
644
645         in_data.value = token_in->data;
646         in_data.length = token_in->length;
647
648         gss_maj = gss_accept_sec_context(&gss_min,
649                                          &gse_ctx->gssapi_context,
650                                          gse_ctx->creds,
651                                          &in_data,
652                                          GSS_C_NO_CHANNEL_BINDINGS,
653                                          &gse_ctx->client_name,
654                                          &gse_ctx->ret_mech,
655                                          &out_data,
656                                          &gse_ctx->gss_got_flags,
657                                          &time_rec,
658                                          &gse_ctx->delegated_cred_handle);
659         switch (gss_maj) {
660         case GSS_S_COMPLETE:
661                 /* we are done with it */
662                 tv = timeval_current_ofs(time_rec, 0);
663                 gse_ctx->expire_time = timeval_to_nttime(&tv);
664
665                 status = NT_STATUS_OK;
666                 break;
667         case GSS_S_CONTINUE_NEEDED:
668                 /* we will need a third leg */
669                 status = NT_STATUS_MORE_PROCESSING_REQUIRED;
670                 break;
671         default:
672                 DEBUG(1, ("gss_accept_sec_context failed with [%s]\n",
673                           gse_errstr(talloc_tos(), gss_maj, gss_min)));
674
675                 if (gse_ctx->gssapi_context) {
676                         gss_delete_sec_context(&gss_min,
677                                                 &gse_ctx->gssapi_context,
678                                                 GSS_C_NO_BUFFER);
679                 }
680
681                 /*
682                  * If we got an output token, make Windows aware of it
683                  * by telling it that more processing is needed
684                  */
685                 if (out_data.length > 0) {
686                         status = NT_STATUS_MORE_PROCESSING_REQUIRED;
687                         /* Fall through to handle the out token */
688                 } else {
689                         status = NT_STATUS_LOGON_FAILURE;
690                         goto done;
691                 }
692         }
693
694         /* we may be told to return nothing */
695         if (out_data.length) {
696                 blob = data_blob_talloc(mem_ctx, out_data.value, out_data.length);
697                 if (!blob.data) {
698                         status = NT_STATUS_NO_MEMORY;
699                 }
700                 gss_release_buffer(&gss_min, &out_data);
701         }
702
703
704 done:
705         *token_out = blob;
706         return status;
707 }
708
709 static char *gse_errstr(TALLOC_CTX *mem_ctx, OM_uint32 maj, OM_uint32 min)
710 {
711         OM_uint32 gss_min, gss_maj;
712         gss_buffer_desc msg_min;
713         gss_buffer_desc msg_maj;
714         OM_uint32 msg_ctx = 0;
715
716         char *errstr = NULL;
717
718         ZERO_STRUCT(msg_min);
719         ZERO_STRUCT(msg_maj);
720
721         gss_maj = gss_display_status(&gss_min, maj, GSS_C_GSS_CODE,
722                                      GSS_C_NO_OID, &msg_ctx, &msg_maj);
723         if (gss_maj) {
724                 goto done;
725         }
726         errstr = talloc_asprintf(mem_ctx, "maj[%d] min[%d]: ",
727                                  (int)maj, (int)gss_min);
728         if (!errstr) {
729                 goto done;
730         }
731         errstr = talloc_strndup_append_buffer(errstr,
732                                 (char *)msg_maj.value,
733                                         msg_maj.length);
734         if (!errstr) {
735                 goto done;
736         }
737         gss_maj = gss_display_status(&gss_min, min, GSS_C_MECH_CODE,
738                                      (gss_OID)discard_const(gss_mech_krb5),
739                                      &msg_ctx, &msg_min);
740         if (gss_maj) {
741                 goto done;
742         }
743
744         errstr = talloc_strdup_append_buffer(errstr, ": ");
745         if (!errstr) {
746                 goto done;
747         }
748         errstr = talloc_strndup_append_buffer(errstr,
749                                                 (char *)msg_min.value,
750                                                         msg_min.length);
751         if (!errstr) {
752                 goto done;
753         }
754
755 done:
756         if (msg_min.value) {
757                 gss_release_buffer(&gss_min, &msg_min);
758         }
759         if (msg_maj.value) {
760                 gss_release_buffer(&gss_min, &msg_maj);
761         }
762         return errstr;
763 }
764
765 static NTSTATUS gensec_gse_client_start(struct gensec_security *gensec_security)
766 {
767         struct gse_context *gse_ctx;
768         struct cli_credentials *creds = gensec_get_credentials(gensec_security);
769         NTSTATUS nt_status;
770         OM_uint32 want_flags = 0;
771         bool do_sign = false, do_seal = false;
772         const char *hostname = gensec_get_target_hostname(gensec_security);
773         const char *service = gensec_get_target_service(gensec_security);
774         const char *username = cli_credentials_get_username(creds);
775         const char *password = cli_credentials_get_password(creds);
776         const char *realm = cli_credentials_get_realm(creds);
777
778         if (!hostname) {
779                 DEBUG(1, ("Could not determine hostname for target computer, cannot use kerberos\n"));
780                 return NT_STATUS_INVALID_PARAMETER;
781         }
782         if (is_ipaddress(hostname)) {
783                 DEBUG(2, ("Cannot do GSE to an IP address\n"));
784                 return NT_STATUS_INVALID_PARAMETER;
785         }
786         if (strcmp(hostname, "localhost") == 0) {
787                 DEBUG(2, ("GSE to 'localhost' does not make sense\n"));
788                 return NT_STATUS_INVALID_PARAMETER;
789         }
790
791         if (gensec_security->want_features & GENSEC_FEATURE_SESSION_KEY) {
792                 do_sign = true;
793         }
794         if (gensec_security->want_features & GENSEC_FEATURE_SIGN) {
795                 do_sign = true;
796         }
797         if (gensec_security->want_features & GENSEC_FEATURE_SEAL) {
798                 do_seal = true;
799         }
800         if (gensec_security->want_features & GENSEC_FEATURE_DCE_STYLE) {
801                 want_flags |= GSS_C_DCE_STYLE;
802         }
803
804         nt_status = gse_init_client(gensec_security, do_sign, do_seal, NULL,
805                                     hostname, service, realm,
806                                     username, password, want_flags,
807                                     &gse_ctx);
808         if (!NT_STATUS_IS_OK(nt_status)) {
809                 return nt_status;
810         }
811         gensec_security->private_data = gse_ctx;
812         return NT_STATUS_OK;
813 }
814
815 static NTSTATUS gensec_gse_server_start(struct gensec_security *gensec_security)
816 {
817         struct gse_context *gse_ctx;
818         NTSTATUS nt_status;
819         OM_uint32 want_flags = 0;
820         bool do_sign = false, do_seal = false;
821
822         if (gensec_security->want_features & GENSEC_FEATURE_SIGN) {
823                 do_sign = true;
824         }
825         if (gensec_security->want_features & GENSEC_FEATURE_SEAL) {
826                 do_seal = true;
827         }
828         if (gensec_security->want_features & GENSEC_FEATURE_DCE_STYLE) {
829                 want_flags |= GSS_C_DCE_STYLE;
830         }
831
832         nt_status = gse_init_server(gensec_security, do_sign, do_seal, want_flags,
833                                     &gse_ctx);
834         if (!NT_STATUS_IS_OK(nt_status)) {
835                 return nt_status;
836         }
837         gensec_security->private_data = gse_ctx;
838         return NT_STATUS_OK;
839 }
840
841 struct gensec_gse_update_state {
842         NTSTATUS status;
843         DATA_BLOB out;
844 };
845
846 static NTSTATUS gensec_gse_update_internal(struct gensec_security *gensec_security,
847                                            TALLOC_CTX *mem_ctx,
848                                            const DATA_BLOB in,
849                                            DATA_BLOB *out);
850
851 static struct tevent_req *gensec_gse_update_send(TALLOC_CTX *mem_ctx,
852                                                  struct tevent_context *ev,
853                                                  struct gensec_security *gensec_security,
854                                                  const DATA_BLOB in)
855 {
856         struct tevent_req *req = NULL;
857         struct gensec_gse_update_state *state = NULL;
858         NTSTATUS status;
859
860         req = tevent_req_create(mem_ctx, &state,
861                                 struct gensec_gse_update_state);
862         if (req == NULL) {
863                 return NULL;
864         }
865
866         status = gensec_gse_update_internal(gensec_security,
867                                             state, in,
868                                             &state->out);
869         state->status = status;
870         if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
871                 tevent_req_done(req);
872                 return tevent_req_post(req, ev);
873         }
874         if (tevent_req_nterror(req, status)) {
875                 return tevent_req_post(req, ev);
876         }
877
878         tevent_req_done(req);
879         return tevent_req_post(req, ev);
880 }
881
882 static NTSTATUS gensec_gse_update_internal(struct gensec_security *gensec_security,
883                                            TALLOC_CTX *mem_ctx,
884                                            const DATA_BLOB in,
885                                            DATA_BLOB *out)
886 {
887         NTSTATUS status;
888
889         switch (gensec_security->gensec_role) {
890         case GENSEC_CLIENT:
891                 status = gse_get_client_auth_token(mem_ctx,
892                                                    gensec_security,
893                                                    &in, out);
894                 break;
895         case GENSEC_SERVER:
896                 status = gse_get_server_auth_token(mem_ctx,
897                                                    gensec_security,
898                                                    &in, out);
899                 break;
900         }
901         if (!NT_STATUS_IS_OK(status)) {
902                 return status;
903         }
904
905         return NT_STATUS_OK;
906 }
907
908 static NTSTATUS gensec_gse_update_recv(struct tevent_req *req,
909                                        TALLOC_CTX *out_mem_ctx,
910                                        DATA_BLOB *out)
911 {
912         struct gensec_gse_update_state *state =
913                 tevent_req_data(req,
914                 struct gensec_gse_update_state);
915         NTSTATUS status;
916
917         *out = data_blob_null;
918
919         if (tevent_req_is_nterror(req, &status)) {
920                 tevent_req_received(req);
921                 return status;
922         }
923
924         *out = state->out;
925         talloc_steal(out_mem_ctx, state->out.data);
926         status = state->status;
927         tevent_req_received(req);
928         return status;
929 }
930
931 static NTSTATUS gensec_gse_wrap(struct gensec_security *gensec_security,
932                                 TALLOC_CTX *mem_ctx,
933                                 const DATA_BLOB *in,
934                                 DATA_BLOB *out)
935 {
936         struct gse_context *gse_ctx =
937                 talloc_get_type_abort(gensec_security->private_data,
938                 struct gse_context);
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                             gse_ctx->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(0, ("gensec_gse_wrap: GSS Wrap failed: %s\n",
954                           gse_errstr(talloc_tos(), maj_stat, min_stat)));
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_have_feature(gensec_security, GENSEC_FEATURE_SEAL)
962             && !conf_state) {
963                 return NT_STATUS_ACCESS_DENIED;
964         }
965         return NT_STATUS_OK;
966 }
967
968 static NTSTATUS gensec_gse_unwrap(struct gensec_security *gensec_security,
969                                      TALLOC_CTX *mem_ctx,
970                                      const DATA_BLOB *in,
971                                      DATA_BLOB *out)
972 {
973         struct gse_context *gse_ctx =
974                 talloc_get_type_abort(gensec_security->private_data,
975                 struct gse_context);
976         OM_uint32 maj_stat, min_stat;
977         gss_buffer_desc input_token, output_token;
978         int conf_state;
979         gss_qop_t qop_state;
980         input_token.length = in->length;
981         input_token.value = in->data;
982
983         maj_stat = gss_unwrap(&min_stat,
984                               gse_ctx->gssapi_context,
985                               &input_token,
986                               &output_token,
987                               &conf_state,
988                               &qop_state);
989         if (GSS_ERROR(maj_stat)) {
990                 DEBUG(0, ("gensec_gse_unwrap: GSS UnWrap failed: %s\n",
991                           gse_errstr(talloc_tos(), maj_stat, min_stat)));
992                 return NT_STATUS_ACCESS_DENIED;
993         }
994
995         *out = data_blob_talloc(mem_ctx, output_token.value, output_token.length);
996         gss_release_buffer(&min_stat, &output_token);
997
998         if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)
999             && !conf_state) {
1000                 return NT_STATUS_ACCESS_DENIED;
1001         }
1002         return NT_STATUS_OK;
1003 }
1004
1005 static NTSTATUS gensec_gse_seal_packet(struct gensec_security *gensec_security,
1006                                        TALLOC_CTX *mem_ctx,
1007                                        uint8_t *data, size_t length,
1008                                        const uint8_t *whole_pdu, size_t pdu_length,
1009                                        DATA_BLOB *sig)
1010 {
1011         struct gse_context *gse_ctx =
1012                 talloc_get_type_abort(gensec_security->private_data,
1013                 struct gse_context);
1014         bool hdr_signing = false;
1015         size_t sig_size = 0;
1016         NTSTATUS status;
1017
1018         if (gensec_security->want_features & GENSEC_FEATURE_SIGN_PKT_HEADER) {
1019                 hdr_signing = true;
1020         }
1021
1022         sig_size = gensec_gse_sig_size(gensec_security, length);
1023
1024         status = gssapi_seal_packet(gse_ctx->gssapi_context,
1025                                     &gse_ctx->gss_mech,
1026                                     hdr_signing, sig_size,
1027                                     data, length,
1028                                     whole_pdu, pdu_length,
1029                                     mem_ctx, sig);
1030         if (!NT_STATUS_IS_OK(status)) {
1031                 DEBUG(0, ("gssapi_seal_packet(hdr_signing=%u,sig_size=%zu,"
1032                           "data=%zu,pdu=%zu) failed: %s\n",
1033                           hdr_signing, sig_size, length, pdu_length,
1034                           nt_errstr(status)));
1035                 return status;
1036         }
1037
1038         return NT_STATUS_OK;
1039 }
1040
1041 static NTSTATUS gensec_gse_unseal_packet(struct gensec_security *gensec_security,
1042                                          uint8_t *data, size_t length,
1043                                          const uint8_t *whole_pdu, size_t pdu_length,
1044                                          const DATA_BLOB *sig)
1045 {
1046         struct gse_context *gse_ctx =
1047                 talloc_get_type_abort(gensec_security->private_data,
1048                 struct gse_context);
1049         bool hdr_signing = false;
1050         NTSTATUS status;
1051
1052         if (gensec_security->want_features & GENSEC_FEATURE_SIGN_PKT_HEADER) {
1053                 hdr_signing = true;
1054         }
1055
1056         status = gssapi_unseal_packet(gse_ctx->gssapi_context,
1057                                       &gse_ctx->gss_mech,
1058                                       hdr_signing,
1059                                       data, length,
1060                                       whole_pdu, pdu_length,
1061                                       sig);
1062         if (!NT_STATUS_IS_OK(status)) {
1063                 DEBUG(0, ("gssapi_unseal_packet(hdr_signing=%u,sig_size=%zu,"
1064                           "data=%zu,pdu=%zu) failed: %s\n",
1065                           hdr_signing, sig->length, length, pdu_length,
1066                           nt_errstr(status)));
1067                 return status;
1068         }
1069
1070         return NT_STATUS_OK;
1071 }
1072
1073 static NTSTATUS gensec_gse_sign_packet(struct gensec_security *gensec_security,
1074                                        TALLOC_CTX *mem_ctx,
1075                                        const uint8_t *data, size_t length,
1076                                        const uint8_t *whole_pdu, size_t pdu_length,
1077                                        DATA_BLOB *sig)
1078 {
1079         struct gse_context *gse_ctx =
1080                 talloc_get_type_abort(gensec_security->private_data,
1081                 struct gse_context);
1082         bool hdr_signing = false;
1083         NTSTATUS status;
1084
1085         if (gensec_security->want_features & GENSEC_FEATURE_SIGN_PKT_HEADER) {
1086                 hdr_signing = true;
1087         }
1088
1089         status = gssapi_sign_packet(gse_ctx->gssapi_context,
1090                                     &gse_ctx->gss_mech,
1091                                     hdr_signing,
1092                                     data, length,
1093                                     whole_pdu, pdu_length,
1094                                     mem_ctx, sig);
1095         if (!NT_STATUS_IS_OK(status)) {
1096                 DEBUG(0, ("gssapi_sign_packet(hdr_signing=%u,"
1097                           "data=%zu,pdu=%zu) failed: %s\n",
1098                           hdr_signing, length, pdu_length,
1099                           nt_errstr(status)));
1100                 return status;
1101         }
1102
1103         return NT_STATUS_OK;
1104 }
1105
1106 static NTSTATUS gensec_gse_check_packet(struct gensec_security *gensec_security,
1107                                         const uint8_t *data, size_t length,
1108                                         const uint8_t *whole_pdu, size_t pdu_length,
1109                                         const DATA_BLOB *sig)
1110 {
1111         struct gse_context *gse_ctx =
1112                 talloc_get_type_abort(gensec_security->private_data,
1113                 struct gse_context);
1114         bool hdr_signing = false;
1115         NTSTATUS status;
1116
1117         if (gensec_security->want_features & GENSEC_FEATURE_SIGN_PKT_HEADER) {
1118                 hdr_signing = true;
1119         }
1120
1121         status = gssapi_check_packet(gse_ctx->gssapi_context,
1122                                      &gse_ctx->gss_mech,
1123                                      hdr_signing,
1124                                      data, length,
1125                                      whole_pdu, pdu_length,
1126                                      sig);
1127         if (!NT_STATUS_IS_OK(status)) {
1128                 DEBUG(0, ("gssapi_check_packet(hdr_signing=%u,sig_size=%zu"
1129                           "data=%zu,pdu=%zu) failed: %s\n",
1130                           hdr_signing, sig->length, length, pdu_length,
1131                           nt_errstr(status)));
1132                 return status;
1133         }
1134
1135         return NT_STATUS_OK;
1136 }
1137
1138 /* Try to figure out what features we actually got on the connection */
1139 static bool gensec_gse_have_feature(struct gensec_security *gensec_security,
1140                                     uint32_t feature)
1141 {
1142         struct gse_context *gse_ctx =
1143                 talloc_get_type_abort(gensec_security->private_data,
1144                 struct gse_context);
1145
1146         if (feature & GENSEC_FEATURE_SESSION_KEY) {
1147                 return gse_ctx->gss_got_flags & GSS_C_INTEG_FLAG;
1148         }
1149         if (feature & GENSEC_FEATURE_SIGN) {
1150                 return gse_ctx->gss_got_flags & GSS_C_INTEG_FLAG;
1151         }
1152         if (feature & GENSEC_FEATURE_SEAL) {
1153                 return gse_ctx->gss_got_flags & GSS_C_CONF_FLAG;
1154         }
1155         if (feature & GENSEC_FEATURE_DCE_STYLE) {
1156                 return gse_ctx->gss_got_flags & GSS_C_DCE_STYLE;
1157         }
1158         if (feature & GENSEC_FEATURE_NEW_SPNEGO) {
1159                 NTSTATUS status;
1160                 uint32_t keytype;
1161
1162                 if (!(gse_ctx->gss_got_flags & GSS_C_INTEG_FLAG)) {
1163                         return false;
1164                 }
1165
1166                 status = gssapi_get_session_key(talloc_tos(), 
1167                                                 gse_ctx->gssapi_context, NULL, &keytype);
1168                 /* 
1169                  * We should do a proper sig on the mechListMic unless
1170                  * we know we have to be backwards compatible with
1171                  * earlier windows versions.  
1172                  * 
1173                  * Negotiating a non-krb5
1174                  * mech for example should be regarded as having
1175                  * NEW_SPNEGO
1176                  */
1177                 if (NT_STATUS_IS_OK(status)) {
1178                         switch (keytype) {
1179                         case ENCTYPE_DES_CBC_CRC:
1180                         case ENCTYPE_DES_CBC_MD5:
1181                         case ENCTYPE_ARCFOUR_HMAC:
1182                         case ENCTYPE_DES3_CBC_SHA1:
1183                                 return false;
1184                         }
1185                 }
1186                 return true;
1187         }
1188         /* We can always do async (rather than strict request/reply) packets.  */
1189         if (feature & GENSEC_FEATURE_ASYNC_REPLIES) {
1190                 return true;
1191         }
1192         if (feature & GENSEC_FEATURE_SIGN_PKT_HEADER) {
1193                 return true;
1194         }
1195         return false;
1196 }
1197
1198 static NTTIME gensec_gse_expire_time(struct gensec_security *gensec_security)
1199 {
1200         struct gse_context *gse_ctx =
1201                 talloc_get_type_abort(gensec_security->private_data,
1202                 struct gse_context);
1203
1204         return gse_ctx->expire_time;
1205 }
1206
1207 /*
1208  * Extract the 'sesssion key' needed by SMB signing and ncacn_np
1209  * (for encrypting some passwords).
1210  *
1211  * This breaks all the abstractions, but what do you expect...
1212  */
1213 static NTSTATUS gensec_gse_session_key(struct gensec_security *gensec_security,
1214                                        TALLOC_CTX *mem_ctx,
1215                                        DATA_BLOB *session_key)
1216 {
1217         struct gse_context *gse_ctx =
1218                 talloc_get_type_abort(gensec_security->private_data,
1219                 struct gse_context);
1220
1221         return gssapi_get_session_key(mem_ctx, gse_ctx->gssapi_context, session_key, NULL);
1222 }
1223
1224 /* Get some basic (and authorization) information about the user on
1225  * this session.  This uses either the PAC (if present) or a local
1226  * database lookup */
1227 static NTSTATUS gensec_gse_session_info(struct gensec_security *gensec_security,
1228                                         TALLOC_CTX *mem_ctx,
1229                                         struct auth_session_info **_session_info)
1230 {
1231         struct gse_context *gse_ctx =
1232                 talloc_get_type_abort(gensec_security->private_data,
1233                 struct gse_context);
1234         NTSTATUS nt_status;
1235         TALLOC_CTX *tmp_ctx;
1236         struct auth_session_info *session_info = NULL;
1237         OM_uint32 maj_stat, min_stat;
1238         DATA_BLOB pac_blob, *pac_blob_ptr = NULL;
1239
1240         gss_buffer_desc name_token;
1241         char *principal_string;
1242
1243         tmp_ctx = talloc_named(mem_ctx, 0, "gensec_gse_session_info context");
1244         NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);
1245
1246         maj_stat = gss_display_name(&min_stat,
1247                                     gse_ctx->client_name,
1248                                     &name_token,
1249                                     NULL);
1250         if (GSS_ERROR(maj_stat)) {
1251                 DEBUG(1, ("GSS display_name failed: %s\n",
1252                           gse_errstr(talloc_tos(), maj_stat, min_stat)));
1253                 talloc_free(tmp_ctx);
1254                 return NT_STATUS_FOOBAR;
1255         }
1256
1257         principal_string = talloc_strndup(tmp_ctx,
1258                                           (const char *)name_token.value,
1259                                           name_token.length);
1260
1261         gss_release_buffer(&min_stat, &name_token);
1262
1263         if (!principal_string) {
1264                 talloc_free(tmp_ctx);
1265                 return NT_STATUS_NO_MEMORY;
1266         }
1267
1268         nt_status = gssapi_obtain_pac_blob(tmp_ctx,  gse_ctx->gssapi_context,
1269                                            gse_ctx->client_name,
1270                                            &pac_blob);
1271
1272         /* IF we have the PAC - otherwise we need to get this
1273          * data from elsewere
1274          */
1275         if (NT_STATUS_IS_OK(nt_status)) {
1276                 pac_blob_ptr = &pac_blob;
1277         }
1278         nt_status = gensec_generate_session_info_pac(tmp_ctx,
1279                                                      gensec_security,
1280                                                      NULL,
1281                                                      pac_blob_ptr, principal_string,
1282                                                      gensec_get_remote_address(gensec_security),
1283                                                      &session_info);
1284         if (!NT_STATUS_IS_OK(nt_status)) {
1285                 talloc_free(tmp_ctx);
1286                 return nt_status;
1287         }
1288
1289         nt_status = gensec_gse_session_key(gensec_security, session_info,
1290                                            &session_info->session_key);
1291         if (!NT_STATUS_IS_OK(nt_status)) {
1292                 talloc_free(tmp_ctx);
1293                 return nt_status;
1294         }
1295
1296         *_session_info = talloc_move(mem_ctx, &session_info);
1297         talloc_free(tmp_ctx);
1298
1299         return NT_STATUS_OK;
1300 }
1301
1302 static size_t gensec_gse_max_input_size(struct gensec_security *gensec_security)
1303 {
1304         struct gse_context *gse_ctx =
1305                 talloc_get_type_abort(gensec_security->private_data,
1306                 struct gse_context);
1307         OM_uint32 maj_stat, min_stat;
1308         OM_uint32 max_input_size;
1309
1310         maj_stat = gss_wrap_size_limit(&min_stat,
1311                                        gse_ctx->gssapi_context,
1312                                        gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL),
1313                                        GSS_C_QOP_DEFAULT,
1314                                        gse_ctx->max_wrap_buf_size,
1315                                        &max_input_size);
1316         if (GSS_ERROR(maj_stat)) {
1317                 TALLOC_CTX *mem_ctx = talloc_new(NULL);
1318                 DEBUG(1, ("gensec_gssapi_max_input_size: determining signature size with gss_wrap_size_limit failed: %s\n",
1319                           gse_errstr(mem_ctx, maj_stat, min_stat)));
1320                 talloc_free(mem_ctx);
1321                 return 0;
1322         }
1323
1324         return max_input_size;
1325 }
1326
1327 /* Find out the maximum output size negotiated on this connection */
1328 static size_t gensec_gse_max_wrapped_size(struct gensec_security *gensec_security)
1329 {
1330         struct gse_context *gse_ctx =
1331                 talloc_get_type_abort(gensec_security->private_data,
1332                 struct gse_context);
1333         return gse_ctx->max_wrap_buf_size;
1334 }
1335
1336 static size_t gensec_gse_sig_size(struct gensec_security *gensec_security,
1337                                   size_t data_size)
1338 {
1339         struct gse_context *gse_ctx =
1340                 talloc_get_type_abort(gensec_security->private_data,
1341                 struct gse_context);
1342
1343         if (gse_ctx->sig_size > 0) {
1344                 return gse_ctx->sig_size;
1345         }
1346
1347         gse_ctx->sig_size = gssapi_get_sig_size(gse_ctx->gssapi_context,
1348                                                 &gse_ctx->gss_mech,
1349                                                 gse_ctx->gss_got_flags,
1350                                                 data_size);
1351         return gse_ctx->sig_size;
1352 }
1353
1354 static const char *gensec_gse_final_auth_type(struct gensec_security *gensec_security)
1355 {
1356         struct gse_context *gse_ctx =
1357                 talloc_get_type_abort(gensec_security->private_data,
1358                 struct gse_context);
1359
1360         /* Only return the string for GSSAPI/Krb5 */
1361         if (smb_gss_oid_equal(&gse_ctx->gss_mech,
1362                               gss_mech_krb5)) {
1363                 return GENSEC_FINAL_AUTH_TYPE_KRB5;
1364         } else {
1365                 return "gensec_gse: UNKNOWN MECH";
1366         }
1367 }
1368
1369 static const char *gensec_gse_krb5_oids[] = {
1370         GENSEC_OID_KERBEROS5_OLD,
1371         GENSEC_OID_KERBEROS5,
1372         NULL
1373 };
1374
1375 const struct gensec_security_ops gensec_gse_krb5_security_ops = {
1376         .name           = "gse_krb5",
1377         .auth_type      = DCERPC_AUTH_TYPE_KRB5,
1378         .oid            = gensec_gse_krb5_oids,
1379         .client_start   = gensec_gse_client_start,
1380         .server_start   = gensec_gse_server_start,
1381         .magic          = gensec_magic_check_krb5_oid,
1382         .update_send    = gensec_gse_update_send,
1383         .update_recv    = gensec_gse_update_recv,
1384         .session_key    = gensec_gse_session_key,
1385         .session_info   = gensec_gse_session_info,
1386         .sig_size       = gensec_gse_sig_size,
1387         .sign_packet    = gensec_gse_sign_packet,
1388         .check_packet   = gensec_gse_check_packet,
1389         .seal_packet    = gensec_gse_seal_packet,
1390         .unseal_packet  = gensec_gse_unseal_packet,
1391         .max_input_size   = gensec_gse_max_input_size,
1392         .max_wrapped_size = gensec_gse_max_wrapped_size,
1393         .wrap           = gensec_gse_wrap,
1394         .unwrap         = gensec_gse_unwrap,
1395         .have_feature   = gensec_gse_have_feature,
1396         .expire_time    = gensec_gse_expire_time,
1397         .final_auth_type  = gensec_gse_final_auth_type,
1398         .enabled        = true,
1399         .kerberos       = true,
1400         .priority       = GENSEC_GSSAPI
1401 };
1402
1403 #endif /* HAVE_KRB5 */