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: fce6190b02baa14b7030a24ef7f7c3ff89c22d28 $
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: fce6190b02baa14b7030a24ef7f7c3ff89c22d28 $")
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 sql_rcode_t sql_query(rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t const *config, char const *query)
110 {
111  SQLRETURN row;
112  rlm_sql_db2_conn_t *conn;
113 
114  conn = handle->conn;
115 
116  /* allocate handle for statement */
117  SQLAllocHandle(SQL_HANDLE_STMT, conn->dbc_handle, &(conn->stmt));
118 
119  /* execute query */
120  {
121  SQLCHAR *db2_query;
122  memcpy(&db2_query, &query, sizeof(query));
123 
124  row = SQLExecDirect(conn->stmt, db2_query, SQL_NTS);
125  if(row != SQL_SUCCESS) {
126  /* XXX Check if row means we should return RLM_SQL_RECONNECT */
127  ERROR("Could not execute statement \"%s\"", query);
128  return RLM_SQL_ERROR;
129  }
130  }
131 
132  return RLM_SQL_OK;
133 }
134 
135 static sql_rcode_t sql_select_query(rlm_sql_handle_t *handle, rlm_sql_config_t const *config, char const *query)
136 {
137  return sql_query(handle, config, query);
138 }
139 
141 {
142  SQLSMALLINT c;
143  rlm_sql_db2_conn_t *conn;
144 
145  conn = handle->conn;
146  SQLNumResultCols(conn->stmt, &c);
147  return c;
148 }
149 
150 static sql_rcode_t sql_fields(char const **out[], rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t const *config)
151 {
152  rlm_sql_db2_conn_t *conn = handle->conn;
153 
154  SQLSMALLINT fields, len, i;
155 
156  char const **names;
157  char field[128];
158 
159  SQLNumResultCols(conn->stmt, &fields);
160  if (fields == 0) return RLM_SQL_ERROR;
161 
162  MEM(names = talloc_array(handle, char const *, fields));
163 
164  for (i = 0; i < fields; i++) {
165  char *p;
166 
167  switch (SQLColAttribute(conn->stmt, i, SQL_DESC_BASE_COLUMN_NAME,
168  field, sizeof(field), &len, NULL)) {
169  case SQL_INVALID_HANDLE:
170  case SQL_ERROR:
171  ERROR("Failed retrieving field name at index %i", i);
173  return RLM_SQL_ERROR;
174 
175  default:
176  break;
177  }
178 
179  MEM(p = talloc_array(names, char, (size_t)len + 1));
180  strlcpy(p, field, (size_t)len + 1);
181  names[i] = p;
182  }
183  *out = names;
184 
185  return RLM_SQL_OK;
186 }
187 
189 {
190  int c, i;
191  SQLINTEGER len, slen;
192  rlm_sql_row_t row;
193  rlm_sql_db2_conn_t *conn;
194 
195  *out = NULL;
196 
197  TALLOC_FREE(handle->row);
198 
199  conn = handle->conn;
200  c = sql_num_fields(handle, config);
201 
202  /* advance cursor */
203  if (SQLFetch(conn->stmt) == SQL_NO_DATA_FOUND) return RLM_SQL_NO_MORE_ROWS;
204 
205  MEM(row = (rlm_sql_row_t)talloc_zero_array(handle, char *, c + 1));
206  for (i = 0; i < c; i++) {
207  /* get column length */
208  SQLColAttribute(conn->stmt, i + 1, SQL_DESC_DISPLAY_SIZE, NULL, 0, NULL, &len);
209 
210  MEM(row[i] = talloc_array(row, char, len + 1));
211 
212  /* get the actual column */
213  SQLGetData(conn->stmt, i + 1, SQL_C_CHAR, row[i], len + 1, &slen);
214  if (slen == SQL_NULL_DATA) row[i][0] = '\0';
215  }
216 
217  *out = handle->row = row;
218 
219  return RLM_SQL_OK;
220 }
221 
223 {
224  rlm_sql_db2_conn_t *conn;
225 
226  conn = handle->conn;
227  TALLOC_FREE(handle->row);
228  SQLFreeHandle(SQL_HANDLE_STMT, conn->stmt);
229 
230  return RLM_SQL_OK;
231 }
232 
233 /** Retrieves any errors associated with the connection handle
234  *
235  * @note Caller will free any memory allocated in ctx.
236  *
237  * @param ctx to allocate temporary error buffers in.
238  * @param out Array of sql_log_entrys to fill.
239  * @param outlen Length of out array.
240  * @param handle rlm_sql connection handle.
241  * @param config rlm_sql config.
242  * @return number of errors written to the #sql_log_entry_t array.
243  */
244 static size_t sql_error(TALLOC_CTX *ctx, sql_log_entry_t out[], NDEBUG_UNUSED size_t outlen,
246 {
247  char state[6];
248  char errbuff[1024];
249  SQLINTEGER err;
250  SQLSMALLINT rl;
251  rlm_sql_db2_conn_t *conn = handle->conn;
252 
253  fr_assert(conn);
254  fr_assert(outlen > 0);
255 
256  errbuff[0] = '\0';
257  SQLGetDiagRec(SQL_HANDLE_STMT, conn->stmt, 1, (SQLCHAR *) state, &err,
258  (SQLCHAR *) errbuff, sizeof(errbuff), &rl);
259  if (errbuff[0] == '\0') return 0;
260 
261  out[0].type = L_ERR;
262  out[0].msg = talloc_typed_asprintf(ctx, "%s: %s", state, errbuff);
263 
264  return 1;
265 }
266 
268 {
269  return RLM_SQL_OK;
270 }
271 
273 {
274  return sql_finish_query(handle, config);
275 }
276 
278 {
279  SQLINTEGER c;
280  rlm_sql_db2_conn_t *conn = handle->conn;
281 
282  SQLRowCount(conn->stmt, &c);
283 
284  return c;
285 }
286 
287 /* Exported to rlm_sql */
290  .common = {
291  .magic = MODULE_MAGIC_INIT,
292  .name = "sql_db2",
293  },
294  .number = 8,
295  .sql_socket_init = sql_socket_init,
296  .sql_query = sql_query,
297  .sql_select_query = sql_select_query,
298  .sql_num_fields = sql_num_fields,
299  .sql_affected_rows = sql_affected_rows,
300  .sql_fields = sql_fields,
301  .sql_fetch_row = sql_fetch_row,
302  .sql_free_result = sql_free_result,
303  .sql_error = sql_error,
304  .sql_finish_query = sql_finish_query,
305  .sql_finish_select_query = sql_finish_select_query
306 };
#define UNCONST(_type, _ptr)
Remove const qualification from a pointer.
Definition: build.h:165
#define RCSID(id)
Definition: build.h:444
#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:65
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
Prototypes and functions for the SQL module.
void * conn
Database specific connection handle.
Definition: rlm_sql.h:136
sql_rcode_t
Action to take at end of an SQL query.
Definition: rlm_sql.h:42
@ RLM_SQL_ERROR
General connection/server error.
Definition: rlm_sql.h:44
@ RLM_SQL_OK
Success.
Definition: rlm_sql.h:45
@ RLM_SQL_NO_MORE_ROWS
No more rows available.
Definition: rlm_sql.h:48
char ** rlm_sql_row_t
Definition: rlm_sql.h:57
rlm_sql_row_t row
Row data from the last query.
Definition: rlm_sql.h:137
Definition: rlm_sql.h:59
rlm_sql_driver_t rlm_sql_db2
Definition: rlm_sql_db2.c:289
static sql_rcode_t sql_fetch_row(rlm_sql_row_t *out, rlm_sql_handle_t *handle, rlm_sql_config_t const *config)
Definition: rlm_sql_db2.c:188
static sql_rcode_t sql_finish_query(UNUSED rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t const *config)
Definition: rlm_sql_db2.c:267
static sql_rcode_t sql_free_result(rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t const *config)
Definition: rlm_sql_db2.c:222
static size_t sql_error(TALLOC_CTX *ctx, sql_log_entry_t out[], NDEBUG_UNUSED size_t outlen, rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t const *config)
Retrieves any errors associated with the connection handle.
Definition: rlm_sql_db2.c:244
static int _sql_socket_destructor(rlm_sql_db2_conn_t *conn)
Definition: rlm_sql_db2.c:48
static sql_rcode_t sql_query(rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t const *config, char const *query)
Definition: rlm_sql_db2.c:109
SQLHANDLE dbc_handle
Definition: rlm_sql_db2.c:43
static sql_rcode_t sql_select_query(rlm_sql_handle_t *handle, rlm_sql_config_t const *config, char const *query)
Definition: rlm_sql_db2.c:135
static sql_rcode_t sql_finish_select_query(rlm_sql_handle_t *handle, rlm_sql_config_t const *config)
Definition: rlm_sql_db2.c:272
static int sql_affected_rows(rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t const *config)
Definition: rlm_sql_db2.c:277
static int sql_num_fields(rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t const *config)
Definition: rlm_sql_db2.c:140
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
static sql_rcode_t sql_fields(char const **out[], rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t const *config)
Definition: rlm_sql_db2.c:150
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:183
char * talloc_typed_asprintf(TALLOC_CTX *ctx, char const *fmt,...)
Call talloc vasprintf, setting the type on the new chunk correctly.
Definition: talloc.c:380
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