123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422 |
- #include <stdio.h>
- #include <unistd.h>
- #include <stdarg.h>
- #include <stdlib.h>
- #include <string.h>
- #include <time.h>
- #include "auth.h"
- #include "sqlite3.h"
- #include "util.h"
- #include "list.h"
- #include "dSFMT.h"
- #include "ow-crypt.h"
- #define BEGIN(db) sqlite3_exec(db->conn, "BEGIN", NULL, NULL, NULL)
- #define COMMIT(db) sqlite3_exec(db->conn, "COMMIT", NULL, NULL, NULL)
- #define buildList(...) _buildList(__VA_ARGS__, NULL)
- #define insertRow(...) _insertRow(__VA_ARGS__, NULL)
- struct account {
- char* username;
- char* passhash;
- char* salt;
- char* sid;
- LIST* groups;
- LIST* perms;
- };
- struct group {
- char* groupname;
- LIST* members;
- LIST* perms;
- };
- struct passdata {
- char* passhash;
- char* salt;
- };
- typedef struct account account;
- typedef struct group group;
- typedef struct passdata passdata;
- //#define group struct group
- char* err; //Global SQLite3 error message buffer
- void init_prng() { init_gen_rand(time(NULL)); }
- static int selectCellWhereText(authdb* db, char* result, char* column, char* table, char* target, char* text) {
- char sql[MAXLEN_SQL]; memset(sql, 0, MAXLEN_SQL);
- sqlite3_stmt* stmt;
- snprintf(sql, MAXLEN_SQL, "select %s from %s where %s='%s'", column, table, target, text);
- if (sqlite3_prepare_v2(db->conn, sql, MAXLEN_SQL, &stmt, NULL) != SQLITE_OK) { return 1; }
- if (sqlite3_step(stmt) != SQLITE_ROW) { return 1; }
- snprintf(result, MAXLEN_RESULT, "%s", (char*)sqlite3_column_text(stmt, 0));
- sqlite3_finalize(stmt);
- return 0;
- }
- static int selectRowWhereText(authdb* db, LIST* list, char* column, char* table, char* target, char* text) {
- int c; int cmax;
- char sql[MAXLEN_SQL]; memset(sql, 0, MAXLEN_SQL);
- sqlite3_stmt* stmt;
-
- snprintf(sql, MAXLEN_SQL, "select %s from %s where %s='%s'", column, table, target, text);
- if (sqlite3_prepare_v2(db->conn, sql, MAXLEN_SQL, &stmt, NULL) != SQLITE_OK) { return 1; }
- if (sqlite3_step(stmt) != SQLITE_ROW) { return 1; }
- cmax = sqlite3_column_count(stmt);
- if (!cmax) { return 1; }
- do {
- c = 0;
- while (c < cmax) {
- listQueue(list, strndup((char*)sqlite3_column_text(stmt, c), MAXLEN_RESULT));
- c++;
- }
- } while (sqlite3_step(stmt) == SQLITE_ROW);
- sqlite3_finalize(stmt);
- return 0;
- }
- static int updateRowWhereText(authdb* db, char* column, char* table, char* value, char* target, char* against) {
- int status = 0;
- char* sql = malloc(MAXLEN_SQL); memset(sql, 0, MAXLEN_SQL);
- snprintf(sql, MAXLEN_SQL, "update %s set %s='%s' where %s='%s'", table, column, value, target, against);
- logs("SQL: %s", sql);
- BEGIN(db);
- if (sqlite3_exec(db->conn, sql, NULL, NULL, &err) != SQLITE_OK) {
- logs("updateRowWhereText: sqlite3_exec failed: %s", err);
- logs("updateRowWhereText: statement was: %s", sql);
- status = 1;
- }
- COMMIT(db);
- #if DO_FREE
- sqlite3_free(err);
- free(sql);
- #endif
- return status;
- }
- static int _insertRow(authdb* db, char* table, char* val, ...) {
- va_list ap; int l;
- char* v = val;
- int c=0; int status=0;
- char* sql = malloc(MAXLEN_SQL); memset(sql, 0, MAXLEN_SQL);
- char* vals = malloc(MAXLEN_SQL); memset(vals, 0, MAXLEN_SQL);
- va_start(ap, val);
- while (v) {
- snprintf(vals, MAXLEN_SQL, "'%s',", v);
- l = strlen(vals);
- vals += l; c+= l;
- v = va_arg(ap, char*);
- }
- va_end(ap);
- vals -= c;
- vals[(c-1)] = '\0'; //Strip off the last comma
- snprintf(sql, MAXLEN_SQL, "insert into %s values (%s)", table, vals);
- logs("SQL: %s", sql);
-
- BEGIN(db);
- if (sqlite3_exec(db->conn, sql, NULL, NULL, &err) != SQLITE_OK) {
- logs("insertRow: sqlite3_exec failed: %s", err);
- logs("insertRow: statement was: %s", sql);
- status=1;
- }
- COMMIT(db);
- #if DO_FREE
- sqlite3_free(err);
- deleteListIterator(i);
- free(vals);
- free(sql);
- #endif
-
- return status;
- }
- static LIST* _buildList(char* v, ...) {
- char* arg;
- va_list ap;
- LIST* list = newList();
- listQueue(list, v);
- va_start(ap, v);
- while ((arg = va_arg(ap, char*))) {
- listQueue(list, arg);
- }
-
- return list;
- }
- #if DO_FREE
- static void freeAccount(account* acc) {
- deleteList(acc->groups);
- deleteList(acc->perms);
- free(acc->username);
- free(acc->passhash);
- free(acc->salt);
- free(acc->sid);
- free(acc);
- }
- static void freeGroup(group* grp) {
- deleteList(grp->members);
- deleteList(grp->perms);
- free(grp->groupname);
- free(grp);
- }
- static void freePassdata(passdata *pd) {
- free(pd->passhash);
- free(pd->salt);
- free(pd);
- }
- #endif
- static account* newAccount() {
- account* acc = malloc(sizeof(*acc));
- if (!acc) { return NULL; }
- memset(acc, 0, sizeof(account));
- acc->groups = newList();
- acc->perms = newList();
- return acc;
- }
- static group* newGroup() {
- group* grp = malloc(sizeof(*grp));
- if (!grp) { return NULL; }
- memset(grp, 0, sizeof(group));
- grp->perms = newList();
- grp->members = newList();
- return grp;
- }
- static void getGroup(authdb* db, char* groupname, group* grp) {
- grp->groupname = groupname;
-
- selectRowWhereText(db, grp->members, "username", "groups_membership", "groupname", groupname);
- selectRowWhereText(db, grp->perms, "perm", "groups_perms", "groupname", groupname);
- }
- static void getAccount(authdb* db, char* user, account* acc) {
- LIST* fields = newList();
- selectRowWhereText(db, acc->groups, "groupname", "groups_membership", "username", user);
- selectRowWhereText(db, acc->perms, "perm", "users_perms", "username", user);
- selectRowWhereText(db, fields, "*", "auth", "username", user);
-
- acc->username = (char*)listPop(fields); acc->passhash = (char*)listPop(fields);
- acc->salt = (char*)listPop(fields); acc->sid = (char*)listPop(fields);
- deleteList(fields);
- }
- static int connect_db(char* path, sqlite3** conn) {
- if (sqlite3_open(path, conn) != SQLITE_OK) {
- logs("AUTH: sqlite3_open failed");
- return 1;
- }
- return 0;
- }
- static int init_authdb(authdb* db) {
- if (connect_db(db->path, &db->conn)) {
- return 1;
- }
- char* query = read_file("initauth.sql", MAXLEN_FILE, 1);
- if (!query) {
- logs("AUTH: couldn't read init SQL file");
- return 1;
- }
- BEGIN(db);
- if (sqlite3_exec(db->conn, query, NULL, NULL, &err) != SQLITE_OK) {
- logs("AUTH: database initialization failed: %s", err);
- #if DO_FREE
- sqlite3_free(err);
- #endif
- return 1;
- }
- COMMIT(db);
- return 0;
- }
- static passdata* newPassdata() {
- passdata* pd = malloc(sizeof(*pd));
- memset(pd, 0, sizeof(passdata));
- pd->passhash = malloc((MAXLEN_PASSHASH+1)); memset(pd->passhash, 0, (MAXLEN_PASSHASH+1));
- pd->salt = malloc(MAXLEN_SALT); memset(pd->salt, 0, MAXLEN_SALT);
-
- return pd;
- }
- static passdata* hash_password(char* password, char* salt) {
- passdata* pd = newPassdata();
- if (!salt) {
- double salt[(LEN_SALT/8)]; memset(salt, 0, LEN_SALT); //8 chars to 1 double
- fill_array_close1_open2(salt, (LEN_SALT/8)); //Get entropy for salt
- crypt_gensalt_rn("$2a$", BCRYPT_ROUNDS, (char*)salt, LEN_SALT, pd->salt, MAXLEN_SALT); //Generate salt
- }
- else { snprintf(pd->salt, MAXLEN_SALT, "%s", salt); }
- crypt_rn(password, pd->salt, pd->passhash, MAXLEN_PASSHASH); //Generate password hash
-
- return pd;
- }
- int user_addgroup(authdb* db, char* username, char* groupname) {
- if (insertRow(db, "groups_membership", username, groupname)) { return 1; }
- return 0;
- }
- int group_addperm(authdb* db, char* groupname, char* perm) {
- if (insertRow(db, "groups_perms", groupname, perm)) { return 1; }
- return 0;
- }
- int user_addperm(authdb* db, char* username, char* perm) {
- if (insertRow(db, "users_perms", username, perm)) { return 1; }
- return 0;
- }
- int register_perm(authdb *db, char* perm, char* desc) {
- if (insertRow(db, "perms", desc)) { return 1; }
- return 0;
- }
- int register_group(authdb *db, char* groupname) {
- if (insertRow(db, "auth", groupname)) { return 1; }
- return 0;
- }
- int user_validate(authdb *db, char* username, char* password) {
- char* salt; char* passhash; passdata* pd;
- LIST* data = newList();
-
- if (selectRowWhereText(db, data, "passhash,salt", "auth", "username", username)) { return 1; }
- passhash = listPop(data);
- salt = listPop(data);
- if (!salt || !passhash) { return 1; }
-
- pd = hash_password(password, salt);
- if (!pd) { return 1; }
- if (!(strncmp(passhash, pd->passhash, MAXLEN_PASSHASH))) { return 0; }
-
- return 1;
- }
- int user_setpass(authdb *db, char* username, char* password) {
- passdata* pd = hash_password(password, NULL);
- if (updateRowWhereText(db, "passhash", "auth", pd->passhash, "username", username) ||
- updateRowWhereText(db, "salt", "auth", pd->salt, "username", username))
- { return 1; }
- return 0;
- }
- int register_user(authdb *db, char* username, char* password, char* groupname, ...) {
- va_list ap;
- int status = 0;
- char sql[MAXLEN_SQL]; memset(sql, 0, MAXLEN_SQL);
-
- if (strlen(password) > MAXLEN_PASSWORD) {
- logs("register_user: Password for '%s' exceeds maximum length of %d", username, MAXLEN_PASSWORD);
- return 1;
- }
- passdata* pd = hash_password(password, NULL);
- if (insertRow(db, "auth", username, pd->passhash, pd->salt, "")) {
- logs("register_user: Couldn't insert row");
- return 1;
- }
-
- //Join supplied groups - move into own function
- va_start(ap, groupname);
- do {
- snprintf(sql, MAXLEN_SQL, "insert into groups_membership values('%s','%s')", username, groupname);
- if (sqlite3_exec(db->conn, sql, NULL, NULL, NULL) != SQLITE_OK) {
- logs("register_user: Couldn't add user '%s' to group '%s'", username, groupname);
- status=1;
- break;
- }
- } while ((groupname = va_arg(ap, char*)));
- va_end(ap);
- #if DO_FREE
- free(pd);
- #endif
-
- return status;
- }
- authdb* new_authdb(char* path) {
- authdb* db = malloc(sizeof(authdb)); memset(db, 0, sizeof(authdb));
- db->path = malloc(MAXLEN_PATH); memset(db->path, 0, MAXLEN_PATH);
- snprintf(db->path, MAXLEN_PATH, "%s", path);
- if (access(db->path, F_OK) == -1) {
- logs("AUTH: initializing new database at '%s'", path);
- if (init_authdb(db)) { return NULL; }
- }
- else if (connect_db(db->path, &db->conn)) {
- return NULL;
- }
- return db;
- }
- int group_has_perm(authdb* db, char* groupname, char* perm) {
- char* p;
- group* grp = newGroup();
- getGroup(db, groupname, grp);
- if (!grp) { return 1; }
- LIST_ITERATOR* ip = newListIterator(grp->perms);
- ITERATE_LIST(p, ip) {
- if (!(strncmp(p, perm, MAXLEN_PERM))) { return 0; }
- }
- #if DO_FREE
- deleteListIterator(ip);
- freeGroup(grp);
- #endif
-
- return 1;
- }
- int user_has_perm(authdb* db, char* user, char* perm) {
- char* p; char* g;
- int status = 1;
- account* acc = newAccount();
- getAccount(db, user, acc);
- if (!acc) { return 1; }
- LIST_ITERATOR* ip = newListIterator(acc->perms);
- LIST_ITERATOR* ig;
-
- //Check if user has permission assigned directly
- ITERATE_LIST(p, ip) {
- if (!(strncmp(p,perm,MAXLEN_PERM))) { status=0; break;}
- }
- if (status) {
- ig = newListIterator(acc->groups);
- //Check if any of the users groups have the permission
- ITERATE_LIST(g, ig) {
- if (!(group_has_perm(db, g, perm))) { status=0; break; }
- }
- }
- #if DO_FREE
- deleteListIterator(ip);
- deleteListIterator(ig);
- freeAccount(acc);
- #endif
-
- return status;
- }
|