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