Пример #1
0
int
log_get_fd ()
{
  return logstream? es_fileno(logstream) : -1;
}
Пример #2
0
/* Read the key identified by GRIP from the private key directory and
   return it as an gcrypt S-expression object in RESULT.  On failure
   returns an error code and stores NULL at RESULT. */
static gpg_error_t
read_key_file (const unsigned char *grip, gcry_sexp_t *result)
{
  int rc;
  char *fname;
  estream_t fp;
  struct stat st;
  unsigned char *buf;
  size_t buflen, erroff;
  gcry_sexp_t s_skey;
  char hexgrip[40+4+1];

  *result = NULL;

  bin2hex (grip, 20, hexgrip);
  strcpy (hexgrip+40, ".key");

  fname = make_filename (opt.homedir, GNUPG_PRIVATE_KEYS_DIR, hexgrip, NULL);
  fp = es_fopen (fname, "rb");
  if (!fp)
    {
      rc = gpg_error_from_syserror ();
      if (gpg_err_code (rc) != GPG_ERR_ENOENT)
        log_error ("can't open '%s': %s\n", fname, strerror (errno));
      xfree (fname);
      return rc;
    }

  if (fstat (es_fileno (fp), &st))
    {
      rc = gpg_error_from_syserror ();
      log_error ("can't stat '%s': %s\n", fname, strerror (errno));
      xfree (fname);
      es_fclose (fp);
      return rc;
    }

  buflen = st.st_size;
  buf = xtrymalloc (buflen+1);
  if (!buf)
    {
      rc = gpg_error_from_syserror ();
      log_error ("error allocating %zu bytes for '%s': %s\n",
                 buflen, fname, strerror (errno));
      xfree (fname);
      es_fclose (fp);
      xfree (buf);
      return rc;

    }

  if (es_fread (buf, buflen, 1, fp) != 1)
    {
      rc = gpg_error_from_syserror ();
      log_error ("error reading %zu bytes from '%s': %s\n",
                 buflen, fname, strerror (errno));
      xfree (fname);
      es_fclose (fp);
      xfree (buf);
      return rc;
    }

  /* Convert the file into a gcrypt S-expression object.  */
  rc = gcry_sexp_sscan (&s_skey, &erroff, (char*)buf, buflen);
  xfree (fname);
  es_fclose (fp);
  xfree (buf);
  if (rc)
    {
      log_error ("failed to build S-Exp (off=%u): %s\n",
                 (unsigned int)erroff, gpg_strerror (rc));
      return rc;
    }
  *result = s_skey;
  return 0;
}
Пример #3
0
static gpgrt_ssize_t
fun_writer (void *cookie_arg, const void *buffer, size_t size)
{
  struct fun_cookie_s *cookie = cookie_arg;

  /* FIXME: Use only estream with a callback for socket writing.  This
     avoids the ugly mix of fd and estream code.  */

  /* Note that we always try to reconnect to the socket but print
     error messages only the first time an error occurred.  If
     RUNNING_DETACHED is set we don't fall back to stderr and even do
     not print any error messages.  This is needed because detached
     processes often close stderr and by writing to file descriptor 2
     we might send the log message to a file not intended for logging
     (e.g. a pipe or network connection). */
  if (cookie->want_socket && cookie->fd == -1)
    {
#ifdef WITH_IPV6
      struct sockaddr_in6 srvr_addr_in6;
#endif
      struct sockaddr_in srvr_addr_in;
#ifndef HAVE_W32_SYSTEM
      struct sockaddr_un srvr_addr_un;
#endif
      size_t addrlen;
      struct sockaddr *srvr_addr = NULL;
      unsigned short port = 0;
      int af = AF_LOCAL;
      int pf = PF_LOCAL;
      const char *name = cookie->name;

      /* Not yet open or meanwhile closed due to an error. */
      cookie->is_socket = 0;

      /* Check whether this is a TCP socket or a local socket.  */
      if (!strncmp (name, "tcp://", 6) && name[6])
        {
          name += 6;
          af = AF_INET;
          pf = PF_INET;
        }
#ifndef HAVE_W32_SYSTEM
      else if (!strncmp (name, "socket://", 9) && name[9])
        name += 9;
#endif

      if (af == AF_LOCAL)
        {
#ifdef HAVE_W32_SYSTEM
          addrlen = 0;
#else
          memset (&srvr_addr, 0, sizeof srvr_addr);
          srvr_addr_un.sun_family = af;
          strncpy (srvr_addr_un.sun_path,
                   name, sizeof (srvr_addr_un.sun_path)-1);
          srvr_addr_un.sun_path[sizeof (srvr_addr_un.sun_path)-1] = 0;
          srvr_addr = (struct sockaddr *)&srvr_addr_un;
          addrlen = SUN_LEN (&srvr_addr_un);
#endif
        }
      else
        {
          char *addrstr, *p;
#ifdef HAVE_INET_PTON
          void *addrbuf = NULL;
#endif /*HAVE_INET_PTON*/

          addrstr = xtrymalloc (strlen (name) + 1);
          if (!addrstr)
            addrlen = 0; /* This indicates an error.  */
          else if (*name == '[')
            {
              /* Check for IPv6 literal address.  */
              strcpy (addrstr, name+1);
              p = strchr (addrstr, ']');
              if (!p || p[1] != ':' || !parse_portno (p+2, &port))
                {
                  gpg_err_set_errno (EINVAL);
                  addrlen = 0;
                }
              else
                {
                  *p = 0;
#ifdef WITH_IPV6
                  af = AF_INET6;
                  pf = PF_INET6;
                  memset (&srvr_addr_in6, 0, sizeof srvr_addr_in6);
                  srvr_addr_in6.sin6_family = af;
                  srvr_addr_in6.sin6_port = htons (port);
#ifdef HAVE_INET_PTON
                  addrbuf = &srvr_addr_in6.sin6_addr;
#endif /*HAVE_INET_PTON*/
                  srvr_addr = (struct sockaddr *)&srvr_addr_in6;
                  addrlen = sizeof srvr_addr_in6;
#else
                  gpg_err_set_errno (EAFNOSUPPORT);
                  addrlen = 0;
#endif
                }
            }
          else
            {
              /* Check for IPv4 literal address.  */
              strcpy (addrstr, name);
              p = strchr (addrstr, ':');
              if (!p || !parse_portno (p+1, &port))
                {
                  gpg_err_set_errno (EINVAL);
                  addrlen = 0;
                }
              else
                {
                  *p = 0;
                  memset (&srvr_addr_in, 0, sizeof srvr_addr_in);
                  srvr_addr_in.sin_family = af;
                  srvr_addr_in.sin_port = htons (port);
#ifdef HAVE_INET_PTON
                  addrbuf = &srvr_addr_in.sin_addr;
#endif /*HAVE_INET_PTON*/
                  srvr_addr = (struct sockaddr *)&srvr_addr_in;
                  addrlen = sizeof srvr_addr_in;
                }
            }

          if (addrlen)
            {
#ifdef HAVE_INET_PTON
              if (inet_pton (af, addrstr, addrbuf) != 1)
                addrlen = 0;
#else /*!HAVE_INET_PTON*/
              /* We need to use the old function.  If we are here v6
                 support isn't enabled anyway and thus we can do fine
                 without.  Note that Windows has a compatible inet_pton
                 function named inetPton, but only since Vista.  */
              srvr_addr_in.sin_addr.s_addr = inet_addr (addrstr);
              if (srvr_addr_in.sin_addr.s_addr == INADDR_NONE)
                addrlen = 0;
#endif /*!HAVE_INET_PTON*/
            }

          xfree (addrstr);
        }

      cookie->fd = addrlen? socket (pf, SOCK_STREAM, 0) : -1;
      if (cookie->fd == -1)
        {
          if (!cookie->quiet && !running_detached
              && isatty (es_fileno (es_stderr)))
            es_fprintf (es_stderr, "failed to create socket for logging: %s\n",
                        strerror(errno));
        }
      else
        {
          if (connect (cookie->fd, srvr_addr, addrlen) == -1)
            {
              if (!cookie->quiet && !running_detached
                  && isatty (es_fileno (es_stderr)))
                es_fprintf (es_stderr, "can't connect to '%s': %s\n",
                            cookie->name, strerror(errno));
              sock_close (cookie->fd);
              cookie->fd = -1;
            }
        }

      if (cookie->fd == -1)
        {
          if (!running_detached)
            {
              /* Due to all the problems with apps not running
                 detached but being called with stderr closed or used
                 for a different purposes, it does not make sense to
                 switch to stderr.  We therefore disable it. */
              if (!cookie->quiet)
                {
                  /* fputs ("switching logging to stderr\n", stderr);*/
                  cookie->quiet = 1;
                }
              cookie->fd = -1; /*fileno (stderr);*/
            }
        }
      else /* Connection has been established. */
        {
          cookie->quiet = 0;
          cookie->is_socket = 1;
        }
    }

  log_socket = cookie->fd;
  if (cookie->fd != -1)
    {
#ifdef HAVE_W32CE_SYSTEM
      if (cookie->use_writefile)
        {
          DWORD nwritten;

          WriteFile ((HANDLE)cookie->fd, buffer, size, &nwritten, NULL);
          return (gpgrt_ssize_t)size; /* Okay.  */
        }
#endif
      if (!writen (cookie->fd, buffer, size, cookie->is_socket))
        return (gpgrt_ssize_t)size; /* Okay. */
    }

  if (!running_detached && cookie->fd != -1
      && isatty (es_fileno (es_stderr)))
    {
      if (*cookie->name)
        es_fprintf (es_stderr, "error writing to '%s': %s\n",
                    cookie->name, strerror(errno));
      else
        es_fprintf (es_stderr, "error writing to file descriptor %d: %s\n",
                    cookie->fd, strerror(errno));
    }
  if (cookie->is_socket && cookie->fd != -1)
    {
      sock_close (cookie->fd);
      cookie->fd = -1;
      log_socket = -1;
    }

  return (gpgrt_ssize_t)size;
}
Пример #4
0
/* Common function to either set the logging to a file or a file
   descriptor. */
static void
set_file_fd (const char *name, int fd)
{
  estream_t fp;
  int want_socket;
#ifdef HAVE_W32CE_SYSTEM
  int use_writefile = 0;
#endif
  struct fun_cookie_s *cookie;

  /* Close an open log stream.  */
  if (logstream)
    {
      es_fclose (logstream);
      logstream = NULL;
    }

  /* Figure out what kind of logging we want.  */
  if (name && !strcmp (name, "-"))
    {
      name = NULL;
      fd = es_fileno (es_stderr);
    }

  want_socket = 0;
  if (name && !strncmp (name, "tcp://", 6) && name[6])
    want_socket = 1;
#ifndef HAVE_W32_SYSTEM
  else if (name && !strncmp (name, "socket://", 9) && name[9])
    want_socket = 2;
#endif /*HAVE_W32_SYSTEM*/
#ifdef HAVE_W32CE_SYSTEM
  else if (name && !strcmp (name, "GPG2:"))
    {
      HANDLE hd;

      ActivateDevice (L"Drivers\\"GNUPG_NAME"_Log", 0);
      /* Ignore a filename and write the debug output to the GPG2:
         device.  */
      hd = CreateFile (L"GPG2:", GENERIC_WRITE,
                       FILE_SHARE_READ | FILE_SHARE_WRITE,
                       NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
      fd = (hd == INVALID_HANDLE_VALUE)? -1 : (int)hd;
      name = NULL;
      force_prefixes = 1;
      use_writefile = 1;
    }
#endif /*HAVE_W32CE_SYSTEM*/

  /* Setup a new stream.  */

  /* The xmalloc below is justified because we can expect that this
     function is called only during initialization and there is no
     easy way out of this error condition.  */
  cookie = xmalloc (sizeof *cookie + (name? strlen (name):0));
  strcpy (cookie->name, name? name:"");
  cookie->quiet = 0;
  cookie->is_socket = 0;
  cookie->want_socket = want_socket;
#ifdef HAVE_W32CE_SYSTEM
  cookie->use_writefile = use_writefile;
#endif
  if (!name)
    cookie->fd = fd;
  else if (want_socket)
    cookie->fd = -1;
  else
    {
      do
        cookie->fd = open (name, O_WRONLY|O_APPEND|O_CREAT,
                           (S_IRUSR|S_IRGRP|S_IROTH|S_IWUSR|S_IWGRP|S_IWOTH));
      while (cookie->fd == -1 && errno == EINTR);
    }
  log_socket = cookie->fd;

  {
    es_cookie_io_functions_t io = { NULL };
    io.func_write = fun_writer;
    io.func_close = fun_closer;

    fp = es_fopencookie (cookie, "w", io);
  }

  /* On error default to a stderr based estream.  */
  if (!fp)
    fp = es_stderr;

  es_setvbuf (fp, NULL, _IOLBF, 0);

  logstream = fp;

  /* We always need to print the prefix and the pid for socket mode,
     so that the server reading the socket can do something
     meaningful. */
  force_prefixes = want_socket;

  missing_lf = 0;
}
Пример #5
0
/* Try to connect to the dirmngr via socket or fork it off and work by
   pipes.  Handle the server's initial greeting */
static assuan_context_t
start_dirmngr (int only_daemon)
{
  int rc;
  char *infostr, *p;
  assuan_context_t ctx;
  int try_default = 0;

  infostr = opt.force_pipe_server? NULL : getenv (DIRMNGR_INFO_NAME);
  if (only_daemon && (!infostr || !*infostr))
    {
      if (dirmngr_user_socket_name ())
        infostr = xstrdup (dirmngr_user_socket_name ());
      else
        infostr = xstrdup (dirmngr_sys_socket_name ());
      try_default = 1;
    }

  rc = assuan_new (&ctx);
  if (rc)
    {
      log_error (_("failed to allocate assuan context: %s\n"),
                 gpg_strerror (rc));
      return NULL;
    }

  if (!infostr || !*infostr)
    {
      const char *pgmname;
      const char *argv[3];
      assuan_fd_t no_close_list[3];
      int i;

      if (only_daemon)
        {
          log_error (_("apparently no running dirmngr\n"));
          return NULL;
        }

      if (opt.verbose)
        log_info (_("no running dirmngr - starting one\n"));

      if (!opt.dirmngr_program || !*opt.dirmngr_program)
        opt.dirmngr_program = "./dirmngr";
      if ( !(pgmname = strrchr (opt.dirmngr_program, '/')))
        pgmname = opt.dirmngr_program;
      else
        pgmname++;

      argv[0] = pgmname;
      argv[1] = "--server";
      argv[2] = NULL;

      i=0;
      if (log_get_fd () != -1)
        no_close_list[i++] = assuan_fd_from_posix_fd (log_get_fd ());
      no_close_list[i++] = assuan_fd_from_posix_fd (es_fileno (es_stderr));
      no_close_list[i] = ASSUAN_INVALID_FD;

      /* Connect to the agent and perform initial handshaking.  */
      rc = assuan_pipe_connect (ctx, opt.dirmngr_program, argv,
                                no_close_list, NULL, NULL, 0);
    }
  else /* Connect to a daemon.  */
    {
      int prot;
      int pid;

      infostr = xstrdup (infostr);
      if (!try_default && *infostr)
        {
          if ( !(p = strchr (infostr, ':')) || p == infostr)
            {
              log_error (_("malformed %s environment variable\n"),
                         DIRMNGR_INFO_NAME);
              xfree (infostr);
              if (only_daemon)
                return NULL;
              /* Try again by starting a new instance.  */
              opt.force_pipe_server = 1;
              return start_dirmngr (0);
            }
          *p++ = 0;
          pid = atoi (p);
          while (*p && *p != ':')
            p++;
          prot = *p? atoi (p+1) : 0;
          if (prot != 1)
            {
              log_error (_("dirmngr protocol version %d is not supported\n"),
                         prot);
              xfree (infostr);
              if (only_daemon)
                return NULL;
              opt.force_pipe_server = 1;
              return start_dirmngr (0);
            }
        }
      else
        pid = -1;

      rc = assuan_socket_connect (ctx, infostr, pid, 0);
      xfree (infostr);
      if (gpg_err_code(rc) == GPG_ERR_ASS_CONNECT_FAILED && !only_daemon)
        {
          log_error (_("can't connect to the dirmngr - trying fall back\n"));
          opt.force_pipe_server = 1;
          return start_dirmngr (0);
        }
    }

  if (rc)
    {
      assuan_release (ctx);
      log_error (_("can't connect to the dirmngr: %s\n"),
                 gpg_strerror (rc));
      return NULL;
    }

  return ctx;
}
Пример #6
0
/* Read the key identified by GRIP from the private key directory and
   return it as an gcrypt S-expression object in RESULT.  On failure
   returns an error code and stores NULL at RESULT. */
static gpg_error_t
read_key_file (const unsigned char *grip, gcry_sexp_t *result)
{
  int rc;
  char *fname;
  estream_t fp;
  struct stat st;
  unsigned char *buf;
  size_t buflen, erroff;
  gcry_sexp_t s_skey;
  char hexgrip[40+4+1];
  char first;

  *result = NULL;

  bin2hex (grip, 20, hexgrip);
  strcpy (hexgrip+40, ".key");

  fname = make_filename (opt.homedir, GNUPG_PRIVATE_KEYS_DIR, hexgrip, NULL);
  fp = es_fopen (fname, "rb");
  if (!fp)
    {
      rc = gpg_error_from_syserror ();
      if (gpg_err_code (rc) != GPG_ERR_ENOENT)
        log_error ("can't open '%s': %s\n", fname, strerror (errno));
      xfree (fname);
      return rc;
    }

  if (es_fread (&first, 1, 1, fp) != 1)
    {
      rc = gpg_error_from_syserror ();
      log_error ("error reading first byte from '%s': %s\n",
                 fname, strerror (errno));
      xfree (fname);
      es_fclose (fp);
      return rc;
    }

  rc = es_fseek (fp, 0, SEEK_SET);
  if (rc)
    {
      log_error ("error seeking in '%s': %s\n", fname, strerror (errno));
      xfree (fname);
      es_fclose (fp);
      return rc;
    }

  if (first != '(')
    {
      /* Key is in extended format.  */
      pkc_t pk;
      int line;

      rc = pkc_parse (&pk, &line, fp);
      es_fclose (fp);

      if (rc)
        log_error ("error parsing '%s' line %d: %s\n",
                   fname, line, gpg_strerror (rc));
      else
        {
          rc = pkc_get_private_key (pk, result);
          pkc_release (pk);
          if (rc)
            log_error ("error getting private key from '%s': %s\n",
                       fname, gpg_strerror (rc));
        }

      xfree (fname);
      return rc;
    }

  if (fstat (es_fileno (fp), &st))
    {
      rc = gpg_error_from_syserror ();
      log_error ("can't stat '%s': %s\n", fname, strerror (errno));
      xfree (fname);
      es_fclose (fp);
      return rc;
    }

  buflen = st.st_size;
  buf = xtrymalloc (buflen+1);
  if (!buf)
    {
      rc = gpg_error_from_syserror ();
      log_error ("error allocating %zu bytes for '%s': %s\n",
                 buflen, fname, strerror (errno));
      xfree (fname);
      es_fclose (fp);
      xfree (buf);
      return rc;

    }

  if (es_fread (buf, buflen, 1, fp) != 1)
    {
      rc = gpg_error_from_syserror ();
      log_error ("error reading %zu bytes from '%s': %s\n",
                 buflen, fname, strerror (errno));
      xfree (fname);
      es_fclose (fp);
      xfree (buf);
      return rc;
    }

  /* Convert the file into a gcrypt S-expression object.  */
  rc = gcry_sexp_sscan (&s_skey, &erroff, (char*)buf, buflen);
  xfree (fname);
  es_fclose (fp);
  xfree (buf);
  if (rc)
    {
      log_error ("failed to build S-Exp (off=%u): %s\n",
                 (unsigned int)erroff, gpg_strerror (rc));
      return rc;
    }
  *result = s_skey;
  return 0;
}
Пример #7
0
static gpg_error_t
write_extended_private_key (char *fname, estream_t fp,
                            const void *buf, size_t len)
{
  gpg_error_t err;
  pkc_t pk = NULL;
  gcry_sexp_t key = NULL;
  int remove = 0;
  int line;

  err = pkc_parse (&pk, &line, fp);
  if (err)
    {
      log_error ("error parsing '%s' line %d: %s\n",
                 fname, line, gpg_strerror (err));
      goto leave;
    }

  err = gcry_sexp_sscan (&key, NULL, buf, len);
  if (err)
    goto leave;

  err = pkc_set_private_key (pk, key);
  if (err)
    goto leave;

  err = es_fseek (fp, 0, SEEK_SET);
  if (err)
    goto leave;

  err = pkc_write (pk, fp);
  if (err)
    {
      log_error ("error writing '%s': %s\n", fname, gpg_strerror (err));
      remove = 1;
      goto leave;
    }

  if (ftruncate (es_fileno (fp), es_ftello (fp)))
    {
      err = gpg_error_from_syserror ();
      log_error ("error truncating '%s': %s\n", fname, gpg_strerror (err));
      remove = 1;
      goto leave;
    }

  if (es_fclose (fp))
    {
      err = gpg_error_from_syserror ();
      log_error ("error closing '%s': %s\n", fname, gpg_strerror (err));
      remove = 1;
      goto leave;
    }
  else
    fp = NULL;

  bump_key_eventcounter ();

 leave:
  if (fp)
    es_fclose (fp);
  if (remove)
    gnupg_remove (fname);
  xfree (fname);
  gcry_sexp_release (key);
  pkc_release (pk);
  return err;
}
Пример #8
0
/* Write an S-expression formatted key to our key storage.  With FORCE
   passed as true an existing key with the given GRIP will get
   overwritten.  */
int
agent_write_private_key (const unsigned char *grip,
                         const void *buffer, size_t length, int force)
{
  char *fname;
  estream_t fp;
  char hexgrip[40+4+1];

  bin2hex (grip, 20, hexgrip);
  strcpy (hexgrip+40, ".key");

  fname = make_filename (opt.homedir, GNUPG_PRIVATE_KEYS_DIR, hexgrip, NULL);

  /* FIXME: Write to a temp file first so that write failures during
     key updates won't lead to a key loss.  */

  if (!force && !access (fname, F_OK))
    {
      log_error ("secret key file '%s' already exists\n", fname);
      xfree (fname);
      return gpg_error (GPG_ERR_EEXIST);
    }

  fp = es_fopen (fname, force? "rb+,mode=-rw" : "wbx,mode=-rw");
  if (!fp)
    {
      gpg_error_t tmperr = gpg_error_from_syserror ();
      log_error ("can't create '%s': %s\n", fname, gpg_strerror (tmperr));
      xfree (fname);
      return tmperr;
    }

  /* See if an existing key is in extended format.  */
  if (force)
    {
      gpg_error_t rc;
      char first;

      if (es_fread (&first, 1, 1, fp) != 1)
        {
          rc = gpg_error_from_syserror ();
          log_error ("error reading first byte from '%s': %s\n",
                     fname, strerror (errno));
          xfree (fname);
          es_fclose (fp);
          return rc;
        }

      rc = es_fseek (fp, 0, SEEK_SET);
      if (rc)
        {
          log_error ("error seeking in '%s': %s\n", fname, strerror (errno));
          xfree (fname);
          es_fclose (fp);
          return rc;
        }

      if (first != '(')
        {
          /* Key is in extended format.  */
          return write_extended_private_key (fname, fp, buffer, length);
        }
    }

  if (es_fwrite (buffer, length, 1, fp) != 1)
    {
      gpg_error_t tmperr = gpg_error_from_syserror ();
      log_error ("error writing '%s': %s\n", fname, gpg_strerror (tmperr));
      es_fclose (fp);
      gnupg_remove (fname);
      xfree (fname);
      return tmperr;
    }

  /* When force is given, the file might have to be truncated.  */
  if (force && ftruncate (es_fileno (fp), es_ftello (fp)))
    {
      gpg_error_t tmperr = gpg_error_from_syserror ();
      log_error ("error truncating '%s': %s\n", fname, gpg_strerror (tmperr));
      es_fclose (fp);
      gnupg_remove (fname);
      xfree (fname);
      return tmperr;
    }

  if (es_fclose (fp))
    {
      gpg_error_t tmperr = gpg_error_from_syserror ();
      log_error ("error closing '%s': %s\n", fname, gpg_strerror (tmperr));
      gnupg_remove (fname);
      xfree (fname);
      return tmperr;
    }
  bump_key_eventcounter ();
  xfree (fname);
  return 0;
}
Пример #9
0
void
import_ownertrust (ctrl_t ctrl, const char *fname )
{
    estream_t fp;
    int is_stdin=0;
    char line[256];
    char *p;
    size_t n, fprlen;
    unsigned int otrust;
    byte fpr[MAX_FINGERPRINT_LEN];
    int any = 0;
    int rc;

    init_trustdb (ctrl, 0);
    if( iobuf_is_pipe_filename (fname) ) {
	fp = es_stdin;
	fname = "[stdin]";
	is_stdin = 1;
    }
    else if( !(fp = es_fopen( fname, "r" )) ) {
	log_error ( _("can't open '%s': %s\n"), fname, strerror(errno) );
	return;
    }

    if (is_secured_file (es_fileno (fp)))
      {
        es_fclose (fp);
        gpg_err_set_errno (EPERM);
	log_error (_("can't open '%s': %s\n"), fname, strerror(errno) );
	return;
      }

    while (es_fgets (line, DIM(line)-1, fp)) {
	TRUSTREC rec;

	if( !*line || *line == '#' )
	    continue;
	n = strlen(line);
	if( line[n-1] != '\n' ) {
	    log_error (_("error in '%s': %s\n"), fname, _("line too long") );
	    /* ... or last line does not have a LF */
	    break; /* can't continue */
	}
	for(p = line; *p && *p != ':' ; p++ )
	    if( !hexdigitp(p) )
		break;
	if( *p != ':' ) {
	    log_error (_("error in '%s': %s\n"), fname, _("colon missing") );
	    continue;
	}
	fprlen = p - line;
	if( fprlen != 32 && fprlen != 40 && fprlen != 64) {
	    log_error (_("error in '%s': %s\n"),
                       fname, _("invalid fingerprint") );
	    continue;
	}
	if( sscanf(p, ":%u:", &otrust ) != 1 ) {
	    log_error (_("error in '%s': %s\n"),
                       fname, _("ownertrust value missing"));
	    continue;
	}
	if( !otrust )
	    continue; /* no otrust defined - no need to update or insert */
	/* Convert the ascii fingerprint to binary */
	for(p=line, fprlen=0;
            fprlen < MAX_FINGERPRINT_LEN && *p != ':';
            p += 2 )
          fpr[fprlen++] = HEXTOBIN(p[0]) * 16 + HEXTOBIN(p[1]);
	while (fprlen < MAX_FINGERPRINT_LEN)
	    fpr[fprlen++] = 0;

	rc = tdbio_search_trust_byfpr (fpr, &rec);
	if( !rc ) { /* found: update */
	    if (rec.r.trust.ownertrust != otrust)
              {
                if (!opt.quiet)
                  {
                    if( rec.r.trust.ownertrust )
                      log_info("changing ownertrust from %u to %u\n",
                               rec.r.trust.ownertrust, otrust );
                    else
                      log_info("setting ownertrust to %u\n", otrust );
                  }
                rec.r.trust.ownertrust = otrust;
                write_record (ctrl, &rec);
                any = 1;
              }
	}
	else if (gpg_err_code (rc) == GPG_ERR_NOT_FOUND) { /* insert */
            if (!opt.quiet)
              log_info("inserting ownertrust of %u\n", otrust );
            memset (&rec, 0, sizeof rec);
            rec.recnum = tdbio_new_recnum (ctrl);
            rec.rectype = RECTYPE_TRUST;
            memcpy (rec.r.trust.fingerprint, fpr, 20);
            rec.r.trust.ownertrust = otrust;
            write_record (ctrl, &rec);
            any = 1;
	}
	else /* error */
	    log_error (_("error finding trust record in '%s': %s\n"),
                       fname, gpg_strerror (rc));
    }
    if (es_ferror (fp))
	log_error ( _("read error in '%s': %s\n"), fname, strerror(errno) );
    if (!is_stdin)
	es_fclose (fp);

    if (any)
      {
        revalidation_mark (ctrl);
        rc = tdbio_sync ();
        if (rc)
          log_error (_("trustdb: sync failed: %s\n"), gpg_strerror (rc) );
      }

}