diff --git a/Makefile.am b/Makefile.am index 965cd676..09efd142 100644 --- a/Makefile.am +++ b/Makefile.am @@ -181,7 +181,6 @@ dist_tmate_slave_SOURCES = \ tmate-debug.c \ tmate-decoder.c \ tmate-encoder.c \ - tmate-replayer.c \ tmate-slave.c \ tmate-ssh-client-pty.c \ tmate-ssh-client.c \ diff --git a/create_keys.sh b/create_keys.sh index b8a1d42b..c8e4c4d4 100755 --- a/create_keys.sh +++ b/create_keys.sh @@ -4,10 +4,10 @@ gen_key() { ks="${keytype}_" key="keys/ssh_host_${ks}key" if [ ! -e "${key}" ] ; then - ssh-keygen -t ${keytype} -f "${key}" -N '' + ssh-keygen -t ${keytype} -f "${key}" -N '' -E md5 return $? fi } mkdir -p keys -gen_key dsa && gen_key rsa && gen_key ecdsa || exit 1 +gen_key rsa && gen_key ecdsa || exit 1 diff --git a/log.c b/log.c index 58e346cb..67cc1b1a 100644 --- a/log.c +++ b/log.c @@ -29,89 +29,68 @@ #include "tmux.h" #include "tmate.h" -/* Log file, if needed. */ -FILE *log_file; +FILE *log_file; -/* Debug level. */ -int log_level = 0; +struct logging_settings { + const char *program_name; + bool use_syslog; + int log_level; +}; + +static struct logging_settings log_settings; void log_event_cb(int, const char *); -void log_vwrite(const char *, va_list); +void log_vwrite(int, const char *, va_list); __dead void log_vfatal(const char *, va_list); -/* Log callback for libevent. */ void log_event_cb(unused int severity, const char *msg) { log_warnx("%s", msg); } -/* Open logging to file. */ -void -log_open(int level, const char *path) +void init_logging(const char *program_name, bool use_syslog, int log_level) { - FILE *f; + log_settings.log_level = log_level; + log_settings.use_syslog = use_syslog; + log_settings.program_name = xstrdup(program_name); - if (path) { - f = fopen(path, "a"); - if (!f) { - if (log_file) { - log_info("cannot reopen log file"); - return; - } - fprintf(stderr, "cannot open log file %s\n", path); - exit(1); - } + if (use_syslog) { + openlog(program_name, LOG_CONS | LOG_PID, LOG_USER); + setlogmask(LOG_UPTO(log_level)); } else { - f = fdopen(dup(STDERR_FILENO), "a"); + log_file = fdopen(dup(STDERR_FILENO), "a"); + if (!log_file) + exit(1); } - if (log_file) - fclose(log_file); - - log_file = f; - log_level = level; - - setlinebuf(log_file); event_set_log_callback(log_event_cb); - - tzset(); -} - -/* Close logging. */ -void -log_close(void) -{ - if (log_file != NULL) - fclose(log_file); - - event_set_log_callback(NULL); } /* Write a log message. */ void -log_vwrite(const char *msg, va_list ap) +log_vwrite(int level, const char *msg, va_list ap) { - char time_str[100]; - time_t now; - struct tm *tm; + char *fmt = NULL; - char *fmt; - - if (log_file == NULL) + if (log_settings.log_level < level) return; - /* XXX Should we do UTC instead of local time? */ - now = time(NULL); - tm = localtime(&now); + if (tmate_session_token) { + if (asprintf(&fmt, "[%s] %s", tmate_session_token, msg) < 0) + exit(1); + msg = fmt; + } - strftime(time_str, sizeof(time_str), "%Y-%m-%d %H:%M:%S", tm); + if (log_settings.use_syslog) { + vsyslog(level, msg, ap); + } else { + fprintf(log_file, "<%d> ", level); + vfprintf(log_file, msg, ap); + fprintf(log_file, "\n"); + fflush(log_file); + } - if (asprintf(&fmt, "%s [%s] %s\n", time_str, tmate_session_token, msg) == -1) - exit(1); - if (vfprintf(log_file, fmt, ap) == -1) - exit(1); - fflush(log_file); free(fmt); } @@ -125,7 +104,7 @@ log_warn(const char *msg, ...) va_start(ap, msg); if (asprintf(&fmt, "%s: %s", msg, strerror(errno)) == -1) exit(1); - log_vwrite(fmt, ap); + log_vwrite(LOG_WARNING, fmt, ap); free(fmt); va_end(ap); } @@ -137,7 +116,7 @@ log_warnx(const char *msg, ...) va_list ap; va_start(ap, msg); - log_vwrite(msg, ap); + log_vwrite(LOG_WARNING, msg, ap); va_end(ap); } @@ -147,11 +126,9 @@ log_info(const char *msg, ...) { va_list ap; - if (log_level > -1) { - va_start(ap, msg); - log_vwrite(msg, ap); - va_end(ap); - } + va_start(ap, msg); + log_vwrite(LOG_NOTICE, msg, ap); + va_end(ap); } /* Log a debug message. */ @@ -160,11 +137,9 @@ log_debug(const char *msg, ...) { va_list ap; - if (log_level > 0) { - va_start(ap, msg); - log_vwrite(msg, ap); - va_end(ap); - } + va_start(ap, msg); + log_vwrite(LOG_INFO, msg, ap); + va_end(ap); } /* Log a debug message at level 2. */ @@ -173,11 +148,12 @@ log_debug2(const char *msg, ...) { va_list ap; - if (log_level > 1) { - va_start(ap, msg); - log_vwrite(msg, ap); - va_end(ap); - } + /* Not going with crazy logging on tmux */ +#ifndef TMATE_SLAVE + va_start(ap, msg); + log_vwrite(LOG_DEBUG, msg, ap); + va_end(ap); +#endif } /* Log a critical error, with error string if necessary, and die. */ @@ -189,11 +165,11 @@ log_vfatal(const char *msg, va_list ap) if (errno != 0) { if (asprintf(&fmt, "fatal: %s: %s", msg, strerror(errno)) == -1) exit(1); - log_vwrite(fmt, ap); + log_vwrite(LOG_CRIT, fmt, ap); } else { if (asprintf(&fmt, "fatal: %s", msg) == -1) exit(1); - log_vwrite(fmt, ap); + log_vwrite(LOG_CRIT, fmt, ap); } free(fmt); @@ -220,3 +196,21 @@ log_fatalx(const char *msg, ...) va_start(ap, msg); log_vfatal(msg, ap); } + +void printflike2 tmate_log(int level, const char *msg, ...) +{ + char *fmt; + va_list ap; + + if (log_settings.log_level < level) + return; + + va_start(ap, msg); + + if (asprintf(&fmt, "(tmate) %s", msg) < 0) + exit(1); + log_vwrite(level, fmt, ap); + va_end(ap); + + free(fmt); +} diff --git a/tmate-decoder.c b/tmate-decoder.c index 3f7e525c..64b63719 100644 --- a/tmate-decoder.c +++ b/tmate-decoder.c @@ -119,14 +119,14 @@ static void tmate_header(struct tmate_decoder *decoder, free(client_version); - if (tmate_port != 22) - sprintf(port_arg, " -p%d", tmate_port); + if (tmate_settings.ssh_port != 22) + sprintf(port_arg, " -p%d", tmate_settings.ssh_port); - sprintf(tmp, "ssh%s ro-%s@%s", port_arg, tmate_session_token_ro, tmate_host); + sprintf(tmp, "ssh%s ro-%s@%s", port_arg, tmate_session_token_ro, tmate_settings.tmate_host); tmate_notify("Remote session read only: %s (clear your screen if you share this)", tmp); tmate_send_env("tmate_ssh_ro", tmp); - sprintf(tmp, "ssh%s %s@%s", port_arg, tmate_session_token, tmate_host); + sprintf(tmp, "ssh%s %s@%s", port_arg, tmate_session_token, tmate_settings.tmate_host); tmate_notify("Remote session: %s", tmp); tmate_send_env("tmate_ssh", tmp); diff --git a/tmate-replayer.c b/tmate-replayer.c deleted file mode 100644 index cd7fb3fb..00000000 --- a/tmate-replayer.c +++ /dev/null @@ -1,70 +0,0 @@ -#include -#include -#include "tmate.h" - -#ifdef TMATE_RECORD_REPLAY - -#define READ_MAX_SIZE 1024 -#define TIMER_INERVAL_USEC 1000 - -extern int server_shutdown; -extern void server_send_shutdown(void); - -static void start_timer(struct tmate_replayer *replayer); - -static void on_read_timer(evutil_socket_t fd, short what, void *arg) -{ - struct tmate_replayer *replayer = arg; - char *buf; - ssize_t len; - - if (replayer->log_fd < 0) { - evtimer_del(&replayer->ev_read_timer); - server_shutdown = 1; - server_send_shutdown(); - return; - } - - tmate_decoder_get_buffer(replayer->decoder, &buf, &len); - if (len == 0) - tmate_fatal("Decoder buffer full"); - - if (len > READ_MAX_SIZE) - len = READ_MAX_SIZE; - - len = read(replayer->log_fd, buf, len); - if (len < 0) - tmate_fatal("cannot read from replay log file"); - - if (len == 0) { - tmate_info("Replay file reached EOF"); - replayer->log_fd = -1; - } else { - tmate_decoder_commit(replayer->decoder, len); - } - - start_timer(replayer); -} - -static void start_timer(struct tmate_replayer *replayer) -{ - struct timeval tv; - tv.tv_sec = 0; - tv.tv_usec = TIMER_INERVAL_USEC; - - evtimer_assign(&replayer->ev_read_timer, ev_base, - on_read_timer, replayer); - evtimer_add(&replayer->ev_read_timer, &tv); -} - -void tmate_replayer_init(struct tmate_replayer *replayer, - struct tmate_decoder *decoder, - int log_fd) -{ - replayer->decoder = decoder; - replayer->log_fd = log_fd; - - start_timer(replayer); -} - -#endif diff --git a/tmate-slave.c b/tmate-slave.c index 89dd96e9..4850d25d 100644 --- a/tmate-slave.c +++ b/tmate-slave.c @@ -15,39 +15,37 @@ #include #include #include +#include #include "tmate.h" -int tmate_port = TMATE_DEFAULT_PORT; -char *tmate_host; - struct tmate_decoder *tmate_decoder; struct tmate_encoder *tmate_encoder; int tmux_socket_fd; -const char *tmate_session_token = "main"; -const char *tmate_session_token_ro = "ro-main"; +const char *tmate_session_token; +const char *tmate_session_token_ro; -#ifdef TMATE_RECORD_REPLAY -int tmate_session_log_fd; -static void tmate_replay_slave_server(const char *replay_file); -#endif +extern FILE *log_file; -static char *log_path; /* NULL means stderr */ static char *cmdline; static char *cmdline_end; static int dev_urandom_fd; -extern FILE *log_file; extern int server_create_socket(void); extern int client_connect(char *path, int start_server); +struct tmate_settings tmate_settings = { + .keys_dir = TMATE_SSH_DEFAULT_KEYS_DIR, + .ssh_port = TMATE_SSH_DEFAULT_PORT, + .master_hostname = TMATE_DEFAULT_MASTER_HOST, + .master_port = TMATE_DEFAULT_MASTER_PORT, + .tmate_host = NULL, + .log_level = LOG_NOTICE, + .use_syslog = false, +}; + static void usage(void) { - fprintf(stderr, "usage: tmate-slave [-k keys_dir] [-l logfile] [-p port] [-r logfile] [-h host] [-v]\n"); -} - -void tmate_reopen_logfile(void) -{ - log_open(debug_level, log_path); + fprintf(stderr, "usage: tmate-slave [-k keys_dir] [-p port] [-m master_hostname] [-q master_port] [-s] [-v]\n"); } void tmate_get_random_bytes(void *buffer, ssize_t len) @@ -66,34 +64,29 @@ long tmate_get_random_long(void) int main(int argc, char **argv, char **envp) { int opt; - const char *keys_dir = "keys"; -#ifdef TMATE_RECORD_REPLAY - const char *replay_file = NULL; -#endif - while ((opt = getopt(argc, argv, "p:l:vk:r:h:")) != -1) { + while ((opt = getopt(argc, argv, "k:p:lvm:q:")) != -1) { switch (opt) { case 'p': - tmate_port = atoi(optarg); - break; - case 'l': - log_path = optarg; + tmate_settings.ssh_port = atoi(optarg); break; case 'k': - keys_dir = optarg; + tmate_settings.keys_dir = xstrdup(optarg); + break; + case 's': + tmate_settings.use_syslog = true; break; case 'v': - debug_level++; + tmate_settings.log_level++; break; - case 'r': -#ifdef TMATE_RECORD_REPLAY - replay_file = optarg; -#else - fprintf(stderr, "Record/Replay not enabled\n"); -#endif + case 'm': + tmate_settings.master_hostname = xstrdup(optarg); + break; + case 'q': + tmate_settings.master_port = atoi(optarg); break; case 'h': - tmate_host = xstrdup(optarg); + tmate_settings.tmate_host = xstrdup(optarg); break; default: usage(); @@ -101,36 +94,30 @@ int main(int argc, char **argv, char **envp) } } - if (!tmate_host) { + if (!tmate_settings.tmate_host) { char hostname[255]; if (gethostname(hostname, sizeof(hostname)) < 0) tmate_fatal("cannot get hostname"); - tmate_host = xstrdup(hostname); + tmate_settings.tmate_host = xstrdup(hostname); } cmdline = *argv; cmdline_end = *envp; - tmate_reopen_logfile(); + init_logging("tmate-ssh", + tmate_settings.use_syslog, tmate_settings.log_level); tmate_preload_trace_lib(); if ((dev_urandom_fd = open("/dev/urandom", O_RDONLY)) < 0) tmate_fatal("Cannot open /dev/urandom"); -#ifdef TMATE_RECORD_REPLAY - if (replay_file) { - tmate_replay_slave_server(replay_file); - return 0; - } -#endif - 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(keys_dir, tmate_port); + tmate_ssh_server_main(tmate_settings.keys_dir, tmate_settings.ssh_port); return 0; } @@ -296,32 +283,6 @@ static void setup_ncurse(int fd, const char *name) tmate_fatal("Cannot setup terminal"); } -#ifdef TMATE_RECORD_REPLAY -static void tmate_replay_slave_server(const char *replay_file) -{ - struct tmate_decoder decoder; - struct tmate_replayer replayer; - - tmate_debug("Replaying slave server with %s", replay_file); - - tmux_socket_fd = server_create_socket(); - if (tmux_socket_fd < 0) - tmate_fatal("Cannot create to the tmux socket"); - - tmate_session_log_fd = open(replay_file, O_RDONLY); - if (tmate_session_log_fd < 0) - tmate_fatal("cannot open session-dump.log"); - - ev_base = osdep_event_init(); - - tmate_decoder_init(&decoder); - tmate_replayer_init(&replayer, &decoder, tmate_session_log_fd); - - tmux_server_init(IDENTIFY_UTF8 | IDENTIFY_256COLOURS); - /* never reached */ -} -#endif - static void tmate_spawn_slave_server(struct tmate_ssh_client *client) { char *token; @@ -339,7 +300,6 @@ static void tmate_spawn_slave_server(struct tmate_ssh_client *client) tmate_debug("Spawning slave server for %s at %s (%s)", client->username, client->ip_address, client->pubkey); - tmux_socket_fd = server_create_socket(); if (tmux_socket_fd < 0) tmate_fatal("Cannot create to the tmux socket"); @@ -354,14 +314,7 @@ static void tmate_spawn_slave_server(struct tmate_ssh_client *client) close_fds_except((int[]){tmux_socket_fd, ssh_get_fd(client->session), - fileno(log_file)}, 3); - -#ifdef TMATE_RECORD_REPLAY - tmate_session_log_fd = open("session-log.log", - O_CREAT | O_WRONLY | O_TRUNC, 0644); - if (tmate_session_log_fd < 0) - tmate_fatal("cannot open session-dump.log"); -#endif + log_file ? fileno(log_file) : -1}, 3); jail(); @@ -395,7 +348,7 @@ static void tmate_spawn_slave_client(struct tmate_ssh_client *client) if (validate_token(token) < 0) { ssh_echo(client, BAD_TOKEN_ERROR_STR); - tmate_fatal("Bad token"); + tmate_fatal("Invalid token"); } set_session_token(client, token); @@ -405,7 +358,7 @@ static void tmate_spawn_slave_client(struct tmate_ssh_client *client) tmux_socket_fd = client_connect(socket_path, 0); if (tmux_socket_fd < 0) { - random_sleep(); /* for timing attacks */ + random_sleep(); /* for making timing attacks harder */ ssh_echo(client, EXPIRED_TOKEN_ERROR_STR); tmate_fatal("Expired token"); } @@ -436,7 +389,7 @@ static void tmate_spawn_slave_client(struct tmate_ssh_client *client) setup_ncurse(slave_pty, "screen-256color"); close_fds_except((int[]){STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO, tmux_socket_fd, ssh_get_fd(client->session), - client->pty, fileno(log_file)}, 7); + client->pty, log_file ? fileno(log_file) : -1}, 7); jail(); ev_base = osdep_event_init(); diff --git a/tmate-ssh-client.c b/tmate-ssh-client.c index e0f33455..e27fe130 100644 --- a/tmate-ssh-client.c +++ b/tmate-ssh-client.c @@ -12,25 +12,6 @@ extern void server_send_shutdown(void); server_send_shutdown(); \ } while(0) -#ifdef TMATE_RECORD_REPLAY -static void record_session_data(const char *buf, size_t len) -{ - ssize_t ret; - - while (len > 0) { - ret = write(tmate_session_log_fd, buf, len); - if (ret < 0) - tmate_fatal("cannot save recording of the session"); - - buf += ret; - len -= ret; - } -} -#else -static inline void record_session_data(const char *buf, size_t len) -{} -#endif - static void consume_channel(struct tmate_ssh_client *client) { char *buf; @@ -56,8 +37,6 @@ static void consume_channel(struct tmate_ssh_client *client) if (len == 0) break; - record_session_data(buf, len); - tmate_decoder_commit(client->decoder, len); } } diff --git a/tmate-ssh-server.c b/tmate-ssh-server.c index 2fd77abf..856af55f 100644 --- a/tmate-ssh-server.c +++ b/tmate-ssh-server.c @@ -129,6 +129,8 @@ static void client_bootstrap(struct tmate_ssh_client *client) ssh_session session = client->session; ssh_message msg; + tmate_notice("Bootstrapping ssh client ip=%s", client->ip_address); + /* new process group, we don't want to die with our parent (upstart) */ setpgid(0, 0); @@ -149,7 +151,8 @@ static void client_bootstrap(struct tmate_ssh_client *client) tmate_debug("Exchanging DH keys"); if (ssh_handle_key_exchange(session) < 0) - tmate_fatal("Error doing the key exchange"); + tmate_fatal("Error doing the key exchange: %s", + ssh_get_error(session)); mainloop = ssh_event_new(); ssh_event_add_session(mainloop, session); @@ -189,18 +192,12 @@ static void handle_sigsegv(void) tmate_fatal("CRASHED"); } -static void handle_sigusr1(void) -{ - tmate_reopen_logfile(); -} - static void signal_handler(int sig) { switch (sig) { case SIGCHLD: handle_sigchld(); break; case SIGALRM: handle_sigalrm(); break; case SIGSEGV: handle_sigsegv(); break; - case SIGUSR1: handle_sigusr1(); break; } } @@ -209,7 +206,6 @@ static void setup_signals(void) signal(SIGCHLD, signal_handler); signal(SIGALRM, signal_handler); signal(SIGSEGV, signal_handler); - signal(SIGUSR1, signal_handler); } static pid_t namespace_fork(void) @@ -260,7 +256,6 @@ static ssh_bind prepare_ssh(const char *keys_dir, int port) ssh_bind bind; char buffer[PATH_MAX]; int verbosity = SSH_LOG_NOLOG; - //int verbosity = SSH_LOG_PACKET; ssh_set_log_callback(ssh_log_function); @@ -272,16 +267,16 @@ static ssh_bind prepare_ssh(const char *keys_dir, int 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_dsa_key", keys_dir); - ssh_bind_options_set(bind, SSH_BIND_OPTIONS_DSAKEY, buffer); - 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_info("Accepting connections on %d", port); + tmate_notice("Accepting connections on %d", port); return bind; } @@ -321,7 +316,7 @@ void tmate_ssh_server_main(const char *keys_dir, int port) ssh_free(client->session); } else { ssh_bind_free(bind); - tmate_session_token = "........................."; + tmate_session_token = "init"; client_bootstrap(client); } } diff --git a/tmate.h b/tmate.h index 59cc94c9..71fd9562 100644 --- a/tmate.h +++ b/tmate.h @@ -1,6 +1,7 @@ #ifndef TMATE_H #define TMATE_H +#include #include #include #include @@ -8,15 +9,18 @@ #include "tmux.h" -// #define TMATE_RECORD_REPLAY /* useful to debug crashes */ +extern void init_logging(const char *program_name, bool use_syslog, int log_level); +extern void printflike2 tmate_log(int level, const char *msg, ...); -#define tmate_debug(str, ...) log_debug("[tmate] " str, ##__VA_ARGS__) -#define tmate_info(str, ...) log_info("[tmate] " str, ##__VA_ARGS__) -#define tmate_fatal(str, ...) \ -do { \ - log_info("[tmate] FATAL " str, ##__VA_ARGS__); \ - exit(-1); \ -} while (0) +#define tmate_debug(str, ...) tmate_log(LOG_DEBUG, str, ##__VA_ARGS__) +#define tmate_info(str, ...) tmate_log(LOG_INFO, str, ##__VA_ARGS__) +#define tmate_notice(str, ...) tmate_log(LOG_NOTICE, str, ##__VA_ARGS__) +#define tmate_warn(str, ...) tmate_log(LOG_WARNING, str, ##__VA_ARGS__) +#define tmate_fatal(str, ...) \ +({ \ + tmate_log(LOG_CRIT, "fatal: " str, ##__VA_ARGS__); \ + exit(1); \ +}) /* tmate-encoder.c */ @@ -84,22 +88,6 @@ extern void tmate_decoder_get_buffer(struct tmate_decoder *decoder, char **buf, size_t *len); extern void tmate_decoder_commit(struct tmate_decoder *decoder, size_t len); -#ifdef TMATE_RECORD_REPLAY -/* tmate-replayer.c */ - -struct tmate_replayer { - struct tmate_decoder *decoder; - int log_fd; - - struct event ev_read_timer; -}; - -extern void tmate_replayer_init(struct tmate_replayer *replayer, - struct tmate_decoder *decoder, - int log_fd); -#endif - - /* tmate-ssh-client.c */ #define TMATE_ROLE_SERVER 1 @@ -153,12 +141,28 @@ extern void tmate_ssh_server_main(const char *keys_dir, int port); /* tmate-slave.c */ +struct tmate_settings { + const char *keys_dir; + int ssh_port; + const char *master_hostname; + int master_port; + const char *tmate_host; + int log_level; + bool use_syslog; +}; +extern struct tmate_settings tmate_settings; + #ifdef DEVENV -#define TMATE_DEFAULT_PORT 2200 +#define TMATE_SSH_DEFAULT_PORT 2200 #else -#define TMATE_DEFAULT_PORT 22 +#define TMATE_SSH_DEFAULT_PORT 22 #endif +#define TMATE_SSH_DEFAULT_KEYS_DIR "keys" + +#define TMATE_DEFAULT_MASTER_HOST NULL +#define TMATE_DEFAULT_MASTER_PORT 7000 + #define TMATE_TOKEN_LEN 25 #define TMATE_WORKDIR "/tmp/tmate" #define TMATE_JAIL_USER "nobody"