1 #include <sys/socket.h>
2 #include <sys/un.h>
3
4 #include "tmate.h"
5
reset_and_enable_authorized_keys(void)6 static void reset_and_enable_authorized_keys(void)
7 {
8 ssh_key *keys = tmate_session->authorized_keys;
9 if (keys) {
10 for (ssh_key *k = keys; *k; k++)
11 ssh_key_free(*k);
12 free(keys);
13 }
14
15 keys = xreallocarray(NULL, sizeof(ssh_key), 1);
16 keys[0] = NULL;
17
18 tmate_session->authorized_keys = keys;
19 }
20
import_ssh_pubkey64(const char * _keystr)21 static ssh_key import_ssh_pubkey64(const char *_keystr)
22 {
23 /* key is formatted as "type base64_key" */
24
25 char * const keystr = xstrdup(_keystr);
26 char *s = keystr;
27 ssh_key ret = NULL;
28
29 char *key_type = strsep(&s, " ");
30 char *key_content = strsep(&s, " ");
31
32 if (!key_content)
33 goto out;
34
35 enum ssh_keytypes_e type = ssh_key_type_from_name(key_type);
36 if (type == SSH_KEYTYPE_UNKNOWN)
37 goto out;
38
39 if (ssh_pki_import_pubkey_base64(key_content, type, &ret) != SSH_OK) {
40 ret = NULL;
41 goto out;
42 }
43 out:
44 free(keystr);
45 return ret;
46 }
47
get_num_authorized_keys(ssh_key * keys)48 int get_num_authorized_keys(ssh_key *keys)
49 {
50 if (!keys)
51 return 0;
52
53 int count = 0;
54 for (ssh_key *k = keys; *k; k++)
55 count++;
56 return count;
57 }
58
append_authorized_key(const char * keystr)59 static void append_authorized_key(const char *keystr)
60 {
61 if (!tmate_session->authorized_keys)
62 reset_and_enable_authorized_keys();
63
64 ssh_key pkey = import_ssh_pubkey64(keystr);
65 if (!pkey)
66 return;
67
68 ssh_key *keys = tmate_session->authorized_keys;
69 int count = get_num_authorized_keys(keys);
70 keys = xreallocarray(keys, sizeof(ssh_key), count+2);
71 tmate_session->authorized_keys = keys;
72
73 keys[count++] = pkey;
74 keys[count] = NULL;
75 }
76
tmate_set(char * key,char * value)77 static void tmate_set(char *key, char *value)
78 {
79 if (!strcmp(key, "authorized_keys"))
80 append_authorized_key(value);
81 }
82
tmate_hook_set_option_auth(const char * name,const char * val)83 void tmate_hook_set_option_auth(const char *name, const char *val)
84 {
85 if (!strcmp(name, "tmate-authorized-keys")) {
86 reset_and_enable_authorized_keys();
87 } else if (!strcmp(name, "tmate-set")) {
88 char *key_value = xstrdup(val);
89 char *s = key_value;
90
91 char *key = strsep(&s, "=");
92 char *value = s;
93 if (value)
94 tmate_set(key, value);
95
96 free(key_value);
97 }
98 }
99
tmate_allow_auth(const char * pubkey)100 bool tmate_allow_auth(const char *pubkey)
101 {
102 /*
103 * Note that we don't accept connections on the tmux socket until we
104 * get the tmate ready message.
105 */
106 if (!tmate_session->authorized_keys)
107 return true;
108
109 if (!pubkey)
110 return false;
111
112 ssh_key client_pkey = import_ssh_pubkey64(pubkey);
113 if (!client_pkey)
114 return false;
115
116 bool ret = false;
117 for (ssh_key *k = tmate_session->authorized_keys; *k; k++) {
118 if (!ssh_key_cmp(client_pkey, *k, SSH_KEY_CMP_PUBLIC)) {
119 ret = true;
120 break;
121 }
122 }
123
124 ssh_key_free(client_pkey);
125
126 return ret;
127 }
128
write_all(int fd,const char * buf,size_t len)129 static int write_all(int fd, const char *buf, size_t len)
130 {
131 for (size_t i = 0; i < len;) {
132 size_t ret = write(fd, buf+i, len-i);
133 if (ret <= 0)
134 return -1;
135 i += ret;
136 }
137 return 0;
138 }
139
read_all(int fd,char * buf,size_t len)140 static int read_all(int fd, char *buf, size_t len)
141 {
142 for (size_t i = 0; i < len;) {
143 size_t ret = read(fd, buf+i, len-i);
144 if (ret <= 0)
145 return -1;
146 i += ret;
147 }
148
149 return 0;
150 }
151
152 /*
153 * The following is executed in the context of the SSH server
154 */
would_tmate_session_allow_auth(const char * token,const char * pubkey)155 bool would_tmate_session_allow_auth(const char *token, const char *pubkey)
156 {
157 /*
158 * The existance of this function is a bit unpleasant:
159 * In order to have the right SSH public key from the SSH client,
160 * we need to ask the tmate session for a match. Denying the key
161 * to the SSH client will make it cycle through its keys.
162 * We briefly connect to the session to get an answer.
163 *
164 * Note that the client will get reauthenticated later (see
165 * server-client.c when identifying the client).
166 */
167 int sock_fd = -1;
168 int ret = true;
169
170 if (tmate_validate_session_token(token) < 0)
171 goto out;
172
173 char *sock_path = get_socket_path(token);
174
175 struct sockaddr_un sa;
176 memset(&sa, 0, sizeof(sa));
177 sa.sun_family = AF_UNIX;
178 size_t size = strlcpy(sa.sun_path, sock_path, sizeof(sa.sun_path));
179 free(sock_path);
180 if (size >= sizeof sa.sun_path)
181 goto out;
182
183 sock_fd = socket(AF_UNIX, SOCK_STREAM, 0);
184 if (sock_fd < 0)
185 goto out;
186
187 if (connect(sock_fd, (struct sockaddr *)&sa, sizeof sa) == -1)
188 goto out;
189
190 struct imsg_hdr hdr = {
191 .type = pubkey ? MSG_IDENTIFY_TMATE_AUTH_PUBKEY :
192 MSG_IDENTIFY_TMATE_AUTH_NONE,
193 .len = IMSG_HEADER_SIZE + (pubkey ? strlen(pubkey)+1 : 0),
194 .flags = 0,
195 .peerid = PROTOCOL_VERSION,
196 .pid = -1,
197 };
198
199 if (write_all(sock_fd, (void*)&hdr, sizeof(hdr)) < 0)
200 goto out;
201
202 if (pubkey) {
203 if (write_all(sock_fd, pubkey, strlen(pubkey)+1) < 0)
204 goto out;
205 }
206
207 struct {
208 struct imsg_hdr hdr;
209 bool allow;
210 } __packed recv_msg;
211
212 if (read_all(sock_fd, (void*)&recv_msg, sizeof(recv_msg)) < 0)
213 goto out;
214
215 if (recv_msg.hdr.type == MSG_TMATE_AUTH_STATUS &&
216 recv_msg.hdr.len == sizeof(recv_msg))
217 ret = recv_msg.allow;
218
219 tmate_debug("(preauth) allow=%d", ret);
220
221 out:
222 if (sock_fd != -1)
223 close(sock_fd);
224 return ret;
225 }
226