[idms-dbma-devel]: COMMIT - r98 - in branches/nonblocking_auth/modules: auth/pgsql protocols/pop3
Status: Pre-Alpha
Brought to you by:
nkukard
|
From: <sv...@li...> - 2005-04-21 12:22:30
|
Author: nkukard
Date: 2005-04-21 12:21:58 +0000 (Thu, 21 Apr 2005)
New Revision: 98
Modified:
branches/nonblocking_auth/modules/auth/pgsql/pgsql.c
branches/nonblocking_auth/modules/protocols/pop3/pop3_cmd_pass.c
Log:
* Intermediate check-in of non-blocking authentication
Modified: branches/nonblocking_auth/modules/auth/pgsql/pgsql.c
===================================================================
--- branches/nonblocking_auth/modules/auth/pgsql/pgsql.c 2005-04-21 12:06:17 UTC (rev 97)
+++ branches/nonblocking_auth/modules/auth/pgsql/pgsql.c 2005-04-21 12:21:58 UTC (rev 98)
@@ -221,6 +221,178 @@
+/* Process database results & try authenticate, return 0 on pass, 1 on success, 2 on failure, and -1 on error*/
+static int authAgainstDB(struct dbConnection_t *dbConn, PGresult *pgres)
+{
+ ExecStatusType pgresStatus;
+ int usernameCol = -1, passwordCol = -1, mailstoreCol = -1, realmCol = -1, quotaCol = -1, activeCol = -1;
+ int numResults = -1;
+ int i;
+ int actives = 0;
+
+
+ /* Check we got the right response */
+ if ((pgresStatus = PQresultStatus(pgres)) != PGRES_TUPLES_OK)
+ {
+ D_PRINT(D_ERROR,"Database error occured: %s",PQresultErrorMessage(pgres));
+ return -1;
+ }
+
+ /* Verify data returned from query */
+ numResults = PQntuples(pgres);
+
+ /* If we have no results just return 0 */
+ if (numResults < 1)
+ return 0;
+
+ D_PRINT(D_NOTICE,"We got %i results back", numResults);
+
+ /* Check that we have the columns we need */
+ if ((usernameCol = PQfnumber(pgres,"username")) < 0)
+ {
+ D_PRINT(D_ERROR,"No username column returned from database query");
+ return -1;
+ }
+
+ if ((passwordCol = PQfnumber(pgres,"password")) < 0)
+ {
+ D_PRINT(D_ERROR,"No password column returned from database query");
+ return -1;
+ }
+
+ if ((mailstoreCol = PQfnumber(pgres,"mailstore")) < 0)
+ {
+ D_PRINT(D_ERROR,"No mailstore column returned from database query");
+ return -1;
+ }
+
+ if ((realmCol = PQfnumber(pgres,"realm")) < 0)
+ D_PRINT(D_NOTICE,"No realm column returned from database query, ignoring realm");
+
+ if ((quotaCol = PQfnumber(pgres,"quota")) < 0)
+ D_PRINT(D_NOTICE,"No quota column returned from database query, ignoring quota");
+
+ if ((activeCol = PQfnumber(pgres,"active")) < 0)
+ D_PRINT(D_NOTICE,"No active column returned from database query, assuming all active");
+
+ /*
+ * Loop with results, it could be someone else had an email address, was cancelled and someone else
+ * signed up in this case we must take first one that authenticates, verify that only 1 active
+ * address exists
+ */
+ for (i = 0; i < numResults; i++)
+ {
+ char *username = NULL, *password = NULL, *mailstore = NULL;
+ char *realm = NULL;
+
+
+ /* First of all check if this entry is active, ignore it otherwise */
+ if (activeCol >= 0)
+ {
+ char *active = NULL;
+
+
+ active = PQgetvalue(pgres,i,activeCol);
+ /* If entry is not active, continue to find one that is */
+ if (strcmp(active,"true") != 0)
+ {
+ D_PRINT(D_NOTICE,"User \"%s\" on realm \"%s\" is deactivated, ignoring",
+ dbConn->authInfo->username, dbConn->authInfo->realm);
+ continue;
+ }
+ }
+
+ /* Pull out username, and make sure everything matches */
+ username = PQgetvalue(pgres,i,usernameCol);
+ if (strcmp(username,dbConn->authInfo->username) != 0)
+ {
+ D_PRINT(D_ERROR,"Returned username result \"%s\" does not match authentication username \"%s\", ignoring",
+ username,dbConn->authInfo->username);
+ continue;
+ }
+
+ /* We are obviously active... if we got this far */
+ actives++;
+
+ /* Only 1 address can match and be active */
+ if (actives > 1)
+ {
+ D_PRINT(D_ERROR,"Too many active usernames which match \"%s\", ignoring results",dbConn->authInfo->username);
+ continue;
+ }
+
+ /* Pull out password & check if it actually contains something */
+ password = PQgetvalue(pgres,i,passwordCol);
+ if (strlen(password) == 0)
+ {
+ D_PRINT(D_ERROR,"Zero length password returned, ignoring");
+ continue;
+ }
+
+ /* Pull out mailstore and check if it also contains something */
+ mailstore = PQgetvalue(pgres,i,mailstoreCol);
+ if (strlen(mailstore) == 0)
+ {
+ D_PRINT(D_ERROR,"Zero length mailstore returned, ignoring");
+ continue;
+ }
+
+ /* Check if we have a realm column */
+ if (realmCol >= 0)
+ {
+
+ /* Get result from database if we do */
+ realm = PQgetvalue(pgres,i,realmCol);
+ /* If we were provided a realm for authenticating, verify we have the right data */
+ if (dbConn->authInfo->realm)
+ {
+ /* Compare and throw us an error if realms don't match */
+ if (strcmp(realm,dbConn->authInfo->realm) != 0)
+ {
+ D_PRINT(D_ERROR,"Returned realm result \"%s\" does not match authentication realm \"%s\", ignoring",
+ realm,dbConn->authInfo->realm);
+ continue;
+ }
+ }
+ }
+
+ /* Check if we have a quota column */
+ if (quotaCol >= 0)
+ {
+ unsigned int quotaVal;
+ char *quota;
+
+
+ /* Get string representation from database */
+ quota = PQgetvalue(pgres,i,quotaCol);
+ /* Convert to long int which is compat with unsigned int */
+ quotaVal = atol(quota);
+ }
+
+ /* Finally verify password */
+ if (strcmp(password,dbConn->authInfo->password) == 0)
+ {
+ /* Set mailstore */
+ dbConn->authInfo->mailstore = mailstore;
+
+ /* Set realm if it was not set but returned */
+ if (realm && !dbConn->authInfo->realm)
+ dbConn->authInfo->realm = strdup(realm);
+
+ return 1;
+ }
+ else
+ {
+ D_PRINT(D_NOTICE,"User \"%s\" on realm \"%s\", access denied",dbConn->authInfo->username,
+ dbConn->authInfo->realm ? dbConn->authInfo->realm : realm);
+ return 2;
+ }
+ }
+
+ return 0;
+}
+
+
/* PGSQL authentication thread */
static gpointer pgsql_auth_thread(gpointer data)
{
@@ -304,145 +476,183 @@
/* Check if all is well */
- if ((dbConn = item->data))
+ if (!(dbConn = item->data))
{
- D_PRINT(D_DEBUG,"Processing active connection");
- /* Poll connection process to database */
- if (dbConn->state == PGSQL_STATE_CONN)
+ D_PRINT(D_ERROR,"Error, item->data is NULL, ignoring...");
+ /* Advance and continue past this entry */
+ item = g_list_next(item);
+ continue;
+ }
+
+ /* Poll connection process to database */
+ if (dbConn->state == PGSQL_STATE_CONN)
+ {
+ D_PRINT(D_DEBUG,"Connection is in the state of connecting");
+ /* Check if our FD is in the set of changed FD's */
+ if (FD_ISSET(dbConn->sock,&tmp_wfds) || FD_ISSET(dbConn->sock,&tmp_rfds))
{
- int isset_wfd = FD_ISSET(dbConn->sock,&tmp_wfds), isset_rfd = FD_ISSET(dbConn->sock,&tmp_rfds);
+ PostgresPollingStatusType pollRes;
+
- D_PRINT(D_DEBUG,"Connection is in the state of connecting");
- /* Check if our FD is in the set of changed FD's */
- if (isset_wfd || isset_rfd)
- {
- PostgresPollingStatusType pollRes;
+ D_PRINT(D_DEBUG,"Something changed on the pgsql connection");
-
- D_PRINT(D_DEBUG,"Something changed on the pgsql connection");
+ pollRes = PQconnectPoll(dbConn->pgConn);
- pollRes = PQconnectPoll(dbConn->pgConn);
-
- if (pollRes == PGRES_POLLING_READING)
+ if (pollRes == PGRES_POLLING_READING)
+ {
+ D_PRINT(D_NOTICE,"Polling read");
+ /* We now want input */
+ FD_CLR(dbConn->sock,&outputFDs);
+ FD_SET(dbConn->sock,&inputFDs);
+ }
+ else if (pollRes == PGRES_POLLING_WRITING)
+ {
+ D_PRINT(D_NOTICE,"Polling write");
+ /* We now want output */
+ FD_CLR(dbConn->sock,&inputFDs);
+ FD_SET(dbConn->sock,&outputFDs);
+ }
+ else if (pollRes == PGRES_POLLING_OK)
+ {
+ D_PRINT(D_NOTICE,"Connected");
+ /* Connection is established */
+ FD_CLR(dbConn->sock,&outputFDs);
+ FD_CLR(dbConn->sock,&inputFDs);
+ /* State is now idle */
+ if (dbConn->authInfo)
+ dbConn->state = PGSQL_STATE_AUTH;
+ else
{
- D_PRINT(D_NOTICE,"Polling read");
- /* Make sure we checking for the right IO */
- if (isset_wfd)
- {
- FD_CLR(dbConn->sock,&outputFDs);
- FD_SET(dbConn->sock,&inputFDs);
- }
+ activeConns = g_list_remove(activeConns,dbConn);
+ idleConns = g_list_append(idleConns,dbConn);
}
- else if (pollRes == PGRES_POLLING_WRITING)
- {
- D_PRINT(D_NOTICE,"Polling write");
- /* Make sure we checking for the right IO */
- if (isset_rfd)
- {
- FD_CLR(dbConn->sock,&inputFDs);
- FD_SET(dbConn->sock,&outputFDs);
- }
- }
- else if (pollRes == PGRES_POLLING_OK)
- {
- D_PRINT(D_NOTICE,"Connected");
- if (isset_wfd)
- FD_CLR(dbConn->sock,&outputFDs);
- if (isset_rfd)
- FD_CLR(dbConn->sock,&inputFDs);
- /* State is now idle */
- if (dbConn->authInfo)
- dbConn->state = PGSQL_STATE_AUTH;
- else
- {
- activeConns = g_list_remove(activeConns,dbConn);
- idleConns = g_list_append(idleConns,dbConn);
- }
+ }
+ else if (pollRes == PGRES_POLLING_FAILED)
+ {
+ D_PRINT(D_ERROR,"Failed to connect to database");
+ /* Remove from being watched */
+ FD_CLR(dbConn->sock,&outputFDs);
+ FD_CLR(dbConn->sock,&inputFDs);
+
+ /* Cleanup pgsql stuff */
+ PQfinish(dbConn->pgConn);
- }
- else if (pollRes == PGRES_POLLING_FAILED)
+ // Throw error at callback... we were originally called from, remove from active connections aswell
+ if (dbConn->authInfo)
{
- D_PRINT(D_ERROR,"Failed to connect to database");
- if (isset_wfd)
- FD_CLR(dbConn->sock,&outputFDs);
- if (isset_rfd)
- FD_CLR(dbConn->sock,&inputFDs);
-
- if (dbConn->authInfo)
- {
- returnCallback(dbConn->authInfo,AUTH_RES_ERROR);
- }
- else
- {
- // FIXME - CLEANUP!! - this would be if we pre-spawned connections
- }
+ activeConns = g_list_remove(activeConns,dbConn);
+ /* We can't destroy here, we must wait for callback function to call disposal routine */
+ returnCallback(dbConn->authInfo,AUTH_RES_ERROR);
}
- else
- {
- D_PRINT(D_FATAL,"Unknown result from PQconnectPoll(): %i",pollRes);
- }
+ else /* If we pre-spawned we can destroy here */
+ /* Free our connection info */
+ free(dbConn);
}
else
- D_PRINT(D_DEBUG,"Nothing changed on the pgsql connection");
+ {
+ D_PRINT(D_FATAL,"Unknown result from PQconnectPoll(): %i",pollRes);
+ }
}
- /* Check if we need to dispatch a query */
- else if (dbConn->state == PGSQL_STATE_AUTH)
+ else
+ D_PRINT(D_DEBUG,"Nothing changed on the pgsql connection");
+ }
+
+ /* Check if we need to dispatch a query */
+ if (dbConn->state == PGSQL_STATE_AUTH)
+ {
+ int res;
+
+ D_PRINT(D_DEBUG,"Connection is in the state of authentication");
+ // FIXME - add check if the connection is still ok
+ // macros...
+ // - %username
+ // - %password
+ // - %realm
+ //
+ // must return...
+ // - username
+ // - password
+ // - mailstore
+ //
+ // optional return...
+ // - realm
+ // - quota
+ // - active
+ //
+ if ((res = PQsendQuery(dbConn->pgConn,"SELECT username, password, mailstore FROM test")) == 1)
{
- int res;
+ D_PRINT(D_NOTICE,"Query dispatched successfully");
+ dbConn->state = PGSQL_STATE_AUTH_WAIT;
+ FD_SET(dbConn->sock,&inputFDs);
+ }
+ else
+ {
+ // FIXME, queue to call again? or will we infact do this by not doing anything above?
+ D_PRINT(D_DEBUG,"Failed to dispatch query.... blocking???");
+ }
+ }
+ /* If we have already dispatched a query, check if we have results */
+ else if (dbConn->state == PGSQL_STATE_AUTH_WAIT)
+ {
+ int res;
- D_PRINT(D_DEBUG,"Connection is in the state of authentication");
- // FIXME - add check if the connection is still ok
- if ((res = PQsendQuery(dbConn->pgConn,"SELECT username, password FROM test")) == 1)
+ D_PRINT(D_DEBUG,"Connection is waiting for authentication information");
+ /* Check if our FD is in the set of changed FD's */
+ if (FD_ISSET(dbConn->sock,&tmp_rfds))
+ {
+ D_PRINT(D_DEBUG,"Authentication information available");
+ /* Eat up whateva is available */
+ if ((res = PQconsumeInput(dbConn->pgConn)) == 1)
{
- D_PRINT(D_NOTICE,"Query dispatched successfully");
- dbConn->state = PGSQL_STATE_AUTH_WAIT;
+ D_PRINT(D_NOTICE,"We consumed something");
}
- }
- /* If we have already dispatched a query, check if we have results */
- else if (dbConn->state == PGSQL_STATE_AUTH_WAIT)
- {
- int res;
+ /* If we not busy, we can call PQgetResult */
+ while (PQisBusy(dbConn->pgConn) == 0)
+ {
+ PGresult *pgres;
+ int authRes = 0;
+ struct authInfo_t *tmpAuthInfo;
- D_PRINT(D_DEBUG,"Connection is waiting for authentication information");
- /* Check if our FD is in the set of changed FD's */
- if (FD_ISSET(dbConn->sock,&tmp_rfds))
- {
- D_PRINT(D_DEBUG,"Authentication information available");
- /* Eat up whateva is available */
- if ((res = PQconsumeInput(dbConn->pgConn)) == 1)
+
+ D_PRINT(D_NOTICE,"We have results");
+ /* If PQgetResult returns NULL, we at the end of our query */
+ while ((pgres = PQgetResult(dbConn->pgConn)) && !authRes)
{
- D_PRINT(D_NOTICE,"We consumed something");
+ authRes = authAgainstDB(dbConn,pgres);
+ PQclear(pgres);
}
- /* If we not busy, we can call PQgetResult */
- if ((res = PQisBusy(dbConn->pgConn)) == 0)
+ /* Save our authInfo to pass back via callback */
+ tmpAuthInfo = dbConn->authInfo;
+ dbConn->authInfo = NULL;
+ /* Re-label database connection as idle */
+ activeConns = g_list_remove(activeConns,dbConn);
+ idleConns = g_list_append(idleConns,dbConn);
+ /* Don't need to watch connection anymore */
+ FD_CLR(dbConn->sock,&outputFDs);
+ FD_CLR(dbConn->sock,&inputFDs);
+ /* Notify ourselves we might beable to process the queue of auth requests */
+ write(noticePipe[1],"1",1);
+
+ D_PRINT(D_NOTICE,"Calling back");
+ /* We can't destroy here, we must wait for callback function to call disposal routine */
+ if (authRes == 1)
{
- PGresult *pgres;
-
- D_PRINT(D_NOTICE,"connection is not busy");
- /* If PQgetResult returns NULL, we at the end of our query */
- if (!(pgres = PQgetResult(dbConn->pgConn)))
- {
- D_PRINT(D_NOTICE,"We got something back");
- /* Return changes back to original caller */
- }
+ D_PRINT(D_NOTICE,"Auth ok");
+ returnCallback(tmpAuthInfo,AUTH_RES_OK);
}
else
{
- D_PRINT(D_NOTICE,"connection is busy");
+ D_PRINT(D_NOTICE,"Auth failed");
+ returnCallback(tmpAuthInfo,AUTH_RES_INVALID);
}
- }
-
- }
- else
- {
- D_PRINT(D_FATAL,"Invalid state");
- }
- }
- else
- D_PRINT(D_FATAL,"item->data is NULL");
+
+ break;
+ } // while (PQisBusy(dbConn->pgConn) == 0)
+ } // if (FD_ISSET(dbConn->sock,&tmp_rfds))
+ } // else if (dbConn->state == PGSQL_STATE_AUTH_WAIT)
item = g_list_next(item);
} // while (item)
Modified: branches/nonblocking_auth/modules/protocols/pop3/pop3_cmd_pass.c
===================================================================
--- branches/nonblocking_auth/modules/protocols/pop3/pop3_cmd_pass.c 2005-04-21 12:06:17 UTC (rev 97)
+++ branches/nonblocking_auth/modules/protocols/pop3/pop3_cmd_pass.c 2005-04-21 12:21:58 UTC (rev 98)
@@ -37,15 +37,22 @@
struct pop3_data_t *data = authInfo->client->data;
- if (authInfo->result == AUTH_RES_ERROR || authInfo->result == AUTH_RES_INVALID)
+ D_PRINT(D_NOTICE,"Callback");
+
+ if (authInfo->result == AUTH_RES_OK)
{
+ snprintf(data->tmpBuf,data->tmpBufSize,"+OK"EOL);
+
+ data->position = POP3_POS_USER_INPUT;
+ queueToSend(authInfo->client,data->tmpBuf,strlen(data->tmpBuf),POP3_IO_TIMEOUT);
+ }
+ else
+ {
D_PRINT(D_ERROR,"Some sort of authentication error occured");
snprintf(data->tmpBuf,data->tmpBufSize,"-ERR Permission denied"EOL);
data->position = POP3_POS_USER_INPUT;
queueToSend(authInfo->client,data->tmpBuf,strlen(data->tmpBuf),POP3_IO_TIMEOUT);
- } else if (authInfo->result == AUTH_RES_OK)\
- {
#if 0
/* Get our mailstore handler commands */
if (!(connection->storageCmds = get_mailstore_handler(connection->authInfo->mailstore)))
|