示例#1
0
/* Send an option to the agent */
static int
agent_send_option (int fd, const char *name, const char *value)
{
  char buf[200];
  int nread;
  char *line;
  int i; 
  
  line = spwq_malloc (7 + strlen (name) + 1 + strlen (value) + 2);
  if (!line)
    return SPWQ_OUT_OF_CORE;
  strcpy (stpcpy (stpcpy (stpcpy (
                     stpcpy (line, "OPTION "), name), "="), value), "\n");
  i = writen (fd, line, strlen (line));
  spwq_free (line);
  if (i)
    return i;
  
  /* get response */
  nread = readline (fd, buf, DIM(buf)-1);
  if (nread < 0)
    return -nread;
  if (nread < 3)
    return SPWQ_PROTOCOL_ERROR;
  
  if (buf[0] == 'O' && buf[1] == 'K' && (buf[2] == ' ' || buf[2] == '\n')) 
    return 0; /* okay */

  return SPWQ_ERR_RESPONSE;
}
示例#2
0
/* Set the name of the default socket to NAME.  */
int 
simple_pw_set_socket (const char *name)
{
  spwq_free (default_gpg_agent_info);
  if (name)
    {
      default_gpg_agent_info = spwq_malloc (strlen (name) + 4 + 1);
      if (!default_gpg_agent_info)
        return SPWQ_OUT_OF_CORE;
      /* We don't know the PID thus we use 0.  */
      strcpy (stpcpy (default_gpg_agent_info, name),
              PATHSEP_S "0" PATHSEP_S "1");
    }
  else
    default_gpg_agent_info = NULL;

  return 0;
}
示例#3
0
/* Ask the gpg-agent for a passphrase and present the user with a
   DESCRIPTION, a PROMPT and optionally with a TRYAGAIN extra text.
   If a CACHEID is not NULL it is used to locate the passphrase in in
   the cache and store it under this ID.  If OPT_CHECK is true
   gpg-agent is asked to apply some checks on the passphrase security.
   If ERRORCODE is not NULL it should point a variable receiving an
   errorcode; this error code might be 0 if the user canceled the
   operation.  The function returns NULL to indicate an error.  */
char *
simple_pwquery (const char *cacheid, 
                const char *tryagain,
                const char *prompt,
                const char *description,
                int opt_check,
                int *errorcode)
{
  int fd = -1;
  int nread;
  char *result = NULL;
  char *pw = NULL;
  char *p;
  int rc, i; 

  rc = agent_open (&fd);
  if (rc)
    goto leave;

  if (!cacheid)
    cacheid = "X";
  if (!tryagain)
    tryagain = "X";
  if (!prompt)
    prompt = "X";
  if (!description)
    description = "X";

  {
    char *line;
    /* We allocate 3 times the needed space so that there is enough
       space for escaping. */
    line = spwq_malloc (15 + 10
                        + 3*strlen (cacheid) + 1
                        + 3*strlen (tryagain) + 1
                        + 3*strlen (prompt) + 1
                        + 3*strlen (description) + 1
                        + 2);
    if (!line)
      {
        rc = SPWQ_OUT_OF_CORE;
        goto leave;
      }
    strcpy (line, "GET_PASSPHRASE ");
    p = line+15;
    if (opt_check)
      p = stpcpy (p, "--check ");
    p = copy_and_escape (p, cacheid);
    *p++ = ' ';
    p = copy_and_escape (p, tryagain);
    *p++ = ' ';
    p = copy_and_escape (p, prompt);
    *p++ = ' ';
    p = copy_and_escape (p, description);
    *p++ = '\n';
    rc = writen (fd, line, p - line);
    spwq_free (line);
    if (rc)
      goto leave;
  }

  /* get response */
  pw = spwq_secure_malloc (500);
  nread = readline (fd, pw, 499);
  if (nread < 0)
    {
      rc = -nread;
      goto leave;
    }
  if (nread < 3)
    {
      rc = SPWQ_PROTOCOL_ERROR;
      goto leave;
    }
      
  if (pw[0] == 'O' && pw[1] == 'K' && pw[2] == ' ') 
    { /* we got a passphrase - convert it back from hex */
      size_t pwlen = 0;
      
      for (i=3; i < nread && hexdigitp (pw+i); i+=2)
        pw[pwlen++] = xtoi_2 (pw+i);
      pw[pwlen] = 0; /* make a C String */
      result = pw;
      pw = NULL;
    }
  else if ((nread > 7 && !memcmp (pw, "ERR 111", 7)
            && (pw[7] == ' ' || pw[7] == '\n') )
           || ((nread > 4 && !memcmp (pw, "ERR ", 4)
                && (strtoul (pw+4, NULL, 0) & 0xffff) == 99)) ) 
    {
      /* 111 is the old Assuan code for canceled which might still
         be in use by old installations. 99 is GPG_ERR_CANCELED as
         used by modern gpg-agents; 0xffff is used to mask out the
         error source.  */
#ifdef SPWQ_USE_LOGGING
      log_info (_("canceled by user\n") );
#endif
      *errorcode = 0; /* Special error code to indicate Cancel. */
    }
  else if (nread > 4 && !memcmp (pw, "ERR ", 4))
    {
      switch ( (strtoul (pw+4, NULL, 0) & 0xffff) )
        {
        case 85: rc = SPWQ_NO_PIN_ENTRY;  break;
        default: rc = SPWQ_GENERAL_ERROR; break;
        }
    }
  else 
    {
#ifdef SPWQ_USE_LOGGING
      log_error (_("problem with the agent\n"));
#endif
      rc = SPWQ_ERR_RESPONSE;
    }
        
 leave:
  if (errorcode)
    *errorcode = rc;
  if (fd != -1)
    close (fd);
  if (pw)
    spwq_secure_free (pw);
  return result;
}
示例#4
0
/* Send all available options to the agent. */
static int 
agent_send_all_options (int fd)
{
  char *dft_display = NULL;
  char *dft_ttyname = NULL;
  char *dft_ttytype = NULL;
  char *dft_xauthority = NULL;
  char *dft_pinentry_user_data = NULL;
  int rc = 0;

  dft_display = getenv ("DISPLAY");
  if (dft_display)
    {
      if ((rc = agent_send_option (fd, "display", dft_display)))
        return rc;
    }

  dft_ttyname = getenv ("GPG_TTY");
#ifndef HAVE_W32_SYSTEM
  if ((!dft_ttyname || !*dft_ttyname) && ttyname (0))
    dft_ttyname = ttyname (0);
#endif
  if (dft_ttyname && *dft_ttyname)
    {
      if ((rc=agent_send_option (fd, "ttyname", dft_ttyname)))
        return rc;
    }

  dft_ttytype = getenv ("TERM");
  if (dft_ttyname && dft_ttytype)
    {
      if ((rc = agent_send_option (fd, "ttytype", dft_ttytype)))
        return rc;
    }

#if defined(HAVE_SETLOCALE) 
  {
    char *old_lc = NULL;
    char *dft_lc = NULL;

#if defined(LC_CTYPE)
    old_lc = setlocale (LC_CTYPE, NULL);
    if (old_lc)
      {
        char *p = spwq_malloc (strlen (old_lc)+1);
        if (!p)
          return SPWQ_OUT_OF_CORE;
        strcpy (p, old_lc);
        old_lc = p;
      }
    dft_lc = setlocale (LC_CTYPE, "");
    if (dft_ttyname && dft_lc)
      rc = agent_send_option (fd, "lc-ctype", dft_lc);
    if (old_lc)
      {
        setlocale (LC_CTYPE, old_lc);
        spwq_free (old_lc);
      }
    if (rc)
      return rc;
#endif

#if defined(LC_MESSAGES)
    old_lc = setlocale (LC_MESSAGES, NULL);
    if (old_lc)
      {
        char *p = spwq_malloc (strlen (old_lc)+1);
        if (!p)
          return SPWQ_OUT_OF_CORE;
        strcpy (p, old_lc);
        old_lc = p;
      }
    dft_lc = setlocale (LC_MESSAGES, "");
    if (dft_ttyname && dft_lc)
      rc = agent_send_option (fd, "lc-messages", dft_lc);
    if (old_lc)
      {
        setlocale (LC_MESSAGES, old_lc);
        spwq_free (old_lc);
      }
    if (rc)
      return rc;
#endif
  }
#endif /*HAVE_SETLOCALE*/

  /* Send the XAUTHORITY variable.  */
  dft_xauthority = getenv ("XAUTHORITY");
  if (dft_xauthority)
    {
      /* We ignore errors here because older gpg-agents don't support
         this option.  */
      agent_send_option (fd, "xauthority", dft_xauthority);
    }

  /* Send the PINENTRY_USER_DATA variable.  */
  dft_pinentry_user_data = getenv ("PINENTRY_USER_DATA");
  if (dft_pinentry_user_data)
    {
      /* We ignore errors here because older gpg-agents don't support
         this option.  */
      agent_send_option (fd, "pinentry-user-data", dft_pinentry_user_data);
    }

  return 0;
}
示例#5
0
/* Try to open a connection to the agent, send all options and return
   the file descriptor for the connection.  Return -1 in case of
   error. */
static int
agent_open (int *rfd)
{
  int rc;
  int fd;
  char *infostr, *p;
  struct sockaddr_un client_addr;
  size_t len;
  char line[200];
  int nread;

  *rfd = -1;
  infostr = default_gpg_agent_info;
  if ( !infostr || !*infostr )
    {
#ifdef SPWQ_USE_LOGGING
      log_error (_("no gpg-agent running in this session\n"));
#endif
      return SPWQ_NO_AGENT;
    }
  p = spwq_malloc (strlen (infostr)+1);
  if (!p)
    return SPWQ_OUT_OF_CORE;
  strcpy (p, infostr);
  infostr = p;

  if ( !(p = strchr ( infostr, PATHSEP_C)) || p == infostr
       || (p-infostr)+1 >= sizeof client_addr.sun_path )
    {
      spwq_free (infostr);
      return SPWQ_NO_AGENT;
    }
  *p++ = 0;

  while (*p && *p != PATHSEP_C)
    p++;

#ifdef HAVE_W32_SYSTEM
  fd = _w32_sock_new (AF_UNIX, SOCK_STREAM, 0);
#else
  fd = socket (AF_UNIX, SOCK_STREAM, 0);
#endif
  if (fd == -1)
    {
#ifdef SPWQ_USE_LOGGING
      log_error ("can't create socket: %s\n", strerror(errno) );
#endif
      spwq_free (infostr);
      return SPWQ_SYS_ERROR;
    }

  memset (&client_addr, 0, sizeof client_addr);
  client_addr.sun_family = AF_UNIX;
  strcpy (client_addr.sun_path, infostr);
  spwq_free (infostr);
  len = SUN_LEN (&client_addr);

#ifdef HAVE_W32_SYSTEM
  rc = _w32_sock_connect (fd, (struct sockaddr*)&client_addr, len );
#else
  rc = connect (fd, (struct sockaddr*)&client_addr, len );
#endif
  if (rc == -1)
    {
#ifdef SPWQ_USE_LOGGING
      log_error (_("can't connect to '%s': %s\n"),
                 client_addr.sun_path, strerror (errno));
#endif
      close (fd );
      return SPWQ_IO_ERROR;
    }

  nread = readline (fd, line, DIM(line));
  if (nread < 3 || !(line[0] == 'O' && line[1] == 'K'
                     && (line[2] == '\n' || line[2] == ' ')) )
    {
#ifdef SPWQ_USE_LOGGING
      log_error ( _("communication problem with gpg-agent\n"));
#endif
      close (fd );
      return SPWQ_PROTOCOL_ERROR;
    }

  rc = agent_send_all_options (fd);
  if (rc)
    {
#ifdef SPWQ_USE_LOGGING
      log_error (_("problem setting the gpg-agent options\n"));
#endif
      close (fd);
      return rc;
    }

  *rfd = fd;
  return 0;
}