#include #include #include #include #include #include #define LOGGERNAME "msgauth" #include #include #include #include #include #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); }