Fix SIGPIPE ignoring regression.
[gpgme.git] / src / decrypt.c
1 /* decrypt.c - Decrypt function.
2    Copyright (C) 2000 Werner Koch (dd9jn)
3    Copyright (C) 2001, 2002, 2003, 2004 g10 Code GmbH
4
5    This file is part of GPGME.
6  
7    GPGME is free software; you can redistribute it and/or modify it
8    under the terms of the GNU Lesser General Public License as
9    published by the Free Software Foundation; either version 2.1 of
10    the License, or (at your option) any later version.
11    
12    GPGME is distributed in the hope that it will be useful, but
13    WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15    Lesser General Public License for more details.
16    
17    You should have received a copy of the GNU Lesser General Public
18    License along with this program; if not, write to the Free Software
19    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
20    02111-1307, USA.  */
21
22 #if HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25 #include <stdlib.h>
26 #include <string.h>
27 #include <errno.h>
28
29 #include "gpgme.h"
30 #include "util.h"
31 #include "context.h"
32 #include "ops.h"
33
34 \f
35 typedef struct
36 {
37   struct _gpgme_op_decrypt_result result;
38
39   int okay;
40   int failed;
41   
42   /* A pointer to the next pointer of the last recipient in the list.
43      This makes appending new invalid signers painless while
44      preserving the order.  */
45   gpgme_recipient_t *last_recipient_p;
46 } *op_data_t;
47
48
49 static void
50 release_op_data (void *hook)
51 {
52   op_data_t opd = (op_data_t) hook;
53   gpgme_recipient_t recipient = opd->result.recipients;
54
55   if (opd->result.unsupported_algorithm)
56     free (opd->result.unsupported_algorithm);
57
58   if (opd->result.file_name)
59     free (opd->result.file_name);
60
61   while (recipient)
62     {
63       gpgme_recipient_t next = recipient->next;
64       free (recipient);
65       recipient = next;
66     }
67 }
68
69
70 gpgme_decrypt_result_t
71 gpgme_op_decrypt_result (gpgme_ctx_t ctx)
72 {
73   void *hook;
74   op_data_t opd;
75   gpgme_error_t err;
76
77   err = _gpgme_op_data_lookup (ctx, OPDATA_DECRYPT, &hook, -1, NULL);
78   opd = hook;
79   if (err || !opd)
80     return NULL;
81
82   return &opd->result;
83 }
84
85 \f
86 static gpgme_error_t
87 parse_enc_to (char *args, gpgme_recipient_t *recp)
88 {
89   gpgme_recipient_t rec;
90   char *tail;
91   int i;
92
93   rec = malloc (sizeof (*rec));
94   if (!rec)
95     return gpg_error_from_errno (errno);
96
97   rec->next = NULL;
98   rec->keyid = rec->_keyid;
99   rec->status = 0;
100
101   for (i = 0; i < sizeof (rec->_keyid) - 1; i++)
102     {
103       if (args[i] == '\0' || args[i] == ' ')
104         break;
105
106       rec->_keyid[i] = args[i];
107     }
108   rec->_keyid[i] = '\0';
109
110   args = &args[i];
111   if (*args != '\0' && *args != ' ')
112     {
113       free (rec);
114       return gpg_error (GPG_ERR_INV_ENGINE);
115     }
116
117   while (*args == ' ')
118     args++;
119
120   if (*args)
121     {
122       errno = 0;
123       rec->pubkey_algo = strtol (args, &tail, 0);
124       if (errno || args == tail || *tail != ' ')
125         {
126           /* The crypto backend does not behave.  */
127           free (rec);
128           return gpg_error (GPG_ERR_INV_ENGINE);
129         }
130     }
131
132   /* FIXME: The key length is always 0 right now, so no need to parse
133      it.  */
134
135   *recp = rec;
136   return 0;
137 }
138
139
140 gpgme_error_t
141 _gpgme_decrypt_status_handler (void *priv, gpgme_status_code_t code,
142                                char *args)
143 {
144   gpgme_ctx_t ctx = (gpgme_ctx_t) priv;
145   gpgme_error_t err;
146   void *hook;
147   op_data_t opd;
148
149   err = _gpgme_passphrase_status_handler (priv, code, args);
150   if (err)
151     return err;
152
153   err = _gpgme_op_data_lookup (ctx, OPDATA_DECRYPT, &hook, -1, NULL);
154   opd = hook;
155   if (err)
156     return err;
157
158   switch (code)
159     {
160     case GPGME_STATUS_EOF:
161       /* FIXME: These error values should probably be attributed to
162          the underlying crypto engine (as error source).  */
163       if (opd->failed)
164         return gpg_error (GPG_ERR_DECRYPT_FAILED);
165       else if (!opd->okay)
166         return gpg_error (GPG_ERR_NO_DATA);
167       break;
168
169     case GPGME_STATUS_DECRYPTION_OKAY:
170       opd->okay = 1;
171       break;
172
173     case GPGME_STATUS_DECRYPTION_FAILED:
174       opd->failed = 1;
175       break;
176
177     case GPGME_STATUS_ERROR:
178       /* Note that this is an informational status code which should
179          not lead to an error return unless it is something not
180          related to the backend.  */
181       {
182         const char d_alg[] = "decrypt.algorithm";
183         const char k_alg[] = "decrypt.keyusage";
184
185         if (!strncmp (args, d_alg, sizeof (d_alg) - 1))
186           {
187             args += sizeof (d_alg) - 1;
188             while (*args == ' ')
189               args++;
190
191             if (gpg_err_code (_gpgme_map_gnupg_error (args))
192                 == GPG_ERR_UNSUPPORTED_ALGORITHM)
193               {
194                 char *end;
195
196                 while (*args && *args != ' ')
197                   args++;
198                 while (*args == ' ')
199                   args++;
200
201                 end = strchr (args, ' ');
202                 if (end)
203                   *end = '\0';
204
205                 if (!(*args == '?' && *(args + 1) == '\0'))
206                   {
207                     opd->result.unsupported_algorithm = strdup (args);
208                     if (!opd->result.unsupported_algorithm)
209                       return gpg_error_from_errno (errno);
210                   }
211               }
212           }
213         else if (!strncmp (args, k_alg, sizeof (k_alg) - 1))
214           {
215             args += sizeof (k_alg) - 1;
216             while (*args == ' ')
217               args++;
218
219             err = _gpgme_map_gnupg_error (args);
220             if (gpg_err_code (err) == GPG_ERR_WRONG_KEY_USAGE)
221               opd->result.wrong_key_usage = 1;
222           }
223       }
224       break;
225
226     case GPGME_STATUS_ENC_TO:
227       err = parse_enc_to (args, opd->last_recipient_p);
228       if (err)
229         return err;
230
231       opd->last_recipient_p = &(*opd->last_recipient_p)->next;
232       break;
233
234     case GPGME_STATUS_NO_SECKEY:
235       {
236         gpgme_recipient_t rec = opd->result.recipients;
237
238         while (rec)
239           {
240             if (!strcmp (rec->keyid, args))
241               {
242                 rec->status = gpg_error (GPG_ERR_NO_SECKEY);
243                 break;
244               }
245             rec = rec->next;
246           }
247         /* FIXME: Is this ok?  */
248         if (!rec)
249           return gpg_error (GPG_ERR_INV_ENGINE);
250       }
251       break;
252
253     case GPGME_STATUS_PLAINTEXT:
254       err = _gpgme_parse_plaintext (args, &opd->result.file_name);
255       if (err)
256         return err;
257       
258     default:
259       break;
260     }
261
262   return 0;
263 }
264
265
266 static gpgme_error_t
267 decrypt_status_handler (void *priv, gpgme_status_code_t code, char *args)
268 {
269   gpgme_error_t err;
270
271   err = _gpgme_progress_status_handler (priv, code, args);
272   if (!err)
273     err = _gpgme_decrypt_status_handler (priv, code, args);
274   return err;
275 }
276
277
278 gpgme_error_t
279 _gpgme_op_decrypt_init_result (gpgme_ctx_t ctx)
280 {
281   gpgme_error_t err;
282   void *hook;
283   op_data_t opd;
284
285   err = _gpgme_op_data_lookup (ctx, OPDATA_DECRYPT, &hook,
286                                sizeof (*opd), release_op_data);
287   opd = hook;
288   if (err)
289     return err;
290
291   opd->last_recipient_p = &opd->result.recipients;
292   return 0;
293 }
294
295
296 static gpgme_error_t
297 decrypt_start (gpgme_ctx_t ctx, int synchronous,
298                       gpgme_data_t cipher, gpgme_data_t plain)
299 {
300   gpgme_error_t err;
301
302   err = _gpgme_op_reset (ctx, synchronous);
303   if (err)
304     return err;
305
306   err = _gpgme_op_decrypt_init_result (ctx);
307   if (err)
308     return err;
309
310   if (!cipher)
311     return gpg_error (GPG_ERR_NO_DATA);
312   if (!plain)
313     return gpg_error (GPG_ERR_INV_VALUE);
314
315   if (err)
316     return err;
317
318   if (ctx->passphrase_cb)
319     {
320       err = _gpgme_engine_set_command_handler
321         (ctx->engine, _gpgme_passphrase_command_handler, ctx, NULL);
322       if (err)
323         return err;
324     }
325
326   _gpgme_engine_set_status_handler (ctx->engine, decrypt_status_handler, ctx);
327
328   return _gpgme_engine_op_decrypt (ctx->engine, cipher, plain);
329 }
330
331
332 gpgme_error_t
333 gpgme_op_decrypt_start (gpgme_ctx_t ctx, gpgme_data_t cipher,
334                         gpgme_data_t plain)
335 {
336   return decrypt_start (ctx, 0, cipher, plain);
337 }
338
339
340 /* Decrypt ciphertext CIPHER within CTX and store the resulting
341    plaintext in PLAIN.  */
342 gpgme_error_t
343 gpgme_op_decrypt (gpgme_ctx_t ctx, gpgme_data_t cipher, gpgme_data_t plain)
344 {
345   gpgme_error_t err = decrypt_start (ctx, 1, cipher, plain);
346   if (!err)
347     err = _gpgme_wait_one (ctx);
348   return err;
349 }