static int main_loop(ssh_channel chan) { ssh_session session = ssh_channel_get_session(chan); socket_t fd; struct termios *term = NULL; struct winsize *win = NULL; pid_t childpid; ssh_event event; short events; childpid = forkpty(&fd, NULL, term, win); if(childpid == 0) { execl("/bin/bash", "/bin/bash", (char *)NULL); abort(); } cb.userdata = &fd; ssh_callbacks_init(&cb); ssh_set_channel_callbacks(chan, &cb); events = POLLIN | POLLPRI | POLLERR | POLLHUP | POLLNVAL; event = ssh_event_new(); if(event == NULL) { printf("Couldn't get a event\n"); return -1; } if(ssh_event_add_fd(event, fd, events, copy_fd_to_chan, chan) != SSH_OK) { printf("Couldn't add an fd to the event\n"); return -1; } if(ssh_event_add_session(event, session) != SSH_OK) { printf("Couldn't add the session to the event\n"); return -1; } do { ssh_event_dopoll(event, 1000); } while(!ssh_channel_is_closed(chan)); ssh_event_remove_fd(event, fd); ssh_event_remove_session(event, session); ssh_event_free(event); return 0; }
static void do_cleanup(struct cleanup_node_struct **head_ref) { struct cleanup_node_struct *current = (*head_ref); struct cleanup_node_struct *previous = NULL, *gone = NULL; while (current != NULL) { if (ssh_channel_is_closed(current->data->channel)) { if (current == (*head_ref)) { (*head_ref) = current->next; } if (previous != NULL) { previous->next = current->next; } gone = current; current = current->next; if (gone->data->channel) { _close_socket(*gone->data); ssh_remove_channel_callbacks(gone->data->channel, gone->data->cb_chan); ssh_channel_free(gone->data->channel); gone->data->channel = NULL; SAFE_FREE(gone->data->p_fd); SAFE_FREE(gone->data->cb_chan); SAFE_FREE(gone->data); SAFE_FREE(gone); } else { fprintf(stderr, "channel already freed!\n"); } _ssh_log(SSH_LOG_FUNCTIONS, "=== do_cleanup", "Freed."); } else { ssh_channel_close(current->data->channel); previous = current; current = current->next; } } }
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 int pkd_exec_hello(int fd, struct pkd_daemon_args *args) { int rc = -1; ssh_bind b = NULL; ssh_session s = NULL; ssh_event e = NULL; ssh_channel c = NULL; enum ssh_bind_options_e opts = -1; int level = args->opts.libssh_log_level; enum pkd_hostkey_type_e type = args->type; const char *hostkeypath = args->hostkeypath; pkd_state.eof_received = 0; pkd_state.close_received = 0; pkd_state.req_exec_received = 0; b = ssh_bind_new(); if (b == NULL) { pkderr("ssh_bind_new\n"); goto outclose; } if (type == PKD_RSA) { opts = SSH_BIND_OPTIONS_RSAKEY; } else if (type == PKD_DSA) { opts = SSH_BIND_OPTIONS_DSAKEY; } else if (type == PKD_ECDSA) { opts = SSH_BIND_OPTIONS_ECDSAKEY; } else { pkderr("unknown kex algorithm: %d\n", type); rc = -1; goto outclose; } rc = ssh_bind_options_set(b, opts, hostkeypath); if (rc != 0) { pkderr("ssh_bind_options_set: %s\n", ssh_get_error(b)); goto outclose; } rc = ssh_bind_options_set(b, SSH_BIND_OPTIONS_LOG_VERBOSITY, &level); if (rc != 0) { pkderr("ssh_bind_options_set log verbosity: %s\n", ssh_get_error(b)); goto outclose; } s = ssh_new(); if (s == NULL) { pkderr("ssh_new\n"); goto outclose; } /* * ssh_bind_accept loads host key as side-effect. If this * succeeds, the given 'fd' will be closed upon 'ssh_free(s)'. */ rc = ssh_bind_accept_fd(b, s, fd); if (rc != SSH_OK) { pkderr("ssh_bind_accept_fd: %s\n", ssh_get_error(b)); goto outclose; } /* accept only publickey-based auth */ ssh_set_auth_methods(s, SSH_AUTH_METHOD_PUBLICKEY); /* initialize callbacks */ ssh_callbacks_init(&pkd_server_cb); pkd_server_cb.userdata = &c; rc = ssh_set_server_callbacks(s, &pkd_server_cb); if (rc != SSH_OK) { pkderr("ssh_set_server_callbacks: %s\n", ssh_get_error(s)); goto out; } /* first do key exchange */ rc = ssh_handle_key_exchange(s); if (rc != SSH_OK) { pkderr("ssh_handle_key_exchange: %s\n", ssh_get_error(s)); goto out; } /* setup and pump event to carry out exec channel */ e = ssh_event_new(); if (e == NULL) { pkderr("ssh_event_new\n"); goto out; } rc = ssh_event_add_session(e, s); if (rc != SSH_OK) { pkderr("ssh_event_add_session\n"); goto out; } /* poll until exec channel established */ while ((ctx.keep_going != 0) && (rc != SSH_ERROR) && (pkd_state.req_exec_received == 0)) { rc = ssh_event_dopoll(e, -1 /* infinite timeout */); } if (rc == SSH_ERROR) { pkderr("ssh_event_dopoll\n"); goto out; } else if (c == NULL) { pkderr("poll loop exited but exec channel not ready\n"); rc = -1; goto out; } rc = ssh_channel_write(c, "hello\n", 6); /* XXX: customizable payloads */ if (rc != 6) { pkderr("ssh_channel_write partial (%d)\n", rc); } rc = ssh_channel_request_send_exit_status(c, 0); if (rc != SSH_OK) { pkderr("ssh_channel_request_send_exit_status: %s\n", ssh_get_error(s)); goto out; } rc = ssh_channel_send_eof(c); if (rc != SSH_OK) { pkderr("ssh_channel_send_eof: %s\n", ssh_get_error(s)); goto out; } rc = ssh_channel_close(c); if (rc != SSH_OK) { pkderr("ssh_channel_close: %s\n", ssh_get_error(s)); goto out; } while ((ctx.keep_going != 0) && (pkd_state.eof_received == 0) && (pkd_state.close_received == 0) && (ssh_channel_is_closed(c) == 0)) { rc = ssh_event_dopoll(e, 1000 /* milliseconds */); if (rc == SSH_ERROR) { pkderr("ssh_event_dopoll for eof + close: %s\n", ssh_get_error(s)); break; } else { rc = 0; } } goto out; outclose: close(fd); out: if (c != NULL) { ssh_channel_free(c); } if (e != NULL) { ssh_event_remove_session(e, s); ssh_event_free(e); } if (s != NULL) { ssh_disconnect(s); ssh_free(s); } if (b != NULL) { ssh_bind_free(b); } return rc; }
/* 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_closed(ssh_channel channel){ return ssh_channel_is_closed(channel); }
static int nc_write(struct nc_session *session, const void *buf, size_t count) { int c; size_t written = 0; #ifdef NC_ENABLED_TLS unsigned long e; #endif if ((session->status != NC_STATUS_RUNNING) && (session->status != NC_STATUS_STARTING)) { return -1; } /* prevent SIGPIPE this way */ if (!nc_session_is_connected(session)) { ERR("Session %u: communication socket unexpectedly closed.", session->id); session->status = NC_STATUS_INVALID; session->term_reason = NC_SESSION_TERM_DROPPED; return -1; } DBG("Session %u: sending message:\n%.*s\n", session->id, count, buf); do { switch (session->ti_type) { case NC_TI_FD: c = write(session->ti.fd.out, (char *)(buf + written), count - written); if (c < 0) { ERR("Session %u: socket error (%s).", session->id, strerror(errno)); return -1; } break; #ifdef NC_ENABLED_SSH case NC_TI_LIBSSH: if (ssh_channel_is_closed(session->ti.libssh.channel) || ssh_channel_is_eof(session->ti.libssh.channel)) { if (ssh_channel_is_closed(session->ti.libssh.channel)) { ERR("Session %u: SSH channel unexpectedly closed.", session->id); } else { ERR("Session %u: SSH channel unexpected EOF.", session->id); } session->status = NC_STATUS_INVALID; session->term_reason = NC_SESSION_TERM_DROPPED; return -1; } c = ssh_channel_write(session->ti.libssh.channel, (char *)(buf + written), count - written); if ((c == SSH_ERROR) || (c == -1)) { ERR("Session %u: SSH channel write failed.", session->id); return -1; } break; #endif #ifdef NC_ENABLED_TLS case NC_TI_OPENSSL: c = SSL_write(session->ti.tls, (char *)(buf + written), count - written); if (c < 1) { switch ((e = SSL_get_error(session->ti.tls, c))) { case SSL_ERROR_ZERO_RETURN: ERR("Session %u: SSL connection was properly closed.", session->id); return -1; case SSL_ERROR_WANT_WRITE: c = 0; break; case SSL_ERROR_SYSCALL: ERR("Session %u: SSL socket error (%s).", session->id, strerror(errno)); return -1; case SSL_ERROR_SSL: ERR("Session %u: SSL error (%s).", session->id, ERR_reason_error_string(e)); return -1; default: ERR("Session %u: unknown SSL error occured.", session->id); return -1; } } break; #endif default: ERRINT; return -1; } if (c == 0) { /* we must wait */ usleep(NC_TIMEOUT_STEP); } written += c; } while (written < count); return written; }