gpg-agent dit que l'agent existe, mais gpg dit que l'agent n'existe pas?

9

Je rencontre des problèmes lors de l'écriture de scripts gpg bashsur une boîte Debian 6.0.6. J'ai un script qui fait un lot d'opérations et veut m'assurer qu'un gpg-agent est disponible avant d'essayer de continuer.

Étant donné que gpg-agent ne prendra aucune action et retournera le succès s'il est lancé lorsqu'il est déjà en cours d'exécution, s'assurer que l'agent est présent est aussi simple que:

eval $(gpg-agent --daemon)

gpg-agent commencer ou fera rapport:

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

et retourner 0 (succès) s'il est déjà en cours d'exécution.

Le problème survient lorsqu'un agent est déjà en cours d'exécution dans une autre session. gpg-agentdit qu'il fonctionne déjà ... mais gpgson auto prétend alors qu'il n'est pas 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

Cela me laisse frustré et confus. Il semble que la gpg-agentdétection de l'agent soit différente de celle de gpg. Pire, gpgn'offre aucun moyen de demander si l'agent est disponible de manière scriptable, tout comme il aime ignorer silencieusement les destinataires avec des clés inutilisables et toujours retourner le succès, il est donc très difficile de détecter ce problème avant de commencer le lot. Je ne veux pas entrer dans l'analyse de la sortie de gpg pour des raisons i18n entre autres.

Vous pouvez reproduire cela en vous assurant que vous n'avez pas d'agent gpg en cours d'exécution ou que vous ne l'avez pas GPG_AGENT_INFOdéfini, puis dans un terminal en cours d'exécution eval $(gpg-agent --daemon)et dans un autre terminal exécutant ce qui précède. Vous remarquerez que gpg-agent indique qu'il est déjà en cours d'exécution, mais gpg ne parvient pas à se connecter à l'agent.

Des idées?

MISE À JOUR : gpg-agentdétecte un autre agent en recherchant un fichier socket dans un emplacement bien connu et en y écrivant pour tester la validité, par ceci 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

tandis que GnuPG semble ne regarder que l'environnement, ignorant l'emplacement bien connu des sockets. Dans 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 */
}

Je ne veux pas vraiment tuer l'agent juste pour m'assurer de pouvoir le redémarrer, et il n'y a pas d'endroit standard où l'agent de l'utilisateur pourrait écrire un fichier d'environnement. Pire, je ne peux même pas tester la présence de GPG_AGENT_INFOdans l'environnement car cela pourrait faire référence à un agent périmé (mort) qui a depuis été remplacé ... et ni gpgni gpg-agentfournir une option de ligne de commande pour envoyer un ping à l'agent et retourner vrai si c'est D'accord.

Craig Ringer
la source
J'ai également demandé sur la liste de diffusion des utilisateurs de gpg; Je créerai un lien vers le message une fois qu'il apparaîtra dans les archives.
Craig Ringer
Unix.SE Comment configurer gpg pour saisir la phrase secrète une seule fois par session a résolu certains de mes problèmes - sur un système mono-utilisateur cependant.
Joel Purra

Réponses:

6
  1. Vous pouvez vérifier le code de sortie de gpg-connect-agent /bye
  2. Vous pouvez vérifier si le socket indiqué dans $ GPG_AGENT_INFO existe. Cela devrait suffire, mais vous pouvez également vérifier avec fuser ou lsof si le processus indiqué dans $ GPG_AGENT_INFO est celui qui a ouvert le socket. Et si vous voulez être vraiment exhaustif, vous pouvez également vérifier si / proc / $ PID / exe est un lien vers / usr / bin / gpg-agent (ou autre).
Hauke ​​Laging
la source
Malheureusement, aucun de ces problèmes ne résout le problème. (1) détermine correctement si gpg-agent est en cours d'exécution, mais il ne teste pas de la même manière que gpglui-même, il peut donc réussir lorsque gpg ne parvient plus à se connecter à l'agent. La même chose est vraie de (2) en ce que l'agent peut être en cours d'exécution, mais GPG_AGENT_INFO n'est pas défini dans la session en cours, et il n'y a aucun moyen apparent de demander la gpg-agentcommande pour GPG_AGENT_INFOun agent déjà en cours d'exécution.
Craig Ringer
3

Jusqu'à présent, la meilleure solution de contournement que j'ai est le désordre hideux suivant:

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

Cela vérifiera GPG_AGENT_INFOdans l'environnement et s'il est défini, assurez-vous que gpg-agent est réellement en cours d'exécution. (Je ne sais pas encore comment cela interagit avec d'autres implémentations d'agent gpg comme l'agent GNOME). Si les informations sur l'agent sont définies mais que l'agent n'est pas en cours d'exécution, il ne sait pas comment faire face et abandonne.

Si les informations sur l'agent ne sont pas définies, il vérifie si l'agent est en cours d'exécution. Si c'est le cas, il recherche les informations env dans quelques endroits bien connus et s'il ne les trouve pas, abandonne.

Si l'agent n'est pas en cours d'exécution et que les informations sur l'agent ne sont pas définies, il démarre un agent, écrit le fichier env dans un emplacement privé et continue.

Dire que je suis mécontent de ce piratage horrible, hostile à l'utilisateur et peu fiable est un euphémisme.

Il est très surprenant qu'un gpgoutil de sécurité / crypto ignore les arguments et continue. --use-agentdevrait être une erreur fatale si un agent n'est pas en cours d'exécution, au moins facultativement, tout comme la spécification -ravec un destinataire non valide devrait être une erreur plutôt qu'ignorée. Le fait de gpgtrouver son agent d'une manière différente de la gpg-agentcommande est déroutant.

Craig Ringer
la source
Comme d'habitude, cela peut être encore plus compliqué ... :-) Si GPG_AGENT_INFO n'est pas (ou à tort) défini et que vous connaissez le PID (par exemple par pgrep gpg-agent) alors ypu peut le faire pour trouver la socket:lsof -n -p $PID | grep S.gpg-agent$ | awk '{print $NF}'
Hauke ​​Laging
1
@HaukeLaging ... si ce n'est vraiment gpg-agentpas dire gnome-keyring-daemonau travail. parce que ce n'était pas déjà assez horrible: S. Je suis étonné que tout cela soit un tel gâchis incohérent.
Craig Ringer
! test -v GPG_AGENT_INFO ne fonctionne pas sur Mac OS X. Vous devrez utiliser quelque chose comme à la [ -z ${GPG_AGENT_INFO+x} ]place.
Dan Loewenherz
2

Sur mon système Ubuntu gpg-agentest configuré pour écrire son fichier d'environnement ~/.gnupg/gpg-agent-info-$(hostname)(ce qui est fait par /etc/X11/Xsession.d/90gpg-agent). Si votre système ne le fait pas, vous pouvez modifier la façon dont l'agent est démarré pour écrire un fichier d'environnement dans un emplacement bien connu qui peut ensuite être obtenu. Par exemple:

$ gpg-agent --daemon --write-env-file="$HOME/.gnupg/gpg-agent-info"
$ source ~/.gnupg/gpg-agent-info
mgorven
la source
Oui, le problème est que je suis des outils de script qui doivent être portables; Je ne peux pas vraiment compter sur des détails spécifiques à la distribution. gpg-agent n'écrira pas de fichier env si un agent est déjà en cours d'exécution et je ne peux pas déterminer où se trouve déjà un fichier env. Si gpg-agent --write-env-file interrogerait l'agent en cours d'exécution et écrirait un fichier env, ce serait bien, mais ce n'est pas le cas.
Craig Ringer
1
NB:gpg-agent[2333]: WARNING: "--write-env-file" is an obsolete option - it has no effect
Kent Fredric