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