(main): Implemented --gpgconf-list.
[gnupg.git] / agent / trustlist.c
1 /* trustlist.c - Maintain the list of trusted keys
2  *      Copyright (C) 2002 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 "\n";
45
46
47 static FILE *trustfp;
48
49
50 static int
51 open_list (int append)
52 {
53   char *fname;
54
55   fname = make_filename (opt.homedir, "trustlist.txt", NULL);
56   trustfp = fopen (fname, append? "a+":"r");
57   if (!trustfp && errno == ENOENT)
58     {
59       trustfp = fopen (fname, "wx");
60       if (!trustfp)
61         {
62           gpg_error_t tmperr = gpg_error (gpg_err_code_from_errno (errno));
63           log_error ("can't create `%s': %s\n", fname, strerror (errno));
64           xfree (fname);
65           return tmperr;
66         }
67       fputs (headerblurb, trustfp);
68       fclose (trustfp);
69       trustfp = fopen (fname, append? "a+":"r");
70     }
71
72   if (!trustfp)
73     {
74       gpg_error_t tmperr = gpg_error (gpg_err_code_from_errno (errno));
75       log_error ("can't open `%s': %s\n", fname, strerror (errno));
76       xfree (fname);
77       return tmperr;
78     }
79
80   /*FIXME: check the MAC */
81
82   return 0;
83 }
84
85
86
87 /* Read the trustlist and return entry by entry.  KEY must point to a
88    buffer of at least 41 characters. KEYFLAG does return either 'P',
89    'S' or '*'.
90
91    Reading a valid entry return 0, EOF returns -1 any other error
92    returns the appropriate error code. */
93 static int
94 read_list (char *key, int *keyflag)
95 {
96   int rc;
97   int c, i;
98   char *p, line[256];
99   
100   if (!trustfp)
101     {
102       rc = open_list (0);
103       if (rc)
104         return rc;
105     }
106
107   do
108     {
109       if (!fgets (line, DIM(line)-1, trustfp) )
110         {
111           if (feof (trustfp))
112             return -1;
113           return gpg_error (gpg_err_code_from_errno (errno));
114         }
115       
116       if (!*line || line[strlen(line)-1] != '\n')
117         {
118           /* eat until end of line */
119           while ( (c=getc (trustfp)) != EOF && c != '\n')
120             ;
121           return gpg_error (*line? GPG_ERR_LINE_TOO_LONG
122                                  : GPG_ERR_INCOMPLETE_LINE);
123         }
124       
125       /* Allow for emty lines and spaces */
126       for (p=line; spacep (p); p++)
127         ;
128     }
129   while (!*p || *p == '\n' || *p == '#');
130   
131   for (i=0; hexdigitp (p+i) && i < 40; i++)
132     key[i] = p[i] >= 'a'? (p[i] & 0xdf): p[i];
133   key[i] = 0;
134   if (i!=40 || !(spacep (p+i) || p[i] == '\n'))
135     {
136       log_error ("invalid formatted fingerprint in trustlist\n");
137       return gpg_error (GPG_ERR_BAD_DATA);
138     }
139   assert (p[i]);
140   if (p[i] == '\n')
141     *keyflag = '*';
142   else 
143     {
144       i++;
145       if ( p[i] == 'P' || p[i] == 'p')
146         *keyflag = 'P';
147       else if ( p[i] == 'S' || p[i] == 's')
148         *keyflag = 'S';
149       else if ( p[i] == '*')
150         *keyflag = '*';
151       else
152         {
153           log_error ("invalid keyflag in trustlist\n");
154           return gpg_error (GPG_ERR_BAD_DATA);
155         }
156       i++;
157       if ( !(spacep (p+i) || p[i] == '\n'))
158         {
159           log_error ("invalid keyflag in trustlist\n");
160           return gpg_error (GPG_ERR_BAD_DATA);
161         }
162     }
163
164   return 0;
165 }
166
167 /* check whether the given fpr is in our trustdb.  We expect FPR to be
168    an all uppercase hexstring of 40 characters. */
169 int 
170 agent_istrusted (const char *fpr)
171 {
172   int rc;
173   static char key[41];
174   int keyflag;
175
176   if (trustfp)
177     rewind (trustfp);
178   while (!(rc=read_list (key, &keyflag)))
179     {
180       if (!strcmp (key, fpr))
181         return 0;
182     }
183   if (rc != -1)
184     {
185       /* error in the trustdb - close it to give the user a chance for
186          correction */
187       fclose (trustfp);
188       trustfp = NULL;
189     }
190   return rc;
191 }
192
193
194 /* write all trust entries to FP */
195 int 
196 agent_listtrusted (void *assuan_context)
197 {
198   int rc;
199   static char key[51];
200   int keyflag;
201
202   if (trustfp)
203     rewind (trustfp);
204   while (!(rc=read_list (key, &keyflag)))
205     {
206       key[40] = ' ';
207       key[41] = keyflag;
208       key[42] = '\n';
209       assuan_send_data (assuan_context, key, 43);
210       assuan_send_data (assuan_context, NULL, 0); /* flush */
211     } 
212   if (rc == -1)
213     rc = 0;
214   if (rc)
215     {
216       /* error in the trustdb - close it to give the user a chance for
217          correction */
218       fclose (trustfp);
219       trustfp = NULL;
220     }
221   return rc;
222 }
223
224
225 /* Insert the given fpr into our trustdb.  We expect FPR to be an all
226    uppercase hexstring of 40 characters. FLAG is either 'P' or 'C'.
227    This function does first check whether that key has alreay ben put
228    into the trustdb and returns success in this case.  Before a FPR
229    actually gets inserted, the user is asked by means of the pin-entry
230    whether this is actual wants he want to do.
231 */
232 int 
233 agent_marktrusted (CTRL ctrl, const char *name, const char *fpr, int flag)
234 {
235   int rc;
236   static char key[41];
237   int keyflag;
238   char *desc;
239   char *fname;
240
241   /* Check whether we are at all allowed to modify the trustlist.
242      This is useful so that the trustlist may be a symlink to a global
243      trustlist with only admin priviliges to modify it.  Of course
244      this is not a secure way of denying access, but it avoids the
245      usual clicking on an Okay buttun thing most users are used to. */
246   fname = make_filename (opt.homedir, "trustlist.txt", NULL);
247   rc = access (fname, W_OK);
248   if (rc && errno != ENOENT)
249     {
250       xfree (fname);
251       return gpg_error (GPG_ERR_EPERM);
252     }    
253   xfree (fname);
254
255
256   if (trustfp)
257     rewind (trustfp);
258   while (!(rc=read_list (key, &keyflag)))
259     {
260       if (!strcmp (key, fpr))
261         return 0;
262     }
263   fclose (trustfp);
264   trustfp = NULL;
265   if (rc != -1)
266     return rc;   /* error in the trustdb */
267
268   /* insert a new one */
269   if (asprintf (&desc,
270                 "Please verify that the certificate identified as:%%0A"
271                 "  \"%s\"%%0A"
272                 "has the fingerprint:%%0A"
273                 "  %s", name, fpr) < 0 )
274     return out_of_core ();
275   rc = agent_get_confirmation (ctrl, desc, "Correct", "No");
276   free (desc);
277   if (rc)
278     return rc;
279
280   if (asprintf (&desc,
281                 "Do you ultimately trust%%0A"
282                 "  \"%s\"%%0A"
283                 "to correctly certify user certificates?",
284                 name) < 0 )
285     return out_of_core ();
286   rc = agent_get_confirmation (ctrl, desc, "Yes", "No");
287   free (desc);
288   if (rc)
289     return rc;
290
291   /* now check again to avoid duplicates.  Also open in append mode now */
292   rc = open_list (1);
293   if (rc)
294     return rc;
295   rewind (trustfp);
296   while (!(rc=read_list (key, &keyflag)))
297     {
298       if (!strcmp (key, fpr))
299         return 0;
300     }
301   if (rc != -1)
302     {
303       fclose (trustfp);
304       trustfp = NULL;
305       return rc;   /* error in the trustdb */
306     }
307   rc = 0;
308
309   /* append the key */
310   fflush (trustfp);
311   fputs ("\n# ", trustfp);
312   print_sanitized_string (trustfp, name, 0);
313   fprintf (trustfp, "\n%s %c\n", fpr, flag);
314   if (ferror (trustfp))
315     rc = gpg_error (gpg_err_code_from_errno (errno));
316   
317   /* close because we are in append mode */
318   if (fclose (trustfp))
319     rc = gpg_error (gpg_err_code_from_errno (errno));
320   trustfp = NULL;
321   return rc;
322 }