~ubuntu-branches/ubuntu/precise/gnupg2/precise-proposed

« back to all changes in this revision

Viewing changes to agent/query.c

  • Committer: Bazaar Package Importer
  • Author(s): Matthias Urlichs
  • Date: 2006-01-24 04:31:42 UTC
  • mfrom: (1.1.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20060124043142-pbg192or6qxv3yk2
Tags: 1.9.20-1
* New Upstream version. Closes:#306890,#344530
  * Closes:#320490: gpg-protect-tool fails to decrypt PKCS-12 files 
* Depend on libopensc2-dev, not -1-. Closes:#348106

Show diffs side-by-side

added added

removed removed

Lines of Context:
27
27
#include <assert.h>
28
28
#include <unistd.h>
29
29
#include <sys/stat.h>
30
 
#ifdef USE_GNU_PTH
31
 
# include <pth.h>
 
30
#ifndef HAVE_W32_SYSTEM
 
31
#include <sys/wait.h>
32
32
#endif
 
33
#include <pth.h>
33
34
 
34
35
#include "agent.h"
35
36
#include "i18n.h"
48
49
   time. */
49
50
#define LOCK_TIMEOUT  (1*60)
50
51
 
51
 
 
52
 
static assuan_context_t entry_ctx = NULL;
53
 
#ifdef USE_GNU_PTH
 
52
/* The assuan context of the current pinentry. */
 
53
static assuan_context_t entry_ctx;
 
54
 
 
55
/* The control variable of the connection owning the current pinentry.
 
56
   This is only valid if ENTRY_CTX is not NULL.  Note, that we care
 
57
   only about the value of the pointer and that it should never be
 
58
   dereferenced.  */
 
59
static ctrl_t entry_owner;
 
60
 
 
61
/* A mutex used to serialize access to the pinentry. */
54
62
static pth_mutex_t entry_lock;
55
 
#endif
56
 
 
57
 
/* data to be passed to our callbacks */
58
 
struct entry_parm_s {
 
63
 
 
64
/* The thread ID of the popup working thread. */
 
65
static pth_t  popup_tid;
 
66
 
 
67
/* A flag used in communication between the popup working thread and
 
68
   its stop function. */
 
69
static int popup_finished;
 
70
 
 
71
 
 
72
 
 
73
/* Data to be passed to our callbacks, */
 
74
struct entry_parm_s
 
75
{
59
76
  int lines;
60
77
  size_t size;
61
78
  unsigned char *buffer;
67
84
/* This function must be called once to initialize this module.  This
68
85
   has to be done before a second thread is spawned.  We can't do the
69
86
   static initialization because Pth emulation code might not be able
70
 
   to do a static init; in particualr, it is not possible for W32. */
 
87
   to do a static init; in particular, it is not possible for W32. */
71
88
void
72
89
initialize_module_query (void)
73
90
{
74
 
#ifdef USE_GNU_PTH
75
91
  static int initialized;
76
92
 
77
93
  if (!initialized)
78
 
    if (pth_mutex_init (&entry_lock))
79
 
      initialized = 1;
80
 
#endif /*USE_GNU_PTH*/
 
94
    {
 
95
      if (pth_mutex_init (&entry_lock))
 
96
        initialized = 1;
 
97
    }
81
98
}
82
99
 
83
100
 
102
119
  log_info ("agent_query_dump_state: entry_lock=");
103
120
  dump_mutex_state (&entry_lock);
104
121
  log_printf ("\n");
105
 
  log_info ("agent_query_dump_state: entry_ctx=%p pid=%ld\n",
106
 
            entry_ctx, (long)assuan_get_pid (entry_ctx));
 
122
  log_info ("agent_query_dump_state: entry_ctx=%p pid=%ld popup_tid=%p\n",
 
123
            entry_ctx, (long)assuan_get_pid (entry_ctx), popup_tid);
 
124
}
 
125
 
 
126
/* Called to make sure that a popup window owned by the current
 
127
   connection gets closed. */
 
128
void
 
129
agent_reset_query (ctrl_t ctrl)
 
130
{
 
131
  if (entry_ctx && popup_tid && entry_owner == ctrl)
 
132
    {
 
133
      agent_popup_message_stop (ctrl);
 
134
    }
107
135
}
108
136
 
109
137
 
117
145
  assuan_context_t ctx = entry_ctx;
118
146
 
119
147
  entry_ctx = NULL;
120
 
#ifdef USE_GNU_PTH
121
148
  if (!pth_mutex_release (&entry_lock))
122
149
    {
123
150
      log_error ("failed to release the entry lock\n");
124
151
      if (!rc)
125
152
        rc = gpg_error (GPG_ERR_INTERNAL);
126
153
    }
127
 
#endif
128
154
  assuan_disconnect (ctx);
129
155
  return rc;
130
156
}
145
171
   pinentry - we will serialize _all_ pinentry calls.
146
172
 */
147
173
static int
148
 
start_pinentry (CTRL ctrl)
 
174
start_pinentry (ctrl_t ctrl)
149
175
{
150
176
  int rc;
151
177
  const char *pgmname;
153
179
  const char *argv[5];
154
180
  int no_close_list[3];
155
181
  int i;
156
 
 
157
 
#ifdef USE_GNU_PTH
158
 
 {
159
 
   pth_event_t evt;
160
 
 
161
 
   evt = pth_event (PTH_EVENT_TIME, pth_timeout (LOCK_TIMEOUT, 0));
162
 
   if (!pth_mutex_acquire (&entry_lock, 0, evt))
 
182
  pth_event_t evt;
 
183
 
 
184
  evt = pth_event (PTH_EVENT_TIME, pth_timeout (LOCK_TIMEOUT, 0));
 
185
  if (!pth_mutex_acquire (&entry_lock, 0, evt))
163
186
    {
164
187
      if (pth_event_occurred (evt))
165
188
        rc = gpg_error (GPG_ERR_TIMEOUT);
170
193
                 gpg_strerror (rc));
171
194
      return rc;
172
195
    }
173
 
   pth_event_free (evt, PTH_FREE_THIS);
174
 
 }
175
 
#endif
 
196
  pth_event_free (evt, PTH_FREE_THIS);
 
197
 
 
198
  entry_owner = ctrl;
176
199
 
177
200
  if (entry_ctx)
178
201
    return 0; 
436
459
   passphrase is returned in RETPASS as an hex encoded string to be
437
460
   freed by the caller */
438
461
int 
439
 
agent_get_passphrase (CTRL ctrl,
 
462
agent_get_passphrase (ctrl_t ctrl,
440
463
                      char **retpass, const char *desc, const char *prompt,
441
464
                      const char *errtext)
442
465
{
517
540
 
518
541
 
519
542
/* Pop up the PIN-entry, display the text and the prompt and ask the
520
 
   user to confirm this.  We return 0 for success, ie. the used
 
543
   user to confirm this.  We return 0 for success, ie. the user
521
544
   confirmed it, GPG_ERR_NOT_CONFIRMED for what the text says or an
522
545
   other error. */
523
546
int 
524
 
agent_get_confirmation (CTRL ctrl,
 
547
agent_get_confirmation (ctrl_t ctrl,
525
548
                        const char *desc, const char *ok, const char *cancel)
526
549
{
527
550
  int rc;
562
585
}
563
586
 
564
587
 
 
588
/* The thread running the popup message. */
 
589
static void *
 
590
popup_message_thread (void *arg)
 
591
{
 
592
  assuan_transact (entry_ctx, "CONFIRM", NULL, NULL, NULL, NULL, NULL, NULL);
 
593
  popup_finished = 1;
 
594
  return NULL;
 
595
}
 
596
 
 
597
 
 
598
/* Pop up a message window similar to the confirm one but keep it open
 
599
   until agent_popup_message_stop has been called.  It is crucial for
 
600
   the caller to make sure that the stop function gets called as soon
 
601
   as the message is not anymore required becuase the message is
 
602
   system modal and all other attempts to use the pinentry will fail
 
603
   (after a timeout). */
 
604
int 
 
605
agent_popup_message_start (ctrl_t ctrl, const char *desc,
 
606
                           const char *ok_btn, const char *cancel_btn)
 
607
{
 
608
  int rc;
 
609
  char line[ASSUAN_LINELENGTH];
 
610
  pth_attr_t tattr;
 
611
 
 
612
  rc = start_pinentry (ctrl);
 
613
  if (rc)
 
614
    return rc;
 
615
 
 
616
  if (desc)
 
617
    snprintf (line, DIM(line)-1, "SETDESC %s", desc);
 
618
  else
 
619
    snprintf (line, DIM(line)-1, "RESET");
 
620
  line[DIM(line)-1] = 0;
 
621
  rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
 
622
  if (rc)
 
623
    return unlock_pinentry (map_assuan_err (rc));
 
624
 
 
625
  if (ok_btn)
 
626
    {
 
627
      snprintf (line, DIM(line)-1, "SETOK %s", ok_btn);
 
628
      line[DIM(line)-1] = 0;
 
629
      rc = assuan_transact (entry_ctx, line, NULL,NULL,NULL,NULL,NULL,NULL);
 
630
      if (rc)
 
631
        return unlock_pinentry (map_assuan_err (rc));
 
632
    }
 
633
  if (cancel_btn)
 
634
    {
 
635
      snprintf (line, DIM(line)-1, "SETCANCEL %s", cancel_btn);
 
636
      line[DIM(line)-1] = 0;
 
637
      rc = assuan_transact (entry_ctx, line, NULL,NULL,NULL,NULL,NULL,NULL);
 
638
      if (rc)
 
639
        return unlock_pinentry (map_assuan_err (rc));
 
640
    }
 
641
 
 
642
  tattr = pth_attr_new();
 
643
  pth_attr_set (tattr, PTH_ATTR_JOINABLE, 1);
 
644
  pth_attr_set (tattr, PTH_ATTR_STACK_SIZE, 256*1024);
 
645
  pth_attr_set (tattr, PTH_ATTR_NAME, "popup-message");
 
646
 
 
647
  popup_finished = 0;
 
648
  popup_tid = pth_spawn (tattr, popup_message_thread, NULL);
 
649
  if (!popup_tid)
 
650
    {
 
651
      rc = gpg_error_from_errno (errno);
 
652
      log_error ("error spawning popup message handler: %s\n",
 
653
                 strerror (errno) );
 
654
      pth_attr_destroy (tattr);
 
655
      return unlock_pinentry (rc);
 
656
    }
 
657
  pth_attr_destroy (tattr);
 
658
 
 
659
  return 0;
 
660
}
 
661
 
 
662
/* Close a popup window. */
 
663
void
 
664
agent_popup_message_stop (ctrl_t ctrl)
 
665
{
 
666
  int rc;
 
667
  pid_t pid;
 
668
 
 
669
  if (!popup_tid || !entry_ctx)
 
670
    {
 
671
      log_debug ("agent_popup_message_stop called with no active popup\n");
 
672
      return; 
 
673
    }
 
674
 
 
675
  pid = assuan_get_pid (entry_ctx);
 
676
  if (pid == (pid_t)(-1))
 
677
    ; /* No pid available can't send a kill. */
 
678
  else if (popup_finished)
 
679
    ; /* Already finished and ready for joining. */
 
680
  else if (pid && ((rc=waitpid (pid, NULL, WNOHANG))==-1 || (rc == pid)) )
 
681
    { /* The daemon already died.  No need to send a kill.  However
 
682
         because we already waited for the process, we need to tell
 
683
         assuan that it should not wait again (done by
 
684
         unlock_pinentry). */
 
685
      if (rc == pid)
 
686
        assuan_set_flag (entry_ctx, ASSUAN_NO_WAITPID, 1);
 
687
    }
 
688
  else
 
689
    kill (pid, SIGINT);
 
690
 
 
691
  /* Now wait for the thread to terminate. */
 
692
  rc = pth_join (popup_tid, NULL);
 
693
  if (!rc)
 
694
    log_debug ("agent_popup_message_stop: pth_join failed: %s\n",
 
695
               strerror (errno));
 
696
  popup_tid = NULL;
 
697
  entry_owner = NULL;
 
698
 
 
699
  /* Now we can close the connection. */
 
700
  unlock_pinentry (0);
 
701
}
 
702
 
565
703