~ubuntu-branches/ubuntu/oneiric/gnupg2/oneiric-proposed

« back to all changes in this revision

Viewing changes to common/asshelp.c

  • Committer: Bazaar Package Importer
  • Author(s): Marc Deslauriers
  • Date: 2011-05-25 14:27:35 UTC
  • mfrom: (1.1.15 upstream) (7.1.7 sid)
  • Revision ID: james.westby@ubuntu.com-20110525142735-jccyw0fopnyv728q
Tags: 2.0.17-2ubuntu1
* Merge from debian unstable. Remaining changes:
  - Add udev rules to give gpg access to some smartcard readers;
    Debian #543217.
    . debian/gnupg2.dev: udev rules to set ACLs on SCM smartcard readers.
    . debian/rules: Call dh_installudev.
  - debian/control: Rename Vcs-* to XS-Debian-Vcs-*.

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, 2007, 2009 Free Software Foundation, Inc.
 
2
 * Copyright (C) 2002, 2004, 2007, 2009, 2010 Free Software Foundation, Inc.
3
3
 *
4
4
 * This file is part of GnuPG.
5
5
 *
27
27
#include <locale.h>
28
28
#endif
29
29
 
 
30
#define JNLIB_NEED_LOG_LOGV
30
31
#include "i18n.h"
31
32
#include "util.h"
32
33
#include "exechelp.h"
34
35
#include "status.h" 
35
36
#include "asshelp.h"
36
37
 
 
38
/* The type we use for lock_agent_spawning.  */
 
39
#ifdef HAVE_W32_SYSTEM
 
40
# define lock_agent_t HANDLE
 
41
#else
 
42
# define lock_agent_t DOTLOCK
 
43
#endif
 
44
 
 
45
 
37
46
static gpg_error_t
38
47
send_one_option (assuan_context_t ctx, gpg_err_source_t errsource,
39
48
                 const char *name, const char *value, int use_putenv)
70
79
 
71
80
{
72
81
  gpg_error_t err = 0;
 
82
#if defined(HAVE_SETLOCALE)
73
83
  char *old_lc = NULL; 
 
84
#endif
74
85
  char *dft_lc = NULL;
75
86
  const char *dft_ttyname;
76
87
  int iterator;
158
169
}
159
170
 
160
171
 
 
172
/* Lock the agent spawning process.  The caller needs to provide the
 
173
   address of a variable to store the lock information.  */
 
174
static gpg_error_t
 
175
lock_agent_spawning (lock_agent_t *lock, const char *homedir)
 
176
{
 
177
#ifdef HAVE_W32_SYSTEM
 
178
  int waitrc;
 
179
 
 
180
  (void)homedir; /* Not required. */
 
181
 
 
182
  *lock = CreateMutex (NULL, FALSE, "GnuPG_spawn_agent_sentinel");
 
183
  if (!*lock)
 
184
    {
 
185
      log_error ("failed to create the spawn_agent mutex: %s\n",
 
186
                 w32_strerror (-1));
 
187
      return gpg_error (GPG_ERR_GENERAL);
 
188
    }
 
189
 
 
190
  waitrc = WaitForSingleObject (*lock, 5000);
 
191
  if (waitrc == WAIT_OBJECT_0)
 
192
    return 0;
 
193
 
 
194
  if (waitrc == WAIT_TIMEOUT)
 
195
    log_info ("error waiting for the spawn_agent mutex: timeout\n");
 
196
  else
 
197
    log_info ("error waiting for the spawn_agent mutex: "
 
198
              "(code=%d) %s\n", waitrc, w32_strerror (-1));
 
199
  return gpg_error (GPG_ERR_GENERAL);
 
200
#else /*!HAVE_W32_SYSTEM*/
 
201
  char *fname;
 
202
 
 
203
  *lock = NULL;
 
204
 
 
205
  fname = make_filename (homedir, "gnupg_spawn_agent_sentinel", NULL);
 
206
  if (!fname)
 
207
    return gpg_error_from_syserror ();
 
208
 
 
209
  *lock = create_dotlock (fname);
 
210
  xfree (fname);
 
211
  if (!*lock)
 
212
    return gpg_error_from_syserror ();
 
213
 
 
214
  /* FIXME: We should use a timeout of 5000 here - however
 
215
     make_dotlock does not yet support values other than -1 and 0.  */
 
216
  if (make_dotlock (*lock, -1))
 
217
    return gpg_error_from_syserror ();
 
218
 
 
219
  return 0;
 
220
#endif /*!HAVE_W32_SYSTEM*/
 
221
}
 
222
 
 
223
 
 
224
/* Unlock the spawning process.  */
 
225
static void
 
226
unlock_agent_spawning (lock_agent_t *lock)
 
227
{
 
228
  if (*lock)
 
229
    {
 
230
#ifdef HAVE_W32_SYSTEM
 
231
      if (!ReleaseMutex (*lock))
 
232
        log_error ("failed to release the spawn_agent mutex: %s\n",
 
233
                   w32_strerror (-1));
 
234
      CloseHandle (*lock);
 
235
#else /*!HAVE_W32_SYSTEM*/
 
236
      destroy_dotlock (*lock);
 
237
#endif /*!HAVE_W32_SYSTEM*/
 
238
      *lock = NULL;
 
239
    }
 
240
}
 
241
 
 
242
 
161
243
/* Try to connect to the agent via socket or fork it off and work by
162
244
   pipes.  Handle the server's initial greeting.  Returns a new assuan
163
245
   context at R_CTX or an error code. */
177
259
     of the pipe based server for the lifetime of the process.  */
178
260
  static int force_pipe_server = 0;
179
261
 
180
 
  gpg_error_t rc = 0;
 
262
  gpg_error_t err = 0;
181
263
  char *infostr, *p;
182
264
  assuan_context_t ctx;
183
265
 
184
266
  *r_ctx = NULL;
185
267
 
 
268
  err = assuan_new (&ctx);
 
269
  if (err)
 
270
    {
 
271
      log_error ("error allocating assuan context: %s\n", gpg_strerror (err));
 
272
      return err;
 
273
    }
 
274
 
186
275
 restart:
187
276
  infostr = force_pipe_server? NULL : getenv ("GPG_AGENT_INFO");
188
277
  if (!infostr || !*infostr)
189
278
    {
190
279
      char *sockname;
 
280
      const char *argv[3];
 
281
      pid_t pid;
 
282
      int excode;
191
283
 
192
284
      /* First check whether we can connect at the standard
193
285
         socket.  */
194
286
      sockname = make_filename (homedir, "S.gpg-agent", NULL);
195
 
      rc = assuan_socket_connect (&ctx, sockname, 0);
 
287
      err = assuan_socket_connect (ctx, sockname, 0, 0);
196
288
 
197
 
      if (rc)
 
289
      if (err)
198
290
        {
199
291
          /* With no success start a new server.  */
200
292
          if (verbose)
210
302
              log_error ("error flushing pending output: %s\n",
211
303
                         strerror (errno));
212
304
              xfree (sockname);
 
305
              assuan_release (ctx);
213
306
              return tmperr;
214
307
            }
215
308
          
216
309
          if (!agent_program || !*agent_program)
217
310
            agent_program = gnupg_module_name (GNUPG_MODULE_NAME_AGENT);
218
311
 
219
 
#ifdef HAVE_W32_SYSTEM
220
 
          {
221
 
            /* Under Windows we start the server in daemon mode.  This
222
 
               is because the default is to use the standard socket
223
 
               and thus there is no need for the GPG_AGENT_INFO
224
 
               envvar.  This is possible as we don't have a real unix
225
 
               domain socket but use a plain file and thus there is no
226
 
               need to care about non-local file systems. */
227
 
            const char *argv[3];
228
 
 
229
 
            argv[0] = "--daemon";
230
 
            argv[1] = "--use-standard-socket"; 
231
 
            argv[2] = NULL;  
232
 
 
233
 
            rc = gnupg_spawn_process_detached (agent_program, argv, NULL);
234
 
            if (rc)
235
 
              log_debug ("failed to start agent `%s': %s\n",
236
 
                         agent_program, gpg_strerror (rc));
237
 
            else
238
 
              {
239
 
                /* Give the agent some time to prepare itself. */
240
 
                gnupg_sleep (3);
241
 
                /* Now try again to connect the agent.  */
242
 
                rc = assuan_socket_connect (&ctx, sockname, 0);
243
 
              }
244
 
          }
245
 
#else /*!HAVE_W32_SYSTEM*/
246
 
          {
247
 
            const char *pgmname;
248
 
            const char *argv[3];
249
 
            int no_close_list[3];
250
 
            int i;
251
 
 
252
 
            if ( !(pgmname = strrchr (agent_program, '/')))
253
 
              pgmname = agent_program;
254
 
            else
255
 
              pgmname++;
256
 
            
257
 
            argv[0] = pgmname;
258
 
            argv[1] = "--server";
259
 
            argv[2] = NULL;
260
 
            
261
 
            i=0;
262
 
            if (log_get_fd () != -1)
263
 
              no_close_list[i++] = log_get_fd ();
264
 
            no_close_list[i++] = fileno (stderr);
265
 
            no_close_list[i] = -1;
266
 
            
267
 
            /* Connect to the agent and perform initial handshaking. */
268
 
            rc = assuan_pipe_connect (&ctx, agent_program, argv,
269
 
                                      no_close_list);
270
 
          }
271
 
#endif /*!HAVE_W32_SYSTEM*/
 
312
          argv[0] = "--use-standard-socket-p"; 
 
313
          argv[1] = NULL;  
 
314
          err = gnupg_spawn_process_fd (agent_program, argv, -1, -1, -1, &pid);
 
315
          if (err)
 
316
            log_debug ("starting `%s' for testing failed: %s\n",
 
317
                       agent_program, gpg_strerror (err));
 
318
          else if ((err = gnupg_wait_process (agent_program, pid, &excode)))
 
319
            {
 
320
              if (excode == -1)
 
321
                log_debug ("running `%s' for testing failed: %s\n",
 
322
                           agent_program, gpg_strerror (err));
 
323
            }          
 
324
 
 
325
          if (!err && !excode)
 
326
            {
 
327
              /* If the agent has been configured for use with a
 
328
                 standard socket, an environment variable is not
 
329
                 required and thus we we can savely start the agent
 
330
                 here.  */
 
331
              lock_agent_t lock;
 
332
 
 
333
              argv[0] = "--daemon";
 
334
              argv[1] = "--use-standard-socket"; 
 
335
              argv[2] = NULL;  
 
336
 
 
337
              if (!(err = lock_agent_spawning (&lock, homedir))
 
338
                  && assuan_socket_connect (ctx, sockname, 0, 0))
 
339
                {
 
340
                  err = gnupg_spawn_process_detached (agent_program, argv,NULL);
 
341
                  if (err)
 
342
                    log_error ("failed to start agent `%s': %s\n",
 
343
                               agent_program, gpg_strerror (err));
 
344
                  else
 
345
                    {
 
346
                      int i;
 
347
 
 
348
                      if (verbose)
 
349
                        log_info (_("waiting %d seconds for the agent "
 
350
                                    "to come up\n"), 5);
 
351
                      for (i=0; i < 5; i++)
 
352
                        {
 
353
                          gnupg_sleep (1);
 
354
                          err = assuan_socket_connect (ctx, sockname, 0, 0);
 
355
                          if (!err)
 
356
                            break;
 
357
                        }
 
358
                    }
 
359
                }
 
360
 
 
361
              unlock_agent_spawning (&lock);
 
362
            }
 
363
          else
 
364
            {
 
365
              /* If using the standard socket is not the default we
 
366
                 start the agent as a pipe server which gives us most
 
367
                 of the required features except for passphrase
 
368
                 caching etc.  */
 
369
              const char *pgmname;
 
370
              int no_close_list[3];
 
371
              int i;
 
372
              
 
373
              if ( !(pgmname = strrchr (agent_program, '/')))
 
374
                pgmname = agent_program;
 
375
              else
 
376
                pgmname++;
 
377
              
 
378
              argv[0] = pgmname;
 
379
              argv[1] = "--server";
 
380
              argv[2] = NULL;
 
381
              
 
382
              i=0;
 
383
              if (log_get_fd () != -1)
 
384
                no_close_list[i++] = assuan_fd_from_posix_fd (log_get_fd ());
 
385
              no_close_list[i++] = assuan_fd_from_posix_fd (fileno (stderr));
 
386
              no_close_list[i] = -1;
 
387
              
 
388
              /* Connect to the agent and perform initial handshaking. */
 
389
              err = assuan_pipe_connect (ctx, agent_program, argv,
 
390
                                         no_close_list, NULL, NULL, 0);
 
391
            }
272
392
        }
273
393
      xfree (sockname);
274
394
    }
299
419
          goto restart;
300
420
        }
301
421
 
302
 
      rc = assuan_socket_connect (&ctx, infostr, pid);
 
422
      err = assuan_socket_connect (ctx, infostr, pid, 0);
303
423
      xfree (infostr);
304
 
      if (gpg_err_code (rc) == GPG_ERR_ASS_CONNECT_FAILED)
 
424
      if (gpg_err_code (err) == GPG_ERR_ASS_CONNECT_FAILED)
305
425
        {
306
426
          log_info (_("can't connect to the agent - trying fall back\n"));
307
427
          force_pipe_server = 1;
309
429
        }
310
430
    }
311
431
 
312
 
  if (rc)
 
432
  if (err)
313
433
    {
314
 
      log_error ("can't connect to the agent: %s\n", gpg_strerror (rc));
 
434
      log_error ("can't connect to the agent: %s\n", gpg_strerror (err));
 
435
      assuan_release (ctx);
315
436
      return gpg_error (GPG_ERR_NO_AGENT);
316
437
    }
317
438
 
318
439
  if (debug)
319
440
    log_debug ("connection to agent established\n");
320
441
 
321
 
  rc = assuan_transact (ctx, "RESET",
 
442
  err = assuan_transact (ctx, "RESET",
322
443
                        NULL, NULL, NULL, NULL, NULL, NULL);
323
 
  if (!rc)
324
 
    rc = send_pinentry_environment (ctx, errsource,
 
444
  if (!err)
 
445
    err = send_pinentry_environment (ctx, errsource,
325
446
                                    opt_lc_ctype, opt_lc_messages,
326
447
                                    session_env);
327
 
  if (rc)
 
448
  if (err)
328
449
    {
329
 
      assuan_disconnect (ctx);
330
 
      return rc;
 
450
      assuan_release (ctx);
 
451
      return err;
331
452
    }
332
453
 
333
454
  *r_ctx = ctx;