2003-06-05 07:14:21 +00:00
|
|
|
|
/* trustlist.c - Maintain the list of trusted keys
|
2006-09-15 18:53:37 +00:00
|
|
|
|
* Copyright (C) 2002, 2004, 2006 Free Software Foundation, Inc.
|
2003-06-05 07:14:21 +00:00
|
|
|
|
*
|
|
|
|
|
* This file is part of GnuPG.
|
|
|
|
|
*
|
|
|
|
|
* GnuPG is free software; you can redistribute it and/or modify
|
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
|
* (at your option) any later version.
|
|
|
|
|
*
|
|
|
|
|
* GnuPG is distributed in the hope that it will be useful,
|
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
|
*
|
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
|
* along with this program; if not, write to the Free Software
|
2006-06-20 17:21:37 +00:00
|
|
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
|
|
|
|
|
* USA.
|
2003-06-05 07:14:21 +00:00
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
|
#include <errno.h>
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include <ctype.h>
|
|
|
|
|
#include <assert.h>
|
|
|
|
|
#include <unistd.h>
|
|
|
|
|
#include <sys/stat.h>
|
2006-09-15 18:53:37 +00:00
|
|
|
|
#include <pth.h>
|
2003-06-05 07:14:21 +00:00
|
|
|
|
|
|
|
|
|
#include "agent.h"
|
|
|
|
|
#include <assuan.h> /* fixme: need a way to avoid assuan calls here */
|
2005-01-13 18:00:46 +00:00
|
|
|
|
#include "i18n.h"
|
2003-06-05 07:14:21 +00:00
|
|
|
|
|
|
|
|
|
|
2006-09-15 18:53:37 +00:00
|
|
|
|
/* A structure to store the information from the trust file. */
|
|
|
|
|
struct trustitem_s
|
|
|
|
|
{
|
|
|
|
|
int keyflag; /* The keyflag: '*', 'P' or 'S'. */
|
|
|
|
|
unsigned char fpr[20]; /* The binary fingerprint. */
|
|
|
|
|
};
|
|
|
|
|
typedef struct trustitem_s trustitem_t;
|
2003-06-05 07:14:21 +00:00
|
|
|
|
|
2006-09-15 18:53:37 +00:00
|
|
|
|
/* Malloced table and its allocated size with all trust items. */
|
|
|
|
|
static trustitem_t *trusttable;
|
|
|
|
|
static size_t trusttablesize;
|
|
|
|
|
/* A mutex used to protect the table. */
|
|
|
|
|
static pth_mutex_t trusttable_lock = PTH_MUTEX_INIT;
|
2003-06-05 07:14:21 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2006-09-15 18:53:37 +00:00
|
|
|
|
static const char headerblurb[] =
|
|
|
|
|
"# This is the list of trusted keys. Comment lines, like this one, as\n"
|
|
|
|
|
"# well as empty lines are ignored. Lines have a length limit but this\n"
|
|
|
|
|
"# is not serious limitation as the format of the entries is fixed and\n"
|
|
|
|
|
"# checked by gpg-agent. A non-comment line starts with optional white\n"
|
|
|
|
|
"# space, followed by the SHA-1 fingerpint in hex, optionally followed\n"
|
|
|
|
|
"# by a flag character which my either be 'P', 'S' or '*'. You should\n"
|
|
|
|
|
"# give the gpg-agent a HUP after editing this file.\n"
|
|
|
|
|
"\n\n"
|
|
|
|
|
"# Include the default trust list\n"
|
|
|
|
|
"include-default\n"
|
|
|
|
|
"\n";
|
2003-06-05 07:14:21 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2006-09-15 18:53:37 +00:00
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
lock_trusttable (void)
|
|
|
|
|
{
|
|
|
|
|
if (!pth_mutex_acquire (&trusttable_lock, 0, NULL))
|
|
|
|
|
log_fatal ("failed to acquire mutex in %s\n", __FILE__);
|
2003-06-05 07:14:21 +00:00
|
|
|
|
}
|
|
|
|
|
|
2006-09-15 18:53:37 +00:00
|
|
|
|
static void
|
|
|
|
|
unlock_trusttable (void)
|
|
|
|
|
{
|
|
|
|
|
if (!pth_mutex_release (&trusttable_lock))
|
|
|
|
|
log_fatal ("failed to release mutex in %s\n", __FILE__);
|
|
|
|
|
}
|
2003-06-05 07:14:21 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2006-09-15 18:53:37 +00:00
|
|
|
|
static gpg_error_t
|
|
|
|
|
read_one_trustfile (const char *fname, int allow_include,
|
|
|
|
|
trustitem_t **addr_of_table,
|
|
|
|
|
size_t *addr_of_tablesize,
|
|
|
|
|
int *addr_of_tableidx)
|
2003-06-05 07:14:21 +00:00
|
|
|
|
{
|
2006-09-15 18:53:37 +00:00
|
|
|
|
gpg_error_t err = 0;
|
|
|
|
|
FILE *fp;
|
|
|
|
|
int n, c;
|
2003-06-05 07:14:21 +00:00
|
|
|
|
char *p, line[256];
|
2006-09-15 18:53:37 +00:00
|
|
|
|
trustitem_t *table, *ti;
|
|
|
|
|
int tableidx;
|
|
|
|
|
size_t tablesize;
|
|
|
|
|
int lnr = 0;
|
|
|
|
|
|
|
|
|
|
table = *addr_of_table;
|
|
|
|
|
tablesize = *addr_of_tablesize;
|
|
|
|
|
tableidx = *addr_of_tableidx;
|
|
|
|
|
|
|
|
|
|
fp = fopen (fname, "r");
|
|
|
|
|
if (!fp)
|
2003-06-05 07:14:21 +00:00
|
|
|
|
{
|
2006-09-15 18:53:37 +00:00
|
|
|
|
err = gpg_error_from_syserror ();
|
|
|
|
|
log_error (_("error opening `%s': %s\n"), fname, gpg_strerror (err));
|
|
|
|
|
goto leave;
|
2003-06-05 07:14:21 +00:00
|
|
|
|
}
|
|
|
|
|
|
2006-09-15 18:53:37 +00:00
|
|
|
|
while (fgets (line, DIM(line)-1, fp))
|
2003-06-05 07:14:21 +00:00
|
|
|
|
{
|
2006-09-15 18:53:37 +00:00
|
|
|
|
lnr++;
|
2003-06-05 07:14:21 +00:00
|
|
|
|
|
|
|
|
|
if (!*line || line[strlen(line)-1] != '\n')
|
|
|
|
|
{
|
2006-09-15 18:53:37 +00:00
|
|
|
|
/* Eat until end of line. */
|
|
|
|
|
while ( (c=getc (fp)) != EOF && c != '\n')
|
2003-06-05 07:14:21 +00:00
|
|
|
|
;
|
2006-09-15 18:53:37 +00:00
|
|
|
|
err = gpg_error (*line? GPG_ERR_LINE_TOO_LONG
|
|
|
|
|
: GPG_ERR_INCOMPLETE_LINE);
|
|
|
|
|
log_error (_("file `%s', line %d: %s\n"),
|
|
|
|
|
fname, lnr, gpg_strerror (err));
|
|
|
|
|
continue;
|
2003-06-05 07:14:21 +00:00
|
|
|
|
}
|
2006-09-15 18:53:37 +00:00
|
|
|
|
line[strlen(line)-1] = 0; /* Chop the LF. */
|
2003-06-05 07:14:21 +00:00
|
|
|
|
|
2004-07-22 09:37:36 +00:00
|
|
|
|
/* Allow for empty lines and spaces */
|
2003-06-05 07:14:21 +00:00
|
|
|
|
for (p=line; spacep (p); p++)
|
|
|
|
|
;
|
2006-09-15 18:53:37 +00:00
|
|
|
|
if (!*p || *p == '#')
|
|
|
|
|
continue;
|
2003-06-05 07:14:21 +00:00
|
|
|
|
|
2006-09-15 18:53:37 +00:00
|
|
|
|
if (!strncmp (p, "include-default", 15)
|
|
|
|
|
&& (!p[15] || spacep (p+15)))
|
|
|
|
|
{
|
|
|
|
|
char *etcname;
|
|
|
|
|
gpg_error_t err2;
|
|
|
|
|
|
|
|
|
|
if (!allow_include)
|
|
|
|
|
{
|
|
|
|
|
log_error (_("statement \"%s\" ignored in `%s', line %d\n"),
|
|
|
|
|
"include-default", fname, lnr);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
/* fixme: Should check for trailing garbage. */
|
|
|
|
|
|
|
|
|
|
etcname = make_filename (GNUPG_SYSCONFDIR, "trustlist.txt", NULL);
|
|
|
|
|
if ( !strcmp (etcname, fname) ) /* Same file. */
|
|
|
|
|
log_info (_("statement \"%s\" ignored in `%s', line %d\n"),
|
|
|
|
|
"include-default", fname, lnr);
|
|
|
|
|
else if ( access (etcname, F_OK) && errno == ENOENT )
|
|
|
|
|
{
|
|
|
|
|
/* A non existent system trustlist is not an error.
|
|
|
|
|
Just print a note. */
|
|
|
|
|
log_info (_("system trustlist `%s' not available\n"), etcname);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
err2 = read_one_trustfile (etcname, 0,
|
|
|
|
|
&table, &tablesize, &tableidx);
|
|
|
|
|
if (err2)
|
|
|
|
|
err = err2;
|
|
|
|
|
}
|
|
|
|
|
xfree (etcname);
|
|
|
|
|
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (tableidx == tablesize) /* Need more space. */
|
|
|
|
|
{
|
|
|
|
|
trustitem_t *tmp;
|
|
|
|
|
size_t tmplen;
|
|
|
|
|
|
|
|
|
|
tmplen = tablesize + 20;
|
|
|
|
|
tmp = xtryrealloc (table, tmplen * sizeof *table);
|
|
|
|
|
if (!tmp)
|
|
|
|
|
{
|
|
|
|
|
err = gpg_error_from_syserror ();
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
|
|
|
|
table = tmp;
|
|
|
|
|
tablesize = tmplen;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ti = table + tableidx;
|
|
|
|
|
|
|
|
|
|
n = hexcolon2bin (p, ti->fpr, 20);
|
|
|
|
|
if (n < 0)
|
|
|
|
|
{
|
|
|
|
|
log_error (_("bad fingerprint in `%s', line %d\n"), fname, lnr);
|
|
|
|
|
err = gpg_error (GPG_ERR_BAD_DATA);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
p += n;
|
|
|
|
|
for (; spacep (p); p++)
|
|
|
|
|
;
|
|
|
|
|
|
|
|
|
|
if (!*p)
|
|
|
|
|
ti->keyflag = '*';
|
|
|
|
|
else if ( *p == 'P' || *p == 'p')
|
|
|
|
|
ti->keyflag = 'P';
|
|
|
|
|
else if ( *p == 'S' || *p == 's')
|
|
|
|
|
ti->keyflag = 'S';
|
|
|
|
|
else if ( *p == '*')
|
|
|
|
|
ti->keyflag = '*';
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
log_error (_("invalid keyflag in `%s', line %d\n"), fname, lnr);
|
|
|
|
|
err = gpg_error (GPG_ERR_BAD_DATA);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
p++;
|
|
|
|
|
if ( *p && !spacep (p) )
|
|
|
|
|
{
|
|
|
|
|
log_error (_("invalid keyflag in `%s', line %d\n"), fname, lnr);
|
|
|
|
|
err = gpg_error (GPG_ERR_BAD_DATA);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
/* Fixme: need to check for trailing garbage. */
|
|
|
|
|
tableidx++;
|
|
|
|
|
}
|
|
|
|
|
if ( !err && !feof (fp) )
|
2003-06-05 07:14:21 +00:00
|
|
|
|
{
|
2006-09-15 18:53:37 +00:00
|
|
|
|
err = gpg_error_from_syserror ();
|
|
|
|
|
log_error (_("error reading `%s', line %d: %s\n"),
|
|
|
|
|
fname, lnr, gpg_strerror (err));
|
2003-06-05 07:14:21 +00:00
|
|
|
|
}
|
2006-09-15 18:53:37 +00:00
|
|
|
|
|
|
|
|
|
leave:
|
|
|
|
|
if (fp)
|
|
|
|
|
fclose (fp);
|
|
|
|
|
*addr_of_table = table;
|
|
|
|
|
*addr_of_tablesize = tablesize;
|
|
|
|
|
*addr_of_tableidx = tableidx;
|
|
|
|
|
return err;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Read the trust files and update the global table on success. */
|
|
|
|
|
static gpg_error_t
|
|
|
|
|
read_trustfiles (void)
|
|
|
|
|
{
|
|
|
|
|
gpg_error_t err;
|
|
|
|
|
trustitem_t *table, *ti;
|
|
|
|
|
int tableidx;
|
|
|
|
|
size_t tablesize;
|
|
|
|
|
char *fname;
|
|
|
|
|
int allow_include = 1;
|
|
|
|
|
|
|
|
|
|
tablesize = 10;
|
|
|
|
|
table = xtrycalloc (tablesize, sizeof *table);
|
|
|
|
|
if (!table)
|
|
|
|
|
return gpg_error_from_syserror ();
|
|
|
|
|
tableidx = 0;
|
|
|
|
|
|
|
|
|
|
fname = make_filename (opt.homedir, "trustlist.txt", NULL);
|
|
|
|
|
if ( access (fname, F_OK) )
|
2003-06-05 07:14:21 +00:00
|
|
|
|
{
|
2006-09-15 18:53:37 +00:00
|
|
|
|
if ( errno == ENOENT )
|
|
|
|
|
; /* Silently ignore a non-existing trustfile. */
|
2003-06-05 07:14:21 +00:00
|
|
|
|
else
|
|
|
|
|
{
|
2006-09-15 18:53:37 +00:00
|
|
|
|
err = gpg_error_from_syserror ();
|
|
|
|
|
log_error (_("error opening `%s': %s\n"), fname, gpg_strerror (err));
|
2003-06-05 07:14:21 +00:00
|
|
|
|
}
|
2006-09-15 18:53:37 +00:00
|
|
|
|
xfree (fname);
|
|
|
|
|
fname = make_filename (GNUPG_SYSCONFDIR, "trustlist.txt", NULL);
|
|
|
|
|
allow_include = 0;
|
2003-06-05 07:14:21 +00:00
|
|
|
|
}
|
2006-09-15 18:53:37 +00:00
|
|
|
|
err = read_one_trustfile (fname, allow_include,
|
|
|
|
|
&table, &tablesize, &tableidx);
|
|
|
|
|
xfree (fname);
|
2003-06-05 07:14:21 +00:00
|
|
|
|
|
2006-09-15 18:53:37 +00:00
|
|
|
|
if (err)
|
|
|
|
|
{
|
|
|
|
|
xfree (table);
|
|
|
|
|
return err;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Fixme: we should drop duplicates and sort the table. */
|
|
|
|
|
|
|
|
|
|
ti = xtryrealloc (table, tableidx * sizeof *table);
|
|
|
|
|
if (!ti)
|
|
|
|
|
{
|
|
|
|
|
xfree (table);
|
|
|
|
|
return err;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
lock_trusttable ();
|
|
|
|
|
xfree (trusttable);
|
|
|
|
|
trusttable = table;
|
|
|
|
|
trusttablesize = tableidx;
|
|
|
|
|
unlock_trusttable ();
|
2003-06-05 07:14:21 +00:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2006-09-15 18:53:37 +00:00
|
|
|
|
|
|
|
|
|
|
2004-05-11 19:11:53 +00:00
|
|
|
|
/* Check whether the given fpr is in our trustdb. We expect FPR to be
|
2003-06-05 07:14:21 +00:00
|
|
|
|
an all uppercase hexstring of 40 characters. */
|
2006-09-15 18:53:37 +00:00
|
|
|
|
gpg_error_t
|
2003-06-05 07:14:21 +00:00
|
|
|
|
agent_istrusted (const char *fpr)
|
|
|
|
|
{
|
2006-09-15 18:53:37 +00:00
|
|
|
|
gpg_error_t err;
|
|
|
|
|
trustitem_t *ti;
|
|
|
|
|
size_t len;
|
|
|
|
|
unsigned char fprbin[20];
|
|
|
|
|
|
|
|
|
|
if ( hexcolon2bin (fpr, fprbin, 20) < 0 )
|
|
|
|
|
return gpg_error (GPG_ERR_INV_VALUE);
|
|
|
|
|
|
|
|
|
|
if (!trusttable)
|
2003-06-05 07:14:21 +00:00
|
|
|
|
{
|
2006-09-15 18:53:37 +00:00
|
|
|
|
err = read_trustfiles ();
|
|
|
|
|
if (err)
|
2004-05-11 19:11:53 +00:00
|
|
|
|
{
|
2006-09-15 18:53:37 +00:00
|
|
|
|
log_error (_("error reading list of trusted root certificates\n"));
|
|
|
|
|
return err;
|
2004-05-11 19:11:53 +00:00
|
|
|
|
}
|
2003-06-05 07:14:21 +00:00
|
|
|
|
}
|
2006-09-15 18:53:37 +00:00
|
|
|
|
|
|
|
|
|
if (trusttable)
|
2003-06-05 07:14:21 +00:00
|
|
|
|
{
|
2006-09-15 18:53:37 +00:00
|
|
|
|
for (ti=trusttable, len = trusttablesize; len; ti++, len--)
|
|
|
|
|
if (!memcmp (ti->fpr, fprbin, 20))
|
|
|
|
|
return 0; /* Trusted. */
|
2003-06-05 07:14:21 +00:00
|
|
|
|
}
|
2006-09-15 18:53:37 +00:00
|
|
|
|
return gpg_error (GPG_ERR_NOT_TRUSTED);
|
2003-06-05 07:14:21 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2004-05-11 19:11:53 +00:00
|
|
|
|
/* Write all trust entries to FP. */
|
2006-09-15 18:53:37 +00:00
|
|
|
|
gpg_error_t
|
2003-06-05 07:14:21 +00:00
|
|
|
|
agent_listtrusted (void *assuan_context)
|
|
|
|
|
{
|
2006-09-15 18:53:37 +00:00
|
|
|
|
trustitem_t *ti;
|
|
|
|
|
char key[51];
|
|
|
|
|
gpg_error_t err;
|
|
|
|
|
size_t len;
|
|
|
|
|
|
|
|
|
|
if (!trusttable)
|
2003-06-05 07:14:21 +00:00
|
|
|
|
{
|
2006-09-15 18:53:37 +00:00
|
|
|
|
err = read_trustfiles ();
|
|
|
|
|
if (err)
|
|
|
|
|
{
|
|
|
|
|
log_error (_("error reading list of trusted root certificates\n"));
|
|
|
|
|
return err;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (trusttable)
|
2003-06-05 07:14:21 +00:00
|
|
|
|
{
|
2006-09-15 18:53:37 +00:00
|
|
|
|
/* We need to lock the table because the scheduler may interrupt
|
|
|
|
|
assuan_send_data and an other thread may then re-read the table. */
|
|
|
|
|
lock_trusttable ();
|
|
|
|
|
for (ti=trusttable, len = trusttablesize; len; ti++, len--)
|
|
|
|
|
{
|
|
|
|
|
bin2hex (ti->fpr, 20, key);
|
|
|
|
|
key[40] = ' ';
|
|
|
|
|
key[41] = ti->keyflag;
|
|
|
|
|
key[42] = '\n';
|
|
|
|
|
assuan_send_data (assuan_context, key, 43);
|
|
|
|
|
assuan_send_data (assuan_context, NULL, 0); /* flush */
|
|
|
|
|
}
|
|
|
|
|
unlock_trusttable ();
|
2003-06-05 07:14:21 +00:00
|
|
|
|
}
|
2006-09-15 18:53:37 +00:00
|
|
|
|
|
|
|
|
|
return 0;
|
2003-06-05 07:14:21 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Insert the given fpr into our trustdb. We expect FPR to be an all
|
|
|
|
|
uppercase hexstring of 40 characters. FLAG is either 'P' or 'C'.
|
2004-05-03 13:37:38 +00:00
|
|
|
|
This function does first check whether that key has alreay been put
|
2003-06-05 07:14:21 +00:00
|
|
|
|
into the trustdb and returns success in this case. Before a FPR
|
|
|
|
|
actually gets inserted, the user is asked by means of the pin-entry
|
|
|
|
|
whether this is actual wants he want to do.
|
|
|
|
|
*/
|
2006-09-15 18:53:37 +00:00
|
|
|
|
gpg_error_t
|
2006-09-06 16:35:52 +00:00
|
|
|
|
agent_marktrusted (ctrl_t ctrl, const char *name, const char *fpr, int flag)
|
2003-06-05 07:14:21 +00:00
|
|
|
|
{
|
2006-09-15 18:53:37 +00:00
|
|
|
|
gpg_error_t err = 0;
|
2003-06-05 07:14:21 +00:00
|
|
|
|
char *desc;
|
2004-01-28 16:19:46 +00:00
|
|
|
|
char *fname;
|
2006-09-15 18:53:37 +00:00
|
|
|
|
FILE *fp;
|
2004-01-28 16:19:46 +00:00
|
|
|
|
|
|
|
|
|
/* Check whether we are at all allowed to modify the trustlist.
|
|
|
|
|
This is useful so that the trustlist may be a symlink to a global
|
|
|
|
|
trustlist with only admin priviliges to modify it. Of course
|
|
|
|
|
this is not a secure way of denying access, but it avoids the
|
2006-09-15 18:53:37 +00:00
|
|
|
|
usual clicking on an Okay button most users are used to. */
|
2004-01-28 16:19:46 +00:00
|
|
|
|
fname = make_filename (opt.homedir, "trustlist.txt", NULL);
|
2006-09-15 18:53:37 +00:00
|
|
|
|
if ( access (fname, W_OK) && errno != ENOENT)
|
2004-01-28 16:19:46 +00:00
|
|
|
|
{
|
|
|
|
|
xfree (fname);
|
|
|
|
|
return gpg_error (GPG_ERR_EPERM);
|
|
|
|
|
}
|
|
|
|
|
xfree (fname);
|
|
|
|
|
|
2006-09-15 18:53:37 +00:00
|
|
|
|
if (!agent_istrusted (fpr))
|
2003-06-05 07:14:21 +00:00
|
|
|
|
{
|
2006-09-15 18:53:37 +00:00
|
|
|
|
return 0; /* We already got this fingerprint. Silently return
|
|
|
|
|
success. */
|
2004-05-11 19:11:53 +00:00
|
|
|
|
}
|
2003-06-05 07:14:21 +00:00
|
|
|
|
|
2004-05-03 13:37:38 +00:00
|
|
|
|
/* This feature must explicitly been enabled. */
|
|
|
|
|
if (!opt.allow_mark_trusted)
|
2006-09-15 18:53:37 +00:00
|
|
|
|
return gpg_error (GPG_ERR_NOT_SUPPORTED);
|
2004-05-03 13:37:38 +00:00
|
|
|
|
|
2005-01-13 18:00:46 +00:00
|
|
|
|
/* Insert a new one. */
|
2003-06-05 07:14:21 +00:00
|
|
|
|
if (asprintf (&desc,
|
2005-01-13 18:00:46 +00:00
|
|
|
|
/* TRANSLATORS: This prompt is shown by the Pinentry
|
|
|
|
|
and has one special property: A "%%0A" is used by
|
|
|
|
|
Pinentry to insert a line break. The double
|
|
|
|
|
percent sign is actually needed because it is also
|
|
|
|
|
a printf format string. If you need to insert a
|
|
|
|
|
plain % sign, you need to encode it as "%%25". The
|
|
|
|
|
second "%s" gets replaced by a hexdecimal
|
|
|
|
|
fingerprint string whereas the first one receives
|
|
|
|
|
the name as store in the certificate. */
|
|
|
|
|
_("Please verify that the certificate identified as:%%0A"
|
|
|
|
|
" \"%s\"%%0A"
|
|
|
|
|
"has the fingerprint:%%0A"
|
|
|
|
|
" %s"), name, fpr) < 0 )
|
2006-09-15 18:53:37 +00:00
|
|
|
|
return out_of_core ();
|
2005-01-13 18:00:46 +00:00
|
|
|
|
|
|
|
|
|
/* TRANSLATORS: "Correct" is the label of a button and intended to
|
|
|
|
|
be hit if the fingerprint matches the one of the CA. The other
|
|
|
|
|
button is "the default "Cancel" of the Pinentry. */
|
2006-09-15 18:53:37 +00:00
|
|
|
|
err = agent_get_confirmation (ctrl, desc, _("Correct"), NULL);
|
2003-06-05 07:14:21 +00:00
|
|
|
|
free (desc);
|
2006-09-15 18:53:37 +00:00
|
|
|
|
if (err)
|
|
|
|
|
return err;
|
2003-06-05 07:14:21 +00:00
|
|
|
|
|
|
|
|
|
if (asprintf (&desc,
|
2005-01-13 18:00:46 +00:00
|
|
|
|
/* TRANSLATORS: This prompt is shown by the Pinentry
|
|
|
|
|
and has one special property: A "%%0A" is used by
|
|
|
|
|
Pinentry to insert a line break. The double
|
|
|
|
|
percent sign is actually needed because it is also
|
|
|
|
|
a printf format string. If you need to insert a
|
|
|
|
|
plain % sign, you need to encode it as "%%25". The
|
|
|
|
|
"%s" gets replaced by the name as store in the
|
|
|
|
|
certificate. */
|
|
|
|
|
_("Do you ultimately trust%%0A"
|
|
|
|
|
" \"%s\"%%0A"
|
|
|
|
|
"to correctly certify user certificates?"),
|
2003-06-05 07:14:21 +00:00
|
|
|
|
name) < 0 )
|
2006-09-15 18:53:37 +00:00
|
|
|
|
return out_of_core ();
|
|
|
|
|
|
|
|
|
|
err = agent_get_confirmation (ctrl, desc, _("Yes"), _("No"));
|
2003-06-05 07:14:21 +00:00
|
|
|
|
free (desc);
|
2006-09-15 18:53:37 +00:00
|
|
|
|
if (err)
|
|
|
|
|
return err;
|
|
|
|
|
|
|
|
|
|
/* Now check again to avoid duplicates. We take the lock to make
|
|
|
|
|
sure that nobody else plays with our file. Frankly we don't work
|
|
|
|
|
with the trusttable but using this lock is just fine for our
|
|
|
|
|
purpose. */
|
|
|
|
|
lock_trusttable ();
|
|
|
|
|
if (!agent_istrusted (fpr))
|
2004-05-11 19:11:53 +00:00
|
|
|
|
{
|
2006-09-15 18:53:37 +00:00
|
|
|
|
unlock_trusttable ();
|
|
|
|
|
return 0;
|
2004-05-11 19:11:53 +00:00
|
|
|
|
}
|
2003-06-05 07:14:21 +00:00
|
|
|
|
|
2006-09-15 18:53:37 +00:00
|
|
|
|
|
|
|
|
|
fname = make_filename (opt.homedir, "trustlist.txt", NULL);
|
|
|
|
|
if ( access (fname, F_OK) && errno == ENOENT)
|
2003-06-05 07:14:21 +00:00
|
|
|
|
{
|
2006-09-15 18:53:37 +00:00
|
|
|
|
fp = fopen (fname, "wx"); /* Warning: "x" is a GNU extension. */
|
|
|
|
|
if (!fp)
|
2004-05-11 19:11:53 +00:00
|
|
|
|
{
|
2006-09-15 18:53:37 +00:00
|
|
|
|
err = gpg_error_from_syserror ();
|
|
|
|
|
log_error ("can't create `%s': %s\n", fname, gpg_strerror (err));
|
|
|
|
|
xfree (fname);
|
|
|
|
|
unlock_trusttable ();
|
|
|
|
|
return err;
|
2004-05-11 19:11:53 +00:00
|
|
|
|
}
|
2006-09-15 18:53:37 +00:00
|
|
|
|
fputs (headerblurb, fp);
|
|
|
|
|
fclose (fp);
|
2003-06-05 07:14:21 +00:00
|
|
|
|
}
|
2006-09-15 18:53:37 +00:00
|
|
|
|
fp = fopen (fname, "a+");
|
|
|
|
|
if (!fp)
|
2003-06-05 07:14:21 +00:00
|
|
|
|
{
|
2006-09-15 18:53:37 +00:00
|
|
|
|
err = gpg_error_from_syserror ();
|
|
|
|
|
log_error ("can't open `%s': %s\n", fname, gpg_strerror (err));
|
|
|
|
|
xfree (fname);
|
|
|
|
|
unlock_trusttable ();
|
|
|
|
|
return err;
|
2003-06-05 07:14:21 +00:00
|
|
|
|
}
|
|
|
|
|
|
2004-05-11 19:11:53 +00:00
|
|
|
|
/* Append the key. */
|
2006-09-15 18:53:37 +00:00
|
|
|
|
fputs ("\n# ", fp);
|
|
|
|
|
print_sanitized_string (fp, name, 0);
|
|
|
|
|
fprintf (fp, "\n%s %c\n", fpr, flag);
|
|
|
|
|
if (ferror (fp))
|
|
|
|
|
err = gpg_error_from_syserror ();
|
2003-06-05 07:14:21 +00:00
|
|
|
|
|
2006-09-15 18:53:37 +00:00
|
|
|
|
if (fclose (fp))
|
|
|
|
|
err = gpg_error_from_syserror ();
|
2004-05-11 19:11:53 +00:00
|
|
|
|
|
2006-09-15 18:53:37 +00:00
|
|
|
|
if (!err)
|
|
|
|
|
agent_reload_trustlist ();
|
|
|
|
|
xfree (fname);
|
|
|
|
|
unlock_trusttable ();
|
|
|
|
|
return err;
|
2004-05-11 19:11:53 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2006-09-15 18:53:37 +00:00
|
|
|
|
/* This function may be called to force reloading of the
|
|
|
|
|
trustlist. */
|
2004-05-11 19:11:53 +00:00
|
|
|
|
void
|
|
|
|
|
agent_reload_trustlist (void)
|
|
|
|
|
{
|
2006-09-15 18:53:37 +00:00
|
|
|
|
/* All we need to do is to delete the trusttable. At the next
|
|
|
|
|
access it will get re-read. */
|
|
|
|
|
lock_trusttable ();
|
|
|
|
|
xfree (trusttable);
|
|
|
|
|
trusttable = NULL;
|
|
|
|
|
trusttablesize = 0;
|
|
|
|
|
unlock_trusttable ();
|
2004-05-11 19:11:53 +00:00
|
|
|
|
}
|