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 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
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
plugin_init(krb5_context context,void ** pctx)67 plugin_init(krb5_context context, void **pctx)
68 {
69 *pctx = NULL;
70 return 0;
71 }
72
73 static void
plugin_fini(void * ctx)74 plugin_fini(void *ctx)
75 {
76 }
77
78 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)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
plugin_send_to_realm(krb5_context context,void * ctx,krb5_const_realm realm,time_t timeout,const krb5_data * in,krb5_data * out)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
perf_start(struct perf * perf)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
perf_stop(struct perf * perf)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
eval_repeat(heim_dict_t o)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
copy_keytab(krb5_context context,krb5_keytab from,krb5_keytab to)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
eval_kinit(heim_dict_t o)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
eval_kgetcred(heim_dict_t o)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
eval_kdestroy(heim_dict_t o)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
eval_array_element(heim_object_t o,void * ptr,int * stop)423 eval_array_element(heim_object_t o, void *ptr, int *stop)
424 {
425 eval_object(o);
426 }
427
428 static void
eval_object(heim_object_t o)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
main(int argc,char ** argv)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