2 Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013
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
++)
157 if (e
->grip
[c
] && e
->grip
[c
] != '0')
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
));
275 memset (p
->grip
, 0, sizeof(p
->grip
));
279 set_timeout (const unsigned char *md5file
, int timeout
, int defer
)
281 MUTEX_LOCK (&cache_mutex
);
282 file_cache_t
*p
= get_entry (md5file
);
287 MUTEX_UNLOCK (&cache_mutex
);
288 return GPG_ERR_NOT_FOUND
;
292 if (p
->timeout
== -1 || timeout
== -1)
293 p
->timeout
= timeout
;
295 if (!timeout
|| defer
)
299 send_status_all (STATUS_CACHE
, NULL
);
302 MUTEX_UNLOCK (&cache_mutex
);
307 cache_set_data (const unsigned char *md5file
, struct cache_data_s
* data
,
308 const unsigned char *grip
)
310 MUTEX_LOCK (&cache_mutex
);
311 file_cache_t
*p
= get_entry (md5file
);
317 set_timeout (md5file
, p
->reset
, p
->defer_clear
);
321 send_status_all (STATUS_CACHE
, NULL
);
325 MUTEX_UNLOCK (&cache_mutex
);
326 return p
? 0 : GPG_ERR_NO_DATA
;
329 struct cache_data_s
*
330 cache_get_data (const unsigned char *md5file
)
332 MUTEX_LOCK (&cache_mutex
);
333 file_cache_t
*p
= get_entry (md5file
);
335 MUTEX_UNLOCK (&cache_mutex
);
336 return p
? p
->data
: NULL
;
340 struct cache_data_s
*
341 cache_get_data_filename (const char *filename
)
343 unsigned char md5file
[16];
345 gcry_md_hash_buffer (GCRY_MD_MD5
, md5file
, filename
, strlen (filename
));
346 return cache_get_data (md5file
);
350 cache_add_file (const unsigned char *md5file
, const unsigned char *grip
,
351 struct cache_data_s
*data
, int timeout
)
353 MUTEX_LOCK (&cache_mutex
);
354 file_cache_t
*p
= get_entry (md5file
);
363 b
= set_timeout (md5file
, timeout
, p
->defer_clear
) == 0 ? 1 : 0;
364 MUTEX_UNLOCK (&cache_mutex
);
365 send_status_all (STATUS_CACHE
, NULL
);
369 p
= xcalloc (1, sizeof (file_cache_t
));
372 MUTEX_UNLOCK (&cache_mutex
);
376 p
->mutex
= (pthread_mutex_t
*) xmalloc (sizeof (pthread_mutex_t
));
380 MUTEX_UNLOCK (&cache_mutex
);
384 pthread_mutexattr_t attr
;
385 pthread_mutexattr_init (&attr
);
386 pthread_mutexattr_settype (&attr
, PTHREAD_MUTEX_RECURSIVE
);
387 pthread_mutex_init (p
->mutex
, &attr
);
388 pthread_mutexattr_destroy (&attr
);
389 memcpy (p
->filename
, md5file
, sizeof (p
->filename
));
391 p
->reset
= p
->timeout
= timeout
;
394 new = slist_append (key_cache
, p
);
397 pthread_mutex_destroy (p
->mutex
);
400 MUTEX_UNLOCK (&cache_mutex
);
405 MUTEX_UNLOCK (&cache_mutex
);
406 send_status_all (STATUS_CACHE
, NULL
);
411 clear_once (file_cache_t
* p
)
413 gpg_error_t rc
= free_data_fn (p
);
415 if (!rc
&& valid_grip (p
))
418 if (use_agent
&& valid_agent_grip (p
))
420 rc
= send_to_agent (cache_agent
, NULL
, NULL
,
421 "CLEAR_PASSPHRASE --mode=normal %s", p
->grip
);
423 log_write ("%s(): %s", __FUNCTION__
, pwmd_strerror (rc
));
426 memset (p
->grip
, 0, sizeof (p
->grip
));
433 free_entry (file_cache_t
* p
)
442 log_write ("%s(): %s", __FUNCTION__
, pwmd_strerror (rc
));
446 pthread_mutex_destroy (p
->mutex
);
450 key_cache
= slist_remove (key_cache
, p
);
455 cache_clear (const unsigned char *md5file
)
461 MUTEX_LOCK (&cache_mutex
);
465 p
= get_entry (md5file
);
468 MUTEX_UNLOCK (&cache_mutex
);
472 pthread_cleanup_push (cleanup_mutex_cb
, &cache_mutex
);
474 pthread_cleanup_pop (1);
476 log_write ("%s(): %s", __FUNCTION__
, pwmd_strerror (rc
));
481 pthread_cleanup_push (cleanup_mutex_cb
, &cache_mutex
);
482 t
= slist_length (key_cache
);
483 for (i
= 0; i
< t
; i
++)
485 p
= slist_nth_data (key_cache
, i
);
489 pthread_cleanup_pop (1);
494 cache_iscached (const char *filename
, int *defer
)
497 unsigned char md5file
[16];
499 if (access (filename
, R_OK
) == -1)
500 return gpg_error_from_syserror ();
502 MUTEX_LOCK (&cache_mutex
);
503 pthread_cleanup_push (cleanup_mutex_cb
, &cache_mutex
);
504 gcry_md_hash_buffer (GCRY_MD_MD5
, md5file
, filename
, strlen (filename
));
505 rc
= iscached (md5file
, defer
);
506 pthread_cleanup_pop (1);
511 cache_defer_clear (const unsigned char *md5file
)
513 MUTEX_LOCK (&cache_mutex
);
514 file_cache_t
*p
= get_entry (md5file
);
518 rc
= GPG_ERR_NOT_FOUND
;
522 MUTEX_UNLOCK (&cache_mutex
);
527 cache_set_timeout (const unsigned char *md5file
, int timeout
)
529 return set_timeout (md5file
, timeout
, 0);
533 cache_get_grip (const unsigned char *md5file
, unsigned char *grip
)
535 MUTEX_LOCK (&cache_mutex
);
536 file_cache_t
*p
= get_entry (md5file
);
538 if (!p
|| !valid_grip (p
))
540 MUTEX_UNLOCK (&cache_mutex
);
544 memcpy (grip
, p
->grip
, sizeof (p
->grip
));
545 MUTEX_UNLOCK (&cache_mutex
);
549 /* The with_pkcs parameter is needed to prevent clearing gpg-agent
550 cached keys during an atfork callback since the agent is still
551 shared between the two processes. */
553 cache_deinit (int atfork
)
555 MUTEX_LOCK (&cache_mutex
);
556 int i
, t
= slist_length (key_cache
);
558 pthread_cleanup_push (cleanup_mutex_cb
, &cache_mutex
);
559 for (i
= 0; i
< t
; i
++)
561 file_cache_t
*p
= slist_nth_data (key_cache
, i
);
564 if (atfork
&& valid_agent_grip (p
))
569 t
= slist_length (key_cache
);
574 if (use_agent
&& cache_agent
)
575 cleanup_agent (cache_agent
);
579 gcry_free (cache_key
);
583 pthread_cleanup_pop (1);
584 pthread_mutex_destroy (&cache_mutex
);
590 pthread_mutexattr_t attr
;
592 pthread_mutexattr_init (&attr
);
593 pthread_mutexattr_settype (&attr
, PTHREAD_MUTEX_RECURSIVE
);
594 pthread_mutex_init (&cache_mutex
, &attr
);
595 pthread_mutexattr_destroy (&attr
);
599 cache_init (free_data_fn_t fn
)
605 rc
= gcry_cipher_algo_info (GCRY_CIPHER_AES
, GCRYCTL_GET_BLKLEN
, NULL
,
610 rc
= gcry_cipher_algo_info (GCRY_CIPHER_AES
, GCRYCTL_GET_KEYLEN
, NULL
,
615 cache_key
= gcry_malloc (cache_keysize
);
617 return GPG_ERR_ENOMEM
;
619 cache_iv
= xmalloc (cache_blocksize
);
622 gcry_free (cache_key
);
624 return GPG_ERR_ENOMEM
;
627 gcry_create_nonce (cache_key
, cache_keysize
);
628 gcry_create_nonce (cache_iv
, cache_blocksize
);
632 if (use_agent
&& !cache_agent
)
634 rc
= agent_init (&cache_agent
);
639 rc
= send_to_agent (cache_agent
, &line
, NULL
, "GETINFO version");
642 char **fields
= str_split (line
, ".", 0);
645 major
= atoi (fields
[0]);
646 minor
= atoi (fields
[1]);
647 if (major
< 2 || minor
< 1)
648 rc
= GPG_ERR_UNKNOWN_VERSION
;
664 cache_is_shadowed (const char *grip
)
666 MUTEX_LOCK (&cache_mutex
);
671 pthread_cleanup_push (cleanup_mutex_cb
, &cache_mutex
);
672 rc
= send_to_agent (cache_agent
, &line
, &len
, "KEYINFO --data %s", grip
);
673 pthread_cleanup_pop (1);
677 char **fields
= str_split (line
, " ", 0);
679 rc
= (*fields
[1] == 'T') ? 0 : GPG_ERR_NO_DATA
;
691 MUTEX_LOCK (&cache_mutex
);
697 MUTEX_UNLOCK (&cache_mutex
);
701 free_cache_data_once (struct cache_data_s
*data
)
708 gcry_sexp_release (data
->pubkey
);
711 gcry_free (data
->doc
);
712 gcry_free (data
->key
);