From 05a818bb65d00ef89cf97e59ebca867fcef5863a Mon Sep 17 00:00:00 2001 From: Tom Smeding Date: Thu, 9 Jul 2020 18:30:13 +0200 Subject: ssh: Abstract SSH communication in mini-library --- ssh/sshnc.h | 102 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 102 insertions(+) create mode 100644 ssh/sshnc.h (limited to 'ssh/sshnc.h') diff --git a/ssh/sshnc.h b/ssh/sshnc.h new file mode 100644 index 0000000..3e4bcfe --- /dev/null +++ b/ssh/sshnc.h @@ -0,0 +1,102 @@ +#pragma once + +#include +#include + + +// This "SSH netcat" library is very specifically oriented on the use of SSH in +// the tomsg protocol. That is: it is assumed that what you want is a +// connection with one simple channel with a particular subsystem, and that you +// need no authentication at all (i.e. authentication type 'none'). For +// anything more involved, use libssh directly. + + +struct sshnc_client; + +// Should return 'true' if the key is trusted, 'false' otherwise. The hash is +// sha256 in byte form, not yet encoded in hexadecimal or similar. +typedef bool (*sshnc_hostkey_checker_t)(const unsigned char *hash, size_t length); + +// Convenience function to convert a hash to a human-readable form. Returns a +// reference to an internal static buffer. +const char* sshnc_print_hash(const unsigned char *hash, size_t length); + +enum sshnc_retval { + // Successful result + SSHNC_OK = 0, + + // Other status codes + SSHNC_EOF, // connection closed (sshnc_send, sshnc_maybe_recv) + SSHNC_AGAIN, // no data now, try again later (sshnc_maybe_recv) + + // Error codes + SSHNC_ERR_CONNECT, // could not connect to host + SSHNC_ERR_UNTRUSTED, // hostkey checker rejected key + SSHNC_ERR_AUTH, // error authenticating to server + SSHNC_ERR_DENIED, // server did not accept 'none' authentication + SSHNC_ERR_CLOSED, // server unexpectedly closed connection + SSHNC_ERR_SUBSYSTEM, // server did not accept the subsystem channel + + // Internal error codes + SSHNC_ERR_SESSION, // could not open libssh session + SSHNC_ERR_CHANNEL, // could not open libssh channel + SSHNC_ERR_OPTIONS, // could not set libssh options + SSHNC_ERR_GETKEY, // could not get key from libssh + SSHNC_ERR_CALLBACKS, // sshnc would not accept our callbacks structure + SSHNC_ERR_EVENT, // could not create libssh event poller + SSHNC_ERR_WRITE, // could not write to ssh channel + SSHNC_ERR_POLL, // could not poll the socket for activity +}; + +// Returns reference to internal static buffer. All error codes are negative. +// Additional error info may be stored in an internal thread_local buffer, and +// returned as part of the description. +const char* sshnc_strerror(enum sshnc_retval code); + +// If successful, stores a new connection structure in 'client' and returns +// SSHNC_OK. On error, stores NULL in 'client' and returns an error code. +enum sshnc_retval sshnc_connect( + const char *hostname, + int port, + const char *username, + const char *subsystem, + sshnc_hostkey_checker_t checker, + struct sshnc_client **client // output +); + +// Close the connection. This also frees the client structure. Note that even +// in case of an error, you must still call this function to prevent a memory +// leak. +void sshnc_close(struct sshnc_client *client); + +// Returns a file descriptor that can be listened for read-ready events (using +// e.g. select(2) or poll(2)). Whenever it becomes ready for reading, you +// should call sshnc_maybe_recv(). If the connection was already closed +// internally due to an error, returns -1. +int sshnc_poll_fd(struct sshnc_client *client); + +// Returns SSHNC_OK if successful, SSHNC_EOF if the connection was closed, or +// an error code otherwise. +enum sshnc_retval sshnc_send( + struct sshnc_client *client, + const char *data, + size_t length +); + +// Retrieves up to 'capacity' bytes from the connection, and writes them to the +// buffer pointed to by 'data', and the number of bytes received to 'length'. +// Returns SSHNC_OK if successful, SSHNC_EOF if the connection was closed +// before any data was received, SSHNC_AGAIN if no data was available without +// blocking, or an error code otherwise. +// If the return value is not SSHNC_OK, 0 is stored in 'length'. +// Note that because this operation is non-blocking, the caller should only +// call this if it has a reason for suspecting there might be data (e.g. +// because poll(2) reported as such). +// This function also handles general ssh protocol messages, and must thus +// ALWAYS be called if there is readable data on the socket. +enum sshnc_retval sshnc_maybe_recv( + struct sshnc_client *client, + size_t capacity, + char *data, // output + size_t *length // output +); -- cgit v1.2.3-54-g00ecf