/************************************************************************* * * Function: sql_getvpdata * * Purpose: Get any group check or reply pairs * *************************************************************************/ int sql_getvpdata(rlm_sql_t * inst, rlm_sql_handle_t **handle, TALLOC_CTX *ctx, VALUE_PAIR **pair, char const *query) { rlm_sql_row_t row; int rows = 0; if (rlm_sql_select_query(handle, inst, query)) { return -1; } while (rlm_sql_fetch_row(handle, inst) == 0) { row = (*handle)->row; if (!row) break; if (sql_userparse(ctx, pair, row) != 0) { ERROR("rlm_sql (%s): Error getting data from database", inst->config->xlat_name); (inst->module->sql_finish_select_query)(*handle, inst->config); return -1; } rows++; } (inst->module->sql_finish_select_query)(*handle, inst->config); return rows; }
/************************************************************************* * * Function: sql_getvpdata * * Purpose: Get any group check or reply pairs * *************************************************************************/ int sql_getvpdata(SQL_INST * inst, SQLSOCK **sqlsocket, VALUE_PAIR **pair, char *query) { SQL_ROW row; int rows = 0; if (rlm_sql_select_query(sqlsocket, inst, query)) return -1; while (rlm_sql_fetch_row(sqlsocket, inst) == 0) { row = (*sqlsocket)->row; if (!row) break; if (sql_userparse(pair, row) != 0) { radlog(L_ERR | L_CONS, "rlm_sql (%s): Error getting data from database", inst->config->xlat_name); (inst->module->sql_finish_select_query)(*sqlsocket, inst->config); return -1; } rows++; } (inst->module->sql_finish_select_query)(*sqlsocket, inst->config); return rows; }
/************************************************************************* * * Function: sql_getvpdata * * Purpose: Get any group check or reply pairs * *************************************************************************/ int sql_getvpdata(TALLOC_CTX *ctx, rlm_sql_t *inst, REQUEST *request, rlm_sql_handle_t **handle, VALUE_PAIR **pair, char const *query) { rlm_sql_row_t row; int rows = 0; sql_rcode_t rcode; rcode = rlm_sql_select_query(handle, inst, query); if (rcode != RLM_SQL_OK) return -1; /* error handled by rlm_sql_select_query */ while (rlm_sql_fetch_row(&row, handle, inst) == 0) { if (!row) break; if (sql_userparse(ctx, pair, row) != 0) { REDEBUG("Error parsing user data from database result"); (inst->module->sql_finish_select_query)(*handle, inst->config); return -1; } rows++; } (inst->module->sql_finish_select_query)(*handle, inst->config); return rows; }
static int SelectFirstRowInternal(SQL_INST* sqlinst, const char* sqlbuf, DBUtil::Row& row) { SQLSOCK* sqlsock = sql_get_socket(sqlinst); if(sqlsock == NULL) { return -1; } if(rlm_sql_select_query(sqlsock, sqlinst, sqlbuf) != 0) { sql_release_socket(sqlinst, sqlsock); return -1; } if(rlm_sql_fetch_row(sqlsock, sqlinst) != 0) { rlm_sql_finish_select_query(sqlsock, sqlinst); sql_release_socket(sqlinst, sqlsock); return -1; } if(sqlsock->row == NULL) { rlm_sql_finish_select_query(sqlsock, sqlinst); sql_release_socket(sqlinst, sqlsock); return 0; } int colcnt = rlm_sql_num_fields(sqlsock, sqlinst); row.clear(); for(int i=0; i<colcnt; ++i) row.push_back(sqlsock->row[i]); rlm_sql_finish_select_query(sqlsock, sqlinst); sql_release_socket(sqlinst, sqlsock); return 1; }
/************************************************************************* * * Function: sql_getvpdata * * Purpose: Get any group check or reply pairs * *************************************************************************/ int sql_getvpdata(SQL_INST * inst, SQLSOCK * sqlsocket, VALUE_PAIR **pair, char *query) { SQL_ROW row; int rows = 0; /* * If there's no query, return an error. */ if (!query || !*query) { return -1; } if (rlm_sql_select_query(sqlsocket, inst, query)) { radlog(L_ERR, "rlm_sql_getvpdata: database query error"); return -1; } while (rlm_sql_fetch_row(sqlsocket, inst)==0) { row = sqlsocket->row; if (!row) break; if (sql_userparse(pair, row) != 0) { radlog(L_ERR | L_CONS, "rlm_sql (%s): Error getting data from database", inst->config->xlat_name); (inst->module->sql_finish_select_query)(sqlsocket, inst->config); return -1; } rows++; } (inst->module->sql_finish_select_query)(sqlsocket, inst->config); return rows; }
/************************************************************************* * * Function: sql_getvpdata * * Purpose: Get any group check or reply pairs * *************************************************************************/ int sql_getvpdata(TALLOC_CTX *ctx, rlm_sql_t const *inst, REQUEST *request, rlm_sql_handle_t **handle, VALUE_PAIR **pair, char const *query) { rlm_sql_row_t row; int rows = 0; sql_rcode_t rcode; rad_assert(request); rcode = rlm_sql_select_query(inst, request, handle, query); if (rcode != RLM_SQL_OK) return -1; /* error handled by rlm_sql_select_query */ while (rlm_sql_fetch_row(&row, inst, request, handle) == RLM_SQL_OK) { if (sql_fr_pair_list_afrom_str(ctx, request, pair, row) != 0) { REDEBUG("Error parsing user data from database result"); (inst->driver->sql_finish_select_query)(*handle, inst->config); return -1; } rows++; } (inst->driver->sql_finish_select_query)(*handle, inst->config); return rows; }
static int sql_get_grouplist(rlm_sql_t *inst, rlm_sql_handle_t **handle, REQUEST *request, rlm_sql_grouplist_t **phead) { char *expanded = NULL; int num_groups = 0; rlm_sql_row_t row; rlm_sql_grouplist_t *entry; int ret; /* NOTE: sql_set_user should have been run before calling this function */ entry = *phead = NULL; if (!inst->config->groupmemb_query || (inst->config->groupmemb_query[0] == 0)) { return 0; } if (radius_axlat(&expanded, request, inst->config->groupmemb_query, sql_escape_func, inst) < 0) { return -1; } ret = rlm_sql_select_query(handle, inst, expanded); talloc_free(expanded); if (ret != RLM_SQL_OK) { return -1; } while (rlm_sql_fetch_row(handle, inst) == 0) { row = (*handle)->row; if (!row) break; if (!row[0]){ RDEBUG("row[0] returned NULL"); (inst->module->sql_finish_select_query)(*handle, inst->config); talloc_free(entry); return -1; } if (!*phead) { *phead = talloc_zero(*handle, rlm_sql_grouplist_t); entry = *phead; } else { entry->next = talloc_zero(*phead, rlm_sql_grouplist_t); entry = entry->next; } entry->next = NULL; entry->name = talloc_typed_strdup(entry, row[0]); num_groups++; } (inst->module->sql_finish_select_query)(*handle, inst->config); return num_groups; }
static int sql_get_grouplist (SQL_INST *inst, SQLSOCK *sqlsocket, REQUEST *request, SQL_GROUPLIST **group_list) { char querystr[MAX_QUERY_LEN]; int num_groups = 0; SQL_ROW row; SQL_GROUPLIST *group_list_tmp; /* NOTE: sql_set_user should have been run before calling this function */ group_list_tmp = *group_list = NULL; if (!inst->config->groupmemb_query || (inst->config->groupmemb_query[0] == 0)) return 0; if (!radius_xlat(querystr, sizeof(querystr), inst->config->groupmemb_query, request, sql_escape_func)) { radlog_request(L_ERR, 0, request, "xlat \"%s\" failed.", inst->config->groupmemb_query); return -1; } if (rlm_sql_select_query(sqlsocket, inst, querystr) < 0) { radlog_request(L_ERR, 0, request, "database query error, %s: %s", querystr, (inst->module->sql_error)(sqlsocket,inst->config)); return -1; } while (rlm_sql_fetch_row(sqlsocket, inst) == 0) { row = sqlsocket->row; if (row == NULL) break; if (row[0] == NULL){ RDEBUG("row[0] returned NULL"); (inst->module->sql_finish_select_query)(sqlsocket, inst->config); sql_grouplist_free(group_list); return -1; } if (*group_list == NULL) { *group_list = rad_malloc(sizeof(SQL_GROUPLIST)); group_list_tmp = *group_list; } else { rad_assert(group_list_tmp != NULL); group_list_tmp->next = rad_malloc(sizeof(SQL_GROUPLIST)); group_list_tmp = group_list_tmp->next; } group_list_tmp->next = NULL; strlcpy(group_list_tmp->groupname, row[0], MAX_STRING_LEN); } (inst->module->sql_finish_select_query)(sqlsocket, inst->config); return num_groups; }
static int sql_get_grouplist (rlm_sql_t *inst, rlm_sql_handle_t *handle, REQUEST *request, rlm_sql_grouplist_t **group_list) { char querystr[MAX_QUERY_LEN]; int num_groups = 0; rlm_sql_row_t row; rlm_sql_grouplist_t *group_list_tmp; /* NOTE: sql_set_user should have been run before calling this function */ group_list_tmp = *group_list = NULL; if (!inst->config->groupmemb_query || (inst->config->groupmemb_query[0] == 0)) return 0; if (!radius_xlat(querystr, sizeof(querystr), inst->config->groupmemb_query, request, sql_escape_func, inst)) { radlog_request(L_ERR, 0, request, "xlat \"%s\" failed.", inst->config->groupmemb_query); return -1; } if (rlm_sql_select_query(&handle, inst, querystr) < 0) { return -1; } while (rlm_sql_fetch_row(&handle, inst) == 0) { row = handle->row; if (row == NULL) break; if (row[0] == NULL){ RDEBUG("row[0] returned NULL"); (inst->module->sql_finish_select_query)(handle, inst->config); sql_grouplist_free(group_list); return -1; } if (*group_list == NULL) { *group_list = rad_malloc(sizeof(rlm_sql_grouplist_t)); group_list_tmp = *group_list; } else { rad_assert(group_list_tmp != NULL); group_list_tmp->next = rad_malloc(sizeof(rlm_sql_grouplist_t)); group_list_tmp = group_list_tmp->next; } group_list_tmp->next = NULL; strlcpy(group_list_tmp->groupname, row[0], MAX_STRING_LEN); } (inst->module->sql_finish_select_query)(handle, inst->config); return num_groups; }
int DBUtil::Query(RowSet& rset, const char* sql, ...) { SQL_INST* sqlinst = (SQL_INST*)dbHandle_; if(sqlinst == 0) { radlog(L_CONS|L_ERROR, "[DBUtil::Query] invalid instance"); return -1; } char sqlbuf[4096]; va_list args; va_start(args, sql); vsNprintf(sqlbuf, sizeof(sqlbuf), sql, args); va_end(args); SQLSOCK* sqlsock = sql_get_socket(sqlinst); if(sqlsock == NULL) { return -1; } if(rlm_sql_select_query(sqlsock, sqlinst, sqlbuf) != 0) { sql_release_socket(sqlinst, sqlsock); return -1; } int colcnt = rlm_sql_num_fields(sqlsock, sqlinst); int rownum = 0; rset.clear(); for(;;) { if(rlm_sql_fetch_row(sqlsock, sqlinst) != 0) { rownum = -1; break; } if(sqlsock->row == NULL) { break; } ++rownum; Row row; for(int i=0; i<colcnt; ++i) row.push_back(sqlsock->row[i]); rset.push_back(row); } rlm_sql_finish_select_query(sqlsock, sqlinst); sql_release_socket(sqlinst, sqlsock); return rownum; }
static int generate_sql_clients(rlm_sql_t *inst) { rlm_sql_handle_t *handle; rlm_sql_row_t row; unsigned int i = 0; RADCLIENT *c; DEBUG("rlm_sql (%s): Processing generate_sql_clients", inst->config->xlat_name); DEBUG("rlm_sql (%s) in generate_sql_clients: query is %s", inst->config->xlat_name, inst->config->client_query); handle = sql_get_socket(inst); if (!handle) { return -1; } if (rlm_sql_select_query(&handle, inst, inst->config->client_query)){ return -1; } while((rlm_sql_fetch_row(&handle, inst) == 0) && (row = handle->row)) { char *server = NULL; i++; /* * The return data for each row MUST be in the following order: * * 0. Row ID (currently unused) * 1. Name (or IP address) * 2. Shortname * 3. Type * 4. Secret * 5. Virtual Server (optional) */ if (!row[0]){ ERROR("rlm_sql (%s): No row id found on pass %d",inst->config->xlat_name,i); continue; } if (!row[1]){ ERROR("rlm_sql (%s): No nasname found for row %s",inst->config->xlat_name,row[0]); continue; } if (!row[2]){ ERROR("rlm_sql (%s): No short name found for row %s",inst->config->xlat_name,row[0]); continue; } if (!row[4]){ ERROR("rlm_sql (%s): No secret found for row %s",inst->config->xlat_name,row[0]); continue; } if (((inst->module->sql_num_fields)(handle, inst->config) > 5) && (row[5] != NULL) && *row[5]) { server = row[5]; } DEBUG("rlm_sql (%s): Adding client %s (%s) to %s clients list", inst->config->xlat_name, row[1], row[2], server ? server : "global"); /* FIXME: We should really pass a proper ctx */ c = client_from_query(NULL, row[1], /* identifier */ row[4], /* secret */ row[2], /* shortname */ row[3], /* type */ server, /* server */ false); /* require message authenticator */ if (!c) { continue; } if (!client_add(NULL, c)) { WARN("Failed to add client, possible duplicate?"); client_free(c); continue; } DEBUG("rlm_sql (%s): Client \"%s\" (%s) added", c->longname, c->shortname, inst->config->xlat_name); } (inst->module->sql_finish_select_query)(handle, inst->config); sql_release_socket(inst, handle); return 0; }
/* * SQL xlat function * * For selects the first value of the first column will be returned, * for inserts, updates and deletes the number of rows afftected will be * returned instead. */ static ssize_t sql_xlat(void *instance, REQUEST *request, char const *query, char *out, size_t freespace) { rlm_sql_handle_t *handle = NULL; rlm_sql_row_t row; rlm_sql_t *inst = instance; ssize_t ret = 0; size_t len = 0; /* * Add SQL-User-Name attribute just in case it is needed * We could search the string fmt for SQL-User-Name to see if this is * needed or not */ sql_set_user(inst, request, NULL); handle = sql_get_socket(inst); if (!handle) { return 0; } rlm_sql_query_log(inst, request, NULL, query); /* * If the query starts with any of the following prefixes, * then return the number of rows affected */ if ((strncasecmp(query, "insert", 6) == 0) || (strncasecmp(query, "update", 6) == 0) || (strncasecmp(query, "delete", 6) == 0)) { int numaffected; char buffer[21]; /* 64bit max is 20 decimal chars + null byte */ if (rlm_sql_query(&handle, inst, query)) { char const *error = (inst->module->sql_error)(handle, inst->config); REDEBUG("SQL query failed: %s", error); ret = -1; goto finish; } numaffected = (inst->module->sql_affected_rows)(handle, inst->config); if (numaffected < 1) { RDEBUG("SQL query affected no rows"); goto finish; } /* * Don't chop the returned number if freespace is * too small. This hack is necessary because * some implementations of snprintf return the * size of the written data, and others return * the size of the data they *would* have written * if the output buffer was large enough. */ snprintf(buffer, sizeof(buffer), "%d", numaffected); len = strlen(buffer); if (len >= freespace){ RDEBUG("rlm_sql (%s): Can't write result, insufficient string space", inst->config->xlat_name); (inst->module->sql_finish_query)(handle, inst->config); ret = -1; goto finish; } memcpy(out, buffer, len + 1); /* we did bounds checking above */ ret = len; (inst->module->sql_finish_query)(handle, inst->config); goto finish; } /* else it's a SELECT statement */ if (rlm_sql_select_query(&handle, inst, query)){ char const *error = (inst->module->sql_error)(handle, inst->config); REDEBUG("SQL query failed: %s", error); ret = -1; goto finish; } ret = rlm_sql_fetch_row(&handle, inst); if (ret) { REDEBUG("SQL query failed"); (inst->module->sql_finish_select_query)(handle, inst->config); ret = -1; goto finish; } row = handle->row; if (!row) { RDEBUG("SQL query returned no results"); (inst->module->sql_finish_select_query)(handle, inst->config); ret = -1; goto finish; } if (!row[0]){ RDEBUG("NULL value in first column of result"); (inst->module->sql_finish_select_query)(handle, inst->config); ret = -1; goto finish; } len = strlen(row[0]); if (len >= freespace){ RDEBUG("Insufficient string space"); (inst->module->sql_finish_select_query)(handle, inst->config); ret = -1; goto finish; } strlcpy(out, row[0], freespace); ret = len; (inst->module->sql_finish_select_query)(handle, inst->config); finish: sql_release_socket(inst, handle); return ret; }
static rlm_rcode_t mod_checksimul(void *instance, REQUEST * request) { rlm_rcode_t rcode = RLM_MODULE_OK; rlm_sql_handle_t *handle = NULL; rlm_sql_t *inst = instance; rlm_sql_row_t row; int check = 0; uint32_t ipno = 0; char const *call_num = NULL; VALUE_PAIR *vp; int ret; uint32_t nas_addr = 0; int nas_port = 0; char *expanded = NULL; /* If simul_count_query is not defined, we don't do any checking */ if (!inst->config->simul_count_query || (inst->config->simul_count_query[0] == '\0')) { return RLM_MODULE_NOOP; } if((!request->username) || (request->username->length == '\0')) { REDEBUG("Zero Length username not permitted"); return RLM_MODULE_INVALID; } if(sql_set_user(inst, request, NULL) < 0) { return RLM_MODULE_FAIL; } if (radius_axlat(&expanded, request, inst->config->simul_count_query, sql_escape_func, inst) < 0) { return RLM_MODULE_FAIL; } /* initialize the sql socket */ handle = sql_get_socket(inst); if (!handle) { talloc_free(expanded); return RLM_MODULE_FAIL; } if (rlm_sql_select_query(&handle, inst, expanded)) { rcode = RLM_MODULE_FAIL; goto finish; } ret = rlm_sql_fetch_row(&handle, inst); if (ret != 0) { rcode = RLM_MODULE_FAIL; goto finish; } row = handle->row; if (!row) { rcode = RLM_MODULE_FAIL; goto finish; } request->simul_count = atoi(row[0]); (inst->module->sql_finish_select_query)(handle, inst->config); TALLOC_FREE(expanded); if(request->simul_count < request->simul_max) { rcode = RLM_MODULE_OK; goto finish; } /* * Looks like too many sessions, so let's start verifying * them, unless told to rely on count query only. */ if (!inst->config->simul_verify_query || (inst->config->simul_verify_query[0] == '\0')) { rcode = RLM_MODULE_OK; goto finish; } if (radius_axlat(&expanded, request, inst->config->simul_verify_query, sql_escape_func, inst) < 0) { rcode = RLM_MODULE_FAIL; goto finish; } if(rlm_sql_select_query(&handle, inst, expanded)) { goto finish; } /* * Setup some stuff, like for MPP detection. */ request->simul_count = 0; if ((vp = pairfind(request->packet->vps, PW_FRAMED_IP_ADDRESS, 0, TAG_ANY)) != NULL) { ipno = vp->vp_ipaddr; } if ((vp = pairfind(request->packet->vps, PW_CALLING_STATION_ID, 0, TAG_ANY)) != NULL) { call_num = vp->vp_strvalue; } while (rlm_sql_fetch_row(&handle, inst) == 0) { row = handle->row; if (!row) { break; } if (!row[2]){ RDEBUG("Cannot zap stale entry. No username present in entry"); rcode = RLM_MODULE_FAIL; goto finish; } if (!row[1]){ RDEBUG("Cannot zap stale entry. No session id in entry"); rcode = RLM_MODULE_FAIL; goto finish; } 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]); if (check == 0) { /* * Stale record - zap it. */ if (inst->config->deletestalesessions == true) { uint32_t framed_addr = 0; char proto = 0; int sess_time = 0; if (row[5]) framed_addr = inet_addr(row[5]); if (row[7]){ if (strcmp(row[7], "PPP") == 0) proto = 'P'; else if (strcmp(row[7], "SLIP") == 0) proto = 'S'; } if (row[8]) sess_time = atoi(row[8]); session_zap(request, nas_addr, nas_port, row[2], row[1], framed_addr, proto, sess_time); } } else if (check == 1) { /* * User is still logged in. */ ++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 { /* * Failed to check the terminal server for * duplicate logins: return an error. */ REDEBUG("Failed to check the terminal server for user '%s'.", row[2]); rcode = RLM_MODULE_FAIL; goto finish; } } finish: (inst->module->sql_finish_select_query)(handle, inst->config); sql_release_socket(inst, handle); talloc_free(expanded); /* * 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 rcode; }
static int generate_sql_clients(rlm_sql_t *inst) { rlm_sql_handle_t *handle; rlm_sql_row_t row; char querystr[MAX_QUERY_LEN]; RADCLIENT *c; char *prefix_ptr = NULL; unsigned int i = 0; int numf = 0; DEBUG("rlm_sql (%s): Processing generate_sql_clients", inst->config->xlat_name); /* NAS query isn't xlat'ed */ strlcpy(querystr, inst->config->nas_query, sizeof(querystr)); DEBUG("rlm_sql (%s) in generate_sql_clients: query is %s", inst->config->xlat_name, querystr); handle = sql_get_socket(inst); if (handle == NULL) return -1; if (rlm_sql_select_query(&handle,inst,querystr)){ return -1; } while(rlm_sql_fetch_row(&handle, inst) == 0) { i++; row = handle->row; if (row == NULL) break; /* * The return data for each row MUST be in the following order: * * 0. Row ID (currently unused) * 1. Name (or IP address) * 2. Shortname * 3. Type * 4. Secret * 5. Virtual Server (optional) */ if (!row[0]){ radlog(L_ERR, "rlm_sql (%s): No row id found on pass %d",inst->config->xlat_name,i); continue; } if (!row[1]){ radlog(L_ERR, "rlm_sql (%s): No nasname found for row %s",inst->config->xlat_name,row[0]); continue; } if (!row[2]){ radlog(L_ERR, "rlm_sql (%s): No short name found for row %s",inst->config->xlat_name,row[0]); continue; } if (!row[4]){ radlog(L_ERR, "rlm_sql (%s): No secret found for row %s",inst->config->xlat_name,row[0]); continue; } DEBUG("rlm_sql (%s): Read entry nasname=%s,shortname=%s,secret=%s",inst->config->xlat_name, row[1],row[2],row[4]); c = talloc_zero(inst, RADCLIENT); #ifdef WITH_DYNAMIC_CLIENTS c->dynamic = 1; #endif /* * Look for prefixes */ c->prefix = -1; prefix_ptr = strchr(row[1], '/'); if (prefix_ptr) { c->prefix = atoi(prefix_ptr + 1); if ((c->prefix < 0) || (c->prefix > 128)) { radlog(L_ERR, "rlm_sql (%s): Invalid Prefix value '%s' for IP.", inst->config->xlat_name, prefix_ptr + 1); talloc_free(c); continue; } /* Replace '/' with '\0' */ *prefix_ptr = '\0'; } /* * Always get the numeric representation of IP */ if (ip_hton(row[1], AF_UNSPEC, &c->ipaddr) < 0) { radlog(L_ERR, "rlm_sql (%s): Failed to look up hostname %s: %s", inst->config->xlat_name, row[1], fr_strerror()); talloc_free(c); continue; } else { char buffer[256]; ip_ntoh(&c->ipaddr, buffer, sizeof(buffer)); c->longname = talloc_strdup(c, buffer); } if (c->prefix < 0) switch (c->ipaddr.af) { case AF_INET: c->prefix = 32; break; case AF_INET6: c->prefix = 128; break; default: break; } /* * Other values (secret, shortname, nastype, virtual_server) */ c->secret = talloc_strdup(c, row[4]); c->shortname = talloc_strdup(c, row[2]); if(row[3] != NULL) c->nastype = strdup(row[3]); numf = (inst->module->sql_num_fields)(handle, inst->config); if ((numf > 5) && (row[5] != NULL) && *row[5]) c->server = strdup(row[5]); DEBUG("rlm_sql (%s): Adding client %s (%s, server=%s) to clients list", inst->config->xlat_name, c->longname,c->shortname, c->server ? c->server : "<none>"); if (!client_add(NULL, c)) { sql_release_socket(inst, handle); DEBUG("rlm_sql (%s): Failed to add client %s (%s) to clients list. Maybe there's a duplicate?", inst->config->xlat_name, c->longname,c->shortname); client_free(c); return -1; } } (inst->module->sql_finish_select_query)(handle, inst->config); sql_release_socket(inst, handle); return 0; }
/* * SQL xlat function * * For selects the first value of the first column will be returned, * for inserts, updates and deletes the number of rows afftected will be * returned instead. */ static size_t sql_xlat(void *instance, REQUEST *request, const char *fmt, char *out, size_t freespace) { rlm_sql_handle_t *handle; rlm_sql_row_t row; rlm_sql_t *inst = instance; char querystr[MAX_QUERY_LEN]; size_t ret = 0; RDEBUG("sql_xlat"); /* * Add SQL-User-Name attribute just in case it is needed * We could search the string fmt for SQL-User-Name to see if this is * needed or not */ sql_set_user(inst, request, NULL); /* * Do an xlat on the provided string (nice recursive operation). */ if (!radius_xlat(querystr, sizeof(querystr), fmt, request, sql_escape_func, inst)) { radlog(L_ERR, "rlm_sql (%s): xlat failed.", inst->config->xlat_name); return 0; } handle = sql_get_socket(inst); if (handle == NULL) return 0; rlm_sql_query_log(inst, request, NULL, querystr); /* * If the query starts with any of the following prefixes, * then return the number of rows affected */ if ((strncasecmp(querystr, "insert", 6) == 0) || (strncasecmp(querystr, "update", 6) == 0) || (strncasecmp(querystr, "delete", 6) == 0)) { int numaffected; char buffer[21]; /* 64bit max is 20 decimal chars + null byte */ if (rlm_sql_query(&handle,inst,querystr)) { sql_release_socket(inst,handle); return 0; } numaffected = (inst->module->sql_affected_rows)(handle, inst->config); if (numaffected < 1) { RDEBUG("rlm_sql (%s): SQL query affected no rows", inst->config->xlat_name); } /* * Don't chop the returned number if freespace is * too small. This hack is necessary because * some implementations of snprintf return the * size of the written data, and others return * the size of the data they *would* have written * if the output buffer was large enough. */ snprintf(buffer, sizeof(buffer), "%d", numaffected); ret = strlen(buffer); if (ret >= freespace){ RDEBUG("rlm_sql (%s): Can't write result, insufficient string space", inst->config->xlat_name); (inst->module->sql_finish_query)(handle, inst->config); sql_release_socket(inst,handle); return 0; } memcpy(out, buffer, ret + 1); /* we did bounds checking above */ (inst->module->sql_finish_query)(handle, inst->config); sql_release_socket(inst,handle); return ret; } /* else it's a SELECT statement */ if (rlm_sql_select_query(&handle,inst,querystr)){ sql_release_socket(inst,handle); return 0; } ret = rlm_sql_fetch_row(&handle, inst); if (ret) { RDEBUG("SQL query did not succeed"); (inst->module->sql_finish_select_query)(handle, inst->config); sql_release_socket(inst,handle); return 0; } row = handle->row; if (row == NULL) { RDEBUG("SQL query did not return any results"); (inst->module->sql_finish_select_query)(handle, inst->config); sql_release_socket(inst,handle); return 0; } if (row[0] == NULL){ RDEBUG("Null value in first column"); (inst->module->sql_finish_select_query)(handle, inst->config); sql_release_socket(inst,handle); return 0; } ret = strlen(row[0]); if (ret >= freespace){ RDEBUG("Insufficient string space"); (inst->module->sql_finish_select_query)(handle, inst->config); sql_release_socket(inst,handle); return 0; } strlcpy(out,row[0],freespace); RDEBUG("sql_xlat finished"); (inst->module->sql_finish_select_query)(handle, inst->config); sql_release_socket(inst,handle); return ret; }
static int sql_groupcmp(void *instance, REQUEST *req, VALUE_PAIR *request, VALUE_PAIR *check, VALUE_PAIR *check_pairs, VALUE_PAIR **reply_pairs) { SQLSOCK *sqlsocket; SQL_ROW row; SQL_INST *inst = instance; char querystr[MAX_QUERY_LEN]; char sqlusername[MAX_STRING_LEN]; check_pairs = check_pairs; reply_pairs = reply_pairs; DEBUG("rlm_sql (%s): - sql_groupcmp", inst->config->xlat_name); if (!check || !check->strvalue || !check->length){ DEBUG("rlm_sql (%s): sql_groupcmp: Illegal group name", inst->config->xlat_name); return 1; } if (req == NULL){ DEBUG("rlm_sql (%s): sql_groupcmp: NULL request", inst->config->xlat_name); return 1; } if (inst->config->groupmemb_query[0] == 0) return 1; /* * Set, escape, and check the user attr here */ if (sql_set_user(inst, req, sqlusername, NULL) < 0) return 1; if (!radius_xlat(querystr, sizeof(querystr), inst->config->groupmemb_query, req, sql_escape_func)){ radlog(L_ERR, "rlm_sql (%s): xlat failed.", inst->config->xlat_name); /* Remove the username we (maybe) added above */ pairdelete(&req->packet->vps, PW_SQL_USER_NAME); return 1; } /* Remove the username we (maybe) added above */ pairdelete(&req->packet->vps, PW_SQL_USER_NAME); sqlsocket = sql_get_socket(inst); if (sqlsocket == NULL) return 1; if ((inst->module->sql_select_query)(sqlsocket,inst->config,querystr) <0){ radlog(L_ERR, "rlm_sql (%s): database query error, %s: %s", inst->config->xlat_name,querystr, (char *)(inst->module->sql_error)(sqlsocket,inst->config)); sql_release_socket(inst,sqlsocket); return 1; } while (rlm_sql_fetch_row(sqlsocket, inst) == 0) { row = sqlsocket->row; if (row == NULL) break; if (row[0] == NULL){ DEBUG("rlm_sql (%s): row[0] returned NULL", inst->config->xlat_name); (inst->module->sql_finish_select_query)(sqlsocket, inst->config); sql_release_socket(inst, sqlsocket); return 1; } if (strcmp(row[0],check->strvalue) == 0){ DEBUG("rlm_sql (%s): - sql_groupcmp finished: User belongs in group %s", inst->config->xlat_name, (char *)check->strvalue); (inst->module->sql_finish_select_query)(sqlsocket, inst->config); sql_release_socket(inst, sqlsocket); return 0; } } (inst->module->sql_finish_select_query)(sqlsocket, inst->config); sql_release_socket(inst,sqlsocket); DEBUG("rlm_sql (%s): - sql_groupcmp finished: User does not belong in group %s", inst->config->xlat_name, (char *)check->strvalue); return 1; }
static int generate_sql_clients(SQL_INST *inst) { SQLSOCK *sqlsocket; SQL_ROW row; char querystr[MAX_QUERY_LEN]; RADCLIENT *c; char *netmask; unsigned int i = 0; DEBUG("rlm_sql (%s): - generate_sql_clients",inst->config->xlat_name); if (inst->config->sql_nas_table == NULL){ radlog(L_ERR, "rlm_sql (%s): sql_nas_table is NULL.",inst->config->xlat_name); return -1; } snprintf(querystr,MAX_QUERY_LEN - 1,"SELECT * FROM %s",inst->config->sql_nas_table); DEBUG("rlm_sql (%s): Query: %s",inst->config->xlat_name,querystr); sqlsocket = sql_get_socket(inst); if (sqlsocket == NULL) return -1; if (rlm_sql_select_query(sqlsocket,inst,querystr)){ radlog(L_ERR, "rlm_sql (%s): database query error, %s: %s", inst->config->xlat_name,querystr, (char *)(inst->module->sql_error)(sqlsocket, inst->config)); sql_release_socket(inst,sqlsocket); return -1; } while(rlm_sql_fetch_row(sqlsocket, inst) == 0) { i++; row = sqlsocket->row; if (row == NULL) break; /* * Format: * Row1 Row2 Row3 Row4 Row5 Row6 Row7 Row8 * * id nasname shortname type ports secret community description * */ if (!row[0]){ radlog(L_ERR, "rlm_sql (%s): No row id found on pass %d",inst->config->xlat_name,i); continue; } if (!row[1]){ radlog(L_ERR, "rlm_sql (%s): No nasname found for row %s",inst->config->xlat_name,row[0]); continue; } if (strlen(row[1]) >= sizeof(c->longname)){ radlog(L_ERR, "rlm_sql (%s): nasname of length %d is greater than the allowed maximum of %d", inst->config->xlat_name,strlen(row[1]),sizeof(c->longname) - 1); continue; } if (!row[2]){ radlog(L_ERR, "rlm_sql (%s): No short name found for row %s",inst->config->xlat_name,row[0]); continue; } if (strlen(row[2]) >= sizeof(c->shortname)){ radlog(L_ERR, "rlm_sql (%s): shortname of length %d is greater than the allowed maximum of %d", inst->config->xlat_name,strlen(row[2]),sizeof(c->shortname) - 1); continue; } if (row[3] && strlen(row[3]) >= sizeof(c->nastype)){ radlog(L_ERR, "rlm_sql (%s): nastype of length %d is greater than the allowed maximum of %d", inst->config->xlat_name,strlen(row[3]),sizeof(c->nastype) - 1); continue; } if (!row[5]){ radlog(L_ERR, "rlm_sql (%s): No secret found for row %s",inst->config->xlat_name,row[0]); continue; } if (strlen(row[5]) >= sizeof(c->secret)){ radlog(L_ERR, "rlm_sql (%s): secret of length %d is greater than the allowed maximum of %d", inst->config->xlat_name,strlen(row[5]),sizeof(c->secret) - 1); continue; } DEBUG("rlm_sql (%s): Read entry nasname=%s,shortname=%s,secret=%s",inst->config->xlat_name, row[1],row[2],row[5]); c = rad_malloc(sizeof(RADCLIENT)); memset(c, 0, sizeof(RADCLIENT)); c->netmask = ~0; netmask = strchr(row[1], '/'); /* * Look for netmasks. */ c->netmask = ~0; if (netmask) { int mask_length; mask_length = atoi(netmask + 1); if ((mask_length < 0) || (mask_length > 32)) { radlog(L_ERR, "rlm_sql (%s): Invalid value '%s' for IP network mask for nasname %s.", inst->config->xlat_name, netmask + 1,row[1]); free(c); continue; } if (mask_length == 0) { c->netmask = 0; } else { c->netmask = ~0 << (32 - mask_length); } *netmask = '\0'; c->netmask = htonl(c->netmask); } c->ipaddr = ip_getaddr(row[1]); if (c->ipaddr == INADDR_NONE) { radlog(L_CONS|L_ERR, "rlm_sql (%s): Failed to look up hostname %s", inst->config->xlat_name, row[1]); free(c); continue; } /* * Update the client name again... */ if (netmask) { *netmask = '/'; c->ipaddr &= c->netmask; strcpy(c->longname, row[1]); } else { ip_hostname(c->longname, sizeof(c->longname), c->ipaddr); } strcpy((char *)c->secret, row[5]); strcpy(c->shortname, row[2]); if(row[3] != NULL) strcpy(c->nastype, row[3]); DEBUG("rlm_sql (%s): Adding client %s (%s) to clients list",inst->config->xlat_name, c->longname,c->shortname); c->next = mainconfig.clients; mainconfig.clients = c; } (inst->module->sql_finish_select_query)(sqlsocket, inst->config); sql_release_socket(inst, sqlsocket); return 0; }
/* * sql xlat function. Right now only SELECTs are supported. Only * the first element of the SELECT result will be used. */ static int sql_xlat(void *instance, REQUEST *request, char *fmt, char *out, size_t freespace, RADIUS_ESCAPE_STRING func) { SQLSOCK *sqlsocket; SQL_ROW row; SQL_INST *inst = instance; char querystr[MAX_QUERY_LEN]; char sqlusername[MAX_STRING_LEN]; int ret = 0; DEBUG("rlm_sql (%s): - sql_xlat", inst->config->xlat_name); /* * Add SQL-User-Name attribute just in case it is needed * We could search the string fmt for SQL-User-Name to see if this is * needed or not */ sql_set_user(inst, request, sqlusername, NULL); /* * Do an xlat on the provided string (nice recursive operation). */ if (!radius_xlat(querystr, sizeof(querystr), fmt, request, sql_escape_func)) { radlog(L_ERR, "rlm_sql (%s): xlat failed.", inst->config->xlat_name); return 0; } query_log(request, inst,querystr); sqlsocket = sql_get_socket(inst); if (sqlsocket == NULL) return 0; if (rlm_sql_select_query(sqlsocket,inst,querystr)){ radlog(L_ERR, "rlm_sql (%s): database query error, %s: %s", inst->config->xlat_name,querystr, (char *)(inst->module->sql_error)(sqlsocket, inst->config)); sql_release_socket(inst,sqlsocket); return 0; } ret = rlm_sql_fetch_row(sqlsocket, inst); if (ret) { DEBUG("rlm_sql (%s): SQL query did not succeed", inst->config->xlat_name); (inst->module->sql_finish_select_query)(sqlsocket, inst->config); sql_release_socket(inst,sqlsocket); return 0; } row = sqlsocket->row; if (row == NULL) { DEBUG("rlm_sql (%s): SQL query did not return any results", inst->config->xlat_name); (inst->module->sql_finish_select_query)(sqlsocket, inst->config); sql_release_socket(inst,sqlsocket); return 0; } if (row[0] == NULL){ DEBUG("rlm_sql (%s): row[0] returned NULL", inst->config->xlat_name); (inst->module->sql_finish_select_query)(sqlsocket, inst->config); sql_release_socket(inst,sqlsocket); return 0; } ret = strlen(row[0]); if (ret > freespace){ DEBUG("rlm_sql (%s): sql_xlat:: Insufficient string space", inst->config->xlat_name); (inst->module->sql_finish_select_query)(sqlsocket, inst->config); sql_release_socket(inst,sqlsocket); return 0; } strncpy(out,row[0],ret); DEBUG("rlm_sql (%s): - sql_xlat finished", inst->config->xlat_name); (inst->module->sql_finish_select_query)(sqlsocket, inst->config); sql_release_socket(inst,sqlsocket); return ret; }
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 an arbitrary SQL query * * For selects the first value of the first column will be returned, * for inserts, updates and deletes the number of rows affected will be * returned instead. */ static ssize_t sql_xlat(char **out, UNUSED size_t outlen, void const *mod_inst, UNUSED void const *xlat_inst, REQUEST *request, char const *fmt) { rlm_sql_handle_t *handle = NULL; rlm_sql_row_t row; rlm_sql_t const *inst = mod_inst; sql_rcode_t rcode; ssize_t ret = 0; /* * Add SQL-User-Name attribute just in case it is needed * We could search the string fmt for SQL-User-Name to see if this is * needed or not */ sql_set_user(inst, request, NULL); handle = fr_connection_get(inst->pool); /* connection pool should produce error */ if (!handle) return 0; rlm_sql_query_log(inst, request, NULL, fmt); /* * If the query starts with any of the following prefixes, * then return the number of rows affected */ if ((strncasecmp(fmt, "insert", 6) == 0) || (strncasecmp(fmt, "update", 6) == 0) || (strncasecmp(fmt, "delete", 6) == 0)) { int numaffected; rcode = rlm_sql_query(inst, request, &handle, fmt); if (rcode != RLM_SQL_OK) { query_error: RERROR("SQL query failed: %s", fr_int2str(sql_rcode_table, rcode, "<INVALID>")); ret = -1; goto finish; } numaffected = (inst->module->sql_affected_rows)(handle, inst->config); if (numaffected < 1) { RDEBUG("SQL query affected no rows"); goto finish; } MEM(*out = talloc_asprintf(request, "%d", numaffected)); ret = talloc_array_length(*out) - 1; (inst->module->sql_finish_query)(handle, inst->config); goto finish; } /* else it's a SELECT statement */ rcode = rlm_sql_select_query(inst, request, &handle, fmt); if (rcode != RLM_SQL_OK) goto query_error; rcode = rlm_sql_fetch_row(&row, inst, request, &handle); if (rcode) { (inst->module->sql_finish_select_query)(handle, inst->config); goto query_error; } if (!row) { RDEBUG("SQL query returned no results"); (inst->module->sql_finish_select_query)(handle, inst->config); ret = -1; goto finish; } if (!row[0]){ RDEBUG("NULL value in first column of result"); (inst->module->sql_finish_select_query)(handle, inst->config); ret = -1; goto finish; } *out = talloc_bstrndup(request, row[0], strlen(row[0])); ret = talloc_array_length(*out) - 1; (inst->module->sql_finish_select_query)(handle, inst->config); finish: fr_connection_release(inst->pool, handle); return ret; }
/** Executes a SELECT query and maps the result to server attributes * * @param mod_inst #rlm_sql_t instance. * @param proc_inst Instance data for this specific mod_proc call (unused). * @param request The current request. * @param query string to execute. * @param maps Head of the map list. * @return * - #RLM_MODULE_NOOP no rows were returned or columns matched. * - #RLM_MODULE_UPDATED if one or more #VALUE_PAIR were added to the #REQUEST. * - #RLM_MODULE_FAIL if a fault occurred. */ static rlm_rcode_t mod_map_proc(void *mod_inst, UNUSED void *proc_inst, REQUEST *request, char const *query, vp_map_t const *maps) { rlm_sql_t *inst = talloc_get_type_abort(mod_inst, rlm_sql_t); rlm_sql_handle_t *handle = NULL; int i, j; rlm_rcode_t rcode = RLM_MODULE_UPDATED; sql_rcode_t ret; vp_map_t const *map; rlm_sql_row_t row; int rows; int field_cnt; char const **fields = NULL, *map_rhs; char map_rhs_buff[128]; #define MAX_SQL_FIELD_INDEX (64) int field_index[MAX_SQL_FIELD_INDEX]; bool found_field = false; /* Did we find any matching fields in the result set ? */ rad_assert(inst->module->sql_fields); /* Should have been caught during validation... */ for (i = 0; i < MAX_SQL_FIELD_INDEX; i++) field_index[i] = -1; /* * Add SQL-User-Name attribute just in case it is needed * We could search the string fmt for SQL-User-Name to see if this is * needed or not */ sql_set_user(inst, request, NULL); handle = fr_connection_get(inst->pool); /* connection pool should produce error */ if (!handle) return 0; rlm_sql_query_log(inst, request, NULL, query); ret = rlm_sql_select_query(inst, request, &handle, query); if (ret != RLM_SQL_OK) { RERROR("SQL query failed: %s", fr_int2str(sql_rcode_table, ret, "<INVALID>")); rcode = RLM_MODULE_FAIL; goto finish; } ret = (inst->module->sql_fields)(&fields, handle, inst->config); if (ret != RLM_SQL_OK) { RERROR("Failed retrieving field names: %s", fr_int2str(sql_rcode_table, ret, "<INVALID>")); error: rcode = RLM_MODULE_FAIL; (inst->module->sql_finish_select_query)(handle, inst->config); goto finish; } rad_assert(fields); field_cnt = talloc_array_length(fields); if (RDEBUG_ENABLED3) for (j = 0; j < field_cnt; j++) RDEBUG3("Got field: %s", fields[j]); /* * Iterate over the maps, it's O(N2)ish but probably * faster than building a radix tree each time the * map set is evaluated (map->rhs can be dynamic). */ for (map = maps, i = 0; map && (i < MAX_SQL_FIELD_INDEX); map = map->next, i++) { /* * Expand the RHS to get the name of the SQL field */ if (tmpl_expand(&map_rhs, map_rhs_buff, sizeof(map_rhs_buff), request, map->rhs, NULL, NULL) < 0) { RERROR("Failed getting field name: %s", fr_strerror()); goto error; } for (j = 0; j < field_cnt; j++) { if (strcmp(fields[j], map_rhs) != 0) continue; field_index[i] = j; found_field = true; } } /* * Couldn't resolve any map RHS values to fields * in the result set. */ if (!found_field) { RDEBUG("No fields matching map found in query result"); rcode = RLM_MODULE_NOOP; (inst->module->sql_finish_select_query)(handle, inst->config); goto finish; } /* * We've resolved all the maps to result indexes, now convert * the values at those indexes into VALUE_PAIRs. * * Note: Not all SQL client libraries provide a row count, * so we have to do the count here. */ for (ret = rlm_sql_fetch_row(&row, inst, request, &handle), rows = 0; (ret == RLM_SQL_OK) && row; ret = rlm_sql_fetch_row(&row, inst, request, &handle), rows++) { for (map = maps, j = 0; map && (j < MAX_SQL_FIELD_INDEX); map = map->next, j++) { if (field_index[j] < 0) continue; /* We didn't find the map RHS in the field set */ if (map_to_request(request, map, _sql_map_proc_get_value, row[field_index[j]]) < 0) goto error; } } if (ret == RLM_SQL_ERROR) goto error; if (!rows) { RDEBUG("SQL query returned no results"); rcode = RLM_MODULE_NOOP; } (inst->module->sql_finish_select_query)(handle, inst->config); finish: talloc_free(fields); fr_connection_release(inst->pool, handle); return rcode; }