Lovely new sqlite-db backed cookie database
This commit is contained in:
+1
-1
@@ -34,7 +34,7 @@ include(cmake/Legacy.cmake)
|
||||
# output header files etc. specifically configured for this build
|
||||
configure_file(config.h.cmake include/config.h @ONLY)
|
||||
configure_file(src/agents/store/sql/create-store.s.cmake src/agents/store/sql/createstore.s @ONLY)
|
||||
configure_file(src/agents/store/sql/create-store-1.s.cmake src/agents/store/sql/createstore-1.s @ONLY)
|
||||
configure_file(src/agents/store/sql/create-cookie-1.s.cmake src/agents/store/sql/createcookie-1.s @ONLY)
|
||||
|
||||
# tell compiler where to find Bongo's header files
|
||||
include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR}/include/)
|
||||
|
||||
@@ -42,19 +42,6 @@ EXPORT int MsgAuthAddUser(const char *user);
|
||||
EXPORT int MsgAuthUserList(char **list[]);
|
||||
EXPORT void MsgAuthUserListFree(char **list[]);
|
||||
|
||||
// Auth / cookie functions
|
||||
|
||||
#define MSGAUTH_COOKIE_LEN XPLHASH_MD5_LENGTH + 1
|
||||
|
||||
typedef struct {
|
||||
char token[MSGAUTH_COOKIE_LEN];
|
||||
uint64_t expiration;
|
||||
} MsgAuthCookie;
|
||||
|
||||
EXPORT BOOL MsgAuthCreateCookie(const char *username, MsgAuthCookie *cookie, uint64_t timeout);
|
||||
EXPORT int MsgAuthFindCookie(const char *username, const char *token);
|
||||
EXPORT BOOL MsgAuthDeleteCookie(const char *username, const char *token);
|
||||
|
||||
// SQL Routines
|
||||
|
||||
typedef struct _MsgSQLStatement {
|
||||
|
||||
@@ -6,7 +6,7 @@ add_executable(bongostore
|
||||
auth.c
|
||||
calendar.c
|
||||
sql/createstore.s
|
||||
sql/createstore-1.s
|
||||
sql/createcookie-1.s
|
||||
command.c
|
||||
command-parsing.c
|
||||
contacts.c
|
||||
|
||||
@@ -571,6 +571,7 @@ StoreCommandLoop(StoreClient *client)
|
||||
case STORE_COMMAND_COOKIE:
|
||||
/* COOKIE [BAKE | NEW] <timeout> */
|
||||
/* COOKIE [CRUMBLE | DELETE] [<token>] */
|
||||
/* COOKIE LIST */
|
||||
|
||||
if (TOKEN_OK != (ccode = RequireUser(client)) ||
|
||||
TOKEN_OK != (ccode = CheckTokC(client, n, 2, 3)))
|
||||
@@ -591,6 +592,8 @@ StoreCommandLoop(StoreClient *client)
|
||||
!XplStrCaseCmp(tokens[1], "DELETE"))
|
||||
{
|
||||
ccode = StoreCommandCOOKIEDELETE(client, 3 == n ? tokens[2] : NULL);
|
||||
} else if (!XplStrCaseCmp(tokens[1], "LIST")) {
|
||||
ccode = StoreCommandCOOKIELIST(client);
|
||||
} else {
|
||||
ccode = ConnWriteStr(client->conn, MSG3000UNKNOWN);
|
||||
}
|
||||
|
||||
@@ -153,6 +153,8 @@ CCode StoreCommandCOOKIENEW(StoreClient *client, uint64_t timeout);
|
||||
|
||||
CCode StoreCommandCOOKIEDELETE(StoreClient *client, const char *token);
|
||||
|
||||
CCode StoreCommandCOOKIELIST(StoreClient *client);
|
||||
|
||||
CCode StoreCommandCOPY(StoreClient *client, StoreObject *object, StoreObject *collection);
|
||||
|
||||
CCode StoreCommandCREATE(StoreClient *client, char *collection, uint64_t guid);
|
||||
|
||||
+211
-118
@@ -1,150 +1,243 @@
|
||||
/****************************************************************************
|
||||
* <Novell-copyright>
|
||||
* Copyright (c) 2006 Novell, Inc. All Rights Reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of version 2 of the GNU General Public License
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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, contact Novell, Inc.
|
||||
*
|
||||
* To contact Novell about this file by physical or electronic mail, you
|
||||
* may find current contact information at www.novell.com.
|
||||
* </Novell-copyright>
|
||||
****************************************************************************/
|
||||
|
||||
#include <config.h>
|
||||
#include <xpl.h>
|
||||
#include <nmlib.h>
|
||||
#include <msgapi.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "stored.h"
|
||||
#include "messages.h"
|
||||
|
||||
extern const char *sql_create_cookie_1[]; // defined in sql/create-cookie-1.s.cmake
|
||||
|
||||
static MsgSQLHandle *
|
||||
OpenCookieDB(StoreClient *client)
|
||||
{
|
||||
char path[XPL_MAX_PATH + 1];
|
||||
int current_version = 0;
|
||||
|
||||
snprintf(path, XPL_MAX_PATH, "%s/cookies.db", MsgGetDir(MSGAPI_DIR_DBF, NULL, 0));
|
||||
|
||||
MsgSQLStatement stmt;
|
||||
memset(&stmt, 0, sizeof(MsgSQLStatement));
|
||||
MsgSQLStatement *schema = NULL;
|
||||
|
||||
MsgSQLHandle *cdb = MsgSQLOpen(path, &client->memstack, 3000);
|
||||
|
||||
if (MsgSQLBeginTransaction(cdb)) return NULL;
|
||||
|
||||
schema = MsgSQLPrepare(cdb, "PRAGMA user_version;", &stmt);
|
||||
if (schema == NULL) goto aborttran;
|
||||
|
||||
if (! MsgSQLResults(cdb, schema)) goto aborttran;
|
||||
|
||||
current_version = MsgSQLResultInt(&stmt, 0);
|
||||
MsgSQLEndStatement(&stmt);
|
||||
MsgSQLFinalize(&stmt);
|
||||
|
||||
if (current_version > 1) {
|
||||
Log(LOG_ERROR, "Cookie DB created with newer version of store, cannot open");
|
||||
}
|
||||
|
||||
if (current_version < 1) {
|
||||
if (MsgSQLQuickExecute(cdb, (const char*)sql_create_cookie_1))
|
||||
goto aborttran;
|
||||
|
||||
MsgSQLReset(cdb);
|
||||
}
|
||||
|
||||
if (MsgSQLCommitTransaction(cdb)) goto aborttran;
|
||||
|
||||
return cdb;
|
||||
|
||||
aborttran:
|
||||
MsgSQLFinalize(&stmt);
|
||||
MsgSQLAbortTransaction(cdb);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
CCode
|
||||
StoreCommandCOOKIENEW(StoreClient *client, uint64_t timeout)
|
||||
{
|
||||
MsgAuthCookie cookie;
|
||||
CCode ccode = 0;
|
||||
|
||||
assert(STORE_PRINCIPAL_USER == client->principal.type);
|
||||
|
||||
if (MsgAuthCreateCookie(client->principal.name, &cookie, timeout)) {
|
||||
ccode = ConnWriteF(client->conn, "1000 %.32s\r\n", cookie.token);
|
||||
} else {
|
||||
ccode = ConnWriteStr(client->conn, MSG5004INTERNALERR);
|
||||
}
|
||||
|
||||
return ccode;
|
||||
}
|
||||
|
||||
MsgSQLStatement stmt;
|
||||
MsgSQLStatement *ret;
|
||||
memset(&stmt, 0, sizeof(MsgSQLStatement));
|
||||
|
||||
char token[50];
|
||||
xpl_hash_context context;
|
||||
MsgSQLHandle *db = NULL;
|
||||
|
||||
XplHashNew(&context, XPLHASH_MD5);
|
||||
snprintf(token, sizeof(token) - 1, "%x%x",
|
||||
(unsigned int) XplGetThreadID(), (unsigned int) time(NULL));
|
||||
XplHashWrite(&context, token, strlen(token));
|
||||
XplRandomData(token, 8);
|
||||
XplHashWrite(&context, token, strlen(token));
|
||||
XplHashFinal(&context, XPLHASH_LOWERCASE, token, XPLHASH_MD5_LENGTH);
|
||||
|
||||
uint64_t expiration = time(NULL) + timeout;
|
||||
|
||||
db = OpenCookieDB(client);
|
||||
if (db == NULL) goto abort;
|
||||
if (MsgSQLBeginTransaction(db)) goto abort;
|
||||
|
||||
ret = MsgSQLPrepare(db, "INSERT INTO cookies (user, cookie, expiration) VALUES (?, ?, ?);", &stmt);
|
||||
MsgSQLBindString(&stmt, 1, client->principal.name, FALSE);
|
||||
MsgSQLBindString(&stmt, 2, token, FALSE);
|
||||
MsgSQLBindInt64(&stmt, 3, expiration);
|
||||
|
||||
if (MsgSQLExecute(db, &stmt)) goto abort;
|
||||
|
||||
MsgSQLFinalize(&stmt);
|
||||
if (MsgSQLCommitTransaction(db))
|
||||
goto abort;
|
||||
|
||||
MsgSQLClose(db);
|
||||
|
||||
return ConnWriteF(client->conn, "1000 %.32s\r\n", token);
|
||||
|
||||
abort:
|
||||
MsgSQLFinalize(&stmt);
|
||||
MsgSQLAbortTransaction(db);
|
||||
if (db) MsgSQLClose(db);
|
||||
return ConnWriteStr(client->conn, MSG5004INTERNALERR);
|
||||
}
|
||||
|
||||
CCode
|
||||
StoreCommandCOOKIEDELETE(StoreClient *client, const char *token)
|
||||
{
|
||||
CCode ccode = 0;
|
||||
assert(STORE_PRINCIPAL_USER == client->principal.type);
|
||||
|
||||
assert(STORE_PRINCIPAL_USER == client->principal.type);
|
||||
MsgSQLStatement stmt;
|
||||
MsgSQLStatement *ret;
|
||||
memset(&stmt, 0, sizeof(MsgSQLStatement));
|
||||
|
||||
if (MsgAuthDeleteCookie(client->principal.name, token)) {
|
||||
ccode = ConnWriteStr(client->conn, MSG1000OK);
|
||||
} else {
|
||||
ccode = ConnWriteStr(client->conn, MSG5004INTERNALERR);
|
||||
}
|
||||
|
||||
return ccode;
|
||||
MsgSQLHandle *db = OpenCookieDB(client);
|
||||
if (db == NULL) goto abort;
|
||||
if (MsgSQLBeginTransaction(db)) goto abort;
|
||||
|
||||
if (token != NULL) {
|
||||
ret = MsgSQLPrepare(db, "DELETE FROM cookies WHERE (expiration < ?) OR (user=? AND cookie=?);", &stmt);
|
||||
MsgSQLBindString(&stmt, 3, token, FALSE);
|
||||
} else {
|
||||
ret = MsgSQLPrepare(db, "DELETE FROM cookies WHERE expiration < ? OR user=?;", &stmt);
|
||||
}
|
||||
MsgSQLBindInt64(&stmt, 1, time(NULL));
|
||||
MsgSQLBindString(&stmt, 2, client->principal.name, FALSE);
|
||||
|
||||
if (MsgSQLExecute(db, &stmt)) goto abort;
|
||||
|
||||
MsgSQLFinalize(&stmt);
|
||||
if (MsgSQLCommitTransaction(db))
|
||||
goto abort;
|
||||
|
||||
MsgSQLClose(db);
|
||||
|
||||
return ConnWriteStr(client->conn, MSG1000OK);
|
||||
|
||||
abort:
|
||||
MsgSQLFinalize(&stmt);
|
||||
MsgSQLAbortTransaction(db);
|
||||
if (db) MsgSQLClose(db);
|
||||
return ConnWriteStr(client->conn, MSG5004INTERNALERR);
|
||||
}
|
||||
|
||||
#if 0
|
||||
// this looks like multiple-store code
|
||||
CCode
|
||||
TunnelAuthCookie(StoreClient *client,
|
||||
struct sockaddr_in *serv, char *user, char *token, int nouser)
|
||||
{
|
||||
Connection *conn = NULL;
|
||||
char buffer[1024];
|
||||
CCode ccode;
|
||||
|
||||
conn = NMAPConnect(NULL, serv);
|
||||
if (!conn) {
|
||||
return ConnWriteStr(client->conn, MSG3242BADAUTH);
|
||||
}
|
||||
|
||||
ccode = NMAPAuthenticateWithCookie(conn, user, token, buffer, sizeof(buffer));
|
||||
switch (ccode) {
|
||||
case 1000:
|
||||
ccode = SelectUser(client, user, NULL, nouser);
|
||||
break;
|
||||
case -1:
|
||||
break;
|
||||
default:
|
||||
if (ccode >= 1000 && ccode < 6000) {
|
||||
ccode = ConnWriteF(client->conn, "%d %s\r\n", ccode, buffer);
|
||||
} else {
|
||||
XplConsolePrintf("Unexpected response from remote store: %s\r\n",
|
||||
buffer);
|
||||
ccode = ConnWriteStr(client->conn, MSG5004INTERNALERR);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
NMAPQuit(conn);
|
||||
ConnFree(conn);
|
||||
|
||||
return ccode;
|
||||
}
|
||||
#endif
|
||||
|
||||
CCode
|
||||
StoreCommandAUTHCOOKIE(StoreClient *client, char *user, char *token, int nouser)
|
||||
{
|
||||
CCode ccode;
|
||||
// struct sockaddr_in serv;
|
||||
CCode ccode;
|
||||
|
||||
if (StoreAgent.installMode) {
|
||||
// don't allow cookie logins in installation mode. FIXME: better error message?
|
||||
return ConnWriteStr(client->conn, MSG3242BADAUTH);
|
||||
}
|
||||
if (StoreAgent.installMode)
|
||||
// don't allow cookie logins in installation mode. FIXME: better error message?
|
||||
return ConnWriteStr(client->conn, MSG3242BADAUTH);
|
||||
|
||||
if (0 != MsgAuthFindUser(user)) {
|
||||
XplConsolePrintf("Couldn't find user object for %s\r\n", user);
|
||||
ccode = ConnWriteStr(client->conn, MSG3242BADAUTH);
|
||||
XplDelay(2000);
|
||||
goto finish;
|
||||
}
|
||||
if (0 != MsgAuthFindUser(user)) {
|
||||
Log(LOG_INFO, "Couldn't find user object for %s\r\n", user);
|
||||
|
||||
XplDelay(2000);
|
||||
return ConnWriteStr(client->conn, MSG3242BADAUTH);
|
||||
}
|
||||
|
||||
// FIXME: This checks for a non-local store. For Bongo 1.0, we assume a single store.
|
||||
#if 0
|
||||
if (serv.sin_addr.s_addr != MsgGetHostIPAddress()) {
|
||||
/* non-local store, need to verify against user's server */
|
||||
|
||||
ccode = TunnelAuthCookie(client, &serv, user, token, nouser);
|
||||
goto finish;
|
||||
}
|
||||
#endif
|
||||
MsgSQLStatement stmt;
|
||||
MsgSQLStatement *find = NULL;
|
||||
int result;
|
||||
|
||||
MsgSQLHandle *db = OpenCookieDB(client);
|
||||
|
||||
if (MsgSQLBeginTransaction(db)) return -2;
|
||||
|
||||
memset(&stmt, 0, sizeof(MsgSQLStatement));
|
||||
find = MsgSQLPrepare(db, "SELECT id FROM cookies WHERE user = ? AND cookie = ? AND expiration > ?;", &stmt);
|
||||
if (find == NULL) goto abort;
|
||||
|
||||
MsgSQLBindString(find, 1, user, FALSE);
|
||||
MsgSQLBindString(find, 2, token, FALSE);
|
||||
MsgSQLBindInt64(find, 3, time(NULL));
|
||||
|
||||
result = MsgSQLResults(db, find);
|
||||
if (result < 0) goto abort;
|
||||
|
||||
MsgSQLFinalize(&stmt);
|
||||
if (MsgSQLCommitTransaction(db))
|
||||
goto abort;
|
||||
|
||||
switch (MsgAuthFindCookie(user, token)) {
|
||||
case 0:
|
||||
XplDelay(2000);
|
||||
ccode = ConnWriteStr(client->conn, MSG3242BADAUTH);
|
||||
break;
|
||||
case 1:
|
||||
ccode = SelectUser(client, user, NULL, nouser);
|
||||
break;
|
||||
default:
|
||||
ccode = ConnWriteStr(client->conn, MSG5004INTERNALERR);
|
||||
break;
|
||||
}
|
||||
MsgSQLClose(db);
|
||||
|
||||
finish:
|
||||
return ccode;
|
||||
if (result == 0) {
|
||||
XplDelay(2000);
|
||||
ccode = ConnWriteStr(client->conn, MSG3242BADAUTH);
|
||||
} else {
|
||||
ccode = SelectUser(client, user, NULL, nouser);
|
||||
}
|
||||
|
||||
return ccode;
|
||||
|
||||
abort:
|
||||
MsgSQLFinalize(&stmt);
|
||||
MsgSQLAbortTransaction(db);
|
||||
if (db) MsgSQLClose(db);
|
||||
return ConnWriteStr(client->conn, MSG5004INTERNALERR);
|
||||
}
|
||||
|
||||
CCode
|
||||
StoreCommandCOOKIELIST(StoreClient *client)
|
||||
{
|
||||
MsgSQLStatement stmt;
|
||||
MsgSQLStatement *find = NULL;
|
||||
|
||||
MsgSQLHandle *db = OpenCookieDB(client);
|
||||
|
||||
if (MsgSQLBeginTransaction(db)) return -2;
|
||||
|
||||
memset(&stmt, 0, sizeof(MsgSQLStatement));
|
||||
find = MsgSQLPrepare(db, "SELECT cookie, expiration FROM cookies WHERE user = ?", &stmt);
|
||||
if (find == NULL) goto abort;
|
||||
|
||||
MsgSQLBindString(find, 1, client->principal.name, FALSE);
|
||||
|
||||
// loop results
|
||||
while (MsgSQLResults(db, &stmt) > 0) {
|
||||
char *token;
|
||||
|
||||
MsgSQLResultTextPtr(&stmt, 0, &token);
|
||||
uint64_t expiration = MsgSQLResultInt64(&stmt, 1);
|
||||
|
||||
ConnWriteF(client->conn, "2001 %s " FMT_UINT64_DEC "\r\n", token, expiration);
|
||||
}
|
||||
|
||||
MsgSQLFinalize(&stmt);
|
||||
if (MsgSQLCommitTransaction(db))
|
||||
goto abort;
|
||||
|
||||
MsgSQLClose(db);
|
||||
|
||||
return ConnWriteStr(client->conn, MSG1000OK);
|
||||
|
||||
abort:
|
||||
MsgSQLFinalize(&stmt);
|
||||
MsgSQLAbortTransaction(db);
|
||||
if (db) MsgSQLClose(db);
|
||||
return ConnWriteStr(client->conn, MSG5004INTERNALERR);
|
||||
}
|
||||
|
||||
|
||||
@@ -27,7 +27,6 @@
|
||||
#include "messages.h"
|
||||
|
||||
extern const char *sql_create_store[]; // defined in sql/create-store.s.cmake
|
||||
extern const char *sql_create_store_1[]; // defined in sql/create-store-1.s.cmake
|
||||
extern const StorePropValName StorePropTable[]; // defined in properties.c
|
||||
|
||||
int ACLCheckOnGUID(StoreClient *client, uint64_t guid, int prop);
|
||||
@@ -151,8 +150,8 @@ StoreObjectDBCheckSchema(StoreClient *client, BOOL new_install)
|
||||
// deliberate fall-through to upgrade to next version
|
||||
case 0:
|
||||
// current database schema
|
||||
if (MsgSQLQuickExecute(client->storedb, (const char*)sql_create_store_1))
|
||||
goto abort;
|
||||
//if (MsgSQLQuickExecute(client->storedb, (const char*)sql_create_store_1))
|
||||
// goto abort;
|
||||
// current version, nothing to do
|
||||
break;
|
||||
default:
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
.section ".note.GNU-stack","",%progbits
|
||||
.section ".rodata"
|
||||
.globl sql_create_cookie_1
|
||||
.type sql_create_cookie_1,@object
|
||||
sql_create_cookie_1:
|
||||
.incbin "@CMAKE_CURRENT_SOURCE_DIR@/src/agents/store/sql/create-cookie-1.sql"
|
||||
.byte 0
|
||||
.size sql_create_cookie_1, .-sql_create_cookie_1
|
||||
@@ -1,10 +1,12 @@
|
||||
CREATE TABLE cookies (
|
||||
guid INTEGER NOT NULL UNIQUE,
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
user TEXT DEFAULT NULL,
|
||||
cookie TEXT DEFAULT NULL,
|
||||
expiration INTEGER DEFAULT 0
|
||||
);
|
||||
|
||||
CREATE INDEX cookies_lookup ON cookies (user, cookie);
|
||||
CREATE INDEX cookies_lookup_user ON cookies (user);
|
||||
CREATE INDEX cookies_expiry ON cookies (expiration);
|
||||
|
||||
PRAGMA user_version = 1;
|
||||
@@ -1,8 +0,0 @@
|
||||
.section ".note.GNU-stack","",%progbits
|
||||
.section ".rodata"
|
||||
.globl sql_create_store_1
|
||||
.type sql_create_store_1,@object
|
||||
sql_create_store_1:
|
||||
.incbin "@CMAKE_CURRENT_SOURCE_DIR@/src/agents/store/sql/create-store-1.sql"
|
||||
.byte 0
|
||||
.size sql_create_store_1, .-sql_create_store_1
|
||||
@@ -1,7 +1,6 @@
|
||||
#StrictCompile()
|
||||
|
||||
add_library(bongomsgapi SHARED
|
||||
cookie.c
|
||||
msgaddr.c
|
||||
msgapi.c
|
||||
msgauth.c
|
||||
|
||||
@@ -1,188 +0,0 @@
|
||||
/* Bongo Project licensing applies to this file, see COPYING
|
||||
* (C) 2007 Alex Hudson
|
||||
*/
|
||||
|
||||
/** \file
|
||||
* Single cookie implementation for all agents; this ensures any cookie
|
||||
* is valid with any agent which recognises them.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <xpl.h>
|
||||
#include <sqlite3.h>
|
||||
#include <bongoutil.h>
|
||||
#include <msgapi.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <time.h>
|
||||
|
||||
// Internal function: path to the cookie file for this user.
|
||||
void
|
||||
MsgAuthCookiePath(const char *username, char *path, size_t length)
|
||||
{
|
||||
snprintf(path, length, "%s/%s",
|
||||
MsgGetDir(MSGAPI_DIR_COOKIE, path, XPL_MAX_PATH),
|
||||
username);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a 'cookie': a password-substitute token, and an associated expiry
|
||||
* SECURITY: We shouldn't create cookies for non-authenticated users
|
||||
* \param username User whose token this will be
|
||||
* \param cookie Reference to the MsgAuthCookie we're creating
|
||||
* \param timeout When the token should expire
|
||||
* \return Whether or not the cookie was created
|
||||
*/
|
||||
EXPORT BOOL
|
||||
MsgAuthCreateCookie(const char *username, MsgAuthCookie *cookie, uint64_t timeout)
|
||||
{
|
||||
char path[XPL_MAX_PATH+1];
|
||||
FILE *cookiefile = NULL;
|
||||
long original_length;
|
||||
size_t written;
|
||||
xpl_hash_context context;
|
||||
|
||||
// create the cookie
|
||||
cookie->expiration = time(NULL) + timeout;
|
||||
|
||||
XplHashNew(&context, XPLHASH_MD5);
|
||||
snprintf(cookie->token, sizeof(cookie->token), "%x%x",
|
||||
(unsigned int) XplGetThreadID(),
|
||||
(unsigned int) time(NULL));
|
||||
XplHashWrite(&context, cookie->token, strlen(cookie->token));
|
||||
XplRandomData(cookie->token, 8);
|
||||
XplHashWrite(&context, cookie->token, strlen(cookie->token));
|
||||
XplHashFinal(&context, XPLHASH_LOWERCASE, cookie->token, XPLHASH_MD5_LENGTH);
|
||||
|
||||
// save it to our cookie list
|
||||
MsgAuthCookiePath(username, path, XPL_MAX_PATH);
|
||||
cookiefile = fopen(path, "a");
|
||||
if (! cookiefile)
|
||||
return FALSE;
|
||||
|
||||
original_length = ftell(cookiefile);
|
||||
|
||||
written = fwrite(cookie, 1, sizeof(MsgAuthCookie), cookiefile);
|
||||
if ((fclose(cookiefile) != 0) || (sizeof(MsgAuthCookie) != written)) {
|
||||
truncate(path, original_length);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a cookie based on the token. If it exists, it's as good as auth'ing
|
||||
* SECURITY: This is much like authentication. Be careful to timeout on bad auth?
|
||||
* \param username User who claims this token is theirs
|
||||
* \param token Token we want to look for
|
||||
* \return 0 = bad auth, 1 = good auth, 2 = internal error
|
||||
*/
|
||||
EXPORT int
|
||||
MsgAuthFindCookie(const char *username, const char *token)
|
||||
{
|
||||
char path[XPL_MAX_PATH+1];
|
||||
FILE *cookiefile = NULL;
|
||||
MsgAuthCookie cookie;
|
||||
int result = 0;
|
||||
BOOL expired_tokens = FALSE;
|
||||
uint64_t now;
|
||||
|
||||
now = time(NULL);
|
||||
|
||||
MsgAuthCookiePath(username, path, XPL_MAX_PATH);
|
||||
|
||||
cookiefile = fopen(path, "r");
|
||||
if (! cookiefile) return 2;
|
||||
|
||||
while (fread(&cookie, 1, sizeof(MsgAuthCookie), cookiefile) == sizeof(MsgAuthCookie)) {
|
||||
if (cookie.expiration < now) {
|
||||
expired_tokens = TRUE;
|
||||
continue;
|
||||
}
|
||||
if (!strncmp (cookie.token, token, MSGAUTH_COOKIE_LEN)) {
|
||||
result = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ferror(cookiefile))
|
||||
result = 2;
|
||||
|
||||
fclose(cookiefile);
|
||||
|
||||
if (expired_tokens)
|
||||
// call this function with no token to remove expired tokens
|
||||
MsgAuthDeleteCookie(username, "");
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a token from the user's cookie store. Removes expired tokens as a side-effect.
|
||||
* \param username User whose token this should be
|
||||
* \param token Token we want rid of.
|
||||
* \return Whether or not we succeeded.
|
||||
*/
|
||||
EXPORT BOOL
|
||||
MsgAuthDeleteCookie(const char *username, const char *token)
|
||||
{
|
||||
char path[XPL_MAX_PATH + 1];
|
||||
FILE *cookiefile = NULL;
|
||||
long filelen;
|
||||
int cookiecount, i;
|
||||
MsgAuthCookie **cookieset;
|
||||
uint64_t now;
|
||||
|
||||
now = time(NULL);
|
||||
|
||||
MsgAuthCookiePath(username, path, XPL_MAX_PATH);
|
||||
|
||||
// first, read cookies into memory
|
||||
cookiefile = fopen(path, "w");
|
||||
if (! cookiefile) return FALSE;
|
||||
|
||||
if (fseek(cookiefile, 0, SEEK_END) != 0) {
|
||||
fclose(cookiefile);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
filelen = ftell(cookiefile);
|
||||
cookiecount = filelen / sizeof(MsgAuthCookie);
|
||||
cookieset = MemMalloc(filelen + 1);
|
||||
if (fread(cookieset, 1, filelen, cookiefile) != filelen) {
|
||||
fclose(cookiefile);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// next, clear the existing file
|
||||
rewind(cookiefile);
|
||||
ftruncate(fileno(cookiefile), 0);
|
||||
|
||||
// now, go through memory writing out only the cookies we want to keep
|
||||
for (i = 0; i < cookiecount; i++) {
|
||||
MsgAuthCookie *cookie = cookieset[i];
|
||||
if (! strncmp(cookie->token, token, MSGAUTH_COOKIE_LEN)) {
|
||||
// we want to delete this token
|
||||
cookie->expiration = 0;
|
||||
}
|
||||
if (cookie->expiration < now) {
|
||||
// this token is expired, so we don't want this.
|
||||
cookie->expiration = 0;
|
||||
}
|
||||
if (cookie->expiration != 0) {
|
||||
// we want to keep this token, so write it out
|
||||
size_t written;
|
||||
written = fwrite(cookie, 1, sizeof(MsgAuthCookie), cookiefile);
|
||||
if (written != sizeof(MsgAuthCookie)) {
|
||||
// ooops, this is pretty bad...
|
||||
fclose(cookiefile);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fclose(cookiefile);
|
||||
return TRUE;
|
||||
}
|
||||
Reference in New Issue
Block a user