/* * Add hints to the info sent by the terminal server * based on the pattern of the username, and other attributes. */ static int hints_setup(PAIR_LIST *hints, REQUEST *request) { char const *name; VALUE_PAIR *add; VALUE_PAIR *tmp; PAIR_LIST *i; VALUE_PAIR *request_pairs; int updated = 0, ft; request_pairs = request->packet->vps; if (!hints || !request_pairs) return RLM_MODULE_NOOP; /* * Check for valid input, zero length names not permitted */ name = (tmp = pairfind(request_pairs, PW_USER_NAME, 0, TAG_ANY)) ? tmp->vp_strvalue : NULL; if (!name || name[0] == 0) { /* * No name, nothing to do. */ return RLM_MODULE_NOOP; } for (i = hints; i; i = i->next) { /* * Use "paircompare", which is a little more general... */ if (((strcmp(i->name, "DEFAULT") == 0) || (strcmp(i->name, name) == 0)) && (paircompare(request, request_pairs, i->check, NULL) == 0)) { RDEBUG2(" hints: Matched %s at %d", i->name, i->lineno); /* * Now add all attributes to the request list, * except PW_STRIP_USER_NAME and PW_FALL_THROUGH * and xlat them. */ add = paircopy(request->packet, i->reply); ft = fallthrough(add); pairdelete(&add, PW_STRIP_USER_NAME, 0, TAG_ANY); pairdelete(&add, PW_FALL_THROUGH, 0, TAG_ANY); radius_xlat_move(request, &request->packet->vps, &add); pairfree(&add); updated = 1; if (!ft) { break; } } } if (updated == 0) { return RLM_MODULE_NOOP; } return RLM_MODULE_UPDATED; }
/* * Common code called by everything below. */ static rlm_rcode_t file_common(rlm_files_t *inst, REQUEST *request, char const *filename, fr_hash_table_t *ht, VALUE_PAIR *request_pairs, VALUE_PAIR **reply_pairs) { char const *name, *match; 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 ? namepair->vp_strvalue : "NONE"; } else { int len; len = radius_xlat(buffer, sizeof(buffer), request, inst->key, NULL, NULL); if (len < 0) { return RLM_MODULE_FAIL; } name = len ? buffer : "NONE"; } 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(request, pl->check); /* ctx may be reply or proxy */ reply_tmp = paircopy(request, pl->reply); radius_xlat_move(request, reply_pairs, &reply_tmp); pairmove(request, &request->config_items, &check_tmp); pairfree(&reply_tmp); pairfree(&check_tmp); /* * Fallthrough? */ if (!fallthrough(pl->reply)) break; } } /* * Remove server internal parameters. */ pairdelete(reply_pairs, PW_FALL_THROUGH, 0, TAG_ANY); /* * See if we succeeded. */ if (!found) return RLM_MODULE_NOOP; /* on to the next module */ return RLM_MODULE_OK; }
static rlm_rcode_t mod_authorize(void *instance, REQUEST * request) { rlm_rcode_t rcode = RLM_MODULE_NOOP; rlm_sql_t *inst = instance; rlm_sql_handle_t *handle; VALUE_PAIR *check_tmp = NULL; VALUE_PAIR *reply_tmp = NULL; VALUE_PAIR *user_profile = NULL; bool user_found = false; bool dofallthrough = true; int rows; char *expanded = NULL; rad_assert(request != NULL); rad_assert(request->packet != NULL); rad_assert(request->reply != NULL); /* * Set, escape, and check the user attr here */ if (sql_set_user(inst, request, NULL) < 0) { return RLM_MODULE_FAIL; } /* * Reserve a socket * * After this point use goto error or goto release to cleanup socket temporary pairlists and * temporary attributes. */ handle = sql_get_socket(inst); if (!handle) { rcode = RLM_MODULE_FAIL; 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[0] != '\0')) { if (radius_axlat(&expanded, request, inst->config->authorize_check_query, sql_escape_func, inst) < 0) { REDEBUG("Error generating query"); rcode = RLM_MODULE_FAIL; goto error; } rows = sql_getvpdata(inst, &handle, request, &check_tmp, expanded); TALLOC_FREE(expanded); if (rows < 0) { REDEBUG("SQL query error"); rcode = RLM_MODULE_FAIL; goto error; } if (rows == 0) { goto skipreply; } /* * Only do this if *some* check pairs were returned */ RDEBUG2("User found in radcheck table"); user_found = true; if (paircompare(request, request->packet->vps, check_tmp, &request->reply->vps) != 0) { goto skipreply; } RDEBUG2("Check items matched"); radius_pairmove(request, &request->config_items, check_tmp, true); rcode = RLM_MODULE_OK; } if (inst->config->authorize_reply_query && (inst->config->authorize_reply_query[0] != '\0')) { /* * Now get the reply pairs since the paircompare matched */ if (radius_axlat(&expanded, request, inst->config->authorize_reply_query, sql_escape_func, inst) < 0) { REDEBUG("Error generating query"); rcode = RLM_MODULE_FAIL; goto error; } rows = sql_getvpdata(inst, &handle, request->reply, &reply_tmp, expanded); TALLOC_FREE(expanded); if (rows < 0) { REDEBUG("SQL query error"); rcode = RLM_MODULE_FAIL; goto error; } if (rows == 0) { goto skipreply; } if (!inst->config->read_groups) { dofallthrough = fallthrough(reply_tmp); } RDEBUG2("User found in radreply table"); user_found = true; radius_pairmove(request, &request->reply->vps, reply_tmp, true); rcode = 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) { rlm_rcode_t ret; RDEBUG3("... falling-through to group processing"); ret = rlm_sql_process_groups(inst, request, handle, &dofallthrough); switch (ret) { /* * Nothing bad happened, continue... */ case RLM_MODULE_UPDATED: rcode = RLM_MODULE_UPDATED; /* FALL-THROUGH */ case RLM_MODULE_OK: if (rcode != RLM_MODULE_UPDATED) { rcode = RLM_MODULE_OK; } /* FALL-THROUGH */ case RLM_MODULE_NOOP: user_found = true; break; case RLM_MODULE_NOTFOUND: break; default: rcode = ret; goto release; } } /* * Repeat the above process with the default profile or User-Profile */ if (dofallthrough) { rlm_rcode_t ret; /* * Check for a default_profile or for a User-Profile. */ RDEBUG3("... falling-through to profile processing"); user_profile = pairfind(request->config_items, PW_USER_PROFILE, 0, TAG_ANY); char const *profile = user_profile ? user_profile->vp_strvalue : inst->config->default_profile; if (!profile || !*profile) { goto release; } RDEBUG2("Checking profile %s", profile); if (sql_set_user(inst, request, profile) < 0) { REDEBUG("Error setting profile"); rcode = RLM_MODULE_FAIL; goto error; } ret = rlm_sql_process_groups(inst, request, handle, &dofallthrough); switch (ret) { /* * Nothing bad happened, continue... */ case RLM_MODULE_UPDATED: rcode = RLM_MODULE_UPDATED; /* FALL-THROUGH */ case RLM_MODULE_OK: if (rcode != RLM_MODULE_UPDATED) { rcode = RLM_MODULE_OK; } /* FALL-THROUGH */ case RLM_MODULE_NOOP: user_found = true; break; case RLM_MODULE_NOTFOUND: break; default: rcode = ret; goto release; } } /* * At this point the key (user) hasn't be found in the check table, the reply table * or the group mapping table, and there was no matching profile. */ release: if (!user_found) { rcode = RLM_MODULE_NOTFOUND; } error: sql_release_socket(inst, handle); pairfree(&check_tmp); pairfree(&reply_tmp); return rcode; }
static rlm_rcode_t rlm_sql_process_groups(rlm_sql_t *inst, REQUEST *request, rlm_sql_handle_t *handle, bool *dofallthrough) { rlm_rcode_t rcode = RLM_MODULE_NOOP; VALUE_PAIR *check_tmp = NULL, *reply_tmp = NULL, *sql_group = NULL; rlm_sql_grouplist_t *head = NULL, *entry = NULL; char *expanded = NULL; int rows; rad_assert(request != NULL); rad_assert(request->packet != NULL); /* * Get the list of groups this user is a member of */ rows = sql_get_grouplist(inst, handle, request, &head); if (rows < 0) { REDEBUG("Error retrieving group list"); return RLM_MODULE_FAIL; } if (rows == 0) { RDEBUG2("User not found in any groups"); rcode = RLM_MODULE_NOTFOUND; goto finish; } RDEBUG2("User found in the group table"); for (entry = head; entry != NULL && (*dofallthrough != 0); entry = entry->next) { /* * Add the Sql-Group attribute to the request list so we know * which group we're retrieving attributes for */ sql_group = pairmake_packet("Sql-Group", entry->name, T_OP_EQ); if (!sql_group) { REDEBUG("Error creating Sql-Group attribute"); rcode = RLM_MODULE_FAIL; goto finish; } if (inst->config->authorize_group_check_query && (inst->config->authorize_group_check_query != '\0')) { /* * Expand the group query */ if (radius_axlat(&expanded, request, inst->config->authorize_group_check_query, sql_escape_func, inst) < 0) { REDEBUG("Error generating query"); rcode = RLM_MODULE_FAIL; goto finish; } rows = sql_getvpdata(inst, &handle, request, &check_tmp, expanded); TALLOC_FREE(expanded); if (rows < 0) { REDEBUG("Error retrieving check pairs for group %s", entry->name); rcode = RLM_MODULE_FAIL; goto finish; } /* * If we got check rows we need to process them before we decide to process the reply rows */ if ((rows > 0) && (paircompare(request, request->packet->vps, check_tmp, &request->reply->vps) != 0)) { pairfree(&check_tmp); pairdelete(&request->packet->vps, PW_SQL_GROUP, 0, TAG_ANY); continue; } RDEBUG2("Group \"%s\" check items matched", entry->name); rcode = RLM_MODULE_OK; radius_pairmove(request, &request->config_items, check_tmp, true); check_tmp = NULL; } if (inst->config->authorize_group_reply_query && (inst->config->authorize_group_reply_query != '\0')) { /* * Now get the reply pairs since the paircompare matched */ if (radius_axlat(&expanded, request, inst->config->authorize_group_reply_query, sql_escape_func, inst) < 0) { REDEBUG("Error generating query"); rcode = RLM_MODULE_FAIL; goto finish; } rows = sql_getvpdata(inst, &handle, request->reply, &reply_tmp, expanded); TALLOC_FREE(expanded); if (rows < 0) { REDEBUG("Error retrieving reply pairs for group %s", entry->name); rcode = RLM_MODULE_FAIL; goto finish; } *dofallthrough = fallthrough(reply_tmp); RDEBUG2("Group \"%s\" reply items processed", entry->name); rcode = RLM_MODULE_OK; radius_pairmove(request, &request->reply->vps, reply_tmp, true); reply_tmp = NULL; } pairdelete(&request->packet->vps, PW_SQL_GROUP, 0, TAG_ANY); } finish: talloc_free(head); pairdelete(&request->packet->vps, PW_SQL_GROUP, 0, TAG_ANY); return rcode; }
static rlm_rcode_t rlm_sql_authorize(void *instance, REQUEST * request) { int ret = RLM_MODULE_NOTFOUND; rlm_sql_t *inst = instance; rlm_sql_handle_t *handle; 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]; /* * Set, escape, and check the user attr here */ if (sql_set_user(inst, request, 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. */ handle = sql_get_socket(inst); if (handle == 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, &handle, &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"); radius_xlat_move(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, &handle, &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); } RDEBUG2("User found in radreply table"); radius_xlat_move(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, handle, &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, TAG_ANY); const 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, profile) < 0) { radlog_request(L_ERR, 0, request, "Error setting profile; rejecting user"); goto error; } rows = rlm_sql_process_groups(inst, request, handle, &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, handle); pairfree(&check_tmp); pairfree(&reply_tmp); return ret; }
static int rlm_sql_process_groups(rlm_sql_t *inst, REQUEST *request, rlm_sql_handle_t *handle, int *dofallthrough) { VALUE_PAIR *check_tmp = NULL; VALUE_PAIR *reply_tmp = NULL; rlm_sql_grouplist_t *group_list, *group_list_tmp; VALUE_PAIR *sql_group = NULL; char querystr[MAX_QUERY_LEN]; int found = 0; int rows; /* * Get the list of groups this user is a member of */ if (sql_get_grouplist(inst, handle, 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 Sql-Group attribute to the request list so we know * which group we're retrieving attributes for */ sql_group = pairmake("Sql-Group", group_list_tmp->groupname, T_OP_EQ); if (!sql_group) { radlog_request(L_ERR, 0, request, "Error creating Sql-Group attribute"); sql_grouplist_free(&group_list); return -1; } pairadd(&request->packet->vps, sql_group); if (!radius_xlat(querystr, sizeof(querystr), inst->config->authorize_group_check_query, request, sql_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_SQL_GROUP, 0, TAG_ANY); sql_grouplist_free(&group_list); return -1; } rows = sql_getvpdata(inst, &handle, &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_SQL_GROUP, 0, TAG_ANY); pairfree(&check_tmp); sql_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->config->authorize_group_reply_query, request, sql_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_SQL_GROUP, 0, TAG_ANY); pairfree(&check_tmp); sql_grouplist_free(&group_list); return -1; } if (sql_getvpdata(inst, &handle, &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_SQL_GROUP, 0, TAG_ANY); pairfree(&check_tmp); pairfree(&reply_tmp); sql_grouplist_free(&group_list); return -1; } *dofallthrough = fallthrough(reply_tmp); radius_xlat_move(request, &request->reply->vps, &reply_tmp); radius_xlat_move(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->config->authorize_group_reply_query, request, sql_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_SQL_GROUP, 0, TAG_ANY); pairfree(&check_tmp); sql_grouplist_free(&group_list); return -1; } if (sql_getvpdata(inst, &handle, &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_SQL_GROUP, 0, TAG_ANY); pairfree(&check_tmp); pairfree(&reply_tmp); sql_grouplist_free(&group_list); return -1; } *dofallthrough = fallthrough(reply_tmp); radius_xlat_move(request, &request->reply->vps, &reply_tmp); radius_xlat_move(request, &request->config_items, &check_tmp); } /* * Delete the Sql-Group we added above * And clear out the pairlists */ pairdelete(&request->packet->vps, PW_SQL_GROUP, 0, TAG_ANY); pairfree(&check_tmp); pairfree(&reply_tmp); } sql_grouplist_free(&group_list); return found; }
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; } }
/* * Find the named realm in the database. Create the * set of attribute-value pairs to check and reply with * for this realm from the database. */ static int attr_filter_postproxy(void *instance, REQUEST *request) { struct attr_filter_instance *inst = instance; VALUE_PAIR *request_pairs; VALUE_PAIR **reply_items; VALUE_PAIR *reply_item; VALUE_PAIR *reply_tmp = NULL; VALUE_PAIR *check_item; PAIR_LIST *pl; int found = 0; int compare; int pass, fail; #ifdef HAVE_REGEX_H regex_t reg; #endif VALUE_PAIR *realmpair; REALM *realm; char *realmname; /* * It's not a proxy reply, so return NOOP */ if( request->proxy == NULL ) { return( RLM_MODULE_NOOP ); } request_pairs = request->packet->vps; reply_items = &request->proxy_reply->vps; /* * Get the realm. Can't use request->config_items as * that gets freed by rad_authenticate.... use the one * set in the original request vps */ realmpair = pairfind(request_pairs, PW_REALM); if(!realmpair) { /* Can't find a realm, so no filtering of attributes * or should we use a DEFAULT entry? * For now, just return NOTFOUND. (maybe NOOP?) */ return RLM_MODULE_NOTFOUND; } realmname = (char *) realmpair->strvalue; realm = realm_find(realmname, FALSE); /* * Find the attr_filter profile entry for the realm. */ for(pl = inst->attrs; pl; pl = pl->next) { /* * If the current entry is NOT a default, * AND the realm does NOT match the current entry, * then skip to the next entry. */ if ( (strcmp(pl->name, "DEFAULT") != 0) && (strcmp(realmname, pl->name) != 0) ) { continue; } DEBUG2(" attr_filter: Matched entry %s at line %d", pl->name, pl->lineno); found = 1; check_item = pl->check; while( check_item != NULL ) { /* * If it is a SET operator, add the attribute to * the reply list without checking reply_items. */ if( check_item->operator == T_OP_SET ) { mypairappend(check_item, &reply_tmp); } check_item = check_item->next; } /* while( check_item != NULL ) */ /* * Iterate through the reply items, * comparing each reply item to every rule, * then moving it to the reply_tmp list only if it matches all * rules for that attribute. * IE, Idle-Timeout is moved only if it matches * all rules that describe an Idle-Timeout. */ for( reply_item = *reply_items; reply_item != NULL; reply_item = reply_item->next ) { /* reset the pass,fail vars for each reply item */ pass = fail = 0; /* reset the check_item pointer to the beginning of the list */ check_item = pl->check; while( check_item != NULL ) { if(reply_item->attribute == check_item->attribute) { compare = simplepaircmp(request, reply_item, check_item); switch(check_item->operator) { case T_OP_SET: /* nothing to do for set */ break; case T_OP_EQ: default: radlog(L_ERR, "Invalid operator for item %s: " "reverting to '=='", check_item->name); case T_OP_CMP_TRUE: /* compare always == 0 */ case T_OP_CMP_FALSE: /* compare always == 1 */ case T_OP_CMP_EQ: if (compare == 0) { pass++; } else { fail++; } break; case T_OP_NE: if (compare != 0) { pass++; } else { fail++; } break; case T_OP_LT: if (compare < 0) { pass++; } else { fail++; } break; case T_OP_GT: if (compare > 0) { pass++; } else { fail++; } break; case T_OP_LE: if (compare <= 0) { pass++; } else { fail++; } break; case T_OP_GE: if (compare >= 0) { pass++; } else { fail++; } break; #ifdef HAVE_REGEX_H case T_OP_REG_EQ: regcomp(®, (char *)check_item->strvalue, 0); compare = regexec(®, (char *)reply_item->strvalue, 0, NULL, 0); regfree(®); if (compare == 0) { pass++; } else { fail++; } break; case T_OP_REG_NE: regcomp(®, (char *)check_item->strvalue, 0); compare = regexec(®, (char *)reply_item->strvalue, 0, NULL, 0); regfree(®); if (compare != 0) { pass++; } else { fail++; } break; #endif } /* switch( check_item->operator ) */ } /* if reply == check */ check_item = check_item->next; } /* while( check ) */ /* only move attribute if it passed all rules */ if (fail == 0 && pass > 0) { mypairappend( reply_item, &reply_tmp); } } /* for( reply ) */ /* If we shouldn't fall through, break */ if(!fallthrough(pl->check)) break; } pairfree(&request->proxy_reply->vps); request->proxy_reply->vps = reply_tmp; /* * See if we succeeded. If we didn't find the realm, * then exit from the module. */ if (!found) return RLM_MODULE_OK; /* * Remove server internal parameters. */ pairdelete(reply_items, PW_FALL_THROUGH); return RLM_MODULE_UPDATED; }