diff options
Diffstat (limited to 'src/medsrv/controller/user_controller.c')
-rwxr-xr-x | src/medsrv/controller/user_controller.c | 363 |
1 files changed, 363 insertions, 0 deletions
diff --git a/src/medsrv/controller/user_controller.c b/src/medsrv/controller/user_controller.c new file mode 100755 index 000000000..9e6d12340 --- /dev/null +++ b/src/medsrv/controller/user_controller.c @@ -0,0 +1,363 @@ +/* + * Copyright (C) 2008 Martin Willi + * Copyright (C) 2008 Philip Boetschi, Adrian Doerig + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * $Id$ + */ + +#define _GNU_SOURCE +#include <string.h> + +#include "user_controller.h" + +#include <library.h> + +typedef struct private_user_controller_t private_user_controller_t; + +/** + * private data of the user_controller + */ +struct private_user_controller_t { + + /** + * public functions + */ + user_controller_t public; + + /** + * database connection + */ + database_t *db; + + /** + * user session + */ + user_t *user; + + /** + * minimum required password lenght + */ + u_int password_length; +}; + +/** + * hash the password for database storage + */ +static chunk_t hash_password(char *login, char *password) +{ + hasher_t *hasher; + chunk_t hash, data; + + hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1); + if (!hasher) + { + return chunk_empty; + } + data = chunk_cata("cc", chunk_create(login, strlen(login)), + chunk_create(password, strlen(password))); + hasher->allocate_hash(hasher, data, &hash); + hasher->destroy(hasher); + return hash; +} + +/** + * Login a user. + */ +static void login(private_user_controller_t *this, request_t *request) +{ + if (request->get_query_data(request, "submit")) + { + char *login, *password; + + login = request->get_query_data(request, "login"); + password = request->get_query_data(request, "password"); + + if (login && password) + { + enumerator_t *query; + u_int id = 0; + chunk_t hash; + + hash = hash_password(login, password); + query = this->db->query(this->db, + "SELECT id FROM user WHERE login = ? AND password = ?", + DB_TEXT, login, DB_BLOB, hash, DB_UINT); + if (query) + { + query->enumerate(query, &id); + query->destroy(query); + } + free(hash.ptr); + if (id) + { + this->user->set_user(this->user, id); + return request->redirect(request, "peer/list"); + } + } + request->setf(request, "error=Invalid username or password."); + } + request->render(request, "templates/user/login.cs"); +} + +/** + * Logout a user. + */ +static void logout(private_user_controller_t *this, request_t *request) +{ + request->redirect(request, "user/login"); + request->close_session(request); +} + +/** + * verify a user entered username for validity + */ +static bool verify_login(private_user_controller_t *this, request_t *request, + char *login) +{ + if (!login || *login == '\0') + { + request->setf(request, "error=Username is missing."); + return FALSE; + } + while (*login != '\0') + { + switch (*login) + { + case 'a' ... 'z': + case 'A' ... 'Z': + case '0' ... '9': + case '-': + case '_': + case '@': + case '.': + login++; + continue; + default: + request->setf(request, "error=Username invalid, " + "valid characters: A-Z a-z 0-9 - _ @ ."); + } + } + return TRUE; +} + +/** + * verify a user entered password for validity + */ +static bool verify_password(private_user_controller_t *this, request_t *request, + char *password, char *confirm) +{ + if (!password || *password == '\0') + { + request->setf(request, "error=Password is missing."); + return FALSE; + } + if (strlen(password) < this->password_length) + { + request->setf(request, "error=Password requires at least %d characters.", + this->password_length); + return FALSE; + } + if (!confirm || !streq(password, confirm)) + { + request->setf(request, "error=Password not confirmed."); + return FALSE; + } + return TRUE; +} + +/** + * Register a user. + */ +static void add(private_user_controller_t *this, request_t *request) +{ + char *login = ""; + + while (request->get_query_data(request, "register")) + { + char *password, *confirm; + chunk_t hash; + u_int id; + + login = request->get_query_data(request, "new_login"); + password = request->get_query_data(request, "new_password"); + confirm = request->get_query_data(request, "confirm_password"); + + if (!verify_login(this, request, login) || + !verify_password(this, request, password, confirm)) + { + break; + } + + hash = hash_password(login, password); + if (!hash.ptr || this->db->execute(this->db, &id, + "INSERT INTO user (login, password) VALUES (?, ?)", + DB_TEXT, login, DB_BLOB, hash) < 0) + { + request->setf(request, "error=Username already exists."); + free(hash.ptr); + break; + } + free(hash.ptr); + this->user->set_user(this->user, id); + return request->redirect(request, "peer/list"); + } + request->set(request, "new_login", login); + request->setf(request, "password_length=%d", this->password_length); + request->render(request, "templates/user/add.cs"); +} + +/** + * Edit the logged in user + */ +static void edit(private_user_controller_t *this, request_t *request) +{ + enumerator_t *query; + char *old_login; + + /* lookup old login */ + query = this->db->query(this->db, "SELECT login FROM user WHERE id = ?", + DB_INT, this->user->get_user(this->user), + DB_TEXT); + if (!query || !query->enumerate(query, &old_login)) + { + DESTROY_IF(query); + request->close_session(request); + return request->redirect(request, "user/login"); + } + old_login = strdupa(old_login); + query->destroy(query); + + /* back pressed */ + if (request->get_query_data(request, "back")) + { + return request->redirect(request, "peer/list"); + } + /* delete pressed */ + if (request->get_query_data(request, "delete")) + { + this->db->execute(this->db, NULL, "DELETE FROM user WHERE id = ?", + DB_UINT, this->user->get_user(this->user)); + this->db->execute(this->db, NULL, + "DELETE FROM peer WHERE user = ?", + DB_UINT, this->user->get_user(this->user)); + return logout(this, request); + } + /* save pressed */ + while (request->get_query_data(request, "save")) + { + char *new_login, *old_pass, *new_pass, *confirm; + chunk_t old_hash, new_hash; + + new_login = request->get_query_data(request, "old_login"); + old_pass = request->get_query_data(request, "old_password"); + new_pass = request->get_query_data(request, "new_password"); + confirm = request->get_query_data(request, "confirm_password"); + + if (!verify_login(this, request, new_login) || + !verify_password(this, request, new_pass, confirm)) + { + old_login = new_login; + break; + } + old_hash = hash_password(old_login, old_pass); + new_hash = hash_password(new_login, new_pass); + + if (this->db->execute(this->db, NULL, + "UPDATE user SET login = ?, password = ? " + "WHERE id = ? AND password = ?", + DB_TEXT, new_login, DB_BLOB, new_hash, + DB_UINT, this->user->get_user(this->user), DB_BLOB, old_hash) <= 0) + { + free(new_hash.ptr); + free(old_hash.ptr); + old_login = new_login; + request->setf(request, "error=Password verification failed."); + break; + } + free(new_hash.ptr); + free(old_hash.ptr); + return request->redirect(request, "peer/list"); + } + /* on error/template rendering */ + request->set(request, "old_login", old_login); + request->setf(request, "password_length=%d", this->password_length); + request->render(request, "templates/user/edit.cs"); +} + +/** + * Implementation of controller_t.get_name + */ +static char* get_name(private_user_controller_t *this) +{ + return "user"; +} + +/** + * Implementation of controller_t.handle + */ +static void handle(private_user_controller_t *this, request_t *request, char *action) +{ + if (action) + { + if (streq(action, "add")) + { + return add(this, request); + } + if (streq(action, "login")) + { + return login(this, request); + } + else if (streq(action, "logout")) + { + return logout(this, request); + } + else if (streq(action, "edit")) + { + return edit(this, request); + } + else if (streq(action, "help")) + { + return request->render(request, "templates/user/help.cs"); + } + } + request->redirect(request, "user/login"); +} + +/** + * Implementation of controller_t.destroy + */ +static void destroy(private_user_controller_t *this) +{ + free(this); +} + +/* + * see header file + */ +controller_t *user_controller_create(user_t *user, database_t *db) +{ + private_user_controller_t *this= malloc_thing(private_user_controller_t); + + this->public.controller.get_name = (char*(*)(controller_t*))get_name; + this->public.controller.handle = (void(*)(controller_t*, request_t*, char*, char*, char*, char*, char*))handle; + this->public.controller.destroy = (void(*)(controller_t*))destroy; + + this->user = user; + this->db = db; + this->password_length = lib->settings->get_int(lib->settings, + "medsrv.password_length", 6); + + return &this->public.controller; +} + |