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

« back to all changes in this revision

Viewing changes to g10/cpr.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
/* status.c - Status message and command-fd interface 
 
2
 * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003,
 
3
 *               2004, 2005, 2006 Free Software Foundation, Inc.
 
4
 *
 
5
 * This file is part of GnuPG.
 
6
 *
 
7
 * GnuPG is free software; you can redistribute it and/or modify
 
8
 * it under the terms of the GNU General Public License as published by
 
9
 * the Free Software Foundation; either version 3 of the License, or
 
10
 * (at your option) any later version.
 
11
 *
 
12
 * GnuPG is distributed in the hope that it will be useful,
 
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
15
 * GNU General Public License for more details.
 
16
 *
 
17
 * You should have received a copy of the GNU General Public License
 
18
 * along with this program; if not, see <http://www.gnu.org/licenses/>.
 
19
 */
 
20
 
 
21
#include <config.h>
 
22
#include <stdio.h>
 
23
#include <stdlib.h>
 
24
#include <string.h>
 
25
#include <errno.h>
 
26
#include <unistd.h>
 
27
#include <signal.h>
 
28
 
 
29
#include "gpg.h"
 
30
#include "util.h"
 
31
#include "status.h"
 
32
#include "ttyio.h"
 
33
#include "options.h"
 
34
#include "main.h"
 
35
#include "i18n.h"
 
36
#include "cipher.h" /* for progress functions */
 
37
 
 
38
#define CONTROL_D ('D' - 'A' + 1)
 
39
 
 
40
 
 
41
 
 
42
static FILE *statusfp;
 
43
 
 
44
 
 
45
static void
 
46
progress_cb (void *ctx, const char *what, int printchar,
 
47
             int current, int total)
 
48
{
 
49
  char buf[50];
 
50
 
 
51
  if ( printchar == '\n' && !strcmp (what, "primegen") )
 
52
    snprintf (buf, sizeof buf -1, "%.20s X 100 100", what );
 
53
  else
 
54
    snprintf (buf, sizeof buf -1, "%.20s %c %d %d",
 
55
              what, printchar=='\n'?'X':printchar, current, total );
 
56
  write_status_text (STATUS_PROGRESS, buf);
 
57
}
 
58
 
 
59
 
 
60
/* Return true if the status message NO may currently be issued.  We
 
61
   need this to avoid syncronisation problem while auto retrieving a
 
62
   key.  There it may happen that a status NODATA is issued for a non
 
63
   available key and the user may falsely interpret this has a missing
 
64
   signature. */
 
65
static int
 
66
status_currently_allowed (int no)
 
67
{
 
68
  if (!glo_ctrl.in_auto_key_retrieve)
 
69
    return 1; /* Yes. */
 
70
 
 
71
  /* We allow some statis anyway, so that import statistics are
 
72
     correct and to avoid problems if the retriebval subsystem will
 
73
     prompt the user. */
 
74
  switch (no)
 
75
    {
 
76
    case STATUS_GET_BOOL:        
 
77
    case STATUS_GET_LINE:        
 
78
    case STATUS_GET_HIDDEN:      
 
79
    case STATUS_GOT_IT:  
 
80
    case STATUS_IMPORTED:
 
81
    case STATUS_IMPORT_OK:      
 
82
    case STATUS_IMPORT_CHECK:  
 
83
    case STATUS_IMPORT_RES:
 
84
      return 1; /* Yes. */
 
85
    default:
 
86
      break;
 
87
    }
 
88
  return 0; /* No. */
 
89
}
 
90
 
 
91
 
 
92
void
 
93
set_status_fd ( int fd )
 
94
{
 
95
    static int last_fd = -1;
 
96
 
 
97
    if ( fd != -1 && last_fd == fd )
 
98
        return;
 
99
 
 
100
    if ( statusfp && statusfp != stdout && statusfp != stderr )
 
101
        fclose (statusfp);
 
102
    statusfp = NULL;
 
103
    if ( fd == -1 ) 
 
104
        return;
 
105
 
 
106
    if( fd == 1 )
 
107
        statusfp = stdout;
 
108
    else if( fd == 2 )
 
109
        statusfp = stderr;
 
110
    else
 
111
        statusfp = fdopen( fd, "w" );
 
112
    if( !statusfp ) {
 
113
        log_fatal("can't open fd %d for status output: %s\n",
 
114
                  fd, strerror(errno));
 
115
    }
 
116
    last_fd = fd;
 
117
 
 
118
    gcry_set_progress_handler ( progress_cb, NULL );
 
119
}
 
120
 
 
121
int
 
122
is_status_enabled()
 
123
{
 
124
    return !!statusfp;
 
125
}
 
126
 
 
127
void
 
128
write_status ( int no )
 
129
{
 
130
    write_status_text( no, NULL );
 
131
}
 
132
 
 
133
void
 
134
write_status_text ( int no, const char *text)
 
135
{
 
136
    if( !statusfp || !status_currently_allowed (no) )
 
137
        return;  /* Not enabled or allowed. */
 
138
 
 
139
    fputs ( "[GNUPG:] ", statusfp );
 
140
    fputs ( get_status_string (no), statusfp );
 
141
    if( text ) {
 
142
        putc ( ' ', statusfp );
 
143
        for (; *text; text++) {
 
144
            if (*text == '\n')
 
145
                fputs ( "\\n", statusfp );
 
146
            else if (*text == '\r')
 
147
                fputs ( "\\r", statusfp );
 
148
            else 
 
149
                putc ( *(const byte *)text,  statusfp );
 
150
        }
 
151
    }
 
152
    putc ('\n',statusfp);
 
153
    if ( fflush (statusfp) && opt.exit_on_status_write_error )
 
154
      g10_exit (0);
 
155
}
 
156
 
 
157
 
 
158
/*
 
159
 * Write a status line with a buffer using %XX escapes.  If WRAP is >
 
160
 * 0 wrap the line after this length.  If STRING is not NULL it will
 
161
 * be prepended to the buffer, no escaping is done for string.
 
162
 * A wrap of -1 forces spaces not to be encoded as %20.
 
163
 */
 
164
void
 
165
write_status_text_and_buffer ( int no, const char *string,
 
166
                               const char *buffer, size_t len, int wrap )
 
167
{
 
168
    const char *s, *text;
 
169
    int esc, first;
 
170
    int lower_limit = ' ';
 
171
    size_t n, count, dowrap;
 
172
 
 
173
    if( !statusfp || !status_currently_allowed (no) )
 
174
        return;  /* Not enabled or allowed. */
 
175
    
 
176
    if (wrap == -1) {
 
177
        lower_limit--;
 
178
        wrap = 0;
 
179
    }
 
180
 
 
181
    text = get_status_string (no);
 
182
    count = dowrap = first = 1;
 
183
    do {
 
184
        if (dowrap) {
 
185
            fprintf (statusfp, "[GNUPG:] %s ", text );
 
186
            count = dowrap = 0;
 
187
            if (first && string) {
 
188
                fputs (string, statusfp);
 
189
                count += strlen (string);
 
190
            }
 
191
            first = 0;
 
192
        }
 
193
        for (esc=0, s=buffer, n=len; n && !esc; s++, n-- ) {
 
194
            if ( *s == '%' || *(const byte*)s <= lower_limit 
 
195
                           || *(const byte*)s == 127 ) 
 
196
                esc = 1;
 
197
            if ( wrap && ++count > wrap ) {
 
198
                dowrap=1;
 
199
                break;
 
200
            }
 
201
        }
 
202
        if (esc) {
 
203
            s--; n++;
 
204
        }
 
205
        if (s != buffer) 
 
206
            fwrite (buffer, s-buffer, 1, statusfp );
 
207
        if ( esc ) {
 
208
            fprintf (statusfp, "%%%02X", *(const byte*)s );
 
209
            s++; n--;
 
210
        }
 
211
        buffer = s;
 
212
        len = n;
 
213
        if ( dowrap && len )
 
214
            putc ( '\n', statusfp );
 
215
    } while ( len );
 
216
 
 
217
    putc ('\n',statusfp);
 
218
    if ( fflush (statusfp) && opt.exit_on_status_write_error )
 
219
      g10_exit (0);
 
220
}
 
221
 
 
222
void
 
223
write_status_buffer ( int no, const char *buffer, size_t len, int wrap )
 
224
{
 
225
    write_status_text_and_buffer (no, NULL, buffer, len, wrap);
 
226
}
 
227
 
 
228
 
 
229
/* Print the BEGIN_SIGNING status message.  If MD is not NULL it is
 
230
   used retrieve the hash algorithms used for the message. */
 
231
void
 
232
write_status_begin_signing (gcry_md_hd_t md)
 
233
{
 
234
  if (md)
 
235
    {
 
236
      char buf[100];
 
237
      size_t buflen;
 
238
      int i;
 
239
      
 
240
      /* We use a hard coded list of possible algorithms.  Using other
 
241
         algorithms than specified by OpenPGP does not make sense
 
242
         anyway.  We do this out of performance reasons: Walking all
 
243
         the 110 allowed Ids is not a good idea given the way the
 
244
         check is implemented in libgcrypt.  Recall that the only use
 
245
         of this status code is to create the micalg algorithm for
 
246
         PGP/MIME. */
 
247
      buflen = 0;
 
248
      for (i=1; i <= 11; i++)
 
249
        if (i < 4 || i > 7)
 
250
          if ( gcry_md_is_enabled (md, i) && buflen < DIM(buf) )
 
251
            {
 
252
              snprintf (buf+buflen, DIM(buf) - buflen - 1, 
 
253
                        "%sH%d", buflen? " ":"",i);
 
254
              buflen += strlen (buf+buflen);
 
255
            }
 
256
      write_status_text ( STATUS_BEGIN_SIGNING, buf );
 
257
    }
 
258
  else
 
259
    write_status ( STATUS_BEGIN_SIGNING );
 
260
}
 
261
 
 
262
 
 
263
static int
 
264
myread(int fd, void *buf, size_t count)
 
265
{
 
266
    int rc;
 
267
    do {
 
268
        rc = read( fd, buf, count );
 
269
    } while ( rc == -1 && errno == EINTR );
 
270
    if ( !rc && count ) {
 
271
        static int eof_emmited=0;
 
272
        if ( eof_emmited < 3 ) {
 
273
            *(char*)buf = CONTROL_D;
 
274
            rc = 1;
 
275
            eof_emmited++;
 
276
        }
 
277
        else { /* Ctrl-D not caught - do something reasonable */
 
278
#ifdef HAVE_DOSISH_SYSTEM
 
279
            raise (SIGINT);  /* nothing to hangup under DOS */
 
280
#else
 
281
            raise (SIGHUP); /* no more input data */
 
282
#endif
 
283
        }
 
284
    }    
 
285
    return rc;
 
286
}
 
287
 
 
288
 
 
289
 
 
290
/* Request a string from the client over the command-fd.  If GETBOOL
 
291
   is set the function returns a static string (do not free) if the
 
292
   netered value was true or NULL if the entered value was false.  */
 
293
static char *
 
294
do_get_from_fd ( const char *keyword, int hidden, int getbool )
 
295
{
 
296
  int i, len;
 
297
  char *string;
 
298
  
 
299
  if (statusfp != stdout)
 
300
    fflush (stdout);
 
301
  
 
302
  write_status_text (getbool? STATUS_GET_BOOL :
 
303
                     hidden? STATUS_GET_HIDDEN : STATUS_GET_LINE, keyword);
 
304
 
 
305
  for (string = NULL, i = len = 200; ; i++ ) 
 
306
    {
 
307
      if (i >= len-1 ) 
 
308
        {
 
309
          char *save = string;
 
310
          len += 100;
 
311
          string = hidden? xmalloc_secure ( len ) : xmalloc ( len );
 
312
          if (save)
 
313
            memcpy (string, save, i );
 
314
          else
 
315
            i = 0;
 
316
        }
 
317
      /* Fixme: why not use our read_line function here? */
 
318
      if ( myread( opt.command_fd, string+i, 1) != 1 || string[i] == '\n'  )
 
319
        break;
 
320
      else if ( string[i] == CONTROL_D ) 
 
321
        {
 
322
          /* Found ETX - Cancel the line and return a sole ETX.  */
 
323
          string[0] = CONTROL_D;
 
324
          i = 1;
 
325
          break;
 
326
        }
 
327
    }
 
328
  string[i] = 0;
 
329
 
 
330
  write_status (STATUS_GOT_IT);
 
331
 
 
332
  if (getbool)   /* Fixme: is this correct??? */
 
333
    return (string[0] == 'Y' || string[0] == 'y') ? "" : NULL;
 
334
 
 
335
  return string;
 
336
}
 
337
 
 
338
 
 
339
 
 
340
int
 
341
cpr_enabled()
 
342
{
 
343
    if( opt.command_fd != -1 )
 
344
        return 1;
 
345
#ifdef USE_SHM_COPROCESSING
 
346
    if( opt.shm_coprocess )
 
347
        return 1;
 
348
#endif
 
349
    return 0;
 
350
}
 
351
 
 
352
char *
 
353
cpr_get_no_help( const char *keyword, const char *prompt )
 
354
{
 
355
    char *p;
 
356
 
 
357
    if( opt.command_fd != -1 )
 
358
        return do_get_from_fd ( keyword, 0, 0 );
 
359
#ifdef USE_SHM_COPROCESSING
 
360
    if( opt.shm_coprocess )
 
361
        return do_shm_get( keyword, 0, 0 );
 
362
#endif
 
363
    for(;;) {
 
364
        p = tty_get( prompt );
 
365
        return p;
 
366
    }
 
367
}
 
368
 
 
369
char *
 
370
cpr_get( const char *keyword, const char *prompt )
 
371
{
 
372
    char *p;
 
373
 
 
374
    if( opt.command_fd != -1 )
 
375
        return do_get_from_fd ( keyword, 0, 0 );
 
376
#ifdef USE_SHM_COPROCESSING
 
377
    if( opt.shm_coprocess )
 
378
        return do_shm_get( keyword, 0, 0 );
 
379
#endif
 
380
    for(;;) {
 
381
        p = tty_get( prompt );
 
382
        if( *p=='?' && !p[1] && !(keyword && !*keyword)) {
 
383
            xfree(p);
 
384
            display_online_help( keyword );
 
385
        }
 
386
        else
 
387
            return p;
 
388
    }
 
389
}
 
390
 
 
391
 
 
392
char *
 
393
cpr_get_utf8( const char *keyword, const char *prompt )
 
394
{
 
395
    char *p;
 
396
    p = cpr_get( keyword, prompt );
 
397
    if( p ) {
 
398
        char *utf8 = native_to_utf8( p );
 
399
        xfree( p );
 
400
        p = utf8;
 
401
    }
 
402
    return p;
 
403
}
 
404
 
 
405
char *
 
406
cpr_get_hidden( const char *keyword, const char *prompt )
 
407
{
 
408
    char *p;
 
409
 
 
410
    if( opt.command_fd != -1 )
 
411
        return do_get_from_fd ( keyword, 1, 0 );
 
412
#ifdef USE_SHM_COPROCESSING
 
413
    if( opt.shm_coprocess )
 
414
        return do_shm_get( keyword, 1, 0 );
 
415
#endif
 
416
    for(;;) {
 
417
        p = tty_get_hidden( prompt );
 
418
        if( *p == '?' && !p[1] ) {
 
419
            xfree(p);
 
420
            display_online_help( keyword );
 
421
        }
 
422
        else
 
423
            return p;
 
424
    }
 
425
}
 
426
 
 
427
void
 
428
cpr_kill_prompt(void)
 
429
{
 
430
    if( opt.command_fd != -1 )
 
431
        return;
 
432
#ifdef USE_SHM_COPROCESSING
 
433
    if( opt.shm_coprocess )
 
434
        return;
 
435
#endif
 
436
    tty_kill_prompt();
 
437
    return;
 
438
}
 
439
 
 
440
int
 
441
cpr_get_answer_is_yes( const char *keyword, const char *prompt )
 
442
{
 
443
    int yes;
 
444
    char *p;
 
445
 
 
446
    if( opt.command_fd != -1 )
 
447
        return !!do_get_from_fd ( keyword, 0, 1 );
 
448
#ifdef USE_SHM_COPROCESSING
 
449
    if( opt.shm_coprocess )
 
450
        return !!do_shm_get( keyword, 0, 1 );
 
451
#endif
 
452
    for(;;) {
 
453
        p = tty_get( prompt );
 
454
        trim_spaces(p); /* it is okay to do this here */
 
455
        if( *p == '?' && !p[1] ) {
 
456
            xfree(p);
 
457
            display_online_help( keyword );
 
458
        }
 
459
        else {
 
460
            tty_kill_prompt();
 
461
            yes = answer_is_yes(p);
 
462
            xfree(p);
 
463
            return yes;
 
464
        }
 
465
    }
 
466
}
 
467
 
 
468
int
 
469
cpr_get_answer_yes_no_quit( const char *keyword, const char *prompt )
 
470
{
 
471
    int yes;
 
472
    char *p;
 
473
 
 
474
    if( opt.command_fd != -1 )
 
475
        return !!do_get_from_fd ( keyword, 0, 1 );
 
476
#ifdef USE_SHM_COPROCESSING
 
477
    if( opt.shm_coprocess )
 
478
        return !!do_shm_get( keyword, 0, 1 );
 
479
#endif
 
480
    for(;;) {
 
481
        p = tty_get( prompt );
 
482
        trim_spaces(p); /* it is okay to do this here */
 
483
        if( *p == '?' && !p[1] ) {
 
484
            xfree(p);
 
485
            display_online_help( keyword );
 
486
        }
 
487
        else {
 
488
            tty_kill_prompt();
 
489
            yes = answer_is_yes_no_quit(p);
 
490
            xfree(p);
 
491
            return yes;
 
492
        }
 
493
    }
 
494
}
 
495
 
 
496
 
 
497
int
 
498
cpr_get_answer_okay_cancel (const char *keyword,
 
499
                            const char *prompt,
 
500
                            int def_answer)
 
501
{
 
502
  int yes;
 
503
  char *answer = NULL;
 
504
  char *p;
 
505
 
 
506
  if( opt.command_fd != -1 )
 
507
    answer = do_get_from_fd ( keyword, 0, 0 );
 
508
#ifdef USE_SHM_COPROCESSING
 
509
  else if( opt.shm_coprocess )
 
510
    answer = do_shm_get( keyword, 0, 0 );
 
511
#endif
 
512
 
 
513
  if (answer)
 
514
    {
 
515
      yes = answer_is_okay_cancel (answer, def_answer);
 
516
      xfree (answer);
 
517
      return yes;
 
518
    }
 
519
 
 
520
  for(;;)
 
521
    {
 
522
      p = tty_get( prompt );
 
523
      trim_spaces(p); /* it is okay to do this here */
 
524
      if (*p == '?' && !p[1])
 
525
        {
 
526
          xfree(p);
 
527
          display_online_help (keyword);
 
528
        }
 
529
      else
 
530
        {
 
531
          tty_kill_prompt();
 
532
          yes = answer_is_okay_cancel (p, def_answer);
 
533
          xfree(p);
 
534
          return yes;
 
535
        }
 
536
    }
 
537
}