dlz_odbc_driver.c
来自「非常好的dns解析软件」· C语言 代码 · 共 1,569 行 · 第 1/3 页
C
1,569 行
} return result;}/*% * If the client is allowed to perform a zone transfer, the next order of * business is to get all the nodes in the zone, so bind can respond to the * query. */static isc_result_todbc_allnodes(const char *zone, void *driverarg, void *dbdata, dns_sdlzallnodes_t *allnodes){ isc_result_t result; dbinstance_t *dbi = NULL; SQLHSTMT *stmnt; SQLSMALLINT fields; char *data; char *type; char *ttl_s; int ttl; char *host; char *endp; UNUSED(driverarg); /* run the query and get the result set from the database. */ result = odbc_get_resultset(zone, NULL, NULL, ALLNODES, dbdata, &dbi); /* if we get "not implemented", send it along */ if (result == ISC_R_NOTIMPLEMENTED) return result; /* if we didn't get a result set, log an err msg. */ if (result != ISC_R_SUCCESS) { isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "Odbc driver unable to return " "result set for all nodes query"); return (ISC_R_FAILURE); } stmnt = ((odbc_db_t *) (dbi->dbconn))->stmnt; /* get number of columns */ if (!sqlOK(SQLNumResultCols(stmnt, &fields))) { isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "Odbc driver unable to process result set"); result = ISC_R_FAILURE; goto allnodes_cleanup; } if (fields < 4) { /* gotta have at least 4 columns */ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "Odbc driver too few fields returned by " "all nodes query"); result = ISC_R_FAILURE; goto allnodes_cleanup; } /* get things ready for processing */ result = ISC_R_FAILURE; while (sqlOK(SQLFetch(stmnt))) { /* set to null for next pass through */ data = host = type = ttl_s = NULL; /* * attempt to get DNS ttl, type, host, data then tell * Bind about them */ if ((result = odbc_getField(stmnt, 1, &ttl_s)) == ISC_R_SUCCESS && (result = odbc_getField(stmnt, 2, &type)) == ISC_R_SUCCESS && (result = odbc_getField(stmnt, 3, &host)) == ISC_R_SUCCESS && (result = odbc_getManyFields(stmnt, 4, fields, &data)) == ISC_R_SUCCESS) { /* convert ttl string to int */ ttl = strtol(ttl_s, &endp, 10); /* failure converting ttl. */ if (*endp != '\0' || ttl < 0) { isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "Odbc driver ttl must be " "a postive number"); result = ISC_R_FAILURE; } else { /* successful converting TTL, tell Bind */ result = dns_sdlz_putnamedrr(allnodes, host, type, ttl, data); } } /* closes big if () */ /* clean up mem */ if (ttl_s != NULL) isc_mem_free(ns_g_mctx, ttl_s); if (type != NULL) isc_mem_free(ns_g_mctx, type); if (host != NULL) isc_mem_free(ns_g_mctx, host); if (data != NULL) isc_mem_free(ns_g_mctx, data); /* if we weren't successful, log err msg */ if (result != ISC_R_SUCCESS) { isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "dns_sdlz_putnamedrr returned error. " "Error code was: %s", isc_result_totext(result)); result = ISC_R_FAILURE; goto allnodes_cleanup; } } /* closes while loop */ allnodes_cleanup: /* close cursor */ SQLCloseCursor(((odbc_db_t *) (dbi->dbconn))->stmnt);#ifdef ISC_PLATFORM_USETHREADS /* free lock on dbi so someone else can use it. */ isc_mutex_unlock(&dbi->instance_lock);#endif return result;}/*% * if the lookup function does not return SOA or NS records for the zone, * use this function to get that information for Bind. */static isc_result_todbc_authority(const char *zone, void *driverarg, void *dbdata, dns_sdlzlookup_t *lookup){ isc_result_t result; dbinstance_t *dbi = NULL; UNUSED(driverarg); /* run the query and get the result set from the database. */ result = odbc_get_resultset(zone, NULL, NULL, AUTHORITY, dbdata, &dbi); /* if we get "not implemented", send it along */ if (result == ISC_R_NOTIMPLEMENTED) return result; /* if we didn't get a result set, log an err msg. */ if (result != ISC_R_SUCCESS) { isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "Odbc driver unable to return " "result set for authority query"); return (ISC_R_FAILURE); } /* lookup and authority result sets are processed in the same manner */ /* odbc_process_rs does the job for both functions. */ return odbc_process_rs(lookup, dbi);}/*% if zone is supported, lookup up a (or multiple) record(s) in it */static isc_result_todbc_lookup(const char *zone, const char *name, void *driverarg, void *dbdata, dns_sdlzlookup_t *lookup){ isc_result_t result; dbinstance_t *dbi = NULL; UNUSED(driverarg); /* run the query and get the result set from the database. */ result = odbc_get_resultset(zone, name, NULL, LOOKUP, dbdata, &dbi); /* if we didn't get a result set, log an err msg. */ if (result != ISC_R_SUCCESS) { isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "Odbc driver unable to return " "result set for lookup query"); return (ISC_R_FAILURE); } /* lookup and authority result sets are processed in the same manner */ /* odbc_process_rs does the job for both functions. */ return odbc_process_rs(lookup, dbi);}/*% * 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_todbc_create(const char *dlzname, unsigned int argc, char *argv[], void *driverarg, void **dbdata){ isc_result_t result; odbc_instance_t *odbc_inst = NULL; dbinstance_t *db = NULL; SQLRETURN sqlRes;#ifdef ISC_PLATFORM_USETHREADS /* if multi-threaded, we need a few extra variables. */ int dbcount; int i; char *endp;#endif /* ISC_PLATFORM_USETHREADS */ UNUSED(dlzname); UNUSED(driverarg);#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), "Odbc 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), "Odbc 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, "Odbc 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, "Odbc 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, "Odbc driver database connection count " "must be positive."); return (ISC_R_FAILURE); }#endif /* ISC_PLATFORM_USETHREADS */ /* allocate memory for odbc instance */ odbc_inst = isc_mem_get(ns_g_mctx, sizeof(odbc_instance_t)); if (odbc_inst == NULL) return (ISC_R_NOMEMORY); memset(odbc_inst, 0, sizeof(odbc_instance_t)); /* parse connection string and get paramters. */ /* get odbc database dsn - required */ odbc_inst->dsn = (SQLCHAR *) getParameterValue(argv[2], "dsn="); if (odbc_inst->dsn == NULL) { isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "odbc driver requires a dns parameter."); result = ISC_R_FAILURE; goto cleanup; } /* get odbc database username */ /* if no username was passed, set odbc_inst.user = NULL; */ odbc_inst->user = (SQLCHAR *) getParameterValue(argv[2], "user="); /* get odbc database password */ /* if no password was passed, set odbc_inst.pass = NULL; */ odbc_inst->pass = (SQLCHAR *) getParameterValue(argv[2], "pass="); /* create odbc environment & set environment to ODBC V3 */ if (odbc_inst->sql_env == NULL) { /* create environment handle */ sqlRes = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &(odbc_inst->sql_env)); if (!sqlOK(sqlRes)) { isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_INFO, "Odbc driver unable to allocate memory"); result = ISC_R_NOMEMORY; goto cleanup; } /*set ODBC version = 3 */ sqlRes = SQLSetEnvAttr(odbc_inst->sql_env, SQL_ATTR_ODBC_VERSION, (void *) SQL_OV_ODBC3, 0); if (!sqlOK(sqlRes)) { isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_INFO, "Unable to configure ODBC environment"); result = ISC_R_NOMEMORY; goto cleanup; } }#ifdef ISC_PLATFORM_USETHREADS /* allocate memory for database connection list */ odbc_inst->db = isc_mem_get(ns_g_mctx, sizeof(db_list_t)); if (odbc_inst->db == NULL) { result = ISC_R_NOMEMORY; goto cleanup; } /* initialize DB connection list */ ISC_LIST_INIT(*odbc_inst->db); /* 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, &db); break; case 6: result = build_sqldbinstance(ns_g_mctx, NULL, NULL, argv[5], argv[3], argv[4], NULL, &db); break; case 7: result = build_sqldbinstance(ns_g_mctx, argv[6], NULL, argv[5], argv[3], argv[4], NULL, &db); break; case 8: result = build_sqldbinstance(ns_g_mctx, argv[6], argv[7], argv[5], argv[3], argv[4], NULL, &db); 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, "Odbc driver could not create " "database instance object."); goto cleanup; }#ifdef ISC_PLATFORM_USETHREADS /* when multithreaded, build a list of DBI's */ ISC_LINK_INIT(db, link); ISC_LIST_APPEND(*odbc_inst->db, db, link);#endif result = odbc_connect(odbc_inst, (odbc_db_t **) &(db->dbconn)); if (result != ISC_R_SUCCESS) {#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. */ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "Odbc driver failed to create database " "connection number %u after 3 attempts", i+1);#else isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "Odbc driver failed to create database " "connection after 3 attempts");#endif goto cleanup; }#ifdef ISC_PLATFORM_USETHREADS /* set DB = null for next loop through. */ db = NULL; } /* end for loop */#else /* tell odbc_inst about the db connection we just created. */ odbc_inst->db = db;#endif /* set dbdata to the odbc_instance we created. */ *dbdata = odbc_inst; /* hey, we got through all of that ok, return success. */ return(ISC_R_SUCCESS); cleanup: destroy_odbc_instance(odbc_inst); return result;}/*% * 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 voidodbc_destroy(void *driverarg, void *dbdata){ UNUSED(driverarg); destroy_odbc_instance((odbc_instance_t *) dbdata);}/* pointers to all our runtime methods. *//* this is used during driver registration *//* i.e. in dlz_odbc_init below. */static dns_sdlzmethods_t dlz_odbc_methods = { odbc_create, odbc_destroy, odbc_findzone, odbc_lookup, odbc_authority, odbc_allnodes, odbc_allowzonexfr};/*% * Wrapper around dns_sdlzregister(). */isc_result_tdlz_odbc_init(void) { isc_result_t result; /* * Write debugging message to log */ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2), "Registering DLZ odbc driver."); /* * Driver is always threadsafe. When multithreaded all * functions use multithreaded code. When not multithreaded, * all functions can only be entered once, but only 1 thread * of operation is available in Bind. So everything is still * threadsafe. */ result = dns_sdlzregister("odbc", &dlz_odbc_methods, NULL, DNS_SDLZFLAG_RELATIVEOWNER | DNS_SDLZFLAG_RELATIVERDATA | DNS_SDLZFLAG_THREADSAFE, ns_g_mctx, &dlz_odbc); /* if we can't register the driver, there are big problems. */ if (result != ISC_R_SUCCESS) { UNEXPECTED_ERROR(__FILE__, __LINE__, "dns_sdlzregister() failed: %s", isc_result_totext(result)); result = ISC_R_UNEXPECTED; } return result;}/*% * Wrapper around dns_sdlzunregister(). */voiddlz_odbc_clear(void) { /* * Write debugging message to log */ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2), "Unregistering DLZ odbc driver."); /* unregister the driver. */ if (dlz_odbc != NULL) dns_sdlzunregister(&dlz_odbc);}#endif
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?