0388dba9408d4662db1866ca02f5e6ca7c18bc59
[gpgol.git] / src / common.c
1 /* common.c - Common routines used by GpgOL
2  *      Copyright (C) 2005, 2007 g10 Code GmbH
3  *
4  * This file is part of GpgOL.
5  *
6  * GpgOL is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public License
8  * as published by the Free Software Foundation; either version 2.1 
9  * of the License, or (at your option) any later version.
10  *  
11  * GpgOL 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 GNU
14  * General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public License
17  * along with this program; if not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include <config.h>
21 #include <windows.h>
22 #include <shlobj.h>
23 #ifndef CSIDL_APPDATA
24 #define CSIDL_APPDATA 0x001a
25 #endif
26 #ifndef CSIDL_LOCAL_APPDATA
27 #define CSIDL_LOCAL_APPDATA 0x001c
28 #endif
29 #ifndef CSIDL_FLAG_CREATE
30 #define CSIDL_FLAG_CREATE 0x8000
31 #endif
32 #include <time.h>
33 #include <fcntl.h>
34
35 #include "common.h"
36
37 HINSTANCE glob_hinst = NULL;
38
39
40 /* The base-64 list used for base64 encoding. */
41 static unsigned char bintoasc[64+1] = ("ABCDEFGHIJKLMNOPQRSTUVWXYZ" 
42                                        "abcdefghijklmnopqrstuvwxyz" 
43                                        "0123456789+/"); 
44
45 /* The reverse base-64 list used for base-64 decoding. */
46 static unsigned char const asctobin[256] = {
47   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
48   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
49   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
50   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3e, 0xff, 0xff, 0xff, 0x3f, 
51   0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0xff, 0xff, 
52   0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 
53   0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 
54   0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0xff, 0xff, 0xff, 0xff, 0xff, 
55   0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 
56   0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 
57   0x31, 0x32, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
58   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
59   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
60   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
61   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
62   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
63   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
64   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
65   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
66   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
67   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
68   0xff, 0xff, 0xff, 0xff
69 };
70
71
72
73 void
74 set_global_hinstance (HINSTANCE hinst)
75 {
76     glob_hinst = hinst;
77 }
78
79 /* Center the given window with the desktop window as the
80    parent window. */
81 void
82 center_window (HWND childwnd, HWND style) 
83 {     
84     HWND parwnd;
85     RECT rchild, rparent;    
86     HDC hdc;
87     int wchild, hchild, wparent, hparent;
88     int wscreen, hscreen, xnew, ynew;
89     int flags = SWP_NOSIZE | SWP_NOZORDER;
90
91     parwnd = GetDesktopWindow ();
92     GetWindowRect (childwnd, &rchild);     
93     wchild = rchild.right - rchild.left;     
94     hchild = rchild.bottom - rchild.top;
95
96     GetWindowRect (parwnd, &rparent);     
97     wparent = rparent.right - rparent.left;     
98     hparent = rparent.bottom - rparent.top;      
99     
100     hdc = GetDC (childwnd);     
101     wscreen = GetDeviceCaps (hdc, HORZRES);     
102     hscreen = GetDeviceCaps (hdc, VERTRES);     
103     ReleaseDC (childwnd, hdc);      
104     xnew = rparent.left + ((wparent - wchild) / 2);     
105     if (xnew < 0)
106         xnew = 0;
107     else if ((xnew+wchild) > wscreen) 
108         xnew = wscreen - wchild;
109     ynew = rparent.top  + ((hparent - hchild) / 2);
110     if (ynew < 0)
111         ynew = 0;
112     else if ((ynew+hchild) > hscreen)
113         ynew = hscreen - hchild;
114     if (style == HWND_TOPMOST || style == HWND_NOTOPMOST)
115         flags = SWP_NOMOVE | SWP_NOSIZE;
116     SetWindowPos (childwnd, style? style : NULL, xnew, ynew, 0, 0, flags);
117 }
118
119
120
121 /* Return a filename to be used for saving an attachment. Returns a
122    malloced string on success. HWND is the current Window and SRCNAME
123    the filename to be used as suggestion.  On error (i.e. cancel) NULL
124    is returned. */
125 char *
126 get_save_filename (HWND root, const char *srcname)
127 {
128   char filter[] = "All Files (*.*)\0*.*\0\0";
129   char fname[MAX_PATH+1];
130   OPENFILENAME ofn;
131
132   memset (fname, 0, sizeof (fname));
133   strncpy (fname, srcname, MAX_PATH-1);
134   fname[MAX_PATH] = 0;  
135   
136
137   memset (&ofn, 0, sizeof (ofn));
138   ofn.lStructSize = sizeof (ofn);
139   ofn.hwndOwner = root;
140   ofn.lpstrFile = fname;
141   ofn.nMaxFile = MAX_PATH;
142   ofn.lpstrFileTitle = NULL;
143   ofn.nMaxFileTitle = 0;
144   ofn.Flags |= OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT;
145   ofn.lpstrTitle = _("GpgOL - Save decrypted attachment");
146   ofn.lpstrFilter = filter;
147
148   if (GetSaveFileName (&ofn))
149     return xstrdup (fname);
150   return NULL;
151 }
152
153
154 void
155 out_of_core (void)
156 {
157     MessageBox (NULL, "Out of core!", "Fatal Error", MB_OK);
158     abort ();
159 }
160
161 void*
162 xmalloc (size_t n)
163 {
164     void *p = malloc (n);
165     if (!p)
166         out_of_core ();
167     return p;
168 }
169
170 void*
171 xcalloc (size_t m, size_t n)
172 {
173     void *p = calloc (m, n);
174     if (!p)
175         out_of_core ();
176     return p;
177 }
178
179 void *
180 xrealloc (void *a, size_t n)
181 {
182   void *p = realloc (a, n);
183   if (!p)
184     out_of_core ();
185   return p;
186 }
187
188 char*
189 xstrdup (const char *s)
190 {
191     char *p = xmalloc (strlen (s)+1);
192     strcpy (p, s);
193     return p;
194 }
195
196 void
197 xfree (void *p)
198 {
199     if (p)
200         free (p);
201 }
202
203
204 /* This is a helper function to load a Windows function from either of
205    one DLLs. */
206 static HRESULT
207 w32_shgetfolderpath (HWND a, int b, HANDLE c, DWORD d, LPSTR e)
208 {
209   static int initialized;
210   static HRESULT (WINAPI * func)(HWND,int,HANDLE,DWORD,LPSTR);
211
212   if (!initialized)
213     {
214       static char *dllnames[] = { "shell32.dll", "shfolder.dll", NULL };
215       void *handle;
216       int i;
217
218       initialized = 1;
219
220       for (i=0, handle = NULL; !handle && dllnames[i]; i++)
221         {
222           handle = LoadLibrary (dllnames[i]);
223           if (handle)
224             {
225               func = (HRESULT (WINAPI *)(HWND,int,HANDLE,DWORD,LPSTR))
226                      GetProcAddress (handle, "SHGetFolderPathA");
227               if (!func)
228                 {
229                   FreeLibrary (handle);
230                   handle = NULL;
231                 }
232             }
233         }
234     }
235
236   if (func)
237     return func (a,b,c,d,e);
238   else
239     return -1;
240 }
241
242
243
244 /* Same as above, but only convert the first LEN wchars.  */
245 char *
246 wchar_to_utf8_2 (const wchar_t *string, size_t len)
247 {
248   int n;
249   char *result;
250
251   /* Note, that CP_UTF8 is not defined in Windows versions earlier
252      than NT.*/
253   n = WideCharToMultiByte (CP_UTF8, 0, string, len, NULL, 0, NULL, NULL);
254   if (n < 0)
255     return NULL;
256
257   result = xmalloc (n+1);
258   n = WideCharToMultiByte (CP_UTF8, 0, string, len, result, n, NULL, NULL);
259   if (n < 0)
260     {
261       xfree (result);
262       return NULL;
263     }
264   return result;
265 }
266
267
268 /* Same as above but convert only the first LEN characters.  STRING
269    must be at least LEN characters long. */
270 wchar_t *
271 utf8_to_wchar2 (const char *string, size_t len)
272 {
273   int n;
274   wchar_t *result;
275
276   n = MultiByteToWideChar (CP_UTF8, 0, string, len, NULL, 0);
277   if (n < 0)
278     return NULL;
279
280   result = xmalloc ((n+1) * sizeof *result);
281   n = MultiByteToWideChar (CP_UTF8, 0, string, len, result, n);
282   if (n < 0)
283     {
284       xfree (result);
285       return NULL;
286     }
287   result[n] = 0;
288   return result;
289 }
290
291
292 /* Assume STRING is a Latin-1 encoded and convert it to utf-8.
293    Returns a newly malloced UTF-8 string. */
294 char *
295 latin1_to_utf8 (const char *string)
296 {
297   const char *s;
298   char *buffer, *p;
299   size_t n;
300
301   for (s=string, n=0; *s; s++) 
302     {
303       n++;
304       if (*s & 0x80)
305         n++;
306     }
307   buffer = xmalloc (n + 1);
308   for (s=string, p=buffer; *s; s++)
309     {
310       if (*s & 0x80)
311         {
312           *p++ = 0xc0 | ((*s >> 6) & 3);
313           *p++ = 0x80 | (*s & 0x3f);
314         }
315       else
316         *p++ = *s;
317     }
318   *p = 0;
319   return buffer;
320 }
321
322
323 /* Strip off trailing white spaces from STRING.  Returns STRING. */
324 char *
325 trim_trailing_spaces (char *string)
326 {
327   char *p, *mark;
328
329   for (mark=NULL, p=string; *p; p++)
330     {
331       if (strchr (" \t\r\n", *p ))
332         {
333           if (!mark)
334             mark = p;
335         }
336         else
337           mark = NULL;
338     }
339
340   if (mark)
341     *mark = 0;
342   return string;
343 }
344
345
346 /* Helper for read_w32_registry_string(). */
347 static HKEY
348 get_root_key(const char *root)
349 {
350   HKEY root_key;
351
352   if( !root )
353     root_key = HKEY_CURRENT_USER;
354   else if( !strcmp( root, "HKEY_CLASSES_ROOT" ) )
355     root_key = HKEY_CLASSES_ROOT;
356   else if( !strcmp( root, "HKEY_CURRENT_USER" ) )
357     root_key = HKEY_CURRENT_USER;
358   else if( !strcmp( root, "HKEY_LOCAL_MACHINE" ) )
359     root_key = HKEY_LOCAL_MACHINE;
360   else if( !strcmp( root, "HKEY_USERS" ) )
361     root_key = HKEY_USERS;
362   else if( !strcmp( root, "HKEY_PERFORMANCE_DATA" ) )
363     root_key = HKEY_PERFORMANCE_DATA;
364   else if( !strcmp( root, "HKEY_CURRENT_CONFIG" ) )
365     root_key = HKEY_CURRENT_CONFIG;
366   else
367     return NULL;
368   return root_key;
369 }
370
371 /* Return a string from the Win32 Registry or NULL in case of error.
372    Caller must release the return value.  A NULL for root is an alias
373    for HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE in turn.  NOTE: The value
374    is allocated with a plain malloc() - use free() and not the usual
375    xfree(). */
376 char *
377 read_w32_registry_string (const char *root, const char *dir, const char *name)
378 {
379   HKEY root_key, key_handle;
380   DWORD n1, nbytes, type;
381   char *result = NULL;
382
383   if ( !(root_key = get_root_key(root) ) )
384     return NULL;
385
386   if( RegOpenKeyEx( root_key, dir, 0, KEY_READ, &key_handle ) )
387     {
388       if (root)
389         return NULL; /* no need for a RegClose, so return direct */
390       /* It seems to be common practise to fall back to HKLM. */
391       if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, dir, 0, KEY_READ, &key_handle) )
392         return NULL; /* still no need for a RegClose, so return direct */
393     }
394
395   nbytes = 1;
396   if( RegQueryValueEx( key_handle, name, 0, NULL, NULL, &nbytes ) ) {
397     if (root)
398       goto leave;
399     /* Try to fallback to HKLM also vor a missing value.  */
400     RegCloseKey (key_handle);
401     if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, dir, 0, KEY_READ, &key_handle) )
402       return NULL; /* Nope.  */
403     if (RegQueryValueEx( key_handle, name, 0, NULL, NULL, &nbytes))
404       goto leave;
405   }
406   result = malloc( (n1=nbytes+1) );
407   if( !result )
408     goto leave;
409   if( RegQueryValueEx( key_handle, name, 0, &type, result, &n1 ) ) {
410     free(result); result = NULL;
411     goto leave;
412   }
413   result[nbytes] = 0; /* make sure it is really a string  */
414   if (type == REG_EXPAND_SZ && strchr (result, '%')) {
415     char *tmp;
416
417     n1 += 1000;
418     tmp = malloc (n1+1);
419     if (!tmp)
420       goto leave;
421     nbytes = ExpandEnvironmentStrings (result, tmp, n1);
422     if (nbytes && nbytes > n1) {
423       free (tmp);
424       n1 = nbytes;
425       tmp = malloc (n1 + 1);
426       if (!tmp)
427         goto leave;
428       nbytes = ExpandEnvironmentStrings (result, tmp, n1);
429       if (nbytes && nbytes > n1) {
430         free (tmp); /* oops - truncated, better don't expand at all */
431         goto leave;
432       }
433       tmp[nbytes] = 0;
434       free (result);
435       result = tmp;
436     }
437     else if (nbytes) { /* okay, reduce the length */
438       tmp[nbytes] = 0;
439       free (result);
440       result = malloc (strlen (tmp)+1);
441       if (!result)
442         result = tmp;
443       else {
444         strcpy (result, tmp);
445         free (tmp);
446       }
447     }
448     else {  /* error - don't expand */
449       free (tmp);
450     }
451   }
452
453  leave:
454   RegCloseKey( key_handle );
455   return result;
456 }
457
458
459 /* Get the standard home directory.  In general this function should
460    not be used as it does not consider a registry value or the
461    GNUPGHOME environment variable.  Please use default_homedir(). */
462 static const char *
463 standard_homedir (void)
464 {
465   static char *dir;
466
467   if (!dir)
468     {
469       char path[MAX_PATH];
470       
471       /* It might be better to use LOCAL_APPDATA because this is
472          defined as "non roaming" and thus more likely to be kept
473          locally.  For private keys this is desired.  However, given
474          that many users copy private keys anyway forth and back,
475          using a system roaming services might be better than to let
476          them do it manually.  A security conscious user will anyway
477          use the registry entry to have better control.  */
478       if (w32_shgetfolderpath (NULL, CSIDL_APPDATA|CSIDL_FLAG_CREATE, 
479                                NULL, 0, path) >= 0) 
480         {
481           char *tmp = malloc (strlen (path) + 6 + 1);
482
483           strcpy (tmp, path);
484           strcat (tmp, "\\gnupg");
485           
486           dir = tmp;
487           
488           /* Try to create the directory if it does not yet exists.  */
489           if (access (dir, F_OK))
490             CreateDirectory (dir, NULL);
491         }
492       else
493         dir = xstrdup ("C:\\gnupg");
494     }
495   return dir;
496 }
497
498
499 /* Retrieve the default home directory.  */
500 const char *
501 default_homedir (void)
502 {
503   static char *dir;
504
505   if (!dir)
506     {
507       dir = getenv ("GNUPGHOME");
508       if (!dir || !*dir)
509         {
510           char *tmp;
511           
512           tmp = read_w32_registry_string (NULL, "Software\\GNU\\GnuPG",
513                                           "HomeDir");
514           if (tmp && !*tmp)
515             {
516               free (tmp);
517               tmp = NULL;
518             }
519           if (tmp)
520             dir = tmp;
521           else
522             dir = xstrdup (standard_homedir ());
523         }
524       else
525         dir = xstrdup (dir);
526     }
527   
528   return dir;
529 }
530
531
532 /* Do in-place decoding of quoted-printable data of LENGTH in BUFFER.
533    Returns the new length of the buffer. */
534 size_t
535 qp_decode (char *buffer, size_t length)
536 {
537   char *d, *s;
538
539   for (s=d=buffer; length; length--)
540     if (*s == '=')
541       {
542         if (length > 2 && hexdigitp (s+1) && hexdigitp (s+2))
543           {
544             s++;
545             *(unsigned char*)d++ = xtoi_2 (s);
546             s += 2;
547             length -= 2;
548           }
549         else if (length > 2 && s[1] == '\r' && s[2] == '\n')
550           {
551             /* Soft line break.  */
552             s += 3;
553             length -= 2;
554           }
555         else if (length > 1 && s[1] == '\n')
556           {
557             /* Soft line break with only a Unix line terminator. */
558             s += 2;
559             length -= 1;
560           }
561         else
562           *d++ = *s++;
563       }
564     else
565       *d++ = *s++;
566   
567   return d - buffer;
568 }
569
570
571 /* Initialize the Base 64 decoder state.  */
572 void b64_init (b64_state_t *state)
573 {
574   state->idx = 0;
575   state->val = 0;
576   state->stop_seen = 0;
577   state->invalid_encoding = 0;
578 }
579
580
581 /* Do in-place decoding of base-64 data of LENGTH in BUFFER.  Returns
582    the new length of the buffer. STATE is required to return errors and
583    to maintain the state of the decoder.  */
584 size_t
585 b64_decode (b64_state_t *state, char *buffer, size_t length)
586 {
587   int idx = state->idx;
588   unsigned char val = state->val;
589   int c;
590   char *d, *s;
591
592   if (state->stop_seen)
593     return 0;
594
595   for (s=d=buffer; length; length--, s++)
596     {
597       if (*s == '\n' || *s == ' ' || *s == '\r' || *s == '\t')
598         continue;
599       if (*s == '=')
600         { 
601           /* Pad character: stop */
602           if (idx == 1)
603             *d++ = val; 
604           state->stop_seen = 1;
605           break;
606         }
607
608       if ((c = asctobin[*(unsigned char *)s]) == 255) 
609         {
610           if (!state->invalid_encoding)
611             log_debug ("%s: invalid base64 character %02X at pos %d skipped\n",
612                        __func__, *(unsigned char*)s, (int)(s-buffer));
613           state->invalid_encoding = 1;
614           continue;
615         }
616
617       switch (idx) 
618         {
619         case 0: 
620           val = c << 2;
621           break;
622         case 1: 
623           val |= (c>>4)&3;
624           *d++ = val;
625           val = (c<<4)&0xf0;
626           break;
627         case 2: 
628           val |= (c>>2)&15;
629           *d++ = val;
630           val = (c<<6)&0xc0;
631           break;
632         case 3: 
633           val |= c&0x3f;
634           *d++ = val;
635           break;
636         }
637       idx = (idx+1) % 4;
638     }
639
640   
641   state->idx = idx;
642   state->val = val;
643   return d - buffer;
644 }
645
646
647 /* Create a boundary.  Note that mimemaker.c knows about the structure
648    of the boundary (i.e. that it starts with "=-=") so that it can
649    protect against accidently used boundaries within the content.  */
650 char *
651 generate_boundary (char *buffer)
652 {
653   char *p = buffer;
654   int i;
655
656 #if RAND_MAX < (64*2*BOUNDARYSIZE)
657 #error RAND_MAX is way too small
658 #endif
659
660   *p++ = '=';
661   *p++ = '-';
662   *p++ = '=';
663   for (i=0; i < BOUNDARYSIZE-6; i++) 
664     *p++ = bintoasc[rand () % 64];
665   *p++ = '=';
666   *p++ = '-';
667   *p++ = '=';
668   *p = 0;
669
670   return buffer;
671 }
672