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/>.
31 #include "pwmd-error.h"
37 #include "util-misc.h"
38 #include "util-string.h"
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
;
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
);
67 get_entry (const char *filename
)
69 int t
= slist_length (key_cache
);
75 for (i
= 0; i
< t
; i
++)
77 file_cache_t
*p
= slist_nth_data (key_cache
, i
);
79 if (!strcmp (p
->filename
, filename
))
87 cache_lock_mutex (void *ctx
, const char *filename
, long lock_timeout
, int add
,
90 MUTEX_LOCK (&cache_mutex
);
92 file_cache_t
*p
= get_entry (filename
);
94 pthread_cleanup_push (release_mutex_cb
, &cache_mutex
);
98 MUTEX_UNLOCK (&cache_mutex
);
99 MUTEX_TRYLOCK (ctx
, p
->mutex
, rc
, lock_timeout
);
101 p
->flags
|= CACHE_FLAG_LOCKED
;
105 rc
= cache_add_file (filename
, NULL
, timeout
);
108 p
= get_entry (filename
);
109 MUTEX_UNLOCK (&cache_mutex
);
112 MUTEX_TRYLOCK (ctx
, p
->mutex
, rc
, lock_timeout
);
114 p
->flags
|= CACHE_FLAG_LOCKED
;
119 MUTEX_UNLOCK (&cache_mutex
);
124 MUTEX_UNLOCK (&cache_mutex
);
127 pthread_cleanup_pop (0);
128 return !p
&& !rc
? GPG_ERR_NO_DATA
: rc
;
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
);
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.
145 free_entry (p
, 0, 1);
148 pthread_cleanup_pop (1);
153 free_cache_data (file_cache_t
*cache
, int force
)
155 gpg_error_t rc
= GPG_ERR_NO_DATA
;
157 struct client_thread_s
*found
= NULL
;
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
170 for (i
= 0; i
< t
; i
++)
172 struct client_thread_s
*thd
= slist_nth_data (cn_thread_list
, i
);
177 if (thd
->cl
->filename
&& !strcmp (thd
->cl
->filename
, cache
->filename
)
180 cache
->defer_clear
= 1;
181 MUTEX_UNLOCK (&cn_mutex
);
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
);
197 self
= pthread_equal (pthread_self (), thd
->tid
);
199 if (thd
->cl
->filename
&& !strcmp (thd
->cl
->filename
, cache
->filename
))
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);
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
);
225 cache
->defer_clear
= 0;
226 cache
->timeout
= (long)-1;
229 cache_unlock_mutex (found
->cl
->filename
, 0);
235 cache
->defer_clear
= 1;
237 pthread_cleanup_pop (1);
238 pthread_cleanup_pop (1);
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
);
252 p
->flags
&= ~CACHE_FLAG_LOCKED
;
254 remove_entry (filename
);
256 MUTEX_UNLOCK (p
->mutex
);
259 pthread_cleanup_pop (1);
260 return p
? 0 : GPG_ERR_NO_DATA
;
264 get_keyinfo (const char *grip
, char ***r_fields
)
269 rc
= agent_command (cache_agent
, &line
, NULL
, "KEYINFO --data %s", grip
);
273 *r_fields
= str_split (line
, " ", 0);
275 return !(*r_fields
) ? GPG_ERR_ENOMEM
: rc
;
279 cache_is_shadowed (const char *filename
)
281 MUTEX_LOCK (&cache_mutex
);
282 file_cache_t
*f
= get_entry (filename
);
284 char **fields
= NULL
;
285 gpg_error_t rc
= GPG_ERR_NO_DATA
, trc
;
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')
308 if (rc
== GPG_ERR_NO_DATA
&& f
->siggrip
)
310 trc
= get_keyinfo (f
->siggrip
, &fields
);
311 if (!trc
&& *fields
[1] == 'T')
318 MUTEX_UNLOCK (&cache_mutex
);
323 test_agent_cache_once (file_cache_t
*p
, const char *grip
)
326 char **fields
= NULL
;
329 rc
= get_keyinfo (grip
, &fields
);
334 if (*fields
[1] == 'T')
335 rc
= GPG_ERR_NO_DATA
;
337 rc
= isdigit (*fields
[4]) || *fields
[5] == 'C' ? 0 : GPG_ERR_NO_DATA
;
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'.
348 test_agent_cache (file_cache_t
*data
, int sign
)
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
)
364 rc
= test_agent_cache_once (data
, data
->siggrip
);
370 extract_keygrip_once (struct crypto_s
*crypto
, char **keyids
, int sign
,
378 rc
= crypto_list_keys (crypto
, keyids
, sign
, &result
);
382 for (i
= 0; result
[i
]; i
++)
386 for (s
= result
[i
]->subkeys
; s
; s
= s
->next
)
390 if (sign
&& !s
->can_sign
)
393 for (k
= keyids
; *k
; k
++)
395 if (!strcmp (*k
, s
->keyid
) && s
->keygrip
)
398 size_t len
= strv_length (grips
);
400 tmp
= xrealloc (grips
, len
+2 * sizeof (char *));
408 grips
[len
] = str_dup (s
->keygrip
);
432 crypto_free_key_list (result
);
433 return rc
? rc
: grips
? rc
: GPG_ERR_NO_DATA
;
437 extract_keygrips (file_cache_t
*data
)
440 struct crypto_s
*crypto
;
441 char **grips
= NULL
, **siggrips
= NULL
;
443 if (!data
|| !data
->data
)
446 rc
= crypto_init (&crypto
, NULL
, NULL
, 0, NULL
);
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
)
459 strv_printf (&tmp
, "%s", data
->data
->sigkey
);
460 rc
= extract_keygrip_once (crypto
, tmp
, 1, &siggrips
);
466 strv_free (data
->grip
);
468 xfree (data
->siggrip
);
469 data
->siggrip
= NULL
;
470 if (siggrips
&& *siggrips
)
471 data
->siggrip
= str_dup (*siggrips
);
472 strv_free (siggrips
);
477 strv_free (siggrips
);
480 pthread_cleanup_pop (1);
485 iscached (const char *filename
, int *defer
, int agent
, int sign
)
487 file_cache_t
*p
= get_entry (filename
);
493 return GPG_ERR_NO_DATA
;
496 *defer
= p
->defer_clear
;
502 return GPG_ERR_NO_DATA
;
505 *defer
= p
->defer_clear
;
507 if (!rc
&& (p
->grip
|| p
->siggrip
))
508 rc
= test_agent_cache (p
, sign
);
510 rc
= GPG_ERR_NO_DATA
;
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))
531 pthread_cleanup_pop (1);
536 cache_adjust_timeout ()
538 MUTEX_LOCK (&cache_mutex
);
539 int t
= slist_length (key_cache
);
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
);
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
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);
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
);
583 pthread_cleanup_push (release_mutex_cb
, &cache_mutex
);
588 if (!p
->defer_clear
&& (p
->timeout
== -1 || force
))
589 p
->timeout
= timeout
;
591 if (!timeout
|| defer
)
593 rc
= clear_once (p
, 1, 0);
595 send_status_all (STATUS_CACHE
, NULL
);
599 rc
= GPG_ERR_NOT_FOUND
;
601 pthread_cleanup_pop (1);
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
);
616 xfree (data
->filename
);
617 data
->filename
= NULL
;
619 data
->filename
= str_dup (p
->filename
);
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
);
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
);
643 *defer
= p
->defer_clear
;
644 MUTEX_UNLOCK (&cache_mutex
);
645 return p
? p
->data
: NULL
;
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
);
656 pthread_cleanup_push (release_mutex_cb
, &cache_mutex
);
662 char *str
= p
->filename
? str_dup (p
->filename
) : NULL
;
664 if (p
->filename
&& !str
)
668 xfree (data
->filename
);
669 data
->filename
= str
;
677 rc
= set_timeout (filename
, timeout
, p
->defer_clear
, 0);
682 p
= xcalloc (1, sizeof (file_cache_t
));
685 p
->mutex
= (pthread_mutex_t
*) xmalloc (sizeof (pthread_mutex_t
));
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
);
697 xfree (data
->filename
);
698 data
->filename
= NULL
;
699 data
->filename
= str_dup (p
->filename
);
704 new = slist_append (key_cache
, p
);
708 rc
= cache_set_timeout(filename
, timeout
);
712 pthread_mutex_destroy (p
->mutex
);
732 rc
= extract_keygrips (p
);
734 pthread_cleanup_pop (1);
737 send_status_all (STATUS_CACHE
, NULL
);
743 cache_clear_agent_keys (const char *filename
, int decrypt
, int sign
)
745 MUTEX_LOCK (&cache_mutex
);
748 file_cache_t
*p
= get_entry (filename
);
750 pthread_cleanup_push (release_mutex_cb
, &cache_mutex
);
754 for (key
= p
->grip
; decrypt
&& key
&& *key
; key
++)
756 rc
= agent_command (cache_agent
, NULL
, NULL
,
757 "CLEAR_PASSPHRASE --mode=normal %s", *key
);
762 if (p
->siggrip
&& sign
)
763 rc
= agent_command (cache_agent
, NULL
, NULL
,
764 "CLEAR_PASSPHRASE --mode=normal %s", p
->siggrip
);
767 rc
= GPG_ERR_NOT_FOUND
;
769 pthread_cleanup_pop (1);
774 clear_once (file_cache_t
*p
, int agent
, int force
)
776 gpg_error_t rc
= 0, trc
;
779 rc
= cache_clear_agent_keys (p
->filename
, 1, 1);
781 trc
= free_cache_data (p
, force
);
782 return rc
? rc
: trc
;
786 free_entry (file_cache_t
*p
, int agent
, int unlock
)
793 rc
= clear_once (p
, agent
, 0);
795 log_write ("%s(): %s", __FUNCTION__
, pwmd_strerror (rc
));
797 key_cache
= slist_remove (key_cache
, p
);
802 MUTEX_UNLOCK (p
->mutex
);
804 pthread_mutex_destroy (p
->mutex
);
815 cache_clear (struct client_s
*client
, const char *filename
, int agent
,
819 gpg_error_t rc
= 0, all_rc
= 0;
822 MUTEX_LOCK (&cache_mutex
);
823 pthread_cleanup_push (release_mutex_cb
, &cache_mutex
);
827 p
= get_entry (filename
);
830 rc
= clear_once (p
, agent
, force
);
832 log_write ("%s(): %s", __FUNCTION__
, pwmd_strerror (rc
));
837 t
= slist_length (key_cache
);
838 for (i
= 0; i
< t
; i
++)
840 p
= slist_nth_data (key_cache
, i
);
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
);
852 all_rc
= !all_rc
? rc
: all_rc
;
857 clear_once (p
, agent
, 0);
861 pthread_cleanup_pop (1);
862 return filename
? rc
: all_rc
;
866 cache_iscached (const char *filename
, int *defer
, int agent
, int sign
)
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
);
897 pthread_cleanup_pop (1);
902 cache_defer_clear (const char *filename
)
904 MUTEX_LOCK (&cache_mutex
);
905 file_cache_t
*p
= get_entry (filename
);
909 rc
= GPG_ERR_NOT_FOUND
;
913 MUTEX_UNLOCK (&cache_mutex
);
918 cache_set_timeout (const char *filename
, long timeout
)
920 return set_timeout (filename
, timeout
, 0, 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
);
940 gcry_free (cache_key
);
944 agent_free (cache_agent
);
946 pthread_cleanup_pop (1);
947 pthread_mutex_destroy (&cache_mutex
);
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
);
966 rc
= agent_init (&cache_agent
);
975 rc
= gcry_cipher_algo_info (GCRY_CIPHER_AES128
, GCRYCTL_GET_BLKLEN
, NULL
,
980 rc
= gcry_cipher_algo_info (GCRY_CIPHER_AES128
, GCRYCTL_GET_KEYLEN
, NULL
,
985 cache_key
= gcry_malloc (cache_keysize
);
987 return GPG_ERR_ENOMEM
;
989 cache_iv
= xmalloc (cache_blocksize
);
992 gcry_free (cache_key
);
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 ();
1009 MUTEX_LOCK (&cache_mutex
);
1015 MUTEX_UNLOCK (&cache_mutex
);
1019 update_plaintext_pointer (xmlDocPtr plaintext
)
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
;
1035 cache_free_data_once (struct cache_data_s
*data
)
1040 xfree (data
->filename
);
1041 strv_free (data
->pubkey
);
1042 xfree (data
->sigkey
);
1049 release_cipher (void *arg
)
1051 gcry_cipher_close ((gcry_cipher_hd_t
) arg
);
1055 cache_encrypt (struct crypto_s
*crypto
)
1059 size_t len
= crypto
->plaintext_size
;
1061 rc
= gcry_cipher_open (&h
, GCRY_CIPHER_AES128
, GCRY_CIPHER_MODE_CBC
, 0);
1065 if (len
% cache_blocksize
)
1069 len
+= cache_blocksize
- (len
% cache_blocksize
);
1070 p
= xrealloc (crypto
->plaintext
, len
* sizeof (unsigned char));
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
);
1086 rc
= gcry_cipher_setkey (h
, cache_key
, cache_keysize
);
1089 unsigned char *buf
= xmalloc (len
);
1091 pthread_cleanup_push (xfree
, buf
);
1094 rc
= GPG_ERR_ENOMEM
;
1098 rc
= gcry_cipher_encrypt (h
, buf
, len
, crypto
->plaintext
, len
);
1101 xfree (crypto
->plaintext
);
1102 crypto
->plaintext
= buf
;
1103 crypto
->plaintext_size
= len
;
1107 pthread_cleanup_pop (rc
!= 0);
1111 pthread_cleanup_pop (1);
1116 cache_decrypt (struct crypto_s
*crypto
)
1118 gcry_cipher_hd_t h
= NULL
;
1121 rc
= gcry_cipher_open (&h
, GCRY_CIPHER_AES128
, GCRY_CIPHER_MODE_CBC
, 0);
1126 rc
= gcry_cipher_setiv (h
, cache_iv
, cache_blocksize
);
1129 rc
= gcry_cipher_setkey (h
, cache_key
, cache_keysize
);
1131 pthread_cleanup_push (release_cipher
, h
);
1135 rc
= gcry_cipher_decrypt (h
, crypto
->plaintext
, crypto
->plaintext_size
,
1137 if (rc
|| strncmp ((char *)crypto
->plaintext
, "<?xml ", 6))
1140 rc
= GPG_ERR_BAD_DATA
;
1144 pthread_cleanup_pop (1);
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);
1161 cache_agent_command (const char *cmd
)
1165 MUTEX_LOCK (&cache_mutex
);
1166 rc
= agent_command (cache_agent
, NULL
, NULL
, "%s", cmd
);
1167 MUTEX_UNLOCK (&cache_mutex
);
1172 cache_release_mutex ()
1174 MUTEX_UNLOCK (&cache_mutex
);
1178 plaintext_get (struct cache_data_s
*data
, xmlDocPtr
*r_doc
)
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
;
1197 return GPG_ERR_NO_DATA
;
1201 cache_plaintext_get (const char *filename
, xmlDocPtr
*r_doc
)
1206 MUTEX_LOCK (&cache_mutex
);
1207 pthread_cleanup_push (release_mutex_cb
, &cache_mutex
);
1209 p
= get_entry (filename
);
1211 rc
= plaintext_get (p
->data
, r_doc
);
1213 rc
= GPG_ERR_NO_DATA
;
1215 pthread_cleanup_pop (1);
1220 release_plaintext (xmlDocPtr
*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
);
1242 update_plaintext_pointer (*plaintext
);
1250 return GPG_ERR_NO_DATA
;
1254 cache_plaintext_release (xmlDocPtr
*plaintext
)
1258 MUTEX_LOCK (&cache_mutex
);
1259 pthread_cleanup_push (release_mutex_cb
, &cache_mutex
);
1260 rc
= release_plaintext (plaintext
);
1261 pthread_cleanup_pop (1);
1266 cache_plaintext_set (const char *filename
, xmlDocPtr doc
, int modified
)
1271 MUTEX_LOCK (&cache_mutex
);
1272 pthread_cleanup_push (release_mutex_cb
, &cache_mutex
);
1274 p
= get_entry (filename
);
1277 struct plaintext_s
*s
= xcalloc (1, sizeof (struct plaintext_s
));
1281 s
->filename
= str_dup (p
->data
->filename
);
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
))
1297 l
= slist_append (plaintext_list
, s
);
1301 s
->plaintext
= p
->data
->plaintext
= doc
;
1302 s
->modified
= modified
;
1307 xfree (s
->filename
);
1308 rc
= GPG_ERR_ENOMEM
;
1312 rc
= GPG_ERR_ENOMEM
;
1318 rc
= GPG_ERR_ENOMEM
;
1321 rc
= GPG_ERR_NO_DATA
;
1323 pthread_cleanup_pop (1);