2 Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012
3 Ben Kibbey <bjk@luxsci.net>
5 This file is part of pwmd.
7 Pwmd is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 2 of the License, or
10 (at your option) any later version.
12 Pwmd is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with Pwmd. If not, see <http://www.gnu.org/licenses/>.
29 #include "pwmd-error.h"
35 #include "util-misc.h"
36 #include "util-string.h"
43 static pthread_mutex_t cache_mutex
;
44 static struct slist_s
*key_cache
;
46 static struct agent_s
*cache_agent
;
49 extern void log_write (const char *fmt
, ...);
51 typedef gpg_error_t (*free_data_fn_t
) (file_cache_t
*);
52 static free_data_fn_t free_data_fn
;
53 static gpg_error_t
clear_once (file_cache_t
* p
);
54 static int remove_entry (const unsigned char *md5file
);
55 static void free_entry (file_cache_t
* p
);
58 get_entry (const unsigned char *md5file
)
60 int t
= slist_length (key_cache
);
66 for (i
= 0; i
< t
; i
++)
68 file_cache_t
*p
= slist_nth_data (key_cache
, i
);
70 if (!memcmp (p
->filename
, md5file
, sizeof (p
->filename
)))
78 cache_lock_mutex (void *ctx
, const unsigned char *md5file
,
79 long lock_timeout
, int add
, int timeout
)
81 MUTEX_LOCK (&cache_mutex
);
83 file_cache_t
*p
= get_entry (md5file
);
87 MUTEX_UNLOCK (&cache_mutex
);
88 MUTEX_TRYLOCK (ctx
, p
->mutex
, rc
, lock_timeout
);
92 if (cache_add_file (md5file
, NULL
, NULL
, timeout
))
94 p
= get_entry (md5file
);
95 MUTEX_UNLOCK (&cache_mutex
);
96 MUTEX_TRYLOCK (ctx
, p
->mutex
, rc
, lock_timeout
);
100 MUTEX_UNLOCK (&cache_mutex
);
106 MUTEX_UNLOCK (&cache_mutex
);
109 return !p
&& !rc
? GPG_ERR_NO_DATA
: rc
;
113 remove_entry (const unsigned char *md5file
)
115 MUTEX_LOCK (&cache_mutex
);
116 file_cache_t
*p
= get_entry (md5file
);
118 pthread_cleanup_push (cleanup_mutex_cb
, &cache_mutex
);
121 /* Keep a refcount because another client maybe editing this same new
122 * file. The entry needs to be kept in case the other client SAVE's.
129 pthread_cleanup_pop (1);
134 cache_unlock_mutex (const unsigned char *md5file
, int remove
)
136 MUTEX_LOCK (&cache_mutex
);
137 file_cache_t
*p
= get_entry (md5file
);
141 MUTEX_UNLOCK (p
->mutex
);
143 remove_entry (md5file
);
146 MUTEX_UNLOCK (&cache_mutex
);
147 return p
? 0 : GPG_ERR_NO_DATA
;
151 static int valid_agent_grip (file_cache_t
*e
)
155 for (c
= 0; c
< sizeof (e
->grip
); c
++)
166 valid_grip (file_cache_t
* e
)
168 if (e
->data
&& e
->data
->key
)
172 return valid_agent_grip (e
);
179 iscached (const unsigned char *md5file
, int *defer
)
182 file_cache_t
*p
= get_entry (md5file
);
184 if (!p
|| !p
->data
|| !valid_grip (p
))
185 return GPG_ERR_NO_DATA
;
188 *defer
= p
->defer_clear
;
190 if (p
->data
&& p
->data
->key
)
196 rc
= send_to_agent (cache_agent
, &line
, NULL
, "KEYINFO --data %s", p
->grip
);
199 char **fields
= str_split (line
, " ", 0);
201 /* Smartcard with a cached document. */
202 if (*fields
[1] == 'T' && p
->data
->doc
)
205 rc
= isdigit (*fields
[4]) || *fields
[5] == 'C' ? 0 : GPG_ERR_NO_DATA
;
218 MUTEX_LOCK (&cache_mutex
);
219 unsigned total
= 0, i
, n
;
221 pthread_cleanup_push (cleanup_mutex_cb
, &cache_mutex
);
222 n
= slist_length (key_cache
);
223 for (i
= 0; i
< n
; i
++)
225 file_cache_t
*p
= slist_nth_data (key_cache
, i
);
227 if (!iscached (p
->filename
, NULL
))
231 pthread_cleanup_pop (1);
236 cache_adjust_timeout ()
238 MUTEX_LOCK (&cache_mutex
);
239 int t
= slist_length (key_cache
);
242 pthread_cleanup_push (cleanup_mutex_cb
, &cache_mutex
);
244 for (i
= 0; i
< t
; i
++)
246 file_cache_t
*p
= slist_nth_data (key_cache
, i
);
253 /* The file associated with this cache entry may be locked by a
254 * client. Defer freeing this cache entry until the next timeout
257 send_status_all (STATUS_CACHE
, NULL
);
261 pthread_cleanup_pop (1);
265 setgrip (file_cache_t
* p
, const unsigned char *grip
)
269 char *tmp
= bin2hex (grip
, 20);
271 memcpy (p
->grip
, tmp
, sizeof (p
->grip
));
277 set_timeout (const unsigned char *md5file
, int timeout
, int defer
)
279 MUTEX_LOCK (&cache_mutex
);
280 file_cache_t
*p
= get_entry (md5file
);
285 MUTEX_UNLOCK (&cache_mutex
);
286 return GPG_ERR_NOT_FOUND
;
290 if (p
->timeout
== -1 || timeout
== -1)
291 p
->timeout
= timeout
;
293 if (!timeout
|| defer
)
297 send_status_all (STATUS_CACHE
, NULL
);
300 MUTEX_UNLOCK (&cache_mutex
);
305 cache_set_data (const unsigned char *md5file
, struct cache_data_s
* data
,
306 const unsigned char *grip
)
308 MUTEX_LOCK (&cache_mutex
);
309 file_cache_t
*p
= get_entry (md5file
);
315 set_timeout (md5file
, p
->reset
, p
->defer_clear
);
319 send_status_all (STATUS_CACHE
, NULL
);
323 MUTEX_UNLOCK (&cache_mutex
);
324 return p
? 0 : GPG_ERR_NO_DATA
;
327 struct cache_data_s
*
328 cache_get_data (const unsigned char *md5file
)
330 MUTEX_LOCK (&cache_mutex
);
331 file_cache_t
*p
= get_entry (md5file
);
333 MUTEX_UNLOCK (&cache_mutex
);
334 return p
? p
->data
: NULL
;
338 struct cache_data_s
*
339 cache_get_data_filename (const char *filename
)
341 unsigned char md5file
[16];
343 gcry_md_hash_buffer (GCRY_MD_MD5
, md5file
, filename
, strlen (filename
));
344 return cache_get_data (md5file
);
348 cache_add_file (const unsigned char *md5file
, const unsigned char *grip
,
349 struct cache_data_s
*data
, int timeout
)
351 MUTEX_LOCK (&cache_mutex
);
352 file_cache_t
*p
= get_entry (md5file
);
361 b
= set_timeout (md5file
, timeout
, p
->defer_clear
) == 0 ? 1 : 0;
362 MUTEX_UNLOCK (&cache_mutex
);
363 send_status_all (STATUS_CACHE
, NULL
);
367 p
= xcalloc (1, sizeof (file_cache_t
));
370 MUTEX_UNLOCK (&cache_mutex
);
374 p
->mutex
= (pthread_mutex_t
*) xmalloc (sizeof (pthread_mutex_t
));
378 MUTEX_UNLOCK (&cache_mutex
);
382 pthread_mutexattr_t attr
;
383 pthread_mutexattr_init (&attr
);
384 pthread_mutexattr_settype (&attr
, PTHREAD_MUTEX_RECURSIVE
);
385 pthread_mutex_init (p
->mutex
, &attr
);
386 pthread_mutexattr_destroy (&attr
);
387 memcpy (p
->filename
, md5file
, sizeof (p
->filename
));
389 p
->reset
= p
->timeout
= timeout
;
392 new = slist_append (key_cache
, p
);
395 pthread_mutex_destroy (p
->mutex
);
398 MUTEX_UNLOCK (&cache_mutex
);
403 MUTEX_UNLOCK (&cache_mutex
);
404 send_status_all (STATUS_CACHE
, NULL
);
409 clear_once (file_cache_t
* p
)
411 gpg_error_t rc
= free_data_fn (p
);
413 if (!rc
&& valid_grip (p
))
416 if (use_agent
&& valid_agent_grip (p
))
418 rc
= send_to_agent (cache_agent
, NULL
, NULL
,
419 "CLEAR_PASSPHRASE --mode=normal %s", p
->grip
);
421 log_write ("%s(): %s", __FUNCTION__
, pwmd_strerror (rc
));
424 memset (p
->grip
, 0, sizeof (p
->grip
));
431 free_entry (file_cache_t
* p
)
440 log_write ("%s(): %s", __FUNCTION__
, pwmd_strerror (rc
));
444 pthread_mutex_destroy (p
->mutex
);
448 key_cache
= slist_remove (key_cache
, p
);
453 cache_clear (const unsigned char *md5file
)
459 MUTEX_LOCK (&cache_mutex
);
463 p
= get_entry (md5file
);
466 MUTEX_UNLOCK (&cache_mutex
);
470 pthread_cleanup_push (cleanup_mutex_cb
, &cache_mutex
);
472 pthread_cleanup_pop (1);
474 log_write ("%s(): %s", __FUNCTION__
, pwmd_strerror (rc
));
479 pthread_cleanup_push (cleanup_mutex_cb
, &cache_mutex
);
480 t
= slist_length (key_cache
);
481 for (i
= 0; i
< t
; i
++)
483 p
= slist_nth_data (key_cache
, i
);
487 pthread_cleanup_pop (1);
492 cache_iscached (const char *filename
, int *defer
)
495 unsigned char md5file
[16];
497 if (access (filename
, R_OK
) == -1)
498 return gpg_error_from_syserror ();
500 MUTEX_LOCK (&cache_mutex
);
501 pthread_cleanup_push (cleanup_mutex_cb
, &cache_mutex
);
502 gcry_md_hash_buffer (GCRY_MD_MD5
, md5file
, filename
, strlen (filename
));
503 rc
= iscached (md5file
, defer
);
504 pthread_cleanup_pop (1);
509 cache_defer_clear (const unsigned char *md5file
)
511 MUTEX_LOCK (&cache_mutex
);
512 file_cache_t
*p
= get_entry (md5file
);
516 rc
= GPG_ERR_NOT_FOUND
;
520 MUTEX_UNLOCK (&cache_mutex
);
525 cache_set_timeout (const unsigned char *md5file
, int timeout
)
527 return set_timeout (md5file
, timeout
, 0);
531 cache_get_grip (const unsigned char *md5file
, unsigned char *grip
)
533 MUTEX_LOCK (&cache_mutex
);
534 file_cache_t
*p
= get_entry (md5file
);
536 if (!p
|| !valid_grip (p
))
538 MUTEX_UNLOCK (&cache_mutex
);
542 memcpy (grip
, p
->grip
, sizeof (p
->grip
));
543 MUTEX_UNLOCK (&cache_mutex
);
550 MUTEX_LOCK (&cache_mutex
);
553 pthread_cleanup_push (cleanup_mutex_cb
, &cache_mutex
);
554 while ((p
= slist_nth_data (key_cache
, 0)))
558 if (use_agent
&& cache_agent
)
559 cleanup_agent (cache_agent
);
563 gcry_free (cache_key
);
567 pthread_cleanup_pop (1);
568 pthread_mutex_destroy (&cache_mutex
);
572 cache_init (free_data_fn_t fn
)
575 pthread_mutexattr_t attr
;
579 rc
= gcry_cipher_algo_info (GCRY_CIPHER_AES
, GCRYCTL_GET_BLKLEN
, NULL
,
584 rc
= gcry_cipher_algo_info (GCRY_CIPHER_AES
, GCRYCTL_GET_KEYLEN
, NULL
,
589 cache_key
= gcry_malloc (cache_keysize
);
591 return GPG_ERR_ENOMEM
;
593 cache_iv
= xmalloc (cache_blocksize
);
596 gcry_free (cache_key
);
598 return GPG_ERR_ENOMEM
;
601 gcry_create_nonce (cache_key
, cache_keysize
);
602 gcry_create_nonce (cache_iv
, cache_blocksize
);
606 if (use_agent
&& !cache_agent
)
608 rc
= agent_init (&cache_agent
);
613 rc
= send_to_agent (cache_agent
, &line
, NULL
, "GETINFO version");
616 char **fields
= str_split (line
, ".", 0);
619 major
= atoi (fields
[0]);
620 minor
= atoi (fields
[1]);
621 if (major
< 2 || minor
< 1)
622 rc
= GPG_ERR_UNKNOWN_VERSION
;
631 pthread_mutexattr_init (&attr
);
632 pthread_mutexattr_settype (&attr
, PTHREAD_MUTEX_RECURSIVE
);
633 pthread_mutex_init (&cache_mutex
, &attr
);
634 pthread_mutexattr_destroy (&attr
);
641 cache_is_shadowed (const char *grip
)
643 MUTEX_LOCK (&cache_mutex
);
648 pthread_cleanup_push (cleanup_mutex_cb
, &cache_mutex
);
649 rc
= send_to_agent (cache_agent
, &line
, &len
, "KEYINFO --data %s", grip
);
650 pthread_cleanup_pop (1);
654 char **fields
= str_split (line
, " ", 0);
656 rc
= (*fields
[1] == 'T') ? 0 : GPG_ERR_NO_DATA
;
668 MUTEX_LOCK (&cache_mutex
);
674 MUTEX_UNLOCK (&cache_mutex
);
678 free_cache_data_once (struct cache_data_s
*data
)
685 gcry_sexp_release (data
->pubkey
);
688 gcry_free (data
->doc
);
689 gcry_free (data
->key
);