/*
 *	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_example_t *inst = instance;
	ATTR_FLAGS flags;

	memset(&flags, 0, sizeof(flags));
	/*
	 *	Do more work here
	 */
	if (!inst->boolean) {
		cf_log_err_cs(conf, "Boolean is false: forcing error!");
		return -1;
	}

	if (dict_addattr("Example-Paircmp", -1, 0, PW_TYPE_STRING, flags) < 0) {
		ERROR("Failed creating paircmp attribute: %s", fr_strerror());

		return -1;
	}

	paircompare_register(dict_attrbyname("Example-Paircmp"), dict_attrbyvalue(PW_USER_NAME, 0), false,
			     rlm_example_cmp, inst);

	return 0;
}
Exemple #2
0
/** Instantiate the module
 *
 * Creates a new instance of the module reading parameters from a configuration section.
 *
 * @param conf to parse.
 * @param instance Where to write pointer to configuration data.
 * @return 0 on success < 0 on failure.
 */
static int mod_instantiate(CONF_SECTION *conf, void *instance)
{
	static bool version_done;

	CONF_SECTION *options;
	ldap_instance_t *inst = instance;

	inst->cs = conf;

	options = cf_section_sub_find(conf, "options");
	if (!options || !cf_pair_find(options, "chase_referrals")) {
		inst->chase_referrals_unset = true;	 /* use OpenLDAP defaults */
	}

	inst->xlat_name = cf_section_name2(conf);
	if (!inst->xlat_name) {
		inst->xlat_name = cf_section_name1(conf);
	}


	/*
	 *	Only needs to be done once, prevents races in environment
	 *	initialisation within libldap.
	 *
	 *	See: https://github.com/arr2036/ldapperf/issues/2
	 */
#ifdef HAVE_LDAP_INITIALIZE
	ldap_initialize(&inst->handle, "");
#else
	inst->handle = ldap_init("", 0);
#endif

	/*
	 *	Get version info from the LDAP API.
	 */
	if (!version_done) {
		static LDAPAPIInfo info;	/* static to quiet valgrind about this being uninitialised */
		int ldap_errno;

		version_done = true;

		ldap_errno = ldap_get_option(NULL, LDAP_OPT_API_INFO, &info);
		if (ldap_errno == LDAP_OPT_SUCCESS) {
			if (strcmp(info.ldapai_vendor_name, LDAP_VENDOR_NAME) != 0) {
				WARN("rlm_ldap: libldap vendor changed since the server was built");
				WARN("rlm_ldap: linked: %s, built: %s", info.ldapai_vendor_name, LDAP_VENDOR_NAME);
			}

			if (info.ldapai_vendor_version != LDAP_VENDOR_VERSION) {
				WARN("rlm_ldap: libldap version changed since the server was built");
				WARN("rlm_ldap: linked: %i, built: %i",
				     info.ldapai_vendor_version, LDAP_VENDOR_VERSION);
			}

			INFO("rlm_ldap: libldap vendor: %s, version: %i", info.ldapai_vendor_name,
			     info.ldapai_vendor_version);

			ldap_memfree(info.ldapai_vendor_name);
			ldap_memfree(info.ldapai_extensions);
		} else {
			DEBUG("rlm_ldap: Falling back to build time libldap version info.  Query for LDAP_OPT_API_INFO "
			      "returned: %i", ldap_errno);
			INFO("rlm_ldap: libldap vendor: %s, version: %i.%i.%i", LDAP_VENDOR_NAME,
			     LDAP_VENDOR_VERSION_MAJOR, LDAP_VENDOR_VERSION_MINOR, LDAP_VENDOR_VERSION_PATCH);
		}
	}

	/*
	 *	If the configuration parameters can't be parsed, then fail.
	 */
	if ((parse_sub_section(inst, conf, &inst->accounting, RLM_COMPONENT_ACCT) < 0) ||
	    (parse_sub_section(inst, conf, &inst->postauth, RLM_COMPONENT_POST_AUTH) < 0)) {
		cf_log_err_cs(conf, "Failed parsing configuration");

		goto error;
	}

	/*
	 *	Sanity checks for cacheable groups code.
	 */
	if (inst->cacheable_group_name && inst->groupobj_membership_filter) {
		if (!inst->groupobj_name_attr) {
			cf_log_err_cs(conf, "Directive 'group.name_attribute' must be set if cacheable "
				      "group names are enabled");

			goto error;
		}
	}

	/*
	 *	Split original server value out into URI, server and port
	 *	so whatever initialization function we use later will have
	 *	the server information in the format it needs.
	 */
	if (ldap_is_ldap_url(inst->server)) {
		LDAPURLDesc *ldap_url;
		int port;

		if (ldap_url_parse(inst->server, &ldap_url)){
			cf_log_err_cs(conf, "Parsing LDAP URL \"%s\" failed", inst->server);
			return -1;
		}

		/*
		 *	Figure out the port from the URL
		 */
		if (ldap_url->lud_port == 0) {
			if (strcmp(ldap_url->lud_scheme, "ldaps://") == 0) {
				if (inst->start_tls == true) {
				start_tls_error:
					cf_log_err_cs(conf, "ldaps:// scheme is not compatible with 'start_tls'");
					return -1;
				}
				port = 636;
			} else {
				port = 384;
			}
		} else {
			port = ldap_url->lud_port;
		}

		inst->uri = inst->server;
		inst->server = talloc_strdup(inst, ldap_url->lud_host);

		if ((inst->port != 384) && (port != inst->port)) {
			WARN("Non-default 'port' directive %i set to %i by LDAP URI", inst->port, port);
		}
		inst->port = port;

		/*
		 *	@todo We could set a few other top level
		 *	directives using the URL, like base_dn
		 *	and scope.
		 */

		ldap_free_urldesc(ldap_url);
	/*
	 *	We need to construct an LDAP URI
	 */
	} else {
		switch (inst->port) {
		default:
		case 384:
			inst->uri = talloc_asprintf(inst, "ldap://%s:%i/", inst->server, inst->port);
			break;

		case 636:
			if (inst->start_tls == true) goto start_tls_error;
			inst->uri = talloc_asprintf(inst, "ldaps://%s:%i/", inst->server, inst->port);
			break;
		}
	}

#ifdef LDAP_OPT_X_TLS_NEVER
	/*
	 *	Workaround for servers which support LDAPS but not START TLS
	 */
	if (inst->port == LDAPS_PORT || inst->tls_mode) {
		inst->tls_mode = LDAP_OPT_X_TLS_HARD;
	} else {
		inst->tls_mode = 0;
	}
#endif

	/*
	 *	Convert dereference strings to enumerated constants
	 */
	if (inst->dereference_str) {
		inst->dereference = fr_str2int(ldap_dereference, inst->dereference_str, -1);
		if (inst->dereference < 0) {
			cf_log_err_cs(conf, "Invalid 'dereference' value \"%s\", expected 'never', 'searching', "
				      "'finding' or 'always'", inst->dereference_str);
			goto error;
		}
	}

#if LDAP_SET_REBIND_PROC_ARGS != 3
	/*
	 *	The 2-argument rebind doesn't take an instance variable.  Our rebind function needs the instance
	 *	variable for the username, password, etc.
	 */
	if (inst->rebind == true) {
		cf_log_err_cs(conf, "Cannot use 'rebind' directive as this version of libldap "
			      "does not support the API that we need");

		goto error;
	}
#endif

	/*
	 *	Convert scope strings to enumerated constants
	 */
	inst->userobj_scope = fr_str2int(ldap_scope, inst->userobj_scope_str, -1);
	if (inst->userobj_scope < 0) {
		cf_log_err_cs(conf, "Invalid 'user.scope' value \"%s\", expected 'sub', 'one'"
#ifdef LDAP_SCOPE_CHILDREN
			      ", 'base' or 'children'"
#else
			      " or 'base'"
#endif
			 , inst->userobj_scope_str);
		goto error;
	}

	inst->groupobj_scope = fr_str2int(ldap_scope, inst->groupobj_scope_str, -1);
	if (inst->groupobj_scope < 0) {
		cf_log_err_cs(conf, "Invalid 'group.scope' value \"%s\", expected 'sub', 'one'"
#ifdef LDAP_SCOPE_CHILDREN
			      ", 'base' or 'children'"
#else
			      " or 'base'"
#endif
			 , inst->groupobj_scope_str);
		goto error;
	}

	inst->clientobj_scope = fr_str2int(ldap_scope, inst->clientobj_scope_str, -1);
	if (inst->clientobj_scope < 0) {
		cf_log_err_cs(conf, "Invalid 'client.scope' value \"%s\", expected 'sub', 'one'"
#ifdef LDAP_SCOPE_CHILDREN
			      ", 'base' or 'children'"
#else
			      " or 'base'"
#endif
			 , inst->clientobj_scope_str);
		goto error;
	}

	if (inst->tls_require_cert_str) {
#ifdef LDAP_OPT_X_TLS_NEVER
		/*
		 *	Convert cert strictness to enumerated constants
		 */
		inst->tls_require_cert = fr_str2int(ldap_tls_require_cert, inst->tls_require_cert_str, -1);
		if (inst->tls_require_cert < 0) {
			cf_log_err_cs(conf, "Invalid 'tls.require_cert' value \"%s\", expected 'never', "
				      "'demand', 'allow', 'try' or 'hard'", inst->tls_require_cert_str);
			goto error;
		}
#else
		cf_log_err_cs(conf, "Modifying 'tls.require_cert' is not supported by current "
			      "version of libldap. Please upgrade or substitute current libldap and "
			      "rebuild this module");

		goto error;
#endif
	}
	/*
	 *	Build the attribute map
	 */
	if (map_afrom_cs(&inst->user_map, cf_section_sub_find(inst->cs, "update"),
			 PAIR_LIST_REPLY, PAIR_LIST_REQUEST, rlm_ldap_map_verify, inst,
			 LDAP_MAX_ATTRMAP) < 0) {
		return -1;
	}

	/*
	 *	Group comparison checks.
	 */
	if (cf_section_name2(conf)) {
		static ATTR_FLAGS flags;
		char buffer[256];

		snprintf(buffer, sizeof(buffer), "%s-Ldap-Group", inst->xlat_name);
		if (dict_addattr(buffer, -1, 0, PW_TYPE_STRING, flags) < 0) {
			LDAP_ERR("Error creating group attribute: %s", fr_strerror());

			return -1;
		}
		inst->group_da = dict_attrbyname(buffer);
		if (!inst->group_da) {
			LDAP_ERR("Failed creating attribute %s", buffer);

			goto error;
		}

		paircompare_register(inst->group_da, dict_attrbyvalue(PW_USER_NAME, 0), false, rlm_ldap_groupcmp, inst);
	/*
	 *	Were the default instance
	 */
	} else {
		inst->group_da = dict_attrbyvalue(PW_LDAP_GROUP, 0);
		paircompare_register(dict_attrbyvalue(PW_LDAP_GROUP, 0), dict_attrbyvalue(PW_USER_NAME, 0),
				false, rlm_ldap_groupcmp, inst);
	}

	xlat_register(inst->xlat_name, ldap_xlat, rlm_ldap_escape_func, inst);

	/*
	 *	Setup the cache attribute
	 */
	if (inst->cache_attribute) {
		static ATTR_FLAGS flags;

		if (dict_addattr(inst->cache_attribute, -1, 0, PW_TYPE_STRING, flags) < 0) {
			LDAP_ERR("Error creating cache attribute: %s", fr_strerror());

			goto error;
		}
		inst->cache_da = dict_attrbyname(inst->cache_attribute);
	} else {
		inst->cache_da = inst->group_da;	/* Default to the group_da */
	}

	/*
	 *	Initialize the socket pool.
	 */
	inst->pool = fr_connection_pool_module_init(inst->cs, inst, mod_conn_create, NULL, NULL);
	if (!inst->pool) goto error;

	/*
	 *	Bulk load dynamic clients.
	 */
	if (inst->do_clients) {
		CONF_SECTION *cs;

		cs = cf_section_sub_find(inst->cs, "client");
		if (!cs) {
			cf_log_err_cs(conf, "Told to load clients but no client section found");
			goto error;
		}

		cs = cf_section_sub_find(cs, "attribute");
		if (!cs) {
			cf_log_err_cs(conf, "Told to load clients but no attribute section found");
			goto error;
		}

		if (rlm_ldap_client_load(inst, cs) < 0) {
			cf_log_err_cs(conf, "Error loading clients");

			return -1;
		}
	}

	return 0;

error:
	return -1;
}
Exemple #3
0
static int mod_instantiate(CONF_SECTION *conf, void *instance)
{
	rlm_sql_t *inst = instance;

	/*
	 *	Hack...
	 */
	inst->config = &inst->myconfig;
	inst->cs = conf;

	inst->config->xlat_name = cf_section_name2(conf);
	if (!inst->config->xlat_name) {
		inst->config->xlat_name = cf_section_name1(conf);
	} else {
		char *group_name;
		DICT_ATTR const *da;
		ATTR_FLAGS flags;

		/*
		 *	Allocate room for <instance>-SQL-Group
		 */
		group_name = talloc_typed_asprintf(inst, "%s-SQL-Group", inst->config->xlat_name);
		DEBUG("rlm_sql (%s): Creating new attribute %s",
		      inst->config->xlat_name, group_name);

		memset(&flags, 0, sizeof(flags));
		if (dict_addattr(group_name, -1, 0, PW_TYPE_STRING, flags) < 0) {
			ERROR("rlm_sql (%s): Failed to create "
			       "attribute %s: %s", inst->config->xlat_name, group_name,
			       fr_strerror());
			return -1;
		}

		da = dict_attrbyname(group_name);
		if (!da) {
			ERROR("rlm_sql (%s): Failed to create "
			       "attribute %s", inst->config->xlat_name, group_name);
			return -1;
		}

		if (inst->config->groupmemb_query &&
		    inst->config->groupmemb_query[0]) {
			DEBUG("rlm_sql (%s): Registering sql_groupcmp for %s",
			      inst->config->xlat_name, group_name);
			paircompare_register(da, dict_attrbyvalue(PW_USER_NAME, 0),
					     false, sql_groupcmp, inst);
		}
	}

	rad_assert(inst->config->xlat_name);

	/*
	 *	If the configuration parameters can't be parsed, then fail.
	 */
	if ((parse_sub_section(conf, inst, &inst->config->accounting, RLM_COMPONENT_ACCT) < 0) ||
	    (parse_sub_section(conf, inst, &inst->config->postauth, RLM_COMPONENT_POST_AUTH) < 0)) {
		cf_log_err_cs(conf, "Invalid configuration");
		return -1;
	}

	/*
	 *	Cache the SQL-User-Name DICT_ATTR, so we can be slightly
	 *	more efficient about creating SQL-User-Name attributes.
	 */
	inst->sql_user = dict_attrbyname("SQL-User-Name");
	if (!inst->sql_user) {
		return -1;
	}

	/*
	 *	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;
	inst->sql_query			= rlm_sql_query;
	inst->sql_select_query		= rlm_sql_select_query;
	inst->sql_fetch_row		= rlm_sql_fetch_row;

	/*
	 *	Register the SQL xlat function
	 */
	xlat_register(inst->config->xlat_name, sql_xlat, sql_escape_func, inst);

	/*
	 *	Sanity check for crazy people.
	 */
	if (strncmp(inst->config->sql_driver_name, "rlm_sql_", 8) != 0) {
		ERROR("rlm_sql (%s): \"%s\" is NOT an SQL driver!",
		       inst->config->xlat_name, inst->config->sql_driver_name);
		return -1;
	}

	/*
	 *	Load the appropriate driver for our database
	 */
	inst->handle = lt_dlopenext(inst->config->sql_driver_name);
	if (!inst->handle) {
		ERROR("Could not link driver %s: %s",
		       inst->config->sql_driver_name,
		       dlerror());
		ERROR("Make sure it (and all its dependent libraries!)"
		       "are in the search path of your system's ld");
		return -1;
	}

	inst->module = (rlm_sql_module_t *) dlsym(inst->handle,
						  inst->config->sql_driver_name);
	if (!inst->module) {
		ERROR("Could not link symbol %s: %s",
		       inst->config->sql_driver_name,
		       dlerror());
		return -1;
	}

	if (inst->module->mod_instantiate) {
		CONF_SECTION *cs;
		char const *name;

		name = strrchr(inst->config->sql_driver_name, '_');
		if (!name) {
			name = inst->config->sql_driver_name;
		} else {
			name++;
		}

		cs = cf_section_sub_find(conf, name);
		if (!cs) {
			cs = cf_section_alloc(conf, name, NULL);
			if (!cs) {
				return -1;
			}
		}

		/*
		 *	It's up to the driver to register a destructor
		 */
		if (inst->module->mod_instantiate(cs, inst->config) < 0) {
			return -1;
		}
	}

	inst->lf = fr_logfile_init(inst);
	if (!inst->lf) {
		cf_log_err_cs(conf, "Failed creating log file context");
		return -1;
	}

	INFO("rlm_sql (%s): Driver %s (module %s) loaded and linked",
	       inst->config->xlat_name, inst->config->sql_driver_name,
	       inst->module->name);

	/*
	 *	Initialise the connection pool for this instance
	 */
	INFO("rlm_sql (%s): Attempting to connect to database \"%s\"",
	       inst->config->xlat_name, inst->config->sql_db);

	if (sql_socket_pool_init(inst) < 0) return -1;

	if (inst->config->groupmemb_query &&
	    inst->config->groupmemb_query[0]) {
		paircompare_register(dict_attrbyvalue(PW_SQL_GROUP, 0),
				dict_attrbyvalue(PW_USER_NAME, 0), false, sql_groupcmp, inst);
	}

	if (inst->config->do_clients) {
		if (generate_sql_clients(inst) == -1){
			ERROR("Failed to load clients from SQL");
			return -1;
		}
	}

	return RLM_MODULE_OK;
}
Exemple #4
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;
}
/** Instantiate the module
 *
 * Creates a new instance of the module reading parameters from a configuration section.
 *
 * @param conf to parse.
 * @param instance Where to write pointer to configuration data.
 * @return 0 on success < 0 on failure.
 */
static int mod_instantiate(CONF_SECTION *conf, void *instance)
{
	CONF_SECTION *options;
	ldap_instance_t *inst = instance;

	inst->cs = conf;

	options = cf_section_sub_find(conf, "options");
	if (!options || !cf_pair_find(options, "chase_referrals")) {
		inst->chase_referrals_unset = true;	 /* use OpenLDAP defaults */
	}

	inst->xlat_name = cf_section_name2(conf);
	if (!inst->xlat_name) {
		inst->xlat_name = cf_section_name1(conf);
	}

	/*
	 *	If the configuration parameters can't be parsed, then fail.
	 */
	if ((parse_sub_section(inst, conf, &inst->accounting, RLM_COMPONENT_ACCT) < 0) ||
	    (parse_sub_section(inst, conf, &inst->postauth, RLM_COMPONENT_POST_AUTH) < 0)) {
		LDAP_ERR("Failed parsing configuration");

		goto error;
	}

	/*
	 *	Sanity checks for cacheable groups code.
	 */
	if (inst->cacheable_group_name && inst->groupobj_membership_filter) {
		if (!inst->groupobj_name_attr) {
			LDAP_ERR("Directive 'group.name_attribute' must be set if cacheable group names are enabled");

			goto error;
		}
	}

	/*
	 *	Check for URLs.  If they're used and the library doesn't support them, then complain.
	 */
	inst->is_url = 0;
	if (ldap_is_ldap_url(inst->server)) {
#ifdef HAVE_LDAP_INITIALIZE
		inst->is_url = 1;
		inst->port = 0;
#else
		LDAP_ERR("Directive 'server' is in URL form but ldap_initialize() is not available");
		goto error;
#endif
	}

	/*
	 *	Workaround for servers which support LDAPS but not START TLS
	 */
	if (inst->port == LDAPS_PORT || inst->tls_mode) {
		inst->tls_mode = LDAP_OPT_X_TLS_HARD;
	} else {
		inst->tls_mode = 0;
	}

#if LDAP_SET_REBIND_PROC_ARGS != 3
	/*
	 *	The 2-argument rebind doesn't take an instance variable.  Our rebind function needs the instance
	 *	variable for the username, password, etc.
	 */
	if (inst->rebind == true) {
		LDAP_ERR("Cannot use 'rebind' directive as this version of libldap does not support the API "
			 "that we need");

		goto error;
	}
#endif

	/*
	 *	Convert scope strings to enumerated constants
	 */
	inst->userobj_scope = fr_str2int(ldap_scope, inst->userobj_scope_str, -1);
	if (inst->userobj_scope < 0) {
		LDAP_ERR("Invalid 'user.scope' value \"%s\", expected 'sub', 'one', 'base' or 'children'",
			 inst->userobj_scope_str);
		goto error;
	}

	inst->groupobj_scope = fr_str2int(ldap_scope, inst->groupobj_scope_str, -1);
	if (inst->groupobj_scope < 0) {
		LDAP_ERR("Invalid 'group.scope' value \"%s\", expected 'sub', 'one', 'base' or 'children'",
			 inst->groupobj_scope_str);
		goto error;
	}

	inst->clientobj_scope = fr_str2int(ldap_scope, inst->clientobj_scope_str, -1);
	if (inst->clientobj_scope < 0) {
		LDAP_ERR("Invalid 'client.scope' value \"%s\", expected 'sub', 'one', 'base' or 'children'",
			 inst->clientobj_scope_str);
		goto error;
	}

	if (inst->tls_require_cert_str) {
#ifdef LDAP_OPT_X_TLS_NEVER
		/*
		 *	Convert cert strictness to enumerated constants
		 */
		inst->tls_require_cert = fr_str2int(ldap_tls_require_cert, inst->tls_require_cert_str, -1);
		if (inst->tls_require_cert < 0) {
			LDAP_ERR("Invalid 'tls.require_cert' value \"%s\", expected 'never', 'demand', 'allow', "
				 "'try' or 'hard'", inst->tls_require_cert_str);
			goto error;
		}
#else
		LDAP_ERR("Modifying 'tls.require_cert' is not supported by current version of libldap. "
			 "Please upgrade libldap and rebuild this module");

		goto error;
#endif
	}
	/*
	 *	Build the attribute map
	 */
	if (rlm_ldap_map_verify(inst, &(inst->user_map)) < 0) {
		goto error;
	}

	/*
	 *	Group comparison checks.
	 */
	if (cf_section_name2(conf)) {
		ATTR_FLAGS flags;
		char buffer[256];

		snprintf(buffer, sizeof(buffer), "%s-Ldap-Group",
			 inst->xlat_name);
		memset(&flags, 0, sizeof(flags));

		if (dict_addattr(buffer, -1, 0, PW_TYPE_STRING, flags) < 0) {
			LDAP_ERR("Error creating group attribute: %s", fr_strerror());

			return -1;
		}
		inst->group_da = dict_attrbyname(buffer);
		if (!inst->group_da) {
			LDAP_ERR("Failed creating attribute %s", buffer);

			goto error;
		}

		paircompare_register(inst->group_da, dict_attrbyvalue(PW_USER_NAME, 0), false, rlm_ldap_groupcmp, inst);
	/*
	 *	Were the default instance
	 */
	} else {
		inst->group_da = dict_attrbyvalue(PW_LDAP_GROUP, 0);
		paircompare_register(dict_attrbyvalue(PW_LDAP_GROUP, 0), dict_attrbyvalue(PW_USER_NAME, 0),
				false, rlm_ldap_groupcmp, inst);
	}

	xlat_register(inst->xlat_name, ldap_xlat, rlm_ldap_escape_func, inst);

	/*
	 *	Setup the cache attribute
	 */
	if (inst->cache_attribute) {
		ATTR_FLAGS flags;
		memset(&flags, 0, sizeof(flags));

		if (dict_addattr(inst->cache_attribute, -1, 0, PW_TYPE_STRING, flags) < 0) {
			LDAP_ERR("Error creating cache attribute: %s", fr_strerror());

			return -1;
		}
		inst->cache_da = dict_attrbyname(inst->cache_attribute);
	} else {
		inst->cache_da = inst->group_da;	/* Default to the group_da */
	}

	/*
	 *	Initialize the socket pool.
	 */
	inst->pool = fr_connection_pool_init(inst->cs, inst, mod_conn_create, NULL, mod_conn_delete, NULL);
	if (!inst->pool) {
		return -1;
	}

	/*
	 *	Bulk load dynamic clients.
	 */
	if (inst->do_clients) {
		if (rlm_ldap_load_clients(inst) < 0) {
			LDAP_ERR("Error loading clients");

			return -1;
		}
	}

	return 0;

error:
	return -1;
}
Exemple #6
0
/*
 *	Process the ATTRIBUTE command
 */
static int process_attribute(const char* fn, const int line,
			     const int block_vendor, DICT_ATTR *block_tlv,
			     char **argv, int argc)
{
	int		vendor = 0;
	int		value;
	int		type;
	ATTR_FLAGS	flags;

	if ((argc < 3) || (argc > 4)) {
		fr_strerror_printf("dict_init: %s[%d]: invalid ATTRIBUTE line",
			fn, line);
		return -1;
	}

	/*
	 *	Validate all entries
	 */
	if (!sscanf_i(argv[1], &value)) {
		fr_strerror_printf("dict_init: %s[%d]: invalid value", fn, line);
		return -1;
	}

	/*
	 *	find the type of the attribute.
	 */
	type = fr_str2int(type_table, argv[2], -1);
	if (type < 0) {
		fr_strerror_printf("dict_init: %s[%d]: invalid type \"%s\"",
			fn, line, argv[2]);
		return -1;
	}

	/*
	 *	Only look up the vendor if the string
	 *	is non-empty.
	 */
	memset(&flags, 0, sizeof(flags));
	if (argc == 4) {
		char *key, *next, *last;

		key = argv[3];
		do {
			next = strchr(key, ',');
			if (next) *(next++) = '\0';

			if (strcmp(key, "has_tag") == 0 ||
			    strcmp(key, "has_tag=1") == 0) {
				/* Boolean flag, means this is a
				   tagged attribute */
				flags.has_tag = 1;
				
			} else if (strncmp(key, "encrypt=", 8) == 0) {
				/* Encryption method, defaults to 0 (none).
				   Currently valid is just type 2,
				   Tunnel-Password style, which can only
				   be applied to strings. */
				flags.encrypt = strtol(key + 8, &last, 0);
				if (*last) {
					fr_strerror_printf( "dict_init: %s[%d] invalid option %s",
						    fn, line, key);
					return -1;
				}
				
			} else if (strncmp(key, "array", 8) == 0) {
				flags.array = 1;
				
				switch (type) {
					case PW_TYPE_IPADDR:
					case PW_TYPE_BYTE:
					case PW_TYPE_SHORT:
					case PW_TYPE_INTEGER:
					case PW_TYPE_DATE:
						break;

					default:
						fr_strerror_printf( "dict_init: %s[%d] Only IP addresses can have the \"array\" flag set.",
							    fn, line);
						return -1;
				}

				/*
				 *	The only thing is the vendor name,
				 *	and it's a known name: allow it.
				 */
			} else if ((key == argv[3]) && !next && !block_vendor &&
				   ((vendor = dict_vendorbyname(key)) !=0)) {
				break;

			} else {
				fr_strerror_printf( "dict_init: %s[%d]: unknown option \"%s\"",
					    fn, line, key);
				return -1;
			}

			key = next;
			if (key && !*key) break;
		} while (key);
	}

	if (block_vendor) vendor = block_vendor;

	/*
	 *	Special checks for tags, they make our life much more
	 *	difficult.
	 */
	if (flags.has_tag) {
		/*
		 *	Only string, octets, and integer can be tagged.
		 */
		switch (type) {
		case PW_TYPE_STRING:
		case PW_TYPE_INTEGER:
			break;

		default:
			fr_strerror_printf("dict_init: %s[%d]: Attributes of type %s cannot be tagged.",
				   fn, line,
				   fr_int2str(type_table, type, "?Unknown?"));
			return -1;

		}
	}

	if (type == PW_TYPE_TLV) {
		flags.has_tlv = 1;
	}

	if (block_tlv) {
		/*
		 *	TLV's can be only one octet.
		 */
		if ((value <= 0) || (value > 255)) {
			fr_strerror_printf( "dict_init: %s[%d]: sub-tlv's cannot have value > 255",
				    fn, line);
			return -1;
		}

		if (flags.encrypt != FLAG_ENCRYPT_NONE) {
			fr_strerror_printf( "dict_init: %s[%d]: sub-tlv's cannot be encrypted",
				    fn, line);
			return -1;
		}

		/*
		 *	
		 */
		value <<= 8;
		value |= (block_tlv->attr & 0xffff);
		flags.is_tlv = 1;
	}

#ifdef WITH_DICTIONARY_WARNINGS
	/*
	 *	Hack to help us discover which vendors have illegal
	 *	attributes.
	 */
	if (!vendor && (value < 256) &&
	    !strstr(fn, "rfc") && !strstr(fn, "illegal")) {
		fprintf(stderr, "WARNING: Illegal Attribute %s in %s\n",
			argv[0], fn);
	}
#endif

	/*
	 *	Add it in.
	 */
	if (dict_addattr(argv[0], vendor, type, value, flags) < 0) {
		char buffer[256];

		strlcpy(buffer, fr_strerror(), sizeof(buffer));

		fr_strerror_printf("dict_init: %s[%d]: %s",
				   fn, line, buffer);
		return -1;
	}

	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 checkval_instantiate(CONF_SECTION *conf, void **instance)
{
	rlm_checkval_t *data;
	DICT_ATTR *dattr;
	ATTR_FLAGS flags;

	static const LRAD_NAME_NUMBER names[] = {
		{ "string", PW_TYPE_STRING },
		{ "integer", PW_TYPE_INTEGER },
		{ "ipaddr", PW_TYPE_IPADDR },
		{ "date", PW_TYPE_DATE },
		{ "abinary", PW_TYPE_OCTETS },
		{ "octets", PW_TYPE_OCTETS },
		{ "binary", PW_TYPE_OCTETS },
		{ NULL, 0 }
	};
	
	/*
	 *	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) {
		checkval_detach(data);
		return -1;
	}

	/*
	 * Check if data_type exists
	 */
	if (!data->data_type || !strlen(data->data_type)){
		radlog(L_ERR, "rlm_checkval: Data type not defined");
		checkval_detach(data);
		return -1;
	}
	if (!data->item_name || !strlen(data->item_name)){
		radlog(L_ERR, "rlm_checkval: Item name not defined");
		checkval_detach(data);
		return -1;
	}
	if (!data->check_name || !strlen(data->check_name)){
		radlog(L_ERR, "rlm_checkval: Check item name not defined");
		checkval_detach(data);
		return -1;
	}

	/*
	 *	Discover the attribute number of the item name
	 */
	dattr = dict_attrbyname(data->item_name);
	if (!dattr) {
		radlog(L_ERR, "rlm_checkval: No such attribute %s",
		       data->item_name);
		checkval_detach(data);
		return -1;
	}
	data->item_attr = dattr->attr;
	
	/*
	 *	Add the check attribute name to the dictionary
	 *	if it does not already exists. dict_addattr() handles that
	 */

	memset(&flags, 0, sizeof(flags));
	dict_addattr(data->check_name, 0, PW_TYPE_STRING, -1,flags);
	dattr = dict_attrbyname(data->check_name);
	if (!dattr){
		radlog(L_ERR, "rlm_checkval: No such attribute %s",
		       data->check_name);
		checkval_detach(data);
		return -1;
	}
	data->chk_attr = dattr->attr;
	DEBUG2("rlm_checkval: Registered name %s for attribute %d",
		dattr->name,dattr->attr);

	/*
	 *	Convert the string type to an integer type,
	 *	so we don't have to do string comparisons on each
	 *	packet.
	 */
	data->dat_type = lrad_str2int(names, data->data_type, -1);
	if (data->dat_type < 0) {
		radlog(L_ERR, "rlm_checkval: Data type %s in not known",data->data_type);
		checkval_detach(data);
		return -1;
	}

	*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 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;
}
static int mod_instantiate(CONF_SECTION *conf, void *instance)
{
	rlm_sql_t *inst = instance;

	/*
	 *	Hack...
	 */
	inst->config = &inst->myconfig;
	inst->cs = conf;

	inst->config->xlat_name = cf_section_name2(conf);
	if (!inst->config->xlat_name) {
		inst->config->xlat_name = cf_section_name1(conf);
	} else {
		char *group_name;
		DICT_ATTR const *da;
		ATTR_FLAGS flags;

		/*
		 *	Allocate room for <instance>-SQL-Group
		 */
		group_name = talloc_typed_asprintf(inst, "%s-SQL-Group", inst->config->xlat_name);
		DEBUG("rlm_sql (%s): Creating new attribute %s",
		      inst->config->xlat_name, group_name);

		memset(&flags, 0, sizeof(flags));
		if (dict_addattr(group_name, -1, 0, PW_TYPE_STRING, flags) < 0) {
			ERROR("rlm_sql (%s): Failed to create "
			       "attribute %s: %s", inst->config->xlat_name, group_name,
			       fr_strerror());
			return -1;
		}

		da = dict_attrbyname(group_name);
		if (!da) {
			ERROR("rlm_sql (%s): Failed to create "
			       "attribute %s", inst->config->xlat_name, group_name);
			return -1;
		}

		if (inst->config->groupmemb_query) {
			DEBUG("rlm_sql (%s): Registering sql_groupcmp for %s",
			      inst->config->xlat_name, group_name);
			paircompare_register(da, dict_attrbyvalue(PW_USER_NAME, 0),
					     false, sql_groupcmp, inst);
		}
	}

	rad_assert(inst->config->xlat_name);

	/*
	 *	Sanity check for crazy people.
	 */
	if (strncmp(inst->config->sql_driver_name, "rlm_sql_", 8) != 0) {
		ERROR("rlm_sql (%s): \"%s\" is NOT an SQL driver!", inst->config->xlat_name, inst->config->sql_driver_name);
		return -1;
	}

	/*
	 *	We need authorize_group_check_query or authorize_group_reply_query
	 *	if group_membership_query is set.
	 *
	 *	Or we need group_membership_query if authorize_group_check_query or
	 *	authorize_group_reply_query is set.
	 */
	if (!inst->config->groupmemb_query) {
		if (inst->config->authorize_group_check_query) {
			WARN("rlm_sql (%s): Ignoring authorize_group_reply_query as group_membership_query "
			     "is not configured", inst->config->xlat_name);
		}

		if (inst->config->authorize_group_reply_query) {
			WARN("rlm_sql (%s): Ignoring authorize_group_check_query as group_membership_query "
			     "is not configured", inst->config->xlat_name);
		}
	} else {
		if (!inst->config->authorize_group_check_query) {
			ERROR("rlm_sql (%s): authorize_group_check_query must be configured as group_membership_query "
			      "is configured", inst->config->xlat_name);
			return -1;
		}

		if (!inst->config->authorize_group_reply_query) {
			ERROR("rlm_sql (%s): authorize_group_reply_query must be configured as group_membership_query "
			      "is configured", inst->config->xlat_name);
			return -1;
		}
	}

	/*
	 *	This will always exist, as cf_section_parse_init()
	 *	will create it if it doesn't exist.  However, the
	 *	"reference" config item won't exist in an auto-created
	 *	configuration.  So if that doesn't exist, we ignore
	 *	the whole subsection.
	 */
	inst->config->accounting.cs = cf_section_sub_find(conf, "accounting");
	inst->config->accounting.reference_cp = (cf_pair_find(inst->config->accounting.cs, "reference") != NULL);

	inst->config->postauth.cs = cf_section_sub_find(conf, "post-auth");
	inst->config->postauth.reference_cp = (cf_pair_find(inst->config->postauth.cs, "reference") != NULL);

	/*
	 *	Cache the SQL-User-Name DICT_ATTR, so we can be slightly
	 *	more efficient about creating SQL-User-Name attributes.
	 */
	inst->sql_user = dict_attrbyname("SQL-User-Name");
	if (!inst->sql_user) {
		return -1;
	}

	/*
	 *	Export these methods, too.  This avoids RTDL_GLOBAL.
	 */
	inst->sql_set_user		= sql_set_user;
	inst->sql_escape_func		= sql_escape_func;
	inst->sql_query			= rlm_sql_query;
	inst->sql_select_query		= rlm_sql_select_query;
	inst->sql_fetch_row		= rlm_sql_fetch_row;

	/*
	 *	Register the SQL xlat function
	 */
	xlat_register(inst->config->xlat_name, sql_xlat, sql_escape_func, inst);

	/*
	 *	Load the appropriate driver for our database
	 */
	inst->handle = lt_dlopenext(inst->config->sql_driver_name);
	if (!inst->handle) {
		ERROR("Could not link driver %s: %s", inst->config->sql_driver_name, dlerror());
		ERROR("Make sure it (and all its dependent libraries!) are in the search path of your system's ld");
		return -1;
	}

	inst->module = (rlm_sql_module_t *) dlsym(inst->handle,
						  inst->config->sql_driver_name);
	if (!inst->module) {
		ERROR("Could not link symbol %s: %s", inst->config->sql_driver_name, dlerror());
		return -1;
	}

	if (inst->module->mod_instantiate) {
		CONF_SECTION *cs;
		char const *name;

		name = strrchr(inst->config->sql_driver_name, '_');
		if (!name) {
			name = inst->config->sql_driver_name;
		} else {
			name++;
		}

		cs = cf_section_sub_find(conf, name);
		if (!cs) {
			cs = cf_section_alloc(conf, name, NULL);
			if (!cs) {
				return -1;
			}
		}

		/*
		 *	It's up to the driver to register a destructor
		 */
		if (inst->module->mod_instantiate(cs, inst->config) < 0) {
			return -1;
		}
	}

	inst->ef = exfile_init(inst, 64, 30);
	if (!inst->ef) {
		cf_log_err_cs(conf, "Failed creating log file context");
		return -1;
	}

	INFO("rlm_sql (%s): Driver %s (module %s) loaded and linked", inst->config->xlat_name,
	     inst->config->sql_driver_name, inst->module->name);

	/*
	 *	Initialise the connection pool for this instance
	 */
	INFO("rlm_sql (%s): Attempting to connect to database \"%s\"", inst->config->xlat_name, inst->config->sql_db);

	inst->pool = fr_connection_pool_module_init(inst->cs, inst, mod_conn_create, NULL, NULL);
	if (!inst->pool) return -1;

	if (inst->config->groupmemb_query) {
		paircompare_register(dict_attrbyvalue(PW_SQL_GROUP, 0),
				     dict_attrbyvalue(PW_USER_NAME, 0), false, sql_groupcmp, inst);
	}

	if (inst->config->do_clients) {
		if (generate_sql_clients(inst) == -1){
			ERROR("Failed to load clients from SQL");
			return -1;
		}
	}

	return RLM_MODULE_OK;
}
/*
 *	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;
}
static int rlm_redisn_instantiate(CONF_SECTION * conf, void **instance)
{
  static size_t query2Queries[]=
    { offsetof(REDIS_INST,accounting_on_query),
      offsetof(REDIS_INST,accounting_on_queries),
      offsetof(REDIS_INST,accounting_off_query),
      offsetof(REDIS_INST,accounting_off_queries),
      offsetof(REDIS_INST,accounting_update_query),
      offsetof(REDIS_INST,accounting_update_queries),
      offsetof(REDIS_INST,accounting_start_query),
      offsetof(REDIS_INST,accounting_start_queries),
      offsetof(REDIS_INST,accounting_stop_query),
      offsetof(REDIS_INST,accounting_stop_queries),
      0
    };

	REDIS_INST *inst;
	const char *xlat_name;

	inst = rad_malloc(sizeof(REDIS_INST));
	memset(inst, 0, sizeof(REDIS_INST));

	/*
	 *	Export these methods, too.  This avoids RTDL_GLOBAL.
	 */
	inst->redisn_set_user = redisn_set_user;
	inst->redisn_get_socket = redisn_get_socket;
	inst->redisn_release_socket = redisn_release_socket;
	inst->redisn_escape_func = redisn_escape_func;
	inst->redisn_query = rlm_redisn_query;
	inst->redisn_finish_query = rlm_redisn_finish_query;
	inst->redisn_fetch_row = rlm_redisn_fetch_row;

	/*
	 * If the configuration parameters can't be parsed, then
	 * fail.
	 */
	if (cf_section_parse(conf, inst, module_config) < 0) {
		rlm_redisn_detach(inst);
		return -1;
	}
DEBUG("rlm_redisn (%s): vp_separator=%s\n",inst->xlat_name,inst->vp_separator);
	if (inst->vp_separator==NULL || 
	    inst->vp_separator[0]=='\0') {
	  radlog(L_CONS | L_ERR, "rlm_redisn (%s): Bad vp_separator",
		 inst->xlat_name);
	  free(inst);
	  return -1;
	}
	if (inst->vp_separator[0]=='0'
	    && inst->vp_separator[1]=='x') {
	  long int sep=strtol(inst->vp_separator+2,NULL,16);
	  if (sep<=0
	      || sep>255) {
	    radlog(L_CONS | L_ERR, "rlm_redisn (%s): Bad vp_separator",
		   inst->xlat_name);
	    free(inst);
	    return -1;
	    }
	  else {
	    //we have space as len is at least 2
	    inst->vp_separator[0]=(char)sep;
	    inst->vp_separator[1]=0;
	  }
	}
	else if (inst->vp_separator[1]!='\0') {
	  radlog(L_CONS | L_ERR, "rlm_redisn (%s): Bad vp_separator",
		 inst->xlat_name);
	  free(inst);
	  return -1;
	}

	if (explode_servers(inst)!=0){
	  free(inst);
	  return -1;
	}

	{
	  int q=0;
	  while(query2Queries[q]>0) {
	    DEBUG("rlm_redisn (%s): query #%d\n",inst->xlat_name,q);
	      char **queryPtr = (char **) (((char *)inst) + query2Queries[q]);
	      char ***queriesPtr = (char ***) (((char *)inst) + query2Queries[q+1]);
	      if (*queryPtr &&
		  **queryPtr!='\0') {
		DEBUG("rlm_redisn (%s): query #%d: %s\n",inst->xlat_name,q,*queryPtr);
		redisn_split_string(queriesPtr,*queryPtr,'\n',1);		
		DEBUG("rlm_redisn (%s): query #%d: q0=%s\n",inst->xlat_name,q,*queriesPtr[0]);
	      }
	      q+=2;
	    };	  
	}
	

	xlat_name = cf_section_name2(conf);
	if (xlat_name == NULL) {
		xlat_name = cf_section_name1(conf);
	} else {
		char *group_name;
		DICT_ATTR *dattr;
		ATTR_FLAGS flags;

		/*
		 * Allocate room for <instance>-REDISN-Group
		 */
		group_name = rad_malloc((strlen(xlat_name) + 1 + 11) * sizeof(char));
		sprintf(group_name,"%s-REDISN-Group",xlat_name);
		DEBUG("rlm_redisn Creating new attribute %s",group_name);

		memset(&flags, 0, sizeof(flags));
		dict_addattr(group_name, 0, PW_TYPE_STRING, -1, flags);
		dattr = dict_attrbyname(group_name);
		if (dattr == NULL){
			radlog(L_ERR, "rlm_redisn: Failed to create attribute %s",group_name);
			free(group_name);
			free(inst);	/* FIXME: detach */
			return -1;
		}

		if (inst->groupmemb_query && 
		    inst->groupmemb_query[0]) {
			DEBUG("rlm_redisn: Registering redisn_groupcmp for %s",group_name);
			paircompare_register(dattr->attr, PW_USER_NAME, redisn_groupcmp, inst);
		}

		free(group_name);
	}
	if (xlat_name){
		inst->xlat_name = strdup(xlat_name);
		xlat_register(xlat_name, (RAD_XLAT_FUNC)redisn_xlat, inst);
	}

	if (inst->num_redisn_socks > MAX_REDISN_SOCKS) {
		radlog(L_ERR, "rlm_redisn (%s): redisn_instantiate: number of redis_sockets cannot exceed MAX_REDISN_SOCKS, %d",
		       inst->xlat_name, MAX_REDISN_SOCKS);
		rlm_redisn_detach(inst);
		return -1;
	}

	radlog(L_INFO, "rlm_redisn (%s): Attempting to connect to servers %s",
	       inst->xlat_name, 
	       inst->redisn_servers);

	if (redisn_init_socketpool(inst) < 0) {
		rlm_redisn_detach(inst);
		return -1;
	}

	if (inst->groupmemb_query && 
	    inst->groupmemb_query[0]) {
		paircompare_register(PW_REDIS_GROUP, PW_USER_NAME, redisn_groupcmp, inst);
	}

	if (inst->do_clients){
		if (generate_redisn_clients(inst) == -1){
			radlog(L_ERR, "Failed to load clients from REDISN.");
			rlm_redisn_detach(inst);
			return -1;
		}
	}
	allowed_chars = inst->allowed_chars;

	*instance = inst;

	return RLM_MODULE_OK;
}
/*
 *	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;
}
/*
 *	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_counter_t *inst = instance;
	DICT_ATTR const *da;
	DICT_VALUE *dval;
	ATTR_FLAGS flags;
	time_t now;
	int cache_size;
	int ret;
	datum key_datum;
	datum time_datum;
	char const *default1 = "DEFAULT1";
	char const *default2 = "DEFAULT2";

	cache_size = inst->cache_size;

	da = dict_attrbyname(inst->key_name);
	rad_assert(da != NULL);
	inst->key_attr = da;

	/*
	 *	Discover the attribute number of the counter.
	 */
	da = dict_attrbyname(inst->count_attribute);
	rad_assert(da != NULL);
	inst->count_attr = da;

	/*
	 * Discover the attribute number of the reply attribute.
	 */
	if (inst->reply_name != NULL) {
		da = dict_attrbyname(inst->reply_name);
		if (!da) {
			cf_log_err_cs(conf, "No such attribute %s", inst->reply_name);
			return -1;
		}
		if (da->type != PW_TYPE_INTEGER) {
			cf_log_err_cs(conf, "Reply attribute' %s' is not of type integer", inst->reply_name);
			return -1;
		}
		inst->reply_attr = da;
	} else {
		inst->reply_attr = NULL;
	}

	/*
	 *  Create a new attribute for the counter.
	 */
	rad_assert(inst->counter_name && *inst->counter_name);
	memset(&flags, 0, sizeof(flags));
	if (dict_addattr(inst->counter_name, -1, 0, PW_TYPE_INTEGER, flags) < 0) {
		ERROR("rlm_counter: Failed to create counter attribute %s: %s", inst->counter_name, fr_strerror());
		return -1;
	}

	da = dict_attrbyname(inst->counter_name);
	if (!da) {
		cf_log_err_cs(conf, "Failed to find counter attribute %s", inst->counter_name);
		return -1;
	}
	inst->dict_attr = da;
	DEBUG2("rlm_counter: Counter attribute %s is number %d", inst->counter_name, inst->dict_attr->attr);

	/*
	 * Create a new attribute for the check item.
	 */
	rad_assert(inst->check_name && *inst->check_name);
	if (dict_addattr(inst->check_name, -1, 0, PW_TYPE_INTEGER, flags) < 0) {
		ERROR("rlm_counter: Failed to create check attribute %s: %s", inst->counter_name, fr_strerror());
		return -1;

	}
	da = dict_attrbyname(inst->check_name);
	if (!da) {
		ERROR("rlm_counter: Failed to find check attribute %s", inst->counter_name);
		return -1;
	}
	inst->check_attr = da;

	/*
	 * Find the attribute for the allowed protocol
	 */
	if (inst->service_type != NULL) {
		if ((dval = dict_valbyname(PW_SERVICE_TYPE, 0, inst->service_type)) == NULL) {
			ERROR("rlm_counter: Failed to find attribute number for %s", inst->service_type);
			return -1;
		}
		inst->service_val = dval->value;
	}

	/*
	 * Find when to reset the database.
	 */
	rad_assert(inst->reset && *inst->reset);
	now = time(NULL);
	inst->reset_time = 0;
	inst->last_reset = now;

	if (find_next_reset(inst,now) == -1) {
		ERROR("rlm_counter: find_next_reset() returned -1. Exiting");
		return -1;
	}

	{
		char *filename;

		memcpy(&filename, &inst->filename, sizeof(filename));
		inst->gdbm = gdbm_open(filename, sizeof(int), GDBM_NEWDB | GDBM_COUNTER_OPTS, 0600, NULL);
	}
	if (!inst->gdbm) {
		ERROR("rlm_counter: Failed to open file %s: %s", inst->filename, fr_syserror(errno));
		return -1;
	}
	if (gdbm_setopt(inst->gdbm, GDBM_CACHESIZE, &cache_size, sizeof(cache_size)) == -1) {
		ERROR("rlm_counter: Failed to set cache size");
	}

	/*
	 * Look for the DEFAULT1 entry. This entry if it exists contains the
	 * time of the next database reset. This time is set each time we reset
	 * the database. If next_reset < now then we reset the database.
	 * That way we can overcome the problem where radiusd is down during a database
	 * reset time. If we did not keep state information in the database then the reset
	 * would be extended and that would create problems.
	 *
	 * We also store the time of the last reset in the DEFAULT2 entry.
	 *
	 * If DEFAULT1 and DEFAULT2 do not exist (new database) we add them to the database
	 */

	memcpy(&key_datum.dptr, &default1, sizeof(key_datum.dptr));
	key_datum.dsize = strlen(key_datum.dptr);

	time_datum = gdbm_fetch(inst->gdbm, key_datum);
	if (time_datum.dptr != NULL) {
		time_t next_reset = 0;

		memcpy(&next_reset, time_datum.dptr, sizeof(time_t));
		free(time_datum.dptr);
		time_datum.dptr = NULL;
		if (next_reset && next_reset <= now) {

			inst->last_reset = now;
			ret = reset_db(inst);
			if (ret != RLM_MODULE_OK) {
				ERROR("rlm_counter: reset_db() failed");
				return -1;
			}
		} else {
			inst->reset_time = next_reset;
		}

		memcpy(&key_datum.dptr, &default2, sizeof(key_datum.dptr));
		key_datum.dsize = strlen(key_datum.dptr);

		time_datum = gdbm_fetch(inst->gdbm, key_datum);
		if (time_datum.dptr != NULL) {
			memcpy(&inst->last_reset, time_datum.dptr, sizeof(time_t));
			free(time_datum.dptr);
		}
	} else {
		ret = add_defaults(inst);
		if (ret != RLM_MODULE_OK) {
			ERROR("rlm_counter: add_defaults() failed");
			return -1;
		}
	}


	/*
	 *	Register the counter comparison operation.
	 * FIXME: move all attributes to DA
	 */
	paircompare_register(inst->dict_attr, NULL, true, counter_cmp, inst);

	/*
	 * Init the mutex
	 */
	pthread_mutex_init(&inst->mutex, NULL);

	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));
	inst->cs = conf;

	/*
	 *	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;
	inst->sql_query = rlm_sql_query;
	inst->sql_select_query = rlm_sql_select_query;
	inst->sql_fetch_row = rlm_sql_fetch_row;

	/*
	 * 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);
	} else {
		char *group_name;
		DICT_ATTR *dattr;
		ATTR_FLAGS flags;

		/*
		 * Allocate room for <instance>-SQL-Group
		 */
		group_name = rad_malloc((strlen(xlat_name) + 1 + 11) * sizeof(char));
		sprintf(group_name,"%s-SQL-Group",xlat_name);
		DEBUG("rlm_sql Creating new attribute %s",group_name);

		memset(&flags, 0, sizeof(flags));
		dict_addattr(group_name, 0, PW_TYPE_STRING, -1, flags);
		dattr = dict_attrbyname(group_name);
		if (dattr == NULL){
			radlog(L_ERR, "rlm_sql: Failed to create attribute %s",group_name);
			free(group_name);
			free(inst);	/* FIXME: detach */
			return -1;
		}

		if (inst->config->groupmemb_query && 
		    inst->config->groupmemb_query[0]) {
			DEBUG("rlm_sql: Registering sql_groupcmp for %s",group_name);
			paircompare_register(dattr->attr, PW_USER_NAME, sql_groupcmp, inst);
		}

		free(group_name);
	}
	if (xlat_name){
		inst->config->xlat_name = strdup(xlat_name);
		xlat_register(xlat_name, (RAD_XLAT_FUNC)sql_xlat, inst);
	}

	/*
	 *	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;
	}

	if (inst->config->groupmemb_query && 
	    inst->config->groupmemb_query[0]) {
		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;
}
/*
 *	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 checkval_instantiate(CONF_SECTION *conf, void **instance)
{
	rlm_checkval_t *inst;
	const DICT_ATTR *da;
	ATTR_FLAGS flags;

	/*
	 *	Set up a storage area for instance data
	 */
	*instance = inst = talloc_zero(conf, rlm_checkval_t);
	if (!inst) {
		return -1;
	}

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

	/*
	 * Check if data_type exists
	 */
	if (!inst->data_type || !*inst->data_type){
		radlog(L_ERR, "rlm_checkval: Data type not defined");
		return -1;
	}

	if (!inst->item_name || !*inst->item_name){
		radlog(L_ERR, "rlm_checkval: Item name not defined");
		return -1;
	}

	if (!inst->check_name || !*inst->check_name){
		radlog(L_ERR, "rlm_checkval: Check item name not defined");
		return -1;
	}

	/*
	 *	Discover the attribute number of the item name
	 */
	da = dict_attrbyname(inst->item_name);
	if (!da) {
		radlog(L_ERR, "rlm_checkval: No such attribute %s",
		       inst->item_name);
		return -1;
	}
	inst->item = da;

	/*
	 *	Add the check attribute name to the dictionary
	 *	if it does not already exists. dict_addattr() handles that
	 */
	memset(&flags, 0, sizeof(flags));

	dict_addattr(inst->check_name, -1, 0, PW_TYPE_STRING, flags);
	da = dict_attrbyname(inst->check_name);
	if (!da){
		radlog(L_ERR, "rlm_checkval: No such attribute %s",
		       inst->check_name);
		return -1;
	}
	inst->check = da;
	DEBUG2("rlm_checkval: Registered name %s for attribute %d",
		da->name,da->attr);

	/*
	 *	Convert the string type to an integer type,
	 *	so we don't have to do string comparisons on each
	 *	packet.
	 */
	inst->type = fr_str2int(dict_attr_types, inst->data_type, 0);
	if (!inst->type) {
		radlog(L_ERR, "rlm_checkval: Data type %s in not known",
		       inst->data_type);
		return -1;
	}

	return 0;
}