Annotation of src/usr.bin/tmux/server-acl.c, Revision 1.2
1.2 ! nicm 1: /* $OpenBSD: server-acl.c,v 1.1 2022/05/30 12:48:57 nicm Exp $ */
1.1 nicm 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: #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: {
44: if (user1->uid < user2->uid)
1.2 ! nicm 45: return (-1);
! 46: return (user1->uid > user2->uid);
1.1 nicm 47: }
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: {
56: RB_INIT(&server_acl_entries);
57:
58: if (getuid() != 0)
59: server_acl_user_allow(0);
60: server_acl_user_allow(getuid());
61: }
62:
63: /* Find user entry. */
64: struct server_acl_user*
65: server_acl_user_find(uid_t uid)
66: {
67: struct server_acl_user find = { .uid = uid };
68:
1.2 ! nicm 69: return (RB_FIND(server_acl_entries, &server_acl_entries, &find));
1.1 nicm 70: }
71:
72: /* Display the tree. */
73: void
74: server_acl_display(struct cmdq_item *item)
75: {
76: struct server_acl_user *loop;
77: struct passwd *pw;
78: const char *name;
79:
80: RB_FOREACH(loop, server_acl_entries, &server_acl_entries) {
81: if (loop->uid == 0)
82: continue;
83: if ((pw = getpwuid(loop->uid)) != NULL)
84: name = pw->pw_name;
85: else
86: name = "unknown";
87: if (loop->flags == SERVER_ACL_READONLY)
88: cmdq_print(item, "%s (R)", name);
89: else
90: cmdq_print(item, "%s (W)", name);
91: }
92: }
93:
94: /* Allow a user. */
95: void
96: server_acl_user_allow(uid_t uid)
97: {
98: struct server_acl_user *user;
99:
100: user = server_acl_user_find(uid);
101: if (user == NULL) {
102: user = xcalloc(1, sizeof *user);
103: user->uid = uid;
104: RB_INSERT(server_acl_entries, &server_acl_entries, user);
105: }
106: }
107:
108: /* Deny a user (remove from the tree). */
109: void
110: server_acl_user_deny(uid_t uid)
111: {
112: struct server_acl_user *user;
113:
114: user = server_acl_user_find(uid);
115: if (user != NULL) {
116: RB_REMOVE(server_acl_entries, &server_acl_entries, user);
117: free(user);
118: }
119: }
120:
121: /* Allow this user write access. */
122: void
123: server_acl_user_allow_write(uid_t uid)
124: {
125: struct server_acl_user *user;
126: struct client *c;
127:
128: user = server_acl_user_find(uid);
129: if (user == NULL)
130: return;
131: user->flags &= ~SERVER_ACL_READONLY;
132:
133: TAILQ_FOREACH(c, &clients, entry) {
134: uid = proc_get_peer_uid(c->peer);
135: if (uid != (uid_t)-1 && uid == user->uid)
136: c->flags &= ~CLIENT_READONLY;
137: }
138: }
139:
140: /* Deny this user write access. */
141: void
142: server_acl_user_deny_write(uid_t uid)
143: {
144: struct server_acl_user *user;
145: struct client *c;
146:
147: user = server_acl_user_find(uid);
148: if (user == NULL)
149: return;
150: user->flags |= SERVER_ACL_READONLY;
151:
152: TAILQ_FOREACH(c, &clients, entry) {
153: uid = proc_get_peer_uid(c->peer);
154: if (uid != (uid_t)-1 && uid == user->uid)
155: c->flags |= CLIENT_READONLY;
156: }
157: }
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: {
166: struct server_acl_user *user;
167: uid_t uid;
168:
169: uid = proc_get_peer_uid(c->peer);
170: if (uid == (uid_t)-1)
171: return (0);
172:
173: user = server_acl_user_find(uid);
174: if (user == NULL)
175: return (0);
176: if (user->flags & SERVER_ACL_READONLY)
177: c->flags |= CLIENT_READONLY;
178: return (1);
179: }
180:
181: /* Get UID for user entry. */
182: uid_t
183: server_acl_get_uid(struct server_acl_user *user)
184: {
185: return (user->uid);
186: }