chiark / gitweb /
gpg agent lockup fix: Interrupt main loop when active_connections_value==0
[gnupg2.git] / tools / call-dirmngr.c
1 /* call-dirmngr.c - Interact with the Dirmngr.
2  * Copyright (C) 2016 g10 Code GmbH
3  *
4  * This file is part of GnuPG.
5  *
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.
10  *
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.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, see <https://www.gnu.org/licenses/>.
18  */
19
20 #include <config.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <errno.h>
25 #include <unistd.h>
26 #include <time.h>
27 #ifdef HAVE_LOCALE_H
28 # include <locale.h>
29 #endif
30
31 #include <assuan.h>
32 #include "util.h"
33 #include "i18n.h"
34 #include "asshelp.h"
35 #include "mbox-util.h"
36 #include "./call-dirmngr.h"
37
38 static struct
39 {
40   int verbose;
41   int debug_ipc;
42   int autostart;
43 } opt;
44
45
46
47 void
48 set_dirmngr_options (int verbose, int debug_ipc, int autostart)
49 {
50   opt.verbose = verbose;
51   opt.debug_ipc = debug_ipc;
52   opt.autostart = autostart;
53 }
54
55
56 /* Connect to the Dirmngr and return an assuan context.  */
57 static gpg_error_t
58 connect_dirmngr (assuan_context_t *r_ctx)
59 {
60   gpg_error_t err;
61   assuan_context_t ctx;
62
63   *r_ctx = NULL;
64   err = start_new_dirmngr (&ctx,
65                            GPG_ERR_SOURCE_DEFAULT,
66                            NULL,
67                            opt.autostart, opt.verbose, opt.debug_ipc,
68                            NULL, NULL);
69   if (!opt.autostart && gpg_err_code (err) == GPG_ERR_NO_DIRMNGR)
70     {
71       static int shown;
72
73       if (!shown)
74         {
75           shown = 1;
76           log_info (_("no dirmngr running in this session\n"));
77         }
78     }
79
80   if (err)
81     assuan_release (ctx);
82   else
83     {
84       *r_ctx = ctx;
85     }
86
87   return err;
88 }
89
90
91
92 \f
93 /* Parameter structure used with the WKD_GET command.  */
94 struct wkd_get_parm_s
95 {
96   estream_t memfp;
97 };
98
99
100 /* Data callback for the WKD_GET command. */
101 static gpg_error_t
102 wkd_get_data_cb (void *opaque, const void *data, size_t datalen)
103 {
104   struct wkd_get_parm_s *parm = opaque;
105   gpg_error_t err = 0;
106   size_t nwritten;
107
108   if (!data)
109     return 0;  /* Ignore END commands.  */
110   if (!parm->memfp)
111     return 0;  /* Data is not required.  */
112
113   if (es_write (parm->memfp, data, datalen, &nwritten))
114     err = gpg_error_from_syserror ();
115
116   return err;
117 }
118
119
120 /* Status callback for the WKD_GET command.  */
121 static gpg_error_t
122 wkd_get_status_cb (void *opaque, const char *line)
123 {
124   struct wkd_get_parm_s *parm = opaque;
125   gpg_error_t err = 0;
126
127   (void)line;
128   (void)parm;
129
130   return err;
131 }
132
133
134 /* Ask the dirmngr for the submission address of a WKD server for the
135  * mail address ADDRSPEC.  On success the submission address is stored
136  * at R_ADDRSPEC.  */
137 gpg_error_t
138 wkd_get_submission_address (const char *addrspec, char **r_addrspec)
139 {
140   gpg_error_t err;
141   assuan_context_t ctx;
142   struct wkd_get_parm_s parm;
143   char *line = NULL;
144   void *vp;
145   char *buffer = NULL;
146   char *p;
147
148   memset (&parm, 0, sizeof parm);
149   *r_addrspec = NULL;
150
151   err = connect_dirmngr (&ctx);
152   if (err)
153     return err;
154
155   line = es_bsprintf ("WKD_GET --submission-address -- %s", addrspec);
156   if (!line)
157     {
158       err = gpg_error_from_syserror ();
159       goto leave;
160     }
161   if (strlen (line) + 2 >= ASSUAN_LINELENGTH)
162     {
163       err = gpg_error (GPG_ERR_TOO_LARGE);
164       goto leave;
165     }
166
167   parm.memfp = es_fopenmem (0, "rwb");
168   if (!parm.memfp)
169     {
170       err = gpg_error_from_syserror ();
171       goto leave;
172     }
173   err = assuan_transact (ctx, line, wkd_get_data_cb, &parm,
174                          NULL, NULL, wkd_get_status_cb, &parm);
175   if (err)
176     goto leave;
177
178   es_fputc (0, parm.memfp);
179   if (es_fclose_snatch (parm.memfp, &vp, NULL))
180     {
181       err = gpg_error_from_syserror ();
182       goto leave;
183     }
184   buffer = vp;
185   parm.memfp = NULL;
186   p = strchr (buffer, '\n');
187   if (p)
188     *p = 0;
189   trim_spaces (buffer);
190   if (!is_valid_mailbox (buffer))
191     {
192       err = gpg_error (GPG_ERR_INV_USER_ID);
193       goto leave;
194     }
195   *r_addrspec = xtrystrdup (buffer);
196   if (!*r_addrspec)
197     err = gpg_error_from_syserror ();
198
199  leave:
200   es_free (buffer);
201   es_fclose (parm.memfp);
202   xfree (line);
203   assuan_release (ctx);
204   return err;
205 }
206
207
208 /* Ask the dirmngr for the policy flags and return them as an estream
209  * memory stream.  If no policy flags are set, NULL is stored at
210  * R_BUFFER.  */
211 gpg_error_t
212 wkd_get_policy_flags (const char *addrspec, estream_t *r_buffer)
213 {
214   gpg_error_t err;
215   assuan_context_t ctx;
216   struct wkd_get_parm_s parm;
217   char *line = NULL;
218   char *buffer = NULL;
219
220   memset (&parm, 0, sizeof parm);
221   *r_buffer = NULL;
222
223   err = connect_dirmngr (&ctx);
224   if (err)
225     return err;
226
227   line = es_bsprintf ("WKD_GET --policy-flags -- %s", addrspec);
228   if (!line)
229     {
230       err = gpg_error_from_syserror ();
231       goto leave;
232     }
233   if (strlen (line) + 2 >= ASSUAN_LINELENGTH)
234     {
235       err = gpg_error (GPG_ERR_TOO_LARGE);
236       goto leave;
237     }
238
239   parm.memfp = es_fopenmem (0, "rwb");
240   if (!parm.memfp)
241     {
242       err = gpg_error_from_syserror ();
243       goto leave;
244     }
245   err = assuan_transact (ctx, line, wkd_get_data_cb, &parm,
246                          NULL, NULL, wkd_get_status_cb, &parm);
247   if (err)
248     goto leave;
249
250   es_rewind (parm.memfp);
251   *r_buffer = parm.memfp;
252   parm.memfp = 0;
253
254  leave:
255   es_free (buffer);
256   es_fclose (parm.memfp);
257   xfree (line);
258   assuan_release (ctx);
259   return err;
260 }
261
262
263 /* Ask the dirmngr for the key for ADDRSPEC.  On success a stream with
264  * the key is stored at R_KEY.  */
265 gpg_error_t
266 wkd_get_key (const char *addrspec, estream_t *r_key)
267 {
268   gpg_error_t err;
269   assuan_context_t ctx;
270   struct wkd_get_parm_s parm;
271   char *line = NULL;
272
273   memset (&parm, 0, sizeof parm);
274   *r_key = NULL;
275
276   err = connect_dirmngr (&ctx);
277   if (err)
278     return err;
279
280   line = es_bsprintf ("WKD_GET -- %s", addrspec);
281   if (!line)
282     {
283       err = gpg_error_from_syserror ();
284       goto leave;
285     }
286   if (strlen (line) + 2 >= ASSUAN_LINELENGTH)
287     {
288       err = gpg_error (GPG_ERR_TOO_LARGE);
289       goto leave;
290     }
291
292   parm.memfp = es_fopenmem (0, "rwb");
293   if (!parm.memfp)
294     {
295       err = gpg_error_from_syserror ();
296       goto leave;
297     }
298   err = assuan_transact (ctx, line, wkd_get_data_cb, &parm,
299                          NULL, NULL, wkd_get_status_cb, &parm);
300   if (err)
301     goto leave;
302
303   es_rewind (parm.memfp);
304   *r_key = parm.memfp;
305   parm.memfp = NULL;
306
307  leave:
308   es_fclose (parm.memfp);
309   xfree (line);
310   assuan_release (ctx);
311   return err;
312 }