Coverage Report

Created: 2026-10-28 06:08

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/tmux/client.c
Line
Count
Source
1
/* $OpenBSD: client.c,v 1.169 2026/10/27 08:38:40 nicm Exp $ */
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;
243
0
  char      **caps = NULL, *cause;
244
0
  u_int      ncaps = 0;
245
0
  struct args_value *values;
246
247
  /* Set up the initial command. */
248
0
  if (shell_command != NULL) {
249
0
    msg = MSG_SHELL;
250
0
    flags |= CLIENT_STARTSERVER;
251
0
  } else if (argc == 0) {
252
0
    msg = MSG_COMMAND;
253
0
    flags |= CLIENT_STARTSERVER;
254
0
  } else {
255
0
    msg = MSG_COMMAND;
256
257
    /*
258
     * It's annoying parsing the command string twice (in client
259
     * and later in server) but it is necessary to get the start
260
     * server flag.
261
     */
262
0
    values = args_from_vector(argc, argv);
263
0
    pr = cmd_parse_from_arguments(values, argc, NULL);
264
0
    if (pr->status == CMD_PARSE_SUCCESS) {
265
0
      if (cmd_list_any_have(pr->cmdlist, CMD_STARTSERVER))
266
0
        flags |= CLIENT_STARTSERVER;
267
0
      cmd_list_free(pr->cmdlist);
268
0
    } else
269
0
      free(pr->error);
270
0
    args_free_values(values, argc);
271
0
    free(values);
272
0
  }
273
274
  /* Create client process structure (starts logging). */
275
0
  client_proc = proc_start("client");
276
0
  proc_set_signals(client_proc, client_signal);
277
278
  /* Save the flags. */
279
0
  client_flags = flags|CLIENT_WRITE_ACK;
280
0
  log_debug("flags are %#llx", (unsigned long long)client_flags);
281
282
  /* Initialize the client socket and start the server. */
283
#ifdef HAVE_SYSTEMD
284
  if (systemd_activated()) {
285
    /* socket-based activation, do not even try to be a client. */
286
    fd = server_start(client_proc, flags, base, -1, NULL);
287
  } else
288
#endif
289
0
  fd = client_connect(base, socket_path, client_flags);
290
0
  if (fd == -1) {
291
0
    if (errno == ECONNREFUSED) {
292
0
      fprintf(stderr, "no server running on %s\n",
293
0
          socket_path);
294
0
    } else {
295
0
      fprintf(stderr, "error connecting to %s (%s)\n",
296
0
          socket_path, strerror(errno));
297
0
    }
298
0
    return (1);
299
0
  }
300
0
  client_peer = proc_add_peer(client_proc, fd, client_dispatch, NULL);
301
302
  /* Save these before pledge(). */
303
0
  if ((cwd = find_cwd()) == NULL && (cwd = find_home()) == NULL)
304
0
    cwd = "/";
305
0
  if ((ttynam = ttyname(STDIN_FILENO)) == NULL)
306
0
    ttynam = "";
307
0
  if ((termname = getenv("TERM")) == NULL)
308
0
    termname = "";
309
310
  /*
311
   * Drop privileges for client. "proc exec" is needed for -c and for
312
   * locking (which uses system(3)).
313
   *
314
   * "tty" is needed to restore termios(4) and also for some reason -CC
315
   * does not work properly without it (input is not recognised).
316
   *
317
   * "sendfd" is dropped later in client_dispatch_wait().
318
   */
319
0
  if (pledge(
320
0
      "stdio rpath wpath cpath unix sendfd proc exec tty",
321
0
      NULL) != 0)
322
0
    fatal("pledge failed");
323
324
  /* Load terminfo entry if any. */
325
0
  if (isatty(STDIN_FILENO) &&
326
0
      *termname != '\0' &&
327
0
      tty_term_read_list(termname, STDIN_FILENO, &caps, &ncaps,
328
0
      &cause) != 0) {
329
0
    fprintf(stderr, "%s\n", cause);
330
0
    free(cause);
331
0
    return (1);
332
0
  }
333
334
  /* Free stuff that is not used in the client. */
335
0
  if (ptm_fd != -1)
336
0
    close(ptm_fd);
337
0
  options_free(global_options);
338
0
  options_free(global_s_options);
339
0
  options_free(global_w_options);
340
0
  environ_free(global_environ);
341
342
  /* Set up control mode. */
343
0
  if (client_flags & CLIENT_CONTROLCONTROL) {
344
0
    if (tcgetattr(STDIN_FILENO, &saved_tio) != 0) {
345
0
      fprintf(stderr, "tcgetattr failed: %s\n",
346
0
          strerror(errno));
347
0
      return (1);
348
0
    }
349
0
    memcpy(&tio, &saved_tio, sizeof tio);
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
  /* Print the exit message, if any, and exit. */
411
0
  if (client_attached) {
412
0
    if (client_exitreason != CLIENT_EXIT_NONE)
413
0
      printf("[%s]\n", client_exit_message());
414
415
0
    ppid = getppid();
416
0
    if (client_exittype == MSG_DETACHKILL && ppid > 1)
417
0
      kill(ppid, SIGHUP);
418
0
  } else if (client_flags & CLIENT_CONTROL) {
419
0
    if (client_exitreason != CLIENT_EXIT_NONE)
420
0
      printf("%%exit %s\n", client_exit_message());
421
0
    else
422
0
      printf("%%exit\n");
423
0
    fflush(stdout);
424
0
    if (client_flags & CLIENT_CONTROL_WAITEXIT)
425
0
      control_wait_exit(STDIN_FILENO);
426
0
    if (client_flags & CLIENT_CONTROLCONTROL) {
427
0
      printf("\033\\");
428
0
      fflush(stdout);
429
0
      tcsetattr(STDOUT_FILENO, TCSAFLUSH, &saved_tio);
430
0
    }
431
0
  } else if (client_exitreason != CLIENT_EXIT_NONE)
432
0
    fprintf(stderr, "%s\n", client_exit_message());
433
434
  /* Restore the streams to blocking. */
435
0
  setblocking(STDIN_FILENO, 1);
436
0
  setblocking(STDOUT_FILENO, 1);
437
0
  setblocking(STDERR_FILENO, 1);
438
439
0
  return (client_exitval);
440
0
}
441
442
/* Send identify messages to server. */
443
static void
444
client_send_identify(const char *ttynam, const char *termname, char **caps,
445
    u_int ncaps, const char *cwd, int feat)
446
0
{
447
0
  char  **ss;
448
0
  size_t    sslen;
449
0
  int   fd;
450
0
  uint64_t  flags = client_flags;
451
0
  pid_t   pid;
452
0
  u_int   i;
453
454
0
  proc_send(client_peer, MSG_IDENTIFY_LONGFLAGS, -1, &flags, sizeof flags);
455
0
  proc_send(client_peer, MSG_IDENTIFY_LONGFLAGS, -1, &client_flags,
456
0
      sizeof client_flags);
457
458
0
  proc_send(client_peer, MSG_IDENTIFY_TERM, -1, termname,
459
0
      strlen(termname) + 1);
460
0
  proc_send(client_peer, MSG_IDENTIFY_FEATURES, -1, &feat, sizeof feat);
461
462
0
  proc_send(client_peer, MSG_IDENTIFY_TTYNAME, -1, ttynam,
463
0
      strlen(ttynam) + 1);
464
0
  proc_send(client_peer, MSG_IDENTIFY_CWD, -1, cwd, strlen(cwd) + 1);
465
466
0
  for (i = 0; i < ncaps; i++) {
467
0
    proc_send(client_peer, MSG_IDENTIFY_TERMINFO, -1,
468
0
        caps[i], strlen(caps[i]) + 1);
469
0
  }
470
471
0
  if ((fd = dup(STDIN_FILENO)) == -1)
472
0
    fatal("dup failed");
473
0
  proc_send(client_peer, MSG_IDENTIFY_STDIN, fd, NULL, 0);
474
0
  if ((fd = dup(STDOUT_FILENO)) == -1)
475
0
    fatal("dup failed");
476
0
  proc_send(client_peer, MSG_IDENTIFY_STDOUT, fd, NULL, 0);
477
478
0
  pid = getpid();
479
0
  proc_send(client_peer, MSG_IDENTIFY_CLIENTPID, -1, &pid, sizeof pid);
480
481
0
  for (ss = environ; *ss != NULL; ss++) {
482
0
    sslen = strlen(*ss) + 1;
483
0
    if (sslen > MAX_IMSGSIZE - IMSG_HEADER_SIZE)
484
0
      continue;
485
0
    proc_send(client_peer, MSG_IDENTIFY_ENVIRON, -1, *ss, sslen);
486
0
  }
487
488
0
  proc_send(client_peer, MSG_IDENTIFY_DONE, -1, NULL, 0);
489
0
}
490
491
/* Run command in shell; used for -c. */
492
static __dead void
493
client_exec(const char *shell, const char *shellcmd)
494
0
{
495
0
  char  *argv0;
496
497
0
  log_debug("shell %s, command %s", shell, shellcmd);
498
0
  argv0 = shell_argv0(shell, !!(client_flags & CLIENT_LOGIN));
499
0
  setenv("SHELL", shell, 1);
500
501
0
  proc_clear_signals(client_proc, 1);
502
503
0
  setblocking(STDIN_FILENO, 1);
504
0
  setblocking(STDOUT_FILENO, 1);
505
0
  setblocking(STDERR_FILENO, 1);
506
0
  closefrom(STDERR_FILENO + 1);
507
508
0
  execl(shell, argv0, "-c", shellcmd, (char *) NULL);
509
0
  fatal("execl failed");
510
0
}
511
512
/* Callback to handle signals in the client. */
513
static void
514
client_signal(int sig)
515
0
{
516
0
  struct sigaction sigact;
517
0
  int    status;
518
0
  pid_t    pid;
519
520
0
  log_debug("%s: %s", __func__, strsignal(sig));
521
0
  if (sig == SIGCHLD) {
522
0
    for (;;) {
523
0
      pid = waitpid(WAIT_ANY, &status, WNOHANG);
524
0
      if (pid == 0)
525
0
        break;
526
0
      if (pid == -1) {
527
0
        if (errno == ECHILD)
528
0
          break;
529
0
        log_debug("waitpid failed: %s",
530
0
            strerror(errno));
531
0
      }
532
0
    }
533
0
  } else if (!client_attached) {
534
0
    if (sig == SIGTERM || sig == SIGHUP)
535
0
      proc_exit(client_proc);
536
0
  } else {
537
0
    switch (sig) {
538
0
    case SIGHUP:
539
0
      client_exitreason = CLIENT_EXIT_LOST_TTY;
540
0
      client_exitval = 1;
541
0
      proc_send(client_peer, MSG_EXITING, -1, NULL, 0);
542
0
      break;
543
0
    case SIGTERM:
544
0
      if (!client_suspended)
545
0
        client_exitreason = CLIENT_EXIT_TERMINATED;
546
0
      client_exitval = 1;
547
0
      proc_send(client_peer, MSG_EXITING, -1, NULL, 0);
548
0
      break;
549
0
    case SIGWINCH:
550
0
      proc_send(client_peer, MSG_RESIZE, -1, NULL, 0);
551
0
      break;
552
0
    case SIGCONT:
553
0
      memset(&sigact, 0, sizeof sigact);
554
0
      sigemptyset(&sigact.sa_mask);
555
0
      sigact.sa_flags = SA_RESTART;
556
0
      sigact.sa_handler = SIG_IGN;
557
0
      if (sigaction(SIGTSTP, &sigact, NULL) != 0)
558
0
        fatal("sigaction failed");
559
0
      proc_send(client_peer, MSG_WAKEUP, -1, NULL, 0);
560
0
      client_suspended = 0;
561
0
      break;
562
0
    }
563
0
  }
564
0
}
565
566
/* Callback for file write error or close. */
567
static void
568
client_file_check_cb(__unused struct client *c, __unused const char *path,
569
    __unused int error, __unused int closed, __unused struct evbuffer *buffer,
570
    __unused void *data)
571
0
{
572
0
  if (client_exitflag)
573
0
    client_exit();
574
0
}
575
576
/* Callback for client read events. */
577
static void
578
client_dispatch(struct imsg *imsg, __unused void *arg)
579
0
{
580
0
  if (imsg == NULL) {
581
0
    if (!client_exitflag) {
582
0
      client_exitreason = CLIENT_EXIT_LOST_SERVER;
583
0
      client_exitval = 1;
584
0
    }
585
0
    proc_exit(client_proc);
586
0
    return;
587
0
  }
588
589
0
  if (client_attached)
590
0
    client_dispatch_attached(imsg);
591
0
  else
592
0
    client_dispatch_wait(imsg);
593
0
}
594
595
/* Process an exit message. */
596
static void
597
client_dispatch_exit_message(char *data, size_t datalen)
598
0
{
599
0
  int retval;
600
601
0
  if (datalen < sizeof retval && datalen != 0)
602
0
    fatalx("bad MSG_EXIT size");
603
604
0
  if (datalen >= sizeof retval) {
605
0
    memcpy(&retval, data, sizeof retval);
606
0
    client_exitval = retval;
607
0
  }
608
609
0
  if (datalen > sizeof retval) {
610
0
    datalen -= sizeof retval;
611
0
    data += sizeof retval;
612
613
0
    client_exitmessage = xmalloc(datalen);
614
0
    memcpy(client_exitmessage, data, datalen);
615
0
    client_exitmessage[datalen - 1] = '\0';
616
617
0
    client_exitreason = CLIENT_EXIT_MESSAGE_PROVIDED;
618
0
  }
619
0
}
620
621
/* Dispatch imsgs when in wait state (before MSG_READY). */
622
static void
623
client_dispatch_wait(struct imsg *imsg)
624
0
{
625
0
  char    *data;
626
0
  ssize_t    datalen;
627
0
  static int   pledge_applied;
628
629
  /*
630
   * "sendfd" is no longer required once all of the identify messages
631
   * have been sent. We know the server won't send us anything until that
632
   * point (because we don't ask it to), so we can drop "sendfd" once we
633
   * get the first message from the server.
634
   */
635
0
  if (!pledge_applied) {
636
0
    if (pledge(
637
0
        "stdio rpath wpath cpath unix proc exec tty",
638
0
        NULL) != 0)
639
0
      fatal("pledge failed");
640
0
    pledge_applied = 1;
641
0
  }
642
643
0
  data = imsg->data;
644
0
  datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
645
646
0
  switch (imsg->hdr.type) {
647
0
  case MSG_EXIT:
648
0
  case MSG_SHUTDOWN:
649
0
    client_dispatch_exit_message(data, datalen);
650
0
    client_exitflag = 1;
651
0
    client_exit();
652
0
    break;
653
0
  case MSG_READY:
654
0
    if (datalen != 0)
655
0
      fatalx("bad MSG_READY size");
656
657
0
    client_attached = 1;
658
0
    proc_send(client_peer, MSG_RESIZE, -1, NULL, 0);
659
0
    break;
660
0
  case MSG_VERSION:
661
0
    if (datalen != 0)
662
0
      fatalx("bad MSG_VERSION size");
663
664
0
    fprintf(stderr, "protocol version mismatch "
665
0
        "(client %d, server %u)\n", PROTOCOL_VERSION,
666
0
        imsg->hdr.peerid & 0xff);
667
0
    client_exitval = 1;
668
0
    proc_exit(client_proc);
669
0
    break;
670
0
  case MSG_FLAGS:
671
0
    if (datalen != sizeof client_flags)
672
0
      fatalx("bad MSG_FLAGS string");
673
674
0
    memcpy(&client_flags, data, sizeof client_flags);
675
0
    log_debug("new flags are %#llx",
676
0
        (unsigned long long)client_flags);
677
0
    break;
678
0
  case MSG_SHELL:
679
0
    if (datalen == 0 || data[datalen - 1] != '\0')
680
0
      fatalx("bad MSG_SHELL string");
681
682
0
    client_exec(data, shell_command);
683
    /* NOTREACHED */
684
0
  case MSG_DETACH:
685
0
  case MSG_DETACHKILL:
686
0
    proc_send(client_peer, MSG_EXITING, -1, NULL, 0);
687
0
    break;
688
0
  case MSG_EXITED:
689
0
    proc_exit(client_proc);
690
0
    break;
691
0
  case MSG_READ_OPEN:
692
0
    file_read_open(&client_files, client_peer, imsg, 1,
693
0
        !(client_flags & CLIENT_CONTROL), client_file_check_cb,
694
0
        NULL);
695
0
    break;
696
0
  case MSG_READ_CANCEL:
697
0
    file_read_cancel(&client_files, imsg);
698
0
    break;
699
0
  case MSG_WRITE_OPEN:
700
0
    file_write_open(&client_files, client_peer, imsg, 1,
701
0
        !(client_flags & CLIENT_CONTROL), client_file_check_cb,
702
0
        NULL);
703
0
    break;
704
0
  case MSG_WRITE:
705
0
    file_write_data(&client_files, imsg);
706
0
    break;
707
0
  case MSG_WRITE_CLOSE:
708
0
    file_write_close(&client_files, imsg);
709
0
    break;
710
0
  case MSG_OLDSTDERR:
711
0
  case MSG_OLDSTDIN:
712
0
  case MSG_OLDSTDOUT:
713
0
    fprintf(stderr, "server version is too old for client\n");
714
0
    proc_exit(client_proc);
715
0
    break;
716
0
  default:
717
0
    log_debug("unknown message type %u", imsg->hdr.type);
718
0
    break;
719
0
  }
720
0
}
721
722
/* Dispatch imsgs in attached state (after MSG_READY). */
723
static void
724
client_dispatch_attached(struct imsg *imsg)
725
0
{
726
0
  struct sigaction   sigact;
727
0
  char      *data;
728
0
  ssize_t      datalen;
729
730
0
  data = imsg->data;
731
0
  datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
732
733
0
  switch (imsg->hdr.type) {
734
0
  case MSG_FLAGS:
735
0
    if (datalen != sizeof client_flags)
736
0
      fatalx("bad MSG_FLAGS string");
737
738
0
    memcpy(&client_flags, data, sizeof client_flags);
739
0
    log_debug("new flags are %#llx",
740
0
        (unsigned long long)client_flags);
741
0
    break;
742
0
  case MSG_DETACH:
743
0
  case MSG_DETACHKILL:
744
0
    if (datalen == 0 || data[datalen - 1] != '\0')
745
0
      fatalx("bad MSG_DETACH string");
746
747
0
    client_exitsession = xstrdup(data);
748
0
    client_exittype = imsg->hdr.type;
749
0
    if (imsg->hdr.type == MSG_DETACHKILL)
750
0
      client_exitreason = CLIENT_EXIT_DETACHED_HUP;
751
0
    else
752
0
      client_exitreason = CLIENT_EXIT_DETACHED;
753
0
    proc_send(client_peer, MSG_EXITING, -1, NULL, 0);
754
0
    break;
755
0
  case MSG_EXEC:
756
0
    if (datalen == 0 || data[datalen - 1] != '\0' ||
757
0
        strlen(data) + 1 == (size_t)datalen)
758
0
      fatalx("bad MSG_EXEC string");
759
0
    client_execcmd = xstrdup(data);
760
0
    client_execshell = xstrdup(data + strlen(data) + 1);
761
762
0
    client_exittype = imsg->hdr.type;
763
0
    proc_send(client_peer, MSG_EXITING, -1, NULL, 0);
764
0
    break;
765
0
  case MSG_EXIT:
766
0
    client_dispatch_exit_message(data, datalen);
767
0
    if (client_exitreason == CLIENT_EXIT_NONE)
768
0
      client_exitreason = CLIENT_EXIT_EXITED;
769
0
    proc_send(client_peer, MSG_EXITING, -1, NULL, 0);
770
0
    break;
771
0
  case MSG_EXITED:
772
0
    if (datalen != 0)
773
0
      fatalx("bad MSG_EXITED size");
774
775
0
    proc_exit(client_proc);
776
0
    break;
777
0
  case MSG_SHUTDOWN:
778
0
    if (datalen != 0)
779
0
      fatalx("bad MSG_SHUTDOWN size");
780
781
0
    proc_send(client_peer, MSG_EXITING, -1, NULL, 0);
782
0
    client_exitreason = CLIENT_EXIT_SERVER_EXITED;
783
0
    client_exitval = 1;
784
0
    break;
785
0
  case MSG_SUSPEND:
786
0
    if (datalen != 0)
787
0
      fatalx("bad MSG_SUSPEND size");
788
789
0
    memset(&sigact, 0, sizeof sigact);
790
0
    sigemptyset(&sigact.sa_mask);
791
0
    sigact.sa_flags = SA_RESTART;
792
0
    sigact.sa_handler = SIG_DFL;
793
0
    if (sigaction(SIGTSTP, &sigact, NULL) != 0)
794
0
      fatal("sigaction failed");
795
0
    client_suspended = 1;
796
0
    kill(getpid(), SIGTSTP);
797
0
    break;
798
0
  case MSG_LOCK:
799
0
    if (datalen == 0 || data[datalen - 1] != '\0')
800
0
      fatalx("bad MSG_LOCK string");
801
802
0
    system(data);
803
0
    proc_send(client_peer, MSG_UNLOCK, -1, NULL, 0);
804
0
    break;
805
0
  default:
806
0
    log_debug("unknown message type %u", imsg->hdr.type);
807
0
    break;
808
0
  }
809
0
}