All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
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: df16cd0ca8d7ba51dddb6a4127c06ffe1ff09d36 $
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@ox.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 
31 RCSID("$Id: df16cd0ca8d7ba51dddb6a4127c06ffe1ff09d36 $")
32 
33 #include <freeradius-devel/radiusd.h>
34 #include <freeradius-devel/rad_assert.h>
35 
36 #include <sys/stat.h>
37 
38 #include <sql.h>
39 #include <sqlcli.h>
40 #include "rlm_sql.h"
41 
42 typedef struct rlm_sql_conn {
43  SQLHANDLE dbc_handle;
44  SQLHANDLE env_handle;
45  SQLHANDLE stmt;
47 
49 {
50  DEBUG2("rlm_sql_db2: 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 
62 static sql_rcode_t sql_socket_init(rlm_sql_handle_t *handle, rlm_sql_config_t *config, struct timeval const *timeout)
63 {
64  SQLRETURN retval;
65  uint32_t timeout_ms = FR_TIMEVAL_TO_MS(timeout);
66  rlm_sql_db2_conn_t *conn;
67 
68  MEM(conn = handle->conn = talloc_zero(handle, rlm_sql_db2_conn_t));
69  talloc_set_destructor(conn, _sql_socket_destructor);
70 
71  /* Allocate handles */
72  SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &(conn->env_handle));
73  SQLAllocHandle(SQL_HANDLE_DBC, conn->env_handle, &(conn->dbc_handle));
74 
75  /* Set the connection timeout */
76  SQLSetConnectAttr(conn->dbc_handle, SQL_ATTR_LOGIN_TIMEOUT, &timeout_ms, SQL_IS_UINTEGER);
77 
78  /*
79  * The db2 API doesn't qualify arguments as const even when they should be.
80  */
81  {
82  SQLCHAR *server, *login, *password;
83 
84  memcpy(&server, &config->sql_server, sizeof(server));
85  memcpy(&login, &config->sql_login, sizeof(login));
86  memcpy(&password, &config->sql_password, sizeof(password));
87 
88  retval = SQLConnect(conn->dbc_handle,
89  server, SQL_NTS,
90  login, SQL_NTS,
91  password, SQL_NTS);
92  }
93 
94  if (retval != SQL_SUCCESS) {
95  ERROR("could not connect to DB2 server %s", config->sql_server);
96 
97  return RLM_SQL_ERROR;
98  }
99 
100  return RLM_SQL_OK;
101 }
102 
103 static sql_rcode_t sql_query(rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t *config, char const *query)
104 {
105  SQLRETURN retval;
106  rlm_sql_db2_conn_t *conn;
107 
108  conn = handle->conn;
109 
110  /* allocate handle for statement */
111  SQLAllocHandle(SQL_HANDLE_STMT, conn->dbc_handle, &(conn->stmt));
112 
113  /* execute query */
114  {
115  SQLCHAR *db2_query;
116  memcpy(&db2_query, &query, sizeof(query));
117 
118  retval = SQLExecDirect(conn->stmt, db2_query, SQL_NTS);
119  if(retval != SQL_SUCCESS) {
120  /* XXX Check if retval means we should return RLM_SQL_RECONNECT */
121  ERROR("Could not execute statement \"%s\"", query);
122  return RLM_SQL_ERROR;
123  }
124  }
125 
126  return RLM_SQL_OK;
127 }
128 
129 static sql_rcode_t sql_select_query(rlm_sql_handle_t *handle, rlm_sql_config_t *config, char const *query)
130 {
131  return sql_query(handle, config, query);
132 }
133 
135 {
136  SQLSMALLINT c;
137  rlm_sql_db2_conn_t *conn;
138 
139  conn = handle->conn;
140  SQLNumResultCols(conn->stmt, &c);
141  return c;
142 }
143 
144 static sql_rcode_t sql_fields(char const **out[], rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t *config)
145 {
146  rlm_sql_db2_conn_t *conn = handle->conn;
147 
148  SQLSMALLINT fields, len, i;
149 
150  char const **names;
151  char field[128];
152 
153  SQLNumResultCols(conn->stmt, &fields);
154  if (fields == 0) return RLM_SQL_ERROR;
155 
156  MEM(names = talloc_array(handle, char const *, fields));
157 
158  for (i = 0; i < fields; i++) {
159  char *p;
160 
161  switch (SQLColAttribute(conn->stmt, i, SQL_DESC_BASE_COLUMN_NAME,
162  field, sizeof(field), &len, NULL)) {
163  case SQL_INVALID_HANDLE:
164  case SQL_ERROR:
165  ERROR("Failed retrieving field name at index %i", i);
166  talloc_free(names);
167  return RLM_SQL_ERROR;
168 
169  default:
170  break;
171  }
172 
173  MEM(p = talloc_array(names, char, (size_t)len + 1));
174  strlcpy(p, field, (size_t)len + 1);
175  names[i] = p;
176  }
177  *out = names;
178 
179  return RLM_SQL_OK;
180 }
181 
183 {
184  int c, i;
185  SQLINTEGER len, slen;
186  rlm_sql_row_t retval;
187  rlm_sql_db2_conn_t *conn;
188 
189  *out = NULL;
190 
191  conn = handle->conn;
192 
193  c = sql_num_fields(handle, config);
194  retval = (rlm_sql_row_t)rad_malloc(c*sizeof(char*)+1);
195  memset(retval, 0, c*sizeof(char*)+1);
196 
197  /* advance cursor */
198  if (SQLFetch(conn->stmt) == SQL_NO_DATA_FOUND) {
199  handle->row = NULL;
200  goto error;
201  }
202 
203  for(i = 0; i < c; i++) {
204  /* get column length */
205  SQLColAttribute(conn->stmt, i+1, SQL_DESC_DISPLAY_SIZE, NULL, 0, NULL, &len);
206 
207  retval[i] = rad_malloc(len+1);
208 
209  /* get the actual column */
210  SQLGetData(conn->stmt, i + 1, SQL_C_CHAR, retval[i], len+1, &slen);
211  if(slen == SQL_NULL_DATA) {
212  retval[i][0] = '\0';
213  }
214  }
215 
216  *out = handle->row = retval;
217  return RLM_SQL_OK;
218 
219 error:
220  for(i = 0; i < c; i++) {
221  free(retval[i]);
222  }
223  free(retval);
224 
225  return RLM_SQL_ERROR;
226 }
227 
229 {
230  rlm_sql_db2_conn_t *conn;
231  conn = handle->conn;
232  SQLFreeHandle(SQL_HANDLE_STMT, conn->stmt);
233 
234  return RLM_SQL_OK;
235 }
236 
237 /** Retrieves any errors associated with the connection handle
238  *
239  * @note Caller will free any memory allocated in ctx.
240  *
241  * @param ctx to allocate temporary error buffers in.
242  * @param out Array of sql_log_entrys to fill.
243  * @param outlen Length of out array.
244  * @param handle rlm_sql connection handle.
245  * @param config rlm_sql config.
246  * @return number of errors written to the #sql_log_entry_t array.
247  */
248 static size_t sql_error(TALLOC_CTX *ctx, sql_log_entry_t out[], size_t outlen,
249  rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t *config)
250 {
251  char state[6];
252  char errbuff[1024];
253  SQLINTEGER err;
254  SQLSMALLINT rl;
255  rlm_sql_db2_conn_t *conn = handle->conn;
256 
257  rad_assert(conn);
258  rad_assert(outlen > 0);
259 
260  errbuff[0] = '\0';
261  SQLGetDiagRec(SQL_HANDLE_STMT, conn->stmt, 1, (SQLCHAR *) state, &err,
262  (SQLCHAR *) errbuff, sizeof(errbuff), &rl);
263  if (errbuff[0] == '\0') return 0;
264 
265  out[0].type = L_ERR;
266  out[0].msg = talloc_asprintf(ctx, "%s: %s", state, errbuff);
267 
268  return 1;
269 }
270 
272 {
273  return RLM_SQL_OK;
274 }
275 
277 {
278  return sql_finish_query(handle, config);
279 }
280 
282 {
283  SQLINTEGER c;
284  rlm_sql_db2_conn_t *conn = handle->conn;
285 
286  SQLRowCount(conn->stmt, &c);
287 
288  return c;
289 }
290 
291 /* Exported to rlm_sql */
293 rlm_sql_module_t rlm_sql_db2 = {
294  .name = "rlm_sql_db2",
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 };
General connection/server error.
Definition: rlm_sql.h:46
static sql_rcode_t sql_socket_init(rlm_sql_handle_t *handle, rlm_sql_config_t *config, struct timeval const *timeout)
Definition: rlm_sql_db2.c:62
Prototypes and functions for the SQL module.
char ** rlm_sql_row_t
Definition: rlm_sql.h:59
log_type_t type
Type of log entry L_ERR, L_WARN, L_INFO, L_DBG etc..
Definition: rlm_sql.h:62
static sql_rcode_t sql_free_result(rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t *config)
Definition: rlm_sql_db2.c:228
void * rad_malloc(size_t size)
Definition: util.c:411
#define MEM(x)
Definition: radiusd.h:396
char const * msg
Log message.
Definition: rlm_sql.h:63
#define UNUSED
Definition: libradius.h:134
Error message.
Definition: log.h:36
char const * sql_server
Server to connect to.
Definition: rlm_sql.h:85
static float timeout
Definition: radclient.c:43
static sql_rcode_t sql_finish_select_query(rlm_sql_handle_t *handle, rlm_sql_config_t *config)
Definition: rlm_sql_db2.c:276
static int sql_affected_rows(rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t *config)
Definition: rlm_sql_db2.c:281
static sql_rcode_t sql_fields(char const **out[], rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t *config)
Definition: rlm_sql_db2.c:144
#define rad_assert(expr)
Definition: rad_assert.h:38
static int _sql_socket_destructor(rlm_sql_db2_conn_t *conn)
Definition: rlm_sql_db2.c:48
char const * name
Definition: rlm_sql.h:191
rlm_sql_module_t rlm_sql_db2
Definition: rlm_sql_db2.c:293
sql_rcode_t
Definition: rlm_sql.h:44
#define DEBUG2(fmt,...)
Definition: log.h:176
Definition: rlm_sql.h:61
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 *config)
Retrieves any errors associated with the connection handle.
Definition: rlm_sql_db2.c:248
Success.
Definition: rlm_sql.h:47
char const * sql_password
Login password to use.
Definition: rlm_sql.h:88
void * conn
Database specific connection handle.
Definition: rlm_sql.h:153
static sql_rcode_t sql_select_query(rlm_sql_handle_t *handle, rlm_sql_config_t *config, char const *query)
Definition: rlm_sql_db2.c:129
SQLHANDLE env_handle
Definition: rlm_sql_db2.c:44
static sql_rcode_t sql_query(rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t *config, char const *query)
Definition: rlm_sql_db2.c:103
rlm_sql_row_t row
Row data from the last query.
Definition: rlm_sql.h:154
SQLHANDLE stmt
Definition: rlm_sql_db2.c:45
unsigned int state
Definition: proto_bfd.c:200
char const * sql_login
Login credentials to use.
Definition: rlm_sql.h:87
static sql_rcode_t sql_fetch_row(rlm_sql_row_t *out, rlm_sql_handle_t *handle, rlm_sql_config_t *config)
Definition: rlm_sql_db2.c:182
size_t strlcpy(char *dst, char const *src, size_t siz)
Definition: strlcpy.c:38
SQLHANDLE dbc_handle
Definition: rlm_sql_db2.c:43
#define FR_TIMEVAL_TO_MS(_x)
Definition: conffile.h:235
static int sql_num_fields(rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t *config)
Definition: rlm_sql_db2.c:134
#define RCSID(id)
Definition: build.h:135
static sql_rcode_t sql_finish_query(UNUSED rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t *config)
Definition: rlm_sql_db2.c:271
#define ERROR(fmt,...)
Definition: log.h:145
struct rlm_sql_conn rlm_sql_db2_conn_t