Home | History | Annotate | Line # | Download | only in kdc
      1 /*	$NetBSD: kdc-tester.c,v 1.2 2017/01/28 21:31:44 christos Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1997-2005 Kungliga Tekniska Hgskolan
      5  * (Royal Institute of Technology, Stockholm, Sweden).
      6  * All rights reserved.
      7  *
      8  * Portions Copyright (c) 2009 Apple Inc. All rights reserved.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  *
     14  * 1. Redistributions of source code must retain the above copyright
     15  *    notice, this list of conditions and the following disclaimer.
     16  *
     17  * 2. Redistributions in binary form must reproduce the above copyright
     18  *    notice, this list of conditions and the following disclaimer in the
     19  *    documentation and/or other materials provided with the distribution.
     20  *
     21  * 3. Neither the name of the Institute nor the names of its contributors
     22  *    may be used to endorse or promote products derived from this software
     23  *    without specific prior written permission.
     24  *
     25  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
     26  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     27  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     28  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
     29  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     30  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     31  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     32  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     33  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     34  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     35  * SUCH DAMAGE.
     36  */
     37 
     38 #include "kdc_locl.h"
     39 #include "send_to_kdc_plugin.h"
     40 
     41 struct perf {
     42     unsigned long as_req;
     43     unsigned long tgs_req;
     44     struct timeval start;
     45     struct timeval stop;
     46     struct perf *next;
     47 } *ptop;
     48 
     49 int detach_from_console = -1;
     50 int daemon_child = -1;
     51 int do_bonjour = -1;
     52 
     53 static krb5_kdc_configuration *kdc_config;
     54 static krb5_context kdc_context;
     55 
     56 static struct sockaddr_storage sa;
     57 static const char *astr = "0.0.0.0";
     58 
     59 static void eval_object(heim_object_t);
     60 
     61 
     62 /*
     63  *
     64  */
     65 
     66 static krb5_error_code
     67 plugin_init(krb5_context context, void **pctx)
     68 {
     69     *pctx = NULL;
     70     return 0;
     71 }
     72 
     73 static void
     74 plugin_fini(void *ctx)
     75 {
     76 }
     77 
     78 static krb5_error_code
     79 plugin_send_to_kdc(krb5_context context,
     80 		   void *ctx,
     81 		   krb5_krbhst_info *ho,
     82 		   time_t timeout,
     83 		   const krb5_data *in,
     84 		   krb5_data *out)
     85 {
     86     return KRB5_PLUGIN_NO_HANDLE;
     87 }
     88 
     89 static krb5_error_code
     90 plugin_send_to_realm(krb5_context context,
     91 		     void *ctx,
     92 		     krb5_const_realm realm,
     93 		     time_t timeout,
     94 		     const krb5_data *in,
     95 		     krb5_data *out)
     96 {
     97     int ret;
     98 
     99     krb5_kdc_update_time(NULL);
    100 
    101     ret = krb5_kdc_process_request(kdc_context, kdc_config,
    102 				   in->data, in->length,
    103 				   out, NULL, astr,
    104 				   (struct sockaddr *)&sa, 0);
    105     if (ret)
    106 	krb5_err(kdc_context, 1, ret, "krb5_kdc_process_request");
    107 
    108     return 0;
    109 }
    110 
    111 static krb5plugin_send_to_kdc_ftable send_to_kdc = {
    112     KRB5_PLUGIN_SEND_TO_KDC_VERSION_2,
    113     plugin_init,
    114     plugin_fini,
    115     plugin_send_to_kdc,
    116     plugin_send_to_realm
    117 };
    118 
    119 static void
    120 perf_start(struct perf *perf)
    121 {
    122     memset(perf, 0, sizeof(*perf));
    123 
    124     gettimeofday(&perf->start, NULL);
    125     perf->next = ptop;
    126     ptop = perf;
    127 }
    128 
    129 static void
    130 perf_stop(struct perf *perf)
    131 {
    132     gettimeofday(&perf->stop, NULL);
    133     ptop = perf->next;
    134 
    135     if (ptop) {
    136 	ptop->as_req += perf->as_req;
    137 	ptop->tgs_req += perf->tgs_req;
    138     }
    139 
    140     timevalsub(&perf->stop, &perf->start);
    141     printf("time: %lu.%06lu\n",
    142 	   (unsigned long)perf->stop.tv_sec,
    143 	   (unsigned long)perf->stop.tv_usec);
    144 
    145 #define USEC_PER_SEC 1000000
    146 
    147     if (perf->as_req) {
    148 	double as_ps = 0.0;
    149 	as_ps = (perf->as_req * USEC_PER_SEC) / (double)((perf->stop.tv_sec * USEC_PER_SEC) + perf->stop.tv_usec);
    150 	printf("as-req/s %.2lf  (total %lu requests)\n", as_ps, perf->as_req);
    151     }
    152 
    153     if (perf->tgs_req) {
    154 	double tgs_ps = 0.0;
    155 	tgs_ps = (perf->tgs_req * USEC_PER_SEC) / (double)((perf->stop.tv_sec * USEC_PER_SEC) + perf->stop.tv_usec);
    156 	printf("tgs-req/s %.2lf (total %lu requests)\n", tgs_ps, perf->tgs_req);
    157     }
    158 }
    159 
    160 /*
    161  *
    162  */
    163 
    164 static void
    165 eval_repeat(heim_dict_t o)
    166 {
    167     heim_object_t or = heim_dict_get_value(o, HSTR("value"));
    168     heim_number_t n = heim_dict_get_value(o, HSTR("num"));
    169     int i, num;
    170     struct perf perf;
    171 
    172     perf_start(&perf);
    173 
    174     heim_assert(or != NULL, "value missing");
    175     heim_assert(n != NULL, "num missing");
    176 
    177     num = heim_number_get_int(n);
    178     heim_assert(num >= 0, "num >= 0");
    179 
    180     for (i = 0; i < num; i++)
    181 	eval_object(or);
    182 
    183     perf_stop(&perf);
    184 }
    185 
    186 /*
    187  *
    188  */
    189 
    190 static krb5_error_code
    191 copy_keytab(krb5_context context, krb5_keytab from, krb5_keytab to)
    192 {
    193     krb5_keytab_entry entry;
    194     krb5_kt_cursor cursor;
    195     krb5_error_code ret;
    196 
    197     ret = krb5_kt_start_seq_get(context, from, &cursor);
    198     if (ret)
    199 	return ret;
    200     while((ret = krb5_kt_next_entry(context, from, &entry, &cursor)) == 0){
    201 	krb5_kt_add_entry(context, to, &entry);
    202 	krb5_kt_free_entry(context, &entry);
    203     }
    204     return krb5_kt_end_seq_get(context, from, &cursor);
    205 }
    206 
    207 /*
    208  *
    209  */
    210 
    211 static void
    212 eval_kinit(heim_dict_t o)
    213 {
    214     heim_string_t user, password, keytab, fast_armor_cc, pk_user_id, ccache;
    215     krb5_get_init_creds_opt *opt;
    216     krb5_init_creds_context ctx;
    217     krb5_principal client;
    218     krb5_keytab ktmem = NULL;
    219     krb5_ccache fast_cc = NULL;
    220     krb5_error_code ret;
    221 
    222     if (ptop)
    223 	ptop->as_req++;
    224 
    225     user = heim_dict_get_value(o, HSTR("client"));
    226     if (user == NULL)
    227 	krb5_errx(kdc_context, 1, "no client");
    228 
    229     password = heim_dict_get_value(o, HSTR("password"));
    230     keytab = heim_dict_get_value(o, HSTR("keytab"));
    231     pk_user_id = heim_dict_get_value(o, HSTR("pkinit-user-cert-id"));
    232     if (password == NULL && keytab == NULL && pk_user_id == NULL)
    233 	krb5_errx(kdc_context, 1, "password, keytab, nor PKINIT user cert ID");
    234 
    235     ccache = heim_dict_get_value(o, HSTR("ccache"));
    236 
    237     ret = krb5_parse_name(kdc_context, heim_string_get_utf8(user), &client);
    238     if (ret)
    239 	krb5_err(kdc_context, 1, ret, "krb5_unparse_name");
    240 
    241     /* PKINIT parts */
    242     ret = krb5_get_init_creds_opt_alloc (kdc_context, &opt);
    243     if (ret)
    244 	krb5_err(kdc_context, 1, ret, "krb5_get_init_creds_opt_alloc");
    245 
    246     if (pk_user_id) {
    247 	heim_bool_t rsaobj = heim_dict_get_value(o, HSTR("pkinit-use-rsa"));
    248 	int use_rsa = rsaobj ? heim_bool_val(rsaobj) : 0;
    249 
    250 	ret = krb5_get_init_creds_opt_set_pkinit(kdc_context, opt,
    251 						 client,
    252 						 heim_string_get_utf8(pk_user_id),
    253 						 NULL, NULL, NULL,
    254 						 use_rsa ? 2 : 0,
    255 						 NULL, NULL, NULL);
    256 	if (ret)
    257 	    krb5_err(kdc_context, 1, ret, "krb5_get_init_creds_opt_set_pkinit");
    258     }
    259 
    260     ret = krb5_init_creds_init(kdc_context, client, NULL, NULL, 0, opt, &ctx);
    261     if (ret)
    262 	krb5_err(kdc_context, 1, ret, "krb5_init_creds_init");
    263 
    264     fast_armor_cc = heim_dict_get_value(o, HSTR("fast-armor-cc"));
    265     if (fast_armor_cc) {
    266 
    267 	ret = krb5_cc_resolve(kdc_context, heim_string_get_utf8(fast_armor_cc), &fast_cc);
    268 	if (ret)
    269 	    krb5_err(kdc_context, 1, ret, "krb5_cc_resolve");
    270 
    271 	ret = krb5_init_creds_set_fast_ccache(kdc_context, ctx, fast_cc);
    272 	if (ret)
    273 	    krb5_err(kdc_context, 1, ret, "krb5_init_creds_set_fast_ccache");
    274     }
    275 
    276     if (password) {
    277 	ret = krb5_init_creds_set_password(kdc_context, ctx,
    278 					   heim_string_get_utf8(password));
    279 	if (ret)
    280 	    krb5_err(kdc_context, 1, ret, "krb5_init_creds_set_password");
    281     }
    282     if (keytab) {
    283 	krb5_keytab kt = NULL;
    284 
    285 	ret = krb5_kt_resolve(kdc_context, heim_string_get_utf8(keytab), &kt);
    286 	if (ret)
    287 	    krb5_err(kdc_context, 1, ret, "krb5_kt_resolve");
    288 
    289 	ret = krb5_kt_resolve(kdc_context, "MEMORY:keytab", &ktmem);
    290 	if (ret)
    291 	    krb5_err(kdc_context, 1, ret, "krb5_kt_resolve(MEMORY)");
    292 
    293 	ret = copy_keytab(kdc_context, kt, ktmem);
    294 	if (ret)
    295 	    krb5_err(kdc_context, 1, ret, "copy_keytab");
    296 
    297 	krb5_kt_close(kdc_context, kt);
    298 
    299 	ret = krb5_init_creds_set_keytab(kdc_context, ctx, ktmem);
    300 	if (ret)
    301 	    krb5_err(kdc_context, 1, ret, "krb5_init_creds_set_keytab");
    302     }
    303 
    304     ret = krb5_init_creds_get(kdc_context, ctx);
    305     if (ret)
    306 	krb5_err(kdc_context, 1, ret, "krb5_init_creds_get");
    307 
    308     if (ccache) {
    309 	const char *name = heim_string_get_utf8(ccache);
    310 	krb5_creds cred;
    311 	krb5_ccache cc;
    312 
    313 	ret = krb5_init_creds_get_creds(kdc_context, ctx, &cred);
    314 	if (ret)
    315 	    krb5_err(kdc_context, 1, ret, "krb5_init_creds_get_creds");
    316 
    317 	ret = krb5_cc_resolve(kdc_context, name, &cc);
    318 	if (ret)
    319 	    krb5_err(kdc_context, 1, ret, "krb5_cc_resolve");
    320 
    321 	krb5_init_creds_store(kdc_context, ctx, cc);
    322 
    323 	ret = krb5_cc_close(kdc_context, cc);
    324 	if (ret)
    325 	    krb5_err(kdc_context, 1, ret, "krb5_cc_close");
    326 
    327 	krb5_free_cred_contents(kdc_context, &cred);
    328     }
    329 
    330     krb5_init_creds_free(kdc_context, ctx);
    331 
    332     if (ktmem)
    333 	krb5_kt_close(kdc_context, ktmem);
    334     if (fast_cc)
    335 	krb5_cc_close(kdc_context, fast_cc);
    336 }
    337 
    338 /*
    339  *
    340  */
    341 
    342 static void
    343 eval_kgetcred(heim_dict_t o)
    344 {
    345     heim_string_t server, ccache;
    346     krb5_get_creds_opt opt;
    347     heim_bool_t nostore;
    348     krb5_error_code ret;
    349     krb5_ccache cc = NULL;
    350     krb5_principal s;
    351     krb5_creds *out = NULL;
    352 
    353     if (ptop)
    354 	ptop->tgs_req++;
    355 
    356     server = heim_dict_get_value(o, HSTR("server"));
    357     if (server == NULL)
    358 	krb5_errx(kdc_context, 1, "no server");
    359 
    360     ccache = heim_dict_get_value(o, HSTR("ccache"));
    361     if (ccache == NULL)
    362 	krb5_errx(kdc_context, 1, "no ccache");
    363 
    364     nostore = heim_dict_get_value(o, HSTR("nostore"));
    365     if (nostore == NULL)
    366 	nostore = heim_bool_create(1);
    367 
    368     ret = krb5_cc_resolve(kdc_context, heim_string_get_utf8(ccache), &cc);
    369     if (ret)
    370 	krb5_err(kdc_context, 1, ret, "krb5_cc_resolve");
    371 
    372     ret = krb5_parse_name(kdc_context, heim_string_get_utf8(server), &s);
    373     if (ret)
    374 	krb5_err(kdc_context, 1, ret, "krb5_parse_name");
    375 
    376     ret = krb5_get_creds_opt_alloc(kdc_context, &opt);
    377     if (ret)
    378 	krb5_err(kdc_context, 1, ret, "krb5_get_creds_opt_alloc");
    379 
    380     if (heim_bool_val(nostore))
    381 	krb5_get_creds_opt_add_options(kdc_context, opt, KRB5_GC_NO_STORE);
    382 
    383     ret = krb5_get_creds(kdc_context, opt, cc, s, &out);
    384     if (ret)
    385 	krb5_err(kdc_context, 1, ret, "krb5_get_creds");
    386 
    387     krb5_free_creds(kdc_context, out);
    388     krb5_free_principal(kdc_context, s);
    389     krb5_get_creds_opt_free(kdc_context, opt);
    390     krb5_cc_close(kdc_context, cc);
    391 }
    392 
    393 
    394 /*
    395  *
    396  */
    397 
    398 static void
    399 eval_kdestroy(heim_dict_t o)
    400 {
    401     heim_string_t ccache = heim_dict_get_value(o, HSTR("ccache"));;
    402     krb5_error_code ret;
    403     const char *name;
    404     krb5_ccache cc;
    405 
    406     heim_assert(ccache != NULL, "ccache_missing");
    407 
    408     name = heim_string_get_utf8(ccache);
    409 
    410     ret = krb5_cc_resolve(kdc_context, name, &cc);
    411     if (ret)
    412 	krb5_err(kdc_context, 1, ret, "krb5_cc_resolve");
    413 
    414     krb5_cc_destroy(kdc_context, cc);
    415 }
    416 
    417 
    418 /*
    419  *
    420  */
    421 
    422 static void
    423 eval_array_element(heim_object_t o, void *ptr, int *stop)
    424 {
    425     eval_object(o);
    426 }
    427 
    428 static void
    429 eval_object(heim_object_t o)
    430 {
    431     heim_tid_t t = heim_get_tid(o);
    432 
    433     if (t == heim_array_get_type_id()) {
    434 	heim_array_iterate_f(o, NULL, eval_array_element);
    435     } else if (t == heim_dict_get_type_id()) {
    436 	const char *op = heim_dict_get_value(o, HSTR("op"));
    437 
    438 	heim_assert(op != NULL, "op missing");
    439 
    440 	if (strcmp(op, "repeat") == 0) {
    441 	    eval_repeat(o);
    442 	} else if (strcmp(op, "kinit") == 0) {
    443 	    eval_kinit(o);
    444 	} else if (strcmp(op, "kgetcred") == 0) {
    445 	    eval_kgetcred(o);
    446 	} else if (strcmp(op, "kdestroy") == 0) {
    447 	    eval_kdestroy(o);
    448 	} else {
    449 	    errx(1, "unsupported ops %s", op);
    450 	}
    451 
    452     } else
    453 	errx(1, "unsupported");
    454 }
    455 
    456 
    457 int
    458 main(int argc, char **argv)
    459 {
    460     krb5_error_code ret;
    461     int optidx = 0;
    462 
    463     setprogname(argv[0]);
    464 
    465     ret = krb5_init_context(&kdc_context);
    466     if (ret == KRB5_CONFIG_BADFORMAT)
    467 	errx (1, "krb5_init_context failed to parse configuration file");
    468     else if (ret)
    469 	errx (1, "krb5_init_context failed: %d", ret);
    470 
    471     ret = krb5_kt_register(kdc_context, &hdb_get_kt_ops);
    472     if (ret)
    473 	errx (1, "krb5_kt_register(HDB) failed: %d", ret);
    474 
    475     kdc_config = configure(kdc_context, argc, argv, &optidx);
    476 
    477     argc -= optidx;
    478     argv += optidx;
    479 
    480     if (argc == 0)
    481 	errx(1, "missing operations");
    482 
    483     krb5_plugin_register(kdc_context, PLUGIN_TYPE_DATA,
    484 			 KRB5_PLUGIN_SEND_TO_KDC, &send_to_kdc);
    485 
    486     {
    487 	void *buf;
    488 	size_t size;
    489 	heim_object_t o;
    490 
    491 	if (rk_undumpdata(argv[0], &buf, &size))
    492 	    errx(1, "undumpdata: %s", argv[0]);
    493 
    494 	o = heim_json_create_with_bytes(buf, size, 10, 0, NULL);
    495 	free(buf);
    496 	if (o == NULL)
    497 	    errx(1, "heim_json");
    498 
    499 	/*
    500 	 * do the work here
    501 	 */
    502 
    503 	eval_object(o);
    504 
    505 	heim_release(o);
    506     }
    507 
    508     krb5_free_context(kdc_context);
    509     return 0;
    510 }
    511