tcldb.c revision ec5347e2c775f027573ce5648b910361aa926c01
823N/A/*
823N/A * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
823N/A * Copyright (C) 2000, 2001 Internet Software Consortium.
823N/A *
823N/A * Permission to use, copy, modify, and/or distribute this software for any
823N/A * purpose with or without fee is hereby granted, provided that the above
823N/A * copyright notice and this permission notice appear in all copies.
823N/A *
6983N/A * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
6983N/A * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
823N/A * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
823N/A * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
823N/A * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
823N/A * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
6983N/A * PERFORMANCE OF THIS SOFTWARE.
6983N/A */
6983N/A
6983N/A/* $Id: tcldb.c,v 1.9 2007/06/18 23:47:33 tbox Exp $ */
823N/A
823N/A/*
823N/A * A simple database driver that calls a Tcl procedure to define
823N/A * the contents of the DNS namespace. The procedure is loaded
823N/A * from the file lookup.tcl; look at the comments there for
5175N/A * more information.
6412N/A */
823N/A
823N/A#include <config.h>
823N/A
6412N/A#include <string.h>
1498N/A#include <stdlib.h>
6412N/A#include <unistd.h>
983N/A#include <sys/stat.h>
983N/A
5175N/A#include <isc/mem.h>
878N/A#include <isc/print.h>
6412N/A#include <isc/result.h>
6412N/A#include <isc/util.h>
6412N/A
6412N/A#include <dns/log.h>
6412N/A#include <dns/sdb.h>
823N/A
823N/A#include <named/globals.h>
823N/A
823N/A#include <tcl.h>
823N/A
897N/A#include <tcldb.h>
6412N/A
878N/A#define CHECK(op) \
878N/A do { result = (op); \
878N/A if (result != ISC_R_SUCCESS) return (result); \
5175N/A } while (0)
5175N/A
5175N/Atypedef struct tcldb_driver {
6412N/A isc_mem_t *mctx;
5175N/A Tcl_Interp *interp;
5175N/A} tcldb_driver_t;
5175N/A
5175N/Astatic tcldb_driver_t *the_driver = NULL;
878N/A
6412N/Astatic dns_sdbimplementation_t *tcldb = NULL;
983N/A
983N/Astatic isc_result_t
983N/Atcldb_driver_create(isc_mem_t *mctx, tcldb_driver_t **driverp) {
983N/A int tclres;
983N/A isc_result_t result = ISC_R_SUCCESS;
983N/A tcldb_driver_t *driver = isc_mem_get(mctx, sizeof(tcldb_driver_t));
983N/A if (driver == NULL)
983N/A return (ISC_R_NOMEMORY);
983N/A driver->mctx = mctx;
983N/A driver->interp = Tcl_CreateInterp();
878N/A
878N/A tclres = Tcl_EvalFile(driver->interp, (char *) "lookup.tcl");
878N/A if (tclres != TCL_OK) {
983N/A isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
983N/A DNS_LOGMODULE_SDB, ISC_LOG_ERROR,
983N/A "initializing tcldb: "
983N/A "loading 'lookup.tcl' failed: %s",
878N/A driver->interp->result);
878N/A result = ISC_R_FAILURE;
878N/A goto cleanup;
878N/A }
878N/A *driverp = driver;
878N/A return (ISC_R_SUCCESS);
878N/A
5175N/A cleanup:
878N/A isc_mem_put(mctx, driver, sizeof(tcldb_driver_t));
5175N/A return (result);
878N/A
5175N/A}
5175N/A
5175N/Astatic void
5175N/Atcldb_driver_destroy(tcldb_driver_t **driverp) {
5175N/A tcldb_driver_t *driver = *driverp;
5175N/A Tcl_DeleteInterp(driver->interp);
5175N/A isc_mem_put(driver->mctx, driver, sizeof(tcldb_driver_t));
5175N/A}
5175N/A
5175N/A/*
5175N/A * Perform a lookup, by invoking the Tcl procedure "lookup".
5175N/A */
5175N/Astatic isc_result_t
5175N/Atcldb_lookup(const char *zone, const char *name, void *dbdata,
6412N/A dns_sdblookup_t *lookup)
6412N/A{
6412N/A isc_result_t result = ISC_R_SUCCESS;
5175N/A int tclres;
5175N/A int rrc; /* RR count */
5175N/A char **rrv; /* RR vector */
5175N/A int i;
5175N/A char *cmdv[3];
5175N/A char *cmd;
5175N/A
5175N/A tcldb_driver_t *driver = (tcldb_driver_t *) dbdata;
5175N/A
5175N/A cmdv[0] = "lookup";
5175N/A cmdv[1] = zone;
5175N/A cmdv[2] = name;
5175N/A cmd = Tcl_Merge(3, cmdv);
5175N/A tclres = Tcl_Eval(driver->interp, cmd);
5175N/A Tcl_Free(cmd);
5175N/A
878N/A if (tclres != TCL_OK) {
823N/A isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
5175N/A DNS_LOGMODULE_SDB, ISC_LOG_ERROR,
5175N/A "zone '%s': tcl lookup function failed: %s",
5175N/A zone, driver->interp->result);
5175N/A return (ISC_R_FAILURE);
5175N/A }
878N/A
878N/A if (strcmp(driver->interp->result, "NXDOMAIN") == 0) {
823N/A result = ISC_R_NOTFOUND;
878N/A goto fail;
983N/A }
983N/A
983N/A tclres = Tcl_SplitList(driver->interp, driver->interp->result,
878N/A &rrc, &rrv);
1497N/A if (tclres != TCL_OK)
1497N/A goto malformed;
878N/A
878N/A for (i = 0; i < rrc; i++) {
5175N/A isc_result_t tmpres;
2086N/A int fieldc; /* Field count */
878N/A char **fieldv; /* Field vector */
5175N/A tclres = Tcl_SplitList(driver->interp, rrv[i],
878N/A &fieldc, &fieldv);
5175N/A if (tclres != TCL_OK) {
5175N/A tmpres = ISC_R_FAILURE;
5175N/A goto failrr;
5175N/A }
5175N/A if (fieldc != 3)
5175N/A goto malformed;
5175N/A tmpres = dns_sdb_putrr(lookup, fieldv[0], atoi(fieldv[1]),
5175N/A fieldv[2]);
5175N/A Tcl_Free((char *) fieldv);
5175N/A failrr:
5175N/A if (tmpres != ISC_R_SUCCESS)
5175N/A result = tmpres;
5175N/A }
5175N/A Tcl_Free((char *) rrv);
823N/A if (result == ISC_R_SUCCESS)
823N/A return (result);
878N/A
878N/A malformed:
878N/A isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
878N/A DNS_LOGMODULE_SDB, ISC_LOG_ERROR,
2487N/A "zone '%s': "
2487N/A "malformed return value from tcl lookup function: %s",
2487N/A zone, driver->interp->result);
2487N/A result = ISC_R_FAILURE;
2487N/A fail:
2487N/A return (result);
2487N/A}
2487N/A
5175N/A/*
5175N/A * Set up per-zone state. In our case, the database arguments of the
5175N/A * zone are collected into a Tcl list and assigned to an element of
5175N/A * the global array "dbargs".
5175N/A */
5175N/Astatic isc_result_t
5175N/Atcldb_create(const char *zone, int argc, char **argv,
5175N/A void *driverdata, void **dbdata)
5175N/A{
5175N/A tcldb_driver_t *driver = (tcldb_driver_t *) driverdata;
2487N/A
2487N/A char *list = Tcl_Merge(argc, argv);
2487N/A
983N/A Tcl_SetVar2(driver->interp, (char *) "dbargs", (char *) zone, list, 0);
983N/A
983N/A Tcl_Free(list);
983N/A
983N/A *dbdata = driverdata;
983N/A
1497N/A return (ISC_R_SUCCESS);
1497N/A}
878N/A
878N/A/*
5175N/A * This driver does not support zone transfer, so allnodes() is NULL.
1497N/A */
2086N/Astatic dns_sdbmethods_t tcldb_methods = {
983N/A tcldb_lookup,
889N/A NULL, /* authority */
5175N/A NULL, /* allnodes */
5175N/A tcldb_create,
5175N/A NULL /* destroy */
5175N/A};
5175N/A
5175N/A/*
5175N/A * Initialize the tcldb driver.
5175N/A */
5175N/Aisc_result_t
5175N/Atcldb_init(void) {
5175N/A isc_result_t result;
5175N/A int flags = DNS_SDBFLAG_RELATIVEOWNER | DNS_SDBFLAG_RELATIVERDATA;
5175N/A
5175N/A result = tcldb_driver_create(ns_g_mctx, &the_driver);
5175N/A if (result != ISC_R_SUCCESS)
5175N/A return (result);
5175N/A
5175N/A return (dns_sdb_register("tcl", &tcldb_methods, the_driver, flags,
5175N/A ns_g_mctx, &tcldb));
5175N/A}
5175N/A
983N/A/*
878N/A * Wrapper around dns_sdb_unregister().
878N/A */
878N/Avoid
878N/Atcldb_clear(void) {
878N/A if (tcldb != NULL)
983N/A dns_sdb_unregister(&tcldb);
983N/A if (the_driver != NULL)
983N/A tcldb_driver_destroy(&the_driver);
983N/A}
878N/A