Example #1
0
/* Format is OUTPUT FD=<n> */
static gpg_error_t
std_handler_output (assuan_context_t ctx, char *line)
{
  gpg_error_t rc;
  assuan_fd_t fd, oldfd;

  rc = assuan_command_parse_fd (ctx, line, &fd);
  if (rc)
    return PROCESS_DONE (ctx, rc);

#ifdef HAVE_W32CE_SYSTEM
  oldfd = fd;
  fd = _assuan_w32ce_finish_pipe ((int)fd, 1);
  if (fd == INVALID_HANDLE_VALUE)
    return PROCESS_DONE (ctx, set_error (ctx, gpg_err_code_from_syserror (),
					 "rvid conversion failed"));
  TRACE2 (ctx, ASSUAN_LOG_SYSIO, "std_handler_output", ctx,
	  "turned RVID 0x%x into handle 0x%x", oldfd, fd);
#endif

  if (ctx->output_notify_fnc)
    {
      oldfd = ctx->output_fd;
      ctx->output_fd = fd;
      rc = ctx->output_notify_fnc (ctx, line);
      if (rc)
        ctx->output_fd = oldfd;
    }
  else if (!rc)
    ctx->output_fd = fd;
  return PROCESS_DONE (ctx, rc);
}
Example #2
0
/* Log the formatted string FORMAT at debug category CAT higher.  */
void
_assuan_debug (assuan_context_t ctx, unsigned int cat, const char *format, ...)
{
  va_list arg_ptr;
  int saved_errno;
  char *msg;
  int res;

  /* vasprintf is an expensive operation thus we first check whether
     the callback has enabled CAT for logging.  */
  if (!ctx
      || !ctx->log_cb
      || !(*ctx->log_cb) (ctx, ctx->log_cb_data, cat, NULL))
    return;

  saved_errno = errno;
  va_start (arg_ptr, format);
  res = gpgrt_vasprintf (&msg, format, arg_ptr);
  va_end (arg_ptr);
  if (res < 0)
    return;
  ctx->log_cb (ctx, ctx->log_cb_data, cat, msg);
  free (msg);
  gpg_err_set_errno (saved_errno);
}
Example #3
0
static gpg_error_t
std_handler_cancel (assuan_context_t ctx, char *line)
{
  if (ctx->cancel_notify_fnc)
    /* Return value ignored.  */
    ctx->cancel_notify_fnc (ctx, line);
  return PROCESS_DONE (ctx, set_error (ctx, GPG_ERR_NOT_IMPLEMENTED, NULL));
}
Example #4
0
/**
 * assuan_accept:
 * @ctx: context
 * 
 * Cancel any existing connection and wait for a connection from a
 * client.  The initial handshake is performed which may include an
 * initial authentication or encryption negotiation.
 * 
 * Return value: 0 on success or an error if the connection could for
 * some reason not be established.
 **/
assuan_error_t
assuan_accept (assuan_context_t ctx)
{
  int rc;
  const char *p, *pend;

  if (!ctx)
    return _assuan_error (ASSUAN_Invalid_Value);

  if (ctx->pipe_mode > 1)
    return -1; /* second invocation for pipemode -> terminate */
  ctx->finish_handler (ctx);

  rc = ctx->accept_handler (ctx);
  if (rc)
    return rc;

  /* Send the hello. */
  p = ctx->hello_line;
  if (p && (pend = strchr (p, '\n')))
    { /* This is a multi line hello.  Send all but the last line as
         comments. */
      do
        {
          rc = _assuan_write_line (ctx, "# ", p, pend - p);
          if (rc)
            return rc;
          p = pend + 1;
          pend = strchr (p, '\n');
        }
      while (pend);
      rc = _assuan_write_line (ctx, "OK ", p, strlen (p));
    }
  else if (p)
    rc = assuan_write_line (ctx, p);
  else
    rc = assuan_write_line (ctx, "OK Pleased to meet you");
  if (rc)
    return rc;
  
  if (ctx->pipe_mode)
    ctx->pipe_mode = 2;
  
  return 0;
}
Example #5
0
void
assuan_deinit_server(assuan_context_t ctx)
{
    if(ctx)
    {
        /* We use this function pointer to avoid linking other server
           when not needed but still allow for a generic deinit function.  */
        ctx->deinit_handler(ctx);
        ctx->deinit_handler = NULL;
        _assuan_release_context(ctx);
    }
}
Example #6
0
static gpg_error_t
std_handler_bye (assuan_context_t ctx, char *line)
{
  if (ctx->bye_notify_fnc)
    /* Return value ignored.  */
    ctx->bye_notify_fnc (ctx, line);
  assuan_close_input_fd (ctx);
  assuan_close_output_fd (ctx);
  /* pretty simple :-) */
  ctx->process_complete = 1;
  return PROCESS_DONE (ctx, 0);
}
Example #7
0
static gpg_error_t
std_handler_option (assuan_context_t ctx, char *line)
{
  char *key, *value, *p;

  for (key=line; spacep (key); key++)
    ;
  if (!*key)
    return
      PROCESS_DONE (ctx, set_error (ctx, GPG_ERR_ASS_SYNTAX, "argument required"));
  if (*key == '=')
    return
      PROCESS_DONE (ctx, set_error (ctx, GPG_ERR_ASS_SYNTAX,
				    "no option name given"));
  for (value=key; *value && !spacep (value) && *value != '='; value++)
    ;
  if (*value)
    {
      if (spacep (value))
        *value++ = 0; /* terminate key */
      for (; spacep (value); value++)
        ;
      if (*value == '=')
        {
          *value++ = 0; /* terminate key */
          for (; spacep (value); value++)
            ;
          if (!*value)
            return
	      PROCESS_DONE (ctx, set_error (ctx, GPG_ERR_ASS_SYNTAX,
					    "option argument expected"));
        }
      if (*value)
        {
          for (p = value + strlen(value) - 1; p > value && spacep (p); p--)
            ;
          if (p > value)
            *++p = 0; /* strip trailing spaces */
        }
    }

  if (*key == '-' && key[1] == '-' && key[2])
    key += 2; /* the double dashes are optional */
  if (*key == '-')
    return PROCESS_DONE (ctx,
			 set_error (ctx, GPG_ERR_ASS_SYNTAX,
				    "option should not begin with one dash"));

  if (ctx->option_handler_fnc)
    return PROCESS_DONE (ctx, ctx->option_handler_fnc (ctx, key, value));
  return PROCESS_DONE (ctx, 0);
}
Example #8
0
gpg_error_t
_assuan_write_line (assuan_context_t ctx, const char *prefix,
                    const char *line, size_t len)
{
  gpg_error_t rc = 0;
  size_t prefixlen = prefix? strlen (prefix):0;
  unsigned int monitor_result;

  /* Make sure that the line is short enough. */
  if (len + prefixlen + 2 > ASSUAN_LINELENGTH)
    {
      _assuan_log_control_channel (ctx, 1,
                                   "supplied line too long - truncated",
                                   NULL, 0, NULL, 0);
      if (prefixlen > 5)
        prefixlen = 5;
      if (len > ASSUAN_LINELENGTH - prefixlen - 2)
        len = ASSUAN_LINELENGTH - prefixlen - 2 - 1;
    }

  monitor_result = 0;
  if (ctx->io_monitor)
    monitor_result = ctx->io_monitor (ctx, ctx->io_monitor_data, 1, line, len);

  /* Fixme: we should do some kind of line buffering.  */
  if (!(monitor_result & ASSUAN_IO_MONITOR_NOLOG))
    _assuan_log_control_channel (ctx, 1, NULL,
                                 prefixlen? prefix:NULL, prefixlen,
                                 line, len);

  if (prefixlen && !(monitor_result & ASSUAN_IO_MONITOR_IGNORE))
    {
      rc = writen (ctx, prefix, prefixlen);
      if (rc)
	rc = _assuan_error (ctx, gpg_err_code_from_syserror ());
    }
  if (!rc && !(monitor_result & ASSUAN_IO_MONITOR_IGNORE))
    {
      rc = writen (ctx, line, len);
      if (rc)
	rc = _assuan_error (ctx, gpg_err_code_from_syserror ());
      if (!rc)
        {
          rc = writen (ctx, "\n", 1);
          if (rc)
	    rc = _assuan_error (ctx, gpg_err_code_from_syserror ());
        }
    }
  return rc;
}
Example #9
0
static gpg_error_t
std_handler_reset (assuan_context_t ctx, char *line)
{
  gpg_error_t err = 0;

  if (ctx->reset_notify_fnc)
    err = ctx->reset_notify_fnc (ctx, line);
  if (! err)
    {
      assuan_close_input_fd (ctx);
      assuan_close_output_fd (ctx);
      _assuan_uds_close_fds (ctx);
    }
  return PROCESS_DONE (ctx, err);
}
Example #10
0
/* Read a line with buffering of partial lines.  Function returns an
   Assuan error.  */
gpg_error_t
_assuan_read_line (assuan_context_t ctx)
{
  gpg_error_t rc = 0;
  char *line = ctx->inbound.line;
  int nread, atticlen;
  char *endp = 0;

  if (ctx->inbound.eof)
    return _assuan_error (ctx, GPG_ERR_EOF);

  atticlen = ctx->inbound.attic.linelen;
  if (atticlen)
    {
      memcpy (line, ctx->inbound.attic.line, atticlen);
      ctx->inbound.attic.linelen = 0;

      endp = memchr (line, '\n', atticlen);
      if (endp)
	{
	  /* Found another line in the attic.  */
	  nread = atticlen;
	  atticlen = 0;
	}
      else
        {
	  /* There is pending data but not a full line.  */
          assert (atticlen < LINELENGTH);
          rc = readline (ctx, line + atticlen,
			 LINELENGTH - atticlen, &nread, &ctx->inbound.eof);
        }
    }
  else
    /* No pending data.  */
    rc = readline (ctx, line, LINELENGTH,
                   &nread, &ctx->inbound.eof);
  if (rc)
    {
      int saved_errno = errno;
      char buf[100];

      snprintf (buf, sizeof buf, "error: %s", strerror (errno));
      _assuan_log_control_channel (ctx, 0, buf, NULL, 0, NULL, 0);

      if (saved_errno == EAGAIN)
        {
          /* We have to save a partial line.  Due to readline's
	     behaviour, we know that this is not a complete line yet
	     (no newline).  So we don't set PENDING to true.  */
          memcpy (ctx->inbound.attic.line, line, atticlen + nread);
          ctx->inbound.attic.pending = 0;
          ctx->inbound.attic.linelen = atticlen + nread;
        }

      gpg_err_set_errno (saved_errno);
      return _assuan_error (ctx, gpg_err_code_from_syserror ());
    }
  if (!nread)
    {
      assert (ctx->inbound.eof);
      _assuan_log_control_channel (ctx, 0, "eof", NULL, 0, NULL, 0);
      return _assuan_error (ctx, GPG_ERR_EOF);
    }

  ctx->inbound.attic.pending = 0;
  nread += atticlen;

  if (! endp)
    endp = memchr (line, '\n', nread);

  if (endp)
    {
      unsigned monitor_result;
      int n = endp - line + 1;

      if (n < nread)
	/* LINE contains more than one line.  We copy it to the attic
	   now as handlers are allowed to modify the passed
	   buffer.  */
	{
	  int len = nread - n;
	  memcpy (ctx->inbound.attic.line, endp + 1, len);
	  ctx->inbound.attic.pending = memrchr (endp + 1, '\n', len) ? 1 : 0;
	  ctx->inbound.attic.linelen = len;
	}

      if (endp != line && endp[-1] == '\r')
	endp --;
      *endp = 0;

      ctx->inbound.linelen = endp - line;

      monitor_result = 0;
      if (ctx->io_monitor)
	monitor_result = ctx->io_monitor (ctx, ctx->io_monitor_data, 0,
					  ctx->inbound.line,
					  ctx->inbound.linelen);
      if (monitor_result & ASSUAN_IO_MONITOR_IGNORE)
        ctx->inbound.linelen = 0;

      if ( !(monitor_result & ASSUAN_IO_MONITOR_NOLOG))
        _assuan_log_control_channel (ctx, 0, NULL,
                                     ctx->inbound.line, ctx->inbound.linelen,
                                     NULL, 0);
      return 0;
    }
  else
    {
      _assuan_log_control_channel (ctx, 0, "invalid line",
                                   NULL, 0, NULL, 0);
      *line = 0;
      ctx->inbound.linelen = 0;
      return _assuan_error (ctx, ctx->inbound.eof
			    ? GPG_ERR_ASS_INCOMPLETE_LINE
			    : GPG_ERR_ASS_LINE_TOO_LONG);
    }
}
Example #11
0
/* Call this to acknowledge the current command.  */
gpg_error_t
assuan_process_done (assuan_context_t ctx, gpg_error_t rc)
{
  if (!ctx->in_command)
    return _assuan_error (ctx, GPG_ERR_ASS_GENERAL);

  ctx->in_command = 0;

  /* Check for data write errors.  */
  if (ctx->outbound.data.fp)
    {
      /* Flush the data lines.  */
      fclose (ctx->outbound.data.fp);
      ctx->outbound.data.fp = NULL;
      if (!rc && ctx->outbound.data.error)
	rc = ctx->outbound.data.error;
    }
  else
    {
      /* Flush any data send without using the data FP.  */
      assuan_send_data (ctx, NULL, 0);
      if (!rc && ctx->outbound.data.error)
	rc = ctx->outbound.data.error;
    }

  /* Error handling.  */
  if (!rc)
    {
      if (ctx->process_complete)
	{
	  /* No error checking because the peer may have already
	     disconnect. */
	  assuan_write_line (ctx, "OK closing connection");
	  ctx->finish_handler (ctx);
	}
      else
	rc = assuan_write_line (ctx, ctx->okay_line ? ctx->okay_line : "OK");
    }
  else
    {
      char errline[300];
      const char *text = ctx->err_no == rc ? ctx->err_str : NULL;
      char ebuf[50];

      gpg_strerror_r (rc, ebuf, sizeof (ebuf));
      sprintf (errline, "ERR %d %.50s <%.30s>%s%.100s",
	       rc, ebuf, gpg_strsource (rc),
	       text? " - ":"", text?text:"");

      rc = assuan_write_line (ctx, errline);
    }

  if (ctx->post_cmd_notify_fnc)
    ctx->post_cmd_notify_fnc (ctx, rc);

  ctx->flags.confidential = 0;
  if (ctx->okay_line)
    {
      _assuan_free (ctx, ctx->okay_line);
      ctx->okay_line = NULL;
    }

  return rc;
}
Example #12
0
/* Parse the line, break out the command, find it in the command
   table, remove leading and white spaces from the arguments, call the
   handler with the argument line and return the error.  */
static gpg_error_t
dispatch_command (assuan_context_t ctx, char *line, int linelen)
{
  gpg_error_t err;
  char *p;
  const char *s;
  int shift, i;

  /* Note that as this function is invoked by assuan_process_next as
     well, we need to hide non-critical errors with PROCESS_DONE.  */

  if (*line == 'D' && line[1] == ' ') /* divert to special handler */
    /* FIXME: Depending on the final implementation of
       handle_data_line, this may be wrong here.  For example, if a
       user callback is invoked, and that callback is responsible for
       calling assuan_process_done, then this is wrong.  */
    return PROCESS_DONE (ctx, handle_data_line (ctx, line+2, linelen-2));

  for (p=line; *p && *p != ' ' && *p != '\t'; p++)
    ;
  if (p==line)
    return PROCESS_DONE
      (ctx, set_error (ctx, GPG_ERR_ASS_SYNTAX, "leading white-space"));
  if (*p)
    { /* Skip over leading WS after the keyword */
      *p++ = 0;
      while ( *p == ' ' || *p == '\t')
        p++;
    }
  shift = p - line;

  for (i=0; (s=ctx->cmdtbl[i].name); i++)
    {
      if (!strcmp (line, s))
        break;
    }
  if (!s)
    { /* and try case insensitive */
      for (i=0; (s=ctx->cmdtbl[i].name); i++)
        {
          if (!my_strcasecmp (line, s))
            break;
        }
    }
  if (!s)
    return PROCESS_DONE (ctx, set_error (ctx, GPG_ERR_ASS_UNKNOWN_CMD, NULL));
  line += shift;
  linelen -= shift;

  if (ctx->pre_cmd_notify_fnc) {
    err = ctx->pre_cmd_notify_fnc(ctx, ctx->cmdtbl[i].name);

    if (err)
      return PROCESS_DONE(ctx, err);
  }

/*    fprintf (stderr, "DBG-assuan: processing %s `%s'\n", s, line); */
  ctx->current_cmd_name = ctx->cmdtbl[i].name;
  err = ctx->cmdtbl[i].handler (ctx, line);
  ctx->current_cmd_name = NULL;
  return err;
}
Example #13
0
/* Function returns an Assuan error. */
assuan_error_t
_assuan_read_line(assuan_context_t ctx)
{
    char *line = ctx->inbound.line;
    int nread, atticlen;
    int rc;
    char *endp = 0;

    if(ctx->inbound.eof)
        return _assuan_error(-1);

    atticlen = ctx->inbound.attic.linelen;
    if(atticlen)
    {
        memcpy(line, ctx->inbound.attic.line, atticlen);
        ctx->inbound.attic.linelen = 0;

        endp = memchr(line, '\n', atticlen);
        if(endp)
            /* Found another line in the attic.  */
        {
            rc = 0;
            nread = atticlen;
            atticlen = 0;
        }
        else
            /* There is pending data but not a full line.  */
        {
            assert(atticlen < LINELENGTH);
            rc = readline(ctx, line + atticlen,
                          LINELENGTH - atticlen, &nread, &ctx->inbound.eof);
        }
    }
    else
        /* No pending data.  */
        rc = readline(ctx, line, LINELENGTH,
                      &nread, &ctx->inbound.eof);
    if(rc)
    {
        if(ctx->log_fp)
            fprintf(ctx->log_fp, "%s[%u.%d] DBG: <- [Error: %s]\n",
                    assuan_get_assuan_log_prefix(),
                    (unsigned int)getpid(), ctx->inbound.fd,
                    strerror(errno));
        return _assuan_error(ASSUAN_Read_Error);
    }
    if(!nread)
    {
        assert(ctx->inbound.eof);
        if(ctx->log_fp)
            fprintf(ctx->log_fp, "%s[%u.%d] DBG: <- [EOF]\n",
                    assuan_get_assuan_log_prefix(),
                    (unsigned int)getpid(), ctx->inbound.fd);
        return _assuan_error(-1);
    }

    ctx->inbound.attic.pending = 0;
    nread += atticlen;

    if(! endp)
        endp = memchr(line, '\n', nread);

    if(endp)
    {
        unsigned monitor_result;
        int n = endp - line + 1;

        if(n < nread)
            /* LINE contains more than one line.  We copy it to the attic
               now as handlers are allowed to modify the passed
               buffer.  */
        {
            int len = nread - n;
            memcpy(ctx->inbound.attic.line, endp + 1, len);
            ctx->inbound.attic.pending = memrchr(endp + 1, '\n', len) ? 1 : 0;
            ctx->inbound.attic.linelen = len;
        }

        if(endp != line && endp[-1] == '\r')
            endp --;
        *endp = 0;

        ctx->inbound.linelen = endp - line;

        monitor_result = (ctx->io_monitor
                          ? ctx->io_monitor(ctx, 0,
                                            ctx->inbound.line,
                                            ctx->inbound.linelen)
                          : 0);
        if((monitor_result & 2))
            ctx->inbound.linelen = 0;

        if(ctx->log_fp && !(monitor_result & 1))
        {
            fprintf(ctx->log_fp, "%s[%u.%d] DBG: <- ",
                    assuan_get_assuan_log_prefix(),
                    (unsigned int)getpid(), ctx->inbound.fd);
            if(ctx->confidential)
                fputs("[Confidential data not shown]", ctx->log_fp);
            else
                _assuan_log_print_buffer(ctx->log_fp,
                                         ctx->inbound.line,
                                         ctx->inbound.linelen);
            putc('\n', ctx->log_fp);
        }
        return 0;
    }
    else
    {
        if(ctx->log_fp)
            fprintf(ctx->log_fp, "%s[%u.%d] DBG: <- [Invalid line]\n",
                    assuan_get_assuan_log_prefix(),
                    (unsigned int)getpid(), ctx->inbound.fd);
        *line = 0;
        ctx->inbound.linelen = 0;
        return _assuan_error(ctx->inbound.eof
                             ? ASSUAN_Line_Not_Terminated
                             : ASSUAN_Line_Too_Long);
    }
}
Example #14
0
assuan_error_t
_assuan_write_line(assuan_context_t ctx, const char *prefix,
                   const char *line, size_t len)
{
    assuan_error_t rc = 0;
    size_t prefixlen = prefix ? strlen(prefix) : 0;
    unsigned int monitor_result;

    /* Make sure that the line is short enough. */
    if(len + prefixlen + 2 > ASSUAN_LINELENGTH)
    {
        if(ctx->log_fp)
            fprintf(ctx->log_fp, "%s[%u.%d] DBG: -> "
                    "[supplied line too long -truncated]\n",
                    assuan_get_assuan_log_prefix(),
                    (unsigned int)getpid(), ctx->inbound.fd);
        if(prefixlen > 5)
            prefixlen = 5;
        if(len > ASSUAN_LINELENGTH - prefixlen - 2)
            len = ASSUAN_LINELENGTH - prefixlen - 2 - 1;
    }

    monitor_result = (ctx->io_monitor
                      ? ctx->io_monitor(ctx, 1, line, len)
                      : 0);

    /* Fixme: we should do some kind of line buffering.  */
    if(ctx->log_fp && !(monitor_result & 1))
    {
        fprintf(ctx->log_fp, "%s[%u.%d] DBG: -> ",
                assuan_get_assuan_log_prefix(),
                (unsigned int)getpid(), ctx->inbound.fd);
        if(ctx->confidential)
            fputs("[Confidential data not shown]", ctx->log_fp);
        else
        {
            if(prefixlen)
                _assuan_log_print_buffer(ctx->log_fp, prefix, prefixlen);
            _assuan_log_print_buffer(ctx->log_fp, line, len);
        }
        putc('\n', ctx->log_fp);
    }

    if(prefixlen && !(monitor_result & 2))
    {
        rc = writen(ctx, prefix, prefixlen);
        if(rc)
            rc = _assuan_error(ASSUAN_Write_Error);
    }
    if(!rc && !(monitor_result & 2))
    {
        rc = writen(ctx, line, len);
        if(rc)
            rc = _assuan_error(ASSUAN_Write_Error);
        if(!rc)
        {
            rc = writen(ctx, "\n", 1);
            if(rc)
                rc = _assuan_error(ASSUAN_Write_Error);
        }
    }
    return rc;
}