Files
bongo/src/libs/msgapi/auth-backends/sqlite.c
T
2008-01-28 17:45:00 +00:00

329 lines
7.0 KiB
C

#include <stdio.h>
#include <config.h>
#include <xpl.h>
#include <sqlite3.h>
#include <bongoutil.h>
#include <msgapi.h>
#define LOGGERNAME "msgauth"
#include <logger.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <time.h>
#include "sqlite.h"
typedef struct {
MsgSQLStatement find_user;
MsgSQLStatement auth_user;
MsgSQLStatement add_user;
MsgSQLStatement list_user;
MsgSQLStatement set_password;
} MsgAuthStatements;
MsgAuthStatements msgauth_stmts;
int
AuthODBC_Init(void)
{
return 0;
}
int
AuthSqlite_GetDbPath(char *path, size_t size)
{
return snprintf(path, size, "%s/%s", XPL_DEFAULT_DBF_DIR, "userdb.sqlite");
}
int
AuthSqlite_GenerateHash(const char *username, const char *password, char *result, size_t result_len)
{
xpl_hash_context ctx;
if (result_len <= XPLHASH_SHA1_LENGTH) return -1;
XplHashNew(&ctx, XPLHASH_SHA1);
XplHashWrite(&ctx, username, strlen(username));
XplHashWrite(&ctx, password, strlen(password));
XplHashFinal(&ctx, XPLHASH_UPPERCASE, result, XPLHASH_SHA1_LENGTH);
result[XPLHASH_SHA1_LENGTH] = '\0';
return 0;
}
/* returns 0 on success */
int
AuthSqlite_Install(void)
{
int dcode;
char path[XPL_MAX_PATH + 1];
MsgSQLHandle *handle;
struct stat buf;
AuthSqlite_GetDbPath(path, XPL_MAX_PATH);
if (stat(path, &buf) == 0) {
// FIXME: db already exists - for now, remove, but could/should be more gentle
unlink(path);
}
handle = MsgSQLOpen(path, NULL, 1000);
if (NULL == handle) return -2;
if (MsgSQLBeginTransaction(handle)) goto fail;
dcode = sqlite3_exec (handle->db,
"PRAGMA user_version=0;"
"CREATE TABLE users (username TEXT DEFAULT NULL UNIQUE,"
" password TEXT DEFAULT NULL"
");"
"INSERT INTO users (username, password)"
" VALUES ('admin', '19E210D6CDA11A1CDED7D3B35E129514FB896B43'); ",
NULL, NULL, NULL);
if (SQLITE_OK != dcode) goto fail;
if (MsgSQLCommitTransaction(handle)) goto fail;
MsgSQLClose(handle);
return 0;
fail:
Log(LOG_ERROR, "Error creating database: %s", sqlite3_errmsg(handle->db));
MsgSQLAbortTransaction(handle);
MsgSQLClose(handle);
return -1;
}
int
AuthSqlite_FindUser(const char *user)
{
MsgSQLStatement *stmt;
char path[XPL_MAX_PATH + 1];
MsgSQLHandle *handle;
int users = -1;
AuthSqlite_GetDbPath(path, XPL_MAX_PATH);
handle = MsgSQLOpen(path, NULL, 1000);
// Log error?
if (NULL == handle) {
Log(LOG_ERROR, "Cannot open user db '%s'", path);
return 1;
}
stmt = MsgSQLPrepare (handle, "SELECT count(username) FROM users WHERE username = ?;",
&msgauth_stmts.find_user);
if (NULL == stmt) {
Log(LOG_ERROR, "Unable to prepare SQL statement in FindUser");
return 1;
}
MsgSQLBindString(stmt, 1, user, TRUE);
if (MsgSQLResults(handle, stmt) >= 0) {
// should only have one result column
users = sqlite3_column_int(stmt->stmt, 0);
}
MsgSQLFinalize(stmt);
MsgSQLClose(handle);
if (users == 1) {
// found the user
return 0;
}
LogAssertF(users == 0, "User %s defined more than once in the user db", user);
return 1;
}
int
AuthSqlite_VerifyPassword(const char *user, const char *password)
{
MsgSQLStatement *stmt;
char path[XPL_MAX_PATH + 1];
char hash[XPLHASH_SHA1_LENGTH + 1];
MsgSQLHandle *handle;
int users = -1;
if (AuthSqlite_GenerateHash(user, password, hash, XPLHASH_SHA1_LENGTH + 1) != 0)
return 1;
AuthSqlite_GetDbPath(path, XPL_MAX_PATH);
handle = MsgSQLOpen(path, NULL, 1000);
// Log error?
if (NULL == handle) {
Log(LOG_ERROR, "Cannot open user db '%s'", path);
return 2;
}
stmt = MsgSQLPrepare (handle, "SELECT count(username) FROM users WHERE username = ? AND password = ?;",
&msgauth_stmts.auth_user);
if (NULL == stmt) {
Log(LOG_ERROR, "Unable to prepare SQL statement in VerifyPassword");
return 1;
}
MsgSQLBindString(stmt, 1, user, TRUE);
MsgSQLBindString(stmt, 2, hash, TRUE);
if (MsgSQLResults(handle, stmt) >= 0) {
// should only have one result column
users = sqlite3_column_int(stmt->stmt, 0);
}
MsgSQLFinalize(stmt);
MsgSQLClose(handle);
if (users == 1) {
return 0; // user exists / password verified
}
if (users == 0) {
return 1; // no such user or password wrong, not an error
}
Log(LOG_ERROR, "User %s exists multiple times in the user db", user);
return 3;
}
/* "Write" functions below */
int
AuthSqlite_AddUser(const char *user)
{
MsgSQLStatement *stmt;
char path[XPL_MAX_PATH + 1];
MsgSQLHandle *handle;
AuthSqlite_GetDbPath(path, XPL_MAX_PATH);
handle = MsgSQLOpen(path, NULL, 1000);
if (NULL == handle) {
Log(LOG_ERROR, "Cannot open user db '%s'", path);
return -10;
}
stmt = MsgSQLPrepare (handle,
"INSERT INTO users (username) VALUES (?);",
&msgauth_stmts.add_user);
if (NULL == stmt) {
Log(LOG_ERROR, "Unable to prepare SQL statement in AddUser");
return -11;
}
if (MsgSQLBindString(stmt, 1, user, TRUE)) return -12;
if (MsgSQLExecute(handle, stmt)) return -13;
MsgSQLFinalize(stmt);
MsgSQLClose(handle);
return 0;
}
int
AuthSqlite_SetPassword(const char *user, const char *password)
{
MsgSQLStatement *stmt;
char path[XPL_MAX_PATH + 1];
char hash[XPLHASH_SHA1_LENGTH + 1];
MsgSQLHandle *handle;
if (AuthSqlite_GenerateHash(user, password, hash, XPLHASH_SHA1_LENGTH + 1) != 0)
return -10;
AuthSqlite_GetDbPath(path, XPL_MAX_PATH);
handle = MsgSQLOpen(path, NULL, 1000);
if (NULL == handle) {
Log(LOG_ERROR, "Cannot open user db '%s'", path);
return -11;
}
stmt = MsgSQLPrepare (handle,
"UPDATE users SET password = ? WHERE username= ?;",
&msgauth_stmts.set_password);
if (NULL == stmt) {
Log(LOG_ERROR, "Unable to prepare SQL in SetPassword()");
return -12;
}
if (MsgSQLBindString(stmt, 1, hash, TRUE)) return -13;
if (MsgSQLBindString(stmt, 2, user, TRUE)) return -13;
if (MsgSQLExecute(handle, stmt)) return -14;
MsgSQLFinalize(stmt);
MsgSQLClose(handle);
return 0;
}
int
AuthSqlite_GetUserStore(const char *user, struct sockaddr_in *store)
{
memset(store, 0, sizeof(store));
store->sin_addr.s_addr = inet_addr("127.0.0.1");
store->sin_family = AF_INET;
store->sin_port = htons(689);
return TRUE;
}
int
AuthSqlite_UserList(char **list[])
{
char **userlist;
MsgSQLStatement *stmt;
char path[XPL_MAX_PATH + 1];
MsgSQLHandle *handle;
int users = 0;
int alloc = 10;
AuthSqlite_GetDbPath(path, XPL_MAX_PATH);
handle = MsgSQLOpen(path, NULL, 1000);
if (NULL == handle) {
Log(LOG_ERROR, "Cannot open user db '%s'", path);
return 1;
}
stmt = MsgSQLPrepare (handle, "SELECT username FROM users;",
&msgauth_stmts.list_user);
if (NULL == stmt) {
Log(LOG_ERROR, "Unable to prepare SQL statement in ListUser");
return 1;
}
userlist = MemMalloc(sizeof(char *) * alloc);
{
int result;
while (1 == (result = MsgSQLStatementStep(handle, stmt))) {
userlist[users] = strdup((char *) sqlite3_column_text(stmt->stmt, 0));
users++;
if (users == alloc) {
alloc += 10;
userlist = MemRealloc(userlist, sizeof(char *) * alloc);
}
}
}
MsgSQLFinalize(stmt);
MsgSQLClose(handle);
userlist[users] = 0;
*list = userlist;
return TRUE;
}
int
AuthSqlite_InterfaceVersion(void)
{
return 1;
}
int
main (int argc, char *argv[])
{
printf("This cannot be run directly");
return (-1);
}