Blame src/client.c

Packit Service 31306d
/*
Packit Service 31306d
 * client.c - SSH client functions
Packit Service 31306d
 *
Packit Service 31306d
 * This file is part of the SSH Library
Packit Service 31306d
 *
Packit Service 31306d
 * Copyright (c) 2003-2013 by Aris Adamantiadis
Packit Service 31306d
 *
Packit Service 31306d
 * The SSH Library is free software; you can redistribute it and/or modify
Packit Service 31306d
 * it under the terms of the GNU Lesser General Public License as published by
Packit Service 31306d
 * the Free Software Foundation; either version 2.1 of the License, or (at your
Packit Service 31306d
 * option) any later version.
Packit Service 31306d
 *
Packit Service 31306d
 * The SSH Library is distributed in the hope that it will be useful, but
Packit Service 31306d
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
Packit Service 31306d
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
Packit Service 31306d
 * License for more details.
Packit Service 31306d
 *
Packit Service 31306d
 * You should have received a copy of the GNU Lesser General Public License
Packit Service 31306d
 * along with the SSH Library; see the file COPYING.  If not, write to
Packit Service 31306d
 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
Packit Service 31306d
 * MA 02111-1307, USA.
Packit Service 31306d
 */
Packit Service 31306d
Packit Service 31306d
#include "config.h"
Packit Service 31306d
Packit Service 31306d
#include <stdio.h>
Packit Service 31306d
Packit Service 31306d
#ifndef _WIN32
Packit Service 31306d
#include <netinet/in.h>
Packit Service 31306d
#include <arpa/inet.h>
Packit Service 31306d
#endif
Packit Service 31306d
Packit Service 31306d
#include "libssh/priv.h"
Packit Service 31306d
#include "libssh/ssh2.h"
Packit Service 31306d
#include "libssh/buffer.h"
Packit Service 31306d
#include "libssh/packet.h"
Packit Service 31306d
#include "libssh/options.h"
Packit Service 31306d
#include "libssh/socket.h"
Packit Service 31306d
#include "libssh/session.h"
Packit Service 31306d
#include "libssh/dh.h"
Packit Service 31306d
#ifdef WITH_GEX
Packit Service 31306d
#include "libssh/dh-gex.h"
Packit Service 31306d
#endif /* WITH_GEX */
Packit Service 31306d
#include "libssh/ecdh.h"
Packit Service 31306d
#include "libssh/threads.h"
Packit Service 31306d
#include "libssh/misc.h"
Packit Service 31306d
#include "libssh/pki.h"
Packit Service 31306d
#include "libssh/kex.h"
Packit Service 31306d
Packit Service 31306d
#define set_status(session, status) do {\
Packit Service 31306d
        if (session->common.callbacks && session->common.callbacks->connect_status_function) \
Packit Service 31306d
            session->common.callbacks->connect_status_function(session->common.callbacks->userdata, status); \
Packit Service 31306d
    } while (0)
Packit Service 31306d
Packit Service 31306d
/**
Packit Service 31306d
 * @internal
Packit Service 31306d
 * @brief Callback to be called when the socket is connected or had a
Packit Service 31306d
 * connection error. Changes the state of the session and updates the error
Packit Service 31306d
 * message.
Packit Service 31306d
 * @param code one of SSH_SOCKET_CONNECTED_OK or SSH_SOCKET_CONNECTED_ERROR
Packit Service 31306d
 * @param user is a pointer to session
Packit Service 31306d
 */
Packit Service 31306d
static void socket_callback_connected(int code, int errno_code, void *user){
Packit Service 31306d
	ssh_session session=(ssh_session)user;
Packit Service 31306d
Packit Service 31306d
	if (session->session_state != SSH_SESSION_STATE_CONNECTING &&
Packit Service 31306d
	    session->session_state != SSH_SESSION_STATE_SOCKET_CONNECTED)
Packit Service 31306d
	{
Packit Service 31306d
		ssh_set_error(session,SSH_FATAL, "Wrong state in socket_callback_connected : %d",
Packit Service 31306d
				session->session_state);
Packit Service 31306d
Packit Service 31306d
		return;
Packit Service 31306d
	}
Packit Service 31306d
Packit Service 31306d
	SSH_LOG(SSH_LOG_RARE,"Socket connection callback: %d (%d)",code, errno_code);
Packit Service 31306d
	if(code == SSH_SOCKET_CONNECTED_OK)
Packit Service 31306d
		session->session_state=SSH_SESSION_STATE_SOCKET_CONNECTED;
Packit Service 31306d
	else {
Packit Service 31306d
		session->session_state=SSH_SESSION_STATE_ERROR;
Packit Service 31306d
		ssh_set_error(session,SSH_FATAL,"%s",strerror(errno_code));
Packit Service 31306d
	}
Packit Service 31306d
	session->ssh_connection_callback(session);
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
/**
Packit Service 31306d
 * @internal
Packit Service 31306d
 *
Packit Service 31306d
 * @brief Gets the banner from socket and saves it in session.
Packit Service 31306d
 * Updates the session state
Packit Service 31306d
 *
Packit Service 31306d
 * @param  data pointer to the beginning of header
Packit Service 31306d
 * @param  len size of the banner
Packit Service 31306d
 * @param  user is a pointer to session
Packit Service 31306d
 * @returns Number of bytes processed, or zero if the banner is not complete.
Packit Service 31306d
 */
Packit Service 31306d
static int callback_receive_banner(const void *data, size_t len, void *user)
Packit Service 31306d
{
Packit Service 31306d
    char *buffer = (char *)data;
Packit Service 31306d
    ssh_session session=(ssh_session) user;
Packit Service 31306d
    char *str = NULL;
Packit Service 31306d
    size_t i;
Packit Service 31306d
    int ret=0;
Packit Service 31306d
Packit Service 31306d
    if (session->session_state != SSH_SESSION_STATE_SOCKET_CONNECTED) {
Packit Service 31306d
        ssh_set_error(session,SSH_FATAL,
Packit Service 31306d
                      "Wrong state in callback_receive_banner : %d",
Packit Service 31306d
                      session->session_state);
Packit Service 31306d
Packit Service 31306d
        return SSH_ERROR;
Packit Service 31306d
    }
Packit Service 31306d
    for (i = 0; i < len; ++i) {
Packit Service 31306d
#ifdef WITH_PCAP
Packit Service 31306d
        if (session->pcap_ctx && buffer[i] == '\n') {
Packit Service 31306d
            ssh_pcap_context_write(session->pcap_ctx,
Packit Service 31306d
                                   SSH_PCAP_DIR_IN,
Packit Service 31306d
                                   buffer,i+1,
Packit Service 31306d
                                   i+1);
Packit Service 31306d
        }
Packit Service 31306d
#endif
Packit Service 31306d
        if (buffer[i] == '\r') {
Packit Service 31306d
            buffer[i] = '\0';
Packit Service 31306d
        }
Packit Service 31306d
        if (buffer[i] == '\n') {
Packit Service 31306d
            int cmp;
Packit Service 31306d
Packit Service 31306d
            buffer[i] = '\0';
Packit Service 31306d
Packit Service 31306d
            /* The server MAY send other lines of data... */
Packit Service 31306d
            cmp = strncmp(buffer, "SSH-", 4);
Packit Service 31306d
            if (cmp == 0) {
Packit Service 31306d
                str = strdup(buffer);
Packit Service 31306d
                if (str == NULL) {
Packit Service 31306d
                    return SSH_ERROR;
Packit Service 31306d
                }
Packit Service 31306d
                /* number of bytes read */
Packit Service 31306d
                ret = i + 1;
Packit Service 31306d
                session->serverbanner = str;
Packit Service 31306d
                session->session_state = SSH_SESSION_STATE_BANNER_RECEIVED;
Packit Service 31306d
                SSH_LOG(SSH_LOG_PACKET, "Received banner: %s", str);
Packit Service 31306d
                session->ssh_connection_callback(session);
Packit Service 31306d
Packit Service 31306d
                return ret;
Packit Service 31306d
            } else {
Packit Service 31306d
                SSH_LOG(SSH_LOG_DEBUG,
Packit Service 31306d
                        "ssh_protocol_version_exchange: %s",
Packit Service 31306d
                        buffer);
Packit Service 31306d
                ret = i + 1;
Packit Service 31306d
                break;
Packit Service 31306d
            }
Packit Service 31306d
        }
Packit Service 31306d
        /* According to RFC 4253 the max banner length is 255 */
Packit Service 31306d
        if (i > 255) {
Packit Service 31306d
            /* Too big banner */
Packit Service 31306d
            session->session_state=SSH_SESSION_STATE_ERROR;
Packit Service 31306d
            ssh_set_error(session,
Packit Service 31306d
                          SSH_FATAL,
Packit Service 31306d
                          "Receiving banner: too large banner");
Packit Service 31306d
Packit Service 31306d
            return 0;
Packit Service 31306d
        }
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    return ret;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
/** @internal
Packit Service 31306d
 * @brief Sends a SSH banner to the server.
Packit Service 31306d
 *
Packit Service 31306d
 * @param session      The SSH session to use.
Packit Service 31306d
 *
Packit Service 31306d
 * @param server       Send client or server banner.
Packit Service 31306d
 *
Packit Service 31306d
 * @return 0 on success, < 0 on error.
Packit Service 31306d
 */
Packit Service 31306d
int ssh_send_banner(ssh_session session, int server)
Packit Service 31306d
{
Packit Service 31306d
    const char *banner = CLIENT_BANNER_SSH2;
Packit Service 31306d
    const char *terminator = "\r\n";
Packit Service 31306d
    /* The maximum banner length is 255 for SSH2 */
Packit Service 31306d
    char buffer[256] = {0};
Packit Service 31306d
    size_t len;
Packit Service 31306d
    int rc = SSH_ERROR;
Packit Service 31306d
Packit Service 31306d
    if (server == 1) {
Packit Service 31306d
        if (session->opts.custombanner == NULL){
Packit Service 31306d
            session->serverbanner = strdup(banner);
Packit Service 31306d
            if (session->serverbanner == NULL) {
Packit Service 31306d
                goto end;
Packit Service 31306d
            }
Packit Service 31306d
        } else {
Packit Service 31306d
            len = strlen(session->opts.custombanner);
Packit Service 31306d
            session->serverbanner = malloc(len + 8 + 1);
Packit Service 31306d
            if(session->serverbanner == NULL) {
Packit Service 31306d
                goto end;
Packit Service 31306d
            }
Packit Service 31306d
            snprintf(session->serverbanner,
Packit Service 31306d
                     len + 8 + 1,
Packit Service 31306d
                     "SSH-2.0-%s",
Packit Service 31306d
                     session->opts.custombanner);
Packit Service 31306d
        }
Packit Service 31306d
Packit Service 31306d
        snprintf(buffer,
Packit Service 31306d
                 sizeof(buffer),
Packit Service 31306d
                 "%s%s",
Packit Service 31306d
                 session->serverbanner,
Packit Service 31306d
                 terminator);
Packit Service 31306d
    } else {
Packit Service 31306d
        session->clientbanner = strdup(banner);
Packit Service 31306d
        if (session->clientbanner == NULL) {
Packit Service 31306d
            goto end;
Packit Service 31306d
        }
Packit Service 31306d
Packit Service 31306d
        snprintf(buffer,
Packit Service 31306d
                 sizeof(buffer),
Packit Service 31306d
                 "%s%s",
Packit Service 31306d
                 session->clientbanner,
Packit Service 31306d
                 terminator);
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    rc = ssh_socket_write(session->socket, buffer, strlen(buffer));
Packit Service 31306d
    if (rc == SSH_ERROR) {
Packit Service 31306d
        goto end;
Packit Service 31306d
    }
Packit Service 31306d
#ifdef WITH_PCAP
Packit Service 31306d
    if (session->pcap_ctx != NULL) {
Packit Service 31306d
        ssh_pcap_context_write(session->pcap_ctx,
Packit Service 31306d
                               SSH_PCAP_DIR_OUT,
Packit Service 31306d
                               buffer,
Packit Service 31306d
                               strlen(buffer),
Packit Service 31306d
                               strlen(buffer));
Packit Service 31306d
    }
Packit Service 31306d
#endif
Packit Service 31306d
Packit Service 31306d
    rc = SSH_OK;
Packit Service 31306d
end:
Packit Service 31306d
    return rc;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
/** @internal
Packit Service 31306d
 * @brief launches the DH handshake state machine
Packit Service 31306d
 * @param session session handle
Packit Service 31306d
 * @returns SSH_OK or SSH_ERROR
Packit Service 31306d
 * @warning this function returning is no proof that DH handshake is
Packit Service 31306d
 * completed
Packit Service 31306d
 */
Packit Service 31306d
static int dh_handshake(ssh_session session) {
Packit Service 31306d
Packit Service 31306d
  int rc = SSH_AGAIN;
Packit Service 31306d
Packit Service 31306d
  switch (session->dh_handshake_state) {
Packit Service 31306d
    case DH_STATE_INIT:
Packit Service 31306d
      switch(session->next_crypto->kex_type){
Packit Service 31306d
        case SSH_KEX_DH_GROUP1_SHA1:
Packit Service 31306d
        case SSH_KEX_DH_GROUP14_SHA1:
Packit Service 31306d
        case SSH_KEX_DH_GROUP14_SHA256:
Packit Service 31306d
        case SSH_KEX_DH_GROUP16_SHA512:
Packit Service 31306d
        case SSH_KEX_DH_GROUP18_SHA512:
Packit Service 31306d
          rc = ssh_client_dh_init(session);
Packit Service 31306d
          break;
Packit Service 31306d
#ifdef WITH_GEX
Packit Service 31306d
        case SSH_KEX_DH_GEX_SHA1:
Packit Service 31306d
        case SSH_KEX_DH_GEX_SHA256:
Packit Service 31306d
          rc = ssh_client_dhgex_init(session);
Packit Service 31306d
          break;
Packit Service 31306d
#endif /* WITH_GEX */
Packit Service 31306d
#ifdef HAVE_ECDH
Packit Service 31306d
        case SSH_KEX_ECDH_SHA2_NISTP256:
Packit Service 31306d
        case SSH_KEX_ECDH_SHA2_NISTP384:
Packit Service 31306d
        case SSH_KEX_ECDH_SHA2_NISTP521:
Packit Service 31306d
          rc = ssh_client_ecdh_init(session);
Packit Service 31306d
          break;
Packit Service 31306d
#endif
Packit Service 31306d
#ifdef HAVE_CURVE25519
Packit Service 31306d
        case SSH_KEX_CURVE25519_SHA256:
Packit Service 31306d
        case SSH_KEX_CURVE25519_SHA256_LIBSSH_ORG:
Packit Service 31306d
          rc = ssh_client_curve25519_init(session);
Packit Service 31306d
          break;
Packit Service 31306d
#endif
Packit Service 31306d
        default:
Packit Service 31306d
          rc = SSH_ERROR;
Packit Service 31306d
      }
Packit Service 31306d
Packit Service 31306d
      break;
Packit Service 31306d
    case DH_STATE_INIT_SENT:
Packit Service 31306d
    	/* wait until ssh_packet_dh_reply is called */
Packit Service 31306d
    	break;
Packit Service 31306d
    case DH_STATE_NEWKEYS_SENT:
Packit Service 31306d
    	/* wait until ssh_packet_newkeys is called */
Packit Service 31306d
    	break;
Packit Service 31306d
    case DH_STATE_FINISHED:
Packit Service 31306d
      return SSH_OK;
Packit Service 31306d
    default:
Packit Service 31306d
      ssh_set_error(session, SSH_FATAL, "Invalid state in dh_handshake(): %d",
Packit Service 31306d
          session->dh_handshake_state);
Packit Service 31306d
Packit Service 31306d
      return SSH_ERROR;
Packit Service 31306d
  }
Packit Service 31306d
Packit Service 31306d
  return rc;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
static int ssh_service_request_termination(void *s){
Packit Service 31306d
  ssh_session session = (ssh_session)s;
Packit Service 31306d
  if(session->session_state == SSH_SESSION_STATE_ERROR ||
Packit Service 31306d
      session->auth.service_state != SSH_AUTH_SERVICE_SENT)
Packit Service 31306d
    return 1;
Packit Service 31306d
  else
Packit Service 31306d
    return 0;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
/**
Packit Service 31306d
 * @internal
Packit Service 31306d
 *
Packit Service 31306d
 * @brief Request a service from the SSH server.
Packit Service 31306d
 *
Packit Service 31306d
 * Service requests are for example: ssh-userauth, ssh-connection, etc.
Packit Service 31306d
 *
Packit Service 31306d
 * @param  session      The session to use to ask for a service request.
Packit Service 31306d
 * @param  service      The service request.
Packit Service 31306d
 *
Packit Service 31306d
 * @return SSH_OK on success
Packit Service 31306d
 * @return SSH_ERROR on error
Packit Service 31306d
 * @return SSH_AGAIN No response received yet
Packit Service 31306d
 * @bug actually only works with ssh-userauth
Packit Service 31306d
 */
Packit Service 31306d
int ssh_service_request(ssh_session session, const char *service) {
Packit Service 31306d
  int rc=SSH_ERROR;
Packit Service 31306d
Packit Service 31306d
  if(session->auth.service_state != SSH_AUTH_SERVICE_NONE)
Packit Service 31306d
    goto pending;
Packit Service 31306d
Packit Service 31306d
  rc = ssh_buffer_pack(session->out_buffer,
Packit Service 31306d
                       "bs",
Packit Service 31306d
                       SSH2_MSG_SERVICE_REQUEST,
Packit Service 31306d
                       service);
Packit Service 31306d
  if (rc != SSH_OK){
Packit Service 31306d
      ssh_set_error_oom(session);
Packit Service 31306d
      return SSH_ERROR;
Packit Service 31306d
  }
Packit Service 31306d
  session->auth.service_state = SSH_AUTH_SERVICE_SENT;
Packit Service 31306d
  if (ssh_packet_send(session) == SSH_ERROR) {
Packit Service 31306d
    ssh_set_error(session, SSH_FATAL,
Packit Service 31306d
        "Sending SSH2_MSG_SERVICE_REQUEST failed.");
Packit Service 31306d
      return SSH_ERROR;
Packit Service 31306d
  }
Packit Service 31306d
Packit Service 31306d
  SSH_LOG(SSH_LOG_PACKET,
Packit Service 31306d
      "Sent SSH_MSG_SERVICE_REQUEST (service %s)", service);
Packit Service 31306d
pending:
Packit Service 31306d
  rc=ssh_handle_packets_termination(session,SSH_TIMEOUT_USER,
Packit Service 31306d
      ssh_service_request_termination, session);
Packit Service 31306d
  if (rc == SSH_ERROR) {
Packit Service 31306d
      return SSH_ERROR;
Packit Service 31306d
  }
Packit Service 31306d
  switch(session->auth.service_state) {
Packit Service 31306d
  case SSH_AUTH_SERVICE_DENIED:
Packit Service 31306d
    ssh_set_error(session,SSH_FATAL,"ssh_auth_service request denied");
Packit Service 31306d
    break;
Packit Service 31306d
  case SSH_AUTH_SERVICE_ACCEPTED:
Packit Service 31306d
    rc=SSH_OK;
Packit Service 31306d
    break;
Packit Service 31306d
  case SSH_AUTH_SERVICE_SENT:
Packit Service 31306d
    rc=SSH_AGAIN;
Packit Service 31306d
    break;
Packit Service 31306d
  case SSH_AUTH_SERVICE_NONE:
Packit Service 31306d
    rc=SSH_ERROR;
Packit Service 31306d
    break;
Packit Service 31306d
  }
Packit Service 31306d
Packit Service 31306d
  return rc;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
/**
Packit Service 31306d
 * @addtogroup libssh_session
Packit Service 31306d
 *
Packit Service 31306d
 * @{
Packit Service 31306d
 */
Packit Service 31306d
Packit Service 31306d
/**
Packit Service 31306d
 * @internal
Packit Service 31306d
 *
Packit Service 31306d
 * @brief A function to be called each time a step has been done in the
Packit Service 31306d
 * connection.
Packit Service 31306d
 */
Packit Service 31306d
static void ssh_client_connection_callback(ssh_session session)
Packit Service 31306d
{
Packit Service 31306d
    int rc;
Packit Service 31306d
Packit Service 31306d
    switch(session->session_state) {
Packit Service 31306d
        case SSH_SESSION_STATE_NONE:
Packit Service 31306d
        case SSH_SESSION_STATE_CONNECTING:
Packit Service 31306d
            break;
Packit Service 31306d
        case SSH_SESSION_STATE_SOCKET_CONNECTED:
Packit Service 31306d
            ssh_set_fd_towrite(session);
Packit Service 31306d
            ssh_send_banner(session, 0);
Packit Service 31306d
Packit Service 31306d
            break;
Packit Service 31306d
        case SSH_SESSION_STATE_BANNER_RECEIVED:
Packit Service 31306d
            if (session->serverbanner == NULL) {
Packit Service 31306d
                goto error;
Packit Service 31306d
            }
Packit Service 31306d
            set_status(session, 0.4f);
Packit Service 31306d
            SSH_LOG(SSH_LOG_PROTOCOL,
Packit Service 31306d
                    "SSH server banner: %s", session->serverbanner);
Packit Service 31306d
Packit Service 31306d
            /* Here we analyze the different protocols the server allows. */
Packit Service 31306d
            rc = ssh_analyze_banner(session, 0);
Packit Service 31306d
            if (rc < 0) {
Packit Service 31306d
                ssh_set_error(session, SSH_FATAL,
Packit Service 31306d
                        "No version of SSH protocol usable (banner: %s)",
Packit Service 31306d
                        session->serverbanner);
Packit Service 31306d
                goto error;
Packit Service 31306d
            }
Packit Service 31306d
Packit Service 31306d
            ssh_packet_register_socket_callback(session, session->socket);
Packit Service 31306d
Packit Service 31306d
            ssh_packet_set_default_callbacks(session);
Packit Service 31306d
            session->session_state = SSH_SESSION_STATE_INITIAL_KEX;
Packit Service 31306d
            rc = ssh_set_client_kex(session);
Packit Service 31306d
            if (rc != SSH_OK) {
Packit Service 31306d
                goto error;
Packit Service 31306d
            }
Packit Service 31306d
            rc = ssh_send_kex(session, 0);
Packit Service 31306d
            if (rc < 0) {
Packit Service 31306d
                goto error;
Packit Service 31306d
            }
Packit Service 31306d
            set_status(session, 0.5f);
Packit Service 31306d
Packit Service 31306d
            break;
Packit Service 31306d
        case SSH_SESSION_STATE_INITIAL_KEX:
Packit Service 31306d
            /* TODO: This state should disappear in favor of get_key handle */
Packit Service 31306d
            break;
Packit Service 31306d
        case SSH_SESSION_STATE_KEXINIT_RECEIVED:
Packit Service 31306d
            set_status(session,0.6f);
Packit Service 31306d
            ssh_list_kex(&session->next_crypto->server_kex);
Packit Service 31306d
            if (session->next_crypto->client_kex.methods[0] == NULL) {
Packit Service 31306d
                /* in rekeying state if next_crypto client_kex is empty */
Packit Service 31306d
                rc = ssh_set_client_kex(session);
Packit Service 31306d
                if (rc != SSH_OK) {
Packit Service 31306d
                    goto error;
Packit Service 31306d
                }
Packit Service 31306d
                rc = ssh_send_kex(session, 0);
Packit Service 31306d
                if (rc < 0) {
Packit Service 31306d
                    goto error;
Packit Service 31306d
                }
Packit Service 31306d
            }
Packit Service 31306d
            if (ssh_kex_select_methods(session) == SSH_ERROR)
Packit Service 31306d
                goto error;
Packit Service 31306d
            set_status(session,0.8f);
Packit Service 31306d
            session->session_state=SSH_SESSION_STATE_DH;
Packit Service 31306d
            if (dh_handshake(session) == SSH_ERROR) {
Packit Service 31306d
                goto error;
Packit Service 31306d
            }
Packit Service 31306d
            /* FALL THROUGH */
Packit Service 31306d
        case SSH_SESSION_STATE_DH:
Packit Service 31306d
            if(session->dh_handshake_state==DH_STATE_FINISHED){
Packit Service 31306d
                set_status(session,1.0f);
Packit Service 31306d
                session->connected = 1;
Packit Service 31306d
                if (session->flags & SSH_SESSION_FLAG_AUTHENTICATED)
Packit Service 31306d
                    session->session_state = SSH_SESSION_STATE_AUTHENTICATED;
Packit Service 31306d
                else
Packit Service 31306d
                    session->session_state=SSH_SESSION_STATE_AUTHENTICATING;
Packit Service 31306d
            }
Packit Service 31306d
            break;
Packit Service 31306d
        case SSH_SESSION_STATE_AUTHENTICATING:
Packit Service 31306d
            break;
Packit Service 31306d
        case SSH_SESSION_STATE_ERROR:
Packit Service 31306d
            goto error;
Packit Service 31306d
        default:
Packit Service 31306d
            ssh_set_error(session,SSH_FATAL,"Invalid state %d",session->session_state);
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    return;
Packit Service 31306d
error:
Packit Service 31306d
    ssh_socket_close(session->socket);
Packit Service 31306d
    session->alive = 0;
Packit Service 31306d
    session->session_state=SSH_SESSION_STATE_ERROR;
Packit Service 31306d
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
/** @internal
Packit Service 31306d
 * @brief describe under which conditions the ssh_connect function may stop
Packit Service 31306d
 */
Packit Service 31306d
static int ssh_connect_termination(void *user){
Packit Service 31306d
  ssh_session session = (ssh_session)user;
Packit Service 31306d
  switch(session->session_state){
Packit Service 31306d
    case SSH_SESSION_STATE_ERROR:
Packit Service 31306d
    case SSH_SESSION_STATE_AUTHENTICATING:
Packit Service 31306d
    case SSH_SESSION_STATE_DISCONNECTED:
Packit Service 31306d
      return 1;
Packit Service 31306d
    default:
Packit Service 31306d
      return 0;
Packit Service 31306d
  }
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
/**
Packit Service 31306d
 * @brief Connect to the ssh server.
Packit Service 31306d
 *
Packit Service 31306d
 * @param[in]  session  The ssh session to connect.
Packit Service 31306d
 *
Packit Service 31306d
 * @returns             SSH_OK on success, SSH_ERROR on error.
Packit Service 31306d
 * @returns             SSH_AGAIN, if the session is in nonblocking mode,
Packit Service 31306d
 *                      and call must be done again.
Packit Service 31306d
 *
Packit Service 31306d
 * @see ssh_new()
Packit Service 31306d
 * @see ssh_disconnect()
Packit Service 31306d
 */
Packit Service 31306d
int ssh_connect(ssh_session session) {
Packit Service 31306d
  int ret;
Packit Service 31306d
Packit Service 31306d
  if (session == NULL) {
Packit Service 31306d
    return SSH_ERROR;
Packit Service 31306d
  }
Packit Service 31306d
Packit Service 31306d
  switch(session->pending_call_state){
Packit Service 31306d
  case SSH_PENDING_CALL_NONE:
Packit Service 31306d
  	break;
Packit Service 31306d
  case SSH_PENDING_CALL_CONNECT:
Packit Service 31306d
  	goto pending;
Packit Service 31306d
  default:
Packit Service 31306d
  	ssh_set_error(session,SSH_FATAL,"Bad call during pending SSH call in ssh_connect");
Packit Service 31306d
Packit Service 31306d
  	return SSH_ERROR;
Packit Service 31306d
  }
Packit Service 31306d
  session->alive = 0;
Packit Service 31306d
  session->client = 1;
Packit Service 31306d
Packit Service 31306d
  if (session->opts.fd == SSH_INVALID_SOCKET &&
Packit Service 31306d
      session->opts.host == NULL &&
Packit Service 31306d
      session->opts.ProxyCommand == NULL) {
Packit Service 31306d
    ssh_set_error(session, SSH_FATAL, "Hostname required");
Packit Service 31306d
    return SSH_ERROR;
Packit Service 31306d
  }
Packit Service 31306d
Packit Service 31306d
  /* If the system configuration files were not yet processed, do it now */
Packit Service 31306d
  if (!session->opts.config_processed) {
Packit Service 31306d
    ret = ssh_options_parse_config(session, NULL);
Packit Service 31306d
    if (ret != 0) {
Packit Service 31306d
      ssh_set_error(session, SSH_FATAL,
Packit Service 31306d
                    "Failed to process system configuration files");
Packit Service 31306d
      return SSH_ERROR;
Packit Service 31306d
    }
Packit Service 31306d
  }
Packit Service 31306d
Packit Service 31306d
  ret = ssh_options_apply(session);
Packit Service 31306d
  if (ret < 0) {
Packit Service 31306d
      ssh_set_error(session, SSH_FATAL, "Couldn't apply options");
Packit Service 31306d
      return SSH_ERROR;
Packit Service 31306d
  }
Packit Service 31306d
Packit Service 31306d
  SSH_LOG(SSH_LOG_PROTOCOL,
Packit Service 31306d
          "libssh %s, using threading %s",
Packit Service 31306d
          ssh_copyright(),
Packit Service 31306d
          ssh_threads_get_type());
Packit Service 31306d
Packit Service 31306d
  session->ssh_connection_callback = ssh_client_connection_callback;
Packit Service 31306d
  session->session_state=SSH_SESSION_STATE_CONNECTING;
Packit Service 31306d
  ssh_socket_set_callbacks(session->socket,&session->socket_callbacks);
Packit Service 31306d
  session->socket_callbacks.connected=socket_callback_connected;
Packit Service 31306d
  session->socket_callbacks.data=callback_receive_banner;
Packit Service 31306d
  session->socket_callbacks.exception=ssh_socket_exception_callback;
Packit Service 31306d
  session->socket_callbacks.userdata=session;
Packit Service 31306d
  if (session->opts.fd != SSH_INVALID_SOCKET) {
Packit Service 31306d
    session->session_state=SSH_SESSION_STATE_SOCKET_CONNECTED;
Packit Service 31306d
    ssh_socket_set_fd(session->socket, session->opts.fd);
Packit Service 31306d
    ret=SSH_OK;
Packit Service 31306d
#ifndef _WIN32
Packit Service 31306d
  } else if (session->opts.ProxyCommand != NULL){
Packit Service 31306d
    ret = ssh_socket_connect_proxycommand(session->socket,
Packit Service 31306d
                                          session->opts.ProxyCommand);
Packit Service 31306d
#endif
Packit Service 31306d
  } else {
Packit Service 31306d
    ret=ssh_socket_connect(session->socket,
Packit Service 31306d
                           session->opts.host,
Packit Service 31306d
                           session->opts.port > 0 ? session->opts.port : 22,
Packit Service 31306d
                           session->opts.bindaddr);
Packit Service 31306d
  }
Packit Service 31306d
  if (ret == SSH_ERROR) {
Packit Service 31306d
    return SSH_ERROR;
Packit Service 31306d
  }
Packit Service 31306d
Packit Service 31306d
  set_status(session, 0.2f);
Packit Service 31306d
Packit Service 31306d
  session->alive = 1;
Packit Service 31306d
  SSH_LOG(SSH_LOG_PROTOCOL,"Socket connecting, now waiting for the callbacks to work");
Packit Service 31306d
pending:
Packit Service 31306d
  session->pending_call_state=SSH_PENDING_CALL_CONNECT;
Packit Service 31306d
  if(ssh_is_blocking(session)) {
Packit Service 31306d
      int timeout = (session->opts.timeout * 1000) +
Packit Service 31306d
                    (session->opts.timeout_usec / 1000);
Packit Service 31306d
      if (timeout == 0) {
Packit Service 31306d
          timeout = 10 * 1000;
Packit Service 31306d
      }
Packit Service 31306d
      SSH_LOG(SSH_LOG_PACKET,"Actual timeout : %d", timeout);
Packit Service 31306d
      ret = ssh_handle_packets_termination(session, timeout, ssh_connect_termination, session);
Packit Service 31306d
      if (session->session_state != SSH_SESSION_STATE_ERROR &&
Packit Service 31306d
          (ret == SSH_ERROR || !ssh_connect_termination(session))) {
Packit Service 31306d
          ssh_set_error(session, SSH_FATAL,
Packit Service 31306d
                        "Timeout connecting to %s", session->opts.host);
Packit Service 31306d
          session->session_state = SSH_SESSION_STATE_ERROR;
Packit Service 31306d
      }
Packit Service 31306d
  }
Packit Service 31306d
  else {
Packit Service 31306d
      ret = ssh_handle_packets_termination(session,
Packit Service 31306d
                                           SSH_TIMEOUT_NONBLOCKING,
Packit Service 31306d
                                           ssh_connect_termination,
Packit Service 31306d
                                           session);
Packit Service 31306d
      if (ret == SSH_ERROR) {
Packit Service 31306d
          session->session_state = SSH_SESSION_STATE_ERROR;
Packit Service 31306d
      }
Packit Service 31306d
  }
Packit Service 31306d
  SSH_LOG(SSH_LOG_PACKET,"current state : %d",session->session_state);
Packit Service 31306d
  if(!ssh_is_blocking(session) && !ssh_connect_termination(session)){
Packit Service 31306d
    return SSH_AGAIN;
Packit Service 31306d
  }
Packit Service 31306d
Packit Service 31306d
  session->pending_call_state=SSH_PENDING_CALL_NONE;
Packit Service 31306d
  if(session->session_state == SSH_SESSION_STATE_ERROR || session->session_state == SSH_SESSION_STATE_DISCONNECTED)
Packit Service 31306d
  	return SSH_ERROR;
Packit Service 31306d
  return SSH_OK;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
/**
Packit Service 31306d
 * @brief Get the issue banner from the server.
Packit Service 31306d
 *
Packit Service 31306d
 * This is the banner showing a disclaimer to users who log in,
Packit Service 31306d
 * typically their right or the fact that they will be monitored.
Packit Service 31306d
 *
Packit Service 31306d
 * @param[in]  session  The SSH session to use.
Packit Service 31306d
 *
Packit Service 31306d
 * @return A newly allocated string with the banner, NULL on error.
Packit Service 31306d
 */
Packit Service 31306d
char *ssh_get_issue_banner(ssh_session session) {
Packit Service 31306d
  if (session == NULL || session->banner == NULL) {
Packit Service 31306d
    return NULL;
Packit Service 31306d
  }
Packit Service 31306d
Packit Service 31306d
  return ssh_string_to_char(session->banner);
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
/**
Packit Service 31306d
 * @brief Get the version of the OpenSSH server, if it is not an OpenSSH server
Packit Service 31306d
 * then 0 will be returned.
Packit Service 31306d
 *
Packit Service 31306d
 * You can use the SSH_VERSION_INT macro to compare version numbers.
Packit Service 31306d
 *
Packit Service 31306d
 * @param[in]  session  The SSH session to use.
Packit Service 31306d
 *
Packit Service 31306d
 * @return The version number if available, 0 otherwise.
Packit Service 31306d
 *
Packit Service 31306d
 * @code
Packit Service 31306d
 * int openssh = ssh_get_openssh_version();
Packit Service 31306d
 *
Packit Service 31306d
 * if (openssh == SSH_INT_VERSION(6, 1, 0)) {
Packit Service 31306d
 *     printf("Version match!\m");
Packit Service 31306d
 * }
Packit Service 31306d
 * @endcode
Packit Service 31306d
 */
Packit Service 31306d
int ssh_get_openssh_version(ssh_session session) {
Packit Service 31306d
  if (session == NULL) {
Packit Service 31306d
    return 0;
Packit Service 31306d
  }
Packit Service 31306d
Packit Service 31306d
  return session->openssh;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
/**
Packit Service 31306d
 * @brief Disconnect from a session (client or server).
Packit Service 31306d
 * The session can then be reused to open a new session.
Packit Service 31306d
 *
Packit Service 31306d
 * @param[in]  session  The SSH session to use.
Packit Service 31306d
 */
Packit Service 31306d
void ssh_disconnect(ssh_session session) {
Packit Service 31306d
  struct ssh_iterator *it;
Packit Service 31306d
  int rc;
Packit Service 31306d
Packit Service 31306d
  if (session == NULL) {
Packit Service 31306d
    return;
Packit Service 31306d
  }
Packit Service 31306d
Packit Service 31306d
  if (session->socket != NULL && ssh_socket_is_open(session->socket)) {
Packit Service 31306d
    rc = ssh_buffer_pack(session->out_buffer,
Packit Service 31306d
                         "bdss",
Packit Service 31306d
                         SSH2_MSG_DISCONNECT,
Packit Service 31306d
                         SSH2_DISCONNECT_BY_APPLICATION,
Packit Service 31306d
                         "Bye Bye",
Packit Service 31306d
                         ""); /* language tag */
Packit Service 31306d
    if (rc != SSH_OK){
Packit Service 31306d
      ssh_set_error_oom(session);
Packit Service 31306d
      goto error;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    ssh_packet_send(session);
Packit Service 31306d
    ssh_socket_close(session->socket);
Packit Service 31306d
  }
Packit Service 31306d
error:
Packit Service 31306d
  session->recv_seq = 0;
Packit Service 31306d
  session->send_seq = 0;
Packit Service 31306d
  session->alive = 0;
Packit Service 31306d
  if (session->socket != NULL){
Packit Service 31306d
    ssh_socket_reset(session->socket);
Packit Service 31306d
  }
Packit Service 31306d
  session->opts.fd = SSH_INVALID_SOCKET;
Packit Service 31306d
  session->session_state=SSH_SESSION_STATE_DISCONNECTED;
Packit Service 31306d
Packit Service 31306d
  while ((it=ssh_list_get_iterator(session->channels)) != NULL) {
Packit Service 31306d
    ssh_channel_do_free(ssh_iterator_value(ssh_channel,it));
Packit Service 31306d
    ssh_list_remove(session->channels, it);
Packit Service 31306d
  }
Packit Service 31306d
  if(session->current_crypto){
Packit Service 31306d
    crypto_free(session->current_crypto);
Packit Service 31306d
    session->current_crypto=NULL;
Packit Service 31306d
  }
Packit Service 31306d
  if (session->next_crypto) {
Packit Service 31306d
    crypto_free(session->next_crypto);
Packit Service 31306d
    session->next_crypto = crypto_new();
Packit Service 31306d
    if (session->next_crypto == NULL) {
Packit Service 31306d
      ssh_set_error_oom(session);
Packit Service 31306d
    }
Packit Service 31306d
  }
Packit Service 31306d
  if (session->in_buffer) {
Packit Service 31306d
    ssh_buffer_reinit(session->in_buffer);
Packit Service 31306d
  }
Packit Service 31306d
  if (session->out_buffer) {
Packit Service 31306d
    ssh_buffer_reinit(session->out_buffer);
Packit Service 31306d
  }
Packit Service 31306d
  if (session->in_hashbuf) {
Packit Service 31306d
    ssh_buffer_reinit(session->in_hashbuf);
Packit Service 31306d
  }
Packit Service 31306d
  if (session->out_hashbuf) {
Packit Service 31306d
    ssh_buffer_reinit(session->out_hashbuf);
Packit Service 31306d
  }
Packit Service 31306d
  session->auth.supported_methods = 0;
Packit Service 31306d
  SAFE_FREE(session->serverbanner);
Packit Service 31306d
  SAFE_FREE(session->clientbanner);
Packit Service 31306d
Packit Service 31306d
  if(session->ssh_message_list){
Packit Service 31306d
    ssh_message msg;
Packit Service 31306d
    while((msg=ssh_list_pop_head(ssh_message ,session->ssh_message_list))
Packit Service 31306d
        != NULL){
Packit Service 31306d
      ssh_message_free(msg);
Packit Service 31306d
    }
Packit Service 31306d
    ssh_list_free(session->ssh_message_list);
Packit Service 31306d
    session->ssh_message_list=NULL;
Packit Service 31306d
  }
Packit Service 31306d
Packit Service 31306d
  if (session->packet_callbacks){
Packit Service 31306d
    ssh_list_free(session->packet_callbacks);
Packit Service 31306d
    session->packet_callbacks=NULL;
Packit Service 31306d
  }
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
const char *ssh_copyright(void) {
Packit Service 31306d
    return SSH_STRINGIFY(LIBSSH_VERSION) " (c) 2003-2019 "
Packit Service 31306d
           "Aris Adamantiadis, Andreas Schneider "
Packit Service 31306d
           "and libssh contributors. "
Packit Service 31306d
           "Distributed under the LGPL, please refer to COPYING "
Packit Service 31306d
           "file for information about your rights";
Packit Service 31306d
}
Packit Service 31306d
/** @} */