Subject Httpd authentication module with firebird
Author hfsnell
Hi everybody!
Is there any software like mod_auth_mysql or mod_auth_pgsql for Firebird?
I have written my own module named mod_auth_fbsql based mod_auth_mysql
source code but not succeed. Httpd connect to Firebird successfully
but an error happend after that
"Child exit with segmentation fault (11)"
Please help me. My source code:
/* ====================================================================
* Copyright (c) 1995 The Apache Group. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. All advertising materials mentioning features or use of this
* software must display the following acknowledgment:
* "This product includes software developed by the Apache Group
* for use in the Apache HTTP server project (http://www.apache.org/)."
*
* 4. The names "Apache Server" and "Apache Group" must not be used to
* endorse or promote products derived from this software without
* prior written permission.
*
* 5. Redistributions of any form whatsoever must retain the following
* acknowledgment:
* "This product includes software developed by the Apache Group
* for use in the Apache HTTP server project (http://www.apache.org/)."
*
* THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR
* IT'S CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Group and was originally based
* on public domain software written at the National Center for
* Supercomputing Applications, University of Illinois, Urbana-Champaign.
* For more information on the Apache Group and the Apache HTTP server
* project, please see <http://www.apache.org/>.
*
*/
/**
* Phuoc H. Nguyen ported to Firebird/Interbase
* Date: 09/11/2006
*
*/
/*
* Module definition information - the part between the -START and -END
* lines below is used by Configure. This could be stored in a separate
* instead.
*
* MODULE-DEFINITION-START
* Name: fbsql_auth_module
* ConfigStart
FBSQL_LIB="-L/opt/firebird/lib -lfbclient -lm -lz"
if [ "X$FBSQL_LIB" != "X" ]; then
LIBS="$LIBS $FbSQL_LIB"
echo " + using $FBSQL_LIB for Firebird support"
fi
* ConfigEnd
* MODULE-DEFINITION-END
*/

#define STRING(x) STR(x) /* Used to build strings from compile options */
#define STR(x) #x

#include "ap_mmn.h" /* For MODULE_MAGIC_NUMBER */
/* Use the MODULE_MAGIC_NUMBER to check if at least Apache 2.0 */
#if AP_MODULE_MAGIC_AT_LEAST(20010223,0)
#define APACHE2
#endif

#define MAX_SIZE 1024*5

/* set any defaults not specified at compile time */
#ifdef HOST /* Host to use */
#define _HOST STRING(HOST)
#else
#define _HOST 0 /* Will default to localhost */
#endif

/* Apache 1.x defines the port as a string, but Apache 2.x uses an
integer */
#ifdef PORT /* The port to use */
#ifdef APACHE2
#define _PORT PORT
#else
#define _PORT STRING(PORT)
#endif
#else
#ifdef APACHE2
#define _PORT 3050 /* Use the one from Firebird */
#else
#define _PORT STRING(3050)
#endif
#endif

#ifdef USER /* Authorized user */
#define _USER STRING(USER)
#else
#define _USER "SYSDBA"
#endif

#ifdef PASSWORD /* Default password */
#define _PASSWORD STRING(PASSWORD)
#else
#define _PASSWORD "masterkey"
#endif

#ifdef DB /* Default database */
#define _DB STRING(DB)
#else
#define _DB STRING(0)
#endif

#ifdef PWTABLE /* Password table */
#define _PWTABLE STRING(PWTABLE)
#else
#define _PWTABLE "user_info" /* Default is user_info */
#endif

#ifdef NAMEFIELD /* Name column in password table */
#define _NAMEFIELD STRING(NAMEFIELD)
#else
#define _NAMEFIELD "user_name" /* Default is "user_name" */
#endif

#ifdef PASSWORDFIELD /* Password column in password table */
#define _PASSWORDFIELD STRING(PASSWORDFIELD)
#else
#define _PASSWORDFIELD "user_password" /* Default is user_password */
#endif

#ifdef GROUPUSERNAMEFIELD
#define _GROUPUSERNAMEFIELD STRING(GROUPUSERNAMEFIELD)
#else
#define _GROUPUSERNAMEFIELD NULL
#endif

#ifdef ENCRYPTION /* Encryption type */
#define _ENCRYPTION STRING(ENCRYPTION)
#else
#define _ENCRYPTION 0 /* Will default to "crypt" in code */
#endif

#ifdef SALTFIELD /* If a salt column is not defined */
#define _SALTFIELD STRING(SALTFIELD)
#else
#define _SALTFIELD "<>" /* Default is no salt */
#endif

#ifdef AUTHORITATIVE /* If we are the last word */
#define _AUTHORITATIVE AUTHORITATIVE
#else
#define _AUTHORITATIVE 1 /* Yes, we are */
#endif

#ifdef NOPASSWORD /* If password not needed */
#define _NOPASSWORD NOPASSWORD
#else
#define _NOPASSWORD 0 /* It is required */
#endif

#ifdef ENABLE /* If we are to be enabled */
#define _ENABLE ENABLE
#else
#define _ENABLE 1 /* Assume we are */
#endif

#include "httpd.h"
#include "http_config.h"
#include "http_core.h"
#include "http_log.h"
#include "http_protocol.h"

#ifdef APACHE2
#define PCALLOC apr_pcalloc
#define SNPRINTF apr_snprintf
#define PSTRDUP apr_pstrdup
#define PSTRNDUP apr_pstrndup
#define STRCAT ap_pstrcat
#define POOL apr_pool_t
#include "http_request.h" /* for ap_hook_(check_user_id |
auth_checker)*/
#include "ap_compat.h"
#include "apr_strings.h"
#include "apr_sha1.h"
#include "apr_base64.h"
#include "apr_lib.h"
#define ISSPACE apr_isspace
#ifdef CRYPT
#include "crypt.h"
#else
#include "unistd.h"
#endif
#define LOG_ERROR(lvl, stat, rqst, msg) \
ap_log_rerror (APLOG_MARK, lvl, stat, rqst, msg)
#define LOG_ERROR_1(lvl, stat, rqst, msg, parm) \
ap_log_rerror (APLOG_MARK, lvl, stat, rqst, msg, parm)
#define LOG_ERROR_2(lvl, stat, rqst, msg, parm1, parm2) \
ap_log_rerror (APLOG_MARK, lvl, stat, rqst, msg, parm1, parm2)
#define LOG_ERROR_3(lvl, stat, rqst, msg, parm1, parm2, parm3) \
ap_log_rerror (APLOG_MARK, lvl, stat, rqst, msg, parm1, parm2, parm3)
#define APACHE_FUNC static apr_status_t
#define APACHE_FUNC_RETURN(rc) return rc

#define NOT_AUTHORIZED HTTP_UNAUTHORIZED

#define TABLE_GET apr_table_get
#else
#define PCALLOC ap_pcalloc
#define SNPRINTF ap_snprintf
#define PSTRDUP ap_pstrdup
#define PSTRNDUP ap_pstrndup
#define STRCAT ap_pstrcat
#define POOL pool
#include <stdlib.h>
#include "ap_sha1.h"
#include "ap_ctype.h"
#define LOG_ERROR(lvl, stat, rqst, msg) \
ap_log_error(APLOG_MARK, lvl, rqst->server, msg)
#define LOG_ERROR_1(lvl, stat, rqst, msg, parm) \
ap_log_error(APLOG_MARK, lvl, rqst->server, msg, parm)
#define LOG_ERROR_2(lvl, stat, rqst, msg, parm1, parm2) \
ap_log_error(APLOG_MARK, lvl, rqst->server, msg, parm1, parm2)
#define LOG_ERROR_3(lvl, stat, rqst, msg, parm1, parm2, parm3) \
ap_log_error(APLOG_MARK, lvl, rqst->server, msg, parm1, parm2, parm3)
#define APACHE_FUNC static void
#define APACHE_FUNC_RETURN(rc) return
#define NOT_AUTHORIZED AUTH_REQUIRED
#define TABLE_GET ap_table_get
#define ISSPACE ap_isspace
#endif

#include "util_md5.h"

#include <ibase.h>

#define sql_val(x,y,z) ((x)->items[y*x->nCols+z])
/* salt flags */
#define NO_SALT 0
#define SALT_OPTIONAL 1
#define SALT_REQUIRED 2

/* forward function declarations */
static short pw_md5(POOL * pool, const char * real_pw, const char *
sent_pw, const char * salt);
static short pw_crypted(POOL * pool, const char * real_pw, const char
* sent_pw, const char * salt);
static short pw_sha1(POOL * pool, const char * real_pw, const char *
sent_pw, const char * salt);
static short pw_plain(POOL * pool, const char * real_pw, const char *
sent_pw, const char * salt);

static char * format_remote_host(request_rec * r, char ** parm);
static char * format_remote_ip(request_rec * r, char ** parm);
static char * format_filename(request_rec * r, char ** parm);
static char * format_server_name(request_rec * r, char ** parm);
static char * format_server_hostname(request_rec * r, char ** parm);
static char * format_protocol(request_rec * r, char ** parm);
static char * format_method(request_rec * r, char ** parm);
static char * format_args(request_rec * r, char ** parm);
static char * format_request(request_rec * r, char ** parm);
static char * format_uri(request_rec * r, char ** parm);
static char * format_percent(request_rec * r, char ** parm);
static char * format_cookie(request_rec * r, char ** parm);


typedef struct { /* Encryption methods */
char * string; /* Identifing string */
short salt_status; /* If a salt is required, optional or unused */
short (*func)(POOL * pool, const char * real_pw, const char *
sent_pw, const char * salt);
} encryption ;

/* Encryption methods used. The first entry is the default entry */
static encryption encryptions[] = {{"crypt", SALT_OPTIONAL, pw_crypted},
{"none", NO_SALT, pw_plain},
{"md5", NO_SALT, pw_md5},
{"sha1", NO_SALT, pw_sha1}};
typedef struct { /* User formatting patterns */
char pattern; /* Pattern to match */
char * (*func)(request_rec * r, char ** parm);
} format;

format formats[] = {{'h', format_remote_host},
{'a', format_remote_ip},
{'f', format_filename},
{'V', format_server_name},
{'v', format_server_hostname},
{'H', format_protocol},
{'m', format_method},
{'q', format_args},
{'r', format_request},
{'U', format_uri},
{'%', format_percent},
{'C', format_cookie}};
/*
* structure to hold the configuration details for the request
*/
typedef struct {
char *fbsqlhost; /* host name of db server */
#ifdef APACHE2
int fbsqlport; /* port number of db server */
#else
char * fbsqlport; /* port number of db server */
#endif
char *fbsqluser; /* user ID to connect to db server */
char *fbsqlpasswd; /* password to connect to db server */
char *fbsqlDB; /* DB name */
char *fbsqlpwtable; /* user password table */
char *fbsqlgrptable; /* user group table */
char *fbsqlNameField; /* field in password table with username */
char *fbsqlPasswordField; /* field in password table with password */
char *fbsqlGroupField; /* field in group table with group name */
char *fbsqlGroupUserNameField;/* field in group table with username */
char *fbsqlEncryptionField; /* encryption type for passwords */
char *fbsqlSaltField; /* salt for scrambled password */
int fbsqlAuthoritative; /* are we authoritative? */
int fbsqlNoPasswd; /* do we ignore password? */
int fbsqlEnable; /* do we bother trying to auth at all? */
char *fbsqlUserCondition; /* Condition to add to the user
where-clause in select query */
char *fbsqlGroupCondition; /* Condition to add to the group
where-clause in select query */
} fbsql_auth_config_rec;

/*
* Global information for the database connection. Contains
* the host name, userid and database name used to open the
* connection. If handle is not null, assume it is
* still valid. Firebird in recent incarnations will re-connect
* automaticaly if the connection is closed, so we don't have
* to worry about that here.
*/
typedef struct {
isc_db_handle handle;
ISC_STATUS status_vector[20];
} fbsql_connection;

typedef struct or_struct
{
int nRows;
int nCols;
char **items;
}IBASE_RES;
typedef char**IBASE_ROW;

static IBASE_RES empty_res;

static fbsql_connection connection = { 0L };
IBASE_RES *fbsql_query(request_rec*,fbsql_connection*, const char *);
char * ssprtrim(char*, char *);
void fbsql_free_result(IBASE_RES *);
int fbsql_num_rows (IBASE_RES *);
IBASE_ROW fbsql_fetch_row(POOL*,IBASE_RES*,int);
char *fbsql_error (POOL*,fbsql_connection*);
void fbsql_escape_string (char*,const char *,int);
/*
* Global handle to db. If not null, assume it is still valid.
* Firebird in recent incarnations will re-connect automatically if the
* connection is closed, so we don't worry about that here.
*/

void close_connection(){
if (connection.handle != 0L)
{
isc_detach_database(connection.status_vector,connection.handle);
connection.handle = 0L; /* make sure we don't try to use it later */
}
}

/*
* Callback to close firebird handle when necessary. Also called when a
* child httpd process is terminated.
*/
APACHE_FUNC
mod_auth_fbsql_cleanup (void *notused)
{
close_connection();
APACHE_FUNC_RETURN(0);
}

/*
* empty function necessary because register_cleanup requires it as one
* of its parameters
*/
APACHE_FUNC
mod_auth_fbsql_cleanup_child (void *data)
{
/* do nothing */
APACHE_FUNC_RETURN(0);
}


#ifndef APACHE2
/*
* handler to do cleanup on child exit
*/
static void
child_exit(server_rec *s, pool *p)
{
mod_auth_fbsql_cleanup(NULL);
}
#endif



#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif

/*
* open connection to DB server if necessary. Return TRUE if connection
* is good, FALSE if not able to connect. If false returned, reason
* for failure has been logged to error_log file already.
*/
static int
open_db_handle(request_rec *r,fbsql_auth_config_rec *m)
{

int nport;
char dpb_buffer[256],*dpb,*p;
char*dbname;
int dbname_length;
short dpb_length;
#ifdef APACHE2
apr_pool_cleanup_register(r->pool, (void *)NULL,
mod_auth_fbsql_cleanup, mod_auth_fbsql_cleanup_child);
#else
ap_register_cleanup(r->pool, (void *)NULL,
mod_auth_fbsql_cleanup, mod_auth_fbsql_cleanup_child);
#endif

#ifndef APACHE2
if (!m->fbsqlport || sscanf(m->fbsqlport,"%d", &nport) < 1)
nport = 3050;
#else
nport = m->fbsqlport;
#endif
//Set database handle bang 0 truoc khi gan database vao.
connection.handle = 0L;
//Xay dung database buffer.
dpb=dpb_buffer;
*dpb++=isc_dpb_version1;
*dpb++=isc_dpb_num_buffers;
*dpb++=1;
*dpb++=90;
dpb_length=dpb-dpb_buffer;
dpb=dpb_buffer;

isc_expand_dpb(&dpb,&dpb_length,isc_dpb_user_name,m->fbsqluser,isc_dpb_password,m->fbsqlpasswd,NULL);
if(strcasecmp(m->fbsqlhost,"localhost")!=0)
{
dbname_length = strlen(m->fbsqlhost)+1+strlen(m->fbsqlDB);
dbname = STRCAT(r->pool,m->fbsqlhost,":",m->fbsqlDB,NULL);
}
else
{
dbname_length = strlen(m->fbsqlDB);
dbname = PSTRDUP(r->pool,m->fbsqlDB);
}

isc_attach_database(connection.status_vector,dbname_length,dbname,&connection.handle,dpb_length,dpb);
if (connection.handle == 0L) {
LOG_ERROR_1(APLOG_ERR, 0, r, "Firebird ERROR: %s",
fbsql_error(r->pool,&connection));
return 0;
}
return 1;
}

static void * create_fbsql_auth_dir_config (POOL *p, char *d)
{
fbsql_auth_config_rec *m = PCALLOC(p, sizeof(fbsql_auth_config_rec));
if (!m) return NULL; /* failure to get memory is a bad thing */

/* default values */
m->fbsqlhost = _HOST;
m->fbsqlport = _PORT;
m->fbsqluser = _USER;
m->fbsqlpasswd = _PASSWORD;
m->fbsqlDB = _DB;
m->fbsqlpwtable = _PWTABLE;
m->fbsqlgrptable = 0; /* user group table */
m->fbsqlNameField = _NAMEFIELD; /* default user name field */
m->fbsqlPasswordField = _PASSWORDFIELD; /* default user password
field */
m->fbsqlGroupUserNameField = _GROUPUSERNAMEFIELD; /* user name field
in group table */
m->fbsqlEncryptionField = _ENCRYPTION; /* default encryption
is encrypted */
m->fbsqlSaltField = _SALTFIELD; /* default is scramble
password against itself */
m->fbsqlAuthoritative = _AUTHORITATIVE; /* we are authoritative
source for users */
m->fbsqlNoPasswd = _NOPASSWORD; /* we require password */
m->fbsqlEnable = _ENABLE; /* authorization on by default */
m->fbsqlUserCondition = 0; /* No condition to add
to the user
where-clause in select query */
m->fbsqlGroupCondition = 0; /* No condition to add
to the group
where-clause in select query */
return (void *)m;
}

#ifdef APACHE2
static
command_rec fbsql_auth_cmds[] = {
AP_INIT_TAKE1("AuthFirebirdHost", ap_set_string_slot,
(void *) APR_XtOffsetOf(fbsql_auth_config_rec, fbsqlhost),
OR_AUTHCFG, "firebird server host name"),

AP_INIT_TAKE1("AuthFirebirdPort", ap_set_int_slot,
(void *) APR_XtOffsetOf(fbsql_auth_config_rec, fbsqlport),
OR_AUTHCFG, "firebird server port number"),

AP_INIT_TAKE1("AuthFirebirdUser", ap_set_string_slot,
(void *) APR_XtOffsetOf(fbsql_auth_config_rec, fbsqluser),
OR_AUTHCFG, "firbird server user name"),

AP_INIT_TAKE1("AuthFirebirdPassword", ap_set_string_slot,
(void *) APR_XtOffsetOf(fbsql_auth_config_rec, fbsqlpasswd),
OR_AUTHCFG, "firebird server user password"),

AP_INIT_TAKE1("AuthFirebirdDB", ap_set_string_slot,
(void *) APR_XtOffsetOf(fbsql_auth_config_rec, fbsqlDB),
OR_AUTHCFG, "firebird database name"),

AP_INIT_TAKE1("AuthFirebirdUserTable", ap_set_string_slot,
(void *) APR_XtOffsetOf(fbsql_auth_config_rec, fbsqlpwtable),
OR_AUTHCFG, "firebird user table name"),

AP_INIT_TAKE1("AuthFirebirdGroupTable", ap_set_string_slot,
(void *) APR_XtOffsetOf(fbsql_auth_config_rec, fbsqlgrptable),
OR_AUTHCFG, "firebird group table name"),

AP_INIT_TAKE1("AuthFirebirdNameField", ap_set_string_slot,
(void *) APR_XtOffsetOf(fbsql_auth_config_rec, fbsqlNameField),
OR_AUTHCFG, "firebird User ID field name within User table"),

AP_INIT_TAKE1("AuthFirebirdGroupField", ap_set_string_slot,
(void *) APR_XtOffsetOf(fbsql_auth_config_rec, fbsqlGroupField),
OR_AUTHCFG, "firebird Group field name within table"),

AP_INIT_TAKE1("AuthFirebirdGroupUserNameField", ap_set_string_slot,
(void *) APR_XtOffsetOf(fbsql_auth_config_rec, fbsqlGroupUserNameField),
OR_AUTHCFG, "firebird User ID field name within Group table"),

AP_INIT_TAKE1("AuthFirebirdPasswordField", ap_set_string_slot,
(void *) APR_XtOffsetOf(fbsql_auth_config_rec, fbsqlPasswordField),
OR_AUTHCFG, "firebird Password field name within table"),

AP_INIT_TAKE1("AuthFirebirdPwEncryption", ap_set_string_slot,
(void *) APR_XtOffsetOf(fbsql_auth_config_rec, fbsqlEncryptionField),
OR_AUTHCFG, "firebird password encryption method"),

AP_INIT_TAKE1("AuthFIrebirdSaltField", ap_set_string_slot,
(void*) APR_XtOffsetOf(fbsql_auth_config_rec, fbsqlSaltField),
OR_AUTHCFG, "firebird salfe field name within table"),

AP_INIT_FLAG("AuthFirebirdAuthoritative", ap_set_flag_slot,
(void *) APR_XtOffsetOf(fbsql_auth_config_rec, fbsqlAuthoritative),
OR_AUTHCFG, "firebird lookup is authoritative if On"),

AP_INIT_FLAG("AuthFirebirdNoPasswd", ap_set_flag_slot,
(void *) APR_XtOffsetOf(fbsql_auth_config_rec, fbsqlNoPasswd),
OR_AUTHCFG, "If On, only check if user exists; ignore password"),

AP_INIT_FLAG("AuthFirebirdEnable", ap_set_flag_slot,
(void *) APR_XtOffsetOf(fbsql_auth_config_rec, fbsqlEnable),
OR_AUTHCFG, "enable firebird authorization"),

AP_INIT_TAKE1("AuthFirebirdUserCondition", ap_set_string_slot,
(void *) APR_XtOffsetOf(fbsql_auth_config_rec, fbsqlUserCondition),
OR_AUTHCFG, "condition to add to user where-clause"),

AP_INIT_TAKE1("AuthFirebirdGroupCondition", ap_set_string_slot,
(void *) APR_XtOffsetOf(fbsql_auth_config_rec, fbsqlGroupCondition),
OR_AUTHCFG, "condition to add to group where-clause"),

{ NULL }
};
#else
static
command_rec fbsql_auth_cmds[] = {
{ "AuthFirebirdHost", ap_set_string_slot,
(void*)XtOffsetOf(fbsql_auth_config_rec, fbsqlhost),
OR_AUTHCFG, TAKE1, "firebird server host name" },


{ "AuthFirebirdPort", ap_set_string_slot,
(void*)XtOffsetOf(fbsql_auth_config_rec, fbsqlport),
OR_AUTHCFG, TAKE1, "firebird server port number" },

{ "AuthFirebirdUser", ap_set_string_slot,
(void*)XtOffsetOf(fbsql_auth_config_rec, fbsqluser),
OR_AUTHCFG, TAKE1, "firbird server user name" },

{ "AuthFirebirdPassword", ap_set_string_slot,
(void*)XtOffsetOf(fbsql_auth_config_rec, fbsqlpasswd),
OR_AUTHCFG, TAKE1, "firebird server user password" },

{ "AuthFirebirdDB", ap_set_string_slot,
(void*)XtOffsetOf(fbsql_auth_config_rec, fbsqlDB),
OR_AUTHCFG, TAKE1, "firebird database name" },

{ "AuthFirebirdUserTable", ap_set_string_slot,
(void*)XtOffsetOf(fbsql_auth_config_rec, fbsqlpwtable),
OR_AUTHCFG, TAKE1, "firebird user table name" },

{ "AuthFirebirdGroupTable", ap_set_string_slot,
(void*)XtOffsetOf(fbsql_auth_config_rec, fbsqlgrptable),
OR_AUTHCFG, TAKE1, "firebird group table name" },

{ "AuthFirebirdNameField", ap_set_string_slot,
(void*)XtOffsetOf(fbsql_auth_config_rec, fbsqlNameField),
OR_AUTHCFG, TAKE1, "firebird User ID field name within User table" },

{ "AuthFirebirdGroupField", ap_set_string_slot,
(void*)XtOffsetOf(fbsql_auth_config_rec, fbsqlGroupField),
OR_AUTHCFG, TAKE1, "firebird Group field name within table" },

{ "AuthFirebirdGroupUserNameField", ap_set_string_slot,
(void*)XtOffsetOf(fbsql_auth_config_rec, fbsqlGroupUserNameField),
OR_AUTHCFG, TAKE1, "firebird User ID field name within Group table" },

{ "AuthFirebirdPasswordField", ap_set_string_slot,
(void*)XtOffsetOf(fbsql_auth_config_rec, fbsqlPasswordField),
OR_AUTHCFG, TAKE1, "firebird Password field name within table" },

{ "AuthFirebirdPwEncryption", ap_set_string_slot,
(void *)XtOffsetOf(fbsql_auth_config_rec, fbsqlEncryptionField),
OR_AUTHCFG, TAKE1, "firebird password encryption method" },

{ "AuthFirebirdSaltField", ap_set_string_slot,
(void *)XtOffsetOf(fbsql_auth_config_rec, fbsqlSaltField),
OR_AUTHCFG, TAKE1, "firebird salt field name within table" },

{ "AuthFirebirdAuthoritative", ap_set_flag_slot,
(void*)XtOffsetOf(fbsql_auth_config_rec, fbsqlAuthoritative),
OR_AUTHCFG, FLAG, "firebird lookup is authoritative if On" },

{ "AuthFirebirdNoPasswd", ap_set_flag_slot,
(void*)XtOffsetOf(fbsql_auth_config_rec, fbsqlNoPasswd),
OR_AUTHCFG, FLAG, "If On, only check if user exists; ignore
password" },

{ "AuthFirebirdEnable", ap_set_flag_slot,
(void *)XtOffsetOf(fbsql_auth_config_rec, fbsqlEnable),
OR_AUTHCFG, FLAG, "enable firebird authorization"},

{ "AuthFirebirdUserCondition", ap_set_string_slot,
(void*)XtOffsetOf(fbsql_auth_config_rec, fbsqlUserCondition),
OR_AUTHCFG, TAKE1, "condition to add to user where-clause" },

{ "AuthFirebirdGroupCondition", ap_set_string_slot,
(void*)XtOffsetOf(fbsql_auth_config_rec, fbsqlGroupCondition),
OR_AUTHCFG, TAKE1, "condition to add to group where-clause" },


{ NULL }
};
#endif

module fbsql_auth_module;

/*
* Convert binary to hex
*/
static char * bin2hex (POOL *pool, const char * bin, short len) {
int i = 0;
static char hexchars [] = {'0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
char * buffer = PCALLOC(pool, len * 2 + 1);
for (i = 0; i < len; i++) {
buffer[i*2] = hexchars[bin[i] >> 4 & 0x0f];
buffer[i*2+1] = hexchars[bin[i] & 0x0f];
}
buffer[len * 2] = '\0';
return buffer;
}

/*
* Convert hexadecimal characters to character
*/

static char hex2chr(char * in) {
static const char * data = "0123456789ABCDEF";
const char * offset;
char val = 0;
int i;

for (i = 0; i < 2; i++) {
val <<= 4;
offset = strchr(data, toupper(in[i]));
if (offset == NULL)
return '\0';
val += offset - data;
}
return val;
}

/* checks md5 hashed passwords */
static short pw_md5(POOL * pool, const char * real_pw, const char *
sent_pw, const char * salt) {
return strcmp(real_pw,ap_md5(pool,(const unsigned char *)sent_pw)) == 0;
}

/* Checks crypt()ed passwords */
static short pw_crypted(POOL * pool, const char * real_pw, const char
* sent_pw, const char * salt) {
/* salt will contain either the salt or real_pw */
return strcmp(real_pw, crypt(sent_pw, salt)) == 0;
}

/* checks SHA1 passwords */
static short pw_sha1(POOL * pool, const char * real_pw, const char *
sent_pw, const char * salt) {
char *scrambled_sent_pw, *buffer = PCALLOC(pool, 128);
short enc_len = 0;
#ifdef APACHE2
apr_sha1_base64(sent_pw, strlen(sent_pw), buffer);
buffer += 5; /* go past {SHA1} eyecatcher */
scrambled_sent_pw = PCALLOC(pool, apr_base64_decode_len(buffer) + 1);
enc_len = apr_base64_decode(scrambled_sent_pw, buffer);
#else
ap_sha1_base64(sent_pw, strlen(sent_pw), buffer);
buffer += 5; /* go past {SHA1} eyecatcher */
scrambled_sent_pw = PCALLOC(pool, ap_base64decode_len(buffer) + 1);
enc_len = ap_base64decode(scrambled_sent_pw, buffer);
#endif
scrambled_sent_pw[enc_len] = '\0';
return strcasecmp(bin2hex(pool, scrambled_sent_pw, enc_len),
real_pw) == 0;
}

/* checks plain text passwords */
static short pw_plain(POOL * pool, const char * real_pw, const char *
sent_pw, const char * salt) {
return strcmp(real_pw, sent_pw) == 0;
}

static char * str_format(request_rec * r, char * input) {
char * output = input, *pos, *start = input, *data, *temp;
int i, len, found;

while ((pos = strchr(start, '%')) != NULL) {
len = pos - output; /* Length of string to copy */
pos++; /* Point at formatting character */
found = 0;
for (i = 0; i < sizeof(formats)/sizeof(formats[0]); i++) {
if (*pos == formats[i].pattern) {
pos++; /* Data following format char */
data = formats[i].func(r, &pos);
temp = PCALLOC(r->pool, len + strlen(data) + strlen(pos) + 1);
if (temp == NULL) {
LOG_ERROR_1(APLOG_ERR|APLOG_NOERRNO, 0, r, "Firebird ERROR:
Insufficient storage to expand format %c", *(pos-1));
return input;
}
strncpy(temp, output, len);
strcat (temp, data);
start = temp + strlen(temp);
strcat (temp, pos);
output = temp;
found = 1;
break;
}
}
if (!found) {
LOG_ERROR_2(APLOG_ERR|APLOG_NOERRNO, 0, r, "Firebird ERROR:
Invalid formatting character at position %d: \"%s\"",
pos-output, output);
return input;
}
}
return output;
}

static char * format_remote_host(request_rec * r, char ** parm) {
#ifdef APACHE2
return ap_escape_logitem(r->pool, ap_get_remote_host(r->connection,
r->per_dir_config, REMOTE_NAME, NULL));
#else
return ap_escape_logitem(r->pool, ap_get_remote_host(r->connection,
r->per_dir_config, REMOTE_NAME));
#endif
}

static char * format_remote_ip(request_rec * r, char ** parm) {
return r->connection->remote_ip;
}

static char * format_filename(request_rec * r, char ** parm) {
return ap_escape_logitem(r->pool, r->filename);
}

static char * format_server_name(request_rec * r, char ** parm) {
return ap_escape_logitem(r->pool, ap_get_server_name(r));
}

static char * format_server_hostname(request_rec * r, char ** parm) {
return ap_escape_logitem(r->pool, r->server->server_hostname);
}

static char * format_protocol(request_rec * r, char ** parm) {
return ap_escape_logitem(r->pool, r->protocol);
}

static char * format_method(request_rec * r, char ** parm) {
return ap_escape_logitem(r->pool, r->method);
}

static char * format_args(request_rec * r, char ** parm) {
if (r->args)
return ap_escape_logitem(r->pool, r->args);
else
return "";
}

static char * format_request(request_rec * r, char ** parm) {
return ap_escape_logitem(r->pool,
(r->parsed_uri.password) ? STRCAT(r->pool, r->method, " ",
#ifdef APACHE2
apr_uri_unparse(r->pool, &r->parsed_uri, 0),
#else
ap_unparse_uri_components(r->pool, &r->parsed_uri, 0),
#endif
r->assbackwards ? NULL : " ", r->protocol, NULL) :
r->the_request);
}

static char * format_uri(request_rec * r, char ** parm) {
return ap_escape_logitem(r->pool, r->uri);
}

static char * format_percent(request_rec * r, char ** parm) {
return "%";
}

static char * format_cookie(request_rec * r, char ** parm) {
const char * cookies;
char * start = *parm;
char delim;
char * end;
char * cookiename;
const char * cookiestart, *cookieend;
char * cookieval;
int len;

delim = *start;
end = strchr(++start, delim);
if (end == NULL) {
LOG_ERROR_1(APLOG_NOERRNO | APLOG_ERR, 0, r, "No ending delimiter
found for cookie starting at %s", *parm -2);
return "";
}
*parm = end + 1; /* Point past end of data */
if ((cookies = TABLE_GET(r->headers_in, "Cookie")) == NULL) {
LOG_ERROR(APLOG_NOERRNO|APLOG_ERR, 0, r, "No cookies found");
return "";
}
len = end - start;
cookiename = PCALLOC(r->pool,len + 2);
strncpy(cookiename, start, len);
strcat(cookiename, "=");
len++;

cookiestart = cookies;
while (cookiestart != NULL) {
while (*cookiestart != '\0' && ISSPACE(*cookiestart))
cookiestart++;
if (strncmp(cookiestart, cookiename, len) == 0) {
cookiestart += len;
cookieend = strchr(cookiestart, ';'); /* Search for end of
cookie data */
if (cookieend == NULL) /* NULL means this was the last cookie */
cookieend = cookiestart + strlen(cookiestart);
len = cookieend - cookiestart;
cookieval = PSTRNDUP(r->pool, cookiestart, len);

start = cookieval;
while ((start = strchr(start, '%')) != NULL) { /* Convert any
hex data to char */
*start = hex2chr(start+1);
strcpy (start+1, start+3);
start++;
}

return cookieval;
}
cookiestart = strchr(cookiestart, ';');
if (cookiestart != NULL)
cookiestart++;
}
return "";
}


/*
* Fetch and return password string from database for named user.
* If we are in NoPasswd mode, returns user name instead.
* If user or password not found, returns NULL
*/

static char * get_fbsql_pw(request_rec *r, char *user,
fbsql_auth_config_rec *m, const char *salt_column, const char ** psalt) {
IBASE_RES *result;
char *pw = NULL; /* password retrieved */
char *sql_safe_user = NULL;
int ulen;
int size_of_query =MAX_STRING_LEN*sizeof(char);
char *query =(char*)PCALLOC(r->pool,size_of_query);


if(!open_db_handle(r,m)) {
return NULL; /* failure reason already logged */
}

/*
* If we are not checking for passwords, there may not be a password
field
* in the database. We just look up the name field value in this case
* since it is guaranteed to exist.
*/
if (m->fbsqlNoPasswd) {
m->fbsqlPasswordField = m->fbsqlNameField;
}

ulen = strlen(user);
sql_safe_user = PCALLOC(r->pool, ulen*2+1);
fbsql_escape_string(sql_safe_user,user,ulen);

if (salt_column) { /* If a salt was requested */
if (m->fbsqlUserCondition) {
SNPRINTF(query,size_of_query-1,"SELECT %s,%s FROM %s WHERE
%s='%s' AND %s",
m->fbsqlPasswordField,salt_column, m->fbsqlpwtable,
m->fbsqlNameField, sql_safe_user, str_format(r, m->fbsqlUserCondition));
} else {
SNPRINTF(query,size_of_query-1,"SELECT %s,%s FROM %s WHERE %s='%s'",
m->fbsqlPasswordField,salt_column, m->fbsqlpwtable,
m->fbsqlNameField, sql_safe_user);
}
} else {
if (m->fbsqlUserCondition) {
SNPRINTF(query,size_of_query-1,"SELECT %s FROM %s WHERE %s='%s'
AND %s",
m->fbsqlPasswordField, m->fbsqlpwtable,
m->fbsqlNameField, sql_safe_user, str_format(r, m->fbsqlUserCondition));
} else {
SNPRINTF(query,size_of_query-1,"SELECT %s FROM %s WHERE %s='%s'",
m->fbsqlPasswordField, m->fbsqlpwtable,
m->fbsqlNameField, sql_safe_user);
LOG_ERROR_2(APLOG_ERR,0,r,"Query= %s,%d",query,size_of_query-1);
}
}
result = fbsql_query(r,&connection,query);
LOG_ERROR(APLOG_ERR, 0, r,"Den day 1");
if ( result == NULL) {
LOG_ERROR_2(APLOG_ERR, 0, r, "Firebird ERROR: %s: %s",
fbsql_error(r->pool,&connection), r->uri);
return NULL;
}
if ((result!= NULL) && (fbsql_num_rows(result) >= 1)) {
LOG_ERROR(APLOG_ERR, 0, r,"Den day 2");
IBASE_ROW data = fbsql_fetch_row(r->pool,result,0);
if (data[0]) {
int len = strlen(data[0]);
pw = (char *) PCALLOC(r->pool, len + 1);
memcpy(pw, data[0], len);
} else { /* no password in firebird table returns NULL */
/* this should never happen, but test for it anyhow */
LOG_ERROR_2(APLOG_NOERRNO|APLOG_ERR, 0, r, "Firebird user %s has
no valid password: %s", user, r->uri);
fbsql_free_result(result);
return NULL;
}

if (salt_column) {
if (data[1]) {
*psalt = (char *) PSTRDUP(r->pool, data[1]);
} else { /* no alt in firebird table returns NULL */
*psalt = 0;
}
}
}

if (result) fbsql_free_result(result);

return pw;
}

/*
* get list of groups from database. Returns array of pointers to strings
* the last of which is NULL. returns NULL pointer if user is not member
* of any groups.
*/
static char ** get_fbsql_groups(request_rec *r, char *user,
fbsql_auth_config_rec *m){
IBASE_RES *result;
char **list = NULL;
int size_of_query = MAX_STRING_LEN*sizeof(char);
char * query = (char*)PCALLOC(r->pool,size_of_query);
char *sql_safe_user;
int ulen;

if(!open_db_handle(r,m)) {
return NULL; /* failure reason already logged */
}

ulen = strlen(user);
sql_safe_user = PCALLOC(r->pool,ulen*2+1);
fbsql_escape_string(sql_safe_user,user,ulen);

if (m->fbsqlGroupUserNameField == NULL)
m->fbsqlGroupUserNameField = m->fbsqlNameField;
if (m->fbsqlGroupCondition) {
SNPRINTF(query,size_of_query-1,"SELECT %s FROM %s WHERE %s='%s'
AND %s",
m->fbsqlGroupField, m->fbsqlgrptable,
m->fbsqlGroupUserNameField, sql_safe_user, str_format(r,
m->fbsqlGroupCondition));
} else {
SNPRINTF(query,size_of_query-1,"SELECT %s FROM %s WHERE %s='%s'",
m->fbsqlGroupField, m->fbsqlgrptable,
m->fbsqlGroupUserNameField, sql_safe_user);
}
result=fbsql_query(r,&connection,query);

if ( result == NULL) {
LOG_ERROR_2(APLOG_ERR, 0, r, "Firebird error %s: %s",
fbsql_error(r->pool,&connection),r->uri);
return NULL;
}

if (result && (fbsql_num_rows(result) > 0)) {
int i = fbsql_num_rows(result);
list = (char **) PCALLOC(r->pool, sizeof(char *) * (i+1));
list[i] = NULL; /* last element in array is NULL */
while (i--) { /* populate the array elements */
IBASE_ROW data = fbsql_fetch_row(r->pool,result,i-1);
if (data[0])
list[i] = (char *) PSTRDUP(r->pool,data[0]);
else
list[i] = ""; /* if no data, make it empty, not NULL */
}
}

if (result) fbsql_free_result(result);
return list;
}

/*
* callback from Apache to do the authentication of the user to his
* password.
*/
static int fbsql_authenticate_basic_user(request_rec *r)
{
int passwords_match = 0; /* Assume no match */
encryption * enc_data = 0;
int i = 0;

char *user;
fbsql_auth_config_rec *sec =
(fbsql_auth_config_rec*)ap_get_module_config
(r->per_dir_config,&fbsql_auth_module);

const char *sent_pw, *real_pw, *salt = 0, *salt_column = 0;
int res;

if (!sec->fbsqlEnable) /* no firbird authorization */
return DECLINED;

if ((res = ap_get_basic_auth_pw(r,&sent_pw)) != OK) return res;

/* Determine the encryption method */
if (sec->fbsqlEncryptionField) {
for (i = 0; i < sizeof(encryptions) / sizeof(encryptions[0]); i++) {
if (strcasecmp(sec->fbsqlEncryptionField, encryptions[i].string)
== 0) {
enc_data = &(encryptions[i]);
break;
}
}
if (!enc_data) { /* Entry was not found in the list */
LOG_ERROR_1(APLOG_NOERRNO|APLOG_ERR, 0, r, "firebird invalid
encryption method %s", sec->fbsqlEncryptionField);
ap_note_basic_auth_failure(r);
return NOT_AUTHORIZED;
}
}
else
enc_data = &encryptions[0];

#ifdef APACHE2
user = r->user;
#else
user = r->connection->user;
#endif

if (enc_data->salt_status == NO_SALT || !sec->fbsqlSaltField)
salt = salt_column = 0;
else { /* Parse the fbsqlSaltField */
short salt_length = strlen(sec->fbsqlSaltField);

if (strcasecmp(sec->fbsqlSaltField, "<>") == 0) { /* Salt against
self */
salt = salt_column = 0;
} else if (sec->fbsqlSaltField[0] == '<' &&
sec->fbsqlSaltField[salt_length-1] == '>') {
salt = PSTRNDUP(r->pool, sec->fbsqlSaltField+1, salt_length - 2);
salt_column = 0;
} else {
salt = 0;
salt_column = sec->fbsqlSaltField;
}
}

if (enc_data->salt_status == SALT_REQUIRED && !salt && !salt_column) {
LOG_ERROR_1(APLOG_NOERRNO | APLOG_ERR, 0, r, "Firebird Salt field
not specified for encryption %s", sec->fbsqlEncryptionField);
return DECLINED;
}

real_pw = get_fbsql_pw(r, user, sec, salt_column, &salt ); /* Get a
salt if one was specified */

//Neu mat khau la NULL
if(!real_pw)
{
/* user not found in database */
LOG_ERROR_2(APLOG_NOERRNO|APLOG_ERR, 0, r, "Firebird user %s not
found: %s", user, r->uri);
ap_note_basic_auth_failure (r);
if (!sec->fbsqlAuthoritative)
return DECLINED; /* let other schemes find user */
else
return NOT_AUTHORIZED;
}

if (!salt)
salt = real_pw;

/* if we don't require password, just return ok since they exist */
if (sec->fbsqlNoPasswd) {
return OK;
}

passwords_match = enc_data->func(r->pool, real_pw, sent_pw, salt);

if(passwords_match) {
return OK;
} else {
LOG_ERROR_2(APLOG_NOERRNO|APLOG_ERR, 0, r, "user %s: password
mismatch: %s", user, r->uri);
ap_note_basic_auth_failure (r);
return NOT_AUTHORIZED;
}
}

/*
* check if user is member of at least one of the necessary group(s)
*/
static int fbsql_check_auth(request_rec *r)
{
fbsql_auth_config_rec *sec =
(fbsql_auth_config_rec *)ap_get_module_config(r->per_dir_config,
&fbsql_auth_module);
#ifdef APACHE2
char *user = r->user;
#else
char *user = r->connection->user;
#endif
int method = r->method_number;

#ifdef APACHE2
const apr_array_header_t *reqs_arr = ap_requires(r);
#else
const array_header *reqs_arr = ap_requires(r);
#endif

require_line *reqs = reqs_arr ? (require_line *)reqs_arr->elts : NULL;

register int x;
char **groups = NULL;

if (!sec->fbsqlGroupField) return DECLINED; /* not doing groups here */
if (!reqs_arr) return DECLINED; /* no "require" line in access config */

/* if the group table is not specified, use the same as for password */
if (!sec->fbsqlgrptable) sec->fbsqlgrptable = sec->fbsqlpwtable;

for(x = 0; x < reqs_arr->nelts; x++) {
const char *t, *want;

if (!(reqs[x].method_mask & (1 << method))) continue;

t = reqs[x].requirement;
want = ap_getword_conf(r->pool, &t);

if (!strcmp(want, "valid-user")) {
return OK;
}

if (!strcmp(want, "user")) {
while (t[0]) {
want = ap_getword_conf(r->pool, &t);
if (strcmp(user, want) == 0) {
return OK;
}
}
}
else if(!strcmp(want,"group")) {
/* check for list of groups from database only first time thru */
if (groups || (groups = get_fbsql_groups(r, user, sec))) {

/* loop through list of groups specified in htaccess file */
while(t[0]) {
int i = 0;
want = ap_getword_conf(r->pool, &t);
/* compare against each group to which this user belongs */
while(groups[i]) { /* last element is NULL */
if(!strcmp(groups[i],want)) {
return OK; /* we found the user! */
}
++i;
}
}
}
}
}

if (sec->fbsqlAuthoritative)
{
LOG_ERROR_2(APLOG_NOERRNO|APLOG_ERR, 0, r,
"firebird user %s failed authorization to access %s",user,r->uri);
ap_note_basic_auth_failure(r);
return NOT_AUTHORIZED;
}

//Return DECLINED so that the Apache core will keep looking for
//other modules to handle this request. This effectively makes
//this module completely transparent.
return DECLINED;
}

#ifdef APACHE2
static void register_hooks(POOL *p)
{
ap_hook_check_user_id(fbsql_authenticate_basic_user, NULL, NULL,
APR_HOOK_MIDDLE);
ap_hook_auth_checker(fbsql_check_auth, NULL, NULL, APR_HOOK_MIDDLE);
}
#endif

#ifdef APACHE2
module AP_MODULE_DECLARE_DATA fbsql_auth_module =
{
STANDARD20_MODULE_STUFF,
create_fbsql_auth_dir_config, /* dir config creater */
NULL, /* dir merger --- default is to
override */
NULL, /* server config */
NULL, /* merge server config */
fbsql_auth_cmds, /* command apr_table_t */
register_hooks /* register hooks */
};
#else
module fbsql_auth_module = {
STANDARD_MODULE_STUFF,
NULL, /* initializer */
create_fbsql_auth_dir_config, /* dir config creater */
NULL, /* dir merger --- default is to override */
NULL, /* server config */
NULL, /* merge server config */
fbsql_auth_cmds, /* command table */
NULL, /* handlers */
NULL, /* filename translation */
fbsql_authenticate_basic_user, /* check_user_id */
fbsql_check_auth, /* check auth */
NULL, /* check access */
NULL, /* type_checker */
NULL, /* fixups */
NULL, /* logger */
NULL, /* header parser */
NULL, /* child_init */
child_exit, /* child_exit */
NULL /* post read-request */
};
#endif

/*
* Escape special characters. "len" is "from" size.
* "to" must point to 2*len+1 chars.
*/
void fbsql_escape_string (char*to,const char *from,int len){
char*s = to;
int i = 0;
while(*from && i<=len)
{
switch(*from)
{
case '\'':
//Note that no break here!
*to = *from,to++;
default:
*to = *from;
}
to++;from++;i++;
}
*to = 0;
to = s;
}

/**
* Thuc thi cau lenh SQL
*/
IBASE_RES *fbsql_query(request_rec*r,fbsql_connection*fbconn, const
char *query)
{
IBASE_RES *result = NULL;
int size_of_query_info = 1*sizeof(char);
char * query_info = (char*)PCALLOC(r->pool,size_of_query_info);
int size_of_info_buffer = 18*sizeof(char);
char * info_buffer = (char*)PCALLOC(r->pool,size_of_info_buffer);
long query_type;
char * que = PSTRDUP(r->pool,query);
query_info[0] = isc_info_sql_stmt_type;
isc_tr_handle tr_handle = 0L;
isc_stmt_handle query_handle = NULL;
if(fbconn->handle == 0L) return NULL;
if(isc_start_transaction(fbconn->status_vector,&tr_handle,1,&(fbconn->handle),0,NULL))
return NULL;
if
(isc_dsql_allocate_statement(fbconn->status_vector,&(fbconn->handle),&query_handle))
{
isc_rollback_transaction(fbconn->status_vector,&tr_handle);
return NULL;
}
if
(isc_dsql_prepare(fbconn->status_vector,&tr_handle,&query_handle,0,que,1,NULL)){
isc_rollback_transaction(fbconn->status_vector,&tr_handle);
return NULL;
}
if
(!isc_dsql_sql_info(fbconn->status_vector,&query_handle,size_of_query_info,query_info,size_of_info_buffer,info_buffer))
{
short l;
l = (short)isc_vax_integer((char ISC_FAR *) info_buffer + 1, 2);
query_type =isc_vax_integer((char ISC_FAR *) info_buffer + 3, l);
}
// Find out what kind of query is to be executed
if (query_type == isc_info_sql_stmt_select || query_type ==
isc_info_sql_stmt_select_for_upd)
{
XSQLDA *osqlda = NULL;
long fetch_stat;
int i;
//Select, need to allocate output sqlda and and prepare it for use.
osqlda =(XSQLDA*)PCALLOC(r->pool,XSQLDA_LENGTH(0));
osqlda->sqln = 0;
osqlda->version = SQLDA_VERSION1;
if(isc_dsql_describe(fbconn->status_vector,&query_handle,1,osqlda))
{
isc_rollback_transaction(fbconn->status_vector,&tr_handle);
return NULL;
}//if
if (osqlda->sqld)
{
short n = osqlda->sqld;
osqlda = (XSQLDA*)PCALLOC(r->pool,XSQLDA_LENGTH(n));
osqlda->sqln = n;
osqlda->version = SQLDA_VERSION1;
if(isc_dsql_describe(fbconn->status_vector,&query_handle,1,osqlda))
{
isc_rollback_transaction(fbconn->status_vector,&tr_handle);
return NULL;
}//if
}//if
for (i = 0; i < osqlda->sqld; i++)
{
int coltype;
osqlda->sqlvar[i].sqlind = (short*)PCALLOC(r->pool,sizeof(short));
coltype = osqlda->sqlvar[i].sqltype & ~1;
switch(coltype)
{
case SQL_TEXT:
osqlda->sqlvar[i].sqldata =
(char*)PCALLOC(r->pool,sizeof(char)*(osqlda->sqlvar[i].sqllen));
break;
case SQL_VARYING:
osqlda->sqlvar[i].sqltype = SQL_TEXT;
osqlda->sqlvar[i].sqldata = (char
*)PCALLOC(r->pool,sizeof(char)*(osqlda->sqlvar[i].sqllen+2));
break;
case SQL_SHORT:
osqlda->sqlvar[i].sqldata = (char *) PCALLOC(r->pool,sizeof(short));
break;
case SQL_LONG:
osqlda->sqlvar[i].sqldata = (char *) PCALLOC(r->pool,sizeof(long));
break;
case SQL_FLOAT:
osqlda->sqlvar[i].sqldata = (char *) PCALLOC(r->pool,sizeof(float));
break;
case SQL_DOUBLE:
osqlda->sqlvar[i].sqldata = (char *) PCALLOC(r->pool,sizeof(double));
break;
case SQL_DATE:
case SQL_BLOB:
case SQL_ARRAY:
osqlda->sqlvar[i].sqldata = (char *)
PCALLOC(r->pool,sizeof(ISC_QUAD));
break;
}//switch
}//for

if
(isc_dsql_execute(fbconn->status_vector,&tr_handle,&query_handle,1,NULL))
{
isc_rollback_transaction(fbconn->status_vector,&tr_handle);
return NULL;
}//if
result = (IBASE_RES*)PCALLOC(r->pool,sizeof(IBASE_RES));
if(result == NULL )
{
isc_rollback_transaction(fbconn->status_vector,&tr_handle);
return NULL;
}//if
result->nRows = 0;
result->nCols = osqlda->sqld;
result->items = NULL;
while ((fetch_stat =
isc_dsql_fetch(fbconn->status_vector,&query_handle,1,osqlda)) == 0)
{
int i;
char*buf = (char*)PCALLOC(r->pool,MAX_SIZE*sizeof(char));
XSQLVAR *var = osqlda->sqlvar;
if(!result->nRows)
{
result->items =
(char**)PCALLOC(r->pool,1*osqlda->sqld*sizeof(char*));
}//if
else
{
result->items =
(char**)PCALLOC(r->pool,((result->nRows+1)*osqlda->sqld*sizeof(char*)));
}//else
for(i=0;i<osqlda->sqld; i++, var++)
{
if(*var->sqlind==-1)
buf[0]=0; // NULL data
else
switch(var->sqltype & ~1)
{
case SQL_TEXT:
strncpy(buf,(char*)var->sqldata,var->sqllen);
buf[var->sqllen]=0;
break;
case SQL_LONG:
sprintf(buf,"%ld",*(long*)(var->sqldata));
break;
case SQL_SHORT:
sprintf(buf,"%d",*(short*)(var->sqldata));
break;

default:
sprintf(buf,"Unknown SQL type\n");
buf[0]=0;
break;
}//switch
ssprtrim(buf," ");
sql_val(result,result->nRows,i) = PSTRDUP(r->pool,buf);
}//for
result->nRows++;
}//while
if (fetch_stat != 100L)
{
isc_rollback_transaction(fbconn->status_vector,&tr_handle);
return NULL;
}//if
if (isc_dsql_free_statement(fbconn->status_vector,&query_handle,
DSQL_close))
{
isc_rollback_transaction(fbconn->status_vector,&tr_handle);
return NULL;
}//if
}//if
else
{
// Not select
if
(isc_dsql_execute(fbconn->status_vector,&tr_handle,&query_handle,1,NULL))
{
//Neu thuc thi bi loi thi rollback transaction
isc_rollback_transaction(fbconn->status_vector,&tr_handle);
//Tra ve ket qua la NULL.
return NULL;
}//if
else
{
//Thu thi tot. Tra ve ket qua la rong.
empty_res.nRows = 0;
empty_res.nCols = 0;
empty_res.items = NULL;
result = &empty_res;
}//else
}//else

//commit the transaction.
if (isc_commit_transaction(fbconn->status_vector,&tr_handle))
{
//Neu bi loi thi tra ve NULL.
return NULL;
}
//Nguoc lai thi tra ket qua ve.
return result;
}

/*
* Get latest error string.
*/
char *fbsql_error (POOL*pool,fbsql_connection *fbconn)
{
long SQLCODE;
char *msg = (char*)PCALLOC(pool,sizeof(char)*512);
if( msg == 0 ) return NULL;

if(fbconn->status_vector[0] == 1 && fbconn->status_vector[1]>0 )
{
SQLCODE = isc_sqlcode(fbconn->status_vector);
isc_sql_interprete(SQLCODE, msg, 512);
return msg;
}
return NULL;
}

IBASE_ROW fbsql_fetch_row(POOL*pool,IBASE_RES*res,int index)
{

if(res == NULL || index > res->nRows) return NULL;
else
{
int i;
char**row = (char**)PCALLOC(pool,sizeof(char*)*res->nCols);
if(row == 0) return NULL;

for(i=0; i<res->nCols; i++)
{
row[i]= PSTRDUP(pool,sql_val(res,index,i));
}
return row;
}
}

/**
* Tra ve so hang trong ket qua truy van res
*/
int fbsql_num_rows (IBASE_RES *res)
{

if (res == NULL) return -1;

return (res->nRows);
}

/**
* Xoa bo ket qua
* Giai phong vung nho tra ve cho he thong
*/
void fbsql_free_result(IBASE_RES *res)
{
return;//nothing here
}

/**
* Bo di phan du thua phia sau chuoi
* chi giu lai nhung ky tu dung bang
* chieu dai duoc cung cap
*/

char * ssprtrim(char*p, char *delim)
{

int len = strlen(p);
//strchr:Tim vi tri xuat hien dau tien cua ky tu thu len-1 cua p
trong delim.
while ((len > 0) && strchr(delim, p[len - 1] )) {
p[len - 1] = '\0';
len--;
}
return(p);
}