1/* $OpenBSD$ */
2
3/*
4 * Copyright (c) 2007 Nicholas Marriott <[email protected]>
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
15 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
16 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19#include <sys/types.h>
20#include <sys/socket.h>
21#include <sys/un.h>
22#include <sys/wait.h>
23#include <sys/file.h>
24
25#include <errno.h>
26#include <event.h>
27#include <fcntl.h>
28#include <signal.h>
29#include <stdlib.h>
30#include <string.h>
31#include <unistd.h>
32
33#include "tmux.h"
34
35static struct tmuxproc *client_proc;
36static struct tmuxpeer *client_peer;
37static int client_flags;
38static enum {
39 CLIENT_EXIT_NONE,
40 CLIENT_EXIT_DETACHED,
41 CLIENT_EXIT_DETACHED_HUP,
42 CLIENT_EXIT_LOST_TTY,
43 CLIENT_EXIT_TERMINATED,
44 CLIENT_EXIT_LOST_SERVER,
45 CLIENT_EXIT_EXITED,
46 CLIENT_EXIT_SERVER_EXITED,
47} client_exitreason = CLIENT_EXIT_NONE;
48static int client_exitflag;
49static int client_exitval;
50static enum msgtype client_exittype;
51static const char *client_exitsession;
52static const char *client_execshell;
53static const char *client_execcmd;
54static int client_attached;
55static struct client_files client_files = RB_INITIALIZER(&client_files);
56
57static __dead void client_exec(const char *,const char *);
58static int client_get_lock(char *);
59static int client_connect(struct event_base *, const char *, int);
60static void client_send_identify(const char *, const char *);
61static void client_signal(int);
62static void client_dispatch(struct imsg *, void *);
63static void client_dispatch_attached(struct imsg *);
64static void client_dispatch_wait(struct imsg *);
65static const char *client_exit_message(void);
66
67/*
68 * Get server create lock. If already held then server start is happening in
69 * another client, so block until the lock is released and return -2 to
70 * retry. Return -1 on failure to continue and start the server anyway.
71 */
72static int
73client_get_lock(char *lockfile)
74{
75 int lockfd;
76
77 log_debug("lock file is %s", lockfile);
78
79 if ((lockfd = open(lockfile, O_WRONLY|O_CREAT, 0600)) == -1) {
80 log_debug("open failed: %s", strerror(errno));
81 return (-1);
82 }
83
84 if (flock(lockfd, LOCK_EX|LOCK_NB) == -1) {
85 log_debug("flock failed: %s", strerror(errno));
86 if (errno != EAGAIN)
87 return (lockfd);
88 while (flock(lockfd, LOCK_EX) == -1 && errno == EINTR)
89 /* nothing */;
90 close(lockfd);
91 return (-2);
92 }
93 log_debug("flock succeeded");
94
95 return (lockfd);
96}
97
98/* Connect client to server. */
99static int
100client_connect(struct event_base *base, const char *path, int start_server)
101{
102 struct sockaddr_un sa;
103 size_t size;
104 int fd, lockfd = -1, locked = 0;
105 char *lockfile = NULL;
106
107 memset(&sa, 0, sizeof sa);
108 sa.sun_family = AF_UNIX;
109 size = strlcpy(sa.sun_path, path, sizeof sa.sun_path);
110 if (size >= sizeof sa.sun_path) {
111 errno = ENAMETOOLONG;
112 return (-1);
113 }
114 log_debug("socket is %s", path);
115
116retry:
117 if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
118 return (-1);
119
120 log_debug("trying connect");
121 if (connect(fd, (struct sockaddr *)&sa, sizeof sa) == -1) {
122 log_debug("connect failed: %s", strerror(errno));
123 if (errno != ECONNREFUSED && errno != ENOENT)
124 goto failed;
125 if (!start_server)
126 goto failed;
127 close(fd);
128
129 if (!locked) {
130 xasprintf(&lockfile, "%s.lock", path);
131 if ((lockfd = client_get_lock(lockfile)) < 0) {
132 log_debug("didn't get lock (%d)", lockfd);
133
134 free(lockfile);
135 lockfile = NULL;
136
137 if (lockfd == -2)
138 goto retry;
139 }
140 log_debug("got lock (%d)", lockfd);
141
142 /*
143 * Always retry at least once, even if we got the lock,
144 * because another client could have taken the lock,
145 * started the server and released the lock between our
146 * connect() and flock().
147 */
148 locked = 1;
149 goto retry;
150 }
151
152 if (lockfd >= 0 && unlink(path) != 0 && errno != ENOENT) {
153 free(lockfile);
154 close(lockfd);
155 return (-1);
156 }
157 fd = server_start(client_proc, base, lockfd, lockfile);
158 }
159
160 if (locked && lockfd >= 0) {
161 free(lockfile);
162 close(lockfd);
163 }
164 setblocking(fd, 0);
165 return (fd);
166
167failed:
168 if (locked) {
169 free(lockfile);
170 close(lockfd);
171 }
172 close(fd);
173 return (-1);
174}
175
176/* Get exit string from reason number. */
177const char *
178client_exit_message(void)
179{
180 static char msg[256];
181
182 switch (client_exitreason) {
183 case CLIENT_EXIT_NONE:
184 break;
185 case CLIENT_EXIT_DETACHED:
186 if (client_exitsession != NULL) {
187 xsnprintf(msg, sizeof msg, "detached "
188 "(from session %s)", client_exitsession);
189 return (msg);
190 }
191 return ("detached");
192 case CLIENT_EXIT_DETACHED_HUP:
193 if (client_exitsession != NULL) {
194 xsnprintf(msg, sizeof msg, "detached and SIGHUP "
195 "(from session %s)", client_exitsession);
196 return (msg);
197 }
198 return ("detached and SIGHUP");
199 case CLIENT_EXIT_LOST_TTY:
200 return ("lost tty");
201 case CLIENT_EXIT_TERMINATED:
202 return ("terminated");
203 case CLIENT_EXIT_LOST_SERVER:
204 return ("server exited unexpectedly");
205 case CLIENT_EXIT_EXITED:
206 return ("exited");
207 case CLIENT_EXIT_SERVER_EXITED:
208 return ("server exited");
209 }
210 return ("unknown reason");
211}
212
213/* Exit if all streams flushed. */
214static void
215client_exit(void)
216{
217 struct client_file *cf;
218 size_t left;
219 int waiting = 0;
220
221 RB_FOREACH (cf, client_files, &client_files) {
222 if (cf->event == NULL)
223 continue;
224 left = EVBUFFER_LENGTH(cf->event->output);
225 if (left != 0) {
226 waiting++;
227 log_debug("file %u %zu bytes left", cf->stream, left);
228 }
229 }
230 if (waiting == 0)
231 proc_exit(client_proc);
232}
233
234/* Client main loop. */
235int
236client_main(struct event_base *base, int argc, char **argv, int flags)
237{
238 struct cmd_parse_result *pr;
239 struct cmd *cmd;
240 struct msg_command *data;
241 int cmdflags, fd, i;
242 const char *ttynam, *cwd;
243 pid_t ppid;
244 enum msgtype msg;
245 struct termios tio, saved_tio;
246 size_t size;
247
248 /* Ignore SIGCHLD now or daemon() in the server will leave a zombie. */
249 signal(SIGCHLD, SIG_IGN);
250
251 /* Save the flags. */
252 client_flags = flags;
253
254 /* Set up the initial command. */
255 cmdflags = 0;
256 if (shell_command != NULL) {
257 msg = MSG_SHELL;
258 cmdflags = CMD_STARTSERVER;
259 } else if (argc == 0) {
260 msg = MSG_COMMAND;
261 cmdflags = CMD_STARTSERVER;
262 } else {
263 msg = MSG_COMMAND;
264
265 /*
266 * It sucks parsing the command string twice (in client and
267 * later in server) but it is necessary to get the start server
268 * flag.
269 */
270 pr = cmd_parse_from_arguments(argc, argv, NULL);
271 if (pr->status == CMD_PARSE_SUCCESS) {
272 TAILQ_FOREACH(cmd, &pr->cmdlist->list, qentry) {
273 if (cmd->entry->flags & CMD_STARTSERVER)
274 cmdflags |= CMD_STARTSERVER;
275 }
276 cmd_list_free(pr->cmdlist);
277 } else
278 free(pr->error);
279 }
280
281 /* Create client process structure (starts logging). */
282 client_proc = proc_start("client");
283 proc_set_signals(client_proc, client_signal);
284
285 /* Initialize the client socket and start the server. */
286 fd = client_connect(base, socket_path, cmdflags & CMD_STARTSERVER);
287 if (fd == -1) {
288 if (errno == ECONNREFUSED) {
289 fprintf(stderr, "no server running on %s\n",
290 socket_path);
291 } else {
292 fprintf(stderr, "error connecting to %s (%s)\n",
293 socket_path, strerror(errno));
294 }
295 return (1);
296 }
297 client_peer = proc_add_peer(client_proc, fd, client_dispatch, NULL);
298
299 /* Save these before pledge(). */
300 if ((cwd = find_cwd()) == NULL && (cwd = find_home()) == NULL)
301 cwd = "/";
302 if ((ttynam = ttyname(STDIN_FILENO)) == NULL)
303 ttynam = "";
304
305 /*
306 * Drop privileges for client. "proc exec" is needed for -c and for
307 * locking (which uses system(3)).
308 *
309 * "tty" is needed to restore termios(4) and also for some reason -CC
310 * does not work properly without it (input is not recognised).
311 *
312 * "sendfd" is dropped later in client_dispatch_wait().
313 */
314 if (pledge(
315 "stdio rpath wpath cpath unix sendfd proc exec tty",
316 NULL) != 0)
317 fatal("pledge failed");
318
319 /* Free stuff that is not used in the client. */
320 if (ptm_fd != -1)
321 close(ptm_fd);
322 options_free(global_options);
323 options_free(global_s_options);
324 options_free(global_w_options);
325 environ_free(global_environ);
326
327 /* Set up control mode. */
328 if (client_flags & CLIENT_CONTROLCONTROL) {
329 if (tcgetattr(STDIN_FILENO, &saved_tio) != 0) {
330 fprintf(stderr, "tcgetattr failed: %s\n",
331 strerror(errno));
332 return (1);
333 }
334 cfmakeraw(&tio);
335 tio.c_iflag = ICRNL|IXANY;
336 tio.c_oflag = OPOST|ONLCR;
337#ifdef NOKERNINFO
338 tio.c_lflag = NOKERNINFO;
339#endif
340 tio.c_cflag = CREAD|CS8|HUPCL;
341 tio.c_cc[VMIN] = 1;
342 tio.c_cc[VTIME] = 0;
343 cfsetispeed(&tio, cfgetispeed(&saved_tio));
344 cfsetospeed(&tio, cfgetospeed(&saved_tio));
345 tcsetattr(STDIN_FILENO, TCSANOW, &tio);
346 }
347
348 /* Send identify messages. */
349 client_send_identify(ttynam, cwd);
350
351 /* Send first command. */
352 if (msg == MSG_COMMAND) {
353 /* How big is the command? */
354 size = 0;
355 for (i = 0; i < argc; i++)
356 size += strlen(argv[i]) + 1;
357 if (size > MAX_IMSGSIZE - (sizeof *data)) {
358 fprintf(stderr, "command too long\n");
359 return (1);
360 }
361 data = xmalloc((sizeof *data) + size);
362
363 /* Prepare command for server. */
364 data->argc = argc;
365 if (cmd_pack_argv(argc, argv, (char *)(data + 1), size) != 0) {
366 fprintf(stderr, "command too long\n");
367 free(data);
368 return (1);
369 }
370 size += sizeof *data;
371
372 /* Send the command. */
373 if (proc_send(client_peer, msg, -1, data, size) != 0) {
374 fprintf(stderr, "failed to send command\n");
375 free(data);
376 return (1);
377 }
378 free(data);
379 } else if (msg == MSG_SHELL)
380 proc_send(client_peer, msg, -1, NULL, 0);
381
382 /* Start main loop. */
383 proc_loop(client_proc, NULL);
384
385 /* Run command if user requested exec, instead of exiting. */
386 if (client_exittype == MSG_EXEC) {
387 if (client_flags & CLIENT_CONTROLCONTROL)
388 tcsetattr(STDOUT_FILENO, TCSAFLUSH, &saved_tio);
389 client_exec(client_execshell, client_execcmd);
390 }
391
392 /* Print the exit message, if any, and exit. */
393 if (client_attached) {
394 if (client_exitreason != CLIENT_EXIT_NONE)
395 printf("[%s]\n", client_exit_message());
396
397 ppid = getppid();
398 if (client_exittype == MSG_DETACHKILL && ppid > 1)
399 kill(ppid, SIGHUP);
400 } else if (client_flags & CLIENT_CONTROLCONTROL) {
401 if (client_exitreason != CLIENT_EXIT_NONE)
402 printf("%%exit %s\n", client_exit_message());
403 else
404 printf("%%exit\n");
405 printf("\033\\");
406 tcsetattr(STDOUT_FILENO, TCSAFLUSH, &saved_tio);
407 } else if (client_exitreason != CLIENT_EXIT_NONE)
408 fprintf(stderr, "%s\n", client_exit_message());
409 setblocking(STDIN_FILENO, 1);
410 return (client_exitval);
411}
412
413/* Send identify messages to server. */
414static void
415client_send_identify(const char *ttynam, const char *cwd)
416{
417 const char *s;
418 char **ss;
419 size_t sslen;
420 int fd, flags = client_flags;
421 pid_t pid;
422
423 proc_send(client_peer, MSG_IDENTIFY_FLAGS, -1, &flags, sizeof flags);
424
425 if ((s = getenv("TERM")) == NULL)
426 s = "";
427 proc_send(client_peer, MSG_IDENTIFY_TERM, -1, s, strlen(s) + 1);
428
429 proc_send(client_peer, MSG_IDENTIFY_TTYNAME, -1, ttynam,
430 strlen(ttynam) + 1);
431 proc_send(client_peer, MSG_IDENTIFY_CWD, -1, cwd, strlen(cwd) + 1);
432
433 if ((fd = dup(STDIN_FILENO)) == -1)
434 fatal("dup failed");
435 proc_send(client_peer, MSG_IDENTIFY_STDIN, fd, NULL, 0);
436
437 pid = getpid();
438 proc_send(client_peer, MSG_IDENTIFY_CLIENTPID, -1, &pid, sizeof pid);
439
440 for (ss = environ; *ss != NULL; ss++) {
441 sslen = strlen(*ss) + 1;
442 if (sslen > MAX_IMSGSIZE - IMSG_HEADER_SIZE)
443 continue;
444 proc_send(client_peer, MSG_IDENTIFY_ENVIRON, -1, *ss, sslen);
445 }
446
447 proc_send(client_peer, MSG_IDENTIFY_DONE, -1, NULL, 0);
448}
449
450/* File write error callback. */
451static void
452client_write_error_callback(__unused struct bufferevent *bev,
453 __unused short what, void *arg)
454{
455 struct client_file *cf = arg;
456
457 log_debug("write error file %d", cf->stream);
458
459 bufferevent_free(cf->event);
460 cf->event = NULL;
461
462 close(cf->fd);
463 cf->fd = -1;
464
465 if (client_exitflag)
466 client_exit();
467}
468
469/* File write callback. */
470static void
471client_write_callback(__unused struct bufferevent *bev, void *arg)
472{
473 struct client_file *cf = arg;
474
475 if (cf->closed && EVBUFFER_LENGTH(cf->event->output) == 0) {
476 bufferevent_free(cf->event);
477 close(cf->fd);
478 RB_REMOVE(client_files, &client_files, cf);
479 file_free(cf);
480 }
481
482 if (client_exitflag)
483 client_exit();
484}
485
486/* Open write file. */
487static void
488client_write_open(void *data, size_t datalen)
489{
490 struct msg_write_open *msg = data;
491 const char *path;
492 struct msg_write_ready reply;
493 struct client_file find, *cf;
494 const int flags = O_NONBLOCK|O_WRONLY|O_CREAT;
495 int error = 0;
496
497 if (datalen < sizeof *msg)
498 fatalx("bad MSG_WRITE_OPEN size");
499 if (datalen == sizeof *msg)
500 path = "-";
501 else
502 path = (const char *)(msg + 1);
503 log_debug("open write file %d %s", msg->stream, path);
504
505 find.stream = msg->stream;
506 if ((cf = RB_FIND(client_files, &client_files, &find)) == NULL) {
507 cf = file_create(NULL, msg->stream, NULL, NULL);
508 RB_INSERT(client_files, &client_files, cf);
509 } else {
510 error = EBADF;
511 goto reply;
512 }
513 if (cf->closed) {
514 error = EBADF;
515 goto reply;
516 }
517
518 cf->fd = -1;
519 if (msg->fd == -1)
520 cf->fd = open(path, msg->flags|flags, 0644);
521 else {
522 if (msg->fd != STDOUT_FILENO && msg->fd != STDERR_FILENO)
523 errno = EBADF;
524 else {
525 cf->fd = dup(msg->fd);
526 if (client_flags & CLIENT_CONTROL)
527 close(msg->fd); /* can only be used once */
528 }
529 }
530 if (cf->fd == -1) {
531 error = errno;
532 goto reply;
533 }
534
535 cf->event = bufferevent_new(cf->fd, NULL, client_write_callback,
536 client_write_error_callback, cf);
537 bufferevent_enable(cf->event, EV_WRITE);
538 goto reply;
539
540reply:
541 reply.stream = msg->stream;
542 reply.error = error;
543 proc_send(client_peer, MSG_WRITE_READY, -1, &reply, sizeof reply);
544}
545
546/* Write to client file. */
547static void
548client_write_data(void *data, size_t datalen)
549{
550 struct msg_write_data *msg = data;
551 struct client_file find, *cf;
552 size_t size = datalen - sizeof *msg;
553
554 if (datalen < sizeof *msg)
555 fatalx("bad MSG_WRITE size");
556 find.stream = msg->stream;
557 if ((cf = RB_FIND(client_files, &client_files, &find)) == NULL)
558 fatalx("unknown stream number");
559 log_debug("write %zu to file %d", size, cf->stream);
560
561 if (cf->event != NULL)
562 bufferevent_write(cf->event, msg + 1, size);
563}
564
565/* Close client file. */
566static void
567client_write_close(void *data, size_t datalen)
568{
569 struct msg_write_close *msg = data;
570 struct client_file find, *cf;
571
572 if (datalen != sizeof *msg)
573 fatalx("bad MSG_WRITE_CLOSE size");
574 find.stream = msg->stream;
575 if ((cf = RB_FIND(client_files, &client_files, &find)) == NULL)
576 fatalx("unknown stream number");
577 log_debug("close file %d", cf->stream);
578
579 if (cf->event == NULL || EVBUFFER_LENGTH(cf->event->output) == 0) {
580 if (cf->event != NULL)
581 bufferevent_free(cf->event);
582 if (cf->fd != -1)
583 close(cf->fd);
584 RB_REMOVE(client_files, &client_files, cf);
585 file_free(cf);
586 }
587}
588
589/* File read callback. */
590static void
591client_read_callback(__unused struct bufferevent *bev, void *arg)
592{
593 struct client_file *cf = arg;
594 void *bdata;
595 size_t bsize;
596 struct msg_read_data *msg;
597 size_t msglen;
598
599 msg = xmalloc(sizeof *msg);
600 for (;;) {
601 bdata = EVBUFFER_DATA(cf->event->input);
602 bsize = EVBUFFER_LENGTH(cf->event->input);
603
604 if (bsize == 0)
605 break;
606 if (bsize > MAX_IMSGSIZE - IMSG_HEADER_SIZE - sizeof *msg)
607 bsize = MAX_IMSGSIZE - IMSG_HEADER_SIZE - sizeof *msg;
608 log_debug("read %zu from file %d", bsize, cf->stream);
609
610 msglen = (sizeof *msg) + bsize;
611 msg = xrealloc(msg, msglen);
612 msg->stream = cf->stream;
613 memcpy(msg + 1, bdata, bsize);
614 proc_send(client_peer, MSG_READ, -1, msg, msglen);
615
616 evbuffer_drain(cf->event->input, bsize);
617 }
618 free(msg);
619}
620
621/* File read error callback. */
622static void
623client_read_error_callback(__unused struct bufferevent *bev,
624 __unused short what, void *arg)
625{
626 struct client_file *cf = arg;
627 struct msg_read_done msg;
628
629 log_debug("read error file %d", cf->stream);
630
631 msg.stream = cf->stream;
632 msg.error = 0;
633 proc_send(client_peer, MSG_READ_DONE, -1, &msg, sizeof msg);
634
635 bufferevent_free(cf->event);
636 close(cf->fd);
637 RB_REMOVE(client_files, &client_files, cf);
638 file_free(cf);
639}
640
641/* Open read file. */
642static void
643client_read_open(void *data, size_t datalen)
644{
645 struct msg_read_open *msg = data;
646 const char *path;
647 struct msg_read_done reply;
648 struct client_file find, *cf;
649 const int flags = O_NONBLOCK|O_RDONLY;
650 int error = 0;
651
652 if (datalen < sizeof *msg)
653 fatalx("bad MSG_READ_OPEN size");
654 if (datalen == sizeof *msg)
655 path = "-";
656 else
657 path = (const char *)(msg + 1);
658 log_debug("open read file %d %s", msg->stream, path);
659
660 find.stream = msg->stream;
661 if ((cf = RB_FIND(client_files, &client_files, &find)) == NULL) {
662 cf = file_create(NULL, msg->stream, NULL, NULL);
663 RB_INSERT(client_files, &client_files, cf);
664 } else {
665 error = EBADF;
666 goto reply;
667 }
668 if (cf->closed) {
669 error = EBADF;
670 goto reply;
671 }
672
673 cf->fd = -1;
674 if (msg->fd == -1)
675 cf->fd = open(path, flags);
676 else {
677 if (msg->fd != STDIN_FILENO)
678 errno = EBADF;
679 else {
680 cf->fd = dup(msg->fd);
681 close(msg->fd); /* can only be used once */
682 }
683 }
684 if (cf->fd == -1) {
685 error = errno;
686 goto reply;
687 }
688
689 cf->event = bufferevent_new(cf->fd, client_read_callback, NULL,
690 client_read_error_callback, cf);
691 bufferevent_enable(cf->event, EV_READ);
692 return;
693
694reply:
695 reply.stream = msg->stream;
696 reply.error = error;
697 proc_send(client_peer, MSG_READ_DONE, -1, &reply, sizeof reply);
698}
699
700/* Run command in shell; used for -c. */
701static __dead void
702client_exec(const char *shell, const char *shellcmd)
703{
704 const char *name, *ptr;
705 char *argv0;
706
707 log_debug("shell %s, command %s", shell, shellcmd);
708
709 ptr = strrchr(shell, '/');
710 if (ptr != NULL && *(ptr + 1) != '\0')
711 name = ptr + 1;
712 else
713 name = shell;
714 if (client_flags & CLIENT_LOGIN)
715 xasprintf(&argv0, "-%s", name);
716 else
717 xasprintf(&argv0, "%s", name);
718 setenv("SHELL", shell, 1);
719
720 proc_clear_signals(client_proc, 1);
721
722 setblocking(STDIN_FILENO, 1);
723 setblocking(STDOUT_FILENO, 1);
724 setblocking(STDERR_FILENO, 1);
725 closefrom(STDERR_FILENO + 1);
726
727 execl(shell, argv0, "-c", shellcmd, (char *) NULL);
728 fatal("execl failed");
729}
730
731/* Callback to handle signals in the client. */
732static void
733client_signal(int sig)
734{
735 struct sigaction sigact;
736 int status;
737
738 if (sig == SIGCHLD)
739 waitpid(WAIT_ANY, &status, WNOHANG);
740 else if (!client_attached) {
741 if (sig == SIGTERM)
742 proc_exit(client_proc);
743 } else {
744 switch (sig) {
745 case SIGHUP:
746 client_exitreason = CLIENT_EXIT_LOST_TTY;
747 client_exitval = 1;
748 proc_send(client_peer, MSG_EXITING, -1, NULL, 0);
749 break;
750 case SIGTERM:
751 client_exitreason = CLIENT_EXIT_TERMINATED;
752 client_exitval = 1;
753 proc_send(client_peer, MSG_EXITING, -1, NULL, 0);
754 break;
755 case SIGWINCH:
756 proc_send(client_peer, MSG_RESIZE, -1, NULL, 0);
757 break;
758 case SIGCONT:
759 memset(&sigact, 0, sizeof sigact);
760 sigemptyset(&sigact.sa_mask);
761 sigact.sa_flags = SA_RESTART;
762 sigact.sa_handler = SIG_IGN;
763 if (sigaction(SIGTSTP, &sigact, NULL) != 0)
764 fatal("sigaction failed");
765 proc_send(client_peer, MSG_WAKEUP, -1, NULL, 0);
766 break;
767 }
768 }
769}
770
771/* Callback for client read events. */
772static void
773client_dispatch(struct imsg *imsg, __unused void *arg)
774{
775 if (imsg == NULL) {
776 client_exitreason = CLIENT_EXIT_LOST_SERVER;
777 client_exitval = 1;
778 proc_exit(client_proc);
779 return;
780 }
781
782 if (client_attached)
783 client_dispatch_attached(imsg);
784 else
785 client_dispatch_wait(imsg);
786}
787
788/* Dispatch imsgs when in wait state (before MSG_READY). */
789static void
790client_dispatch_wait(struct imsg *imsg)
791{
792 char *data;
793 ssize_t datalen;
794 int retval;
795 static int pledge_applied;
796
797 /*
798 * "sendfd" is no longer required once all of the identify messages
799 * have been sent. We know the server won't send us anything until that
800 * point (because we don't ask it to), so we can drop "sendfd" once we
801 * get the first message from the server.
802 */
803 if (!pledge_applied) {
804 if (pledge(
805 "stdio rpath wpath cpath unix proc exec tty",
806 NULL) != 0)
807 fatal("pledge failed");
808 pledge_applied = 1;
809 }
810
811 data = imsg->data;
812 datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
813
814 switch (imsg->hdr.type) {
815 case MSG_EXIT:
816 case MSG_SHUTDOWN:
817 if (datalen != sizeof retval && datalen != 0)
818 fatalx("bad MSG_EXIT size");
819 if (datalen == sizeof retval) {
820 memcpy(&retval, data, sizeof retval);
821 client_exitval = retval;
822 }
823 client_exitflag = 1;
824 client_exit();
825 break;
826 case MSG_READY:
827 if (datalen != 0)
828 fatalx("bad MSG_READY size");
829
830 client_attached = 1;
831 proc_send(client_peer, MSG_RESIZE, -1, NULL, 0);
832 break;
833 case MSG_VERSION:
834 if (datalen != 0)
835 fatalx("bad MSG_VERSION size");
836
837 fprintf(stderr, "protocol version mismatch "
838 "(client %d, server %u)\n", PROTOCOL_VERSION,
839 imsg->hdr.peerid & 0xff);
840 client_exitval = 1;
841 proc_exit(client_proc);
842 break;
843 case MSG_SHELL:
844 if (datalen == 0 || data[datalen - 1] != '\0')
845 fatalx("bad MSG_SHELL string");
846
847 client_exec(data, shell_command);
848 /* NOTREACHED */
849 case MSG_DETACH:
850 case MSG_DETACHKILL:
851 proc_send(client_peer, MSG_EXITING, -1, NULL, 0);
852 break;
853 case MSG_EXITED:
854 proc_exit(client_proc);
855 break;
856 case MSG_READ_OPEN:
857 client_read_open(data, datalen);
858 break;
859 case MSG_WRITE_OPEN:
860 client_write_open(data, datalen);
861 break;
862 case MSG_WRITE:
863 client_write_data(data, datalen);
864 break;
865 case MSG_WRITE_CLOSE:
866 client_write_close(data, datalen);
867 break;
868 case MSG_OLDSTDERR:
869 case MSG_OLDSTDIN:
870 case MSG_OLDSTDOUT:
871 fprintf(stderr, "server version is too old for client\n");
872 proc_exit(client_proc);
873 break;
874 }
875}
876
877/* Dispatch imsgs in attached state (after MSG_READY). */
878static void
879client_dispatch_attached(struct imsg *imsg)
880{
881 struct sigaction sigact;
882 char *data;
883 ssize_t datalen;
884
885 data = imsg->data;
886 datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
887
888 switch (imsg->hdr.type) {
889 case MSG_DETACH:
890 case MSG_DETACHKILL:
891 if (datalen == 0 || data[datalen - 1] != '\0')
892 fatalx("bad MSG_DETACH string");
893
894 client_exitsession = xstrdup(data);
895 client_exittype = imsg->hdr.type;
896 if (imsg->hdr.type == MSG_DETACHKILL)
897 client_exitreason = CLIENT_EXIT_DETACHED_HUP;
898 else
899 client_exitreason = CLIENT_EXIT_DETACHED;
900 proc_send(client_peer, MSG_EXITING, -1, NULL, 0);
901 break;
902 case MSG_EXEC:
903 if (datalen == 0 || data[datalen - 1] != '\0' ||
904 strlen(data) + 1 == (size_t)datalen)
905 fatalx("bad MSG_EXEC string");
906 client_execcmd = xstrdup(data);
907 client_execshell = xstrdup(data + strlen(data) + 1);
908
909 client_exittype = imsg->hdr.type;
910 proc_send(client_peer, MSG_EXITING, -1, NULL, 0);
911 break;
912 case MSG_EXIT:
913 if (datalen != 0 && datalen != sizeof (int))
914 fatalx("bad MSG_EXIT size");
915
916 proc_send(client_peer, MSG_EXITING, -1, NULL, 0);
917 client_exitreason = CLIENT_EXIT_EXITED;
918 break;
919 case MSG_EXITED:
920 if (datalen != 0)
921 fatalx("bad MSG_EXITED size");
922
923 proc_exit(client_proc);
924 break;
925 case MSG_SHUTDOWN:
926 if (datalen != 0)
927 fatalx("bad MSG_SHUTDOWN size");
928
929 proc_send(client_peer, MSG_EXITING, -1, NULL, 0);
930 client_exitreason = CLIENT_EXIT_SERVER_EXITED;
931 client_exitval = 1;
932 break;
933 case MSG_SUSPEND:
934 if (datalen != 0)
935 fatalx("bad MSG_SUSPEND size");
936
937 memset(&sigact, 0, sizeof sigact);
938 sigemptyset(&sigact.sa_mask);
939 sigact.sa_flags = SA_RESTART;
940 sigact.sa_handler = SIG_DFL;
941 if (sigaction(SIGTSTP, &sigact, NULL) != 0)
942 fatal("sigaction failed");
943 kill(getpid(), SIGTSTP);
944 break;
945 case MSG_LOCK:
946 if (datalen == 0 || data[datalen - 1] != '\0')
947 fatalx("bad MSG_LOCK string");
948
949 system(data);
950 proc_send(client_peer, MSG_UNLOCK, -1, NULL, 0);
951 break;
952 }
953}
954