Exemplo n.º 1
0
static Boolean avl_ranges_init(SshADTContainer c)
{
  if (!avl_init(c, ssh_malloc(sizeof(SshADTRangesCRootStruct))))
    return FALSE;

  if ((RROOT(c)->merge_additions = ssh_buffer_allocate()) == NULL ||
      (RROOT(c)->merge_deletions = ssh_buffer_allocate()) == NULL)
    return FALSE;

  return TRUE;
}
Exemplo n.º 2
0
SshBuffer
ssh_eap_create_request(SshEap eap, SshUInt16 len, SshUInt8 type)
{
  SshBuffer pkt;

  pkt = ssh_buffer_allocate();

  if (pkt == NULL)
    return NULL;

  eap->id++; /* Increment identifier here,
                making "each packet" unique */

  if (!ssh_eap_packet_build_hdr_with_type(pkt,
					  SSH_EAP_CODE_REQUEST,
					  eap->id,
					  len,
					  type))
    {
      ssh_buffer_free(pkt);
      return NULL;
    }


  return pkt;
}
Exemplo n.º 3
0
void copy_data_test(SshStream s1, SshStream s2)
{
  ts1 = s1;
  ts2 = s2;

  create_testdata();
  if (received_data)
    ssh_buffer_clear(received_data);
  else
    received_data = ssh_buffer_allocate();
  test_data_index = 0;
  destroy_count = 0;
  reader_sent_eof = FALSE;

  ssh_stream_set_callback(s1, copy_writer, NULL);
  ssh_stream_set_callback(s2, copy_reader, NULL);

  ssh_event_loop_run();
  if (destroy_count != 2 || ts1 != NULL || ts2 != NULL)
    ssh_fatal("copy_data_test: one stream not destroyed");
  if (ssh_buffer_len(received_data) > ssh_buffer_len(testdata))
    ssh_fatal("copy_data_test: received more data than sent");
  if (break_test)
    ssh_buffer_consume_end(testdata,
                           ssh_buffer_len(testdata)
                           - ssh_buffer_len(received_data));
  if (ssh_buffer_len(testdata) != ssh_buffer_len(received_data))
    ssh_fatal("copy_data_test: data lens differ");
  if (memcmp(ssh_buffer_ptr(testdata), ssh_buffer_ptr(received_data),
             ssh_buffer_len(testdata)) != 0)
    ssh_fatal("copy_data_test: received data differs");
}
Exemplo n.º 4
0
SshBuffer
ssh_eap_create_reply(SshEap eap, SshUInt16 len, SshUInt8 type)
{
  SshBuffer pkt;

  SSH_PRECOND(eap != NULL);

  pkt = ssh_buffer_allocate();

  if (pkt == NULL)
    return NULL;

  SSH_ASSERT(eap->id_isinit == 1);

  if (!ssh_eap_packet_build_hdr_with_type(pkt,
					  SSH_EAP_CODE_REPLY,
					  eap->id,
					  len,
					  type))
    {
      ssh_buffer_free(pkt);
      return NULL;
    }
  return pkt;
}
Exemplo n.º 5
0
static void
pkix_http_receive_data_operate(SshHttpClientContext ctx,
                               SshHttpResult result,
                               SshTcpError ip_error,
                               SshStream stream,
                               void *context)
{
  PkixHttpReadContext c = (PkixHttpReadContext)ssh_malloc(sizeof(*c));
  SshFSMThread thread = (SshFSMThread)context;
  SshPkiThreadData tdata = ssh_fsm_get_tdata(thread);
  SshPkiGlobalData gdata = ssh_fsm_get_gdata(thread);

  tdata->transport_op = NULL;
  if (c && result == SSH_HTTP_RESULT_SUCCESS)
    {
      c->http_stream = stream;
      c->upper_context = context;
      if ((c->input = ssh_buffer_allocate()) != NULL)
        {
          ssh_stream_set_callback(stream,
                                  pkix_http_stream_callback, (void *)c);
          pkix_http_stream_callback(SSH_STREAM_INPUT_AVAILABLE, (void *)c);
          return;
        }
    }
  ssh_free(c);
  tdata->input_type = SSH_PKI_MSG_ERRORREP;
  tdata->input_len = 1;
  ssh_fsm_continue(gdata->input_thread);
}
Exemplo n.º 6
0
Arquivo: t-tr.c Projeto: AnthraX1/rk
SshBuffer *handler_input_cross(Handler c)
{
  int len;
  unsigned char *cp;
  SshBuffer *packet;
  
  packet = c->incoming;
  if (packet == NULL)
    {
      /* No partial packet already received; initialize for receiving packet
         header. */
      packet = ssh_buffer_allocate();
      c->incoming = packet;
      c->incoming_offset = 0;
      c->incoming_len = 4;
      ssh_buffer_append_space(packet, &cp, c->incoming_len);
    }

keep_reading:
  /* Keep reading until either entire header or entire packet received
     (determined by incoming_len).  Space has already been allocated
     in the buffer. */
  while (c->incoming_offset < c->incoming_len)
    {
      len = c->incoming_len - c->incoming_offset;
      cp = ssh_buffer_ptr(packet);
      cp += c->incoming_offset;
      len = ssh_stream_read(c->stream, cp, len);
      if (len < 0)
        return NULL;
      if (len == 0)
        ssh_fatal("%s: handler_input_cross: received unexpected eof", c->side);
      c->incoming_offset += len;
    }

  /* If this was the header received, read the rest of the packet if there
     is non-zero length payload. */
  if (c->incoming_len == 4 && c->incoming_offset == 4)
    {
      cp = ssh_buffer_ptr(packet);
      c->incoming_len = 4 + SSH_GET_32BIT(cp);
      if (c->incoming_len > 4)
        {
          ssh_buffer_append_space(packet, &cp, c->incoming_len - 4);
          goto keep_reading;
        }
    }

  /* The entire packet has been received.  Return it. */
  c->incoming = NULL;
  cp = ssh_buffer_ptr(packet);

  return packet;
}
Exemplo n.º 7
0
static Boolean
catch_handler(SshHttpServerContext ctx, SshHttpServerConnection conn,
              SshStream stream, void *context)
{
  SshBuffer data = ssh_buffer_allocate();

  ssh_buffer_append_cstrs(data,
                          "<body><h1>ProxyFilter Update Wizard</h1>\n",
                          NULL);
  ssh_http_server_send_buffer(conn, data);

  return TRUE;
}
Exemplo n.º 8
0
int main()
{
  int pass;

  test1();
  for (pass = 0; pass < 1000; pass++)
    {
      buffer = ssh_buffer_allocate();
      test_encode();
      test_empty_decode();
      test_random_decode();
      ssh_buffer_free(buffer);
    }
  ssh_util_uninit();
  return 0;
}
Exemplo n.º 9
0
static Boolean
ssh_eap_send_failure(SshEap eap)
{
  SshBuffer pkt;
  Boolean ret;

  ret = FALSE;
  pkt = ssh_buffer_allocate();

  if (pkt == NULL)
    {
      ssh_eap_fatal(eap, NULL,
                    "Out of memory. Can not send EAP failure packet.");
      return FALSE;
    }

  eap->previous_eap_code = SSH_EAP_CODE_FAILURE;
  eap->previous_eap_type = 0;

  if (eap->id_isrecv == 1)
    {
      SSH_DEBUG(SSH_D_MIDOK,("sending EAP failure packet!"));

      if (ssh_eap_packet_build_hdr(pkt, SSH_EAP_CODE_FAILURE,
                                   eap->id, 0) == TRUE)
        {
          ssh_eap_remember_packet(eap, pkt);
          ssh_eap_send_packet(eap, pkt);
          ret = TRUE;
        }
      else
        {
	  ssh_buffer_free(pkt);
          ssh_eap_fatal(eap, NULL,
                        "Out of memory. "
                        "Canot not send EAP failure packet");
        }
    }
  else
    {
      ssh_buffer_free(pkt);
      ssh_eap_fatal(eap, NULL, "Cannot send EAP failure packet, "
                               "no valid identifier available!");
    }
  return ret;
}
Exemplo n.º 10
0
void
ssh_eap_build_and_send_reply(SshEap eap, SshUInt8 type,
                             const SshUInt8 *ptr, SshUInt16 len)
{
  SshBuffer pkt;

  /* Only send replies to requests */

  SSH_ASSERT(eap->id_isinit == 1);

  pkt = ssh_buffer_allocate();

  if (pkt == NULL)
    {
      ssh_eap_fatal(eap, NULL,
                    "Out of memory. Can not send reply.");
      return;
    }

  if (!ssh_eap_packet_build_hdr_with_type(pkt,
					  SSH_EAP_CODE_REPLY,
					  eap->id,
					  len,
					  type))
    {
      ssh_buffer_free(pkt);
      ssh_eap_fatal(eap, NULL,
                    "Out of memory. Can not send reply.");
      return;
    }

  if (len != 0 && ptr != NULL)
    {
      if (ssh_buffer_append(pkt, ptr, len) != SSH_BUFFER_OK)
        {
	  ssh_buffer_free(pkt);
          ssh_eap_fatal(eap, NULL, "Out of memory. Can not send reply.");
          return;
        }
    }

  /* Ok. let's transmit this packet */

  ssh_eap_remember_packet(eap, pkt);
  ssh_eap_send_packet(eap, pkt);
}
Exemplo n.º 11
0
void create_testdata(void)
{
  int len, i;
  unsigned char ch;

  if (testdata)
    ssh_buffer_clear(testdata);
  else
    testdata = ssh_buffer_allocate();

  len = ssh_rand() % 100000;
  for (i = 0; i < len; i++)
    {
      ch = (unsigned char)(ssh_rand() % 256);
      ssh_buffer_append(testdata, &ch, 1);
    }
}
Exemplo n.º 12
0
/* 
 * Inserts specified event into log file specified in context.
 * event parameter specifies the audited event. Each element after event 
 * must start with a SshAuditformat type followed by arguments of the 
 * appropriate type, and the list must end with SSH_AUDIT_ARGUMENT_END.
 */
void ssh_audit_event(SshAuditContext context, SshAuditEvent event, ...)
{
  size_t bytes;
  va_list ap;
  SshBuffer *audit_info, *formated_str;
  char *audit_time;

  if (context == NULL) return;

  if ((event < 0) || (event > SSH_AUDIT_MAX_VALUE)) return;
  /* Check if given event is allowed */
  if (!context->ssh_audit_event_allowed[(int)event]) return;

  /* Initialize a buffer for output string */
  audit_info = ssh_buffer_allocate();

  /* Start constructing string which will be inserted into audit log.*/
  /* Start with inserting the name of the event.*/
  /* then date and time */
  audit_time = ssh_time_string(ssh_time());
  ssh_buffer_append_cstrs(audit_info, 
                          ssh_find_keyword_name(ssh_audit_event_title, 
                                                (int)event),
                          ": ", audit_time, ": ", 
                          NULL); 
  ssh_xfree(audit_time);

  /* Handle the variable list*/
  va_start(ap, event);
  formated_str = ssh_format_audit_string(ap);
  va_end(ap);

  /* Insert given parameters into string*/
  ssh_buffer_append(audit_info, 
                    ssh_buffer_ptr(formated_str),
                    ssh_buffer_len(formated_str));
  ssh_buffer_append(audit_info, (unsigned char *) "\0", 1);

  /* Output the log message*/
  ssh_send_log_message(context, ssh_buffer_ptr(audit_info));

  ssh_buffer_free(formated_str);
  ssh_buffer_free(audit_info);
}
Exemplo n.º 13
0
static void test1(void)
{
  unsigned char *t1, *t2;

  buffer = ssh_buffer_allocate();
  ssh_encode_buffer(buffer,
    SSH_ENCODE_CHAR(0),
    SSH_ENCODE_DATA("sikapantteri", strlen("sikapantteri")),
    SSH_ENCODE_UINT32_SSTR("sikapantteri", strlen("sikapantteri")),
    SSH_ENCODE_UINT32_SSTR("sikapantteri", strlen("sikapantteri")),
    SSH_FORMAT_END);
  if (ssh_decode_buffer(buffer,
			SSH_DECODE_CHAR(NULL),
			SSH_DECODE_DATA(NULL, strlen("sikapantteri")),
			SSH_DECODE_UINT32_STR(&t1, NULL),
			SSH_DECODE_UINT32_STR(&t2, NULL),
			SSH_FORMAT_END) == 0)
    ssh_fatal("ssh_decode_buffer failed");
  ssh_xfree(t2);
  ssh_xfree(t1);
  ssh_buffer_free(buffer);
}
Exemplo n.º 14
0
/* Callback, which is used to notify that our packetstream has a
   packet for us.*/
void auth_hostbased_received_packet(SshPacketType type,
                                    const unsigned char *packet,
                                    size_t packet_len,
                                    void *context)
{
  SshBuffer *b;

  SshClientHostbasedAuth state = (SshClientHostbasedAuth) context;
  
  switch(type)
    {
    case SSH_AUTH_HOSTBASED_PACKET:
      SSH_TRACE(2, ("ssh-signer returned SSH_AUTH_HOSTBASED_PACKET "\
                    "(this is an error)"));
      /* signer shouldn't send this to us, so this is an error.*/
      /* XXX */
      break;
    case SSH_AUTH_HOSTBASED_SIGNATURE:
      SSH_TRACE(2, ("ssh-signer returned SSH_AUTH_HOSTBASED_SIGNATURE"));
      /* We've got a signature. */
      b = ssh_buffer_allocate();


      /* Destroy wrapper (and signer) */
      ssh_packet_wrapper_send_eof(state->wrapper);
      ssh_packet_wrapper_destroy(state->wrapper);
      state->wrapper = NULL;
      
      ssh_encode_buffer(b,
                        /* public key algorithm (string) */
                        SSH_FORMAT_UINT32_STR,
                        state->pubkey_algorithm,
                        strlen(state->pubkey_algorithm),
                        /* public key (string) */
                        SSH_FORMAT_UINT32_STR, state->pubkeyblob,
                        state->pubkeyblob_len,
                        /* client host name (FQDN, string) */
                        SSH_FORMAT_UINT32_STR, state->local_host_name,
                        strlen(state->local_host_name),
                        /* user name at client side */
                        SSH_FORMAT_UINT32_STR, state->local_user_name,
                        strlen(state->local_user_name),
                        /* signature */
                        SSH_FORMAT_DATA, packet, packet_len,
                        SSH_FORMAT_END);

      /* Detach the state structure from the state_placeholder. */
      *state->state_placeholder = NULL;
  
      /* Call the authentication method completion procedure. */
      (*state->completion)(SSH_AUTH_CLIENT_SEND, state->user, b,
                           state->completion_context);

      /* Free the buffer */
      ssh_buffer_free(b);

      /* XXX Free the state. */

      break;
    case SSH_AUTH_HOSTBASED_ERROR:
      /* Destroy wrapper (and signer) */
      ssh_packet_wrapper_send_eof(state->wrapper);
      ssh_packet_wrapper_destroy(state->wrapper);
      state->wrapper = NULL;

      SSH_TRACE(0, ("ssh-signer returned SSH_AUTH_HOSTBASED_ERROR"));
      /* Send failure message to server, and return. */
      (*state->completion)(SSH_AUTH_CLIENT_FAIL, state->user, NULL,
                           state->completion_context);
      break;
    }
}
Exemplo n.º 15
0
/* 
 * Formats string that is being writen to the log file. Function gets its 
 * information in variable-length argument list. Each element must start with 
 * a SshAuditformat type followed by arguments of the appropriate type. 
 * The list must end with SSH_AUDIT_ARGUMENT_END.  
 * Function returns buffer containing the constructed string. 
 * NOTE: Returned buffer MUST be released by the calling function! 
 */
SshBuffer *ssh_format_audit_string(va_list ap)
{
  SshAuditArgument format;
  char s[128];
  SshBuffer *result;
  SshUInt32 size;
  unsigned char *i;

  result = ssh_buffer_allocate();
  

  for (;;)
    {
      format = va_arg(ap, SshAuditArgument);
      switch (format)
        {
        case SSH_AUDIT_SPI:
            i = va_arg(ap, unsigned char *);
            size = va_arg(ap, size_t);
            if (i == NULL || size == 0)
              break;
            ssh_bin_to_hex_str(s, size, i);
            ssh_buffer_append_cstrs(result, "  SPI:0x", s, NULL);
          break;
          
        case SSH_AUDIT_SOURCE_ADDRESS:
            i = va_arg(ap, unsigned char *);
            size = va_arg(ap, size_t);
            if (i == NULL || size == 0)
              break;
            if (size == 4)
              ssh_audit_v4tostr(s, sizeof(s), i);
            else
              ssh_audit_v6tostr(s, sizeof(s), i);

            ssh_buffer_append_cstrs(result, "  Source addr:", s, NULL);
          break;

        case SSH_AUDIT_DESTINATION_ADDRESS:
            i = va_arg(ap, unsigned char *);
            size = va_arg(ap, size_t);
            if (i == NULL || size == 0)
              break;
            if (size == 4)
              ssh_audit_v4tostr(s, sizeof(s), i);
            else
              ssh_audit_v6tostr(s, sizeof(s), i);

            ssh_buffer_append_cstrs(result, "  Destination addr:", s, NULL);
          break;

        case SSH_AUDIT_SOURCE_ADDRESS_STR:
            i = va_arg(ap, unsigned char *);
            if (i == NULL)
              break;
            ssh_buffer_append_cstrs(result, "  Source addr:", i, NULL); 
            break;

        case SSH_AUDIT_DESTINATION_ADDRESS_STR:
            i = va_arg(ap, unsigned char *);
            if (i == NULL)
              break;
            ssh_buffer_append_cstrs(result, "  Destination addr:", i, NULL);
            break;

        case SSH_AUDIT_IPV6_FLOW_ID:
            i = va_arg(ap, unsigned char *);
            size = va_arg(ap, size_t);
            if (i == NULL || size == 0)
              break;
            ssh_bin_to_hex_str(s, size, i);
            ssh_buffer_append_cstrs(result, "  IPV6:0x", s, NULL); 
          break;

        case SSH_AUDIT_SEQUENCE_NUMBER:
            i = va_arg(ap, unsigned char *);
            size = va_arg(ap, size_t);
            if (i == NULL || size == 0)
              break;
            ssh_bin_to_hex_str(s, size, i);
            ssh_buffer_append_cstrs(result, "  Sequence NO:0x", s, NULL); 
          break;

        case SSH_AUDIT_TXT:
            i = va_arg(ap, unsigned char *);
            if (i == NULL)
              break;
            ssh_buffer_append_cstrs(result, "  Description:", i, NULL); 
            break;

        case SSH_AUDIT_ARGUMENT_END:
          return result;  /* return constructed string */

        default:
          ssh_fatal("ssh_format_audit_string: invalid format code %d (check arguments and SSH_AUDIT_ARGUMENT_END)", 
                    (int)format);
        }
    }
  /*NOTREACHED*/
}
Exemplo n.º 16
0
unsigned char*
ssh_appgw_http_marshal_config(SshAppgwHttpConfig config,
                              size_t *res_len)
{
  SshBuffer buf;
  char *data;
  int i,nblocks,nrules,ok;
  unsigned char tbuf[SSH_IP_ADDR_STRING_SIZE];
  SshAppgwHttpBlockAction reply;
  SshAppgwHttpRule rule;

  nblocks = 0;
  for (reply = config->blocks; reply != NULL; reply=reply->next)
    nblocks++;

  nrules = 0;
  for (rule = config->rules; rule != NULL; rule=rule->next)
    nrules++;

  buf = ssh_buffer_allocate();
  if (buf == NULL)
    return NULL;

  ok = 1;
  ok &= ssh_appgw_http_marshal_string(buf, ssh_custr(CFGVERSION));

  /* Marshal TCP redirection */
  tbuf[0] = '\0';
  if (SSH_IP_DEFINED(&config->tcp_dst))
    ssh_ipaddr_print(&config->tcp_dst, tbuf, sizeof(tbuf));

  ok &= ssh_appgw_http_marshal_string(buf, tbuf);
  ok &= ssh_appgw_http_marshal_int(buf, config->tcp_port);

  ok &= ssh_appgw_http_marshal_int(buf,config->nclauses);
  for (i = 0; i < config->nclauses; i++)
    {
      ok &= ssh_appgw_http_marshal_string(buf,config->clauses[i]->name);
      ok &= ssh_appgw_http_marshal_string(buf,
                                          config->clauses[i]->hdr_regex_str);
      ok &= ssh_appgw_http_marshal_string(buf,config->clauses[i]->host);
      ok &= ssh_appgw_http_marshal_int(buf,config->clauses[i]->min_url_length);
    }

  ok &= ssh_appgw_http_marshal_int(buf,nblocks);

  for (reply = config->blocks; reply != NULL; reply=reply->next)
    {
      ok &= ssh_appgw_http_marshal_string(buf,reply->name);
      ok &= ssh_appgw_http_marshal_int(buf,reply->code);
      ok &= ssh_appgw_http_marshal_string(buf,reply->content_type);
      ok &= ssh_appgw_http_marshal_data(buf, reply->header,
                                        reply->header_len);
      ok &= ssh_appgw_http_marshal_data(buf, reply->data,
                                        reply->data_len);
    }


  ok &= ssh_appgw_http_marshal_int(buf,nrules);

  for (rule = config->rules; rule != NULL; rule=rule->next)
    {
      ok &= ssh_appgw_http_marshal_string(buf,rule->name);
      ok &= ssh_appgw_http_marshal_int(buf,rule->action);

      if (rule->block != NULL)
        ok &= ssh_appgw_http_marshal_string(buf,rule->block->name);
      else
        ok &= ssh_appgw_http_marshal_string(buf,NULL);

      ok &= ssh_appgw_http_marshal_int(buf,rule->precedence);
      ok &= ssh_appgw_http_marshal_int(buf,rule->nclauses);
      for (i = 0; i < rule->nclauses; i++)
        ok &= ssh_appgw_http_marshal_string(buf,rule->clauses[i]->name);
    }

  ok &= ssh_appgw_http_marshal_int(buf,0);

  data = ssh_malloc(ssh_buffer_len(buf));

  if (ok == 0 || data == NULL)
    {
      SSH_DEBUG(SSH_D_FAIL,("out of memory error"));
      ssh_buffer_free(buf);
      return NULL;
    }
  memcpy(data,ssh_buffer_ptr(buf),ssh_buffer_len(buf));
  *res_len = ssh_buffer_len(buf);

  ssh_buffer_free(buf);
  SSH_DEBUG(SSH_D_MY,
            ("marshaled config blob (%d bytes)",*res_len));

  return (unsigned char *)data;
}
Exemplo n.º 17
0
int main(int argc, char* argv[])
{
  t_tcpc_context  pcontext = 0;
  SshGetOptData   pgetoptdata = 0;
  int                             i;

  SSH_TRACE(SSH_D_MY, ("%s", "main"));

  pcontext = ssh_xmalloc(sizeof (*pcontext));
  memset(pcontext, 0, sizeof (*pcontext));

  pgetoptdata = ssh_xmalloc(sizeof (*pgetoptdata));
  memset(pgetoptdata, 0, sizeof (*pgetoptdata));

  ssh_getopt_init_data(pgetoptdata);
  pcontext->pport_or_service = "23242";

  while ((i = ssh_getopt(argc, argv, "p:h:d:D:G:t:", pgetoptdata)) != -1)
    {
      switch (i)
        {
        case 'p':
          pcontext->pport_or_service = ssh_xstrdup(pgetoptdata->arg);
          break;
        case 'h':
          pcontext->phost_name_or_address = ssh_xstrdup(pgetoptdata->arg);
          break;
        case 'd':
          pcontext->pdata = ssh_xstrdup(pgetoptdata->arg);
          break;
        case 'D':
          ssh_debug_set_module_level(SSH_DEBUG_MODULE, atoi(pgetoptdata->arg));
          break;
        case 'G':
          ssh_debug_set_global_level(atoi(pgetoptdata->arg));
          break;
        case 't':
          pcontext->timeout = atoi(pgetoptdata->arg);
          break;
        default:
          SSH_NOTREACHED;
          break;
        }
    }

  ssh_xfree(pgetoptdata);

  ssh_event_loop_initialize();

  pcontext->pbuffer = ssh_buffer_allocate();

  if (pcontext->phost_name_or_address)
    {
      ssh_tcp_connect(pcontext->phost_name_or_address,
                      pcontext->pport_or_service,
                      NULL,
                      t_tcpc_tcp_callback,
                      pcontext);
    }
  else
    {
      pcontext->ptcplistener =
        ssh_tcp_make_listener(SSH_IPADDR_ANY_IPV4,
                              pcontext->pport_or_service,
                              NULL,
                              t_tcpc_tcp_callback,
                              pcontext);
    }

  ssh_event_loop_run();
  ssh_name_server_uninit();
  ssh_event_loop_uninitialize();

  ssh_buffer_free(pcontext->pbuffer);
  ssh_xfree(pcontext);
  ssh_util_uninit();
  return 0;
}
Exemplo n.º 18
0
static void
result_callback(SshHttpClientContext ctx, SshHttpResult result,
                SshTcpError ip_error, SshStream stream, void *callback_context)
{
  ProxyRequest *req = callback_context;
  SshBuffer error;
  char buf[256];

  switch (result)
    {
    case SSH_HTTP_RESULT_SUCCESS:
      {
        const char *value = NULL;
        SshCopyStreamCopyCb copy_cb = copy_data;

        if ((value = ssh_http_get_header_field(ctx, "Content-Type")))
          ssh_http_server_set_values(req->conn,
                                     SSH_HTTP_HDR_FIELD,
                                     "Content-Type", value,
                                     SSH_HTTP_HDR_END);

        req->client_stream = stream;

#if SMART_UPDATE
        if (value && strncmp(value, "text/html", 9) == 0)
          copy_cb = filter_html;
#endif

        ssh_copy_stream(req->server_stream, req->client_stream,
                        copy_cb, req_finish, req);
      }
      break;

    case SSH_HTTP_RESULT_MALFORMED_URL:
      error = ssh_buffer_allocate();

      ssh_buffer_append_cstrs(error, "<body><h1>Malformed URL</h1>n", NULL);
      ssh_http_server_send_buffer(req->conn, error);

      ssh_xfree(req);
      break;

    case SSH_HTTP_RESULT_REDIRECT_LIMIT_EXCEEDED:
      {
        const char *location = ssh_http_get_header_field(ctx, "Location");
        const char *reason_phrase;

        SSH_DEBUG(SSH_D_HIGHSTART, ("Redirect: %s", location));
        ssh_http_server_error(req->conn,
                              ssh_http_get_status_code(ctx, &reason_phrase),
                              SSH_HTTP_HDR_LOCATION, location,
                              SSH_HTTP_HDR_END);

        ssh_stream_destroy(req->server_stream);
        ssh_xfree(req);

      }
      break;

    case SSH_HTTP_RESULT_HTTP_ERROR:
      {
        const char *reason_phrase;
        SshUInt32 error_code;

        error_code = ssh_http_get_status_code(ctx, &reason_phrase);
        error = ssh_buffer_allocate();

        ssh_snprintf(buf, sizeof(buf), "%ld", error_code);

        ssh_http_server_error(req->conn, error_code,
                              SSH_HTTP_HDR_END);

        ssh_buffer_append_cstrs(error,
                                "<body><h1>HTTP Error (", buf,
                                ")</h1>\n<pre>\n",
                                reason_phrase, "\n", NULL);
        ssh_http_server_send_buffer(req->conn, error);

        ssh_xfree(req);
      }
      break;

    default:
      error = ssh_buffer_allocate();

      ssh_snprintf(buf, sizeof(buf), "%d", result);

      ssh_buffer_append_cstrs(error,
                              "<body><h1>HTTP Library Error ", buf, "</h1>\n",
                              NULL);
      ssh_http_server_send_buffer(req->conn, error);
      ssh_xfree(req);
      break;
    }
}
Exemplo n.º 19
0
/* The URI handler. */
static Boolean
proxy_handler(SshHttpServerContext ctx,
              SshHttpServerConnection conn,
              SshStream stream, void *context)
{
  const char *method = ssh_http_server_get_method(conn);
  const char *uri = ssh_http_server_get_uri(conn);
  SshHttpClientParams params;
  ProxyRequest *req;
  SshBuffer error;
  ProxyCensor *c;

  SSH_DEBUG(SSH_D_HIGHSTART,
            ("method=%s, uri=%s", method, uri));

  for (c = censor; c; c = c->next)
    if (ssh_match_pattern(uri, c->pattern))
      {
        SSH_DEBUG(SSH_D_HIGHSTART,
                  ("censored by pattern `%s'", c->pattern));
        ssh_http_server_error(conn, 301,
                              SSH_HTTP_HDR_LOCATION,
                              "http://people.ssh.fi/mtr/censor.jpg",
                              SSH_HTTP_HDR_FIELD,
                              "Content-Type", "text/html",
                              SSH_HTTP_HDR_END);
        ssh_stream_destroy(stream);
        return TRUE;
      }

  memset(&params, 0, sizeof(params));
  params.http_proxy_url = proxy_url;
  params.num_redirections = 0;

  req = ssh_xcalloc(1, sizeof(*req));
  req->server = ctx;
  req->conn = conn;
  req->server_stream = stream;

  req->client = ssh_http_client_init(&params);

  if (strcmp(method, "GET") == 0)
    ssh_http_get(req->client, uri, result_callback, req,
                 SSH_HTTP_HDR_END);
  else if (strcmp(method, "HEAD") == 0)
    ssh_http_head(req->client, uri, result_callback, req,
                  SSH_HTTP_HDR_END);
  else if (strcmp(method, "POST") == 0
           || strcmp(method, "PUT") == 0)
    {
      SSH_DEBUG(SSH_D_ERROR, ("%s not implemented yet", method));
      ssh_xfree(req);

      error = ssh_buffer_allocate();
      ssh_buffer_append_cstrs(error, "<body><h1>Method `", method,
                              "' not implemented yet</h1>\n", NULL);
      ssh_http_server_send_buffer(conn, error);
    }
  else
    {
      SSH_DEBUG(SSH_D_ERROR, ("unknown method `%s'", method));
      ssh_xfree(req);

      error = ssh_buffer_allocate();
      ssh_buffer_append_cstrs(error, "<body><h1>Unknown method `",
                              method, "'</h1>\n", NULL);

      ssh_http_server_send_buffer(conn, error);
    }

  return TRUE;
}
Exemplo n.º 20
0
SshTlsTransStatus ssh_tls_trans_write_client_hello(SshTlsProtocolState s)
{
  SshTlsCipherSuite tab[SSH_TLS_NUM_CIPHERSUITES];
  SshTlsCipherSuite *suites_to_send;
  SshTlsCipherSuiteDetailsStruct details;
  int number_suites;
  int contents_len;
  unsigned char tempbuf[2];
  int i;

  s->kex.flags |= SSH_TLS_KEX_NEW_SESSION; /* Initially. */

  if (s->conf.preferred_suites != NULL)
    {

      /* If a preference list has been given, check that the
         preferences are sound w.r.t. the protocol flags given in the
         configuration. */

      SshTlsCipherSuite *tmp;

      SSH_DEBUG(6, ("Got a preference list."));

      number_suites = 0;
      tmp = s->conf.preferred_suites;
      while (*tmp != SSH_TLS_NO_CIPHERSUITE)
        {
          ssh_tls_get_ciphersuite_details(*tmp, &details);
          if (details.crippled && (!(s->conf.flags & SSH_TLS_WEAKCIPHERS)))
            {
	      return SSH_TLS_TRANS_FAILED;
            }
          if (details.cipher == SSH_TLS_CIPH_NULL &&
              (!(s->conf.flags & SSH_TLS_NULLCIPHER)))
            {
	      return SSH_TLS_TRANS_FAILED;
            }
          tmp++; number_suites++;
        }
      suites_to_send = s->conf.preferred_suites;
    }
  else
    {
      /* Otherwise construct a list containing all those ciphersuites
         that are supported by our implementation and that can be used
         according to the protocol configuration flags. */

      number_suites = 0;

      for (i = SSH_TLS_RSA_WITH_NULL_MD5; i < SSH_TLS_MAX_CIPHERSUITE; i++)
        {
          ssh_tls_get_ciphersuite_details(i, &details);

          SSH_DEBUG(7, ("Check if suite %d can be supported.", i));

	  if ((details.kex_method == SSH_TLS_UNKNOWN_SUITE)
	       || !(ssh_tls_supported_suite(s->conf.flags, 
					    (SshTlsCipherSuite) i)))
	     continue;

          SSH_DEBUG(7, ("Null? %d  Crippled? %d  RC2? %d  RSA? %d  "
                        "Nosign? %d",
                        (details.cipher == SSH_TLS_CIPH_NULL),
                        (details.crippled),
                        (details.cipher == SSH_TLS_CIPH_RC2),
                        (details.kex_method == SSH_TLS_KEX_RSA),
                        (details.signature_method == SSH_TLS_SIGN_NONE)));

          if ((details.cipher == SSH_TLS_CIPH_NULL &&
               (!(s->conf.flags & SSH_TLS_NULLCIPHER)))
              || (details.crippled && (!(s->conf.flags & SSH_TLS_WEAKCIPHERS)))
              || (details.cipher == SSH_TLS_CIPH_RC2)
              || (details.kex_method != SSH_TLS_KEX_RSA)
              || (details.signature_method != SSH_TLS_SIGN_NONE))
            continue;

          SSH_DEBUG(7, ("Adding the cipher suite %d.", i));

          tab[number_suites++] = i;
        }
      suites_to_send = tab;
    }

  /* Now we can calculate the length of the packet. */

  /* Protocol version 2 bytes, random value 32 bytes,
     session ID 1 + N bytes, ciphersuites list 2 bytes (length)
     plus number_suites * 2 bytes, and 2 bytes for the single
     compression method (no compression) we support. */

  contents_len = 2 + 32 + 1 + s->kex.id_len + 2 + number_suites * 2 + 2;

  /* Initialize the handshake history buffer now. */
  SSH_ASSERT(s->kex.handshake_history == NULL);
  s->kex.handshake_history = ssh_buffer_allocate();

  if (s->kex.handshake_history == NULL)
    return SSH_TLS_TRANS_FAILED;

  ssh_tls_make_hs_header(s, SSH_TLS_HS_CLIENT_HELLO, contents_len);

  /* Write the highest protocol version or that of a hopefully-resumed
     session. */

  tempbuf[0] = s->kex.client_version.major;
  tempbuf[1] = s->kex.client_version.minor;

  ssh_tls_add_to_kex_packet(s, tempbuf, 2);

  /* Write unix time. */
  SSH_PUT_32BIT(s->kex.client_random, (SshUInt32)ssh_time());

  /* Write 28 random bytes. */
  for (i = 4; i < 32; i++)
    {
      s->kex.client_random[i]
        = ssh_random_get_byte();
    }
  ssh_tls_add_to_kex_packet(s, s->kex.client_random, 32);

  /* Write the requested session identifier. */
  tempbuf[0] = s->kex.id_len;
  ssh_tls_add_to_kex_packet(s, &tempbuf[0], 1);
  if (s->kex.id_len > 0)
    {
      ssh_tls_add_to_kex_packet(s, s->kex.session_id, s->kex.id_len);
    }

  /* Write the cipher suites. */
  SSH_PUT_16BIT(tempbuf, number_suites * 2);
  ssh_tls_add_to_kex_packet(s, tempbuf, 2);

  for (i = 0; i < number_suites; i++)
    {
      SSH_PUT_16BIT(tempbuf, suites_to_send[i]);
      ssh_tls_add_to_kex_packet(s, tempbuf, 2);
    }

  /* And the compression method. */
  tempbuf[0] = 1;
  tempbuf[1] = 0; /* the null compression */
  ssh_tls_add_to_kex_packet(s, tempbuf, 2);

  s->kex.state = SSH_TLS_KEX_WAIT_S_HELLO;

  return SSH_TLS_TRANS_OK;
}
Exemplo n.º 21
0
/* Opens a connection to the specified host, and calls the callback
   when the connection has been established or has failed.  If
   connecting is successful, the callback will be called with error
   set to SSH_TCP_OK and an SshStream object for the connection passed
   in in the stream argument.  Otherwise, error will indicate the
   reason for the connection failing, and the stream will be NULL.

   Note that the callback may be called either during this
   call or some time later.

   Returns SshOperationHandle that can be used to abort the tcp open.

   The `host_name_or_address' argument may be a numeric IP address or a
   host name (domain name), in which case it is looked up from the name
   servers.

   The params structure can either be NULL or memset to zero to get default
   parameters. All data inside the params is copied during this call, so it can
   be freed immediately when this function returns. */
SshOperationHandle ssh_tcp_connect(const unsigned char *host_name_or_address,
                                   const unsigned char *port_or_service,
                                   const SshTcpConnectParams params,
                                   SshTcpCallback callback,
                                   void *context)
{
    ConnectContext c;

    c = ssh_calloc(1, sizeof(*c));
    if (c == NULL)
    {
        SSH_DEBUG(1, ("Failed to allocate TCP connection context."));
        (*callback)(SSH_TCP_FAILURE, NULL, context);
        return NULL;
    }

    if (params && params->local_address)
    {
        c->local_address = ssh_strdup(params->local_address);
        if (c->local_address == NULL)
        {
error_local:
            (*callback)(SSH_TCP_FAILURE, NULL, context);
            tcp_connect_destroy_ctx(c);
            return NULL;
        }

        if (params->local_port_or_service)
        {
            c->local_port
                = ssh_inet_get_port_by_service(params->local_port_or_service,
                                               ssh_custr("tcp"));
            if (c->local_port == 0)
                goto error_local;
        }
        c->local_reusable = params->local_reusable;
    }

    c->host_name = ssh_strdup(host_name_or_address);
    c->host_port = ssh_inet_get_port_by_service(port_or_service,
                   ssh_custr("tcp"));
    c->host_addresses = NULL;
    c->next_address = NULL;

    if (c->host_name == NULL || c->host_port == 0)
    {
        (*callback)(SSH_TCP_FAILURE, NULL, context);
        tcp_connect_destroy_ctx(c);
        return NULL;
    }

    if (params && (params->protocol_mask != 0))
        c->protocol_mask = params->protocol_mask;
    else
        c->protocol_mask = (~0);

    c->user_callback = callback;
    c->user_context = context;
    if (params && params->connection_timeout != 0)
    {
        ssh_register_timeout(&c->timeout,
                             params->connection_timeout, 0,
                             tcp_connect_time_out, c);
    }

    c->connection_attempts = 1;
    if (params && params->connection_attempts != 0)
        c->connection_attempts = params->connection_attempts;

    c->attempts_done = 0;

    c->stream = NULL;

    /* Initialize socks-related data. */
    if (params &&
            params->socks_server_url != NULL &&
            ssh_usstrcmp(params->socks_server_url, "") != 0)
    {
        unsigned char *scheme, *port;

        if (ssh_url_parse_and_decode_relaxed(params->socks_server_url, &scheme,
                                             &(c->socks_host), &port,
                                             &(c->user_name), NULL,
                                             &(c->socks_exceptions)))
        {
            if (scheme != NULL && ssh_usstrcmp(scheme, "socks") != 0)
                ssh_warning("Socks server scheme not socks");
            if (scheme != NULL)
                ssh_free(scheme);

            if (c->socks_host != NULL)
            {
                if ((c->socks_buf = ssh_buffer_allocate()) == NULL)
                {
                    (*callback)(SSH_TCP_FAILURE, NULL, context);
                    tcp_connect_destroy_ctx(c);
                    return NULL;
                }
                c->socks_addresses = NULL;
                if (port == NULL || ssh_usstrcmp(port, "") == 0)
                    c->socks_port = 1080; /* The standard socks port. */
                else
                    c->socks_port = ssh_inet_get_port_by_service(port,
                                    ssh_custr("tcp"));
            }
            if (port != NULL)
                ssh_free(port);
        }
        else
        {
            ssh_warning("Socks server URL is malformed.");
        }
    }
    else
        c->socks_host = NULL;

    if (params)
        c->socks_type = params->socks_type;

    c->upper_handle = NULL;
    c->handle = NULL;

    c->fsm = ssh_fsm_create(c);
    if (c->fsm == NULL)
    {
        SSH_DEBUG(2, ("Creating FSM failed."));
        (*callback)(SSH_TCP_FAILURE, NULL, context);
        tcp_connect_destroy_ctx(c);
        return NULL;
    }
    c->thread = ssh_fsm_thread_create(c->fsm, tcp_connect_start,
                                      NULL_FNPTR, NULL_FNPTR, NULL);
    if (c->thread == NULL)
    {
        SSH_DEBUG(2, ("Creating thread failed."));
        (*callback)(SSH_TCP_FAILURE, NULL, context);
        ssh_fsm_destroy(c->fsm);
        tcp_connect_destroy_ctx(c);
        return NULL;
    }
    c->upper_handle = ssh_operation_register(ssh_tcp_connect_aborted, c);
    return c->upper_handle;
}
Exemplo n.º 22
0
/** @internal
 * @handles a data received event. It then calls the handlers for the different packet types
 * or and exception handler callback.
 * @param user pointer to current ssh_session
 * @param data pointer to the data received
 * @len length of data received. It might not be enough for a complete packet
 * @returns number of bytes read and processed.
 */
int ssh_packet_socket_callback(const void *data, size_t receivedlen, void *user)
{
    ssh_session session= (ssh_session) user;
    unsigned int blocksize = (session->current_crypto ?
                              session->current_crypto->in_cipher->blocksize : 8);
    unsigned int lenfield_blocksize = (session->current_crypto ?
                                  session->current_crypto->in_cipher->lenfield_blocksize : 8);
    size_t current_macsize = 0;
    uint8_t *ptr = NULL;
    int to_be_read;
    int rc;
    uint8_t *cleartext_packet = NULL;
    uint8_t *packet_second_block = NULL;
    uint8_t *mac = NULL;
    size_t packet_remaining;
    uint32_t packet_len, compsize, payloadsize;
    uint8_t padding;
    size_t processed = 0; /* number of byte processed from the callback */

    if(session->current_crypto != NULL) {
      current_macsize = hmac_digest_len(session->current_crypto->in_hmac);
    }
    if (lenfield_blocksize == 0) {
        lenfield_blocksize = blocksize;
    }
    if (data == NULL) {
        goto error;
    }

    if (session->session_state == SSH_SESSION_STATE_ERROR) {
        goto error;
    }
#ifdef DEBUG_PACKET
    SSH_LOG(SSH_LOG_PACKET,
            "rcv packet cb (len=%zu, state=%s)",
            receivedlen,
            session->packet_state == PACKET_STATE_INIT ?
                "INIT" :
                session->packet_state == PACKET_STATE_SIZEREAD ?
                    "SIZE_READ" :
                    session->packet_state == PACKET_STATE_PROCESSING ?
                    "PROCESSING" : "unknown");
#endif
    switch(session->packet_state) {
        case PACKET_STATE_INIT:
            if (receivedlen < lenfield_blocksize) {
                /*
                 * We didn't receive enough data to read at least one
                 * block size, give up
                 */
#ifdef DEBUG_PACKET
                SSH_LOG(SSH_LOG_PACKET,
                        "Waiting for more data (%zu < %u)",
                        receivedlen,
                        lenfield_blocksize);
#endif
                return 0;
            }

            memset(&session->in_packet, 0, sizeof(PACKET));

            if (session->in_buffer) {
                rc = ssh_buffer_reinit(session->in_buffer);
                if (rc < 0) {
                    goto error;
                }
            } else {
                session->in_buffer = ssh_buffer_new();
                if (session->in_buffer == NULL) {
                    goto error;
                }
            }

            ptr = ssh_buffer_allocate(session->in_buffer, lenfield_blocksize);
            if (ptr == NULL) {
                goto error;
            }
            processed += lenfield_blocksize;
            packet_len = ssh_packet_decrypt_len(session, ptr, (uint8_t *)data);

            if (packet_len > MAX_PACKET_LEN) {
                ssh_set_error(session,
                              SSH_FATAL,
                              "read_packet(): Packet len too high(%u %.4x)",
                              packet_len, packet_len);
                goto error;
            }
            to_be_read = packet_len - lenfield_blocksize + sizeof(uint32_t);
            if (to_be_read < 0) {
                /* remote sshd sends invalid sizes? */
                ssh_set_error(session,
                              SSH_FATAL,
                              "Given numbers of bytes left to be read < 0 (%d)!",
                              to_be_read);
                goto error;
            }

            session->in_packet.len = packet_len;
            session->packet_state = PACKET_STATE_SIZEREAD;
            FALL_THROUGH;
        case PACKET_STATE_SIZEREAD:
            packet_len = session->in_packet.len;
            processed = lenfield_blocksize;
            to_be_read = packet_len + sizeof(uint32_t) + current_macsize;
            /* if to_be_read is zero, the whole packet was blocksize bytes. */
            if (to_be_read != 0) {
                if (receivedlen  < (unsigned int)to_be_read) {
                    /* give up, not enough data in buffer */
                    SSH_LOG(SSH_LOG_PACKET,
                            "packet: partial packet (read len) "
                            "[len=%d, receivedlen=%d, to_be_read=%d]",
                            packet_len,
                            (int)receivedlen,
                            to_be_read);
                    return 0;
                }

                packet_second_block = (uint8_t*)data + lenfield_blocksize;
                processed = to_be_read - current_macsize;
            }

            /* remaining encrypted bytes from the packet, MAC not included */
            packet_remaining =
                packet_len - (lenfield_blocksize - sizeof(uint32_t));
            cleartext_packet = ssh_buffer_allocate(session->in_buffer,
                                                   packet_remaining);
            if (session->current_crypto) {
                /*
                 * Decrypt the rest of the packet (lenfield_blocksize bytes already
                 * have been decrypted)
                 */
                if (packet_remaining > 0) {
                    rc = ssh_packet_decrypt(session,
                                            cleartext_packet,
                                            (uint8_t *)data,
                                            lenfield_blocksize,
                                            processed - lenfield_blocksize);
                    if (rc < 0) {
                        ssh_set_error(session, SSH_FATAL, "Decryption error");
                        goto error;
                    }
                }
                mac = packet_second_block + packet_remaining;

                rc = ssh_packet_hmac_verify(session, session->in_buffer, mac, session->current_crypto->in_hmac);
                if (rc < 0) {
                    ssh_set_error(session, SSH_FATAL, "HMAC error");
                    goto error;
                }
                processed += current_macsize;
            } else {
                memcpy(cleartext_packet, packet_second_block, packet_remaining);
            }

            /* skip the size field which has been processed before */
            ssh_buffer_pass_bytes(session->in_buffer, sizeof(uint32_t));

            rc = ssh_buffer_get_u8(session->in_buffer, &padding);
            if (rc == 0) {
                ssh_set_error(session,
                              SSH_FATAL,
                              "Packet too short to read padding");
                goto error;
            }

            if (padding > ssh_buffer_get_len(session->in_buffer)) {
                ssh_set_error(session,
                              SSH_FATAL,
                              "Invalid padding: %d (%d left)",
                              padding,
                              ssh_buffer_get_len(session->in_buffer));
                goto error;
            }
            ssh_buffer_pass_bytes_end(session->in_buffer, padding);
            compsize = ssh_buffer_get_len(session->in_buffer);

#ifdef WITH_ZLIB
            if (session->current_crypto
                && session->current_crypto->do_compress_in
                && ssh_buffer_get_len(session->in_buffer) > 0) {
                rc = decompress_buffer(session, session->in_buffer,MAX_PACKET_LEN);
                if (rc < 0) {
                    goto error;
                }
            }
#endif /* WITH_ZLIB */
            payloadsize = ssh_buffer_get_len(session->in_buffer);
            session->recv_seq++;
            if (session->raw_counter != NULL) {
                session->raw_counter->in_bytes += payloadsize;
                session->raw_counter->in_packets++;
            }

            /*
             * We don't want to rewrite a new packet while still executing the
             * packet callbacks
             */
            session->packet_state = PACKET_STATE_PROCESSING;
            ssh_packet_parse_type(session);
            SSH_LOG(SSH_LOG_PACKET,
                    "packet: read type %hhd [len=%d,padding=%hhd,comp=%d,payload=%d]",
                    session->in_packet.type, packet_len, padding, compsize, payloadsize);

            /* Execute callbacks */
            ssh_packet_process(session, session->in_packet.type);
            session->packet_state = PACKET_STATE_INIT;
            if (processed < receivedlen) {
                /* Handle a potential packet left in socket buffer */
                SSH_LOG(SSH_LOG_PACKET,
                        "Processing %" PRIdS " bytes left in socket buffer",
                        receivedlen-processed);

                ptr = ((uint8_t*)data) + processed;

                rc = ssh_packet_socket_callback(ptr, receivedlen - processed,user);
                processed += rc;
            }

            return processed;
        case PACKET_STATE_PROCESSING:
            SSH_LOG(SSH_LOG_PACKET, "Nested packet processing. Delaying.");
            return 0;
    }

    ssh_set_error(session,
                  SSH_FATAL,
                  "Invalid state into packet_read2(): %d",
                  session->packet_state);

error:
    session->session_state= SSH_SESSION_STATE_ERROR;
    SSH_LOG(SSH_LOG_PACKET,"Packet: processed %" PRIdS " bytes", processed);
    return processed;
}
Exemplo n.º 23
0
void simple_password_client(SshAuthClientOperation op,
                            const char *user,
                            unsigned int packet_type,
                            SshBuffer *packet_in,
                            const unsigned char *session_id,
                            size_t session_id_len,
                            void **state_placeholder,
                            SshAuthClientCompletionProc completion_proc,
                            void *completion_context,
                            void *method_context)
{
  char *pass;
  SshBuffer *b;
  ClientPingPongData *pd;
  SshUInt32 value;

#ifdef DEBUG
  ssh_debug("simple_password_client: op %d", (int)op);
#endif  

  switch (op)
    {
    case SSH_AUTH_CLIENT_OP_START:

      simple_user_accept = random() % 2;
      simple_password_accept = random() % 2;
      
      if (simple_password_may_fail && pingpong_success &&
          random() % 5 == 0)
        {
#ifdef DEBUG
          ssh_debug("simple_password_client: cancelling");
#endif
          simple_password_failed = TRUE;
          (*completion_proc)(SSH_AUTH_CLIENT_CANCEL, user, NULL,
                             completion_context);
          return;
        }
      
      if (simple_user_accept)
        user = CORRECT_USER;
      else
        user = WRONG_USER;
      if (simple_password_accept)
        pass = CORRECT_PASS;
      else
        pass = WRONG_PASS;

      b = ssh_buffer_allocate();

      if (pingpong_count > 0)
        {
          /* Send pingpong reply */
          assert(*state_placeholder == NULL);
          pd = ssh_xmalloc(sizeof(*pd));
          *state_placeholder = pd;
          pd->count = 0;
#ifdef DEBUG
          ssh_debug("simple_password_client: sending pongpong %ld", pd->count);
#endif
          ssh_encode_buffer(b,
                            SSH_FORMAT_BOOLEAN, TRUE,
                            SSH_FORMAT_UINT32, pd->count,
                            SSH_FORMAT_END);
          if (pd->count < pingpong_count)
            (*completion_proc)(SSH_AUTH_CLIENT_SEND_AND_CONTINUE, user, b,
                               completion_context);
          else
            {
              ssh_xfree(*state_placeholder);
              *state_placeholder = NULL;
              (*completion_proc)(SSH_AUTH_CLIENT_SEND, user, b,
                                 completion_context);
            }
        }
      else
        {
          /* Send normal reply */
#ifdef DEBUG
          ssh_debug("simple_password_client: sending req");
#endif
          ssh_encode_buffer(b,
                            SSH_FORMAT_BOOLEAN, FALSE,
                            SSH_FORMAT_UINT32_STR, pass, strlen(pass),
                            SSH_FORMAT_END);
          (*completion_proc)(SSH_AUTH_CLIENT_SEND, user, b,
                             completion_context);
        }
      ssh_buffer_free(b);
      break;
      
    case SSH_AUTH_CLIENT_OP_START_NONINTERACTIVE:
#ifdef DEBUG
      ssh_debug("simple_password_client: noninteractive failing");
#endif
      (*completion_proc)(SSH_AUTH_CLIENT_FAIL, user, NULL, completion_context);
      break;
      
    case SSH_AUTH_CLIENT_OP_CONTINUE:
#ifdef DEBUG
      ssh_debug("simple_password_client: OP_CONTINUE");
#endif
      pd = *state_placeholder;
      if (pd == NULL || pd->count < 0 || pd->count >= pingpong_count)
        ssh_fatal("simple_password_client: strange pd");
      if (ssh_decode_buffer(packet_in,
                            SSH_FORMAT_UINT32, &value,
                            SSH_FORMAT_END) == 0)
        ssh_fatal("simple_password_client: bad packet_in");
      if ((value ^ 0x12345678) != pd->count)
        ssh_fatal("simple_password_client: bad value");
      pd->count++;
#ifdef DEBUG
      ssh_debug("simple_password_client: sending pongpong %ld", pd->count);
#endif
      b = ssh_buffer_allocate();
      ssh_encode_buffer(b,
                        SSH_FORMAT_BOOLEAN, TRUE,
                        SSH_FORMAT_UINT32, pd->count,
                        SSH_FORMAT_END);
      if (pd->count < pingpong_count)
        (*completion_proc)(SSH_AUTH_CLIENT_SEND_AND_CONTINUE, user, b,
                           completion_context);
      else
        {
          ssh_xfree(*state_placeholder);
          *state_placeholder = NULL;
          (*completion_proc)(SSH_AUTH_CLIENT_SEND, user, b,
                             completion_context);
        }
      ssh_buffer_free(b);
      break;
      
    case SSH_AUTH_CLIENT_OP_ABORT:
      if (*state_placeholder)
        {
          ssh_xfree(*state_placeholder);
          *state_placeholder = NULL;
        }
      break;
      
    default:
      ssh_fatal("simple_password_client: unknown op %d", (int)op);
    }
}