Ejemplo n.º 1
0
static void
run_umount_helper (const char *mountpoint)
{
  gpg_error_t err;
  const char pgmname[] = FUSERMOUNT;
  const char *args[3];

  args[0] = "-u";
  args[1] = mountpoint;
  args[2] = NULL;

  err = gnupg_spawn_process_detached (pgmname, args, NULL);
  if (err)
    log_error ("failed to run '%s': %s\n",
               pgmname, gpg_strerror (err));
}
Ejemplo n.º 2
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;
}
Ejemplo n.º 3
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;
}