~ubuntu-branches/ubuntu/oneiric/gnupg2/oneiric-updates

« back to all changes in this revision

Viewing changes to common/asshelp.c

  • Committer: Bazaar Package Importer
  • Author(s): Thomas Viehmann
  • Date: 2008-10-04 10:25:53 UTC
  • mfrom: (5.1.15 intrepid)
  • Revision ID: james.westby@ubuntu.com-20081004102553-fv62pp8dsitxli47
Tags: 2.0.9-3.1
* Non-maintainer upload.
* agent/gpg-agent.c: Deinit the threading library before exec'ing
  the command to run in --daemon mode. And because that still doesn't
  restore the sigprocmask, do that manually. Closes: #499569

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/* asshelp.c - Helper functions for Assuan
2
 
 * Copyright (C) 2002, 2004 Free Software Foundation, Inc.
 
2
 * Copyright (C) 2002, 2004, 2007 Free Software Foundation, Inc.
3
3
 *
4
4
 * This file is part of GnuPG.
5
5
 *
6
6
 * GnuPG is free software; you can redistribute it and/or modify
7
7
 * it under the terms of the GNU General Public License as published by
8
 
 * the Free Software Foundation; either version 2 of the License, or
 
8
 * the Free Software Foundation; either version 3 of the License, or
9
9
 * (at your option) any later version.
10
10
 *
11
11
 * GnuPG is distributed in the hope that it will be useful,
14
14
 * GNU General Public License for more details.
15
15
 *
16
16
 * You should have received a copy of the GNU General Public License
17
 
 * along with this program; if not, write to the Free Software
18
 
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
 
17
 * along with this program; if not, see <http://www.gnu.org/licenses/>.
19
18
 */
20
19
 
21
20
#include <config.h>
28
27
#include <locale.h>
29
28
#endif
30
29
 
 
30
#include "i18n.h"
31
31
#include "util.h"
32
 
 
 
32
#include "exechelp.h"
 
33
#include "sysutils.h"
 
34
#include "status.h" 
33
35
#include "asshelp.h"
34
36
 
35
37
 
43
45
  if (!value || !*value)
44
46
    err = 0;  /* Avoid sending empty strings.  */
45
47
  else if (asprintf (&optstr, "OPTION %s=%s", name, value ) < 0)
46
 
    err = gpg_error_from_errno (errno);
 
48
    err = gpg_error_from_syserror ();
47
49
  else
48
50
    {
49
 
      assuan_error_t ae;
50
 
 
51
 
      ae = assuan_transact (ctx, optstr, NULL, NULL, NULL, NULL, NULL, NULL);
52
 
      err = ae? map_assuan_err_with_source (errsource, ae) : 0;
 
51
      err = assuan_transact (ctx, optstr, NULL, NULL, NULL, NULL, NULL, NULL);
53
52
      free (optstr);
54
53
    }
55
54
 
57
56
}
58
57
 
59
58
 
60
 
/* Send the assuan commands pertaining to the pinenry environment.  The
 
59
/* Send the assuan commands pertaining to the pinentry environment.  The
61
60
   OPT_* arguments are optional and may be used to override the
62
61
   defaults taken from the current locale. */
63
62
gpg_error_t
67
66
                           const char *opt_ttyname,
68
67
                           const char *opt_ttytype,
69
68
                           const char *opt_lc_ctype,
70
 
                           const char *opt_lc_messages)
 
69
                           const char *opt_lc_messages,
 
70
                           const char *opt_xauthority,
 
71
                           const char *opt_pinentry_user_data)
71
72
{
72
73
  gpg_error_t err = 0;
73
74
  char *dft_display = NULL;
75
76
  char *dft_ttytype = NULL;
76
77
  char *old_lc = NULL; 
77
78
  char *dft_lc = NULL;
 
79
  char *dft_xauthority = NULL;
 
80
  char *dft_pinentry_user_data = NULL;
78
81
 
79
82
  /* Send the DISPLAY variable.  */
80
83
  dft_display = getenv ("DISPLAY");
118
121
    {
119
122
      old_lc = strdup (old_lc);
120
123
      if (!old_lc)
121
 
        return gpg_error_from_errno (errno);
 
124
        return gpg_error_from_syserror ();
122
125
    }
123
126
  dft_lc = setlocale (LC_CTYPE, "");
124
127
#endif
144
147
    {
145
148
      old_lc = strdup (old_lc);
146
149
      if (!old_lc)
147
 
        return gpg_error_from_errno (errno);
 
150
        return gpg_error_from_syserror ();
148
151
    }
149
152
  dft_lc = setlocale (LC_MESSAGES, "");
150
153
#endif
163
166
  if (err)
164
167
    return err;
165
168
 
 
169
  /* Send the XAUTHORITY variable.  */
 
170
  dft_xauthority = getenv ("XAUTHORITY");
 
171
  if (opt_xauthority || dft_xauthority)
 
172
    {
 
173
      err = send_one_option (ctx, errsource, "xauthority", 
 
174
                             opt_xauthority ? opt_xauthority : dft_xauthority);
 
175
      if (gpg_err_code (err) == GPG_ERR_UNKNOWN_OPTION)
 
176
        err = 0;
 
177
      if (err)
 
178
        return err;
 
179
    }
 
180
 
 
181
  /* Send the PINENTRY_USER_DATA variable.  */
 
182
  dft_pinentry_user_data = getenv ("PINENTRY_USER_DATA");
 
183
  if (opt_pinentry_user_data || dft_pinentry_user_data)
 
184
    {
 
185
      err = send_one_option (ctx, errsource, "pinentry-user-data", 
 
186
                             opt_pinentry_user_data ?
 
187
                             opt_pinentry_user_data : dft_pinentry_user_data);
 
188
      if (gpg_err_code (err) == GPG_ERR_UNKNOWN_OPTION)
 
189
        err = 0;
 
190
      if (err)
 
191
        return err;
 
192
    }
 
193
 
 
194
  return 0;
 
195
}
 
196
 
 
197
 
 
198
/* Try to connect to the agent via socket or fork it off and work by
 
199
   pipes.  Handle the server's initial greeting.  Returns a new assuan
 
200
   context at R_CTX or an error code. */
 
201
gpg_error_t
 
202
start_new_gpg_agent (assuan_context_t *r_ctx,
 
203
                     gpg_err_source_t errsource,
 
204
                     const char *homedir,
 
205
                     const char *agent_program,
 
206
                     const char *opt_display,
 
207
                     const char *opt_ttyname,
 
208
                     const char *opt_ttytype,
 
209
                     const char *opt_lc_ctype,
 
210
                     const char *opt_lc_messages,
 
211
                     const char *opt_xauthority,
 
212
                     const char *opt_pinentry_user_data,
 
213
                     int verbose, int debug,
 
214
                     gpg_error_t (*status_cb)(ctrl_t, int, ...),
 
215
                     ctrl_t status_cb_arg)
 
216
{
 
217
  /* If we ever failed to connect via a socket we will force the use
 
218
     of the pipe based server for the lifetime of the process.  */
 
219
  static int force_pipe_server = 0;
 
220
 
 
221
  gpg_error_t rc = 0;
 
222
  char *infostr, *p;
 
223
  assuan_context_t ctx;
 
224
 
 
225
  *r_ctx = NULL;
 
226
 
 
227
 restart:
 
228
  infostr = force_pipe_server? NULL : getenv ("GPG_AGENT_INFO");
 
229
  if (!infostr || !*infostr)
 
230
    {
 
231
      char *sockname;
 
232
 
 
233
      /* First check whether we can connect at the standard
 
234
         socket.  */
 
235
      sockname = make_filename (homedir, "S.gpg-agent", NULL);
 
236
      rc = assuan_socket_connect (&ctx, sockname, 0);
 
237
 
 
238
      if (rc)
 
239
        {
 
240
          /* With no success start a new server.  */
 
241
          if (verbose)
 
242
            log_info (_("no running gpg-agent - starting one\n"));
 
243
          
 
244
          if (status_cb)
 
245
            status_cb (status_cb_arg, STATUS_PROGRESS, 
 
246
                       "starting_agent ? 0 0", NULL);
 
247
          
 
248
          if (fflush (NULL))
 
249
            {
 
250
              gpg_error_t tmperr = gpg_error (gpg_err_code_from_errno (errno));
 
251
              log_error ("error flushing pending output: %s\n",
 
252
                         strerror (errno));
 
253
              xfree (sockname);
 
254
              return tmperr;
 
255
            }
 
256
          
 
257
          if (!agent_program || !*agent_program)
 
258
            agent_program = gnupg_module_name (GNUPG_MODULE_NAME_AGENT);
 
259
 
 
260
#ifdef HAVE_W32_SYSTEM
 
261
          {
 
262
            /* Under Windows we start the server in daemon mode.  This
 
263
               is because the default is to use the standard socket
 
264
               and thus there is no need for the GPG_AGENT_INFO
 
265
               envvar.  This is possible as we don't have a real unix
 
266
               domain socket but use a plain file and thus there is no
 
267
               need to care about non-local file systems. */
 
268
            const char *argv[3];
 
269
 
 
270
            argv[0] = "--daemon";
 
271
            argv[1] = "--use-standard-socket"; 
 
272
            argv[2] = NULL;  
 
273
 
 
274
            rc = gnupg_spawn_process_detached (agent_program, argv, NULL);
 
275
            if (rc)
 
276
              log_debug ("failed to start agent `%s': %s\n",
 
277
                         agent_program, gpg_strerror (rc));
 
278
            else
 
279
              {
 
280
                /* Give the agent some time to prepare itself. */
 
281
                gnupg_sleep (3);
 
282
                /* Now try again to connect the agent.  */
 
283
                rc = assuan_socket_connect (&ctx, sockname, 0);
 
284
              }
 
285
          }
 
286
#else /*!HAVE_W32_SYSTEM*/
 
287
          {
 
288
            const char *pgmname;
 
289
            const char *argv[3];
 
290
            int no_close_list[3];
 
291
            int i;
 
292
 
 
293
            if ( !(pgmname = strrchr (agent_program, '/')))
 
294
              pgmname = agent_program;
 
295
            else
 
296
              pgmname++;
 
297
            
 
298
            argv[0] = pgmname;
 
299
            argv[1] = "--server";
 
300
            argv[2] = NULL;
 
301
            
 
302
            i=0;
 
303
            if (log_get_fd () != -1)
 
304
              no_close_list[i++] = log_get_fd ();
 
305
            no_close_list[i++] = fileno (stderr);
 
306
            no_close_list[i] = -1;
 
307
            
 
308
            /* Connect to the agent and perform initial handshaking. */
 
309
            rc = assuan_pipe_connect (&ctx, agent_program, argv,
 
310
                                      no_close_list);
 
311
          }
 
312
#endif /*!HAVE_W32_SYSTEM*/
 
313
        }
 
314
      xfree (sockname);
 
315
    }
 
316
  else
 
317
    {
 
318
      int prot;
 
319
      int pid;
 
320
 
 
321
      infostr = xstrdup (infostr);
 
322
      if ( !(p = strchr (infostr, PATHSEP_C)) || p == infostr)
 
323
        {
 
324
          log_error (_("malformed GPG_AGENT_INFO environment variable\n"));
 
325
          xfree (infostr);
 
326
          force_pipe_server = 1;
 
327
          goto restart;
 
328
        }
 
329
      *p++ = 0;
 
330
      pid = atoi (p);
 
331
      while (*p && *p != PATHSEP_C)
 
332
        p++;
 
333
      prot = *p? atoi (p+1) : 0;
 
334
      if (prot != 1)
 
335
        {
 
336
          log_error (_("gpg-agent protocol version %d is not supported\n"),
 
337
                     prot);
 
338
          xfree (infostr);
 
339
          force_pipe_server = 1;
 
340
          goto restart;
 
341
        }
 
342
 
 
343
      rc = assuan_socket_connect (&ctx, infostr, pid);
 
344
      xfree (infostr);
 
345
      if (gpg_err_code (rc) == GPG_ERR_ASS_CONNECT_FAILED)
 
346
        {
 
347
          log_info (_("can't connect to the agent - trying fall back\n"));
 
348
          force_pipe_server = 1;
 
349
          goto restart;
 
350
        }
 
351
    }
 
352
 
 
353
  if (rc)
 
354
    {
 
355
      log_error ("can't connect to the agent: %s\n", gpg_strerror (rc));
 
356
      return gpg_error (GPG_ERR_NO_AGENT);
 
357
    }
 
358
 
 
359
  if (debug)
 
360
    log_debug ("connection to agent established\n");
 
361
 
 
362
  rc = assuan_transact (ctx, "RESET",
 
363
                        NULL, NULL, NULL, NULL, NULL, NULL);
 
364
  if (!rc)
 
365
    rc = send_pinentry_environment (ctx, errsource,
 
366
                                    opt_display, opt_ttyname, opt_ttytype,
 
367
                                    opt_lc_ctype, opt_lc_messages,
 
368
                                    opt_xauthority,
 
369
                                    opt_pinentry_user_data);
 
370
  if (rc)
 
371
    {
 
372
      assuan_disconnect (ctx);
 
373
      return rc;
 
374
    }
 
375
 
 
376
  *r_ctx = ctx;
166
377
  return 0;
167
378
}
168
379