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

Annotation of /trunk/Src/wptPassCache.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2 - (hide annotations)
Mon Jan 31 11:02:21 2005 UTC (20 years, 1 month ago) by twoaday
File size: 7473 byte(s)
WinPT initial checkin.


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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26