2 * Copyright (c) 2008 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
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.
17 * 3. Neither the name of the Institute nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 #include "krb5_locl.h"
40 typedef struct krb5_scache
{
50 sqlite3_stmt
*iprincipal
;
53 sqlite3_stmt
*ucachen
;
54 sqlite3_stmt
*ucachep
;
57 sqlite3_stmt
*scache_name
;
58 sqlite3_stmt
*umaster
;
62 #define SCACHE(X) ((krb5_scache *)(X)->data.data)
65 * Because we can't control what permissions SQLite3 (if not in-tree) will use,
66 * and we're a library and can't set the umask. We can't even determine the
67 * current umask in a thread-safe way (not easily), and we can't tell if some
68 * other thread might change it. So what we'll do is put the SQLite3-based
69 * ccache file in its own directory so we can create that directory with
70 * mkdir(2) and the correct permissions.
73 #define SCACHE_DEF_NAME "Default-cache"
74 #define KRB5_SCACHE_DIR "%{TEMP}/krb5scc_%{uid}"
75 #define KRB5_SCACHE_DB KRB5_SCACHE_DIR "scc"
76 #define KRB5_SCACHE_NAME "SCC:" KRB5_SCACHE_DB ":" SCACHE_DEF_NAME
78 #define SCACHE_INVALID_CID ((sqlite_uint64)-1)
84 #define SQL_CMASTER "" \
85 "CREATE TABLE master (" \
86 "oid INTEGER PRIMARY KEY," \
87 "version INTEGER NOT NULL," \
88 "defaultcache TEXT NOT NULL" \
91 #define SQL_SETUP_MASTER \
92 "INSERT INTO master (version,defaultcache) VALUES(2, \"" SCACHE_DEF_NAME "\")"
93 #define SQL_UMASTER "UPDATE master SET defaultcache=? WHERE version=2"
95 #define SQL_CCACHE "" \
96 "CREATE TABLE caches (" \
97 "oid INTEGER PRIMARY KEY," \
99 "name TEXT NOT NULL" \
102 #define SQL_TCACHE "" \
103 "CREATE TRIGGER CacheDropCreds AFTER DELETE ON caches " \
104 "FOR EACH ROW BEGIN " \
105 "DELETE FROM credentials WHERE cid=old.oid;" \
108 #define SQL_ICACHE "INSERT INTO caches (name) VALUES(?)"
109 #define SQL_UCACHE_NAME "UPDATE caches SET name=? WHERE OID=?"
110 #define SQL_UCACHE_PRINCIPAL "UPDATE caches SET principal=? WHERE OID=?"
111 #define SQL_DCACHE "DELETE FROM caches WHERE OID=?"
112 #define SQL_SCACHE "SELECT principal,name FROM caches WHERE OID=?"
113 #define SQL_SCACHE_NAME "SELECT oid FROM caches WHERE NAME=? OR " \
114 "(PRINCIPAL IS NOT NULL AND PRINCIPAL=?)"
116 #define SQL_CCREDS "" \
117 "CREATE TABLE credentials (" \
118 "oid INTEGER PRIMARY KEY," \
119 "cid INTEGER NOT NULL," \
120 "kvno INTEGER NOT NULL," \
121 "etype INTEGER NOT NULL," \
122 "created_at INTEGER NOT NULL," \
123 "cred BLOB NOT NULL" \
126 #define SQL_TCRED "" \
127 "CREATE TRIGGER credDropPrincipal AFTER DELETE ON credentials " \
128 "FOR EACH ROW BEGIN " \
129 "DELETE FROM principals WHERE credential_id=old.oid;" \
132 #define SQL_ICRED "INSERT INTO credentials (cid, kvno, etype, cred, created_at) VALUES (?,?,?,?,?)"
133 #define SQL_DCRED "DELETE FROM credentials WHERE cid=?"
135 #define SQL_CPRINCIPALS "" \
136 "CREATE TABLE principals (" \
137 "oid INTEGER PRIMARY KEY," \
138 "principal TEXT NOT NULL," \
139 "type INTEGER NOT NULL," \
140 "credential_id INTEGER NOT NULL" \
143 #define SQL_IPRINCIPAL "INSERT INTO principals (principal, type, credential_id) VALUES (?,?,?)"
150 free_data(void *data
)
162 scc_free(krb5_scache
*s
)
174 sqlite3_finalize(s
->icred
);
176 sqlite3_finalize(s
->dcred
);
178 sqlite3_finalize(s
->iprincipal
);
180 sqlite3_finalize(s
->icache
);
182 sqlite3_finalize(s
->ucachen
);
184 sqlite3_finalize(s
->ucachep
);
186 sqlite3_finalize(s
->dcache
);
188 sqlite3_finalize(s
->scache
);
190 sqlite3_finalize(s
->scache_name
);
192 sqlite3_finalize(s
->umaster
);
195 sqlite3_close(s
->db
);
201 trace(void* ptr
, const char * str
)
203 printf("SQL: %s\n", str
);
207 static krb5_error_code
208 prepare_stmt(krb5_context context
, sqlite3
*db
,
209 sqlite3_stmt
**stmt
, const char *str
)
213 ret
= sqlite3_prepare_v2(db
, str
, -1, stmt
, NULL
);
214 if (ret
!= SQLITE_OK
) {
215 krb5_set_error_message(context
, ENOENT
,
216 N_("Failed to prepare stmt %s: %s", ""),
217 str
, sqlite3_errmsg(db
));
223 static krb5_error_code
224 exec_stmt(krb5_context context
, sqlite3
*db
, const char *str
,
225 krb5_error_code code
)
229 ret
= sqlite3_exec(db
, str
, NULL
, NULL
, NULL
);
230 if (ret
!= SQLITE_OK
&& code
) {
231 krb5_set_error_message(context
, code
,
232 N_("scache execute %s: %s", ""), str
,
239 /* See block comment at the top of this file */
240 static krb5_error_code
241 make_dir(krb5_context context
, const char *name
)
243 krb5_error_code ret
= 0;
246 /* We really need a dirname() in roken; lib/krb5/fcache.c has one */
247 if ((s
= strdup(name
)) == NULL
)
248 return krb5_enomem(context
);
249 for (p
= s
+ strlen(s
); p
> s
; p
--) {
251 if (*p
!= '/' && *p
!= '\\')
261 /* If p == s then DB in current directory -- nothing we can do */
262 if (p
> s
&& mkdir(s
, 0700) == -1)
266 /* If we created it, we're good, else there's nothing we can do */
270 krb5_set_error_message(context
, ret
,
271 N_("Error making directory for scache file %s", ""),
276 static krb5_error_code
277 default_db(krb5_context context
, const char *name
, sqlite3
**db
, char **file
)
279 krb5_error_code ret
= 0;
287 if ((name
= krb5_cc_default_name(context
))) {
288 if (strncmp(name
, "SCC:", sizeof("SCC:") - 1) == 0)
289 name
+= sizeof("SCC:") - 1;
292 ret
= _krb5_expand_default_cc_name(context
, KRB5_SCACHE_DB
, &s
);
299 if (strncmp(name
, "SCC:", sizeof("SCC:") - 1) == 0)
300 name
+= sizeof("SCC:") - 1;
302 if ((f
= strdup(name
)) == NULL
) {
304 return krb5_enomem(context
);
308 /* Strip off any residue from default name */
310 if (f
[0] && f
[1] == ':' && (s
= strrchr(f
, ':')) != &f
[1])
313 if ((s
= strrchr(f
, ':')))
317 ret
= make_dir(context
, f
);
321 sret
= sqlite3_open_v2(f
, db
, SQLITE_OPEN_READWRITE
, NULL
);
322 if (sret
!= SQLITE_OK
) {
324 krb5_set_error_message(context
, ENOENT
,
325 N_("Error opening scache file %s: %s (%d)", ""),
326 f
, sqlite3_errmsg(*db
), sret
);
330 krb5_set_error_message(context
, ENOENT
,
331 N_("Error opening scache file %s: %s (%d)", ""),
332 f
, sqlite3_errstr(sret
), sret
);
340 * Just in case we're using an out-of-tree SQLite3. See block comment at
341 * the top of this file, near KRB5_SCACHE_DIR's definition.
343 (void) chmod(f
, 0600);
352 sqlite3_trace(*db
, trace
, NULL
);
358 static krb5_error_code
359 get_def_name(krb5_context context
, char *filein
, char **str
, char **file
)
366 ret
= default_db(context
, filein
, &db
, file
);
370 ret
= prepare_stmt(context
, db
, &stmt
, "SELECT defaultcache FROM master");
376 ret
= sqlite3_step(stmt
);
377 if (ret
!= SQLITE_ROW
)
380 if (sqlite3_column_type(stmt
, 0) != SQLITE_TEXT
)
383 name
= (const char *)sqlite3_column_text(stmt
, 0);
391 sqlite3_finalize(stmt
);
395 sqlite3_finalize(stmt
);
397 krb5_clear_error_message(context
);
403 static krb5_scache
* KRB5_CALLCONV
404 scc_alloc(krb5_context context
,
409 krb5_error_code ret
= 0;
418 s
->cid
= SCACHE_INVALID_CID
;
420 if (name
&& *name
&& sub
&& *sub
) {
421 if ((s
->sub
= strdup(sub
)) == NULL
||
422 (s
->file
= strdup(name
)) == NULL
) {
425 (void) krb5_enomem(context
);
434 name
= krb5_cc_default_name(context
);
436 ret
= _krb5_expand_default_cc_name(context
, KRB5_SCACHE_DB
,
445 if (strncmp(name
, "SCC:", sizeof("SCC:") - 1) == 0)
446 name
+= sizeof("SCC:") - 1;
448 if ((s
->file
= strdup(name
)) == NULL
) {
449 (void) krb5_enomem(context
);
455 if ((subsidiary
= strrchr(s
->file
, ':'))) {
457 if (subsidiary
== s
->file
+ 1)
461 *(subsidiary
++) = '\0';
465 ret
= asprintf(&s
->sub
, "unique-%p", s
) < 0 || s
->sub
== NULL
?
466 krb5_enomem(context
) : 0;
467 } else if (subsidiary
== NULL
|| *subsidiary
== '\0') {
468 ret
= get_def_name(context
, s
->file
, &s
->sub
, NULL
);
470 if ((s
->sub
= strdup(SCACHE_DEF_NAME
)) == NULL
)
471 ret
= krb5_enomem(context
);
475 } else if ((s
->sub
= strdup(subsidiary
)) == NULL
) {
476 ret
= krb5_enomem(context
);
480 if (ret
== 0 && s
->file
&& s
->sub
&&
481 (asprintf(&s
->name
, "%s:%s", s
->file
, s
->sub
) < 0 || s
->name
== NULL
))
482 ret
= krb5_enomem(context
);
483 if (ret
|| s
->file
== NULL
|| s
->sub
== NULL
|| s
->name
== NULL
) {
491 static krb5_error_code
492 open_database(krb5_context context
, krb5_scache
*s
, int flags
)
499 if (!(flags
& SQLITE_OPEN_CREATE
) && stat(s
->file
, &st
) == 0 &&
503 ret
= make_dir(context
, s
->file
);
506 sret
= sqlite3_open_v2(s
->file
, &s
->db
, SQLITE_OPEN_READWRITE
|flags
, NULL
);
507 if (sret
!= SQLITE_OK
) {
509 krb5_set_error_message(context
, ENOENT
,
510 N_("Error opening scache file %s: %s (%d)", ""),
511 s
->file
, sqlite3_errmsg(s
->db
), sret
);
512 sqlite3_close(s
->db
);
515 krb5_set_error_message(context
, ENOENT
,
516 N_("Error opening scache file %s: %s (%d)", ""),
517 s
->file
, sqlite3_errstr(sret
), sret
);
523 static krb5_error_code
524 create_cache(krb5_context context
, krb5_scache
*s
)
528 sqlite3_bind_text(s
->icache
, 1, s
->sub
, -1, NULL
);
530 ret
= sqlite3_step(s
->icache
);
531 } while (ret
== SQLITE_ROW
);
532 if (ret
!= SQLITE_DONE
) {
533 krb5_set_error_message(context
, KRB5_CC_IO
,
534 N_("Failed to add scache: %d", ""), ret
);
537 sqlite3_reset(s
->icache
);
539 s
->cid
= sqlite3_last_insert_rowid(s
->db
);
544 static krb5_error_code
545 make_database(krb5_context context
, krb5_scache
*s
)
547 int created_file
= 0;
553 ret
= open_database(context
, s
, 0);
555 ret
= open_database(context
, s
, SQLITE_OPEN_CREATE
);
560 ret
= exec_stmt(context
, s
->db
, SQL_CMASTER
, KRB5_CC_IO
);
562 ret
= exec_stmt(context
, s
->db
, SQL_CCACHE
, KRB5_CC_IO
);
564 ret
= exec_stmt(context
, s
->db
, SQL_CCREDS
, KRB5_CC_IO
);
566 ret
= exec_stmt(context
, s
->db
, SQL_CPRINCIPALS
, KRB5_CC_IO
);
568 ret
= exec_stmt(context
, s
->db
, SQL_SETUP_MASTER
, KRB5_CC_IO
);
571 ret
= exec_stmt(context
, s
->db
, SQL_TCACHE
, KRB5_CC_IO
);
573 ret
= exec_stmt(context
, s
->db
, SQL_TCRED
, KRB5_CC_IO
);
578 sqlite3_trace(s
->db
, trace
, NULL
);
581 ret
= prepare_stmt(context
, s
->db
, &s
->icred
, SQL_ICRED
);
583 ret
= prepare_stmt(context
, s
->db
, &s
->dcred
, SQL_DCRED
);
585 ret
= prepare_stmt(context
, s
->db
, &s
->iprincipal
, SQL_IPRINCIPAL
);
587 ret
= prepare_stmt(context
, s
->db
, &s
->icache
, SQL_ICACHE
);
589 ret
= prepare_stmt(context
, s
->db
, &s
->ucachen
, SQL_UCACHE_NAME
);
591 ret
= prepare_stmt(context
, s
->db
, &s
->ucachep
, SQL_UCACHE_PRINCIPAL
);
593 ret
= prepare_stmt(context
, s
->db
, &s
->dcache
, SQL_DCACHE
);
595 ret
= prepare_stmt(context
, s
->db
, &s
->scache
, SQL_SCACHE
);
597 ret
= prepare_stmt(context
, s
->db
, &s
->scache_name
, SQL_SCACHE_NAME
);
599 ret
= prepare_stmt(context
, s
->db
, &s
->umaster
, SQL_UMASTER
);
604 * Just in case we're using an out-of-tree SQLite3. See block comment at
605 * the top of this file, near KRB5_SCACHE_DIR's definition.
607 (void) chmod(s
->file
, 0600);
614 sqlite3_close(s
->db
);
621 static krb5_error_code
622 bind_principal(krb5_context context
,
626 krb5_const_principal principal
)
631 ret
= krb5_unparse_name(context
, principal
, &str
);
635 ret
= sqlite3_bind_text(stmt
, col
, str
, -1, free_krb5
);
636 if (ret
!= SQLITE_OK
) {
638 krb5_set_error_message(context
, ENOMEM
,
639 N_("scache bind principal: %s", ""),
650 static krb5_error_code KRB5_CALLCONV
651 scc_get_name_2(krb5_context context
,
658 *name
= SCACHE(id
)->name
;
660 *file
= SCACHE(id
)->file
;
662 *sub
= SCACHE(id
)->sub
;
666 static krb5_error_code KRB5_CALLCONV
667 scc_resolve_2(krb5_context context
,
675 s
= scc_alloc(context
, res
, sub
, 0);
677 krb5_set_error_message(context
, KRB5_CC_NOMEM
,
678 N_("malloc: out of memory", ""));
679 return KRB5_CC_NOMEM
;
682 ret
= make_database(context
, s
);
688 ret
= sqlite3_bind_text(s
->scache_name
, 1, s
->sub
, -1, NULL
);
689 if (ret
!= SQLITE_OK
) {
690 krb5_set_error_message(context
, ENOMEM
,
691 "bind principal: %s", sqlite3_errmsg(s
->db
));
696 if (sqlite3_step(s
->scache_name
) == SQLITE_ROW
) {
698 if (sqlite3_column_type(s
->scache_name
, 0) != SQLITE_INTEGER
) {
699 sqlite3_reset(s
->scache_name
);
700 krb5_set_error_message(context
, KRB5_CC_END
,
701 N_("Cache name of wrong type "
702 "for scache %s", ""),
708 s
->cid
= sqlite3_column_int(s
->scache_name
, 0);
710 s
->cid
= SCACHE_INVALID_CID
;
712 sqlite3_reset(s
->scache_name
);
714 (*id
)->data
.data
= s
;
715 (*id
)->data
.length
= sizeof(*s
);
720 static krb5_error_code KRB5_CALLCONV
721 scc_gen_new(krb5_context context
, krb5_ccache
*id
)
725 s
= scc_alloc(context
, NULL
, NULL
, 1);
728 krb5_set_error_message(context
, KRB5_CC_NOMEM
,
729 N_("malloc: out of memory", ""));
730 return KRB5_CC_NOMEM
;
733 (*id
)->data
.data
= s
;
734 (*id
)->data
.length
= sizeof(*s
);
739 static krb5_error_code KRB5_CALLCONV
740 scc_initialize(krb5_context context
,
742 krb5_principal principal
)
744 krb5_scache
*s
= SCACHE(id
);
747 ret
= make_database(context
, s
);
751 ret
= exec_stmt(context
, s
->db
, "BEGIN IMMEDIATE TRANSACTION", KRB5_CC_IO
);
754 if (s
->cid
== SCACHE_INVALID_CID
) {
755 ret
= create_cache(context
, s
);
759 sqlite3_bind_int(s
->dcred
, 1, s
->cid
);
761 ret
= sqlite3_step(s
->dcred
);
762 } while (ret
== SQLITE_ROW
);
763 sqlite3_reset(s
->dcred
);
764 if (ret
!= SQLITE_DONE
) {
766 krb5_set_error_message(context
, ret
,
767 N_("Failed to delete old "
768 "credentials: %s", ""),
769 sqlite3_errmsg(s
->db
));
774 ret
= bind_principal(context
, s
->db
, s
->ucachep
, 1, principal
);
777 sqlite3_bind_int(s
->ucachep
, 2, s
->cid
);
780 ret
= sqlite3_step(s
->ucachep
);
781 } while (ret
== SQLITE_ROW
);
782 sqlite3_reset(s
->ucachep
);
783 if (ret
!= SQLITE_DONE
) {
785 krb5_set_error_message(context
, ret
,
786 N_("Failed to bind principal to cache %s", ""),
787 sqlite3_errmsg(s
->db
));
791 ret
= exec_stmt(context
, s
->db
, "COMMIT", KRB5_CC_IO
);
797 exec_stmt(context
, s
->db
, "ROLLBACK", 0);
803 static krb5_error_code KRB5_CALLCONV
804 scc_close(krb5_context context
,
807 scc_free(SCACHE(id
));
811 static krb5_error_code KRB5_CALLCONV
812 scc_destroy(krb5_context context
,
815 krb5_scache
*s
= SCACHE(id
);
818 if (s
->cid
== SCACHE_INVALID_CID
)
821 sqlite3_bind_int(s
->dcache
, 1, s
->cid
);
823 ret
= sqlite3_step(s
->dcache
);
824 } while (ret
== SQLITE_ROW
);
825 sqlite3_reset(s
->dcache
);
826 if (ret
!= SQLITE_DONE
) {
827 krb5_set_error_message(context
, KRB5_CC_IO
,
828 N_("Failed to destroy cache %s: %s", ""),
829 s
->name
, sqlite3_errmsg(s
->db
));
835 static krb5_error_code
836 encode_creds(krb5_context context
, krb5_creds
*creds
, krb5_data
*data
)
841 krb5_data_zero(data
);
842 sp
= krb5_storage_emem();
844 return krb5_enomem(context
);
846 ret
= krb5_store_creds(sp
, creds
);
848 krb5_set_error_message(context
, ret
,
849 N_("Failed to store credential in scache", ""));
850 krb5_storage_free(sp
);
854 ret
= krb5_storage_to_data(sp
, data
);
855 krb5_storage_free(sp
);
857 krb5_set_error_message(context
, ret
,
858 N_("Failed to encode credential in scache", ""));
862 static krb5_error_code
863 decode_creds(krb5_context context
, const void *data
, size_t length
,
869 sp
= krb5_storage_from_readonly_mem(data
, length
);
871 return krb5_enomem(context
);
873 ret
= krb5_ret_creds(sp
, creds
);
874 krb5_storage_free(sp
);
876 krb5_set_error_message(context
, ret
,
877 N_("Failed to read credential in scache", ""));
884 static krb5_error_code KRB5_CALLCONV
885 scc_store_cred(krb5_context context
,
889 sqlite_uint64 credid
;
890 krb5_scache
*s
= SCACHE(id
);
894 ret
= make_database(context
, s
);
898 ret
= encode_creds(context
, creds
, &data
);
902 sqlite3_bind_int(s
->icred
, 1, s
->cid
);
904 krb5_enctype etype
= 0;
909 ret
= decode_Ticket(creds
->ticket
.data
,
910 creds
->ticket
.length
, &t
, &len
);
913 kvno
= *t
.enc_part
.kvno
;
915 etype
= t
.enc_part
.etype
;
920 sqlite3_bind_int(s
->icred
, 2, kvno
);
921 sqlite3_bind_int(s
->icred
, 3, etype
);
925 sqlite3_bind_blob(s
->icred
, 4, data
.data
, data
.length
, free_data
);
926 sqlite3_bind_int(s
->icred
, 5, time(NULL
));
928 ret
= exec_stmt(context
, s
->db
, "BEGIN IMMEDIATE TRANSACTION", KRB5_CC_IO
);
932 ret
= sqlite3_step(s
->icred
);
933 } while (ret
== SQLITE_ROW
);
934 sqlite3_reset(s
->icred
);
935 if (ret
!= SQLITE_DONE
) {
937 krb5_set_error_message(context
, ret
,
938 N_("Failed to add credential: %s", ""),
939 sqlite3_errmsg(s
->db
));
943 credid
= sqlite3_last_insert_rowid(s
->db
);
946 bind_principal(context
, s
->db
, s
->iprincipal
, 1, creds
->server
);
947 sqlite3_bind_int(s
->iprincipal
, 2, 1);
948 sqlite3_bind_int(s
->iprincipal
, 3, credid
);
951 ret
= sqlite3_step(s
->iprincipal
);
952 } while (ret
== SQLITE_ROW
);
953 sqlite3_reset(s
->iprincipal
);
954 if (ret
!= SQLITE_DONE
) {
956 krb5_set_error_message(context
, ret
,
957 N_("Failed to add principal: %s", ""),
958 sqlite3_errmsg(s
->db
));
964 bind_principal(context
, s
->db
, s
->iprincipal
, 1, creds
->client
);
965 sqlite3_bind_int(s
->iprincipal
, 2, 0);
966 sqlite3_bind_int(s
->iprincipal
, 3, credid
);
969 ret
= sqlite3_step(s
->iprincipal
);
970 } while (ret
== SQLITE_ROW
);
971 sqlite3_reset(s
->iprincipal
);
972 if (ret
!= SQLITE_DONE
) {
974 krb5_set_error_message(context
, ret
,
975 N_("Failed to add principal: %s", ""),
976 sqlite3_errmsg(s
->db
));
981 ret
= exec_stmt(context
, s
->db
, "COMMIT", KRB5_CC_IO
);
987 exec_stmt(context
, s
->db
, "ROLLBACK", 0);
992 static krb5_error_code KRB5_CALLCONV
993 scc_get_principal(krb5_context context
,
995 krb5_principal
*principal
)
997 krb5_scache
*s
= SCACHE(id
);
1003 ret
= make_database(context
, s
);
1007 sqlite3_bind_int(s
->scache
, 1, s
->cid
);
1009 if (sqlite3_step(s
->scache
) != SQLITE_ROW
) {
1010 sqlite3_reset(s
->scache
);
1011 krb5_set_error_message(context
, KRB5_CC_END
,
1012 N_("No principal for cache SCC:%s", ""),
1017 if (sqlite3_column_type(s
->scache
, 0) != SQLITE_TEXT
) {
1018 sqlite3_reset(s
->scache
);
1019 krb5_set_error_message(context
, KRB5_CC_END
,
1020 N_("Principal data of wrong type "
1026 str
= (const char *)sqlite3_column_text(s
->scache
, 0);
1028 sqlite3_reset(s
->scache
);
1029 krb5_set_error_message(context
, KRB5_CC_END
,
1030 N_("Principal not set for SCC:%s", ""),
1035 ret
= krb5_parse_name(context
, str
, principal
);
1037 sqlite3_reset(s
->scache
);
1045 sqlite3_stmt
*credstmt
;
1048 static krb5_error_code KRB5_CALLCONV
1049 scc_get_first (krb5_context context
,
1051 krb5_cc_cursor
*cursor
)
1053 krb5_scache
*s
= SCACHE(id
);
1054 krb5_error_code ret
;
1055 struct cred_ctx
*ctx
;
1056 char *str
= NULL
, *name
= NULL
;
1060 ctx
= calloc(1, sizeof(*ctx
));
1062 return krb5_enomem(context
);
1064 ret
= make_database(context
, s
);
1070 if (s
->cid
== SCACHE_INVALID_CID
) {
1071 krb5_set_error_message(context
, KRB5_CC_END
,
1072 N_("Iterating a invalid scache %s", ""),
1078 ret
= asprintf(&name
, "credIteration%pPid%d",
1079 ctx
, (int)getpid());
1080 if (ret
< 0 || name
== NULL
) {
1082 return krb5_enomem(context
);
1085 ret
= asprintf(&ctx
->drop
, "DROP TABLE %s", name
);
1086 if (ret
< 0 || ctx
->drop
== NULL
) {
1089 return krb5_enomem(context
);
1092 ret
= asprintf(&str
, "CREATE TEMPORARY TABLE %s "
1093 "AS SELECT oid,created_at FROM credentials WHERE cid = %lu",
1094 name
, (unsigned long)s
->cid
);
1095 if (ret
< 0 || str
== NULL
) {
1099 return krb5_enomem(context
);
1102 ret
= exec_stmt(context
, s
->db
, str
, KRB5_CC_IO
);
1112 ret
= asprintf(&str
, "SELECT oid FROM %s ORDER BY created_at", name
);
1113 if (ret
< 0 || str
== NULL
) {
1114 exec_stmt(context
, s
->db
, ctx
->drop
, 0);
1121 ret
= prepare_stmt(context
, s
->db
, &ctx
->stmt
, str
);
1126 exec_stmt(context
, s
->db
, ctx
->drop
, 0);
1132 ret
= prepare_stmt(context
, s
->db
, &ctx
->credstmt
,
1133 "SELECT cred FROM credentials WHERE oid = ?");
1135 sqlite3_finalize(ctx
->stmt
);
1136 exec_stmt(context
, s
->db
, ctx
->drop
, 0);
1147 static krb5_error_code KRB5_CALLCONV
1148 scc_get_next (krb5_context context
,
1150 krb5_cc_cursor
*cursor
,
1153 struct cred_ctx
*ctx
= *cursor
;
1154 krb5_scache
*s
= SCACHE(id
);
1155 krb5_error_code ret
;
1157 const void *data
= NULL
;
1161 ret
= sqlite3_step(ctx
->stmt
);
1162 if (ret
== SQLITE_DONE
) {
1163 krb5_clear_error_message(context
);
1165 } else if (ret
!= SQLITE_ROW
) {
1166 krb5_set_error_message(context
, KRB5_CC_IO
,
1167 N_("scache Database failed: %s", ""),
1168 sqlite3_errmsg(s
->db
));
1172 oid
= sqlite3_column_int64(ctx
->stmt
, 0);
1174 /* read cred from credentials table */
1176 sqlite3_bind_int(ctx
->credstmt
, 1, oid
);
1178 ret
= sqlite3_step(ctx
->credstmt
);
1179 if (ret
!= SQLITE_ROW
) {
1180 sqlite3_reset(ctx
->credstmt
);
1184 if (sqlite3_column_type(ctx
->credstmt
, 0) != SQLITE_BLOB
) {
1185 krb5_set_error_message(context
, KRB5_CC_END
,
1186 N_("credential of wrong type for SCC:%s", ""),
1188 sqlite3_reset(ctx
->credstmt
);
1192 data
= sqlite3_column_blob(ctx
->credstmt
, 0);
1193 len
= sqlite3_column_bytes(ctx
->credstmt
, 0);
1195 ret
= decode_creds(context
, data
, len
, creds
);
1196 sqlite3_reset(ctx
->credstmt
);
1200 static krb5_error_code KRB5_CALLCONV
1201 scc_end_get (krb5_context context
,
1203 krb5_cc_cursor
*cursor
)
1205 struct cred_ctx
*ctx
= *cursor
;
1206 krb5_scache
*s
= SCACHE(id
);
1208 sqlite3_finalize(ctx
->stmt
);
1209 sqlite3_finalize(ctx
->credstmt
);
1211 exec_stmt(context
, s
->db
, ctx
->drop
, 0);
1219 static krb5_error_code KRB5_CALLCONV
1220 scc_remove_cred(krb5_context context
,
1225 krb5_scache
*s
= SCACHE(id
);
1226 krb5_error_code ret
;
1228 sqlite_uint64 credid
= 0;
1229 const void *data
= NULL
;
1232 ret
= make_database(context
, s
);
1236 ret
= prepare_stmt(context
, s
->db
, &stmt
,
1237 "SELECT cred,oid FROM credentials "
1242 sqlite3_bind_int(stmt
, 1, s
->cid
);
1244 /* find credential... */
1248 ret
= sqlite3_step(stmt
);
1249 if (ret
== SQLITE_DONE
) {
1252 } else if (ret
!= SQLITE_ROW
) {
1254 krb5_set_error_message(context
, ret
,
1255 N_("scache Database failed: %s", ""),
1256 sqlite3_errmsg(s
->db
));
1260 if (sqlite3_column_type(stmt
, 0) != SQLITE_BLOB
) {
1262 krb5_set_error_message(context
, ret
,
1263 N_("Credential of wrong type "
1269 data
= sqlite3_column_blob(stmt
, 0);
1270 len
= sqlite3_column_bytes(stmt
, 0);
1272 ret
= decode_creds(context
, data
, len
, &creds
);
1276 ret
= krb5_compare_creds(context
, which
, mcreds
, &creds
);
1277 krb5_free_cred_contents(context
, &creds
);
1279 credid
= sqlite3_column_int64(stmt
, 1);
1285 sqlite3_finalize(stmt
);
1288 ret
= prepare_stmt(context
, s
->db
, &stmt
,
1289 "DELETE FROM credentials WHERE oid=?");
1292 sqlite3_bind_int(stmt
, 1, credid
);
1295 ret
= sqlite3_step(stmt
);
1296 } while (ret
== SQLITE_ROW
);
1297 sqlite3_finalize(stmt
);
1298 if (ret
!= SQLITE_DONE
) {
1300 krb5_set_error_message(context
, ret
,
1301 N_("failed to delete scache credental", ""));
1309 static krb5_error_code KRB5_CALLCONV
1310 scc_set_flags(krb5_context context
,
1324 static krb5_error_code KRB5_CALLCONV
1325 scc_get_cache_first(krb5_context context
, krb5_cc_cursor
*cursor
)
1327 struct cache_iter
*ctx
;
1328 krb5_error_code ret
;
1329 char *name
= NULL
, *str
= NULL
;
1333 ctx
= calloc(1, sizeof(*ctx
));
1335 return krb5_enomem(context
);
1337 ret
= default_db(context
, NULL
, &ctx
->db
, &ctx
->file
);
1343 ret
= asprintf(&name
, "cacheIteration%pPid%d",
1344 ctx
, (int)getpid());
1345 if (ret
< 0 || name
== NULL
) {
1346 sqlite3_close(ctx
->db
);
1348 return krb5_enomem(context
);
1351 ret
= asprintf(&ctx
->drop
, "DROP TABLE %s", name
);
1352 if (ret
< 0 || ctx
->drop
== NULL
) {
1353 sqlite3_close(ctx
->db
);
1356 return krb5_enomem(context
);
1359 ret
= asprintf(&str
, "CREATE TEMPORARY TABLE %s AS SELECT name FROM caches",
1361 if (ret
< 0 || str
== NULL
) {
1362 sqlite3_close(ctx
->db
);
1366 return krb5_enomem(context
);
1369 ret
= exec_stmt(context
, ctx
->db
, str
, KRB5_CC_IO
);
1373 sqlite3_close(ctx
->db
);
1380 ret
= asprintf(&str
, "SELECT name FROM %s", name
);
1381 if (ret
< 0 || str
== NULL
) {
1382 exec_stmt(context
, ctx
->db
, ctx
->drop
, 0);
1383 sqlite3_close(ctx
->db
);
1387 return krb5_enomem(context
);
1391 ret
= prepare_stmt(context
, ctx
->db
, &ctx
->stmt
, str
);
1394 exec_stmt(context
, ctx
->db
, ctx
->drop
, 0);
1395 sqlite3_close(ctx
->db
);
1406 static krb5_error_code KRB5_CALLCONV
1407 scc_get_cache_next(krb5_context context
,
1408 krb5_cc_cursor cursor
,
1411 struct cache_iter
*ctx
= cursor
;
1412 krb5_error_code ret
;
1416 ret
= sqlite3_step(ctx
->stmt
);
1417 if (ret
== SQLITE_DONE
) {
1418 krb5_clear_error_message(context
);
1420 } else if (ret
!= SQLITE_ROW
) {
1421 krb5_set_error_message(context
, KRB5_CC_IO
,
1422 N_("Database failed: %s", ""),
1423 sqlite3_errmsg(ctx
->db
));
1427 if (sqlite3_column_type(ctx
->stmt
, 0) != SQLITE_TEXT
)
1430 name
= (const char *)sqlite3_column_text(ctx
->stmt
, 0);
1434 ret
= _krb5_cc_allocate(context
, &krb5_scc_ops
, id
);
1436 ret
= scc_resolve_2(context
, id
, ctx
->file
, name
);
1444 static krb5_error_code KRB5_CALLCONV
1445 scc_end_cache_get(krb5_context context
, krb5_cc_cursor cursor
)
1447 struct cache_iter
*ctx
= cursor
;
1449 exec_stmt(context
, ctx
->db
, ctx
->drop
, 0);
1450 sqlite3_finalize(ctx
->stmt
);
1451 sqlite3_close(ctx
->db
);
1458 static krb5_error_code KRB5_CALLCONV
1459 scc_move(krb5_context context
, krb5_ccache from
, krb5_ccache to
)
1461 krb5_scache
*sfrom
= SCACHE(from
);
1462 krb5_scache
*sto
= SCACHE(to
);
1463 krb5_error_code ret
;
1465 if (strcmp(sfrom
->file
, sto
->file
) != 0) {
1466 /* Let upstairs handle the move */
1470 ret
= make_database(context
, sfrom
);
1474 ret
= exec_stmt(context
, sfrom
->db
,
1475 "BEGIN IMMEDIATE TRANSACTION", KRB5_CC_IO
);
1476 if (ret
) return ret
;
1478 if (sto
->cid
!= SCACHE_INVALID_CID
) {
1479 /* drop old cache entry */
1481 sqlite3_bind_int(sfrom
->dcache
, 1, sto
->cid
);
1483 ret
= sqlite3_step(sfrom
->dcache
);
1484 } while (ret
== SQLITE_ROW
);
1485 sqlite3_reset(sfrom
->dcache
);
1486 if (ret
!= SQLITE_DONE
) {
1487 krb5_set_error_message(context
, KRB5_CC_IO
,
1488 N_("Failed to delete old cache: %d", ""),
1494 sqlite3_bind_text(sfrom
->ucachen
, 1, sto
->sub
, -1, NULL
);
1495 sqlite3_bind_int(sfrom
->ucachen
, 2, sfrom
->cid
);
1498 ret
= sqlite3_step(sfrom
->ucachen
);
1499 } while (ret
== SQLITE_ROW
);
1500 sqlite3_reset(sfrom
->ucachen
);
1501 if (ret
!= SQLITE_DONE
) {
1502 krb5_set_error_message(context
, KRB5_CC_IO
,
1503 N_("Failed to update new cache: %d", ""),
1508 sto
->cid
= sfrom
->cid
;
1510 ret
= exec_stmt(context
, sfrom
->db
, "COMMIT", KRB5_CC_IO
);
1511 if (ret
) return ret
;
1513 krb5_cc_close(context
, from
);
1517 exec_stmt(context
, sfrom
->db
, "ROLLBACK", 0);
1521 static krb5_error_code KRB5_CALLCONV
1522 scc_get_default_name(krb5_context context
, char **str
)
1525 return _krb5_expand_default_cc_name(context
, KRB5_SCACHE_NAME
, str
);
1528 static krb5_error_code KRB5_CALLCONV
1529 scc_set_default(krb5_context context
, krb5_ccache id
)
1531 krb5_scache
*s
= SCACHE(id
);
1532 krb5_error_code ret
;
1534 if (s
->cid
== SCACHE_INVALID_CID
) {
1535 krb5_set_error_message(context
, KRB5_CC_IO
,
1536 N_("Trying to set a invalid cache "
1537 "as default %s", ""),
1542 ret
= sqlite3_bind_text(s
->umaster
, 1, s
->sub
, -1, NULL
);
1544 sqlite3_reset(s
->umaster
);
1545 krb5_set_error_message(context
, KRB5_CC_IO
,
1546 N_("Failed to set name of default cache", ""));
1551 ret
= sqlite3_step(s
->umaster
);
1552 } while (ret
== SQLITE_ROW
);
1553 sqlite3_reset(s
->umaster
);
1554 if (ret
!= SQLITE_DONE
) {
1555 krb5_set_error_message(context
, KRB5_CC_IO
,
1556 N_("Failed to update default cache", ""));
1564 * Variable containing the SCC based credential cache implemention.
1566 * @ingroup krb5_ccache
1569 KRB5_LIB_VARIABLE
const krb5_cc_ops krb5_scc_ops
= {
1570 KRB5_CC_OPS_VERSION_5
,
1579 NULL
, /* scc_retrieve */
1587 scc_get_cache_first
,
1591 scc_get_default_name
,