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