libassuan: fix for commit 386e7ee when using a local pinentry.
[libpwmd.git] / assuan / assuan-buffer.c
blobe0acfb63317f26ead8cb3a2db6b9bfb8e7f7d740
1 /* assuan-buffer.c - read and send data
2 * Copyright (C) 2001, 2002, 2003, 2004, 2006 Free Software Foundation, Inc.
4 * This file is part of Assuan.
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.
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.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this program; if not, see <http://www.gnu.org/licenses/>.
20 #include <config.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <stdio.h>
24 #include <errno.h>
25 #include <unistd.h>
26 #include <assert.h>
27 #ifdef HAVE_W32_SYSTEM
28 #include <process.h>
29 #endif
30 #include "assuan-defs.h"
33 /* Extended version of write(2) to guarantee that all bytes are
34 written. Returns 0 on success or -1 and ERRNO on failure. */
35 static int
36 writen (assuan_context_t ctx, const char *buffer, size_t length)
38 while (length)
40 ssize_t nwritten = ctx->io->writefnc (ctx, buffer, length);
42 if (nwritten < 0)
44 if (errno == EINTR)
45 continue;
46 return -1; /* write error */
48 length -= nwritten;
49 buffer += nwritten;
51 return 0; /* okay */
54 /* Read an entire line. Returns 0 on success or -1 and ERRNO on
55 failure. EOF is indictated by setting the integer at address
56 R_EOF. Note: BUF, R_NREAD and R_EOF contain a valid result even if
57 an error is returned. */
58 static int
59 readline (assuan_context_t ctx, char *buf, size_t buflen,
60 int *r_nread, int *r_eof)
62 size_t nleft = buflen;
63 char *p;
65 *r_eof = 0;
66 *r_nread = 0;
67 while (nleft > 0)
69 ssize_t n = ctx->io->readfnc (ctx, buf, nleft);
71 if (n < 0)
73 if (errno == EINTR)
74 continue;
75 return -1; /* read error */
77 else if (!n)
79 *r_eof = 1;
80 break; /* allow incomplete lines */
82 p = buf;
83 nleft -= n;
84 buf += n;
85 *r_nread += n;
87 p = memrchr (p, '\n', n);
88 if (p)
89 break; /* at least one full line available - that's enough for now */
92 return 0;
96 /* Function returns an Assuan error. */
97 assuan_error_t
98 _assuan_read_line (assuan_context_t ctx)
100 char *line = ctx->inbound.line;
101 int nread, atticlen;
102 int rc;
103 char *endp = 0;
105 if (ctx->inbound.eof)
106 return _assuan_error (-1);
108 atticlen = ctx->inbound.attic.linelen;
109 if (atticlen)
111 memcpy (line, ctx->inbound.attic.line, atticlen);
112 ctx->inbound.attic.linelen = 0;
114 endp = memchr (line, '\n', atticlen);
115 if (endp)
116 /* Found another line in the attic. */
118 rc = 0;
119 nread = atticlen;
120 atticlen = 0;
122 else
123 /* There is pending data but not a full line. */
125 assert (atticlen < LINELENGTH);
126 rc = readline (ctx, line + atticlen,
127 LINELENGTH - atticlen, &nread, &ctx->inbound.eof);
130 else
131 /* No pending data. */
132 rc = readline (ctx, line, LINELENGTH,
133 &nread, &ctx->inbound.eof);
134 if (rc)
136 int saved_errno = errno;
138 if (ctx->log_fp)
139 fprintf (ctx->log_fp, "%s[%u.%d] DBG: <- [Error: %s]\n",
140 assuan_get_assuan_log_prefix (),
141 (unsigned int)getpid (), (int)ctx->inbound.fd,
142 strerror (errno));
144 if (saved_errno == EAGAIN)
146 /* We have to save a partial line. */
147 memcpy (ctx->inbound.attic.line, line, atticlen + nread);
148 ctx->inbound.attic.pending = 0;
149 ctx->inbound.attic.linelen = atticlen + nread;
152 errno = saved_errno;
153 return _assuan_error (ASSUAN_Read_Error);
155 if (!nread)
157 assert (ctx->inbound.eof);
158 if (ctx->log_fp)
159 fprintf (ctx->log_fp, "%s[%u.%d] DBG: <- [EOF]\n",
160 assuan_get_assuan_log_prefix (),
161 (unsigned int)getpid (), (int)ctx->inbound.fd);
162 return _assuan_error (-1);
165 ctx->inbound.attic.pending = 0;
166 nread += atticlen;
168 if (! endp)
169 endp = memchr (line, '\n', nread);
171 if (endp)
173 unsigned monitor_result;
174 int n = endp - line + 1;
176 if (n < nread)
177 /* LINE contains more than one line. We copy it to the attic
178 now as handlers are allowed to modify the passed
179 buffer. */
181 int len = nread - n;
182 memcpy (ctx->inbound.attic.line, endp + 1, len);
183 ctx->inbound.attic.pending = memrchr (endp + 1, '\n', len) ? 1 : 0;
184 ctx->inbound.attic.linelen = len;
187 if (endp != line && endp[-1] == '\r')
188 endp --;
189 *endp = 0;
191 ctx->inbound.linelen = endp - line;
193 monitor_result = (ctx->io_monitor
194 ? ctx->io_monitor (ctx, 0,
195 ctx->inbound.line,
196 ctx->inbound.linelen)
197 : 0);
198 if ( (monitor_result & 2) )
199 ctx->inbound.linelen = 0;
201 if (ctx->log_fp && !(monitor_result & 1))
203 fprintf (ctx->log_fp, "%s[%u.%d] DBG: <- ",
204 assuan_get_assuan_log_prefix (),
205 (unsigned int)getpid (), (int)ctx->inbound.fd);
206 if (ctx->confidential)
207 fputs ("[Confidential data not shown]", ctx->log_fp);
208 else
209 _assuan_log_print_buffer (ctx->log_fp,
210 ctx->inbound.line,
211 ctx->inbound.linelen);
212 putc ('\n', ctx->log_fp);
214 return 0;
216 else
218 if (ctx->log_fp)
219 fprintf (ctx->log_fp, "%s[%u.%d] DBG: <- [Invalid line]\n",
220 assuan_get_assuan_log_prefix (),
221 (unsigned int)getpid (), (int)ctx->inbound.fd);
222 *line = 0;
223 ctx->inbound.linelen = 0;
224 return _assuan_error (ctx->inbound.eof
225 ? ASSUAN_Line_Not_Terminated
226 : ASSUAN_Line_Too_Long);
231 /* Read the next line from the client or server and return a pointer
232 in *LINE to a buffer holding the line. LINELEN is the length of
233 *LINE. The buffer is valid until the next read operation on it.
234 The caller may modify the buffer. The buffer is invalid (i.e. must
235 not be used) if an error is returned.
237 Returns 0 on success or an assuan error code.
238 See also: assuan_pending_line().
240 assuan_error_t
241 assuan_read_line (assuan_context_t ctx, char **line, size_t *linelen)
243 assuan_error_t err;
245 if (!ctx)
246 return _assuan_error (ASSUAN_Invalid_Value);
250 err = _assuan_read_line (ctx);
252 while (!ctx->in_inquire && _assuan_error_is_eagain (err));
254 *line = ctx->inbound.line;
255 *linelen = ctx->inbound.linelen;
256 return err;
260 /* Return true if a full line is buffered (i.e. an entire line may be
261 read without any I/O). */
263 assuan_pending_line (assuan_context_t ctx)
265 return ctx && ctx->inbound.attic.pending;
269 assuan_error_t
270 _assuan_write_line (assuan_context_t ctx, const char *prefix,
271 const char *line, size_t len)
273 assuan_error_t rc = 0;
274 size_t prefixlen = prefix? strlen (prefix):0;
275 unsigned int monitor_result;
277 /* Make sure that the line is short enough. */
278 if (len + prefixlen + 2 > ASSUAN_LINELENGTH)
280 if (ctx->log_fp)
281 fprintf (ctx->log_fp, "%s[%u.%d] DBG: -> "
282 "[supplied line too long -truncated]\n",
283 assuan_get_assuan_log_prefix (),
284 (unsigned int)getpid (), (int)ctx->inbound.fd);
285 if (prefixlen > 5)
286 prefixlen = 5;
287 if (len > ASSUAN_LINELENGTH - prefixlen - 2)
288 len = ASSUAN_LINELENGTH - prefixlen - 2 - 1;
291 monitor_result = (ctx->io_monitor
292 ? ctx->io_monitor (ctx, 1, line, len)
293 : 0);
295 /* Fixme: we should do some kind of line buffering. */
296 if (ctx->log_fp && !(monitor_result & 1))
298 fprintf (ctx->log_fp, "%s[%u.%d] DBG: -> ",
299 assuan_get_assuan_log_prefix (),
300 (unsigned int)getpid (), (int)ctx->inbound.fd);
301 if (ctx->confidential)
302 fputs ("[Confidential data not shown]", ctx->log_fp);
303 else
305 if (prefixlen)
306 _assuan_log_print_buffer (ctx->log_fp, prefix, prefixlen);
307 _assuan_log_print_buffer (ctx->log_fp, line, len);
309 putc ('\n', ctx->log_fp);
312 if (prefixlen && !(monitor_result & 2))
314 rc = writen (ctx, prefix, prefixlen);
315 if (rc)
316 rc = _assuan_error (ASSUAN_Write_Error);
318 if (!rc && !(monitor_result & 2))
320 rc = writen (ctx, line, len);
321 if (rc)
322 rc = _assuan_error (ASSUAN_Write_Error);
323 if (!rc)
325 rc = writen (ctx, "\n", 1);
326 if (rc)
327 rc = _assuan_error (ASSUAN_Write_Error);
330 return rc;
334 assuan_error_t
335 assuan_write_line (assuan_context_t ctx, const char *line)
337 size_t len;
338 const char *s;
340 if (!ctx)
341 return _assuan_error (ASSUAN_Invalid_Value);
343 /* Make sure that we never take a LF from the user - this might
344 violate the protocol. */
345 s = strchr (line, '\n');
346 len = s? (s-line) : strlen (line);
348 if (ctx->log_fp && s)
349 fprintf (ctx->log_fp, "%s[%u.%d] DBG: -> "
350 "[supplied line contained a LF - truncated]\n",
351 assuan_get_assuan_log_prefix (),
352 (unsigned int)getpid (), (int)ctx->inbound.fd);
354 return _assuan_write_line (ctx, NULL, line, len);
359 /* Write out the data in buffer as datalines with line wrapping and
360 percent escaping. This function is used for GNU's custom streams. */
362 _assuan_cookie_write_data (void *cookie, const char *buffer, size_t orig_size)
364 assuan_context_t ctx = cookie;
365 size_t size = orig_size;
366 char *line;
367 size_t linelen;
369 if (ctx->outbound.data.error) {
370 if (_assuan_error_is_eagain(ctx->outbound.data.error))
371 ctx->outbound.data.error = 0;
372 else
373 return 0;
376 line = ctx->outbound.data.line;
377 linelen = ctx->outbound.data.linelen;
378 line += linelen;
379 while (size)
381 unsigned int monitor_result;
383 /* Insert data line header. */
384 if (!linelen)
386 *line++ = 'D';
387 *line++ = ' ';
388 linelen += 2;
391 /* Copy data, keep space for the CRLF and to escape one character. */
392 while (size && linelen < LINELENGTH-2-2)
394 if (*buffer == '%' || *buffer == '\r' || *buffer == '\n')
396 sprintf (line, "%%%02X", *(unsigned char*)buffer);
397 line += 3;
398 linelen += 3;
399 buffer++;
401 else
403 *line++ = *buffer++;
404 linelen++;
406 size--;
410 monitor_result = (ctx->io_monitor
411 ? ctx->io_monitor (ctx, 1,
412 ctx->outbound.data.line, linelen)
413 : 0);
415 if (linelen >= LINELENGTH-2-2)
417 if (ctx->log_fp && !(monitor_result & 1))
419 fprintf (ctx->log_fp, "%s[%u.%d] DBG: -> ",
420 assuan_get_assuan_log_prefix (),
421 (unsigned int)getpid (), (int)ctx->inbound.fd);
423 if (ctx->confidential)
424 fputs ("[Confidential data not shown]", ctx->log_fp);
425 else
426 _assuan_log_print_buffer (ctx->log_fp,
427 ctx->outbound.data.line,
428 linelen);
429 putc ('\n', ctx->log_fp);
431 *line++ = '\n';
432 linelen++;
433 if ( !(monitor_result & 2)
434 && writen (ctx, ctx->outbound.data.line, linelen))
436 ctx->outbound.data.error = _assuan_error (ASSUAN_Write_Error);
437 return 0;
439 line = ctx->outbound.data.line;
440 linelen = 0;
444 ctx->outbound.data.linelen = linelen;
445 return (int)orig_size;
449 /* Write out any buffered data
450 This function is used for GNU's custom streams */
452 _assuan_cookie_write_flush (void *cookie)
454 assuan_context_t ctx = cookie;
455 char *line;
456 size_t linelen;
457 unsigned int monitor_result;
459 if (ctx->outbound.data.error)
460 return 0;
462 line = ctx->outbound.data.line;
463 linelen = ctx->outbound.data.linelen;
464 line += linelen;
466 monitor_result = (ctx->io_monitor
467 ? ctx->io_monitor (ctx, 1,
468 ctx->outbound.data.line, linelen)
469 : 0);
471 if (linelen)
473 if (ctx->log_fp && !(monitor_result & 1))
475 fprintf (ctx->log_fp, "%s[%u.%d] DBG: -> ",
476 assuan_get_assuan_log_prefix (),
477 (unsigned int)getpid (), (int)ctx->inbound.fd);
478 if (ctx->confidential)
479 fputs ("[Confidential data not shown]", ctx->log_fp);
480 else
481 _assuan_log_print_buffer (ctx->log_fp,
482 ctx->outbound.data.line, linelen);
483 putc ('\n', ctx->log_fp);
485 *line++ = '\n';
486 linelen++;
487 if ( !(monitor_result & 2)
488 && writen (ctx, ctx->outbound.data.line, linelen))
490 ctx->outbound.data.error = _assuan_error (ASSUAN_Write_Error);
491 return 0;
493 ctx->outbound.data.linelen = 0;
495 return 0;
500 * assuan_send_data:
501 * @ctx: An assuan context
502 * @buffer: Data to send or NULL to flush
503 * @length: length of the data to send/
505 * This function may be used by the server or the client to send data
506 * lines. The data will be escaped as required by the Assuan protocol
507 * and may get buffered until a line is full. To force sending the
508 * data out @buffer may be passed as NULL (in which case @length must
509 * also be 0); however when used by a client this flush operation does
510 * also send the terminating "END" command to terminate the reponse on
511 * a INQUIRE response. However, when assuan_transact() is used, this
512 * function takes care of sending END itself.
514 * Return value: 0 on success or an error code
517 assuan_error_t
518 assuan_send_data (assuan_context_t ctx, const void *buffer, size_t length)
520 if (!ctx)
521 return _assuan_error (ASSUAN_Invalid_Value);
522 if (!buffer && length)
523 return _assuan_error (ASSUAN_Invalid_Value);
525 if (!buffer)
526 { /* flush what we have */
527 _assuan_cookie_write_flush (ctx);
528 if (ctx->outbound.data.error)
529 return ctx->outbound.data.error;
530 if (!ctx->is_server)
531 return assuan_write_line (ctx, "END");
533 else
535 _assuan_cookie_write_data (ctx, buffer, length);
536 if (ctx->outbound.data.error)
537 return ctx->outbound.data.error;
540 return 0;
543 assuan_error_t
544 assuan_sendfd (assuan_context_t ctx, assuan_fd_t fd)
546 /* It is explicitly allowed to use (NULL, -1) as a runtime test to
547 check whether descriptor passing is available. */
548 if (!ctx && fd == ASSUAN_INVALID_FD)
549 #ifdef USE_DESCRIPTOR_PASSING
550 return 0;
551 #else
552 return _assuan_error (ASSUAN_Not_Implemented);
553 #endif
555 if (! ctx->io->sendfd)
556 return set_error (ctx, Not_Implemented,
557 "server does not support sending and receiving "
558 "of file descriptors");
559 return ctx->io->sendfd (ctx, fd);
562 assuan_error_t
563 assuan_receivefd (assuan_context_t ctx, assuan_fd_t *fd)
565 if (! ctx->io->receivefd)
566 return set_error (ctx, Not_Implemented,
567 "server does not support sending and receiving "
568 "of file descriptors");
569 return ctx->io->receivefd (ctx, fd);