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
;
58 pa_gss_display_status(astgs_request_t r
,
61 gss_client_params
*gcp
,
65 pa_gss_display_name(gss_name_t name
,
67 gss_const_buffer_t
*namebuf_p
);
70 * Create a checksum over KDC-REQ-BODY (without the nonce), used to
71 * assert the request is invariant within the preauth conversation.
73 static krb5_error_code
74 pa_gss_create_req_body_checksum(astgs_request_t r
,
75 krb5_checksum
*checksum
)
78 KDC_REQ_BODY b
= r
->req
.req_body
;
84 ASN1_MALLOC_ENCODE(KDC_REQ_BODY
, data
.data
, data
.length
, &b
, &size
, ret
);
85 heim_assert(ret
|| data
.length
,
86 "internal asn1 encoder error");
88 ret
= krb5_create_checksum(r
->context
, NULL
, 0, CKSUMTYPE_SHA256
,
89 data
.data
, data
.length
, checksum
);
90 krb5_data_free(&data
);
96 * Verify a checksum over KDC-REQ-BODY (without the nonce), used to
97 * assert the request is invariant within the preauth conversation.
99 static krb5_error_code
100 pa_gss_verify_req_body_checksum(astgs_request_t r
,
101 krb5_checksum
*checksum
)
104 KDC_REQ_BODY b
= r
->req
.req_body
;
110 ASN1_MALLOC_ENCODE(KDC_REQ_BODY
, data
.data
, data
.length
, &b
, &size
, ret
);
111 heim_assert(ret
|| data
.length
,
112 "internal asn1 encoder error");
114 ret
= _kdc_verify_checksum(r
->context
, NULL
, 0, &data
, checksum
);
115 krb5_data_free(&data
);
121 * Decode the FX-COOKIE context state, consisting of the exported
122 * GSS context token concatenated with the checksum of the initial
125 static krb5_error_code
126 pa_gss_decode_context_state(astgs_request_t r
,
127 const krb5_data
*state
,
128 gss_buffer_t sec_context_token
,
129 krb5_checksum
*req_body_checksum
)
136 memset(req_body_checksum
, 0, sizeof(*req_body_checksum
));
137 sec_context_token
->length
= 0;
138 sec_context_token
->value
= NULL
;
140 krb5_data_zero(&data
);
142 sp
= krb5_storage_from_readonly_mem(state
->data
, state
->length
);
144 ret
= krb5_enomem(r
->context
);
148 krb5_storage_set_eof_code(sp
, KRB5_BAD_MSIZE
);
149 krb5_storage_set_byteorder(sp
, KRB5_STORAGE_BYTEORDER_PACKED
);
151 ret
= krb5_ret_data(sp
, &data
);
155 ret
= krb5_ret_int32(sp
, &req_body_checksum
->cksumtype
);
159 if (req_body_checksum
->cksumtype
== CKSUMTYPE_NONE
||
160 krb5_checksum_is_keyed(r
->context
, req_body_checksum
->cksumtype
)) {
161 ret
= KRB5KDC_ERR_SUMTYPE_NOSUPP
;
165 ret
= krb5_checksumsize(r
->context
, req_body_checksum
->cksumtype
,
170 req_body_checksum
->checksum
.data
= malloc(cksumsize
);
171 if (req_body_checksum
->checksum
.data
== NULL
) {
172 ret
= krb5_enomem(r
->context
);
176 if (krb5_storage_read(sp
, req_body_checksum
->checksum
.data
,
177 cksumsize
) != cksumsize
) {
178 ret
= KRB5_BAD_MSIZE
;
182 req_body_checksum
->checksum
.length
= cksumsize
;
184 _krb5_gss_data_to_buffer(&data
, sec_context_token
);
188 krb5_data_free(&data
);
189 free_Checksum(req_body_checksum
);
190 memset(req_body_checksum
, 0, sizeof(*req_body_checksum
));
192 krb5_storage_free(sp
);
198 * Deserialize a GSS-API security context from the FAST cookie.
200 static krb5_error_code
201 pa_gss_get_context_state(astgs_request_t r
,
202 gss_client_params
*gcp
)
208 OM_uint32 major
, minor
;
209 gss_buffer_desc sec_context_token
;
211 fast_pa
= krb5_find_padata(r
->fast
.fast_state
.val
,
212 r
->fast
.fast_state
.len
,
213 KRB5_PADATA_GSS
, &idx
);
217 ret
= pa_gss_decode_context_state(r
, &fast_pa
->padata_value
,
219 &gcp
->req_body_checksum
);
223 ret
= pa_gss_verify_req_body_checksum(r
, &gcp
->req_body_checksum
);
225 gss_release_buffer(&minor
, &sec_context_token
);
229 major
= gss_import_sec_context(&minor
, &sec_context_token
,
230 &gcp
->context_handle
);
231 if (GSS_ERROR(major
)) {
232 pa_gss_display_status(r
, major
, minor
, gcp
,
233 "Failed to import GSS pre-authentication context");
234 ret
= _krb5_gss_map_error(major
, minor
);
238 gss_release_buffer(&minor
, &sec_context_token
);
244 * Encode the FX-COOKIE context state, consisting of the exported
245 * GSS context token concatenated with the checksum of the initial
248 static krb5_error_code
249 pa_gss_encode_context_state(astgs_request_t r
,
250 gss_const_buffer_t sec_context_token
,
251 const krb5_checksum
*req_body_checksum
,
258 krb5_data_zero(state
);
260 sp
= krb5_storage_emem();
262 ret
= krb5_enomem(r
->context
);
266 krb5_storage_set_byteorder(sp
, KRB5_STORAGE_BYTEORDER_PACKED
);
268 _krb5_gss_buffer_to_data(sec_context_token
, &data
);
270 ret
= krb5_store_data(sp
, data
);
274 ret
= krb5_store_int32(sp
, req_body_checksum
->cksumtype
);
278 ret
= krb5_store_bytes(sp
, req_body_checksum
->checksum
.data
,
279 req_body_checksum
->checksum
.length
);
283 ret
= krb5_storage_to_data(sp
, state
);
288 krb5_storage_free(sp
);
294 * Serialize a GSS-API security context into a FAST cookie.
296 static krb5_error_code
297 pa_gss_set_context_state(astgs_request_t r
,
298 gss_client_params
*gcp
)
305 OM_uint32 major
, minor
;
306 gss_buffer_desc sec_context_token
= GSS_C_EMPTY_BUFFER
;
309 * On second and subsequent responses, we can recycle the checksum
310 * from the request as it is validated and invariant. This saves
311 * re-encoding the request body again.
313 if (gcp
->req_body_checksum
.cksumtype
== CKSUMTYPE_NONE
) {
314 ret
= pa_gss_create_req_body_checksum(r
, &gcp
->req_body_checksum
);
319 major
= gss_export_sec_context(&minor
, &gcp
->context_handle
,
321 if (GSS_ERROR(major
)) {
322 pa_gss_display_status(r
, major
, minor
, gcp
,
323 "Failed to export GSS pre-authentication context");
324 return _krb5_gss_map_error(major
, minor
);
327 ret
= pa_gss_encode_context_state(r
, &sec_context_token
,
328 &gcp
->req_body_checksum
, &state
);
329 gss_release_buffer(&minor
, &sec_context_token
);
333 fast_pa
= krb5_find_padata(r
->fast
.fast_state
.val
,
334 r
->fast
.fast_state
.len
,
335 KRB5_PADATA_GSS
, &idx
);
337 krb5_data_free(&fast_pa
->padata_value
);
338 fast_pa
->padata_value
= state
;
340 ret
= krb5_padata_add(r
->context
, &r
->fast
.fast_state
,
342 state
.data
, state
.length
);
344 krb5_data_free(&state
);
350 static krb5_error_code
351 pa_gss_acquire_acceptor_cred(astgs_request_t r
,
352 gss_client_params
*gcp
,
356 krb5_principal tgs_name
;
358 OM_uint32 major
, minor
;
359 gss_name_t target_name
= GSS_C_NO_NAME
;
360 gss_buffer_desc display_name
= GSS_C_EMPTY_BUFFER
;
361 gss_const_buffer_t display_name_p
;
363 *cred
= GSS_C_NO_CREDENTIAL
;
365 ret
= krb5_make_principal(r
->context
, &tgs_name
, r
->req
.req_body
.realm
,
366 KRB5_TGS_NAME
, r
->req
.req_body
.realm
, NULL
);
370 ret
= _krb5_gss_pa_unparse_name(r
->context
, tgs_name
, &target_name
);
371 krb5_free_principal(r
->context
, tgs_name
);
375 pa_gss_display_name(target_name
, &display_name
, &display_name_p
);
377 kdc_log(r
->context
, r
->config
, 4,
378 "Acquiring GSS acceptor credential for %.*s",
379 (int)display_name_p
->length
, (char *)display_name_p
->value
);
381 major
= gss_acquire_cred(&minor
, target_name
, GSS_C_INDEFINITE
,
382 r
->config
->gss_mechanisms_allowed
,
383 GSS_C_ACCEPT
, cred
, NULL
, NULL
);
384 ret
= _krb5_gss_map_error(major
, minor
);
387 pa_gss_display_status(r
, major
, minor
, gcp
,
388 "Failed to acquire GSS acceptor credential");
390 gss_release_buffer(&minor
, &display_name
);
391 gss_release_name(&minor
, &target_name
);
397 _kdc_gss_rd_padata(astgs_request_t r
,
399 gss_client_params
**pgcp
,
405 gss_client_params
*gcp
= NULL
;
406 gss_cred_id_t cred
= GSS_C_NO_CREDENTIAL
;
407 gss_buffer_desc input_token
= GSS_C_EMPTY_BUFFER
;
408 struct gss_channel_bindings_struct cb
;
410 memset(&cb
, 0, sizeof(cb
));
414 if (!r
->config
->enable_gss_preauth
) {
415 ret
= KRB5KDC_ERR_POLICY
;
419 if (pa
->padata_value
.length
== 0) {
420 ret
= KRB5KDC_ERR_PREAUTH_FAILED
;
424 gcp
= calloc(1, sizeof(*gcp
));
426 ret
= krb5_enomem(r
->context
);
430 /* errors are fast fail until gss_accept_sec_context() is called */
431 gcp
->major
= GSS_S_NO_CONTEXT
;
433 ret
= pa_gss_get_context_state(r
, gcp
);
437 ret
= pa_gss_acquire_acceptor_cred(r
, gcp
, &cred
);
441 _krb5_gss_data_to_buffer(&pa
->padata_value
, &input_token
);
442 _krb5_gss_data_to_buffer(&r
->req
.req_body
._save
, &cb
.application_data
);
444 gcp
->major
= gss_accept_sec_context(&gcp
->minor
,
445 &gcp
->context_handle
,
449 &gcp
->initiator_name
,
454 NULL
); /* delegated_cred_handle */
456 ret
= _krb5_gss_map_error(gcp
->major
, gcp
->minor
);
458 if (GSS_ERROR(gcp
->major
)) {
459 pa_gss_display_status(r
, gcp
->major
, gcp
->minor
, gcp
,
460 "Failed to accept GSS security context");
461 } else if ((gcp
->flags
& GSS_C_ANON_FLAG
) && !_kdc_is_anon_request(&r
->req
)) {
462 kdc_log(r
->context
, r
->config
, 2,
463 "Anonymous GSS pre-authentication request w/o anonymous flag");
464 ret
= KRB5KDC_ERR_BADOPTION
;
466 *open
= (gcp
->major
== GSS_S_COMPLETE
);
469 gss_release_cred(&minor
, &cred
);
471 if (gcp
&& gcp
->major
!= GSS_S_NO_CONTEXT
)
474 _kdc_gss_free_client_param(r
, gcp
);
480 _kdc_gss_endtime(astgs_request_t r
,
481 gss_client_params
*gcp
)
483 krb5_timestamp endtime
;
485 if (gcp
->lifetime
== GSS_C_INDEFINITE
)
488 endtime
= kdc_time
+ gcp
->lifetime
;
490 kdc_log(r
->context
, r
->config
, 10,
491 "GSS pre-authentication endtime is %ld", endtime
);
496 struct pa_gss_authorize_plugin_ctx
{
498 struct gss_client_params
*gcp
;
499 krb5_boolean authorized
;
500 krb5_principal initiator_princ
;
504 static krb5_error_code KRB5_LIB_CALL
505 pa_gss_authorize_cb(krb5_context context
,
510 const krb5plugin_gss_preauth_authorizer_ftable
*authorizer
= plug
;
511 struct pa_gss_authorize_plugin_ctx
*pa_gss_authorize_plugin_ctx
= userctx
;
513 return authorizer
->authorize(plugctx
,
514 pa_gss_authorize_plugin_ctx
->r
,
515 pa_gss_authorize_plugin_ctx
->gcp
->initiator_name
,
516 pa_gss_authorize_plugin_ctx
->gcp
->mech_type
,
517 pa_gss_authorize_plugin_ctx
->gcp
->flags
,
518 &pa_gss_authorize_plugin_ctx
->authorized
,
519 &pa_gss_authorize_plugin_ctx
->initiator_princ
,
520 &pa_gss_authorize_plugin_ctx
->pac_data
);
523 static const char *plugin_deps
[] = {
531 static struct heim_plugin_data
532 gss_preauth_authorizer_data
= {
534 KDC_GSS_PREAUTH_AUTHORIZER
,
535 KDC_GSS_PREAUTH_AUTHORIZER_VERSION_1
,
540 static krb5_error_code
541 pa_gss_authorize_plugin(astgs_request_t r
,
542 struct gss_client_params
*gcp
,
543 gss_const_buffer_t display_name
,
544 krb5_boolean
*authorized
,
545 krb5_principal
*initiator_princ
,
549 struct pa_gss_authorize_plugin_ctx ctx
;
554 ctx
.initiator_princ
= NULL
;
555 krb5_data_zero(&ctx
.pac_data
);
557 krb5_clear_error_message(r
->context
);
558 ret
= _krb5_plugin_run_f(r
->context
, &gss_preauth_authorizer_data
,
559 0, &ctx
, pa_gss_authorize_cb
);
561 if (ret
!= KRB5_PLUGIN_NO_HANDLE
) {
562 const char *msg
= krb5_get_error_message(r
->context
, ret
);
564 kdc_log(r
->context
, r
->config
, 7,
565 "GSS authz plugin %sauthorize%s %s initiator %.*s: %s",
566 ctx
.authorized
? "" : "did not " ,
567 ctx
.authorized
? "d" : "",
568 gss_oid_to_name(gcp
->mech_type
),
569 (int)display_name
->length
, (char *)display_name
->value
,
571 krb5_free_error_message(r
->context
, msg
);
574 *authorized
= ctx
.authorized
;
575 *initiator_princ
= ctx
.initiator_princ
;
576 *pac_data
= ctx
.pac_data
;
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
,
590 krb5_principal principal
;
591 krb5_const_realm realm
= r
->server
->entry
.principal
->realm
;
592 int flags
= 0, cross_realm_allowed
= 0, unauth_anon
;
595 * gss_cross_realm_mechanisms_allowed is a list of GSS-API mechanisms
596 * that are allowed to map directly to Kerberos principals in any
597 * realm. If the authenticating mechanism is not on the list, then
598 * the initiator will be mapped to an enterprise principal in the
599 * service realm. This is useful to stop synthetic principals in
600 * foreign realms being conflated with true cross-realm principals.
602 if (r
->config
->gss_cross_realm_mechanisms_allowed
) {
605 gss_test_oid_set_member(&minor
, gcp
->mech_type
,
606 r
->config
->gss_cross_realm_mechanisms_allowed
,
607 &cross_realm_allowed
);
610 kdc_log(r
->context
, r
->config
, 10,
611 "Initiator %.*s will be mapped to %s",
612 (int)display_name
->length
, (char *)display_name
->value
,
613 cross_realm_allowed
? "nt-principal" : "nt-enterprise-principal");
615 if (!cross_realm_allowed
)
616 flags
|= KRB5_PRINCIPAL_PARSE_ENTERPRISE
| KRB5_PRINCIPAL_PARSE_NO_REALM
;
618 ret
= _krb5_gss_pa_parse_name(r
->context
, gcp
->initiator_name
,
621 const char *msg
= krb5_get_error_message(r
->context
, ret
);
623 kdc_log(r
->context
, r
->config
, 2,
624 "Failed to parse %s initiator name %.*s: %s",
625 gss_oid_to_name(gcp
->mech_type
),
626 (int)display_name
->length
, (char *)display_name
->value
, msg
);
627 krb5_free_error_message(r
->context
, msg
);
633 * GSS_C_ANON_FLAG indicates the client requested anonymous authentication
634 * (it is validated against the request-anonymous flag).
636 * _kdc_is_anonymous_pkinit() returns TRUE if the principal contains both
637 * the well known anonymous name and realm.
639 unauth_anon
= (gcp
->flags
& GSS_C_ANON_FLAG
) &&
640 _kdc_is_anonymous_pkinit(r
->context
, principal
);
643 * Always use the anonymous entry created in our HDB, i.e. with the local
644 * realm, for authorizing anonymous requests. This matches PKINIT behavior
645 * as anonymous PKINIT requests include the KDC realm in the request.
647 if (unauth_anon
|| (flags
& KRB5_PRINCIPAL_PARSE_ENTERPRISE
)) {
648 ret
= krb5_principal_set_realm(r
->context
, principal
, realm
);
650 krb5_free_principal(r
->context
, principal
);
657 * Special case to avoid changing _kdc_as_rep(). If the initiator is
658 * the unauthenticated anonymous principal, r->client_princ also needs
659 * to be set in order to force the AS-REP realm to be set to the well-
660 * known anonymous identity. This is because (unlike anonymous PKINIT)
661 * we only require the anonymous flag, not the anonymous name, in the
664 krb5_principal anon_princ
;
666 ret
= krb5_copy_principal(r
->context
, principal
, &anon_princ
);
670 krb5_free_principal(r
->context
, r
->client_princ
);
671 r
->client_princ
= anon_princ
;
675 *initiator_princ
= principal
;
681 _kdc_gss_check_client(astgs_request_t r
,
682 gss_client_params
*gcp
,
686 krb5_principal initiator_princ
= NULL
;
687 hdb_entry_ex
*initiator
= NULL
;
688 krb5_boolean authorized
= FALSE
;
692 gss_buffer_desc display_name
= GSS_C_EMPTY_BUFFER
;
693 gss_const_buffer_t display_name_p
;
696 krb5_data_zero(&pac_data
);
698 pa_gss_display_name(gcp
->initiator_name
, &display_name
, &display_name_p
);
701 * If no plugins handled the authorization request, then all clients
702 * are authorized as the directly corresponding Kerberos principal.
704 ret
= pa_gss_authorize_plugin(r
, gcp
, display_name_p
,
705 &authorized
, &initiator_princ
, &pac_data
);
706 if (ret
== KRB5_PLUGIN_NO_HANDLE
)
707 ret
= pa_gss_authorize_default(r
, gcp
, display_name_p
,
708 &authorized
, &initiator_princ
, &pac_data
);
709 if (ret
== 0 && !authorized
)
710 ret
= KRB5_KDC_ERR_CLIENT_NAME_MISMATCH
;
714 ret
= krb5_unparse_name(r
->context
, initiator_princ
, client_name
);
718 kdc_log(r
->context
, r
->config
, 4,
719 "Mapped GSS %s initiator %.*s to principal %s",
720 gss_oid_to_name(gcp
->mech_type
),
721 (int)display_name_p
->length
, (char *)display_name_p
->value
,
724 ret
= _kdc_db_fetch(r
->context
,
727 HDB_F_FOR_AS_REQ
| HDB_F_GET_CLIENT
|
728 HDB_F_CANON
| HDB_F_SYNTHETIC_OK
,
733 const char *msg
= krb5_get_error_message(r
->context
, ret
);
735 kdc_log(r
->context
, r
->config
, 4, "UNKNOWN -- %s: %s",
737 krb5_free_error_message(r
->context
, msg
);
743 * If the AS-REQ client name was the well-known federated name, then
744 * replace the client name with the initiator name. Otherwise, the
745 * two principals must match, noting that GSS pre-authentication is
746 * for authentication, not general purpose impersonation.
748 if (krb5_principal_is_federated(r
->context
, r
->client
->entry
.principal
)) {
749 initiator
->entry
.flags
.force_canonicalize
= 1;
751 _kdc_free_ent(r
->context
, r
->client
);
752 r
->client
= initiator
;
754 } else if (!krb5_principal_compare(r
->context
,
755 r
->client
->entry
.principal
,
756 initiator
->entry
.principal
)) {
757 kdc_log(r
->context
, r
->config
, 2,
758 "GSS %s initiator %.*s does not match principal %s",
759 gss_oid_to_name(gcp
->mech_type
),
760 (int)display_name_p
->length
, (char *)display_name_p
->value
,
762 ret
= KRB5_KDC_ERR_CLIENT_NAME_MISMATCH
;
766 gcp
->pac_data
= pac_data
;
767 krb5_data_zero(&pac_data
);
770 krb5_free_principal(r
->context
, initiator_princ
);
772 _kdc_free_ent(r
->context
, initiator
);
773 krb5_data_free(&pac_data
);
774 gss_release_buffer(&minor
, &display_name
);
780 _kdc_gss_mk_pa_reply(astgs_request_t r
,
781 gss_client_params
*gcp
)
784 const KDC_REQ
*req
= &r
->req
;
786 if (gcp
->major
== GSS_S_COMPLETE
) {
787 krb5_enctype enctype
;
789 krb5_keyblock
*reply_key
= NULL
;
791 if (krb5_principal_is_krbtgt(r
->context
, r
->server_princ
))
794 ret
= _kdc_find_etype(r
, kfe
, req
->req_body
.etype
.val
,
795 req
->req_body
.etype
.len
, &enctype
, NULL
, NULL
);
799 ret
= _krb5_gss_pa_derive_key(r
->context
, gcp
->context_handle
,
801 enctype
, &reply_key
);
803 kdc_log(r
->context
, r
->config
, 10,
804 "Failed to derive GSS reply key: %d", ret
);
808 krb5_free_keyblock_contents(r
->context
, &r
->reply_key
);
809 r
->reply_key
= *reply_key
;
811 } else if (gcp
->major
== GSS_S_CONTINUE_NEEDED
) {
812 ret
= pa_gss_set_context_state(r
, gcp
);
817 /* only return padata in error case if we have an error token */
818 if (!GSS_ERROR(gcp
->major
) || gcp
->output_token
.length
) {
819 ret
= krb5_padata_add(r
->context
, r
->rep
.padata
, KRB5_PADATA_GSS
,
820 gcp
->output_token
.value
, gcp
->output_token
.length
);
824 /* token is now owned by r->rep.padata */
825 gcp
->output_token
.length
= 0;
826 gcp
->output_token
.value
= NULL
;
829 if (gcp
->major
== GSS_S_CONTINUE_NEEDED
)
830 ret
= KRB5_KDC_ERR_MORE_PREAUTH_DATA_REQUIRED
;
832 ret
= _krb5_gss_map_error(gcp
->major
, gcp
->minor
);
838 _kdc_gss_mk_composite_name_ad(astgs_request_t r
,
839 gss_client_params
*gcp
)
844 OM_uint32 major
, minor
;
845 gss_buffer_desc namebuf
= GSS_C_EMPTY_BUFFER
;
847 if (!r
->config
->enable_gss_auth_data
|| (gcp
->flags
& GSS_C_ANON_FLAG
))
850 major
= gss_export_name_composite(&minor
, gcp
->initiator_name
, &namebuf
);
851 if (major
== GSS_S_COMPLETE
) {
852 _krb5_gss_buffer_to_data(&namebuf
, &data
);
854 ret
= _kdc_tkt_add_if_relevant_ad(r
->context
, &r
->et
,
855 KRB5_AUTHDATA_GSS_COMPOSITE_NAME
,
857 } else if (major
!= GSS_S_UNAVAILABLE
)
858 ret
= _krb5_gss_map_error(major
, minor
);
862 gss_release_buffer(&minor
, &namebuf
);
868 _kdc_gss_free_client_param(astgs_request_t r
,
869 gss_client_params
*gcp
)
876 gss_delete_sec_context(&minor
, &gcp
->context_handle
, GSS_C_NO_BUFFER
);
877 gss_release_name(&minor
, &gcp
->initiator_name
);
878 gss_release_buffer(&minor
, &gcp
->output_token
);
879 free_Checksum(&gcp
->req_body_checksum
);
880 krb5_data_free(&gcp
->pac_data
);
881 memset(gcp
, 0, sizeof(*gcp
));
886 _kdc_gss_get_mechanism_config(krb5_context context
,
892 char **mechs
, **mechp
;
894 gss_OID_set oids
= GSS_C_NO_OID_SET
;
895 OM_uint32 major
, minor
;
897 mechs
= krb5_config_get_strings(context
, NULL
, section
, key
, NULL
);
901 major
= gss_create_empty_oid_set(&minor
, &oids
);
902 if (GSS_ERROR(major
)) {
903 krb5_config_free_strings(mechs
);
904 return _krb5_gss_map_error(major
, minor
);
907 for (mechp
= mechs
; *mechp
; mechp
++) {
908 gss_OID oid
= gss_name_to_oid(*mechp
);
909 if (oid
== GSS_C_NO_OID
)
912 major
= gss_add_oid_set_member(&minor
, oid
, &oids
);
913 if (GSS_ERROR(major
))
917 ret
= _krb5_gss_map_error(major
, minor
);
921 gss_release_oid_set(&minor
, &oids
);
923 krb5_config_free_strings(mechs
);
929 pa_gss_display_status(astgs_request_t r
,
932 gss_client_params
*gcp
,
935 krb5_error_code ret
= _krb5_gss_map_error(major
, minor
);
936 gss_buffer_desc buf
= GSS_C_EMPTY_BUFFER
;
937 OM_uint32 dmaj
, dmin
;
944 gss_release_buffer(&dmin
, &buf
);
945 dmaj
= gss_display_status(&dmin
, major
, GSS_C_GSS_CODE
, GSS_C_NO_OID
,
947 if (GSS_ERROR(dmaj
) ||
948 buf
.length
>= INT_MAX
||
949 asprintf(&s
, "%s%s%.*s", gmsg
? gmsg
: "", gmsg
? ": " : "",
950 (int)buf
.length
, (char *)buf
.value
) == -1 ||
958 } while (!GSS_ERROR(dmaj
) && more
);
960 if (gcp
->mech_type
!= GSS_C_NO_OID
) {
962 gss_release_buffer(&dmin
, &buf
);
963 dmaj
= gss_display_status(&dmin
, major
, GSS_C_MECH_CODE
,
964 gcp
->mech_type
, &more
, &buf
);
965 if (GSS_ERROR(dmaj
) ||
966 asprintf(&s
, "%s%s%.*s", gmmsg
? gmmsg
: "", gmmsg
? ": " : "",
967 (int)buf
.length
, (char *)buf
.value
) == -1 ||
975 } while (!GSS_ERROR(dmaj
) && more
);
979 krb5_set_error_message(r
->context
, ENOMEM
,
980 "Error displaying GSS-API status");
982 krb5_set_error_message(r
->context
, ret
, "%s%s%s%s", gmsg
,
983 gmmsg
? " (" : "", gmmsg
? gmmsg
: "",
985 krb5_prepend_error_message(r
->context
, ret
, "%s", msg
);
987 kdc_log(r
->context
, r
->config
, 1,
989 msg
, gmsg
, gmmsg
? " (" : "", gmmsg
? gmmsg
: "",
996 static const gss_buffer_desc
997 gss_pa_unknown_display_name
= {
998 sizeof("<unknown name>") - 1,
1003 pa_gss_display_name(gss_name_t name
,
1004 gss_buffer_t namebuf
,
1005 gss_const_buffer_t
*namebuf_p
)
1007 OM_uint32 major
, minor
;
1009 major
= gss_display_name(&minor
, name
, namebuf
, NULL
);
1010 if (GSS_ERROR(major
))
1011 *namebuf_p
= &gss_pa_unknown_display_name
;
1013 *namebuf_p
= namebuf
;
1016 struct pa_gss_finalize_pac_plugin_ctx
{
1018 krb5_data
*pac_data
;
1021 static krb5_error_code KRB5_LIB_CALL
1022 pa_gss_finalize_pac_cb(krb5_context context
,
1027 const krb5plugin_gss_preauth_authorizer_ftable
*authorizer
= plug
;
1028 struct pa_gss_finalize_pac_plugin_ctx
*pa_gss_finalize_pac_ctx
= userctx
;
1030 return authorizer
->finalize_pac(plugctx
,
1031 pa_gss_finalize_pac_ctx
->r
,
1032 pa_gss_finalize_pac_ctx
->pac_data
);
1037 _kdc_gss_finalize_pac(astgs_request_t r
,
1038 gss_client_params
*gcp
)
1040 krb5_error_code ret
;
1041 struct pa_gss_finalize_pac_plugin_ctx ctx
;
1044 ctx
.pac_data
= &gcp
->pac_data
;
1046 krb5_clear_error_message(r
->context
);
1047 ret
= _krb5_plugin_run_f(r
->context
, &gss_preauth_authorizer_data
,
1048 0, &ctx
, pa_gss_finalize_pac_cb
);
1050 if (ret
== KRB5_PLUGIN_NO_HANDLE
)