/** Iterate over all client attribute pairs and create client pair data using JSON element names
 *
 * If we hit a CONF_SECTION we recurse and process its CONF_PAIRS as well to support nested
 * configurations sections.
 *
 * @param client The new client config section using the mapped names.
 * @param map    The client attribute section from the module configuration.
 * @param json   JSON object representation of a client document fetched from Couchbase.
 * @param docid  Document id.
 * @return       Returns 0 on success, -1 on error.
 */
int _mod_client_map_section(CONF_SECTION *client, CONF_SECTION const *map,
			    json_object *json, char const *docid)
{
	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;
		char const *attribute;
		char const *element;
		json_object *jval;

		/*
		 * Recursively process map subsection
		 */
		if (cf_item_is_section(ci)) {
			CONF_SECTION *cs, *cc;    /* local scoped for new section */

			cs = cf_itemtosection(ci);
			cc = cf_section_alloc(client, cf_section_name1(cs), cf_section_name2(cs));
			if (!cc) return -1;

			cf_section_add(client, cc);

			if (_mod_client_map_section(cc, cs, json, docid) != 0) {
				return -1;
			}
			/* continue on to the next item */
			continue;
		}

		/* create pair from item and get attribute name and value */
		cp = cf_itemtopair(ci);
		attribute = cf_pair_attr(cp);
		element = cf_pair_value(cp);

		/* attempt to find element in json object */
		if (!json_object_object_get_ex(json, element, &jval)) {
			/* skip this item */
			continue;
		}

		/* allocate config pair */
		cp = cf_pair_alloc(client, attribute, json_object_get_string(jval), T_OP_SET, T_SINGLE_QUOTED_STRING);

		/* check pair */
		if (!cp) {
			ERROR("rlm_couchbase: failed allocating config pair '%s' = '%s'", attribute, json_object_get_string(jval));
			return -1;
		}

		/* add pair to section */
		cf_item_add(client, cf_pairtoitem(cp));
	}

	/* return success */
	return 0;
}
/** Allocate a fake client representing the LDAP connection
 *
 * The server expects a client, and it's easier to fake one than check all
 * request->client dereferences.
 *
 * @param[in] inst	of proto_ldap to allocate a fake client for.
 * @return
 *	- A fake client.
 *	- NULL on error.
 */
static RADCLIENT *proto_ldap_fake_client_alloc(proto_ldap_inst_t *inst)
{
	CONF_SECTION	*cs;
	CONF_PAIR	*cp;
	RADCLIENT	*client;
	char		buffer[FR_IPADDR_STRLEN];

	cs = cf_section_alloc(NULL, NULL, "client", "ldap");
	cp = cf_pair_alloc(cs, "ipaddr", fr_inet_ntop(buffer, sizeof(buffer), &inst->dst_ipaddr),
			   T_OP_EQ, T_BARE_WORD, T_BARE_WORD);
	cf_pair_add(cs, cp);
	cp = cf_pair_alloc(cs, "secret", "fake", T_OP_EQ, T_BARE_WORD, T_BARE_WORD);
	cf_pair_add(cs, cp);

	client = client_afrom_cs(inst, cs, NULL);
	if (!client) {
		PERROR("Failed creating fake LDAP client");
		talloc_free(cs);
		return NULL;
	}
	talloc_steal(client, cs);

	return client;
}
/** Iterate over pairs in mapping section creating equivalent client pairs from LDAP values
 *
 * If we hit a CONF_SECTION we recurse and process its CONF_PAIRS too.
 *
 * @param[in] inst rlm_ldap configuration.
 * @param[out] client config section.
 * @param[in] map section.
 * @param[in] conn LDAP connection.
 * @param[in] entry returned from search.
 * @return 0 on success else -1 on error.
 */
static int rlm_ldap_client_map_section(ldap_instance_t const *inst, CONF_SECTION *client,
				       CONF_SECTION const *map, ldap_handle_t *conn,
				       LDAPMessage *entry)
{
	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;
	     	char **value;
		char const *attr;

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

			cs = cf_itemtosection(ci);
			cc = cf_section_alloc(client, cf_section_name1(cs), cf_section_name2(cs));
			if (!cc) return -1;

			cf_section_add(client, cc);

			if (rlm_ldap_client_map_section(inst, cc, cs, conn, entry) < 0) return -1;
			continue;
		}

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

		value = ldap_get_values(conn->handle, entry, cf_pair_value(cp));
		if (!value) continue;

		cp = cf_pair_alloc(client, attr, value[0], T_OP_SET, T_SINGLE_QUOTED_STRING);
		if (!cp) {
			LDAP_ERR("Failed allocing pair \"%s\" = \"%s\"", attr, value[0]);
			return -1;
		}
		cf_item_add(client, cf_pairtoitem(cp));
	}

	return 0;
}
Beispiel #4
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;
}