diff --git a/include/application/application.h b/include/application/application.h
index e9113c4..8a89c10 100644
--- a/include/application/application.h
+++ b/include/application/application.h
@@ -31,6 +31,7 @@
#include "auth/credential.h"
#include "storage.h"
#include "session.h"
+#include "user.h"
struct randval {
@@ -48,9 +49,11 @@ CLASS(Application) {
struct randval * val;
Storage users;
+ Storage passwords;
};
int applicationLogin(Application, Credential, Session);
+int applicationSignup(Application, Credential, User, Session);
Session applicationSessionStart(Application);
Session applicationSessionGet(Application, const char *);
diff --git a/include/auth.h b/include/auth.h
index 00bc28e..a3ec86a 100644
--- a/include/auth.h
+++ b/include/auth.h
@@ -25,6 +25,7 @@
#include "auth/auth.h"
#include "auth/ldap.h"
+#include "auth/storage.h"
#include "auth/credential.h"
#include "auth/interface/auth.h"
diff --git a/include/auth/storage.h b/include/auth/storage.h
new file mode 100644
index 0000000..5409f36
--- /dev/null
+++ b/include/auth/storage.h
@@ -0,0 +1,49 @@
+/**
+ * \file
+ *
+ * \author Georg Hopp
+ *
+ * \copyright
+ * Copyright © 2012 Georg Hopp
+ *
+ * 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#ifndef __AUTH_STORAGE_H__
+#define __AUTH_STORAGE_H__
+
+#include
+
+#include
+
+#include "class.h"
+
+
+#define SALT_SIZE 32
+#define HASH_SIZE SHA512_DIGEST_LENGTH
+
+
+CLASS(AuthStorage) {
+ Storage store;
+};
+
+/*
+ * @TODO In future this should use a more general purpose hash
+ * function, which then will be in utils/hash.c
+ */
+int hash_pw(const char *, const size_t, unsigned char *, unsigned char **);
+
+#endif // __AUTH_STORAGE_H__
+
+// vim: set ts=4 sw=4:
diff --git a/include/storage.h b/include/storage.h
index c2fcb8b..277a9da 100644
--- a/include/storage.h
+++ b/include/storage.h
@@ -29,12 +29,21 @@
#include "class.h"
+typedef enum e_StoragePutResults {
+ SPR_OK = 0,
+ SPR_READ_ONLY = 1,
+ SPR_EXISTS = 2,
+ SPR_UNKNOWN = -1
+} StoragePutResult;
+
+
CLASS(Storage) {
GDBM_FILE gdbm;
char * db_name;
};
-void storagePut(Storage, char *, size_t, char *, size_t);
+StoragePutResult storagePut(Storage, char *, size_t, char *, size_t);
+StoragePutResult storageUpdate(Storage, char *, size_t, char *, size_t);
void storageGet(Storage, char *, size_t, char **, size_t *);
#endif // __STORAGE_H__
diff --git a/src/application/adapter/http/update.c b/src/application/adapter/http/update.c
index bca45e8..a78b28a 100644
--- a/src/application/adapter/http/update.c
+++ b/src/application/adapter/http/update.c
@@ -35,6 +35,7 @@
#include "http/header.h"
#include "http/response.h"
#include "auth/credential.h"
+#include "user.h"
#include "utils/memory.h"
@@ -121,7 +122,6 @@ getSession(Queue sess_queue, const char * sid)
return sess;
}
-
static
void
loginAdapter(Application application, HttpWorker worker, Session session)
@@ -159,6 +159,73 @@ loginAdapter(Application application, HttpWorker worker, Session session)
delete(credential);
}
+static
+void
+signupAdapter(Application application, HttpWorker worker, Session session)
+{
+ HashValue email;
+ HashValue password;
+ HashValue pwrepeat;
+ HashValue firstname;
+ HashValue surname;
+
+ Credential credential;
+ User user;
+
+ email = hashGet(
+ worker->current_request->post,
+ CSTRA("email"));
+ password = hashGet(
+ worker->current_request->post,
+ CSTRA("password"));
+ pwrepeat = hashGet(
+ worker->current_request->post,
+ CSTRA("pwrepeat"));
+ firstname = hashGet(
+ worker->current_request->post,
+ CSTRA("firstname"));
+ surname = hashGet(
+ worker->current_request->post,
+ CSTRA("surname"));
+
+ if (
+ NULL == email ||
+ NULL == password ||
+ NULL == pwrepeat ||
+ NULL == firstname ||
+ NULL == surname) {
+ // maybe this is not a 500...have to check repsonse codes.
+ worker->current_response = httpResponse500();
+ return;
+ }
+
+ if (password->nvalue != pwrepeat->nvalue ||
+ 0 != memcmp(password->value, pwrepeat->value, password->nvalue)) {
+ // maybe this is not a 500...have to check repsonse codes.
+ worker->current_response = httpResponse500();
+ return;
+ }
+
+ credential = new(Credential,
+ CRED_PASSWORD,
+ (char *)(email->value), email->nvalue,
+ (char *)(password->value), password->nvalue);
+
+ user = new(User,
+ (char *)(email->value), email->nvalue,
+ (char *)(firstname->value), firstname->nvalue,
+ (char *)(surname->value), surname->nvalue);
+
+ if (! applicationSignup(application, credential, user, session)) {
+ worker->current_response = httpResonse500();
+ } else {
+ loginAdapter(application, worker, session);
+ }
+
+ delete(credential);
+}
+
+
void
applicationAdapterHttpUpdate(void * _this, void * subject)
{
@@ -190,6 +257,11 @@ applicationAdapterHttpUpdate(void * _this, void * subject)
loginAdapter(this->application, worker, session);
return;
}
+
+ if (0 == strcmp("/signup/", worker->current_request->path)) {
+ signupAdapter(this->application, worker, session);
+ return;
+ }
}
if (0 == strcmp("GET", worker->current_request->method)) {
diff --git a/src/application/application.c b/src/application/application.c
index 31c146f..ffa1d7c 100644
--- a/src/application/application.c
+++ b/src/application/application.c
@@ -49,7 +49,15 @@ applicationCtor(void * _this, va_list * params)
this->active_sessions = new(Queue);
- this->users = new(Storage, "./run/users.db");
+ /*
+ * @TODO for both of these...each user should be identified
+ * by a number...that way I could use that number in the
+ * passwords db and no direct association between email and
+ * password could be made when someone get the hands on the
+ * password database.
+ */
+ this->users = new(Storage, "./run/users.db");
+ this->passwords = new(Storage, "./run/passwords.db")
return 0;
}
@@ -61,6 +69,8 @@ applicationDtor(void * _this)
Application this = _this;
size_t i;
+ delete(this->passwords);
+ delete(this->users);
delete(this->active_sessions);
for (i=0; inauth; i++) {
diff --git a/src/application/signup.c b/src/application/signup.c
new file mode 100644
index 0000000..acd6b0c
--- /dev/null
+++ b/src/application/signup.c
@@ -0,0 +1,78 @@
+/**
+ * \file
+ *
+ * \author Georg Hopp
+ *
+ * \copyright
+ * Copyright © 2012 Georg Hopp
+ *
+ * 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#define _GNU_SOURCE
+
+#include
+#include
+#include
+
+#include "class.h"
+#include "auth.h"
+#include "user.h"
+#include "application/application.h"
+
+#include "utils/memory.h"
+
+int
+applicationSignup(
+ Application this,
+ Credential credential,
+ User user,
+ Session session)
+{
+ unsigned char hash[SALT_SIZE+HASH_SIZE];
+
+ if (NULL != userLoad(user, this->users)) {
+ /*
+ * if any user is found with this email return false
+ * as on signup equal email adresses are not allowed
+ * at all.
+ */
+ return 0;
+ }
+
+ userSave(user, this->users);
+
+ if (FALSE == hash_pw(
+ CRED_PWD(cred).pass,
+ CRED_PWD(cred).npass,
+ &hash,
+ &(hash+SALT_SIZE))) {
+ /*
+ * @TODO if we come here we have to delete the previously saved
+ * user again...
+ */
+ return 0;
+ }
+
+ storagePut(
+ this->passwords,
+ CRED_PWD(cred).user,
+ CRED_PWD(cred).nuser,
+ hash,
+ SALT_SIZE + HASH_SIZE);
+
+ return 0;
+}
+
+// vim: set ts=4 sw=4:
diff --git a/src/auth/storage/hash_pw.c b/src/auth/storage/hash_pw.c
new file mode 100644
index 0000000..93228f3
--- /dev/null
+++ b/src/auth/storage/hash_pw.c
@@ -0,0 +1,103 @@
+/**
+ * \file
+ *
+ * \author Georg Hopp
+ *
+ * \copyright
+ * Copyright © 2012 Georg Hopp
+ *
+ * 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#include
+
+#include
+#include
+
+#include "class.h"
+#include "storage.h"
+#include "utils/memory.h"
+
+/*
+ * I have to hash the passwords, maybe this will move in
+ * a separate class in future, but now everything is done
+ * here
+ */
+#define PBKDF2_ITERATIONS 2048
+
+/*
+ * base64 decode via openssl...
+ * I do not need this i think, but I keep it...maybe I have
+ * use for it later.
+ *
+#include
+#include
+
+#define B64_SALT "q36MilkD6Ezlt6+G394aPYWrSwAdEhdnK8k="
+
+BIO_METHOD * BIO_f_base64(void);
+
+void
+base64decode(char * data) {
+ BIO * bio,
+ * b64;
+ FILE * b64_salt = fmemopen(B64_SALT, sizeof(B64_SALT)-1, "r");
+
+ b64 = BIO_new(BIO_f_base64());
+ bio = BIO_new_fp(b64_salt, BIO_NOCLOSE);
+ bio = BIO_push(b64, bio);
+
+ BIO_set_flags(bio, BIO_FLAGS_BASE64_NO_NL);
+
+ if (SALT_SIZE != BIO_read(bio, data, SALT_SIZE)) {
+ return -1;
+ }
+
+ BIO_free_all(bio);
+ fclose(b64_salt);
+}
+*/
+
+int
+hash_pw(
+ const char * password,
+ const size_t npassword,
+ unsigned char * hash,
+ unsigned char ** salt)
+{
+ if (NULL == *salt) {
+ *salt = memMalloc(SALT_SIZE * sizeof(unsigned char));
+ if (0 > RAND_pseudo_bytes(unsigned char *buf, int num)) {
+ MEM_FREE(*salt);
+ return FALSE;
+ }
+ }
+
+ if (0 == PKCS5_PBKDF2_HMAC(
+ password,
+ npassword,
+ *salt,
+ SALT_SIZE,
+ PBKDF2_ITERATIONS,
+ EVP_sha512(),
+ HASH_SIZE,
+ hash)) {
+ MEM_FREE(*salt);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+// vim: set ts=4 sw=4:
diff --git a/src/auth/storage/signup.c b/src/auth/storage/signup.c
new file mode 100644
index 0000000..2db9efb
--- /dev/null
+++ b/src/auth/storage/signup.c
@@ -0,0 +1,53 @@
+/**
+ * \file
+ *
+ * \author Georg Hopp
+ *
+ * \copyright
+ * Copyright © 2012 Georg Hopp
+ *
+ * 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#include
+
+#include "class.h"
+#include "storage.h"
+#include "auth/storage.h"
+#include "auth/credential.h"
+
+int
+authStorageSignup(AuthStorage this, Credential cred)
+{
+ unsigned char hash[SALT_SIZE+HASH_SIZE];
+
+ if (FALSE == hash_pw(
+ CRED_PWD(cred).pass,
+ CRED_PWD(cred).npass,
+ &hash,
+ &(hash+SALT_SIZE))) {
+ return 0;
+ }
+
+ storagePut(
+ this->store,
+ CRED_PWD(cred).user,
+ CRED_PWD(cred).nuser,
+ hash,
+ SALT_SIZE + HASH_SIZE);
+
+ return 1;
+}
+
+// vim: set ts=4 sw=4:
diff --git a/src/auth/storage/storage.c b/src/auth/storage/storage.c
new file mode 100644
index 0000000..5aa8e47
--- /dev/null
+++ b/src/auth/storage/storage.c
@@ -0,0 +1,95 @@
+/**
+ * \file
+ *
+ * \author Georg Hopp
+ *
+ * \copyright
+ * Copyright © 2012 Georg Hopp
+ *
+ * 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#include "class.h"
+#include "storage.h"
+#include "auth/storage.h"
+#include "auth/credential.h"
+#include "commons.h"
+
+static
+int
+authStorageCtor(void * _this, va_list * params)
+{
+ AuthStorage this = _this;
+
+ this->store = va_arg(*params, Storage);
+
+ return 0;
+}
+
+static
+void
+authStorageDtor(void * _this)
+{
+}
+
+static
+int
+authStorageAuthenticate(void * _this, Credential cred)
+{
+ AuthStorage this = _this;
+
+ unsigned char current_hash[HASH_SIZE];
+ unsigned char * found_hash = NULL;
+ size_t nfound_hash = 0;
+
+ if (CRED_PASSWORD != cred->type) {
+ return FALSE;
+ }
+
+ storageGet(
+ this->store,
+ CRED_PWD(cred).user,
+ CRED_PWD(cred).nuser,
+ &found_hash,
+ &nfound_hash);
+
+ if (NULL == found_hash || (SALT_SIZE + HASH_SIZE) != nfound_hash) {
+ /* user not found or found hash is invalid */
+ return FALSE;
+ }
+
+ /* found_hash <=> salt+hash */
+ if (FALSE == hash_pw(
+ CRED_PWD(cred).pass,
+ CRED_PWD(cred).npass,
+ current_hash,
+ &found_hash)) {
+ MEM_FREE(found_hash);
+ return FALSE;
+ }
+
+ if (0 != memcmp(current_hash, found_hash+SALT_SIZE, HASH_SIZE)) {
+ MEM_FREE(found_hash);
+ return FALSE;
+ }
+
+ MEM_FREE(found_hash);
+ return TRUE;
+}
+
+INIT_IFACE(Class, authStorageCtor, authStorageDtor, NULL);
+INIT_IFACE(Auth, authStorageAuthenticate);
+CREATE_CLASS(AuthLdap, NULL, IFACE(Class), IFACE(Auth));
+
+// vim: set ts=4 sw=4:
diff --git a/src/storage/put.c b/src/storage/put.c
index f6d8079..c992e4f 100644
--- a/src/storage/put.c
+++ b/src/storage/put.c
@@ -29,13 +29,32 @@
#include "utils/memory.h"
-void
+typedef enum e_StoragePutResults {
+ SPR_OK = 0,
+ SPR_READ_ONLY = 1,
+ SPR_EXISTS = 2,
+ SPR_UNKNOWN = -1
+} StoragePutResult;
+
+
+StoragePutResult
storagePut(Storage this, char * _key, size_t nkey, char * data, size_t ndata)
{
datum key = {_key, nkey};
datum value = {data, ndata};
- gdbm_store(this->gdbm, key, value, GDBM_REPLACE);
+ switch (gdbm_store(this->gdbm, key, value, GDBM_INSERT)) {
+ case 0:
+ return SPR_OK;
+ case 1:
+ return SPR_EXISTS;
+ case -1:
+ return SPR_READ_ONLY;
+ default:
+ return SPR_UNKNOWN;
+ }
+
+ return SPR_UNKNOWN;
}
// vim: set ts=4 sw=4:
diff --git a/src/storage/update.c b/src/storage/update.c
new file mode 100644
index 0000000..a48ef96
--- /dev/null
+++ b/src/storage/update.c
@@ -0,0 +1,50 @@
+/**
+ * \file
+ *
+ * \author Georg Hopp
+ *
+ * \copyright
+ * Copyright © 2012 Georg Hopp
+ *
+ * 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#include
+#include
+#include
+
+#include "storage.h"
+#include "class.h"
+
+#include "utils/memory.h"
+
+StoragePutResult
+storagePut(Storage this, char * _key, size_t nkey, char * data, size_t ndata)
+{
+ datum key = {_key, nkey};
+ datum value = {data, ndata};
+
+ switch (gdbm_store(this->gdbm, key, value, GDBM_REPLACE)) {
+ case 0:
+ return SPR_OK;
+ case -1:
+ return SPR_READ_ONLY;
+ default:
+ return SPR_UNKNOWN;
+ }
+
+ return SPR_UNKNOWN;
+}
+
+// vim: set ts=4 sw=4:
diff --git a/src/user/save.c b/src/user/save.c
index 17e546f..acb268f 100644
--- a/src/user/save.c
+++ b/src/user/save.c
@@ -39,7 +39,10 @@ userSave(User this, Storage storage)
*this->nsurname + 1 +
3 * sizeof(size_t);
- storagePut(
+ /*
+ * @TODO user return value for error handling
+ */
+ storageUpdate(
storage,
this->email, *this->nemail,
this->email, storage_size);
diff --git a/src/utils/hash.c b/src/utils/hash.c
index ea46085..aef07bc 100644
--- a/src/utils/hash.c
+++ b/src/utils/hash.c
@@ -24,6 +24,8 @@
#include
#include
+#include
+
#include "utils/hash.h"
/**
@@ -50,4 +52,21 @@ sdbm(const unsigned char * str, size_t len)
return hash;
}
+
+/*
+ * this will use openssl to hash a given password with a given salt.
+ * If salt is NULL a random salt is generated and returned in salt.
+ * The memory for this is allocated via memMalloc and has to be freed
+ * by the caller via MEM_FREE.
+ * The size of the salt is always SALT_SIZE and that of hash is always
+ * hash size. Both are defined in auth/storage.h
+ */
+int
+hash_pw(
+ const char * password,
+ const size_t npassword,
+ unsigned char * pw_hash,
+ unsigned char ** salt)
+{
+}
// vim: set ts=4 sw=4: