libssh2 / libssh2

the SSH library

Home Page:https://libssh2.org/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Missing API-calls for common structure fields make programing unduly difficult.

UnitedMarsupials opened this issue · comments

Describe the bug
A program to upload files over SFTP must go through several layers before it can start writing the data (using libssh2_sftp_write):

  • initialize and connect the socket
  • initialize LIBSSH2_SESSION -- and add the above socket to it (via libssh2_session_handshake())
  • initialize LIBSSH2_SFTP with the above session (via libssh2_sftp_init)
  • initialize LIBSSH2_SFTP_HANDLE with the above pointer (via libssh2_sftp_open_ex)

Each layer creates an internal structure -- and returns an opaque pointer to it, which is Ok. However, various upper-level operations still require the lower-level identifiers. Currently the programmers must keep all of them in their own code in addition to them being kept inside libssh2's own internal structures:

  • The _LIBSSH2_SFTP_HANDLE has a reference to LIBSSH2_SFTP
  • The _LIBSSH2_SFTP has a reference to the underlying LIBSSH2_SESSION (via the channel-pointer)
  • The _LIBSSH2_SESSION keeps the associated socket recorded too -- the socket_fd-field

But there are no API-calls for a library-client to access any of this.

To Reproduce
The below snippet trying to analyze the result of a libssh2_sftp_mkdir-call, for example, shows the need for both LIBSSH2_SFTP and LIBSSH2_SESSION pointers -- which must be kept around by the client on its own, despite already being recorded by the library:

		e = libssh2_sftp_mkdir(sftp, dir,
		    LIBSSH2_SFTP_S_IRWXU|
		    LIBSSH2_SFTP_S_IRGRP|LIBSSH2_SFTP_S_IXGRP|
		    LIBSSH2_SFTP_S_IROTH|LIBSSH2_SFTP_S_IXOTH);

		switch (e) {
		case 0:
			inform(2, "%s created", dir);
			break;
		case LIBSSH2_ERROR_SFTP_PROTOCOL:
			e = libssh2_sftp_last_error(sftp);
			if (e == LIBSSH2_FX_FILE_ALREADY_EXISTS)
				inform(1, "%s was already there", dir);
			else
				inform(0, "Creating %s: SFTP-error %d, "
				    "ignoring", dir, e);
			break;
		default:
			libssh2_session_last_error(session, &emsg, &elen, 0);
			inform(1, "Creating %s: %.*s, ignoring",
			    dir, elen, emsg);
		}

Another example is freeing-up/closing of an SFTP-transfer:

cleanup:
	if (remote)
		libssh2_sftp_close(remote);
	libssh2_sftp_shutdown(sftp);
	libssh2_session_disconnect(session, "Normal Shutdown");
	libssh2_session_free(session);
	close(socket);
	return result;

Expected behavior
Access to those fields of the internal structures, that originated from the client-program anyway, should be accessible to the program via API-calls like:

int libssh2_session_getsocket(const LIBSSH2_SESSION *);
LIBSSH2_SESSION *libssh2_sftp_getsession(const LIBSSH2_SFTP *);
LIBSSH2_SFTP *libssh2_sftp_getsftp(const LIBSSH2_SFTP_HANDLE *);

Version (please complete the following information):

  • OS and version: FreeBSD-13, RHEL7
  • libssh2 version: 1.10.0, 1.8.0 respectively
  • crypto backend and version: OpenSSL