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