/*! \reimp */ qint64 QxtSshChannel::readData(char* buff, qint64 len) { ssize_t ret=libssh2_channel_read_ex(d->d_channel, d->d_read_stream_id,buff, len); if(ret<0){ if(ret==LIBSSH2_ERROR_EAGAIN){ return 0; }else{ #ifdef QXT_DEBUG_SSH qDebug()<<"read err"<<ret; #endif return -1; } } return ret; }
BinaryNode *SSH2Channel::readBinary(qore_size_t size, int stream_id, int timeout_ms, ExceptionSink *xsink) { AutoLocker al(parent->m); if (check_open(xsink)) return 0; SimpleRefHolder<BinaryNode> bin(new BinaryNode); BlockingHelper bh(parent); qore_offset_t rc; // bytes read qore_size_t b_read = 0; // bytes remaining qore_size_t b_remaining = size; while (true) { char buffer[QSSH2_BUFSIZE]; qore_size_t to_read = QSSH2_BUFSIZE < b_remaining ? QSSH2_BUFSIZE : b_remaining; rc = libssh2_channel_read_ex(channel, stream_id, buffer, to_read); //printd(5, "SSH2Channel::read() rc=%lld (EAGAIN=%d)\n", rc, LIBSSH2_ERROR_EAGAIN); if (rc > 0) { bin->append(buffer, rc); b_read += rc; b_remaining -= rc; if (b_read >= size) break; continue; } if (!rc || rc == LIBSSH2_ERROR_EAGAIN) { rc = parent->waitSocketUnlocked(timeout_ms); if (!rc) { xsink->raiseException(SSH2CHANNEL_TIMEOUT, "read timeout after %dms reading %lld byte%s of %lld requested", timeout_ms, b_read, b_read == 1 ? "" : "s", size); return 0; } if (rc < 0) { xsink->raiseException(SSH2CHANNEL_TIMEOUT, strerror(errno)); return 0; } } } if (rc < 0 && rc != LIBSSH2_ERROR_EAGAIN) { parent->doSessionErrUnlocked(xsink); return 0; } return bin.release(); }
static PyObject * channel_read(SSH2_ChannelObj *self, PyObject *args) { int ret; int bufsiz; int stream_id = 0; PyObject *buf; if (!PyArg_ParseTuple(args, "i|i:read", &bufsiz, &stream_id)) return NULL; if (bufsiz < 0) { PyErr_SetString(PyExc_ValueError, "negative size"); return NULL; } if ((buf = PyBytes_FromStringAndSize(NULL, bufsiz)) == NULL) return NULL; Py_BEGIN_ALLOW_THREADS ret = libssh2_channel_read_ex(self->channel, stream_id, PyBytes_AS_STRING(buf), bufsiz); Py_END_ALLOW_THREADS if (ret < 0) { Py_DECREF(buf); /* We have to work around a bug in libssh2, that _libssh2_error() is not * called by libssh2_channel_read_ex() when the transport layer returns * LIBSSH2_ERROR_EAGAIN. So in that case the last error is not set and * the RAISE_SSH2_ERROR macro will not be able to raise the correct exception. * Thanks to Daniel Stenberg, who has fixed that issue now (see 2db4863). * However in order that our bindings work correctly with older versions * of libssh2, we need the workaround below. */ if (ret == LIBSSH2_ERROR_EAGAIN) { PyObject *exc; PyObject *value; exc = PyObject_CallFunction(SSH2_Error, "s", "Would block"); value=Py_BuildValue("i", ret); PyObject_SetAttrString(exc, "errno", value); PyErr_SetObject(SSH2_Error, exc); Py_DECREF(exc); Py_DECREF(value); return NULL; } RAISE_SSH2_ERROR(self->session) }
void cql_ccm_bridge_t::terminal_read_stream(cql_escape_sequences_remover_t& buffer, int stream) { char buf[128]; while (true) { // disable blocking libssh2_session_set_blocking(_ssh_internals->_session, 0); ssize_t readed = libssh2_channel_read_ex(_ssh_internals->_channel, stream, buf, sizeof(buf)); // return if no data to read if (readed == LIBSSH2_ERROR_EAGAIN || readed == 0) { return; } // some error occurred if (readed < 0) { throw cql_ccm_bridge_exception_t("error during reading from socket"); } buffer.push_character_range(buf, buf + readed); } }
int process_d::read_some( char* data, size_t len, int stream_id ) { if( !sshc->my->m_session ) { MACE_SSH_THROW( "Session closed\n" ); } int rc; char* buf = data; size_t buflen = len; do { rc = libssh2_channel_read_ex( chan, stream_id, buf, buflen ); if( rc > 0 ) { buf += rc; buflen -= rc; return buf-data; } else if( rc == 0 ) { if( libssh2_channel_eof( chan ) ) { return -1; // eof } sshc->my->wait_on_socket(); } else { if( rc == LIBSSH2_ERROR_EAGAIN ) { if( 0 < (buf-data) ) { return buf-data; } else { sshc->my->wait_on_socket(); rc = 0; continue; } } else { char* msg; if( !sshc || !sshc->my || !sshc->my->m_session ) { MACE_SSH_THROW( "Session closed" ); } slog( "my: %1%", sshc->my ); rc = libssh2_session_last_error( sshc->my->m_session, &msg, 0, 0 ); MACE_SSH_THROW( "read failed: %1% - %2%", %rc %msg ); return buf-data; } } } while( rc >= 0 && buflen); return buf-data; }
static size_t php_ssh2_channel_stream_read(php_stream *stream, char *buf, size_t count TSRMLS_DC) { php_ssh2_channel_data *abstract = (php_ssh2_channel_data*)stream->abstract; ssize_t readstate; LIBSSH2_SESSION *session; stream->eof = libssh2_channel_eof(abstract->channel); libssh2_channel_set_blocking(abstract->channel, abstract->is_blocking); session = (LIBSSH2_SESSION *)zend_fetch_resource(NULL TSRMLS_CC, abstract->session_rsrc, PHP_SSH2_SESSION_RES_NAME, NULL, 1, le_ssh2_session); #ifdef PHP_SSH2_SESSION_TIMEOUT if (abstract->is_blocking) { libssh2_session_set_timeout(session, abstract->timeout); } #endif readstate = libssh2_channel_read_ex(abstract->channel, abstract->streamid, buf, count); #ifdef PHP_SSH2_SESSION_TIMEOUT if (abstract->is_blocking) { libssh2_session_set_timeout(session, 0); } #endif if (readstate == LIBSSH2_ERROR_EAGAIN) { readstate = 0; } if (readstate < 0) { char *error_msg = NULL; if (libssh2_session_last_error(session, &error_msg, NULL, 0) == readstate) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failure '%s' (%ld)", error_msg, readstate); } stream->eof = 1; readstate = 0; } return readstate; }
BinaryNode *SSH2Channel::readBinary(ExceptionSink *xsink, int stream_id, int timeout_ms) { AutoLocker al(parent->m); if (check_open(xsink)) return 0; SimpleRefHolder<BinaryNode> bin(new BinaryNode); BlockingHelper bh(parent); qore_offset_t rc; bool first = true; do { loop0: char buffer[QSSH2_BUFSIZE]; rc = libssh2_channel_read_ex(channel, stream_id, buffer, QSSH2_BUFSIZE); //printd(5, "SSH2Channel::readBinary() rc=%ld (EAGAIN=%d)\n", rc, LIBSSH2_ERROR_EAGAIN); if (rc > 0) { bin->append(buffer, rc); } else if (rc == LIBSSH2_ERROR_EAGAIN && !bin->size() && first) { first = false; if ((rc = parent->waitSocketUnlocked(xsink, SSH2CHANNEL_TIMEOUT, "SSH2CHANNEL-READBINARY-ERROR", "SSH2Channel::readBinary", timeout_ms))) return 0; goto loop0; } } while (rc > 0); if (rc < 0 && rc != LIBSSH2_ERROR_EAGAIN) { parent->doSessionErrUnlocked(xsink); return 0; } return bin.release(); }
QoreStringNode *SSH2Channel::read(ExceptionSink *xsink, int stream_id, int timeout_ms) { AutoLocker al(parent->m); if (check_open(xsink)) return 0; QoreStringNodeHolder str(new QoreStringNode(enc)); BlockingHelper bh(parent); qore_offset_t rc; bool first = true; do { loop0: char buffer[QSSH2_BUFSIZE]; rc = libssh2_channel_read_ex(channel, stream_id, buffer, QSSH2_BUFSIZE); //printd(0, "SSH2Channel::read() rc=%ld (EAGAIN=%d)\n", rc, LIBSSH2_ERROR_EAGAIN); if (rc > 0) { str->concat(buffer, rc); } else if (rc == LIBSSH2_ERROR_EAGAIN && !str->strlen() && first) { first = false; if ((rc = parent->waitSocketUnlocked(xsink, SSH2CHANNEL_TIMEOUT, "SSH2CHANNEL-READ-ERROR", "SSH2Channel::read", timeout_ms))) return 0; goto loop0; } } while (rc > 0); if (rc < 0 && rc != LIBSSH2_ERROR_EAGAIN) { parent->doSessionErrUnlocked(xsink); return 0; } return str.release(); }
int ssh_exec(ssh_conn_t *conn, param_t *params) { LIBSSH2_CHANNEL *channel; int rc; int exitcode = 127; char *exitsignal=(char *)"none"; const char *commandline = params->command; /* Exec non-blocking on the remove host */ while( (channel = libssh2_channel_open_session(conn->session)) == NULL && libssh2_session_last_error(conn->session,NULL,NULL,0) == LIBSSH2_ERROR_EAGAIN ) { waitsocket(conn); } if( channel == NULL ) { fprintf(stderr,"Error\n"); return ( 1 ); } rc = ssh_setenv(channel, params); if(rc<0) { if(rc==LIBSSH2_ERROR_CHANNEL_REQUEST_DENIED) printf("Error: Environment variable is not accepted by target SSH server."); goto shutdown; } while( (rc = libssh2_channel_exec(channel, commandline)) == LIBSSH2_ERROR_EAGAIN ) { waitsocket(conn); } if( rc != 0 ) { fprintf(stderr,"Error\n"); return ( 1 ); } int stream_id = 0; for( ;; ) { /* loop until we block */ int rc; do { char buffer[0x4000]; rc = libssh2_channel_read_ex( channel, stream_id, buffer, sizeof(buffer) ); if( rc > 0 ) { fwrite(buffer, sizeof(char), rc, stream_id==0?stdout:stderr); }else{ if( rc != LIBSSH2_ERROR_EAGAIN ) goto shutdown; } } while( rc > 0 ); /* this is due to blocking that would occur otherwise so we loop on this condition */ if( rc == LIBSSH2_ERROR_EAGAIN ) { waitsocket(conn); } else break; stream_id = stream_id==0?1:0; } while( (rc = libssh2_channel_close(channel)) == LIBSSH2_ERROR_EAGAIN ) waitsocket(conn); if( rc == 0 ) { exitcode = libssh2_channel_get_exit_status( channel ); libssh2_channel_get_exit_signal(channel, &exitsignal, NULL, NULL, NULL, NULL, NULL); } shutdown: libssh2_channel_free(channel); channel = NULL; return exitcode; }
/* {{{ libssh2_scp_send_ex * Send a file using SCP * * NOTE: Will block in a busy loop on error. This has to be done, * otherwise the blocking error code would erase the true * cause of the error. */ LIBSSH2_API LIBSSH2_CHANNEL * libssh2_scp_send_ex(LIBSSH2_SESSION * session, const char *path, int mode, size_t size, long mtime, long atime) { int path_len = strlen(path); unsigned const char *base; int rc; if (session->scpSend_state == libssh2_NB_state_idle) { session->scpSend_command_len = path_len + sizeof("scp -t "); if (mtime || atime) { session->scpSend_command_len++; } session->scpSend_command = LIBSSH2_ALLOC(session, session->scpSend_command_len); if (!session->scpSend_command) { libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate a command buffer for scp session", 0); return NULL; } if (mtime || atime) { memcpy(session->scpSend_command, "scp -pt ", sizeof("scp -pt ") - 1); memcpy(session->scpSend_command + sizeof("scp -pt ") - 1, path, path_len); } else { memcpy(session->scpSend_command, "scp -t ", sizeof("scp -t ") - 1); memcpy(session->scpSend_command + sizeof("scp -t ") - 1, path, path_len); } session->scpSend_command[session->scpSend_command_len - 1] = '\0'; _libssh2_debug(session, LIBSSH2_DBG_SCP, "Opening channel for SCP send"); /* Allocate a channel */ session->scpSend_state = libssh2_NB_state_created; } if (session->scpSend_state == libssh2_NB_state_created) { session->scpSend_channel = libssh2_channel_open_ex(session, "session", sizeof("session") - 1, LIBSSH2_CHANNEL_WINDOW_DEFAULT, LIBSSH2_CHANNEL_PACKET_DEFAULT, NULL, 0); if (!session->scpSend_channel) { if (libssh2_session_last_errno(session) != LIBSSH2_ERROR_EAGAIN) { /* previous call set libssh2_session_last_error(), pass it through */ LIBSSH2_FREE(session, session->scpSend_command); session->scpSend_command = NULL; session->scpSend_state = libssh2_NB_state_idle; return NULL; } else if (libssh2_session_last_errno(session) == LIBSSH2_ERROR_EAGAIN) { libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block starting up channel", 0); return NULL; } } session->scpSend_state = libssh2_NB_state_sent; } if (session->scpSend_state == libssh2_NB_state_sent) { /* Request SCP for the desired file */ rc = libssh2_channel_process_startup(session->scpSend_channel, "exec", sizeof("exec") - 1, (char *) session->scpSend_command, session->scpSend_command_len); if (rc == PACKET_EAGAIN) { libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block requesting SCP startup", 0); return NULL; } else if (rc) { /* previous call set libssh2_session_last_error(), pass it through */ LIBSSH2_FREE(session, session->scpSend_command); session->scpSend_command = NULL; libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, "Unknown error while getting error string", 0); goto scp_send_error; } LIBSSH2_FREE(session, session->scpSend_command); session->scpSend_command = NULL; session->scpSend_state = libssh2_NB_state_sent1; } if (session->scpSend_state == libssh2_NB_state_sent1) { /* Wait for ACK */ rc = libssh2_channel_read_ex(session->scpSend_channel, 0, (char *) session->scpSend_response, 1); if (rc == PACKET_EAGAIN) { libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block waiting for response from remote", 0); return NULL; } else if ((rc <= 0) || (session->scpSend_response[0] != 0)) { libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, "Invalid ACK response from remote", 0); goto scp_send_error; } if (mtime || atime) { /* Send mtime and atime to be used for file */ session->scpSend_response_len = snprintf((char *) session->scpSend_response, LIBSSH2_SCP_RESPONSE_BUFLEN, "T%ld 0 %ld 0\n", mtime, atime); _libssh2_debug(session, LIBSSH2_DBG_SCP, "Sent %s", session->scpSend_response); } session->scpSend_state = libssh2_NB_state_sent2; } /* Send mtime and atime to be used for file */ if (mtime || atime) { if (session->scpSend_state == libssh2_NB_state_sent2) { rc = libssh2_channel_write_ex(session->scpSend_channel, 0, (char *) session->scpSend_response, session->scpSend_response_len); if (rc == PACKET_EAGAIN) { libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block sending time data for SCP file", 0); return NULL; } else if (rc != session->scpSend_response_len) { libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send time data for SCP file", 0); goto scp_send_error; } session->scpSend_state = libssh2_NB_state_sent3; } if (session->scpSend_state == libssh2_NB_state_sent3) { /* Wait for ACK */ rc = libssh2_channel_read_ex(session->scpSend_channel, 0, (char *) session->scpSend_response, 1); if (rc == PACKET_EAGAIN) { libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block waiting for response", 0); return NULL; } else if ((rc <= 0) || (session->scpSend_response[0] != 0)) { libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, "Invalid ACK response from remote", 0); goto scp_send_error; } session->scpSend_state = libssh2_NB_state_sent4; } } else { if (session->scpSend_state == libssh2_NB_state_sent2) { session->scpSend_state = libssh2_NB_state_sent4; } } if (session->scpSend_state == libssh2_NB_state_sent4) { /* Send mode, size, and basename */ base = (unsigned char *) strrchr(path, '/'); if (base) { base++; } else { base = (unsigned char *) path; } session->scpSend_response_len = snprintf((char *) session->scpSend_response, LIBSSH2_SCP_RESPONSE_BUFLEN, "C0%o %lu %s\n", mode, (unsigned long) size, base); _libssh2_debug(session, LIBSSH2_DBG_SCP, "Sent %s", session->scpSend_response); session->scpSend_state = libssh2_NB_state_sent5; } if (session->scpSend_state == libssh2_NB_state_sent5) { rc = libssh2_channel_write_ex(session->scpSend_channel, 0, (char *) session->scpSend_response, session->scpSend_response_len); if (rc == PACKET_EAGAIN) { libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block send core file data for SCP file", 0); return NULL; } else if (rc != session->scpSend_response_len) { libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send core file data for SCP file", 0); goto scp_send_error; } session->scpSend_state = libssh2_NB_state_sent6; } if (session->scpSend_state == libssh2_NB_state_sent6) { /* Wait for ACK */ rc = libssh2_channel_read_ex(session->scpSend_channel, 0, (char *) session->scpSend_response, 1); if (rc == PACKET_EAGAIN) { libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block waiting for response", 0); return NULL; } else if (rc <= 0) { libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, "Invalid ACK response from remote", 0); goto scp_send_error; } else if (session->scpSend_response[0] != 0) { /* * Set this as the default error for here, if * we are successful it will be replaced */ libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, "Invalid ACK response from remote", 0); session->scpSend_err_len = libssh2_channel_packet_data_len(session->scpSend_channel, 0); session->scpSend_err_msg = LIBSSH2_ALLOC(session, session->scpSend_err_len + 1); if (!session->scpSend_err_msg) { goto scp_send_error; } memset(session->scpSend_err_msg, 0, session->scpSend_err_len + 1); /* Read the remote error message */ rc = libssh2_channel_read_ex(session->scpSend_channel, 0, session->scpSend_err_msg, session->scpSend_err_len); if (rc <= 0) { /* * Since we have alread started reading this packet, it is * already in the systems so it can't return PACKET_EAGAIN */ LIBSSH2_FREE(session, session->scpSend_err_msg); session->scpSend_err_msg = NULL; goto scp_send_error; } libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, session->scpSend_err_msg, 1); session->scpSend_err_msg = NULL; goto scp_send_error; } } session->scpSend_state = libssh2_NB_state_idle; return session->scpSend_channel; scp_send_error: while (libssh2_channel_free(session->scpSend_channel) == PACKET_EAGAIN); session->scpSend_channel = NULL; session->scpSend_state = libssh2_NB_state_idle; return NULL; }
/* {{{ libssh2_scp_recv * Open a channel and request a remote file via SCP * * NOTE: Will block in a busy loop on error. This has to be done, * otherwise the blocking error code would erase the true * cause of the error. */ LIBSSH2_API LIBSSH2_CHANNEL * libssh2_scp_recv(LIBSSH2_SESSION * session, const char *path, struct stat * sb) { int path_len = strlen(path); int rc; if (session->scpRecv_state == libssh2_NB_state_idle) { session->scpRecv_mode = 0; session->scpRecv_size = 0; session->scpRecv_mtime = 0; session->scpRecv_atime = 0; session->scpRecv_command_len = path_len + sizeof("scp -f "); if (sb) { session->scpRecv_command_len++; } session->scpRecv_command = LIBSSH2_ALLOC(session, session->scpRecv_command_len); if (!session->scpRecv_command) { libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate a command buffer for SCP session", 0); return NULL; } if (sb) { memcpy(session->scpRecv_command, "scp -pf ", sizeof("scp -pf ") - 1); memcpy(session->scpRecv_command + sizeof("scp -pf ") - 1, path, path_len); } else { memcpy(session->scpRecv_command, "scp -f ", sizeof("scp -f ") - 1); memcpy(session->scpRecv_command + sizeof("scp -f ") - 1, path, path_len); } session->scpRecv_command[session->scpRecv_command_len - 1] = '\0'; _libssh2_debug(session, LIBSSH2_DBG_SCP, "Opening channel for SCP receive"); session->scpRecv_state = libssh2_NB_state_created; } if (session->scpRecv_state == libssh2_NB_state_created) { /* Allocate a channel */ do { session->scpRecv_channel = libssh2_channel_open_ex(session, "session", sizeof("session") - 1, LIBSSH2_CHANNEL_WINDOW_DEFAULT, LIBSSH2_CHANNEL_PACKET_DEFAULT, NULL, 0); if (!session->scpRecv_channel) { if (libssh2_session_last_errno(session) != LIBSSH2_ERROR_EAGAIN) { LIBSSH2_FREE(session, session->scpRecv_command); session->scpRecv_command = NULL; session->scpRecv_state = libssh2_NB_state_idle; return NULL; } else if (libssh2_session_last_errno(session) == LIBSSH2_ERROR_EAGAIN) { libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block starting up channel", 0); return NULL; } } } while (!session->scpRecv_channel); session->scpRecv_state = libssh2_NB_state_sent; } if (session->scpRecv_state == libssh2_NB_state_sent) { /* Request SCP for the desired file */ rc = libssh2_channel_process_startup(session->scpRecv_channel, "exec", sizeof("exec") - 1, (char *) session->scpRecv_command, session->scpRecv_command_len); if (rc == PACKET_EAGAIN) { libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block requesting SCP startup", 0); return NULL; } else if (rc) { LIBSSH2_FREE(session, session->scpRecv_command); session->scpRecv_command = NULL; goto scp_recv_error; } LIBSSH2_FREE(session, session->scpRecv_command); session->scpRecv_command = NULL; _libssh2_debug(session, LIBSSH2_DBG_SCP, "Sending initial wakeup"); /* SCP ACK */ session->scpRecv_response[0] = '\0'; session->scpRecv_state = libssh2_NB_state_sent1; } if (session->scpRecv_state == libssh2_NB_state_sent1) { rc = libssh2_channel_write_ex(session->scpRecv_channel, 0, (char *) session->scpRecv_response, 1); if (rc == PACKET_EAGAIN) { libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block sending initial wakeup", 0); return NULL; } else if (rc != 1) { goto scp_recv_error; } /* Parse SCP response */ session->scpRecv_response_len = 0; session->scpRecv_state = libssh2_NB_state_sent2; } if ((session->scpRecv_state == libssh2_NB_state_sent2) || (session->scpRecv_state == libssh2_NB_state_sent3)) { while (sb && (session->scpRecv_response_len < LIBSSH2_SCP_RESPONSE_BUFLEN)) { unsigned char *s, *p; if (session->scpRecv_state == libssh2_NB_state_sent2) { rc = libssh2_channel_read_ex(session->scpRecv_channel, 0, (char *) session-> scpRecv_response + session->scpRecv_response_len, 1); if (rc == PACKET_EAGAIN) { libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block waiting for SCP response", 0); return NULL; } else if (rc <= 0) { /* Timeout, give up */ libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, "Timed out waiting for SCP response", 0); goto scp_recv_error; } session->scpRecv_response_len++; if (session->scpRecv_response[0] != 'T') { /* * Set this as the default error for here, if * we are successful it will be replaced */ libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, "Invalid data in SCP response, missing Time data", 0); session->scpRecv_err_len = libssh2_channel_packet_data_len(session-> scpRecv_channel, 0); session->scpRecv_err_msg = LIBSSH2_ALLOC(session, session->scpRecv_err_len + 1); if (!session->scpRecv_err_msg) { goto scp_recv_error; } memset(session->scpRecv_err_msg, 0, session->scpRecv_err_len + 1); /* Read the remote error message */ rc = libssh2_channel_read_ex(session->scpRecv_channel, 0, session->scpRecv_err_msg, session->scpRecv_err_len); if (rc <= 0) { /* * Since we have alread started reading this packet, it is * already in the systems so it can't return PACKET_EAGAIN */ LIBSSH2_FREE(session, session->scpRecv_err_msg); session->scpRecv_err_msg = NULL; libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, "Unknown error while getting error string", 0); goto scp_recv_error; } libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, session->scpRecv_err_msg, 1); session->scpRecv_err_msg = NULL; goto scp_recv_error; } if ((session->scpRecv_response_len > 1) && ((session-> scpRecv_response[session->scpRecv_response_len - 1] < '0') || (session-> scpRecv_response[session->scpRecv_response_len - 1] > '9')) && (session-> scpRecv_response[session->scpRecv_response_len - 1] != ' ') && (session-> scpRecv_response[session->scpRecv_response_len - 1] != '\r') && (session-> scpRecv_response[session->scpRecv_response_len - 1] != '\n')) { libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, "Invalid data in SCP response", 0); goto scp_recv_error; } if ((session->scpRecv_response_len < 9) || (session-> scpRecv_response[session->scpRecv_response_len - 1] != '\n')) { if (session->scpRecv_response_len == LIBSSH2_SCP_RESPONSE_BUFLEN) { /* You had your chance */ libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, "Unterminated response from SCP server", 0); goto scp_recv_error; } /* Way too short to be an SCP response, or not done yet, short circuit */ continue; } /* We're guaranteed not to go under response_len == 0 by the logic above */ while ((session-> scpRecv_response[session->scpRecv_response_len - 1] == '\r') || (session-> scpRecv_response[session->scpRecv_response_len - 1] == '\n')) session->scpRecv_response_len--; session->scpRecv_response[session->scpRecv_response_len] = '\0'; if (session->scpRecv_response_len < 8) { /* EOL came too soon */ libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, "Invalid response from SCP server, too short", 0); goto scp_recv_error; } s = session->scpRecv_response + 1; p = (unsigned char *) strchr((char *) s, ' '); if (!p || ((p - s) <= 0)) { /* No spaces or space in the wrong spot */ libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, "Invalid response from SCP server, malformed mtime", 0); goto scp_recv_error; } *(p++) = '\0'; /* Make sure we don't get fooled by leftover values */ errno = 0; session->scpRecv_mtime = strtol((char *) s, NULL, 10); if (errno) { libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, "Invalid response from SCP server, invalid mtime", 0); goto scp_recv_error; } s = (unsigned char *) strchr((char *) p, ' '); if (!s || ((s - p) <= 0)) { /* No spaces or space in the wrong spot */ libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, "Invalid response from SCP server, malformed mtime.usec", 0); goto scp_recv_error; } /* Ignore mtime.usec */ s++; p = (unsigned char *) strchr((char *) s, ' '); if (!p || ((p - s) <= 0)) { /* No spaces or space in the wrong spot */ libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, "Invalid response from SCP server, too short or malformed", 0); goto scp_recv_error; } *(p++) = '\0'; /* Make sure we don't get fooled by leftover values */ errno = 0; session->scpRecv_atime = strtol((char *) s, NULL, 10); if (errno) { libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, "Invalid response from SCP server, invalid atime", 0); goto scp_recv_error; } /* SCP ACK */ session->scpRecv_response[0] = '\0'; session->scpRecv_state = libssh2_NB_state_sent3; } if (session->scpRecv_state == libssh2_NB_state_sent3) { rc = libssh2_channel_write_ex(session->scpRecv_channel, 0, (char *) session-> scpRecv_response, 1); if (rc == PACKET_EAGAIN) { libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block waiting to send SCP ACK", 0); return NULL; } else if (rc != 1) { goto scp_recv_error; } _libssh2_debug(session, LIBSSH2_DBG_SCP, "mtime = %ld, atime = %ld", session->scpRecv_mtime, session->scpRecv_atime); /* We *should* check that atime.usec is valid, but why let that stop use? */ break; } } session->scpRecv_state = libssh2_NB_state_sent4; } if (session->scpRecv_state == libssh2_NB_state_sent4) { session->scpRecv_response_len = 0; session->scpRecv_state = libssh2_NB_state_sent5; } if ((session->scpRecv_state == libssh2_NB_state_sent5) || (session->scpRecv_state == libssh2_NB_state_sent6)) { while (session->scpRecv_response_len < LIBSSH2_SCP_RESPONSE_BUFLEN) { char *s, *p, *e = NULL; if (session->scpRecv_state == libssh2_NB_state_sent5) { rc = libssh2_channel_read_ex(session->scpRecv_channel, 0, (char *) session-> scpRecv_response + session->scpRecv_response_len, 1); if (rc == PACKET_EAGAIN) { libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block waiting for SCP response", 0); return NULL; } else if (rc <= 0) { /* Timeout, give up */ libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, "Timed out waiting for SCP response", 0); goto scp_recv_error; } session->scpRecv_response_len++; if (session->scpRecv_response[0] != 'C') { libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, "Invalid response from SCP server", 0); goto scp_recv_error; } if ((session->scpRecv_response_len > 1) && (session-> scpRecv_response[session->scpRecv_response_len - 1] != '\r') && (session-> scpRecv_response[session->scpRecv_response_len - 1] != '\n') && ((session-> scpRecv_response[session->scpRecv_response_len - 1] < 32) || (session-> scpRecv_response[session->scpRecv_response_len - 1] > 126))) { libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, "Invalid data in SCP response", 0); goto scp_recv_error; } if ((session->scpRecv_response_len < 7) || (session-> scpRecv_response[session->scpRecv_response_len - 1] != '\n')) { if (session->scpRecv_response_len == LIBSSH2_SCP_RESPONSE_BUFLEN) { /* You had your chance */ libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, "Unterminated response from SCP server", 0); goto scp_recv_error; } /* Way too short to be an SCP response, or not done yet, short circuit */ continue; } /* We're guaranteed not to go under response_len == 0 by the logic above */ while ((session-> scpRecv_response[session->scpRecv_response_len - 1] == '\r') || (session-> scpRecv_response[session->scpRecv_response_len - 1] == '\n')) { session->scpRecv_response_len--; } session->scpRecv_response[session->scpRecv_response_len] = '\0'; if (session->scpRecv_response_len < 6) { /* EOL came too soon */ libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, "Invalid response from SCP server, too short", 0); goto scp_recv_error; } s = (char *) session->scpRecv_response + 1; p = strchr(s, ' '); if (!p || ((p - s) <= 0)) { /* No spaces or space in the wrong spot */ libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, "Invalid response from SCP server, malformed mode", 0); goto scp_recv_error; } *(p++) = '\0'; /* Make sure we don't get fooled by leftover values */ errno = 0; session->scpRecv_mode = strtol(s, &e, 8); if ((e && *e) || errno) { libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, "Invalid response from SCP server, invalid mode", 0); goto scp_recv_error; } s = strchr(p, ' '); if (!s || ((s - p) <= 0)) { /* No spaces or space in the wrong spot */ libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, "Invalid response from SCP server, too short or malformed", 0); goto scp_recv_error; } *(s++) = '\0'; /* Make sure we don't get fooled by leftover values */ errno = 0; session->scpRecv_size = scpsize_strtol(p, &e, 10); if ((e && *e) || errno) { libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, "Invalid response from SCP server, invalid size", 0); goto scp_recv_error; } /* SCP ACK */ session->scpRecv_response[0] = '\0'; session->scpRecv_state = libssh2_NB_state_sent6; } if (session->scpRecv_state == libssh2_NB_state_sent6) { rc = libssh2_channel_write_ex(session->scpRecv_channel, 0, (char *) session-> scpRecv_response, 1); if (rc == PACKET_EAGAIN) { libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block sending SCP ACK", 0); return NULL; } else if (rc != 1) { goto scp_recv_error; } _libssh2_debug(session, LIBSSH2_DBG_SCP, "mode = 0%lo size = %ld", session->scpRecv_mode, session->scpRecv_size); /* We *should* check that basename is valid, but why let that stop us? */ break; } } session->scpRecv_state = libssh2_NB_state_sent7; } if (sb) { memset(sb, 0, sizeof(struct stat)); sb->st_mtime = session->scpRecv_mtime; sb->st_atime = session->scpRecv_atime; sb->st_size = session->scpRecv_size; sb->st_mode = session->scpRecv_mode; } session->scpRecv_state = libssh2_NB_state_idle; return session->scpRecv_channel; scp_recv_error: while (libssh2_channel_free(session->scpRecv_channel) == PACKET_EAGAIN); session->scpRecv_channel = NULL; session->scpRecv_state = libssh2_NB_state_idle; return NULL; }