Initial code checking for backup - not yet working.
[gnupg.git] / g10 / call-dirmngr.c
1 /* call-dirmngr.c - GPG operations to the Dirmngr.
2  * Copyright (C) 2011 Free Software Foundation, Inc.
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 <http://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 #include <assert.h>
28 #ifdef HAVE_LOCALE_H
29 # include <locale.h>
30 #endif
31
32 #include "gpg.h"
33 #include <assuan.h>
34 #include "util.h"
35 #include "membuf.h"
36 #include "options.h"
37 #include "i18n.h"
38 #include "asshelp.h"
39 #include "call-dirmngr.h"
40
41
42 /* Data used to associate an session with dirmngr contexts.  We can't
43    use a simple one to one mapping because we sometimes need two
44    connection s to the dirmngr; for example while doing a listing and
45    being in a data callback we may want to retrieve a key.  The local
46    dirmngr data takes care of this.  At the end of the session the
47    function dirmngr_deinit_session_data is called bu gpg.c to cleanup
48    these resources.  Note that gpg.h defines a typedef dirmngr_local_t
49    for this structure. */
50 struct dirmngr_local_s 
51 {
52   /* Link to other contexts which are used simultaneously.  */
53   struct dirmngr_local_s *next;
54
55   /* The active Assuan context. */
56   static assuan_context_t ctx;
57
58   /* Flag set to true while an operation is running on CTX.  */
59   int is_active;
60 };
61
62
63 \f
64 /* Deinitialize all session data of dirmngr pertaining to CTRL.  */
65 void
66 gpg_dirmngr_deinit_session_data (ctrl_t ctrl)
67 {
68   dirmngr_local_t dml;
69
70   while ((dml = ctrl->dirmngr_local))
71     {
72       ctrl->dirmngr_local = dml->next;
73       if (dml->is_active)
74         log_error ("oops: trying to cleanup an active dirmngr context\n");
75       else
76         assuan_release (dml->ctx);
77       xfree (dml);
78     }
79 }
80
81
82 /* Try to connect to the Dirmngr via a socket or fork it off if
83    possible.  Handle the server's initial greeting and set global
84    options.  */
85 static gpg_error_t
86 create_context (ctrl_t ctrl, assuan_context_t *r_ctx)
87 {
88   gpg_error_t err;
89   assuan_context_t ctx;
90
91   *r_ctx = NULL;
92   err = start_new_dirmngr (&ctx,
93                            GPG_ERR_SOURCE_DEFAULT,
94                            opt.homedir,
95                            NULL,
96                            opt.verbose, DBG_ASSUAN,
97                            NULL /*gpg_status2*/, ctrl);
98   if (!err)
99     {
100       keyserver_spec_t ksi;
101
102       /* Tell the dirmngr that we want to collect audit event. */
103       /* err = assuan_transact (agent_ctx, "OPTION audit-events=1", */
104       /*                        NULL, NULL, NULL, NULL, NULL, NULL); */
105       
106       /* Set all configured keyservers.  We clear existing keyservers
107          so that any keyserver configured in GPG overrides keyservers
108          possibly configured in Dirmngr. */
109       if (ksi = opt.keyservers; !err && ksi; ksi = ksi->next)
110         {
111           char *line;
112           
113           line = xtryasprintf ("KEYSERVER%s %s",
114                                ksi == opt.keyservers? " --clear":"", ksi->uri);
115           if (!line)
116             err = gpg_error_from_syserror ();
117           else
118             {
119               err = assuan_transact (ctx, line,
120                                      NULL, NULL, NULL, NULL, NULL, NULL);
121               xfree (line);
122             }
123         }
124     }
125
126   if (err)
127     assuan_release (ctx);
128   else
129     {
130       /* audit_log_ok (ctrl->audit, AUDIT_DIRMNGR_READY, err); */
131       *r_ctx = ctx;
132     }
133   
134   return err;
135 }
136
137
138 /* Get a context for accessing dirmngr.  If no context is available a
139    new one is created and - if requred - dirmngr started.  On success
140    an assuan context is stored at R_CTX.  This Context may only be
141    released by means of close_context.  Note that NULL is stored at
142    R_CTX on error.  */
143 static gpg_error_t
144 open_context (ctrl_t ctrl, assuan_context_t *r_ctx)
145 {
146   gpg_error_t err;
147   dirmngr_local_t dml;
148
149   *r_ctx = NULL;
150   for (;;)
151     {
152       for (dml = ctrl->dirmngr_local; dml && dml->is_active; dml = dml->next)
153         ;
154       if (dml)
155         {
156           /* Found an inactive local session - return that.  */
157           assert (!dml->is_active);
158           dml->is_active = 1;
159           return dml;
160         }
161       
162       dml = xtrycalloc (1, sizeof *dml);
163       if (!dml)
164         return gpg_error_from_syserror ();
165       err = create_context (ctrl, &dml->ctx);
166       if (err)
167         {
168           xfree (dml);
169           return err;
170         }
171       /* To be on the Pth thread safe site we need to add it to a
172          list; this is far easier than to have a lock for this
173          function.  It should not happen anyway but the code is free
174          because we need it for the is_active check above.  */
175       dml->next = ctrl->dirmngr_local;
176       ctrl->dirmngr_local = dml;
177     }
178 }
179
180
181 /* Close the assuan context CTX or return it to a pool of unused
182    contexts.  If CTX is NULL, the function does nothing.  */
183 static void
184 close_context (ctrl_t ctrl, assuan_context_t ctx)
185 {
186   dirmngr_local_t dml;
187
188   if (!ctx)
189     return;
190
191   for (dml = ctrl->dirmngr_local; dml; dml = dml->next)
192     {
193       if (dml->ctx == ctx)
194         {
195           if (!ctx->is_active)
196             log_fatal ("closing inactive dirmngr context %p\n", ctx);
197           ctx->is_active = 0;
198           return;
199         }
200     }
201   log_fatal ("closing unknown dirmngr ctx %p\n", ctx);
202 }
203
204
205 \f
206
207 int 
208 gpg_dirmngr_ks_search (ctrl_t ctrl, strlist_t names,
209                        void (*cb)(void*, ksba_cert_t), void *cb_value)
210
211   gpg_error_t err;
212   assuan_context_t ctx;
213   char *pattern;
214   char line[ASSUAN_LINELENGTH];
215
216   err = open_context (ctrl, &ctx);
217   if (err)
218     return err;
219
220   pattern = pattern_from_strlist (names);
221   if (!pattern)
222     {
223       if (ctx == dirmngr_ctx)
224         release_dirmngr (ctrl);
225       else
226         release_dirmngr2 (ctrl);
227
228       return out_of_core ();
229     }
230   snprintf (line, DIM(line)-1, "LOOKUP%s %s", 
231             cache_only? " --cache-only":"", pattern);
232   line[DIM(line)-1] = 0;
233   xfree (pattern);
234
235   parm.ctrl = ctrl;
236   parm.ctx = ctx;
237   parm.cb = cb;
238   parm.cb_value = cb_value;
239   parm.error = 0;
240   init_membuf (&parm.data, 4096);
241
242   rc = assuan_transact (ctx, line, lookup_cb, &parm,
243                         NULL, NULL, lookup_status_cb, &parm);
244   xfree (get_membuf (&parm.data, &len));
245
246   if (ctx == dirmngr_ctx)
247     release_dirmngr (ctrl);
248   else
249     release_dirmngr2 (ctrl);
250
251   if (rc)
252       return rc;
253
254   close_context (ctrl, ctx);
255   return parm.error;
256 }