static int rlm_sql_authorize(void *instance, REQUEST * request) { VALUE_PAIR *check_tmp = NULL; VALUE_PAIR *reply_tmp = NULL; VALUE_PAIR *user_profile = NULL; int found = 0; SQLSOCK *sqlsocket; SQL_INST *inst = instance; char querystr[MAX_QUERY_LEN]; char sqlusername[MAX_STRING_LEN]; /* * They MUST have a user name to do SQL authorization. */ 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; } /* * Set, escape, and check the user attr here. */ if (sql_set_user(inst, request, sqlusername, NULL) < 0) return RLM_MODULE_FAIL; radius_xlat(querystr, sizeof(querystr), inst->config->authorize_check_query, request, sql_escape_func); sqlsocket = sql_get_socket(inst); if (sqlsocket == NULL) { /* Remove the username we (maybe) added above */ pairdelete(&request->packet->vps, PW_SQL_USER_NAME); return RLM_MODULE_FAIL; } /* * After this point, ALL 'return's MUST release the SQL socket! */ found = sql_getvpdata(inst, sqlsocket, &check_tmp, querystr, PW_VP_USERDATA); /* * Find the entry for the user. */ if (found > 0) { radius_xlat(querystr, sizeof(querystr), inst->config->authorize_group_check_query, request, sql_escape_func); sql_getvpdata(inst, sqlsocket, &check_tmp, querystr, PW_VP_GROUPDATA); radius_xlat(querystr, sizeof(querystr), inst->config->authorize_reply_query, request, sql_escape_func); sql_getvpdata(inst, sqlsocket, &reply_tmp, querystr, PW_VP_USERDATA); radius_xlat(querystr, sizeof(querystr), inst->config->authorize_group_reply_query, request, sql_escape_func); sql_getvpdata(inst, sqlsocket, &reply_tmp, querystr, PW_VP_GROUPDATA); } else if (found < 0) { radlog(L_ERR, "rlm_sql (%s): SQL query error; rejecting user", inst->config->xlat_name); sql_release_socket(inst, sqlsocket); /* Remove the username we (maybe) added above */ pairdelete(&request->packet->vps, PW_SQL_USER_NAME); pairfree(&check_tmp); return RLM_MODULE_FAIL; } else { radlog(L_DBG, "rlm_sql (%s): User %s not found in radcheck", inst->config->xlat_name, sqlusername); /* * We didn't find the user in radcheck, so we try looking * for radgroupcheck entry */ radius_xlat(querystr, sizeof(querystr), inst->config->authorize_group_check_query, request, sql_escape_func); found = sql_getvpdata(inst, sqlsocket, &check_tmp, querystr, PW_VP_GROUPDATA); radius_xlat(querystr, sizeof(querystr), inst->config->authorize_group_reply_query, request, sql_escape_func); sql_getvpdata(inst, sqlsocket, &reply_tmp, querystr, PW_VP_GROUPDATA); } if (!found) radlog(L_DBG, "rlm_sql (%s): User %s not found in radgroupcheck", inst->config->xlat_name, sqlusername); if (found || (!found && inst->config->query_on_not_found)){ int def_found = 0; /* * Check for a default_profile or for a User-Profile. */ user_profile = pairfind(request->config_items, PW_USER_PROFILE); if (inst->config->default_profile[0] != 0 || user_profile != NULL){ char *profile = inst->config->default_profile; if (user_profile != NULL) profile = user_profile->strvalue; if (profile && strlen(profile)){ radlog(L_DBG, "rlm_sql (%s): Checking profile %s", inst->config->xlat_name, profile); if (sql_set_user(inst, request, sqlusername, profile) < 0) { sql_release_socket(inst, sqlsocket); pairfree(&reply_tmp); pairfree(&check_tmp); return RLM_MODULE_FAIL; } radius_xlat(querystr, sizeof(querystr), inst->config->authorize_group_check_query, request, sql_escape_func); def_found = sql_getvpdata(inst, sqlsocket, &check_tmp, querystr, PW_VP_GROUPDATA); if (def_found) found = 1; radius_xlat(querystr, sizeof(querystr), inst->config->authorize_group_reply_query, request, sql_escape_func); sql_getvpdata(inst, sqlsocket, &reply_tmp, querystr, PW_VP_GROUPDATA); } } } /* * We don't need the SQL socket anymore. */ sql_release_socket(inst, sqlsocket); if (!found) { radlog(L_DBG, "rlm_sql (%s): User not found", inst->config->xlat_name); /* Remove the username we (maybe) added above */ pairdelete(&request->packet->vps, PW_SQL_USER_NAME); pairfree(&reply_tmp); pairfree(&check_tmp); return RLM_MODULE_NOTFOUND; } /* * Uncomment these lines for debugging * Recompile, and run 'radiusd -X' */ /* DEBUG2("rlm_sql: check items"); vp_listdebug(check_tmp); DEBUG2("rlm_sql: reply items"); vp_listdebug(reply_tmp); */ if (paircmp(request, request->packet->vps, check_tmp, &reply_tmp) != 0) { radlog(L_INFO, "rlm_sql (%s): No matching entry in the database for request from user [%s]", inst->config->xlat_name, sqlusername); /* Remove the username we (maybe) added above */ pairdelete(&request->packet->vps, PW_SQL_USER_NAME); pairfree(&reply_tmp); pairfree(&check_tmp); return RLM_MODULE_NOTFOUND; } pairxlatmove(request, &request->reply->vps, &reply_tmp); pairxlatmove(request, &request->config_items, &check_tmp); pairfree(&reply_tmp); pairfree(&check_tmp); /* Remove the username we (maybe) added above */ pairdelete(&request->packet->vps, PW_SQL_USER_NAME); return RLM_MODULE_OK; }
static int rlm_redisn_process_groups(REDIS_INST *inst, REQUEST *request, REDISSOCK *redis_socket, int *dofallthrough) { VALUE_PAIR *check_tmp = NULL; VALUE_PAIR *reply_tmp = NULL; REDISN_GROUPLIST *group_list, *group_list_tmp; VALUE_PAIR *redisn_group = NULL; char querystr[MAX_QUERY_LEN]; int found = 0; int rows; /* * Get the list of groups this user is a member of */ if (redisn_get_grouplist(inst, redis_socket, request, &group_list) < 0) { radlog_request(L_ERR, 0, request, "Error retrieving group list"); return -1; } for (group_list_tmp = group_list; group_list_tmp != NULL && *dofallthrough != 0; group_list_tmp = group_list_tmp->next) { /* * Add the Redis-Group attribute to the request list so we know * which group we're retrieving attributes for */ DEBUG("rlm_redisn_process_groups: group_list_tmp->groupname: %s\n", group_list_tmp->groupname); redisn_group = pairmake("Redis-Group", group_list_tmp->groupname, T_OP_EQ); if (!redisn_group) { radlog_request(L_ERR, 0, request, "Error creating Redis-Group attribute"); redisn_grouplist_free(&group_list); return -1; } pairadd(&request->packet->vps, redisn_group); if (!radius_xlat(querystr, sizeof(querystr), inst->authorize_group_check_query, request, redisn_escape_func, inst)) { radlog_request(L_ERR, 0, request, "Error generating query; rejecting user"); /* Remove the grouup we added above */ pairdelete(&request->packet->vps, PW_REDIS_GROUP, 0, TAG_ANY); redisn_grouplist_free(&group_list); return -1; } rows = redisn_getvpdata(inst, redis_socket, &check_tmp, querystr); if (rows < 0) { radlog_request(L_ERR, 0, request, "Error retrieving check pairs for group %s", group_list_tmp->groupname); /* Remove the grouup we added above */ pairdelete(&request->packet->vps, PW_REDIS_GROUP, 0, TAG_ANY); pairfree(&check_tmp); redisn_grouplist_free(&group_list); return -1; } else if (rows > 0) { /* * Only do this if *some* check pairs were returned */ if (paircompare(request, request->packet->vps, check_tmp, &request->reply->vps) == 0) { found = 1; RDEBUG2("User found in group %s", group_list_tmp->groupname); /* * Now get the reply pairs since the paircompare matched */ if (!radius_xlat(querystr, sizeof(querystr), inst->authorize_group_reply_query, request, redisn_escape_func, inst)) { radlog_request(L_ERR, 0, request, "Error generating query; rejecting user"); /* Remove the grouup we added above */ pairdelete(&request->packet->vps, PW_REDIS_GROUP, 0, TAG_ANY); pairfree(&check_tmp); redisn_grouplist_free(&group_list); return -1; } if (redisn_getvpdata(inst, redis_socket, &reply_tmp, querystr) < 0) { radlog_request(L_ERR, 0, request, "Error retrieving reply pairs for group %s", group_list_tmp->groupname); /* Remove the grouup we added above */ pairdelete(&request->packet->vps, PW_REDIS_GROUP, 0, TAG_ANY); pairfree(&check_tmp); pairfree(&reply_tmp); redisn_grouplist_free(&group_list); return -1; } *dofallthrough = fallthrough(reply_tmp); DEBUG("rlm_redisn (%s) %d: *dofallthrough: %d", inst->xlat_name, __LINE__,*dofallthrough); pairxlatmove(request, &request->reply->vps, &reply_tmp); pairxlatmove(request, &request->config_items, &check_tmp); } } else { /* * rows == 0. This is like having the username on a line * in the user's file with no check vp's. As such, we treat * it as found and add the reply attributes, so that we * match expected behavior */ found = 1; RDEBUG2("User found in group %s", group_list_tmp->groupname); /* * Now get the reply pairs since the paircompare matched */ if (!radius_xlat(querystr, sizeof(querystr), inst->authorize_group_reply_query, request, redisn_escape_func, inst)) { radlog_request(L_ERR, 0, request, "Error generating query; rejecting user"); /* Remove the grouup we added above */ pairdelete(&request->packet->vps, PW_REDIS_GROUP, 0, TAG_ANY); pairfree(&check_tmp); redisn_grouplist_free(&group_list); return -1; } DEBUG("rlm_redisn %d: PROCESSSGROUP",__LINE__); if (redisn_getvpdata(inst, redis_socket, &reply_tmp, querystr) < 0) { radlog_request(L_ERR, 0, request, "Error retrieving reply pairs for group %s", group_list_tmp->groupname); /* Remove the grouup we added above */ pairdelete(&request->packet->vps, PW_REDIS_GROUP, 0, TAG_ANY); pairfree(&check_tmp); pairfree(&reply_tmp); redisn_grouplist_free(&group_list); return -1; } *dofallthrough = fallthrough(reply_tmp); DEBUG("rlm_redisn (%s) %d: *dofallthrough: %d", inst->xlat_name, __LINE__,*dofallthrough); pairxlatmove(request, &request->reply->vps, &reply_tmp); pairxlatmove(request, &request->config_items, &check_tmp); } /* * Delete the Redis-Group we added above * And clear out the pairlists */ pairdelete(&request->packet->vps, PW_REDIS_GROUP, 0, TAG_ANY); pairfree(&check_tmp); pairfree(&reply_tmp); } redisn_grouplist_free(&group_list); return found; }
/* * Common code called by everything below. */ static int file_common(struct file_instance *inst, REQUEST *request, const char *filename, fr_hash_table_t *ht, VALUE_PAIR *request_pairs, VALUE_PAIR **reply_pairs) { const char *name, *match; VALUE_PAIR **config_pairs; VALUE_PAIR *check_tmp; VALUE_PAIR *reply_tmp; const PAIR_LIST *user_pl, *default_pl; int found = 0; PAIR_LIST my_pl; char buffer[256]; if (!inst->key) { VALUE_PAIR *namepair; namepair = request->username; name = namepair ? (char *) namepair->vp_strvalue : "NONE"; } else { int len; len = radius_xlat(buffer, sizeof(buffer), inst->key, request, NULL); if (len) name = buffer; else name = "NONE"; } config_pairs = &request->config_items; if (!ht) return RLM_MODULE_NOOP; my_pl.name = name; user_pl = fr_hash_table_finddata(ht, &my_pl); my_pl.name = "DEFAULT"; default_pl = fr_hash_table_finddata(ht, &my_pl); /* * Find the entry for the user. */ while (user_pl || default_pl) { const PAIR_LIST *pl; if (!default_pl && user_pl) { pl = user_pl; match = name; user_pl = user_pl->next; } else if (!user_pl && default_pl) { pl = default_pl; match = "DEFAULT"; default_pl = default_pl->next; } else if (user_pl->order < default_pl->order) { pl = user_pl; match = name; user_pl = user_pl->next; } else { pl = default_pl; match = "DEFAULT"; default_pl = default_pl->next; } if (paircompare(request, request_pairs, pl->check, reply_pairs) == 0) { RDEBUG2("%s: Matched entry %s at line %d", filename, match, pl->lineno); found = 1; check_tmp = paircopy(pl->check); reply_tmp = paircopy(pl->reply); pairxlatmove(request, reply_pairs, &reply_tmp); pairmove(config_pairs, &check_tmp); pairfree(&reply_tmp); pairfree(&check_tmp); /* * Fallthrough? */ if (!fallthrough(pl->reply)) break; } } /* * Remove server internal parameters. */ pairdelete(reply_pairs, PW_FALL_THROUGH); /* * See if we succeeded. */ if (!found) return RLM_MODULE_NOOP; /* on to the next module */ return RLM_MODULE_OK; }
static rlm_rcode_t rlm_redisn_authorize(void *instance, REQUEST * request) { VALUE_PAIR *check_tmp = NULL; VALUE_PAIR *reply_tmp = NULL; VALUE_PAIR *user_profile = NULL; int found = 0; int dofallthrough = 1; int rows; REDISSOCK *redis_socket; REDIS_INST *inst = instance; char querystr[MAX_QUERY_LEN]; char redisnusername[MAX_STRING_LEN]; /* * the profile username is used as the redisnusername during * profile checking so that we don't overwrite the orignal * redisnusername string */ char profileusername[MAX_STRING_LEN]; /* * Set, escape, and check the user attr here */ if (redisn_set_user(inst, request, redisnusername, NULL) < 0) return RLM_MODULE_FAIL; /* * reserve a socket */ redis_socket = redisn_get_socket(inst); if (redis_socket == NULL) { /* Remove the username we (maybe) added above */ pairdelete(&request->packet->vps, PW_REDIS_USER_NAME, 0, TAG_ANY); return RLM_MODULE_FAIL; } /* * After this point, ALL 'return's MUST release the REDISN socket! */ /* * Alright, start by getting the specific entry for the user */ if (!radius_xlat(querystr, sizeof(querystr), inst->authorize_check_query, request, redisn_escape_func, inst)) { radlog_request(L_ERR, 0, request, "Error generating query; rejecting user"); redisn_release_socket(inst, redis_socket); /* Remove the username we (maybe) added above */ pairdelete(&request->packet->vps, PW_REDIS_USER_NAME, 0, TAG_ANY); return RLM_MODULE_FAIL; } rows = redisn_getvpdata(inst, redis_socket, &check_tmp, querystr); if (rows < 0) { radlog_request(L_ERR, 0, request, "REDISN query error; rejecting user"); redisn_release_socket(inst, redis_socket); /* Remove the username we (maybe) added above */ pairdelete(&request->packet->vps, PW_REDIS_USER_NAME, 0, TAG_ANY); pairfree(&check_tmp); return RLM_MODULE_FAIL; } else if (rows > 0) { /* * Only do this if *some* check pairs were returned */ if (paircompare(request, request->packet->vps, check_tmp, &request->reply->vps) == 0) { found = 1; RDEBUG2("User found in radcheck table"); if (inst->authorize_reply_query && *inst->authorize_reply_query) { /* * Now get the reply pairs since the paircompare matched */ if (!radius_xlat(querystr, sizeof(querystr), inst->authorize_reply_query, request, redisn_escape_func, inst)) { radlog_request(L_ERR, 0, request, "Error generating query; rejecting user"); redisn_release_socket(inst, redis_socket); /* Remove the username we (maybe) added above */ pairdelete(&request->packet->vps, PW_REDIS_USER_NAME, 0, TAG_ANY); pairfree(&check_tmp); return RLM_MODULE_FAIL; } if (redisn_getvpdata(inst, redis_socket, &reply_tmp, querystr) < 0) { radlog_request(L_ERR, 0, request, "REDISN query error; rejecting user"); redisn_release_socket(inst, redis_socket); /* Remove the username we (maybe) added above */ pairdelete(&request->packet->vps, PW_REDIS_USER_NAME, 0, TAG_ANY); pairfree(&check_tmp); pairfree(&reply_tmp); return RLM_MODULE_FAIL; } if (!inst->read_groups) { dofallthrough = fallthrough(reply_tmp); DEBUG("rlm_redisn (%s) %d: dofallthrough: %d", inst->xlat_name, __LINE__,dofallthrough); } pairxlatmove(request, &request->reply->vps, &reply_tmp); } pairxlatmove(request, &request->config_items, &check_tmp); } } /* * Clear out the pairlists */ pairfree(&check_tmp); pairfree(&reply_tmp); /* * dofallthrough is set to 1 by default so that if the user information * is not found, we will still process groups. If the user information, * however, *is* found, Fall-Through must be set in order to process * the groups as well */ DEBUG("rlm_redisn (%s) %d: dofallthrough: %d", inst->xlat_name, __LINE__,dofallthrough); if (dofallthrough) { rows = rlm_redisn_process_groups(inst, request, redis_socket, &dofallthrough); if (rows < 0) { radlog_request(L_ERR, 0, request, "Error processing groups; rejecting user"); redisn_release_socket(inst, redis_socket); /* Remove the username we (maybe) added above */ pairdelete(&request->packet->vps, PW_REDIS_USER_NAME, 0, TAG_ANY); return RLM_MODULE_FAIL; } else if (rows > 0) { found = 1; } } /* * repeat the above process with the default profile or User-Profile */ DEBUG("rlm_redisn (%s) %d: dofallthrough: %d", inst->xlat_name, __LINE__,dofallthrough); if (dofallthrough) { int profile_found = 0; /* * Check for a default_profile or for a User-Profile. */ user_profile = pairfind(request->config_items, PW_USER_PROFILE, 0, TAG_ANY); if (inst->default_profile[0] != 0 || user_profile != NULL){ char *profile = inst->default_profile; if (user_profile != NULL) profile = user_profile->vp_strvalue; if (profile && strlen(profile)){ RDEBUG("Checking profile %s", profile); if (redisn_set_user(inst, request, profileusername, profile) < 0) { radlog_request(L_ERR, 0, request, "Error setting profile; rejecting user"); redisn_release_socket(inst, redis_socket); /* Remove the username we (maybe) added above */ pairdelete(&request->packet->vps, PW_REDIS_USER_NAME, 0, TAG_ANY); return RLM_MODULE_FAIL; } else { profile_found = 1; } } } if (profile_found) { rows = rlm_redisn_process_groups(inst, request, redis_socket, &dofallthrough); DEBUG("rlm_redisn (%s) %d: dofallthrough: %d", inst->xlat_name, __LINE__,dofallthrough); if (rows < 0) { radlog_request(L_ERR, 0, request, "Error processing profile groups; rejecting user"); redisn_release_socket(inst, redis_socket); /* Remove the username we (maybe) added above */ pairdelete(&request->packet->vps, PW_REDIS_USER_NAME, 0, TAG_ANY); return RLM_MODULE_FAIL; } else if (rows > 0) { found = 1; } } } /* Remove the username we (maybe) added above */ pairdelete(&request->packet->vps, PW_REDIS_USER_NAME, 0, TAG_ANY); redisn_release_socket(inst, redis_socket); if (!found) { RDEBUG("User %s not found", redisnusername); return RLM_MODULE_NOTFOUND; } else { return RLM_MODULE_OK; } }
static int rlm_sql_authorize(void *instance, REQUEST * request) { int ret = RLM_MODULE_NOTFOUND; SQL_INST *inst = instance; SQLSOCK *sqlsocket; VALUE_PAIR *check_tmp = NULL; VALUE_PAIR *reply_tmp = NULL; VALUE_PAIR *user_profile = NULL; int dofallthrough = 1; int rows; char querystr[MAX_QUERY_LEN]; char sqlusername[MAX_STRING_LEN]; /* * the profile username is used as the sqlusername during * profile checking so that we don't overwrite the orignal * sqlusername string */ char profileusername[MAX_STRING_LEN]; /* * Set, escape, and check the user attr here */ if (sql_set_user(inst, request, sqlusername, NULL) < 0) return RLM_MODULE_FAIL; /* * Reserve a socket * * After this point use goto error or goto release to cleanup sockets * temporary pairlists and temporary attributes. */ sqlsocket = sql_get_socket(inst); if (sqlsocket == NULL) goto error; /* * Query the check table to find any conditions associated with * this user/realm/whatever... */ if (inst->config->authorize_check_query && *inst->config->authorize_check_query) { if (!radius_xlat(querystr, sizeof(querystr), inst->config->authorize_check_query, request, sql_escape_func, inst)) { radlog_request(L_ERR, 0, request, "Error generating query; rejecting user"); goto error; } rows = sql_getvpdata(inst, &sqlsocket, &check_tmp, querystr); if (rows < 0) { radlog_request(L_ERR, 0, request, "SQL query error; rejecting user"); goto error; } /* * Only do this if *some* check pairs were returned */ if ((rows > 0) && (paircompare(request, request->packet->vps, check_tmp, &request->reply->vps) == 0)) { RDEBUG2("User found in radcheck table"); pairxlatmove(request, &request->config_items, &check_tmp); ret = RLM_MODULE_OK; } /* * We only process reply table items if check conditions * were verified */ else goto skipreply; } if (inst->config->authorize_reply_query && *inst->config->authorize_reply_query) { /* * Now get the reply pairs since the paircompare matched */ if (!radius_xlat(querystr, sizeof(querystr), inst->config->authorize_reply_query, request, sql_escape_func, inst)) { radlog_request(L_ERR, 0, request, "Error generating query; rejecting user"); goto error; } rows = sql_getvpdata(inst, &sqlsocket, &reply_tmp, querystr); if (rows < 0) { radlog_request(L_ERR, 0, request, "SQL query error; rejecting user"); goto error; } if (rows > 0) { if (!inst->config->read_groups) dofallthrough = fallthrough(reply_tmp); pairxlatmove(request, &request->reply->vps, &reply_tmp); ret = RLM_MODULE_OK; } } skipreply: /* * Clear out the pairlists */ pairfree(&check_tmp); pairfree(&reply_tmp); /* * dofallthrough is set to 1 by default so that if the user information * is not found, we will still process groups. If the user information, * however, *is* found, Fall-Through must be set in order to process * the groups as well. */ if (dofallthrough) { rows = rlm_sql_process_groups(inst, request, sqlsocket, &dofallthrough); if (rows < 0) { radlog_request(L_ERR, 0, request, "Error processing groups; rejecting user"); goto error; } if (rows > 0) ret = RLM_MODULE_OK; } /* * Repeat the above process with the default profile or User-Profile */ if (dofallthrough) { /* * Check for a default_profile or for a User-Profile. */ user_profile = pairfind(request->config_items, PW_USER_PROFILE, 0); char *profile = user_profile ? user_profile->vp_strvalue : inst->config->default_profile; if (!profile || !*profile) goto release; RDEBUG("Checking profile %s", profile); if (sql_set_user(inst, request, profileusername, profile) < 0) { radlog_request(L_ERR, 0, request, "Error setting profile; rejecting user"); goto error; } rows = rlm_sql_process_groups(inst, request, sqlsocket, &dofallthrough); if (rows < 0) { radlog_request(L_ERR, 0, request, "Error processing profile groups; rejecting user"); goto error; } if (rows > 0) ret = RLM_MODULE_OK; } goto release; error: ret = RLM_MODULE_FAIL; release: sql_release_socket(inst, sqlsocket); /* Remove the username we (maybe) added above */ pairdelete(&request->packet->vps, PW_SQL_USER_NAME, 0, -1); pairfree(&check_tmp); pairfree(&reply_tmp); return ret; }