summaryrefslogtreecommitdiffstats
path: root/src/modules/rlm_sql/rlm_sql.h
blob: 5af8db40905fa83358081d70b1525090c77d8e1e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
/*
 *   This program is is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation; either version 2 of the License, or (at
 *   your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program; if not, write to the Free Software
 *   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 */

/**
 * $Id$
 * @file rlm_sql.h
 * @brief Prototypes and functions for the SQL module
 *
 * @copyright 2012-2014  Arran Cudbard-Bell <a.cudbardb@freeradius.org>
 * @copyright 2000,2006  The FreeRADIUS server project
 * @copyright 2000  Mike Machado <mike@innercite.com>
 * @copyright 2000  Alan DeKok <aland@ox.org>
 */
#ifndef _RLM_SQL_H
#define _RLM_SQL_H

RCSIDH(rlm_sql_h, "$Id$")

#include <freeradius-devel/radiusd.h>
#include <freeradius-devel/connection.h>
#include <freeradius-devel/modpriv.h>
#include <freeradius-devel/exfile.h>

#define MOD_PREFIX "rlm_sql"

#define PW_ITEM_CHECK 0
#define PW_ITEM_REPLY 1


/* SQL Errors */
typedef enum {
	RLM_SQL_QUERY_INVALID = -3,	//!< Query syntax error.
	RLM_SQL_ERROR = -2,		//!< General connection/server error.
	RLM_SQL_OK = 0,			//!< Success.
	RLM_SQL_RECONNECT = 1,		//!< Stale connection, should reconnect.
	RLM_SQL_ALT_QUERY,		//!< Key constraint violation, use an alternative query.
	RLM_SQL_NO_MORE_ROWS,		//!< No more rows available
} sql_rcode_t;

typedef enum {
	FALL_THROUGH_NO = 0,
	FALL_THROUGH_YES,
	FALL_THROUGH_DEFAULT,
} sql_fall_through_t;


typedef char **rlm_sql_row_t;

typedef struct sql_log_entry {
	log_type_t	type;		//!< Type of log entry L_ERR, L_WARN, L_INFO, L_DBG etc..
	char const	*msg;		//!< Log message.
} sql_log_entry_t;

/*
 * Sections where we dynamically resolve the config entry to use,
 * by xlating reference.
 */
typedef struct sql_acct_section {
	CONF_SECTION		*cs;				//!< The CONF_SECTION representing the group
								//!< of queries to process.

	char const		*reference;			//!< Reference string, expanded to point to
								//!< a group of queries.
	bool			reference_cp;

	char const		*logfile;

	char const		*query;	/* for xlat parsing */
} sql_acct_section_t;

typedef struct sql_config {
	char const 		*sql_driver_name;		//!< SQL driver module name e.g. rlm_sql_sqlite.
	char const 		*sql_server;			//!< Server to connect to.
	uint32_t 		sql_port;			//!< Port to connect to.
	char const 		*sql_login;			//!< Login credentials to use.
	char const 		*sql_password;			//!< Login password to use.
	char const 		*sql_db;			//!< Database to run queries against.

	char const		*query_user;			//!< xlat expansion used to specify the user
								//!< to use as the subject of queries.

	char const		*default_profile;		//!< Default profile to use if no other
								//!< profiles were configured.

	char const		*client_query;			//!< Query used to get FreeRADIUS client
								//!< definitions.

	char const		*authorize_check_query;		//!< Query used get check VPs for a user.
	char const 		*authorize_reply_query;		//!< Query used get reply VPs for a user.
	char const		*authorize_group_check_query;	//!< Query used get check VPs for a group.
	char const		*authorize_group_reply_query;	//!< Query used get reply VPs for a group.
	char const		*simul_count_query;		//!< Query used get number of active sessions
								//!< for a user (basic simultaneous use check).
	char const		*simul_verify_query;		//!< Query to get active sessions for a user
								//!< the result is fed to session_zap.
	char const 		*groupmemb_query;		//!< Query to determine group membership.

	bool			do_clients;			//!< Read clients from SQL database.
	bool			read_groups;			//!< Read user groups by default.
								//!< If false, Fall-Through = yes is required
								//!< in the previous reply list to process
								//!< groups.
	bool			read_profiles;			//!< Read user profiles by default.
								//!< If false, Fall-Through = yes is required
								//!< in the previous reply list to process
								//!< profiles.
	char const		*logfile;			//!< Keep a log of all SQL queries executed
								//!< Useful for batch insertion with the
								//!< NULL drivers.

	bool			delete_stale_sessions;		//!< Whether we should use session_zap to create
								//!< a fake stop packet, to terminate any
								//!< stale sessions.

	char const		*allowed_chars;			//!< Chars which done need escaping..
	bool			driver_specific_escape;		//!< Use the driver specific SQL escape method
	uint32_t		query_timeout;			//!< How long to allow queries to run for.

	char const		*connect_query;			//!< Query executed after establishing
								//!< new connection.
	struct timeval		connect_timeout_tv;		//!< Connection timeout timeval.
	uint32_t		connect_timeout_ms;		//!< Connection timeout ms.
	uint32_t		connect_timeout_s;		//!< Connection timeout in seconds.

	void			*driver;			//!< Where drivers should write a
								//!< pointer to their configurations.

	/*
	 *	@todo The rest of the queries should also be moved into
	 *	their own sections.
	 */

	/*
	 *	Section configurations
	 */
	sql_acct_section_t	postauth;
	sql_acct_section_t	accounting;
} rlm_sql_config_t;

typedef struct sql_inst rlm_sql_t;

typedef struct rlm_sql_handle {
	void			*conn;				//!< Database specific connection handle.
	rlm_sql_row_t		row;				//!< Row data from the last query.
	rlm_sql_t		*inst;				//!< The rlm_sql instance this connection belongs to.
	TALLOC_CTX		*log_ctx;			//!< Talloc pool used to avoid mallocing memory on
								//!< when log strings need to be copied.
} rlm_sql_handle_t;

extern const FR_NAME_NUMBER sql_rcode_table[];
/*
 *	Capabilities flags for drivers
 */
#define RLM_SQL_RCODE_FLAGS_ALT_QUERY	1			//!< Can distinguish between other errors and those
								//!< resulting from a unique key violation.

/** Retrieve errors from the last query operation
 *
 * @note Buffers allocated in the context provided will be automatically freed. The driver
 *	should not free these buffers explicitly.
 * @note If the driver uses its own buffers to aggregate messages, they should be cleared
 *	on sql_query_finish, and after each call to sql_error, to prevent the same messages
 *	being printed multiple times.
 *
 * @param[in,out] ctx to allocate any buffers required. If static buffers are provided by the
 *	driver they need not be strduped, just write the pointer to those buffers to the .msg
 *	field of a sql_log_entry_t element.
 * @param[out] out a pre-allocated array of log entries to fill. Need not be NULL terminated.
 * @param[in] outlen Number of log entries available for populating. Do not write to index
 *	out[outlen] or higher.
 * @param[in] handle to retrieve errors from.
 * @param[in] config of the SQL instance.
 * @return
 *	0  - If no error messages are available.
 *	>0 - Number of log entries
 */
typedef size_t (*sql_error_t)(TALLOC_CTX *ctx, sql_log_entry_t out[], size_t outlen, rlm_sql_handle_t *handle,
			      rlm_sql_config_t *config);

typedef struct rlm_sql_module_t {
	char const	*name;
	int		flags;

	sql_rcode_t (*mod_instantiate)(CONF_SECTION *conf, rlm_sql_config_t *config);
	sql_rcode_t (*sql_socket_init)(rlm_sql_handle_t *handle, rlm_sql_config_t *config);

	sql_rcode_t (*sql_query)(rlm_sql_handle_t *handle, rlm_sql_config_t *config, char const *query);
	sql_rcode_t (*sql_select_query)(rlm_sql_handle_t *handle, rlm_sql_config_t *config, char const *query);
	sql_rcode_t (*sql_store_result)(rlm_sql_handle_t *handle, rlm_sql_config_t *config);

	int (*sql_num_fields)(rlm_sql_handle_t *handle, rlm_sql_config_t *config);
	int (*sql_num_rows)(rlm_sql_handle_t *handle, rlm_sql_config_t *config);
	int (*sql_affected_rows)(rlm_sql_handle_t *handle, rlm_sql_config_t *config);

	sql_rcode_t (*sql_fetch_row)(rlm_sql_handle_t *handle, rlm_sql_config_t *config);
	sql_rcode_t (*sql_free_result)(rlm_sql_handle_t *handle, rlm_sql_config_t *config);

	sql_error_t	sql_error;				//!< Get any errors from the previous query.

	sql_rcode_t (*sql_finish_query)(rlm_sql_handle_t *handle, rlm_sql_config_t *config);
	sql_rcode_t (*sql_finish_select_query)(rlm_sql_handle_t *handle, rlm_sql_config_t *config);

	xlat_escape_t	sql_escape_func;
} rlm_sql_module_t;

struct sql_inst {
	rlm_sql_config_t	myconfig; /* HACK */
	fr_connection_pool_t	*pool;
	rlm_sql_config_t	*config;
	CONF_SECTION		*cs;

	DICT_ATTR const		*sql_user;		//!< Cached pointer to SQL-User-Name
							//!< dictionary attribute.
	exfile_t		*ef;

	void			*handle;
	rlm_sql_module_t	*module;

	int (*sql_set_user)(rlm_sql_t *inst, REQUEST *request, char const *username);
	size_t (*sql_escape_func)(REQUEST *, char *out, size_t outlen, char const *in, void *arg);
	sql_rcode_t (*sql_query)(rlm_sql_t *inst, REQUEST *request, rlm_sql_handle_t **handle, char const *query);
	sql_rcode_t (*sql_select_query)(rlm_sql_t *inst, REQUEST *request, rlm_sql_handle_t **handle, char const *query);
	sql_rcode_t (*sql_fetch_row)(rlm_sql_t *inst, REQUEST *request, rlm_sql_handle_t **handle);

	char const		*name;			//!< Module instance name.
	DICT_ATTR const		*group_da;
};

typedef struct sql_grouplist {
	char			*name;
	struct sql_grouplist	*next;
} rlm_sql_grouplist_t;

int		sql_fr_pair_list_afrom_str(TALLOC_CTX *ctx, REQUEST *request, VALUE_PAIR **first_pair, rlm_sql_row_t row);
int		sql_read_realms(rlm_sql_handle_t *handle);
int		sql_getvpdata(TALLOC_CTX *ctx, rlm_sql_t *inst, REQUEST *request, rlm_sql_handle_t **handle, VALUE_PAIR **pair, char const *query);
int		sql_read_clients(rlm_sql_handle_t *handle);
int		sql_dict_init(rlm_sql_handle_t *handle);
void 		CC_HINT(nonnull (1, 2, 4)) rlm_sql_query_log(rlm_sql_t *inst, REQUEST *request, sql_acct_section_t *section, char const *query);
sql_rcode_t	CC_HINT(nonnull (1, 3, 4)) rlm_sql_select_query(rlm_sql_t *inst, REQUEST *request, rlm_sql_handle_t **handle, char const *query);
sql_rcode_t	CC_HINT(nonnull (1, 3, 4)) rlm_sql_query(rlm_sql_t *inst, REQUEST *request, rlm_sql_handle_t **handle, char const *query);
int		rlm_sql_fetch_row(rlm_sql_t *inst, REQUEST *request, rlm_sql_handle_t **handle);
void		rlm_sql_print_error(rlm_sql_t *inst, REQUEST *request, rlm_sql_handle_t *handle, bool force_debug);
int		sql_set_user(rlm_sql_t *inst, REQUEST *request, char const *username);
#endif