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 RCSID("$Id: test_cc.c 22115 2007-12-03 21:21:42Z lha $"); 38 39 static int debug_flag = 0; 40 static int version_flag = 0; 41 static int help_flag = 0; 42 43 static void 44 test_default_name(krb5_context context) 45 { 46 krb5_error_code ret; 47 const char *p, *test_cc_name = "/tmp/krb5-cc-test-foo"; 48 char *p1, *p2, *p3; 49 50 p = krb5_cc_default_name(context); 51 if (p == NULL) 52 krb5_errx (context, 1, "krb5_cc_default_name 1 failed"); 53 p1 = estrdup(p); 54 55 ret = krb5_cc_set_default_name(context, NULL); 56 if (p == NULL) 57 krb5_errx (context, 1, "krb5_cc_set_default_name failed"); 58 59 p = krb5_cc_default_name(context); 60 if (p == NULL) 61 krb5_errx (context, 1, "krb5_cc_default_name 2 failed"); 62 p2 = estrdup(p); 63 64 if (strcmp(p1, p2) != 0) 65 krb5_errx (context, 1, "krb5_cc_default_name no longer same"); 66 67 ret = krb5_cc_set_default_name(context, test_cc_name); 68 if (p == NULL) 69 krb5_errx (context, 1, "krb5_cc_set_default_name 1 failed"); 70 71 p = krb5_cc_default_name(context); 72 if (p == NULL) 73 krb5_errx (context, 1, "krb5_cc_default_name 2 failed"); 74 p3 = estrdup(p); 75 76 if (strcmp(p3, test_cc_name) != 0) 77 krb5_errx (context, 1, "krb5_cc_set_default_name 1 failed"); 78 79 free(p1); 80 free(p2); 81 free(p3); 82 } 83 84 /* 85 * Check that a closed cc still keeps it data and that it's no longer 86 * there when it's destroyed. 87 */ 88 89 static void 90 test_mcache(krb5_context context) 91 { 92 krb5_error_code ret; 93 krb5_ccache id, id2; 94 const char *nc, *tc; 95 char *c; 96 krb5_principal p, p2; 97 98 ret = krb5_parse_name(context, "lha@SU.SE", &p); 99 if (ret) 100 krb5_err(context, 1, ret, "krb5_parse_name"); 101 102 ret = krb5_cc_gen_new(context, &krb5_mcc_ops, &id); 103 if (ret) 104 krb5_err(context, 1, ret, "krb5_cc_gen_new"); 105 106 ret = krb5_cc_initialize(context, id, p); 107 if (ret) 108 krb5_err(context, 1, ret, "krb5_cc_initialize"); 109 110 nc = krb5_cc_get_name(context, id); 111 if (nc == NULL) 112 krb5_errx(context, 1, "krb5_cc_get_name"); 113 114 tc = krb5_cc_get_type(context, id); 115 if (tc == NULL) 116 krb5_errx(context, 1, "krb5_cc_get_name"); 117 118 asprintf(&c, "%s:%s", tc, nc); 119 120 krb5_cc_close(context, id); 121 122 ret = krb5_cc_resolve(context, c, &id2); 123 if (ret) 124 krb5_err(context, 1, ret, "krb5_cc_resolve"); 125 126 ret = krb5_cc_get_principal(context, id2, &p2); 127 if (ret) 128 krb5_err(context, 1, ret, "krb5_cc_get_principal"); 129 130 if (krb5_principal_compare(context, p, p2) == FALSE) 131 krb5_errx(context, 1, "p != p2"); 132 133 krb5_cc_destroy(context, id2); 134 krb5_free_principal(context, p); 135 krb5_free_principal(context, p2); 136 137 ret = krb5_cc_resolve(context, c, &id2); 138 if (ret) 139 krb5_err(context, 1, ret, "krb5_cc_resolve"); 140 141 ret = krb5_cc_get_principal(context, id2, &p2); 142 if (ret == 0) 143 krb5_errx(context, 1, "krb5_cc_get_principal"); 144 145 krb5_cc_destroy(context, id2); 146 free(c); 147 } 148 149 /* 150 * Test that init works on a destroyed cc. 151 */ 152 153 static void 154 test_init_vs_destroy(krb5_context context, const krb5_cc_ops *ops) 155 { 156 krb5_error_code ret; 157 krb5_ccache id, id2; 158 krb5_principal p, p2; 159 char *n; 160 161 ret = krb5_parse_name(context, "lha@SU.SE", &p); 162 if (ret) 163 krb5_err(context, 1, ret, "krb5_parse_name"); 164 165 ret = krb5_cc_gen_new(context, ops, &id); 166 if (ret) 167 krb5_err(context, 1, ret, "krb5_cc_gen_new"); 168 169 asprintf(&n, "%s:%s", 170 krb5_cc_get_type(context, id), 171 krb5_cc_get_name(context, id)); 172 173 ret = krb5_cc_resolve(context, n, &id2); 174 free(n); 175 if (ret) 176 krb5_err(context, 1, ret, "krb5_cc_resolve"); 177 178 krb5_cc_destroy(context, id); 179 180 ret = krb5_cc_initialize(context, id2, p); 181 if (ret) 182 krb5_err(context, 1, ret, "krb5_cc_initialize"); 183 184 ret = krb5_cc_get_principal(context, id2, &p2); 185 if (ret) 186 krb5_err(context, 1, ret, "krb5_cc_get_principal"); 187 188 krb5_cc_destroy(context, id2); 189 krb5_free_principal(context, p); 190 krb5_free_principal(context, p2); 191 } 192 193 static void 194 test_fcache_remove(krb5_context context) 195 { 196 krb5_error_code ret; 197 krb5_ccache id; 198 krb5_principal p; 199 krb5_creds cred; 200 201 ret = krb5_parse_name(context, "lha@SU.SE", &p); 202 if (ret) 203 krb5_err(context, 1, ret, "krb5_parse_name"); 204 205 ret = krb5_cc_gen_new(context, &krb5_fcc_ops, &id); 206 if (ret) 207 krb5_err(context, 1, ret, "krb5_cc_gen_new"); 208 209 ret = krb5_cc_initialize(context, id, p); 210 if (ret) 211 krb5_err(context, 1, ret, "krb5_cc_initialize"); 212 213 /* */ 214 memset(&cred, 0, sizeof(cred)); 215 ret = krb5_parse_name(context, "krbtgt/SU.SE@SU.SE", &cred.server); 216 if (ret) 217 krb5_err(context, 1, ret, "krb5_parse_name"); 218 ret = krb5_parse_name(context, "lha@SU.SE", &cred.client); 219 if (ret) 220 krb5_err(context, 1, ret, "krb5_parse_name"); 221 222 ret = krb5_cc_store_cred(context, id, &cred); 223 if (ret) 224 krb5_err(context, 1, ret, "krb5_cc_store_cred"); 225 226 ret = krb5_cc_remove_cred(context, id, 0, &cred); 227 if (ret) 228 krb5_err(context, 1, ret, "krb5_cc_remove_cred"); 229 230 ret = krb5_cc_destroy(context, id); 231 if (ret) 232 krb5_err(context, 1, ret, "krb5_cc_destroy"); 233 234 krb5_free_principal(context, p); 235 krb5_free_principal(context, cred.server); 236 krb5_free_principal(context, cred.client); 237 } 238 239 static void 240 test_mcc_default(void) 241 { 242 krb5_context context; 243 krb5_error_code ret; 244 krb5_ccache id, id2; 245 int i; 246 247 for (i = 0; i < 10; i++) { 248 249 ret = krb5_init_context(&context); 250 if (ret) 251 krb5_err(context, 1, ret, "krb5_init_context"); 252 253 ret = krb5_cc_set_default_name(context, "MEMORY:foo"); 254 if (ret) 255 krb5_err(context, 1, ret, "krb5_cc_set_default_name"); 256 257 ret = krb5_cc_default(context, &id); 258 if (ret) 259 krb5_err(context, 1, ret, "krb5_cc_default"); 260 261 ret = krb5_cc_default(context, &id2); 262 if (ret) 263 krb5_err(context, 1, ret, "krb5_cc_default"); 264 265 ret = krb5_cc_close(context, id); 266 if (ret) 267 krb5_err(context, 1, ret, "krb5_cc_close"); 268 269 ret = krb5_cc_close(context, id2); 270 if (ret) 271 krb5_err(context, 1, ret, "krb5_cc_close"); 272 273 krb5_free_context(context); 274 } 275 } 276 277 struct { 278 char *str; 279 int fail; 280 char *res; 281 } cc_names[] = { 282 { "foo", 0, "foo" }, 283 { "%{uid}", 0 }, 284 { "foo%{null}", 0, "foo" }, 285 { "foo%{null}bar", 0, "foobar" }, 286 { "%{", 1 }, 287 { "%{foo %{", 1 }, 288 { "%{{", 1 }, 289 }; 290 291 static void 292 test_def_cc_name(krb5_context context) 293 { 294 krb5_error_code ret; 295 char *str; 296 int i; 297 298 for (i = 0; i < sizeof(cc_names)/sizeof(cc_names[0]); i++) { 299 ret = _krb5_expand_default_cc_name(context, cc_names[i].str, &str); 300 if (ret) { 301 if (cc_names[i].fail == 0) 302 krb5_errx(context, 1, "test %d \"%s\" failed", 303 i, cc_names[i].str); 304 } else { 305 if (cc_names[i].fail) 306 krb5_errx(context, 1, "test %d \"%s\" was successful", 307 i, cc_names[i].str); 308 if (cc_names[i].res && strcmp(cc_names[i].res, str) != 0) 309 krb5_errx(context, 1, "test %d %s != %s", 310 i, cc_names[i].res, str); 311 if (debug_flag) 312 printf("%s => %s\n", cc_names[i].str, str); 313 free(str); 314 } 315 } 316 } 317 318 static void 319 test_cache_find(krb5_context context, const char *type, const char *principal, 320 int find) 321 { 322 krb5_principal client; 323 krb5_error_code ret; 324 krb5_ccache id = NULL; 325 326 ret = krb5_parse_name(context, principal, &client); 327 if (ret) 328 krb5_err(context, 1, ret, "parse_name for %s failed", principal); 329 330 ret = krb5_cc_cache_match(context, client, type, &id); 331 if (ret && find) 332 krb5_err(context, 1, ret, "cc_cache_match for %s failed", principal); 333 if (ret == 0 && !find) 334 krb5_err(context, 1, ret, "cc_cache_match for %s found", principal); 335 336 if (id) 337 krb5_cc_close(context, id); 338 krb5_free_principal(context, client); 339 } 340 341 342 static void 343 test_cache_iter(krb5_context context, const char *type, int destroy) 344 { 345 krb5_cc_cache_cursor cursor; 346 krb5_error_code ret; 347 krb5_ccache id; 348 349 ret = krb5_cc_cache_get_first (context, type, &cursor); 350 if (ret == KRB5_CC_NOSUPP) 351 return; 352 else if (ret) 353 krb5_err(context, 1, ret, "krb5_cc_cache_get_first(%s)", type); 354 355 356 while ((ret = krb5_cc_cache_next (context, cursor, &id)) == 0) { 357 krb5_principal principal; 358 char *name; 359 360 if (debug_flag) 361 printf("name: %s\n", krb5_cc_get_name(context, id)); 362 ret = krb5_cc_get_principal(context, id, &principal); 363 if (ret == 0) { 364 ret = krb5_unparse_name(context, principal, &name); 365 if (ret == 0) { 366 if (debug_flag) 367 printf("\tprincipal: %s\n", name); 368 free(name); 369 } 370 krb5_free_principal(context, principal); 371 } 372 if (destroy) 373 krb5_cc_destroy(context, id); 374 else 375 krb5_cc_close(context, id); 376 } 377 378 krb5_cc_cache_end_seq_get(context, cursor); 379 } 380 381 static void 382 test_copy(krb5_context context, const char *fromtype, const char *totype) 383 { 384 const krb5_cc_ops *from, *to; 385 krb5_ccache fromid, toid; 386 krb5_error_code ret; 387 krb5_principal p, p2; 388 389 from = krb5_cc_get_prefix_ops(context, fromtype); 390 if (from == NULL) 391 krb5_errx(context, 1, "%s isn't a type", fromtype); 392 393 to = krb5_cc_get_prefix_ops(context, totype); 394 if (to == NULL) 395 krb5_errx(context, 1, "%s isn't a type", totype); 396 397 ret = krb5_parse_name(context, "lha@SU.SE", &p); 398 if (ret) 399 krb5_err(context, 1, ret, "krb5_parse_name"); 400 401 ret = krb5_cc_gen_new(context, from, &fromid); 402 if (ret) 403 krb5_err(context, 1, ret, "krb5_cc_gen_new"); 404 405 ret = krb5_cc_initialize(context, fromid, p); 406 if (ret) 407 krb5_err(context, 1, ret, "krb5_cc_initialize"); 408 409 ret = krb5_cc_gen_new(context, to, &toid); 410 if (ret) 411 krb5_err(context, 1, ret, "krb5_cc_gen_new"); 412 413 ret = krb5_cc_copy_cache(context, fromid, toid); 414 if (ret) 415 krb5_err(context, 1, ret, "krb5_cc_copy_cache"); 416 417 ret = krb5_cc_get_principal(context, toid, &p2); 418 if (ret) 419 krb5_err(context, 1, ret, "krb5_cc_get_principal"); 420 421 if (krb5_principal_compare(context, p, p2) == FALSE) 422 krb5_errx(context, 1, "p != p2"); 423 424 krb5_free_principal(context, p); 425 krb5_free_principal(context, p2); 426 427 krb5_cc_destroy(context, fromid); 428 krb5_cc_destroy(context, toid); 429 } 430 431 static void 432 test_prefix_ops(krb5_context context, const char *name, const krb5_cc_ops *ops) 433 { 434 const krb5_cc_ops *o; 435 436 o = krb5_cc_get_prefix_ops(context, name); 437 if (o == NULL) 438 krb5_errx(context, 1, "found no match for prefix '%s'", name); 439 if (strcmp(o->prefix, ops->prefix) != 0) 440 krb5_errx(context, 1, "ops for prefix '%s' is not " 441 "the expected %s != %s", name, o->prefix, ops->prefix); 442 } 443 444 445 static struct getargs args[] = { 446 {"debug", 'd', arg_flag, &debug_flag, 447 "turn on debuggin", NULL }, 448 {"version", 0, arg_flag, &version_flag, 449 "print version", NULL }, 450 {"help", 0, arg_flag, &help_flag, 451 NULL, NULL } 452 }; 453 454 static void 455 usage (int ret) 456 { 457 arg_printusage (args, sizeof(args)/sizeof(*args), NULL, "hostname ..."); 458 exit (ret); 459 } 460 461 int 462 main(int argc, char **argv) 463 { 464 krb5_context context; 465 krb5_error_code ret; 466 int optidx = 0; 467 krb5_ccache id1, id2; 468 469 setprogname(argv[0]); 470 471 if(getarg(args, sizeof(args) / sizeof(args[0]), argc, argv, &optidx)) 472 usage(1); 473 474 if (help_flag) 475 usage (0); 476 477 if(version_flag){ 478 print_version(NULL); 479 exit(0); 480 } 481 482 argc -= optidx; 483 argv += optidx; 484 485 ret = krb5_init_context(&context); 486 if (ret) 487 errx (1, "krb5_init_context failed: %d", ret); 488 489 test_fcache_remove(context); 490 test_default_name(context); 491 test_mcache(context); 492 test_init_vs_destroy(context, &krb5_mcc_ops); 493 test_init_vs_destroy(context, &krb5_fcc_ops); 494 test_mcc_default(); 495 test_def_cc_name(context); 496 test_cache_iter(context, "MEMORY", 0); 497 { 498 krb5_principal p; 499 krb5_cc_new_unique(context, "MEMORY", "bar", &id1); 500 krb5_cc_new_unique(context, "MEMORY", "baz", &id2); 501 krb5_parse_name(context, "lha@SU.SE", &p); 502 krb5_cc_initialize(context, id1, p); 503 krb5_free_principal(context, p); 504 } 505 506 test_cache_find(context, "MEMORY", "lha@SU.SE", 1); 507 test_cache_find(context, "MEMORY", "hulabundulahotentot@SU.SE", 0); 508 509 test_cache_iter(context, "MEMORY", 0); 510 test_cache_iter(context, "MEMORY", 1); 511 test_cache_iter(context, "MEMORY", 0); 512 test_cache_iter(context, "FILE", 0); 513 test_cache_iter(context, "API", 0); 514 515 test_copy(context, "FILE", "FILE"); 516 test_copy(context, "MEMORY", "MEMORY"); 517 test_copy(context, "FILE", "MEMORY"); 518 test_copy(context, "MEMORY", "FILE"); 519 520 test_prefix_ops(context, "FILE:/tmp/foo", &krb5_fcc_ops); 521 test_prefix_ops(context, "FILE", &krb5_fcc_ops); 522 test_prefix_ops(context, "MEMORY", &krb5_mcc_ops); 523 test_prefix_ops(context, "MEMORY:foo", &krb5_mcc_ops); 524 test_prefix_ops(context, "/tmp/kaka", &krb5_fcc_ops); 525 526 krb5_cc_destroy(context, id1); 527 krb5_cc_destroy(context, id2); 528 529 krb5_free_context(context); 530 531 return 0; 532 } 533