Integrate more into the server. Dp4
authoraland <aland>
Sun, 20 Apr 2008 15:00:06 +0000 (15:00 +0000)
committeraland <aland>
Sun, 20 Apr 2008 15:00:06 +0000 (15:00 +0000)
src/main/client.c
src/main/dhcpd.c [new file with mode: 0644]
src/main/event.c
src/main/listen.c
src/main/modules.c

index 7e822de..eeb3092 100644 (file)
@@ -529,6 +529,18 @@ static RADCLIENT *client_parse(CONF_SECTION *cs, int in_server)
        }
 
        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");
diff --git a/src/main/dhcpd.c b/src/main/dhcpd.c
new file mode 100644 (file)
index 0000000..893104c
--- /dev/null
@@ -0,0 +1,182 @@
+/*
+ * 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 */
+
index 5334c7c..b1071a4 100644 (file)
@@ -1616,6 +1616,14 @@ static void request_post_handler(REQUEST *request)
                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;
        }
index 003752b..d990b0a 100644 (file)
@@ -29,6 +29,7 @@ RCSID("$Id$")
 #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>
@@ -84,7 +85,8 @@ RADCLIENT *client_listener_find(const rad_listen_t *listener,
 
        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;
 
@@ -196,6 +198,12 @@ static int socket_print(rad_listen_t *this, char *buffer, size_t bufsize)
                break;
 #endif
 
+#ifdef WITH_DHCP
+       case RAD_LISTEN_DHCP:
+               name = "dhcp";
+               break;
+#endif
+
        default:
                name = "??";
                break;
@@ -734,7 +742,6 @@ static int proxy_socket_decode(UNUSED rad_listen_t *listener, REQUEST *request)
                           request->home_server->secret);
 }
 
-
 #ifdef WITH_SNMP
 static int radius_snmp_recv(rad_listen_t *listener,
                            UNUSED RAD_REQUEST_FUNP *pfun,
@@ -770,6 +777,8 @@ static int radius_snmp_print(UNUSED rad_listen_t *this, char *buffer, size_t buf
 
 #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 */
 
@@ -802,6 +811,15 @@ static const rad_listen_master_t master_listen[RAD_LISTEN_MAX] = {
        { 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 */
 };
 
@@ -946,6 +964,7 @@ static rad_listen_t *listen_alloc(RAD_LISTEN_TYPE type)
        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;
@@ -1041,6 +1060,11 @@ static const FR_NAME_NUMBER listen_compare[] = {
 #ifdef WITH_VMPS
        { "vmps",       RAD_LISTEN_VQP },
 #endif
+#ifdef WITH_DHCP
+       { "dhcp",       RAD_LISTEN_DHCP },
+#else
+       { "dhcp",       RAD_LISTEN_NONE },
+#endif
        { NULL, 0 },
 };
 
index 24063c5..268d8df 100644 (file)
@@ -455,7 +455,7 @@ int indexed_modcall(int comp, int idx, REQUEST *request)
  *     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;
@@ -489,7 +489,7 @@ static int load_subcomponent_section(modcallable *parent, CONF_SECTION *cs,
         *      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",
@@ -580,7 +580,9 @@ static int load_component_section(CONF_SECTION *cs,
                        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;
@@ -782,6 +784,38 @@ static int load_byserver(CONF_SECTION *cs)
                        }
                        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, " }");