📄 rlm_sql.c
字号:
/* * sql groupcmp function. That way we can do group comparisons (in the users file for example) * with the group memberships reciding in sql * The group membership query should only return one element which is the username. The returned * username will then be checked with the passed check string. */static int sql_groupcmp(void *instance, REQUEST *request, VALUE_PAIR *request_vp, VALUE_PAIR *check, VALUE_PAIR *check_pairs, VALUE_PAIR **reply_pairs){ SQLSOCK *sqlsocket; SQL_INST *inst = instance; char sqlusername[MAX_STRING_LEN]; SQL_GROUPLIST *group_list, *group_list_tmp; check_pairs = check_pairs; reply_pairs = reply_pairs; request_vp = request_vp; RDEBUG("sql_groupcmp"); if (!check || !check->vp_strvalue || !check->length){ RDEBUG("sql_groupcmp: Illegal group name"); return 1; } if (!request){ RDEBUG("sql_groupcmp: NULL request"); return 1; } /* * Set, escape, and check the user attr here */ if (sql_set_user(inst, request, sqlusername, NULL) < 0) return 1; /* * Get a socket for this lookup */ sqlsocket = sql_get_socket(inst); if (sqlsocket == NULL) { /* Remove the username we (maybe) added above */ pairdelete(&request->packet->vps, PW_SQL_USER_NAME); return 1; } /* * Get the list of groups this user is a member of */ if (sql_get_grouplist(inst, sqlsocket, request, &group_list) < 0) { radlog_request(L_ERR, 0, request, "Error getting group membership"); /* Remove the username we (maybe) added above */ pairdelete(&request->packet->vps, PW_SQL_USER_NAME); sql_release_socket(inst, sqlsocket); return 1; } for (group_list_tmp = group_list; group_list_tmp != NULL; group_list_tmp = group_list_tmp->next) { if (strcmp(group_list_tmp->groupname, check->vp_strvalue) == 0){ RDEBUG("sql_groupcmp finished: User is a member of group %s", check->vp_strvalue); /* Free the grouplist */ sql_grouplist_free(&group_list); /* Remove the username we (maybe) added above */ pairdelete(&request->packet->vps, PW_SQL_USER_NAME); sql_release_socket(inst, sqlsocket); return 0; } } /* Free the grouplist */ sql_grouplist_free(&group_list); /* Remove the username we (maybe) added above */ pairdelete(&request->packet->vps, PW_SQL_USER_NAME); sql_release_socket(inst,sqlsocket); RDEBUG("sql_groupcmp finished: User is NOT a member of group %s", check->vp_strvalue); return 1;}static int rlm_sql_process_groups(SQL_INST *inst, REQUEST *request, SQLSOCK *sqlsocket, int *dofallthrough){ VALUE_PAIR *check_tmp = NULL; VALUE_PAIR *reply_tmp = NULL; SQL_GROUPLIST *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, sqlsocket, 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"); return -1; } pairadd(&request->packet->vps, sql_group); if (!radius_xlat(querystr, sizeof(querystr), inst->config->authorize_group_check_query, request, sql_escape_func)) { radlog_request(L_ERR, 0, request, "Error generating query; rejecting user"); /* Remove the grouup we added above */ pairdelete(&request->packet->vps, PW_SQL_GROUP); return -1; } rows = sql_getvpdata(inst, sqlsocket, &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); pairfree(&check_tmp); 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)) { radlog_request(L_ERR, 0, request, "Error generating query; rejecting user"); /* Remove the grouup we added above */ pairdelete(&request->packet->vps, PW_SQL_GROUP); pairfree(&check_tmp); return -1; } if (sql_getvpdata(inst, sqlsocket, &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); pairfree(&check_tmp); pairfree(&reply_tmp); return -1; } *dofallthrough = fallthrough(reply_tmp); 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->config->authorize_group_reply_query, request, sql_escape_func)) { radlog_request(L_ERR, 0, request, "Error generating query; rejecting user"); /* Remove the grouup we added above */ pairdelete(&request->packet->vps, PW_SQL_GROUP); pairfree(&check_tmp); return -1; } if (sql_getvpdata(inst, sqlsocket, &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); pairfree(&check_tmp); pairfree(&reply_tmp); return -1; } *dofallthrough = fallthrough(reply_tmp); pairxlatmove(request, &request->reply->vps, &reply_tmp); pairxlatmove(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); pairfree(&check_tmp); pairfree(&reply_tmp); } sql_grouplist_free(&group_list); return found;}static int rlm_sql_detach(void *instance){ SQL_INST *inst = instance; paircompare_unregister(PW_SQL_GROUP, sql_groupcmp); if (inst->config) { int i; if (inst->sqlpool) { sql_poolfree(inst); } if (inst->config->xlat_name) { xlat_unregister(inst->config->xlat_name,(RAD_XLAT_FUNC)sql_xlat); free(inst->config->xlat_name); } /* * Free up dynamically allocated string pointers. */ for (i = 0; module_config[i].name != NULL; i++) { char **p; if (module_config[i].type != PW_TYPE_STRING_PTR) { continue; } /* * Treat 'config' as an opaque array of bytes, * and take the offset into it. There's a * (char*) pointer at that offset, and we want * to point to it. */ p = (char **) (((char *)inst->config) + module_config[i].offset); if (!*p) { /* nothing allocated */ continue; } free(*p); *p = NULL; } allowed_chars = NULL; free(inst->config); inst->config = NULL; } if (inst->handle) {#if 0 /* * FIXME: Call the modules 'destroy' function? */ lt_dlclose(inst->handle); /* ignore any errors */#endif } free(inst); return 0;}static int rlm_sql_instantiate(CONF_SECTION * conf, void **instance){ SQL_INST *inst; const char *xlat_name; inst = rad_malloc(sizeof(SQL_INST)); memset(inst, 0, sizeof(SQL_INST)); inst->config = rad_malloc(sizeof(SQL_CONFIG)); memset(inst->config, 0, sizeof(SQL_CONFIG)); /* * Export these methods, too. This avoids RTDL_GLOBAL. */ inst->sql_set_user = sql_set_user; inst->sql_get_socket = sql_get_socket; inst->sql_release_socket = sql_release_socket; inst->sql_escape_func = sql_escape_func; /* * If the configuration parameters can't be parsed, then * fail. */ if (cf_section_parse(conf, inst->config, module_config) < 0) { rlm_sql_detach(inst); return -1; } xlat_name = cf_section_name2(conf); if (xlat_name == NULL) xlat_name = cf_section_name1(conf); if (xlat_name){ inst->config->xlat_name = strdup(xlat_name); xlat_register(xlat_name, (RAD_XLAT_FUNC)sql_xlat, inst); } if (inst->config->num_sql_socks > MAX_SQL_SOCKS) { radlog(L_ERR, "rlm_sql (%s): sql_instantiate: number of sqlsockets cannot exceed MAX_SQL_SOCKS, %d", inst->config->xlat_name, MAX_SQL_SOCKS); rlm_sql_detach(inst); return -1; } /* * Sanity check for crazy people. */ if (strncmp(inst->config->sql_driver, "rlm_sql_", 8) != 0) { radlog(L_ERR, "\"%s\" is NOT an SQL driver!", inst->config->sql_driver); rlm_sql_detach(inst); return -1; } inst->handle = lt_dlopenext(inst->config->sql_driver); if (inst->handle == NULL) { radlog(L_ERR, "Could not link driver %s: %s", inst->config->sql_driver, lt_dlerror()); radlog(L_ERR, "Make sure it (and all its dependent libraries!) are in the search path of your system's ld."); rlm_sql_detach(inst); return -1; } inst->module = (rlm_sql_module_t *) lt_dlsym(inst->handle, inst->config->sql_driver); if (!inst->module) { radlog(L_ERR, "Could not link symbol %s: %s", inst->config->sql_driver, lt_dlerror()); rlm_sql_detach(inst); return -1; } radlog(L_INFO, "rlm_sql (%s): Driver %s (module %s) loaded and linked", inst->config->xlat_name, inst->config->sql_driver, inst->module->name); radlog(L_INFO, "rlm_sql (%s): Attempting to connect to %s@%s:%s/%s", inst->config->xlat_name, inst->config->sql_login, inst->config->sql_server, inst->config->sql_port, inst->config->sql_db); if (sql_init_socketpool(inst) < 0) { rlm_sql_detach(inst); return -1; } paircompare_register(PW_SQL_GROUP, PW_USER_NAME, sql_groupcmp, inst); if (inst->config->do_clients){ if (generate_sql_clients(inst) == -1){ radlog(L_ERR, "Failed to load clients from SQL."); rlm_sql_detach(inst); return -1; } } allowed_chars = inst->config->allowed_chars; *instance = inst; return RLM_MODULE_OK;}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; int dofallthrough = 1; int rows; SQLSOCK *sqlsocket; SQL_INST *inst = instance; 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 */ 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! */ /* * Alright, start by getting the specific entry for the user */ if (!radius_xlat(querystr, sizeof(querystr), inst->config->authorize_check_query, request, sql_escape_func)) { radlog_request(L_ERR, 0, request, "Error generating query; rejecting user"); sql_release_socket(inst, sqlsocket); /* Remove the username we (maybe) added above */ pairdelete(&request->packet->vps, PW_SQL_USER_NAME); return RLM_MODULE_FAIL; } rows = sql_getvpdata(inst, sqlsocket, &check_tmp, querystr); if (rows < 0) { radlog_request(L_ERR, 0, request, "SQL query error; rejecting user"); 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 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->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)) { radlog_request(L_ERR, 0, request, "Error generating query; rejecting user"); 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; } if (sql_getvpdata(inst, sqlsocket, &reply_tmp, querystr) < 0) { radlog_request(L_ERR, 0, request, "SQL query error; rejecting user"); sql_release_socket(inst, sqlsocket); /* Remove the username we (maybe) added above */ pairdelete(&request->packet->vps, PW_SQL_USER_NAME); pairfree(&check_tmp); pairfree(&reply_tmp); return RLM_MODULE_FAIL; } if (!inst->config->read_groups) dofallthrough = fallthrough(reply_tmp); 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 */ 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"); sql_release_socket(inst, sqlsocket); /* Remove the username we (maybe) added above */ pairdelete(&request->packet->vps, PW_SQL_USER_NAME); return RLM_MODULE_FAIL; } else if (rows > 0) { found = 1; } } /* * repeat the above process with the default profile or User-Profile */ 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); if (inst->config->default_profile[0] != 0 || user_profile != NULL){ char *profile = inst->config->default_profile; if (user_profile != NULL) profile = user_profile->vp_strvalue; if (profile && strlen(profile)){ 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"); sql_release_socket(inst, sqlsocket); /* Remove the username we (maybe) added above */ pairdelete(&request->packet->vps, PW_SQL_USER_NAME); return RLM_MODULE_FAIL; } else {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -