/** Add a dynamic client * */ bool client_add_dynamic(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 = talloc_typed_strdup(c, 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)) { ERROR("Cannot add client %s/%i: Virtual server %s is not the same as the virtual server for the network", fr_inet_ntoh(&c->ipaddr, buffer, sizeof(buffer)), c->ipaddr.prefix, c->server); goto error; } if (!client_add(clients, c)) { ERROR("Cannot add client %s/%i: Internal error", fr_inet_ntoh(&c->ipaddr, buffer, sizeof(buffer)), c->ipaddr.prefix); goto error; } /* * Initialize the remaining fields. */ c->dynamic = true; c->lifetime = master->lifetime; c->created = time(NULL); c->longname = talloc_typed_strdup(c, c->shortname); INFO("Adding client %s/%i with shared secret \"%s\"", fr_inet_ntoh(&c->ipaddr, buffer, sizeof(buffer)), c->ipaddr.prefix, c->secret); return true; error: client_free(c); return false; }
/** Describe the socket we opened to the LDAP server * * @param[in] listen abstracting the connection to the server. * @param[out] buffer Where to write text describing the socket. * @param[in] bufsize the length of data written to buffe.r * @return 1. */ static int proto_ldap_socket_print(rad_listen_t const *listen, char *buffer, size_t bufsize) { size_t len; proto_ldap_inst_t *inst = listen->data; char const *name = listen->proto->name; #define FORWARD len = strlen(buffer); if (len >= (bufsize + 1)) return 0;buffer += len;bufsize -= len #define ADDSTRING(_x) strlcpy(buffer, _x, bufsize);FORWARD ADDSTRING(name); ADDSTRING(" server "); fr_inet_ntoh(&inst->dst_ipaddr, buffer, bufsize); FORWARD; ADDSTRING(" port "); snprintf(buffer, bufsize, "%d", inst->dst_port); FORWARD; if (listen->server) { ADDSTRING(" bound to virtual-server "); strlcpy(buffer, listen->server, bufsize); } #undef ADDSTRING #undef FORWARD return 1; }
static int send_with_pcap(RADIUS_PACKET **reply, RADIUS_PACKET *request) { char ip[16]; char pcap_filter[255]; pcap = fr_pcap_init(NULL, iface, PCAP_INTERFACE_IN_OUT); if (!pcap) { ERROR("Failed creating pcap"); return -1; } if (fr_pcap_open(pcap) < 0) { ERROR("Failed opening interface"); talloc_free(pcap); return -1; } fr_inet_ntoh(&request->src_ipaddr, ip, sizeof(ip)); sprintf(pcap_filter, "udp and dst port %d", request->src_port); if (fr_pcap_apply_filter(pcap, pcap_filter) < 0) { ERROR("Failing setting filter"); talloc_free(pcap); return -1; } if (fr_dhcpv4_pcap_send(pcap, eth_bcast, request) < 0) { ERROR("Failed sending packet"); talloc_free(pcap); return -1; } if (!reply_expected) return 0; *reply = fr_dhcpv4_recv_raw_loop(pcap->fd, #ifdef HAVE_LINUX_IF_PACKET_H &ll, #endif request); if (!*reply) { ERROR("Error receiving reply"); talloc_free(pcap); return -1; } talloc_free(pcap); return 0; }
int proxy_tls_recv(rad_listen_t *listener) { listen_socket_t *sock = listener->data; char buffer[256]; RADIUS_PACKET *packet; uint8_t *data; ssize_t data_len; if (listener->status != RAD_LISTEN_STATUS_KNOWN) return 0; DEBUG3("Proxy SSL socket has data to read"); PTHREAD_MUTEX_LOCK(&sock->mutex); data_len = proxy_tls_read(listener); PTHREAD_MUTEX_UNLOCK(&sock->mutex); if (data_len < 0) { DEBUG("Closing TLS socket to home server"); PTHREAD_MUTEX_LOCK(&sock->mutex); tls_socket_close(listener); PTHREAD_MUTEX_UNLOCK(&sock->mutex); return 0; } if (data_len == 0) return 0; /* not done yet */ data = sock->data; packet = fr_radius_alloc(sock, false); packet->sockfd = listener->fd; packet->src_ipaddr = sock->other_ipaddr; packet->src_port = sock->other_port; packet->dst_ipaddr = sock->my_ipaddr; packet->dst_port = sock->my_port; packet->code = data[0]; packet->id = data[1]; packet->data_len = data_len; packet->data = talloc_array(packet, uint8_t, packet->data_len); memcpy(packet->data, data, packet->data_len); memcpy(packet->vector, packet->data + 4, 16); /* * FIXME: Client MIB updates? */ switch (packet->code) { case PW_CODE_ACCESS_ACCEPT: case PW_CODE_ACCESS_CHALLENGE: case PW_CODE_ACCESS_REJECT: break; #ifdef WITH_ACCOUNTING case PW_CODE_ACCOUNTING_RESPONSE: break; #endif default: /* * FIXME: Update MIB for packet types? */ ERROR("Invalid packet code %d sent to a proxy port " "from home server %s port %d - ID %d : IGNORED", packet->code, fr_inet_ntoh(&packet->src_ipaddr, buffer, sizeof(buffer)), packet->src_port, packet->id); fr_radius_free(&packet); return 0; } if (!request_proxy_reply(packet)) { fr_radius_free(&packet); return 0; } return 1; }
/** 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. */ fr_inet_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_inet_pton4(&c->src_ipaddr, cl_srcipaddr, -1, true, false, true) < 0) { cf_log_err_cs(cs, "Failed parsing src_ipaddr: %s", fr_strerror()); goto error; } break; case AF_INET6: if (fr_inet_pton6(&c->src_ipaddr, cl_srcipaddr, -1, true, false, true) < 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); }
/* * Find the client definition. */ static rlm_rcode_t CC_HINT(nonnull) mod_authorize(UNUSED void *instance, UNUSED void *thread, REQUEST *request) { size_t length; char const *value; CONF_PAIR *cp; RADCLIENT *c; CONF_SECTION *server_cs; char buffer[2048]; /* * Ensure we're only being called from the main thread, * with fake packets. */ if ((request->packet->src_port != 0) || (request->packet->vps != NULL) || (request->parent != NULL)) { REDEBUG("Improper configuration"); return RLM_MODULE_NOOP; } if (!request->client || !request->client->cs) { REDEBUG("Unknown client definition"); return RLM_MODULE_NOOP; } cp = cf_pair_find(request->client->cs, "directory"); if (!cp) { REDEBUG("No directory configuration in the client"); return RLM_MODULE_NOOP; } value = cf_pair_value(cp); if (!value) { REDEBUG("No value given for the directory entry in the client"); return RLM_MODULE_NOOP; } length = strlen(value); if (length > (sizeof(buffer) - 256)) { REDEBUG("Directory name too long"); return RLM_MODULE_NOOP; } memcpy(buffer, value, length + 1); fr_inet_ntoh(&request->packet->src_ipaddr, buffer + length, sizeof(buffer) - length - 1); /* * Read the buffer and generate the client. */ if (request->client->server) { server_cs = request->client->server_cs; } else if (request->listener) { server_cs = request->listener->server_cs; } else { return RLM_MODULE_FAIL; } c = client_read(buffer, server_cs, true); if (!c) return RLM_MODULE_FAIL; /* * Replace the client. This is more than a bit of a * hack. */ request->client = c; return RLM_MODULE_OK; }