AmendHub

Download

jcs

/

subtext

/

user.c

 

(View History)

jcs   user: constify banned usernames Latest amendment: 279 on 2022-11-11

1 /*
2 * Copyright (c) 2021-2022 joshua stein <jcs@jcs.org>
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17 #include <ctype.h>
18 #include <string.h>
19
20 #include "bile.h"
21 #include "db.h"
22 #include "sha2.h"
23 #include "subtext.h"
24 #include "user.h"
25 #include "util.h"
26
27 static const char *BANNED_USERNAMES[] = {
28 "admin", "administrator", "\"admin", "admin1",
29 "client", "contact",
30 "daemon", "default",
31 "enable",
32 "fraud",
33 "guest",
34 "help", "hostmaster",
35 "mailer-daemon",
36 "moderator", "moderators",
37 "nobody", "notme",
38 "postmaster",
39 "root", "\"root",
40 "security", "server", "support", "sventek", "sysop", "system",
41 "test",
42 "ubnt", "unknown",
43 "webmaster",
44 };
45
46 void
47 user_cache_usernames(void)
48 {
49 struct user user;
50 struct username_cache *muser;
51 struct bile_object *o;
52 size_t nuser, len;
53
54 if (db->username_cache != NULL)
55 xfree(&db->username_cache);
56
57 db->nusers = bile_count_by_type(db->bile, DB_USER_RTYPE);
58 db->username_cache = xmalloczero(sizeof(struct username_cache) *
59 db->nusers, "username_cache");
60
61 nuser = 0;
62 while ((o = bile_get_nth_of_type(db->bile, nuser, DB_USER_RTYPE))) {
63 muser = &db->username_cache[nuser];
64 muser->id = o->id;
65
66 len = bile_read(db->bile, DB_USER_RTYPE, o->id, (char *)&user,
67 sizeof(user));
68 if (len != sizeof(user))
69 warn("user_update_cache_map: user %lu read size %lu != %lu (%d)",
70 o->id, len, sizeof(user), bile_error(db->bile));
71
72 strncpy(muser->username, user.username, sizeof(muser->username));
73
74 xfree(&o);
75 nuser++;
76 }
77 }
78
79 void
80 user_save(struct user *user)
81 {
82 size_t len, n;
83
84 if (!user->id) {
85 user->id = bile_next_id(db->bile, DB_USER_RTYPE);
86 user->created_at = Time;
87 }
88
89 len = bile_write(db->bile, DB_USER_RTYPE, user->id,
90 user, sizeof(struct user));
91 if (len != sizeof(struct user))
92 panic("user_save: failed to write: %d", bile_error(db->bile));
93
94 bile_flush(db->bile, true);
95 }
96
97 struct user *
98 user_find(unsigned long id)
99 {
100 struct user *user;
101 char *data;
102 size_t len;
103
104 len = bile_read_alloc(db->bile, DB_USER_RTYPE, id, &data);
105 if (len == 0 || data == NULL)
106 return NULL;
107 if (len != sizeof(struct user))
108 panic("user_find: bad user record size %lu != %lu", len,
109 sizeof(struct user));
110 user = xmalloczero(sizeof(struct user), "user_find");
111 memcpy(user, data, sizeof(struct user));
112 xfree(&data);
113 return user;
114 }
115
116 struct user *
117 user_find_by_username(const char *username)
118 {
119 struct user suser;
120 struct username_cache *muser;
121 short n;
122 size_t len;
123
124 len = strlen(username);
125 if (len > sizeof(suser.username))
126 return NULL;
127
128 for (n = 0; n < db->nusers; n++) {
129 muser = &db->username_cache[n];
130
131 if (strcasecmp(muser->username, username) == 0)
132 return user_find(muser->id);
133 }
134
135 return NULL;
136 }
137
138 struct username_cache *
139 user_username(unsigned long id)
140 {
141 struct username_cache *muser;
142 size_t n;
143
144 for (n = 0; n < db->nusers; n++) {
145 muser = &db->username_cache[n];
146 if (muser->id == id)
147 return muser;
148 }
149
150 return NULL;
151 }
152
153 short
154 user_authenticate(struct user *user, const char *password)
155 {
156 char hash[SHA256_DIGEST_STRING_LENGTH];
157 char *salted;
158 size_t plen, slen;
159 short n;
160 unsigned char res;
161
162 plen = strlen(password);
163 slen = SHA256_DIGEST_STRING_LENGTH - 1 + plen;
164 salted = xmalloc(slen, "user_authenticate");
165 memcpy(salted, user->password_salt, SHA256_DIGEST_STRING_LENGTH - 1);
166 memcpy(salted + SHA256_DIGEST_STRING_LENGTH - 1, password, plen);
167
168 SHA256Data((const u_int8_t *)salted, slen, hash);
169
170 /* timing-safe comparison */
171 for (res = 0, n = 0; n < SHA256_DIGEST_STRING_LENGTH; n++)
172 res |= (hash[n] ^ user->password_hash[n]);
173
174 memset(&hash, 0, sizeof(hash));
175 memset(salted, 0, slen);
176 xfree(&salted);
177
178 if (res == 0)
179 return AUTH_USER_OK;
180
181 return AUTH_USER_FAILED;
182 }
183
184 void
185 user_set_password(struct user *user, const char *password)
186 {
187 char hash[SHA256_DIGEST_STRING_LENGTH];
188 char salt[SHA256_DIGEST_STRING_LENGTH];
189 char *salted;
190 unsigned long tmp[8];
191 size_t plen, slen;
192 short n;
193
194 /* make a random salt out of a sha256 of some random longs */
195 for (n = 0; n < sizeof(tmp); n++)
196 tmp[n] = xorshift32();
197
198 SHA256Data((const u_int8_t *)tmp, sizeof(tmp), salt);
199 memcpy(&user->password_salt, &salt, sizeof(salt));
200
201 plen = strlen(password);
202 slen = plen + sizeof(salt) - 1;
203 salted = xmalloc(slen, "user_set_password");
204 memcpy(salted, salt, sizeof(salt) - 1); /* exclude null */
205 memcpy(salted + sizeof(salt) - 1, password, plen);
206 SHA256Data((const u_int8_t *)salted, slen, hash);
207 memset(salted, 0, slen);
208 xfree(&salted);
209
210 memcpy(&user->password_hash, &hash, sizeof(user->password_hash));
211
212 memset(&hash, 0, sizeof(hash));
213 memset(&salt, 0, sizeof(salt));
214 }
215
216 bool
217 user_valid_username(struct user *user, char *username, char **error)
218 {
219 struct user *ouser;
220 unsigned long ouser_id;
221 size_t len, n;
222 char c;
223
224 if (username == NULL) {
225 *error = xstrdup("username cannot be empty", "user_valid_username");
226 return false;
227 }
228
229 len = strlen(username);
230 if (len > DB_USERNAME_LENGTH) {
231 *error = xmalloc(61, "user_valid_username");
232 snprintf(*error, 60, "username cannot be more than %d characters",
233 DB_USERNAME_LENGTH);
234 return false;
235 }
236
237 for (n = 0; n < len; n++) {
238 c = username[n];
239
240 if (!((c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') ||
241 (c >= 'a' && c <= 'z') || c == '_')) {
242 *error = xstrdup("username cannot contain non-alphanumeric "
243 "characters", "user_valid_username");
244 return false;
245 }
246 }
247
248 if (strcasecmp(username, GUEST_USERNAME) == 0) {
249 *error = xstrdup("username is already in use",
250 "user_valid_username");
251 return false;
252 }
253
254 if (!(user != NULL && user->is_sysop) &&
255 user_username_is_banned(username)) {
256 *error = xstrdup("username is not permitted", "user_valid_username");
257 return false;
258 }
259
260 if ((ouser = user_find_by_username(username))) {
261 ouser_id = ouser->id;
262 xfree(&ouser);
263
264 if (user == NULL || ouser_id != user->id) {
265 *error = xstrdup("username is already in use",
266 "user_valid_username");
267 return false;
268 }
269 }
270
271 return true;
272 }
273
274 bool
275 user_username_is_banned(char *username)
276 {
277 size_t n;
278
279 for (n = 0; n < nitems(BANNED_USERNAMES); n++) {
280 if (strcasecmp(username, BANNED_USERNAMES[n]) == 0)
281 return true;
282 }
283
284 return false;
285 }
286
287 char *
288 user_first_sysop_username(void)
289 {
290 struct user user;
291 struct bile_object *o;
292 char *ret = NULL;
293 size_t nuser, len;
294
295 nuser = 0;
296 while ((o = bile_get_nth_of_type(db->bile, nuser, DB_USER_RTYPE))) {
297 len = bile_read(db->bile, DB_USER_RTYPE, o->id, (char *)&user,
298 sizeof(user));
299 xfree(&o);
300 if (user.is_sysop) {
301 ret = xstrdup(user.username, "user_first_sysop_username");
302 break;
303 }
304 nuser++;
305 }
306
307 return ret;
308 }
309
310 void
311 user_change_password(struct session *s, struct user *user)
312 {
313 char *password = NULL, *password_confirm = NULL;
314
315 if (!user) {
316 session_printf(s, "{{B}}Error{{/B}}: Guest accounts "
317 "cannot change passwords\r\n");
318 return;
319 }
320
321 while (!s->ending) {
322 session_printf(s, "{{B}}New Password:{{/B}} ");
323 session_flush(s);
324 password = session_field_input(s, 64, 64, NULL, false, '*');
325 session_output(s, "\r\n", 2);
326 session_flush(s);
327
328 if (password == NULL || s->ending)
329 break;
330
331 if (password[0] == '\0') {
332 session_printf(s, "{{B}}Error:{{/B}} "
333 "Password cannot be blank\r\n");
334 xfree(&password);
335 password = NULL;
336 continue;
337 }
338
339 session_printf(s, "{{B}}New Password (again):{{/B}} ");
340 session_flush(s);
341 password_confirm = session_field_input(s, 64, 64, NULL, false, '*');
342 session_output(s, "\r\n", 2);
343 session_flush(s);
344
345 if (password_confirm == NULL || s->ending)
346 break;
347
348 if (strcmp(password_confirm, password) != 0) {
349 session_printf(s, "{{B}}Error:{{/B}} "
350 "Passwords do not match\r\n");
351 xfree(&password);
352 password = NULL;
353 xfree(&password_confirm);
354 password_confirm = NULL;
355 continue;
356 }
357
358 user_set_password(user, password);
359 user_save(user);
360
361 if (strcmp(s->user->username, user->username) == 0) {
362 session_logf(s, "User changed password");
363 session_printf(s, "{{B}}Your password has been "
364 "changed{{/B}}\r\n");
365 } else {
366 session_logf(s, "User %s changed password for %s",
367 s->user->username, user->username);
368 session_printf(s, "{{B}}Password has been "
369 "changed{{/B}}\r\n");
370 }
371
372 break;
373 }
374
375 if (password != NULL)
376 xfree(&password);
377 if (password_confirm != NULL)
378 xfree(&password_confirm);
379 }
380
381 void
382 user_delete(struct user *user)
383 {
384 struct bile_object *o;
385 unsigned long msg_user_id, id;
386 size_t n;
387
388 /* delete the user's mail */
389 n = 0;
390 while (o = bile_get_nth_of_type(db->bile, n, DB_MESSAGE_RTYPE)) {
391 id = o->id;
392 bile_read(db->bile, DB_MESSAGE_RTYPE, id, (char *)&msg_user_id,
393 sizeof(msg_user_id));
394 xfree(&o);
395
396 if (msg_user_id != user->id) {
397 n++;
398 continue;
399 }
400
401 bile_delete(db->bile, DB_MESSAGE_RTYPE, id);
402
403 /* don't increase n, the remaining messages will shift down */
404 }
405
406 /* delete the user */
407 bile_delete(db->bile, DB_USER_RTYPE, user->id);
408 }