I'm sorry, you're right. I'm attaching the code of my class. It has an interface to hide dependencies for final applications. It is a windows DLL. Basically, the callback function is the same as the one shown in the examples. I'm forcing the password just for testing purposes. As I've said, the callback function is declared in the CSSHSession.cpp, but outside the class.

The code crashes exactly at line 171, when calling libssh2_userauth_keyboard_interactive(m_Session, "root", &kbd_callback)

Regards,

Ezequiel

El 06/09/2010 01:13 p.m., Alexander Lamaison escribió:
On 6 September 2010 16:49, Ezequiel Ruiz<[email protected]>  wrote:

...snip

I'm not sure what can be wrong, the libssh2 version is 1.2.7. And the
compile is VS2008 (windows 7).
Without looking at your example source code, we can't really help.

Alex

--
Swish - Easy SFTP for Windows Explorer (http://www.swish-sftp.org)
_______________________________________________
libssh2-devel http://cool.haxx.se/cgi-bin/mailman/listinfo/libssh2-devel

#ifndef __RUNCOMMAND_ISSHSESSION_INCLUDED__
#define __RUNCOMMAND_ISSHSESSION_INCLUDED__

#include "RunCommandBase.h"
#include "ISSHChannel.h"
#include "ISFTPSession.h"


//! \brief Connection information for SSH sessions.
struct RUNCOMMANDAPI SConnectionInfo
{
    //! \brief Default constructor.
    SConnectionInfo()
    : timeout_s(5),port(22),compress(false) {}

        int timeout_s; //!< The connection timeout in seconds.
        int port; //!< The connection port.
        bool compress;
        std::string hostname; //!< The remote hostname or ip address.
        std::string username; //!< The connection user name.
        std::string userpasswd; //!< The connection password.
        std::string pkeyfile; //!< The connection private key file path (SSHv2 
only).
};

//! \brief Interface class to handle a remote SSH connection instance.

//! This class allows to manipulate remote SSH connections, create and manage
//! some other higher level interfaces, like channels and subsystems (SFTP), and
//! dealing with error messages.
//! This is the class you have to start with, after you have a working 
CSSHSession
//! instance, you can create several child instances of channels and SFTP 
subsistems
//! in the same session, and sharing the same connection socket.
//! It currently supports 3 authentication methods:
//! - Password authentication.
//! - Keyboard interactive authentication.
//! - Private Key authentication.
//!
//! \note For Keyboard Interactive authentication, it only supports a "direct" 
password
//! question, if the remote server includes a set of questions, it won't be 
able to connect.
//! \todo
//! - Improve multithread support for this class and derivates.
//! - Add child hierarchy.
//! - Add "known hosts" detection.
class RUNCOMMANDAPI ISSHSession
{
        public:

        //! \brief Constructor.
        //! \param session_id The assigned session ID, usefull for a 
higher-level manager implementation.
        //! \param log A CLogger instance, if provided, the object will use the 
logger
        //! to report errors or trak debugging information.
                ISSHSession(int session_id)
                : m_SessionID(session_id) {}

        //! \brief Connects to the server.

        //! It attemps to create a connection socket against the remote server.
        //! You need to have the connection parameters already defined with the
        //! ISSHSession::setConnectionInfo() method before calling this one.
        //! \return true on success, false on failure.
        //! you must use the CLogger to see error messages.
                virtual bool connect() = 0;

        //! \brief Closes the connection to the remote server
        //! \return true on success, false on failure.
        //! you must use the CLogger to see error messages.
                virtual bool disconnect() = 0;

        //! \brief Creates a new ISSHSession instance attached to this session.

        //! Once you have a valid connected session, you can create as many 
channels
        //! as you want. The limits are theoretical. Remember that you can call 
just
        //! one batch command per channel right now (still in research).
        //! \return A new ISSHSession object.
        //! \note You are responsable for deleting the allocated object.
                virtual ISSHChannel* createChannel() = 0;

        //! \brief Creates a new CSFTPSession instance attached to this session.

        //! Once you have a valid connected session, you can create as many SFTP
        //! sessions as you want. But normally you will use just one.
        //! \return A new CSFTPSession object.
        //! \note You are responsable for deleting the allocated object.
                virtual ISFTPSession* createSFTPSession() = 0;

        //! \brief Gets the internal session ID.
        //! \return The session ID. This ID is ignored at low-level, you may 
use it when
        //! implementing a session manager (read only).
                virtual int getSessionID() const = 0;

        //! \brief Set a connection info struct for this object.

        //! It is important to call this method with the right parameters 
BEFORE calling the
        //! ISSHSession::connect() method. It will fail if not.
        //! \param info The SConnectionInfo struct with the desired parameters.
                virtual void setConnectionInfo(const SConnectionInfo &info) = 0;

        //! \brief Gets the current connection info for this object.
        //! \return The SConnectionInfo struct with the current parameters 
(read only).
                virtual const SConnectionInfo& getConnectionInfo() const = 0;

        //! \brief Check if the session is connected to the remote server.
        //! \return true if connected, false if not.
        //! \todo Improve the stability of this method.
                virtual bool isConnected() = 0;

        //! \brief Destructor.
                virtual ~ISSHSession() {}

        protected:

                // Session ID is used to identify the object instance by the 
connection manager.
                // if a user creates two sessions with the same hostname, user 
and password, then
                // it will share the same object instance, but with different 
channels.
                int m_SessionID;
                
        private:
};

#endif //__RUNCOMMAND_ISSHSESSION_INCLUDED__
#ifndef __RUNCOMMAND_CSSHSESSION_INCLUDED__
#define __RUNCOMMAND_CSSHSESSION_INCLUDED__

#include "ISSHSession.h"
#include "ILogger.h"

#include <libssh2.h>
#include <winsock2.h>


//! \brief Class to handle a remote SSH connection instance.

//! This class allows to manipulate remote SSH connections, create and manage
//! some other higher level interfaces, like channels and subsystems (SFTP), and
//! dealing with error messages.
//! This is the class you have to start with, after you have a working 
CSSHSession
//! instance, you can create several child instances of channels and SFTP 
subsistems
//! in the same session, and sharing the same connection socket.
//! It currently supports 3 authentication methods:
//! - Password authentication.
//! - Keyboard interactive authentication.
//! - Private Key authentication.
//!
//! \note For Keyboard Interactive authentication, it only supports a "direct" 
password
//! question, if the remote server includes a set of questions, it won't be 
able to connect.
//! \todo
//! - Improve multithread support for this class and derivates.
//! - Add child hierarchy.
//! - Add "known hosts" detection.
class RUNCOMMANDAPI CSSHSession : public ISSHSession
{
        public:

        //! \brief Constructor.
        //! \param session_id The assigned session ID, usefull for a 
higher-level manager implementation.
        //! \param log A CLogger instance, if provided, the object will use the 
logger
        //! to report errors or trak debugging information.
                CSSHSession(int session_id, ILogger *log=0);

        //! \brief Connects to the server.

        //! It attemps to create a connection socket against the remote server.
        //! You need to have the connection parameters already defined with the
        //! CSSHSession::setConnectionInfo() method before calling this one.
        //! \return true on success, false on failure.
        //! you must use the CLogger to see error messages.
                virtual bool connect();

        //! \brief Closes the connection to the remote server
        //! \return true on success, false on failure.
        //! you must use the CLogger to see error messages.
                virtual bool disconnect();

        //! \brief Creates a new ISSHChannel instance attached to this session.

        //! Once you have a valid connected session, you can create as many 
channels
        //! as you want. The limits are theoretical. Remember that you can call 
just
        //! one batch command per channel right now (still in research).
        //! \return A new ISSHChannel object.
        //! \note You are responsable for deleting the allocated object.
                virtual ISSHChannel* createChannel();

        //! \brief Creates a new ISFTPSession instance attached to this session.

        //! Once you have a valid connected session, you can create as many SFTP
        //! sessions as you want. But normally you will use just one.
        //! \return A new ISFTPSession object.
        //! \note You are responsable for deleting the allocated object.
                virtual ISFTPSession* createSFTPSession();

        //! \brief Gets the internal session ID.
        //! \return The session ID. This ID is ignored at low-level, you may 
use it when
        //! implementing a session manager (read only).
                virtual int getSessionID() const;

        //! \brief Set a connection info struct for this object.

        //! It is important to call this method with the right parameters 
BEFORE calling the
        //! CSSHSession::connect() method. It will fail if not.
        //! \param info The SConnectionInfo struct with the desired parameters.
                virtual void setConnectionInfo(const SConnectionInfo &info);

        //! \brief Gets the current connection info for this object.
        //! \return The SConnectionInfo struct with the current parameters 
(read only).
                virtual const SConnectionInfo& getConnectionInfo() const;

        //! \brief Check if the session is connected to the remote server.
        //! \return true if connected, false if not.
        //! \todo Improve the stability of this method.
                virtual bool isConnected();

        //! \brief Destructor.
                virtual ~CSSHSession();

        protected:
        private:

                bool _init();

                static void kbd_callback(const char *name, int name_len,
                         const char *instruction, int instruction_len,
                         int num_prompts,
                         const LIBSSH2_USERAUTH_KBDINT_PROMPT *prompts,
                         LIBSSH2_USERAUTH_KBDINT_RESPONSE *responses,
                         void **abstract);

                SConnectionInfo m_ConnectionInfo;

        LIBSSH2_SESSION *m_Session;

                struct sockaddr_in sin;
                int m_Socket;

                bool m_IsConnected;

                // Session ID is used to identify the object instance by the 
connection manager.
                // if a user creates two sessions with the same hostname, user 
and password, then
                // it will share the same object instance, but with different 
channels.
                int m_SessionID;

                int m_SSHServerVersion;

        ILogger *m_Logger;
};

#endif //__RUNCOMMAND_CSSHSESSION_INCLUDED__
#include "CSSHSession.h"
#include "CStringTool.h"
#include "CSSHChannel.h"
#include "CSFTPSession.h"


const char *password="test";

void CSSHSession::kbd_callback(const char *name, int name_len,
                         const char *instruction, int instruction_len,
                         int num_prompts,
                         const LIBSSH2_USERAUTH_KBDINT_PROMPT *prompts,
                         LIBSSH2_USERAUTH_KBDINT_RESPONSE *responses,
                         void **abstract)
{
    (void)name;
    (void)name_len;
    (void)instruction;
    (void)instruction_len;
    if (num_prompts == 1) {
        responses[0].text = _strdup(password);
        responses[0].length = strlen(password);
    }
    (void)prompts;
    (void)abstract;
}



CSSHSession::CSSHSession(int session_id, ILogger *log)
: ISSHSession(session_id), m_Socket(0), m_Session(0), m_SSHServerVersion(0), 
m_Logger(log), m_IsConnected(false)
{

}

int CSSHSession::getSessionID() const
{
    return m_SessionID;
}

ISSHChannel *CSSHSession::createChannel()
{
    ISSHChannel *channel = new 
CSSHChannel(m_Session,m_ConnectionInfo.hostname.c_str(),m_Logger);
    return channel;
}

ISFTPSession *CSSHSession::createSFTPSession()
{
    ISFTPSession *sftp = new CSFTPSession(m_Session, 
m_ConnectionInfo.hostname.c_str(), m_Logger);
    return sftp;
}

void CSSHSession::setConnectionInfo(const SConnectionInfo &info)
{
    m_ConnectionInfo.timeout_s = info.timeout_s;
        m_ConnectionInfo.compress = info.compress;
    m_ConnectionInfo.hostname = info.hostname;
    m_ConnectionInfo.username = info.username;
    m_ConnectionInfo.userpasswd = info.userpasswd;
    m_ConnectionInfo.pkeyfile = info.pkeyfile;
}

const SConnectionInfo &CSSHSession::getConnectionInfo() const
{
    return m_ConnectionInfo;
}

bool CSSHSession::isConnected()
{
    return m_IsConnected;
}


bool CSSHSession::connect()
{
        int auth_pw = 0;
        char *userauthlist;
        
    m_Socket = socket(AF_INET, SOCK_STREAM, 0);

    sin.sin_family = AF_INET;
        sin.sin_port = htons(m_ConnectionInfo.port);
        sin.sin_addr.s_addr = inet_addr(m_ConnectionInfo.hostname.c_str());
    if (::connect(m_Socket, (struct sockaddr*)(&sin), sizeof(struct 
sockaddr_in)) != 0) 
        {
                if(m_Logger)
                        m_Logger->log("Failed creating a socket with the host " 
+ m_ConnectionInfo.hostname,ILogger::ECritical);
        return false;
    }

        if(m_Logger)
                m_Logger->log("Socket created!, now starting a new SSH session 
with the host " + m_ConnectionInfo.hostname);

    m_Session = libssh2_session_init();
    
        // TODO: set all the connection parameters here! (like compression...)
        if(m_ConnectionInfo.compress)
        {
                if(m_Logger)
                        m_Logger->log("Compression flag enabled, trying to set 
it up for server " + m_ConnectionInfo.hostname);

                if(libssh2_session_method_pref(m_Session, 
LIBSSH2_METHOD_COMP_SC,"zlib"))
                {
                         if(m_Logger)
                                 m_Logger->log("Error setting up compression 
for server " + m_ConnectionInfo.hostname,ILogger::ECritical);
                         return false;
                }

                if(libssh2_session_method_pref(m_Session, 
LIBSSH2_METHOD_COMP_CS,"zlib"))
                {
                         if(m_Logger)
                                 m_Logger->log("Error setting up compression 
for server " + m_ConnectionInfo.hostname,ILogger::ECritical);
                         return false;
                }
        }
        
        if (libssh2_session_startup(m_Session, m_Socket)) 
        {
                        if(m_Logger)
                                m_Logger->log("Failed creating an SSH 
connection with the host " + m_ConnectionInfo.hostname,ILogger::ECritical);

                        return false;
    }

        if(m_Logger)
                m_Logger->log("SSH session started successfuly with the host " 
+ m_ConnectionInfo.hostname);


        // TODO: check host keys here!

    // check what authentication methods are available
        userauthlist = libssh2_userauth_list(m_Session, 
m_ConnectionInfo.username.c_str(), m_ConnectionInfo.username.length());

        if(m_Logger)
        {
                m_Logger->log("Authentication methods for host " + 
m_ConnectionInfo.hostname + " with user " + m_ConnectionInfo.username + ": ");
                m_Logger->log(userauthlist);
        }

    if (strstr(userauthlist, "password") != NULL) 
        {
        auth_pw |= 1;
    }
    if (strstr(userauthlist, "keyboard-interactive") != NULL) 
        {
        auth_pw |= 2;
    }
    if (strstr(userauthlist, "publickey") != NULL) 
        {
        auth_pw |= 4;
    }

    if (auth_pw & 1) 
        {
        // We could authenticate via password
                if (libssh2_userauth_password(m_Session, 
m_ConnectionInfo.username.c_str(), m_ConnectionInfo.userpasswd.c_str()))
                {
                        if(m_Logger)
                                m_Logger->log("SSH authentication by password 
failed in host " + m_ConnectionInfo.hostname + " for user " + 
m_ConnectionInfo.username,ILogger::ECritical);
                        return false;
        } 
                else 
                {
                        if(m_Logger)
                                m_Logger->log("SSH authentication by password 
succeeded with the host " + m_ConnectionInfo.hostname + " for user " + 
m_ConnectionInfo.username);
        }
    } 
        else if (auth_pw & 2) 
        {
        // Or via keyboard-interactive
                if (libssh2_userauth_keyboard_interactive(m_Session, "root", 
&kbd_callback) ) 
                {
                        if(m_Logger)
                                m_Logger->log("SSH authentication by 
keyboard-interactive failed in host " + m_ConnectionInfo.hostname + " for user 
" + m_ConnectionInfo.username,ILogger::ECritical);
                        return false;
        } 
                else 
                {
                        if(m_Logger)
                                m_Logger->log("SSH authentication by 
keyboard-interactive succeeded with the host " + m_ConnectionInfo.hostname + " 
for user " + m_ConnectionInfo.username);
        }
    } 
/*      else if (auth_pw & 4) 
        {
        // Or by public key
        if (libssh2_userauth_publickey_fromfile(m_Session, 
m_ConnectionInfo.username.c_str(), keyfile1,keyfile2, 
m_ConnectionInfo.userpasswd.c_str())) 
                {
                        if(m_Logger)
                                m_Logger->log("SSH authentication by public key 
failed in host " + m_ConnectionInfo.hostname + " for user " + 
m_ConnectionInfo.username,ILogger::ECritical);
                        return false;
        } 
                else 
                {
                        if(m_Logger)
                                m_Logger->log("SSH authentication by public key 
succeeded with the host " + m_ConnectionInfo.hostname + " for user " + 
m_ConnectionInfo.username);
        }
    } */
        else 
        {
                if(m_Logger)
                        m_Logger->log("No supported SSH authentication methods 
found in host " + m_ConnectionInfo.hostname + " for user " + 
m_ConnectionInfo.username,ILogger::ECritical);
        return false;
    }

        m_IsConnected=true;
        return true;
}

bool CSSHSession::disconnect()
{
        if(m_Session && m_IsConnected)
        {
                libssh2_session_disconnect(m_Session, "Normal Shutdown");
                libssh2_session_free(m_Session);
                m_Session=0;
                m_IsConnected=false;

                closesocket(m_Socket);
                if(m_Logger)
                        m_Logger->log("SSH session disconnected from host " + 
m_ConnectionInfo.hostname);
        }

        return true;
}

CSSHSession::~CSSHSession()
{
        this->disconnect();
}
_______________________________________________
libssh2-devel http://cool.haxx.se/cgi-bin/mailman/listinfo/libssh2-devel

Reply via email to