diff options
author | Luke Howard <lukeh@padl.com> | 2010-05-08 15:31:09 +0000 |
---|---|---|
committer | Luke Howard <lukeh@padl.com> | 2010-05-08 15:31:09 +0000 |
commit | 360e7f04bf02ce23616726719402ed8ae38576b7 (patch) | |
tree | 29df97c082fab7f20ba6d4365a4a0e8cbd04bc98 | |
parent | f851e20940be3831e57c4b8a5fae1c442c427d6d (diff) | |
download | krb5-360e7f04bf02ce23616726719402ed8ae38576b7.zip krb5-360e7f04bf02ce23616726719402ed8ae38576b7.tar.gz krb5-360e7f04bf02ce23616726719402ed8ae38576b7.tar.bz2 |
SignedPath authdata backend implementation
git-svn-id: svn://anonsvn.mit.edu/krb5/users/lhoward/signedpath-naming-exts@23977 dc483132-0cff-0310-8789-dd5450dbe970
-rw-r--r-- | src/lib/krb5/krb/Makefile.in | 3 | ||||
-rw-r--r-- | src/lib/krb5/krb/authdata.h | 1 | ||||
-rw-r--r-- | src/lib/krb5/krb/s4u_authdata.c | 586 |
3 files changed, 590 insertions, 0 deletions
diff --git a/src/lib/krb5/krb/Makefile.in b/src/lib/krb5/krb/Makefile.in index 4384c5e..e820c64 100644 --- a/src/lib/krb5/krb/Makefile.in +++ b/src/lib/krb5/krb/Makefile.in @@ -87,6 +87,7 @@ STLIBOBJS= \ rd_req_dec.o \ rd_safe.o \ recvauth.o \ + s4u_authdata.o \ s4u_creds.o \ sendauth.o \ send_tgs.o \ @@ -186,6 +187,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) \ @@ -286,6 +288,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.h b/src/lib/krb5/krb/authdata.h index 090ce33..af5016e 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/s4u_authdata.c b/src/lib/krb5/krb/s4u_authdata.c new file mode 100644 index 0000000..90f6db5 --- /dev/null +++ b/src/lib/krb5/krb/s4u_authdata.c @@ -0,0 +1,586 @@ +/* -*- 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->delegated == NULL) + 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); +} + +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; + + if (s4uctx->delegated == NULL || s4uctx->delegated[0] == NULL) + return ENOENT; + + attrs = k5alloc(2 * sizeof(krb5_data), &code); + if (attrs == NULL) + return code; + + code = krb5int_copy_data_contents(kcontext, + &s4u2proxy_transited_services_attr, + &attrs[0]); + if (code != 0) { + free(attrs); + return code; + } + + attrs[1].data = NULL; + attrs[1].length = 0; + + *out_attrs = 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 (s4uctx->delegated == NULL) + return ENOENT; + + i = -(*more) - 1; + + assert(i < s4uctx->count); + + 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->delegated == NULL) + return 0; + + if (restrict_authenticated) + return 0; + + 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; + 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; + 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 > 65536) + 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 +}; + |