aboutsummaryrefslogtreecommitdiff
path: root/doc/libssh-0.2-api-1.txt
diff options
context:
space:
mode:
authorAris Adamantiadis <aris@0xbadc0de.be>2005-07-05 01:21:44 +0000
committerAris Adamantiadis <aris@0xbadc0de.be>2005-07-05 01:21:44 +0000
commitc65f56aefa50a2e2a78a0e45564526ecc921d74f (patch)
tree11bd53cf92869ccbab30f29253ce30f7078a4a26 /doc/libssh-0.2-api-1.txt
downloadlibssh-c65f56aefa50a2e2a78a0e45564526ecc921d74f.tar.gz
libssh-c65f56aefa50a2e2a78a0e45564526ecc921d74f.tar.xz
libssh-c65f56aefa50a2e2a78a0e45564526ecc921d74f.zip
first import
git-svn-id: svn+ssh://svn.berlios.de/svnroot/repos/libssh/trunk@1 7dcaeef0-15fb-0310-b436-a5af3365683c
Diffstat (limited to 'doc/libssh-0.2-api-1.txt')
-rw-r--r--doc/libssh-0.2-api-1.txt370
1 files changed, 370 insertions, 0 deletions
diff --git a/doc/libssh-0.2-api-1.txt b/doc/libssh-0.2-api-1.txt
new file mode 100644
index 00000000..ff35b392
--- /dev/null
+++ b/doc/libssh-0.2-api-1.txt
@@ -0,0 +1,370 @@
+ The new libssh 0.2 API
+ ----------------------
+
+Version 1
+
+A. Introduction
+---------------
+
+With the time from the first release of libssh, I have received lots of
+comments about the current API. Myself, I found it quite limiting when doing
+my first libssh-server drafts. Thus, I am moving to a stronger API.
+This API must still be simple. I am not introducing complex changes. An API
+well designed must hide the implementation details. Implementation can change
+easily within bugfixes - but API cannot change each release.
+
+To the people already using libssh 0.11 : sorry. Once I have the complete API
+redesigned, I will write a migration paper. It won't be too hard normally.
+
+Here are the things that were lacking in the previous API and *must* change:
+
+* A non-blocking mode connection type
+* Functions to relegate File descriptor listening to Calling functions and to
+ the programmer. (I'll explain later).
+* Along with that, good buffering system (well, it's not an API but).
+* Leave the "functions returns a pointer when it works and NULL when it does
+ not work". It gives serious problems to implement bindings (A C++
+ constructor should not fail and should not depend on a network thing
+* Make the Session structure an abstract structure that can work with both
+ client and *servers*. That mean we should have a Server object which listen
+ to clients on a bound port, does the different handshakes and return a
+ session.
+ Since C is not per se an Object language, I won't use inheritance between
+ objects.
+* This same server thing must provide the reverse capabilities than the
+ client. That is, accept the handshake, in a nonblocking way. Accept channel
+ requests, or send them to the controller program.
+* Support for program forking : Imagine you have a Ssh server object. You
+ accept a connection and receive a session, then you receive a channel. You
+ may want to keep the good old days fork() tricks. Libssh will give a way to
+ destroy handlers from sessions which belong to an other process without
+ disturbing the session.
+* So often I received the comment back saying that it was not clear why a
+ session or a channel was terminated. This is over.
+* And of course I received lot of mails about the fact I'm doing namespace
+ polution. this will be resolved this time.
+So, please read this draft not as a formal documentation but like a roadmap of
+things that each kind of object must do.
+
+B. Description of objects and functions
+
+Options structure
+~~~~~~~~~~~~~~~~~
+
+struct ssh_options *ssh_options_new()
+
+ssh_options_getopt(options, *argc, argv)
+
+ssh_options_copy(options)
+
+char ** ssh_options_get_supported_algos(options,type)
+ returns a list of the algos supported by libssh, type being one of
+ SSH_HOSTKEYS, SSH_KEX, SSH_CRYPT, SSH_MAC, SSH_COMP, SSH_LANG
+
+ssh_options_set_wanted_algos(options,type, char *list)
+list being comma-separated list of algos, and type being the upper constants
+but with _C_S or _S_V added to them.
+
+ssh_options_set_port(options, port)
+
+ssh_options_set_host(options, host)
+
+ssh_options_set_fd(options, fd)
+
+ssh_options_set_bind(options, bindaddr, port)
+this options sets the address to bind for a client *or* a server. a port of
+zero means whatever port is free (what most clients want).
+
+ssh_options_set_username(options, username)
+
+ssh_options_set_connect_timeout(options, seconds, usec)
+
+ssh_options_set_ssh_dir(options, dir)
+ssh_options_set_known_hosts_file(options, file)
+ssh_options_set_identity(options, file)
+
+ssh_options_set_banner(options, banner)
+ssh_options_allow_ssh1(options, bool allow)
+ssh_options_allow_ssh2(options, bool allow)
+
+options_set_status_callback has moved into ssh_* functions.
+
+ssh_session Structure
+~~~~~~~~~~~~~~~~~~~~~
+
+This session structure represents a ssh socket to a server *or* a client.
+
+ssh_session *ssh_new()
+
+ssh_set_options(ssh_session,ssh_options)
+
+ssh_connect(session);
+ it will return some status describing at which point of the connection it is,
+ or an error code. If the connection method is non-blocking, the function
+ will be called more than once, though the return value SSH_AGAIN.
+
+ssh_set_blocking(session, bool blocking)
+ set blocking mode or non blocking mode.
+
+ssh_get_fd(session)
+ get the currently used connection file descriptor or equivalent (windows)
+
+ssh_set_fd_toread(session)
+ssh_set_fd_towrite(session)
+ssh_set_fd_except(session)
+ Serve to notify the library that data is actualy available to be read on the
+ file descriptor socket. why ? because on most platforms select can't be done
+ twice on the same socket when the first reported data to read or to write
+
+ssh_get_status(session)
+ Returns the current status bitmask : connection Open or closed, data
+ pending to read or not (even if connection closed), connection closed on
+ error or on an exit message
+
+ssh_get_disconnect_message(session)
+ Returns the connection disconnect error/exit message
+
+ssh_get_pubkey_hash(session, hash)
+ get the public key hash from the server.
+
+ssh_is_server_known(session)
+ssh_write_knownhost(session)
+ these 2 functions will be kept
+
+ssh_disconnect(session)
+ standard disconnect
+
+ssh_disconnect_error(session,error code, message)
+ disconnect with a message
+
+ssh_set_username(session)
+ set the user name to log in
+
+ssh_userauth_* functions will be kept as they are now, excepted the fact that
+the username field will disapear.
+the public key mechanism may get some more functions, like retrieving a public
+key from a private key and authenticating without a public key.
+
+ssh_get_issue_banner(session)
+ get the issue banner from the server, that is the welcome message.
+
+ssh_silent_free(session)
+ This function silently free all data structures used by the session and
+ closes the socket. It may be used for instance when the process forked and
+ doesn't want to keep track of this session. This is obviously not possible to
+ do with separate channels.
+
+The channel_struct structure
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The channels will change a bit. the constructor thing will change, and the way
+to multiplex different connections will change too. channel functions will be
+prefixed with "ssh_"
+
+struct channel_struct *ssh_channel_new()
+
+ssh_channel_open_session(channel)
+ will return if the channel allocation failed or not.
+
+ssh_channel_open_forward(channel, ...) won't change. it will report an error if
+the channel allocation failed.
+
+ssh_channel_send_eof(channel)
+ send EOF
+ssh_channel_close(channel)
+ closes a channel but doesn't destroy it. you may read unread data still in
+ the buffer. Once you closed the buffer, the other party can't send you data,
+ while it could still do it if you only sent an EOF.
+ssh_channel_is_closed(channel)
+ returns true if the channel was closed at one of both sides. a closed chan
+ may still have data to read, if you closed yourself the connection. otherwise
+ (you didn't close it) the closed notification only comes when you read the
+ last buffer byte, or when trying to write into the channel (the SIGPIPE-like
+ behaviour).
+
+ssh_channel_is_eof(channel)
+ reports if the other side has sent an EOF. This functions returns FALSE if
+ there is still data to read. A closed channel is always EOF.
+ssh_channel_free(channel)
+ completely free the channel. closes it before if it was not done.
+
+ssh_channel_request_env(channel, name, value)
+ set an environment variable.
+
+ssh_channel_request_pty(channel)
+ssh_channel_request_pty_size()
+ssh_channel_change_pty_size()
+ssh_channel_request_shell()
+ssh_channel_request_exec()
+ssh_channel_request_subsystem()
+These functions won't change.
+
+int ssh_channel_write(channel,data, len,stderr)
+ Depending on the blocking/non blocking mode of the channel, the behaviour may
+ change.
+ stderr is the extended buffer. It's generaly only a server->client stream.
+
+ssh_channel_set_blocking(bool blocking)
+
+int ssh_channel_read(channel, buffer, maxlen, is_stderr)
+ the behaviour will be this one:
+ -if the chan is in non blocking mode, it will poll what's available to read
+ and return this. otherwise (nothing to read) it will return 0.
+ -if the chan is blocking, it will block until at least one byte is
+ available.
+ssh_channel_nonblocking disapears for the later reason.
+
+int channel_poll(channel, is_stderr)
+ polls the network and reports the number of bytes ready to be read in the
+ chan.
+
+ssh_session ssh_channel_get_session(channel)
+ returns the session pointer associated to the channel, for simplicity
+ reasons.
+
+int ssh_channel_select(CHANNELS *readchans, CHANNELS *writechans, CHANNELS
+ *exceptchans, struct timeval *timeout)
+ This function won't work the same way ssh_select did.
+ I removed the custom file descriptor thing for 2 reasons:
+ 1- it's not windows compliant. D'ouh !
+ 2- most programmers won't want to depend on libssh for socket multiplexing.
+ that's why i let the programmer poll the fds himself and then use
+ ssh_set_fd_toread, towrite or except. Then, he may use ssh_channel_select
+ with a NULL timeout to poll which channels have something to read, write or
+ error report.
+ Here is how it's going to work. The coder sets 3 different arrays with the
+ channels he wants to select(), the last entry being a NULL pointer. The
+ function will first poll them and return the chans that must be
+ read/write/excepted. If nothing has this state, the function will select()
+ using the timeout.
+ The function will return 0 if everything is ok, SSH_TIMEOUT or SSH_EINTR if
+ the select was interrupted by a signal. It is dangerous to execute any
+ channel-related functions into signal handlers. they should set a flag that
+ you read into your loop. this "trap" (SSH_EINTR) will permit you to catch
+ them faster and make your program responsive and look fast.
+ the function will return -1 if a serious problem happens.
+
+
+Error handling
+~~~~~~~~~~~~~~
+
+when an error happens, the programmer can get the error code and description
+with ssh_get_error(session). the creation of a failess constructor for
+ssh_session was needed for this reason.
+
+ssh_get_error_code(session) will return an error code into this subset:
+ SSH_NO_ERROR : no error :)
+ SSH_REQUEST_DENIED : you request for a functionality or a service that is not
+ allowed. The session can continue.
+ SSH_FATAL : Unrecoverable error. The session can't continue and you should
+ disconnect the session. It includes the connection being cut without a
+ disconnect() message.
+ If a disconnect() message or the channel was closed, a read on such a channel
+ won't produce an error. otherwise it will return -1 with a SSH_FATAL error
+ code.
+
+Server socket binding
+~~~~~~~~~~~~~~~~~~~~~
+
+It is not possible to bind a socket for ssh with a SSH_SESSION type, because a
+single bound port may lead to multiple ssh connections. That's why the
+SSH_BIND structure must be created. It uses options from the SSH_OPTIONS
+structure.
+
+SSH_BIND *ssh_bind_new()
+creates a structure
+ssh_bind_set_options(bind, options)
+set the option structure
+int ssh_bind_listen(bind)
+ bind and listen to the port. This call is not blocking. if some error
+ happens, it returns -1 and the error code can be found with perror().
+
+ssh_bind_set_blocking(bind, bool blocking)
+ should ssh_bind_accept() block or not.
+
+int ssh_bind_get_fd(bind)
+ return the bound file descriptor, that is the listener socket. you may put it
+ into a select() in your code to detect a connection attempt.
+
+ssh_bind_set_fd_toaccept(bind)
+ say that the listener socket has a connection to accept (to avoid
+ ssh_bind_accept() to do a select on it).
+
+SSH_SESSION *ssh_bind_accept(bind)
+ return a server handle to a ssh session. if the mode is blocking, the
+ function will always return a pointer to a session. if the mode is not
+ blocking, the function can return NULL if there is no connection to accept.
+
+This SSH_SESSION handle must then pass through the functions explained above.
+
+
+*server functions *
+
+int ssh_accept(session)
+ when a new connection is accepted, the handshake must be done. this function
+ will do the banner handshake and the key exchange.
+ it will return SSH_AGAIN if the session mode is non blocking, and the
+ function must be called again until an error occurs or the kex is done.
+
+Here, I had a few choises about *how* to implement the message parsing as a
+server. There are multiple ways to do it, one being callbacks and one being
+"Message" reading, parsing and then choice going to the user to use it and
+answer. I've choosen the latter because i believe it's the stronger method.
+A ssh server can receive 30 different kind of messages having to be dealt by
+the high level routines, like channel request_shell or authentication. Having
+a callback for all of them would produce a huge kludge of callbacks, with
+no relations on when there were called etc.
+A message based parsing allows the user to filtrate the messages he's
+interested into and to use a default answer for the others. Then, the callback
+thing is still possible to handle through a simple message code/callback
+function array.
+
+I did not define yet what it would look like, but i'm sure there will be a
+SSH_MESSAGE (they won't have a 1/1 correspondance with ssh packets) which will
+be read through
+SSH_MESSAGE *ssh_server_read_message(session).
+with all of the non-blocking stuff in head like returning NULL if the message
+is not full.
+Then, the message can be parsed, ie
+int ssh_message_get_code(message)
+which will return SSH_MESSAGE_AUTH
+then
+int ssh_message_get_subcode(message)
+which then will returh SSH_MESSAGE_AUTH_PASSWORD or _NONE or _PUBKEY etc.
+
+Then, once the message was parsed, the message will have to be answered, ie
+with the generic functions like
+ssh_message_accept(message) which says 'Ok your request is accepted' or
+ssh_message_deny(message) which says 'Your request is refused'.
+
+There would be specific message answer functions for some kind of messages
+like the authentication one. you may want to reply that the authentication is
+Partial rather than denied, and that you still accept some kind of auths, like
+ssh_message_auth_reply(message,SSH_AUTH_PARTIAL,SSH_AUTH_PASSWORD |
+SSH_AUTH_PUBKEY | SSH_AUTH_KEYBINT);
+
+I won't let the user have to deal with the channels himself. When a channel is
+going to be created by the remote size, a message will come asking to open a
+channel. the programmer can either deny or accept, in which case a CHANNEL
+object will be created and returned to the programmer. then, all standard
+channel functions will run.
+
+C. Change log of this document
+
+2. ssh_options_set_username finaly is kept into the options, because it can be
+set by ssh_options_getopt()
+
+1. first release
+
+D. End notes
+
+I think libssh must have a very simple to use, powerful and exhaustive API. It
+must have no design flaw either.
+While I got some good experience at the SSH protocol, I've never writen
+more-than-100 lines programs than use libssh and I don't really know the
+problems of the library. I'd like people who don't understand some detail into
+the API I describe here, who have comments or opinions about it to write me
+the soonest possible to limit the damages if I made something the completely
+wrong way.
+Thanks for your patience.
+