Esempio n. 1
0
/* Create pipe where one end is inheritable: With an INHERIT_IDX of 0
   the read end is inheritable, with 1 the write end is inheritable.
   Note that the inheritable ends are rendezvous ids and no file
   descriptors or handles. */
static gpg_error_t
create_inheritable_pipe (int filedes[2], int inherit_idx)
{
  HANDLE hd;
  int rvid;

  filedes[0] = filedes[1] = -1;
  hd = _assuan_w32ce_prepare_pipe (&rvid, !inherit_idx);
  if (hd == INVALID_HANDLE_VALUE)
    {
      log_error ("_assuan_w32ce_prepare_pipe failed: %s\n", w32_strerror (-1));
      gpg_err_set_errno (EIO);
      return gpg_error_from_syserror ();
    }

  if (inherit_idx)
    {
      filedes[0] = handle_to_fd (hd);
      filedes[1] = rvid;
    }
  else
    {
      filedes[0] = rvid;
      filedes[1] = handle_to_fd (hd);
    }
  return 0;
}
Esempio n. 2
0
/* Locking core for Windows.  This version does not need a temporary
   file but uses the plain lock file along with record locking.  We
   create this file here so that we later only need to do the file
   locking.  For error reporting it is useful to keep the name of the
   file in the handle.  */
static dotlock_t
dotlock_create_w32 (dotlock_t h, const char *file_to_lock)
{
  LOCK_all_lockfiles ();
  h->next = all_lockfiles;
  all_lockfiles = h;

  h->lockname = jnlib_malloc ( strlen (file_to_lock) + 6 );
  if (!h->lockname)
    {
      all_lockfiles = h->next;
      UNLOCK_all_lockfiles ();
      jnlib_free (h);
      return NULL;
    }
  strcpy (stpcpy(h->lockname, file_to_lock), EXTSEP_S "lock");

  /* If would be nice if we would use the FILE_FLAG_DELETE_ON_CLOSE
     along with FILE_SHARE_DELETE but that does not work due to a race
     condition: Despite the OPEN_ALWAYS flag CreateFile may return an
     error and we can't reliable create/open the lock file unless we
     would wait here until it works - however there are other valid
     reasons why a lock file can't be created and thus the process
     would not stop as expected but spin until Windows crashes.  Our
     solution is to keep the lock file open; that does not harm. */
  {
#ifdef HAVE_W32CE_SYSTEM
    wchar_t *wname = utf8_to_wchar (h->lockname);

    if (wname)
      h->lockhd = CreateFile (wname,
                              GENERIC_READ|GENERIC_WRITE,
                              FILE_SHARE_READ|FILE_SHARE_WRITE,
                              NULL, OPEN_ALWAYS, 0, NULL);
    else
      h->lockhd = INVALID_HANDLE_VALUE;
    jnlib_free (wname);
#else
    h->lockhd = CreateFile (h->lockname,
                            GENERIC_READ|GENERIC_WRITE,
                            FILE_SHARE_READ|FILE_SHARE_WRITE,
                            NULL, OPEN_ALWAYS, 0, NULL);
#endif
  }
  if (h->lockhd == INVALID_HANDLE_VALUE)
    {
      all_lockfiles = h->next;
      UNLOCK_all_lockfiles ();
      my_error_2 (_("can't create `%s': %s\n"), h->lockname, w32_strerror (-1));
      jnlib_free (h->lockname);
      jnlib_free (h);
      return NULL;
    }
  return h;
}
Esempio n. 3
0
static void *
handle_taskbar (void *ctx)
{
    WNDCLASS wndwclass = {0, wndw_proc, 0, 0, glob_hinst,
                          0, 0, 0, 0, "gpg-agent"
                         };
    NOTIFYICONDATA nid;
    HWND hwnd;
    MSG msg;
    int rc;

    if (!RegisterClass (&wndwclass))
    {
        log_error ("error registering window class\n");
        ExitThread (0);
    }
    hwnd = CreateWindow ("gpg-agent", "gpg-agent",
                         0, 0, 0, 0, 0,
                         NULL, NULL, glob_hinst, NULL);
    if (!hwnd)
    {
        log_error ("error creating main window\n");
        ExitThread (0);
    }
    glob_hwnd = hwnd;
    UpdateWindow (hwnd);

    memset (&nid, 0, sizeof nid);
    nid.cbSize = sizeof (nid);
    nid.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP;
    nid.uCallbackMessage = WM_USER;
    nid.hWnd = glob_hwnd;
    nid.uID = 1;
    nid.hIcon = LoadIcon (glob_hinst, MAKEINTRESOURCE (1));
    mem2str (nid.szTip, "GnuPG Agent version "PACKAGE_VERSION,
             sizeof nid.szTip);
    Shell_NotifyIcon (NIM_ADD, &nid);
    DestroyIcon (nid.hIcon);

    fprintf (stderr, "%s: enter\n", __func__);
    while ( (rc=GetMessage (&msg, hwnd,  0, 0)) )
    {
        if (rc == -1)
        {
            log_error ("getMessage failed: %s\n", w32_strerror (-1));
            break;
        }
        TranslateMessage (&msg);
        DispatchMessage (&msg);
    }
    fprintf (stderr,"%s: leave\n", __func__);
    ExitThread (0);
    return NULL;
}
Esempio n. 4
0
/* Windows specific code of make_dotlock.  Returns 0 on success and -1 on
   error.  */
static int
dotlock_take_w32 (dotlock_t h, long timeout)
{
  int wtime = 0;
  int w32err;
  OVERLAPPED ovl;

 again:
  /* Lock one byte at offset 0.  The offset is given by OVL.  */
  memset (&ovl, 0, sizeof ovl);
  if (LockFileEx (h->lockhd, (LOCKFILE_EXCLUSIVE_LOCK
                              | LOCKFILE_FAIL_IMMEDIATELY), 0, 1, 0, &ovl))
    {
      h->locked = 1;
      return 0; /* okay */
    }

  w32err = GetLastError ();
  if (w32err != ERROR_LOCK_VIOLATION)
    {
      my_error_2 (_("lock `%s' not made: %s\n"),
                  h->lockname, w32_strerror (w32err));
      return -1;
    }

  if (timeout)
    {
      /* Wait until lock has been released.  We use retry intervals of
         50ms, 100ms, 200ms, 400ms, 800ms, 2s, 4s and 8s.  */
      if (!wtime)
        wtime = 50;
      else if (wtime < 800)
        wtime *= 2;
      else if (wtime == 800)
        wtime = 2000;
      else if (wtime < 8000)
        wtime *= 2;

      if (timeout > 0)
        {
          if (wtime > timeout)
            wtime = timeout;
          timeout -= wtime;
        }

      if (wtime >= 800)
        my_info_1 (_("waiting for lock %s...\n"), h->lockname);

      Sleep (wtime);
      goto again;
    }

  return -1;
}
Esempio n. 5
0
/* Hack required for Windows.  */
void
gnupg_allow_set_foregound_window (pid_t pid)
{
  if (!pid)
    log_info ("%s called with invalid pid %lu\n",
              "gnupg_allow_set_foregound_window", (unsigned long)pid);
#ifdef HAVE_W32_SYSTEM
  else if (!AllowSetForegroundWindow ((pid_t)pid == (pid_t)(-1)?ASFW_ANY:pid))
    log_info ("AllowSetForegroundWindow(%lu) failed: %s\n",
               (unsigned long)pid, w32_strerror (-1));
#endif
}
Esempio n. 6
0
static HANDLE
w32_open_null (int for_write)
{
  HANDLE hfile;

  hfile = CreateFileW (L"nul",
                       for_write? GENERIC_WRITE : GENERIC_READ,
                       FILE_SHARE_READ | FILE_SHARE_WRITE,
                       NULL, OPEN_EXISTING, 0, NULL);
  if (hfile == INVALID_HANDLE_VALUE)
    log_debug ("can't open `nul': %s\n", w32_strerror (-1));
  return hfile;
}
Esempio n. 7
0
static const char *
w32_rootdir (void)
{
  static int got_dir;
  static char dir[MAX_PATH+5];

  if (!got_dir)
    {
      char *p;
      int rc;

#ifdef HAVE_W32CE_SYSTEM
      {
        wchar_t wdir [MAX_PATH+5];
        rc = GetModuleFileName (NULL, wdir, MAX_PATH);
        if (rc && WideCharToMultiByte (CP_UTF8, 0, wdir, -1, dir, MAX_PATH-4,
                                       NULL, NULL) < 0)
          rc = 0;
      }
#else
      rc = GetModuleFileName (NULL, dir, MAX_PATH);
#endif
      if (!rc)
        {
          log_debug ("GetModuleFileName failed: %s\n", w32_strerror (0));
          *dir = 0;
        }
      got_dir = 1;
      p = strrchr (dir, DIRSEP_C);
      if (p)
        {
          *p = 0;
          /* If we are installed below "bin" we strip that and use
             the top directory instead.  */
          p = strrchr (dir, DIRSEP_C);
          if (p && !strcmp (p+1, "bin"))
            *p = 0;
        }
      if (!p)
        {
          log_debug ("bad filename '%s' returned for this process\n", dir);
          *dir = 0;
        }
    }

  if (*dir)
    return dir;
  /* Fallback to the hardwired value. */
  return GNUPG_LIBEXECDIR;
}
Esempio n. 8
0
static void
move_mouse_and_click (HWND hwnd)
{
#ifndef HAVE_W32CE_SYSTEM
    RECT rect;
    HDC hdc;
    int wscreen, hscreen, x, y, normx, normy;
    INPUT inp[3];
    int idx;

    hdc = GetDC (hwnd);
    wscreen = GetDeviceCaps (hdc, HORZRES);
    hscreen = GetDeviceCaps (hdc, VERTRES);
    ReleaseDC (hwnd, hdc);
    if (wscreen < 10 || hscreen < 10)
        return;

    GetWindowRect (hwnd, &rect);
    x = rect.left;
    y = rect.bottom;

    normx = x * (65535 / wscreen);
    if (normx < 0 || normx > 65535)
        return;
    normy = y * (65535 / hscreen);
    if (normy < 0 || normy > 65535)
        return;

    for (idx=0; idx < 3; idx++)
        memset (&inp[idx], 0, sizeof inp[idx]);

    idx=0;
    inp[idx].type = INPUT_MOUSE;
    inp[idx].mi.dx = normx;
    inp[idx].mi.dy = normy;
    inp[idx].mi.dwFlags = MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE;
    idx++;

    inp[idx].type = INPUT_MOUSE;
    inp[idx].mi.dwFlags = MOUSEEVENTF_LEFTDOWN;
    idx++;

    inp[idx].type = INPUT_MOUSE;
    inp[idx].mi.dwFlags = MOUSEEVENTF_LEFTUP;
    idx++;

    if ( (SendInput (idx, inp, sizeof (INPUT)) != idx) && debugfp)
        fprintf (debugfp, "SendInput failed: %s\n", w32_strerror (-1));
#endif
}
Esempio n. 9
0
/* Windows specific code of release_dotlock.  */
static int
dotlock_release_w32 (dotlock_t h)
{
  OVERLAPPED ovl;

  memset (&ovl, 0, sizeof ovl);
  if (!UnlockFileEx (h->lockhd, 0, 1, 0, &ovl))
    {
      my_error_2 ("release_dotlock: error removing lockfile `%s': %s\n",
                  h->lockname, w32_strerror (-1));
      return -1;
    }

  return 0;
}
Esempio n. 10
0
/* Unlock the spawning process.  */
static void
unlock_spawning (lock_spawn_t *lock, const char *name)
{
  if (*lock)
    {
#ifdef HAVE_W32_SYSTEM
      if (!ReleaseMutex (*lock))
        log_error ("failed to release the spawn_%s mutex: %s\n",
                   name, w32_strerror (-1));
      CloseHandle (*lock);
#else /*!HAVE_W32_SYSTEM*/
      (void)name;
      dotlock_destroy (*lock);
#endif /*!HAVE_W32_SYSTEM*/
      *lock = NULL;
    }
}
Esempio n. 11
0
static const char *
w32_rootdir (void)
{
  static int got_dir;
  static char dir[MAX_PATH+5];

  if (!got_dir)
    {
      char *p;

      if ( !GetModuleFileName ( NULL, dir, MAX_PATH) )
        {
          log_debug ("GetModuleFileName failed: %s\n", w32_strerror (0));
          *dir = 0;
        }
      got_dir = 1;
      p = strrchr (dir, DIRSEP_C);
      if (p)
        {
          *p = 0;

          check_portable_app (dir);

          /* If we are installed below "bin" we strip that and use
             the top directory instead.  */
          p = strrchr (dir, DIRSEP_C);

          if (p && !strcmp (p+1, "bin"))
            {
              *p = 0;
              w32_bin_is_bin = 1;
            }
        }
      if (!p)
        {
          log_debug ("bad filename `%s' returned for this process\n", dir);
          *dir = 0;
        }
    }

  if (*dir)
    return dir;
  /* Fallback to the hardwired value. */
  return GNUPG_LIBEXECDIR;
}
Esempio n. 12
0
/* Simplified version of gnupg_spawn_process.  This function forks and
   then execs PGMNAME, while connecting INFD to stdin, OUTFD to stdout
   and ERRFD to stderr (any of them may be -1 to connect them to
   /dev/null).  The arguments for the process are expected in the NULL
   terminated array ARGV.  The program name itself should not be
   included there.  Calling gnupg_wait_process is required.

   Returns 0 on success or an error code. */
gpg_error_t
gnupg_spawn_process_fd (const char *pgmname, const char *argv[],
                        int infd, int outfd, int errfd, pid_t *pid)
{
  gpg_error_t err;
  PROCESS_INFORMATION pi = {NULL};
  char *cmdline;

  /* Setup return values.  */
  *pid = (pid_t)(-1);

  if (infd != -1 || outfd != -1 || errfd != -1)
    return gpg_error (GPG_ERR_NOT_SUPPORTED);

  /* Build the command line.  */
  err = build_w32_commandline (argv, 0, 0, 0, &cmdline);
  if (err)
    return err;

  log_debug ("CreateProcess, path='%s' cmdline='%s'\n", pgmname, cmdline);
  if (!create_process (pgmname, cmdline, &pi))
    {
      log_error ("CreateProcess(fd) failed: %s\n", w32_strerror (-1));
      xfree (cmdline);
      return gpg_error (GPG_ERR_GENERAL);
    }
  xfree (cmdline);
  cmdline = NULL;

  log_debug ("CreateProcess(fd) ready: hProcess=%p hThread=%p"
             " dwProcessID=%d dwThreadId=%d\n",
             pi.hProcess, pi.hThread,
             (int) pi.dwProcessId, (int) pi.dwThreadId);

  /* Process has been created suspended; resume it now. */
  ResumeThread (pi.hThread);
  CloseHandle (pi.hThread);

  *pid = handle_to_pid (pi.hProcess);
  return 0;
}
Esempio n. 13
0
/* Create pipe where one end is inheritable: With an INHERIT_IDX of 0
   the read end is inheritable, with 1 the write end is inheritable.  */
static int
create_inheritable_pipe (HANDLE filedes[2], int inherit_idx)
{
  HANDLE r, w, h;
  SECURITY_ATTRIBUTES sec_attr;

  memset (&sec_attr, 0, sizeof sec_attr );
  sec_attr.nLength = sizeof sec_attr;
  sec_attr.bInheritHandle = FALSE;

  if (!CreatePipe (&r, &w, &sec_attr, 0))
    return -1;

  if (!DuplicateHandle (GetCurrentProcess(), inherit_idx? w : r,
                        GetCurrentProcess(), &h, 0,
                        TRUE, DUPLICATE_SAME_ACCESS ))
    {
      log_error ("DuplicateHandle failed: %s\n", w32_strerror (-1));
      CloseHandle (r);
      CloseHandle (w);
      return -1;
    }

  if (inherit_idx)
    {
      CloseHandle (w);
      w = h;
    }
  else
    {
      CloseHandle (r);
      r = h;
    }

  filedes[0] = r;
  filedes[1] = w;
  return 0;
}
Esempio n. 14
0
/* Determine the root directory of the gnupg installation on Windows.  */
static const char *
get_sourcedir (void)
{
#if _WIN32
  static int got_dir;
  static char dir[MAX_PATH+5];

  if (!got_dir)
    {
      char *p;
      int rc;

      rc = GetModuleFileName (NULL, dir, MAX_PATH);
      if (!rc)
        die ("GetModuleFileName failed: %s\n", w32_strerror (-1));
      got_dir = 1;
      p = strrchr (dir, '\\');
      if (p)
        {
          *p = 0;

          /* If we are installed below "bin" we strip that and use
             the top directory instead.  */
          p = strrchr (dir, '\\');
          if (p && !strcmp (p+1, "bin"))
            *p = 0;
        }
      if (!p)
        die ("bad filename '%s' returned for this process\n", dir);
      fix_backslashes (dir);
    }

  if (*dir)
    return dir;
#endif /*_WIN32*/
  /* Fallback to the current directory. */
  return ".";
}
Esempio n. 15
0
/* Spawn a new process and immediatley detach from it.  The name of
   the program to exec is PGMNAME and its arguments are in ARGV (the
   programname is automatically passed as first argument).
   Environment strings in ENVP are set.  An error is returned if
   pgmname is not executable; to make this work it is necessary to
   provide an absolute file name.  All standard file descriptors are
   connected to /dev/null. */
gpg_error_t
gnupg_spawn_process_detached (const char *pgmname, const char *argv[],
                              const char *envp[] )
{
  gpg_error_t err;
  char *cmdline;
  PROCESS_INFORMATION pi = {NULL };

  (void)envp;

  /* Build the command line.  */
  err = build_w32_commandline (argv, 0, 0, 0, &cmdline);
  if (err)
    return err;

  /* Note: There is no detached flag under CE.  */
  log_debug ("CreateProcess, path='%s' cmdline='%s'\n", pgmname, cmdline);
  if (!create_process (pgmname, cmdline, &pi))
    {
      log_error ("CreateProcess(detached) failed: %s\n", w32_strerror (-1));
      xfree (cmdline);
      return gpg_error (GPG_ERR_GENERAL);
    }
  xfree (cmdline);
  cmdline = NULL;

  log_debug ("CreateProcess(detached) ready: hProcess=%p hThread=%p"
             " dwProcessID=%d dwThreadId=%d\n",
             pi.hProcess, pi.hThread,
             (int) pi.dwProcessId, (int) pi.dwThreadId);

  /* Process has been created suspended; resume it now. */
  ResumeThread (pi.hThread);
  CloseHandle (pi.hThread);

  return 0;
}
Esempio n. 16
0
/* Simplified version of gnupg_spawn_process.  This function forks and
   then execs PGMNAME, while connecting INFD to stdin, OUTFD to stdout
   and ERRFD to stderr (any of them may be -1 to connect them to
   /dev/null).  The arguments for the process are expected in the NULL
   terminated array ARGV.  The program name itself should not be
   included there.  Calling gnupg_wait_process is required.

   Returns 0 on success or an error code. */
gpg_error_t
gnupg_spawn_process_fd (const char *pgmname, const char *argv[],
                        int infd, int outfd, int errfd, pid_t *pid)
{
  gpg_error_t err;
  SECURITY_ATTRIBUTES sec_attr;
  PROCESS_INFORMATION pi = { NULL, 0, 0, 0 };
  STARTUPINFO si;
  char *cmdline;
  int i;
  HANDLE stdhd[3];

  /* Setup return values.  */
  *pid = (pid_t)(-1);

  /* Prepare security attributes.  */
  memset (&sec_attr, 0, sizeof sec_attr );
  sec_attr.nLength = sizeof sec_attr;
  sec_attr.bInheritHandle = FALSE;

  /* Build the command line.  */
  err = build_w32_commandline (pgmname, argv, &cmdline);
  if (err)
    return err;

  memset (&si, 0, sizeof si);
  si.cb = sizeof (si);
  si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
  si.wShowWindow = DEBUG_W32_SPAWN? SW_SHOW : SW_MINIMIZE;
  stdhd[0] = infd  == -1? w32_open_null (0) : INVALID_HANDLE_VALUE;
  stdhd[1] = outfd == -1? w32_open_null (1) : INVALID_HANDLE_VALUE;
  stdhd[2] = errfd == -1? w32_open_null (1) : INVALID_HANDLE_VALUE;
  si.hStdInput  = infd  == -1? stdhd[0] : (void*)_get_osfhandle (infd);
  si.hStdOutput = outfd == -1? stdhd[1] : (void*)_get_osfhandle (outfd);
  si.hStdError  = errfd == -1? stdhd[2] : (void*)_get_osfhandle (errfd);

/*   log_debug ("CreateProcess, path=`%s' cmdline=`%s'\n", pgmname, cmdline); */
  if (!CreateProcess (pgmname,       /* Program to start.  */
                      cmdline,       /* Command line arguments.  */
                      &sec_attr,     /* Process security attributes.  */
                      &sec_attr,     /* Thread security attributes.  */
                      TRUE,          /* Inherit handles.  */
                      (CREATE_DEFAULT_ERROR_MODE
                       | GetPriorityClass (GetCurrentProcess ())
                       | CREATE_SUSPENDED | DETACHED_PROCESS),
                      NULL,          /* Environment.  */
                      NULL,          /* Use current drive/directory.  */
                      &si,           /* Startup information. */
                      &pi            /* Returns process information.  */
                      ))
    {
      log_error ("CreateProcess failed: %s\n", w32_strerror (-1));
      err = gpg_error (GPG_ERR_GENERAL);
    }
  else
    err = 0;
  xfree (cmdline);
  for (i=0; i < 3; i++)
    if (stdhd[i] != INVALID_HANDLE_VALUE)
      CloseHandle (stdhd[i]);
  if (err)
    return err;

/*   log_debug ("CreateProcess ready: hProcess=%p hThread=%p" */
/*              " dwProcessID=%d dwThreadId=%d\n", */
/*              pi.hProcess, pi.hThread, */
/*              (int) pi.dwProcessId, (int) pi.dwThreadId); */

  /* Process has been created suspended; resume it now. */
  ResumeThread (pi.hThread);
  CloseHandle (pi.hThread);

  *pid = handle_to_pid (pi.hProcess);
  return 0;

}
Esempio n. 17
0
/* Fork and exec the PGMNAME, see exechelp.h for details.  */
gpg_error_t
gnupg_spawn_process (const char *pgmname, const char *argv[],
                     gpg_err_source_t errsource,
                     void (*preexec)(void), unsigned int flags,
                     estream_t infp,
                     estream_t *r_outfp,
                     estream_t *r_errfp,
                     pid_t *pid)
{
  gpg_error_t err;
  SECURITY_ATTRIBUTES sec_attr;
  PROCESS_INFORMATION pi =
    {
      NULL,      /* Returns process handle.  */
      0,         /* Returns primary thread handle.  */
      0,         /* Returns pid.  */
      0          /* Returns tid.  */
    };
  STARTUPINFO si;
  int cr_flags;
  char *cmdline;
  HANDLE inhandle = INVALID_HANDLE_VALUE;
  HANDLE outpipe[2] = {INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE};
  HANDLE errpipe[2] = {INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE};
  estream_t outfp = NULL;
  estream_t errfp = NULL;
  HANDLE nullhd[3] = {INVALID_HANDLE_VALUE,
                      INVALID_HANDLE_VALUE,
                      INVALID_HANDLE_VALUE};
  int i;
  es_syshd_t syshd;

  if (r_outfp)
    *r_outfp = NULL;
  if (r_errfp)
    *r_errfp = NULL;
  *pid = (pid_t)(-1); /* Always required.  */

  if (infp)
    {
      es_fflush (infp);
      es_rewind (infp);
      es_syshd (infp, &syshd);
      switch (syshd.type)
        {
        case ES_SYSHD_FD:
          inhandle = (HANDLE)_get_osfhandle (syshd.u.fd);
          break;
        case ES_SYSHD_SOCK:
          inhandle = (HANDLE)_get_osfhandle (syshd.u.sock);
          break;
        case ES_SYSHD_HANDLE:
          inhandle = syshd.u.handle;
          break;
        default:
          inhandle = INVALID_HANDLE_VALUE;
          break;
        }
      if (inhandle == INVALID_HANDLE_VALUE)
        return gpg_err_make (errsource, GPG_ERR_INV_VALUE);
      /* FIXME: In case we can't get a system handle (e.g. due to
         es_fopencookie we should create a piper and a feeder
         thread.  */
    }

  if (r_outfp)
    {
      if (create_inheritable_pipe (outpipe, 1))
        {
          err = gpg_err_make (errsource, GPG_ERR_GENERAL);
          log_error (_("error creating a pipe: %s\n"), gpg_strerror (err));
          return err;
        }

      syshd.type = ES_SYSHD_HANDLE;
      syshd.u.handle = outpipe[0];
      outfp = es_sysopen (&syshd, "r");
      if (!outfp)
        {
          err = gpg_err_make (errsource, gpg_err_code_from_syserror ());
          log_error (_("error creating a stream for a pipe: %s\n"),
                     gpg_strerror (err));
          CloseHandle (outpipe[0]);
          CloseHandle (outpipe[1]);
          outpipe[0] = outpipe[1] = INVALID_HANDLE_VALUE;
          return err;
        }
    }

  if (r_errfp)
    {
      if (create_inheritable_pipe (errpipe, 1))
        {
          err = gpg_err_make (errsource, GPG_ERR_GENERAL);
          log_error (_("error creating a pipe: %s\n"), gpg_strerror (err));
          return err;
        }

      syshd.type = ES_SYSHD_HANDLE;
      syshd.u.handle = errpipe[0];
      errfp = es_sysopen (&syshd, "r");
      if (!errfp)
        {
          err = gpg_err_make (errsource, gpg_err_code_from_syserror ());
          log_error (_("error creating a stream for a pipe: %s\n"),
                     gpg_strerror (err));
          CloseHandle (errpipe[0]);
          CloseHandle (errpipe[1]);
          errpipe[0] = errpipe[1] = INVALID_HANDLE_VALUE;
          if (outfp)
            es_fclose (outfp);
          else if (outpipe[0] != INVALID_HANDLE_VALUE)
            CloseHandle (outpipe[0]);
          if (outpipe[1] != INVALID_HANDLE_VALUE)
            CloseHandle (outpipe[1]);
          return err;
        }
    }

  /* Prepare security attributes.  */
  memset (&sec_attr, 0, sizeof sec_attr );
  sec_attr.nLength = sizeof sec_attr;
  sec_attr.bInheritHandle = FALSE;

  /* Build the command line.  */
  err = build_w32_commandline (pgmname, argv, &cmdline);
  if (err)
    return err;

  if (inhandle != INVALID_HANDLE_VALUE)
    nullhd[0] = w32_open_null (0);
  if (outpipe[1] != INVALID_HANDLE_VALUE)
    nullhd[1] = w32_open_null (0);
  if (errpipe[1] != INVALID_HANDLE_VALUE)
    nullhd[2] = w32_open_null (0);

  /* Start the process.  Note that we can't run the PREEXEC function
     because this might change our own environment. */
  (void)preexec;

  memset (&si, 0, sizeof si);
  si.cb = sizeof (si);
  si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
  si.wShowWindow = DEBUG_W32_SPAWN? SW_SHOW : SW_MINIMIZE;
  si.hStdInput  =   inhandle == INVALID_HANDLE_VALUE? nullhd[0] : inhandle;
  si.hStdOutput = outpipe[1] == INVALID_HANDLE_VALUE? nullhd[1] : outpipe[1];
  si.hStdError  = errpipe[1] == INVALID_HANDLE_VALUE? nullhd[2] : errpipe[1];

  cr_flags = (CREATE_DEFAULT_ERROR_MODE
              | ((flags & 128)? DETACHED_PROCESS : 0)
              | GetPriorityClass (GetCurrentProcess ())
              | CREATE_SUSPENDED);
/*   log_debug ("CreateProcess, path=`%s' cmdline=`%s'\n", pgmname, cmdline); */
  if (!CreateProcess (pgmname,       /* Program to start.  */
                      cmdline,       /* Command line arguments.  */
                      &sec_attr,     /* Process security attributes.  */
                      &sec_attr,     /* Thread security attributes.  */
                      TRUE,          /* Inherit handles.  */
                      cr_flags,      /* Creation flags.  */
                      NULL,          /* Environment.  */
                      NULL,          /* Use current drive/directory.  */
                      &si,           /* Startup information. */
                      &pi            /* Returns process information.  */
                      ))
    {
      log_error ("CreateProcess failed: %s\n", w32_strerror (-1));
      xfree (cmdline);
      if (outfp)
        es_fclose (outfp);
      else if (outpipe[0] != INVALID_HANDLE_VALUE)
        CloseHandle (outpipe[0]);
      if (outpipe[1] != INVALID_HANDLE_VALUE)
        CloseHandle (outpipe[1]);
      if (errfp)
        es_fclose (errfp);
      else if (errpipe[0] != INVALID_HANDLE_VALUE)
        CloseHandle (errpipe[0]);
      if (errpipe[1] != INVALID_HANDLE_VALUE)
        CloseHandle (errpipe[1]);
      return gpg_err_make (errsource, GPG_ERR_GENERAL);
    }
  xfree (cmdline);
  cmdline = NULL;

  /* Close the inherited handles to /dev/null.  */
  for (i=0; i < DIM (nullhd); i++)
    if (nullhd[i] != INVALID_HANDLE_VALUE)
      CloseHandle (nullhd[i]);

  /* Close the inherited ends of the pipes.  */
  if (outpipe[1] != INVALID_HANDLE_VALUE)
    CloseHandle (outpipe[1]);
  if (errpipe[1] != INVALID_HANDLE_VALUE)
    CloseHandle (errpipe[1]);

  /* log_debug ("CreateProcess ready: hProcess=%p hThread=%p" */
  /*            " dwProcessID=%d dwThreadId=%d\n", */
  /*            pi.hProcess, pi.hThread, */
  /*            (int) pi.dwProcessId, (int) pi.dwThreadId); */
  /* log_debug ("                     outfp=%p errfp=%p\n", outfp, errfp); */

  /* Fixme: For unknown reasons AllowSetForegroundWindow returns an
     invalid argument error if we pass it the correct processID.  As a
     workaround we use -1 (ASFW_ANY).  */
  if ( (flags & 64) )
    gnupg_allow_set_foregound_window ((pid_t)(-1)/*pi.dwProcessId*/);

  /* Process has been created suspended; resume it now. */
  ResumeThread (pi.hThread);
  CloseHandle (pi.hThread);

  if (r_outfp)
    *r_outfp = outfp;
  if (r_errfp)
    *r_errfp = errfp;

  *pid = handle_to_pid (pi.hProcess);
  return 0;

}
Esempio n. 18
0
/* Fork and exec the PGMNAME, see exechelp.h for details.  */
gpg_error_t
gnupg_spawn_process (const char *pgmname, const char *argv[],
                     gpg_err_source_t errsource,
                     void (*preexec)(void), unsigned int flags,
                     estream_t infp,
                     estream_t *r_outfp,
                     estream_t *r_errfp,
                     pid_t *pid)
{
  gpg_error_t err;
  PROCESS_INFORMATION pi = {NULL };
  char *cmdline;
  es_syshd_t syshd;
  struct {
    HANDLE hd;
    int rvid;
  } inpipe = {INVALID_HANDLE_VALUE, 0};
  struct {
    HANDLE hd;
    int rvid;
  } outpipe = {INVALID_HANDLE_VALUE, 0};
  struct {
    HANDLE hd;
    int rvid;
  } errpipe = {INVALID_HANDLE_VALUE, 0};
  estream_t outfp = NULL;
  estream_t errfp = NULL;

  (void)preexec;
  (void)flags;

  /* Setup return values.  */
  if (r_outfp)
    *r_outfp = NULL;
  if (r_errfp)
    *r_errfp = NULL;
  *pid = (pid_t)(-1); /* Always required.  */

  log_debug ("%s: enter\n", __func__);
  if (infp)
    {
      es_fflush (infp);
      es_rewind (infp);

      /* Create a pipe to copy our infile to the stdin of the child
         process.  On success inpipe.hd is owned by the feeder.  */
      inpipe.hd = _assuan_w32ce_prepare_pipe (&inpipe.rvid, 1);
      if (inpipe.hd == INVALID_HANDLE_VALUE)
        {
          log_error ("_assuan_w32ce_prepare_pipe failed: %s\n",
                     w32_strerror (-1));
          gpg_err_set_errno (EIO);
          return gpg_error_from_syserror ();
        }
      log_debug ("%s: inpipe %p created; hd=%p rvid=%d\n", __func__,
                 infp, inpipe.hd, inpipe.rvid);
      err = start_feeder (infp, inpipe.hd, 1);
      if (err)
        {
          log_error ("error spawning feeder: %s\n", gpg_strerror (err));
          CloseHandle (inpipe.hd);
          return err;
        }
      inpipe.hd = INVALID_HANDLE_VALUE; /* Now owned by the feeder.  */
      log_debug ("%s: inpipe %p created; feeder started\n", __func__,
                 infp);
    }

  if (r_outfp)
    {
      /* Create a pipe to make the stdout of the child process
         available as a stream.  */
      outpipe.hd = _assuan_w32ce_prepare_pipe (&outpipe.rvid, 0);
      if (outpipe.hd == INVALID_HANDLE_VALUE)
        {
          log_error ("_assuan_w32ce_prepare_pipe failed: %s\n",
                     w32_strerror (-1));
          gpg_err_set_errno (EIO);
          /* Fixme release other stuff/kill feeder.  */
          return gpg_error_from_syserror ();
        }
      syshd.type = ES_SYSHD_HANDLE;
      syshd.u.handle = outpipe.hd;
      err = 0;
      outfp = es_sysopen (&syshd, "r");
      if (!outfp)
        {
          err = gpg_err_make (errsource, gpg_err_code_from_syserror ());
          log_error ("error opening pipe stream: %s\n", gpg_strerror (err));
          CloseHandle (outpipe.hd);
          return err;
        }
      log_debug ("%s: outpipe %p created; hd=%p rvid=%d\n", __func__,
                 outfp, outpipe.hd, outpipe.rvid);
      outpipe.hd = INVALID_HANDLE_VALUE; /* Now owned by the OUTFP.  */
    }

  if (r_errfp)
    {
      /* Create a pipe to make the stderr of the child process
         available as a stream.  */
      errpipe.hd = _assuan_w32ce_prepare_pipe (&errpipe.rvid, 0);
      if (errpipe.hd == INVALID_HANDLE_VALUE)
        {
          log_error ("_assuan_w32ce_prepare_pipe failed: %s\n",
                     w32_strerror (-1));
          gpg_err_set_errno (EIO);
          /* Fixme release other stuff/kill feeder.  */
          return gpg_error_from_syserror ();
        }
      syshd.type = ES_SYSHD_HANDLE;
      syshd.u.handle = errpipe.hd;
      err = 0;
      errfp = es_sysopen (&syshd, "r");
      if (!errfp)
        {
          err = gpg_err_make (errsource, gpg_err_code_from_syserror ());
          log_error ("error opening pipe stream: %s\n", gpg_strerror (err));
          CloseHandle (errpipe.hd);
          return err;
        }
      log_debug ("%s: errpipe %p created; hd=%p rvid=%d\n", __func__,
                 errfp, errpipe.hd, errpipe.rvid);
      errpipe.hd = INVALID_HANDLE_VALUE; /* Now owned by the ERRFP.  */
    }



  /* Build the command line.  */
  err = build_w32_commandline (argv, inpipe.rvid, outpipe.rvid, errpipe.rvid,
                               &cmdline);
  if (err)
    {
      /* Fixme release other stuff/kill feeder.  */
      CloseHandle (errpipe.hd);
      return err;
    }

  log_debug ("CreateProcess, path='%s' cmdline='%s'\n", pgmname, cmdline);
  if (!create_process (pgmname, cmdline, &pi))
    {
      log_error ("CreateProcess failed: %s\n", w32_strerror (-1));
      xfree (cmdline);
      /* Fixme release other stuff/kill feeder.  */
      CloseHandle (errpipe.hd);
      return gpg_error (GPG_ERR_GENERAL);
    }
  xfree (cmdline);
  cmdline = NULL;

  /* Note: The other end of the pipe is a rendezvous id and thus there
     is no need for a close.  */

  log_debug ("CreateProcess ready: hProcess=%p hThread=%p"
             " dwProcessID=%d dwThreadId=%d\n",
             pi.hProcess, pi.hThread,
             (int) pi.dwProcessId, (int) pi.dwThreadId);


  /* Process has been created suspended; resume it now. */
  ResumeThread (pi.hThread);
  CloseHandle (pi.hThread);

  if (r_outfp)
    *r_outfp = outfp;
  if (r_errfp)
    *r_errfp = errfp;
  *pid = handle_to_pid (pi.hProcess);
  return 0;
}
Esempio n. 19
0
/* See exechelp.h for a description.  */
gpg_error_t
gnupg_wait_process (const char *pgmname, pid_t pid, int hang, int *r_exitcode)
{
  gpg_err_code_t ec;
  HANDLE proc = fd_to_handle (pid);
  int code;
  DWORD exc;

  if (r_exitcode)
    *r_exitcode = -1;

  if (pid == (pid_t)(-1))
    return gpg_error (GPG_ERR_INV_VALUE);

  /* FIXME: We should do a pth_waitpid here.  However this has not yet
     been implemented.  A special W32 pth system call would even be
     better.  */
  code = WaitForSingleObject (proc, hang? INFINITE : 0);
  switch (code)
    {
    case WAIT_TIMEOUT:
      ec = GPG_ERR_TIMEOUT;
      break;

    case WAIT_FAILED:
      log_error (_("waiting for process %d to terminate failed: %s\n"),
                 (int)pid, w32_strerror (-1));
      ec = GPG_ERR_GENERAL;
      break;

    case WAIT_OBJECT_0:
      if (!GetExitCodeProcess (proc, &exc))
        {
          log_error (_("error getting exit code of process %d: %s\n"),
                     (int)pid, w32_strerror (-1) );
          ec = GPG_ERR_GENERAL;
        }
      else if (exc)
        {
          log_error (_("error running `%s': exit status %d\n"),
                     pgmname, (int)exc );
          if (r_exitcode)
            *r_exitcode = (int)exc;
          ec = GPG_ERR_GENERAL;
        }
      else
        {
          if (r_exitcode)
            *r_exitcode = 0;
          ec = 0;
        }
      break;

    default:
      log_error ("WaitForSingleObject returned unexpected "
                 "code %d for pid %d\n", code, (int)pid );
      ec = GPG_ERR_GENERAL;
      break;
    }

  return gpg_err_make (GPG_ERR_SOURCE_DEFAULT, ec);
}
Esempio n. 20
0
/* Return 0 if the target directory is suitable.  */
static int
check_target_dir (int force)
{
  int count = 0;

#if _WIN32
  {
    char *fname;
    HANDLE hd = INVALID_HANDLE_VALUE;
    WIN32_FIND_DATAA fi;

    fname = xmalloc (strlen (target_dir) + 2 + 2 + 1);
    if (!strcmp (target_dir, "/"))
      strcpy (fname, "/*"); /* Trailing slash is not allowed.  */
    else if (!strcmp (target_dir, "."))
      strcpy (fname, "*");
    else if (*target_dir && target_dir[strlen (target_dir)-1] == '/')
      {
        strcpy (fname, target_dir);
        strcat (fname, "*");
      }
    else if (*target_dir && target_dir[strlen (target_dir)-1] != '*')
      {
        strcpy (fname, target_dir);
        strcat (fname, "/*");
      }
    else
      strcpy (fname, target_dir);

    inf ("finding files in '%s'", fname);

    unfix_backslashes (fname);
    hd = FindFirstFileA (fname, &fi);
    if (hd == INVALID_HANDLE_VALUE)
      {
        err ("error reading target directory '%s': %s",
             target_dir, w32_strerror (-1));
        free (fname);
        return 1;
      }
    do
      {
        if (!strcmp (fi.cFileName, "." ) || !strcmp (fi.cFileName, ".."))
          ;
        else
          count++;
      }
    while (FindNextFileA (hd, &fi));
    FindClose (hd);
    free (fname);
  }
#else /*!_WIN32*/
  {
    DIR *dir;
    struct dirent *de;

    dir = opendir (target_dir);
    if (!dir)
      {
        err ("error reading read target directory '%s': %s",
             target_dir, strerror (errno));
        return 1;
      }
    while ((de = readdir (dir)))
      {
        if (!strcmp (de->d_name, "." ) || !strcmp (de->d_name, ".."))
          continue; /* Skip self and parent dir entry.  */
        count++;
      }
    closedir (dir);
  }
#endif /*!_WIN32*/

  if (count)
    inf ("number of files in target directory: %d", count);
  if (count)
    {
      err ("target directory '%s' is not empty%s",
           target_dir, force? " - continuing anyway":"");
      if (!force)
        return 1;
    }

  return 0;
}
Esempio n. 21
0
/* Lock a spawning process.  The caller needs to provide the address
   of a variable to store the lock information and the name or the
   process.  */
static gpg_error_t
lock_spawning (lock_spawn_t *lock, const char *homedir, const char *name,
               int verbose)
{
#ifdef HAVE_W32_SYSTEM
  int waitrc;
  int timeout = (!strcmp (name, "agent")
                 ? SECS_TO_WAIT_FOR_AGENT
                 : SECS_TO_WAIT_FOR_DIRMNGR);

  (void)homedir; /* Not required. */

  *lock = CreateMutexW
    (NULL, FALSE,
     !strcmp (name, "agent")?   L"GnuPG_spawn_agent_sentinel":
     !strcmp (name, "dirmngr")? L"GnuPG_spawn_dirmngr_sentinel":
     /*                    */   L"GnuPG_spawn_unknown_sentinel");
  if (!*lock)
    {
      log_error ("failed to create the spawn_%s mutex: %s\n",
                 name, w32_strerror (-1));
      return gpg_error (GPG_ERR_GENERAL);
    }

 retry:
  waitrc = WaitForSingleObject (*lock, 1000);
  if (waitrc == WAIT_OBJECT_0)
    return 0;

  if (waitrc == WAIT_TIMEOUT && timeout)
    {
      timeout--;
      if (verbose)
        log_info ("another process is trying to start the %s ... (%ds)\n",
                  name, timeout);
      goto retry;
    }
  if (waitrc == WAIT_TIMEOUT)
    log_info ("error waiting for the spawn_%s mutex: timeout\n", name);
  else
    log_info ("error waiting for the spawn_%s mutex: (code=%d) %s\n",
              name, waitrc, w32_strerror (-1));
  return gpg_error (GPG_ERR_GENERAL);
#else /*!HAVE_W32_SYSTEM*/
  char *fname;

  (void)verbose;

  *lock = NULL;

  fname = make_filename
    (homedir,
     !strcmp (name, "agent")?   "gnupg_spawn_agent_sentinel":
     !strcmp (name, "dirmngr")? "gnupg_spawn_dirmngr_sentinel":
     /*                    */   "gnupg_spawn_unknown_sentinel",
     NULL);
  if (!fname)
    return gpg_error_from_syserror ();

  *lock = dotlock_create (fname, 0);
  xfree (fname);
  if (!*lock)
    return gpg_error_from_syserror ();

  /* FIXME: We should use a timeout of 5000 here - however
     make_dotlock does not yet support values other than -1 and 0.  */
  if (dotlock_take (*lock, -1))
    return gpg_error_from_syserror ();

  return 0;
#endif /*!HAVE_W32_SYSTEM*/
}
Esempio n. 22
0
/* Spawn a new process and immediatley detach from it.  The name of
   the program to exec is PGMNAME and its arguments are in ARGV (the
   programname is automatically passed as first argument).
   Environment strings in ENVP are set.  An error is returned if
   pgmname is not executable; to make this work it is necessary to
   provide an absolute file name.  All standard file descriptors are
   connected to /dev/null. */
gpg_error_t
gnupg_spawn_process_detached (const char *pgmname, const char *argv[],
                              const char *envp[] )
{
  gpg_error_t err;
  SECURITY_ATTRIBUTES sec_attr;
  PROCESS_INFORMATION pi =
    {
      NULL,      /* Returns process handle.  */
      0,         /* Returns primary thread handle.  */
      0,         /* Returns pid.  */
      0          /* Returns tid.  */
    };
  STARTUPINFO si;
  int cr_flags;
  char *cmdline;


  /* FIXME: We don't make use of ENVP yet.  It is currently only used
     to pass the GPG_AGENT_INFO variable to gpg-agent.  As the default
     on windows is to use a standard socket, this does not really
     matter.  */
  (void)envp;

  if (access (pgmname, X_OK))
    return gpg_error_from_syserror ();

  /* Prepare security attributes.  */
  memset (&sec_attr, 0, sizeof sec_attr );
  sec_attr.nLength = sizeof sec_attr;
  sec_attr.bInheritHandle = FALSE;

  /* Build the command line.  */
  err = build_w32_commandline (pgmname, argv, &cmdline);
  if (err)
    return err;

  /* Start the process.  */
  memset (&si, 0, sizeof si);
  si.cb = sizeof (si);
  si.dwFlags = STARTF_USESHOWWINDOW;
  si.wShowWindow = DEBUG_W32_SPAWN? SW_SHOW : SW_MINIMIZE;

  cr_flags = (CREATE_DEFAULT_ERROR_MODE
              | GetPriorityClass (GetCurrentProcess ())
              | CREATE_NEW_PROCESS_GROUP
              | DETACHED_PROCESS);
/*   log_debug ("CreateProcess(detached), path=`%s' cmdline=`%s'\n", */
/*              pgmname, cmdline); */
  if (!CreateProcess (pgmname,       /* Program to start.  */
                      cmdline,       /* Command line arguments.  */
                      &sec_attr,     /* Process security attributes.  */
                      &sec_attr,     /* Thread security attributes.  */
                      FALSE,         /* Inherit handles.  */
                      cr_flags,      /* Creation flags.  */
                      NULL,          /* Environment.  */
                      NULL,          /* Use current drive/directory.  */
                      &si,           /* Startup information. */
                      &pi            /* Returns process information.  */
                      ))
    {
      log_error ("CreateProcess(detached) failed: %s\n", w32_strerror (-1));
      xfree (cmdline);
      return gpg_error (GPG_ERR_GENERAL);
    }
  xfree (cmdline);
  cmdline = NULL;

/*   log_debug ("CreateProcess(detached) ready: hProcess=%p hThread=%p" */
/*              " dwProcessID=%d dwThreadId=%d\n", */
/*              pi.hProcess, pi.hThread, */
/*              (int) pi.dwProcessId, (int) pi.dwThreadId); */

  CloseHandle (pi.hThread);

  return 0;
}
Esempio n. 23
0
/* Load all certificates from the Windows store named STORENAME.  All
 * certificates are considered to be system provided trusted
 * certificates.  The cache should be in a locked state when calling
 * this function.  */
static void
load_certs_from_w32_store (const char *storename)
{
  static int init_done;
  static CERTOPENSYSTEMSTORE pCertOpenSystemStore;
  static CERTENUMCERTIFICATESINSTORE pCertEnumCertificatesInStore;
  static CERTCLOSESTORE pCertCloseStore;
  gpg_error_t err;
  HCERTSTORE w32store;
  const CERT_CONTEXT *w32cert;
  ksba_cert_t cert = NULL;
  unsigned int count = 0;

  /* Initialize on the first use.  */
  if (!init_done)
    {
      static HANDLE hCrypt32;

      init_done = 1;

      hCrypt32 = LoadLibrary ("Crypt32.dll");
      if (!hCrypt32)
        {
          log_error ("can't load Crypt32.dll: %s\n",  w32_strerror (-1));
          return;
        }

      pCertOpenSystemStore = (CERTOPENSYSTEMSTORE)
        GetProcAddress (hCrypt32, "CertOpenSystemStoreA");
      pCertEnumCertificatesInStore = (CERTENUMCERTIFICATESINSTORE)
        GetProcAddress (hCrypt32, "CertEnumCertificatesInStore");
      pCertCloseStore = (CERTCLOSESTORE)
        GetProcAddress (hCrypt32, "CertCloseStore");
      if (   !pCertOpenSystemStore
          || !pCertEnumCertificatesInStore
          || !pCertCloseStore)
        {
          log_error ("can't load crypt32.dll: %s\n", "missing function");
          pCertOpenSystemStore = NULL;
        }
    }

  if (!pCertOpenSystemStore)
    return;  /* Not initialized.  */


  w32store = pCertOpenSystemStore (0, storename);
  if (!w32store)
    {
      log_error ("can't open certificate store '%s': %s\n",
                 storename, w32_strerror (-1));
      return;
    }

  w32cert = NULL;
  while ((w32cert = pCertEnumCertificatesInStore (w32store, w32cert)))
    {
      if (w32cert->dwCertEncodingType == X509_ASN_ENCODING)
        {
          ksba_cert_release (cert);
          cert = NULL;
          err = ksba_cert_new (&cert);
          if (!err)
            err = ksba_cert_init_from_mem (cert,
                                           w32cert->pbCertEncoded,
                                           w32cert->cbCertEncoded);
          if (err)
            {
              log_error (_("can't parse certificate '%s': %s\n"),
                         storename, gpg_strerror (err));
              break;
            }

          err = put_cert (cert, 1, CERTTRUST_CLASS_SYSTEM, NULL);
          if (!err)
            count++;
          if (gpg_err_code (err) == GPG_ERR_DUP_VALUE)
            {
              if (DBG_X509)
                log_debug (_("certificate '%s' already cached\n"), storename);
            }
          else if (err)
            log_error (_("error loading certificate '%s': %s\n"),
                       storename, gpg_strerror (err));
          else if (opt.verbose > 1)
            {
              char *p;

              log_info (_("trusted certificate '%s' loaded\n"), storename);
              p = get_fingerprint_hexstring_colon (cert);
              log_info (_("  SHA1 fingerprint = %s\n"), p);
              xfree (p);

              cert_log_name    (_("   issuer ="), cert);
              cert_log_subject (_("  subject ="), cert);
            }
        }
    }

  ksba_cert_release (cert);
  pCertCloseStore (w32store, 0);

  if (DBG_X509)
    log_debug ("number of certs loaded from store '%s': %u\n",
               storename, count);

}