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

Contents of /trunk/Src/wptPassCache.cpp

Parent Directory Parent Directory | Revision Log Revision Log


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


1 /* wptPassCache.cpp - keep a cache of passphrases
2 * Copyright (C) 2002 Free Software Foundation, Inc.
3 * Copyright (C) 2003, 2006 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 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #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 #include "wptTypes.h"
34 #include "wptErrors.h"
35 #include "wptAgent.h"
36
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 struct secret_data_s * pw;
52 size_t pwlen;
53 char key[1];
54 };
55
56
57 static ITEM thecache;
58
59
60 static void
61 release_data (struct secret_data_s *data)
62 {
63 free (data);
64 }
65
66
67 static struct secret_data_s *
68 new_data (const void * data, size_t length)
69 {
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 if( !r->lockcount && r->pw && r->accessed + r->ttl < current ) {
99 wipememory (r->pw, r->pwlen);
100 release_data (r->pw);
101 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 if( !r->lockcount && r->pw && r->created + 60*60 < current ) {
110 wipememory (r->pw, r->pwlen);
111 release_data (r->pw);
112 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 if (r->lockcount) {
122 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 agent_flush_cache (void)
147 {
148 ITEM r;
149
150 for (r=thecache; r; r = r->next) {
151 if( !r->lockcount && r->pw ) {
152 wipememory (r->pw, r->pwlen);
153 release_data (r->pw);
154 r->pw = NULL;
155 r->accessed = 0;
156 }
157 else if (r->lockcount && r->pw) {
158 r->accessed = 0;
159 r->ttl = 0;
160 }
161 }
162 }
163
164
165 /* 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
173 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 /* 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 if( r->pw ) {
206 wipememory (r->pw, r->pwlen);
207 release_data( r->pw );
208 r->pw = NULL;
209 }
210 if (data) {
211 r->created = r->accessed = time( NULL );
212 r->ttl = ttl;
213 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 r->ttl = ttl;
227 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 agent_get_cache (const char *key, void **cache_id)
244 {
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 if( !r->lockcount )
285 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