// ============================================================================ // // = LIBRARY // ULib - c++ library // // = FILENAME // sshsocket.h // // = AUTHOR // Stefano Casazza // // ============================================================================ #ifndef ULIB_SSHSOCKET_H #define ULIB_SSHSOCKET_H 1 #include #undef PACKAGE_NAME #undef PACKAGE_STRING #undef PACKAGE_TARNAME #undef PACKAGE_VERSION #undef PACKAGE_BUGREPORT #include #undef PACKAGE_NAME #define PACKAGE_NAME "ULib" #undef PACKAGE_VERSION #define PACKAGE_VERSION ULIB_VERSION /** * -------------------------------------------------------------------------------------------------------------------------- * The SSH protocol was designed for some goals which I resume here: * * a) Privacy of data * b) Security * c) Authentication of the server * d) Authentication of the client * * The client MUST be sure who's speaking to before entering into any authentication way. That's where the end programmer must * ensure the given fingerprints *are* from the legitimate server. A ssh connection must follow the following steps: * * 1) Before connecting the socket, you can set up if you wish one or other server public key authentication ie. DSA or RSA. * You can choose cryptographic algorithms you trust and compression algorithms if any * 2) The connection is made. A secure handshake is made, and resulting from it, a public key from the server is gained. * You MUST verify that the public key is legitimate * 3) The client must authenticate: the two implemented ways are password, and public keys (from dsa and rsa key-pairs * generated by openssh). It is harmless to authenticate to a fake server with these keys because the protocol ensures * the data you sign can't be used twice. It just avoids man-in-the-middle attacks * 4) Now that the user has been authenticated, you must open one or several channels. channels are different subways for * information into a single ssh connection. Each channel has a standard stream (stdout) and an error stream (stderr). * You can theoretically open an infinity of channel * 5) With the channel you opened, you can do several things: * - Open a shell. You may want to request a pseudo virtual terminal before * - Execute a command. The virtual terminal is usable, too * - Invoke the sftp subsystem. (look at chapter 6) * - invoke your own subsystem. This is out the scope of this document but it is easy to do * 6) When everything is finished, just close the channels, and then the connection * --------------------------------------------------------------------------------------------------------------------------- */ class U_EXPORT USSHSocket : public USocket { public: USSHSocket(bool bSocketIsIPv6 = false) : USocket(bSocketIsIPv6) { U_TRACE_REGISTER_OBJECT(0, USSHSocket, "%b", bSocketIsIPv6) buffer = 0; channel = 0; ret = auth = 0; user = public_key = private_key = 0; session = (ssh_session) U_SYSCALL_NO_PARAM(ssh_new); } ~USSHSocket() { U_TRACE_UNREGISTER_OBJECT(0, USSHSocket) close(); if (buffer) U_SYSCALL_VOID(buffer_free, "%p", buffer); } void close(); bool setError(); bool SSHConnection(int fd); void setUser(const char* _user) { U_TRACE(1, "USSHSocket::setUser(%S)", _user) U_INTERNAL_ASSERT_POINTER(_user) user = _user; (void) U_SYSCALL(ssh_options_set, "%p,%d,%S", session, SSH_OPTIONS_USER, user); } void setKey(const char* _private_key = "/%U/.ssh/id_rsa", const char* _public_key = "/%U/.ssh/id_rsa.pub") { U_TRACE(1, "USSHSocket::setKey(%S,%S)", _private_key, _public_key) public_key = _public_key; private_key = _private_key; } void setVerbosity(int num = -1) { U_TRACE(1, "USSHSocket::setVerbosity(%d)", num) (void) U_SYSCALL(ssh_options_set, "%p,%d,%p", session, SSH_OPTIONS_LOG_VERBOSITY, &num); } void sendEOF() { U_TRACE_NO_PARAM(1, "USSHSocket::sendEOF()") U_INTERNAL_ASSERT_POINTER(channel) U_SYSCALL_VOID(channel_send_eof, "%p", channel); } /** * This method is called to connect the socket to a server SSH deamon that is specified * by the provided host name and port number. We call the ssh_connect() function to perform the connection */ virtual bool connectServer(const UString& server, unsigned int iServPort, int timeoutMS = 0) U_DECL_OVERRIDE; // 22 virtual int recv( void* pBuffer, uint32_t iBufLength) U_DECL_OVERRIDE; virtual int send(const char* pPayload, uint32_t iPayloadLength) U_DECL_OVERRIDE; #if defined(U_STDCPP_ENABLE) && defined(DEBUG) const char* dump(bool reset) const; #endif protected: const char* user; ssh_buffer buffer; ssh_channel channel; ssh_session session; const char* public_key; const char* private_key; int ret, auth; void setStatus() U_NO_EXPORT; void setStatus(int n) { ret = n; setStatus(); } private: U_DISALLOW_COPY_AND_ASSIGN(USSHSocket) }; #endif