Skip to content

Commit

Permalink
kdc: include SID in PAC with GSS authorizer
Browse files Browse the repository at this point in the history
Update the sample GSS pre-authentication authorizer plugin to allow the PAC to
be pinned to the authenticating user's SID.

There is still a race condition between the time the user authenticates and the
time the SID is looked up via LDAP, but it should be sufficient as an example;
if more security is required, then users should be enrolled with their SIDs.
  • Loading branch information
lhoward committed Dec 20, 2021
1 parent 07036c3 commit c1b82f6
Show file tree
Hide file tree
Showing 4 changed files with 150 additions and 39 deletions.
45 changes: 35 additions & 10 deletions kdc/altsecid_gss_preauth_authorizer.c
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -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) {
Expand Down Expand Up @@ -329,16 +335,23 @@ 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)
goto out;

ret = krb5_make_principal(context, canon_principal, realm,
values[0]->bv_val, NULL);
if (ret)
goto out;

goto out;

enomem:
Expand All @@ -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;
Expand All @@ -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))
Expand Down Expand Up @@ -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;
Expand All @@ -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;

Expand All @@ -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;
Expand All @@ -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 };

Expand Down
88 changes: 72 additions & 16 deletions kdc/gss_preauth.c
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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[] = {
Expand All @@ -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
};
Expand All @@ -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,
Expand All @@ -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;
}
Expand All @@ -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;
Expand Down Expand Up @@ -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);

Expand All @@ -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)
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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;
}
13 changes: 9 additions & 4 deletions kdc/gss_preauth_authorizer_plugin.h
Expand Up @@ -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 <krb5.h>
#include <gssapi/gssapi.h>

/*
* @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
*
Expand All @@ -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 */

0 comments on commit c1b82f6

Please sign in to comment.