1/*
2 * Copyright (c) 2003 - 2007 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 *
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 *
17 * 3. Neither the name of KTH nor the names of its contributors may be
18 *    used to endorse or promote products derived from this software without
19 *    specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY KTH AND ITS CONTRIBUTORS ``AS IS'' AND ANY
22 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KTH OR ITS CONTRIBUTORS BE
25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
28 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
30 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
31 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
32
33#include "krb5_locl.h"
34#include <getarg.h>
35#include <err.h>
36
37#ifdef __APPLE_PRIVATE__
38#include <dispatch/dispatch.h>
39#endif
40
41static int debug_flag	= 0;
42static int version_flag = 0;
43static int help_flag	= 0;
44
45#ifdef KRB5_USE_PATH_TOKENS
46#define TEST_CC_NAME "%{TEMP}/krb5-cc-test-foo"
47#else
48#define TEST_CC_NAME "/tmp/krb5-cc-test-foo"
49#endif
50
51static void
52test_default_name(krb5_context context)
53{
54    krb5_error_code ret;
55    const char *p, *test_cc_name = TEST_CC_NAME;
56    char *p1, *p2, *p3;
57
58    p = krb5_cc_default_name(context);
59    if (p == NULL)
60	krb5_errx (context, 1, "krb5_cc_default_name 1 failed");
61    p1 = estrdup(p);
62
63    ret = krb5_cc_set_default_name(context, NULL);
64    if (ret)
65	krb5_errx (context, 1, "krb5_cc_set_default_name failed");
66
67    p = krb5_cc_default_name(context);
68    if (p == NULL)
69	krb5_errx (context, 1, "krb5_cc_default_name 2 failed");
70    p2 = estrdup(p);
71
72    if (strcmp(p1, p2) != 0)
73	krb5_errx (context, 1, "krb5_cc_default_name no longer same");
74
75    ret = krb5_cc_set_default_name(context, test_cc_name);
76    if (ret)
77	krb5_errx (context, 1, "krb5_cc_set_default_name 1 failed");
78
79    p = krb5_cc_default_name(context);
80    if (p == NULL)
81	krb5_errx (context, 1, "krb5_cc_default_name 2 failed");
82    p3 = estrdup(p);
83
84#ifndef KRB5_USE_PATH_TOKENS
85    /* If we are using path tokens, we don't expect the p3 and
86       test_cc_name to match since p3 is going to have expanded
87       tokens. */
88    if (strcmp(p3, test_cc_name) != 0)
89	krb5_errx (context, 1, "krb5_cc_set_default_name 1 failed");
90#endif
91
92    free(p1);
93    free(p2);
94    free(p3);
95}
96
97/*
98 * Check that a closed cc still keeps it data and that it's no longer
99 * there when it's destroyed.
100 */
101
102static void
103test_mcache(krb5_context context)
104{
105    krb5_error_code ret;
106    krb5_ccache id, id2;
107    const char *nc, *tc;
108    char *c;
109    krb5_principal p, p2;
110
111    ret = krb5_parse_name(context, "lha@SU.SE", &p);
112    if (ret)
113	krb5_err(context, 1, ret, "krb5_parse_name");
114
115    ret = krb5_cc_new_unique(context, krb5_cc_type_memory, NULL, &id);
116    if (ret)
117	krb5_err(context, 1, ret, "krb5_cc_new_unique");
118
119    ret = krb5_cc_initialize(context, id, p);
120    if (ret)
121	krb5_err(context, 1, ret, "krb5_cc_initialize");
122
123    nc = krb5_cc_get_name(context, id);
124    if (nc == NULL)
125	krb5_errx(context, 1, "krb5_cc_get_name");
126
127    tc = krb5_cc_get_type(context, id);
128    if (tc == NULL)
129	krb5_errx(context, 1, "krb5_cc_get_name");
130
131    if (asprintf(&c, "%s:%s", tc, nc) < 0 || c == NULL)
132	errx(1, "malloc");
133
134    krb5_cc_close(context, id);
135
136    ret = krb5_cc_resolve(context, c, &id2);
137    if (ret)
138	krb5_err(context, 1, ret, "krb5_cc_resolve");
139
140    ret = krb5_cc_get_principal(context, id2, &p2);
141    if (ret)
142	krb5_err(context, 1, ret, "krb5_cc_get_principal");
143
144    if (krb5_principal_compare(context, p, p2) == FALSE)
145	krb5_errx(context, 1, "p != p2");
146
147    krb5_cc_destroy(context, id2);
148    krb5_free_principal(context, p);
149    krb5_free_principal(context, p2);
150
151    ret = krb5_cc_resolve(context, c, &id2);
152    if (ret)
153	krb5_err(context, 1, ret, "krb5_cc_resolve");
154
155    ret = krb5_cc_get_principal(context, id2, &p2);
156    if (ret == 0)
157	krb5_errx(context, 1, "krb5_cc_get_principal");
158
159    krb5_cc_destroy(context, id2);
160    free(c);
161}
162
163/*
164 * Test that init works on a destroyed cc.
165 */
166
167static void
168test_init_vs_destroy(krb5_context context, const char *type)
169{
170    krb5_error_code ret;
171    krb5_ccache id, id2;
172    krb5_principal p, p2;
173    char *n = NULL;
174
175    ret = krb5_parse_name(context, "lha@SU.SE", &p);
176    if (ret)
177	krb5_err(context, 1, ret, "krb5_parse_name");
178
179    ret = krb5_cc_new_unique(context, type, NULL, &id);
180    if (ret)
181	krb5_err(context, 1, ret, "krb5_cc_new_unique: %s", type);
182
183    if (asprintf(&n, "%s:%s",
184		 krb5_cc_get_type(context, id),
185		 krb5_cc_get_name(context, id)) < 0 || n == NULL)
186	errx(1, "malloc");
187
188
189    ret = krb5_cc_resolve(context, n, &id2);
190    free(n);
191    if (ret)
192	krb5_err(context, 1, ret, "krb5_cc_resolve");
193
194    krb5_cc_destroy(context, id);
195
196    ret = krb5_cc_initialize(context, id2, p);
197    if (ret)
198	krb5_err(context, 1, ret, "krb5_cc_initialize");
199
200    ret = krb5_cc_get_principal(context, id2, &p2);
201    if (ret)
202	krb5_err(context, 1, ret, "krb5_cc_get_principal");
203
204    krb5_cc_destroy(context, id2);
205    krb5_free_principal(context, p);
206    krb5_free_principal(context, p2);
207}
208
209static void
210test_cache_remove(krb5_context context, const char *type)
211{
212    krb5_error_code ret;
213    krb5_ccache id;
214    krb5_principal p;
215    krb5_creds cred;
216
217    ret = krb5_parse_name(context, "lha@SU.SE", &p);
218    if (ret)
219	krb5_err(context, 1, ret, "krb5_parse_name");
220
221    ret = krb5_cc_new_unique(context, type, NULL, &id);
222    if (ret)
223	krb5_err(context, 1, ret, "krb5_cc_gen_new: %s", type);
224
225    ret = krb5_cc_initialize(context, id, p);
226    if (ret)
227	krb5_err(context, 1, ret, "krb5_cc_initialize");
228
229    /* */
230    memset(&cred, 0, sizeof(cred));
231    ret = krb5_parse_name(context, "krbtgt/SU.SE@SU.SE", &cred.server);
232    if (ret)
233	krb5_err(context, 1, ret, "krb5_parse_name");
234    ret = krb5_parse_name(context, "lha@SU.SE", &cred.client);
235    if (ret)
236	krb5_err(context, 1, ret, "krb5_parse_name");
237
238    ret = krb5_cc_store_cred(context, id, &cred);
239    if (ret)
240	krb5_err(context, 1, ret, "krb5_cc_store_cred");
241
242    ret = krb5_cc_remove_cred(context, id, 0, &cred);
243    if (ret)
244	krb5_err(context, 1, ret, "krb5_cc_remove_cred");
245
246    ret = krb5_cc_destroy(context, id);
247    if (ret)
248	krb5_err(context, 1, ret, "krb5_cc_destroy");
249
250    krb5_free_principal(context, p);
251    krb5_free_principal(context, cred.server);
252    krb5_free_principal(context, cred.client);
253}
254
255static void
256test_mcc_default(void)
257{
258    krb5_context context;
259    krb5_error_code ret;
260    krb5_ccache id, id2;
261    int i;
262
263    for (i = 0; i < 10; i++) {
264
265	ret = krb5_init_context(&context);
266	if (ret)
267	    krb5_err(context, 1, ret, "krb5_init_context");
268
269	ret = krb5_cc_set_default_name(context, "MEMORY:foo");
270	if (ret)
271	    krb5_err(context, 1, ret, "krb5_cc_set_default_name");
272
273	ret = krb5_cc_default(context, &id);
274	if (ret)
275	    krb5_err(context, 1, ret, "krb5_cc_default");
276
277	ret = krb5_cc_default(context, &id2);
278	if (ret)
279	    krb5_err(context, 1, ret, "krb5_cc_default");
280
281	ret = krb5_cc_close(context, id);
282	if (ret)
283	    krb5_err(context, 1, ret, "krb5_cc_close");
284
285	ret = krb5_cc_close(context, id2);
286	if (ret)
287	    krb5_err(context, 1, ret, "krb5_cc_close");
288
289	krb5_free_context(context);
290    }
291}
292
293struct {
294    char *str;
295    int fail;
296    char *res;
297} cc_names[] = {
298#ifdef KRB5_USE_PATH_TOKENS
299#ifdef _WIN32
300    { "%{APPDATA}", 0 },
301    { "%{COMMON_APPDATA}", 0},
302    { "%{LOCAL_APPDATA}", 0},
303    { "%{SYSTEM}", 0},
304    { "%{WINDOWS}", 0},
305    { "%{USERCONFIG}", 0},
306    { "%{COMMONCONFIG}", 0},
307#else
308    { "%{LIBDIR}", 0},
309    { "%{BINDIR}", 0},
310    { "%{LIBEXEC}", 0},
311    { "%{SBINDIR}", 0},
312#endif
313#if __APPLE__
314    { "%{ApplicationResources}", 1}, /* only for .app's */
315#endif
316    { "%{USERID}", 0},
317    { "%{uid}", 0},
318    { "%{TEMP}", 0},
319#endif
320    { "foo", 0, "foo" },
321    { "foo%}", 0, "foo%}" },
322    { "%{uid}", 0 },
323    { "foo%{null}", 0, "foo" },
324    { "foo%{null}bar", 0, "foobar" },
325    { "%{", 1 },
326    { "%{foo %{", 1 },
327    { "%{{", 1 },
328    { "%{{}", 1 },
329    { "%{nulll}", 1 },
330    { "%{does not exist}", 1 },
331    { "%{}", 1 }
332};
333
334static void
335test_def_cc_name(krb5_context context)
336{
337    krb5_error_code ret;
338    char *str;
339    int i;
340
341    for (i = 0; i < sizeof(cc_names)/sizeof(cc_names[0]); i++) {
342	ret = _krb5_expand_default_cc_name(context, cc_names[i].str, &str);
343	if (ret) {
344	    if (cc_names[i].fail == 0)
345		krb5_errx(context, 1, "test %d \"%s\" failed",
346			  i, cc_names[i].str);
347	} else {
348	    if (cc_names[i].fail)
349		krb5_errx(context, 1, "test %d \"%s\" was successful",
350			  i, cc_names[i].str);
351	    if (cc_names[i].res && strcmp(cc_names[i].res, str) != 0)
352		krb5_errx(context, 1, "test %d %s != %s",
353			  i, cc_names[i].res, str);
354	    if (debug_flag)
355		printf("%s => %s\n", cc_names[i].str, str);
356	    free(str);
357	}
358    }
359}
360
361static void
362test_cache_find(krb5_context context, const char *principal, int find)
363{
364    krb5_principal client;
365    krb5_error_code ret;
366    krb5_ccache id = NULL;
367
368    ret = krb5_parse_name(context, principal, &client);
369    if (ret)
370	krb5_err(context, 1, ret, "parse_name for %s failed", principal);
371
372    ret = krb5_cc_cache_match(context, client, &id);
373    if (ret && find)
374	krb5_err(context, 1, ret, "cc_cache_match for %s failed", principal);
375    if (ret == 0 && !find)
376	krb5_err(context, 1, ret, "cc_cache_match for %s found", principal);
377
378    if (id)
379	krb5_cc_close(context, id);
380    krb5_free_principal(context, client);
381}
382
383
384static void
385test_cache_iter(krb5_context context, const char *type, int destroy)
386{
387    krb5_cc_cache_cursor cursor;
388    krb5_error_code ret;
389    krb5_ccache id;
390
391    ret = krb5_cc_cache_get_first (context, type, &cursor);
392    if (ret == KRB5_CC_NOSUPP)
393	return;
394    else if (ret)
395	krb5_err(context, 1, ret, "krb5_cc_cache_get_first(%s)", type);
396
397
398    while ((ret = krb5_cc_cache_next (context, cursor, &id)) == 0) {
399	krb5_principal principal;
400	char *name;
401
402	if (debug_flag)
403	    printf("name: %s\n", krb5_cc_get_name(context, id));
404	ret = krb5_cc_get_principal(context, id, &principal);
405	if (ret == 0) {
406	    ret = krb5_unparse_name(context, principal, &name);
407	    if (ret == 0) {
408		if (debug_flag)
409		    printf("\tprincipal: %s\n", name);
410		free(name);
411	    }
412	    krb5_free_principal(context, principal);
413	}
414	if (destroy)
415	    krb5_cc_destroy(context, id);
416	else
417	    krb5_cc_close(context, id);
418    }
419    if (ret != KRB5_CC_END)
420	krb5_err(context, 1, ret, "krb5_cc_cache_next returned not expected error");
421
422    krb5_cc_cache_end_seq_get(context, cursor);
423}
424
425static void
426test_cache_iter_all(krb5_context context)
427{
428    krb5_cccol_cursor cursor;
429    krb5_error_code ret;
430    krb5_ccache id;
431
432    ret = krb5_cccol_cursor_new (context, &cursor);
433    if (ret)
434	krb5_err(context, 1, ret, "krb5_cccol_cursor_new");
435
436
437    while ((ret = krb5_cccol_cursor_next (context, cursor, &id)) == 0 && id != NULL) {
438	krb5_principal principal;
439	char *name;
440
441	if (debug_flag)
442	    printf("name: %s\n", krb5_cc_get_name(context, id));
443	ret = krb5_cc_get_principal(context, id, &principal);
444	if (ret == 0) {
445	    ret = krb5_unparse_name(context, principal, &name);
446	    if (ret == 0) {
447		if (debug_flag)
448		    printf("\tprincipal: %s\n", name);
449		free(name);
450	    }
451	    krb5_free_principal(context, principal);
452	}
453	krb5_cc_close(context, id);
454    }
455    if (ret != KRB5_CC_END)
456	krb5_err(context, 1, ret, "krb5_cccol_cursor_next returned not expected error");
457
458    krb5_cccol_cursor_free(context, &cursor);
459}
460
461
462static void
463test_copy(krb5_context context, const char *from, const char *to)
464{
465    krb5_ccache fromid, toid;
466    krb5_error_code ret;
467    krb5_principal p, p2;
468
469    ret = krb5_parse_name(context, "lha@SU.SE", &p);
470    if (ret)
471	krb5_err(context, 1, ret, "krb5_parse_name");
472
473    ret = krb5_cc_new_unique(context, from, NULL, &fromid);
474    if (ret)
475	krb5_err(context, 1, ret, "krb5_cc_new_unique: %s", from);
476
477    ret = krb5_cc_initialize(context, fromid, p);
478    if (ret)
479	krb5_err(context, 1, ret, "krb5_cc_initialize");
480
481    ret = krb5_cc_new_unique(context, to, NULL, &toid);
482    if (ret)
483	krb5_err(context, 1, ret, "krb5_cc_gen_new: %s", to);
484
485    ret = krb5_cc_copy_cache(context, fromid, toid);
486    if (ret)
487	krb5_err(context, 1, ret, "krb5_cc_copy_cache");
488
489    ret = krb5_cc_get_principal(context, toid, &p2);
490    if (ret)
491	krb5_err(context, 1, ret, "krb5_cc_get_principal");
492
493    if (krb5_principal_compare(context, p, p2) == FALSE)
494	krb5_errx(context, 1, "p != p2");
495
496    krb5_free_principal(context, p);
497    krb5_free_principal(context, p2);
498
499    krb5_cc_destroy(context, fromid);
500    krb5_cc_destroy(context, toid);
501}
502
503static void
504test_move(krb5_context context, const char *type)
505{
506    const krb5_cc_ops *ops;
507    krb5_ccache fromid, toid;
508    krb5_error_code ret;
509    krb5_principal p, p2;
510
511    ops = krb5_cc_get_prefix_ops(context, type);
512    if (ops == NULL)
513	return;
514
515    ret = krb5_cc_new_unique(context, type, NULL, &fromid);
516    if (ret == KRB5_CC_NOSUPP)
517	return;
518    else if (ret)
519	krb5_err(context, 1, ret, "krb5_cc_new_unique: %s", type);
520
521    ret = krb5_parse_name(context, "lha@SU.SE", &p);
522    if (ret)
523	krb5_err(context, 1, ret, "krb5_parse_name");
524
525    ret = krb5_cc_initialize(context, fromid, p);
526    if (ret)
527	krb5_err(context, 1, ret, "krb5_cc_initialize");
528
529    ret = krb5_cc_new_unique(context, type, NULL, &toid);
530    if (ret)
531	krb5_err(context, 1, ret, "krb5_cc_new_unique");
532
533    ret = krb5_cc_initialize(context, toid, p);
534    if (ret)
535	krb5_err(context, 1, ret, "krb5_cc_initialize");
536
537    ret = krb5_cc_get_principal(context, toid, &p2);
538    if (ret)
539	krb5_err(context, 1, ret, "krb5_cc_get_principal");
540
541    if (krb5_principal_compare(context, p, p2) == FALSE)
542	krb5_errx(context, 1, "p != p2");
543
544    krb5_free_principal(context, p);
545    krb5_free_principal(context, p2);
546
547    krb5_cc_destroy(context, toid);
548    krb5_cc_destroy(context, fromid);
549}
550
551
552static void
553test_prefix_ops(krb5_context context, const char *name, const krb5_cc_ops *ops)
554{
555    const krb5_cc_ops *o;
556
557    o = krb5_cc_get_prefix_ops(context, name);
558    if (o == NULL)
559	krb5_errx(context, 1, "found no match for prefix '%s'", name);
560    if (strcmp(o->prefix, ops->prefix) != 0)
561	krb5_errx(context, 1, "ops for prefix '%s' is not "
562		  "the expected %s != %s", name, o->prefix, ops->prefix);
563}
564
565static void
566test_cc_config(krb5_context context)
567{
568    krb5_error_code ret;
569    krb5_principal p;
570    krb5_ccache id;
571    unsigned int i;
572
573    ret = krb5_cc_new_unique(context, "MEMORY", "bar", &id);
574    if (ret)
575	krb5_err(context, 1, ret, "krb5_cc_new_unique");
576
577    ret = krb5_parse_name(context, "lha@SU.SE", &p);
578    if (ret)
579	krb5_err(context, 1, ret, "krb5_parse_name");
580
581    ret = krb5_cc_initialize(context, id, p);
582    if (ret)
583	krb5_err(context, 1, ret, "krb5_cc_initialize");
584
585    for (i = 0; i < 1000; i++) {
586	krb5_data data, data2;
587	const char *name = "foo";
588	krb5_principal p1 = NULL;
589
590	if (i & 1)
591	    p1 = p;
592
593	data.data = rk_UNCONST(name);
594	data.length = strlen(name);
595
596	ret = krb5_cc_set_config(context, id, p1, "FriendlyName", &data);
597	if (ret)
598	    krb5_errx(context, 1, "krb5_cc_set_config: add");
599
600	ret = krb5_cc_get_config(context, id, p1, "FriendlyName", &data2);
601	if (ret)
602	    krb5_errx(context, 1, "krb5_cc_get_config: first");
603	krb5_data_free(&data2);
604
605	ret = krb5_cc_set_config(context, id, p1, "FriendlyName", &data);
606	if (ret)
607	    krb5_errx(context, 1, "krb5_cc_set_config: add -second");
608
609	ret = krb5_cc_get_config(context, id, p1, "FriendlyName", &data2);
610	if (ret)
611	    krb5_errx(context, 1, "krb5_cc_get_config: second");
612	krb5_data_free(&data2);
613
614	ret = krb5_cc_set_config(context, id, p1, "FriendlyName", NULL);
615	if (ret)
616	    krb5_errx(context, 1, "krb5_cc_set_config: delete");
617
618	ret = krb5_cc_get_config(context, id, p1, "FriendlyName", &data2);
619	if (ret == 0)
620	    krb5_errx(context, 1, "krb5_cc_get_config: non-existant");
621    }
622
623    krb5_cc_destroy(context, id);
624    krb5_free_principal(context, p);
625}
626
627#ifdef HAVE_DISPATCH_DISPATCH_H
628
629static void
630test_threaded(krb5_context context)
631{
632    dispatch_semaphore_t sema;
633    dispatch_queue_t q;
634    dispatch_group_t group;
635    time_t old;
636    const char *type = "API";
637
638    /* clean up old caches first */
639    test_cache_iter(context, type, 1);
640
641    sema = dispatch_semaphore_create(10);
642
643    q = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
644
645    old = time(NULL);
646
647    group = dispatch_group_create();
648    if (group == NULL) abort();
649
650    while (time(NULL) - old < 10) {
651	size_t number = 100;
652
653	dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
654
655	if (debug_flag)
656	    printf("time: %d\n", (int)(time(NULL) - old));
657
658	dispatch_group_async(group, q, ^{
659		dispatch_group_t inner = dispatch_group_create();
660		if (inner == NULL) abort();
661
662		dispatch_group_async(inner, q, ^{
663			dispatch_apply(number, q, ^(size_t num) {
664				test_move(context, "API");
665			    });
666		    });
667		dispatch_group_async(inner, q, ^{
668			dispatch_apply(number, q, ^(size_t num) {
669				test_move(context, "API");
670			    });
671		    });
672		dispatch_group_async(inner, q, ^{
673			dispatch_apply(number / 10, q, ^(size_t num) {
674				test_cache_iter(context, type, 0);
675			    });
676		    });
677		dispatch_group_async(inner, q, ^{
678			dispatch_apply(number / 10, q, ^(size_t num) {
679				test_cache_iter_all(context);
680			    });
681		    });
682
683		dispatch_group_wait(inner, DISPATCH_TIME_FOREVER);
684		dispatch_release(inner);
685		dispatch_semaphore_signal(sema);
686	    });
687    }
688
689    dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
690    dispatch_release(group);
691}
692
693#endif
694
695static struct getargs args[] = {
696    {"debug",	'd',	arg_flag,	&debug_flag,
697     "turn on debuggin", NULL },
698    {"version",	0,	arg_flag,	&version_flag,
699     "print version", NULL },
700    {"help",	0,	arg_flag,	&help_flag,
701     NULL, NULL }
702};
703
704static void
705usage (int ret)
706{
707    arg_printusage (args, sizeof(args)/sizeof(*args), NULL, "hostname ...");
708    exit (ret);
709}
710
711int
712main(int argc, char **argv)
713{
714    krb5_context context;
715    krb5_error_code ret;
716    int optidx = 0;
717    krb5_ccache id1, id2;
718
719    setprogname(argv[0]);
720
721    if(getarg(args, sizeof(args) / sizeof(args[0]), argc, argv, &optidx))
722	usage(1);
723
724    if (help_flag)
725	usage (0);
726
727    if(version_flag){
728	print_version(NULL);
729	exit(0);
730    }
731
732    ret = krb5_init_context(&context);
733    if (ret)
734	errx (1, "krb5_init_context failed: %d", ret);
735
736    test_cache_remove(context, krb5_cc_type_file);
737    test_cache_remove(context, krb5_cc_type_memory);
738#ifdef HAVE_SCC
739    test_cache_remove(context, krb5_cc_type_scc);
740#endif
741
742    test_default_name(context);
743    test_mcache(context);
744    test_init_vs_destroy(context, krb5_cc_type_memory);
745    test_init_vs_destroy(context, krb5_cc_type_file);
746#if 0
747    test_init_vs_destroy(context, krb5_cc_type_api);
748#endif
749#ifdef HAVE_SCC
750    test_init_vs_destroy(context, krb5_cc_type_scc);
751#endif
752    test_mcc_default();
753    test_def_cc_name(context);
754
755    test_cache_iter_all(context);
756
757    test_cache_iter(context, krb5_cc_type_memory, 0);
758    {
759	krb5_principal p;
760	krb5_cc_new_unique(context, krb5_cc_type_memory, "bar", &id1);
761	krb5_cc_new_unique(context, krb5_cc_type_memory, "baz", &id2);
762	krb5_parse_name(context, "lha@SU.SE", &p);
763	krb5_cc_initialize(context, id1, p);
764	krb5_cc_initialize(context, id1, p);
765	krb5_cc_initialize(context, id1, p);
766	krb5_cc_initialize(context, id1, p);
767	krb5_cc_initialize(context, id1, p);
768	krb5_cc_initialize(context, id1, p);
769	krb5_free_principal(context, p);
770    }
771
772    test_cache_find(context, "lha@SU.SE", 1);
773    test_cache_find(context, "hulabundulahotentot@SU.SE", 0);
774
775    test_cache_iter(context, krb5_cc_type_memory, 0);
776    test_cache_iter(context, krb5_cc_type_memory, 1);
777    test_cache_iter(context, krb5_cc_type_memory, 0);
778    test_cache_iter(context, krb5_cc_type_file, 0);
779    test_cache_iter(context, krb5_cc_type_api, 0);
780#ifdef HAVE_SCC
781    test_cache_iter(context, krb5_cc_type_scc, 0);
782    test_cache_iter(context, krb5_cc_type_scc, 1);
783#endif
784#ifdef HAVE_KCC
785    test_cache_iter(context, krb5_cc_type_kcc, 0);
786    test_cache_iter(context, krb5_cc_type_kcc, 1);
787#endif
788
789    test_copy(context, krb5_cc_type_file, krb5_cc_type_file);
790    test_copy(context, krb5_cc_type_memory, krb5_cc_type_memory);
791    test_copy(context, krb5_cc_type_file, krb5_cc_type_memory);
792    test_copy(context, krb5_cc_type_memory, krb5_cc_type_file);
793#ifdef HAVE_SCC
794    test_copy(context, krb5_cc_type_scc, krb5_cc_type_file);
795    test_copy(context, krb5_cc_type_file, krb5_cc_type_scc);
796    test_copy(context, krb5_cc_type_scc, krb5_cc_type_memory);
797    test_copy(context, krb5_cc_type_memory, krb5_cc_type_scc);
798#endif
799#ifdef HAVE_KCC
800    test_copy(context, krb5_cc_type_kcc, krb5_cc_type_file);
801    test_copy(context, krb5_cc_type_file, krb5_cc_type_kcc);
802    test_copy(context, krb5_cc_type_kcc, krb5_cc_type_memory);
803    test_copy(context, krb5_cc_type_memory, krb5_cc_type_kcc);
804#endif
805    test_move(context, krb5_cc_type_file);
806    test_move(context, krb5_cc_type_memory);
807#ifdef HAVE_KCM
808    test_move(context, krb5_cc_type_kcm);
809#endif
810#ifdef HAVE_SCC
811    test_move(context, krb5_cc_type_scc);
812#endif
813
814    test_prefix_ops(context, "FILE:/tmp/foo", &krb5_fcc_ops);
815    test_prefix_ops(context, "FILE", &krb5_fcc_ops);
816    test_prefix_ops(context, "MEMORY", &krb5_mcc_ops);
817    test_prefix_ops(context, "MEMORY:foo", &krb5_mcc_ops);
818    test_prefix_ops(context, "/tmp/kaka", &krb5_fcc_ops);
819#ifdef HAVE_SCC
820    test_prefix_ops(context, "SCC:", &krb5_scc_ops);
821    test_prefix_ops(context, "SCC:foo", &krb5_scc_ops);
822#endif
823#ifdef HAVE_KCC
824    test_prefix_ops(context, "KCC:", &krb5_kcc_ops);
825    test_prefix_ops(context, "KCC:foo", &krb5_kcc_ops);
826#endif
827#ifdef HAVE_XCC
828    test_prefix_ops(context, "XCACHE:", &krb5_xcc_ops);
829    test_prefix_ops(context, "XCACHE:68ADE5C1-C1FF-4088-8AA2-8AF815CDCC5A", &krb5_xcc_ops);
830#endif
831
832    krb5_cc_destroy(context, id1);
833    krb5_cc_destroy(context, id2);
834
835    test_cc_config(context);
836
837#ifdef HAVE_DISPATCH_DISPATCH_H
838    test_threaded(context);
839#endif
840
841    krb5_free_context(context);
842
843    return 0;
844}
845