gpg-agent dice que el agente existe, pero gpg dice que el agente no existe?

9

Tengo problemas con algunos problemas al crear scripts gpg bashen un cuadro de Debian 6.0.6. Tengo un script que realiza un lote de operaciones y quiere asegurarse de que haya un agente gpg disponible antes de intentar continuar.

Dado que gpg-agent no realizará ninguna acción y devolverá el éxito si se inicia cuando ya se está ejecutando, garantizar que el agente esté presente es tan simple como:

eval $(gpg-agent --daemon)

gpg-agent comenzará o informará:

gpg-agent[21927]: a gpg-agent is already running - not starting a new one

y devuelve 0 (éxito) si ya se está ejecutando.

El problema surge cuando un agente ya se está ejecutando en otra sesión. gpg-agentdice que ya se está ejecutando ... pero gpgluego afirma que no está disponible.

$ gpg-agent --version
gpg-agent (GnuPG) 2.0.19
libgcrypt 1.5.0
$ gpg --version
gpg (GnuPG) 1.4.13

$ eval $(gpg-agent --daemon)
gpg-agent[21927]: a gpg-agent is already running - not starting a new one
$ gpg -d demo-file.asc
gpg: gpg-agent is not available in this session

Esto me deja frustrado y confundido. Parece que gpg-agentestá detectando al agente de una manera diferente a gpg por sí mismo. Peor aún, gpgno ofrece ninguna manera de preguntar si el agente está disponible de manera programable, por mucho que le guste ignorar silenciosamente a los destinatarios con claves inutilizables y aún así devolver el éxito, por lo que es muy difícil detectar este problema antes de comenzar el lote. No quiero entrar en el análisis de la salida de gpg por razones i18n entre otras.

Puede reproducir esto asegurándose de no tener un agente gpg ejecutándose o GPG_AGENT_INFOconfigurado, luego en un terminal ejecutándose eval $(gpg-agent --daemon)y en otro terminal ejecutando lo anterior. Notarás que gpg-agent dice que ya se está ejecutando, pero gpg no se conecta al agente.

Ideas?

ACTUALIZACIÓN : gpg-agentdetecta a otro agente buscando un archivo de socket en una ubicación conocida y escribiéndole para probar la vida, por esto strace:

socket(PF_FILE, SOCK_STREAM, 0)         = 5
connect(5, {sa_family=AF_FILE, sun_path="/home/craig/.gnupg/S.gpg-agent"}, 32) = 0
fcntl(5, F_GETFL)                       = 0x2 (flags O_RDWR)
fcntl(5, F_GETFL)                       = 0x2 (flags O_RDWR)
select(6, [5], NULL, NULL, {0, 0})      = 1 (in [5], left {0, 0})
read(5, "OK Pleased to meet you, process "..., 1002) = 38
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f41a3e61000
write(2, "gpg-agent: gpg-agent running and"..., 43gpg-agent: gpg-agent running and available
) = 43

mientras que GnuPG parece mirar solo el entorno, ignorando la conocida ubicación del socket. En common/simple-pwquery.c:

/* 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;
  int prot;
  char line[200];
  int nread;

  *rfd = -1;
  infostr = getenv ( "GPG_AGENT_INFO" );
  if ( !infostr || !*infostr )
    infostr = default_gpg_agent_info;
  if ( !infostr || !*infostr )
    {
#ifdef SPWQ_USE_LOGGING
      log_error (_("gpg-agent is not available in this session\n"));
#endif
      return SPWQ_NO_AGENT;
    }
    /* blah blah blah truncated blah */
}

Realmente no quiero matar al agente solo para asegurarme de que puedo iniciarlo nuevamente, y no hay un lugar estándar donde el agente del usuario pueda escribir un archivo de entorno. Peor aún, ni siquiera puedo probar la presencia GPG_AGENT_INFOen el entorno, ya que eso podría referirse a un agente obsoleto (muerto) que desde entonces ha sido reemplazado ... y gpgtampoco gpg-agentproporcionar una opción de línea de comando para hacer ping al agente y devolver verdadero si es Okay.

Craig Ringer
fuente
También he preguntado en la lista de correo gpg-users; Voy a vincular a la publicación una vez que aparezca en los archivos.
Craig Ringer
Unix.SE Cómo configurar gpg para ingresar una frase de contraseña solo una vez por sesión resolvió algunos de mis problemas, aunque en un sistema de usuario único.
Joel Purra

Respuestas:

6
  1. Puede consultar el código de salida de gpg-connect-agent /bye
  2. Puede verificar si el socket dado en $ GPG_AGENT_INFO existe. Eso debería ser suficiente, pero también puede verificar con fuser o lsof si el proceso dado en $ GPG_AGENT_INFO es el que ha abierto el socket. Y si quiere ser realmente exhaustivo, también puede verificar si / proc / $ PID / exe es un enlace a / usr / bin / gpg-agent (o lo que sea).
Hauke ​​Laging
fuente
Lamentablemente, ninguno de estos resuelve el problema. (1) determina correctamente si gpg-agent se está ejecutando, pero no se prueba de la misma manera que gpgsí mismo, por lo que puede tener éxito cuando gpg posteriormente no se conecta al agente. Lo mismo se aplica a (2) en que el agente puede estar ejecutándose, pero GPG_AGENT_INFO no está configurado en la sesión actual, y no hay una forma aparente de pedirle al gpg-agentcomando GPG_AGENT_INFOun agente que ya se está ejecutando.
Craig Ringer
3

Hasta ahora, la mejor solución que tengo es el siguiente desastre horrible:

if ! test -v GPG_AGENT_INFO; then
    if gpg-agent 2>/dev/null; then
        if test -e /tmp/.gpg-agent-$USER/env; then
            . /tmp/.gpg-agent-$USER/env
        elif test -e ~/.gpg-agent-info; then
            . ~/.gpg-agent-info
        else
            echo 'A gpg agent is running, but we cannot find its socket info because'
            echo 'the GPG_AGENT_INFO env var is not set and gpg agent info has not been'
            echo 'written to any expected location. Cannot continue. Please report this'
            echo 'issue for investigation.'
            exit 5
        fi
    else
        mkdir /tmp/.gpg-agent-$USER
        chmod 700 /tmp/.gpg-agent-$USER
        gpg-agent --daemon --write-env-file /tmp/.gpg-agent-$USER/env
        . /tmp/.gpg-agent-$USER/env
    fi
    # The env file doesn't include an export statement
    export GPG_AGENT_INFO
else
    if ! gpg-agent 2>/dev/null; then
        echo 'GPG_AGENT_INFO is set, but cannot connect to the agent.'
        echo 'Unsure how to proceed, so aborting execution. Please report this'
        echo 'issue for investigation.'
        exit 5
    fi
fi

Esto verificará GPG_AGENT_INFOen el entorno y si está configurado, asegúrese de que gpg-agent se esté ejecutando realmente. (Todavía no estoy seguro de cómo interactúa esto con otras implementaciones de agentes gpg como el agente de GNOME). Si la información del agente está configurada pero el agente no se está ejecutando, no sabe cómo hacer frente y se da por vencido.

Si la información del agente no está configurada, verifica si el agente se está ejecutando. Si es así, busca la información ambiental en un par de ubicaciones conocidas y, si no la encuentra, se da por vencida.

Si el agente no se está ejecutando y la información del agente no está configurada, inicia un agente, escribe el archivo env en una ubicación privada y continúa.

Decir que no estoy satisfecho con este truco horrible, hostil para el usuario y poco confiable es un eufemismo.

Es muy sorprendente que gpg, una herramienta de seguridad / criptografía, ignore los argumentos y continúe. --use-agentdebería ser un error grave si un agente no se está ejecutando, al menos opcionalmente, ya que especificar -rcon un destinatario no válido debería ser un error en lugar de ignorarse. El hecho de que gpgencuentre a su agente de una manera diferente al gpg-agentcomando es desconcertante.

Craig Ringer
fuente
Como de costumbre, puede volverse aún más desordenado ... :-) Si GPG_AGENT_INFO no está configurado (o incorrectamente) y conoce el PID (p. Ej., Por pgrep gpg-agent), entonces puede hacer esto para encontrar el socket:lsof -n -p $PID | grep S.gpg-agent$ | awk '{print $NF}'
Hauke ​​Laging
1
@HaukeLaging ... si realmente gpg-agentno se dice gnome-keyring-daemonen el trabajo. porque ya no era lo suficientemente horrible: S. Estoy sorprendido de que todo sea un desastre tan inconsistente.
Craig Ringer
! test -v GPG_AGENT_INFO no funciona en Mac OS X. Tendrás que usar algo como en su [ -z ${GPG_AGENT_INFO+x} ]lugar.
Dan Loewenherz
2

En mi sistema Ubuntu gpg-agentestá configurado para escribir su archivo de entorno ~/.gnupg/gpg-agent-info-$(hostname)(que se hace por /etc/X11/Xsession.d/90gpg-agent). Si su sistema no hace esto, puede modificar la forma en que se inicia el agente para escribir un archivo de entorno en una ubicación conocida que luego se puede obtener. Por ejemplo:

$ gpg-agent --daemon --write-env-file="$HOME/.gnupg/gpg-agent-info"
$ source ~/.gnupg/gpg-agent-info
mgorven
fuente
Sí, el problema es que estoy usando herramientas de script que necesitan ser portátiles; Realmente no puedo confiar en detalles específicos de la distribución. gpg-agent no escribirá un archivo env si un agente ya se está ejecutando y no puedo determinar dónde podría estar el archivo env. Si gpg-agent --write-env-file consultara al agente actualmente en ejecución y escribiera un archivo env, estaría bien, pero no lo hace.
Craig Ringer
1
NB:gpg-agent[2333]: WARNING: "--write-env-file" is an obsolete option - it has no effect
Kent Fredric