/*
* Copyright (C) 2002 Stichting NLnet, Netherlands, stichting@nlnet.nl.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the
* above copyright notice and this permission notice appear in all
* copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND STICHTING NLNET
* DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
* STICHTING NLNET BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE
* USE OR PERFORMANCE OF THIS SOFTWARE.
*
* The development of Dynamically Loadable Zones (DLZ) for Bind 9 was
* conceived and contributed by Rob Butler.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the
* above copyright notice and this permission notice appear in all
* copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND ROB BUTLER
* DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
* ROB BUTLER BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE
* USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/*
* Copyright (C) 1999-2001, 2016 Internet Systems Consortium, Inc. ("ISC")
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#ifdef DLZ_BDB
/*
* exit codes
* 0 everything ok
* 1 error parsing command line
* 2 Missing, too many or invalid combination of command line parameters
* 3 Unable to open BDB database.
* 4 Unable to allocate memory for, or create lexer.
* 5 unable to perform BDB cursor operation
*/
#include <config.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <isc/commandline.h>
#include <isc/formatcheck.h>
#include <db.h>
/* shut up compiler warnings about no previous prototype */
static void
show_usage(void);
int
int
void
bdb_cleanup(void);
void
void
insert_data(void);
openBDB(void);
open_lexer(void);
void
close_lexer(void);
void
operation_add(void);
void
operation_bulk(void);
void
/*%
* Maximum length of a single data line that
* may be inserted into database by this program.
* If you need to insert a line of data that is more
* than 10,000 characters change this definition.
*/
/*%
* BDB database names. If you want to use different
* database names change them here.
*/
/*%
* Error code returned by BDB secondary index callback functions.
* This error is returned if the callback function could not create
* the secondary index for any reason.
*/
/* A struct to hold all the relevant info about the database */
typedef struct bdb_instance {
/* Possible operations */
/*%
* quit macro is used instead of exit. quit always trys to close the lexer
* and the BDB database before exiting.
*/
/*%
* checkOp is used to verify that only one operation (list, del, add,
* bulk from file, bulk from stdin) is specified on the command line.
* This prevents a user from specifying two operations on the command
* line, which would make no sense anyway.
*/
/*%
* checkParam is used to only allow a parameter to be specified once.
* I.E. the parameter key can only be used on the command line once.
* any attempt to use it twice causes an error.
*/
/*%
* checkInvalidParam is used to only allow paramters which make sense for
* the operation selected. I.E. passing the key parameter makes no sense
* for the add operation, and thus it isn't allowed.
*/
/*%
* checkInvalidOption is used to only allow paramters which make sense for
* the operation selected - but checks boolean options.
* I.E. passing the "b" bare_list parameter makes no sense for the add
* operation, and thus it isn't allowed.
* if w == x then output error message "flag", "message"
*/
/* Global Variables */
/*% allow new lock files or DB to be created. */
/*% dump DB in DLZBDB bulk format */
/*%
* Displays usage message
*/
static void
show_usage(void) {
---Usage:---------------------------------------------------------------------\
\n\n\
List data:\n\
dlzbdb -l [-k key] [-z zone] [-h host] [-c client_zone] [-i client_ip]\n\
BDB_environment BDB_database\n\n\
Delete data:\n\
dlzbdb -d [-k key] [-c client_zone] [-i client_ip]\n\
BDB_environment BDB_database\n\n\
Bulk load data from file:\n\
dlzbdb -f file_to_load BDB_environment BDB_database\n\n\
Bulk load data from stdin\n\
dlzbdb -s BDB_environment BDB_database\n\n\
Add data:\n\
dlzbdb -a \"dns data to be added\" BDB_environment BDB_database\n\n\
Export data:\n\
dlzbdb -e BDB_environment BDB_database\n\n\
Normally operations can only be performed on an existing database files.\n\
Use the -n flag with any operation to allow files to be created.\n\
Existing files will NOT be truncated by using the -n flag.\n\
The -n flag will allow a new database to be created, or allow new\n\
environment files to be created for an existing database.\n\n\
---Format for -f & -a options:------------------------------------------------\
\n\n\
db_type zone host dns_type ttl ip\n\
db_type zone host dns_type ttl mx_priority mail_host\n\
db_type zone host dns_type ttl nm_svr resp_psn serial refresh retry expire min\
\n\
db_type zone client_ip\n\n\
---Examples:------------------------------------------------------------------\
\n\n\
d mynm.com www A 10 127.0.0.1\n\
d mynm.com @ MX 10 5 mail\n\
d mynm.com @ SOA 10 ns1.mynm.com. root.mynm.com. 2 28800 7200 604800 86400\n\
c mynm.com 127.0.0.1\n\
c mynm.com 192.168.0.10\n\
");
quit(1);
}
/*% BDB callback to create zone secondary index */
int
char *tmp;
char *left;
char *right;
int result=0;
/* Allocate memory to use in parsing the string */
/* verify memory was allocated */
goto getzone_cleanup;
}
/* copy data string into newly allocated memory */
/* split string at the first space */
/* copy string for "zone" secondary index */
goto getzone_cleanup;
}
/* set required values for BDB */
/* cleanup memory */
return result;
}
/*%
* BDB callback to create host secondary index
*/
int
char *tmp;
char *left;
char *right;
int result=0;
/* allocate memory to use in parsing the string */
/* verify memory was allocated */
goto gethost_cleanup;
}
/* copy data string into newly allocated memory */
/* we don't care about left string. */
/* memory of left string will be freed when tmp is freed. */
/* verify right still has some characters left */
goto gethost_cleanup;
}
/* get "host" from data string */
/* copy string for "host" secondary index */
goto gethost_cleanup;
}
/* set required values for BDB */
/* cleanup memory */
return result;
}
/*%
* Performs BDB cleanup. Close each database that we opened.
* Close environment. Set each var to NULL so we know they
* were closed and don't accidentally try to close them twice.
*/
void
bdb_cleanup(void) {
/* close cursors */
}
}
}
}
/* close databases */
}
}
}
}
/* close environment */
}
}
/*% Initializes, sets flags and then opens Berkeley databases. */
int result;
int createFlag = 0;
/* Initialize the database. */
return ISC_R_FAILURE;
}
/* set database flags. */
return ISC_R_FAILURE;
}
if (create_allowed == isc_boolean_true) {
}
/* open the database. */
createFlag, 0)) != 0) {
return ISC_R_FAILURE;
}
return ISC_R_SUCCESS;
}
/*%
* parses input and adds it to the BDB database
* Lexer should be instantiated, and either a file or buffer opened for it.
* The insert_data function is used by both the add, and bulk insert
* operations
*/
void
int bdbres;
/* make sure key & data are completely empty */
/* if client data, setup key for insertion */
}
/* always setup data for insertion */
/* execute insert against appropriate database. */
if (dns_data) {
} else {
}
/* if something went wrong, log error and quit */
if (bdbres != 0) {
quit(5);
}
}
void
insert_data(void) {
unsigned int opt =
ISC_LEXOPT_EOL | /* Want end-of-line token. */
ISC_LEXOPT_EOF | /* Want end-of-file token. */
ISC_LEXOPT_QSTRING | /* Recognize qstrings. */
ISC_LEXOPT_QSTRINGMULTILINE; /* Allow multiline "" strings */
/* Initialize buffers */
while (loop) {
if (result != ISC_R_SUCCESS)
goto data_cleanup;
case isc_tokentype_string:
if (data_type == 'u') {
/* store data_type */
/* verify data_type was specified correctly on input */
/* if not, set to 'b' so this line is ignored. */
data_type = 'b';
}
if (have_czone == isc_boolean_true) {
/* add string terminator to buffer */
} else {
/* add string terminator to buffer */
}
} else {
}
break;
case isc_tokentype_qstring:
break;
case isc_tokentype_eol:
case isc_tokentype_eof:
/* perform insert operation */
/* add string terminator to buffer */
(char *) &data_arr2);
} else if (data_type == 'b') {
} else {
}
}
}
/* reset buffer for next insert */
data_type ='u';
break;
default:
data_type = 'b';
break;
}
}
return;
/* let user know we had problems */
"\"bulk\" operation.\nStoped processing on line %lu.",
}
openBDB(void) {
int bdbres;
/* create BDB environment */
/* Basically BDB allocates and assigns memory to db->dbenv */
if (bdbres != 0) {
goto openBDB_cleanup;
}
/* open BDB environment */
if (create_allowed == isc_boolean_true) {
/* allowed to create new files */
} else { /* not allowed to create new files. */
DB_INIT_CDB | DB_INIT_MPOOL, 0);
}
if (bdbres != 0) {
goto openBDB_cleanup;
}
/* open dlz_data database. */
if (result != ISC_R_SUCCESS)
goto openBDB_cleanup;
/* open dlz_host database */
if (result != ISC_R_SUCCESS)
goto openBDB_cleanup;
/* open dlz_zone database. */
if (result != ISC_R_SUCCESS)
goto openBDB_cleanup;
/* open dlz_client database. */
if (result != ISC_R_SUCCESS)
goto openBDB_cleanup;
/* associate the host secondary database with the primary database */
if (bdbres != 0) {
goto openBDB_cleanup;
}
/* associate the zone secondary database with the primary database */
if (bdbres != 0) {
goto openBDB_cleanup;
}
return result;
bdb_cleanup();
return result;
}
/*% Create & open lexer to parse input data */
open_lexer(void) {
/* check if we already opened the lexer, if we did, return success */
return ISC_R_SUCCESS;
/* allocate memory for lexer, and verify it was allocated */
if (result != ISC_R_SUCCESS) {
return result;
}
/* create lexer */
if (result != ISC_R_SUCCESS)
/* set allowed commenting style */
ISC_LEXCOMMENT_CPLUSPLUS | /* Allow C++ comments */
ISC_LEXCOMMENT_SHELL); /* Allow shellcomments */
return result;
}
/*% Close the lexer, and cleanup memory */
void
close_lexer(void) {
/* If lexer is still open, close it & destroy it. */
}
/* if lexer memory is still allocated, destroy it. */
}
/*% Perform add operation */
void
operation_add(void) {
/* check for any parameters that are not allowed during add */
"for add operation");
/* if open lexer fails it alread prints error messages. */
if (open_lexer() != ISC_R_SUCCESS) {
quit(4);
}
/* copy input data to buffer */
/* tell lexer to use buffer as input */
quit(4);
}
/*common logic for "add" & "bulk" operations are handled by insert_data */
insert_data();
}
/*% Perform bulk insert operation */
void
operation_bulk(void) {
/* check for any parameters that are not allowed during bulk */
"for bulk load operation");
/* if open lexer fails it already prints error messages. */
if (open_lexer() != ISC_R_SUCCESS) {
quit(4);
}
quit(4);
}
quit(4);
}
/* common logic for "add" & "bulk" operations are handled by insert_data */
insert_data();
}
int bdbres;
void *p;
/* use a 5MB buffer for the bulk dump */
/* try to allocate a 5 MB buffer, if we fail write err msg, die. */
"Unable to allocate 5 MB buffer for bulk database dump\n");
return ISC_R_FAILURE;
}
/* get a cursor, make sure it worked. */
if (bdbres != 0) {
return ISC_R_FAILURE;
}
/* loop and dump all data */
for (;;) {
/* loop through data until DB_NOTFOUND is returned */
/* if not successful did we encounter DB_NOTFOUND, or */
/* have a different problem. */
if (bdbres != 0) {
if (bdbres != DB_NOTFOUND) {
return ISC_R_FAILURE;
}
/* Hit DB_NOTFOUND which means end of data. */
break;
} /* end of if (bdbres !=0) */
for (DB_MULTIPLE_INIT(p, bdbdata);;) {
if (type == 'c')
else
if (p == NULL)
break;
if (type == 'c')
else
} /* end of for (DB_MULTIPLE_INIT....) */
} /* end of for (;;) */
/* free the buffer we created earlier */
return ISC_R_SUCCESS;
}
/*%
* Perform listOrDelete operation
* if dlt == true, delete data
* else list data
*/
void
int bdbres = 0;
int curIndex = 0;
/* verify that only allowed parameters were passed. */
if (dlt == isc_boolean_true) {
"for delete operation");
"for delete operation");
"for list when k, z, or h are specified");
"for list operation");
"for list when c or i are specified");
"for list operation");
}
/* Dump database in "dlzbdb" bulk format */
if (list_everything == isc_boolean_true) {
!= ISC_R_SUCCESS)
return;
return;
} /* end if (list_everything) */
/* set NULL the 2nd and 3rd positions in curList. */
/* that way later when add cursors to the join list */
/* it is already null terminated. */
/* make sure other parameters weren't */
if (dlt == isc_boolean_true) {
} else {
if (bdbres == 0) {
printf("KEY | DATA\n");
}
} /* closes else of if (dlt == isc_boolean_true) */
if (bdbres == DB_NOTFOUND) {
printf("Key not found in database");
}
} /* closes if (key != NULL) */
/* if zone is passed */
/* create a cursor and make sure it worked */
if (bdbres != 0) {
return;
}
if (bdbres != 0) {
if (bdbres != DB_NOTFOUND) {
} else {
printf("Zone not found in database");
}
return;
}
/* add cursor to cursor list for later use in join */
}
/* if host is passed */
/* create a cursor and make sure it worked. */
if (bdbres != 0) {
return;
}
if (bdbres != 0) {
if (bdbres != DB_NOTFOUND) {
} else {
printf("Host not found in database");
}
return;
}
/* add cursor to cursor list for later use in join */
}
/* join any cursors */
if (bdbres != 0) {
return;
}
/* print a header to explain the output */
printf("KEY | DATA\n");
/* loop and list all results. */
while (bdbres == 0) {
/* get data */
/* verify call had no errors */
if (bdbres != 0) {
break;
}
} /* closes while loop */
}
quit(2);
}
/* if client_zone was passed */
/* create a cursor and make sure it worked. */
if (dlt == isc_boolean_true) {
/* open read-write cursor */
} else {
/* open read only cursor */
/* print a header to explain the output */
printf("CLIENT_ZONE | CLIENT_IP\n");
}
if (bdbres == DB_NOTFOUND) {
printf("Client zone & IP not found in database");
}
} else {
if (bdbres == DB_NOTFOUND) {
printf("Client zone not found in database");
}
}
while (bdbres == 0) {
if (dlt == isc_boolean_false) {
} else {
/* delete record. */
if (bdbres != 0) {
break;
}
}
break;
}
if (bdbres != 0) {
break;
}
} /* end while loop */
}
}
}
}
}
int
int ch;
char *endp;
/* there has to be at least 2 args, some operations require more */
if (argc < 2)
show_usage();
/* use the ISC commandline parser to get all the program arguments */
switch (ch) {
case 'n':
break;
case 'l':
break;
case 'd':
break;
case 'a':
break;
case 'f':
break;
case 's':
break;
case 'k':
}
break;
case 'z':
break;
case 'h':
break;
case 'c':
break;
case 'i':
break;
case 'e':
break;
case '?':
show_usage();
break;
default:
/* should never reach this point */
quit(1);
break;
}
}
/* argc & argv have been modified, so now only "extra" parameters are */
/* left in argc & argv. "Extra" parameters are any parameters that were */
/* not passed using a command line flag. Exactly 2 args should be left. */
/* The first should be the BDB environment path, the second should be the */
/* BDB database. The BDB database path can be either relative to the */
/* BDB environment path, or absolute. */
if (argc < 2) {
"must be specified");
quit(2);
} else if (argc > 2) {
quit(2);
}
/* get db_file to operate on */
if (openBDB() != ISC_R_SUCCESS) {
/* openBDB already prints error messages, don't do it here. */
bdb_cleanup();
quit(3);
}
switch(operation) {
case list:
break;
case dele:
break;
case add:
break;
case bulk:
break;
default:
"Select an operation (l d a f)");
quit(2);
break;
}
quit(0);
}
#endif