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 : #include "param/param.h"
35 :
36 : #if defined(HAVE_KRB5)
37 :
38 : #include "auth/kerberos/pac_utils.h"
39 : #include "auth/kerberos/gssapi_helper.h"
40 : #include "gse_krb5.h"
41 :
42 : static char *gse_errstr(TALLOC_CTX *mem_ctx, OM_uint32 maj, OM_uint32 min);
43 : static size_t gensec_gse_sig_size(struct gensec_security *gensec_security,
44 : size_t data_size);
45 :
46 : struct gse_context {
47 : gss_ctx_id_t gssapi_context;
48 : gss_name_t server_name;
49 : gss_name_t client_name;
50 : OM_uint32 gss_want_flags, gss_got_flags;
51 : size_t max_wrap_buf_size;
52 : size_t sig_size;
53 :
54 : gss_cred_id_t delegated_cred_handle;
55 :
56 : NTTIME expire_time;
57 :
58 : /* gensec_gse only */
59 : krb5_context k5ctx;
60 : krb5_ccache ccache;
61 : krb5_keytab keytab;
62 :
63 : gss_OID_desc gss_mech;
64 : gss_cred_id_t creds;
65 :
66 : gss_OID ret_mech;
67 :
68 : struct gss_channel_bindings_struct _channel_bindings;
69 : struct gss_channel_bindings_struct *channel_bindings;
70 : };
71 :
72 : /* free non talloc dependent contexts */
73 6301 : static int gse_context_destructor(void *ptr)
74 : {
75 0 : struct gse_context *gse_ctx;
76 0 : OM_uint32 gss_min;
77 :
78 6301 : gse_ctx = talloc_get_type_abort(ptr, struct gse_context);
79 6301 : if (gse_ctx->k5ctx) {
80 6301 : if (gse_ctx->ccache) {
81 2770 : krb5_cc_close(gse_ctx->k5ctx, gse_ctx->ccache);
82 2770 : gse_ctx->ccache = NULL;
83 : }
84 6301 : if (gse_ctx->keytab) {
85 3521 : krb5_kt_close(gse_ctx->k5ctx, gse_ctx->keytab);
86 3521 : gse_ctx->keytab = NULL;
87 : }
88 6301 : krb5_free_context(gse_ctx->k5ctx);
89 6301 : gse_ctx->k5ctx = NULL;
90 : }
91 6301 : if (gse_ctx->gssapi_context != GSS_C_NO_CONTEXT) {
92 3656 : (void)gss_delete_sec_context(&gss_min,
93 : &gse_ctx->gssapi_context,
94 : GSS_C_NO_BUFFER);
95 : }
96 6301 : if (gse_ctx->server_name) {
97 2770 : (void)gss_release_name(&gss_min,
98 : &gse_ctx->server_name);
99 : }
100 6301 : if (gse_ctx->client_name) {
101 890 : (void)gss_release_name(&gss_min,
102 : &gse_ctx->client_name);
103 : }
104 6301 : if (gse_ctx->creds) {
105 6291 : (void)gss_release_cred(&gss_min,
106 : &gse_ctx->creds);
107 : }
108 6301 : if (gse_ctx->delegated_cred_handle) {
109 0 : (void)gss_release_cred(&gss_min,
110 : &gse_ctx->delegated_cred_handle);
111 : }
112 :
113 : /* MIT and Heimdal differ as to if you can call
114 : * gss_release_oid() on this OID, generated by
115 : * gss_{accept,init}_sec_context(). However, as long as the
116 : * oid is gss_mech_krb5 (which it always is at the moment),
117 : * then this is a moot point, as both declare this particular
118 : * OID static, and so no memory is lost. This assert is in
119 : * place to ensure that the programmer who wishes to extend
120 : * this code to EAP or other GSS mechanisms determines an
121 : * implementation-dependent way of releasing any dynamically
122 : * allocated OID */
123 6301 : SMB_ASSERT(smb_gss_oid_equal(&gse_ctx->gss_mech, GSS_C_NO_OID) ||
124 : smb_gss_oid_equal(&gse_ctx->gss_mech, gss_mech_krb5));
125 :
126 6301 : return 0;
127 : }
128 :
129 2798 : static NTSTATUS gse_setup_server_principal(TALLOC_CTX *mem_ctx,
130 : const char *target_principal,
131 : const char *service,
132 : const char *hostname,
133 : const char *realm,
134 : char **pserver_principal,
135 : gss_name_t *pserver_name)
136 : {
137 2798 : char *server_principal = NULL;
138 0 : gss_buffer_desc name_token;
139 0 : gss_OID name_type;
140 2798 : OM_uint32 maj_stat, min_stat = 0;
141 :
142 2798 : if (target_principal != NULL) {
143 0 : server_principal = talloc_strdup(mem_ctx, target_principal);
144 0 : name_type = GSS_C_NULL_OID;
145 : } else {
146 2798 : server_principal = talloc_asprintf(mem_ctx,
147 : "%s/%s@%s",
148 : service,
149 : hostname,
150 : realm);
151 2798 : name_type = GSS_C_NT_USER_NAME;
152 : }
153 2798 : if (server_principal == NULL) {
154 0 : return NT_STATUS_NO_MEMORY;
155 : }
156 :
157 2798 : name_token.value = (uint8_t *)server_principal;
158 2798 : name_token.length = strlen(server_principal);
159 :
160 2798 : maj_stat = gss_import_name(&min_stat,
161 : &name_token,
162 : name_type,
163 : pserver_name);
164 2798 : if (maj_stat) {
165 0 : DBG_WARNING("GSS Import name of %s failed: %s\n",
166 : server_principal,
167 : gse_errstr(mem_ctx, maj_stat, min_stat));
168 0 : TALLOC_FREE(server_principal);
169 0 : return NT_STATUS_INVALID_PARAMETER;
170 : }
171 :
172 2798 : *pserver_principal = server_principal;
173 :
174 2798 : return NT_STATUS_OK;
175 : }
176 :
177 6339 : static NTSTATUS gse_context_init(struct gensec_security *gensec_security,
178 : bool do_sign, bool do_seal,
179 : const struct gss_OID_desc_struct *mech,
180 : uint32_t add_gss_c_flags,
181 : struct gse_context **_gse_ctx)
182 : {
183 0 : struct gse_context *gse_ctx;
184 0 : krb5_error_code k5ret;
185 0 : NTSTATUS status;
186 :
187 6339 : gse_ctx = talloc_zero(gensec_security, struct gse_context);
188 6339 : if (!gse_ctx) {
189 0 : return NT_STATUS_NO_MEMORY;
190 : }
191 6339 : talloc_set_destructor((TALLOC_CTX *)gse_ctx, gse_context_destructor);
192 :
193 6339 : gse_ctx->expire_time = GENSEC_EXPIRE_TIME_INFINITY;
194 6339 : gse_ctx->max_wrap_buf_size = UINT16_MAX;
195 :
196 6339 : memcpy(&gse_ctx->gss_mech, mech, sizeof(gss_OID_desc));
197 :
198 6339 : gse_ctx->gss_want_flags = GSS_C_MUTUAL_FLAG |
199 : GSS_C_DELEG_POLICY_FLAG |
200 : GSS_C_REPLAY_FLAG |
201 : GSS_C_SEQUENCE_FLAG;
202 6339 : if (do_sign) {
203 2758 : gse_ctx->gss_want_flags |= GSS_C_INTEG_FLAG;
204 : }
205 6339 : if (do_seal) {
206 398 : gse_ctx->gss_want_flags |= GSS_C_INTEG_FLAG;
207 398 : gse_ctx->gss_want_flags |= GSS_C_CONF_FLAG;
208 : }
209 :
210 6339 : gse_ctx->gss_want_flags |= add_gss_c_flags;
211 :
212 6339 : if (gensec_security->channel_bindings != NULL) {
213 24 : gse_ctx->_channel_bindings.initiator_addrtype =
214 24 : gensec_security->channel_bindings->initiator_addrtype;
215 24 : gse_ctx->_channel_bindings.initiator_address.value =
216 24 : gensec_security->channel_bindings->initiator_address.data;
217 24 : gse_ctx->_channel_bindings.initiator_address.length =
218 24 : gensec_security->channel_bindings->initiator_address.length;
219 :
220 24 : gse_ctx->_channel_bindings.acceptor_addrtype =
221 24 : gensec_security->channel_bindings->acceptor_addrtype;
222 24 : gse_ctx->_channel_bindings.acceptor_address.value =
223 24 : gensec_security->channel_bindings->acceptor_address.data;
224 24 : gse_ctx->_channel_bindings.acceptor_address.length =
225 24 : gensec_security->channel_bindings->acceptor_address.length;
226 :
227 24 : gse_ctx->_channel_bindings.application_data.value =
228 24 : gensec_security->channel_bindings->application_data.data;
229 24 : gse_ctx->_channel_bindings.application_data.length =
230 24 : gensec_security->channel_bindings->application_data.length;
231 :
232 24 : gse_ctx->channel_bindings =
233 24 : &gse_ctx->_channel_bindings;
234 : } else {
235 6315 : gse_ctx->channel_bindings = GSS_C_NO_CHANNEL_BINDINGS;
236 : }
237 :
238 : /* Initialize Kerberos Context */
239 6339 : k5ret = smb_krb5_init_context_common(&gse_ctx->k5ctx);
240 6339 : if (k5ret) {
241 0 : DBG_ERR("kerberos init context failed (%s)\n",
242 : error_message(k5ret));
243 0 : status = NT_STATUS_INTERNAL_ERROR;
244 0 : goto err_out;
245 : }
246 :
247 : #ifdef SAMBA4_USES_HEIMDAL
248 3632 : k5ret = gsskrb5_set_dns_canonicalize(false);
249 3632 : if (k5ret) {
250 0 : DBG_ERR("gsskrb5_set_dns_canonicalize() failed (%s)\n",
251 : error_message(k5ret));
252 0 : status = NT_STATUS_INTERNAL_ERROR;
253 0 : goto err_out;
254 : }
255 : #endif
256 :
257 : /* TODO: Should we enforce a enc_types list ?
258 : ret = krb5_set_default_tgs_ktypes(gse_ctx->k5ctx, enc_types);
259 : */
260 :
261 6339 : *_gse_ctx = gse_ctx;
262 6339 : return NT_STATUS_OK;
263 :
264 0 : err_out:
265 0 : TALLOC_FREE(gse_ctx);
266 0 : return status;
267 : }
268 :
269 2776 : static NTSTATUS gse_init_client(struct gensec_security *gensec_security,
270 : bool do_sign, bool do_seal,
271 : const char *ccache_name,
272 : const struct gss_OID_desc_struct *mech,
273 : uint32_t add_gss_c_flags,
274 : struct gse_context **_gse_ctx)
275 : {
276 0 : struct gse_context *gse_ctx;
277 0 : OM_uint32 gss_maj, gss_min;
278 : #ifdef HAVE_GSS_KRB5_CRED_NO_CI_FLAGS_X
279 2776 : gss_buffer_desc empty_buffer = GSS_C_EMPTY_BUFFER;
280 2776 : gss_OID oid = discard_const(GSS_KRB5_CRED_NO_CI_FLAGS_X);
281 : #endif
282 0 : krb5_error_code k5ret;
283 0 : NTSTATUS status;
284 :
285 2776 : status = gse_context_init(gensec_security,
286 : do_sign,
287 : do_seal,
288 : mech,
289 : add_gss_c_flags,
290 : &gse_ctx);
291 2776 : if (!NT_STATUS_IS_OK(status)) {
292 0 : return NT_STATUS_NO_MEMORY;
293 : }
294 :
295 2776 : if (ccache_name == NULL) {
296 0 : DBG_ERR("No explicit ccache_name given\n");
297 0 : return NT_STATUS_INTERNAL_ERROR;
298 : }
299 :
300 2776 : k5ret = krb5_cc_resolve(gse_ctx->k5ctx,
301 : ccache_name,
302 2776 : &gse_ctx->ccache);
303 2776 : if (k5ret) {
304 0 : DBG_WARNING("Failed to resolve credential cache '%s'! (%s)\n",
305 : ccache_name, error_message(k5ret));
306 0 : return NT_STATUS_INTERNAL_ERROR;
307 : }
308 :
309 : #ifdef SAMBA4_USES_HEIMDAL
310 : {
311 0 : int ret;
312 1807 : bool set_dns_canon = gensec_setting_bool(
313 : gensec_security->settings,
314 : "krb5", "set_dns_canonicalize",
315 : false);
316 1807 : const char *server_realm = lpcfg_realm(
317 1807 : gensec_security->settings->lp_ctx);
318 1807 : if (server_realm != NULL) {
319 1807 : ret = gsskrb5_set_default_realm(server_realm);
320 1807 : if (ret) {
321 0 : DBG_ERR("gsskrb5_set_default_realm failed\n");
322 0 : return NT_STATUS_INTERNAL_ERROR;
323 : }
324 : }
325 :
326 : /*
327 : * don't do DNS lookups of any kind, it might/will
328 : * fail for a netbios name
329 : */
330 1807 : ret = gsskrb5_set_dns_canonicalize(set_dns_canon);
331 1807 : if (ret != GSS_S_COMPLETE) {
332 0 : DBG_ERR("gsskrb5_set_dns_canonicalize failed\n");
333 0 : return NT_STATUS_INTERNAL_ERROR;
334 : }
335 : }
336 : #endif
337 :
338 : /* TODO: get krb5 ticket using username/password, if no valid
339 : * one already available in ccache */
340 :
341 2776 : gss_maj = smb_gss_krb5_import_cred(&gss_min,
342 2776 : gse_ctx->k5ctx,
343 2776 : gse_ctx->ccache,
344 : NULL, /* keytab_principal */
345 : NULL, /* keytab */
346 2776 : &gse_ctx->creds);
347 2776 : if (gss_maj) {
348 0 : char *ccache = NULL;
349 0 : int kret;
350 :
351 0 : kret = krb5_cc_get_full_name(gse_ctx->k5ctx,
352 0 : gse_ctx->ccache,
353 : &ccache);
354 0 : if (kret != 0) {
355 0 : ccache = NULL;
356 : }
357 :
358 0 : DEBUG(5, ("smb_gss_krb5_import_cred ccache[%s] failed with [%s] -"
359 : "the caller may retry after a kinit.\n",
360 : ccache, gse_errstr(gse_ctx, gss_maj, gss_min)));
361 0 : krb5_free_string(gse_ctx->k5ctx, ccache);
362 0 : status = NT_STATUS_INTERNAL_ERROR;
363 0 : goto err_out;
364 : }
365 :
366 : #ifdef HAVE_GSS_KRB5_CRED_NO_CI_FLAGS_X
367 : /*
368 : * Don't force GSS_C_CONF_FLAG and GSS_C_INTEG_FLAG.
369 : *
370 : * This allows us to disable SIGN and SEAL for
371 : * AUTH_LEVEL_CONNECT and AUTH_LEVEL_INTEGRITY.
372 : *
373 : * https://groups.yahoo.com/neo/groups/cat-ietf/conversations/topics/575
374 : * http://krbdev.mit.edu/rt/Ticket/Display.html?id=6938
375 : */
376 2776 : gss_maj = gss_set_cred_option(&gss_min, &gse_ctx->creds,
377 : oid,
378 : &empty_buffer);
379 2776 : if (gss_maj) {
380 0 : DEBUG(0, ("gss_set_cred_option(GSS_KRB5_CRED_NO_CI_FLAGS_X), "
381 : "failed with [%s]\n",
382 : gse_errstr(gse_ctx, gss_maj, gss_min)));
383 0 : status = NT_STATUS_INTERNAL_ERROR;
384 0 : goto err_out;
385 : }
386 : #endif
387 :
388 2776 : *_gse_ctx = gse_ctx;
389 2776 : return NT_STATUS_OK;
390 :
391 0 : err_out:
392 0 : TALLOC_FREE(gse_ctx);
393 0 : return status;
394 : }
395 :
396 5531 : static NTSTATUS gse_get_client_auth_token(TALLOC_CTX *mem_ctx,
397 : struct gensec_security *gensec_security,
398 : const DATA_BLOB *token_in,
399 : DATA_BLOB *token_out)
400 : {
401 0 : struct gse_context *gse_ctx =
402 5531 : talloc_get_type_abort(gensec_security->private_data,
403 : struct gse_context);
404 5531 : OM_uint32 gss_maj = 0;
405 0 : OM_uint32 gss_min;
406 0 : gss_buffer_desc in_data;
407 0 : gss_buffer_desc out_data;
408 5531 : DATA_BLOB blob = data_blob_null;
409 0 : NTSTATUS status;
410 5531 : OM_uint32 time_rec = 0;
411 0 : struct timeval tv;
412 5531 : struct cli_credentials *cli_creds = gensec_get_credentials(gensec_security);
413 5531 : const char *target_principal = gensec_get_target_principal(gensec_security);
414 5531 : const char *hostname = gensec_get_target_hostname(gensec_security);
415 5531 : const char *service = gensec_get_target_service(gensec_security);
416 5531 : const char *client_realm = cli_credentials_get_realm(cli_creds);
417 5531 : char *server_principal = NULL;
418 5531 : char *server_realm = NULL;
419 5531 : bool fallback = false;
420 5531 : OM_uint32 time_req = 0;
421 :
422 5531 : time_req = gensec_setting_int(gensec_security->settings,
423 : "gensec_gssapi",
424 : "requested_life_time",
425 : time_req);
426 :
427 5531 : in_data.value = token_in->data;
428 5531 : in_data.length = token_in->length;
429 :
430 : /*
431 : * With credentials for administrator@FOREST1.EXAMPLE.COM this patch
432 : * changes the target_principal for the ldap service of host
433 : * dc2.forest2.example.com from
434 : *
435 : * ldap/dc2.forest2.example.com@FOREST1.EXAMPLE.COM
436 : *
437 : * to
438 : *
439 : * ldap/dc2.forest2.example.com@FOREST2.EXAMPLE.COM
440 : *
441 : * Typically ldap/dc2.forest2.example.com@FOREST1.EXAMPLE.COM should be
442 : * used in order to allow the KDC of FOREST1.EXAMPLE.COM to generate a
443 : * referral ticket for krbtgt/FOREST2.EXAMPLE.COM@FOREST1.EXAMPLE.COM.
444 : *
445 : * The problem is that KDCs only return such referral tickets if
446 : * there's a forest trust between FOREST1.EXAMPLE.COM and
447 : * FOREST2.EXAMPLE.COM. If there's only an external domain trust
448 : * between FOREST1.EXAMPLE.COM and FOREST2.EXAMPLE.COM the KDC of
449 : * FOREST1.EXAMPLE.COM will respond with S_PRINCIPAL_UNKNOWN when being
450 : * asked for ldap/dc2.forest2.example.com@FOREST1.EXAMPLE.COM.
451 : *
452 : * In the case of an external trust the client can still ask explicitly
453 : * for krbtgt/FOREST2.EXAMPLE.COM@FOREST1.EXAMPLE.COM and the KDC of
454 : * FOREST1.EXAMPLE.COM will generate it.
455 : *
456 : * From there the client can use the
457 : * krbtgt/FOREST2.EXAMPLE.COM@FOREST1.EXAMPLE.COM ticket and ask a KDC
458 : * of FOREST2.EXAMPLE.COM for a service ticket for
459 : * ldap/dc2.forest2.example.com@FOREST2.EXAMPLE.COM.
460 : *
461 : * With Heimdal we'll get the fallback on S_PRINCIPAL_UNKNOWN behavior
462 : * when we pass ldap/dc2.forest2.example.com@FOREST2.EXAMPLE.COM as
463 : * target principal. As _krb5_get_cred_kdc_any() first calls
464 : * get_cred_kdc_referral() (which always starts with the client realm)
465 : * and falls back to get_cred_kdc_capath() (which starts with the given
466 : * realm).
467 : *
468 : * MIT krb5 only tries the given realm of the target principal, if we
469 : * want to autodetect support for transitive forest trusts, would have
470 : * to do the fallback ourself.
471 : */
472 : #ifndef SAMBA4_USES_HEIMDAL
473 1928 : if (gse_ctx->server_name == NULL) {
474 969 : OM_uint32 gss_min2 = 0;
475 :
476 969 : status = gse_setup_server_principal(mem_ctx,
477 : target_principal,
478 : service,
479 : hostname,
480 : client_realm,
481 : &server_principal,
482 : &gse_ctx->server_name);
483 969 : if (!NT_STATUS_IS_OK(status)) {
484 0 : return status;
485 : }
486 :
487 1938 : gss_maj = gss_init_sec_context(&gss_min,
488 : gse_ctx->creds,
489 : &gse_ctx->gssapi_context,
490 : gse_ctx->server_name,
491 969 : &gse_ctx->gss_mech,
492 : gse_ctx->gss_want_flags,
493 : time_req,
494 : gse_ctx->channel_bindings,
495 : &in_data,
496 : NULL,
497 : &out_data,
498 : &gse_ctx->gss_got_flags,
499 : &time_rec);
500 969 : if (gss_maj != GSS_S_FAILURE) {
501 947 : goto init_sec_context_done;
502 : }
503 22 : if (gss_min != (OM_uint32)KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN) {
504 0 : goto init_sec_context_done;
505 : }
506 22 : if (target_principal != NULL) {
507 0 : goto init_sec_context_done;
508 : }
509 :
510 22 : fallback = true;
511 22 : TALLOC_FREE(server_principal);
512 22 : gss_release_name(&gss_min2, &gse_ctx->server_name);
513 : }
514 : #endif /* !SAMBA4_USES_HEIMDAL */
515 :
516 4584 : if (gse_ctx->server_name == NULL) {
517 1829 : server_realm = smb_krb5_get_realm_from_hostname(mem_ctx,
518 : hostname,
519 : client_realm);
520 1829 : if (server_realm == NULL) {
521 0 : return NT_STATUS_NO_MEMORY;
522 : }
523 :
524 1851 : if (fallback &&
525 22 : strequal(client_realm, server_realm)) {
526 0 : goto init_sec_context_done;
527 : }
528 :
529 1829 : status = gse_setup_server_principal(mem_ctx,
530 : target_principal,
531 : service,
532 : hostname,
533 : server_realm,
534 : &server_principal,
535 : &gse_ctx->server_name);
536 1829 : TALLOC_FREE(server_realm);
537 1829 : if (!NT_STATUS_IS_OK(status)) {
538 0 : return status;
539 : }
540 :
541 1829 : TALLOC_FREE(server_principal);
542 : }
543 :
544 9168 : gss_maj = gss_init_sec_context(&gss_min,
545 3603 : gse_ctx->creds,
546 : &gse_ctx->gssapi_context,
547 3603 : gse_ctx->server_name,
548 4584 : &gse_ctx->gss_mech,
549 : gse_ctx->gss_want_flags,
550 : time_req,
551 : gse_ctx->channel_bindings,
552 : &in_data, NULL, &out_data,
553 : &gse_ctx->gss_got_flags, &time_rec);
554 4584 : goto init_sec_context_done;
555 : /* JUMP! */
556 5531 : init_sec_context_done:
557 :
558 5531 : switch (gss_maj) {
559 2755 : case GSS_S_COMPLETE:
560 : /* we are done with it */
561 2755 : tv = timeval_current_ofs(time_rec, 0);
562 2755 : gse_ctx->expire_time = timeval_to_nttime(&tv);
563 :
564 2755 : status = NT_STATUS_OK;
565 2755 : break;
566 2772 : case GSS_S_CONTINUE_NEEDED:
567 : /* we will need a third leg */
568 2772 : status = NT_STATUS_MORE_PROCESSING_REQUIRED;
569 2772 : break;
570 0 : case GSS_S_CONTEXT_EXPIRED:
571 : /* Make SPNEGO ignore us, we can't go any further here */
572 0 : DBG_NOTICE("Context expired\n");
573 0 : status = NT_STATUS_INVALID_PARAMETER;
574 4 : goto done;
575 4 : case GSS_S_FAILURE:
576 4 : switch (gss_min) {
577 2 : case (OM_uint32)KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN: {
578 2 : gss_buffer_desc name_token = {
579 : .length = 0,
580 : };
581 :
582 2 : gss_maj = gss_display_name(&gss_min,
583 0 : gse_ctx->server_name,
584 : &name_token,
585 : NULL);
586 2 : if (gss_maj == GSS_S_COMPLETE) {
587 2 : DBG_NOTICE("Server principal %.*s not found\n",
588 : (int)name_token.length,
589 : (char *)name_token.value);
590 2 : gss_release_buffer(&gss_maj, &name_token);
591 : } else {
592 0 : DBG_NOTICE("Server principal not found\n");
593 : }
594 :
595 : /* Make SPNEGO ignore us, we can't go any further here */
596 2 : status = NT_STATUS_INVALID_PARAMETER;
597 2 : goto done;
598 : }
599 0 : case (OM_uint32)KRB5KRB_AP_ERR_TKT_EXPIRED:
600 0 : DBG_NOTICE("Ticket expired\n");
601 : /* Make SPNEGO ignore us, we can't go any further here */
602 0 : status = NT_STATUS_INVALID_PARAMETER;
603 0 : goto done;
604 0 : case (OM_uint32)KRB5KRB_AP_ERR_TKT_NYV:
605 0 : DBG_NOTICE("Clockskew\n");
606 : /* Make SPNEGO ignore us, we can't go any further here */
607 0 : status = NT_STATUS_TIME_DIFFERENCE_AT_DC;
608 0 : goto done;
609 0 : case (OM_uint32)KRB5_KDC_UNREACH:
610 0 : DBG_NOTICE("KDC unreachable\n");
611 : /* Make SPNEGO ignore us, we can't go any further here */
612 0 : status = NT_STATUS_NO_LOGON_SERVERS;
613 0 : goto done;
614 0 : case (OM_uint32)KRB5KRB_AP_ERR_MSG_TYPE:
615 : /* Garbage input, possibly from the auto-mech detection */
616 0 : status = NT_STATUS_INVALID_PARAMETER;
617 0 : goto done;
618 0 : case (OM_uint32)KRB5KDC_ERR_ETYPE_NOSUPP:
619 0 : status = NT_STATUS_KDC_UNKNOWN_ETYPE;
620 0 : goto done;
621 2 : default:
622 2 : DBG_ERR("gss_init_sec_context failed with [%s](%u)\n",
623 : gse_errstr(talloc_tos(), gss_maj, gss_min),
624 : gss_min);
625 2 : status = NT_STATUS_LOGON_FAILURE;
626 2 : goto done;
627 : }
628 0 : break;
629 0 : default:
630 0 : DBG_ERR("gss_init_sec_context failed with [%s]\n",
631 : gse_errstr(talloc_tos(), gss_maj, gss_min));
632 0 : status = NT_STATUS_INTERNAL_ERROR;
633 0 : goto done;
634 : }
635 :
636 : /* we may be told to return nothing */
637 5527 : if (out_data.length) {
638 2799 : blob = data_blob_talloc(mem_ctx, out_data.value, out_data.length);
639 2799 : if (!blob.data) {
640 0 : status = NT_STATUS_NO_MEMORY;
641 : }
642 :
643 2799 : gss_release_buffer(&gss_min, &out_data);
644 : }
645 :
646 2728 : done:
647 5531 : *token_out = blob;
648 5531 : return status;
649 : }
650 :
651 3563 : static NTSTATUS gse_init_server(struct gensec_security *gensec_security,
652 : bool do_sign, bool do_seal,
653 : const struct gss_OID_desc_struct *mech,
654 : uint32_t add_gss_c_flags,
655 : struct gse_context **_gse_ctx)
656 : {
657 0 : struct gse_context *gse_ctx;
658 0 : OM_uint32 gss_maj, gss_min;
659 0 : krb5_error_code ret;
660 0 : NTSTATUS status;
661 :
662 3563 : status = gse_context_init(gensec_security,
663 : do_sign,
664 : do_seal,
665 : mech,
666 : add_gss_c_flags,
667 : &gse_ctx);
668 3563 : if (!NT_STATUS_IS_OK(status)) {
669 0 : return NT_STATUS_NO_MEMORY;
670 : }
671 :
672 3563 : ret = gse_krb5_get_server_keytab(gse_ctx->k5ctx,
673 3563 : &gse_ctx->keytab);
674 3563 : if (ret) {
675 10 : status = NT_STATUS_INTERNAL_ERROR;
676 10 : goto done;
677 : }
678 :
679 : /* This creates a GSSAPI cred_id_t with the keytab set */
680 3553 : gss_maj = smb_gss_mech_import_cred(&gss_min, gse_ctx->k5ctx,
681 3553 : NULL, NULL, gse_ctx->keytab,
682 3553 : &gse_ctx->gss_mech,
683 3553 : &gse_ctx->creds);
684 :
685 3553 : if (gss_maj != 0) {
686 0 : DEBUG(0, ("smb_gss_krb5_import_cred failed with [%s]\n",
687 : gse_errstr(gse_ctx, gss_maj, gss_min)));
688 0 : status = NT_STATUS_INTERNAL_ERROR;
689 0 : goto done;
690 : }
691 :
692 3553 : status = NT_STATUS_OK;
693 :
694 3563 : done:
695 3563 : if (!NT_STATUS_IS_OK(status)) {
696 10 : TALLOC_FREE(gse_ctx);
697 : }
698 :
699 3563 : *_gse_ctx = gse_ctx;
700 3563 : return status;
701 : }
702 :
703 1011 : static NTSTATUS gse_get_server_auth_token(TALLOC_CTX *mem_ctx,
704 : struct gensec_security *gensec_security,
705 : const DATA_BLOB *token_in,
706 : DATA_BLOB *token_out)
707 : {
708 0 : struct gse_context *gse_ctx =
709 1011 : talloc_get_type_abort(gensec_security->private_data,
710 : struct gse_context);
711 0 : OM_uint32 gss_maj, gss_min;
712 0 : gss_buffer_desc in_data;
713 0 : gss_buffer_desc out_data;
714 1011 : DATA_BLOB blob = data_blob_null;
715 0 : NTSTATUS status;
716 1011 : OM_uint32 time_rec = 0;
717 0 : struct timeval tv;
718 :
719 1011 : in_data.value = token_in->data;
720 1011 : in_data.length = token_in->length;
721 :
722 1011 : gss_maj = gss_accept_sec_context(&gss_min,
723 : &gse_ctx->gssapi_context,
724 535 : gse_ctx->creds,
725 : &in_data,
726 : gse_ctx->channel_bindings,
727 : &gse_ctx->client_name,
728 : &gse_ctx->ret_mech,
729 : &out_data,
730 : &gse_ctx->gss_got_flags,
731 : &time_rec,
732 : &gse_ctx->delegated_cred_handle);
733 : #ifdef GSS_C_CHANNEL_BOUND_FLAG
734 953 : if (gss_maj == GSS_S_COMPLETE &&
735 853 : gensec_security->channel_bindings != NULL &&
736 0 : !(gensec_security->want_features & GENSEC_FEATURE_CB_OPTIONAL) &&
737 0 : !(gse_ctx->gss_got_flags & GSS_C_CHANNEL_BOUND_FLAG))
738 : {
739 : /*
740 : * If we require valid channel bindings
741 : * we need to check the client provided
742 : * them.
743 : *
744 : * We detect this if
745 : * GSS_C_CHANNEL_BOUND_FLAG is given.
746 : *
747 : * Recent heimdal and MIT releases support this
748 : * with older releases (e.g. MIT > 1.19).
749 : *
750 : * It means client with zero channel bindings
751 : * on a server with non-zero channel bindings
752 : * won't generate GSS_S_BAD_BINDINGS directly
753 : * unless KERB_AP_OPTIONS_CBT was also
754 : * provides by the client.
755 : *
756 : * So we need to convert a missing
757 : * GSS_C_CHANNEL_BOUND_FLAG into
758 : * GSS_S_BAD_BINDINGS by default
759 : * (unless GENSEC_FEATURE_CB_OPTIONAL is given).
760 : */
761 0 : gss_maj = GSS_S_BAD_BINDINGS;
762 0 : gss_min = 0;
763 : }
764 : #endif /* GSS_C_CHANNEL_BOUND_FLAG */
765 :
766 1011 : switch (gss_maj) {
767 896 : case GSS_S_COMPLETE:
768 : /* we are done with it */
769 896 : tv = timeval_current_ofs(time_rec, 0);
770 896 : gse_ctx->expire_time = timeval_to_nttime(&tv);
771 :
772 896 : status = NT_STATUS_OK;
773 1011 : break;
774 115 : case GSS_S_CONTINUE_NEEDED:
775 : /* we will need a third leg */
776 115 : status = NT_STATUS_MORE_PROCESSING_REQUIRED;
777 115 : break;
778 0 : case GSS_S_BAD_BINDINGS:
779 0 : DBG_WARNING("Got GSS_S_BAD_BINDINGS\n");
780 0 : status = NT_STATUS_BAD_BINDINGS;
781 0 : goto done;
782 0 : default:
783 0 : DEBUG(1, ("gss_accept_sec_context failed with [%s]\n",
784 : gse_errstr(talloc_tos(), gss_maj, gss_min)));
785 :
786 0 : if (gse_ctx->gssapi_context) {
787 0 : gss_delete_sec_context(&gss_min,
788 : &gse_ctx->gssapi_context,
789 : GSS_C_NO_BUFFER);
790 : }
791 :
792 : /*
793 : * If we got an output token, make Windows aware of it
794 : * by telling it that more processing is needed
795 : */
796 0 : if (out_data.length > 0) {
797 0 : status = NT_STATUS_MORE_PROCESSING_REQUIRED;
798 : /* Fall through to handle the out token */
799 : } else {
800 0 : status = NT_STATUS_LOGON_FAILURE;
801 0 : goto done;
802 : }
803 : }
804 :
805 : /* we may be told to return nothing */
806 1011 : if (out_data.length) {
807 896 : blob = data_blob_talloc(mem_ctx, out_data.value, out_data.length);
808 896 : if (!blob.data) {
809 0 : status = NT_STATUS_NO_MEMORY;
810 : }
811 896 : gss_release_buffer(&gss_min, &out_data);
812 : }
813 :
814 :
815 115 : done:
816 1011 : *token_out = blob;
817 1011 : return status;
818 : }
819 :
820 2 : static char *gse_errstr(TALLOC_CTX *mem_ctx, OM_uint32 maj, OM_uint32 min)
821 : {
822 0 : OM_uint32 gss_min, gss_maj;
823 0 : gss_buffer_desc msg_min;
824 0 : gss_buffer_desc msg_maj;
825 2 : OM_uint32 msg_ctx = 0;
826 :
827 2 : char *errstr = NULL;
828 :
829 2 : ZERO_STRUCT(msg_min);
830 2 : ZERO_STRUCT(msg_maj);
831 :
832 2 : gss_maj = gss_display_status(&gss_min, maj, GSS_C_GSS_CODE,
833 : GSS_C_NO_OID, &msg_ctx, &msg_maj);
834 2 : if (gss_maj) {
835 0 : goto done;
836 : }
837 2 : errstr = talloc_strndup(mem_ctx,
838 2 : (char *)msg_maj.value,
839 : msg_maj.length);
840 2 : if (!errstr) {
841 0 : goto done;
842 : }
843 2 : gss_maj = gss_display_status(&gss_min, min, GSS_C_MECH_CODE,
844 : (gss_OID)discard_const(gss_mech_krb5),
845 : &msg_ctx, &msg_min);
846 2 : if (gss_maj) {
847 0 : goto done;
848 : }
849 :
850 2 : errstr = talloc_strdup_append_buffer(errstr, ": ");
851 2 : if (!errstr) {
852 0 : goto done;
853 : }
854 2 : errstr = talloc_strndup_append_buffer(errstr,
855 2 : (char *)msg_min.value,
856 : msg_min.length);
857 2 : if (!errstr) {
858 0 : goto done;
859 : }
860 :
861 2 : done:
862 2 : if (msg_min.value) {
863 2 : gss_release_buffer(&gss_min, &msg_min);
864 : }
865 2 : if (msg_maj.value) {
866 2 : gss_release_buffer(&gss_min, &msg_maj);
867 : }
868 2 : return errstr;
869 : }
870 :
871 : struct gensec_gse_client_prepare_krb5_ccache {
872 : krb5_context kctx;
873 : krb5_ccache id;
874 : char *name;
875 : };
876 :
877 2355 : static int gensec_gse_client_prepare_krb5_ccache_destructor(
878 : struct gensec_gse_client_prepare_krb5_ccache *ccache)
879 : {
880 2355 : if (ccache->id != NULL) {
881 2355 : krb5_cc_destroy(ccache->kctx, ccache->id);
882 2355 : ccache->id = NULL;
883 : }
884 :
885 2355 : if (ccache->kctx != NULL) {
886 2355 : krb5_free_context(ccache->kctx);
887 2355 : ccache->kctx = NULL;
888 : }
889 :
890 2355 : return 0;
891 : }
892 :
893 2481 : static NTSTATUS gensec_gse_client_prepare_krb5_ccache_create(TALLOC_CTX *mem_ctx,
894 : struct gensec_gse_client_prepare_krb5_ccache **_ccache)
895 : {
896 2481 : struct gensec_gse_client_prepare_krb5_ccache *ccache = NULL;
897 0 : int ret;
898 :
899 2481 : *_ccache = NULL;
900 :
901 2481 : ccache = talloc_zero(mem_ctx, struct gensec_gse_client_prepare_krb5_ccache);
902 2481 : if (ccache == NULL) {
903 0 : return NT_STATUS_NO_MEMORY;
904 : }
905 :
906 2481 : talloc_set_destructor(ccache,
907 : gensec_gse_client_prepare_krb5_ccache_destructor);
908 :
909 2481 : ret = smb_krb5_init_context_common(&ccache->kctx);
910 2481 : if (ret != 0) {
911 0 : TALLOC_FREE(ccache);
912 0 : return krb5_to_nt_status(ret);
913 : }
914 :
915 2481 : ret = smb_krb5_cc_new_unique_memory(ccache->kctx,
916 : ccache,
917 : &ccache->name,
918 : &ccache->id);
919 2481 : if (ret != 0) {
920 0 : TALLOC_FREE(ccache);
921 0 : return krb5_to_nt_status(ret);
922 : }
923 :
924 2481 : *_ccache = ccache;
925 2481 : return NT_STATUS_OK;
926 : }
927 :
928 3215 : static NTSTATUS gensec_gse_client_prepare_ccache(struct gensec_security *gensec,
929 : const char **_ccache_name)
930 : {
931 3215 : TALLOC_CTX *frame = talloc_stackframe();
932 3215 : struct cli_credentials *creds = gensec_get_credentials(gensec);
933 3215 : enum credentials_use_kerberos krb5_state = CRED_USE_KERBEROS_REQUIRED;
934 3215 : enum credentials_obtained user_obtained = CRED_UNINITIALISED;
935 3215 : const char *user_principal = NULL;
936 3215 : const char *debug_username = NULL;
937 3215 : const char *debug_target = NULL;
938 3215 : enum credentials_obtained pass_obtained = CRED_UNINITIALISED;
939 3215 : const char *pass = NULL;
940 3215 : bool ccache_valid = false;
941 3215 : enum credentials_obtained ccache_obtained = CRED_UNINITIALISED;
942 3215 : char *e_ccache_name = NULL;
943 3215 : struct gensec_gse_client_prepare_krb5_ccache *ccache = NULL;
944 3215 : const char *error_string = NULL;
945 3215 : char *canon_principal = NULL;
946 3215 : char *canon_realm = NULL;
947 0 : NTSTATUS status;
948 0 : int ret;
949 3215 : int dbg_fail_lvl = DBGLVL_NOTICE;
950 3215 : bool may_ignore_krb5 = true;
951 :
952 3215 : debug_username = cli_credentials_get_unparsed_name(creds, frame);
953 3215 : debug_target = gensec_get_unparsed_target_principal(gensec, frame);
954 :
955 3215 : krb5_state = cli_credentials_get_kerberos_state(creds);
956 3215 : if (krb5_state == CRED_USE_KERBEROS_REQUIRED) {
957 417 : DBG_DEBUG("Kerberos required username[%s]\n",
958 : debug_username);
959 417 : dbg_fail_lvl = DBGLVL_ERR;
960 417 : may_ignore_krb5 = false;
961 : }
962 :
963 3215 : pass_obtained = cli_credentials_get_password_obtained(creds);
964 3215 : ccache_valid = cli_credentials_get_ccache_name_obtained(creds,
965 : gensec,
966 : &e_ccache_name,
967 : &ccache_obtained);
968 3215 : if (ccache_valid && ccache_obtained >= pass_obtained) {
969 726 : DBG_INFO("No kinit required for %s to access %s, %s\n",
970 : debug_username, debug_target, e_ccache_name);
971 726 : *_ccache_name = e_ccache_name;
972 726 : TALLOC_FREE(frame);
973 726 : return NT_STATUS_OK;
974 : }
975 2489 : TALLOC_FREE(e_ccache_name);
976 :
977 : /*
978 : * gensec_kerberos_possible() already checked
979 : * cli_credentials_get_principal() worked
980 : */
981 2489 : user_principal = cli_credentials_get_principal_and_obtained(creds,
982 : frame,
983 : &user_obtained);
984 2489 : if (user_principal == NULL) {
985 0 : TALLOC_FREE(frame);
986 0 : return NT_STATUS_NO_MEMORY;
987 : }
988 :
989 2489 : pass = cli_credentials_get_password(creds);
990 2489 : if (pass == NULL) {
991 8 : DBG_PREFIX(dbg_fail_lvl, (
992 : "No password for user principal[%s]\n",
993 : user_principal));
994 8 : TALLOC_FREE(frame);
995 8 : if (may_ignore_krb5) {
996 0 : return NT_STATUS_INVALID_PARAMETER;
997 : }
998 8 : return NT_STATUS_WRONG_CREDENTIAL_HANDLE;
999 : }
1000 :
1001 2481 : status = gensec_gse_client_prepare_krb5_ccache_create(creds,
1002 : &ccache);
1003 2481 : if (!NT_STATUS_IS_OK(status)) {
1004 0 : DBG_ERR("gensec_gse_client_prepare_krb5_ccache_create(): %s\n",
1005 : nt_errstr(status));
1006 0 : TALLOC_FREE(frame);
1007 0 : return status;
1008 : }
1009 : /* cleanup via frame on error */
1010 2481 : talloc_reparent(creds, frame, ccache);
1011 :
1012 2481 : DBG_INFO("Doing kinit for %s to access %s into %s\n",
1013 : user_principal, debug_target, ccache->name);
1014 :
1015 2481 : ret = kerberos_kinit_password_ext(user_principal,
1016 : pass,
1017 : 0,
1018 : 0,
1019 : 0,
1020 2481 : ccache->name,
1021 : false,
1022 : false,
1023 : 0,
1024 : frame,
1025 : &canon_principal,
1026 : &canon_realm,
1027 : NULL);
1028 2481 : if (ret != 0) {
1029 431 : switch (ret) {
1030 18 : case KRB5KDC_ERR_PREAUTH_FAILED:
1031 : case KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN:
1032 : case KRB5KRB_AP_ERR_BAD_INTEGRITY:
1033 : /*
1034 : * If the fail to authenticate a
1035 : * valid user
1036 : */
1037 18 : dbg_fail_lvl = DBGLVL_ERR;
1038 18 : may_ignore_krb5 = false;
1039 18 : status = NT_STATUS_LOGON_FAILURE;
1040 18 : break;
1041 2 : case KRB5KDC_ERR_CLIENT_REVOKED:
1042 : /*
1043 : * If the fail to authenticate a
1044 : * valid user
1045 : */
1046 2 : dbg_fail_lvl = DBGLVL_ERR;
1047 2 : may_ignore_krb5 = false;
1048 2 : status = NT_STATUS_ACCOUNT_LOCKED_OUT;
1049 2 : break;
1050 405 : case KRB5_REALM_UNKNOWN:
1051 : case KRB5_KDC_UNREACH:
1052 405 : status = NT_STATUS_NO_LOGON_SERVERS;
1053 405 : break;
1054 6 : default:
1055 6 : status = krb5_to_nt_status(ret);
1056 6 : break;
1057 : }
1058 :
1059 431 : DBG_PREFIX(dbg_fail_lvl, (
1060 : "Kinit for %s to access %s failed: %s: %s\n",
1061 : user_principal,
1062 : debug_target,
1063 : error_message(ret), nt_errstr(status)));
1064 431 : TALLOC_FREE(frame);
1065 431 : if (may_ignore_krb5) {
1066 411 : return NT_STATUS_INVALID_PARAMETER;
1067 : }
1068 20 : return status;
1069 : }
1070 :
1071 2050 : ret = cli_credentials_set_ccache(creds,
1072 2050 : gensec->settings->lp_ctx,
1073 2050 : ccache->name,
1074 : CRED_SPECIFIED,
1075 : &error_string);
1076 2050 : if (ret != 0) {
1077 0 : DBG_ERR("cli_credentials_set_ccache(%s) "
1078 : "for %s to access %s failed: %s\n",
1079 : ccache->name,
1080 : user_principal,
1081 : debug_target,
1082 : error_string);
1083 0 : TALLOC_FREE(frame);
1084 0 : return krb5_to_nt_status(ret);
1085 : }
1086 :
1087 2050 : DBG_DEBUG("Successfully kinit as %s (%s) to access %s into %s\n",
1088 : user_principal,
1089 : canon_principal,
1090 : debug_target,
1091 : ccache->name);
1092 :
1093 : /*
1094 : * keep the ccache for the lifetime
1095 : * of creds
1096 : */
1097 2050 : *_ccache_name = ccache->name;
1098 :
1099 2050 : talloc_move(creds, &ccache);
1100 :
1101 2050 : TALLOC_FREE(frame);
1102 2050 : return NT_STATUS_OK;
1103 : }
1104 :
1105 17589 : static NTSTATUS gensec_gse_client_start(struct gensec_security *gensec_security)
1106 : {
1107 0 : struct gse_context *gse_ctx;
1108 17589 : struct cli_credentials *creds = gensec_get_credentials(gensec_security);
1109 0 : NTSTATUS nt_status;
1110 17589 : OM_uint32 want_flags = 0;
1111 17589 : bool do_sign = false, do_seal = false;
1112 17589 : const char *ccache_name = NULL;
1113 :
1114 17589 : nt_status = gensec_kerberos_possible(gensec_security);
1115 17589 : if (!NT_STATUS_IS_OK(nt_status)) {
1116 14374 : char *target_name = NULL;
1117 14374 : char *cred_name = NULL;
1118 :
1119 14374 : target_name = gensec_get_unparsed_target_principal(gensec_security,
1120 : gensec_security);
1121 14374 : cred_name = cli_credentials_get_unparsed_name(creds,
1122 : gensec_security);
1123 :
1124 14374 : DBG_NOTICE("Not using kerberos to %s as %s: %s\n",
1125 : target_name, cred_name, nt_errstr(nt_status));
1126 :
1127 14374 : TALLOC_FREE(target_name);
1128 14374 : TALLOC_FREE(cred_name);
1129 14374 : return nt_status;
1130 : }
1131 :
1132 3215 : nt_status = gensec_gse_client_prepare_ccache(gensec_security,
1133 : &ccache_name);
1134 3215 : if (!NT_STATUS_IS_OK(nt_status)) {
1135 439 : return nt_status;
1136 : }
1137 :
1138 2776 : if (gensec_security->want_features & GENSEC_FEATURE_SESSION_KEY) {
1139 2354 : do_sign = true;
1140 : }
1141 2776 : if (gensec_security->want_features & GENSEC_FEATURE_SIGN) {
1142 406 : do_sign = true;
1143 : }
1144 2776 : if (gensec_security->want_features & GENSEC_FEATURE_SEAL) {
1145 380 : do_seal = true;
1146 : }
1147 2776 : if (gensec_security->want_features & GENSEC_FEATURE_DCE_STYLE) {
1148 27 : want_flags |= GSS_C_DCE_STYLE;
1149 : }
1150 :
1151 : #ifdef HAVE_CLIENT_GSS_C_CHANNEL_BOUND_FLAG
1152 : /*
1153 : * We can only use GSS_C_CHANNEL_BOUND_FLAG if the kerberos library
1154 : * supports that in order to add KERB_AP_OPTIONS_CBT.
1155 : *
1156 : * See:
1157 : * https://github.com/heimdal/heimdal/pull/1234
1158 : * https://github.com/krb5/krb5/pull/1329
1159 : */
1160 1780 : if (!(gensec_security->want_features & GENSEC_FEATURE_CB_OPTIONAL)) {
1161 1780 : want_flags |= GSS_C_CHANNEL_BOUND_FLAG;
1162 : }
1163 : #endif
1164 :
1165 2776 : nt_status = gse_init_client(gensec_security,
1166 : do_sign,
1167 : do_seal,
1168 : ccache_name,
1169 : gss_mech_krb5,
1170 : want_flags,
1171 : &gse_ctx);
1172 2776 : if (!NT_STATUS_IS_OK(nt_status)) {
1173 0 : return nt_status;
1174 : }
1175 2776 : gensec_security->private_data = gse_ctx;
1176 2776 : return NT_STATUS_OK;
1177 : }
1178 :
1179 3563 : static NTSTATUS gensec_gse_server_start(struct gensec_security *gensec_security)
1180 : {
1181 0 : struct gse_context *gse_ctx;
1182 0 : NTSTATUS nt_status;
1183 3563 : OM_uint32 want_flags = 0;
1184 3563 : bool do_sign = false, do_seal = false;
1185 :
1186 3563 : if (gensec_security->want_features & GENSEC_FEATURE_SIGN) {
1187 18 : do_sign = true;
1188 : }
1189 3563 : if (gensec_security->want_features & GENSEC_FEATURE_SEAL) {
1190 18 : do_seal = true;
1191 : }
1192 3563 : if (gensec_security->want_features & GENSEC_FEATURE_DCE_STYLE) {
1193 115 : want_flags |= GSS_C_DCE_STYLE;
1194 : }
1195 :
1196 3563 : nt_status = gse_init_server(gensec_security,
1197 : do_sign,
1198 : do_seal,
1199 : gss_mech_krb5,
1200 : want_flags,
1201 : &gse_ctx);
1202 3563 : if (!NT_STATUS_IS_OK(nt_status)) {
1203 10 : return nt_status;
1204 : }
1205 3553 : gensec_security->private_data = gse_ctx;
1206 3553 : return NT_STATUS_OK;
1207 : }
1208 :
1209 : struct gensec_gse_update_state {
1210 : NTSTATUS status;
1211 : DATA_BLOB out;
1212 : };
1213 :
1214 : static NTSTATUS gensec_gse_update_internal(struct gensec_security *gensec_security,
1215 : TALLOC_CTX *mem_ctx,
1216 : const DATA_BLOB in,
1217 : DATA_BLOB *out);
1218 :
1219 6542 : static struct tevent_req *gensec_gse_update_send(TALLOC_CTX *mem_ctx,
1220 : struct tevent_context *ev,
1221 : struct gensec_security *gensec_security,
1222 : const DATA_BLOB in)
1223 : {
1224 6542 : struct tevent_req *req = NULL;
1225 6542 : struct gensec_gse_update_state *state = NULL;
1226 0 : NTSTATUS status;
1227 :
1228 6542 : req = tevent_req_create(mem_ctx, &state,
1229 : struct gensec_gse_update_state);
1230 6542 : if (req == NULL) {
1231 0 : return NULL;
1232 : }
1233 :
1234 6542 : status = gensec_gse_update_internal(gensec_security,
1235 : state, in,
1236 6542 : &state->out);
1237 6542 : state->status = status;
1238 6542 : if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1239 2887 : tevent_req_done(req);
1240 2887 : return tevent_req_post(req, ev);
1241 : }
1242 3655 : if (tevent_req_nterror(req, status)) {
1243 4 : return tevent_req_post(req, ev);
1244 : }
1245 :
1246 3651 : tevent_req_done(req);
1247 3651 : return tevent_req_post(req, ev);
1248 : }
1249 :
1250 6542 : static NTSTATUS gensec_gse_update_internal(struct gensec_security *gensec_security,
1251 : TALLOC_CTX *mem_ctx,
1252 : const DATA_BLOB in,
1253 : DATA_BLOB *out)
1254 : {
1255 0 : NTSTATUS status;
1256 :
1257 6542 : switch (gensec_security->gensec_role) {
1258 5531 : case GENSEC_CLIENT:
1259 5531 : status = gse_get_client_auth_token(mem_ctx,
1260 : gensec_security,
1261 : &in, out);
1262 5531 : break;
1263 1011 : case GENSEC_SERVER:
1264 1011 : status = gse_get_server_auth_token(mem_ctx,
1265 : gensec_security,
1266 : &in, out);
1267 1011 : break;
1268 : }
1269 6542 : if (!NT_STATUS_IS_OK(status)) {
1270 2891 : return status;
1271 : }
1272 :
1273 3651 : return NT_STATUS_OK;
1274 : }
1275 :
1276 6542 : static NTSTATUS gensec_gse_update_recv(struct tevent_req *req,
1277 : TALLOC_CTX *out_mem_ctx,
1278 : DATA_BLOB *out)
1279 : {
1280 0 : struct gensec_gse_update_state *state =
1281 6542 : tevent_req_data(req,
1282 : struct gensec_gse_update_state);
1283 0 : NTSTATUS status;
1284 :
1285 6542 : *out = data_blob_null;
1286 :
1287 6542 : if (tevent_req_is_nterror(req, &status)) {
1288 4 : tevent_req_received(req);
1289 4 : return status;
1290 : }
1291 :
1292 6538 : *out = state->out;
1293 6538 : talloc_steal(out_mem_ctx, state->out.data);
1294 6538 : status = state->status;
1295 6538 : tevent_req_received(req);
1296 6538 : return status;
1297 : }
1298 :
1299 1572 : static NTSTATUS gensec_gse_wrap(struct gensec_security *gensec_security,
1300 : TALLOC_CTX *mem_ctx,
1301 : const DATA_BLOB *in,
1302 : DATA_BLOB *out)
1303 : {
1304 0 : struct gse_context *gse_ctx =
1305 1572 : talloc_get_type_abort(gensec_security->private_data,
1306 : struct gse_context);
1307 0 : OM_uint32 maj_stat, min_stat;
1308 0 : gss_buffer_desc input_token, output_token;
1309 0 : int conf_state;
1310 1572 : input_token.length = in->length;
1311 1572 : input_token.value = in->data;
1312 :
1313 1572 : maj_stat = gss_wrap(&min_stat,
1314 814 : gse_ctx->gssapi_context,
1315 1572 : gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL),
1316 : GSS_C_QOP_DEFAULT,
1317 : &input_token,
1318 : &conf_state,
1319 : &output_token);
1320 1572 : if (GSS_ERROR(maj_stat)) {
1321 0 : DEBUG(0, ("gensec_gse_wrap: GSS Wrap failed: %s\n",
1322 : gse_errstr(talloc_tos(), maj_stat, min_stat)));
1323 0 : return NT_STATUS_ACCESS_DENIED;
1324 : }
1325 :
1326 1572 : *out = data_blob_talloc(mem_ctx, output_token.value, output_token.length);
1327 1572 : gss_release_buffer(&min_stat, &output_token);
1328 :
1329 1572 : if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)
1330 1572 : && !conf_state) {
1331 0 : return NT_STATUS_ACCESS_DENIED;
1332 : }
1333 1572 : return NT_STATUS_OK;
1334 : }
1335 :
1336 1272 : static NTSTATUS gensec_gse_unwrap(struct gensec_security *gensec_security,
1337 : TALLOC_CTX *mem_ctx,
1338 : const DATA_BLOB *in,
1339 : DATA_BLOB *out)
1340 : {
1341 0 : struct gse_context *gse_ctx =
1342 1272 : talloc_get_type_abort(gensec_security->private_data,
1343 : struct gse_context);
1344 0 : OM_uint32 maj_stat, min_stat;
1345 0 : gss_buffer_desc input_token, output_token;
1346 0 : int conf_state;
1347 0 : gss_qop_t qop_state;
1348 1272 : input_token.length = in->length;
1349 1272 : input_token.value = in->data;
1350 :
1351 1272 : maj_stat = gss_unwrap(&min_stat,
1352 660 : gse_ctx->gssapi_context,
1353 : &input_token,
1354 : &output_token,
1355 : &conf_state,
1356 : &qop_state);
1357 1272 : if (GSS_ERROR(maj_stat)) {
1358 0 : DEBUG(0, ("gensec_gse_unwrap: GSS UnWrap failed: %s\n",
1359 : gse_errstr(talloc_tos(), maj_stat, min_stat)));
1360 0 : return NT_STATUS_ACCESS_DENIED;
1361 : }
1362 :
1363 1272 : *out = data_blob_talloc(mem_ctx, output_token.value, output_token.length);
1364 1272 : gss_release_buffer(&min_stat, &output_token);
1365 :
1366 1272 : if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)
1367 1272 : && !conf_state) {
1368 0 : return NT_STATUS_ACCESS_DENIED;
1369 : }
1370 1272 : return NT_STATUS_OK;
1371 : }
1372 :
1373 24 : static NTSTATUS gensec_gse_seal_packet(struct gensec_security *gensec_security,
1374 : TALLOC_CTX *mem_ctx,
1375 : uint8_t *data, size_t length,
1376 : const uint8_t *whole_pdu, size_t pdu_length,
1377 : DATA_BLOB *sig)
1378 : {
1379 0 : struct gse_context *gse_ctx =
1380 24 : talloc_get_type_abort(gensec_security->private_data,
1381 : struct gse_context);
1382 24 : bool hdr_signing = false;
1383 24 : size_t sig_size = 0;
1384 0 : NTSTATUS status;
1385 :
1386 24 : if (gensec_security->want_features & GENSEC_FEATURE_SIGN_PKT_HEADER) {
1387 24 : hdr_signing = true;
1388 : }
1389 :
1390 24 : sig_size = gensec_gse_sig_size(gensec_security, length);
1391 :
1392 24 : status = gssapi_seal_packet(gse_ctx->gssapi_context,
1393 24 : &gse_ctx->gss_mech,
1394 : hdr_signing, sig_size,
1395 : data, length,
1396 : whole_pdu, pdu_length,
1397 : mem_ctx, sig);
1398 24 : if (!NT_STATUS_IS_OK(status)) {
1399 0 : DEBUG(0, ("gssapi_seal_packet(hdr_signing=%u,sig_size=%zu,"
1400 : "data=%zu,pdu=%zu) failed: %s\n",
1401 : hdr_signing, sig_size, length, pdu_length,
1402 : nt_errstr(status)));
1403 0 : return status;
1404 : }
1405 :
1406 24 : return NT_STATUS_OK;
1407 : }
1408 :
1409 24 : static NTSTATUS gensec_gse_unseal_packet(struct gensec_security *gensec_security,
1410 : uint8_t *data, size_t length,
1411 : const uint8_t *whole_pdu, size_t pdu_length,
1412 : const DATA_BLOB *sig)
1413 : {
1414 0 : struct gse_context *gse_ctx =
1415 24 : talloc_get_type_abort(gensec_security->private_data,
1416 : struct gse_context);
1417 24 : bool hdr_signing = false;
1418 0 : NTSTATUS status;
1419 :
1420 24 : if (gensec_security->want_features & GENSEC_FEATURE_SIGN_PKT_HEADER) {
1421 24 : hdr_signing = true;
1422 : }
1423 :
1424 24 : status = gssapi_unseal_packet(gse_ctx->gssapi_context,
1425 24 : &gse_ctx->gss_mech,
1426 : hdr_signing,
1427 : data, length,
1428 : whole_pdu, pdu_length,
1429 : sig);
1430 24 : if (!NT_STATUS_IS_OK(status)) {
1431 0 : DEBUG(0, ("gssapi_unseal_packet(hdr_signing=%u,sig_size=%zu,"
1432 : "data=%zu,pdu=%zu) failed: %s\n",
1433 : hdr_signing, sig->length, length, pdu_length,
1434 : nt_errstr(status)));
1435 0 : return status;
1436 : }
1437 :
1438 24 : return NT_STATUS_OK;
1439 : }
1440 :
1441 287 : static NTSTATUS gensec_gse_sign_packet(struct gensec_security *gensec_security,
1442 : TALLOC_CTX *mem_ctx,
1443 : const uint8_t *data, size_t length,
1444 : const uint8_t *whole_pdu, size_t pdu_length,
1445 : DATA_BLOB *sig)
1446 : {
1447 0 : struct gse_context *gse_ctx =
1448 287 : talloc_get_type_abort(gensec_security->private_data,
1449 : struct gse_context);
1450 287 : bool hdr_signing = false;
1451 0 : NTSTATUS status;
1452 :
1453 287 : if (gensec_security->want_features & GENSEC_FEATURE_SIGN_PKT_HEADER) {
1454 122 : hdr_signing = true;
1455 : }
1456 :
1457 287 : status = gssapi_sign_packet(gse_ctx->gssapi_context,
1458 287 : &gse_ctx->gss_mech,
1459 : hdr_signing,
1460 : data, length,
1461 : whole_pdu, pdu_length,
1462 : mem_ctx, sig);
1463 287 : if (!NT_STATUS_IS_OK(status)) {
1464 0 : DEBUG(0, ("gssapi_sign_packet(hdr_signing=%u,"
1465 : "data=%zu,pdu=%zu) failed: %s\n",
1466 : hdr_signing, length, pdu_length,
1467 : nt_errstr(status)));
1468 0 : return status;
1469 : }
1470 :
1471 287 : return NT_STATUS_OK;
1472 : }
1473 :
1474 254 : static NTSTATUS gensec_gse_check_packet(struct gensec_security *gensec_security,
1475 : const uint8_t *data, size_t length,
1476 : const uint8_t *whole_pdu, size_t pdu_length,
1477 : const DATA_BLOB *sig)
1478 : {
1479 0 : struct gse_context *gse_ctx =
1480 254 : talloc_get_type_abort(gensec_security->private_data,
1481 : struct gse_context);
1482 254 : bool hdr_signing = false;
1483 0 : NTSTATUS status;
1484 :
1485 254 : if (gensec_security->want_features & GENSEC_FEATURE_SIGN_PKT_HEADER) {
1486 136 : hdr_signing = true;
1487 : }
1488 :
1489 254 : status = gssapi_check_packet(gse_ctx->gssapi_context,
1490 254 : &gse_ctx->gss_mech,
1491 : hdr_signing,
1492 : data, length,
1493 : whole_pdu, pdu_length,
1494 : sig);
1495 254 : if (!NT_STATUS_IS_OK(status)) {
1496 8 : DEBUG(0, ("gssapi_check_packet(hdr_signing=%u,sig_size=%zu"
1497 : "data=%zu,pdu=%zu) failed: %s\n",
1498 : hdr_signing, sig->length, length, pdu_length,
1499 : nt_errstr(status)));
1500 8 : return status;
1501 : }
1502 :
1503 246 : return NT_STATUS_OK;
1504 : }
1505 :
1506 : /* Try to figure out what features we actually got on the connection */
1507 19904 : static bool gensec_gse_have_feature(struct gensec_security *gensec_security,
1508 : uint32_t feature)
1509 : {
1510 0 : struct gse_context *gse_ctx =
1511 19904 : talloc_get_type_abort(gensec_security->private_data,
1512 : struct gse_context);
1513 :
1514 19904 : if (feature & GENSEC_FEATURE_SESSION_KEY) {
1515 4666 : return gse_ctx->gss_got_flags & GSS_C_INTEG_FLAG;
1516 : }
1517 15238 : if (feature & GENSEC_FEATURE_SIGN) {
1518 5790 : return gse_ctx->gss_got_flags & GSS_C_INTEG_FLAG;
1519 : }
1520 9448 : if (feature & GENSEC_FEATURE_SEAL) {
1521 6263 : return gse_ctx->gss_got_flags & GSS_C_CONF_FLAG;
1522 : }
1523 3185 : if (feature & GENSEC_FEATURE_DCE_STYLE) {
1524 126 : return gse_ctx->gss_got_flags & GSS_C_DCE_STYLE;
1525 : }
1526 3059 : if (feature & GENSEC_FEATURE_NEW_SPNEGO) {
1527 0 : NTSTATUS status;
1528 0 : uint32_t keytype;
1529 :
1530 2759 : if (!(gse_ctx->gss_got_flags & GSS_C_INTEG_FLAG)) {
1531 42 : return false;
1532 : }
1533 :
1534 2717 : status = gssapi_get_session_key(talloc_tos(),
1535 : gse_ctx->gssapi_context, NULL, &keytype);
1536 : /*
1537 : * We should do a proper sig on the mechListMic unless
1538 : * we know we have to be backwards compatible with
1539 : * earlier windows versions.
1540 : *
1541 : * Negotiating a non-krb5
1542 : * mech for example should be regarded as having
1543 : * NEW_SPNEGO
1544 : */
1545 2717 : if (NT_STATUS_IS_OK(status)) {
1546 2717 : switch (keytype) {
1547 61 : case ENCTYPE_DES_CBC_CRC:
1548 : case ENCTYPE_DES_CBC_MD5:
1549 : case ENCTYPE_ARCFOUR_HMAC:
1550 : case ENCTYPE_DES3_CBC_SHA1:
1551 61 : return false;
1552 : }
1553 : }
1554 2656 : return true;
1555 : }
1556 : /* We can always do async (rather than strict request/reply) packets. */
1557 300 : if (feature & GENSEC_FEATURE_ASYNC_REPLIES) {
1558 171 : return true;
1559 : }
1560 129 : if (feature & GENSEC_FEATURE_SIGN_PKT_HEADER) {
1561 129 : return true;
1562 : }
1563 0 : return false;
1564 : }
1565 :
1566 1065 : static NTTIME gensec_gse_expire_time(struct gensec_security *gensec_security)
1567 : {
1568 0 : struct gse_context *gse_ctx =
1569 1065 : talloc_get_type_abort(gensec_security->private_data,
1570 : struct gse_context);
1571 :
1572 1065 : return gse_ctx->expire_time;
1573 : }
1574 :
1575 : /*
1576 : * Extract the 'session key' needed by SMB signing and ncacn_np
1577 : * (for encrypting some passwords).
1578 : *
1579 : * This breaks all the abstractions, but what do you expect...
1580 : */
1581 3211 : static NTSTATUS gensec_gse_session_key(struct gensec_security *gensec_security,
1582 : TALLOC_CTX *mem_ctx,
1583 : DATA_BLOB *session_key)
1584 : {
1585 0 : struct gse_context *gse_ctx =
1586 3211 : talloc_get_type_abort(gensec_security->private_data,
1587 : struct gse_context);
1588 :
1589 3211 : return gssapi_get_session_key(mem_ctx, gse_ctx->gssapi_context, session_key, NULL);
1590 : }
1591 :
1592 : /* Get some basic (and authorization) information about the user on
1593 : * this session. This uses either the PAC (if present) or a local
1594 : * database lookup */
1595 892 : static NTSTATUS gensec_gse_session_info(struct gensec_security *gensec_security,
1596 : TALLOC_CTX *mem_ctx,
1597 : struct auth_session_info **_session_info)
1598 : {
1599 0 : struct gse_context *gse_ctx =
1600 892 : talloc_get_type_abort(gensec_security->private_data,
1601 : struct gse_context);
1602 0 : NTSTATUS nt_status;
1603 0 : TALLOC_CTX *tmp_ctx;
1604 892 : struct auth_session_info *session_info = NULL;
1605 0 : OM_uint32 maj_stat, min_stat;
1606 892 : DATA_BLOB pac_blob, *pac_blob_ptr = NULL;
1607 :
1608 0 : gss_buffer_desc name_token;
1609 0 : char *principal_string;
1610 :
1611 892 : tmp_ctx = talloc_named(mem_ctx, 0, "gensec_gse_session_info context");
1612 892 : NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);
1613 :
1614 892 : maj_stat = gss_display_name(&min_stat,
1615 468 : gse_ctx->client_name,
1616 : &name_token,
1617 : NULL);
1618 892 : if (GSS_ERROR(maj_stat)) {
1619 0 : DEBUG(1, ("GSS display_name failed: %s\n",
1620 : gse_errstr(talloc_tos(), maj_stat, min_stat)));
1621 0 : talloc_free(tmp_ctx);
1622 0 : return NT_STATUS_FOOBAR;
1623 : }
1624 :
1625 892 : principal_string = talloc_strndup(tmp_ctx,
1626 892 : (const char *)name_token.value,
1627 : name_token.length);
1628 :
1629 892 : gss_release_buffer(&min_stat, &name_token);
1630 :
1631 892 : if (!principal_string) {
1632 0 : talloc_free(tmp_ctx);
1633 0 : return NT_STATUS_NO_MEMORY;
1634 : }
1635 :
1636 892 : nt_status = gssapi_obtain_pac_blob(tmp_ctx, gse_ctx->gssapi_context,
1637 : gse_ctx->client_name,
1638 : &pac_blob);
1639 :
1640 : /* IF we have the PAC - otherwise we need to get this
1641 : * data from elsewhere
1642 : */
1643 892 : if (NT_STATUS_IS_OK(nt_status)) {
1644 884 : pac_blob_ptr = &pac_blob;
1645 : }
1646 892 : nt_status = gensec_generate_session_info_pac(tmp_ctx,
1647 : gensec_security,
1648 : NULL,
1649 : pac_blob_ptr, principal_string,
1650 : gensec_get_remote_address(gensec_security),
1651 : &session_info);
1652 892 : if (!NT_STATUS_IS_OK(nt_status)) {
1653 14 : talloc_free(tmp_ctx);
1654 14 : return nt_status;
1655 : }
1656 :
1657 878 : nt_status = gensec_gse_session_key(gensec_security, session_info,
1658 878 : &session_info->session_key);
1659 878 : if (!NT_STATUS_IS_OK(nt_status)) {
1660 0 : talloc_free(tmp_ctx);
1661 0 : return nt_status;
1662 : }
1663 :
1664 878 : *_session_info = talloc_move(mem_ctx, &session_info);
1665 878 : talloc_free(tmp_ctx);
1666 :
1667 878 : return NT_STATUS_OK;
1668 : }
1669 :
1670 300 : static size_t gensec_gse_max_input_size(struct gensec_security *gensec_security)
1671 : {
1672 0 : struct gse_context *gse_ctx =
1673 300 : talloc_get_type_abort(gensec_security->private_data,
1674 : struct gse_context);
1675 0 : OM_uint32 maj_stat, min_stat;
1676 0 : OM_uint32 max_input_size;
1677 :
1678 454 : maj_stat = gss_wrap_size_limit(&min_stat,
1679 154 : gse_ctx->gssapi_context,
1680 300 : gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL),
1681 : GSS_C_QOP_DEFAULT,
1682 300 : gse_ctx->max_wrap_buf_size,
1683 : &max_input_size);
1684 300 : if (GSS_ERROR(maj_stat)) {
1685 0 : TALLOC_CTX *mem_ctx = talloc_new(NULL);
1686 0 : DEBUG(1, ("gensec_gssapi_max_input_size: determining signature size with gss_wrap_size_limit failed: %s\n",
1687 : gse_errstr(mem_ctx, maj_stat, min_stat)));
1688 0 : talloc_free(mem_ctx);
1689 0 : return 0;
1690 : }
1691 :
1692 300 : return max_input_size;
1693 : }
1694 :
1695 : /* Find out the maximum output size negotiated on this connection */
1696 300 : static size_t gensec_gse_max_wrapped_size(struct gensec_security *gensec_security)
1697 : {
1698 0 : struct gse_context *gse_ctx =
1699 300 : talloc_get_type_abort(gensec_security->private_data,
1700 : struct gse_context);
1701 300 : return gse_ctx->max_wrap_buf_size;
1702 : }
1703 :
1704 186 : static size_t gensec_gse_sig_size(struct gensec_security *gensec_security,
1705 : size_t data_size)
1706 : {
1707 0 : struct gse_context *gse_ctx =
1708 186 : talloc_get_type_abort(gensec_security->private_data,
1709 : struct gse_context);
1710 :
1711 186 : if (gse_ctx->sig_size > 0) {
1712 82 : return gse_ctx->sig_size;
1713 : }
1714 :
1715 208 : gse_ctx->sig_size = gssapi_get_sig_size(gse_ctx->gssapi_context,
1716 104 : &gse_ctx->gss_mech,
1717 : gse_ctx->gss_got_flags,
1718 : data_size);
1719 104 : return gse_ctx->sig_size;
1720 : }
1721 :
1722 872 : static const char *gensec_gse_final_auth_type(struct gensec_security *gensec_security)
1723 : {
1724 0 : struct gse_context *gse_ctx =
1725 872 : talloc_get_type_abort(gensec_security->private_data,
1726 : struct gse_context);
1727 :
1728 : /* Only return the string for GSSAPI/Krb5 */
1729 872 : if (smb_gss_oid_equal(&gse_ctx->gss_mech,
1730 : gss_mech_krb5)) {
1731 872 : return GENSEC_FINAL_AUTH_TYPE_KRB5;
1732 : } else {
1733 0 : return "gensec_gse: UNKNOWN MECH";
1734 : }
1735 : }
1736 :
1737 : static const char *gensec_gse_krb5_oids[] = {
1738 : GENSEC_OID_KERBEROS5_OLD,
1739 : GENSEC_OID_KERBEROS5,
1740 : NULL
1741 : };
1742 :
1743 : static const struct gensec_security_ops gensec_gse_krb5_security_ops = {
1744 : .name = "gse_krb5",
1745 : .auth_type = DCERPC_AUTH_TYPE_KRB5,
1746 : .oid = gensec_gse_krb5_oids,
1747 : .client_start = gensec_gse_client_start,
1748 : .server_start = gensec_gse_server_start,
1749 : .magic = gensec_magic_check_krb5_oid,
1750 : .update_send = gensec_gse_update_send,
1751 : .update_recv = gensec_gse_update_recv,
1752 : .session_key = gensec_gse_session_key,
1753 : .session_info = gensec_gse_session_info,
1754 : .sig_size = gensec_gse_sig_size,
1755 : .sign_packet = gensec_gse_sign_packet,
1756 : .check_packet = gensec_gse_check_packet,
1757 : .seal_packet = gensec_gse_seal_packet,
1758 : .unseal_packet = gensec_gse_unseal_packet,
1759 : .max_input_size = gensec_gse_max_input_size,
1760 : .max_wrapped_size = gensec_gse_max_wrapped_size,
1761 : .wrap = gensec_gse_wrap,
1762 : .unwrap = gensec_gse_unwrap,
1763 : .have_feature = gensec_gse_have_feature,
1764 : .expire_time = gensec_gse_expire_time,
1765 : .final_auth_type = gensec_gse_final_auth_type,
1766 : .enabled = true,
1767 : .kerberos = true,
1768 : .priority = GENSEC_GSSAPI
1769 : };
1770 :
1771 120652 : const struct gensec_security_ops *gensec_gse_security_by_oid(
1772 : const char *oid_string)
1773 : {
1774 0 : int cmp;
1775 :
1776 120652 : cmp = strcmp(oid_string, GENSEC_OID_KERBEROS5);
1777 120652 : if (cmp == 0) {
1778 120652 : return &gensec_gse_krb5_security_ops;
1779 : }
1780 :
1781 0 : return NULL;
1782 : }
1783 : #endif /* HAVE_KRB5 */
|