~ubuntu-branches/ubuntu/jaunty/gnupg2/jaunty

« back to all changes in this revision

Viewing changes to agent/cache.c

  • Committer: Bazaar Package Importer
  • Author(s): Andreas Mueller
  • Date: 2005-03-29 10:30:32 UTC
  • Revision ID: james.westby@ubuntu.com-20050329103032-sj42n2ain3ipx310
Tags: upstream-1.9.15
ImportĀ upstreamĀ versionĀ 1.9.15

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* cache.c - keep a cache of passphrases
 
2
 *      Copyright (C) 2002 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 2 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, write to the Free Software
 
18
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
 
19
 */
 
20
 
 
21
#include <config.h>
 
22
 
 
23
#include <stdio.h>
 
24
#include <stdlib.h>
 
25
#include <string.h>
 
26
#include <time.h>
 
27
#include <assert.h>
 
28
 
 
29
#include "agent.h"
 
30
 
 
31
struct secret_data_s {
 
32
  int  totallen; /* this includes the padding */
 
33
  int  datalen;  /* actual data length */
 
34
  char data[1];
 
35
};
 
36
 
 
37
typedef struct cache_item_s *ITEM;
 
38
struct cache_item_s {
 
39
  ITEM next;
 
40
  time_t created;
 
41
  time_t accessed;
 
42
  int ttl;  /* max. lifetime given in seconds, -1 one means infinite */
 
43
  int lockcount;
 
44
  struct secret_data_s *pw;
 
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
/* check whether there are items to expire */
 
82
static void
 
83
housekeeping (void)
 
84
{
 
85
  ITEM r, rprev;
 
86
  time_t current = gnupg_get_time ();
 
87
 
 
88
  /* first expire the actual data */
 
89
  for (r=thecache; r; r = r->next)
 
90
    {
 
91
      if (!r->lockcount && r->pw
 
92
          && r->ttl >= 0 && r->accessed + r->ttl < current)
 
93
        {
 
94
          if (DBG_CACHE)
 
95
            log_debug ("  expired `%s' (%ds after last access)\n",
 
96
                       r->key, r->ttl);
 
97
          release_data (r->pw);
 
98
          r->pw = NULL;
 
99
          r->accessed = current;
 
100
        }
 
101
    }
 
102
 
 
103
  /* second, make sure that we also remove them based on the created stamp so
 
104
     that the user has to enter it from time to time.  We do this every hour */
 
105
  for (r=thecache; r; r = r->next)
 
106
    {
 
107
      if (!r->lockcount && r->pw && r->created + opt.max_cache_ttl < current)
 
108
        {
 
109
          if (DBG_CACHE)
 
110
            log_debug ("  expired `%s' (%lus after creation)\n",
 
111
                       r->key, opt.max_cache_ttl);
 
112
          release_data (r->pw);
 
113
          r->pw = NULL;
 
114
          r->accessed = current;
 
115
        }
 
116
    }
 
117
 
 
118
  /* third, make sure that we don't have too many items in the list.
 
119
     Expire old and unused entries after 30 minutes */
 
120
  for (rprev=NULL, r=thecache; r; )
 
121
    {
 
122
      if (!r->pw && r->ttl >= 0 && r->accessed + 60*30 < current)
 
123
        {
 
124
          if (r->lockcount)
 
125
            {
 
126
              log_error ("can't remove unused cache entry `%s' due to"
 
127
                         " lockcount=%d\n",
 
128
                         r->key, r->lockcount);
 
129
              r->accessed += 60*10; /* next error message in 10 minutes */
 
130
              rprev = r;
 
131
              r = r->next;
 
132
            }
 
133
          else
 
134
            {
 
135
              ITEM r2 = r->next;
 
136
              if (DBG_CACHE)
 
137
                log_debug ("  removed `%s' (slot not used for 30m)\n", r->key);
 
138
              xfree (r);
 
139
              if (!rprev)
 
140
                thecache = r2;
 
141
              else
 
142
                rprev->next = r2;
 
143
              r = r2;
 
144
            }
 
145
        }
 
146
      else
 
147
        {
 
148
          rprev = r;
 
149
          r = r->next;
 
150
        }
 
151
    }
 
152
}
 
153
 
 
154
 
 
155
void
 
156
agent_flush_cache (void)
 
157
{
 
158
  ITEM r;
 
159
 
 
160
  if (DBG_CACHE)
 
161
    log_debug ("agent_flush_cache\n");
 
162
 
 
163
  for (r=thecache; r; r = r->next)
 
164
    {
 
165
      if (!r->lockcount && r->pw)
 
166
        {
 
167
          if (DBG_CACHE)
 
168
            log_debug ("  flushing `%s'\n", r->key);
 
169
          release_data (r->pw);
 
170
          r->pw = NULL;
 
171
          r->accessed = 0;
 
172
        }
 
173
      else if (r->lockcount && r->pw)
 
174
        {
 
175
          if (DBG_CACHE)
 
176
            log_debug ("    marked `%s' for flushing\n", r->key);
 
177
          r->accessed = 0;
 
178
          r->ttl = 0;
 
179
        }
 
180
    }
 
181
}
 
182
 
 
183
 
 
184
 
 
185
/* Store DATA of length DATALEN in the cache under KEY and mark it
 
186
   with a maximum lifetime of TTL seconds.  If there is already data
 
187
   under this key, it will be replaced.  Using a DATA of NULL deletes
 
188
   the entry.  A TTL of 0 is replaced by the default TTL and a TTL of
 
189
   -1 set infinite timeout. */
 
190
int
 
191
agent_put_cache (const char *key, const char *data, int ttl)
 
192
{
 
193
  ITEM r;
 
194
 
 
195
  if (DBG_CACHE)
 
196
    log_debug ("agent_put_cache `%s' requested ttl=%d\n", key, ttl);
 
197
  housekeeping ();
 
198
 
 
199
  if (!ttl)
 
200
    ttl = opt.def_cache_ttl;
 
201
  if (!ttl)
 
202
    return 0;
 
203
 
 
204
  for (r=thecache; r; r = r->next)
 
205
    {
 
206
      if (!r->lockcount && !strcmp (r->key, key))
 
207
        break;
 
208
    }
 
209
  if (r)
 
210
    { /* replace */
 
211
      if (r->pw)
 
212
        {
 
213
          release_data (r->pw);
 
214
          r->pw = NULL;
 
215
        }
 
216
      if (data)
 
217
        {
 
218
          r->created = r->accessed = gnupg_get_time (); 
 
219
          r->ttl = ttl;
 
220
          r->pw = new_data (data, strlen (data)+1);
 
221
          if (!r->pw)
 
222
            log_error ("out of core while allocating new cache item\n");
 
223
        }
 
224
    }
 
225
  else if (data)
 
226
    { /* simply insert */
 
227
      r = xtrycalloc (1, sizeof *r + strlen (key));
 
228
      if (!r)
 
229
        log_error ("out of core while allocating new cache control\n");
 
230
      else
 
231
        {
 
232
          strcpy (r->key, key);
 
233
          r->created = r->accessed = gnupg_get_time (); 
 
234
          r->ttl = ttl;
 
235
          r->pw = new_data (data, strlen (data)+1);
 
236
          if (!r->pw)
 
237
            {
 
238
              log_error ("out of core while allocating new cache item\n");
 
239
              xfree (r);
 
240
            }
 
241
          else
 
242
            {
 
243
              r->next = thecache;
 
244
              thecache = r;
 
245
            }
 
246
        }
 
247
    }
 
248
  return 0;
 
249
}
 
250
 
 
251
 
 
252
/* Try to find an item in the cache */
 
253
const char *
 
254
agent_get_cache (const char *key, void **cache_id)
 
255
{
 
256
  ITEM r;
 
257
 
 
258
  if (DBG_CACHE)
 
259
    log_debug ("agent_get_cache `%s'...\n", key);
 
260
  housekeeping ();
 
261
 
 
262
  /* first try to find one with no locks - this is an updated cache
 
263
     entry: We might have entries with a lockcount and without a
 
264
     lockcount. */
 
265
  for (r=thecache; r; r = r->next)
 
266
    {
 
267
      if (!r->lockcount && r->pw && !strcmp (r->key, key))
 
268
        {
 
269
          /* put_cache does only put strings into the cache, so we
 
270
             don't need the lengths */
 
271
          r->accessed = gnupg_get_time ();
 
272
          if (DBG_CACHE)
 
273
            log_debug ("... hit\n");
 
274
          r->lockcount++;
 
275
          *cache_id = r;
 
276
          return r->pw->data;
 
277
        }
 
278
    }
 
279
  /* again, but this time get even one with a lockcount set */
 
280
  for (r=thecache; r; r = r->next)
 
281
    {
 
282
      if (r->pw && !strcmp (r->key, key))
 
283
        {
 
284
          r->accessed = gnupg_get_time ();
 
285
          if (DBG_CACHE)
 
286
            log_debug ("... hit (locked)\n");
 
287
          r->lockcount++;
 
288
          *cache_id = r;
 
289
          return r->pw->data;
 
290
        }
 
291
    }
 
292
  if (DBG_CACHE)
 
293
    log_debug ("... miss\n");
 
294
 
 
295
  *cache_id = NULL;
 
296
  return NULL;
 
297
}
 
298
 
 
299
 
 
300
void
 
301
agent_unlock_cache_entry (void **cache_id)
 
302
{
 
303
  ITEM r;
 
304
 
 
305
  for (r=thecache; r; r = r->next)
 
306
    {
 
307
      if (r == *cache_id)
 
308
        {
 
309
          if (!r->lockcount)
 
310
            log_error ("trying to unlock non-locked cache entry `%s'\n",
 
311
                       r->key);
 
312
          else
 
313
            r->lockcount--;
 
314
          return;
 
315
        }
 
316
    }
 
317
}