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

Contents of /trunk/Src/wptPassCache.cpp

Parent Directory Parent Directory | Revision Log Revision Log


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

Properties

Name Value
svn:eol-style native

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26