[BACK]Return to dlz_mysql_driver.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / external / mpl / bind / dist / contrib / dlz / drivers

Annotation of src/external/mpl/bind/dist/contrib/dlz/drivers/dlz_mysql_driver.c, Revision 1.3

1.2       christos    1: /*     $NetBSD: dlz_mysql_driver.c,v 1.1.1.9 2014/12/10 03:34:31 christos Exp $        */
1.1       christos    2:
                      3: /*
                      4:  * Copyright (C) 2002 Stichting NLnet, Netherlands, stichting@nlnet.nl.
                      5:  *
                      6:  * Permission to use, copy, modify, and distribute this software for any
                      7:  * purpose with or without fee is hereby granted, provided that the
                      8:  * above copyright notice and this permission notice appear in all
                      9:  * copies.
                     10:  *
                     11:  * THE SOFTWARE IS PROVIDED "AS IS" AND STICHTING NLNET
                     12:  * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
                     13:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
                     14:  * STICHTING NLNET BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
                     15:  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
                     16:  * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
                     17:  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE
                     18:  * USE OR PERFORMANCE OF THIS SOFTWARE.
                     19:  *
                     20:  * The development of Dynamically Loadable Zones (DLZ) for Bind 9 was
                     21:  * conceived and contributed by Rob Butler.
                     22:  *
                     23:  * Permission to use, copy, modify, and distribute this software for any
                     24:  * purpose with or without fee is hereby granted, provided that the
                     25:  * above copyright notice and this permission notice appear in all
                     26:  * copies.
                     27:  *
                     28:  * THE SOFTWARE IS PROVIDED "AS IS" AND ROB BUTLER
                     29:  * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
                     30:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
                     31:  * ROB BUTLER BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
                     32:  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
                     33:  * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
                     34:  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE
                     35:  * USE OR PERFORMANCE OF THIS SOFTWARE.
                     36:  */
                     37:
                     38: /*
                     39:  * Copyright (C) 1999-2001, 2016  Internet Systems Consortium, Inc. ("ISC")
                     40:  *
                     41:  * This Source Code Form is subject to the terms of the Mozilla Public
                     42:  * License, v. 2.0. If a copy of the MPL was not distributed with this
                     43:  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
                     44:  */
                     45:
                     46: #ifdef DLZ_MYSQL
1.3     ! christos   47: #include <mysql.h>
1.1       christos   48: #include <stdio.h>
1.3     ! christos   49: #include <stdlib.h>
1.1       christos   50: #include <string.h>
                     51:
                     52: #include <isc/mem.h>
                     53: #include <isc/platform.h>
                     54: #include <isc/print.h>
                     55: #include <isc/result.h>
                     56: #include <isc/string.h>
                     57: #include <isc/util.h>
                     58:
1.3     ! christos   59: #include <dns/log.h>
        !            60: #include <dns/result.h>
        !            61: #include <dns/sdlz.h>
1.1       christos   62:
1.3     ! christos   63: #include <dlz/dlz_mysql_driver.h>
1.1       christos   64: #include <dlz/sdlz_helper.h>
1.3     ! christos   65: #include <named/globals.h>
1.1       christos   66:
1.3     ! christos   67: #if !defined(LIBMARIADB) && MYSQL_VERSION_ID >= 80000
        !            68: typedef bool my_bool;
        !            69: #endif /* !defined(LIBMARIADB) && MYSQL_VERSION_ID >= 80000 */
1.1       christos   70:
                     71: static dns_sdlzimplementation_t *dlz_mysql = NULL;
                     72:
                     73: #define dbc_search_limit 30
1.3     ! christos   74: #define ALLNODES        1
        !            75: #define ALLOWXFR        2
        !            76: #define AUTHORITY       3
        !            77: #define FINDZONE        4
        !            78: #define COUNTZONE       5
        !            79: #define LOOKUP          6
1.1       christos   80:
                     81: #define safeGet(in) in == NULL ? "" : in
                     82:
                     83: /*
                     84:  * Private methods
                     85:  */
                     86:
                     87: /*%
                     88:  * Allocates memory for a new string, and then constructs the new
                     89:  * string by "escaping" the input string.  The new string is
                     90:  * safe to be used in queries.  This is necessary because we cannot
                     91:  * be sure of what types of strings are passed to us, and we don't
                     92:  * want special characters in the string causing problems.
                     93:  */
                     94:
                     95: static char *
                     96: mysqldrv_escape_string(MYSQL *mysql, const char *instr) {
                     97:        char *outstr;
                     98:        unsigned int len;
                     99:
1.3     ! christos  100:        if (instr == NULL) {
        !           101:                return (NULL);
        !           102:        }
1.1       christos  103:
                    104:        len = strlen(instr);
                    105:
1.3     ! christos  106:        outstr = isc_mem_allocate(named_g_mctx, (2 * len * sizeof(char)) + 1);
1.1       christos  107:
                    108:        mysql_real_escape_string(mysql, outstr, instr, len);
                    109:
1.3     ! christos  110:        return (outstr);
1.1       christos  111: }
                    112:
                    113: /*%
                    114:  * This function is the real core of the driver.   Zone, record
                    115:  * and client strings are passed in (or NULL is passed if the
                    116:  * string is not available).  The type of query we want to run
                    117:  * is indicated by the query flag, and the dbdata object is passed
                    118:  * passed in to.  dbdata really holds a single database instance.
                    119:  * The function will construct and run the query, hopefully getting
                    120:  * a result set.
                    121:  */
                    122:
                    123: static isc_result_t
1.3     ! christos  124: mysql_get_resultset(const char *zone, const char *record, const char *client,
        !           125:                    unsigned int query, void *dbdata, MYSQL_RES **rs) {
1.1       christos  126:        isc_result_t result;
                    127:        dbinstance_t *dbi = NULL;
                    128:        char *querystring = NULL;
                    129:        unsigned int i = 0;
                    130:        unsigned int j = 0;
                    131:        int qres = 0;
                    132:
1.3     ! christos  133:        if (query != COUNTZONE) {
1.1       christos  134:                REQUIRE(*rs == NULL);
1.3     ! christos  135:        } else {
1.1       christos  136:                REQUIRE(rs == NULL);
1.3     ! christos  137:        }
1.1       christos  138:
                    139:        /* get db instance / connection */
1.3     ! christos  140:        dbi = (dbinstance_t *)dbdata;
1.1       christos  141:
                    142:        /* if DBI is null, can't do anything else */
                    143:        if (dbi == NULL) {
1.3     ! christos  144:                return (ISC_R_FAILURE);
1.1       christos  145:        }
                    146:
                    147:        /* what type of query are we going to run? */
1.3     ! christos  148:        switch (query) {
1.1       christos  149:        case ALLNODES:
                    150:                /*
                    151:                 * if the query was not passed in from the config file
                    152:                 * then we can't run it.  return not_implemented, so
                    153:                 * it's like the code for that operation was never
                    154:                 * built into the driver.... AHHH flexibility!!!
                    155:                 */
                    156:                if (dbi->allnodes_q == NULL) {
                    157:                        result = ISC_R_NOTIMPLEMENTED;
                    158:                        goto cleanup;
                    159:                }
                    160:                break;
                    161:        case ALLOWXFR:
                    162:                /* same as comments as ALLNODES */
                    163:                if (dbi->allowxfr_q == NULL) {
                    164:                        result = ISC_R_NOTIMPLEMENTED;
                    165:                        goto cleanup;
                    166:                }
                    167:                break;
                    168:        case AUTHORITY:
                    169:                /* same as comments as ALLNODES */
                    170:                if (dbi->authority_q == NULL) {
                    171:                        result = ISC_R_NOTIMPLEMENTED;
                    172:                        goto cleanup;
                    173:                }
                    174:                break;
                    175:        case FINDZONE:
                    176:                /* this is required.  It's the whole point of DLZ! */
                    177:                if (dbi->findzone_q == NULL) {
                    178:                        isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
                    179:                                      DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
                    180:                                      "No query specified for findzone.  "
                    181:                                      "Findzone requires a query");
                    182:                        result = ISC_R_FAILURE;
                    183:                        goto cleanup;
                    184:                }
                    185:                break;
                    186:        case COUNTZONE:
                    187:                /* same as comments as ALLNODES */
                    188:                if (dbi->countzone_q == NULL) {
                    189:                        result = ISC_R_NOTIMPLEMENTED;
                    190:                        goto cleanup;
                    191:                }
                    192:                break;
                    193:        case LOOKUP:
                    194:                /* this is required.  It's also a major point of DLZ! */
                    195:                if (dbi->lookup_q == NULL) {
                    196:                        isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
                    197:                                      DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
                    198:                                      "No query specified for lookup.  "
                    199:                                      "Lookup requires a query");
                    200:                        result = ISC_R_FAILURE;
                    201:                        goto cleanup;
                    202:                }
                    203:                break;
                    204:        default:
                    205:                /*
                    206:                 * this should never happen.  If it does, the code is
                    207:                 * screwed up!
                    208:                 */
                    209:                UNEXPECTED_ERROR(__FILE__, __LINE__,
                    210:                                 "Incorrect query flag passed to "
                    211:                                 "mysql_get_resultset");
                    212:                result = ISC_R_UNEXPECTED;
                    213:                goto cleanup;
                    214:        }
                    215:
                    216:        /*
                    217:         * was a zone string passed?  If so, make it safe for use in
                    218:         * queries.
                    219:         */
                    220:        if (zone != NULL) {
1.3     ! christos  221:                dbi->zone = mysqldrv_escape_string((MYSQL *)dbi->dbconn, zone);
1.1       christos  222:                if (dbi->zone == NULL) {
                    223:                        result = ISC_R_NOMEMORY;
                    224:                        goto cleanup;
                    225:                }
1.3     ! christos  226:        } else { /* no string passed, set the string pointer to NULL */
1.1       christos  227:                dbi->zone = NULL;
                    228:        }
                    229:
                    230:        /*
                    231:         * was a record string passed?  If so, make it safe for use in
                    232:         * queries.
                    233:         */
                    234:        if (record != NULL) {
1.3     ! christos  235:                dbi->record = mysqldrv_escape_string((MYSQL *)dbi->dbconn,
1.1       christos  236:                                                     record);
                    237:                if (dbi->record == NULL) {
                    238:                        result = ISC_R_NOMEMORY;
                    239:                        goto cleanup;
                    240:                }
1.3     ! christos  241:        } else { /* no string passed, set the string pointer to NULL */
1.1       christos  242:                dbi->record = NULL;
                    243:        }
                    244:
                    245:        /*
                    246:         * was a client string passed?  If so, make it safe for use in
                    247:         * queries.
                    248:         */
                    249:        if (client != NULL) {
1.3     ! christos  250:                dbi->client = mysqldrv_escape_string((MYSQL *)dbi->dbconn,
1.1       christos  251:                                                     client);
                    252:                if (dbi->client == NULL) {
                    253:                        result = ISC_R_NOMEMORY;
                    254:                        goto cleanup;
                    255:                }
1.3     ! christos  256:        } else { /* no string passed, set the string pointer to NULL */
1.1       christos  257:                dbi->client = NULL;
                    258:        }
                    259:
                    260:        /*
                    261:         * what type of query are we going to run?  this time we build
                    262:         * the actual query to run.
                    263:         */
1.3     ! christos  264:        switch (query) {
1.1       christos  265:        case ALLNODES:
                    266:                querystring = build_querystring(named_g_mctx, dbi->allnodes_q);
                    267:                break;
                    268:        case ALLOWXFR:
                    269:                querystring = build_querystring(named_g_mctx, dbi->allowxfr_q);
                    270:                break;
                    271:        case AUTHORITY:
                    272:                querystring = build_querystring(named_g_mctx, dbi->authority_q);
                    273:                break;
                    274:        case FINDZONE:
                    275:                querystring = build_querystring(named_g_mctx, dbi->findzone_q);
                    276:                break;
                    277:        case COUNTZONE:
                    278:                querystring = build_querystring(named_g_mctx, dbi->countzone_q);
                    279:                break;
                    280:        case LOOKUP:
                    281:                querystring = build_querystring(named_g_mctx, dbi->lookup_q);
                    282:                break;
                    283:        default:
                    284:                /*
                    285:                 * this should never happen.  If it does, the code is
                    286:                 * screwed up!
                    287:                 */
                    288:                UNEXPECTED_ERROR(__FILE__, __LINE__,
                    289:                                 "Incorrect query flag passed to "
                    290:                                 "mysql_get_resultset");
                    291:                result = ISC_R_UNEXPECTED;
                    292:                goto cleanup;
                    293:        }
                    294:
                    295:        /* if the querystring is null, Bummer, outta RAM.  UPGRADE TIME!!!   */
                    296:        if (querystring == NULL) {
                    297:                result = ISC_R_NOMEMORY;
                    298:                goto cleanup;
                    299:        }
                    300:
                    301:        /*
                    302:         * output the full query string during debug so we can see
                    303:         * what lame error the query has.
                    304:         */
1.3     ! christos  305:        isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ,
        !           306:                      ISC_LOG_DEBUG(1), "\nQuery String: %s\n", querystring);
1.1       christos  307:
                    308:        /* attempt query up to 3 times. */
1.3     ! christos  309:        for (i = 0; i < 3; i++) {
        !           310:                qres = mysql_query((MYSQL *)dbi->dbconn, querystring);
        !           311:                if (qres == 0) {
1.1       christos  312:                        break;
1.3     ! christos  313:                }
        !           314:                for (j = 0; mysql_ping((MYSQL *)dbi->dbconn) != 0 && j < 4; j++)
1.1       christos  315:                        ;
                    316:        }
                    317:
                    318:        if (qres == 0) {
                    319:                result = ISC_R_SUCCESS;
                    320:                if (query != COUNTZONE) {
1.3     ! christos  321:                        *rs = mysql_store_result((MYSQL *)dbi->dbconn);
        !           322:                        if (*rs == NULL) {
1.1       christos  323:                                result = ISC_R_FAILURE;
1.3     ! christos  324:                        }
1.1       christos  325:                }
                    326:        } else {
                    327:                result = ISC_R_FAILURE;
                    328:        }
                    329:
1.3     ! christos  330: cleanup:
1.1       christos  331:        /* it's always good to cleanup after yourself */
                    332:
                    333:        /* free dbi->zone string */
1.3     ! christos  334:        if (dbi->zone != NULL) {
1.1       christos  335:                isc_mem_free(named_g_mctx, dbi->zone);
1.3     ! christos  336:        }
1.1       christos  337:
                    338:        /* free dbi->record string */
1.3     ! christos  339:        if (dbi->record != NULL) {
1.1       christos  340:                isc_mem_free(named_g_mctx, dbi->record);
1.3     ! christos  341:        }
1.1       christos  342:
                    343:        /* free dbi->client string */
1.3     ! christos  344:        if (dbi->client != NULL) {
1.1       christos  345:                isc_mem_free(named_g_mctx, dbi->client);
1.3     ! christos  346:        }
1.1       christos  347:
                    348:        /* release query string */
1.3     ! christos  349:        if (querystring != NULL) {
1.1       christos  350:                isc_mem_free(named_g_mctx, querystring);
1.3     ! christos  351:        }
1.1       christos  352:
                    353:        /* return result */
1.3     ! christos  354:        return (result);
1.1       christos  355: }
                    356:
                    357: /*%
                    358:  * The processing of result sets for lookup and authority are
                    359:  * exactly the same.  So that functionality has been moved
                    360:  * into this function to minimize code.
                    361:  */
                    362:
                    363: static isc_result_t
1.3     ! christos  364: mysql_process_rs(dns_sdlzlookup_t *lookup, MYSQL_RES *rs) {
1.1       christos  365:        isc_result_t result = ISC_R_NOTFOUND;
                    366:        MYSQL_ROW row;
                    367:        unsigned int fields;
                    368:        unsigned int j;
                    369:        unsigned int len;
                    370:        char *tmpString;
                    371:        char *endp;
                    372:        int ttl;
                    373:
1.3     ! christos  374:        row = mysql_fetch_row(rs);     /* get a row from the result set */
        !           375:        fields = mysql_num_fields(rs); /* how many columns in result set */
1.1       christos  376:        while (row != NULL) {
1.3     ! christos  377:                switch (fields) {
1.1       christos  378:                case 1:
                    379:                        /*
                    380:                         * one column in rs, it's the data field.  use
                    381:                         * default type of A record, and default TTL
                    382:                         * of 86400
                    383:                         */
                    384:                        result = dns_sdlz_putrr(lookup, "a", 86400,
                    385:                                                safeGet(row[0]));
                    386:                        break;
                    387:                case 2:
                    388:                        /*
                    389:                         * two columns, data field, and data type.
                    390:                         * use default TTL of 86400.
                    391:                         */
                    392:                        result = dns_sdlz_putrr(lookup, safeGet(row[0]), 86400,
                    393:                                                safeGet(row[1]));
                    394:                        break;
                    395:                case 3:
                    396:                        /*
                    397:                         * three columns, all data no defaults.
                    398:                         * convert text to int, make sure it worked
                    399:                         * right.
                    400:                         */
                    401:                        ttl = strtol(safeGet(row[0]), &endp, 10);
                    402:                        if (*endp != '\0' || ttl < 0) {
                    403:                                isc_log_write(dns_lctx,
                    404:                                              DNS_LOGCATEGORY_DATABASE,
                    405:                                              DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
                    406:                                              "mysql driver ttl must be "
1.3     ! christos  407:                                              "a positive number");
1.1       christos  408:                        }
                    409:                        result = dns_sdlz_putrr(lookup, safeGet(row[1]), ttl,
                    410:                                                safeGet(row[2]));
                    411:                        break;
                    412:                default:
                    413:                        /*
                    414:                         * more than 3 fields, concatenate the last
                    415:                         * ones together.  figure out how long to make
                    416:                         * string.
                    417:                         */
1.3     ! christos  418:                        for (j = 2, len = 0; j < fields; j++) {
1.1       christos  419:                                len += strlen(safeGet(row[j])) + 1;
                    420:                        }
                    421:                        /*
                    422:                         * allocate string memory, allow for NULL to
                    423:                         * term string
                    424:                         */
                    425:                        tmpString = isc_mem_allocate(named_g_mctx, len + 1);
                    426:                        /* copy field to tmpString */
                    427:                        strcpy(tmpString, safeGet(row[2]));
                    428:
                    429:                        /*
                    430:                         * concat the rest of fields together, space
                    431:                         * between each one.
                    432:                         */
1.3     ! christos  433:                        for (j = 3; j < fields; j++) {
1.1       christos  434:                                strcat(tmpString, " ");
                    435:                                strcat(tmpString, safeGet(row[j]));
                    436:                        }
                    437:                        /* convert text to int, make sure it worked right */
                    438:                        ttl = strtol(safeGet(row[0]), &endp, 10);
                    439:                        if (*endp != '\0' || ttl < 0) {
                    440:                                isc_log_write(dns_lctx,
                    441:                                              DNS_LOGCATEGORY_DATABASE,
                    442:                                              DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
                    443:                                              "mysql driver ttl must be "
1.3     ! christos  444:                                              "a positive number");
1.1       christos  445:                        }
                    446:                        /* ok, now tell Bind about it. */
1.3     ! christos  447:                        result = dns_sdlz_putrr(lookup, safeGet(row[1]), ttl,
        !           448:                                                tmpString);
1.1       christos  449:                        /* done, get rid of this thing. */
                    450:                        isc_mem_free(named_g_mctx, tmpString);
                    451:                }
                    452:                /* I sure hope we were successful */
                    453:                if (result != ISC_R_SUCCESS) {
                    454:                        /* nope, get rid of the Result set, and log a msg */
                    455:                        mysql_free_result(rs);
                    456:                        isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
                    457:                                      DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
                    458:                                      "dns_sdlz_putrr returned error. "
                    459:                                      "Error code was: %s",
                    460:                                      isc_result_totext(result));
                    461:                        return (ISC_R_FAILURE);
                    462:                }
1.3     ! christos  463:                row = mysql_fetch_row(rs); /* get next row */
1.1       christos  464:        }
                    465:
                    466:        /* free result set memory */
                    467:        mysql_free_result(rs);
                    468:
                    469:        /* return result code */
1.3     ! christos  470:        return (result);
1.1       christos  471: }
                    472:
                    473: /*
                    474:  * SDLZ interface methods
                    475:  */
                    476:
                    477: /*% determine if the zone is supported by (in) the database */
                    478:
                    479: static isc_result_t
                    480: mysql_findzone(void *driverarg, void *dbdata, const char *name,
1.3     ! christos  481:               dns_clientinfomethods_t *methods, dns_clientinfo_t *clientinfo) {
1.1       christos  482:        isc_result_t result;
                    483:        MYSQL_RES *rs = NULL;
                    484:        my_ulonglong rows;
                    485:
                    486:        UNUSED(driverarg);
                    487:        UNUSED(methods);
                    488:        UNUSED(clientinfo);
                    489:
                    490:        /* run the query and get the result set from the database. */
                    491:        result = mysql_get_resultset(name, NULL, NULL, FINDZONE, dbdata, &rs);
                    492:        /* if we didn't get a result set, log an err msg. */
                    493:        if (result != ISC_R_SUCCESS || rs == NULL) {
1.3     ! christos  494:                if (rs != NULL) {
1.1       christos  495:                        mysql_free_result(rs);
1.3     ! christos  496:                }
1.1       christos  497:                isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
                    498:                              DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
                    499:                              "mysql driver unable to return "
                    500:                              "result set for findzone query");
                    501:                return (ISC_R_FAILURE);
                    502:        }
                    503:        /* count how many rows in result set */
                    504:        rows = mysql_num_rows(rs);
                    505:        /* get rid of result set, we are done with it. */
                    506:        mysql_free_result(rs);
                    507:
                    508:        /* if we returned any rows, zone is supported. */
                    509:        if (rows > 0) {
                    510:                mysql_get_resultset(name, NULL, NULL, COUNTZONE, dbdata, NULL);
                    511:                return (ISC_R_SUCCESS);
                    512:        }
                    513:
                    514:        /* no rows returned, zone is not supported. */
                    515:        return (ISC_R_NOTFOUND);
                    516: }
                    517:
                    518: /*% Determine if the client is allowed to perform a zone transfer */
                    519: static isc_result_t
                    520: mysql_allowzonexfr(void *driverarg, void *dbdata, const char *name,
1.3     ! christos  521:                   const char *client) {
1.1       christos  522:        isc_result_t result;
                    523:        MYSQL_RES *rs = NULL;
                    524:        my_ulonglong rows;
                    525:
                    526:        UNUSED(driverarg);
                    527:
                    528:        /* first check if the zone is supported by the database. */
                    529:        result = mysql_findzone(driverarg, dbdata, name, NULL, NULL);
1.3     ! christos  530:        if (result != ISC_R_SUCCESS) {
1.1       christos  531:                return (ISC_R_NOTFOUND);
1.3     ! christos  532:        }
1.1       christos  533:
                    534:        /*
                    535:         * if we get to this point we know the zone is supported by
                    536:         * the database the only questions now are is the zone
                    537:         * transfer is allowed for this client and did the config file
                    538:         * have an allow zone xfr query.
                    539:         *
                    540:         * Run our query, and get a result set from the database.
                    541:         */
1.3     ! christos  542:        result = mysql_get_resultset(name, NULL, client, ALLOWXFR, dbdata, &rs);
1.1       christos  543:        /* if we get "not implemented", send it along. */
1.3     ! christos  544:        if (result == ISC_R_NOTIMPLEMENTED) {
        !           545:                return (result);
        !           546:        }
1.1       christos  547:        /* if we didn't get a result set, log an err msg. */
                    548:        if (result != ISC_R_SUCCESS || rs == NULL) {
1.3     ! christos  549:                if (rs != NULL) {
1.1       christos  550:                        mysql_free_result(rs);
1.3     ! christos  551:                }
1.1       christos  552:                isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
                    553:                              DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
                    554:                              "mysql driver unable to return "
                    555:                              "result set for allow xfr query");
                    556:                return (ISC_R_FAILURE);
                    557:        }
                    558:        /* count how many rows in result set */
                    559:        rows = mysql_num_rows(rs);
                    560:        /* get rid of result set, we are done with it. */
                    561:        mysql_free_result(rs);
                    562:
                    563:        /* if we returned any rows, zone xfr is allowed. */
1.3     ! christos  564:        if (rows > 0) {
1.1       christos  565:                return (ISC_R_SUCCESS);
1.3     ! christos  566:        }
1.1       christos  567:
                    568:        /* no rows returned, zone xfr not allowed */
                    569:        return (ISC_R_NOPERM);
                    570: }
                    571:
                    572: /*%
                    573:  * If the client is allowed to perform a zone transfer, the next order of
                    574:  * business is to get all the nodes in the zone, so bind can respond to the
                    575:  * query.
                    576:  */
                    577: static isc_result_t
                    578: mysql_allnodes(const char *zone, void *driverarg, void *dbdata,
1.3     ! christos  579:               dns_sdlzallnodes_t *allnodes) {
1.1       christos  580:        isc_result_t result;
                    581:        MYSQL_RES *rs = NULL;
                    582:        MYSQL_ROW row;
                    583:        unsigned int fields;
                    584:        unsigned int j;
                    585:        unsigned int len;
                    586:        char *tmpString;
                    587:        char *endp;
                    588:        int ttl;
                    589:
                    590:        UNUSED(driverarg);
                    591:
                    592:        /* run the query and get the result set from the database. */
                    593:        result = mysql_get_resultset(zone, NULL, NULL, ALLNODES, dbdata, &rs);
                    594:        /* if we get "not implemented", send it along */
1.3     ! christos  595:        if (result == ISC_R_NOTIMPLEMENTED) {
        !           596:                return (result);
        !           597:        }
1.1       christos  598:        /* if we didn't get a result set, log an err msg. */
                    599:        if (result != ISC_R_SUCCESS) {
1.3     ! christos  600:                if (rs != NULL) {
1.1       christos  601:                        mysql_free_result(rs);
1.3     ! christos  602:                }
1.1       christos  603:                isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
                    604:                              DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
                    605:                              "mysql driver unable to return "
                    606:                              "result set for all nodes query");
                    607:                return (ISC_R_FAILURE);
                    608:        }
                    609:
                    610:        result = ISC_R_NOTFOUND;
                    611:
1.3     ! christos  612:        row = mysql_fetch_row(rs);     /* get a row from the result set */
        !           613:        fields = mysql_num_fields(rs); /* how many columns in result set */
1.1       christos  614:        while (row != NULL) {
1.3     ! christos  615:                if (fields < 4) { /* gotta have at least 4 columns */
1.1       christos  616:                        isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
                    617:                                      DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
                    618:                                      "mysql driver too few fields returned "
                    619:                                      "by all nodes query");
                    620:                }
                    621:                /* convert text to int, make sure it worked right  */
                    622:                ttl = strtol(safeGet(row[0]), &endp, 10);
                    623:                if (*endp != '\0' || ttl < 0) {
                    624:                        isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
                    625:                                      DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
                    626:                                      "mysql driver ttl must be "
1.3     ! christos  627:                                      "a positive number");
1.1       christos  628:                }
                    629:                if (fields == 4) {
                    630:                        /* tell Bind about it. */
                    631:                        result = dns_sdlz_putnamedrr(allnodes, safeGet(row[2]),
                    632:                                                     safeGet(row[1]), ttl,
                    633:                                                     safeGet(row[3]));
                    634:                } else {
                    635:                        /*
                    636:                         * more than 4 fields, concatenate the last
                    637:                         * ones together.  figure out how long to make
                    638:                         * string.
                    639:                         */
1.3     ! christos  640:                        for (j = 3, len = 0; j < fields; j++) {
1.1       christos  641:                                len += strlen(safeGet(row[j])) + 1;
                    642:                        }
                    643:                        /* allocate memory, allow for NULL to term string */
                    644:                        tmpString = isc_mem_allocate(named_g_mctx, len + 1);
                    645:                        /* copy this field to tmpString */
                    646:                        strcpy(tmpString, safeGet(row[3]));
1.3     ! christos  647:                        /* concatenate the rest, with spaces between */
        !           648:                        for (j = 4; j < fields; j++) {
1.1       christos  649:                                strcat(tmpString, " ");
                    650:                                strcat(tmpString, safeGet(row[j]));
                    651:                        }
                    652:                        /* tell Bind about it. */
                    653:                        result = dns_sdlz_putnamedrr(allnodes, safeGet(row[2]),
1.3     ! christos  654:                                                     safeGet(row[1]), ttl,
        !           655:                                                     tmpString);
1.1       christos  656:                        isc_mem_free(named_g_mctx, tmpString);
                    657:                }
                    658:                /* if we weren't successful, log err msg */
                    659:                if (result != ISC_R_SUCCESS) {
                    660:                        isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
                    661:                                      DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
                    662:                                      "dns_sdlz_putnamedrr returned error. "
                    663:                                      "Error code was: %s",
                    664:                                      isc_result_totext(result));
                    665:                        result = ISC_R_FAILURE;
                    666:                        break;
                    667:                }
                    668:                /* get next row from the result set */
                    669:                row = mysql_fetch_row(rs);
                    670:        }
                    671:
                    672:        /* free result set memory */
                    673:        mysql_free_result(rs);
                    674:
1.3     ! christos  675:        return (result);
1.1       christos  676: }
                    677:
                    678: /*% if the lookup function does not return SOA or NS records for the zone,
                    679:  * use this function to get that information for Bind.
                    680:  */
                    681:
                    682: static isc_result_t
                    683: mysql_authority(const char *zone, void *driverarg, void *dbdata,
1.3     ! christos  684:                dns_sdlzlookup_t *lookup) {
1.1       christos  685:        isc_result_t result;
                    686:        MYSQL_RES *rs = NULL;
                    687:
                    688:        UNUSED(driverarg);
                    689:
                    690:        /* run the query and get the result set from the database. */
                    691:        result = mysql_get_resultset(zone, NULL, NULL, AUTHORITY, dbdata, &rs);
                    692:        /* if we get "not implemented", send it along */
1.3     ! christos  693:        if (result == ISC_R_NOTIMPLEMENTED) {
        !           694:                return (result);
        !           695:        }
1.1       christos  696:        /* if we didn't get a result set, log an err msg. */
                    697:        if (result != ISC_R_SUCCESS) {
1.3     ! christos  698:                if (rs != NULL) {
1.1       christos  699:                        mysql_free_result(rs);
1.3     ! christos  700:                }
1.1       christos  701:                isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
                    702:                              DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
                    703:                              "mysql driver unable to return "
                    704:                              "result set for authority query");
                    705:                return (ISC_R_FAILURE);
                    706:        }
                    707:        /*
                    708:         * lookup and authority result sets are processed in the same
                    709:         * manner mysql_process_rs does the job for both functions.
                    710:         */
1.3     ! christos  711:        return (mysql_process_rs(lookup, rs));
1.1       christos  712: }
                    713:
                    714: /*% if zone is supported, lookup up a (or multiple) record(s) in it */
                    715: static isc_result_t
1.3     ! christos  716: mysql_lookup(const char *zone, const char *name, void *driverarg, void *dbdata,
        !           717:             dns_sdlzlookup_t *lookup, dns_clientinfomethods_t *methods,
        !           718:             dns_clientinfo_t *clientinfo) {
1.1       christos  719:        isc_result_t result;
                    720:        MYSQL_RES *rs = NULL;
                    721:
                    722:        UNUSED(driverarg);
                    723:        UNUSED(methods);
                    724:        UNUSED(clientinfo);
                    725:
                    726:        /* run the query and get the result set from the database. */
                    727:        result = mysql_get_resultset(zone, name, NULL, LOOKUP, dbdata, &rs);
                    728:        /* if we didn't get a result set, log an err msg. */
                    729:        if (result != ISC_R_SUCCESS) {
1.3     ! christos  730:                if (rs != NULL) {
1.1       christos  731:                        mysql_free_result(rs);
1.3     ! christos  732:                }
1.1       christos  733:                isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
                    734:                              DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
                    735:                              "mysql driver unable to return "
                    736:                              "result set for lookup query");
                    737:                return (ISC_R_FAILURE);
                    738:        }
                    739:        /*
                    740:         * lookup and authority result sets are processed in the same manner
                    741:         * mysql_process_rs does the job for both functions.
                    742:         */
1.3     ! christos  743:        return (mysql_process_rs(lookup, rs));
1.1       christos  744: }
                    745:
                    746: /*%
                    747:  * create an instance of the driver.  Remember, only 1 copy of the driver's
                    748:  * code is ever loaded, the driver has to remember which context it's
                    749:  * operating in.  This is done via use of the dbdata argument which is
                    750:  * passed into all query functions.
                    751:  */
                    752: static isc_result_t
                    753: mysql_create(const char *dlzname, unsigned int argc, char *argv[],
1.3     ! christos  754:             void *driverarg, void **dbdata) {
1.1       christos  755:        isc_result_t result;
                    756:        dbinstance_t *dbi = NULL;
                    757:        char *tmp = NULL;
                    758:        char *dbname = NULL;
                    759:        char *host = NULL;
                    760:        char *user = NULL;
                    761:        char *pass = NULL;
                    762:        char *socket = NULL;
                    763:        int port;
                    764:        MYSQL *dbc;
                    765:        char *endp;
                    766:        int j;
                    767:        unsigned int flags = 0;
                    768:
                    769:        UNUSED(driverarg);
                    770:        UNUSED(dlzname);
                    771:
                    772:        /* verify we have at least 4 arg's passed to the driver */
                    773:        if (argc < 4) {
                    774:                isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
                    775:                              DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
                    776:                              "mysql driver requires "
                    777:                              "at least 4 command line args.");
                    778:                return (ISC_R_FAILURE);
                    779:        }
                    780:
                    781:        /* no more than 8 arg's should be passed to the driver */
                    782:        if (argc > 8) {
                    783:                isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
                    784:                              DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
                    785:                              "mysql driver cannot accept "
                    786:                              "more than 7 command line args.");
                    787:                return (ISC_R_FAILURE);
                    788:        }
                    789:
1.3     ! christos  790:        /* parse connection string and get parameters. */
1.1       christos  791:
                    792:        /* get db name - required */
                    793:        dbname = getParameterValue(argv[1], "dbname=");
                    794:        if (dbname == NULL) {
                    795:                isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
                    796:                              DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
                    797:                              "mysql driver requires a dbname parameter.");
                    798:                result = ISC_R_FAILURE;
                    799:                goto full_cleanup;
                    800:        }
                    801:
                    802:        /* get db port.  Not required, but must be > 0 if specified */
                    803:        tmp = getParameterValue(argv[1], "port=");
                    804:        if (tmp == NULL) {
                    805:                port = 0;
                    806:        } else {
                    807:                port = strtol(tmp, &endp, 10);
                    808:                if (*endp != '\0' || port < 0) {
                    809:                        isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
                    810:                                      DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
                    811:                                      "Mysql driver port "
                    812:                                      "must be a positive number.");
                    813:                        isc_mem_free(named_g_mctx, tmp);
                    814:                        result = ISC_R_FAILURE;
                    815:                        goto full_cleanup;
                    816:                }
                    817:                isc_mem_free(named_g_mctx, tmp);
                    818:        }
                    819:
                    820:        /* how many queries were passed in from config file? */
1.3     ! christos  821:        switch (argc) {
1.1       christos  822:        case 4:
                    823:                result = build_sqldbinstance(named_g_mctx, NULL, NULL, NULL,
                    824:                                             argv[2], argv[3], NULL, &dbi);
                    825:                break;
                    826:        case 5:
                    827:                result = build_sqldbinstance(named_g_mctx, NULL, NULL, argv[4],
                    828:                                             argv[2], argv[3], NULL, &dbi);
                    829:                break;
                    830:        case 6:
1.3     ! christos  831:                result = build_sqldbinstance(named_g_mctx, argv[5], NULL,
        !           832:                                             argv[4], argv[2], argv[3], NULL,
        !           833:                                             &dbi);
1.1       christos  834:                break;
                    835:        case 7:
1.3     ! christos  836:                result = build_sqldbinstance(named_g_mctx, argv[5], argv[6],
        !           837:                                             argv[4], argv[2], argv[3], NULL,
        !           838:                                             &dbi);
1.1       christos  839:                break;
                    840:        case 8:
1.3     ! christos  841:                result = build_sqldbinstance(named_g_mctx, argv[5], argv[6],
        !           842:                                             argv[4], argv[2], argv[3], argv[7],
        !           843:                                             &dbi);
1.1       christos  844:                break;
                    845:        default:
                    846:                /* not really needed, should shut up compiler. */
                    847:                result = ISC_R_FAILURE;
                    848:        }
                    849:
                    850:        /* unsuccessful?, log err msg and cleanup. */
                    851:        if (result != ISC_R_SUCCESS) {
                    852:                isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
                    853:                              DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
                    854:                              "mysql driver could not create "
                    855:                              "database instance object.");
                    856:                result = ISC_R_FAILURE;
                    857:                goto cleanup;
                    858:        }
                    859:
                    860:        /* create and set db connection */
                    861:        dbi->dbconn = mysql_init(NULL);
                    862:
                    863:        /* if db connection cannot be created, log err msg and cleanup. */
                    864:        if (dbi->dbconn == NULL) {
                    865:                isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
                    866:                              DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
                    867:                              "mysql driver could not allocate "
                    868:                              "memory for database connection");
                    869:                result = ISC_R_FAILURE;
                    870:                goto full_cleanup;
                    871:        }
                    872:
                    873:        tmp = getParameterValue(argv[1], "compress=");
                    874:        if (tmp != NULL) {
1.3     ! christos  875:                if (strcasecmp(tmp, "true") == 0) {
1.1       christos  876:                        flags = CLIENT_COMPRESS;
1.3     ! christos  877:                }
1.1       christos  878:                isc_mem_free(named_g_mctx, tmp);
                    879:        }
                    880:
                    881:        tmp = getParameterValue(argv[1], "ssl=");
                    882:        if (tmp != NULL) {
1.3     ! christos  883:                if (strcasecmp(tmp, "true") == 0) {
1.1       christos  884:                        flags = flags | CLIENT_SSL;
1.3     ! christos  885:                }
1.1       christos  886:                isc_mem_free(named_g_mctx, tmp);
                    887:        }
                    888:
                    889:        tmp = getParameterValue(argv[1], "space=");
                    890:        if (tmp != NULL) {
1.3     ! christos  891:                if (strcasecmp(tmp, "ignore") == 0) {
1.1       christos  892:                        flags = flags | CLIENT_IGNORE_SPACE;
1.3     ! christos  893:                }
1.1       christos  894:                isc_mem_free(named_g_mctx, tmp);
                    895:        }
                    896:
                    897:        dbc = NULL;
                    898:        host = getParameterValue(argv[1], "host=");
                    899:        user = getParameterValue(argv[1], "user=");
                    900:        pass = getParameterValue(argv[1], "pass=");
                    901:        socket = getParameterValue(argv[1], "socket=");
                    902:
                    903:        /* enable automatic reconnection. */
1.3     ! christos  904:        if (mysql_options((MYSQL *)dbi->dbconn, MYSQL_OPT_RECONNECT,
        !           905:                          &(my_bool){ 1 }) != 0)
        !           906:        {
1.1       christos  907:                isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
                    908:                              DNS_LOGMODULE_DLZ, ISC_LOG_WARNING,
                    909:                              "mysql driver failed to set "
1.3     ! christos  910:                              "MYSQL_OPT_RECONNECT option, "
        !           911:                              "continuing");
1.1       christos  912:        }
                    913:
1.3     ! christos  914:        for (j = 0; dbc == NULL && j < 4; j++) {
        !           915:                dbc = mysql_real_connect((MYSQL *)dbi->dbconn, host, user, pass,
        !           916:                                         dbname, port, socket, flags);
        !           917:        }
1.1       christos  918:
                    919:        /* let user know if we couldn't connect. */
                    920:        if (dbc == NULL) {
                    921:                isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
                    922:                              DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
                    923:                              "mysql driver failed to create "
                    924:                              "database connection after 4 attempts");
                    925:                result = ISC_R_FAILURE;
                    926:                goto full_cleanup;
                    927:        }
                    928:
                    929:        /* return db connection via dbdata */
                    930:        *dbdata = dbi;
                    931:
                    932:        result = ISC_R_SUCCESS;
                    933:        goto cleanup;
                    934:
1.3     ! christos  935: full_cleanup:
1.1       christos  936:
1.3     ! christos  937:        if (dbi != NULL) {
1.1       christos  938:                destroy_sqldbinstance(dbi);
1.3     ! christos  939:        }
1.1       christos  940:
1.3     ! christos  941: cleanup:
1.1       christos  942:
1.3     ! christos  943:        if (dbname != NULL) {
1.1       christos  944:                isc_mem_free(named_g_mctx, dbname);
1.3     ! christos  945:        }
        !           946:        if (host != NULL) {
1.1       christos  947:                isc_mem_free(named_g_mctx, host);
1.3     ! christos  948:        }
        !           949:        if (user != NULL) {
1.1       christos  950:                isc_mem_free(named_g_mctx, user);
1.3     ! christos  951:        }
        !           952:        if (pass != NULL) {
1.1       christos  953:                isc_mem_free(named_g_mctx, pass);
1.3     ! christos  954:        }
        !           955:        if (socket != NULL) {
1.1       christos  956:                isc_mem_free(named_g_mctx, socket);
1.3     ! christos  957:        }
1.1       christos  958:
1.3     ! christos  959:        return (result);
1.1       christos  960: }
                    961:
                    962: /*%
                    963:  * destroy the driver.  Remember, only 1 copy of the driver's
                    964:  * code is ever loaded, the driver has to remember which context it's
                    965:  * operating in.  This is done via use of the dbdata argument.
                    966:  * so we really only need to clean it up since we are not using driverarg.
                    967:  */
                    968:
                    969: static void
1.3     ! christos  970: mysql_destroy(void *driverarg, void *dbdata) {
1.1       christos  971:        dbinstance_t *dbi;
                    972:
                    973:        UNUSED(driverarg);
                    974:
1.3     ! christos  975:        dbi = (dbinstance_t *)dbdata;
1.1       christos  976:
                    977:        /* release DB connection */
1.3     ! christos  978:        if (dbi->dbconn != NULL) {
        !           979:                mysql_close((MYSQL *)dbi->dbconn);
        !           980:        }
1.1       christos  981:
                    982:        /* destroy DB instance */
                    983:        destroy_sqldbinstance(dbi);
                    984: }
                    985:
                    986: /* pointers to all our runtime methods. */
                    987: /* this is used during driver registration */
                    988: /* i.e. in dlz_mysql_init below. */
                    989: static dns_sdlzmethods_t dlz_mysql_methods = {
                    990:        mysql_create,
                    991:        mysql_destroy,
                    992:        mysql_findzone,
                    993:        mysql_lookup,
                    994:        mysql_authority,
                    995:        mysql_allnodes,
                    996:        mysql_allowzonexfr,
                    997:        NULL,
                    998:        NULL,
                    999:        NULL,
                   1000:        NULL,
                   1001:        NULL,
                   1002:        NULL,
                   1003:        NULL,
                   1004: };
                   1005:
                   1006: /*%
                   1007:  * Wrapper around dns_sdlzregister().
                   1008:  */
                   1009: isc_result_t
                   1010: dlz_mysql_init(void) {
                   1011:        isc_result_t result;
                   1012:
                   1013:        /*
                   1014:         * Write debugging message to log
                   1015:         */
1.3     ! christos 1016:        isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ,
        !          1017:                      ISC_LOG_DEBUG(2), "Registering DLZ mysql driver.");
1.1       christos 1018:
                   1019:        /* Driver is always threadsafe.  Because of the way MySQL handles
1.3     ! christos 1020:         * threads the MySQL driver can only be used when bind is run single
        !          1021:         * threaded.  Using MySQL with Bind running multi-threaded is not
        !          1022:         * allowed.  When using the MySQL driver "-n1" should always be
        !          1023:         * passed to Bind to guarantee single threaded operation.
1.1       christos 1024:         */
                   1025:        result = dns_sdlzregister("mysql", &dlz_mysql_methods, NULL,
                   1026:                                  DNS_SDLZFLAG_RELATIVEOWNER |
1.3     ! christos 1027:                                          DNS_SDLZFLAG_RELATIVERDATA |
        !          1028:                                          DNS_SDLZFLAG_THREADSAFE,
1.1       christos 1029:                                  named_g_mctx, &dlz_mysql);
                   1030:        /* if we can't register the driver, there are big problems. */
                   1031:        if (result != ISC_R_SUCCESS) {
                   1032:                UNEXPECTED_ERROR(__FILE__, __LINE__,
                   1033:                                 "dns_sdlzregister() failed: %s",
                   1034:                                 isc_result_totext(result));
                   1035:                result = ISC_R_UNEXPECTED;
                   1036:        }
                   1037:
1.3     ! christos 1038:        return (result);
1.1       christos 1039: }
                   1040:
                   1041: /*%
                   1042:  * Wrapper around dns_sdlzunregister().
                   1043:  */
                   1044: void
                   1045: dlz_mysql_clear(void) {
                   1046:        /*
                   1047:         * Write debugging message to log
                   1048:         */
1.3     ! christos 1049:        isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ,
        !          1050:                      ISC_LOG_DEBUG(2), "Unregistering DLZ mysql driver.");
1.1       christos 1051:
                   1052:        /* unregister the driver. */
1.3     ! christos 1053:        if (dlz_mysql != NULL) {
1.1       christos 1054:                dns_sdlzunregister(&dlz_mysql);
1.3     ! christos 1055:        }
1.1       christos 1056: }
                   1057:
1.3     ! christos 1058: #endif /* ifdef DLZ_MYSQL */

CVSweb <webmaster@jp.NetBSD.org>