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