static size_t read_from_channel_port (SCM channel, SCM dst, size_t start, size_t count) #define FUNC_NAME "read_from_channel_port" { char *data = (char *) SCM_BYTEVECTOR_CONTENTS (dst) + start; struct channel_data *cd = _scm_to_channel_data (channel); int res; if (! ssh_channel_is_open (cd->ssh_channel)) return 0; /* Update state of the underlying channel and check whether we have data to read or not. */ res = ssh_channel_poll (cd->ssh_channel, cd->is_stderr); if (res == SSH_ERROR) guile_ssh_error1 (FUNC_NAME, "Error polling channel", channel); else if (res == SSH_EOF) return 0; /* Note: `ssh_channel_read' sometimes returns 0 even if `ssh_channel_poll' returns a positive value. */ res = ssh_channel_read (cd->ssh_channel, data, count, cd->is_stderr); if (res == SSH_AGAIN) res = 0; else if (res == SSH_ERROR) guile_ssh_error1 (FUNC_NAME, "Error reading from the channel", channel); assert (res >= 0); return res; }
/** * Remove a channel from its associated port mapping structure * * Take the channel given and remove it from its parent port_map structure, * closing it first and removing it from the fd_map in the gateway struct that * maps client sockets -> channels. * * All channel pointers in pm->ch[] higher than this one are shifted down by * one position and the array is shrunk appropriately. * * @cs channel structure to remove * @return Nothing, if there are errors here they are either logged or the * program exits (on malloc failure) */ void remove_channel_from_map(struct chan_sock *cs) { struct static_port_map *pm = cs->parent; int i; if(cs->parent == NULL) log_exit(FATAL_ERROR, "Corrupt chan_sock parent %p->parent NULL", cs); for(i = 0; i < pm->n_channels; i++) { if(pm->ch[i] == cs) { if( ssh_channel_is_open(cs->channel) && ssh_channel_close(cs->channel) != SSH_OK) log_msg("Error on channel close for %s", pm->parent->name); ssh_channel_free(cs->channel); break; } } debug("Destroy channel %p, closing fd=%d", cs->channel, cs->sock_fd); for(; i < pm->n_channels - 1; i++) pm->ch[i] = pm->ch[i + 1]; saferealloc((void **)&pm->ch, pm->n_channels * sizeof(cs), "pm->channel realloc"); pm->n_channels -= 1; close(cs->sock_fd); /* Remove this fd from parent gw's fd_map */ remove_fdmap(pm->parent->chan_sock_fdmap, cs->sock_fd); free(cs); }
static void select_loop(ssh_session session,ssh_channel channel) { ssh_connector connector_in, connector_out, connector_err; ssh_event event = ssh_event_new(); /* stdin */ connector_in = ssh_connector_new(session); ssh_connector_set_out_channel(connector_in, channel, SSH_CONNECTOR_STDOUT); /* Attach first endpointg of input pipe to SSH core */ ssh_connector_set_in_fd(connector_in, input_pipe[0] /* 0 */); ssh_event_add_connector(event, connector_in); /* stdout */ connector_out = ssh_connector_new(session); #if defined(OUT_PIPE) /* Attach first endpointg of output pipe to SSH core */ ssh_connector_set_out_fd(connector_out, output_pipe[0] /* 1*/); #else ssh_connector_set_out_fd(connector_out, 1); #endif /* OUT_PIPE */ ssh_connector_set_in_channel(connector_out, channel, SSH_CONNECTOR_STDOUT); ssh_event_add_connector(event, connector_out); /* stderr */ connector_err = ssh_connector_new(session); ssh_connector_set_out_fd(connector_err, 2); ssh_connector_set_in_channel(connector_err, channel, SSH_CONNECTOR_STDERR); ssh_event_add_connector(event, connector_err); while(ssh_channel_is_open(channel)) { if(signal_delayed) sizechanged(); ssh_event_dopoll(event, 60000); } ssh_event_remove_connector(event, connector_in); ssh_event_remove_connector(event, connector_out); ssh_event_remove_connector(event, connector_err); ssh_connector_free(connector_in); ssh_connector_free(connector_out); ssh_connector_free(connector_err); ssh_event_free(event); ssh_channel_free(channel); }
int SSH_Socket::pollSocket() { int numready; if(sshChannel && ssh_channel_is_open(sshChannel) && ssh_channel_poll(sshChannel,0) > 0) { numready = 1; } else { numready = 0; } if(ssh_channel_poll(sshChannel,0) < 0) TheSocketHandler::Instance()->setActive(false); return numready; }
/* Read data from the channel. Return EOF if no data is available or throw `guile-ssh-error' if an error occured. */ static int ptob_fill_input (SCM channel) #define FUNC_NAME "ptob_fill_input" { struct channel_data *cd = _scm_to_channel_data (channel); scm_port *pt = SCM_PTAB_ENTRY (channel); int res; if (! ssh_channel_is_open (cd->ssh_channel)) return EOF; /* Update state of the underlying channel and check whether we have data to read or not. */ res = ssh_channel_poll (cd->ssh_channel, cd->is_stderr); if (res == SSH_ERROR) guile_ssh_error1 (FUNC_NAME, "Error polling channel", channel); else if (res == SSH_EOF) return EOF; res = ssh_channel_read (cd->ssh_channel, pt->read_buf, pt->read_buf_size, cd->is_stderr); if (res == SSH_ERROR) guile_ssh_error1 (FUNC_NAME, "Error reading from the channel", channel); /* `ssh_channel_read' sometimes returns 0 even if `ssh_channel_poll' returns a positive value. So we must ensure that res != 0 otherwise an assertion in `scm_i_fill_input' won't be meet (see `ports.c' in Guile 2.0.9). */ if ((! res) || (res == SSH_AGAIN)) return EOF; pt->read_pos = pt->read_buf; pt->read_end = pt->read_buf + res; return *pt->read_buf; }
/* Print the CHANNEL object to port PORT. */ static int print_channel (SCM channel, SCM port, scm_print_state *pstate) { struct channel_data *ch = NULL; #if USING_GUILE_BEFORE_2_2 if (SCM_PTAB_ENTRY (channel)) ch = _scm_to_channel_data (channel); #else ch = _scm_to_channel_data (channel); #endif scm_puts ("#<", port); if (! ch) { scm_puts ("unknown channel (freed) ", port); } else { scm_print_port_mode (channel, port); scm_puts ("channel ", port); if (SCM_OPPORTP (channel)) { int is_open = ssh_channel_is_open (ch->ssh_channel); scm_puts (is_open ? "(open) " : "(closed) ", port); } else { scm_puts ("(closed) ", port); } } scm_display (_scm_object_hex_address (channel), port); scm_puts (">", port); return 1; }
static int #else static void #endif ptob_close (SCM channel) { struct channel_data *ch = _scm_to_channel_data (channel); #if USING_GUILE_BEFORE_2_2 scm_port *pt = SCM_PTAB_ENTRY (channel); ptob_flush (channel); #endif if (ch && ssh_channel_is_open (ch->ssh_channel)) { _gssh_log_debug ("ptob_close", "closing and freeing the channel...", channel); ssh_channel_close (ch->ssh_channel); ssh_channel_free (ch->ssh_channel); _gssh_log_debug1 ("ptob_close", "closing and freeing the channel... done"); } else { _gssh_log_debug1 ("ptob_close", "the channel is already freeed."); } SCM_SETSTREAM (channel, NULL); #if USING_GUILE_BEFORE_2_2 scm_gc_free (pt->write_buf, pt->write_buf_size, "port write buffer"); scm_gc_free (pt->read_buf, pt->read_buf_size, "port read buffer"); return 0; #endif }
static void close_immediately (CockpitSshTransport *self, const gchar *problem) { GSource *source; GThread *thread; if (self->timeout_close) { g_source_remove (self->timeout_close); self->timeout_close = 0; } if (self->closed) return; self->closed = TRUE; if (self->connect_thread) { thread = self->connect_thread; self->connect_thread = NULL; /* This causes thread to fail */ g_atomic_int_set (&self->connecting, 0); close (self->connect_fd); self->connect_fd = -1; g_assert (self->data == NULL); self->data = g_thread_join (thread); } g_assert (self->data != NULL); if (problem == NULL) problem = self->problem; g_object_ref (self); if (!self->result_emitted) { self->result_emitted = TRUE; g_signal_emit_by_name (self, "result", problem); } g_debug ("%s: closing io%s%s", self->logname, problem ? ": " : "", problem ? problem : ""); if (self->io) { source = self->io; self->io = NULL; g_source_destroy (source); g_source_unref (source); } if (self->data->channel && ssh_channel_is_open (self->data->channel)) ssh_channel_close (self->data->channel); ssh_disconnect (self->data->session); cockpit_transport_emit_closed (COCKPIT_TRANSPORT (self), problem); g_object_unref (self); }
static void select_loop(ssh_session_t *session,ssh_channel_t *channel) { fd_set fds; struct timeval timeout; char buffer[4096]; /* channels will be set to the channels to poll. * outchannels will contain the result of the poll */ ssh_channel_t *channels[2], *outchannels[2]; int lus; int eof=0; int maxfd; unsigned int r; int ret; while(channel) { do { FD_ZERO(&fds); if(!eof) { FD_SET(0, &fds); } timeout.tv_sec = 30; timeout.tv_usec = 0; FD_SET(ssh_get_fd(session), &fds); maxfd = ssh_get_fd(session) + 1; channels[0] = channel; // set the first channel we want to read from channels[1] = NULL; ret = ssh_select(channels, outchannels, maxfd, &fds, &timeout); if(signal_delayed) { sizechanged(); } if(ret == EINTR) { continue; } if(FD_ISSET(0, &fds)) { lus = read(0, buffer, sizeof(buffer)); if(lus) ssh_channel_write(channel, buffer, lus); else { eof = 1; ssh_channel_send_eof(channel); } } if(channel && ssh_channel_is_closed(channel)) { ssh_channel_free(channel); channel=NULL; channels[0]=NULL; } if(outchannels[0]) { while(channel && ssh_channel_is_open(channel) && (r = ssh_channel_poll(channel,0))!=0) { lus = ssh_channel_read(channel,buffer,sizeof(buffer) > r ? r : sizeof(buffer),0); if(lus == -1) { fprintf(stderr, "Error reading channel: %s\n", ssh_get_error(session)); return; } if(lus == 0) { ssh_channel_free(channel); channel=channels[0]=NULL; } else { if (write(1,buffer,lus) < 0) { fprintf(stderr, "Error writing to buffer\n"); return; } } } while(channel && ssh_channel_is_open(channel) && (r = ssh_channel_poll(channel,1))!=0) /* stderr */ { lus = ssh_channel_read(channel,buffer,sizeof(buffer) > r ? r : sizeof(buffer),1); if(lus == -1) { fprintf(stderr, "Error reading channel: %s\n", ssh_get_error(session)); return; } if(lus == 0) { ssh_channel_free(channel); channel = channels[0] = NULL; } else { if (write(2, buffer, lus) < 0) { fprintf(stderr, "Error writing to buffer\n"); return; } } } } if(channel && ssh_channel_is_closed(channel)) { ssh_channel_free(channel); channel=NULL; } } while (ret == EINTR || ret == SSH_EINTR); } }
static void handle_session(ssh_event event, ssh_session session) { int n; int rc = 0; /* Structure for storing the pty size. */ struct winsize wsize = { .ws_row = 0, .ws_col = 0, .ws_xpixel = 0, .ws_ypixel = 0 }; /* Our struct holding information about the channel. */ struct channel_data_struct cdata = { .pid = 0, .pty_master = -1, .pty_slave = -1, .child_stdin = -1, .child_stdout = -1, .child_stderr = -1, .event = NULL, .winsize = &wsize }; /* Our struct holding information about the session. */ struct session_data_struct sdata = { .channel = NULL, .auth_attempts = 0, .authenticated = 0 }; struct ssh_channel_callbacks_struct channel_cb = { .userdata = &cdata, .channel_pty_request_function = pty_request, .channel_pty_window_change_function = pty_resize, .channel_shell_request_function = shell_request, .channel_exec_request_function = exec_request, .channel_data_function = data_function, .channel_subsystem_request_function = subsystem_request }; struct ssh_server_callbacks_struct server_cb = { .userdata = &sdata, .auth_password_function = auth_password, .channel_open_request_session_function = channel_open, }; if (authorizedkeys[0]) { server_cb.auth_pubkey_function = auth_publickey; ssh_set_auth_methods(session, SSH_AUTH_METHOD_PASSWORD | SSH_AUTH_METHOD_PUBLICKEY); } else ssh_set_auth_methods(session, SSH_AUTH_METHOD_PASSWORD); ssh_callbacks_init(&server_cb); ssh_callbacks_init(&channel_cb); ssh_set_server_callbacks(session, &server_cb); if (ssh_handle_key_exchange(session) != SSH_OK) { fprintf(stderr, "%s\n", ssh_get_error(session)); return; } ssh_event_add_session(event, session); n = 0; while (sdata.authenticated == 0 || sdata.channel == NULL) { /* If the user has used up all attempts, or if he hasn't been able to * authenticate in 10 seconds (n * 100ms), disconnect. */ if (sdata.auth_attempts >= 3 || n >= 100) { return; } if (ssh_event_dopoll(event, 100) == SSH_ERROR) { fprintf(stderr, "%s\n", ssh_get_error(session)); return; } n++; } ssh_set_channel_callbacks(sdata.channel, &channel_cb); do { /* Poll the main event which takes care of the session, the channel and * even our child process's stdout/stderr (once it's started). */ if (ssh_event_dopoll(event, -1) == SSH_ERROR) { ssh_channel_close(sdata.channel); } /* If child process's stdout/stderr has been registered with the event, * or the child process hasn't started yet, continue. */ if (cdata.event != NULL || cdata.pid == 0) { continue; } /* Executed only once, once the child process starts. */ cdata.event = event; /* If stdout valid, add stdout to be monitored by the poll event. */ if (cdata.child_stdout != -1) { if (ssh_event_add_fd(event, cdata.child_stdout, POLLIN, process_stdout, sdata.channel) != SSH_OK) { fprintf(stderr, "Failed to register stdout to poll context\n"); ssh_channel_close(sdata.channel); } } /* If stderr valid, add stderr to be monitored by the poll event. */ if (cdata.child_stderr != -1){ if (ssh_event_add_fd(event, cdata.child_stderr, POLLIN, process_stderr, sdata.channel) != SSH_OK) { fprintf(stderr, "Failed to register stderr to poll context\n"); ssh_channel_close(sdata.channel); } } } while(ssh_channel_is_open(sdata.channel) && (cdata.pid == 0 || waitpid(cdata.pid, &rc, WNOHANG) == 0)); close(cdata.pty_master); close(cdata.child_stdin); close(cdata.child_stdout); close(cdata.child_stderr); /* Remove the descriptors from the polling context, since they are now * closed, they will always trigger during the poll calls. */ ssh_event_remove_fd(event, cdata.child_stdout); ssh_event_remove_fd(event, cdata.child_stderr); /* If the child process exited. */ if (kill(cdata.pid, 0) < 0 && WIFEXITED(rc)) { rc = WEXITSTATUS(rc); ssh_channel_request_send_exit_status(sdata.channel, rc); /* If client terminated the channel or the process did not exit nicely, * but only if something has been forked. */ } else if (cdata.pid > 0) { kill(cdata.pid, SIGKILL); } ssh_channel_send_eof(sdata.channel); ssh_channel_close(sdata.channel); /* Wait up to 5 seconds for the client to terminate the session. */ for (n = 0; n < 50 && (ssh_get_status(session) & SESSION_END) == 0; n++) { ssh_event_dopoll(event, 100); } } /* SIGCHLD handler for cleaning up dead children. */ static void sigchld_handler(int signo) { (void) signo; while (waitpid(-1, NULL, WNOHANG) > 0); } int main(int argc, char **argv) { ssh_bind sshbind; ssh_session session; ssh_event event; struct sigaction sa; int rc; /* Set up SIGCHLD handler. */ sa.sa_handler = sigchld_handler; sigemptyset(&sa.sa_mask); sa.sa_flags = SA_RESTART | SA_NOCLDSTOP; if (sigaction(SIGCHLD, &sa, NULL) != 0) { fprintf(stderr, "Failed to register SIGCHLD handler\n"); return 1; } rc = ssh_init(); if (rc < 0) { fprintf(stderr, "ssh_init failed\n"); return 1; } sshbind = ssh_bind_new(); if (sshbind == NULL) { fprintf(stderr, "ssh_bind_new failed\n"); return 1; } #ifdef HAVE_ARGP_H argp_parse(&argp, argc, argv, 0, 0, sshbind); #else (void) argc; (void) argv; set_default_keys(sshbind, 0, 0, 0); #endif /* HAVE_ARGP_H */ if(ssh_bind_listen(sshbind) < 0) { fprintf(stderr, "%s\n", ssh_get_error(sshbind)); return 1; } while (1) { session = ssh_new(); if (session == NULL) { fprintf(stderr, "Failed to allocate session\n"); continue; } /* Blocks until there is a new incoming connection. */ if(ssh_bind_accept(sshbind, session) != SSH_ERROR) { switch(fork()) { case 0: /* Remove the SIGCHLD handler inherited from parent. */ sa.sa_handler = SIG_DFL; sigaction(SIGCHLD, &sa, NULL); /* Remove socket binding, which allows us to restart the * parent process, without terminating existing sessions. */ ssh_bind_free(sshbind); event = ssh_event_new(); if (event != NULL) { /* Blocks until the SSH session ends by either * child process exiting, or client disconnecting. */ handle_session(event, session); ssh_event_free(event); } else { fprintf(stderr, "Could not create polling context\n"); } ssh_disconnect(session); ssh_free(session); exit(0); case -1: fprintf(stderr, "Failed to fork\n"); } } else { fprintf(stderr, "%s\n", ssh_get_error(sshbind)); } /* Since the session has been passed to a child fork, do some cleaning * up at the parent process. */ ssh_disconnect(session); ssh_free(session); } ssh_bind_free(sshbind); ssh_finalize(); return 0; }
/* channel_select base main loop, with a standard select(2) */ static void select_loop(ssh_session session,ssh_channel channel){ fd_set fds; struct timeval timeout; char buffer[4096]; ssh_buffer readbuf=ssh_buffer_new(); ssh_channel channels[2]; int lus; int eof=0; int maxfd; int ret; while(channel){ /* when a signal is caught, ssh_select will return * with SSH_EINTR, which means it should be started * again. It lets you handle the signal the faster you * can, like in this window changed example. Of course, if * your signal handler doesn't call libssh at all, you're * free to handle signals directly in sighandler. */ do{ FD_ZERO(&fds); if(!eof) FD_SET(0,&fds); timeout.tv_sec=30; timeout.tv_usec=0; FD_SET(ssh_get_fd(session),&fds); maxfd=ssh_get_fd(session)+1; ret=select(maxfd,&fds,NULL,NULL,&timeout); if(ret==EINTR) continue; if(FD_ISSET(0,&fds)){ lus=read(0,buffer,sizeof(buffer)); if(lus) ssh_channel_write(channel,buffer,lus); else { eof=1; ssh_channel_send_eof(channel); } } if(FD_ISSET(ssh_get_fd(session),&fds)){ ssh_set_fd_toread(session); } channels[0]=channel; // set the first channel we want to read from channels[1]=NULL; ret=ssh_channel_select(channels,NULL,NULL,NULL); // no specific timeout - just poll if(signal_delayed) sizechanged(); } while (ret==EINTR || ret==SSH_EINTR); // we already looked for input from stdin. Now, we are looking for input from the channel if(channel && ssh_channel_is_closed(channel)){ ssh_channel_free(channel); channel=NULL; channels[0]=NULL; } if(channels[0]){ while(channel && ssh_channel_is_open(channel) && ssh_channel_poll(channel,0)>0){ lus=channel_read_buffer(channel,readbuf,0,0); if(lus==-1){ fprintf(stderr, "Error reading channel: %s\n", ssh_get_error(session)); return; } if(lus==0){ ssh_channel_free(channel); channel=channels[0]=NULL; } else if (write(1,ssh_buffer_get_begin(readbuf),lus) < 0) { fprintf(stderr, "Error writing to buffer\n"); return; } } while(channel && ssh_channel_is_open(channel) && ssh_channel_poll(channel,1)>0){ /* stderr */ lus=channel_read_buffer(channel,readbuf,0,1); if(lus==-1){ fprintf(stderr, "Error reading channel: %s\n", ssh_get_error(session)); return; } if(lus==0){ ssh_channel_free(channel); channel=channels[0]=NULL; } else if (write(2,ssh_buffer_get_begin(readbuf),lus) < 0) { fprintf(stderr, "Error writing to buffer\n"); return; } } } if(channel && ssh_channel_is_closed(channel)){ ssh_channel_free(channel); channel=NULL; } } ssh_buffer_free(readbuf); }
static int my_fd_data_function(UNUSED_PARAM(socket_t fd), int revents, void *userdata) { struct event_fd_data_struct *event_fd_data = (struct event_fd_data_struct *)userdata; ssh_channel channel = event_fd_data->channel; ssh_session session; int len, i, wr; char buf[16384]; int blocking; if (channel == NULL) { _ssh_log(SSH_LOG_FUNCTIONS, "=== my_fd_data_function", "channel == NULL!"); return 0; } session = ssh_channel_get_session(channel); if (ssh_channel_is_closed(channel)) { _ssh_log(SSH_LOG_FUNCTIONS, "=== my_fd_data_function", "channel is closed!"); stack_socket_close(session, event_fd_data); return 0; } if (!(revents & POLLIN)) { if (revents & POLLPRI) { _ssh_log(SSH_LOG_PROTOCOL, "=== my_fd_data_function", "poll revents & POLLPRI"); } if (revents & POLLOUT) { _ssh_log(SSH_LOG_PROTOCOL, "=== my_fd_data_function", "poll revents & POLLOUT"); } if (revents & POLLHUP) { _ssh_log(SSH_LOG_PROTOCOL, "=== my_fd_data_function", "poll revents & POLLHUP"); } if (revents & POLLNVAL) { _ssh_log(SSH_LOG_PROTOCOL, "=== my_fd_data_function", "poll revents & POLLNVAL"); } if (revents & POLLERR) { _ssh_log(SSH_LOG_PROTOCOL, "=== my_fd_data_function", "poll revents & POLLERR"); } return 0; } blocking = ssh_is_blocking(session); ssh_set_blocking(session, 0); _ssh_log(SSH_LOG_FUNCTIONS, "=== my_fd_data_function", "Trying to read from tcp socket fd = %d... (Channel %d:%d state=%d)", *event_fd_data->p_fd, channel->local_channel, channel->remote_channel, channel->state); #ifdef _WIN32 struct sockaddr from; int fromlen = sizeof(from); len = recvfrom(*event_fd_data->p_fd, buf, sizeof(buf), 0, &from, &fromlen); #else len = recv(*event_fd_data->p_fd, buf, sizeof(buf), 0); #endif // _WIN32 if (len < 0) { _ssh_log(SSH_LOG_WARNING, "=== my_fd_data_function", "Reading from tcp socket: %s", strerror(errno)); ssh_channel_send_eof(channel); } else if (len > 0) { if (ssh_channel_is_open(channel)) { wr = 0; do { i = ssh_channel_write(channel, buf, len); if (i < 0) { _ssh_log(SSH_LOG_WARNING, "=== my_fd_data_function", "Error writing on the direct-tcpip channel: %d", i); len = wr; break; } wr += i; _ssh_log(SSH_LOG_FUNCTIONS, "=== my_fd_data_function", "channel_write (%d from %d)", wr, len); } while (i > 0 && wr < len); } else { _ssh_log(SSH_LOG_WARNING, "=== my_fd_data_function", "Can't write on closed channel!"); } } else { _ssh_log(SSH_LOG_PROTOCOL, "=== my_fd_data_function", "The destination host has disconnected!"); ssh_channel_close(channel); #ifdef _WIN32 shutdown(*event_fd_data->p_fd, SD_RECEIVE); #else shutdown(*event_fd_data->p_fd, SHUT_RD); #endif // _WIN32 } ssh_set_blocking(session, blocking); return len; }
int channel_is_open(ssh_channel channel){ return ssh_channel_is_open(channel); }
int send_cmd_to_ssh(ssh_channel chanusr, ssh_channel chansvr, char *buff) { int rc; unsigned int nbytes; char buffer[256]; char* ligne; if (chansvr == NULL) { return SSH_ERROR; } if(ssh_channel_is_open(chansvr) != SSH_OK) { rc = ssh_channel_open_session(chansvr); if (rc != SSH_OK) { ssh_channel_free(chansvr); chansvr = NULL; return rc; } } rc = ssh_channel_request_exec(chansvr, buff); //rc = ssh_channel_request_exec(chansvr, "ls"); //ssh_channel_write(chansvr, "ls", 2); if (rc != SSH_OK) { ssh_channel_close(chansvr); ssh_channel_free(chansvr); return rc; } memset(buffer, 0, 256); nbytes = ssh_channel_read(chansvr, buffer, sizeof(buffer) - 1, 0); while (nbytes > 0) { ligne = strtok(buffer,"\n"); while (ligne) { ssh_channel_write(chanusr, ligne, strlen(ligne)); ligne = strtok(NULL,"\n"); if (ligne != NULL) ssh_channel_write(chanusr, "\r\n", 2); } //ssh_channel_write(chanusr, buffer, nbytes); /*if (write(fd, buffer, nbytes) != nbytes) { ssh_channel_close(chansvr); ssh_channel_free(chansvr); return SSH_ERROR; } */ memset(buffer, 0, 256); nbytes = ssh_channel_read(chansvr, buffer, sizeof(buffer) - 1, 0); } return rc; }