40 RCSID(
"$Id: 9bfc51623bb9f7f21f7093a4b11de6ad19c619c8 $")
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");
283 ERROR(
"Unable to obtain socket: %s", PQerrorMessage(conn->
db));
287 if (!PQsendQuery(conn->
db, query)) {
288 ERROR(
"Failed to send query: %s", PQerrorMessage(conn->
db));
297 while (PQisBusy(conn->
db)) {
318 if (errno == EINTR)
continue;
322 if (!PQconsumeInput(conn->
db)) {
323 ERROR(
"Failed reading input: %s", PQerrorMessage(conn->
db));
336 conn->
result = PQgetResult(conn->
db);
339 while ((tmp_result = PQgetResult(conn->
db)) != NULL)
348 ERROR(
"Failed getting query result: %s", PQerrorMessage(conn->
db));
352 status = PQresultStatus(conn->
result);
357 case PGRES_COMMAND_OK:
368 #ifdef HAVE_PGRES_SINGLE_TUPLE
369 case PGRES_SINGLE_TUPLE:
371 case PGRES_TUPLES_OK:
374 numfields = PQnfields(conn->
result);
378 #ifdef HAVE_PGRES_COPY_BOTH
379 case PGRES_COPY_BOTH:
383 DEBUG2(
"Data transfer started");
389 case PGRES_EMPTY_QUERY:
390 case PGRES_BAD_RESPONSE:
391 case PGRES_NONFATAL_ERROR:
392 case PGRES_FATAL_ERROR:
393 #ifdef HAVE_PGRES_PIPELINE_SYNC
394 case PGRES_PIPELINE_SYNC:
395 case PGRES_PIPELINE_ABORTED:
415 fields = PQnfields(conn->
result);
418 MEM(
names = talloc_array(handle,
char const *, fields));
420 for (i = 0; i < fields; i++)
names[i] = PQfname(conn->
result, i);
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);
472 if (conn->
result != NULL) {
502 p = PQerrorMessage(conn->
db);
503 while ((q = strchr(p,
'\n'))) {
507 if (++i == outlen)
return outlen;
534 if ((
inlen * 2 + 1) > outlen)
return 0;
558 if (
inst->send_application_name) {
567 snprintf(application_name,
sizeof(application_name),
576 if (!strchr(
config->sql_db,
'=')) {
579 if (
config->sql_server[0] !=
'\0') {
580 db_string = talloc_asprintf_append(db_string,
" host='%s'",
config->sql_server);
584 db_string = talloc_asprintf_append(db_string,
" port=%i",
config->sql_port);
587 if (
config->sql_login[0] !=
'\0') {
588 db_string = talloc_asprintf_append(db_string,
" user='%s'",
config->sql_login);
591 if (
config->sql_password[0] !=
'\0') {
592 db_string = talloc_asprintf_append(db_string,
" password='%s'",
config->sql_password);
599 if (
inst->send_application_name) {
600 db_string = talloc_asprintf_append(db_string,
" application_name='%s'", application_name);
611 if ((
config->sql_server[0] !=
'\0') && !strstr(db_string,
"host=")) {
612 db_string = talloc_asprintf_append(db_string,
" host='%s'",
config->sql_server);
615 if (
config->sql_port && !strstr(db_string,
"port=")) {
616 db_string = talloc_asprintf_append(db_string,
" port=%i",
config->sql_port);
619 if ((
config->sql_login[0] !=
'\0') && !strstr(db_string,
"user=")) {
620 db_string = talloc_asprintf_append(db_string,
" user='%s'",
config->sql_login);
623 if ((
config->sql_password[0] !=
'\0') && !strstr(db_string,
"password=")) {
624 db_string = talloc_asprintf_append(db_string,
" password='%s'",
config->sql_password);
631 if (
inst->send_application_name && !strstr(db_string,
"application_name=")) {
632 db_string = talloc_asprintf_append(db_string,
" application_name='%s'", application_name);
635 inst->db_string = db_string;
659 #if defined(WITH_TLS) && (defined(HAVE_PQINITOPENSSL) || defined(HAVE_PQINITSSL))
660 # ifdef HAVE_PQINITOPENSSL
674 .name =
"sql_postgresql",
#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
void *_CONST data
Module instance's parsed configuration.
#define MODULE_MAGIC_INIT
Stop people using different module/library/server versions together.
CONF_SECTION *_CONST conf
Module's instance configuration.
dl_module_inst_t const *_CONST parent
Parent module's instance (if any).
#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'.
dl_module_inst_t const * inst
Dynamic loader API handle for the module.
Temporary structure to hold arguments for instantiation calls.
static const conf_parser_t config[]
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.
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.
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.
int sql_state_entries_from_cs(fr_trie_t *states, CONF_SECTION *overrides)
Insert the contents of a CONF_SECTION into the state trie.
rlm_sql_row_t row
Row data from the last query.
static sql_rcode_t sql_classify_error(UNUSED PGresult const *result)
static int mod_load(void)
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.
static size_t sql_error(TALLOC_CTX *ctx, sql_log_entry_t out[], size_t outlen, rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t const *config)
Retrieves any errors associated with the connection handle.
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 sql_rcode_t sql_fetch_row(rlm_sql_row_t *out, rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t const *config)
static conf_parser_t driver_config[]
static int mod_bootstrap(module_inst_ctx_t const *mctx)
static sql_rcode_t sql_free_result(rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t const *config)
fr_trie_t * states
sql state trie.
static sql_rcode_t sql_select_query(rlm_sql_handle_t *handle, rlm_sql_config_t const *config, char const *query)
static int sql_affected_rows(rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t const *config)
static int sql_num_fields(rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t const *config)
static sql_rcode_t sql_query(rlm_sql_handle_t *handle, rlm_sql_config_t const *config, char const *query)
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.
bool send_application_name
Whether we send the application name to PostgreSQL.
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.
static sql_rcode_t sql_fields(char const **out[], rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t const *config)
PostgreSQL configuration.
dl_module_inst_t * dl_inst
Structure containing the module's instance data, configuration, and dl handle.
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