static rlm_rcode_t mod_do_linelog(void *instance, REQUEST *request)
{
	int			fd = -1;
	linelog_conn_t		*conn;
	struct timeval		*timeout = NULL;

	char			buff[4096];
	char			*p = buff;
	linelog_instance_t	*inst = instance;
	char const		*value;
	vp_tmpl_t		empty, *vpt = NULL, *vpt_p = NULL;
	rlm_rcode_t		rcode = RLM_MODULE_OK;
	ssize_t			slen;

	struct iovec		vector_s[2];
	struct iovec		*vector = NULL, *vector_p;
	size_t			vector_len;
	bool			with_delim;

	buff[0] = '.';	/* force to be in current section */
	buff[1] = '\0';
	buff[2] = '\0';

	/*
	 *	Expand log_ref to a config path, using the module
	 *	configuration section as the root.
	 */
	if (inst->log_ref) {
		CONF_ITEM	*ci;
		CONF_PAIR	*cp;
		char const	*tmpl_str;

		if (tmpl_expand(NULL, buff + 1, sizeof(buff) - 1,
				request, inst->log_ref, linelog_escape_func, NULL) < 0) {
			return RLM_MODULE_FAIL;
		}

		if (buff[1] == '.') p++;

		/*
		 *	Don't go back up.
		 */
		if (buff[2] == '.') {
			REDEBUG("Invalid path \"%s\"", p);
			return RLM_MODULE_FAIL;
		}

		ci = cf_reference_item(NULL, inst->cs, p);
		if (!ci) {
			RDEBUG2("Path \"%s\" doesn't exist", p);
			goto default_msg;
		}

		if (!cf_item_is_pair(ci)) {
			REDEBUG("Path \"%s\" resolves to a section (should be a pair)", p);
			return RLM_MODULE_FAIL;
		}

		cp = cf_item_to_pair(ci);
		tmpl_str = cf_pair_value(cp);
		if (!tmpl_str || (tmpl_str[0] == '\0')) {
			RDEBUG2("Path \"%s\" resolves to an empty config pair", p);
			vpt_p = tmpl_init(&empty, TMPL_TYPE_LITERAL, "", 0);
			goto build_vector;
		}

		/*
		 *	Alloc a template from the value of the CONF_PAIR
		 *	using request as the context (which will hopefully avoid a malloc).
		 */
		slen = tmpl_afrom_str(request, &vpt, tmpl_str, talloc_array_length(tmpl_str) - 1,
				      cf_pair_value_type(cp), REQUEST_CURRENT, PAIR_LIST_REQUEST, true);
		if (slen <= 0) {
			REMARKER(tmpl_str, -slen, fr_strerror());
			return RLM_MODULE_FAIL;
		}
		vpt_p = vpt;
	} else {
	default_msg:
		/*
		 *	Use the default format string
		 */
		if (!inst->log_src) {
			RDEBUG2("No default message configured");
			return RLM_MODULE_NOOP;
		}
		/*
		 *	Use the pre-parsed format template
		 */
		RDEBUG2("Using default message");
		vpt_p = inst->log_src;
	}

build_vector:
	with_delim = (inst->log_dst != LINELOG_DST_SYSLOG) && (inst->delimiter_len > 0);

	/*
	 *	Log all the things!
	 */
	switch (vpt_p->type) {
	case TMPL_TYPE_ATTR:
	case TMPL_TYPE_LIST:
	{
		#define VECTOR_INCREMENT 20
		vp_cursor_t	cursor;
		VALUE_PAIR	*vp;
		int		alloced = VECTOR_INCREMENT, i;

		MEM(vector = talloc_array(request, struct iovec, alloced));
		for (vp = tmpl_cursor_init(NULL, &cursor, request, vpt_p), i = 0;
		     vp;
		     vp = tmpl_cursor_next(&cursor, vpt_p), i++) {
		     	/* need extra for line terminator */
			if ((with_delim && ((i + 1) >= alloced)) ||
			    (i >= alloced)) {
				alloced += VECTOR_INCREMENT;
				MEM(vector = talloc_realloc(request, vector, struct iovec, alloced));
			}

			switch (vp->da->type) {
			case PW_TYPE_OCTETS:
			case PW_TYPE_STRING:
				vector[i].iov_base = vp->data.ptr;
				vector[i].iov_len = vp->vp_length;
				break;

			default:
				p = vp_aprints_value(vector, vp, '\0');
				vector[i].iov_base = p;
				vector[i].iov_len = talloc_array_length(p) - 1;
				break;
			}

			/*
			 *	Add the line delimiter string
			 */
			if (with_delim) {
				i++;
				memcpy(&vector[i].iov_base, &(inst->delimiter), sizeof(vector[i].iov_base));
				vector[i].iov_len = inst->delimiter_len;
			}
		}
		vector_p = vector;
		vector_len = i;
	}
		break;

	/*
	 *	Log a single thing.
	 */
	default:
		slen = tmpl_expand(&value, buff, sizeof(buff), request, vpt_p, linelog_escape_func, NULL);
		if (slen < 0) {
			rcode = RLM_MODULE_FAIL;
			goto finish;
		}

		/* iov_base is not declared as const *sigh* */
		memcpy(&vector_s[0].iov_base, &value, sizeof(vector_s[0].iov_base));
		vector_s[0].iov_len = slen;

		if (!with_delim) {
			vector_len = 1;
		} else {
			memcpy(&vector_s[1].iov_base, &(inst->delimiter), sizeof(vector_s[1].iov_base));
			vector_s[1].iov_len = inst->delimiter_len;
			vector_len = 2;
		}

		vector_p = &vector_s[0];
	}
Example #2
0
/** Convert an 'update' config section into an attribute map.
 *
 * Uses 'name2' of section to set default request and lists.
 * Copied from map_afrom_cs, except that list assignments can have the RHS
 * be a bare word.
 *
 * @param[in] cs the update section
 * @param[out] out Where to store the head of the map.
 * @param[in] dst_list_def The default destination list, usually dictated by
 * 	the section the module is being called in.
 * @param[in] src_list_def The default source list, usually dictated by the
 *	section the module is being called in.
 * @param[in] max number of mappings to process.
 * @return -1 on error, else 0.
 */
static int ldap_map_afrom_cs(value_pair_map_t **out, CONF_SECTION *cs, pair_lists_t dst_list_def, pair_lists_t src_list_def,
			     unsigned int max)
{
	char const *cs_list, *p;

	request_refs_t request_def = REQUEST_CURRENT;

	CONF_ITEM *ci;

	unsigned int total = 0;
	value_pair_map_t **tail, *map;
	TALLOC_CTX *ctx;

	*out = NULL;
	tail = out;

	if (!cs) return 0;

	/*
	 *	The first map has cs as the parent.
	 *	The rest have the previous map as the parent.
	 */
	ctx = cs;

	ci = cf_sectiontoitem(cs);

	cs_list = p = cf_section_name2(cs);
	if (cs_list) {
		request_def = radius_request_name(&p, REQUEST_CURRENT);
		if (request_def == REQUEST_UNKNOWN) {
			cf_log_err(ci, "Default request specified "
				   "in mapping section is invalid");
			return -1;
		}

		dst_list_def = fr_str2int(pair_lists, p, PAIR_LIST_UNKNOWN);
		if (dst_list_def == PAIR_LIST_UNKNOWN) {
			cf_log_err(ci, "Default list \"%s\" specified "
				   "in mapping section is invalid", p);
			return -1;
		}
	}

	for (ci = cf_item_find_next(cs, NULL);
	     ci != NULL;
	     ci = cf_item_find_next(cs, ci)) {
		char const *attr;
		FR_TOKEN type;
		CONF_PAIR *cp;

		cp = cf_itemtopair(ci);

		type = cf_pair_value_type(cp);

		if (total++ == max) {
			cf_log_err(ci, "Map size exceeded");
			goto error;
		}

		if (!cf_item_is_pair(ci)) {
			cf_log_err(ci, "Entry is not in \"attribute = value\" format");
			goto error;
		}

		cp = cf_itemtopair(ci);

		/*
		 *	Look for "list: OP BARE_WORD".  If it exists,
		 *	we can make the RHS a bare word.  Otherwise,
		 *	just call map_afrom_cp()
		 *
		 *	Otherwise, the map functions check the RHS of
		 *	list assignments, and complain that the RHS
		 *	isn't another list.
		 */
		attr = cf_pair_attr(cp);

		p = strrchr(attr, ':');
		if (!p || (p[1] != '\0') || (type == T_DOUBLE_QUOTED_STRING)) {
			if (map_afrom_cp(ctx, &map, cp, request_def, dst_list_def, REQUEST_CURRENT, src_list_def) < 0) {
				goto error;
			}
		} else {
			ssize_t slen;
			char const *value;

			map = talloc_zero(ctx, value_pair_map_t);
			map->op = cf_pair_operator(cp);
			map->ci = cf_pairtoitem(cp);

			slen = tmpl_afrom_attr_str(ctx, &map->lhs, attr, request_def, dst_list_def);
			if (slen <= 0) {
				char *spaces, *text;

				fr_canonicalize_error(ctx, &spaces, &text, slen, attr);
				
				cf_log_err(ci, "Failed parsing list reference");
				cf_log_err(ci, "%s", text);
				cf_log_err(ci, "%s^ %s", spaces, fr_strerror());

				talloc_free(spaces);
				talloc_free(text);
				goto error;
			}
		      
			if (map->lhs->type != TMPL_TYPE_LIST) {
				cf_log_err(map->ci, "Invalid list name");
				goto error;
			}
			
			if (map->op != T_OP_ADD) {
				cf_log_err(map->ci, "Only '+=' operator is permitted for valuepair to list mapping");
				goto error;
			}

			value = cf_pair_value(cp);
			if (!value) {
				cf_log_err(map->ci, "No value specified for list assignment");
				goto error;
			}

			/*
			 *	the RHS type is a bare word or single
			 *	quoted string.  We don't want it being
			 *	interpreted as a list or attribute
			 *	reference, so we force the RHS to be a
			 *	literal.
			 */
			slen = tmpl_afrom_str(ctx, &map->rhs, value, T_SINGLE_QUOTED_STRING, request_def, dst_list_def);
			if (slen <= 0) {
				char *spaces, *text;

				fr_canonicalize_error(ctx, &spaces, &text, slen, value);
				
				cf_log_err(ci, "Failed parsing string");
				cf_log_err(ci, "%s", text);
				cf_log_err(ci, "%s^ %s", spaces, fr_strerror());

				talloc_free(spaces);
				talloc_free(text);
				goto error;
			}

			/*
			 *	And unlike map_afrom_cp(), we do NOT
			 *	try to parse the RHS as a list
			 *	reference.  It's a literal, and we
			 *	leave it as a literal.
			 */
			rad_assert(map->rhs->type == TMPL_TYPE_LITERAL);
		}

		ctx = *tail = map;
		tail = &(map->next);
	}

	return 0;
error:
	TALLOC_FREE(*out);
	return -1;
}