fba2c2fba377f8fa7a0ab8e0c341deb041ef1251
[samba.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 #include "lib/util/asn1.h"
32
33 #if defined(HAVE_KRB5) && defined(HAVE_GSS_WRAP_IOV)
34
35 #include "smb_krb5.h"
36 #include "gse_krb5.h"
37
38 #ifndef GSS_C_DCE_STYLE
39 #define GSS_C_DCE_STYLE 0x1000
40 #endif
41
42 #ifndef GSS_KRB5_INQ_SSPI_SESSION_KEY_OID
43 #define GSS_KRB5_INQ_SSPI_SESSION_KEY_OID_LENGTH 11
44 #define GSS_KRB5_INQ_SSPI_SESSION_KEY_OID "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x05"
45 #endif
46
47 gss_OID_desc gse_sesskey_inq_oid = {
48         GSS_KRB5_INQ_SSPI_SESSION_KEY_OID_LENGTH,
49         (void *)GSS_KRB5_INQ_SSPI_SESSION_KEY_OID
50 };
51
52 #ifndef GSS_KRB5_SESSION_KEY_ENCTYPE_OID
53 #define GSS_KRB5_SESSION_KEY_ENCTYPE_OID_LENGTH 10
54 #define GSS_KRB5_SESSION_KEY_ENCTYPE_OID  "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x04"
55 #endif
56
57 gss_OID_desc gse_sesskeytype_oid = {
58         GSS_KRB5_SESSION_KEY_ENCTYPE_OID_LENGTH,
59         (void *)GSS_KRB5_SESSION_KEY_ENCTYPE_OID
60 };
61
62 #define GSE_EXTRACT_RELEVANT_AUTHZ_DATA_OID_LENGTH 12
63 /*                                          EXTRACTION OID                                 AUTHZ ID */
64 #define GSE_EXTRACT_RELEVANT_AUTHZ_DATA_OID "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x0a" "\x01"
65
66 gss_OID_desc gse_authz_data_oid = {
67         GSE_EXTRACT_RELEVANT_AUTHZ_DATA_OID_LENGTH,
68         (void *)GSE_EXTRACT_RELEVANT_AUTHZ_DATA_OID
69 };
70
71 static char *gse_errstr(TALLOC_CTX *mem_ctx, OM_uint32 maj, OM_uint32 min);
72
73 struct gse_context {
74         gss_ctx_id_t gssapi_context;
75         gss_name_t server_name;
76         gss_name_t client_name;
77         OM_uint32 gss_want_flags, gss_got_flags;
78
79         gss_cred_id_t delegated_cred_handle;
80
81         /* gensec_gse only */
82         krb5_context k5ctx;
83         krb5_ccache ccache;
84         krb5_keytab keytab;
85
86         gss_OID_desc gss_mech;
87         gss_cred_id_t creds;
88
89         gss_OID ret_mech;
90 };
91
92 #ifndef HAVE_GSS_OID_EQUAL
93
94 static bool gss_oid_equal(const gss_OID o1, const gss_OID o2)
95 {
96         if (o1 == o2) {
97                 return true;
98         }
99         if ((o1 == NULL && o2 != NULL) || (o1 != NULL && o2 == NULL)) {
100                 return false;
101         }
102         if (o1->length != o2->length) {
103                 return false;
104         }
105         return memcmp(o1->elements, o2->elements, o1->length) == false;
106 }
107
108 #endif
109
110 /* free non talloc dependent contexts */
111 static int gse_context_destructor(void *ptr)
112 {
113         struct gse_context *gse_ctx;
114         OM_uint32 gss_min, gss_maj;
115
116         gse_ctx = talloc_get_type_abort(ptr, struct gse_context);
117         if (gse_ctx->k5ctx) {
118                 if (gse_ctx->ccache) {
119                         krb5_cc_close(gse_ctx->k5ctx, gse_ctx->ccache);
120                         gse_ctx->ccache = NULL;
121                 }
122                 if (gse_ctx->keytab) {
123                         krb5_kt_close(gse_ctx->k5ctx, gse_ctx->keytab);
124                         gse_ctx->keytab = NULL;
125                 }
126                 krb5_free_context(gse_ctx->k5ctx);
127                 gse_ctx->k5ctx = NULL;
128         }
129         if (gse_ctx->gssapi_context != GSS_C_NO_CONTEXT) {
130                 gss_maj = gss_delete_sec_context(&gss_min,
131                                                  &gse_ctx->gssapi_context,
132                                                  GSS_C_NO_BUFFER);
133         }
134         if (gse_ctx->server_name) {
135                 gss_maj = gss_release_name(&gss_min,
136                                            &gse_ctx->server_name);
137         }
138         if (gse_ctx->client_name) {
139                 gss_maj = gss_release_name(&gss_min,
140                                            &gse_ctx->client_name);
141         }
142         if (gse_ctx->creds) {
143                 gss_maj = gss_release_cred(&gss_min,
144                                            &gse_ctx->creds);
145         }
146         if (gse_ctx->delegated_cred_handle) {
147                 gss_maj = gss_release_cred(&gss_min,
148                                            &gse_ctx->delegated_cred_handle);
149         }
150
151         /* MIT and Heimdal differ as to if you can call
152          * gss_release_oid() on this OID, generated by
153          * gss_{accept,init}_sec_context().  However, as long as the
154          * oid is gss_mech_krb5 (which it always is at the moment),
155          * then this is a moot point, as both declare this particular
156          * OID static, and so no memory is lost.  This assert is in
157          * place to ensure that the programmer who wishes to extend
158          * this code to EAP or other GSS mechanisms determines an
159          * implementation-dependent way of releasing any dynamically
160          * allocated OID */
161         SMB_ASSERT(gss_oid_equal(&gse_ctx->gss_mech, GSS_C_NO_OID) || gss_oid_equal(&gse_ctx->gss_mech, gss_mech_krb5));
162
163         return 0;
164 }
165
166 static NTSTATUS gse_context_init(TALLOC_CTX *mem_ctx,
167                                  bool do_sign, bool do_seal,
168                                  const char *ccache_name,
169                                  uint32_t add_gss_c_flags,
170                                  struct gse_context **_gse_ctx)
171 {
172         struct gse_context *gse_ctx;
173         krb5_error_code k5ret;
174         NTSTATUS status;
175
176         gse_ctx = talloc_zero(mem_ctx, struct gse_context);
177         if (!gse_ctx) {
178                 return NT_STATUS_NO_MEMORY;
179         }
180         talloc_set_destructor((TALLOC_CTX *)gse_ctx, gse_context_destructor);
181
182         memcpy(&gse_ctx->gss_mech, gss_mech_krb5, sizeof(gss_OID_desc));
183
184         gse_ctx->gss_want_flags = GSS_C_MUTUAL_FLAG |
185                                 GSS_C_DELEG_FLAG |
186                                 GSS_C_DELEG_POLICY_FLAG |
187                                 GSS_C_REPLAY_FLAG |
188                                 GSS_C_SEQUENCE_FLAG;
189         if (do_sign) {
190                 gse_ctx->gss_want_flags |= GSS_C_INTEG_FLAG;
191         }
192         if (do_seal) {
193                 gse_ctx->gss_want_flags |= GSS_C_INTEG_FLAG;
194                 gse_ctx->gss_want_flags |= GSS_C_CONF_FLAG;
195         }
196
197         gse_ctx->gss_want_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->gssapi_context,
334                                         gse_ctx->server_name,
335                                         &gse_ctx->gss_mech,
336                                         gse_ctx->gss_want_flags,
337                                         0, GSS_C_NO_CHANNEL_BINDINGS,
338                                         &in_data, NULL, &out_data,
339                                         &gse_ctx->gss_got_flags, NULL);
340         switch (gss_maj) {
341         case GSS_S_COMPLETE:
342                 /* we are done with it */
343                 status = NT_STATUS_OK;
344                 break;
345         case GSS_S_CONTINUE_NEEDED:
346                 /* we will need a third leg */
347                 status = NT_STATUS_MORE_PROCESSING_REQUIRED;
348                 break;
349         default:
350                 DEBUG(0, ("gss_init_sec_context failed with [%s]\n",
351                           gse_errstr(talloc_tos(), gss_maj, gss_min)));
352                 status = NT_STATUS_INTERNAL_ERROR;
353                 goto done;
354         }
355
356         /* we may be told to return nothing */
357         if (out_data.length) {
358                 blob = data_blob_talloc(mem_ctx, out_data.value, out_data.length);
359                 if (!blob.data) {
360                         status = NT_STATUS_NO_MEMORY;
361                 }
362
363                 gss_maj = gss_release_buffer(&gss_min, &out_data);
364         }
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->gssapi_context,
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->gss_got_flags, NULL,
489                                          &gse_ctx->delegated_cred_handle);
490         switch (gss_maj) {
491         case GSS_S_COMPLETE:
492                 /* we are done with it */
493                 status = NT_STATUS_OK;
494                 break;
495         case GSS_S_CONTINUE_NEEDED:
496                 /* we will need a third leg */
497                 status = NT_STATUS_MORE_PROCESSING_REQUIRED;
498                 break;
499         default:
500                 DEBUG(1, ("gss_init_sec_context failed with [%s]\n",
501                           gse_errstr(talloc_tos(), gss_maj, gss_min)));
502
503                 if (gse_ctx->gssapi_context) {
504                         gss_delete_sec_context(&gss_min,
505                                                 &gse_ctx->gssapi_context,
506                                                 GSS_C_NO_BUFFER);
507                 }
508
509                 status = NT_STATUS_LOGON_FAILURE;
510                 goto done;
511         }
512
513         /* we may be told to return nothing */
514         if (out_data.length) {
515                 blob = data_blob_talloc(mem_ctx, out_data.value, out_data.length);
516                 if (!blob.data) {
517                         status = NT_STATUS_NO_MEMORY;
518                 }
519                 gss_maj = gss_release_buffer(&gss_min, &out_data);
520         }
521
522
523 done:
524         *token_out = blob;
525         return status;
526 }
527
528 static char *gse_errstr(TALLOC_CTX *mem_ctx, OM_uint32 maj, OM_uint32 min)
529 {
530         OM_uint32 gss_min, gss_maj;
531         gss_buffer_desc msg_min;
532         gss_buffer_desc msg_maj;
533         OM_uint32 msg_ctx = 0;
534
535         char *errstr = NULL;
536
537         ZERO_STRUCT(msg_min);
538         ZERO_STRUCT(msg_maj);
539
540         gss_maj = gss_display_status(&gss_min, maj, GSS_C_GSS_CODE,
541                                      GSS_C_NO_OID, &msg_ctx, &msg_maj);
542         if (gss_maj) {
543                 goto done;
544         }
545         errstr = talloc_strndup(mem_ctx,
546                                 (char *)msg_maj.value,
547                                         msg_maj.length);
548         if (!errstr) {
549                 goto done;
550         }
551         gss_maj = gss_display_status(&gss_min, min, GSS_C_MECH_CODE,
552                                      (gss_OID)discard_const(gss_mech_krb5),
553                                      &msg_ctx, &msg_min);
554         if (gss_maj) {
555                 goto done;
556         }
557
558         errstr = talloc_strdup_append_buffer(errstr, ": ");
559         if (!errstr) {
560                 goto done;
561         }
562         errstr = talloc_strndup_append_buffer(errstr,
563                                                 (char *)msg_min.value,
564                                                         msg_min.length);
565         if (!errstr) {
566                 goto done;
567         }
568
569 done:
570         if (msg_min.value) {
571                 gss_maj = gss_release_buffer(&gss_min, &msg_min);
572         }
573         if (msg_maj.value) {
574                 gss_maj = gss_release_buffer(&gss_min, &msg_maj);
575         }
576         return errstr;
577 }
578
579 static NTSTATUS gse_get_session_key(TALLOC_CTX *mem_ctx,
580                                     struct gse_context *gse_ctx, 
581                                     DATA_BLOB *session_key, 
582                                     uint32_t *keytype)
583 {
584         OM_uint32 gss_min, gss_maj;
585         gss_buffer_set_t set = GSS_C_NO_BUFFER_SET;
586
587         gss_maj = gss_inquire_sec_context_by_oid(
588                                 &gss_min, gse_ctx->gssapi_context,
589                                 &gse_sesskey_inq_oid, &set);
590         if (gss_maj) {
591                 DEBUG(0, ("gss_inquire_sec_context_by_oid failed [%s]\n",
592                           gse_errstr(talloc_tos(), gss_maj, gss_min)));
593                 return NT_STATUS_NO_USER_SESSION_KEY;
594         }
595
596         if ((set == GSS_C_NO_BUFFER_SET) ||
597             (set->count != 2) ||
598             (memcmp(set->elements[1].value,
599                     gse_sesskeytype_oid.elements,
600                     gse_sesskeytype_oid.length) != 0)) {
601 #ifdef HAVE_GSSKRB5_GET_SUBKEY
602                 krb5_keyblock *subkey;
603                 gss_maj = gsskrb5_get_subkey(&gss_min,
604                                              gse_ctx->gssapi_context,
605                                              &subkey);
606                 if (gss_maj != 0) {
607                         DEBUG(1, ("NO session key for this mech\n"));
608                         return NT_STATUS_NO_USER_SESSION_KEY;
609                 }
610                 if (session_key) {
611                         *session_key = data_blob_talloc(mem_ctx,
612                                                         KRB5_KEY_DATA(subkey), KRB5_KEY_LENGTH(subkey));
613                 }
614                 if (keytype) {
615                         *keytype = KRB5_KEY_TYPE(subkey);
616                 }
617                 krb5_free_keyblock(NULL /* should be krb5_context */, subkey);
618                 return NT_STATUS_OK;
619 #else
620                 DEBUG(0, ("gss_inquire_sec_context_by_oid returned unknown "
621                           "OID for data in results:\n"));
622                 dump_data(1, (uint8_t *)set->elements[1].value,
623                              set->elements[1].length);
624                 return NT_STATUS_NO_USER_SESSION_KEY;
625 #endif
626         }
627
628         if (session_key) {
629                 *session_key = data_blob_talloc(mem_ctx, set->elements[0].value,
630                                                 set->elements[0].length);
631         }
632
633         if (keytype) {
634                 char *oid;
635                 char *p, *q = NULL;
636                 if (!ber_read_OID_String(talloc_tos(), 
637                                          data_blob_const(set->elements[0].value,
638                                                          set->elements[0].length), &oid)) {
639                         TALLOC_FREE(oid);
640                         gss_maj = gss_release_buffer_set(&gss_min, &set);
641                         return NT_STATUS_INVALID_PARAMETER;
642                 }
643                 p = strrchr(oid, '.');
644                 if (!p) {
645                         TALLOC_FREE(oid);
646                         gss_maj = gss_release_buffer_set(&gss_min, &set);
647                         return NT_STATUS_INVALID_PARAMETER;
648                 } else {
649                         p++;
650                         *keytype = strtoul(p, &q, 10);
651                         if (q == NULL || *q != '\0') {
652                                 return NT_STATUS_INVALID_PARAMETER;
653                         }
654                 }
655                 TALLOC_FREE(oid);
656         }
657         
658         gss_maj = gss_release_buffer_set(&gss_min, &set);
659         return NT_STATUS_OK;
660 }
661
662 static size_t gse_get_signature_length(struct gse_context *gse_ctx,
663                                        bool seal, size_t payload_size)
664 {
665         OM_uint32 gss_min, gss_maj;
666         gss_iov_buffer_desc iov[2];
667         int sealed;
668
669         /*
670          * gss_wrap_iov_length() only needs the type and length
671          */
672         iov[0].type = GSS_IOV_BUFFER_TYPE_HEADER;
673         iov[0].buffer.value = NULL;
674         iov[0].buffer.length = 0;
675         iov[1].type = GSS_IOV_BUFFER_TYPE_DATA;
676         iov[1].buffer.value = NULL;
677         iov[1].buffer.length = payload_size;
678
679         gss_maj = gss_wrap_iov_length(&gss_min, gse_ctx->gssapi_context,
680                                         seal, GSS_C_QOP_DEFAULT,
681                                         &sealed, iov, 2);
682         if (gss_maj) {
683                 DEBUG(0, ("gss_wrap_iov_length failed with [%s]\n",
684                           gse_errstr(talloc_tos(), gss_maj, gss_min)));
685                 return 0;
686         }
687
688         return iov[0].buffer.length;
689 }
690
691 static NTSTATUS gse_seal(TALLOC_CTX *mem_ctx, struct gse_context *gse_ctx,
692                          DATA_BLOB *data, DATA_BLOB *signature)
693 {
694         OM_uint32 gss_min, gss_maj;
695         gss_iov_buffer_desc iov[2];
696         int req_seal = 1; /* setting to 1 means we request sign+seal */
697         int sealed = 1;
698         NTSTATUS status;
699
700         /* allocate the memory ourselves so we do not need to talloc_memdup */
701         signature->length = gse_get_signature_length(gse_ctx, true, data->length);
702         if (!signature->length) {
703                 return NT_STATUS_INTERNAL_ERROR;
704         }
705         signature->data = (uint8_t *)talloc_size(mem_ctx, signature->length);
706         if (!signature->data) {
707                 return NT_STATUS_NO_MEMORY;
708         }
709         iov[0].type = GSS_IOV_BUFFER_TYPE_HEADER;
710         iov[0].buffer.value = signature->data;
711         iov[0].buffer.length = signature->length;
712
713         /* data is encrypted in place, which is ok */
714         iov[1].type = GSS_IOV_BUFFER_TYPE_DATA;
715         iov[1].buffer.value = data->data;
716         iov[1].buffer.length = data->length;
717
718         gss_maj = gss_wrap_iov(&gss_min, gse_ctx->gssapi_context,
719                                 req_seal, GSS_C_QOP_DEFAULT,
720                                 &sealed, iov, 2);
721         if (gss_maj) {
722                 DEBUG(0, ("gss_wrap_iov failed with [%s]\n",
723                           gse_errstr(talloc_tos(), gss_maj, gss_min)));
724                 status = NT_STATUS_ACCESS_DENIED;
725                 goto done;
726         }
727
728         if (!sealed) {
729                 DEBUG(0, ("gss_wrap_iov says data was not sealed!\n"));
730                 status = NT_STATUS_ACCESS_DENIED;
731                 goto done;
732         }
733
734         status = NT_STATUS_OK;
735
736         DEBUG(10, ("Sealed %d bytes, and got %d bytes header/signature.\n",
737                    (int)iov[1].buffer.length, (int)iov[0].buffer.length));
738
739 done:
740         return status;
741 }
742
743 static NTSTATUS gse_unseal(TALLOC_CTX *mem_ctx, struct gse_context *gse_ctx,
744                            DATA_BLOB *data, const DATA_BLOB *signature)
745 {
746         OM_uint32 gss_min, gss_maj;
747         gss_iov_buffer_desc iov[2];
748         int sealed;
749         NTSTATUS status;
750
751         iov[0].type = GSS_IOV_BUFFER_TYPE_HEADER;
752         iov[0].buffer.value = signature->data;
753         iov[0].buffer.length = signature->length;
754
755         /* data is decrypted in place, which is ok */
756         iov[1].type = GSS_IOV_BUFFER_TYPE_DATA;
757         iov[1].buffer.value = data->data;
758         iov[1].buffer.length = data->length;
759
760         gss_maj = gss_unwrap_iov(&gss_min, gse_ctx->gssapi_context,
761                                  &sealed, NULL, iov, 2);
762         if (gss_maj) {
763                 DEBUG(0, ("gss_unwrap_iov failed with [%s]\n",
764                           gse_errstr(talloc_tos(), gss_maj, gss_min)));
765                 status = NT_STATUS_ACCESS_DENIED;
766                 goto done;
767         }
768
769         if (!sealed) {
770                 DEBUG(0, ("gss_unwrap_iov says data is not sealed!\n"));
771                 status = NT_STATUS_ACCESS_DENIED;
772                 goto done;
773         }
774
775         status = NT_STATUS_OK;
776
777         DEBUG(10, ("Unsealed %d bytes, with %d bytes header/signature.\n",
778                    (int)iov[1].buffer.length, (int)iov[0].buffer.length));
779
780 done:
781         return status;
782 }
783
784 static NTSTATUS gse_sign(TALLOC_CTX *mem_ctx, struct gse_context *gse_ctx,
785                          DATA_BLOB *data, DATA_BLOB *signature)
786 {
787         OM_uint32 gss_min, gss_maj;
788         gss_buffer_desc in_data = { 0, NULL };
789         gss_buffer_desc out_data = { 0, NULL};
790         NTSTATUS status;
791
792         in_data.value = data->data;
793         in_data.length = data->length;
794
795         gss_maj = gss_get_mic(&gss_min, gse_ctx->gssapi_context,
796                               GSS_C_QOP_DEFAULT,
797                               &in_data, &out_data);
798         if (gss_maj) {
799                 DEBUG(0, ("gss_get_mic failed with [%s]\n",
800                           gse_errstr(talloc_tos(), gss_maj, gss_min)));
801                 status = NT_STATUS_ACCESS_DENIED;
802                 goto done;
803         }
804
805         *signature = data_blob_talloc(mem_ctx,
806                                         out_data.value, out_data.length);
807         if (!signature->data) {
808                 status = NT_STATUS_NO_MEMORY;
809                 goto done;
810         }
811
812         status = NT_STATUS_OK;
813
814 done:
815         if (out_data.value) {
816                 gss_maj = gss_release_buffer(&gss_min, &out_data);
817         }
818         return status;
819 }
820
821 static NTSTATUS gse_sigcheck(TALLOC_CTX *mem_ctx, struct gse_context *gse_ctx,
822                              const DATA_BLOB *data, const DATA_BLOB *signature)
823 {
824         OM_uint32 gss_min, gss_maj;
825         gss_buffer_desc in_data = { 0, NULL };
826         gss_buffer_desc in_token = { 0, NULL};
827         NTSTATUS status;
828
829         in_data.value = data->data;
830         in_data.length = data->length;
831         in_token.value = signature->data;
832         in_token.length = signature->length;
833
834         gss_maj = gss_verify_mic(&gss_min, gse_ctx->gssapi_context,
835                                  &in_data, &in_token, NULL);
836         if (gss_maj) {
837                 DEBUG(0, ("gss_verify_mic failed with [%s]\n",
838                           gse_errstr(talloc_tos(), gss_maj, gss_min)));
839                 status = NT_STATUS_ACCESS_DENIED;
840                 goto done;
841         }
842
843         status = NT_STATUS_OK;
844
845 done:
846         return status;
847 }
848
849 static NTSTATUS gensec_gse_client_start(struct gensec_security *gensec_security)
850 {
851         struct gse_context *gse_ctx;
852         struct cli_credentials *creds = gensec_get_credentials(gensec_security);
853         NTSTATUS nt_status;
854         OM_uint32 want_flags = 0;
855         bool do_sign = false, do_seal = false;
856         const char *hostname = gensec_get_target_hostname(gensec_security);
857         const char *service = gensec_get_target_service(gensec_security);
858         const char *username = cli_credentials_get_username(creds);
859         const char *password = cli_credentials_get_password(creds);
860
861         if (!hostname) {
862                 DEBUG(1, ("Could not determine hostname for target computer, cannot use kerberos\n"));
863                 return NT_STATUS_INVALID_PARAMETER;
864         }
865         if (is_ipaddress(hostname)) {
866                 DEBUG(2, ("Cannot do GSE to an IP address\n"));
867                 return NT_STATUS_INVALID_PARAMETER;
868         }
869         if (strcmp(hostname, "localhost") == 0) {
870                 DEBUG(2, ("GSE to 'localhost' does not make sense\n"));
871                 return NT_STATUS_INVALID_PARAMETER;
872         }
873
874         if (gensec_security->want_features & GENSEC_FEATURE_SIGN) {
875                 do_sign = true;
876         }
877         if (gensec_security->want_features & GENSEC_FEATURE_SEAL) {
878                 do_seal = true;
879         }
880         if (gensec_security->want_features & GENSEC_FEATURE_DCE_STYLE) {
881                 want_flags |= GSS_C_DCE_STYLE;
882         }
883
884         nt_status = gse_init_client(gensec_security, do_sign, do_seal, NULL,
885                                     hostname, service,
886                                     username, password, want_flags,
887                                     &gse_ctx);
888         if (!NT_STATUS_IS_OK(nt_status)) {
889                 return nt_status;
890         }
891         gensec_security->private_data = gse_ctx;
892         return NT_STATUS_OK;
893 }
894
895 static NTSTATUS gensec_gse_server_start(struct gensec_security *gensec_security)
896 {
897         struct gse_context *gse_ctx;
898         NTSTATUS nt_status;
899         OM_uint32 want_flags = 0;
900         bool do_sign = false, do_seal = false;
901
902         if (gensec_security->want_features & GENSEC_FEATURE_SIGN) {
903                 do_sign = true;
904         }
905         if (gensec_security->want_features & GENSEC_FEATURE_SEAL) {
906                 do_seal = true;
907         }
908         if (gensec_security->want_features & GENSEC_FEATURE_DCE_STYLE) {
909                 want_flags |= GSS_C_DCE_STYLE;
910         }
911
912         nt_status = gse_init_server(gensec_security, do_sign, do_seal, want_flags,
913                                     &gse_ctx);
914         if (!NT_STATUS_IS_OK(nt_status)) {
915                 return nt_status;
916         }
917         gensec_security->private_data = gse_ctx;
918         return NT_STATUS_OK;
919 }
920
921 /**
922  * Check if the packet is one for this mechansim
923  *
924  * @param gensec_security GENSEC state
925  * @param in The request, as a DATA_BLOB
926  * @return Error, INVALID_PARAMETER if it's not a packet for us
927  *                or NT_STATUS_OK if the packet is ok.
928  */
929
930 static NTSTATUS gensec_gse_magic(struct gensec_security *gensec_security,
931                                  const DATA_BLOB *in)
932 {
933         if (gensec_gssapi_check_oid(in, GENSEC_OID_KERBEROS5)) {
934                 return NT_STATUS_OK;
935         } else {
936                 return NT_STATUS_INVALID_PARAMETER;
937         }
938 }
939
940
941 /**
942  * Next state function for the GSE GENSEC mechanism
943  *
944  * @param gensec_gse_state GSE State
945  * @param mem_ctx The TALLOC_CTX for *out to be allocated on
946  * @param in The request, as a DATA_BLOB
947  * @param out The reply, as an talloc()ed DATA_BLOB, on *mem_ctx
948  * @return Error, MORE_PROCESSING_REQUIRED if a reply is sent,
949  *                or NT_STATUS_OK if the user is authenticated.
950  */
951
952 static NTSTATUS gensec_gse_update(struct gensec_security *gensec_security,
953                                   TALLOC_CTX *mem_ctx,
954                                   struct tevent_context *ev,
955                                   const DATA_BLOB in, DATA_BLOB *out)
956 {
957         NTSTATUS status;
958         struct gse_context *gse_ctx =
959                 talloc_get_type_abort(gensec_security->private_data,
960                 struct gse_context);
961
962         switch (gensec_security->gensec_role) {
963         case GENSEC_CLIENT:
964                 status = gse_get_client_auth_token(mem_ctx, gse_ctx,
965                                                    &in, out);
966                 break;
967         case GENSEC_SERVER:
968                 status = gse_get_server_auth_token(mem_ctx, gse_ctx,
969                                                    &in, out);
970                 break;
971         }
972         if (!NT_STATUS_IS_OK(status)) {
973                 return status;
974         }
975
976         return NT_STATUS_OK;
977 }
978
979 static NTSTATUS gensec_gse_wrap(struct gensec_security *gensec_security,
980                                 TALLOC_CTX *mem_ctx,
981                                 const DATA_BLOB *in,
982                                 DATA_BLOB *out)
983 {
984         struct gse_context *gse_ctx =
985                 talloc_get_type_abort(gensec_security->private_data,
986                 struct gse_context);
987         OM_uint32 maj_stat, min_stat;
988         gss_buffer_desc input_token, output_token;
989         int conf_state;
990         input_token.length = in->length;
991         input_token.value = in->data;
992
993         maj_stat = gss_wrap(&min_stat,
994                             gse_ctx->gssapi_context,
995                             gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL),
996                             GSS_C_QOP_DEFAULT,
997                             &input_token,
998                             &conf_state,
999                             &output_token);
1000         if (GSS_ERROR(maj_stat)) {
1001                 DEBUG(0, ("gensec_gse_wrap: GSS Wrap failed: %s\n",
1002                           gse_errstr(talloc_tos(), maj_stat, min_stat)));
1003                 return NT_STATUS_ACCESS_DENIED;
1004         }
1005
1006         *out = data_blob_talloc(mem_ctx, output_token.value, output_token.length);
1007         gss_release_buffer(&min_stat, &output_token);
1008
1009         if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)
1010             && !conf_state) {
1011                 return NT_STATUS_ACCESS_DENIED;
1012         }
1013         return NT_STATUS_OK;
1014 }
1015
1016 static NTSTATUS gensec_gse_unwrap(struct gensec_security *gensec_security,
1017                                      TALLOC_CTX *mem_ctx,
1018                                      const DATA_BLOB *in,
1019                                      DATA_BLOB *out)
1020 {
1021         struct gse_context *gse_ctx =
1022                 talloc_get_type_abort(gensec_security->private_data,
1023                 struct gse_context);
1024         OM_uint32 maj_stat, min_stat;
1025         gss_buffer_desc input_token, output_token;
1026         int conf_state;
1027         gss_qop_t qop_state;
1028         input_token.length = in->length;
1029         input_token.value = in->data;
1030
1031         maj_stat = gss_unwrap(&min_stat,
1032                               gse_ctx->gssapi_context,
1033                               &input_token,
1034                               &output_token,
1035                               &conf_state,
1036                               &qop_state);
1037         if (GSS_ERROR(maj_stat)) {
1038                 DEBUG(0, ("gensec_gse_unwrap: GSS UnWrap failed: %s\n",
1039                           gse_errstr(talloc_tos(), maj_stat, min_stat)));
1040                 return NT_STATUS_ACCESS_DENIED;
1041         }
1042
1043         *out = data_blob_talloc(mem_ctx, output_token.value, output_token.length);
1044         gss_release_buffer(&min_stat, &output_token);
1045
1046         if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)
1047             && !conf_state) {
1048                 return NT_STATUS_ACCESS_DENIED;
1049         }
1050         return NT_STATUS_OK;
1051 }
1052
1053 static NTSTATUS gensec_gse_seal_packet(struct gensec_security *gensec_security,
1054                                        TALLOC_CTX *mem_ctx,
1055                                        uint8_t *data, size_t length,
1056                                        const uint8_t *whole_pdu, size_t pdu_length,
1057                                        DATA_BLOB *sig)
1058 {
1059         struct gse_context *gse_ctx =
1060                 talloc_get_type_abort(gensec_security->private_data,
1061                 struct gse_context);
1062         DATA_BLOB payload = data_blob_const(data, length);
1063         return gse_seal(mem_ctx, gse_ctx, &payload, sig);
1064 }
1065
1066 static NTSTATUS gensec_gse_unseal_packet(struct gensec_security *gensec_security,
1067                                          uint8_t *data, size_t length,
1068                                          const uint8_t *whole_pdu, size_t pdu_length,
1069                                          const DATA_BLOB *sig)
1070 {
1071         struct gse_context *gse_ctx =
1072                 talloc_get_type_abort(gensec_security->private_data,
1073                 struct gse_context);
1074         DATA_BLOB payload = data_blob_const(data, length);
1075         return gse_unseal(talloc_tos() /* unused */, gse_ctx, &payload, sig);
1076 }
1077
1078 static NTSTATUS gensec_gse_sign_packet(struct gensec_security *gensec_security,
1079                                        TALLOC_CTX *mem_ctx,
1080                                        const uint8_t *data, size_t length,
1081                                        const uint8_t *whole_pdu, size_t pdu_length,
1082                                        DATA_BLOB *sig)
1083 {
1084         struct gse_context *gse_ctx =
1085                 talloc_get_type_abort(gensec_security->private_data,
1086                 struct gse_context);
1087         DATA_BLOB payload = data_blob_const(data, length);
1088         return gse_sign(mem_ctx, gse_ctx, &payload, sig);
1089 }
1090
1091 static NTSTATUS gensec_gse_check_packet(struct gensec_security *gensec_security,
1092                                         const uint8_t *data, size_t length,
1093                                         const uint8_t *whole_pdu, size_t pdu_length,
1094                                         const DATA_BLOB *sig)
1095 {
1096         struct gse_context *gse_ctx =
1097                 talloc_get_type_abort(gensec_security->private_data,
1098                 struct gse_context);
1099         DATA_BLOB payload = data_blob_const(data, length);
1100         return gse_sigcheck(NULL, gse_ctx, &payload, sig);
1101 }
1102
1103 /* Try to figure out what features we actually got on the connection */
1104 static bool gensec_gse_have_feature(struct gensec_security *gensec_security,
1105                                     uint32_t feature)
1106 {
1107         struct gse_context *gse_ctx =
1108                 talloc_get_type_abort(gensec_security->private_data,
1109                 struct gse_context);
1110
1111         if (feature & GENSEC_FEATURE_SIGN) {
1112                 return gse_ctx->gss_got_flags & GSS_C_INTEG_FLAG;
1113         }
1114         if (feature & GENSEC_FEATURE_SEAL) {
1115                 return gse_ctx->gss_got_flags & GSS_C_CONF_FLAG;
1116         }
1117         if (feature & GENSEC_FEATURE_SESSION_KEY) {
1118                 /* Only for GSE/Krb5 */
1119                 if (gss_oid_equal(gse_ctx->ret_mech, gss_mech_krb5)) {
1120                         return true;
1121                 }
1122         }
1123         if (feature & GENSEC_FEATURE_DCE_STYLE) {
1124                 return gse_ctx->gss_got_flags & GSS_C_DCE_STYLE;
1125         }
1126         if (feature & GENSEC_FEATURE_NEW_SPNEGO) {
1127                 NTSTATUS status;
1128                 uint32_t keytype;
1129
1130                 if (!(gse_ctx->gss_got_flags & GSS_C_INTEG_FLAG)) {
1131                         return false;
1132                 }
1133
1134                 status = gse_get_session_key(talloc_tos(), 
1135                                            gse_ctx, NULL, &keytype);
1136                 /* 
1137                  * We should do a proper sig on the mechListMic unless
1138                  * we know we have to be backwards compatible with
1139                  * earlier windows versions.  
1140                  * 
1141                  * Negotiating a non-krb5
1142                  * mech for example should be regarded as having
1143                  * NEW_SPNEGO
1144                  */
1145                 if (NT_STATUS_IS_OK(status)) {
1146                         switch (keytype) {
1147                         case ENCTYPE_DES_CBC_CRC:
1148                         case ENCTYPE_DES_CBC_MD5:
1149                         case ENCTYPE_ARCFOUR_HMAC:
1150                         case ENCTYPE_DES3_CBC_SHA1:
1151                                 return false;
1152                         }
1153                 }
1154                 return true;
1155         }
1156         /* We can always do async (rather than strict request/reply) packets.  */
1157         if (feature & GENSEC_FEATURE_ASYNC_REPLIES) {
1158                 return true;
1159         }
1160         return false;
1161 }
1162
1163 /*
1164  * Extract the 'sesssion key' needed by SMB signing and ncacn_np
1165  * (for encrypting some passwords).
1166  *
1167  * This breaks all the abstractions, but what do you expect...
1168  */
1169 static NTSTATUS gensec_gse_session_key(struct gensec_security *gensec_security,
1170                                        TALLOC_CTX *mem_ctx,
1171                                        DATA_BLOB *session_key)
1172 {
1173         struct gse_context *gse_ctx =
1174                 talloc_get_type_abort(gensec_security->private_data,
1175                 struct gse_context);
1176
1177         return gse_get_session_key(mem_ctx, gse_ctx, session_key, NULL);
1178 }
1179
1180 /* Get some basic (and authorization) information about the user on
1181  * this session.  This uses either the PAC (if present) or a local
1182  * database lookup */
1183 static NTSTATUS gensec_gse_session_info(struct gensec_security *gensec_security,
1184                                         TALLOC_CTX *mem_ctx,
1185                                         struct auth_session_info **_session_info)
1186 {
1187         struct gse_context *gse_ctx =
1188                 talloc_get_type_abort(gensec_security->private_data,
1189                 struct gse_context);
1190         NTSTATUS nt_status;
1191         TALLOC_CTX *tmp_ctx;
1192         struct auth_session_info *session_info = NULL;
1193         OM_uint32 maj_stat, min_stat;
1194         DATA_BLOB pac_blob, *pac_blob_ptr = NULL;
1195
1196         gss_buffer_desc name_token;
1197         char *principal_string;
1198
1199         tmp_ctx = talloc_named(mem_ctx, 0, "gensec_gse_session_info context");
1200         NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);
1201
1202         maj_stat = gss_display_name(&min_stat,
1203                                     gse_ctx->client_name,
1204                                     &name_token,
1205                                     NULL);
1206         if (GSS_ERROR(maj_stat)) {
1207                 DEBUG(1, ("GSS display_name failed: %s\n",
1208                           gse_errstr(talloc_tos(), maj_stat, min_stat)));
1209                 talloc_free(tmp_ctx);
1210                 return NT_STATUS_FOOBAR;
1211         }
1212
1213         principal_string = talloc_strndup(tmp_ctx,
1214                                           (const char *)name_token.value,
1215                                           name_token.length);
1216
1217         gss_release_buffer(&min_stat, &name_token);
1218
1219         if (!principal_string) {
1220                 talloc_free(tmp_ctx);
1221                 return NT_STATUS_NO_MEMORY;
1222         }
1223
1224         nt_status = gssapi_obtain_pac_blob(tmp_ctx,  gse_ctx->gssapi_context,
1225                                            gse_ctx->client_name,
1226                                            &pac_blob);
1227
1228         /* IF we have the PAC - otherwise we need to get this
1229          * data from elsewere
1230          */
1231         if (NT_STATUS_IS_OK(nt_status)) {
1232                 pac_blob_ptr = &pac_blob;
1233         }
1234         nt_status = gensec_generate_session_info_pac(tmp_ctx,
1235                                                      gensec_security,
1236                                                      NULL,
1237                                                      pac_blob_ptr, principal_string,
1238                                                      gensec_get_remote_address(gensec_security),
1239                                                      &session_info);
1240         if (!NT_STATUS_IS_OK(nt_status)) {
1241                 talloc_free(tmp_ctx);
1242                 return nt_status;
1243         }
1244
1245         nt_status = gensec_gse_session_key(gensec_security, session_info,
1246                                            &session_info->session_key);
1247         if (!NT_STATUS_IS_OK(nt_status)) {
1248                 talloc_free(tmp_ctx);
1249                 return nt_status;
1250         }
1251
1252         *_session_info = talloc_move(mem_ctx, &session_info);
1253         talloc_free(tmp_ctx);
1254
1255         return NT_STATUS_OK;
1256 }
1257
1258 static size_t gensec_gse_sig_size(struct gensec_security *gensec_security,
1259                                   size_t data_size)
1260 {
1261         struct gse_context *gse_ctx =
1262                 talloc_get_type_abort(gensec_security->private_data,
1263                 struct gse_context);
1264
1265         return gse_get_signature_length(gse_ctx,
1266                                         gensec_security->want_features & GENSEC_FEATURE_SEAL,
1267                                         data_size);
1268 }
1269
1270 static const char *gensec_gse_krb5_oids[] = {
1271         GENSEC_OID_KERBEROS5_OLD,
1272         GENSEC_OID_KERBEROS5,
1273         NULL
1274 };
1275
1276 const struct gensec_security_ops gensec_gse_krb5_security_ops = {
1277         .name           = "gse_krb5",
1278         .auth_type      = DCERPC_AUTH_TYPE_KRB5,
1279         .oid            = gensec_gse_krb5_oids,
1280         .client_start   = gensec_gse_client_start,
1281         .server_start   = gensec_gse_server_start,
1282         .magic          = gensec_gse_magic,
1283         .update         = gensec_gse_update,
1284         .session_key    = gensec_gse_session_key,
1285         .session_info   = gensec_gse_session_info,
1286         .sig_size       = gensec_gse_sig_size,
1287         .sign_packet    = gensec_gse_sign_packet,
1288         .check_packet   = gensec_gse_check_packet,
1289         .seal_packet    = gensec_gse_seal_packet,
1290         .unseal_packet  = gensec_gse_unseal_packet,
1291         .wrap           = gensec_gse_wrap,
1292         .unwrap         = gensec_gse_unwrap,
1293         .have_feature   = gensec_gse_have_feature,
1294         .enabled        = true,
1295         .kerberos       = true,
1296         .priority       = GENSEC_GSSAPI
1297 };
1298
1299 #endif /* HAVE_KRB5 && HAVE_GSS_WRAP_IOV */