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

« back to all changes in this revision

Viewing changes to assuan/assuan-buffer.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-buffer.c - read and send data
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 <string.h>
24
 
#include <stdio.h>
25
 
#include <errno.h>
26
 
#include <unistd.h>
27
 
#include <assert.h>
28
 
#include "assuan-defs.h"
29
 
 
30
 
#ifdef HAVE_JNLIB_LOGGING
31
 
#include "../jnlib/logging.h"
32
 
#endif
33
 
 
34
 
 
35
 
static const char *
36
 
my_log_prefix (void)
37
 
{
38
 
#ifdef HAVE_JNLIB_LOGGING
39
 
  return log_get_prefix (NULL);
40
 
#else
41
 
  return "";
42
 
#endif
43
 
}
44
 
 
45
 
 
46
 
static int
47
 
writen ( int fd, const char *buffer, size_t length )
48
 
{
49
 
  while (length)
50
 
    {
51
 
      int nwritten = _assuan_write_wrapper?
52
 
        _assuan_write_wrapper (fd, buffer, length):
53
 
        write (fd, buffer, length);
54
 
      
55
 
      if (nwritten < 0)
56
 
        {
57
 
          if (errno == EINTR)
58
 
            continue;
59
 
          return -1; /* write error */
60
 
        }
61
 
      length -= nwritten;
62
 
      buffer += nwritten;
63
 
    }
64
 
  return 0;  /* okay */
65
 
}
66
 
 
67
 
/* read an entire line */
68
 
static int
69
 
readline (int fd, char *buf, size_t buflen, int *r_nread, int *eof)
70
 
{
71
 
  size_t nleft = buflen;
72
 
  char *p;
73
 
 
74
 
  *eof = 0;
75
 
  *r_nread = 0;
76
 
  while (nleft > 0)
77
 
    {
78
 
      int n = _assuan_read_wrapper?
79
 
        _assuan_read_wrapper (fd, buf, nleft):
80
 
        read (fd, buf, nleft);
81
 
 
82
 
      if (n < 0)
83
 
        {
84
 
          if (errno == EINTR)
85
 
            continue;
86
 
          return -1; /* read error */
87
 
        }
88
 
      else if (!n)
89
 
        {
90
 
          *eof = 1;
91
 
          break; /* allow incomplete lines */
92
 
        }
93
 
      p = buf;
94
 
      nleft -= n;
95
 
      buf += n;
96
 
      *r_nread += n;
97
 
      
98
 
      for (; n && *p != '\n'; n--, p++)
99
 
        ;
100
 
      if (n)
101
 
        break; /* at least one full line available - that's enough for now */
102
 
    }
103
 
 
104
 
  return 0;
105
 
}
106
 
 
107
 
 
108
 
int
109
 
_assuan_read_line (ASSUAN_CONTEXT ctx)
110
 
{
111
 
  char *line = ctx->inbound.line;
112
 
  int n, nread, atticlen;
113
 
  int rc;
114
 
 
115
 
  if (ctx->inbound.eof)
116
 
    return -1;
117
 
 
118
 
  atticlen = ctx->inbound.attic.linelen;
119
 
  if (atticlen)
120
 
    {
121
 
      memcpy (line, ctx->inbound.attic.line, atticlen);
122
 
      ctx->inbound.attic.linelen = 0;
123
 
      for (n=0; n < atticlen && line[n] != '\n'; n++)
124
 
        ;
125
 
      if (n < atticlen)
126
 
        {
127
 
          rc = 0; /* found another line in the attic */
128
 
          nread = atticlen;
129
 
          atticlen = 0;
130
 
        }
131
 
      else
132
 
        { /* read the rest */
133
 
          assert (atticlen < LINELENGTH);
134
 
          rc = readline (ctx->inbound.fd, line + atticlen,
135
 
                         LINELENGTH - atticlen, &nread, &ctx->inbound.eof);
136
 
        }
137
 
    }
138
 
  else
139
 
    rc = readline (ctx->inbound.fd, line, LINELENGTH,
140
 
                   &nread, &ctx->inbound.eof);
141
 
  if (rc)
142
 
    {
143
 
      if (ctx->log_fp)
144
 
        fprintf (ctx->log_fp, "%s[%p] <- [Error: %s]\n",
145
 
                 my_log_prefix (), ctx, strerror (errno)); 
146
 
      return ASSUAN_Read_Error;
147
 
    }
148
 
  if (!nread)
149
 
    {
150
 
      assert (ctx->inbound.eof);
151
 
      if (ctx->log_fp)
152
 
        fprintf (ctx->log_fp, "%s[%p] <- [EOF]\n", my_log_prefix (),ctx); 
153
 
      return -1; 
154
 
    }
155
 
 
156
 
  ctx->inbound.attic.pending = 0;
157
 
  nread += atticlen;
158
 
  for (n=0; n < nread; n++)
159
 
    {
160
 
      if (line[n] == '\n')
161
 
        {
162
 
          if (n+1 < nread)
163
 
            {
164
 
              char *s, *d;
165
 
              int i;
166
 
 
167
 
              n++;
168
 
              /* we have to copy the rest because the handlers are
169
 
                 allowed to modify the passed buffer */
170
 
              for (d=ctx->inbound.attic.line, s=line+n, i=nread-n; i; i--)
171
 
                {
172
 
                  if (*s=='\n')
173
 
                    ctx->inbound.attic.pending = 1;
174
 
                  *d++ = *s++;
175
 
                }
176
 
              ctx->inbound.attic.linelen = nread-n;
177
 
              n--;
178
 
            }
179
 
          if (n && line[n-1] == '\r')
180
 
            n--;
181
 
          line[n] = 0;
182
 
          ctx->inbound.linelen = n;
183
 
          if (ctx->log_fp)
184
 
            {
185
 
              fprintf (ctx->log_fp, "%s[%p] <- ", my_log_prefix (), ctx); 
186
 
              if (ctx->confidential)
187
 
                fputs ("[Confidential data not shown]", ctx->log_fp);
188
 
              else
189
 
                _assuan_log_print_buffer (ctx->log_fp, 
190
 
                                          ctx->inbound.line,
191
 
                                          ctx->inbound.linelen);
192
 
              putc ('\n', ctx->log_fp);
193
 
            }
194
 
          return 0;
195
 
        }
196
 
    }
197
 
 
198
 
  if (ctx->log_fp)
199
 
    fprintf (ctx->log_fp, "%s[%p] <- [Invalid line]\n", my_log_prefix (), ctx);
200
 
  *line = 0;
201
 
  ctx->inbound.linelen = 0;
202
 
  return ctx->inbound.eof? ASSUAN_Line_Not_Terminated : ASSUAN_Line_Too_Long;
203
 
}
204
 
 
205
 
 
206
 
/* Read the next line from the client or server and return a pointer
207
 
   to a buffer with holding that line.  linelen returns the length of
208
 
   the line.  This buffer is valid until another read operation is
209
 
   done on this buffer.  The caller is allowed to modify this buffer.
210
 
   He should only use the buffer if the function returns without an
211
 
   error.
212
 
 
213
 
   Returns: 0 on success or an assuan error code
214
 
   See also: assuan_pending_line().
215
 
*/
216
 
AssuanError
217
 
assuan_read_line (ASSUAN_CONTEXT ctx, char **line, size_t *linelen)
218
 
{
219
 
  AssuanError err;
220
 
 
221
 
  if (!ctx)
222
 
    return ASSUAN_Invalid_Value;
223
 
 
224
 
  err = _assuan_read_line (ctx);
225
 
  *line = ctx->inbound.line;
226
 
  *linelen = ctx->inbound.linelen;
227
 
  return err;
228
 
}
229
 
 
230
 
 
231
 
/* Return true when a full line is pending for a read, without the need
232
 
   for actual IO */
233
 
int
234
 
assuan_pending_line (ASSUAN_CONTEXT ctx)
235
 
{
236
 
  return ctx && ctx->inbound.attic.pending;
237
 
}
238
 
 
239
 
 
240
 
AssuanError 
241
 
assuan_write_line (ASSUAN_CONTEXT ctx, const char *line )
242
 
{
243
 
  int rc;
244
 
  size_t len;
245
 
  const char *s;
246
 
 
247
 
  if (!ctx)
248
 
    return ASSUAN_Invalid_Value;
249
 
 
250
 
  /* Make sure that we never take a LF from the user - this might
251
 
     violate the protocol. */
252
 
  s = strchr (line, '\n');
253
 
  len = s? (s-line) : strlen (line);
254
 
 
255
 
  /* fixme: we should do some kind of line buffering.  */
256
 
  if (ctx->log_fp)
257
 
    {
258
 
      fprintf (ctx->log_fp, "%s[%p] -> ", my_log_prefix (), ctx); 
259
 
      if (s)
260
 
        fputs ("[supplied line contained a LF]", ctx->log_fp);
261
 
      if (ctx->confidential)
262
 
        fputs ("[Confidential data not shown]", ctx->log_fp);
263
 
      else
264
 
        _assuan_log_print_buffer (ctx->log_fp, line, len);
265
 
      putc ('\n', ctx->log_fp);
266
 
    }
267
 
 
268
 
  rc = writen (ctx->outbound.fd, line, len);
269
 
  if (rc)
270
 
    rc = ASSUAN_Write_Error;
271
 
  if (!rc)
272
 
    {
273
 
      rc = writen (ctx->outbound.fd, "\n", 1);
274
 
      if (rc)
275
 
        rc = ASSUAN_Write_Error;
276
 
    }
277
 
 
278
 
  return rc;
279
 
}
280
 
 
281
 
 
282
 
 
283
 
/* Write out the data in buffer as datalines with line wrapping and
284
 
   percent escaping.  This fucntion is used for GNU's custom streams */
285
 
int
286
 
_assuan_cookie_write_data (void *cookie, const char *buffer, size_t size)
287
 
{
288
 
  ASSUAN_CONTEXT ctx = cookie;
289
 
  char *line;
290
 
  size_t linelen;
291
 
 
292
 
  if (ctx->outbound.data.error)
293
 
    return 0;
294
 
 
295
 
  line = ctx->outbound.data.line;
296
 
  linelen = ctx->outbound.data.linelen;
297
 
  line += linelen;
298
 
  while (size)
299
 
    {
300
 
      /* insert data line header */
301
 
      if (!linelen)
302
 
        {
303
 
          *line++ = 'D';
304
 
          *line++ = ' ';
305
 
          linelen += 2;
306
 
        }
307
 
      
308
 
      /* copy data, keep some space for the CRLF and to escape one character */
309
 
      while (size && linelen < LINELENGTH-2-2)
310
 
        {
311
 
          if (*buffer == '%' || *buffer == '\r' || *buffer == '\n')
312
 
            {
313
 
              sprintf (line, "%%%02X", *(unsigned char*)buffer);
314
 
              line += 3;
315
 
              linelen += 3;
316
 
              buffer++;
317
 
            }
318
 
          else
319
 
            {
320
 
              *line++ = *buffer++;
321
 
              linelen++;
322
 
            }
323
 
          size--;
324
 
        }
325
 
      
326
 
      if (linelen >= LINELENGTH-2-2)
327
 
        {
328
 
          if (ctx->log_fp)
329
 
            {
330
 
              fprintf (ctx->log_fp, "%s[%p] -> ", my_log_prefix (), ctx); 
331
 
              if (ctx->confidential)
332
 
                fputs ("[Confidential data not shown]", ctx->log_fp);
333
 
              else 
334
 
                _assuan_log_print_buffer (ctx->log_fp, 
335
 
                                          ctx->outbound.data.line,
336
 
                                          linelen);
337
 
              putc ('\n', ctx->log_fp);
338
 
            }
339
 
          *line++ = '\n';
340
 
          linelen++;
341
 
          if (writen (ctx->outbound.fd, ctx->outbound.data.line, linelen))
342
 
            {
343
 
              ctx->outbound.data.error = ASSUAN_Write_Error;
344
 
              return 0;
345
 
            }
346
 
          line = ctx->outbound.data.line;
347
 
          linelen = 0;
348
 
        }
349
 
    }
350
 
 
351
 
  ctx->outbound.data.linelen = linelen;
352
 
  return 0;
353
 
}
354
 
 
355
 
 
356
 
/* Write out any buffered data 
357
 
   This fucntion is used for GNU's custom streams */
358
 
int
359
 
_assuan_cookie_write_flush (void *cookie)
360
 
{
361
 
  ASSUAN_CONTEXT ctx = cookie;
362
 
  char *line;
363
 
  size_t linelen;
364
 
 
365
 
  if (ctx->outbound.data.error)
366
 
    return 0;
367
 
 
368
 
  line = ctx->outbound.data.line;
369
 
  linelen = ctx->outbound.data.linelen;
370
 
  line += linelen;
371
 
  if (linelen)
372
 
    {
373
 
      if (ctx->log_fp)
374
 
        {
375
 
          fprintf (ctx->log_fp, "%s[%p] -> ", my_log_prefix (), ctx); 
376
 
          if (ctx->confidential)
377
 
            fputs ("[Confidential data not shown]", ctx->log_fp);
378
 
          else
379
 
            _assuan_log_print_buffer (ctx->log_fp, 
380
 
                                      ctx->outbound.data.line,
381
 
                                      linelen);
382
 
          putc ('\n', ctx->log_fp);
383
 
            }
384
 
      *line++ = '\n';
385
 
      linelen++;
386
 
      if (writen (ctx->outbound.fd, ctx->outbound.data.line, linelen))
387
 
        {
388
 
          ctx->outbound.data.error = ASSUAN_Write_Error;
389
 
          return 0;
390
 
        }
391
 
      ctx->outbound.data.linelen = 0;
392
 
    }
393
 
  return 0;
394
 
}
395
 
 
396
 
 
397
 
/**
398
 
 * assuan_send_data:
399
 
 * @ctx: An assuan context
400
 
 * @buffer: Data to send or NULL to flush
401
 
 * @length: length of the data to send/
402
 
 * 
403
 
 * This function may be used by the server or the client to send data
404
 
 * lines.  The data will be escaped as required by the Assuan protocol
405
 
 * and may get buffered until a line is full.  To force sending the
406
 
 * data out @buffer may be passed as NULL (in which case @length must
407
 
 * also be 0); however when used by a client this flush operation does
408
 
 * also send the terminating "END" command to terminate the reponse on
409
 
 * a INQUIRE response.  However, when assuan_transact() is used, this
410
 
 * function takes care of sending END itself.
411
 
 * 
412
 
 * Return value: 0 on success or an error code
413
 
 **/
414
 
 
415
 
AssuanError
416
 
assuan_send_data (ASSUAN_CONTEXT ctx, const void *buffer, size_t length)
417
 
{
418
 
  if (!ctx)
419
 
    return ASSUAN_Invalid_Value;
420
 
  if (!buffer && length)
421
 
    return ASSUAN_Invalid_Value;
422
 
 
423
 
  if (!buffer)
424
 
    { /* flush what we have */
425
 
      _assuan_cookie_write_flush (ctx);
426
 
      if (ctx->outbound.data.error)
427
 
        return ctx->outbound.data.error;
428
 
      if (!ctx->is_server)
429
 
        return assuan_write_line (ctx, "END");
430
 
    }
431
 
  else
432
 
    {
433
 
      _assuan_cookie_write_data (ctx, buffer, length);
434
 
      if (ctx->outbound.data.error)
435
 
        return ctx->outbound.data.error;
436
 
    }
437
 
 
438
 
  return 0;
439
 
}
440
 
 
441
 
 
442
 
 
443