core: Add public function gpgme_get_ctx_flag.
[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.  */
122       if (ctx->status_cb && !ctx->full_status)
123         {
124           err = ctx->status_cb (ctx->status_cb_value, "ERROR", args);
125           if (err)
126             return err;
127         }
128       break;
129
130     case GPGME_STATUS_FAILURE:
131       /* We abuse this status handler to forward FAILURE status codes
132          to the caller.  */
133       if (ctx->status_cb && !ctx->full_status)
134         {
135           err = ctx->status_cb (ctx->status_cb_value, "FAILURE", args);
136           if (err)
137             return err;
138         }
139       break;
140
141
142     default:
143       /* Ignore all other codes.  */
144       break;
145     }
146   return 0;
147 }
148
149
150 gpgme_error_t
151 _gpgme_passphrase_command_handler (void *priv, gpgme_status_code_t code,
152                                    const char *key, int fd, int *processed)
153 {
154   gpgme_ctx_t ctx = (gpgme_ctx_t) priv;
155   gpgme_error_t err;
156   void *hook;
157   op_data_t opd;
158
159   assert (ctx->passphrase_cb);
160
161   err = _gpgme_op_data_lookup (ctx, OPDATA_PASSPHRASE, &hook,
162                                sizeof (*opd), release_op_data);
163   opd = hook;
164   if (err)
165     return err;
166
167   if (code == GPGME_STATUS_GET_HIDDEN
168       && (!strcmp (key, "passphrase.enter")
169           || !strcmp (key, "passphrase.pin.ask")))
170     {
171       if (processed)
172         *processed = 1;
173
174       /* Fake a status line to to convey the MAXLEN info.  */
175       if (ctx->status_cb && opd->maxlen)
176         err = ctx->status_cb (ctx->status_cb_value, "INQUIRE_MAXLEN",
177                               opd->maxlen);
178
179       if (!err)
180         err = ctx->passphrase_cb (ctx->passphrase_cb_value,
181                                   opd->uid_hint, opd->passphrase_info,
182                                   opd->bad_passphrase, fd);
183
184       /* Reset bad passphrase flag, in case it is correct now.  */
185       opd->bad_passphrase = 0;
186
187       return err;
188     }
189
190   return 0;
191 }