/*% * destroy an instance of the driver. Remember, only 1 copy of the driver's * code is ever loaded, the driver has to remember which context it's * operating in. This is done via use of the dbdata argument. * so we really only need to clean it up since we are not using driverarg. */ static void postgres_destroy(void *driverarg, void *dbdata) { #ifdef ISC_PLATFORM_USETHREADS UNUSED(driverarg); /* cleanup the list of DBI's */ postgres_destroy_dblist((db_list_t *) dbdata); #else /* ISC_PLATFORM_USETHREADS */ dbinstance_t *dbi; UNUSED(driverarg); dbi = (dbinstance_t *) dbdata; /* release DB connection */ if (dbi->dbconn != NULL) PQfinish((PGconn *) dbi->dbconn); /* destroy single DB instance */ destroy_sqldbinstance(dbi); #endif /* ISC_PLATFORM_USETHREADS */ }
void dlz_ldap_destroy(void *driverarg, void *dbdata) { UNUSED(driverarg); if (dbdata != NULL) { #ifdef ISC_PLATFORM_USETHREADS /* cleanup the list of DBI's */ ldap_destroy_dblist((db_list_t *) ((ldap_instance_t *)dbdata)->db); #else /* ISC_PLATFORM_USETHREADS */ if (((ldap_instance_t *)dbdata)->db->dbconn != NULL) ldap_unbind_s((LDAP *) ((ldap_instance_t *)dbdata)->db->dbconn); /* destroy single DB instance */ destroy_sqldbinstance(((ldap_instance_t *)dbdata)->db); #endif /* ISC_PLATFORM_USETHREADS */ if (((ldap_instance_t *)dbdata)->hosts != NULL) isc_mem_free(ns_g_mctx, ((ldap_instance_t *)dbdata)->hosts); if (((ldap_instance_t *)dbdata)->user != NULL) isc_mem_free(ns_g_mctx, ((ldap_instance_t *)dbdata)->user); if (((ldap_instance_t *)dbdata)->cred != NULL) isc_mem_free(ns_g_mctx, ((ldap_instance_t *)dbdata)->cred); isc_mem_put(ns_g_mctx, dbdata, sizeof(ldap_instance_t)); } }
static void mysql_destroy(void *driverarg, void *dbdata) { dbinstance_t *dbi; UNUSED(driverarg); dbi = (dbinstance_t *) dbdata; /* release DB connection */ if (dbi->dbconn != NULL) mysql_close((MYSQL *) dbi->dbconn); /* destroy DB instance */ destroy_sqldbinstance(dbi); }
/*% * Properly cleans up a list of database instances. * This function is only used when the driver is compiled for * multithreaded operation. */ static void ldap_destroy_dblist(db_list_t *dblist) { dbinstance_t *ndbi = NULL; dbinstance_t *dbi = NULL; /* get the first DBI in the list */ ndbi = ISC_LIST_HEAD(*dblist); /* loop through the list */ while (ndbi != NULL) { dbi = ndbi; /* get the next DBI in the list */ ndbi = ISC_LIST_NEXT(dbi, link); /* release DB connection */ if (dbi->dbconn != NULL) ldap_unbind_s((LDAP *) dbi->dbconn); /* release all memory that comprised a DBI */ destroy_sqldbinstance(dbi); } /* release memory for the list structure */ isc_mem_put(ns_g_mctx, dblist, sizeof(db_list_t)); }
/*% * create an instance of the driver. Remember, only 1 copy of the driver's * code is ever loaded, the driver has to remember which context it's * operating in. This is done via use of the dbdata argument which is * passed into all query functions. */ static isc_result_t postgres_create(const char *dlzname, unsigned int argc, char *argv[], void *driverarg, void **dbdata) { isc_result_t result; dbinstance_t *dbi = NULL; unsigned int j; #ifdef ISC_PLATFORM_USETHREADS /* if multi-threaded, we need a few extra variables. */ int dbcount; db_list_t *dblist = NULL; int i; char *endp; #endif /* ISC_PLATFORM_USETHREADS */ UNUSED(driverarg); UNUSED(dlzname); /* seed random # generator */ srand( (unsigned)time( NULL ) ); #ifdef ISC_PLATFORM_USETHREADS /* if debugging, let user know we are multithreaded. */ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(1), "Postgres driver running multithreaded"); #else /* ISC_PLATFORM_USETHREADS */ /* if debugging, let user know we are single threaded. */ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(1), "Postgres driver running single threaded"); #endif /* ISC_PLATFORM_USETHREADS */ /* verify we have at least 5 arg's passed to the driver */ if (argc < 5) { isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "Postgres driver requires at least " "4 command line args."); return (ISC_R_FAILURE); } /* no more than 8 arg's should be passed to the driver */ if (argc > 8) { isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "Postgres driver cannot accept more than " "7 command line args."); return (ISC_R_FAILURE); } /* multithreaded build can have multiple DB connections */ #ifdef ISC_PLATFORM_USETHREADS /* check how many db connections we should create */ dbcount = strtol(argv[1], &endp, 10); if (*endp != '\0' || dbcount < 0) { isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "Postgres driver database connection count " "must be positive."); return (ISC_R_FAILURE); } /* allocate memory for database connection list */ dblist = isc_mem_get(ns_g_mctx, sizeof(db_list_t)); if (dblist == NULL) return (ISC_R_NOMEMORY); /* initialize DB connection list */ ISC_LIST_INIT(*dblist); /* * create the appropriate number of database instances (DBI) * append each new DBI to the end of the list */ for (i=0; i < dbcount; i++) { #endif /* ISC_PLATFORM_USETHREADS */ /* how many queries were passed in from config file? */ switch(argc) { case 5: result = build_sqldbinstance(ns_g_mctx, NULL, NULL, NULL, argv[3], argv[4], NULL, &dbi); break; case 6: result = build_sqldbinstance(ns_g_mctx, NULL, NULL, argv[5], argv[3], argv[4], NULL, &dbi); break; case 7: result = build_sqldbinstance(ns_g_mctx, argv[6], NULL, argv[5], argv[3], argv[4], NULL, &dbi); break; case 8: result = build_sqldbinstance(ns_g_mctx, argv[6], argv[7], argv[5], argv[3], argv[4], NULL, &dbi); break; default: /* not really needed, should shut up compiler. */ result = ISC_R_FAILURE; } if (result == ISC_R_SUCCESS) { isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2), "Postgres driver created database " "instance object."); } else { /* unsuccessful?, log err msg and cleanup. */ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "Postgres driver could not create " "database instance object."); goto cleanup; } #ifdef ISC_PLATFORM_USETHREADS /* when multithreaded, build a list of DBI's */ ISC_LINK_INIT(dbi, link); ISC_LIST_APPEND(*dblist, dbi, link); #endif /* create and set db connection */ dbi->dbconn = PQconnectdb(argv[2]); /* * if db connection cannot be created, log err msg and * cleanup. */ if (dbi->dbconn == NULL) { isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "Postgres driver could not allocate " "memory for database connection"); goto cleanup; } /* if we cannot connect the first time, try 3 more times. */ for (j = 0; PQstatus((PGconn *) dbi->dbconn) != CONNECTION_OK && j < 3; j++) PQreset((PGconn *) dbi->dbconn); #ifdef ISC_PLATFORM_USETHREADS /* * if multi threaded, let user know which connection * failed. user could be attempting to create 10 db * connections and for some reason the db backend only * allows 9 */ if (PQstatus((PGconn *) dbi->dbconn) != CONNECTION_OK) { isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "Postgres driver failed to create " "database connection number %u " "after 4 attempts", i + 1); goto cleanup; } /* set DBI = null for next loop through. */ dbi = NULL; } /* end for loop */ /* set dbdata to the list we created. */ *dbdata = dblist; #else /* ISC_PLATFORM_USETHREADS */ /* if single threaded, just let user know we couldn't connect. */ if (PQstatus((PGconn *) dbi->dbconn) != CONNECTION_OK) { isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "Postgres driver failed to create database " "connection after 4 attempts"); goto cleanup; } /* * single threaded build can only use 1 db connection, return * it via dbdata */ *dbdata = dbi; #endif /* ISC_PLATFORM_USETHREADS */ /* hey, we got through all of that ok, return success. */ return(ISC_R_SUCCESS); cleanup: #ifdef ISC_PLATFORM_USETHREADS /* * if multithreaded, we could fail because only 1 connection * couldn't be made. We should cleanup the other successful * connections properly. */ postgres_destroy_dblist(dblist); #else /* ISC_PLATFORM_USETHREADS */ if (dbi != NULL) destroy_sqldbinstance(dbi); #endif /* ISC_PLATFORM_USETHREADS */ return(ISC_R_FAILURE); }
/*% * create an instance of the driver. Remember, only 1 copy of the driver's * code is ever loaded, the driver has to remember which context it's * operating in. This is done via use of the dbdata argument which is * passed into all query functions. */ static isc_result_t mysql_create(const char *dlzname, unsigned int argc, char *argv[], void *driverarg, void **dbdata) { isc_result_t result; dbinstance_t *dbi = NULL; char *tmp = NULL; char *dbname = NULL; char *host = NULL; char *user = NULL; char *pass = NULL; char *socket = NULL; int port; MYSQL *dbc; char *endp; int j; unsigned int flags = 0; #if MYSQL_VERSION_ID >= 50000 my_bool auto_reconnect = 1; #endif UNUSED(driverarg); UNUSED(dlzname); /* verify we have at least 4 arg's passed to the driver */ if (argc < 4) { isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "mysql driver requires " "at least 4 command line args."); return (ISC_R_FAILURE); } /* no more than 8 arg's should be passed to the driver */ if (argc > 8) { isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "mysql driver cannot accept " "more than 7 command line args."); return (ISC_R_FAILURE); } /* parse connection string and get paramters. */ /* get db name - required */ dbname = getParameterValue(argv[1], "dbname="); if (dbname == NULL) { isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "mysql driver requires a dbname parameter."); result = ISC_R_FAILURE; goto full_cleanup; } /* get db port. Not required, but must be > 0 if specified */ tmp = getParameterValue(argv[1], "port="); if (tmp == NULL) { port = 0; } else { port = strtol(tmp, &endp, 10); if (*endp != '\0' || port < 0) { isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "Mysql driver port " "must be a positive number."); isc_mem_free(ns_g_mctx, tmp); result = ISC_R_FAILURE; goto full_cleanup; } isc_mem_free(ns_g_mctx, tmp); } /* how many queries were passed in from config file? */ switch(argc) { case 4: result = build_sqldbinstance(ns_g_mctx, NULL, NULL, NULL, argv[2], argv[3], NULL, &dbi); break; case 5: result = build_sqldbinstance(ns_g_mctx, NULL, NULL, argv[4], argv[2], argv[3], NULL, &dbi); break; case 6: result = build_sqldbinstance(ns_g_mctx, argv[5], NULL, argv[4], argv[2], argv[3], NULL, &dbi); break; case 7: result = build_sqldbinstance(ns_g_mctx, argv[5], argv[6], argv[4], argv[2], argv[3], NULL, &dbi); break; case 8: result = build_sqldbinstance(ns_g_mctx, argv[5], argv[6], argv[4], argv[2], argv[3], argv[7], &dbi); break; default: /* not really needed, should shut up compiler. */ result = ISC_R_FAILURE; } /* unsuccessful?, log err msg and cleanup. */ if (result != ISC_R_SUCCESS) { isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "mysql driver could not create " "database instance object."); result = ISC_R_FAILURE; goto cleanup; } /* create and set db connection */ dbi->dbconn = mysql_init(NULL); /* if db connection cannot be created, log err msg and cleanup. */ if (dbi->dbconn == NULL) { isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "mysql driver could not allocate " "memory for database connection"); result = ISC_R_FAILURE; goto full_cleanup; } tmp = getParameterValue(argv[1], "compress="); if (tmp != NULL) { if (strcasecmp(tmp, "true") == 0) flags = CLIENT_COMPRESS; isc_mem_free(ns_g_mctx, tmp); } tmp = getParameterValue(argv[1], "ssl="); if (tmp != NULL) { if (strcasecmp(tmp, "true") == 0) flags = flags | CLIENT_SSL; isc_mem_free(ns_g_mctx, tmp); } tmp = getParameterValue(argv[1], "space="); if (tmp != NULL) { if (strcasecmp(tmp, "ignore") == 0) flags = flags | CLIENT_IGNORE_SPACE; isc_mem_free(ns_g_mctx, tmp); } dbc = NULL; host = getParameterValue(argv[1], "host="); user = getParameterValue(argv[1], "user="******"pass="******"socket="); #if MYSQL_VERSION_ID >= 50000 /* enable automatic reconnection. */ if (mysql_options((MYSQL *) dbi->dbconn, MYSQL_OPT_RECONNECT, &auto_reconnect) != 0) { isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_WARNING, "mysql driver failed to set " "MYSQL_OPT_RECONNECT option, continuing"); } #endif for (j=0; dbc == NULL && j < 4; j++) dbc = mysql_real_connect((MYSQL *) dbi->dbconn, host, user, pass, dbname, port, socket, flags); /* let user know if we couldn't connect. */ if (dbc == NULL) { isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "mysql driver failed to create " "database connection after 4 attempts"); result = ISC_R_FAILURE; goto full_cleanup; } /* return db connection via dbdata */ *dbdata = dbi; result = ISC_R_SUCCESS; goto cleanup; full_cleanup: destroy_sqldbinstance(dbi); cleanup: if (dbname != NULL) isc_mem_free(ns_g_mctx, dbname); if (host != NULL) isc_mem_free(ns_g_mctx, host); if (user != NULL) isc_mem_free(ns_g_mctx, user); if (pass != NULL) isc_mem_free(ns_g_mctx, pass); if (socket != NULL) isc_mem_free(ns_g_mctx, socket); return result; }
/*% constructs a sql dbinstance (DBI) */ isc_result_t sdlzh_build_sqldbinstance(isc_mem_t *mctx, const char *allnodes_str, const char *allowxfr_str, const char *authority_str, const char *findzone_str, const char *lookup_str, const char *countzone_str, dbinstance_t **dbi) { isc_result_t result; dbinstance_t *db = NULL; REQUIRE(dbi != NULL && *dbi == NULL); REQUIRE(mctx != NULL); /* allocate and zero memory for driver structure */ db = isc_mem_get(mctx, sizeof(dbinstance_t)); if (db == NULL) { isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "Could not allocate memory for " "database instance object."); return (ISC_R_NOMEMORY); } memset(db, 0, sizeof(dbinstance_t)); db->dbconn = NULL; db->client = NULL; db->record = NULL; db->zone = NULL; db->mctx = NULL; db->query_buf = NULL; db->allnodes_q = NULL; db->allowxfr_q = NULL; db->authority_q = NULL; db->findzone_q = NULL; db->countzone_q = NULL; db->lookup_q = NULL; /* attach to the memory context */ isc_mem_attach(mctx, &db->mctx); /* initialize the reference count mutex */ result = isc_mutex_init(&db->instance_lock); if (result != ISC_R_SUCCESS) { UNEXPECTED_ERROR(__FILE__, __LINE__, "isc_mutex_init() failed: %s", isc_result_totext(result)); goto cleanup; } /* build the all nodes query list */ result = build_querylist(mctx, allnodes_str, &db->zone, &db->record, &db->client, &db->allnodes_q, SDLZH_REQUIRE_ZONE); /* if unsuccessful, log err msg and cleanup */ if (result != ISC_R_SUCCESS) { isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "Could not build all nodes query list"); goto cleanup; } /* build the allow zone transfer query list */ result = build_querylist(mctx, allowxfr_str, &db->zone, &db->record, &db->client, &db->allowxfr_q, SDLZH_REQUIRE_ZONE | SDLZH_REQUIRE_CLIENT); /* if unsuccessful, log err msg and cleanup */ if (result != ISC_R_SUCCESS) { isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "Could not build allow xfr query list"); goto cleanup; } /* build the authority query, query list */ result = build_querylist(mctx, authority_str, &db->zone, &db->record, &db->client, &db->authority_q, SDLZH_REQUIRE_ZONE); /* if unsuccessful, log err msg and cleanup */ if (result != ISC_R_SUCCESS) { isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "Could not build authority query list"); goto cleanup; } /* build findzone query, query list */ result = build_querylist(mctx, findzone_str, &db->zone, &db->record, &db->client, &db->findzone_q, SDLZH_REQUIRE_ZONE); /* if unsuccessful, log err msg and cleanup */ if (result != ISC_R_SUCCESS) { isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "Could not build find zone query list"); goto cleanup; } /* build countzone query, query list */ result = build_querylist(mctx, countzone_str, &db->zone, &db->record, &db->client, &db->countzone_q, SDLZH_REQUIRE_ZONE); /* if unsuccessful, log err msg and cleanup */ if (result != ISC_R_SUCCESS) { isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "Could not build count zone query list"); goto cleanup; } /* build lookup query, query list */ result = build_querylist(mctx, lookup_str, &db->zone, &db->record, &db->client, &db->lookup_q, SDLZH_REQUIRE_RECORD); /* if unsuccessful, log err msg and cleanup */ if (result != ISC_R_SUCCESS) { isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "Could not build lookup query list"); goto cleanup; } /* pass back the db instance */ *dbi = (dbinstance_t *) db; /* return success */ return (ISC_R_SUCCESS); cleanup: /* destroy whatever was build of the db instance */ destroy_sqldbinstance(db); /* return failure */ return (ISC_R_FAILURE); }
static void destroy_odbc_instance(odbc_instance_t *odbc_inst) { #ifdef ISC_PLATFORM_USETHREADS dbinstance_t *ndbi = NULL; dbinstance_t *dbi = NULL; /* get the first DBI in the list */ ndbi = ISC_LIST_HEAD(*odbc_inst->db); /* loop through the list */ while (ndbi != NULL) { dbi = ndbi; /* get the next DBI in the list */ ndbi = ISC_LIST_NEXT(dbi, link); /* if we have a connection / statement object in memory */ if (dbi->dbconn != NULL) { /* free statement handle */ if (((odbc_db_t *) (dbi->dbconn))->stmnt != NULL) { SQLFreeHandle(SQL_HANDLE_STMT, ((odbc_db_t *) (dbi->dbconn))->stmnt); ((odbc_db_t *) (dbi->dbconn))->stmnt = NULL; } /* disconnect from database & free connection handle */ if (((odbc_db_t *) (dbi->dbconn))->dbc != NULL) { SQLDisconnect(((odbc_db_t *) dbi->dbconn)->dbc); SQLFreeHandle(SQL_HANDLE_DBC, ((odbc_db_t *) (dbi->dbconn))->dbc); ((odbc_db_t *) (dbi->dbconn))->dbc = NULL; } /* free memory that held connection & statement. */ isc_mem_free(ns_g_mctx, dbi->dbconn); } /* release all memory that comprised a DBI */ destroy_sqldbinstance(dbi); } /* release memory for the list structure */ isc_mem_put(ns_g_mctx, odbc_inst->db, sizeof(db_list_t)); #else /* ISC_PLATFORM_USETHREADS */ /* free statement handle */ if (((odbc_db_t *) (odbc_inst->db->dbconn))->stmnt != NULL) { SQLFreeHandle(SQL_HANDLE_STMT, ((odbc_db_t *) (odbc_inst->db->dbconn))->stmnt); ((odbc_db_t *) (odbc_inst->db->dbconn))->stmnt = NULL; } /* disconnect from database, free connection handle */ if (((odbc_db_t *) (odbc_inst->db->dbconn))->dbc != NULL) { SQLDisconnect(((odbc_db_t *) (odbc_inst->db->dbconn))->dbc); SQLFreeHandle(SQL_HANDLE_DBC, ((odbc_db_t *) (odbc_inst->db->dbconn))->dbc); ((odbc_db_t *) (odbc_inst->db->dbconn))->dbc = NULL; } /* free mem for the odbc_db_t structure held in db */ if (((odbc_db_t *) odbc_inst->db->dbconn) != NULL) { isc_mem_free(ns_g_mctx, odbc_inst->db->dbconn); odbc_inst->db->dbconn = NULL; } if (odbc_inst->db != NULL) destroy_sqldbinstance(odbc_inst->db); #endif /* ISC_PLATFORM_USETHREADS */ /* free sql environment */ if (odbc_inst->sql_env != NULL) SQLFreeHandle(SQL_HANDLE_ENV, odbc_inst->sql_env); /* free ODBC instance strings */ if (odbc_inst->dsn != NULL) isc_mem_free(ns_g_mctx, odbc_inst->dsn); if (odbc_inst->pass != NULL) isc_mem_free(ns_g_mctx, odbc_inst->pass); if (odbc_inst->user != NULL) isc_mem_free(ns_g_mctx, odbc_inst->user); /* free memory for odbc_inst */ if (odbc_inst != NULL) isc_mem_put(ns_g_mctx, odbc_inst, sizeof(odbc_instance_t)); }