* Manifest: New.
[gnupg.git] / sm / import.c
1 /* import.c - Import certificates
2  *      Copyright (C) 2001, 2003 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 <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <errno.h>
26 #include <unistd.h> 
27 #include <time.h>
28 #include <assert.h>
29
30 #include "gpgsm.h"
31 #include <gcrypt.h>
32 #include <ksba.h>
33
34 #include "keydb.h"
35 #include "i18n.h"
36
37 struct stats_s {
38   unsigned long count;
39   unsigned long imported;
40   unsigned long unchanged;
41   unsigned long not_imported;
42 };
43
44
45
46 static void
47 print_imported_status (CTRL ctrl, ksba_cert_t cert)
48 {
49   char *fpr;
50  
51   fpr = gpgsm_get_fingerprint_hexstring (cert, GCRY_MD_SHA1);
52   gpgsm_status2 (ctrl, STATUS_IMPORTED, fpr, "[X.509]", NULL);
53   xfree (fpr);
54 }
55
56
57 /* Print an IMPORT_PROBLEM status.  REASON is one of:
58    0 := "No specific reason given".
59    1 := "Invalid Certificate".
60    2 := "Issuer Certificate missing".
61    3 := "Certificate Chain too long".
62    4 := "Error storing certificate".
63 */
64 static void
65 print_import_problem (CTRL ctrl, ksba_cert_t cert, int reason)
66 {
67   char *fpr = NULL;
68   char buf[25];
69   int i;
70
71   sprintf (buf, "%d", reason);
72   if (cert)
73     {
74       fpr = gpgsm_get_fingerprint_hexstring (cert, GCRY_MD_SHA1);
75       /* detetect an error (all high) value */
76       for (i=0; fpr[i] == 'F'; i++)
77         ;
78       if (!fpr[i])
79         {
80           xfree (fpr);
81           fpr = NULL;
82         }
83     }
84   gpgsm_status2 (ctrl, STATUS_IMPORT_PROBLEM, buf, fpr, NULL);
85   xfree (fpr);
86 }
87
88
89 void
90 print_imported_summary (CTRL ctrl, struct stats_s *stats)
91 {
92   char buf[14*25];
93
94   if (!opt.quiet)
95     {
96       log_info (_("total number processed: %lu\n"), stats->count);
97       if (stats->imported) 
98         {
99           log_info (_("              imported: %lu"), stats->imported );
100           log_printf ("\n");
101         }
102       if (stats->unchanged)
103         log_info (_("             unchanged: %lu\n"), stats->unchanged);
104       if (stats->not_imported)
105         log_info (_("          not imported: %lu\n"), stats->not_imported);
106     }
107
108   sprintf (buf, "%lu 0 %lu 0 %lu 0 0 0 0 0 0 0 0 %lu",
109            stats->count,
110            stats->imported,
111            stats->unchanged,
112            stats->not_imported
113            );
114   gpgsm_status (ctrl, STATUS_IMPORT_RES, buf);
115 }
116
117
118
119 static void
120 check_and_store (CTRL ctrl, struct stats_s *stats, ksba_cert_t cert, int depth)
121 {
122   int rc;
123
124   stats->count++;
125   if ( depth >= 50 )
126     {
127       log_error (_("certificate chain too long\n"));
128       stats->not_imported++;
129       print_import_problem (ctrl, cert, 3);
130       return;
131     }
132
133   rc = gpgsm_basic_cert_check (cert);
134   if (!rc)
135     {
136       int existed;
137
138       if (!keydb_store_cert (cert, 0, &existed))
139         {
140           ksba_cert_t next = NULL;
141
142           if (!existed)
143             {
144               print_imported_status (ctrl, cert);
145               stats->imported++;
146             }
147           else
148             stats->unchanged++;
149             
150           if (opt.verbose > 1 && existed)
151             {
152               if (depth)
153                 log_info ("issuer certificate already in DB\n");
154               else
155                 log_info ("certificate already in DB\n");
156             }
157           else if (opt.verbose && !existed)
158             {
159               if (depth)
160                 log_info ("issuer certificate imported\n");
161               else
162                 log_info ("certificate imported\n");
163             }
164           /* Now lets walk up the chain and import all certificates up
165              the chain.*/
166           else if (!gpgsm_walk_cert_chain (cert, &next))
167             {
168               check_and_store (ctrl, stats, next, depth+1);
169               ksba_cert_release (next);
170             }
171         }
172       else
173         {
174           log_error (_("error storing certificate\n"));
175           stats->not_imported++;
176           print_import_problem (ctrl, cert, 4);
177         }
178     }
179   else
180     {
181       log_error (_("basic certificate checks failed - not imported\n"));
182       stats->not_imported++;
183       print_import_problem (ctrl, cert,
184                             gpg_err_code (rc) == GPG_ERR_MISSING_CERT? 2 :
185                             gpg_err_code (rc) == GPG_ERR_BAD_CERT?     1 : 0);
186     }
187 }
188
189
190 \f
191
192 static int
193 import_one (CTRL ctrl, struct stats_s *stats, int in_fd)
194 {
195   int rc;
196   Base64Context b64reader = NULL;
197   ksba_reader_t reader;
198   ksba_cert_t cert = NULL;
199   ksba_cms_t cms = NULL;
200   FILE *fp = NULL;
201   ksba_content_type_t ct;
202
203   fp = fdopen ( dup (in_fd), "rb");
204   if (!fp)
205     {
206       rc = gpg_error (gpg_err_code_from_errno (errno));
207       log_error ("fdopen() failed: %s\n", strerror (errno));
208       goto leave;
209     }
210
211   rc = gpgsm_create_reader (&b64reader, ctrl, fp, &reader);
212   if (rc)
213     {
214       log_error ("can't create reader: %s\n", gpg_strerror (rc));
215       goto leave;
216     }
217
218   ct = ksba_cms_identify (reader);
219   if (ct == KSBA_CT_SIGNED_DATA)
220     { /* This is probably a signed-only message - import the certs */
221       ksba_stop_reason_t stopreason;
222       int i;
223
224       rc = ksba_cms_new (&cms);
225       if (rc)
226         goto leave;
227
228       rc = ksba_cms_set_reader_writer (cms, reader, NULL);
229       if (rc)
230         {
231           log_error ("ksba_cms_set_reader_writer failed: %s\n",
232                      gpg_strerror (rc));
233           goto leave;
234         }
235
236
237       do 
238         {
239           rc = ksba_cms_parse (cms, &stopreason);
240           if (rc)
241             {
242               log_error ("ksba_cms_parse failed: %s\n", gpg_strerror (rc));
243               goto leave;
244             }
245
246           if (stopreason == KSBA_SR_BEGIN_DATA)
247               log_info ("not a certs-only message\n");
248         }
249       while (stopreason != KSBA_SR_READY);   
250       
251       for (i=0; (cert=ksba_cms_get_cert (cms, i)); i++)
252         {
253           check_and_store (ctrl, stats, cert, 0);
254           ksba_cert_release (cert); 
255           cert = NULL;
256         }
257       if (!i)
258         log_error ("no certificate found\n");
259     }
260   else if (ct == KSBA_CT_NONE)
261     { /* Failed to identify this message - assume a certificate */
262
263       rc = ksba_cert_new (&cert);
264       if (rc)
265         goto leave;
266
267       rc = ksba_cert_read_der (cert, reader);
268       if (rc)
269         goto leave;
270
271       check_and_store (ctrl, stats, cert, 0);
272     }
273   else
274     {
275       log_error ("can't extract certificates from input\n");
276       rc = gpg_error (GPG_ERR_NO_DATA);
277     }
278    
279  leave:
280   ksba_cms_release (cms);
281   ksba_cert_release (cert);
282   gpgsm_destroy_reader (b64reader);
283   if (fp)
284     fclose (fp);
285   return rc;
286 }
287
288
289 int
290 gpgsm_import (CTRL ctrl, int in_fd)
291 {
292   int rc;
293   struct stats_s stats;
294
295   memset (&stats, 0, sizeof stats);
296   rc = import_one (ctrl, &stats, in_fd);
297   print_imported_summary (ctrl, &stats);
298   /* If we never printed an error message do it now so that a command
299      line invocation will return with an error (log_error keeps a
300      global errorcount) */
301   if (rc && !log_get_errorcount (0))
302     log_error (_("error importing certificate: %s\n"), gpg_strerror (rc));
303   return rc;
304 }
305
306
307 int
308 gpgsm_import_files (CTRL ctrl, int nfiles, char **files,
309                     int (*of)(const char *fname))
310 {
311   int rc = 0;
312   struct stats_s stats;
313
314   memset (&stats, 0, sizeof stats);
315   
316   if (!nfiles)
317     rc = import_one (ctrl, &stats, 0);
318   else
319     {
320       for (; nfiles && !rc ; nfiles--, files++)
321         {
322           int fd = of (*files);
323           rc = import_one (ctrl, &stats, fd);
324           close (fd);
325           if (rc == -1)
326             rc = 0;
327         }
328     }
329   print_imported_summary (ctrl, &stats);
330   /* If we never printed an error message do it now so that a command
331      line invocation will return with an error (log_error keeps a
332      global errorcount) */
333   if (rc && !log_get_errorcount (0))
334     log_error (_("error importing certificate: %s\n"), gpg_strerror (rc));
335   return rc;
336 }
337
338