Coverage Report

Created: 2026-06-12 06:51

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/tmux/cmd-server-access.c
Line
Count
Source
1
/* $OpenBSD$ */
2
3
/*
4
 * Copyright (c) 2021 Dallas Lyons <dallasdlyons@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/stat.h>
20
#include <sys/types.h>
21
22
#include <grp.h>
23
#include <pwd.h>
24
#include <stdio.h>
25
#include <string.h>
26
#include <stdlib.h>
27
#include <unistd.h>
28
29
#include "tmux.h"
30
31
/*
32
 * Controls access to session.
33
 */
34
35
static enum cmd_retval cmd_server_access_exec(struct cmd *, struct cmdq_item *);
36
37
const struct cmd_entry cmd_server_access_entry = {
38
  .name = "server-access",
39
  .alias = NULL,
40
41
  .args = { "adglrw", 0, 1, NULL },
42
  .usage = "[-adglrw] " CMD_TARGET_PANE_USAGE " [user|group]",
43
44
  .flags = CMD_CLIENT_CANFAIL,
45
  .exec = cmd_server_access_exec
46
};
47
48
static enum cmd_retval
49
cmd_server_access_deny(struct cmdq_item *item, id_t id, int flags,
50
    const char *type, const char *name)
51
0
{
52
0
  if (!server_acl_find(id, flags)) {
53
0
    cmdq_error(item, "%s %s not found", type, name);
54
0
    return (CMD_RETURN_ERROR);
55
0
  }
56
0
  server_acl_deny(id, flags);
57
0
  return (CMD_RETURN_NORMAL);
58
0
}
59
60
static enum cmd_retval
61
cmd_server_access_exec(struct cmd *self, struct cmdq_item *item)
62
0
{
63
0
  struct args *args = cmd_get_args(self);
64
0
  struct client *c = cmdq_get_target_client(item);
65
0
  char    *arg;
66
0
  const char  *name = NULL, *type;
67
0
  struct passwd *pw;
68
0
  struct group  *gr;
69
0
  id_t     id;
70
0
  int    flags = 0;
71
72
0
  if (args_has(args, 'l')) {
73
0
    server_acl_display(item);
74
0
    return (CMD_RETURN_NORMAL);
75
0
  }
76
0
  if (args_count(args) == 0) {
77
0
    cmdq_error(item, "missing user or group argument");
78
0
    return (CMD_RETURN_ERROR);
79
0
  }
80
81
0
  arg = format_single(item, args_string(args, 0), c, NULL, NULL, NULL);
82
0
  if (args_has(args, 'g')) {
83
0
    type = "group";
84
0
    if ((gr = getgrnam(arg)) != NULL) {
85
0
      id = gr->gr_gid;
86
0
      name = gr->gr_name;
87
0
      flags |= SERVER_ACL_IS_GROUP;
88
0
    }
89
0
  } else {
90
0
    type = "user";
91
0
    if ((pw = getpwnam(arg)) != NULL) {
92
0
      id = pw->pw_uid;
93
0
      name = pw->pw_name;
94
0
    }
95
0
  }
96
0
  if (name == NULL) {
97
0
    cmdq_error(item, "unknown %s: %s", type, arg);
98
0
    free(arg);
99
0
    return (CMD_RETURN_ERROR);
100
0
  }
101
0
  free(arg);
102
103
0
  if ((~flags & SERVER_ACL_IS_GROUP) && (id == 0 || id == getuid())) {
104
0
    cmdq_error(item, "%s owns the server, can't change access",
105
0
        name);
106
0
    return (CMD_RETURN_ERROR);
107
0
  }
108
109
0
  if (args_has(args, 'a') && args_has(args, 'd')) {
110
0
    cmdq_error(item, "-a and -d cannot be used together");
111
0
    return (CMD_RETURN_ERROR);
112
0
  }
113
0
  if (args_has(args, 'w') && args_has(args, 'r')) {
114
0
    cmdq_error(item, "-r and -w cannot be used together");
115
0
    return (CMD_RETURN_ERROR);
116
0
  }
117
118
0
  if (args_has(args, 'd'))
119
0
    return (cmd_server_access_deny(item, id, flags, type, name));
120
0
  if (args_has(args, 'a')) {
121
0
    if (server_acl_find(id, flags)) {
122
0
      cmdq_error(item, "%s %s is already added", type, name);
123
0
      return (CMD_RETURN_ERROR);
124
0
    }
125
0
    server_acl_allow(id, flags);
126
    /* Do not return - allow -r or -w with -a. */
127
0
  } else if (args_has(args, 'r') || args_has(args, 'w')) {
128
    /* -r or -w implies -a if the entry does not exist. */
129
0
    if (!server_acl_find(id, flags))
130
0
      server_acl_allow(id, flags);
131
0
  }
132
133
0
  if (args_has(args, 'w')) {
134
0
    if (!server_acl_find(id, flags)) {
135
0
      cmdq_error(item, "%s %s not found", type, name);
136
0
      return (CMD_RETURN_ERROR);
137
0
    }
138
0
    server_acl_allow_write(id, flags);
139
0
    return (CMD_RETURN_NORMAL);
140
0
  }
141
142
0
  if (args_has(args, 'r')) {
143
0
    if (!server_acl_find(id, flags)) {
144
0
      cmdq_error(item, "%s %s not found", type, name);
145
0
      return (CMD_RETURN_ERROR);
146
0
    }
147
0
    server_acl_deny_write(id, flags);
148
0
    return (CMD_RETURN_NORMAL);
149
0
  }
150
151
0
  return (CMD_RETURN_NORMAL);
152
0
}