gpg-agent diz que o agente existe, mas gpg diz que o agente não existe?

9

Estou lutando com alguns problemas ao escrever gpg bashem uma caixa Debian 6.0.6. Eu tenho um script que executa um lote de operações e deseja garantir que um agente gpg esteja disponível antes de tentar prosseguir.

Como o gpg-agent não executará nenhuma ação e retornará êxito se for lançado quando já estiver em execução, garantir que o agente esteja presente é tão simples quanto:

eval $(gpg-agent --daemon)

gpg-agent iniciar ou informará:

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

e retorne 0 (sucesso) se já estiver em execução.

O problema surge quando um agente já está sendo executado em outra sessão. gpg-agentdiz que já está em execução ... mas gpgafirma que não está disponível.

$ 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

Isso me deixa frustrado e confuso. Parece que gpg-agentestá detectando o agente de uma maneira diferente de se auto-manipular. Pior, gpgnão há como perguntar se o agente está disponível de maneira programável, da mesma forma que ele gosta de ignorar silenciosamente os destinatários com chaves inutilizáveis ​​e ainda assim retornar com êxito, por isso é muito difícil detectar esse problema antes de iniciar o lote. Não quero analisar a saída do gpg por razões de i18n, entre outros.

Você pode reproduzir isso garantindo que não tenha um agente gpg em execução ou tenha GPG_AGENT_INFOdefinido, em um terminal em execução eval $(gpg-agent --daemon)e em outro terminal executando o acima. Você notará que o gpg-agent diz que já está em execução, mas o gpg não consegue se conectar ao agente.

Ideias?

UPDATE : gpg-agentdetecta outro agente procurando um arquivo de soquete em um local conhecido e gravando nele para testar a vitalidade, conforme abaixo 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

enquanto o GnuPG parece olhar apenas para o ambiente, ignorando a conhecida localização do soquete. Em 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 */
}

Eu realmente não quero matar o agente apenas para ter certeza de que posso iniciá-lo novamente, e não há um local padrão onde o agente do usuário possa gravar um arquivo de ambiente. Pior, não posso nem testar a presença de GPG_AGENT_INFOum ambiente, pois isso pode se referir a um agente obsoleto (inoperante) que foi substituído desde então ... e gpgnem gpg-agentfornecer uma opção de linha de comando para executar ping no agente e retornar verdadeiro se for Está bem.

Craig Ringer
fonte
Eu também perguntei na lista de discussão gpg-users; Vou vincular o post assim que ele aparecer nos arquivos.
Craig Ringer
Unix.SE Como configurar o gpg para inserir a senha apenas uma vez por sessão, resolveu alguns dos meus problemas - em um sistema de usuário único.
Joel Purra

Respostas:

6
  1. Você pode verificar o código de saída de gpg-connect-agent /bye
  2. Você pode verificar se o soquete fornecido em $ GPG_AGENT_INFO existe. Isso deve ser suficiente, mas você também pode verificar com o fusor ou lsof se o processo fornecido em $ GPG_AGENT_INFO é o que abriu o soquete. E se você quer ser realmente exaustivo, também pode verificar se / proc / $ PID / exe é um link para / usr / bin / gpg-agent (ou qualquer outra coisa).
Hauke ​​Laging
fonte
Infelizmente, nenhum deles resolve o problema. (1) determina corretamente se o gpg-agent está em execução, mas não é testado da mesma forma que gpgele, por isso pode ser bem-sucedido quando o gpg subsequentemente não conseguir se conectar ao agente. O mesmo se aplica a (2), pois o agente pode estar em execução, mas GPG_AGENT_INFO não está definido na sessão atual e não há maneira aparente de solicitar ao gpg-agentcomando GPG_AGENT_INFOum agente já em execução.
Craig Ringer
3

Até agora, a melhor solução alternativa que tenho é a seguinte bagunça hedionda:

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

Isso verificará GPG_AGENT_INFO o ambiente e, se estiver definido, verifique se o gpg-agent está realmente em execução. (Ainda não tenho certeza de como isso interage com outras implementações do gpg-agent, como o agente do GNOME). Se as informações do agente estiverem definidas, mas o agente não estiver em execução, ele não saberá como lidar e desistirá.

Se as informações do agente não estiverem definidas, ele verifica se o agente está em execução. Se for, procura as informações do ambiente em alguns locais conhecidos e, se não conseguir encontrá-las, desiste.

Se o agente não estiver em execução e as informações do agente não estiverem definidas, ele inicia um agente, grava o arquivo env em um local privado e continua.

Dizer que estou descontente com esse corte horrível, hostil ao usuário e não confiável é um eufemismo.

É muito surpreendente que gpg, uma ferramenta de segurança / criptografia, ignore argumentos e prossiga. --use-agentdeve ser um erro fatal se um agente não estiver em execução, pelo menos opcionalmente, assim como especificar -rcom um destinatário inválido deve ser um erro e não ignorado. O fato de gpgencontrar seu agente de uma maneira diferente do gpg-agentcomando é desconcertante.

Craig Ringer
fonte
Como de costume, isso pode ser ainda mais confuso ... :-) Se GPG_AGENT_INFO não estiver definido (ou errado) e você souber o PID (por exemplo, por pgrep gpg-agent), então o ypu poderá fazer isso para encontrar o soquete:lsof -n -p $PID | grep S.gpg-agent$ | awk '{print $NF}'
Hauke ​​Laging
1
@HaukeLaging ... se não é realmente gpg-agentdizer gnome-keyring-daemonno trabalho. porque já não era horrível o suficiente: S. Estou surpreso que seja uma bagunça tão inconsistente.
Craig Ringer
! test -v GPG_AGENT_INFO não funciona no Mac OS X. Você precisará usar algo parecido [ -z ${GPG_AGENT_INFO+x} ].
Dan Loewenherz
2

No meu sistema Ubuntu gpg-agentestá configurado para gravar seu arquivo de ambiente ~/.gnupg/gpg-agent-info-$(hostname)(o que é feito por /etc/X11/Xsession.d/90gpg-agent). Se o seu sistema não fizer isso, você poderá modificar a maneira como o agente é iniciado para gravar um arquivo de ambiente em um local conhecido que possa ser posteriormente adquirido. Por exemplo:

$ gpg-agent --daemon --write-env-file="$HOME/.gnupg/gpg-agent-info"
$ source ~/.gnupg/gpg-agent-info
mgorven
fonte
Sim, o problema é que eu sou ferramentas de script que precisam ser portáveis; Eu realmente não posso confiar em detalhes específicos da distribuição. O gpg-agent não gravará um arquivo env se um agente já estiver em execução e não for possível determinar onde já pode estar qualquer arquivo env. Se o gpg-agent --write-env-file consultasse o agente atualmente em execução e gravasse um arquivo env, isso seria ótimo, mas não é.
Craig Ringer
1
Nota:gpg-agent[2333]: WARNING: "--write-env-file" is an obsolete option - it has no effect
Kent Fredric