1 /* $NetBSD: scache.c,v 1.1.1.1 2011/04/13 18:15:37 elric Exp $ */ 2 3 /* 4 * Copyright (c) 2008 Kungliga Tekniska Högskolan 5 * (Royal Institute of Technology, Stockholm, Sweden). 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * 3. Neither the name of the Institute nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 36 #include "krb5_locl.h" 37 38 #ifdef HAVE_SCC 39 40 #include <sqlite3.h> 41 42 typedef struct krb5_scache { 43 char *name; 44 char *file; 45 sqlite3 *db; 46 47 sqlite_uint64 cid; 48 49 sqlite3_stmt *icred; 50 sqlite3_stmt *dcred; 51 sqlite3_stmt *iprincipal; 52 53 sqlite3_stmt *icache; 54 sqlite3_stmt *ucachen; 55 sqlite3_stmt *ucachep; 56 sqlite3_stmt *dcache; 57 sqlite3_stmt *scache; 58 sqlite3_stmt *scache_name; 59 sqlite3_stmt *umaster; 60 61 } krb5_scache; 62 63 #define SCACHE(X) ((krb5_scache *)(X)->data.data) 64 65 #define SCACHE_DEF_NAME "Default-cache" 66 #ifdef KRB5_USE_PATH_TOKENS 67 #define KRB5_SCACHE_DB "%{TEMP}/krb5scc_%{uid}" 68 #else 69 #define KRB5_SCACHE_DB "/tmp/krb5scc_%{uid}" 70 #endif 71 #define KRB5_SCACHE_NAME "SCC:" SCACHE_DEF_NAME ":" KRB5_SCACHE_DB 72 73 #define SCACHE_INVALID_CID ((sqlite_uint64)-1) 74 75 /* 76 * 77 */ 78 79 #define SQL_CMASTER "" \ 80 "CREATE TABLE master (" \ 81 "oid INTEGER PRIMARY KEY," \ 82 "version INTEGER NOT NULL," \ 83 "defaultcache TEXT NOT NULL" \ 84 ")" 85 86 #define SQL_SETUP_MASTER \ 87 "INSERT INTO master (version,defaultcache) VALUES(2, \"" SCACHE_DEF_NAME "\")" 88 #define SQL_UMASTER "UPDATE master SET defaultcache=? WHERE version=2" 89 90 #define SQL_CCACHE "" \ 91 "CREATE TABLE caches (" \ 92 "oid INTEGER PRIMARY KEY," \ 93 "principal TEXT," \ 94 "name TEXT NOT NULL" \ 95 ")" 96 97 #define SQL_TCACHE "" \ 98 "CREATE TRIGGER CacheDropCreds AFTER DELETE ON caches " \ 99 "FOR EACH ROW BEGIN " \ 100 "DELETE FROM credentials WHERE cid=old.oid;" \ 101 "END" 102 103 #define SQL_ICACHE "INSERT INTO caches (name) VALUES(?)" 104 #define SQL_UCACHE_NAME "UPDATE caches SET name=? WHERE OID=?" 105 #define SQL_UCACHE_PRINCIPAL "UPDATE caches SET principal=? WHERE OID=?" 106 #define SQL_DCACHE "DELETE FROM caches WHERE OID=?" 107 #define SQL_SCACHE "SELECT principal,name FROM caches WHERE OID=?" 108 #define SQL_SCACHE_NAME "SELECT oid FROM caches WHERE NAME=?" 109 110 #define SQL_CCREDS "" \ 111 "CREATE TABLE credentials (" \ 112 "oid INTEGER PRIMARY KEY," \ 113 "cid INTEGER NOT NULL," \ 114 "kvno INTEGER NOT NULL," \ 115 "etype INTEGER NOT NULL," \ 116 "created_at INTEGER NOT NULL," \ 117 "cred BLOB NOT NULL" \ 118 ")" 119 120 #define SQL_TCRED "" \ 121 "CREATE TRIGGER credDropPrincipal AFTER DELETE ON credentials " \ 122 "FOR EACH ROW BEGIN " \ 123 "DELETE FROM principals WHERE credential_id=old.oid;" \ 124 "END" 125 126 #define SQL_ICRED "INSERT INTO credentials (cid, kvno, etype, cred, created_at) VALUES (?,?,?,?,?)" 127 #define SQL_DCRED "DELETE FROM credentials WHERE cid=?" 128 129 #define SQL_CPRINCIPALS "" \ 130 "CREATE TABLE principals (" \ 131 "oid INTEGER PRIMARY KEY," \ 132 "principal TEXT NOT NULL," \ 133 "type INTEGER NOT NULL," \ 134 "credential_id INTEGER NOT NULL" \ 135 ")" 136 137 #define SQL_IPRINCIPAL "INSERT INTO principals (principal, type, credential_id) VALUES (?,?,?)" 138 139 /* 140 * sqlite destructors 141 */ 142 143 static void 144 free_data(void *data) 145 { 146 free(data); 147 } 148 149 static void 150 free_krb5(void *str) 151 { 152 krb5_xfree(str); 153 } 154 155 static void 156 scc_free(krb5_scache *s) 157 { 158 if (s->file) 159 free(s->file); 160 if (s->name) 161 free(s->name); 162 163 if (s->icred) 164 sqlite3_finalize(s->icred); 165 if (s->dcred) 166 sqlite3_finalize(s->dcred); 167 if (s->iprincipal) 168 sqlite3_finalize(s->iprincipal); 169 if (s->icache) 170 sqlite3_finalize(s->icache); 171 if (s->ucachen) 172 sqlite3_finalize(s->ucachen); 173 if (s->ucachep) 174 sqlite3_finalize(s->ucachep); 175 if (s->dcache) 176 sqlite3_finalize(s->dcache); 177 if (s->scache) 178 sqlite3_finalize(s->scache); 179 if (s->scache_name) 180 sqlite3_finalize(s->scache_name); 181 if (s->umaster) 182 sqlite3_finalize(s->umaster); 183 184 if (s->db) 185 sqlite3_close(s->db); 186 free(s); 187 } 188 189 #ifdef TRACEME 190 static void 191 trace(void* ptr, const char * str) 192 { 193 printf("SQL: %s\n", str); 194 } 195 #endif 196 197 static krb5_error_code 198 prepare_stmt(krb5_context context, sqlite3 *db, 199 sqlite3_stmt **stmt, const char *str) 200 { 201 int ret; 202 203 ret = sqlite3_prepare_v2(db, str, -1, stmt, NULL); 204 if (ret != SQLITE_OK) { 205 krb5_set_error_message(context, ENOENT, 206 N_("Failed to prepare stmt %s: %s", ""), 207 str, sqlite3_errmsg(db)); 208 return ENOENT; 209 } 210 return 0; 211 } 212 213 static krb5_error_code 214 exec_stmt(krb5_context context, sqlite3 *db, const char *str, 215 krb5_error_code code) 216 { 217 int ret; 218 219 ret = sqlite3_exec(db, str, NULL, NULL, NULL); 220 if (ret != SQLITE_OK && code) { 221 krb5_set_error_message(context, code, 222 N_("scache execute %s: %s", ""), str, 223 sqlite3_errmsg(db)); 224 return code; 225 } 226 return 0; 227 } 228 229 static krb5_error_code 230 default_db(krb5_context context, sqlite3 **db) 231 { 232 char *name; 233 int ret; 234 235 ret = _krb5_expand_default_cc_name(context, KRB5_SCACHE_DB, &name); 236 if (ret) 237 return ret; 238 239 ret = sqlite3_open_v2(name, db, SQLITE_OPEN_READWRITE, NULL); 240 free(name); 241 if (ret != SQLITE_OK) { 242 krb5_clear_error_message(context); 243 return ENOENT; 244 } 245 246 #ifdef TRACEME 247 sqlite3_trace(*db, trace, NULL); 248 #endif 249 250 return 0; 251 } 252 253 static krb5_error_code 254 get_def_name(krb5_context context, char **str) 255 { 256 krb5_error_code ret; 257 sqlite3_stmt *stmt; 258 const char *name; 259 sqlite3 *db; 260 261 ret = default_db(context, &db); 262 if (ret) 263 return ret; 264 265 ret = prepare_stmt(context, db, &stmt, "SELECT defaultcache FROM master"); 266 if (ret) { 267 sqlite3_close(db); 268 return ret; 269 } 270 271 ret = sqlite3_step(stmt); 272 if (ret != SQLITE_ROW) 273 goto out; 274 275 if (sqlite3_column_type(stmt, 0) != SQLITE_TEXT) 276 goto out; 277 278 name = (const char *)sqlite3_column_text(stmt, 0); 279 if (name == NULL) 280 goto out; 281 282 *str = strdup(name); 283 if (*str == NULL) 284 goto out; 285 286 sqlite3_finalize(stmt); 287 sqlite3_close(db); 288 return 0; 289 out: 290 sqlite3_finalize(stmt); 291 sqlite3_close(db); 292 krb5_clear_error_message(context); 293 return ENOENT; 294 } 295 296 297 298 static krb5_scache * KRB5_CALLCONV 299 scc_alloc(krb5_context context, const char *name) 300 { 301 krb5_error_code ret; 302 krb5_scache *s; 303 304 ALLOC(s, 1); 305 if(s == NULL) 306 return NULL; 307 308 s->cid = SCACHE_INVALID_CID; 309 310 if (name) { 311 char *file; 312 313 if (*name == '\0') { 314 krb5_error_code ret; 315 ret = get_def_name(context, &s->name); 316 if (ret) 317 s->name = strdup(SCACHE_DEF_NAME); 318 } else 319 s->name = strdup(name); 320 321 file = strrchr(s->name, ':'); 322 if (file) { 323 *file++ = '\0'; 324 s->file = strdup(file); 325 ret = 0; 326 } else { 327 ret = _krb5_expand_default_cc_name(context, KRB5_SCACHE_DB, &s->file); 328 } 329 } else { 330 _krb5_expand_default_cc_name(context, KRB5_SCACHE_DB, &s->file); 331 ret = asprintf(&s->name, "unique-%p", s); 332 } 333 if (ret < 0 || s->file == NULL || s->name == NULL) { 334 scc_free(s); 335 return NULL; 336 } 337 338 return s; 339 } 340 341 static krb5_error_code 342 open_database(krb5_context context, krb5_scache *s, int flags) 343 { 344 int ret; 345 346 ret = sqlite3_open_v2(s->file, &s->db, SQLITE_OPEN_READWRITE|flags, NULL); 347 if (ret) { 348 if (s->db) { 349 krb5_set_error_message(context, ENOENT, 350 N_("Error opening scache file %s: %s", ""), 351 s->file, sqlite3_errmsg(s->db)); 352 sqlite3_close(s->db); 353 s->db = NULL; 354 } else 355 krb5_set_error_message(context, ENOENT, 356 N_("malloc: out of memory", "")); 357 return ENOENT; 358 } 359 return 0; 360 } 361 362 static krb5_error_code 363 create_cache(krb5_context context, krb5_scache *s) 364 { 365 int ret; 366 367 sqlite3_bind_text(s->icache, 1, s->name, -1, NULL); 368 do { 369 ret = sqlite3_step(s->icache); 370 } while (ret == SQLITE_ROW); 371 if (ret != SQLITE_DONE) { 372 krb5_set_error_message(context, KRB5_CC_IO, 373 N_("Failed to add scache: %d", ""), ret); 374 return KRB5_CC_IO; 375 } 376 sqlite3_reset(s->icache); 377 378 s->cid = sqlite3_last_insert_rowid(s->db); 379 380 return 0; 381 } 382 383 static krb5_error_code 384 make_database(krb5_context context, krb5_scache *s) 385 { 386 int created_file = 0; 387 int ret; 388 389 if (s->db) 390 return 0; 391 392 ret = open_database(context, s, 0); 393 if (ret) { 394 mode_t oldumask = umask(077); 395 ret = open_database(context, s, SQLITE_OPEN_CREATE); 396 umask(oldumask); 397 if (ret) goto out; 398 399 created_file = 1; 400 401 ret = exec_stmt(context, s->db, SQL_CMASTER, KRB5_CC_IO); 402 if (ret) goto out; 403 ret = exec_stmt(context, s->db, SQL_CCACHE, KRB5_CC_IO); 404 if (ret) goto out; 405 ret = exec_stmt(context, s->db, SQL_CCREDS, KRB5_CC_IO); 406 if (ret) goto out; 407 ret = exec_stmt(context, s->db, SQL_CPRINCIPALS, KRB5_CC_IO); 408 if (ret) goto out; 409 ret = exec_stmt(context, s->db, SQL_SETUP_MASTER, KRB5_CC_IO); 410 if (ret) goto out; 411 412 ret = exec_stmt(context, s->db, SQL_TCACHE, KRB5_CC_IO); 413 if (ret) goto out; 414 ret = exec_stmt(context, s->db, SQL_TCRED, KRB5_CC_IO); 415 if (ret) goto out; 416 } 417 418 #ifdef TRACEME 419 sqlite3_trace(s->db, trace, NULL); 420 #endif 421 422 ret = prepare_stmt(context, s->db, &s->icred, SQL_ICRED); 423 if (ret) goto out; 424 ret = prepare_stmt(context, s->db, &s->dcred, SQL_DCRED); 425 if (ret) goto out; 426 ret = prepare_stmt(context, s->db, &s->iprincipal, SQL_IPRINCIPAL); 427 if (ret) goto out; 428 ret = prepare_stmt(context, s->db, &s->icache, SQL_ICACHE); 429 if (ret) goto out; 430 ret = prepare_stmt(context, s->db, &s->ucachen, SQL_UCACHE_NAME); 431 if (ret) goto out; 432 ret = prepare_stmt(context, s->db, &s->ucachep, SQL_UCACHE_PRINCIPAL); 433 if (ret) goto out; 434 ret = prepare_stmt(context, s->db, &s->dcache, SQL_DCACHE); 435 if (ret) goto out; 436 ret = prepare_stmt(context, s->db, &s->scache, SQL_SCACHE); 437 if (ret) goto out; 438 ret = prepare_stmt(context, s->db, &s->scache_name, SQL_SCACHE_NAME); 439 if (ret) goto out; 440 ret = prepare_stmt(context, s->db, &s->umaster, SQL_UMASTER); 441 if (ret) goto out; 442 443 return 0; 444 445 out: 446 if (s->db) 447 sqlite3_close(s->db); 448 if (created_file) 449 unlink(s->file); 450 451 return ret; 452 } 453 454 static krb5_error_code 455 bind_principal(krb5_context context, 456 sqlite3 *db, 457 sqlite3_stmt *stmt, 458 int col, 459 krb5_const_principal principal) 460 { 461 krb5_error_code ret; 462 char *str; 463 464 ret = krb5_unparse_name(context, principal, &str); 465 if (ret) 466 return ret; 467 468 ret = sqlite3_bind_text(stmt, col, str, -1, free_krb5); 469 if (ret != SQLITE_OK) { 470 krb5_xfree(str); 471 krb5_set_error_message(context, ENOMEM, 472 N_("scache bind principal: %s", ""), 473 sqlite3_errmsg(db)); 474 return ENOMEM; 475 } 476 return 0; 477 } 478 479 /* 480 * 481 */ 482 483 static const char* KRB5_CALLCONV 484 scc_get_name(krb5_context context, 485 krb5_ccache id) 486 { 487 return SCACHE(id)->name; 488 } 489 490 static krb5_error_code KRB5_CALLCONV 491 scc_resolve(krb5_context context, krb5_ccache *id, const char *res) 492 { 493 krb5_scache *s; 494 int ret; 495 496 s = scc_alloc(context, res); 497 if (s == NULL) { 498 krb5_set_error_message(context, KRB5_CC_NOMEM, 499 N_("malloc: out of memory", "")); 500 return KRB5_CC_NOMEM; 501 } 502 503 ret = make_database(context, s); 504 if (ret) { 505 scc_free(s); 506 return ret; 507 } 508 509 ret = sqlite3_bind_text(s->scache_name, 1, s->name, -1, NULL); 510 if (ret != SQLITE_OK) { 511 krb5_set_error_message(context, ENOMEM, 512 "bind name: %s", sqlite3_errmsg(s->db)); 513 scc_free(s); 514 return ENOMEM; 515 } 516 517 if (sqlite3_step(s->scache_name) == SQLITE_ROW) { 518 519 if (sqlite3_column_type(s->scache_name, 0) != SQLITE_INTEGER) { 520 sqlite3_reset(s->scache_name); 521 krb5_set_error_message(context, KRB5_CC_END, 522 N_("Cache name of wrong type " 523 "for scache %ld", ""), 524 (unsigned long)s->name); 525 scc_free(s); 526 return KRB5_CC_END; 527 } 528 529 s->cid = sqlite3_column_int(s->scache_name, 0); 530 } else { 531 s->cid = SCACHE_INVALID_CID; 532 } 533 sqlite3_reset(s->scache_name); 534 535 (*id)->data.data = s; 536 (*id)->data.length = sizeof(*s); 537 538 return 0; 539 } 540 541 static krb5_error_code KRB5_CALLCONV 542 scc_gen_new(krb5_context context, krb5_ccache *id) 543 { 544 krb5_scache *s; 545 546 s = scc_alloc(context, NULL); 547 548 if (s == NULL) { 549 krb5_set_error_message(context, KRB5_CC_NOMEM, 550 N_("malloc: out of memory", "")); 551 return KRB5_CC_NOMEM; 552 } 553 554 (*id)->data.data = s; 555 (*id)->data.length = sizeof(*s); 556 557 return 0; 558 } 559 560 static krb5_error_code KRB5_CALLCONV 561 scc_initialize(krb5_context context, 562 krb5_ccache id, 563 krb5_principal primary_principal) 564 { 565 krb5_scache *s = SCACHE(id); 566 krb5_error_code ret; 567 568 ret = make_database(context, s); 569 if (ret) 570 return ret; 571 572 ret = exec_stmt(context, s->db, "BEGIN IMMEDIATE TRANSACTION", KRB5_CC_IO); 573 if (ret) return ret; 574 575 if (s->cid == SCACHE_INVALID_CID) { 576 ret = create_cache(context, s); 577 if (ret) 578 goto rollback; 579 } else { 580 sqlite3_bind_int(s->dcred, 1, s->cid); 581 do { 582 ret = sqlite3_step(s->dcred); 583 } while (ret == SQLITE_ROW); 584 sqlite3_reset(s->dcred); 585 if (ret != SQLITE_DONE) { 586 ret = KRB5_CC_IO; 587 krb5_set_error_message(context, ret, 588 N_("Failed to delete old " 589 "credentials: %s", ""), 590 sqlite3_errmsg(s->db)); 591 goto rollback; 592 } 593 } 594 595 ret = bind_principal(context, s->db, s->ucachep, 1, primary_principal); 596 if (ret) 597 goto rollback; 598 sqlite3_bind_int(s->ucachep, 2, s->cid); 599 600 do { 601 ret = sqlite3_step(s->ucachep); 602 } while (ret == SQLITE_ROW); 603 sqlite3_reset(s->ucachep); 604 if (ret != SQLITE_DONE) { 605 ret = KRB5_CC_IO; 606 krb5_set_error_message(context, ret, 607 N_("Failed to bind principal to cache %s", ""), 608 sqlite3_errmsg(s->db)); 609 goto rollback; 610 } 611 612 ret = exec_stmt(context, s->db, "COMMIT", KRB5_CC_IO); 613 if (ret) return ret; 614 615 return 0; 616 617 rollback: 618 exec_stmt(context, s->db, "ROLLBACK", 0); 619 620 return ret; 621 622 } 623 624 static krb5_error_code KRB5_CALLCONV 625 scc_close(krb5_context context, 626 krb5_ccache id) 627 { 628 scc_free(SCACHE(id)); 629 return 0; 630 } 631 632 static krb5_error_code KRB5_CALLCONV 633 scc_destroy(krb5_context context, 634 krb5_ccache id) 635 { 636 krb5_scache *s = SCACHE(id); 637 int ret; 638 639 if (s->cid == SCACHE_INVALID_CID) 640 return 0; 641 642 sqlite3_bind_int(s->dcache, 1, s->cid); 643 do { 644 ret = sqlite3_step(s->dcache); 645 } while (ret == SQLITE_ROW); 646 sqlite3_reset(s->dcache); 647 if (ret != SQLITE_DONE) { 648 krb5_set_error_message(context, KRB5_CC_IO, 649 N_("Failed to destroy cache %s: %s", ""), 650 s->name, sqlite3_errmsg(s->db)); 651 return KRB5_CC_IO; 652 } 653 return 0; 654 } 655 656 static krb5_error_code 657 encode_creds(krb5_context context, krb5_creds *creds, krb5_data *data) 658 { 659 krb5_error_code ret; 660 krb5_storage *sp; 661 662 sp = krb5_storage_emem(); 663 if (sp == NULL) { 664 krb5_set_error_message(context, ENOMEM, 665 N_("malloc: out of memory", "")); 666 return ENOMEM; 667 } 668 669 ret = krb5_store_creds(sp, creds); 670 if (ret) { 671 krb5_set_error_message(context, ret, 672 N_("Failed to store credential in scache", "")); 673 krb5_storage_free(sp); 674 return ret; 675 } 676 677 ret = krb5_storage_to_data(sp, data); 678 krb5_storage_free(sp); 679 if (ret) 680 krb5_set_error_message(context, ret, 681 N_("Failed to encode credential in scache", "")); 682 return ret; 683 } 684 685 static krb5_error_code 686 decode_creds(krb5_context context, const void *data, size_t length, 687 krb5_creds *creds) 688 { 689 krb5_error_code ret; 690 krb5_storage *sp; 691 692 sp = krb5_storage_from_readonly_mem(data, length); 693 if (sp == NULL) { 694 krb5_set_error_message(context, ENOMEM, 695 N_("malloc: out of memory", "")); 696 return ENOMEM; 697 } 698 699 ret = krb5_ret_creds(sp, creds); 700 krb5_storage_free(sp); 701 if (ret) { 702 krb5_set_error_message(context, ret, 703 N_("Failed to read credential in scache", "")); 704 return ret; 705 } 706 return 0; 707 } 708 709 710 static krb5_error_code KRB5_CALLCONV 711 scc_store_cred(krb5_context context, 712 krb5_ccache id, 713 krb5_creds *creds) 714 { 715 sqlite_uint64 credid; 716 krb5_scache *s = SCACHE(id); 717 krb5_error_code ret; 718 krb5_data data; 719 720 ret = make_database(context, s); 721 if (ret) 722 return ret; 723 724 ret = encode_creds(context, creds, &data); 725 if (ret) 726 return ret; 727 728 sqlite3_bind_int(s->icred, 1, s->cid); 729 { 730 krb5_enctype etype = 0; 731 int kvno = 0; 732 Ticket t; 733 size_t len; 734 735 ret = decode_Ticket(creds->ticket.data, 736 creds->ticket.length, &t, &len); 737 if (ret == 0) { 738 if(t.enc_part.kvno) 739 kvno = *t.enc_part.kvno; 740 741 etype = t.enc_part.etype; 742 743 free_Ticket(&t); 744 } 745 746 sqlite3_bind_int(s->icred, 2, kvno); 747 sqlite3_bind_int(s->icred, 3, etype); 748 749 } 750 751 sqlite3_bind_blob(s->icred, 4, data.data, data.length, free_data); 752 sqlite3_bind_int(s->icred, 5, time(NULL)); 753 754 ret = exec_stmt(context, s->db, "BEGIN IMMEDIATE TRANSACTION", KRB5_CC_IO); 755 if (ret) return ret; 756 757 do { 758 ret = sqlite3_step(s->icred); 759 } while (ret == SQLITE_ROW); 760 sqlite3_reset(s->icred); 761 if (ret != SQLITE_DONE) { 762 ret = KRB5_CC_IO; 763 krb5_set_error_message(context, ret, 764 N_("Failed to add credential: %s", ""), 765 sqlite3_errmsg(s->db)); 766 goto rollback; 767 } 768 769 credid = sqlite3_last_insert_rowid(s->db); 770 771 { 772 bind_principal(context, s->db, s->iprincipal, 1, creds->server); 773 sqlite3_bind_int(s->iprincipal, 2, 1); 774 sqlite3_bind_int(s->iprincipal, 3, credid); 775 776 do { 777 ret = sqlite3_step(s->iprincipal); 778 } while (ret == SQLITE_ROW); 779 sqlite3_reset(s->iprincipal); 780 if (ret != SQLITE_DONE) { 781 ret = KRB5_CC_IO; 782 krb5_set_error_message(context, ret, 783 N_("Failed to add principal: %s", ""), 784 sqlite3_errmsg(s->db)); 785 goto rollback; 786 } 787 } 788 789 { 790 bind_principal(context, s->db, s->iprincipal, 1, creds->client); 791 sqlite3_bind_int(s->iprincipal, 2, 0); 792 sqlite3_bind_int(s->iprincipal, 3, credid); 793 794 do { 795 ret = sqlite3_step(s->iprincipal); 796 } while (ret == SQLITE_ROW); 797 sqlite3_reset(s->iprincipal); 798 if (ret != SQLITE_DONE) { 799 ret = KRB5_CC_IO; 800 krb5_set_error_message(context, ret, 801 N_("Failed to add principal: %s", ""), 802 sqlite3_errmsg(s->db)); 803 goto rollback; 804 } 805 } 806 807 ret = exec_stmt(context, s->db, "COMMIT", KRB5_CC_IO); 808 if (ret) return ret; 809 810 return 0; 811 812 rollback: 813 exec_stmt(context, s->db, "ROLLBACK", 0); 814 815 return ret; 816 } 817 818 static krb5_error_code KRB5_CALLCONV 819 scc_get_principal(krb5_context context, 820 krb5_ccache id, 821 krb5_principal *principal) 822 { 823 krb5_scache *s = SCACHE(id); 824 krb5_error_code ret; 825 const char *str; 826 827 *principal = NULL; 828 829 ret = make_database(context, s); 830 if (ret) 831 return ret; 832 833 sqlite3_bind_int(s->scache, 1, s->cid); 834 835 if (sqlite3_step(s->scache) != SQLITE_ROW) { 836 sqlite3_reset(s->scache); 837 krb5_set_error_message(context, KRB5_CC_END, 838 N_("No principal for cache SCC:%s:%s", ""), 839 s->name, s->file); 840 return KRB5_CC_END; 841 } 842 843 if (sqlite3_column_type(s->scache, 0) != SQLITE_TEXT) { 844 sqlite3_reset(s->scache); 845 krb5_set_error_message(context, KRB5_CC_END, 846 N_("Principal data of wrong type " 847 "for SCC:%s:%s", ""), 848 s->name, s->file); 849 return KRB5_CC_END; 850 } 851 852 str = (const char *)sqlite3_column_text(s->scache, 0); 853 if (str == NULL) { 854 sqlite3_reset(s->scache); 855 krb5_set_error_message(context, KRB5_CC_END, 856 N_("Principal not set for SCC:%s:%s", ""), 857 s->name, s->file); 858 return KRB5_CC_END; 859 } 860 861 ret = krb5_parse_name(context, str, principal); 862 863 sqlite3_reset(s->scache); 864 865 return ret; 866 } 867 868 struct cred_ctx { 869 char *drop; 870 sqlite3_stmt *stmt; 871 sqlite3_stmt *credstmt; 872 }; 873 874 static krb5_error_code KRB5_CALLCONV 875 scc_get_first (krb5_context context, 876 krb5_ccache id, 877 krb5_cc_cursor *cursor) 878 { 879 krb5_scache *s = SCACHE(id); 880 krb5_error_code ret; 881 struct cred_ctx *ctx; 882 char *str = NULL, *name = NULL; 883 884 *cursor = NULL; 885 886 ctx = calloc(1, sizeof(*ctx)); 887 if (ctx == NULL) { 888 krb5_set_error_message(context, ENOMEM, 889 N_("malloc: out of memory", "")); 890 return ENOMEM; 891 } 892 893 ret = make_database(context, s); 894 if (ret) { 895 free(ctx); 896 return ret; 897 } 898 899 if (s->cid == SCACHE_INVALID_CID) { 900 krb5_set_error_message(context, KRB5_CC_END, 901 N_("Iterating a invalid scache %s", ""), 902 s->name); 903 free(ctx); 904 return KRB5_CC_END; 905 } 906 907 ret = asprintf(&name, "credIteration%luPid%d", 908 (unsigned long)ctx, (int)getpid()); 909 if (ret < 0 || name == NULL) { 910 krb5_set_error_message(context, ENOMEM, 911 N_("malloc: out of memory", "")); 912 free(ctx); 913 return ENOMEM; 914 } 915 916 ret = asprintf(&ctx->drop, "DROP TABLE %s", name); 917 if (ret < 0 || ctx->drop == NULL) { 918 krb5_set_error_message(context, ENOMEM, 919 N_("malloc: out of memory", "")); 920 free(name); 921 free(ctx); 922 return ENOMEM; 923 } 924 925 ret = asprintf(&str, "CREATE TEMPORARY TABLE %s " 926 "AS SELECT oid,created_at FROM credentials WHERE cid = %lu", 927 name, (unsigned long)s->cid); 928 if (ret < 0 || str == NULL) { 929 free(ctx->drop); 930 free(name); 931 free(ctx); 932 return ENOMEM; 933 } 934 935 ret = exec_stmt(context, s->db, str, KRB5_CC_IO); 936 free(str); 937 str = NULL; 938 if (ret) { 939 free(ctx->drop); 940 free(name); 941 free(ctx); 942 return ret; 943 } 944 945 ret = asprintf(&str, "SELECT oid FROM %s ORDER BY created_at", name); 946 if (ret < 0 || str == NULL) { 947 exec_stmt(context, s->db, ctx->drop, 0); 948 free(ctx->drop); 949 free(name); 950 free(ctx); 951 return ret; 952 } 953 954 ret = prepare_stmt(context, s->db, &ctx->stmt, str); 955 free(str); 956 str = NULL; 957 free(name); 958 if (ret) { 959 exec_stmt(context, s->db, ctx->drop, 0); 960 free(ctx->drop); 961 free(ctx); 962 return ret; 963 } 964 965 ret = prepare_stmt(context, s->db, &ctx->credstmt, 966 "SELECT cred FROM credentials WHERE oid = ?"); 967 if (ret) { 968 sqlite3_finalize(ctx->stmt); 969 exec_stmt(context, s->db, ctx->drop, 0); 970 free(ctx->drop); 971 free(ctx); 972 return ret; 973 } 974 975 *cursor = ctx; 976 977 return 0; 978 } 979 980 static krb5_error_code KRB5_CALLCONV 981 scc_get_next (krb5_context context, 982 krb5_ccache id, 983 krb5_cc_cursor *cursor, 984 krb5_creds *creds) 985 { 986 struct cred_ctx *ctx = *cursor; 987 krb5_scache *s = SCACHE(id); 988 krb5_error_code ret; 989 sqlite_uint64 oid; 990 const void *data = NULL; 991 size_t len = 0; 992 993 next: 994 ret = sqlite3_step(ctx->stmt); 995 if (ret == SQLITE_DONE) { 996 krb5_clear_error_message(context); 997 return KRB5_CC_END; 998 } else if (ret != SQLITE_ROW) { 999 krb5_set_error_message(context, KRB5_CC_IO, 1000 N_("scache Database failed: %s", ""), 1001 sqlite3_errmsg(s->db)); 1002 return KRB5_CC_IO; 1003 } 1004 1005 oid = sqlite3_column_int64(ctx->stmt, 0); 1006 1007 /* read cred from credentials table */ 1008 1009 sqlite3_bind_int(ctx->credstmt, 1, oid); 1010 1011 ret = sqlite3_step(ctx->credstmt); 1012 if (ret != SQLITE_ROW) { 1013 sqlite3_reset(ctx->credstmt); 1014 goto next; 1015 } 1016 1017 if (sqlite3_column_type(ctx->credstmt, 0) != SQLITE_BLOB) { 1018 krb5_set_error_message(context, KRB5_CC_END, 1019 N_("credential of wrong type for SCC:%s:%s", ""), 1020 s->name, s->file); 1021 sqlite3_reset(ctx->credstmt); 1022 return KRB5_CC_END; 1023 } 1024 1025 data = sqlite3_column_blob(ctx->credstmt, 0); 1026 len = sqlite3_column_bytes(ctx->credstmt, 0); 1027 1028 ret = decode_creds(context, data, len, creds); 1029 sqlite3_reset(ctx->credstmt); 1030 return ret; 1031 } 1032 1033 static krb5_error_code KRB5_CALLCONV 1034 scc_end_get (krb5_context context, 1035 krb5_ccache id, 1036 krb5_cc_cursor *cursor) 1037 { 1038 struct cred_ctx *ctx = *cursor; 1039 krb5_scache *s = SCACHE(id); 1040 1041 sqlite3_finalize(ctx->stmt); 1042 sqlite3_finalize(ctx->credstmt); 1043 1044 exec_stmt(context, s->db, ctx->drop, 0); 1045 1046 free(ctx->drop); 1047 free(ctx); 1048 1049 return 0; 1050 } 1051 1052 static krb5_error_code KRB5_CALLCONV 1053 scc_remove_cred(krb5_context context, 1054 krb5_ccache id, 1055 krb5_flags which, 1056 krb5_creds *mcreds) 1057 { 1058 krb5_scache *s = SCACHE(id); 1059 krb5_error_code ret; 1060 sqlite3_stmt *stmt; 1061 sqlite_uint64 credid = 0; 1062 const void *data = NULL; 1063 size_t len = 0; 1064 1065 ret = make_database(context, s); 1066 if (ret) 1067 return ret; 1068 1069 ret = prepare_stmt(context, s->db, &stmt, 1070 "SELECT cred,oid FROM credentials " 1071 "WHERE cid = ?"); 1072 if (ret) 1073 return ret; 1074 1075 sqlite3_bind_int(stmt, 1, s->cid); 1076 1077 /* find credential... */ 1078 while (1) { 1079 krb5_creds creds; 1080 1081 ret = sqlite3_step(stmt); 1082 if (ret == SQLITE_DONE) { 1083 ret = 0; 1084 break; 1085 } else if (ret != SQLITE_ROW) { 1086 ret = KRB5_CC_IO; 1087 krb5_set_error_message(context, ret, 1088 N_("scache Database failed: %s", ""), 1089 sqlite3_errmsg(s->db)); 1090 break; 1091 } 1092 1093 if (sqlite3_column_type(stmt, 0) != SQLITE_BLOB) { 1094 ret = KRB5_CC_END; 1095 krb5_set_error_message(context, ret, 1096 N_("Credential of wrong type " 1097 "for SCC:%s:%s", ""), 1098 s->name, s->file); 1099 break; 1100 } 1101 1102 data = sqlite3_column_blob(stmt, 0); 1103 len = sqlite3_column_bytes(stmt, 0); 1104 1105 ret = decode_creds(context, data, len, &creds); 1106 if (ret) 1107 break; 1108 1109 ret = krb5_compare_creds(context, which, mcreds, &creds); 1110 krb5_free_cred_contents(context, &creds); 1111 if (ret) { 1112 credid = sqlite3_column_int64(stmt, 1); 1113 ret = 0; 1114 break; 1115 } 1116 } 1117 1118 sqlite3_finalize(stmt); 1119 1120 if (id) { 1121 ret = prepare_stmt(context, s->db, &stmt, 1122 "DELETE FROM credentials WHERE oid=?"); 1123 if (ret) 1124 return ret; 1125 sqlite3_bind_int(stmt, 1, credid); 1126 1127 do { 1128 ret = sqlite3_step(stmt); 1129 } while (ret == SQLITE_ROW); 1130 sqlite3_finalize(stmt); 1131 if (ret != SQLITE_DONE) { 1132 ret = KRB5_CC_IO; 1133 krb5_set_error_message(context, ret, 1134 N_("failed to delete scache credental", "")); 1135 } else 1136 ret = 0; 1137 } 1138 1139 return ret; 1140 } 1141 1142 static krb5_error_code KRB5_CALLCONV 1143 scc_set_flags(krb5_context context, 1144 krb5_ccache id, 1145 krb5_flags flags) 1146 { 1147 return 0; /* XXX */ 1148 } 1149 1150 struct cache_iter { 1151 char *drop; 1152 sqlite3 *db; 1153 sqlite3_stmt *stmt; 1154 }; 1155 1156 static krb5_error_code KRB5_CALLCONV 1157 scc_get_cache_first(krb5_context context, krb5_cc_cursor *cursor) 1158 { 1159 struct cache_iter *ctx; 1160 krb5_error_code ret; 1161 char *name = NULL, *str = NULL; 1162 1163 *cursor = NULL; 1164 1165 ctx = calloc(1, sizeof(*ctx)); 1166 if (ctx == NULL) { 1167 krb5_set_error_message(context, ENOMEM, 1168 N_("malloc: out of memory", "")); 1169 return ENOMEM; 1170 } 1171 1172 ret = default_db(context, &ctx->db); 1173 if (ctx->db == NULL) { 1174 free(ctx); 1175 return ret; 1176 } 1177 1178 ret = asprintf(&name, "cacheIteration%luPid%d", 1179 (unsigned long)ctx, (int)getpid()); 1180 if (ret < 0 || name == NULL) { 1181 krb5_set_error_message(context, ENOMEM, 1182 N_("malloc: out of memory", "")); 1183 sqlite3_close(ctx->db); 1184 free(ctx); 1185 return ENOMEM; 1186 } 1187 1188 ret = asprintf(&ctx->drop, "DROP TABLE %s", name); 1189 if (ret < 0 || ctx->drop == NULL) { 1190 krb5_set_error_message(context, ENOMEM, 1191 N_("malloc: out of memory", "")); 1192 sqlite3_close(ctx->db); 1193 free(name); 1194 free(ctx); 1195 return ENOMEM; 1196 } 1197 1198 ret = asprintf(&str, "CREATE TEMPORARY TABLE %s AS SELECT name FROM caches", 1199 name); 1200 if (ret < 0 || str == NULL) { 1201 krb5_set_error_message(context, ENOMEM, 1202 N_("malloc: out of memory", "")); 1203 sqlite3_close(ctx->db); 1204 free(name); 1205 free(ctx->drop); 1206 free(ctx); 1207 return ENOMEM; 1208 } 1209 1210 ret = exec_stmt(context, ctx->db, str, KRB5_CC_IO); 1211 free(str); 1212 str = NULL; 1213 if (ret) { 1214 sqlite3_close(ctx->db); 1215 free(name); 1216 free(ctx->drop); 1217 free(ctx); 1218 return ret; 1219 } 1220 1221 ret = asprintf(&str, "SELECT name FROM %s", name); 1222 free(name); 1223 if (ret < 0 || str == NULL) { 1224 exec_stmt(context, ctx->db, ctx->drop, 0); 1225 sqlite3_close(ctx->db); 1226 free(name); 1227 free(ctx->drop); 1228 free(ctx); 1229 return ENOMEM; 1230 } 1231 1232 ret = prepare_stmt(context, ctx->db, &ctx->stmt, str); 1233 free(str); 1234 if (ret) { 1235 exec_stmt(context, ctx->db, ctx->drop, 0); 1236 sqlite3_close(ctx->db); 1237 free(ctx->drop); 1238 free(ctx); 1239 return ret; 1240 } 1241 1242 *cursor = ctx; 1243 1244 return 0; 1245 } 1246 1247 static krb5_error_code KRB5_CALLCONV 1248 scc_get_cache_next(krb5_context context, 1249 krb5_cc_cursor cursor, 1250 krb5_ccache *id) 1251 { 1252 struct cache_iter *ctx = cursor; 1253 krb5_error_code ret; 1254 const char *name; 1255 1256 again: 1257 ret = sqlite3_step(ctx->stmt); 1258 if (ret == SQLITE_DONE) { 1259 krb5_clear_error_message(context); 1260 return KRB5_CC_END; 1261 } else if (ret != SQLITE_ROW) { 1262 krb5_set_error_message(context, KRB5_CC_IO, 1263 N_("Database failed: %s", ""), 1264 sqlite3_errmsg(ctx->db)); 1265 return KRB5_CC_IO; 1266 } 1267 1268 if (sqlite3_column_type(ctx->stmt, 0) != SQLITE_TEXT) 1269 goto again; 1270 1271 name = (const char *)sqlite3_column_text(ctx->stmt, 0); 1272 if (name == NULL) 1273 goto again; 1274 1275 ret = _krb5_cc_allocate(context, &krb5_scc_ops, id); 1276 if (ret) 1277 return ret; 1278 1279 return scc_resolve(context, id, name); 1280 } 1281 1282 static krb5_error_code KRB5_CALLCONV 1283 scc_end_cache_get(krb5_context context, krb5_cc_cursor cursor) 1284 { 1285 struct cache_iter *ctx = cursor; 1286 1287 exec_stmt(context, ctx->db, ctx->drop, 0); 1288 sqlite3_finalize(ctx->stmt); 1289 sqlite3_close(ctx->db); 1290 free(ctx->drop); 1291 free(ctx); 1292 return 0; 1293 } 1294 1295 static krb5_error_code KRB5_CALLCONV 1296 scc_move(krb5_context context, krb5_ccache from, krb5_ccache to) 1297 { 1298 krb5_scache *sfrom = SCACHE(from); 1299 krb5_scache *sto = SCACHE(to); 1300 krb5_error_code ret; 1301 1302 if (strcmp(sfrom->file, sto->file) != 0) { 1303 krb5_set_error_message(context, KRB5_CC_BADNAME, 1304 N_("Can't handle cross database " 1305 "credential move: %s -> %s", ""), 1306 sfrom->file, sto->file); 1307 return KRB5_CC_BADNAME; 1308 } 1309 1310 ret = make_database(context, sfrom); 1311 if (ret) 1312 return ret; 1313 1314 ret = exec_stmt(context, sfrom->db, 1315 "BEGIN IMMEDIATE TRANSACTION", KRB5_CC_IO); 1316 if (ret) return ret; 1317 1318 if (sto->cid != SCACHE_INVALID_CID) { 1319 /* drop old cache entry */ 1320 1321 sqlite3_bind_int(sfrom->dcache, 1, sto->cid); 1322 do { 1323 ret = sqlite3_step(sfrom->dcache); 1324 } while (ret == SQLITE_ROW); 1325 sqlite3_reset(sfrom->dcache); 1326 if (ret != SQLITE_DONE) { 1327 krb5_set_error_message(context, KRB5_CC_IO, 1328 N_("Failed to delete old cache: %d", ""), 1329 (int)ret); 1330 goto rollback; 1331 } 1332 } 1333 1334 sqlite3_bind_text(sfrom->ucachen, 1, sto->name, -1, NULL); 1335 sqlite3_bind_int(sfrom->ucachen, 2, sfrom->cid); 1336 1337 do { 1338 ret = sqlite3_step(sfrom->ucachen); 1339 } while (ret == SQLITE_ROW); 1340 sqlite3_reset(sfrom->ucachen); 1341 if (ret != SQLITE_DONE) { 1342 krb5_set_error_message(context, KRB5_CC_IO, 1343 N_("Failed to update new cache: %d", ""), 1344 (int)ret); 1345 goto rollback; 1346 } 1347 1348 sto->cid = sfrom->cid; 1349 1350 ret = exec_stmt(context, sfrom->db, "COMMIT", KRB5_CC_IO); 1351 if (ret) return ret; 1352 1353 scc_free(sfrom); 1354 1355 return 0; 1356 1357 rollback: 1358 exec_stmt(context, sfrom->db, "ROLLBACK", 0); 1359 scc_free(sfrom); 1360 1361 return KRB5_CC_IO; 1362 } 1363 1364 static krb5_error_code KRB5_CALLCONV 1365 scc_get_default_name(krb5_context context, char **str) 1366 { 1367 krb5_error_code ret; 1368 char *name; 1369 1370 *str = NULL; 1371 1372 ret = get_def_name(context, &name); 1373 if (ret) 1374 return _krb5_expand_default_cc_name(context, KRB5_SCACHE_NAME, str); 1375 1376 ret = asprintf(str, "SCC:%s", name); 1377 free(name); 1378 if (ret < 0 || *str == NULL) { 1379 krb5_set_error_message(context, ENOMEM, 1380 N_("malloc: out of memory", "")); 1381 return ENOMEM; 1382 } 1383 return 0; 1384 } 1385 1386 static krb5_error_code KRB5_CALLCONV 1387 scc_set_default(krb5_context context, krb5_ccache id) 1388 { 1389 krb5_scache *s = SCACHE(id); 1390 krb5_error_code ret; 1391 1392 if (s->cid == SCACHE_INVALID_CID) { 1393 krb5_set_error_message(context, KRB5_CC_IO, 1394 N_("Trying to set a invalid cache " 1395 "as default %s", ""), 1396 s->name); 1397 return KRB5_CC_IO; 1398 } 1399 1400 ret = sqlite3_bind_text(s->umaster, 1, s->name, -1, NULL); 1401 if (ret) { 1402 sqlite3_reset(s->umaster); 1403 krb5_set_error_message(context, KRB5_CC_IO, 1404 N_("Failed to set name of default cache", "")); 1405 return KRB5_CC_IO; 1406 } 1407 1408 do { 1409 ret = sqlite3_step(s->umaster); 1410 } while (ret == SQLITE_ROW); 1411 sqlite3_reset(s->umaster); 1412 if (ret != SQLITE_DONE) { 1413 krb5_set_error_message(context, KRB5_CC_IO, 1414 N_("Failed to update default cache", "")); 1415 return KRB5_CC_IO; 1416 } 1417 1418 return 0; 1419 } 1420 1421 /** 1422 * Variable containing the SCC based credential cache implemention. 1423 * 1424 * @ingroup krb5_ccache 1425 */ 1426 1427 KRB5_LIB_VARIABLE const krb5_cc_ops krb5_scc_ops = { 1428 KRB5_CC_OPS_VERSION, 1429 "SCC", 1430 scc_get_name, 1431 scc_resolve, 1432 scc_gen_new, 1433 scc_initialize, 1434 scc_destroy, 1435 scc_close, 1436 scc_store_cred, 1437 NULL, /* scc_retrieve */ 1438 scc_get_principal, 1439 scc_get_first, 1440 scc_get_next, 1441 scc_end_get, 1442 scc_remove_cred, 1443 scc_set_flags, 1444 NULL, 1445 scc_get_cache_first, 1446 scc_get_cache_next, 1447 scc_end_cache_get, 1448 scc_move, 1449 scc_get_default_name, 1450 scc_set_default 1451 }; 1452 1453 #endif 1454