diff --git a/kdc/altsecid_gss_preauth_authorizer.c b/kdc/altsecid_gss_preauth_authorizer.c index 8acce3a809..3dd370f385 100644 --- a/kdc/altsecid_gss_preauth_authorizer.c +++ b/kdc/altsecid_gss_preauth_authorizer.c @@ -70,6 +70,10 @@ #include "gss_preauth_authorizer_plugin.h" +#ifndef PAC_REQUESTOR_SID +#define PAC_REQUESTOR_SID 18 +#endif + struct ad_server_tuple { HEIM_TAILQ_ENTRY(ad_server_tuple) link; char *realm; @@ -267,7 +271,8 @@ ad_lookup(krb5_context context, struct ad_server_tuple *server, gss_const_name_t initiator_name, gss_const_OID mech_type, - krb5_principal *canon_principal) + krb5_principal *canon_principal, + krb5_data *requestor_sid) { krb5_error_code ret; OM_uint32 minor; @@ -277,10 +282,11 @@ ad_lookup(krb5_context context, LDAPMessage *m = NULL, *m0; char *basedn = NULL; int lret; - char *attrs[] = { "sAMAccountName", NULL }; + char *attrs[] = { "sAMAccountName", "objectSid", NULL }; struct berval **values = NULL; *canon_principal = NULL; + krb5_data_zero(requestor_sid); mech_type_str = gss_oid_to_name(mech_type); if (mech_type_str == NULL) { @@ -329,6 +335,16 @@ ad_lookup(krb5_context context, if (m0 == NULL) goto out; + values = ldap_get_values_len(server->ld, m0, "objectSid"); + if (values == NULL || + ldap_count_values_len(values) == 0) + goto out; + + if (krb5_data_copy(requestor_sid, values[0]->bv_val, values[0]->bv_len) != 0) + goto enomem; + + ldap_value_free_len(values); + values = ldap_get_values_len(server->ld, m0, "sAMAccountName"); if (values == NULL || ldap_count_values_len(values) == 0) @@ -336,9 +352,6 @@ ad_lookup(krb5_context context, ret = krb5_make_principal(context, canon_principal, realm, values[0]->bv_val, NULL); - if (ret) - goto out; - goto out; enomem: @@ -365,7 +378,8 @@ authorize(void *ctx, gss_const_OID mech_type, OM_uint32 ret_flags, krb5_boolean *authorized, - krb5_principal *mapped_name) + krb5_principal *mapped_name, + krb5_data *requestor_sid) { struct altsecid_gss_preauth_authorizer_context *c = ctx; struct ad_server_tuple *server = NULL; @@ -375,6 +389,7 @@ authorize(void *ctx, *authorized = FALSE; *mapped_name = NULL; + krb5_data_zero(requestor_sid); if (!krb5_principal_is_federated(context, client->entry.principal) || (ret_flags & GSS_C_ANON_FLAG)) @@ -408,7 +423,7 @@ authorize(void *ctx, ret = ad_lookup(context, realm, server, initiator_name, mech_type, - mapped_name); + mapped_name, requestor_sid); if (ret == KRB5KDC_ERR_SVC_UNAVAILABLE) { ldap_unbind_ext_s(server->ld, NULL, NULL); server->ld = NULL; @@ -424,7 +439,17 @@ authorize(void *ctx, } static KRB5_LIB_CALL krb5_error_code -altsecid_gss_preauth_authorizer_init(krb5_context context, void **contextp) +finalize_pac(void *ctx, + krb5_context context, + krb5_pac mspac, + krb5_data *requestor_sid) +{ + return krb5_pac_add_buffer(context, mspac, + PAC_REQUESTOR_SID, requestor_sid); +} + +static KRB5_LIB_CALL krb5_error_code +init(krb5_context context, void **contextp) { struct altsecid_gss_preauth_authorizer_context *c; @@ -439,7 +464,7 @@ altsecid_gss_preauth_authorizer_init(krb5_context context, void **contextp) } static KRB5_LIB_CALL void -altsecid_gss_preauth_authorizer_fini(void *context) +fini(void *context) { struct altsecid_gss_preauth_authorizer_context *c = context; struct ad_server_tuple *server, *next; @@ -456,7 +481,7 @@ altsecid_gss_preauth_authorizer_fini(void *context) } static krb5plugin_gss_preauth_authorizer_ftable plug_desc = - { 1, altsecid_gss_preauth_authorizer_init, altsecid_gss_preauth_authorizer_fini, authorize }; + { 1, init, fini, authorize, finalize_pac }; static krb5plugin_gss_preauth_authorizer_ftable *plugs[] = { &plug_desc }; diff --git a/kdc/gss_preauth.c b/kdc/gss_preauth.c index c1029f1005..58a627c2ea 100644 --- a/kdc/gss_preauth.c +++ b/kdc/gss_preauth.c @@ -51,6 +51,7 @@ struct gss_client_params { OM_uint32 flags; OM_uint32 lifetime; krb5_checksum req_body_checksum; + krb5_data pac_data; }; static void @@ -492,11 +493,12 @@ _kdc_gss_endtime(astgs_request_t r, return endtime; } -struct pa_gss_plugin_ctx { +struct pa_gss_authorize_plugin_ctx { astgs_request_t r; struct gss_client_params *gcp; krb5_boolean authorized; krb5_principal initiator_princ; + krb5_data pac_data; }; static krb5_error_code KRB5_LIB_CALL @@ -506,17 +508,18 @@ pa_gss_authorize_cb(krb5_context context, void *userctx) { const krb5plugin_gss_preauth_authorizer_ftable *authorizer = plug; - struct pa_gss_plugin_ctx *pa_gss_plugin_ctx = userctx; + struct pa_gss_authorize_plugin_ctx *pa_gss_authorize_plugin_ctx = userctx; return authorizer->authorize(plugctx, context, - &pa_gss_plugin_ctx->r->req, - pa_gss_plugin_ctx->r->client_princ, - pa_gss_plugin_ctx->r->client, - pa_gss_plugin_ctx->gcp->initiator_name, - pa_gss_plugin_ctx->gcp->mech_type, - pa_gss_plugin_ctx->gcp->flags, - &pa_gss_plugin_ctx->authorized, - &pa_gss_plugin_ctx->initiator_princ); + &pa_gss_authorize_plugin_ctx->r->req, + pa_gss_authorize_plugin_ctx->r->client_princ, + pa_gss_authorize_plugin_ctx->r->client, + pa_gss_authorize_plugin_ctx->gcp->initiator_name, + pa_gss_authorize_plugin_ctx->gcp->mech_type, + pa_gss_authorize_plugin_ctx->gcp->flags, + &pa_gss_authorize_plugin_ctx->authorized, + &pa_gss_authorize_plugin_ctx->initiator_princ, + &pa_gss_authorize_plugin_ctx->pac_data); } static const char *plugin_deps[] = { @@ -531,7 +534,7 @@ static struct heim_plugin_data gss_preauth_authorizer_data = { "kdc", KDC_GSS_PREAUTH_AUTHORIZER, - KDC_GSS_PREAUTH_AUTHORIZER_VERSION_0, + KDC_GSS_PREAUTH_AUTHORIZER_VERSION_1, plugin_deps, kdc_get_instance }; @@ -541,15 +544,17 @@ pa_gss_authorize_plugin(astgs_request_t r, struct gss_client_params *gcp, gss_const_buffer_t display_name, krb5_boolean *authorized, - krb5_principal *initiator_princ) + krb5_principal *initiator_princ, + krb5_data *pac_data) { krb5_error_code ret; - struct pa_gss_plugin_ctx ctx; + struct pa_gss_authorize_plugin_ctx ctx; ctx.r = r; ctx.gcp = gcp; ctx.authorized = 0; ctx.initiator_princ = NULL; + krb5_data_zero(&ctx.pac_data); krb5_clear_error_message(r->context); ret = _krb5_plugin_run_f(r->context, &gss_preauth_authorizer_data, @@ -570,6 +575,7 @@ pa_gss_authorize_plugin(astgs_request_t r, *authorized = ctx.authorized; *initiator_princ = ctx.initiator_princ; + *pac_data = ctx.pac_data; return ret; } @@ -579,7 +585,8 @@ pa_gss_authorize_default(astgs_request_t r, struct gss_client_params *gcp, gss_const_buffer_t display_name, krb5_boolean *authorized, - krb5_principal *initiator_princ) + krb5_principal *initiator_princ, + krb5_data *pac_data) { krb5_error_code ret; krb5_principal principal; @@ -681,12 +688,14 @@ _kdc_gss_check_client(astgs_request_t r, krb5_principal initiator_princ = NULL; hdb_entry_ex *initiator = NULL; krb5_boolean authorized = FALSE; + krb5_data pac_data; OM_uint32 minor; gss_buffer_desc display_name = GSS_C_EMPTY_BUFFER; gss_const_buffer_t display_name_p; *client_name = NULL; + krb5_data_zero(&pac_data); pa_gss_display_name(gcp->initiator_name, &display_name, &display_name_p); @@ -695,10 +704,10 @@ _kdc_gss_check_client(astgs_request_t r, * are authorized as the directly corresponding Kerberos principal. */ ret = pa_gss_authorize_plugin(r, gcp, display_name_p, - &authorized, &initiator_princ); + &authorized, &initiator_princ, &pac_data); if (ret == KRB5_PLUGIN_NO_HANDLE) ret = pa_gss_authorize_default(r, gcp, display_name_p, - &authorized, &initiator_princ); + &authorized, &initiator_princ, &pac_data); if (ret == 0 && !authorized) ret = KRB5_KDC_ERR_CLIENT_NAME_MISMATCH; if (ret) @@ -756,10 +765,14 @@ _kdc_gss_check_client(astgs_request_t r, goto out; } + gcp->pac_data = pac_data; + krb5_data_zero(&pac_data); + out: krb5_free_principal(r->context, initiator_princ); if (initiator) _kdc_free_ent(r->context, initiator); + krb5_data_free(&pac_data); gss_release_buffer(&minor, &display_name); return ret; @@ -866,6 +879,7 @@ _kdc_gss_free_client_param(astgs_request_t r, gss_release_name(&minor, &gcp->initiator_name); gss_release_buffer(&minor, &gcp->output_token); free_Checksum(&gcp->req_body_checksum); + krb5_data_free(&gcp->pac_data); memset(gcp, 0, sizeof(*gcp)); free(gcp); } @@ -1000,3 +1014,45 @@ pa_gss_display_name(gss_name_t name, else *namebuf_p = namebuf; } + +struct pa_gss_finalize_pac_plugin_ctx { + astgs_request_t r; + krb5_pac mspac; + krb5_data *pac_data; +}; + +static krb5_error_code KRB5_LIB_CALL +pa_gss_finalize_pac_cb(krb5_context context, + const void *plug, + void *plugctx, + void *userctx) +{ + const krb5plugin_gss_preauth_authorizer_ftable *authorizer = plug; + struct pa_gss_finalize_pac_plugin_ctx *pa_gss_finalize_pac_ctx = userctx; + + return authorizer->finalize_pac(plugctx, context, + pa_gss_finalize_pac_ctx->mspac, + pa_gss_finalize_pac_ctx->pac_data); +} + + +krb5_error_code +_kdc_gss_finalize_pac(astgs_request_t r, + gss_client_params *gcp, + krb5_pac mspac) +{ + krb5_error_code ret; + struct pa_gss_finalize_pac_plugin_ctx ctx; + + ctx.mspac = mspac; + ctx.pac_data = &gcp->pac_data; + + krb5_clear_error_message(r->context); + ret = _krb5_plugin_run_f(r->context, &gss_preauth_authorizer_data, + 0, &ctx, pa_gss_finalize_pac_cb); + + if (ret == KRB5_PLUGIN_NO_HANDLE) + ret = 0; + + return ret; +} diff --git a/kdc/gss_preauth_authorizer_plugin.h b/kdc/gss_preauth_authorizer_plugin.h index 5394e654b5..8763004b34 100644 --- a/kdc/gss_preauth_authorizer_plugin.h +++ b/kdc/gss_preauth_authorizer_plugin.h @@ -35,14 +35,14 @@ #define HEIMDAL_KDC_GSS_PREAUTH_AUTHORIZER_PLUGIN_H 1 #define KDC_GSS_PREAUTH_AUTHORIZER "kdc_gss_preauth_authorizer" -#define KDC_GSS_PREAUTH_AUTHORIZER_VERSION_0 0 +#define KDC_GSS_PREAUTH_AUTHORIZER_VERSION_1 1 #include #include /* * @param init Plugin initialization function (see krb5-plugin(7)) - * @param minor_version The plugin minor version number (0) + * @param minor_version The plugin minor version number (1) * @param fini Plugin finalization function * @param authorize Plugin name authorization function * @@ -69,10 +69,15 @@ typedef struct krb5plugin_gss_preauth_authorizer_ftable_desc { krb5_const_principal,/*client_name*/ hdb_entry_ex *, /*client*/ gss_const_name_t, /*initiator_name*/ - gss_const_OID, /*mech_type*/ + gss_const_OID, /*mech_type*/ OM_uint32, /*ret_flags*/ krb5_boolean *, /*authorized*/ - krb5_principal *); /*mapped_name*/ + krb5_principal *, /*mapped_name*/ + krb5_data *); /*pac_data*/ + krb5_error_code (KRB5_LIB_CALL *finalize_pac)(void *, /*plug_ctx*/ + krb5_context, /*context*/ + krb5_pac, /*pac*/ + krb5_data *); /*pac_data*/ } krb5plugin_gss_preauth_authorizer_ftable; #endif /* HEIMDAL_KDC_GSS_PREAUTH_AUTHORIZER_PLUGIN_H */ diff --git a/kdc/kerberos5.c b/kdc/kerberos5.c index a20f472ff3..4979e4bf05 100644 --- a/kdc/kerberos5.c +++ b/kdc/kerberos5.c @@ -566,7 +566,8 @@ pa_gss_validate(astgs_request_t r, _kdc_set_e_text(r, "GSS-API client not allowed to " "impersonate principal"); auth_status->auth_status = HDB_AUTHSTATUS_GSS_FAILURE; - goto out; + _kdc_gss_free_client_param(r, gcp); + return ret; } auth_status->auth_details = client_name; auth_status->free_ptr = client_name; @@ -579,7 +580,8 @@ pa_gss_validate(astgs_request_t r, ret = _kdc_gss_mk_composite_name_ad(r, gcp); if (ret) { _kdc_set_e_text(r, "Failed to build GSS authorization data"); - goto out; + _kdc_gss_free_client_param(r, gcp); + return ret; } } @@ -587,17 +589,40 @@ pa_gss_validate(astgs_request_t r, if (ret && ret != KRB5_KDC_ERR_MORE_PREAUTH_DATA_REQUIRED) { _kdc_set_e_text(r, "Failed to build GSS pre-authentication reply"); - goto out; + _kdc_gss_free_client_param(r, gcp); + return ret; } - auth_status->auth_status = HDB_AUTHSTATUS_GSS_SUCCESS; - out: - if (gcp) - _kdc_gss_free_client_param(r, gcp); + if (ret == 0) + auth_status->auth_status = HDB_AUTHSTATUS_GSS_SUCCESS; + + heim_assert(r->pa_state == NULL, "already have PA state"); + r->pa_state = (struct as_request_pa_state *)gcp; return ret; } +static krb5_error_code +pa_gss_finalize_pac(astgs_request_t r, krb5_pac mspac) +{ + gss_client_params *gcp = (gss_client_params *)r->pa_state; + + heim_assert(gcp != NULL, "invalid GSS-API client params"); + + return _kdc_gss_finalize_pac(r, gcp, mspac); +} + +static void +pa_gss_cleanup(astgs_request_t r) +{ + gss_client_params *gcp = (gss_client_params *)r->pa_state; + + if (gcp) { + _kdc_gss_free_client_param(r, gcp); + r->pa_state = NULL; + } +} + static krb5_error_code pa_enc_chal_validate(astgs_request_t r, const PA_DATA *pa, @@ -999,7 +1024,7 @@ static const struct kdc_patypes pat[] = { { KRB5_PADATA_GSS , "GSS", PA_ANNOUNCE | PA_SYNTHETIC_OK | PA_REPLACE_REPLY_KEY, - pa_gss_validate, NULL, NULL + pa_gss_validate, pa_gss_finalize_pac, pa_gss_cleanup }, }; @@ -2301,7 +2326,7 @@ _kdc_as_rep(astgs_request_t r) r->pa_used = pat[n].type; if (auth_status.auth_status == HDB_AUTHSTATUS_INVALID) - auth_status.auth_status = HDB_AUTHSTATUS_GENERIC_SUCCESS; + auth_status.auth_status = HDB_AUTHSTATUS_GENERIC_SUCCESS; _kdc_audit_auth_status(r, &auth_status,