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
);
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
)
138 memset(req_body_checksum
, 0, sizeof(*req_body_checksum
));
139 sec_context_token
->length
= 0;
140 sec_context_token
->value
= NULL
;
142 krb5_data_zero(&data
);
144 sp
= krb5_storage_from_readonly_mem(state
->data
, state
->length
);
146 ret
= krb5_enomem(r
->context
);
150 krb5_storage_set_eof_code(sp
, KRB5_BAD_MSIZE
);
151 krb5_storage_set_byteorder(sp
, KRB5_STORAGE_BYTEORDER_PACKED
);
153 ret
= krb5_ret_data(sp
, &data
);
157 ret
= krb5_ret_int32(sp
, &req_body_checksum
->cksumtype
);
161 if (req_body_checksum
->cksumtype
== CKSUMTYPE_NONE
||
162 krb5_checksum_is_keyed(r
->context
, req_body_checksum
->cksumtype
)) {
163 ret
= KRB5KDC_ERR_SUMTYPE_NOSUPP
;
167 ret
= krb5_checksumsize(r
->context
, req_body_checksum
->cksumtype
,
172 req_body_checksum
->checksum
.data
= malloc(cksumsize
);
173 if (req_body_checksum
->checksum
.data
== NULL
) {
174 ret
= krb5_enomem(r
->context
);
178 if (krb5_storage_read(sp
, req_body_checksum
->checksum
.data
,
179 cksumsize
) != cksumsize
) {
180 ret
= KRB5_BAD_MSIZE
;
184 req_body_checksum
->checksum
.length
= cksumsize
;
186 _krb5_gss_data_to_buffer(&data
, sec_context_token
);
190 krb5_data_free(&data
);
191 free_Checksum(req_body_checksum
);
192 memset(req_body_checksum
, 0, sizeof(*req_body_checksum
));
194 krb5_storage_free(sp
);
200 * Deserialize a GSS-API security context from the FAST cookie.
202 static krb5_error_code
203 pa_gss_get_context_state(astgs_request_t r
,
204 gss_client_params
*gcp
)
210 OM_uint32 major
, minor
;
211 gss_buffer_desc sec_context_token
;
213 fast_pa
= krb5_find_padata(r
->fast
.fast_state
.val
,
214 r
->fast
.fast_state
.len
,
215 KRB5_PADATA_GSS
, &idx
);
219 ret
= pa_gss_decode_context_state(r
, &fast_pa
->padata_value
,
221 &gcp
->req_body_checksum
);
225 ret
= pa_gss_verify_req_body_checksum(r
, &gcp
->req_body_checksum
);
227 gss_release_buffer(&minor
, &sec_context_token
);
231 major
= gss_import_sec_context(&minor
, &sec_context_token
,
232 &gcp
->context_handle
);
233 if (GSS_ERROR(major
)) {
234 pa_gss_display_status(r
, major
, minor
, gcp
,
235 "Failed to import GSS pre-authentication context");
236 ret
= _krb5_gss_map_error(major
, minor
);
240 gss_release_buffer(&minor
, &sec_context_token
);
246 * Encode the FX-COOKIE context state, consisting of the exported
247 * GSS context token concatenated with the checksum of the initial
250 static krb5_error_code
251 pa_gss_encode_context_state(astgs_request_t r
,
252 gss_const_buffer_t sec_context_token
,
253 const krb5_checksum
*req_body_checksum
,
260 krb5_data_zero(state
);
262 sp
= krb5_storage_emem();
264 ret
= krb5_enomem(r
->context
);
268 krb5_storage_set_byteorder(sp
, KRB5_STORAGE_BYTEORDER_PACKED
);
270 _krb5_gss_buffer_to_data(sec_context_token
, &data
);
272 ret
= krb5_store_data(sp
, data
);
276 ret
= krb5_store_int32(sp
, req_body_checksum
->cksumtype
);
280 ret
= krb5_store_bytes(sp
, req_body_checksum
->checksum
.data
,
281 req_body_checksum
->checksum
.length
);
285 ret
= krb5_storage_to_data(sp
, state
);
290 krb5_storage_free(sp
);
296 * Serialize a GSS-API security context into a FAST cookie.
298 static krb5_error_code
299 pa_gss_set_context_state(astgs_request_t r
,
300 gss_client_params
*gcp
)
307 OM_uint32 major
, minor
;
308 gss_buffer_desc sec_context_token
= GSS_C_EMPTY_BUFFER
;
311 * On second and subsequent responses, we can recycle the checksum
312 * from the request as it is validated and invariant. This saves
313 * re-encoding the request body again.
315 if (gcp
->req_body_checksum
.cksumtype
== CKSUMTYPE_NONE
) {
316 ret
= pa_gss_create_req_body_checksum(r
, &gcp
->req_body_checksum
);
321 major
= gss_export_sec_context(&minor
, &gcp
->context_handle
,
323 if (GSS_ERROR(major
)) {
324 pa_gss_display_status(r
, major
, minor
, gcp
,
325 "Failed to export GSS pre-authentication context");
326 return _krb5_gss_map_error(major
, minor
);
329 ret
= pa_gss_encode_context_state(r
, &sec_context_token
,
330 &gcp
->req_body_checksum
, &state
);
331 gss_release_buffer(&minor
, &sec_context_token
);
335 fast_pa
= krb5_find_padata(r
->fast
.fast_state
.val
,
336 r
->fast
.fast_state
.len
,
337 KRB5_PADATA_GSS
, &idx
);
339 krb5_data_free(&fast_pa
->padata_value
);
340 fast_pa
->padata_value
= state
;
342 ret
= krb5_padata_add(r
->context
, &r
->fast
.fast_state
,
344 state
.data
, state
.length
);
346 krb5_data_free(&state
);
352 static krb5_error_code
353 pa_gss_acquire_acceptor_cred(astgs_request_t r
,
354 gss_client_params
*gcp
,
358 krb5_principal tgs_name
;
360 OM_uint32 major
, minor
;
361 gss_name_t target_name
= GSS_C_NO_NAME
;
362 gss_buffer_desc display_name
= GSS_C_EMPTY_BUFFER
;
363 gss_const_buffer_t display_name_p
;
365 *cred
= GSS_C_NO_CREDENTIAL
;
367 ret
= krb5_make_principal(r
->context
, &tgs_name
, r
->req
.req_body
.realm
,
368 KRB5_TGS_NAME
, r
->req
.req_body
.realm
, NULL
);
372 ret
= _krb5_gss_pa_unparse_name(r
->context
, tgs_name
, &target_name
);
373 krb5_free_principal(r
->context
, tgs_name
);
377 pa_gss_display_name(target_name
, &display_name
, &display_name_p
);
379 kdc_log(r
->context
, r
->config
, 4,
380 "Acquiring GSS acceptor credential for %.*s",
381 (int)display_name_p
->length
, (char *)display_name_p
->value
);
383 major
= gss_acquire_cred(&minor
, target_name
, GSS_C_INDEFINITE
,
384 r
->config
->gss_mechanisms_allowed
,
385 GSS_C_ACCEPT
, cred
, NULL
, NULL
);
386 ret
= _krb5_gss_map_error(major
, minor
);
389 pa_gss_display_status(r
, major
, minor
, gcp
,
390 "Failed to acquire GSS acceptor credential");
392 gss_release_buffer(&minor
, &display_name
);
393 gss_release_name(&minor
, &target_name
);
399 _kdc_gss_rd_padata(astgs_request_t r
,
401 gss_client_params
**pgcp
,
407 gss_client_params
*gcp
= NULL
;
408 gss_cred_id_t cred
= GSS_C_NO_CREDENTIAL
;
409 gss_buffer_desc input_token
= GSS_C_EMPTY_BUFFER
;
410 struct gss_channel_bindings_struct cb
;
412 memset(&cb
, 0, sizeof(cb
));
416 if (!r
->config
->enable_gss_preauth
) {
417 ret
= KRB5KDC_ERR_POLICY
;
421 if (pa
->padata_value
.length
== 0) {
422 ret
= KRB5KDC_ERR_PREAUTH_FAILED
;
426 gcp
= heim_alloc(sizeof(*gcp
), "pa-gss-client-params", pa_gss_dealloc_client_params
);
428 ret
= krb5_enomem(r
->context
);
432 /* errors are fast fail until gss_accept_sec_context() is called */
433 gcp
->major
= GSS_S_NO_CONTEXT
;
435 ret
= pa_gss_get_context_state(r
, gcp
);
439 ret
= pa_gss_acquire_acceptor_cred(r
, gcp
, &cred
);
443 _krb5_gss_data_to_buffer(&pa
->padata_value
, &input_token
);
444 _krb5_gss_data_to_buffer(&r
->req
.req_body
._save
, &cb
.application_data
);
446 gcp
->major
= gss_accept_sec_context(&gcp
->minor
,
447 &gcp
->context_handle
,
451 &gcp
->initiator_name
,
456 NULL
); /* delegated_cred_handle */
458 ret
= _krb5_gss_map_error(gcp
->major
, gcp
->minor
);
460 if (GSS_ERROR(gcp
->major
)) {
461 pa_gss_display_status(r
, gcp
->major
, gcp
->minor
, gcp
,
462 "Failed to accept GSS security context");
463 } else if ((gcp
->flags
& GSS_C_ANON_FLAG
) && !_kdc_is_anon_request(&r
->req
)) {
464 kdc_log(r
->context
, r
->config
, 2,
465 "Anonymous GSS pre-authentication request w/o anonymous flag");
466 ret
= KRB5KDC_ERR_BADOPTION
;
468 *open
= (gcp
->major
== GSS_S_COMPLETE
);
471 gss_release_cred(&minor
, &cred
);
473 if (gcp
&& gcp
->major
!= GSS_S_NO_CONTEXT
)
482 _kdc_gss_endtime(astgs_request_t r
,
483 gss_client_params
*gcp
)
485 krb5_timestamp endtime
;
487 if (gcp
->lifetime
== GSS_C_INDEFINITE
)
490 endtime
= kdc_time
+ gcp
->lifetime
;
492 kdc_log(r
->context
, r
->config
, 10,
493 "GSS pre-authentication endtime is %ld", endtime
);
498 struct pa_gss_authorize_plugin_ctx
{
500 struct gss_client_params
*gcp
;
501 krb5_boolean authorized
;
502 krb5_principal initiator_princ
;
505 static krb5_error_code KRB5_LIB_CALL
506 pa_gss_authorize_cb(krb5_context context
,
511 const krb5plugin_gss_preauth_authorizer_ftable
*authorizer
= plug
;
512 struct pa_gss_authorize_plugin_ctx
*pa_gss_authorize_plugin_ctx
= userctx
;
514 return authorizer
->authorize(plugctx
,
515 pa_gss_authorize_plugin_ctx
->r
,
516 pa_gss_authorize_plugin_ctx
->gcp
->initiator_name
,
517 pa_gss_authorize_plugin_ctx
->gcp
->mech_type
,
518 pa_gss_authorize_plugin_ctx
->gcp
->flags
,
519 &pa_gss_authorize_plugin_ctx
->authorized
,
520 &pa_gss_authorize_plugin_ctx
->initiator_princ
);
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
)
548 struct pa_gss_authorize_plugin_ctx ctx
;
553 ctx
.initiator_princ
= NULL
;
555 krb5_clear_error_message(r
->context
);
556 ret
= _krb5_plugin_run_f(r
->context
, &gss_preauth_authorizer_data
,
557 0, &ctx
, pa_gss_authorize_cb
);
559 if (ret
!= KRB5_PLUGIN_NO_HANDLE
) {
560 const char *msg
= krb5_get_error_message(r
->context
, ret
);
562 kdc_log(r
->context
, r
->config
, 7,
563 "GSS authz plugin %sauthorize%s %s initiator %.*s: %s",
564 ctx
.authorized
? "" : "did not " ,
565 ctx
.authorized
? "d" : "",
566 gss_oid_to_name(gcp
->mech_type
),
567 (int)display_name
->length
, (char *)display_name
->value
,
569 krb5_free_error_message(r
->context
, msg
);
572 *authorized
= ctx
.authorized
;
573 *initiator_princ
= ctx
.initiator_princ
;
578 static krb5_error_code
579 pa_gss_authorize_default(astgs_request_t r
,
580 struct gss_client_params
*gcp
,
581 gss_const_buffer_t display_name
,
582 krb5_boolean
*authorized
,
583 krb5_principal
*initiator_princ
)
586 krb5_principal principal
;
587 krb5_const_realm realm
= r
->server
->entry
.principal
->realm
;
588 int flags
= 0, cross_realm_allowed
= 0, unauth_anon
;
591 * gss_cross_realm_mechanisms_allowed is a list of GSS-API mechanisms
592 * that are allowed to map directly to Kerberos principals in any
593 * realm. If the authenticating mechanism is not on the list, then
594 * the initiator will be mapped to an enterprise principal in the
595 * service realm. This is useful to stop synthetic principals in
596 * foreign realms being conflated with true cross-realm principals.
598 if (r
->config
->gss_cross_realm_mechanisms_allowed
) {
601 gss_test_oid_set_member(&minor
, gcp
->mech_type
,
602 r
->config
->gss_cross_realm_mechanisms_allowed
,
603 &cross_realm_allowed
);
606 kdc_log(r
->context
, r
->config
, 10,
607 "Initiator %.*s will be mapped to %s",
608 (int)display_name
->length
, (char *)display_name
->value
,
609 cross_realm_allowed
? "nt-principal" : "nt-enterprise-principal");
611 if (!cross_realm_allowed
)
612 flags
|= KRB5_PRINCIPAL_PARSE_ENTERPRISE
| KRB5_PRINCIPAL_PARSE_NO_REALM
;
614 ret
= _krb5_gss_pa_parse_name(r
->context
, gcp
->initiator_name
,
617 const char *msg
= krb5_get_error_message(r
->context
, ret
);
619 kdc_log(r
->context
, r
->config
, 2,
620 "Failed to parse %s initiator name %.*s: %s",
621 gss_oid_to_name(gcp
->mech_type
),
622 (int)display_name
->length
, (char *)display_name
->value
, msg
);
623 krb5_free_error_message(r
->context
, msg
);
629 * GSS_C_ANON_FLAG indicates the client requested anonymous authentication
630 * (it is validated against the request-anonymous flag).
632 * _kdc_is_anonymous_pkinit() returns TRUE if the principal contains both
633 * the well known anonymous name and realm.
635 unauth_anon
= (gcp
->flags
& GSS_C_ANON_FLAG
) &&
636 _kdc_is_anonymous_pkinit(r
->context
, principal
);
639 * Always use the anonymous entry created in our HDB, i.e. with the local
640 * realm, for authorizing anonymous requests. This matches PKINIT behavior
641 * as anonymous PKINIT requests include the KDC realm in the request.
643 if (unauth_anon
|| (flags
& KRB5_PRINCIPAL_PARSE_ENTERPRISE
)) {
644 ret
= krb5_principal_set_realm(r
->context
, principal
, realm
);
646 krb5_free_principal(r
->context
, principal
);
653 * Special case to avoid changing _kdc_as_rep(). If the initiator is
654 * the unauthenticated anonymous principal, r->client_princ also needs
655 * to be set in order to force the AS-REP realm to be set to the well-
656 * known anonymous identity. This is because (unlike anonymous PKINIT)
657 * we only require the anonymous flag, not the anonymous name, in the
660 krb5_principal anon_princ
;
662 ret
= krb5_copy_principal(r
->context
, principal
, &anon_princ
);
666 krb5_free_principal(r
->context
, r
->client_princ
);
667 r
->client_princ
= anon_princ
;
671 *initiator_princ
= principal
;
677 _kdc_gss_check_client(astgs_request_t r
,
678 gss_client_params
*gcp
,
682 krb5_principal initiator_princ
= NULL
;
683 hdb_entry_ex
*initiator
= NULL
;
684 krb5_boolean authorized
= FALSE
;
687 gss_buffer_desc display_name
= GSS_C_EMPTY_BUFFER
;
688 gss_const_buffer_t display_name_p
;
692 pa_gss_display_name(gcp
->initiator_name
, &display_name
, &display_name_p
);
695 * If no plugins handled the authorization request, then all clients
696 * are authorized as the directly corresponding Kerberos principal.
698 ret
= pa_gss_authorize_plugin(r
, gcp
, display_name_p
,
699 &authorized
, &initiator_princ
);
700 if (ret
== KRB5_PLUGIN_NO_HANDLE
)
701 ret
= pa_gss_authorize_default(r
, gcp
, display_name_p
,
702 &authorized
, &initiator_princ
);
703 if (ret
== 0 && !authorized
)
704 ret
= KRB5_KDC_ERR_CLIENT_NAME_MISMATCH
;
708 ret
= krb5_unparse_name(r
->context
, initiator_princ
, client_name
);
712 kdc_log(r
->context
, r
->config
, 4,
713 "Mapped GSS %s initiator %.*s to principal %s",
714 gss_oid_to_name(gcp
->mech_type
),
715 (int)display_name_p
->length
, (char *)display_name_p
->value
,
718 ret
= _kdc_db_fetch(r
->context
,
721 HDB_F_FOR_AS_REQ
| HDB_F_GET_CLIENT
|
722 HDB_F_CANON
| HDB_F_SYNTHETIC_OK
,
727 const char *msg
= krb5_get_error_message(r
->context
, ret
);
729 kdc_log(r
->context
, r
->config
, 4, "UNKNOWN -- %s: %s",
731 krb5_free_error_message(r
->context
, msg
);
737 * If the AS-REQ client name was the well-known federated name, then
738 * replace the client name with the initiator name. Otherwise, the
739 * two principals must match, noting that GSS pre-authentication is
740 * for authentication, not general purpose impersonation.
742 if (krb5_principal_is_federated(r
->context
, r
->client
->entry
.principal
)) {
743 initiator
->entry
.flags
.force_canonicalize
= 1;
745 _kdc_free_ent(r
->context
, r
->client
);
746 r
->client
= initiator
;
748 } else if (!krb5_principal_compare(r
->context
,
749 r
->client
->entry
.principal
,
750 initiator
->entry
.principal
)) {
751 kdc_log(r
->context
, r
->config
, 2,
752 "GSS %s initiator %.*s does not match principal %s",
753 gss_oid_to_name(gcp
->mech_type
),
754 (int)display_name_p
->length
, (char *)display_name_p
->value
,
756 ret
= KRB5_KDC_ERR_CLIENT_NAME_MISMATCH
;
761 krb5_free_principal(r
->context
, initiator_princ
);
763 _kdc_free_ent(r
->context
, initiator
);
764 gss_release_buffer(&minor
, &display_name
);
770 _kdc_gss_mk_pa_reply(astgs_request_t r
,
771 gss_client_params
*gcp
)
774 const KDC_REQ
*req
= &r
->req
;
776 if (gcp
->major
== GSS_S_COMPLETE
) {
777 krb5_enctype enctype
;
779 krb5_keyblock
*reply_key
= NULL
;
781 if (krb5_principal_is_krbtgt(r
->context
, r
->server_princ
))
784 ret
= _kdc_find_etype(r
, kfe
, req
->req_body
.etype
.val
,
785 req
->req_body
.etype
.len
, &enctype
, NULL
, NULL
);
789 ret
= _krb5_gss_pa_derive_key(r
->context
, gcp
->context_handle
,
791 enctype
, &reply_key
);
793 kdc_log(r
->context
, r
->config
, 10,
794 "Failed to derive GSS reply key: %d", ret
);
798 krb5_free_keyblock_contents(r
->context
, &r
->reply_key
);
799 r
->reply_key
= *reply_key
;
801 } else if (gcp
->major
== GSS_S_CONTINUE_NEEDED
) {
802 ret
= pa_gss_set_context_state(r
, gcp
);
807 /* only return padata in error case if we have an error token */
808 if (!GSS_ERROR(gcp
->major
) || gcp
->output_token
.length
) {
809 ret
= krb5_padata_add(r
->context
, r
->rep
.padata
, KRB5_PADATA_GSS
,
810 gcp
->output_token
.value
, gcp
->output_token
.length
);
814 /* token is now owned by r->rep.padata */
815 gcp
->output_token
.length
= 0;
816 gcp
->output_token
.value
= NULL
;
819 if (gcp
->major
== GSS_S_CONTINUE_NEEDED
)
820 ret
= KRB5_KDC_ERR_MORE_PREAUTH_DATA_REQUIRED
;
822 ret
= _krb5_gss_map_error(gcp
->major
, gcp
->minor
);
828 _kdc_gss_mk_composite_name_ad(astgs_request_t r
,
829 gss_client_params
*gcp
)
834 OM_uint32 major
, minor
;
835 gss_buffer_desc namebuf
= GSS_C_EMPTY_BUFFER
;
837 if (!r
->config
->enable_gss_auth_data
|| (gcp
->flags
& GSS_C_ANON_FLAG
))
840 major
= gss_export_name_composite(&minor
, gcp
->initiator_name
, &namebuf
);
841 if (major
== GSS_S_COMPLETE
) {
842 _krb5_gss_buffer_to_data(&namebuf
, &data
);
844 ret
= _kdc_tkt_add_if_relevant_ad(r
->context
, &r
->et
,
845 KRB5_AUTHDATA_GSS_COMPOSITE_NAME
,
847 } else if (major
!= GSS_S_UNAVAILABLE
)
848 ret
= _krb5_gss_map_error(major
, minor
);
852 gss_release_buffer(&minor
, &namebuf
);
858 pa_gss_dealloc_client_params(void *ptr
)
860 gss_client_params
*gcp
= ptr
;
866 gss_delete_sec_context(&minor
, &gcp
->context_handle
, GSS_C_NO_BUFFER
);
867 gss_release_name(&minor
, &gcp
->initiator_name
);
868 gss_release_buffer(&minor
, &gcp
->output_token
);
869 free_Checksum(&gcp
->req_body_checksum
);
870 memset(gcp
, 0, sizeof(*gcp
));
874 _kdc_gss_get_mechanism_config(krb5_context context
,
880 char **mechs
, **mechp
;
882 gss_OID_set oids
= GSS_C_NO_OID_SET
;
883 OM_uint32 major
, minor
;
885 mechs
= krb5_config_get_strings(context
, NULL
, section
, key
, NULL
);
889 major
= gss_create_empty_oid_set(&minor
, &oids
);
890 if (GSS_ERROR(major
)) {
891 krb5_config_free_strings(mechs
);
892 return _krb5_gss_map_error(major
, minor
);
895 for (mechp
= mechs
; *mechp
; mechp
++) {
896 gss_OID oid
= gss_name_to_oid(*mechp
);
897 if (oid
== GSS_C_NO_OID
)
900 major
= gss_add_oid_set_member(&minor
, oid
, &oids
);
901 if (GSS_ERROR(major
))
905 ret
= _krb5_gss_map_error(major
, minor
);
909 gss_release_oid_set(&minor
, &oids
);
911 krb5_config_free_strings(mechs
);
917 pa_gss_display_status(astgs_request_t r
,
920 gss_client_params
*gcp
,
923 krb5_error_code ret
= _krb5_gss_map_error(major
, minor
);
924 gss_buffer_desc buf
= GSS_C_EMPTY_BUFFER
;
925 OM_uint32 dmaj
, dmin
;
932 gss_release_buffer(&dmin
, &buf
);
933 dmaj
= gss_display_status(&dmin
, major
, GSS_C_GSS_CODE
, GSS_C_NO_OID
,
935 if (GSS_ERROR(dmaj
) ||
936 buf
.length
>= INT_MAX
||
937 asprintf(&s
, "%s%s%.*s", gmsg
? gmsg
: "", gmsg
? ": " : "",
938 (int)buf
.length
, (char *)buf
.value
) == -1 ||
946 } while (!GSS_ERROR(dmaj
) && more
);
948 if (gcp
->mech_type
!= GSS_C_NO_OID
) {
950 gss_release_buffer(&dmin
, &buf
);
951 dmaj
= gss_display_status(&dmin
, major
, GSS_C_MECH_CODE
,
952 gcp
->mech_type
, &more
, &buf
);
953 if (GSS_ERROR(dmaj
) ||
954 asprintf(&s
, "%s%s%.*s", gmmsg
? gmmsg
: "", gmmsg
? ": " : "",
955 (int)buf
.length
, (char *)buf
.value
) == -1 ||
963 } while (!GSS_ERROR(dmaj
) && more
);
967 krb5_set_error_message(r
->context
, ENOMEM
,
968 "Error displaying GSS-API status");
970 krb5_set_error_message(r
->context
, ret
, "%s%s%s%s", gmsg
,
971 gmmsg
? " (" : "", gmmsg
? gmmsg
: "",
973 krb5_prepend_error_message(r
->context
, ret
, "%s", msg
);
975 kdc_log(r
->context
, r
->config
, 1,
977 msg
, gmsg
, gmmsg
? " (" : "", gmmsg
? gmmsg
: "",
984 static const gss_buffer_desc
985 gss_pa_unknown_display_name
= {
986 sizeof("<unknown name>") - 1,
991 pa_gss_display_name(gss_name_t name
,
992 gss_buffer_t namebuf
,
993 gss_const_buffer_t
*namebuf_p
)
995 OM_uint32 major
, minor
;
997 major
= gss_display_name(&minor
, name
, namebuf
, NULL
);
998 if (GSS_ERROR(major
))
999 *namebuf_p
= &gss_pa_unknown_display_name
;
1001 *namebuf_p
= namebuf
;
1004 static krb5_error_code KRB5_LIB_CALL
1005 pa_gss_finalize_pac_cb(krb5_context context
,
1010 const krb5plugin_gss_preauth_authorizer_ftable
*authorizer
= plug
;
1012 return authorizer
->finalize_pac(plugctx
, userctx
);
1017 _kdc_gss_finalize_pac(astgs_request_t r
,
1018 gss_client_params
*gcp
)
1020 krb5_error_code ret
;
1022 krb5_clear_error_message(r
->context
);
1023 ret
= _krb5_plugin_run_f(r
->context
, &gss_preauth_authorizer_data
,
1024 0, r
, pa_gss_finalize_pac_cb
);
1026 if (ret
== KRB5_PLUGIN_NO_HANDLE
)