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

Contents of /trunk/Src/wptPassCache.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 48 - (show annotations)
Mon Oct 31 21:14:11 2005 UTC (19 years, 4 months ago) by werner
File size: 7461 byte(s)
More changes.  Compiles again but there are at least gettext issues with
w32-gettext.c.  I can't get a gpg-error build with ENABLE_NLS.

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

Properties

Name Value
svn:eol-style native

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26