/[winpt]/trunk/Src/wptPassCache.cpp
ViewVC logotype

Annotation of /trunk/Src/wptPassCache.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 273 - (hide annotations)
Fri Dec 8 10:22:17 2006 UTC (18 years, 2 months ago) by twoaday
File size: 7289 byte(s)


1 twoaday 273 /* wptPassCache.cpp - keep a cache of passphrases
2 werner 36 * Copyright (C) 2002 Free Software Foundation, Inc.
3 twoaday 273 * Copyright (C) 2003, 2006 Timo Schulz
4 twoaday 2 *
5     * This file is part of WinPT.
6     *
7     * WinPT 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.
11     *
12     * WinPT 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.
16     *
17     * You should have received a copy of the GNU General Public License
18 werner 36 * along with WinPT; if not, write to the Free Software Foundation,
19 twoaday 2 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
20 werner 36 */
21 twoaday 273
22 werner 36 #ifdef HAVE_CONFIG_H
23     #include <config.h>
24     #endif
25    
26 twoaday 2 #include <windows.h>
27     #include <stdio.h>
28     #include <stdlib.h>
29     #include <string.h>
30     #include <time.h>
31     #include <assert.h>
32    
33 werner 36 #include "wptTypes.h"
34     #include "wptErrors.h"
35     #include "wptAgent.h"
36 twoaday 2
37    
38     struct secret_data_s {
39     int totallen; /* this includes the padding */
40     int datalen; /* actual data length */
41     char data[1];
42     };
43    
44     typedef struct cache_item_s *ITEM;
45     struct cache_item_s {
46     ITEM next;
47     time_t created;
48     time_t accessed;
49     int ttl; /* max. lifetime given in seconds */
50     int lockcount;
51 werner 36 struct secret_data_s * pw;
52 twoaday 2 size_t pwlen;
53     char key[1];
54     };
55    
56    
57     static ITEM thecache;
58    
59    
60     static void
61 twoaday 273 release_data (struct secret_data_s *data)
62 twoaday 2 {
63 twoaday 25 free (data);
64 werner 36 }
65 twoaday 2
66    
67     static struct secret_data_s *
68 twoaday 25 new_data (const void * data, size_t length)
69 twoaday 2 {
70     struct secret_data_s * d;
71     int total;
72    
73     /* we pad the data to 32 bytes so that it get more complicated
74     finding something out by watching allocation patterns. This is
75     usally not possible but we better assume nothing about our
76     secure storage provider*/
77     total = length + 32 - (length % 32);
78    
79     d = (secret_data_s *)malloc( sizeof *d + total - 1 );
80     if( d ) {
81     d->totallen = total;
82     d->datalen = length;
83     memcpy( d->data, data, length );
84     }
85     return d;
86     }
87    
88    
89     /* check whether there are items to expire */
90     static void
91     housekeeping( void )
92     {
93     ITEM r, rprev;
94     time_t current = time( NULL );
95    
96     /* first expire the actual data */
97     for( r=thecache; r; r = r->next ) {
98 werner 36 if( !r->lockcount && r->pw && r->accessed + r->ttl < current ) {
99 twoaday 273 wipememory (r->pw, r->pwlen);
100     release_data (r->pw);
101 twoaday 2 r->pw = NULL;
102     r->accessed = current;
103     }
104     }
105    
106     /* second, make sure that we also remove them based on the created stamp so
107     that the user has to enter it from time to time. We do this every hour */
108     for( r=thecache; r; r = r->next ) {
109 werner 36 if( !r->lockcount && r->pw && r->created + 60*60 < current ) {
110 twoaday 273 wipememory (r->pw, r->pwlen);
111     release_data (r->pw);
112 twoaday 2 r->pw = NULL;
113     r->accessed = current;
114     }
115     }
116    
117     /* third, make sure that we don't have too many items in the list.
118     Expire old and unused entries after 30 minutes */
119     for( rprev=NULL, r=thecache; r; ) {
120     if (!r->pw && r->accessed + 60*30 < current) {
121 werner 36 if (r->lockcount) {
122 twoaday 2 BUG( NULL );
123     r->accessed += 60*10; /* next error message in 10 minutes */
124     rprev = r;
125     r = r->next;
126     }
127     else {
128     ITEM r2 = r->next;
129     free (r);
130     if( !rprev )
131     thecache = r2;
132     else
133     rprev->next = r2;
134     r = r2;
135     }
136     }
137     else {
138     rprev = r;
139     r = r->next;
140     }
141     }
142     }
143    
144    
145     void
146 twoaday 25 agent_flush_cache (void)
147 twoaday 2 {
148     ITEM r;
149    
150 twoaday 25 for (r=thecache; r; r = r->next) {
151 werner 36 if( !r->lockcount && r->pw ) {
152 twoaday 273 wipememory (r->pw, r->pwlen);
153 twoaday 25 release_data (r->pw);
154 twoaday 2 r->pw = NULL;
155     r->accessed = 0;
156     }
157 twoaday 25 else if (r->lockcount && r->pw) {
158 twoaday 2 r->accessed = 0;
159     r->ttl = 0;
160     }
161     }
162     }
163    
164    
165 werner 36 /* Try to find the item given by key and set the TTL value to zero.
166     This means the item expires the next time the passphrase cache is used. */
167     int
168     agent_del_cache( const char * key )
169     {
170     void * item;
171     ITEM r;
172 twoaday 2
173 werner 36 if( agent_get_cache( key, &item ) ) {
174     r = (ITEM)item;
175     if( r )
176     r->ttl = 0;
177     agent_unlock_cache_entry( &item );
178     return 0;
179     }
180     return -1;
181     }
182    
183    
184 twoaday 2 /* Store DATA of length DATALEN in the cache under KEY and mark it
185     with a maximum lifetime of TTL seconds. If there is already data
186     under this key, it will be replaced. Using a DATA of NULL deletes
187     the entry */
188     int
189     agent_put_cache( const char * key, const char * data, int ttl )
190     {
191     ITEM r;
192    
193     housekeeping ();
194    
195     if (ttl < 1)
196     ttl = 5*60;
197     if (!ttl)
198     return 0;
199    
200     for (r=thecache; r; r = r->next) {
201     if (!r->lockcount && !strcmp (r->key, key))
202     break;
203     }
204     if( r ) { /* replace */
205 werner 36 if( r->pw ) {
206 twoaday 273 wipememory (r->pw, r->pwlen);
207 twoaday 2 release_data( r->pw );
208     r->pw = NULL;
209     }
210     if (data) {
211     r->created = r->accessed = time( NULL );
212 werner 36 r->ttl = ttl;
213 twoaday 2 r->pwlen = strlen( data );
214     r->pw = new_data( data, r->pwlen+1 );
215     if (!r->pw)
216     BUG( NULL );
217     }
218     }
219     else if (data) { /* simply insert */
220     r = (ITEM)calloc (1, sizeof *r + strlen (key));
221     if (!r)
222     BUG( NULL );
223     else {
224     strcpy (r->key, key);
225     r->created = r->accessed = time( NULL );
226 werner 36 r->ttl = ttl;
227 twoaday 2 r->pwlen = strlen( data );
228     r->pw = new_data( data, r->pwlen+1 );
229     if (!r->pw)
230     BUG( NULL );
231     else {
232     r->next = thecache;
233     thecache = r;
234     }
235     }
236     }
237     return 0;
238     }
239    
240    
241     /* Try to find an item in the cache */
242     const char *
243 twoaday 25 agent_get_cache (const char *key, void **cache_id)
244 twoaday 2 {
245     ITEM r;
246    
247     housekeeping ();
248    
249     /* first try to find one with no locks - this is an updated cache
250     entry: We might have entries with a lockcount and without a
251     lockcount. */
252     for (r=thecache; r; r = r->next) {
253     if (!r->lockcount && r->pw && !strcmp (r->key, key)) {
254     /* put_cache does only put strings into the cache, so we
255     don't need the lengths */
256     r->accessed = time (NULL);
257     r->lockcount++;
258     *cache_id = r;
259     return r->pw->data;
260     }
261     }
262     /* again, but this time get even one with a lockcount set */
263     for (r=thecache; r; r = r->next) {
264     if (r->pw && !strcmp (r->key, key)) {
265     r->accessed = time (NULL);
266     r->lockcount++;
267     *cache_id = r;
268     return r->pw->data;
269     }
270     }
271    
272     *cache_id = NULL;
273     return NULL;
274     }
275    
276    
277     void
278     agent_unlock_cache_entry( void ** cache_id )
279     {
280     ITEM r;
281    
282     for( r=thecache; r; r = r->next ) {
283     if( r == *cache_id ) {
284 werner 36 if( !r->lockcount )
285 twoaday 2 BUG( NULL );
286     else
287     r->lockcount--;
288     return;
289     }
290     }
291     }

Properties

Name Value
svn:eol-style native

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26