5d656b1729aad8032751ade3f2e93bc16093af7e
[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     default:
132       /* Ignore all other codes.  */
133       break;
134     }
135   return 0;
136 }
137
138
139 gpgme_error_t
140 _gpgme_passphrase_command_handler (void *priv, gpgme_status_code_t code,
141                                    const char *key, int fd, int *processed)
142 {
143   gpgme_ctx_t ctx = (gpgme_ctx_t) priv;
144   gpgme_error_t err;
145   void *hook;
146   op_data_t opd;
147
148   assert (ctx->passphrase_cb);
149
150   err = _gpgme_op_data_lookup (ctx, OPDATA_PASSPHRASE, &hook,
151                                sizeof (*opd), release_op_data);
152   opd = hook;
153   if (err)
154     return err;
155
156   if (code == GPGME_STATUS_GET_HIDDEN
157       && (!strcmp (key, "passphrase.enter")
158           || !strcmp (key, "passphrase.pin.ask")))
159     {
160       if (processed)
161         *processed = 1;
162
163       if (ctx->status_cb && opd->maxlen)
164         err = ctx->status_cb (ctx->status_cb_value, "INQUIRE_MAXLEN",
165                               opd->maxlen);
166
167       if (!err)
168         err = ctx->passphrase_cb (ctx->passphrase_cb_value,
169                                   opd->uid_hint, opd->passphrase_info,
170                                   opd->bad_passphrase, fd);
171
172       /* Reset bad passphrase flag, in case it is correct now.  */
173       opd->bad_passphrase = 0;
174
175       return err;
176     }
177
178   return 0;
179 }