mirror of
https://github.com/tmate-io/tmate-ssh-server.git
synced 2020-11-18 19:53:51 -08:00
Jail in place
Still missing the network isolation. Maybe a iptable filtered by uid would work.
This commit is contained in:
parent
31b5c08472
commit
3ee065ce52
5
server.c
5
server.c
@ -84,12 +84,7 @@ server_create_socket(void)
|
|||||||
fatal("socket failed");
|
fatal("socket failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef TMATE_SLAVE
|
|
||||||
if (access(sa.sun_path, F_OK) == 0)
|
|
||||||
tmate_fatal("session exists");
|
|
||||||
#else
|
|
||||||
unlink(sa.sun_path);
|
unlink(sa.sun_path);
|
||||||
#endif
|
|
||||||
|
|
||||||
if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
|
if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
|
||||||
fatal("socket failed");
|
fatal("socket failed");
|
||||||
|
@ -2,6 +2,16 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <libssh/libssh.h>
|
#include <libssh/libssh.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <grp.h>
|
||||||
|
#include <pwd.h>
|
||||||
|
#ifdef HAVE_CURSES_H
|
||||||
|
#include <curses.h>
|
||||||
|
#else
|
||||||
|
#include <ncurses.h>
|
||||||
|
#endif
|
||||||
|
#include <term.h>
|
||||||
#include "tmate.h"
|
#include "tmate.h"
|
||||||
|
|
||||||
struct tmate_encoder *tmate_encoder;
|
struct tmate_encoder *tmate_encoder;
|
||||||
@ -41,6 +51,12 @@ int main(int argc, char **argv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
log_open(debug_level, log_path);
|
log_open(debug_level, log_path);
|
||||||
|
|
||||||
|
if ((mkdir(TMATE_WORKDIR, 0700) < 0 && errno != EEXIST) ||
|
||||||
|
(mkdir(TMATE_WORKDIR "/sessions", 0700) < 0 && errno != EEXIST) ||
|
||||||
|
(mkdir(TMATE_WORKDIR "/jail", 0700) < 0 && errno != EEXIST))
|
||||||
|
tmate_fatal("Cannot prepare session in " TMATE_WORKDIR);
|
||||||
|
|
||||||
tmate_ssh_server_main(port);
|
tmate_ssh_server_main(port);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -48,7 +64,7 @@ int main(int argc, char **argv)
|
|||||||
static void set_session_token(const char *token)
|
static void set_session_token(const char *token)
|
||||||
{
|
{
|
||||||
tmate_session_token = xstrdup(token);
|
tmate_session_token = xstrdup(token);
|
||||||
strcpy(socket_path, "/tmp/tmate-slave-");
|
strcpy(socket_path, TMATE_WORKDIR "/sessions/");
|
||||||
strcat(socket_path, token);
|
strcat(socket_path, token);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -62,6 +78,11 @@ static char *get_random_token(void)
|
|||||||
int i;
|
int i;
|
||||||
char *token = xmalloc(TMATE_TOKEN_LEN + 1);
|
char *token = xmalloc(TMATE_TOKEN_LEN + 1);
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
strcpy(token, "TOKENTOKENTOKENTOKENTOKEN");
|
||||||
|
return token;
|
||||||
|
#endif
|
||||||
|
|
||||||
ssh_get_random(token, TMATE_TOKEN_LEN, 0);
|
ssh_get_random(token, TMATE_TOKEN_LEN, 0);
|
||||||
for (i = 0; i < TMATE_TOKEN_LEN; i++)
|
for (i = 0; i < TMATE_TOKEN_LEN; i++)
|
||||||
token[i] = tmate_token_digits[token[i] % NUM_DIGITS];
|
token[i] = tmate_token_digits[token[i] % NUM_DIGITS];
|
||||||
@ -134,6 +155,50 @@ static void close_fds_except(int *fd_to_preserve, int num_fds)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void jail(void)
|
||||||
|
{
|
||||||
|
struct passwd *pw;
|
||||||
|
uid_t uid;
|
||||||
|
gid_t gid;
|
||||||
|
|
||||||
|
pw = getpwnam(TMATE_JAIL_USER);
|
||||||
|
if (!pw) {
|
||||||
|
tmate_fatal("Cannot get the /etc/passwd entry for %s",
|
||||||
|
TMATE_JAIL_USER);
|
||||||
|
}
|
||||||
|
uid = pw->pw_uid;
|
||||||
|
gid = pw->pw_gid;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We are already in a new PID namespace (from the server fork).
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (chroot(TMATE_WORKDIR "/jail") < 0)
|
||||||
|
tmate_fatal("Cannot chroot()");
|
||||||
|
|
||||||
|
if (chdir("/") < 0)
|
||||||
|
tmate_fatal("Cannot chdir()");
|
||||||
|
|
||||||
|
if (setgroups(1, (gid_t[]){gid}) < 0)
|
||||||
|
tmate_fatal("Cannot setgroups()");
|
||||||
|
|
||||||
|
if (setresuid(uid, uid, uid) < 0)
|
||||||
|
tmate_fatal("Cannot setresuid()");
|
||||||
|
|
||||||
|
if (setresuid(gid, gid, gid) < 0)
|
||||||
|
tmate_fatal("Cannot setresgid()");
|
||||||
|
|
||||||
|
tmate_debug("Dropped priviledges to %s (%d,%d)",
|
||||||
|
TMATE_JAIL_USER, uid, gid);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void setup_ncurse(int fd, const char *name)
|
||||||
|
{
|
||||||
|
int error;
|
||||||
|
if (setupterm(name, fd, &error) != OK)
|
||||||
|
tmate_fatal("Cannot setup terminal");
|
||||||
|
}
|
||||||
|
|
||||||
static void tmate_spawn_slave_server(struct tmate_ssh_client *client)
|
static void tmate_spawn_slave_server(struct tmate_ssh_client *client)
|
||||||
{
|
{
|
||||||
char *token;
|
char *token;
|
||||||
@ -150,8 +215,14 @@ static void tmate_spawn_slave_server(struct tmate_ssh_client *client)
|
|||||||
if (tmux_socket_fd < 0)
|
if (tmux_socket_fd < 0)
|
||||||
tmate_fatal("Cannot create to the tmux socket");
|
tmate_fatal("Cannot create to the tmux socket");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Needed to initialize the database used in tty-term.c.
|
||||||
|
* We won't have access to it once in the jail.
|
||||||
|
*/
|
||||||
|
setup_ncurse(STDOUT_FILENO, "screen-256color");
|
||||||
close_fds_except((int[]){tmux_socket_fd, ssh_get_fd(client->session),
|
close_fds_except((int[]){tmux_socket_fd, ssh_get_fd(client->session),
|
||||||
fileno(log_file)}, 7);
|
fileno(log_file)}, 7);
|
||||||
|
jail();
|
||||||
|
|
||||||
ev_base = osdep_event_init();
|
ev_base = osdep_event_init();
|
||||||
|
|
||||||
@ -195,9 +266,11 @@ static void tmate_spawn_slave_client(struct tmate_ssh_client *client)
|
|||||||
dup2(slave_pty, STDOUT_FILENO);
|
dup2(slave_pty, STDOUT_FILENO);
|
||||||
dup2(slave_pty, STDERR_FILENO);
|
dup2(slave_pty, STDERR_FILENO);
|
||||||
|
|
||||||
|
setup_ncurse(slave_pty, "screen-256color");
|
||||||
close_fds_except((int[]){STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO,
|
close_fds_except((int[]){STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO,
|
||||||
tmux_socket_fd, ssh_get_fd(client->session),
|
tmux_socket_fd, ssh_get_fd(client->session),
|
||||||
client->pty, fileno(log_file)}, 7);
|
client->pty, fileno(log_file)}, 7);
|
||||||
|
jail();
|
||||||
|
|
||||||
ev_base = osdep_event_init();
|
ev_base = osdep_event_init();
|
||||||
|
|
||||||
|
@ -3,6 +3,8 @@
|
|||||||
#include <libssh/server.h>
|
#include <libssh/server.h>
|
||||||
#include <libssh/callbacks.h>
|
#include <libssh/callbacks.h>
|
||||||
|
|
||||||
|
extern int server_shutdown;
|
||||||
|
|
||||||
static void consume_channel(struct tmate_ssh_client *client)
|
static void consume_channel(struct tmate_ssh_client *client)
|
||||||
{
|
{
|
||||||
char *buf;
|
char *buf;
|
||||||
@ -18,7 +20,8 @@ static void consume_channel(struct tmate_ssh_client *client)
|
|||||||
if (len < 0) {
|
if (len < 0) {
|
||||||
tmate_debug("Error reading from channel: %s",
|
tmate_debug("Error reading from channel: %s",
|
||||||
ssh_get_error(client->session));
|
ssh_get_error(client->session));
|
||||||
exit(1);
|
server_shutdown = 1;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
if (len == 0)
|
if (len == 0)
|
||||||
break;
|
break;
|
||||||
@ -35,7 +38,8 @@ static void on_session_event(struct tmate_ssh_client *client)
|
|||||||
consume_channel(client);
|
consume_channel(client);
|
||||||
if (!ssh_is_connected(session)) {
|
if (!ssh_is_connected(session)) {
|
||||||
tmate_debug("Disconnected");
|
tmate_debug("Disconnected");
|
||||||
exit(1);
|
server_shutdown = 1;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -68,7 +72,8 @@ static void flush_input_stream(struct tmate_ssh_client *client)
|
|||||||
if (written < 0) {
|
if (written < 0) {
|
||||||
tmate_debug("Error writing to channel: %s",
|
tmate_debug("Error writing to channel: %s",
|
||||||
ssh_get_error(client->session));
|
ssh_get_error(client->session));
|
||||||
exit(1);
|
server_shutdown = 1;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
evbuffer_drain(evb, written);
|
evbuffer_drain(evb, written);
|
||||||
|
@ -3,9 +3,11 @@
|
|||||||
#include <libssh/callbacks.h>
|
#include <libssh/callbacks.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <netinet/tcp.h>
|
#include <netinet/tcp.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
#include <sys/syscall.h>
|
||||||
|
#include <sched.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <event.h>
|
#include <event.h>
|
||||||
#include <sys/wait.h>
|
|
||||||
|
|
||||||
#include "tmate.h"
|
#include "tmate.h"
|
||||||
|
|
||||||
@ -160,6 +162,8 @@ static void handle_sigchld(void)
|
|||||||
int status, child_dead, child_exit_status;
|
int status, child_dead, child_exit_status;
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
|
|
||||||
|
/* TODO cleanup the socket when the client dies */
|
||||||
|
|
||||||
while ((pid = waitpid(0, &status, WNOHANG)) > 0) {
|
while ((pid = waitpid(0, &status, WNOHANG)) > 0) {
|
||||||
child_dead = 0;
|
child_dead = 0;
|
||||||
|
|
||||||
@ -208,6 +212,14 @@ static struct ssh_callbacks_struct ssh_session_callbacks = {
|
|||||||
.log_function = ssh_log_cb
|
.log_function = ssh_log_cb
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static pid_t namespace_fork(void)
|
||||||
|
{
|
||||||
|
/* XXX we are breaking getpid() libc cache. Bad libc. */
|
||||||
|
unsigned long flags;
|
||||||
|
flags = CLONE_NEWPID | CLONE_NEWIPC | CLONE_NEWNS | CLONE_NEWNET;
|
||||||
|
return syscall(SYS_clone, flags | SIGCHLD, NULL, NULL, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
void tmate_ssh_server_main(int port)
|
void tmate_ssh_server_main(int port)
|
||||||
{
|
{
|
||||||
struct tmate_ssh_client _client;
|
struct tmate_ssh_client _client;
|
||||||
@ -245,8 +257,8 @@ void tmate_ssh_server_main(int port)
|
|||||||
if (ssh_bind_accept(bind, client->session) < 0)
|
if (ssh_bind_accept(bind, client->session) < 0)
|
||||||
tmate_fatal("Error accepting connection: %s", ssh_get_error(bind));
|
tmate_fatal("Error accepting connection: %s", ssh_get_error(bind));
|
||||||
|
|
||||||
if ((pid = fork()) < 0)
|
if ((pid = namespace_fork()) < 0)
|
||||||
tmate_fatal("Can't fork");
|
tmate_fatal("Can't fork in new namespace");
|
||||||
|
|
||||||
if (pid) {
|
if (pid) {
|
||||||
ssh_free(client->session);
|
ssh_free(client->session);
|
||||||
|
2
tmate.h
2
tmate.h
@ -101,6 +101,8 @@ extern void tmate_ssh_server_main(int port);
|
|||||||
/* tmate-slave.c */
|
/* tmate-slave.c */
|
||||||
|
|
||||||
#define TMATE_TOKEN_LEN 25
|
#define TMATE_TOKEN_LEN 25
|
||||||
|
#define TMATE_WORKDIR "/tmp/tmate"
|
||||||
|
#define TMATE_JAIL_USER "nobody"
|
||||||
|
|
||||||
extern struct tmate_encoder *tmate_encoder;
|
extern struct tmate_encoder *tmate_encoder;
|
||||||
extern int tmux_socket_fd;
|
extern int tmux_socket_fd;
|
||||||
|
@ -333,6 +333,8 @@ tty_term_find(char *name, int fd, const char *overrides, char **cause)
|
|||||||
memset(term->codes, 0, sizeof term->codes);
|
memset(term->codes, 0, sizeof term->codes);
|
||||||
LIST_INSERT_HEAD(&tty_terms, term, entry);
|
LIST_INSERT_HEAD(&tty_terms, term, entry);
|
||||||
|
|
||||||
|
/* we are in a jail, no access to files */
|
||||||
|
#ifndef TMATE_SLAVE
|
||||||
/* Set up curses terminal. */
|
/* Set up curses terminal. */
|
||||||
if (setupterm(name, fd, &error) != OK) {
|
if (setupterm(name, fd, &error) != OK) {
|
||||||
switch (error) {
|
switch (error) {
|
||||||
@ -353,6 +355,7 @@ tty_term_find(char *name, int fd, const char *overrides, char **cause)
|
|||||||
}
|
}
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Fill in codes. */
|
/* Fill in codes. */
|
||||||
for (i = 0; i < NTTYCODE; i++) {
|
for (i = 0; i < NTTYCODE; i++) {
|
||||||
|
4
tty.c
4
tty.c
@ -72,9 +72,13 @@ tty_init(struct tty *tty, struct client *c, int fd, char *term)
|
|||||||
tty->fd = fd;
|
tty->fd = fd;
|
||||||
tty->client = c;
|
tty->client = c;
|
||||||
|
|
||||||
|
#ifdef TMATE_SLAVE
|
||||||
|
tty->path = NULL;
|
||||||
|
#else
|
||||||
if ((path = ttyname(fd)) == NULL)
|
if ((path = ttyname(fd)) == NULL)
|
||||||
fatalx("ttyname failed");
|
fatalx("ttyname failed");
|
||||||
tty->path = xstrdup(path);
|
tty->path = xstrdup(path);
|
||||||
|
#endif
|
||||||
tty->cstyle = 0;
|
tty->cstyle = 0;
|
||||||
tty->ccolour = xstrdup("");
|
tty->ccolour = xstrdup("");
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user