version 1.161, 2015/10/26 23:16:18 |
version 1.162, 2015/10/27 13:23:24 |
|
|
|
|
#include <sys/types.h> |
#include <sys/types.h> |
#include <sys/ioctl.h> |
#include <sys/ioctl.h> |
|
#include <sys/uio.h> |
|
|
#include <errno.h> |
#include <errno.h> |
#include <event.h> |
#include <event.h> |
#include <fcntl.h> |
#include <fcntl.h> |
|
#include <imsg.h> |
#include <paths.h> |
#include <paths.h> |
#include <stdlib.h> |
#include <stdlib.h> |
#include <string.h> |
#include <string.h> |
|
|
void server_client_reset_state(struct client *); |
void server_client_reset_state(struct client *); |
int server_client_assume_paste(struct session *); |
int server_client_assume_paste(struct session *); |
|
|
int server_client_msg_dispatch(struct client *); |
void server_client_dispatch(struct imsg *, void *); |
void server_client_msg_command(struct client *, struct imsg *); |
void server_client_dispatch_command(struct client *, struct imsg *); |
void server_client_msg_identify(struct client *, struct imsg *); |
void server_client_dispatch_identify(struct client *, struct imsg *); |
void server_client_msg_shell(struct client *); |
void server_client_dispatch_shell(struct client *); |
|
|
/* Check if this client is inside this server. */ |
/* Check if this client is inside this server. */ |
int |
int |
|
|
|
|
c = xcalloc(1, sizeof *c); |
c = xcalloc(1, sizeof *c); |
c->references = 1; |
c->references = 1; |
imsg_init(&c->ibuf, fd); |
c->peer = proc_add_peer(server_proc, fd, server_client_dispatch, c); |
server_update_event(c); |
|
|
|
if (gettimeofday(&c->creation_time, NULL) != 0) |
if (gettimeofday(&c->creation_time, NULL) != 0) |
fatal("gettimeofday failed"); |
fatal("gettimeofday failed"); |
|
|
|
|
environ_free(&c->environ); |
environ_free(&c->environ); |
|
|
close(c->ibuf.fd); |
proc_remove_peer(c->peer); |
imsg_clear(&c->ibuf); |
c->peer = NULL; |
if (event_initialized(&c->event)) |
|
event_del(&c->event); |
|
|
|
server_client_unref(c); |
server_client_unref(c); |
|
|
|
|
free(c); |
free(c); |
} |
} |
|
|
/* Process a single client event. */ |
|
void |
|
server_client_callback(int fd, short events, void *data) |
|
{ |
|
struct client *c = data; |
|
|
|
if (c->flags & CLIENT_DEAD) |
|
return; |
|
|
|
if (fd == c->ibuf.fd) { |
|
if (events & EV_WRITE && msgbuf_write(&c->ibuf.w) <= 0 && |
|
errno != EAGAIN) |
|
goto client_lost; |
|
|
|
if (c->flags & CLIENT_BAD) { |
|
if (c->ibuf.w.queued == 0) |
|
goto client_lost; |
|
return; |
|
} |
|
|
|
if (events & EV_READ && server_client_msg_dispatch(c) != 0) |
|
goto client_lost; |
|
} |
|
|
|
server_push_stdout(c); |
|
server_push_stderr(c); |
|
|
|
server_update_event(c); |
|
return; |
|
|
|
client_lost: |
|
server_client_lost(c); |
|
} |
|
|
|
/* Check for mouse keys. */ |
/* Check for mouse keys. */ |
int |
int |
server_client_check_mouse(struct client *c) |
server_client_check_mouse(struct client *c) |
|
|
if (EVBUFFER_LENGTH(c->stderr_data) != 0) |
if (EVBUFFER_LENGTH(c->stderr_data) != 0) |
return; |
return; |
|
|
server_write_client(c, MSG_EXIT, &c->retval, sizeof c->retval); |
proc_send(c->peer, MSG_EXIT, -1, &c->retval, sizeof c->retval); |
c->flags &= ~CLIENT_EXIT; |
c->flags &= ~CLIENT_EXIT; |
} |
} |
|
|
|
|
} |
} |
|
|
/* Dispatch message from client. */ |
/* Dispatch message from client. */ |
int |
void |
server_client_msg_dispatch(struct client *c) |
server_client_dispatch(struct imsg *imsg, void *arg) |
{ |
{ |
struct imsg imsg; |
struct client *c = arg; |
struct msg_stdin_data stdindata; |
struct msg_stdin_data stdindata; |
const char *data; |
const char *data; |
ssize_t n, datalen; |
ssize_t datalen; |
struct session *s; |
struct session *s; |
|
|
if ((n = imsg_read(&c->ibuf)) == -1 || n == 0) |
if (c->flags & CLIENT_DEAD) |
return (-1); |
return; |
|
|
for (;;) { |
if (imsg == NULL) { |
if ((n = imsg_get(&c->ibuf, &imsg)) == -1) |
server_client_lost(c); |
return (-1); |
return; |
if (n == 0) |
} |
return (0); |
|
|
|
data = imsg.data; |
data = imsg->data; |
datalen = imsg.hdr.len - IMSG_HEADER_SIZE; |
datalen = imsg->hdr.len - IMSG_HEADER_SIZE; |
|
|
if (imsg.hdr.peerid != PROTOCOL_VERSION) { |
switch (imsg->hdr.type) { |
server_write_client(c, MSG_VERSION, NULL, 0); |
case MSG_IDENTIFY_FLAGS: |
c->flags |= CLIENT_BAD; |
case MSG_IDENTIFY_TERM: |
if (imsg.fd != -1) |
case MSG_IDENTIFY_TTYNAME: |
close(imsg.fd); |
case MSG_IDENTIFY_CWD: |
imsg_free(&imsg); |
case MSG_IDENTIFY_STDIN: |
continue; |
case MSG_IDENTIFY_ENVIRON: |
} |
case MSG_IDENTIFY_CLIENTPID: |
|
case MSG_IDENTIFY_DONE: |
|
server_client_dispatch_identify(c, imsg); |
|
break; |
|
case MSG_COMMAND: |
|
server_client_dispatch_command(c, imsg); |
|
break; |
|
case MSG_STDIN: |
|
if (datalen != sizeof stdindata) |
|
fatalx("bad MSG_STDIN size"); |
|
memcpy(&stdindata, data, sizeof stdindata); |
|
|
log_debug("got %u from client %p", imsg.hdr.type, c); |
if (c->stdin_callback == NULL) |
switch (imsg.hdr.type) { |
|
case MSG_IDENTIFY_FLAGS: |
|
case MSG_IDENTIFY_TERM: |
|
case MSG_IDENTIFY_TTYNAME: |
|
case MSG_IDENTIFY_CWD: |
|
case MSG_IDENTIFY_STDIN: |
|
case MSG_IDENTIFY_ENVIRON: |
|
case MSG_IDENTIFY_CLIENTPID: |
|
case MSG_IDENTIFY_DONE: |
|
server_client_msg_identify(c, &imsg); |
|
break; |
break; |
case MSG_COMMAND: |
if (stdindata.size <= 0) |
server_client_msg_command(c, &imsg); |
c->stdin_closed = 1; |
break; |
else { |
case MSG_STDIN: |
evbuffer_add(c->stdin_data, stdindata.data, |
if (datalen != sizeof stdindata) |
stdindata.size); |
fatalx("bad MSG_STDIN size"); |
} |
memcpy(&stdindata, data, sizeof stdindata); |
c->stdin_callback(c, c->stdin_closed, |
|
c->stdin_callback_data); |
|
break; |
|
case MSG_RESIZE: |
|
if (datalen != 0) |
|
fatalx("bad MSG_RESIZE size"); |
|
|
if (c->stdin_callback == NULL) |
if (c->flags & CLIENT_CONTROL) |
break; |
|
if (stdindata.size <= 0) |
|
c->stdin_closed = 1; |
|
else { |
|
evbuffer_add(c->stdin_data, stdindata.data, |
|
stdindata.size); |
|
} |
|
c->stdin_callback(c, c->stdin_closed, |
|
c->stdin_callback_data); |
|
break; |
break; |
case MSG_RESIZE: |
if (tty_resize(&c->tty)) { |
if (datalen != 0) |
recalculate_sizes(); |
fatalx("bad MSG_RESIZE size"); |
server_redraw_client(c); |
|
} |
|
break; |
|
case MSG_EXITING: |
|
if (datalen != 0) |
|
fatalx("bad MSG_EXITING size"); |
|
|
if (c->flags & CLIENT_CONTROL) |
c->session = NULL; |
break; |
tty_close(&c->tty); |
if (tty_resize(&c->tty)) { |
proc_send(c->peer, MSG_EXITED, -1, NULL, 0); |
recalculate_sizes(); |
break; |
server_redraw_client(c); |
case MSG_WAKEUP: |
} |
case MSG_UNLOCK: |
break; |
if (datalen != 0) |
case MSG_EXITING: |
fatalx("bad MSG_WAKEUP size"); |
if (datalen != 0) |
|
fatalx("bad MSG_EXITING size"); |
|
|
|
c->session = NULL; |
if (!(c->flags & CLIENT_SUSPENDED)) |
tty_close(&c->tty); |
|
server_write_client(c, MSG_EXITED, NULL, 0); |
|
break; |
break; |
case MSG_WAKEUP: |
c->flags &= ~CLIENT_SUSPENDED; |
case MSG_UNLOCK: |
|
if (datalen != 0) |
|
fatalx("bad MSG_WAKEUP size"); |
|
|
|
if (!(c->flags & CLIENT_SUSPENDED)) |
if (c->tty.fd == -1) /* exited in the meantime */ |
break; |
|
c->flags &= ~CLIENT_SUSPENDED; |
|
|
|
if (c->tty.fd == -1) /* exited in the meantime */ |
|
break; |
|
s = c->session; |
|
|
|
if (gettimeofday(&c->activity_time, NULL) != 0) |
|
fatal("gettimeofday failed"); |
|
if (s != NULL) |
|
session_update_activity(s, &c->activity_time); |
|
|
|
tty_start_tty(&c->tty); |
|
server_redraw_client(c); |
|
recalculate_sizes(); |
|
break; |
break; |
case MSG_SHELL: |
s = c->session; |
if (datalen != 0) |
|
fatalx("bad MSG_SHELL size"); |
|
|
|
server_client_msg_shell(c); |
if (gettimeofday(&c->activity_time, NULL) != 0) |
break; |
fatal("gettimeofday failed"); |
} |
if (s != NULL) |
|
session_update_activity(s, &c->activity_time); |
|
|
imsg_free(&imsg); |
tty_start_tty(&c->tty); |
|
server_redraw_client(c); |
|
recalculate_sizes(); |
|
break; |
|
case MSG_SHELL: |
|
if (datalen != 0) |
|
fatalx("bad MSG_SHELL size"); |
|
|
|
server_client_dispatch_shell(c); |
|
break; |
} |
} |
|
|
|
server_push_stdout(c); |
|
server_push_stderr(c); |
} |
} |
|
|
/* Handle command message. */ |
/* Handle command message. */ |
void |
void |
server_client_msg_command(struct client *c, struct imsg *imsg) |
server_client_dispatch_command(struct client *c, struct imsg *imsg) |
{ |
{ |
struct msg_command_data data; |
struct msg_command_data data; |
char *buf; |
char *buf; |
|
|
|
|
/* Handle identify message. */ |
/* Handle identify message. */ |
void |
void |
server_client_msg_identify(struct client *c, struct imsg *imsg) |
server_client_dispatch_identify(struct client *c, struct imsg *imsg) |
{ |
{ |
const char *data; |
const char *data; |
size_t datalen; |
size_t datalen; |
|
|
|
|
if (c->flags & CLIENT_CONTROLCONTROL) |
if (c->flags & CLIENT_CONTROLCONTROL) |
evbuffer_add_printf(c->stdout_data, "\033P1000p"); |
evbuffer_add_printf(c->stdout_data, "\033P1000p"); |
server_write_client(c, MSG_STDIN, NULL, 0); |
proc_send(c->peer, MSG_STDIN, -1, NULL, 0); |
|
|
c->tty.fd = -1; |
c->tty.fd = -1; |
c->tty.log_fd = -1; |
c->tty.log_fd = -1; |
|
|
|
|
/* Handle shell message. */ |
/* Handle shell message. */ |
void |
void |
server_client_msg_shell(struct client *c) |
server_client_dispatch_shell(struct client *c) |
{ |
{ |
const char *shell; |
const char *shell; |
|
|
shell = options_get_string(&global_s_options, "default-shell"); |
shell = options_get_string(&global_s_options, "default-shell"); |
if (*shell == '\0' || areshell(shell)) |
if (*shell == '\0' || areshell(shell)) |
shell = _PATH_BSHELL; |
shell = _PATH_BSHELL; |
server_write_client(c, MSG_SHELL, shell, strlen(shell) + 1); |
proc_send_s(c->peer, MSG_SHELL, shell); |
|
|
c->flags |= CLIENT_BAD; /* it will die after exec */ |
proc_kill_peer(c->peer); |
} |
} |