* trustlist.c: New.
[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 charcter 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 (void)
53 {
54   char *fname;
55
56   fname = make_filename (opt.homedir, "trustlist.txt", NULL);
57   trustfp = fopen (fname, "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, "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 ();
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 fr 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
224
225
226
227