/** Allocate a new client from a config section * * @param ctx to allocate new clients in. * @param cs to process as a client. * @param in_server Whether the client should belong to a specific virtual server. * @param with_coa If true and coa_server or coa_pool aren't specified automatically, * create a coa home_server section and add it to the client CONF_SECTION. * @return new RADCLIENT struct. */ RADCLIENT *client_afrom_cs(TALLOC_CTX *ctx, CONF_SECTION *cs, bool in_server, bool with_coa) { RADCLIENT *c; char const *name2; name2 = cf_section_name2(cs); if (!name2) { cf_log_err_cs(cs, "Missing client name"); return NULL; } /* * The size is fine.. Let's create the buffer */ c = talloc_zero(ctx, RADCLIENT); c->cs = cs; memset(&cl_ipaddr, 0, sizeof(cl_ipaddr)); if (cf_section_parse(cs, c, client_config) < 0) { cf_log_err_cs(cs, "Error parsing client section"); error: client_free(c); #ifdef WITH_TCP hs_proto = NULL; cl_srcipaddr = NULL; #endif return NULL; } /* * Global clients can set servers to use, per-server clients cannot. */ if (in_server && c->server) { cf_log_err_cs(cs, "Clients inside of an server section cannot point to a server"); goto error; } /* * Newer style client definitions with either ipaddr or ipaddr6 * config items. */ if (cf_pair_find(cs, "ipaddr") || cf_pair_find(cs, "ipv4addr") || cf_pair_find(cs, "ipv6addr")) { char buffer[128]; /* * Sets ipv4/ipv6 address and prefix. */ c->ipaddr = cl_ipaddr; /* * Set the long name to be the result of a reverse lookup on the IP address. */ ip_ntoh(&c->ipaddr, buffer, sizeof(buffer)); c->longname = talloc_typed_strdup(c, buffer); /* * Set the short name to the name2. */ if (!c->shortname) c->shortname = talloc_typed_strdup(c, name2); /* * No "ipaddr" or "ipv6addr", use old-style "client <ipaddr> {" syntax. */ } else { cf_log_err_cs(cs, "No 'ipaddr' or 'ipv4addr' or 'ipv6addr' configuration " "directive found in client %s", name2); goto error; } c->proto = IPPROTO_UDP; if (hs_proto) { if (strcmp(hs_proto, "udp") == 0) { hs_proto = NULL; #ifdef WITH_TCP } else if (strcmp(hs_proto, "tcp") == 0) { hs_proto = NULL; c->proto = IPPROTO_TCP; # ifdef WITH_TLS } else if (strcmp(hs_proto, "tls") == 0) { hs_proto = NULL; c->proto = IPPROTO_TCP; c->tls_required = true; } else if (strcmp(hs_proto, "radsec") == 0) { hs_proto = NULL; c->proto = IPPROTO_TCP; c->tls_required = true; # endif } else if (strcmp(hs_proto, "*") == 0) { hs_proto = NULL; c->proto = IPPROTO_IP; /* fake for dual */ #endif } else { cf_log_err_cs(cs, "Unknown proto \"%s\".", hs_proto); goto error; } } /* * If a src_ipaddr is specified, when we send the return packet * we will use this address instead of the src from the * request. */ if (cl_srcipaddr) { #ifdef WITH_UDPFROMTO switch (c->ipaddr.af) { case AF_INET: if (fr_pton4(&c->src_ipaddr, cl_srcipaddr, -1, true, false) < 0) { cf_log_err_cs(cs, "Failed parsing src_ipaddr: %s", fr_strerror()); goto error; } break; case AF_INET6: if (fr_pton6(&c->src_ipaddr, cl_srcipaddr, -1, true, false) < 0) { cf_log_err_cs(cs, "Failed parsing src_ipaddr: %s", fr_strerror()); goto error; } break; default: rad_assert(0); } #else WARN("Server not built with udpfromto, ignoring client src_ipaddr"); #endif cl_srcipaddr = NULL; } /* * A response_window of zero is OK, and means that it's * ignored by the rest of the server timers. */ if (timerisset(&c->response_window)) { FR_TIMEVAL_BOUND_CHECK("response_window", &c->response_window, >=, 0, 1000); FR_TIMEVAL_BOUND_CHECK("response_window", &c->response_window, <=, 60, 0); FR_TIMEVAL_BOUND_CHECK("response_window", &c->response_window, <=, main_config.max_request_time, 0); }
static RADCLIENT *client_parse(CONF_SECTION *cs, int in_server) { RADCLIENT *c; char const *name2; name2 = cf_section_name2(cs); if (!name2) { cf_log_err_cs(cs, "Missing client name"); return NULL; } /* * The size is fine.. Let's create the buffer */ c = talloc_zero(cs, RADCLIENT); c->cs = cs; memset(&cl_ipaddr, 0, sizeof(cl_ipaddr)); if (cf_section_parse(cs, c, client_config) < 0) { cf_log_err_cs(cs, "Error parsing client section"); error: client_free(c); #ifdef WITH_TCP hs_proto = NULL; cl_srcipaddr = NULL; #endif return NULL; } /* * Global clients can set servers to use per-server clients cannot. */ if (in_server && c->server) { cf_log_err_cs(cs, "Clients inside of an server section cannot point to a server"); goto error; } /* * Newer style client definitions with either ipaddr or ipaddr6 * config items. */ if (cf_pair_find(cs, "ipaddr") || cf_pair_find(cs, "ipv4addr") || cf_pair_find(cs, "ipv6addr")) { char buffer[128]; /* * Sets ipv4/ipv6 address and prefix. */ c->ipaddr = cl_ipaddr; /* * Set the long name to be the result of a reverse lookup on the IP address. */ ip_ntoh(&c->ipaddr, buffer, sizeof(buffer)); c->longname = talloc_typed_strdup(c, buffer); /* * Set the short name to the name2. */ if (!c->shortname) c->shortname = talloc_typed_strdup(c, name2); /* * No "ipaddr" or "ipv6addr", use old-style "client <ipaddr> {" syntax. */ } else { ERROR("No 'ipaddr' or 'ipv4addr' or 'ipv6addr' configuration directive found in client %s", name2); goto error; } c->proto = IPPROTO_UDP; if (hs_proto) { if (strcmp(hs_proto, "udp") == 0) { hs_proto = NULL; #ifdef WITH_TCP } else if (strcmp(hs_proto, "tcp") == 0) { hs_proto = NULL; c->proto = IPPROTO_TCP; # ifdef WITH_TLS } else if (strcmp(hs_proto, "tls") == 0) { hs_proto = NULL; c->proto = IPPROTO_TCP; c->tls_required = true; } else if (strcmp(hs_proto, "radsec") == 0) { hs_proto = NULL; c->proto = IPPROTO_TCP; c->tls_required = true; # endif } else if (strcmp(hs_proto, "*") == 0) { hs_proto = NULL; c->proto = IPPROTO_IP; /* fake for dual */ #endif } else { cf_log_err_cs(cs, "Unknown proto \"%s\".", hs_proto); goto error; } } /* * If a src_ipaddr is specified, when we send the return packet * we will use this address instead of the src from the * request. */ if (cl_srcipaddr) { #ifdef WITH_UDPFROMTO switch (c->ipaddr.af) { case AF_INET: if (fr_pton4(&c->src_ipaddr, cl_srcipaddr, 0, true, false) < 0) { cf_log_err_cs(cs, "Failed parsing src_ipaddr: %s", fr_strerror()); goto error; } break; case AF_INET6: if (fr_pton6(&c->src_ipaddr, cl_srcipaddr, 0, true, false) < 0) { cf_log_err_cs(cs, "Failed parsing src_ipaddr: %s", fr_strerror()); goto error; } break; default: rad_assert(0); } #else WARN("Server not built with udpfromto, ignoring client src_ipaddr"); #endif cl_srcipaddr = NULL; } FR_TIMEVAL_BOUND_CHECK("response_window", &c->response_window, >=, 0, 1000); FR_TIMEVAL_BOUND_CHECK("response_window", &c->response_window, <=, 60, 0); FR_TIMEVAL_BOUND_CHECK("response_window", &c->response_window, <=, main_config.max_request_time, 0); #ifdef WITH_DYNAMIC_CLIENTS if (c->client_server) { c->secret = talloc_typed_strdup(c, "testing123"); if (((c->ipaddr.af == AF_INET) && (c->ipaddr.prefix == 32)) || ((c->ipaddr.af == AF_INET6) && (c->ipaddr.prefix == 128))) { cf_log_err_cs(cs, "Dynamic clients MUST be a network, not a single IP address"); goto error; } return c; } #endif if (!c->secret || (c->secret[0] == '\0')) { #ifdef WITH_DHCP char const *value = NULL; CONF_PAIR *cp = cf_pair_find(cs, "dhcp"); if (cp) value = cf_pair_value(cp); /* * Secrets aren't needed for DHCP. */ if (value && (strcmp(value, "yes") == 0)) return c; #endif #ifdef WITH_TLS /* * If the client is TLS only, the secret can be * omitted. When omitted, it's hard-coded to * "radsec". See RFC 6614. */ if (c->tls_required) { c->secret = talloc_typed_strdup(cs, "radsec"); } else #endif { cf_log_err_cs(cs, "secret must be at least 1 character long"); 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_cs(cs, "No such home_server or home_server_pool \"%s\"", c->coa_name); goto error; } } #endif #ifdef WITH_TCP if ((c->proto == IPPROTO_TCP) || (c->proto == IPPROTO_IP)) { if ((c->limit.idle_timeout > 0) && (c->limit.idle_timeout < 5)) c->limit.idle_timeout = 5; if ((c->limit.lifetime > 0) && (c->limit.lifetime < 5)) c->limit.lifetime = 5; if ((c->limit.lifetime > 0) && (c->limit.idle_timeout > c->limit.lifetime)) c->limit.idle_timeout = 0; } #endif return c; }