Ejemplo n.º 1
0
RADCLIENT *client_from_request(RADCLIENT_LIST *clients, REQUEST *request)
{
	int i, *pi;
	char **p;
	RADCLIENT *c;
	char buffer[128];

	if (!clients || !request) return NULL;

	c = talloc_zero(clients, RADCLIENT);
	c->cs = request->client->cs;
	c->ipaddr.af = AF_UNSPEC;
	c->src_ipaddr.af = AF_UNSPEC;

	for (i = 0; dynamic_config[i].name != NULL; i++) {
		DICT_ATTR const *da;
		VALUE_PAIR *vp;

		da = dict_attrbyname(dynamic_config[i].name);
		if (!da) {
			DEBUG("- Cannot add client %s: attribute \"%s\"is not in the dictionary",
			      ip_ntoh(&request->packet->src_ipaddr,
				      buffer, sizeof(buffer)),
			      dynamic_config[i].name);
		error:
			client_free(c);
			return NULL;
		}

		vp = pairfind(request->config_items, da->attr, da->vendor, TAG_ANY);
		if (!vp) {
			/*
			 *	Not required.  Skip it.
			 */
			if (!dynamic_config[i].dflt) continue;

			DEBUG("- Cannot add client %s: Required attribute \"%s\" is missing.",
			      ip_ntoh(&request->packet->src_ipaddr,
				      buffer, sizeof(buffer)),
			      dynamic_config[i].name);
			goto error;
		}

		switch (dynamic_config[i].type) {
		case PW_TYPE_IPV4_ADDR:
			if (da->attr == PW_FREERADIUS_CLIENT_IP_ADDRESS) {
				c->ipaddr.af = AF_INET;
				c->ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;
				c->ipaddr.prefix = 32;
			} else if (da->attr == PW_FREERADIUS_CLIENT_SRC_IP_ADDRESS) {
#ifdef WITH_UDPFROMTO
				c->src_ipaddr.af = AF_INET;
				c->src_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;
#else
				WARN("Server not built with udpfromto, ignoring FreeRADIUS-Client-Src-IP-Address");
#endif
			}

			break;

		case PW_TYPE_IPV6_ADDR:
			if (da->attr == PW_FREERADIUS_CLIENT_IPV6_ADDRESS) {
				c->ipaddr.af = AF_INET6;
				c->ipaddr.ipaddr.ip6addr = vp->vp_ipv6addr;
				c->ipaddr.prefix = 128;
			} else if (da->attr == PW_FREERADIUS_CLIENT_SRC_IPV6_ADDRESS) {
#ifdef WITH_UDPFROMTO
				c->src_ipaddr.af = AF_INET6;
				c->src_ipaddr.ipaddr.ip6addr = vp->vp_ipv6addr;
#else
				WARN("Server not built with udpfromto, ignoring FreeRADIUS-Client-Src-IPv6-Address");
#endif
			}

			break;

		case PW_TYPE_IPV4_PREFIX:
			if (da->attr == PW_FREERADIUS_CLIENT_IP_PREFIX) {
				c->ipaddr.af = AF_INET;
				memcpy(&c->ipaddr.ipaddr.ip4addr.s_addr, &(vp->vp_ipv4prefix[2]), sizeof(c->ipaddr.ipaddr.ip4addr.s_addr));
				fr_ipaddr_mask(&c->ipaddr, (vp->vp_ipv4prefix[1] & 0x3f));
			}

			break;

		case PW_TYPE_IPV6_PREFIX:
			if (da->attr == PW_FREERADIUS_CLIENT_IPV6_PREFIX) {
				c->ipaddr.af = AF_INET6;
				memcpy(&c->ipaddr.ipaddr.ip6addr, &(vp->vp_ipv6prefix[2]), sizeof(c->ipaddr.ipaddr.ip6addr));
				fr_ipaddr_mask(&c->ipaddr, vp->vp_ipv6prefix[1]);
			}

			break;

		case PW_TYPE_STRING:
			p = (char **) ((char *) c + dynamic_config[i].offset);
			if (*p) talloc_free(*p);
			if (vp->vp_strvalue[0]) {
				*p = talloc_typed_strdup(c->cs, vp->vp_strvalue);
			} else {
				*p = NULL;
			}
			break;

		case PW_TYPE_BOOLEAN:
			pi = (int *) ((bool *) ((char *) c + dynamic_config[i].offset));
			*pi = vp->vp_integer;
			break;

		default:
			goto error;
		}
	}

	if (c->ipaddr.af == AF_UNSPEC) {
		DEBUG("- Cannot add client %s: No IP address was specified.",
		      ip_ntoh(&request->packet->src_ipaddr,
			      buffer, sizeof(buffer)));

		goto error;
	}

	{
		fr_ipaddr_t addr;

		/*
		 *	Need to apply the same mask as we set for the client
		 *	else clients created with FreeRADIUS-Client-IPv6-Prefix
		 *	or FreeRADIUS-Client-IPv4-Prefix will fail this check.
		 */
		addr = request->packet->src_ipaddr;
		fr_ipaddr_mask(&addr, c->ipaddr.prefix);
		if (fr_ipaddr_cmp(&addr, &c->ipaddr) != 0) {
			char buf2[128];

			DEBUG("- Cannot add client %s: IP address %s do not match",
			      ip_ntoh(&request->packet->src_ipaddr, buffer, sizeof(buffer)),
			      ip_ntoh(&c->ipaddr, buf2, sizeof(buf2)));
			goto error;
		}
	}

	if (!c->secret || !*c->secret) {
		DEBUG("- Cannot add client %s: No secret was specified.",
		      ip_ntoh(&request->packet->src_ipaddr,
			      buffer, sizeof(buffer)));
		goto error;
	}

	if (!client_validate(clients, request->client, c)) {
		return NULL;
	}

	if ((c->src_ipaddr.af != AF_UNSPEC) && (c->src_ipaddr.af != c->ipaddr.af)) {
		DEBUG("- Cannot add client %s: Client IP and src address are different IP version.",
		      ip_ntoh(&request->packet->src_ipaddr,
			      buffer, sizeof(buffer)));

		goto error;
	}

	return c;
}
Ejemplo n.º 2
0
/*
 *	Find a per-socket client.
 */
RADCLIENT *client_listener_find(const rad_listen_t *listener,
				const fr_ipaddr_t *ipaddr, int src_port)
{
#ifdef WITH_DYNAMIC_CLIENTS
	int rcode;
	REQUEST *request;
	RADCLIENT *created;
#endif
	time_t now;
	RADCLIENT *client;
	RADCLIENT_LIST *clients;
	listen_socket_t *sock;

	rad_assert(listener != NULL);
	rad_assert(ipaddr != NULL);

	sock = listener->data;
	clients = sock->clients;

	/*
	 *	This HAS to have been initialized previously.
	 */
	rad_assert(clients != NULL);

	client = client_find(clients, ipaddr,sock->proto);
	if (!client) {
		char name[256], buffer[128];
					
#ifdef WITH_DYNAMIC_CLIENTS
	unknown:		/* used only for dynamic clients */
#endif

		/*
		 *	DoS attack quenching, but only in daemon mode.
		 *	If they're running in debug mode, show them
		 *	every packet.
		 */
		if (debug_flag == 0) {
			static time_t last_printed = 0;

			now = time(NULL);
			if (last_printed == now) return NULL;
			
			last_printed = now;
		}

		listener->print(listener, name, sizeof(name));

		radlog(L_ERR, "Ignoring request to %s from unknown client %s port %d"
#ifdef WITH_TCP
		       " proto %s"
#endif
		       , name, inet_ntop(ipaddr->af, &ipaddr->ipaddr,
					 buffer, sizeof(buffer)), src_port
#ifdef WITH_TCP
		       , (sock->proto == IPPROTO_UDP) ? "udp" : "tcp"
#endif
		       );
		return NULL;
	}

#ifndef WITH_DYNAMIC_CLIENTS
	return client;		/* return the found client. */
#else

	/*
	 *	No server defined, and it's not dynamic.  Return it.
	 */
	if (!client->client_server && !client->dynamic) return client;

	now = time(NULL);
	
	/*
	 *	It's a dynamically generated client, check it.
	 */
	if (client->dynamic && (src_port != 0)) {
		/*
		 *	Lives forever.  Return it.
		 */
		if (client->lifetime == 0) return client;
		
		/*
		 *	Rate-limit the deletion of known clients.
		 *	This makes them last a little longer, but
		 *	prevents the server from melting down if (say)
		 *	10k clients all expire at once.
		 */
		if (now == client->last_new_client) return client;

		/*
		 *	It's not dead yet.  Return it.
		 */
		if ((client->created + client->lifetime) > now) return client;
		
		/*
		 *	This really puts them onto a queue for later
		 *	deletion.
		 */
		client_delete(clients, client);

		/*
		 *	Go find the enclosing network again.
		 */
		client = client_find(clients, ipaddr, sock->proto);

		/*
		 *	WTF?
		 */
		if (!client) goto unknown;
		if (!client->client_server) goto unknown;

		/*
		 *	At this point, 'client' is the enclosing
		 *	network that configures where dynamic clients
		 *	can be defined.
		 */
		rad_assert(client->dynamic == 0);
	} else {
		/*
		 *	The IP is unknown, so we've found an enclosing
		 *	network.  Enable DoS protection.  We only
		 *	allow one new client per second.  Known
		 *	clients aren't subject to this restriction.
		 */
		if (now == client->last_new_client) goto unknown;
	}

	client->last_new_client = now;

	request = request_alloc();
	if (!request) goto unknown;

	request->listener = listener;
	request->client = client;
	request->packet = rad_recv(listener->fd, 0x02); /* MSG_PEEK */
	if (!request->packet) {				/* badly formed, etc */
		request_free(&request);
		goto unknown;
	}
	request->reply = rad_alloc_reply(request->packet);
	if (!request->reply) {
		request_free(&request);
		goto unknown;
	}
	request->packet->timestamp = request->timestamp;
	request->number = 0;
	request->priority = listener->type;
	request->server = client->client_server;
	request->root = &mainconfig;

	/*
	 *	Run a fake request through the given virtual server.
	 *	Look for FreeRADIUS-Client-IP-Address
	 *	         FreeRADIUS-Client-Secret
	 *		...
	 *
	 *	and create the RADCLIENT structure from that.
	 */
	DEBUG("server %s {", request->server);

	rcode = module_authorize(0, request);

	DEBUG("} # server %s", request->server);

	if (rcode != RLM_MODULE_OK) {
		request_free(&request);
		goto unknown;
	}

	/*
	 *	If the client was updated by rlm_dynamic_clients,
	 *	don't create the client from attribute-value pairs.
	 */
	if (request->client == client) {
		created = client_create(clients, request);
	} else {
		created = request->client;

		/*
		 *	This frees the client if it isn't valid.
		 */
		if (!client_validate(clients, client, created)) goto unknown;
	}
	request_free(&request);

	if (!created) goto unknown;

	return created;
#endif
}
Ejemplo n.º 3
0
RADCLIENT_LIST *clients_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 = clients_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));
		clients_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_parse(cs, in_server);
		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);
			clients_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_validate(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;
}