static int ssh_stream_read( git_smart_subtransport_stream *stream, char *buffer, size_t buf_size, size_t *bytes_read) { int rc; ssh_stream *s = (ssh_stream *)stream; *bytes_read = 0; if (!s->sent_command && send_command(s) < 0) return -1; if ((rc = libssh2_channel_read(s->channel, buffer, buf_size)) < LIBSSH2_ERROR_NONE) { ssh_error(s->session, "SSH could not read data"); return -1; } /* * If we can't get anything out of stdout, it's typically a * not-found error, so read from stderr and signal EOF on * stderr. */ if (rc == 0) { if ((rc = libssh2_channel_read_stderr(s->channel, buffer, buf_size)) > 0) { giterr_set(GITERR_SSH, "%*s", rc, buffer); return GIT_EEOF; } else if (rc < LIBSSH2_ERROR_NONE) { ssh_error(s->session, "SSH could not read stderr"); return -1; } } *bytes_read = rc; return 0; }
static int exec_channel_command_exec(SSH_SESSION* p_session, const char* command, int (*callback)(char*, const char*, void*), void* obj) { char* buffer; int buffer_length = COMMAND_RESULT_BUFFER_LENGTH; int ec; int result_code; LIBSSH2_CHANNEL* channel; while((ec = libssh2_channel_exec(p_session->session_param->channel, command)) == LIBSSH2_ERROR_EAGAIN) { waitsocket(p_session->session_param->sock, p_session->session_param->session, TIMEOUT_SEC); } if(ec < 0) { debug_log(SSH_TERMINAL_COMMAND_EXEC_ERROR, "sync_command_exec : channel exec failed."); return SSH_TERMINAL_COMMAND_EXEC_ERROR; } buffer = (char*)malloc(sizeof(char) * (buffer_length + 1)); while(1) { do{ memset(buffer, 0, buffer_length + 1); ec = libssh2_channel_read(p_session->session_param->channel, buffer, buffer_length); if(ec == 0) { ec = libssh2_channel_read_stderr(p_session->session_param->channel, buffer, buffer_length); } if(ec > 0) { callback(buffer, command, obj); } } while(ec > 0); if(ec == LIBSSH2_ERROR_EAGAIN) { waitsocket(p_session->session_param->sock, p_session->session_param->session, TIMEOUT_SEC); } else { break; } } free(buffer); if(ec < 0) { debug_log(SSH_TERMINAL_CHANNEL_READ_ERROR, "sync_command_exec : channel read failed."); result_code = SSH_TERMINAL_CHANNEL_READ_ERROR; } else { result_code = 0; } while(libssh2_channel_close(p_session->session_param->channel) == LIBSSH2_ERROR_EAGAIN) { waitsocket(p_session->session_param->sock, p_session->session_param->session, TIMEOUT_SEC); } libssh2_channel_free(p_session->session_param->channel); while((channel = libssh2_channel_open_session(p_session->session_param->session)) == NULL && libssh2_session_last_error(p_session->session_param->session, NULL, NULL, 0) == LIBSSH2_ERROR_EAGAIN) { waitsocket(p_session->session_param->sock, p_session->session_param->session, TIMEOUT_SEC); } if(channel == NULL) { result_code = SSH_TERMINAL_CHANNEL_OPEN_ERROR; } p_session->session_param->channel = channel; return result_code; }
int Parser::runCommand(QString command) { // command channel //------------setup channel ---------------------- LIBSSH2_CHANNEL *channel = NULL; channel = libssh2_channel_open_session(session_); if ( channel == NULL ) { qDebug()<<"Failed to open a new channel\n"; socket_->disconnectFromHost(); return -1; } /* Force Data to on STDOUT and STDERR to be on seperate channels * read individually with *_read and *_read_stderr functions */ libssh2_channel_handle_extended_data(channel,LIBSSH2_CHANNEL_EXTENDED_DATA_NORMAL); libssh2_channel_set_blocking(channel, 1); { int rc; while ((rc=libssh2_channel_exec(channel, command.toLocal8Bit().constData()))==LIBSSH2_ERROR_EAGAIN ); if (rc) { return -1; } //-------read channel----------- int read; QString stdout_str; QString stderr_str; while(true) { //qDebug("libssh2_channel_read() >>>"); { QByteArray byte_array; byte_array.resize(4096); char* buffer=byte_array.data(); int buffer_size=byte_array.size(); read = libssh2_channel_read(channel, buffer, buffer_size-10); if(read>0) { QByteArray debug = QByteArray(buffer, read); stdout_str.append(debug); } if(LIBSSH2_ERROR_EAGAIN == read) { qDebug("LIBSSH2_ERROR_EAGAIN"); break; } else if(read < 0) { qDebug(" error reading from std channel"); closeChannel(channel); goto next_channel; } } { QByteArray byte_array; byte_array.resize(4096); char* buffer=byte_array.data(); int buffer_size=byte_array.size(); read = libssh2_channel_read_stderr(channel, buffer, buffer_size-10); if(read>0) { QByteArray debug = QByteArray(buffer, read); stderr_str.append(debug); } if(LIBSSH2_ERROR_EAGAIN == read) { qDebug("LIBSSH2_ERROR_EAGAIN"); break; } else if(read < 0) { qDebug(" error reading from stderr channel"); closeChannel(channel); goto next_channel; } } int i = libssh2_channel_eof(channel); if(i) { //qDebug("libssh2_channel_eof %i", i); closeChannel(channel); goto next_channel; } } next_channel: if(!stdout_str.isEmpty()) { qDebug()<<"STDOUT:\n"<<stdout_str; } if(!stderr_str.isEmpty()) { qDebug()<<"STDERR:\n"<<stderr_str; } } return 1; }
/** * usage: seashell-tunnel [username] [host] [target] * * First n bytes on standard input should be: * * ---------------------------------------------------------------------------------------------------------- * | length / 4 byte unsigned integer | authentication method / 1 byte | authentication data : length bytes | * ---------------------------------------------------------------------------------------------------------- * * Authentication methods: * 0 - password. * * Currently, only password authentication is supported. Therefore, * the authentication method is ignored. It might be worth looking * at supporting public key authentication in the future. This'll * require extending the connection launcher. * * Bytes after n are simply forwarded onwards with no processing applied. * * For password authentication, the null terminating byte is expected to be in the authentication data. * * seashell-tunnel will write a single ASCII 'O' (79) denoting handshake success before starting * two-way forwarding. * * IP address are also written; IPv4 passed as X.X.X.X, IPv6 as [:X:X::X] */ int main (int argc, char *argv[]) { uint32_t length = 0; uint8_t method = 0; int8_t* data = NULL; int i = 0; char stderr_buffer[4096]; ssize_t stderr_read = 0; if (argc < 4) { fprintf(stderr, "usage: %s [username] [host] [target]\n", argv[0]); return IO_ERROR; } FPRINTF_IF_DEBUG(stderr, "%s: Launching tunnel!\n", argv[1]); for (i = 0; i < 4; i++) { uint8_t buf; if (1 != read(0, &buf, 1)) { fprintf(stderr, "%s: I/O error on reading authentication packet length.\n", argv[1]); return IO_ERROR; } length |= buf << (8 * i); } FPRINTF_IF_DEBUG(stderr, "%s: Read authentication packet length.\n", argv[1]); if (1 != read(0, &method, 1)) { fprintf(stderr, "%s: I/O error on reading authentication method.\n", argv[1]); return IO_ERROR; } FPRINTF_IF_DEBUG(stderr, "%s: Read authentication method.\n", argv[1]); data = malloc(length); if (!data) { fprintf(stderr, "%s: Ran out of memory!\n", argv[1]); return OTHER_ERROR; } if (length != read(0, data, length)) { fprintf(stderr, "%s: Couldn't read authentication data!\n", argv[1]); return IO_ERROR; } FPRINTF_IF_DEBUG(stderr, "%s: Read authentication data.\n", argv[1]); /** This is where we need to handle extra authentication methods. */ int error; char* exitsignal; error = seashell_tunnel_startup(); if (error) { fprintf(stderr, "%s: Error launching libssh2!\n", argv[1]); goto end; } char remote_addr[128]; memset(remote_addr, 0, 128); int family; struct seashell_connection* conn = seashell_tunnel_connect_password( argv[2], argv[1], data, &error, remote_addr, &family, argv[3]); if (!conn) { fprintf(stderr, "%s: Error on opening tunnel to %s: %d\n", argv[1], argv[2], error); goto end; } /** Signal success */ { const int8_t success = 'O'; write(1, &success, 1); uint8_t addrlen = strlen(remote_addr); /** Write the address, formatted for URI safety. */ /** IPv6 addresses need to be formatted for safety. */ if (family == AF_INET6) { char buffer[130] = {0}; int bufferlen = snprintf(buffer, 130, "[%s]", remote_addr); write(1, &bufferlen, 1); write(1, buffer, bufferlen); } /** IPv4 addresses do not need to be formatted. */ else if (family == AF_INET) { write(1, &addrlen, 1); write(1, remote_addr, addrlen); } else { fprintf(stderr, "%s: Unknown address family %d!\n", argv[1], family); goto end; } FPRINTF_IF_DEBUG(stderr, "%s: Remote address is '%s' (%d) (%d)\n", argv[1], remote_addr, (int)addrlen, family); } FPRINTF_IF_DEBUG(stderr, "%s: Tunnel launched!\n", argv[1]); /** Now we select from fd 0, write to socket, * select from socket, write to fd 1 */ error = loop_and_copy(0, 1, conn); if (error) { fprintf(stderr, "%s: I/O error on copy: %d\n", argv[1], error); goto report_errors; } /** Make sure the remote end hung up cleanly. */ error = libssh2_channel_get_exit_status(conn->channel); libssh2_channel_get_exit_signal(conn->channel, &exitsignal, NULL, NULL, NULL, NULL, NULL); FPRINTF_IF_DEBUG(stderr, "%s: Remote end hung up with %d (%s)\n", argv[1], error, exitsignal); if (exitsignal) { error = OTHER_ERROR; } report_errors: /** Drain stderr on the SSH connection. */ while ((stderr_read = libssh2_channel_read_stderr(conn->channel, stderr_buffer, sizeof(char)*4096)) > 0) { fwrite(stderr_buffer, sizeof(char), stderr_read, stderr); } end: seashell_tunnel_free(conn); seashell_tunnel_teardown(); return error; }
/** * loop_and_copy (int infd, int outfd, struct seashell_connection* conn) * Copies data to/from the file descriptors and socket. * * * Arguments: * infd, outfd - input/output file descriptors. * conn - Seashell connection object. * * Returns: * 0 on clean disconnect, nonzero value otherwise. */ int loop_and_copy(int infd, int outfd, struct seashell_connection* conn) { struct timeval timeout; fd_set readfds; char buffer[4096]; ssize_t start = 0, len = 0, rc = 0; int nfds = 1 + MAX(infd, conn->sockfd); while (1) { FD_ZERO(&readfds); FD_SET(conn->sockfd, &readfds); FD_SET(infd, &readfds); timeout.tv_sec = 10; timeout.tv_usec = 0; if (select(nfds, &readfds, NULL, NULL, &timeout) > 0) { /** We're OK only when we have something to read from and something to write to. */ /** * Something to read from remote - might block on write, this is OK. * Time permitting, it might be nice to have a write queue and * go through the select loop again for fairness, * but it really doesn't matter. */ if (FD_ISSET(conn->sockfd, &readfds)) { /** Do our reads in nonblocking mode as we may get payload data for * some other stream. */ seashell_set_nonblocking(conn); len = libssh2_channel_read(conn->channel, buffer, sizeof(buffer)); seashell_set_blocking(conn); if (len == LIBSSH2_ERROR_EAGAIN) { } else if (len < 0) { return len; } else if (len > 0) { start = 0; while (len) { rc = write(outfd, buffer + start, len); if (rc < 0) { return rc; } len -= rc; start += rc; } } /** Drain stderr. */ seashell_set_nonblocking(conn); len = libssh2_channel_read_stderr(conn->channel, buffer, sizeof(buffer)); seashell_set_blocking(conn); if (len == LIBSSH2_ERROR_EAGAIN) { } else if (len < 0) { return len; } else if (len > 0) { start = 0; while (len) { rc = write(2, buffer + start, len); if (rc < 0) { return rc; } len -= rc; start += rc; } } } /** * Something to read from local - might block on write, this is OK. * See above for rationale, and libssh2_channel_write doesn't seem * to block nicely. Oh well. */ if (FD_ISSET(infd, &readfds)) { len = read(infd, buffer, sizeof(buffer)); if (len < 0) { return len; } else if (len == 0) { return 0; } else { start = 0; while (len) { rc = libssh2_channel_write(conn->channel, buffer + start, len); if (rc < 0) { return rc; } len -= rc; start += rc; } } } } /** * And if we died... */ if (libssh2_channel_eof(conn->channel) == 1) { return 0; } } }
int ssh::exec_cmd(const string &command) { int rc; /* Exec non-blocking on the remove host */ while( (channel = libssh2_channel_open_session(session)) == NULL && libssh2_session_last_error(session,NULL,NULL,0) == LIBSSH2_ERROR_EAGAIN ) { waitsocket(_sock_fd, session); } if( channel == NULL ) { cout << "Error" << std::endl; exit( 1 ); } while( (rc = libssh2_channel_exec(channel, command.c_str())) == LIBSSH2_ERROR_EAGAIN ) { waitsocket(_sock_fd, session); } if( rc != 0 ) { cout << "Error" << std::endl; exit( 1 ); } for( ;; ) { /* loop until we block */ int rc; do { char buffer[0x4000]; rc = libssh2_channel_read( channel, buffer, sizeof(buffer) ); if( rc > 0 ) { /* int i; bytecount += rc;*/ /* cout << "We read: " << std::endl;*/ cout << "[" << _ip_addr << "]====start====== " << std::endl; /*for( i=0; i < rc; ++i ) fputc( buffer[i], stderr);*/ cout << buffer; cout << "[" << _ip_addr << "]====end======== " << std::endl; } /*else { if( rc != LIBSSH2_ERROR_EAGAIN ) no need to output this for the EAGAIN case cout << "libssh2_channel_read returned " << rc << std::endl; }*/ } while( rc > 0 ); do { char buffer2[0x4000]; rc = libssh2_channel_read_stderr( channel, buffer2, sizeof(buffer2) ); if( rc > 0 ) { /* int i; bytecount += rc;*/ /*cout << "We read: " << std::endl;*/ cout << "[" << _ip_addr << "]====start====== " << std::endl; /*for( i=0; i < rc; ++i ) fputc( buffer[i], stderr);*/ cout << buffer2; cout << "[" << _ip_addr << "]====end======== " << std::endl; } /*else { if( rc != LIBSSH2_ERROR_EAGAIN ) no need to output this for the EAGAIN case cout << "libssh2_channel_read_stderr returned " << rc << std::endl; }*/ } while( rc > 0 ); /* this is due to blocking that would occur otherwise so we loop on this condition */ if( rc == LIBSSH2_ERROR_EAGAIN ) { waitsocket(_sock_fd, session); } else break; } quit_channel(); return 0; }
QString Parser::sshRequest(QString commandline) { QString host_ip(this->sharedHost); QString user_name=this->sharedUser; QString pass_word=this->sharedPass; //---------- connection -------------- int libssh2_error = libssh2_init(0); if(libssh2_error) { qDebug("libssh2_init() error: %d", libssh2_error); //return -2; } QTcpSocket socket; socket.connectToHost(host_ip, 22); if(!socket.waitForConnected()) { qDebug("Error connecting to host %s", host_ip.toLocal8Bit().constData()); //return -1; } LIBSSH2_SESSION *session = libssh2_session_init(); if(!session) { qDebug("libssh2_session_init() failed"); //return -2; } libssh2_error = libssh2_session_startup(session, socket.socketDescriptor()); if(libssh2_error) { qDebug("libssh2_session_startup() error: %d", libssh2_error); //return -3; } { /* At this point we havn't yet authenticated. The first thing to do * is check the hostkey's fingerprint against our known hosts Your app * may have it hard coded, may go to a file, may present it to the * user, that's your call */ const char *fingerprint = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_SHA1); } libssh2_userauth_list(session, user_name.toLocal8Bit().constData(), user_name.toLocal8Bit().length()); if(libssh2_userauth_password( session, user_name.toLocal8Bit().constData(), pass_word.toLocal8Bit().constData() )) { qDebug("Password authentication failed"); socket.disconnectFromHost(); libssh2_session_disconnect(session, "Client disconnecting for error"); libssh2_session_free(session); libssh2_exit(); //return -4; } // command channel //------------setup channel ---------------------- LIBSSH2_CHANNEL *channel = NULL; channel = libssh2_channel_open_session(session); int rc; if ( channel == NULL ) { qDebug()<<"Failed to open a new channel\n"; socket.disconnectFromHost(); //return -1; } libssh2_channel_set_blocking(channel, 1); while ((rc=libssh2_channel_exec(channel, commandline.toLocal8Bit().constData()))==LIBSSH2_ERROR_EAGAIN ); if (rc) { //return -1; } //-------read channel----------- int read; QByteArray byte_array; byte_array.resize(4096); char* buffer=byte_array.data(); int buffer_size=byte_array.size(); QString myOutPut; while(true) { { read = libssh2_channel_read(channel, buffer, buffer_size); QByteArray debug = QByteArray(buffer, read); //qDebug()<<"STDOUT: "<<debug.constData(); myOutPut = debug.constData(); qDebug() << myOutPut; if(LIBSSH2_ERROR_EAGAIN == read) { qDebug("LIBSSH2_ERROR_EAGAIN"); break; } else if(read < 0) { qDebug(" error reading from channel"); closeChannel(channel); goto next_channel; } } { read = libssh2_channel_read_stderr(channel, buffer, buffer_size); QByteArray debug = QByteArray(buffer, read); qDebug()<<"STDERR: "<<debug.constData(); if(LIBSSH2_ERROR_EAGAIN == read) { qDebug("LIBSSH2_ERROR_EAGAIN"); break; } else if(read < 0) { qDebug(" error reading from channel"); closeChannel(channel); goto next_channel; } } int i=0; i = libssh2_channel_eof(channel); if(i) { qDebug("libssh2_channel_eof %i", i); closeChannel(channel); goto next_channel; } } next_channel: //------------ clean session socket.disconnectFromHost(); libssh2_session_disconnect(session, "Client disconnecting normally"); libssh2_session_free(session); libssh2_exit(); return myOutPut; }