+
+#ifdef WITH_DYNAMIC_CLIENTS
+void client_delete(RADCLIENT_LIST *clients, RADCLIENT *client)
+{
+ if (!client) return;
+
+ if (!clients) clients = root_clients;
+
+ if (!client->dynamic) return;
+
+ rad_assert((client->prefix >= 0) && (client->prefix <= 128));
+
+ client->dynamic = 2; /* signal to client_free */
+
+#ifdef WITH_STATS
+ rbtree_deletebydata(tree_num, client);
+#endif
+ rbtree_deletebydata(clients->trees[client->prefix], client);
+}
+#endif
+
+
+/*
+ * Find a client in the RADCLIENTS list by number.
+ * This is a support function for the statistics code.
+ */
+RADCLIENT *client_findbynumber(const RADCLIENT_LIST *clients,
+ int number)
+{
+#ifdef WITH_STATS
+ if (!clients) clients = root_clients;
+
+ if (!clients) return NULL;
+
+ if (number >= tree_num_max) return NULL;
+
+ if (tree_num) {
+ RADCLIENT myclient;
+
+ myclient.number = number;
+
+ return rbtree_finddata(tree_num, &myclient);
+ }
+#else
+ clients = clients; /* -Wunused */
+ number = number; /* -Wunused */
+#endif
+ return NULL;
+}
+
+
+/*
+ * Find a client in the RADCLIENTS list.
+ */
+RADCLIENT *client_find(const RADCLIENT_LIST *clients,
+ const fr_ipaddr_t *ipaddr, int proto)
+{
+ int i, max_prefix;
+ RADCLIENT myclient;
+
+ if (!clients) clients = root_clients;
+
+ if (!clients || !ipaddr) return NULL;
+
+ switch (ipaddr->af) {
+ case AF_INET:
+ max_prefix = 32;
+ break;
+
+ case AF_INET6:
+ max_prefix = 128;
+ break;
+
+ default :
+ return NULL;
+ }
+
+ for (i = max_prefix; i >= clients->min_prefix; i--) {
+ void *data;
+
+ myclient.prefix = i;
+ myclient.ipaddr = *ipaddr;
+ myclient.proto = proto;
+ client_sane(&myclient); /* clean up the ipaddress */
+
+ if (!clients->trees[i]) continue;
+
+ data = rbtree_finddata(clients->trees[i], &myclient);
+ if (data) {
+ return data;
+ }
+ }
+
+ return NULL;
+}
+
+
+/*
+ * Old wrapper for client_find
+ */
+RADCLIENT *client_find_old(const fr_ipaddr_t *ipaddr)
+{
+ return client_find(root_clients, ipaddr, IPPROTO_UDP);
+}
+
+static struct in_addr cl_ip4addr;
+static struct in6_addr cl_ip6addr;
+#ifdef WITH_TCP
+static char *hs_proto = NULL;
+#endif
+
+static const CONF_PARSER client_config[] = {
+ { "ipaddr", PW_TYPE_IPADDR,
+ 0, &cl_ip4addr, NULL },
+ { "ipv6addr", PW_TYPE_IPV6ADDR,
+ 0, &cl_ip6addr, NULL },
+ { "netmask", PW_TYPE_INTEGER,
+ offsetof(RADCLIENT, prefix), 0, NULL },
+
+ { "require_message_authenticator", PW_TYPE_BOOLEAN,
+ offsetof(RADCLIENT, message_authenticator), 0, "no" },
+
+ { "secret", PW_TYPE_STRING_PTR,
+ offsetof(RADCLIENT, secret), 0, NULL },
+ { "shortname", PW_TYPE_STRING_PTR,
+ offsetof(RADCLIENT, shortname), 0, NULL },
+ { "nastype", PW_TYPE_STRING_PTR,
+ offsetof(RADCLIENT, nastype), 0, NULL },
+ { "login", PW_TYPE_STRING_PTR,
+ offsetof(RADCLIENT, login), 0, NULL },
+ { "password", PW_TYPE_STRING_PTR,
+ offsetof(RADCLIENT, password), 0, NULL },
+ { "virtual_server", PW_TYPE_STRING_PTR,
+ offsetof(RADCLIENT, server), 0, NULL },
+ { "server", PW_TYPE_STRING_PTR, /* compatability with 2.0-pre */
+ offsetof(RADCLIENT, server), 0, NULL },
+
+#ifdef WITH_TCP
+ { "proto", PW_TYPE_STRING_PTR,
+ 0, &hs_proto, NULL },
+ { "max_connections", PW_TYPE_INTEGER,
+ offsetof(RADCLIENT, max_connections), 0, "16" },
+#endif
+
+#ifdef WITH_DYNAMIC_CLIENTS
+ { "dynamic_clients", PW_TYPE_STRING_PTR,
+ offsetof(RADCLIENT, client_server), 0, NULL },
+ { "lifetime", PW_TYPE_INTEGER,
+ offsetof(RADCLIENT, lifetime), 0, NULL },
+ { "rate_limit", PW_TYPE_BOOLEAN,
+ offsetof(RADCLIENT, rate_limit), 0, NULL },
+#endif
+
+#ifdef WITH_COA
+ { "coa_server", PW_TYPE_STRING_PTR,
+ offsetof(RADCLIENT, coa_name), 0, NULL },
+#endif
+
+ { NULL, -1, 0, NULL, NULL }
+};
+
+
+static RADCLIENT *client_parse(CONF_SECTION *cs, int in_server)
+{
+ RADCLIENT *c;
+ const char *name2;
+
+ name2 = cf_section_name2(cs);
+ if (!name2) {
+ cf_log_err(cf_sectiontoitem(cs),
+ "Missing client name");
+ return NULL;
+ }
+
+ /*
+ * The size is fine.. Let's create the buffer
+ */
+ c = rad_malloc(sizeof(*c));
+ memset(c, 0, sizeof(*c));
+ c->cs = cs;
+
+#ifdef WITH_STATS
+ c->auth = rad_malloc(sizeof(*c->auth));
+ memset(c->auth, 0, sizeof(*c->auth));
+
+#ifdef WITH_ACCOUNTING
+ c->acct = rad_malloc(sizeof(*c->acct));
+ memset(c->acct, 0, sizeof(*c->acct));
+#endif
+#endif
+
+ memset(&cl_ip4addr, 0, sizeof(cl_ip4addr));
+ memset(&cl_ip6addr, 0, sizeof(cl_ip6addr));
+ c->prefix = -1;
+
+ if (cf_section_parse(cs, c, client_config) < 0) {
+ cf_log_err(cf_sectiontoitem(cs),
+ "Error parsing client section.");
+ error:
+ client_free(c);
+#ifdef WITH_TCP
+ free(hs_proto);
+ hs_proto = NULL;
+#endif
+
+ return NULL;
+ }
+
+ /*
+ * Global clients can set servers to use,
+ * per-server clients cannot.
+ */
+ if (in_server && c->server) {
+ cf_log_err(cf_sectiontoitem(cs),
+ "Clients inside of an server section cannot point to a server.");
+ goto error;
+ }
+
+ /*
+ * No "ipaddr" or "ipv6addr", use old-style
+ * "client <ipaddr> {" syntax.
+ */
+ if (!cf_pair_find(cs, "ipaddr") &&
+ !cf_pair_find(cs, "ipv6addr")) {
+ char *prefix_ptr;
+
+ prefix_ptr = strchr(name2, '/');
+
+ /*
+ * Look for prefixes.
+ */
+ if (prefix_ptr) {
+ c->prefix = atoi(prefix_ptr + 1);
+ if ((c->prefix < 0) || (c->prefix > 128)) {
+ cf_log_err(cf_sectiontoitem(cs),
+ "Invalid Prefix value '%s' for IP.",
+ prefix_ptr + 1);
+ goto error;