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