Exemplo n.º 1
0
static gpg_error_t
export_cert (char *fpr, struct cert *cert)
{
  gpg_error_t err;
  assuan_context_t ctx;
  const char *argv[] = { "gpgsm", "--server", NULL };
#define COMMANDLINELEN 80
  char cmd[COMMANDLINELEN];
  struct export_hook exp;

  err = assuan_new (&ctx);
  if (err)
    {
      DEBUG (DBG_CRIT, "failed to allocate assuan context: %s",
	     gpg_strerror (err));
      return err;
    }

  err = assuan_pipe_connect (ctx, get_gpgsm_path (), argv, NULL,
			     NULL, NULL, 128);
  if (err)
    {
      assuan_release (ctx);
      DEBUG (DBG_CRIT, "spawning %s\n", get_gpgsm_path ());
      return err;
    }

  exp.buffer = NULL;
  exp.buffer_len = 0;
  exp.buffer_size = 0;

  snprintf (cmd, sizeof (cmd), "EXPORT --data -- %s\n", cert->fpr);
  err = assuan_transact (ctx, cmd, export_cert_cb, &exp,
			 NULL, NULL, NULL, NULL);
  assuan_release (ctx);

  if (!err)
    {
      cert->cert_der = exp.buffer;
      cert->cert_der_len = exp.buffer_len;
    }
#ifdef COMPAT_FALLBACK
  else if (gpg_err_code (err) == GPG_ERR_ASS_NO_OUTPUT)
    {
      /* For compatibility with GPGSM 2.0.0, we fall back to a work
	 around in that case.  */
      if (cert->cert_der)
	{
	  free (cert->cert_der);
	  cert->cert_der = NULL;
	}
      err = export_cert_compat (fpr, cert);
    }
#endif

  if (!err)
    err = scute_agent_is_trusted (fpr, &cert->is_trusted);

  return err;
}
Exemplo n.º 2
0
/* Connect to the Dirmngr and return an assuan context.  */
static gpg_error_t
connect_dirmngr (assuan_context_t *r_ctx)
{
  gpg_error_t err;
  assuan_context_t ctx;

  *r_ctx = NULL;
  err = start_new_dirmngr (&ctx,
                           GPG_ERR_SOURCE_DEFAULT,
                           NULL,
                           opt.autostart, opt.verbose, opt.debug_ipc,
                           NULL, NULL);
  if (!opt.autostart && gpg_err_code (err) == GPG_ERR_NO_DIRMNGR)
    {
      static int shown;

      if (!shown)
        {
          shown = 1;
          log_info (_("no dirmngr running in this session\n"));
        }
    }

  if (err)
    assuan_release (ctx);
  else
    {
      *r_ctx = ctx;
    }

  return err;
}
Exemplo n.º 3
0
static gpgme_error_t
uiserver_cancel (void *engine)
{
  engine_uiserver_t uiserver = engine;

  if (!uiserver)
    return gpg_error (GPG_ERR_INV_VALUE);

  if (uiserver->status_cb.fd != -1)
    _gpgme_io_close (uiserver->status_cb.fd);
  if (uiserver->input_cb.fd != -1)
    _gpgme_io_close (uiserver->input_cb.fd);
  if (uiserver->output_cb.fd != -1)
    _gpgme_io_close (uiserver->output_cb.fd);
  if (uiserver->message_cb.fd != -1)
    _gpgme_io_close (uiserver->message_cb.fd);

  if (uiserver->assuan_ctx)
    {
      assuan_release (uiserver->assuan_ctx);
      uiserver->assuan_ctx = NULL;
    }

  return 0;
}
Exemplo n.º 4
0
static gpgme_error_t
gpgsm_cancel (void *engine)
{
  engine_gpgsm_t gpgsm = engine;

  if (!gpgsm)
    return gpg_error (GPG_ERR_INV_VALUE);

  if (gpgsm->status_cb.fd != -1)
    _gpgme_io_close (gpgsm->status_cb.fd);
  if (gpgsm->input_cb.fd != -1)
    _gpgme_io_close (gpgsm->input_cb.fd);
  if (gpgsm->output_cb.fd != -1)
    _gpgme_io_close (gpgsm->output_cb.fd);
  if (gpgsm->message_cb.fd != -1)
    _gpgme_io_close (gpgsm->message_cb.fd);

  if (gpgsm->assuan_ctx)
    {
      assuan_release (gpgsm->assuan_ctx);
      gpgsm->assuan_ctx = NULL;
    }

  return 0;
}
Exemplo n.º 5
0
/* Reset the SCD if it has been used.  Actually it is not a reset but
   a cleanup of resources used by the current connection. */
int
agent_reset_scd (ctrl_t ctrl)
{
  if (ctrl->scd_local)
    {
      if (ctrl->scd_local->ctx)
        {
          /* We can't disconnect the primary context because libassuan
             does a waitpid on it and thus the system would hang.
             Instead we send a reset and keep that connection for
             reuse. */
          if (ctrl->scd_local->ctx == primary_scd_ctx)
            {
              /* Send a RESTART to the SCD.  This is required for the
                 primary connection as a kind of virtual EOF; we don't
                 have another way to tell it that the next command
                 should be viewed as if a new connection has been
                 made.  For the non-primary connections this is not
                 needed as we simply close the socket.  We don't check
                 for an error here because the RESTART may fail for
                 example if the scdaemon has already been terminated.
                 Anyway, we need to set the reusable flag to make sure
                 that the aliveness check can clean it up. */
              assuan_transact (primary_scd_ctx, "RESTART",
                               NULL, NULL, NULL, NULL, NULL, NULL);
              primary_scd_ctx_reusable = 1;
            }
          else
            assuan_release (ctrl->scd_local->ctx);
          ctrl->scd_local->ctx = NULL;
        }

      /* Remove the local context from our list and release it. */
      if (!scd_local_list)
        BUG ();
      else if (scd_local_list == ctrl->scd_local)
        scd_local_list = ctrl->scd_local->next_local;
      else
        {
          struct scd_local_s *sl;

          for (sl=scd_local_list; sl->next_local; sl = sl->next_local)
            if (sl->next_local == ctrl->scd_local)
              break;
          if (!sl->next_local)
            BUG ();
          sl->next_local = ctrl->scd_local->next_local;
        }
      xfree (ctrl->scd_local);
      ctrl->scd_local = NULL;
    }

  return 0;
}
Exemplo n.º 6
0
void
assuan_sock_deinit ()
{
  if (sock_ctx == NULL)
    return;

#ifdef HAVE_W32_SYSTEM
  WSACleanup ();
#endif

  assuan_release (sock_ctx);
  sock_ctx = NULL;
}
Exemplo n.º 7
0
/* Client main.  If true is returned, a disconnect has not been done. */
static int
client (assuan_context_t ctx, const char *fname)
{
  int rc;
  FILE *fp;
  int i;

  log_info ("client started. Servers's pid is %ld\n",
            (long)assuan_get_pid (ctx));

  for (i=0; i < 6; i++)
    {
      fp = fopen (fname, "r");
      if (!fp)
        {
          log_error ("failed to open `%s': %s\n", fname,
                     strerror (errno));
          return -1;
        }
      
      rc = assuan_sendfd (ctx, fileno (fp));
      if (rc)
        {
          log_error ("assuan_sendfd failed: %s\n", gpg_strerror (rc));
          return -1;
        }
      fclose (fp);

      rc = assuan_transact (ctx, "INPUT FD", NULL, NULL, NULL, NULL,
                            NULL, NULL);
      if (rc)
        {
          log_error ("sending INPUT FD failed: %s\n", gpg_strerror (rc));
          return -1;
        }

      rc = assuan_transact (ctx, "ECHO", NULL, NULL, NULL, NULL, NULL, NULL);
      if (rc)
        {
          log_error ("sending ECHO failed: %s\n", gpg_strerror (rc));
          return -1;
        }
    }

  /* Give us some time to check with lsof that all descriptors are closed. */
/*   sleep (10); */

  assuan_release (ctx);
  return 0;
}
Exemplo n.º 8
0
/* Ask the dirmngr for the policy flags and return them as an estream
 * memory stream.  If no policy flags are set, NULL is stored at
 * R_BUFFER.  */
gpg_error_t
wkd_get_policy_flags (const char *addrspec, estream_t *r_buffer)
{
  gpg_error_t err;
  assuan_context_t ctx;
  struct wkd_get_parm_s parm;
  char *line = NULL;
  char *buffer = NULL;

  memset (&parm, 0, sizeof parm);
  *r_buffer = NULL;

  err = connect_dirmngr (&ctx);
  if (err)
    return err;

  line = es_bsprintf ("WKD_GET --policy-flags -- %s", addrspec);
  if (!line)
    {
      err = gpg_error_from_syserror ();
      goto leave;
    }
  if (strlen (line) + 2 >= ASSUAN_LINELENGTH)
    {
      err = gpg_error (GPG_ERR_TOO_LARGE);
      goto leave;
    }

  parm.memfp = es_fopenmem (0, "rwb");
  if (!parm.memfp)
    {
      err = gpg_error_from_syserror ();
      goto leave;
    }
  err = assuan_transact (ctx, line, wkd_get_data_cb, &parm,
                         NULL, NULL, wkd_get_status_cb, &parm);
  if (err)
    goto leave;

  es_rewind (parm.memfp);
  *r_buffer = parm.memfp;
  parm.memfp = 0;

 leave:
  es_free (buffer);
  es_fclose (parm.memfp);
  xfree (line);
  assuan_release (ctx);
  return err;
}
Exemplo n.º 9
0
/* Invoke SEARCH_CB for each certificate found using assuan connection
   CTX to GPGSM.  */
gpg_error_t
scute_gpgsm_search_certs_by_fpr (const char *fpr,
				 cert_search_cb_t search_cb,
				 void *search_cb_hook)
{
  gpg_error_t err;
  assuan_context_t ctx;
  const char *argv[] = { "gpgsm", "--server", NULL };
  struct search_ctx_by_field search;

  err = assuan_new (&ctx);
  if (err)
    {
      DEBUG (DBG_CRIT, "failed to allocate assuan context: %s",
	     gpg_strerror (err));
      return err;
    }

  err = assuan_pipe_connect (ctx, get_gpgsm_path (), argv, NULL,
			     NULL, NULL, 128);
  if (err)
    {
      assuan_release (ctx);
      DEBUG (DBG_CRIT, "failed to spawn %s\n", get_gpgsm_path ());
      return err;
    }

  search.field = SEARCH_BY_FPR;
  search.pattern = fpr;
  search.search_cb = search_cb;
  search.search_cb_hook = search_cb_hook;

  err = scute_gpgsm_search_certs (ctx, &search_certs_by_field, &search);
  assuan_release (ctx);
  return err;
}
Exemplo n.º 10
0
/* Unlock the pinentry so that another thread can start one and
   disconnect that pinentry - we do this after the unlock so that a
   stalled pinentry does not block other threads.  Fixme: We should
   have a timeout in Assuan for the disconnect operation. */
static int 
unlock_pinentry (int rc)
{
  assuan_context_t ctx = entry_ctx;

  entry_ctx = NULL;
  if (!pth_mutex_release (&entry_lock))
    {
      log_error ("failed to release the entry lock\n");
      if (!rc)
        rc = gpg_error (GPG_ERR_INTERNAL);
    }
  assuan_release (ctx);
  return rc;
}
Exemplo n.º 11
0
/* Unlock the pinentry so that another thread can start one and
   disconnect that pinentry - we do this after the unlock so that a
   stalled pinentry does not block other threads.  Fixme: We should
   have a timeout in Assuan for the disconnect operation. */
static int
unlock_pinentry (int rc)
{
  assuan_context_t ctx = entry_ctx;
  int err;

  entry_ctx = NULL;
  err = npth_mutex_unlock (&entry_lock);
  if (err)
    {
      log_error ("failed to release the entry lock: %s\n", strerror (err));
      if (!rc)
        rc = gpg_error_from_errno (err);
    }
  assuan_release (ctx);
  return rc;
}
Exemplo n.º 12
0
static gpgme_error_t
g13_cancel (void *engine)
{
  engine_g13_t g13 = engine;

  if (!g13)
    return gpg_error (GPG_ERR_INV_VALUE);

  if (g13->status_cb.fd != -1)
    _gpgme_io_close (g13->status_cb.fd);

  if (g13->assuan_ctx)
    {
      assuan_release (g13->assuan_ctx);
      g13->assuan_ctx = NULL;
    }

  return 0;
}
Exemplo n.º 13
0
static void
server (void)
{
  int rc;
  assuan_context_t ctx;

  log_info ("server started\n");

  rc = assuan_new (&ctx);
  if (rc)
    log_fatal ("assuan_new failed: %s\n", gpg_strerror (rc));

  rc = assuan_init_pipe_server (ctx, NULL);
  if (rc)
    log_fatal ("assuan_init_pipe_server failed: %s\n", gpg_strerror (rc));

  rc = register_commands (ctx);
  if (rc)
    log_fatal ("register_commands failed: %s\n", gpg_strerror(rc));

  assuan_set_log_stream (ctx, stderr);

  for (;;) 
    {
      rc = assuan_accept (ctx);
      if (rc)
        {
          if (rc != -1)
            log_error ("assuan_accept failed: %s\n", gpg_strerror (rc));
          break;
        }
      
      log_info ("client connected.  Client's pid is %ld\n",
                (long)assuan_get_pid (ctx));

      rc = assuan_process (ctx);
      if (rc)
        log_error ("assuan_process failed: %s\n", gpg_strerror (rc));
    }
  
  assuan_release (ctx);
}
Exemplo n.º 14
0
/* 
 
     M A I N

*/
int 
main (int argc, char **argv)
{
  int last_argc = -1;
  assuan_context_t ctx;
  gpg_error_t err;
  int no_close_fds[2];
  const char *arglist[10];
  int is_server = 0;
  int with_exec = 0;
  char *fname = prepend_srcdir ("motd");

  if (argc)
    {
      log_set_prefix (*argv);
      argc--; argv++;
    }
  while (argc && last_argc != argc )
    {
      last_argc = argc;
      if (!strcmp (*argv, "--help"))
        {
          puts (
"usage: ./fdpassing [options]\n"
"\n"
"Options:\n"
"  --verbose      Show what is going on\n"
"  --with-exec    Exec the child.  Default is just a fork\n"
);
          exit (0);
        }
      if (!strcmp (*argv, "--verbose"))
        {
          verbose = 1;
          argc--; argv++;
        }
      else if (!strcmp (*argv, "--debug"))
        {
          verbose = debug = 1;
          argc--; argv++;
        }
      else if (!strcmp (*argv, "--server"))
        {
          is_server = 1;
          argc--; argv++;
        }
      else if (!strcmp (*argv, "--with-exec"))
        {
          with_exec = 1;
          argc--; argv++;
        }
    }


  assuan_set_assuan_log_prefix (log_prefix);

  if (is_server)
    {
      server ();
      log_info ("server finished\n");
    }
  else
    {
      const char *loc;

      no_close_fds[0] = 2;
      no_close_fds[1] = -1;
      if (with_exec)
        {
          arglist[0] = "fdpassing";
          arglist[1] = "--server";
          arglist[2] = verbose? "--verbose":NULL;
          arglist[3] = NULL;
        }

      err = assuan_new (&ctx);
      if (err)
	log_fatal ("assuan_new failed: %s\n", gpg_strerror (err));

      err = assuan_pipe_connect (ctx, with_exec? "./fdpassing":NULL,
				 with_exec ? arglist : &loc,
				 no_close_fds, NULL, NULL, 1);
      if (err)
        {
          log_error ("assuan_pipe_connect failed: %s\n", gpg_strerror (err));
          return 1;
        }
      
      if (!with_exec && loc[0] == 's')
        {
          server ();
          log_info ("server finished\n");
        }
      else
        {
          if (client (ctx, fname)) 
            {
              log_info ("waiting for server to terminate...\n");
              assuan_release (ctx);
            }
          log_info ("client finished\n");
        }
    }

  return errorcount ? 1 : 0;
}
Exemplo n.º 15
0
Pin::~Pin()
{
  assuan_release(ctx);
}
Exemplo n.º 16
0
/* Fire up a new GPG.  Handle the server's initial greeting.  Returns
   0 on success and stores the assuan context at R_CTX.  */
static gpg_error_t
start_gpg (ctrl_t ctrl, const char *gpg_program, strlist_t gpg_arguments,
           int input_fd, int output_fd, assuan_context_t *r_ctx)
{
  gpg_error_t err;
  assuan_context_t ctx = NULL;
  const char *pgmname;
  const char **argv;
  assuan_fd_t no_close_list[5];
  int i;
  char line[ASSUAN_LINELENGTH];

  (void)ctrl;

  *r_ctx = NULL;

  err = assuan_new (&ctx);
  if (err)
    {
      log_error ("can't allocate assuan context: %s\n", gpg_strerror (err));
      return err;
    }

  /* The first time we are used, intialize the gpg_program variable.  */
  if ( !gpg_program || !*gpg_program )
    gpg_program = gnupg_module_name (GNUPG_MODULE_NAME_GPG);

  /* Compute argv[0].  */
  if ( !(pgmname = strrchr (gpg_program, '/')))
    pgmname = gpg_program;
  else
    pgmname++;

  if (fflush (NULL))
    {
      err = my_error_from_syserror ();
      log_error ("error flushing pending output: %s\n", gpg_strerror (err));
      return err;
    }

  argv = xtrycalloc (strlist_length (gpg_arguments) + 3, sizeof *argv);
  if (argv == NULL)
    {
      err = my_error_from_syserror ();
      return err;
    }
  i = 0;
  argv[i++] = pgmname;
  argv[i++] = "--server";
  for (; gpg_arguments; gpg_arguments = gpg_arguments->next)
    argv[i++] = gpg_arguments->d;
  argv[i++] = 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 (fileno (stderr));
  if (input_fd != -1)
    no_close_list[i++] = assuan_fd_from_posix_fd (input_fd);
  if (output_fd != -1)
    no_close_list[i++] = assuan_fd_from_posix_fd (output_fd);
  no_close_list[i] = ASSUAN_INVALID_FD;

  /* Connect to GPG and perform initial handshaking.  */
  err = assuan_pipe_connect (ctx, gpg_program, argv, no_close_list,
			     NULL, NULL, 0);
  if (err)
    {
      assuan_release (ctx);
      log_error ("can't connect to GPG: %s\n", gpg_strerror (err));
      return gpg_error (GPG_ERR_NO_ENGINE);
    }

  if (input_fd != -1)
    {
      snprintf (line, sizeof line, "INPUT FD=%d", input_fd);
      err = assuan_transact (ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
      if (err)
        {
          assuan_release (ctx);
          log_error ("error sending INPUT command: %s\n", gpg_strerror (err));
          return err;
        }
    }

  if (output_fd != -1)
    {
      snprintf (line, sizeof line, "OUTPUT FD=%d", output_fd);
      err = assuan_transact (ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
      if (err)
        {
          assuan_release (ctx);
          log_error ("error sending OUTPUT command: %s\n", gpg_strerror (err));
          return err;
        }
    }

  *r_ctx = ctx;
  return 0;
}
Exemplo n.º 17
0
/* Fork off the pin entry if this has not already been done.  Note,
   that this function must always be used to aquire the lock for the
   pinentry - we will serialize _all_ pinentry calls.
 */
static int
start_pinentry (ctrl_t ctrl)
{
  int rc = 0;
  const char *pgmname;
  assuan_context_t ctx;
  const char *argv[5];
  int no_close_list[3];
  int i;
  const char *tmpstr;
  unsigned long pinentry_pid;
  const char *value;
  struct timespec abstime;
  int err;

  npth_clock_gettime (&abstime);
  abstime.tv_sec += LOCK_TIMEOUT;
  err = npth_mutex_timedlock (&entry_lock, &abstime);
  if (err)
    {
      if (err == ETIMEDOUT)
	rc = gpg_error (GPG_ERR_TIMEOUT);
      else
	rc = gpg_error_from_errno (rc);
      log_error (_("failed to acquire the pinentry lock: %s\n"),
                 gpg_strerror (rc));
      return rc;
    }

  entry_owner = ctrl;

  if (entry_ctx)
    return 0;

  if (opt.verbose)
    log_info ("starting a new PIN Entry\n");

#ifdef HAVE_W32_SYSTEM
  fflush (stdout);
  fflush (stderr);
#endif
  if (fflush (NULL))
    {
#ifndef HAVE_W32_SYSTEM
      gpg_error_t tmperr = gpg_error (gpg_err_code_from_errno (errno));
#endif
      log_error ("error flushing pending output: %s\n", strerror (errno));
      /* At least Windows XP fails here with EBADF.  According to docs
         and Wine an fflush(NULL) is the same as _flushall.  However
         the Wime implementaion does not flush stdin,stdout and stderr
         - see above.  Lets try to ignore the error. */
#ifndef HAVE_W32_SYSTEM
      return unlock_pinentry (tmperr);
#endif
    }

  if (!opt.pinentry_program || !*opt.pinentry_program)
    opt.pinentry_program = gnupg_module_name (GNUPG_MODULE_NAME_PINENTRY);
  pgmname = opt.pinentry_program;
  if ( !(pgmname = strrchr (opt.pinentry_program, '/')))
    pgmname = opt.pinentry_program;
  else
    pgmname++;

  /* OS X needs the entire file name in argv[0], so that it can locate
     the resource bundle.  For other systems we stick to the usual
     convention of supplying only the name of the program.  */
#ifdef __APPLE__
  argv[0] = opt.pinentry_program;
#else /*!__APPLE__*/
  argv[0] = pgmname;
#endif /*__APPLE__*/

  if (!opt.keep_display
      && (value = session_env_getenv (ctrl->session_env, "DISPLAY")))
    {
      argv[1] = "--display";
      argv[2] = value;
      argv[3] = NULL;
    }
  else
    argv[1] = NULL;

  i=0;
  if (!opt.running_detached)
    {
      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 (fileno (stderr));
    }
  no_close_list[i] = -1;

  rc = assuan_new (&ctx);
  if (rc)
    {
      log_error ("can't allocate assuan context: %s\n", gpg_strerror (rc));
      return rc;
    }
  /* We don't want to log the pinentry communication to make the logs
     easier to read.  We might want to add a new debug option to enable
     pinentry logging.  */
#ifdef ASSUAN_NO_LOGGING
  assuan_set_flag (ctx, ASSUAN_NO_LOGGING, 1);
#endif

  /* Connect to the pinentry and perform initial handshaking.  Note
     that atfork is used to change the environment for pinentry.  We
     start the server in detached mode to suppress the console window
     under Windows.  */
  rc = assuan_pipe_connect (ctx, opt.pinentry_program, argv,
			    no_close_list, atfork_cb, ctrl,
			    ASSUAN_PIPE_CONNECT_DETACHED);
  if (rc)
    {
      log_error ("can't connect to the PIN entry module '%s': %s\n",
                 opt.pinentry_program, gpg_strerror (rc));
      assuan_release (ctx);
      return unlock_pinentry (gpg_error (GPG_ERR_NO_PIN_ENTRY));
    }
  entry_ctx = ctx;

  if (DBG_ASSUAN)
    log_debug ("connection to PIN entry established\n");

  rc = assuan_transact (entry_ctx,
                        opt.no_grab? "OPTION no-grab":"OPTION grab",
                        NULL, NULL, NULL, NULL, NULL, NULL);
  if (rc)
    return unlock_pinentry (rc);

  value = session_env_getenv (ctrl->session_env, "GPG_TTY");
  if (value)
    {
      char *optstr;
      if (asprintf (&optstr, "OPTION ttyname=%s", value) < 0 )
	return unlock_pinentry (out_of_core ());
      rc = assuan_transact (entry_ctx, optstr, NULL, NULL, NULL, NULL, NULL,
			    NULL);
      xfree (optstr);
      if (rc)
	return unlock_pinentry (rc);
    }
  value = session_env_getenv (ctrl->session_env, "TERM");
  if (value)
    {
      char *optstr;
      if (asprintf (&optstr, "OPTION ttytype=%s", value) < 0 )
	return unlock_pinentry (out_of_core ());
      rc = assuan_transact (entry_ctx, optstr, NULL, NULL, NULL, NULL, NULL,
			    NULL);
      xfree (optstr);
      if (rc)
	return unlock_pinentry (rc);
    }
  if (ctrl->lc_ctype)
    {
      char *optstr;
      if (asprintf (&optstr, "OPTION lc-ctype=%s", ctrl->lc_ctype) < 0 )
	return unlock_pinentry (out_of_core ());
      rc = assuan_transact (entry_ctx, optstr, NULL, NULL, NULL, NULL, NULL,
			    NULL);
      xfree (optstr);
      if (rc)
	return unlock_pinentry (rc);
    }
  if (ctrl->lc_messages)
    {
      char *optstr;
      if (asprintf (&optstr, "OPTION lc-messages=%s", ctrl->lc_messages) < 0 )
	return unlock_pinentry (out_of_core ());
      rc = assuan_transact (entry_ctx, optstr, NULL, NULL, NULL, NULL, NULL,
			    NULL);
      xfree (optstr);
      if (rc)
	return unlock_pinentry (rc);
    }

  {
    /* Provide a few default strings for use by the pinentries.  This
       may help a pinentry to avoid implementing localization code.  */
    static struct { const char *key, *value; } tbl[] = {
      /* TRANSLATORS: These are labels for buttons etc used in
         Pinentries.  An underscore indicates that the next letter
         should be used as an accelerator.  Double the underscore for
         a literal one.  The actual to be translated text starts after
         the second vertical bar.  */
      { "ok",     N_("|pinentry-label|_OK") },
      { "cancel", N_("|pinentry-label|_Cancel") },
      { "prompt", N_("|pinentry-label|PIN:") },
      { NULL, NULL}
    };
    char *optstr;
    int idx;
    const char *s, *s2;

    for (idx=0; tbl[idx].key; idx++)
      {
        s = _(tbl[idx].value);
        if (*s == '|' && (s2=strchr (s+1,'|')))
          s = s2+1;
        if (asprintf (&optstr, "OPTION default-%s=%s", tbl[idx].key, s) < 0 )
          return unlock_pinentry (out_of_core ());
        assuan_transact (entry_ctx, optstr, NULL, NULL, NULL, NULL, NULL,
                         NULL);
        xfree (optstr);
      }
  }


  /* Tell the pinentry the name of a file it shall touch after having
     messed with the tty.  This is optional and only supported by
     newer pinentries and thus we do no error checking. */
  tmpstr = opt.pinentry_touch_file;
  if (tmpstr && !strcmp (tmpstr, "/dev/null"))
    tmpstr = NULL;
  else if (!tmpstr)
    tmpstr = get_agent_socket_name ();
  if (tmpstr)
    {
      char *optstr;

      if (asprintf (&optstr, "OPTION touch-file=%s", tmpstr ) < 0 )
        ;
      else
        {
          assuan_transact (entry_ctx, optstr, NULL, NULL, NULL, NULL, NULL,
                           NULL);
          xfree (optstr);
        }
    }


  /* Now ask the Pinentry for its PID.  If the Pinentry is new enough
     it will send the pid back and we will use an inquire to notify
     our client.  The client may answer the inquiry either with END or
     with CAN to cancel the pinentry. */
  rc = assuan_transact (entry_ctx, "GETINFO pid",
                        getinfo_pid_cb, &pinentry_pid,
                        NULL, NULL, NULL, NULL);
  if (rc)
    {
      log_info ("You may want to update to a newer pinentry\n");
      rc = 0;
    }
  else if (!rc && (pid_t)pinentry_pid == (pid_t)(-1))
    log_error ("pinentry did not return a PID\n");
  else
    {
      rc = agent_inq_pinentry_launched (ctrl, pinentry_pid);
      if (gpg_err_code (rc) == GPG_ERR_CANCELED
          || gpg_err_code (rc) == GPG_ERR_FULLY_CANCELED)
        return unlock_pinentry (gpg_err_make (GPG_ERR_SOURCE_DEFAULT,
                                              gpg_err_code (rc)));
      rc = 0;
    }

  return 0;
}
Exemplo n.º 18
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");
  if (only_daemon && (!infostr || !*infostr))
    {
      infostr = xstrdup (dirmngr_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];
      int 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] = -1;

      /* 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 DIRMNGR_INFO environment variable\n"));
              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;
}
Exemplo n.º 19
0
/* Release the assuan context created by start_gpg.  */
static void
release_gpg (assuan_context_t ctx)
{
  assuan_release (ctx);
}
Exemplo n.º 20
0
int ask_user_consent(sc_card_t *card) {
    int res;
    struct stat buf;
    const char *argv[3];
    assuan_fd_t noclosefds[2];
    assuan_context_t ctx; 
    if ( (card==NULL) || (card->ctx==NULL)) return SC_ERROR_INVALID_ARGUMENTS;
    get_user_consent_env(card->ctx);
    res=stat(user_consent_app,&buf);
    if (res!=0) {
      /* TODO: check that pinentry file is executable */
      sc_debug(card->ctx,SC_LOG_DEBUG_NORMAL,"Invalid pinentry application: %s\n",user_consent_app);
      SC_FUNC_RETURN(card->ctx,SC_LOG_DEBUG_NORMAL,SC_ERROR_INVALID_ARGUMENTS);
    }
    argv[0]=user_consent_app;
    argv[1]=NULL;
    argv[2]=NULL;
    noclosefds[0]= fileno(stderr);
    noclosefds[1]= ASSUAN_INVALID_FD;
#ifdef HAVE_ASSUAN_2
    res = assuan_new(&ctx);
    if (res!=0) {
      sc_debug(card->ctx,SC_LOG_DEBUG_NORMAL,"Can't create the User Consent environment: %s\n",_gpg_error(res));
      SC_FUNC_RETURN(card->ctx,SC_LOG_DEBUG_NORMAL,SC_ERROR_INVALID_ARGUMENTS);
    }
    res = assuan_pipe_connect(ctx,user_consent_app,argv,noclosefds,NULL,NULL,0);
#else 
    res = assuan_pipe_connect(&ctx,user_consent_app,argv,0);
#endif
    if (res!=0) {
        sc_debug(card->ctx,SC_LOG_DEBUG_NORMAL,"Can't connect to the User Consent module: %s\n",_gpg_error(res));
        res=SC_ERROR_INVALID_ARGUMENTS; /* invalid or not available pinentry */
        goto exit;
    }
    res = assuan_transact(
       ctx, 
       "SETDESC Está a punto de realizar una firma electrónica con su clave de FIRMA del DNI electrónico.¿Desea permitir esta operación?", 
       NULL, NULL, NULL, NULL, NULL, NULL);
    if (res!=0) {
       sc_debug(card->ctx,SC_LOG_DEBUG_NORMAL,"SETDESC: %s\n", _gpg_error(res));
       res=SC_ERROR_CARD_CMD_FAILED; /* perhaps should use a better errcode */
       goto exit;
    }
    res = assuan_transact(ctx,"CONFIRM",NULL,NULL,NULL,NULL,NULL,NULL);
#ifdef HAVE_ASSUAN_1
    if (res == ASSUAN_Canceled) {
       sc_debug(card->ctx,SC_LOG_DEBUG_VERBOSE,"Sign cancelled by user");
       res= SC_ERROR_NOT_ALLOWED;
       goto exit;
    }
#endif
    if (res) {
       sc_debug(card->ctx,SC_LOG_DEBUG_NORMAL,"SETERROR: %s\n",_gpg_error(res));
       res=SC_ERROR_SECURITY_STATUS_NOT_SATISFIED;
     } else {
       res=SC_SUCCESS;
     }
exit:
#ifdef HAVE_ASSUAN_2
    assuan_release(ctx);
#else
    assuan_disconnect(ctx);
#endif
    SC_FUNC_RETURN(card->ctx,SC_LOG_DEBUG_NORMAL,res);
}
Exemplo n.º 21
0
int
main (int argc, char **argv )
{
  ARGPARSE_ARGS pargs;
  assuan_context_t ctx;
  gpg_error_t err;
  unsigned char *certbuf;
  size_t certbuflen = 0;
  int cmd_ping = 0;
  int cmd_cache_cert = 0;
  int cmd_validate = 0;
  int cmd_lookup = 0;
  int cmd_loadcrl = 0;
  int cmd_squid_mode = 0;

  set_strusage (my_strusage);
  log_set_prefix ("dirmngr-client",
                  JNLIB_LOG_WITH_PREFIX);

  /* For W32 we need to initialize the socket subsystem.  Becuase we
     don't use Pth we need to do this explicit. */
#ifdef HAVE_W32_SYSTEM
 {
   WSADATA wsadat;

   WSAStartup (0x202, &wsadat);
 }
#endif /*HAVE_W32_SYSTEM*/

  /* Init Assuan.  */
  assuan_set_assuan_log_prefix (log_get_prefix (NULL));
  assuan_set_gpg_err_source (GPG_ERR_SOURCE_DEFAULT);

  /* Setup I18N. */
  i18n_init();

  /* Parse the command line.  */
  pargs.argc = &argc;
  pargs.argv = &argv;
  pargs.flags= 1;  /* Do not remove the args. */
  while (arg_parse (&pargs, opts) )
    {
      switch (pargs.r_opt)
        {
        case oVerbose: opt.verbose++; break;
        case oQuiet: opt.quiet++; break;

        case oOCSP: opt.use_ocsp++; break;
        case oPing: cmd_ping = 1; break;
        case oCacheCert: cmd_cache_cert = 1; break;
        case oValidate: cmd_validate = 1; break;
        case oLookup: cmd_lookup = 1; break;
        case oUrl: opt.url = 1; break;
        case oLocal: opt.local = 1; break;
        case oLoadCRL: cmd_loadcrl = 1; break;
        case oPEM: opt.pem = 1; break;
        case oSquidMode:
          opt.pem = 1;
          opt.escaped_pem = 1;
          cmd_squid_mode = 1;
          break;
        case oForceDefaultResponder: opt.force_default_responder = 1; break;

        default : pargs.err = 2; break;
	}
    }
  if (log_get_errorcount (0))
    exit (2);

  /* Build the helptable for radix64 to bin conversion. */
  if (opt.pem)
    {
      int i;
      unsigned char *s;

      for (i=0; i < 256; i++ )
        asctobin[i] = 255; /* Used to detect invalid characters. */
      for (s=bintoasc, i=0; *s; s++, i++)
        asctobin[*s] = i;
    }


  if (cmd_ping)
    err = 0;
  else if (cmd_lookup || cmd_loadcrl)
    {
      if (!argc)
        usage (1);
      err = 0;
    }
  else if (cmd_squid_mode)
    {
      err = 0;
      if (argc)
        usage (1);
    }
  else if (!argc)
    {
      err = read_certificate (NULL, &certbuf, &certbuflen);
      if (err)
        log_error (_("error reading certificate from stdin: %s\n"),
                   gpg_strerror (err));
    }
  else if (argc == 1)
    {
      err = read_certificate (*argv, &certbuf, &certbuflen);
      if (err)
        log_error (_("error reading certificate from '%s': %s\n"),
                   *argv, gpg_strerror (err));
    }
  else
    {
      err = 0;
      usage (1);
    }

  if (log_get_errorcount (0))
    exit (2);

  if (certbuflen > 20000)
    {
      log_error (_("certificate too large to make any sense\n"));
      exit (2);
    }

  ctx = start_dirmngr (1);
  if (!ctx)
    exit (2);

  if (cmd_ping)
    ;
  else if (cmd_squid_mode)
    {
      while (!(err = squid_loop_body (ctx)))
        ;
      if (gpg_err_code (err) == GPG_ERR_EOF)
        err = 0;
    }
  else if (cmd_lookup)
    {
      int last_err = 0;

      for (; argc; argc--, argv++)
        {
          err = do_lookup (ctx, *argv);
          if (err)
            {
              log_error (_("lookup failed: %s\n"), gpg_strerror (err));
              last_err = err;
            }
        }
      err = last_err;
    }
  else if (cmd_loadcrl)
    {
      int last_err = 0;

      for (; argc; argc--, argv++)
        {
          err = do_loadcrl (ctx, *argv);
          if (err)
            {
              log_error (_("loading CRL '%s' failed: %s\n"),
                         *argv, gpg_strerror (err));
              last_err = err;
            }
        }
      err = last_err;
    }
  else if (cmd_cache_cert)
    {
      err = do_cache (ctx, certbuf, certbuflen);
      xfree (certbuf);
    }
  else if (cmd_validate)
    {
      err = do_validate (ctx, certbuf, certbuflen);
      xfree (certbuf);
    }
  else
    {
      err = do_check (ctx, certbuf, certbuflen);
      xfree (certbuf);
    }

  assuan_release (ctx);

  if (cmd_ping)
    {
      if (!opt.quiet)
        log_info (_("a dirmngr daemon is up and running\n"));
      return 0;
    }
  else if (cmd_lookup|| cmd_loadcrl || cmd_squid_mode)
    return err? 1:0;
  else if (cmd_cache_cert)
    {
      if (err && gpg_err_code (err) == GPG_ERR_DUP_VALUE )
        {
          if (!opt.quiet)
            log_info (_("certificate already cached\n"));
        }
      else if (err)
        {
          log_error (_("error caching certificate: %s\n"),
                     gpg_strerror (err));
          return 1;
        }
      return 0;
    }
  else if (cmd_validate && err)
    {
      log_error (_("validation of certificate failed: %s\n"),
                 gpg_strerror (err));
      return 1;
    }
  else if (!err)
    {
      if (!opt.quiet)
        log_info (_("certificate is valid\n"));
      return 0;
    }
  else if (gpg_err_code (err) == GPG_ERR_CERT_REVOKED )
    {
      if (!opt.quiet)
        log_info (_("certificate has been revoked\n"));
      return 1;
    }
  else
    {
      log_error (_("certificate check failed: %s\n"), gpg_strerror (err));
      return 2;
    }
}
Exemplo n.º 22
0
/* Try to connect to the dirmngr via a socket.  On platforms
   supporting it, start it up if needed.  Returns a new assuan context
   at R_CTX or an error code. */
gpg_error_t
start_new_dirmngr (assuan_context_t *r_ctx,
                   gpg_err_source_t errsource,
                   const char *homedir,
                   const char *dirmngr_program,
                   int verbose, int debug,
                   gpg_error_t (*status_cb)(ctrl_t, int, ...),
                   ctrl_t status_cb_arg)
{
  gpg_error_t err;
  assuan_context_t ctx;
  const char *sockname;
  int did_success_msg = 0;

  *r_ctx = NULL;

  err = assuan_new (&ctx);
  if (err)
    {
      log_error ("error allocating assuan context: %s\n", gpg_strerror (err));
      return err;
    }

  sockname = dirmngr_socket_name ();
  err = assuan_socket_connect (ctx, sockname, 0, 0);
#ifdef USE_DIRMNGR_AUTO_START
  if (err)
    {
      lock_spawn_t lock;
      const char *argv[2];

      /* With no success try start a new Dirmngr.  On most systems
         this will fail because the Dirmngr is expected to be a system
         service.  However on Wince we don't distinguish users and
         thus we can start it.  A future extension might be to use the
         userv system to start the Dirmngr as a system service.  */
      if (!dirmngr_program || !*dirmngr_program)
        dirmngr_program = gnupg_module_name (GNUPG_MODULE_NAME_DIRMNGR);

      if (verbose)
        log_info (_("no running Dirmngr - starting '%s'\n"),
                  dirmngr_program);

      if (status_cb)
        status_cb (status_cb_arg, STATUS_PROGRESS,
                   "starting_dirmngr ? 0 0", NULL);

      if (fflush (NULL))
        {
          gpg_error_t tmperr = gpg_err_make (errsource,
                                             gpg_err_code_from_syserror ());
          log_error ("error flushing pending output: %s\n",
                     strerror (errno));
          assuan_release (ctx);
          return tmperr;
        }

      argv[0] = "--daemon";
      argv[1] = NULL;

      if (!(err = lock_spawning (&lock, homedir, "dirmngr", verbose))
          && assuan_socket_connect (ctx, sockname, 0, 0))
        {
          err = gnupg_spawn_process_detached (dirmngr_program, argv,NULL);
          if (err)
            log_error ("failed to start the dirmngr '%s': %s\n",
                       dirmngr_program, gpg_strerror (err));
          else
            {
              int i;

              for (i=0; i < SECS_TO_WAIT_FOR_DIRMNGR; i++)
                {
                  if (verbose)
                    log_info (_("waiting for the dirmngr "
                                "to come up ... (%ds)\n"),
                              SECS_TO_WAIT_FOR_DIRMNGR - i);
                  gnupg_sleep (1);
                  err = assuan_socket_connect (ctx, sockname, 0, 0);
                  if (!err)
                    {
                      if (verbose)
                        {
                          log_info (_("connection to the dirmngr"
                                      " established\n"));
                          did_success_msg = 1;
                        }
                      break;
                    }
                }
            }
        }

      unlock_spawning (&lock, "dirmngr");
    }
#else
  (void)homedir;
  (void)dirmngr_program;
  (void)verbose;
  (void)status_cb;
  (void)status_cb_arg;
#endif /*USE_DIRMNGR_AUTO_START*/

  if (err)
    {
      log_error ("connecting dirmngr at '%s' failed: %s\n",
                 sockname, gpg_strerror (err));
      assuan_release (ctx);
      return gpg_err_make (errsource, GPG_ERR_NO_DIRMNGR);
    }

  if (debug && !did_success_msg)
    log_debug (_("connection to the dirmngr established\n"));

  *r_ctx = ctx;
  return 0;
}
Exemplo n.º 23
0
/* Try to connect to the agent via socket or fork it off and work by
   pipes.  Handle the server's initial greeting */
static int
start_dirmngr_ext (ctrl_t ctrl, assuan_context_t *ctx_r)
{
  int rc;
  char *infostr, *p;
  assuan_context_t ctx = NULL;
  int try_default = 0;

  if (opt.disable_dirmngr)
    return gpg_error (GPG_ERR_NO_DIRMNGR);

  if (*ctx_r)
    return 0;

  /* Note: if you change this to multiple connections, you also need
     to take care of the implicit option sending caching. */

#ifdef HAVE_W32_SYSTEM
  infostr = NULL;
  opt.prefer_system_dirmngr = 1;
#else
  infostr = force_pipe_server? NULL : getenv ("DIRMNGR_INFO");
#endif /*HAVE_W32_SYSTEM*/
  if (infostr && !*infostr)
    infostr = NULL;
  else if (infostr)
    infostr = xstrdup (infostr);

  if (opt.prefer_system_dirmngr && !force_pipe_server && !infostr)
    {
      infostr = xstrdup (dirmngr_socket_name ());
      try_default = 1;
    }

  rc = assuan_new (&ctx);
  if (rc)
    {
      log_error ("can't allocate assuan context: %s\n", gpg_strerror (rc));
      return rc;
    }

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

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

      if (opt.verbose)
        log_info (_("no running dirmngr - starting `%s'\n"),
                  opt.dirmngr_program);
      
      if (fflush (NULL))
        {
          gpg_error_t tmperr = gpg_error (gpg_err_code_from_errno (errno));
          log_error ("error flushing pending output: %s\n", strerror (errno));
          return tmperr;
        }

      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 (fileno (stderr));
      no_close_list[i] = -1;

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

      if (!try_default)
        {
          if ( !(p = strchr (infostr, PATHSEP_C)) || p == infostr)
            {
              log_error (_("malformed DIRMNGR_INFO environment variable\n"));
              xfree (infostr);
              force_pipe_server = 1;
              return start_dirmngr_ext (ctrl, ctx_r);
            }
          *p++ = 0;
          pid = atoi (p);
          while (*p && *p != PATHSEP_C)
            p++;
          prot = *p? atoi (p+1) : 0;
          if (prot != 1)
            {
              log_error (_("dirmngr protocol version %d is not supported\n"),
                         prot);
              xfree (infostr);
              force_pipe_server = 1;
              return start_dirmngr_ext (ctrl, ctx_r);
            }
        }
      else
        pid = -1;

      rc = assuan_socket_connect (ctx, infostr, pid, 0);
#ifdef HAVE_W32_SYSTEM
      if (rc)
        log_debug ("connecting dirmngr at `%s' failed\n", infostr);
#endif

      xfree (infostr);
#ifndef HAVE_W32_SYSTEM
      if (gpg_err_code (rc) == GPG_ERR_ASS_CONNECT_FAILED)
        {
          log_info (_("can't connect to the dirmngr - trying fall back\n"));
          force_pipe_server = 1;
          return start_dirmngr_ext (ctrl, ctx_r);
        }
#endif /*!HAVE_W32_SYSTEM*/
    }

  prepare_dirmngr (ctrl, ctx, rc);

  if (rc)
    {
      assuan_release (ctx);
      log_error ("can't connect to the dirmngr: %s\n", gpg_strerror (rc));
      return gpg_error (GPG_ERR_NO_DIRMNGR);
    }
  *ctx_r = ctx;

  if (DBG_ASSUAN)
    log_debug ("connection to dirmngr established\n");
  return 0;
}
Pinentry::~Pinentry() {
  assuan_release(_pinentry);
}
Exemplo n.º 25
0
/* Startup the server. DEFAULT_RECPLIST is the list of recipients as
   set from the command line or config file.  We only require those
   marked as encrypt-to. */
void
gpgsm_server (certlist_t default_recplist)
{
  int rc;
  assuan_fd_t filedes[2];
  assuan_context_t ctx;
  struct server_control_s ctrl;
  static const char hello[] = ("GNU Privacy Guard's S/M server "
                               VERSION " ready");

  memset (&ctrl, 0, sizeof ctrl);
  gpgsm_init_default_ctrl (&ctrl);

  /* We use a pipe based server so that we can work from scripts.
     assuan_init_pipe_server will automagically detect when we are
     called with a socketpair and ignore FILEDES in this case. */
#ifdef HAVE_W32CE_SYSTEM
  #define SERVER_STDIN es_fileno(es_stdin)
  #define SERVER_STDOUT es_fileno(es_stdout)
#else
#define SERVER_STDIN 0
#define SERVER_STDOUT 1
#endif
  filedes[0] = assuan_fdopen (SERVER_STDIN);
  filedes[1] = assuan_fdopen (SERVER_STDOUT);
  rc = assuan_new (&ctx);
  if (rc)
    {
      log_error ("failed to allocate assuan context: %s\n",
                 gpg_strerror (rc));
      gpgsm_exit (2);
    }

  rc = assuan_init_pipe_server (ctx, filedes);
  if (rc)
    {
      log_error ("failed to initialize the server: %s\n",
                 gpg_strerror (rc));
      gpgsm_exit (2);
    }
  rc = register_commands (ctx);
  if (rc)
    {
      log_error ("failed to the register commands with Assuan: %s\n",
                 gpg_strerror(rc));
      gpgsm_exit (2);
    }
  if (opt.verbose || opt.debug)
    {
      char *tmp = NULL;
      const char *s1 = getenv ("GPG_AGENT_INFO");

      if (asprintf (&tmp,
                    "Home: %s\n"
                    "Config: %s\n"
                    "AgentInfo: %s\n"
                    "DirmngrInfo: %s\n"
                    "%s",
                    opt.homedir,
                    opt.config_filename,
                    s1?s1:"[not set]",
                    dirmngr_socket_name (),
                    hello) > 0)
        {
          assuan_set_hello_line (ctx, tmp);
          free (tmp);
        }
    }
  else
    assuan_set_hello_line (ctx, hello);

  assuan_register_reset_notify (ctx, reset_notify);
  assuan_register_input_notify (ctx, input_notify);
  assuan_register_output_notify (ctx, output_notify);
  assuan_register_option_handler (ctx, option_handler);

  assuan_set_pointer (ctx, &ctrl);
  ctrl.server_local = xcalloc (1, sizeof *ctrl.server_local);
  ctrl.server_local->assuan_ctx = ctx;
  ctrl.server_local->message_fd = -1;
  ctrl.server_local->list_internal = 1;
  ctrl.server_local->list_external = 0;
  ctrl.server_local->default_recplist = default_recplist;

  for (;;)
    {
      rc = assuan_accept (ctx);
      if (rc == -1)
        {
          break;
        }
      else if (rc)
        {
          log_info ("Assuan accept problem: %s\n", gpg_strerror (rc));
          break;
        }

      rc = assuan_process (ctx);
      if (rc)
        {
          log_info ("Assuan processing failed: %s\n", gpg_strerror (rc));
          continue;
        }
    }

  gpgsm_release_certlist (ctrl.server_local->recplist);
  ctrl.server_local->recplist = NULL;
  gpgsm_release_certlist (ctrl.server_local->signerlist);
  ctrl.server_local->signerlist = NULL;
  xfree (ctrl.server_local);

  audit_release (ctrl.audit);
  ctrl.audit = NULL;

  assuan_release (ctx);
}
Exemplo n.º 26
0
/* Ask the dirmngr for the submission address of a WKD server for the
 * mail address ADDRSPEC.  On success the submission address is stored
 * at R_ADDRSPEC.  */
gpg_error_t
wkd_get_submission_address (const char *addrspec, char **r_addrspec)
{
  gpg_error_t err;
  assuan_context_t ctx;
  struct wkd_get_parm_s parm;
  char *line = NULL;
  void *vp;
  char *buffer = NULL;
  char *p;

  memset (&parm, 0, sizeof parm);
  *r_addrspec = NULL;

  err = connect_dirmngr (&ctx);
  if (err)
    return err;

  line = es_bsprintf ("WKD_GET --submission-address -- %s", addrspec);
  if (!line)
    {
      err = gpg_error_from_syserror ();
      goto leave;
    }
  if (strlen (line) + 2 >= ASSUAN_LINELENGTH)
    {
      err = gpg_error (GPG_ERR_TOO_LARGE);
      goto leave;
    }

  parm.memfp = es_fopenmem (0, "rwb");
  if (!parm.memfp)
    {
      err = gpg_error_from_syserror ();
      goto leave;
    }
  err = assuan_transact (ctx, line, wkd_get_data_cb, &parm,
                         NULL, NULL, wkd_get_status_cb, &parm);
  if (err)
    goto leave;

  es_fputc (0, parm.memfp);
  if (es_fclose_snatch (parm.memfp, &vp, NULL))
    {
      err = gpg_error_from_syserror ();
      goto leave;
    }
  buffer = vp;
  parm.memfp = NULL;
  p = strchr (buffer, '\n');
  if (p)
    *p = 0;
  trim_spaces (buffer);
  if (!is_valid_mailbox (buffer))
    {
      err = gpg_error (GPG_ERR_INV_USER_ID);
      goto leave;
    }
  *r_addrspec = xtrystrdup (buffer);
  if (!*r_addrspec)
    err = gpg_error_from_syserror ();

 leave:
  es_free (buffer);
  es_fclose (parm.memfp);
  xfree (line);
  assuan_release (ctx);
  return err;
}
Exemplo n.º 27
0
/* Startup the server.  CTRL must have been allocated by the caller
   and set to the default values. */
int
gpg_server (ctrl_t ctrl)
{
  int rc;
#ifndef HAVE_W32_SYSTEM
  int filedes[2];
#endif
  assuan_context_t ctx = NULL;
  static const char hello[] = ("GNU Privacy Guard's OpenPGP server "
                               VERSION " ready");

  /* We use a pipe based server so that we can work from scripts.
     assuan_init_pipe_server will automagically detect when we are
     called with a socketpair and ignore FILEDES in this case.  */
#ifndef HAVE_W32_SYSTEM
  filedes[0] = assuan_fdopen (0);
  filedes[1] = assuan_fdopen (1);
#endif
  rc = assuan_new (&ctx);
  if (rc)
    {
      log_error ("failed to allocate the assuan context: %s\n",
		 gpg_strerror (rc));
      goto leave;
    }

#ifdef HAVE_W32_SYSTEM
  rc = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
#else
  rc = assuan_init_pipe_server (ctx, filedes);
#endif
  if (rc)
    {
      log_error ("failed to initialize the server: %s\n", gpg_strerror (rc));
      goto leave;
    }

  rc = register_commands (ctx);
  if (rc)
    {
      log_error ("failed to the register commands with Assuan: %s\n",
                 gpg_strerror(rc));
      goto leave;
    }

  assuan_set_pointer (ctx, ctrl);
  if (opt.verbose || opt.debug)
    {
      char *tmp = NULL;

      tmp = xtryasprintf ("Home: %s\n"
                          "Config: %s\n"
                          "%s",
                          opt.homedir,
                          "fixme: need config filename",
                          hello);
      if (tmp)
        {
          assuan_set_hello_line (ctx, tmp);
          xfree (tmp);
        }
    }
  else
    assuan_set_hello_line (ctx, hello);
  assuan_register_reset_notify (ctx, reset_notify);
  assuan_register_input_notify (ctx, input_notify);
  assuan_register_output_notify (ctx, output_notify);
  assuan_register_option_handler (ctx, option_handler);

  ctrl->server_local = xtrycalloc (1, sizeof *ctrl->server_local);
  if (!ctrl->server_local)
    {
      rc = gpg_error_from_syserror ();
      goto leave;
    }
  ctrl->server_local->assuan_ctx = ctx;
  ctrl->server_local->message_fd = GNUPG_INVALID_FD;

  for (;;)
    {
      rc = assuan_accept (ctx);
      if (rc == -1)
        {
          rc = 0;
          break;
        }
      else if (rc)
        {
          log_info ("Assuan accept problem: %s\n", gpg_strerror (rc));
          break;
        }

      rc = assuan_process (ctx);
      if (rc)
        {
          log_info ("Assuan processing failed: %s\n", gpg_strerror (rc));
          continue;
        }
    }

 leave:
  if (ctrl->server_local)
    {
      release_pk_list (ctrl->server_local->recplist);

      xfree (ctrl->server_local);
      ctrl->server_local = NULL;
    }
  assuan_release (ctx);
  return rc;
}
Exemplo n.º 28
0
/* This is a compatibility function for GPGSM 2.0.0, which does not
   support the --data option with the EXPORT command.  */
static gpg_error_t
export_cert_compat (char *fpr, struct cert *cert)
{
  gpg_error_t err;
  assuan_context_t ctx;
  const char *argv[] = { "gpgsm", "--server", NULL };
  int got;
#define COMMANDLINELEN 80
  char cmd[COMMANDLINELEN];
  int output_fds[2];
  int child_fds[2];

#define MAX_CERT_SIZE 4096
  cert->cert_der = malloc (MAX_CERT_SIZE);
  if (!cert->cert_der)
    return gpg_error_from_syserror ();

  if(pipe (output_fds) < 0)
    return gpg_error_from_syserror ();

  child_fds[0] = assuan_fd_from_posix_fd (output_fds[1]);
  child_fds[1] = -1;

  err = assuan_new (&ctx);
  if (err)
    {
      close (output_fds[0]);
      close (output_fds[1]);
      DEBUG (DBG_CRIT, "failed to allocate assuan context: %s\n",
	     gpg_strerror (err));
      return err;
    }

  err = assuan_pipe_connect (ctx, get_gpgsm_path (), argv, child_fds,
			     NULL, NULL, 128);
  close (output_fds[1]);
  if (err)
    {
      close (output_fds[0]);
      assuan_release (ctx);
      DEBUG (DBG_CRIT, "failed to spawn %s\n", get_gpgsm_path ());
      return err;
    }

  snprintf (cmd, sizeof (cmd), "OUTPUT FD=%i", output_fds[1]);
  err = assuan_transact (ctx, cmd, NULL, NULL, NULL, NULL, NULL, NULL);
  if (err)
    goto export_out;

  /* FIXME: This will only work if the certificate is small and fits
     into the pipe buffer completely!!!  */
  snprintf (cmd, sizeof (cmd), "EXPORT %s\n", cert->fpr);
  err = assuan_transact (ctx, cmd, NULL, NULL, NULL, NULL, NULL, NULL);
  if (err)
    goto export_out;

  do
    {
      got = read (output_fds[0], cert->cert_der + cert->cert_der_len,
		  MAX_CERT_SIZE - cert->cert_der_len);
      if (got > 0)
	cert->cert_der_len += got;
    }
  while (!err && got > 0 && cert->cert_der_len < MAX_CERT_SIZE);
  
  if (got < 0 || cert->cert_der_len == MAX_CERT_SIZE)
    err = gpg_error (GPG_ERR_GENERAL);

 export_out:
  assuan_release (ctx);
  close (output_fds[0]);
  return err;
}
Exemplo n.º 29
0
/* Try to connect to the agent via socket or fork it off and work by
   pipes.  Handle the server's initial greeting.  Returns a new assuan
   context at R_CTX or an error code. */
gpg_error_t
start_new_gpg_agent (assuan_context_t *r_ctx,
                     gpg_err_source_t errsource,
                     const char *homedir,
                     const char *agent_program,
                     const char *opt_lc_ctype,
                     const char *opt_lc_messages,
                     session_env_t session_env,
                     int verbose, int debug,
                     gpg_error_t (*status_cb)(ctrl_t, int, ...),
                     ctrl_t status_cb_arg)
{
  /* If we ever failed to connect via a socket we will force the use
     of the pipe based server for the lifetime of the process.  */
  static int force_pipe_server = 0;

  gpg_error_t err = 0;
  char *infostr, *p;
  assuan_context_t ctx;
  int did_success_msg = 0;

  *r_ctx = NULL;

  err = assuan_new (&ctx);
  if (err)
    {
      log_error ("error allocating assuan context: %s\n", gpg_strerror (err));
      return err;
    }

 restart:
  infostr = force_pipe_server? NULL : getenv ("GPG_AGENT_INFO");
  if (!infostr || !*infostr)
    {
      char *sockname;
      const char *argv[3];
      pid_t pid;
      int excode;

      /* First check whether we can connect at the standard
         socket.  */
      sockname = make_filename (homedir, "S.gpg-agent", NULL);
      err = assuan_socket_connect (ctx, sockname, 0, 0);

      if (err)
        {
          /* With no success start a new server.  */
          if (!agent_program || !*agent_program)
            agent_program = gnupg_module_name (GNUPG_MODULE_NAME_AGENT);

          if (verbose)
            log_info (_("no running gpg-agent - starting '%s'\n"),
                      agent_program);

          if (status_cb)
            status_cb (status_cb_arg, STATUS_PROGRESS,
                       "starting_agent ? 0 0", NULL);

          if (fflush (NULL))
            {
              gpg_error_t tmperr = gpg_err_make (errsource,
                                                 gpg_err_code_from_syserror ());
              log_error ("error flushing pending output: %s\n",
                         strerror (errno));
              xfree (sockname);
	      assuan_release (ctx);
              return tmperr;
            }

          argv[0] = "--use-standard-socket-p";
          argv[1] = NULL;
          err = gnupg_spawn_process_fd (agent_program, argv, -1, -1, -1, &pid);
          if (err)
            log_debug ("starting '%s' for testing failed: %s\n",
                       agent_program, gpg_strerror (err));
          else if ((err = gnupg_wait_process (agent_program, pid, 1, &excode)))
            {
              if (excode == -1)
                log_debug ("running '%s' for testing failed (wait): %s\n",
                           agent_program, gpg_strerror (err));
            }
          gnupg_release_process (pid);

          if (!err && !excode)
            {
              /* If the agent has been configured for use with a
                 standard socket, an environment variable is not
                 required and thus we we can savely start the agent
                 here.  */
              lock_spawn_t lock;

              argv[0] = "--daemon";
              argv[1] = "--use-standard-socket";
              argv[2] = NULL;

              if (!(err = lock_spawning (&lock, homedir, "agent", verbose))
                  && assuan_socket_connect (ctx, sockname, 0, 0))
                {
                  err = gnupg_spawn_process_detached (agent_program, argv,NULL);
                  if (err)
                    log_error ("failed to start agent '%s': %s\n",
                               agent_program, gpg_strerror (err));
                  else
                    {
                      int i;

                      for (i=0; i < SECS_TO_WAIT_FOR_AGENT; i++)
                        {
                          if (verbose)
                            log_info (_("waiting for the agent "
                                        "to come up ... (%ds)\n"),
                                      SECS_TO_WAIT_FOR_AGENT - i);
                          gnupg_sleep (1);
                          err = assuan_socket_connect (ctx, sockname, 0, 0);
                          if (!err)
                            {
                              if (verbose)
                                {
                                  log_info (_("connection to agent "
                                              "established\n"));
                                  did_success_msg = 1;
                                }
                              break;
                            }
                        }
                    }
                }

              unlock_spawning (&lock, "agent");
            }
          else
            {
              /* If using the standard socket is not the default we
                 start the agent as a pipe server which gives us most
                 of the required features except for passphrase
                 caching etc.  */
              const char *pgmname;
              int no_close_list[3];
              int i;

              if ( !(pgmname = strrchr (agent_program, '/')))
                pgmname = agent_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 (fileno (stderr));
              no_close_list[i] = -1;

              /* Connect to the agent and perform initial handshaking. */
              err = assuan_pipe_connect (ctx, agent_program, argv,
                                         no_close_list, NULL, NULL, 0);
            }
        }
      xfree (sockname);
    }
  else
    {
      int prot;
      int pid;

      infostr = xstrdup (infostr);
      if ( !(p = strchr (infostr, PATHSEP_C)) || p == infostr)
        {
          log_error (_("malformed GPG_AGENT_INFO environment variable\n"));
          xfree (infostr);
          force_pipe_server = 1;
          goto restart;
        }
      *p++ = 0;
      pid = atoi (p);
      while (*p && *p != PATHSEP_C)
        p++;
      prot = *p? atoi (p+1) : 0;
      if (prot != 1)
        {
          log_error (_("gpg-agent protocol version %d is not supported\n"),
                     prot);
          xfree (infostr);
          force_pipe_server = 1;
          goto restart;
        }

      err = assuan_socket_connect (ctx, infostr, pid, 0);
      xfree (infostr);
      if (gpg_err_code (err) == GPG_ERR_ASS_CONNECT_FAILED)
        {
          log_info (_("can't connect to the agent - trying fall back\n"));
          force_pipe_server = 1;
          goto restart;
        }
    }

  if (err)
    {
      log_error ("can't connect to the agent: %s\n", gpg_strerror (err));
      assuan_release (ctx);
      return gpg_err_make (errsource, GPG_ERR_NO_AGENT);
    }

  if (debug && !did_success_msg)
    log_debug (_("connection to agent established\n"));

  err = assuan_transact (ctx, "RESET",
                        NULL, NULL, NULL, NULL, NULL, NULL);
  if (!err)
    err = send_pinentry_environment (ctx, errsource,
                                    opt_lc_ctype, opt_lc_messages,
                                    session_env);
  if (err)
    {
      assuan_release (ctx);
      return err;
    }

  *r_ctx = ctx;
  return 0;
}
Exemplo n.º 30
0
/* Fire up a new GPG.  Handle the server's initial greeting.  Returns
   0 on success and stores the assuan context at R_CTX.  */
static gpg_error_t
start_gpg (ctrl_t ctrl, int input_fd, int output_fd, assuan_context_t *r_ctx)
{
  gpg_error_t err;
  assuan_context_t ctx = NULL;
  const char *pgmname;
  const char *argv[10];
  int no_close_list[5];
  int i;
  char line[ASSUAN_LINELENGTH];

  (void)ctrl;

  *r_ctx = NULL;

  err = assuan_new (&ctx);
  if (err)
    {
      log_error ("can't allocate assuan context: %s\n", gpg_strerror (err));
      return err;
    }

  /* The first time we are used, intialize the gpg_program variable.  */
  if ( !opt.gpg_program || !*opt.gpg_program )
    opt.gpg_program = gnupg_module_name (GNUPG_MODULE_NAME_GPG);

  if (opt.verbose)
    log_info (_("no running gpg - starting '%s'\n"), opt.gpg_program);

  /* Compute argv[0].  */
  if ( !(pgmname = strrchr (opt.gpg_program, '/')))
    pgmname = opt.gpg_program;
  else
    pgmname++;

  if (fflush (NULL))
    {
      err = gpg_error_from_syserror ();
      log_error ("error flushing pending output: %s\n", gpg_strerror (err));
      return err;
    }

  i = 0;
  argv[i++] = pgmname;
  argv[i++] = "--server";
  if ((opt.debug & 1024))
    argv[i++] = "--debug=1024";
  argv[i++] = "-z";
  argv[i++] = "0";
  argv[i++] = "--trust-model";
  argv[i++] = "always";
  argv[i++] = 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 (fileno (stderr));
  if (input_fd != -1)
    no_close_list[i++] = assuan_fd_from_posix_fd (input_fd);
  if (output_fd != -1)
    no_close_list[i++] = assuan_fd_from_posix_fd (output_fd);
  no_close_list[i] = -1;

  /* Connect to GPG and perform initial handshaking.  */
  err = assuan_pipe_connect (ctx, opt.gpg_program, argv, no_close_list,
			     NULL, NULL, 0);
  if (err)
    {
      assuan_release (ctx);
      log_error ("can't connect to GPG: %s\n", gpg_strerror (err));
      return gpg_error (GPG_ERR_NO_ENGINE);
    }

  if (input_fd != -1)
    {
      snprintf (line, sizeof line, "INPUT FD=%d", input_fd);
      err = assuan_transact (ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
      if (err)
        {
          assuan_release (ctx);
          log_error ("error sending INPUT command: %s\n", gpg_strerror (err));
          return err;
        }
    }

  if (output_fd != -1)
    {
      snprintf (line, sizeof line, "OUTPUT FD=%d", output_fd);
      err = assuan_transact (ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
      if (err)
        {
          assuan_release (ctx);
          log_error ("error sending OUTPUT command: %s\n", gpg_strerror (err));
          return err;
        }
    }

  *r_ctx = ctx;

  if (DBG_ASSUAN)
    log_debug ("connection to GPG established\n");
  return 0;
}