Example #1
0
/**
 * @brief Check if the server is known.
 *
 * Checks the user's known host file for a previous connection to the
 * current server.
 *
 * @param[in]  session  The SSH session to use.
 *
 * @returns SSH_SERVER_KNOWN_OK:       The server is known and has not changed.\n
 *          SSH_SERVER_KNOWN_CHANGED:  The server key has changed. Either you
 *                                     are under attack or the administrator
 *                                     changed the key. You HAVE to warn the
 *                                     user about a possible attack.\n
 *          SSH_SERVER_FOUND_OTHER:    The server gave use a key of a type while
 *                                     we had an other type recorded. It is a
 *                                     possible attack.\n
 *          SSH_SERVER_NOT_KNOWN:      The server is unknown. User should
 *                                     confirm the MD5 is correct.\n
 *          SSH_SERVER_FILE_NOT_FOUND: The known host file does not exist. The
 *                                     host is thus unknown. File will be
 *                                     created if host key is accepted.\n
 *          SSH_SERVER_ERROR:          Some error happened.
 *
 * @see ssh_get_pubkey_hash()
 *
 * @bug There is no current way to remove or modify an entry into the known
 *      host table.
 */
int ssh_is_server_known(ssh_session session) {
  FILE *file = NULL;
  char **tokens;
  char *host;
  char *hostport;
  const char *type;
  int match;
  int ret = SSH_SERVER_NOT_KNOWN;

  enter_function();

  if (session->knownhosts == NULL) {
    if (ssh_options_apply(session) < 0) {
      ssh_set_error(session, SSH_REQUEST_DENIED,
          "Can't find a known_hosts file");
      leave_function();
      return SSH_SERVER_FILE_NOT_FOUND;
    }
  }

  if (session->host == NULL) {
    ssh_set_error(session, SSH_FATAL,
        "Can't verify host in known hosts if the hostname isn't known");
    leave_function();
    return SSH_SERVER_ERROR;
  }

  if (session->current_crypto == NULL){
  	ssh_set_error(session, SSH_FATAL,
  			"ssh_is_host_known called without cryptographic context");
  	leave_function();
  	return SSH_SERVER_ERROR;
  }
  host = ssh_lowercase(session->host);
  hostport = ssh_hostport(host,session->port);
  if (host == NULL || hostport == NULL) {
    ssh_set_error_oom(session);
    SAFE_FREE(host);
    SAFE_FREE(hostport);
    leave_function();
    return SSH_SERVER_ERROR;
  }

  do {
    tokens = ssh_get_knownhost_line(session, &file,
        session->knownhosts, &type);

    /* End of file, return the current state */
    if (tokens == NULL) {
      break;
    }
    match = match_hashed_host(session, host, tokens[0]);
    if (match == 0){
    	match = match_hostname(hostport, tokens[0], strlen(tokens[0]));
    }
    if (match == 0) {
      match = match_hostname(host, tokens[0], strlen(tokens[0]));
    }
    if (match == 0) {
      match = match_hashed_host(session, hostport, tokens[0]);
    }
    if (match) {
      /* We got a match. Now check the key type */
      if (strcmp(session->current_crypto->server_pubkey_type, type) != 0) {
        /* Different type. We don't override the known_changed error which is
         * more important */
        if (ret != SSH_SERVER_KNOWN_CHANGED)
          ret = SSH_SERVER_FOUND_OTHER;
        tokens_free(tokens);
        continue;
      }
      /* so we know the key type is good. We may get a good key or a bad key. */
      match = check_public_key(session, tokens);
      tokens_free(tokens);

      if (match < 0) {
        ret = SSH_SERVER_ERROR;
        break;
      } else if (match == 1) {
        ret = SSH_SERVER_KNOWN_OK;
        break;
      } else if(match == 0) {
        /* We override the status with the wrong key state */
        ret = SSH_SERVER_KNOWN_CHANGED;
      }
    } else {
      tokens_free(tokens);
    }
  } while (1);

  if ( (ret == SSH_SERVER_NOT_KNOWN) && (session->StrictHostKeyChecking == 0) ) {
    ssh_write_knownhost(session);
    ret = SSH_SERVER_KNOWN_OK;
  }

  SAFE_FREE(host);
  SAFE_FREE(hostport);
  if (file != NULL) {
    fclose(file);
  }

  /* Return the current state at end of file */
  leave_function();
  return ret;
}
Example #2
0
int
parse_body (char *buffer, int length, struct body_msg *body)
{
  char *tmp = buffer;
  char *end = buffer + length;
  int offset;
  int off;
  char *bodyline;
  char *address;
  uint16_t port = 0;
  size_t keylen;
  struct reg_body *tmp_body = NULL;
  struct id_body *tmp_body1 = NULL;
  struct add_body *tmp_body2 = NULL;
  struct key_body *tmp_body3 = NULL;




/* strip the beginning space */
  for (tmp; ((*tmp == '\n') || (*tmp == '\r'))
       && ((tmp - buffer) < length); tmp++);
  offset = tmp - buffer;
  do
    {
      switch (*tmp)
        {
        case 'U':
        case 'u':
          {
            if (!tmp_body)
              tmp_body = create_reg_body ();
            body->type = BODYREG;
            if (off = check ("USER", 4, tmp, end))
              {
                if (LOG_PARSER)
                  log_info ("Body USER found in %u\n", tmp - buffer);
                offset += off;

                /* find the end of this header */
                offset += find_end (tmp + off, end);

                /* find the user address */
                tmp = tmp + off;
                for (tmp; (*tmp == ' ') && ((tmp) < end); tmp++);

                /* copy it to structure */
                tmp_body->user =
                  (char *) strndup (tmp, buffer + offset - tmp - 1);
                tmp_body->user_len = buffer + offset - tmp - 1;

                if (LOG_PARSER)
                  log_info ("The user is : %s\n", tmp_body->user);
                tmp = buffer + offset;
                break;
              }
          }

        case 'A':
        case 'a':
          {
            if (off = check ("ADDRESS", 7, tmp, end))
              {
                if (!tmp_body)
                  tmp_body = create_reg_body ();
                body->type = BODYREG;
                if (LOG_PARSER)
                  log_info ("Body ADDRESS found in %u\n", tmp - buffer);
                offset += off;

                /* find the end of this header */
                offset += find_end (tmp + off, end);

                /* find the IP address */
                tmp = tmp + off;
                for (tmp; (*tmp == ' ') && ((tmp) < end); tmp++);


                /* copy it to structure */
                tmp_body->ip =
                  (char *) strndup (tmp, buffer + offset - tmp - 1);
                tmp_body->ip_len = buffer + offset - tmp - 1;

                if (LOG_PARSER)
                  log_info ("The IP address is : %s\n", tmp_body->ip);
                tmp = buffer + offset;
                break;
              }
            else if (off = check ("ADDER", 5, tmp, end))
              {
                char *data;
                MPI val = mpi_alloc (0);

                if (!tmp_body2)
                  tmp_body2 = create_add_body ();
                body->type = BODYADD;

                if (LOG_PARSER)
                  log_info ("Body Adder found in %u\n", tmp - buffer);

                offset += off;
                /* find the end of this line */
                offset += find_end (tmp + off, end);

                /* find the adder */
                tmp = tmp + off;
                for (tmp; (*tmp == ' ') && ((tmp) < end); tmp++);
                data = m_alloc_clear (buffer + offset - tmp);
                strncpy (data, tmp, buffer + offset - tmp - 1);

                if (mpi_fromstr (val, data))
                  {
                    mpi_free (val);
                    m_free (data);
                    tmp = buffer + offset;
                    break;
                  }
                tmp_body2->adder[tmp_body2->num] = val;
                (tmp_body2->num)++;
                m_free (data);
                tmp = buffer + offset;
                break;
              }
          }

        case 'P':
        case 'p':
          {
            if (off = check ("PORT", 4, tmp, end))
              {
                if (!tmp_body)
                  tmp_body = create_reg_body ();
                body->type = BODYREG;
                if (LOG_PARSER)
                  log_info ("Body PORT found in %u\n", tmp - buffer);
                offset += off;

                /* find the end of this header */
                offset += find_end (tmp + off, end);

                /* find the user address */
                tmp = tmp + off;
                for (tmp; (*tmp == ' ') && ((tmp) < end); tmp++);
                for (tmp; tmp < (buffer + offset - 1); tmp++)
                  {
                    if ((*tmp - 48) <= 9 && (*tmp - 48) >= 0)
                      port = port * 10 + (*tmp - 48);
                    else
                      {
                        log_error ("Error while changing port to number\n");
                        return 1;
                      }
                  }

                /* copy it to structure */
                tmp_body->port = port;

                if (LOG_PARSER)
                  log_info ("The PORT is : %u\n", port);
                tmp = buffer + offset;
                break;
              }
          }

        case '-':
          {
            if (!tmp_body)
              tmp_body = create_reg_body ();
            body->type = BODYREG;
            if (keylen = check_public_key (tmp, end))
              {
                tmp_body->public_key = (char *) strndup (tmp, keylen);
                tmp_body->pk_len = keylen;

                if (LOG_PARSER)
                  log_info ("We found begin pgp length : %u\n"
                            "%s\n", keylen, strndup (tmp, keylen));
                tmp += (keylen + 1);
              }
          }
          break;

        case 'I':
        case 'i':
          {
            uint32_t address;
            char c;
            if (!tmp_body1)
              tmp_body1 = create_id_body ();
            body->type = BODYID;
            if (off = check ("ID_LIST", 7, tmp, end))
              {
                if (LOG_PARSER)
                  log_info ("Body id list found in %u\n", tmp - buffer);
                offset += off;
                /* find the end of this header */
                offset += find_end (tmp + off, end);

                /* find the id */
                tmp = tmp + off;
                for (tmp; (*tmp == ' ') && ((tmp) < end); tmp++);
                if (sscanf (tmp, "%x%c", &address, &c) == 2)
                  {
                    tmp_body1->id[tmp_body1->num] = address;
                    (tmp_body1->num)++;
                  }
                tmp = buffer + offset;
                break;
              }
          }

        case 'K':
        case 'k':
          {
            int length;
            if (!tmp_body3)
              tmp_body3 = create_key_body ();
            body->type = BODYKEY;
            if (off = check ("KEY", 3, tmp, end))
              {
                if (LOG_PARSER)
                  log_info ("Body key found in %u\n", tmp - buffer);
                offset += off;
                /* find the end of this header */
                offset += find_end (tmp + off, end);

                /* find the key */
                tmp = tmp + off;
                for (tmp; (*tmp == ' ') && ((tmp) < end); tmp++);
                length = buffer + offset - tmp;
                tmp_body3->radmsg = m_alloc (length);
                strncpy (tmp_body3->radmsg, tmp, length - 1);
                tmp_body3->radmsg[length] = '\0';
                tmp_body3->length = length - 1;
                tmp = buffer + offset;
                break;
              }
          }
        default:
          {

            log_error
              ("Other body type is found %c. Dont know what to do in %u\n",
               *tmp, tmp - buffer);
            return 1;
          }
        }
    }
  while (*tmp != '\n' && *tmp != '\r' && tmp < end);

  if (body->type == BODYREG)
    {
      /* check if any field is empty, we need a full one */
      if (!tmp_body->user || !tmp_body->ip || (tmp_body->port == 0)
          || !tmp_body->public_key)
        {

          if (tmp_body->user)
            m_free (tmp_body->user);
          if (tmp_body->ip)
            m_free (tmp_body->ip);
          if (tmp_body->public_key)
            m_free (tmp_body->public_key);
          m_free (tmp_body);
          return 1;
        }
      else
        {

          body->msg.regbody = tmp_body;
          tmp_body = NULL;
          return 0;
        }
    }
  else if (body->type == BODYID)
    {
      body->msg.idbody = tmp_body1;
      tmp_body1 = NULL;
      return 0;
    }
  else if (body->type == BODYADD)
    {
      body->msg.addbody = tmp_body2;
      tmp_body2 = NULL;
      return 0;
    }
  else if (body->type == BODYKEY)
    {
      body->msg.keybody = tmp_body3;
      tmp_body2 = NULL;
      return 0;
    }
  return 1;
}
Example #3
0
int
initialize_client_stage1(ClientRealm* cr, SSL_CTX* ctx, unsigned char* buff, char wanttoexit,
    char ignorePublicKeys)
{
  int n, nlen, elen, len, tmp;
  unsigned int olen;
  X509* server_cert;
  const EVP_MD *md;
  EVP_PKEY* pkey;
  EVP_MD_CTX md_ctx;
  unsigned char *encoded = NULL;
  char b64_encoded[100];
  unsigned char *key_buf = NULL;
  assert((ClientRealm_get_tunnelType(cr) == 0) || (ClientRealm_get_tunnelType(cr) == 1));
  switch (ClientRealm_get_tunnelType(cr)) {
    case 0: {
      if (ip_connect(&tmp, ClientRealm_get_serverName(cr),
            ClientRealm_get_managePort(cr),
            ClientRealm_get_ipFamily(cr),
            ClientRealm_get_localName(cr),
            ClientRealm_get_localPort(cr))) {
#ifdef AF_INET6
        aflog(LOG_T_INIT, LOG_I_CRIT,
            "tcp_connect_%s error for %s, %s",
            (ClientRealm_get_ipFamily(cr) & 0x02) ?
              "ipv4":(ClientRealm_get_ipFamily(cr) & 0x04) ?
                "ipv6":"unspec", ClientRealm_get_serverName(cr), ClientRealm_get_managePort(cr));
#else
        aflog(LOG_T_INIT, LOG_I_CRIT,
            "tcp_connect error for %s, %s", ClientRealm_get_serverName(cr), ClientRealm_get_managePort(cr));
#endif
        if (wanttoexit) {
          exit(1);
        }
        else {
          return 1;
        }
      } 
      SslFd_set_fd(ClientRealm_get_masterSslFd(cr), tmp);
      break;
            }
#ifdef HAVE_LIBPTHREAD 
    case 1: {
      if (initialize_http_proxy_client(&tmp, cr, ctx)) {
#ifdef AF_INET6
        aflog(LOG_T_INIT, LOG_I_CRIT,
            "http_proxy_connect_%s error for %s, %s (proxy: %s, %s)",
            (ClientRealm_get_ipFamily(cr) & 0x02) ?
              "ipv4":(ClientRealm_get_ipFamily(cr) & 0x04) ?
                "ipv6":"unspec", ClientRealm_get_serverName(cr),
                ClientRealm_get_managePort(cr),
                HttpProxyOptions_get_proxyname(ClientRealm_get_httpProxyOptions(cr)),
                HttpProxyOptions_get_proxyport(ClientRealm_get_httpProxyOptions(cr)));
#else 
        aflog(LOG_T_INIT, LOG_I_CRIT,
            "http_proxy_connect error for %s, %s (proxy: %s, %s)", ClientRealm_get_serverName(cr),
            ClientRealm_get_managePort(cr),
            HttpProxyOptions_get_proxyname(ClientRealm_get_httpProxyOptions(cr)),
            HttpProxyOptions_get_proxyport(ClientRealm_get_httpProxyOptions(cr)));
#endif 
        if (wanttoexit) {
          exit(1);
        }
        else {
          return 1;
        }
      }
      SslFd_set_fd(ClientRealm_get_masterSslFd(cr), tmp);
      break;
            }
#endif
    default: {
               aflog(LOG_T_INIT, LOG_I_CRIT,
                   "Unknown tunnel type");
               if (wanttoexit) {
                 exit(1);
               }
               else {
                 return 1;
               }
               break;
             }
  }
  
  SslFd_set_ssl(ClientRealm_get_masterSslFd(cr), SSL_new(ctx));
  if (SSL_set_fd(SslFd_get_ssl(ClientRealm_get_masterSslFd(cr)),
        SslFd_get_fd(ClientRealm_get_masterSslFd(cr))) != 1) {
    aflog(LOG_T_INIT, LOG_I_CRIT,
        "Problem with initializing ssl... exiting");
    if (wanttoexit) {
      exit(1);
    }
    else {
      close(SslFd_get_fd(ClientRealm_get_masterSslFd(cr)));
      return 2;
    }
  }

  alarm(60);
  
  aflog(LOG_T_INIT, LOG_I_INFO,
      "Trying SSL_connect");
  if ((n = SSL_connect(SslFd_get_ssl(ClientRealm_get_masterSslFd(cr)))) == 1) {
    if ((server_cert = SSL_get_peer_certificate(SslFd_get_ssl(ClientRealm_get_masterSslFd(cr)))) == NULL) {
      aflog(LOG_T_MAIN, LOG_I_CRIT,
          "Server did not present a certificate... exiting");
      exit(1);
    }
    /* FIXME: change almost everything here */
    pkey = X509_get_pubkey(server_cert);
    if (pkey == NULL) {
      aflog(LOG_T_MAIN, LOG_I_CRIT,
          "Server's public key is invalid... exiting");
      exit(1);
    }
    nlen = BN_num_bytes(pkey->pkey.rsa->n);
    elen = BN_num_bytes(pkey->pkey.rsa->e);
    len = nlen + elen;
    key_buf = malloc(len);
    if (key_buf == NULL) {
      aflog(LOG_T_MAIN, LOG_I_CRIT,
          "Cannot allocate memory for server's public key checking... exiting");
      exit(1);
    }
    BN_bn2bin(pkey->pkey.rsa->n, key_buf);
    BN_bn2bin(pkey->pkey.rsa->e, key_buf + nlen);
    md = EVP_md5();
    EVP_DigestInit(&md_ctx, md);
    EVP_DigestUpdate(&md_ctx, key_buf, len);
    encoded = calloc(1, EVP_MAX_MD_SIZE+1);
    if (encoded == NULL) {
      aflog(LOG_T_MAIN, LOG_I_CRIT,
          "Cannot allocate memory for server's public key checking... exiting");
      exit(1);
    }
    EVP_DigestFinal(&md_ctx, encoded, &olen);

    if (b64_ntop(encoded, olen, b64_encoded, 100) == -1) {
      aflog(LOG_T_MAIN, LOG_I_CRIT,
          "Problem with base64 encoding... exiting");
      exit(1);
    }
    
    switch (check_public_key(get_store_filename(), ClientRealm_get_serverName(cr), b64_encoded)) {
      case SSL_PUBLIC_KEY_VALID:
        /* public key is ok - do nothing */
        break;
      case SSL_PUBLIC_KEY_NOT_KNOWN:
        aflog(LOG_T_MAIN, LOG_I_WARNING,
            "WARNING: implicitly added new server's public key to the list of known hosts");
        add_public_key(get_store_filename(), ClientRealm_get_serverName(cr), b64_encoded);
        break;
      default:
        if (ignorePublicKeys) {
          aflog(LOG_T_MAIN, LOG_I_WARNING,
              "WARNING: Invalid server's public key... ignoring");
        }
        else {
          aflog(LOG_T_MAIN, LOG_I_CRIT,
              "Invalid server's public key... exiting");
          aflog(LOG_T_MAIN, LOG_I_CRIT,
              "Please delete conflicting entry in %s or use '--ignorepkeys' option",
              get_store_filename());
          exit(1);
        }
    }

    memset(key_buf, 0, len);
    free(key_buf);
    free(encoded);

    aflog(LOG_T_INIT, LOG_I_INFO,
        "SSL_connect successful");
  }
  else {
    alarm(0);
    aflog(LOG_T_INIT, LOG_I_CRIT,
        "SSL_connect has failed (%d | %d)... exiting", n,
        SSL_get_error(SslFd_get_ssl(ClientRealm_get_masterSslFd(cr)), n));
    if (wanttoexit) {
      exit(1);
    }
    else {
      close(SslFd_get_fd(ClientRealm_get_masterSslFd(cr)));
      return 3;
    }
  }
  alarm(0);

  buff[0] = AF_S_LOGIN;
  buff[1] = ClientRealm_get_password(cr)[0];
  buff[2] = ClientRealm_get_password(cr)[1];
  buff[3] = ClientRealm_get_password(cr)[2];
  buff[4] = ClientRealm_get_password(cr)[3];

  return 0;
}