Fix some warnings found by Valgrind (helgrind tool).
[pwmd.git] / src / cache.c
blobb3e5f32623a34e0cb294898abf55b8e31fc57221
1 /*
2 Copyright (C) 2006-2021 Ben Kibbey <bjk@luxsci.net>
4 This file is part of pwmd.
6 Pwmd is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License version 2 as
8 published by the Free Software Foundation.
10 Pwmd is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with Pwmd. If not, see <http://www.gnu.org/licenses/>.
18 #ifdef HAVE_CONFIG_H
19 #include <config.h>
20 #endif
22 #include <stdio.h>
23 #ifdef HAVE_UNISTD_H
24 #include <unistd.h>
25 #endif
26 #include <time.h>
27 #include <pthread.h>
28 #include <ctype.h>
29 #include <errno.h>
31 #include "pwmd-error.h"
32 #include <gcrypt.h>
33 #include "mutex.h"
34 #include "cache.h"
35 #include "status.h"
36 #include "mem.h"
37 #include "util-misc.h"
38 #include "util-string.h"
39 #include "agent.h"
40 #include "acl.h"
42 struct plaintext_s
44 xmlDocPtr plaintext;
45 unsigned refcount;
46 char *filename;
47 int modified;
50 static pthread_mutex_t cache_mutex;
51 static struct slist_s *key_cache;
52 static struct slist_s *plaintext_list;
53 static unsigned char *cache_iv;
54 static unsigned char *cache_key;
55 static size_t cache_blocksize;
56 static size_t cache_keysize;
57 static struct agent_s *cache_agent;
58 static int exiting;
60 void log_write (const char *fmt, ...);
62 static gpg_error_t clear_once (file_cache_t * p, int agent, int force);
63 static int remove_entry (const char *);
64 static void free_entry (file_cache_t * p, int agent, int unlock);
66 static file_cache_t *
67 get_entry (const char *filename)
69 int t = slist_length (key_cache);
70 int i;
72 if (!filename)
73 return NULL;
75 for (i = 0; i < t; i++)
77 file_cache_t *p = slist_nth_data (key_cache, i);
79 if (!strcmp (p->filename, filename))
80 return p;
83 return NULL;
86 gpg_error_t
87 cache_lock_mutex (void *ctx, const char *filename, long lock_timeout, int add,
88 long timeout)
90 MUTEX_LOCK (&cache_mutex);
91 gpg_error_t rc = 0;
92 file_cache_t *p = get_entry (filename);
94 pthread_cleanup_push (release_mutex_cb, &cache_mutex);
96 if (p)
98 MUTEX_UNLOCK (&cache_mutex);
99 MUTEX_TRYLOCK (ctx, p->mutex, rc, lock_timeout);
100 if (!rc)
101 p->flags |= CACHE_FLAG_LOCKED;
103 else if (add)
105 rc = cache_add_file (filename, NULL, timeout);
106 if (!rc)
108 p = get_entry (filename);
109 MUTEX_UNLOCK (&cache_mutex);
110 if (p)
112 MUTEX_TRYLOCK (ctx, p->mutex, rc, lock_timeout);
113 if (!rc)
114 p->flags |= CACHE_FLAG_LOCKED;
117 else
119 MUTEX_UNLOCK (&cache_mutex);
122 else
124 MUTEX_UNLOCK (&cache_mutex);
127 pthread_cleanup_pop (0);
128 return !p && !rc ? GPG_ERR_NO_DATA : rc;
131 static int
132 remove_entry (const char *filename)
134 MUTEX_LOCK (&cache_mutex);
135 file_cache_t *p = get_entry (filename);
137 pthread_cleanup_push (release_mutex_cb, &cache_mutex);
138 if (p)
140 /* Keep a refcount because another client may be editing this same new
141 * file. The entry needs to be kept in case the other client SAVE's.
143 p->refcount--;
144 if (!p->refcount)
145 free_entry (p, 0, 1);
148 pthread_cleanup_pop (1);
149 return p ? 1 : 0;
152 static gpg_error_t
153 free_cache_data (file_cache_t *cache, int force)
155 gpg_error_t rc = GPG_ERR_NO_DATA;
156 int i, t;
157 struct client_thread_s *found = NULL;
158 int self = 0;
160 if (!cache->data)
161 return 0;
163 MUTEX_LOCK (&cn_mutex);
164 t = slist_length (cn_thread_list);
166 /* Prevent clearing the cache entry when there are any connected clients
167 * using this cache entry to prevent clearing the plaintext which would cause
168 * cache_plaintext_set() to return GPG_ERR_NO_DATA and prevent CoW commands
169 * from working. */
170 for (i = 0; i < t; i++)
172 struct client_thread_s *thd = slist_nth_data (cn_thread_list, i);
174 if (!thd->cl)
175 continue;
177 if (thd->cl->filename && !strcmp (thd->cl->filename, cache->filename)
178 && !force)
180 cache->defer_clear = 1;
181 MUTEX_UNLOCK (&cn_mutex);
182 return 0;
186 pthread_cleanup_push (release_mutex_cb, &cn_mutex);
187 MUTEX_LOCK (&cache_mutex);
188 pthread_cleanup_push (release_mutex_cb, &cache_mutex);
190 for (i = 0; i < t; i++)
192 struct client_thread_s *thd = slist_nth_data (cn_thread_list, i);
194 if (!thd->cl)
195 continue;
197 self = pthread_equal (pthread_self (), thd->tid);
199 if (thd->cl->filename && !strcmp (thd->cl->filename, cache->filename))
201 if (self)
203 found = thd;
204 continue;
207 /* Continue trying to find a client who has the same file open and
208 * also has a lock. */
209 rc = cache_lock_mutex (thd->cl->ctx, thd->cl->filename, -1, 0, -1);
210 if (!rc)
212 found = thd;
213 break;
218 if (self && (!rc || rc == GPG_ERR_NO_DATA) && found)
219 rc = cache_lock_mutex (found->cl->ctx, found->cl->filename, -1, 0, -1);
221 if (exiting || !rc || rc == GPG_ERR_NO_DATA)
223 cache_free_data_once (cache->data);
224 cache->data = NULL;
225 cache->defer_clear = 0;
226 cache->timeout = (long)-1;
228 if (found)
229 cache_unlock_mutex (found->cl->filename, 0);
231 rc = 0;
234 if (rc)
235 cache->defer_clear = 1;
237 pthread_cleanup_pop (1);
238 pthread_cleanup_pop (1);
239 return rc;
242 gpg_error_t
243 cache_unlock_mutex (const char *filename, int remove)
245 MUTEX_LOCK (&cache_mutex);
246 file_cache_t *p = get_entry (filename);
248 pthread_cleanup_push (release_mutex_cb, &cache_mutex);
250 if (p)
252 p->flags &= ~CACHE_FLAG_LOCKED;
253 if (remove)
254 remove_entry (filename);
255 else
256 MUTEX_UNLOCK (p->mutex);
259 pthread_cleanup_pop (1);
260 return p ? 0 : GPG_ERR_NO_DATA;
263 static gpg_error_t
264 get_keyinfo (const char *grip, char ***r_fields)
266 gpg_error_t rc;
267 char *line;
269 rc = agent_command (cache_agent, &line, NULL, "KEYINFO --data %s", grip);
270 if (rc)
271 return rc;
273 *r_fields = str_split (line, " ", 0);
274 xfree (line);
275 return !(*r_fields) ? GPG_ERR_ENOMEM : rc;
278 gpg_error_t
279 cache_is_shadowed (const char *filename)
281 MUTEX_LOCK (&cache_mutex);
282 file_cache_t *f = get_entry (filename);
283 char **p;
284 char **fields = NULL;
285 gpg_error_t rc = GPG_ERR_NO_DATA, trc;
287 if (!f)
288 return GPG_ERR_NOT_FOUND;
290 for (p = f->grip; p && *p; p++)
292 trc = get_keyinfo (*p, &fields);
293 if (!trc && *fields[1] == 'T')
295 rc = 0;
296 break;
298 else if (trc)
300 rc = trc;
301 break;
305 strv_free (fields);
306 fields = NULL;
308 if (rc == GPG_ERR_NO_DATA && f->siggrip)
310 trc = get_keyinfo (f->siggrip, &fields);
311 if (!trc && *fields[1] == 'T')
312 rc = 0;
313 else if (trc)
314 rc = trc;
317 strv_free (fields);
318 MUTEX_UNLOCK (&cache_mutex);
319 return rc;
322 static gpg_error_t
323 test_agent_cache_once (file_cache_t *p, const char *grip)
325 gpg_error_t rc;
326 char **fields = NULL;
328 (void)p;
329 rc = get_keyinfo (grip, &fields);
330 if (rc)
331 return rc;
333 /* Smartcard. */
334 if (*fields[1] == 'T')
335 rc = GPG_ERR_NO_DATA;
336 else
337 rc = isdigit (*fields[4]) || *fields[5] == 'C' ? 0 : GPG_ERR_NO_DATA;
339 strv_free (fields);
340 return rc;
343 /* Test each keygrip in data->(sig)grip for gpg-agent cache status. The file is
344 * considered cached if at least one grip is cached in the agent or one siggrip
345 * is cached in the case of 'sign'.
347 static gpg_error_t
348 test_agent_cache (file_cache_t *data, int sign)
350 gpg_error_t rc = 0;
351 char **p;
353 if ((!data->grip && !sign) || (!data->siggrip && sign))
354 return GPG_ERR_NO_DATA;
356 for (p = data->grip; !sign && p && *p; p++)
358 rc = test_agent_cache_once (data, *p);
359 if (!rc || rc != GPG_ERR_NO_DATA)
360 break;
363 if (!rc && sign)
364 rc = test_agent_cache_once (data, data->siggrip);
366 return rc;
369 static gpg_error_t
370 extract_keygrip_once (struct crypto_s *crypto, char **keyids, int sign,
371 char ***dst)
373 gpgme_key_t *result;
374 gpgme_error_t rc;
375 int i;
376 char **grips = NULL;
378 rc = crypto_list_keys (crypto, keyids, sign, &result);
379 if (rc)
380 return rc;
382 for (i = 0; result[i]; i++)
384 gpgme_subkey_t s;
386 for (s = result[i]->subkeys; s; s = s->next)
388 char **k;
390 if (sign && !s->can_sign)
391 continue;
393 for (k = keyids; *k; k++)
395 if (!strcmp (*k, s->keyid) && s->keygrip)
397 char **tmp;
398 size_t len = strv_length (grips);
400 tmp = xrealloc (grips, len+2 * sizeof (char *));
401 if (!tmp)
403 rc = GPG_ERR_ENOMEM;
404 break;
407 grips = tmp;
408 grips[len] = str_dup (s->keygrip);
409 if (!grips[len])
411 rc = GPG_ERR_ENOMEM;
412 break;
415 grips[++len] = NULL;
421 if (!rc)
423 strv_free (*dst);
424 *dst = grips;
426 else
428 strv_free (grips);
429 grips = NULL;
432 crypto_free_key_list (result);
433 return rc ? rc : grips ? rc : GPG_ERR_NO_DATA;
436 static gpg_error_t
437 extract_keygrips (file_cache_t *data)
439 gpg_error_t rc = 0;
440 struct crypto_s *crypto;
441 char **grips = NULL, **siggrips = NULL;
443 if (!data || !data->data)
444 return 0;
446 rc = crypto_init (&crypto, NULL, NULL, 0, NULL);
447 if (rc)
448 return rc;
450 pthread_cleanup_push ((void *)crypto_free, crypto);
452 if (data->data->pubkey)
453 rc = extract_keygrip_once (crypto, data->data->pubkey, 0, &grips);
455 if (!rc && data->data->sigkey)
457 char **tmp = NULL;
459 strv_printf (&tmp, "%s", data->data->sigkey);
460 rc = extract_keygrip_once (crypto, tmp, 1, &siggrips);
461 strv_free (tmp);
464 if (!rc)
466 strv_free (data->grip);
467 data->grip = grips;
468 xfree (data->siggrip);
469 data->siggrip = NULL;
470 if (siggrips && *siggrips)
471 data->siggrip = str_dup (*siggrips);
472 strv_free (siggrips);
474 else
476 strv_free (grips);
477 strv_free (siggrips);
480 pthread_cleanup_pop (1);
481 return rc;
484 static gpg_error_t
485 iscached (const char *filename, int *defer, int agent, int sign)
487 file_cache_t *p = get_entry (filename);
488 gpg_error_t rc = 0;
490 if (!agent)
492 if (!p || !p->data)
493 return GPG_ERR_NO_DATA;
495 if (defer)
496 *defer = p->defer_clear;
498 return 0;
501 if (!p)
502 return GPG_ERR_NO_DATA;
504 if (defer)
505 *defer = p->defer_clear;
507 if (!rc && (p->grip || p->siggrip))
508 rc = test_agent_cache (p, sign);
509 else if (!rc)
510 rc = GPG_ERR_NO_DATA;
512 return rc;
515 unsigned
516 cache_file_count ()
518 MUTEX_LOCK (&cache_mutex);
519 unsigned total = 0, i, n;
521 pthread_cleanup_push (release_mutex_cb, &cache_mutex);
522 n = slist_length (key_cache);
523 for (i = 0; i < n; i++)
525 file_cache_t *p = slist_nth_data (key_cache, i);
527 if (!iscached (p->filename, NULL, 0, 0))
528 total++;
531 pthread_cleanup_pop (1);
532 return total;
535 void
536 cache_adjust_timeout ()
538 MUTEX_LOCK (&cache_mutex);
539 int t = slist_length (key_cache);
540 int i;
542 pthread_cleanup_push (release_mutex_cb, &cache_mutex);
544 for (i = 0; i < t; i++)
546 file_cache_t *p = slist_nth_data (key_cache, i);
548 if (p->timeout > 0)
549 p->timeout--;
551 /* Test the cache entry timeout for expiration and also whether the file
552 * is a new one (no crc) and without any associated clients (refcount ==
553 * 1) and remove the cache entry accordingly. */
554 if (!p->timeout || (p->defer_clear && p->timeout != (long)-1)
555 || (p->timeout > 0 && p->refcount == 1
556 && (!p->data || !p->data->crc)
557 && !(p->flags & CACHE_FLAG_LOCKED)))
559 /* The file associated with this cache entry may be locked by a
560 * client. Defer freeing this cache entry until the next timeout
561 * check. */
562 gpg_error_t rc = clear_once (p, 1, 0);
564 if (!rc && !p->defer_clear)
566 free_entry (p, 0, 0);
567 t = slist_length (key_cache);
568 send_status_all (STATUS_CACHE, NULL);
573 pthread_cleanup_pop (1);
576 static gpg_error_t
577 set_timeout (const char *filename, long timeout, int defer, int force)
579 MUTEX_LOCK (&cache_mutex);
580 file_cache_t *p = get_entry (filename);
581 gpg_error_t rc = 0;
583 pthread_cleanup_push (release_mutex_cb, &cache_mutex);
585 if (p)
587 p->reset = timeout;
588 if (!p->defer_clear && (p->timeout == -1 || force))
589 p->timeout = timeout;
591 if (!timeout || defer)
593 rc = clear_once (p, 1, 0);
594 if (!rc)
595 send_status_all (STATUS_CACHE, NULL);
598 else
599 rc = GPG_ERR_NOT_FOUND;
601 pthread_cleanup_pop (1);
602 return rc;
605 gpg_error_t
606 cache_set_data (const char *filename, struct cache_data_s *data)
608 MUTEX_LOCK (&cache_mutex);
609 gpg_error_t rc = GPG_ERR_NO_DATA;
610 file_cache_t *p = get_entry (filename);
612 pthread_cleanup_push (release_mutex_cb, &cache_mutex);
614 if (p)
616 xfree (data->filename);
617 data->filename = NULL;
618 if (p->filename)
619 data->filename = str_dup (p->filename);
621 p->data = data;
622 rc = set_timeout (filename, p->reset, p->defer_clear, 0);
623 if (!rc && !p->reset)
625 clear_once (p, 0, 0);
626 send_status_all (STATUS_CACHE, NULL);
628 else if (!rc)
629 rc = extract_keygrips (p);
632 pthread_cleanup_pop (1);
633 return p && !rc ? 0 : rc;
636 struct cache_data_s *
637 cache_get_data (const char *filename, int *defer)
639 MUTEX_LOCK (&cache_mutex);
640 file_cache_t *p = get_entry (filename);
642 if (defer && p)
643 *defer = p->defer_clear;
644 MUTEX_UNLOCK (&cache_mutex);
645 return p ? p->data : NULL;
648 gpg_error_t
649 cache_add_file (const char *filename, struct cache_data_s *data, long timeout)
651 MUTEX_LOCK (&cache_mutex);
652 file_cache_t *p = get_entry (filename);
653 struct slist_s *new;
654 gpg_error_t rc = 0;
656 pthread_cleanup_push (release_mutex_cb, &cache_mutex);
658 if (p)
660 if (data)
662 char *str = p->filename ? str_dup (p->filename) : NULL;
664 if (p->filename && !str)
665 rc = GPG_ERR_ENOMEM;
666 else
668 xfree (data->filename);
669 data->filename = str;
673 if (!rc)
675 p->data = data;
676 p->refcount++;
677 rc = set_timeout (filename, timeout, p->defer_clear, 0);
680 else
682 p = xcalloc (1, sizeof (file_cache_t));
683 if (p)
685 p->mutex = (pthread_mutex_t *) xmalloc (sizeof (pthread_mutex_t));
686 if (p->mutex)
688 pthread_mutexattr_t attr;
689 pthread_mutexattr_init (&attr);
690 pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_RECURSIVE);
691 pthread_mutex_init (p->mutex, &attr);
692 pthread_mutexattr_destroy (&attr);
693 p->filename = str_dup (filename);
695 if (data)
697 xfree (data->filename);
698 data->filename = NULL;
699 data->filename = str_dup (p->filename);
702 p->data = data;
703 p->refcount++;
704 new = slist_append (key_cache, p);
705 if (new)
707 key_cache = new;
708 rc = cache_set_timeout(filename, timeout);
710 else
712 pthread_mutex_destroy (p->mutex);
713 xfree (p->mutex);
714 xfree (p->filename);
715 xfree (p);
716 p = NULL;
717 rc = GPG_ERR_ENOMEM;
720 else
722 xfree (p);
723 p = NULL;
724 rc = GPG_ERR_ENOMEM;
727 else
728 rc = GPG_ERR_ENOMEM;
731 if (!rc)
732 rc = extract_keygrips (p);
734 pthread_cleanup_pop (1);
736 if (!rc)
737 send_status_all (STATUS_CACHE, NULL);
739 return rc;
742 gpg_error_t
743 cache_clear_agent_keys (const char *filename, int decrypt, int sign)
745 MUTEX_LOCK (&cache_mutex);
746 gpg_error_t rc = 0;
747 char **key;
748 file_cache_t *p = get_entry (filename);
750 pthread_cleanup_push (release_mutex_cb, &cache_mutex);
752 if (p)
754 for (key = p->grip; decrypt && key && *key; key++)
756 rc = agent_command (cache_agent, NULL, NULL,
757 "CLEAR_PASSPHRASE --mode=normal %s", *key);
758 if (rc)
759 break;
762 if (p->siggrip && sign)
763 rc = agent_command (cache_agent, NULL, NULL,
764 "CLEAR_PASSPHRASE --mode=normal %s", p->siggrip);
766 else
767 rc = GPG_ERR_NOT_FOUND;
769 pthread_cleanup_pop (1);
770 return rc;
773 static gpg_error_t
774 clear_once (file_cache_t *p, int agent, int force)
776 gpg_error_t rc = 0, trc;
778 if (agent)
779 rc = cache_clear_agent_keys (p->filename, 1, 1);
781 trc = free_cache_data (p, force);
782 return rc ? rc : trc;
785 static void
786 free_entry (file_cache_t *p, int agent, int unlock)
788 gpg_error_t rc;
790 if (!p)
791 return;
793 rc = clear_once (p, agent, 0);
794 if (rc)
795 log_write ("%s(): %s", __FUNCTION__, pwmd_strerror (rc));
797 key_cache = slist_remove (key_cache, p);
799 if (p->mutex)
801 if (unlock)
802 MUTEX_UNLOCK (p->mutex);
804 pthread_mutex_destroy (p->mutex);
805 xfree (p->mutex);
808 strv_free (p->grip);
809 xfree (p->siggrip);
810 xfree (p->filename);
811 xfree (p);
814 gpg_error_t
815 cache_clear (struct client_s *client, const char *filename, int agent,
816 int force)
818 file_cache_t *p;
819 gpg_error_t rc = 0, all_rc = 0;
820 int i, t;
822 MUTEX_LOCK (&cache_mutex);
823 pthread_cleanup_push (release_mutex_cb, &cache_mutex);
825 if (filename)
827 p = get_entry (filename);
828 if (p)
830 rc = clear_once (p, agent, force);
831 if (rc)
832 log_write ("%s(): %s", __FUNCTION__, pwmd_strerror (rc));
835 else
837 t = slist_length (key_cache);
838 for (i = 0; i < t; i++)
840 p = slist_nth_data (key_cache, i);
842 if (client)
844 assuan_peercred_t peer;
846 rc = do_validate_peer (client->ctx, p->filename, &peer, NULL);
847 if (rc == GPG_ERR_FORBIDDEN)
848 rc = peer_is_invoker (client);
850 if (rc)
852 all_rc = !all_rc ? rc : all_rc;
853 continue;
857 clear_once (p, agent, 0);
861 pthread_cleanup_pop (1);
862 return filename ? rc : all_rc;
865 gpg_error_t
866 cache_iscached (const char *filename, int *defer, int agent, int sign)
868 gpg_error_t rc;
870 if (!filename)
871 return GPG_ERR_INV_PARAMETER;
873 MUTEX_LOCK (&cache_mutex);
874 pthread_cleanup_push (release_mutex_cb, &cache_mutex);
875 rc = iscached (filename, defer, agent, sign);
877 /* Test if the data file disappeared from the filesystem. */
878 if ((!rc || gpg_err_code (rc) == GPG_ERR_NO_DATA)
879 && access (filename, R_OK) == -1)
881 rc = gpg_error_from_errno (errno);
882 if (gpg_err_code (rc) == GPG_ERR_ENOENT)
884 /* Fixes clearing the cache entry that was created during OPEN when
885 * SAVE'ing a new file. */
886 if ((defer && *defer == 1) || !defer)
888 rc = cache_defer_clear (filename);
889 if (!rc && defer)
890 *defer = 1;
893 rc = GPG_ERR_ENOENT;
897 pthread_cleanup_pop (1);
898 return rc;
901 gpg_error_t
902 cache_defer_clear (const char *filename)
904 MUTEX_LOCK (&cache_mutex);
905 file_cache_t *p = get_entry (filename);
906 gpg_error_t rc = 0;
908 if (!p)
909 rc = GPG_ERR_NOT_FOUND;
910 else
911 p->defer_clear = 1;
913 MUTEX_UNLOCK (&cache_mutex);
914 return rc;
917 gpg_error_t
918 cache_set_timeout (const char *filename, long timeout)
920 return set_timeout (filename, timeout, 0, 1);
923 void
924 cache_deinit ()
926 exiting = 1;
927 MUTEX_LOCK (&cache_mutex);
928 int i, t = slist_length (key_cache);
930 pthread_cleanup_push (release_mutex_cb, &cache_mutex);
931 for (i = 0; i < t; i++)
933 file_cache_t *p = slist_nth_data (key_cache, i);
935 free_entry (p, 1, 0);
936 t = slist_length (key_cache);
937 i = -1;
940 gcry_free (cache_key);
941 xfree (cache_iv);
942 cache_key = NULL;
943 cache_iv = NULL;
944 agent_free (cache_agent);
945 cache_agent = NULL;
946 pthread_cleanup_pop (1);
947 pthread_mutex_destroy (&cache_mutex);
950 void
951 cache_mutex_init ()
953 pthread_mutexattr_t attr;
955 pthread_mutexattr_init (&attr);
956 pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_RECURSIVE);
957 pthread_mutex_init (&cache_mutex, &attr);
958 pthread_mutexattr_destroy (&attr);
961 gpg_error_t
962 cache_init ()
964 gpg_error_t rc = 0;
966 rc = agent_init (&cache_agent);
967 if (rc)
969 cache_agent = NULL;
970 return rc;
973 if (!cache_key)
975 rc = gcry_cipher_algo_info (GCRY_CIPHER_AES128, GCRYCTL_GET_BLKLEN, NULL,
976 &cache_blocksize);
977 if (rc)
978 return rc;
980 rc = gcry_cipher_algo_info (GCRY_CIPHER_AES128, GCRYCTL_GET_KEYLEN, NULL,
981 &cache_keysize);
982 if (rc)
983 return rc;
985 cache_key = gcry_malloc (cache_keysize);
986 if (!cache_key)
987 return GPG_ERR_ENOMEM;
989 cache_iv = xmalloc (cache_blocksize);
990 if (!cache_iv)
992 gcry_free (cache_key);
993 cache_key = NULL;
994 return GPG_ERR_ENOMEM;
997 gcry_create_nonce (cache_key, cache_keysize);
998 gcry_create_nonce (cache_iv, cache_blocksize);
1002 cache_mutex_init ();
1003 return rc;
1006 void
1007 cache_lock ()
1009 MUTEX_LOCK (&cache_mutex);
1012 void
1013 cache_unlock ()
1015 MUTEX_UNLOCK (&cache_mutex);
1018 static void
1019 update_plaintext_pointer (xmlDocPtr plaintext)
1021 unsigned i;
1022 unsigned t;
1024 t = slist_length (key_cache);
1025 for (i = 0; i < t; i++)
1027 file_cache_t *p = slist_nth_data (key_cache, i);
1029 if (p->data && p->data->plaintext == plaintext)
1030 p->data->plaintext = NULL;
1034 void
1035 cache_free_data_once (struct cache_data_s *data)
1037 if (!data)
1038 return;
1040 xfree (data->filename);
1041 strv_free (data->pubkey);
1042 xfree (data->sigkey);
1043 xfree (data->crc);
1044 xfree (data->doc);
1045 xfree (data);
1048 static void
1049 release_cipher (void *arg)
1051 gcry_cipher_close ((gcry_cipher_hd_t) arg);
1054 gpg_error_t
1055 cache_encrypt (struct crypto_s *crypto)
1057 gpg_error_t rc;
1058 gcry_cipher_hd_t h;
1059 size_t len = crypto->plaintext_size;
1061 rc = gcry_cipher_open (&h, GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_CBC, 0);
1062 if (rc)
1063 return rc;
1065 if (len % cache_blocksize)
1067 unsigned char *p;
1069 len += cache_blocksize - (len % cache_blocksize);
1070 p = xrealloc (crypto->plaintext, len * sizeof (unsigned char));
1071 if (!p)
1073 gcry_cipher_close (h);
1074 return GPG_ERR_ENOMEM;
1077 crypto->plaintext = p;
1078 memset (&crypto->plaintext[crypto->plaintext_size], 0,
1079 len - crypto->plaintext_size);
1082 pthread_cleanup_push (release_cipher, h);
1083 rc = gcry_cipher_setiv (h, cache_iv, cache_blocksize);
1084 if (!rc)
1086 rc = gcry_cipher_setkey (h, cache_key, cache_keysize);
1087 if (!rc)
1089 unsigned char *buf = xmalloc (len);
1091 pthread_cleanup_push (xfree, buf);
1093 if (!buf)
1094 rc = GPG_ERR_ENOMEM;
1096 if (!rc)
1098 rc = gcry_cipher_encrypt (h, buf, len, crypto->plaintext, len);
1099 if (!rc)
1101 xfree (crypto->plaintext);
1102 crypto->plaintext = buf;
1103 crypto->plaintext_size = len;
1107 pthread_cleanup_pop (rc != 0);
1111 pthread_cleanup_pop (1);
1112 return rc;
1115 gpg_error_t
1116 cache_decrypt (struct crypto_s *crypto)
1118 gcry_cipher_hd_t h = NULL;
1119 gpg_error_t rc;
1121 rc = gcry_cipher_open (&h, GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_CBC, 0);
1122 if (rc)
1123 return rc;
1125 if (!rc)
1126 rc = gcry_cipher_setiv (h, cache_iv, cache_blocksize);
1128 if (!rc)
1129 rc = gcry_cipher_setkey (h, cache_key, cache_keysize);
1131 pthread_cleanup_push (release_cipher, h);
1133 if (!rc)
1135 rc = gcry_cipher_decrypt (h, crypto->plaintext, crypto->plaintext_size,
1136 NULL, 0);
1137 if (rc || strncmp ((char *)crypto->plaintext, "<?xml ", 6))
1139 if (!rc)
1140 rc = GPG_ERR_BAD_DATA;
1144 pthread_cleanup_pop (1);
1145 return rc;
1148 gpg_error_t
1149 cache_kill_scd ()
1151 gpg_error_t rc;
1153 MUTEX_LOCK (&cache_mutex);
1154 pthread_cleanup_push (release_mutex_cb, &cache_mutex);
1155 rc = agent_kill_scd (cache_agent);
1156 pthread_cleanup_pop (1);
1157 return rc;
1160 gpg_error_t
1161 cache_agent_command (const char *cmd)
1163 gpg_error_t rc;
1165 MUTEX_LOCK (&cache_mutex);
1166 rc = agent_command (cache_agent, NULL, NULL, "%s", cmd);
1167 MUTEX_UNLOCK (&cache_mutex);
1168 return rc;
1171 void
1172 cache_release_mutex ()
1174 MUTEX_UNLOCK (&cache_mutex);
1177 static gpg_error_t
1178 plaintext_get (struct cache_data_s *data, xmlDocPtr *r_doc)
1180 unsigned i;
1181 unsigned t = slist_length (plaintext_list);
1183 assert (r_doc != NULL);
1185 for (i = 0; i < t; i++)
1187 struct plaintext_s *p = slist_nth_data (plaintext_list, i);
1189 if (!strcmp (p->filename, data->filename) && !p->modified)
1191 *r_doc = p->plaintext;
1192 p->refcount++;
1193 return 0;
1197 return GPG_ERR_NO_DATA;
1200 gpg_error_t
1201 cache_plaintext_get (const char *filename, xmlDocPtr *r_doc)
1203 file_cache_t *p;
1204 gpg_error_t rc = 0;
1206 MUTEX_LOCK (&cache_mutex);
1207 pthread_cleanup_push (release_mutex_cb, &cache_mutex);
1209 p = get_entry (filename);
1210 if (p && p->data)
1211 rc = plaintext_get (p->data, r_doc);
1212 else
1213 rc = GPG_ERR_NO_DATA;
1215 pthread_cleanup_pop (1);
1216 return rc;
1219 static gpg_error_t
1220 release_plaintext (xmlDocPtr *plaintext)
1222 unsigned i;
1223 unsigned t;
1225 if (!plaintext)
1226 return GPG_ERR_NO_DATA;
1228 t = slist_length (plaintext_list);
1229 for (i = 0; i < t; i++)
1231 struct plaintext_s *p = slist_nth_data (plaintext_list, i);
1233 if (p->plaintext == *plaintext)
1235 assert (p->refcount > 0);
1236 if (--p->refcount == 0)
1238 xmlFreeDoc (p->plaintext);
1239 xfree (p->filename);
1240 plaintext_list = slist_remove (plaintext_list, p);
1241 xfree (p);
1242 update_plaintext_pointer (*plaintext);
1243 *plaintext = NULL;
1246 return 0;
1250 return GPG_ERR_NO_DATA;
1253 gpg_error_t
1254 cache_plaintext_release (xmlDocPtr *plaintext)
1256 gpg_error_t rc = 0;
1258 MUTEX_LOCK (&cache_mutex);
1259 pthread_cleanup_push (release_mutex_cb, &cache_mutex);
1260 rc = release_plaintext (plaintext);
1261 pthread_cleanup_pop (1);
1262 return rc;
1265 gpg_error_t
1266 cache_plaintext_set (const char *filename, xmlDocPtr doc, int modified)
1268 file_cache_t *p;
1269 gpg_error_t rc = 0;
1271 MUTEX_LOCK (&cache_mutex);
1272 pthread_cleanup_push (release_mutex_cb, &cache_mutex);
1274 p = get_entry (filename);
1275 if (p && p->data)
1277 struct plaintext_s *s = xcalloc (1, sizeof (struct plaintext_s));
1279 if (s)
1281 s->filename = str_dup (p->data->filename);
1282 if (s->filename)
1284 struct slist_s *l;
1285 int i, t = slist_length (plaintext_list);
1287 /* Prevent cache_plaintext_get() from returning the other
1288 * client's document copy. */
1289 for (i = 0; i < t; i++)
1291 struct plaintext_s *x = slist_nth_data (plaintext_list, i);
1293 if (!strcmp (s->filename, x->filename))
1294 x->modified = 1;
1297 l = slist_append (plaintext_list, s);
1298 if (l)
1300 plaintext_list = l;
1301 s->plaintext = p->data->plaintext = doc;
1302 s->modified = modified;
1303 s->refcount = 1;
1305 else
1307 xfree (s->filename);
1308 rc = GPG_ERR_ENOMEM;
1311 else
1312 rc = GPG_ERR_ENOMEM;
1314 if (rc)
1315 xfree (s);
1317 else
1318 rc = GPG_ERR_ENOMEM;
1320 else
1321 rc = GPG_ERR_NO_DATA;
1323 pthread_cleanup_pop (1);
1324 return rc;