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