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

Contents of /trunk/Src/wptPassCache.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 23 - (show annotations)
Fri Sep 30 10:10:16 2005 UTC (19 years, 5 months ago) by twoaday
File size: 7470 byte(s)
Almost finished phase 1 of the WinPT GPGME port.
Still need more cleanup, comments and tests.


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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26