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