Dear OpenDNSSEC-Community,

we tested OpenDNSSEC for a few weeks now and we are pretty happy with
it.

We noticed the section "External API" on your todo list and we think,
that there is a third possibility to simplify integration into existing
systems. In addition to a "library" or "improved command line tools" the
following could be interesting too:

In our opinion there are a lot of organizations which use a database
backend to store their records for their nameservers. After an
integration of OpenDNSSEC the workflow would most probably look like the
following: exporting the zones to files, sign them and maybe importing
them again. If OpenDNSSEC could read the records of an unsigned zone out
of a database table and write the signed zone to a database table again,
integration into such a system would be simplified.

We created a proof of concept implementation of a mysql adapter for
OpenDNSSEC. It is not completed yet; currently only the "reading part"
is working and the audit of the zone fails after signing, because the
auditor still wants to get the unsigned zone out of the file.

The patch file for the mysql adapter is attached to this email as well
as the database schema with a few test records and an example of
zonelist.xml. The patch was developed using r4174. The auditor has to be
disabled (--disable-auditor) and the mysql headers have to be included
(--with-database-backend=mysql) when executing ./configure

What are your thoughts about this subject? Any suggestions and comments
are highly appreciated.

I am looking forward to hear from you.



Kind regards,

Simon Mittelberger
united-domains AG
www.united-domains.de
diff -Nur --exclude=.svn OpenDNSSEC.orig/conf/zonelist.rnc OpenDNSSEC/conf/zonelist.rnc
--- OpenDNSSEC.orig/conf/zonelist.rnc	2010-11-10 14:41:36.382962649 +0100
+++ OpenDNSSEC/conf/zonelist.rnc	2010-11-11 11:40:08.070964685 +0100
@@ -41,13 +41,21 @@
 
 		element Adapters {
 			# Where do the signer fetch the unsigned zone?
-			element Input { adapter },
+			element Input { (file_adapter | mysql_adapter) },
 			
 			# Where do the signer deliver the signed zone?
-			element Output { adapter }
+			element Output { (file_adapter | mysql_adapter) }
 		}
 	}*
 }
 
 # for now, only the file adapter is defined
-adapter = element File { xsd:string }
+file_adapter = element File { xsd:string }
+
+mysql_adapter = element MySQL {
+    element Hostname { xsd:string },
+    element Username { xsd:string },
+    element Password { xsd:string },
+    element Database { xsd:string },
+    element Table { xsd:string }
+}
diff -Nur --exclude=.svn OpenDNSSEC.orig/signer/src/adapter/adapter.c OpenDNSSEC/signer/src/adapter/adapter.c
--- OpenDNSSEC.orig/signer/src/adapter/adapter.c	2010-11-10 14:41:36.418992506 +0100
+++ OpenDNSSEC/signer/src/adapter/adapter.c	2010-11-15 15:53:22.755809347 +0100
@@ -56,6 +56,28 @@
     return adapter;
 }
 
+adapter_type*
+adapter_create_mysql(const char* hostname, const char* username,
+    const char* password, const char* database, const char* table,
+    adapter_mode type, int inbound)
+{
+    adapter_type* adapter = (adapter_type*) se_malloc(sizeof(adapter_type));
+
+    se_log_assert(hostname);
+    se_log_assert(username);
+    se_log_assert(password);
+    se_log_assert(database);
+    se_log_assert(table);
+    adapter->hostname = se_strdup(hostname);
+    adapter->username = se_strdup(username);
+    adapter->password = se_strdup(password);
+    adapter->database = se_strdup(database);
+    adapter->table = se_strdup(table);
+    adapter->type = type;
+    adapter->inbound = inbound;
+    return adapter;
+}
+
 
 /**
  * Compare adapters.
@@ -75,7 +97,29 @@
     } else if (a1->type != a2->type) {
         return a1->type - a2->type;
     }
-    return se_strcmp(a1->filename, a2->filename);
+    if (a1->type == ADAPTER_FILE) {
+        return se_strcmp(a1->filename, a2->filename);
+    }
+    /* if a1 is mysql, also a2 has to be mysql at this point */
+    if (a1->type == ADAPTER_MYSQL) {
+        int equal = 0;
+        if ((equal = se_strcmp(a1->hostname, a2->hostname)) != 0) {
+            return equal;
+        }
+        if ((equal = se_strcmp(a1->username, a2->username)) != 0) {
+            return equal;
+        }
+        if ((equal = se_strcmp(a1->password, a2->password)) != 0) {
+            return equal;
+        }
+        if ((equal = se_strcmp(a1->database, a2->database)) != 0) {
+            return equal;
+        }
+        if ((equal = se_strcmp(a1->table, a2->table)) != 0) {
+            return equal;
+        }
+        return equal;
+    }
 }
 
 
@@ -86,12 +130,41 @@
 void
 adapter_cleanup(adapter_type* adapter)
 {
+    
     if (adapter) {
-        if (adapter->filename) {
-            se_free((void*)adapter->filename);
-            adapter->filename = NULL;
+        /* we have to check, because all the string values are not NULL,
+         * when not initialized */
+        if (adapter->type == ADAPTER_FILE) {
+            
+            if (adapter->filename) {
+                se_free((void*)adapter->filename);
+                adapter->filename = NULL;
+            }
+        } else if (adapter->type == ADAPTER_MYSQL) {
+        
+            if (adapter->hostname) {
+                se_free((void*)adapter->hostname);
+                adapter->hostname = NULL;
+            }
+            if (adapter->username) {
+                se_free((void*)adapter->username);
+                adapter->username = NULL;
+            }
+            if (adapter->password) {
+                se_free((void*)adapter->password);
+                adapter->password = NULL;
+            }
+            if (adapter->database) {
+                se_free((void*)adapter->database);
+                adapter->database = NULL;
+            }
+            if (adapter->table) {
+                se_free((void*)adapter->table);
+                adapter->table = NULL;
+            }
         }
         se_free((void*)adapter);
+        adapter = NULL;
     } else {
         se_log_warning("cleanup empty adapter");
     }
diff -Nur --exclude=.svn OpenDNSSEC.orig/signer/src/adapter/adapter.h OpenDNSSEC/signer/src/adapter/adapter.h
--- OpenDNSSEC.orig/signer/src/adapter/adapter.h	2010-11-10 14:41:36.422984494 +0100
+++ OpenDNSSEC/signer/src/adapter/adapter.h	2010-11-12 11:12:03.918967780 +0100
@@ -35,6 +35,7 @@
 #define ADAPTER_ADAPTER_H
 
 #include "adapter/adfile.h"
+#include "adapter/admysql.h"
 #include "config.h"
 
 #include <stdio.h>
@@ -45,7 +46,8 @@
 enum adapter_mode_enum
 {
         ADAPTER_UNKNOWN = 0,
-        ADAPTER_FILE
+        ADAPTER_FILE,
+        ADAPTER_MYSQL
 };
 typedef enum adapter_mode_enum adapter_mode;
 
@@ -56,6 +58,11 @@
 typedef struct adapter_struct adapter_type;
 struct adapter_struct {
     const char* filename;
+    const char* hostname;
+    const char* username;
+    const char* password;
+    const char* database;
+    const char* table;
     adapter_mode type;
     int inbound;
 };
@@ -72,6 +79,22 @@
     int inbound);
 
 /**
+ * Create a new adapter for mysql.
+ * \param[in] hostname mysql hostname
+ * \param[in] username mysql username
+ * \param[in] password mysql password
+ * \param[in] database mysql database
+ * \param[in] table mysql table
+ * \param[in] type type of adapter
+ * \param[in] inbound inbound adapter or outbound
+ * \return adapter_type* created adapter
+ *
+ */
+adapter_type* adapter_create_mysql(const char* hostname, const char* username,
+    const char* password, const char* database, const char* table,
+    adapter_mode type, int inbound);
+
+/**
  * Compare adapters.
  * /param[in] a1 adapter 1
  * /param[in] a2 adapter 2
diff -Nur --exclude=.svn OpenDNSSEC.orig/signer/src/adapter/admysql.c OpenDNSSEC/signer/src/adapter/admysql.c
--- OpenDNSSEC.orig/signer/src/adapter/admysql.c	1970-01-01 01:00:00.000000000 +0100
+++ OpenDNSSEC/signer/src/adapter/admysql.c	2010-11-15 16:44:54.196288509 +0100
@@ -0,0 +1,288 @@
+/**
+ * MySQL Adapters.
+ *
+ */
+
+#include "adapter/adapter.h"
+#include "adapter/adfile.h"
+#include "config.h"
+#include "signer/zone.h"
+#include "signer/zonedata.h"
+#include "util/duration.h"
+#include "util/file.h"
+#include "util/log.h"
+#include "util/se_malloc.h"
+#include "util/util.h"
+
+#include <ldns/ldns.h> /* ldns_*() */
+#include <stdio.h> /* rewind() */
+#include <mysql.h>
+
+/**
+ *  Open a mysql connection
+ * 
+ */
+MYSQL* admysql_connect(MYSQL **mysql_connection, const char* hostname, const char* username, const char* password, const char* database) {
+    *mysql_connection = mysql_init(NULL);
+    if (*mysql_connection == NULL) {
+        se_log_error("cannot initialize a mysql connection. Error: %u: %s",
+            mysql_errno(*mysql_connection), mysql_error(*mysql_connection));
+        return NULL;
+    }
+    if (mysql_real_connect(*mysql_connection, hostname, username, password, database, 0, NULL, 0) == NULL) {
+        se_log_error("cannot establish a mysql connection. Error: %u: %s",
+            mysql_errno(*mysql_connection), mysql_error(*mysql_connection));
+        return NULL;
+    }
+    return *mysql_connection;
+}
+
+/**
+ *  Close a mysql connection
+ * 
+ */
+int admysql_close(MYSQL *mysql_connection) {
+    mysql_close(mysql_connection);
+    return 0;
+}
+
+/**
+ * Lookup SOA RR.
+ *
+ */
+static ldns_rr*
+admysql_lookup_soa_rr(MYSQL* mysql_connection, const char* table, const char* zonename)
+{
+    ldns_rr *cur_rr = NULL;
+    ldns_status status = LDNS_STATUS_OK;
+    char soa_str[300];
+    MYSQL_RES *mysql_result = NULL;
+    MYSQL_ROW row = NULL;
+    int num_rows = 0;
+    char query[150];
+    
+    sprintf(query, "select owner_name, ttl, class, type, content from %s where zone_name='%s' and type='SOA'", table, zonename);
+    if (mysql_query(mysql_connection, query) == 0) {
+        mysql_result = mysql_store_result(mysql_connection);
+        num_rows = mysql_num_rows(mysql_result);
+    }
+    /* just one SOA record per zone is allowed */
+    if (num_rows > 0 && num_rows < 2) {
+        row = mysql_fetch_row(mysql_result);
+        
+        /* check if name contains trailing . (dot) */
+        if (row[0][strlen(row[0])] == '.') {
+            /* name ttl class type content */
+            sprintf(soa_str, "%s %s %s %s %s", row[0], row[1], row[2], row[3], row[4]);
+        } else {
+            sprintf(soa_str, "%s. %s %s %s %s", row[0], row[1], row[2], row[3], row[4]);
+        }
+        
+        /* create the soa record */
+        status = ldns_rr_new_frm_str(&cur_rr, soa_str, 0, NULL, NULL);
+        
+        if (status == LDNS_STATUS_OK && ldns_rr_get_type(cur_rr) == LDNS_RR_TYPE_SOA) {
+            mysql_free_result(mysql_result);
+            mysql_result = NULL;
+            return cur_rr;
+        }
+        
+    }
+    if (cur_rr) {
+        ldns_rr_free(cur_rr);
+        cur_rr = NULL;
+    }
+    if (mysql_result) {
+        mysql_free_result(mysql_result);
+        mysql_result = NULL;
+    }
+    return NULL;
+}
+
+/**
+ * Read zone from mysql.
+ *
+ */
+static int
+admysql_read_mysql(MYSQL* mysql_connection, const char* table, struct zone_struct* zone, int include, int recover)
+{
+    int result = 0;
+    uint32_t soa_min = 0;
+    zone_type* zone_in = zone;
+    ldns_rr* rr = NULL;
+    ldns_rdf* orig = NULL;
+    ldns_status status = LDNS_STATUS_OK;
+    char rr_str[300];
+    MYSQL_RES *mysql_result = NULL;
+    MYSQL_ROW row = NULL;
+    int num_rows = 0;
+    int i = 0;
+    char query[150];
+
+    se_log_assert(mysql_connection);
+    se_log_assert(zone_in);
+    se_log_assert(zone_in->stats);
+
+    if (!include) {
+        rr = admysql_lookup_soa_rr(mysql_connection, table, zone_in->name);
+        /* default TTL: taking the SOA MINIMUM is in conflict with RFC2308 */
+        if (zone_in->signconf->soa_min) {
+            soa_min = (uint32_t) duration2time(zone_in->signconf->soa_min);
+        } else if (rr) {
+            soa_min = ldns_rdf2native_int32(ldns_rr_rdf(rr,
+                SE_SOA_RDATA_MINIMUM));
+        }
+        zone_in->zonedata->default_ttl = soa_min;
+        /* serial */
+        if (rr) {
+            zone_in->zonedata->inbound_serial =
+                ldns_rdf2native_int32(ldns_rr_rdf(rr, SE_SOA_RDATA_SERIAL));
+            ldns_rr_free(rr);
+            rr = NULL;
+        }
+
+        if (se_strcmp(zone_in->signconf->soa_serial, "keep") == 0) {
+            if (zone_in->zonedata->inbound_serial <=
+                zone_in->zonedata->outbound_serial) {
+                se_log_error("cannot read zone %s: SOA SERIAL is set to keep "
+                    "but serial %u in input zone is not incremental",
+                    zone_in->name?zone_in->name:"(null)",
+                    zone_in->zonedata->inbound_serial);
+                return 1;
+            }
+        }
+    }
+
+    /* $ORIGIN <zone name> */
+    orig = ldns_rdf_clone(zone_in->dname);
+
+    /* read records */
+    /* select all records also SOA */
+    sprintf(query, "select owner_name, ttl, class, type, content from %s where zone_name='%s'", table, zone_in->name);
+    if (mysql_query(mysql_connection, query) == 0) {
+        mysql_result = mysql_store_result(mysql_connection);
+        num_rows = mysql_num_rows(mysql_result);
+    }
+    for (i = 0; i < num_rows; i++) {
+        row = mysql_fetch_row(mysql_result);
+        
+        /* check if name contains trailing . (dot) */
+        if (row[0][strlen(row[0])] == '.') {
+            /* name ttl class type content */
+            sprintf(rr_str, "%s %s %s %s %s", row[0], row[1], row[2], row[3], row[4]);
+        } else {
+            sprintf(rr_str, "%s. %s %s %s %s", row[0], row[1], row[2], row[3], row[4]);
+        }
+        
+        /* create the soa record */
+        status = ldns_rr_new_frm_str(&rr, rr_str, 0, NULL, NULL);
+        
+        if (status != LDNS_STATUS_OK) {
+            se_log_error("error reading RR: %s", ldns_get_errorstr_by_id(status));
+            result = 1;
+            break;
+        }
+        
+        /* filter out DNSSEC RRs (except DNSKEY) from the Input File Adapter */
+        if (util_is_dnssec_rr(rr)) {
+            ldns_rr_free(rr);
+            rr = NULL;
+            continue;
+        }
+
+        /* add to the zonedata */
+        result = zone_add_rr(zone_in, rr, recover);
+        if (result != 0) {
+            se_log_error("error adding RR.");
+            break;
+        }
+        
+        zone_in->stats->sort_count += 1;
+    }
+
+    /* and done */
+    if (orig) {
+        ldns_rdf_deep_free(orig);
+        orig = NULL;
+    }
+    
+    if (mysql_result) {
+        mysql_free_result(mysql_result);
+        mysql_result = NULL;
+    }
+
+    if (!result && status != LDNS_STATUS_OK) {
+        se_log_error("error reading RR: %s", ldns_get_errorstr_by_id(status));
+        result = 1;
+    }
+
+    /* reset the default ttl (directives only affect the zone file) */
+    zone_in->zonedata->default_ttl = soa_min;
+
+    return result;
+}
+
+
+/**
+ * Read input mysql adapter
+ *
+ */
+int
+admysql_read(struct zone_struct* zone, const char* zonename, const char* hostname,
+    const char* username, const char* password, const char* database,
+    const char* table, int recover)
+{
+    MYSQL *mysql_connection = NULL;
+    zone_type* zone_in = zone;
+    int error = 0;
+
+    se_log_assert(zone_in);
+    se_log_assert(zone_in->name);
+    se_log_assert(zonename);
+    se_log_debug("read zone %s from mysql %s",
+        zone_in->name?zone_in->name:"(null)", zonename?zonename:"(null)");
+
+    /* read the zonedata */
+	admysql_connect(&mysql_connection, hostname, username, password, database);
+    if (mysql_connection) {
+        if (recover) {
+            error = admysql_read_mysql(mysql_connection, table, zone_in, 1, 1);
+        } else {
+            error = admysql_read_mysql(mysql_connection, table, zone_in, 0, 0);
+        }
+        admysql_close(mysql_connection);
+    } else {
+        error = 1;
+    }
+    if (error) {
+        se_log_error("error reading zone %s zone name %s",
+            zone_in->name?zone_in->name:"(null)",
+            zonename?zonename:"(null)");
+        return error;
+    }
+
+    if (!recover) {
+        /* remove current rrs */
+        error = zonedata_del_rrs(zone_in->zonedata);
+        if (error) {
+            se_log_error("error removing current RRs in zone %s",
+                zone_in->name?zone_in->name:"(null)");
+        }
+    }
+    return error;
+}
+
+
+/**
+ * Write zone mysql adapter
+ *
+ */
+int
+admysql_write(struct zone_struct* zone, const char* zonename, const char* hostname,
+    const char* username, const char* password, const char* database,
+    const char* table)
+{
+    
+    /* TODO: does currently nothing */
+    return 0;
+}
diff -Nur --exclude=.svn OpenDNSSEC.orig/signer/src/adapter/admysql.h OpenDNSSEC/signer/src/adapter/admysql.h
--- OpenDNSSEC.orig/signer/src/adapter/admysql.h	1970-01-01 01:00:00.000000000 +0100
+++ OpenDNSSEC/signer/src/adapter/admysql.h	2010-11-11 12:00:39.238975432 +0100
@@ -0,0 +1,53 @@
+/**
+ * MySQL Adapters.
+ *
+ */
+
+#ifndef ADAPTER_ADMYSQL_H
+#define ADAPTER_ADMYSQL_H
+
+#include "config.h"
+
+#include <stdio.h>
+
+#define MYSQL_HOSTNAME "localhost"
+#define MYSQL_USERNAME "opendnssec"
+#define MYSQL_PASSWORD "opendnssec"
+#define MYSQL_DATABASE "opendnssec"
+
+struct zone_struct;
+
+/**
+ * Read zone from MySQL DB.
+ * \param[in] zone zone structure
+ * \param[in] zonename name of the zone
+ * \param[in] hostname mysql hostname
+ * \param[in] username mysql username
+ * \param[in] password mysql password
+ * \param[in] database mysql database
+ * \param[in] table mysql table
+ * \param[in] recover true if we are recovering from backup
+ * \return 0 on success, 1 on error
+ *
+ */
+int admysql_read(struct zone_struct* zone, const char* zonename,
+	const char* hostname, const char* username, const char* password,
+	const char* database, const char* table, int recover);
+
+/**
+ * Write zone to MySQL DB.
+ * \param[in] zone zone structure
+ * \param[in] zonename name of the zone
+ * \param[in] hostname mysql hostname
+ * \param[in] username mysql username
+ * \param[in] password mysql password
+ * \param[in] database mysql database
+ * \param[in] table mysql table
+ * \return 0 on success, 1 on error
+ *
+ */
+int admysql_write(struct zone_struct* zone, const char* zonename,
+	const char* hostname, const char* username, const char* password,
+	const char* database, const char* table);
+
+#endif /* ADAPTER_ADMYSQL_H */
diff -Nur --exclude=.svn OpenDNSSEC.orig/signer/src/Makefile.am OpenDNSSEC/signer/src/Makefile.am
--- OpenDNSSEC.orig/signer/src/Makefile.am	2010-11-10 14:41:36.871963348 +0100
+++ OpenDNSSEC/signer/src/Makefile.am	2010-11-11 14:16:11.767028508 +0100
@@ -10,7 +10,8 @@
 	-I$(srcdir)/../../libhsm/src \
 	-I$(builddir)/../../libhsm/src \
 	@XML2_INCLUDES@ \
-	@LDNS_INCLUDES@
+	@LDNS_INCLUDES@ \
+	@DB_INCLUDES@
 
 signerdir =     @libdir@/opendnssec/signer
 
@@ -20,6 +21,7 @@
 ods_signerd_SOURCES=		ods-signerd.c \
 				adapter/adapter.c adapter/adapter.h \
 				adapter/adfile.c adapter/adfile.h \
+				adapter/admysql.c adapter/admysql.h \
 				daemon/cmdhandler.c daemon/cmdhandler.h \
 				daemon/cfg.c daemon/cfg.h \
 				daemon/engine.c daemon/engine.h \
@@ -52,7 +54,7 @@
 				util/se_malloc.c util/se_malloc.h \
 				util/util.c util/util.h
 
-ods_signerd_LDADD=		$(LIBHSM)
+ods_signerd_LDADD=		$(LIBHSM) @DB_LIBS@
 ods_signerd_LDADD+=		@LDNS_LIBS@ @XML2_LIBS@ @PTHREAD_LIBS@ @RT_LIBS@
 
 ods_signer_SOURCES=		ods-signer.c \
@@ -61,5 +63,5 @@
 				util/log.c util/log.h \
 				util/se_malloc.c util/se_malloc.h
 
-ods_signer_LDADD=		$(LIBHSM)
+ods_signer_LDADD=		$(LIBHSM) @DB_LIBS@
 ods_signer_LDADD+=		@LDNS_LIBS@ @XML2_LIBS@
diff -Nur --exclude=.svn OpenDNSSEC.orig/signer/src/parser/zonelistparser.c OpenDNSSEC/signer/src/parser/zonelistparser.c
--- OpenDNSSEC.orig/signer/src/parser/zonelistparser.c	2010-11-10 14:41:36.746963603 +0100
+++ OpenDNSSEC/signer/src/parser/zonelistparser.c	2010-11-15 16:08:51.106968989 +0100
@@ -79,8 +79,14 @@
 {
     xmlXPathObjectPtr xpathObj = NULL;
     xmlNode* curNode = NULL;
+    xmlNode* curNodeMysql = NULL;
     adapter_type* adapter = NULL;
     char* file = NULL;
+    char* mysql_hostname = NULL;
+    char* mysql_username = NULL;
+    char* mysql_password = NULL;
+    char* mysql_database = NULL;
+    char* mysql_table = NULL;
     int i = 0;
 
     se_log_assert(xpathCtx);
@@ -102,7 +108,38 @@
                         se_free((void*)file);
                     }
                     file = (char*) xmlNodeGetContent(curNode);
-                }
+                } else if (xmlStrEqual(curNode->name, (const xmlChar*)"MySQL")) {
+                    curNodeMysql = curNode->xmlChildrenNode;
+                    while (curNodeMysql) {
+                        if (xmlStrEqual(curNodeMysql->name, (const xmlChar*)"Hostname")) {
+                            if (mysql_hostname) {
+                                se_free((void*)mysql_hostname);
+                            }
+                            mysql_hostname = (char*) xmlNodeGetContent(curNodeMysql);
+                        } else if (xmlStrEqual(curNodeMysql->name, (const xmlChar*)"Username")) {
+                            if (mysql_username) {
+                                se_free((void*)mysql_username);
+                            }
+                            mysql_username = (char*) xmlNodeGetContent(curNodeMysql);
+                        } else if (xmlStrEqual(curNodeMysql->name, (const xmlChar*)"Password")) {
+                            if (mysql_password) {
+                                se_free((void*)mysql_password);
+                            }
+                            mysql_password = (char*) xmlNodeGetContent(curNodeMysql);
+                        } else if (xmlStrEqual(curNodeMysql->name, (const xmlChar*)"Database")) {
+                            if (mysql_database) {
+                                se_free((void*)mysql_database);
+                            }
+                            mysql_database = (char*) xmlNodeGetContent(curNodeMysql);
+                        } else if (xmlStrEqual(curNodeMysql->name, (const xmlChar*)"Table")) {
+                            if (mysql_table) {
+                                se_free((void*)mysql_table);
+                            }
+                            mysql_table = (char*) xmlNodeGetContent(curNodeMysql);
+                        }
+                        curNodeMysql = curNodeMysql->next;
+                    }
+				}
                 curNode = curNode->next;
             }
             if (file) {
@@ -112,6 +149,19 @@
                     /* [TODO] fix this ugly hack, possible bug in libxml2 ? */
                 }
                 se_free((void*)file);
+            } else if (mysql_hostname && mysql_username && mysql_password &&
+                mysql_database && mysql_table) {
+                if (!adapter) {
+                    adapter = adapter_create_mysql(mysql_hostname, mysql_username, mysql_password,
+                        mysql_database, mysql_table, ADAPTER_MYSQL, inbound);
+                } else {
+                    /* [TODO] fix this ugly hack, possible bug in libxml2 ? */
+                }
+                se_free((void*)mysql_hostname);
+                se_free((void*)mysql_username);
+                se_free((void*)mysql_password);
+                se_free((void*)mysql_database);
+                se_free((void*)mysql_table);
             }
         }
     }
diff -Nur --exclude=.svn OpenDNSSEC.orig/signer/src/signer/tools.c OpenDNSSEC/signer/src/signer/tools.c
--- OpenDNSSEC.orig/signer/src/signer/tools.c	2010-11-10 14:41:36.695961171 +0100
+++ OpenDNSSEC/signer/src/signer/tools.c	2010-11-15 16:39:29.986993612 +0100
@@ -97,6 +97,29 @@
             }
             se_free((void*)tmpname);
             break;
+        case ADAPTER_MYSQL:
+            se_log_verbose("read zone %s from input mysql adapter H:%s U:%s D:%s T:%s",
+                zone->name?zone->name:"(null)",
+                zone->inbound_adapter->hostname ?
+                zone->inbound_adapter->hostname:"(null)",
+                zone->inbound_adapter->username ?
+                zone->inbound_adapter->username:"(null)",
+                zone->inbound_adapter->database ?
+                zone->inbound_adapter->database:"(null)",
+                zone->inbound_adapter->table ?
+                zone->inbound_adapter->table:"(null)");
+            tmpname = se_build_path(zone->name, ".inbound", 0);
+            error = admysql_read(zone, zone->name,
+				zone->inbound_adapter->hostname,
+				zone->inbound_adapter->username,
+				zone->inbound_adapter->password,
+				zone->inbound_adapter->database,
+				zone->inbound_adapter->table, 0);
+			if (!error) {
+				error = adfile_write(zone, tmpname);
+			}
+            se_free((void*)tmpname);
+            break;
         case ADAPTER_UNKNOWN:
         default:
             se_log_error("read zone %s failed: unknown inbound adapter type "
@@ -311,6 +334,9 @@
         case ADAPTER_FILE:
             error = adfile_write(zone, NULL);
             break;
+        case ADAPTER_MYSQL:
+            error = admysql_write(zone, zone->name, NULL, NULL, NULL, NULL, NULL);
+            break;
         case ADAPTER_UNKNOWN:
         default:
             se_log_error("write zone %s failed: unknown outbound adapter "
diff -Nur --exclude=.svn OpenDNSSEC.orig/signer/src/signer/zone.c OpenDNSSEC/signer/src/signer/zone.c
--- OpenDNSSEC.orig/signer/src/signer/zone.c	2010-11-10 14:41:36.699961121 +0100
+++ OpenDNSSEC/signer/src/signer/zone.c	2010-11-11 12:02:39.286964210 +0100
@@ -119,10 +119,21 @@
     if (adapter_compare(z1->inbound_adapter, z2->inbound_adapter) != 0) {
         adapter_cleanup(z1->inbound_adapter);
         if (z2->inbound_adapter) {
-            z1->inbound_adapter = adapter_create(
-                z2->inbound_adapter->filename,
-                z2->inbound_adapter->type,
-                z2->inbound_adapter->inbound);
+			if (z2->inbound_adapter->type == ADAPTER_FILE) {
+				z1->inbound_adapter = adapter_create(
+					z2->inbound_adapter->filename,
+					z2->inbound_adapter->type,
+					z2->inbound_adapter->inbound);
+			} else if (z2->inbound_adapter->type == ADAPTER_MYSQL) {
+				z1->inbound_adapter = adapter_create_mysql(
+					z2->inbound_adapter->hostname,
+					z2->inbound_adapter->username,
+					z2->inbound_adapter->password,
+					z2->inbound_adapter->database,
+					z2->inbound_adapter->table,
+					z2->inbound_adapter->type,
+					z2->inbound_adapter->inbound);
+			}
         } else {
             z1->inbound_adapter = NULL;
         }
@@ -132,10 +143,21 @@
     if (adapter_compare(z1->outbound_adapter, z2->outbound_adapter) != 0) {
         adapter_cleanup(z1->outbound_adapter);
         if (z2->outbound_adapter) {
-            z1->outbound_adapter = adapter_create(
-                z2->outbound_adapter->filename,
-                z2->outbound_adapter->type,
-                z2->outbound_adapter->inbound);
+			if (z2->outbound_adapter->type == ADAPTER_FILE) {
+				z1->outbound_adapter = adapter_create(
+					z2->outbound_adapter->filename,
+					z2->outbound_adapter->type,
+					z2->outbound_adapter->inbound);
+			} else if (z2->outbound_adapter->type == ADAPTER_MYSQL) {
+				z1->outbound_adapter = adapter_create_mysql(
+					z2->outbound_adapter->hostname,
+					z2->outbound_adapter->username,
+					z2->outbound_adapter->password,
+					z2->outbound_adapter->database,
+					z2->outbound_adapter->table,
+					z2->outbound_adapter->type,
+					z2->outbound_adapter->inbound);
+			}
         } else {
             z1->outbound_adapter = NULL;
         }
CREATE TABLE unsigned_records (
    record_id INT auto_increment,
    zone_name VARCHAR(255) DEFAULT NULL,
    owner_name VARCHAR(255) DEFAULT NULL,
    ttl INT DEFAULT 1,
    class VARCHAR(6) DEFAULT NULL,
    type VARCHAR(6) DEFAULT NULL,
    content VARCHAR(255) DEFAULT NULL,
    primary key(record_id)
)type=InnoDB;

CREATE TABLE signed_records (
    record_id INT auto_increment,
    zone_name VARCHAR(255) DEFAULT NULL,
    owner_name VARCHAR(255) DEFAULT NULL,
    ttl INT DEFAULT 1,
    class VARCHAR(6) DEFAULT NULL,
    type VARCHAR(6) DEFAULT NULL,
    content VARCHAR(255) DEFAULT NULL,
    primary key(record_id)
)type=InnoDB;

INSERT INTO unsigned_records(zone_name, owner_name, ttl, class, type, content) 
VALUES('sub01.domain.tld', 'sub01.domain.tld', '1', 'IN', 'SOA', 
'ns1.sub01.domain.tld. hostmaster.sub01.domain.tld. (1 1 1 1 1)');
INSERT INTO unsigned_records(zone_name, owner_name, ttl, class, type, content) 
VALUES('sub01.domain.tld', 'sub01.domain.tld', '1', 'IN', 'A', '172.16.0.10');
INSERT INTO unsigned_records(zone_name, owner_name, ttl, class, type, content) 
VALUES('sub01.domain.tld', 'sub01.domain.tld', '1', 'IN', 'NS', 
'ns1.sub01.domain.tld.');
INSERT INTO unsigned_records(zone_name, owner_name, ttl, class, type, content) 
VALUES('sub01.domain.tld', 'ns1.sub01.domain.tld', '1', 'IN', 'A', 
'172.16.0.10');
INSERT INTO unsigned_records(zone_name, owner_name, ttl, class, type, content) 
VALUES('sub01.domain.tld', 'sub01.domain.tld', '1', 'IN', 'MX', '10 
mail1.sub01.domain.tld.');
INSERT INTO unsigned_records(zone_name, owner_name, ttl, class, type, content) 
VALUES('sub01.domain.tld', 'mail1.sub01.domain.tld', '1', 'IN', 'A', 
'172.16.0.10');

INSERT INTO unsigned_records(zone_name, owner_name, ttl, class, type, content) 
VALUES('sub01.domain.tld', 'www01.sub01.domain.tld', '1', 'IN', 'A', 
'172.16.0.10');
INSERT INTO unsigned_records(zone_name, owner_name, ttl, class, type, content) 
VALUES('sub01.domain.tld', 'www02.sub01.domain.tld', '1', 'IN', 'A', 
'172.16.0.10');
INSERT INTO unsigned_records(zone_name, owner_name, ttl, class, type, content) 
VALUES('sub01.domain.tld', 'www03.sub01.domain.tld', '1', 'IN', 'A', 
'172.16.0.10');
INSERT INTO unsigned_records(zone_name, owner_name, ttl, class, type, content) 
VALUES('sub01.domain.tld', 'www04.sub01.domain.tld', '1', 'IN', 'A', 
'172.16.0.10');
INSERT INTO unsigned_records(zone_name, owner_name, ttl, class, type, content) 
VALUES('sub01.domain.tld', 'www05.sub01.domain.tld', '1', 'IN', 'A', 
'172.16.0.10');
INSERT INTO unsigned_records(zone_name, owner_name, ttl, class, type, content) 
VALUES('sub01.domain.tld', 'www06.sub01.domain.tld', '1', 'IN', 'A', 
'172.16.0.10');
INSERT INTO unsigned_records(zone_name, owner_name, ttl, class, type, content) 
VALUES('sub01.domain.tld', 'www07.sub01.domain.tld', '1', 'IN', 'A', 
'172.16.0.10');
INSERT INTO unsigned_records(zone_name, owner_name, ttl, class, type, content) 
VALUES('sub01.domain.tld', 'www08.sub01.domain.tld', '1', 'IN', 'A', 
'172.16.0.10');
INSERT INTO unsigned_records(zone_name, owner_name, ttl, class, type, content) 
VALUES('sub01.domain.tld', 'www09.sub01.domain.tld', '1', 'IN', 'A', 
'172.16.0.10');
INSERT INTO unsigned_records(zone_name, owner_name, ttl, class, type, content) 
VALUES('sub01.domain.tld', 'www10.sub01.domain.tld', '1', 'IN', 'A', 
'172.16.0.10');

Attachment: zonelist.xml
Description: XML document

_______________________________________________
Opendnssec-user mailing list
[email protected]
https://lists.opendnssec.org/mailman/listinfo/opendnssec-user

Reply via email to