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