Improve error return by checking the FAILURE status.
[gpgme.git] / src / passphrase.c
1 /* passphrase.c - Passphrase callback.
2    Copyright (C) 2000 Werner Koch (dd9jn)
3    Copyright (C) 2001, 2002, 2003, 2004, 2005 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 <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <assert.h>
29 #include <errno.h>
30
31 #include "gpgme.h"
32 #include "context.h"
33 #include "ops.h"
34 #include "util.h"
35 #include "debug.h"
36
37 \f
38 typedef struct
39 {
40   int no_passphrase;
41   char *uid_hint;
42   char *passphrase_info;
43   int bad_passphrase;
44   char *maxlen;
45 } *op_data_t;
46
47
48 static void
49 release_op_data (void *hook)
50 {
51   op_data_t opd = (op_data_t) hook;
52
53   if (opd->passphrase_info)
54     free (opd->passphrase_info);
55   if (opd->uid_hint)
56     free (opd->uid_hint);
57   free (opd->maxlen);
58 }
59
60 \f
61 gpgme_error_t
62 _gpgme_passphrase_status_handler (void *priv, gpgme_status_code_t code,
63                                   char *args)
64 {
65   gpgme_ctx_t ctx = (gpgme_ctx_t) priv;
66   gpgme_error_t err;
67   void *hook;
68   op_data_t opd;
69
70   err = _gpgme_op_data_lookup (ctx, OPDATA_PASSPHRASE, &hook,
71                                sizeof (*opd), release_op_data);
72   opd = hook;
73   if (err)
74     return err;
75
76   switch (code)
77     {
78     case GPGME_STATUS_INQUIRE_MAXLEN:
79       free (opd->maxlen);
80       if (!(opd->maxlen = strdup (args)))
81         return gpg_error_from_syserror ();
82       break;
83     case GPGME_STATUS_USERID_HINT:
84       if (opd->uid_hint)
85         free (opd->uid_hint);
86       if (!(opd->uid_hint = strdup (args)))
87         return gpg_error_from_syserror ();
88       break;
89
90     case GPGME_STATUS_BAD_PASSPHRASE:
91       opd->bad_passphrase++;
92       opd->no_passphrase = 0;
93       break;
94
95     case GPGME_STATUS_GOOD_PASSPHRASE:
96       opd->bad_passphrase = 0;
97       opd->no_passphrase = 0;
98       break;
99
100     case GPGME_STATUS_NEED_PASSPHRASE:
101     case GPGME_STATUS_NEED_PASSPHRASE_SYM:
102     case GPGME_STATUS_NEED_PASSPHRASE_PIN:
103       if (opd->passphrase_info)
104         free (opd->passphrase_info);
105       opd->passphrase_info = strdup (args);
106       if (!opd->passphrase_info)
107         return gpg_error_from_syserror ();
108       break;
109
110     case GPGME_STATUS_MISSING_PASSPHRASE:
111       opd->no_passphrase = 1;
112       break;
113
114     case GPGME_STATUS_EOF:
115       if (opd->no_passphrase || opd->bad_passphrase)
116         return gpg_error (GPG_ERR_BAD_PASSPHRASE);
117       break;
118
119     case GPGME_STATUS_ERROR:
120       /* We abuse this status handler to forward ERROR status codes to
121          the caller.  This should better be done in a generic handler,
122          but for now this is sufficient.  */
123       if (ctx->status_cb)
124         {
125           err = ctx->status_cb (ctx->status_cb_value, "ERROR", args);
126           if (err)
127             return err;
128         }
129       break;
130
131     case GPGME_STATUS_FAILURE:
132       /* We abuse this status handler to forward FAILURE status codes
133          to the caller.  This should better be done in a generic
134          handler, but for now this is sufficient.  */
135       if (ctx->status_cb)
136         {
137           err = ctx->status_cb (ctx->status_cb_value, "FAILURE", args);
138           if (err)
139             return err;
140         }
141       break;
142
143
144     default:
145       /* Ignore all other codes.  */
146       break;
147     }
148   return 0;
149 }
150
151
152 gpgme_error_t
153 _gpgme_passphrase_command_handler (void *priv, gpgme_status_code_t code,
154                                    const char *key, int fd, int *processed)
155 {
156   gpgme_ctx_t ctx = (gpgme_ctx_t) priv;
157   gpgme_error_t err;
158   void *hook;
159   op_data_t opd;
160
161   assert (ctx->passphrase_cb);
162
163   err = _gpgme_op_data_lookup (ctx, OPDATA_PASSPHRASE, &hook,
164                                sizeof (*opd), release_op_data);
165   opd = hook;
166   if (err)
167     return err;
168
169   if (code == GPGME_STATUS_GET_HIDDEN
170       && (!strcmp (key, "passphrase.enter")
171           || !strcmp (key, "passphrase.pin.ask")))
172     {
173       if (processed)
174         *processed = 1;
175
176       if (ctx->status_cb && opd->maxlen)
177         err = ctx->status_cb (ctx->status_cb_value, "INQUIRE_MAXLEN",
178                               opd->maxlen);
179
180       if (!err)
181         err = ctx->passphrase_cb (ctx->passphrase_cb_value,
182                                   opd->uid_hint, opd->passphrase_info,
183                                   opd->bad_passphrase, fd);
184
185       /* Reset bad passphrase flag, in case it is correct now.  */
186       opd->bad_passphrase = 0;
187
188       return err;
189     }
190
191   return 0;
192 }