Line | Count | Source (jump to first uncovered line) |
1 | | /* $OpenBSD$ */ |
2 | | |
3 | | /* |
4 | | * Copyright (c) 2021 Holland Schutte, Jayson Morberg |
5 | | * Copyright (c) 2021 Dallas Lyons <dallasdlyons@gmail.com> |
6 | | * |
7 | | * Permission to use, copy, modify, and distribute this software for any |
8 | | * purpose with or without fee is hereby granted, provided that the above |
9 | | * copyright notice and this permission notice appear in all copies. |
10 | | * |
11 | | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
12 | | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
13 | | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
14 | | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
15 | | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER |
16 | | * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING |
17 | | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
18 | | */ |
19 | | |
20 | | #include <sys/types.h> |
21 | | #include <sys/stat.h> |
22 | | #include <sys/socket.h> |
23 | | |
24 | | #include <ctype.h> |
25 | | #include <pwd.h> |
26 | | #include <stdlib.h> |
27 | | #include <string.h> |
28 | | #include <unistd.h> |
29 | | |
30 | | #include "tmux.h" |
31 | | |
32 | | struct server_acl_user { |
33 | | uid_t uid; |
34 | | |
35 | | int flags; |
36 | 0 | #define SERVER_ACL_READONLY 0x1 |
37 | | |
38 | | RB_ENTRY(server_acl_user) entry; |
39 | | }; |
40 | | |
41 | | static int |
42 | | server_acl_cmp(struct server_acl_user *user1, struct server_acl_user *user2) |
43 | 0 | { |
44 | 0 | if (user1->uid < user2->uid) |
45 | 0 | return (-1); |
46 | 0 | return (user1->uid > user2->uid); |
47 | 0 | } |
48 | | |
49 | | RB_HEAD(server_acl_entries, server_acl_user) server_acl_entries; |
50 | | RB_GENERATE_STATIC(server_acl_entries, server_acl_user, entry, server_acl_cmp); |
51 | | |
52 | | /* Initialize server_acl tree. */ |
53 | | void |
54 | | server_acl_init(void) |
55 | 0 | { |
56 | 0 | RB_INIT(&server_acl_entries); |
57 | |
|
58 | 0 | if (getuid() != 0) |
59 | 0 | server_acl_user_allow(0); |
60 | 0 | server_acl_user_allow(getuid()); |
61 | 0 | } |
62 | | |
63 | | /* Find user entry. */ |
64 | | struct server_acl_user* |
65 | | server_acl_user_find(uid_t uid) |
66 | 0 | { |
67 | 0 | struct server_acl_user find = { .uid = uid }; |
68 | |
|
69 | 0 | return (RB_FIND(server_acl_entries, &server_acl_entries, &find)); |
70 | 0 | } |
71 | | |
72 | | /* Display the tree. */ |
73 | | void |
74 | | server_acl_display(struct cmdq_item *item) |
75 | 0 | { |
76 | 0 | struct server_acl_user *loop; |
77 | 0 | struct passwd *pw; |
78 | 0 | const char *name; |
79 | |
|
80 | 0 | RB_FOREACH(loop, server_acl_entries, &server_acl_entries) { |
81 | 0 | if (loop->uid == 0) |
82 | 0 | continue; |
83 | 0 | if ((pw = getpwuid(loop->uid)) != NULL) |
84 | 0 | name = pw->pw_name; |
85 | 0 | else |
86 | 0 | name = "unknown"; |
87 | 0 | if (loop->flags == SERVER_ACL_READONLY) |
88 | 0 | cmdq_print(item, "%s (R)", name); |
89 | 0 | else |
90 | 0 | cmdq_print(item, "%s (W)", name); |
91 | 0 | } |
92 | 0 | } |
93 | | |
94 | | /* Allow a user. */ |
95 | | void |
96 | | server_acl_user_allow(uid_t uid) |
97 | 0 | { |
98 | 0 | struct server_acl_user *user; |
99 | |
|
100 | 0 | user = server_acl_user_find(uid); |
101 | 0 | if (user == NULL) { |
102 | 0 | user = xcalloc(1, sizeof *user); |
103 | 0 | user->uid = uid; |
104 | 0 | RB_INSERT(server_acl_entries, &server_acl_entries, user); |
105 | 0 | } |
106 | 0 | } |
107 | | |
108 | | /* Deny a user (remove from the tree). */ |
109 | | void |
110 | | server_acl_user_deny(uid_t uid) |
111 | 0 | { |
112 | 0 | struct server_acl_user *user; |
113 | |
|
114 | 0 | user = server_acl_user_find(uid); |
115 | 0 | if (user != NULL) { |
116 | 0 | RB_REMOVE(server_acl_entries, &server_acl_entries, user); |
117 | 0 | free(user); |
118 | 0 | } |
119 | 0 | } |
120 | | |
121 | | /* Allow this user write access. */ |
122 | | void |
123 | | server_acl_user_allow_write(uid_t uid) |
124 | 0 | { |
125 | 0 | struct server_acl_user *user; |
126 | 0 | struct client *c; |
127 | |
|
128 | 0 | user = server_acl_user_find(uid); |
129 | 0 | if (user == NULL) |
130 | 0 | return; |
131 | 0 | user->flags &= ~SERVER_ACL_READONLY; |
132 | |
|
133 | 0 | TAILQ_FOREACH(c, &clients, entry) { |
134 | 0 | uid = proc_get_peer_uid(c->peer); |
135 | 0 | if (uid != (uid_t)-1 && uid == user->uid) |
136 | 0 | c->flags &= ~CLIENT_READONLY; |
137 | 0 | } |
138 | 0 | } |
139 | | |
140 | | /* Deny this user write access. */ |
141 | | void |
142 | | server_acl_user_deny_write(uid_t uid) |
143 | 0 | { |
144 | 0 | struct server_acl_user *user; |
145 | 0 | struct client *c; |
146 | |
|
147 | 0 | user = server_acl_user_find(uid); |
148 | 0 | if (user == NULL) |
149 | 0 | return; |
150 | 0 | user->flags |= SERVER_ACL_READONLY; |
151 | |
|
152 | 0 | TAILQ_FOREACH(c, &clients, entry) { |
153 | 0 | uid = proc_get_peer_uid(c->peer); |
154 | 0 | if (uid != (uid_t)-1 && uid == user->uid) |
155 | 0 | c->flags |= CLIENT_READONLY; |
156 | 0 | } |
157 | 0 | } |
158 | | |
159 | | /* |
160 | | * Check if the client's UID exists in the ACL list and if so, set as read only |
161 | | * if needed. Return false if the user does not exist. |
162 | | */ |
163 | | int |
164 | | server_acl_join(struct client *c) |
165 | 0 | { |
166 | 0 | struct server_acl_user *user; |
167 | 0 | uid_t uid; |
168 | |
|
169 | 0 | uid = proc_get_peer_uid(c->peer); |
170 | 0 | if (uid == (uid_t)-1) |
171 | 0 | return (0); |
172 | | |
173 | 0 | user = server_acl_user_find(uid); |
174 | 0 | if (user == NULL) |
175 | 0 | return (0); |
176 | 0 | if (user->flags & SERVER_ACL_READONLY) |
177 | 0 | c->flags |= CLIENT_READONLY; |
178 | 0 | return (1); |
179 | 0 | } |
180 | | |
181 | | /* Get UID for user entry. */ |
182 | | uid_t |
183 | | server_acl_get_uid(struct server_acl_user *user) |
184 | 0 | { |
185 | 0 | return (user->uid); |
186 | 0 | } |