2 * Copyright (C) 2008 Martin Willi
3 * Copyright (C) 2008 Philip Boetschi, Adrian Doerig
4 * Hochschule fuer Technik Rapperswil
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22 #include "user_controller.h"
26 typedef struct private_user_controller_t private_user_controller_t
;
29 * private data of the user_controller
31 struct private_user_controller_t
{
36 user_controller_t
public;
49 * minimum required password lenght
51 u_int password_length
;
55 * hash the password for database storage
57 static chunk_t
hash_password(char *login
, char *password
)
62 hasher
= lib
->crypto
->create_hasher(lib
->crypto
, HASH_SHA1
);
67 data
= chunk_cata("cc", chunk_create(login
, strlen(login
)),
68 chunk_create(password
, strlen(password
)));
69 hasher
->allocate_hash(hasher
, data
, &hash
);
70 hasher
->destroy(hasher
);
77 static void login(private_user_controller_t
*this, request_t
*request
)
79 if (request
->get_query_data(request
, "submit"))
81 char *login
, *password
;
83 login
= request
->get_query_data(request
, "login");
84 password
= request
->get_query_data(request
, "password");
86 if (login
&& password
)
92 hash
= hash_password(login
, password
);
93 query
= this->db
->query(this->db
,
94 "SELECT id FROM user WHERE login = ? AND password = ?",
95 DB_TEXT
, login
, DB_BLOB
, hash
, DB_UINT
);
98 query
->enumerate(query
, &id
);
99 query
->destroy(query
);
104 this->user
->set_user(this->user
, id
);
105 return request
->redirect(request
, "peer/list");
108 request
->setf(request
, "error=Invalid username or password.");
110 request
->render(request
, "templates/user/login.cs");
116 static void logout(private_user_controller_t
*this, request_t
*request
)
118 request
->redirect(request
, "user/login");
119 request
->close_session(request
);
123 * verify a user entered username for validity
125 static bool verify_login(private_user_controller_t
*this, request_t
*request
,
128 if (!login
|| *login
== '\0')
130 request
->setf(request
, "error=Username is missing.");
133 while (*login
!= '\0')
147 request
->setf(request
, "error=Username invalid, "
148 "valid characters: A-Z a-z 0-9 - _ @ .");
155 * verify a user entered password for validity
157 static bool verify_password(private_user_controller_t
*this, request_t
*request
,
158 char *password
, char *confirm
)
160 if (!password
|| *password
== '\0')
162 request
->setf(request
, "error=Password is missing.");
165 if (strlen(password
) < this->password_length
)
167 request
->setf(request
, "error=Password requires at least %d characters.",
168 this->password_length
);
171 if (!confirm
|| !streq(password
, confirm
))
173 request
->setf(request
, "error=Password not confirmed.");
182 static void add(private_user_controller_t
*this, request_t
*request
)
186 while (request
->get_query_data(request
, "register"))
188 char *password
, *confirm
;
192 login
= request
->get_query_data(request
, "new_login");
193 password
= request
->get_query_data(request
, "new_password");
194 confirm
= request
->get_query_data(request
, "confirm_password");
196 if (!verify_login(this, request
, login
) ||
197 !verify_password(this, request
, password
, confirm
))
202 hash
= hash_password(login
, password
);
203 if (!hash
.ptr
|| this->db
->execute(this->db
, &id
,
204 "INSERT INTO user (login, password) VALUES (?, ?)",
205 DB_TEXT
, login
, DB_BLOB
, hash
) < 0)
207 request
->setf(request
, "error=Username already exists.");
212 this->user
->set_user(this->user
, id
);
213 return request
->redirect(request
, "peer/list");
215 request
->set(request
, "new_login", login
);
216 request
->setf(request
, "password_length=%d", this->password_length
);
217 request
->render(request
, "templates/user/add.cs");
221 * Edit the logged in user
223 static void edit(private_user_controller_t
*this, request_t
*request
)
228 /* lookup old login */
229 query
= this->db
->query(this->db
, "SELECT login FROM user WHERE id = ?",
230 DB_INT
, this->user
->get_user(this->user
),
232 if (!query
|| !query
->enumerate(query
, &old_login
))
235 request
->close_session(request
);
236 return request
->redirect(request
, "user/login");
238 old_login
= strdupa(old_login
);
239 query
->destroy(query
);
242 if (request
->get_query_data(request
, "back"))
244 return request
->redirect(request
, "peer/list");
247 if (request
->get_query_data(request
, "delete"))
249 this->db
->execute(this->db
, NULL
, "DELETE FROM user WHERE id = ?",
250 DB_UINT
, this->user
->get_user(this->user
));
251 this->db
->execute(this->db
, NULL
,
252 "DELETE FROM peer WHERE user = ?",
253 DB_UINT
, this->user
->get_user(this->user
));
254 return logout(this, request
);
257 while (request
->get_query_data(request
, "save"))
259 char *new_login
, *old_pass
, *new_pass
, *confirm
;
260 chunk_t old_hash
, new_hash
;
262 new_login
= request
->get_query_data(request
, "old_login");
263 old_pass
= request
->get_query_data(request
, "old_password");
264 new_pass
= request
->get_query_data(request
, "new_password");
265 confirm
= request
->get_query_data(request
, "confirm_password");
267 if (!verify_login(this, request
, new_login
) ||
268 !verify_password(this, request
, new_pass
, confirm
))
270 old_login
= new_login
;
273 old_hash
= hash_password(old_login
, old_pass
);
274 new_hash
= hash_password(new_login
, new_pass
);
276 if (this->db
->execute(this->db
, NULL
,
277 "UPDATE user SET login = ?, password = ? "
278 "WHERE id = ? AND password = ?",
279 DB_TEXT
, new_login
, DB_BLOB
, new_hash
,
280 DB_UINT
, this->user
->get_user(this->user
), DB_BLOB
, old_hash
) <= 0)
284 old_login
= new_login
;
285 request
->setf(request
, "error=Password verification failed.");
290 return request
->redirect(request
, "peer/list");
292 /* on error/template rendering */
293 request
->set(request
, "old_login", old_login
);
294 request
->setf(request
, "password_length=%d", this->password_length
);
295 request
->render(request
, "templates/user/edit.cs");
299 * Implementation of controller_t.get_name
301 static char* get_name(private_user_controller_t
*this)
307 * Implementation of controller_t.handle
309 static void handle(private_user_controller_t
*this, request_t
*request
, char *action
)
313 if (streq(action
, "add"))
315 return add(this, request
);
317 if (streq(action
, "login"))
319 return login(this, request
);
321 else if (streq(action
, "logout"))
323 return logout(this, request
);
325 else if (streq(action
, "edit"))
327 return edit(this, request
);
329 else if (streq(action
, "help"))
331 return request
->render(request
, "templates/user/help.cs");
334 request
->redirect(request
, "user/login");
338 * Implementation of controller_t.destroy
340 static void destroy(private_user_controller_t
*this)
348 controller_t
*user_controller_create(user_t
*user
, database_t
*db
)
350 private_user_controller_t
*this= malloc_thing(private_user_controller_t
);
352 this->public.controller
.get_name
= (char*(*)(controller_t
*))get_name
;
353 this->public.controller
.handle
= (void(*)(controller_t
*, request_t
*, char*, char*, char*, char*, char*))handle
;
354 this->public.controller
.destroy
= (void(*)(controller_t
*))destroy
;
358 this->password_length
= lib
->settings
->get_int(lib
->settings
,
359 "medsrv.password_length", 6);
361 return &this->public.controller
;