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 + -
显示快捷键?