The FreeRADIUS server  $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
rlm_sql_db2.c
Go to the documentation of this file.
1 /*
2  * sql_db2.c IBM DB2 rlm_sql driver
3  *
4  * Version: $Id: b3bedf83d808b8df0bf3d7f1803888dc84b03f52 $
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  *
20  * @copyright 2000,2006 The FreeRADIUS server project
21  * @copyright 2000 Mike Machado (mike@innercite.com)
22  * @copyright 2000 Alan DeKok (aland@freeradius.org)
23  * @copyright 2001 Joerg Wendland (wendland@scan-plus.de)
24  */
25 
26 /*
27  * Modification of rlm_sql_db2 to handle IBM DB2 UDB V7
28  * by Joerg Wendland <wendland@scan-plus.de>
29  */
30 RCSID("$Id: b3bedf83d808b8df0bf3d7f1803888dc84b03f52 $")
31 
32 #define LOG_PREFIX "sql - db2"
33 
34 #include <freeradius-devel/server/base.h>
35 #include <freeradius-devel/util/debug.h>
36 
37 #include <sys/stat.h>
38 
39 #include <sqlcli.h>
40 #include "rlm_sql.h"
41 
42 typedef struct {
43  SQLHANDLE dbc_handle;
44  SQLHANDLE env_handle;
45  SQLHANDLE stmt;
47 
49 {
50  DEBUG2("Socket destructor called, closing socket");
51 
52  if (conn->dbc_handle) {
53  SQLDisconnect(conn->dbc_handle);
54  SQLFreeHandle(SQL_HANDLE_DBC, conn->dbc_handle);
55  }
56 
57  if (conn->env_handle) SQLFreeHandle(SQL_HANDLE_ENV, conn->env_handle);
58 
59  return RLM_SQL_OK;
60 }
61 
64 {
65  SQLRETURN row;
66 #if 0
67  uint32_t timeout_ms = FR_TIMEVAL_TO_MS(timeout);
68 #endif
69  rlm_sql_db2_conn_t *conn;
70 
71  MEM(conn = handle->conn = talloc_zero(handle, rlm_sql_db2_conn_t));
72  talloc_set_destructor(conn, _sql_socket_destructor);
73 
74  /* Allocate handles */
75  SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &(conn->env_handle));
76  SQLAllocHandle(SQL_HANDLE_DBC, conn->env_handle, &(conn->dbc_handle));
77 
78  /* Set the connection timeout */
79 #if 0
80  /* Not supported ? */
81  SQLSetConnectAttr(conn->dbc_handle, SQL_ATTR_LOGIN_TIMEOUT, &timeout_ms, SQL_IS_UINTEGER);
82 #endif
83 
84  /*
85  * We probably want to use SQLDriverConnect, which connects
86  * to a remote server.
87  *
88  * http://www.ibm.com/support/knowledgecenter/SSEPGG_10.5.0/com.ibm.db2.luw.apdv.cli.doc/doc/r0000584.html
89  * http://stackoverflow.com/questions/27167070/connection-string-to-a-remote-db2-db-in-another-server
90  *
91  * And probably synthesise the retarded connection string ourselves,
92  * probably via config file expansions:
93  *
94  * Driver={IBM DB2 ODBC Driver};Database=testDb;Hostname=remoteHostName.com;UID=username;PWD=mypasswd;PORT=50000
95  */
96  row = SQLConnect(conn->dbc_handle,
97  UNCONST(SQLCHAR *, config->sql_server), SQL_NTS,
98  UNCONST(SQLCHAR *, config->sql_login), SQL_NTS,
99  UNCONST(SQLCHAR *, config->sql_password), SQL_NTS);
100  if (row != SQL_SUCCESS) {
101  ERROR("could not connect to DB2 server %s", config->sql_server);
102 
103  return RLM_SQL_ERROR;
104  }
105 
106  return RLM_SQL_OK;
107 }
108 
109 static unlang_action_t sql_query(rlm_rcode_t *p_result, UNUSED int *priority, request_t *request, void *uctx)
110 {
111  fr_sql_query_t *query_ctx = talloc_get_type_abort(uctx, fr_sql_query_t);
112  SQLRETURN row;
113  rlm_sql_db2_conn_t *conn;
114 
115  conn = query_ctx->handle->conn;
116 
117  /* allocate handle for statement */
118  SQLAllocHandle(SQL_HANDLE_STMT, conn->dbc_handle, &(conn->stmt));
119 
120  /* execute query */
121  {
122  SQLCHAR *db2_query;
123  memcpy(&db2_query, &query_ctx->query_str, sizeof(query_ctx->query_str));
124 
125  row = SQLExecDirect(conn->stmt, db2_query, SQL_NTS);
126  if(row != SQL_SUCCESS) {
127  /* XXX Check if row means we should return RLM_SQL_RECONNECT */
128  ERROR("Could not execute statement \"%s\"", query);
129  query_ctx->rcode = RLM_SQL_ERROR;
131  }
132  }
133 
134  query_ctx->rcode = RLM_SQL_OK;
136 }
137 
138 static sql_rcode_t sql_fields(char const **out[], fr_sql_query_t *query_ctx, UNUSED rlm_sql_config_t const *config)
139 {
140  rlm_sql_db2_conn_t *conn = query_ctx->handle->conn;
141 
142  SQLSMALLINT fields, len, i;
143 
144  char const **names;
145  char field[128];
146 
147  SQLNumResultCols(conn->stmt, &fields);
148  if (fields == 0) return RLM_SQL_ERROR;
149 
150  MEM(names = talloc_array(query_ctx, char const *, fields));
151 
152  for (i = 0; i < fields; i++) {
153  char *p;
154 
155  switch (SQLColAttribute(conn->stmt, i, SQL_DESC_BASE_COLUMN_NAME,
156  field, sizeof(field), &len, NULL)) {
157  case SQL_INVALID_HANDLE:
158  case SQL_ERROR:
159  ERROR("Failed retrieving field name at index %i", i);
161  return RLM_SQL_ERROR;
162 
163  default:
164  break;
165  }
166 
167  MEM(p = talloc_array(names, char, (size_t)len + 1));
168  strlcpy(p, field, (size_t)len + 1);
169  names[i] = p;
170  }
171  *out = names;
172 
173  return RLM_SQL_OK;
174 }
175 
176 static unlang_action_t sql_fetch_row(rlm_rcode_t *p_result, UNUSED int *priority, UNUSED request_t *request, void *uctx)
177 {
178  fr_sql_query_t *query_ctx = talloc_get_type_abort(uctx, fr_sql_query_t);
179  int i;
180  SQLINTEGER len, slen;
181  SQLSMALLINT c;
182  rlm_sql_row_t row;
183  rlm_sql_db2_conn_t *conn;
184  rlm_sql_handle_t *handle = query_ctx->handle;
185 
186  TALLOC_FREE(query_ctx->row);
187 
188  conn = handle->conn;
189  SQLNumResultCols(conn->stmt, &c);
190 
191  /* advance cursor */
192  if (SQLFetch(conn->stmt) == SQL_NO_DATA_FOUND) {
193  query_ctx->rcode = RLM_SQL_NO_MORE_ROWS;
195  }
196 
197  MEM(row = (rlm_sql_row_t)talloc_zero_array(query_ctx, char *, c + 1));
198  for (i = 0; i < c; i++) {
199  /* get column length */
200  SQLColAttribute(conn->stmt, i + 1, SQL_DESC_DISPLAY_SIZE, NULL, 0, NULL, &len);
201 
202  MEM(row[i] = talloc_array(row, char, len + 1));
203 
204  /* get the actual column */
205  SQLGetData(conn->stmt, i + 1, SQL_C_CHAR, row[i], len + 1, &slen);
206  if (slen == SQL_NULL_DATA) row[i][0] = '\0';
207  }
208 
209  query_ctx->row = row;
210 
211  query_ctx->rcode = RLM_SQL_OK;
213 }
214 
216 {
217  rlm_sql_db2_conn_t *conn;
218 
219  conn = query_ctx->handle->conn;
220  TALLOC_FREE(query_ctx->row);
221  SQLFreeHandle(SQL_HANDLE_STMT, conn->stmt);
222 
223  return RLM_SQL_OK;
224 }
225 
226 /** Retrieves any errors associated with the query context
227  *
228  * @note Caller will free any memory allocated in ctx.
229  *
230  * @param ctx to allocate temporary error buffers in.
231  * @param out Array of sql_log_entrys to fill.
232  * @param outlen Length of out array.
233  * @param query_ctx Query context to retrieve error for.
234  * @param config rlm_sql config.
235  * @return number of errors written to the #sql_log_entry_t array.
236  */
237 static size_t sql_error(TALLOC_CTX *ctx, sql_log_entry_t out[], NDEBUG_UNUSED size_t outlen,
238  fr_sql_query_t *query_ctx, UNUSED rlm_sql_config_t const *config)
239 {
240  char state[6];
241  char errbuff[1024];
242  SQLINTEGER err;
243  SQLSMALLINT rl;
244  rlm_sql_db2_conn_t *conn = query_ctx->handle->conn;
245 
246  fr_assert(conn);
247  fr_assert(outlen > 0);
248 
249  errbuff[0] = '\0';
250  SQLGetDiagRec(SQL_HANDLE_STMT, conn->stmt, 1, (SQLCHAR *) state, &err,
251  (SQLCHAR *) errbuff, sizeof(errbuff), &rl);
252  if (errbuff[0] == '\0') return 0;
253 
254  out[0].type = L_ERR;
255  out[0].msg = talloc_typed_asprintf(ctx, "%s: %s", state, errbuff);
256 
257  return 1;
258 }
259 
261 {
262  return RLM_SQL_OK;
263 }
264 
266 {
267  SQLINTEGER c;
268  rlm_sql_db2_conn_t *conn = query_ctx->handle->conn;
269 
270  SQLRowCount(conn->stmt, &c);
271 
272  return c;
273 }
274 
275 /* Exported to rlm_sql */
278  .common = {
279  .magic = MODULE_MAGIC_INIT,
280  .name = "sql_db2",
281  },
282  .sql_socket_init = sql_socket_init,
283  .sql_query = sql_query,
284  .sql_select_query = sql_query,
285  .sql_affected_rows = sql_affected_rows,
286  .sql_fields = sql_fields,
287  .sql_fetch_row = sql_fetch_row,
288  .sql_free_result = sql_free_result,
289  .sql_error = sql_error,
290  .sql_finish_query = sql_finish_query,
291  .sql_finish_select_query = sql_finish_query
292 };
unlang_action_t
Returned by unlang_op_t calls, determine the next action of the interpreter.
Definition: action.h:35
#define UNCONST(_type, _ptr)
Remove const qualification from a pointer.
Definition: build.h:165
#define RCSID(id)
Definition: build.h:446
#define NDEBUG_UNUSED
Definition: build.h:324
#define UNUSED
Definition: build.h:313
#define FR_TIMEVAL_TO_MS(_x)
Definition: cf_util.h:53
#define ERROR(fmt,...)
Definition: dhcpclient.c:41
static fr_time_delta_t timeout
Definition: dhcpclient.c:54
static fr_slen_t err
Definition: dict.h:645
#define MODULE_MAGIC_INIT
Stop people using different module/library/server versions together.
Definition: dl_module.h:63
talloc_free(reap)
@ L_ERR
Error message.
Definition: log.h:56
unsigned int uint32_t
Definition: merged_model.c:33
static const conf_parser_t config[]
Definition: base.c:188
#define DEBUG2(fmt,...)
Definition: radclient.h:43
#define RETURN_MODULE_OK
Definition: rcode.h:57
rlm_rcode_t
Return codes indicating the result of the module call.
Definition: rcode.h:40
Prototypes and functions for the SQL module.
void * conn
Database specific connection handle.
Definition: rlm_sql.h:114
char const * query_str
Query string to run.
Definition: rlm_sql.h:143
sql_rcode_t
Action to take at end of an SQL query.
Definition: rlm_sql.h:44
@ RLM_SQL_ERROR
General connection/server error.
Definition: rlm_sql.h:46
@ RLM_SQL_OK
Success.
Definition: rlm_sql.h:47
@ RLM_SQL_NO_MORE_ROWS
No more rows available.
Definition: rlm_sql.h:50
rlm_sql_handle_t * handle
Connection handle this query is being run on.
Definition: rlm_sql.h:139
char ** rlm_sql_row_t
Definition: rlm_sql.h:59
rlm_sql_row_t row
Row data from the last query.
Definition: rlm_sql.h:147
sql_rcode_t rcode
Result code.
Definition: rlm_sql.h:146
Definition: rlm_sql.h:61
rlm_sql_driver_t rlm_sql_db2
Definition: rlm_sql_db2.c:277
static sql_rcode_t sql_fields(char const **out[], fr_sql_query_t *query_ctx, UNUSED rlm_sql_config_t const *config)
Definition: rlm_sql_db2.c:138
static unlang_action_t sql_query(rlm_rcode_t *p_result, UNUSED int *priority, request_t *request, void *uctx)
Definition: rlm_sql_db2.c:109
static unlang_action_t sql_fetch_row(rlm_rcode_t *p_result, UNUSED int *priority, UNUSED request_t *request, void *uctx)
Definition: rlm_sql_db2.c:176
static size_t sql_error(TALLOC_CTX *ctx, sql_log_entry_t out[], NDEBUG_UNUSED size_t outlen, fr_sql_query_t *query_ctx, UNUSED rlm_sql_config_t const *config)
Retrieves any errors associated with the query context.
Definition: rlm_sql_db2.c:237
static sql_rcode_t sql_finish_query(UNUSED fr_sql_query_t *query_ctx, UNUSED rlm_sql_config_t const *config)
Definition: rlm_sql_db2.c:260
static int _sql_socket_destructor(rlm_sql_db2_conn_t *conn)
Definition: rlm_sql_db2.c:48
SQLHANDLE dbc_handle
Definition: rlm_sql_db2.c:43
static sql_rcode_t sql_free_result(fr_sql_query_t *query_, UNUSED rlm_sql_config_t const *config)
Definition: rlm_sql_db2.c:215
static int sql_affected_rows(fr_sql_query_t *query_ctx, UNUSED rlm_sql_config_t const *config)
Definition: rlm_sql_db2.c:265
SQLHANDLE env_handle
Definition: rlm_sql_db2.c:44
static sql_rcode_t sql_socket_init(rlm_sql_handle_t *handle, rlm_sql_config_t const *config, UNUSED fr_time_delta_t timeout)
Definition: rlm_sql_db2.c:62
RETURN_MODULE_FAIL
fr_assert(0)
MEM(pair_append_request(&vp, attr_eap_aka_sim_identity) >=0)
size_t strlcpy(char *dst, char const *src, size_t siz)
Definition: strlcpy.c:34
module_t common
Common fields for all loadable modules.
Definition: rlm_sql.h:202
char * talloc_typed_asprintf(TALLOC_CTX *ctx, char const *fmt,...)
Call talloc vasprintf, setting the type on the new chunk correctly.
Definition: talloc.c:492
static const char * names[8]
Definition: time.c:617
A time delta, a difference in time measured in nanoseconds.
Definition: time.h:80
static size_t char ** out
Definition: value.h:984