}
if (!c->secret || !*c->secret) {
+#ifdef WITH_DHCP
+ const char *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
client_free(c);
cf_log_err(cf_sectiontoitem(cs),
"secret must be at least 1 character long");
--- /dev/null
+/*
+ * dhcp.c DHCP processing. Done poorly for now.
+ *
+ * Version: $Id$
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright 2008 The FreeRADIUS server project
+ * Copyright 2008 Alan DeKok <aland@deployingradius.com>
+ */
+
+#ifdef WITH_DHCP
+
+static int dhcp_process(REQUEST *request)
+{
+ int rcode;
+ VALUE_PAIR *vp;
+
+ vp = pairfind(request->packet->vps, DHCP2ATTR(53)); /* DHCP-Message-Type */
+ if (vp) {
+ DICT_VALUE *dv = dict_valbyattr(DHCP2ATTR(53), vp->vp_integer);
+ DEBUG("Trying sub-section dhcp %s {...}",
+ dv->name ? dv->name : "<unknown>");
+ rcode = module_post_auth(vp->vp_integer, request);
+ } else {
+ DEBUG("DHCP: Failed to find DHCP-Message-Type in packet!");
+ rcode = RLM_MODULE_FAIL;
+ }
+
+ /*
+ * Look for Relay attribute, and forward it if so...
+ */
+
+ switch (rcode) {
+ case RLM_MODULE_OK:
+ case RLM_MODULE_UPDATED:
+ if (request->packet->code == (PW_DHCP_DISCOVER)) {
+ request->reply->code = PW_DHCP_OFFER;
+ break;
+
+ } else if (request->packet->code == PW_DHCP_REQUEST) {
+ request->reply->code = PW_DHCP_ACK;
+ break;
+ }
+
+ /* FALL-THROUGH */
+
+ default:
+ case RLM_MODULE_REJECT:
+ case RLM_MODULE_FAIL:
+ case RLM_MODULE_INVALID:
+ case RLM_MODULE_NOOP:
+ request->reply->code = PW_DHCP_NAK;
+ break;
+
+ case RLM_MODULE_NOTFOUND:
+ request->reply->code = PW_DHCP_DECLINE;
+ break;
+
+ case RLM_MODULE_HANDLED:
+ request->reply->code = PW_DHCP_NAK;
+ break;
+ }
+
+ return 1;
+}
+
+static int dhcp_socket_parse(CONF_SECTION *cs, rad_listen_t *this)
+{
+ int rcode;
+ int on = 1;
+ listen_socket_t *sock;
+
+ rcode = common_socket_parse(cs, this);
+ if (rcode != 0) return rcode;
+
+ sock = this->data;
+
+ /*
+ * FIXME: Parse config file option for "do broadast = yes/no"
+ */
+ if (setsockopt(this->fd, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)) < 0) {
+ radlog(L_ERR, "Can't set broadcast option: %s\n",
+ strerror(errno));
+ return -1;
+ }
+
+ if (setsockopt(this->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) {
+ radlog(L_ERR, "Can't set re-use addres option: %s\n",
+ strerror(errno));
+ return -1;
+ }
+
+ return 0;
+}
+
+
+/*
+ * Check if an incoming request is "ok"
+ *
+ * It takes packets, not requests. It sees if the packet looks
+ * OK. If so, it does a number of sanity checks on it.
+ */
+static int dhcp_socket_recv(rad_listen_t *listener,
+ RAD_REQUEST_FUNP *pfun, REQUEST **prequest)
+{
+ RADIUS_PACKET *packet;
+ RADCLIENT *client;
+
+ packet = fr_dhcp_recv(listener->fd);
+ if (!packet) {
+ radlog(L_ERR, "%s", librad_errstr);
+ return 0;
+ }
+
+ if ((client = client_listener_find(listener,
+ &packet->src_ipaddr)) == NULL) {
+ char buffer[256];
+ radlog(L_ERR, "Ignoring request from unknown client %s port %d",
+ inet_ntop(packet->src_ipaddr.af,
+ &packet->src_ipaddr.ipaddr,
+ buffer, sizeof(buffer)),
+ packet->src_port);
+ rad_free(&packet);
+ return 0;
+ }
+
+ if (!received_request(listener, packet, prequest, client)) {
+ rad_free(&packet);
+ return 0;
+ }
+
+ *pfun = dhcp_process;
+
+ return 1;
+}
+
+
+/*
+ * Send an authentication response packet
+ */
+static int dhcp_socket_send(rad_listen_t *listener, REQUEST *request)
+{
+ rad_assert(request->listener == listener);
+ rad_assert(listener->send == dhcp_socket_send);
+
+ if (request->reply->code == 0) return 0; /* don't reply */
+
+ if (fr_dhcp_encode(request->reply, request->packet) < 0) {
+ return -1;
+ }
+
+ return fr_dhcp_send(request->reply);
+}
+
+
+static int dhcp_socket_encode(UNUSED rad_listen_t *listener, REQUEST *request)
+{
+ DEBUG2("NO ENCODE!");
+ return 0;
+ return fr_dhcp_encode(request->reply, request->packet);
+}
+
+
+static int dhcp_socket_decode(UNUSED rad_listen_t *listener, REQUEST *request)
+{
+ return fr_dhcp_decode(request->packet);
+}
+#endif /* WITH_DCHP */
+
break;
default:
+ if ((request->packet->code > 1024) &&
+ (request->packet->code < (1024 + 254 + 1))) {
+ request->next_callback = NULL;
+ child_state = REQUEST_DONE;
+ break;
+ }
+
+ radlog(L_ERR, "Unknown packet type %d", request->packet->code);
rad_panic("Unknown packet type");
break;
}
#include <freeradius-devel/modules.h>
#include <freeradius-devel/rad_assert.h>
#include <freeradius-devel/vqp.h>
+#include <freeradius-devel/dhcp.h>
#include <freeradius-devel/vmps.h>
#include <freeradius-devel/detail.h>
rad_assert((listener->type == RAD_LISTEN_AUTH) ||
(listener->type == RAD_LISTEN_ACCT) ||
- (listener->type == RAD_LISTEN_VQP));
+ (listener->type == RAD_LISTEN_VQP) ||
+ (listener->type == RAD_LISTEN_DHCP));
clients = ((listen_socket_t *)listener->data)->clients;
break;
#endif
+#ifdef WITH_DHCP
+ case RAD_LISTEN_DHCP:
+ name = "dhcp";
+ break;
+#endif
+
default:
name = "??";
break;
request->home_server->secret);
}
-
#ifdef WITH_SNMP
static int radius_snmp_recv(rad_listen_t *listener,
UNUSED RAD_REQUEST_FUNP *pfun,
#endif
+#include "dhcpd.c"
+
static const rad_listen_master_t master_listen[RAD_LISTEN_MAX] = {
{ NULL, NULL, NULL, NULL, NULL, NULL, NULL}, /* RAD_LISTEN_NONE */
{ NULL, NULL, NULL, NULL, NULL, NULL, NULL},
#endif
+#ifdef WITH_DHCP
+ /* dhcp query protocol */
+ { dhcp_socket_parse, NULL,
+ dhcp_socket_recv, dhcp_socket_send,
+ socket_print, dhcp_socket_encode, dhcp_socket_decode },
+#else
+ { NULL, NULL, NULL, NULL, NULL, NULL, NULL},
+#endif
+
{ NULL, NULL, NULL, NULL, NULL, NULL, NULL} /* RAD_LISTEN_SNMP */
};
case RAD_LISTEN_ACCT:
case RAD_LISTEN_PROXY:
case RAD_LISTEN_VQP:
+ case RAD_LISTEN_DHCP:
this->data = rad_malloc(sizeof(listen_socket_t));
memset(this->data, 0, sizeof(listen_socket_t));
break;
#ifdef WITH_VMPS
{ "vmps", RAD_LISTEN_VQP },
#endif
+#ifdef WITH_DHCP
+ { "dhcp", RAD_LISTEN_DHCP },
+#else
+ { "dhcp", RAD_LISTEN_NONE },
+#endif
{ NULL, 0 },
};
* block
*/
static int load_subcomponent_section(modcallable *parent, CONF_SECTION *cs,
- const char *server, int comp)
+ const char *server, int attr, int comp)
{
indexed_modcallable *subcomp;
modcallable *ml;
* automatically. If it isn't found, it's a serious
* error.
*/
- dval = dict_valbyname(section_type_value[comp].attr, name2);
+ dval = dict_valbyname(attr, name2);
if (!dval) {
cf_log_err(cf_sectiontoitem(cs),
"%s %s Not previously configured",
if (strcmp(name1,
section_type_value[comp].typename) == 0) {
if (!load_subcomponent_section(NULL, scs,
- server, comp)) {
+ server,
+ dattr->attr,
+ comp)) {
return -1; /* FIXME: memleak? */
}
continue;
}
flag = 1;
}
+
+#ifdef WITH_DHCP
+ if (!flag) {
+ const DICT_ATTR *dattr;
+
+ dattr = dict_attrbyname("DHCP-Message-Type");
+ if (!dattr) {
+ radlog(L_ERR, "No DHCP-Message-Type attribute");
+ return -1;
+ }
+
+ /*
+ * Handle each DHCP Message type separately.
+ */
+ for (subcs = cf_subsection_find_next(cs, NULL,
+ "dhcp");
+ subcs != NULL;
+ subcs = cf_subsection_find_next(cs, subcs,
+ "dhcp")) {
+ const char *name2 = cf_section_name2(subcs);
+
+ DEBUG2(" Module: Checking dhcp %s {...} for more modules to load", name2);
+ if (!load_subcomponent_section(NULL, subcs,
+ server,
+ dattr->attr,
+ RLM_COMPONENT_POST_AUTH)) {
+ return -1; /* FIXME: memleak? */
+ }
+ flag = 1;
+ }
+ }
+#endif
}
cf_log_info(cs, " }");