Пример #1
0
/** Write an error to the library errorbuff detailing the mismatch
 *
 * Retrieve output with fr_strerror();
 *
 * @todo add thread specific talloc contexts.
 *
 * @param ctx a hack until we have thread specific talloc contexts.
 * @param failed pair of attributes which didn't match.
 */
void pairvalidate_debug(TALLOC_CTX *ctx, VALUE_PAIR const *failed[2])
{
	VALUE_PAIR const *filter = failed[0];
	VALUE_PAIR const *list = failed[1];

	char *value, *str;

	(void) fr_strerror();	/* Clear any existing messages */

	if (!fr_assert(!(!filter && !list))) return;

	if (!list) {
		if (!filter) return;
		fr_strerror_printf("Attribute \"%s\" not found in list", filter->da->name);
		return;
	}

	if (!filter || (filter->da != list->da)) {
		fr_strerror_printf("Attribute \"%s\" not found in filter", list->da->name);
		return;
	}

	if (!TAG_EQ(filter->tag, list->tag)) {
		fr_strerror_printf("Attribute \"%s\" tag \"%i\" didn't match filter tag \"%i\"",
				   list->da->name, list->tag, filter->tag);
		return;
	}


	value = vp_aprints_value(ctx, list, '"');
	str = vp_aprints(ctx, filter, '"');

	fr_strerror_printf("Attribute value \"%s\" didn't match filter: %s", value, str);

	talloc_free(str);
	talloc_free(value);

	return;
}
Пример #2
0
/** Extract the IV value from an AT_IV attribute
 *
 * SIM uses padding at the start of the attribute to make it a multiple of 4.
 * We need to strip packet_ctx and check that it was set to zero.
 *
 * @param[out] out 	Where to write IV.
 * @param[in] in	value of AT_IV attribute.
 * @param[in] in_len	the length of the AT_IV attribute (should be 18).
 * @return
 *	- 0 on success.
 *	- < 0 on failure (bad IV).
 */
static inline int sim_iv_extract(uint8_t out[SIM_IV_SIZE], uint8_t const *in, size_t in_len)
{
	/*
	 *	Two bytes are reserved, so although
	 *	the IV is actually 16 bytes, we
	 *	check for 18.
	 */
	if (in_len != (SIM_IV_SIZE + 2)) {
		fr_strerror_printf("%s: Invalid IV length, expected %u got %zu",
				   __FUNCTION__, (SIM_IV_SIZE + 2), in_len);
		return -1;
	}

	if ((in[0] != 0x00) || (in[1] != 0x00)) {
		fr_strerror_printf("%s: Reserved bytes in IV are not zeroed", __FUNCTION__);
		return -1;
	}

	/* skip reserved bytes */
	memcpy(out, in + 2, SIM_IV_SIZE);

	return 0;
}
Пример #3
0
/** Free a control structure
 *
 *  This function really only calls the underlying "garbage collect".
 *
 * @param[in] c the control structure
 */
void fr_control_free(fr_control_t *c)
{
	struct kevent kev;

	(void) talloc_get_type_abort(c, fr_control_t);

	EV_SET(&kev, c->ident, EVFILT_USER, EV_DELETE, NOTE_FFNOP, 0, NULL);
	if (kevent(c->kq, &kev, 1, NULL, 0, NULL) < 0) {
		talloc_free(c);
		fr_strerror_printf("Failed opening KQ for control socket: %s", fr_syserror(errno));
	}

	talloc_free(c);
}
Пример #4
0
/** Determine if an address is a prefix
 *
 * @param ipaddr to check.
 * @return
 *	- 0 if it's not.
 *	- 1 if it is.
 *	- -1 on error.
 */
int fr_ipaddr_is_prefix(fr_ipaddr_t const *ipaddr)
{
	switch (ipaddr->af) {
	case AF_INET:
		return (ipaddr->prefix < 32);

	case AF_INET6:
		return (ipaddr->prefix < 128);

	default:
		fr_strerror_printf("Unknown address family");
		return -1;
	}
}
Пример #5
0
/*
 *	Process the VALUE command
 */
static int process_value(const char* fn, const int line, char **argv,
			 int argc)
{
	int	value;

	if (argc != 3) {
		fr_strerror_printf("dict_init: %s[%d]: invalid VALUE line",
			fn, line);
		return -1;
	}
	/*
	 *	For Compatibility, skip "Server-Config"
	 */
	if (strcasecmp(argv[0], "Server-Config") == 0)
		return 0;

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

	if (dict_addvalue(argv[1], argv[0], value) < 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;
}
Пример #6
0
/** Write the result of a set operation back to net-snmp
 *
 * Writes "DONE\n" on success, or an error as described in man snmpd.conf
 * on error.
 *
 * @param fd to write to.
 * @param error attribute.
 * @param head of list of attributes to convert and write.
 * @return
 *	- 0 on success.
 *	- -1 on failure.
 */
static int radsnmp_set_response(int fd, fr_dict_attr_t const *error, VALUE_PAIR *head)
{
	VALUE_PAIR	*vp;
	char		buffer[64];
	size_t		len;
	struct iovec	io_vector[2];
	char		newline[] = "\n";

	vp = fr_pair_find_by_da(head, error, TAG_NONE);
	if (!vp) {
		if (write(fd, "DONE\n", 5) < 0) {
			fr_strerror_printf("Failed writing set response: %s", fr_syserror(errno));
			return -1;
		}
		return 0;
	}

	len = fr_pair_value_snprint(buffer, sizeof(buffer), vp, '\0');
	if (is_truncated(len, sizeof(buffer))) {
		assert(0);
		return -1;
	}

	io_vector[0].iov_base = buffer;
	io_vector[0].iov_len = len;
	io_vector[1].iov_base = newline;
	io_vector[1].iov_len = 1;

	DEBUG2("said: %s", buffer);

	if (writev(fd, io_vector, sizeof(io_vector) / sizeof(*io_vector)) < 0) {
		fr_strerror_printf("Failed writing set response: %s", fr_syserror(errno));
		return -1;
	}

	return 0;
}
Пример #7
0
/** Enable or disable core dumps
 *
 * @param allow_core_dumps whether to enable or disable core dumps.
 */
int fr_set_dumpable(bool allow_core_dumps)
{
	dump_core = allow_core_dumps;
	/*
	 *	If configured, turn core dumps off.
	 */
	if (!allow_core_dumps) {
#ifdef HAVE_SYS_RESOURCE_H
		struct rlimit no_core;

		no_core.rlim_cur = 0;
		no_core.rlim_max = 0;

		if (setrlimit(RLIMIT_CORE, &no_core) < 0) {
			fr_strerror_printf("Failed disabling core dumps: %s", fr_syserror(errno));

			return -1;
		}
#endif
		return 0;
	}

	if (fr_set_dumpable_flag(true) < 0) return -1;

	/*
	 *	Reset the core dump limits to their original value.
	 */
#ifdef HAVE_SYS_RESOURCE_H
	if (setrlimit(RLIMIT_CORE, &core_limits) < 0) {
		fr_strerror_printf("Cannot update core dump limit: %s", fr_syserror(errno));

		return -1;
	}
#endif
	return 0;
}
Пример #8
0
/** Create a control-plane signaling path.
 *
 * @param[in] ctx the talloc context
 * @param[in] kq the KQ descriptor where we will be sending signals
 * @param[in] aq the atomic queue where we will be pushing message data
 * @param[in] ident the identifier to use for EVFILT_USER signals.
 * @return
 *	- NULL on error
 *	- fr_control_t on success
 */
fr_control_t *fr_control_create(TALLOC_CTX *ctx, int kq, fr_atomic_queue_t *aq, uintptr_t ident)
{
	fr_control_t *c;
	struct kevent kev;

	c = talloc_zero(ctx, fr_control_t);
	if (!c) {
		fr_strerror_printf("Failed allocating memory");
		return NULL;
	}

	c->kq = kq;
	c->aq = aq;
	c->ident = ident;

	/*
	 *	Tell the KQ to listen on our events.
	 *
	 *	We COULD overload the "ident" field with our channel
	 *	number, followed by the actual signal we're sending.
	 *	This would work.  The downside is that it would
	 *	require N*M EVFILT_USER kevents to be registered,
	 *	which is bad
	 *
	 *	The implementation here is perhaps a bit less optimal,
	 *	but it's clean, and it works.
	 */
	EV_SET(&kev, ident, EVFILT_USER, EV_ADD | EV_CLEAR, NOTE_FFNOP, 0, NULL);
	if (kevent(c->kq, &kev, 1, NULL, 0, NULL) < 0) {
		talloc_free(c);
		fr_strerror_printf("Failed opening KQ for control socket: %s", fr_syserror(errno));
		return NULL;
	}

	return c;
}
Пример #9
0
/** Copy a single valuepair
 *
 * Allocate a new valuepair and copy the da from the old vp.
 *
 * @param[in] ctx for talloc
 * @param[in] vp to copy.
 * @return a copy of the input VP or NULL on error.
 */
VALUE_PAIR *paircopyvp(TALLOC_CTX *ctx, VALUE_PAIR const *vp)
{
	VALUE_PAIR *n;

	if (!vp) return NULL;

	VERIFY(vp);

	n = pairalloc(ctx, vp->da);
	if (!n) {
		fr_strerror_printf("out of memory");
		return NULL;
	}
	
	memcpy(n, vp, sizeof(*n));
	
	/*
	 *	Now copy the value
	 */
	if (vp->type == VT_XLAT) {
		n->value.xlat = talloc_strdup(n, n->value.xlat);
	}
	
	n->da = dict_attr_copy(vp->da, true);
	if (!n->da) {
		pairbasicfree(n);
		return NULL;
	}
	
	n->next = NULL;

	if ((n->da->type == PW_TYPE_TLV) ||
	    (n->da->type == PW_TYPE_OCTETS)) {
		if (n->vp_octets != NULL) {
			n->vp_octets = talloc_memdup(n, vp->vp_octets, n->length);
		}

	} else if (n->da->type == PW_TYPE_STRING) {
		if (n->vp_strvalue != NULL) {
			/*
			 *	Equivalent to, and faster than strdup.
			 */
			n->vp_strvalue = talloc_memdup(n, vp->vp_octets, n->length + 1);
		}
	}

	return n;
}
Пример #10
0
static int fr_get_dumpable_flag(void)
{
	int ret;

	ret = prctl(PR_GET_DUMPABLE);
	if (ret < 0) {
		fr_strerror_printf("Cannot get dumpable flag: %s", fr_syserror(errno));
		return -1;
	}

	/*
	 *  Linux is crazy and prctl sometimes returns 2 for disabled
	 */
	if (ret != 1) return 0;
	return 1;
}
Пример #11
0
/** Send a control-plane message
 *
 *  This function is called ONLY from the originating thread.
 *
 * @param[in] c the control structure
 * @param[in] rb the callers ring buffer for message allocation.
 * @param[in] id the ident of this message.
 * @param[in] data the data to write to the control plane
 * @param[in] data_size the size of the data to write to the control plane.
 * @return
 *	- <0 on error
 *	- 0 on success
 */
int fr_control_message_send(fr_control_t *c, fr_ring_buffer_t *rb, uint32_t id, void *data, size_t data_size)
{
	int rcode;
	struct kevent kev;

	(void) talloc_get_type_abort(c, fr_control_t);

	if (fr_control_message_push(c, rb, id, data, data_size) < 0) return -1;

	EV_SET(&kev, c->ident, EVFILT_USER, 0, NOTE_TRIGGER | NOTE_FFNOP, 0, NULL);
	rcode = kevent(c->kq, &kev, 1, NULL, 0, NULL);
	if (rcode >= 0) return rcode;

	fr_strerror_printf("Failed sending user event to kqueue (%i): %s", c->kq, fr_syserror(errno));
	return rcode;
}
Пример #12
0
/** Registers signal handlers to execute panic_action on fatal signal
 *
 * May be called multiple time to change the panic_action/program.
 *
 * @param cmd to execute on fault. If present %p will be substituted
 *        for the parent PID before the command is executed, and %e
 *        will be substituted for the currently running program.
 * @param program Name of program currently executing (argv[0]).
 * @return 0 on success -1 on failure.
 */
int fr_fault_setup(char const *cmd, char const *program)
{
	static bool setup = false;

	char *out = panic_action;
	size_t left = sizeof(panic_action), ret;

	char const *p = cmd;
	char const *q;

	if (cmd) {
		/* Substitute %e for the current program */
		while ((q = strstr(p, "%e"))) {
			out += ret = snprintf(out, left, "%.*s%s", (int) (q - p), p, program ? program : "");
			if (left <= ret) {
			oob:
				fr_strerror_printf("Panic action too long");
				return -1;
			}
			left -= ret;
			p = q + 2;
		}
		if (strlen(p) >= left) goto oob;
		strlcpy(out, p, left);
	} else {
		*panic_action = '\0';
	}

	/* Unsure what the side effects of changing the signal handler mid execution might be */
	if (!setup) {
#ifdef SIGSEGV
		if (fr_set_signal(SIGSEGV, fr_fault) < 0) return -1;
#endif
#ifdef SIGBUS
		if (fr_set_signal(SIGBUS, fr_fault) < 0) return -1;
#endif
#ifdef SIGABRT
		if (fr_set_signal(SIGABRT, fr_fault) < 0) return -1;
#endif
#ifdef SIGFPE
		if (fr_set_signal(SIGFPE, fr_fault) < 0) return -1;
#endif
	}
	setup = true;

	return 0;
}
Пример #13
0
/** Allocate a new RADIUS_PACKET
 *
 * @param ctx the context in which the packet is allocated. May be NULL if
 *	the packet is not associated with a REQUEST.
 * @param new_vector if true a new request authenticator will be generated.
 * @return
 *	- New RADIUS_PACKET.
 *	- NULL on error.
 */
RADIUS_PACKET *fr_radius_alloc(TALLOC_CTX *ctx, bool new_vector)
{
	RADIUS_PACKET	*rp;

	rp = talloc_zero(ctx, RADIUS_PACKET);
	if (!rp) {
		fr_strerror_printf("out of memory");
		return NULL;
	}
	rp->id = -1;

	if (new_vector) {
		fr_rand_buffer(rp->vector, sizeof(rp->vector));
	}

	return rp;
}
Пример #14
0
/** Delete a callback for an ID
 *
 * @param[in] c the control structure
 * @param[in] id the ident of this message.
 * @return
 *	- <0 on error
 *	- 0 on success
 */
int fr_control_callback_delete(fr_control_t *c, uint32_t id)
{
	(void) talloc_get_type_abort(c, fr_control_t);

	if (id >= FR_CONTROL_MAX_TYPES) {
		fr_strerror_printf("Failed adding unknown ID %d", id);
		return -1;
	}

	if (c->type[id].callback == NULL) return 0;

	c->type[id].id = 0;
	c->type[id].ctx = NULL;
	c->type[id].callback = NULL;

	return 0;
}
Пример #15
0
/** Print a #fr_ipaddr_t as a CIDR style network prefix
 *
 * @param[out] out Where to write the resulting prefix string.
 *	Should be at least FR_IPADDR_PREFIX_STRLEN bytes.
 * @param[in] outlen of output buffer.
 * @param[in] addr to convert to presentation format.
 * @return
 *	- NULL on error (use fr_syserror(errno)).
 *	- a pointer to out on success.
 */
char *fr_inet_ntop_prefix(char out[FR_IPADDR_PREFIX_STRLEN], size_t outlen, fr_ipaddr_t const *addr)
{
	char	*p;
	size_t	len;

	if (fr_inet_ntop(out, outlen, addr) == NULL) return NULL;

	p = out + strlen(out);

	len = snprintf(p, outlen - (p - out), "/%i", addr->prefix);
	if (is_truncated(len + (p - out), outlen)) {
		fr_strerror_printf("Address buffer too small, needed %zu bytes, have %zu bytes",
				   (p - out) + len, outlen);
		return NULL;
	}

	return out;
}
Пример #16
0
int fr_logfile_unlock(fr_logfile_t *lf, int fd)
{
	int i;

	for (i = 0; i < lf->max_entries; i++) {
		if (!lf->entries[i].filename) continue;

		if (lf->entries[i].dup == fd) {
			lf->entries[i].dup = -1;
			PTHREAD_MUTEX_UNLOCK(&(lf->mutex));
			return 0;
		}
	}

	PTHREAD_MUTEX_UNLOCK(&(lf->mutex));

	fr_strerror_printf("Attempt to unlock file which does not exist");
	return -1;
}
Пример #17
0
int exfile_unlock(exfile_t *ef, int fd)
{
	uint32_t i;

	for (i = 0; i < ef->max_entries; i++) {
		if (!ef->entries[i].filename) continue;

		if (ef->entries[i].dup == fd) {
			ef->entries[i].dup = -1;
			PTHREAD_MUTEX_UNLOCK(&(ef->mutex));
			return 0;
		}
	}

	PTHREAD_MUTEX_UNLOCK(&(ef->mutex));

	fr_strerror_printf("Attempt to unlock file which does not exist");
	return -1;
}
Пример #18
0
/*
 *	Create a new valuepair.
 */
VALUE_PAIR *paircreate(int attr, int type)
{
	VALUE_PAIR	*vp;
	DICT_ATTR	*da;

	da = dict_attrbyvalue(attr);
	if ((vp = pairalloc(da)) == NULL) {
		fr_strerror_printf("out of memory");
		return NULL;
	}
	vp->operator = T_OP_EQ;

	/*
	 *	It isn't in the dictionary: update the name.
	 */
	if (!da) return paircreate_raw(attr, type, vp);

	return vp;
}
Пример #19
0
/** Dynamically allocate a new attribute
 *
 * Allocates a new attribute and a new dictionary attr if no DA is provided.
 *
 * @param[in] ctx for allocated memory, usually a pointer to a RADIUS_PACKET
 * @param[in] da Specifies the dictionary attribute to build the VP from.
 * @return a new value pair or NULL if an error occurred.
 */
VALUE_PAIR *pairalloc(TALLOC_CTX *ctx, DICT_ATTR const *da)
{
	VALUE_PAIR *vp;

	/*
	 *	Caller must specify a da else we don't know what the attribute
	 *	type is.
	 */
	if (!da) return NULL;

	vp = talloc_zero(ctx, VALUE_PAIR);
	if (!vp) {
		fr_strerror_printf("Out of memory");
		return NULL;
	}
	
	vp->da = da;
	vp->op = T_OP_EQ;
	vp->type = VT_NONE;

	return vp;
}
Пример #20
0
/** Perform reverse resolution of an IP address
 *
 * Attempt to resolve an IP address to a DNS record (if dns lookups are enabled).
 *
 * @param[in] src address to resolve.
 * @param[out] out Where to write the resulting hostname.
 * @param[in] outlen length of the output buffer.
 */
char const *fr_inet_ntoh(fr_ipaddr_t const *src, char *out, size_t outlen)
{
	struct sockaddr_storage ss;
	int error;
	socklen_t salen;

	/*
	 *	No DNS lookups
	 */
	if (!fr_reverse_lookups) {
		return inet_ntop(src->af, &(src->addr), out, outlen);
	}

	if (fr_ipaddr_to_sockaddr(src, 0, &ss, &salen) < 0) return NULL;

	if ((error = getnameinfo((struct sockaddr *)&ss, salen, out, outlen, NULL, 0,
				 NI_NUMERICHOST | NI_NUMERICSERV)) != 0) {
		fr_strerror_printf("fr_inet_ntoh: %s", gai_strerror(error));
		return NULL;
	}
	return out;
}
Пример #21
0
/** Determine if an address is the INADDR_ANY address for its address family
 *
 * @param ipaddr to check.
 * @return
 *	- 0 if it's not.
 *	- 1 if it is.
 *	- -1 on error.
 */
int fr_ipaddr_is_inaddr_any(fr_ipaddr_t const *ipaddr)
{

	if (ipaddr->af == AF_INET) {
		if (ipaddr->addr.v4.s_addr == htonl(INADDR_ANY)) {
			return 1;
		}

#ifdef HAVE_STRUCT_SOCKADDR_IN6
	} else if (ipaddr->af == AF_INET6) {
		if (IN6_IS_ADDR_UNSPECIFIED(&(ipaddr->addr.v6))) {
			return 1;
		}
#endif

	} else {
		fr_strerror_printf("Unknown address family");
		return -1;
	}

	return 0;
}
Пример #22
0
/** Clean up messages in a control-plane buffer
 *
 *  Find the oldest messages which are marked FR_CONTROL_MESSAGE_DONE,
 *  and mark them FR_CONTROL_MESSAGE_FREE.
 *
 * @param[in] c the fr_control_t
 * @param[in] rb the callers ring buffer for message allocation.
 * @return
 *	- <0 there are still messages used
 *	- 0 the control list is empty.
 */
int fr_control_gc(UNUSED fr_control_t *c, fr_ring_buffer_t *rb)
{
	while (true) {
		size_t room, message_size;
		fr_control_message_t *m;

		(void) fr_ring_buffer_start(rb, (uint8_t **) &m, &room);
		if (room == 0) break;

		rad_assert(m != NULL);
		rad_assert(room >= sizeof(*m));

		rad_assert(m->status != FR_CONTROL_MESSAGE_FREE);

		if (m->status != FR_CONTROL_MESSAGE_DONE) break;

		m->status = FR_CONTROL_MESSAGE_FREE;

		/*
		 *	Each message is aligned to a 64-byte boundary,
		 *	for cache contention issues.
		 */
		message_size = sizeof(*m);
		message_size += m->data_size;
		message_size += 63;
		message_size &= ~(size_t) 63;
		fr_ring_buffer_free(rb, message_size);
	}

	/*
	 *	Maybe we failed to garbage collect everything?
	 */
	if (fr_ring_buffer_used(rb) > 0) {
		fr_strerror_printf("Data still in control buffers");
		return -1;
	}

	return 0;
}
Пример #23
0
VALUE_PAIR *pairalloc(DICT_ATTR *da)
{
	size_t name_len = 0;
	VALUE_PAIR *vp;

	/*
	 *	Not in the dictionary: the name is allocated AFTER
	 *	the VALUE_PAIR struct.
	 */
	if (!da) name_len = FR_VP_NAME_PAD;

	vp = malloc(sizeof(*vp) + name_len);
	if (!vp) {
		fr_strerror_printf("Out of memory");
		return NULL;
	}
	memset(vp, 0, sizeof(*vp));

	if (da) {
		vp->attribute = da->attr;
		vp->vendor = da->vendor;
		vp->type = da->type;
		vp->name = da->name;
		vp->flags = da->flags;
	} else {
		vp->attribute = 0;
		vp->vendor = 0;
		vp->type = PW_TYPE_OCTETS;
		vp->name = NULL;
		memset(&vp->flags, 0, sizeof(vp->flags));
		vp->flags.unknown_attr = 1;
	}
	vp->operator = T_OP_EQ;

	switch (vp->type) {
		case PW_TYPE_BYTE:
			vp->length = 1;
			break;

		case PW_TYPE_SHORT:
			vp->length = 2;
			break;

		case PW_TYPE_INTEGER:
		case PW_TYPE_IPADDR:
		case PW_TYPE_DATE:
		case PW_TYPE_SIGNED:
			vp->length = 4;
			break;

		case PW_TYPE_INTEGER64:
			vp->length = 8;
			break;

		case PW_TYPE_IFID:
			vp->length = sizeof(vp->vp_ifid);
			break;

		case PW_TYPE_IPV6ADDR:
			vp->length = sizeof(vp->vp_ipv6addr);
			break;

		case PW_TYPE_IPV6PREFIX:
			vp->length = sizeof(vp->vp_ipv6prefix);
			break;

		case PW_TYPE_ETHERNET:
			vp->length = sizeof(vp->vp_ether);
			break;

		case PW_TYPE_TLV:
			vp->vp_tlv = NULL;
			vp->length = 0;
			break;

		case PW_TYPE_COMBO_IP:
		default:
			vp->length = 0;
			break;
	}

	return vp;
}
Пример #24
0
static RADIUS_PACKET *fr_dhcp_recv_raw_loop(int lsockfd,
#ifdef HAVE_LINUX_IF_PACKET_H
					    struct sockaddr_ll *p_ll,
#endif
					    RADIUS_PACKET *request_p)
{
	struct timeval tval;
	RADIUS_PACKET *reply_p = NULL;
	RADIUS_PACKET *cur_reply_p = NULL;
	int nb_reply = 0;
	int nb_offer = 0;
	dc_offer_t *offer_list = NULL;
	fd_set read_fd;
	int retval;

	memcpy(&tval, &tv_timeout, sizeof(struct timeval));

	/* Loop waiting for DHCP replies until timer expires */
	while (timerisset(&tval)) {
		if ((!reply_p) || (cur_reply_p)) { // only debug at start and each time we get a valid DHCP reply on raw socket
			DEBUG("Waiting for%sDHCP replies for: %d.%06d",
				(nb_reply>0)?" additional ":" ", (int)tval.tv_sec, (int)tval.tv_usec);
		}

		cur_reply_p = NULL;
		FD_ZERO(&read_fd);
		FD_SET(lsockfd, &read_fd);
		retval = select(lsockfd + 1, &read_fd, NULL, NULL, &tval);

		if (retval < 0) {
			fr_strerror_printf("Select on DHCP socket failed: %s", fr_syserror(errno));
			return NULL;
		}

		if ( retval > 0 && FD_ISSET(lsockfd, &read_fd)) {
			/* There is something to read on our socket */

#ifdef HAVE_LINUX_IF_PACKET_H
			cur_reply_p = fr_dhcp_recv_raw_packet(lsockfd, p_ll, request_p);
#else
#ifdef HAVE_LIBPCAP
			cur_reply_p = fr_dhcp_recv_pcap(pcap);
#else
#error Need <if/packet.h> or <pcap.h>
#endif
#endif
		} else {
			// Not all implementations of select clear the timer
			timerclear(&tval);
		}

		if (cur_reply_p) {
			nb_reply ++;

			if (fr_debug_lvl) print_hex(cur_reply_p);

			if (fr_dhcp_decode(cur_reply_p) < 0) {
				fprintf(stderr, "dhcpclient: failed decoding reply\n");
				return NULL;
			}

			if (!reply_p) reply_p = cur_reply_p;

			if (cur_reply_p->code == PW_DHCP_OFFER) {
				VALUE_PAIR *vp1 = fr_pair_find_by_num(cur_reply_p->vps, 54,  DHCP_MAGIC_VENDOR, TAG_ANY); /* DHCP-DHCP-Server-Identifier */
				VALUE_PAIR *vp2 = fr_pair_find_by_num(cur_reply_p->vps, 264, DHCP_MAGIC_VENDOR, TAG_ANY); /* DHCP-Your-IP-address */
				
				if (vp1 && vp2) {
					nb_offer ++;
					offer_list = talloc_realloc(request_p, offer_list, dc_offer_t, nb_offer);
					offer_list[nb_offer-1].server_addr = vp1->vp_ipaddr;
					offer_list[nb_offer-1].offered_addr = vp2->vp_ipaddr;
				}
			}
		}
	}

	if (0 == nb_reply) {
		DEBUG("No valid DHCP reply received");
		return NULL;
	}

	/* display offer(s) received */
	if (nb_offer > 0 ) {
		DEBUG("Received %d DHCP Offer(s):\n", nb_offer);
		int i;
		for (i=0; i<nb_reply; i++) {
			char server_addr_buf[INET6_ADDRSTRLEN];
			char offered_addr_buf[INET6_ADDRSTRLEN];

			DEBUG("IP address: %s offered by DHCP server: %s\n",
				inet_ntop(AF_INET, &offer_list[i].offered_addr, offered_addr_buf, sizeof(offered_addr_buf)),
				inet_ntop(AF_INET, &offer_list[i].server_addr, server_addr_buf, sizeof(server_addr_buf))
			);
		}
	}

	return reply_p;
}
Пример #25
0
lt_dlhandle lt_dlopenext(char const *name)
{
	int		flags = RTLD_NOW;
	void		*handle;
	char		buffer[2048];
	char		*env;
	char const	*search_path;
#ifdef RTLD_GLOBAL
	if (strcmp(name, "rlm_perl") == 0) {
		flags |= RTLD_GLOBAL;
	} else
#endif
		flags |= RTLD_LOCAL;

#ifndef NDEBUG
	/*
	 *	Bind all the symbols *NOW* so we don't hit errors later
	 */
	flags |= RTLD_NOW;
#endif

	/*
	 *	Apple removed support for DYLD_LIBRARY_PATH in rootless mode.
	 */
	env = getenv("FR_LIBRARY_PATH");
	if (env) {
		DEBUG3("Ignoring libdir as FR_LIBRARY_PATH set.  Module search path will be: %s", env);
		search_path = env;
	} else {
		search_path = radlib_dir;
	}

	/*
	 *	Prefer loading our libraries by absolute path.
	 */
	if (search_path) {
		char *error;
		char *ctx, *paths, *path;
		char *p;

		fr_strerror();

		ctx = paths = talloc_strdup(NULL, search_path);
		while ((path = strsep(&paths, ":")) != NULL) {
			/*
			 *	Trim the trailing slash
			 */
			p = strrchr(path, '/');
			if (p && ((p[1] == '\0') || (p[1] == ':'))) *p = '\0';

			path = talloc_asprintf(ctx, "%s/%s%s", path, name, LT_SHREXT);

			DEBUG4("Loading %s with path: %s", name, path);

			handle = dlopen(path, flags);
			if (handle) {
				talloc_free(ctx);
				return handle;
			}
			error = dlerror();

			fr_strerror_printf("%s%s\n", fr_strerror(), error);
			DEBUG4("Loading %s failed: %s - %s", name, error,
			       (access(path, R_OK) < 0) ? fr_syserror(errno) : "No access errors");
			talloc_free(path);
		}
		talloc_free(ctx);
	}

	DEBUG4("Loading library using linker search path(s)");
	if (DEBUG_ENABLED4) {
#ifdef __APPLE__

		env = getenv("LD_LIBRARY_PATH");
		if (env) {
			DEBUG4("LD_LIBRARY_PATH            : %s", env);
		}
		env = getenv("DYLD_LIBRARY_PATH");
		if (env) {
			DEBUG4("DYLB_LIBRARY_PATH          : %s", env);
		}
		env = getenv("DYLD_FALLBACK_LIBRARY_PATH");
		if (env) {
			DEBUG4("DYLD_FALLBACK_LIBRARY_PATH : %s", env);
		}
		env = getcwd(buffer, sizeof(buffer));
		if (env) {
			DEBUG4("Current directory          : %s", env);
		}
#else
		env = getenv("LD_LIBRARY_PATH");
		if (env) {
			DEBUG4("LD_LIBRARY_PATH  : %s", env);
		}
		DEBUG4("Defaults         : /lib:/usr/lib");
#endif
	}

	strlcpy(buffer, name, sizeof(buffer));
	/*
	 *	FIXME: Make this configurable...
	 */
	strlcat(buffer, LT_SHREXT, sizeof(buffer));

	handle = dlopen(buffer, flags);
	if (!handle) {
		char *error = dlerror();

		DEBUG4("Failed with error: %s", error);
		/*
		 *	Append the error
		 */
		fr_strerror_printf("%s: %s", fr_strerror(), error);
		return NULL;
	}
	return handle;
}
Пример #26
0
VALUE_PAIR *pairparsevalue(VALUE_PAIR *vp, const char *value)
{
	char		*p, *s=0;
	const char	*cp, *cs;
	int		x;
	size_t		length;
	DICT_VALUE	*dval;

	if (!value) return NULL;

	/*
	 *	Even for integers, dates and ip addresses we
	 *	keep the original string in vp->vp_strvalue.
	 */
	if (vp->type != PW_TYPE_TLV) {
		strlcpy(vp->vp_strvalue, value, sizeof(vp->vp_strvalue));
		vp->length = strlen(vp->vp_strvalue);
	}

	switch(vp->type) {
		case PW_TYPE_STRING:
			/*
			 *	Do escaping here
			 */
			p = vp->vp_strvalue;
			cp = value;
			length = 0;

			while (*cp && (length < (sizeof(vp->vp_strvalue) - 1))) {
				char c = *cp++;

				if (c == '\\') {
					switch (*cp) {
					case 'r':
						c = '\r';
						cp++;
						break;
					case 'n':
						c = '\n';
						cp++;
						break;
					case 't':
						c = '\t';
						cp++;
						break;
					case '"':
						c = '"';
						cp++;
						break;
					case '\'':
						c = '\'';
						cp++;
						break;
					case '\\':
						c = '\\';
						cp++;
						break;
					case '`':
						c = '`';
						cp++;
						break;
					case '\0':
						c = '\\'; /* no cp++ */
						break;
					default:
						if ((cp[0] >= '0') &&
						    (cp[0] <= '9') &&
						    (cp[1] >= '0') &&
						    (cp[1] <= '9') &&
						    (cp[2] >= '0') &&
						    (cp[2] <= '9') &&
						    (sscanf(cp, "%3o", &x) == 1)) {
							c = x;
							cp += 3;
						} /* else just do '\\' */
					}
				}
				*p++ = c;
				length++;
			}
			vp->vp_strvalue[length] = '\0';
			vp->length = length;
			break;

		case PW_TYPE_IPADDR:
			/*
			 *	It's a comparison, not a real IP.
			 */
			if ((vp->operator == T_OP_REG_EQ) ||
			    (vp->operator == T_OP_REG_NE)) {
				break;
			}

			/*
			 *	FIXME: complain if hostname
			 *	cannot be resolved, or resolve later!
			 */
			s = NULL;
			if ((p = strrchr(value, '+')) != NULL && !p[1]) {
				cs = s = strdup(value);
				if (!s) return NULL;
				p = strrchr(s, '+');
				*p = 0;
				vp->flags.addport = 1;
			} else {
				p = NULL;
				cs = value;
			}

			{
				fr_ipaddr_t ipaddr;

				if (ip_hton(cs, AF_INET, &ipaddr) < 0) {
					fr_strerror_printf("Failed to find IP address for %s", cs);
					free(s);
					return NULL;
				}

				vp->vp_ipaddr = ipaddr.ipaddr.ip4addr.s_addr;
			}
			free(s);
			vp->length = 4;
			break;

		case PW_TYPE_BYTE:
			vp->length = 1;

			/*
			 *	Note that ALL integers are unsigned!
			 */
			vp->vp_integer = getint(value, &p);
			if (!*p) {
				if (vp->vp_integer > 255) {
					fr_strerror_printf("Byte value \"%s\" is larger than 255", value);
					return NULL;
				}
				break;
			}
			if (check_for_whitespace(p)) break;
			goto check_for_value;

		case PW_TYPE_SHORT:
			/*
			 *	Note that ALL integers are unsigned!
			 */
			vp->vp_integer = getint(value, &p);
			vp->length = 2;
			if (!*p) {
				if (vp->vp_integer > 65535) {
					fr_strerror_printf("Byte value \"%s\" is larger than 65535", value);
					return NULL;
				}
				break;
			}
			if (check_for_whitespace(p)) break;
			goto check_for_value;

		case PW_TYPE_INTEGER:
			/*
			 *	Note that ALL integers are unsigned!
			 */
			vp->vp_integer = getint(value, &p);
			vp->length = 4;
			if (!*p) break;
			if (check_for_whitespace(p)) break;

	check_for_value:
			/*
			 *	Look for the named value for the given
			 *	attribute.
			 */
			if ((dval = dict_valbyname(vp->attribute, value)) == NULL) {
				fr_strerror_printf("Unknown value %s for attribute %s",
					   value, vp->name);
				return NULL;
			}
			vp->vp_integer = dval->value;
			break;

		case PW_TYPE_DATE:
		  	{
				/*
				 *	time_t may be 64 bits, whule vp_date
				 *	MUST be 32-bits.  We need an
				 *	intermediary variable to handle
				 *	the conversions.
				 */
				time_t date;

				if (gettime(value, &date) < 0) {
					fr_strerror_printf("failed to parse time string "
						   "\"%s\"", value);
					return NULL;
				}

				vp->vp_date = date;
			}
			vp->length = 4;
			break;

		case PW_TYPE_ABINARY:
#ifdef ASCEND_BINARY
			if (strncasecmp(value, "0x", 2) == 0) {
				vp->type = PW_TYPE_OCTETS;
				goto do_octets;
			}

		  	if (ascend_parse_filter(vp) < 0 ) {
				char buffer[256];

				snprintf(buffer, sizeof(buffer), "failed to parse Ascend binary attribute: %s", fr_strerror());
				fr_strerror_printf("%s", buffer);
				return NULL;
			}
			break;

			/*
			 *	If Ascend binary is NOT defined,
			 *	then fall through to raw octets, so that
			 *	the user can at least make them by hand...
			 */
	do_octets:
#endif
			/* raw octets: 0x01020304... */
		case PW_TYPE_OCTETS:
			if (strncasecmp(value, "0x", 2) == 0) {
				uint8_t *us;
				cp = value + 2;
				us = vp->vp_octets;
				vp->length = 0;


				/*
				 *	There is only one character,
				 *	die.
				 */
				if ((strlen(cp) & 0x01) != 0) {
					fr_strerror_printf("Hex string is not an even length string.");
					return NULL;
				}


				while (*cp &&
				       (vp->length < MAX_STRING_LEN)) {
					unsigned int tmp;

					if (sscanf(cp, "%02x", &tmp) != 1) {
						fr_strerror_printf("Non-hex characters at %c%c", cp[0], cp[1]);
						return NULL;
					}

					cp += 2;
					*(us++) = tmp;
					vp->length++;
				}
			}
			break;

		case PW_TYPE_IFID:
			if (ifid_aton(value, (void *) &vp->vp_ifid) == NULL) {
				fr_strerror_printf("failed to parse interface-id "
					   "string \"%s\"", value);
				return NULL;
			}
			vp->length = 8;
			break;

		case PW_TYPE_IPV6ADDR:
			{
				fr_ipaddr_t ipaddr;

				if (ip_hton(value, AF_INET6, &ipaddr) < 0) {
					char buffer[1024];

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

					fr_strerror_printf("failed to parse IPv6 address "
                                                           "string \"%s\": %s", value, buffer);
					return NULL;
				}
				vp->vp_ipv6addr = ipaddr.ipaddr.ip6addr;
				vp->length = 16; /* length of IPv6 address */
			}
			break;

		case PW_TYPE_IPV6PREFIX:
			p = strchr(value, '/');
			if (!p || ((p - value) >= 256)) {
				fr_strerror_printf("invalid IPv6 prefix "
					   "string \"%s\"", value);
				return NULL;
			} else {
				unsigned int prefix;
				char buffer[256], *eptr;

				memcpy(buffer, value, p - value);
				buffer[p - value] = '\0';

				if (inet_pton(AF_INET6, buffer, vp->vp_octets + 2) <= 0) {
					fr_strerror_printf("failed to parse IPv6 address "
						   "string \"%s\"", value);
					return NULL;
				}

				prefix = strtoul(p + 1, &eptr, 10);
				if ((prefix > 128) || *eptr) {
					fr_strerror_printf("failed to parse IPv6 address "
						   "string \"%s\"", value);
					return NULL;
				}
				vp->vp_octets[1] = prefix;
			}
			vp->vp_octets[0] = '\0';
			vp->length = 16 + 2;
			break;

		case PW_TYPE_ETHERNET:
			{
				const char *c1, *c2;

				length = 0;
				cp = value;
				while (*cp) {
					if (cp[1] == ':') {
						c1 = hextab;
						c2 = memchr(hextab, tolower((int) cp[0]), 16);
						cp += 2;
					} else if ((cp[1] != '\0') &&
						   ((cp[2] == ':') ||
						    (cp[2] == '\0'))) {
						   c1 = memchr(hextab, tolower((int) cp[0]), 16);
						   c2 = memchr(hextab, tolower((int) cp[1]), 16);
						   cp += 2;
						   if (*cp == ':') cp++;
					} else {
						c1 = c2 = NULL;
					}
					if (!c1 || !c2 || (length >= sizeof(vp->vp_ether))) {
						fr_strerror_printf("failed to parse Ethernet address \"%s\"", value);
						return NULL;
					}
					vp->vp_ether[length] = ((c1-hextab)<<4) + (c2-hextab);
					length++;
				}
			}
			vp->length = 6;
			break;

		case PW_TYPE_COMBO_IP:
			if (inet_pton(AF_INET6, value, vp->vp_strvalue) > 0) {
				vp->type = PW_TYPE_IPV6ADDR;
				vp->length = 16; /* length of IPv6 address */
				vp->vp_strvalue[vp->length] = '\0';

			} else {
				fr_ipaddr_t ipaddr;

				if (ip_hton(value, AF_INET, &ipaddr) < 0) {
					fr_strerror_printf("Failed to find IPv4 address for %s", value);
					return NULL;
				}

				vp->type = PW_TYPE_IPADDR;
				vp->vp_ipaddr = ipaddr.ipaddr.ip4addr.s_addr;
				vp->length = 4;
			}
			break;

		case PW_TYPE_SIGNED: /* Damned code for 1 WiMAX attribute */
			vp->vp_signed = (int32_t) strtol(value, &p, 10);
			vp->length = 4;
			break;

		case PW_TYPE_TLV: /* don't use this! */
			if (strncasecmp(value, "0x", 2) != 0) {
				fr_strerror_printf("Invalid TLV specification");
				return NULL;
			}
			length = strlen(value + 2) / 2;
			if (vp->length < length) {
				free(vp->vp_tlv);
				vp->vp_tlv = NULL;
			}
			vp->vp_tlv = malloc(length);
			if (!vp->vp_tlv) {
				fr_strerror_printf("No memory");
				return NULL;
			}
			if (fr_hex2bin(value + 2, vp->vp_tlv,
				       length) != length) {
				fr_strerror_printf("Invalid hex data in TLV");
				return NULL;
			}
			vp->length = length;
			break;

			/*
			 *  Anything else.
			 */
		default:
			fr_strerror_printf("unknown attribute type %d", vp->type);
			return NULL;
	}

	return vp;
}
Пример #27
0
/*
 *	Compare two pairs, using the operator from "one".
 *
 *	i.e. given two attributes, it does:
 *
 *	(two->data) (one->operator) (one->data)
 *
 *	e.g. "foo" != "bar"
 *
 *	Returns true (comparison is true), or false (comparison is not true);
 *
 *	FIXME: Ignores tags!
 */
int paircmp(VALUE_PAIR *one, VALUE_PAIR *two)
{
	int compare;

	switch (one->operator) {
	case T_OP_CMP_TRUE:
		return (two != NULL);

	case T_OP_CMP_FALSE:
		return (two == NULL);

		/*
		 *	One is a regex, compile it, print two to a string,
		 *	and then do string comparisons.
		 */
	case T_OP_REG_EQ:
	case T_OP_REG_NE:
#ifndef HAVE_REGEX_H
		return -1;
#else
		{
			regex_t reg;
			char buffer[MAX_STRING_LEN * 4 + 1];

			compare = regcomp(&reg, one->vp_strvalue,
					  REG_EXTENDED);
			if (compare != 0) {
				regerror(compare, &reg, buffer, sizeof(buffer));
				fr_strerror_printf("Illegal regular expression in attribute: %s: %s",
					   one->name, buffer);
				return -1;
			}

			vp_prints_value(buffer, sizeof(buffer), two, 0);

			/*
			 *	Don't care about substring matches,
			 *	oh well...
			 */
			compare = regexec(&reg, buffer, 0, NULL, 0);

			regfree(&reg);
			if (one->operator == T_OP_REG_EQ) return (compare == 0);
			return (compare != 0);
		}
#endif

	default:		/* we're OK */
		break;
	}

	/*
	 *	After doing the previous check for special comparisons,
	 *	do the per-type comparison here.
	 */
	switch (one->type) {
	case PW_TYPE_ABINARY:
	case PW_TYPE_OCTETS:
	{
		size_t length;

		if (one->length < two->length) {
			length = one->length;
		} else {
			length = two->length;
		}

		if (length) {
			compare = memcmp(two->vp_octets, one->vp_octets,
					 length);
			if (compare != 0) break;
		}

		/*
		 *	Contents are the same.  The return code
		 *	is therefore the difference in lengths.
		 *
		 *	i.e. "0x00" is smaller than "0x0000"
		 */
		compare = two->length - one->length;
	}
		break;

	case PW_TYPE_STRING:
		compare = strcmp(two->vp_strvalue, one->vp_strvalue);
		break;

	case PW_TYPE_BYTE:
	case PW_TYPE_SHORT:
	case PW_TYPE_INTEGER:
	case PW_TYPE_DATE:
		compare = two->vp_integer - one->vp_integer;
		break;

	case PW_TYPE_IPADDR:
		compare = ntohl(two->vp_ipaddr) - ntohl(one->vp_ipaddr);
		break;

	case PW_TYPE_IPV6ADDR:
		compare = memcmp(&two->vp_ipv6addr, &one->vp_ipv6addr,
				 sizeof(two->vp_ipv6addr));
		break;

	case PW_TYPE_IPV6PREFIX:
		compare = memcmp(&two->vp_ipv6prefix, &one->vp_ipv6prefix,
				 sizeof(two->vp_ipv6prefix));
		break;

	case PW_TYPE_IFID:
		compare = memcmp(&two->vp_ifid, &one->vp_ifid,
				 sizeof(two->vp_ifid));
		break;

	default:
		return 0;	/* unknown type */
	}

	/*
	 *	Now do the operator comparison.
	 */
	switch (one->operator) {
	case T_OP_CMP_EQ:
		return (compare == 0);

	case T_OP_NE:
		return (compare != 0);

	case T_OP_LT:
		return (compare < 0);

	case T_OP_GT:
		return (compare > 0);

	case T_OP_LE:
		return (compare <= 0);

	case T_OP_GE:
		return (compare >= 0);

	default:
		return 0;
	}

	return 0;
}
Пример #28
0
/*
 *	Read a valuepair from a buffer, and advance pointer.
 *	Sets *eol to T_EOL if end of line was encountered.
 */
VALUE_PAIR *pairread(const char **ptr, FR_TOKEN *eol)
{
	char		buf[64];
	char		attr[64];
	char		value[1024], *q;
	const char	*p;
	FR_TOKEN	token, t, xlat;
	VALUE_PAIR	*vp;
	size_t		len;

	*eol = T_OP_INVALID;

	p = *ptr;
	while ((*p == ' ') || (*p == '\t')) p++;

	if (!*p) {
		*eol = T_OP_INVALID;
		fr_strerror_printf("No token read where we expected an attribute name");
		return NULL;
	}

	if (*p == '#') {
		*eol = T_HASH;
		fr_strerror_printf("Read a comment instead of a token");
		return NULL;
	}

	q = attr;
	for (len = 0; len < sizeof(attr); len++) {
		if (valid_attr_name[(int)*p]) {
			*q++ = *p++;
			continue;
		}
		break;
	}

	if (len == sizeof(attr)) {
		*eol = T_OP_INVALID;
		fr_strerror_printf("Attribute name is too long");
		return NULL;
	}

	/*
	 *	We may have Foo-Bar:= stuff, so back up.
	 */
	if ((len > 0) && (attr[len - 1] == ':')) {
		p--;
		len--;
	}

	attr[len] = '\0';
	*ptr = p;

	/* Now we should have an operator here. */
	token = gettoken(ptr, buf, sizeof(buf));
	if (token < T_EQSTART || token > T_EQEND) {
		fr_strerror_printf("expecting operator");
		return NULL;
	}

	/* Read value.  Note that empty string values are allowed */
	xlat = gettoken(ptr, value, sizeof(value));
	if (xlat == T_EOL) {
		fr_strerror_printf("failed to get value");
		return NULL;
	}

	/*
	 *	Peek at the next token. Must be T_EOL, T_COMMA, or T_HASH
	 */
	p = *ptr;
	t = gettoken(&p, buf, sizeof(buf));
	if (t != T_EOL && t != T_COMMA && t != T_HASH) {
		fr_strerror_printf("Expected end of line or comma");
		return NULL;
	}

	*eol = t;
	if (t == T_COMMA) {
		*ptr = p;
	}

	vp = NULL;
	switch (xlat) {
		/*
		 *	Make the full pair now.
		 */
	default:
		vp = pairmake(attr, value, token);
		break;

		/*
		 *	Perhaps do xlat's
		 */
	case T_DOUBLE_QUOTED_STRING:
		p = strchr(value, '%');
		if (p && (p[1] == '{')) {
			if (strlen(value) >= sizeof(vp->vp_strvalue)) {
				fr_strerror_printf("Value too long");
				return NULL;
			}
			vp = pairmake(attr, NULL, token);
			if (!vp) {
				*eol = T_OP_INVALID;
				return NULL;
			}

			strlcpy(vp->vp_strvalue, value, sizeof(vp->vp_strvalue));
			vp->flags.do_xlat = 1;
			vp->length = 0;
		} else {
			/*
			 *	Parse && escape it, as defined by the
			 *	data type.
			 */
			vp = pairmake(attr, value, token);
			if (!vp) {
				*eol = T_OP_INVALID;
				return NULL;
			}
		}
		break;

	case T_SINGLE_QUOTED_STRING:
		vp = pairmake(attr, NULL, token);
		if (!vp) {
			*eol = T_OP_INVALID;
			return NULL;
		}

		/*
		 *	String and octet types get copied verbatim.
		 */
		if ((vp->type == PW_TYPE_STRING) ||
		    (vp->type == PW_TYPE_OCTETS)) {
			strlcpy(vp->vp_strvalue, value,
				sizeof(vp->vp_strvalue));
			vp->length = strlen(vp->vp_strvalue);

			/*
			 *	Everything else gets parsed: it's
			 *	DATA, not a string!
			 */
		} else if (!pairparsevalue(vp, value)) {
			pairfree(&vp);
			*eol = T_OP_INVALID;
			return NULL;
		}
		break;

		/*
		 *	Mark the pair to be allocated later.
		 */
	case T_BACK_QUOTED_STRING:
		if (strlen(value) >= sizeof(vp->vp_strvalue)) {
			fr_strerror_printf("Value too long");
			return NULL;
		}

		vp = pairmake(attr, NULL, token);
		if (!vp) {
			*eol = T_OP_INVALID;
			return NULL;
		}

		vp->flags.do_xlat = 1;
		strlcpy(vp->vp_strvalue, value, sizeof(vp->vp_strvalue));
		vp->length = 0;
		break;
	}

	/*
	 *	If we didn't make a pair, return an error.
	 */
	if (!vp) {
		*eol = T_OP_INVALID;
		return NULL;
	}

	return vp;
}
Пример #29
0
/*
 *	Create a VALUE_PAIR from an ASCII attribute and value.
 */
VALUE_PAIR *pairmake(const char *attribute, const char *value, int operator)
{
	DICT_ATTR	*da;
	VALUE_PAIR	*vp;
	char            *tc, *ts;
	signed char     tag;
	int             found_tag;
	char		buffer[64];
	const char	*attrname = attribute;

	/*
	 *    Check for tags in 'Attribute:Tag' format.
	 */
	found_tag = 0;
	tag = 0;

	ts = strrchr(attribute, ':');
	if (ts && !ts[1]) {
		fr_strerror_printf("Invalid tag for attribute %s", attribute);
		return NULL;
	}

	if (ts && ts[1]) {
		strlcpy(buffer, attribute, sizeof(buffer));
		attrname = buffer;
		ts = strrchr(attrname, ':');

	         /* Colon found with something behind it */
	         if (ts[1] == '*' && ts[2] == 0) {
		         /* Wildcard tag for check items */
		         tag = TAG_ANY;
			 *ts = 0;
		 } else if ((ts[1] >= '0') && (ts[1] <= '9')) {
		         /* It's not a wild card tag */
		         tag = strtol(ts + 1, &tc, 0);
			 if (tc && !*tc && TAG_VALID_ZERO(tag))
				 *ts = 0;
			 else tag = 0;
		 } else {
			 fr_strerror_printf("Invalid tag for attribute %s", attribute);
			 return NULL;
		 }
		 found_tag = 1;
	}

	/*
	 *	It's not found in the dictionary, so we use
	 *	another method to create the attribute.
	 */
	if ((da = dict_attrbyname(attrname)) == NULL) {
		return pairmake_any(attrname, value, operator);
	}

	if ((vp = pairalloc(da)) == NULL) {
		fr_strerror_printf("out of memory");
		return NULL;
	}
	vp->operator = (operator == 0) ? T_OP_EQ : operator;

	/*      Check for a tag in the 'Merit' format of:
	 *      :Tag:Value.  Print an error if we already found
	 *      a tag in the Attribute.
	 */

	if (value && (*value == ':' && da->flags.has_tag)) {
	        /* If we already found a tag, this is invalid */
	        if(found_tag) {
			fr_strerror_printf("Duplicate tag %s for attribute %s",
				   value, vp->name);
			DEBUG("Duplicate tag %s for attribute %s\n",
				   value, vp->name);
		        pairbasicfree(vp);
			return NULL;
		}
	        /* Colon found and attribute allows a tag */
	        if (value[1] == '*' && value[2] == ':') {
		       /* Wildcard tag for check items */
		       tag = TAG_ANY;
		       value += 3;
		} else {
	               /* Real tag */
		       tag = strtol(value + 1, &tc, 0);
		       if (tc && *tc==':' && TAG_VALID_ZERO(tag))
			    value = tc + 1;
		       else tag = 0;
		}
		found_tag = 1;
	}

	if (found_tag) {
	  vp->flags.tag = tag;
	}

	switch (vp->operator) {
	default:
		break;

		/*
		 *      For =* and !* operators, the value is irrelevant
		 *      so we return now.
		 */
	case T_OP_CMP_TRUE:
	case T_OP_CMP_FALSE:
		vp->vp_strvalue[0] = '\0';
		vp->length = 0;
	        return vp;
		break;

		/*
		 *	Regular expression comparison of integer attributes
		 *	does a STRING comparison of the names of their
		 *	integer attributes.
		 */
	case T_OP_REG_EQ:	/* =~ */
	case T_OP_REG_NE:	/* !~ */
		if (!value) {
			fr_strerror_printf("No regular expression found in %s",
					   vp->name);
		        pairbasicfree(vp);
			return NULL;
		}
	  
		strlcpy(vp->vp_strvalue, value, sizeof(vp->vp_strvalue));
		vp->length = strlen(vp->vp_strvalue);
		/*
		 *	If anything goes wrong, this is a run-time error,
		 *	not a compile-time error.
		 */
		return vp;

	}

	/*
	 *	FIXME: if (strcasecmp(attribute, vp->name) != 0)
	 *	then the user MAY have typed in the attribute name
	 *	as Vendor-%d-Attr-%d, and the value MAY be octets.
	 *
	 *	We probably want to fix pairparsevalue to accept
	 *	octets as values for any attribute.
	 */
	if (value && (pairparsevalue(vp, value) == NULL)) {
		pairbasicfree(vp);
		return NULL;
	}

	return vp;
}
Пример #30
0
/*
 *	Create a VALUE_PAIR from an ASCII attribute and value,
 *	where the attribute name is in the form:
 *
 *	Attr-%d
 *	Vendor-%d-Attr-%d
 *	VendorName-Attr-%d
 */
static VALUE_PAIR *pairmake_any(const char *attribute, const char *value,
				int operator)
{
	int		attr, vendor;
	size_t		size;
	const char	*p = attribute;
	char		*q;
	VALUE_PAIR	*vp;

	/*
	 *	Unknown attributes MUST be of type 'octets'
	 */
	if (value && (strncasecmp(value, "0x", 2) != 0)) {
		fr_strerror_printf("Unknown attribute \"%s\" requires a hex string, not \"%s\"", attribute, value);
		return NULL;
	}

	vendor = 0;

	/*
	 *	Pull off vendor prefix first.
	 */
	if (strncasecmp(p, "Attr-", 5) != 0) {
		if (strncasecmp(p, "Vendor-", 7) == 0) {
			vendor = (int) strtol(p + 7, &q, 10);
			if ((vendor == 0) || (vendor > 65535)) {
				fr_strerror_printf("Invalid vendor value in attribute name \"%s\"", attribute);
				return NULL;
			}

			p = q;

		} else {	/* must be vendor name */
			char buffer[256];

			q = strchr(p, '-');

			if (!q) {
				fr_strerror_printf("Invalid vendor name in attribute name \"%s\"", attribute);
				return NULL;
			}

			if ((size_t) (q - p) >= sizeof(buffer)) {
				fr_strerror_printf("Vendor name too long in attribute name \"%s\"", attribute);
				return NULL;
			}

			memcpy(buffer, p, (q - p));
			buffer[q - p] = '\0';

			vendor = dict_vendorbyname(buffer);
			if (!vendor) {
				fr_strerror_printf("Unknown vendor name in attribute name \"%s\"", attribute);
				return NULL;
			}

			p = q;
		}

		if (*p != '-') {
			fr_strerror_printf("Invalid text following vendor definition in attribute name \"%s\"", attribute);
			return NULL;
		}
		p++;
	}

	/*
	 *	Attr-%d
	 */
	if (strncasecmp(p, "Attr-", 5) != 0) {
		fr_strerror_printf("Invalid format in attribute name \"%s\"", attribute);
		return NULL;
	}

	attr = strtol(p + 5, &q, 10);

	/*
	 *	Invalid, or trailing text after number.
	 */
	if ((attr == 0) || *q) {
		fr_strerror_printf("Invalid value in attribute name \"%s\"", attribute);
		return NULL;
	}

	/*
	 *	Double-check the size of attr.
	 */
	if (vendor) {
		DICT_VENDOR *dv = dict_vendorbyvalue(vendor);

		if (!dv) {
			if (attr > 255) {
			attr_error:
				fr_strerror_printf("Invalid attribute number in attribute name \"%s\"", attribute);
				return NULL;
			}

		} else switch (dv->type) {
			case 1:
				if (attr > 255) goto attr_error;
				break;

			case 2:
				if (attr > 65535) goto attr_error;
				break;

			case 4:	/* Internal limitations! */
				if (attr > 65535) goto attr_error;
				break;

			default:
				fr_strerror_printf("Internal sanity check failed");
				return NULL;
		}
	}

	attr |= vendor << 16;

	/*
	 *	We've now parsed the attribute properly, Let's create
	 *	it.  This next stop also looks the attribute up in the
	 *	dictionary, and creates the appropriate type for it.
	 */
	if ((vp = paircreate(attr, PW_TYPE_OCTETS)) == NULL) {
		fr_strerror_printf("out of memory");
		return NULL;
	}

	vp->operator = (operator == 0) ? T_OP_EQ : operator;
	if (!value) return vp;

	size = strlen(value + 2);

	/*
	 *	We may be reading something like Attr-5.  i.e.
	 *	who-ever wrote the text didn't understand it, but we
	 *	do.
	 */
	switch (vp->type) {
	default:
		if (size == (vp->length * 2)) break;
		vp->type = PW_TYPE_OCTETS;
		/* FALL-THROUGH */
		
	case PW_TYPE_OCTETS:
	case PW_TYPE_ABINARY:
		vp->length = size >> 1;
		if (vp->length > sizeof(vp->vp_octets)) {
			vp->length = sizeof(vp->vp_octets);
		}
		break;

	case PW_TYPE_STRING:
		vp->length = size >> 1;
		memset(&vp->vp_strvalue, 0, sizeof(vp->vp_strvalue));
		if (vp->length >= sizeof(vp->vp_strvalue)) {
			vp->length = sizeof(vp->vp_strvalue) - 1;
		}
		break;
	}

	if (fr_hex2bin(value + 2, vp->vp_octets, size) != vp->length) {
		fr_strerror_printf("Invalid hex string");
		free(vp);
		return NULL;
	}

	/*
	 *	Move contents around based on type.  This is
	 *	to work around the historical use of "lvalue".
	 */
	switch (vp->type) {
	case PW_TYPE_DATE:
	case PW_TYPE_IPADDR:
	case PW_TYPE_INTEGER:
		memcpy(&vp->lvalue, vp->vp_octets, sizeof(vp->lvalue));
		vp->vp_strvalue[0] = '\0';
		break;
		
	default:
		break;
	}
       
	return vp;
}