s3:librpc:crypto:gse: increase debug level for gse_init_client().
[Samba.git] / source3 / librpc / crypto / gse.c
blob963c98a9e9d25d675865aa8ff4920a6d1222ab4b
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
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.
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.
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/>.
22 /* We support only GSSAPI/KRB5 here */
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"
33 #if defined(HAVE_KRB5)
35 #include "auth/kerberos/pac_utils.h"
36 #include "auth/kerberos/gssapi_helper.h"
37 #include "gse_krb5.h"
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);
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;
51 gss_cred_id_t delegated_cred_handle;
53 NTTIME expire_time;
55 /* gensec_gse only */
56 krb5_context k5ctx;
57 krb5_ccache ccache;
58 krb5_keytab keytab;
60 gss_OID_desc gss_mech;
61 gss_cred_id_t creds;
63 gss_OID ret_mech;
66 /* free non talloc dependent contexts */
67 static int gse_context_destructor(void *ptr)
69 struct gse_context *gse_ctx;
70 OM_uint32 gss_min;
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;
78 if (gse_ctx->keytab) {
79 krb5_kt_close(gse_ctx->k5ctx, gse_ctx->keytab);
80 gse_ctx->keytab = NULL;
82 krb5_free_context(gse_ctx->k5ctx);
83 gse_ctx->k5ctx = NULL;
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);
90 if (gse_ctx->server_name) {
91 (void)gss_release_name(&gss_min,
92 &gse_ctx->server_name);
94 if (gse_ctx->client_name) {
95 (void)gss_release_name(&gss_min,
96 &gse_ctx->client_name);
98 if (gse_ctx->creds) {
99 (void)gss_release_cred(&gss_min,
100 &gse_ctx->creds);
102 if (gse_ctx->delegated_cred_handle) {
103 (void)gss_release_cred(&gss_min,
104 &gse_ctx->delegated_cred_handle);
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));
120 return 0;
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)
129 struct gse_context *gse_ctx;
130 krb5_error_code k5ret;
131 NTSTATUS status;
133 gse_ctx = talloc_zero(mem_ctx, struct gse_context);
134 if (!gse_ctx) {
135 return NT_STATUS_NO_MEMORY;
137 talloc_set_destructor((TALLOC_CTX *)gse_ctx, gse_context_destructor);
139 gse_ctx->expire_time = GENSEC_EXPIRE_TIME_INFINITY;
140 gse_ctx->max_wrap_buf_size = UINT16_MAX;
142 memcpy(&gse_ctx->gss_mech, gss_mech_krb5, sizeof(gss_OID_desc));
144 gse_ctx->gss_want_flags = GSS_C_MUTUAL_FLAG |
145 GSS_C_DELEG_FLAG |
146 GSS_C_DELEG_POLICY_FLAG |
147 GSS_C_REPLAY_FLAG |
148 GSS_C_SEQUENCE_FLAG;
149 if (do_sign) {
150 gse_ctx->gss_want_flags |= GSS_C_INTEG_FLAG;
152 if (do_seal) {
153 gse_ctx->gss_want_flags |= GSS_C_INTEG_FLAG;
154 gse_ctx->gss_want_flags |= GSS_C_CONF_FLAG;
157 gse_ctx->gss_want_flags |= add_gss_c_flags;
159 /* Initialize Kerberos Context */
160 initialize_krb5_error_table();
162 k5ret = krb5_init_context(&gse_ctx->k5ctx);
163 if (k5ret) {
164 DEBUG(0, ("Failed to initialize kerberos context! (%s)\n",
165 error_message(k5ret)));
166 status = NT_STATUS_INTERNAL_ERROR;
167 goto err_out;
170 if (!ccache_name) {
171 ccache_name = krb5_cc_default_name(gse_ctx->k5ctx);
173 k5ret = krb5_cc_resolve(gse_ctx->k5ctx, ccache_name,
174 &gse_ctx->ccache);
175 if (k5ret) {
176 DEBUG(1, ("Failed to resolve credential cache! (%s)\n",
177 error_message(k5ret)));
178 status = NT_STATUS_INTERNAL_ERROR;
179 goto err_out;
182 /* TODO: Should we enforce a enc_types list ?
183 ret = krb5_set_default_tgs_ktypes(gse_ctx->k5ctx, enc_types);
186 *_gse_ctx = gse_ctx;
187 return NT_STATUS_OK;
189 err_out:
190 TALLOC_FREE(gse_ctx);
191 return status;
194 static NTSTATUS gse_init_client(TALLOC_CTX *mem_ctx,
195 bool do_sign, bool do_seal,
196 const char *ccache_name,
197 const char *server,
198 const char *service,
199 const char *username,
200 const char *password,
201 uint32_t add_gss_c_flags,
202 struct gse_context **_gse_ctx)
204 struct gse_context *gse_ctx;
205 OM_uint32 gss_maj, gss_min;
206 gss_buffer_desc name_buffer = GSS_C_EMPTY_BUFFER;
207 gss_OID_set_desc mech_set;
208 #ifdef HAVE_GSS_KRB5_CRED_NO_CI_FLAGS_X
209 gss_buffer_desc empty_buffer = GSS_C_EMPTY_BUFFER;
210 #endif
211 NTSTATUS status;
213 if (!server || !service) {
214 return NT_STATUS_INVALID_PARAMETER;
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;
224 /* Guess the realm based on the supplied service, and avoid the GSS libs
225 doing DNS lookups which may fail.
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
231 name_buffer.value = kerberos_get_principal_from_service_hostname(
232 gse_ctx, service, server, lp_realm());
233 if (!name_buffer.value) {
234 status = NT_STATUS_NO_MEMORY;
235 goto err_out;
237 name_buffer.length = strlen((char *)name_buffer.value);
238 gss_maj = gss_import_name(&gss_min, &name_buffer,
239 GSS_C_NT_USER_NAME,
240 &gse_ctx->server_name);
241 if (gss_maj) {
242 DEBUG(5, ("gss_import_name failed for %s, with [%s]\n",
243 (char *)name_buffer.value,
244 gse_errstr(gse_ctx, gss_maj, gss_min)));
245 status = NT_STATUS_INTERNAL_ERROR;
246 goto err_out;
249 /* TODO: get krb5 ticket using username/password, if no valid
250 * one already available in ccache */
252 mech_set.count = 1;
253 mech_set.elements = &gse_ctx->gss_mech;
255 gss_maj = gss_acquire_cred(&gss_min,
256 GSS_C_NO_NAME,
257 GSS_C_INDEFINITE,
258 &mech_set,
259 GSS_C_INITIATE,
260 &gse_ctx->creds,
261 NULL, NULL);
262 if (gss_maj) {
263 DEBUG(5, ("gss_acquire_creds failed for GSS_C_NO_NAME with [%s] -"
264 "the caller may retry after a kinit.\n",
265 gse_errstr(gse_ctx, gss_maj, gss_min)));
266 status = NT_STATUS_INTERNAL_ERROR;
267 goto err_out;
270 #ifdef HAVE_GSS_KRB5_CRED_NO_CI_FLAGS_X
272 * Don't force GSS_C_CONF_FLAG and GSS_C_INTEG_FLAG.
274 * This allows us to disable SIGN and SEAL for
275 * AUTH_LEVEL_CONNECT and AUTH_LEVEL_INTEGRITY.
277 * https://groups.yahoo.com/neo/groups/cat-ietf/conversations/topics/575
278 * http://krbdev.mit.edu/rt/Ticket/Display.html?id=6938
280 gss_maj = gss_set_cred_option(&gss_min, &gse_ctx->creds,
281 GSS_KRB5_CRED_NO_CI_FLAGS_X,
282 &empty_buffer);
283 if (gss_maj) {
284 DEBUG(0, ("gss_set_cred_option(GSS_KRB5_CRED_NO_CI_FLAGS_X), "
285 "failed with [%s]\n",
286 gse_errstr(gse_ctx, gss_maj, gss_min)));
287 status = NT_STATUS_INTERNAL_ERROR;
288 goto err_out;
290 #endif
292 *_gse_ctx = gse_ctx;
293 TALLOC_FREE(name_buffer.value);
294 return NT_STATUS_OK;
296 err_out:
297 TALLOC_FREE(name_buffer.value);
298 TALLOC_FREE(gse_ctx);
299 return status;
302 static NTSTATUS gse_get_client_auth_token(TALLOC_CTX *mem_ctx,
303 struct gse_context *gse_ctx,
304 const DATA_BLOB *token_in,
305 DATA_BLOB *token_out)
307 OM_uint32 gss_maj, gss_min;
308 gss_buffer_desc in_data;
309 gss_buffer_desc out_data;
310 DATA_BLOB blob = data_blob_null;
311 NTSTATUS status;
312 OM_uint32 time_rec = 0;
313 struct timeval tv;
315 in_data.value = token_in->data;
316 in_data.length = token_in->length;
318 gss_maj = gss_init_sec_context(&gss_min,
319 gse_ctx->creds,
320 &gse_ctx->gssapi_context,
321 gse_ctx->server_name,
322 &gse_ctx->gss_mech,
323 gse_ctx->gss_want_flags,
324 0, GSS_C_NO_CHANNEL_BINDINGS,
325 &in_data, NULL, &out_data,
326 &gse_ctx->gss_got_flags, &time_rec);
327 switch (gss_maj) {
328 case GSS_S_COMPLETE:
329 /* we are done with it */
330 tv = timeval_current_ofs(time_rec, 0);
331 gse_ctx->expire_time = timeval_to_nttime(&tv);
333 status = NT_STATUS_OK;
334 break;
335 case GSS_S_CONTINUE_NEEDED:
336 /* we will need a third leg */
337 status = NT_STATUS_MORE_PROCESSING_REQUIRED;
338 break;
339 default:
340 DEBUG(0, ("gss_init_sec_context failed with [%s]\n",
341 gse_errstr(talloc_tos(), gss_maj, gss_min)));
342 status = NT_STATUS_INTERNAL_ERROR;
343 goto done;
346 /* we may be told to return nothing */
347 if (out_data.length) {
348 blob = data_blob_talloc(mem_ctx, out_data.value, out_data.length);
349 if (!blob.data) {
350 status = NT_STATUS_NO_MEMORY;
353 gss_maj = gss_release_buffer(&gss_min, &out_data);
356 done:
357 *token_out = blob;
358 return status;
361 static 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)
366 struct gse_context *gse_ctx;
367 OM_uint32 gss_maj, gss_min;
368 krb5_error_code ret;
369 NTSTATUS status;
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;
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;
384 #ifdef HAVE_GSS_KRB5_IMPORT_CRED
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);
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;
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 ... */
410 const char *ktname;
411 gss_OID_set_desc mech_set;
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;
420 ret = gsskrb5_register_acceptor_identity(ktname);
421 if (ret) {
422 status = NT_STATUS_INTERNAL_ERROR;
423 goto done;
426 mech_set.count = 1;
427 mech_set.elements = &gse_ctx->gss_mech;
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);
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;
445 status = NT_STATUS_OK;
447 done:
448 if (!NT_STATUS_IS_OK(status)) {
449 TALLOC_FREE(gse_ctx);
452 *_gse_ctx = gse_ctx;
453 return status;
456 static NTSTATUS gse_get_server_auth_token(TALLOC_CTX *mem_ctx,
457 struct gse_context *gse_ctx,
458 const DATA_BLOB *token_in,
459 DATA_BLOB *token_out)
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 OM_uint32 time_rec = 0;
467 struct timeval tv;
469 in_data.value = token_in->data;
470 in_data.length = token_in->length;
472 gss_maj = gss_accept_sec_context(&gss_min,
473 &gse_ctx->gssapi_context,
474 gse_ctx->creds,
475 &in_data,
476 GSS_C_NO_CHANNEL_BINDINGS,
477 &gse_ctx->client_name,
478 &gse_ctx->ret_mech,
479 &out_data,
480 &gse_ctx->gss_got_flags,
481 &time_rec,
482 &gse_ctx->delegated_cred_handle);
483 switch (gss_maj) {
484 case GSS_S_COMPLETE:
485 /* we are done with it */
486 tv = timeval_current_ofs(time_rec, 0);
487 gse_ctx->expire_time = timeval_to_nttime(&tv);
489 status = NT_STATUS_OK;
490 break;
491 case GSS_S_CONTINUE_NEEDED:
492 /* we will need a third leg */
493 status = NT_STATUS_MORE_PROCESSING_REQUIRED;
494 break;
495 default:
496 DEBUG(1, ("gss_accept_sec_context failed with [%s]\n",
497 gse_errstr(talloc_tos(), gss_maj, gss_min)));
499 if (gse_ctx->gssapi_context) {
500 gss_delete_sec_context(&gss_min,
501 &gse_ctx->gssapi_context,
502 GSS_C_NO_BUFFER);
506 * If we got an output token, make Windows aware of it
507 * by telling it that more processing is needed
509 if (out_data.length > 0) {
510 status = NT_STATUS_MORE_PROCESSING_REQUIRED;
511 /* Fall through to handle the out token */
512 } else {
513 status = NT_STATUS_LOGON_FAILURE;
514 goto done;
518 /* we may be told to return nothing */
519 if (out_data.length) {
520 blob = data_blob_talloc(mem_ctx, out_data.value, out_data.length);
521 if (!blob.data) {
522 status = NT_STATUS_NO_MEMORY;
524 gss_maj = gss_release_buffer(&gss_min, &out_data);
528 done:
529 *token_out = blob;
530 return status;
533 static char *gse_errstr(TALLOC_CTX *mem_ctx, OM_uint32 maj, OM_uint32 min)
535 OM_uint32 gss_min, gss_maj;
536 gss_buffer_desc msg_min;
537 gss_buffer_desc msg_maj;
538 OM_uint32 msg_ctx = 0;
540 char *errstr = NULL;
542 ZERO_STRUCT(msg_min);
543 ZERO_STRUCT(msg_maj);
545 gss_maj = gss_display_status(&gss_min, maj, GSS_C_GSS_CODE,
546 GSS_C_NO_OID, &msg_ctx, &msg_maj);
547 if (gss_maj) {
548 goto done;
550 errstr = talloc_strndup(mem_ctx,
551 (char *)msg_maj.value,
552 msg_maj.length);
553 if (!errstr) {
554 goto done;
556 gss_maj = gss_display_status(&gss_min, min, GSS_C_MECH_CODE,
557 (gss_OID)discard_const(gss_mech_krb5),
558 &msg_ctx, &msg_min);
559 if (gss_maj) {
560 goto done;
563 errstr = talloc_strdup_append_buffer(errstr, ": ");
564 if (!errstr) {
565 goto done;
567 errstr = talloc_strndup_append_buffer(errstr,
568 (char *)msg_min.value,
569 msg_min.length);
570 if (!errstr) {
571 goto done;
574 done:
575 if (msg_min.value) {
576 gss_maj = gss_release_buffer(&gss_min, &msg_min);
578 if (msg_maj.value) {
579 gss_maj = gss_release_buffer(&gss_min, &msg_maj);
581 return errstr;
584 static NTSTATUS gensec_gse_client_start(struct gensec_security *gensec_security)
586 struct gse_context *gse_ctx;
587 struct cli_credentials *creds = gensec_get_credentials(gensec_security);
588 NTSTATUS nt_status;
589 OM_uint32 want_flags = 0;
590 bool do_sign = false, do_seal = false;
591 const char *hostname = gensec_get_target_hostname(gensec_security);
592 const char *service = gensec_get_target_service(gensec_security);
593 const char *username = cli_credentials_get_username(creds);
594 const char *password = cli_credentials_get_password(creds);
596 if (!hostname) {
597 DEBUG(1, ("Could not determine hostname for target computer, cannot use kerberos\n"));
598 return NT_STATUS_INVALID_PARAMETER;
600 if (is_ipaddress(hostname)) {
601 DEBUG(2, ("Cannot do GSE to an IP address\n"));
602 return NT_STATUS_INVALID_PARAMETER;
604 if (strcmp(hostname, "localhost") == 0) {
605 DEBUG(2, ("GSE to 'localhost' does not make sense\n"));
606 return NT_STATUS_INVALID_PARAMETER;
609 if (gensec_security->want_features & GENSEC_FEATURE_SESSION_KEY) {
610 do_sign = true;
612 if (gensec_security->want_features & GENSEC_FEATURE_SIGN) {
613 do_sign = true;
615 if (gensec_security->want_features & GENSEC_FEATURE_SEAL) {
616 do_seal = true;
618 if (gensec_security->want_features & GENSEC_FEATURE_DCE_STYLE) {
619 want_flags |= GSS_C_DCE_STYLE;
622 nt_status = gse_init_client(gensec_security, do_sign, do_seal, NULL,
623 hostname, service,
624 username, password, want_flags,
625 &gse_ctx);
626 if (!NT_STATUS_IS_OK(nt_status)) {
627 return nt_status;
629 gensec_security->private_data = gse_ctx;
630 return NT_STATUS_OK;
633 static NTSTATUS gensec_gse_server_start(struct gensec_security *gensec_security)
635 struct gse_context *gse_ctx;
636 NTSTATUS nt_status;
637 OM_uint32 want_flags = 0;
638 bool do_sign = false, do_seal = false;
640 if (gensec_security->want_features & GENSEC_FEATURE_SIGN) {
641 do_sign = true;
643 if (gensec_security->want_features & GENSEC_FEATURE_SEAL) {
644 do_seal = true;
646 if (gensec_security->want_features & GENSEC_FEATURE_DCE_STYLE) {
647 want_flags |= GSS_C_DCE_STYLE;
650 nt_status = gse_init_server(gensec_security, do_sign, do_seal, want_flags,
651 &gse_ctx);
652 if (!NT_STATUS_IS_OK(nt_status)) {
653 return nt_status;
655 gensec_security->private_data = gse_ctx;
656 return NT_STATUS_OK;
660 * Next state function for the GSE GENSEC mechanism
662 * @param gensec_gse_state GSE State
663 * @param mem_ctx The TALLOC_CTX for *out to be allocated on
664 * @param in The request, as a DATA_BLOB
665 * @param out The reply, as an talloc()ed DATA_BLOB, on *mem_ctx
666 * @return Error, MORE_PROCESSING_REQUIRED if a reply is sent,
667 * or NT_STATUS_OK if the user is authenticated.
670 static NTSTATUS gensec_gse_update(struct gensec_security *gensec_security,
671 TALLOC_CTX *mem_ctx,
672 struct tevent_context *ev,
673 const DATA_BLOB in, DATA_BLOB *out)
675 NTSTATUS status;
676 struct gse_context *gse_ctx =
677 talloc_get_type_abort(gensec_security->private_data,
678 struct gse_context);
680 switch (gensec_security->gensec_role) {
681 case GENSEC_CLIENT:
682 status = gse_get_client_auth_token(mem_ctx, gse_ctx,
683 &in, out);
684 break;
685 case GENSEC_SERVER:
686 status = gse_get_server_auth_token(mem_ctx, gse_ctx,
687 &in, out);
688 break;
690 if (!NT_STATUS_IS_OK(status)) {
691 return status;
694 return NT_STATUS_OK;
697 static NTSTATUS gensec_gse_wrap(struct gensec_security *gensec_security,
698 TALLOC_CTX *mem_ctx,
699 const DATA_BLOB *in,
700 DATA_BLOB *out)
702 struct gse_context *gse_ctx =
703 talloc_get_type_abort(gensec_security->private_data,
704 struct gse_context);
705 OM_uint32 maj_stat, min_stat;
706 gss_buffer_desc input_token, output_token;
707 int conf_state;
708 input_token.length = in->length;
709 input_token.value = in->data;
711 maj_stat = gss_wrap(&min_stat,
712 gse_ctx->gssapi_context,
713 gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL),
714 GSS_C_QOP_DEFAULT,
715 &input_token,
716 &conf_state,
717 &output_token);
718 if (GSS_ERROR(maj_stat)) {
719 DEBUG(0, ("gensec_gse_wrap: GSS Wrap failed: %s\n",
720 gse_errstr(talloc_tos(), maj_stat, min_stat)));
721 return NT_STATUS_ACCESS_DENIED;
724 *out = data_blob_talloc(mem_ctx, output_token.value, output_token.length);
725 gss_release_buffer(&min_stat, &output_token);
727 if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)
728 && !conf_state) {
729 return NT_STATUS_ACCESS_DENIED;
731 return NT_STATUS_OK;
734 static NTSTATUS gensec_gse_unwrap(struct gensec_security *gensec_security,
735 TALLOC_CTX *mem_ctx,
736 const DATA_BLOB *in,
737 DATA_BLOB *out)
739 struct gse_context *gse_ctx =
740 talloc_get_type_abort(gensec_security->private_data,
741 struct gse_context);
742 OM_uint32 maj_stat, min_stat;
743 gss_buffer_desc input_token, output_token;
744 int conf_state;
745 gss_qop_t qop_state;
746 input_token.length = in->length;
747 input_token.value = in->data;
749 maj_stat = gss_unwrap(&min_stat,
750 gse_ctx->gssapi_context,
751 &input_token,
752 &output_token,
753 &conf_state,
754 &qop_state);
755 if (GSS_ERROR(maj_stat)) {
756 DEBUG(0, ("gensec_gse_unwrap: GSS UnWrap failed: %s\n",
757 gse_errstr(talloc_tos(), maj_stat, min_stat)));
758 return NT_STATUS_ACCESS_DENIED;
761 *out = data_blob_talloc(mem_ctx, output_token.value, output_token.length);
762 gss_release_buffer(&min_stat, &output_token);
764 if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)
765 && !conf_state) {
766 return NT_STATUS_ACCESS_DENIED;
768 return NT_STATUS_OK;
771 static NTSTATUS gensec_gse_seal_packet(struct gensec_security *gensec_security,
772 TALLOC_CTX *mem_ctx,
773 uint8_t *data, size_t length,
774 const uint8_t *whole_pdu, size_t pdu_length,
775 DATA_BLOB *sig)
777 struct gse_context *gse_ctx =
778 talloc_get_type_abort(gensec_security->private_data,
779 struct gse_context);
780 bool hdr_signing = false;
781 size_t sig_size = 0;
782 NTSTATUS status;
784 if (gensec_security->want_features & GENSEC_FEATURE_SIGN_PKT_HEADER) {
785 hdr_signing = true;
788 sig_size = gensec_gse_sig_size(gensec_security, length);
790 status = gssapi_seal_packet(gse_ctx->gssapi_context,
791 &gse_ctx->gss_mech,
792 hdr_signing, sig_size,
793 data, length,
794 whole_pdu, pdu_length,
795 mem_ctx, sig);
796 if (!NT_STATUS_IS_OK(status)) {
797 DEBUG(0, ("gssapi_seal_packet(hdr_signing=%u,sig_size=%zu,"
798 "data=%zu,pdu=%zu) failed: %s\n",
799 hdr_signing, sig_size, length, pdu_length,
800 nt_errstr(status)));
801 return status;
804 return NT_STATUS_OK;
807 static NTSTATUS gensec_gse_unseal_packet(struct gensec_security *gensec_security,
808 uint8_t *data, size_t length,
809 const uint8_t *whole_pdu, size_t pdu_length,
810 const DATA_BLOB *sig)
812 struct gse_context *gse_ctx =
813 talloc_get_type_abort(gensec_security->private_data,
814 struct gse_context);
815 bool hdr_signing = false;
816 NTSTATUS status;
818 if (gensec_security->want_features & GENSEC_FEATURE_SIGN_PKT_HEADER) {
819 hdr_signing = true;
822 status = gssapi_unseal_packet(gse_ctx->gssapi_context,
823 &gse_ctx->gss_mech,
824 hdr_signing,
825 data, length,
826 whole_pdu, pdu_length,
827 sig);
828 if (!NT_STATUS_IS_OK(status)) {
829 DEBUG(0, ("gssapi_unseal_packet(hdr_signing=%u,sig_size=%zu,"
830 "data=%zu,pdu=%zu) failed: %s\n",
831 hdr_signing, sig->length, length, pdu_length,
832 nt_errstr(status)));
833 return status;
836 return NT_STATUS_OK;
839 static NTSTATUS gensec_gse_sign_packet(struct gensec_security *gensec_security,
840 TALLOC_CTX *mem_ctx,
841 const uint8_t *data, size_t length,
842 const uint8_t *whole_pdu, size_t pdu_length,
843 DATA_BLOB *sig)
845 struct gse_context *gse_ctx =
846 talloc_get_type_abort(gensec_security->private_data,
847 struct gse_context);
848 bool hdr_signing = false;
849 NTSTATUS status;
851 if (gensec_security->want_features & GENSEC_FEATURE_SIGN_PKT_HEADER) {
852 hdr_signing = true;
855 status = gssapi_sign_packet(gse_ctx->gssapi_context,
856 &gse_ctx->gss_mech,
857 hdr_signing,
858 data, length,
859 whole_pdu, pdu_length,
860 mem_ctx, sig);
861 if (!NT_STATUS_IS_OK(status)) {
862 DEBUG(0, ("gssapi_sign_packet(hdr_signing=%u,"
863 "data=%zu,pdu=%zu) failed: %s\n",
864 hdr_signing, length, pdu_length,
865 nt_errstr(status)));
866 return status;
869 return NT_STATUS_OK;
872 static NTSTATUS gensec_gse_check_packet(struct gensec_security *gensec_security,
873 const uint8_t *data, size_t length,
874 const uint8_t *whole_pdu, size_t pdu_length,
875 const DATA_BLOB *sig)
877 struct gse_context *gse_ctx =
878 talloc_get_type_abort(gensec_security->private_data,
879 struct gse_context);
880 bool hdr_signing = false;
881 NTSTATUS status;
883 if (gensec_security->want_features & GENSEC_FEATURE_SIGN_PKT_HEADER) {
884 hdr_signing = true;
887 status = gssapi_check_packet(gse_ctx->gssapi_context,
888 &gse_ctx->gss_mech,
889 hdr_signing,
890 data, length,
891 whole_pdu, pdu_length,
892 sig);
893 if (!NT_STATUS_IS_OK(status)) {
894 DEBUG(0, ("gssapi_check_packet(hdr_signing=%u,sig_size=%zu"
895 "data=%zu,pdu=%zu) failed: %s\n",
896 hdr_signing, sig->length, length, pdu_length,
897 nt_errstr(status)));
898 return status;
901 return NT_STATUS_OK;
904 /* Try to figure out what features we actually got on the connection */
905 static bool gensec_gse_have_feature(struct gensec_security *gensec_security,
906 uint32_t feature)
908 struct gse_context *gse_ctx =
909 talloc_get_type_abort(gensec_security->private_data,
910 struct gse_context);
912 if (feature & GENSEC_FEATURE_SESSION_KEY) {
913 return gse_ctx->gss_got_flags & GSS_C_INTEG_FLAG;
915 if (feature & GENSEC_FEATURE_SIGN) {
916 return gse_ctx->gss_got_flags & GSS_C_INTEG_FLAG;
918 if (feature & GENSEC_FEATURE_SEAL) {
919 return gse_ctx->gss_got_flags & GSS_C_CONF_FLAG;
921 if (feature & GENSEC_FEATURE_DCE_STYLE) {
922 return gse_ctx->gss_got_flags & GSS_C_DCE_STYLE;
924 if (feature & GENSEC_FEATURE_NEW_SPNEGO) {
925 NTSTATUS status;
926 uint32_t keytype;
928 if (!(gse_ctx->gss_got_flags & GSS_C_INTEG_FLAG)) {
929 return false;
932 status = gssapi_get_session_key(talloc_tos(),
933 gse_ctx->gssapi_context, NULL, &keytype);
935 * We should do a proper sig on the mechListMic unless
936 * we know we have to be backwards compatible with
937 * earlier windows versions.
939 * Negotiating a non-krb5
940 * mech for example should be regarded as having
941 * NEW_SPNEGO
943 if (NT_STATUS_IS_OK(status)) {
944 switch (keytype) {
945 case ENCTYPE_DES_CBC_CRC:
946 case ENCTYPE_DES_CBC_MD5:
947 case ENCTYPE_ARCFOUR_HMAC:
948 case ENCTYPE_DES3_CBC_SHA1:
949 return false;
952 return true;
954 /* We can always do async (rather than strict request/reply) packets. */
955 if (feature & GENSEC_FEATURE_ASYNC_REPLIES) {
956 return true;
958 if (feature & GENSEC_FEATURE_SIGN_PKT_HEADER) {
959 if (gensec_security->want_features & GENSEC_FEATURE_SEAL) {
960 return true;
963 if (gensec_security->want_features & GENSEC_FEATURE_SIGN) {
964 return true;
967 return false;
969 return false;
972 static NTTIME gensec_gse_expire_time(struct gensec_security *gensec_security)
974 struct gse_context *gse_ctx =
975 talloc_get_type_abort(gensec_security->private_data,
976 struct gse_context);
978 return gse_ctx->expire_time;
982 * Extract the 'sesssion key' needed by SMB signing and ncacn_np
983 * (for encrypting some passwords).
985 * This breaks all the abstractions, but what do you expect...
987 static NTSTATUS gensec_gse_session_key(struct gensec_security *gensec_security,
988 TALLOC_CTX *mem_ctx,
989 DATA_BLOB *session_key)
991 struct gse_context *gse_ctx =
992 talloc_get_type_abort(gensec_security->private_data,
993 struct gse_context);
995 return gssapi_get_session_key(mem_ctx, gse_ctx->gssapi_context, session_key, NULL);
998 /* Get some basic (and authorization) information about the user on
999 * this session. This uses either the PAC (if present) or a local
1000 * database lookup */
1001 static NTSTATUS gensec_gse_session_info(struct gensec_security *gensec_security,
1002 TALLOC_CTX *mem_ctx,
1003 struct auth_session_info **_session_info)
1005 struct gse_context *gse_ctx =
1006 talloc_get_type_abort(gensec_security->private_data,
1007 struct gse_context);
1008 NTSTATUS nt_status;
1009 TALLOC_CTX *tmp_ctx;
1010 struct auth_session_info *session_info = NULL;
1011 OM_uint32 maj_stat, min_stat;
1012 DATA_BLOB pac_blob, *pac_blob_ptr = NULL;
1014 gss_buffer_desc name_token;
1015 char *principal_string;
1017 tmp_ctx = talloc_named(mem_ctx, 0, "gensec_gse_session_info context");
1018 NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);
1020 maj_stat = gss_display_name(&min_stat,
1021 gse_ctx->client_name,
1022 &name_token,
1023 NULL);
1024 if (GSS_ERROR(maj_stat)) {
1025 DEBUG(1, ("GSS display_name failed: %s\n",
1026 gse_errstr(talloc_tos(), maj_stat, min_stat)));
1027 talloc_free(tmp_ctx);
1028 return NT_STATUS_FOOBAR;
1031 principal_string = talloc_strndup(tmp_ctx,
1032 (const char *)name_token.value,
1033 name_token.length);
1035 gss_release_buffer(&min_stat, &name_token);
1037 if (!principal_string) {
1038 talloc_free(tmp_ctx);
1039 return NT_STATUS_NO_MEMORY;
1042 nt_status = gssapi_obtain_pac_blob(tmp_ctx, gse_ctx->gssapi_context,
1043 gse_ctx->client_name,
1044 &pac_blob);
1046 /* IF we have the PAC - otherwise we need to get this
1047 * data from elsewere
1049 if (NT_STATUS_IS_OK(nt_status)) {
1050 pac_blob_ptr = &pac_blob;
1052 nt_status = gensec_generate_session_info_pac(tmp_ctx,
1053 gensec_security,
1054 NULL,
1055 pac_blob_ptr, principal_string,
1056 gensec_get_remote_address(gensec_security),
1057 &session_info);
1058 if (!NT_STATUS_IS_OK(nt_status)) {
1059 talloc_free(tmp_ctx);
1060 return nt_status;
1063 nt_status = gensec_gse_session_key(gensec_security, session_info,
1064 &session_info->session_key);
1065 if (!NT_STATUS_IS_OK(nt_status)) {
1066 talloc_free(tmp_ctx);
1067 return nt_status;
1070 *_session_info = talloc_move(mem_ctx, &session_info);
1071 talloc_free(tmp_ctx);
1073 return NT_STATUS_OK;
1076 static size_t gensec_gse_max_input_size(struct gensec_security *gensec_security)
1078 struct gse_context *gse_ctx =
1079 talloc_get_type_abort(gensec_security->private_data,
1080 struct gse_context);
1081 OM_uint32 maj_stat, min_stat;
1082 OM_uint32 max_input_size;
1084 maj_stat = gss_wrap_size_limit(&min_stat,
1085 gse_ctx->gssapi_context,
1086 gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL),
1087 GSS_C_QOP_DEFAULT,
1088 gse_ctx->max_wrap_buf_size,
1089 &max_input_size);
1090 if (GSS_ERROR(maj_stat)) {
1091 TALLOC_CTX *mem_ctx = talloc_new(NULL);
1092 DEBUG(1, ("gensec_gssapi_max_input_size: determining signature size with gss_wrap_size_limit failed: %s\n",
1093 gse_errstr(mem_ctx, maj_stat, min_stat)));
1094 talloc_free(mem_ctx);
1095 return 0;
1098 return max_input_size;
1101 /* Find out the maximum output size negotiated on this connection */
1102 static size_t gensec_gse_max_wrapped_size(struct gensec_security *gensec_security)
1104 struct gse_context *gse_ctx =
1105 talloc_get_type_abort(gensec_security->private_data,
1106 struct gse_context);
1107 return gse_ctx->max_wrap_buf_size;
1110 static size_t gensec_gse_sig_size(struct gensec_security *gensec_security,
1111 size_t data_size)
1113 struct gse_context *gse_ctx =
1114 talloc_get_type_abort(gensec_security->private_data,
1115 struct gse_context);
1117 if (gse_ctx->sig_size > 0) {
1118 return gse_ctx->sig_size;
1121 gse_ctx->sig_size = gssapi_get_sig_size(gse_ctx->gssapi_context,
1122 &gse_ctx->gss_mech,
1123 gse_ctx->gss_want_flags,
1124 data_size);
1125 return gse_ctx->sig_size;
1128 static const char *gensec_gse_krb5_oids[] = {
1129 GENSEC_OID_KERBEROS5_OLD,
1130 GENSEC_OID_KERBEROS5,
1131 NULL
1134 const struct gensec_security_ops gensec_gse_krb5_security_ops = {
1135 .name = "gse_krb5",
1136 .auth_type = DCERPC_AUTH_TYPE_KRB5,
1137 .oid = gensec_gse_krb5_oids,
1138 .client_start = gensec_gse_client_start,
1139 .server_start = gensec_gse_server_start,
1140 .magic = gensec_magic_check_krb5_oid,
1141 .update = gensec_gse_update,
1142 .session_key = gensec_gse_session_key,
1143 .session_info = gensec_gse_session_info,
1144 .sig_size = gensec_gse_sig_size,
1145 .sign_packet = gensec_gse_sign_packet,
1146 .check_packet = gensec_gse_check_packet,
1147 .seal_packet = gensec_gse_seal_packet,
1148 .unseal_packet = gensec_gse_unseal_packet,
1149 .max_input_size = gensec_gse_max_input_size,
1150 .max_wrapped_size = gensec_gse_max_wrapped_size,
1151 .wrap = gensec_gse_wrap,
1152 .unwrap = gensec_gse_unwrap,
1153 .have_feature = gensec_gse_have_feature,
1154 .expire_time = gensec_gse_expire_time,
1155 .enabled = true,
1156 .kerberos = true,
1157 .priority = GENSEC_GSSAPI
1160 #endif /* HAVE_KRB5 */