27 RCSID(
"$Id: 2932e61d65e98e34ede0b62bb0ccc1de4028690f $")
29 #include <freeradius-devel/radiusd.h>
30 #include <freeradius-devel/rad_assert.h>
47 #define MAX_DATASTR_LEN 256
67 if (emsgp->severity == CS_SV_INFORM) {
68 INFO(
"rlm_sql_freetds: %s", emsgp->msgstring);
73 if ((cs_config(context, CS_GET, CS_USERDATA, &
this,
sizeof(
this), &len) != CS_SUCCEED) || !
this) {
74 ERROR(
"rlm_sql_freetds: failed retrieving context userdata");
79 if (this->error) TALLOC_FREE(this->error);
81 this->error =
talloc_typed_asprintf(
this,
"client error: severity(%ld), number(%ld), origin(%ld), layer(%ld): %s",
82 (
long)CS_SEVERITY(emsgp->severity), (
long)CS_NUMBER(emsgp->msgnumber),
83 (
long)CS_ORIGIN(emsgp->msgnumber), (
long)CS_LAYER(emsgp->msgnumber),
86 if (emsgp->osstringlen > 0) {
87 this->error = talloc_asprintf_append(this->error,
". os error: number(%ld): %s",
88 (
long)emsgp->osnumber, emsgp->osstring);
103 static CS_RETCODE CS_PUBLIC
csmsg_callback(CS_CONTEXT *context, CS_CLIENTMSG *emsgp)
111 if (emsgp->severity == CS_SV_INFORM) {
112 INFO(
"rlm_sql_freetds: %s", emsgp->msgstring);
117 if ((cs_config(context, CS_GET, CS_USERDATA, &
this,
sizeof(
this), &len) != CS_SUCCEED) || !
this) {
118 ERROR(
"rlm_sql_freetds: failed retrieving context userdata");
123 if (this->error) TALLOC_FREE(this->error);
125 this->error =
talloc_typed_asprintf(
this,
"cs error: severity(%ld), number(%ld), origin(%ld), layer(%ld): %s",
126 (
long)CS_SEVERITY(emsgp->severity), (
long)CS_NUMBER(emsgp->msgnumber),
127 (
long)CS_ORIGIN(emsgp->msgnumber), (
long)CS_LAYER(emsgp->msgnumber),
130 if (emsgp->osstringlen > 0) {
131 this->error = talloc_asprintf_append(this->error,
". os error: number(%ld): %s",
132 (
long)emsgp->osnumber, emsgp->osstring);
155 if ((cs_config(context, CS_GET, CS_USERDATA, &
this,
sizeof(
this), &len) != CS_SUCCEED) || !
this) {
156 ERROR(
"rlm_sql_freetds: failed retrieving context userdata");
164 if (this->established) {
165 INFO(
"rlm_sql_freetds: server msg from \"%s\": severity(%ld), number(%ld), origin(%ld), "
166 "layer(%ld), procedure \"%s\": %s",
167 (msgp->svrnlen > 0) ? msgp->svrname :
"unknown",
168 (
long)msgp->msgnumber, (
long)msgp->severity, (
long)msgp->state, (
long)msgp->line,
169 (msgp->proclen > 0) ? msgp->proc :
"none", msgp->text);
171 if (this->error) TALLOC_FREE(this->error);
174 "origin(%ld), layer(%ld), procedure \"%s\": %s",
175 (msgp->svrnlen > 0) ? msgp->svrname :
"unknown",
176 (
long)msgp->msgnumber, (
long)msgp->severity, (
long)msgp->state,
178 (msgp->proclen > 0) ? msgp->proc :
"none", msgp->text);
196 CS_RETCODE results_ret;
199 if (ct_cmd_alloc(conn->
db, &conn->
command) != CS_SUCCEED) {
200 ERROR(
"rlm_sql_freetds: Unable to allocate command structure (ct_cmd_alloc())");
205 if (ct_command(conn->
command, CS_LANG_CMD, query, CS_NULLTERM, CS_UNUSED) != CS_SUCCEED) {
206 ERROR(
"rlm_sql_freetds: Unable to initialise command structure (ct_command())");
211 if (ct_send(conn->
command) != CS_SUCCEED) {
212 ERROR(
"rlm_sql_freetds: Unable to send command (ct_send())");
225 if ((results_ret = ct_results(conn->
command, &result_type)) == CS_SUCCEED) {
226 if (result_type != CS_CMD_SUCCEED) {
227 if (result_type == CS_ROW_RESULT) {
228 ERROR(
"rlm_sql_freetds: sql_query processed a query returning rows. "
229 "Use sql_select_query instead!");
231 ERROR(
"rlm_sql_freetds: Result failure or unexpected result type from query");
236 switch (results_ret) {
238 ERROR(
"rlm_sql_freetds: Failure retrieving query results");
240 if (ct_cancel(NULL, conn->
command, CS_CANCEL_ALL) == CS_FAIL) {
241 INFO(
"rlm_sql_freetds: Cleaning up");
249 ERROR(
"rlm_sql_freetds: Unexpected return value from ct_results()");
259 if ((results_ret = ct_results(conn->
command, &result_type)) == CS_SUCCEED) {
260 if (result_type != CS_CMD_DONE) {
261 ERROR(
"rlm_sql_freetds: Result failure or unexpected result type from query");
266 switch (results_ret) {
268 ERROR(
"rlm_sql_freetds: Failure retrieving query results");
275 ERROR(
"rlm_sql_freetds: Unexpected return value from ct_results()");
284 results_ret = ct_results(conn->
command, &result_type);
285 switch (results_ret) {
287 ERROR(
"rlm_sql_freetds: Failure retrieving query results");
297 ERROR(
"rlm_sql_freetds: Unexpected return value from ct_results()");
318 if (ct_res_info(conn->
command, CS_NUMDATA, (CS_INT *)&num, CS_UNUSED, NULL) != CS_SUCCEED) {
319 ERROR(
"rlm_sql_freetds: Error retrieving column count");
342 if (ct_res_info(conn->
command, CS_NUMDATA, (CS_INT *)&fields, CS_UNUSED, NULL) != CS_SUCCEED) {
343 ERROR(
"rlm_sql_freetds: sql_fields() Error retrieving column count");
350 MEM(names = talloc_array(handle,
char const *, fields));
352 for (i = 0; i < fields; i++) {
360 if (ct_describe(conn->
command, col, &datafmt) != CS_SUCCEED) {
361 ERROR(
"rlm_sql_freetds: sql_fields() Problems with ct_describe(), column %d", col);
366 if (datafmt.namelen > 0) {
367 MEM(p = talloc_array(names,
char, (
size_t)datafmt.namelen + 1));
368 strlcpy(p, datafmt.name, (
size_t)datafmt.namelen + 1);
397 if (!conn->
error)
return 0;
409 ct_cancel(NULL, conn->
command, CS_CANCEL_ALL);
410 if (ct_cmd_drop(conn->
command) != CS_SUCCEED) {
411 ERROR(
"rlm_sql_freetds: freeing command structure failed");
433 CS_RETCODE results_ret;
435 CS_DATAFMT descriptor;
441 ERROR(
"rlm_sql_freetds: socket not connected");
446 if (ct_cmd_alloc(conn->
db, &conn->
command) != CS_SUCCEED) {
447 ERROR(
"rlm_sql_freetds: unable to allocate command structure (ct_cmd_alloc())");
452 if (ct_command(conn->
command, CS_LANG_CMD, query, CS_NULLTERM, CS_UNUSED) != CS_SUCCEED) {
453 ERROR(
"rlm_sql_freetds: unable to initiate command structure (ct_command()");
458 if (ct_send(conn->
command) != CS_SUCCEED) {
459 ERROR(
"rlm_sql_freetds: unable to send command (ct_send())");
463 results_ret = ct_results(conn->
command, &result_type);
464 switch (results_ret) {
466 switch (result_type) {
481 descriptor.datatype = CS_CHAR_TYPE;
482 descriptor.format = CS_FMT_NULLTERM;
484 descriptor.count = 1;
485 descriptor.locale = NULL;
489 rowdata = talloc_zero_array(conn,
char *, colcount + 1);
490 rowdata[colcount] = NULL;
492 for (i = 0; i < colcount; i++) {
497 if (ct_bind(conn->
command, i + 1, &descriptor, rowdata[i], NULL, NULL) != CS_SUCCEED) {
498 talloc_free(rowdata);
500 ERROR(
"rlm_sql_freetds: ct_bind() failed)");
513 ERROR(
"rlm_sql_freetds: query returned no data");
518 ERROR(
"rlm_sql_freetds: unexpected result type from query");
531 ERROR(
"rlm_sql_freetds: failure retrieving query results");
533 if (ct_cancel(NULL, conn->
command, CS_CANCEL_ALL) == CS_FAIL) {
534 ERROR(
"rlm_sql_freetds: cleaning up");
543 ERROR(
"rlm_sql_freetds: unexpected return value from ct_results()");
556 if (ct_res_info(conn->
command, CS_ROW_COUNT, (CS_INT *)&num, CS_UNUSED, NULL) != CS_SUCCEED) {
557 ERROR(
"rlm_sql_freetds: error retrieving row count");
573 ret = ct_fetch(conn->
command, CS_UNUSED, CS_UNUSED, CS_UNUSED, &count);
579 ERROR(
"rlm_sql_freetds: failure fetching row data");
580 if (ct_cancel(NULL, conn->
command, CS_CANCEL_ALL) == CS_FAIL) {
581 ERROR(
"rlm_sql_freetds: cleaning up");
597 ERROR(
"rlm_sql_freetds: recoverable failure fetching row data");
602 ERROR(
"rlm_sql_freetds: unexpected returncode from ct_fetch");
623 ct_cancel(NULL, conn->
command, CS_CANCEL_ALL);
624 if (ct_cmd_drop(conn->
command) != CS_SUCCEED) {
625 ERROR(
"rlm_sql_freetds: freeing command structure failed");
642 DEBUG2(
"rlm_sql_freetds: socket destructor called, closing socket");
645 ct_cancel(NULL, conn->
command, CS_CANCEL_ALL);
646 if (ct_cmd_drop(conn->
command) != CS_SUCCEED) {
647 ERROR(
"rlm_sql_freetds: freeing command structure failed");
662 if (ct_close(conn->
db, CS_UNUSED) != CS_SUCCEED) {
663 ct_close(conn->
db, CS_FORCE_CLOSE);
666 ct_con_drop(conn->
db);
670 ct_exit(conn->
context, CS_UNUSED);
689 if (cs_ctx_alloc(CS_VERSION_100, &conn->
context) != CS_SUCCEED) {
690 ERROR(
"rlm_sql_freetds: unable to allocate CS context structure (cs_ctx_alloc())");
698 if (ct_init(conn->
context, CS_VERSION_100) != CS_SUCCEED) {
699 ERROR(
"rlm_sql_freetds: unable to initialize Client-Library");
704 if (ct_config(conn->
context, CS_GET, CS_LOGIN_TIMEOUT, (CS_VOID *)&timeout_ms, CS_UNUSED, NULL) != CS_SUCCEED) {
705 ERROR(
"rlm_sql_freetds: Setting connection timeout failed");
713 if (cs_config(conn->
context, CS_SET, CS_MESSAGE_CB, (CS_VOID *)
csmsg_callback, CS_UNUSED, NULL) != CS_SUCCEED) {
714 ERROR(
"rlm_sql_freetds: unable to install CS Library error callback");
719 if (cs_config(conn->
context, CS_SET, CS_USERDATA,
720 (CS_VOID *)&handle->
conn,
sizeof(handle->
conn), NULL) != CS_SUCCEED) {
721 ERROR(
"rlm_sql_freetds: unable to set userdata pointer");
727 ERROR(
"rlm_sql_freetds: unable to install client message callback");
733 ERROR(
"rlm_sql_freetds: unable to install server message callback");
741 if (ct_con_alloc(conn->
context, &conn->
db) != CS_SUCCEED) {
742 ERROR(
"rlm_sql_freetds: unable to allocate db structure");
751 CS_VOID *login, *password;
755 memcpy(&login, &config->
sql_login,
sizeof(login));
756 if (ct_con_props(conn->
db, CS_SET, CS_USERNAME, login, strlen(config->
sql_login), NULL) != CS_SUCCEED) {
757 ERROR(
"rlm_sql_freetds: unable to set username for db");
762 memcpy(&password, &config->
sql_password,
sizeof(password));
763 if (ct_con_props(conn->
db, CS_SET, CS_PASSWORD,
764 password, strlen(config->
sql_password), NULL) != CS_SUCCEED) {
765 ERROR(
"rlm_sql_freetds: unable to set password for db");
773 memcpy(&server, &config->
sql_server,
sizeof(server));
774 if (ct_connect(conn->
db, server, strlen(config->
sql_server)) != CS_SUCCEED) {
775 ERROR(
"rlm_sql_freetds: unable to establish db to symbolic servername %s",
799 if (
sql_error(NULL, &error, 1, handle, config) > 0)
ERROR(
"rlm_sql_freetds: %s", error.
msg);
808 .
name =
"rlm_sql_freetds",
static sql_rcode_t sql_select_query(rlm_sql_handle_t *handle, rlm_sql_config_t *config, char const *query)
Execute a query when we expected a result set.
General connection/server error.
static sql_rcode_t sql_fields(char const **out[], rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t *config)
static sql_rcode_t sql_free_result(UNUSED rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t *config)
Prototypes and functions for the SQL module.
log_type_t type
Type of log entry L_ERR, L_WARN, L_INFO, L_DBG etc..
static int sql_num_rows(rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t *config)
char const * msg
Log message.
char const * sql_server
Server to connect to.
PUBLIC int snprintf(char *string, size_t length, char *format, va_alist)
static sql_rcode_t sql_query(rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t *config, char const *query)
bool established
Set to false once the connection has been properly established.
static sql_rcode_t sql_fetch_row(rlm_sql_row_t *out, rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t *config)
Stale connection, should reconnect.
CS_CONNECTION * db
Handle specifying a single connection to the database.
CS_CONTEXT * context
Structure FreeTDS uses to avoid creating globals.
static size_t sql_error(UNUSED TALLOC_CTX *ctx, sql_log_entry_t out[], size_t outlen, rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t *config)
Retrieves any errors associated with the connection handle.
char * talloc_typed_asprintf(void const *t, char const *fmt,...)
Call talloc vasprintf, setting the type on the new chunk correctly.
char const * sql_password
Login password to use.
void * conn
Database specific connection handle.
char * error
The last error string created by one of the call backs.
static CS_RETCODE CS_PUBLIC csmsg_callback(CS_CONTEXT *context, CS_CLIENTMSG *emsgp)
Client error handler.
rlm_sql_row_t row
Row data from the last query.
struct rlm_sql_freetds_conn rlm_sql_freetds_conn_t
static sql_rcode_t sql_finish_query(rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t *config)
char const * sql_login
Login credentials to use.
char ** results
Result strings from statement execution.
static int sql_num_fields(rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t *config)
static CS_RETCODE CS_PUBLIC servermsg_callback(CS_CONTEXT *context, UNUSED CS_CONNECTION *conn, CS_SERVERMSG *msgp)
Server error handler.
char const * sql_db
Database to run queries against.
size_t strlcpy(char *dst, char const *src, size_t siz)
static sql_rcode_t sql_finish_select_query(rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t *config)
static int sql_affected_rows(rlm_sql_handle_t *handle, rlm_sql_config_t *config)
static CS_RETCODE CS_PUBLIC clientmsg_callback(CS_CONTEXT *context, UNUSED CS_CONNECTION *conn, CS_CLIENTMSG *emsgp)
Client-Library error handler.
#define FR_TIMEVAL_TO_MS(_x)
CS_COMMAND * command
A prepared statement.
static sql_rcode_t sql_socket_init(rlm_sql_handle_t *handle, rlm_sql_config_t *config, struct timeval const *timeout)
rlm_sql_module_t rlm_sql_freetds
static int _sql_socket_destructor(rlm_sql_freetds_conn_t *conn)