static void cockpit_ssh_transport_constructed (GObject *object) { CockpitSshTransport *self = COCKPIT_SSH_TRANSPORT (object); CockpitSshData *data; static GSourceFuncs source_funcs = { cockpit_ssh_source_prepare, cockpit_ssh_source_check, cockpit_ssh_source_dispatch, NULL, }; G_OBJECT_CLASS (cockpit_ssh_transport_parent_class)->constructed (object); g_return_if_fail (self->data->creds != NULL); g_warn_if_fail (ssh_options_set (self->data->session, SSH_OPTIONS_USER, cockpit_creds_get_user (self->data->creds)) == 0); self->io = g_source_new (&source_funcs, sizeof (CockpitSshSource)); ((CockpitSshSource *)self->io)->transport = self; g_source_attach (self->io, self->data->context); /* Setup for connect thread */ self->connect_fd = ssh_get_fd (self->data->session); g_atomic_int_set (&self->connecting, 1); self->data->connecting = &self->connecting; data = self->data; self->data = NULL; self->connect_thread = g_thread_new ("ssh-transport-connect", cockpit_ssh_connect_thread, data); g_debug ("%s: constructed", self->logname); }
// get the ip static int *get_client_ip(struct connection *c) { struct sockaddr_storage tmp; struct sockaddr_in *sock; unsigned int len = MAXBUF; getpeername(ssh_get_fd(c->session), (struct sockaddr*)&tmp, &len); sock = (struct sockaddr_in *)&tmp; inet_ntop(AF_INET, &sock->sin_addr, c->client_ip, len); return 0; }
static void torture_channel_read_error(void **state) { ssh_session session = *state; char *user = getenv("TORTURE_USER"); ssh_channel channel; int rc; int i; if (user == NULL) { print_message("*** Please set the environment variable TORTURE_USER" " to enable this test!!\n"); return; } rc = ssh_options_set(session, SSH_OPTIONS_USER, user); assert_true(rc == SSH_OK); rc = ssh_connect(session); assert_true(rc == SSH_OK); rc = ssh_userauth_none(session,NULL); /* This request should return a SSH_REQUEST_DENIED error */ if (rc == SSH_ERROR) { assert_true(ssh_get_error_code(session) == SSH_REQUEST_DENIED); } assert_true(ssh_auth_list(session) & SSH_AUTH_METHOD_PUBLICKEY); rc = ssh_userauth_autopubkey(session, NULL); assert_true(rc == SSH_AUTH_SUCCESS); channel = ssh_channel_new(session); assert_true(channel != NULL); rc = ssh_channel_open_session(channel); assert_true(rc == SSH_OK); rc = ssh_channel_request_exec(channel, "hexdump -C /dev/urandom"); assert_true(rc == SSH_OK); /* send crap and for server to send us a disconnect */ rc = write(ssh_get_fd(session),"AAAA", 4); assert_int_equal(rc, 4); for (i=0;i<20;++i){ rc = ssh_channel_read(channel,buffer,sizeof(buffer),0); if (rc == SSH_ERROR) break; } assert_true(rc == SSH_ERROR); }
void tmate_ssh_server_main(struct tmate_session *session, const char *keys_dir, int port) { sigset_t sigchld_set; struct tmate_ssh_client *client = &session->ssh_client; ssh_bind bind; pid_t pid; signal(SIGSEGV, handle_sigsegv); signal(SIGCHLD, handle_sigchld); sigemptyset(&sigchld_set); sigaddset(&sigchld_set, SIGCHLD); sigprocmask(SIG_BLOCK, &sigchld_set, NULL); bind = prepare_ssh(keys_dir, port); for (;;) { client->session = ssh_new(); client->channel = NULL; client->winsize_pty.ws_col = 80; client->winsize_pty.ws_row = 24; if (!client->session) tmate_fatal("Cannot initialize session"); sigprocmask(SIG_UNBLOCK, &sigchld_set, NULL); if (ssh_bind_accept(bind, client->session) < 0) tmate_fatal("Error accepting connection: %s", ssh_get_error(bind)); sigprocmask(SIG_BLOCK, &sigchld_set, NULL); if (get_ip(ssh_get_fd(client->session), client->ip_address, sizeof(client->ip_address)) < 0) tmate_fatal("Error getting IP address from connection"); if ((pid = fork()) < 0) tmate_fatal("Can't fork"); if (pid) { tmate_info("Child spawned pid=%d, ip=%s", pid, client->ip_address); ssh_free(client->session); } else { ssh_bind_free(bind); session->session_token = "init"; client_bootstrap(session); } } }
/** * @brief Remove a session object from an event context. * * @param event The ssh_event object. * @param session The session to remove. * * @returns SSH_OK on success * SSH_ERROR on failure */ int ssh_event_remove_session(ssh_event event, ssh_session session) { ssh_poll_handle p; register size_t i, used; int rc = SSH_ERROR; socket_t session_fd; #ifdef WITH_SERVER struct ssh_iterator *iterator; #endif if(event == NULL || event->ctx == NULL || session == NULL) { return SSH_ERROR; } session_fd = ssh_get_fd(session); used = event->ctx->polls_used; for(i = 0; i < used; i++) { if(session_fd == event->ctx->pollfds[i].fd) { p = event->ctx->pollptrs[i]; ssh_poll_ctx_remove(event->ctx, p); ssh_poll_ctx_add(session->default_poll_ctx, p); rc = SSH_OK; } } #ifdef WITH_SERVER iterator = ssh_list_get_iterator(event->sessions); while(iterator != NULL) { if((ssh_session)iterator->data == session) { ssh_list_remove(event->sessions, iterator); /* there should be only one instance of this session */ break; } iterator = iterator->next; } #endif return rc; }
static void torture_channel_read_error(void **state) { struct torture_state *s = *state; ssh_session session = s->ssh.session; ssh_channel channel; int rc; int fd; int i; channel = ssh_channel_new(session); assert_non_null(channel); rc = ssh_channel_open_session(channel); assert_ssh_return_code(session, rc); rc = ssh_channel_request_exec(channel, "hexdump -C /dev/urandom"); assert_ssh_return_code(session, rc); /* send crap and for server to send us a disconnect */ fd = ssh_get_fd(session); assert_true(fd > 2); rc = write(fd, "AAAA", 4); assert_int_equal(rc, 4); for (i=0;i<20;++i){ rc = ssh_channel_read(channel,buffer,sizeof(buffer),0); if (rc == SSH_ERROR) break; } #if OPENSSH_VERSION_MAJOR == 6 && OPENSSH_VERSION_MINOR >= 7 /* With openssh 6.7 this doesn't produce and error anymore */ assert_ssh_return_code(session, rc); #else assert_ssh_return_code_equal(session, rc, SSH_ERROR); #endif ssh_channel_free(channel); }
static gboolean cockpit_ssh_source_prepare (GSource *source, gint *timeout) { CockpitSshSource *cs = (CockpitSshSource *)source; CockpitSshTransport *self = cs->transport; GThread *thread; gint status; *timeout = 1; /* Connecting, check if done */ if (G_UNLIKELY (!self->data)) { if (g_atomic_int_get (&self->connecting)) return FALSE; g_object_ref (self); /* Get the result from connecting thread */ thread = self->connect_thread; self->connect_fd = -1; self->connect_thread = NULL; self->data = g_thread_join (thread); g_assert (self->data != NULL); if (!self->result_emitted) { self->result_emitted = TRUE; g_signal_emit_by_name (self, "result", self->data->problem); } if (self->data->problem) { close_immediately (self, self->data->problem); g_object_unref (self); return FALSE; } g_object_unref (self); ssh_event_add_session (self->event, self->data->session); ssh_set_channel_callbacks (self->data->channel, &self->channel_cbs); /* Start watching the fd */ ssh_set_blocking (self->data->session, 0); cs->pfd.fd = ssh_get_fd (self->data->session); g_source_add_poll (source, &cs->pfd); g_debug ("%s: starting io", self->logname); } status = ssh_get_status (self->data->session); /* Short cut this ... we're ready now */ if (self->drain_buffer) return TRUE; /* * Channel completely closed, and output buffers * are empty. We're in a good place to close the * SSH session and thus the transport. */ if (close_maybe (self, status)) return FALSE; cs->pfd.revents = 0; cs->pfd.events = G_IO_IN | G_IO_ERR | G_IO_NVAL | G_IO_HUP; /* libssh has something in its buffer: want to write */ if (status & SSH_WRITE_PENDING) cs->pfd.events |= G_IO_OUT; /* We have something in our queue: want to write */ else if (!g_queue_is_empty (self->queue)) cs->pfd.events |= G_IO_OUT; /* We are closing and need to send eof: want to write */ else if (self->closing && !self->sent_eof) cs->pfd.events |= G_IO_OUT; /* Need to reply to an EOF or close */ if ((self->received_eof && self->sent_eof && !self->sent_close) || (self->received_close && !self->sent_close)) cs->pfd.events |= G_IO_OUT; return cockpit_ssh_source_check (source); }
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 gint mock_ssh_server (const gchar *server_addr, gint server_port, const gchar *user, const gchar *password, gboolean multi_step) { char portname[16]; char addrname[16]; struct sockaddr_storage addr; socklen_t addrlen; ssh_bind sshbind; const char *msg; int r; gint rounds = 0; state.event = ssh_event_new (); if (state.event == NULL) g_return_val_if_reached (-1); sshbind = ssh_bind_new (); state.session = ssh_new (); if (server_addr == NULL) server_addr = "127.0.0.1"; ssh_bind_options_set (sshbind, SSH_BIND_OPTIONS_BINDADDR, server_addr); ssh_bind_options_set (sshbind, SSH_BIND_OPTIONS_BINDPORT, &server_port); ssh_bind_options_set (sshbind, SSH_BIND_OPTIONS_RSAKEY, SRCDIR "/src/ws/mock_rsa_key"); ssh_bind_options_set (sshbind, SSH_BIND_OPTIONS_DSAKEY, SRCDIR "/src/ws/mock_dsa_key"); if (ssh_bind_listen (sshbind) < 0) { g_critical ("couldn't listen on socket: %s", ssh_get_error (sshbind)); return 1; } state.bind_fd = ssh_bind_get_fd (sshbind); state.user = user; state.password = password; state.multi_step = multi_step; ssh_pki_import_pubkey_file (SRCDIR "/src/ws/test_rsa.pub", &state.pkey); state.buffer = g_byte_array_new (); /* Print out the port */ if (server_port == 0) { addrlen = sizeof (addr); if (getsockname (state.bind_fd, (struct sockaddr *)&addr, &addrlen) < 0) { g_critical ("couldn't get local address: %s", g_strerror (errno)); return 1; } r = getnameinfo ((struct sockaddr *)&addr, addrlen, addrname, sizeof (addrname), portname, sizeof (portname), NI_NUMERICHOST | NI_NUMERICSERV); if (r != 0) { g_critical ("couldn't get local port: %s", gai_strerror (r)); return 1; } /* Caller wants to know the port */ g_print ("%s\n", portname); } /* Close stdout (once above info is printed) */ close (1); ssh_set_message_callback (state.session, authenticate_callback, &rounds); r = ssh_bind_accept (sshbind, state.session); if (r == SSH_ERROR) { g_critical ("accepting connection failed: %s", ssh_get_error (sshbind)); return 1; } state.session_fd = ssh_get_fd (state.session); if (ssh_handle_key_exchange (state.session)) { msg = ssh_get_error (state.session); if (!strstr (msg, "_DISCONNECT")) g_critical ("key exchange failed: %s", msg); return 1; } if (ssh_event_add_session (state.event, state.session) != SSH_OK) g_return_val_if_reached (-1); do { ssh_event_dopoll (state.event, 10000); } while (ssh_is_connected (state.session)); ssh_event_remove_session (state.event, state.session); ssh_event_free (state.event); ssh_free (state.session); ssh_key_free (state.pkey); g_byte_array_free (state.buffer, TRUE); ssh_bind_free (sshbind); return 0; }
void select_loop(SSH_SESSION *session,CHANNEL *channel){ fd_set fds; struct timeval timeout; char buffer[10]; BUFFER *readbuf=buffer_new(); 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,10); if(lus) channel_write(channel,buffer,lus); else { eof=1; 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=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 && channel_is_closed(channel)){ channel_free(channel); channel=NULL; channels[0]=NULL; } if(channels[0]){ while(channel && channel_is_open(channel) && channel_poll(channel,0)){ lus=channel_read(channel,readbuf,0,0); if(lus==-1){ ssh_say(0,"error reading channel : %s\n",ssh_get_error(session)); return; } if(lus==0){ ssh_say(1,"EOF received\n"); channel_free(channel); channel=channels[0]=NULL; } else write(1,buffer_get(readbuf),lus); } while(channel && channel_is_open(channel) && channel_poll(channel,1)){ /* stderr */ lus=channel_read(channel,readbuf,0,1); if(lus==-1){ ssh_say(0,"error reading channel : %s\n",ssh_get_error(session)); return; } if(lus==0){ ssh_say(1,"EOF received\n"); channel_free(channel); channel=channels[0]=NULL; } else write(2,buffer_get(readbuf),lus); } } if(channel && channel_is_closed(channel)){ channel_free(channel); channel=NULL; } } buffer_free(readbuf); }
static void client_bootstrap(struct tmate_session *_session) { struct tmate_ssh_client *client = &_session->ssh_client; int grace_period = TMATE_SSH_GRACE_PERIOD; ssh_event mainloop; ssh_session session = client->session; tmate_notice("Bootstrapping ssh client ip=%s", client->ip_address); _session->ev_base = osdep_event_init(); /* new process group, we don't want to die with our parent (upstart) */ setpgid(0, 0); { int flag = 1; setsockopt(ssh_get_fd(session), IPPROTO_TCP, TCP_NODELAY, &flag, sizeof(flag)); } signal(SIGALRM, handle_sigalrm); alarm(grace_period); /* * We should die early if we can't connect to proxy. This way the * tmate daemon will pick another server to work on. */ _session->proxy_fd = -1; if (tmate_has_proxy()) _session->proxy_fd = tmate_connect_to_proxy(); ssh_server_cb.userdata = client; ssh_callbacks_init(&ssh_server_cb); ssh_set_server_callbacks(client->session, &ssh_server_cb); ssh_options_set(session, SSH_OPTIONS_TIMEOUT, &grace_period); ssh_options_set(session, SSH_OPTIONS_COMPRESSION, "yes"); ssh_set_auth_methods(client->session, SSH_AUTH_METHOD_PUBLICKEY); tmate_info("Exchanging DH keys"); if (ssh_handle_key_exchange(session) < 0) tmate_fatal("Error doing the key exchange: %s", ssh_get_error(session)); mainloop = ssh_event_new(); ssh_event_add_session(mainloop, session); while (!client->role) { if (ssh_event_dopoll(mainloop, -1) == SSH_ERROR) tmate_fatal("Error polling ssh socket: %s", ssh_get_error(session)); } alarm(0); /* The latency is callback set later */ tmate_start_ssh_latency_probes(client, &ssh_server_cb, TMATE_SSH_KEEPALIVE * 1000); register_on_ssh_read(client); tmate_spawn(_session); /* never reached */ }
static void register_on_ssh_read(struct tmate_ssh_client *client) { event_set(&client->ev_ssh, ssh_get_fd(client->session), EV_READ | EV_PERSIST, on_ssh_read, client); event_add(&client->ev_ssh, NULL); }