/*% * This function is the real core of the module. Zone, record * and client strings are passed in (or NULL is passed if the * string is not available). The type of query we want to run * is indicated by the query flag, and the dbdata object is passed * passed in to. dbdata really holds a single database instance. * The function will construct and run the query, hopefully getting * a result set. */ static isc_result_t mysql_get_resultset(const char *zone, const char *record, const char *client, unsigned int query, void *dbdata, MYSQL_RES **rs) { isc_result_t result; dbinstance_t *dbi = NULL; mysql_instance_t *db = (mysql_instance_t *)dbdata; char *querystring = NULL; unsigned int i = 0; unsigned int j = 0; int qres = 0; #if PTHREADS /* find an available DBI from the list */ dbi = mysql_find_avail_conn(db); #else /* PTHREADS */ /* * only 1 DBI - no need to lock instance lock either * only 1 thread in the whole process, no possible contention. */ dbi = (dbinstance_t *)(db->db); #endif /* PTHREADS */ if (dbi == NULL) { result = ISC_R_FAILURE; goto cleanup; } /* what type of query are we going to run? */ switch(query) { case ALLNODES: if (dbi->allnodes_q == NULL) { result = ISC_R_NOTIMPLEMENTED; goto cleanup; } break; case ALLOWXFR: if (dbi->allowxfr_q == NULL) { result = ISC_R_NOTIMPLEMENTED; goto cleanup; } break; case AUTHORITY: if (dbi->authority_q == NULL) { result = ISC_R_NOTIMPLEMENTED; goto cleanup; } break; case FINDZONE: if (dbi->findzone_q == NULL) { db->log(ISC_LOG_DEBUG(2), "No query specified for findzone. " "Findzone requires a query"); result = ISC_R_FAILURE; goto cleanup; } break; case COUNTZONE: if (dbi->countzone_q == NULL) { result = ISC_R_NOTIMPLEMENTED; goto cleanup; } break; case LOOKUP: if (dbi->lookup_q == NULL) { db->log(ISC_LOG_DEBUG(2), "No query specified for lookup. " "Lookup requires a query"); result = ISC_R_FAILURE; goto cleanup; } break; default: db->log(ISC_LOG_ERROR, "Incorrect query flag passed to " "mysql_get_resultset"); result = ISC_R_UNEXPECTED; goto cleanup; } if (zone != NULL) { if (dbi->zone != NULL) free(dbi->zone); dbi->zone = mysqldrv_escape_string((MYSQL *) dbi->dbconn, zone); if (dbi->zone == NULL) { result = ISC_R_NOMEMORY; goto cleanup; } } else dbi->zone = NULL; if (record != NULL) { if (dbi->record != NULL) free(dbi->record); dbi->record = mysqldrv_escape_string((MYSQL *) dbi->dbconn, record); if (dbi->record == NULL) { result = ISC_R_NOMEMORY; goto cleanup; } } else dbi->record = NULL; if (client != NULL) { if (dbi->client != NULL) free(dbi->client); dbi->client = mysqldrv_escape_string((MYSQL *) dbi->dbconn, client); if (dbi->client == NULL) { result = ISC_R_NOMEMORY; goto cleanup; } } else 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(dbi->allnodes_q); break; case ALLOWXFR: querystring = build_querystring(dbi->allowxfr_q); break; case AUTHORITY: querystring = build_querystring(dbi->authority_q); break; case FINDZONE: querystring = build_querystring(dbi->findzone_q); break; case COUNTZONE: querystring = build_querystring(dbi->countzone_q); break; case LOOKUP: querystring = build_querystring(dbi->lookup_q); break; default: db->log(ISC_LOG_ERROR, "Incorrect query flag passed to " "mysql_get_resultset"); result = ISC_R_UNEXPECTED; goto cleanup; } if (querystring == NULL) { result = ISC_R_NOMEMORY; goto cleanup; } /* output the full query string when debugging */ db->log(ISC_LOG_DEBUG(1), "\nQuery String: %s\n", querystring); /* attempt query up to 3 times. */ for (i = 0; i < 3; i++) { qres = mysql_query((MYSQL *) dbi->dbconn, querystring); if (qres == 0) break; for (j = 0; j < 4; j++) if (mysql_ping((MYSQL *) dbi->dbconn) == 0) break; } if (qres == 0) { result = ISC_R_SUCCESS; if (query != COUNTZONE) { *rs = mysql_store_result((MYSQL *) dbi->dbconn); if (*rs == NULL) result = ISC_R_FAILURE; } } else result = ISC_R_FAILURE; cleanup: if (dbi == NULL) return (ISC_R_FAILURE); if (dbi->zone != NULL) { free(dbi->zone); dbi->zone = NULL; } if (dbi->record != NULL) { free(dbi->record); dbi->record = NULL; } if (dbi->client != NULL) { free(dbi->client); dbi->client = NULL; } /* release the lock so another thread can use this dbi */ (void) dlz_mutex_unlock(&dbi->lock); if (querystring != NULL) free(querystring); return (result); }
/*% * This function is the real core of the driver. Zone, record * and client strings are passed in (or NULL is passed if the * string is not available). The type of query we want to run * is indicated by the query flag, and the dbdata object is passed * passed in to. dbdata really holds either: * 1) a list of database instances (in multithreaded mode) OR * 2) a single database instance (in single threaded mode) * The function will construct the query and obtain an available * database instance (DBI). It will then run the query and hopefully * obtain a result set. */ static isc_result_t ldap_get_results(const char *zone, const char *record, const char *client, unsigned int query, void *dbdata, void *ptr) { isc_result_t result; ldap_instance_t *db = (ldap_instance_t *)dbdata; dbinstance_t *dbi = NULL; char *querystring = NULL; LDAPURLDesc *ldap_url = NULL; int ldap_result = 0; LDAPMessage *ldap_msg = NULL; int i; int entries; /* get db instance / connection */ #if PTHREADS /* find an available DBI from the list */ dbi = ldap_find_avail_conn(db); #else /* PTHREADS */ /* * only 1 DBI - no need to lock instance lock either * only 1 thread in the whole process, no possible contention. */ dbi = (dbinstance_t *)(db->db); #endif /* PTHREADS */ /* if DBI is null, can't do anything else */ if (dbi == NULL) return (ISC_R_FAILURE); /* set fields */ if (zone != NULL) { dbi->zone = strdup(zone); if (dbi->zone == NULL) { result = ISC_R_NOMEMORY; goto cleanup; } } else dbi->zone = NULL; if (record != NULL) { dbi->record = strdup(record); if (dbi->record == NULL) { result = ISC_R_NOMEMORY; goto cleanup; } } else dbi->record = NULL; if (client != NULL) { dbi->client = strdup(client); if (dbi->client == NULL) { result = ISC_R_NOMEMORY; goto cleanup; } } else dbi->client = NULL; /* what type of query are we going to run? */ switch (query) { case ALLNODES: /* * if the query was not passed in from the config file * then we can't run it. return not_implemented, so * it's like the code for that operation was never * built into the driver.... AHHH flexibility!!! */ if (dbi->allnodes_q == NULL) { result = ISC_R_NOTIMPLEMENTED; goto cleanup; } else querystring = build_querystring(dbi->allnodes_q); break; case ALLOWXFR: /* same as comments as ALLNODES */ if (dbi->allowxfr_q == NULL) { result = ISC_R_NOTIMPLEMENTED; goto cleanup; } else querystring = build_querystring(dbi->allowxfr_q); break; case AUTHORITY: /* same as comments as ALLNODES */ if (dbi->authority_q == NULL) { result = ISC_R_NOTIMPLEMENTED; goto cleanup; } else querystring = build_querystring(dbi->authority_q); break; case FINDZONE: /* this is required. It's the whole point of DLZ! */ if (dbi->findzone_q == NULL) { db->log(ISC_LOG_DEBUG(2), "No query specified for findzone. " "Findzone requires a query"); result = ISC_R_FAILURE; goto cleanup; } else querystring = build_querystring(dbi->findzone_q); break; case LOOKUP: /* this is required. It's also a major point of DLZ! */ if (dbi->lookup_q == NULL) { db->log(ISC_LOG_DEBUG(2), "No query specified for lookup. " "Lookup requires a query"); result = ISC_R_FAILURE; goto cleanup; } else querystring = build_querystring(dbi->lookup_q); break; default: /* * this should never happen. If it does, the code is * screwed up! */ db->log(ISC_LOG_ERROR, "Incorrect query flag passed to ldap_get_results"); 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. */ db->log(ISC_LOG_DEBUG(1), "Query String: %s", querystring); /* break URL down into it's component parts, if error cleanup */ ldap_result = ldap_url_parse(querystring, &ldap_url); if (ldap_result != LDAP_SUCCESS || ldap_url == NULL) { result = ISC_R_FAILURE; goto cleanup; } for (i = 0; i < 3; i++) { /* * dbi->dbconn may be null if trying to reconnect on a * previous query failed. */ if (dbi->dbconn == NULL) { db->log(ISC_LOG_INFO, "LDAP driver attempting to re-connect"); result = ldap_connect((ldap_instance_t *) dbdata, dbi); if (result != ISC_R_SUCCESS) { result = ISC_R_FAILURE; continue; } } /* perform ldap search syncronously */ ldap_result = ldap_search_s((LDAP *) dbi->dbconn, ldap_url->lud_dn, ldap_url->lud_scope, ldap_url->lud_filter, ldap_url->lud_attrs, 0, &ldap_msg); /* * check return code. No such object is ok, just * didn't find what we wanted */ switch (ldap_result) { case LDAP_NO_SUCH_OBJECT: db->log(ISC_LOG_DEBUG(1), "No object found matching query requirements"); result = ISC_R_NOTFOUND; goto cleanup; break; case LDAP_SUCCESS: /* on success do nothing */ result = ISC_R_SUCCESS; i = 3; break; case LDAP_SERVER_DOWN: db->log(ISC_LOG_INFO, "LDAP driver attempting to re-connect"); result = ldap_connect((ldap_instance_t *) dbdata, dbi); if (result != ISC_R_SUCCESS) result = ISC_R_FAILURE; break; default: /* * other errors not ok. Log error message and * get out */ db->log(ISC_LOG_ERROR, "LDAP error: %s", ldap_err2string(ldap_result)); result = ISC_R_FAILURE; goto cleanup; break; } } if (result != ISC_R_SUCCESS) goto cleanup; switch (query) { case ALLNODES: result = ldap_process_results(db, (LDAP *) dbi->dbconn, ldap_msg, ldap_url->lud_attrs, ptr, ISC_TRUE); break; case AUTHORITY: case LOOKUP: result = ldap_process_results(db, (LDAP *) dbi->dbconn, ldap_msg, ldap_url->lud_attrs, ptr, ISC_FALSE); break; case ALLOWXFR: entries = ldap_count_entries((LDAP *) dbi->dbconn, ldap_msg); if (entries == 0) result = ISC_R_NOPERM; else if (entries > 0) result = ISC_R_SUCCESS; else result = ISC_R_FAILURE; break; case FINDZONE: entries = ldap_count_entries((LDAP *) dbi->dbconn, ldap_msg); if (entries == 0) result = ISC_R_NOTFOUND; else if (entries > 0) result = ISC_R_SUCCESS; else result = ISC_R_FAILURE; break; default: /* * this should never happen. If it does, the code is * screwed up! */ db->log(ISC_LOG_ERROR, "Incorrect query flag passed to ldap_get_results"); result = ISC_R_UNEXPECTED; } cleanup: /* it's always good to cleanup after yourself */ /* if we retrieved results, free them */ if (ldap_msg != NULL) ldap_msgfree(ldap_msg); if (ldap_url != NULL) ldap_free_urldesc(ldap_url); /* cleanup */ if (dbi->zone != NULL) free(dbi->zone); if (dbi->record != NULL) free(dbi->record); if (dbi->client != NULL) free(dbi->client); dbi->zone = dbi->record = dbi->client = NULL; /* release the lock so another thread can use this dbi */ (void) dlz_mutex_unlock(&dbi->lock); /* release query string */ if (querystring != NULL) free(querystring); /* return result */ return (result); }