dlz_odbc_driver.c

来自「非常好的dns解析软件」· C语言 代码 · 共 1,569 行 · 第 1/3 页

C
1,569
字号
		if (dbi->allnodes_q == NULL) {			result = ISC_R_NOTIMPLEMENTED;			goto cleanup;		}		break;	case ALLOWXFR:		/* same as comments as ALLNODES */		if (dbi->allowxfr_q == NULL) {			result = ISC_R_NOTIMPLEMENTED;			goto cleanup;		}		break;	case AUTHORITY:		/* same as comments as ALLNODES */		if (dbi->authority_q == NULL) {			result = ISC_R_NOTIMPLEMENTED;			goto cleanup;		}		break;	case FINDZONE:		/* this is required.  It's the whole point of DLZ! */		if (dbi->findzone_q == NULL) {			isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,				      DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),				      "No query specified for findzone.  "				      "Findzone requires a query");			result = ISC_R_FAILURE;			goto cleanup;		}		break;	case LOOKUP:		/* this is required.  It's also a major point of DLZ! */		if (dbi->lookup_q == NULL) {			isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,				      DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),				      "No query specified for lookup.  "				      "Lookup requires a query");			result = ISC_R_FAILURE;			goto cleanup;		}		break;	default:		/*		 * this should never happen.  If it does, the code is		 * screwed up!		 */		UNEXPECTED_ERROR(__FILE__, __LINE__,				 "Incorrect query flag passed to "				 "odbc_get_resultset");		result = ISC_R_UNEXPECTED;		goto cleanup;	}	/*	 * was a zone string passed?  If so, make it safe for use in	 * queries.	 */	if (zone != NULL) {		dbi->zone = odbc_escape_string(zone);		if (dbi->zone == NULL) {			result = ISC_R_NOMEMORY;			goto cleanup;		}	} else {	/* no string passed, set the string pointer to NULL */		dbi->zone = NULL;	}	/*	 * was a record string passed?  If so, make it safe for use in	 * queries.	 */	if (record != NULL) {		dbi->record = odbc_escape_string(record);		if (dbi->record == NULL) {			result = ISC_R_NOMEMORY;			goto cleanup;		}	} else {	/* no string passed, set the string pointer to NULL */		dbi->record = NULL;	}	/*	 * was a client string passed?  If so, make it safe for use in	 * queries.	 */	if (client != NULL) {		dbi->client = odbc_escape_string(client);		if (dbi->client == NULL) {			result = ISC_R_NOMEMORY;			goto cleanup;		}	} else {	/* no string passed, set the string pointer to NULL */		dbi->client = NULL;	}	/*	 * what type of query are we going to run?	 * this time we build the actual query to run.	 */	switch(query) {	case ALLNODES:		querystring = build_querystring(ns_g_mctx, dbi->allnodes_q);		break;	case ALLOWXFR:		querystring = build_querystring(ns_g_mctx, dbi->allowxfr_q);		break;	case AUTHORITY:		querystring = build_querystring(ns_g_mctx, dbi->authority_q);		break;	case FINDZONE:		querystring = build_querystring(ns_g_mctx, dbi->findzone_q);		break;	case LOOKUP:		querystring = build_querystring(ns_g_mctx, dbi->lookup_q);		break;	default:		/*		 * this should never happen.  If it does, the code is		 * screwed up!		 */		UNEXPECTED_ERROR(__FILE__, __LINE__,				 "Incorrect query flag passed to "				 "odbc_get_resultset");		result = ISC_R_UNEXPECTED;		goto cleanup;	}	/* if the querystring is null, Bummer, outta RAM.  UPGRADE TIME!!!   */	if (querystring  == NULL) {		result = ISC_R_NOMEMORY;		goto cleanup;	}	/* output the full query string during debug so we can see */	/* what lame error the query has. */	isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,		      DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(1),		      "\nQuery String: %s\n", querystring);	/* attempt query up to 3 times. */	for (j=0; j < 3; j++) {		/* try to get result set */		sqlRes = SQLExecDirect(((odbc_db_t *) dbi->dbconn)->stmnt,				       (SQLCHAR *) querystring,				       (SQLINTEGER) strlen(querystring));		/* if error, reset DB connection */		if (!sqlOK(sqlRes)) {			/* close cursor */			SQLCloseCursor(((odbc_db_t *) dbi->dbconn)->stmnt);			/* attempt to reconnect */			result = odbc_connect((odbc_instance_t *) dbdata,					      (odbc_db_t **) &(dbi->dbconn));			/* check if we reconnected */			if (result != ISC_R_SUCCESS)				break;			/* incase this is the last time through the loop */			result = ISC_R_FAILURE;		} else {			result = ISC_R_SUCCESS;			/* return dbi */			*r_dbi = dbi;			/* result set ok, break loop */			break;		}	}	/* end for loop */ cleanup:	/* it's always good to cleanup after yourself */		/* if we couldn't even allocate DBI, just return NULL */	if (dbi == NULL)		return ISC_R_FAILURE;	/* free dbi->zone string */	if (dbi->zone != NULL)		isc_mem_free(ns_g_mctx, dbi->zone);	/* free dbi->record string */	if (dbi->record != NULL)		isc_mem_free(ns_g_mctx, dbi->record);	/* free dbi->client string */	if (dbi->client != NULL)		isc_mem_free(ns_g_mctx, dbi->client);#ifdef ISC_PLATFORM_USETHREADS	/* if we are done using this dbi, release the lock */	if (result != ISC_R_SUCCESS)		isc_mutex_unlock(&dbi->instance_lock);#endif /* ISC_PLATFORM_USETHREADS */	/* release query string */	if (querystring  != NULL)		isc_mem_free(ns_g_mctx, querystring );	/* return result */	return result;}/*% * Gets a single field from the ODBC statement.  The memory for the * returned data is dynamically allocated.  If this method is successful * it is the reponsibility of the caller to free the memory using * isc_mem_free(ns_g_mctx, *ptr); */static isc_result_todbc_getField(SQLHSTMT *stmnt, SQLSMALLINT field, char **data) {	SQLINTEGER size;	REQUIRE(data != NULL && *data == NULL);	if (sqlOK(SQLColAttribute(stmnt, field, SQL_DESC_DISPLAY_SIZE,				  NULL, 0, NULL, &size)) && size > 0) {		*data = isc_mem_allocate(ns_g_mctx, size + 1);		if (data != NULL) {			if (sqlOK(SQLGetData(stmnt, field, SQL_C_CHAR,					     *data, size + 1,&size)))				return ISC_R_SUCCESS;			isc_mem_free(ns_g_mctx, *data);		}	}	return ISC_R_FAILURE;}/*% * Gets multiple fields from the ODBC statement.  The memory for the * returned data is dynamically allocated.  If this method is successful * it is the reponsibility of the caller to free the memory using * isc_mem_free(ns_g_mctx, *ptr); */static isc_result_todbc_getManyFields(SQLHSTMT *stmnt, SQLSMALLINT startField,		   SQLSMALLINT endField, char **retData) {	isc_result_t result;	SQLINTEGER size;	int totSize = 0;	SQLSMALLINT i;	int j = 0;	char *data;	REQUIRE(retData != NULL && *retData == NULL);	REQUIRE(startField > 0 && startField <= endField);	/* determine how large the data is */	for (i=startField; i <= endField; i++)		if (sqlOK(SQLColAttribute(stmnt, i, SQL_DESC_DISPLAY_SIZE,					  NULL, 0, NULL, &size)) && size > 0) {			/* always allow for a " " (space) character */			totSize += (size + 1);			/* after the data item */		}	if (totSize < 1)		return ISC_R_FAILURE;	/* allow for a "\n" at the end of the string/ */	data = isc_mem_allocate(ns_g_mctx, ++totSize);	if (data == NULL)		return ISC_R_NOMEMORY;	result = ISC_R_FAILURE;	/* get the data and concat all fields into a large string */	for (i=startField; i <= endField; i++) {		if (sqlOK(SQLGetData(stmnt, i, SQL_C_CHAR, &(data[j]),				     totSize - j, &size))) {			if (size > 0) {				j += size;				data[j++] = ' ';				data[j] = '\0';				result = ISC_R_SUCCESS;			}		} else {			isc_mem_free(ns_g_mctx, data);			return ISC_R_FAILURE;		}	}	if (result != ISC_R_SUCCESS) {		isc_mem_free(ns_g_mctx, data);		return result;	}	*retData = data;	return ISC_R_SUCCESS;}/*% * The processing of result sets for lookup and authority are * exactly the same.  So that functionality has been moved * into this function to minimize code. */static isc_result_todbc_process_rs(dns_sdlzlookup_t *lookup, dbinstance_t *dbi){	isc_result_t result;	SQLSMALLINT fields;	SQLHSTMT  *stmnt;	char *ttl_s;	char *type;	char *data;	char *endp;	int ttl;	REQUIRE(dbi != NULL);	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 process_rs_cleanup;	}	/* get things ready for processing */	result = ISC_R_FAILURE;	while (sqlOK(SQLFetch(stmnt))) {		/* set to null for next pass through */		data = type = ttl_s = NULL;		switch(fields) {		case 1:			/*			 * one column in rs, it's the data field.  use			 * default type of A record, and default TTL			 * of 86400.  attempt to get data, & tell bind			 * about it.			 */			if ((result = odbc_getField(stmnt, 1,						    &data)) == ISC_R_SUCCESS) {				result = dns_sdlz_putrr(lookup, "a",							86400, data);			}			break;		case 2:			/*			 * two columns, data field, and data type.			 * use default TTL of 86400.  attempt to get			 * DNS type & data, then tell bind about it.			 */			if ((result = odbc_getField(stmnt, 1,						    &type)) == ISC_R_SUCCESS &&			    (result = odbc_getField(stmnt, 2,						    &data)) == ISC_R_SUCCESS) {				result = dns_sdlz_putrr(lookup, type,							86400, data);			}			break;		default:			/*			 * 3 fields or more, concatenate the last ones			 * together.  attempt to get DNS ttl, type,			 * 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_getManyFields(stmnt, 3,							 fields, &data))				== ISC_R_SUCCESS) {				/* try to 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 everything					 */					result = dns_sdlz_putrr(lookup, type,								ttl, data);				}			} /* closes bid if () */		} /* closes switch(fields) */		/* 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 (data != NULL)			isc_mem_free(ns_g_mctx, data);		/* I sure hope we were successful */		if (result != ISC_R_SUCCESS) {			isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,				      DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,				      "dns_sdlz_putrr returned error. "				      "Error code was: %s",				      isc_result_totext(result));			result = ISC_R_FAILURE;			goto process_rs_cleanup;		}	} /* closes while loop */ process_rs_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;}/* * SDLZ interface methods *//*% determine if the zone is supported by (in) the database */static isc_result_todbc_findzone(void *driverarg, void *dbdata, const char *name){	isc_result_t result;	dbinstance_t *dbi = NULL;	UNUSED(driverarg);	/* run the query and get the result set from the database. */	/* if result != ISC_R_SUCCESS cursor and mutex already cleaned up. */	/* so we don't have to do it here. */	result = odbc_get_resultset(name, NULL, NULL, FINDZONE, dbdata, &dbi);	/* Check that we got a result set with data */	if (result == ISC_R_SUCCESS &&	    !sqlOK(SQLFetch(((odbc_db_t *) (dbi->dbconn))->stmnt))) {		result = ISC_R_NOTFOUND;	}	if (dbi != NULL) {		/* get rid of result set, we are done with it. */		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;}/*% Determine if the client is allowed to perform a zone transfer */static isc_result_todbc_allowzonexfr(void *driverarg, void *dbdata, const char *name,		  const char *client){	isc_result_t result;	dbinstance_t *dbi = NULL;	UNUSED(driverarg);	/* first check if the zone is supported by the database. */	result = odbc_findzone(driverarg, dbdata, name);	if (result != ISC_R_SUCCESS)		return (ISC_R_NOTFOUND);	/*	 * if we get to this point we know the zone is supported by	 * the database.  the only questions now are is the zone	 * transfer is allowed for this client and did the config file	 * have an allow zone xfr query	 *	 * Run our query, and get a result set from the database.  if	 * result != ISC_R_SUCCESS cursor and mutex already cleaned	 * up, so we don't have to do it here.	 */	result = odbc_get_resultset(name, NULL, client, ALLOWXFR,				    dbdata, &dbi);	/* if we get "not implemented", send it along. */	if (result == ISC_R_NOTIMPLEMENTED)		return result;	/* Check that we got a result set with data */	if (result == ISC_R_SUCCESS &&	    !sqlOK(SQLFetch(((odbc_db_t *) (dbi->dbconn))->stmnt))) {		result = ISC_R_NOPERM;	}	if (dbi != NULL) {		/* get rid of result set, we are done with it. */		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

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?