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