]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[#53,!125] Ensure that the HW address and client id buffers are non-zero.
authorMarcin Siodelski <marcin@isc.org>
Fri, 16 Nov 2018 18:30:27 +0000 (19:30 +0100)
committerMarcin Siodelski <marcin@isc.org>
Wed, 21 Nov 2018 19:18:48 +0000 (14:18 -0500)
src/lib/dhcpsrv/mysql_lease_mgr.cc

index 696a829cb80aaaf605c5429c4b7f9c53794c58b2..6e241fe174c89f987016d9611c38db601ffbb077 100644 (file)
@@ -464,14 +464,18 @@ public:
             if (hwaddr) {
                 hwaddr_ = hwaddr->hwaddr_;
                 hwaddr_length_ = hwaddr->hwaddr_.size();
-                bind_[1].buffer_type = MYSQL_TYPE_BLOB;
 
-                // Do not reference the buffer if it is empty and just leave it
-                // set to 0 (memset set it to 0 above).
-                if (!hwaddr_.empty()) {
-                    bind_[1].buffer = reinterpret_cast<char*>(&(hwaddr_[0]));
+                // Make sure that the buffer has at least length of 1, even if
+                // empty HW address is passed. This is required by some of the
+                // MySQL connectors that the buffer is set to non-null value.
+                // Otherwise, null value would be inserted into the database,
+                // rather than empty string.
+                if (hwaddr_.empty()) {
+                    hwaddr_.resize(1);
                 }
 
+                bind_[1].buffer_type = MYSQL_TYPE_BLOB;
+                bind_[1].buffer = reinterpret_cast<char*>(&(hwaddr_[0]));
                 bind_[1].buffer_length = hwaddr_length_;
                 bind_[1].length = &hwaddr_length_;
             } else {
@@ -490,14 +494,18 @@ public:
             if (lease_->client_id_) {
                 client_id_ = lease_->client_id_->getClientId();
                 client_id_length_ = client_id_.size();
-                bind_[2].buffer_type = MYSQL_TYPE_BLOB;
 
-                // Do not reference the buffer if it is empty and just leave it
-                // set to 0 (memset set it to 0 above).
-                if (!client_id_.empty()) {
-                    bind_[2].buffer = reinterpret_cast<char*>(&client_id_[0]);
+                // Make sure that the buffer has at least length of 1, even if
+                // empty HW address is passed. This is required by some of the
+                // MySQL connectors that the buffer is set to non-null value.
+                // Otherwise, null value would be inserted into the database,
+                // rather than empty string.
+                if (client_id_.empty()) {
+                    client_id_.resize(1);
                 }
 
+                bind_[2].buffer_type = MYSQL_TYPE_BLOB;
+                bind_[2].buffer = reinterpret_cast<char*>(&client_id_[0]);
                 bind_[2].buffer_length = client_id_length_;
                 bind_[2].length = &client_id_length_;
                 // bind_[2].is_null = &MLM_FALSE; // commented out for performance
@@ -1035,6 +1043,16 @@ public:
             if (hwaddr) {
                 hwaddr_ = hwaddr->hwaddr_;
                 hwaddr_length_ = hwaddr->hwaddr_.size();
+
+                // Make sure that the buffer has at least length of 1, even if
+                // empty HW address is passed. This is required by some of the
+                // MySQL connectors that the buffer is set to non-null value.
+                // Otherwise, null value would be inserted into the database,
+                // rather than empty string.
+                if (hwaddr_.empty()) {
+                    hwaddr_.resize(1);
+                }
+
                 bind_[12].buffer_type = MYSQL_TYPE_BLOB;
                 bind_[12].buffer = reinterpret_cast<char*>(&(hwaddr_[0]));
                 bind_[12].buffer_length = hwaddr_length_;
@@ -1912,20 +1930,20 @@ MySqlLeaseMgr::getLease4(const HWAddr& hwaddr) const {
     inbind[0].buffer_type = MYSQL_TYPE_BLOB;
 
     unsigned long hwaddr_length = hwaddr.hwaddr_.size();
-    uint8_t* data = 0;
-
-    // Only reference the buffer if the buffer has any data. Otherwise
-    // leave it set to 0 (memset set it to 0 above).
-    if (hwaddr_length > 0) {
-        // As "buffer" is "char*" - even though the data is being read - we need
-        // to cast away the "const"ness as well as reinterpreting the data as
-        // a "char*". (We could avoid the "const_cast" by copying the data to a
-        // local variable, but as the data is only being read, this introduces
-        // an unnecessary copy).
-        data = const_cast<uint8_t*>(&hwaddr.hwaddr_[0]);
-        inbind[0].buffer = reinterpret_cast<char*>(data);
-    }
 
+    // If the data happens to be empty, we have to create a 1 byte dummy
+    // buffer and pass it to the binding.
+    std::vector<uint8_t> single_byte_vec(1);
+
+    // As "buffer" is "char*" - even though the data is being read - we need
+    // to cast away the "const"ness as well as reinterpreting the data as
+    // a "char*". (We could avoid the "const_cast" by copying the data to a
+    // local variable, but as the data is only being read, this introduces
+    // an unnecessary copy).
+    uint8_t* data = !hwaddr.hwaddr_.empty() ? const_cast<uint8_t*>(&hwaddr.hwaddr_[0])
+        : &single_byte_vec[0];
+
+    inbind[0].buffer = reinterpret_cast<char*>(data);
     inbind[0].buffer_length = hwaddr_length;
     inbind[0].length = &hwaddr_length;
 
@@ -1949,20 +1967,20 @@ MySqlLeaseMgr::getLease4(const HWAddr& hwaddr, SubnetID subnet_id) const {
     inbind[0].buffer_type = MYSQL_TYPE_BLOB;
 
     unsigned long hwaddr_length = hwaddr.hwaddr_.size();
-    uint8_t* data = 0;
-
-    // Only reference the buffer if the buffer has any data. Otherwise
-    // leave it set to 0 (memset set it to 0 above).
-    if (hwaddr_length > 0) {
-        // As "buffer" is "char*" - even though the data is being read - we need
-        // to cast away the "const"ness as well as reinterpreting the data as
-        // a "char*". (We could avoid the "const_cast" by copying the data to a
-        // local variable, but as the data is only being read, this introduces
-        // an unnecessary copy).
-        data = const_cast<uint8_t*>(&hwaddr.hwaddr_[0]);
-        inbind[0].buffer = reinterpret_cast<char*>(data);
-    }
 
+    // If the data happens to be empty, we have to create a 1 byte dummy
+    // buffer and pass it to the binding.
+    std::vector<uint8_t> single_byte_vec(1);
+
+    // As "buffer" is "char*" - even though the data is being read - we need
+    // to cast away the "const"ness as well as reinterpreting the data as
+    // a "char*". (We could avoid the "const_cast" by copying the data to a
+    // local variable, but as the data is only being read, this introduces
+    // an unnecessary copy).
+    uint8_t* data = !hwaddr.hwaddr_.empty() ? const_cast<uint8_t*>(&hwaddr.hwaddr_[0])
+        : &single_byte_vec[0];
+
+    inbind[0].buffer = reinterpret_cast<char*>(data);
     inbind[0].buffer_length = hwaddr_length;
     inbind[0].length = &hwaddr_length;
 
@@ -1991,12 +2009,13 @@ MySqlLeaseMgr::getLease4(const ClientId& clientid) const {
     std::vector<uint8_t> client_data = clientid.getClientId();
     unsigned long client_data_length = client_data.size();
 
-    // Only reference the buffer if the buffer has any data. Otherwise
-    // leave it set to 0 (memset set it to 0 above).
-    if (client_data_length > 0) {
-        inbind[0].buffer = reinterpret_cast<char*>(&client_data[0]);
+    // If the data happens to be empty, we have to create a 1 byte dummy
+    // buffer and pass it to the binding.
+    if (client_data.empty()) {
+        client_data.resize(1);
     }
 
+    inbind[0].buffer = reinterpret_cast<char*>(&client_data[0]);
     inbind[0].buffer_length = client_data_length;
     inbind[0].length = &client_data_length;
 
@@ -2027,16 +2046,18 @@ MySqlLeaseMgr::getLease4(const ClientId& clientid, SubnetID subnet_id) const {
     MYSQL_BIND inbind[2];
     memset(inbind, 0, sizeof(inbind));
 
+    inbind[0].buffer_type = MYSQL_TYPE_BLOB;
+
     std::vector<uint8_t> client_data = clientid.getClientId();
     unsigned long client_data_length = client_data.size();
-    inbind[0].buffer_type = MYSQL_TYPE_BLOB;
 
-    // Only reference the buffer if the buffer has any data. Otherwise
-    // leave it set to 0 (memset set it to 0 above).
-    if (client_data_length > 0) {
-        inbind[0].buffer = reinterpret_cast<char*>(&client_data[0]);
+    // If the data happens to be empty, we have to create a 1 byte dummy
+    // buffer and pass it to the binding.
+    if (client_data.empty()) {
+        client_data.resize(1);
     }
 
+    inbind[0].buffer = reinterpret_cast<char*>(&client_data[0]);
     inbind[0].buffer_length = client_data_length;
     inbind[0].length = &client_data_length;