aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuke Howard <lukeh@padl.com>2010-05-08 15:31:09 +0000
committerLuke Howard <lukeh@padl.com>2010-05-08 15:31:09 +0000
commit360e7f04bf02ce23616726719402ed8ae38576b7 (patch)
tree29df97c082fab7f20ba6d4365a4a0e8cbd04bc98
parentf851e20940be3831e57c4b8a5fae1c442c427d6d (diff)
downloadkrb5-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.in3
-rw-r--r--src/lib/krb5/krb/authdata.h1
-rw-r--r--src/lib/krb5/krb/s4u_authdata.c586
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
+};
+