aheinecke@404: /* Copyright (C) 2014 by Bundesamt für Sicherheit in der Informationstechnik
aheinecke@404:  * Software engineering by Intevation GmbH
aheinecke@404:  *
aheinecke@404:  * This file is Free Software under the GNU GPL (v>=2)
aheinecke@404:  * and comes with ABSOLUTELY NO WARRANTY!
aheinecke@404:  * See LICENSE.txt for details.
aheinecke@404:  */
aheinecke@252: #include "logging.h"
aheinecke@252: #include "strhelp.h"
aheinecke@252: 
aheinecke@252: #include <stdio.h>
andre@615: #include <stdarg.h>
andre@615: #include <stdbool.h>
andre@615: 
andre@615: #include <strhelp.h>
aheinecke@252: 
andre@623: #include <certhelp.h>
andre@623: 
andre@623: #include <polarssl/sha256.h>
andre@623: 
aheinecke@252: #ifdef WIN32
andre@615: # include <windows.h>
andre@620: # include "events.h"
andre@615: #else
andre@615: # include <syslog.h>
andre@615: #endif
andre@615: 
andre@615: #ifdef WIN32
andre@623: 
andre@623: /** @brief helper to prepare common logging information */
andre@615: static void
andre@623: win_do_log(WORD type, WORD category, DWORD eventID, WORD numStrings, LPCWSTR *strings)
andre@615: {
andre@616:   HANDLE log_src = NULL,
andre@616:          process_token = NULL;
andre@616:   PTOKEN_USER user_struct = NULL;
andre@616:   PSID user_sid = NULL;
andre@623:   BOOL success = FALSE;
andre@615: 
andre@620:   log_src = RegisterEventSourceW (NULL, L"" LOG_NAME);
andre@615: 
andre@615:   if (log_src == NULL)
andre@615:     {
andre@615:       PRINTLASTERROR ("Failed to open log source.");
andre@615:       return;
andre@615:     }
andre@615: 
andre@616:   /* Get the current user sid for logging */
andre@616:   OpenProcessToken (GetCurrentProcess(), TOKEN_READ, &process_token);
andre@616:   if (process_token)
andre@616:     {
andre@616:       DWORD size = 0;
andre@616: 
andre@616:       // check how much space is needed
andre@616:       GetTokenInformation (process_token, TokenUser, NULL, 0, &size);
andre@616:       if (ERROR_INSUFFICIENT_BUFFER == GetLastError())
andre@616:         {
andre@616:           user_struct = xmalloc (size);
andre@616:           GetTokenInformation (process_token, TokenUser, user_struct, size, &size);
andre@616:           user_sid = user_struct->User.Sid;
andre@616:         }
andre@616:     }
andre@616: 
andre@620:   success = ReportEventW (log_src,
andre@623:                           type,
andre@623:                           category,
andre@623:                           eventID,
andre@616:                           user_sid,
andre@623:                           numStrings,
andre@615:                           0,
andre@623:                           strings,
andre@615:                           NULL);
andre@620:   if (!success)
andre@615:     {
andre@615:       PRINTLASTERROR ("Failed to report event.");
andre@615:     }
andre@615: 
andre@616:   if (process_token)
andre@616:     {
andre@616:       CloseHandle(process_token);
andre@616:     }
andre@616:   xfree (user_struct);
andre@615: 
andre@615:   if (!DeregisterEventSource (log_src))
andre@615:     {
andre@615:       PRINTLASTERROR ("Failed to close log source.");
andre@615:     }
andre@623: }
andre@623: 
andre@623: static void
andre@623: win_log(const char *format, va_list ap, bool error)
andre@623: {
andre@623:   wchar_t *wmsg = NULL;
andre@623:   char buffer[MAX_LOG+1];
andre@623:   vsnprintf (buffer, MAX_LOG, format, ap);
andre@623: 
andre@623:   buffer[MAX_LOG] = '\0';
andre@623: 
andre@623:   wmsg = utf8_to_wchar (buffer, strlen(buffer));
andre@623:   if (wmsg == NULL)
andre@623:     {
andre@623:       ERRORPRINTF ("Failed to convert log message to utf-16");
andre@623:       return;
andre@623:     }
andre@623: 
andre@623:   win_do_log (error ? EVENTLOG_ERROR_TYPE : EVENTLOG_INFORMATION_TYPE,
andre@623:               EVENT_CAT_TB,
andre@623:               error ? MSG_DEFAULT_ERROR : MSG_DEFAULT_INFO,
andre@623:               1,
andre@623:               (const WCHAR **) &wmsg);
andre@623: 
andre@623: 
andre@623:   xfree (wmsg);
andre@623: 
andre@615:   return;
andre@615: }
andre@615: 
aheinecke@252: char *
aheinecke@252: getLastErrorMsg()
aheinecke@252: {
aheinecke@252:   LPWSTR bufPtr = NULL;
aheinecke@252:   DWORD err = GetLastError();
aheinecke@252:   char *retval = NULL;
aheinecke@252:   FormatMessageW (FORMAT_MESSAGE_ALLOCATE_BUFFER |
aheinecke@252:                   FORMAT_MESSAGE_FROM_SYSTEM |
aheinecke@252:                   FORMAT_MESSAGE_IGNORE_INSERTS,
aheinecke@252:                   NULL, err, 0, (LPWSTR) &bufPtr, 0, NULL);
aheinecke@252:   if (!bufPtr)
aheinecke@252:     {
aheinecke@252:       HMODULE hWinhttp = GetModuleHandleW (L"crypt32");
aheinecke@252:       if (hWinhttp)
aheinecke@252:         {
aheinecke@252:           FormatMessageW (FORMAT_MESSAGE_ALLOCATE_BUFFER |
aheinecke@252:                           FORMAT_MESSAGE_FROM_HMODULE |
aheinecke@252:                           FORMAT_MESSAGE_IGNORE_INSERTS,
aheinecke@252:                           hWinhttp, HRESULT_CODE (err), 0,
aheinecke@252:                           (LPWSTR) &bufPtr, 0, NULL);
aheinecke@252:         }
aheinecke@252:     }
andre@905:   if (!bufPtr)
andre@905:     {
andre@905:       fprintf (stderr, "Error getting last error for code: %lx \n", err);
andre@905:       return NULL;
andre@905:     }
aheinecke@252: 
aheinecke@252:   retval = wchar_to_utf8(bufPtr, wcslen(bufPtr));
aheinecke@252:   LocalFree (bufPtr);
aheinecke@252: 
aheinecke@252:   return retval;
aheinecke@252: }
aheinecke@252: 
andre@615: #else /* WIN32 */
andre@615: 
andre@615: static void
andre@615: linux_log (const char *format, va_list ap, bool error)
andre@615: {
andre@615:   openlog (LOG_NAME, LOG_CONS | LOG_PID | LOG_NDELAY, LOG_USER);
andre@615:   vsyslog ( error ? LOG_ERR : LOG_INFO, format, ap);
andre@615: }
andre@615: 
andre@615: #endif /* WIN32 */
andre@615: 
andre@615: void
andre@623: log_certificate(const char* store, char *b64cert, bool install)
andre@623: {
andre@625:   char *der_data = NULL;
andre@623:   size_t der_size = 0;
andre@625:   int ret = 0;
andre@623: 
andre@623:   ret = str_base64_decode (&der_data, &der_size, b64cert, strlen(b64cert));
andre@623: 
andre@623:   if (ret != 0)
andre@623:     {
andre@623:       ERRORPRINTF ("Error decoding certificate.\n");
andre@623:       return;
andre@623:     }
andre@623: 
andre@625:   log_certificate_der (store, (unsigned char *) der_data, der_size, install);
andre@625: 
andre@625:   xfree (der_data);
andre@625: }
andre@625: 
andre@625: void
andre@625: log_certificate_der(const char *store, unsigned char *der_data, size_t der_size, bool install)
andre@625: {
andre@625:   char subject[MAX_LOG + 1];
andre@625:   int ret = 0,
andre@625:       i = 0;
andre@625:   x509_crt chain;
andre@625:   unsigned char sha256sum[32];
andre@625:   char fingerprint[32 * 3 + 1];
andre@625: 
andre@623:   x509_crt_init(&chain);
andre@623:   if (x509_crt_parse_der(&chain, (const unsigned char *)der_data,
andre@623:                          der_size) != 0)
andre@623:     {
andre@623:       ERRORPRINTF("Failed to parse cert..");
andre@623:       return;
andre@623:     }
andre@623: 
andre@623:   ret = x509_dn_gets(subject, MAX_LOG, &(chain.subject));
andre@623: 
andre@623:   if (ret == -1)
andre@623:     {
andre@623:       ERRORPRINTF("Failed to parse subject..");
andre@623:       return;
andre@623:     }
andre@623:   subject[MAX_LOG] = '\0';
andre@623: 
andre@623:   sha256 (chain.raw.p, chain.raw.len, sha256sum, 0);
andre@623: 
andre@623:   for (i = 0; i < 31; i++)
andre@623:     {
andre@625:       snprintf (fingerprint + (i * 3), 4, "%02X:", sha256sum[i]);
andre@623:     }
andre@625:   snprintf (fingerprint + (31 * 3), 3, "%02X", sha256sum[31]);
andre@623: 
andre@623:   fingerprint[32*3] = '\0';
andre@623: 
andre@623: #ifdef WIN32
andre@905:   {
andre@905:     wchar_t *wstrings[3];
andre@623: 
andre@905:     wstrings[0] = utf8_to_wchar (subject, strnlen (subject, MAX_LOG));
andre@905:     wstrings[1] = utf8_to_wchar (fingerprint, strnlen (fingerprint, MAX_LOG));
andre@905:     wstrings[2] = utf8_to_wchar (store, strnlen (store, MAX_LOG));
andre@905: 
andre@905:     win_do_log (EVENTLOG_INFORMATION_TYPE,
andre@905:                 EVENT_CAT_CINST,
andre@905:                 install ? MSG_CERT_INSTALL : MSG_CERT_REMOVE,
andre@905:                 3,
andre@905:                 (const WCHAR**) wstrings);
andre@905:     xfree (wstrings[0]);
andre@905:     xfree (wstrings[1]);
andre@905:     xfree (wstrings[2]);
andre@905:   }
andre@623: #else
andre@623:   /* Please keep the following line in line with message from events.mc */
andre@625:   syslog_info_printf ("%s of root certificate: %s Sha256 thumbprint:<%s>. Certificate store \"%s\"",
andre@625:                       install ? "Installation" : "Removal",
andre@625:                       subject, fingerprint, store);
andre@623: #endif
andre@623:   x509_crt_free (&chain);
andre@623: }
andre@623: 
andre@623: void
andre@615: syslog_info_printf(const char *format, ...)
andre@615: {
andre@615:   va_list args;
andre@615:   va_start (args, format);
andre@615: #ifdef WIN32
andre@615:   win_log (format, args, false);
andre@615: #else
andre@615:   linux_log (format, args, false);
aheinecke@252: #endif
andre@615:   va_end (args);
andre@615: }
andre@615: 
andre@615: void
andre@615: syslog_error_printf(const char *format, ...)
andre@615: {
andre@615:   va_list args;
andre@615:   va_start (args, format);
andre@615: #ifdef WIN32
andre@615:   win_log (format, args, true);
andre@615: #else
andre@615:   linux_log (format, args, true);
andre@615: #endif
andre@615:   va_end (args);
andre@615: }