s3-gse: add GENSEC_FEATURE_NEW_SPNEGO detection in gensec_gse_have_feature()
[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 "gse.h"
26 #include "libads/kerberos_proto.h"
27 #include "auth/common_auth.h"
28 #include "auth/gensec/gensec.h"
29 #include "auth/credentials/credentials.h"
30 #include "../librpc/gen_ndr/dcerpc.h"
31
32 #if defined(HAVE_KRB5) && defined(HAVE_GSS_WRAP_IOV)
33
34 #include "smb_krb5.h"
35 #include "gse_krb5.h"
36
37 #ifndef GSS_C_DCE_STYLE
38 #define GSS_C_DCE_STYLE 0x1000
39 #endif
40
41 #ifndef GSS_KRB5_INQ_SSPI_SESSION_KEY_OID
42 #define GSS_KRB5_INQ_SSPI_SESSION_KEY_OID_LENGTH 11
43 #define GSS_KRB5_INQ_SSPI_SESSION_KEY_OID "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x05"
44 #endif
45
46 gss_OID_desc gse_sesskey_inq_oid = {
47         GSS_KRB5_INQ_SSPI_SESSION_KEY_OID_LENGTH,
48         (void *)GSS_KRB5_INQ_SSPI_SESSION_KEY_OID
49 };
50
51 #ifndef GSS_KRB5_SESSION_KEY_ENCTYPE_OID
52 #define GSS_KRB5_SESSION_KEY_ENCTYPE_OID_LENGTH 10
53 #define GSS_KRB5_SESSION_KEY_ENCTYPE_OID  "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x04"
54 #endif
55
56 gss_OID_desc gse_sesskeytype_oid = {
57         GSS_KRB5_SESSION_KEY_ENCTYPE_OID_LENGTH,
58         (void *)GSS_KRB5_SESSION_KEY_ENCTYPE_OID
59 };
60
61 #define GSE_EXTRACT_RELEVANT_AUTHZ_DATA_OID_LENGTH 12
62 /*                                          EXTRACTION OID                                 AUTHZ ID */
63 #define GSE_EXTRACT_RELEVANT_AUTHZ_DATA_OID "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x0a" "\x01"
64
65 gss_OID_desc gse_authz_data_oid = {
66         GSE_EXTRACT_RELEVANT_AUTHZ_DATA_OID_LENGTH,
67         (void *)GSE_EXTRACT_RELEVANT_AUTHZ_DATA_OID
68 };
69
70 static char *gse_errstr(TALLOC_CTX *mem_ctx, OM_uint32 maj, OM_uint32 min);
71
72 struct gse_context {
73         gss_ctx_id_t gssapi_context;
74         gss_name_t server_name;
75         gss_name_t client_name;
76         OM_uint32 gss_want_flags, gss_got_flags;
77
78         gss_cred_id_t delegated_cred_handle;
79
80         gss_krb5_lucid_context_v1_t *lucid;
81
82         /* gensec_gse only */
83         krb5_context k5ctx;
84         krb5_ccache ccache;
85         krb5_keytab keytab;
86
87         gss_OID_desc gss_mech;
88         gss_cred_id_t creds;
89
90         gss_OID ret_mech;
91 };
92
93 #ifndef HAVE_GSS_OID_EQUAL
94
95 static bool gss_oid_equal(const gss_OID o1, const gss_OID o2)
96 {
97         if (o1 == o2) {
98                 return true;
99         }
100         if ((o1 == NULL && o2 != NULL) || (o1 != NULL && o2 == NULL)) {
101                 return false;
102         }
103         if (o1->length != o2->length) {
104                 return false;
105         }
106         return memcmp(o1->elements, o2->elements, o1->length) == false;
107 }
108
109 #endif
110
111 /* free non talloc dependent contexts */
112 static int gse_context_destructor(void *ptr)
113 {
114         struct gse_context *gse_ctx;
115         OM_uint32 gss_min, gss_maj;
116
117         gse_ctx = talloc_get_type_abort(ptr, struct gse_context);
118         if (gse_ctx->k5ctx) {
119                 if (gse_ctx->ccache) {
120                         krb5_cc_close(gse_ctx->k5ctx, gse_ctx->ccache);
121                         gse_ctx->ccache = NULL;
122                 }
123                 if (gse_ctx->keytab) {
124                         krb5_kt_close(gse_ctx->k5ctx, gse_ctx->keytab);
125                         gse_ctx->keytab = NULL;
126                 }
127                 krb5_free_context(gse_ctx->k5ctx);
128                 gse_ctx->k5ctx = NULL;
129         }
130         if (gse_ctx->gssapi_context != GSS_C_NO_CONTEXT) {
131                 gss_maj = gss_delete_sec_context(&gss_min,
132                                                  &gse_ctx->gssapi_context,
133                                                  GSS_C_NO_BUFFER);
134         }
135         if (gse_ctx->server_name) {
136                 gss_maj = gss_release_name(&gss_min,
137                                            &gse_ctx->server_name);
138         }
139         if (gse_ctx->client_name) {
140                 gss_maj = gss_release_name(&gss_min,
141                                            &gse_ctx->client_name);
142         }
143         if (gse_ctx->creds) {
144                 gss_maj = gss_release_cred(&gss_min,
145                                            &gse_ctx->creds);
146         }
147         if (gse_ctx->delegated_cred_handle) {
148                 gss_maj = gss_release_cred(&gss_min,
149                                            &gse_ctx->delegated_cred_handle);
150         }
151
152         /* MIT and Heimdal differ as to if you can call
153          * gss_release_oid() on this OID, generated by
154          * gss_{accept,init}_sec_context().  However, as long as the
155          * oid is gss_mech_krb5 (which it always is at the moment),
156          * then this is a moot point, as both declare this particular
157          * OID static, and so no memory is lost.  This assert is in
158          * place to ensure that the programmer who wishes to extend
159          * this code to EAP or other GSS mechanisms determines an
160          * implementation-dependent way of releasing any dynamically
161          * allocated OID */
162         SMB_ASSERT(gss_oid_equal(&gse_ctx->gss_mech, GSS_C_NO_OID) || gss_oid_equal(&gse_ctx->gss_mech, gss_mech_krb5));
163
164         return 0;
165 }
166
167 static NTSTATUS gse_context_init(TALLOC_CTX *mem_ctx,
168                                  bool do_sign, bool do_seal,
169                                  const char *ccache_name,
170                                  uint32_t add_gss_c_flags,
171                                  struct gse_context **_gse_ctx)
172 {
173         struct gse_context *gse_ctx;
174         krb5_error_code k5ret;
175         NTSTATUS status;
176
177         gse_ctx = talloc_zero(mem_ctx, struct gse_context);
178         if (!gse_ctx) {
179                 return NT_STATUS_NO_MEMORY;
180         }
181         talloc_set_destructor((TALLOC_CTX *)gse_ctx, gse_context_destructor);
182
183         memcpy(&gse_ctx->gss_mech, gss_mech_krb5, sizeof(gss_OID_desc));
184
185         gse_ctx->gss_want_flags = GSS_C_MUTUAL_FLAG |
186                                 GSS_C_DELEG_FLAG |
187                                 GSS_C_DELEG_POLICY_FLAG |
188                                 GSS_C_REPLAY_FLAG |
189                                 GSS_C_SEQUENCE_FLAG;
190         if (do_sign) {
191                 gse_ctx->gss_want_flags |= GSS_C_INTEG_FLAG;
192         }
193         if (do_seal) {
194                 gse_ctx->gss_want_flags |= GSS_C_INTEG_FLAG;
195                 gse_ctx->gss_want_flags |= GSS_C_CONF_FLAG;
196         }
197
198         gse_ctx->gss_want_flags |= add_gss_c_flags;
199
200         /* Initialize Kerberos Context */
201         initialize_krb5_error_table();
202
203         k5ret = krb5_init_context(&gse_ctx->k5ctx);
204         if (k5ret) {
205                 DEBUG(0, ("Failed to initialize kerberos context! (%s)\n",
206                           error_message(k5ret)));
207                 status = NT_STATUS_INTERNAL_ERROR;
208                 goto err_out;
209         }
210
211         if (!ccache_name) {
212                 ccache_name = krb5_cc_default_name(gse_ctx->k5ctx);
213         }
214         k5ret = krb5_cc_resolve(gse_ctx->k5ctx, ccache_name,
215                                 &gse_ctx->ccache);
216         if (k5ret) {
217                 DEBUG(1, ("Failed to resolve credential cache! (%s)\n",
218                           error_message(k5ret)));
219                 status = NT_STATUS_INTERNAL_ERROR;
220                 goto err_out;
221         }
222
223         /* TODO: Should we enforce a enc_types list ?
224         ret = krb5_set_default_tgs_ktypes(gse_ctx->k5ctx, enc_types);
225         */
226
227         *_gse_ctx = gse_ctx;
228         return NT_STATUS_OK;
229
230 err_out:
231         TALLOC_FREE(gse_ctx);
232         return status;
233 }
234
235 static NTSTATUS gse_init_client(TALLOC_CTX *mem_ctx,
236                                 bool do_sign, bool do_seal,
237                                 const char *ccache_name,
238                                 const char *server,
239                                 const char *service,
240                                 const char *username,
241                                 const char *password,
242                                 uint32_t add_gss_c_flags,
243                                 struct gse_context **_gse_ctx)
244 {
245         struct gse_context *gse_ctx;
246         OM_uint32 gss_maj, gss_min;
247         gss_buffer_desc name_buffer = {0, NULL};
248         gss_OID_set_desc mech_set;
249         NTSTATUS status;
250
251         if (!server || !service) {
252                 return NT_STATUS_INVALID_PARAMETER;
253         }
254
255         status = gse_context_init(mem_ctx, do_sign, do_seal,
256                                   ccache_name, add_gss_c_flags,
257                                   &gse_ctx);
258         if (!NT_STATUS_IS_OK(status)) {
259                 return NT_STATUS_NO_MEMORY;
260         }
261
262         /* Guess the realm based on the supplied service, and avoid the GSS libs
263            doing DNS lookups which may fail.
264
265            TODO: Loop with the KDC on some more combinations (local
266            realm in particular), possibly falling back to
267            GSS_C_NT_HOSTBASED_SERVICE
268         */
269         name_buffer.value = kerberos_get_principal_from_service_hostname(gse_ctx,
270                                                                          service, server);
271         if (!name_buffer.value) {
272                 status = NT_STATUS_NO_MEMORY;
273                 goto err_out;
274         }
275         name_buffer.length = strlen((char *)name_buffer.value);
276         gss_maj = gss_import_name(&gss_min, &name_buffer,
277                                   GSS_C_NT_USER_NAME,
278                                   &gse_ctx->server_name);
279         if (gss_maj) {
280                 DEBUG(0, ("gss_import_name failed for %s, with [%s]\n",
281                           (char *)name_buffer.value,
282                           gse_errstr(gse_ctx, gss_maj, gss_min)));
283                 status = NT_STATUS_INTERNAL_ERROR;
284                 goto err_out;
285         }
286
287         /* TODO: get krb5 ticket using username/password, if no valid
288          * one already available in ccache */
289
290         mech_set.count = 1;
291         mech_set.elements = &gse_ctx->gss_mech;
292
293         gss_maj = gss_acquire_cred(&gss_min,
294                                    GSS_C_NO_NAME,
295                                    GSS_C_INDEFINITE,
296                                    &mech_set,
297                                    GSS_C_INITIATE,
298                                    &gse_ctx->creds,
299                                    NULL, NULL);
300         if (gss_maj) {
301                 DEBUG(0, ("gss_acquire_creds failed for %s, with [%s]\n",
302                           (char *)name_buffer.value,
303                           gse_errstr(gse_ctx, gss_maj, gss_min)));
304                 status = NT_STATUS_INTERNAL_ERROR;
305                 goto err_out;
306         }
307
308         *_gse_ctx = gse_ctx;
309         TALLOC_FREE(name_buffer.value);
310         return NT_STATUS_OK;
311
312 err_out:
313         TALLOC_FREE(name_buffer.value);
314         TALLOC_FREE(gse_ctx);
315         return status;
316 }
317
318 static NTSTATUS gse_get_client_auth_token(TALLOC_CTX *mem_ctx,
319                                           struct gse_context *gse_ctx,
320                                           const DATA_BLOB *token_in,
321                                           DATA_BLOB *token_out)
322 {
323         OM_uint32 gss_maj, gss_min;
324         gss_buffer_desc in_data;
325         gss_buffer_desc out_data;
326         DATA_BLOB blob = data_blob_null;
327         NTSTATUS status;
328
329         in_data.value = token_in->data;
330         in_data.length = token_in->length;
331
332         gss_maj = gss_init_sec_context(&gss_min,
333                                         gse_ctx->creds,
334                                         &gse_ctx->gssapi_context,
335                                         gse_ctx->server_name,
336                                         &gse_ctx->gss_mech,
337                                         gse_ctx->gss_want_flags,
338                                         0, GSS_C_NO_CHANNEL_BINDINGS,
339                                         &in_data, NULL, &out_data,
340                                         &gse_ctx->gss_got_flags, NULL);
341         switch (gss_maj) {
342         case GSS_S_COMPLETE:
343                 /* we are done with it */
344                 status = NT_STATUS_OK;
345                 break;
346         case GSS_S_CONTINUE_NEEDED:
347                 /* we will need a third leg */
348                 status = NT_STATUS_MORE_PROCESSING_REQUIRED;
349                 break;
350         default:
351                 DEBUG(0, ("gss_init_sec_context failed with [%s]\n",
352                           gse_errstr(talloc_tos(), gss_maj, gss_min)));
353                 status = NT_STATUS_INTERNAL_ERROR;
354                 goto done;
355         }
356
357         /* we may be told to return nothing */
358         if (out_data.length) {
359                 blob = data_blob_talloc(mem_ctx, out_data.value, out_data.length);
360                 if (!blob.data) {
361                         status = NT_STATUS_NO_MEMORY;
362                 }
363
364                 gss_maj = gss_release_buffer(&gss_min, &out_data);
365         }
366
367 done:
368         *token_out = blob;
369         return status;
370 }
371
372 static NTSTATUS gse_init_server(TALLOC_CTX *mem_ctx,
373                                 bool do_sign, bool do_seal,
374                                 uint32_t add_gss_c_flags,
375                                 struct gse_context **_gse_ctx)
376 {
377         struct gse_context *gse_ctx;
378         OM_uint32 gss_maj, gss_min;
379         krb5_error_code ret;
380         NTSTATUS status;
381
382         status = gse_context_init(mem_ctx, do_sign, do_seal,
383                                   NULL, add_gss_c_flags, &gse_ctx);
384         if (!NT_STATUS_IS_OK(status)) {
385                 return NT_STATUS_NO_MEMORY;
386         }
387
388         ret = gse_krb5_get_server_keytab(gse_ctx->k5ctx,
389                                          &gse_ctx->keytab);
390         if (ret) {
391                 status = NT_STATUS_INTERNAL_ERROR;
392                 goto done;
393         }
394
395 #ifdef HAVE_GSS_KRB5_IMPORT_CRED
396
397         /* This creates a GSSAPI cred_id_t with the keytab set */
398         gss_maj = gss_krb5_import_cred(&gss_min, NULL, NULL, gse_ctx->keytab, 
399                                        &gse_ctx->creds);
400
401         if (gss_maj != 0
402             && gss_maj != (GSS_S_CALL_BAD_STRUCTURE|GSS_S_BAD_NAME)) {
403                 DEBUG(0, ("gss_krb5_import_cred failed with [%s]\n",
404                           gse_errstr(gse_ctx, gss_maj, gss_min)));
405                 status = NT_STATUS_INTERNAL_ERROR;
406                 goto done;
407
408                 /* This is the error the MIT krb5 1.9 gives when it
409                  * implements the function, but we do not specify the
410                  * principal.  However, when we specify the principal
411                  * as host$@REALM the GSS acceptor fails with 'wrong
412                  * principal in request'.  Work around the issue by
413                  * falling back to the alternate approach below. */
414         } else if (gss_maj == (GSS_S_CALL_BAD_STRUCTURE|GSS_S_BAD_NAME))
415 #endif
416         /* FIXME!!!
417          * This call sets the default keytab for the whole server, not
418          * just for this context. Need to find a way that does not alter
419          * the state of the whole server ... */
420         {
421                 const char *ktname;
422                 gss_OID_set_desc mech_set;
423
424                 ret = smb_krb5_keytab_name(gse_ctx, gse_ctx->k5ctx,
425                                    gse_ctx->keytab, &ktname);
426                 if (ret) {
427                         status = NT_STATUS_INTERNAL_ERROR;
428                         goto done;
429                 }
430
431                 ret = gsskrb5_register_acceptor_identity(ktname);
432                 if (ret) {
433                         status = NT_STATUS_INTERNAL_ERROR;
434                         goto done;
435                 }
436
437                 mech_set.count = 1;
438                 mech_set.elements = &gse_ctx->gss_mech;
439
440                 gss_maj = gss_acquire_cred(&gss_min,
441                                    GSS_C_NO_NAME,
442                                    GSS_C_INDEFINITE,
443                                    &mech_set,
444                                    GSS_C_ACCEPT,
445                                    &gse_ctx->creds,
446                                    NULL, NULL);
447
448                 if (gss_maj) {
449                         DEBUG(0, ("gss_acquire_creds failed with [%s]\n",
450                                   gse_errstr(gse_ctx, gss_maj, gss_min)));
451                         status = NT_STATUS_INTERNAL_ERROR;
452                         goto done;
453                 }
454         }
455
456         status = NT_STATUS_OK;
457
458 done:
459         if (!NT_STATUS_IS_OK(status)) {
460                 TALLOC_FREE(gse_ctx);
461         }
462
463         *_gse_ctx = gse_ctx;
464         return status;
465 }
466
467 static NTSTATUS gse_get_server_auth_token(TALLOC_CTX *mem_ctx,
468                                           struct gse_context *gse_ctx,
469                                           const DATA_BLOB *token_in,
470                                           DATA_BLOB *token_out)
471 {
472         OM_uint32 gss_maj, gss_min;
473         gss_buffer_desc in_data;
474         gss_buffer_desc out_data;
475         DATA_BLOB blob = data_blob_null;
476         NTSTATUS status;
477
478         in_data.value = token_in->data;
479         in_data.length = token_in->length;
480
481         gss_maj = gss_accept_sec_context(&gss_min,
482                                          &gse_ctx->gssapi_context,
483                                          gse_ctx->creds,
484                                          &in_data,
485                                          GSS_C_NO_CHANNEL_BINDINGS,
486                                          &gse_ctx->client_name,
487                                          &gse_ctx->ret_mech,
488                                          &out_data,
489                                          &gse_ctx->gss_got_flags, NULL,
490                                          &gse_ctx->delegated_cred_handle);
491         switch (gss_maj) {
492         case GSS_S_COMPLETE:
493                 /* we are done with it */
494                 status = NT_STATUS_OK;
495                 break;
496         case GSS_S_CONTINUE_NEEDED:
497                 /* we will need a third leg */
498                 status = NT_STATUS_MORE_PROCESSING_REQUIRED;
499                 break;
500         default:
501                 DEBUG(0, ("gss_init_sec_context failed with [%s]\n",
502                           gse_errstr(talloc_tos(), gss_maj, gss_min)));
503
504                 if (gse_ctx->gssapi_context) {
505                         gss_delete_sec_context(&gss_min,
506                                                 &gse_ctx->gssapi_context,
507                                                 GSS_C_NO_BUFFER);
508                 }
509
510                 status = NT_STATUS_INTERNAL_ERROR;
511                 goto done;
512         }
513
514         /* we may be told to return nothing */
515         if (out_data.length) {
516                 blob = data_blob_talloc(mem_ctx, out_data.value, out_data.length);
517                 if (!blob.data) {
518                         status = NT_STATUS_NO_MEMORY;
519                 }
520                 gss_maj = gss_release_buffer(&gss_min, &out_data);
521         }
522
523
524 done:
525         *token_out = blob;
526         return status;
527 }
528
529 static NTSTATUS gse_verify_server_auth_flags(struct gse_context *gse_ctx)
530 {
531         if (memcmp(gse_ctx->ret_mech,
532                    gss_mech_krb5, sizeof(gss_OID_desc)) != 0) {
533                 return NT_STATUS_ACCESS_DENIED;
534         }
535
536         /* GSS_C_MUTUAL_FLAG */
537         /* GSS_C_DELEG_FLAG */
538         /* GSS_C_DELEG_POLICY_FLAG */
539         /* GSS_C_REPLAY_FLAG */
540         /* GSS_C_SEQUENCE_FLAG */
541
542         /* GSS_C_INTEG_FLAG */
543         if (gse_ctx->gss_want_flags & GSS_C_INTEG_FLAG) {
544                 if (!(gse_ctx->gss_got_flags & GSS_C_INTEG_FLAG)) {
545                         return NT_STATUS_ACCESS_DENIED;
546                 }
547         }
548
549         /* GSS_C_CONF_FLAG */
550         if (gse_ctx->gss_want_flags & GSS_C_CONF_FLAG) {
551                 if (!(gse_ctx->gss_got_flags & GSS_C_CONF_FLAG)) {
552                         return NT_STATUS_ACCESS_DENIED;
553                 }
554
555                 /* GSS_C_CONF_FLAG implies GSS_C_INTEG_FLAG */
556                 if (!(gse_ctx->gss_got_flags & GSS_C_INTEG_FLAG)) {
557                         return NT_STATUS_ACCESS_DENIED;
558                 }
559         }
560
561         /* GSS_C_DCE_STYLE */
562         if (gse_ctx->gss_want_flags & GSS_C_DCE_STYLE) {
563                 if (!(gse_ctx->gss_got_flags & GSS_C_DCE_STYLE)) {
564                         return NT_STATUS_ACCESS_DENIED;
565                 }
566                 /* GSS_C_DCE_STYLE implies GSS_C_MUTUAL_FLAG */
567                 if (!(gse_ctx->gss_got_flags & GSS_C_MUTUAL_FLAG)) {
568                         return NT_STATUS_ACCESS_DENIED;
569                 }
570         }
571
572         return NT_STATUS_OK;
573 }
574
575 static char *gse_errstr(TALLOC_CTX *mem_ctx, OM_uint32 maj, OM_uint32 min)
576 {
577         OM_uint32 gss_min, gss_maj;
578         gss_buffer_desc msg_min;
579         gss_buffer_desc msg_maj;
580         OM_uint32 msg_ctx = 0;
581
582         char *errstr = NULL;
583
584         ZERO_STRUCT(msg_min);
585         ZERO_STRUCT(msg_maj);
586
587         gss_maj = gss_display_status(&gss_min, maj, GSS_C_GSS_CODE,
588                                      GSS_C_NO_OID, &msg_ctx, &msg_maj);
589         if (gss_maj) {
590                 goto done;
591         }
592         errstr = talloc_strndup(mem_ctx,
593                                 (char *)msg_maj.value,
594                                         msg_maj.length);
595         if (!errstr) {
596                 goto done;
597         }
598         gss_maj = gss_display_status(&gss_min, min, GSS_C_MECH_CODE,
599                                      (gss_OID)discard_const(gss_mech_krb5),
600                                      &msg_ctx, &msg_min);
601         if (gss_maj) {
602                 goto done;
603         }
604
605         errstr = talloc_strdup_append_buffer(errstr, ": ");
606         if (!errstr) {
607                 goto done;
608         }
609         errstr = talloc_strndup_append_buffer(errstr,
610                                                 (char *)msg_min.value,
611                                                         msg_min.length);
612         if (!errstr) {
613                 goto done;
614         }
615
616 done:
617         if (msg_min.value) {
618                 gss_maj = gss_release_buffer(&gss_min, &msg_min);
619         }
620         if (msg_maj.value) {
621                 gss_maj = gss_release_buffer(&gss_min, &msg_maj);
622         }
623         return errstr;
624 }
625
626 static NTSTATUS gse_init_lucid(struct gse_context *gse_ctx)
627 {
628         OM_uint32 maj_stat, min_stat;
629         void *ptr = NULL;
630
631         if (gse_ctx->lucid) {
632                 return NT_STATUS_OK;
633         }
634
635         maj_stat = gss_krb5_export_lucid_sec_context(&min_stat,
636                                                      &gse_ctx->gssapi_context,
637                                                      1, &ptr);
638         if (maj_stat != GSS_S_COMPLETE) {
639                 DEBUG(0,("gse_init_lucid: %s\n",
640                         gse_errstr(talloc_tos(), maj_stat, min_stat)));
641                 return NT_STATUS_INTERNAL_ERROR;
642         }
643         gse_ctx->lucid = (gss_krb5_lucid_context_v1_t *)ptr;
644
645         if (gse_ctx->lucid->version != 1) {
646                 DEBUG(0,("gse_init_lucid: lucid version[%d] != 1\n",
647                         gse_ctx->lucid->version));
648                 gss_krb5_free_lucid_sec_context(&min_stat, gse_ctx->lucid);
649                 gse_ctx->lucid = NULL;
650                 return NT_STATUS_INTERNAL_ERROR;
651         }
652
653         return NT_STATUS_OK;
654 }
655
656 static DATA_BLOB gse_get_session_key(TALLOC_CTX *mem_ctx,
657                                      struct gse_context *gse_ctx)
658 {
659         OM_uint32 gss_min, gss_maj;
660         gss_buffer_set_t set = GSS_C_NO_BUFFER_SET;
661         DATA_BLOB ret;
662
663         gss_maj = gss_inquire_sec_context_by_oid(
664                                 &gss_min, gse_ctx->gssapi_context,
665                                 &gse_sesskey_inq_oid, &set);
666         if (gss_maj) {
667                 DEBUG(0, ("gss_inquire_sec_context_by_oid failed [%s]\n",
668                           gse_errstr(talloc_tos(), gss_maj, gss_min)));
669                 return data_blob_null;
670         }
671
672         if ((set == GSS_C_NO_BUFFER_SET) ||
673             (set->count != 2) ||
674             (memcmp(set->elements[1].value,
675                     gse_sesskeytype_oid.elements,
676                     gse_sesskeytype_oid.length) != 0)) {
677 #ifdef HAVE_GSSKRB5_GET_SUBKEY
678                 krb5_keyblock *subkey;
679                 gss_maj = gsskrb5_get_subkey(&gss_min,
680                                              gse_ctx->gssapi_context,
681                                              &subkey);
682                 if (gss_maj != 0) {
683                         DEBUG(1, ("NO session key for this mech\n"));
684                         return data_blob_null;
685                 }
686                 ret = data_blob_talloc(mem_ctx,
687                                        KRB5_KEY_DATA(subkey), KRB5_KEY_LENGTH(subkey));
688                 krb5_free_keyblock(NULL /* should be krb5_context */, subkey);
689                 return ret;
690 #else
691                 DEBUG(0, ("gss_inquire_sec_context_by_oid returned unknown "
692                           "OID for data in results:\n"));
693                 dump_data(1, (uint8_t *)set->elements[1].value,
694                              set->elements[1].length);
695                 return data_blob_null;
696 #endif
697         }
698
699         ret = data_blob_talloc(mem_ctx, set->elements[0].value,
700                                         set->elements[0].length);
701
702         gss_maj = gss_release_buffer_set(&gss_min, &set);
703         return ret;
704 }
705
706 static size_t gse_get_signature_length(struct gse_context *gse_ctx,
707                                        bool seal, size_t payload_size)
708 {
709         OM_uint32 gss_min, gss_maj;
710         gss_iov_buffer_desc iov[2];
711         int sealed;
712
713         /*
714          * gss_wrap_iov_length() only needs the type and length
715          */
716         iov[0].type = GSS_IOV_BUFFER_TYPE_HEADER;
717         iov[0].buffer.value = NULL;
718         iov[0].buffer.length = 0;
719         iov[1].type = GSS_IOV_BUFFER_TYPE_DATA;
720         iov[1].buffer.value = NULL;
721         iov[1].buffer.length = payload_size;
722
723         gss_maj = gss_wrap_iov_length(&gss_min, gse_ctx->gssapi_context,
724                                         seal, GSS_C_QOP_DEFAULT,
725                                         &sealed, iov, 2);
726         if (gss_maj) {
727                 DEBUG(0, ("gss_wrap_iov_length failed with [%s]\n",
728                           gse_errstr(talloc_tos(), gss_maj, gss_min)));
729                 return 0;
730         }
731
732         return iov[0].buffer.length;
733 }
734
735 static NTSTATUS gse_seal(TALLOC_CTX *mem_ctx, struct gse_context *gse_ctx,
736                          DATA_BLOB *data, DATA_BLOB *signature)
737 {
738         OM_uint32 gss_min, gss_maj;
739         gss_iov_buffer_desc iov[2];
740         int req_seal = 1; /* setting to 1 means we request sign+seal */
741         int sealed = 1;
742         NTSTATUS status;
743
744         /* allocate the memory ourselves so we do not need to talloc_memdup */
745         signature->length = gse_get_signature_length(gse_ctx, true, data->length);
746         if (!signature->length) {
747                 return NT_STATUS_INTERNAL_ERROR;
748         }
749         signature->data = (uint8_t *)talloc_size(mem_ctx, signature->length);
750         if (!signature->data) {
751                 return NT_STATUS_NO_MEMORY;
752         }
753         iov[0].type = GSS_IOV_BUFFER_TYPE_HEADER;
754         iov[0].buffer.value = signature->data;
755         iov[0].buffer.length = signature->length;
756
757         /* data is encrypted in place, which is ok */
758         iov[1].type = GSS_IOV_BUFFER_TYPE_DATA;
759         iov[1].buffer.value = data->data;
760         iov[1].buffer.length = data->length;
761
762         gss_maj = gss_wrap_iov(&gss_min, gse_ctx->gssapi_context,
763                                 req_seal, GSS_C_QOP_DEFAULT,
764                                 &sealed, iov, 2);
765         if (gss_maj) {
766                 DEBUG(0, ("gss_wrap_iov failed with [%s]\n",
767                           gse_errstr(talloc_tos(), gss_maj, gss_min)));
768                 status = NT_STATUS_ACCESS_DENIED;
769                 goto done;
770         }
771
772         if (!sealed) {
773                 DEBUG(0, ("gss_wrap_iov says data was not sealed!\n"));
774                 status = NT_STATUS_ACCESS_DENIED;
775                 goto done;
776         }
777
778         status = NT_STATUS_OK;
779
780         DEBUG(10, ("Sealed %d bytes, and got %d bytes header/signature.\n",
781                    (int)iov[1].buffer.length, (int)iov[0].buffer.length));
782
783 done:
784         return status;
785 }
786
787 static NTSTATUS gse_unseal(TALLOC_CTX *mem_ctx, struct gse_context *gse_ctx,
788                            DATA_BLOB *data, const DATA_BLOB *signature)
789 {
790         OM_uint32 gss_min, gss_maj;
791         gss_iov_buffer_desc iov[2];
792         int sealed;
793         NTSTATUS status;
794
795         iov[0].type = GSS_IOV_BUFFER_TYPE_HEADER;
796         iov[0].buffer.value = signature->data;
797         iov[0].buffer.length = signature->length;
798
799         /* data is decrypted in place, which is ok */
800         iov[1].type = GSS_IOV_BUFFER_TYPE_DATA;
801         iov[1].buffer.value = data->data;
802         iov[1].buffer.length = data->length;
803
804         gss_maj = gss_unwrap_iov(&gss_min, gse_ctx->gssapi_context,
805                                  &sealed, NULL, iov, 2);
806         if (gss_maj) {
807                 DEBUG(0, ("gss_unwrap_iov failed with [%s]\n",
808                           gse_errstr(talloc_tos(), gss_maj, gss_min)));
809                 status = NT_STATUS_ACCESS_DENIED;
810                 goto done;
811         }
812
813         if (!sealed) {
814                 DEBUG(0, ("gss_unwrap_iov says data is not sealed!\n"));
815                 status = NT_STATUS_ACCESS_DENIED;
816                 goto done;
817         }
818
819         status = NT_STATUS_OK;
820
821         DEBUG(10, ("Unsealed %d bytes, with %d bytes header/signature.\n",
822                    (int)iov[1].buffer.length, (int)iov[0].buffer.length));
823
824 done:
825         return status;
826 }
827
828 static NTSTATUS gse_sign(TALLOC_CTX *mem_ctx, struct gse_context *gse_ctx,
829                          DATA_BLOB *data, DATA_BLOB *signature)
830 {
831         OM_uint32 gss_min, gss_maj;
832         gss_buffer_desc in_data = { 0, NULL };
833         gss_buffer_desc out_data = { 0, NULL};
834         NTSTATUS status;
835
836         in_data.value = data->data;
837         in_data.length = data->length;
838
839         gss_maj = gss_get_mic(&gss_min, gse_ctx->gssapi_context,
840                               GSS_C_QOP_DEFAULT,
841                               &in_data, &out_data);
842         if (gss_maj) {
843                 DEBUG(0, ("gss_get_mic failed with [%s]\n",
844                           gse_errstr(talloc_tos(), gss_maj, gss_min)));
845                 status = NT_STATUS_ACCESS_DENIED;
846                 goto done;
847         }
848
849         *signature = data_blob_talloc(mem_ctx,
850                                         out_data.value, out_data.length);
851         if (!signature->data) {
852                 status = NT_STATUS_NO_MEMORY;
853                 goto done;
854         }
855
856         status = NT_STATUS_OK;
857
858 done:
859         if (out_data.value) {
860                 gss_maj = gss_release_buffer(&gss_min, &out_data);
861         }
862         return status;
863 }
864
865 static NTSTATUS gse_sigcheck(TALLOC_CTX *mem_ctx, struct gse_context *gse_ctx,
866                              const DATA_BLOB *data, const DATA_BLOB *signature)
867 {
868         OM_uint32 gss_min, gss_maj;
869         gss_buffer_desc in_data = { 0, NULL };
870         gss_buffer_desc in_token = { 0, NULL};
871         NTSTATUS status;
872
873         in_data.value = data->data;
874         in_data.length = data->length;
875         in_token.value = signature->data;
876         in_token.length = signature->length;
877
878         gss_maj = gss_verify_mic(&gss_min, gse_ctx->gssapi_context,
879                                  &in_data, &in_token, NULL);
880         if (gss_maj) {
881                 DEBUG(0, ("gss_verify_mic failed with [%s]\n",
882                           gse_errstr(talloc_tos(), gss_maj, gss_min)));
883                 status = NT_STATUS_ACCESS_DENIED;
884                 goto done;
885         }
886
887         status = NT_STATUS_OK;
888
889 done:
890         return status;
891 }
892
893 static NTSTATUS gensec_gse_client_start(struct gensec_security *gensec_security)
894 {
895         struct gse_context *gse_ctx;
896         struct cli_credentials *creds = gensec_get_credentials(gensec_security);
897         NTSTATUS nt_status;
898         OM_uint32 want_flags = 0;
899         bool do_sign = false, do_seal = false;
900         const char *hostname = gensec_get_target_hostname(gensec_security);
901         const char *service = gensec_get_target_service(gensec_security);
902         const char *username = cli_credentials_get_username(creds);
903         const char *password = cli_credentials_get_password(creds);
904
905         if (!hostname) {
906                 DEBUG(1, ("Could not determine hostname for target computer, cannot use kerberos\n"));
907                 return NT_STATUS_INVALID_PARAMETER;
908         }
909         if (is_ipaddress(hostname)) {
910                 DEBUG(2, ("Cannot do GSE to an IP address\n"));
911                 return NT_STATUS_INVALID_PARAMETER;
912         }
913         if (strcmp(hostname, "localhost") == 0) {
914                 DEBUG(2, ("GSE to 'localhost' does not make sense\n"));
915                 return NT_STATUS_INVALID_PARAMETER;
916         }
917
918         if (gensec_security->want_features & GENSEC_FEATURE_SIGN) {
919                 do_sign = true;
920         }
921         if (gensec_security->want_features & GENSEC_FEATURE_SEAL) {
922                 do_seal = true;
923         }
924         if (gensec_security->want_features & GENSEC_FEATURE_DCE_STYLE) {
925                 want_flags |= GSS_C_DCE_STYLE;
926         }
927
928         nt_status = gse_init_client(gensec_security, do_sign, do_seal, NULL,
929                                     hostname, service,
930                                     username, password, want_flags,
931                                     &gse_ctx);
932         if (!NT_STATUS_IS_OK(nt_status)) {
933                 return nt_status;
934         }
935         gensec_security->private_data = gse_ctx;
936         return NT_STATUS_OK;
937 }
938
939 static NTSTATUS gensec_gse_server_start(struct gensec_security *gensec_security)
940 {
941         struct gse_context *gse_ctx;
942         NTSTATUS nt_status;
943         OM_uint32 want_flags = 0;
944         bool do_sign = false, do_seal = false;
945
946         if (gensec_security->want_features & GENSEC_FEATURE_SIGN) {
947                 do_sign = true;
948         }
949         if (gensec_security->want_features & GENSEC_FEATURE_SEAL) {
950                 do_seal = true;
951         }
952         if (gensec_security->want_features & GENSEC_FEATURE_DCE_STYLE) {
953                 want_flags |= GSS_C_DCE_STYLE;
954         }
955
956         nt_status = gse_init_server(gensec_security, do_sign, do_seal, want_flags,
957                                     &gse_ctx);
958         if (!NT_STATUS_IS_OK(nt_status)) {
959                 return nt_status;
960         }
961         gensec_security->private_data = gse_ctx;
962         return NT_STATUS_OK;
963 }
964
965 /**
966  * Check if the packet is one for this mechansim
967  *
968  * @param gensec_security GENSEC state
969  * @param in The request, as a DATA_BLOB
970  * @return Error, INVALID_PARAMETER if it's not a packet for us
971  *                or NT_STATUS_OK if the packet is ok.
972  */
973
974 static NTSTATUS gensec_gse_magic(struct gensec_security *gensec_security,
975                                  const DATA_BLOB *in)
976 {
977         if (gensec_gssapi_check_oid(in, GENSEC_OID_KERBEROS5)) {
978                 return NT_STATUS_OK;
979         } else {
980                 return NT_STATUS_INVALID_PARAMETER;
981         }
982 }
983
984
985 /**
986  * Next state function for the GSE GENSEC mechanism
987  *
988  * @param gensec_gse_state GSE State
989  * @param mem_ctx The TALLOC_CTX for *out to be allocated on
990  * @param in The request, as a DATA_BLOB
991  * @param out The reply, as an talloc()ed DATA_BLOB, on *mem_ctx
992  * @return Error, MORE_PROCESSING_REQUIRED if a reply is sent,
993  *                or NT_STATUS_OK if the user is authenticated.
994  */
995
996 static NTSTATUS gensec_gse_update(struct gensec_security *gensec_security,
997                                   TALLOC_CTX *mem_ctx,
998                                   struct tevent_context *ev,
999                                   const DATA_BLOB in, DATA_BLOB *out)
1000 {
1001         NTSTATUS status;
1002         struct gse_context *gse_ctx =
1003                 talloc_get_type_abort(gensec_security->private_data,
1004                 struct gse_context);
1005
1006         switch (gensec_security->gensec_role) {
1007         case GENSEC_CLIENT:
1008                 status = gse_get_client_auth_token(mem_ctx, gse_ctx,
1009                                                    &in, out);
1010                 break;
1011         case GENSEC_SERVER:
1012                 status = gse_get_server_auth_token(mem_ctx, gse_ctx,
1013                                                    &in, out);
1014                 break;
1015         }
1016         if (!NT_STATUS_IS_OK(status)) {
1017                 return status;
1018         }
1019
1020         if (gensec_security->gensec_role == GENSEC_SERVER) {
1021                 return gse_verify_server_auth_flags(gse_ctx);
1022         }
1023
1024         return NT_STATUS_OK;
1025 }
1026
1027 static NTSTATUS gensec_gse_wrap(struct gensec_security *gensec_security,
1028                                 TALLOC_CTX *mem_ctx,
1029                                 const DATA_BLOB *in,
1030                                 DATA_BLOB *out)
1031 {
1032         struct gse_context *gse_ctx =
1033                 talloc_get_type_abort(gensec_security->private_data,
1034                 struct gse_context);
1035         OM_uint32 maj_stat, min_stat;
1036         gss_buffer_desc input_token, output_token;
1037         int conf_state;
1038         input_token.length = in->length;
1039         input_token.value = in->data;
1040
1041         maj_stat = gss_wrap(&min_stat,
1042                             gse_ctx->gssapi_context,
1043                             gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL),
1044                             GSS_C_QOP_DEFAULT,
1045                             &input_token,
1046                             &conf_state,
1047                             &output_token);
1048         if (GSS_ERROR(maj_stat)) {
1049                 DEBUG(0, ("gensec_gse_wrap: GSS Wrap failed: %s\n",
1050                           gse_errstr(talloc_tos(), maj_stat, min_stat)));
1051                 return NT_STATUS_ACCESS_DENIED;
1052         }
1053
1054         *out = data_blob_talloc(mem_ctx, output_token.value, output_token.length);
1055         gss_release_buffer(&min_stat, &output_token);
1056
1057         if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)
1058             && !conf_state) {
1059                 return NT_STATUS_ACCESS_DENIED;
1060         }
1061         return NT_STATUS_OK;
1062 }
1063
1064 static NTSTATUS gensec_gse_unwrap(struct gensec_security *gensec_security,
1065                                      TALLOC_CTX *mem_ctx,
1066                                      const DATA_BLOB *in,
1067                                      DATA_BLOB *out)
1068 {
1069         struct gse_context *gse_ctx =
1070                 talloc_get_type_abort(gensec_security->private_data,
1071                 struct gse_context);
1072         OM_uint32 maj_stat, min_stat;
1073         gss_buffer_desc input_token, output_token;
1074         int conf_state;
1075         gss_qop_t qop_state;
1076         input_token.length = in->length;
1077         input_token.value = in->data;
1078
1079         maj_stat = gss_unwrap(&min_stat,
1080                               gse_ctx->gssapi_context,
1081                               &input_token,
1082                               &output_token,
1083                               &conf_state,
1084                               &qop_state);
1085         if (GSS_ERROR(maj_stat)) {
1086                 DEBUG(0, ("gensec_gse_unwrap: GSS UnWrap failed: %s\n",
1087                           gse_errstr(talloc_tos(), maj_stat, min_stat)));
1088                 return NT_STATUS_ACCESS_DENIED;
1089         }
1090
1091         *out = data_blob_talloc(mem_ctx, output_token.value, output_token.length);
1092         gss_release_buffer(&min_stat, &output_token);
1093
1094         if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)
1095             && !conf_state) {
1096                 return NT_STATUS_ACCESS_DENIED;
1097         }
1098         return NT_STATUS_OK;
1099 }
1100
1101 static NTSTATUS gensec_gse_seal_packet(struct gensec_security *gensec_security,
1102                                        TALLOC_CTX *mem_ctx,
1103                                        uint8_t *data, size_t length,
1104                                        const uint8_t *whole_pdu, size_t pdu_length,
1105                                        DATA_BLOB *sig)
1106 {
1107         struct gse_context *gse_ctx =
1108                 talloc_get_type_abort(gensec_security->private_data,
1109                 struct gse_context);
1110         DATA_BLOB payload = data_blob_const(data, length);
1111         return gse_seal(mem_ctx, gse_ctx, &payload, sig);
1112 }
1113
1114 static NTSTATUS gensec_gse_unseal_packet(struct gensec_security *gensec_security,
1115                                          uint8_t *data, size_t length,
1116                                          const uint8_t *whole_pdu, size_t pdu_length,
1117                                          const DATA_BLOB *sig)
1118 {
1119         struct gse_context *gse_ctx =
1120                 talloc_get_type_abort(gensec_security->private_data,
1121                 struct gse_context);
1122         DATA_BLOB payload = data_blob_const(data, length);
1123         return gse_unseal(talloc_tos() /* unused */, gse_ctx, &payload, sig);
1124 }
1125
1126 static NTSTATUS gensec_gse_sign_packet(struct gensec_security *gensec_security,
1127                                        TALLOC_CTX *mem_ctx,
1128                                        const uint8_t *data, size_t length,
1129                                        const uint8_t *whole_pdu, size_t pdu_length,
1130                                        DATA_BLOB *sig)
1131 {
1132         struct gse_context *gse_ctx =
1133                 talloc_get_type_abort(gensec_security->private_data,
1134                 struct gse_context);
1135         DATA_BLOB payload = data_blob_const(data, length);
1136         return gse_sign(mem_ctx, gse_ctx, &payload, sig);
1137 }
1138
1139 static NTSTATUS gensec_gse_check_packet(struct gensec_security *gensec_security,
1140                                         const uint8_t *data, size_t length,
1141                                         const uint8_t *whole_pdu, size_t pdu_length,
1142                                         const DATA_BLOB *sig)
1143 {
1144         struct gse_context *gse_ctx =
1145                 talloc_get_type_abort(gensec_security->private_data,
1146                 struct gse_context);
1147         DATA_BLOB payload = data_blob_const(data, length);
1148         return gse_sigcheck(NULL, gse_ctx, &payload, sig);
1149 }
1150
1151 /* Try to figure out what features we actually got on the connection */
1152 static bool gensec_gse_have_feature(struct gensec_security *gensec_security,
1153                                     uint32_t feature)
1154 {
1155         struct gse_context *gse_ctx =
1156                 talloc_get_type_abort(gensec_security->private_data,
1157                 struct gse_context);
1158
1159         if (feature & GENSEC_FEATURE_SIGN) {
1160                 return gse_ctx->gss_got_flags & GSS_C_INTEG_FLAG;
1161         }
1162         if (feature & GENSEC_FEATURE_SEAL) {
1163                 return gse_ctx->gss_got_flags & GSS_C_CONF_FLAG;
1164         }
1165         if (feature & GENSEC_FEATURE_SESSION_KEY) {
1166                 /* Only for GSE/Krb5 */
1167                 if (gss_oid_equal(gse_ctx->ret_mech, gss_mech_krb5)) {
1168                         return true;
1169                 }
1170         }
1171         if (feature & GENSEC_FEATURE_DCE_STYLE) {
1172                 return gse_ctx->gss_got_flags & GSS_C_DCE_STYLE;
1173         }
1174         if (feature & GENSEC_FEATURE_NEW_SPNEGO) {
1175                 NTSTATUS status;
1176
1177                 if (!(gse_ctx->gss_got_flags & GSS_C_INTEG_FLAG)) {
1178                         return false;
1179                 }
1180
1181                 status = gse_init_lucid(gse_ctx);
1182                 if (!NT_STATUS_IS_OK(status)) {
1183                         return false;
1184                 }
1185
1186                 if (gse_ctx->lucid->protocol == 1) {
1187                         return true;
1188                 }
1189
1190                 return false;
1191         }
1192         /* We can always do async (rather than strict request/reply) packets.  */
1193         if (feature & GENSEC_FEATURE_ASYNC_REPLIES) {
1194                 return true;
1195         }
1196         return false;
1197 }
1198
1199 /*
1200  * Extract the 'sesssion key' needed by SMB signing and ncacn_np
1201  * (for encrypting some passwords).
1202  *
1203  * This breaks all the abstractions, but what do you expect...
1204  */
1205 static NTSTATUS gensec_gse_session_key(struct gensec_security *gensec_security,
1206                                        TALLOC_CTX *mem_ctx,
1207                                        DATA_BLOB *session_key_out)
1208 {
1209         struct gse_context *gse_ctx =
1210                 talloc_get_type_abort(gensec_security->private_data,
1211                 struct gse_context);
1212
1213         DATA_BLOB session_key = gse_get_session_key(mem_ctx, gse_ctx);
1214         if (session_key.data == NULL) {
1215                 return NT_STATUS_NO_USER_SESSION_KEY;
1216         }
1217
1218         *session_key_out = session_key;
1219
1220         return NT_STATUS_OK;
1221 }
1222
1223 /* Get some basic (and authorization) information about the user on
1224  * this session.  This uses either the PAC (if present) or a local
1225  * database lookup */
1226 static NTSTATUS gensec_gse_session_info(struct gensec_security *gensec_security,
1227                                         TALLOC_CTX *mem_ctx,
1228                                         struct auth_session_info **_session_info)
1229 {
1230         struct gse_context *gse_ctx =
1231                 talloc_get_type_abort(gensec_security->private_data,
1232                 struct gse_context);
1233         NTSTATUS nt_status;
1234         TALLOC_CTX *tmp_ctx;
1235         struct auth_session_info *session_info = NULL;
1236         OM_uint32 maj_stat, min_stat;
1237         DATA_BLOB pac_blob, *pac_blob_ptr = NULL;
1238
1239         gss_buffer_desc name_token;
1240         char *principal_string;
1241
1242         tmp_ctx = talloc_named(mem_ctx, 0, "gensec_gse_session_info context");
1243         NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);
1244
1245         maj_stat = gss_display_name(&min_stat,
1246                                     gse_ctx->client_name,
1247                                     &name_token,
1248                                     NULL);
1249         if (GSS_ERROR(maj_stat)) {
1250                 DEBUG(1, ("GSS display_name failed: %s\n",
1251                           gse_errstr(talloc_tos(), maj_stat, min_stat)));
1252                 talloc_free(tmp_ctx);
1253                 return NT_STATUS_FOOBAR;
1254         }
1255
1256         principal_string = talloc_strndup(tmp_ctx,
1257                                           (const char *)name_token.value,
1258                                           name_token.length);
1259
1260         gss_release_buffer(&min_stat, &name_token);
1261
1262         if (!principal_string) {
1263                 talloc_free(tmp_ctx);
1264                 return NT_STATUS_NO_MEMORY;
1265         }
1266
1267         nt_status = gssapi_obtain_pac_blob(tmp_ctx,  gse_ctx->gssapi_context,
1268                                            gse_ctx->client_name,
1269                                            &pac_blob);
1270
1271         /* IF we have the PAC - otherwise we need to get this
1272          * data from elsewere
1273          */
1274         if (NT_STATUS_IS_OK(nt_status)) {
1275                 pac_blob_ptr = &pac_blob;
1276         }
1277         nt_status = gensec_generate_session_info_pac(tmp_ctx,
1278                                                      gensec_security,
1279                                                      NULL,
1280                                                      pac_blob_ptr, principal_string,
1281                                                      gensec_get_remote_address(gensec_security),
1282                                                      &session_info);
1283         if (!NT_STATUS_IS_OK(nt_status)) {
1284                 talloc_free(tmp_ctx);
1285                 return nt_status;
1286         }
1287
1288         nt_status = gensec_gse_session_key(gensec_security, session_info,
1289                                            &session_info->session_key);
1290         if (!NT_STATUS_IS_OK(nt_status)) {
1291                 talloc_free(tmp_ctx);
1292                 return nt_status;
1293         }
1294
1295         *_session_info = talloc_move(mem_ctx, &session_info);
1296         talloc_free(tmp_ctx);
1297
1298         return NT_STATUS_OK;
1299 }
1300
1301 static size_t gensec_gse_sig_size(struct gensec_security *gensec_security,
1302                                   size_t data_size)
1303 {
1304         struct gse_context *gse_ctx =
1305                 talloc_get_type_abort(gensec_security->private_data,
1306                 struct gse_context);
1307
1308         return gse_get_signature_length(gse_ctx,
1309                                         gensec_security->want_features & GENSEC_FEATURE_SEAL,
1310                                         data_size);
1311 }
1312
1313 static const char *gensec_gse_krb5_oids[] = {
1314         GENSEC_OID_KERBEROS5_OLD,
1315         GENSEC_OID_KERBEROS5,
1316         NULL
1317 };
1318
1319 const struct gensec_security_ops gensec_gse_krb5_security_ops = {
1320         .name           = "gse_krb5",
1321         .auth_type      = DCERPC_AUTH_TYPE_KRB5,
1322         .oid            = gensec_gse_krb5_oids,
1323         .client_start   = gensec_gse_client_start,
1324         .server_start   = gensec_gse_server_start,
1325         .magic          = gensec_gse_magic,
1326         .update         = gensec_gse_update,
1327         .session_key    = gensec_gse_session_key,
1328         .session_info   = gensec_gse_session_info,
1329         .sig_size       = gensec_gse_sig_size,
1330         .sign_packet    = gensec_gse_sign_packet,
1331         .check_packet   = gensec_gse_check_packet,
1332         .seal_packet    = gensec_gse_seal_packet,
1333         .unseal_packet  = gensec_gse_unseal_packet,
1334         .wrap           = gensec_gse_wrap,
1335         .unwrap         = gensec_gse_unwrap,
1336         .have_feature   = gensec_gse_have_feature,
1337         .enabled        = true,
1338         .kerberos       = true,
1339         .priority       = GENSEC_GSSAPI
1340 };
1341
1342 #endif /* HAVE_KRB5 && HAVE_GSS_WRAP_IOV */