Coverage Report

Created: 2024-02-25 06:30

/src/tmux/client.c
Line
Count
Source (jump to first uncovered line)
1
/* $OpenBSD$ */
2
3
/*
4
 * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
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/uio.h>
22
#include <sys/un.h>
23
#include <sys/wait.h>
24
#include <sys/file.h>
25
26
#include <errno.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
35
static struct tmuxproc  *client_proc;
36
static struct tmuxpeer  *client_peer;
37
static uint64_t    client_flags;
38
static int     client_suspended;
39
static enum {
40
  CLIENT_EXIT_NONE,
41
  CLIENT_EXIT_DETACHED,
42
  CLIENT_EXIT_DETACHED_HUP,
43
  CLIENT_EXIT_LOST_TTY,
44
  CLIENT_EXIT_TERMINATED,
45
  CLIENT_EXIT_LOST_SERVER,
46
  CLIENT_EXIT_EXITED,
47
  CLIENT_EXIT_SERVER_EXITED,
48
  CLIENT_EXIT_MESSAGE_PROVIDED
49
} client_exitreason = CLIENT_EXIT_NONE;
50
static int     client_exitflag;
51
static int     client_exitval;
52
static enum msgtype  client_exittype;
53
static const char *client_exitsession;
54
static char   *client_exitmessage;
55
static const char *client_execshell;
56
static const char *client_execcmd;
57
static int     client_attached;
58
static struct client_files client_files = RB_INITIALIZER(&client_files);
59
60
static __dead void   client_exec(const char *,const char *);
61
static int     client_get_lock(char *);
62
static int     client_connect(struct event_base *, const char *,
63
           uint64_t);
64
static void    client_send_identify(const char *, const char *,
65
           char **, u_int, const char *, int);
66
static void    client_signal(int);
67
static void    client_dispatch(struct imsg *, void *);
68
static void    client_dispatch_attached(struct imsg *);
69
static void    client_dispatch_wait(struct imsg *);
70
static const char *client_exit_message(void);
71
72
/*
73
 * Get server create lock. If already held then server start is happening in
74
 * another client, so block until the lock is released and return -2 to
75
 * retry. Return -1 on failure to continue and start the server anyway.
76
 */
77
static int
78
client_get_lock(char *lockfile)
79
0
{
80
0
  int lockfd;
81
82
0
  log_debug("lock file is %s", lockfile);
83
84
0
  if ((lockfd = open(lockfile, O_WRONLY|O_CREAT, 0600)) == -1) {
85
0
    log_debug("open failed: %s", strerror(errno));
86
0
    return (-1);
87
0
  }
88
89
0
  if (flock(lockfd, LOCK_EX|LOCK_NB) == -1) {
90
0
    log_debug("flock failed: %s", strerror(errno));
91
0
    if (errno != EAGAIN)
92
0
      return (lockfd);
93
0
    while (flock(lockfd, LOCK_EX) == -1 && errno == EINTR)
94
0
      /* nothing */;
95
0
    close(lockfd);
96
0
    return (-2);
97
0
  }
98
0
  log_debug("flock succeeded");
99
100
0
  return (lockfd);
101
0
}
102
103
/* Connect client to server. */
104
static int
105
client_connect(struct event_base *base, const char *path, uint64_t flags)
106
0
{
107
0
  struct sockaddr_un  sa;
108
0
  size_t      size;
109
0
  int     fd, lockfd = -1, locked = 0;
110
0
  char           *lockfile = NULL;
111
112
0
  memset(&sa, 0, sizeof sa);
113
0
  sa.sun_family = AF_UNIX;
114
0
  size = strlcpy(sa.sun_path, path, sizeof sa.sun_path);
115
0
  if (size >= sizeof sa.sun_path) {
116
0
    errno = ENAMETOOLONG;
117
0
    return (-1);
118
0
  }
119
0
  log_debug("socket is %s", path);
120
121
0
retry:
122
0
  if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
123
0
    return (-1);
124
125
0
  log_debug("trying connect");
126
0
  if (connect(fd, (struct sockaddr *)&sa, sizeof sa) == -1) {
127
0
    log_debug("connect failed: %s", strerror(errno));
128
0
    if (errno != ECONNREFUSED && errno != ENOENT)
129
0
      goto failed;
130
0
    if (flags & CLIENT_NOSTARTSERVER)
131
0
      goto failed;
132
0
    if (~flags & CLIENT_STARTSERVER)
133
0
      goto failed;
134
0
    close(fd);
135
136
0
    if (!locked) {
137
0
      xasprintf(&lockfile, "%s.lock", path);
138
0
      if ((lockfd = client_get_lock(lockfile)) < 0) {
139
0
        log_debug("didn't get lock (%d)", lockfd);
140
141
0
        free(lockfile);
142
0
        lockfile = NULL;
143
144
0
        if (lockfd == -2)
145
0
          goto retry;
146
0
      }
147
0
      log_debug("got lock (%d)", lockfd);
148
149
      /*
150
       * Always retry at least once, even if we got the lock,
151
       * because another client could have taken the lock,
152
       * started the server and released the lock between our
153
       * connect() and flock().
154
       */
155
0
      locked = 1;
156
0
      goto retry;
157
0
    }
158
159
0
    if (lockfd >= 0 && unlink(path) != 0 && errno != ENOENT) {
160
0
      free(lockfile);
161
0
      close(lockfd);
162
0
      return (-1);
163
0
    }
164
0
    fd = server_start(client_proc, flags, base, lockfd, lockfile);
165
0
  }
166
167
0
  if (locked && lockfd >= 0) {
168
0
    free(lockfile);
169
0
    close(lockfd);
170
0
  }
171
0
  setblocking(fd, 0);
172
0
  return (fd);
173
174
0
failed:
175
0
  if (locked) {
176
0
    free(lockfile);
177
0
    close(lockfd);
178
0
  }
179
0
  close(fd);
180
0
  return (-1);
181
0
}
182
183
/* Get exit string from reason number. */
184
const char *
185
client_exit_message(void)
186
0
{
187
0
  static char msg[256];
188
189
0
  switch (client_exitreason) {
190
0
  case CLIENT_EXIT_NONE:
191
0
    break;
192
0
  case CLIENT_EXIT_DETACHED:
193
0
    if (client_exitsession != NULL) {
194
0
      xsnprintf(msg, sizeof msg, "detached "
195
0
          "(from session %s)", client_exitsession);
196
0
      return (msg);
197
0
    }
198
0
    return ("detached");
199
0
  case CLIENT_EXIT_DETACHED_HUP:
200
0
    if (client_exitsession != NULL) {
201
0
      xsnprintf(msg, sizeof msg, "detached and SIGHUP "
202
0
          "(from session %s)", client_exitsession);
203
0
      return (msg);
204
0
    }
205
0
    return ("detached and SIGHUP");
206
0
  case CLIENT_EXIT_LOST_TTY:
207
0
    return ("lost tty");
208
0
  case CLIENT_EXIT_TERMINATED:
209
0
    return ("terminated");
210
0
  case CLIENT_EXIT_LOST_SERVER:
211
0
    return ("server exited unexpectedly");
212
0
  case CLIENT_EXIT_EXITED:
213
0
    return ("exited");
214
0
  case CLIENT_EXIT_SERVER_EXITED:
215
0
    return ("server exited");
216
0
  case CLIENT_EXIT_MESSAGE_PROVIDED:
217
0
    return (client_exitmessage);
218
0
  }
219
0
  return ("unknown reason");
220
0
}
221
222
/* Exit if all streams flushed. */
223
static void
224
client_exit(void)
225
0
{
226
0
  if (!file_write_left(&client_files))
227
0
    proc_exit(client_proc);
228
0
}
229
230
/* Client main loop. */
231
int
232
client_main(struct event_base *base, int argc, char **argv, uint64_t flags,
233
    int feat)
234
0
{
235
0
  struct cmd_parse_result *pr;
236
0
  struct msg_command  *data;
237
0
  int      fd, i;
238
0
  const char    *ttynam, *termname, *cwd;
239
0
  pid_t      ppid;
240
0
  enum msgtype     msg;
241
0
  struct termios     tio, saved_tio;
242
0
  size_t       size, linesize = 0;
243
0
  ssize_t      linelen;
244
0
  char      *line = NULL, **caps = NULL, *cause;
245
0
  u_int      ncaps = 0;
246
0
  struct args_value *values;
247
248
  /* Set up the initial command. */
249
0
  if (shell_command != NULL) {
250
0
    msg = MSG_SHELL;
251
0
    flags |= CLIENT_STARTSERVER;
252
0
  } else if (argc == 0) {
253
0
    msg = MSG_COMMAND;
254
0
    flags |= CLIENT_STARTSERVER;
255
0
  } else {
256
0
    msg = MSG_COMMAND;
257
258
    /*
259
     * It's annoying parsing the command string twice (in client
260
     * and later in server) but it is necessary to get the start
261
     * server flag.
262
     */
263
0
    values = args_from_vector(argc, argv);
264
0
    pr = cmd_parse_from_arguments(values, argc, NULL);
265
0
    if (pr->status == CMD_PARSE_SUCCESS) {
266
0
      if (cmd_list_any_have(pr->cmdlist, CMD_STARTSERVER))
267
0
        flags |= CLIENT_STARTSERVER;
268
0
      cmd_list_free(pr->cmdlist);
269
0
    } else
270
0
      free(pr->error);
271
0
    args_free_values(values, argc);
272
0
    free(values);
273
0
  }
274
275
  /* Create client process structure (starts logging). */
276
0
  client_proc = proc_start("client");
277
0
  proc_set_signals(client_proc, client_signal);
278
279
  /* Save the flags. */
280
0
  client_flags = flags;
281
0
  log_debug("flags are %#llx", (unsigned long long)client_flags);
282
283
  /* Initialize the client socket and start the server. */
284
#ifdef HAVE_SYSTEMD
285
  if (systemd_activated()) {
286
    /* socket-based activation, do not even try to be a client. */
287
    fd = server_start(client_proc, flags, base, 0, NULL);
288
  } else
289
#endif
290
0
  fd = client_connect(base, socket_path, client_flags);
291
0
  if (fd == -1) {
292
0
    if (errno == ECONNREFUSED) {
293
0
      fprintf(stderr, "no server running on %s\n",
294
0
          socket_path);
295
0
    } else {
296
0
      fprintf(stderr, "error connecting to %s (%s)\n",
297
0
          socket_path, strerror(errno));
298
0
    }
299
0
    return (1);
300
0
  }
301
0
  client_peer = proc_add_peer(client_proc, fd, client_dispatch, NULL);
302
303
  /* Save these before pledge(). */
304
0
  if ((cwd = find_cwd()) == NULL && (cwd = find_home()) == NULL)
305
0
    cwd = "/";
306
0
  if ((ttynam = ttyname(STDIN_FILENO)) == NULL)
307
0
    ttynam = "";
308
0
  if ((termname = getenv("TERM")) == NULL)
309
0
    termname = "";
310
311
  /*
312
   * Drop privileges for client. "proc exec" is needed for -c and for
313
   * locking (which uses system(3)).
314
   *
315
   * "tty" is needed to restore termios(4) and also for some reason -CC
316
   * does not work properly without it (input is not recognised).
317
   *
318
   * "sendfd" is dropped later in client_dispatch_wait().
319
   */
320
0
  if (pledge(
321
0
      "stdio rpath wpath cpath unix sendfd proc exec tty",
322
0
      NULL) != 0)
323
0
    fatal("pledge failed");
324
325
  /* Load terminfo entry if any. */
326
0
  if (isatty(STDIN_FILENO) &&
327
0
      *termname != '\0' &&
328
0
      tty_term_read_list(termname, STDIN_FILENO, &caps, &ncaps,
329
0
      &cause) != 0) {
330
0
    fprintf(stderr, "%s\n", cause);
331
0
    free(cause);
332
0
    return (1);
333
0
  }
334
335
  /* Free stuff that is not used in the client. */
336
0
  if (ptm_fd != -1)
337
0
    close(ptm_fd);
338
0
  options_free(global_options);
339
0
  options_free(global_s_options);
340
0
  options_free(global_w_options);
341
0
  environ_free(global_environ);
342
343
  /* Set up control mode. */
344
0
  if (client_flags & CLIENT_CONTROLCONTROL) {
345
0
    if (tcgetattr(STDIN_FILENO, &saved_tio) != 0) {
346
0
      fprintf(stderr, "tcgetattr failed: %s\n",
347
0
          strerror(errno));
348
0
      return (1);
349
0
    }
350
0
    cfmakeraw(&tio);
351
0
    tio.c_iflag = ICRNL|IXANY;
352
0
    tio.c_oflag = OPOST|ONLCR;
353
#ifdef NOKERNINFO
354
    tio.c_lflag = NOKERNINFO;
355
#endif
356
0
    tio.c_cflag = CREAD|CS8|HUPCL;
357
0
    tio.c_cc[VMIN] = 1;
358
0
    tio.c_cc[VTIME] = 0;
359
0
    cfsetispeed(&tio, cfgetispeed(&saved_tio));
360
0
    cfsetospeed(&tio, cfgetospeed(&saved_tio));
361
0
    tcsetattr(STDIN_FILENO, TCSANOW, &tio);
362
0
  }
363
364
  /* Send identify messages. */
365
0
  client_send_identify(ttynam, termname, caps, ncaps, cwd, feat);
366
0
  tty_term_free_list(caps, ncaps);
367
0
  proc_flush_peer(client_peer);
368
369
  /* Send first command. */
370
0
  if (msg == MSG_COMMAND) {
371
    /* How big is the command? */
372
0
    size = 0;
373
0
    for (i = 0; i < argc; i++)
374
0
      size += strlen(argv[i]) + 1;
375
0
    if (size > MAX_IMSGSIZE - (sizeof *data)) {
376
0
      fprintf(stderr, "command too long\n");
377
0
      return (1);
378
0
    }
379
0
    data = xmalloc((sizeof *data) + size);
380
381
    /* Prepare command for server. */
382
0
    data->argc = argc;
383
0
    if (cmd_pack_argv(argc, argv, (char *)(data + 1), size) != 0) {
384
0
      fprintf(stderr, "command too long\n");
385
0
      free(data);
386
0
      return (1);
387
0
    }
388
0
    size += sizeof *data;
389
390
    /* Send the command. */
391
0
    if (proc_send(client_peer, msg, -1, data, size) != 0) {
392
0
      fprintf(stderr, "failed to send command\n");
393
0
      free(data);
394
0
      return (1);
395
0
    }
396
0
    free(data);
397
0
  } else if (msg == MSG_SHELL)
398
0
    proc_send(client_peer, msg, -1, NULL, 0);
399
400
  /* Start main loop. */
401
0
  proc_loop(client_proc, NULL);
402
403
  /* Run command if user requested exec, instead of exiting. */
404
0
  if (client_exittype == MSG_EXEC) {
405
0
    if (client_flags & CLIENT_CONTROLCONTROL)
406
0
      tcsetattr(STDOUT_FILENO, TCSAFLUSH, &saved_tio);
407
0
    client_exec(client_execshell, client_execcmd);
408
0
  }
409
410
  /* Restore streams to blocking. */
411
0
  setblocking(STDIN_FILENO, 1);
412
0
  setblocking(STDOUT_FILENO, 1);
413
0
  setblocking(STDERR_FILENO, 1);
414
415
  /* Print the exit message, if any, and exit. */
416
0
  if (client_attached) {
417
0
    if (client_exitreason != CLIENT_EXIT_NONE)
418
0
      printf("[%s]\n", client_exit_message());
419
420
0
    ppid = getppid();
421
0
    if (client_exittype == MSG_DETACHKILL && ppid > 1)
422
0
      kill(ppid, SIGHUP);
423
0
  } else if (client_flags & CLIENT_CONTROL) {
424
0
    if (client_exitreason != CLIENT_EXIT_NONE)
425
0
      printf("%%exit %s\n", client_exit_message());
426
0
    else
427
0
      printf("%%exit\n");
428
0
    fflush(stdout);
429
0
    if (client_flags & CLIENT_CONTROL_WAITEXIT) {
430
0
      setvbuf(stdin, NULL, _IOLBF, 0);
431
0
      for (;;) {
432
0
        linelen = getline(&line, &linesize, stdin);
433
0
        if (linelen <= 1)
434
0
          break;
435
0
      }
436
0
      free(line);
437
0
    }
438
0
    if (client_flags & CLIENT_CONTROLCONTROL) {
439
0
      printf("\033\\");
440
0
      fflush(stdout);
441
0
      tcsetattr(STDOUT_FILENO, TCSAFLUSH, &saved_tio);
442
0
    }
443
0
  } else if (client_exitreason != CLIENT_EXIT_NONE)
444
0
    fprintf(stderr, "%s\n", client_exit_message());
445
0
  return (client_exitval);
446
0
}
447
448
/* Send identify messages to server. */
449
static void
450
client_send_identify(const char *ttynam, const char *termname, char **caps,
451
    u_int ncaps, const char *cwd, int feat)
452
0
{
453
0
  char  **ss;
454
0
  size_t    sslen;
455
0
  int   fd, flags = client_flags;
456
0
  pid_t   pid;
457
0
  u_int   i;
458
459
0
  proc_send(client_peer, MSG_IDENTIFY_FLAGS, -1, &flags, sizeof flags);
460
0
  proc_send(client_peer, MSG_IDENTIFY_LONGFLAGS, -1, &client_flags,
461
0
      sizeof client_flags);
462
463
0
  proc_send(client_peer, MSG_IDENTIFY_TERM, -1, termname,
464
0
      strlen(termname) + 1);
465
0
  proc_send(client_peer, MSG_IDENTIFY_FEATURES, -1, &feat, sizeof feat);
466
467
0
  proc_send(client_peer, MSG_IDENTIFY_TTYNAME, -1, ttynam,
468
0
      strlen(ttynam) + 1);
469
0
  proc_send(client_peer, MSG_IDENTIFY_CWD, -1, cwd, strlen(cwd) + 1);
470
471
0
  for (i = 0; i < ncaps; i++) {
472
0
    proc_send(client_peer, MSG_IDENTIFY_TERMINFO, -1,
473
0
        caps[i], strlen(caps[i]) + 1);
474
0
  }
475
476
0
  if ((fd = dup(STDIN_FILENO)) == -1)
477
0
    fatal("dup failed");
478
0
  proc_send(client_peer, MSG_IDENTIFY_STDIN, fd, NULL, 0);
479
0
  if ((fd = dup(STDOUT_FILENO)) == -1)
480
0
    fatal("dup failed");
481
0
  proc_send(client_peer, MSG_IDENTIFY_STDOUT, fd, NULL, 0);
482
483
0
  pid = getpid();
484
0
  proc_send(client_peer, MSG_IDENTIFY_CLIENTPID, -1, &pid, sizeof pid);
485
486
0
  for (ss = environ; *ss != NULL; ss++) {
487
0
    sslen = strlen(*ss) + 1;
488
0
    if (sslen > MAX_IMSGSIZE - IMSG_HEADER_SIZE)
489
0
      continue;
490
0
    proc_send(client_peer, MSG_IDENTIFY_ENVIRON, -1, *ss, sslen);
491
0
  }
492
493
0
  proc_send(client_peer, MSG_IDENTIFY_DONE, -1, NULL, 0);
494
0
}
495
496
/* Run command in shell; used for -c. */
497
static __dead void
498
client_exec(const char *shell, const char *shellcmd)
499
0
{
500
0
  const char  *name, *ptr;
501
0
  char    *argv0;
502
503
0
  log_debug("shell %s, command %s", shell, shellcmd);
504
505
0
  ptr = strrchr(shell, '/');
506
0
  if (ptr != NULL && *(ptr + 1) != '\0')
507
0
    name = ptr + 1;
508
0
  else
509
0
    name = shell;
510
0
  if (client_flags & CLIENT_LOGIN)
511
0
    xasprintf(&argv0, "-%s", name);
512
0
  else
513
0
    xasprintf(&argv0, "%s", name);
514
0
  setenv("SHELL", shell, 1);
515
516
0
  proc_clear_signals(client_proc, 1);
517
518
0
  setblocking(STDIN_FILENO, 1);
519
0
  setblocking(STDOUT_FILENO, 1);
520
0
  setblocking(STDERR_FILENO, 1);
521
0
  closefrom(STDERR_FILENO + 1);
522
523
0
  execl(shell, argv0, "-c", shellcmd, (char *) NULL);
524
0
  fatal("execl failed");
525
0
}
526
527
/* Callback to handle signals in the client. */
528
static void
529
client_signal(int sig)
530
0
{
531
0
  struct sigaction sigact;
532
0
  int    status;
533
0
  pid_t    pid;
534
535
0
  log_debug("%s: %s", __func__, strsignal(sig));
536
0
  if (sig == SIGCHLD) {
537
0
    for (;;) {
538
0
      pid = waitpid(WAIT_ANY, &status, WNOHANG);
539
0
      if (pid == 0)
540
0
        break;
541
0
      if (pid == -1) {
542
0
        if (errno == ECHILD)
543
0
          break;
544
0
        log_debug("waitpid failed: %s",
545
0
            strerror(errno));
546
0
      }
547
0
    }
548
0
  } else if (!client_attached) {
549
0
    if (sig == SIGTERM || sig == SIGHUP)
550
0
      proc_exit(client_proc);
551
0
  } else {
552
0
    switch (sig) {
553
0
    case SIGHUP:
554
0
      client_exitreason = CLIENT_EXIT_LOST_TTY;
555
0
      client_exitval = 1;
556
0
      proc_send(client_peer, MSG_EXITING, -1, NULL, 0);
557
0
      break;
558
0
    case SIGTERM:
559
0
      if (!client_suspended)
560
0
        client_exitreason = CLIENT_EXIT_TERMINATED;
561
0
      client_exitval = 1;
562
0
      proc_send(client_peer, MSG_EXITING, -1, NULL, 0);
563
0
      break;
564
0
    case SIGWINCH:
565
0
      proc_send(client_peer, MSG_RESIZE, -1, NULL, 0);
566
0
      break;
567
0
    case SIGCONT:
568
0
      memset(&sigact, 0, sizeof sigact);
569
0
      sigemptyset(&sigact.sa_mask);
570
0
      sigact.sa_flags = SA_RESTART;
571
0
      sigact.sa_handler = SIG_IGN;
572
0
      if (sigaction(SIGTSTP, &sigact, NULL) != 0)
573
0
        fatal("sigaction failed");
574
0
      proc_send(client_peer, MSG_WAKEUP, -1, NULL, 0);
575
0
      client_suspended = 0;
576
0
      break;
577
0
    }
578
0
  }
579
0
}
580
581
/* Callback for file write error or close. */
582
static void
583
client_file_check_cb(__unused struct client *c, __unused const char *path,
584
    __unused int error, __unused int closed, __unused struct evbuffer *buffer,
585
    __unused void *data)
586
0
{
587
0
  if (client_exitflag)
588
0
    client_exit();
589
0
}
590
591
/* Callback for client read events. */
592
static void
593
client_dispatch(struct imsg *imsg, __unused void *arg)
594
0
{
595
0
  if (imsg == NULL) {
596
0
    if (!client_exitflag) {
597
0
      client_exitreason = CLIENT_EXIT_LOST_SERVER;
598
0
      client_exitval = 1;
599
0
    }
600
0
    proc_exit(client_proc);
601
0
    return;
602
0
  }
603
604
0
  if (client_attached)
605
0
    client_dispatch_attached(imsg);
606
0
  else
607
0
    client_dispatch_wait(imsg);
608
0
}
609
610
/* Process an exit message. */
611
static void
612
client_dispatch_exit_message(char *data, size_t datalen)
613
0
{
614
0
  int retval;
615
616
0
  if (datalen < sizeof retval && datalen != 0)
617
0
    fatalx("bad MSG_EXIT size");
618
619
0
  if (datalen >= sizeof retval) {
620
0
    memcpy(&retval, data, sizeof retval);
621
0
    client_exitval = retval;
622
0
  }
623
624
0
  if (datalen > sizeof retval) {
625
0
    datalen -= sizeof retval;
626
0
    data += sizeof retval;
627
628
0
    client_exitmessage = xmalloc(datalen);
629
0
    memcpy(client_exitmessage, data, datalen);
630
0
    client_exitmessage[datalen - 1] = '\0';
631
632
0
    client_exitreason = CLIENT_EXIT_MESSAGE_PROVIDED;
633
0
  }
634
0
}
635
636
/* Dispatch imsgs when in wait state (before MSG_READY). */
637
static void
638
client_dispatch_wait(struct imsg *imsg)
639
0
{
640
0
  char    *data;
641
0
  ssize_t    datalen;
642
0
  static int   pledge_applied;
643
644
  /*
645
   * "sendfd" is no longer required once all of the identify messages
646
   * have been sent. We know the server won't send us anything until that
647
   * point (because we don't ask it to), so we can drop "sendfd" once we
648
   * get the first message from the server.
649
   */
650
0
  if (!pledge_applied) {
651
0
    if (pledge(
652
0
        "stdio rpath wpath cpath unix proc exec tty",
653
0
        NULL) != 0)
654
0
      fatal("pledge failed");
655
0
    pledge_applied = 1;
656
0
  }
657
658
0
  data = imsg->data;
659
0
  datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
660
661
0
  switch (imsg->hdr.type) {
662
0
  case MSG_EXIT:
663
0
  case MSG_SHUTDOWN:
664
0
    client_dispatch_exit_message(data, datalen);
665
0
    client_exitflag = 1;
666
0
    client_exit();
667
0
    break;
668
0
  case MSG_READY:
669
0
    if (datalen != 0)
670
0
      fatalx("bad MSG_READY size");
671
672
0
    client_attached = 1;
673
0
    proc_send(client_peer, MSG_RESIZE, -1, NULL, 0);
674
0
    break;
675
0
  case MSG_VERSION:
676
0
    if (datalen != 0)
677
0
      fatalx("bad MSG_VERSION size");
678
679
0
    fprintf(stderr, "protocol version mismatch "
680
0
        "(client %d, server %u)\n", PROTOCOL_VERSION,
681
0
        imsg->hdr.peerid & 0xff);
682
0
    client_exitval = 1;
683
0
    proc_exit(client_proc);
684
0
    break;
685
0
  case MSG_FLAGS:
686
0
    if (datalen != sizeof client_flags)
687
0
      fatalx("bad MSG_FLAGS string");
688
689
0
    memcpy(&client_flags, data, sizeof client_flags);
690
0
    log_debug("new flags are %#llx",
691
0
        (unsigned long long)client_flags);
692
0
    break;
693
0
  case MSG_SHELL:
694
0
    if (datalen == 0 || data[datalen - 1] != '\0')
695
0
      fatalx("bad MSG_SHELL string");
696
697
0
    client_exec(data, shell_command);
698
    /* NOTREACHED */
699
0
  case MSG_DETACH:
700
0
  case MSG_DETACHKILL:
701
0
    proc_send(client_peer, MSG_EXITING, -1, NULL, 0);
702
0
    break;
703
0
  case MSG_EXITED:
704
0
    proc_exit(client_proc);
705
0
    break;
706
0
  case MSG_READ_OPEN:
707
0
    file_read_open(&client_files, client_peer, imsg, 1,
708
0
        !(client_flags & CLIENT_CONTROL), client_file_check_cb,
709
0
        NULL);
710
0
    break;
711
0
  case MSG_READ_CANCEL:
712
0
    file_read_cancel(&client_files, imsg);
713
0
    break;
714
0
  case MSG_WRITE_OPEN:
715
0
    file_write_open(&client_files, client_peer, imsg, 1,
716
0
        !(client_flags & CLIENT_CONTROL), client_file_check_cb,
717
0
        NULL);
718
0
    break;
719
0
  case MSG_WRITE:
720
0
    file_write_data(&client_files, imsg);
721
0
    break;
722
0
  case MSG_WRITE_CLOSE:
723
0
    file_write_close(&client_files, imsg);
724
0
    break;
725
0
  case MSG_OLDSTDERR:
726
0
  case MSG_OLDSTDIN:
727
0
  case MSG_OLDSTDOUT:
728
0
    fprintf(stderr, "server version is too old for client\n");
729
0
    proc_exit(client_proc);
730
0
    break;
731
0
  }
732
0
}
733
734
/* Dispatch imsgs in attached state (after MSG_READY). */
735
static void
736
client_dispatch_attached(struct imsg *imsg)
737
0
{
738
0
  struct sigaction   sigact;
739
0
  char      *data;
740
0
  ssize_t      datalen;
741
742
0
  data = imsg->data;
743
0
  datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
744
745
0
  switch (imsg->hdr.type) {
746
0
  case MSG_FLAGS:
747
0
    if (datalen != sizeof client_flags)
748
0
      fatalx("bad MSG_FLAGS string");
749
750
0
    memcpy(&client_flags, data, sizeof client_flags);
751
0
    log_debug("new flags are %#llx",
752
0
        (unsigned long long)client_flags);
753
0
    break;
754
0
  case MSG_DETACH:
755
0
  case MSG_DETACHKILL:
756
0
    if (datalen == 0 || data[datalen - 1] != '\0')
757
0
      fatalx("bad MSG_DETACH string");
758
759
0
    client_exitsession = xstrdup(data);
760
0
    client_exittype = imsg->hdr.type;
761
0
    if (imsg->hdr.type == MSG_DETACHKILL)
762
0
      client_exitreason = CLIENT_EXIT_DETACHED_HUP;
763
0
    else
764
0
      client_exitreason = CLIENT_EXIT_DETACHED;
765
0
    proc_send(client_peer, MSG_EXITING, -1, NULL, 0);
766
0
    break;
767
0
  case MSG_EXEC:
768
0
    if (datalen == 0 || data[datalen - 1] != '\0' ||
769
0
        strlen(data) + 1 == (size_t)datalen)
770
0
      fatalx("bad MSG_EXEC string");
771
0
    client_execcmd = xstrdup(data);
772
0
    client_execshell = xstrdup(data + strlen(data) + 1);
773
774
0
    client_exittype = imsg->hdr.type;
775
0
    proc_send(client_peer, MSG_EXITING, -1, NULL, 0);
776
0
    break;
777
0
  case MSG_EXIT:
778
0
    client_dispatch_exit_message(data, datalen);
779
0
    if (client_exitreason == CLIENT_EXIT_NONE)
780
0
      client_exitreason = CLIENT_EXIT_EXITED;
781
0
    proc_send(client_peer, MSG_EXITING, -1, NULL, 0);
782
0
    break;
783
0
  case MSG_EXITED:
784
0
    if (datalen != 0)
785
0
      fatalx("bad MSG_EXITED size");
786
787
0
    proc_exit(client_proc);
788
0
    break;
789
0
  case MSG_SHUTDOWN:
790
0
    if (datalen != 0)
791
0
      fatalx("bad MSG_SHUTDOWN size");
792
793
0
    proc_send(client_peer, MSG_EXITING, -1, NULL, 0);
794
0
    client_exitreason = CLIENT_EXIT_SERVER_EXITED;
795
0
    client_exitval = 1;
796
0
    break;
797
0
  case MSG_SUSPEND:
798
0
    if (datalen != 0)
799
0
      fatalx("bad MSG_SUSPEND size");
800
801
0
    memset(&sigact, 0, sizeof sigact);
802
0
    sigemptyset(&sigact.sa_mask);
803
0
    sigact.sa_flags = SA_RESTART;
804
0
    sigact.sa_handler = SIG_DFL;
805
0
    if (sigaction(SIGTSTP, &sigact, NULL) != 0)
806
0
      fatal("sigaction failed");
807
0
    client_suspended = 1;
808
0
    kill(getpid(), SIGTSTP);
809
0
    break;
810
0
  case MSG_LOCK:
811
0
    if (datalen == 0 || data[datalen - 1] != '\0')
812
0
      fatalx("bad MSG_LOCK string");
813
814
0
    system(data);
815
0
    proc_send(client_peer, MSG_UNLOCK, -1, NULL, 0);
816
0
    break;
817
0
  }
818
0
}