📄 rlm_sqlcounter.c
字号:
/* * rlm_sqlcounter.c * * Version: $Id: rlm_sqlcounter.c,v 1.11 2004/05/15 15:50:26 mgriego Exp $ * * This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Copyright 2001 The FreeRADIUS server project * Copyright 2001 Alan DeKok <aland@ox.org> *//* This module is based directly on the rlm_counter module */#include "config.h"#include "autoconf.h"#include "libradius.h"#include <stdio.h>#include <stdlib.h>#include <string.h>#include <ctype.h>#include "radiusd.h"#include "modules.h"#include "conffile.h"#define MAX_QUERY_LEN 1024#include <time.h>/* Note: When your counter spans more than 1 period (ie 3 months or 2 weeks), this module * probably does NOT do what you want! It calculates the range of dates to count across * by first calculating the End of the Current period and then subtracting the number of * periods you specify from that to determine the beginning of the range. * * For example, if you specify a 3 month counter and today is June 15th, the end of the current * period is June 30. Subtracting 3 months from that gives April 1st. So, the counter will * sum radacct entries from April 1st to June 30. Then, next month, it will sum entries * from May 1st to July 31st. * * To fix this behavior, we need to add some way of storing the Next Reset Time */static const char rcsid[] = "$Id: rlm_sqlcounter.c,v 1.11 2004/05/15 15:50:26 mgriego Exp $";/* * Define a structure for our module configuration. * * These variables do not need to be in a structure, but it's * a lot cleaner to do so, and a pointer to the structure can * be used as the instance handle. */typedef struct rlm_sqlcounter_t { char *counter_name; /* Daily-Session-Time */ char *check_name; /* Max-Daily-Session */ char *key_name; /* User-Name */ char *sqlmod_inst; /* instance of SQL module to use, usually just 'sql' */ char *query; /* SQL query to retrieve current session time */ char *reset; /* daily, weekly, monthly, never or user defined */ time_t reset_time; time_t last_reset; int key_attr; /* attribute number for key field */ int dict_attr; /* attribute number for the counter. */} rlm_sqlcounter_t;/* * A mapping of configuration file names to internal variables. * * Note that the string is dynamically allocated, so it MUST * be freed. When the configuration file parse re-reads the string, * it free's the old one, and strdup's the new one, placing the pointer * to the strdup'd string into 'config.string'. This gets around * buffer over-flows. */static CONF_PARSER module_config[] = { { "counter-name", PW_TYPE_STRING_PTR, offsetof(rlm_sqlcounter_t,counter_name), NULL, NULL }, { "check-name", PW_TYPE_STRING_PTR, offsetof(rlm_sqlcounter_t,check_name), NULL, NULL }, { "key", PW_TYPE_STRING_PTR, offsetof(rlm_sqlcounter_t,key_name), NULL, NULL }, { "sqlmod-inst", PW_TYPE_STRING_PTR, offsetof(rlm_sqlcounter_t,sqlmod_inst), NULL, NULL }, { "query", PW_TYPE_STRING_PTR, offsetof(rlm_sqlcounter_t,query), NULL, NULL }, { "reset", PW_TYPE_STRING_PTR, offsetof(rlm_sqlcounter_t,reset), NULL, NULL }, { NULL, -1, 0, NULL, NULL }};static int find_next_reset(rlm_sqlcounter_t *data, time_t timeval){ int ret=0; unsigned int num=1; char last = 0; struct tm *tm, s_tm; char sCurrentTime[40], sNextTime[40]; tm = localtime_r(&timeval, &s_tm); strftime(sCurrentTime, sizeof(sCurrentTime),"%Y-%m-%d %H:%M:%S",tm); tm->tm_sec = tm->tm_min = 0; if (data->reset == NULL) return -1; if (isdigit((int) data->reset[0])){ unsigned int len=0; len = strlen(data->reset); if (len == 0) return -1; last = data->reset[len - 1]; if (!isalpha((int) last)) last = 'd';/* num = atoi(data->reset); */ DEBUG("rlm_sqlcounter: num=%d, last=%c",num,last); } if (strcmp(data->reset, "hourly") == 0 || last == 'h') { /* * Round up to the next nearest hour. */ tm->tm_hour += num; data->reset_time = mktime(tm); } else if (strcmp(data->reset, "daily") == 0 || last == 'd') { /* * Round up to the next nearest day. */ tm->tm_hour = 0; tm->tm_mday += num; data->reset_time = mktime(tm); } else if (strcmp(data->reset, "weekly") == 0 || last == 'w') { /* * Round up to the next nearest week. */ tm->tm_hour = 0; tm->tm_mday += (7 - tm->tm_wday) +(7*(num-1)); data->reset_time = mktime(tm); } else if (strcmp(data->reset, "monthly") == 0 || last == 'm') { tm->tm_hour = 0; tm->tm_mday = 1; tm->tm_mon += num; data->reset_time = mktime(tm); } else if (strcmp(data->reset, "never") == 0) { data->reset_time = 0; } else { radlog(L_ERR, "rlm_sqlcounter: Unknown reset timer \"%s\"", data->reset); return -1; } strftime(sNextTime, sizeof(sNextTime),"%Y-%m-%d %H:%M:%S",tm); DEBUG2("rlm_sqlcounter: Current Time: %d [%s], Next reset %d [%s]", (int)timeval,sCurrentTime,(int)data->reset_time, sNextTime); return ret;}/* I don't believe that this routine handles Daylight Saving Time adjustments properly. Any suggestions?*/static int find_prev_reset(rlm_sqlcounter_t *data, time_t timeval){ int ret=0; unsigned int num=1; char last = 0; struct tm *tm, s_tm; char sCurrentTime[40], sPrevTime[40]; tm = localtime_r(&timeval, &s_tm); strftime(sCurrentTime, sizeof(sCurrentTime),"%Y-%m-%d %H:%M:%S",tm); tm->tm_sec = tm->tm_min = 0; if (data->reset == NULL) return -1; if (isdigit((int) data->reset[0])){ unsigned int len=0; len = strlen(data->reset); if (len == 0) return -1; last = data->reset[len - 1]; if (!isalpha((int) last)) last = 'd'; num = atoi(data->reset); DEBUG("rlm_sqlcounter: num=%d, last=%c",num,last); } if (strcmp(data->reset, "hourly") == 0 || last == 'h') { /* * Round down to the prev nearest hour. */ tm->tm_hour -= num - 1; data->last_reset = mktime(tm); } else if (strcmp(data->reset, "daily") == 0 || last == 'd') { /* * Round down to the prev nearest day. */ tm->tm_hour = 0; tm->tm_mday -= num - 1; data->last_reset = mktime(tm); } else if (strcmp(data->reset, "weekly") == 0 || last == 'w') { /* * Round down to the prev nearest week. */ tm->tm_hour = 0; tm->tm_mday -= (7 - tm->tm_wday) +(7*(num-1)); data->last_reset = mktime(tm); } else if (strcmp(data->reset, "monthly") == 0 || last == 'm') { tm->tm_hour = 0; tm->tm_mday = 1; tm->tm_mon -= num - 1; data->last_reset = mktime(tm); } else if (strcmp(data->reset, "never") == 0) { data->reset_time = 0; } else { radlog(L_ERR, "rlm_sqlcounter: Unknown reset timer \"%s\"", data->reset); return -1; } strftime(sPrevTime, sizeof(sPrevTime),"%Y-%m-%d %H:%M:%S",tm); DEBUG2("rlm_sqlcounter: Current Time: %d [%s], Prev reset %d [%s]", (int)timeval,sCurrentTime,(int)data->last_reset, sPrevTime); return ret;}/* * Replace %<whatever> in a string. * * %b last_reset * %e reset_time * %k key_name * %S sqlmod_inst * */static int sqlcounter_expand(char *out, int outlen, const char *fmt, void *instance){ rlm_sqlcounter_t *data = (rlm_sqlcounter_t *) instance; int c,freespace; const char *p; char *q; char tmpdt[40]; /* For temporary storing of dates */ int openbraces=0; q = out; for (p = fmt; *p ; p++) { /* Calculate freespace in output */ freespace = outlen - (q - out); if (freespace <= 1) break; c = *p; if ((c != '%') && (c != '$') && (c != '\\')) { /* * We check if we're inside an open brace. If we are * then we assume this brace is NOT literal, but is * a closing brace and apply it */ if((c == '}') && openbraces) { openbraces--; continue; } *q++ = *p; continue; } if (*++p == '\0') break; if (c == '\\') switch(*p) { case '\\': *q++ = *p; break; case 't': *q++ = '\t'; break; case 'n': *q++ = '\n'; break; default: *q++ = c; *q++ = *p; break; } else if (c == '%') switch(*p) { case '%': *q++ = *p; case 'b': /* last_reset */ sprintf(tmpdt, "%lu", data->last_reset); strNcpy(q, tmpdt, freespace); q += strlen(q); break; case 'e': /* reset_time */ sprintf(tmpdt, "%lu", data->reset_time); strNcpy(q, tmpdt, freespace); q += strlen(q); break; case 'k': /* Key Name */ strNcpy(q, data->key_name, freespace); q += strlen(q); break; case 'S': /* SQL module instance */ strNcpy(q, data->sqlmod_inst, freespace); q += strlen(q); break; default: *q++ = '%'; *q++ = *p; break; } } *q = '\0'; DEBUG2("sqlcounter_expand: '%s'", out); return strlen(out);}/* * See if the counter matches. */static int sqlcounter_cmp(void *instance, REQUEST *req, VALUE_PAIR *request, VALUE_PAIR *check, VALUE_PAIR *check_pairs, VALUE_PAIR **reply_pairs){ rlm_sqlcounter_t *data = (rlm_sqlcounter_t *) instance; int counter; char querystr[MAX_QUERY_LEN]; char responsestr[MAX_QUERY_LEN];
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -