Ejemplo n.º 1
0
static ssh_channel channel_open_request_cb(ssh_session session, void *userdata)
{
	struct tmate_ssh_client *client = userdata;

	if (!client->username) {
		/* The authentication did not go through yet */
		return NULL;
	}

	if (client->channel) {
		/*
		 * We already have a channel, and we don't support multi
		 * channels yet. Returning NULL means the channel request will
		 * be denied.
		 */
		return NULL;
	}

	client->channel = ssh_channel_new(session);
	if (!client->channel)
		tmate_fatal("Error getting channel");

	memset(&client->channel_cb, 0, sizeof(client->channel_cb));
	ssh_callbacks_init(&client->channel_cb);
	client->channel_cb.userdata = client;
	client->channel_cb.channel_pty_request_function = pty_request;
	client->channel_cb.channel_shell_request_function = shell_request;
	client->channel_cb.channel_subsystem_request_function = subsystem_request;
	client->channel_cb.channel_exec_request_function = exec_request;
	ssh_set_channel_callbacks(client->channel, &client->channel_cb);

	return client->channel;
}
Ejemplo n.º 2
0
static ssh_channel pkd_channel_openreq_cb(ssh_session s,
                                          void *userdata) {
    ssh_channel c = NULL;
    ssh_channel *out = (ssh_channel *) userdata;

    /* assumes pubkey authentication has already succeeded */
    pkdout("pkd_channel_openreq_cb\n");

    c = ssh_channel_new(s);
    if (c == NULL) {
        pkderr("ssh_channel_new: %s\n", ssh_get_error(s));
        return NULL;
    }

    ssh_callbacks_init(&pkd_channel_cb);
    pkd_channel_cb.userdata = userdata;
    if (ssh_set_channel_callbacks(c, &pkd_channel_cb) != SSH_OK) {
        pkderr("ssh_set_channel_callbacks: %s\n", ssh_get_error(s));
        ssh_channel_free(c);
        c = NULL;
    }

    *out = c;

    return c;
}
Ejemplo n.º 3
0
static int message_callback(ssh_session session, ssh_message message, void *userdata) {
    ssh_channel channel;
    int socket_fd, *pFd;
    struct ssh_channel_callbacks_struct *cb_chan;
    struct event_fd_data_struct *event_fd_data;
    (void)session;
    (void)message;
    (void)userdata;

    _ssh_log(SSH_LOG_PACKET, "=== message_callback", "Message type: %d", ssh_message_type(message));
    _ssh_log(SSH_LOG_PACKET, "=== message_callback", "Message Subtype: %d", ssh_message_subtype(message));
    if (ssh_message_type(message) == SSH_REQUEST_CHANNEL_OPEN) {
        _ssh_log(SSH_LOG_PROTOCOL, "=== message_callback", "channel_request_open");

        if (ssh_message_subtype(message) == SSH_CHANNEL_DIRECT_TCPIP) {
            channel = ssh_message_channel_request_open_reply_accept(message);

            if (channel == NULL) {
                _ssh_log(SSH_LOG_WARNING, "=== message_callback", "Accepting direct-tcpip channel failed!");
                return 1;
            }
            else {
                _ssh_log(SSH_LOG_PROTOCOL, "=== message_callback", "Connected to channel!");

                socket_fd = open_tcp_socket(message);
                if (-1 == socket_fd) {
                    return 1;
                }

                pFd = malloc(sizeof *pFd);
                cb_chan = malloc(sizeof *cb_chan);
                event_fd_data = malloc(sizeof *event_fd_data);

                (*pFd) = socket_fd;
                event_fd_data->channel = channel;
                event_fd_data->p_fd = pFd;
                event_fd_data->stacked = 0;
                event_fd_data->cb_chan = cb_chan;

                cb_chan->userdata = event_fd_data;
                cb_chan->channel_eof_function = my_channel_eof_function;
                cb_chan->channel_close_function = my_channel_close_function;
                cb_chan->channel_data_function = my_channel_data_function;
                cb_chan->channel_exit_status_function = my_channel_exit_status_function;

                ssh_callbacks_init(cb_chan);
                ssh_set_channel_callbacks(channel, cb_chan);

                ssh_event_add_fd(mainloop, (socket_t)*pFd, POLLIN, my_fd_data_function, event_fd_data);

                return 0;
            }
        }
    }
    return 1;
}
Ejemplo n.º 4
0
static ssh_channel new_session_channel(ssh_session session, void *userdata){
    (void) session;
    (void) userdata;
    if(chan != NULL)
        return NULL;
    printf("Allocated session channel\n");
    chan = ssh_channel_new(session);
    ssh_callbacks_init(&channel_cb);
    ssh_set_channel_callbacks(chan, &channel_cb);
    return chan;
}
Ejemplo n.º 5
0
static ssh_channel channel_open(ssh_session session, void *userdata) {
    ssh_channel channel = NULL;
    ssh_channel_callbacks channel_cb = userdata;

    /* unused */
    (void)userdata;

    channel = ssh_channel_new(session);
    if (channel == NULL) {
        goto out;
    }
    ssh_set_channel_callbacks(channel, channel_cb);

 out:
    return channel;
}
Ejemplo n.º 6
0
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;
}
Ejemplo n.º 7
0
static ssh_channel new_session_channel( ssh_session session, void *userdata )
{
	SSHSession *s = (SSHSession *)userdata;
	(void) session;
	
	if( s->sshs_Chan != NULL)
	{
		ERROR("New session channel\n");
		return NULL;
	}
	printf("Allocated session channel\n");
	s->sshs_Chan = ssh_channel_new( session );
	ssh_callbacks_init( &channel_cb );
	ssh_set_channel_callbacks( s->sshs_Chan, &channel_cb );
	
	return s->sshs_Chan;
}
Ejemplo n.º 8
0
static int
do_shell (ssh_event event,
          ssh_channel chan)
{
  socket_t fd;
  struct termios *term = NULL;
  struct winsize *win = NULL;
  short events;
  int fd_status;

  state.childpid = forkpty (&fd, NULL, term, win);
  if (state.childpid == 0)
    {
      close (state.bind_fd);
      close (state.session_fd);
      execl ("/bin/bash", "/bin/bash", NULL);
      _exit (127);
    }
  else if (state.childpid < 0)
    {
      g_critical ("forkpty failed: %s", g_strerror (errno));
      return -1;
    }

  fd_status = fcntl (fd, F_GETFL, 0);
  if (fcntl (fd, F_SETFL, fd_status | O_NONBLOCK) < 0)
    {
      g_critical ("couldn't set non-blocking mode");
      return -1;
    }

  cb.userdata = (gpointer)(long)fd;
  ssh_callbacks_init(&cb);
  ssh_set_channel_callbacks (chan, &cb);

  events = POLLIN | POLLOUT | POLLPRI | POLLERR | POLLHUP | POLLNVAL;
  if (ssh_event_add_fd (event, fd, events, fd_data, chan) != SSH_OK)
    g_return_val_if_reached(-1);

  return 0;
}
Ejemplo n.º 9
0
static int
do_exec (ssh_event event,
         ssh_channel chan,
         const gchar *cmd)
{
  socket_t fd;
  short events;

  fd = fork_exec (cmd);
  if (fd < 0)
    return -1;

  cb.userdata = GINT_TO_POINTER (fd);
  ssh_callbacks_init(&cb);
  ssh_set_channel_callbacks (chan, &cb);

  events = POLLIN | POLLOUT | POLLPRI | POLLERR | POLLHUP | POLLNVAL;
  if (ssh_event_add_fd (event, fd, events, fd_data, chan) != SSH_OK)
    g_return_val_if_reached(-1);

  return 0;
}
Ejemplo n.º 10
0
void tmate_client_pty_init(struct tmate_session *session)
{
	struct tmate_ssh_client *client = &session->ssh_client;

	ioctl(session->pty, TIOCSWINSZ, &session->ssh_client.winsize_pty);

	memset(&client->channel_cb, 0, sizeof(client->channel_cb));
	ssh_callbacks_init(&client->channel_cb);
	client->channel_cb.userdata = session;
	client->channel_cb.channel_data_function = on_ssh_channel_read,
	ssh_set_channel_callbacks(client->channel, &client->channel_cb);

	ssh_set_message_callback(session->ssh_client.session,
				 on_ssh_message_callback, session);

	setblocking(session->pty, 0);
	event_set(&session->ev_pty, session->pty,
		  EV_READ | EV_PERSIST, __on_pty_event, session);
	event_add(&session->ev_pty, NULL);

	tmate_add_ssh_latency_callback(client, on_latency_callback, session);
}
Ejemplo n.º 11
0
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);
}
Ejemplo n.º 12
0
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;
}
Ejemplo n.º 13
0
int set_channel_callbacks(ssh_channel channel, ssh_channel_callbacks callbacks) {
	ssh_callbacks_init(callbacks);
	return ssh_set_channel_callbacks(channel, callbacks);
}