1*3e8355bdSnicm /* $OpenBSD: server-acl.c,v 1.2 2022/05/30 12:55:25 nicm Exp $ */
28ab000fcSnicm
38ab000fcSnicm /*
48ab000fcSnicm * Copyright (c) 2021 Holland Schutte, Jayson Morberg
58ab000fcSnicm * Copyright (c) 2021 Dallas Lyons <dallasdlyons@gmail.com>
68ab000fcSnicm *
78ab000fcSnicm * Permission to use, copy, modify, and distribute this software for any
88ab000fcSnicm * purpose with or without fee is hereby granted, provided that the above
98ab000fcSnicm * copyright notice and this permission notice appear in all copies.
108ab000fcSnicm *
118ab000fcSnicm * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
128ab000fcSnicm * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
138ab000fcSnicm * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
148ab000fcSnicm * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
158ab000fcSnicm * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
168ab000fcSnicm * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
178ab000fcSnicm * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
188ab000fcSnicm */
198ab000fcSnicm
208ab000fcSnicm #include <sys/types.h>
218ab000fcSnicm #include <sys/stat.h>
228ab000fcSnicm #include <sys/socket.h>
238ab000fcSnicm
248ab000fcSnicm #include <ctype.h>
258ab000fcSnicm #include <pwd.h>
268ab000fcSnicm #include <stdlib.h>
278ab000fcSnicm #include <string.h>
288ab000fcSnicm #include <unistd.h>
298ab000fcSnicm
308ab000fcSnicm #include "tmux.h"
318ab000fcSnicm
328ab000fcSnicm struct server_acl_user {
338ab000fcSnicm uid_t uid;
348ab000fcSnicm
358ab000fcSnicm int flags;
368ab000fcSnicm #define SERVER_ACL_READONLY 0x1
378ab000fcSnicm
388ab000fcSnicm RB_ENTRY(server_acl_user) entry;
398ab000fcSnicm };
408ab000fcSnicm
418ab000fcSnicm static int
server_acl_cmp(struct server_acl_user * user1,struct server_acl_user * user2)428ab000fcSnicm server_acl_cmp(struct server_acl_user *user1, struct server_acl_user *user2)
438ab000fcSnicm {
448ab000fcSnicm if (user1->uid < user2->uid)
45*3e8355bdSnicm return (-1);
46*3e8355bdSnicm return (user1->uid > user2->uid);
478ab000fcSnicm }
488ab000fcSnicm
498ab000fcSnicm RB_HEAD(server_acl_entries, server_acl_user) server_acl_entries;
508ab000fcSnicm RB_GENERATE_STATIC(server_acl_entries, server_acl_user, entry, server_acl_cmp);
518ab000fcSnicm
528ab000fcSnicm /* Initialize server_acl tree. */
538ab000fcSnicm void
server_acl_init(void)548ab000fcSnicm server_acl_init(void)
558ab000fcSnicm {
568ab000fcSnicm RB_INIT(&server_acl_entries);
578ab000fcSnicm
588ab000fcSnicm if (getuid() != 0)
598ab000fcSnicm server_acl_user_allow(0);
608ab000fcSnicm server_acl_user_allow(getuid());
618ab000fcSnicm }
628ab000fcSnicm
638ab000fcSnicm /* Find user entry. */
648ab000fcSnicm struct server_acl_user*
server_acl_user_find(uid_t uid)658ab000fcSnicm server_acl_user_find(uid_t uid)
668ab000fcSnicm {
678ab000fcSnicm struct server_acl_user find = { .uid = uid };
688ab000fcSnicm
69*3e8355bdSnicm return (RB_FIND(server_acl_entries, &server_acl_entries, &find));
708ab000fcSnicm }
718ab000fcSnicm
728ab000fcSnicm /* Display the tree. */
738ab000fcSnicm void
server_acl_display(struct cmdq_item * item)748ab000fcSnicm server_acl_display(struct cmdq_item *item)
758ab000fcSnicm {
768ab000fcSnicm struct server_acl_user *loop;
778ab000fcSnicm struct passwd *pw;
788ab000fcSnicm const char *name;
798ab000fcSnicm
808ab000fcSnicm RB_FOREACH(loop, server_acl_entries, &server_acl_entries) {
818ab000fcSnicm if (loop->uid == 0)
828ab000fcSnicm continue;
838ab000fcSnicm if ((pw = getpwuid(loop->uid)) != NULL)
848ab000fcSnicm name = pw->pw_name;
858ab000fcSnicm else
868ab000fcSnicm name = "unknown";
878ab000fcSnicm if (loop->flags == SERVER_ACL_READONLY)
888ab000fcSnicm cmdq_print(item, "%s (R)", name);
898ab000fcSnicm else
908ab000fcSnicm cmdq_print(item, "%s (W)", name);
918ab000fcSnicm }
928ab000fcSnicm }
938ab000fcSnicm
948ab000fcSnicm /* Allow a user. */
958ab000fcSnicm void
server_acl_user_allow(uid_t uid)968ab000fcSnicm server_acl_user_allow(uid_t uid)
978ab000fcSnicm {
988ab000fcSnicm struct server_acl_user *user;
998ab000fcSnicm
1008ab000fcSnicm user = server_acl_user_find(uid);
1018ab000fcSnicm if (user == NULL) {
1028ab000fcSnicm user = xcalloc(1, sizeof *user);
1038ab000fcSnicm user->uid = uid;
1048ab000fcSnicm RB_INSERT(server_acl_entries, &server_acl_entries, user);
1058ab000fcSnicm }
1068ab000fcSnicm }
1078ab000fcSnicm
1088ab000fcSnicm /* Deny a user (remove from the tree). */
1098ab000fcSnicm void
server_acl_user_deny(uid_t uid)1108ab000fcSnicm server_acl_user_deny(uid_t uid)
1118ab000fcSnicm {
1128ab000fcSnicm struct server_acl_user *user;
1138ab000fcSnicm
1148ab000fcSnicm user = server_acl_user_find(uid);
1158ab000fcSnicm if (user != NULL) {
1168ab000fcSnicm RB_REMOVE(server_acl_entries, &server_acl_entries, user);
1178ab000fcSnicm free(user);
1188ab000fcSnicm }
1198ab000fcSnicm }
1208ab000fcSnicm
1218ab000fcSnicm /* Allow this user write access. */
1228ab000fcSnicm void
server_acl_user_allow_write(uid_t uid)1238ab000fcSnicm server_acl_user_allow_write(uid_t uid)
1248ab000fcSnicm {
1258ab000fcSnicm struct server_acl_user *user;
1268ab000fcSnicm struct client *c;
1278ab000fcSnicm
1288ab000fcSnicm user = server_acl_user_find(uid);
1298ab000fcSnicm if (user == NULL)
1308ab000fcSnicm return;
1318ab000fcSnicm user->flags &= ~SERVER_ACL_READONLY;
1328ab000fcSnicm
1338ab000fcSnicm TAILQ_FOREACH(c, &clients, entry) {
1348ab000fcSnicm uid = proc_get_peer_uid(c->peer);
1358ab000fcSnicm if (uid != (uid_t)-1 && uid == user->uid)
1368ab000fcSnicm c->flags &= ~CLIENT_READONLY;
1378ab000fcSnicm }
1388ab000fcSnicm }
1398ab000fcSnicm
1408ab000fcSnicm /* Deny this user write access. */
1418ab000fcSnicm void
server_acl_user_deny_write(uid_t uid)1428ab000fcSnicm server_acl_user_deny_write(uid_t uid)
1438ab000fcSnicm {
1448ab000fcSnicm struct server_acl_user *user;
1458ab000fcSnicm struct client *c;
1468ab000fcSnicm
1478ab000fcSnicm user = server_acl_user_find(uid);
1488ab000fcSnicm if (user == NULL)
1498ab000fcSnicm return;
1508ab000fcSnicm user->flags |= SERVER_ACL_READONLY;
1518ab000fcSnicm
1528ab000fcSnicm TAILQ_FOREACH(c, &clients, entry) {
1538ab000fcSnicm uid = proc_get_peer_uid(c->peer);
1548ab000fcSnicm if (uid != (uid_t)-1 && uid == user->uid)
1558ab000fcSnicm c->flags |= CLIENT_READONLY;
1568ab000fcSnicm }
1578ab000fcSnicm }
1588ab000fcSnicm
1598ab000fcSnicm /*
1608ab000fcSnicm * Check if the client's UID exists in the ACL list and if so, set as read only
1618ab000fcSnicm * if needed. Return false if the user does not exist.
1628ab000fcSnicm */
1638ab000fcSnicm int
server_acl_join(struct client * c)1648ab000fcSnicm server_acl_join(struct client *c)
1658ab000fcSnicm {
1668ab000fcSnicm struct server_acl_user *user;
1678ab000fcSnicm uid_t uid;
1688ab000fcSnicm
1698ab000fcSnicm uid = proc_get_peer_uid(c->peer);
1708ab000fcSnicm if (uid == (uid_t)-1)
1718ab000fcSnicm return (0);
1728ab000fcSnicm
1738ab000fcSnicm user = server_acl_user_find(uid);
1748ab000fcSnicm if (user == NULL)
1758ab000fcSnicm return (0);
1768ab000fcSnicm if (user->flags & SERVER_ACL_READONLY)
1778ab000fcSnicm c->flags |= CLIENT_READONLY;
1788ab000fcSnicm return (1);
1798ab000fcSnicm }
1808ab000fcSnicm
1818ab000fcSnicm /* Get UID for user entry. */
1828ab000fcSnicm uid_t
server_acl_get_uid(struct server_acl_user * user)1838ab000fcSnicm server_acl_get_uid(struct server_acl_user *user)
1848ab000fcSnicm {
1858ab000fcSnicm return (user->uid);
1868ab000fcSnicm }
187