Change the timer syscalls so that sysret_t can be 32-bit
[monolithium.git] / kernel / src / user.c
1 /*
2  * user.c
3  *
4  * Copyright (C) 2013 Aleksandar Andrejevic <theflash@sdf.lonestar.org>
5  *
6  * This program is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU Affero General Public License as
8  * published by the Free Software Foundation, either version 3 of the
9  * License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU Affero General Public License for more details.
15  *
16  * You should have received a copy of the GNU Affero General Public License
17  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include <user.h>
21 #include <process.h>
22 #include <heap.h>
23 #include <timer.h>
24
25 static user_t *reference_user_by_id(uid_t uid)
26 {
27     user_t *user = NULL;
28
29     while (enum_objects_by_type(OBJECT_USER, (object_t**)&user) == ERR_SUCCESS)
30     {
31         if (user->uid == uid) return user;
32     }
33
34     return NULL;
35 }
36
37 static dword_t add_user(uid_t uid, const char *name, dword_t *password_hash, qword_t privileges)
38 {
39     user_t *user;
40
41     if ((user = reference_user_by_id(uid)) != NULL)
42     {
43         dereference(&user->header);
44         return ERR_EXISTS;
45     }
46
47     if (reference_by_name(name, OBJECT_USER, (object_t**)&user))
48     {
49         dereference(&user->header);
50         return ERR_EXISTS;
51     }
52
53     user = (user_t*)malloc(sizeof(user_t));
54     if (user == NULL) return ERR_NOMEMORY;
55
56     init_object(&user->header, name, OBJECT_USER);
57     user->uid = uid;
58     memcpy(user->password_hash, password_hash, sizeof(user->password_hash));
59     user->privileges = privileges;
60
61     dword_t ret = create_object(&user->header);
62     if (ret != ERR_SUCCESS)
63     {
64         free(user->header.name);
65         free(user);
66     }
67
68     return ret;
69 }
70
71 static void sha256_compute(byte_t *buffer, size_t size, dword_t *sum)
72 {
73     static const dword_t round_constants[] =
74     {
75         0x428A2F98, 0x71374491, 0xB5C0FBCF, 0xE9B5DBA5, 0x3956C25B, 0x59F111F1, 0x923F82A4, 0xAB1C5ED5,
76         0xD807AA98, 0x12835B01, 0x243185BE, 0x550C7DC3, 0x72BE5D74, 0x80DEB1FE, 0x9BDC06A7, 0xC19BF174,
77         0xE49B69C1, 0xEFBE4786, 0x0FC19DC6, 0x240CA1CC, 0x2DE92C6F, 0x4A7484AA, 0x5CB0A9DC, 0x76F988DA,
78         0x983E5152, 0xA831C66D, 0xB00327C8, 0xBF597FC7, 0xC6E00BF3, 0xD5A79147, 0x06CA6351, 0x14292967,
79         0x27B70A85, 0x2E1B2138, 0x4D2C6DFC, 0x53380D13, 0x650A7354, 0x766A0ABB, 0x81C2C92E, 0x92722C85,
80         0xA2BFE8A1, 0xA81A664B, 0xC24B8B70, 0xC76C51A3, 0xD192E819, 0xD6990624, 0xF40E3585, 0x106AA070,
81         0x19A4C116, 0x1E376C08, 0x2748774C, 0x34B0BCB5, 0x391C0CB3, 0x4ED8AA4A, 0x5B9CCA4F, 0x682E6FF3,
82         0x748F82EE, 0x78A5636F, 0x84C87814, 0x8CC70208, 0x90BEFFFA, 0xA4506CEB, 0xBEF9A3F7, 0xC67178F2
83     };
84
85     size_t i, j;
86     dword_t message[64];
87     size_t num_chunks = (size >> 6) + ((size & 0x3F) > 55) ? 2 : 1;
88
89     sum[0] = 0x6A09E667;
90     sum[1] = 0xBB67AE85;
91     sum[2] = 0x3C6EF372;
92     sum[3] = 0xA54FF53A;
93     sum[4] = 0x510E527F;
94     sum[5] = 0x9B05688C;
95     sum[6] = 0x1F83D9AB;
96     sum[7] = 0x5BE0CD19;
97
98     for (i = 0; i < num_chunks; i++)
99     {
100         for (j = 0; j < 64; j++)
101         {
102             byte_t value = 0;
103
104             if ((i << 6) + j < size) value = buffer[(i << 6) + j];
105             else if ((i << 6) + j == size) value = 0x80;
106             else if (i == num_chunks - 1 && j >= 56) value = ((size << 3) >> ((63 - j) << 3)) & 0xFF;
107
108             switch (j & 3)
109             {
110             case 0:
111                 message[j >> 2] = value << 24;
112                 break;
113             case 1:
114                 message[j >> 2] |= value << 16;
115                 break;
116             case 2:
117                 message[j >> 2] |= value << 8;
118                 break;
119             case 3:
120                 message[j >> 2] |= value;
121                 break;
122             }
123         }
124
125         for (j = 16; j < 64; j++)
126         {
127             message[j] = message[j - 7] + message[j - 16]
128                          + (((message[j - 15] >> 7) | (message[j - 15] << 25))
129                          ^ ((message[j - 15] >> 18) | (message[j - 15] << 14))
130                          ^ (message[j - 15] >> 3))
131                          + (((message[j - 2] >> 17) | (message[j - 2] << 15))
132                          ^ ((message[j - 2] >> 19) | (message[j - 2] << 13))
133                          ^ (message[j - 2] >> 10));
134         }
135
136         dword_t vars[8];
137         for (j = 0; j < 8; j++) vars[j] = sum[j];
138
139         for (j = 0; j < 64; j++)
140         {
141             dword_t temp1 = vars[7] + (((vars[4] >> 6) | (vars[4] << 26))
142                             ^ ((vars[4] >> 11) | (vars[4] << 21))
143                             ^ ((vars[4] >> 25) | (vars[4] << 7)))
144                             + ((vars[4] & vars[5]) ^ (~vars[4] & vars[6]))
145                             + round_constants[j] + message[j];
146
147             dword_t temp2 = (((vars[0] >> 2) | (vars[0] << 30))
148                             ^ ((vars[0] >> 13) | (vars[0] << 19))
149                             ^ ((vars[0] >> 22) | (vars[0] << 10)))
150                             + ((vars[0] & vars[1]) ^ (vars[0] & vars[2]) ^ (vars[1] & vars[2]));
151
152             vars[7] = vars[6];
153             vars[6] = vars[5];
154             vars[5] = vars[4];
155             vars[4] = vars[3] + temp1;
156             vars[3] = vars[2];
157             vars[2] = vars[1];
158             vars[1] = vars[0];
159             vars[0] = temp1 + temp2;
160         }
161
162         for (j = 0; j < 8; j++) sum[j] += vars[j];
163     }
164 }
165
166 bool_t check_privileges(qword_t privilege_mask)
167 {
168     qword_t privileges = get_current_process()->current_user->privileges;
169     return ((privileges & privilege_mask) == privilege_mask);
170 }
171
172 dword_t get_current_uid(void)
173 {
174     process_t *proc = get_current_process();
175     return proc && proc->current_user ? proc->current_user->uid : 0;
176 }
177
178 sysret_t syscall_set_user_id(uid_t uid)
179 {
180     process_t *proc = get_current_process();
181     user_t *user = reference_user_by_id(uid);
182     if (user == NULL) return ERR_NOTFOUND;
183
184     if (get_previous_mode() == USER_MODE && !check_privileges(PRIVILEGE_CHANGE_UID))
185     {
186         dereference(&user->header);
187         return ERR_FORBIDDEN;
188     }
189
190     if (proc->current_user) dereference(&proc->current_user->header);
191     proc->current_user = user;
192
193     return ERR_SUCCESS;
194 }
195
196 sysret_t syscall_revert_user()
197 {
198     process_t *proc = get_current_process();
199
200     if (proc->original_user != proc->current_user)
201     {
202         if (proc->current_user) dereference(&proc->current_user->header);
203         reference(&proc->original_user->header);
204         proc->current_user = proc->original_user;
205         return ERR_SUCCESS;
206     }
207     else
208     {
209         return ERR_INVALID;
210     }
211 }
212
213 sysret_t syscall_create_user(uid_t uid, const char *name, dword_t *password_hash, qword_t privileges)
214 {
215     dword_t safe_password_hash[64];
216
217     if (get_previous_mode() == USER_MODE)
218     {
219         if (!check_privileges(privileges | PRIVILEGE_MANAGE_USERS)) return ERR_FORBIDDEN;
220         if (!check_usermode(password_hash, sizeof(safe_password_hash))) return ERR_BADPTR;
221
222         EH_TRY
223         {
224             memcpy(safe_password_hash, password_hash, sizeof(safe_password_hash));
225             password_hash = &safe_password_hash[0];
226         }
227         EH_CATCH
228         {
229             EH_ESCAPE(return ERR_BADPTR);
230         }
231         EH_DONE;
232     }
233
234     return add_user(uid, name, password_hash, privileges);
235 }
236
237 sysret_t syscall_delete_user(uid_t uid)
238 {
239     if (get_previous_mode() == USER_MODE && !check_privileges(PRIVILEGE_MANAGE_USERS))
240     {
241         return ERR_FORBIDDEN;
242     }
243
244     process_t *proc = NULL;
245     dword_t ret = enum_objects_by_type(OBJECT_PROCESS, (object_t**)&proc);
246     ASSERT(ret == ERR_SUCCESS || ret == ERR_NOMORE);
247
248     while (ret == ERR_SUCCESS)
249     {
250         if (proc->current_user->uid == uid || proc->original_user->uid == uid)
251         {
252             dereference(&proc->header);
253             return ERR_BUSY;
254         }
255
256         ret = enum_objects_by_type(OBJECT_PROCESS, (object_t**)&proc);
257     }
258
259     ASSERT(ret == ERR_NOMORE);
260
261     user_t *user = reference_user_by_id(uid);
262     if (user == NULL) return ERR_NOTFOUND;
263
264     dereference(&user->header);
265     dereference(&user->header);
266
267     return ERR_SUCCESS;
268 }
269
270 sysret_t syscall_logon_user(uid_t uid, const char *password)
271 {
272     dword_t ret;
273     process_t *proc = get_current_process();
274     user_t *user = reference_user_by_id(uid);
275     user_t *current_user = get_current_process()->current_user;
276     char *safe_password;
277
278     if (user == NULL) return ERR_NOTFOUND;
279     if ((timer_get_milliseconds() - current_user->last_login_attempt) < LOGIN_ATTEMPT_TIMEOUT) return ERR_BUSY;
280
281     if (get_previous_mode() == USER_MODE)
282     {
283         safe_password = copy_user_string(password);
284     }
285     else
286     {
287         safe_password = (char*)password;
288     }
289
290     if (uid == 0)
291     {
292         current_user->last_login_attempt = timer_get_milliseconds();
293         ret = ERR_INVALID;
294         goto cleanup;
295     }
296
297     char *salted = (char*)__builtin_alloca(strlen(user->name) + strlen(password) + 4);
298     strcpy(salted, "%");
299     strcat(salted, user->name);
300     strcat(salted, "%");
301     strcat(salted, password);
302     strcat(salted, "%");
303
304     dword_t hash_sum[64];
305     sha256_compute((byte_t*)salted, strlen(salted), hash_sum);
306
307     if (memcmp(hash_sum, user->password_hash, sizeof(hash_sum)) == 0)
308     {
309         reference(&user->header);
310         proc->current_user = user;
311         ret = ERR_SUCCESS;
312     }
313     else
314     {
315         user->last_login_attempt = timer_get_milliseconds();
316         ret = ERR_INVALID;
317     }
318
319 cleanup:
320     dereference(&user->header);
321     if (get_previous_mode() == USER_MODE) free(safe_password);
322     return ret;
323 }
324
325 sysret_t syscall_query_user(uid_t uid, user_info_t info_type, void *buffer, dword_t size)
326 {
327     dword_t ret = ERR_SUCCESS;
328     void *safe_buffer;
329
330     user_t *user = reference_user_by_id(uid);
331     if (user == NULL) return ERR_NOTFOUND;
332
333     if (get_previous_mode() == USER_MODE)
334     {
335         if (!check_usermode(buffer, size))
336         {
337             ret = ERR_BADPTR;
338             goto cleanup;
339         }
340
341         safe_buffer = malloc(size);
342
343         if (safe_buffer == NULL)
344         {
345             ret = ERR_NOMEMORY;
346             goto cleanup;
347         }
348
349         memset(safe_buffer, 0, size);
350     }
351     else
352     {
353         safe_buffer = buffer;
354     }
355
356     switch (info_type)
357     {
358     case USER_NAME_INFO:
359         if (size >= sizeof(strlen(user->name) + 1)) strcpy(safe_buffer, user->name);
360         else ret = ERR_SMALLBUF;
361
362         break;
363
364     case USER_PRIVILEGE_INFO:
365         if (size >= sizeof(qword_t)) *((qword_t*)safe_buffer) = user->privileges;
366         else ret = ERR_SMALLBUF;
367
368         break;
369
370     default:
371         ret = ERR_INVALID;
372     }
373
374     if (get_previous_mode() == USER_MODE)
375     {
376         EH_TRY memcpy(buffer, safe_buffer, size);
377         EH_CATCH ret = ERR_BADPTR;
378         EH_DONE;
379     }
380
381 cleanup:
382     dereference(&user->header);
383     return ret;
384 }
385
386 void user_init()
387 {
388     dword_t blank_password_hash[64] = { 0 };
389
390     if (add_user(0, "root", blank_password_hash, ALL_PRIVILEGES) != ERR_SUCCESS)
391     {
392         KERNEL_CRASH("Failed to create root user!");
393     }
394
395     user_t *root = reference_user_by_id(0);
396     reference(&root->header);
397
398     kernel_process->original_user = kernel_process->current_user = root;
399 }