Coverage Report

Created: 2026-01-09 06:46

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gnupg/g10/server.c
Line
Count
Source
1
/* server.c - server mode for gpg
2
 * Copyright (C) 2006, 2008  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 3 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, see <https://www.gnu.org/licenses/>.
18
 */
19
20
#include <config.h>
21
#include <errno.h>
22
#include <stdio.h>
23
#include <stdlib.h>
24
#include <string.h>
25
#include <stdarg.h>
26
#include <ctype.h>
27
#include <unistd.h>
28
29
30
#include "gpg.h"
31
#include <assuan.h>
32
#include "../common/util.h"
33
#include "../common/i18n.h"
34
#include "options.h"
35
#include "../common/server-help.h"
36
#include "../common/sysutils.h"
37
#include "../common/status.h"
38
39
40
0
#define set_error(e,t) assuan_set_error (ctx, gpg_error (e), (t))
41
42
43
/* Data used to associate an Assuan context with local server data.  */
44
struct server_local_s
45
{
46
  /* Our current Assuan context. */
47
  assuan_context_t assuan_ctx;
48
  /* File descriptor as set by the MESSAGE command. */
49
  gnupg_fd_t message_fd;
50
51
  /* List of prepared recipients.  */
52
  pk_list_t recplist;
53
54
  /* Set if pinentry notifications should be passed back to the
55
     client. */
56
  int allow_pinentry_notify;
57
};
58
59
60

61
/* Helper to close the message fd if it is open. */
62
static void
63
close_message_fd (ctrl_t ctrl)
64
0
{
65
0
  if (ctrl->server_local->message_fd != GNUPG_INVALID_FD)
66
0
    {
67
0
      assuan_sock_close (ctrl->server_local->message_fd);
68
0
      ctrl->server_local->message_fd = GNUPG_INVALID_FD;
69
0
    }
70
0
}
71
72

73
/* Called by libassuan for Assuan options.  See the Assuan manual for
74
   details. */
75
static gpg_error_t
76
option_handler (assuan_context_t ctx, const char *key, const char *value)
77
0
{
78
0
  ctrl_t ctrl = assuan_get_pointer (ctx);
79
80
0
  (void)value;
81
82
  /* Fixme: Implement the tty and locale args. */
83
0
  if (!strcmp (key, "display"))
84
0
    {
85
0
    }
86
0
  else if (!strcmp (key, "ttyname"))
87
0
    {
88
0
    }
89
0
  else if (!strcmp (key, "ttytype"))
90
0
    {
91
0
    }
92
0
  else if (!strcmp (key, "lc-ctype"))
93
0
    {
94
0
    }
95
0
  else if (!strcmp (key, "lc-messages"))
96
0
    {
97
0
    }
98
0
  else if (!strcmp (key, "xauthority"))
99
0
    {
100
0
    }
101
0
  else if (!strcmp (key, "pinentry_user_data"))
102
0
    {
103
0
    }
104
0
  else if (!strcmp (key, "list-mode"))
105
0
    {
106
      /* This is for now a dummy option. */
107
0
    }
108
0
  else if (!strcmp (key, "allow-pinentry-notify"))
109
0
    {
110
0
      ctrl->server_local->allow_pinentry_notify = 1;
111
0
    }
112
0
  else
113
0
    return gpg_error (GPG_ERR_UNKNOWN_OPTION);
114
115
0
  return 0;
116
0
}
117
118
119
/* Called by libassuan for RESET commands. */
120
static gpg_error_t
121
reset_notify (assuan_context_t ctx, char *line)
122
0
{
123
0
  ctrl_t ctrl = assuan_get_pointer (ctx);
124
125
0
  (void)line;
126
127
0
  release_pk_list (ctrl->server_local->recplist);
128
0
  ctrl->server_local->recplist = NULL;
129
130
0
  close_message_fd (ctrl);
131
0
  assuan_close_input_fd (ctx);
132
0
  assuan_close_output_fd (ctx);
133
0
  return 0;
134
0
}
135
136
137
/* Called by libassuan for INPUT commands. */
138
static gpg_error_t
139
input_notify (assuan_context_t ctx, char *line)
140
0
{
141
/*   ctrl_t ctrl = assuan_get_pointer (ctx); */
142
143
0
  (void)ctx;
144
145
0
  if (strstr (line, "--armor"))
146
0
    ; /* FIXME */
147
0
  else if (strstr (line, "--base64"))
148
0
    ; /* FIXME */
149
0
  else if (strstr (line, "--binary"))
150
0
    ;
151
0
  else
152
0
    {
153
      /* FIXME (autodetect encoding) */
154
0
    }
155
0
  return 0;
156
0
}
157
158
159
/* Called by libassuan for OUTPUT commands. */
160
static gpg_error_t
161
output_notify (assuan_context_t ctx, char *line)
162
0
{
163
/*   ctrl_t ctrl = assuan_get_pointer (ctx); */
164
165
0
  (void)ctx;
166
167
0
  if (strstr (line, "--armor"))
168
0
    ; /* FIXME */
169
0
  else if (strstr (line, "--base64"))
170
0
    {
171
      /* FIXME */
172
0
    }
173
0
  return 0;
174
0
}
175
176
177
178

179
/*  RECIPIENT [--hidden] <userID>
180
    RECIPIENT [--hidden] --file <filename>
181
182
   Set the recipient for the encryption.  <userID> should be the
183
   internal representation of the key; the server may accept any other
184
   way of specification.  If this is a valid and trusted recipient the
185
   server does respond with OK, otherwise the return is an ERR with
186
   the reason why the recipient can't be used, the encryption will
187
   then not be done for this recipient.  If the policy is not to
188
   encrypt at all if not all recipients are valid, the client has to
189
   take care of this.  All RECIPIENT commands are cumulative until a
190
   RESET or an successful ENCRYPT command.  */
191
static gpg_error_t
192
cmd_recipient (assuan_context_t ctx, char *line)
193
0
{
194
0
  ctrl_t ctrl = assuan_get_pointer (ctx);
195
0
  gpg_error_t err;
196
0
  int hidden, file;
197
198
0
  hidden = has_option (line,"--hidden");
199
0
  file = has_option (line,"--file");
200
0
  line = skip_options (line);
201
202
  /* FIXME: Expand groups
203
  if (opt.grouplist)
204
    remusr = expand_group (rcpts);
205
  else
206
    remusr = rcpts;
207
  */
208
209
0
  err = find_and_check_key (ctrl, line, PUBKEY_USAGE_ENC, hidden, file,
210
0
                            &ctrl->server_local->recplist);
211
212
0
  if (err)
213
0
    log_error ("command '%s' failed: %s\n", "RECIPIENT", gpg_strerror (err));
214
0
  return err;
215
0
}
216
217
218

219
/*  SIGNER <userID>
220
221
   Set the signer's keys for the signature creation.  <userID> should
222
   be the internal representation of the key; the server may accept
223
   any other way of specification.  If this is a valid and usable
224
   signing key the server does respond with OK, otherwise it returns
225
   an ERR with the reason why the key can't be used, the signing will
226
   then not be done for this key.  If the policy is not to sign at all
227
   if not all signer keys are valid, the client has to take care of
228
   this.  All SIGNER commands are cumulative until a RESET but they
229
   are *not* reset by an SIGN command because it can be expected that
230
   set of signers are used for more than one sign operation.
231
232
   Note that this command returns an INV_RECP status which is a bit
233
   strange, but they are very similar.  */
234
static gpg_error_t
235
cmd_signer (assuan_context_t ctx, char *line)
236
0
{
237
0
  (void)ctx;
238
0
  (void)line;
239
0
  return gpg_error (GPG_ERR_NOT_SUPPORTED);
240
0
}
241
242
243

244
/*  ENCRYPT
245
246
   Do the actual encryption process.  Takes the plaintext from the
247
   INPUT command, writes the ciphertext to the file descriptor set
248
   with the OUTPUT command, take the recipients from all the
249
   recipients set so far with RECIPIENTS.
250
251
   If this command fails the clients should try to delete all output
252
   currently done or otherwise mark it as invalid.  GPG does ensure
253
   that there won't be any security problem with leftover data on the
254
   output in this case.
255
256
   In most cases this command won't fail because most necessary checks
257
   have been done while setting the recipients.  However some checks
258
   can only be done right here and thus error may occur anyway (for
259
   example, no recipients at all).
260
261
   The input, output and message pipes are closed after this
262
   command.  */
263
static gpg_error_t
264
cmd_encrypt (assuan_context_t ctx, char *line)
265
0
{
266
0
  ctrl_t ctrl = assuan_get_pointer (ctx);
267
0
  gpg_error_t err;
268
0
  gnupg_fd_t inp_fd, out_fd;
269
270
0
  (void)line; /* LINE is not used.  */
271
272
0
  if ( !ctrl->server_local->recplist )
273
0
    {
274
0
      write_status_text (STATUS_NO_RECP, "0");
275
0
      err = gpg_error (GPG_ERR_NO_USER_ID);
276
0
      goto leave;
277
0
    }
278
279
0
  inp_fd = assuan_get_input_fd (ctx);
280
0
  if (inp_fd == GNUPG_INVALID_FD)
281
0
    {
282
0
      err = set_error (GPG_ERR_ASS_NO_INPUT, NULL);
283
0
      goto leave;
284
0
    }
285
0
  out_fd = assuan_get_output_fd (ctx);
286
0
  if (out_fd == GNUPG_INVALID_FD)
287
0
    {
288
0
      err = set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
289
0
      goto leave;
290
0
    }
291
292
293
  /* FIXME: GPGSM does this here: Add all encrypt-to marked recipients
294
     from the default list. */
295
296
  /* fixme: err = ctrl->audit? 0 : start_audit_session (ctrl);*/
297
298
0
  err = encrypt_crypt (ctrl, inp_fd, NULL, NULL, 0,
299
0
                       ctrl->server_local->recplist,
300
0
                       out_fd);
301
302
0
 leave:
303
  /* Release the recipient list on success.  */
304
0
  if (!err)
305
0
    {
306
0
      release_pk_list (ctrl->server_local->recplist);
307
0
      ctrl->server_local->recplist = NULL;
308
0
    }
309
310
  /* Close and reset the fds. */
311
0
  close_message_fd (ctrl);
312
0
  assuan_close_input_fd (ctx);
313
0
  assuan_close_output_fd (ctx);
314
315
0
  if (err)
316
0
    log_error ("command '%s' failed: %s\n", "ENCRYPT", gpg_strerror (err));
317
0
  return err;
318
0
}
319
320
321

322
/*  DECRYPT
323
324
    This performs the decrypt operation.  */
325
static gpg_error_t
326
cmd_decrypt (assuan_context_t ctx, char *line)
327
0
{
328
0
  ctrl_t ctrl = assuan_get_pointer (ctx);
329
0
  gpg_error_t err;
330
0
  gnupg_fd_t inp_fd, out_fd;
331
332
0
  (void)line; /* LINE is not used.  */
333
334
0
  inp_fd = assuan_get_input_fd (ctx);
335
0
  if (inp_fd == GNUPG_INVALID_FD)
336
0
    return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
337
0
  out_fd = assuan_get_output_fd (ctx);
338
0
  if (out_fd == GNUPG_INVALID_FD)
339
0
    return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
340
341
0
  glo_ctrl.lasterr = 0;
342
0
  err = decrypt_message_fd (ctrl, inp_fd, out_fd);
343
0
  if (!err)
344
0
    err = glo_ctrl.lasterr;
345
346
  /* Close and reset the fds. */
347
0
  close_message_fd (ctrl);
348
0
  assuan_close_input_fd (ctx);
349
0
  assuan_close_output_fd (ctx);
350
351
0
  if (err)
352
0
    log_error ("command '%s' failed: %s\n", "DECRYPT", gpg_strerror (err));
353
0
  return err;
354
0
}
355
356
357

358
/*  VERIFY
359
360
   This does a verify operation on the message send to the input-FD.
361
   The result is written out using status lines.  If an output FD was
362
   given, the signed text will be written to that.
363
364
   If the signature is a detached one, the server will inquire about
365
   the signed material and the client must provide it.
366
 */
367
static gpg_error_t
368
cmd_verify (assuan_context_t ctx, char *line)
369
0
{
370
0
  int rc;
371
#ifdef HAVE_W32_SYSTEM
372
  (void)ctx;
373
  (void)line;
374
  rc = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
375
#else
376
0
  ctrl_t ctrl = assuan_get_pointer (ctx);
377
0
  gnupg_fd_t fd = assuan_get_input_fd (ctx);
378
0
  gnupg_fd_t out_fd = assuan_get_output_fd (ctx);
379
0
  estream_t out_fp = NULL;
380
381
  /* FIXME: Revamp this code it is nearly to 3 years old and was only
382
     intended as a quick test.  */
383
384
0
  (void)line;
385
386
0
  if (fd == GNUPG_INVALID_FD)
387
0
    return gpg_error (GPG_ERR_ASS_NO_INPUT);
388
389
0
  if (out_fd != GNUPG_INVALID_FD)
390
0
    {
391
0
      out_fp = open_stream_nc (fd, "w");
392
0
      if (!out_fp)
393
0
        return set_error (gpg_err_code_from_syserror (), "fdopen() failed");
394
0
    }
395
396
0
  log_debug ("WARNING: The server mode is WORK "
397
0
             "IN PROGRESS and not ready for use\n");
398
399
0
  rc = gpg_verify (ctrl, fd, ctrl->server_local->message_fd, out_fp);
400
401
0
  es_fclose (out_fp);
402
0
  close_message_fd (ctrl);
403
0
  assuan_close_input_fd (ctx);
404
0
  assuan_close_output_fd (ctx);
405
0
#endif
406
407
0
  if (rc)
408
0
    log_error ("command '%s' failed: %s\n", "VERIFY", gpg_strerror (rc));
409
0
  return rc;
410
0
}
411
412
413

414
/*  SIGN [--detached]
415
416
   Sign the data set with the INPUT command and write it to the sink
417
   set by OUTPUT.  With "--detached" specified, a detached signature
418
   is created.  */
419
static gpg_error_t
420
cmd_sign (assuan_context_t ctx, char *line)
421
0
{
422
0
  (void)ctx;
423
0
  (void)line;
424
0
  return gpg_error (GPG_ERR_NOT_SUPPORTED);
425
0
}
426
427
428

429
/*  IMPORT
430
431
  Import keys as read from the input-fd, return status message for
432
  each imported one.  The import checks the validity of the key.  */
433
static gpg_error_t
434
cmd_import (assuan_context_t ctx, char *line)
435
0
{
436
0
  (void)ctx;
437
0
  (void)line;
438
0
  return gpg_error (GPG_ERR_NOT_SUPPORTED);
439
0
}
440
441
442

443
/*  EXPORT [--data [--armor|--base64]] [--] pattern
444
445
   Similar to the --export command line command, this command exports
446
   public keys matching PATTERN.  The output is send to the output fd
447
   unless the --data option has been used in which case the output
448
   gets send inline using regular data lines.  The options "--armor"
449
   and "--base" ospecify an output format if "--data" has been used.
450
   Recall that in general the output format is set with the OUTPUT
451
   command.
452
 */
453
static gpg_error_t
454
cmd_export (assuan_context_t ctx, char *line)
455
0
{
456
0
  (void)ctx;
457
0
  (void)line;
458
0
  return gpg_error (GPG_ERR_NOT_SUPPORTED);
459
0
}
460
461
462

463
/*  DELKEYS
464
465
    Fixme
466
*/
467
static gpg_error_t
468
cmd_delkeys (assuan_context_t ctx, char *line)
469
0
{
470
0
  (void)ctx;
471
0
  (void)line;
472
0
  return gpg_error (GPG_ERR_NOT_SUPPORTED);
473
0
}
474
475
476

477
/*  MESSAGE FD[=<n>]
478
479
   Set the file descriptor to read a message which is used with
480
   detached signatures.  */
481
static gpg_error_t
482
cmd_message (assuan_context_t ctx, char *line)
483
0
{
484
0
  int rc;
485
0
  gnupg_fd_t fd;
486
0
  ctrl_t ctrl = assuan_get_pointer (ctx);
487
488
0
  rc = assuan_command_parse_fd (ctx, line, &fd);
489
0
  if (rc)
490
0
    return rc;
491
0
  if (fd == GNUPG_INVALID_FD)
492
0
    return gpg_error (GPG_ERR_ASS_NO_INPUT);
493
0
  ctrl->server_local->message_fd = fd;
494
0
  return 0;
495
0
}
496
497
498

499
/* LISTKEYS [<patterns>]
500
   LISTSECRETKEYS [<patterns>]
501
502
   fixme
503
*/
504
static gpg_error_t
505
do_listkeys (assuan_context_t ctx, char *line, int mode)
506
0
{
507
0
  (void)ctx;
508
0
  (void)line;
509
0
  (void)mode;
510
511
0
  return gpg_error (GPG_ERR_NOT_SUPPORTED);
512
0
}
513
514
515
static gpg_error_t
516
cmd_listkeys (assuan_context_t ctx, char *line)
517
0
{
518
0
  return do_listkeys (ctx, line, 3);
519
0
}
520
521
522
static gpg_error_t
523
cmd_listsecretkeys (assuan_context_t ctx, char *line)
524
0
{
525
0
  return do_listkeys (ctx, line, 2);
526
0
}
527
528
529

530
/* GENKEY
531
532
   Read the parameters in native format from the input fd and create a
533
   new OpenPGP key.
534
 */
535
static gpg_error_t
536
cmd_genkey (assuan_context_t ctx, char *line)
537
0
{
538
0
  (void)ctx;
539
0
  (void)line;
540
0
  return gpg_error (GPG_ERR_NOT_SUPPORTED);
541
0
}
542
543
544
/* GETINFO <what>
545
546
   Multipurpose function to return a variety of information.
547
   Supported values for WHAT are:
548
549
     version     - Return the version of the program.
550
     pid         - Return the process id of the server.
551
552
 */
553
static gpg_error_t
554
cmd_getinfo (assuan_context_t ctx, char *line)
555
0
{
556
0
  int rc;
557
558
0
  if (!strcmp (line, "version"))
559
0
    {
560
0
      const char *s = VERSION;
561
0
      rc = assuan_send_data (ctx, s, strlen (s));
562
0
    }
563
0
  else if (!strcmp (line, "pid"))
564
0
    {
565
0
      char numbuf[50];
566
567
0
      snprintf (numbuf, sizeof numbuf, "%lu", (unsigned long)getpid ());
568
0
      rc = assuan_send_data (ctx, numbuf, strlen (numbuf));
569
0
    }
570
0
  else
571
0
    rc = set_error (GPG_ERR_ASS_PARAMETER, "unknown value for WHAT");
572
0
  return rc;
573
0
}
574
575
static const char hlp_passwd[] =
576
  "PASSWD <userID>\n"
577
  "\n"
578
  "Change the passphrase of the secret key for USERID.";
579
static gpg_error_t
580
cmd_passwd (assuan_context_t ctx, char *line)
581
0
{
582
  /* ctrl_t ctrl = assuan_get_pointer (ctx); */
583
0
  gpg_error_t err;
584
585
0
  (void)ctx;
586
0
  (void)line;
587
  /* line = skip_options (line); */
588
589
0
  err = gpg_error (GPG_ERR_NOT_SUPPORTED);
590
591
0
  return err;
592
0
}
593
594
595
596

597
/* Helper to register our commands with libassuan. */
598
static int
599
register_commands (assuan_context_t ctx)
600
0
{
601
0
  static struct
602
0
  {
603
0
    const char *name;
604
0
    assuan_handler_t handler;
605
0
    const char * const help;
606
0
  } table[] = {
607
0
    { "RECIPIENT",     cmd_recipient },
608
0
    { "SIGNER",        cmd_signer    },
609
0
    { "ENCRYPT",       cmd_encrypt   },
610
0
    { "DECRYPT",       cmd_decrypt   },
611
0
    { "VERIFY",        cmd_verify    },
612
0
    { "SIGN",          cmd_sign      },
613
0
    { "IMPORT",        cmd_import    },
614
0
    { "EXPORT",        cmd_export    },
615
0
    { "INPUT",         NULL          },
616
0
    { "OUTPUT",        NULL          },
617
0
    { "MESSAGE",       cmd_message   },
618
0
    { "LISTKEYS",      cmd_listkeys  },
619
0
    { "LISTSECRETKEYS",cmd_listsecretkeys },
620
0
    { "GENKEY",        cmd_genkey    },
621
0
    { "DELKEYS",       cmd_delkeys   },
622
0
    { "GETINFO",       cmd_getinfo   },
623
0
    { "PASSWD",        cmd_passwd,  hlp_passwd},
624
0
    { NULL }
625
0
  };
626
0
  int i, rc;
627
628
0
  for (i=0; table[i].name; i++)
629
0
    {
630
0
      rc = assuan_register_command (ctx, table[i].name,
631
0
                                    table[i].handler, table[i].help);
632
0
      if (rc)
633
0
        return rc;
634
0
    }
635
0
  return 0;
636
0
}
637
638
639
640

641
/* Startup the server.  CTRL must have been allocated by the caller
642
   and set to the default values. */
643
int
644
gpg_server (ctrl_t ctrl)
645
0
{
646
0
  int rc;
647
0
#ifndef HAVE_W32_SYSTEM
648
0
  int filedes[2];
649
0
#endif
650
0
  assuan_context_t ctx = NULL;
651
0
  static const char hello[] = ("GNU Privacy Guard's OpenPGP server "
652
0
                               VERSION " ready");
653
654
  /* We use a pipe based server so that we can work from scripts.
655
     assuan_init_pipe_server will automagically detect when we are
656
     called with a socketpair and ignore FILEDES in this case.  */
657
0
#ifndef HAVE_W32_SYSTEM
658
0
  filedes[0] = assuan_fdopen (0);
659
0
  filedes[1] = assuan_fdopen (1);
660
0
#endif
661
0
  rc = assuan_new (&ctx);
662
0
  if (rc)
663
0
    {
664
0
      log_error ("failed to allocate the assuan context: %s\n",
665
0
     gpg_strerror (rc));
666
0
      goto leave;
667
0
    }
668
669
#ifdef HAVE_W32_SYSTEM
670
  rc = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
671
#else
672
0
  rc = assuan_init_pipe_server (ctx, filedes);
673
0
#endif
674
0
  if (rc)
675
0
    {
676
0
      log_error ("failed to initialize the server: %s\n", gpg_strerror (rc));
677
0
      goto leave;
678
0
    }
679
680
0
  rc = register_commands (ctx);
681
0
  if (rc)
682
0
    {
683
0
      log_error ("failed to the register commands with Assuan: %s\n",
684
0
                 gpg_strerror(rc));
685
0
      goto leave;
686
0
    }
687
688
0
  assuan_set_pointer (ctx, ctrl);
689
0
  if (opt.verbose || opt.debug)
690
0
    {
691
0
      char *tmp;
692
693
0
      tmp = xtryasprintf ("Home: %s\n"
694
0
                          "Config: %s\n"
695
0
                          "%s",
696
0
                          gnupg_homedir (),
697
0
                          "fixme: need config filename",
698
0
                          hello);
699
0
      if (tmp)
700
0
        {
701
0
          assuan_set_hello_line (ctx, tmp);
702
0
          xfree (tmp);
703
0
        }
704
0
    }
705
0
  else
706
0
    assuan_set_hello_line (ctx, hello);
707
0
  assuan_register_reset_notify (ctx, reset_notify);
708
0
  assuan_register_input_notify (ctx, input_notify);
709
0
  assuan_register_output_notify (ctx, output_notify);
710
0
  assuan_register_option_handler (ctx, option_handler);
711
712
0
  ctrl->server_local = xtrycalloc (1, sizeof *ctrl->server_local);
713
0
  if (!ctrl->server_local)
714
0
    {
715
0
      rc = gpg_error_from_syserror ();
716
0
      goto leave;
717
0
    }
718
0
  ctrl->server_local->assuan_ctx = ctx;
719
0
  ctrl->server_local->message_fd = GNUPG_INVALID_FD;
720
721
0
  for (;;)
722
0
    {
723
0
      rc = assuan_accept (ctx);
724
0
      if (rc == -1)
725
0
        {
726
0
          rc = 0;
727
0
          break;
728
0
        }
729
0
      else if (rc)
730
0
        {
731
0
          log_info ("Assuan accept problem: %s\n", gpg_strerror (rc));
732
0
          break;
733
0
        }
734
735
0
      rc = assuan_process (ctx);
736
0
      if (rc)
737
0
        {
738
0
          log_info ("Assuan processing failed: %s\n", gpg_strerror (rc));
739
0
          continue;
740
0
        }
741
0
    }
742
743
0
 leave:
744
0
  if (ctrl->server_local)
745
0
    {
746
0
      release_pk_list (ctrl->server_local->recplist);
747
748
0
      xfree (ctrl->server_local);
749
0
      ctrl->server_local = NULL;
750
0
    }
751
0
  assuan_release (ctx);
752
0
  return rc;
753
0
}
754
755
756
/* Helper to notify the client about Pinentry events.  Because that
757
   might disturb some older clients, this is only done when enabled
758
   via an option.  If it is not enabled we tell Windows to allow
759
   setting the foreground window right here.  Returns an gpg error
760
   code. */
761
gpg_error_t
762
gpg_proxy_pinentry_notify (ctrl_t ctrl, const unsigned char *line)
763
0
{
764
0
  const char *s;
765
766
0
  if (opt.verbose
767
0
      && !strncmp (line, "PINENTRY_LAUNCHED", 17)
768
0
      && (line[17]==' '||!line[17]))
769
0
    {
770
0
      for (s = line + 17; *s && spacep (s); s++)
771
0
        ;
772
0
      log_info (_("pinentry launched (%s)\n"), s);
773
0
    }
774
775
0
  if (!ctrl || !ctrl->server_local
776
0
      || !ctrl->server_local->allow_pinentry_notify)
777
0
    {
778
0
      gnupg_allow_set_foregound_window ((pid_t)strtoul (line+17, NULL, 10));
779
      /* Client might be interested in that event - send as status line.  */
780
0
      if (!strncmp (line, "PINENTRY_LAUNCHED", 17)
781
0
          && (line[17]==' '||!line[17]))
782
0
        {
783
0
          for (line += 17; *line && spacep (line); line++)
784
0
            ;
785
0
          write_status_text (STATUS_PINENTRY_LAUNCHED, line);
786
0
        }
787
0
      return 0;
788
0
    }
789
0
  return assuan_inquire (ctrl->server_local->assuan_ctx, line, NULL, NULL, 0);
790
0
}