/* * Callback for when data is available on the standard output handle of * a process channel that is interactive mode */ DWORD process_channel_interact_notify(Remote *remote, Channel *channel) { ProcessChannelContext *ctx = (ProcessChannelContext *)channel->ops.stream.native.context; DWORD bytesRead, bytesAvail = 0; CHAR buffer[16384]; DWORD result = ERROR_SUCCESS; #ifdef _WIN32 if( PeekNamedPipe( ctx->pStdout, NULL, 0, NULL, &bytesAvail, NULL ) ) { if( bytesAvail ) { if( ReadFile( ctx->pStdout, buffer, sizeof(buffer) - 1, &bytesRead, NULL ) ) { return channel_write( channel, remote, NULL, 0, buffer, bytesRead, NULL ); } } else { // sf: if no data is available on the pipe we sleep to avoid running a tight loop // in this thread, as anonymous pipes won't block for data to arrive. Sleep( 100 ); } } #else bytesRead = read ( ctx->pStdout, buffer, sizeof(buffer) - 1); if ( bytesRead > 0 ) { dprintf("bytesRead: %d, errno: %d", bytesRead, errno); result = channel_write ( channel, remote, NULL, 0, buffer, bytesRead, NULL ); } if(bytesRead == -1) { if(errno == EINTR || errno == EWOULDBLOCK || errno == EAGAIN) { errno = ERROR_SUCCESS; } } if(bytesRead == 0) { errno = ECONNRESET; } if(bytesRead <= 0) result = errno; #endif if( GetLastError() != ERROR_SUCCESS ) { dprintf("Closing down socket: errno: %d\n", errno); process_channel_close( channel, NULL, ctx ); channel_close( channel, remote, NULL, 0, NULL ); } return result; }
static void remmina_nx_session_send_command(RemminaNXSession *nx, const gchar *cmdfmt, ...) { va_list args; gchar *cmd; va_start (args, cmdfmt); cmd = g_strdup_vprintf (cmdfmt, args); channel_write (nx->channel, cmd, strlen (cmd)); g_free(cmd); ssh_set_fd_towrite (nx->session); channel_write (nx->channel, "\n", 1); }
/** @brief creates a directory in a scp in sink mode * @param scp the scp handle. * @param dirname Name of the directory being created. * @param mode Unix permissions for the new directory, e.g. 0755. * @returns SSH_OK if the directory was created. * @returns SSH_ERROR if an error happened. * @see ssh_scp_leave_directory */ int ssh_scp_push_directory(ssh_scp scp, const char *dirname, int mode){ char buffer[1024]; int r; uint8_t code; char *dir; char *perms; if(scp->state != SSH_SCP_WRITE_INITED){ ssh_set_error(scp->session,SSH_FATAL,"ssh_scp_push_directory called under invalid state"); return SSH_ERROR; } dir=ssh_basename(dirname); perms=ssh_scp_string_mode(mode); snprintf(buffer, sizeof(buffer), "D%s 0 %s\n", perms, dir); SAFE_FREE(dir); SAFE_FREE(perms); r=channel_write(scp->channel,buffer,strlen(buffer)); if(r==SSH_ERROR){ scp->state=SSH_SCP_ERROR; return SSH_ERROR; } r=channel_read(scp->channel,&code,1,0); if(code != 0){ ssh_set_error(scp->session,SSH_FATAL, "scp status code %ud not valid", code); scp->state=SSH_SCP_ERROR; return SSH_ERROR; } return SSH_OK; }
/** @brief initializes the sending of a file to a scp in sink mode * @param scp the scp handle. * @param filename Name of the file being sent. It should not contain any path indicator * @param size Exact size in bytes of the file being sent. * @param mode Unix permissions for the new file, e.g. 0644 * @returns SSH_OK if the file is ready to be sent. * @returns SSH_ERROR if an error happened. */ int ssh_scp_push_file(ssh_scp scp, const char *filename, size_t size, int mode){ char buffer[1024]; int r; uint8_t code; char *file; char *perms; if(scp->state != SSH_SCP_WRITE_INITED){ ssh_set_error(scp->session,SSH_FATAL,"ssh_scp_push_file called under invalid state"); return SSH_ERROR; } file=ssh_basename(filename); perms=ssh_scp_string_mode(mode); ssh_log(scp->session,SSH_LOG_PROTOCOL,"SCP pushing file %s, size %" PRIdS " with permissions '%s'",file,size,perms); snprintf(buffer, sizeof(buffer), "C%s %" PRIdS " %s\n", perms, size, file); SAFE_FREE(file); SAFE_FREE(perms); r=channel_write(scp->channel,buffer,strlen(buffer)); if(r==SSH_ERROR){ scp->state=SSH_SCP_ERROR; return SSH_ERROR; } r=channel_read(scp->channel,&code,1,0); if(code != 0){ ssh_set_error(scp->session,SSH_FATAL, "scp status code %ud not valid", code); scp->state=SSH_SCP_ERROR; return SSH_ERROR; } scp->filelen = size; scp->processed = 0; scp->state=SSH_SCP_WRITE_WRITING; return SSH_OK; }
static gboolean forward_data(GIOChannel *chan, GIOCondition cond, gpointer data) { char buf[BUF_SIZE]; struct serial_proxy *prx = data; GIOChannel *dest; GIOError err; size_t rbytes; if (cond & G_IO_NVAL) return FALSE; dest = (chan == prx->rfcomm) ? prx->local : prx->rfcomm; if (cond & (G_IO_HUP | G_IO_ERR)) { /* Try forward remaining data */ do { rbytes = 0; err = g_io_channel_read(chan, buf, sizeof(buf), &rbytes); if (err != G_IO_ERROR_NONE || rbytes == 0) break; err = channel_write(dest, buf, rbytes); } while (err == G_IO_ERROR_NONE); g_io_channel_shutdown(prx->local, TRUE, NULL); g_io_channel_unref(prx->local); prx->local = NULL; g_io_channel_shutdown(prx->rfcomm, TRUE, NULL); g_io_channel_unref(prx->rfcomm); prx->rfcomm = NULL; return FALSE; } rbytes = 0; err = g_io_channel_read(chan, buf, sizeof(buf), &rbytes); if (err != G_IO_ERROR_NONE) return FALSE; err = channel_write(dest, buf, rbytes); if (err != G_IO_ERROR_NONE) return FALSE; return TRUE; }
int terminal_write(const uchar_t *buf, size_t len) { #ifdef ENABLE_SSH return channel_write(ssh_chan, buf, len); #else // ENABLE_SSH return file_write(STDIN_FILENO, buf, len); #endif // ENABLE_SSH }
static int ping(time_t *now) { time(now); if (!last_ping || (last_ping + RDP2TCP_PING_DELAY - 1 < *now)) { last_ping = *now; return channel_write(R2TCMD_PING, 0, NULL, 0); } return 0; }
int SSHClient::sshWrite(const std::uint8_t *buf, size_t size) { GNASH_REPORT_FUNCTION; int ret = channel_write(_channel, buf, size); if (ret < 0) { log_error(_("SSH write error was: \"%s\"!"), ssh_get_error(_session)); } return ret; }
void *thr_fn(void *id) { int i; for (i = (uintptr_t) id; i < COUNT; i += THREADS_N) { if (channel_write(chan, (char *) &i, sizeof(i)) == -1) { perror("channel_write() failed"); return NULL; } } return NULL; }
int sdb_channel_write(sdb_channel_t *chan, const void *data) { int status; if ((! chan) || (! data)) return -1; pthread_mutex_lock(&chan->lock); status = channel_write(chan, data); pthread_mutex_unlock(&chan->lock); return status; } /* sdb_channel_write */
int SSHClient::writeChannel(ssh_channel channel, cygnal::Buffer &buf) { // GNASH_REPORT_FUNCTION; int ret = -1; if (channel) { ret = channel_write(channel, buf.reference(), buf.size()); } else { log_error(_("Can't write to a non-existent channel!")); } return ret; }
int ssh_scp_init(ssh_scp scp){ int r; char execbuffer[1024]; uint8_t code; if(scp->state != SSH_SCP_NEW){ ssh_set_error(scp->session,SSH_FATAL,"ssh_scp_init called under invalid state"); return SSH_ERROR; } ssh_log(scp->session,SSH_LOG_PROTOCOL,"Initializing scp session %s %son location '%s'", scp->mode==SSH_SCP_WRITE?"write":"read", scp->recursive?"recursive ":"", scp->location); scp->channel=channel_new(scp->session); if(scp->channel == NULL){ scp->state=SSH_SCP_ERROR; return SSH_ERROR; } r= channel_open_session(scp->channel); if(r==SSH_ERROR){ scp->state=SSH_SCP_ERROR; return SSH_ERROR; } if(scp->mode == SSH_SCP_WRITE) snprintf(execbuffer,sizeof(execbuffer),"scp -t %s %s", scp->recursive ? "-r":"", scp->location); else snprintf(execbuffer,sizeof(execbuffer),"scp -f %s %s", scp->recursive ? "-r":"", scp->location); if(channel_request_exec(scp->channel,execbuffer) == SSH_ERROR){ scp->state=SSH_SCP_ERROR; return SSH_ERROR; } if(scp->mode == SSH_SCP_WRITE){ r=channel_read(scp->channel,&code,1,0); if(code != 0){ ssh_set_error(scp->session,SSH_FATAL, "scp status code %ud not valid", code); scp->state=SSH_SCP_ERROR; return SSH_ERROR; } } else { channel_write(scp->channel,"",1); } if(scp->mode == SSH_SCP_WRITE) scp->state=SSH_SCP_WRITE_INITED; else scp->state=SSH_SCP_READ_INITED; return SSH_OK; }
/** * @brief denies the transfer of a file or creation of a directory * coming from the remote party * @param scp the scp handle. * @param reason nul-terminated string with a human-readable explanation * of the deny * @returns SSH_OK the message was sent * @returns SSH_ERROR Error sending the message, or sending it in a bad state */ int ssh_scp_deny_request(ssh_scp scp, const char *reason){ char buffer[4096]; int err; if(scp->state != SSH_SCP_READ_REQUESTED){ ssh_set_error(scp->session,SSH_FATAL,"ssh_scp_deny_request called under invalid state"); return SSH_ERROR; } snprintf(buffer,sizeof(buffer),"%c%s\n",2,reason); err=channel_write(scp->channel,buffer,strlen(buffer)); if(err==SSH_ERROR) { return SSH_ERROR; } else { scp->state=SSH_SCP_READ_INITED; return SSH_OK; } }
/** * @brief accepts transfer of a file or creation of a directory * coming from the remote party * @param scp the scp handle. * @returns SSH_OK the message was sent * @returns SSH_ERROR Error sending the message, or sending it in a bad state */ int ssh_scp_accept_request(ssh_scp scp){ char buffer[]={0x00}; int err; if(scp->state != SSH_SCP_READ_REQUESTED){ ssh_set_error(scp->session,SSH_FATAL,"ssh_scp_deny_request called under invalid state"); return SSH_ERROR; } err=channel_write(scp->channel,buffer,1); if(err==SSH_ERROR) { return SSH_ERROR; } if(scp->request_type==SSH_SCP_REQUEST_NEWFILE) scp->state=SSH_SCP_READ_READING; else scp->state=SSH_SCP_READ_INITED; return SSH_OK; }
/* * Callback for when data is available on the standard output handle of * a process channel that is interactive mode */ DWORD process_channel_interact_notify(Remote *remote, LPVOID entryContext, LPVOID threadContext) { Channel *channel = (Channel*)entryContext; ProcessChannelContext *ctx = (ProcessChannelContext *)threadContext; DWORD bytesRead, bytesAvail = 0; CHAR buffer[16384]; DWORD result = ERROR_SUCCESS; if (!channel_exists(channel) || ctx == NULL) { return result; } if( PeekNamedPipe( ctx->pStdout, NULL, 0, NULL, &bytesAvail, NULL ) ) { if( bytesAvail ) { if( ReadFile( ctx->pStdout, buffer, sizeof(buffer) - 1, &bytesRead, NULL ) ) { return channel_write( channel, remote, NULL, 0, buffer, bytesRead, NULL ); } result = GetLastError(); } else { // sf: if no data is available on the pipe we sleep to avoid running a tight loop // in this thread, as anonymous pipes won't block for data to arrive. Sleep( 100 ); } } else { result = GetLastError(); } if( result != ERROR_SUCCESS ) { dprintf("Closing down socket: result: %d\n", result); process_channel_close( channel, NULL, ctx ); channel_close( channel, remote, NULL, 0, NULL ); } return result; }
/* * Notification handler for when a client connection has data */ DWORD portfwd_local_client_notify(Remote *remote, PortForwardClientContext *pcctx) { UCHAR buf[8192]; LONG bytesRead; // Reset the notification event ResetEvent(pcctx->notify); // Read data from the client connection if (((bytesRead = recv(pcctx->clientFd, buf, sizeof(buf), 0)) == SOCKET_ERROR) || (bytesRead == 0)) channel_close(pcctx->channel, pcctx->remote, NULL, 0, NULL); //portfwd_destroy_client(pcctx); else if (pcctx->channel) channel_write(pcctx->channel, pcctx->remote, NULL, 0, buf, bytesRead, 0); return ERROR_SUCCESS; }
/** @brief Read from a remote scp file * @param scp the scp handle. * @param buffer Destination buffer * @param size Size of the buffer * @returns Number of bytes read * @returns SSH_ERROR An error happened while reading */ int ssh_scp_read(ssh_scp scp, void *buffer, size_t size){ int r; int code; if(scp->state == SSH_SCP_READ_REQUESTED && scp->request_type == SSH_SCP_REQUEST_NEWFILE){ r=ssh_scp_accept_request(scp); if(r==SSH_ERROR) return r; } if(scp->state != SSH_SCP_READ_READING){ ssh_set_error(scp->session,SSH_FATAL,"ssh_scp_read called under invalid state"); return SSH_ERROR; } if(scp->processed + size > scp->filelen) size = scp->filelen - scp->processed; if(size > 65536) size=65536; /* avoid too large reads */ r=channel_read(scp->channel,buffer,size,0); if(r != SSH_ERROR) scp->processed += r; else { scp->state=SSH_SCP_ERROR; return SSH_ERROR; } /* Check if we arrived at end of file */ if(scp->processed == scp->filelen) { scp->processed=scp->filelen=0; channel_write(scp->channel,"",1); code=ssh_scp_response(scp,NULL); if(code == 0){ scp->state=SSH_SCP_READ_INITED; return r; } if(code==1){ scp->state=SSH_SCP_READ_INITED; return SSH_ERROR; } scp->state=SSH_SCP_ERROR; return SSH_ERROR; } return r; }
/** * @brief Leaves a directory * @returns SSH_OK if the directory was created. * @returns SSH_ERROR if an error happened. * @see ssh_scp_push_directory */ int ssh_scp_leave_directory(ssh_scp scp){ char buffer[]="E\n"; int r; uint8_t code; if(scp->state != SSH_SCP_WRITE_INITED){ ssh_set_error(scp->session,SSH_FATAL,"ssh_scp_leave_directory called under invalid state"); return SSH_ERROR; } r=channel_write(scp->channel,buffer,strlen(buffer)); if(r==SSH_ERROR){ scp->state=SSH_SCP_ERROR; return SSH_ERROR; } r=channel_read(scp->channel,&code,1,0); if(code != 0){ ssh_set_error(scp->session,SSH_FATAL, "scp status code %ud not valid", code); scp->state=SSH_SCP_ERROR; return SSH_ERROR; } return SSH_OK; }
/* * Callback for when there is data available on the local side of the TCP * client connection */ static DWORD tcp_channel_client_local_notify(Remote *remote, TcpClientContext *ctx) { struct timeval tv; fd_set set; UCHAR buf[16384]; LONG bytesRead; // Reset the notification event ResetEvent(ctx->notify); tv.tv_sec = 0; tv.tv_usec = 0; // We select in a loop with a zero second timeout because it's possible // that we could get a recv notification and a close notification at once, // so we need some way to make sure that we see them both, otherwise the // event handle wont get re set to notify us. do { FD_ZERO(&set); FD_SET(ctx->fd, &set); // Read data from the client connection if (((bytesRead = recv(ctx->fd, buf, sizeof(buf), 0)) == SOCKET_ERROR) || (bytesRead == 0)) { channel_close(ctx->channel, ctx->remote, NULL, 0, NULL); break; } else if (ctx->channel) channel_write(ctx->channel, ctx->remote, NULL, 0, buf, bytesRead, 0); } while (select(0, &set, NULL, NULL, &tv) > 0); return ERROR_SUCCESS; }
/** @brief Write into a remote scp file * @param scp the scp handle. * @param buffer the buffer to write * @param len the number of bytes to write * @returns SSH_OK the write was successful * @returns SSH_ERROR an error happened while writing */ int ssh_scp_write(ssh_scp scp, const void *buffer, size_t len){ int w; //int r; //uint8_t code; if(scp->state != SSH_SCP_WRITE_WRITING){ ssh_set_error(scp->session,SSH_FATAL,"ssh_scp_write called under invalid state"); return SSH_ERROR; } if(scp->processed + len > scp->filelen) len = scp->filelen - scp->processed; /* hack to avoid waiting for window change */ channel_poll(scp->channel,0); w=channel_write(scp->channel,buffer,len); if(w != SSH_ERROR) scp->processed += w; else { scp->state=SSH_SCP_ERROR; //return=channel_get_exit_status(scp->channel); return SSH_ERROR; } /* Check if we arrived at end of file */ if(scp->processed == scp->filelen) { /* r=channel_read(scp->channel,&code,1,0); if(r==SSH_ERROR){ scp->state=SSH_SCP_ERROR; return SSH_ERROR; } if(code != 0){ ssh_set_error(scp->session,SSH_FATAL, "scp status code %ud not valid", code); scp->state=SSH_SCP_ERROR; return SSH_ERROR; } */ scp->processed=scp->filelen=0; scp->state=SSH_SCP_WRITE_INITED; } return SSH_OK; }
int process_cgi_data(struct cgi_request *r) { int ret; int len; int status; char *buf = r->in_buf; char *outptr = r->in_buf; char *end; char *endl; unsigned char advance; mk_api->socket_cork_flag(r->cs->socket, TCP_CORK_OFF); if (!r->status_done && r->in_len >= 8) { if (memcmp(buf, "Status: ", 8) == 0) { status = atoi(buf + 8); mk_api->header_set_http_status(r->sr, status); endl = memchr(buf + 8, '\n', r->in_len - 8); if (!endl) { return MK_PLUGIN_RET_EVENT_OWNED; } else { endl++; outptr = endl; r->in_len -= endl - buf; } } else if (memcmp(buf, "HTTP", 4) == 0) { status = atoi(buf + 9); mk_api->header_set_http_status(r->sr, status); endl = memchr(buf + 8, '\n', r->in_len - 8); if (!endl) { return MK_PLUGIN_RET_EVENT_OWNED; } else { endl++; outptr = endl; r->in_len -= endl - buf; } } mk_api->header_prepare(r->plugin, r->cs, r->sr); r->status_done = 1; } if (!r->all_headers_done) { advance = 4; /* Write the rest of the headers without chunking */ end = getearliestbreak(outptr, r->in_len, &advance); if (!end) { /* Let's return until we have the headers break */ return MK_PLUGIN_RET_EVENT_OWNED; } end += advance; len = end - outptr; channel_write(r, outptr, len); outptr += len; r->in_len -= len; r->all_headers_done = 1; if (r->in_len == 0) { return MK_PLUGIN_RET_EVENT_OWNED; } } if (r->chunked) { char tmp[16]; len = snprintf(tmp, 16, "%x\r\n", r->in_len); ret = channel_write(r, tmp, len); if (ret < 0) return MK_PLUGIN_RET_EVENT_CLOSE; } ret = channel_write(r, outptr, r->in_len); if (ret < 0) { return MK_PLUGIN_RET_EVENT_CLOSE; } r->in_len = 0; if (r->chunked) { channel_write(r, MK_CRLF, 2); } return MK_PLUGIN_RET_EVENT_OWNED; }
/* * Callback for when there is data available on the local side of the TCP client connection */ DWORD tcp_channel_client_local_notify( Remote * remote, TcpClientContext * ctx ) { struct timeval tv = {0}; fd_set set = {0}; UCHAR buf[16384] = {0}; LONG dwBytesRead = 0; // We select in a loop with a zero second timeout because it's possible // that we could get a recv notification and a close notification at once, // so we need some way to make sure that we see them both, otherwise the // event handle wont get re set to notify us. do { // Reset the notification event ResetEvent( ctx->notify ); FD_ZERO( &set ); FD_SET( ctx->fd, &set ); tv.tv_sec = 0; tv.tv_usec = 0; // Read data from the client connection dwBytesRead = recv( ctx->fd, buf, sizeof(buf), 0 ); if( dwBytesRead == SOCKET_ERROR ) { DWORD dwError = WSAGetLastError(); // WSAECONNRESET: The connection was forcibly closed by the remote host. // WSAECONNABORTED: The connection was terminated due to a time-out or other failure. if( dwError == WSAECONNRESET || dwError == WSAECONNABORTED ) { dprintf( "[TCP] tcp_channel_client_local_notify. [error] closing down channel gracefully. WSAGetLastError=%d", dwError ); // By setting bytesRead to zero, we can ensure we close down the channel gracefully... dwBytesRead = 0; } else if( dwError == WSAEWOULDBLOCK ) { dprintf( "[TCP] tcp_channel_client_local_notify. channel=0x%08X. recv generated a WSAEWOULDBLOCK", ctx->channel ); // break and let the scheduler notify us again if needed. break; } else { dprintf( "[TCP] tcp_channel_client_local_notify. [error] channel=0x%08X read=0x%.8x (ignored). WSAGetLastError=%d", ctx->channel, dwBytesRead, dwError ); // we loop again because bytesRead is -1. } } if( dwBytesRead == 0 ) { dprintf( "[TCP] tcp_channel_client_local_notify. [closed] channel=0x%08X read=0x%.8x", ctx->channel, dwBytesRead ); // Set the native channel operations context to NULL channel_set_native_io_context( ctx->channel, NULL ); // Sleep for a quarter second Sleep( 250 ); // Free the context free_tcp_client_context( ctx ); // Stop processing break; } else if( dwBytesRead > 0 ) { if( ctx->channel ) { dprintf( "[TCP] tcp_channel_client_local_notify. [data] channel=0x%08X read=%d", ctx->channel, dwBytesRead ); channel_write( ctx->channel, ctx->remote, NULL, 0, buf, dwBytesRead, 0 ); } else { dprintf( "[TCP] tcp_channel_client_local_notify. [data] channel=<invalid> read=0x%.8x", dwBytesRead ); } } } while( select( 1, &set, NULL, NULL, &tv ) > 0 ); return ERROR_SUCCESS; }
int main(int argc, char **argv) { char *x; const char *keydir = 0; long long i; struct pollfd p[6]; struct pollfd *q; struct pollfd *watch0; struct pollfd *watch1; struct pollfd *watchtochild; struct pollfd *watchfromchild1; struct pollfd *watchfromchild2; struct pollfd *watchselfpipe; int exitsignal, exitcode; signal(SIGPIPE, SIG_IGN); signal(SIGALRM, timeout); log_init(0, "tinysshd", 0, 0); if (argc < 2) die_usage(USAGE); if (!argv[0]) die_usage(USAGE); for (;;) { if (!argv[1]) break; if (argv[1][0] != '-') break; x = *++argv; if (x[0] == '-' && x[1] == 0) break; if (x[0] == '-' && x[1] == '-' && x[2] == 0) break; while (*++x) { if (*x == 'q') { flagverbose = 0; continue; } if (*x == 'Q') { flagverbose = 1; continue; } if (*x == 'v') { if (flagverbose >= 2) flagverbose = 3; else flagverbose = 2; continue; } if (*x == 'o') { cryptotypeselected |= sshcrypto_TYPEOLDCRYPTO; continue; } if (*x == 'O') { cryptotypeselected &= ~sshcrypto_TYPEOLDCRYPTO; continue; } if (*x == 's') { cryptotypeselected |= sshcrypto_TYPENEWCRYPTO; continue; } if (*x == 'S') { cryptotypeselected &= ~sshcrypto_TYPENEWCRYPTO; continue; } if (*x == 'p') { cryptotypeselected |= sshcrypto_TYPEPQCRYPTO; continue; } if (*x == 'P') { cryptotypeselected &= ~sshcrypto_TYPEPQCRYPTO; continue; } if (*x == 'l') { flaglogger = 1; continue; } if (*x == 'L') { flaglogger = 0; continue; } if (*x == 'x') { if (x[1]) { channel_subsystem_add(x + 1); break; } if (argv[1]) { channel_subsystem_add(*++argv); break; } } die_usage(USAGE); } } keydir = *++argv; if (!keydir) die_usage(USAGE); log_init(flagverbose, "tinysshd", 1, flaglogger); connectioninfo(channel.localip, channel.localport, channel.remoteip, channel.remoteport); log_i4("connection from ", channel.remoteip, ":", channel.remoteport); channel_subsystem_log(); global_init(); blocking_disable(0); blocking_disable(1); blocking_disable(2); /* get server longterm keys */ fdwd = open_cwd(); if (fdwd == -1) die_fatal("unable to open current directory", 0, 0); if (chdir(keydir) == -1) die_fatal("unable to chdir to", keydir, 0); for (i = 0; sshcrypto_keys[i].name; ++i) sshcrypto_keys[i].sign_flagserver |= sshcrypto_kexs[i].cryptotype & cryptotypeselected; for (i = 0; sshcrypto_keys[i].name; ++i) sshcrypto_keys[i].sign_flagclient |= sshcrypto_kexs[i].cryptotype & cryptotypeselected; for (i = 0; sshcrypto_kexs[i].name; ++i) sshcrypto_kexs[i].flagenabled |= sshcrypto_kexs[i].cryptotype & cryptotypeselected; for (i = 0; sshcrypto_ciphers[i].name; ++i) sshcrypto_ciphers[i].flagenabled |= sshcrypto_ciphers[i].cryptotype & cryptotypeselected; /* read public keys */ for (i = 0; sshcrypto_keys[i].name; ++i) { if (!sshcrypto_keys[i].sign_flagserver) continue; if (load(sshcrypto_keys[i].sign_publickeyfilename, sshcrypto_keys[i].sign_publickey, sshcrypto_keys[i].sign_publickeybytes) == -1) { sshcrypto_keys[i].sign_flagserver = 0; if (errno == ENOENT) continue; die_fatal("unable to read public key from file", keydir, sshcrypto_keys[i].sign_publickeyfilename); } } if (fchdir(fdwd) == -1) die_fatal("unable to change directory to working directory", 0, 0); close(fdwd); /* set timeout */ alarm(60); /* send and receive hello */ if (!packet_hello_send()) die_fatal("unable to send hello-string", 0, 0); if (!packet_hello_receive()) die_fatal("unable to receive hello-string", 0, 0); /* send and receive kex */ if (!packet_kex_send()) die_fatal("unable to send kex-message", 0, 0); if (!packet_kex_receive()) die_fatal("unable to receive kex-message", 0, 0); rekeying: /* rekeying */ alarm(60); if (packet.flagrekeying == 1) { buf_purge(&packet.kexrecv); buf_put(&packet.kexrecv, b1.buf, b1.len); if (!packet_kex_send()) die_fatal("unable to send kex-message", 0, 0); } /* send and receive kexdh */ if (!packet_kexdh(keydir, &b1, &b2)) die_fatal("unable to subprocess kexdh", 0, 0); if (packet.flagkeys) log_d1("rekeying: done"); packet.flagkeys = 1; /* note: comunication is encrypted */ /* authentication + authorization */ if (packet.flagauthorized == 0) { if (!packet_auth(&b1, &b2)) die_fatal("authentication failed", 0, 0); packet.flagauthorized = 1; } /* note: user is authenticated and authorized */ alarm(3600); /* main loop */ for (;;) { if (channel_iseof()) if (!packet.sendbuf.len) if (packet.flagchanneleofreceived) break; watch0 = watch1 = 0; watchtochild = watchfromchild1 = watchfromchild2 = 0; watchselfpipe = 0; q = p; if (packet_sendisready()) { watch1 = q; q->fd = 1; q->events = POLLOUT; ++q; } if (packet_recvisready()) { watch0 = q; q->fd = 0; q->events = POLLIN; ++q; } if (channel_writeisready()) { watchtochild = q; q->fd = channel_getfd0(); q->events = POLLOUT; ++q; } if (channel_readisready() && packet_putisready()) { watchfromchild1 = q; q->fd = channel_getfd1(); q->events = POLLIN; ++q; } if (channel_extendedreadisready() && packet_putisready()) { watchfromchild2 = q; q->fd = channel_getfd2(); q->events = POLLIN; ++q; } if (selfpipe[0] != -1) { watchselfpipe = q; q->fd = selfpipe[0]; q->events = POLLIN; ++q; } if (poll(p, q - p, 60000) < 0) { watch0 = watch1 = 0; watchtochild = watchfromchild1 = watchfromchild2 = 0; watchselfpipe = 0; } else { if (watch0) if (!watch0->revents) watch0 = 0; if (watch1) if (!watch1->revents) watch1 = 0; if (watchfromchild1) if (!watchfromchild1->revents) watchfromchild1 = 0; if (watchfromchild2) if (!watchfromchild2->revents) watchfromchild2 = 0; if (watchtochild) if (!watchtochild->revents) watchtochild = 0; if (watchselfpipe) if (!watchselfpipe->revents) watchselfpipe = 0; } if (watchtochild) { /* write data to child */ if (!channel_write()) die_fatal("unable to write data to child", 0, 0); /* try to adjust window */ if (!packet_channel_send_windowadjust(&b1)) die_fatal("unable to send data to network", 0, 0); } /* read data from child */ if (watchfromchild1) packet_channel_send_data(&b2); if (watchfromchild2) packet_channel_send_extendeddata(&b2); /* check child */ if (channel_iseof()) { if (selfpipe[0] == -1) if (open_pipe(selfpipe) == -1) die_fatal("unable to open pipe", 0, 0); signal(SIGCHLD, trigger); if (channel_waitnohang(&exitsignal, &exitcode)) { packet_channel_send_eof(&b2); if (!packet_channel_send_close(&b2, exitsignal, exitcode)) die_fatal("unable to close channel", 0, 0); } } /* send data to network */ if (watch1) if (!packet_send()) die_fatal("unable to send data to network", 0, 0); /* receive data from network */ if (watch0) { alarm(3600); /* refresh timeout */ if (!packet_recv()) { if (channel_iseof()) break; /* XXX */ die_fatal("unable to receive data from network", 0, 0); } } /* process packets */ for (;;) { if (!packet_get(&b1, 0)) { if (!errno) break; die_fatal("unable to get packets from network", 0, 0); } if (b1.len < 1) break; /* XXX */ switch (b1.buf[0]) { case SSH_MSG_CHANNEL_OPEN: if (!packet_channel_open(&b1, &b2)) die_fatal("unable to open channel", 0, 0); break; case SSH_MSG_CHANNEL_REQUEST: if (!packet_channel_request(&b1, &b2)) die_fatal("unable to handle channel-request", 0, 0); break; case SSH_MSG_CHANNEL_DATA: if (!packet_channel_recv_data(&b1)) die_fatal("unable to handle channel-data", 0, 0); break; case SSH_MSG_CHANNEL_EXTENDED_DATA: if (!packet_channel_recv_extendeddata(&b1)) die_fatal("unable to handle channel-extended-data", 0, 0); break; case SSH_MSG_CHANNEL_WINDOW_ADJUST: if (!packet_channel_recv_windowadjust(&b1)) die_fatal("unable to handle channel-window-adjust", 0, 0); break; case SSH_MSG_CHANNEL_EOF: if (!packet_channel_recv_eof(&b1)) die_fatal("unable to handle channel-eof", 0, 0); break; case SSH_MSG_CHANNEL_CLOSE: if (!packet_channel_recv_close(&b1)) die_fatal("unable to handle channel-close", 0, 0); break; case SSH_MSG_KEXINIT: goto rekeying; default: if (!packet_unimplemented(&b1)) die_fatal("unable to send SSH_MSG_UNIMPLEMENTED message", 0, 0); } } } log_i1("finished"); global_die(0); return 111; }
/* * Reads in data from the input device, potentially calling the * command processing function if a complete command has been read. */ VOID console_read_buffer(Remote *remote) { DWORD newInputBufferLength, stringLength, offset; Channel *interactiveChannel; PCHAR newInputBuffer; BOOL process = FALSE; CHAR buf[4096]; PCHAR eoln, eolr; LONG bytesRead; // Ensure null termination buf[sizeof(buf) - 1] = 0; do { // Is there data available? if (WaitForSingleObject(GetStdHandle(STD_INPUT_HANDLE), INFINITE) != WAIT_OBJECT_0) break; // If a console escape character was sent and we're currently interactive, // break out of interactive mode if ((console_check_escape_sent()) && (console_get_interactive_channel())) { console_set_interactive_channel(remote, NULL); console_write_output( "\n" "\n" "Exiting interactive mode..\n"); console_write_prompt(); } // Read the command if ((!ReadConsole(GetStdHandle(STD_INPUT_HANDLE), buf, sizeof(buf) - 1, &bytesRead, NULL)) || (bytesRead <= 0)) break; buf[bytesRead] = 0; // If an interactive channel is in use, write directly to it. if ((interactiveChannel = console_get_interactive_channel())) { channel_write(interactiveChannel, remote, NULL, 0, buf, bytesRead, NULL); break; } if ((eoln = strchr(buf, '\n'))) { *eoln = 0; process = TRUE; } // Remove end of line characters if ((eolr = strchr(buf, '\r'))) *eolr = 0; // Calculate lengths stringLength = strlen(buf); newInputBufferLength = inputBufferLength + stringLength; if (inputBuffer) newInputBuffer = (PCHAR)realloc(inputBuffer, newInputBufferLength); else newInputBuffer = (PCHAR)malloc(++newInputBufferLength); // Allocation failure? if (!newInputBuffer) break; if ((offset = inputBufferLength)) offset--; // Copy the string memcpy(newInputBuffer + offset, buf, stringLength); // Update the input buffer inputBuffer = newInputBuffer; inputBufferLength = newInputBufferLength; // Process the full command line if it's completed if (process) { inputBuffer[inputBufferLength - 1] = 0; client_acquire_lock(); console_process_command(remote); client_release_lock(); free(inputBuffer); inputBuffer = NULL; inputBufferLength = 0; console_write_prompt(); } } while (0); }
int sdb_channel_select(sdb_channel_t *chan, int *wantread, void *read_data, int *wantwrite, void *write_data, const struct timespec *timeout) { int status = 0; if (! chan) { errno = EINVAL; return -1; } if ((! wantread) && (! read_data) && (! wantwrite) && (! write_data)) { errno = EINVAL; return -1; } pthread_mutex_lock(&chan->lock); while (! status) { int read_status, write_status; read_status = channel_read(chan, read_data); write_status = channel_write(chan, write_data); if ((! read_status) || (! write_status)) { if (wantread) *wantread = read_status == 0; if (wantwrite) *wantwrite = write_status == 0; if (((wantread || read_data) && (! read_status)) || ((wantwrite || write_data) && (! write_status))) break; } if (chan->shutdown) { if (read_status) status = EBADF; break; } if (timeout) { struct timespec abstime; if (clock_gettime(CLOCK_REALTIME, &abstime)) { pthread_mutex_unlock(&chan->lock); return -1; } abstime.tv_sec += timeout->tv_sec; abstime.tv_nsec += timeout->tv_nsec; if (abstime.tv_nsec > 1000000000) { abstime.tv_nsec -= 1000000000; abstime.tv_sec += 1; } status = pthread_cond_timedwait(&chan->cond, &chan->lock, &abstime); } else status = pthread_cond_wait(&chan->cond, &chan->lock); } pthread_mutex_unlock(&chan->lock); if (status) { errno = status; return -1; } return 0; } /* sdb_channel_select */
static gpointer remmina_ssh_tunnel_main_thread_proc (gpointer data) { RemminaSSHTunnel *tunnel = (RemminaSSHTunnel*) data; gchar *ptr; ssize_t len = 0, lenw = 0; fd_set set; struct timeval timeout; GTimeVal t1, t2; glong diff; ssh_channel channel = NULL; gboolean first = TRUE; gboolean disconnected; gint sock; gint maxfd; gint i; gint ret; struct sockaddr_in sin; g_get_current_time (&t1); t2 = t1; switch (tunnel->tunnel_type) { case REMMINA_SSH_TUNNEL_OPEN: /* Accept a local connection */ sock = accept (tunnel->server_sock, NULL, NULL); if (sock < 0) { REMMINA_SSH (tunnel)->error = g_strdup ("Failed to accept local socket"); tunnel->thread = 0; return NULL; } if ((channel = channel_new (tunnel->ssh.session)) == NULL) { close (sock); remmina_ssh_set_error (REMMINA_SSH (tunnel), "Failed to createt channel : %s"); tunnel->thread = 0; return NULL; } /* Request the SSH server to connect to the destination */ if (channel_open_forward (channel, tunnel->dest, tunnel->port, "127.0.0.1", 0) != SSH_OK) { close (sock); channel_close (channel); channel_free (channel); remmina_ssh_set_error (REMMINA_SSH (tunnel), _("Failed to connect to the SSH tunnel destination: %s")); tunnel->thread = 0; return NULL; } remmina_ssh_tunnel_add_channel (tunnel, channel, sock); break; case REMMINA_SSH_TUNNEL_X11: if ((tunnel->x11_channel = channel_new (tunnel->ssh.session)) == NULL) { remmina_ssh_set_error (REMMINA_SSH (tunnel), "Failed to create channel : %s"); tunnel->thread = 0; return NULL; } if (!remmina_public_get_xauth_cookie (tunnel->localdisplay, &ptr)) { remmina_ssh_set_application_error (REMMINA_SSH (tunnel), "%s", ptr); g_free(ptr); tunnel->thread = 0; return NULL; } if (channel_open_session (tunnel->x11_channel) || channel_request_x11 (tunnel->x11_channel, TRUE, NULL, ptr, gdk_screen_get_number (gdk_screen_get_default ()))) { g_free(ptr); remmina_ssh_set_error (REMMINA_SSH (tunnel), "Failed to open channel : %s"); tunnel->thread = 0; return NULL; } g_free(ptr); if (channel_request_exec (tunnel->x11_channel, tunnel->dest)) { ptr = g_strdup_printf(_("Failed to execute %s on SSH server : %%s"), tunnel->dest); remmina_ssh_set_error (REMMINA_SSH (tunnel), ptr); g_free(ptr); tunnel->thread = 0; return NULL; } if (tunnel->init_func && ! (*tunnel->init_func) (tunnel, tunnel->callback_data)) { if (tunnel->disconnect_func) { (*tunnel->disconnect_func) (tunnel, tunnel->callback_data); } tunnel->thread = 0; return NULL; } break; case REMMINA_SSH_TUNNEL_XPORT: /* Detect the next available port starting from 6010 on the server */ for (i = 10; i <= MAX_X_DISPLAY_NUMBER; i++) { if (channel_forward_listen (REMMINA_SSH (tunnel)->session, (tunnel->bindlocalhost ? "localhost" : NULL), 6000 + i, NULL)) { continue; } else { tunnel->remotedisplay = i; break; } } if (tunnel->remotedisplay < 1) { remmina_ssh_set_error (REMMINA_SSH (tunnel), _("Failed to request port forwarding : %s")); if (tunnel->disconnect_func) { (*tunnel->disconnect_func) (tunnel, tunnel->callback_data); } tunnel->thread = 0; return NULL; } if (tunnel->init_func && ! (*tunnel->init_func) (tunnel, tunnel->callback_data)) { if (tunnel->disconnect_func) { (*tunnel->disconnect_func) (tunnel, tunnel->callback_data); } tunnel->thread = 0; return NULL; } break; case REMMINA_SSH_TUNNEL_REVERSE: if (channel_forward_listen (REMMINA_SSH (tunnel)->session, NULL, tunnel->port, NULL)) { remmina_ssh_set_error (REMMINA_SSH (tunnel), _("Failed to request port forwarding : %s")); if (tunnel->disconnect_func) { (*tunnel->disconnect_func) (tunnel, tunnel->callback_data); } tunnel->thread = 0; return NULL; } if (tunnel->init_func && ! (*tunnel->init_func) (tunnel, tunnel->callback_data)) { if (tunnel->disconnect_func) { (*tunnel->disconnect_func) (tunnel, tunnel->callback_data); } tunnel->thread = 0; return NULL; } break; } tunnel->buffer_len = 10240; tunnel->buffer = g_malloc (tunnel->buffer_len); /* Start the tunnel data transmittion */ while (tunnel->running) { if (tunnel->tunnel_type == REMMINA_SSH_TUNNEL_XPORT || tunnel->tunnel_type == REMMINA_SSH_TUNNEL_X11 || tunnel->tunnel_type == REMMINA_SSH_TUNNEL_REVERSE) { if (first) { first = FALSE; /* Wait for a period of time for the first incoming connection */ if (tunnel->tunnel_type == REMMINA_SSH_TUNNEL_X11) { channel = channel_accept_x11 (tunnel->x11_channel, 15000); } else { channel = channel_forward_accept (REMMINA_SSH (tunnel)->session, 15000); } if (!channel) { remmina_ssh_set_application_error (REMMINA_SSH (tunnel), _("No response from the server.")); if (tunnel->disconnect_func) { (*tunnel->disconnect_func) (tunnel, tunnel->callback_data); } tunnel->thread = 0; return NULL; } if (tunnel->connect_func) { (*tunnel->connect_func) (tunnel, tunnel->callback_data); } if (tunnel->tunnel_type == REMMINA_SSH_TUNNEL_REVERSE) { /* For reverse tunnel, we only need one connection. */ channel_forward_cancel (REMMINA_SSH (tunnel)->session, NULL, tunnel->port); } } else if (tunnel->tunnel_type != REMMINA_SSH_TUNNEL_REVERSE) { /* Poll once per some period of time if no incoming connections. * Don't try to poll continuously as it will significantly slow down the loop */ g_get_current_time (&t1); diff = (t1.tv_sec - t2.tv_sec) * 10 + (t1.tv_usec - t2.tv_usec) / 100000; if (diff > 1) { if (tunnel->tunnel_type == REMMINA_SSH_TUNNEL_X11) { channel = channel_accept_x11 (tunnel->x11_channel, 0); } else { channel = channel_forward_accept (REMMINA_SSH (tunnel)->session, 0); } if (channel == NULL) { t2 = t1; } } } if (channel) { if (tunnel->tunnel_type == REMMINA_SSH_TUNNEL_REVERSE) { sin.sin_family = AF_INET; sin.sin_port = htons (tunnel->localport); sin.sin_addr.s_addr = inet_addr ("127.0.0.1"); sock = socket (AF_INET, SOCK_STREAM, 0); if (connect (sock, (struct sockaddr *) &sin, sizeof (sin)) < 0) { remmina_ssh_set_application_error (REMMINA_SSH (tunnel), "Cannot connect to local port %i.", tunnel->localport); close (sock); sock = -1; } } else { sock = remmina_public_open_xdisplay (tunnel->localdisplay); } if (sock >= 0) { remmina_ssh_tunnel_add_channel (tunnel, channel, sock); } else { /* Failed to create unix socket. Will this happen? */ channel_close (channel); channel_free (channel); } channel = NULL; } } if (tunnel->num_channels <= 0) { /* No more connections. We should quit */ break; } timeout.tv_sec = 0; timeout.tv_usec = 200000; FD_ZERO (&set); maxfd = 0; for (i = 0; i < tunnel->num_channels; i++) { if (tunnel->sockets[i] > maxfd) { maxfd = tunnel->sockets[i]; } FD_SET (tunnel->sockets[i], &set); } ret = ssh_select (tunnel->channels, tunnel->channels_out, maxfd + 1, &set, &timeout); if (!tunnel->running) break; if (ret == SSH_EINTR) continue; if (ret == -1) break; i = 0; while (tunnel->running && i < tunnel->num_channels) { disconnected = FALSE; if (FD_ISSET (tunnel->sockets[i], &set)) { while (!disconnected && (len = read (tunnel->sockets[i], tunnel->buffer, tunnel->buffer_len)) > 0) { for (ptr = tunnel->buffer, lenw = 0; len > 0; len -= lenw, ptr += lenw) { lenw = channel_write (tunnel->channels[i], (char*) ptr, len); if (lenw <= 0) { disconnected = TRUE; break; } } } if (len == 0) disconnected = TRUE; } if (disconnected) { remmina_ssh_tunnel_remove_channel (tunnel, i); continue; } i++; } if (!tunnel->running) break; i = 0; while (tunnel->running && i < tunnel->num_channels) { disconnected = FALSE; if (!tunnel->socketbuffers[i]) { len = channel_poll (tunnel->channels[i], 0); if (len == SSH_ERROR || len == SSH_EOF) { disconnected = TRUE; } else if (len > 0) { tunnel->socketbuffers[i] = remmina_ssh_tunnel_buffer_new (len); len = channel_read_nonblocking (tunnel->channels[i], tunnel->socketbuffers[i]->data, len, 0); if (len <= 0) { disconnected = TRUE; } else { tunnel->socketbuffers[i]->len = len; } } } if (!disconnected && tunnel->socketbuffers[i]) { for (lenw = 0; tunnel->socketbuffers[i]->len > 0; tunnel->socketbuffers[i]->len -= lenw, tunnel->socketbuffers[i]->ptr += lenw) { lenw = write (tunnel->sockets[i], tunnel->socketbuffers[i]->ptr, tunnel->socketbuffers[i]->len); if (lenw == -1 && errno == EAGAIN && tunnel->running) { /* Sometimes we cannot write to a socket (always EAGAIN), probably because it's internal * buffer is full. We need read the pending bytes from the socket first. so here we simply * break, leave the buffer there, and continue with other data */ break; } if (lenw <= 0) { disconnected = TRUE; break; } } if (tunnel->socketbuffers[i]->len <= 0) { remmina_ssh_tunnel_buffer_free (tunnel->socketbuffers[i]); tunnel->socketbuffers[i] = NULL; } } if (disconnected) { remmina_ssh_tunnel_remove_channel (tunnel, i); continue; } i++; } } remmina_ssh_tunnel_close_all_channels (tunnel); return NULL; }
static gpointer remmina_ssh_shell_thread (gpointer data) { RemminaSSHShell *shell = (RemminaSSHShell*) data; fd_set fds; struct timeval timeout; ssh_channel channel = NULL; ssh_channel ch[2], chout[2]; gchar *buf = NULL; gint buf_len; gint len; gint i, ret; LOCK_SSH (shell) if ((channel = channel_new (REMMINA_SSH (shell)->session)) == NULL || channel_open_session (channel)) { UNLOCK_SSH (shell) remmina_ssh_set_error (REMMINA_SSH (shell), "Failed to open channel : %s"); if (channel) channel_free (channel); shell->thread = 0; return NULL; } channel_request_pty (channel); if (shell->exec && shell->exec[0]) { ret = channel_request_exec (channel, shell->exec); } else { ret = channel_request_shell (channel); } if (ret) { UNLOCK_SSH (shell) remmina_ssh_set_error (REMMINA_SSH (shell), "Failed to request shell : %s"); channel_close (channel); channel_free (channel); shell->thread = 0; return NULL; } shell->channel = channel; UNLOCK_SSH (shell) buf_len = 1000; buf = g_malloc (buf_len + 1); ch[0] = channel; ch[1] = NULL; while (!shell->closed) { timeout.tv_sec = 1; timeout.tv_usec = 0; FD_ZERO (&fds); FD_SET (shell->master, &fds); ret = ssh_select (ch, chout, shell->master + 1, &fds, &timeout); if (ret == SSH_EINTR) continue; if (ret == -1) break; if (FD_ISSET (shell->master, &fds)) { len = read (shell->master, buf, buf_len); if (len <= 0) break; LOCK_SSH (shell) channel_write (channel, buf, len); UNLOCK_SSH (shell) } for (i = 0; i < 2; i++) { LOCK_SSH (shell) len = channel_poll (channel, i); UNLOCK_SSH (shell) if (len == SSH_ERROR || len == SSH_EOF) { shell->closed = TRUE; break; } if (len <= 0) continue; if (len > buf_len) { buf_len = len; buf = (gchar*) g_realloc (buf, buf_len + 1); } LOCK_SSH (shell) len = channel_read_nonblocking (channel, buf, len, i); UNLOCK_SSH (shell) if (len <= 0) { shell->closed = TRUE; break; } while (len > 0) { ret = write (shell->master, buf, len); if (ret <= 0) break; len -= ret; } } }
static gpointer remmina_nx_session_tunnel_main_thread(gpointer data) { RemminaNXSession *nx = (RemminaNXSession*) data; gchar *ptr; ssize_t len = 0, lenw = 0; fd_set set; struct timeval timeout; ssh_channel channels[2]; ssh_channel channels_out[2]; gint sock; gint ret; gchar buffer[10240]; gchar socketbuffer[10240]; gchar *socketbuffer_ptr = NULL; gint socketbuffer_len = 0; pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); /* Accept a local connection */ sock = accept(nx->server_sock, NULL, NULL); if (sock < 0) { remmina_nx_session_set_application_error(nx, "Failed to accept local socket"); nx->thread = 0; return NULL; } close(nx->server_sock); nx->server_sock = -1; channels[0] = nx->channel; channels[1] = NULL; /* Start the tunnel data transmittion */ while (nx->running) { timeout.tv_sec = 1; timeout.tv_usec = 0; FD_ZERO(&set); FD_SET(sock, &set); ret = ssh_select(channels, channels_out, sock + 1, &set, &timeout); if (!nx->running) break; if (ret == SSH_EINTR) continue; if (ret == -1) break; if (FD_ISSET(sock, &set)) { len = read(sock, buffer, sizeof(buffer)); if (len == 0) nx->running = FALSE; else if (len > 0) { for (ptr = buffer, lenw = 0; len > 0; len -= lenw, ptr += lenw) { ssh_set_fd_towrite(nx->session); lenw = channel_write(channels[0], (char*) ptr, len); if (lenw <= 0) { nx->running = FALSE; break; } } } } if (!nx->running) break; if (channels_out[0] && socketbuffer_len <= 0) { len = channel_read_nonblocking(channels_out[0], socketbuffer, sizeof(socketbuffer), 0); if (len == SSH_ERROR || len == SSH_EOF) { nx->running = FALSE; break; } else if (len > 0) { socketbuffer_ptr = socketbuffer; socketbuffer_len = len; } else { /* Clean up the stderr buffer in case FreeNX send something there */ len = channel_read_nonblocking(channels_out[0], buffer, sizeof(buffer), 1); } } if (nx->running && socketbuffer_len > 0) { for (lenw = 0; socketbuffer_len > 0; socketbuffer_len -= lenw, socketbuffer_ptr += lenw) { lenw = write(sock, socketbuffer_ptr, socketbuffer_len); if (lenw == -1 && errno == EAGAIN && nx->running) { /* Sometimes we cannot write to a socket (always EAGAIN), probably because it's internal * buffer is full. We need read the pending bytes from the socket first. so here we simply * break, leave the buffer there, and continue with other data */ break; } if (lenw <= 0) { nx->running = FALSE; break; } } } } nx->thread = 0; return NULL; }
/* * Channel write complete handler for writing data to the remote endpoint * during a file upload. */ DWORD file_upload_write_complete(Remote *remote, Channel *channel, LPVOID context, DWORD result, ULONG bytesWritten) { FileUploadContext *ctx = (FileUploadContext *)context; ChannelCompletionRoutine complete; DWORD res = ERROR_SUCCESS; BOOL textPrinted = TRUE; CHAR buffer[8192]; LONG bytesRead; do { // If the result was not successful, no sense in continuing if ((!channel) || (result != ERROR_SUCCESS)) { console_write_output( "\n" INBOUND_PREFIX " FS: file_upload_write failed, result %lu.\n", result); res = result; break; } // Try to read more data from the local file bytesRead = fread(buffer, 1, sizeof(buffer), ctx->fd); // If there are no more bytes in the file, send a channel close // notification. if (bytesRead <= 0) { console_write_output( "\n" INBOUND_PREFIX " FS: Upload to '%s' completed.\n", ctx->source); channel_close(channel, remote, NULL, 0, NULL); break; } textPrinted = FALSE; // Keep writing to the channel until it's done with memset(&complete, 0, sizeof(complete)); complete.context = (LPVOID)ctx; complete.routine.write = file_upload_write_complete; // Write the buffer to the wire res = channel_write(channel, remote, NULL, 0, (PUCHAR)buffer, bytesRead, &complete); } while (0); // If the result was not successful, clean up the context here if (result != ERROR_SUCCESS) { if (channel) channel_close(channel, remote, NULL, 0, NULL); // Deallocate the passed in context if (ctx->fd) fclose(ctx->fd); free(ctx); } if (textPrinted) console_write_prompt(); return res; }
/* * core_channel_read * ----------------- * * From from the local buffer and write back to the requester * * Takes TLVs: * * req: TLV_TYPE_CHANNEL_ID -- The channel identifier to read from * req: TLV_TYPE_LENGTH -- The number of bytes to read */ DWORD remote_request_core_channel_read(Remote *remote, Packet *packet) { DWORD res = ERROR_SUCCESS, bytesToRead, bytesRead, channelId; Packet *response = packet_create_response(packet); PUCHAR temporaryBuffer = NULL; Channel *channel = NULL; do { if (!response) { res = ERROR_NOT_ENOUGH_MEMORY; break; } // Get the number of bytes to read bytesToRead = packet_get_tlv_value_uint(packet, TLV_TYPE_LENGTH); channelId = packet_get_tlv_value_uint(packet, TLV_TYPE_CHANNEL_ID); // Try to locate the specified channel if (!(channel = channel_find_by_id(channelId))) { res = ERROR_NOT_FOUND; break; } lock_acquire( channel->lock ); // Allocate temporary storage if (!(temporaryBuffer = (PUCHAR)malloc(bytesToRead))) { res = ERROR_NOT_ENOUGH_MEMORY; break; } switch (channel_get_class(channel)) { // If it's buffered, read from the local buffer and either transmit // the buffer in the response or write it back asynchronously // depending on the mode of the channel. case CHANNEL_CLASS_BUFFERED: // Read in from local res = channel_read_from_buffered(channel, temporaryBuffer, bytesToRead, (PULONG)&bytesRead); break; // Handle read I/O for the pool class case CHANNEL_CLASS_POOL: // If the channel has a read handler if (channel->ops.pool.read) res = channel->ops.pool.read(channel, packet, channel->ops.pool.native.context, temporaryBuffer, bytesToRead, &bytesRead); else res = ERROR_NOT_SUPPORTED; break; default: res = ERROR_NOT_SUPPORTED; } // If we've so far been successful and we have a temporary buffer... if ((res == ERROR_SUCCESS) &&(temporaryBuffer) && (bytesRead)) { // If the channel should operate synchronously, add the data to theresponse if (channel_is_flag(channel, CHANNEL_FLAG_SYNCHRONOUS)) { // if the channel data is ment to be compressed, compress it! if( channel_is_flag( channel, CHANNEL_FLAG_COMPRESS ) ) packet_add_tlv_raw(response, TLV_TYPE_CHANNEL_DATA|TLV_META_TYPE_COMPRESSED, temporaryBuffer, bytesRead); else packet_add_tlv_raw(response, TLV_TYPE_CHANNEL_DATA, temporaryBuffer, bytesRead); res = ERROR_SUCCESS; } // Otherwise, asynchronously write the buffer to the remote endpoint else { if ((res = channel_write(channel, remote, NULL, 0, temporaryBuffer, bytesRead, NULL)) != ERROR_SUCCESS) break; } } } while (0); if( channel ) lock_release( channel->lock ); if (temporaryBuffer) free(temporaryBuffer); // Transmit the acknowledgement if (response) { packet_add_tlv_uint(response, TLV_TYPE_RESULT, res); packet_add_tlv_uint(response, TLV_TYPE_LENGTH, bytesRead); packet_add_tlv_uint(response, TLV_TYPE_CHANNEL_ID, channelId); res = packet_transmit(remote, response, NULL); } return res; }