X-Git-Url: http://www.project-moonshot.org/gitweb/?a=blobdiff_plain;f=src%2Fmain%2Fclient.c;h=74875c7ba2cf820eb21eff39767c2c5a2242f9c1;hb=d8b47607f33382da1f753b7c7aea81c95d1be8a5;hp=3efcc365eabcb11869a725e24b5b2a14d54d61a0;hpb=6334a01578017be2289302a396bea899c8724466;p=freeradius.git diff --git a/src/main/client.c b/src/main/client.c index 3efcc36..74875c7 100644 --- a/src/main/client.c +++ b/src/main/client.c @@ -26,7 +26,6 @@ RCSID("$Id$") #include -#include #include #include @@ -34,6 +33,12 @@ RCSID("$Id$") #include #include +#ifdef WITH_DYNAMIC_CLIENTS +#ifdef HAVE_DIRENT_H +#include +#endif +#endif + struct radclient_list { /* * FIXME: One set of trees for IPv4, and another for IPv6? @@ -43,17 +48,52 @@ struct radclient_list { }; -#ifdef WITH_SNMP -static rbtree_t *tree_num; /* client numbers 0..N */ -static int tree_num_max; +#ifdef WITH_STATS +static rbtree_t *tree_num = NULL; /* client numbers 0..N */ +static int tree_num_max = 0; +#endif +static RADCLIENT_LIST *root_clients = NULL; + +#ifdef WITH_DYNAMIC_CLIENTS +static fr_fifo_t *deleted_clients = NULL; #endif -static RADCLIENT_LIST *root_clients; /* * Callback for freeing a client. */ void client_free(RADCLIENT *client) { +#ifdef WITH_DYNAMIC_CLIENTS + if (client->dynamic == 2) { + time_t now; + + if (!deleted_clients) { + deleted_clients = fr_fifo_create(1024, + (void *) client_free); + if (!deleted_clients) return; /* MEMLEAK */ + } + + /* + * Mark it as in the fifo, and remember when we + * pushed it. + */ + client->dynamic = 3; + client->created = now = time(NULL); /* re-set it */ + fr_fifo_push(deleted_clients, client); + + /* + * Peek at the head of the fifo. If it might + * still be in use, return. Otherwise, pop it + * from the queue and delete it. + */ + client = fr_fifo_peek(deleted_clients); + if ((client->created + 120) >= now) return; + + client = fr_fifo_pop(deleted_clients); + rad_assert(client != NULL); + } +#endif + free(client->longname); free(client->secret); free(client->shortname); @@ -62,15 +102,20 @@ void client_free(RADCLIENT *client) free(client->password); free(client->server); -#ifdef WITH_SNMP +#ifdef WITH_STATS free(client->auth); +#ifdef WITH_ACCOUNTING free(client->acct); #endif +#endif + +#ifdef WITH_DYNAMIC_CLIENTS + free(client->client_server); +#endif free(client); } - /* * Callback for comparing two clients. */ @@ -78,11 +123,26 @@ static int client_ipaddr_cmp(const void *one, const void *two) { const RADCLIENT *a = one; const RADCLIENT *b = two; +#ifndef WITH_TCP return fr_ipaddr_cmp(&a->ipaddr, &b->ipaddr); +#else + int rcode; + + rcode = fr_ipaddr_cmp(&a->ipaddr, &b->ipaddr); + if (rcode != 0) return rcode; + + /* + * Wildcard match + */ + if ((a->proto == IPPROTO_IP) || + (b->proto == IPPROTO_IP)) return 0; + + return (a->proto - b->proto); +#endif } -#ifdef WITH_SNMP +#ifdef WITH_STATS static int client_num_cmp(const void *one, const void *two) { const RADCLIENT *a = one; @@ -107,7 +167,7 @@ void clients_free(RADCLIENT_LIST *clients) } if (clients == root_clients) { -#ifdef WITH_SNMP +#ifdef WITH_STATS if (tree_num) rbtree_free(tree_num); tree_num = NULL; tree_num_max = 0; @@ -115,6 +175,12 @@ void clients_free(RADCLIENT_LIST *clients) root_clients = NULL; } +#ifdef WITH_DYNAMIC_CLIENTS + /* + * FIXME: No fr_fifo_delete() + */ +#endif + free(clients); } @@ -167,15 +233,34 @@ static int client_sane(RADCLIENT *client) sizeof(client->ipaddr.ipaddr.ip6addr)); } else if (client->prefix < 128) { - int i; uint32_t mask, *addr; addr = (uint32_t *) &client->ipaddr.ipaddr.ip6addr; - for (i = client->prefix; i < 128; i += 32) { - mask = ~0; - mask <<= ((128 - i) & 0x1f); - addr[i / 32] &= mask; + if ((client->prefix & 0x1f) == 0) { + mask = 0; + } else { + mask = ~ ((uint32_t) 0); + mask <<= (32 - (client->prefix & 0x1f)); + mask = htonl(mask); + } + + switch (client->prefix >> 5) { + case 0: + addr[0] &= mask; + mask = 0; + /* FALL-THROUGH */ + case 1: + addr[1] &= mask; + mask = 0; + /* FALL-THROUGH */ + case 2: + addr[2] &= mask; + mask = 0; + /* FALL-THROUGH */ + case 3: + addr[3] &= mask; + break; } } break; @@ -193,6 +278,8 @@ static int client_sane(RADCLIENT *client) */ int client_add(RADCLIENT_LIST *clients, RADCLIENT *client) { + RADCLIENT *old; + if (!client) { return 0; } @@ -228,14 +315,42 @@ int client_add(RADCLIENT_LIST *clients, RADCLIENT *client) } } +#define namecmp(a) ((!old->a && !client->a) || (old->a && client->a && (strcmp(old->a, client->a) == 0))) + /* * Cannot insert the same client twice. */ - if (rbtree_find(clients->trees[client->prefix], client)) { + old = rbtree_finddata(clients->trees[client->prefix], client); + if (old) { + /* + * If it's a complete duplicate, then free the new + * one, and return "OK". + */ + if ((fr_ipaddr_cmp(&old->ipaddr, &client->ipaddr) == 0) && + (old->prefix == client->prefix) && + namecmp(longname) && namecmp(secret) && + namecmp(shortname) && namecmp(nastype) && + namecmp(login) && namecmp(password) && namecmp(server) && +#ifdef WITH_DYNAMIC_CLIENTS + (old->lifetime == client->lifetime) && + namecmp(client_server) && +#endif +#ifdef WITH_COA + namecmp(coa_name) && + (old->coa_server == client->coa_server) && + (old->coa_pool == client->coa_pool) && +#endif + (old->message_authenticator == client->message_authenticator)) { + DEBUG("WARNING: Ignoring duplicate client %s", client->longname); + client_free(client); + return 1; + } + radlog(L_ERR, "Failed to add duplicate client %s", client->shortname); return 0; } +#undef namecmp /* * Other error adding client: likely is fatal. @@ -244,7 +359,7 @@ int client_add(RADCLIENT_LIST *clients, RADCLIENT *client) return 0; } -#ifdef WITH_SNMP +#ifdef WITH_STATS if (!tree_num) { tree_num = rbtree_create(client_num_cmp, NULL, 0); } @@ -258,11 +373,34 @@ int client_add(RADCLIENT_LIST *clients, RADCLIENT *client) memset(client->auth, 0, sizeof(*client->auth)); } +#ifdef WITH_ACCOUNTING if (!client->acct) { client->acct = rad_malloc(sizeof(*client->acct)); memset(client->acct, 0, sizeof(*client->acct)); } +#endif +#ifdef WITH_DYNAMIC_CLIENTS + /* + * More catching of clients added by rlm_sql. + * + * The sql modules sets the dynamic flag BEFORE calling + * us. The client_create() function sets it AFTER + * calling us. + */ + if (client->dynamic && (client->lifetime == 0)) { + RADCLIENT *network; + + /* + * If there IS an enclosing network, + * inherit the lifetime from it. + */ + network = client_find(clients, &client->ipaddr, client->proto); + if (network) { + client->lifetime = network->lifetime; + } + } +#endif client->number = tree_num_max; tree_num_max++; @@ -277,14 +415,33 @@ int client_add(RADCLIENT_LIST *clients, RADCLIENT *client) } +#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 */ + + rbtree_deletebydata(tree_num, client); + rbtree_deletebydata(clients->trees[client->prefix], client); +} +#endif + + /* * Find a client in the RADCLIENTS list by number. - * This is a support function for the SNMP code. + * This is a support function for the statistics code. */ RADCLIENT *client_findbynumber(const RADCLIENT_LIST *clients, int number) { -#ifdef WITH_SNMP +#ifdef WITH_STATS if (!clients) clients = root_clients; if (!clients) return NULL; @@ -310,7 +467,7 @@ RADCLIENT *client_findbynumber(const RADCLIENT_LIST *clients, * Find a client in the RADCLIENTS list. */ RADCLIENT *client_find(const RADCLIENT_LIST *clients, - const fr_ipaddr_t *ipaddr) + const fr_ipaddr_t *ipaddr, int proto) { int i, max_prefix; RADCLIENT myclient; @@ -337,6 +494,7 @@ RADCLIENT *client_find(const RADCLIENT_LIST *clients, myclient.prefix = i; myclient.ipaddr = *ipaddr; + myclient.proto = proto; client_sane(&myclient); /* clean up the ipaddress */ if (!clients->trees[i]) continue; @@ -356,11 +514,14 @@ RADCLIENT *client_find(const RADCLIENT_LIST *clients, */ RADCLIENT *client_find_old(const fr_ipaddr_t *ipaddr) { - return client_find(root_clients, 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, @@ -388,6 +549,27 @@ static const CONF_PARSER client_config[] = { { "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 } }; @@ -411,22 +593,30 @@ static RADCLIENT *client_parse(CONF_SECTION *cs, int in_server) memset(c, 0, sizeof(*c)); c->cs = cs; -#ifdef WITH_SNMP +#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) { - client_free(c); 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; } @@ -435,10 +625,9 @@ static RADCLIENT *client_parse(CONF_SECTION *cs, int in_server) * per-server clients cannot. */ if (in_server && c->server) { - client_free(c); cf_log_err(cf_sectiontoitem(cs), "Clients inside of an server section cannot point to a server."); - return NULL; + goto error; } /* @@ -457,11 +646,10 @@ static RADCLIENT *client_parse(CONF_SECTION *cs, int in_server) if (prefix_ptr) { c->prefix = atoi(prefix_ptr + 1); if ((c->prefix < 0) || (c->prefix > 128)) { - client_free(c); cf_log_err(cf_sectiontoitem(cs), "Invalid Prefix value '%s' for IP.", prefix_ptr + 1); - return NULL; + goto error; } /* Replace '/' with '\0' */ *prefix_ptr = '\0'; @@ -471,11 +659,10 @@ static RADCLIENT *client_parse(CONF_SECTION *cs, int in_server) * Always get the numeric representation of IP */ if (ip_hton(name2, AF_UNSPEC, &c->ipaddr) < 0) { - client_free(c); cf_log_err(cf_sectiontoitem(cs), "Failed to look up hostname %s: %s", - name2, librad_errstr); - return NULL; + name2, fr_strerror()); + goto error; } if (prefix_ptr) *prefix_ptr = '/'; @@ -494,10 +681,9 @@ static RADCLIENT *client_parse(CONF_SECTION *cs, int in_server) c->ipaddr.ipaddr.ip4addr = cl_ip4addr; if ((c->prefix < -1) || (c->prefix > 32)) { - client_free(c); cf_log_err(cf_sectiontoitem(cs), "Netmask must be between 0 and 32"); - return NULL; + goto error; } } else if (cf_pair_find(cs, "ipv6addr")) { @@ -505,16 +691,14 @@ static RADCLIENT *client_parse(CONF_SECTION *cs, int in_server) c->ipaddr.ipaddr.ip6addr = cl_ip6addr; if ((c->prefix < -1) || (c->prefix > 128)) { - client_free(c); cf_log_err(cf_sectiontoitem(cs), "Netmask must be between 0 and 128"); - return NULL; + goto error; } } else { cf_log_err(cf_sectiontoitem(cs), "No IP address defined for the client"); - client_free(c); - return NULL; + goto error; } ip_ntoh(&c->ipaddr, buffer, sizeof(buffer)); @@ -524,6 +708,31 @@ static RADCLIENT *client_parse(CONF_SECTION *cs, int in_server) * Set the short name to the name2 */ if (!c->shortname) c->shortname = strdup(name2); + + c->proto = IPPROTO_UDP; +#ifdef WITH_TCP + if (hs_proto) { + if (strcmp(hs_proto, "udp") == 0) { + free(hs_proto); + hs_proto = NULL; + + } else if (strcmp(hs_proto, "tcp") == 0) { + free(hs_proto); + hs_proto = NULL; + c->proto = IPPROTO_TCP; + + } else if (strcmp(hs_proto, "*") == 0) { + free(hs_proto); + hs_proto = NULL; + c->proto = IPPROTO_IP; /* fake for dual */ + + } else { + cf_log_err(cf_sectiontoitem(cs), + "Unknown proto \"%s\".", hs_proto); + goto error; + } + } +#endif } if (c->prefix < 0) switch (c->ipaddr.af) { @@ -537,6 +746,24 @@ static RADCLIENT *client_parse(CONF_SECTION *cs, int in_server) break; } +#ifdef WITH_DYNAMIC_CLIENTS + if (c->client_server) { + free(c->secret); + c->secret = strdup("testing123"); + + if (((c->ipaddr.af == AF_INET) && + (c->prefix == 32)) || + ((c->ipaddr.af == AF_INET6) && + (c->prefix == 128))) { + cf_log_err(cf_sectiontoitem(cs), + "Dynamic clients MUST be a network, not a single IP address."); + goto error; + } + + return c; + } +#endif + if (!c->secret || !*c->secret) { #ifdef WITH_DHCP const char *value = NULL; @@ -550,16 +777,34 @@ static RADCLIENT *client_parse(CONF_SECTION *cs, int in_server) if (value && (strcmp(value, "yes") == 0)) return c; #endif - client_free(c); cf_log_err(cf_sectiontoitem(cs), "secret must be at least 1 character long"); - return NULL; + goto error; } +#ifdef WITH_COA + /* + * Point the client to the home server pool, OR to the + * home server. This gets around the problem of figuring + * out which port to use. + */ + if (c->coa_name) { + c->coa_pool = home_pool_byname(c->coa_name, HOME_TYPE_COA); + if (!c->coa_pool) { + c->coa_server = home_server_byname(c->coa_name, + HOME_TYPE_COA); + } + if (!c->coa_pool && !c->coa_server) { + cf_log_err(cf_sectiontoitem(cs), "No such home_server or home_server_pool \"%s\"", c->coa_name); + goto error; + } + } +#endif return c; } + /* * Create the linked list of clients from the new configuration * type. This way we don't have to change too much in the other @@ -611,6 +856,89 @@ RADCLIENT_LIST *clients_parse_section(CONF_SECTION *section) * for migration issues. */ +#ifdef WITH_DYNAMIC_CLIENTS +#ifdef HAVE_DIRENT_H + if (c->client_server) { + const char *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(cf_sectiontoitem(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(cf_sectiontoitem(cs), "Error reading directory %s: %s", value, strerror(errno)); + client_free(c); + return NULL; + } + + /* + * Read the directory, ignoring "." files. + */ + while ((dp = readdir(dir)) != NULL) { + const char *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(cf_sectiontoitem(cs), + "Failed reading client file \"%s\"", buf2); + client_free(c); + return NULL; + } + + /* + * Validate, and add to the list. + */ + if (!client_validate(clients, c, dc)) { + + client_free(c); + return NULL; + } + } /* loop over the directory */ + } +#endif /* HAVE_DIRENT_H */ +#endif /* WITH_DYNAMIC_CLIENTS */ + + add_client: if (!client_add(clients, c)) { cf_log_err(cf_sectiontoitem(cs), "Failed to add client %s", @@ -618,6 +946,7 @@ RADCLIENT_LIST *clients_parse_section(CONF_SECTION *section) client_free(c); return NULL; } + } /* @@ -631,3 +960,224 @@ RADCLIENT_LIST *clients_parse_section(CONF_SECTION *section) return clients; } + +#ifdef WITH_DYNAMIC_CLIENTS +/* + * We overload this structure a lot. + */ +static const CONF_PARSER dynamic_config[] = { + { "FreeRADIUS-Client-IP-Address", PW_TYPE_IPADDR, + offsetof(RADCLIENT, ipaddr), 0, NULL }, + { "FreeRADIUS-Client-IPv6-Address", PW_TYPE_IPV6ADDR, + offsetof(RADCLIENT, ipaddr), 0, NULL }, + + { "FreeRADIUS-Client-Require-MA", PW_TYPE_BOOLEAN, + offsetof(RADCLIENT, message_authenticator), NULL, NULL }, + + { "FreeRADIUS-Client-Secret", PW_TYPE_STRING_PTR, + offsetof(RADCLIENT, secret), 0, "" }, + { "FreeRADIUS-Client-Shortname", PW_TYPE_STRING_PTR, + offsetof(RADCLIENT, shortname), 0, "" }, + { "FreeRADIUS-Client-NAS-Type", PW_TYPE_STRING_PTR, + offsetof(RADCLIENT, nastype), 0, NULL }, + { "FreeRADIUS-Client-Virtual-Server", PW_TYPE_STRING_PTR, + offsetof(RADCLIENT, server), 0, NULL }, + + { NULL, -1, 0, NULL, NULL } +}; + + +int client_validate(RADCLIENT_LIST *clients, RADCLIENT *master, RADCLIENT *c) +{ + char buffer[128]; + + /* + * No virtual server defined. Inherit the parent's + * definition. + */ + if (master->server && !c->server) { + c->server = strdup(master->server); + } + + /* + * If the client network isn't global (not tied to a + * virtual server), then ensure that this clients server + * is the same as the enclosing networks virtual server. + */ + if (master->server && + (strcmp(master->server, c->server) != 0)) { + DEBUG("- Cannot add client %s: Virtual server %s is not the same as the virtual server for the network.", + ip_ntoh(&c->ipaddr, + buffer, sizeof(buffer)), + c->server); + + goto error; + } + + if (!client_add(clients, c)) { + DEBUG("- Cannot add client %s: Internal error", + ip_ntoh(&c->ipaddr, + buffer, sizeof(buffer))); + + goto error; + } + + /* + * Initialize the remaining fields. + */ + c->dynamic = TRUE; + c->lifetime = master->lifetime; + c->created = time(NULL); + c->longname = strdup(c->shortname); + + DEBUG("- Added client %s with shared secret %s", + ip_ntoh(&c->ipaddr, buffer, sizeof(buffer)), + c->secret); + + return 1; + + error: + client_free(c); + return 0; +} + + +RADCLIENT *client_create(RADCLIENT_LIST *clients, REQUEST *request) +{ + int i, *pi; + char **p; + RADCLIENT *c; + char buffer[128]; + + if (!clients || !request) return NULL; + + c = rad_malloc(sizeof(*c)); + memset(c, 0, sizeof(*c)); + c->cs = request->client->cs; + c->ipaddr.af = AF_UNSPEC; + + for (i = 0; dynamic_config[i].name != NULL; i++) { + DICT_ATTR *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); + 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_IPADDR: + c->ipaddr.af = AF_INET; + c->ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr; + c->prefix = 32; + break; + + case PW_TYPE_IPV6ADDR: + c->ipaddr.af = AF_INET6; + c->ipaddr.ipaddr.ip6addr = vp->vp_ipv6addr; + c->prefix = 128; + break; + + case PW_TYPE_STRING_PTR: + p = (char **) ((char *) c + dynamic_config[i].offset); + if (*p) free(*p); + *p = strdup(vp->vp_strvalue); + break; + + case PW_TYPE_BOOLEAN: + pi = (int *) ((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; + } + + if (fr_ipaddr_cmp(&request->packet->src_ipaddr, &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 (!client_validate(clients, request->client, c)) { + return NULL; + } + + return c; +} + +/* + * Read a client definition from the given filename. + */ +RADCLIENT *client_read(const char *filename, int in_server, int flag) +{ + const char *p; + RADCLIENT *c; + CONF_SECTION *cs; + char buffer[256]; + + if (!filename) return NULL; + + cs = cf_file_read(filename); + if (!cs) return NULL; + + c = client_parse(cf_section_sub_find(cs, "client"), in_server); + + p = strrchr(filename, FR_DIR_SEP); + if (p) { + p++; + } else { + p = filename; + } + + if (!flag) return c; + + /* + * Additional validations + */ + ip_ntoh(&c->ipaddr, buffer, sizeof(buffer)); + if (strcmp(p, buffer) != 0) { + DEBUG("Invalid client definition in %s: IP address %s does not match name %s", filename, buffer, p); + client_free(c); + return NULL; + } + + + + return c; +} +#endif