63765f5bd033c53cf86a9a27e3b8505cb5431786
[gpgol.git] / src / main.c
1 /* main.c - DLL entry point
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
22 #include <windows.h>
23 #include <wincrypt.h>
24
25 #include "mymapi.h"
26 #include "mymapitags.h"
27
28 #include "common.h"
29 #include "passcache.h"
30 #include "msgcache.h"
31 #include "mymapi.h"
32
33
34 /* The malloced name of the logfile and the logging stream.  If
35    LOGFILE is NULL, no logging is done. */
36 static char *logfile;
37 static FILE *logfp;
38
39 /* For certain operations we need to acquire a log on the logging
40    functions.  This lock is controlled by this Mutex. */
41 static HANDLE log_mutex;
42
43 /* The session key used to temporary encrypt attachments.  It is
44    initialized at startup.  */
45 static char *the_session_key;
46
47 /* The session marker to identify this session.  Its value is not
48   confidential.  It is initialized at startup.  */
49 static char *the_session_marker;
50
51 /* Local function prototypes. */
52 static char *get_locale_dir (void);
53 static void drop_locale_dir (char *locale_dir);
54
55
56 \f
57 /* Initialization of gloabl options.  These are merely the defaults
58    and will get updated later from the Registry.  That is done later
59    at the time Outlook calls its entry point the first time. */
60 static void
61 init_options (void)
62 {
63   opt.passwd_ttl = 10; /* Seconds. Use a small value, so that no
64                           multiple prompts for attachment encryption
65                           are issued. */
66   opt.enc_format = GPG_FMT_CLASSIC;
67 }
68
69
70 /* Early initialization of this module.  This is done right at startup
71    with only one thread running.  Should be called only once. Returns
72    0 on success. */
73 static int
74 initialize_main (void)
75 {
76   SECURITY_ATTRIBUTES sa;
77   
78   memset (&sa, 0, sizeof sa);
79   sa.bInheritHandle = FALSE;
80   sa.lpSecurityDescriptor = NULL;
81   sa.nLength = sizeof sa;
82   log_mutex = CreateMutex (&sa, FALSE, NULL);
83   return log_mutex? 0 : -1;
84 }
85
86 /* Return nbytes of cryptographic strong random.  Caller needs to free
87    the returned buffer.  */
88 static char *
89 get_crypt_random (size_t nbytes) 
90 {
91   HCRYPTPROV prov;
92   char *buffer;
93
94   if (!CryptAcquireContext (&prov, NULL, NULL, PROV_RSA_FULL, 
95                             (CRYPT_VERIFYCONTEXT|CRYPT_SILENT)) )
96     return NULL;
97   
98   buffer = xmalloc (nbytes);
99   if (!CryptGenRandom (prov, nbytes, buffer))
100     {
101       xfree (buffer);
102       buffer = NULL;
103     }
104   CryptReleaseContext (prov, 0);
105   return buffer;
106 }
107
108
109 /* Initialize the session key and the session marker.  */
110 static int
111 initialize_session_key (void)
112 {
113   the_session_key = get_crypt_random (16+sizeof (unsigned int)+8);
114   if (the_session_key)
115     {
116       /* We use rand() in generate_boundary so we need to seed it. */
117       unsigned int tmp;
118
119       memcpy (&tmp, the_session_key+16, sizeof (unsigned int));
120       srand (tmp);
121
122       /* And save the session marker. */
123       the_session_marker = the_session_key + 16 + sizeof (unsigned int);
124     }
125   return !the_session_key;
126 }
127
128
129 static void
130 i18n_init (void)
131 {
132   char *locale_dir;
133
134 #ifdef ENABLE_NLS
135 # ifdef HAVE_LC_MESSAGES
136   setlocale (LC_TIME, "");
137   setlocale (LC_MESSAGES, "");
138 # else
139   setlocale (LC_ALL, "" );
140 # endif
141 #endif
142
143   locale_dir = get_locale_dir ();
144   if (locale_dir)
145     {
146       bindtextdomain (PACKAGE_GT, locale_dir);
147       drop_locale_dir (locale_dir);
148     }
149   textdomain (PACKAGE_GT);
150 }
151
152
153 /* Entry point called by DLL loader. */
154 int WINAPI
155 DllMain (HINSTANCE hinst, DWORD reason, LPVOID reserved)
156 {
157   if (reason == DLL_PROCESS_ATTACH)
158     {
159       set_global_hinstance (hinst);
160       /* The next call initializes subsystems of gpgme and should be
161          done as early as possible.  The actual return value (the
162          version string) is not used here.  It may be called at any
163          time later for this. */
164       gpgme_check_version (NULL);
165
166       /* Early initializations of our subsystems. */
167       if (initialize_main ())
168         return FALSE;
169       i18n_init ();
170       if (initialize_session_key ())
171         return FALSE;
172       if (initialize_passcache ())
173         return FALSE;
174       if (initialize_msgcache ())
175         return FALSE;
176       init_options ();
177     }
178   else if (reason == DLL_PROCESS_DETACH)
179     {
180     }
181   
182   return TRUE;
183 }
184
185
186
187 /* Return the static session key we are using for temporary encrypting
188    attachments.  The session key is guaranteed to be available.  */
189 const void *
190 get_128bit_session_key (void)
191 {
192   return the_session_key;
193 }
194
195
196 const void *
197 get_64bit_session_marker (void)
198 {
199   return the_session_marker;
200 }
201
202
203 /* Return a new allocated IV of size NBYTES.  Caller must free it.  On
204    error NULL is returned. */
205 void *
206 create_initialization_vector (size_t nbytes)
207 {
208   return get_crypt_random (nbytes);
209 }
210
211
212 /* Acquire the mutex for logging.  Returns 0 on success. */
213 static int 
214 lock_log (void)
215 {
216   int code = WaitForSingleObject (log_mutex, INFINITE);
217   return code != WAIT_OBJECT_0;
218 }
219
220 /* Release the mutex for logging. No error return is done because this
221    is a fatal error anyway and we have no means for proper
222    notification. */
223 static void
224 unlock_log (void)
225 {
226   ReleaseMutex (log_mutex);
227 }
228
229
230
231 static void
232 do_log (const char *fmt, va_list a, int w32err, int err,
233         const void *buf, size_t buflen)
234 {
235   if (!logfile)
236     return;
237
238   if (lock_log ())
239     return;
240   
241   if (!logfp)
242     logfp = fopen (logfile, "a+");
243   if (!logfp)
244     {
245       unlock_log ();
246       return;
247     }
248   
249   fprintf (logfp, "%lu/", (unsigned long)GetCurrentThreadId ());
250   if (err == 1)
251     fputs ("ERROR/", logfp);
252   vfprintf (logfp, fmt, a);
253   if (w32err) 
254     {
255       char tmpbuf[256];
256       
257       FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, NULL, w32err, 
258                      MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), 
259                      tmpbuf, sizeof (tmpbuf)-1, NULL);
260       fputs (": ", logfp);
261       if (*tmpbuf && tmpbuf[strlen (tmpbuf)-1] == '\n')
262         tmpbuf[strlen (tmpbuf)-1] = 0;
263       if (*tmpbuf && tmpbuf[strlen (tmpbuf)-1] == '\r')
264         tmpbuf[strlen (tmpbuf)-1] = 0;
265       fprintf (logfp, "%s (%d)", tmpbuf, w32err);
266     }
267   if (buf)
268     {
269       const unsigned char *p = (const unsigned char*)buf;
270
271       for ( ; buflen; buflen--, p++)
272         fprintf (logfp, "%02X", *p);
273       putc ('\n', logfp);
274     }
275   else if ( *fmt && fmt[strlen (fmt) - 1] != '\n')
276     putc ('\n', logfp);
277
278   fflush (logfp);
279   unlock_log ();
280 }
281
282
283 void 
284 log_debug (const char *fmt, ...)
285 {
286   va_list a;
287   
288   va_start (a, fmt);
289   do_log (fmt, a, 0, 0, NULL, 0);
290   va_end (a);
291 }
292
293 void 
294 log_error (const char *fmt, ...)
295 {
296   va_list a;
297   
298   va_start (a, fmt);
299   do_log (fmt, a, 0, 1, NULL, 0);
300   va_end (a);
301 }
302
303 void 
304 log_vdebug (const char *fmt, va_list a)
305 {
306   do_log (fmt, a, 0, 0, NULL, 0);
307 }
308
309
310 void 
311 log_debug_w32 (int w32err, const char *fmt, ...)
312 {
313   va_list a;
314
315   if (w32err == -1)
316     w32err = GetLastError ();
317   
318   va_start (a, fmt);
319   do_log (fmt, a, w32err, 0, NULL, 0);
320   va_end (a);
321 }
322
323 void 
324 log_error_w32 (int w32err, const char *fmt, ...)
325 {
326   va_list a;
327
328   if (w32err == -1)
329     w32err = GetLastError ();
330   
331   va_start (a, fmt);
332   do_log (fmt, a, w32err, 1, NULL, 0);
333   va_end (a);
334 }
335
336
337 void 
338 log_hexdump (const void *buf, size_t buflen, const char *fmt, ...)
339 {
340   va_list a;
341
342   va_start (a, fmt);
343   do_log (fmt, a, 0, 2, buf, buflen);
344   va_end (a);
345 }
346
347
348 static void
349 do_log_window_info (HWND window, int level)
350 {
351   char buf[1024+1];
352   char name[200];
353   int nname;
354   char *pname;
355
356   if (!window)
357     return;
358       
359   memset (buf, 0, sizeof (buf));
360   GetWindowText (window, buf, sizeof (buf)-1);
361   nname = GetClassName (window, name, sizeof (name)-1);
362   if (nname)
363     pname = name;
364   else
365     pname = NULL;
366   if (level == -1)
367     log_debug ("  parent=%p (%s) `%s'", window, pname? pname:"", buf);
368   else
369     log_debug ("    %*shwnd=%p (%s) `%s'", level*2, "", window,
370                pname? pname:"", buf);
371 }
372
373
374 /* Helper to log_window_hierarchy.  */
375 static HWND
376 do_log_window_hierarchy (HWND parent, int level)
377 {
378   HWND child;
379
380   child = GetWindow (parent, GW_CHILD);
381   while (child)
382     {
383       do_log_window_info (child, level);
384       do_log_window_hierarchy (child, level+1);
385       child = GetNextWindow (child, GW_HWNDNEXT);       
386     }
387
388   return NULL;
389 }
390
391
392 /* Print a debug message using the format string FMT followed by the
393    window hierarchy of WINDOW.  */
394 void
395 log_window_hierarchy (HWND window, const char *fmt, ...)
396 {
397   va_list a;
398
399   va_start (a, fmt);
400   do_log (fmt, a, 0, 0, NULL, 0);
401   va_end (a);
402   if (window)
403     {
404       do_log_window_info (window, -1);
405       do_log_window_hierarchy (window, 0);
406     }
407 }
408
409
410
411
412 const char *
413 log_srcname (const char *file)
414 {
415   const char *s = strrchr (file, '/');
416   return s? s+1:file;
417 }
418
419 const char *
420 get_log_file (void)
421 {
422   return logfile? logfile : "";
423 }
424
425 void
426 set_log_file (const char *name)
427 {
428   if (!lock_log ())
429     {
430       if (logfp)
431         {
432           fclose (logfp);
433           logfp = NULL;
434         }
435       xfree (logfile);
436       if (!name || *name == '\"' || !*name) 
437         logfile = NULL;
438       else
439         logfile = xstrdup (name);
440       unlock_log ();
441     }
442 }
443
444
445
446 void
447 set_default_key (const char *name)
448 {
449   if (!lock_log ())
450     {
451       if (!name || *name == '\"' || !*name)
452         {
453           xfree (opt.default_key);
454           opt.default_key = NULL;
455         }
456       else
457         {
458           xfree (opt.default_key);
459           opt.default_key = xstrdup (name);;
460         }
461       unlock_log ();
462     }
463 }
464
465
466 static char *
467 get_locale_dir (void)
468 {
469   char *instdir;
470   char *p;
471   char *dname;
472
473   instdir = read_w32_registry_string ("HKEY_LOCAL_MACHINE", GNUPG_REGKEY,
474                                       "Install Directory");
475   if (!instdir)
476     return NULL;
477   
478   /* Build the key: "<instdir>/share/locale".  */
479 #define SLDIR "\\share\\locale"
480   dname = malloc (strlen (instdir) + strlen (SLDIR) + 1);
481   if (!dname)
482     {
483       free (instdir);
484       return NULL;
485     }
486   p = dname;
487   strcpy (p, instdir);
488   p += strlen (instdir);
489   strcpy (p, SLDIR);
490   
491   free (instdir);
492   
493   return dname;
494 }
495
496
497 static void
498 drop_locale_dir (char *locale_dir)
499 {
500   free (locale_dir);
501 }
502
503
504 /* Read option settings from the Registry. */
505 void
506 read_options (void)
507 {
508   static int warnings_shown;
509   char *val = NULL;
510  
511   load_extension_value ("enableDebug", &val);
512   opt.enable_debug = val == NULL || *val != '1' ? 0 : 1;
513   xfree (val); val = NULL;
514
515   load_extension_value ("enableSmime", &val);
516   opt.enable_smime = val == NULL || *val != '1' ? 0 : 1;
517   xfree (val); val = NULL;
518   
519   load_extension_value ("defaultProtocol", &val);
520   switch ((!val || *val == '0')? 0 : atol (val))
521     {
522     case 1: opt.default_protocol = PROTOCOL_OPENPGP; break;
523     case 2: opt.default_protocol = PROTOCOL_SMIME; break;
524     case 0:
525     default: opt.default_protocol = PROTOCOL_UNKNOWN /*(auto*)*/; break;
526     }
527   xfree (val); val = NULL;
528
529   load_extension_value ("encryptDefault", &val);
530   opt.encrypt_default = val == NULL || *val != '1'? 0 : 1;
531   xfree (val); val = NULL;
532
533   load_extension_value ("signDefault", &val);
534   opt.sign_default = val == NULL || *val != '1'? 0 : 1;
535   xfree (val); val = NULL;
536
537   load_extension_value ("previewDecrypt", &val);
538   opt.preview_decrypt = val == NULL || *val != '1'? 0 : 1;
539   xfree (val); val = NULL;
540
541   load_extension_value ("enableDefaultKey", &val);
542   opt.enable_default_key = val == NULL || *val != '1' ? 0 : 1;
543   xfree (val); val = NULL;
544
545   if (load_extension_value ("storePasswdTime", &val) )
546     opt.passwd_ttl = 600; /* Initial default. */
547   else
548     opt.passwd_ttl = val == NULL || *val == '0'? 0 : atol (val);
549   xfree (val); val = NULL;
550
551   load_extension_value ("encodingFormat", &val);
552   opt.enc_format = val == NULL? GPG_FMT_CLASSIC  : atol (val);
553   xfree (val); val = NULL;
554
555   load_extension_value ("logFile", &val);
556   set_log_file (val);
557   xfree (val); val = NULL;
558   
559   load_extension_value ("defaultKey", &val);
560   set_default_key (val);
561   xfree (val); val = NULL;
562
563   load_extension_value ("preferHtml", &val);
564   opt.prefer_html = val == NULL || *val != '1'? 0 : 1;
565   xfree (val); val = NULL;
566
567   /* Note, that on purpose these flags are only Registry changeable.
568      The format of the entry is a string of of "0" and "1" digits; see
569      the switch below for a description. */
570   memset (&opt.compat, 0, sizeof opt.compat);
571   load_extension_value ("compatFlags", &val);
572   if (val)
573     {
574       const char *s = val;
575       int i, x;
576
577       for (s=val, i=0; *s; s++, i++)
578         {
579           x = *s == '1';
580           switch (i)
581             {
582             case 0: opt.compat.no_msgcache = x; break;
583             case 1: opt.compat.no_pgpmime = x; break;
584             case 2: opt.compat.no_oom_write = x; break;
585             case 3: opt.compat.no_preview_info = x; break;
586             case 4: opt.compat.old_reply_hack = x; break;
587             case 5: opt.compat.auto_decrypt = x; break;
588             case 6: opt.compat.no_attestation = x; break;
589             }
590         }
591       log_debug ("Note: using compatibility flags: %s", val);
592     }
593
594   if (!warnings_shown)
595     {
596       char tmpbuf[512];
597           
598       warnings_shown = 1;
599       if (val && *val)
600         {
601           snprintf (tmpbuf, sizeof tmpbuf,
602                     _("Note: Using compatibility flags: %s"), val);
603           MessageBox (NULL, tmpbuf, _("GpgOL"), MB_ICONWARNING|MB_OK);
604         }
605       if (logfile && !opt.enable_debug)
606         {
607           snprintf (tmpbuf, sizeof tmpbuf,
608                     _("Note: Writing debug logs to\n\n\"%s\""), logfile);
609           MessageBox (NULL, tmpbuf, _("GpgOL"), MB_ICONWARNING|MB_OK);
610         }
611     }
612   xfree (val); val = NULL;
613
614 }
615
616
617 /* Write current options back to the Registry. */
618 int
619 write_options (void)
620 {
621   struct 
622   {
623     const char *name;
624     int  mode;
625     int  value;
626     char *s_val;
627   } table[] = {
628     {"enableSmime",              0, opt.enable_smime},
629     {"defaultProtocol",          3, opt.default_protocol},
630     {"encryptDefault",           0, opt.encrypt_default},
631     {"signDefault",              0, opt.sign_default},
632     {"previewDecrypt",           0, opt.preview_decrypt},
633     {"storePasswdTime",          1, opt.passwd_ttl},
634     {"encodingFormat",           1, opt.enc_format},
635     {"logFile",                  2, 0, logfile},
636     {"defaultKey",               2, 0, opt.default_key},
637     {"enableDefaultKey",         0, opt.enable_default_key},
638     {"preferHtml",               0, opt.prefer_html},
639     {NULL, 0}
640   };
641   char buf[32];
642   int rc, i;
643
644   for (i=0; table[i].name; i++) 
645     {
646       log_debug ("storing option `%s'\n", table[i].name);
647       switch (table[i].mode)
648         {
649         case 0:
650           rc = store_extension_value (table[i].name, table[i].value? "1": "0");
651           break;
652         case 1:
653           sprintf (buf, "%d", table[i].value);
654           rc = store_extension_value (table[i].name, buf);
655           break;
656         case 2:
657           rc = store_extension_value (table[i].name,
658                                       table[i].s_val? table[i].s_val : "");
659           break;
660         case 3:
661           buf[0] = '0';
662           buf[1] = 0;
663           switch (opt.default_protocol)
664             {
665             case PROTOCOL_UNKNOWN: buf[0] = '0'; /* auto */ break;
666             case PROTOCOL_OPENPGP: buf[0] = '1'; break;
667             case PROTOCOL_SMIME:   buf[0] = '2'; break;
668             }
669           rc = store_extension_value (table[i].name, buf);
670           break;  
671
672         default:
673           rc = -1;
674           break;
675         }
676       if (rc)
677         log_error ("error storing option `%s': rc = %d\n", table[i].name, rc);
678     }
679   
680   return 0;
681 }