summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--database/postgresql/administration/authentication.c530
-rw-r--r--database/postgresql/edb-pgsql.c2
2 files changed, 531 insertions, 1 deletions
diff --git a/database/postgresql/administration/authentication.c b/database/postgresql/administration/authentication.c
new file mode 100644
index 0000000..24b90a3
--- /dev/null
+++ b/database/postgresql/administration/authentication.c
@@ -0,0 +1,530 @@
+/* administration.c -- Functions needed for administration tasks
+ *
+ * GPLv2 only - Copyright (C) 2008 - 2010
+ * David Sommerseth <dazo@users.sourceforge.net>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; version 2
+ * of the License.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/**
+ * @file authentication.c
+ * @author David Sommerseth <dazo@users.sourceforge.net>
+ * @date 2008-12-03
+ *
+ * @brief Functions used for authentication of administration sessions.
+ *
+ */
+
+#include <string.h>
+#include <unistd.h>
+#include <assert.h>
+#include <libxml/tree.h>
+#include <libpq-fe.h>
+
+/**
+ * @{
+ */
+#ifndef DRIVERAPIVERSION
+# define DRIVERAPIVERSION 2
+#endif
+/**
+ * @}
+ */
+
+#include <eurephia_nullsafe.h>
+#include <eurephia_context.h>
+#include <eurephia_log.h>
+#include <eurephia_xml.h>
+#include <eurephia_values.h>
+#include <eurephiadb_session_struct.h>
+#include <eurephiadb_mapping.h>
+#include <passwd.h>
+
+#ifndef DRIVER_MODE
+#define DRIVER_MODE
+#endif
+#include <eurephiadb_driver.h>
+
+#include "../pgsql-common.h"
+
+#if (DRIVERAPIVERSION > 1) || defined(DOXYGEN)
+/*
+ * API Version 2 functions
+ *
+ */
+
+
+/**
+ * Authenticate a user for the administration interface. This interface do not
+ * require any certificate validation and is intended for administration utilities
+ * for eurephia. The eurephia context type must be either ECTX_ADMIN_CONSOLE or
+ * ECTX_ADMIN_WEB.
+ *
+ * @param ctx eurephiaCTX - context used for administration task
+ * @param req_access String containing the requested administration access level
+ * @param uname username of the user being authenticated
+ * @param pwd password from the user
+ *
+ * @return Returns an eurephia ResultMsg XML document with the result. On fatal errors, NULL is returned
+ */
+static xmlDoc *auth_user(eurephiaCTX *ctx, const char *req_access, const char *uname, const char *pwd) {
+ xmlDoc *res_d = NULL;
+ xmlNode *info_n = NULL;
+ PGresult *dbr = NULL;
+ ePGprepParams *qry_args = NULL;
+ char *crpwd = NULL, *dbpwd = NULL;
+ char *activated = NULL, *deactivated = NULL, *blid = NULL, *uid = NULL;
+ int access = 0;
+ char interface;
+
+ DEBUG(ctx, 21, "Function call: auth_user(ctx, '%s, '%s', 'xxxxxxxx')", req_access, uname);
+
+ assert(ctx != NULL);
+
+ switch( ctx->context_type ) {
+ case ECTX_ADMIN_CONSOLE:
+ interface = 'C';
+ break;
+ case ECTX_ADMIN_WEB:
+ interface = 'W';
+ break;
+ default:
+ eurephia_log(ctx, LOG_ERROR, 0, "Wrong eurephia context type (0x%04x)", ctx->context_type);
+ return NULL;
+ }
+
+ if( (strlen_nullsafe(uname) < 4) || (strlen_nullsafe(pwd) < 4) ) {
+ eurephia_log(ctx, LOG_WARNING, 0,
+ "Username and/or password is either null or less than 4 bytes");
+ return eurephiaXML_ResultMsg(ctx, exmlERROR, NULL, "Username or password is too short");
+ }
+
+ //
+ // Authenticate user and password
+ //
+ qry_args = ePGprepParamsAlloc(ctx, PREPSQL_ADMIN_AUTHUSER);
+ ePGprepParamsAddArgument(ctx, qry_args, uname);
+ dbr = ePGprepExec(ctx, qry_args);
+ if( !dbr || (PQresultStatus(dbr) != PGRES_TUPLES_OK) ) {
+ xmlNode *err_n = NULL;
+
+ eurephia_log(ctx, LOG_FATAL, 0, "Could not authenticate user against the database");
+ err_n = ePGerrorMessageXML(ctx, dbr, LOG_FATAL, PREPSQL_ADMIN_AUTHUSER);
+ res_d = eurephiaXML_ResultMsg(ctx, exmlERROR, err_n, "Authentication failed");
+ xmlFreeNode(err_n);
+ return res_d;
+ }
+
+ if( PQntuples(dbr) == 1 ) {
+ activated = ePGgetValue(dbr, 0, 0);
+ deactivated = ePGgetValue(dbr, 0, 1);
+ blid = ePGgetValue(dbr, 0, 2);
+ dbpwd = ePGgetValue(dbr, 0, 3);
+ uid = strdup_nullsafe(ePGgetValue(dbr, 0, 4));
+
+ if( blid != NULL ) {
+ eurephia_log(ctx, LOG_WARNING, 0,
+ "User account '%s' is BLACKLISTED. You have no access.", uname);
+ PQclear(dbr);
+ return eurephiaXML_ResultMsg(ctx, exmlERROR, NULL, "Authentication failed");
+ }
+
+ if( activated == NULL ) {
+ eurephia_log(ctx, LOG_WARNING, 0, "User account '%s' is not yet activated.", uname);
+ PQclear(dbr);
+ return eurephiaXML_ResultMsg(ctx, exmlERROR, NULL, "Authentication failed");
+ }
+
+ if( deactivated != NULL ) {
+ eurephia_log(ctx, LOG_WARNING, 0, "User account '%s' is deactivated.", uname);
+ PQclear(dbr);
+ return eurephiaXML_ResultMsg(ctx, exmlERROR, NULL, "Authentication failed");
+ }
+
+ if( dbpwd == NULL ) {
+ eurephia_log(ctx, LOG_WARNING, 0, "Authentication failed. DB error.");
+ PQclear(dbr);
+ return eurephiaXML_ResultMsg(ctx, exmlERROR, NULL, "Authentication failed");
+ } else {
+ int pwdok = 0;
+ // Verify the password
+ crpwd = eurephia_pwd_crypt(ctx, pwd, dbpwd);
+ pwdok = ((crpwd != NULL) && (strcmp(crpwd, dbpwd) == 0) ? 1 : 0);
+ memset(crpwd, 0, strlen_nullsafe(crpwd));
+ memset(dbpwd, 0, strlen_nullsafe(dbpwd));
+ free_nullsafe(ctx, crpwd);
+ if( pwdok == 0 ) {
+ eurephia_log(ctx, LOG_WARNING, 0, "Authentication failed.");
+ sleep(2);
+ PQclear(dbr);
+ return eurephiaXML_ResultMsg(ctx, exmlERROR, NULL, "Authentication failed");
+ }
+ }
+ PQclear(dbr);
+
+ // Check if access level is granted
+ // (SQLite do not handle advanced joins so well, so we need to
+ // do this check with an extra query)
+ qry_args = ePGprepParamsAlloc(ctx, PREPSQL_ADMIN_CHECKACL);
+ ePGprepParamsAddArgument(ctx, qry_args, uid);
+ ePGprepParamsAddArgumentChar(ctx, qry_args, interface);
+ ePGprepParamsAddArgument(ctx, qry_args, req_access);
+ dbr = ePGprepExec(ctx, qry_args);
+ if( !dbr || (PQresultStatus(dbr) != PGRES_TUPLES_OK) ) {
+ xmlNode *err_n = NULL;
+
+ eurephia_log(ctx, LOG_FATAL, 0, "Could not check access level");
+ err_n = ePGerrorMessageXML(ctx, dbr, LOG_FATAL, PREPSQL_ADMIN_AUTHUSER);
+ res_d = eurephiaXML_ResultMsg(ctx, exmlERROR,
+ err_n,"Failed to validate access level");
+ xmlFreeNode(err_n);
+ return res_d;
+ }
+ access = ePGgetValue_bool(dbr, 0, 0);
+ PQclear(dbr);
+
+ if( access == 0 ) {
+ eurephia_log(ctx, LOG_WARNING, 0,
+ "User account '%s' is lacking privileges for this operation", uname);
+ return eurephiaXML_ResultMsg(ctx, exmlERROR, NULL, "Authentication failed");
+ }
+ } else {
+ eurephia_log(ctx, LOG_WARNING, 0, "Authentication failed. No unique records found.");
+ PQclear(dbr);
+ sleep(2);
+ return eurephiaXML_ResultMsg(ctx, exmlERROR, NULL, "Authentication failed");
+ }
+
+ // If we reach this place, authentication was successful. Return users uid
+ info_n = xmlNewNode(NULL, (xmlChar *) "UserAccount");
+ assert( info_n != NULL );
+ xmlNewProp(info_n, (xmlChar *) "uid", (xmlChar *) uid);
+ res_d = eurephiaXML_ResultMsg(ctx, exmlRESULT, info_n, "Successful authentication");
+ xmlFreeNode(info_n);
+ free_nullsafe(ctx, uid);
+ return res_d;
+}
+
+
+/**
+ * Validates a session key, to see if it still is valid (not auto-logged out or invalid session key)
+ * and to check if they have access to a different access level. The eurephia context type must be
+ * either ECTX_ADMIN_CONSOLE or ECTX_ADMIN_WEB.
+ *
+ * @param ctx eurephiaCTX
+ * @param sesskey String containing the session key to validate
+ * @param req_access String containing the required administration access level
+ *
+ * @return Returns an eurephia ResultMsg XML document with the result. On fatal errors, NULL is returned
+ */
+static xmlDoc *auth_session(eurephiaCTX *ctx, const char *sesskey, const char *req_access) {
+ PGresult *dbr = NULL;
+ ePGprepParams *qry_args = NULL;
+ int valid = 0, access = 0, expire_time = 0;
+ char interface;
+ xmlDoc *ret_d = NULL;
+ xmlNode *err_n = NULL;
+
+ DEBUG(ctx, 21, "Function call: auth_session(ctx, '%s, '%s')", sesskey, req_access);
+ assert( (ctx != NULL) && (sesskey != NULL) );
+
+ switch( ctx->context_type ) {
+ case ECTX_ADMIN_CONSOLE:
+ interface = 'C';
+ break;
+ case ECTX_ADMIN_WEB:
+ interface = 'W';
+ break;
+ default:
+ eurephia_log(ctx, LOG_ERROR, 0, "Wrong eurephia context type (0x%04x)", ctx->context_type);
+ return NULL;
+ }
+
+ // Check if the session is still valid (not expired) and that this session are allowed to access
+ // the requested access level.
+ expire_time = atoi_nullsafe(defaultValue(eGet_value(ctx->dbc->config,
+ "eurephiadmin_autologout"),
+ "10")
+ );
+
+ qry_args = ePGprepParamsAlloc(ctx, PREPSQL_ADMIN_AUTHSESS);
+ ePGprepParamsAddArgumentInt(ctx, qry_args, expire_time);
+ ePGprepParamsAddArgument(ctx, qry_args, sesskey);
+ ePGprepParamsAddArgument(ctx, qry_args, req_access);
+ ePGprepParamsAddArgumentChar(ctx, qry_args, interface);
+ dbr = ePGprepExec(ctx, qry_args);
+ if( !dbr || (PQresultStatus(dbr) != PGRES_TUPLES_OK) ) {
+ eurephia_log(ctx, LOG_FATAL, 0, "Could not validate session");
+ err_n = ePGerrorMessageXML(ctx, dbr, LOG_FATAL, PREPSQL_ADMIN_AUTHSESS);
+ ret_d = eurephiaXML_ResultMsg(ctx, exmlERROR, NULL, "Session authentication failed");
+ xmlFreeNode(err_n);
+ return ret_d;
+ }
+
+ valid = (ePGgetValue_bool(dbr, 0, 0) == 0);
+ access = (ePGgetValue_bool(dbr, 0, 1) == 1);
+ PQclear(dbr);
+
+ // If still valid, update last_action
+ if( valid && access ) {
+ qry_args = ePGprepParamsAlloc(ctx, PREPSQL_ADMIN_ADMLOG_LASTACT);
+ ePGprepParamsAddArgument(ctx, qry_args, sesskey);
+ dbr = ePGprepExec(ctx, qry_args);
+ if( !dbr || (PQresultStatus(dbr) != PGRES_COMMAND_OK) ) {
+ eurephia_log(ctx, LOG_ERROR, 0, "Could not register session activity");
+ err_n = ePGerrorMessageXML(ctx, dbr, LOG_CRITICAL, PREPSQL_ADMIN_ADMLOG_LASTACT);
+ } else {
+ PQclear(dbr);
+ }
+ } else {
+ // If not valid, register session as auto-logged out
+ qry_args = ePGprepParamsAlloc(ctx, PREPSQL_ADMIN_ADMLOG_LOGOUT);
+ ePGprepParamsAddArgumentInt(ctx, qry_args, (access ? 4 : 5));
+ ePGprepParamsAddArgument(ctx, qry_args, sesskey);
+ if( !dbr || (PQresultStatus(dbr) != PGRES_COMMAND_OK) ) {
+ eurephia_log(ctx, LOG_ERROR, 0, "Could not register old session as logged out");
+ err_n = ePGerrorMessageXML(ctx, dbr, LOG_CRITICAL, PREPSQL_ADMIN_ADMLOG_LOGOUT);
+ } else {
+ PQclear(dbr);
+ }
+
+ // Delete session variables
+ qry_args = ePGprepParamsAlloc(ctx, PREPSQL_SESSIONS_DESTROY_SESS);
+ ePGprepParamsAddArgument(ctx, qry_args, sesskey);
+ dbr = ePGprepExec(ctx, qry_args);
+ if( !dbr || (PQresultStatus(dbr) != PGRES_COMMAND_OK) ) {
+ eurephia_log(ctx, LOG_ERROR, 0,
+ "Could not delete session variables (%s))", sesskey);
+ err_n = ePGerrorMessageXML(ctx, dbr, LOG_CRITICAL, PREPSQL_SESSIONS_DESTROY_SESS);
+ dbr = NULL;
+ } else if( !access ) {
+ eurephia_log(ctx, LOG_WARNING, 0, "User account is lacking privileges");
+ }
+ if( dbr != NULL ) {
+ PQclear(dbr);
+ }
+ }
+
+ if (valid && access) {
+ ret_d = eurephiaXML_ResultMsg(ctx, exmlRESULT, err_n, "Session authenticated");
+ } else {
+ ret_d = eurephiaXML_ResultMsg(ctx, exmlERROR, err_n, "Session authentication failed");
+ }
+ if( err_n != NULL ) {
+ xmlFreeNode(err_n);
+ }
+ return ret_d;
+}
+
+
+/**
+ * Registers the user as logged in after a successful authentication. The user must
+ * be registered as logged in to have a valid session.
+ *
+ * @param ctx eurephiaCTX
+ * @param uid Numeric value if the user ID the session belongs to
+ * @param sesskey String containing the session key
+ *
+ * @return Returns an eurephia ResultMsg XML document with the result. On fatal errors, NULL is returned
+ */
+static xmlDoc *register_login(eurephiaCTX *ctx, const int uid, const char *sesskey) {
+ PGresult *dbr = NULL;
+ ePGprepParams *qry_args = NULL;
+ xmlDoc *ret_d = NULL;
+ char interface;
+
+ DEBUG(ctx, 21, "Function call: register_login(ctx, %i, '%s')", uid, sesskey);
+ assert( ctx != NULL );
+
+ if( (sesskey == NULL) || (uid < 1) ) {
+ return eurephiaXML_ResultMsg(ctx, exmlERROR, NULL, "Invalid data for login registration");
+ }
+
+ switch( ctx->context_type ) {
+ case ECTX_ADMIN_CONSOLE:
+ interface = 'C'; break;
+ case ECTX_ADMIN_WEB:
+ interface = 'W'; break;
+ default:
+ eurephia_log(ctx, LOG_ERROR, 0, "Wrong eurephia context type (0x%04x)", ctx->context_type);
+ return NULL;
+ }
+
+ // Register login into eurephia_adminlog ... uid, login, interface, sessionkey
+ qry_args = ePGprepParamsAlloc(ctx, PREPSQL_ADMIN_REGLOGIN);
+ ePGprepParamsAddArgumentInt(ctx, qry_args, uid);
+ ePGprepParamsAddArgumentChar(ctx, qry_args, interface);
+ ePGprepParamsAddArgument(ctx, qry_args, sesskey);
+ dbr = ePGprepExec(ctx, qry_args);
+ if( dbr && (PQresultStatus(dbr) == PGRES_COMMAND_OK) ) {
+ ret_d = eurephiaXML_ResultMsg(ctx, exmlRESULT, NULL, "Session is registered as logged in");
+ PQclear(dbr);
+ } else {
+ xmlNode *err_n = NULL;
+
+ eurephia_log(ctx, LOG_FATAL, 0, "Failed to register the session in the database");
+ err_n = ePGerrorMessageXML(ctx, dbr, LOG_CRITICAL, PREPSQL_ADMIN_REGLOGIN);
+ ret_d = eurephiaXML_ResultMsg(ctx, exmlERROR, err_n,
+ "Failed to register the session in the database");
+ xmlFreeNode(err_n);
+ }
+ return ret_d;
+}
+
+
+/**
+ * Registers a session as logged out. This will require the user to do a new authentication
+ * on next access via the administration interface
+ *
+ * @param ctx eurephiaCTX
+ * @param sessionkey String containing the session key
+ *
+ * @return Returns an eurephia ResultMsg XML document with the result. On fatal errors, NULL is returned
+ */
+static xmlDoc *register_logout(eurephiaCTX *ctx, const char *sessionkey) {
+ PGresult *dbr = NULL;
+ ePGprepParams *qry_args = NULL;
+ xmlDoc *ret_d = NULL;
+ xmlNode *err_n = NULL;
+
+ DEBUG(ctx, 21, "Function call: register_logout(ctx, '%s')", sessionkey);
+ assert((ctx != NULL) && (sessionkey != NULL));
+
+ if( (ctx->context_type != ECTX_ADMIN_CONSOLE) && (ctx->context_type != ECTX_ADMIN_WEB) ) {
+ eurephia_log(ctx, LOG_CRITICAL, 0,
+ "eurephia admin function call attempted with wrong context type");
+ return NULL;
+ }
+
+ // Update session as logged out
+ qry_args = ePGprepParamsAlloc(ctx, PREPSQL_ADMIN_ADMLOG_LOGOUT);
+ ePGprepParamsAddArgument(ctx, qry_args, "3");
+ ePGprepParamsAddArgument(ctx, qry_args, sessionkey);
+ dbr = ePGprepExec(ctx, qry_args);
+ if( !dbr || (PQresultStatus(dbr) != PGRES_COMMAND_OK) ) {
+ eurephia_log(ctx, LOG_FATAL, 0,
+ "Failed to register the session as logged out");
+ err_n = ePGerrorMessageXML(ctx, dbr, LOG_CRITICAL, PREPSQL_ADMIN_ADMLOG_LOGOUT);
+ ret_d = eurephiaXML_ResultMsg(ctx, exmlERROR, err_n,
+ "Failed to register the session as logged out");
+ xmlSaveFormatFileEnc("-", ret_d, "UTF-8", 1);
+ xmlFreeNode(err_n);
+ return ret_d;
+ }
+ PQclear(dbr);
+
+ // Delete session variables
+ qry_args = ePGprepParamsAlloc(ctx, PREPSQL_SESSIONS_DESTROY_SESS);
+ ePGprepParamsAddArgument(ctx, qry_args, sessionkey);
+ dbr = ePGprepExec(ctx, qry_args);
+ if( dbr && (PQresultStatus(dbr) == PGRES_COMMAND_OK) ) {
+ ret_d = eurephiaXML_ResultMsg(ctx, exmlRESULT, NULL, "Session is logged out");
+ PQclear(dbr);
+ } else {
+ eurephia_log(ctx, LOG_ERROR, 0,
+ "Could not delete session variables (%s))", sessionkey);
+ err_n = ePGerrorMessageXML(ctx, dbr, LOG_CRITICAL, PREPSQL_SESSIONS_DESTROY_SESS);
+ ret_d = eurephiaXML_ResultMsg(ctx, exmlERROR, err_n,
+ "Could not delete session variables (%s)", sessionkey);
+ xmlFreeNode(err_n);
+ }
+
+ return ret_d;
+}
+
+
+/**
+ * @copydoc eDBadminAuthenticate()
+ */
+xmlDoc *eDBadminAuthenticate(eurephiaCTX *ctx, xmlDoc *qryxml) {
+ xmlDoc *res_d = NULL;
+ xmlNode *qry_n = NULL;
+ char *mode = NULL;
+ int type = 0;
+
+ DEBUG(ctx, 20, "Function call: eDBadminAuthenticate(ctx, xmlDoc)");
+ assert( (ctx != NULL) && (qryxml != NULL) );
+
+ if( (ctx->context_type != ECTX_ADMIN_CONSOLE) && (ctx->context_type != ECTX_ADMIN_WEB) ) {
+ eurephia_log(ctx, LOG_CRITICAL, 0,
+ "eurephia admin function call attempted with wrong context type");
+ return NULL;
+ }
+
+ qry_n = eurephiaXML_getRoot(ctx, qryxml, "Authenticate", 1);
+ if( qry_n != NULL ) {
+ type = 1;
+ goto accept;
+ }
+
+ qry_n = eurephiaXML_getRoot(ctx, qryxml, "Register", 1);
+ if( qry_n != NULL ) {
+ type = 2;
+ goto accept;
+ }
+
+ eurephia_log(ctx, LOG_ERROR, 0, "Could not find a valid XML request for eDBadminAuthenticate()");
+ return NULL;
+
+ accept:
+ mode = xmlGetAttrValue(qry_n->properties, "mode");
+ if( mode == NULL ) {
+ eurephia_log(ctx, LOG_ERROR, 0, "Invalid authentication request");
+ return NULL;
+ }
+
+ switch( type ) {
+ case 1: // Authenticate tag
+ if( strcmp(mode, "user") == 0 ) {
+ // const char *req_access, const char *uname, const char *pwd
+ const char *reqacc = NULL, *uname = NULL, *pwd = NULL;
+ uname = xmlGetNodeContent(qry_n, "username");
+ pwd = xmlGetNodeContent(qry_n, "password");
+ reqacc = xmlGetNodeContent(qry_n, "accesslevel");
+ res_d = auth_user(ctx, reqacc, uname, pwd);
+ } else if ( strcmp(mode, "session") == 0 ) {
+ const char *sesskey = NULL, *reqacc = NULL;
+ sesskey = xmlGetNodeContent(qry_n, "sessionkey");
+ reqacc = xmlGetNodeContent(qry_n, "accesslevel");
+ res_d = auth_session(ctx, sesskey, reqacc);
+ }
+ break;
+
+ case 2: // Register tag
+ if( strcmp(mode, "login") == 0 ) {
+ const char *sesskey = NULL;
+ unsigned int uid = 0;
+
+ uid = atoi_nullsafe(xmlGetAttrValue(qry_n->properties, "uid"));
+ sesskey = xmlExtractContent(qry_n);
+ res_d = register_login(ctx, uid, sesskey);
+ } else if( strcmp(mode, "logout") == 0 ) {
+ const char *sesskey = NULL;
+
+ sesskey = xmlExtractContent(qry_n);
+ res_d = register_logout(ctx, sesskey);
+ }
+ break;
+
+ default:
+ eurephia_log(ctx, LOG_FATAL, 0, "The unthinkable has just happened (type %i)", type);
+ res_d = NULL;
+ break;
+ }
+ return res_d;
+}
+
+#endif
diff --git a/database/postgresql/edb-pgsql.c b/database/postgresql/edb-pgsql.c
index 2fe1463..79389ac 100644
--- a/database/postgresql/edb-pgsql.c
+++ b/database/postgresql/edb-pgsql.c
@@ -37,7 +37,7 @@
#define DRIVERVERSION "1.0"
#ifndef DRIVERAPIVERSION
-# define DRIVERAPIVERSION 1
+# define DRIVERAPIVERSION 2
#endif
#include <eurephiadb_driver.h>