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