s3-gse Use Heimdal gsskrb5_extract_authz_data_from_sec_context when available
[abartlet/samba.git/.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  *
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation; either version 3 of the License, or
9  *  (at your option) any later version.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, see <http://www.gnu.org/licenses/>.
18  */
19
20 /* We support only GSSAPI/KRB5 here */
21
22 #include "includes.h"
23 #include "gse.h"
24
25 #if defined(HAVE_KRB5) && defined(HAVE_GSS_WRAP_IOV)
26
27 #include "smb_krb5.h"
28 #include "gse_krb5.h"
29
30 #include <gssapi/gssapi.h>
31 #include <gssapi/gssapi_krb5.h>
32 #ifdef HAVE_GSSAPI_GSSAPI_EXT_H
33 #include <gssapi/gssapi_ext.h>
34 #endif
35
36 #ifndef GSS_KRB5_INQ_SSPI_SESSION_KEY_OID
37 #define GSS_KRB5_INQ_SSPI_SESSION_KEY_OID_LENGTH 11
38 #define GSS_KRB5_INQ_SSPI_SESSION_KEY_OID "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x05"
39 #endif
40
41 gss_OID_desc gse_sesskey_inq_oid = {
42         GSS_KRB5_INQ_SSPI_SESSION_KEY_OID_LENGTH,
43         (void *)GSS_KRB5_INQ_SSPI_SESSION_KEY_OID
44 };
45
46 #ifndef GSS_KRB5_SESSION_KEY_ENCTYPE_OID
47 #define GSS_KRB5_SESSION_KEY_ENCTYPE_OID_LENGTH 10
48 #define GSS_KRB5_SESSION_KEY_ENCTYPE_OID  "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x04"
49 #endif
50
51 gss_OID_desc gse_sesskeytype_oid = {
52         GSS_KRB5_SESSION_KEY_ENCTYPE_OID_LENGTH,
53         (void *)GSS_KRB5_SESSION_KEY_ENCTYPE_OID
54 };
55
56 #define GSE_EXTRACT_RELEVANT_AUTHZ_DATA_OID_LENGTH 12
57 /*                                          EXTRACTION OID                                 AUTHZ ID */
58 #define GSE_EXTRACT_RELEVANT_AUTHZ_DATA_OID "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x0a" "\x01"
59
60 gss_OID_desc gse_authz_data_oid = {
61         GSE_EXTRACT_RELEVANT_AUTHZ_DATA_OID_LENGTH,
62         (void *)GSE_EXTRACT_RELEVANT_AUTHZ_DATA_OID
63 };
64
65 #ifndef GSS_KRB5_EXTRACT_AUTHTIME_FROM_SEC_CONTEXT_OID
66 #define GSS_KRB5_EXTRACT_AUTHTIME_FROM_SEC_CONTEXT_OID_LENGTH 11
67 #define GSS_KRB5_EXTRACT_AUTHTIME_FROM_SEC_CONTEXT_OID "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x0c"
68 #endif
69
70 gss_OID_desc gse_authtime_oid = {
71         GSS_KRB5_EXTRACT_AUTHTIME_FROM_SEC_CONTEXT_OID_LENGTH,
72         (void *)GSS_KRB5_EXTRACT_AUTHTIME_FROM_SEC_CONTEXT_OID
73 };
74
75 static char *gse_errstr(TALLOC_CTX *mem_ctx, OM_uint32 maj, OM_uint32 min);
76
77 struct gse_context {
78         krb5_context k5ctx;
79         krb5_ccache ccache;
80         krb5_keytab keytab;
81
82         gss_ctx_id_t gss_ctx;
83
84         gss_OID_desc gss_mech;
85         OM_uint32 gss_c_flags;
86         gss_cred_id_t creds;
87         gss_name_t server_name;
88
89         gss_OID ret_mech;
90         OM_uint32 ret_flags;
91         gss_cred_id_t delegated_creds;
92         gss_name_t client_name;
93
94         bool more_processing;
95         bool authenticated;
96 };
97
98 /* free non talloc dependent contexts */
99 static int gse_context_destructor(void *ptr)
100 {
101         struct gse_context *gse_ctx;
102         OM_uint32 gss_min, gss_maj;
103
104         gse_ctx = talloc_get_type_abort(ptr, struct gse_context);
105         if (gse_ctx->k5ctx) {
106                 if (gse_ctx->ccache) {
107                         krb5_cc_close(gse_ctx->k5ctx, gse_ctx->ccache);
108                         gse_ctx->ccache = NULL;
109                 }
110                 if (gse_ctx->keytab) {
111                         krb5_kt_close(gse_ctx->k5ctx, gse_ctx->keytab);
112                         gse_ctx->keytab = NULL;
113                 }
114                 krb5_free_context(gse_ctx->k5ctx);
115                 gse_ctx->k5ctx = NULL;
116         }
117         if (gse_ctx->gss_ctx != GSS_C_NO_CONTEXT) {
118                 gss_maj = gss_delete_sec_context(&gss_min,
119                                                  &gse_ctx->gss_ctx,
120                                                  GSS_C_NO_BUFFER);
121         }
122         if (gse_ctx->server_name) {
123                 gss_maj = gss_release_name(&gss_min,
124                                            &gse_ctx->server_name);
125         }
126         if (gse_ctx->client_name) {
127                 gss_maj = gss_release_name(&gss_min,
128                                            &gse_ctx->client_name);
129         }
130         if (gse_ctx->creds) {
131                 gss_maj = gss_release_cred(&gss_min,
132                                            &gse_ctx->creds);
133         }
134         if (gse_ctx->delegated_creds) {
135                 gss_maj = gss_release_cred(&gss_min,
136                                            &gse_ctx->delegated_creds);
137         }
138         return 0;
139 }
140
141 static NTSTATUS gse_context_init(TALLOC_CTX *mem_ctx,
142                                  bool do_sign, bool do_seal,
143                                  const char *ccache_name,
144                                  uint32_t add_gss_c_flags,
145                                  struct gse_context **_gse_ctx)
146 {
147         struct gse_context *gse_ctx;
148         krb5_error_code k5ret;
149         NTSTATUS status;
150
151         gse_ctx = talloc_zero(mem_ctx, struct gse_context);
152         if (!gse_ctx) {
153                 return NT_STATUS_NO_MEMORY;
154         }
155         talloc_set_destructor((TALLOC_CTX *)gse_ctx, gse_context_destructor);
156
157         memcpy(&gse_ctx->gss_mech, gss_mech_krb5, sizeof(gss_OID_desc));
158
159         gse_ctx->gss_c_flags = GSS_C_MUTUAL_FLAG |
160                                 GSS_C_DELEG_FLAG |
161                                 GSS_C_DELEG_POLICY_FLAG |
162                                 GSS_C_REPLAY_FLAG |
163                                 GSS_C_SEQUENCE_FLAG;
164         if (do_sign) {
165                 gse_ctx->gss_c_flags |= GSS_C_INTEG_FLAG;
166         }
167         if (do_seal) {
168                 gse_ctx->gss_c_flags |= GSS_C_CONF_FLAG;
169         }
170
171         gse_ctx->gss_c_flags |= add_gss_c_flags;
172
173         /* Initialize Kerberos Context */
174         initialize_krb5_error_table();
175
176         k5ret = krb5_init_context(&gse_ctx->k5ctx);
177         if (k5ret) {
178                 DEBUG(0, ("Failed to initialize kerberos context! (%s)\n",
179                           error_message(k5ret)));
180                 status = NT_STATUS_INTERNAL_ERROR;
181                 goto err_out;
182         }
183
184         if (!ccache_name) {
185                 ccache_name = krb5_cc_default_name(gse_ctx->k5ctx);
186         }
187         k5ret = krb5_cc_resolve(gse_ctx->k5ctx, ccache_name,
188                                 &gse_ctx->ccache);
189         if (k5ret) {
190                 DEBUG(1, ("Failed to resolve credential cache! (%s)\n",
191                           error_message(k5ret)));
192                 status = NT_STATUS_INTERNAL_ERROR;
193                 goto err_out;
194         }
195
196         /* TODO: Should we enforce a enc_types list ?
197         ret = krb5_set_default_tgs_ktypes(gse_ctx->k5ctx, enc_types);
198         */
199
200         *_gse_ctx = gse_ctx;
201         return NT_STATUS_OK;
202
203 err_out:
204         TALLOC_FREE(gse_ctx);
205         return status;
206 }
207
208 NTSTATUS gse_init_client(TALLOC_CTX *mem_ctx,
209                           bool do_sign, bool do_seal,
210                           const char *ccache_name,
211                           const char *server,
212                           const char *service,
213                           const char *username,
214                           const char *password,
215                           uint32_t add_gss_c_flags,
216                           struct gse_context **_gse_ctx)
217 {
218         struct gse_context *gse_ctx;
219         OM_uint32 gss_maj, gss_min;
220         gss_buffer_desc name_buffer = {0, NULL};
221         gss_OID_set_desc mech_set;
222         NTSTATUS status;
223
224         if (!server || !service) {
225                 return NT_STATUS_INVALID_PARAMETER;
226         }
227
228         status = gse_context_init(mem_ctx, do_sign, do_seal,
229                                   ccache_name, add_gss_c_flags,
230                                   &gse_ctx);
231         if (!NT_STATUS_IS_OK(status)) {
232                 return NT_STATUS_NO_MEMORY;
233         }
234
235         name_buffer.value = talloc_asprintf(gse_ctx,
236                                             "%s@%s", service, server);
237         if (!name_buffer.value) {
238                 status = NT_STATUS_NO_MEMORY;
239                 goto err_out;
240         }
241         name_buffer.length = strlen((char *)name_buffer.value);
242         gss_maj = gss_import_name(&gss_min, &name_buffer,
243                                   GSS_C_NT_HOSTBASED_SERVICE,
244                                   &gse_ctx->server_name);
245         if (gss_maj) {
246                 DEBUG(0, ("gss_import_name failed for %s, with [%s]\n",
247                           (char *)name_buffer.value,
248                           gse_errstr(gse_ctx, gss_maj, gss_min)));
249                 status = NT_STATUS_INTERNAL_ERROR;
250                 goto err_out;
251         }
252
253         /* TODO: get krb5 ticket using username/password, if no valid
254          * one already available in ccache */
255
256         mech_set.count = 1;
257         mech_set.elements = &gse_ctx->gss_mech;
258
259         gss_maj = gss_acquire_cred(&gss_min,
260                                    GSS_C_NO_NAME,
261                                    GSS_C_INDEFINITE,
262                                    &mech_set,
263                                    GSS_C_INITIATE,
264                                    &gse_ctx->creds,
265                                    NULL, NULL);
266         if (gss_maj) {
267                 DEBUG(0, ("gss_acquire_creds failed for %s, with [%s]\n",
268                           (char *)name_buffer.value,
269                           gse_errstr(gse_ctx, gss_maj, gss_min)));
270                 status = NT_STATUS_INTERNAL_ERROR;
271                 goto err_out;
272         }
273
274         *_gse_ctx = gse_ctx;
275         TALLOC_FREE(name_buffer.value);
276         return NT_STATUS_OK;
277
278 err_out:
279         TALLOC_FREE(name_buffer.value);
280         TALLOC_FREE(gse_ctx);
281         return status;
282 }
283
284 NTSTATUS gse_get_client_auth_token(TALLOC_CTX *mem_ctx,
285                                    struct gse_context *gse_ctx,
286                                    DATA_BLOB *token_in,
287                                    DATA_BLOB *token_out)
288 {
289         OM_uint32 gss_maj, gss_min;
290         gss_buffer_desc in_data;
291         gss_buffer_desc out_data;
292         DATA_BLOB blob = data_blob_null;
293         NTSTATUS status;
294
295         in_data.value = token_in->data;
296         in_data.length = token_in->length;
297
298         gss_maj = gss_init_sec_context(&gss_min,
299                                         gse_ctx->creds,
300                                         &gse_ctx->gss_ctx,
301                                         gse_ctx->server_name,
302                                         &gse_ctx->gss_mech,
303                                         gse_ctx->gss_c_flags,
304                                         0, GSS_C_NO_CHANNEL_BINDINGS,
305                                         &in_data, NULL, &out_data,
306                                         NULL, NULL);
307         switch (gss_maj) {
308         case GSS_S_COMPLETE:
309                 /* we are done with it */
310                 gse_ctx->more_processing = false;
311                 status = NT_STATUS_OK;
312                 break;
313         case GSS_S_CONTINUE_NEEDED:
314                 /* we will need a third leg */
315                 gse_ctx->more_processing = true;
316                 /* status = NT_STATUS_MORE_PROCESSING_REQUIRED; */
317                 status = NT_STATUS_OK;
318                 break;
319         default:
320                 DEBUG(0, ("gss_init_sec_context failed with [%s]\n",
321                           gse_errstr(talloc_tos(), gss_maj, gss_min)));
322                 status = NT_STATUS_INTERNAL_ERROR;
323                 goto done;
324         }
325
326         blob = data_blob_talloc(mem_ctx, out_data.value, out_data.length);
327         if (!blob.data) {
328                 status = NT_STATUS_NO_MEMORY;
329         }
330
331         gss_maj = gss_release_buffer(&gss_min, &out_data);
332
333 done:
334         *token_out = blob;
335         return status;
336 }
337
338 NTSTATUS gse_init_server(TALLOC_CTX *mem_ctx,
339                          bool do_sign, bool do_seal,
340                          uint32_t add_gss_c_flags,
341                          struct gse_context **_gse_ctx)
342 {
343         struct gse_context *gse_ctx;
344         OM_uint32 gss_maj, gss_min;
345         krb5_error_code ret;
346         NTSTATUS status;
347         const char *ktname;
348
349         status = gse_context_init(mem_ctx, do_sign, do_seal,
350                                   NULL, add_gss_c_flags, &gse_ctx);
351         if (!NT_STATUS_IS_OK(status)) {
352                 return NT_STATUS_NO_MEMORY;
353         }
354
355         ret = gse_krb5_get_server_keytab(gse_ctx->k5ctx,
356                                          &gse_ctx->keytab);
357         if (ret) {
358                 status = NT_STATUS_INTERNAL_ERROR;
359                 goto done;
360         }
361
362 #ifdef HAVE_GSS_KRB5_IMPORT_CRED
363         /* This creates a GSSAPI cred_id_t with the principal and keytab set */
364         gss_maj = gss_krb5_import_cred(&gss_min, NULL, NULL, gse_ctx->keytab, 
365                                         &gse_ctx->creds);
366         if (gss_maj) {
367                 DEBUG(0, ("gss_krb5_import_cred failed with [%s]\n",
368                           gse_errstr(gse_ctx, gss_maj, gss_min)));
369                 status = NT_STATUS_INTERNAL_ERROR;
370                 goto done;
371         }
372 #else
373         /* FIXME!!!
374          * This call sets the default keytab for the whole server, not
375          * just for this context. Need to find a way that does not alter
376          * the state of the whole server ... */
377
378         ret = smb_krb5_keytab_name(gse_ctx, gse_ctx->k5ctx,
379                                    gse_ctx->keytab, &ktname);
380         if (ret) {
381                 status = NT_STATUS_INTERNAL_ERROR;
382                 goto done;
383         }
384
385         ret = gsskrb5_register_acceptor_identity(ktname);
386         if (ret) {
387                 status = NT_STATUS_INTERNAL_ERROR;
388                 goto done;
389         }
390
391         {
392                 gss_OID_set_desc mech_set;
393                 
394                 mech_set.count = 1;
395                 mech_set.elements = &gse_ctx->gss_mech;
396                 
397                 gss_maj = gss_acquire_cred(&gss_min,
398                                            GSS_C_NO_NAME,
399                                            GSS_C_INDEFINITE,
400                                            &mech_set,
401                                            GSS_C_ACCEPT,
402                                            &gse_ctx->creds,
403                                            NULL, NULL);
404         }
405
406         if (gss_maj) {
407                 DEBUG(0, ("gss_acquire_creds failed with [%s]\n",
408                           gse_errstr(gse_ctx, gss_maj, gss_min)));
409                 status = NT_STATUS_INTERNAL_ERROR;
410                 goto done;
411         }
412 #endif
413         status = NT_STATUS_OK;
414
415 done:
416         if (!NT_STATUS_IS_OK(status)) {
417                 TALLOC_FREE(gse_ctx);
418         }
419
420         *_gse_ctx = gse_ctx;
421         return status;
422 }
423
424 NTSTATUS gse_get_server_auth_token(TALLOC_CTX *mem_ctx,
425                                    struct gse_context *gse_ctx,
426                                    DATA_BLOB *token_in,
427                                    DATA_BLOB *token_out)
428 {
429         OM_uint32 gss_maj, gss_min;
430         gss_buffer_desc in_data;
431         gss_buffer_desc out_data;
432         DATA_BLOB blob = data_blob_null;
433         NTSTATUS status;
434
435         in_data.value = token_in->data;
436         in_data.length = token_in->length;
437
438         gss_maj = gss_accept_sec_context(&gss_min,
439                                          &gse_ctx->gss_ctx,
440                                          gse_ctx->creds,
441                                          &in_data,
442                                          GSS_C_NO_CHANNEL_BINDINGS,
443                                          &gse_ctx->client_name,
444                                          &gse_ctx->ret_mech,
445                                          &out_data,
446                                          &gse_ctx->ret_flags, NULL,
447                                          &gse_ctx->delegated_creds);
448         switch (gss_maj) {
449         case GSS_S_COMPLETE:
450                 /* we are done with it */
451                 gse_ctx->more_processing = false;
452                 gse_ctx->authenticated = true;
453                 status = NT_STATUS_OK;
454                 break;
455         case GSS_S_CONTINUE_NEEDED:
456                 /* we will need a third leg */
457                 gse_ctx->more_processing = true;
458                 /* status = NT_STATUS_MORE_PROCESSING_REQUIRED; */
459                 status = NT_STATUS_OK;
460                 break;
461         default:
462                 DEBUG(0, ("gss_init_sec_context failed with [%s]\n",
463                           gse_errstr(talloc_tos(), gss_maj, gss_min)));
464
465                 if (gse_ctx->gss_ctx) {
466                         gss_delete_sec_context(&gss_min,
467                                                 &gse_ctx->gss_ctx,
468                                                 GSS_C_NO_BUFFER);
469                 }
470
471                 status = NT_STATUS_INTERNAL_ERROR;
472                 goto done;
473         }
474
475         /* we may be told to return nothing */
476         if (out_data.length) {
477                 blob = data_blob_talloc(mem_ctx, out_data.value, out_data.length);
478                 if (!blob.data) {
479                         status = NT_STATUS_NO_MEMORY;
480                 }
481                 gss_maj = gss_release_buffer(&gss_min, &out_data);
482         }
483
484
485 done:
486         *token_out = blob;
487         return status;
488 }
489
490 NTSTATUS gse_verify_server_auth_flags(struct gse_context *gse_ctx)
491 {
492         if (!gse_ctx->authenticated) {
493                 return NT_STATUS_INVALID_HANDLE;
494         }
495
496         if (memcmp(gse_ctx->ret_mech,
497                    gss_mech_krb5, sizeof(gss_OID_desc)) != 0) {
498                 return NT_STATUS_ACCESS_DENIED;
499         }
500
501         /* GSS_C_MUTUAL_FLAG */
502         if (gse_ctx->gss_c_flags & GSS_C_MUTUAL_FLAG) {
503                 if (!(gse_ctx->ret_flags & GSS_C_MUTUAL_FLAG)) {
504                         return NT_STATUS_ACCESS_DENIED;
505                 }
506         }
507
508         /* GSS_C_DELEG_FLAG */
509         /* GSS_C_DELEG_POLICY_FLAG */
510         /* GSS_C_REPLAY_FLAG */
511         /* GSS_C_SEQUENCE_FLAG */
512
513         /* GSS_C_INTEG_FLAG */
514         if (gse_ctx->gss_c_flags & GSS_C_INTEG_FLAG) {
515                 if (!(gse_ctx->ret_flags & GSS_C_INTEG_FLAG)) {
516                         return NT_STATUS_ACCESS_DENIED;
517                 }
518         }
519
520         /* GSS_C_CONF_FLAG */
521         if (gse_ctx->gss_c_flags & GSS_C_CONF_FLAG) {
522                 if (!(gse_ctx->ret_flags & GSS_C_CONF_FLAG)) {
523                         return NT_STATUS_ACCESS_DENIED;
524                 }
525         }
526
527         return NT_STATUS_OK;
528 }
529
530 static char *gse_errstr(TALLOC_CTX *mem_ctx, OM_uint32 maj, OM_uint32 min)
531 {
532         OM_uint32 gss_min, gss_maj;
533         gss_buffer_desc msg_min;
534         gss_buffer_desc msg_maj;
535         OM_uint32 msg_ctx = 0;
536
537         char *errstr = NULL;
538
539         ZERO_STRUCT(msg_min);
540         ZERO_STRUCT(msg_maj);
541
542         gss_maj = gss_display_status(&gss_min, maj, GSS_C_GSS_CODE,
543                                      GSS_C_NO_OID, &msg_ctx, &msg_maj);
544         if (gss_maj) {
545                 goto done;
546         }
547         gss_maj = gss_display_status(&gss_min, min, GSS_C_MECH_CODE,
548                                      (gss_OID)discard_const(gss_mech_krb5),
549                                      &msg_ctx, &msg_min);
550         if (gss_maj) {
551                 goto done;
552         }
553
554         errstr = talloc_strndup(mem_ctx,
555                                 (char *)msg_maj.value,
556                                         msg_maj.length);
557         if (!errstr) {
558                 goto done;
559         }
560         errstr = talloc_strdup_append_buffer(errstr, ": ");
561         if (!errstr) {
562                 goto done;
563         }
564         errstr = talloc_strndup_append_buffer(errstr,
565                                                 (char *)msg_min.value,
566                                                         msg_min.length);
567         if (!errstr) {
568                 goto done;
569         }
570
571 done:
572         if (msg_min.value) {
573                 gss_maj = gss_release_buffer(&gss_min, &msg_min);
574         }
575         if (msg_maj.value) {
576                 gss_maj = gss_release_buffer(&gss_min, &msg_maj);
577         }
578         return errstr;
579 }
580
581 bool gse_require_more_processing(struct gse_context *gse_ctx)
582 {
583         return gse_ctx->more_processing;
584 }
585
586 DATA_BLOB gse_get_session_key(TALLOC_CTX *mem_ctx,
587                                 struct gse_context *gse_ctx)
588 {
589         OM_uint32 gss_min, gss_maj;
590         gss_buffer_set_t set = GSS_C_NO_BUFFER_SET;
591         DATA_BLOB ret;
592
593         gss_maj = gss_inquire_sec_context_by_oid(
594                                 &gss_min, gse_ctx->gss_ctx,
595                                 &gse_sesskey_inq_oid, &set);
596         if (gss_maj) {
597                 DEBUG(0, ("gss_inquire_sec_context_by_oid failed [%s]\n",
598                           gse_errstr(talloc_tos(), gss_maj, gss_min)));
599                 return data_blob_null;
600         }
601
602         if ((set == GSS_C_NO_BUFFER_SET) ||
603             (set->count != 2) ||
604             (memcmp(set->elements[1].value,
605                     gse_sesskeytype_oid.elements,
606                     gse_sesskeytype_oid.length) != 0)) {
607                 DEBUG(0, ("gss_inquire_sec_context_by_oid returned unknown "
608                           "OID for data in results:\n"));
609                 dump_data(1, (uint8_t *)set->elements[1].value,
610                              set->elements[1].length);
611                 return data_blob_null;
612         }
613
614         ret = data_blob_talloc(mem_ctx, set->elements[0].value,
615                                         set->elements[0].length);
616
617         gss_maj = gss_release_buffer_set(&gss_min, &set);
618         return ret;
619 }
620
621 NTSTATUS gse_get_client_name(struct gse_context *gse_ctx,
622                              TALLOC_CTX *mem_ctx, char **cli_name)
623 {
624         OM_uint32 gss_min, gss_maj;
625         gss_buffer_desc name_buffer;
626
627         if (!gse_ctx->authenticated) {
628                 return NT_STATUS_ACCESS_DENIED;
629         }
630
631         if (!gse_ctx->client_name) {
632                 return NT_STATUS_NOT_FOUND;
633         }
634
635         /* TODO: check OID matches KRB5 Principal Name OID ? */
636
637         gss_maj = gss_display_name(&gss_min,
638                                    gse_ctx->client_name,
639                                    &name_buffer, NULL);
640         if (gss_maj) {
641                 DEBUG(0, ("gss_display_name failed [%s]\n",
642                           gse_errstr(talloc_tos(), gss_maj, gss_min)));
643                 return NT_STATUS_INTERNAL_ERROR;
644         }
645
646         *cli_name = talloc_strndup(talloc_tos(),
647                                         (char *)name_buffer.value,
648                                         name_buffer.length);
649
650         gss_maj = gss_release_buffer(&gss_min, &name_buffer);
651
652         if (!*cli_name) {
653                 return NT_STATUS_NO_MEMORY;
654         }
655
656         return NT_STATUS_OK;
657 }
658
659 NTSTATUS gse_get_pac_data(struct gse_context *gse_ctx,
660                           TALLOC_CTX *mem_ctx, DATA_BLOB *pac)
661 {
662         OM_uint32 gss_min, gss_maj;
663         gss_buffer_set_t set = GSS_C_NO_BUFFER_SET;
664         DATA_BLOB auth_data;
665
666         if (!gse_ctx->authenticated) {
667                 return NT_STATUS_ACCESS_DENIED;
668         }
669 #ifdef HAVE_GSSKRB5_EXTRACT_AUTHZ_DATA_FROM_SEC_CONTEXT
670         {
671                 gss_buffer_desc pac_buffer;
672                 gss_maj = gsskrb5_extract_authz_data_from_sec_context(&gss_min, 
673                                                                       gse_ctx->gss_ctx,
674                                                                       KRB5_AUTHDATA_WIN2K_PAC,
675                                                                       &pac_buffer);
676         
677         
678                 if (gss_maj == 0) {
679                         *pac = data_blob_talloc(mem_ctx, pac_buffer.value, pac_buffer.length);
680                         gss_release_buffer(&gss_min, &pac_buffer);
681                         
682                 } else {
683                         DEBUG(0, ("gsskrb5_extract_authz_data_from_sec_context failed [%s]\n",
684                                   gse_errstr(talloc_tos(), gss_maj, gss_min)));
685                         
686                         return NT_STATUS_NOT_FOUND;
687                 }
688         }
689 #else
690         gss_maj = gss_inquire_sec_context_by_oid(
691                                 &gss_min, gse_ctx->gss_ctx,
692                                 &gse_authz_data_oid, &set);
693         if (gss_maj) {
694                 DEBUG(0, ("gss_inquire_sec_context_by_oid failed [%s]\n",
695                           gse_errstr(talloc_tos(), gss_maj, gss_min)));
696                 return NT_STATUS_NOT_FOUND;
697         }
698
699         if (set == GSS_C_NO_BUFFER_SET) {
700                 DEBUG(0, ("gss_inquire_sec_context_by_oid returned unknown "
701                           "data in results.\n"));
702                 return NT_STATUS_INTERNAL_ERROR;
703         }
704
705         auth_data = data_blob_const(set->elements[0].value,
706                                     set->elements[0].length);
707         
708         if (!unwrap_pac(mem_ctx, &auth_data, pac)) {
709                 DEBUG(1, ("Failed to unwrap PAC\n"));
710                 gss_release_buffer_set(&gss_min, &set);
711                 return NT_STATUS_ACCESS_DENIED;
712         }
713
714         gss_release_buffer_set(&gss_min, &set);
715 #endif
716         return NT_STATUS_OK;    
717 }
718
719 NTSTATUS gse_get_authtime(struct gse_context *gse_ctx, time_t *authtime)
720 {
721         OM_uint32 gss_min, gss_maj;
722         gss_buffer_set_t set = GSS_C_NO_BUFFER_SET;
723         int32_t tkttime;
724
725         if (!gse_ctx->authenticated) {
726                 return NT_STATUS_ACCESS_DENIED;
727         }
728
729         gss_maj = gss_inquire_sec_context_by_oid(
730                                 &gss_min, gse_ctx->gss_ctx,
731                                 &gse_authtime_oid, &set);
732         if (gss_maj) {
733                 DEBUG(0, ("gss_inquire_sec_context_by_oid failed [%s]\n",
734                           gse_errstr(talloc_tos(), gss_maj, gss_min)));
735                 return NT_STATUS_NOT_FOUND;
736         }
737
738         if ((set == GSS_C_NO_BUFFER_SET) || (set->count != 1) != 0) {
739                 DEBUG(0, ("gss_inquire_sec_context_by_oid returned unknown "
740                           "data in results.\n"));
741                 return NT_STATUS_INTERNAL_ERROR;
742         }
743
744         if (set->elements[0].length != sizeof(int32_t)) {
745                 DEBUG(0, ("Invalid authtime size!\n"));
746                 return NT_STATUS_INTERNAL_ERROR;
747         }
748
749         tkttime = *((int32_t *)set->elements[0].value);
750
751         gss_maj = gss_release_buffer_set(&gss_min, &set);
752
753         *authtime = (time_t)tkttime;
754         return NT_STATUS_OK;
755 }
756
757 size_t gse_get_signature_length(struct gse_context *gse_ctx,
758                                 int seal, size_t payload_size)
759 {
760         OM_uint32 gss_min, gss_maj;
761         gss_iov_buffer_desc iov[2];
762         uint8_t fakebuf[payload_size];
763         int sealed;
764
765         iov[0].type = GSS_IOV_BUFFER_TYPE_HEADER;
766         iov[0].buffer.value = NULL;
767         iov[0].buffer.length = 0;
768         iov[1].type = GSS_IOV_BUFFER_TYPE_DATA;
769         iov[1].buffer.value = fakebuf;
770         iov[1].buffer.length = payload_size;
771
772         gss_maj = gss_wrap_iov_length(&gss_min, gse_ctx->gss_ctx,
773                                         seal, GSS_C_QOP_DEFAULT,
774                                         &sealed, iov, 2);
775         if (gss_maj) {
776                 DEBUG(0, ("gss_wrap_iov_length failed with [%s]\n",
777                           gse_errstr(talloc_tos(), gss_maj, gss_min)));
778                 return 0;
779         }
780
781         return iov[0].buffer.length;
782 }
783
784 NTSTATUS gse_seal(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_iov_buffer_desc iov[2];
789         int req_seal = 1; /* setting to 1 means we request sign+seal */
790         int sealed;
791         NTSTATUS status;
792
793         /* allocate the memory ourselves so we do not need to talloc_memdup */
794         signature->length = gse_get_signature_length(gse_ctx, 1, data->length);
795         if (!signature->length) {
796                 return NT_STATUS_INTERNAL_ERROR;
797         }
798         signature->data = (uint8_t *)talloc_size(mem_ctx, signature->length);
799         if (!signature->data) {
800                 return NT_STATUS_NO_MEMORY;
801         }
802         iov[0].type = GSS_IOV_BUFFER_TYPE_HEADER;
803         iov[0].buffer.value = signature->data;
804         iov[0].buffer.length = signature->length;
805
806         /* data is encrypted in place, which is ok */
807         iov[1].type = GSS_IOV_BUFFER_TYPE_DATA;
808         iov[1].buffer.value = data->data;
809         iov[1].buffer.length = data->length;
810
811         gss_maj = gss_wrap_iov(&gss_min, gse_ctx->gss_ctx,
812                                 req_seal, GSS_C_QOP_DEFAULT,
813                                 &sealed, iov, 2);
814         if (gss_maj) {
815                 DEBUG(0, ("gss_wrap_iov failed with [%s]\n",
816                           gse_errstr(talloc_tos(), gss_maj, gss_min)));
817                 status = NT_STATUS_ACCESS_DENIED;
818                 goto done;
819         }
820
821         if (!sealed) {
822                 DEBUG(0, ("gss_wrap_iov says data was not sealed!\n"));
823                 status = NT_STATUS_ACCESS_DENIED;
824                 goto done;
825         }
826
827         status = NT_STATUS_OK;
828
829         DEBUG(10, ("Sealed %d bytes, and got %d bytes header/signature.\n",
830                    (int)iov[1].buffer.length, (int)iov[0].buffer.length));
831
832 done:
833         return status;
834 }
835
836 NTSTATUS gse_unseal(TALLOC_CTX *mem_ctx, struct gse_context *gse_ctx,
837                     DATA_BLOB *data, DATA_BLOB *signature)
838 {
839         OM_uint32 gss_min, gss_maj;
840         gss_iov_buffer_desc iov[2];
841         int sealed;
842         NTSTATUS status;
843
844         iov[0].type = GSS_IOV_BUFFER_TYPE_HEADER;
845         iov[0].buffer.value = signature->data;
846         iov[0].buffer.length = signature->length;
847
848         /* data is decrypted in place, which is ok */
849         iov[1].type = GSS_IOV_BUFFER_TYPE_DATA;
850         iov[1].buffer.value = data->data;
851         iov[1].buffer.length = data->length;
852
853         gss_maj = gss_unwrap_iov(&gss_min, gse_ctx->gss_ctx,
854                                  &sealed, NULL, iov, 2);
855         if (gss_maj) {
856                 DEBUG(0, ("gss_unwrap_iov failed with [%s]\n",
857                           gse_errstr(talloc_tos(), gss_maj, gss_min)));
858                 status = NT_STATUS_ACCESS_DENIED;
859                 goto done;
860         }
861
862         if (!sealed) {
863                 DEBUG(0, ("gss_unwrap_iov says data is not sealed!\n"));
864                 status = NT_STATUS_ACCESS_DENIED;
865                 goto done;
866         }
867
868         status = NT_STATUS_OK;
869
870         DEBUG(10, ("Unsealed %d bytes, with %d bytes header/signature.\n",
871                    (int)iov[1].buffer.length, (int)iov[0].buffer.length));
872
873 done:
874         return status;
875 }
876
877 NTSTATUS gse_sign(TALLOC_CTX *mem_ctx, struct gse_context *gse_ctx,
878                   DATA_BLOB *data, DATA_BLOB *signature)
879 {
880         OM_uint32 gss_min, gss_maj;
881         gss_buffer_desc in_data = { 0, NULL };
882         gss_buffer_desc out_data = { 0, NULL};
883         NTSTATUS status;
884
885         in_data.value = data->data;
886         in_data.length = data->length;
887
888         gss_maj = gss_get_mic(&gss_min, gse_ctx->gss_ctx,
889                               GSS_C_QOP_DEFAULT,
890                               &in_data, &out_data);
891         if (gss_maj) {
892                 DEBUG(0, ("gss_get_mic failed with [%s]\n",
893                           gse_errstr(talloc_tos(), gss_maj, gss_min)));
894                 status = NT_STATUS_ACCESS_DENIED;
895                 goto done;
896         }
897
898         *signature = data_blob_talloc(mem_ctx,
899                                         out_data.value, out_data.length);
900         if (!signature->data) {
901                 status = NT_STATUS_NO_MEMORY;
902                 goto done;
903         }
904
905         status = NT_STATUS_OK;
906
907 done:
908         if (out_data.value) {
909                 gss_maj = gss_release_buffer(&gss_min, &out_data);
910         }
911         return status;
912 }
913
914 NTSTATUS gse_sigcheck(TALLOC_CTX *mem_ctx, struct gse_context *gse_ctx,
915                       DATA_BLOB *data, DATA_BLOB *signature)
916 {
917         OM_uint32 gss_min, gss_maj;
918         gss_buffer_desc in_data = { 0, NULL };
919         gss_buffer_desc in_token = { 0, NULL};
920         NTSTATUS status;
921
922         in_data.value = data->data;
923         in_data.length = data->length;
924         in_token.value = signature->data;
925         in_token.length = signature->length;
926
927         gss_maj = gss_verify_mic(&gss_min, gse_ctx->gss_ctx,
928                                  &in_data, &in_token, NULL);
929         if (gss_maj) {
930                 DEBUG(0, ("gss_verify_mic failed with [%s]\n",
931                           gse_errstr(talloc_tos(), gss_maj, gss_min)));
932                 status = NT_STATUS_ACCESS_DENIED;
933                 goto done;
934         }
935
936         status = NT_STATUS_OK;
937
938 done:
939         return status;
940 }
941
942 #else
943
944 NTSTATUS gse_init_client(TALLOC_CTX *mem_ctx,
945                           bool do_sign, bool do_seal,
946                           const char *ccache_name,
947                           const char *server,
948                           const char *service,
949                           const char *username,
950                           const char *password,
951                           uint32_t add_gss_c_flags,
952                           struct gse_context **_gse_ctx)
953 {
954         return NT_STATUS_NOT_IMPLEMENTED;
955 }
956
957 NTSTATUS gse_get_client_auth_token(TALLOC_CTX *mem_ctx,
958                                    struct gse_context *gse_ctx,
959                                    DATA_BLOB *token_in,
960                                    DATA_BLOB *token_out)
961 {
962         return NT_STATUS_NOT_IMPLEMENTED;
963 }
964
965 NTSTATUS gse_init_server(TALLOC_CTX *mem_ctx,
966                          bool do_sign, bool do_seal,
967                          uint32_t add_gss_c_flags,
968                          const char *keytab,
969                          struct gse_context **_gse_ctx)
970 {
971         return NT_STATUS_NOT_IMPLEMENTED;
972 }
973
974 NTSTATUS gse_get_server_auth_token(TALLOC_CTX *mem_ctx,
975                                    struct gse_context *gse_ctx,
976                                    DATA_BLOB *token_in,
977                                    DATA_BLOB *token_out)
978 {
979         return NT_STATUS_NOT_IMPLEMENTED;
980 }
981
982 NTSTATUS gse_verify_server_auth_flags(struct gse_context *gse_ctx)
983 {
984         return NT_STATUS_NOT_IMPLEMENTED;
985 }
986
987 bool gse_require_more_processing(struct gse_context *gse_ctx)
988 {
989         return false;
990 }
991
992 DATA_BLOB gse_get_session_key(TALLOC_CTX *mem_ctx,
993                               struct gse_context *gse_ctx)
994 {
995         return data_blob_null;
996 }
997
998 NTSTATUS gse_get_client_name(struct gse_context *gse_ctx,
999                              TALLOC_CTX *mem_ctx, char **cli_name)
1000 {
1001         return NT_STATUS_NOT_IMPLEMENTED;
1002 }
1003
1004 NTSTATUS gse_get_authz_data(struct gse_context *gse_ctx,
1005                             TALLOC_CTX *mem_ctx, DATA_BLOB *pac)
1006 {
1007         return NT_STATUS_NOT_IMPLEMENTED;
1008 }
1009
1010 NTSTATUS gse_get_authtime(struct gse_context *gse_ctx, time_t *authtime)
1011 {
1012         return NT_STATUS_NOT_IMPLEMENTED;
1013 }
1014
1015 size_t gse_get_signature_length(struct gse_context *gse_ctx,
1016                                 int seal, size_t payload_size)
1017 {
1018         return 0;
1019 }
1020
1021 NTSTATUS gse_seal(TALLOC_CTX *mem_ctx, struct gse_context *gse_ctx,
1022                   DATA_BLOB *data, DATA_BLOB *signature)
1023 {
1024         return NT_STATUS_NOT_IMPLEMENTED;
1025 }
1026
1027 NTSTATUS gse_unseal(TALLOC_CTX *mem_ctx, struct gse_context *gse_ctx,
1028                     DATA_BLOB *data, DATA_BLOB *signature)
1029 {
1030         return NT_STATUS_NOT_IMPLEMENTED;
1031 }
1032
1033 NTSTATUS gse_sign(TALLOC_CTX *mem_ctx, struct gse_context *gse_ctx,
1034                   DATA_BLOB *data, DATA_BLOB *signature)
1035 {
1036         return NT_STATUS_NOT_IMPLEMENTED;
1037 }
1038
1039 NTSTATUS gse_sigcheck(TALLOC_CTX *mem_ctx, struct gse_context *gse_ctx,
1040                       DATA_BLOB *data, DATA_BLOB *signature)
1041 {
1042         return NT_STATUS_NOT_IMPLEMENTED;
1043 }
1044
1045 #endif /* HAVE_KRB5 && HAVE_GSSAPI_EXT_H && HAVE_GSS_WRAP_IOV */