kdc-tester.c revision 1.1
1/* $NetBSD: kdc-tester.c,v 1.1 2017/01/28 20:46:42 christos Exp $ */ 2 3/* 4 * Copyright (c) 1997-2005 Kungliga Tekniska H��gskolan 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 41struct 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 49int detach_from_console = -1; 50int daemon_child = -1; 51int do_bonjour = -1; 52 53static krb5_kdc_configuration *kdc_config; 54static krb5_context kdc_context; 55 56static struct sockaddr_storage sa; 57static const char *astr = "0.0.0.0"; 58 59static void eval_object(heim_object_t); 60 61 62/* 63 * 64 */ 65 66static krb5_error_code 67plugin_init(krb5_context context, void **pctx) 68{ 69 *pctx = NULL; 70 return 0; 71} 72 73static void 74plugin_fini(void *ctx) 75{ 76} 77 78static krb5_error_code 79plugin_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 89static krb5_error_code 90plugin_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 111static 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 119static void 120perf_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 129static void 130perf_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 164static void 165eval_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 190static krb5_error_code 191copy_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 211static void 212eval_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 342static void 343eval_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 398static void 399eval_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 422static void 423eval_array_element(heim_object_t o, void *ptr, int *stop) 424{ 425 eval_object(o); 426} 427 428static void 429eval_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 457int 458main(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