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

« back to all changes in this revision

Viewing changes to scd/command.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
/* command.c - SCdaemon command handler
2
 
 * Copyright (C) 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
 
2
 * Copyright (C) 2001, 2002, 2003, 2004, 2005,
 
3
 *               2007  Free Software Foundation, Inc.
3
4
 *
4
5
 * This file is part of GnuPG.
5
6
 *
6
7
 * GnuPG is free software; you can redistribute it and/or modify
7
8
 * 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
 
9
 * the Free Software Foundation; either version 3 of the License, or
9
10
 * (at your option) any later version.
10
11
 *
11
12
 * GnuPG is distributed in the hope that it will be useful,
14
15
 * GNU General Public License for more details.
15
16
 *
16
17
 * 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
 
18
 * along with this program; if not, see <http://www.gnu.org/licenses/>.
19
19
 */
20
20
 
21
21
#include <config.h>
36
36
#include <ksba.h>
37
37
#include "app-common.h"
38
38
#include "apdu.h" /* Required for apdu_*_reader (). */
 
39
#include "exechelp.h"
 
40
#ifdef HAVE_LIBUSB
 
41
#include "ccid-driver.h"
 
42
#endif
39
43
 
40
44
/* Maximum length allowed as a PIN; used for INQUIRE NEEDPIN */
41
45
#define MAXLEN_PIN 100
44
48
#define MAXLEN_KEYDATA 4096
45
49
 
46
50
 
47
 
#define set_error(e,t) assuan_set_error (ctx, ASSUAN_ ## e, (t))
48
 
 
49
 
 
50
 
/* Macro to flag a a removed card.  */
 
51
#define set_error(e,t) assuan_set_error (ctx, gpg_error (e), (t))
 
52
 
 
53
 
 
54
/* Macro to flag a removed card.  */
51
55
#define TEST_CARD_REMOVAL(c,r)                              \
52
56
       do {                                                 \
53
57
          int _r = (r);                                     \
62
66
      && (c)->reader_slot == locked_session->ctrl_backlink->reader_slot)
63
67
 
64
68
 
 
69
/* This structure is used to keep track of open readers (slots). */
 
70
struct slot_status_s 
 
71
{
 
72
  int valid;  /* True if the other objects are valid. */
 
73
  int slot;   /* Slot number of the reader or -1 if not open. */
 
74
 
 
75
  int reset_failed; /* A reset failed. */
 
76
 
 
77
  int any;    /* Flag indicating whether any status check has been
 
78
                 done.  This is set once to indicate that the status
 
79
                 tracking for the slot has been initialized.  */
 
80
  unsigned int status;  /* Last status of the slot. */
 
81
  unsigned int changed; /* Last change counter of teh slot. */
 
82
};
 
83
 
 
84
 
65
85
/* Data used to associate an Assuan context with local server data.
66
86
   This object describes the local properties of one session.  */
67
 
struct server_local_s {
 
87
struct server_local_s 
 
88
{
68
89
  /* We keep a list of all active sessions with the anchor at
69
90
     SESSION_LIST (see below).  This field is used for linking. */
70
91
  struct server_local_s *next_session; 
86
107
};
87
108
 
88
109
 
 
110
/* The table with information on all used slots.  FIXME: This is a
 
111
   different slot number than the one used by the APDU layer, and
 
112
   should be renamed.  */
 
113
static struct slot_status_s slot_table[10];
 
114
 
 
115
 
89
116
/* To keep track of all running sessions, we link all active server
90
117
   contexts and the anchor in this variable.  */
91
118
static struct server_local_s *session_list;
94
121
   in this variable. */
95
122
static struct server_local_s *locked_session;
96
123
 
97
 
 
98
 
 
99
 
 
 
124
/* While doing a reset we need to make sure that the ticker does not
 
125
   call scd_update_reader_status_file while we are using it. */
 
126
static pth_mutex_t status_file_update_lock;
 
127
 
 
128
 
 
129
/*-- Local prototypes --*/
 
130
static void update_reader_status_file (void);
 
131
 
 
132
 
 
133
 
 
134
 
 
135
/* This function must be called once to initialize this module.  This
 
136
   has to be done before a second thread is spawned.  We can't do the
 
137
   static initialization because Pth emulation code might not be able
 
138
   to do a static init; in particular, it is not possible for W32. */
 
139
void
 
140
initialize_module_command (void)
 
141
{
 
142
  static int initialized;
 
143
 
 
144
  if (!initialized)
 
145
    {
 
146
      if (pth_mutex_init (&status_file_update_lock))
 
147
        initialized = 1;
 
148
    }
 
149
}
 
150
 
 
151
 
100
152
/* Update the CARD_REMOVED element of all sessions using the reader
101
153
   given by SLOT to VALUE  */
102
154
static void
107
159
  for (sl=session_list; sl; sl = sl->next_session)
108
160
    if (sl->ctrl_backlink
109
161
        && sl->ctrl_backlink->reader_slot == slot)
110
 
      sl->card_removed = value;
 
162
      {
 
163
        sl->card_removed = value;
 
164
      }
 
165
  if (value)
 
166
    application_notify_card_removed (slot);
111
167
}
112
168
 
113
169
 
123
179
  return (s && (s == line || spacep (s-1)) && (!s[n] || spacep (s+n)));
124
180
}
125
181
 
126
 
 
127
 
/* Reset the card and free the application context.  With DO_CLOSE set
128
 
   to true and this is the last session with a reference to the
129
 
   reader, close the reader and don't do just a reset. */
 
182
/* Same as has_option but does only test for the name of the option
 
183
   and ignores an argument, i.e. with NAME being "--hash" it would
 
184
   return a pointer for "--hash" as well as for "--hash=foo".  If
 
185
   thhere is no such option NULL is returned.  The pointer returned
 
186
   points right behind the option name, this may be an equal sign, Nul
 
187
   or a space.  */
 
188
static const char *
 
189
has_option_name (const char *line, const char *name)
 
190
{
 
191
  const char *s;
 
192
  int n = strlen (name);
 
193
 
 
194
  s = strstr (line, name);
 
195
  return (s && (s == line || spacep (s-1))
 
196
          && (!s[n] || spacep (s+n) || s[n] == '=')) ? (s+n) : NULL;
 
197
}
 
198
 
 
199
 
 
200
/* Skip over options.  It is assumed that leading spaces have been
 
201
   removed (this is the case for lines passed to a handler from
 
202
   assuan).  Blanks after the options are also removed. */
 
203
static char *
 
204
skip_options (char *line)
 
205
{
 
206
  while ( *line == '-' && line[1] == '-' )
 
207
    {
 
208
      while (*line && !spacep (line))
 
209
        line++;
 
210
      while (spacep (line))
 
211
        line++;
 
212
    }
 
213
  return line;
 
214
}
 
215
 
 
216
 
 
217
 
 
218
/* Convert the STRING into a newly allocated buffer while translating
 
219
   the hex numbers.  Stops at the first invalid character.  Blanks and
 
220
   colons are allowed to separate the hex digits.  Returns NULL on
 
221
   error or a newly malloced buffer and its length in LENGTH.  */
 
222
static unsigned char *
 
223
hex_to_buffer (const char *string, size_t *r_length)
 
224
{
 
225
  unsigned char *buffer;
 
226
  const char *s;
 
227
  size_t n;
 
228
 
 
229
  buffer = xtrymalloc (strlen (string)+1);
 
230
  if (!buffer)
 
231
    return NULL;
 
232
  for (s=string, n=0; *s; s++)
 
233
    {
 
234
      if (spacep (s) || *s == ':') 
 
235
        continue;
 
236
      if (hexdigitp (s) && hexdigitp (s+1))
 
237
        {
 
238
          buffer[n++] = xtoi_2 (s);
 
239
          s++;
 
240
        }
 
241
      else
 
242
        break;
 
243
    }
 
244
  *r_length = n;
 
245
  return buffer;
 
246
}
 
247
 
 
248
 
 
249
 
 
250
/* Reset the card and free the application context.  With SEND_RESET
 
251
   set to true actually send a RESET to the reader. */
130
252
static void
131
 
do_reset (ctrl_t ctrl, int do_close)
 
253
do_reset (ctrl_t ctrl, int send_reset)
132
254
{
133
255
  int slot = ctrl->reader_slot;
134
256
 
 
257
  if (!(slot == -1 || (slot >= 0 && slot < DIM(slot_table))))
 
258
    BUG ();
 
259
 
135
260
  if (ctrl->app_ctx)
136
261
    {
137
262
      release_application (ctrl->app_ctx);
138
263
      ctrl->app_ctx = NULL;
139
264
    }
140
 
  if (ctrl->reader_slot != -1)
141
 
    {
142
 
      struct server_local_s *sl;
143
 
 
144
 
      /* If we are the only session with the reader open we may close
145
 
         it.  If not, do a reset unless the a lock is held on the
146
 
         reader.  */
147
 
      for (sl=session_list; sl; sl = sl->next_session)
148
 
        if (sl != ctrl->server_local
149
 
            && sl->ctrl_backlink->reader_slot == ctrl->reader_slot)
150
 
          break;
151
 
      if (sl) /* There is another session with the reader open. */
152
 
        {
153
 
          if ( IS_LOCKED (ctrl) ) /* If it is locked, release it. */
154
 
            ctrl->reader_slot = -1;
155
 
          else
156
 
            {
157
 
              if (do_close) /* Always mark reader unused. */
158
 
                ctrl->reader_slot = -1;
159
 
              else if (apdu_reset (ctrl->reader_slot)) /* Reset only if
160
 
                                                          not locked */
161
 
                {
162
 
                  /* The reset failed.  Mark the reader as closed. */
163
 
                  ctrl->reader_slot = -1;
164
 
                }
165
 
 
166
 
              if (locked_session && ctrl->server_local == locked_session)
167
 
                {
168
 
                  locked_session = NULL;
169
 
                  log_debug ("implicitly unlocking due to RESET\n");
170
 
                }
171
 
            }
172
 
        }
173
 
      else /* No other session has the reader open.  */
174
 
        {
175
 
          if (do_close || apdu_reset (ctrl->reader_slot))
176
 
            {
177
 
              apdu_close_reader (ctrl->reader_slot);
178
 
              ctrl->reader_slot = -1;
179
 
            }
180
 
          if ( IS_LOCKED (ctrl) )
181
 
            {
182
 
              log_debug ("WARNING: cleaning up stale session lock\n");
183
 
              locked_session =  NULL;
184
 
            }
185
 
        }
186
 
    }
187
 
 
188
 
  /* Reset card removed flag for the current reader.  */
 
265
 
 
266
  if (slot != -1 && send_reset && !IS_LOCKED (ctrl) )
 
267
    {
 
268
      if (apdu_reset (slot)) 
 
269
        {
 
270
          slot_table[slot].reset_failed = 1;
 
271
        }
 
272
    }
 
273
 
 
274
  /* If we hold a lock, unlock now. */
 
275
  if (locked_session && ctrl->server_local == locked_session)
 
276
    {
 
277
      locked_session = NULL;
 
278
      log_info ("implicitly unlocking due to RESET\n");
 
279
    }
 
280
 
 
281
  /* Reset card removed flag for the current reader.  We need to take
 
282
     the lock here so that the ticker thread won't concurrently try to
 
283
     update the file.  Note that the update function will set the card
 
284
     removed flag and we will later reset it - not a particualar nice
 
285
     way of implementing it but it works. */
 
286
  if (!pth_mutex_acquire (&status_file_update_lock, 0, NULL))
 
287
    {
 
288
      log_error ("failed to acquire status_fle_update lock\n");
 
289
      ctrl->reader_slot = -1;
 
290
      return;
 
291
    }
 
292
  update_reader_status_file ();
189
293
  update_card_removed (slot, 0);
 
294
  if (!pth_mutex_release (&status_file_update_lock))
 
295
    log_error ("failed to release status_file_update lock\n");
 
296
 
 
297
  /* Do this last, so that update_card_removed does its job.  */
 
298
  ctrl->reader_slot = -1;
190
299
}
191
300
 
192
301
 
195
304
{
196
305
  ctrl_t ctrl = assuan_get_pointer (ctx); 
197
306
 
198
 
  do_reset (ctrl, 0);
 
307
  do_reset (ctrl, 1);
199
308
}
200
309
 
201
310
 
209
318
      /* A value of 0 is allowed to reset the event signal. */
210
319
      int i = *value? atoi (value) : -1;
211
320
      if (i < 0)
212
 
        return ASSUAN_Parameter_Error;
 
321
        return gpg_error (GPG_ERR_ASS_PARAMETER);
213
322
      ctrl->server_local->event_signal = i;
214
323
    }
215
324
 
224
333
static int
225
334
get_reader_slot (void)
226
335
{
227
 
  struct server_local_s *sl;
228
 
  int slot= -1;
229
 
 
230
 
  for (sl=session_list; sl; sl = sl->next_session)
231
 
    if (sl->ctrl_backlink
232
 
        && (slot = sl->ctrl_backlink->reader_slot) != -1)
233
 
      break;
234
 
 
235
 
  if (slot == -1)
236
 
    slot = apdu_open_reader (opt.reader_port);
237
 
 
238
 
  return slot;
 
336
  struct slot_status_s *ss;
 
337
 
 
338
  ss = &slot_table[0]; /* One reader for now. */
 
339
 
 
340
  /* Initialize the item if needed. */
 
341
  if (!ss->valid)
 
342
    {
 
343
      ss->slot = -1;
 
344
      ss->valid = 1;
 
345
    }
 
346
 
 
347
  /* Try to open the reader. */
 
348
  if (ss->slot == -1)
 
349
    ss->slot = apdu_open_reader (opt.reader_port);
 
350
 
 
351
  /* Return the slot_table index.  */
 
352
  return 0;
239
353
}
240
354
 
241
355
/* If the card has not yet been opened, do it.  Note that this
242
356
   function returns an Assuan error, so don't map the error a second
243
 
   time */
 
357
   time.  */
244
358
static assuan_error_t
245
359
open_card (ctrl_t ctrl, const char *apptype)
246
360
{
251
365
     the SERIALNO command and a reset are able to clear from that
252
366
     state. */
253
367
  if (ctrl->server_local->card_removed)
254
 
    return map_to_assuan_status (gpg_error (GPG_ERR_CARD_REMOVED));
 
368
    return gpg_error (GPG_ERR_CARD_REMOVED);
255
369
 
256
370
  if ( IS_LOCKED (ctrl) )
257
371
    return gpg_error (GPG_ERR_LOCKED);
258
372
 
259
373
  if (ctrl->app_ctx)
260
 
    return 0; /* Already initialized for one specific application. */
 
374
    {
 
375
      /* Already initialized for one specific application.  Need to
 
376
         check that the client didn't requested a specific application
 
377
         different from the one in use. */
 
378
      return check_application_conflict (ctrl, apptype);
 
379
    }
261
380
 
262
381
  if (ctrl->reader_slot != -1)
263
382
    slot = ctrl->reader_slot;
270
389
    err = select_application (ctrl, slot, apptype, &ctrl->app_ctx);
271
390
 
272
391
  TEST_CARD_REMOVAL (ctrl, err);
273
 
  return map_to_assuan_status (err);
 
392
  return err;
274
393
}
275
394
 
276
395
 
342
461
    {
343
462
      if ( IS_LOCKED (ctrl) )
344
463
        return gpg_error (GPG_ERR_LOCKED);
345
 
      do_reset (ctrl, 0);
 
464
      do_reset (ctrl, 1);
346
465
    }
347
466
 
348
467
  if ((rc = open_card (ctrl, *line? line:NULL)))
350
469
 
351
470
  rc = app_get_serial_and_stamp (ctrl->app_ctx, &serial, &stamp);
352
471
  if (rc)
353
 
    return map_to_assuan_status (rc);
 
472
    return rc;
354
473
 
355
474
  rc = asprintf (&serial_and_stamp, "%s %lu", serial, (unsigned long)stamp);
356
475
  xfree (serial);
357
476
  if (rc < 0)
358
 
    return ASSUAN_Out_Of_Core;
 
477
    return out_of_core ();
359
478
  rc = 0;
360
479
  assuan_write_status (ctx, "SERIALNO", serial_and_stamp);
361
480
  free (serial_and_stamp);
447
566
 
448
567
    rc = app_get_serial_and_stamp (ctrl->app_ctx, &serial, &stamp);
449
568
    if (rc)
450
 
      return map_to_assuan_status (rc);
 
569
      return rc;
451
570
    rc = asprintf (&serial_and_stamp, "%s %lu", serial, (unsigned long)stamp);
452
571
    xfree (serial);
453
572
    if (rc < 0)
454
 
      return ASSUAN_Out_Of_Core;
 
573
      return out_of_core ();
455
574
    rc = 0;
456
575
    assuan_write_status (ctx, "SERIALNO", serial_and_stamp);
457
576
 
463
582
        if (rc < 0)
464
583
          {
465
584
            free (serial_and_stamp);
466
 
            return ASSUAN_Out_Of_Core;
 
585
            return out_of_core ();
467
586
          }
468
587
        rc = 0;
469
588
        rc = assuan_inquire (ctx, command, NULL, NULL, 0); 
470
589
        free (command);  /* (must use standard free here) */
471
590
        if (rc)
472
591
          {
473
 
            if (rc != ASSUAN_Canceled)
 
592
            if (gpg_err_code (rc) != GPG_ERR_ASS_CANCELED)
474
593
              log_error ("inquire KNOWNCARDP failed: %s\n",
475
 
                         assuan_strerror (rc));
 
594
                         gpg_strerror (rc));
476
595
            free (serial_and_stamp);
477
596
            return rc; 
478
597
          }
487
606
    rc = app_write_learn_status (ctrl->app_ctx, ctrl);
488
607
 
489
608
  TEST_CARD_REMOVAL (ctrl, rc);
490
 
  return map_to_assuan_status (rc);
 
609
  return rc;
491
610
}
492
611
 
493
612
 
522
641
    }
523
642
 
524
643
  TEST_CARD_REMOVAL (ctrl, rc);
525
 
  return map_to_assuan_status (rc);
 
644
  return rc;
526
645
}
527
646
 
528
647
 
557
676
    { /* Yeah, got that key - send it back.  */
558
677
      rc = assuan_send_data (ctx, pk, pklen);
559
678
      xfree (pk);
560
 
      rc = map_assuan_err (rc);
561
679
      xfree (line);
562
680
      line = NULL;
563
681
      goto leave;
598
716
 
599
717
  n = gcry_sexp_canon_len (p, 0, NULL, NULL);
600
718
  rc = assuan_send_data (ctx, p, n);
601
 
  rc = map_assuan_err (rc);
602
719
  xfree (p);
603
720
 
604
721
 
606
723
  ksba_cert_release (kc);
607
724
  xfree (cert);
608
725
  TEST_CARD_REMOVAL (ctrl, rc);
609
 
  return map_to_assuan_status (rc);
 
726
  return rc;
610
727
}
611
728
 
612
729
 
631
748
  for (p=line,n=0; hexdigitp (p); p++, n++)
632
749
    ;
633
750
  if (*p)
634
 
    return set_error (Parameter_Error, "invalid hexstring");
 
751
    return set_error (GPG_ERR_ASS_PARAMETER, "invalid hexstring");
635
752
  if (!n)
636
 
    return set_error (Parameter_Error, "no data given");
 
753
    return set_error (GPG_ERR_ASS_PARAMETER, "no data given");
637
754
  if ((n&1))
638
 
    return set_error (Parameter_Error, "odd number of digits");
 
755
    return set_error (GPG_ERR_ASS_PARAMETER, "odd number of digits");
639
756
  n /= 2;
640
757
  buf = xtrymalloc (n);
641
758
  if (!buf)
642
 
    return ASSUAN_Out_Of_Core;
 
759
    return out_of_core ();
643
760
 
644
761
  ctrl->in_data.value = buf;
645
762
  ctrl->in_data.valuelen = n;
659
776
  unsigned char *value;
660
777
  size_t valuelen;
661
778
 
 
779
  if (!retstr)
 
780
    {
 
781
      /* We prompt for keypad entry.  To make sure that the popup has
 
782
         been show we use an inquire and not just a status message.
 
783
         We ignore any value returned.  */
 
784
      if (info)
 
785
        {
 
786
          log_debug ("prompting for keypad entry '%s'\n", info);
 
787
          rc = asprintf (&command, "POPUPKEYPADPROMPT %s", info);
 
788
          if (rc < 0)
 
789
            return gpg_error (gpg_err_code_from_errno (errno));
 
790
          rc = assuan_inquire (ctx, command, &value, &valuelen, MAXLEN_PIN); 
 
791
          free (command);  
 
792
        }
 
793
      else
 
794
        {
 
795
          log_debug ("dismiss keypad entry prompt\n");
 
796
          rc = assuan_inquire (ctx, "DISMISSKEYPADPROMPT",
 
797
                               &value, &valuelen, MAXLEN_PIN); 
 
798
        }
 
799
      if (!rc)
 
800
        xfree (value);
 
801
      return rc;
 
802
    }
 
803
 
662
804
  *retstr = NULL;
663
805
  log_debug ("asking for PIN '%s'\n", info);
664
806
 
671
813
  rc = assuan_inquire (ctx, command, &value, &valuelen, MAXLEN_PIN); 
672
814
  free (command);  
673
815
  if (rc)
674
 
    return map_assuan_err (rc);
 
816
    return rc;
675
817
 
676
818
  if (!valuelen || value[valuelen-1])
677
819
    {
684
826
}
685
827
 
686
828
 
687
 
/* PKSIGN <hexified_id>
 
829
/* PKSIGN [--hash=[rmd160|sha1|md5]] <hexified_id>
 
830
 
 
831
   The --hash option is optional; the default is SHA1.
688
832
 
689
833
 */
690
834
static int
695
839
  unsigned char *outdata;
696
840
  size_t outdatalen;
697
841
  char *keyidstr;
 
842
  int hash_algo;
 
843
 
 
844
  if (has_option (line, "--hash=rmd160"))
 
845
    hash_algo = GCRY_MD_RMD160;
 
846
  else if (has_option (line, "--hash=sha1"))
 
847
    hash_algo = GCRY_MD_SHA1;
 
848
  else if (has_option (line, "--hash=md5"))
 
849
    hash_algo = GCRY_MD_MD5;
 
850
  else if (!strstr (line, "--"))
 
851
    hash_algo = GCRY_MD_SHA1; 
 
852
  else
 
853
    return set_error (GPG_ERR_ASS_PARAMETER, "invalid hash algorithm");
 
854
  /* Skip over options. */
 
855
  while ( *line == '-' && line[1] == '-' )
 
856
    {
 
857
      while (*line && !spacep (line))
 
858
        line++;
 
859
      while (spacep (line))
 
860
        line++;
 
861
    }
698
862
 
699
863
  if ( IS_LOCKED (ctrl) )
700
864
    return gpg_error (GPG_ERR_LOCKED);
707
871
     overwriting the original line with the keyid */
708
872
  keyidstr = xtrystrdup (line);
709
873
  if (!keyidstr)
710
 
    return ASSUAN_Out_Of_Core;
 
874
    return out_of_core ();
711
875
  
712
876
  rc = app_sign (ctrl->app_ctx,
713
 
                 keyidstr, GCRY_MD_SHA1,
 
877
                 keyidstr, hash_algo,
714
878
                 pin_cb, ctx,
715
879
                 ctrl->in_data.value, ctrl->in_data.valuelen,
716
880
                 &outdata, &outdatalen);
729
893
    }
730
894
 
731
895
  TEST_CARD_REMOVAL (ctrl, rc);
732
 
  return map_to_assuan_status (rc);
 
896
  return rc;
733
897
}
734
898
 
735
899
/* PKAUTH <hexified_id>
753
917
  if (!ctrl->app_ctx)
754
918
    return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
755
919
 
756
 
  /* We have to use a copy of the key ID because the function may use
 
920
 /* We have to use a copy of the key ID because the function may use
757
921
     the pin_cb which in turn uses the assuan line buffer and thus
758
922
     overwriting the original line with the keyid */
759
923
  keyidstr = xtrystrdup (line);
760
924
  if (!keyidstr)
761
 
    return ASSUAN_Out_Of_Core;
 
925
    return out_of_core ();
762
926
  
763
927
  rc = app_auth (ctrl->app_ctx,
764
928
                 keyidstr,
779
943
    }
780
944
 
781
945
  TEST_CARD_REMOVAL (ctrl, rc);
782
 
  return map_to_assuan_status (rc);
 
946
  return rc;
783
947
}
784
948
 
785
949
/* PKDECRYPT <hexified_id>
802
966
 
803
967
  keyidstr = xtrystrdup (line);
804
968
  if (!keyidstr)
805
 
    return ASSUAN_Out_Of_Core;
 
969
    return out_of_core ();
806
970
  rc = app_decipher (ctrl->app_ctx,
807
971
                     keyidstr, 
808
972
                     pin_cb, ctx,
823
987
    }
824
988
 
825
989
  TEST_CARD_REMOVAL (ctrl, rc);
826
 
  return map_to_assuan_status (rc);
 
990
  return rc;
827
991
}
828
992
 
829
993
 
857
1021
 
858
1022
  /* (We ignore any garbage for now.) */
859
1023
 
860
 
  /* FIXME: Applications should not return sensistive data if the card
 
1024
  /* FIXME: Applications should not return sensitive data if the card
861
1025
     is locked.  */
862
1026
  rc = app_getattr (ctrl->app_ctx, ctrl, keyword);
863
1027
 
864
1028
  TEST_CARD_REMOVAL (ctrl, rc);
865
 
  return map_to_assuan_status (rc);
 
1029
  return rc;
866
1030
}
867
1031
 
868
1032
 
898
1062
     context and thus reuses the Assuan provided LINE. */
899
1063
  line = linebuf = xtrystrdup (orig_line);
900
1064
  if (!line)
901
 
    return ASSUAN_Out_Of_Core;
 
1065
    return out_of_core ();
902
1066
 
903
1067
  keyword = line;
904
1068
  for (keywordlen=0; *line && !spacep (line); line++, keywordlen++)
914
1078
  xfree (linebuf);
915
1079
 
916
1080
  TEST_CARD_REMOVAL (ctrl, rc);
917
 
  return map_to_assuan_status (rc);
 
1081
  return rc;
918
1082
}
919
1083
 
920
1084
 
954
1118
        line++;
955
1119
    }
956
1120
  if (!*line)
957
 
    return set_error (Parameter_Error, "no keyid given");
 
1121
    return set_error (GPG_ERR_ASS_PARAMETER, "no keyid given");
958
1122
  keyid = line;
959
1123
  while (*line && !spacep (line))
960
1124
    line++;
968
1132
 
969
1133
  keyid = xtrystrdup (keyid);
970
1134
  if (!keyid)
971
 
    return ASSUAN_Out_Of_Core;
 
1135
    return out_of_core ();
972
1136
 
973
1137
  /* Now get the actual keydata. */
 
1138
  assuan_begin_confidential (ctx);
974
1139
  rc = assuan_inquire (ctx, "KEYDATA", &keydata, &keydatalen, MAXLEN_KEYDATA);
 
1140
  assuan_end_confidential (ctx);
975
1141
  if (rc)
976
1142
    {
977
1143
      xfree (keyid);
985
1151
  xfree (keydata);
986
1152
 
987
1153
  TEST_CARD_REMOVAL (ctrl, rc);
988
 
  return map_to_assuan_status (rc);
 
1154
  return rc;
989
1155
}
990
1156
 
991
1157
 
992
1158
 
993
 
/* GENKEY [--force] <no>
 
1159
/* GENKEY [--force] [--timestamp=<isodate>] <no>
994
1160
 
995
1161
   Generate a key on-card identified by NO, which is application
996
1162
   specific.  Return values are application specific.  For OpenPGP
1000
1166
     S KEY-CREATED-AT <seconds_since_epoch>
1001
1167
     S KEY-DATA [p|n] <hexdata>
1002
1168
     
1003
 
 
1004
1169
   --force is required to overwrite an already existing key.  The
1005
1170
   KEY-CREATED-AT is required for further processing because it is
1006
1171
   part of the hashed key material for the fingerprint.
1007
1172
 
 
1173
   If --timestamp is given an OpenPGP key will be created using this
 
1174
   value.  The value needs to be in ISO Format; e.g.
 
1175
   "--timestamp=20030316T120000" and after 1970-01-01 00:00:00.
 
1176
 
1008
1177
   The public part of the key can also later be retrieved using the
1009
1178
   READKEY command.
1010
1179
 
1015
1184
  ctrl_t ctrl = assuan_get_pointer (ctx);
1016
1185
  int rc;
1017
1186
  char *keyno;
1018
 
  int force = has_option (line, "--force");
 
1187
  int force;
 
1188
  const char *s;
 
1189
  time_t timestamp;
1019
1190
 
1020
1191
  if ( IS_LOCKED (ctrl) )
1021
1192
    return gpg_error (GPG_ERR_LOCKED);
1022
1193
 
1023
 
  /* Skip over options. */
1024
 
  while ( *line == '-' && line[1] == '-' )
 
1194
  force = has_option (line, "--force");
 
1195
 
 
1196
  if ((s=has_option_name (line, "--timestamp")))
1025
1197
    {
1026
 
      while (*line && !spacep (line))
1027
 
        line++;
1028
 
      while (spacep (line))
1029
 
        line++;
 
1198
      if (*s != '=')
 
1199
        return set_error (GPG_ERR_ASS_PARAMETER, "missing value for option");
 
1200
      timestamp = isotime2epoch (s+1);
 
1201
      if (timestamp < 1)
 
1202
        return set_error (GPG_ERR_ASS_PARAMETER, "invalid time value");
1030
1203
    }
 
1204
  else
 
1205
    timestamp = 0;
 
1206
 
 
1207
 
 
1208
  line = skip_options (line);
1031
1209
  if (!*line)
1032
 
    return set_error (Parameter_Error, "no key number given");
 
1210
    return set_error (GPG_ERR_ASS_PARAMETER, "no key number given");
1033
1211
  keyno = line;
1034
1212
  while (*line && !spacep (line))
1035
1213
    line++;
1043
1221
 
1044
1222
  keyno = xtrystrdup (keyno);
1045
1223
  if (!keyno)
1046
 
    return ASSUAN_Out_Of_Core;
1047
 
  rc = app_genkey (ctrl->app_ctx, ctrl, keyno, force? 1:0, pin_cb, ctx);
 
1224
    return out_of_core ();
 
1225
  rc = app_genkey (ctrl->app_ctx, ctrl, keyno, force? 1:0,
 
1226
                   timestamp, pin_cb, ctx);
1048
1227
  xfree (keyno);
1049
1228
 
1050
1229
  TEST_CARD_REMOVAL (ctrl, rc);
1051
 
  return map_to_assuan_status (rc);
 
1230
  return rc;
1052
1231
}
1053
1232
 
1054
1233
 
1067
1246
  unsigned char *buffer;
1068
1247
 
1069
1248
  if (!*line)
1070
 
    return set_error (Parameter_Error, "number of requested bytes missing");
 
1249
    return set_error (GPG_ERR_ASS_PARAMETER, "number of requested bytes missing");
1071
1250
  nbytes = strtoul (line, NULL, 0);
1072
1251
 
1073
1252
  if ((rc = open_card (ctrl, NULL)))
1078
1257
 
1079
1258
  buffer = xtrymalloc (nbytes);
1080
1259
  if (!buffer)
1081
 
    return ASSUAN_Out_Of_Core;
 
1260
    return out_of_core ();
1082
1261
 
1083
1262
  rc = app_get_challenge (ctrl->app_ctx, nbytes, buffer);
1084
1263
  if (!rc)
1090
1269
  xfree (buffer);
1091
1270
 
1092
1271
  TEST_CARD_REMOVAL (ctrl, rc);
1093
 
  return map_to_assuan_status (rc);
 
1272
  return rc;
1094
1273
}
1095
1274
 
1096
1275
 
1118
1297
        line++;
1119
1298
    }
1120
1299
  if (!*line)
1121
 
    return set_error (Parameter_Error, "no CHV number given");
 
1300
    return set_error (GPG_ERR_ASS_PARAMETER, "no CHV number given");
1122
1301
  chvnostr = line;
1123
1302
  while (*line && !spacep (line))
1124
1303
    line++;
1132
1311
  
1133
1312
  chvnostr = xtrystrdup (chvnostr);
1134
1313
  if (!chvnostr)
1135
 
    return ASSUAN_Out_Of_Core;
 
1314
    return out_of_core ();
1136
1315
  rc = app_change_pin (ctrl->app_ctx, ctrl, chvnostr, reset_mode, pin_cb, ctx);
1137
1316
  if (rc)
1138
1317
    log_error ("command passwd failed: %s\n", gpg_strerror (rc));
1139
1318
  xfree (chvnostr);
1140
1319
 
1141
1320
  TEST_CARD_REMOVAL (ctrl, rc);
1142
 
  return map_to_assuan_status (rc);
 
1321
  return rc;
1143
1322
}
1144
1323
 
1145
1324
 
1183
1362
     overwriting the original line with the keyid. */
1184
1363
  keyidstr = xtrystrdup (line);
1185
1364
  if (!keyidstr)
1186
 
    return ASSUAN_Out_Of_Core;
 
1365
    return out_of_core ();
1187
1366
  
1188
1367
  rc = app_check_pin (ctrl->app_ctx,
1189
1368
                      keyidstr,
1193
1372
    log_error ("app_check_pin failed: %s\n", gpg_strerror (rc));
1194
1373
 
1195
1374
  TEST_CARD_REMOVAL (ctrl, rc);
1196
 
  return map_to_assuan_status (rc);
 
1375
  return rc;
1197
1376
}
1198
1377
 
1199
1378
 
1201
1380
 
1202
1381
   Grant exclusive card access to this session.  Note that there is
1203
1382
   no lock counter used and a second lock from the same session will
1204
 
   get ignore.  A single unlock (or RESET) unlocks the session.
 
1383
   be ignored.  A single unlock (or RESET) unlocks the session.
1205
1384
   Return GPG_ERR_LOCKED if another session has locked the reader.
1206
1385
 
1207
1386
   If the option --wait is given the command will wait until a
1225
1404
#ifdef USE_GNU_PTH
1226
1405
  if (rc && has_option (line, "--wait"))
1227
1406
    {
 
1407
      rc = 0;
1228
1408
      pth_sleep (1); /* Better implement an event mechanism. However,
1229
1409
                        for card operations this should be
1230
1410
                        sufficient. */
 
1411
      /* FIXME: Need to check that the connection is still alive.
 
1412
         This can be done by issuing status messages. */
1231
1413
      goto retry;
1232
1414
    }
1233
1415
#endif /*USE_GNU_PTH*/
1234
1416
  
1235
1417
  if (rc)
1236
1418
    log_error ("cmd_lock failed: %s\n", gpg_strerror (rc));
1237
 
  return map_to_assuan_status (rc);
 
1419
  return rc;
1238
1420
}
1239
1421
 
1240
1422
 
1260
1442
 
1261
1443
  if (rc)
1262
1444
    log_error ("cmd_unlock failed: %s\n", gpg_strerror (rc));
1263
 
  return map_to_assuan_status (rc);
 
1445
  return rc;
1264
1446
}
1265
1447
 
1266
1448
 
1269
1451
   Multi purpose command to return certain information.  
1270
1452
   Supported values of WHAT are:
1271
1453
 
 
1454
   version     - Return the version of the program.
 
1455
   pid         - Return the process id of the server.
 
1456
 
1272
1457
   socket_name - Return the name of the socket.
1273
1458
 
 
1459
   status - Return the status of the current slot (in the future, may
 
1460
   also return the status of all slots).  The status is a list of
 
1461
   one-character flags.  The following flags are currently defined:
 
1462
     'u'  Usable card present.  This is the normal state during operation.
 
1463
     'r'  Card removed.  A reset is necessary.
 
1464
   These flags are exclusive.
 
1465
 
 
1466
   reader_list - Return a list of detected card readers.  Does
 
1467
                 currently only work with the internal CCID driver.
1274
1468
*/
1275
1469
 
1276
1470
static int
1278
1472
{
1279
1473
  int rc = 0;
1280
1474
 
1281
 
  if (!strcmp (line, "socket_name"))
 
1475
  if (!strcmp (line, "version"))
 
1476
    {
 
1477
      const char *s = VERSION;
 
1478
      rc = assuan_send_data (ctx, s, strlen (s));
 
1479
    }
 
1480
  else if (!strcmp (line, "pid"))
 
1481
    {
 
1482
      char numbuf[50];
 
1483
 
 
1484
      snprintf (numbuf, sizeof numbuf, "%lu", (unsigned long)getpid ());
 
1485
      rc = assuan_send_data (ctx, numbuf, strlen (numbuf));
 
1486
    }
 
1487
  else if (!strcmp (line, "socket_name"))
1282
1488
    {
1283
1489
      const char *s = scd_get_socket_name ();
1284
1490
 
1287
1493
      else
1288
1494
        rc = gpg_error (GPG_ERR_NO_DATA);
1289
1495
    }
 
1496
  else if (!strcmp (line, "status"))
 
1497
    {
 
1498
      ctrl_t ctrl = assuan_get_pointer (ctx);
 
1499
      int slot = ctrl->reader_slot;
 
1500
      char flag = 'r';
 
1501
 
 
1502
      if (!ctrl->server_local->card_removed && slot != -1)
 
1503
        {
 
1504
          struct slot_status_s *ss;
 
1505
          
 
1506
          if (!(slot >= 0 && slot < DIM(slot_table)))
 
1507
            BUG ();
 
1508
 
 
1509
          ss = &slot_table[slot];
 
1510
 
 
1511
          if (!ss->valid)
 
1512
            BUG ();
 
1513
 
 
1514
          if (ss->any && (ss->status & 1))
 
1515
            flag = 'u';
 
1516
        }
 
1517
      rc = assuan_send_data (ctx, &flag, 1);
 
1518
    }
 
1519
  else if (!strcmp (line, "reader_list"))
 
1520
    {
 
1521
#ifdef HAVE_LIBUSB
 
1522
      char *s = ccid_get_reader_list ();
 
1523
#else
 
1524
      char *s = NULL;
 
1525
#endif
 
1526
      
 
1527
      if (s)
 
1528
        rc = assuan_send_data (ctx, s, strlen (s));
 
1529
      else
 
1530
        rc = gpg_error (GPG_ERR_NO_DATA);
 
1531
      xfree (s);
 
1532
    }
1290
1533
  else
1291
 
    rc = set_error (Parameter_Error, "unknown value for WHAT");
1292
 
  return rc;
1293
 
}
 
1534
    rc = set_error (GPG_ERR_ASS_PARAMETER, "unknown value for WHAT");
 
1535
  return rc;
 
1536
}
 
1537
 
 
1538
 
 
1539
/* RESTART
 
1540
 
 
1541
   Restart the current connection; this is a kind of warm reset.  It
 
1542
   deletes the context used by this connection but does not send a
 
1543
   RESET to the card.  Thus the card itself won't get reset. 
 
1544
 
 
1545
   This is used by gpg-agent to reuse a primary pipe connection and
 
1546
   may be used by clients to backup from a conflict in the serial
 
1547
   command; i.e. to select another application. 
 
1548
*/
 
1549
 
 
1550
static int
 
1551
cmd_restart (assuan_context_t ctx, char *line)
 
1552
{
 
1553
  ctrl_t ctrl = assuan_get_pointer (ctx);
 
1554
 
 
1555
  if (ctrl->app_ctx)
 
1556
    {
 
1557
      release_application (ctrl->app_ctx);
 
1558
      ctrl->app_ctx = NULL;
 
1559
    }
 
1560
  if (locked_session && ctrl->server_local == locked_session)
 
1561
    {
 
1562
      locked_session = NULL;
 
1563
      log_info ("implicitly unlocking due to RESTART\n");
 
1564
    }
 
1565
  return 0;
 
1566
}
 
1567
 
 
1568
 
 
1569
/* APDU [--atr] [--more] [hexstring]
 
1570
 
 
1571
   Send an APDU to the current reader.  This command bypasses the high
 
1572
   level functions and sends the data directly to the card.  HEXSTRING
 
1573
   is expected to be a proper APDU.  If HEXSTRING is not given no
 
1574
   commands are set to the card but the command will implictly check
 
1575
   whether the card is ready for use. 
 
1576
 
 
1577
   Using the option "--atr" returns the ATR of the card as a status
 
1578
   message before any data like this:
 
1579
     S CARD-ATR 3BFA1300FF813180450031C173C00100009000B1
 
1580
 
 
1581
   Using the option --more handles the card status word MORE_DATA
 
1582
   (61xx) and concatenate all reponses to one block.
 
1583
 
 
1584
 */
 
1585
static int
 
1586
cmd_apdu (assuan_context_t ctx, char *line)
 
1587
{
 
1588
  ctrl_t ctrl = assuan_get_pointer (ctx);
 
1589
  int rc;
 
1590
  unsigned char *apdu;
 
1591
  size_t apdulen;
 
1592
  int with_atr;
 
1593
  int handle_more;
 
1594
 
 
1595
  with_atr = has_option (line, "--atr");
 
1596
  handle_more = has_option (line, "--more");
 
1597
 
 
1598
  /* Skip over options. */
 
1599
  while ( *line == '-' && line[1] == '-' )
 
1600
    {
 
1601
      while (*line && !spacep (line))
 
1602
        line++;
 
1603
      while (spacep (line))
 
1604
        line++;
 
1605
    }
 
1606
 
 
1607
  if ( IS_LOCKED (ctrl) )
 
1608
    return gpg_error (GPG_ERR_LOCKED);
 
1609
 
 
1610
  if ((rc = open_card (ctrl, NULL)))
 
1611
    return rc;
 
1612
 
 
1613
  if (with_atr)
 
1614
    {
 
1615
      unsigned char *atr;
 
1616
      size_t atrlen;
 
1617
      int i;
 
1618
      char hexbuf[400];
 
1619
      
 
1620
      atr = apdu_get_atr (ctrl->reader_slot, &atrlen);
 
1621
      if (!atr || atrlen > sizeof hexbuf - 2 )
 
1622
        {
 
1623
          rc = gpg_error (GPG_ERR_INV_CARD);
 
1624
          goto leave;
 
1625
        }
 
1626
      for (i=0; i < atrlen; i++)
 
1627
        sprintf (hexbuf+2*i, "%02X", atr[i]);
 
1628
      xfree (atr);
 
1629
      send_status_info (ctrl, "CARD-ATR", hexbuf, strlen (hexbuf), NULL, 0);
 
1630
    }
 
1631
 
 
1632
  apdu = hex_to_buffer (line, &apdulen);
 
1633
  if (!apdu)
 
1634
    {
 
1635
      rc = gpg_error_from_syserror ();
 
1636
      goto leave;
 
1637
    }
 
1638
  if (apdulen)
 
1639
    {
 
1640
      unsigned char *result = NULL;
 
1641
      size_t resultlen;
 
1642
 
 
1643
      rc = apdu_send_direct (ctrl->reader_slot, apdu, apdulen, handle_more,
 
1644
                             &result, &resultlen);
 
1645
      if (rc)
 
1646
        log_error ("apdu_send_direct failed: %s\n", gpg_strerror (rc));
 
1647
      else
 
1648
        {
 
1649
          rc = assuan_send_data (ctx, result, resultlen);
 
1650
          xfree (result);
 
1651
        }
 
1652
    }
 
1653
  xfree (apdu);
 
1654
 
 
1655
 leave:
 
1656
  TEST_CARD_REMOVAL (ctrl, rc);
 
1657
  return rc;
 
1658
}
 
1659
 
1294
1660
 
1295
1661
 
1296
1662
 
1323
1689
    { "LOCK",         cmd_lock },
1324
1690
    { "UNLOCK",       cmd_unlock },
1325
1691
    { "GETINFO",      cmd_getinfo },
 
1692
    { "RESTART",      cmd_restart },
 
1693
    { "APDU",         cmd_apdu },
1326
1694
    { NULL }
1327
1695
  };
1328
1696
  int i, rc;
1344
1712
/* Startup the server.  If FD is given as -1 this is simple pipe
1345
1713
   server, otherwise it is a regular server. */
1346
1714
void
1347
 
scd_command_handler (int fd)
 
1715
scd_command_handler (ctrl_t ctrl, int fd)
1348
1716
{
1349
1717
  int rc;
1350
1718
  assuan_context_t ctx;
1351
 
  struct server_control_s ctrl;
1352
 
 
1353
 
  memset (&ctrl, 0, sizeof ctrl);
1354
 
  scd_init_default_ctrl (&ctrl);
1355
1719
  
1356
1720
  if (fd == -1)
1357
1721
    {
1363
1727
    }
1364
1728
  else
1365
1729
    {
1366
 
      rc = assuan_init_connected_socket_server (&ctx, fd);
 
1730
      rc = assuan_init_socket_server_ext (&ctx, fd, 2);
1367
1731
    }
1368
1732
  if (rc)
1369
1733
    {
1370
1734
      log_error ("failed to initialize the server: %s\n",
1371
 
                 assuan_strerror(rc));
 
1735
                 gpg_strerror(rc));
1372
1736
      scd_exit (2);
1373
1737
    }
1374
1738
  rc = register_commands (ctx);
1375
1739
  if (rc)
1376
1740
    {
1377
1741
      log_error ("failed to register commands with Assuan: %s\n",
1378
 
                 assuan_strerror(rc));
 
1742
                 gpg_strerror(rc));
1379
1743
      scd_exit (2);
1380
1744
    }
1381
 
  assuan_set_pointer (ctx, &ctrl);
 
1745
  assuan_set_pointer (ctx, ctrl);
1382
1746
 
1383
1747
  /* Allocate and initialize the server object.  Put it into the list
1384
1748
     of active sessions. */
1385
 
  ctrl.server_local = xcalloc (1, sizeof *ctrl.server_local);
1386
 
  ctrl.server_local->next_session = session_list;
1387
 
  session_list = ctrl.server_local;
1388
 
  ctrl.server_local->ctrl_backlink = &ctrl;
1389
 
  ctrl.server_local->assuan_ctx = ctx;
 
1749
  ctrl->server_local = xcalloc (1, sizeof *ctrl->server_local);
 
1750
  ctrl->server_local->next_session = session_list;
 
1751
  session_list = ctrl->server_local;
 
1752
  ctrl->server_local->ctrl_backlink = ctrl;
 
1753
  ctrl->server_local->assuan_ctx = ctx;
1390
1754
 
1391
1755
  if (DBG_ASSUAN)
1392
1756
    assuan_set_log_stream (ctx, log_get_stream ());
1393
1757
 
1394
1758
  /* We open the reader right at startup so that the ticker is able to
1395
1759
     update the status file. */
1396
 
  if (ctrl.reader_slot == -1)
 
1760
  if (ctrl->reader_slot == -1)
1397
1761
    {
1398
 
      ctrl.reader_slot = get_reader_slot ();
 
1762
      ctrl->reader_slot = get_reader_slot ();
1399
1763
    }
1400
1764
 
1401
1765
  /* Command processing loop. */
1408
1772
        }
1409
1773
      else if (rc)
1410
1774
        {
1411
 
          log_info ("Assuan accept problem: %s\n", assuan_strerror (rc));
 
1775
          log_info ("Assuan accept problem: %s\n", gpg_strerror (rc));
1412
1776
          break;
1413
1777
        }
1414
1778
      
1415
1779
      rc = assuan_process (ctx);
1416
1780
      if (rc)
1417
1781
        {
1418
 
          log_info ("Assuan processing failed: %s\n", assuan_strerror (rc));
 
1782
          log_info ("Assuan processing failed: %s\n", gpg_strerror (rc));
1419
1783
          continue;
1420
1784
        }
1421
1785
    }
1422
1786
 
1423
1787
  /* Cleanup.  */
1424
 
  do_reset (&ctrl, 1); 
 
1788
  do_reset (ctrl, 0); 
1425
1789
 
1426
1790
  /* Release the server object.  */
1427
 
  if (session_list == ctrl.server_local)
1428
 
    session_list = ctrl.server_local->next_session;
 
1791
  if (session_list == ctrl->server_local)
 
1792
    session_list = ctrl->server_local->next_session;
1429
1793
  else
1430
1794
    {
1431
1795
      struct server_local_s *sl;
1432
1796
      
1433
1797
      for (sl=session_list; sl->next_session; sl = sl->next_session)
1434
 
        if (sl->next_session == ctrl.server_local)
 
1798
        if (sl->next_session == ctrl->server_local)
1435
1799
          break;
1436
1800
      if (!sl->next_session)
1437
1801
          BUG ();
1438
 
      sl->next_session = ctrl.server_local->next_session;
 
1802
      sl->next_session = ctrl->server_local->next_session;
1439
1803
    }
1440
 
  xfree (ctrl.server_local);
 
1804
  xfree (ctrl->server_local);
 
1805
  ctrl->server_local = NULL;
1441
1806
 
1442
1807
  /* Release the Assuan context.  */
1443
1808
  assuan_deinit_server (ctx);
1491
1856
}
1492
1857
 
1493
1858
 
1494
 
/* This function is called by the ticker thread to check for changes
1495
 
   of the reader stati.  It updates the reader status files and if
1496
 
   requested by the caller also send a signal to the caller.  */
1497
 
void
1498
 
scd_update_reader_status_file (void)
 
1859
/* This is the core of scd_update_reader_status_file but the caller
 
1860
   needs to take care of the locking. */
 
1861
static void
 
1862
update_reader_status_file (void)
1499
1863
{
1500
 
  static struct {
1501
 
    int any;
1502
 
    unsigned int status;
1503
 
    unsigned int changed;
1504
 
  } last[10];
1505
 
  int slot;
1506
 
  int used;
 
1864
  int idx;
1507
1865
  unsigned int status, changed;
1508
1866
 
1509
1867
  /* Note, that we only try to get the status, because it does not
1510
1868
     make sense to wait here for a operation to complete.  If we are
1511
1869
     busy working with a card, delays in the status file update should
1512
1870
     be acceptable. */
1513
 
  for (slot=0; (slot < DIM(last)
1514
 
                &&!apdu_enum_reader (slot, &used)); slot++)
1515
 
    if (used && !apdu_get_status (slot, 0, &status, &changed))
1516
 
      {
1517
 
        if (!last[slot].any || last[slot].status != status
1518
 
            || last[slot].changed != changed )
 
1871
  for (idx=0; idx < DIM(slot_table); idx++)
 
1872
    {
 
1873
      struct slot_status_s *ss = slot_table + idx;
 
1874
 
 
1875
      if (!ss->valid || ss->slot == -1)
 
1876
        continue; /* Not valid or reader not yet open. */
 
1877
      
 
1878
      if ( apdu_get_status (ss->slot, 0, &status, &changed) )
 
1879
        continue; /* Get status failed. */
 
1880
 
 
1881
      if (!ss->any || ss->status != status || ss->changed != changed )
 
1882
        {
 
1883
          char *fname;
 
1884
          char templ[50];
 
1885
          FILE *fp;
 
1886
          struct server_local_s *sl;
 
1887
 
 
1888
          log_info ("updating status of slot %d to 0x%04X\n",
 
1889
                    ss->slot, status);
 
1890
 
 
1891
          /* FIXME: Should this be IDX instead of ss->slot?  This
 
1892
             depends on how client sessions will associate the reader
 
1893
             status with their session.  */
 
1894
          sprintf (templ, "reader_%d.status", ss->slot);
 
1895
          fname = make_filename (opt.homedir, templ, NULL );
 
1896
          fp = fopen (fname, "w");
 
1897
          if (fp)
 
1898
            {
 
1899
              fprintf (fp, "%s\n",
 
1900
                       (status & 1)? "USABLE":
 
1901
                       (status & 4)? "ACTIVE":
 
1902
                       (status & 2)? "PRESENT": "NOCARD");
 
1903
              fclose (fp);
 
1904
            }
 
1905
          xfree (fname);
 
1906
            
 
1907
          /* If a status script is executable, run it. */
1519
1908
          {
1520
 
            char *fname;
1521
 
            char templ[50];
1522
 
            FILE *fp;
1523
 
            struct server_local_s *sl;
1524
 
 
1525
 
            log_info ("updating status of slot %d to 0x%04X\n", slot, status);
 
1909
            const char *args[9], *envs[2];
 
1910
            char numbuf1[30], numbuf2[30], numbuf3[30];
 
1911
            char *homestr, *envstr;
 
1912
            gpg_error_t err;
1526
1913
            
1527
 
            sprintf (templ, "reader_%d.status", slot);
1528
 
            fname = make_filename (opt.homedir, templ, NULL );
1529
 
            fp = fopen (fname, "w");
1530
 
            if (fp)
 
1914
            homestr = make_filename (opt.homedir, NULL);
 
1915
            if (asprintf (&envstr, "GNUPGHOME=%s", homestr) < 0)
 
1916
              log_error ("out of core while building environment\n");
 
1917
            else
1531
1918
              {
1532
 
                fprintf (fp, "%s\n",
1533
 
                         (status & 1)? "USABLE":
1534
 
                         (status & 4)? "ACTIVE":
1535
 
                         (status & 2)? "PRESENT": "NOCARD");
1536
 
                fclose (fp);
 
1919
                envs[0] = envstr;
 
1920
                envs[1] = NULL;
 
1921
 
 
1922
                sprintf (numbuf1, "%d", ss->slot);
 
1923
                sprintf (numbuf2, "0x%04X", ss->status);
 
1924
                sprintf (numbuf3, "0x%04X", status);
 
1925
                args[0] = "--reader-port";
 
1926
                args[1] = numbuf1; 
 
1927
                args[2] = "--old-code";
 
1928
                args[3] = numbuf2;  
 
1929
                args[4] = "--new-code";
 
1930
                args[5] = numbuf3; 
 
1931
                args[6] = "--status";
 
1932
                args[7] = ((status & 1)? "USABLE":
 
1933
                           (status & 4)? "ACTIVE":
 
1934
                           (status & 2)? "PRESENT": "NOCARD");
 
1935
                args[8] = NULL;  
 
1936
 
 
1937
                fname = make_filename (opt.homedir, "scd-event", NULL);
 
1938
                err = gnupg_spawn_process_detached (fname, args, envs);
 
1939
                if (err && gpg_err_code (err) != GPG_ERR_ENOENT)
 
1940
                  log_error ("failed to run event handler `%s': %s\n",
 
1941
                             fname, gpg_strerror (err));
 
1942
                xfree (fname);
 
1943
                free (envstr);
1537
1944
              }
1538
 
            xfree (fname);
1539
 
 
1540
 
            /* Set the card removed flag for all current sessions.  We
1541
 
               will set this on any card change because a reset or
1542
 
               SERIALNO request must be done in any case.  */
1543
 
            if (last[slot].any)
1544
 
              update_card_removed (slot, 1);
1545
 
 
1546
 
            last[slot].any = 1;
1547
 
            last[slot].status = status;
1548
 
            last[slot].changed = changed;
1549
 
 
1550
 
 
1551
 
            /* Send a signal to all clients who applied for it.  */
1552
 
            for (sl=session_list; sl; sl = sl->next_session)
1553
 
              if (sl->event_signal && sl->assuan_ctx)
1554
 
                {
1555
 
                  pid_t pid = assuan_get_pid (sl->assuan_ctx);
1556
 
                  int signo = sl->event_signal;
1557
 
 
1558
 
                  log_info ("client pid is %d, sending signal %d\n",
1559
 
                            pid, signo);
 
1945
            xfree (homestr);
 
1946
          }
 
1947
 
 
1948
          /* Set the card removed flag for all current sessions.  We
 
1949
             will set this on any card change because a reset or
 
1950
             SERIALNO request must be done in any case.  */
 
1951
          if (ss->any)
 
1952
            update_card_removed (idx, 1);
 
1953
          
 
1954
          ss->any = 1;
 
1955
          ss->status = status;
 
1956
          ss->changed = changed;
 
1957
 
 
1958
          /* Send a signal to all clients who applied for it.  */
 
1959
          for (sl=session_list; sl; sl = sl->next_session)
 
1960
            if (sl->event_signal && sl->assuan_ctx)
 
1961
              {
 
1962
                pid_t pid = assuan_get_pid (sl->assuan_ctx);
 
1963
                int signo = sl->event_signal;
 
1964
                
 
1965
                log_info ("client pid is %d, sending signal %d\n",
 
1966
                          pid, signo);
1560
1967
#ifndef HAVE_W32_SYSTEM
1561
 
                  if (pid != (pid_t)(-1) && pid && signo > 0)
1562
 
                    kill (pid, signo);
 
1968
                if (pid != (pid_t)(-1) && pid && signo > 0)
 
1969
                  kill (pid, signo);
1563
1970
#endif
1564
 
                }
1565
 
          }
1566
 
      }
 
1971
              }
 
1972
 
 
1973
        }
 
1974
    }
 
1975
}
 
1976
 
 
1977
/* This function is called by the ticker thread to check for changes
 
1978
   of the reader stati.  It updates the reader status files and if
 
1979
   requested by the caller also send a signal to the caller.  */
 
1980
void
 
1981
scd_update_reader_status_file (void)
 
1982
{
 
1983
  if (!pth_mutex_acquire (&status_file_update_lock, 1, NULL))
 
1984
    return; /* locked - give up. */
 
1985
  update_reader_status_file ();
 
1986
  if (!pth_mutex_release (&status_file_update_lock))
 
1987
    log_error ("failed to release status_file_update lock\n");
1567
1988
}