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