1
0
mirror of git://git.gnupg.org/gnupg.git synced 2025-02-03 16:53:03 +01:00

* passphrase.c (agent_open): Add support for the new Assuan based

gpg-agent.  New arg to return the used protocol version.
(agent_get_passphrase): Implemented new protocol here.
(passphrase_clear_cache): Ditto.
This commit is contained in:
Werner Koch 2002-01-19 18:30:27 +00:00
parent e17cd91abe
commit 646b214d48
2 changed files with 355 additions and 168 deletions

View File

@ -1,3 +1,10 @@
2002-01-19 Werner Koch <wk@gnupg.org>
* passphrase.c (agent_open): Add support for the new Assuan based
gpg-agent. New arg to return the used protocol version.
(agent_get_passphrase): Implemented new protocol here.
(passphrase_clear_cache): Ditto.
2002-01-15 Timo Schulz <ts@winpt.org> 2002-01-15 Timo Schulz <ts@winpt.org>
* encode.c (encode_crypt_files): Fail if --output is used. * encode.c (encode_crypt_files): Fail if --output is used.

View File

@ -80,6 +80,15 @@ enum gpga_protocol_codes {
((byte*)p)[3] = (byte)((a) ); \ ((byte*)p)[3] = (byte)((a) ); \
} while(0) } while(0)
#define digitp(p) (*(p) >= '0' && *(p) <= '9')
#define hexdigitp(a) (digitp (a) \
|| (*(a) >= 'A' && *(a) <= 'F') \
|| (*(a) >= 'a' && *(a) <= 'f'))
#define xtoi_1(p) (*(p) <= '9'? (*(p)- '0'): \
*(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10))
#define xtoi_2(p) ((xtoi_1(p) * 16) + xtoi_1((p)+1))
static char *fd_passwd = NULL; static char *fd_passwd = NULL;
static char *next_pw = NULL; static char *next_pw = NULL;
@ -257,6 +266,48 @@ readn ( int fd, void *buf, size_t buflen, size_t *ret_nread )
return 0; return 0;
} }
/* read an entire line */
static int
readline (int fd, char *buf, size_t buflen)
{
size_t nleft = buflen;
char *p;
int nread = 0;
while (nleft > 0)
{
int n = read (fd, buf, nleft);
if (n < 0)
{
if (errno == EINTR)
continue;
return -1; /* read error */
}
else if (!n)
{
return -1; /* incomplete line */
}
p = buf;
nleft -= n;
buf += n;
nread += n;
for (; n && *p != '\n'; n--, p++)
;
if (n)
{
break; /* at least one full line available - that's enough.
This function is just a temporary hack until we use
the assuna lib in gpg. So it is okay to forget
about pending bytes */
}
}
return nread;
}
#if !defined (__riscos__) #if !defined (__riscos__)
/* /*
* Open a connection to the agent and send the magic string * Open a connection to the agent and send the magic string
@ -264,7 +315,7 @@ readn ( int fd, void *buf, size_t buflen, size_t *ret_nread )
*/ */
static int static int
agent_open (void) agent_open (int *ret_prot)
{ {
#if defined (__MINGW32__) || defined (__CYGWIN32__) #if defined (__MINGW32__) || defined (__CYGWIN32__)
int fd; int fd;
@ -272,6 +323,7 @@ agent_open (void)
HANDLE h; HANDLE h;
char pidstr[128]; char pidstr[128];
*ret_prot = 0;
if ( !(infostr = read_w32_registry_string(NULL, "Software\\GNU\\GnuPG", if ( !(infostr = read_w32_registry_string(NULL, "Software\\GNU\\GnuPG",
"agentPID")) "agentPID"))
|| *infostr == '0') { || *infostr == '0') {
@ -314,6 +366,7 @@ agent_open (void)
char *infostr, *p; char *infostr, *p;
struct sockaddr_un client_addr; struct sockaddr_un client_addr;
size_t len; size_t len;
int prot;
infostr = getenv ( "GPG_AGENT_INFO" ); infostr = getenv ( "GPG_AGENT_INFO" );
if ( !infostr ) { if ( !infostr ) {
@ -327,7 +380,19 @@ agent_open (void)
m_free (infostr ); m_free (infostr );
return -1; return -1;
} }
*p = 0; *p++ = 0;
/* See whether this is the new gpg-agent using the Assuna protocl.
This agent identifies itself by have an info string with a
version number in the 3rd field. */
while (*p && *p != ':')
p++;
prot = *p? atoi (p+1) : 0;
if ( prot < 0 || prot > 1) {
log_error (_("gpg-agent protocol version %d is not supported\n"),prot);
m_free (infostr );
return -1;
}
*ret_prot = prot;
if( (fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1 ) { if( (fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1 ) {
log_error ("can't create socket: %s\n", strerror(errno) ); log_error ("can't create socket: %s\n", strerror(errno) );
@ -350,10 +415,25 @@ agent_open (void)
} }
m_free (infostr); m_free (infostr);
if (!prot) {
if ( writen ( fd, "GPGA\0\0\0\x01", 8 ) ) { if ( writen ( fd, "GPGA\0\0\0\x01", 8 ) ) {
close (fd); close (fd);
fd = -1; fd = -1;
} }
}
else { /* assuan based gpg-agent */
char line[200];
int nread;
nread = readline (fd, line, DIM(line));
if (nread < 3 || !(line[0] == 'O' && line[1] == 'K'
&& (line[2] == '\n' || line[2] == ' ')) ) {
log_error ( _("communication problem with gpg-agent\n"));
close (fd );
return -1;
}
}
#endif #endif
return fd; return fd;
@ -394,6 +474,7 @@ agent_get_passphrase ( u32 *keyid, int mode )
char *pw = NULL; char *pw = NULL;
PKT_public_key *pk = m_alloc_clear( sizeof *pk ); PKT_public_key *pk = m_alloc_clear( sizeof *pk );
byte fpr[MAX_FINGERPRINT_LEN]; byte fpr[MAX_FINGERPRINT_LEN];
int prot;
#if MAX_FINGERPRINT_LEN < 20 #if MAX_FINGERPRINT_LEN < 20
#error agent needs a 20 byte fingerprint #error agent needs a 20 byte fingerprint
@ -403,7 +484,8 @@ agent_get_passphrase ( u32 *keyid, int mode )
if( keyid && get_pubkey( pk, keyid ) ) if( keyid && get_pubkey( pk, keyid ) )
pk = NULL; /* oops: no key for some reason */ pk = NULL; /* oops: no key for some reason */
if ( !mode && pk ) { if ( !mode && pk )
{
char *uid; char *uid;
size_t uidlen; size_t uidlen;
const char *algo_name = pubkey_algo_to_string ( pk->pubkey_algo ); const char *algo_name = pubkey_algo_to_string ( pk->pubkey_algo );
@ -449,9 +531,11 @@ agent_get_passphrase ( u32 *keyid, int mode )
else else
atext = m_strdup ( _("Repeat passphrase\n") ); atext = m_strdup ( _("Repeat passphrase\n") );
if ( (fd = agent_open ()) == -1 ) if ( (fd = agent_open (&prot)) == -1 )
goto failure; goto failure;
if (!prot)
{ /* old style protocol */
n = 4 + 20 + strlen (atext); n = 4 + 20 + strlen (atext);
u32tobuf (buf, n ); u32tobuf (buf, n );
u32tobuf (buf+4, GPGA_PROT_GET_PASSPHRASE ); u32tobuf (buf+4, GPGA_PROT_GET_PASSPHRASE );
@ -464,24 +548,28 @@ agent_get_passphrase ( u32 *keyid, int mode )
if ( readn ( fd, buf, 12, &nread ) ) if ( readn ( fd, buf, 12, &nread ) )
goto failure; goto failure;
if ( nread < 8 ) { if ( nread < 8 )
{
log_error ( "response from agent too short\n" ); log_error ( "response from agent too short\n" );
goto failure; goto failure;
} }
n = buftou32 ( buf ); n = buftou32 ( buf );
reply = buftou32 ( buf + 4 ); reply = buftou32 ( buf + 4 );
if ( reply == GPGA_PROT_GOT_PASSPHRASE ) { if ( reply == GPGA_PROT_GOT_PASSPHRASE )
{
size_t pwlen; size_t pwlen;
size_t nn; size_t nn;
if ( nread < 12 || n < 8 ) { if ( nread < 12 || n < 8 )
{
log_error ( "response from agent too short\n" ); log_error ( "response from agent too short\n" );
goto failure; goto failure;
} }
pwlen = buftou32 ( buf + 8 ); pwlen = buftou32 ( buf + 8 );
nread -= 12; nread -= 12;
n -= 8; n -= 8;
if ( pwlen > n || n > 1000 ) { if ( pwlen > n || n > 1000 )
{
log_error (_("passphrase too long\n")); log_error (_("passphrase too long\n"));
/* or protocol error */ /* or protocol error */
goto failure; goto failure;
@ -493,7 +581,8 @@ agent_get_passphrase ( u32 *keyid, int mode )
pw = m_alloc_secure ( n+1 ); pw = m_alloc_secure ( n+1 );
if ( readn ( fd, pw, n, &nn ) ) if ( readn ( fd, pw, n, &nn ) )
goto failure; goto failure;
if ( n != nn ) { if ( n != nn )
{
log_error (_("invalid response from agent\n")); log_error (_("invalid response from agent\n"));
goto failure; goto failure;
} }
@ -502,13 +591,73 @@ agent_get_passphrase ( u32 *keyid, int mode )
free_public_key( pk ); free_public_key( pk );
return pw; return pw;
} }
else if ( reply == GPGA_PROT_CANCELED ) { else if ( reply == GPGA_PROT_CANCELED )
log_info ( _("cancelled by user\n") ); log_info ( _("cancelled by user\n") );
} else
else {
log_error ( _("problem with the agent: agent returns 0x%lx\n"), log_error ( _("problem with the agent: agent returns 0x%lx\n"),
(ulong)reply ); (ulong)reply );
} }
else
{ /* The new Assuan protocol */
char *line, *p;
int i;
/* We allocate 2 time the needed space for atext so that there
is nenough space for escaping */
line = m_alloc (15 + 46 + 3*strlen (atext) + 2);
strcpy (line, "GET_PASSPHRASE ");
p = line+15;
for (i=0; i < 20; i++, p +=2 )
sprintf (p, "%02X", fpr[i]);
*p++ = ' ';
*p++ = 'X'; /* No error prompt */
*p++ = ' ';
*p++ = 'X'; /* Use the standard prompt */
*p++ = ' ';
/* copy description */
for (i=0; atext[i]; i++)
{
if (atext[i] < ' ' || atext[i] == '+')
{
sprintf (p, "%%%02X", atext[i]);
p += 3;
}
else if (atext[i] == ' ')
*p++ = '+';
else
*p++ = atext[i];
}
*p++ = '\n';
i = writen (fd, line, p - line);
m_free (line);
if (i)
goto failure;
m_free (atext); atext = NULL;
/* get response */
pw = m_alloc_secure (500);
nread = readline (fd, pw, 499);
if (nread < 3)
goto failure;
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 */
log_debug ("passphrase=`%s'\n", pw);
agent_close (fd);
free_public_key( pk );
return pw;
}
else if (nread > 7 && !memcmp (pw, "ERR 111", 7)
&& (pw[7] == ' ' || pw[7] == '\n') )
log_info (_("cancelled by user\n") );
else
log_error (_("problem with the agent\n"));
}
failure: failure:
@ -532,12 +681,13 @@ passphrase_clear_cache ( u32 *keyid, int algo )
return ; return ;
#else #else
size_t n; size_t n;
char buf[50]; char buf[200];
int fd = -1; int fd = -1;
size_t nread; size_t nread;
u32 reply; u32 reply;
PKT_public_key *pk; PKT_public_key *pk;
byte fpr[MAX_FINGERPRINT_LEN]; byte fpr[MAX_FINGERPRINT_LEN];
int prot;
#if MAX_FINGERPRINT_LEN < 20 #if MAX_FINGERPRINT_LEN < 20
#error agent needs a 20 byte fingerprint #error agent needs a 20 byte fingerprint
@ -548,7 +698,8 @@ passphrase_clear_cache ( u32 *keyid, int algo )
pk = m_alloc_clear ( sizeof *pk ); pk = m_alloc_clear ( sizeof *pk );
memset (fpr, 0, MAX_FINGERPRINT_LEN ); memset (fpr, 0, MAX_FINGERPRINT_LEN );
if( !keyid || get_pubkey( pk, keyid ) ) { if( !keyid || get_pubkey( pk, keyid ) )
{
log_debug ("oops, no key in passphrase_clear_cache\n"); log_debug ("oops, no key in passphrase_clear_cache\n");
goto failure; /* oops: no key for some reason */ goto failure; /* oops: no key for some reason */
} }
@ -558,9 +709,11 @@ passphrase_clear_cache ( u32 *keyid, int algo )
fingerprint_from_pk( pk, fpr, &dummy ); fingerprint_from_pk( pk, fpr, &dummy );
} }
if ( (fd = agent_open ()) == -1 ) if ( (fd = agent_open (&prot)) == -1 )
goto failure; goto failure;
if (!prot)
{
n = 4 + 20; n = 4 + 20;
u32tobuf (buf, n ); u32tobuf (buf, n );
u32tobuf (buf+4, GPGA_PROT_CLEAR_PASSPHRASE ); u32tobuf (buf+4, GPGA_PROT_CLEAR_PASSPHRASE );
@ -578,14 +731,41 @@ passphrase_clear_cache ( u32 *keyid, int algo )
} }
reply = buftou32 ( buf + 4 ); reply = buftou32 ( buf + 4 );
if ( reply != GPGA_PROT_OKAY && reply != GPGA_PROT_NO_PASSPHRASE ) { if ( reply != GPGA_PROT_OKAY && reply != GPGA_PROT_NO_PASSPHRASE )
{
log_error ( _("problem with the agent: agent returns 0x%lx\n"), log_error ( _("problem with the agent: agent returns 0x%lx\n"),
(ulong)reply ); (ulong)reply );
} }
}
else
{ /* The assuan protocol */
char *line, *p;
int i;
line = m_alloc (17 + 40 + 2);
strcpy (line, "CLEAR_PASSPHRASE ");
p = line+17;
for (i=0; i < 20; i++, p +=2 )
sprintf (p, "%02X", fpr[i]);
*p++ = '\n';
i = writen (fd, line, p - line);
m_free (line);
if (i)
goto failure;
/* get response */
nread = readline (fd, buf, DIM(buf)-1);
if (nread < 3)
goto failure;
if (buf[0] == 'O' && buf[1] == 'K' && (buf[2] == ' ' || buf[2] == '\n'))
;
else
log_error (_("problem with the agent\n"));
}
failure: failure:
if ( fd != -1 ) if (fd != -1)
agent_close (fd); agent_close (fd);
free_public_key( pk ); free_public_key( pk );
#endif /* Posix or W32 */ #endif /* Posix or W32 */