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