2
2
* rlm_sql_log.c Append the SQL queries in a log file which
3
3
* is read later by the radsqlrelay program
5
* Version: $Id: rlm_sql_log.c,v 1.12 2007/12/15 21:26:51 aland Exp $
7
7
* Author: Nicolas Baradakis <nicolas.baradakis@cegetel.net>
27
27
#include <freeradius-devel/ident.h>
28
RCSID("$Id: rlm_sql_log.c,v 1.12 2007/12/15 21:26:51 aland Exp $")
30
30
#include <freeradius-devel/radiusd.h>
31
31
#include <freeradius-devel/modules.h>
32
#include <freeradius-devel/rad_assert.h>
34
35
#include <sys/stat.h>
38
39
static int sql_log_accounting(void *instance, REQUEST *request);
39
40
static int sql_log_postauth(void *instance, REQUEST *request);
41
#ifndef HAVE_PTHREAD_H
43
* This is a lot simpler than putting ifdef's around
44
* every use of the pthread functions.
46
#define pthread_mutex_lock(a)
47
#define pthread_mutex_trylock(a) (0)
48
#define pthread_mutex_unlock(a)
49
#define pthread_mutex_init(a,b)
50
#define pthread_mutex_destroy(a)
55
42
#define MAX_QUERY_LEN 4096
58
45
* Define a structure for our module configuration.
60
47
typedef struct rlm_sql_log_t {
63
49
char *postauth_query;
64
50
char *sql_user_name;
65
52
char *allowed_chars;
66
53
CONF_SECTION *conf_section;
68
pthread_mutex_t mutex;
79
63
offsetof(rlm_sql_log_t,postauth_query), NULL, ""},
80
64
{"sql_user_name", PW_TYPE_STRING_PTR,
81
65
offsetof(rlm_sql_log_t,sql_user_name), NULL, ""},
66
{"utf8", PW_TYPE_BOOLEAN,
67
offsetof(rlm_sql_log_t,utf8), NULL, "no"},
82
68
{"safe-characters", PW_TYPE_STRING_PTR,
83
69
offsetof(rlm_sql_log_t,allowed_chars), NULL,
84
70
"@abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-_: /"},
116
* Get the name of the current section in the conf file.
118
name = cf_section_name2(conf);
120
name = cf_section_name1(conf);
123
inst->name = strdup(name);
126
101
* If the configuration parameters can't be parsed,
129
104
if (cf_section_parse(conf, inst, module_config) < 0) {
130
radlog(L_ERR, "rlm_sql_log (%s): Unable to parse parameters",
105
radlog(L_ERR, "rlm_sql_log: Unable to parse parameters");
132
106
sql_log_detach(inst);
200
static size_t sql_utf8_escape_func(char *out, size_t outlen, const char *in)
207
* Skip over UTF8 characters
209
utf8 = fr_utf8_char((uint8_t *)in);
211
if (outlen <= utf8) {
225
* Non-printable characters get replaced with their
226
* mime-encoded equivalents.
229
strchr(allowed_chars, *in) == NULL) {
231
* Only 3 or less bytes available.
237
snprintf(out, outlen, "=%02X", (unsigned char) in[0]);
246
* Only one byte left.
232
266
* Add the 'SQL-User-Name' attribute to the packet.
239
273
tmpuser[0] = '\0';
240
274
sqlusername[0] = '\0';
276
rad_assert(request != NULL);
277
rad_assert(request->packet != NULL);
242
279
/* Remove any user attr we added previously */
243
280
pairdelete(&request->packet->vps, PW_SQL_USER_NAME);
254
291
if (tmpuser[0] != '\0') {
255
292
strlcpy(sqlusername, tmpuser, sizeof(tmpuser));
256
DEBUG2("rlm_sql_log (%s): sql_set_user escaped user --> '%s'",
257
inst->name, sqlusername);
293
RDEBUG2("sql_set_user escaped user --> '%s'", sqlusername);
258
294
vp = pairmake("SQL-User-Name", sqlusername, 0);
259
295
if (vp == NULL) {
260
radlog(L_ERR, "%s", librad_errstr);
296
radlog(L_ERR, "%s", fr_strerror());
281
317
/* Add attribute 'SQL-User-Name' */
282
318
if (sql_set_user(inst, request, sqlusername, NULL) <0) {
283
radlog(L_ERR, "rlm_sql_log (%s): Couldn't add SQL-User-Name attribute",
319
radlog_request(L_ERR, 0, request,
320
"Couldn't add SQL-User-Name attribute");
285
321
return RLM_MODULE_FAIL;
288
324
/* Expand variables in the query */
289
325
xlat_query[0] = '\0';
290
radius_xlat(xlat_query, len, query, request, sql_escape_func);
326
radius_xlat(xlat_query, len, query, request,
327
inst->utf8 ? sql_utf8_escape_func : sql_escape_func);
291
328
if (xlat_query[0] == '\0') {
292
radlog(L_ERR, "rlm_sql_log (%s): Couldn't xlat the query %s",
329
radlog_request(L_ERR, 0, request, "Couldn't xlat the query %s",
294
331
return RLM_MODULE_FAIL;
331
368
while (!locked) {
332
369
if ((fd = open(path, O_WRONLY | O_APPEND | O_CREAT, 0666)) < 0) {
333
radlog(L_ERR, "rlm_sql_log (%s): Couldn't open file %s: %s",
334
inst->name, path, strerror(errno));
370
radlog_request(L_ERR, 0, request, "Couldn't open file %s: %s",
371
path, strerror(errno));
335
372
return RLM_MODULE_FAIL;
337
374
if (setlock(fd) != 0) {
338
radlog(L_ERR, "rlm_sql_log (%s): Couldn't lock file %s: %s",
339
inst->name, path, strerror(errno));
375
radlog_request(L_ERR, 0, request, "Couldn't lock file %s: %s",
376
path, strerror(errno));
341
378
return RLM_MODULE_FAIL;
343
380
if (fstat(fd, &st) != 0) {
344
radlog(L_ERR, "rlm_sql_log (%s): Couldn't stat file %s: %s",
345
inst->name, path, strerror(errno));
381
radlog_request(L_ERR, 0, request, "Couldn't stat file %s: %s",
382
path, strerror(errno));
347
384
return RLM_MODULE_FAIL;
349
386
if (st.st_nlink == 0) {
350
DEBUG("rlm_sql_log (%s): File %s removed by another program, retrying",
387
RDEBUG("File %s removed by another program, retrying",
358
395
if ((fp = fdopen(fd, "a")) == NULL) {
359
radlog(L_ERR, "rlm_sql_log (%s): Couldn't associate a stream with file %s: %s",
360
inst->name, path, strerror(errno));
396
radlog_request(L_ERR, 0, request, "Couldn't associate a stream with file %s: %s",
397
path, strerror(errno));
362
399
return RLM_MODULE_FAIL;
380
417
DICT_VALUE *dval;
383
DEBUG("rlm_sql_log (%s): Processing sql_log_accounting", inst->name);
420
rad_assert(request != NULL);
421
rad_assert(request->packet != NULL);
423
RDEBUG("Processing sql_log_accounting");
385
425
/* Find the Acct Status Type. */
386
426
if ((pair = pairfind(request->packet->vps, PW_ACCT_STATUS_TYPE)) == NULL) {
387
radlog(L_ERR, "rlm_sql_log (%s): Packet has no account status type",
427
radlog_request(L_ERR, 0, request, "Packet has no account status type");
389
428
return RLM_MODULE_INVALID;
392
431
/* Search the query in conf section of the module */
393
432
if ((dval = dict_valbyattr(PW_ACCT_STATUS_TYPE, pair->vp_integer)) == NULL) {
394
radlog(L_ERR, "rlm_sql_log (%s): Unsupported Acct-Status-Type = %d",
395
inst->name, pair->vp_integer);
433
radlog_request(L_ERR, 0, request, "Unsupported Acct-Status-Type = %d",
396
435
return RLM_MODULE_NOOP;
398
437
if ((cp = cf_pair_find(inst->conf_section, dval->name)) == NULL) {
399
DEBUG("rlm_sql_log (%s): Couldn't find an entry %s in the config section",
400
inst->name, dval->name);
438
RDEBUG("Couldn't find an entry %s in the config section",
401
440
return RLM_MODULE_NOOP;
403
442
cfquery = cf_pair_value(cp);
420
459
char querystr[MAX_QUERY_LEN];
421
460
rlm_sql_log_t *inst = (rlm_sql_log_t *)instance;
423
DEBUG("rlm_sql_log (%s): Processing sql_log_postauth", inst->name);
462
rad_assert(request != NULL);
464
RDEBUG("Processing sql_log_postauth");
425
466
/* Xlat the query */
426
467
ret = sql_xlat_query(inst, request, inst->postauth_query,