Beispiel #1
0
static int parse_sub_section(CONF_SECTION *parent,
                             rlm_rest_section_t *config,
                             rlm_components_t comp)
{
    CONF_SECTION *cs;

    char const *name = section_type_value[comp].section;

    cs = cf_section_sub_find(parent, name);
    if (!cs) {
        /* TODO: Should really setup section with default values */
        return 0;
    }

    if (cf_section_parse(cs, config, section_config) < 0) {
        return -1;
    }

    /*
     *	Add section name (Maybe add to headers later?).
     */
    config->name = name;

    /*
     *	Convert HTTP method auth and body type strings into their
     *	integer equivalents.
     */
    config->auth = fr_str2int(http_auth_table, config->auth_str, HTTP_AUTH_UNKNOWN);
    if (config->auth == HTTP_AUTH_UNKNOWN) {
        cf_log_err_cs(cs, "Unknown HTTP auth type '%s'", config->auth_str);
        return -1;
    } else if ((config->auth != HTTP_AUTH_NONE) && !http_curl_auth[config->auth]) {
        cf_log_err_cs(cs, "Unsupported HTTP auth type \"%s\""
                      ", check libcurl version, OpenSSL build configuration,"
                      " then recompile this module",
                      config->auth_str);
        return -1;
    }

    config->method = fr_str2int(http_method_table, config->method_str,
                                HTTP_METHOD_CUSTOM);

    config->body = fr_str2int(http_body_type_table, config->body_str,
                              HTTP_BODY_UNKNOWN);

    if (config->body == HTTP_BODY_UNKNOWN) {
        cf_log_err_cs(cs, "Unknown HTTP body type '%s'",
                      config->body_str);
        return -1;
    }

    if (http_body_type_supported[config->body] == HTTP_BODY_UNSUPPORTED) {
        cf_log_err_cs(cs, "Unsupported HTTP body type \"%s\""
                      ", please submit patches",
                      config->body_str);
        return -1;
    }

    return 1;
}
/*
 *	Instantiate the module.
 */
static int mod_instantiate(CONF_SECTION *conf, void *instance)
{
	rlm_linelog_t *inst = instance;

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

#ifndef HAVE_SYSLOG_H
	if (strcmp(inst->filename, "syslog") == 0) {
		cf_log_err_cs(conf, "Syslog output is not supported on this system");
		return -1;
	}
#else
	inst->facility = 0;

	if (inst->syslog_facility) {
		inst->facility = fr_str2int(syslog_str2fac, inst->syslog_facility, -1);
		if (inst->facility < 0) {
			cf_log_err_cs(conf, "Invalid syslog facility '%s'",
				   inst->syslog_facility);
			return -1;
		}
	}

	inst->facility |= LOG_INFO;
#endif

	if (!inst->line) {
		cf_log_err_cs(conf, "Must specify a log format");
		return -1;
	}

	inst->cs = conf;
	return 0;
}
Beispiel #3
0
static int mod_instantiate(CONF_SECTION *conf, void *instance)
{
	struct rlm_realm_t *inst = instance;

	if (strcasecmp(inst->format_string, "suffix") == 0) {
		inst->format = REALM_FORMAT_SUFFIX;

	} else if (strcasecmp(inst->format_string, "prefix") == 0) {
		inst->format = REALM_FORMAT_PREFIX;

	} else {
		cf_log_err_cs(conf, "Invalid value \"%s\" for format",
			      inst->format_string);
		return -1;
	}

	if (strcmp(inst->delim, "\\\\") == 0) {
		/* it's OK */
	} else if (strlen(inst->delim) != 1) {
		cf_log_err_cs(conf, "Invalid value \"%s\" for delimiter",
			      inst->delim);
		return -1;
	}

#ifdef HAVE_TRUST_ROUTER_TR_DH_H
	/* initialize the trust router integration code */
	if (strcmp(inst->trust_router, "none") != 0) {
		if (!tr_init()) return -1;
	} else {
		rad_const_free(&inst->trust_router);
	}
#endif

	return 0;
}
/** Check if the magic number in the module matches the one in the library
 *
 * This is used to detect potential ABI issues caused by running with modules which
 * were built for a different version of the server.
 *
 * @param cs being parsed.
 * @param module being loaded.
 * @returns 0 on success, -1 if prefix mismatch, -2 if version mismatch, -3 if commit mismatch.
 */
static int check_module_magic(CONF_SECTION *cs, module_t const *module)
{
	if (MAGIC_PREFIX(module->magic) != MAGIC_PREFIX(RADIUSD_MAGIC_NUMBER)) {
		cf_log_err_cs(cs, "Application and rlm_%s magic number (prefix) mismatch."
			      "  application: %x module: %x", module->name,
			      MAGIC_PREFIX(RADIUSD_MAGIC_NUMBER),
			      MAGIC_PREFIX(module->magic));
		return -1;
	}

	if (MAGIC_VERSION(module->magic) != MAGIC_VERSION(RADIUSD_MAGIC_NUMBER)) {
		cf_log_err_cs(cs, "Application and rlm_%s magic number (version) mismatch."
			      "  application: %lx module: %lx", module->name,
			      (unsigned long) MAGIC_VERSION(RADIUSD_MAGIC_NUMBER),
			      (unsigned long) MAGIC_VERSION(module->magic));
		return -2;
	}

	if (MAGIC_COMMIT(module->magic) != MAGIC_COMMIT(RADIUSD_MAGIC_NUMBER)) {
		cf_log_err_cs(cs, "Application and rlm_%s magic number (commit) mismatch."
			      "  application: %lx module: %lx", module->name,
			      (unsigned long) MAGIC_COMMIT(RADIUSD_MAGIC_NUMBER),
			      (unsigned long) MAGIC_COMMIT(module->magic));
		return -3;
	}

	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)
{
	module_instance_t *sqlinst;
	rlm_sqlippool_t *inst = instance;
	char const *pool_name = NULL;

	pool_name = cf_section_name2(conf);
	if (pool_name != NULL) {
		inst->pool_name = talloc_typed_strdup(inst, pool_name);
	} else {
		inst->pool_name = talloc_typed_strdup(inst, "ippool");
	}
	sqlinst = find_module_instance(cf_section_find("modules"),
				       inst->sql_instance_name, 1);
	if (!sqlinst) {
		cf_log_err_cs(conf, "failed to find sql instance named %s",
			   inst->sql_instance_name);
		return -1;
	}

	if (strcmp(sqlinst->entry->name, "rlm_sql") != 0) {
		cf_log_err_cs(conf, "Module \"%s\""
		       " is not an instance of the rlm_sql module",
		       inst->sql_instance_name);
		return -1;
	}

	inst->sql_inst = (rlm_sql_t *) sqlinst->insthandle;
	return 0;
}
/*
 *	Convert a buffer to a CSV entry
 */
static rlm_csv_entry_t *file2csv(CONF_SECTION *conf, rlm_csv_t *inst, int lineno, char *buffer)
{
	rlm_csv_entry_t *e;
	int i;
	char *p, *q;

	e = (rlm_csv_entry_t *) talloc_zero_array(inst->tree, uint8_t, sizeof(*e) + inst->used_fields + sizeof(e->data[0]));
	if (!e) {
		cf_log_err_cs(conf, "Out of memory");
		return NULL;
	}

	for (p = buffer, i = 0; p != NULL; p = q, i++) {
		if (!buf2entry(inst, p, &q)) {
			cf_log_err_cs(conf, "Malformed entry in file %s line %d", inst->filename, lineno);
			return NULL;
		}

		if (q) *(q++) = '\0';

		if (i >= inst->num_fields) {
			cf_log_err_cs(conf, "Too many fields at file %s line %d", inst->filename, lineno);
			return NULL;
		}

		/*
		 *	This is the key field.
		 */
		if (i == inst->key_field) {
			e->key = talloc_strdup(e, p);
			continue;
		}

		/*
		 *	This field is unused.  Ignore it.
		 */
		if (inst->field_offsets[i] < 0) continue;

		e->data[inst->field_offsets[i]] = talloc_strdup(e, p);
	}

	if (i < inst->num_fields) {
		cf_log_err_cs(conf, "Too few fields at file %s line %d (%d < %d)", inst->filename, lineno, i, inst->num_fields);
		return NULL;
	}

	/*
	 *	FIXME: Allow duplicate keys later.
	 */
	if (!rbtree_insert(inst->tree, e)) {
		cf_log_err_cs(conf, "Failed inserting entry for filename %s line %d: duplicate entry",
			      inst->filename, lineno);
		return NULL;
	}

	return e;
}
/*
 *	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;
}
static int mod_instantiate (CONF_SECTION *cs, void **instance)
{
	eap_pwd_t *inst;

	*instance = inst = talloc_zero(cs, eap_pwd_t);
	if (!inst) return -1;

	if (cf_section_parse(cs, inst, pwd_module_config) < 0) return -1;

	if (inst->fragment_size < 100) {
		cf_log_err_cs(cs, "Fragment size is too small");
		return -1;
	}

	if ((inst->bnctx = BN_CTX_new()) == NULL) {
		cf_log_err_cs(cs, "Failed to get BN context");
		return -1;
	}

	return 0;
}
Beispiel #9
0
/*
 *	Instantiate the module.
 */
static int mod_instantiate(CONF_SECTION *conf, void *instance)
{
    rlm_linelog_t *inst = instance;
    int num;

    if (!inst->filename) {
        cf_log_err_cs(conf, "No value provided for 'filename'");
        return -1;
    }

    /*
     *	Escape filenames only if asked.
     */
    if (inst->escape) {
        inst->escape_func = rad_filename_escape;
    } else {
        inst->escape_func = rad_filename_make_safe;
    }

#ifndef HAVE_SYSLOG_H
    if (strcmp(inst->filename, "syslog") == 0) {
        cf_log_err_cs(conf, "Syslog output is not supported on this system");
        return -1;
    }
#else

    if (inst->syslog_facility) {
        num = fr_str2int(syslog_facility_table, inst->syslog_facility, -1);
        if (num < 0) {
            cf_log_err_cs(conf, "Invalid syslog facility \"%s\"", inst->syslog_facility);
            return -1;
        }

        inst->syslog_priority |= num;
    }

    num = fr_str2int(syslog_severity_table, inst->syslog_severity, -1);
    if (num < 0) {
        cf_log_err_cs(conf, "Invalid syslog severity \"%s\"", inst->syslog_severity);
        return -1;
    }
    inst->syslog_priority |= num;
#endif

    if (!inst->line && !inst->reference) {
        cf_log_err_cs(conf, "Must specify a log format, or reference");
        return -1;
    }

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

    inst->cs = conf;
    return 0;
}
Beispiel #10
0
static int mod_instantiate(CONF_SECTION *conf, void *instance)
{
	struct realm_config_t *inst = instance;

	if (strcasecmp(inst->formatstring, "suffix") == 0) {
	     inst->format = REALM_FORMAT_SUFFIX;

	} else if (strcasecmp(inst->formatstring, "prefix") == 0) {
	     inst->format = REALM_FORMAT_PREFIX;

	} else {
		cf_log_err_cs(conf, "Invalid value \"%s\" for format",
			      inst->formatstring);
	     return -1;
	}

	if (strlen(inst->delim) != 1) {
		cf_log_err_cs(conf, "Invalid value \"%s\" for delimiter",
			      inst->delim);
	     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 mod_instantiate(CONF_SECTION *conf, void *instance)
{
    rlm_logintime_t *inst = instance;

    if (inst->min_time == 0) {
        cf_log_err_cs(conf, "Invalid value '0' for minimum-timeout");
        return -1;
    }

    /*
     * Register a Current-Time comparison function
     */
    paircompare_register(PW_CURRENT_TIME, 0, timecmp, inst);
    paircompare_register(PW_TIME_OF_DAY, 0, time_of_day, inst);

    return 0;
}
/**
 * Instantiate module.
 * @param[in] conf Module config.
 * @param[in] instance Module instance.
 * @return Zero on success.
 */
static int mod_instantiate(CONF_SECTION *conf, void *instance) {
  rlm_mongodb_t *inst = instance;

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

  if (!strcasecmp(inst->cfg.action, "get")) {
    inst->action = RLM_MONGODB_GET;
    cf_log_err_cs(conf, "action 'get' is not implemented");
    goto err;
  } else if (!strcasecmp(inst->cfg.action, "set")) {
    inst->action = RLM_MONGODB_SET;
  } else {
    cf_log_err_cs(conf, "invalid 'action', use'get' or 'set'");
    goto err;
  }

  if (inst->cfg.remove && inst->cfg.update_query) {
    cf_log_err_cs(conf, "'update_query' and 'remove' can't be used at the same time");
    goto err;
  } else if (!inst->cfg.remove && !inst->cfg.update_query) {
    cf_log_err_cs(conf, "'update_query' or 'remove' must be set for 'set' action");
    goto err;
  }

  if (!cf_pair_find(conf, "pool")) {
    if (!inst->cfg.server) {
      cf_log_err_cs(conf, "Invalid or missing 'server' option");
      goto err;
    }
  } else {
    if (inst->cfg.server) {
      cf_log_err_cs(conf, "Can't use server option when foreign connection pool specified");
      goto err;
    }
  }

  mongoc_init();
  mongoc_log_set_handler(mongoc_log_handler, inst);

  inst->pool = fr_connection_pool_module_init(conf, inst, mod_conn_create, NULL, inst->name);
  if (!inst->pool) {
    goto err;
  }

  return 0;

  err:
  return -1;
}
static int mod_instantiate(CONF_SECTION *conf, void *instance)
{
	rlm_sometimes_t *inst = instance;

	/*
	 *	Convert the rcode string to an int, and get rid of it
	 */
	inst->rcode = fr_str2int(mod_rcode_table, inst->rcode_str, RLM_MODULE_UNKNOWN);
	if (inst->rcode == RLM_MODULE_UNKNOWN) {
		cf_log_err_cs(conf, "Unknown module return code '%s'", inst->rcode_str);
		return -1;
	}

	inst->da = dict_attrbyname(inst->key);
	rad_assert(inst->da);

	return 0;
}
Beispiel #14
0
static int mod_instantiate(CONF_SECTION *conf, void *instance)
{
	rlm_always_t *inst = instance;

	inst->name = cf_section_name1(conf);
	if (!inst->name) inst->name = cf_section_name2(conf);
	/*
	 *	Convert the rcode string to an int
	 */
	inst->rcode = fr_str2int(mod_rcode_table, inst->rcode_str, RLM_MODULE_UNKNOWN);
	if (inst->rcode == RLM_MODULE_UNKNOWN) {
		cf_log_err_cs(conf, "rcode value \"%s\" is invalid", inst->rcode_str);
		return -1;
	}
	inst->rcode_old = NULL;	/* Hack - forces the compiler not to optimise away rcode_old */

	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_smsotp_t *inst = instance;
	struct sockaddr_un sa;
	if (strlen(inst->socket) > (sizeof(sa.sun_path) - 1)) {
		cf_log_err_cs(conf, "Socket filename is too long");
		return -1;
	}

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

	return 0;
}
Beispiel #16
0
/** Parse module's configuration section and setup destructors
 *
 */
static int module_conf_parse(module_instance_t *node, void **handle)
{
	*handle = NULL;

	/*
	 *	If there is supposed to be instance data, allocate it now.
	 *	Also parse the configuration data, if required.
	 */
	if (node->entry->module->inst_size) {
		/* FIXME: make this rlm_config_t ?? */
		*handle = talloc_zero_array(node, uint8_t, node->entry->module->inst_size);
		rad_assert(handle);

		/*
		 *	So we can see where this configuration is from
		 *	FIXME: set it to rlm_NAME_t, or some such thing
		 */
		talloc_set_name(*handle, "rlm_config_t");

		if (node->entry->module->config &&
		    (cf_section_parse(node->cs, *handle, node->entry->module->config) < 0)) {
			cf_log_err_cs(node->cs,"Invalid configuration for module \"%s\"", node->name);
			talloc_free(*handle);

			return -1;
		}

		/*
		 *	Set the destructor.
		 */
		if (node->entry->module->detach) {
			talloc_set_destructor((void *) *handle, node->entry->module->detach);
		}
	}

	return 0;
}
Beispiel #17
0
/** Check if the magic number in the module matches the one in the library
 *
 * This is used to detect potential ABI issues caused by running with modules which
 * were built for a different version of the server.
 *
 * @param cs being parsed.
 * @param module being loaded.
 * @returns
 *	- 0 on success.
 *	- -1 if prefix mismatch.
 *	- -2 if version mismatch.
 *	- -3 if commit mismatch.
 */
static int check_module_magic(CONF_SECTION *cs, module_t const *module)
{
#ifdef HAVE_DLADDR
	Dl_info dl_info;
	dladdr(module, &dl_info);
#endif

	if (MAGIC_PREFIX(module->magic) != MAGIC_PREFIX(RADIUSD_MAGIC_NUMBER)) {
#ifdef HAVE_DLADDR
		cf_log_err_cs(cs, "Failed loading module rlm_%s from file %s", module->name, dl_info.dli_fname);
#endif
		cf_log_err_cs(cs, "Application and rlm_%s magic number (prefix) mismatch."
			      "  application: %x module: %x", module->name,
			      MAGIC_PREFIX(RADIUSD_MAGIC_NUMBER),
			      MAGIC_PREFIX(module->magic));
		return -1;
	}

	if (MAGIC_VERSION(module->magic) != MAGIC_VERSION(RADIUSD_MAGIC_NUMBER)) {
#ifdef HAVE_DLADDR
		cf_log_err_cs(cs, "Failed loading module rlm_%s from file %s", module->name, dl_info.dli_fname);
#endif
		cf_log_err_cs(cs, "Application and rlm_%s magic number (version) mismatch."
			      "  application: %lx module: %lx", module->name,
			      (unsigned long) MAGIC_VERSION(RADIUSD_MAGIC_NUMBER),
			      (unsigned long) MAGIC_VERSION(module->magic));
		return -2;
	}

	if (MAGIC_COMMIT(module->magic) != MAGIC_COMMIT(RADIUSD_MAGIC_NUMBER)) {
#ifdef HAVE_DLADDR
		cf_log_err_cs(cs, "Failed loading module rlm_%s from file %s", module->name, dl_info.dli_fname);
#endif
		cf_log_err_cs(cs, "Application and rlm_%s magic number (commit) mismatch."
			      "  application: %lx module: %lx", module->name,
			      (unsigned long) MAGIC_COMMIT(RADIUSD_MAGIC_NUMBER),
			      (unsigned long) MAGIC_COMMIT(module->magic));
		return -3;
	}

	return 0;
}
Beispiel #18
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;
}
Beispiel #19
0
static int parse_sub_section(CONF_SECTION *parent, rlm_rest_section_t *config, rlm_components_t comp)
{
	CONF_SECTION *cs;

	char const *name = section_type_value[comp].section;

	cs = cf_section_sub_find(parent, name);
	if (!cs) {
		config->name = NULL;
		return 0;
	}

	if (cf_section_parse(cs, config, section_config) < 0) {
		config->name = NULL;
		return -1;
	}

	/*
	 *  Add section name (Maybe add to headers later?).
	 */
	config->name = name;

	/*
	 *  Sanity check
	 */
	 if ((config->username && !config->password) || (!config->username && config->password)) {
		cf_log_err_cs(cs, "'username' and 'password' must both be set or both be absent");

		return -1;
	 }

	/*
	 *  Convert HTTP method auth and body type strings into their integer equivalents.
	 */
	config->auth = fr_str2int(http_auth_table, config->auth_str, HTTP_AUTH_UNKNOWN);
	if (config->auth == HTTP_AUTH_UNKNOWN) {
		cf_log_err_cs(cs, "Unknown HTTP auth type '%s'", config->auth_str);

		return -1;
	} else if ((config->auth != HTTP_AUTH_NONE) && !http_curl_auth[config->auth]) {
		cf_log_err_cs(cs, "Unsupported HTTP auth type \"%s\", check libcurl version, OpenSSL build "
			      "configuration, then recompile this module", config->auth_str);

		return -1;
	}

	config->method = fr_str2int(http_method_table, config->method_str, HTTP_METHOD_CUSTOM);

	/*
	 *  We don't have any custom user data, so we need to select the right encoder based
	 *  on the body type.
	 *
	 *  To make this slightly more/less confusing, we accept both canonical body_types,
	 *  and content_types.
	 */
	if (!config->data) {
		config->body = fr_str2int(http_body_type_table, config->body_str, HTTP_BODY_UNKNOWN);
		if (config->body == HTTP_BODY_UNKNOWN) {
			config->body = fr_str2int(http_content_type_table, config->body_str, HTTP_BODY_UNKNOWN);
		}

		if (config->body == HTTP_BODY_UNKNOWN) {
			cf_log_err_cs(cs, "Unknown HTTP body type '%s'", config->body_str);
			return -1;
		}

		switch (http_body_type_supported[config->body]) {
		case HTTP_BODY_UNSUPPORTED:
			cf_log_err_cs(cs, "Unsupported HTTP body type \"%s\", please submit patches",
				      config->body_str);
			return -1;

		case HTTP_BODY_INVALID:
			cf_log_err_cs(cs, "Invalid HTTP body type.  \"%s\" is not a valid web API data "
				      "markup format", config->body_str);
			return -1;

		default:
			break;
		}
	/*
	 *  We have custom body data so we set HTTP_BODY_CUSTOM_XLAT, but also need to try and
	 *  figure out what content-type to use. So if they've used the canonical form we
	 *  need to convert it back into a proper HTTP content_type value.
	 */
	} else {
		http_body_type_t body;

		config->body = HTTP_BODY_CUSTOM_XLAT;

		body = fr_str2int(http_body_type_table, config->body_str, HTTP_BODY_UNKNOWN);
		if (body != HTTP_BODY_UNKNOWN) {
			config->body_str = fr_int2str(http_content_type_table, body, config->body_str);
		}
	}

	if (config->force_to_str) {
		config->force_to = fr_str2int(http_body_type_table, config->force_to_str, HTTP_BODY_UNKNOWN);
		if (config->force_to == HTTP_BODY_UNKNOWN) {
			config->force_to = fr_str2int(http_content_type_table, config->force_to_str, HTTP_BODY_UNKNOWN);
		}

		if (config->force_to == HTTP_BODY_UNKNOWN) {
			cf_log_err_cs(cs, "Unknown forced response body type '%s'", config->force_to_str);
			return -1;
		}

		switch (http_body_type_supported[config->force_to]) {
		case HTTP_BODY_UNSUPPORTED:
			cf_log_err_cs(cs, "Unsupported forced response body type \"%s\", please submit patches",
				      config->force_to_str);
			return -1;

		case HTTP_BODY_INVALID:
			cf_log_err_cs(cs, "Invalid HTTP forced response body type.  \"%s\" is not a valid web API data "
				      "markup format", config->force_to_str);
			return -1;

		default:
			break;
		}
	}

	return 0;
}
Beispiel #20
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)
{
	char const *p;
	rlm_exec_t	*inst = instance;

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

	xlat_register(inst->xlat_name, exec_xlat, rlm_exec_shell_escape, inst);

	if (inst->input) {
		p = inst->input;
		inst->input_list = radius_list_name(&p, PAIR_LIST_UNKNOWN);
		if ((inst->input_list == PAIR_LIST_UNKNOWN) || (*p != '\0')) {
			cf_log_err_cs(conf, "Invalid input list '%s'", inst->input);
			return -1;
		}
	}

	if (inst->output) {
		p = inst->output;
		inst->output_list = radius_list_name(&p, PAIR_LIST_UNKNOWN);
		if ((inst->output_list == PAIR_LIST_UNKNOWN) || (*p != '\0')) {
			cf_log_err_cs(conf, "Invalid output list '%s'", inst->output);
			return -1;
		}
	}

	/*
	 *	Sanity check the config.  If we're told to NOT wait,
	 *	then the output pairs must not be defined.
	 */
	if (!inst->wait &&
	    (inst->output != NULL)) {
		cf_log_err_cs(conf, "Cannot read output pairs if wait = no");
		return -1;
	}

	/*
	 *	Get the packet type on which to execute
	 */
	if (!inst->packet_type) {
		inst->packet_code = 0;
	} else {
		DICT_VALUE	*dval;

		dval = dict_valbyname(PW_PACKET_TYPE, 0, inst->packet_type);
		if (!dval) {
			cf_log_err_cs(conf, "Unknown packet type %s: See list of VALUEs for Packet-Type in "
				      "share/dictionary", inst->packet_type);
			return -1;
		}
		inst->packet_code = dval->value;
	}

	/*
	 *	Get the time to wait before killing the child
	 */
	if (!inst->timeout) {
		inst->timeout = EXEC_TIMEOUT;
	}
	if (inst->timeout < 1) {
		cf_log_err_cs(conf, "Timeout '%d' is too small (minimum: 1)", inst->timeout);
		return -1;
	}
	/*
	 *	Blocking a request longer than 30 seconds isn't going to help anyone.
	 */
	if (inst->timeout > 30) {
		cf_log_err_cs(conf, "Timeout '%d' is too large (maximum: 30)", inst->timeout);
		return -1;
	}

	return 0;
}
Beispiel #21
0
/*
 *	Find a module instance.
 */
module_instance_t *find_module_instance(CONF_SECTION *modules,
					char const *askedname, int do_link)
{
	int check_config_safe = false;
	CONF_SECTION *cs;
	char const *name1, *instname;
	module_instance_t *node, myNode;
	char module_name[256];

	if (!modules) return NULL;

	/*
	 *	Look for the real name.  Ignore the first character,
	 *	which tells the server "it's OK for this module to not
	 *	exist."
	 */
	instname = askedname;
	if (instname[0] == '-') {
		instname++;
	}

	/*
	 *	Module instances are declared in the modules{} block
	 *	and referenced later by their name, which is the
	 *	name2 from the config section, or name1 if there was
	 *	no name2.
	 */
	cs = cf_section_sub_find_name2(modules, NULL, instname);
	if (!cs) {
		ERROR("Cannot find a configuration entry for module \"%s\"", instname);
		return NULL;
	}

	/*
	 *	If there's already a module instance, return it.
	 */
	strlcpy(myNode.name, instname, sizeof(myNode.name));

	node = rbtree_finddata(instance_tree, &myNode);
	if (node) {
		return node;
	}

	if (!do_link) {
		return NULL;
	}

	name1 = cf_section_name1(cs);

	/*
	 *	Found the configuration entry, hang the node struct off of the
	 *	configuration section. If the CS is free'd the instance will
	 *	be too.
	 */
	node = talloc_zero(cs, module_instance_t);
	node->cs = cs;

	/*
	 *	Names in the "modules" section aren't prefixed
	 *	with "rlm_", so we add it here.
	 */
	snprintf(module_name, sizeof(module_name), "rlm_%s", name1);

	/*
	 *	Pull in the module object
	 */
	node->entry = linkto_module(module_name, cs);
	if (!node->entry) {
		talloc_free(node);
		/* linkto_module logs any errors */
		return NULL;
	}

	if (check_config && (node->entry->module->instantiate) &&
	    (node->entry->module->type & RLM_TYPE_CHECK_CONFIG_SAFE) == 0) {
		char const *value = NULL;
		CONF_PAIR *cp;

		cp = cf_pair_find(cs, "force_check_config");
		if (cp) {
			value = cf_pair_value(cp);
		}

		if (value && (strcmp(value, "yes") == 0)) goto print_inst;

		cf_log_module(cs, "Skipping instantiation of %s", instname);
	} else {
	print_inst:
		check_config_safe = true;
		cf_log_module(cs, "Instantiating module \"%s\" from file %s", instname,
			      cf_section_filename(cs));
	}

	strlcpy(node->name, instname, sizeof(node->name));

	/*
	 *	Parse the module configuration, and setup destructors so the
	 *	module's detach method is called when it's instance data is
	 *	about to be freed.
	 */
	if (module_conf_parse(node, &node->insthandle) < 0) {
		talloc_free(node);

		return NULL;
	}

	/*
	 *	Call the module's instantiation routine.
	 */
	if ((node->entry->module->instantiate) &&
	    (!check_config || check_config_safe) &&
	    ((node->entry->module->instantiate)(cs, node->insthandle) < 0)) {
		cf_log_err_cs(cs, "Instantiation failed for module \"%s\"", node->name);
		talloc_free(node);

		return NULL;
	}

#ifdef HAVE_PTHREAD_H
	/*
	 *	If we're threaded, check if the module is thread-safe.
	 *
	 *	If it isn't, we create a mutex.
	 */
	if ((node->entry->module->type & RLM_TYPE_THREAD_UNSAFE) != 0) {
		node->mutex = talloc_zero(node, pthread_mutex_t);

		/*
		 *	Initialize the mutex.
		 */
		pthread_mutex_init(node->mutex, NULL);
	} else {
		/*
		 *	The module is thread-safe.  Don't give it a mutex.
		 */
		node->mutex = NULL;
	}

#endif
	rbtree_insert(instance_tree, node);

	return node;
}
Beispiel #22
0
/*
 *	Find a module on disk or in memory, and link to it.
 */
static module_entry_t *linkto_module(char const *module_name,
				     CONF_SECTION *cs)
{
	module_entry_t myentry;
	module_entry_t *node;
	void *handle = NULL;
	const module_t *module;

	strlcpy(myentry.name, module_name, sizeof(myentry.name));
	node = rbtree_finddata(module_tree, &myentry);
	if (node) return node;

	/*
	 *	Link to the module's rlm_FOO{} structure, the same as
	 *	the module name.
	 */

#if !defined(WITH_LIBLTDL) && defined(HAVE_DLFCN_H) && defined(RTLD_SELF)
	module = dlsym(RTLD_SELF, module_name);
	if (module) goto open_self;
#endif

	/*
	 *	Keep the handle around so we can dlclose() it.
	 */
	handle = lt_dlopenext(module_name);
	if (!handle) {
		cf_log_err_cs(cs,
			   "Failed to link to module '%s': %s\n",
			   module_name, dlerror());
		return NULL;
	}

	DEBUG3("    (Loaded %s, checking if it's valid)", module_name);

	/*
	 *	libltld MAY core here, if the handle it gives us contains
	 *	garbage data.
	 */
	module = dlsym(handle, module_name);
	if (!module) {
		cf_log_err_cs(cs,
			   "Failed linking to %s structure: %s\n",
			   module_name, dlerror());
		dlclose(handle);
		return NULL;
	}

#if !defined(WITH_LIBLTDL) && defined (HAVE_DLFCN_H) && defined(RTLD_SELF)
 open_self:
#endif
	/*
	 *	Before doing anything else, check if it's sane.
	 */
	if (module->magic != RLM_MODULE_MAGIC_NUMBER) {
		dlclose(handle);
		cf_log_err_cs(cs,
			   "Invalid version in module '%s'",
			   module_name);
		return NULL;

	}

	/* make room for the module type */
	node = talloc_zero(cs, module_entry_t);
	talloc_set_destructor((void *) node, module_entry_free);
	strlcpy(node->name, module_name, sizeof(node->name));
	node->module = module;
	node->handle = handle;

	cf_log_module(cs, "Loaded module %s", module_name);

	/*
	 *	Add the module as "rlm_foo-version" to the configuration
	 *	section.
	 */
	if (!rbtree_insert(module_tree, node)) {
		ERROR("Failed to cache module %s", module_name);
		dlclose(handle);
		talloc_free(node);
		return NULL;
	}

	return node;
}
Beispiel #23
0
/*
 *	(Re-)read radiusd.conf into memory.
 */
static int mod_instantiate(CONF_SECTION *conf, void *instance)
{
	detail_instance_t *inst = instance;
	CONF_SECTION	*cs;

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

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

	/*
	 *	Suppress certain attributes.
	 */
	cs = cf_section_sub_find(conf, "suppress");
	if (cs) {
		CONF_ITEM	*ci;

		inst->ht = fr_hash_table_create(detail_hash, detail_cmp, NULL);

		for (ci = cf_item_find_next(cs, NULL);
		     ci != NULL;
		     ci = cf_item_find_next(cs, ci)) {
			char const	*attr;
			DICT_ATTR const	*da;

			if (!cf_item_is_pair(ci)) continue;

			attr = cf_pair_attr(cf_itemtopair(ci));
			if (!attr) continue; /* pair-anoia */

			da = dict_attrbyname(attr);
			if (!da) {
				cf_log_err_cs(conf, "No such attribute '%s'", attr);
				return -1;
			}

			/*
			 *	Be kind to minor mistakes.
			 */
			if (fr_hash_table_finddata(inst->ht, da)) {
				WARN("rlm_detail (%s): Ignoring duplicate entry '%s'", inst->name, attr);
				continue;
			}


			if (!fr_hash_table_insert(inst->ht, da)) {
				ERROR("rlm_detail (%s): Failed inserting '%s' into suppression table",
				      inst->name, attr);
				return -1;
			}

			DEBUG("rlm_detail (%s): '%s' suppressed, will not appear in detail output", inst->name, attr);
		}

		/*
		 *	If we didn't suppress anything, delete the hash table.
		 */
		if (fr_hash_table_num_elements(inst->ht) == 0) {
			fr_hash_table_free(inst->ht);
			inst->ht = NULL;
		}
	}

	return 0;
}
Beispiel #24
0
/** Allocate a new client from a config section
 *
 * @param ctx to allocate new clients in.
 * @param cs to process as a client.
 * @param in_server Whether the client should belong to a specific virtual server.
 * @param with_coa If true and coa_server or coa_pool aren't specified automatically,
 *	create a coa home_server section and add it to the client CONF_SECTION.
 * @return new RADCLIENT struct.
 */
RADCLIENT *client_afrom_cs(TALLOC_CTX *ctx, CONF_SECTION *cs, bool in_server, bool with_coa)
{
	RADCLIENT	*c;
	char const	*name2;

	name2 = cf_section_name2(cs);
	if (!name2) {
		cf_log_err_cs(cs, "Missing client name");
		return NULL;
	}

	/*
	 *	The size is fine.. Let's create the buffer
	 */
	c = talloc_zero(ctx, RADCLIENT);
	c->cs = cs;

	memset(&cl_ipaddr, 0, sizeof(cl_ipaddr));
	if (cf_section_parse(cs, c, client_config) < 0) {
		cf_log_err_cs(cs, "Error parsing client section");
	error:
		client_free(c);
#ifdef WITH_TCP
		hs_proto = NULL;
		cl_srcipaddr = NULL;
#endif

		return NULL;
	}

	/*
	 *	Global clients can set servers to use, per-server clients cannot.
	 */
	if (in_server && c->server) {
		cf_log_err_cs(cs, "Clients inside of an server section cannot point to a server");
		goto error;
	}

	/*
	 *	Newer style client definitions with either ipaddr or ipaddr6
	 *	config items.
	 */
	if (cf_pair_find(cs, "ipaddr") || cf_pair_find(cs, "ipv4addr") || cf_pair_find(cs, "ipv6addr")) {
		char buffer[128];

		/*
		 *	Sets ipv4/ipv6 address and prefix.
		 */
		c->ipaddr = cl_ipaddr;

		/*
		 *	Set the long name to be the result of a reverse lookup on the IP address.
		 */
		ip_ntoh(&c->ipaddr, buffer, sizeof(buffer));
		c->longname = talloc_typed_strdup(c, buffer);

		/*
		 *	Set the short name to the name2.
		 */
		if (!c->shortname) c->shortname = talloc_typed_strdup(c, name2);
	/*
	 *	No "ipaddr" or "ipv6addr", use old-style "client <ipaddr> {" syntax.
	 */
	} else {
		cf_log_err_cs(cs, "No 'ipaddr' or 'ipv4addr' or 'ipv6addr' configuration "
			      "directive found in client %s", name2);
		goto error;
	}

	c->proto = IPPROTO_UDP;
	if (hs_proto) {
		if (strcmp(hs_proto, "udp") == 0) {
			hs_proto = NULL;

#ifdef WITH_TCP
		} else if (strcmp(hs_proto, "tcp") == 0) {
			hs_proto = NULL;
			c->proto = IPPROTO_TCP;
#  ifdef WITH_TLS
		} else if (strcmp(hs_proto, "tls") == 0) {
			hs_proto = NULL;
			c->proto = IPPROTO_TCP;
			c->tls_required = true;

		} else if (strcmp(hs_proto, "radsec") == 0) {
			hs_proto = NULL;
			c->proto = IPPROTO_TCP;
			c->tls_required = true;
#  endif
		} else if (strcmp(hs_proto, "*") == 0) {
			hs_proto = NULL;
			c->proto = IPPROTO_IP; /* fake for dual */
#endif
		} else {
			cf_log_err_cs(cs, "Unknown proto \"%s\".", hs_proto);
			goto error;
		}
	}

	/*
	 *	If a src_ipaddr is specified, when we send the return packet
	 *	we will use this address instead of the src from the
	 *	request.
	 */
	if (cl_srcipaddr) {
#ifdef WITH_UDPFROMTO
		switch (c->ipaddr.af) {
		case AF_INET:
			if (fr_pton4(&c->src_ipaddr, cl_srcipaddr, -1, true, false) < 0) {
				cf_log_err_cs(cs, "Failed parsing src_ipaddr: %s", fr_strerror());
				goto error;
			}
			break;

		case AF_INET6:
			if (fr_pton6(&c->src_ipaddr, cl_srcipaddr, -1, true, false) < 0) {
				cf_log_err_cs(cs, "Failed parsing src_ipaddr: %s", fr_strerror());
				goto error;
			}
			break;
		default:
			rad_assert(0);
		}
#else
		WARN("Server not built with udpfromto, ignoring client src_ipaddr");
#endif
		cl_srcipaddr = NULL;
	}

	/*
	 *	A response_window of zero is OK, and means that it's
	 *	ignored by the rest of the server timers.
	 */
	if (timerisset(&c->response_window)) {
		FR_TIMEVAL_BOUND_CHECK("response_window", &c->response_window, >=, 0, 1000);
		FR_TIMEVAL_BOUND_CHECK("response_window", &c->response_window, <=, 60, 0);
		FR_TIMEVAL_BOUND_CHECK("response_window", &c->response_window, <=, main_config.max_request_time, 0);
	}
Beispiel #25
0
/** Create a client CONF_SECTION using a mapping section to map values from a result set to client attributes
 *
 * If we hit a CONF_SECTION we recurse and process its CONF_PAIRS too.
 *
 * @note Caller should free CONF_SECTION passed in as out, on error.
 *	 Contents of that section will be in an undefined state.
 *
 * @param[in,out] out Section to perform mapping on. Either the root of the client config, or a parent section
 *	(when this function is called recursively).
 *	Should be alloced with cf_section_alloc, or if there's a separate template section, the
 *	result of calling cf_section_dup on that section.
 * @param[in] map section.
 * @param[in] func to call to retrieve CONF_PAIR values. Must return a talloced buffer containing the value.
 * @param[in] data to pass to func, usually a result pointer.
 * @return 0 on success else -1 on error.
 */
int client_map_section(CONF_SECTION *out, CONF_SECTION const *map, client_value_cb_t func, void *data)
{
	CONF_ITEM const *ci;

	for (ci = cf_item_find_next(map, NULL);
	     ci != NULL;
	     ci = cf_item_find_next(map, ci)) {
	     	CONF_PAIR const *cp;
	     	CONF_PAIR *old;
	     	char *value;
		char const *attr;

		/*
		 *	Recursively process map subsection
		 */
		if (cf_item_is_section(ci)) {
			CONF_SECTION *cs, *cc;

			cs = cf_item_to_section(ci);
			/*
			 *	Use pre-existing section or alloc a new one
			 */
			cc = cf_section_sub_find_name2(out, cf_section_name1(cs), cf_section_name2(cs));
			if (!cc) {
				cc = cf_section_alloc(out, cf_section_name1(cs), cf_section_name2(cs));
				cf_section_add(out, cc);
				if (!cc) return -1;
			}

			if (client_map_section(cc, cs, func, data) < 0) return -1;
			continue;
		}

		cp = cf_item_to_pair(ci);
		attr = cf_pair_attr(cp);

		/*
		 *	The callback can return 0 (success) and not provide a value
		 *	in which case we skip the mapping pair.
		 *
		 *	Or return -1 in which case we error out.
		 */
		if (func(&value, cp, data) < 0) {
			cf_log_err_cs(out, "Failed performing mapping \"%s\" = \"%s\"", attr, cf_pair_value(cp));
			return -1;
		}
		if (!value) continue;

		/*
		 *	Replace an existing CONF_PAIR
		 */
		old = cf_pair_find(out, attr);
		if (old) {
			cf_pair_replace(out, old, value);
			talloc_free(value);
			continue;
		}

		/*
		 *	...or add a new CONF_PAIR
		 */
		cp = cf_pair_alloc(out, attr, value, T_OP_SET, T_BARE_WORD, T_SINGLE_QUOTED_STRING);
		if (!cp) {
			cf_log_err_cs(out, "Failed allocing pair \"%s\" = \"%s\"", attr, value);
			talloc_free(value);
			return -1;
		}
		talloc_free(value);
		cf_item_add(out, cf_pair_to_item(cp));
	}

	return 0;
}
/*
 *	Instantiate the module.
 */
static int mod_instantiate(CONF_SECTION *conf, void *instance)
{
	linelog_instance_t	*inst = instance;
	char			prefix[100];

	/*
	 *	Escape filenames only if asked.
	 */
	if (inst->file.escape) {
		inst->file.escape_func = rad_filename_escape;
	} else {
		inst->file.escape_func = rad_filename_make_safe;
	}

	inst->log_dst = fr_str2int(linelog_dst_table, inst->log_dst_str, LINELOG_DST_INVALID);
	if (inst->log_dst == LINELOG_DST_INVALID) {
		cf_log_err_cs(conf, "Invalid log destination \"%s\"", inst->log_dst_str);
		return -1;
	}

	if (!inst->log_src && !inst->log_ref) {
		cf_log_err_cs(conf, "Must specify a log format, or reference");
		return -1;
	}

	inst->name = cf_section_name2(conf);
	if (!inst->name) inst->name = cf_section_name1(conf);

	snprintf(prefix, sizeof(prefix), "rlm_linelog (%s)", inst->name);

	/*
	 *	Setup the logging destination
	 */
	switch (inst->log_dst) {
	case LINELOG_DST_FILE:
	{
		if (!inst->file.name) {
			cf_log_err_cs(conf, "No value provided for 'filename'");
			return -1;
		}

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

		if (inst->file.group_str) {
			char *endptr;

			inst->file.group = strtol(inst->file.group_str, &endptr, 10);
			if (*endptr != '\0') {
				if (rad_getgid(inst, &(inst->file.group), inst->file.group_str) < 0) {
					cf_log_err_cs(conf, "Unable to find system group \"%s\"",
						      inst->file.group_str);
					return -1;
				}
			}
		}
	}
		break;

	case LINELOG_DST_SYSLOG:
	{
		int num;

#ifndef HAVE_SYSLOG_H
		cf_log_err_cs(conf, "Syslog output is not supported on this system");
		return -1;
#else
		if (inst->syslog.facility) {
			num = fr_str2int(syslog_facility_table, inst->syslog.facility, -1);
			if (num < 0) {
				cf_log_err_cs(conf, "Invalid syslog facility \"%s\"", inst->syslog.facility);
				return -1;
			}
			inst->syslog.priority |= num;
		}

		num = fr_str2int(syslog_severity_table, inst->syslog.severity, -1);
		if (num < 0) {
			cf_log_err_cs(conf, "Invalid syslog severity \"%s\"", inst->syslog.severity);
			return -1;
		}
		inst->syslog.priority |= num;
#endif
	}
		break;

	case LINELOG_DST_UNIX:
#ifndef HAVE_SYS_UN_H
		cf_log_err_cs(conf, "Unix sockets are not supported on this sytem");
		return -1;
#else
		inst->pool = fr_connection_pool_module_init(cf_section_sub_find(conf, "unix"),
							    inst, mod_conn_create, NULL, prefix);
		if (!inst->pool) return -1;
#endif
		break;

	case LINELOG_DST_UDP:
		inst->pool = fr_connection_pool_module_init(cf_section_sub_find(conf, "udp"),
							    inst, mod_conn_create, NULL, prefix);
		if (!inst->pool) return -1;
		break;

	case LINELOG_DST_TCP:
		inst->pool = fr_connection_pool_module_init(cf_section_sub_find(conf, "tcp"),
							    inst, mod_conn_create, NULL, prefix);
		if (!inst->pool) return -1;
		break;

	case LINELOG_DST_INVALID:
		rad_assert(0);
		break;
	}

	inst->delimiter_len = talloc_array_length(inst->delimiter) - 1;
	inst->cs = conf;

	return 0;
}
Beispiel #27
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;
}
Beispiel #28
0
/*
 *	Per-instance initialization
 */
static int mod_instantiate(CONF_SECTION *conf, void *instance)
{
	rlm_otp_t *inst = instance;

	/* Onetime initialization. */
	if (!ninstance) {
		/* Generate a random key, used to protect the State attribute. */
		otp_get_random(inst->hmac_key, sizeof(inst->hmac_key));

		/* Initialize the passcode encoding/checking functions. */
		otp_pwe_init();

		/*
		 * Don't do this again.
		 * Only the main thread instantiates and detaches instances,
		 * so this does not need mutex protection.
		 */
		ninstance++;
	}

	/* Verify ranges for those vars that are limited. */
	if ((inst->challenge_len < 5) ||
	    (inst->challenge_len > OTP_MAX_CHALLENGE_LEN)) {
		inst->challenge_len = 6;

		WDEBUG("invalid challenge_length %d, "
		       "range 5-%d, using default of 6",
		       inst->challenge_len, OTP_MAX_CHALLENGE_LEN);
	}

	if (!inst->allow_sync && !inst->allow_async) {
		cf_log_err_cs(conf, "at least one of {allow_async, "
			      "allow_sync} must be set");
		return -1;
	}

	if ((inst->mschapv2_mppe_policy > 2) ||
	    (inst->mschapv2_mppe_policy < 0)) {
		inst->mschapv2_mppe_policy = 2;
		WDEBUG("Invalid value for mschapv2_mppe, "
			"using default of 2");
	}

	if ((inst->mschapv2_mppe_types > 2) || (inst->mschapv2_mppe_types < 0)) {
		inst->mschapv2_mppe_types = 2;
		WDEBUG("Invalid value for "
		       "mschapv2_mppe_bits, using default of 2");
	}

	if ((inst->mschap_mppe_policy > 2) || (inst->mschap_mppe_policy < 0)) {
		inst->mschap_mppe_policy = 2;
		WDEBUG("Invalid value for mschap_mppe, "
		       "using default of 2");
	}

	if (inst->mschap_mppe_types != 2) {
		inst->mschap_mppe_types = 2;
		WDEBUG("Invalid value for "
		       "mschap_mppe_bits, using default of 2");
	}

	/* set the instance name (for use with authorize()) */
	inst->name = cf_section_name2(conf);
	if (!inst->name) inst->name = cf_section_name1(conf);

	return 0;
}
/*
 *	Instantiate the module.
 */
static int mod_instantiate(CONF_SECTION *conf, void *instance)
{
	rlm_cache_t *inst = instance;

	inst->cs = conf;

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

	/*
	 *	Register the cache xlat function
	 */
	xlat_register(inst->xlat_name, cache_xlat, NULL, inst);

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

	/*
	 *	Load the appropriate driver for our database
	 */
	inst->handle = lt_dlopenext(inst->driver_name);
	if (!inst->handle) {
		ERROR("Could not link driver %s: %s", inst->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 = (cache_module_t *) dlsym(inst->handle, inst->driver_name);
	if (!inst->module) {
		ERROR("Could not link symbol %s: %s", inst->driver_name, dlerror());
		return -1;
	}

	DEBUG3("Driver %s loaded successfully", inst->module->name);

	/*
	 *	Non optional fields and callbacks
	 */
	rad_assert(inst->module->name);
	rad_assert(inst->module->find);
	rad_assert(inst->module->insert);
	rad_assert(inst->module->expire);

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

		name = strrchr(inst->driver_name, '_');
		if (!name) {
			name = inst->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 (using talloc)
		 *
		 *	Should write its instance data in inst->driver,
		 *	and parent it off of inst.
		 */
		if (inst->module->mod_instantiate(cs, inst) < 0) return -1;
	}

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

	if (inst->ttl == 0) {
		cf_log_err_cs(conf, "Must set 'ttl' to non-zero");
		return -1;
	}

	if (inst->epoch != 0) {
		cf_log_err_cs(conf, "Must not set 'epoch' in the configuration files");
		return -1;
	}

	/*
	 *	Make sure the users don't screw up too badly.
	 */
	if (map_afrom_cs(&inst->maps, cf_section_sub_find(inst->cs, "update"),
			 PAIR_LIST_REQUEST, PAIR_LIST_REQUEST, cache_verify, NULL, MAX_ATTRMAP) < 0) {
		return -1;
	}

	if (!inst->maps) {
		cf_log_err_cs(inst->cs, "Cache config must contain an update section, and "
			      "that section must not be empty");

		return -1;
	}
	return 0;
}
Beispiel #30
0
RADCLIENT_LIST *client_list_parse_section(CONF_SECTION *section, UNUSED bool tls_required)
#endif
{
	bool		global = false, in_server = false;
	CONF_SECTION	*cs;
	RADCLIENT	*c;
	RADCLIENT_LIST	*clients;

	/*
	 *	Be forgiving.  If there's already a clients, return
	 *	it.  Otherwise create a new one.
	 */
	clients = cf_data_find(section, "clients");
	if (clients) return clients;

	clients = client_list_init(section);
	if (!clients) return NULL;

	if (cf_top_section(section) == section) global = true;

	if (strcmp("server", cf_section_name1(section)) == 0) in_server = true;

	/*
	 *	Associate the clients structure with the section.
	 */
	if (cf_data_add(section, "clients", clients, NULL) < 0) {
		cf_log_err_cs(section,
			   "Failed to associate clients with section %s",
		       cf_section_name1(section));
		client_list_free(clients);
		return NULL;
	}

	for (cs = cf_subsection_find_next(section, NULL, "client");
	     cs != NULL;
	     cs = cf_subsection_find_next(section, cs, "client")) {
		c = client_afrom_cs(cs, cs, in_server, false);
		if (!c) {
			return NULL;
		}

#ifdef WITH_TLS
		/*
		 *	TLS clients CANNOT use non-TLS listeners.
		 *	non-TLS clients CANNOT use TLS listeners.
		 */
		if (tls_required != c->tls_required) {
			cf_log_err_cs(cs, "Client does not have the same TLS configuration as the listener");
			client_free(c);
			client_list_free(clients);
			return NULL;
		}
#endif

		/*
		 *	FIXME: Add the client as data via cf_data_add,
		 *	for migration issues.
		 */

#ifdef WITH_DYNAMIC_CLIENTS
#ifdef HAVE_DIRENT_H
		if (c->client_server) {
			char const *value;
			CONF_PAIR *cp;
			DIR		*dir;
			struct dirent	*dp;
			struct stat stat_buf;
			char buf2[2048];

			/*
			 *	Find the directory where individual
			 *	client definitions are stored.
			 */
			cp = cf_pair_find(cs, "directory");
			if (!cp) goto add_client;

			value = cf_pair_value(cp);
			if (!value) {
				cf_log_err_cs(cs,
					   "The \"directory\" entry must not be empty");
				client_free(c);
				return NULL;
			}

			DEBUG("including dynamic clients in %s", value);

			dir = opendir(value);
			if (!dir) {
				cf_log_err_cs(cs, "Error reading directory %s: %s", value, fr_syserror(errno));
				client_free(c);
				return NULL;
			}

			/*
			 *	Read the directory, ignoring "." files.
			 */
			while ((dp = readdir(dir)) != NULL) {
				char const *p;
				RADCLIENT *dc;

				if (dp->d_name[0] == '.') continue;

				/*
				 *	Check for valid characters
				 */
				for (p = dp->d_name; *p != '\0'; p++) {
					if (isalpha((int)*p) ||
					    isdigit((int)*p) ||
					    (*p == ':') ||
					    (*p == '.')) continue;
						break;
				}
				if (*p != '\0') continue;

				snprintf(buf2, sizeof(buf2), "%s/%s",
					 value, dp->d_name);

				if ((stat(buf2, &stat_buf) != 0) ||
				    S_ISDIR(stat_buf.st_mode)) continue;

				dc = client_read(buf2, in_server, true);
				if (!dc) {
					cf_log_err_cs(cs,
						   "Failed reading client file \"%s\"", buf2);
					client_free(c);
					closedir(dir);
					return NULL;
				}

				/*
				 *	Validate, and add to the list.
				 */
				if (!client_add_dynamic(clients, c, dc)) {

					client_free(c);
					closedir(dir);
					return NULL;
				}
			} /* loop over the directory */
			closedir(dir);
		}
#endif /* HAVE_DIRENT_H */

	add_client:
#endif /* WITH_DYNAMIC_CLIENTS */
		if (!client_add(clients, c)) {
			cf_log_err_cs(cs,
				   "Failed to add client %s",
				   cf_section_name2(cs));
			client_free(c);
			return NULL;
		}

	}

	/*
	 *	Replace the global list of clients with the new one.
	 *	The old one is still referenced from the original
	 *	configuration, and will be freed when that is freed.
	 */
	if (global) {
		root_clients = clients;
	}

	return clients;
}