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

« back to all changes in this revision

Viewing changes to g10/call-agent.c

  • Committer: Bazaar Package Importer
  • Author(s): Andreas Mueller
  • Date: 2005-03-29 10:30:32 UTC
  • Revision ID: james.westby@ubuntu.com-20050329103032-sj42n2ain3ipx310
Tags: upstream-1.9.15
ImportĀ upstreamĀ versionĀ 1.9.15

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* call-agent.c - divert operations to the agent
 
2
 *      Copyright (C) 2001, 2002, 2003 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 2 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, write to the Free Software
 
18
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
 
19
 */
 
20
 
 
21
#if 0  /* lety Emacs display a red warning */
 
22
#error fixme: this shares a lof of code with the file in ../sm
 
23
#endif
 
24
 
 
25
#include <config.h>
 
26
#include <stdio.h>
 
27
#include <stdlib.h>
 
28
#include <string.h>
 
29
#include <errno.h>
 
30
#include <unistd.h> 
 
31
#include <time.h>
 
32
#include <assert.h>
 
33
#ifdef HAVE_LOCALE_H
 
34
#include <locale.h>
 
35
#endif
 
36
#include <assuan.h>
 
37
 
 
38
#include "gpg.h"
 
39
#include "util.h"
 
40
#include "membuf.h"
 
41
#include "options.h"
 
42
#include "i18n.h"
 
43
#include "call-agent.h"
 
44
 
 
45
#ifndef DBG_ASSUAN
 
46
# define DBG_ASSUAN 1
 
47
#endif
 
48
 
 
49
static ASSUAN_CONTEXT agent_ctx = NULL;
 
50
static int force_pipe_server = 1; /* FIXME: set this back to 0. */
 
51
 
 
52
struct cipher_parm_s {
 
53
  ASSUAN_CONTEXT ctx;
 
54
  const char *ciphertext;
 
55
  size_t ciphertextlen;
 
56
};
 
57
 
 
58
struct genkey_parm_s {
 
59
  ASSUAN_CONTEXT ctx;
 
60
  const char *sexp;
 
61
  size_t sexplen;
 
62
};
 
63
 
 
64
 
 
65
 
 
66
/* Try to connect to the agent via socket or fork it off and work by
 
67
   pipes.  Handle the server's initial greeting */
 
68
static int
 
69
start_agent (void)
 
70
{
 
71
  int rc = 0;
 
72
  char *infostr, *p;
 
73
  ASSUAN_CONTEXT ctx;
 
74
  char *dft_display = NULL;
 
75
  char *dft_ttyname = NULL;
 
76
  char *dft_ttytype = NULL;
 
77
  char *old_lc = NULL;
 
78
  char *dft_lc = NULL;
 
79
 
 
80
  if (agent_ctx)
 
81
    return 0; /* fixme: We need a context for each thread or serialize
 
82
                 the access to the agent. */
 
83
 
 
84
  infostr = force_pipe_server? NULL : getenv ("GPG_AGENT_INFO");
 
85
  if (!infostr || !*infostr)
 
86
    {
 
87
      const char *pgmname;
 
88
      const char *argv[3];
 
89
      int no_close_list[3];
 
90
      int i;
 
91
 
 
92
      if (opt.verbose)
 
93
        log_info (_("no running gpg-agent - starting one\n"));
 
94
 
 
95
      if (fflush (NULL))
 
96
        {
 
97
          gpg_error_t tmperr = gpg_error_from_errno (errno);
 
98
          log_error ("error flushing pending output: %s\n", strerror (errno));
 
99
          return tmperr;
 
100
        }
 
101
 
 
102
      if (!opt.agent_program || !*opt.agent_program)
 
103
        opt.agent_program = GNUPG_DEFAULT_AGENT;
 
104
      if ( !(pgmname = strrchr (opt.agent_program, '/')))
 
105
        pgmname = opt.agent_program;
 
106
      else
 
107
        pgmname++;
 
108
 
 
109
      argv[0] = pgmname;
 
110
      argv[1] = "--server";
 
111
      argv[2] = NULL;
 
112
 
 
113
      i=0;
 
114
      if (log_get_fd () != -1)
 
115
        no_close_list[i++] = log_get_fd ();
 
116
      no_close_list[i++] = fileno (stderr);
 
117
      no_close_list[i] = -1;
 
118
 
 
119
      /* connect to the agent and perform initial handshaking */
 
120
      rc = assuan_pipe_connect (&ctx, opt.agent_program, (char**)argv,
 
121
                                no_close_list);
 
122
    }
 
123
  else
 
124
    {
 
125
      int prot;
 
126
      int pid;
 
127
 
 
128
      infostr = xstrdup (infostr);
 
129
      if ( !(p = strchr (infostr, ':')) || p == infostr)
 
130
        {
 
131
          log_error (_("malformed GPG_AGENT_INFO environment variable\n"));
 
132
          xfree (infostr);
 
133
          force_pipe_server = 1;
 
134
          return start_agent ();
 
135
        }
 
136
      *p++ = 0;
 
137
      pid = atoi (p);
 
138
      while (*p && *p != ':')
 
139
        p++;
 
140
      prot = *p? atoi (p+1) : 0;
 
141
      if (prot != 1)
 
142
        {
 
143
          log_error (_("gpg-agent protocol version %d is not supported\n"),
 
144
                     prot);
 
145
          xfree (infostr);
 
146
          force_pipe_server = 1;
 
147
          return start_agent ();
 
148
        }
 
149
 
 
150
      rc = assuan_socket_connect (&ctx, infostr, pid);
 
151
      xfree (infostr);
 
152
      if (rc == ASSUAN_Connect_Failed)
 
153
        {
 
154
          log_error (_("can't connect to the agent - trying fall back\n"));
 
155
          force_pipe_server = 1;
 
156
          return start_agent ();
 
157
        }
 
158
    }
 
159
 
 
160
  if (rc)
 
161
    {
 
162
      log_error ("can't connect to the agent: %s\n", assuan_strerror (rc));
 
163
      return gpg_error (GPG_ERR_NO_AGENT);
 
164
    }
 
165
  agent_ctx = ctx;
 
166
 
 
167
  if (DBG_ASSUAN)
 
168
    log_debug ("connection to agent established\n");
 
169
 
 
170
  rc = assuan_transact (agent_ctx, "RESET", NULL, NULL, NULL, NULL, NULL, NULL);
 
171
  if (rc)
 
172
    return map_assuan_err (rc);
 
173
 
 
174
#ifdef __GNUC__
 
175
#warning put this code into common/asshelp.c
 
176
#endif
 
177
 
 
178
  dft_display = getenv ("DISPLAY");
 
179
  if (opt.display || dft_display)
 
180
    {
 
181
      char *optstr;
 
182
      if (asprintf (&optstr, "OPTION display=%s",
 
183
                    opt.display ? opt.display : dft_display) < 0)
 
184
        return gpg_error_from_errno (errno);
 
185
      rc = assuan_transact (agent_ctx, optstr, NULL, NULL, NULL, NULL, NULL,
 
186
                            NULL);
 
187
      free (optstr);
 
188
      if (rc)
 
189
        return map_assuan_err (rc);
 
190
    }
 
191
  if (!opt.ttyname)
 
192
    {
 
193
      dft_ttyname = getenv ("GPG_TTY");
 
194
      if ((!dft_ttyname || !*dft_ttyname) && ttyname (0))
 
195
        dft_ttyname = ttyname (0);
 
196
    }
 
197
  if (opt.ttyname || dft_ttyname)
 
198
    {
 
199
      char *optstr;
 
200
      if (asprintf (&optstr, "OPTION ttyname=%s",
 
201
                    opt.ttyname ? opt.ttyname : dft_ttyname) < 0)
 
202
        return gpg_error_from_errno (errno);
 
203
      rc = assuan_transact (agent_ctx, optstr, NULL, NULL, NULL, NULL, NULL,
 
204
                            NULL);
 
205
      free (optstr);
 
206
      if (rc)
 
207
        return map_assuan_err (rc);
 
208
    }
 
209
  dft_ttytype = getenv ("TERM");
 
210
  if (opt.ttytype || (dft_ttyname && dft_ttytype))
 
211
    {
 
212
      char *optstr;
 
213
      if (asprintf (&optstr, "OPTION ttytype=%s",
 
214
                    opt.ttyname ? opt.ttytype : dft_ttytype) < 0)
 
215
        return gpg_error_from_errno (errno);
 
216
      rc = assuan_transact (agent_ctx, optstr, NULL, NULL, NULL, NULL, NULL,
 
217
                            NULL);
 
218
      free (optstr);
 
219
      if (rc)
 
220
        return map_assuan_err (rc);
 
221
    }
 
222
#if defined(HAVE_SETLOCALE) && defined(LC_CTYPE)
 
223
  old_lc = setlocale (LC_CTYPE, NULL);
 
224
  if (old_lc)
 
225
    {
 
226
      old_lc = strdup (old_lc);
 
227
      if (!old_lc)
 
228
        return gpg_error_from_errno (errno);
 
229
 
 
230
    }
 
231
  dft_lc = setlocale (LC_CTYPE, "");
 
232
#endif
 
233
  if (opt.lc_ctype || (dft_ttyname && dft_lc))
 
234
    {
 
235
      char *optstr;
 
236
      if (asprintf (&optstr, "OPTION lc-ctype=%s",
 
237
                    opt.lc_ctype ? opt.lc_ctype : dft_lc) < 0)
 
238
        rc = gpg_error_from_errno (errno);
 
239
      else
 
240
        {
 
241
          rc = assuan_transact (agent_ctx, optstr, NULL, NULL, NULL, NULL, NULL,
 
242
                                NULL);
 
243
          free (optstr);
 
244
          if (rc)
 
245
            rc = map_assuan_err (rc);
 
246
        }
 
247
    }
 
248
#if defined(HAVE_SETLOCALE) && defined(LC_CTYPE)
 
249
  if (old_lc)
 
250
    {
 
251
      setlocale (LC_CTYPE, old_lc);
 
252
      free (old_lc);
 
253
    }
 
254
#endif
 
255
  if (rc)
 
256
    return rc;
 
257
#if defined(HAVE_SETLOCALE) && defined(LC_MESSAGES)
 
258
  old_lc = setlocale (LC_MESSAGES, NULL);
 
259
  if (old_lc)
 
260
    {
 
261
      old_lc = strdup (old_lc);
 
262
      if (!old_lc)
 
263
        return gpg_error_from_errno (errno);
 
264
    }
 
265
  dft_lc = setlocale (LC_MESSAGES, "");
 
266
#endif
 
267
  if (opt.lc_messages || (dft_ttyname && dft_lc))
 
268
    {
 
269
      char *optstr;
 
270
      if (asprintf (&optstr, "OPTION lc-messages=%s",
 
271
                    opt.lc_messages ? opt.lc_messages : dft_lc) < 0)
 
272
        rc = gpg_error_from_errno (errno);
 
273
      else
 
274
        {
 
275
          rc = assuan_transact (agent_ctx, optstr, NULL, NULL, NULL, NULL, NULL,
 
276
                                NULL);
 
277
          free (optstr);
 
278
          if (rc)
 
279
            rc = map_assuan_err (rc);
 
280
        }
 
281
    }
 
282
#if defined(HAVE_SETLOCALE) && defined(LC_MESSAGES)
 
283
  if (old_lc)
 
284
    {
 
285
      setlocale (LC_MESSAGES, old_lc);
 
286
      free (old_lc);
 
287
    }
 
288
#endif
 
289
 
 
290
  return rc;
 
291
}
 
292
 
 
293
 
 
294
/* Return a new malloced string by unescaping the string S.  Escaping
 
295
   is percent escaping and '+'/space mapping.  A binary nul will
 
296
   silently be replaced by a 0xFF.  Function returns NULL to indicate
 
297
   an out of memory status. */
 
298
static char *
 
299
unescape_status_string (const unsigned char *s)
 
300
{
 
301
  char *buffer, *d;
 
302
 
 
303
  buffer = d = xtrymalloc (strlen (s)+1);
 
304
  if (!buffer)
 
305
    return NULL;
 
306
  while (*s)
 
307
    {
 
308
      if (*s == '%' && s[1] && s[2])
 
309
        { 
 
310
          s++;
 
311
          *d = xtoi_2 (s);
 
312
          if (!*d)
 
313
            *d = '\xff';
 
314
          d++;
 
315
          s += 2;
 
316
        }
 
317
      else if (*s == '+')
 
318
        {
 
319
          *d++ = ' ';
 
320
          s++;
 
321
        }
 
322
      else
 
323
        *d++ = *s++;
 
324
    }
 
325
  *d = 0; 
 
326
  return buffer;
 
327
}
 
328
 
 
329
/* Take a 20 byte hexencoded string and put it into the the provided
 
330
   20 byte buffer FPR in binary format. */
 
331
static int
 
332
unhexify_fpr (const char *hexstr, unsigned char *fpr)
 
333
{
 
334
  const char *s;
 
335
  int n;
 
336
 
 
337
  for (s=hexstr, n=0; hexdigitp (s); s++, n++)
 
338
    ;
 
339
  if (*s || (n != 40))
 
340
    return 0; /* no fingerprint (invalid or wrong length). */
 
341
  n /= 2;
 
342
  for (s=hexstr, n=0; *s; s += 2, n++)
 
343
    fpr[n] = xtoi_2 (s);
 
344
  return 1; /* okay */
 
345
}
 
346
 
 
347
/* Take the serial number from LINE and return it verbatim in a newly
 
348
   allocated string.  We make sure that only hex characters are
 
349
   returned. */
 
350
static char *
 
351
store_serialno (const char *line)
 
352
{
 
353
  const char *s;
 
354
  char *p;
 
355
 
 
356
  for (s=line; hexdigitp (s); s++)
 
357
    ;
 
358
  p = xtrymalloc (s + 1 - line);
 
359
  if (p)
 
360
    {
 
361
      memcpy (p, line, s-line);
 
362
      p[s-line] = 0;
 
363
    }
 
364
  return p;
 
365
}
 
366
 
 
367
 
 
368
 
 
369
#if 0
 
370
/* Handle a KEYPARMS inquiry.  Note, we only send the data,
 
371
   assuan_transact takes care of flushing and writing the end */
 
372
static AssuanError
 
373
inq_genkey_parms (void *opaque, const char *keyword)
 
374
{
 
375
  struct genkey_parm_s *parm = opaque; 
 
376
  AssuanError rc;
 
377
 
 
378
  rc = assuan_send_data (parm->ctx, parm->sexp, parm->sexplen);
 
379
  return rc; 
 
380
}
 
381
 
 
382
 
 
383
 
 
384
/* Call the agent to generate a new key */
 
385
int
 
386
agent_genkey (KsbaConstSexp keyparms, KsbaSexp *r_pubkey)
 
387
{
 
388
  int rc;
 
389
  struct genkey_parm_s gk_parm;
 
390
  membuf_t data;
 
391
  size_t len;
 
392
  char *buf;
 
393
 
 
394
  *r_pubkey = NULL;
 
395
  rc = start_agent ();
 
396
  if (rc)
 
397
    return rc;
 
398
 
 
399
  rc = assuan_transact (agent_ctx, "RESET", NULL, NULL,
 
400
                        NULL, NULL, NULL, NULL);
 
401
  if (rc)
 
402
    return map_assuan_err (rc);
 
403
 
 
404
  init_membuf (&data, 1024);
 
405
  gk_parm.ctx = agent_ctx;
 
406
  gk_parm.sexp = keyparms;
 
407
  gk_parm.sexplen = gcry_sexp_canon_len (keyparms, 0, NULL, NULL);
 
408
  if (!gk_parm.sexplen)
 
409
    return gpg_error (GPG_ERR_INV_VALUE);
 
410
  rc = assuan_transact (agent_ctx, "GENKEY",
 
411
                        membuf_data_cb, &data, 
 
412
                        inq_genkey_parms, &gk_parm, NULL, NULL);
 
413
  if (rc)
 
414
    {
 
415
      xfree (get_membuf (&data, &len));
 
416
      return map_assuan_err (rc);
 
417
    }
 
418
  buf = get_membuf (&data, &len);
 
419
  if (!buf)
 
420
    return gpg_error (GPG_ERR_ENOMEM);
 
421
  if (!gcry_sexp_canon_len (buf, len, NULL, NULL))
 
422
    {
 
423
      xfree (buf);
 
424
      return gpg_error (GPG_ERR_INV_SEXP);
 
425
    }
 
426
  *r_pubkey = buf;
 
427
  return 0;
 
428
}
 
429
#endif /*0*/
 
430
 
 
431
 
 
432
 
 
433
/* Ask the agent whether the corresponding secret key is available for
 
434
   the given keygrip. */
 
435
int
 
436
agent_havekey (const char *hexkeygrip)
 
437
{
 
438
  int rc;
 
439
  char line[ASSUAN_LINELENGTH];
 
440
 
 
441
  rc = start_agent ();
 
442
  if (rc)
 
443
    return rc;
 
444
 
 
445
  if (!hexkeygrip || strlen (hexkeygrip) != 40)
 
446
    return gpg_error (GPG_ERR_INV_VALUE);
 
447
 
 
448
  snprintf (line, DIM(line)-1, "HAVEKEY %s", hexkeygrip);
 
449
  line[DIM(line)-1] = 0;
 
450
 
 
451
  rc = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
 
452
  return map_assuan_err (rc);
 
453
}
 
454
 
 
455
 
 
456
/* Release the card info structure INFO. */
 
457
void
 
458
agent_release_card_info (struct agent_card_info_s *info)
 
459
{
 
460
  if (!info)
 
461
    return;
 
462
 
 
463
  xfree (info->serialno); info->serialno = NULL;
 
464
  xfree (info->disp_name); info->disp_name = NULL;
 
465
  xfree (info->disp_lang); info->disp_lang = NULL;
 
466
  xfree (info->pubkey_url); info->pubkey_url = NULL;
 
467
  xfree (info->login_data); info->login_data = NULL;
 
468
  info->cafpr1valid = info->cafpr2valid = info->cafpr3valid = 0;
 
469
  info->fpr1valid = info->fpr2valid = info->fpr3valid = 0;
 
470
}
 
471
 
 
472
static AssuanError
 
473
learn_status_cb (void *opaque, const char *line)
 
474
{
 
475
  struct agent_card_info_s *parm = opaque;
 
476
  const char *keyword = line;
 
477
  int keywordlen;
 
478
  int i;
 
479
 
 
480
  for (keywordlen=0; *line && !spacep (line); line++, keywordlen++)
 
481
    ;
 
482
  while (spacep (line))
 
483
    line++;
 
484
 
 
485
  if (keywordlen == 8 && !memcmp (keyword, "SERIALNO", keywordlen))
 
486
    {
 
487
      xfree (parm->serialno);
 
488
      parm->serialno = store_serialno (line);
 
489
    }
 
490
  else if (keywordlen == 9 && !memcmp (keyword, "DISP-NAME", keywordlen))
 
491
    {
 
492
      xfree (parm->disp_name);
 
493
      parm->disp_name = unescape_status_string (line);
 
494
    }
 
495
  else if (keywordlen == 9 && !memcmp (keyword, "DISP-LANG", keywordlen))
 
496
    {
 
497
      xfree (parm->disp_lang);
 
498
      parm->disp_lang = unescape_status_string (line);
 
499
    }
 
500
  else if (keywordlen == 8 && !memcmp (keyword, "DISP-SEX", keywordlen))
 
501
    {
 
502
      parm->disp_sex = *line == '1'? 1 : *line == '2' ? 2: 0;
 
503
    }
 
504
  else if (keywordlen == 10 && !memcmp (keyword, "PUBKEY-URL", keywordlen))
 
505
    {
 
506
      xfree (parm->pubkey_url);
 
507
      parm->pubkey_url = unescape_status_string (line);
 
508
    }
 
509
  else if (keywordlen == 10 && !memcmp (keyword, "LOGIN-DATA", keywordlen))
 
510
    {
 
511
      xfree (parm->login_data);
 
512
      parm->login_data = unescape_status_string (line);
 
513
    }
 
514
  else if (keywordlen == 11 && !memcmp (keyword, "SIG-COUNTER", keywordlen))
 
515
    {
 
516
      parm->sig_counter = strtoul (line, NULL, 0);
 
517
    }
 
518
  else if (keywordlen == 10 && !memcmp (keyword, "CHV-STATUS", keywordlen))
 
519
    {
 
520
      char *p, *buf;
 
521
 
 
522
      buf = p = unescape_status_string (line);
 
523
      if (buf)
 
524
        {
 
525
          while (spacep (p))
 
526
            p++;
 
527
          parm->chv1_cached = atoi (p);
 
528
          while (*p && !spacep (p))
 
529
            p++;
 
530
          while (spacep (p))
 
531
            p++;
 
532
          for (i=0; *p && i < 3; i++)
 
533
            {
 
534
              parm->chvmaxlen[i] = atoi (p);
 
535
              while (*p && !spacep (p))
 
536
                p++;
 
537
              while (spacep (p))
 
538
                p++;
 
539
            }
 
540
          for (i=0; *p && i < 3; i++)
 
541
            {
 
542
              parm->chvretry[i] = atoi (p);
 
543
              while (*p && !spacep (p))
 
544
                p++;
 
545
              while (spacep (p))
 
546
                p++;
 
547
            }
 
548
          xfree (buf);
 
549
        }
 
550
    }
 
551
  else if (keywordlen == 7 && !memcmp (keyword, "KEY-FPR", keywordlen))
 
552
    {
 
553
      int no = atoi (line);
 
554
      while (*line && !spacep (line))
 
555
        line++;
 
556
      while (spacep (line))
 
557
        line++;
 
558
      if (no == 1)
 
559
        parm->fpr1valid = unhexify_fpr (line, parm->fpr1);
 
560
      else if (no == 2)
 
561
        parm->fpr2valid = unhexify_fpr (line, parm->fpr2);
 
562
      else if (no == 3)
 
563
        parm->fpr3valid = unhexify_fpr (line, parm->fpr3);
 
564
    }
 
565
  else if (keywordlen == 6 && !memcmp (keyword, "CA-FPR", keywordlen))
 
566
    {
 
567
      int no = atoi (line);
 
568
      while (*line && !spacep (line))
 
569
        line++;
 
570
      while (spacep (line))
 
571
        line++;
 
572
      if (no == 1)
 
573
        parm->cafpr1valid = unhexify_fpr (line, parm->cafpr1);
 
574
      else if (no == 2)
 
575
        parm->cafpr2valid = unhexify_fpr (line, parm->cafpr2);
 
576
      else if (no == 3)
 
577
        parm->cafpr3valid = unhexify_fpr (line, parm->cafpr3);
 
578
    }
 
579
  
 
580
  return 0;
 
581
}
 
582
 
 
583
/* Call the agent to learn about a smartcard */
 
584
int
 
585
agent_learn (struct agent_card_info_s *info)
 
586
{
 
587
  int rc;
 
588
 
 
589
  rc = start_agent ();
 
590
  if (rc)
 
591
    return rc;
 
592
 
 
593
  memset (info, 0, sizeof *info);
 
594
  rc = assuan_transact (agent_ctx, "LEARN --send",
 
595
                        NULL, NULL, NULL, NULL,
 
596
                        learn_status_cb, info);
 
597
  
 
598
  return map_assuan_err (rc);
 
599
}
 
600
 
 
601
/* Call the agent to retrieve a data object.  This function returns
 
602
   the data in the same structure as used by the learn command.  It is
 
603
   allowed to update such a structure using this commmand. */
 
604
int
 
605
agent_scd_getattr (const char *name, struct agent_card_info_s *info)
 
606
{
 
607
  int rc;
 
608
  char line[ASSUAN_LINELENGTH];
 
609
 
 
610
  if (!*name)
 
611
    return gpg_error (GPG_ERR_INV_VALUE);
 
612
 
 
613
  /* We assume that NAME does not need escaping. */
 
614
  if (12 + strlen (name) > DIM(line)-1)
 
615
    return gpg_error (GPG_ERR_TOO_LARGE);
 
616
  stpcpy (stpcpy (line, "SCD GETATTR "), name); 
 
617
 
 
618
  rc = start_agent ();
 
619
  if (rc)
 
620
    return rc;
 
621
 
 
622
  rc = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL,
 
623
                        learn_status_cb, info);
 
624
  
 
625
  return map_assuan_err (rc);
 
626
}
 
627
 
 
628
 
 
629
/* Send an setattr command to the SCdaemon. */
 
630
int
 
631
agent_scd_setattr (const char *name,
 
632
                   const unsigned char *value, size_t valuelen)
 
633
{
 
634
  int rc;
 
635
  char line[ASSUAN_LINELENGTH];
 
636
  char *p;
 
637
 
 
638
  if (!*name || !valuelen)
 
639
    return gpg_error (GPG_ERR_INV_VALUE);
 
640
 
 
641
  /* We assume that NAME does not need escaping. */
 
642
  if (12 + strlen (name) > DIM(line)-1)
 
643
    return gpg_error (GPG_ERR_TOO_LARGE);
 
644
      
 
645
  p = stpcpy (stpcpy (line, "SCD SETATTR "), name); 
 
646
  *p++ = ' ';
 
647
  for (; valuelen; value++, valuelen--)
 
648
    {
 
649
      if (p >= line + DIM(line)-5 )
 
650
        return gpg_error (GPG_ERR_TOO_LARGE);
 
651
      if (*value < ' ' || *value == '+' || *value == '%')
 
652
        {
 
653
          sprintf (p, "%%%02X", *value);
 
654
          p += 3;
 
655
        }
 
656
      else if (*value == ' ')
 
657
        *p++ = '+';
 
658
      else
 
659
        *p++ = *value;
 
660
    }
 
661
  *p = 0;
 
662
 
 
663
  rc = start_agent ();
 
664
  if (rc)
 
665
    return rc;
 
666
 
 
667
  rc = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
 
668
  return map_assuan_err (rc);
 
669
}
 
670
 
 
671
 
 
672
/* Status callback for the SCD GENKEY command. */
 
673
static AssuanError
 
674
scd_genkey_cb (void *opaque, const char *line)
 
675
{
 
676
  struct agent_card_genkey_s *parm = opaque;
 
677
  const char *keyword = line;
 
678
  int keywordlen;
 
679
  gpg_error_t rc;
 
680
 
 
681
  log_debug ("got status line `%s'\n", line);
 
682
  for (keywordlen=0; *line && !spacep (line); line++, keywordlen++)
 
683
    ;
 
684
  while (spacep (line))
 
685
    line++;
 
686
 
 
687
  if (keywordlen == 7 && !memcmp (keyword, "KEY-FPR", keywordlen))
 
688
    {
 
689
      parm->fprvalid = unhexify_fpr (line, parm->fpr);
 
690
    }
 
691
  if (keywordlen == 8 && !memcmp (keyword, "KEY-DATA", keywordlen))
 
692
    {
 
693
      gcry_mpi_t a;
 
694
      const char *name = line;
 
695
 
 
696
      while (*line && !spacep (line))
 
697
        line++;
 
698
      while (spacep (line))
 
699
        line++;
 
700
 
 
701
      rc = gcry_mpi_scan (&a, GCRYMPI_FMT_HEX, line, 0, NULL);
 
702
      if (rc)
 
703
        log_error ("error parsing received key data: %s\n", gpg_strerror (rc));
 
704
      else if (*name == 'n' && spacep (name+1))
 
705
        parm->n = a;
 
706
      else if (*name == 'e' && spacep (name+1))
 
707
        parm->e = a;
 
708
      else
 
709
        {
 
710
          log_info ("unknown parameter name in received key data\n");
 
711
          gcry_mpi_release (a);
 
712
        }
 
713
    }
 
714
  else if (keywordlen == 14 && !memcmp (keyword,"KEY-CREATED-AT", keywordlen))
 
715
    {
 
716
      parm->created_at = (u32)strtoul (line, NULL, 10);
 
717
    }
 
718
 
 
719
  return 0;
 
720
}
 
721
 
 
722
/* Send a GENKEY command to the SCdaemon. */
 
723
int
 
724
agent_scd_genkey (struct agent_card_genkey_s *info, int keyno, int force)
 
725
{
 
726
  int rc;
 
727
  char line[ASSUAN_LINELENGTH];
 
728
 
 
729
  rc = start_agent ();
 
730
  if (rc)
 
731
    return rc;
 
732
 
 
733
  memset (info, 0, sizeof *info);
 
734
  snprintf (line, DIM(line)-1, "SCD GENKEY %s%d",
 
735
            force? "--force ":"", keyno);
 
736
  line[DIM(line)-1] = 0;
 
737
 
 
738
  memset (info, 0, sizeof *info);
 
739
  rc = assuan_transact (agent_ctx, line,
 
740
                        NULL, NULL, NULL, NULL,
 
741
                        scd_genkey_cb, info);
 
742
  
 
743
  return map_assuan_err (rc);
 
744
}
 
745
 
 
746
 
 
747
static AssuanError
 
748
membuf_data_cb (void *opaque, const void *buffer, size_t length)
 
749
{
 
750
  membuf_t *data = opaque;
 
751
 
 
752
  if (buffer)
 
753
    put_membuf (data, buffer, length);
 
754
  return 0;
 
755
}
 
756
  
 
757
/* Send a sign command to the scdaemon via gpg-agent's pass thru
 
758
   mechanism. */
 
759
int
 
760
agent_scd_pksign (const char *serialno, int hashalgo,
 
761
                  const unsigned char *indata, size_t indatalen,
 
762
                  char **r_buf, size_t *r_buflen)
 
763
{
 
764
  int rc, i;
 
765
  char *p, line[ASSUAN_LINELENGTH];
 
766
  membuf_t data;
 
767
  size_t len;
 
768
 
 
769
  /* Note, hashalgo is not yet used but hardwired to SHA1 in SCdaemon. */
 
770
 
 
771
  *r_buf = NULL;
 
772
  *r_buflen = 0;
 
773
 
 
774
  rc = start_agent ();
 
775
  if (rc)
 
776
    return rc;
 
777
 
 
778
  if (indatalen*2 + 50 > DIM(line))
 
779
    return gpg_error (GPG_ERR_GENERAL);
 
780
 
 
781
  sprintf (line, "SCD SETDATA ");
 
782
  p = line + strlen (line);
 
783
  for (i=0; i < indatalen ; i++, p += 2 )
 
784
    sprintf (p, "%02X", indata[i]);
 
785
  rc = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
 
786
  if (rc)
 
787
    return map_assuan_err (rc);
 
788
 
 
789
  init_membuf (&data, 1024);
 
790
#if 0
 
791
  if (!hashalgo) /* Temporary test hack. */
 
792
    snprintf (line, DIM(line)-1, "SCD PKAUTH %s", serialno);
 
793
  else
 
794
#endif
 
795
   snprintf (line, DIM(line)-1, "SCD PKSIGN %s", serialno);
 
796
  line[DIM(line)-1] = 0;
 
797
  rc = assuan_transact (agent_ctx, line, membuf_data_cb, &data,
 
798
                        NULL, NULL, NULL, NULL);
 
799
  if (rc)
 
800
    {
 
801
      xfree (get_membuf (&data, &len));
 
802
      return map_assuan_err (rc);
 
803
    }
 
804
  *r_buf = get_membuf (&data, r_buflen);
 
805
 
 
806
  return 0;
 
807
}
 
808
 
 
809
 
 
810
/* Decrypt INDATA of length INDATALEN using the card identified by
 
811
   SERIALNO.  Return the plaintext in a nwly allocated buffer stored
 
812
   at the address of R_BUF. 
 
813
 
 
814
   Note, we currently support only RSA or more exactly algorithms
 
815
   taking one input data element. */
 
816
int
 
817
agent_scd_pkdecrypt (const char *serialno,
 
818
                     const unsigned char *indata, size_t indatalen,
 
819
                     char **r_buf, size_t *r_buflen)
 
820
{
 
821
  int rc, i;
 
822
  char *p, line[ASSUAN_LINELENGTH];
 
823
  membuf_t data;
 
824
  size_t len;
 
825
 
 
826
  *r_buf = NULL;
 
827
  rc = start_agent ();
 
828
  if (rc)
 
829
    return rc;
 
830
 
 
831
  /* FIXME: use secure memory where appropriate */
 
832
  if (indatalen*2 + 50 > DIM(line))
 
833
    return gpg_error (GPG_ERR_GENERAL);
 
834
 
 
835
  sprintf (line, "SCD SETDATA ");
 
836
  p = line + strlen (line);
 
837
  for (i=0; i < indatalen ; i++, p += 2 )
 
838
    sprintf (p, "%02X", indata[i]);
 
839
  rc = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
 
840
  if (rc)
 
841
    return map_assuan_err (rc);
 
842
 
 
843
  init_membuf (&data, 1024);
 
844
  snprintf (line, DIM(line)-1, "SCD PKDECRYPT %s", serialno);
 
845
  line[DIM(line)-1] = 0;
 
846
  rc = assuan_transact (agent_ctx, line,
 
847
                        membuf_data_cb, &data,
 
848
                        NULL, NULL, NULL, NULL);
 
849
  if (rc)
 
850
    {
 
851
      xfree (get_membuf (&data, &len));
 
852
      return map_assuan_err (rc);
 
853
    }
 
854
  *r_buf = get_membuf (&data, r_buflen);
 
855
  if (!*r_buf)
 
856
    return gpg_error (GPG_ERR_ENOMEM);
 
857
 
 
858
  return 0;
 
859
}
 
860
 
 
861
 
 
862
/* Change the PIN of an OpenPGP card or reset the retry counter.
 
863
   CHVNO 1: Change the PIN
 
864
         2: Same as 1
 
865
         3: Change the admin PIN
 
866
       101: Set a new PIN and reset the retry counter
 
867
       102: Same as 101
 
868
 */
 
869
int
 
870
agent_scd_change_pin (int chvno)
 
871
{
 
872
  int rc;
 
873
  char line[ASSUAN_LINELENGTH];
 
874
  const char *reset = "";
 
875
 
 
876
  if (chvno >= 100)
 
877
    reset = "--reset";
 
878
  chvno %= 100;
 
879
 
 
880
  rc = start_agent ();
 
881
  if (rc)
 
882
    return rc;
 
883
 
 
884
  snprintf (line, DIM(line)-1, "SCD PASSWD %s %d", reset, chvno);
 
885
  line[DIM(line)-1] = 0;
 
886
  rc = assuan_transact (agent_ctx, line, NULL, NULL,
 
887
                        NULL, NULL, NULL, NULL);
 
888
  return map_assuan_err (rc);
 
889
}
 
890
 
 
891
 
 
892
/* Perform a CHECKPIN operation.  SERIALNO should be the serial
 
893
   number of the card - optioanlly followed by the fingerprint;
 
894
   however the fingerprint is ignored here. */
 
895
int
 
896
agent_scd_checkpin  (const char *serialno)
 
897
{
 
898
  int rc;
 
899
  char line[ASSUAN_LINELENGTH];
 
900
 
 
901
  rc = start_agent ();
 
902
  if (rc)
 
903
    return rc;
 
904
 
 
905
  snprintf (line, DIM(line)-1, "SCD CHECKPIN %s", serialno);
 
906
  line[DIM(line)-1] = 0;
 
907
  return assuan_transact (agent_ctx, line,
 
908
                          NULL, NULL,
 
909
                          NULL, NULL, NULL, NULL);
 
910
}
 
911
 
 
912