~ubuntu-branches/ubuntu/jaunty/gnupg2/jaunty-security

« back to all changes in this revision

Viewing changes to assuan/assuan-handler.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
 
/* assuan-handler.c - dispatch commands 
2
 
 *      Copyright (C) 2001, 2002 Free Software Foundation, Inc.
3
 
 *
4
 
 * This file is part of Assuan.
5
 
 *
6
 
 * Assuan is free software; you can redistribute it and/or modify it
7
 
 * under the terms of the GNU Lesser General Public License as
8
 
 * published by the Free Software Foundation; either version 2.1 of
9
 
 * the License, or (at your option) any later version.
10
 
 *
11
 
 * Assuan is distributed in the hope that it will be useful, but
12
 
 * WITHOUT ANY WARRANTY; without even the implied warranty of
13
 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
 
 * Lesser General Public License for more details.
15
 
 *
16
 
 * You should have received a copy of the GNU Lesser General Public
17
 
 * License 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
 
#include <config.h>
22
 
#include <stdlib.h>
23
 
#include <stdio.h>
24
 
#include <string.h>
25
 
 
26
 
#include "assuan-defs.h"
27
 
 
28
 
#define spacep(p)  (*(p) == ' ' || *(p) == '\t')
29
 
#define digitp(a) ((a) >= '0' && (a) <= '9')
30
 
 
31
 
 
32
 
#if !HAVE_FOPENCOOKIE
33
 
/* Provide structure for our dummy replacement function.  Usually this
34
 
   is defined in ../common/util.h but assuan should be self
35
 
   contained. */
36
 
/* Fixme: Remove fopencoookie :-(( */
37
 
typedef struct
38
 
{
39
 
  ssize_t (*read)(void*,char*,size_t);
40
 
  ssize_t (*write)(void*,const char*,size_t);
41
 
  int (*seek)(void*,off_t*,int);
42
 
  int (*close)(void*);
43
 
} _IO_cookie_io_functions_t;
44
 
typedef _IO_cookie_io_functions_t cookie_io_functions_t;
45
 
FILE *fopencookie (void *cookie, const char *opentype,
46
 
                   cookie_io_functions_t funclist);
47
 
#endif /*!HAVE_FOPENCOOKIE*/
48
 
 
49
 
 
50
 
 
51
 
 
52
 
static int
53
 
dummy_handler (ASSUAN_CONTEXT ctx, char *line)
54
 
{
55
 
  return set_error (ctx, Server_Fault, "no handler registered");
56
 
}
57
 
 
58
 
 
59
 
static int
60
 
std_handler_nop (ASSUAN_CONTEXT ctx, char *line)
61
 
{
62
 
  return 0; /* okay */
63
 
}
64
 
  
65
 
static int
66
 
std_handler_cancel (ASSUAN_CONTEXT ctx, char *line)
67
 
{
68
 
  if (ctx->cancel_notify_fnc)
69
 
    ctx->cancel_notify_fnc (ctx);
70
 
  return set_error (ctx, Not_Implemented, NULL); 
71
 
}
72
 
 
73
 
static int
74
 
std_handler_option (ASSUAN_CONTEXT ctx, char *line)
75
 
{
76
 
  char *key, *value, *p;
77
 
 
78
 
  for (key=line; spacep (key); key++)
79
 
    ;
80
 
  if (!*key)
81
 
    return set_error (ctx, Syntax_Error, "argument required");
82
 
  if (*key == '=')
83
 
    return set_error (ctx, Syntax_Error, "no option name given");
84
 
  for (value=key; *value && !spacep (value) && *value != '='; value++)
85
 
    ;
86
 
  if (*value)
87
 
    {
88
 
      if (spacep (value))
89
 
        *value++ = 0; /* terminate key */
90
 
      for (; spacep (value); value++)
91
 
        ;
92
 
      if (*value == '=')
93
 
        {
94
 
          *value++ = 0; /* terminate key */
95
 
          for (; spacep (value); value++)
96
 
            ;
97
 
          if (!*value)
98
 
            return set_error (ctx, Syntax_Error, "option argument expected");
99
 
        }
100
 
      if (*value)
101
 
        {
102
 
          for (p = value + strlen(value) - 1; p > value && spacep (p); p--)
103
 
            ;
104
 
          if (p > value)
105
 
            *++p = 0; /* strip trailing spaces */
106
 
        }
107
 
    }
108
 
 
109
 
  if (*key == '-' && key[1] == '-' && key[2])
110
 
    key += 2; /* the double dashes are optional */
111
 
  if (*key == '-')
112
 
    return set_error (ctx, Syntax_Error,
113
 
                      "option should not begin with one dash");
114
 
 
115
 
  if (ctx->option_handler_fnc)
116
 
    return ctx->option_handler_fnc (ctx, key, value);
117
 
  return 0;
118
 
}
119
 
  
120
 
static int
121
 
std_handler_bye (ASSUAN_CONTEXT ctx, char *line)
122
 
{
123
 
  if (ctx->bye_notify_fnc)
124
 
    ctx->bye_notify_fnc (ctx);
125
 
  assuan_close_input_fd (ctx);
126
 
  assuan_close_output_fd (ctx);
127
 
  return -1; /* pretty simple :-) */
128
 
}
129
 
  
130
 
static int
131
 
std_handler_auth (ASSUAN_CONTEXT ctx, char *line)
132
 
{
133
 
  return set_error (ctx, Not_Implemented, NULL); 
134
 
}
135
 
  
136
 
static int
137
 
std_handler_reset (ASSUAN_CONTEXT ctx, char *line)
138
 
{
139
 
  if (ctx->reset_notify_fnc)
140
 
    ctx->reset_notify_fnc (ctx);
141
 
  assuan_close_input_fd (ctx);
142
 
  assuan_close_output_fd (ctx);
143
 
  return 0;
144
 
}
145
 
  
146
 
static int
147
 
std_handler_end (ASSUAN_CONTEXT ctx, char *line)
148
 
{
149
 
  return set_error (ctx, Not_Implemented, NULL); 
150
 
}
151
 
 
152
 
static int
153
 
parse_cmd_input_output (ASSUAN_CONTEXT ctx, char *line, int *rfd)
154
 
{
155
 
  char *endp;
156
 
 
157
 
  if (strncmp (line, "FD=", 3))
158
 
    return set_error (ctx, Syntax_Error, "FD=<n> expected");
159
 
  line += 3;
160
 
  if (!digitp (*line))
161
 
    return set_error (ctx, Syntax_Error, "number required");
162
 
  *rfd = strtoul (line, &endp, 10);
163
 
  /* remove that argument so that a notify handler won't see it */
164
 
  memset (line, ' ', endp? (endp-line):strlen(line));
165
 
 
166
 
  if (*rfd == ctx->inbound.fd)
167
 
    return set_error (ctx, Parameter_Conflict, "fd same as inbound fd");
168
 
  if (*rfd == ctx->outbound.fd)
169
 
    return set_error (ctx, Parameter_Conflict, "fd same as outbound fd");
170
 
  return 0;
171
 
}
172
 
 
173
 
/* Format is INPUT FD=<n> */
174
 
static int
175
 
std_handler_input (ASSUAN_CONTEXT ctx, char *line)
176
 
{
177
 
  int rc, fd;
178
 
 
179
 
  rc = parse_cmd_input_output (ctx, line, &fd);
180
 
  if (rc)
181
 
    return rc;
182
 
  ctx->input_fd = fd;
183
 
  if (ctx->input_notify_fnc)
184
 
    ctx->input_notify_fnc (ctx, line);
185
 
  return 0;
186
 
}
187
 
 
188
 
/* Format is OUTPUT FD=<n> */
189
 
static int
190
 
std_handler_output (ASSUAN_CONTEXT ctx, char *line)
191
 
{
192
 
  int rc, fd;
193
 
 
194
 
  rc = parse_cmd_input_output (ctx, line, &fd);
195
 
  if (rc)
196
 
    return rc;
197
 
  ctx->output_fd = fd;
198
 
  if (ctx->output_notify_fnc)
199
 
    ctx->output_notify_fnc (ctx, line);
200
 
  return 0;
201
 
}
202
 
 
203
 
 
204
 
 
205
 
  
206
 
 
207
 
/* This is a table with the standard commands and handler for them.
208
 
   The table is used to initialize a new context and assuciate strings
209
 
   and handlers with cmd_ids */
210
 
static struct {
211
 
  const char *name;
212
 
  int cmd_id;
213
 
  int (*handler)(ASSUAN_CONTEXT, char *line);
214
 
  int always; /* always initialize this command */
215
 
} std_cmd_table[] = {
216
 
  { "NOP",    ASSUAN_CMD_NOP,    std_handler_nop, 1 },
217
 
  { "CANCEL", ASSUAN_CMD_CANCEL, std_handler_cancel, 1 },
218
 
  { "OPTION", ASSUAN_CMD_OPTION, std_handler_option, 1 },
219
 
  { "BYE",    ASSUAN_CMD_BYE,    std_handler_bye, 1 },
220
 
  { "AUTH",   ASSUAN_CMD_AUTH,   std_handler_auth, 1 },
221
 
  { "RESET",  ASSUAN_CMD_RESET,  std_handler_reset, 1 },
222
 
  { "END",    ASSUAN_CMD_END,    std_handler_end, 1 },
223
 
 
224
 
  { "INPUT",  ASSUAN_CMD_INPUT,  std_handler_input },
225
 
  { "OUTPUT", ASSUAN_CMD_OUTPUT, std_handler_output },
226
 
  { "OPTION", ASSUAN_CMD_OPTION, std_handler_option, 1 },
227
 
  { NULL }
228
 
};
229
 
 
230
 
 
231
 
/**
232
 
 * assuan_register_command:
233
 
 * @ctx: the server context
234
 
 * @cmd_id: An ID value for the command
235
 
 * @cmd_name: A string with the command name
236
 
 * @handler: The handler function to be called
237
 
 * 
238
 
 * Register a handler to be used for a given command.
239
 
 * 
240
 
 * The @cmd_name must be %NULL or an empty string for all @cmd_ids
241
 
 * below %ASSUAN_CMD_USER because predefined values are used.
242
 
 * 
243
 
 * Return value: 
244
 
 **/
245
 
int
246
 
assuan_register_command (ASSUAN_CONTEXT ctx,
247
 
                         int cmd_id, const char *cmd_name,
248
 
                         int (*handler)(ASSUAN_CONTEXT, char *))
249
 
{
250
 
  int i;
251
 
 
252
 
  if (cmd_name && !*cmd_name)
253
 
    cmd_name = NULL;
254
 
 
255
 
  if (cmd_id < ASSUAN_CMD_USER)
256
 
    { 
257
 
      if (cmd_name)
258
 
        return ASSUAN_Invalid_Value; /* must be NULL for these values*/
259
 
 
260
 
      for (i=0; std_cmd_table[i].name; i++)
261
 
        {
262
 
          if (std_cmd_table[i].cmd_id == cmd_id)
263
 
            {
264
 
              cmd_name = std_cmd_table[i].name;
265
 
              if (!handler)
266
 
                handler = std_cmd_table[i].handler;
267
 
              break;
268
 
            }
269
 
        }
270
 
      if (!std_cmd_table[i].name)
271
 
        return ASSUAN_Invalid_Value; /* not a pre-registered one */
272
 
    }
273
 
  
274
 
  if (!handler)
275
 
    handler = dummy_handler;
276
 
 
277
 
  if (!cmd_name)
278
 
    return ASSUAN_Invalid_Value;
279
 
 
280
 
/*    fprintf (stderr, "DBG-assuan: registering %d as `%s'\n", cmd_id, cmd_name); */
281
 
 
282
 
  if (!ctx->cmdtbl)
283
 
    {
284
 
      ctx->cmdtbl_size = 50;
285
 
      ctx->cmdtbl = xtrycalloc ( ctx->cmdtbl_size, sizeof *ctx->cmdtbl);
286
 
      if (!ctx->cmdtbl)
287
 
        return ASSUAN_Out_Of_Core;
288
 
      ctx->cmdtbl_used = 0;
289
 
    }
290
 
  else if (ctx->cmdtbl_used >= ctx->cmdtbl_size)
291
 
    {
292
 
      struct cmdtbl_s *x;
293
 
 
294
 
      x = xtryrealloc ( ctx->cmdtbl, (ctx->cmdtbl_size+10) * sizeof *x);
295
 
      if (!x)
296
 
        return ASSUAN_Out_Of_Core;
297
 
      ctx->cmdtbl = x;
298
 
      ctx->cmdtbl_size += 50;
299
 
    }
300
 
 
301
 
  ctx->cmdtbl[ctx->cmdtbl_used].name = cmd_name;
302
 
  ctx->cmdtbl[ctx->cmdtbl_used].cmd_id = cmd_id;
303
 
  ctx->cmdtbl[ctx->cmdtbl_used].handler = handler;
304
 
  ctx->cmdtbl_used++;
305
 
  return 0;
306
 
}
307
 
 
308
 
int
309
 
assuan_register_bye_notify (ASSUAN_CONTEXT ctx, void (*fnc)(ASSUAN_CONTEXT))
310
 
{
311
 
  if (!ctx)
312
 
    return ASSUAN_Invalid_Value;
313
 
  ctx->bye_notify_fnc = fnc;
314
 
  return 0;
315
 
}
316
 
 
317
 
int
318
 
assuan_register_reset_notify (ASSUAN_CONTEXT ctx, void (*fnc)(ASSUAN_CONTEXT))
319
 
{
320
 
  if (!ctx)
321
 
    return ASSUAN_Invalid_Value;
322
 
  ctx->reset_notify_fnc = fnc;
323
 
  return 0;
324
 
}
325
 
 
326
 
int
327
 
assuan_register_cancel_notify (ASSUAN_CONTEXT ctx, void (*fnc)(ASSUAN_CONTEXT))
328
 
{
329
 
  if (!ctx)
330
 
    return ASSUAN_Invalid_Value;
331
 
  ctx->cancel_notify_fnc = fnc;
332
 
  return 0;
333
 
}
334
 
 
335
 
int
336
 
assuan_register_option_handler (ASSUAN_CONTEXT ctx,
337
 
                               int (*fnc)(ASSUAN_CONTEXT,
338
 
                                          const char*, const char*))
339
 
{
340
 
  if (!ctx)
341
 
    return ASSUAN_Invalid_Value;
342
 
  ctx->option_handler_fnc = fnc;
343
 
  return 0;
344
 
}
345
 
 
346
 
int
347
 
assuan_register_input_notify (ASSUAN_CONTEXT ctx,
348
 
                              void (*fnc)(ASSUAN_CONTEXT, const char *))
349
 
{
350
 
  if (!ctx)
351
 
    return ASSUAN_Invalid_Value;
352
 
  ctx->input_notify_fnc = fnc;
353
 
  return 0;
354
 
}
355
 
 
356
 
int
357
 
assuan_register_output_notify (ASSUAN_CONTEXT ctx,
358
 
                              void (*fnc)(ASSUAN_CONTEXT, const char *))
359
 
{
360
 
  if (!ctx)
361
 
    return ASSUAN_Invalid_Value;
362
 
  ctx->output_notify_fnc = fnc;
363
 
  return 0;
364
 
}
365
 
 
366
 
 
367
 
/* Helper to register the standards commands */
368
 
int
369
 
_assuan_register_std_commands (ASSUAN_CONTEXT ctx)
370
 
{
371
 
  int i, rc;
372
 
 
373
 
  for (i=0; std_cmd_table[i].name; i++)
374
 
    {
375
 
      if (std_cmd_table[i].always)
376
 
        {
377
 
          rc = assuan_register_command (ctx, std_cmd_table[i].cmd_id,
378
 
                                        NULL, NULL);
379
 
          if (rc)
380
 
            return rc;
381
 
        }
382
 
    } 
383
 
  return 0;
384
 
}
385
 
 
386
 
 
387
 
 
388
 
/* Process the special data lines.  The "D " has already been removed
389
 
   from the line.  As all handlers this function may modify the line.  */
390
 
static int
391
 
handle_data_line (ASSUAN_CONTEXT ctx, char *line, int linelen)
392
 
{
393
 
  return set_error (ctx, Not_Implemented, NULL);
394
 
}
395
 
 
396
 
/* like ascii_strcasecmp but assume that B is already uppercase */
397
 
static int
398
 
my_strcasecmp (const char *a, const char *b)
399
 
{
400
 
    if (a == b)
401
 
        return 0;
402
 
 
403
 
    for (; *a && *b; a++, b++)
404
 
      {
405
 
        if (((*a >= 'a' && *a <= 'z')? (*a&~0x20):*a) != *b)
406
 
            break;
407
 
      }
408
 
    return *a == *b? 0 : (((*a >= 'a' && *a <= 'z')? (*a&~0x20):*a) - *b);
409
 
}
410
 
 
411
 
/* Parse the line, break out the command, find it in the command
412
 
   table, remove leading and white spaces from the arguments, all the
413
 
   handler with the argument line and return the error */
414
 
static int 
415
 
dispatch_command (ASSUAN_CONTEXT ctx, char *line, int linelen)
416
 
{
417
 
  char *p;
418
 
  const char *s;
419
 
  int shift, i;
420
 
 
421
 
  if (*line == 'D' && line[1] == ' ') /* divert to special handler */
422
 
    return handle_data_line (ctx, line+2, linelen-2);
423
 
 
424
 
  for (p=line; *p && *p != ' ' && *p != '\t'; p++)
425
 
    ;
426
 
  if (p==line)
427
 
    return set_error (ctx, Invalid_Command, "leading white-space"); 
428
 
  if (*p) 
429
 
    { /* Skip over leading WS after the keyword */
430
 
      *p++ = 0;
431
 
      while ( *p == ' ' || *p == '\t')
432
 
        p++;
433
 
    }
434
 
  shift = p - line;
435
 
 
436
 
  for (i=0; (s=ctx->cmdtbl[i].name); i++)
437
 
    {
438
 
      if (!strcmp (line, s))
439
 
        break;
440
 
    }
441
 
  if (!s)
442
 
    { /* and try case insensitive */
443
 
      for (i=0; (s=ctx->cmdtbl[i].name); i++)
444
 
        {
445
 
          if (!my_strcasecmp (line, s))
446
 
            break;
447
 
        }
448
 
    }
449
 
  if (!s)
450
 
    return set_error (ctx, Unknown_Command, NULL);
451
 
  line += shift;
452
 
  linelen -= shift;
453
 
 
454
 
/*    fprintf (stderr, "DBG-assuan: processing %s `%s'\n", s, line); */
455
 
  return ctx->cmdtbl[i].handler (ctx, line);
456
 
}
457
 
 
458
 
 
459
 
 
460
 
 
461
 
static int
462
 
process_request (ASSUAN_CONTEXT ctx)
463
 
{
464
 
  int rc;
465
 
 
466
 
  if (ctx->in_inquire)
467
 
    return ASSUAN_Nested_Commands;
468
 
 
469
 
  rc = _assuan_read_line (ctx);
470
 
  if (rc)
471
 
    return rc;
472
 
  if (*ctx->inbound.line == '#' || !ctx->inbound.linelen)
473
 
    return 0; /* comment line - ignore */
474
 
 
475
 
  ctx->outbound.data.error = 0;
476
 
  ctx->outbound.data.linelen = 0;
477
 
  /* dispatch command and return reply */
478
 
  rc = dispatch_command (ctx, ctx->inbound.line, ctx->inbound.linelen);
479
 
  /* check from data write errors */
480
 
  if (ctx->outbound.data.fp)
481
 
    { /* Flush the data lines */
482
 
      fclose (ctx->outbound.data.fp);
483
 
      ctx->outbound.data.fp = NULL;
484
 
      if (!rc && ctx->outbound.data.error)
485
 
        rc = ctx->outbound.data.error;
486
 
    }
487
 
  else /* flush any data send w/o using the data fp */
488
 
    {
489
 
      assuan_send_data (ctx, NULL, 0);
490
 
      if (!rc && ctx->outbound.data.error)
491
 
        rc = ctx->outbound.data.error;
492
 
    }
493
 
  /* Error handling */
494
 
  if (!rc)
495
 
    {
496
 
      rc = assuan_write_line (ctx, ctx->okay_line? ctx->okay_line : "OK");
497
 
    }
498
 
  else if (rc == -1)
499
 
    { /* No error checking because the peer may have already disconnect */ 
500
 
      assuan_write_line (ctx, "OK closing connection");
501
 
      ctx->finish_handler (ctx);
502
 
    }
503
 
  else 
504
 
    {
505
 
      char errline[256];
506
 
 
507
 
      if (rc < 100)
508
 
        sprintf (errline, "ERR %d server fault (%.50s)",
509
 
                 ASSUAN_Server_Fault, assuan_strerror (rc));
510
 
      else
511
 
        {
512
 
          const char *text = ctx->err_no == rc? ctx->err_str:NULL;
513
 
 
514
 
          sprintf (errline, "ERR %d %.50s%s%.100s",
515
 
                   rc, assuan_strerror (rc), text? " - ":"", text?text:"");
516
 
        }
517
 
      rc = assuan_write_line (ctx, errline);
518
 
    }
519
 
 
520
 
  ctx->confidential = 0;
521
 
  if (ctx->okay_line)
522
 
    {
523
 
      xfree (ctx->okay_line);
524
 
      ctx->okay_line = NULL;
525
 
    }
526
 
  return rc;
527
 
}
528
 
 
529
 
/**
530
 
 * assuan_process:
531
 
 * @ctx: assuan context
532
 
 * 
533
 
 * This fucntion is used to handle the assuan protocol after a
534
 
 * connection has been established using assuan_accept().  This is the
535
 
 * main protocol handler.
536
 
 * 
537
 
 * Return value: 0 on success or an error code if the assuan operation
538
 
 * failed.  Note, that no error is returned for operational errors.
539
 
 **/
540
 
int
541
 
assuan_process (ASSUAN_CONTEXT ctx)
542
 
{
543
 
  int rc;
544
 
 
545
 
  do {
546
 
    rc = process_request (ctx);
547
 
  } while (!rc);
548
 
 
549
 
  if (rc == -1)
550
 
    rc = 0;
551
 
 
552
 
  return rc;
553
 
}
554
 
 
555
 
 
556
 
/**
557
 
 * assuan_process_next:
558
 
 * @ctx: Assuan context
559
 
 * 
560
 
 * Same as assuan_process() but the user has to provide the outer
561
 
 * loop.  He should loop as long as the return code is zero and stop
562
 
 * otherwise; -1 is regular end.
563
 
 * 
564
 
 * See also: assuan_get_active_fds()
565
 
 * Return value: -1 for end of server, 0 on success or an error code
566
 
 **/
567
 
int 
568
 
assuan_process_next (ASSUAN_CONTEXT ctx)
569
 
{
570
 
  return process_request (ctx);
571
 
}
572
 
 
573
 
 
574
 
/**
575
 
 * assuan_get_active_fds:
576
 
 * @ctx: Assuan context
577
 
 * @what: 0 for read fds, 1 for write fds
578
 
 * @fdarray: Caller supplied array to store the FDs
579
 
 * @fdarraysize: size of that array
580
 
 * 
581
 
 * Return all active filedescriptors for the given context.  This
582
 
 * function can be used to select on the fds and call
583
 
 * assuan_process_next() if there is an active one.  The first fd in
584
 
 * the array is the one used for the command connection.
585
 
 *
586
 
 * Note, that write FDs are not yet supported.
587
 
 * 
588
 
 * Return value: number of FDs active and put into @fdarray or -1 on
589
 
 * error which is most likely a too small fdarray.
590
 
 **/
591
 
int 
592
 
assuan_get_active_fds (ASSUAN_CONTEXT ctx, int what,
593
 
                       int *fdarray, int fdarraysize)
594
 
{
595
 
  int n = 0;
596
 
 
597
 
  if (!ctx || fdarraysize < 2 || what < 0 || what > 1)
598
 
    return -1;
599
 
 
600
 
  if (!what)
601
 
    {
602
 
      if (ctx->inbound.fd != -1)
603
 
        fdarray[n++] = ctx->inbound.fd;
604
 
    }
605
 
  else
606
 
    {
607
 
      if (ctx->outbound.fd != -1)
608
 
        fdarray[n++] = ctx->outbound.fd;
609
 
      if (ctx->outbound.data.fp)
610
 
        fdarray[n++] = fileno (ctx->outbound.data.fp);
611
 
    }
612
 
 
613
 
  return n;
614
 
}
615
 
 
616
 
/* Return a FP to be used for data output.  The FILE pointer is valid
617
 
   until the end of a handler.  So a close is not needed.  Assuan does
618
 
   all the buffering needed to insert the status line as well as the
619
 
   required line wappping and quoting for data lines.
620
 
 
621
 
   We use GNU's custom streams here.  There should be an alternative
622
 
   implementaion for systems w/o a glibc, a simple implementation
623
 
   could use a child process */
624
 
FILE *
625
 
assuan_get_data_fp (ASSUAN_CONTEXT ctx)
626
 
{
627
 
  cookie_io_functions_t cookie_fnc;
628
 
 
629
 
  if (ctx->outbound.data.fp)
630
 
    return ctx->outbound.data.fp;
631
 
  
632
 
  cookie_fnc.read = NULL; 
633
 
  cookie_fnc.write = _assuan_cookie_write_data;
634
 
  cookie_fnc.seek = NULL;
635
 
  cookie_fnc.close = _assuan_cookie_write_flush;
636
 
 
637
 
  ctx->outbound.data.fp = fopencookie (ctx, "wb", cookie_fnc);
638
 
  ctx->outbound.data.error = 0;
639
 
  return ctx->outbound.data.fp;
640
 
}
641
 
 
642
 
 
643
 
/* Set the text used for the next OK reponse.  This string is
644
 
   automatically reset to NULL after the next command. */
645
 
AssuanError
646
 
assuan_set_okay_line (ASSUAN_CONTEXT ctx, const char *line)
647
 
{
648
 
  if (!ctx)
649
 
    return ASSUAN_Invalid_Value;
650
 
  if (!line)
651
 
    {
652
 
      xfree (ctx->okay_line);
653
 
      ctx->okay_line = NULL;
654
 
    }
655
 
  else
656
 
    {
657
 
      /* FIXME: we need to use gcry_is_secure() to test whether
658
 
         we should allocate the entire line in secure memory */
659
 
      char *buf = xtrymalloc (3+strlen(line)+1);
660
 
      if (!buf)
661
 
        return ASSUAN_Out_Of_Core;
662
 
      strcpy (buf, "OK ");
663
 
      strcpy (buf+3, line);
664
 
      xfree (ctx->okay_line);
665
 
      ctx->okay_line = buf;
666
 
    }
667
 
  return 0;
668
 
}
669
 
 
670
 
 
671
 
 
672
 
void
673
 
assuan_write_status (ASSUAN_CONTEXT ctx, const char *keyword, const char *text)
674
 
{
675
 
  char buffer[256];
676
 
  char *helpbuf;
677
 
  size_t n;
678
 
 
679
 
  if ( !ctx || !keyword)
680
 
    return;
681
 
  if (!text)
682
 
    text = "";
683
 
 
684
 
  n = 2 + strlen (keyword) + 1 + strlen (text) + 1;
685
 
  if (n < sizeof (buffer))
686
 
    {
687
 
      strcpy (buffer, "S ");
688
 
      strcat (buffer, keyword);
689
 
      if (*text)
690
 
        {
691
 
          strcat (buffer, " ");
692
 
          strcat (buffer, text);
693
 
        }
694
 
      assuan_write_line (ctx, buffer);
695
 
    }
696
 
  else if ( (helpbuf = xtrymalloc (n)) )
697
 
    {
698
 
      strcpy (helpbuf, "S ");
699
 
      strcat (helpbuf, keyword);
700
 
      if (*text)
701
 
        {
702
 
          strcat (helpbuf, " ");
703
 
          strcat (helpbuf, text);
704
 
        }
705
 
      assuan_write_line (ctx, helpbuf);
706
 
      xfree (helpbuf);
707
 
    }
708
 
}