Example #1
0
/*
 *	Do any per-module initialization that is separate to each
 *	configured instance of the module.  e.g. set up connections
 *	to external databases, read configuration files, set up
 *	dictionary entries, etc.
 *
 *	If configuration information is given in the config section
 *	that must be referenced in later calls, store a handle to it
 *	in *instance otherwise put a null pointer there.
 */
static int sqlcounter_instantiate(CONF_SECTION *conf, void **instance)
{
	rlm_sqlcounter_t *data;
	DICT_ATTR *dattr;
	ATTR_FLAGS flags;
	time_t now;
	char buffer[MAX_STRING_LEN];

	/*
	 *	Set up a storage area for instance data
	 */
	data = rad_malloc(sizeof(*data));
	if (!data) {
		return -1;
	}
	memset(data, 0, sizeof(*data));

	/*
	 *	If the configuration parameters can't be parsed, then
	 *	fail.
	 */
	if (cf_section_parse(conf, data, module_config) < 0) {
		free(data);
		return -1;
	}

	/*
	 *	No query, die.
	 */
	if (data->query == NULL) {
		radlog(L_ERR, "rlm_sqlcounter: 'query' must be set.");
		return -1;
	}

	/*
	 *	Safe characters list for sql queries. Everything else is
	 *	replaced rwith their mime-encoded equivalents.
	 */
	allowed_chars = data->allowed_chars;

	/*
	 *	Discover the attribute number of the key.
	 */
	if (data->key_name == NULL) {
		radlog(L_ERR, "rlm_sqlcounter: 'key' must be set.");
		return -1;
	}
	sql_escape_func(buffer, sizeof(buffer), data->key_name);
	if (strcmp(buffer, data->key_name) != 0) {
		radlog(L_ERR, "rlm_sqlcounter: The value for option 'key' is too long or contains unsafe characters.");
		return -1;
	}
	dattr = dict_attrbyname(data->key_name);
	if (dattr == NULL) {
		radlog(L_ERR, "rlm_sqlcounter: No such attribute %s",
				data->key_name);
		return -1;
	}
	data->key_attr = dattr->attr;

	/*
	 *	Check the "sqlmod-inst" option.
	 */
	if (data->sqlmod_inst == NULL) {
		radlog(L_ERR, "rlm_sqlcounter: 'sqlmod-inst' must be set.");
		return -1;
	}
	sql_escape_func(buffer, sizeof(buffer), data->sqlmod_inst);
	if (strcmp(buffer, data->sqlmod_inst) != 0) {
		radlog(L_ERR, "rlm_sqlcounter: The value for option 'sqlmod-inst' is too long or contains unsafe characters.");
		return -1;
	}

	/*
	 *  Create a new attribute for the counter.
	 */
	if (data->counter_name == NULL) {
		radlog(L_ERR, "rlm_sqlcounter: 'counter-name' must be set.");
		return -1;
	}

	memset(&flags, 0, sizeof(flags));
	dict_addattr(data->counter_name, 0, PW_TYPE_INTEGER, -1, flags);
	dattr = dict_attrbyname(data->counter_name);
	if (dattr == NULL) {
		radlog(L_ERR, "rlm_sqlcounter: Failed to create counter attribute %s",
				data->counter_name);
		return -1;
	}
	data->dict_attr = dattr->attr;
	DEBUG2("rlm_sqlcounter: Counter attribute %s is number %d",
			data->counter_name, data->dict_attr);

	/*
	 * Create a new attribute for the check item.
	 */
	if (data->check_name == NULL) {
		radlog(L_ERR, "rlm_sqlcounter: 'check-name' must be set.");
		return -1;
	}
	dict_addattr(data->check_name, 0, PW_TYPE_INTEGER, -1, flags);
	dattr = dict_attrbyname(data->check_name);
	if (dattr == NULL) {
		radlog(L_ERR, "rlm_sqlcounter: Failed to create check attribute %s",
				data->counter_name);
		return -1;
	}
	DEBUG2("rlm_sqlcounter: Check attribute %s is number %d",
			data->check_name, dattr->attr);

	/*
	 *  Discover the end of the current time period.
	 */
	if (data->reset == NULL) {
		radlog(L_ERR, "rlm_sqlcounter: 'reset' must be set.");
		return -1;
	}
	now = time(NULL);
	data->reset_time = 0;

	if (find_next_reset(data,now) == -1)
		return -1;

	/*
	 *  Discover the beginning of the current time period.
	 */
	data->last_reset = 0;

	if (find_prev_reset(data,now) == -1)
		return -1;


	/*
	 *	Register the counter comparison operation.
	 */
	paircompare_register(data->dict_attr, 0, sqlcounter_cmp, data);

	*instance = data;

	return 0;
}
/*
 *	Do any per-module initialization that is separate to each
 *	configured instance of the module.  e.g. set up connections
 *	to external databases, read configuration files, set up
 *	dictionary entries, etc.
 *
 *	If configuration information is given in the config section
 *	that must be referenced in later calls, store a handle to it
 *	in *instance otherwise put a null pointer there.
 */
static int mod_instantiate(CONF_SECTION *conf, void *instance)
{
	rlm_sqlcounter_t *inst = instance;
	DICT_ATTR const *da;
	ATTR_FLAGS flags;
	time_t now;

	rad_assert(inst->query && *inst->query);

	da = dict_attrbyname(inst->key_name);
	if (!da) {
		cf_log_err_cs(conf, "Invalid attribute '%s'", inst->key_name);
		return -1;
	}
	inst->key_attr = da;

	da = dict_attrbyname(inst->reply_name);
	if (!da) {
		cf_log_err_cs(conf, "Invalid attribute '%s'", inst->reply_name);
		return -1;
	}
	inst->reply_attr = da;

	/*
	 *  Create a new attribute for the counter.
	 */
	rad_assert(inst->counter_name && *inst->counter_name);
	memset(&flags, 0, sizeof(flags));
	dict_addattr(inst->counter_name, -1, 0, PW_TYPE_INTEGER, flags);
	da = dict_attrbyname(inst->counter_name);
	if (!da) {
		cf_log_err_cs(conf, "Failed to create counter attribute %s", inst->counter_name);
		return -1;
	}
	inst->dict_attr = da;

	/*
	 *  Create a new attribute for the check item.
	 */
	rad_assert(inst->limit_name && *inst->limit_name);
	dict_addattr(inst->limit_name, -1, 0, PW_TYPE_INTEGER, flags);
	da = dict_attrbyname(inst->limit_name);
	if (!da) {
		cf_log_err_cs(conf, "Failed to create check attribute %s", inst->limit_name);
		return -1;
	}

	now = time(NULL);
	inst->reset_time = 0;

	if (find_next_reset(inst,now) == -1) {
		cf_log_err_cs(conf, "Invalid reset '%s'", inst->reset);
		return -1;
	}

	/*
	 *  Discover the beginning of the current time period.
	 */
	inst->last_reset = 0;

	if (find_prev_reset(inst, now) < 0) {
		cf_log_err_cs(conf, "Invalid reset '%s'", inst->reset);
		return -1;
	}

	/*
	 *  Register the counter comparison operation.
	 */
	paircompare_register(inst->dict_attr, NULL, true, sqlcounter_cmp, inst);

	return 0;
}
/*
 *	Do any per-module initialization that is separate to each
 *	configured instance of the module.  e.g. set up connections
 *	to external databases, read configuration files, set up
 *	dictionary entries, etc.
 *
 *	If configuration information is given in the config section
 *	that must be referenced in later calls, store a handle to it
 *	in *instance otherwise put a null pointer there.
 */
static int sqlcounter_instantiate(CONF_SECTION *conf, void **instance)
{
	rlm_sqlcounter_t *data;
	DICT_ATTR *dattr;
	ATTR_FLAGS flags;
	time_t now;

	/*
	 *	Set up a storage area for instance data
	 */
	data = rad_malloc(sizeof(*data));
	if (!data) {
		radlog(L_ERR, "rlm_sqlcounter: Not enough memory.");
		return -1;
	}
	memset(data, 0, sizeof(*data));

	/*
	 *	If the configuration parameters can't be parsed, then
	 *	fail.
	 */
	if (cf_section_parse(conf, data, module_config) < 0) {
		radlog(L_ERR, "rlm_sqlcounter: Unable to parse parameters.");
		sqlcounter_detach(data);
		return -1;
	}

	/*
	 *	No query, die.
	 */
	if (data->query == NULL) {
		radlog(L_ERR, "rlm_sqlcounter: 'query' must be set.");
		sqlcounter_detach(data);
		return -1;
	}

	/*
	 *	Discover the attribute number of the key.
	 */
	if (data->key_name == NULL) {
		radlog(L_ERR, "rlm_sqlcounter: 'key' must be set.");
		sqlcounter_detach(data);
		return -1;
	}
	dattr = dict_attrbyname(data->key_name);
	if (dattr == NULL) {
		radlog(L_ERR, "rlm_sqlcounter: No such attribute %s",
				data->key_name);
		sqlcounter_detach(data);
		return -1;
	}
	data->key_attr = dattr;

	dattr = dict_attrbyname(data->reply_name);
	if (dattr == NULL) {
		radlog(L_ERR, "rlm_sqlcounter: No such attribute %s",
			       data->reply_name);
		sqlcounter_detach(data);
		return -1;
	}
	data->reply_attr = dattr;
	DEBUG2("rlm_sqlcounter: Reply attribute %s is number %d",
		       data->reply_name, dattr->attr);

	/*
	 *	Check the "sqlmod-inst" option.
	 */
	if (data->sqlmod_inst == NULL) {
		radlog(L_ERR, "rlm_sqlcounter: 'sqlmod-inst' must be set.");
		sqlcounter_detach(data);
		return -1;
	}

	/*
	 *  Create a new attribute for the counter.
	 */
	if (data->counter_name == NULL) {
		radlog(L_ERR, "rlm_sqlcounter: 'counter-name' must be set.");
		sqlcounter_detach(data);
		return -1;
	}

	memset(&flags, 0, sizeof(flags));
	dict_addattr(data->counter_name, -1, 0, PW_TYPE_INTEGER, flags);
	dattr = dict_attrbyname(data->counter_name);
	if (dattr == NULL) {
		radlog(L_ERR, "rlm_sqlcounter: Failed to create counter attribute %s",
				data->counter_name);
		sqlcounter_detach(data);
		return -1;
	}
	if (dattr->vendor != 0) {
		radlog(L_ERR, "Counter attribute must not be a VSA");
		sqlcounter_detach(data);
		return -1;
	}
	data->dict_attr = dattr;

	/*
	 * Create a new attribute for the check item.
	 */
	if (data->check_name == NULL) {
		radlog(L_ERR, "rlm_sqlcounter: 'check-name' must be set.");
		sqlcounter_detach(data);
		return -1;
	}
	dict_addattr(data->check_name, 0, PW_TYPE_INTEGER, -1, flags);
	dattr = dict_attrbyname(data->check_name);
	if (dattr == NULL) {
		radlog(L_ERR, "rlm_sqlcounter: Failed to create check attribute %s",
				data->check_name);
		sqlcounter_detach(data);
		return -1;
	}
	DEBUG2("rlm_sqlcounter: Check attribute %s is number %d",
			data->check_name, dattr->attr);

	/*
	 *  Discover the end of the current time period.
	 */
	if (data->reset == NULL) {
		radlog(L_ERR, "rlm_sqlcounter: 'reset' must be set.");
		sqlcounter_detach(data);
		return -1;
	}
	now = time(NULL);
	data->reset_time = 0;

	if (find_next_reset(data,now) == -1) {
		radlog(L_ERR, "rlm_sqlcounter: Failed to find the next reset time.");
		sqlcounter_detach(data);
		return -1;
	}

	/*
	 *  Discover the beginning of the current time period.
	 */
	data->last_reset = 0;

	if (find_prev_reset(data,now) == -1) {
		radlog(L_ERR, "rlm_sqlcounter: Failed to find the previous reset time.");
		sqlcounter_detach(data);
		return -1;
	}

	/*
	 *	Register the counter comparison operation.
	 */
	paircompare_register(data->dict_attr->attr, 0, sqlcounter_cmp, data);

	*instance = data;

	return 0;
}
/*
 *	Do any per-module initialization that is separate to each
 *	configured instance of the module.  e.g. set up connections
 *	to external databases, read configuration files, set up
 *	dictionary entries, etc.
 *
 *	If configuration information is given in the config section
 *	that must be referenced in later calls, store a handle to it
 *	in *instance otherwise put a null pointer there.
 */
static int mod_instantiate(CONF_SECTION *conf, void *instance)
{
	rlm_sqlcounter_t *inst = instance;
	DICT_ATTR const *dattr;
	ATTR_FLAGS flags;
	time_t now;

	rad_assert(inst->query && *inst->query);

	dattr = dict_attrbyname(inst->key_name);
	rad_assert(dattr != NULL);
	if (dattr->vendor != 0) {
		cf_log_err_cs(conf, "Configuration item 'key' cannot be a VSA");
		return -1;
	}
	inst->key_attr = dattr;

	dattr = dict_attrbyname(inst->reply_name);
	rad_assert(dattr != NULL);
	if (dattr->vendor != 0) {
		cf_log_err_cs(conf, "Configuration item 'reply_name' cannot be a VSA");
		return -1;
	}
	inst->reply_attr = dattr;

	DEBUG2("rlm_sqlcounter: Reply attribute %s is number %d",
		       inst->reply_name, dattr->attr);

	/*
	 *  Create a new attribute for the counter.
	 */
	rad_assert(inst->counter_name && *inst->counter_name);
	memset(&flags, 0, sizeof(flags));
	dict_addattr(inst->counter_name, -1, 0, PW_TYPE_INTEGER, flags);
	dattr = dict_attrbyname(inst->counter_name);
	if (!dattr) {
		cf_log_err_cs(conf, "Failed to create counter attribute %s",
				inst->counter_name);
		return -1;
	}
	if (dattr->vendor != 0) {
		cf_log_err_cs(conf, "Counter attribute must not be a VSA");
		return -1;
	}
	inst->dict_attr = dattr;

	/*
	 * Create a new attribute for the check item.
	 */
	rad_assert(inst->check_name && *inst->check_name);
	dict_addattr(inst->check_name, 0, PW_TYPE_INTEGER, -1, flags);
	dattr = dict_attrbyname(inst->check_name);
	if (!dattr) {
		cf_log_err_cs(conf, "Failed to create check attribute %s",
				inst->check_name);
		return -1;
	}
	DEBUG2("rlm_sqlcounter: Check attribute %s is number %d",
			inst->check_name, dattr->attr);

	now = time(NULL);
	inst->reset_time = 0;

	if (find_next_reset(inst,now) == -1) {
		cf_log_err_cs(conf, "Invalid reset '%s'", inst->reset);
		return -1;
	}

	/*
	 *  Discover the beginning of the current time period.
	 */
	inst->last_reset = 0;

	if (find_prev_reset(inst, now) < 0) {
		cf_log_err_cs(conf, "Invalid reset '%s'", inst->reset);
		return -1;
	}

	/*
	 *	Register the counter comparison operation.
	 */
	paircompare_register(inst->dict_attr, NULL, true, sqlcounter_cmp, inst);

	return 0;
}