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