/*% constructs a query list by parsing a string into query segments */ isc_result_t build_querylist(const char *query_str, char **zone, char **record, char **client, query_list_t **querylist, unsigned int flags, log_t log) { isc_result_t result; isc_boolean_t foundzone = ISC_FALSE; isc_boolean_t foundrecord = ISC_FALSE; isc_boolean_t foundclient = ISC_FALSE; char *temp_str = NULL; char *right_str = NULL; query_list_t *tql; query_segment_t *tseg = NULL; /* if query string is null, or zero length */ if (query_str == NULL || strlen(query_str) < 1) { if ((flags & REQUIRE_QUERY) == 0) /* we don't need it were ok. */ return (ISC_R_SUCCESS); else /* we did need it, PROBLEM!!! */ return (ISC_R_FAILURE); } /* allocate memory for query list */ tql = calloc(1, sizeof(query_list_t)); /* couldn't allocate memory. Problem!! */ if (tql == NULL) return (ISC_R_NOMEMORY); /* initialize the query segment list */ DLZ_LIST_INIT(*tql); /* make a copy of query_str so we can chop it up */ temp_str = right_str = strdup(query_str); /* couldn't make a copy, problem!! */ if (right_str == NULL) { result = ISC_R_NOMEMORY; goto cleanup; } /* loop through the string and chop it up */ while (right_str != NULL) { /* allocate memory for tseg */ tseg = calloc(1, sizeof(query_segment_t)); if (tseg == NULL) { /* no memory, clean everything up. */ result = ISC_R_NOMEMORY; goto cleanup; } tseg->cmd = NULL; tseg->direct = ISC_FALSE; /* initialize the query segment link */ DLZ_LINK_INIT(tseg, link); /* append the query segment to the list */ DLZ_LIST_APPEND(*tql, tseg, link); /* * split string at the first "$". set query segment to * left portion */ tseg->cmd = strdup(strsep(&right_str, "$")); if (tseg->cmd == NULL) { /* no memory, clean everything up. */ result = ISC_R_NOMEMORY; goto cleanup; } /* tseg->cmd points directly to a string. */ tseg->direct = ISC_TRUE; tseg->strlen = strlen(tseg->cmd); /* check if we encountered "$zone$" token */ if (strcasecmp(tseg->cmd, "zone") == 0) { /* * we don't really need, or want the "zone" * text, so get rid of it. */ free(tseg->cmd); /* set tseg->cmd to in-direct zone string */ tseg->cmd = (char**) zone; tseg->strlen = 0; /* tseg->cmd points in-directly to a string */ tseg->direct = ISC_FALSE; foundzone = ISC_TRUE; /* check if we encountered "$record$" token */ } else if (strcasecmp(tseg->cmd, "record") == 0) { /* * we don't really need, or want the "record" * text, so get rid of it. */ free(tseg->cmd); /* set tseg->cmd to in-direct record string */ tseg->cmd = (char**) record; tseg->strlen = 0; /* tseg->cmd points in-directly poinsts to a string */ tseg->direct = ISC_FALSE; foundrecord = ISC_TRUE; /* check if we encountered "$client$" token */ } else if (strcasecmp(tseg->cmd, "client") == 0) { /* * we don't really need, or want the "client" * text, so get rid of it. */ free(tseg->cmd); /* set tseg->cmd to in-direct record string */ tseg->cmd = (char**) client; tseg->strlen = 0; /* tseg->cmd points in-directly poinsts to a string */ tseg->direct = ISC_FALSE; foundclient = ISC_TRUE; } } /* we don't need temp_str any more */ free(temp_str); /* * add checks later to verify zone and record are found if * necessary. */ /* if this query requires %client%, make sure we found it */ if (((flags & REQUIRE_CLIENT) != 0) && (!foundclient) ) { /* Write error message to log */ if (log != NULL) log(ISC_LOG_ERROR, "Required token $client$ not found."); result = ISC_R_FAILURE; goto flag_fail; } /* if this query requires %record%, make sure we found it */ if (((flags & REQUIRE_RECORD) != 0) && (!foundrecord) ) { /* Write error message to log */ if (log != NULL) log(ISC_LOG_ERROR, "Required token $record$ not found."); result = ISC_R_FAILURE; goto flag_fail; } /* if this query requires %zone%, make sure we found it */ if (((flags & REQUIRE_ZONE) != 0) && (!foundzone) ) { /* Write error message to log */ if (log != NULL) log(ISC_LOG_ERROR, "Required token $zone$ not found."); result = ISC_R_FAILURE; goto flag_fail; } /* pass back the query list */ *querylist = (query_list_t *) tql; /* return success */ return (ISC_R_SUCCESS); cleanup: /* get rid of temp_str */ if (temp_str != NULL) free(temp_str); flag_fail: /* get rid of what was build of the query list */ if (tql != NULL) destroy_querylist(&tql); return (result); }
/*% * Create an instance of the module. */ isc_result_t dlz_create(const char *dlzname, unsigned int argc, char *argv[], void **dbdata, ...) { isc_result_t result = ISC_R_FAILURE; mysql_instance_t *mysql = NULL; dbinstance_t *dbi = NULL; MYSQL *dbc; char *tmp = NULL; char *endp; int j; const char *helper_name; #if MYSQL_VERSION_ID >= 50000 my_bool auto_reconnect = 1; #endif #if PTHREADS int dbcount; int i; #endif /* PTHREADS */ va_list ap; UNUSED(dlzname); /* allocate memory for MySQL instance */ mysql = calloc(1, sizeof(mysql_instance_t)); if (mysql == NULL) return (ISC_R_NOMEMORY); memset(mysql, 0, sizeof(mysql_instance_t)); /* Fill in the helper functions */ va_start(ap, dbdata); while ((helper_name = va_arg(ap, const char*)) != NULL) b9_add_helper(mysql, helper_name, va_arg(ap, void*)); va_end(ap); #if PTHREADS /* if debugging, let user know we are multithreaded. */ mysql->log(ISC_LOG_DEBUG(1), "MySQL module running multithreaded"); #else /* PTHREADS */ /* if debugging, let user know we are single threaded. */ mysql->log(ISC_LOG_DEBUG(1), "MySQL module running single threaded"); #endif /* PTHREADS */ /* verify we have at least 4 arg's passed to the module */ if (argc < 4) { mysql->log(ISC_LOG_ERROR, "MySQL module requires " "at least 4 command line args."); return (ISC_R_FAILURE); } /* no more than 8 arg's should be passed to the module */ if (argc > 8) { mysql->log(ISC_LOG_ERROR, "MySQL module cannot accept " "more than 7 command line args."); return (ISC_R_FAILURE); } /* get db name - required */ mysql->dbname = get_parameter_value(argv[1], "dbname="); if (mysql->dbname == NULL) { mysql->log(ISC_LOG_ERROR, "MySQL module requires a dbname parameter."); result = ISC_R_FAILURE; goto cleanup; } /* get db port. Not required, but must be > 0 if specified */ tmp = get_parameter_value(argv[1], "port="); if (tmp == NULL) mysql->port = 0; else { mysql->port = strtol(tmp, &endp, 10); if (*endp != '\0' || mysql->port < 0) { mysql->log(ISC_LOG_ERROR, "Mysql module: port " "must be a positive number."); free(tmp); result = ISC_R_FAILURE; goto cleanup; } free(tmp); } mysql->host = get_parameter_value(argv[1], "host="); mysql->user = get_parameter_value(argv[1], "user="******"pass="******"socket="); mysql->flags = CLIENT_REMEMBER_OPTIONS; tmp = get_parameter_value(argv[1], "compress="); if (tmp != NULL) { if (strcasecmp(tmp, "true") == 0) mysql->flags |= CLIENT_COMPRESS; free(tmp); } tmp = get_parameter_value(argv[1], "ssl="); if (tmp != NULL) { if (strcasecmp(tmp, "true") == 0) mysql->flags |= CLIENT_SSL; free(tmp); } tmp = get_parameter_value(argv[1], "space="); if (tmp != NULL) { if (strcasecmp(tmp, "ignore") == 0) mysql->flags |= CLIENT_IGNORE_SPACE; free(tmp); } #if PTHREADS /* multithreaded build can have multiple DB connections */ tmp = get_parameter_value(argv[1], "threads="); if (tmp == NULL) dbcount = 1; else { dbcount = strtol(tmp, &endp, 10); if (*endp != '\0' || dbcount < 1) { mysql->log(ISC_LOG_ERROR, "MySQL database connection count " "must be positive."); free(tmp); result = ISC_R_FAILURE; goto cleanup; } free(tmp); } /* allocate memory for database connection list */ mysql->db = calloc(1, sizeof(db_list_t)); if (mysql->db == NULL) { result = ISC_R_NOMEMORY; goto cleanup; } /* initialize DB connection list */ DLZ_LIST_INIT(*(mysql->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 /* PTHREADS */ switch(argc) { case 4: result = build_dbinstance(NULL, NULL, NULL, argv[2], argv[3], NULL, &dbi, mysql->log); break; case 5: result = build_dbinstance(NULL, NULL, argv[4], argv[2], argv[3], NULL, &dbi, mysql->log); break; case 6: result = build_dbinstance(argv[5], NULL, argv[4], argv[2], argv[3], NULL, &dbi, mysql->log); break; case 7: result = build_dbinstance(argv[5], argv[6], argv[4], argv[2], argv[3], NULL, &dbi, mysql->log); break; case 8: result = build_dbinstance(argv[5], argv[6], argv[4], argv[2], argv[3], argv[7], &dbi, mysql->log); break; default: result = ISC_R_FAILURE; } if (result != ISC_R_SUCCESS) { mysql->log(ISC_LOG_ERROR, "MySQL module could not create " "database instance object."); result = ISC_R_FAILURE; goto cleanup; } #if PTHREADS /* when multithreaded, build a list of DBI's */ DLZ_LINK_INIT(dbi, link); DLZ_LIST_APPEND(*(mysql->db), dbi, link); #else /* * when single threaded, hold onto the one connection * instance. */ mysql->db = dbi; #endif /* create and set db connection */ dbi->dbconn = mysql_init(NULL); if (dbi->dbconn == NULL) { mysql->log(ISC_LOG_ERROR, "MySQL module could not allocate " "memory for database connection"); result = ISC_R_FAILURE; goto cleanup; } dbc = NULL; #if MYSQL_VERSION_ID >= 50000 /* enable automatic reconnection. */ if (mysql_options((MYSQL *) dbi->dbconn, MYSQL_OPT_RECONNECT, &auto_reconnect) != 0) { mysql->log(ISC_LOG_WARNING, "MySQL module failed to set " "MYSQL_OPT_RECONNECT option, continuing"); } #endif for (j = 0; dbc == NULL && j < 4; j++) { dbc = mysql_real_connect((MYSQL *) dbi->dbconn, mysql->host, mysql->user, mysql->pass, mysql->dbname, mysql->port, mysql->socket, mysql->flags); if (dbc == NULL) mysql->log(ISC_LOG_ERROR, "MySQL connection failed: %s", mysql_error((MYSQL *) dbi->dbconn)); } if (dbc == NULL) { mysql->log(ISC_LOG_ERROR, "MySQL module failed to create " "database connection after 4 attempts"); result = ISC_R_FAILURE; goto cleanup; } #if PTHREADS /* set DBI = null for next loop through. */ dbi = NULL; } #endif /* PTHREADS */ *dbdata = mysql; return (ISC_R_SUCCESS); cleanup: dlz_destroy(mysql); return (result); }
isc_result_t dlz_create(const char *dlzname, unsigned int argc, char *argv[], void **dbdata, ...) { isc_result_t result = ISC_R_FAILURE; ldap_instance_t *ldap = NULL; dbinstance_t *dbi = NULL; const char *helper_name; int protocol; int method; #if PTHREADS int dbcount; char *endp; int i; #endif /* PTHREADS */ va_list ap; UNUSED(dlzname); /* allocate memory for LDAP instance */ ldap = calloc(1, sizeof(ldap_instance_t)); if (ldap == NULL) return (ISC_R_NOMEMORY); memset(ldap, 0, sizeof(ldap_instance_t)); /* Fill in the helper functions */ va_start(ap, dbdata); while ((helper_name = va_arg(ap, const char*)) != NULL) b9_add_helper(ldap, helper_name, va_arg(ap, void*)); va_end(ap); #if PTHREADS /* if debugging, let user know we are multithreaded. */ ldap->log(ISC_LOG_DEBUG(1), "LDAP driver running multithreaded"); #else /* PTHREADS */ /* if debugging, let user know we are single threaded. */ ldap->log(ISC_LOG_DEBUG(1), "LDAP driver running single threaded"); #endif /* PTHREADS */ if (argc < 9) { ldap->log(ISC_LOG_ERROR, "LDAP driver requires at least " "8 command line args."); goto cleanup; } /* no more than 13 arg's should be passed to the driver */ if (argc > 12) { ldap->log(ISC_LOG_ERROR, "LDAP driver cannot accept more than " "11 command line args."); goto cleanup; } /* determine protocol version. */ if (strncasecmp(argv[2], V2, strlen(V2)) == 0) protocol = 2; else if (strncasecmp(argv[2], V3, strlen(V3)) == 0) protocol = 3; else { ldap->log(ISC_LOG_ERROR, "LDAP driver protocol must be either %s or %s", V2, V3); goto cleanup; } /* determine connection method. */ if (strncasecmp(argv[3], SIMPLE, strlen(SIMPLE)) == 0) method = LDAP_AUTH_SIMPLE; else if (strncasecmp(argv[3], KRB41, strlen(KRB41)) == 0) method = LDAP_AUTH_KRBV41; else if (strncasecmp(argv[3], KRB42, strlen(KRB42)) == 0) method = LDAP_AUTH_KRBV42; else { ldap->log(ISC_LOG_ERROR, "LDAP driver authentication method must be " "one of %s, %s or %s", SIMPLE, KRB41, KRB42); goto cleanup; } /* multithreaded build can have multiple DB connections */ #if PTHREADS /* check how many db connections we should create */ dbcount = strtol(argv[1], &endp, 10); if (*endp != '\0' || dbcount < 0) { ldap->log(ISC_LOG_ERROR, "LDAP driver database connection count " "must be positive."); goto cleanup; } #endif /* check that LDAP URL parameters make sense */ switch (argc) { case 12: result = ldap_checkURL(ldap, argv[11], 0, "allow zone transfer"); if (result != ISC_R_SUCCESS) goto cleanup; case 11: result = ldap_checkURL(ldap, argv[10], 3, "all nodes"); if (result != ISC_R_SUCCESS) goto cleanup; case 10: if (strlen(argv[9]) > 0) { result = ldap_checkURL(ldap, argv[9], 3, "authority"); if (result != ISC_R_SUCCESS) goto cleanup; } case 9: result = ldap_checkURL(ldap, argv[8], 3, "lookup"); if (result != ISC_R_SUCCESS) goto cleanup; result = ldap_checkURL(ldap, argv[7], 0, "find zone"); if (result != ISC_R_SUCCESS) goto cleanup; break; default: /* not really needed, should shut up compiler. */ result = ISC_R_FAILURE; } /* store info needed to automatically re-connect. */ ldap->protocol = protocol; ldap->method = method; ldap->hosts = strdup(argv[6]); if (ldap->hosts == NULL) { result = ISC_R_NOMEMORY; goto cleanup; } ldap->user = strdup(argv[4]); if (ldap->user == NULL) { result = ISC_R_NOMEMORY; goto cleanup; } ldap->cred = strdup(argv[5]); if (ldap->cred == NULL) { result = ISC_R_NOMEMORY; goto cleanup; } #if PTHREADS /* allocate memory for database connection list */ ldap->db = calloc(1, sizeof(db_list_t)); if (ldap->db == NULL) { result = ISC_R_NOMEMORY; goto cleanup; } /* initialize DB connection list */ DLZ_LIST_INIT(*(ldap->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 /* PTHREADS */ /* how many queries were passed in from config file? */ switch (argc) { case 9: result = build_dbinstance(NULL, NULL, NULL, argv[7], argv[8], NULL, &dbi, ldap->log); break; case 10: result = build_dbinstance(NULL, NULL, argv[9], argv[7], argv[8], NULL, &dbi, ldap->log); break; case 11: result = build_dbinstance(argv[10], NULL, argv[9], argv[7], argv[8], NULL, &dbi, ldap->log); break; case 12: result = build_dbinstance(argv[10], argv[11], argv[9], argv[7], argv[8], NULL, &dbi, ldap->log); break; default: /* not really needed, should shut up compiler. */ result = ISC_R_FAILURE; } if (result == ISC_R_SUCCESS) { ldap->log(ISC_LOG_DEBUG(2), "LDAP driver created " "database instance object."); } else { /* unsuccessful?, log err msg and cleanup. */ ldap->log(ISC_LOG_ERROR, "LDAP driver could not create " "database instance object."); goto cleanup; } #if PTHREADS /* when multithreaded, build a list of DBI's */ DLZ_LINK_INIT(dbi, link); DLZ_LIST_APPEND(*(ldap->db), dbi, link); #else /* * when single threaded, hold onto the one connection * instance. */ ldap->db = dbi; #endif /* attempt to connect */ result = ldap_connect(ldap, dbi); /* * if db connection cannot be created, log err msg and * cleanup. */ switch (result) { /* success, do nothing */ case ISC_R_SUCCESS: break; /* * no memory means ldap_init could not * allocate memory */ case ISC_R_NOMEMORY: #if PTHREADS ldap->log(ISC_LOG_ERROR, "LDAP driver could not allocate memory " "for connection number %u", i + 1); #else ldap->log(ISC_LOG_ERROR, "LDAP driver could not allocate memory " "for connection"); #endif goto cleanup; /* * no perm means ldap_set_option could not set * protocol version */ case ISC_R_NOPERM: ldap->log(ISC_LOG_ERROR, "LDAP driver could not " "set protocol version."); result = ISC_R_FAILURE; goto cleanup; /* failure means couldn't connect to ldap server */ case ISC_R_FAILURE: #if PTHREADS ldap->log(ISC_LOG_ERROR, "LDAP driver could not bind " "connection number %u to server.", i + 1); #else ldap->log(ISC_LOG_ERROR, "LDAP driver could not " "bind connection to server."); #endif goto cleanup; /* * default should never happen. If it does, * major errors. */ default: ldap->log(ISC_LOG_ERROR, "dlz_create() failed (%d)", result); result = ISC_R_UNEXPECTED; goto cleanup; } #if PTHREADS /* set DBI = null for next loop through. */ dbi = NULL; } #endif /* PTHREADS */ /* set dbdata to the ldap_instance we created. */ *dbdata = ldap; return (ISC_R_SUCCESS); cleanup: dlz_destroy(ldap); return (result); }