1#include <stdlib.h>
2#include <string.h>
3#include <strings.h>
4
5#include "config.h"
6#include "log.h"
7#include "users.h"
8#include "utils.h"
9
10struct users users;
11
12static int allow_push(struct user* u, const char* s);
13static int b64_decode(unsigned char* out, size_t outsz, const char* in);
14static int b64_val(int c);
15static bool ct_equal(const char* a, const char* b);
16static const struct user* find_user(const char* name);
17
18/* Append allow prefix to user entry
19 Returns 0=Success, -1=Failure */
20static int allow_push(struct user* u, const char* s)
21{
22 if (u->allow_len == u->allow_cap) {
23 size_t ncap = u->allow_cap ? (u->allow_cap * 2) : 8;
24 char** nv = realloc(u->allow, ncap * sizeof(*nv));
25 if (!nv)
26 return -1;
27
28 u->allow = nv;
29 u->allow_cap = ncap;
30 }
31
32 char* p = strdup(s);
33 if (!p)
34 return -1;
35
36 u->allow[u->allow_len++] = p;
37 return 0;
38}
39
40/* Decode base64 string
41 Returns 0=Success, -1=Failure */
42static int b64_decode(unsigned char* out, size_t outsz, const char* in)
43{
44 size_t olen = 0;
45 int buf = 0;
46 int bits = 0;
47
48 for (; *in; in++) {
49 int v = b64_val((unsigned char)*in);
50 if (v == -1)
51 continue; /* skip whitespace/junk */
52
53 if (v == -2)
54 break; /* padding */
55
56 buf = (buf << 6) | v; /* append 6 bits */
57 bits += 6;
58
59 if (bits >= 8) {
60 bits -= 8;
61 if (olen + 1 >= outsz)
62 return -1; /* overflow */
63
64 out[olen++] = (unsigned char)((buf >> bits) & 0xff);
65 }
66 }
67
68 if (olen >= outsz)
69 return -1;
70
71 out[olen] = '\0';
72 return 0;
73}
74
75/* Map base64 byte to sextet value
76 Returns 0..63=Value, -2=Padding, -1=Invalid */
77static int b64_val(int c)
78{
79 if (c >= 'A' && c <= 'Z')
80 return c - 'A';
81 if (c >= 'a' && c <= 'z')
82 return c - 'a' + 26;
83 if (c >= '0' && c <= '9')
84 return c - '0' + 52;
85 if (c == '+')
86 return 62;
87 if (c == '/')
88 return 63;
89 if (c == '=')
90 return -2;
91
92 return -1;
93}
94/* Compare two strings in constant time
95 Returns true=Equal, false=Not equal */
96static bool ct_equal(const char* a, const char* b)
97{
98 size_t la = strlen(a);
99 size_t lb = strlen(b);
100 size_t n = (la > lb) ? la : lb;
101
102 unsigned char diff = 0;
103
104 for (size_t i = 0; i < n; i++) {
105 unsigned char ca = (i < la) ? (unsigned char)a[i] : 0;
106 unsigned char cb = (i < lb) ? (unsigned char)b[i] : 0;
107 diff |= (unsigned char)(ca ^ cb);
108 }
109
110 return (diff == 0) && (la == lb);
111}
112
113/* Find user by name
114 Returns User Ptr=Found, NULL=Not found */
115static const struct user* find_user(const char* name)
116{
117 for (size_t i = 0; i < users.len; i++)
118 if (strcmp(users.v[i].name, name) == 0)
119 return &users.v[i];
120
121 return NULL;
122}
123
124/* Check whether path matches allow prefix
125 Returns true=Match, false=No match */
126static bool prefix_ok(const char* path, const char* pre)
127{
128 size_t n = strlen(pre);
129 if (n == 0)
130 return false;
131
132 if (strcmp(pre, "*") == 0)
133 return true;
134
135 if (strncmp(path, pre, n) != 0)
136 return false;
137
138 /* allow match or dir boundary */
139 if (path[n] == '\0')
140 return true;
141 if (pre[n - 1] == '/')
142 return true;
143 if (path[n] == '/')
144 return true;
145
146 return false;
147}
148
149bool user_allows_path(const struct user* u, const char* relpath)
150{
151 if (!u || !relpath)
152 return false;
153
154 /* no allow list -> allow nothing */
155 if (u->allow_len == 0)
156 return false;
157
158 for (size_t i = 0; i < u->allow_len; i++)
159 if (prefix_ok(relpath, u->allow[i]))
160 return true;
161
162 return false;
163}
164
165int users_add_allow(const char* prefix)
166{
167 if (users.len == 0 || !prefix) {
168 LOG_FIELD(true, "AUTH", "AddAllow FAILED", "No user or prefix");
169 return -1;
170 }
171
172 LOG_FIELD(verbose_log, "AUTH", "Allow directories", "%s %s", users.v[users.len - 1].name, prefix);
173
174 return allow_push(&users.v[users.len - 1], prefix);
175}
176
177const struct user* users_auth_from_hdr(const char* hdr)
178{
179 if (users.len == 0)
180 return NULL;
181
182 char auth[512];
183 if (hdr_get_value(auth, hdr, "authorization") < 0) {
184 LOG_FIELD(true, "AUTH", "Authorization", "Not found");
185 return NULL;
186 }
187
188 /* given "Basic XXXX" */
189 const char* p = auth;
190 while (*p == ' ' || *p == '\t')
191 p++;
192
193 if (strncasecmp(p, "Basic", 5) != 0) {
194 LOG_FIELD(verbose_log, "AUTH", "Authorization", "Not Basic");
195 return NULL;
196 }
197
198 p += 5;
199 while (*p == ' ' || *p == '\t')
200 p++;
201
202 if (*p == '\0') {
203 LOG_FIELD(verbose_log, "AUTH", "Basic Auth", "Missing token");
204 return NULL;
205 }
206
207 unsigned char dec[512];
208 if (b64_decode(dec, sizeof(dec), p) < 0) {
209 LOG_FIELD(verbose_log, "AUTH", "Basic Auth", "B64 decode failed");
210 secure_bzero(dec, sizeof(dec));
211 return NULL;
212 }
213
214 char* sep = strchr((char*)dec, ':');
215 if (!sep) {
216 LOG_FIELD(verbose_log, "AUTH", "Basic Auth", "Decoded but missing ':'");
217 secure_bzero(dec, sizeof(dec));
218 return NULL;
219 }
220
221 *sep = '\0';
222 const char* user = (const char*)dec;
223 const char* pass = (const char*)(sep + 1);
224
225 const struct user* u = find_user(user);
226 if (!u) {
227 LOG(true, "AUTH", "Login FAILED Unknown user '%s'", user);
228 secure_bzero(dec, sizeof(dec));
229 return NULL;
230 }
231
232 /* empty password -> passwordless account */
233 if (u->pass[0] == '\0') {
234 if (pass[0] == '\0') {
235 LOG_FIELD(true, "AUTH", "Login OK", "%s", user);
236 secure_bzero(dec, sizeof(dec));
237 return u;
238 }
239 LOG_FIELD(true, "AUTH", "Login FAILED", "%s", user);
240 secure_bzero(dec, sizeof(dec));
241 return NULL;
242 }
243
244 if (!ct_equal(u->pass, pass)) {
245 LOG(true, "AUTH", "Login FAILED Bad password %s", user);
246 secure_bzero(dec, sizeof(dec));
247 return NULL;
248 }
249
250 LOG_FIELD(verbose_log, "AUTH", "Login OK", "%s", user);
251 secure_bzero(dec, sizeof(dec));
252 return u;
253}
254
255void users_free(void)
256{
257 for (size_t i = 0; i < users.len; i++) {
258 for (size_t j = 0; j < users.v[i].allow_len; j++)
259 free(users.v[i].allow[j]);
260 free(users.v[i].allow);
261
262 users.v[i].allow = NULL;
263 users.v[i].allow_len = 0;
264 users.v[i].allow_cap = 0;
265 }
266
267 free(users.v);
268 users.v = NULL;
269 users.len = 0;
270 users.cap = 0;
271}
272
273int users_push(const char* name)
274{
275 if (!name || name[0] == '\0') {
276 LOG_FIELD(true, "AUTH", "UserAdd FAILED", "Empty username");
277 return -1;
278 }
279
280 if (users.len == users.cap) {
281 size_t ncap = users.cap ? (users.cap * 2) : 8;
282 struct user* nv = realloc(users.v, ncap * sizeof(*nv));
283 if (!nv) {
284 LOG_FIELD(true, "AUTH", "realloc FAILED", "(cap=%zu -> %zu)", users.cap, ncap);
285 return -1;
286 }
287 users.v = nv;
288 users.cap = ncap;
289 }
290
291 memset(&users.v[users.len], 0, sizeof(users.v[users.len]));
292 snprintf(users.v[users.len].name, sizeof(users.v[users.len].name), "%s", name);
293
294 LOG_FIELD(verbose_log, "AUTH", "UserAdd SUCCESS", "%s", users.v[users.len].name);
295
296 users.len++;
297 return 0;
298}
299
300int users_set_pass(const char* pass)
301{
302 if (users.len == 0) {
303 LOG_FIELD(true, "AUTH", "SetPass FAILED", "No users");
304 return -1;
305 }
306
307 if (!pass)
308 pass = "";
309
310 /* copy pass->user.pass */
311 snprintf(users.v[users.len - 1].pass, sizeof(users.v[users.len - 1].pass), "%s", pass);
312
313 LOG_FIELD(verbose_log, "AUTH", "Password set for", "%s (%s)",
314 users.v[users.len - 1].name, (pass[0] == '\0') ? "none" : "set"
315 );
316 return 0;
317}
318