Fix possible SEGFAULT conditions
[project/odhcpd.git] / src / dhcpv6-ia.c
index b0a31a2..205b617 100644 (file)
@@ -63,6 +63,11 @@ int setup_dhcpv6_ia_interface(struct interface *iface, bool enable)
 
                if (list_empty(&iface->ia_assignments)) {
                        struct dhcpv6_assignment *border = calloc(1, sizeof(*border));
+                       if (!border) {
+                               syslog(LOG_ERR, "Calloc failed for border on interface %s", iface->ifname);
+                               return -1;
+                       }
+                       
                        border->length = 64;
                        list_add(&border->head, &iface->ia_assignments);
                }
@@ -74,6 +79,12 @@ int setup_dhcpv6_ia_interface(struct interface *iface, bool enable)
                list_for_each_entry(lease, &leases, head) {
                        // Construct entry
                        struct dhcpv6_assignment *a = calloc(1, sizeof(*a) + lease->duid_len);
+                       if (!a) {
+                               syslog(LOG_ERR, "Calloc failed for static lease assignment on interface %s",
+                                       iface->ifname);
+                               return -1;
+                       }
+
                        a->clid_len = lease->duid_len;
                        a->length = 128;
                        a->assigned = lease->hostid;
@@ -600,7 +611,7 @@ static size_t append_reply(uint8_t *buf, size_t buflen, uint16_t status,
                                                .addr = iface->ia_addr[i].addr
                                        };
                                        p.addr.s6_addr32[1] |= htonl(a->assigned);
-                                       size_t entrlen = sizeof(p);
+                                       size_t entrlen = sizeof(p) - 4;
 
 #ifdef DHCPV6_OPT_PREFIX_CLASS
                                        if (iface->ia_addr[i].has_class) {
@@ -609,14 +620,14 @@ static size_t append_reply(uint8_t *buf, size_t buflen, uint16_t status,
                                        }
 #endif
 
-                                       if (datalen + entrlen > buflen || a->assigned == 0)
+                                       if (datalen + entrlen + 4 > buflen || a->assigned == 0)
                                                continue;
 
                                        memcpy(buf + datalen, &p, sizeof(p));
 #ifdef DHCPV6_OPT_PREFIX_CLASS
                                        memcpy(buf + datalen + sizeof(p), &pclass, sizeof(pclass));
 #endif
-                                       datalen += entrlen;
+                                       datalen += entrlen + 4;
                                } else {
                                        struct dhcpv6_ia_addr n = {
                                                .type = htons(DHCPV6_OPT_IA_ADDR),
@@ -626,7 +637,7 @@ static size_t append_reply(uint8_t *buf, size_t buflen, uint16_t status,
                                                .valid = htonl(prefix_valid)
                                        };
                                        n.addr.s6_addr32[3] = htonl(a->assigned);
-                                       size_t entrlen = sizeof(n);
+                                       size_t entrlen = sizeof(n) - 4;
 
 #ifdef DHCPV6_OPT_PREFIX_CLASS
                                        if (iface->ia_addr[i].has_class) {
@@ -635,14 +646,14 @@ static size_t append_reply(uint8_t *buf, size_t buflen, uint16_t status,
                                        }
 #endif
 
-                                       if (datalen + entrlen > buflen || a->assigned == 0)
+                                       if (datalen + entrlen + 4 > buflen || a->assigned == 0)
                                                continue;
 
                                        memcpy(buf + datalen, &n, sizeof(n));
 #ifdef DHCPV6_OPT_PREFIX_CLASS
                                        memcpy(buf + datalen + sizeof(n), &pclass, sizeof(pclass));
 #endif
-                                       datalen += entrlen;
+                                       datalen += entrlen + 4;
                                }
 
                                // Calculate T1 / T2 based on non-deprecated addresses
@@ -882,6 +893,11 @@ size_t dhcpv6_handle_ia(uint8_t *buf, size_t buflen, struct interface *iface,
                                a->peer = *addr;
                                a->reconf_cnt = 0;
                                a->reconf_sent = 0;
+                               a->all_class = class_oro;
+                               a->classes_cnt = classes_cnt;
+                               a->classes = realloc(a->classes, classes_cnt * sizeof(uint16_t));
+                               if (a->classes)
+                                       memcpy(a->classes, classes, classes_cnt * sizeof(uint16_t));
                                break;
                        }
                }
@@ -893,28 +909,31 @@ size_t dhcpv6_handle_ia(uint8_t *buf, size_t buflen, struct interface *iface,
 
                        if (!a && !iface->no_dynamic_dhcp) { // Create new binding
                                a = calloc(1, sizeof(*a) + clid_len);
-                               a->clid_len = clid_len;
-                               a->iaid = ia->iaid;
-                               a->length = reqlen;
-                               a->peer = *addr;
-                               a->assigned = reqhint;
-                               a->all_class = class_oro;
-                               a->classes_cnt = classes_cnt;
-                               if (classes_cnt) {
-                                       a->classes = malloc(classes_cnt * sizeof(uint16_t));
-                                       memcpy(a->classes, classes, classes_cnt * sizeof(uint16_t));
-                               }
+                               if (a) {
+                                       a->clid_len = clid_len;
+                                       a->iaid = ia->iaid;
+                                       a->length = reqlen;
+                                       a->peer = *addr;
+                                       a->assigned = reqhint;
+                                       a->all_class = class_oro;
+                                       a->classes_cnt = classes_cnt;
+                                       if (classes_cnt) {
+                                               a->classes = malloc(classes_cnt * sizeof(uint16_t));
+                                               if (a->classes)
+                                                       memcpy(a->classes, classes, classes_cnt * sizeof(uint16_t));
+                                       }
 
-                               if (first)
-                                       memcpy(a->key, first->key, sizeof(a->key));
-                               else
-                                       odhcpd_urandom(a->key, sizeof(a->key));
-                               memcpy(a->clid_data, clid_data, clid_len);
+                                       if (first)
+                                               memcpy(a->key, first->key, sizeof(a->key));
+                                       else
+                                               odhcpd_urandom(a->key, sizeof(a->key));
+                                       memcpy(a->clid_data, clid_data, clid_len);
 
-                               if (is_pd)
-                                       while (!(assigned = assign_pd(iface, a)) && ++a->length <= 64);
-                               else
-                                       assigned = assign_na(iface, a);
+                                       if (is_pd)
+                                               while (!(assigned = assign_pd(iface, a)) && ++a->length <= 64);
+                                       else
+                                               assigned = assign_na(iface, a);
+                               }
                        }
 
                        if (!assigned || iface->ia_addr_len == 0) { // Set error status
@@ -955,8 +974,10 @@ size_t dhcpv6_handle_ia(uint8_t *buf, size_t buflen, struct interface *iface,
                        } else if (assigned && hdr->msg_type == DHCPV6_MSG_REQUEST) {
                                if (hostname_len > 0) {
                                        a->hostname = realloc(a->hostname, hostname_len + 1);
-                                       memcpy(a->hostname, hostname, hostname_len);
-                                       a->hostname[hostname_len] = 0;
+                                       if (a->hostname) {
+                                               memcpy(a->hostname, hostname, hostname_len);
+                                               a->hostname[hostname_len] = 0;
+                                       }
                                }
                                a->accept_reconf = accept_reconf;
                                apply_lease(iface, a, true);