|
|
1.1.1.5 root 1: /*
1.1.1.7 root 2: Copyright (c) 2005 TrueCrypt Foundation. All rights reserved.
1.1 root 3:
1.1.1.9 root 4: Governed by the TrueCrypt License 2.6 the full text of which is contained
1.1.1.5 root 5: in the file License.txt included in TrueCrypt binary and source code
6: distribution packages.
1.1 root 7: */
8:
1.1.1.5 root 9: #include <stdlib.h>
10: #include <string.h>
1.1 root 11: #include <sys/stat.h>
12: #include <sys/types.h>
13:
14: #include "Tcdefs.h"
15: #include "Keyfiles.h"
16: #include "Crc.h"
17:
18: #include <io.h>
19: #include "Dlgcode.h"
20: #include "Language.h"
1.1.1.9 root 21: #include "SecurityToken.h"
22: #include "Common/resource.h"
23: #include "Platform/ForEach.h"
24:
25: using namespace TrueCrypt;
1.1 root 26:
27: #define stat _stat
28: #define S_IFDIR _S_IFDIR
29: #define snprintf _snprintf
30:
31:
32: KeyFile *KeyFileAdd (KeyFile *firstKeyFile, KeyFile *keyFile)
33: {
34: KeyFile *kf = firstKeyFile;
35:
36: if (firstKeyFile != NULL)
37: {
38: while (kf->Next)
39: kf = kf->Next;
40:
41: kf->Next = keyFile;
42: }
43: else
44: firstKeyFile = keyFile;
45:
46: keyFile->Next = NULL;
47:
48: return firstKeyFile;
49: }
50:
51:
52: // Returns first keyfile, NULL if last keyfile was removed
53: static KeyFile *KeyFileRemove (KeyFile *firstKeyFile, KeyFile *keyFile)
54: {
55: KeyFile *prevkf = NULL, *kf = firstKeyFile;
56:
57: if (firstKeyFile == NULL) return NULL;
58: do
59: {
60: if (kf == keyFile)
61: {
62: if (prevkf == NULL)
63: firstKeyFile = kf->Next;
64: else
65: prevkf->Next = kf->Next;
66:
1.1.1.7 root 67: burn (keyFile, sizeof(*keyFile)); // wipe
1.1 root 68: free (keyFile);
69: break;
70: }
71: prevkf = kf;
72: }
73: while (kf = kf->Next);
74:
75: return firstKeyFile;
76: }
77:
78:
79: void KeyFileRemoveAll (KeyFile **firstKeyFile)
80: {
81: KeyFile *kf = *firstKeyFile;
82: while (kf != NULL)
83: {
84: KeyFile *d = kf;
85: kf = kf->Next;
86: burn (d, sizeof(*d)); // wipe
87: free (d);
88: }
89:
90: *firstKeyFile = NULL;
91: }
92:
93:
94: KeyFile *KeyFileClone (KeyFile *keyFile)
95: {
96: KeyFile *clone;
97:
98: if (keyFile == NULL) return NULL;
99:
1.1.1.9 root 100: clone = (KeyFile *) malloc (sizeof (KeyFile));
1.1 root 101: strcpy (clone->FileName, keyFile->FileName);
102: clone->Next = NULL;
103: return clone;
104: }
105:
106:
107: KeyFile *KeyFileCloneAll (KeyFile *firstKeyFile)
108: {
109: KeyFile *cloneFirstKeyFile = KeyFileClone (firstKeyFile);
110: KeyFile *kf;
111:
112: if (firstKeyFile == NULL) return NULL;
113: kf = firstKeyFile->Next;
114: while (kf != NULL)
115: {
116: KeyFileAdd (cloneFirstKeyFile, KeyFileClone (kf));
117: kf = kf->Next;
118: }
119:
120: return cloneFirstKeyFile;
121: }
122:
123:
1.1.1.6 root 124: static BOOL KeyFileProcess (unsigned __int8 *keyPool, KeyFile *keyFile)
1.1 root 125: {
126: FILE *f;
127: unsigned __int8 buffer[64 * 1024];
128: unsigned __int32 crc = 0xffffffff;
129: int writePos = 0;
130: size_t bytesRead, totalRead = 0;
1.1.1.6 root 131: int status = TRUE;
1.1 root 132:
133: HANDLE src;
134: FILETIME ftCreationTime;
135: FILETIME ftLastWriteTime;
136: FILETIME ftLastAccessTime;
137:
138: BOOL bTimeStampValid = FALSE;
139:
1.1.1.6 root 140: /* Remember the last access time of the keyfile. It will be preserved in order to prevent
141: an adversary from determining which file may have been used as keyfile. */
142: src = CreateFile (keyFile->FileName,
143: GENERIC_READ | GENERIC_WRITE,
144: FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
1.1 root 145:
1.1.1.6 root 146: if (src != INVALID_HANDLE_VALUE)
147: {
148: if (GetFileTime ((HANDLE) src, &ftCreationTime, &ftLastAccessTime, &ftLastWriteTime))
149: bTimeStampValid = TRUE;
150: else
151: Warning ("GETFILETIME_FAILED_KEYFILE");
152: }
1.1 root 153:
154: f = fopen (keyFile->FileName, "rb");
155: if (f == NULL) return FALSE;
156:
157: while ((bytesRead = fread (buffer, 1, sizeof (buffer), f)) > 0)
158: {
159: size_t i;
160:
1.1.1.6 root 161: if (ferror (f))
162: {
163: status = FALSE;
164: goto close;
165: }
166:
1.1 root 167: for (i = 0; i < bytesRead; i++)
168: {
169: crc = UPDC32 (buffer[i], crc);
170:
171: keyPool[writePos++] += (unsigned __int8) (crc >> 24);
172: keyPool[writePos++] += (unsigned __int8) (crc >> 16);
173: keyPool[writePos++] += (unsigned __int8) (crc >> 8);
174: keyPool[writePos++] += (unsigned __int8) crc;
175:
176: if (writePos >= KEYFILE_POOL_SIZE)
177: writePos = 0;
178:
179: if (++totalRead >= KEYFILE_MAX_READ_LEN)
180: goto close;
181: }
182: }
183:
1.1.1.6 root 184: if (ferror (f))
1.1.1.9 root 185: {
186: status = FALSE;
187: }
188: else if (totalRead == 0)
189: {
1.1.1.6 root 190: status = FALSE;
1.1.1.9 root 191: SetLastError (ERROR_HANDLE_EOF);
192: }
1.1.1.6 root 193:
1.1 root 194: close:
1.1.1.9 root 195: DWORD err = GetLastError();
1.1 root 196: fclose (f);
197:
1.1.1.9 root 198: if (bTimeStampValid && !IsFileOnReadOnlyFilesystem (keyFile->FileName))
1.1 root 199: {
200: // Restore the keyfile timestamp
201: if (!SetFileTime (src, &ftCreationTime, &ftLastAccessTime, &ftLastWriteTime))
202: Warning ("SETFILETIME_FAILED_KEYFILE");
203: CloseHandle (src);
204: }
205:
1.1.1.9 root 206: SetLastError (err);
1.1.1.6 root 207: return status;
1.1 root 208: }
209:
210:
1.1.1.6 root 211: BOOL KeyFilesApply (Password *password, KeyFile *firstKeyFile)
1.1 root 212: {
213: BOOL status = TRUE;
214: KeyFile kfSubStruct;
215: KeyFile *kf;
216: KeyFile *kfSub = &kfSubStruct;
217: static unsigned __int8 keyPool [KEYFILE_POOL_SIZE];
1.1.1.10! root 218: size_t i;
1.1 root 219: struct stat statStruct;
220: char searchPath [TC_MAX_PATH*2];
221: struct _finddata_t fBuf;
222: intptr_t searchHandle;
223:
224: if (firstKeyFile == NULL) return TRUE;
225:
226: VirtualLock (keyPool, sizeof (keyPool));
227: memset (keyPool, 0, sizeof (keyPool));
228:
229: for (kf = firstKeyFile; kf != NULL; kf = kf->Next)
230: {
1.1.1.9 root 231: // Determine whether it's a security token path
232: try
233: {
234: if (SecurityToken::IsKeyfilePathValid (SingleStringToWide (kf->FileName)))
235: {
236: // Apply security token keyfile
237: vector <byte> keyfileData;
238: SecurityToken::GetKeyfileData (SecurityTokenKeyfile (SingleStringToWide (kf->FileName)), keyfileData);
239:
240: if (keyfileData.empty())
241: {
242: SetLastError (ERROR_HANDLE_EOF);
243: handleWin32Error (MainDlg);
244: Error ("ERR_PROCESS_KEYFILE");
245: status = FALSE;
246: continue;
247: }
248:
249: unsigned __int32 crc = 0xffffffff;
250: int writePos = 0;
251: size_t totalRead = 0;
252:
253: for (size_t i = 0; i < keyfileData.size(); i++)
254: {
255: crc = UPDC32 (keyfileData[i], crc);
256:
257: keyPool[writePos++] += (unsigned __int8) (crc >> 24);
258: keyPool[writePos++] += (unsigned __int8) (crc >> 16);
259: keyPool[writePos++] += (unsigned __int8) (crc >> 8);
260: keyPool[writePos++] += (unsigned __int8) crc;
261:
262: if (writePos >= KEYFILE_POOL_SIZE)
263: writePos = 0;
264:
265: if (++totalRead >= KEYFILE_MAX_READ_LEN)
266: break;
267: }
268:
269: burn (&keyfileData.front(), keyfileData.size());
270: continue;
271: }
272: }
273: catch (Exception &e)
274: {
275: e.Show (NULL);
276: return FALSE;
277: }
278:
1.1 root 279: // Determine whether it's a path or a file
280: if (stat (kf->FileName, &statStruct) != 0)
281: {
1.1.1.6 root 282: handleWin32Error (MainDlg);
1.1 root 283: Error ("ERR_PROCESS_KEYFILE");
284: status = FALSE;
285: continue;
286: }
287:
288: if (statStruct.st_mode & S_IFDIR) // If it's a directory
289: {
290: /* Find and process all keyfiles in the directory */
291:
292: snprintf (searchPath, sizeof (searchPath), "%s\\*.*", kf->FileName);
293: if ((searchHandle = _findfirst (searchPath, &fBuf)) == -1)
294: {
1.1.1.6 root 295: handleWin32Error (MainDlg);
1.1 root 296: Error ("ERR_PROCESS_KEYFILE_PATH");
297: status = FALSE;
298: continue;
299: }
300:
301: do
302: {
303: snprintf (kfSub->FileName, sizeof(kfSub->FileName), "%s%c%s", kf->FileName,
304: '\\',
305: fBuf.name
306: );
307:
308: // Determine whether it's a path or a file
309: if (stat (kfSub->FileName, &statStruct) != 0)
310: {
1.1.1.6 root 311: handleWin32Error (MainDlg);
1.1 root 312: Error ("ERR_PROCESS_KEYFILE");
313: status = FALSE;
314: continue;
315: }
316: else if (statStruct.st_mode & S_IFDIR) // If it's a directory
317: {
318: // Prevent recursive folder scanning
319: continue;
320: }
321:
322:
323: // Apply keyfile to the pool
1.1.1.6 root 324: if (!KeyFileProcess (keyPool, kfSub))
1.1 root 325: {
1.1.1.6 root 326: handleWin32Error (MainDlg);
1.1 root 327: Error ("ERR_PROCESS_KEYFILE");
328: status = FALSE;
329: }
330:
331: } while (_findnext (searchHandle, &fBuf) != -1);
332: _findclose (searchHandle);
333:
334: burn (&kfSubStruct, sizeof (kfSubStruct));
335:
336: }
337: // Apply keyfile to the pool
1.1.1.6 root 338: else if (!KeyFileProcess (keyPool, kf))
1.1 root 339: {
1.1.1.6 root 340: handleWin32Error (MainDlg);
1.1 root 341: Error ("ERR_PROCESS_KEYFILE");
342: status = FALSE;
343: }
344: }
345:
346: /* Mix the keyfile pool contents into the password */
347:
1.1.1.10! root 348: for (i = 0; i < sizeof (keyPool); i++)
1.1 root 349: {
350: if (i < password->Length)
351: password->Text[i] += keyPool[i];
352: else
353: password->Text[i] = keyPool[i];
354: }
355:
356: if (password->Length < (int)sizeof (keyPool))
357: password->Length = sizeof (keyPool);
358:
359: burn (keyPool, sizeof (keyPool));
360:
361: return status;
362: }
363:
364:
365: static void LoadKeyList (HWND hwndDlg, KeyFile *firstKeyFile)
366: {
367: KeyFile *kf;
368: LVITEM LvItem;
369: int line = 0;
370: HWND hList = GetDlgItem (hwndDlg, IDC_KEYLIST);
371:
372: ListView_DeleteAllItems (hList);
373: EnableWindow (GetDlgItem (hwndDlg, IDC_KEYREMOVE), FALSE);
374: EnableWindow (GetDlgItem (hwndDlg, IDC_KEYREMOVEALL), firstKeyFile != NULL);
375: SetCheckBox (hwndDlg, IDC_KEYFILES_ENABLE, firstKeyFile != NULL);
376:
377: for (kf = firstKeyFile; kf != NULL; kf = kf->Next)
378: {
379: memset (&LvItem,0,sizeof(LvItem));
380: LvItem.mask = LVIF_TEXT|LVIF_PARAM;
381: LvItem.iItem = line++;
382: LvItem.iSubItem = 0;
383: LvItem.pszText = kf->FileName;
384: LvItem.lParam = (LPARAM) kf;
385: SendMessage (hList, LVM_INSERTITEM, 0, (LPARAM)&LvItem);
386: }
387: }
388:
389: #if KEYFILE_POOL_SIZE % 4 != 0
390: #error KEYFILE_POOL_SIZE must be a multiple of 4
391: #endif
392:
1.1.1.6 root 393: BOOL CALLBACK KeyFilesDlgProc (HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
1.1 root 394: {
395: static KeyFilesDlgParam *param;
396: static KeyFilesDlgParam origParam;
397:
398: WORD lw = LOWORD (wParam);
399:
400: switch (msg)
401: {
402: case WM_INITDIALOG:
403: {
1.1.1.2 root 404: LVCOLUMNW LvCol;
1.1 root 405: HWND hList = GetDlgItem (hwndDlg, IDC_KEYLIST);
406:
407: param = (KeyFilesDlgParam *) lParam;
408: origParam = *(KeyFilesDlgParam *) lParam;
409:
410: param->FirstKeyFile = KeyFileCloneAll (param->FirstKeyFile);
411:
412: LocalizeDialog (hwndDlg, "IDD_KEYFILES");
413: DragAcceptFiles (hwndDlg, TRUE);
414:
1.1.1.2 root 415: SendMessageW (hList,LVM_SETEXTENDEDLISTVIEWSTYLE,0,
1.1 root 416: LVS_EX_FULLROWSELECT|LVS_EX_HEADERDRAGDROP
417: );
418:
419: memset (&LvCol,0,sizeof(LvCol));
420: LvCol.mask = LVCF_TEXT|LVCF_WIDTH|LVCF_SUBITEM|LVCF_FMT;
1.1.1.2 root 421: LvCol.pszText = GetString ("KEYFILE");
1.1.1.9 root 422: LvCol.cx = CompensateXDPI (374);
1.1 root 423: LvCol.fmt = LVCFMT_LEFT;
1.1.1.2 root 424: SendMessageW (hList, LVM_INSERTCOLUMNW, 0, (LPARAM)&LvCol);
1.1 root 425:
426: LoadKeyList (hwndDlg, param->FirstKeyFile);
427: SetCheckBox (hwndDlg, IDC_KEYFILES_ENABLE, param->EnableKeyFiles);
428:
1.1.1.9 root 429: SetWindowTextW(GetDlgItem(hwndDlg, IDT_KEYFILES_NOTE), GetString ("KEYFILES_NOTE"));
1.1.1.5 root 430:
431: ToHyperlink (hwndDlg, IDC_LINK_KEYFILES_INFO);
1.1 root 432: }
433: return 1;
434:
435: case WM_COMMAND:
436:
437: if (lw == IDC_KEYADD)
438: {
1.1.1.9 root 439: KeyFile *kf = (KeyFile *) malloc (sizeof (KeyFile));
1.1.1.4 root 440: if (SelectMultipleFiles (hwndDlg, "SELECT_KEYFILE", kf->FileName, bHistory))
1.1 root 441: {
1.1.1.3 root 442: do
443: {
444: param->FirstKeyFile = KeyFileAdd (param->FirstKeyFile, kf);
445: LoadKeyList (hwndDlg, param->FirstKeyFile);
446:
1.1.1.9 root 447: kf = (KeyFile *) malloc (sizeof (KeyFile));
1.1.1.3 root 448: } while (SelectMultipleFilesNext (kf->FileName));
1.1 root 449: }
1.1.1.3 root 450:
451: free (kf);
1.1 root 452: return 1;
453: }
454:
455: if (lw == IDC_ADD_KEYFILE_PATH)
456: {
1.1.1.9 root 457: KeyFile *kf = (KeyFile *) malloc (sizeof (KeyFile));
1.1 root 458:
459: if (BrowseDirectories (hwndDlg,"SELECT_KEYFILE_PATH", kf->FileName))
460: {
461: param->FirstKeyFile = KeyFileAdd (param->FirstKeyFile, kf);
462: LoadKeyList (hwndDlg, param->FirstKeyFile);
463: }
464: else
465: {
466: free (kf);
467: }
468: return 1;
469: }
470:
1.1.1.9 root 471: if (lw == IDC_TOKEN_FILES_ADD)
472: {
473: list <SecurityTokenKeyfilePath> selectedTokenKeyfiles;
474: if (DialogBoxParamW (hInst, MAKEINTRESOURCEW (IDD_TOKEN_KEYFILES), hwndDlg, (DLGPROC) SecurityTokenKeyfileDlgProc, (LPARAM) &selectedTokenKeyfiles) == IDOK)
475: {
476: foreach (const SecurityTokenKeyfilePath &keyPath, selectedTokenKeyfiles)
477: {
478: KeyFile *kf = (KeyFile *) malloc (sizeof (KeyFile));
479: strcpy_s (kf->FileName, sizeof (kf->FileName), WideToSingleString (keyPath).c_str());
480:
481: param->FirstKeyFile = KeyFileAdd (param->FirstKeyFile, kf);
482: LoadKeyList (hwndDlg, param->FirstKeyFile);
483: }
484: }
485:
486: return 1;
487: }
488:
1.1 root 489: if (lw == IDC_KEYREMOVE)
490: {
491: HWND list = GetDlgItem (hwndDlg, IDC_KEYLIST);
492: LVITEM LvItem;
493: memset (&LvItem, 0, sizeof(LvItem));
494: LvItem.mask = LVIF_PARAM;
495: LvItem.iItem = -1;
496:
497: while (-1 != (LvItem.iItem = ListView_GetNextItem (list, LvItem.iItem, LVIS_SELECTED)))
498: {
499: ListView_GetItem (list, &LvItem);
500: param->FirstKeyFile = KeyFileRemove (param->FirstKeyFile, (KeyFile *) LvItem.lParam);
501: }
502:
503: LoadKeyList (hwndDlg, param->FirstKeyFile);
504: return 1;
505: }
506:
507: if (lw == IDC_KEYREMOVEALL)
508: {
509: KeyFileRemoveAll (¶m->FirstKeyFile);
510: LoadKeyList (hwndDlg, NULL);
511: return 1;
512: }
513:
514: if (lw == IDC_GENERATE_KEYFILE)
515: {
516: DialogBoxParamW (hInst,
517: MAKEINTRESOURCEW (IDD_KEYFILE_GENERATOR), hwndDlg,
518: (DLGPROC) KeyfileGeneratorDlgProc, (LPARAM) 0);
519: return 1;
520: }
521:
1.1.1.5 root 522: if (lw == IDC_LINK_KEYFILES_INFO)
523: {
524: Applink ("keyfiles", TRUE, "");
525: }
526:
1.1 root 527: if (lw == IDOK)
528: {
529: param->EnableKeyFiles = IsButtonChecked (GetDlgItem (hwndDlg, IDC_KEYFILES_ENABLE));
530: EndDialog (hwndDlg, IDOK);
531: return 1;
532: }
533:
534: if (lw == IDCANCEL)
535: {
536: KeyFileRemoveAll (¶m->FirstKeyFile);
537: *param = origParam;
538:
539: EndDialog (hwndDlg, IDCLOSE);
540: return 1;
541: }
542:
543: case WM_DROPFILES:
544: {
545: HDROP hdrop = (HDROP) wParam;
546:
547: int i = 0, count = DragQueryFile (hdrop, -1, NULL, 0);
548:
549: while (count-- > 0)
550: {
1.1.1.9 root 551: KeyFile *kf = (KeyFile *) malloc (sizeof (KeyFile));
1.1 root 552: DragQueryFile (hdrop, i++, kf->FileName, sizeof (kf->FileName));
553: param->FirstKeyFile = KeyFileAdd (param->FirstKeyFile, kf);
554: LoadKeyList (hwndDlg, param->FirstKeyFile);
555: }
556:
557: DragFinish (hdrop);
558: }
559: return 1;
560:
561: case WM_NOTIFY:
562: if (((LPNMHDR) lParam)->code == LVN_ITEMCHANGED)
563: {
564: EnableWindow (GetDlgItem (hwndDlg, IDC_KEYREMOVE),
565: ListView_GetNextItem (GetDlgItem (hwndDlg, IDC_KEYLIST), -1, LVIS_SELECTED) != -1);
566: return 1;
567: }
568: break;
569:
570: case WM_CLOSE:
571: KeyFileRemoveAll (¶m->FirstKeyFile);
572: *param = origParam;
573:
574: EndDialog (hwndDlg, IDCLOSE);
575: return 1;
576:
577: break;
578:
579: }
580:
581: return 0;
582: }
583:
584:
1.1.1.9 root 585: #define IDM_KEYFILES_POPUP_ADD_FILES 9001
586: #define IDM_KEYFILES_POPUP_ADD_DIR 9002
587: #define IDM_KEYFILES_POPUP_ADD_TOKEN_FILES 9003
588:
589: BOOL KeyfilesPopupMenu (HWND hwndDlg, POINT popupPosition, KeyFilesDlgParam *param)
590: {
591: HMENU popup = CreatePopupMenu ();
592: int sel;
593: BOOL status = FALSE;
594:
595: AppendMenuW (popup, MF_STRING, IDM_KEYFILES_POPUP_ADD_FILES, GetString ("IDC_KEYADD"));
596: AppendMenuW (popup, MF_STRING, IDM_KEYFILES_POPUP_ADD_DIR, GetString ("IDC_ADD_KEYFILE_PATH"));
597: AppendMenuW (popup, MF_STRING, IDM_KEYFILES_POPUP_ADD_TOKEN_FILES, GetString ("IDC_TOKEN_FILES_ADD"));
598:
599: sel = TrackPopupMenu (popup, TPM_RETURNCMD | TPM_LEFTBUTTON, popupPosition.x, popupPosition.y, 0, hwndDlg, NULL);
600:
601: switch (sel)
602: {
603: case IDM_KEYFILES_POPUP_ADD_FILES:
604: {
605: KeyFile *kf = (KeyFile *) malloc (sizeof (KeyFile));
606: if (SelectMultipleFiles (hwndDlg, "SELECT_KEYFILE", kf->FileName, bHistory))
607: {
608: do
609: {
610: param->FirstKeyFile = KeyFileAdd (param->FirstKeyFile, kf);
611: kf = (KeyFile *) malloc (sizeof (KeyFile));
612: } while (SelectMultipleFilesNext (kf->FileName));
613:
614: param->EnableKeyFiles = TRUE;
615: status = TRUE;
616: }
617:
618: free (kf);
619: }
620: break;
621:
622: case IDM_KEYFILES_POPUP_ADD_DIR:
623: {
624: KeyFile *kf = (KeyFile *) malloc (sizeof (KeyFile));
625:
626: if (BrowseDirectories (hwndDlg,"SELECT_KEYFILE_PATH", kf->FileName))
627: {
628: param->FirstKeyFile = KeyFileAdd (param->FirstKeyFile, kf);
629: param->EnableKeyFiles = TRUE;
630: status = TRUE;
631: }
632: else
633: {
634: free (kf);
635: }
636: }
637: break;
638:
639: case IDM_KEYFILES_POPUP_ADD_TOKEN_FILES:
640: {
641: list <SecurityTokenKeyfilePath> selectedTokenKeyfiles;
642: if (DialogBoxParamW (hInst, MAKEINTRESOURCEW (IDD_TOKEN_KEYFILES), hwndDlg, (DLGPROC) SecurityTokenKeyfileDlgProc, (LPARAM) &selectedTokenKeyfiles) == IDOK)
643: {
644: foreach (const SecurityTokenKeyfilePath &keyPath, selectedTokenKeyfiles)
645: {
646: KeyFile *kf = (KeyFile *) malloc (sizeof (KeyFile));
647: strcpy_s (kf->FileName, sizeof (kf->FileName), WideToSingleString (keyPath).c_str());
648:
649: param->FirstKeyFile = KeyFileAdd (param->FirstKeyFile, kf);
650: param->EnableKeyFiles = TRUE;
651: status = TRUE;
652: }
653: }
654: }
655: break;
656: }
657:
658: DestroyMenu (popup);
659: return status;
660: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.