summaryrefslogtreecommitdiffstats
path: root/third_party/heimdal/kdc/kdc-tester.c
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/heimdal/kdc/kdc-tester.c')
-rw-r--r--third_party/heimdal/kdc/kdc-tester.c517
1 files changed, 517 insertions, 0 deletions
diff --git a/third_party/heimdal/kdc/kdc-tester.c b/third_party/heimdal/kdc/kdc-tester.c
new file mode 100644
index 0000000..8f8073a
--- /dev/null
+++ b/third_party/heimdal/kdc/kdc-tester.c
@@ -0,0 +1,517 @@
+/*
+ * Copyright (c) 1997-2005 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Portions Copyright (c) 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "kdc_locl.h"
+#include "send_to_kdc_plugin.h"
+
+struct perf {
+ unsigned long as_req;
+ unsigned long tgs_req;
+ struct timeval start;
+ struct timeval stop;
+ struct perf *next;
+} *ptop;
+
+int detach_from_console = -1;
+int daemon_child = -1;
+int do_bonjour = -1;
+
+static krb5_kdc_configuration *kdc_config;
+static krb5_context kdc_context;
+
+static struct sockaddr_storage sa;
+static const char *astr = "0.0.0.0";
+
+static void eval_object(heim_object_t);
+
+
+/*
+ *
+ */
+
+static krb5_error_code
+plugin_init(krb5_context context, void **pctx)
+{
+ *pctx = NULL;
+ return 0;
+}
+
+static void
+plugin_fini(void *ctx)
+{
+}
+
+static krb5_error_code
+plugin_send_to_kdc(krb5_context context,
+ void *ctx,
+ krb5_krbhst_info *ho,
+ time_t timeout,
+ const krb5_data *in,
+ krb5_data *out)
+{
+ return KRB5_PLUGIN_NO_HANDLE;
+}
+
+static krb5_error_code
+plugin_send_to_realm(krb5_context context,
+ void *ctx,
+ krb5_const_realm realm,
+ time_t timeout,
+ const krb5_data *in,
+ krb5_data *out)
+{
+ int ret;
+
+ krb5_kdc_update_time(NULL);
+
+ ret = krb5_kdc_process_request(kdc_context, kdc_config,
+ in->data, in->length,
+ out, NULL, astr,
+ (struct sockaddr *)&sa, 0);
+ if (ret)
+ krb5_err(kdc_context, 1, ret, "krb5_kdc_process_request");
+
+ return 0;
+}
+
+static krb5plugin_send_to_kdc_ftable send_to_kdc = {
+ KRB5_PLUGIN_SEND_TO_KDC_VERSION_2,
+ plugin_init,
+ plugin_fini,
+ plugin_send_to_kdc,
+ plugin_send_to_realm
+};
+
+static void
+perf_start(struct perf *perf)
+{
+ memset(perf, 0, sizeof(*perf));
+
+ gettimeofday(&perf->start, NULL);
+ perf->next = ptop;
+ ptop = perf;
+}
+
+static void
+perf_stop(struct perf *perf)
+{
+ gettimeofday(&perf->stop, NULL);
+ ptop = perf->next;
+
+ if (ptop) {
+ ptop->as_req += perf->as_req;
+ ptop->tgs_req += perf->tgs_req;
+ }
+
+ timevalsub(&perf->stop, &perf->start);
+ printf("time: %lu.%06lu\n",
+ (unsigned long)perf->stop.tv_sec,
+ (unsigned long)perf->stop.tv_usec);
+
+#define USEC_PER_SEC 1000000
+
+ if (perf->as_req) {
+ double as_ps = 0.0;
+ as_ps = (perf->as_req * USEC_PER_SEC) / (double)((perf->stop.tv_sec * USEC_PER_SEC) + perf->stop.tv_usec);
+ printf("as-req/s %.2lf (total %lu requests)\n", as_ps, perf->as_req);
+ }
+
+ if (perf->tgs_req) {
+ double tgs_ps = 0.0;
+ tgs_ps = (perf->tgs_req * USEC_PER_SEC) / (double)((perf->stop.tv_sec * USEC_PER_SEC) + perf->stop.tv_usec);
+ printf("tgs-req/s %.2lf (total %lu requests)\n", tgs_ps, perf->tgs_req);
+ }
+}
+
+/*
+ *
+ */
+
+static void
+eval_repeat(heim_dict_t o)
+{
+ heim_object_t or = heim_dict_get_value(o, HSTR("value"));
+ heim_number_t n = heim_dict_get_value(o, HSTR("num"));
+ int i, num;
+ struct perf perf;
+
+ perf_start(&perf);
+
+ heim_assert(or != NULL, "value missing");
+ heim_assert(n != NULL, "num missing");
+
+ num = heim_number_get_int(n);
+ heim_assert(num >= 0, "num >= 0");
+
+ for (i = 0; i < num; i++)
+ eval_object(or);
+
+ perf_stop(&perf);
+}
+
+/*
+ *
+ */
+
+static krb5_error_code
+copy_keytab(krb5_context context, krb5_keytab from, krb5_keytab to)
+{
+ krb5_keytab_entry entry;
+ krb5_kt_cursor cursor;
+ krb5_error_code ret;
+
+ ret = krb5_kt_start_seq_get(context, from, &cursor);
+ if (ret)
+ return ret;
+ while ((ret = krb5_kt_next_entry(context, from, &entry, &cursor)) == 0){
+ krb5_kt_add_entry(context, to, &entry);
+ krb5_kt_free_entry(context, &entry);
+ }
+ (void) krb5_kt_end_seq_get(context, from, &cursor);
+ if (ret == KRB5_KT_END)
+ return 0;
+ return ret;
+}
+
+/*
+ *
+ */
+
+static void
+eval_kinit(heim_dict_t o)
+{
+ heim_string_t user, password, keytab, fast_armor_cc, pk_user_id, ccache;
+ krb5_get_init_creds_opt *opt;
+ krb5_init_creds_context ctx;
+ krb5_principal client;
+ krb5_keytab ktmem = NULL;
+ krb5_ccache fast_cc = NULL;
+ krb5_error_code ret;
+
+ if (ptop)
+ ptop->as_req++;
+
+ user = heim_dict_get_value(o, HSTR("client"));
+ if (user == NULL)
+ krb5_errx(kdc_context, 1, "no client");
+
+ password = heim_dict_get_value(o, HSTR("password"));
+ keytab = heim_dict_get_value(o, HSTR("keytab"));
+ pk_user_id = heim_dict_get_value(o, HSTR("pkinit-user-cert-id"));
+ if (password == NULL && keytab == NULL && pk_user_id == NULL)
+ krb5_errx(kdc_context, 1, "password, keytab, nor PKINIT user cert ID");
+
+ ccache = heim_dict_get_value(o, HSTR("ccache"));
+
+ ret = krb5_parse_name(kdc_context, heim_string_get_utf8(user), &client);
+ if (ret)
+ krb5_err(kdc_context, 1, ret, "krb5_unparse_name");
+
+ /* PKINIT parts */
+ ret = krb5_get_init_creds_opt_alloc (kdc_context, &opt);
+ if (ret)
+ krb5_err(kdc_context, 1, ret, "krb5_get_init_creds_opt_alloc");
+
+ if (pk_user_id) {
+ heim_bool_t rsaobj = heim_dict_get_value(o, HSTR("pkinit-use-rsa"));
+ int use_rsa = rsaobj ? heim_bool_val(rsaobj) : 0;
+
+ ret = krb5_get_init_creds_opt_set_pkinit(kdc_context, opt,
+ client,
+ heim_string_get_utf8(pk_user_id),
+ NULL, NULL, NULL,
+ use_rsa ? 2 : 0,
+ NULL, NULL, NULL);
+ if (ret)
+ krb5_err(kdc_context, 1, ret, "krb5_get_init_creds_opt_set_pkinit");
+ }
+
+ fast_armor_cc = heim_dict_get_value(o, HSTR("fast-armor-cc"));
+ if (fast_armor_cc) {
+
+ ret = krb5_cc_resolve(kdc_context, heim_string_get_utf8(fast_armor_cc), &fast_cc);
+ if (ret)
+ krb5_err(kdc_context, 1, ret, "krb5_cc_resolve");
+
+ ret = krb5_get_init_creds_opt_set_fast_ccache(kdc_context, opt, fast_cc);
+ if (ret)
+ krb5_err(kdc_context, 1, ret, "krb5_get_init_creds_set_fast_ccache");
+
+ ret = krb5_get_init_creds_opt_set_fast_flags(kdc_context, opt, KRB5_FAST_REQUIRED|KRB5_FAST_KDC_VERIFIED);
+ if (ret)
+ krb5_err(kdc_context, 1, ret, "krb5_get_init_creds_set_fast_ccache");
+
+ fast_cc = NULL;
+ }
+
+ ret = krb5_init_creds_init(kdc_context, client, NULL, NULL, 0, opt, &ctx);
+ if (ret)
+ krb5_err(kdc_context, 1, ret, "krb5_init_creds_init");
+
+ if (password) {
+ ret = krb5_init_creds_set_password(kdc_context, ctx,
+ heim_string_get_utf8(password));
+ if (ret)
+ krb5_err(kdc_context, 1, ret, "krb5_init_creds_set_password");
+ }
+ if (keytab) {
+ krb5_keytab kt = NULL;
+
+ ret = krb5_kt_resolve(kdc_context, heim_string_get_utf8(keytab), &kt);
+ if (ret)
+ krb5_err(kdc_context, 1, ret, "krb5_kt_resolve");
+
+ ret = krb5_kt_resolve(kdc_context, "MEMORY:keytab", &ktmem);
+ if (ret)
+ krb5_err(kdc_context, 1, ret, "krb5_kt_resolve(MEMORY)");
+
+ ret = copy_keytab(kdc_context, kt, ktmem);
+ if (ret)
+ krb5_err(kdc_context, 1, ret, "copy_keytab");
+
+ krb5_kt_close(kdc_context, kt);
+
+ ret = krb5_init_creds_set_keytab(kdc_context, ctx, ktmem);
+ if (ret)
+ krb5_err(kdc_context, 1, ret, "krb5_init_creds_set_keytab");
+ }
+
+ ret = krb5_init_creds_get(kdc_context, ctx);
+ if (ret)
+ krb5_err(kdc_context, 1, ret, "krb5_init_creds_get");
+
+ if (ccache) {
+ const char *name = heim_string_get_utf8(ccache);
+ krb5_creds cred;
+ krb5_ccache cc;
+
+ ret = krb5_init_creds_get_creds(kdc_context, ctx, &cred);
+ if (ret)
+ krb5_err(kdc_context, 1, ret, "krb5_init_creds_get_creds");
+
+ ret = krb5_cc_resolve(kdc_context, name, &cc);
+ if (ret)
+ krb5_err(kdc_context, 1, ret, "krb5_cc_resolve");
+
+ krb5_init_creds_store(kdc_context, ctx, cc);
+
+ ret = krb5_cc_close(kdc_context, cc);
+ if (ret)
+ krb5_err(kdc_context, 1, ret, "krb5_cc_close");
+
+ krb5_free_cred_contents(kdc_context, &cred);
+ }
+
+ krb5_init_creds_free(kdc_context, ctx);
+
+ if (ktmem)
+ krb5_kt_close(kdc_context, ktmem);
+ if (fast_cc)
+ krb5_cc_close(kdc_context, fast_cc);
+}
+
+/*
+ *
+ */
+
+static void
+eval_kgetcred(heim_dict_t o)
+{
+ heim_string_t server, ccache;
+ krb5_get_creds_opt opt;
+ heim_bool_t nostore;
+ krb5_error_code ret;
+ krb5_ccache cc = NULL;
+ krb5_principal s;
+ krb5_creds *out = NULL;
+
+ if (ptop)
+ ptop->tgs_req++;
+
+ server = heim_dict_get_value(o, HSTR("server"));
+ if (server == NULL)
+ krb5_errx(kdc_context, 1, "no server");
+
+ ccache = heim_dict_get_value(o, HSTR("ccache"));
+ if (ccache == NULL)
+ krb5_errx(kdc_context, 1, "no ccache");
+
+ nostore = heim_dict_get_value(o, HSTR("nostore"));
+ if (nostore == NULL)
+ nostore = heim_bool_create(1);
+
+ ret = krb5_cc_resolve(kdc_context, heim_string_get_utf8(ccache), &cc);
+ if (ret)
+ krb5_err(kdc_context, 1, ret, "krb5_cc_resolve");
+
+ ret = krb5_parse_name(kdc_context, heim_string_get_utf8(server), &s);
+ if (ret)
+ krb5_err(kdc_context, 1, ret, "krb5_parse_name");
+
+ ret = krb5_get_creds_opt_alloc(kdc_context, &opt);
+ if (ret)
+ krb5_err(kdc_context, 1, ret, "krb5_get_creds_opt_alloc");
+
+ if (heim_bool_val(nostore))
+ krb5_get_creds_opt_add_options(kdc_context, opt, KRB5_GC_NO_STORE);
+
+ ret = krb5_get_creds(kdc_context, opt, cc, s, &out);
+ if (ret)
+ krb5_err(kdc_context, 1, ret, "krb5_get_creds");
+
+ krb5_free_creds(kdc_context, out);
+ krb5_free_principal(kdc_context, s);
+ krb5_get_creds_opt_free(kdc_context, opt);
+ krb5_cc_close(kdc_context, cc);
+}
+
+
+/*
+ *
+ */
+
+static void
+eval_kdestroy(heim_dict_t o)
+{
+ heim_string_t ccache = heim_dict_get_value(o, HSTR("ccache"));;
+ krb5_error_code ret;
+ const char *name;
+ krb5_ccache cc;
+
+ heim_assert(ccache != NULL, "ccache_missing");
+
+ name = heim_string_get_utf8(ccache);
+
+ ret = krb5_cc_resolve(kdc_context, name, &cc);
+ if (ret)
+ krb5_err(kdc_context, 1, ret, "krb5_cc_resolve");
+
+ krb5_cc_destroy(kdc_context, cc);
+}
+
+
+/*
+ *
+ */
+
+static void
+eval_array_element(heim_object_t o, void *ptr, int *stop)
+{
+ eval_object(o);
+}
+
+static void
+eval_object(heim_object_t o)
+{
+ heim_tid_t t = heim_get_tid(o);
+
+ if (t == heim_array_get_type_id()) {
+ heim_array_iterate_f(o, NULL, eval_array_element);
+ } else if (t == heim_dict_get_type_id()) {
+ const char *op = heim_dict_get_value(o, HSTR("op"));
+
+ heim_assert(op != NULL, "op missing");
+
+ if (strcmp(op, "repeat") == 0) {
+ eval_repeat(o);
+ } else if (strcmp(op, "kinit") == 0) {
+ eval_kinit(o);
+ } else if (strcmp(op, "kgetcred") == 0) {
+ eval_kgetcred(o);
+ } else if (strcmp(op, "kdestroy") == 0) {
+ eval_kdestroy(o);
+ } else {
+ errx(1, "unsupported ops %s", op);
+ }
+
+ } else
+ errx(1, "unsupported");
+}
+
+
+int
+main(int argc, char **argv)
+{
+ krb5_error_code ret;
+ int optidx = 0;
+
+ setprogname(argv[0]);
+
+ ret = krb5_init_context(&kdc_context);
+ if (ret == KRB5_CONFIG_BADFORMAT)
+ errx (1, "krb5_init_context failed to parse configuration file");
+ else if (ret)
+ errx (1, "krb5_init_context failed: %d", ret);
+
+ ret = krb5_kt_register(kdc_context, &hdb_get_kt_ops);
+ if (ret)
+ errx (1, "krb5_kt_register(HDB) failed: %d", ret);
+
+ kdc_config = configure(kdc_context, argc, argv, &optidx);
+
+ argc -= optidx;
+ argv += optidx;
+
+ if (argc == 0)
+ errx(1, "missing operations");
+
+ krb5_plugin_register(kdc_context, PLUGIN_TYPE_DATA,
+ KRB5_PLUGIN_SEND_TO_KDC, &send_to_kdc);
+
+ {
+ void *buf;
+ size_t size;
+ heim_object_t o;
+
+ if (rk_undumpdata(argv[0], &buf, &size))
+ errx(1, "undumpdata: %s", argv[0]);
+
+ o = heim_json_create_with_bytes(buf, size, 10, 0, NULL);
+ free(buf);
+ if (o == NULL)
+ errx(1, "heim_json");
+
+ /*
+ * do the work here
+ */
+
+ eval_object(o);
+
+ heim_release(o);
+ }
+
+ krb5_free_context(kdc_context);
+ return 0;
+}