40 RCSID(
"$Id: b1c577895c2adca06b3802aa5722de7f3eed29b1 $")
42 #define LOG_PREFIX "sql - postgresql"
44 #include <freeradius-devel/server/base.h>
45 #include <freeradius-devel/util/debug.h>
50 #include <postgres_ext.h>
56 # define NAMEDATALEN 64
86 {
"03",
"SQL statement not yet complete",
RLM_SQL_OK },
139 return atoi(PQcmdTuples(result));
147 TALLOC_FREE(conn->
row);
151 #if defined(PG_DIAG_SQLSTATE) && defined(PG_DIAG_MESSAGE_PRIMARY)
154 char const *error_code;
155 char const *error_msg;
158 error_code = PQresultErrorField(result, PG_DIAG_SQLSTATE);
164 case PGRES_COMMAND_OK:
165 #ifdef HAVE_PGRES_SINGLE_TUPLE
166 case PGRES_SINGLE_TUPLE:
168 case PGRES_TUPLES_OK:
169 #ifdef HAVE_PGRES_COPY_BOTH
170 case PGRES_COPY_BOTH:
174 error_code =
"00000";
177 case PGRES_EMPTY_QUERY:
178 error_code =
"42000";
181 #ifdef HAVE_PGRES_PIPELINE_SYNC
182 case PGRES_PIPELINE_SYNC:
183 case PGRES_PIPELINE_ABORTED:
184 ERROR(
"libpq reported aborted pipeline");
188 case PGRES_BAD_RESPONSE:
189 case PGRES_NONFATAL_ERROR:
190 case PGRES_FATAL_ERROR:
191 ERROR(
"libpq provided no error code");
198 ERROR(
"Can't classify: %s", error_code);
202 DEBUG2(
"sqlstate %s matched %s: %s (%s)", error_code,
209 error_msg = PQresultErrorField(result, PG_DIAG_MESSAGE_PRIMARY);
210 if (error_msg)
WARN(
"%s", error_msg);
218 ERROR(
"Error occurred, no more information available, rebuild with newer libpq");
225 DEBUG2(
"Socket destructor called, closing socket");
227 if (!conn->
db)
return 0;
244 DEBUG2(
"Connecting using parameters: %s",
inst->db_string);
245 conn->
db = PQconnectdb(
inst->db_string);
247 ERROR(
"Connection failed: Out of memory");
250 if (PQstatus(conn->
db) != CONNECTION_OK) {
251 ERROR(
"Connection failed: %s", PQerrorMessage(conn->
db));
257 DEBUG2(
"Connected to database '%s' on '%s' server version %i, protocol version %i, backend PID %i ",
258 PQdb(conn->
db), PQhost(conn->
db), PQserverVersion(conn->
db), PQprotocolVersion(conn->
db),
259 PQbackendPID(conn->
db));
272 PGresult *tmp_result;
274 ExecStatusType status;
277 ERROR(
"Socket not connected");
285 ERROR(
"Unable to obtain socket: %s", PQerrorMessage(conn->
db));
289 if (!PQsendQuery(conn->
db, query_ctx->
query_str)) {
290 ERROR(
"Failed to send query: %s", PQerrorMessage(conn->
db));
299 while (PQisBusy(conn->
db)) {
320 if (errno == EINTR)
continue;
324 if (!PQconsumeInput(conn->
db)) {
325 ERROR(
"Failed reading input: %s", PQerrorMessage(conn->
db));
338 conn->
result = PQgetResult(conn->
db);
341 while ((tmp_result = PQgetResult(conn->
db)) != NULL)
350 ERROR(
"Failed getting query result: %s", PQerrorMessage(conn->
db));
354 status = PQresultStatus(conn->
result);
359 case PGRES_COMMAND_OK:
370 #ifdef HAVE_PGRES_SINGLE_TUPLE
371 case PGRES_SINGLE_TUPLE:
373 case PGRES_TUPLES_OK:
376 numfields = PQnfields(conn->
result);
380 #ifdef HAVE_PGRES_COPY_BOTH
381 case PGRES_COPY_BOTH:
385 DEBUG2(
"Data transfer started");
391 case PGRES_EMPTY_QUERY:
392 case PGRES_BAD_RESPONSE:
393 case PGRES_NONFATAL_ERROR:
394 case PGRES_FATAL_ERROR:
395 #ifdef HAVE_PGRES_PIPELINE_SYNC
396 case PGRES_PIPELINE_SYNC:
397 case PGRES_PIPELINE_ABORTED:
414 fields = PQnfields(conn->
result);
417 MEM(
names = talloc_array(query_ctx,
char const *, fields));
419 for (i = 0; i < fields; i++)
names[i] = PQfname(conn->
result, i);
432 query_ctx->
row = NULL;
439 records = PQnfields(conn->
result);
442 if ((PQntuples(conn->
result) > 0) && (records > 0)) {
443 conn->
row = talloc_zero_array(conn,
char *, records + 1);
444 for (i = 0; i < records; i++) {
446 conn->
row[i] = talloc_array(conn->
row,
char, len + 1);
450 query_ctx->
row = conn->
row;
462 if (conn->
result != NULL) {
492 p = PQerrorMessage(conn->
db);
493 while ((q = strchr(p,
'\n'))) {
497 if (++i == outlen)
return outlen;
524 if ((
inlen * 2 + 1) > outlen)
return 0;
548 if (
inst->send_application_name) {
557 snprintf(application_name,
sizeof(application_name),
566 if (!strchr(
config->sql_db,
'=')) {
569 if (
config->sql_server[0] !=
'\0') {
570 db_string = talloc_asprintf_append(db_string,
" host='%s'",
config->sql_server);
574 db_string = talloc_asprintf_append(db_string,
" port=%i",
config->sql_port);
577 if (
config->sql_login[0] !=
'\0') {
578 db_string = talloc_asprintf_append(db_string,
" user='%s'",
config->sql_login);
581 if (
config->sql_password[0] !=
'\0') {
582 db_string = talloc_asprintf_append(db_string,
" password='%s'",
config->sql_password);
589 if (
inst->send_application_name) {
590 db_string = talloc_asprintf_append(db_string,
" application_name='%s'", application_name);
601 if ((
config->sql_server[0] !=
'\0') && !strstr(db_string,
"host=")) {
602 db_string = talloc_asprintf_append(db_string,
" host='%s'",
config->sql_server);
605 if (
config->sql_port && !strstr(db_string,
"port=")) {
606 db_string = talloc_asprintf_append(db_string,
" port=%i",
config->sql_port);
609 if ((
config->sql_login[0] !=
'\0') && !strstr(db_string,
"user=")) {
610 db_string = talloc_asprintf_append(db_string,
" user='%s'",
config->sql_login);
613 if ((
config->sql_password[0] !=
'\0') && !strstr(db_string,
"password=")) {
614 db_string = talloc_asprintf_append(db_string,
" password='%s'",
config->sql_password);
621 if (
inst->send_application_name && !strstr(db_string,
"application_name=")) {
622 db_string = talloc_asprintf_append(db_string,
" application_name='%s'", application_name);
625 inst->db_string = db_string;
649 #if defined(WITH_TLS) && (defined(HAVE_PQINITOPENSSL) || defined(HAVE_PQINITSSL))
650 # ifdef HAVE_PQINITOPENSSL
664 .name =
"sql_postgresql",
unlang_action_t
Returned by unlang_op_t calls, determine the next action of the interpreter.
#define CONF_PARSER_TERMINATOR
#define FR_CONF_OFFSET(_name, _struct, _field)
conf_parser_t which parses a single CONF_PAIR, writing the result to a field in a struct
Defines a CONF_PAIR to C data type mapping.
A section grouping multiple CONF_PAIR.
CONF_SECTION * cf_section_find(CONF_SECTION const *cs, char const *name1, char const *name2)
Find a CONF_SECTION with name1 and optionally name2.
char const * cf_section_name2(CONF_SECTION const *cs)
Return the second identifier of a CONF_SECTION.
CONF_SECTION * cf_item_to_section(CONF_ITEM const *ci)
Cast a CONF_ITEM to a CONF_SECTION.
char const * cf_section_name1(CONF_SECTION const *cs)
Return the second identifier of a CONF_SECTION.
#define RADIUSD_VERSION_STRING
static fr_time_delta_t timeout
#define MODULE_MAGIC_INIT
Stop people using different module/library/server versions together.
#define ROPTIONAL(_l_request, _l_global, _fmt,...)
Use different logging functions depending on whether request is NULL or not.
main_config_t const * main_config
Main server configuration.
char const * name
Name of the daemon, usually 'radiusd'.
module_instance_t * mi
Instance of the module being instantiated.
Temporary structure to hold arguments for instantiation calls.
static const conf_parser_t config[]
rlm_rcode_t
Return codes indicating the result of the module call.
static int instantiate(module_inst_ctx_t const *mctx)
Prototypes and functions for the SQL module.
rlm_sql_t const * inst
The rlm_sql instance this connection belongs to.
int sql_state_entries_from_table(fr_trie_t *states, sql_state_entry_t const table[])
Insert the contents of a state table into the state trie.
sql_rcode_t rcode
What should happen if we receive this error.
void * conn
Database specific connection handle.
char const * meaning
Verbose description.
fr_table_num_sorted_t const sql_rcode_table[]
fr_trie_t * sql_state_trie_alloc(TALLOC_CTX *ctx)
Allocate a sql_state trie, and insert the initial set of entries.
rlm_sql_t const * inst
Module instance for this query.
char const * query_str
Query string to run.
sql_rcode_t
Action to take at end of an SQL query.
@ RLM_SQL_QUERY_INVALID
Query syntax error.
@ RLM_SQL_RECONNECT
Stale connection, should reconnect.
@ RLM_SQL_ERROR
General connection/server error.
@ RLM_SQL_NO_MORE_ROWS
No more rows available.
fr_time_delta_t query_timeout
How long to allow queries to run for.
rlm_sql_handle_t * handle
Connection handle this query is being run on.
char const * sql_state
2-5 char error code.
#define RLM_SQL_RCODE_FLAGS_ALT_QUERY
Can distinguish between other errors and those.
sql_state_entry_t const * sql_state_entry_find(fr_trie_t const *states, char const *sql_state)
Lookup an SQL state based on an error code returned from the SQL server or client library.
rlm_sql_row_t row
Row data from the last query.
int sql_state_entries_from_cs(fr_trie_t *states, CONF_SECTION *overrides)
Insert the contents of a CONF_SECTION into the state trie.
sql_rcode_t rcode
Result code.
static sql_rcode_t sql_classify_error(UNUSED PGresult const *result)
static int mod_load(void)
static sql_rcode_t sql_fields(char const **out[], fr_sql_query_t *query_ctx, UNUSED rlm_sql_config_t const *config)
static size_t sql_escape_func(request_t *request, char *out, size_t outlen, char const *in, void *arg)
static sql_state_entry_t sql_state_table[]
These are PostgreSQL specific error codes which are not covered in SQL 2011.
rlm_sql_driver_t rlm_sql_postgresql
static int sql_socket_init(rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t const *config, UNUSED fr_time_delta_t timeout)
static int _sql_socket_destructor(rlm_sql_postgres_conn_t *conn)
static conf_parser_t driver_config[]
static unlang_action_t sql_fetch_row(rlm_rcode_t *p_result, UNUSED int *priority, UNUSED request_t *request, void *uctx)
fr_trie_t * states
sql state trie.
static sql_rcode_t sql_free_result(fr_sql_query_t *query_ctx, UNUSED rlm_sql_config_t const *config)
static int sql_affected_rows(fr_sql_query_t *query_ctx, UNUSED rlm_sql_config_t const *config)
static int affected_rows(PGresult *result)
Return the number of affected rows of the result as an int instead of the string that postgresql prov...
char const * db_string
Text based configuration string.
static int mod_instantiate(module_inst_ctx_t const *mctx)
bool send_application_name
Whether we send the application name to PostgreSQL.
static unlang_action_t sql_query(rlm_rcode_t *p_result, UNUSED int *priority, UNUSED request_t *request, void *uctx)
static size_t sql_error(TALLOC_CTX *ctx, sql_log_entry_t out[], size_t outlen, fr_sql_query_t *query_ctx, UNUSED rlm_sql_config_t const *config)
Retrieves any errors associated with the query context.
static void free_result_row(rlm_sql_postgres_conn_t *conn)
Free the row of the current result that's stored in the conn struct.
PostgreSQL configuration.
CONF_SECTION * conf
Module's instance configuration.
void * data
Module's instance data.
module_instance_t const * parent
Parent module's instance (if any).
PUBLIC int snprintf(char *string, size_t length, char *format, va_alist)
MEM(pair_append_request(&vp, attr_eap_aka_sim_identity) >=0)
eap_aka_sim_process_conf_t * inst
#define fr_time()
Allow us to arbitrarily manipulate time.
size_t strlcpy(char *dst, char const *src, size_t siz)
module_t common
Common fields for all loadable modules.
module_instance_t * driver_submodule
Driver's submodule.
char const * fr_syserror(int num)
Guaranteed to be thread-safe version of strerror.
#define fr_table_str_by_value(_table, _number, _def)
Convert an integer to a string.
char * talloc_typed_strdup(TALLOC_CTX *ctx, char const *p)
Call talloc_strdup, setting the type on the new chunk correctly.
char * talloc_typed_asprintf(TALLOC_CTX *ctx, char const *fmt,...)
Call talloc vasprintf, setting the type on the new chunk correctly.
static const char * names[8]
#define fr_time_delta_wrap(_time)
#define fr_time_delta_ispos(_a)
#define fr_time_delta_to_timeval(_delta)
Convert a delta to a timeval.
static int64_t fr_time_delta_to_sec(fr_time_delta_t delta)
static fr_time_delta_t fr_time_delta_sub(fr_time_delta_t a, fr_time_delta_t b)
#define fr_time_delta_gteq(_a, _b)
#define fr_time_sub(_a, _b)
Subtract one time from another.
A time delta, a difference in time measured in nanoseconds.
static size_t char fr_sbuff_t size_t inlen
static size_t char ** out