--- /dev/null
+#define CHECKRAD1 "/usr/sbin/checkrad"
+#define CHECKRAD2 "/usr/local/sbin/checkrad"
+
+/* Hack for funky ascend ports on MAX 4048 (and probably others)
+ The "NAS-Port-Id" value is "xyyzz" where "x" = 1 for digital, 2 for analog;
+ "yy" = line number (1 for first PRI/T1/E1, 2 for second, so on);
+ "zz" = channel number (on the PRI or Channelized T1/E1).
+ This should work with normal terminal servers, unless you have a TS with
+ more than 9999 ports ;^).
+ The "ASCEND_CHANNELS_PER_LINE" is the number of channels for each line into
+ the unit. For my US/PRI that's 23. A US/T1 would be 24, and a
+ European E1 would be 30 (I think ... never had one ;^).
+ This will NOT change the "NAS-Port-Id" reported in the detail log. This
+ is simply to fix the dynamic IP assignments a la Cistron.
+ WARNING: This hack works for me, but I only have one PRI!!! I've not
+ tested it on 2 or more (or with models other than the Max 4048)
+ Use at your own risk!
+ -- dgreer@austintx.com
+*/
+
+#define ASCEND_PORT_HACK
+#define ASCEND_CHANNELS_PER_LINE 23
+
+#define CISCO_ACCOUNTING_HACK
+
+/* SQL defines */
+#define SQL_LOCK_LEN sizeof(SQLACCTREC)
+#define SQLQUERYLOG "/var/log/radacct/radius.sql"
+#define SQLCONFIGFILE "rlm_sql.conf"
+#define SQLBACKUP "/var/log/radacct/sqlbackup.dat"
+#define SQLBIGREC 32
+#define SQLLILREC 15
+
+#define MAX_COMMUNITY_LEN 50
+#define MAX_SQL_SOCKS 5
+#define MAX_TABLE_LEN 20
+#define MAX_AUTH_QUERY_LEN 256
+#define AUTH_STRING_LEN 128
static int rlm_sql_init(int argc, char **argv) {
- FILE *sqlfd;
- char dummystr[64];
- char namestr[64];
- int line_no;
- char buffer[256];
- char sqlfile[256];
-
- if ((sql = malloc(sizeof(SQL))) == NULL) {
- log(L_ERR|L_CONS, "no memory");
- exit(1);
- }
-
- strcpy(sql->config.sql_server,"localhost");
- strcpy(sql->config.sql_login,"");
- strcpy(sql->config.sql_password,"");
- strcpy(sql->config.sql_db,"radius");
- strcpy(sql->config.sql_authcheck_table,"radcheck");
- strcpy(sql->config.sql_authreply_table,"radreply");
- strcpy(sql->config.sql_groupcheck_table,"radgroupcheck");
- strcpy(sql->config.sql_groupreply_table,"radgroupreply");
- strcpy(sql->config.sql_usergroup_table,"usergroup");
- strcpy(sql->config.sql_realmgroup_table,"realmgroup");
- strcpy(sql->config.sql_acct_table,"radacct");
- strcpy(sql->config.sql_nas_table,"nas");
- strcpy(sql->config.sql_realm_table, "realms");
- strcpy(sql->config.sql_dict_table,"dictionary");
- sql->config.sqltrace = 0;
- sql->config.sql_keepopen = 0;
-
- sprintf(sqlfile, "%s/%s", radius_dir, SQLCONFIGFILE);
-
- if((sqlfd = fopen(sqlfile, "r")) == (FILE *)NULL) {
- log(L_ERR,"could not read sql configuration file %s",sqlfile);
- return(-1);
- }
-
- line_no = 0;
- while(fgets(buffer, sizeof(buffer), sqlfd) != (char *)NULL) {
- line_no++;
-
- /* Skip empty space */
- if(*buffer == '#' || *buffer == '\0' || *buffer == '\n') {
- continue;
- }
-
- if(strncasecmp(buffer, "type", 4) == 0) {
- /* Read the SERVER line */
- if(sscanf(buffer, "%s%s", dummystr, namestr) != 2) {
- log(L_ERR,"invalid attribute on line %d of sqlserver file %s", line_no,sqlfile);
- } else {
- strcpy(sql->config.sql_type,namestr);
- }
- }
- if(strncasecmp(buffer, "server", 6) == 0) {
- /* Read the SERVER line */
- if(sscanf(buffer, "%s%s", dummystr, namestr) != 2) {
- log(L_ERR,"invalid attribute on line %d of sqlserver file %s", line_no,sqlfile);
- } else {
- strcpy(sql->config.sql_server,namestr);
- }
- }
- if(strncasecmp(buffer, "port", 4) == 0) {
- /* Read the SERVER line */
- if(sscanf(buffer, "%s%s", dummystr, namestr) != 2) {
- log(L_ERR,"invalid attribute on line %d of sqlserver file %s", line_no,sqlfile);
- } else {
- sql->config.sql_port = strtol(namestr, (char **)NULL, 10);
- }
- }
- if(strncasecmp(buffer, "login", 5) == 0) {
- /* Read the LOGIN line */
- if(sscanf(buffer, "%s%s", dummystr, namestr) != 2) {
- log(L_ERR,"invalid attribute on line %d of sqlserver file %s", line_no,sqlfile);
- } else {
- strcpy(sql->config.sql_login,namestr);
- }
- }
- if(strncasecmp(buffer, "password", 8) == 0) {
- /* Read the PASSWORD line */
- if(sscanf(buffer, "%s%s", dummystr, namestr) != 2) {
- log(L_ERR,"invalid attribute on line %d of sqlserver file %s", line_no,sqlfile);
- } else {
- strcpy(sql->config.sql_password,namestr);
- }
- }
- if(strncasecmp(buffer, "radius_db", 9) == 0) {
- /* Read the RADIUS_DB line */
- if(sscanf(buffer, "%s%s", dummystr, namestr) != 2) {
- log(L_ERR,"invalid attribute on line %d of sqlserver file %s", line_no,sqlfile);
- } else {
- strcpy(sql->config.sql_db,namestr);
- }
- }
- if(strncasecmp(buffer, "authcheck_table", 15) == 0) {
- /* Read the AUTHCHECK_TABLE line */
- if(sscanf(buffer, "%s%s", dummystr, namestr) != 2) {
- log(L_ERR,"invalid attribute on line %d of sqlserver file %s", line_no,sqlfile);
- } else {
- strncpy(sql->config.sql_authcheck_table,namestr, MAX_TABLE_LEN);
- }
- }
- if(strncasecmp(buffer, "authreply_table", 15) == 0) {
- /* Read the AUTHREPLY_TABLE line */
- if(sscanf(buffer, "%s%s", dummystr, namestr) != 2) {
- log(L_ERR,"invalid attribute on line %d of sqlserver file %s", line_no,sqlfile);
- } else {
- strncpy(sql->config.sql_authreply_table,namestr, MAX_TABLE_LEN);
- }
- }
- if(strncasecmp(buffer, "groupcheck_table", 16) == 0) {
- /* Read the GROUPCHECK_TABLE line */
- if(sscanf(buffer, "%s%s", dummystr, namestr) != 2) {
- log(L_ERR,"invalid attribute on line %d of sqlserver file %s", line_no,sqlfile);
- } else {
- strncpy(sql->config.sql_groupcheck_table,namestr, MAX_TABLE_LEN);
- }
- }
- if(strncasecmp(buffer, "groupreply_table", 16) == 0) {
- /* Read the GROUP_REPLY_TABLE line */
- if(sscanf(buffer, "%s%s", dummystr, namestr) != 2) {
- log(L_ERR,"invalid attribute on line %d of sqlserver file %s", line_no,sqlfile);
- } else {
- strncpy(sql->config.sql_groupreply_table,namestr, MAX_TABLE_LEN);
- }
- }
- if(strncasecmp(buffer, "usergroup_table", 15) == 0) {
- /* Read the USERGROUP_TABLE line */
- if(sscanf(buffer, "%s%s", dummystr, namestr) != 2) {
- log(L_ERR,"invalid attribute on line %d of sqlserver file %s", line_no,sqlfile);
- } else {
- strncpy(sql->config.sql_usergroup_table,namestr, MAX_TABLE_LEN);
- }
- }
- if(strncasecmp(buffer, "realmgroup_table", 16) == 0) {
- /* Read the REALMGROUP_TABLE line */
- if(sscanf(buffer, "%s%s", dummystr, namestr) != 2) {
- log(L_ERR,"invalid attribute on line %d of sqlserver file %s", line_no,sqlfile);
- } else {
- strncpy(sql->config.sql_realmgroup_table,namestr, MAX_TABLE_LEN);
- }
- }
- if(strncasecmp(buffer, "acct_table", 10) == 0) {
- /* Read the ACCT_TABLE line */
- if(sscanf(buffer, "%s%s", dummystr, namestr) != 2) {
- log(L_ERR,"invalid attribute on line %d of sqlserver file %s", line_no,sqlfile);
- } else {
- strncpy(sql->config.sql_acct_table,namestr, MAX_TABLE_LEN);
- }
- }
- if(strncasecmp(buffer, "nas_table", 9) == 0) {
- /* Read the NAS_TABLE line */
- if(sscanf(buffer, "%s%s", dummystr, namestr) != 2) {
- log(L_ERR,"invalid attribute on line %d of sqlserver file %s", line_no,sqlfile);
- } else {
- strncpy(sql->config.sql_nas_table,namestr, MAX_TABLE_LEN);
- }
- }
- if(strncasecmp(buffer, "realm_table", 9) == 0) {
- /* Read the REALM_TABLE line */
- if(sscanf(buffer, "%s%s", dummystr, namestr) != 2) {
- log(L_ERR,"invalid attribute on line %d of sqlserver file %s", line_no,sqlfile);
- } else {
- strncpy(sql->config.sql_realm_table,namestr, MAX_TABLE_LEN);
- }
- }
- if(strncasecmp(buffer, "dict_table", 9) == 0) {
- /* Read the DICT_TABLE line */
- if(sscanf(buffer, "%s%s", dummystr, namestr) != 2) {
- log(L_ERR,"invalid attribute on line %d of sqlserver file %s", line_no,sqlfile);
- } else {
- strncpy(sql->config.sql_dict_table,namestr, MAX_TABLE_LEN);
- }
- }
- if(strncasecmp(buffer, "sqltrace", 8) == 0) {
- /* Read the SQLTRACE line */
- if(sscanf(buffer, "%s%s", dummystr, namestr) != 2) {
- log(L_ERR,"invalid attribute on line %d of sqlserver file %s", line_no,sqlfile);
- } else {
- if(strncasecmp(namestr, "on", 2) == 0) {
- sql->config.sqltrace = 1;
- } else {
- sql->config.sqltrace = 0;
- }
- }
- }
- if(strncasecmp(buffer, "keepopen", 8) == 0) {
- /* Read the KEEPOPEN line */
- if(sscanf(buffer, "%s%s", dummystr, namestr) != 2) {
- log(L_ERR,"invalid attribute on line %d of sqlserver file %s", line_no,sqlfile);
- } else {
- if(strncasecmp(namestr, "yes", 3) == 0) {
- sql->config.sql_keepopen = 1;
- } else {
- sql->config.sql_keepopen = 0;
- }
- }
- }
-
- }
- fclose(sqlfd);
-
- log(L_INFO,"SQL: Attempting to connect to %s@%s:%s",
- sql->config.sql_login,
- sql->config.sql_server,
- sql->config.sql_db);
-
- if (sql->config.sql_keepopen)
- sql_connect();
+ sql_init(0);
return 0;
}
}
-static int rlm_sql_authorize(REQUEST *request, char *name, VALUE_PAIR **check_pairs, VALUE_PAIR **reply_pairs) {
+static int rlm_sql_authorize(REQUEST *request, VALUE_PAIR **check_pairs, VALUE_PAIR **reply_pairs) {
int nas_port = 0;
VALUE_PAIR *check_tmp = NULL;
VALUE_PAIR *reply_tmp = NULL;
VALUE_PAIR *tmp;
int found = 0;
-#ifdef NT_DOMAIN_HACK
+ char *name;
+ SQLSOCK *socket;
+ #ifdef NT_DOMAIN_HACK
char *ptr;
char newname[AUTH_STRING_LEN];
-#endif
-
+ #endif
- /*
- * Check for valid input, zero length names not permitted
- */
- if (name[0] == 0) {
- log(L_ERR, "zero length username not permitted\n");
- return -1;
- }
+ name = request->username->strvalue;
- /*
- * Find the NAS port ID.
- */
- if ((tmp = pairfind(request->packet->vps, PW_NAS_PORT_ID)) != NULL)
- nas_port = tmp->lvalue;
-
- /*
- * Find the entry for the user.
- */
-
-#ifdef NT_DOMAIN_HACK
- /*
- * Windows NT machines often authenticate themselves as
- * NT_DOMAIN\username. Try to be smart about this.
- *
- * FIXME: should we handle this as a REALM ?
- */
- if ((ptr = strchr(name, '\\')) != NULL) {
- strncpy(newname, ptr + 1, sizeof(newname));
- newname[sizeof(newname) - 1] = 0;
- strcpy(name, newname);
- }
-#endif /* NT_DOMAIN_HACK */
+ /*
+ * Check for valid input, zero length names not permitted
+ */
+ if (name[0] == 0) {
+ log(L_ERR, "zero length username not permitted\n");
+ return -1;
+ }
+ socket = sql_get_socket();
+
+ /*
+ * Find the NAS port ID.
+ */
+ if ((tmp = pairfind(request->packet->vps, PW_NAS_PORT_ID)) != NULL)
+ nas_port = tmp->lvalue;
+
+ /*
+ * Find the entry for the user.
+ */
+
+ #ifdef NT_DOMAIN_HACK
+ /*
+ * Windows NT machines often authenticate themselves as
+ * NT_DOMAIN\username. Try to be smart about this.
+ *
+ * FIXME: should we handle this as a REALM ?
+ */
+ if ((ptr = strchr(name, '\\')) != NULL) {
+ strncpy(newname, ptr + 1, sizeof(newname));
+ newname[sizeof(newname) - 1] = 0;
+ strcpy(name, newname);
+ }
+ #endif /* NT_DOMAIN_HACK */
+
+
+ if ((found = sql_getvpdata(socket, sql->config->sql_authcheck_table, &check_tmp, name, PW_VP_USERDATA)) > 0) {
+ sql_getvpdata(socket, sql->config->sql_groupcheck_table, &check_tmp, name, PW_VP_GROUPDATA);
+ sql_getvpdata(socket, sql->config->sql_authreply_table, &reply_tmp, name, PW_VP_USERDATA);
+ sql_getvpdata(socket, sql->config->sql_groupreply_table, &reply_tmp, name, PW_VP_GROUPDATA);
+ } else {
+
+ int gcheck, greply;
+ gcheck = sql_getvpdata(socket, sql->config->sql_groupcheck_table, &check_tmp, "DEFAULT", PW_VP_GROUPDATA);
+ greply = sql_getvpdata(socket, sql->config->sql_groupreply_table, &reply_tmp, "DEFAULT", PW_VP_GROUPDATA);
+ if (gcheck && greply)
+ found = 1;
+ }
+ sql_release_socket(socket);
+
+ if (!found) {
+ DEBUG2("User %s not found and DEFAULT not found", name);
+ return RLM_AUTZ_NOTFOUND;
+ }
- if ((found = sql_getvpdata(sql->config.sql_authcheck_table, &check_tmp, name, PW_VP_USERDATA)) <= 0)
+ if (paircmp(request->packet->vps, check_tmp, reply_tmp) != 0) {
+ DEBUG2("Pairs do not match [%s]", name);
return RLM_AUTZ_NOTFOUND;
- sql_getvpdata(sql->config.sql_groupcheck_table, &check_tmp, name, PW_VP_GROUPDATA);
- sql_getvpdata(sql->config.sql_authreply_table, &reply_tmp, name, PW_VP_USERDATA);
- sql_getvpdata(sql->config.sql_groupreply_table, &reply_tmp, name, PW_VP_GROUPDATA);
-
- pairmove(reply_pairs, &reply_tmp);
- pairmove(check_pairs, &check_tmp);
- pairfree(reply_tmp);
- pairfree(check_tmp);
-
- /*
- * Fix dynamic IP address if needed.
- */
- if ((tmp = pairfind(*reply_pairs, PW_ADD_PORT_TO_IP_ADDRESS)) != NULL){
- if (tmp->lvalue != 0) {
- tmp = pairfind(*reply_pairs, PW_FRAMED_IP_ADDRESS);
- if (tmp) {
- /*
- * FIXME: This only works because IP
- * numbers are stored in host order
- * everywhere in this program.
- */
-#ifdef ASCEND_PORT_HACK
- nas_port = ascend_port_number(nas_port);
-#endif
- tmp->lvalue += nas_port;
- }
- }
- pairdelete(reply_pairs, PW_ADD_PORT_TO_IP_ADDRESS);
}
+
+ pairmove(reply_pairs, &reply_tmp);
+ pairmove(check_pairs, &check_tmp);
+ pairfree(reply_tmp);
+ pairfree(check_tmp);
+
+
+ /*
+ * Fix dynamic IP address if needed.
+ */
+ if ((tmp = pairfind(*reply_pairs, PW_ADD_PORT_TO_IP_ADDRESS)) != NULL){
+ if (tmp->lvalue != 0) {
+ tmp = pairfind(*reply_pairs, PW_FRAMED_IP_ADDRESS);
+ if (tmp) {
+ /*
+ * FIXME: This only works because IP
+ * numbers are stored in host order
+ * everywhere in this program.
+ */
+ tmp->lvalue += nas_port;
+ }
+ }
+ pairdelete(reply_pairs, PW_ADD_PORT_TO_IP_ADDRESS);
+ }
- /*
- * Remove server internal parameters.
- */
return RLM_AUTZ_OK;
}
-static int rlm_sql_authenticate(REQUEST *request, char *user, char *password)
-{
+static int rlm_sql_authenticate(REQUEST *request) {
+
VALUE_PAIR *auth_pair;
SQL_ROW row;
+ SQLSOCK *socket;
char *querystr;
char *escaped_user;
+ char *user;
+ char *password;
char query[] = "SELECT Value FROM %s WHERE UserName = '%s' AND Attribute = 'Password'";
+ user = request->username->strvalue;
+
if ((auth_pair = pairfind(request->packet->vps, PW_AUTHTYPE)) == NULL)
return RLM_AUTH_REJECT;
log(L_ERR|L_CONS, "no memory");
exit(1);
}
- if((escaped_user = sql_escape_string(user)) == NULL) {
- log(L_ERR|L_CONS, "no memory");
- exit(1);
- }
- if((querystr = malloc(strlen(escaped_user)+strlen(sql->config.sql_authcheck_table)+sizeof(query)))
+ sql_escape_string(escaped_user, user, strlen(user));
+
+ if((querystr = malloc(strlen(escaped_user)+strlen(sql->config->sql_authcheck_table)+sizeof(query)))
== NULL) {
log(L_ERR|L_CONS, "no memory");
exit(1);
}
- sprintf(querystr, query, sql->config.sql_authcheck_table, escaped_user);
+ sprintf(querystr, query, sql->config->sql_authcheck_table, escaped_user);
free(escaped_user);
free(query);
- sql_select_query(sql->AcctSock, querystr);
- row = sql_fetch_row(sql->AcctSock);
- sql_finish_select_query(sql->AcctSock);
+ socket = sql_get_socket();
+
+ sql_select_query(socket, querystr);
+ row = sql_fetch_row(socket);
+ sql_finish_select_query(socket);
if (strncmp( password, row[0],strlen(password)) != 0)
return RLM_AUTH_REJECT;
else
return RLM_AUTH_OK;
-
-
-
-
}
static int rlm_sql_accounting(REQUEST *request) {
- time_t nowtime;
- struct tm *tim;
- char datebuf[20];
- int *sqlpid;
- int sqlstatus;
- FILE *backupfile;
- struct stat backup;
- char *valbuf;
- VALUE_PAIR *pair;
-
-
- if ((sql->sqlrecord = malloc(sizeof(SQLREC))) == NULL) {
- log(L_ERR|L_CONS, "no memory");
- exit(1);
- }
-
- pair = request->packet->vps;
- strcpy(sql->sqlrecord->Realm, "");
- while(pair != (VALUE_PAIR *)NULL) {
-
-
-
- /* Check the pairs to see if they are anything we are interested in. */
- switch(pair->attribute) {
- case PW_ACCT_SESSION_ID:
- strncpy(sql->sqlrecord->AcctSessionId, pair->strvalue, SQLBIGREC);
- break;
-
- case PW_USER_NAME:
- strncpy(sql->sqlrecord->UserName, pair->strvalue, SQLBIGREC);
- break;
-
- case PW_NAS_IP_ADDRESS:
- ip_ntoa(sql->sqlrecord->NASIPAddress, pair->lvalue);
- //ipaddr2str(sql->sqlrecord->NASIPAddress, pair->lvalue);
- break;
-
- case PW_NAS_PORT_ID:
- sql->sqlrecord->NASPortId = pair->lvalue;
- break;
-
- case PW_NAS_PORT_TYPE:
- valbuf = (char *)dict_valgetname(pair->lvalue, pair->name);
- if(valbuf != (char *)NULL) {
- strncpy(sql->sqlrecord->NASPortType, valbuf, SQLBIGREC);
- }
- break;
-
- case PW_ACCT_STATUS_TYPE:
- sql->sqlrecord->AcctStatusTypeId = pair->lvalue;
- valbuf = (char *)dict_valgetname(pair->lvalue, pair->name);
- if(valbuf != (char *)NULL) {
- strncpy(sql->sqlrecord->AcctStatusType, valbuf, SQLBIGREC);
- }
- break;
-
- case PW_ACCT_SESSION_TIME:
- sql->sqlrecord->AcctSessionTime = pair->lvalue;
- break;
-
- case PW_ACCT_AUTHENTIC:
- valbuf = (char *)dict_valgetname(pair->lvalue, pair->name);
- if(valbuf != (char *)NULL) {
- strncpy(sql->sqlrecord->AcctAuthentic, valbuf, SQLBIGREC);
- }
- break;
-
- case PW_CONNECT_INFO:
- strncpy(sql->sqlrecord->ConnectInfo, pair->strvalue, SQLBIGREC);
- break;
-
- case PW_ACCT_INPUT_OCTETS:
- sql->sqlrecord->AcctInputOctets = pair->lvalue;
- break;
-
- case PW_ACCT_OUTPUT_OCTETS:
- sql->sqlrecord->AcctOutputOctets = pair->lvalue;
- break;
-
- case PW_CALLED_STATION_ID:
- strncpy(sql->sqlrecord->CalledStationId, pair->strvalue, SQLLILREC);
- break;
-
- case PW_CALLING_STATION_ID:
- strncpy(sql->sqlrecord->CallingStationId, pair->strvalue, SQLLILREC);
- break;
-
-/* case PW_ACCT_TERMINATE_CAUSE:
- valbuf = (char *)dict_valgetname(pair->lvalue, pair->name);
- if(valbuf != (char *)NULL) {
- strncpy(sql->sqlrecord->AcctTerminateCause, valbuf, SQLBIGREC);
- }
- break;
-*/
-
-
- case PW_SERVICE_TYPE:
- valbuf = (char *)dict_valgetname(pair->lvalue, pair->name);
- if(valbuf != (char *)NULL) {
- strncpy(sql->sqlrecord->ServiceType, valbuf, SQLBIGREC);
- }
- break;
-
- case PW_FRAMED_PROTOCOL:
- valbuf = (char *)dict_valgetname(pair->lvalue, pair->name);
- if(valbuf != (char *)NULL) {
- strncpy(sql->sqlrecord->FramedProtocol, valbuf, SQLBIGREC);
- }
- break;
-
- case PW_FRAMED_IP_ADDRESS:
- ip_ntoa(sql->sqlrecord->FramedIPAddress, pair->lvalue);
- //ipaddr2str(sql->sqlrecord->FramedIPAddress, pair->lvalue);
- break;
-
- case PW_ACCT_DELAY_TIME:
- sql->sqlrecord->AcctDelayTime = pair->lvalue;
- break;
-
- default:
- break;
- }
-
- pair = pair->next;
- }
-
-
- nowtime = time(0) - sql->sqlrecord->AcctDelayTime;
- tim = localtime(&nowtime);
- strftime(datebuf, sizeof(datebuf), "%Y%m%d%H%M%S", tim);
-
- strncpy(sql->sqlrecord->AcctTimeStamp, datebuf, 20);
-
-
- /* If backup file exists we know the database was down */
- if(stat(SQLBACKUP, &backup) == 0) {
- if(backup.st_size > 0) {
-
- /* We'll fork a child to load records in the backup file */
- (pid_t)sqlpid = fork();
- if(sqlpid > 0) {
-
- /* suspend the parent while child reads records */
- while(waitpid((pid_t)sqlpid, &sqlstatus, 0) != (pid_t)sqlpid);
- }
- /* Child Process */
- if(sqlpid == 0) {
- if((backupfile = fopen(SQLBACKUP, "rwb")) == (FILE *)NULL) {
- log(L_ERR, "Acct: (Child) Couldn't open file %s", SQLBACKUP);
- exit(1);
- }
-
- /* Lock the mysql backup file, prefer lockf() over flock(). */
-#if defined(F_LOCK) && !defined( BSD)
- (void)lockf((int)backupfile, (int)F_LOCK, (off_t)SQL_LOCK_LEN);
-#else
- (void)flock(backupfile, SQL_LOCK_LEN);
-#endif
-
- log(L_INFO, "Acct: Clearing out sql backup file - %s", SQLBACKUP);
-
- while(!feof(backupfile)) {
- if(fread(sql->backuprecord, sizeof(SQLREC), 1, backupfile) == 1) {
-
- /* pass our filled structure to the
- function that will write to the database */
- if (sql_save_acct(sql->backuprecord) == 0)
- return RLM_ACCT_FAIL_SOFT;
-
- }
-
- }
- unlink((const char *)SQLBACKUP);
- exit(0);
- }
- }
- }
- if (sql_save_acct(sql->sqlrecord) == 0)
- return RLM_ACCT_FAIL_SOFT;
- if (!sql->config.sql_keepopen) {
- sql_close(sql->AcctSock);
- sql->AcctSock = NULL;
- }
-
return RLM_ACCT_OK;
}
#include "sql_module.h"
-#define QUERYLOG "/var/log/radacct/radius.sql"
-#define SQLCONFIGFILE "rlm_sql.conf"
-#define SQLBACKUP "/var/log/radacct/sqlbackup.dat"
-#define CHECKRAD1 "/usr/sbin/checkrad"
-#define CHECKRAD2 "/usr/local/sbin/checkrad"
-
-#define SQLBIGREC 32
-#define SQLLILREC 16
#define PW_VP_USERDATA 1
#define PW_VP_GROUPDATA 2
#define PW_VP_REALMDATA 3
-#define MAX_TABLE_LEN 20
-#define MAX_AUTH_QUERY_LEN 256
-
typedef struct sqlrec {
char AcctSessionId[SQLBIGREC];
char UserName[SQLBIGREC];
char FramedProtocol[SQLBIGREC];
char FramedIPAddress[SQLLILREC];
unsigned long AcctDelayTime;
-} SQLREC;
-
-typedef struct sqlconfig {
- char sql_type[40];
- char sql_server[40];
- int sql_port;
- char sql_login[20];
- char sql_password[20];
- char sql_db[20];
- char sql_acct_table[MAX_TABLE_LEN];
- char sql_authcheck_table[MAX_TABLE_LEN];
- char sql_authreply_table[MAX_TABLE_LEN];
- char sql_groupcheck_table[MAX_TABLE_LEN];
- char sql_groupreply_table[MAX_TABLE_LEN];
- char sql_usergroup_table[MAX_TABLE_LEN];
- char sql_realm_table[MAX_TABLE_LEN];
- char sql_realmgroup_table[MAX_TABLE_LEN];
- char sql_nas_table[MAX_TABLE_LEN];
- char sql_dict_table[MAX_TABLE_LEN];
- int sql_keepopen;
- int sqltrace;
-} SQLCONFIG;
-
-typedef struct sql {
- SQLSOCK *AuthSock;
- SQLSOCK *AcctSock;
- SQLREC *sqlrecord;
- SQLREC *backuprecord;
- SQLCONFIG config;
-} SQL;
-
-#define SQL_LOCK_LEN sizeof(SQLREC)
-
-int sql_start();
-int sql_save_acct(SQLREC *sqlrecord);
-int sql_userparse(VALUE_PAIR **first_pair, SQL_ROW row);
-int sql_checksocket(const char *facility);
-int sql_getvpdata(char *table, VALUE_PAIR **vp, char *user, int mode);
-int sql_check_multi(char *name, VALUE_PAIR *request, int maxsimul);
-
+} SQLACCTREC;
+
+int sql_init(int reload);
+int sql_init_socket(int reload);
+int sql_close_socket(SQLSOCK *socket);
+SQLSOCK *sql_get_socket(void);
+int sql_release_socket(SQLSOCK *socket);
+int sql_save_acct(SQLSOCK *socket, SQLACCTREC *sqlrecord);
+int sql_userparse(VALUE_PAIR **first_pair, SQL_ROW row, int mode);
+int sql_read_realms(SQLSOCK *socket);
+int sql_getvpdata(SQLSOCK *socket, char *table, VALUE_PAIR **vp, char *user, int mode);
+int sql_check_multi(SQLSOCK *socket, char *name, VALUE_PAIR *request, int maxsimul);
+int sql_read_naslist(SQLSOCK *socket);
+int sql_read_clients(SQLSOCK *socket);
+int sql_dict_init(SQLSOCK *socket);
SQL *sql;
-
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/file.h>
#include <sys/stat.h>
#include <netinet/in.h>
-#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/wait.h>
-#include <string.h>
-
#include "radiusd.h"
#include "rlm_sql.h"
+/*************************************************************************
+ *
+ * Function: mysql_start
+ *
+ * Purpose: Reads SQL Config File
+ *
+ *************************************************************************/
+
+int sql_init(int reload) {
+ FILE *sqlfd;
+ char dummystr[64];
+ char namestr[64];
+ int line_no = 0;
+ char buffer[256];
+ char sqlfile[256];
+
+ if (reload)
+ free(sql->config);
+ if ((sql->config = malloc(sizeof(SQL_CONFIG))) == NULL) {
+ log(L_ERR|L_CONS, "no memory");
+ exit(1);
+ }
+ strcpy(sql->config->sql_server,"localhost");
+ strcpy(sql->config->sql_login,"");
+ strcpy(sql->config->sql_password,"");
+ strcpy(sql->config->sql_db,"radius");
+ strcpy(sql->config->sql_authcheck_table,"radcheck");
+ strcpy(sql->config->sql_authreply_table,"radreply");
+ strcpy(sql->config->sql_groupcheck_table,"radgroupcheck");
+ strcpy(sql->config->sql_groupreply_table,"radgroupreply");
+ strcpy(sql->config->sql_usergroup_table,"usergroup");
+ strcpy(sql->config->sql_realmgroup_table,"realmgroup");
+ strcpy(sql->config->sql_acct_table,"radacct");
+ sql->config->sqltrace = 0;
+ sql->config->sensitiveusername = 1;
+ sql->config->deletestalesessions = 0;
+
+ strcpy(sql->config->sql_nas_table,"nas");
+ strcpy(sql->config->sql_realm_table, "realms");
+ strcpy(sql->config->sql_dict_table,"dictionary");
+ sql->config->max_sql_socks = MAX_SQL_SOCKS;
+
+ sprintf(sqlfile, "%s/%s", radius_dir, SQLCONFIGFILE);
+ if((sqlfd = fopen(sqlfile, "r")) == (FILE *)NULL) {
+ log(L_ERR,"could not read MySQL configuration file %s",sqlfile);
+ return(-1);
+ }
+ line_no = 0;
+ while(fgets(buffer, sizeof(buffer), sqlfd) != (char *)NULL) {
+ line_no++;
+
+ /* Skip empty space */
+ if(*buffer == '#' || *buffer == '\0' || *buffer == '\n') {
+ continue;
+ }
+
+ if(strncasecmp(buffer, "server", 6) == 0) {
+ /* Read the SERVER line */
+ if(sscanf(buffer, "%s%s", dummystr, namestr) != 2) {
+ log(L_ERR,"invalid attribute on line %d of configuration file %s", line_no,sqlfile);
+ } else {
+ strcpy(sql->config->sql_server,namestr);
+ }
+ }
+ if(strncasecmp(buffer, "login", 5) == 0) {
+ /* Read the LOGIN line */
+ if(sscanf(buffer, "%s%s", dummystr, namestr) != 2) {
+ log(L_ERR,"invalid attribute on line %d of configuration file %s", line_no,sqlfile);
+ } else {
+ strcpy(sql->config->sql_login,namestr);
+ }
+ }
+ if(strncasecmp(buffer, "password", 8) == 0) {
+ /* Read the PASSWORD line */
+ if(sscanf(buffer, "%s%s", dummystr, namestr) != 2) {
+ log(L_ERR,"invalid attribute on line %d of configuration file %s", line_no,sqlfile);
+ } else {
+ strcpy(sql->config->sql_password,namestr);
+ }
+ }
+ if(strncasecmp(buffer, "radius_db", 9) == 0) {
+ /* Read the RADIUS_DB line */
+ if(sscanf(buffer, "%s%s", dummystr, namestr) != 2) {
+ log(L_ERR,"invalid attribute on line %d of configuration file %s", line_no,sqlfile);
+ } else {
+ strcpy(sql->config->sql_db,namestr);
+ }
+ }
+ if(strncasecmp(buffer, "authcheck_table", 15) == 0) {
+ /* Read the AUTHCHECK_TABLE line */
+ if(sscanf(buffer, "%s%s", dummystr, namestr) != 2) {
+ log(L_ERR,"invalid attribute on line %d of configuration file %s", line_no,sqlfile);
+ } else {
+ strncpy(sql->config->sql_authcheck_table,namestr, MAX_TABLE_LEN);
+ }
+ }
+ if(strncasecmp(buffer, "authreply_table", 15) == 0) {
+ /* Read the AUTHREPLY_TABLE line */
+ if(sscanf(buffer, "%s%s", dummystr, namestr) != 2) {
+ log(L_ERR,"invalid attribute on line %d of configuration file %s", line_no,sqlfile);
+ } else {
+ strncpy(sql->config->sql_authreply_table,namestr, MAX_TABLE_LEN);
+ }
+ }
+ if(strncasecmp(buffer, "groupcheck_table", 16) == 0) {
+ /* Read the GROUPCHECK_TABLE line */
+ if(sscanf(buffer, "%s%s", dummystr, namestr) != 2) {
+ log(L_ERR,"invalid attribute on line %d of configuration file %s", line_no,sqlfile);
+ } else {
+ strncpy(sql->config->sql_groupcheck_table,namestr, MAX_TABLE_LEN);
+ }
+ }
+ if(strncasecmp(buffer, "groupreply_table", 16) == 0) {
+ /* Read the GROUP_REPLY_TABLE line */
+ if(sscanf(buffer, "%s%s", dummystr, namestr) != 2) {
+ log(L_ERR,"invalid attribute on line %d of configuration file %s", line_no,sqlfile);
+ } else {
+ strncpy(sql->config->sql_groupreply_table,namestr, MAX_TABLE_LEN);
+ }
+ }
+ if(strncasecmp(buffer, "usergroup_table", 15) == 0) {
+ /* Read the USERGROUP_TABLE line */
+ if(sscanf(buffer, "%s%s", dummystr, namestr) != 2) {
+ log(L_ERR,"invalid attribute on line %d of configuration file %s", line_no,sqlfile);
+ } else {
+ strncpy(sql->config->sql_usergroup_table,namestr, MAX_TABLE_LEN);
+ }
+ }
+ if(strncasecmp(buffer, "realmgroup_table", 16) == 0) {
+ /* Read the REALMGROUP_TABLE line */
+ if(sscanf(buffer, "%s%s", dummystr, namestr) != 2) {
+ log(L_ERR,"invalid attribute on line %d of configuration file %s", line_no,sqlfile);
+ } else {
+ strncpy(sql->config->sql_realmgroup_table,namestr, MAX_TABLE_LEN);
+ }
+ }
+ if(strncasecmp(buffer, "acct_table", 10) == 0) {
+ /* Read the ACCT_TABLE line */
+ if(sscanf(buffer, "%s%s", dummystr, namestr) != 2) {
+ log(L_ERR,"invalid attribute on line %d of configuration file %s", line_no,sqlfile);
+ } else {
+ strncpy(sql->config->sql_acct_table,namestr, MAX_TABLE_LEN);
+ }
+ }
+ if(strncasecmp(buffer, "nas_table", 9) == 0) {
+ /* Read the NAS_TABLE line */
+ if(sscanf(buffer, "%s%s", dummystr, namestr) != 2) {
+ log(L_ERR,"invalid attribute on line %d of configuration file %s", line_no,sqlfile);
+ } else {
+ strncpy(sql->config->sql_nas_table,namestr, MAX_TABLE_LEN);
+ }
+ }
+ if(strncasecmp(buffer, "realm_table", 9) == 0) {
+ /* Read the REALM_TABLE line */
+ if(sscanf(buffer, "%s%s", dummystr, namestr) != 2) {
+ log(L_ERR,"invalid attribute on line %d of configuration file %s", line_no,sqlfile);
+ } else {
+ strncpy(sql->config->sql_realm_table,namestr, MAX_TABLE_LEN);
+ }
+ }
+ if(strncasecmp(buffer, "dict_table", 9) == 0) {
+ /* Read the DICT_TABLE line */
+ if(sscanf(buffer, "%s%s", dummystr, namestr) != 2) {
+ log(L_ERR,"invalid attribute on line %d of configuration file %s", line_no,sqlfile);
+ } else {
+ strncpy(sql->config->sql_dict_table,namestr, MAX_TABLE_LEN);
+ }
+ }
+ if(strncasecmp(buffer, "sqltrace", 8) == 0) {
+ /* Read the SQLTRACE line */
+ if(sscanf(buffer, "%s%s", dummystr, namestr) != 2) {
+ log(L_ERR,"invalid attribute on line %d of configuration file %s", line_no,sqlfile);
+ } else {
+ if(strncasecmp(namestr, "on", 2) == 0) {
+ sql->config->sqltrace = 1;
+ } else {
+ sql->config->sqltrace = 0;
+ }
+ }
+ }
+ if(strncasecmp(buffer, "sensitiveusername", 17) == 0) {
+ /* Read the SENSITIVEUSERNAME line */
+ if(sscanf(buffer, "%s%s", dummystr, namestr) != 2) {
+ log(L_ERR,"invalid attribute on line %d of configuration file %s", line_no,sqlfile);
+ } else {
+ if(strncasecmp(namestr, "on", 2) == 0) {
+ sql->config->sensitiveusername = 1;
+ } else {
+ sql->config->sensitiveusername = 0;
+ }
+ }
+ }
+ if(strncasecmp(buffer, "deletestalesessions", 19) == 0) {
+ /* Read the DELETESTALESESSIONS line */
+ if(sscanf(buffer, "%s%s", dummystr, namestr) != 2) {
+ log(L_ERR,"invalid attribute on line %d of configuration file %s", line_no,sqlfile);
+ } else {
+ if(strncasecmp(namestr, "on", 2) == 0) {
+ sql->config->deletestalesessions = 1;
+ } else {
+ sql->config->deletestalesessions = 0;
+ }
+ }
+ }
+
+ }
+ fclose(sqlfd);
+
+ log(L_INFO,"SQL: Attempting to connect to %s@%s:%s", sql->config->sql_login, sql->config->sql_server, sql->config->sql_db);
+
+ sql_init_socket(reload);
+
+ return 0;
+}
/*************************************************************************
*
+ * Function: sql_init_socket
+ *
+ * Purpose: Connect to the sql server
+ *
+ *************************************************************************/
+int sql_init_socket(int reload) {
+
+ int i;
+
+ /* Clear up old connections if reload */
+ if (reload)
+ for (i = 0; i < sql->config->max_sql_socks; i++)
+ if (!sql_close_socket(sql->socks[i]))
+ log(L_CONS|L_ERR, "Could not release socket %d", i);
+
+
+ /* Initalize our connection pool */
+ for (i = 0; i < sql->config->max_sql_socks; i++) {
+ if ((sql->socks[i] = sql_create_socket()) == NULL) {
+ log(L_CONS|L_ERR, "SQL: Failed to connect socket %d", i);
+ } else {
+ sql->socks[i]->id = i;
+ sql->socks[i]->in_use = 0;
+ DEBUG2("SQL: Connected socket %d", i);
+ }
+ }
+
+ return 1;
+}
+
+
+/*************************************************************************
+ *
+ * Function: sql_close_socket
+ *
+ * Purpose: Close and free a sql socket
+ *
+ *************************************************************************/
+int sql_close_socket(SQLSOCK *socket) {
+
+ DEBUG2("SQL: Closing socket %d", socket->id);
+ sql_close(socket);
+ free(socket);
+ return 1;
+}
+
+
+/*************************************************************************
+ *
+ * Function: sql_get_socket
+ *
+ * Purpose: Return a SQL socket from the connection pool
+ *
+ *************************************************************************/
+SQLSOCK *sql_get_socket(void) {
+
+ int i = 0;
+
+ DEBUG2("SQL: Attempting to reserve socket");
+ while (1) {
+ if (i == sql->config->max_sql_socks)
+ i = 0;
+ if (sql->socks[i]->in_use == 0) {
+ sql->socks[i]->in_use = 1;
+ gettimeofday(&(sql->socks[i]->tv), NULL);
+ DEBUG2("SQL: Reserved socket %d", i);
+ return sql->socks[i];
+ }
+ i++;
+ }
+}
+
+/*************************************************************************
+ *
+ * Function: sql_release_socket
+ *
+ * Purpose: Frees a SQL socket back to the connection pool
+ *
+ *************************************************************************/
+int sql_release_socket(SQLSOCK *socket) {
+
+ struct timeval tv;
+ double start, end;
+ char buff[24];
+
+ gettimeofday(&tv, NULL);
+ sprintf(buff, "%ld.%2ld", tv.tv_sec, tv.tv_usec);
+ end = strtod(buff, NULL);
+ sprintf(buff, "%ld %2.0ld", socket->tv.tv_sec, socket->tv.tv_usec);
+ start = strtod(buff, NULL);
+ DEBUG2("SQL: Socket %d used for %.2f seconds", socket->id, end - start);
+
+ socket->tv.tv_sec = tv.tv_sec;
+ socket->tv.tv_usec = tv.tv_usec;
+ sql->socks[socket->id]->in_use = 0;
+ DEBUG2("SQL: Released socket %d", socket->id);
+ return 1;
+}
+
+
+/*************************************************************************
+ *
* Function: sql_save_acct
*
* Purpose: Write data from the sqlrecord structure to the database
*
*************************************************************************/
-int sql_save_acct(SQLREC *sqlrecord) {
+int sql_save_acct(SQLSOCK *socket, SQLACCTREC *sqlrecord) {
char querystr[2048];
FILE *sqlfile;
- FILE *backupfile;
int num = 0;
#ifdef NT_DOMAIN_HACK
char *ptr;
- if((sqlfile = fopen(QUERYLOG, "a")) == (FILE *)NULL) {
- log(L_ERR, "Acct: Couldn't open file %s", QUERYLOG);
+ if((sqlfile = fopen(SQLQUERYLOG, "a")) == (FILE *)NULL) {
+ log(L_ERR, "Acct: Couldn't open file %s", SQLQUERYLOG);
} else {
#if defined(F_LOCK) && !defined(BSD)
(void)lockf((int)sqlfile, (int)F_LOCK, (off_t)SQL_LOCK_LEN);
}
#endif /* NT_DOMAIN_HACK */
- if (sql_checksocket("Acct")) {
-
if (sqlrecord->AcctStatusTypeId == PW_STATUS_ACCOUNTING_ON || sqlrecord->AcctStatusTypeId == PW_STATUS_ACCOUNTING_OFF) {
log(L_INFO, "Portmaster %s rebooted at %s", sqlrecord->NASIPAddress, sqlrecord->AcctTimeStamp);
/* The Terminal server informed us that it was rebooted
* STOP all records from this NAS */
- sprintf(querystr, "UPDATE %s SET AcctStopTime='%s', AcctSessionTime=unix_timestamp('%s') - unix_timestamp(AcctStartTime), AcctTerminateCause='%s' WHERE AcctSessionTime=0 AND AcctStopTime=0 AND NASIPAddress= '%s' AND AcctStartTime <= '%s'", sql->config.sql_acct_table, sqlrecord->AcctTimeStamp, sqlrecord->AcctTimeStamp, sqlrecord->AcctTerminateCause, sqlrecord->NASIPAddress, sqlrecord->AcctTimeStamp);
+ sprintf(querystr, "UPDATE %s SET AcctStopTime='%s', AcctSessionTime=unix_timestamp('%s') - unix_timestamp(AcctStartTime), AcctTerminateCause='%s', AcctStopDelay = %ld WHERE AcctSessionTime=0 AND AcctStopTime=0 AND NASIPAddress= '%s' AND AcctStartTime <= '%s'", sql->config->sql_acct_table, sqlrecord->AcctTimeStamp, sqlrecord->AcctTimeStamp, sqlrecord->AcctTerminateCause, sqlrecord->AcctDelayTime, sqlrecord->NASIPAddress, sqlrecord->AcctTimeStamp);
- if (sql_query(sql->AcctSock, querystr) < 0)
- log(L_ERR, "Acct: Couldn't update SQL accounting after NAS reboot - %s", sql_error(sql->AcctSock));
- sql_finish_query(sql->AcctSock);
+ if (sql_query(socket, querystr) < 0)
+ log(L_ERR, "Acct: Couldn't update SQL accounting after NAS reboot - %s", sql_error(socket));
+ sql_finish_query(socket);
if (sqlfile) {
fputs(querystr, sqlfile);
}
if (sqlrecord->AcctStatusTypeId == PW_STATUS_ALIVE) {
- sprintf(querystr, "UPDATE %s SET Framed-IP-Address = '%s' WHERE AcctSessionId = '%s' AND UserName = '%s' AND NASIPAddress= '%s'", sql->config.sql_acct_table, sqlrecord->FramedIPAddress, sqlrecord->AcctSessionId, sqlrecord->UserName, sqlrecord->NASIPAddress);
- if (sql_query(sql->AcctSock, querystr) < 0)
- log(L_ERR, "Acct: Couldn't update SQL accounting after NAS reboot - %s", sql_error(sql->AcctSock));
- sql_finish_query(sql->AcctSock);
+ sprintf(querystr, "UPDATE %s SET FramedIPAddress = '%s' WHERE AcctSessionId = '%s' AND UserName = '%s' AND NASIPAddress= '%s'", sql->config->sql_acct_table, sqlrecord->FramedIPAddress, sqlrecord->AcctSessionId, sqlrecord->UserName, sqlrecord->NASIPAddress);
+ if (sql_query(socket, querystr) < 0)
+ log(L_ERR, "Acct: Couldn't update SQL accounting for ALIVE packet - %s", sql_error(socket));
+ sql_finish_query(socket);
if (sqlfile) {
fputs(querystr, sqlfile);
return 0;
}
-
/* Got start record */
if(sqlrecord->AcctStatusTypeId == PW_STATUS_START) {
/* Set start time on record with only a stop record */
- snprintf(querystr, 2048, "UPDATE %s SET AcctStartTime = '%s' WHERE AcctSessionId = '%s' AND UserName = '%s' AND NASIPAddress = '%s'",
- sql->config.sql_acct_table,
+ snprintf(querystr, 2048, "UPDATE %s SET AcctStartTime = '%s', AcctStartDelay = %ld WHERE AcctSessionId = '%s' AND UserName = '%s' AND NASIPAddress = '%s'",
+ sql->config->sql_acct_table,
sqlrecord->AcctTimeStamp,
+ sqlrecord->AcctDelayTime,
sqlrecord->AcctSessionId,
sqlrecord->UserName,
sqlrecord->NASIPAddress
);
- if (sql_query(sql->AcctSock, querystr) < 0)
- log(L_ERR, "Acct: Couldn't update SQL accounting START record - %s", sql_error(sql->AcctSock));
- sql_finish_query(sql->AcctSock);
+ if (sql_query(socket, querystr) < 0)
+ log(L_ERR, "Acct: Couldn't update SQL accounting START record - %s", sql_error(socket));
+ sql_finish_query(socket);
- num = sql_affected_rows(sql->AcctSock);
+ num = sql_affected_rows(socket);
if (num == 0) {
/* Insert new record with blank stop time until stop record is got */
- snprintf(querystr, 2048, "INSERT INTO %s VALUES (0, '%s', '%s', '%s', '%s', %ld, '%s', '%s', 0, 0, '%s', '%s', 0, 0, '%s', '%s', '', '%s', '%s', '%s', %ld)",
- sql->config.sql_acct_table,
+ snprintf(querystr, 2048, "INSERT INTO %s VALUES (0, '%s', '%s', '%s', '%s', %ld, '%s', '%s', 0, 0, '%s', '%s', 0, 0, '%s', '%s', '', '%s', '%s', '%s', %ld, 0)",
+ sql->config->sql_acct_table,
sqlrecord->AcctSessionId,
sqlrecord->UserName,
sqlrecord->Realm,
sqlrecord->AcctDelayTime
);
- if (sql_query(sql->AcctSock, querystr) < 0)
- log(L_ERR, "Acct: Couldn't insert SQL accounting START record - %s", sql_error(sql->AcctSock));
- sql_finish_query(sql->AcctSock);
+ if (sql_query(socket, querystr) < 0)
+ log(L_ERR, "Acct: Couldn't insert SQL accounting START record - %s", sql_error(socket));
+ sql_finish_query(socket);
}
/* Got stop record */
} else {
- sprintf(querystr, "SELECT RadAcctId FROM %s WHERE AcctSessionId='%s' AND NASIPAddress='%s' AND UserName='%s'", sql->config.sql_acct_table, sqlrecord->AcctSessionId, sqlrecord->NASIPAddress, sqlrecord->UserName);
- sql_select_query(sql->AcctSock, querystr);
- num = sql_num_rows(sql->AcctSock);
- sql_finish_select_query(sql->AcctSock);
+ sprintf(querystr, "SELECT RadAcctId FROM %s WHERE AcctSessionId='%s' AND NASIPAddress='%s' AND UserName='%s'", sql->config->sql_acct_table, sqlrecord->AcctSessionId, sqlrecord->NASIPAddress, sqlrecord->UserName);
+ sql_select_query(socket, querystr);
+ num = sql_num_rows(socket);
+ sql_finish_select_query(socket);
- if (num > 0) {
+ if (num > 0) {
- /* Set stop time on matching record with start time */
- snprintf(querystr, 2048, "UPDATE %s SET AcctStopTime = '%s', AcctSessionTime = '%lu', AcctInputOctets = '%u', AcctOutputOctets = '%u', AcctTerminateCause = '%s' WHERE AcctSessionId = '%s' AND UserName = '%s' AND NASIPAddress = '%s'",
- sql->config.sql_acct_table,
- sqlrecord->AcctTimeStamp,
- sqlrecord->AcctSessionTime,
- sqlrecord->AcctInputOctets,
- sqlrecord->AcctOutputOctets,
- sqlrecord->AcctTerminateCause,
- sqlrecord->AcctSessionId,
- sqlrecord->UserName,
- sqlrecord->NASIPAddress);
+ /* Set stop time on matching record with start time */
+ snprintf(querystr, 2048, "UPDATE %s SET AcctStopTime = '%s', AcctSessionTime = '%lu', AcctInputOctets = '%lu', AcctOutputOctets = '%lu', AcctTerminateCause = '%s', AcctStopDelay = %ld WHERE AcctSessionId = '%s' AND UserName = '%s' AND NASIPAddress = '%s'",
+ sql->config->sql_acct_table,
+ sqlrecord->AcctTimeStamp,
+ sqlrecord->AcctSessionTime,
+ sqlrecord->AcctInputOctets,
+ sqlrecord->AcctOutputOctets,
+ sqlrecord->AcctTerminateCause,
+ sqlrecord->AcctDelayTime,
+ sqlrecord->AcctSessionId,
+ sqlrecord->UserName,
+ sqlrecord->NASIPAddress
+ );
- if (sql_query(sql->AcctSock, querystr) < 0)
- log(L_ERR, "Acct: Couldn't update SQL accounting STOP record - %s", sql_error(sql->AcctSock));
- sql_finish_query(sql->AcctSock);
+ if (sql_query(socket, querystr) < 0)
+ log(L_ERR, "Acct: Couldn't update SQL accounting STOP record - %s", sql_error(socket));
+ sql_finish_query(socket);
- } else if (num == 0) {
+ } else if (num == 0) {
-
- /* Insert record with no start time until matching start record comes */
- snprintf(querystr, 2048, "INSERT INTO %s VALUES (0, '%s', '%s', '%s', '%s', %ld, '%s', 0, '%s', '%lu', '%s', '%s', '%u', '%u', '%s', '%s', '%s', '%s', '%s', '%s', %ld)",
- sql->config.sql_acct_table,
- sqlrecord->AcctSessionId,
- sqlrecord->UserName,
- sqlrecord->Realm,
- sqlrecord->NASIPAddress,
- sqlrecord->NASPortId,
- sqlrecord->NASPortType,
- sqlrecord->AcctTimeStamp,
- sqlrecord->AcctSessionTime,
- sqlrecord->AcctAuthentic,
- sqlrecord->ConnectInfo,
- sqlrecord->AcctInputOctets,
- sqlrecord->AcctOutputOctets,
- sqlrecord->CalledStationId,
- sqlrecord->CallingStationId,
- sqlrecord->AcctTerminateCause,
- sqlrecord->ServiceType,
- sqlrecord->FramedProtocol,
- sqlrecord->FramedIPAddress,
- sqlrecord->AcctDelayTime);
-
- if (sql_query(sql->AcctSock, querystr) < 0)
- log(L_ERR, "Acct: Couldn't insert SQL accounting STOP record - %s", sql_error(sql->AcctSock));
- sql_finish_query(sql->AcctSock);
+#ifdef CISCO_ACCOUNTING_HACK
+ /* If stop but zero session length AND no previous session found, drop it as in invalid packet */
+ /* This is to fix CISCO's aaa from filling our table with bogus crap */
+ if (sqlrecord->AcctSessionTime <= 0) {
+ log(L_ERR, "Acct: Invalid STOP record. [%s] STOP record but zero session length? (nas %s)", sqlrecord->UserName, sqlrecord->NASIPAddress);
+ return 0;
}
+#endif
+
+ /* Insert record with no start time until matching start record comes */
+ snprintf(querystr, 2048, "INSERT INTO %s VALUES (0, '%s', '%s', '%s', '%s', %ld, '%s', 0, '%s', '%lu', '%s', '%s', '%lu', '%lu', '%s', '%s', '%s', '%s', '%s', '%s', 0, %ld)",
+ sql->config->sql_acct_table,
+ sqlrecord->AcctSessionId,
+ sqlrecord->UserName,
+ sqlrecord->Realm,
+ sqlrecord->NASIPAddress,
+ sqlrecord->NASPortId,
+ sqlrecord->NASPortType,
+ sqlrecord->AcctTimeStamp,
+ sqlrecord->AcctSessionTime,
+ sqlrecord->AcctAuthentic,
+ sqlrecord->ConnectInfo,
+ sqlrecord->AcctInputOctets,
+ sqlrecord->AcctOutputOctets,
+ sqlrecord->CalledStationId,
+ sqlrecord->CallingStationId,
+ sqlrecord->AcctTerminateCause,
+ sqlrecord->ServiceType,
+ sqlrecord->FramedProtocol,
+ sqlrecord->FramedIPAddress,
+ sqlrecord->AcctDelayTime
+ );
+
+ if (sql_query(socket, querystr) < 0)
+ log(L_ERR, "Acct: Couldn't insert SQL accounting STOP record - %s", sql_error(socket));
+ sql_finish_query(socket);
+ }
}
if (sqlfile) {
fclose(sqlfile);
}
-
- } else {
-
- /*
- * The database is down for some reason
- * So open up the backup file to save records in
- */
-
- if((backupfile = fopen(SQLBACKUP, "a")) == (FILE *)NULL) {
- log(L_ERR, "Acct: Couldn't open file %s", SQLBACKUP);
- } else {
- /*
- * Lock the sql backup file, prefer lockf() over flock().
- */
- #if defined(F_LOCK) && !defined(BSD)
- (void)lockf((int)backupfile, (int)F_LOCK, (off_t)SQL_LOCK_LEN);
- #else
- (void)flock(backupfile, SQL_LOCK_EX);
- #endif
- if(fwrite(sqlrecord, sizeof(SQLREC), 1, backupfile) < 1) {
- log(L_ERR, "Acct: Couldn't write to file %s", SQLBACKUP);
- }
- fclose(backupfile);
- }
-
- }
-
return 0;
}
* Purpose: Read entries from the database and fill VALUE_PAIR structures
*
*************************************************************************/
-int sql_userparse(VALUE_PAIR **first_pair, SQL_ROW row) {
+int sql_userparse(VALUE_PAIR **first_pair, SQL_ROW row, int mode) {
DICT_ATTR *attr;
VALUE_PAIR *pair, *check;
/* If attribute is already there, skip it because we checked usercheck first
and we want user settings to over ride group settings */
- if ((check = pairfind(*first_pair, attr->attr)) != NULL)
+ if ((check = pairfind(*first_pair, attr->attr)) != NULL && mode == PW_VP_GROUPDATA)
return 0;
- pair = pairmake(row[2], row[3], T_OP_EQ);
- pairadd(first_pair, pair);
-
- return 0;
+ pair = pairmake(row[2], row[3], T_OP_EQ);
+ pairadd(first_pair, pair);
+
+ return 0;
}
-
/*************************************************************************
*
* Function: sql_getvpdata
* Purpose: Get any group check or reply pairs
*
*************************************************************************/
-int sql_getvpdata(char *table, VALUE_PAIR **vp, char *user, int mode) {
+int sql_getvpdata(SQLSOCK *socket, char *table, VALUE_PAIR **vp, char *user, int mode) {
char querystr[256];
+ char authstr[256];
+ char username[AUTH_STRING_LEN*2+1];
SQL_ROW row;
int rows;
-
- if (mode == PW_VP_USERDATA)
- sprintf(querystr, "SELECT * FROM %s WHERE UserName = '%s'", table, user);
- else if (mode == PW_VP_GROUPDATA)
- sprintf(querystr, "SELECT %s.* FROM %s, %s WHERE %s.UserName = '%s' AND %s.GroupName = %s.GroupName ORDER BY %s.id", table, table, sql->config.sql_usergroup_table, sql->config.sql_usergroup_table, user, sql->config.sql_usergroup_table, table, table);
- else if (mode == PW_VP_REALMDATA)
- sprintf(querystr, "SELECT %s.* FROM %s, %s WHERE %s.RealmName = '%s' AND %s.GroupName = %s.GroupName ORDER BY %s.id", table, table, sql->config.sql_realmgroup_table, sql->config.sql_realmgroup_table, user, sql->config.sql_realmgroup_table, table, table);
- sql_checksocket("Auth");
- sql_select_query(sql->AuthSock, querystr);
- rows = sql_num_rows(sql->AuthSock);
- while ((row = sql_fetch_row(sql->AuthSock))) {
- if (sql_userparse(vp, row) != 0) {
- log(L_ERR|L_CONS, "Error getting data from SQL database");
- sql_finish_select_query(sql->AuthSock);
+ int length;
+
+ if (strlen(user) > AUTH_STRING_LEN)
+ length = AUTH_STRING_LEN;
+ else
+ length = strlen(user);
+
+ /* FIXME CHECK user for weird charactors!! */
+ sql_escape_string(username, user, length);
+
+ if (mode == PW_VP_USERDATA) {
+ if (sql->config->sensitiveusername)
+ sprintf(authstr, "STRCMP(Username, '%s') = 0", username);
+ else
+ sprintf(authstr, "UserName = '%s'", username);
+ sprintf(querystr, "SELECT * FROM %s WHERE %s ORDER BY id", table, authstr);
+ } else if (mode == PW_VP_GROUPDATA) {
+ if (sql->config->sensitiveusername)
+ sprintf(authstr, "STRCMP(%s.Username, '%s') = 0", sql->config->sql_usergroup_table, username);
+ else
+ sprintf(authstr, "%s.UserName = '%s'",sql->config->sql_usergroup_table, username);
+ sprintf(querystr, "SELECT %s.* FROM %s, %s WHERE %s AND %s.GroupName = %s.GroupName ORDER BY %s.id", table, table, sql->config->sql_usergroup_table, authstr, sql->config->sql_usergroup_table, table, table);
+ } else if (mode == PW_VP_REALMDATA)
+ sprintf(querystr, "SELECT %s.* FROM %s, %s WHERE %s.RealmName = '%s' AND %s.GroupName = %s.GroupName ORDER BY %s.id", table, table, sql->config->sql_realmgroup_table, sql->config->sql_realmgroup_table, username, sql->config->sql_realmgroup_table, table, table);
+ sql_select_query(socket, querystr);
+ rows = sql_num_rows(socket);
+ while ((row = sql_fetch_row(socket))) {
+
+ if (sql_userparse(vp, row, mode) != 0) {
+ log(L_ERR|L_CONS, "Error getting data from SQL");
+ sql_finish_select_query(socket);
return -1;
}
}
- sql_finish_select_query(sql->AuthSock);
+ sql_finish_select_query(socket);
return rows;
static int got_alrm;
-static void alrm_handler() {
+static void alrm_handler()
+{
got_alrm = 1;
}
/*
* Find NAS type.
*/
- if ((nas = nas_find(ip_addr(row[3]))) == NULL) {
- log(L_ERR, "Accounting: unknown NAS [%s]", row[3]);
+ if ((nas = nas_find(ipstr2long(row[4]))) == NULL) {
+ log(L_ERR, "Accounting: unknown NAS [%s]", row[4]);
return -1;
}
* Purpose: Check radius accounting for duplicate logins
*
*************************************************************************/
-int sql_check_multi(char *name, VALUE_PAIR *request, int maxsimul) {
+int sql_check_multi(SQLSOCK *socket, char *name, VALUE_PAIR *request, int maxsimul) {
char querystr[256];
+ char authstr[256];
VALUE_PAIR *fra;
SQL_ROW row;
int count = 0;
uint32_t ipno = 0;
int mpp = 1;
- if (!sql_checksocket("Auth"))
- return 0;
- sprintf(querystr, "SELECT COUNT(*) FROM %s WHERE UserName = '%s' AND AcctStopTime = 0", sql->config.sql_acct_table, name);
- sql_select_query(sql->AuthSock, querystr);
- row = sql_fetch_row(sql->AuthSock);
+ if (sql->config->sensitiveusername)
+ sprintf(authstr, "STRCMP(UserName, '%s') = 0", name);
+ else
+ sprintf(authstr, "UserName = '%s'", name);
+ sprintf(querystr, "SELECT COUNT(*) FROM %s WHERE %s AND AcctStopTime = 0", sql->config->sql_acct_table, authstr);
+ sql_select_query(socket, querystr);
+ row = sql_fetch_row(socket);
count = atoi(row[0]);
- sql_finish_select_query(sql->AuthSock);
+ sql_finish_select_query(socket);
if (count < maxsimul)
return 0;
ipno = htonl(fra->lvalue);
count = 0;
- sprintf(querystr, "SELECT * FROM %s WHERE UserName = '%s' AND AcctStopTime = 0", sql->config.sql_acct_table, name);
- sql_select_query(sql->AuthSock, querystr);
- while ((row = sql_fetch_row(sql->AuthSock))) {
- if (sql_check_ts(row) == 1) {
+ sprintf(querystr, "SELECT * FROM %s WHERE %s AND AcctStopTime = 0", sql->config->sql_acct_table, authstr);
+ sql_select_query(socket, querystr);
+ while ((row = sql_fetch_row(socket))) {
+ int check = sql_check_ts(row);
+ if (check == 1) {
count++;
- if (ipno && atoi(row[18]) == ipno)
+ if (ipno && atoi(row[19]) == ipno)
mpp = 2;
- } else {
+ } else if (check == 2)
+ log(L_ERR,"Problem with checkrad [%s] (from nas %s)", name, row[4]);
+ else {
/*
* False record - zap it
*/
- sprintf(querystr, "DELETE FROM %s WHERE RadAcctId = '%s'", sql->config.sql_acct_table, row[0]);
- sql_query(sql->AuthSock, querystr);
- sql_finish_query(sql->AuthSock);
-
+ if (sql->config->deletestalesessions) {
+ SQLSOCK *socket;
+
+ log(L_ERR,"Deleteing stale session [%s] (from nas %s/%s)", row[2], row[4], row[5]);
+ socket = sql_get_socket();
+ sprintf(querystr, "DELETE FROM %s WHERE RadAcctId = '%s'", sql->config->sql_acct_table, row[0]);
+ sql_query(socket, querystr);
+ sql_finish_query(socket);
+ sql_close_socket(socket);
+ }
}
}
- sql_finish_select_query(sql->AuthSock);
+ sql_finish_select_query(socket);
return (count < maxsimul) ? 0 : mpp;
/*************************************************************************
*
- * Function: sql_connect
- *
- * Purpose: Connect to the sql server
- *
- *************************************************************************/
-int sql_connect(void) {
-
- MYSQL MyAuthConn;
- MYSQL MyAcctConn;
-
- /* Connect to the database server */
- mysql_init(&MyAuthConn);
- if (!(sql->AuthSock->conn = mysql_real_connect(&MyAuthConn, sql->config.sql_server, sql->config.sql_login, sql->config.sql_password, sql->config.sql_db, 0, NULL, 0))) {
- log(L_ERR, "Init: Couldn't connect authentication socket to MySQL server on %s as %s", sql->config.sql_server, sql->config.sql_login);
- sql->AuthSock->conn = NULL;
- }
- mysql_init(&MyAcctConn);
- if (!(sql->AcctSock->conn = mysql_real_connect(&MyAcctConn, sql->config.sql_server, sql->config.sql_login, sql->config.sql_password, sql->config.sql_db, 0, NULL, 0))) {
- log(L_ERR, "Init: Couldn't connect accounting socket to MySQL server on %s as %s", sql->config.sql_server, sql->config.sql_login);
- sql->AcctSock->conn = NULL;
- }
-
- return 0;
-}
-
-
-
-/*************************************************************************
- *
- * Function: sql_checksocket
+ * Function: sql_query
*
- * Purpose: Make sure our database connection is up
+ * Purpose: Issue a query to the database
*
*************************************************************************/
-int sql_checksocket(const char *facility) {
-
- if ((strncmp(facility, "Auth", 4) == 0)) {
- if (sql->AuthSock->conn == NULL) {
-
- MYSQL MyAuthConn;
- if (sql->config.sql_keepopen)
- log(L_ERR, "%s: Keepopen set but had to reconnect to MySQL", facility);
- /* Connect to the database server */
- mysql_init(&MyAuthConn);
- if (!(sql->AuthSock->conn = mysql_real_connect(&MyAuthConn, sql->config.sql_server, sql->config.sql_login, sql->config.sql_password, sql->config.sql_db, 0, NULL, 0))) {
- log(L_ERR, "Auth: Couldn't connect authentication socket to MySQL server on %s as %s", sql->config.sql_server, sql->config.sql_login);
- sql->AuthSock->conn = NULL;
- return 0;
- }
- }
-
- } else {
- if (sql->AcctSock->conn == NULL) {
- MYSQL MyAcctConn;
- if (sql->config.sql_keepopen)
- log(L_ERR, "%s: Keepopen set but had to reconnect to MySQL", facility);
- /* Connect to the database server */
- mysql_init(&MyAcctConn);
- if (!(sql->AcctSock->conn = mysql_real_connect(&MyAcctConn, sql->config.sql_server, sql->config.sql_login, sql->config.sql_password, sql->config.sql_db, 0, NULL, 0))) {
- log(L_ERR, "Acct: Couldn't connect accounting socket to MySQL server on %s as %s", sql->config.sql_server, sql->config.sql_login);
- sql->AcctSock->conn = NULL;
- return 0;
- }
- }
+SQLSOCK *sql_create_socket(void) {
+ SQLSOCK *socket;
+ if ((socket = malloc(sizeof(SQLSOCK))) == NULL) {
+ log(L_CONS|L_ERR, "sql_create_socket: no memory");
+ exit(1);
}
- return 1;
-
+ mysql_init(&(socket->conn));
+ if (!(socket->sock = mysql_real_connect(&(socket->conn), sql->config->sql_server, sql->config->sql_login, sql->config->sql_password, sql->config->sql_db, 0, NULL, 0))) {
+ log(L_ERR, "Init: Couldn't connect socket to MySQL server %s@%s:%s", sql->config->sql_login, sql->config->sql_server, sql->config->sql_db);
+ socket->sock = NULL;
+ return NULL;
+ }
+ return socket;
}
-
/*************************************************************************
*
* Function: sql_query
*************************************************************************/
int sql_query(SQLSOCK *socket, char *querystr) {
- if (sql->config.sqltrace)
- DEBUG(querystr);
- return mysql_query(socket->conn, querystr);
-
+ if (sql->config->sqltrace)
+ DEBUG(querystr);
+ if (socket->sock == NULL) {
+ log(L_ERR, "Socket not connected");
+ return 0;
+ }
+ return mysql_query(socket->sock, querystr);
}
*************************************************************************/
int sql_select_query(SQLSOCK *socket, char *querystr) {
- if (sql->config.sqltrace)
- DEBUG(querystr);
- mysql_query(socket->conn, querystr);
- if (sql_store_result(socket) && sql_num_fields(socket))
- return 0;
- else
- return 1;
-
+ if (sql->config->sqltrace)
+ DEBUG(querystr);
+ if (socket->sock == NULL) {
+ log(L_ERR, "Socket not connected");
+ return 0;
+ }
+ mysql_query(socket->sock, querystr);
+ if (sql_store_result(socket) && sql_num_fields(socket))
+ return 1;
+ else
+ return 0;
}
*************************************************************************/
int sql_store_result(SQLSOCK *socket) {
- if (!(socket->result = mysql_store_result(socket->conn))) {
+ if (socket->sock == NULL) {
+ log(L_ERR, "Socket not connected");
+ return 0;
+ }
+ if (!(socket->result = mysql_store_result(socket->sock))) {
log(L_ERR,"MYSQL Error: Cannot get result");
- log(L_ERR,"MYSQL error: %s",mysql_error(socket->conn));
- sql_close(socket);
+ log(L_ERR,"MYSQL Error: %s",mysql_error(socket->sock));
return 0;
}
return 1;
int sql_num_fields(SQLSOCK *socket) {
int num = 0;
- if (!(num = mysql_num_fields(socket->conn))) {
+#if MYSQL_VERSION_ID >= 32224
+ if (!(num = mysql_field_count(socket->sock))) {
+#else
+ if (!(num = mysql_num_fields(socket->sock))) {
+#endif
log(L_ERR,"MYSQL Error: Cannot get result");
- log(L_ERR,"MYSQL error: %s",mysql_error(socket->conn));
- sql_close(socket);
+ log(L_ERR,"MYSQL error: %s",mysql_error(socket->sock));
}
return num;
}
*************************************************************************/
int sql_num_rows(SQLSOCK *socket) {
- return mysql_num_rows(socket->result);
-
+ return mysql_num_rows(socket->result);
}
*************************************************************************/
SQL_ROW sql_fetch_row(SQLSOCK *socket) {
- return mysql_fetch_row(socket->result);
-
+ return mysql_fetch_row(socket->result);
}
*************************************************************************/
void sql_free_result(SQLSOCK *socket) {
- mysql_free_result(socket->result);
-
+ mysql_free_result(socket->result);
}
*************************************************************************/
char *sql_error(SQLSOCK *socket) {
- return (mysql_error(socket->conn));
-
+ return mysql_error(socket->sock);
}
*************************************************************************/
void sql_close(SQLSOCK *socket) {
- mysql_close(socket->conn);
-
+ mysql_close(socket->sock);
+ socket->sock = NULL;
}
*************************************************************************/
void sql_finish_select_query(SQLSOCK *socket) {
- sql_free_result(socket);
+ sql_free_result(socket);
}
*
* Function: sql_affected_rows
*
- * Purpose: End the select quh as freeing memory or result
+ * Purpose: End the select query, such as freeing memory or result
*
*************************************************************************/
int sql_affected_rows(SQLSOCK *socket) {
- int rows;
- rows = mysql_affected_rows(socket->conn);
- return rows;
+ return mysql_affected_rows(socket->sock);
}
*
* Function: sql_escape_string
*
- * Purpose: strdup() with the added feature of escaping binary
- * data in the string to safely fit into an SQL query
+ * Purpose: Esacpe "'" and any other wierd charactors
*
*************************************************************************/
-char *sql_escape_string(const char *from) {
- char *to;
-
- if(from==NULL)
- return NULL;
- if((to=malloc((strlen(from)*2) + 1)) == NULL)
- return NULL;
- mysql_escape_string(to,from,strlen(from));
- return to;
+int sql_escape_string(char *to, char *from, int length) {
+
+ mysql_escape_string(to, from, length);
+ return 1;
}
*/
#include <mysql/mysql.h>
+#include "conf.h"
typedef MYSQL_ROW SQL_ROW;
-typedef MYSQL_RES SQL_RES;
-typedef struct {
- MYSQL *conn;
- MYSQL_RES *result;
+typedef struct sql_config {
+ char sql_server[40];
+ char sql_login[20];
+ char sql_password[20];
+ char sql_db[20];
+ char sql_acct_table[MAX_TABLE_LEN];
+ char sql_authcheck_table[MAX_TABLE_LEN];
+ char sql_authreply_table[MAX_TABLE_LEN];
+ char sql_groupcheck_table[MAX_TABLE_LEN];
+ char sql_groupreply_table[MAX_TABLE_LEN];
+ char sql_usergroup_table[MAX_TABLE_LEN];
+ char sql_realm_table[MAX_TABLE_LEN];
+ char sql_realmgroup_table[MAX_TABLE_LEN];
+ char sql_nas_table[MAX_TABLE_LEN];
+ char sql_dict_table[MAX_TABLE_LEN];
+ int sensitiveusername;
+ int sqltrace;
+ int deletestalesessions;
+ int max_sql_socks;
+} SQL_CONFIG;
+
+typedef struct sql_socket {
+ MYSQL *sock;
+ MYSQL conn;
+ MYSQL_RES *result;
+ int id;
+ int in_use;
+ struct timeval tv;
} SQLSOCK;
+
+typedef struct sql {
+ SQL_CONFIG *config;
+ SQLSOCK *socks[MAX_SQL_SOCKS];
+} SQL;
-int sql_connect(void);
+SQLSOCK *sql_create_socket(void);
int sql_checksocket(const char *facility);
int sql_query(SQLSOCK *socket, char *querystr);
int sql_select_query(SQLSOCK *socket, char *querystr);
void sql_finish_query(SQLSOCK *socket);
void sql_finish_select_query(SQLSOCK *socket);
int sql_affected_rows(SQLSOCK *socket);
-char *sql_escape_string(const char *from);
+int sql_escape_string(char *to, char *from, int length);
/*************************************************************************
*
- * Function: sql_connect
- *
- * Purpose: Connect to the sql server
- *
- *************************************************************************/
-int sql_connect(void) {
-
- MYSQL MyAuthConn;
- MYSQL MyAcctConn;
-
- /* Connect to the database server */
- mysql_init(&MyAuthConn);
- if (!(sql->AuthSock->conn = mysql_real_connect(&MyAuthConn, sql->config.sql_server, sql->config.sql_login, sql->config.sql_password, sql->config.sql_db, 0, NULL, 0))) {
- log(L_ERR, "Init: Couldn't connect authentication socket to MySQL server on %s as %s", sql->config.sql_server, sql->config.sql_login);
- sql->AuthSock->conn = NULL;
- }
- mysql_init(&MyAcctConn);
- if (!(sql->AcctSock->conn = mysql_real_connect(&MyAcctConn, sql->config.sql_server, sql->config.sql_login, sql->config.sql_password, sql->config.sql_db, 0, NULL, 0))) {
- log(L_ERR, "Init: Couldn't connect accounting socket to MySQL server on %s as %s", sql->config.sql_server, sql->config.sql_login);
- sql->AcctSock->conn = NULL;
- }
-
- return 0;
-}
-
-
-
-/*************************************************************************
- *
- * Function: sql_checksocket
+ * Function: sql_query
*
- * Purpose: Make sure our database connection is up
+ * Purpose: Issue a query to the database
*
*************************************************************************/
-int sql_checksocket(const char *facility) {
-
- if ((strncmp(facility, "Auth", 4) == 0)) {
- if (sql->AuthSock->conn == NULL) {
-
- MYSQL MyAuthConn;
- if (sql->config.sql_keepopen)
- log(L_ERR, "%s: Keepopen set but had to reconnect to MySQL", facility);
- /* Connect to the database server */
- mysql_init(&MyAuthConn);
- if (!(sql->AuthSock->conn = mysql_real_connect(&MyAuthConn, sql->config.sql_server, sql->config.sql_login, sql->config.sql_password, sql->config.sql_db, 0, NULL, 0))) {
- log(L_ERR, "Auth: Couldn't connect authentication socket to MySQL server on %s as %s", sql->config.sql_server, sql->config.sql_login);
- sql->AuthSock->conn = NULL;
- return 0;
- }
- }
-
- } else {
- if (sql->AcctSock->conn == NULL) {
- MYSQL MyAcctConn;
- if (sql->config.sql_keepopen)
- log(L_ERR, "%s: Keepopen set but had to reconnect to MySQL", facility);
- /* Connect to the database server */
- mysql_init(&MyAcctConn);
- if (!(sql->AcctSock->conn = mysql_real_connect(&MyAcctConn, sql->config.sql_server, sql->config.sql_login, sql->config.sql_password, sql->config.sql_db, 0, NULL, 0))) {
- log(L_ERR, "Acct: Couldn't connect accounting socket to MySQL server on %s as %s", sql->config.sql_server, sql->config.sql_login);
- sql->AcctSock->conn = NULL;
- return 0;
- }
- }
+SQLSOCK *sql_create_socket(void) {
+ SQLSOCK *socket;
+ if ((socket = malloc(sizeof(SQLSOCK))) == NULL) {
+ log(L_CONS|L_ERR, "sql_create_socket: no memory");
+ exit(1);
}
- return 1;
-
+ mysql_init(&(socket->conn));
+ if (!(socket->sock = mysql_real_connect(&(socket->conn), sql->config->sql_server, sql->config->sql_login, sql->config->sql_password, sql->config->sql_db, 0, NULL, 0))) {
+ log(L_ERR, "Init: Couldn't connect socket to MySQL server %s@%s:%s", sql->config->sql_login, sql->config->sql_server, sql->config->sql_db);
+ socket->sock = NULL;
+ return NULL;
+ }
+ return socket;
}
-
/*************************************************************************
*
* Function: sql_query
*************************************************************************/
int sql_query(SQLSOCK *socket, char *querystr) {
- if (sql->config.sqltrace)
- DEBUG(querystr);
- return mysql_query(socket->conn, querystr);
-
+ if (sql->config->sqltrace)
+ DEBUG(querystr);
+ if (socket->sock == NULL) {
+ log(L_ERR, "Socket not connected");
+ return 0;
+ }
+ return mysql_query(socket->sock, querystr);
}
*************************************************************************/
int sql_select_query(SQLSOCK *socket, char *querystr) {
- if (sql->config.sqltrace)
- DEBUG(querystr);
- mysql_query(socket->conn, querystr);
- if (sql_store_result(socket) && sql_num_fields(socket))
- return 0;
- else
- return 1;
-
+ if (sql->config->sqltrace)
+ DEBUG(querystr);
+ if (socket->sock == NULL) {
+ log(L_ERR, "Socket not connected");
+ return 0;
+ }
+ mysql_query(socket->sock, querystr);
+ if (sql_store_result(socket) && sql_num_fields(socket))
+ return 1;
+ else
+ return 0;
}
*************************************************************************/
int sql_store_result(SQLSOCK *socket) {
- if (!(socket->result = mysql_store_result(socket->conn))) {
+ if (socket->sock == NULL) {
+ log(L_ERR, "Socket not connected");
+ return 0;
+ }
+ if (!(socket->result = mysql_store_result(socket->sock))) {
log(L_ERR,"MYSQL Error: Cannot get result");
- log(L_ERR,"MYSQL error: %s",mysql_error(socket->conn));
- sql_close(socket);
+ log(L_ERR,"MYSQL Error: %s",mysql_error(socket->sock));
return 0;
}
return 1;
int sql_num_fields(SQLSOCK *socket) {
int num = 0;
- if (!(num = mysql_num_fields(socket->conn))) {
+#if MYSQL_VERSION_ID >= 32224
+ if (!(num = mysql_field_count(socket->sock))) {
+#else
+ if (!(num = mysql_num_fields(socket->sock))) {
+#endif
log(L_ERR,"MYSQL Error: Cannot get result");
- log(L_ERR,"MYSQL error: %s",mysql_error(socket->conn));
- sql_close(socket);
+ log(L_ERR,"MYSQL error: %s",mysql_error(socket->sock));
}
return num;
}
*************************************************************************/
int sql_num_rows(SQLSOCK *socket) {
- return mysql_num_rows(socket->result);
-
+ return mysql_num_rows(socket->result);
}
*************************************************************************/
SQL_ROW sql_fetch_row(SQLSOCK *socket) {
- return mysql_fetch_row(socket->result);
-
+ return mysql_fetch_row(socket->result);
}
*************************************************************************/
void sql_free_result(SQLSOCK *socket) {
- mysql_free_result(socket->result);
-
+ mysql_free_result(socket->result);
}
*************************************************************************/
char *sql_error(SQLSOCK *socket) {
- return (mysql_error(socket->conn));
-
+ return mysql_error(socket->sock);
}
*************************************************************************/
void sql_close(SQLSOCK *socket) {
- mysql_close(socket->conn);
-
+ mysql_close(socket->sock);
+ socket->sock = NULL;
}
*************************************************************************/
void sql_finish_select_query(SQLSOCK *socket) {
- sql_free_result(socket);
+ sql_free_result(socket);
}
*
*************************************************************************/
int sql_affected_rows(SQLSOCK *socket) {
- int rows;
- rows = mysql_affected_rows(socket->conn);
- return rows;
+ return mysql_affected_rows(socket->sock);
}
*
* Function: sql_escape_string
*
- * Purpose: strdup() with the added feature of escaping binary
- * data in the string to safely fit into an SQL query
+ * Purpose: Esacpe "'" and any other wierd charactors
*
*************************************************************************/
-char *sql_escape_string(const char *from) {
- char *to;
-
- if(from==NULL)
- return NULL;
- if((to=malloc((strlen(from)*2) + 1)) == NULL)
- return NULL;
- mysql_escape_string(to,from,strlen(from));
- return to;
+int sql_escape_string(char *to, char *from, int length) {
+
+ mysql_escape_string(to, from, length);
+ return 1;
}
*/
#include <mysql/mysql.h>
+#include "conf.h"
typedef MYSQL_ROW SQL_ROW;
-typedef MYSQL_RES SQL_RES;
-typedef struct {
- MYSQL *conn;
- MYSQL_RES *result;
+typedef struct sql_config {
+ char sql_server[40];
+ char sql_login[20];
+ char sql_password[20];
+ char sql_db[20];
+ char sql_acct_table[MAX_TABLE_LEN];
+ char sql_authcheck_table[MAX_TABLE_LEN];
+ char sql_authreply_table[MAX_TABLE_LEN];
+ char sql_groupcheck_table[MAX_TABLE_LEN];
+ char sql_groupreply_table[MAX_TABLE_LEN];
+ char sql_usergroup_table[MAX_TABLE_LEN];
+ char sql_realm_table[MAX_TABLE_LEN];
+ char sql_realmgroup_table[MAX_TABLE_LEN];
+ char sql_nas_table[MAX_TABLE_LEN];
+ char sql_dict_table[MAX_TABLE_LEN];
+ int sensitiveusername;
+ int sqltrace;
+ int deletestalesessions;
+ int max_sql_socks;
+} SQL_CONFIG;
+
+typedef struct sql_socket {
+ MYSQL *sock;
+ MYSQL conn;
+ MYSQL_RES *result;
+ int id;
+ int in_use;
+ struct timeval tv;
} SQLSOCK;
+
+typedef struct sql {
+ SQL_CONFIG *config;
+ SQLSOCK *socks[MAX_SQL_SOCKS];
+} SQL;
-int sql_connect(void);
+SQLSOCK *sql_create_socket(void);
int sql_checksocket(const char *facility);
int sql_query(SQLSOCK *socket, char *querystr);
int sql_select_query(SQLSOCK *socket, char *querystr);
void sql_finish_query(SQLSOCK *socket);
void sql_finish_select_query(SQLSOCK *socket);
int sql_affected_rows(SQLSOCK *socket);
-char *sql_escape_string(const char *from);
+int sql_escape_string(char *to, char *from, int length);