6ba23bafce949c45e1a922a52940d626128506aa
[gpgme.git] / gpgme / passphrase.c
1 /* passphrase.c -  passphrase functions
2  *      Copyright (C) 2000 Werner Koch (dd9jn)
3  *      Copyright (C) 2001, 2002 g10 Code GmbH
4  *
5  * This file is part of GPGME.
6  *
7  * GPGME is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * GPGME is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
20  */
21
22 #include <config.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <assert.h>
27
28 #include "util.h"
29 #include "context.h"
30 #include "ops.h"
31
32
33 struct passphrase_result_s
34 {
35   int no_passphrase;
36   void *last_pw_handle;
37   char *userid_hint;
38   char *passphrase_info;
39   int bad_passphrase;
40 };
41
42
43 void
44 _gpgme_release_passphrase_result (PassphraseResult result)
45 {
46   if (!result)
47     return;
48   xfree (result->passphrase_info);
49   xfree (result->userid_hint);
50   xfree (result);
51 }
52
53
54 void
55 _gpgme_passphrase_status_handler (GpgmeCtx ctx, GpgStatusCode code, char *args)
56 {
57   if (ctx->error)
58     return;
59   test_and_allocate_result (ctx, passphrase);
60
61   switch (code)
62     {
63     case STATUS_USERID_HINT:
64       xfree (ctx->result.passphrase->userid_hint);
65       if (!(ctx->result.passphrase->userid_hint = xtrystrdup (args)))
66         ctx->error = mk_error (Out_Of_Core);
67       break;
68
69     case STATUS_BAD_PASSPHRASE:
70       ctx->result.passphrase->bad_passphrase++;
71       break;
72
73     case STATUS_GOOD_PASSPHRASE:
74       ctx->result.passphrase->bad_passphrase = 0;
75       break;
76
77     case STATUS_NEED_PASSPHRASE:
78     case STATUS_NEED_PASSPHRASE_SYM:
79       xfree (ctx->result.passphrase->passphrase_info);
80       ctx->result.passphrase->passphrase_info = xtrystrdup (args);
81       if (!ctx->result.passphrase->passphrase_info)
82         ctx->error = mk_error (Out_Of_Core);
83       break;
84
85     case STATUS_MISSING_PASSPHRASE:
86       DEBUG0 ("missing passphrase - stop\n");;
87       ctx->result.passphrase->no_passphrase = 1;
88       break;
89
90     case STATUS_EOF:
91       if (ctx->result.passphrase->no_passphrase
92           || ctx->result.passphrase->bad_passphrase)
93         ctx->error = mk_error (No_Passphrase);
94       break;
95
96     default:
97       /* Ignore all other codes.  */
98       break;
99     }
100 }
101
102
103 static const char *
104 command_handler (void *opaque, GpgStatusCode code, const char *key)
105 {
106   GpgmeCtx ctx = opaque;
107
108   if (!ctx->result.passphrase)
109     {
110       ctx->result.passphrase = xtrycalloc (1, sizeof *ctx->result.passphrase);
111       if (!ctx->result.passphrase)
112         {
113           ctx->error = mk_error (Out_Of_Core);
114           return NULL;
115         }
116     }
117
118   if (!code)
119     {
120       /* We have been called for cleanup.  */
121       if (ctx->passphrase_cb)
122         { 
123           /* Fixme: Take the key in account.  */
124           ctx->passphrase_cb (ctx->passphrase_cb_value, NULL, 
125                               &ctx->result.passphrase->last_pw_handle);
126         }
127       return NULL;
128     }
129
130   if (!key || !ctx->passphrase_cb)
131     return NULL;
132     
133   if (code == STATUS_GET_HIDDEN && !strcmp (key, "passphrase.enter"))
134     {
135       const char *userid_hint = ctx->result.passphrase->userid_hint;
136       const char *passphrase_info = ctx->result.passphrase->passphrase_info;
137       int bad_passphrase = ctx->result.passphrase->bad_passphrase;
138       char *buf;
139       const char *s;
140
141       ctx->result.passphrase->bad_passphrase = 0;
142       if (!userid_hint)
143         userid_hint = "[User ID hint missing]";
144       if (!passphrase_info)
145         passphrase_info = "[passphrase info missing]";
146       buf = xtrymalloc (20 + strlen (userid_hint)
147                         + strlen (passphrase_info) + 3);
148       if (!buf)
149         {
150           ctx->error = mk_error (Out_Of_Core);
151           return NULL;
152         }
153       sprintf (buf, "%s\n%s\n%s",
154                bad_passphrase ? "TRY_AGAIN":"ENTER",
155                userid_hint, passphrase_info);
156
157       s = ctx->passphrase_cb (ctx->passphrase_cb_value,
158                               buf, &ctx->result.passphrase->last_pw_handle);
159       xfree (buf);
160       return s;
161     }
162
163     return NULL;
164 }
165
166
167 GpgmeError
168 _gpgme_passphrase_start (GpgmeCtx ctx)
169 {
170   GpgmeError err = 0;
171
172   if (ctx->passphrase_cb)
173     err = _gpgme_engine_set_command_handler (ctx->engine, command_handler, ctx);
174   return err;
175 }