329 lines
7.0 KiB
C
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);
|
|
}
|