From: Greg Hudson Date: Sun, 23 May 2010 20:23:31 +0000 (+0000) Subject: Make signedpath authdata visible via GSS naming exts X-Git-Tag: krb5-1.9-beta1~215 X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=d2a071db7a60c5fe8ee48f83154a86b50fa38e0a;p=krb5.git Make signedpath authdata visible via GSS naming exts Merge users/lhoward/signedpath-naming-exts to trunk. Adds an authdata provider which makes non-PAC S4U2Proxy signedpath authdata visible to application servers via GSS naming extensions. ticket: 6733 git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@24094 dc483132-0cff-0310-8789-dd5450dbe970 --- diff --git a/src/lib/krb5/krb/Makefile.in b/src/lib/krb5/krb/Makefile.in index ba9903209..3b3dcd74d 100644 --- a/src/lib/krb5/krb/Makefile.in +++ b/src/lib/krb5/krb/Makefile.in @@ -86,6 +86,7 @@ STLIBOBJS= \ rd_req_dec.o \ rd_safe.o \ recvauth.o \ + s4u_authdata.o \ s4u_creds.o \ sendauth.o \ send_tgs.o \ @@ -184,6 +185,7 @@ OBJS= $(OUTPRE)addr_comp.$(OBJEXT) \ $(OUTPRE)rd_req_dec.$(OBJEXT) \ $(OUTPRE)rd_safe.$(OBJEXT) \ $(OUTPRE)recvauth.$(OBJEXT) \ + $(OUTPRE)s4u_authdata.$(OBJEXT) \ $(OUTPRE)s4u_creds.$(OBJEXT) \ $(OUTPRE)sendauth.$(OBJEXT) \ $(OUTPRE)send_tgs.$(OBJEXT) \ @@ -283,6 +285,7 @@ SRCS= $(srcdir)/addr_comp.c \ $(srcdir)/rd_req_dec.c \ $(srcdir)/rd_safe.c \ $(srcdir)/recvauth.c \ + $(srcdir)/s4u_authdata.c\ $(srcdir)/s4u_creds.c \ $(srcdir)/sendauth.c \ $(srcdir)/send_tgs.c \ diff --git a/src/lib/krb5/krb/authdata.c b/src/lib/krb5/krb/authdata.c index d98bfe943..3664b66d0 100644 --- a/src/lib/krb5/krb/authdata.c +++ b/src/lib/krb5/krb/authdata.c @@ -44,6 +44,7 @@ static const char *objdirs[] = { /* Internal authdata systems */ static krb5plugin_authdata_client_ftable_v0 *authdata_systems[] = { &krb5int_mspac_authdata_client_ftable, + &krb5int_s4u2proxy_authdata_client_ftable, NULL }; diff --git a/src/lib/krb5/krb/authdata.h b/src/lib/krb5/krb/authdata.h index 090ce336a..af5016ebb 100644 --- a/src/lib/krb5/krb/authdata.h +++ b/src/lib/krb5/krb/authdata.h @@ -88,6 +88,7 @@ struct krb5_pac_data { #define NT_TIME_EPOCH 11644473600LL extern krb5plugin_authdata_client_ftable_v0 krb5int_mspac_authdata_client_ftable; +extern krb5plugin_authdata_client_ftable_v0 krb5int_s4u2proxy_authdata_client_ftable; krb5_error_code k5_pac_locate_buffer(krb5_context context, diff --git a/src/lib/krb5/krb/pac.c b/src/lib/krb5/krb/pac.c index b3be61c84..5b6e18288 100644 --- a/src/lib/krb5/krb/pac.c +++ b/src/lib/krb5/krb/pac.c @@ -1053,10 +1053,10 @@ mspac_export_internal(krb5_context kcontext, *ptr = NULL; if (pacctx->pac == NULL) - return 0; + return ENOENT; if (restrict_authenticated && (pacctx->pac->verified) == FALSE) - return 0; + return ENOENT; code = krb5_pac_parse(kcontext, pacctx->pac->data.data, pacctx->pac->data.length, &pac); diff --git a/src/lib/krb5/krb/s4u_authdata.c b/src/lib/krb5/krb/s4u_authdata.c new file mode 100644 index 000000000..3c9ccb036 --- /dev/null +++ b/src/lib/krb5/krb/s4u_authdata.c @@ -0,0 +1,608 @@ +/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ +/* + * Copyright 2010 by the Massachusetts Institute of Technology. All + * Rights Reserved. + * + * Export of this software from the United States of America may + * require a specific license from the United States Government. + * It is the responsibility of any person or organization contemplating + * export to obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + * distribute this software and its documentation for any purpose and + * without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright notice and + * this permission notice appear in supporting documentation, and that + * the name of M.I.T. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. Furthermore if you modify this software you must label + * your software as modified software and not distribute it in such a + * fashion that it might be confused with the original M.I.T. software. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + * + */ + +#include "k5-int.h" +#include "authdata.h" +#include "auth_con.h" +#include "int-proto.h" + +/* + * Authdata backend for processing SignedPath. Presently does not handle + * the equivalent information in [MS-PAC], as that would require an NDR + * interpreter. + */ + +struct s4u2proxy_context { + int count; + krb5_principal *delegated; + krb5_boolean authenticated; +}; + +static krb5_error_code +s4u2proxy_init(krb5_context kcontext, void **plugin_context) +{ + *plugin_context = NULL; + return 0; +} + +static void +s4u2proxy_flags(krb5_context kcontext, + void *plugin_context, + krb5_authdatatype ad_type, + krb5_flags *flags) +{ + *flags = AD_USAGE_KDC_ISSUED; +} + +static void +s4u2proxy_fini(krb5_context kcontext, void *plugin_context) +{ + return; +} + +static krb5_error_code +s4u2proxy_request_init(krb5_context kcontext, + krb5_authdata_context context, + void *plugin_context, + void **request_context) +{ + krb5_error_code code; + struct s4u2proxy_context *s4uctx; + + s4uctx = k5alloc(sizeof(*s4uctx), &code); + if (s4uctx == NULL) + return code; + + s4uctx->count = 0; + s4uctx->delegated = NULL; + s4uctx->authenticated = FALSE; + + *request_context = s4uctx; + + return 0; +} + +static void +s4u2proxy_free_internal(krb5_context kcontext, + krb5_authdata_context context, + void *plugin_context, + void *request_context, + void *ptr) +{ + krb5_principal *delegated = (krb5_principal *)ptr; + int i; + + if (delegated != NULL) { + for (i = 0; delegated[i] != NULL; i++) + krb5_free_principal(kcontext, delegated[i]); + free(delegated); + } +} + +static krb5_error_code +s4u2proxy_import_authdata(krb5_context kcontext, + krb5_authdata_context context, + void *plugin_context, + void *request_context, + krb5_authdata **authdata, + krb5_boolean kdc_issued, + krb5_const_principal kdc_issuer) +{ + struct s4u2proxy_context *s4uctx = (struct s4u2proxy_context *)request_context; + krb5_error_code code; + krb5_ad_signedpath *sp; + krb5_data enc_sp; + + enc_sp.data = (char *)authdata[0]->contents; + enc_sp.length = authdata[0]->length; + + code = decode_krb5_ad_signedpath(&enc_sp, &sp); + if (code != 0) + return code; + + s4u2proxy_free_internal(kcontext, context, + plugin_context, request_context, + s4uctx->delegated); + + s4uctx->delegated = sp->delegated; + sp->delegated = NULL; + + krb5_free_ad_signedpath(kcontext, sp); + + s4uctx->count = 0; + + if (s4uctx->delegated != NULL) { + for (s4uctx->count = 0; s4uctx->delegated[s4uctx->count]; + s4uctx->count++) + ; + } + + s4uctx->authenticated = FALSE; + + return 0; +} + +static krb5_error_code +s4u2proxy_export_authdata(krb5_context kcontext, + krb5_authdata_context context, + void *plugin_context, + void *request_context, + krb5_flags usage, + krb5_authdata ***out_authdata) +{ + struct s4u2proxy_context *s4uctx = (struct s4u2proxy_context *)request_context; + krb5_error_code code; + krb5_ad_signedpath sp; + krb5_authdata **authdata; + krb5_data *data; + + if (s4uctx->count == 0) + return 0; + + memset(&sp, 0, sizeof(sp)); + sp.delegated = s4uctx->delegated; + + authdata = k5alloc(2 * sizeof(krb5_authdata *), &code); + if (authdata == NULL) + return code; + + authdata[0] = k5alloc(sizeof(krb5_authdata), &code); + if (authdata[0] == NULL) + return code; + + code = encode_krb5_ad_signedpath(&sp, &data); + if (code != 0) { + krb5_free_authdata(kcontext, authdata); + return code; + } + + authdata[0]->magic = KV5M_AUTHDATA; + authdata[0]->ad_type = KRB5_AUTHDATA_SIGNTICKET; + authdata[0]->length = data->length; + authdata[0]->contents = (krb5_octet *)data->data; + + authdata[1] = NULL; + + free(data); + + *out_authdata = authdata; + + return 0; +} + +static krb5_error_code +s4u2proxy_verify(krb5_context kcontext, + krb5_authdata_context context, + void *plugin_context, + void *request_context, + const krb5_auth_context *auth_context, + const krb5_keyblock *key, + const krb5_ap_req *req) +{ + /* + * XXX there is no way to verify the SignedPath without the TGS + * key. This means that we can never mark this as authenticated. + */ + + return 0; +} + +static void +s4u2proxy_request_fini(krb5_context kcontext, + krb5_authdata_context context, + void *plugin_context, + void *request_context) +{ + struct s4u2proxy_context *s4uctx = (struct s4u2proxy_context *)request_context; + + if (s4uctx == NULL) + return; + + s4u2proxy_free_internal(kcontext, context, + plugin_context, request_context, + s4uctx->delegated); + free(s4uctx); +} + +/* + * Nomenclature defined to be similar to [MS-PAC] 2.9, for future + * interoperability + */ + +#if 0 +static krb5_data s4u2proxy_proxy_target_attr = { + KV5M_DATA, + sizeof("urn:constrained-delegation:proxy-target") - 1, + "urn:constrained-delegation:proxy-target" +}; +#endif + +static krb5_data s4u2proxy_transited_services_attr = { + KV5M_DATA, + sizeof("urn:constrained-delegation:transited-services") - 1, + "urn:constrained-delegation:transited-services" +}; + +static krb5_error_code +s4u2proxy_get_attribute_types(krb5_context kcontext, + krb5_authdata_context context, + void *plugin_context, + void *request_context, + krb5_data **out_attrs) +{ + struct s4u2proxy_context *s4uctx = (struct s4u2proxy_context *)request_context; + krb5_error_code code; + krb5_data *attrs; + int i = 0; + + if (s4uctx->count == 0) + return ENOENT; + + attrs = k5alloc(2 * sizeof(krb5_data), &code); + if (attrs == NULL) + goto cleanup; + + code = krb5int_copy_data_contents(kcontext, + &s4u2proxy_transited_services_attr, + &attrs[i++]); + if (code != 0) + goto cleanup; + + attrs[i].data = NULL; + attrs[i].length = 0; + + *out_attrs = attrs; + attrs = NULL; + +cleanup: + if (attrs != NULL) { + for (i = 0; attrs[i].data; i++) + krb5_free_data_contents(kcontext, &attrs[i]); + free(attrs); + } + + return 0; +} + +static krb5_error_code +s4u2proxy_get_attribute(krb5_context kcontext, + krb5_authdata_context context, + void *plugin_context, + void *request_context, + const krb5_data *attribute, + krb5_boolean *authenticated, + krb5_boolean *complete, + krb5_data *value, + krb5_data *display_value, + int *more) +{ + struct s4u2proxy_context *s4uctx = (struct s4u2proxy_context *)request_context; + krb5_error_code code; + krb5_principal principal; + int i; + + if (display_value != NULL) { + display_value->data = NULL; + display_value->length = 0; + } + + if (!data_eq(*attribute, s4u2proxy_transited_services_attr)) + return ENOENT; + + i = -(*more) - 1; + if (i < 0) + return EINVAL; + else if (i >= s4uctx->count) + return ENOENT; + + principal = s4uctx->delegated[i]; + assert(principal != NULL); + + code = krb5_unparse_name_flags(kcontext, principal, 0, &value->data); + if (code != 0) + return code; + + value->length = strlen(value->data); + + if (display_value != NULL) { + code = krb5_unparse_name_flags(kcontext, principal, + KRB5_PRINCIPAL_UNPARSE_DISPLAY, + &display_value->data); + if (code != 0) + return code; + + display_value->length = strlen(display_value->data); + } + + i++; + + if (i == s4uctx->count) + *more = 0; + else + *more = -(i + 1); + + *authenticated = s4uctx->authenticated; + *complete = TRUE; + + return 0; +} + +static krb5_error_code +s4u2proxy_set_attribute(krb5_context kcontext, + krb5_authdata_context context, + void *plugin_context, + void *request_context, + krb5_boolean complete, + const krb5_data *attribute, + const krb5_data *value) +{ + /* Only the KDC can set this attribute. */ + + return EPERM; +} + +static krb5_error_code +s4u2proxy_export_internal(krb5_context kcontext, + krb5_authdata_context context, + void *plugin_context, + void *request_context, + krb5_boolean restrict_authenticated, + void **ptr) +{ + struct s4u2proxy_context *s4uctx = (struct s4u2proxy_context *)request_context; + krb5_error_code code; + int i; + krb5_principal *delegated; + + *ptr = NULL; + + if (s4uctx->count == 0) + return ENOENT; + + if (restrict_authenticated) + return ENOENT; + + delegated = k5alloc((s4uctx->count + 1) * sizeof(krb5_principal), &code); + if (delegated == NULL) + return code; + + for (i = 0; i < s4uctx->count; i++) { + code = krb5_copy_principal(kcontext, s4uctx->delegated[i], + &delegated[i]); + if (code != 0) + goto cleanup; + } + + delegated[i] = NULL; + + *ptr = delegated; + delegated = NULL; + +cleanup: + s4u2proxy_free_internal(kcontext, context, + plugin_context, request_context, + delegated); + + return code; +} + +static krb5_error_code +s4u2proxy_size(krb5_context kcontext, + krb5_authdata_context context, + void *plugin_context, + void *request_context, + size_t *sizep) +{ + struct s4u2proxy_context *s4uctx = (struct s4u2proxy_context *)request_context; + krb5_error_code code = 0; + int i; + + *sizep += sizeof(krb5_int32); /* version */ + *sizep += sizeof(krb5_int32); /* princ count */ + + for (i = 0; i < s4uctx->count; i++) { + code = krb5_size_opaque(kcontext, KV5M_PRINCIPAL, + (krb5_pointer)s4uctx->delegated[i], sizep); + if (code != 0) + return code; + } + + *sizep += sizeof(krb5_int32); /* authenticated flag */ + + return code; +} + +static krb5_error_code +s4u2proxy_externalize(krb5_context kcontext, + krb5_authdata_context context, + void *plugin_context, + void *request_context, + krb5_octet **buffer, + size_t *lenremain) +{ + struct s4u2proxy_context *s4uctx = (struct s4u2proxy_context *)request_context; + krb5_error_code code = 0; + size_t required = 0; + krb5_octet *bp; + size_t remain; + int i = 0; + + bp = *buffer; + remain = *lenremain; + + s4u2proxy_size(kcontext, context, plugin_context, + request_context, &required); + + if (required > remain) + return ENOMEM; + + krb5_ser_pack_int32(1, &bp, &remain); /* version */ + krb5_ser_pack_int32(s4uctx->count, &bp, &remain); /* princ count */ + + for (i = 0; i < s4uctx->count; i++) { + code = krb5_externalize_opaque(kcontext, KV5M_PRINCIPAL, + (krb5_pointer)s4uctx->delegated[i], + &bp, &remain); + if (code != 0) + return code; + } + + krb5_ser_pack_int32(s4uctx->authenticated, &bp, &remain); /* authenticated */ + + *buffer = bp; + *lenremain = remain; + + return 0; +} + +static krb5_error_code +s4u2proxy_internalize(krb5_context kcontext, + krb5_authdata_context context, + void *plugin_context, + void *request_context, + krb5_octet **buffer, + size_t *lenremain) +{ + struct s4u2proxy_context *s4uctx = (struct s4u2proxy_context *)request_context; + krb5_error_code code; + krb5_int32 ibuf; + krb5_octet *bp; + size_t remain; + int count; + krb5_principal *delegated = NULL; + + bp = *buffer; + remain = *lenremain; + + /* version */ + code = krb5_ser_unpack_int32(&ibuf, &bp, &remain); + if (code != 0) + goto cleanup; + + if (ibuf != 1) { + code = EINVAL; + goto cleanup; + } + + /* count */ + code = krb5_ser_unpack_int32(&count, &bp, &remain); + if (code != 0) + goto cleanup; + + if (count > 65535) + return ERANGE; /* let's set some reasonable limits here */ + else if (count > 0) { + int i; + + delegated = k5alloc((count + 1) * sizeof(krb5_principal), &code); + if (delegated == NULL) + goto cleanup; + + for (i = 0; i < count; i++) { + code = krb5_internalize_opaque(kcontext, KV5M_PRINCIPAL, + (krb5_pointer *)&delegated[i], + &bp, &remain); + if (code != 0) + goto cleanup; + } + + delegated[i] = NULL; + } + + code = krb5_ser_unpack_int32(&ibuf, &bp, &remain); + if (code != 0) + goto cleanup; + + s4u2proxy_free_internal(kcontext, context, + plugin_context, request_context, + s4uctx->delegated); + + s4uctx->count = count; + s4uctx->delegated = delegated; + s4uctx->authenticated = (ibuf != 0); + + delegated = NULL; + + *buffer = bp; + *lenremain = remain; + +cleanup: + s4u2proxy_free_internal(kcontext, context, + plugin_context, request_context, + delegated); + + return code; +} + +static krb5_error_code +s4u2proxy_copy(krb5_context kcontext, + krb5_authdata_context context, + void *plugin_context, + void *request_context, + void *dst_plugin_context, + void *dst_request_context) +{ + struct s4u2proxy_context *srcctx = (struct s4u2proxy_context *)request_context; + struct s4u2proxy_context *dstctx = (struct s4u2proxy_context *)dst_request_context; + krb5_error_code code; + + code = s4u2proxy_export_internal(kcontext, context, + plugin_context, request_context, + FALSE, (void **)&dstctx->delegated); + if (code != 0) + return code; + + dstctx->count = srcctx->count; + dstctx->authenticated = srcctx->authenticated; + + return 0; +} + +static krb5_authdatatype s4u2proxy_ad_types[] = { KRB5_AUTHDATA_SIGNTICKET, 0 }; + +krb5plugin_authdata_client_ftable_v0 krb5int_s4u2proxy_authdata_client_ftable = { + "constrained-delegation", + s4u2proxy_ad_types, + s4u2proxy_init, + s4u2proxy_fini, + s4u2proxy_flags, + s4u2proxy_request_init, + s4u2proxy_request_fini, + s4u2proxy_get_attribute_types, + s4u2proxy_get_attribute, + s4u2proxy_set_attribute, + NULL, /* delete_attribute_proc */ + s4u2proxy_export_authdata, + s4u2proxy_import_authdata, + s4u2proxy_export_internal, + s4u2proxy_free_internal, + s4u2proxy_verify, + s4u2proxy_size, + s4u2proxy_externalize, + s4u2proxy_internalize, + s4u2proxy_copy +}; +