* srv.c (getsrv): Raise maximum packet size to 2048, as PACKETSZ is
[gnupg.git] / common / get-passphrase.c
blob68d7b706a165e8e0c848cd19bb1cfa99f725c168
1 /* get-passphrase.c - Ask for a passphrase via the agent
2 * Copyright (C) 2009 Free Software Foundation, Inc.
4 * This file is part of GnuPG.
6 * GnuPG is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
11 * GnuPG is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, see <http://www.gnu.org/licenses/>.
20 #include <config.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <assert.h>
25 #include <assuan.h>
27 #include "util.h"
28 #include "i18n.h"
29 #include "asshelp.h"
30 #include "membuf.h"
31 #include "sysutils.h"
32 #include "get-passphrase.h"
34 /* The context used by this process to ask for the passphrase. */
35 static assuan_context_t agent_ctx;
36 static struct
38 gpg_err_source_t errsource;
39 int verbosity;
40 const char *homedir;
41 const char *agent_program;
42 const char *display;
43 const char *ttyname;
44 const char *ttytype;
45 const char *lc_ctype;
46 const char *lc_messages;
47 const char *xauthority;
48 const char *pinentry_user_data;
49 } agentargs;
52 /* Set local variable to be used for a possible agent startup. Note
53 that the strings are just pointers and should not anymore be
54 modified by the caller. */
55 void
56 gnupg_prepare_get_passphrase (gpg_err_source_t errsource,
57 int verbosity,
58 const char *homedir,
59 const char *agent_program,
60 const char *opt_display,
61 const char *opt_ttyname,
62 const char *opt_ttytype,
63 const char *opt_lc_ctype,
64 const char *opt_lc_messages,
65 const char *opt_xauthority,
66 const char *opt_pinentry_user_data)
68 agentargs.errsource = errsource;
69 agentargs.verbosity = verbosity;
70 agentargs.homedir = homedir;
71 agentargs.agent_program = agent_program;
72 agentargs.display = opt_display;
73 agentargs.ttyname = opt_ttyname;
74 agentargs.ttytype = opt_ttytype;
75 agentargs.lc_ctype = opt_lc_ctype;
76 agentargs.lc_messages = opt_lc_messages;
77 agentargs.xauthority = opt_xauthority;
78 agentargs.pinentry_user_data = opt_pinentry_user_data;
82 /* Try to connect to the agent via socket or fork it off and work by
83 pipes. Handle the server's initial greeting. */
84 static gpg_error_t
85 start_agent (void)
87 gpg_error_t err;
89 /* Fixme: This code is not thread safe, thus we don't build it with
90 pth. We will need a context for each thread or serialize the
91 access to the agent. */
92 if (agent_ctx)
93 return 0;
95 err = start_new_gpg_agent (&agent_ctx,
96 agentargs.errsource,
97 agentargs.homedir,
98 agentargs.agent_program,
99 agentargs.display,
100 agentargs.ttyname,
101 agentargs.ttytype,
102 agentargs.lc_ctype,
103 agentargs.lc_messages,
104 agentargs.xauthority,
105 agentargs.pinentry_user_data,
106 agentargs.verbosity, 0, NULL, NULL);
107 if (!err)
109 /* Tell the agent that we support Pinentry notifications. No
110 error checking so that it will work with older agents. */
111 assuan_transact (agent_ctx, "OPTION allow-pinentry-notify",
112 NULL, NULL, NULL, NULL, NULL, NULL);
115 return err;
119 /* This is the default inquiry callback. It merely handles the
120 Pinentry notification. */
121 static int
122 default_inq_cb (void *opaque, const char *line)
124 (void)opaque;
126 if (!strncmp (line, "PINENTRY_LAUNCHED", 17) && (line[17]==' '||!line[17]))
128 gnupg_allow_set_foregound_window ((pid_t)strtoul (line+17, NULL, 10));
129 /* We do not return errors to avoid breaking other code. */
131 else
132 log_debug ("ignoring gpg-agent inquiry `%s'\n", line);
134 return 0;
138 static int
139 membuf_data_cb (void *opaque, const void *buffer, size_t length)
141 membuf_t *data = opaque;
143 if (buffer)
144 put_membuf (data, buffer, length);
145 return 0;
149 /* Ask for a passphrase via gpg-agent. On success the caller needs to
150 free the string stored at R_PASSPHRASE. On error NULL will be
151 stored at R_PASSPHRASE and an appropriate gpg error code is
152 returned. With REPEAT set to 1, gpg-agent will ask the user to
153 repeat the just entered passphrase. CACHE_ID is a gpg-agent style
154 passphrase cache id or NULL. ERR_MSG is a error message to be
155 presented to the user (e.g. "bad passphrase - try again") or NULL.
156 PROMPT is the prompt string to label the entry box, it may be NULL
157 for a default one. DESC_MSG is a longer description to be
158 displayed above the entry box, if may be NULL for a default one.
159 If USE_SECMEM is true, the returned passphrase is retruned in
160 secure memory. The length of all these strings is limited; they
161 need to fit in their encoded form into a standard Assuan line (i.e
162 less then about 950 characters). All strings shall be UTF-8. */
163 gpg_error_t
164 gnupg_get_passphrase (const char *cache_id,
165 const char *err_msg,
166 const char *prompt,
167 const char *desc_msg,
168 int repeat,
169 int check_quality,
170 int use_secmem,
171 char **r_passphrase)
173 gpg_error_t err;
174 char line[ASSUAN_LINELENGTH];
175 const char *arg1 = NULL;
176 char *arg2 = NULL;
177 char *arg3 = NULL;
178 char *arg4 = NULL;
179 membuf_t data;
181 *r_passphrase = NULL;
183 err = start_agent ();
184 if (err)
185 return err;
187 /* Check that the gpg-agent understands the repeat option. */
188 if (assuan_transact (agent_ctx,
189 "GETINFO cmd_has_option GET_PASSPHRASE repeat",
190 NULL, NULL, NULL, NULL, NULL, NULL))
191 return gpg_error (GPG_ERR_NOT_SUPPORTED);
193 arg1 = cache_id && *cache_id? cache_id:NULL;
194 if (err_msg && *err_msg)
195 if (!(arg2 = percent_plus_escape (err_msg)))
196 goto no_mem;
197 if (prompt && *prompt)
198 if (!(arg3 = percent_plus_escape (prompt)))
199 goto no_mem;
200 if (desc_msg && *desc_msg)
201 if (!(arg4 = percent_plus_escape (desc_msg)))
202 goto no_mem;
204 snprintf (line, DIM(line)-1,
205 "GET_PASSPHRASE --data %s--repeat=%d -- %s %s %s %s",
206 check_quality? "--check ":"",
207 repeat,
208 arg1? arg1:"X",
209 arg2? arg2:"X",
210 arg3? arg3:"X",
211 arg4? arg4:"X");
212 line[DIM(line)-1] = 0;
213 xfree (arg2);
214 xfree (arg3);
215 xfree (arg4);
217 if (use_secmem)
218 init_membuf_secure (&data, 64);
219 else
220 init_membuf (&data, 64);
221 err = assuan_transact (agent_ctx, line,
222 membuf_data_cb, &data,
223 default_inq_cb, NULL, NULL, NULL);
225 /* Older Pinentries return the old assuan error code for canceled
226 which gets translated bt libassuan to GPG_ERR_ASS_CANCELED and
227 not to the code for a user cancel. Fix this here. */
228 if (err && gpg_err_source (err)
229 && gpg_err_code (err) == GPG_ERR_ASS_CANCELED)
230 err = gpg_err_make (gpg_err_source (err), GPG_ERR_CANCELED);
232 if (err)
234 void *p;
235 size_t n;
237 p = get_membuf (&data, &n);
238 if (p)
239 wipememory (p, n);
240 xfree (p);
242 else
244 put_membuf (&data, "", 1);
245 *r_passphrase = get_membuf (&data, NULL);
246 if (!*r_passphrase)
247 err = gpg_error_from_syserror ();
249 return err;
250 no_mem:
251 err = gpg_error_from_syserror ();
252 xfree (arg2);
253 xfree (arg3);
254 xfree (arg4);
255 return err;
259 /* Flush the passphrase cache with Id CACHE_ID. */
260 gpg_error_t
261 gnupg_clear_passphrase (const char *cache_id)
263 gpg_error_t err;
264 char line[ASSUAN_LINELENGTH];
266 if (!cache_id || !*cache_id)
267 return 0;
269 err = start_agent ();
270 if (err)
271 return err;
273 snprintf (line, DIM(line)-1, "CLEAR_PASSPHRASE %s", cache_id);
274 line[DIM(line)-1] = 0;
275 return assuan_transact (agent_ctx, line, NULL, NULL,
276 default_inq_cb, NULL, NULL, NULL);