/** * Update serial. * */ ods_status zone_update_serial(zone_type* zone) { ods_status status = ODS_STATUS_OK; rrset_type* rrset = NULL; rr_type* soa = NULL; ldns_rr* rr = NULL; ldns_rdf* soa_rdata = NULL; ods_log_assert(zone); ods_log_assert(zone->apex); ods_log_assert(zone->name); ods_log_assert(zone->db); ods_log_assert(zone->signconf); if (zone->db->serial_updated) { /* already done, unmark and return ok */ ods_log_debug("[%s] zone %s soa serial already up to date", zone_str, zone->name); zone->db->serial_updated = 0; return ODS_STATUS_OK; } rrset = zone_lookup_rrset(zone, zone->apex, LDNS_RR_TYPE_SOA); ods_log_assert(rrset); ods_log_assert(rrset->rrs); ods_log_assert(rrset->rrs[0].rr); rr = ldns_rr_clone(rrset->rrs[0].rr); if (!rr) { ods_log_error("[%s] unable to update zone %s soa serial: failed to " "clone soa rr", zone_str, zone->name); return ODS_STATUS_ERR; } status = namedb_update_serial(zone->db, zone->signconf->soa_serial, zone->db->inbserial); if (status != ODS_STATUS_OK) { ods_log_error("[%s] unable to update zone %s soa serial: %s", zone_str, zone->name, ods_status2str(status)); ldns_rr_free(rr); return status; } ods_log_verbose("[%s] zone %s set soa serial to %u", zone_str, zone->name, zone->db->intserial); soa_rdata = ldns_rr_set_rdf(rr, ldns_native2rdf_int32(LDNS_RDF_TYPE_INT32, zone->db->intserial), SE_SOA_RDATA_SERIAL); if (soa_rdata) { ldns_rdf_deep_free(soa_rdata); soa_rdata = NULL; } else { ods_log_error("[%s] unable to update zone %s soa serial: failed to " "replace soa serial rdata", zone_str, zone->name); ldns_rr_free(rr); return ODS_STATUS_ERR; } soa = rrset_add_rr(rrset, rr); ods_log_assert(soa); rrset_diff(rrset, 0, 0); zone->db->serial_updated = 0; return ODS_STATUS_OK; }
/** * Merge zones. * */ void zone_merge(zone_type* z1, zone_type* z2) { const char* str; adapter_type* adtmp = NULL; if (!z1 || !z2) { return; } /* policy name */ if (ods_strcmp(z2->policy_name, z1->policy_name) != 0) { if (z2->policy_name) { str = strdup(z2->policy_name); if (!str) { ods_log_error("[%s] failed to merge policy %s name to zone " "%s", zone_str, z2->policy_name, z1->name); } else { free((void*)z1->policy_name); z1->policy_name = str; z1->zl_status = ZONE_ZL_UPDATED; } } else { free((void*)z1->policy_name); z1->policy_name = NULL; z1->zl_status = ZONE_ZL_UPDATED; } } /* signconf filename */ if (ods_strcmp(z2->signconf_filename, z1->signconf_filename) != 0) { if (z2->signconf_filename) { str = strdup(z2->signconf_filename); if (!str) { ods_log_error("[%s] failed to merge signconf filename %s to " "zone %s", zone_str, z2->policy_name, z1->name); } else { free((void*)z1->signconf_filename); z1->signconf_filename = str; z1->zl_status = ZONE_ZL_UPDATED; } } else { free((void*)z1->signconf_filename); z1->signconf_filename = NULL; z1->zl_status = ZONE_ZL_UPDATED; } } /* adapters */ if (adapter_compare(z2->adinbound, z1->adinbound) != 0) { adtmp = z2->adinbound; z2->adinbound = z1->adinbound; z1->adinbound = adtmp; adtmp = NULL; } if (adapter_compare(z2->adoutbound, z1->adoutbound) != 0) { adtmp = z2->adoutbound; z2->adoutbound = z1->adoutbound; z1->adoutbound = adtmp; adtmp = NULL; } return; }
/** * Publish the NSEC3 parameters as indicated by the signer configuration. * */ ods_status zone_publish_nsec3param(zone_type* zone) { rrset_type* rrset = NULL; rr_type* n3prr = NULL; ldns_rr* rr = NULL; ods_status status = ODS_STATUS_OK; if (!zone || !zone->name || !zone->db || !zone->signconf) { return ODS_STATUS_ASSERT_ERR; } if (!zone->signconf->nsec3params) { /* NSEC */ ods_log_assert(zone->signconf->nsec_type == LDNS_RR_TYPE_NSEC); return ODS_STATUS_OK; } if (!zone->signconf->nsec3params->rr) { rr = ldns_rr_new_frm_type(LDNS_RR_TYPE_NSEC3PARAMS); if (!rr) { ods_log_error("[%s] unable to publish nsec3params for zone %s: " "error creating rr (%s)", zone_str, zone->name, ods_status2str(status)); return ODS_STATUS_MALLOC_ERR; } ldns_rr_set_class(rr, zone->klass); ldns_rr_set_ttl(rr, 0); ldns_rr_set_owner(rr, ldns_rdf_clone(zone->apex)); ldns_nsec3_add_param_rdfs(rr, zone->signconf->nsec3params->algorithm, 0, zone->signconf->nsec3params->iterations, zone->signconf->nsec3params->salt_len, zone->signconf->nsec3params->salt_data); /** * Always set bit 7 of the flags to zero, * according to rfc5155 section 11 */ ldns_set_bit(ldns_rdf_data(ldns_rr_rdf(rr, 1)), 7, 0); zone->signconf->nsec3params->rr = rr; } ods_log_assert(zone->signconf->nsec3params->rr); status = zone_add_rr(zone, zone->signconf->nsec3params->rr, 0); if (status == ODS_STATUS_UNCHANGED) { /* rr already exists, adjust pointer */ rrset = zone_lookup_rrset(zone, zone->apex, LDNS_RR_TYPE_NSEC3PARAMS); ods_log_assert(rrset); n3prr = rrset_lookup_rr(rrset, zone->signconf->nsec3params->rr); ods_log_assert(n3prr); if (n3prr->rr != zone->signconf->nsec3params->rr) { ldns_rr_free(zone->signconf->nsec3params->rr); } zone->signconf->nsec3params->rr = n3prr->rr; status = ODS_STATUS_OK; } else if (status != ODS_STATUS_OK) { ods_log_error("[%s] unable to publish nsec3params for zone %s: " "error adding nsec3params (%s)", zone_str, zone->name, ods_status2str(status)); } return status; }
/** * Create new NSEC3 parameters. * */ nsec3params_type* nsec3params_create(void* sc, uint8_t algo, uint8_t flags, uint16_t iter, const char* salt) { nsec3params_type* nsec3params = NULL; signconf_type* signconf = (signconf_type*) sc; uint8_t salt_len; /* calculate salt len */ uint8_t* salt_data; /* calculate salt data */ if (!sc) { return NULL; } nsec3params = (nsec3params_type*) allocator_alloc(signconf->allocator, sizeof(nsec3params_type)); if (!nsec3params) { ods_log_error("[%s] unable to create: allocator_alloc() failed", nsec3_str); return NULL; } nsec3params->sc = sc; nsec3params->algorithm = algo; nsec3params->flags = flags; nsec3params->iterations = iter; /* construct the salt from the string */ if (nsec3params_create_salt(salt, &salt_len, &salt_data) != 0) { ods_log_error("[%s] unable to create: create salt failed", nsec3_str); allocator_deallocate(signconf->allocator, (void*)nsec3params); return NULL; } nsec3params->salt_len = salt_len; nsec3params->salt_data = salt_data; nsec3params->rr = NULL; return nsec3params; }
/** * Create new schedule. * */ schedule_type* schedule_create(allocator_type* allocator) { schedule_type* schedule; if (!allocator) { return NULL; } schedule = (schedule_type*) allocator_alloc(allocator, sizeof(schedule_type)); if (!schedule) { ods_log_error("[%s] unable to create schedule: allocator_alloc() " "failed", schedule_str); return NULL; } schedule->allocator = allocator; schedule->loading = 0; schedule->flushcount = 0; schedule->tasks = ldns_rbtree_create(task_compare); if (!schedule->tasks) { ods_log_error("[%s] unable to create schedule: ldns_rbtree_create() " "failed", schedule_str); allocator_deallocate(allocator, (void*) schedule); return NULL; } lock_basic_init(&schedule->schedule_lock); return schedule; }
/** * Convert salt to string. * */ const char* nsec3params_salt2str(nsec3params_type* nsec3params) { uint8_t *data; uint8_t salt_length = 0; uint8_t salt_pos = 0; int written = 0; char* str = NULL; ldns_buffer* buffer = NULL; salt_length = nsec3params->salt_len; data = nsec3params->salt_data; /* from now there are variable length entries so remember pos */ if (salt_length == 0) { buffer = ldns_buffer_new(2); written = ldns_buffer_printf(buffer, "-"); } else { buffer = ldns_buffer_new(salt_pos+1); for (salt_pos = 0; salt_pos < salt_length; salt_pos++) { written = ldns_buffer_printf(buffer, "%02x", data[salt_pos]); } } if (ldns_buffer_status(buffer) == LDNS_STATUS_OK) { str = ldns_buffer2str(buffer); } else if (written) { ods_log_error("[%s] unable to convert nsec3 salt to string: %s", nsec3_str, ldns_get_errorstr_by_id(ldns_buffer_status(buffer))); } else { ods_log_error("[%s] unable to convert nsec3 salt to string: zero " "bytes written", nsec3_str); } ldns_buffer_free(buffer); return (const char*) str; }
/** * Check configuration. * */ ods_status engine_config_check(engineconfig_type* config) { if (!config) { ods_log_error("[%s] check failed: config does not exist", conf_str); return ODS_STATUS_CFG_ERR; } if (!config->policy_filename) { ods_log_error("[%s] check failed: no policy filename", conf_str); return ODS_STATUS_CFG_ERR; } if (!config->zonelist_filename) { ods_log_error("[%s] check failed: no zonelist filename", conf_str); return ODS_STATUS_CFG_ERR; } if (!config->clisock_filename) { ods_log_error("[%s] check failed: no socket filename", conf_str); return ODS_STATUS_CFG_ERR; } if (!config->datastore) { ods_log_error("[%s] check failed: no datastore", conf_str); return ODS_STATUS_CFG_ERR; } /* [TODO] room for more checks here */ return ODS_STATUS_OK; }
/** * Make sure that no appointed jobs have failed. * */ static ods_status worker_check_jobs(worker_type* worker, task_type* task) { ods_log_assert(worker); ods_log_assert(task); lock_basic_lock(&worker->worker_lock); if (worker->jobs_failed) { ods_log_error("[%s[%i]] sign zone %s failed: %u RRsets failed", worker2str(worker->type), worker->thread_num, task_who2str(task), worker->jobs_failed); lock_basic_unlock(&worker->worker_lock); return ODS_STATUS_ERR; } else if (worker->jobs_completed != worker->jobs_appointed) { ods_log_error("[%s[%i]] sign zone %s failed: processed %u of %u " "RRsets", worker2str(worker->type), worker->thread_num, task_who2str(task), worker->jobs_completed, worker->jobs_appointed); lock_basic_unlock(&worker->worker_lock); return ODS_STATUS_ERR; } else if (worker->need_to_exit) { ods_log_debug("[%s[%i]] sign zone %s failed: worker needs to exit", worker2str(worker->type), worker->thread_num, task_who2str(task)); lock_basic_unlock(&worker->worker_lock); return ODS_STATUS_ERR; } else { ods_log_debug("[%s[%i]] sign zone %s ok: %u of %u RRsets " "succeeded", worker2str(worker->type), worker->thread_num, task_who2str(task), worker->jobs_completed, worker->jobs_appointed); ods_log_assert(worker->jobs_appointed == worker->jobs_completed); } lock_basic_unlock(&worker->worker_lock); return ODS_STATUS_OK; }
/** * Create a new task. * */ task_type* task_create(task_id what, time_t when, void* zone) { allocator_type* allocator = NULL; task_type* task = NULL; if (!zone) { return NULL; } allocator = allocator_create(malloc, free); if (!allocator) { ods_log_error("[%s] unable to create task: allocator_create() failed", task_str); return NULL; } task = (task_type*) allocator_alloc(allocator, sizeof(task_type)); if (!task) { ods_log_error("[%s] unable to create task: allocator_alloc() failed", task_str); allocator_cleanup(allocator); return NULL; } task->allocator = allocator; task->what = what; task->interrupt = TASK_NONE; task->halted = TASK_NONE; task->when = when; task->halted_when = 0; task->backoff = 0; task->flush = 0; task->zone = zone; return task; }
/** * Set udp socket to non-blocking and bind. * */ static ods_status sock_fcntl_and_bind(sock_type* sock, const char* node, const char* port, const char* stype, const char* fam) { ods_log_assert(sock); ods_log_assert(port); ods_log_assert(stype); ods_log_assert(fam); if (fcntl(sock->s, F_SETFL, O_NONBLOCK) == -1) { ods_log_error("[%s] unable to set %s/%s socket '%s:%s' to " "non-blocking: fcntl() failed (%s)", sock_str, stype, fam, node?node:"localhost", port, strerror(errno)); return ODS_STATUS_SOCK_FCNTL_NONBLOCK; } ods_log_debug("[%s] bind %s/%s socket '%s:%s'", sock_str, stype, fam, node?node:"localhost", port, strerror(errno)); if (bind(sock->s, (struct sockaddr *) sock->addr->ai_addr, sock->addr->ai_addrlen) != 0) { ods_log_error("[%s] unable to bind %s/%s socket '%s:%s': bind() " "failed (%s)", sock_str, stype, fam, node?node:"localhost", port, strerror(errno)); return ODS_STATUS_SOCK_BIND; } return ODS_STATUS_OK; }
/** * Update DNS output adapter. * */ ods_status dnsout_update(dnsout_type** addns, const char* filename, time_t* last_mod) { dnsout_type* new_addns = NULL; time_t st_mtime = 0; ods_status status = ODS_STATUS_OK; if (!filename || !addns || !last_mod) { return ODS_STATUS_UNCHANGED; } /* read the new signer configuration */ new_addns = dnsout_create(); if (!new_addns) { ods_log_error("[%s] unable to update dnsout: dnsout_create() " "failed", adapter_str); return ODS_STATUS_ERR; } status = dnsout_read(new_addns, filename); if (status == ODS_STATUS_OK) { *addns = new_addns; *last_mod = st_mtime; } else { ods_log_error("[%s] unable to update dnsout: dnsout_read(%s) " "failed (%s)", adapter_str, filename, ods_status2str(status)); dnsout_cleanup(new_addns); } return status; }
/** * Read DNS output adapter. * */ static ods_status dnsout_read(dnsout_type* addns, const char* filename) { const char* rngfile = ODS_SE_RNGDIR "/addns.rng"; ods_status status = ODS_STATUS_OK; FILE* fd = NULL; if (!filename || !addns) { return ODS_STATUS_ASSERT_ERR; } ods_log_debug("[%s] read dnsout file %s", adapter_str, filename); status = parse_file_check(filename, rngfile); if (status != ODS_STATUS_OK) { ods_log_error("[%s] unable to read dnsout: parse error in " "file %s (%s)", adapter_str, filename, ods_status2str(status)); return status; } fd = ods_fopen(filename, NULL, "r"); if (fd) { addns->tsig = parse_addns_tsig(addns->allocator, filename); addns->provide_xfr = parse_addns_provide_xfr(addns->allocator, filename, addns->tsig); addns->do_notify = parse_addns_do_notify(addns->allocator, filename, addns->tsig); ods_fclose(fd); return ODS_STATUS_OK; } ods_log_error("[%s] unable to read dnsout: failed to open file %s", adapter_str, filename); return ODS_STATUS_ERR; }
/** * Create a new 'instant' duration. * */ duration_type* duration_create(void) { duration_type* duration; allocator_type* allocator = allocator_create(malloc, free); if (!allocator) { ods_log_error("[%s] cannot create: no allocator available", duration_str); return NULL; } duration = (duration_type*) allocator_alloc(allocator, sizeof(duration_type)); if (!duration) { ods_log_error("[%s] cannot create: allocator failed", duration_str); allocator_cleanup(allocator); return NULL; } duration->allocator = allocator; duration->years = 0; duration->months = 0; duration->weeks = 0; duration->days = 0; duration->hours = 0; duration->minutes = 0; duration->seconds = 0; return duration; }
/** * copycode: This code is based on the EXAMPLE in the strftime manual. * */ uint32_t time_datestamp(time_t tt, const char* format, char** str) { time_t t; struct tm *tmp; uint32_t ut = 0; char outstr[32]; if (tt) { t = tt; } else { t = time_now(); } tmp = localtime(&t); if (tmp == NULL) { ods_log_error("[%s] time_datestamp: localtime() failed", duration_str); return 0; } if (strftime(outstr, sizeof(outstr), format, tmp) == 0) { ods_log_error("[%s] time_datestamp: strftime() failed", duration_str); return 0; } ut = (uint32_t) strtoul(outstr, NULL, 10); if (str) { *str = strdup(outstr); } return ut; }
/** * Self pipe trick (see Unix Network Programming). * */ static int self_pipe_trick(engine_type* engine) { int sockfd, ret; struct sockaddr_un servaddr; const char* servsock_filename = ODS_SE_SOCKFILE; ods_log_assert(engine); ods_log_assert(engine->cmdhandler); sockfd = socket(AF_UNIX, SOCK_STREAM, 0); if (sockfd < 0) { ods_log_error("[%s] unable to connect to command handler: " "socket() failed (%s)", engine_str, strerror(errno)); return 1; } else { bzero(&servaddr, sizeof(servaddr)); servaddr.sun_family = AF_UNIX; strncpy(servaddr.sun_path, servsock_filename, sizeof(servaddr.sun_path) - 1); ret = connect(sockfd, (const struct sockaddr*) &servaddr, sizeof(servaddr)); if (ret != 0) { ods_log_error("[%s] unable to connect to command handler: " "connect() failed (%s)", engine_str, strerror(errno)); close(sockfd); return 1; } else { /* self-pipe trick */ ods_writen(sockfd, "", 1); close(sockfd); } } return 0; }
/** * IXFR. * */ static query_state query_process_ixfr(query_type* q) { uint16_t count = 0; ods_log_assert(q); ods_log_assert(q->buffer); ods_log_assert(buffer_pkt_qdcount(q->buffer) == 1); /* skip header and question section */ buffer_skip(q->buffer, BUFFER_PKT_HEADER_SIZE); if (!buffer_skip_rr(q->buffer, 1)) { ods_log_error("[%s] dropped packet: zone %s received bad ixfr " "request (bad question section)", query_str, q->zone->name); return QUERY_DISCARDED; } /* answer section is empty */ ods_log_assert(buffer_pkt_ancount(q->buffer) == 0); /* examine auth section */ q->startpos = buffer_position(q->buffer); count = buffer_pkt_nscount(q->buffer); if (count) { if (!buffer_skip_dname(q->buffer) || !query_parse_soa(q->buffer, &(q->serial))) { ods_log_error("[%s] dropped packet: zone %s received bad ixfr " "request (bad soa in auth section)", query_str, q->zone->name); return QUERY_DISCARDED; } ods_log_debug("[%s] found ixfr request zone %s serial=%u", query_str, q->zone->name, q->serial); return QUERY_PROCESSED; } ods_log_debug("[%s] ixfr request zone %s has no auth section", query_str, q->zone->name); q->serial = 0; return QUERY_PROCESSED; }
/** * (Create) and change ownership of directories * */ void ods_chown(const char* file, uid_t uid, gid_t gid, int getdir) { char* dir = NULL; if (!file) { ods_log_warning("[%s] no filename given for chown()", file_str); return; } if (!getdir) { ods_log_debug("[%s] create and chown %s with user=%ld group=%ld", file_str, file, (signed long) uid, (signed long) gid); if (chown(file, uid, gid) != 0) { ods_log_error("[%s] chown() %s failed: %s", file_str, file, strerror(errno)); } } else if ((dir = ods_dir_name(file)) != NULL) { ods_log_debug("[%s] create and chown %s with user=%ld group=%ld", file_str, dir, (signed long) uid, (signed long) gid); if (chown(dir, uid, gid) != 0) { ods_log_error("[%s] chown() %s failed: %s", file_str, dir, strerror(errno)); } free((void*) dir); } else { ods_log_warning("[%s] use of relative path: %s", file_str, file); } }
/** * Write zonefile. * */ ods_status adfile_write(void* zone, const char* filename) { FILE* fd = NULL; char* tmpname = NULL; zone_type* adzone = (zone_type*) zone; ods_status status = ODS_STATUS_OK; /* [start] sanity parameter checking */ if (!adzone || !adzone->adoutbound) { ods_log_error("[%s] unable to write file: no output adapter", adapter_str); return ODS_STATUS_ASSERT_ERR; } if (!filename) { ods_log_error("[%s] unable to write file: no filename given", adapter_str); return ODS_STATUS_ASSERT_ERR; } /* [end] sanity parameter checking */ /* [start] write zone */ tmpname = ods_build_path(filename, ".tmp", 0, 0); if (!tmpname) { return ODS_STATUS_MALLOC_ERR; } fd = ods_fopen(tmpname, NULL, "w"); if (fd) { status = adapi_printzone(fd, adzone); ods_fclose(fd); if (status == ODS_STATUS_OK) { if (adzone->adoutbound->error) { ods_log_error("[%s] unable to write zone %s file %s: one or " "more RR print failed", adapter_str, adzone->name, filename); /* clear error */ adzone->adoutbound->error = 0; status = ODS_STATUS_FWRITE_ERR; } } } else { status = ODS_STATUS_FOPEN_ERR; } if (status == ODS_STATUS_OK) { if (rename((const char*) tmpname, filename) != 0) { ods_log_error("[%s] unable to write file: failed to rename %s " "to %s (%s)", adapter_str, tmpname, filename, strerror(errno)); status = ODS_STATUS_RENAME_ERR; } } free(tmpname); /* [end] write zone */ return status; }
/** * Update zone list. * */ ods_status zonelist_update(zonelist_type* zl, const char* zlfile) { zonelist_type* new_zlist = NULL; allocator_type* tmp_alloc = NULL; time_t st_mtime = 0; ods_status status = ODS_STATUS_OK; char* datestamp = NULL; ods_log_debug("[%s] update zone list", zl_str); if (!zl|| !zl->zones || !zlfile) { return ODS_STATUS_ASSERT_ERR; } /* is the file updated? */ st_mtime = ods_file_lastmodified(zlfile); if (st_mtime <= zl->last_modified) { (void)time_datestamp(zl->last_modified, "%Y-%m-%d %T", &datestamp); ods_log_debug("[%s] zonelist file %s is unchanged since %s", zl_str, zlfile, datestamp?datestamp:"Unknown"); free((void*)datestamp); return ODS_STATUS_UNCHANGED; } /* create new zonelist */ tmp_alloc = allocator_create(malloc, free); if (!tmp_alloc) { return ODS_STATUS_MALLOC_ERR; } new_zlist = zonelist_create(tmp_alloc); if (!new_zlist) { ods_log_error("[%s] unable to update zonelist: zonelist_create() " "failed", zl_str); allocator_cleanup(tmp_alloc); return ODS_STATUS_ERR; } /* read zonelist */ status = zonelist_read(new_zlist, zlfile); if (status == ODS_STATUS_OK) { zl->just_removed = 0; zl->just_added = 0; zl->just_updated = 0; new_zlist->last_modified = st_mtime; zonelist_merge(zl, new_zlist); (void)time_datestamp(zl->last_modified, "%Y-%m-%d %T", &datestamp); ods_log_debug("[%s] file %s is modified since %s", zl_str, zlfile, datestamp?datestamp:"Unknown"); free((void*)datestamp); } else { ods_log_error("[%s] unable to update zonelist: read file %s failed " "(%s)", zl_str, zlfile, ods_status2str(status)); } zonelist_free(new_zlist); allocator_cleanup(tmp_alloc); return status; }
/** * Parse elements from the configuration file. * */ const char* parse_conf_string(const char* cfgfile, const char* expr, int required) { xmlDocPtr doc = NULL; xmlXPathContextPtr xpathCtx = NULL; xmlXPathObjectPtr xpathObj = NULL; xmlChar *xexpr = NULL; const char* string = NULL; ods_log_assert(expr); ods_log_assert(cfgfile); /* Load XML document */ doc = xmlParseFile(cfgfile); if (doc == NULL) { return NULL; } /* Create xpath evaluation context */ xpathCtx = xmlXPathNewContext(doc); if (xpathCtx == NULL) { ods_log_error("[%s] unable to create new XPath context for cfgile " "%s expr %s", parser_str, cfgfile, (char*) expr); xmlFreeDoc(doc); return NULL; } /* Get string */ xexpr = (unsigned char*) expr; xpathObj = xmlXPathEvalExpression(xexpr, xpathCtx); if (xpathObj == NULL || xpathObj->nodesetval == NULL || xpathObj->nodesetval->nodeNr <= 0) { if (required) { ods_log_error("[%s] unable to evaluate required element %s in " "cfgfile %s", parser_str, (char*) xexpr, cfgfile); } xmlXPathFreeContext(xpathCtx); if (xpathObj) { xmlXPathFreeObject(xpathObj); } xmlFreeDoc(doc); return NULL; } if (xpathObj->nodesetval != NULL && xpathObj->nodesetval->nodeNr > 0) { string = (const char*) xmlXPathCastToString(xpathObj); xmlXPathFreeContext(xpathCtx); xmlXPathFreeObject(xpathObj); xmlFreeDoc(doc); return string; } xmlXPathFreeContext(xpathCtx); xmlXPathFreeObject(xpathObj); xmlFreeDoc(doc); return NULL; }
/** * Create engine. * */ static engine_type* engine_create(void) { engine_type* engine; allocator_type* allocator = allocator_create(malloc, free); if (!allocator) { ods_log_error("[%s] unable to create engine: allocator_create() " "failed", engine_str); return NULL; } engine = (engine_type*) allocator_alloc(allocator, sizeof(engine_type)); if (!engine) { ods_log_error("[%s] unable to create engine: allocator_alloc() " "failed", engine_str); allocator_cleanup(allocator); return NULL; } engine->allocator = allocator; engine->config = NULL; engine->workers = NULL; engine->drudgers = NULL; engine->cmdhandler = NULL; engine->cmdhandler_done = 0; engine->dnshandler = NULL; engine->xfrhandler = NULL; engine->pid = -1; engine->uid = -1; engine->gid = -1; engine->daemonize = 0; engine->need_to_exit = 0; engine->need_to_reload = 0; lock_basic_init(&engine->signal_lock); lock_basic_set(&engine->signal_cond); lock_basic_lock(&engine->signal_lock); engine->signal = SIGNAL_INIT; lock_basic_unlock(&engine->signal_lock); engine->zonelist = zonelist_create(engine->allocator); if (!engine->zonelist) { engine_cleanup(engine); return NULL; } engine->taskq = schedule_create(engine->allocator); if (!engine->taskq) { engine_cleanup(engine); return NULL; } engine->signq = fifoq_create(engine->allocator); if (!engine->signq) { engine_cleanup(engine); return NULL; } return engine; }
/** * Push an interface to the listener. * */ interface_type* listener_push(listener_type* listener, char* address, int family, char* port) { interface_type* ifs_old = NULL; ods_log_assert(listener); ods_log_assert(address); ifs_old = listener->interfaces; listener->interfaces = (interface_type*) allocator_alloc( listener->allocator, (listener->count + 1) * sizeof(interface_type)); if (!listener->interfaces) { ods_log_error("[%s] unable to add interface: allocator_alloc() failed", listener_str); exit(1); } if (ifs_old) { memcpy(listener->interfaces, ifs_old, (listener->count) * sizeof(interface_type)); } allocator_deallocate(listener->allocator, (void*) ifs_old); listener->count++; listener->interfaces[listener->count -1].address = allocator_strdup(listener->allocator, address); listener->interfaces[listener->count -1].family = family; if (port) { listener->interfaces[listener->count -1].port = allocator_strdup(listener->allocator, port); } else{ listener->interfaces[listener->count -1].port = NULL; } memset(&listener->interfaces[listener->count -1].addr, 0, sizeof(union acl_addr_storage)); if (listener->interfaces[listener->count -1].family == AF_INET6 && strlen(listener->interfaces[listener->count -1].address) > 0) { if (inet_pton(listener->interfaces[listener->count -1].family, listener->interfaces[listener->count -1].address, &listener->interfaces[listener->count -1].addr.addr6) != 1) { ods_log_error("[%s] bad ip address '%s'", listener->interfaces[listener->count -1].address); return NULL; } } else if (listener->interfaces[listener->count -1].family == AF_INET && strlen(listener->interfaces[listener->count -1].address) > 0) { if (inet_pton(listener->interfaces[listener->count -1].family, listener->interfaces[listener->count -1].address, &listener->interfaces[listener->count -1].addr.addr) != 1) { ods_log_error("[%s] bad ip address '%s'", listener->interfaces[listener->count -1].address); return NULL; } } return &listener->interfaces[listener->count -1]; }
/** * File copy. * */ ods_status ods_file_copy(const char* file1, const char* file2, long startpos, int append) { char buf[BUFFER_SIZE]; int fin = 0; int fout = 0; int read_size = 0; if (!file1 || !file2) { return ODS_STATUS_ASSERT_ERR; } if ((fin = open(file1, O_RDONLY|O_NONBLOCK)) < 0) { return ODS_STATUS_FOPEN_ERR; } if (append) { fout = open(file2, O_WRONLY|O_APPEND|O_CREAT, 0666); } else { fout = open(file2, O_WRONLY|O_TRUNC|O_CREAT, 0666); } if (fout < 0) { close(fin); return ODS_STATUS_FOPEN_ERR; } ods_log_debug("[%s] lseek file %s pos %ld", file_str, file1, startpos); if (lseek(fin, startpos, SEEK_SET) < 0) { close(fin); close(fout); return ODS_STATUS_FSEEK_ERR; } while (1) { read_size = read(fin, buf, sizeof(buf)); if (read_size == 0) { break; } if (read_size < 0) { ods_log_error("[%s] read file %s error %s", file_str, file1, strerror(errno)); close(fin); close(fout); return ODS_STATUS_FREAD_ERR; } if (write(fout, buf, (unsigned int) read_size) < 0) { ods_log_error("[%s] write file %s error %s", file_str, file1, strerror(errno)); close(fin); close(fout); return ODS_STATUS_FWRITE_ERR; } } close(fin); close(fout); return ODS_STATUS_OK; }
/** * Create zone transfer handler. * */ xfrhandler_type* xfrhandler_create() { xfrhandler_type* xfrh = NULL; CHECKALLOC(xfrh = (xfrhandler_type*) malloc(sizeof(xfrhandler_type))); xfrh->engine = NULL; xfrh->packet = NULL; xfrh->netio = NULL; xfrh->tcp_set = NULL; xfrh->tcp_waiting_first = NULL; xfrh->udp_waiting_first = NULL; xfrh->udp_waiting_last = NULL; xfrh->udp_use_num = 0; xfrh->start_time = 0; xfrh->current_time = 0; xfrh->got_time = 0; xfrh->need_to_exit = 0; xfrh->started = 0; /* notify */ xfrh->notify_waiting_first = NULL; xfrh->notify_waiting_last = NULL; xfrh->notify_udp_num = 0; /* setup */ xfrh->netio = netio_create(); if (!xfrh->netio) { ods_log_error("[%s] unable to create xfrhandler: " "netio_create() failed", xfrh_str); xfrhandler_cleanup(xfrh); return NULL; } xfrh->packet = buffer_create(PACKET_BUFFER_SIZE); if (!xfrh->packet) { ods_log_error("[%s] unable to create xfrhandler: " "buffer_create() failed", xfrh_str); xfrhandler_cleanup(xfrh); return NULL; } xfrh->tcp_set = tcp_set_create(); if (!xfrh->tcp_set) { ods_log_error("[%s] unable to create xfrhandler: " "tcp_set_create() failed", xfrh_str); xfrhandler_cleanup(xfrh); return NULL; } xfrh->dnshandler.fd = -1; xfrh->dnshandler.user_data = (void*) xfrh; xfrh->dnshandler.timeout = 0; xfrh->dnshandler.event_types = NETIO_EVENT_READ; xfrh->dnshandler.event_handler = xfrhandler_handle_dns; xfrh->dnshandler.free_handler = 0; return xfrh; }
/** * Create dns handler. * */ dnshandler_type* dnshandler_create(allocator_type* allocator, listener_type* interfaces) { dnshandler_type* dnsh = NULL; if (!allocator || !interfaces || interfaces->count <= 0) { return NULL; } dnsh = (dnshandler_type*) allocator_alloc(allocator, sizeof(dnshandler_type)); if (!dnsh) { ods_log_error("[%s] unable to create dnshandler: " "allocator_alloc() failed", dnsh_str); return NULL; } dnsh->allocator = allocator; dnsh->need_to_exit = 0; dnsh->engine = NULL; dnsh->interfaces = interfaces; dnsh->socklist = NULL; dnsh->netio = NULL; dnsh->query = NULL; /* setup */ dnsh->socklist = (socklist_type*) allocator_alloc(allocator, sizeof(socklist_type)); if (!dnsh->socklist) { ods_log_error("[%s] unable to create socklist: " "allocator_alloc() failed", dnsh_str); dnshandler_cleanup(dnsh); return NULL; } dnsh->netio = netio_create(allocator); if (!dnsh->netio) { ods_log_error("[%s] unable to create dnshandler: " "netio_create() failed", dnsh_str); dnshandler_cleanup(dnsh); return NULL; } dnsh->query = query_create(); if (!dnsh->query) { ods_log_error("[%s] unable to create dnshandler: " "query_create() failed", dnsh_str); dnshandler_cleanup(dnsh); return NULL; } dnsh->xfrhandler.fd = -1; dnsh->xfrhandler.user_data = (void*) dnsh; dnsh->xfrhandler.timeout = 0; dnsh->xfrhandler.event_types = NETIO_EVENT_READ; dnsh->xfrhandler.event_handler = dnshandler_handle_xfr; return dnsh; }
/** * Get the user identifier from the username. * */ uid_t privuid(const char* username) { struct passwd pwd; struct passwd* result; long bufsize; char* buf; uid_t uid; int s; uid = geteuid(); if (username) { bufsize = sysconf(_SC_GETPW_R_SIZE_MAX); if (bufsize == -1) { bufsize = 16384; /* should be more than enough */ } buf = (char*) calloc(bufsize, sizeof(char)); if (!buf) { ods_log_crit("[%s] calloc failed: insufficient memory", logstr); return -1; } /* Lookup the user id in /etc/passwd */ s = getpwnam_r(username, &pwd, buf, bufsize, &result); /* leaks? */ if (s) { ods_log_error("[%s] unable to get user id for %s: %s", logstr, username, strerror(s)); } if (result != NULL) { uid = pwd.pw_uid; } free(buf); } else { uid = -1; } return uid; }
static int run(int sockfd, cmdhandler_ctx_type* context, const char *cmd) { db_connection_t* dbconn = getconnectioncontext(context); engine_type* engine = getglobalcontext(context); (void)cmd; if (!engine) { return 1; } if (!engine->config) { return 1; } if (!engine->config->zonelist_filename) { return 1; } if (!dbconn) { return 1; } ods_log_debug("[%s] %s command", module_str, zonelist_export_funcblock.cmdname); if (zonelist_export(sockfd, dbconn, engine->config->zonelist_filename, 1) != ZONELIST_EXPORT_OK) { ods_log_error("[%s] zonelist exported to %s failed", module_str, engine->config->zonelist_filename); client_printf_err(sockfd, "Exported zonelist to %s failed!\n", engine->config->zonelist_filename); return 1; } ods_log_info("[%s] zonelist exported to %s successfully", module_str, engine->config->zonelist_filename); client_printf(sockfd, "Exported zonelist to %s successfully\n", engine->config->zonelist_filename); return 0; }
/** * Sign notify. * */ static void notify_tsig_sign(notify_type* notify, buffer_type* buffer) { tsig_algo_type* algo = NULL; if (!notify || !notify->tsig_rr || !notify->secondary || !notify->secondary->tsig || !notify->secondary->tsig->key || !buffer) { return; /* no tsig configured */ } algo = tsig_lookup_algo(notify->secondary->tsig->algorithm); if (!algo) { ods_log_error("[%s] unable to sign notify: tsig unknown algorithm " "%s", notify_str, notify->secondary->tsig->algorithm); return; } ods_log_assert(algo); tsig_rr_reset(notify->tsig_rr, algo, notify->secondary->tsig->key); notify->tsig_rr->original_query_id = buffer_pkt_id(buffer); notify->tsig_rr->algo_name = ldns_rdf_clone(notify->tsig_rr->algo->wf_name); notify->tsig_rr->key_name = ldns_rdf_clone(notify->tsig_rr->key->dname); log_dname(notify->tsig_rr->key_name, "tsig sign notify with key %s", LOG_DEBUG); log_dname(notify->tsig_rr->algo_name, "tsig sign notify with algorithm %s", LOG_DEBUG); tsig_rr_prepare(notify->tsig_rr); tsig_rr_update(notify->tsig_rr, buffer, buffer_position(buffer)); tsig_rr_sign(notify->tsig_rr); ods_log_debug("[%s] tsig append rr to notify id=%u", notify_str, buffer_pkt_id(buffer)); tsig_rr_append(notify->tsig_rr, buffer); buffer_pkt_set_arcount(buffer, buffer_pkt_arcount(buffer)+1); tsig_rr_prepare(notify->tsig_rr); return; }
/** * Create new schedule. Allocate and initialise scheduler. To clean * up schedule_cleanup() should be called. */ schedule_type* schedule_create() { schedule_type* schedule; struct sigaction action; schedule = (schedule_type*) malloc(sizeof(schedule_type)); if (!schedule) { ods_log_error("[%s] unable to create: malloc failed", schedule_str); return NULL; } schedule->tasks = ldns_rbtree_create(task_compare); schedule->tasks_by_name = ldns_rbtree_create(task_compare_name); pthread_mutex_init(&schedule->schedule_lock, NULL); pthread_cond_init(&schedule->schedule_cond, NULL); /* static condition for alarm. Must be accessible from interrupt */ schedule_cond = &schedule->schedule_cond; action.sa_handler = (void (*)(int))&alarm_handler; sigfillset(&action.sa_mask); action.sa_flags = 0; sigaction(SIGALRM, &action, NULL); return schedule; }
/** * Start zone transfer handler. * */ void xfrhandler_start(xfrhandler_type* xfrhandler) { ods_log_assert(xfrhandler); ods_log_assert(xfrhandler->engine); ods_log_debug("[%s] start", xfrh_str); /* setup */ xfrhandler->start_time = time_now(); /* handlers */ netio_add_handler(xfrhandler->netio, &xfrhandler->dnshandler); /* service */ while (xfrhandler->need_to_exit == 0) { /* dispatch may block for a longer period, so current is gone */ xfrhandler->got_time = 0; ods_log_deeebug("[%s] netio dispatch", xfrh_str); if (netio_dispatch(xfrhandler->netio, NULL, NULL) == -1) { if (errno != EINTR) { ods_log_error("[%s] unable to dispatch netio: %s", xfrh_str, strerror(errno)); } } } /* shutdown */ ods_log_debug("[%s] shutdown", xfrh_str); }