"Fossies" - the Fresh Open Source Software Archive

Member "src/Common/Keyfiles.c" (10 Oct 2018, 19177 Bytes) of package /windows/misc/VeraCrypt_1.23-Hotfix-2_Source.zip:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "Keyfiles.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 1.18_Source_vs_1.19_Source.

    1 /*
    2  Derived from source code of TrueCrypt 7.1a, which is
    3  Copyright (c) 2008-2012 TrueCrypt Developers Association and which is governed
    4  by the TrueCrypt License 3.0.
    5 
    6  Modifications and additions to the original source code (contained in this file)
    7  and all other portions of this file are Copyright (c) 2013-2017 IDRIX
    8  and are governed by the Apache License 2.0 the full text of which is
    9  contained in the file License.txt included in VeraCrypt binary and source
   10  code distribution packages.
   11 */
   12 
   13 #include <stdlib.h>
   14 #include <string.h>
   15 #include <sys/stat.h>
   16 #include <sys/types.h>
   17 
   18 #include "Tcdefs.h"
   19 #include "Keyfiles.h"
   20 #include "Crc.h"
   21 
   22 #include <io.h>
   23 #include "Dlgcode.h"
   24 #include "Language.h"
   25 #include "SecurityToken.h"
   26 #include "Common/resource.h"
   27 #include "Platform/Finally.h"
   28 #include "Platform/ForEach.h"
   29 #ifdef TCMOUNT
   30 #include "Mount/Mount.h"
   31 #endif
   32 
   33 #include <Strsafe.h>
   34 
   35 using namespace VeraCrypt;
   36 
   37 #define stat _stat
   38 #define S_IFDIR _S_IFDIR
   39 
   40 
   41 BOOL HiddenFilesPresentInKeyfilePath = FALSE;
   42 
   43 #ifdef TCMOUNT
   44 extern BOOL UsePreferences;
   45 #endif
   46 
   47 KeyFile *KeyFileAdd (KeyFile *firstKeyFile, KeyFile *keyFile)
   48 {
   49     KeyFile *kf = firstKeyFile;
   50 
   51     if (firstKeyFile != NULL)
   52     {
   53         while (kf->Next)
   54             kf = kf->Next;
   55 
   56         kf->Next = keyFile;
   57     }
   58     else
   59         firstKeyFile = keyFile;
   60 
   61     keyFile->Next = NULL;
   62 
   63     return firstKeyFile;
   64 }
   65 
   66 
   67 // Returns first keyfile, NULL if last keyfile was removed
   68 static KeyFile *KeyFileRemove (KeyFile *firstKeyFile, KeyFile *keyFile)
   69 {
   70     KeyFile *prevkf = NULL, *kf = firstKeyFile;
   71 
   72     if (firstKeyFile == NULL) return NULL;
   73     do
   74     {
   75         if (kf == keyFile)
   76         {
   77             if (prevkf == NULL)
   78                 firstKeyFile = kf->Next;
   79             else
   80                 prevkf->Next = kf->Next;
   81 
   82             burn (keyFile, sizeof(*keyFile));   // wipe
   83             free (keyFile);
   84             break;
   85         }
   86         prevkf = kf;
   87     }
   88     while (kf = kf->Next);
   89 
   90     return firstKeyFile;
   91 }
   92 
   93 
   94 void KeyFileRemoveAll (KeyFile **firstKeyFile)
   95 {
   96     KeyFile *kf = *firstKeyFile;
   97     while (kf != NULL)
   98     {
   99         KeyFile *d = kf;
  100         kf = kf->Next;
  101         burn (d, sizeof(*d));   // wipe
  102         free (d);
  103     }
  104 
  105     *firstKeyFile = NULL;
  106 }
  107 
  108 
  109 KeyFile *KeyFileClone (KeyFile *keyFile)
  110 {
  111     KeyFile *clone = NULL;
  112 
  113     if (keyFile == NULL) return NULL;
  114 
  115     clone = (KeyFile *) malloc (sizeof (KeyFile));
  116     if (clone)
  117     {
  118         StringCbCopyW (clone->FileName, sizeof(clone->FileName), keyFile->FileName);
  119         clone->Next = NULL;
  120     }
  121     return clone;
  122 }
  123 
  124 
  125 void KeyFileCloneAll (KeyFile *firstKeyFile, KeyFile **outputKeyFile)
  126 {
  127     if (outputKeyFile)
  128     {
  129         KeyFile *cloneFirstKeyFile = KeyFileClone (firstKeyFile);
  130         KeyFile *kf;
  131 
  132         // free output only if different from input
  133         if (*outputKeyFile != firstKeyFile)
  134             KeyFileRemoveAll (outputKeyFile);
  135         if (firstKeyFile)
  136         {
  137             kf = firstKeyFile->Next;
  138             while (kf != NULL)
  139             {
  140                 KeyFileAdd (cloneFirstKeyFile, KeyFileClone (kf));
  141                 kf = kf->Next;
  142             }
  143 
  144             *outputKeyFile = cloneFirstKeyFile;
  145         }
  146     }
  147 }
  148 
  149 
  150 static BOOL KeyFileProcess (unsigned __int8 *keyPool, KeyFile *keyFile)
  151 {
  152     FILE *f;
  153     unsigned __int8 buffer[64 * 1024];
  154     unsigned __int32 crc = 0xffffffff;
  155     int writePos = 0;
  156     size_t bytesRead, totalRead = 0;
  157     int status = TRUE;
  158 
  159     HANDLE src;
  160     FILETIME ftCreationTime;
  161     FILETIME ftLastWriteTime;
  162     FILETIME ftLastAccessTime;
  163 
  164     BOOL bTimeStampValid = FALSE;
  165 
  166     /* Remember the last access time of the keyfile. It will be preserved in order to prevent
  167     an adversary from determining which file may have been used as keyfile. */
  168     src = CreateFile (keyFile->FileName,
  169         GENERIC_READ | GENERIC_WRITE,
  170         FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
  171 
  172     if (src != INVALID_HANDLE_VALUE)
  173     {
  174         if (GetFileTime ((HANDLE) src, &ftCreationTime, &ftLastAccessTime, &ftLastWriteTime))
  175             bTimeStampValid = TRUE;
  176     }
  177 
  178     finally_do_arg (HANDLE, src,
  179     {
  180         if (finally_arg != INVALID_HANDLE_VALUE)
  181             CloseHandle (finally_arg);
  182     });
  183 
  184     f = _wfopen (keyFile->FileName, L"rb");
  185     if (f == NULL) return FALSE;
  186 
  187     while ((bytesRead = fread (buffer, 1, sizeof (buffer), f)) > 0)
  188     {
  189         size_t i;
  190 
  191         if (ferror (f))
  192         {
  193             status = FALSE;
  194             goto close;
  195         }
  196 
  197         for (i = 0; i < bytesRead; i++)
  198         {
  199             crc = UPDC32 (buffer[i], crc);
  200 
  201             keyPool[writePos++] += (unsigned __int8) (crc >> 24);
  202             keyPool[writePos++] += (unsigned __int8) (crc >> 16);
  203             keyPool[writePos++] += (unsigned __int8) (crc >> 8);
  204             keyPool[writePos++] += (unsigned __int8) crc;
  205 
  206             if (writePos >= KEYFILE_POOL_SIZE)
  207                 writePos = 0;
  208 
  209             if (++totalRead >= KEYFILE_MAX_READ_LEN)
  210                 goto close;
  211         }
  212     }
  213 
  214     if (ferror (f))
  215     {
  216         status = FALSE;
  217     }
  218     else if (totalRead == 0)
  219     {
  220         status = FALSE;
  221         SetLastError (ERROR_HANDLE_EOF);
  222     }
  223 
  224 close:
  225     DWORD err = GetLastError();
  226     fclose (f);
  227 
  228     if (bTimeStampValid && !IsFileOnReadOnlyFilesystem (keyFile->FileName))
  229     {
  230         // Restore the keyfile timestamp
  231         SetFileTime (src, &ftCreationTime, &ftLastAccessTime, &ftLastWriteTime);
  232     }
  233 
  234     SetLastError (err);
  235     return status;
  236 }
  237 
  238 
  239 BOOL KeyFilesApply (HWND hwndDlg, Password *password, KeyFile *firstKeyFile, const wchar_t* volumeFileName)
  240 {
  241     BOOL status = TRUE;
  242     KeyFile kfSubStruct;
  243     KeyFile *kf;
  244     KeyFile *kfSub = &kfSubStruct;
  245     static unsigned __int8 keyPool [KEYFILE_POOL_SIZE];
  246     size_t i;
  247     struct stat statStruct;
  248     wchar_t searchPath [TC_MAX_PATH*2];
  249     struct _wfinddata_t fBuf;
  250     intptr_t searchHandle;
  251 
  252     HiddenFilesPresentInKeyfilePath = FALSE;
  253 
  254     if (firstKeyFile == NULL) return TRUE;
  255 
  256     VirtualLock (keyPool, sizeof (keyPool));
  257     memset (keyPool, 0, sizeof (keyPool));
  258 
  259     for (kf = firstKeyFile; kf != NULL; kf = kf->Next)
  260     {
  261         // Determine whether it's a security token path
  262         try
  263         {
  264             if (SecurityToken::IsKeyfilePathValid (kf->FileName))
  265             {
  266                 // Apply security token keyfile
  267                 vector <byte> keyfileData;
  268                 SecurityTokenKeyfilePath secPath (kf->FileName);
  269                 SecurityToken::GetKeyfileData (SecurityTokenKeyfile (secPath), keyfileData);
  270 
  271                 if (keyfileData.empty())
  272                 {
  273                     SetLastError (ERROR_HANDLE_EOF);
  274                     handleWin32Error (hwndDlg, SRC_POS);
  275                     Error ("ERR_PROCESS_KEYFILE", hwndDlg);
  276                     status = FALSE;
  277                     continue;
  278                 }
  279 
  280                 unsigned __int32 crc = 0xffffffff;
  281                 int writePos = 0;
  282                 size_t totalRead = 0;
  283 
  284                 for (size_t i = 0; i < keyfileData.size(); i++)
  285                 {
  286                     crc = UPDC32 (keyfileData[i], crc);
  287 
  288                     keyPool[writePos++] += (unsigned __int8) (crc >> 24);
  289                     keyPool[writePos++] += (unsigned __int8) (crc >> 16);
  290                     keyPool[writePos++] += (unsigned __int8) (crc >> 8);
  291                     keyPool[writePos++] += (unsigned __int8) crc;
  292 
  293                     if (writePos >= KEYFILE_POOL_SIZE)
  294                         writePos = 0;
  295 
  296                     if (++totalRead >= KEYFILE_MAX_READ_LEN)
  297                         break;
  298                 }
  299 
  300                 burn (&keyfileData.front(), keyfileData.size());
  301                 continue;
  302             }
  303         }
  304         catch (Exception &e)
  305         {
  306             e.Show (NULL);
  307             return FALSE;
  308         }
  309 
  310         // Determine whether it's a path or a file
  311         if (_wstat (kf->FileName, &statStruct) != 0)
  312         {
  313             handleWin32Error (hwndDlg, SRC_POS);
  314             Error ("ERR_PROCESS_KEYFILE", hwndDlg);
  315             status = FALSE;
  316             continue;
  317         }
  318 
  319         if (statStruct.st_mode & S_IFDIR)       // If it's a directory
  320         {
  321             /* Find and process all keyfiles in the directory */
  322             int keyfileCount = 0;
  323 
  324             StringCbPrintfW (searchPath, sizeof (searchPath), L"%s\\*.*", kf->FileName);
  325             if ((searchHandle = _wfindfirst (searchPath, &fBuf)) == -1)
  326             {
  327                 handleWin32Error (hwndDlg, SRC_POS);
  328                 Error ("ERR_PROCESS_KEYFILE_PATH", hwndDlg);
  329                 status = FALSE;
  330                 continue;
  331             }
  332 
  333             do
  334             {
  335                 WIN32_FILE_ATTRIBUTE_DATA fileAttributes;
  336 
  337                 StringCbPrintfW (kfSub->FileName, sizeof(kfSub->FileName), L"%s%c%s", kf->FileName,
  338                     L'\\',
  339                     fBuf.name
  340                     );
  341 
  342                 // Determine whether it's a path or a file
  343                 if (_wstat (kfSub->FileName, &statStruct) != 0)
  344                 {
  345                     handleWin32Error (hwndDlg, SRC_POS);
  346                     Error ("ERR_PROCESS_KEYFILE", hwndDlg);
  347                     status = FALSE;
  348                     continue;
  349                 }
  350                 else if (statStruct.st_mode & S_IFDIR)      // If it's a directory
  351                 {
  352                     // Prevent recursive folder scanning
  353                     continue;
  354                 }
  355 
  356                 // Skip hidden files
  357                 if (GetFileAttributesExW (kfSub->FileName, GetFileExInfoStandard, &fileAttributes)
  358                     && (fileAttributes.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) != 0)
  359                 {
  360                     HiddenFilesPresentInKeyfilePath = TRUE;
  361                     continue;
  362                 }
  363 
  364                 CorrectFileName (kfSub->FileName);
  365                 if (volumeFileName && (_wcsicmp (volumeFileName, kfSub->FileName) == 0))
  366                 {
  367                     // skip if it is the current container file name
  368                     continue;
  369                 }
  370 
  371                 ++keyfileCount;
  372 
  373                 // Apply keyfile to the pool
  374                 if (!KeyFileProcess (keyPool, kfSub))
  375                 {
  376                     handleWin32Error (hwndDlg, SRC_POS);
  377                     Error ("ERR_PROCESS_KEYFILE", hwndDlg);
  378                     status = FALSE;
  379                 }
  380 
  381             } while (_wfindnext (searchHandle, &fBuf) != -1);
  382             _findclose (searchHandle);
  383 
  384             burn (&kfSubStruct, sizeof (kfSubStruct));
  385 
  386             if (keyfileCount == 0)
  387             {
  388                 ErrorDirect ((wstring (GetString ("ERR_KEYFILE_PATH_EMPTY")) + L"\n\n" + wstring (kf->FileName)).c_str(), hwndDlg);
  389                 status = FALSE;
  390             }
  391         }
  392         // Apply keyfile to the pool
  393         else if (!KeyFileProcess (keyPool, kf))
  394         {
  395             handleWin32Error (hwndDlg, SRC_POS);
  396             Error ("ERR_PROCESS_KEYFILE", hwndDlg);
  397             status = FALSE;
  398         }
  399     }
  400 
  401     /* Mix the keyfile pool contents into the password */
  402 
  403     for (i = 0; i < sizeof (keyPool); i++)
  404     {
  405         if (i < password->Length)
  406             password->Text[i] += keyPool[i];
  407         else
  408             password->Text[i] = keyPool[i];
  409     }
  410 
  411     if (password->Length < (int)sizeof (keyPool))
  412         password->Length = sizeof (keyPool);
  413 
  414     burn (keyPool, sizeof (keyPool));
  415 
  416     return status;
  417 }
  418 
  419 
  420 static void LoadKeyList (HWND hwndDlg, KeyFile *firstKeyFile)
  421 {
  422     KeyFile *kf;
  423     LVITEM LvItem;
  424     int line = 0;
  425     HWND hList = GetDlgItem (hwndDlg, IDC_KEYLIST);
  426 
  427     ListView_DeleteAllItems (hList);
  428     EnableWindow (GetDlgItem (hwndDlg, IDC_KEYREMOVE), FALSE);
  429     EnableWindow (GetDlgItem (hwndDlg, IDC_KEYREMOVEALL), firstKeyFile != NULL);
  430     SetCheckBox (hwndDlg, IDC_KEYFILES_ENABLE, firstKeyFile != NULL);
  431 
  432     for (kf = firstKeyFile; kf != NULL; kf = kf->Next)
  433     {
  434         memset (&LvItem,0,sizeof(LvItem));
  435         LvItem.mask = LVIF_TEXT|LVIF_PARAM;
  436         LvItem.iItem = line++;
  437         LvItem.iSubItem = 0;
  438         LvItem.pszText = kf->FileName;
  439         LvItem.lParam = (LPARAM) kf;
  440         SendMessage (hList, LVM_INSERTITEM, 0, (LPARAM)&LvItem);
  441     }
  442 }
  443 
  444 #if KEYFILE_POOL_SIZE % 4 != 0
  445 #error KEYFILE_POOL_SIZE must be a multiple of 4
  446 #endif
  447 
  448 BOOL CALLBACK KeyFilesDlgProc (HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
  449 {
  450     static KeyFilesDlgParam *param;
  451     static KeyFilesDlgParam origParam;
  452 
  453     WORD lw = LOWORD (wParam);
  454 
  455     switch (msg)
  456     {
  457     case WM_INITDIALOG:
  458         {
  459             LVCOLUMNW LvCol;
  460             HWND hList = GetDlgItem (hwndDlg, IDC_KEYLIST);
  461 
  462             param = (KeyFilesDlgParam *) lParam;
  463             origParam = *(KeyFilesDlgParam *) lParam;
  464 
  465             KeyFileCloneAll (param->FirstKeyFile, &param->FirstKeyFile);
  466 
  467             LocalizeDialog (hwndDlg, "IDD_KEYFILES");
  468             DragAcceptFiles (hwndDlg, TRUE);
  469 
  470             SendMessageW (hList,LVM_SETEXTENDEDLISTVIEWSTYLE,0,
  471                 LVS_EX_FULLROWSELECT|LVS_EX_HEADERDRAGDROP
  472                 );
  473 
  474             memset (&LvCol,0,sizeof(LvCol));
  475             LvCol.mask = LVCF_TEXT|LVCF_WIDTH|LVCF_SUBITEM|LVCF_FMT;
  476             LvCol.pszText = GetString ("KEYFILE");
  477             LvCol.cx = CompensateXDPI (374);
  478             LvCol.fmt = LVCFMT_LEFT;
  479             SendMessageW (hList, LVM_INSERTCOLUMNW, 0, (LPARAM)&LvCol);
  480 
  481             LoadKeyList (hwndDlg, param->FirstKeyFile);
  482             SetCheckBox (hwndDlg, IDC_KEYFILES_ENABLE, param->EnableKeyFiles);
  483 
  484 #ifdef TCMOUNT
  485             if (    (origParam.EnableKeyFiles == defaultKeyFilesParam.EnableKeyFiles)
  486                 &&  (origParam.FirstKeyFile == defaultKeyFilesParam.FirstKeyFile)
  487                 )
  488             {
  489                 /* default keyfile dialog case */
  490                 SetCheckBox (hwndDlg, IDC_KEYFILES_TRY_EMPTY_PASSWORD, bTryEmptyPasswordWhenKeyfileUsed);
  491                 ShowWindow(GetDlgItem(hwndDlg, IDC_KEYFILES_TRY_EMPTY_PASSWORD), SW_SHOW);
  492             }
  493 #endif
  494 
  495             SetWindowTextW(GetDlgItem(hwndDlg, IDT_KEYFILES_NOTE), GetString ("KEYFILES_NOTE"));
  496 
  497             ToHyperlink (hwndDlg, IDC_LINK_KEYFILES_INFO);
  498         }
  499         return 1;
  500 
  501     case WM_COMMAND:
  502 
  503         if (lw == IDC_KEYADD)
  504         {
  505             KeyFile *kf = (KeyFile *) malloc (sizeof (KeyFile));
  506             if (kf)
  507             {
  508                 if (SelectMultipleFiles (hwndDlg, "SELECT_KEYFILE", kf->FileName, sizeof(kf->FileName),bHistory))
  509                 {
  510                     bool containerFileSkipped = false;
  511                     do
  512                     {
  513                         CorrectFileName (kf->FileName);
  514                         if (_wcsicmp (param->VolumeFileName, kf->FileName) == 0)
  515                             containerFileSkipped = true;
  516                         else
  517                         {
  518                             param->FirstKeyFile = KeyFileAdd (param->FirstKeyFile, kf);
  519                             LoadKeyList (hwndDlg, param->FirstKeyFile);
  520 
  521                             kf = (KeyFile *) malloc (sizeof (KeyFile));
  522                             if (!kf)
  523                             {
  524                                 Warning ("ERR_MEM_ALLOC", hwndDlg);
  525                                 break;
  526                             }
  527                         }
  528                     } while (SelectMultipleFilesNext (kf->FileName, sizeof(kf->FileName)));
  529 
  530                     if (containerFileSkipped)
  531                     {
  532                         Warning ("SELECTED_KEYFILE_IS_CONTAINER_FILE", hwndDlg);
  533                     }
  534                 }
  535 
  536                 if (kf)
  537                     free (kf);
  538             }
  539             return 1;
  540         }
  541 
  542         if (lw == IDC_ADD_KEYFILE_PATH)
  543         {
  544             KeyFile *kf = (KeyFile *) malloc (sizeof (KeyFile));
  545             if (kf)
  546             {
  547                 if (BrowseDirectories (hwndDlg,"SELECT_KEYFILE_PATH", kf->FileName))
  548                 {
  549                     param->FirstKeyFile = KeyFileAdd (param->FirstKeyFile, kf);
  550                     LoadKeyList (hwndDlg, param->FirstKeyFile);
  551                 }
  552                 else
  553                 {
  554                     free (kf);
  555                 }
  556             }
  557             else
  558             {
  559                 Warning ("ERR_MEM_ALLOC", hwndDlg);
  560             }
  561             return 1;
  562         }
  563 
  564         if (lw == IDC_TOKEN_FILES_ADD)
  565         {
  566             list <SecurityTokenKeyfilePath> selectedTokenKeyfiles;
  567             if (DialogBoxParamW (hInst, MAKEINTRESOURCEW (IDD_TOKEN_KEYFILES), hwndDlg, (DLGPROC) SecurityTokenKeyfileDlgProc, (LPARAM) &selectedTokenKeyfiles) == IDOK)
  568             {
  569                 foreach (const SecurityTokenKeyfilePath &keyPath, selectedTokenKeyfiles)
  570                 {
  571                     KeyFile *kf = (KeyFile *) malloc (sizeof (KeyFile));
  572                     if (kf)
  573                     {
  574                         StringCbCopyW (kf->FileName, sizeof (kf->FileName), wstring(keyPath).c_str ());
  575 
  576                         param->FirstKeyFile = KeyFileAdd (param->FirstKeyFile, kf);
  577                         LoadKeyList (hwndDlg, param->FirstKeyFile);
  578                     }
  579                 }
  580             }
  581 
  582             return 1;
  583         }
  584 
  585         if (lw == IDC_KEYREMOVE)
  586         {
  587             HWND list = GetDlgItem (hwndDlg, IDC_KEYLIST);
  588             LVITEM LvItem;
  589             memset (&LvItem, 0, sizeof(LvItem));
  590             LvItem.mask = LVIF_PARAM;
  591             LvItem.iItem = -1;
  592 
  593             while (-1 != (LvItem.iItem = ListView_GetNextItem (list, LvItem.iItem, LVIS_SELECTED)))
  594             {
  595                 ListView_GetItem (list, &LvItem);
  596                 param->FirstKeyFile = KeyFileRemove (param->FirstKeyFile, (KeyFile *) LvItem.lParam);
  597             }
  598 
  599             LoadKeyList (hwndDlg, param->FirstKeyFile);
  600             return 1;
  601         }
  602 
  603         if (lw == IDC_KEYREMOVEALL)
  604         {
  605             KeyFileRemoveAll (&param->FirstKeyFile);
  606             LoadKeyList (hwndDlg, NULL);
  607             return 1;
  608         }
  609 
  610         if (lw == IDC_GENERATE_KEYFILE)
  611         {
  612             DialogBoxParamW (hInst,
  613                 MAKEINTRESOURCEW (IDD_KEYFILE_GENERATOR), hwndDlg,
  614                 (DLGPROC) KeyfileGeneratorDlgProc, (LPARAM) 0);
  615             return 1;
  616         }
  617 
  618         if (lw == IDC_LINK_KEYFILES_INFO)
  619         {
  620             Applink ("keyfiles");
  621             return 1;
  622         }
  623 
  624         if (lw == IDOK)
  625         {
  626             param->EnableKeyFiles = IsButtonChecked (GetDlgItem (hwndDlg, IDC_KEYFILES_ENABLE));
  627 
  628 #ifdef TCMOUNT
  629             if (IsWindowVisible (GetDlgItem (hwndDlg, IDC_KEYFILES_TRY_EMPTY_PASSWORD)))
  630             {
  631                 bTryEmptyPasswordWhenKeyfileUsed = IsButtonChecked (GetDlgItem (hwndDlg, IDC_KEYFILES_TRY_EMPTY_PASSWORD));
  632 
  633                 if (UsePreferences)
  634                 {
  635                     WaitCursor ();
  636                     SaveSettings (hwndDlg);
  637                     NormalCursor ();
  638                 }
  639             }
  640 #endif
  641             EndDialog (hwndDlg, IDOK);
  642             return 1;
  643         }
  644 
  645         if (lw == IDCANCEL)
  646         {
  647             KeyFileRemoveAll (&param->FirstKeyFile);
  648             *param = origParam;
  649 
  650             EndDialog (hwndDlg, IDCLOSE);
  651             return 1;
  652         }
  653         break;
  654 
  655     case WM_DROPFILES:
  656         {
  657             HDROP hdrop = (HDROP) wParam;
  658 
  659             int i = 0, count = DragQueryFile (hdrop, 0xFFFFFFFF, NULL, 0);
  660 
  661             while (count-- > 0)
  662             {
  663                 KeyFile *kf = (KeyFile *) malloc (sizeof (KeyFile));
  664                 if (kf)
  665                 {
  666                     DragQueryFile (hdrop, i++, kf->FileName, ARRAYSIZE (kf->FileName));
  667                     param->FirstKeyFile = KeyFileAdd (param->FirstKeyFile, kf);
  668                     LoadKeyList (hwndDlg, param->FirstKeyFile);
  669                 }
  670             }
  671 
  672             DragFinish (hdrop);
  673         }
  674         return 1;
  675 
  676     case WM_NOTIFY:
  677         if (((LPNMHDR) lParam)->code == LVN_ITEMCHANGED)
  678         {
  679             EnableWindow (GetDlgItem (hwndDlg, IDC_KEYREMOVE),
  680                 ListView_GetNextItem (GetDlgItem (hwndDlg, IDC_KEYLIST), -1, LVIS_SELECTED) != -1);
  681             return 1;
  682         }
  683         break;
  684 
  685     case WM_CLOSE:
  686         KeyFileRemoveAll (&param->FirstKeyFile);
  687         *param = origParam;
  688 
  689         EndDialog (hwndDlg, IDCLOSE);
  690         return 1;
  691 
  692         break;
  693 
  694     }
  695 
  696     return 0;
  697 }
  698 
  699 
  700 #define IDM_KEYFILES_POPUP_ADD_FILES        9001
  701 #define IDM_KEYFILES_POPUP_ADD_DIR          9002
  702 #define IDM_KEYFILES_POPUP_ADD_TOKEN_FILES  9003
  703 
  704 BOOL KeyfilesPopupMenu (HWND hwndDlg, POINT popupPosition, KeyFilesDlgParam *param)
  705 {
  706     HMENU popup = CreatePopupMenu ();
  707     if (!popup)
  708         return FALSE;
  709     int sel;
  710     BOOL status = FALSE;
  711 
  712     AppendMenuW (popup, MF_STRING, IDM_KEYFILES_POPUP_ADD_FILES, GetString ("IDC_KEYADD"));
  713     AppendMenuW (popup, MF_STRING, IDM_KEYFILES_POPUP_ADD_DIR, GetString ("IDC_ADD_KEYFILE_PATH"));
  714     AppendMenuW (popup, MF_STRING, IDM_KEYFILES_POPUP_ADD_TOKEN_FILES, GetString ("IDC_TOKEN_FILES_ADD"));
  715 
  716     sel = TrackPopupMenu (popup, TPM_RETURNCMD | TPM_LEFTBUTTON, popupPosition.x, popupPosition.y, 0, hwndDlg, NULL);
  717 
  718     switch (sel)
  719     {
  720     case IDM_KEYFILES_POPUP_ADD_FILES:
  721         {
  722             KeyFile *kf = (KeyFile *) malloc (sizeof (KeyFile));
  723             if (kf)
  724             {
  725                 if (SelectMultipleFiles (hwndDlg, "SELECT_KEYFILE", kf->FileName, sizeof(kf->FileName),bHistory))
  726                 {
  727                     do
  728                     {
  729                         param->FirstKeyFile = KeyFileAdd (param->FirstKeyFile, kf);
  730                         kf = (KeyFile *) malloc (sizeof (KeyFile));
  731                         if (!kf)
  732                         {
  733                             Warning ("ERR_MEM_ALLOC", hwndDlg);
  734                             break;
  735                         }
  736                     } while (SelectMultipleFilesNext (kf->FileName, sizeof(kf->FileName)));
  737 
  738                     param->EnableKeyFiles = TRUE;
  739                     status = TRUE;
  740                 }
  741 
  742                 if (kf)
  743                     free (kf);
  744             }
  745         }
  746         break;
  747 
  748     case IDM_KEYFILES_POPUP_ADD_DIR:
  749         {
  750             KeyFile *kf = (KeyFile *) malloc (sizeof (KeyFile));
  751             if (kf)
  752             {
  753                 if (BrowseDirectories (hwndDlg,"SELECT_KEYFILE_PATH", kf->FileName))
  754                 {
  755                     param->FirstKeyFile = KeyFileAdd (param->FirstKeyFile, kf);
  756                     param->EnableKeyFiles = TRUE;
  757                     status = TRUE;
  758                 }
  759                 else
  760                 {
  761                     free (kf);
  762                 }
  763             }
  764             else
  765             {
  766                 Warning ("ERR_MEM_ALLOC", hwndDlg);
  767             }
  768         }
  769         break;
  770 
  771     case IDM_KEYFILES_POPUP_ADD_TOKEN_FILES:
  772         {
  773             list <SecurityTokenKeyfilePath> selectedTokenKeyfiles;
  774             if (DialogBoxParamW (hInst, MAKEINTRESOURCEW (IDD_TOKEN_KEYFILES), hwndDlg, (DLGPROC) SecurityTokenKeyfileDlgProc, (LPARAM) &selectedTokenKeyfiles) == IDOK)
  775             {
  776                 foreach (const SecurityTokenKeyfilePath &keyPath, selectedTokenKeyfiles)
  777                 {
  778                     KeyFile *kf = (KeyFile *) malloc (sizeof (KeyFile));
  779                     if (kf)
  780                     {
  781                         StringCbCopyW (kf->FileName, sizeof (kf->FileName), wstring (keyPath).c_str());
  782 
  783                         param->FirstKeyFile = KeyFileAdd (param->FirstKeyFile, kf);
  784                         param->EnableKeyFiles = TRUE;
  785                         status = TRUE;
  786                     }
  787                     else
  788                     {
  789                         Warning ("ERR_MEM_ALLOC", hwndDlg);
  790                         break;
  791                     }
  792                 }
  793             }
  794         }
  795         break;
  796     }
  797 
  798     DestroyMenu (popup);
  799     return status;
  800 }