📄 rlm_sql.c
字号:
*/ if ((pair = pairfind(request->packet->vps, PW_ACCT_STATUS_TYPE)) != NULL) { acctstatustype = pair->lvalue; } else { radius_xlat(logstr, sizeof(logstr), "rlm_sql: packet has no account status type. [user '%{User-Name}', nas '%{NAS-IP-Address}']", request, sql_escape_func); radlog(L_ERR, logstr); return RLM_MODULE_INVALID; } switch (acctstatustype) { /* * The Terminal server informed us that it was rebooted * STOP all records from this NAS */ case PW_STATUS_ACCOUNTING_ON: case PW_STATUS_ACCOUNTING_OFF: radlog(L_INFO, "rlm_sql (%s): received Acct On/Off packet", inst->config->xlat_name); radius_xlat(querystr, sizeof(querystr), inst->config->accounting_onoff_query, request, sql_escape_func); query_log(request, inst, querystr); sqlsocket = sql_get_socket(inst); if (sqlsocket == NULL) return(RLM_MODULE_FAIL); if (*querystr) { /* non-empty query */ if (rlm_sql_query(sqlsocket, inst, querystr)) { radlog(L_ERR, "rlm_sql (%s): Couldn't update SQL accounting for Acct On/Off packet - %s", inst->config->xlat_name, (char *)(inst->module->sql_error)(sqlsocket, inst->config)); ret = RLM_MODULE_FAIL; } (inst->module->sql_finish_query)(sqlsocket, inst->config); } break; /* * Got an update accounting packet */ case PW_STATUS_ALIVE: /* * Set, escape, and check the user attr here */ sql_set_user(inst, request, sqlusername, NULL); radius_xlat(querystr, sizeof(querystr), inst->config->accounting_update_query, request, sql_escape_func); query_log(request, inst, querystr); sqlsocket = sql_get_socket(inst); if (sqlsocket == NULL) return(RLM_MODULE_FAIL); if (*querystr) { /* non-empty query */ if (rlm_sql_query(sqlsocket, inst, querystr)) { radlog(L_ERR, "rlm_sql (%s): Couldn't update SQL accounting ALIVE record - %s", inst->config->xlat_name, (char *)(inst->module->sql_error)(sqlsocket, inst->config)); ret = RLM_MODULE_FAIL; } else { numaffected = (inst->module->sql_affected_rows)(sqlsocket, inst->config); if (numaffected < 1) { /* * If our update above didn't match anything * we assume it's because we haven't seen a * matching Start record. So we have to * insert this update rather than do an update */ radius_xlat(querystr, sizeof(querystr), inst->config->accounting_update_query_alt, request, sql_escape_func); query_log(request, inst, querystr); if (*querystr) { /* non-empty query */ if (rlm_sql_query(sqlsocket, inst, querystr)) { radlog(L_ERR, "rlm_sql (%s): Couldn't insert SQL accounting ALIVE record - %s", inst->config->xlat_name, (char *)(inst->module->sql_error)(sqlsocket, inst->config)); ret = RLM_MODULE_FAIL; } (inst->module->sql_finish_query)(sqlsocket, inst->config); } } } (inst->module->sql_finish_query)(sqlsocket, inst->config); } break; /* * Got accounting start packet */ case PW_STATUS_START: /* * Set, escape, and check the user attr here */ sql_set_user(inst, request, sqlusername, NULL); radius_xlat(querystr, sizeof(querystr), inst->config->accounting_start_query, request, sql_escape_func); query_log(request, inst, querystr); sqlsocket = sql_get_socket(inst); if (sqlsocket == NULL) return(RLM_MODULE_FAIL); if (*querystr) { /* non-empty query */ if (rlm_sql_query(sqlsocket, inst, querystr)) { radlog(L_ERR, "rlm_sql (%s): Couldn't insert SQL accounting START record - %s", inst->config->xlat_name, (char *)(inst->module->sql_error)(sqlsocket, inst->config)); /* * We failed the insert above. It's probably because * the stop record came before the start. We try * our alternate query now (typically an UPDATE) */ radius_xlat(querystr, sizeof(querystr), inst->config->accounting_start_query_alt, request, sql_escape_func); query_log(request, inst, querystr); if (*querystr) { /* non-empty query */ if (rlm_sql_query(sqlsocket, inst, querystr)) { radlog(L_ERR, "rlm_sql (%s): Couldn't update SQL accounting START record - %s", inst->config->xlat_name, (char *)(inst->module->sql_error)(sqlsocket, inst->config)); ret = RLM_MODULE_FAIL; } (inst->module->sql_finish_query)(sqlsocket, inst->config); } } (inst->module->sql_finish_query)(sqlsocket, inst->config); } break; /* * Got accounting stop packet */ case PW_STATUS_STOP: /* * Set, escape, and check the user attr here */ sql_set_user(inst, request, sqlusername, NULL); radius_xlat(querystr, sizeof(querystr), inst->config->accounting_stop_query, request, sql_escape_func); query_log(request, inst, querystr); sqlsocket = sql_get_socket(inst); if (sqlsocket == NULL) return(RLM_MODULE_FAIL); if (*querystr) { /* non-empty query */ if (rlm_sql_query(sqlsocket, inst, querystr)) { radlog(L_ERR, "rlm_sql (%s): Couldn't update SQL accounting STOP record - %s", inst->config->xlat_name, (char *)(inst->module->sql_error)(sqlsocket, inst->config)); ret = RLM_MODULE_FAIL; } else { numaffected = (inst->module->sql_affected_rows)(sqlsocket, inst->config); if (numaffected < 1) { /* * If our update above didn't match anything * we assume it's because we haven't seen a * matching Start record. So we have to * insert this stop rather than do an update */#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 ((pair = pairfind(request->packet->vps, PW_ACCT_SESSION_TIME)) != NULL) acctsessiontime = pair->lvalue; if (acctsessiontime <= 0) { radius_xlat(logstr, sizeof(logstr), "rlm_sql: Stop packet with zero session length. (user '%{User-Name}', nas '%{NAS-IP-Address}')", request, sql_escape_func); radlog(L_ERR, logstr); sql_release_socket(inst, sqlsocket); ret = RLM_MODULE_NOOP; }#endif radius_xlat(querystr, sizeof(querystr), inst->config->accounting_stop_query_alt, request, sql_escape_func); query_log(request, inst, querystr); if (*querystr) { /* non-empty query */ if (rlm_sql_query(sqlsocket, inst, querystr)) { radlog(L_ERR, "rlm_sql (%s): Couldn't insert SQL accounting STOP record - %s", inst->config->xlat_name, (char *)(inst->module->sql_error)(sqlsocket, inst->config)); ret = RLM_MODULE_FAIL; } (inst->module->sql_finish_query)(sqlsocket, inst->config); } } } (inst->module->sql_finish_query)(sqlsocket, inst->config); } break; /* * Anything else is ignored. */ default: radlog(L_INFO, "rlm_sql (%s): Unsupported Acct-Status-Type = %d", inst->config->xlat_name, acctstatustype); return RLM_MODULE_NOOP; break; } sql_release_socket(inst, sqlsocket); return ret;}/* * See if a user is already logged in. Sets request->simul_count to the * current session count for this user. * * Check twice. If on the first pass the user exceeds his * max. number of logins, do a second pass and validate all * logins by querying the terminal server (using eg. SNMP). */static int rlm_sql_checksimul(void *instance, REQUEST * request) { SQLSOCK *sqlsocket; SQL_INST *inst = instance; SQL_ROW row; char querystr[MAX_QUERY_LEN]; char sqlusername[MAX_STRING_LEN]; int check = 0; uint32_t ipno = 0; char *call_num = NULL; VALUE_PAIR *vp; int ret; uint32_t nas_addr = 0; int nas_port = 0; /* If simul_count_query is not defined, we don't do any checking */ if (inst->config->simul_count_query[0] == 0) { return RLM_MODULE_NOOP; } if((request->username == NULL) || (request->username->length == 0)) { radlog(L_ERR, "rlm_sql (%s): Zero Length username not permitted\n", inst->config->xlat_name); return RLM_MODULE_INVALID; } if(sql_set_user(inst, request, sqlusername, NULL) < 0) return RLM_MODULE_FAIL; radius_xlat(querystr, sizeof(querystr), inst->config->simul_count_query, request, sql_escape_func); /* initialize the sql socket */ sqlsocket = sql_get_socket(inst); if(sqlsocket == NULL) return RLM_MODULE_FAIL; if(rlm_sql_select_query(sqlsocket, inst, querystr)) { radlog(L_ERR, "rlm_sql (%s) sql_checksimul: Database query failed", inst->config->xlat_name); sql_release_socket(inst, sqlsocket); return RLM_MODULE_FAIL; } ret = rlm_sql_fetch_row(sqlsocket, inst); if (ret != 0) { (inst->module->sql_finish_select_query)(sqlsocket, inst->config); sql_release_socket(inst, sqlsocket); return RLM_MODULE_FAIL; } row = sqlsocket->row; if (row == NULL) { (inst->module->sql_finish_select_query)(sqlsocket, inst->config); sql_release_socket(inst, sqlsocket); return RLM_MODULE_FAIL; } request->simul_count = atoi(row[0]); (inst->module->sql_finish_select_query)(sqlsocket, inst->config); if(request->simul_count < request->simul_max) { sql_release_socket(inst, sqlsocket); return RLM_MODULE_OK; } /* Looks like too many sessions, so lets start verifying them */ if (inst->config->simul_verify_query[0] == 0) { /* No verify query defined, so skip verify step and rely on count query only */ sql_release_socket(inst, sqlsocket); return RLM_MODULE_OK; } radius_xlat(querystr, sizeof(querystr), inst->config->simul_verify_query, request, sql_escape_func); if(rlm_sql_select_query(sqlsocket, inst, querystr)) { radlog(L_ERR, "rlm_sql (%s): sql_checksimul: Database query error", inst->config->xlat_name); sql_release_socket(inst, sqlsocket); return RLM_MODULE_FAIL; } /* * Setup some stuff, like for MPP detection. */ request->simul_count = 0; if ((vp = pairfind(request->packet->vps, PW_FRAMED_IP_ADDRESS)) != NULL) ipno = vp->lvalue; if ((vp = pairfind(request->packet->vps, PW_CALLING_STATION_ID)) != NULL) call_num = vp->strvalue; while (rlm_sql_fetch_row(sqlsocket, inst) == 0) { row = sqlsocket->row; if (row == NULL) break; if (!row[2]){ (inst->module->sql_finish_select_query)(sqlsocket, inst->config); sql_release_socket(inst, sqlsocket); DEBUG("rlm_sql (%s): Cannot zap stale entry. No username present in entry.", inst->config->xlat_name); return RLM_MODULE_FAIL; } if (!row[1]){ (inst->module->sql_finish_select_query)(sqlsocket, inst->config); sql_release_socket(inst, sqlsocket); DEBUG("rlm_sql (%s): Cannot zap stale entry. No session id in entry.", inst->config->xlat_name); return RLM_MODULE_FAIL; } if (row[3]) nas_addr = inet_addr(row[3]); if (row[4]) nas_port = atoi(row[4]); check = rad_check_ts(nas_addr, nas_port, row[2], row[1]); /* * Failed to check the terminal server for * duplicate logins: Return an error. */ if (check < 0) { (inst->module->sql_finish_select_query)(sqlsocket, inst->config); sql_release_socket(inst, sqlsocket); DEBUG("rlm_sql (%s) rad_check_ts() failed.", inst->config->xlat_name); return RLM_MODULE_FAIL; } if(check == 1) { ++request->simul_count; /* * Does it look like a MPP attempt? */ if (row[5] && ipno && inet_addr(row[5]) == ipno) request->simul_mpp = 2; else if (row[6] && call_num && !strncmp(row[6],call_num,16)) request->simul_mpp = 2; } else { /* * Stale record - zap it. */ uint32_t framed_addr = 0; char proto = 'P'; if (row[5]) framed_addr = inet_addr(row[5]); if (row[7]) if (strcmp(row[7],"SLIP") == 0) proto = 'S'; session_zap(request, nas_addr,nas_port,row[2],row[1], framed_addr, proto); } } (inst->module->sql_finish_select_query)(sqlsocket, inst->config); sql_release_socket(inst, sqlsocket); /* The Auth module apparently looks at request->simul_count, not the return value of this module when deciding to deny a call for too many sessions */ return RLM_MODULE_OK;}/* * Execute postauth_query after authentication */static int rlm_sql_postauth(void *instance, REQUEST *request) { SQLSOCK *sqlsocket = NULL; SQL_INST *inst = instance; char querystr[MAX_QUERY_LEN]; char sqlusername[MAX_STRING_LEN]; DEBUG("rlm_sql (%s): Processing sql_postauth", inst->config->xlat_name); if(sql_set_user(inst, request, sqlusername, NULL) < 0) return RLM_MODULE_FAIL; /* If postauth_query is not defined, we stop here */ if (inst->config->postauth_query[0] == '\0') return RLM_MODULE_NOOP; /* Expand variables in the query */ memset(querystr, 0, MAX_QUERY_LEN); radius_xlat(querystr, sizeof(querystr), inst->config->postauth_query, request, sql_escape_func); query_log(request, inst, querystr); DEBUG2("rlm_sql (%s) in sql_postauth: query is %s", inst->config->xlat_name, querystr); /* Initialize the sql socket */ sqlsocket = sql_get_socket(inst); if (sqlsocket == NULL) return RLM_MODULE_FAIL; /* Process the query */ if (rlm_sql_query(sqlsocket, inst, querystr)) { radlog(L_ERR, "rlm_sql (%s) in sql_postauth: Database query error - %s", inst->config->xlat_name, (char *)(inst->module->sql_error)(sqlsocket, inst->config)); sql_release_socket(inst, sqlsocket); return RLM_MODULE_FAIL; } (inst->module->sql_finish_query)(sqlsocket, inst->config); sql_release_socket(inst, sqlsocket); return RLM_MODULE_OK;}/* globally exported name */module_t rlm_sql = { "SQL", RLM_TYPE_THREAD_SAFE, /* type: reserved */ rlm_sql_init, /* initialization */ rlm_sql_instantiate, /* instantiation */ { NULL, /* authentication */ rlm_sql_authorize, /* authorization */ NULL, /* preaccounting */ rlm_sql_accounting, /* accounting */ rlm_sql_checksimul, /* checksimul */ NULL, /* pre-proxy */ NULL, /* post-proxy */ rlm_sql_postauth /* post-auth */ }, rlm_sql_detach, /* detach */ rlm_sql_destroy, /* destroy */};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -