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; }
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); } }
int igetch() { time_t now; char c; int hasaddio = 1; extern int RMSG; if ((uinfo.mode == CHAT1 || uinfo.mode == TALK || uinfo.mode == PAGE) && RMSG == true) hasaddio = 0; igetagain: if (ibufsize == icurrchar) { fd_set readfds, xds; struct timeval to; int sr, hifd; to.tv_sec = 0; to.tv_usec = 0; hifd = 1; FD_ZERO(&readfds); FD_SET(0, &readfds); if ((hasaddio && (i_newfd))&&(!inremsg)) { FD_SET(i_newfd, &readfds); if (hifd <= i_newfd) hifd = i_newfd + 1; } //TODO: igetkey重入问题 if ((uinfo.mode != POSTING && uinfo.mode != SMAIL && uinfo.mode != EDIT) || DEFINE(getCurrentUser(), DEF_LOGININFORM)) if (scrint&&!inremsg) { while (msg_count) { inremsg = true; msg_count--; r_msg(); refresh(); inremsg = false; } } if (kicked) return KEY_TIMEOUT; #ifdef SSHBBS sr = ssh_select(hifd, &readfds, NULL, NULL, &to); #else sr = select(hifd, &readfds, NULL, NULL, &to); #endif if (sr < 0 && errno == EINTR) { if (talkrequest) return KEY_TALK; if ((uinfo.mode != POSTING && uinfo.mode != SMAIL && uinfo.mode != EDIT) || DEFINE(getCurrentUser(), DEF_LOGININFORM)) if (scrint&&!inremsg) { while (msg_count) { inremsg = true; msg_count--; r_msg(); inremsg = false; } goto igetagain; } } if (sr < 0 && errno != EINTR) abort_bbs(0); if (sr == 0) { refresh(); if (flushf) (*flushf)(); while (1) { int alarm_timeout; hifd = 1; FD_ZERO(&xds); FD_SET(0, &xds); FD_ZERO(&readfds); FD_SET(0, &readfds); if ((hasaddio && (i_newfd))&&(!inremsg)) { FD_SET(i_newfd, &readfds); if (hifd <= i_newfd) hifd = i_newfd + 1; } alarm_timeout = 0; if (i_top) to = *i_top; else { while ((i_timeout != 0)||(i_timeoutusec!=0)) { to.tv_sec = i_timeout - (time(0) - i_begintimeout); to.tv_usec = i_timeoutusec; if ((to.tv_sec < 0) ||((to.tv_sec==0)&&(i_timeoutusec==0))) { i_timeout = 0; i_timeoutusec=0; if (i_timeout_func) (*i_timeout_func)(timeout_data); else return KEY_TIMEOUT; if (kicked) return KEY_TIMEOUT; continue; }; alarm_timeout = 1; break; }; if (!alarm_timeout) to.tv_sec = IDLE_TIMEOUT; } #ifdef SSHBBS sr = ssh_select(hifd, &readfds, NULL, &xds, &to); #else sr = select(hifd, &readfds, NULL, &xds, &to); #endif if (sr < 0 && errno == EINTR) { if (talkrequest) return KEY_TALK; } if (kicked) return KEY_TIMEOUT; if ((uinfo.mode != POSTING && uinfo.mode != SMAIL && uinfo.mode != EDIT) || DEFINE(getCurrentUser(), DEF_LOGININFORM)) if (!inremsg) { int saveerrno=errno; while (msg_count) { inremsg = true; msg_count--; r_msg(); refresh(); inremsg = false; } if (sr<0&&saveerrno==EINTR)continue; } if (sr == 0 && alarm_timeout) { i_timeout = 0; i_timeoutusec=0; if (i_timeout_func) (*i_timeout_func)(timeout_data); else return KEY_TIMEOUT; continue; } if (sr >= 0) break; if (errno == EINTR) continue; else abort_bbs(0); } if ((sr == 0) && (!i_top)) abort_bbs(0); if (sr == 0) return I_TIMEOUT; if (FD_ISSET(0, &xds)) abort_bbs(0); } if (hasaddio && (i_newfd && FD_ISSET(i_newfd, &readfds))) return I_OTHERDATA; #ifdef SSHBBS while ((ibufsize = ssh_read(0, inbuffer + 1, IBUFSIZE)) <= 0) #else while ((ibufsize = read(0, inbuffer + 1, IBUFSIZE)) <= 0) #endif { if (ibufsize == 0) longjmp(byebye, -1); if (ibufsize < 0 && errno != EINTR) longjmp(byebye, -1); } if (!filter_telnet(inbuffer + 1, &ibufsize)) { icurrchar = 0; ibufsize = 0; goto igetagain; } /* * add by KCN for GB/BIG5 encode */ if (convcode) { inbuf = big2gb(inbuffer + 1, &ibufsize, 0, getSession()); if (ibufsize == 0) { icurrchar = 0; goto igetagain; } } else inbuf = inbuffer + 1; /* * end */ icurrchar = 0; if (ibufsize > IBUFSIZE) { ibufsize = 0; goto igetagain; } } if (icurrchar >= ibufsize) { ibufsize = icurrchar; goto igetagain; } if (((inbuf[icurrchar] == '\n') && (lastch == '\r')) || ((inbuf[icurrchar] == '\r') && (lastch == '\n'))) { lastch = 0; goto igetagain; } else if (icurrchar != ibufsize) { if (((inbuf[icurrchar] == '\n') && (inbuf[icurrchar + 1] == '\r')) || ((inbuf[icurrchar] == '\r') && (inbuf[icurrchar + 1] == '\n'))) { icurrchar++; lastch = 0; } } else lastch = inbuf[icurrchar]; idle_count = 0; c = inbuf[icurrchar]; switch (c) { case Ctrl('@'): case Ctrl('L'): redoscr(); icurrchar++; now = time(0); uinfo.freshtime = now; if (now - old > 60) { UPDATE_UTMP(freshtime, uinfo); old = now; } goto igetagain; case Ctrl('Z'): if (scrint&&uinfo.mode!=LOCKSCREEN&&uinfo.mode!=NEW&&uinfo.mode!=LOGIN&&uinfo.mode!=BBSNET &&uinfo.mode!=WINMINE&&!inremsg) { icurrchar++; inremsg = true; r_msg(); inremsg = false; goto igetagain; } break; default: break; } icurrchar++; while ((icurrchar != ibufsize) && (inbuf[icurrchar] == 0)) icurrchar++; now = time(0); if (Ctrl('T') != c) uinfo.freshtime = now; /* * add by KCN , decrease temp_numposts */ if (lasttime + 60 * 60 * 8 < now) { lasttime = now; if (temp_numposts > 0) temp_numposts--; } if (now - old > 60) { UPDATE_UTMP(freshtime, uinfo); old = now; } return c; }