Beispiel #1
0
static void
enf_schedule_task(int sockfd, engine_type* engine, task_type *task, const char *what)
{
	/* schedule task */
	if (!task) {
		ods_log_crit("[%s] failed to create %s task", module_str, what);
	} else {
		ods_status status = schedule_task(engine->taskq, task);
		if (status != ODS_STATUS_OK) {
			ods_log_crit("[%s] failed to create %s task", module_str, what);
			client_printf(sockfd, "Unable to schedule %s task.\n", what);
		} else {
			client_printf(sockfd, "Scheduled %s task.\n", what);
		}
	}
}
Beispiel #2
0
/**
 * 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;
}
Beispiel #3
0
/**
 * Get the group identifier from the group name.
 *
 */
gid_t
privgid(const char *groupname)
{
    struct group grp;
    struct group* result;
    long bufsize;
    char* buf;
    gid_t gid;
    int s;
    gid = getegid();
    if (groupname) {
        bufsize = sysconf(_SC_GETGR_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 group id in /etc/group */
        s = getgrnam_r(groupname, &grp, buf, bufsize, &result); /* leaks? */
        if (s) {
            ods_log_error("[%s] unable to get group id for %s: %s",
                logstr, groupname, strerror(s));
        }
        if (result != NULL) {
            gid = grp.gr_gid;
        }
        free(buf);
    } else {
        gid = -1;
    }
    return gid;
}
Beispiel #4
0
static void 
ods_protobuf_loghandler(::google::protobuf::LogLevel level,
						const char *filename,
						int line,
						const std::string &message)
{
	const char * const fmt = "[%s] %s %s:%d] %s";
	switch (level) {
		case ::google::protobuf::LOGLEVEL_INFO:
			ods_log_info(fmt,module_str,"INFO",filename,line,message.c_str());
			break;
		case ::google::protobuf::LOGLEVEL_WARNING:
			ods_log_warning(fmt,module_str,"WARNING",filename,line,message.c_str());
			break;
		case ::google::protobuf::LOGLEVEL_ERROR:
			ods_log_crit(fmt,module_str,"ERROR",filename,line,message.c_str());
			break;
		case ::google::protobuf::LOGLEVEL_FATAL:
			ods_fatal_exit(fmt,module_str,"FATAL",filename,line,message.c_str());
			break;
		default:
			ods_log_assert(false);
			break;
	}
}
Beispiel #5
0
/**
 * Construct file name. (StrAppend?, snprintf?)
 *
 */
char*
ods_build_path(const char* file, const char* suffix, int dir, int no_slash)
{
    size_t len_file = 0;
    size_t len_suffix = 0;
    size_t len_total = 0;
    char* openf = NULL;

    if (file) {
        len_file = strlen(file);
        if (suffix) {
            len_suffix = strlen(suffix);
        }
        len_total = len_suffix + len_file;
        if (dir) {
            len_total++;
        }

        if (len_total > 0) {
            openf = (char*) malloc(sizeof(char)*(len_total + 1));
            if (!openf) {
                ods_log_crit("[%s] build path failed: malloc failed", file_str);
                return NULL;
            }

            strncpy(openf, file, len_file);
            openf[len_file] = '\0';
            if (no_slash) {
                size_t i = 0;
                for (i=0; i<len_file; i++) {
                    switch (openf[i]) {
                        case '/':
                        case ' ':
                        /* more? */
                            openf[i] = '-';
                            break;
                        default:
                            break;
                    }
                }
            }

            if (suffix) {
                strncat(openf, suffix, len_suffix);
            }
            if (dir) {
                strncat(openf, "/", 1);
            }
            openf[len_total] = '\0';
        }
    }

    return openf;
}
Beispiel #6
0
/**
 * Get next char.
 *
 */
int
ods_fgetc(FILE* fd, unsigned int* line_nr)
{
    int c;

    ods_log_assert(fd);
    ods_log_assert(line_nr);

    c = fgetc(fd);
	if (c == '\n') {
        (*line_nr)++;
    }
    if (c == EOF && errno != 0) {
        ods_log_crit("[%s] fgetc() failed, enough memory? (%s)",
            file_str, strerror(errno));
    }
    return c;
}
Beispiel #7
0
int
schedule_flush_type(schedule_type* schedule, task_id id)
{
    ldns_rbnode_t *node, *nextnode;
    int nflushed = 0;
    
    ods_log_debug("[%s] flush task", schedule_str);
    if (!schedule || !schedule->tasks) return 0;

    pthread_mutex_lock(&schedule->schedule_lock);
        node = ldns_rbtree_first(schedule->tasks);
        while (node && node != LDNS_RBTREE_NULL) {
            nextnode = ldns_rbtree_next(node);
            if (node->data && ((task_type*)node->data)->what == id) {
                /* Merely setting flush is not enough. We must set it
                 * to the front of the queue as well. */
                node = ldns_rbtree_delete(schedule->tasks, node->data);
                if (!node) break; /* stange, bail out */
                if (node->data) { /* task */
                    ((task_type*)node->data)->flush = 1;
                    /* This is important for our tests only. If a task is
                     * set to flush it should not affect the current time.
                     * Otherwise timeleap will advance time. */
                    ((task_type*)node->data)->when = time_now();
                    if (!ldns_rbtree_insert(schedule->tasks, node)) {
                        ods_log_crit("[%s] Could not reschedule task "
                            "after flush. A task has been lost!",
                            schedule_str);
                        free(node);
                        /* Do not free node->data it is still in use
                         * by the other rbtree. */
                        break;
                    }
                    nflushed++;
                }
            }
            node = nextnode;
        }
        /* wakeup! work to do! */
        pthread_cond_signal(&schedule->schedule_cond);
    pthread_mutex_unlock(&schedule->schedule_lock);
    return nflushed;
}
/**
 * Open HSM.
 *
 */
int
lhsm_open(const char* filename)
{
    int result = hsm_open(filename, hsm_check_pin);
    if (result != HSM_OK) {
        char* error =  hsm_get_error(NULL);
        if (error != NULL) {
            ods_log_error("[%s] %s", hsm_str, error);
            free(error);
        } else {
            ods_log_crit("[%s] error opening libhsm (errno %i)", hsm_str,
                         result);
        }
        /* exit? */
    } else {
        ods_log_info("[%s] libhsm connection opened succesfully", hsm_str);
    }
    return result;
}
/**
 * Drudge.
 *
 */
static void
worker_drudge(worker_type* worker)
{
    engine_type* engine = NULL;
    zone_type* zone = NULL;
    task_type* task = NULL;
    rrset_type* rrset = NULL;
    ods_status status = ODS_STATUS_OK;
    worker_type* superior = NULL;
    hsm_ctx_t* ctx = NULL;

    ods_log_assert(worker);
    ods_log_assert(worker->engine);
    ods_log_assert(worker->type == WORKER_DRUDGER);

    engine = (engine_type*) worker->engine;
    while (worker->need_to_exit == 0) {
        ods_log_deeebug("[%s[%i]] report for duty", worker2str(worker->type),
            worker->thread_num);
        /* initialize */
        superior = NULL;
        zone = NULL;
        task = NULL;
        /* get item */
        lock_basic_lock(&engine->signq->q_lock);
        rrset = (rrset_type*) fifoq_pop(engine->signq, &superior);
        if (!rrset) {
            ods_log_deeebug("[%s[%i]] nothing to do, wait",
                worker2str(worker->type), worker->thread_num);
            /**
             * Apparently the queue is empty. Wait until new work is queued.
             * The drudger will release the signq lock while sleeping and
             * will automatically grab the lock when the threshold is reached.
             * Threshold is at 1 and MAX (after a number of tries).
             */
            lock_basic_sleep(&engine->signq->q_threshold,
                &engine->signq->q_lock, 0);
            rrset = (rrset_type*) fifoq_pop(engine->signq, &superior);
        }
        lock_basic_unlock(&engine->signq->q_lock);
        /* do some work */
        if (rrset) {
            ods_log_assert(superior);
            if (!ctx) {
                ods_log_debug("[%s[%i]] create hsm context",
                    worker2str(worker->type), worker->thread_num);
                ctx = hsm_create_context();
            }
            if (!ctx) {
                ods_log_crit("[%s[%i]] error creating libhsm context",
                    worker2str(worker->type), worker->thread_num);
                engine->need_to_reload = 1;
                lock_basic_lock(&superior->worker_lock);
                superior->jobs_failed++;
                lock_basic_unlock(&superior->worker_lock);
            } else {
                ods_log_assert(ctx);
                lock_basic_lock(&superior->worker_lock);
                task = superior->task;
                ods_log_assert(task);
                zone = task->zone;
                lock_basic_unlock(&superior->worker_lock);
                ods_log_assert(zone);
                ods_log_assert(zone->apex);
                ods_log_assert(zone->signconf);
                worker->clock_in = time(NULL);
                status = rrset_sign(ctx, rrset, superior->clock_in);
                lock_basic_lock(&superior->worker_lock);
                if (status == ODS_STATUS_OK) {
                    superior->jobs_completed++;
                } else {
                    superior->jobs_failed++;
                }
                lock_basic_unlock(&superior->worker_lock);
            }
            if (worker_fulfilled(superior) && superior->sleeping) {
                ods_log_deeebug("[%s[%i]] wake up superior[%u], work is "
                    "done", worker2str(worker->type), worker->thread_num,
                    superior->thread_num);
                worker_wakeup(superior);
            }
            superior = NULL;
            rrset = NULL;
        }
        /* done work */
    }
    /* wake up superior */
    if (superior && superior->sleeping) {
        ods_log_deeebug("[%s[%i]] wake up superior[%u], i am exiting",
            worker2str(worker->type), worker->thread_num, superior->thread_num);
         worker_wakeup(superior);
    }
    /* cleanup open HSM sessions */
    if (ctx) {
        hsm_destroy_context(ctx);
    }
    return;
}
/**
 * Perform task.
 *
 */
static void
worker_perform_task(worker_type* worker)
{
    engine_type* engine = NULL;
    zone_type* zone = NULL;
    task_type* task = NULL;
    task_id what = TASK_NONE;
    time_t when = 0;
    time_t never = (3600*24*365);
    ods_status status = ODS_STATUS_OK;
    int backup = 0;
    time_t start = 0;
    time_t end = 0;

    if (!worker || !worker->task || !worker->task->zone || !worker->engine) {
        return;
    }
    engine = (engine_type*) worker->engine;
    task = (task_type*) worker->task;
    zone = (zone_type*) worker->task->zone;
    ods_log_debug("[%s[%i]] perform task %s for zone %s at %u",
       worker2str(worker->type), worker->thread_num, task_what2str(task->what),
       task_who2str(task), (uint32_t) worker->clock_in);
    /* do what you have been told to do */
    switch (task->what) {
        case TASK_SIGNCONF:
            /* perform 'load signconf' task */
            worker_working_with(worker, TASK_SIGNCONF, TASK_READ,
                "configure", task_who2str(task), &what, &when);
            status = tools_signconf(zone);
            if (status == ODS_STATUS_UNCHANGED) {
                if (!zone->signconf->last_modified) {
                    ods_log_debug("[%s[%i]] no signconf.xml for zone %s yet",
                        worker2str(worker->type), worker->thread_num,
                        task_who2str(task));
                    status = ODS_STATUS_ERR;
                }
            }
            if (status == ODS_STATUS_UNCHANGED) {
                if (task->halted != TASK_NONE && task->halted != TASK_SIGNCONF) {
                    goto task_perform_continue;
                }
                status = ODS_STATUS_OK;
            } else if (status == ODS_STATUS_OK) {
                task->interrupt = TASK_NONE;
                task->halted = TASK_NONE;
            } else {
                if (task->halted == TASK_NONE) {
                    goto task_perform_fail;
                }
                goto task_perform_continue;
            }
            /* break; */
        case TASK_READ:
            /* perform 'read input adapter' task */
            worker_working_with(worker, TASK_READ, TASK_SIGN,
                "read", task_who2str(task), &what, &when);
            task->what = TASK_READ;
            if (!zone->signconf->last_modified) {
                ods_log_debug("[%s[%i]] no signconf.xml for zone %s yet",
                    worker2str(worker->type), worker->thread_num,
                    task_who2str(task));
                status = ODS_STATUS_ERR;
            } else {
                lhsm_check_connection((void*)engine);
                status = tools_input(zone);
            }

            if (status == ODS_STATUS_UNCHANGED) {
                ods_log_verbose("[%s[%i]] zone %s unsigned data not changed, "
                    "continue", worker2str(worker->type), worker->thread_num,
                    task_who2str(task));
                status = ODS_STATUS_OK;
            }
            if (status == ODS_STATUS_OK) {
                if (task->interrupt > TASK_SIGNCONF) {
                    task->interrupt = TASK_NONE;
                    task->halted = TASK_NONE;
                }
            } else {
                if (task->halted == TASK_NONE) {
                    goto task_perform_fail;
                }
                goto task_perform_continue;
            }
            /* break; */
        case TASK_SIGN:
            /* perform 'sign' task */
            worker_working_with(worker, TASK_SIGN, TASK_WRITE,
                "sign", task_who2str(task), &what, &when);
            task->what = TASK_SIGN;
            status = zone_update_serial(zone);
            if (status == ODS_STATUS_OK) {
                if (task->interrupt > TASK_SIGNCONF) {
                    task->interrupt = TASK_NONE;
                    task->halted = TASK_NONE;
                }
            } else {
                ods_log_error("[%s[%i]] unable to sign zone %s: "
                    "failed to increment serial",
                    worker2str(worker->type), worker->thread_num,
                    task_who2str(task));
                if (task->halted == TASK_NONE) {
                    goto task_perform_fail;
                }
                goto task_perform_continue;
            }

            /* start timer */
            start = time(NULL);
            if (zone->stats) {
                lock_basic_lock(&zone->stats->stats_lock);
                if (!zone->stats->start_time) {
                    zone->stats->start_time = start;
                }
                zone->stats->sig_count = 0;
                zone->stats->sig_soa_count = 0;
                zone->stats->sig_reuse = 0;
                zone->stats->sig_time = 0;
                lock_basic_unlock(&zone->stats->stats_lock);
            }
            /* check the HSM connection before queuing sign operations */
            lhsm_check_connection((void*)engine);
            /* queue menial, hard signing work */
            worker_queue_zone(worker, engine->signq, zone);
            ods_log_deeebug("[%s[%i]] wait until drudgers are finished "
                "signing zone %s", worker2str(worker->type), worker->thread_num,
                task_who2str(task));
            /* sleep until work is done */
            worker_sleep_unless(worker, 0);
            /* stop timer */
            end = time(NULL);
            status = worker_check_jobs(worker, task);
            worker_clear_jobs(worker);
            if (status == ODS_STATUS_OK && zone->stats) {
                lock_basic_lock(&zone->stats->stats_lock);
                zone->stats->sig_time = (end-start);
                lock_basic_unlock(&zone->stats->stats_lock);
            }
            if (status != ODS_STATUS_OK) {
                if (task->halted == TASK_NONE) {
                    goto task_perform_fail;
                }
                goto task_perform_continue;
            } else {
                if (task->interrupt > TASK_SIGNCONF) {
                    task->interrupt = TASK_NONE;
                    task->halted = TASK_NONE;
                }
            }
            /* break; */
        case TASK_WRITE:
            /* perform 'write to output adapter' task */
            worker_working_with(worker, TASK_WRITE, TASK_SIGN,
                "write", task_who2str(task), &what, &when);
            task->what = TASK_WRITE;
            status = tools_output(zone, engine);
            if (status == ODS_STATUS_OK) {
                if (task->interrupt > TASK_SIGNCONF) {
                    task->interrupt = TASK_NONE;
                    task->halted = TASK_NONE;
                }
            } else {
                /* clear signatures? */
                if (task->halted == TASK_NONE) {
                    goto task_perform_fail;
                }
                goto task_perform_continue;
            }
            zone->db->is_processed = 1;
            if (zone->signconf &&
                duration2time(zone->signconf->sig_resign_interval)) {
                what = TASK_SIGN;
                when = worker->clock_in +
                    duration2time(zone->signconf->sig_resign_interval);
            } else {
                ods_log_error("[%s[%i]] unable to retrieve resign interval "
                    "for zone %s: duration2time() failed",
                    worker2str(worker->type), worker->thread_num,
                    task_who2str(task));
                ods_log_info("[%s[%i]] defaulting to 1H resign interval for "
                    "zone %s", worker2str(worker->type), worker->thread_num,
                    task_who2str(task));
                what = TASK_SIGN;
                when = worker->clock_in + 3600;
            }
            backup = 1;
            break;
        case TASK_NONE:
            worker->working_with = TASK_NONE;
            /* no task */
            ods_log_warning("[%s[%i]] none task for zone %s",
                worker2str(worker->type), worker->thread_num,
                task_who2str(task));
            when = time_now() + never;
            break;
        default:
            worker->working_with = TASK_NONE;
            /* unknown task */
            ods_log_warning("[%s[%i]] unknown task, trying full sign zone %s",
                worker2str(worker->type), worker->thread_num,
                task_who2str(task));
            what = TASK_SIGNCONF;
            when = time_now();
            break;
    }
    /* no error */
    task->backoff = 0;
    if (task->interrupt != TASK_NONE && task->interrupt != what) {
        ods_log_debug("[%s[%i]] interrupt task %s for zone %s",
            worker2str(worker->type), worker->thread_num,
            task_what2str(what), task_who2str(task));
        task->halted = what;
        task->halted_when = when;
        task->what = task->interrupt;
        task->when = time_now();
    } else {
        ods_log_debug("[%s[%i]] next task %s for zone %s",
            worker2str(worker->type), worker->thread_num,
            task_what2str(what), task_who2str(task));
        task->what = what;
        task->when = when;
        task->interrupt = TASK_NONE;
        task->halted = TASK_NONE;
        task->halted_when = 0;
    }
    /* backup the last successful run */
    if (backup) {
        status = zone_backup2(zone);
        if (status != ODS_STATUS_OK) {
            ods_log_warning("[%s[%i]] unable to backup zone %s: %s",
            worker2str(worker->type), worker->thread_num,
            task_who2str(task), ods_status2str(status));
            /* just a warning */
            status = ODS_STATUS_OK;
        }
        backup = 0;
    }
    return;

task_perform_fail:
    if (status != ODS_STATUS_XFR_NOT_READY) {
        /* other statuses is critical, and we know it is not ODS_STATUS_OK */
        ods_log_crit("[%s[%i]] CRITICAL: failed to sign zone %s: %s",
            worker2str(worker->type), worker->thread_num,
            task_who2str(task), ods_status2str(status));
    }
    /* in case of failure, also mark zone processed (for single run usage) */
    zone->db->is_processed = 1;
    if (task->backoff) {
        task->backoff *= 2;
    } else {
        task->backoff = 60;
    }
    if (task->backoff > ODS_SE_MAX_BACKOFF) {
        task->backoff = ODS_SE_MAX_BACKOFF;
    }
    ods_log_info("[%s[%i]] backoff task %s for zone %s with %u seconds",
        worker2str(worker->type), worker->thread_num,
        task_what2str(task->what), task_who2str(task), task->backoff);
    task->when = time_now() + task->backoff;
    return;

task_perform_continue:
    ods_log_info("[%s[%i]] continue task %s for zone %s",
        worker2str(worker->type), worker->thread_num,
        task_what2str(task->halted), task_who2str(task));
    task->what = task->halted;
    task->when = task->halted_when;
    task->interrupt = TASK_NONE;
    task->halted = TASK_NONE;
    task->halted_when = 0;
    return;
}
/**
 * Try to recover from the backup files.
 *
 */
static ods_status
engine_recover(engine_type* engine)
{
    ldns_rbnode_t* node = LDNS_RBTREE_NULL;
    zone_type* zone = NULL;
    ods_status status = ODS_STATUS_OK;
    ods_status result = ODS_STATUS_UNCHANGED;

    if (!engine || !engine->zonelist || !engine->zonelist->zones) {
        ods_log_error("[%s] cannot recover zones: no engine or zonelist",
            engine_str);
        return ODS_STATUS_ERR; /* no need to update zones */
    }
    ods_log_assert(engine);
    ods_log_assert(engine->zonelist);
    ods_log_assert(engine->zonelist->zones);

    lock_basic_lock(&engine->zonelist->zl_lock);
    /* [LOCK] zonelist */
    node = ldns_rbtree_first(engine->zonelist->zones);
    while (node && node != LDNS_RBTREE_NULL) {
        zone = (zone_type*) node->data;

        ods_log_assert(zone->zl_status == ZONE_ZL_ADDED);
        status = zone_recover2(zone);
        if (status == ODS_STATUS_OK) {
            ods_log_assert(zone->task);
            ods_log_assert(zone->db);
            ods_log_assert(zone->signconf);
            /* notify nameserver */
            if (engine->config->notify_command && !zone->notify_ns) {
                set_notify_ns(zone, engine->config->notify_command);
            }
            /* schedule task */
            lock_basic_lock(&engine->taskq->schedule_lock);
            /* [LOCK] schedule */
            status = schedule_task(engine->taskq, (task_type*) zone->task, 0);
            /* [UNLOCK] schedule */
            lock_basic_unlock(&engine->taskq->schedule_lock);

            if (status != ODS_STATUS_OK) {
                ods_log_crit("[%s] unable to schedule task for zone %s: %s",
                    engine_str, zone->name, ods_status2str(status));
                task_cleanup((task_type*) zone->task);
                zone->task = NULL;
                result = ODS_STATUS_OK; /* will trigger update zones */
            } else {
                ods_log_debug("[%s] recovered zone %s", engine_str,
                    zone->name);
                /* recovery done */
                zone->zl_status = ZONE_ZL_OK;
            }
        } else {
            if (status != ODS_STATUS_UNCHANGED) {
                ods_log_warning("[%s] unable to recover zone %s from backup,"
                " performing full sign", engine_str, zone->name);
            }
            result = ODS_STATUS_OK; /* will trigger update zones */
        }
        node = ldns_rbtree_next(node);
    }
    /* [UNLOCK] zonelist */
    lock_basic_unlock(&engine->zonelist->zl_lock);
    return result;
}
/**
 * Update zones.
 *
 */
void
engine_update_zones(engine_type* engine, ods_status zl_changed)
{
    ldns_rbnode_t* node = LDNS_RBTREE_NULL;
    zone_type* zone = NULL;
    zone_type* delzone = NULL;
    task_type* task = NULL;
    ods_status status = ODS_STATUS_OK;
    unsigned wake_up = 0;
    int warnings = 0;
    time_t now = 0;

    if (!engine || !engine->zonelist || !engine->zonelist->zones) {
        return;
    }
    now = time_now();

    ods_log_debug("[%s] commit zone list changes", engine_str);
    lock_basic_lock(&engine->zonelist->zl_lock);
    node = ldns_rbtree_first(engine->zonelist->zones);
    while (node && node != LDNS_RBTREE_NULL) {
        zone = (zone_type*) node->data;
        task = NULL; /* reset task */

        if (zone->zl_status == ZONE_ZL_REMOVED) {
            node = ldns_rbtree_next(node);
            lock_basic_lock(&zone->zone_lock);
            delzone = zonelist_del_zone(engine->zonelist, zone);
            if (delzone) {
                lock_basic_lock(&engine->taskq->schedule_lock);
                task = unschedule_task(engine->taskq,
                    (task_type*) zone->task);
                lock_basic_unlock(&engine->taskq->schedule_lock);
            }
            task_cleanup(task);
            task = NULL;
            lock_basic_unlock(&zone->zone_lock);
            netio_remove_handler(engine->xfrhandler->netio,
                &zone->xfrd->handler);
            zone_cleanup(zone);
            zone = NULL;
            continue;
        } else if (zone->zl_status == ZONE_ZL_ADDED) {
            lock_basic_lock(&zone->zone_lock);
            ods_log_assert(!zone->task);
            /* set notify nameserver command */
            if (engine->config->notify_command && !zone->notify_ns) {
                set_notify_ns(zone, engine->config->notify_command);
            }
            /* create task */
            task = task_create(TASK_SIGNCONF, now, zone);
            lock_basic_unlock(&zone->zone_lock);
            if (!task) {
                ods_log_crit("[%s] unable to create task for zone %s: "
                    "task_create() failed", engine_str, zone->name);
                node = ldns_rbtree_next(node);
                continue;
            }
        }
        /* load adapter config */
        status = adapter_load_config(zone->adinbound);
        if (status != ODS_STATUS_OK) {
            ods_log_error("[%s] unable to load config for inbound adapter "
                "for zone %s: %s", engine_str, zone->name,
                ods_status2str(status));
        }
        status = adapter_load_config(zone->adoutbound);
        if (status != ODS_STATUS_OK) {
            ods_log_error("[%s] unable to load config for outbound adapter "
                "for zone %s: %s", engine_str, zone->name,
                ods_status2str(status));
        }
        /* for dns adapters */
        warnings += dnsconfig_zone(engine, zone);

        if (zone->zl_status == ZONE_ZL_ADDED) {
            ods_log_assert(task);
            lock_basic_lock(&zone->zone_lock);
            zone->task = task;
            lock_basic_unlock(&zone->zone_lock);
            lock_basic_lock(&engine->taskq->schedule_lock);
            status = schedule_task(engine->taskq, task, 0);
            lock_basic_unlock(&engine->taskq->schedule_lock);
        } else if (zl_changed == ODS_STATUS_OK) {
            /* always try to update signconf */
            lock_basic_lock(&zone->zone_lock);
            status = zone_reschedule_task(zone, engine->taskq, TASK_SIGNCONF);
            lock_basic_unlock(&zone->zone_lock);
        }
        if (status != ODS_STATUS_OK) {
            ods_log_crit("[%s] unable to schedule task for zone %s: %s",
                engine_str, zone->name, ods_status2str(status));
        } else {
            wake_up = 1;
            zone->zl_status = ZONE_ZL_OK;
        }
        node = ldns_rbtree_next(node);
    }
    lock_basic_unlock(&engine->zonelist->zl_lock);
    if (engine->dnshandler) {
        dnshandler_fwd_notify(engine->dnshandler,
            (uint8_t*) ODS_SE_NOTIFY_CMD, strlen(ODS_SE_NOTIFY_CMD));
    } else if (warnings) {
        ods_log_warning("[%s] no dnshandler/listener configured, but zones "
         "are configured with dns adapters: notify and zone transfer "
         "requests will not work properly", engine_str);
    }
    if (wake_up) {
        engine_wakeup_workers(engine);
    }
    return;
}
/**
 * Get RRSIG from one of the HSMs, given a RRset and a key.
 *
 */
ldns_rr*
lhsm_sign(hsm_ctx_t* ctx, ldns_rr_list* rrset, key_type* key_id,
          ldns_rdf* owner, time_t inception, time_t expiration)
{
    ods_status status = ODS_STATUS_OK;
    char* error = NULL;
    ldns_rr* result = NULL;
    hsm_sign_params_t* params = NULL;
    int retries = 0;

    if (!owner || !key_id || !rrset || !inception || !expiration) {
        ods_log_error("[%s] unable to sign: missing required elements",
                      hsm_str);
        return NULL;
    }

lhsm_sign_start:

    /* get dnskey */
    if (!key_id->dnskey) {
        status = lhsm_get_key(ctx, owner, key_id);
        if (status != ODS_STATUS_OK) {
            error = hsm_get_error(ctx);
            if (error) {
                ods_log_error("[%s] %s", hsm_str, error);
                free((void*)error);
            } else if (!retries) {
                lhsm_clear_key_cache(key_id);
                retries++;
                goto lhsm_sign_start;
            }
            ods_log_error("[%s] unable to sign: get key failed", hsm_str);
            return NULL;
        }
    }
    ods_log_assert(key_id->dnskey);
    ods_log_assert(key_id->hsmkey);
    ods_log_assert(key_id->params);
    /* adjust parameters */
    params = hsm_sign_params_new();
    params->owner = ldns_rdf_clone(key_id->params->owner);
    params->algorithm = key_id->algorithm;
    params->flags = key_id->flags;
    params->inception = inception;
    params->expiration = expiration;
    params->keytag = ldns_calc_keytag(key_id->dnskey);
    ods_log_deeebug("[%s] sign RRset[%i] with key %s tag %u", hsm_str,
                    ldns_rr_get_type(ldns_rr_list_rr(rrset, 0)),
                    key_id->locator?key_id->locator:"(null)", params->keytag);
    result = hsm_sign_rrset(ctx, rrset, key_id->hsmkey, params);
    hsm_sign_params_free(params);
    if (!result) {
        error = hsm_get_error(ctx);
        if (error) {
            ods_log_error("[%s] %s", hsm_str, error);
            free((void*)error);
        } else if (!retries) {
            lhsm_clear_key_cache(key_id);
            retries++;
            goto lhsm_sign_start;
        }
        ods_log_crit("[%s] error signing rrset with libhsm", hsm_str);
    }
    return result;
}
Beispiel #14
0
/**
 * Merge zone lists.
 *
 */
static void
zonelist_merge(zonelist_type* zl1, zonelist_type* zl2)
{
    zone_type* z1 = NULL;
    zone_type* z2 = NULL;
    ldns_rbnode_t* n1 = LDNS_RBTREE_NULL;
    ldns_rbnode_t* n2 = LDNS_RBTREE_NULL;
    int ret = 0;

    ods_log_assert(zl1);
    ods_log_assert(zl2);
    ods_log_assert(zl1->zones);
    ods_log_assert(zl2->zones);
    ods_log_debug("[%s] merge two zone lists", zl_str);

    n1 = ldns_rbtree_first(zl1->zones);
    n2 = ldns_rbtree_first(zl2->zones);
    while (n2 && n2 != LDNS_RBTREE_NULL) {
        z2 = (zone_type*) n2->data;
        if (n1 && n1 != LDNS_RBTREE_NULL) {
            z1 = (zone_type*) n1->data;
        } else {
            z1 = NULL;
        }
        if (!z2) {
            /* no more zones to merge into zl1 */
            return;
        } else if (!z1) {
            /* just add remaining zones from zl2 */
            z2 = zonelist_add_zone(zl1, z2);
            if (!z2) {
                ods_log_crit("[%s] merge failed: z2 not added", zl_str);
                return;
            }
            n2 = ldns_rbtree_next(n2);
        } else {
            /* compare the zones z1 and z2 */
            ret = zone_compare(z1, z2);
            if (ret < 0) {
                /* remove zone z1, it is not present in the new list zl2 */
                z1->zl_status = ZONE_ZL_REMOVED;
                zl1->just_removed++;
                n1 = ldns_rbtree_next(n1);
            } else if (ret > 0) {
                /* add the new zone z2 */
                z2 = zonelist_add_zone(zl1, z2);
                if (!z2) {
                    ods_log_crit("[%s] merge failed: z2 not added", zl_str);
                    return;
                }
                n2 = ldns_rbtree_next(n2);
            } else {
                /* just update zone z1 */
                n1 = ldns_rbtree_next(n1);
                n2 = ldns_rbtree_next(n2);
                zone_merge(z1, z2);
                zone_cleanup(z2);
                if (z1->zl_status == ZONE_ZL_UPDATED) {
                    zl1->just_updated++;
                }
                z1->zl_status = ZONE_ZL_UPDATED;
            }
        }
    }
    /* remove remaining zones from z1 */
    while (n1 && n1 != LDNS_RBTREE_NULL) {
        z1 = (zone_type*) n1->data;
        z1->zl_status = ZONE_ZL_REMOVED;
        zl1->just_removed++;
        n1 = ldns_rbtree_next(n1);
    }
    zl1->last_modified = zl2->last_modified;
    return;
}