s/CACHE_MODE_IMPGEN/CACHE_MODE_NONCE/.
[gnupg.git] / agent / cache.c
1 /* cache.c - keep a cache of passphrases
2  * Copyright (C) 2002, 2010 Free Software Foundation, Inc.
3  *
4  * This file is part of GnuPG.
5  *
6  * GnuPG is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * GnuPG is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include <config.h>
21
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <time.h>
26 #include <assert.h>
27
28 #include "agent.h"
29
30 struct secret_data_s {
31   int  totallen; /* this includes the padding */
32   int  datalen;  /* actual data length */
33   char data[1];
34 };
35
36 typedef struct cache_item_s *ITEM;
37 struct cache_item_s {
38   ITEM next;
39   time_t created;
40   time_t accessed;
41   int ttl;  /* max. lifetime given in seconds, -1 one means infinite */
42   int lockcount;
43   struct secret_data_s *pw;
44   cache_mode_t cache_mode;
45   char key[1];
46 };
47
48
49 static ITEM thecache;
50
51
52 static void
53 release_data (struct secret_data_s *data)
54 {
55    xfree (data);
56 }
57
58 static struct secret_data_s *
59 new_data (const void *data, size_t length)
60 {
61   struct secret_data_s *d;
62   int total;
63
64   /* we pad the data to 32 bytes so that it get more complicated
65      finding something out by watching allocation patterns.  This is
66      usally not possible but we better assume nothing about our
67      secure storage provider*/
68   total = length + 32 - (length % 32);
69
70   d = gcry_malloc_secure (sizeof *d + total - 1);
71   if (d)
72     {
73       d->totallen = total;
74       d->datalen  = length;
75       memcpy (d->data, data, length);
76     }
77   return d;
78 }
79
80
81
82 /* check whether there are items to expire */
83 static void
84 housekeeping (void)
85 {
86   ITEM r, rprev;
87   time_t current = gnupg_get_time ();
88
89   /* First expire the actual data */
90   for (r=thecache; r; r = r->next)
91     {
92       if (!r->lockcount && r->pw
93           && r->ttl >= 0 && r->accessed + r->ttl < current)
94         {
95           if (DBG_CACHE)
96             log_debug ("  expired `%s' (%ds after last access)\n",
97                        r->key, r->ttl);
98           release_data (r->pw);
99           r->pw = NULL;
100           r->accessed = current;
101         }
102     }
103
104   /* Second, make sure that we also remove them based on the created stamp so
105      that the user has to enter it from time to time. */
106   for (r=thecache; r; r = r->next)
107     {
108       unsigned long maxttl;
109       
110       switch (r->cache_mode)
111         {
112         case CACHE_MODE_SSH: maxttl = opt.max_cache_ttl_ssh; break;
113         default: maxttl = opt.max_cache_ttl; break;
114         }
115       if (!r->lockcount && r->pw && r->created + maxttl < current)
116         {
117           if (DBG_CACHE)
118             log_debug ("  expired `%s' (%lus after creation)\n",
119                        r->key, opt.max_cache_ttl);
120           release_data (r->pw);
121           r->pw = NULL;
122           r->accessed = current;
123         }
124     }
125
126   /* Third, make sure that we don't have too many items in the list.
127      Expire old and unused entries after 30 minutes */
128   for (rprev=NULL, r=thecache; r; )
129     {
130       if (!r->pw && r->ttl >= 0 && r->accessed + 60*30 < current)
131         {
132           if (r->lockcount)
133             {
134               log_error ("can't remove unused cache entry `%s' (mode %d) due to"
135                          " lockcount=%d\n",
136                          r->key, r->cache_mode, r->lockcount);
137               r->accessed += 60*10; /* next error message in 10 minutes */
138               rprev = r;
139               r = r->next;
140             }
141           else
142             {
143               ITEM r2 = r->next;
144               if (DBG_CACHE)
145                 log_debug ("  removed `%s' (mode %d) (slot not used for 30m)\n",
146                            r->key, r->cache_mode);
147               xfree (r);
148               if (!rprev)
149                 thecache = r2;
150               else
151                 rprev->next = r2;
152               r = r2;
153             }
154         }
155       else
156         {
157           rprev = r;
158           r = r->next;
159         }
160     }
161 }
162
163
164 void
165 agent_flush_cache (void)
166 {
167   ITEM r;
168
169   if (DBG_CACHE)
170     log_debug ("agent_flush_cache\n");
171
172   for (r=thecache; r; r = r->next)
173     {
174       if (!r->lockcount && r->pw)
175         {
176           if (DBG_CACHE)
177             log_debug ("  flushing `%s'\n", r->key);
178           release_data (r->pw);
179           r->pw = NULL;
180           r->accessed = 0;
181         }
182       else if (r->lockcount && r->pw)
183         {
184           if (DBG_CACHE)
185             log_debug ("    marked `%s' for flushing\n", r->key);
186           r->accessed = 0;
187           r->ttl = 0;
188         }
189     }
190 }
191
192
193
194 /* Store DATA of length DATALEN in the cache under KEY and mark it
195    with a maximum lifetime of TTL seconds.  If there is already data
196    under this key, it will be replaced.  Using a DATA of NULL deletes
197    the entry.  A TTL of 0 is replaced by the default TTL and a TTL of
198    -1 set infinite timeout.  CACHE_MODE is stored with the cache entry
199    and used to select different timeouts.  */
200 int
201 agent_put_cache (const char *key, cache_mode_t cache_mode,
202                  const char *data, int ttl)
203 {
204   ITEM r;
205
206   if (DBG_CACHE)
207     log_debug ("agent_put_cache `%s' (mode %d) requested ttl=%d\n",
208                key, cache_mode, ttl);
209   housekeeping ();
210
211   if (!ttl)
212     {
213       switch(cache_mode)
214         {
215         case CACHE_MODE_SSH: ttl = opt.def_cache_ttl_ssh; break;
216         default: ttl = opt.def_cache_ttl; break;
217         }
218     }
219   if (!ttl || cache_mode == CACHE_MODE_IGNORE)
220     return 0;
221
222   for (r=thecache; r; r = r->next)
223     {
224       if (!r->lockcount
225           && ((cache_mode != CACHE_MODE_USER
226                && cache_mode != CACHE_MODE_NONCE)
227               || r->cache_mode == cache_mode)
228           && !strcmp (r->key, key))
229         break;
230     }
231   if (r)
232     { /* replace */
233       if (r->pw)
234         {
235           release_data (r->pw);
236           r->pw = NULL;
237         }
238       if (data)
239         {
240           r->created = r->accessed = gnupg_get_time (); 
241           r->ttl = ttl;
242           r->cache_mode = cache_mode;
243           r->pw = new_data (data, strlen (data)+1);
244           if (!r->pw)
245             log_error ("out of core while allocating new cache item\n");
246         }
247     }
248   else if (data)
249     { /* simply insert */
250       r = xtrycalloc (1, sizeof *r + strlen (key));
251       if (!r)
252         log_error ("out of core while allocating new cache control\n");
253       else
254         {
255           strcpy (r->key, key);
256           r->created = r->accessed = gnupg_get_time (); 
257           r->ttl = ttl;
258           r->cache_mode = cache_mode;
259           r->pw = new_data (data, strlen (data)+1);
260           if (!r->pw)
261             {
262               log_error ("out of core while allocating new cache item\n");
263               xfree (r);
264             }
265           else
266             {
267               r->next = thecache;
268               thecache = r;
269             }
270         }
271     }
272   return 0;
273 }
274
275
276 /* Try to find an item in the cache.  Note that we currently don't
277    make use of CACHE_MODE except for CACHE_MODE_NONCE and
278    CACHE_MODE_USER.  */
279 const char *
280 agent_get_cache (const char *key, cache_mode_t cache_mode, void **cache_id)
281 {
282   ITEM r;
283
284   if (cache_mode == CACHE_MODE_IGNORE)
285     return NULL;
286
287   if (DBG_CACHE)
288     log_debug ("agent_get_cache `%s' (mode %d) ...\n", key, cache_mode);
289   housekeeping ();
290
291   /* first try to find one with no locks - this is an updated cache
292      entry: We might have entries with a lockcount and without a
293      lockcount. */
294   for (r=thecache; r; r = r->next)
295     {
296       if (!r->lockcount && r->pw
297           && ((cache_mode != CACHE_MODE_USER
298                && cache_mode != CACHE_MODE_NONCE)
299               || r->cache_mode == cache_mode)
300           && !strcmp (r->key, key))
301         {
302           /* put_cache does only put strings into the cache, so we
303              don't need the lengths */
304           r->accessed = gnupg_get_time ();
305           if (DBG_CACHE)
306             log_debug ("... hit\n");
307           r->lockcount++;
308           *cache_id = r;
309           return r->pw->data;
310         }
311     }
312   /* again, but this time get even one with a lockcount set */
313   for (r=thecache; r; r = r->next)
314     {
315       if (r->pw 
316           && ((cache_mode != CACHE_MODE_USER
317                && cache_mode != CACHE_MODE_NONCE)
318               || r->cache_mode == cache_mode)
319           && !strcmp (r->key, key))
320         {
321           r->accessed = gnupg_get_time ();
322           if (DBG_CACHE)
323             log_debug ("... hit (locked)\n");
324           r->lockcount++;
325           *cache_id = r;
326           return r->pw->data;
327         }
328     }
329   if (DBG_CACHE)
330     log_debug ("... miss\n");
331
332   *cache_id = NULL;
333   return NULL;
334 }
335
336
337 void
338 agent_unlock_cache_entry (void **cache_id)
339 {
340   ITEM r;
341
342   for (r=thecache; r; r = r->next)
343     {
344       if (r == *cache_id)
345         {
346           if (!r->lockcount)
347             log_error ("trying to unlock non-locked cache entry `%s'\n",
348                        r->key);
349           else
350             r->lockcount--;
351           return;
352         }
353     }
354 }