s3-gse Make seal parameter a boolean for clarity
[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         krb5_context k5ctx;
74         krb5_ccache ccache;
75         krb5_keytab keytab;
76
77         gss_ctx_id_t gss_ctx;
78
79         gss_OID_desc gss_mech;
80         OM_uint32 gss_c_flags;
81         gss_cred_id_t creds;
82         gss_name_t server_name;
83
84         gss_OID ret_mech;
85         OM_uint32 ret_flags;
86         gss_cred_id_t delegated_creds;
87         gss_name_t client_name;
88
89         bool more_processing;
90         bool authenticated;
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->gss_ctx != GSS_C_NO_CONTEXT) {
131                 gss_maj = gss_delete_sec_context(&gss_min,
132                                                  &gse_ctx->gss_ctx,
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_creds) {
148                 gss_maj = gss_release_cred(&gss_min,
149                                            &gse_ctx->delegated_creds);
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_c_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_c_flags |= GSS_C_INTEG_FLAG;
192         }
193         if (do_seal) {
194                 gse_ctx->gss_c_flags |= GSS_C_CONF_FLAG;
195         }
196
197         gse_ctx->gss_c_flags |= add_gss_c_flags;
198
199         /* Initialize Kerberos Context */
200         initialize_krb5_error_table();
201
202         k5ret = krb5_init_context(&gse_ctx->k5ctx);
203         if (k5ret) {
204                 DEBUG(0, ("Failed to initialize kerberos context! (%s)\n",
205                           error_message(k5ret)));
206                 status = NT_STATUS_INTERNAL_ERROR;
207                 goto err_out;
208         }
209
210         if (!ccache_name) {
211                 ccache_name = krb5_cc_default_name(gse_ctx->k5ctx);
212         }
213         k5ret = krb5_cc_resolve(gse_ctx->k5ctx, ccache_name,
214                                 &gse_ctx->ccache);
215         if (k5ret) {
216                 DEBUG(1, ("Failed to resolve credential cache! (%s)\n",
217                           error_message(k5ret)));
218                 status = NT_STATUS_INTERNAL_ERROR;
219                 goto err_out;
220         }
221
222         /* TODO: Should we enforce a enc_types list ?
223         ret = krb5_set_default_tgs_ktypes(gse_ctx->k5ctx, enc_types);
224         */
225
226         *_gse_ctx = gse_ctx;
227         return NT_STATUS_OK;
228
229 err_out:
230         TALLOC_FREE(gse_ctx);
231         return status;
232 }
233
234 static NTSTATUS gse_init_client(TALLOC_CTX *mem_ctx,
235                                 bool do_sign, bool do_seal,
236                                 const char *ccache_name,
237                                 const char *server,
238                                 const char *service,
239                                 const char *username,
240                                 const char *password,
241                                 uint32_t add_gss_c_flags,
242                                 struct gse_context **_gse_ctx)
243 {
244         struct gse_context *gse_ctx;
245         OM_uint32 gss_maj, gss_min;
246         gss_buffer_desc name_buffer = {0, NULL};
247         gss_OID_set_desc mech_set;
248         NTSTATUS status;
249
250         if (!server || !service) {
251                 return NT_STATUS_INVALID_PARAMETER;
252         }
253
254         status = gse_context_init(mem_ctx, do_sign, do_seal,
255                                   ccache_name, add_gss_c_flags,
256                                   &gse_ctx);
257         if (!NT_STATUS_IS_OK(status)) {
258                 return NT_STATUS_NO_MEMORY;
259         }
260
261         /* Guess the realm based on the supplied service, and avoid the GSS libs
262            doing DNS lookups which may fail.
263
264            TODO: Loop with the KDC on some more combinations (local
265            realm in particular), possibly falling back to
266            GSS_C_NT_HOSTBASED_SERVICE
267         */
268         name_buffer.value = kerberos_get_principal_from_service_hostname(gse_ctx,
269                                                                          service, server);
270         if (!name_buffer.value) {
271                 status = NT_STATUS_NO_MEMORY;
272                 goto err_out;
273         }
274         name_buffer.length = strlen((char *)name_buffer.value);
275         gss_maj = gss_import_name(&gss_min, &name_buffer,
276                                   GSS_C_NT_USER_NAME,
277                                   &gse_ctx->server_name);
278         if (gss_maj) {
279                 DEBUG(0, ("gss_import_name failed for %s, with [%s]\n",
280                           (char *)name_buffer.value,
281                           gse_errstr(gse_ctx, gss_maj, gss_min)));
282                 status = NT_STATUS_INTERNAL_ERROR;
283                 goto err_out;
284         }
285
286         /* TODO: get krb5 ticket using username/password, if no valid
287          * one already available in ccache */
288
289         mech_set.count = 1;
290         mech_set.elements = &gse_ctx->gss_mech;
291
292         gss_maj = gss_acquire_cred(&gss_min,
293                                    GSS_C_NO_NAME,
294                                    GSS_C_INDEFINITE,
295                                    &mech_set,
296                                    GSS_C_INITIATE,
297                                    &gse_ctx->creds,
298                                    NULL, NULL);
299         if (gss_maj) {
300                 DEBUG(0, ("gss_acquire_creds failed for %s, with [%s]\n",
301                           (char *)name_buffer.value,
302                           gse_errstr(gse_ctx, gss_maj, gss_min)));
303                 status = NT_STATUS_INTERNAL_ERROR;
304                 goto err_out;
305         }
306
307         *_gse_ctx = gse_ctx;
308         TALLOC_FREE(name_buffer.value);
309         return NT_STATUS_OK;
310
311 err_out:
312         TALLOC_FREE(name_buffer.value);
313         TALLOC_FREE(gse_ctx);
314         return status;
315 }
316
317 static NTSTATUS gse_get_client_auth_token(TALLOC_CTX *mem_ctx,
318                                           struct gse_context *gse_ctx,
319                                           const DATA_BLOB *token_in,
320                                           DATA_BLOB *token_out)
321 {
322         OM_uint32 gss_maj, gss_min;
323         gss_buffer_desc in_data;
324         gss_buffer_desc out_data;
325         DATA_BLOB blob = data_blob_null;
326         NTSTATUS status;
327
328         in_data.value = token_in->data;
329         in_data.length = token_in->length;
330
331         gss_maj = gss_init_sec_context(&gss_min,
332                                         gse_ctx->creds,
333                                         &gse_ctx->gss_ctx,
334                                         gse_ctx->server_name,
335                                         &gse_ctx->gss_mech,
336                                         gse_ctx->gss_c_flags,
337                                         0, GSS_C_NO_CHANNEL_BINDINGS,
338                                         &in_data, NULL, &out_data,
339                                         &gse_ctx->ret_flags, NULL);
340         switch (gss_maj) {
341         case GSS_S_COMPLETE:
342                 /* we are done with it */
343                 gse_ctx->more_processing = false;
344                 status = NT_STATUS_OK;
345                 break;
346         case GSS_S_CONTINUE_NEEDED:
347                 /* we will need a third leg */
348                 gse_ctx->more_processing = true;
349                 /* status = NT_STATUS_MORE_PROCESSING_REQUIRED; */
350                 status = NT_STATUS_OK;
351                 break;
352         default:
353                 DEBUG(0, ("gss_init_sec_context failed with [%s]\n",
354                           gse_errstr(talloc_tos(), gss_maj, gss_min)));
355                 status = NT_STATUS_INTERNAL_ERROR;
356                 goto done;
357         }
358
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 done:
367         *token_out = blob;
368         return status;
369 }
370
371 static NTSTATUS gse_init_server(TALLOC_CTX *mem_ctx,
372                                 bool do_sign, bool do_seal,
373                                 uint32_t add_gss_c_flags,
374                                 struct gse_context **_gse_ctx)
375 {
376         struct gse_context *gse_ctx;
377         OM_uint32 gss_maj, gss_min;
378         krb5_error_code ret;
379         NTSTATUS status;
380
381         status = gse_context_init(mem_ctx, do_sign, do_seal,
382                                   NULL, add_gss_c_flags, &gse_ctx);
383         if (!NT_STATUS_IS_OK(status)) {
384                 return NT_STATUS_NO_MEMORY;
385         }
386
387         ret = gse_krb5_get_server_keytab(gse_ctx->k5ctx,
388                                          &gse_ctx->keytab);
389         if (ret) {
390                 status = NT_STATUS_INTERNAL_ERROR;
391                 goto done;
392         }
393
394 #ifdef HAVE_GSS_KRB5_IMPORT_CRED
395
396         /* This creates a GSSAPI cred_id_t with the keytab set */
397         gss_maj = gss_krb5_import_cred(&gss_min, NULL, NULL, gse_ctx->keytab, 
398                                        &gse_ctx->creds);
399
400         if (gss_maj != 0
401             && gss_maj != (GSS_S_CALL_BAD_STRUCTURE|GSS_S_BAD_NAME)) {
402                 DEBUG(0, ("gss_krb5_import_cred failed with [%s]\n",
403                           gse_errstr(gse_ctx, gss_maj, gss_min)));
404                 status = NT_STATUS_INTERNAL_ERROR;
405                 goto done;
406
407                 /* This is the error the MIT krb5 1.9 gives when it
408                  * implements the function, but we do not specify the
409                  * principal.  However, when we specify the principal
410                  * as host$@REALM the GSS acceptor fails with 'wrong
411                  * principal in request'.  Work around the issue by
412                  * falling back to the alternate approach below. */
413         } else if (gss_maj == (GSS_S_CALL_BAD_STRUCTURE|GSS_S_BAD_NAME))
414 #endif
415         /* FIXME!!!
416          * This call sets the default keytab for the whole server, not
417          * just for this context. Need to find a way that does not alter
418          * the state of the whole server ... */
419         {
420                 const char *ktname;
421                 gss_OID_set_desc mech_set;
422
423                 ret = smb_krb5_keytab_name(gse_ctx, gse_ctx->k5ctx,
424                                    gse_ctx->keytab, &ktname);
425                 if (ret) {
426                         status = NT_STATUS_INTERNAL_ERROR;
427                         goto done;
428                 }
429
430                 ret = gsskrb5_register_acceptor_identity(ktname);
431                 if (ret) {
432                         status = NT_STATUS_INTERNAL_ERROR;
433                         goto done;
434                 }
435
436                 mech_set.count = 1;
437                 mech_set.elements = &gse_ctx->gss_mech;
438
439                 gss_maj = gss_acquire_cred(&gss_min,
440                                    GSS_C_NO_NAME,
441                                    GSS_C_INDEFINITE,
442                                    &mech_set,
443                                    GSS_C_ACCEPT,
444                                    &gse_ctx->creds,
445                                    NULL, NULL);
446
447                 if (gss_maj) {
448                         DEBUG(0, ("gss_acquire_creds failed with [%s]\n",
449                                   gse_errstr(gse_ctx, gss_maj, gss_min)));
450                         status = NT_STATUS_INTERNAL_ERROR;
451                         goto done;
452                 }
453         }
454
455         status = NT_STATUS_OK;
456
457 done:
458         if (!NT_STATUS_IS_OK(status)) {
459                 TALLOC_FREE(gse_ctx);
460         }
461
462         *_gse_ctx = gse_ctx;
463         return status;
464 }
465
466 static NTSTATUS gse_get_server_auth_token(TALLOC_CTX *mem_ctx,
467                                           struct gse_context *gse_ctx,
468                                           const DATA_BLOB *token_in,
469                                           DATA_BLOB *token_out)
470 {
471         OM_uint32 gss_maj, gss_min;
472         gss_buffer_desc in_data;
473         gss_buffer_desc out_data;
474         DATA_BLOB blob = data_blob_null;
475         NTSTATUS status;
476
477         in_data.value = token_in->data;
478         in_data.length = token_in->length;
479
480         gss_maj = gss_accept_sec_context(&gss_min,
481                                          &gse_ctx->gss_ctx,
482                                          gse_ctx->creds,
483                                          &in_data,
484                                          GSS_C_NO_CHANNEL_BINDINGS,
485                                          &gse_ctx->client_name,
486                                          &gse_ctx->ret_mech,
487                                          &out_data,
488                                          &gse_ctx->ret_flags, NULL,
489                                          &gse_ctx->delegated_creds);
490         switch (gss_maj) {
491         case GSS_S_COMPLETE:
492                 /* we are done with it */
493                 gse_ctx->more_processing = false;
494                 gse_ctx->authenticated = true;
495                 status = NT_STATUS_OK;
496                 break;
497         case GSS_S_CONTINUE_NEEDED:
498                 /* we will need a third leg */
499                 gse_ctx->more_processing = true;
500                 /* status = NT_STATUS_MORE_PROCESSING_REQUIRED; */
501                 status = NT_STATUS_OK;
502                 break;
503         default:
504                 DEBUG(0, ("gss_init_sec_context failed with [%s]\n",
505                           gse_errstr(talloc_tos(), gss_maj, gss_min)));
506
507                 if (gse_ctx->gss_ctx) {
508                         gss_delete_sec_context(&gss_min,
509                                                 &gse_ctx->gss_ctx,
510                                                 GSS_C_NO_BUFFER);
511                 }
512
513                 status = NT_STATUS_INTERNAL_ERROR;
514                 goto done;
515         }
516
517         /* we may be told to return nothing */
518         if (out_data.length) {
519                 blob = data_blob_talloc(mem_ctx, out_data.value, out_data.length);
520                 if (!blob.data) {
521                         status = NT_STATUS_NO_MEMORY;
522                 }
523                 gss_maj = gss_release_buffer(&gss_min, &out_data);
524         }
525
526
527 done:
528         *token_out = blob;
529         return status;
530 }
531
532 static NTSTATUS gse_verify_server_auth_flags(struct gse_context *gse_ctx)
533 {
534         if (!gse_ctx->authenticated) {
535                 return NT_STATUS_INVALID_HANDLE;
536         }
537
538         if (memcmp(gse_ctx->ret_mech,
539                    gss_mech_krb5, sizeof(gss_OID_desc)) != 0) {
540                 return NT_STATUS_ACCESS_DENIED;
541         }
542
543         /* GSS_C_MUTUAL_FLAG */
544         if (gse_ctx->gss_c_flags & GSS_C_MUTUAL_FLAG) {
545                 if (!(gse_ctx->ret_flags & GSS_C_MUTUAL_FLAG)) {
546                         return NT_STATUS_ACCESS_DENIED;
547                 }
548         }
549
550         /* GSS_C_DELEG_FLAG */
551         /* GSS_C_DELEG_POLICY_FLAG */
552         /* GSS_C_REPLAY_FLAG */
553         /* GSS_C_SEQUENCE_FLAG */
554
555         /* GSS_C_INTEG_FLAG */
556         if (gse_ctx->gss_c_flags & GSS_C_INTEG_FLAG) {
557                 if (!(gse_ctx->ret_flags & GSS_C_INTEG_FLAG)) {
558                         return NT_STATUS_ACCESS_DENIED;
559                 }
560         }
561
562         /* GSS_C_CONF_FLAG */
563         if (gse_ctx->gss_c_flags & GSS_C_CONF_FLAG) {
564                 if (!(gse_ctx->ret_flags & GSS_C_CONF_FLAG)) {
565                         return NT_STATUS_ACCESS_DENIED;
566                 }
567         }
568
569         return NT_STATUS_OK;
570 }
571
572 static char *gse_errstr(TALLOC_CTX *mem_ctx, OM_uint32 maj, OM_uint32 min)
573 {
574         OM_uint32 gss_min, gss_maj;
575         gss_buffer_desc msg_min;
576         gss_buffer_desc msg_maj;
577         OM_uint32 msg_ctx = 0;
578
579         char *errstr = NULL;
580
581         ZERO_STRUCT(msg_min);
582         ZERO_STRUCT(msg_maj);
583
584         gss_maj = gss_display_status(&gss_min, maj, GSS_C_GSS_CODE,
585                                      GSS_C_NO_OID, &msg_ctx, &msg_maj);
586         if (gss_maj) {
587                 goto done;
588         }
589         errstr = talloc_strndup(mem_ctx,
590                                 (char *)msg_maj.value,
591                                         msg_maj.length);
592         if (!errstr) {
593                 goto done;
594         }
595         gss_maj = gss_display_status(&gss_min, min, GSS_C_MECH_CODE,
596                                      (gss_OID)discard_const(gss_mech_krb5),
597                                      &msg_ctx, &msg_min);
598         if (gss_maj) {
599                 goto done;
600         }
601
602         errstr = talloc_strdup_append_buffer(errstr, ": ");
603         if (!errstr) {
604                 goto done;
605         }
606         errstr = talloc_strndup_append_buffer(errstr,
607                                                 (char *)msg_min.value,
608                                                         msg_min.length);
609         if (!errstr) {
610                 goto done;
611         }
612
613 done:
614         if (msg_min.value) {
615                 gss_maj = gss_release_buffer(&gss_min, &msg_min);
616         }
617         if (msg_maj.value) {
618                 gss_maj = gss_release_buffer(&gss_min, &msg_maj);
619         }
620         return errstr;
621 }
622
623 static DATA_BLOB gse_get_session_key(TALLOC_CTX *mem_ctx,
624                                      struct gse_context *gse_ctx)
625 {
626         OM_uint32 gss_min, gss_maj;
627         gss_buffer_set_t set = GSS_C_NO_BUFFER_SET;
628         DATA_BLOB ret;
629
630         gss_maj = gss_inquire_sec_context_by_oid(
631                                 &gss_min, gse_ctx->gss_ctx,
632                                 &gse_sesskey_inq_oid, &set);
633         if (gss_maj) {
634                 DEBUG(0, ("gss_inquire_sec_context_by_oid failed [%s]\n",
635                           gse_errstr(talloc_tos(), gss_maj, gss_min)));
636                 return data_blob_null;
637         }
638
639         if ((set == GSS_C_NO_BUFFER_SET) ||
640             (set->count != 2) ||
641             (memcmp(set->elements[1].value,
642                     gse_sesskeytype_oid.elements,
643                     gse_sesskeytype_oid.length) != 0)) {
644 #ifdef HAVE_GSSKRB5_GET_SUBKEY
645                 krb5_keyblock *subkey;
646                 gss_maj = gsskrb5_get_subkey(&gss_min,
647                                              gse_ctx->gss_ctx,
648                                              &subkey);
649                 if (gss_maj != 0) {
650                         DEBUG(1, ("NO session key for this mech\n"));
651                         return data_blob_null;
652                 }
653                 ret = data_blob_talloc(mem_ctx,
654                                        KRB5_KEY_DATA(subkey), KRB5_KEY_LENGTH(subkey));
655                 krb5_free_keyblock(NULL /* should be krb5_context */, subkey);
656                 return ret;
657 #else
658                 DEBUG(0, ("gss_inquire_sec_context_by_oid returned unknown "
659                           "OID for data in results:\n"));
660                 dump_data(1, (uint8_t *)set->elements[1].value,
661                              set->elements[1].length);
662                 return data_blob_null;
663 #endif
664         }
665
666         ret = data_blob_talloc(mem_ctx, set->elements[0].value,
667                                         set->elements[0].length);
668
669         gss_maj = gss_release_buffer_set(&gss_min, &set);
670         return ret;
671 }
672
673 static size_t gse_get_signature_length(struct gse_context *gse_ctx,
674                                        bool seal, size_t payload_size)
675 {
676         OM_uint32 gss_min, gss_maj;
677         gss_iov_buffer_desc iov[2];
678         uint8_t fakebuf[payload_size];
679         int sealed;
680
681         iov[0].type = GSS_IOV_BUFFER_TYPE_HEADER;
682         iov[0].buffer.value = NULL;
683         iov[0].buffer.length = 0;
684         iov[1].type = GSS_IOV_BUFFER_TYPE_DATA;
685         iov[1].buffer.value = fakebuf;
686         iov[1].buffer.length = payload_size;
687
688         gss_maj = gss_wrap_iov_length(&gss_min, gse_ctx->gss_ctx,
689                                         seal, GSS_C_QOP_DEFAULT,
690                                         &sealed, iov, 2);
691         if (gss_maj) {
692                 DEBUG(0, ("gss_wrap_iov_length failed with [%s]\n",
693                           gse_errstr(talloc_tos(), gss_maj, gss_min)));
694                 return 0;
695         }
696
697         return iov[0].buffer.length;
698 }
699
700 static NTSTATUS gse_seal(TALLOC_CTX *mem_ctx, struct gse_context *gse_ctx,
701                          DATA_BLOB *data, DATA_BLOB *signature)
702 {
703         OM_uint32 gss_min, gss_maj;
704         gss_iov_buffer_desc iov[2];
705         int req_seal = 1; /* setting to 1 means we request sign+seal */
706         int sealed = 1;
707         NTSTATUS status;
708
709         /* allocate the memory ourselves so we do not need to talloc_memdup */
710         signature->length = gse_get_signature_length(gse_ctx, true, data->length);
711         if (!signature->length) {
712                 return NT_STATUS_INTERNAL_ERROR;
713         }
714         signature->data = (uint8_t *)talloc_size(mem_ctx, signature->length);
715         if (!signature->data) {
716                 return NT_STATUS_NO_MEMORY;
717         }
718         iov[0].type = GSS_IOV_BUFFER_TYPE_HEADER;
719         iov[0].buffer.value = signature->data;
720         iov[0].buffer.length = signature->length;
721
722         /* data is encrypted in place, which is ok */
723         iov[1].type = GSS_IOV_BUFFER_TYPE_DATA;
724         iov[1].buffer.value = data->data;
725         iov[1].buffer.length = data->length;
726
727         gss_maj = gss_wrap_iov(&gss_min, gse_ctx->gss_ctx,
728                                 req_seal, GSS_C_QOP_DEFAULT,
729                                 &sealed, iov, 2);
730         if (gss_maj) {
731                 DEBUG(0, ("gss_wrap_iov failed with [%s]\n",
732                           gse_errstr(talloc_tos(), gss_maj, gss_min)));
733                 status = NT_STATUS_ACCESS_DENIED;
734                 goto done;
735         }
736
737         if (!sealed) {
738                 DEBUG(0, ("gss_wrap_iov says data was not sealed!\n"));
739                 status = NT_STATUS_ACCESS_DENIED;
740                 goto done;
741         }
742
743         status = NT_STATUS_OK;
744
745         DEBUG(10, ("Sealed %d bytes, and got %d bytes header/signature.\n",
746                    (int)iov[1].buffer.length, (int)iov[0].buffer.length));
747
748 done:
749         return status;
750 }
751
752 static NTSTATUS gse_unseal(TALLOC_CTX *mem_ctx, struct gse_context *gse_ctx,
753                            DATA_BLOB *data, const DATA_BLOB *signature)
754 {
755         OM_uint32 gss_min, gss_maj;
756         gss_iov_buffer_desc iov[2];
757         int sealed;
758         NTSTATUS status;
759
760         iov[0].type = GSS_IOV_BUFFER_TYPE_HEADER;
761         iov[0].buffer.value = signature->data;
762         iov[0].buffer.length = signature->length;
763
764         /* data is decrypted in place, which is ok */
765         iov[1].type = GSS_IOV_BUFFER_TYPE_DATA;
766         iov[1].buffer.value = data->data;
767         iov[1].buffer.length = data->length;
768
769         gss_maj = gss_unwrap_iov(&gss_min, gse_ctx->gss_ctx,
770                                  &sealed, NULL, iov, 2);
771         if (gss_maj) {
772                 DEBUG(0, ("gss_unwrap_iov failed with [%s]\n",
773                           gse_errstr(talloc_tos(), gss_maj, gss_min)));
774                 status = NT_STATUS_ACCESS_DENIED;
775                 goto done;
776         }
777
778         if (!sealed) {
779                 DEBUG(0, ("gss_unwrap_iov says data is not sealed!\n"));
780                 status = NT_STATUS_ACCESS_DENIED;
781                 goto done;
782         }
783
784         status = NT_STATUS_OK;
785
786         DEBUG(10, ("Unsealed %d bytes, with %d bytes header/signature.\n",
787                    (int)iov[1].buffer.length, (int)iov[0].buffer.length));
788
789 done:
790         return status;
791 }
792
793 static NTSTATUS gse_sign(TALLOC_CTX *mem_ctx, struct gse_context *gse_ctx,
794                          DATA_BLOB *data, DATA_BLOB *signature)
795 {
796         OM_uint32 gss_min, gss_maj;
797         gss_buffer_desc in_data = { 0, NULL };
798         gss_buffer_desc out_data = { 0, NULL};
799         NTSTATUS status;
800
801         in_data.value = data->data;
802         in_data.length = data->length;
803
804         gss_maj = gss_get_mic(&gss_min, gse_ctx->gss_ctx,
805                               GSS_C_QOP_DEFAULT,
806                               &in_data, &out_data);
807         if (gss_maj) {
808                 DEBUG(0, ("gss_get_mic failed with [%s]\n",
809                           gse_errstr(talloc_tos(), gss_maj, gss_min)));
810                 status = NT_STATUS_ACCESS_DENIED;
811                 goto done;
812         }
813
814         *signature = data_blob_talloc(mem_ctx,
815                                         out_data.value, out_data.length);
816         if (!signature->data) {
817                 status = NT_STATUS_NO_MEMORY;
818                 goto done;
819         }
820
821         status = NT_STATUS_OK;
822
823 done:
824         if (out_data.value) {
825                 gss_maj = gss_release_buffer(&gss_min, &out_data);
826         }
827         return status;
828 }
829
830 static NTSTATUS gse_sigcheck(TALLOC_CTX *mem_ctx, struct gse_context *gse_ctx,
831                              const DATA_BLOB *data, const DATA_BLOB *signature)
832 {
833         OM_uint32 gss_min, gss_maj;
834         gss_buffer_desc in_data = { 0, NULL };
835         gss_buffer_desc in_token = { 0, NULL};
836         NTSTATUS status;
837
838         in_data.value = data->data;
839         in_data.length = data->length;
840         in_token.value = signature->data;
841         in_token.length = signature->length;
842
843         gss_maj = gss_verify_mic(&gss_min, gse_ctx->gss_ctx,
844                                  &in_data, &in_token, NULL);
845         if (gss_maj) {
846                 DEBUG(0, ("gss_verify_mic failed with [%s]\n",
847                           gse_errstr(talloc_tos(), gss_maj, gss_min)));
848                 status = NT_STATUS_ACCESS_DENIED;
849                 goto done;
850         }
851
852         status = NT_STATUS_OK;
853
854 done:
855         return status;
856 }
857
858 static NTSTATUS gensec_gse_client_start(struct gensec_security *gensec_security)
859 {
860         struct gse_context *gse_ctx;
861         struct cli_credentials *creds = gensec_get_credentials(gensec_security);
862         NTSTATUS nt_status;
863         OM_uint32 want_flags = 0;
864         bool do_sign = false, do_seal = false;
865         const char *hostname = gensec_get_target_hostname(gensec_security);
866         const char *service = gensec_get_target_service(gensec_security);
867         const char *username = cli_credentials_get_username(creds);
868         const char *password = cli_credentials_get_password(creds);
869
870         if (!hostname) {
871                 DEBUG(1, ("Could not determine hostname for target computer, cannot use kerberos\n"));
872                 return NT_STATUS_INVALID_PARAMETER;
873         }
874         if (is_ipaddress(hostname)) {
875                 DEBUG(2, ("Cannot do GSE to an IP address\n"));
876                 return NT_STATUS_INVALID_PARAMETER;
877         }
878         if (strcmp(hostname, "localhost") == 0) {
879                 DEBUG(2, ("GSE to 'localhost' does not make sense\n"));
880                 return NT_STATUS_INVALID_PARAMETER;
881         }
882
883         if (gensec_security->want_features & GENSEC_FEATURE_SIGN) {
884                 do_sign = true;
885         }
886         if (gensec_security->want_features & GENSEC_FEATURE_SEAL) {
887                 do_seal = true;
888         }
889         if (gensec_security->want_features & GENSEC_FEATURE_DCE_STYLE) {
890                 want_flags |= GSS_C_DCE_STYLE;
891         }
892
893         nt_status = gse_init_client(gensec_security, do_sign, do_seal, NULL,
894                                     hostname, service,
895                                     username, password, want_flags,
896                                     &gse_ctx);
897         if (!NT_STATUS_IS_OK(nt_status)) {
898                 return nt_status;
899         }
900         gensec_security->private_data = gse_ctx;
901         return NT_STATUS_OK;
902 }
903
904 static NTSTATUS gensec_gse_server_start(struct gensec_security *gensec_security)
905 {
906         struct gse_context *gse_ctx;
907         NTSTATUS nt_status;
908         OM_uint32 want_flags = 0;
909         bool do_sign = false, do_seal = false;
910
911         if (gensec_security->want_features & GENSEC_FEATURE_SIGN) {
912                 do_sign = true;
913         }
914         if (gensec_security->want_features & GENSEC_FEATURE_SEAL) {
915                 do_seal = true;
916         }
917         if (gensec_security->want_features & GENSEC_FEATURE_DCE_STYLE) {
918                 want_flags |= GSS_C_DCE_STYLE;
919         }
920
921         nt_status = gse_init_server(gensec_security, do_sign, do_seal, want_flags,
922                                     &gse_ctx);
923         if (!NT_STATUS_IS_OK(nt_status)) {
924                 return nt_status;
925         }
926         gensec_security->private_data = gse_ctx;
927         return NT_STATUS_OK;
928 }
929
930 /**
931  * Check if the packet is one for this mechansim
932  *
933  * @param gensec_security GENSEC state
934  * @param in The request, as a DATA_BLOB
935  * @return Error, INVALID_PARAMETER if it's not a packet for us
936  *                or NT_STATUS_OK if the packet is ok.
937  */
938
939 static NTSTATUS gensec_gse_magic(struct gensec_security *gensec_security,
940                                  const DATA_BLOB *in)
941 {
942         if (gensec_gssapi_check_oid(in, GENSEC_OID_KERBEROS5)) {
943                 return NT_STATUS_OK;
944         } else {
945                 return NT_STATUS_INVALID_PARAMETER;
946         }
947 }
948
949
950 /**
951  * Next state function for the GSE GENSEC mechanism
952  *
953  * @param gensec_gse_state GSE State
954  * @param mem_ctx The TALLOC_CTX for *out to be allocated on
955  * @param in The request, as a DATA_BLOB
956  * @param out The reply, as an talloc()ed DATA_BLOB, on *mem_ctx
957  * @return Error, MORE_PROCESSING_REQUIRED if a reply is sent,
958  *                or NT_STATUS_OK if the user is authenticated.
959  */
960
961 static NTSTATUS gensec_gse_update(struct gensec_security *gensec_security,
962                                   TALLOC_CTX *mem_ctx,
963                                   struct tevent_context *ev,
964                                   const DATA_BLOB in, DATA_BLOB *out)
965 {
966         NTSTATUS status;
967         struct gse_context *gse_ctx =
968                 talloc_get_type_abort(gensec_security->private_data,
969                 struct gse_context);
970
971         switch (gensec_security->gensec_role) {
972         case GENSEC_CLIENT:
973                 status = gse_get_client_auth_token(mem_ctx, gse_ctx,
974                                                    &in, out);
975                 break;
976         case GENSEC_SERVER:
977                 status = gse_get_server_auth_token(mem_ctx, gse_ctx,
978                                                    &in, out);
979                 break;
980         }
981         if (!NT_STATUS_IS_OK(status)) {
982                 return status;
983         }
984         if (gse_ctx->more_processing) {
985                 return NT_STATUS_MORE_PROCESSING_REQUIRED;
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->gss_ctx,
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->gss_ctx,
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->ret_flags & GSS_C_INTEG_FLAG;
1129         }
1130         if (feature & GENSEC_FEATURE_SEAL) {
1131                 return gse_ctx->ret_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->ret_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->gss_ctx,
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 */