~ubuntu-branches/ubuntu/jaunty/gnupg2/jaunty

« back to all changes in this revision

Viewing changes to agent/trustlist.c

  • Committer: Bazaar Package Importer
  • Author(s): Andreas Mueller
  • Date: 2005-03-29 10:30:32 UTC
  • Revision ID: james.westby@ubuntu.com-20050329103032-sj42n2ain3ipx310
Tags: upstream-1.9.15
ImportĀ upstreamĀ versionĀ 1.9.15

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* trustlist.c - Maintain the list of trusted keys
 
2
 *      Copyright (C) 2002, 2004 Free Software Foundation, Inc.
 
3
 *
 
4
 * This file is part of GnuPG.
 
5
 *
 
6
 * GnuPG is free software; you can redistribute it and/or modify
 
7
 * it under the terms of the GNU General Public License as published by
 
8
 * the Free Software Foundation; either version 2 of the License, or
 
9
 * (at your option) any later version.
 
10
 *
 
11
 * GnuPG is distributed in the hope that it will be useful,
 
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
14
 * GNU General Public License for more details.
 
15
 *
 
16
 * You should have received a copy of the GNU General Public License
 
17
 * along with this program; if not, write to the Free Software
 
18
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
 
19
 */
 
20
 
 
21
#include <config.h>
 
22
#include <errno.h>
 
23
#include <stdio.h>
 
24
#include <stdlib.h>
 
25
#include <string.h>
 
26
#include <ctype.h>
 
27
#include <assert.h>
 
28
#include <unistd.h>
 
29
#include <sys/stat.h>
 
30
 
 
31
#include "agent.h"
 
32
#include <assuan.h> /* fixme: need a way to avoid assuan calls here */
 
33
#include "i18n.h"
 
34
 
 
35
static const char headerblurb[] =
 
36
"# This is the list of trusted keys.  Comment lines, like this one, as\n"
 
37
"# well as empty lines are ignored. The entire file may be integrity\n"
 
38
"# protected by the use of a MAC, so changing the file does not make\n"
 
39
"# sense without the knowledge of the MAC key.  Lines do have a length\n"
 
40
"# limit but this is not serious limitation as the format of the\n"
 
41
"# entries is fixed and checked by gpg-agent: A non-comment line starts\n"
 
42
"# with optional white spaces, followed by the SHA-1 fingerpint in hex,\n"
 
43
"# optionally followed by a flag character which my either be 'P', 'S'\n"
 
44
"# or '*'. Additional data, delimited by white space, is ignored.\n"
 
45
"#\n"
 
46
"# NOTE: You should give the gpg-agent a HUP after editing this file.\n"
 
47
"\n";
 
48
 
 
49
 
 
50
static FILE *trustfp;
 
51
static int   trustfp_used; /* Counter to track usage of TRUSTFP. */
 
52
static int   reload_trustlist_pending;
 
53
 
 
54
 
 
55
static int
 
56
open_list (int append)
 
57
{
 
58
  char *fname;
 
59
 
 
60
  fname = make_filename (opt.homedir, "trustlist.txt", NULL);
 
61
  trustfp = fopen (fname, append? "a+":"r");
 
62
  if (!trustfp && errno == ENOENT)
 
63
    {
 
64
      trustfp = fopen (fname, "wx");
 
65
      if (!trustfp)
 
66
        {
 
67
          gpg_error_t tmperr = gpg_error (gpg_err_code_from_errno (errno));
 
68
          log_error ("can't create `%s': %s\n", fname, strerror (errno));
 
69
          xfree (fname);
 
70
          return tmperr;
 
71
        }
 
72
      fputs (headerblurb, trustfp);
 
73
      fclose (trustfp);
 
74
      trustfp = fopen (fname, append? "a+":"r");
 
75
    }
 
76
 
 
77
  if (!trustfp)
 
78
    {
 
79
      gpg_error_t tmperr = gpg_error (gpg_err_code_from_errno (errno));
 
80
      log_error ("can't open `%s': %s\n", fname, strerror (errno));
 
81
      xfree (fname);
 
82
      return tmperr;
 
83
    }
 
84
 
 
85
  /*FIXME: check the MAC */
 
86
 
 
87
  return 0;
 
88
}
 
89
 
 
90
 
 
91
 
 
92
/* Read the trustlist and return entry by entry.  KEY must point to a
 
93
   buffer of at least 41 characters. KEYFLAG does return either 'P',
 
94
   'S' or '*'.
 
95
 
 
96
   Reading a valid entry return 0, EOF returns -1 any other error
 
97
   returns the appropriate error code. */
 
98
static int
 
99
read_list (char *key, int *keyflag)
 
100
{
 
101
  int rc;
 
102
  int c, i, j;
 
103
  char *p, line[256];
 
104
  
 
105
  if (!trustfp)
 
106
    {
 
107
      rc = open_list (0);
 
108
      if (rc)
 
109
        return rc;
 
110
    }
 
111
 
 
112
  do
 
113
    {
 
114
      if (!fgets (line, DIM(line)-1, trustfp) )
 
115
        {
 
116
          if (feof (trustfp))
 
117
            return -1;
 
118
          return gpg_error (gpg_err_code_from_errno (errno));
 
119
        }
 
120
      
 
121
      if (!*line || line[strlen(line)-1] != '\n')
 
122
        {
 
123
          /* eat until end of line */
 
124
          while ( (c=getc (trustfp)) != EOF && c != '\n')
 
125
            ;
 
126
          return gpg_error (*line? GPG_ERR_LINE_TOO_LONG
 
127
                                 : GPG_ERR_INCOMPLETE_LINE);
 
128
        }
 
129
      
 
130
      /* Allow for empty lines and spaces */
 
131
      for (p=line; spacep (p); p++)
 
132
        ;
 
133
    }
 
134
  while (!*p || *p == '\n' || *p == '#');
 
135
  
 
136
  for (i=j=0; (p[i] == ':' || hexdigitp (p+i)) && j < 40; i++)
 
137
    if ( p[i] != ':' )
 
138
      key[j++] = p[i] >= 'a'? (p[i] & 0xdf): p[i];
 
139
  key[j] = 0;
 
140
  if (j!=40 || !(spacep (p+i) || p[i] == '\n'))
 
141
    {
 
142
      log_error ("invalid formatted fingerprint in trustlist\n");
 
143
      return gpg_error (GPG_ERR_BAD_DATA);
 
144
    }
 
145
  assert (p[i]);
 
146
  if (p[i] == '\n')
 
147
    *keyflag = '*';
 
148
  else 
 
149
    {
 
150
      i++;
 
151
      if ( p[i] == 'P' || p[i] == 'p')
 
152
        *keyflag = 'P';
 
153
      else if ( p[i] == 'S' || p[i] == 's')
 
154
        *keyflag = 'S';
 
155
      else if ( p[i] == '*')
 
156
        *keyflag = '*';
 
157
      else
 
158
        {
 
159
          log_error ("invalid keyflag in trustlist\n");
 
160
          return gpg_error (GPG_ERR_BAD_DATA);
 
161
        }
 
162
      i++;
 
163
      if ( !(spacep (p+i) || p[i] == '\n'))
 
164
        {
 
165
          log_error ("invalid keyflag in trustlist\n");
 
166
          return gpg_error (GPG_ERR_BAD_DATA);
 
167
        }
 
168
    }
 
169
 
 
170
  return 0;
 
171
}
 
172
 
 
173
/* Check whether the given fpr is in our trustdb.  We expect FPR to be
 
174
   an all uppercase hexstring of 40 characters. */
 
175
int 
 
176
agent_istrusted (const char *fpr)
 
177
{
 
178
  int rc;
 
179
  static char key[41];
 
180
  int keyflag;
 
181
 
 
182
  trustfp_used++;
 
183
  if (trustfp)
 
184
    rewind (trustfp);
 
185
  while (!(rc=read_list (key, &keyflag)))
 
186
    {
 
187
      if (!strcmp (key, fpr))
 
188
        {
 
189
          trustfp_used--;
 
190
          return 0;
 
191
        }
 
192
    }
 
193
  if (rc != -1)
 
194
    {
 
195
      /* Error in the trustdb - close it to give the user a chance for
 
196
         correction */
 
197
      if (trustfp)
 
198
        fclose (trustfp);
 
199
      trustfp = NULL;
 
200
    }
 
201
  trustfp_used--;
 
202
  return rc;
 
203
}
 
204
 
 
205
 
 
206
/* Write all trust entries to FP. */
 
207
int 
 
208
agent_listtrusted (void *assuan_context)
 
209
{
 
210
  int rc;
 
211
  static char key[51];
 
212
  int keyflag;
 
213
 
 
214
  trustfp_used++;
 
215
  if (trustfp)
 
216
    rewind (trustfp);
 
217
  while (!(rc=read_list (key, &keyflag)))
 
218
    {
 
219
      key[40] = ' ';
 
220
      key[41] = keyflag;
 
221
      key[42] = '\n';
 
222
      assuan_send_data (assuan_context, key, 43);
 
223
      assuan_send_data (assuan_context, NULL, 0); /* flush */
 
224
    } 
 
225
  if (rc == -1)
 
226
    rc = 0;
 
227
  if (rc)
 
228
    {
 
229
      /* Error in the trustdb - close it to give the user a chance for
 
230
         correction */
 
231
      if (trustfp)
 
232
        fclose (trustfp);
 
233
      trustfp = NULL;
 
234
    }
 
235
  trustfp_used--;
 
236
  return rc;
 
237
}
 
238
 
 
239
 
 
240
/* Insert the given fpr into our trustdb.  We expect FPR to be an all
 
241
   uppercase hexstring of 40 characters. FLAG is either 'P' or 'C'.
 
242
   This function does first check whether that key has alreay been put
 
243
   into the trustdb and returns success in this case.  Before a FPR
 
244
   actually gets inserted, the user is asked by means of the pin-entry
 
245
   whether this is actual wants he want to do.
 
246
*/
 
247
int 
 
248
agent_marktrusted (CTRL ctrl, const char *name, const char *fpr, int flag)
 
249
{
 
250
  int rc;
 
251
  static char key[41];
 
252
  int keyflag;
 
253
  char *desc;
 
254
  char *fname;
 
255
 
 
256
  /* Check whether we are at all allowed to modify the trustlist.
 
257
     This is useful so that the trustlist may be a symlink to a global
 
258
     trustlist with only admin priviliges to modify it.  Of course
 
259
     this is not a secure way of denying access, but it avoids the
 
260
     usual clicking on an Okay buttun thing most users are used to. */
 
261
  fname = make_filename (opt.homedir, "trustlist.txt", NULL);
 
262
  rc = access (fname, W_OK);
 
263
  if (rc && errno != ENOENT)
 
264
    {
 
265
      xfree (fname);
 
266
      return gpg_error (GPG_ERR_EPERM);
 
267
    }    
 
268
  xfree (fname);
 
269
 
 
270
  trustfp_used++;
 
271
  if (trustfp)
 
272
    rewind (trustfp);
 
273
  while (!(rc=read_list (key, &keyflag)))
 
274
    {
 
275
      if (!strcmp (key, fpr))
 
276
        return 0;
 
277
    }
 
278
  if (trustfp)
 
279
    fclose (trustfp);
 
280
  trustfp = NULL;
 
281
  if (rc != -1)
 
282
    {
 
283
      trustfp_used--;
 
284
      return rc;   /* Error in the trustlist. */
 
285
    }
 
286
 
 
287
  /* This feature must explicitly been enabled. */
 
288
  if (!opt.allow_mark_trusted)
 
289
    {
 
290
      trustfp_used--;
 
291
      return gpg_error (GPG_ERR_NOT_SUPPORTED);
 
292
    }
 
293
 
 
294
  /* Insert a new one. */
 
295
  if (asprintf (&desc,
 
296
                /* TRANSLATORS: This prompt is shown by the Pinentry
 
297
                   and has one special property: A "%%0A" is used by
 
298
                   Pinentry to insert a line break.  The double
 
299
                   percent sign is actually needed because it is also
 
300
                   a printf format string.  If you need to insert a
 
301
                   plain % sign, you need to encode it as "%%25".  The
 
302
                   second "%s" gets replaced by a hexdecimal
 
303
                   fingerprint string whereas the first one receives
 
304
                   the name as store in the certificate. */
 
305
                _("Please verify that the certificate identified as:%%0A"
 
306
                  "  \"%s\"%%0A"
 
307
                  "has the fingerprint:%%0A"
 
308
                  "  %s"), name, fpr) < 0 )
 
309
    {
 
310
      trustfp_used--;
 
311
      return out_of_core ();
 
312
    }
 
313
 
 
314
  /* TRANSLATORS: "Correct" is the label of a button and intended to
 
315
     be hit if the fingerprint matches the one of the CA.  The other
 
316
     button is "the default "Cancel" of the Pinentry. */
 
317
  rc = agent_get_confirmation (ctrl, desc, _("Correct"), NULL);
 
318
  free (desc);
 
319
  if (rc)
 
320
    {
 
321
      trustfp_used--;
 
322
      return rc;
 
323
    }
 
324
 
 
325
  if (asprintf (&desc,
 
326
                /* TRANSLATORS: This prompt is shown by the Pinentry
 
327
                   and has one special property: A "%%0A" is used by
 
328
                   Pinentry to insert a line break.  The double
 
329
                   percent sign is actually needed because it is also
 
330
                   a printf format string.  If you need to insert a
 
331
                   plain % sign, you need to encode it as "%%25".  The
 
332
                   "%s" gets replaced by the name as store in the
 
333
                   certificate. */
 
334
                _("Do you ultimately trust%%0A"
 
335
                  "  \"%s\"%%0A"
 
336
                  "to correctly certify user certificates?"),
 
337
                name) < 0 )
 
338
    {
 
339
      trustfp_used--;
 
340
      return out_of_core ();
 
341
    }
 
342
  rc = agent_get_confirmation (ctrl, desc, _("Yes"), _("No"));
 
343
  free (desc);
 
344
  if (rc)
 
345
    {
 
346
      trustfp_used--;
 
347
      return rc;
 
348
    }
 
349
 
 
350
  /* Now check again to avoid duplicates.  Also open in append mode now. */
 
351
  rc = open_list (1);
 
352
  if (rc)
 
353
    {
 
354
      trustfp_used--;
 
355
      return rc;
 
356
    }
 
357
  rewind (trustfp);
 
358
  while (!(rc=read_list (key, &keyflag)))
 
359
    {
 
360
      if (!strcmp (key, fpr))
 
361
        {
 
362
          trustfp_used--;
 
363
          return 0;
 
364
        }
 
365
    }
 
366
  if (rc != -1)
 
367
    {
 
368
      if (trustfp)
 
369
        fclose (trustfp);
 
370
      trustfp = NULL;
 
371
      trustfp_used--;
 
372
      return rc;   /* Error in the trustlist. */
 
373
    }
 
374
  rc = 0;
 
375
 
 
376
  /* Append the key. */
 
377
  fflush (trustfp);
 
378
  fputs ("\n# ", trustfp);
 
379
  print_sanitized_string (trustfp, name, 0);
 
380
  fprintf (trustfp, "\n%s %c\n", fpr, flag);
 
381
  if (ferror (trustfp))
 
382
    rc = gpg_error (gpg_err_code_from_errno (errno));
 
383
  
 
384
  /* close because we are in append mode */
 
385
  if (fclose (trustfp))
 
386
    rc = gpg_error (gpg_err_code_from_errno (errno));
 
387
  trustfp = NULL;
 
388
  trustfp_used--;
 
389
  return rc;
 
390
}
 
391
 
 
392
 
 
393
void
 
394
agent_trustlist_housekeeping (void)
 
395
{
 
396
  if (reload_trustlist_pending && !trustfp_used)
 
397
    {
 
398
      if (trustfp)
 
399
        {
 
400
          fclose (trustfp);
 
401
          trustfp = NULL;
 
402
        }
 
403
      reload_trustlist_pending = 0;
 
404
    }
 
405
}
 
406
 
 
407
 
 
408
/* Not all editors are editing files in place, thus a changes
 
409
   trustlist.txt won't be recognozed if we keep the file descriptor
 
410
   open. This function may be used to explicitly close that file
 
411
   descriptor, which will force a reopen in turn. */
 
412
void
 
413
agent_reload_trustlist (void)
 
414
{
 
415
  reload_trustlist_pending = 1;
 
416
  agent_trustlist_housekeeping ();
 
417
}