2 * Copyright (c) 2021, PADL Software Pty Ltd.
5 * Portions Copyright (c) 2019 Kungliga Tekniska Högskolan
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of PADL Software nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY PADL SOFTWARE AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL PADL SOFTWARE OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 #include <gssapi/gssapi.h>
38 #include <gssapi_mech.h>
40 #include <gss-preauth-protos.h>
41 #include <gss-preauth-private.h>
43 #include "gss_preauth_authorizer_plugin.h"
45 struct gss_client_params
{
46 OM_uint32 major
, minor
;
47 gss_ctx_id_t context_handle
;
48 gss_name_t initiator_name
;
50 gss_buffer_desc output_token
;
53 krb5_checksum req_body_checksum
;
57 pa_gss_display_status(astgs_request_t r
,
60 gss_client_params
*gcp
,
64 pa_gss_display_name(gss_name_t name
,
66 gss_const_buffer_t
*namebuf_p
);
68 static void HEIM_CALLCONV
69 pa_gss_dealloc_client_params(void *ptr
);
72 * Create a checksum over KDC-REQ-BODY (without the nonce), used to
73 * assert the request is invariant within the preauth conversation.
75 static krb5_error_code
76 pa_gss_create_req_body_checksum(astgs_request_t r
,
77 krb5_checksum
*checksum
)
80 KDC_REQ_BODY b
= r
->req
.req_body
;
86 ASN1_MALLOC_ENCODE(KDC_REQ_BODY
, data
.data
, data
.length
, &b
, &size
, ret
);
87 heim_assert(ret
|| data
.length
,
88 "internal asn1 encoder error");
90 ret
= krb5_create_checksum(r
->context
, NULL
, 0, CKSUMTYPE_SHA256
,
91 data
.data
, data
.length
, checksum
);
92 krb5_data_free(&data
);
98 * Verify a checksum over KDC-REQ-BODY (without the nonce), used to
99 * assert the request is invariant within the preauth conversation.
101 static krb5_error_code
102 pa_gss_verify_req_body_checksum(astgs_request_t r
,
103 krb5_checksum
*checksum
)
106 KDC_REQ_BODY b
= r
->req
.req_body
;
112 ASN1_MALLOC_ENCODE(KDC_REQ_BODY
, data
.data
, data
.length
, &b
, &size
, ret
);
113 heim_assert(ret
|| data
.length
,
114 "internal asn1 encoder error");
116 ret
= _kdc_verify_checksum(r
->context
, NULL
, 0, &data
, checksum
);
117 krb5_data_free(&data
);
123 * Decode the FX-COOKIE context state, consisting of the exported
124 * GSS context token concatenated with the checksum of the initial
127 static krb5_error_code
128 pa_gss_decode_context_state(astgs_request_t r
,
129 const krb5_data
*state
,
130 gss_buffer_t sec_context_token
,
131 krb5_checksum
*req_body_checksum
)
139 memset(req_body_checksum
, 0, sizeof(*req_body_checksum
));
140 sec_context_token
->length
= 0;
141 sec_context_token
->value
= NULL
;
143 krb5_data_zero(&data
);
145 sp
= krb5_storage_from_readonly_mem(state
->data
, state
->length
);
147 ret
= krb5_enomem(r
->context
);
151 krb5_storage_set_eof_code(sp
, KRB5_BAD_MSIZE
);
152 krb5_storage_set_byteorder(sp
, KRB5_STORAGE_BYTEORDER_PACKED
);
154 ret
= krb5_ret_data(sp
, &data
);
158 ret
= krb5_ret_int32(sp
, &cksumtype
);
162 req_body_checksum
->cksumtype
= (CKSUMTYPE
)cksumtype
;
164 if (req_body_checksum
->cksumtype
== CKSUMTYPE_NONE
||
165 krb5_checksum_is_keyed(r
->context
, req_body_checksum
->cksumtype
)) {
166 ret
= KRB5KDC_ERR_SUMTYPE_NOSUPP
;
170 ret
= krb5_checksumsize(r
->context
, req_body_checksum
->cksumtype
,
175 req_body_checksum
->checksum
.data
= malloc(cksumsize
);
176 if (req_body_checksum
->checksum
.data
== NULL
) {
177 ret
= krb5_enomem(r
->context
);
181 if (krb5_storage_read(sp
, req_body_checksum
->checksum
.data
,
182 cksumsize
) != cksumsize
) {
183 ret
= KRB5_BAD_MSIZE
;
187 req_body_checksum
->checksum
.length
= cksumsize
;
189 _krb5_gss_data_to_buffer(&data
, sec_context_token
);
193 krb5_data_free(&data
);
194 free_Checksum(req_body_checksum
);
195 memset(req_body_checksum
, 0, sizeof(*req_body_checksum
));
197 krb5_storage_free(sp
);
203 * Deserialize a GSS-API security context from the FAST cookie.
205 static krb5_error_code
206 pa_gss_get_context_state(astgs_request_t r
,
207 gss_client_params
*gcp
)
213 OM_uint32 major
, minor
;
214 gss_buffer_desc sec_context_token
;
216 fast_pa
= krb5_find_padata(r
->fast
.fast_state
.val
,
217 r
->fast
.fast_state
.len
,
218 KRB5_PADATA_GSS
, &idx
);
222 ret
= pa_gss_decode_context_state(r
, &fast_pa
->padata_value
,
224 &gcp
->req_body_checksum
);
228 ret
= pa_gss_verify_req_body_checksum(r
, &gcp
->req_body_checksum
);
230 gss_release_buffer(&minor
, &sec_context_token
);
234 major
= gss_import_sec_context(&minor
, &sec_context_token
,
235 &gcp
->context_handle
);
236 if (GSS_ERROR(major
)) {
237 pa_gss_display_status(r
, major
, minor
, gcp
,
238 "Failed to import GSS pre-authentication context");
239 ret
= _krb5_gss_map_error(major
, minor
);
243 gss_release_buffer(&minor
, &sec_context_token
);
249 * Encode the FX-COOKIE context state, consisting of the exported
250 * GSS context token concatenated with the checksum of the initial
253 static krb5_error_code
254 pa_gss_encode_context_state(astgs_request_t r
,
255 gss_const_buffer_t sec_context_token
,
256 const krb5_checksum
*req_body_checksum
,
263 krb5_data_zero(state
);
265 sp
= krb5_storage_emem();
267 ret
= krb5_enomem(r
->context
);
271 krb5_storage_set_byteorder(sp
, KRB5_STORAGE_BYTEORDER_PACKED
);
273 _krb5_gss_buffer_to_data(sec_context_token
, &data
);
275 ret
= krb5_store_data(sp
, data
);
279 ret
= krb5_store_int32(sp
, (int32_t)req_body_checksum
->cksumtype
);
283 ret
= krb5_store_bytes(sp
, req_body_checksum
->checksum
.data
,
284 req_body_checksum
->checksum
.length
);
288 ret
= krb5_storage_to_data(sp
, state
);
293 krb5_storage_free(sp
);
299 * Serialize a GSS-API security context into a FAST cookie.
301 static krb5_error_code
302 pa_gss_set_context_state(astgs_request_t r
,
303 gss_client_params
*gcp
)
310 OM_uint32 major
, minor
;
311 gss_buffer_desc sec_context_token
= GSS_C_EMPTY_BUFFER
;
314 * On second and subsequent responses, we can recycle the checksum
315 * from the request as it is validated and invariant. This saves
316 * re-encoding the request body again.
318 if (gcp
->req_body_checksum
.cksumtype
== CKSUMTYPE_NONE
) {
319 ret
= pa_gss_create_req_body_checksum(r
, &gcp
->req_body_checksum
);
324 major
= gss_export_sec_context(&minor
, &gcp
->context_handle
,
326 if (GSS_ERROR(major
)) {
327 pa_gss_display_status(r
, major
, minor
, gcp
,
328 "Failed to export GSS pre-authentication context");
329 return _krb5_gss_map_error(major
, minor
);
332 ret
= pa_gss_encode_context_state(r
, &sec_context_token
,
333 &gcp
->req_body_checksum
, &state
);
334 gss_release_buffer(&minor
, &sec_context_token
);
338 fast_pa
= krb5_find_padata(r
->fast
.fast_state
.val
,
339 r
->fast
.fast_state
.len
,
340 KRB5_PADATA_GSS
, &idx
);
342 krb5_data_free(&fast_pa
->padata_value
);
343 fast_pa
->padata_value
= state
;
345 ret
= krb5_padata_add(r
->context
, &r
->fast
.fast_state
,
347 state
.data
, state
.length
);
349 krb5_data_free(&state
);
355 static krb5_error_code
356 pa_gss_acquire_acceptor_cred(astgs_request_t r
,
357 gss_client_params
*gcp
,
361 krb5_principal tgs_name
;
363 OM_uint32 major
, minor
;
364 gss_name_t target_name
= GSS_C_NO_NAME
;
365 gss_buffer_desc display_name
= GSS_C_EMPTY_BUFFER
;
366 gss_const_buffer_t display_name_p
;
368 *cred
= GSS_C_NO_CREDENTIAL
;
370 ret
= krb5_make_principal(r
->context
, &tgs_name
, r
->req
.req_body
.realm
,
371 KRB5_TGS_NAME
, r
->req
.req_body
.realm
, NULL
);
375 ret
= _krb5_gss_pa_unparse_name(r
->context
, tgs_name
, &target_name
);
376 krb5_free_principal(r
->context
, tgs_name
);
380 pa_gss_display_name(target_name
, &display_name
, &display_name_p
);
382 kdc_log(r
->context
, r
->config
, 4,
383 "Acquiring GSS acceptor credential for %.*s",
384 (int)display_name_p
->length
, (char *)display_name_p
->value
);
386 major
= gss_acquire_cred(&minor
, target_name
, GSS_C_INDEFINITE
,
387 r
->config
->gss_mechanisms_allowed
,
388 GSS_C_ACCEPT
, cred
, NULL
, NULL
);
389 ret
= _krb5_gss_map_error(major
, minor
);
392 pa_gss_display_status(r
, major
, minor
, gcp
,
393 "Failed to acquire GSS acceptor credential");
395 gss_release_buffer(&minor
, &display_name
);
396 gss_release_name(&minor
, &target_name
);
402 _kdc_gss_rd_padata(astgs_request_t r
,
404 gss_client_params
**pgcp
,
410 gss_client_params
*gcp
= NULL
;
411 gss_cred_id_t cred
= GSS_C_NO_CREDENTIAL
;
412 gss_buffer_desc input_token
= GSS_C_EMPTY_BUFFER
;
413 struct gss_channel_bindings_struct cb
;
415 memset(&cb
, 0, sizeof(cb
));
419 if (!r
->config
->enable_gss_preauth
) {
420 ret
= KRB5KDC_ERR_POLICY
;
424 if (pa
->padata_value
.length
== 0) {
425 ret
= KRB5KDC_ERR_PREAUTH_FAILED
;
429 gcp
= kdc_object_alloc(sizeof(*gcp
), "pa-gss-client-params", pa_gss_dealloc_client_params
);
431 ret
= krb5_enomem(r
->context
);
435 /* errors are fast fail until gss_accept_sec_context() is called */
436 gcp
->major
= GSS_S_NO_CONTEXT
;
438 ret
= pa_gss_get_context_state(r
, gcp
);
442 ret
= pa_gss_acquire_acceptor_cred(r
, gcp
, &cred
);
446 _krb5_gss_data_to_buffer(&pa
->padata_value
, &input_token
);
447 _krb5_gss_data_to_buffer(&r
->req
.req_body
._save
, &cb
.application_data
);
449 gcp
->major
= gss_accept_sec_context(&gcp
->minor
,
450 &gcp
->context_handle
,
454 &gcp
->initiator_name
,
459 NULL
); /* delegated_cred_handle */
461 ret
= _krb5_gss_map_error(gcp
->major
, gcp
->minor
);
463 if (GSS_ERROR(gcp
->major
)) {
464 pa_gss_display_status(r
, gcp
->major
, gcp
->minor
, gcp
,
465 "Failed to accept GSS security context");
466 } else if ((gcp
->flags
& GSS_C_ANON_FLAG
) && !_kdc_is_anon_request(&r
->req
)) {
467 kdc_log(r
->context
, r
->config
, 2,
468 "Anonymous GSS pre-authentication request w/o anonymous flag");
469 ret
= KRB5KDC_ERR_BADOPTION
;
471 *open
= (gcp
->major
== GSS_S_COMPLETE
);
474 gss_release_cred(&minor
, &cred
);
476 if (gcp
&& gcp
->major
!= GSS_S_NO_CONTEXT
)
479 kdc_object_release(gcp
);
485 _kdc_gss_endtime(astgs_request_t r
,
486 gss_client_params
*gcp
)
488 krb5_timestamp endtime
;
490 if (gcp
->lifetime
== GSS_C_INDEFINITE
)
493 endtime
= kdc_time
+ gcp
->lifetime
;
495 kdc_log(r
->context
, r
->config
, 10,
496 "GSS pre-authentication endtime is %ld", (long)endtime
);
501 struct pa_gss_authorize_plugin_ctx
{
503 struct gss_client_params
*gcp
;
504 krb5_boolean authorized
;
505 krb5_principal initiator_princ
;
508 static krb5_error_code KRB5_LIB_CALL
509 pa_gss_authorize_cb(krb5_context context
,
514 const krb5plugin_gss_preauth_authorizer_ftable
*authorizer
= plug
;
515 struct pa_gss_authorize_plugin_ctx
*pa_gss_authorize_plugin_ctx
= userctx
;
517 return authorizer
->authorize(plugctx
,
518 pa_gss_authorize_plugin_ctx
->r
,
519 pa_gss_authorize_plugin_ctx
->gcp
->initiator_name
,
520 pa_gss_authorize_plugin_ctx
->gcp
->mech_type
,
521 pa_gss_authorize_plugin_ctx
->gcp
->flags
,
522 &pa_gss_authorize_plugin_ctx
->authorized
,
523 &pa_gss_authorize_plugin_ctx
->initiator_princ
);
526 static const char *plugin_deps
[] = {
534 static struct heim_plugin_data
535 gss_preauth_authorizer_data
= {
537 KDC_GSS_PREAUTH_AUTHORIZER
,
538 KDC_GSS_PREAUTH_AUTHORIZER_VERSION_1
,
543 static krb5_error_code
544 pa_gss_authorize_plugin(astgs_request_t r
,
545 struct gss_client_params
*gcp
,
546 gss_const_buffer_t display_name
,
547 krb5_boolean
*authorized
,
548 krb5_principal
*initiator_princ
)
551 struct pa_gss_authorize_plugin_ctx ctx
;
556 ctx
.initiator_princ
= NULL
;
558 krb5_clear_error_message(r
->context
);
559 ret
= _krb5_plugin_run_f(r
->context
, &gss_preauth_authorizer_data
,
560 0, &ctx
, pa_gss_authorize_cb
);
562 if (ret
!= KRB5_PLUGIN_NO_HANDLE
) {
563 const char *msg
= krb5_get_error_message(r
->context
, ret
);
565 kdc_log(r
->context
, r
->config
, 7,
566 "GSS authz plugin %sauthorize%s %s initiator %.*s: %s",
567 ctx
.authorized
? "" : "did not " ,
568 ctx
.authorized
? "d" : "",
569 gss_oid_to_name(gcp
->mech_type
),
570 (int)display_name
->length
, (char *)display_name
->value
,
572 krb5_free_error_message(r
->context
, msg
);
575 *authorized
= ctx
.authorized
;
576 *initiator_princ
= ctx
.initiator_princ
;
581 static krb5_error_code
582 pa_gss_authorize_default(astgs_request_t r
,
583 struct gss_client_params
*gcp
,
584 gss_const_buffer_t display_name
,
585 krb5_boolean
*authorized
,
586 krb5_principal
*initiator_princ
)
589 krb5_principal principal
;
590 krb5_const_realm realm
= r
->server
->principal
->realm
;
591 int flags
= 0, cross_realm_allowed
= 0, unauth_anon
;
594 * gss_cross_realm_mechanisms_allowed is a list of GSS-API mechanisms
595 * that are allowed to map directly to Kerberos principals in any
596 * realm. If the authenticating mechanism is not on the list, then
597 * the initiator will be mapped to an enterprise principal in the
598 * service realm. This is useful to stop synthetic principals in
599 * foreign realms being conflated with true cross-realm principals.
601 if (r
->config
->gss_cross_realm_mechanisms_allowed
) {
604 gss_test_oid_set_member(&minor
, gcp
->mech_type
,
605 r
->config
->gss_cross_realm_mechanisms_allowed
,
606 &cross_realm_allowed
);
609 kdc_log(r
->context
, r
->config
, 10,
610 "Initiator %.*s will be mapped to %s",
611 (int)display_name
->length
, (char *)display_name
->value
,
612 cross_realm_allowed
? "nt-principal" : "nt-enterprise-principal");
614 if (!cross_realm_allowed
)
615 flags
|= KRB5_PRINCIPAL_PARSE_ENTERPRISE
| KRB5_PRINCIPAL_PARSE_NO_REALM
;
617 ret
= _krb5_gss_pa_parse_name(r
->context
, gcp
->initiator_name
,
620 const char *msg
= krb5_get_error_message(r
->context
, ret
);
622 kdc_log(r
->context
, r
->config
, 2,
623 "Failed to parse %s initiator name %.*s: %s",
624 gss_oid_to_name(gcp
->mech_type
),
625 (int)display_name
->length
, (char *)display_name
->value
, msg
);
626 krb5_free_error_message(r
->context
, msg
);
632 * GSS_C_ANON_FLAG indicates the client requested anonymous authentication
633 * (it is validated against the request-anonymous flag).
635 * _kdc_is_anonymous_pkinit() returns TRUE if the principal contains both
636 * the well known anonymous name and realm.
638 unauth_anon
= (gcp
->flags
& GSS_C_ANON_FLAG
) &&
639 _kdc_is_anonymous_pkinit(r
->context
, principal
);
642 * Always use the anonymous entry created in our HDB, i.e. with the local
643 * realm, for authorizing anonymous requests. This matches PKINIT behavior
644 * as anonymous PKINIT requests include the KDC realm in the request.
646 if (unauth_anon
|| (flags
& KRB5_PRINCIPAL_PARSE_ENTERPRISE
)) {
647 ret
= krb5_principal_set_realm(r
->context
, principal
, realm
);
649 krb5_free_principal(r
->context
, principal
);
656 * Special case to avoid changing _kdc_as_rep(). If the initiator is
657 * the unauthenticated anonymous principal, r->client_princ also needs
658 * to be set in order to force the AS-REP realm to be set to the well-
659 * known anonymous identity. This is because (unlike anonymous PKINIT)
660 * we only require the anonymous flag, not the anonymous name, in the
663 krb5_principal anon_princ
;
665 ret
= krb5_copy_principal(r
->context
, principal
, &anon_princ
);
669 krb5_free_principal(r
->context
, r
->client_princ
);
670 r
->client_princ
= anon_princ
;
674 *initiator_princ
= principal
;
680 _kdc_gss_check_client(astgs_request_t r
,
681 gss_client_params
*gcp
,
685 krb5_principal initiator_princ
= NULL
;
686 hdb_entry
*initiator
= NULL
;
687 krb5_boolean authorized
= FALSE
;
688 HDB
*clientdb
= r
->clientdb
;
691 gss_buffer_desc display_name
= GSS_C_EMPTY_BUFFER
;
692 gss_const_buffer_t display_name_p
;
696 pa_gss_display_name(gcp
->initiator_name
, &display_name
, &display_name_p
);
699 * If no plugins handled the authorization request, then all clients
700 * are authorized as the directly corresponding Kerberos principal.
702 ret
= pa_gss_authorize_plugin(r
, gcp
, display_name_p
,
703 &authorized
, &initiator_princ
);
704 if (ret
== KRB5_PLUGIN_NO_HANDLE
)
705 ret
= pa_gss_authorize_default(r
, gcp
, display_name_p
,
706 &authorized
, &initiator_princ
);
707 if (ret
== 0 && !authorized
)
708 ret
= KRB5_KDC_ERR_CLIENT_NAME_MISMATCH
;
712 ret
= krb5_unparse_name(r
->context
, initiator_princ
, client_name
);
716 kdc_log(r
->context
, r
->config
, 4,
717 "Mapped GSS %s initiator %.*s to principal %s",
718 gss_oid_to_name(gcp
->mech_type
),
719 (int)display_name_p
->length
, (char *)display_name_p
->value
,
722 ret
= _kdc_db_fetch(r
->context
,
725 HDB_F_FOR_AS_REQ
| HDB_F_GET_CLIENT
|
726 HDB_F_CANON
| HDB_F_SYNTHETIC_OK
,
731 const char *msg
= krb5_get_error_message(r
->context
, ret
);
733 kdc_log(r
->context
, r
->config
, 4, "UNKNOWN -- %s: %s",
735 krb5_free_error_message(r
->context
, msg
);
741 * If the AS-REQ client name was the well-known federated name, then
742 * replace the client name with the initiator name. Otherwise, the
743 * two principals must match, noting that GSS pre-authentication is
744 * for authentication, not general purpose impersonation.
746 if (krb5_principal_is_federated(r
->context
, r
->client
->principal
)) {
747 initiator
->flags
.force_canonicalize
= 1;
749 _kdc_free_ent(r
->context
, clientdb
, r
->client
);
750 r
->client
= initiator
;
752 } else if (!krb5_principal_compare(r
->context
,
753 r
->client
->principal
,
754 initiator
->principal
)) {
755 kdc_log(r
->context
, r
->config
, 2,
756 "GSS %s initiator %.*s does not match principal %s",
757 gss_oid_to_name(gcp
->mech_type
),
758 (int)display_name_p
->length
, (char *)display_name_p
->value
,
760 ret
= KRB5_KDC_ERR_CLIENT_NAME_MISMATCH
;
765 krb5_free_principal(r
->context
, initiator_princ
);
767 _kdc_free_ent(r
->context
, r
->clientdb
, initiator
);
768 gss_release_buffer(&minor
, &display_name
);
774 _kdc_gss_mk_pa_reply(astgs_request_t r
,
775 gss_client_params
*gcp
)
778 const KDC_REQ
*req
= &r
->req
;
780 if (gcp
->major
== GSS_S_COMPLETE
) {
781 krb5_enctype enctype
;
783 krb5_keyblock
*reply_key
= NULL
;
785 if (krb5_principal_is_krbtgt(r
->context
, r
->server_princ
))
788 ret
= _kdc_find_etype(r
, kfe
, req
->req_body
.etype
.val
,
789 req
->req_body
.etype
.len
, &enctype
, NULL
, NULL
);
793 ret
= _krb5_gss_pa_derive_key(r
->context
, gcp
->context_handle
,
795 enctype
, &reply_key
);
797 kdc_log(r
->context
, r
->config
, 10,
798 "Failed to derive GSS reply key: %d", ret
);
802 krb5_free_keyblock_contents(r
->context
, &r
->reply_key
);
803 r
->reply_key
= *reply_key
;
805 } else if (gcp
->major
== GSS_S_CONTINUE_NEEDED
) {
806 ret
= pa_gss_set_context_state(r
, gcp
);
811 /* only return padata in error case if we have an error token */
812 if (!GSS_ERROR(gcp
->major
) || gcp
->output_token
.length
) {
813 ret
= krb5_padata_add(r
->context
, r
->rep
.padata
, KRB5_PADATA_GSS
,
814 gcp
->output_token
.value
, gcp
->output_token
.length
);
818 /* token is now owned by r->rep.padata */
819 gcp
->output_token
.length
= 0;
820 gcp
->output_token
.value
= NULL
;
823 if (gcp
->major
== GSS_S_CONTINUE_NEEDED
)
824 ret
= KRB5_KDC_ERR_MORE_PREAUTH_DATA_REQUIRED
;
826 ret
= _krb5_gss_map_error(gcp
->major
, gcp
->minor
);
832 _kdc_gss_mk_composite_name_ad(astgs_request_t r
,
833 gss_client_params
*gcp
)
838 OM_uint32 major
, minor
;
839 gss_buffer_desc namebuf
= GSS_C_EMPTY_BUFFER
;
841 if (!r
->config
->enable_gss_auth_data
|| (gcp
->flags
& GSS_C_ANON_FLAG
))
844 major
= gss_export_name_composite(&minor
, gcp
->initiator_name
, &namebuf
);
845 if (major
== GSS_S_COMPLETE
) {
846 _krb5_gss_buffer_to_data(&namebuf
, &data
);
848 ret
= _kdc_tkt_add_if_relevant_ad(r
->context
, &r
->et
,
849 KRB5_AUTHDATA_GSS_COMPOSITE_NAME
,
851 } else if (major
!= GSS_S_UNAVAILABLE
)
852 ret
= _krb5_gss_map_error(major
, minor
);
856 gss_release_buffer(&minor
, &namebuf
);
861 static void HEIM_CALLCONV
862 pa_gss_dealloc_client_params(void *ptr
)
864 gss_client_params
*gcp
= ptr
;
870 gss_delete_sec_context(&minor
, &gcp
->context_handle
, GSS_C_NO_BUFFER
);
871 gss_release_name(&minor
, &gcp
->initiator_name
);
872 gss_release_buffer(&minor
, &gcp
->output_token
);
873 free_Checksum(&gcp
->req_body_checksum
);
874 memset(gcp
, 0, sizeof(*gcp
));
878 _kdc_gss_get_mechanism_config(krb5_context context
,
884 char **mechs
, **mechp
;
886 gss_OID_set oids
= GSS_C_NO_OID_SET
;
887 OM_uint32 major
, minor
;
889 mechs
= krb5_config_get_strings(context
, NULL
, section
, key
, NULL
);
893 major
= gss_create_empty_oid_set(&minor
, &oids
);
894 if (GSS_ERROR(major
)) {
895 krb5_config_free_strings(mechs
);
896 return _krb5_gss_map_error(major
, minor
);
899 for (mechp
= mechs
; *mechp
; mechp
++) {
900 gss_OID oid
= gss_name_to_oid(*mechp
);
901 if (oid
== GSS_C_NO_OID
)
904 major
= gss_add_oid_set_member(&minor
, oid
, &oids
);
905 if (GSS_ERROR(major
))
909 ret
= _krb5_gss_map_error(major
, minor
);
913 gss_release_oid_set(&minor
, &oids
);
915 krb5_config_free_strings(mechs
);
921 pa_gss_display_status(astgs_request_t r
,
924 gss_client_params
*gcp
,
927 krb5_error_code ret
= _krb5_gss_map_error(major
, minor
);
928 gss_buffer_desc buf
= GSS_C_EMPTY_BUFFER
;
929 OM_uint32 dmaj
, dmin
;
936 gss_release_buffer(&dmin
, &buf
);
937 dmaj
= gss_display_status(&dmin
, major
, GSS_C_GSS_CODE
, GSS_C_NO_OID
,
939 if (GSS_ERROR(dmaj
) ||
940 buf
.length
>= INT_MAX
||
941 asprintf(&s
, "%s%s%.*s", gmsg
? gmsg
: "", gmsg
? ": " : "",
942 (int)buf
.length
, (char *)buf
.value
) == -1 ||
950 } while (!GSS_ERROR(dmaj
) && more
);
952 if (gcp
->mech_type
!= GSS_C_NO_OID
) {
954 gss_release_buffer(&dmin
, &buf
);
955 dmaj
= gss_display_status(&dmin
, major
, GSS_C_MECH_CODE
,
956 gcp
->mech_type
, &more
, &buf
);
957 if (GSS_ERROR(dmaj
) ||
958 asprintf(&s
, "%s%s%.*s", gmmsg
? gmmsg
: "", gmmsg
? ": " : "",
959 (int)buf
.length
, (char *)buf
.value
) == -1 ||
967 } while (!GSS_ERROR(dmaj
) && more
);
971 krb5_set_error_message(r
->context
, ENOMEM
,
972 "Error displaying GSS-API status");
974 krb5_set_error_message(r
->context
, ret
, "%s%s%s%s", gmsg
,
975 gmmsg
? " (" : "", gmmsg
? gmmsg
: "",
977 krb5_prepend_error_message(r
->context
, ret
, "%s", msg
);
979 kdc_log(r
->context
, r
->config
, 1,
981 msg
, gmsg
, gmmsg
? " (" : "", gmmsg
? gmmsg
: "",
988 static const gss_buffer_desc
989 gss_pa_unknown_display_name
= {
990 sizeof("<unknown name>") - 1,
995 pa_gss_display_name(gss_name_t name
,
996 gss_buffer_t namebuf
,
997 gss_const_buffer_t
*namebuf_p
)
999 OM_uint32 major
, minor
;
1001 major
= gss_display_name(&minor
, name
, namebuf
, NULL
);
1002 if (GSS_ERROR(major
))
1003 *namebuf_p
= &gss_pa_unknown_display_name
;
1005 *namebuf_p
= namebuf
;
1008 static krb5_error_code KRB5_LIB_CALL
1009 pa_gss_finalize_pac_cb(krb5_context context
,
1014 const krb5plugin_gss_preauth_authorizer_ftable
*authorizer
= plug
;
1016 return authorizer
->finalize_pac(plugctx
, userctx
);
1021 _kdc_gss_finalize_pac(astgs_request_t r
,
1022 gss_client_params
*gcp
)
1024 krb5_error_code ret
;
1026 krb5_clear_error_message(r
->context
);
1027 ret
= _krb5_plugin_run_f(r
->context
, &gss_preauth_authorizer_data
,
1028 0, r
, pa_gss_finalize_pac_cb
);
1030 if (ret
== KRB5_PLUGIN_NO_HANDLE
)