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

Diff of /trunk/Src/wptCryptdisk.cpp

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 23 by twoaday, Fri Sep 30 10:10:16 2005 UTC revision 36 by werner, Thu Oct 27 15:25:13 2005 UTC
# Line 1  Line 1 
 /* wptCryptdisk.cpp  
  *      Copyright (C) 2004 Timo Schulz  
  *  
  * This file is part of WinPT.  
  *  
  * WinPT is free software; you can redistribute it and/or modify  
  * it under the terms of the GNU General Public License as published by  
  * the Free Software Foundation; either version 2 of the License, or  
  * (at your option) any later version.  
  *  
  * WinPT is distributed in the hope that it will be useful,  
  * but WITHOUT ANY WARRANTY; without even the implied warranty of  
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the  
  * GNU General Public License for more details.  
  *  
  * You should have received a copy of the GNU General Public License  
  * along with WinPT; if not, write to the Free Software Foundation,  
  * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA  
  */  
   
 #include <windows.h>  
 #include <winioctl.h>  
 #include <stdio.h>  
 #include <ctype.h>  
   
 #include "../resource.h"  
 #include "wptCryptdisk.h"  
 #include "wptTypes.h"  
 #include "wptW32API.h"  
 #include "wptNLS.h"  
 #include "wptErrors.h"  
   
 /*DWORD SHFormatDrive(HWND hwnd, UINT drive, UINT fmtID, UINT options);*/  
 typedef DWORD (WINAPI *sh_format_drive_p) (HWND, UINT, UINT, UINT);  
   
 static mount_list_t mounted=NULL;  
 static HMODULE shell32=NULL;  
 static sh_format_drive_p shfmt=NULL;  
   
   
 static int  
 is_nt4 (void)  
 {  
     static int nt_flag = -1;  
     OSVERSIONINFO osinf;  
   
     if (nt_flag != -1)  
         return nt_flag;  
       
     memset (&osinf, 0, sizeof osinf);  
     osinf.dwOSVersionInfoSize = sizeof osinf;  
     GetVersionEx (&osinf);  
     if (osinf.dwPlatformId == VER_PLATFORM_WIN32_NT) {  
         nt_flag = 1;  
         shell32 = LoadLibrary ("SHELL32.DLL");  
         shfmt = (sh_format_drive_p)GetProcAddress (shell32, "SHFormatDrive");  
         if (!shfmt)  
             BUG (0);  
     }  
     else  
         nt_flag = 0;  
     return nt_flag;  
 }  
   
 static int  
 check_filedisk (void)  
 {  
     HKEY hk;  
     int rc = -1;  
   
     rc = RegOpenKeyEx (HKEY_LOCAL_MACHINE,  
                        "SYSTEM\\CurrentControlSet\\Services\\FileDisk",  
                        0, KEY_READ, &hk);  
     if (rc == ERROR_SUCCESS) {  
         RegCloseKey (hk);  
         rc = 0;  
     }  
     return rc;  
 }  
   
   
 int  
 cryptdisk_available (void)  
 {  
     return (is_nt4 () == 1 && check_filedisk () == 0)? 1 : 0;  
 }  
   
   
 void  
 cryptdisk_cleanup (void)  
 {  
     if (shell32)  
         FreeLibrary (shell32);  
     shell32 = NULL;  
 }  
   
   
 static int  
 num_of_devices (void)  
 {  
     HKEY hk;  
     BYTE buf[32];  
     DWORD n=0, type=0;  
     int rc;  
   
     rc = RegOpenKeyEx (HKEY_LOCAL_MACHINE,  
                        "SYSTEM\\CurrentControlSet\\Services\\FileDisk\\Parameters",  
                        0, KEY_READ, &hk);  
     if (rc != ERROR_SUCCESS)  
         return -1;  
   
     n = sizeof buf-1;  
     memset (buf, 0, sizeof buf);  
     rc = RegQueryValueEx (hk, "NumberOfDevices", 0, &type, buf, &n);  
     if (rc != ERROR_SUCCESS || type != REG_DWORD)  
         n=0;  
     else  
         n = *buf;  
     RegCloseKey (hk);  
     return n;  
 }  
   
   
 static HWND  
 start_cryptdisk_server (HANDLE * r_proc)  
 {  
     STARTUPINFO si;  
     PROCESS_INFORMATION pi;  
   
     memset (&si, 0, sizeof si);  
     memset (&pi, 0, sizeof pi);  
     si.cb = sizeof si;  
       
     if (CreateProcess (NULL, "CryptdiskSrv", NULL, NULL, FALSE, 0,  
                        NULL, NULL, &si, &pi) == FALSE) {  
         msg_box (NULL, _("Could not execute Cryptdisk Server."),  
                  _("Cryptdisk Error"), MB_ERR);  
         return NULL;  
     }  
     *r_proc = pi.hProcess;  
     Sleep (300);  
     return FindWindow ("CryptdiskSrv", NULL);  
 }  
   
   
 static int  
 cryptdisk_mount (int devnum,  
                  const char * imgfile,  
                  u32 size,  
                  const char * hdlet)  
 {  
     HWND h;  
     HANDLE proc, wait_ev;  
     COPYDATASTRUCT cds;  
     struct private_ofi_s ofi;  
   
     h = start_cryptdisk_server (&proc);  
     if (!h)  
         return WPTERR_GENERAL;  
     memset (&ofi, 0, sizeof ofi);  
     ofi.cmd = CMD_MOUNT;  
     ofi.devnum = devnum;  
     ofi.filesize.LowPart = size;  
     ofi.drvlet = *hdlet;  
     ofi.readonly = 0;  
     strcpy ((char *)ofi.fname, imgfile);  
     ofi.flen = strlen (imgfile);  
   
     wait_ev = OpenEvent (SYNCHRONIZE, FALSE, "cryptdisksrv.wait");  
     if (!wait_ev)  
         BUG (0);  
     memset (&cds, 0, sizeof cds);  
     cds.cbData = sizeof ofi;  
     cds.lpData = &ofi;  
     SendMessage (h, WM_COPYDATA, (WPARAM)GetDesktopWindow (), (LPARAM)&cds);  
     WaitForSingleObject (wait_ev, INFINITE);  
     CloseHandle (wait_ev);  
     CloseHandle (proc);  
     return 0;  
 }  
   
   
   
 int  
 cryptdisk_unmount (char drivelet, int forced)  
 {  
     HWND h;  
     HANDLE proc;  
     COPYDATASTRUCT cds;  
     struct private_ofi_s ofi;  
   
     h = start_cryptdisk_server (&proc);  
     if (!h)  
         return WPTERR_GENERAL;  
   
     memset (&ofi, 0, sizeof ofi);  
     ofi.cmd = CMD_UMOUNT;  
     ofi.drvlet = drivelet;  
     ofi.forced = forced;  
   
     memset (&cds, 0, sizeof cds);  
     cds.lpData = &ofi;  
     cds.cbData = sizeof ofi;  
     SendMessage (h, WM_COPYDATA, (WPARAM)GetDesktopWindow (), (LPARAM)&cds);  
     CloseHandle (proc);  
   
     return 0;  
 }  
   
 static void  
 print_lasterr (char * prefix)  
 {  
     LPVOID msg;  
   
     FormatMessage(  
         FORMAT_MESSAGE_ALLOCATE_BUFFER |  
         FORMAT_MESSAGE_FROM_SYSTEM |  
         FORMAT_MESSAGE_IGNORE_INSERTS,  
         NULL,  
         GetLastError(),  
         0,  
         (LPTSTR) &msg,  
         0,  
         NULL  
         );  
     MessageBox (NULL, (LPTSTR)msg, prefix, MB_ICONERROR|MB_OK);  
     LocalFree (msg);  
 }  
   
   
 static int  
 filedisk_status (char drivelet, LARGE_INTEGER * size, int * rdonly)  
 {  
     char                    VolumeName[] = "\\\\.\\ :";  
     HANDLE                  Device;  
     POPEN_FILE_INFORMATION  ofi;  
     DWORD                   BytesReturned;  
     int n= sizeof (OPEN_FILE_INFORMATION)+ MAX_PATH;  
   
     VolumeName[4] = drivelet;  
   
     Device = CreateFile (VolumeName,  
                          GENERIC_READ,  
                          FILE_SHARE_READ | FILE_SHARE_WRITE,  
                          NULL,  
                          OPEN_EXISTING,  
                          FILE_FLAG_NO_BUFFERING,  
                         NULL);  
   
     if (Device == INVALID_HANDLE_VALUE) {  
         print_lasterr(&VolumeName[4]);  
         return WPTERR_CDISK_OPEN;  
     }  
   
     ofi = (POPEN_FILE_INFORMATION)malloc (n);  
   
     if (!DeviceIoControl (Device,  
                           IOCTL_FILE_DISK_QUERY_FILE,  
                           NULL,  
                           0,  
                           ofi,  
                           sizeof(OPEN_FILE_INFORMATION) + MAX_PATH,  
                           &BytesReturned, NULL)) {  
         print_lasterr (&VolumeName[4]);  
         return WPTERR_CDISK_QUERY;  
     }  
   
     if (BytesReturned < sizeof(OPEN_FILE_INFORMATION)) {  
         SetLastError (ERROR_INSUFFICIENT_BUFFER);  
         print_lasterr (&VolumeName[4]);  
         return WPTERR_CDISK_QUERY;  
     }  
   
     if (size)  
         *size = ofi->FileSize;  
     if (rdonly)  
         *rdonly = ofi->ReadOnly;  
   
     return 0;  
 }  
   
   
 static mount_list_t  
 new_mount_list (const char * drive, int devnum)  
 {  
     mount_list_t n;  
   
     n = (mount_list_t)calloc (1, sizeof *n);  
     if (n) {  
         strcpy (n->drive, drive);  
         n->devnum = devnum;  
         n->ttl = 1;  
         filedisk_status (*drive, &n->size, &n->rdonly);  
     }  
     return n;  
 }  
   
   
 static mount_list_t  
 find_mount_list (mount_list_t root, const char * drive)  
 {  
     mount_list_t n;  
   
     for (n=root; n; n=n->next) {  
         if (n->ttl == 0)  
             continue;  
         if (!strncmp (n->drive, drive, strlen (drive)))  
             return n;  
     }  
     return NULL;  
 }  
   
   
 static void  
 add_mount_list (mount_list_t root, mount_list_t node)  
 {  
     mount_list_t n;  
   
     if (find_mount_list (root, node->drive))  
         return;  
   
     for (n=root; n->next; n=n->next)  
         ;  
     n->next = node;  
 }  
   
   
 static void  
 remove_mount_list (mount_list_t root, mount_list_t node)  
 {  
     mount_list_t n;  
   
     n = find_mount_list (root, node->drive);  
     if (n)  
         n->ttl = 0;  
 }  
   
   
 static void  
 free_mount_list (mount_list_t root)  
 {  
     mount_list_t n;  
   
     while (root) {  
         n = root->next;  
         free (root);  
         root = n;  
     }  
 }  
   
   
 static int  
 last_devnum (mount_list_t root)  
 {  
     mount_list_t n;  
     int devnum=0;  
   
     if (!root)  
         return 0;  
   
     for (n=root; n; n=n->next) {  
         if (devnum < n->devnum)  
             devnum=n->devnum;  
     }  
     return devnum+1;  
 }  
   
   
 static char  
 init_drives (HWND dlg, int ctlid)  
 {  
     char buf[512], drv[5];  
     DWORD n=0, i=0;  
   
     n=GetLogicalDriveStrings (sizeof buf-1, buf);  
     for (i=0; i < n; i++) {  
         memcpy (drv, buf+i, 3); drv[3]=0;  
         i += 3;  
     }  
     if (!dlg && ctlid == -1)  
         return ++drv[0];  
   
     for (++drv[0]; drv[0] < 'Z'; drv[0]++)  
         SendDlgItemMessage (dlg, ctlid, CB_ADDSTRING, 0,  
                             (LPARAM)(const char *)drv);  
     SendDlgItemMessage (dlg, ctlid, CB_SETCURSEL, 0, 0);  
     return 0;  
 }  
   
   
 static int  
 check_freespace (const char * imgfile, u32 size)  
 {  
     ULARGE_INTEGER tocaller, total, totfree;  
     char buf[128] = {0};  
   
     if (!strchr (imgfile, ':'))  
         GetCurrentDirectory (sizeof buf-1, buf);  
     else  
         strncpy (buf, imgfile, sizeof buf-1);  
     buf[3] = '\0';  
     GetDiskFreeSpaceEx (buf, &tocaller, &total, &totfree);  
     if (size > tocaller.LowPart)  
         return -1;  
     return 0;  
 }  
   
   
 static void  
 do_check (HWND dlg)  
 {  
     if (!cryptdisk_serv_run ()) { /* xxx */  
         msg_box (dlg, _("The Cryptdisk service seems to be available but "  
                         "it is not started yet.\nPlease start the service "  
                         "and try again."), _("Cryptdisk Error"), MB_ERR);  
         EndDialog (dlg, TRUE);  
     }  
 }  
   
   
 BOOL CALLBACK  
 cryptdisk_new_dlg_proc (HWND dlg, UINT msg, WPARAM wparam, LPARAM lparam)  
 {  
     const char * ciphers [] = {  
         "twofish",  
         NULL  
     };  
     const char * s;  
     char imgfile[128], key[128], drv[3];  
     int i;  
     u32 size=0;  
   
     switch (msg) {  
     case WM_INITDIALOG:  
         do_check (dlg);  
         SetDlgItemInt (dlg, IDC_CDNEW_SIZE, DISK_DEFSIZE, FALSE);  
         for (i=0; (s=ciphers[i]); i++)  
             SendDlgItemMessage (dlg, IDC_CDNEW_CIPHERS, CB_ADDSTRING,  
                                      0, (LPARAM)(const char *) s);  
         SendDlgItemMessage (dlg, IDC_CDNEW_CIPHERS, CB_SETCURSEL, 0, 0);  
         center_window (dlg, NULL);  
         SetForegroundWindow (dlg);  
         break;  
   
     case WM_COMMAND:  
         switch (LOWORD (wparam)) {  
         case IDOK:  
             i = GetDlgItemText (dlg, IDC_CDNEW_IMGFILE, imgfile, sizeof imgfile-1);  
             if (!i) {  
                 msg_box (dlg, _("Please enter a name for the image file."),  
                          _("Cryptdisk"), MB_ERR);  
                 return FALSE;  
             }  
             if (file_exist_check (imgfile) == 0) {  
                 i = msg_box (dlg, _("This volume file already exists.\n"  
                                     "Do you want to overwrite it?"),  
                             _("Cryptdisk Warning"), MB_YESNO|MB_WARN);  
                 if (i == IDNO)  
                     return FALSE;  
             }  
             for (i=0; i < (int)strlen (imgfile); i++)  
                 imgfile[i] = toupper (imgfile[i]);  
             size = GetDlgItemInt (dlg, IDC_CDNEW_SIZE, NULL, FALSE);  
             if (!size) {  
                 msg_box (dlg, _("Please enter the size for the volume"),  
                                 _("Cryptdisk"), MB_INFO);  
                 return FALSE;  
             }  
             size *= 1024; /*KB*/  
             if (check_freespace (imgfile, (size*1024))) {  
                 msg_box (dlg, _("There is not enough free disk space to "  
                                 "store the volume."), _("Cryptdisk"), MB_ERR);  
                 return FALSE;  
             }  
             i = GetDlgItemText (dlg, IDC_CDNEW_PASS, key, sizeof key-1);  
             if (!i) {  
                 msg_box (dlg, _("Please enter a passphrase for the volume."),  
                             _("Cryptdisk"), MB_ERR);  
                 return FALSE;  
             }  
             strcpy (drv, "?:\\");  
             drv[0] = init_drives (NULL, -1);  
             i = cryptdisk_mount (last_devnum (mounted), imgfile, size, drv);  
             if (!i)  
                 shfmt (dlg, drv[0] - 65, 0, 0);  
             break;  
         case IDCANCEL:  
             EndDialog (dlg, FALSE);  
             break;  
         }  
         break;  
   
     }  
   
     return FALSE;  
 }  
   
   
 BOOL CALLBACK  
 cryptdisk_mount_dlg_proc (HWND dlg, UINT msg, WPARAM wparam, LPARAM lparam)  
 {  
     const char * s_imgfile;  
     char buf[8], drive[8], passwd[64], imgfile[128];  
     int n, i, devnum=0;  
     int rc;  
   
     switch (msg) {  
     case WM_INITDIALOG:  
         do_check (dlg);  
         s_imgfile = (const char *)lparam;  
         if (s_imgfile)  
             SetDlgItemText (dlg, IDC_CDMOUNT_IMGFILE, s_imgfile);  
         init_drives (dlg, IDC_CDMOUNT_DRV);  
         n = num_of_devices ();  
         if (n == -1) {  
             msg_box (dlg, _("Cannot determine the number of drives."),  
                      _("Cryptdisk Error"), MB_ERR);  
             EndDialog (dlg, FALSE);  
         }  
         for (i=last_devnum (mounted); i < n; i++) {  
             sprintf (buf, "%d", i);  
             SendDlgItemMessage (dlg, IDC_CDMOUNT_ID, CB_ADDSTRING, 0,  
                                 (LPARAM)(const char *)buf);  
         }  
         SendDlgItemMessage (dlg, IDC_CDMOUNT_ID, CB_SETCURSEL, 0, 0);  
         center_window (dlg, NULL);  
         SetForegroundWindow (dlg);  
         break;  
   
     case WM_COMMAND:  
         switch (LOWORD (wparam)) {  
         case IDC_CDMOUNT_SELFILE:  
             s_imgfile = get_filename_dlg (dlg, FILE_OPEN, _("Select Crypdisk Volume"),  
                                           NULL, NULL);  
             if (s_imgfile != NULL)  
                 SetDlgItemText (dlg, IDC_CDMOUNT_IMGFILE, s_imgfile);  
             break;  
   
         case IDOK:  
             n = item_get_text_length (dlg, IDC_CDMOUNT_IMGFILE);  
             if (!n) {  
                 msg_box (dlg, _("Please enter the name of the image file."),  
                          _("Cryptdisk Error"), MB_ERR);  
                 return FALSE;  
             }  
             n = item_get_text_length (dlg, IDC_CDMOUNT_PASS);  
             if (!n) {  
                 msg_box (dlg, _("Please enter a password."),  
                          _("Cryptdisk Error"), MB_ERR);  
                 return FALSE;  
             }  
             devnum = GetDlgItemInt (dlg, IDC_CDMOUNT_ID, NULL, FALSE);  
             GetDlgItemText (dlg, IDC_CDMOUNT_DRV, drive, sizeof drive-1);  
             GetDlgItemText (dlg, IDC_CDMOUNT_PASS, passwd, sizeof passwd-1);  
             GetDlgItemText (dlg, IDC_CDMOUNT_IMGFILE, imgfile, sizeof imgfile-1);  
             if (file_exist_check  (imgfile)) {  
                 msg_box (dlg, _("Image file does not exist or could not be accessed."),  
                          _("Cryptdisk Error"), MB_ERR);  
                 return FALSE;  
             }  
             rc = cryptdisk_mount (devnum, imgfile, 0, drive);  
             if (!rc) {  
                 mount_list_t n = new_mount_list (drive, devnum);  
                 if (!mounted)  
                     mounted = n;  
                 else  
                     add_mount_list (mounted, n);  
                 EndDialog (dlg, TRUE);  
             }  
             else  
                 msg_box (dlg, winpt_strerror (rc), _("Cryptdisk Error"), MB_ERR);  
             break;  
   
         case IDCANCEL:  
             EndDialog (dlg, FALSE);  
             break;  
         }  
         break;  
     }  
     return FALSE;  
 }  
   
   
 static void  
 load_devs_from_mountlist (HWND dlg, int ctlid)  
 {  
     mount_list_t n;  
     char buf[128];  
   
     if (!mounted)  
         return;  
   
     for (n=mounted; n; n=n->next) {  
         if (n->ttl == 0)  
             continue;  
         _snprintf (buf, sizeof buf-1, _("Drive %s (ID %d); Size %d MB, Readonly=%s"),  
                     n->drive, n->devnum, n->size.LowPart/1024/1024,  
                     n->rdonly? "true" : "false");  
         SendDlgItemMessage (dlg, ctlid, LB_ADDSTRING, 0, (LPARAM)(const char *)buf);  
     }  
   
 }  
   
   
 static void  
 do_reaping (void)  
 {  
     mount_list_t n;  
     int ndevs=0, numount=0;  
   
     for (n=mounted; n; n=n->next) {  
         if (n->ttl == 0)  
             numount++;  
         ndevs++;  
     }  
     if (ndevs == numount) {  
         free_mount_list (mounted);  
         mounted = NULL;  
     }  
 }  
   
   
 BOOL CALLBACK  
 cryptdisk_umount_dlg_proc (HWND dlg, UINT msg, WPARAM wparam, LPARAM lparam)  
 {      
     mount_list_t vol;  
     char buf[128];  
     int n, rc=0;  
   
     switch (msg) {  
     case WM_INITDIALOG:  
         do_check (dlg);  
         load_devs_from_mountlist (dlg, IDC_CDUMOUNT_LIST);  
         center_window (dlg, NULL);  
         SetForegroundWindow (dlg);  
         break;  
   
     case WM_DESTROY:  
         do_reaping ();  
         break;  
   
     case WM_COMMAND:  
         switch (LOWORD (wparam)) {  
         case IDOK:  
             n = SendDlgItemMessage (dlg, IDC_CDUMOUNT_LIST, LB_GETCURSEL, 0, 0);  
             if (n == LB_ERR) {  
                 msg_box (dlg, _("Please select one drive to umount."), _("Cryptdisk"), MB_INFO);  
                 return FALSE;  
             }  
             SendDlgItemMessage (dlg, IDC_CDUMOUNT_LIST, LB_GETTEXT, n,  
                                 (LPARAM)(char *)buf);  
             strcpy (buf, buf+6);  
             buf[2] = '\0';  
             vol = find_mount_list (mounted, buf);  
             if (!vol)  
                 BUG (0);  
             rc = cryptdisk_unmount (buf[0], 0);  
             //if (rc == WPTERR_CDISK_LOCK)  
         //      rc = cryptdisk_unmount (buf[0], 0);  
             if (!rc) {  
                 SendDlgItemMessage (dlg, IDC_CDUMOUNT_LIST, LB_DELETESTRING, (WPARAM)n, 0);  
                 remove_mount_list (mounted, vol);  
             }  
             else  
                 msg_box (dlg, winpt_strerror (rc), _("Cryptdisk Error"), MB_ERR);  
             break;  
         case IDCANCEL:  
             EndDialog (dlg, FALSE);  
             break;  
         }  
         break;  
     }  
   
     return FALSE;  
 }  
   
   
 int  
 cryptdisk_serv_run (void)  
 {  
     SC_HANDLE hd;  
     ENUM_SERVICE_STATUS ess[4096];  
     DWORD nservs=0, dummy=0;  
     DWORD i;  
     int rc=0;  
   
     hd = OpenSCManager (NULL, NULL, SC_MANAGER_ENUMERATE_SERVICE);  
     if (!hd)  
         return 0;  
   
     EnumServicesStatus (hd,  SERVICE_DRIVER, SERVICE_ACTIVE,  
                         (LPENUM_SERVICE_STATUS)&ess,  
                         sizeof ess-1, &dummy, &nservs, &dummy);  
   
     for (i=0; i < nservs; i++) {  
         if (!strnicmp ("FileDisk", ess[i].lpDisplayName, 8)) {  
             rc = 1;  
             break;  
         }  
     }  
   
     CloseServiceHandle (hd);  
     return rc;  
 }  
1    /* wptCryptdisk.cpp
2     *      Copyright (C) 2004 Timo Schulz
3     *
4     * This file is part of WinPT.
5     *
6     * WinPT is free software; you can redistribute it and/or modify
7     * it under the terms of the GNU General Public License as published by
8     * the Free Software Foundation; either version 2 of the License, or
9     * (at your option) any later version.
10     *
11     * WinPT is distributed in the hope that it will be useful,
12     * but WITHOUT ANY WARRANTY; without even the implied warranty of
13     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14     * GNU General Public License for more details.
15     *
16     * You should have received a copy of the GNU General Public License
17     * along with WinPT; if not, write to the Free Software Foundation,
18     * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19     */
20    
21    #ifdef HAVE_CONFIG_H
22    #include <config.h>
23    #endif
24    
25    #include <windows.h>
26    #include <windows.h>
27    #include <winioctl.h>
28    #include <stdio.h>
29    #include <ctype.h>
30    
31    #include "../resource.h"
32    #include "wptCryptdisk.h"
33    #include "wptTypes.h"
34    #include "wptW32API.h"
35    #include "wptNLS.h"
36    #include "wptErrors.h"
37    
38    /*DWORD SHFormatDrive(HWND hwnd, UINT drive, UINT fmtID, UINT options);*/
39    typedef DWORD (WINAPI *sh_format_drive_p) (HWND, UINT, UINT, UINT);
40    
41    static mount_list_t mounted=NULL;
42    static HMODULE shell32=NULL;
43    static sh_format_drive_p shfmt=NULL;
44    
45    
46    static int
47    is_nt4 (void)
48    {
49        static int nt_flag = -1;
50        OSVERSIONINFO osinf;
51    
52        if (nt_flag != -1)
53            return nt_flag;
54        
55        memset (&osinf, 0, sizeof osinf);
56        osinf.dwOSVersionInfoSize = sizeof osinf;
57        GetVersionEx (&osinf);
58        if (osinf.dwPlatformId == VER_PLATFORM_WIN32_NT) {
59            nt_flag = 1;
60            shell32 = LoadLibrary ("SHELL32.DLL");
61            shfmt = (sh_format_drive_p)GetProcAddress (shell32, "SHFormatDrive");
62            if (!shfmt)
63                BUG (0);
64        }
65        else
66            nt_flag = 0;
67        return nt_flag;
68    }
69    
70    static int
71    check_filedisk (void)
72    {
73        HKEY hk;
74        int rc = -1;
75    
76        rc = RegOpenKeyEx (HKEY_LOCAL_MACHINE,
77                           "SYSTEM\\CurrentControlSet\\Services\\FileDisk",
78                           0, KEY_READ, &hk);
79        if (rc == ERROR_SUCCESS) {
80            RegCloseKey (hk);
81            rc = 0;
82        }
83        return rc;
84    }
85    
86    
87    int
88    cryptdisk_available (void)
89    {
90        return (is_nt4 () == 1 && check_filedisk () == 0)? 1 : 0;
91    }
92    
93    
94    void
95    cryptdisk_cleanup (void)
96    {
97        if (shell32)
98            FreeLibrary (shell32);
99        shell32 = NULL;
100    }
101    
102    
103    static int
104    num_of_devices (void)
105    {
106        HKEY hk;
107        BYTE buf[32];
108        DWORD n=0, type=0;
109        int rc;
110    
111        rc = RegOpenKeyEx (HKEY_LOCAL_MACHINE,
112                           "SYSTEM\\CurrentControlSet\\Services\\FileDisk\\Parameters",
113                           0, KEY_READ, &hk);
114        if (rc != ERROR_SUCCESS)
115            return -1;
116    
117        n = sizeof buf-1;
118        memset (buf, 0, sizeof buf);
119        rc = RegQueryValueEx (hk, "NumberOfDevices", 0, &type, buf, &n);
120        if (rc != ERROR_SUCCESS || type != REG_DWORD)
121            n=0;
122        else
123            n = *buf;
124        RegCloseKey (hk);
125        return n;
126    }
127    
128    
129    static HWND
130    start_cryptdisk_server (HANDLE * r_proc)
131    {
132        STARTUPINFO si;
133        PROCESS_INFORMATION pi;
134    
135        memset (&si, 0, sizeof si);
136        memset (&pi, 0, sizeof pi);
137        si.cb = sizeof si;
138        
139        if (CreateProcess (NULL, "CryptdiskSrv", NULL, NULL, FALSE, 0,
140                           NULL, NULL, &si, &pi) == FALSE) {
141            msg_box (NULL, _("Could not execute Cryptdisk Server."),
142                     _("Cryptdisk Error"), MB_ERR);
143            return NULL;
144        }
145        *r_proc = pi.hProcess;
146        Sleep (300);
147        return FindWindow ("CryptdiskSrv", NULL);
148    }
149    
150    
151    static int
152    cryptdisk_mount (int devnum,
153                     const char * imgfile,
154                     u32 size,
155                     const char * hdlet)
156    {
157        HWND h;
158        HANDLE proc, wait_ev;
159        COPYDATASTRUCT cds;
160        struct private_ofi_s ofi;
161    
162        h = start_cryptdisk_server (&proc);
163        if (!h)
164            return WPTERR_GENERAL;
165        memset (&ofi, 0, sizeof ofi);
166        ofi.cmd = CMD_MOUNT;
167        ofi.devnum = devnum;
168        ofi.filesize.LowPart = size;
169        ofi.drvlet = *hdlet;
170        ofi.readonly = 0;
171        strcpy ((char *)ofi.fname, imgfile);
172        ofi.flen = strlen (imgfile);
173    
174        wait_ev = OpenEvent (SYNCHRONIZE, FALSE, "cryptdisksrv.wait");
175        if (!wait_ev)
176            BUG (0);
177        memset (&cds, 0, sizeof cds);
178        cds.cbData = sizeof ofi;
179        cds.lpData = &ofi;
180        SendMessage (h, WM_COPYDATA, (WPARAM)GetDesktopWindow (), (LPARAM)&cds);
181        WaitForSingleObject (wait_ev, INFINITE);
182        CloseHandle (wait_ev);
183        CloseHandle (proc);
184        return 0;
185    }
186    
187    
188    
189    int
190    cryptdisk_unmount (char drivelet, int forced)
191    {
192        HWND h;
193        HANDLE proc;
194        COPYDATASTRUCT cds;
195        struct private_ofi_s ofi;
196    
197        h = start_cryptdisk_server (&proc);
198        if (!h)
199            return WPTERR_GENERAL;
200    
201        memset (&ofi, 0, sizeof ofi);
202        ofi.cmd = CMD_UMOUNT;
203        ofi.drvlet = drivelet;
204        ofi.forced = forced;
205    
206        memset (&cds, 0, sizeof cds);
207        cds.lpData = &ofi;
208        cds.cbData = sizeof ofi;
209        SendMessage (h, WM_COPYDATA, (WPARAM)GetDesktopWindow (), (LPARAM)&cds);
210        CloseHandle (proc);
211    
212        return 0;
213    }
214    
215    static void
216    print_lasterr (char * prefix)
217    {
218        LPVOID msg;
219    
220        FormatMessage(
221            FORMAT_MESSAGE_ALLOCATE_BUFFER |
222            FORMAT_MESSAGE_FROM_SYSTEM |
223            FORMAT_MESSAGE_IGNORE_INSERTS,
224            NULL,
225            GetLastError(),
226            0,
227            (LPTSTR) &msg,
228            0,
229            NULL
230            );
231        MessageBox (NULL, (LPTSTR)msg, prefix, MB_ICONERROR|MB_OK);
232        LocalFree (msg);
233    }
234    
235    
236    static int
237    filedisk_status (char drivelet, LARGE_INTEGER * size, int * rdonly)
238    {
239        char                    VolumeName[] = "\\\\.\\ :";
240        HANDLE                  Device;
241        POPEN_FILE_INFORMATION  ofi;
242        DWORD                   BytesReturned;
243        int n= sizeof (OPEN_FILE_INFORMATION)+ MAX_PATH;
244    
245        VolumeName[4] = drivelet;
246    
247        Device = CreateFile (VolumeName,
248                             GENERIC_READ,
249                             FILE_SHARE_READ | FILE_SHARE_WRITE,
250                             NULL,
251                             OPEN_EXISTING,
252                             FILE_FLAG_NO_BUFFERING,
253                            NULL);
254    
255        if (Device == INVALID_HANDLE_VALUE) {
256            print_lasterr(&VolumeName[4]);
257            return WPTERR_CDISK_OPEN;
258        }
259    
260        ofi = (POPEN_FILE_INFORMATION)malloc (n);
261    
262        if (!DeviceIoControl (Device,
263                              IOCTL_FILE_DISK_QUERY_FILE,
264                              NULL,
265                              0,
266                              ofi,
267                              sizeof(OPEN_FILE_INFORMATION) + MAX_PATH,
268                              &BytesReturned, NULL)) {
269            print_lasterr (&VolumeName[4]);
270            return WPTERR_CDISK_QUERY;
271        }
272    
273        if (BytesReturned < sizeof(OPEN_FILE_INFORMATION)) {
274            SetLastError (ERROR_INSUFFICIENT_BUFFER);
275            print_lasterr (&VolumeName[4]);
276            return WPTERR_CDISK_QUERY;
277        }
278    
279        if (size)
280            *size = ofi->FileSize;
281        if (rdonly)
282            *rdonly = ofi->ReadOnly;
283    
284        return 0;
285    }
286    
287    
288    static mount_list_t
289    new_mount_list (const char * drive, int devnum)
290    {
291        mount_list_t n;
292    
293        n = (mount_list_t)calloc (1, sizeof *n);
294        if (n) {
295            strcpy (n->drive, drive);
296            n->devnum = devnum;
297            n->ttl = 1;
298            filedisk_status (*drive, &n->size, &n->rdonly);
299        }
300        return n;
301    }
302    
303    
304    static mount_list_t
305    find_mount_list (mount_list_t root, const char * drive)
306    {
307        mount_list_t n;
308    
309        for (n=root; n; n=n->next) {
310            if (n->ttl == 0)
311                continue;
312            if (!strncmp (n->drive, drive, strlen (drive)))
313                return n;
314        }
315        return NULL;
316    }
317    
318    
319    static void
320    add_mount_list (mount_list_t root, mount_list_t node)
321    {
322        mount_list_t n;
323    
324        if (find_mount_list (root, node->drive))
325            return;
326    
327        for (n=root; n->next; n=n->next)
328            ;
329        n->next = node;
330    }
331    
332    
333    static void
334    remove_mount_list (mount_list_t root, mount_list_t node)
335    {
336        mount_list_t n;
337    
338        n = find_mount_list (root, node->drive);
339        if (n)
340            n->ttl = 0;
341    }
342    
343    
344    static void
345    free_mount_list (mount_list_t root)
346    {
347        mount_list_t n;
348    
349        while (root) {
350            n = root->next;
351            free (root);
352            root = n;
353        }
354    }
355    
356    
357    static int
358    last_devnum (mount_list_t root)
359    {
360        mount_list_t n;
361        int devnum=0;
362    
363        if (!root)
364            return 0;
365    
366        for (n=root; n; n=n->next) {
367            if (devnum < n->devnum)
368                devnum=n->devnum;
369        }
370        return devnum+1;
371    }
372    
373    
374    static char
375    init_drives (HWND dlg, int ctlid)
376    {
377        char buf[512], drv[5];
378        DWORD n=0, i=0;
379    
380        n=GetLogicalDriveStrings (sizeof buf-1, buf);
381        for (i=0; i < n; i++) {
382            memcpy (drv, buf+i, 3); drv[3]=0;
383            i += 3;
384        }
385        if (!dlg && ctlid == -1)
386            return ++drv[0];
387    
388        for (++drv[0]; drv[0] < 'Z'; drv[0]++)
389            SendDlgItemMessage (dlg, ctlid, CB_ADDSTRING, 0,
390                                (LPARAM)(const char *)drv);
391        SendDlgItemMessage (dlg, ctlid, CB_SETCURSEL, 0, 0);
392        return 0;
393    }
394    
395    
396    static int
397    check_freespace (const char * imgfile, u32 size)
398    {
399        ULARGE_INTEGER tocaller, total, totfree;
400        char buf[128] = {0};
401    
402        if (!strchr (imgfile, ':'))
403            GetCurrentDirectory (sizeof buf-1, buf);
404        else
405            strncpy (buf, imgfile, sizeof buf-1);
406        buf[3] = '\0';
407        GetDiskFreeSpaceEx (buf, &tocaller, &total, &totfree);
408        if (size > tocaller.LowPart)
409            return -1;
410        return 0;
411    }
412    
413    
414    static void
415    do_check (HWND dlg)
416    {
417        if (!cryptdisk_serv_run ()) { /* xxx */
418            msg_box (dlg, _("The Cryptdisk service seems to be available but "
419                            "it is not started yet.\nPlease start the service "
420                            "and try again."), _("Cryptdisk Error"), MB_ERR);
421            EndDialog (dlg, TRUE);
422        }
423    }
424    
425    
426    BOOL CALLBACK
427    cryptdisk_new_dlg_proc (HWND dlg, UINT msg, WPARAM wparam, LPARAM lparam)
428    {
429        const char * ciphers [] = {
430            "twofish",
431            NULL
432        };
433        const char * s;
434        char imgfile[128], key[128], drv[3];
435        int i;
436        u32 size=0;
437    
438        switch (msg) {
439        case WM_INITDIALOG:
440            do_check (dlg);
441            SetDlgItemInt (dlg, IDC_CDNEW_SIZE, DISK_DEFSIZE, FALSE);
442            for (i=0; (s=ciphers[i]); i++)
443                SendDlgItemMessage (dlg, IDC_CDNEW_CIPHERS, CB_ADDSTRING,
444                                         0, (LPARAM)(const char *) s);
445            SendDlgItemMessage (dlg, IDC_CDNEW_CIPHERS, CB_SETCURSEL, 0, 0);
446            center_window (dlg, NULL);
447            SetForegroundWindow (dlg);
448            break;
449    
450        case WM_COMMAND:
451            switch (LOWORD (wparam)) {
452            case IDOK:
453                i = GetDlgItemText (dlg, IDC_CDNEW_IMGFILE, imgfile, sizeof imgfile-1);
454                if (!i) {
455                    msg_box (dlg, _("Please enter a name for the image file."),
456                             _("Cryptdisk"), MB_ERR);
457                    return FALSE;
458                }
459                if (file_exist_check (imgfile) == 0) {
460                    i = msg_box (dlg, _("This volume file already exists.\n"
461                                        "Do you want to overwrite it?"),
462                                _("Cryptdisk Warning"), MB_YESNO|MB_WARN);
463                    if (i == IDNO)
464                        return FALSE;
465                }
466                for (i=0; i < (int)strlen (imgfile); i++)
467                    imgfile[i] = toupper (imgfile[i]);
468                size = GetDlgItemInt (dlg, IDC_CDNEW_SIZE, NULL, FALSE);
469                if (!size) {
470                    msg_box (dlg, _("Please enter the size for the volume"),
471                                    _("Cryptdisk"), MB_INFO);
472                    return FALSE;
473                }
474                size *= 1024; /*KB*/
475                if (check_freespace (imgfile, (size*1024))) {
476                    msg_box (dlg, _("There is not enough free disk space to "
477                                    "store the volume."), _("Cryptdisk"), MB_ERR);
478                    return FALSE;
479                }
480                i = GetDlgItemText (dlg, IDC_CDNEW_PASS, key, sizeof key-1);
481                if (!i) {
482                    msg_box (dlg, _("Please enter a passphrase for the volume."),
483                                _("Cryptdisk"), MB_ERR);
484                    return FALSE;
485                }
486                strcpy (drv, "?:\\");
487                drv[0] = init_drives (NULL, -1);
488                i = cryptdisk_mount (last_devnum (mounted), imgfile, size, drv);
489                if (!i)
490                    shfmt (dlg, drv[0] - 65, 0, 0);
491                break;
492            case IDCANCEL:
493                EndDialog (dlg, FALSE);
494                break;
495            }
496            break;
497    
498        }
499    
500        return FALSE;
501    }
502    
503    
504    BOOL CALLBACK
505    cryptdisk_mount_dlg_proc (HWND dlg, UINT msg, WPARAM wparam, LPARAM lparam)
506    {
507        const char * s_imgfile;
508        char buf[8], drive[8], passwd[64], imgfile[128];
509        int n, i, devnum=0;
510        int rc;
511    
512        switch (msg) {
513        case WM_INITDIALOG:
514            do_check (dlg);
515            s_imgfile = (const char *)lparam;
516            if (s_imgfile)
517                SetDlgItemText (dlg, IDC_CDMOUNT_IMGFILE, s_imgfile);
518            init_drives (dlg, IDC_CDMOUNT_DRV);
519            n = num_of_devices ();
520            if (n == -1) {
521                msg_box (dlg, _("Cannot determine the number of drives."),
522                         _("Cryptdisk Error"), MB_ERR);
523                EndDialog (dlg, FALSE);
524            }
525            for (i=last_devnum (mounted); i < n; i++) {
526                sprintf (buf, "%d", i);
527                SendDlgItemMessage (dlg, IDC_CDMOUNT_ID, CB_ADDSTRING, 0,
528                                    (LPARAM)(const char *)buf);
529            }
530            SendDlgItemMessage (dlg, IDC_CDMOUNT_ID, CB_SETCURSEL, 0, 0);
531            center_window (dlg, NULL);
532            SetForegroundWindow (dlg);
533            break;
534    
535        case WM_COMMAND:
536            switch (LOWORD (wparam)) {
537            case IDC_CDMOUNT_SELFILE:
538                s_imgfile = get_fileopen_dlg (dlg, _("Select Crypdisk Volume"),
539                                              NULL, NULL);
540                if (s_imgfile != NULL)
541                    SetDlgItemText (dlg, IDC_CDMOUNT_IMGFILE, s_imgfile);
542                break;
543    
544            case IDOK:
545                n = item_get_text_length (dlg, IDC_CDMOUNT_IMGFILE);
546                if (!n) {
547                    msg_box (dlg, _("Please enter the name of the image file."),
548                             _("Cryptdisk Error"), MB_ERR);
549                    return FALSE;
550                }
551                n = item_get_text_length (dlg, IDC_CDMOUNT_PASS);
552                if (!n) {
553                    msg_box (dlg, _("Please enter a password."),
554                             _("Cryptdisk Error"), MB_ERR);
555                    return FALSE;
556                }
557                devnum = GetDlgItemInt (dlg, IDC_CDMOUNT_ID, NULL, FALSE);
558                GetDlgItemText (dlg, IDC_CDMOUNT_DRV, drive, sizeof drive-1);
559                GetDlgItemText (dlg, IDC_CDMOUNT_PASS, passwd, sizeof passwd-1);
560                GetDlgItemText (dlg, IDC_CDMOUNT_IMGFILE, imgfile, sizeof imgfile-1);
561                if (file_exist_check  (imgfile)) {
562                    msg_box (dlg, _("Image file does not exist or could not be accessed."),
563                             _("Cryptdisk Error"), MB_ERR);
564                    return FALSE;
565                }
566                rc = cryptdisk_mount (devnum, imgfile, 0, drive);
567                if (!rc) {
568                    mount_list_t n = new_mount_list (drive, devnum);
569                    if (!mounted)
570                        mounted = n;
571                    else
572                        add_mount_list (mounted, n);
573                    EndDialog (dlg, TRUE);
574                }
575                else
576                    msg_box (dlg, winpt_strerror (rc), _("Cryptdisk Error"), MB_ERR);
577                break;
578    
579            case IDCANCEL:
580                EndDialog (dlg, FALSE);
581                break;
582            }
583            break;
584        }
585        return FALSE;
586    }
587    
588    
589    static void
590    load_devs_from_mountlist (HWND dlg, int ctlid)
591    {
592        mount_list_t n;
593        char buf[128];
594    
595        if (!mounted)
596            return;
597    
598        for (n=mounted; n; n=n->next) {
599            if (n->ttl == 0)
600                continue;
601            _snprintf (buf, sizeof buf-1, _("Drive %s (ID %d); Size %d MB, Readonly=%s"),
602                        n->drive, n->devnum, n->size.LowPart/1024/1024,
603                        n->rdonly? "true" : "false");
604            SendDlgItemMessage (dlg, ctlid, LB_ADDSTRING, 0, (LPARAM)(const char *)buf);
605        }
606    
607    }
608    
609    
610    static void
611    do_reaping (void)
612    {
613        mount_list_t n;
614        int ndevs=0, numount=0;
615    
616        for (n=mounted; n; n=n->next) {
617            if (n->ttl == 0)
618                numount++;
619            ndevs++;
620        }
621        if (ndevs == numount) {
622            free_mount_list (mounted);
623            mounted = NULL;
624        }
625    }
626    
627    
628    BOOL CALLBACK
629    cryptdisk_umount_dlg_proc (HWND dlg, UINT msg, WPARAM wparam, LPARAM lparam)
630    {    
631        mount_list_t vol;
632        char buf[128];
633        int n, rc=0;
634    
635        switch (msg) {
636        case WM_INITDIALOG:
637            do_check (dlg);
638            load_devs_from_mountlist (dlg, IDC_CDUMOUNT_LIST);
639            center_window (dlg, NULL);
640            SetForegroundWindow (dlg);
641            break;
642    
643        case WM_DESTROY:
644            do_reaping ();
645            break;
646    
647        case WM_COMMAND:
648            switch (LOWORD (wparam)) {
649            case IDOK:
650                n = SendDlgItemMessage (dlg, IDC_CDUMOUNT_LIST, LB_GETCURSEL, 0, 0);
651                if (n == LB_ERR) {
652                    msg_box (dlg, _("Please select one drive to umount."), _("Cryptdisk"), MB_INFO);
653                    return FALSE;
654                }
655                SendDlgItemMessage (dlg, IDC_CDUMOUNT_LIST, LB_GETTEXT, n,
656                                    (LPARAM)(char *)buf);
657                strcpy (buf, buf+6);
658                buf[2] = '\0';
659                vol = find_mount_list (mounted, buf);
660                if (!vol)
661                    BUG (0);
662                rc = cryptdisk_unmount (buf[0], 0);
663                //if (rc == WPTERR_CDISK_LOCK)
664            //      rc = cryptdisk_unmount (buf[0], 0);
665                if (!rc) {
666                    SendDlgItemMessage (dlg, IDC_CDUMOUNT_LIST, LB_DELETESTRING, (WPARAM)n, 0);
667                    remove_mount_list (mounted, vol);
668                }
669                else
670                    msg_box (dlg, winpt_strerror (rc), _("Cryptdisk Error"), MB_ERR);
671                break;
672            case IDCANCEL:
673                EndDialog (dlg, FALSE);
674                break;
675            }
676            break;
677        }
678    
679        return FALSE;
680    }
681    
682    
683    int
684    cryptdisk_serv_run (void)
685    {
686        SC_HANDLE hd;
687        ENUM_SERVICE_STATUS ess[4096];
688        DWORD nservs=0, dummy=0;
689        DWORD i;
690        int rc=0;
691    
692        hd = OpenSCManager (NULL, NULL, SC_MANAGER_ENUMERATE_SERVICE);
693        if (!hd)
694            return 0;
695    
696        EnumServicesStatus (hd,  SERVICE_DRIVER, SERVICE_ACTIVE,
697                            (LPENUM_SERVICE_STATUS)&ess,
698                            sizeof ess-1, &dummy, &nservs, &dummy);
699    
700        for (i=0; i < nservs; i++) {
701            if (!strnicmp ("FileDisk", ess[i].lpDisplayName, 8)) {
702                rc = 1;
703                break;
704            }
705        }
706    
707        CloseServiceHandle (hd);
708        return rc;
709    }

Legend:
Removed from v.23  
changed lines
  Added in v.36

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26