More options / config cleanup
[gpgol.git] / src / common_indep.c
1 /* common_indep.c - Common, platform indepentent routines used by GpgOL
2  * Copyright (C) 2005, 2007, 2008 g10 Code GmbH
3  * Copyright (C) 2016 by Bundesamt für Sicherheit in der Informationstechnik
4  * Software engineering by Intevation GmbH
5  *
6  * This file is part of GpgOL.
7  *
8  * GpgOL is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public License
10  * as published by the Free Software Foundation; either version 2.1
11  * of the License, or (at your option) any later version.
12  *
13  * GpgOL is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  * General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public License
19  * along with this program; if not, see <http://www.gnu.org/licenses/>.
20  */
21
22 #include "common_indep.h"
23 #ifdef HAVE_W32_SYSTEM
24 #include <windows.h>
25 #endif
26
27 #include <stdlib.h>
28 #include <ctype.h>
29
30 /* The base-64 list used for base64 encoding. */
31 static unsigned char bintoasc[64+1] = ("ABCDEFGHIJKLMNOPQRSTUVWXYZ"
32                                        "abcdefghijklmnopqrstuvwxyz"
33                                        "0123456789+/");
34
35 /* The reverse base-64 list used for base-64 decoding. */
36 static unsigned char const asctobin[256] = {
37   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
38   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
39   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
40   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3e, 0xff, 0xff, 0xff, 0x3f,
41   0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0xff, 0xff,
42   0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
43   0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12,
44   0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0xff, 0xff, 0xff, 0xff, 0xff,
45   0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24,
46   0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
47   0x31, 0x32, 0x33, 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, 0xff, 0xff, 0xff, 0xff, 0xff,
51   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
52   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
53   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
54   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
55   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
56   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
57   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
58   0xff, 0xff, 0xff, 0xff
59 };
60
61 void
62 out_of_core (void)
63 {
64 #ifdef HAVE_W32_SYSTEM
65   MessageBox (NULL, "Out of core!", "Fatal Error", MB_OK);
66 #endif
67   abort ();
68 }
69
70 void*
71 xmalloc (size_t n)
72 {
73   void *p = malloc (n);
74   if (!p)
75     out_of_core ();
76   return p;
77 }
78
79 void*
80 xcalloc (size_t m, size_t n)
81 {
82   void *p = calloc (m, n);
83   if (!p)
84     out_of_core ();
85   return p;
86 }
87
88 void *
89 xrealloc (void *a, size_t n)
90 {
91   void *p = realloc (a, n);
92   if (!p)
93     out_of_core ();
94   return p;
95 }
96
97 char*
98 xstrdup (const char *s)
99 {
100   char *p = xmalloc (strlen (s)+1);
101   strcpy (p, s);
102   return p;
103 }
104
105 void
106 xfree (void *p)
107 {
108   if (p)
109     free (p);
110 }
111
112 /* Strip off leading and trailing white spaces from STRING.  Returns
113    STRING. */
114 char *
115 trim_spaces (char *arg_string)
116 {
117   char *string = arg_string;
118   char *p, *mark;
119
120   /* Find first non space character. */
121   for (p = string; *p && isascii (*p) && isspace (*p) ; p++ )
122     ;
123   /* Move characters. */
124   for (mark = NULL; (*string = *p); string++, p++ )
125     {
126       if (isascii (*p) && isspace (*p))
127         {
128           if (!mark)
129             mark = string;
130         }
131       else
132         mark = NULL ;
133     }
134   if (mark)
135     *mark = 0;
136
137   return arg_string;
138 }
139 /* Assume STRING is a Latin-1 encoded and convert it to utf-8.
140    Returns a newly malloced UTF-8 string. */
141 char *
142 latin1_to_utf8 (const char *string)
143 {
144   const char *s;
145   char *buffer, *p;
146   size_t n;
147
148   for (s=string, n=0; *s; s++)
149     {
150       n++;
151       if (*s & 0x80)
152         n++;
153     }
154   buffer = xmalloc (n + 1);
155   for (s=string, p=buffer; *s; s++)
156     {
157       if (*s & 0x80)
158         {
159           *p++ = 0xc0 | ((*s >> 6) & 3);
160           *p++ = 0x80 | (*s & 0x3f);
161         }
162       else
163         *p++ = *s;
164     }
165   *p = 0;
166   return buffer;
167 }
168
169
170 /* This function is similar to strncpy().  However it won't copy more
171    than N - 1 characters and makes sure that a Nul is appended. With N
172    given as 0, nothing will happen.  With DEST given as NULL, memory
173    will be allocated using xmalloc (i.e. if it runs out of core the
174    function terminates).  Returns DEST or a pointer to the allocated
175    memory.  */
176 char *
177 mem2str (char *dest, const void *src, size_t n)
178 {
179   char *d;
180   const char *s;
181
182   if (n)
183     {
184       if (!dest)
185         dest = xmalloc (n);
186       d = dest;
187       s = src ;
188       for (n--; n && *s; n--)
189         *d++ = *s++;
190       *d = 0;
191     }
192   else if (!dest)
193     {
194       dest = xmalloc (1);
195       *dest = 0;
196     }
197
198   return dest;
199 }
200
201
202 /* Strip off trailing white spaces from STRING.  Returns STRING. */
203 char *
204 trim_trailing_spaces (char *string)
205 {
206   char *p, *mark;
207
208   for (mark=NULL, p=string; *p; p++)
209     {
210       if (strchr (" \t\r\n", *p ))
211         {
212           if (!mark)
213             mark = p;
214         }
215       else
216         mark = NULL;
217     }
218
219   if (mark)
220     *mark = 0;
221   return string;
222 }
223
224 /* Do in-place decoding of quoted-printable data of LENGTH in BUFFER.
225    Returns the new length of the buffer and stores true at R_SLBRK if
226    the line ended with a soft line break; false is stored if not.
227    This fucntion asssumes that a complete line is passed in
228    buffer.  */
229 size_t
230 qp_decode (char *buffer, size_t length, int *r_slbrk)
231 {
232   char *d, *s;
233
234   if (r_slbrk)
235     *r_slbrk = 0;
236
237   /* Fixme:  We should remove trailing white space first.  */
238   for (s=d=buffer; length; length--)
239     if (*s == '=')
240       {
241         if (length > 2 && hexdigitp (s+1) && hexdigitp (s+2))
242           {
243             s++;
244             *(unsigned char*)d++ = xtoi_2 (s);
245             s += 2;
246             length -= 2;
247           }
248         else if (length > 2 && s[1] == '\r' && s[2] == '\n')
249           {
250             /* Soft line break.  */
251             s += 3;
252             length -= 2;
253             if (r_slbrk && length == 1)
254               *r_slbrk = 1;
255           }
256         else if (length > 1 && s[1] == '\n')
257           {
258             /* Soft line break with only a Unix line terminator. */
259             s += 2;
260             length -= 1;
261             if (r_slbrk && length == 1)
262               *r_slbrk = 1;
263           }
264         else if (length == 1)
265           {
266             /* Soft line break at the end of the line. */
267             s += 1;
268             if (r_slbrk)
269               *r_slbrk = 1;
270           }
271         else
272           *d++ = *s++;
273       }
274     else
275       *d++ = *s++;
276
277   return d - buffer;
278 }
279
280 /* Return the a quoted printable encoded version of the
281    input string. If outlen is not null the size of the
282    quoted printable string is returned. String will be
283    malloced and zero terminated. Aborts if the output
284    is more then three times the size of the input.
285    This is only basic and does not handle mutliline data. */
286 char *
287 qp_encode (const char *input, size_t inlen, size_t *r_outlen)
288 {
289   size_t max_len = inlen * 3 +1;
290   char *outbuf = xmalloc (max_len);
291   size_t outlen = 0;
292   const unsigned char *p;
293
294   memset (outbuf, 0, max_len);
295
296   for (p = input; inlen; p++, inlen--)
297     {
298       if (*p >= '!' && *p <= '~' && *p != '=')
299         {
300           outbuf[outlen++] = *p;
301         }
302       else if (*p == ' ')
303         {
304           /* Outlook does it this way */
305           outbuf[outlen++] = '_';
306         }
307       else
308         {
309           outbuf[outlen++] = '=';
310           outbuf[outlen++] = tohex ((*p>>4)&15);
311           outbuf[outlen++] = tohex (*p&15);
312         }
313       if (outlen == max_len -1)
314         {
315           log_error ("Quoted printable too long. Bug.");
316           r_outlen = NULL;
317           xfree (outbuf);
318           return NULL;
319         }
320     }
321   if (r_outlen)
322     *r_outlen = outlen;
323   return outbuf;
324 }
325
326
327 /* Initialize the Base 64 decoder state.  */
328 void b64_init (b64_state_t *state)
329 {
330   state->idx = 0;
331   state->val = 0;
332   state->stop_seen = 0;
333   state->invalid_encoding = 0;
334 }
335
336
337 /* Do in-place decoding of base-64 data of LENGTH in BUFFER.  Returns
338    the new length of the buffer. STATE is required to return errors and
339    to maintain the state of the decoder.  */
340 size_t
341 b64_decode (b64_state_t *state, char *buffer, size_t length)
342 {
343   int idx = state->idx;
344   unsigned char val = state->val;
345   int c;
346   char *d, *s;
347
348   if (state->stop_seen)
349     return 0;
350
351   for (s=d=buffer; length; length--, s++)
352     {
353       if (*s == '\n' || *s == ' ' || *s == '\r' || *s == '\t')
354         continue;
355       if (*s == '=')
356         {
357           /* Pad character: stop */
358           if (idx == 1)
359             *d++ = val;
360           state->stop_seen = 1;
361           break;
362         }
363
364       if ((c = asctobin[*(unsigned char *)s]) == 255)
365         {
366           if (!state->invalid_encoding)
367             log_debug ("%s: invalid base64 character %02X at pos %d skipped\n",
368                        __func__, *(unsigned char*)s, (int)(s-buffer));
369           state->invalid_encoding = 1;
370           continue;
371         }
372
373       switch (idx)
374         {
375         case 0:
376           val = c << 2;
377           break;
378         case 1:
379           val |= (c>>4)&3;
380           *d++ = val;
381           val = (c<<4)&0xf0;
382           break;
383         case 2:
384           val |= (c>>2)&15;
385           *d++ = val;
386           val = (c<<6)&0xc0;
387           break;
388         case 3:
389           val |= c&0x3f;
390           *d++ = val;
391           break;
392         }
393       idx = (idx+1) % 4;
394     }
395
396
397   state->idx = idx;
398   state->val = val;
399   return d - buffer;
400 }
401
402
403 /* Base 64 encode the input. If input is null returns NULL otherwise
404    a pointer to the malloced encoded string. */
405 char *
406 b64_encode (const char *input, size_t length)
407 {
408   size_t out_len = 4 * ((length + 2) / 3);
409   char *ret;
410   int i, j;
411
412   if (!length || !input)
413     {
414       return NULL;
415     }
416   ret = xmalloc (out_len);
417   memset (ret, 0, out_len);
418
419   for (i = 0, j = 0; i < length;)
420     {
421       unsigned int a = i < length ? (unsigned char)input[i++] : 0;
422       unsigned int b = i < length ? (unsigned char)input[i++] : 0;
423       unsigned int c = i < length ? (unsigned char)input[i++] : 0;
424
425       unsigned int triple = (a << 0x10) + (b << 0x08) + c;
426
427       ret[j++] = bintoasc[(triple >> 3 * 6) & 0x3F];
428       ret[j++] = bintoasc[(triple >> 2 * 6) & 0x3F];
429       ret[j++] = bintoasc[(triple >> 1 * 6) & 0x3F];
430       ret[j++] = bintoasc[(triple >> 0 * 6) & 0x3F];
431     }
432
433   if (length % 3)
434     {
435       ret [j - 1] = '=';
436     }
437   if (length % 3 == 1)
438     {
439       ret [j - 2] = '=';
440     }
441
442   return ret;
443 }
444
445 /* Create a boundary.  Note that mimemaker.c knows about the structure
446    of the boundary (i.e. that it starts with "=-=") so that it can
447    protect against accidently used boundaries within the content.  */
448 char *
449 generate_boundary (char *buffer)
450 {
451   char *p = buffer;
452   int i;
453
454 #if RAND_MAX < (64*2*BOUNDARYSIZE)
455 #error RAND_MAX is way too small
456 #endif
457
458   *p++ = '=';
459   *p++ = '-';
460   *p++ = '=';
461   for (i=0; i < BOUNDARYSIZE-6; i++)
462     *p++ = bintoasc[rand () % 64];
463   *p++ = '=';
464   *p++ = '-';
465   *p++ = '=';
466   *p = 0;
467
468   return buffer;
469 }
470
471 /* The malloced name of the logfile and the logging stream.  If
472    LOGFILE is NULL, no logging is done. */
473 static char *logfile;
474 static FILE *logfp;
475
476 #ifdef HAVE_W32_SYSTEM
477
478 /* Acquire the mutex for logging.  Returns 0 on success. */
479 static int
480 lock_log (void)
481 {
482   int code = WaitForSingleObject (log_mutex, INFINITE);
483   return code != WAIT_OBJECT_0;
484 }
485
486 /* Release the mutex for logging. No error return is done because this
487    is a fatal error anyway and we have no means for proper
488    notification. */
489 static void
490 unlock_log (void)
491 {
492   ReleaseMutex (log_mutex);
493 }
494 #endif
495
496 const char *
497 get_log_file (void)
498 {
499   return logfile? logfile : "";
500 }
501
502 void
503 set_log_file (const char *name)
504 {
505 #ifdef HAVE_W32_SYSTEM
506   if (!lock_log ())
507     {
508 #endif
509       if (logfp)
510         {
511           fclose (logfp);
512           logfp = NULL;
513         }
514       xfree (logfile);
515       if (!name || *name == '\"' || !*name)
516         logfile = NULL;
517       else
518         logfile = xstrdup (name);
519 #ifdef HAVE_W32_SYSTEM
520       unlock_log ();
521     }
522 #endif
523 }
524
525 static void
526 do_log (const char *fmt, va_list a, int w32err, int err,
527         const void *buf, size_t buflen)
528 {
529   if (!logfile)
530     return;
531
532 #ifdef HAVE_W32_SYSTEM
533   if (!opt.enable_debug)
534     return;
535
536   if (lock_log ())
537     return;
538 #endif
539
540   if (!strcmp (logfile, "stdout"))
541     {
542       logfp = stdout;
543     }
544   else if (!strcmp (logfile, "stderr"))
545     {
546       logfp = stderr;
547     }
548   if (!logfp)
549     logfp = fopen (logfile, "a+");
550 #ifdef HAVE_W32_SYSTEM
551   if (!logfp)
552     {
553       unlock_log ();
554       return;
555     }
556
557   char time_str[9];
558   SYSTEMTIME utc_time;
559   GetSystemTime (&utc_time);
560   if (GetTimeFormatA (LOCALE_INVARIANT,
561                       TIME_FORCE24HOURFORMAT | LOCALE_USE_CP_ACP,
562                       &utc_time,
563                       "HH:mm:ss",
564                       time_str,
565                       9))
566     {
567       fprintf (logfp, "%s/%lu/",
568                time_str,
569                (unsigned long)GetCurrentThreadId ());
570     }
571   else
572     {
573       fprintf (logfp, "unknown/%lu/",
574                (unsigned long)GetCurrentThreadId ());
575     }
576 #endif
577
578   if (err == 1)
579     fputs ("ERROR/", logfp);
580   vfprintf (logfp, fmt, a);
581 #ifdef HAVE_W32_SYSTEM
582   if (w32err)
583     {
584       char tmpbuf[256];
585
586       FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, NULL, w32err,
587                      MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
588                      tmpbuf, sizeof (tmpbuf)-1, NULL);
589       fputs (": ", logfp);
590       if (*tmpbuf && tmpbuf[strlen (tmpbuf)-1] == '\n')
591         tmpbuf[strlen (tmpbuf)-1] = 0;
592       if (*tmpbuf && tmpbuf[strlen (tmpbuf)-1] == '\r')
593         tmpbuf[strlen (tmpbuf)-1] = 0;
594       fprintf (logfp, "%s (%d)", tmpbuf, w32err);
595     }
596 #endif
597   if (buf)
598     {
599       const unsigned char *p = (const unsigned char*)buf;
600
601       for ( ; buflen; buflen--, p++)
602         fprintf (logfp, "%02X", *p);
603       putc ('\n', logfp);
604     }
605   else if ( *fmt && fmt[strlen (fmt) - 1] != '\n')
606     putc ('\n', logfp);
607
608   fflush (logfp);
609 #ifdef HAVE_W32_SYSTEM
610   unlock_log ();
611 #endif
612 }
613
614 const char *
615 log_srcname (const char *file)
616 {
617   const char *s = strrchr (file, '/');
618   return s? s+1:file;
619 }
620
621 void
622 log_debug (const char *fmt, ...)
623 {
624   va_list a;
625
626   va_start (a, fmt);
627   do_log (fmt, a, 0, 0, NULL, 0);
628   va_end (a);
629 }
630
631 void
632 log_error (const char *fmt, ...)
633 {
634   va_list a;
635
636   va_start (a, fmt);
637   do_log (fmt, a, 0, 1, NULL, 0);
638   va_end (a);
639 }
640
641 void
642 log_vdebug (const char *fmt, va_list a)
643 {
644   do_log (fmt, a, 0, 0, NULL, 0);
645 }
646
647 void
648 log_hexdump (const void *buf, size_t buflen, const char *fmt, ...)
649 {
650   va_list a;
651
652   va_start (a, fmt);
653   do_log (fmt, a, 0, 2, buf, buflen);
654   va_end (a);
655 }
656
657 #ifdef HAVE_W32_SYSTEM
658 void
659 log_debug_w32 (int w32err, const char *fmt, ...)
660 {
661   va_list a;
662
663   if (w32err == -1)
664     w32err = GetLastError ();
665
666   va_start (a, fmt);
667   do_log (fmt, a, w32err, 0, NULL, 0);
668   va_end (a);
669 }
670
671 void
672 log_error_w32 (int w32err, const char *fmt, ...)
673 {
674   va_list a;
675
676   if (w32err == -1)
677     w32err = GetLastError ();
678
679   va_start (a, fmt);
680   do_log (fmt, a, w32err, 1, NULL, 0);
681   va_end (a);
682 }
683
684 static void
685 do_log_window_info (HWND window, int level)
686 {
687   char buf[1024+1];
688   char name[200];
689   int nname;
690   char *pname;
691   DWORD pid;
692
693   if (!window)
694     return;
695
696   GetWindowThreadProcessId (window, &pid);
697   if (pid != GetCurrentProcessId ())
698     return;
699
700   memset (buf, 0, sizeof (buf));
701   GetWindowText (window, buf, sizeof (buf)-1);
702   nname = GetClassName (window, name, sizeof (name)-1);
703   if (nname)
704     pname = name;
705   else
706     pname = NULL;
707
708   if (level == -1)
709     log_debug ("  parent=%p/%lu (%s) `%s'", window, (unsigned long)pid,
710                pname? pname:"", buf);
711   else
712     log_debug ("    %*shwnd=%p/%lu (%s) `%s'", level*2, "", window,
713                (unsigned long)pid, pname? pname:"", buf);
714 }
715
716
717 /* Helper to log_window_hierarchy.  */
718 static HWND
719 do_log_window_hierarchy (HWND parent, int level)
720 {
721   HWND child;
722
723   child = GetWindow (parent, GW_CHILD);
724   while (child)
725     {
726       do_log_window_info (child, level);
727       do_log_window_hierarchy (child, level+1);
728       child = GetNextWindow (child, GW_HWNDNEXT);
729     }
730
731   return NULL;
732 }
733
734
735 /* Print a debug message using the format string FMT followed by the
736    window hierarchy of WINDOW.  */
737 void
738 log_window_hierarchy (HWND window, const char *fmt, ...)
739 {
740   va_list a;
741
742   va_start (a, fmt);
743   do_log (fmt, a, 0, 0, NULL, 0);
744   va_end (a);
745   if (window)
746     {
747       do_log_window_info (window, -1);
748       do_log_window_hierarchy (window, 0);
749     }
750 }
751
752 #endif