Пример #1
0
static void on_pty_event(struct tmate_session *session)
{
	ssize_t len, written;
	char buf[4096];

	for (;;) {
		len = read(session->pty, buf, sizeof(buf));
		if (len < 0) {
			if (errno == EAGAIN)
				return;
			tmate_fatal("pty read error");
		}

		if (len == 0)
			tmate_fatal("pty reached EOF");

		written = ssh_channel_write(session->ssh_client.channel, buf, len);
		if (written < 0)
			tmate_fatal("Error writing to channel: %s",
				    ssh_get_error(session->ssh_client.session));
		if (len != written)
			tmate_fatal("Cannot write %d bytes, wrote %d",
				    (int)len, (int)written);
	}
}
Пример #2
0
static ssh_bind prepare_ssh(const char *keys_dir, int port)
{
	ssh_bind bind;
	char buffer[PATH_MAX];
	int verbosity = SSH_LOG_NOLOG;

	ssh_set_log_callback(ssh_log_function);

	bind = ssh_bind_new();
	if (!bind)
		tmate_fatal("Cannot initialize ssh");

	ssh_bind_options_set(bind, SSH_BIND_OPTIONS_BINDPORT, &port);
	ssh_bind_options_set(bind, SSH_BIND_OPTIONS_BANNER, TMATE_SSH_BANNER);
	ssh_bind_options_set(bind, SSH_BIND_OPTIONS_LOG_VERBOSITY, &verbosity);

	sprintf(buffer, "%s/ssh_host_rsa_key", keys_dir);
	ssh_bind_options_set(bind, SSH_BIND_OPTIONS_RSAKEY, buffer);

	sprintf(buffer, "%s/ssh_host_ecdsa_key", keys_dir);
	ssh_bind_options_set(bind, SSH_BIND_OPTIONS_ECDSAKEY, buffer);

	if (ssh_bind_listen(bind) < 0)
		tmate_fatal("Error listening to socket: %s\n", ssh_get_error(bind));

	tmate_notice("Accepting connections on %d", port);

	return bind;
}
Пример #3
0
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);
		}
	}
}
Пример #4
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;
}
Пример #5
0
static void handle_sigsegv(__unused int sig)
{
	/* TODO send stack trace to server */
	tmate_info("CRASH, printing stack trace");
	tmate_print_stack_trace();
	tmate_fatal("CRASHED");
}
Пример #6
0
static int on_ssh_channel_read(__unused ssh_session _session,
			       __unused ssh_channel channel,
			       void *_data, uint32_t total_len,
			       __unused int is_stderr, void *userdata)
{
	struct tmate_session *session = userdata;
	char *data = _data;
	size_t written = 0;
	ssize_t len;

	if (session->readonly)
		return total_len;

	setblocking(session->pty, 1);
	while (total_len) {
		len = write(session->pty, data, total_len);
		if (len < 0)
			tmate_fatal("Error writing to pty");

		total_len -= len;
		written += len;
		data += len;
	}
	setblocking(session->pty, 0);

	return written;
}
Пример #7
0
void tmate_decoder_init(struct tmate_decoder *decoder, tmate_decoder_reader *reader,
			void *userdata)
{
	if (!msgpack_unpacker_init(&decoder->unpacker, UNPACKER_RESERVE_SIZE))
		tmate_fatal("Cannot initialize the unpacker");
	decoder->reader = reader;
	decoder->userdata = userdata;
}
Пример #8
0
void tmate_decoder_get_buffer(struct tmate_decoder *decoder,
			      char **buf, size_t *len)
{
	if (!msgpack_unpacker_reserve_buffer(&decoder->unpacker, UNPACKER_RESERVE_SIZE))
		tmate_fatal("cannot expand decoder buffer");

	*buf = msgpack_unpacker_buffer(&decoder->unpacker);
	*len = msgpack_unpacker_buffer_capacity(&decoder->unpacker);
}
Пример #9
0
static int check_authorized_keys(struct ssh_key_struct *client_pubkey) {
	#define MAX_PUBKEY_SIZE 0x4000

	const char *authorized_keys_path = tmate_settings->authorized_keys_path;
	const char *token_delim = " ";

	FILE *file;
	char key_buf[MAX_PUBKEY_SIZE], *key_type, *key_content;
	enum ssh_keytypes_e type;
	ssh_key pkey;

	if (authorized_keys_path == NULL)
		return SSH_AUTH_SUCCESS;

	file = fopen(authorized_keys_path, "rb");
	if (file == NULL) {
		tmate_fatal("Could not open authorized_keys file: \"%s\"", authorized_keys_path);
		return SSH_AUTH_DENIED;
	}

	while (fgets(key_buf, MAX_PUBKEY_SIZE, file)) {
		if (key_buf[0] == '#' || key_buf[0] == '\0')
			continue;

		key_type = strtok(key_buf, token_delim);
		if (key_type == NULL)
			continue;

		type = ssh_key_type_from_name(key_type);
		if (type == SSH_KEYTYPE_UNKNOWN)
			continue;

		key_content = strtok(NULL, token_delim);
		if (key_content == NULL)
			continue;

		pkey = ssh_key_new();
		if (ssh_pki_import_pubkey_base64(key_content, type, &pkey) != SSH_OK) {
			ssh_key_free(pkey);
			continue;
		}

		if (!ssh_key_cmp(pkey, client_pubkey, SSH_KEY_CMP_PUBLIC)) {
			ssh_key_free(pkey);
			fclose(file);
			return SSH_AUTH_SUCCESS;
		}

		ssh_key_free(pkey);
	}

	fclose(file);
	return SSH_AUTH_DENIED;
}
Пример #10
0
static int on_encoder_write(void *userdata, const char *buf, size_t len)
{
	struct tmate_encoder *encoder = userdata;

	if (evbuffer_add(encoder->buffer, buf, len) < 0)
		tmate_fatal("Cannot buffer encoded data");

	if (!encoder->ev_active) {
		event_active(&encoder->ev_buffer, EV_READ, 0);
		encoder->ev_active = true;
	}

	return 0;
}
Пример #11
0
static ssh_bind prepare_ssh(const char *keys_dir, const char *bind_addr, int port)
{
	ssh_bind bind;
	char buffer[PATH_MAX];
	int ssh_log_level;
	ssh_key rsakey = NULL;
	ssh_key ed25519key = NULL;

	ssh_log_level = SSH_LOG_WARNING + max(log_get_level() - LOG_NOTICE, 0);

	ssh_set_log_callback(ssh_log_function);

	bind = ssh_bind_new();
	if (!bind)
		tmate_fatal("Cannot initialize ssh");

	if (bind_addr)
		ssh_bind_options_set(bind, SSH_BIND_OPTIONS_BINDADDR, bind_addr);
	ssh_bind_options_set(bind, SSH_BIND_OPTIONS_BINDPORT, &port);
	ssh_bind_options_set(bind, SSH_BIND_OPTIONS_BANNER, TMATE_SSH_BANNER);
	ssh_bind_options_set(bind, SSH_BIND_OPTIONS_LOG_VERBOSITY, &ssh_log_level);

	sprintf(buffer, "%s/ssh_host_rsa_key", keys_dir);
	ssh_pki_import_privkey_file(buffer, NULL, NULL, NULL, &rsakey);
	ssh_bind_options_set(bind, SSH_BIND_OPTIONS_IMPORT_KEY, rsakey);

	sprintf(buffer, "%s/ssh_host_ed25519_key", keys_dir);
	ssh_pki_import_privkey_file(buffer, NULL, NULL, NULL, &ed25519key);
	ssh_bind_options_set(bind, SSH_BIND_OPTIONS_IMPORT_KEY, ed25519key);

	if (ssh_bind_listen(bind) < 0)
		tmate_fatal("Error listening to socket: %s\n", ssh_get_error(bind));

	tmate_notice("Accepting connections on %s:%d", bind_addr ?: "", port);

	return bind;
}
Пример #12
0
void tmate_decoder_commit(struct tmate_decoder *decoder, size_t len)
{
	msgpack_unpacked result;

	msgpack_unpacker_buffer_consumed(&decoder->unpacker, len);

	msgpack_unpacked_init(&result);
	while (msgpack_unpacker_next(&decoder->unpacker, &result)) {
		handle_message(decoder, result.data);
	}
	msgpack_unpacked_destroy(&result);

	if (msgpack_unpacker_message_size(&decoder->unpacker) >
						TMATE_MAX_MESSAGE_SIZE) {
		tmate_fatal("Message too big");
	}
}
Пример #13
0
static void lookup_and_connect(void)
{
	struct evutil_addrinfo hints;

	if (!ev_dnsbase)
		ev_dnsbase = evdns_base_new(ev_base, 1);
	if (!ev_dnsbase)
		tmate_fatal("Cannot initialize the DNS lookup service");

	memset(&hints, 0, sizeof(hints));
	hints.ai_family = AF_UNSPEC;
	hints.ai_flags = 0;
	hints.ai_socktype = SOCK_STREAM;
	hints.ai_protocol = IPPROTO_TCP;

	tmate_info("Looking up %s...", TMATE_HOST);
	(void)evdns_getaddrinfo(ev_dnsbase, TMATE_HOST, NULL,
				&hints, dns_cb, NULL);
}
Пример #14
0
void tmate_encoder_init(struct tmate_encoder *encoder,
			tmate_encoder_write_cb *callback,
			void *userdata)
{
	msgpack_packer_init(&encoder->pk, encoder, &on_encoder_write);
	encoder->buffer = evbuffer_new();
	encoder->ready_callback = callback;
	encoder->userdata = userdata;

	if (!encoder->buffer)
		tmate_fatal("Can't allocate buffer");

	event_set(&encoder->ev_buffer, -1,
		  EV_READ | EV_PERSIST, on_encoder_buffer_ready, encoder);

	event_add(&encoder->ev_buffer, NULL);

	encoder->ev_active = false;
}
Пример #15
0
static int auth_pubkey_cb(__unused ssh_session session,
			  const char *user,
			  struct ssh_key_struct *pubkey,
			  char signature_state, void *userdata)
{
	struct tmate_ssh_client *client = userdata;

	switch (signature_state) {
	case SSH_PUBLICKEY_STATE_VALID:
		client->username = xstrdup(user);
		if (ssh_pki_export_pubkey_base64(pubkey, &client->pubkey) != SSH_OK)
			tmate_fatal("error getting public key");

		return check_authorized_keys(pubkey);
	case SSH_PUBLICKEY_STATE_NONE:
		return SSH_AUTH_SUCCESS;
	default:
		return SSH_AUTH_DENIED;
	}
}
Пример #16
0
static void lookup_and_connect(void)
{
	struct evutil_addrinfo hints;
	const char *tmate_server_host;

	if (!tmate_session.ev_dnsbase)
		tmate_session.ev_dnsbase = evdns_base_new(tmate_session.ev_base, 1);
	if (!tmate_session.ev_dnsbase)
		tmate_fatal("Cannot initialize the DNS lookup service");

	memset(&hints, 0, sizeof(hints));
	hints.ai_family = AF_UNSPEC;
	hints.ai_flags = EVUTIL_AI_ADDRCONFIG;
	hints.ai_socktype = SOCK_STREAM;
	hints.ai_protocol = IPPROTO_TCP;

	tmate_server_host = options_get_string(global_options,
					       "tmate-server-host");
	tmate_info("Looking up %s...", tmate_server_host);
	(void)evdns_getaddrinfo(tmate_session.ev_dnsbase, tmate_server_host, NULL,
				&hints, dns_cb, (void *)tmate_server_host);
}
Пример #17
0
void tmate_decoder_init(struct tmate_decoder *decoder)
{
	if (!msgpack_unpacker_init(&decoder->unpacker, 2*TMATE_MAX_MESSAGE_SIZE))
		tmate_fatal("cannot initialize the unpacker");
	decoder->ready = 0;
}
Пример #18
0
void tmate_decoder_error(void)
{
	/* TODO Don't kill the session, disconnect */
	tmate_print_stack_trace();
	tmate_fatal("Received a bad message");
}
Пример #19
0
static void decoder_error(void)
{
	/* TODO Don't kill the session, disconnect */
	tmate_fatal("Received a bad message");
}
Пример #20
0
static void handle_sigalrm(__unused int sig)
{
	tmate_fatal("Connection grace period (%d) passed", TMATE_SSH_GRACE_PERIOD);
}
Пример #21
0
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 */
}
Пример #22
0
static void handle_sigsegv(__unused int sig)
{
	tmate_info("CRASH, printing stack trace");
	tmate_print_stack_trace();
	tmate_fatal("CRASHED");
}