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