xref: /netbsd-src/crypto/external/bsd/heimdal/dist/kdc/kdc-tester.c (revision d3273b5b76f5afaafe308cead5511dbb8df8c5e9)
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