Пример #1
0
/**
 * Drop privileges.
 *
 */
static ods_status
engine_privdrop(engine_type* engine)
{
    ods_status status = ODS_STATUS_OK;
    uid_t uid = -1;
    gid_t gid = -1;
    ods_log_assert(engine);
    ods_log_assert(engine->config);
    ods_log_debug("[%s] drop privileges", engine_str);
    if (engine->config->username && engine->config->group) {
        ods_log_verbose("[%s] drop privileges to user %s, group %s",
           engine_str, engine->config->username, engine->config->group);
    } else if (engine->config->username) {
        ods_log_verbose("[%s] drop privileges to user %s", engine_str,
           engine->config->username);
    } else if (engine->config->group) {
        ods_log_verbose("[%s] drop privileges to group %s", engine_str,
           engine->config->group);
    }
    if (engine->config->chroot) {
        ods_log_verbose("[%s] chroot to %s", engine_str,
            engine->config->chroot);
    }
    status = privdrop(engine->config->username, engine->config->group,
        engine->config->chroot, &uid, &gid);
    engine->uid = uid;
    engine->gid = gid;
    privclose(engine->config->username, engine->config->group);
    return status;
}
Пример #2
0
/**
 * 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;
}
Пример #3
0
/**
 * Worker working with...
 *
 */
static void
worker_working_with(worker_type* worker, task_id with, task_id next,
    const char* str, const char* name, task_id* what, time_t* when)
{
    worker->working_with = with;
    ods_log_verbose("[%s[%i]] %s zone %s", worker2str(worker->type),
       worker->thread_num, str, name);
    *what = next;
    *when = time_now();
    return;
}
Пример #4
0
/**
 * Handle notify.
 *
 */
static void
notify_handle_zone(netio_type* ATTR_UNUSED(netio),
    netio_handler_type* handler, netio_events_type event_types)
{
    notify_type* notify = NULL;
    xfrhandler_type* xfrhandler = NULL;
    zone_type* zone = NULL;
    if (!handler) {
        return;
    }
    notify = (notify_type*) handler->user_data;
    ods_log_assert(notify);
    xfrhandler = (xfrhandler_type*) notify->xfrhandler;
    zone = (zone_type*) notify->zone;
    ods_log_assert(xfrhandler);
    ods_log_assert(zone);
    ods_log_assert(zone->name);
    ods_log_debug("[%s] handle notify for zone %s", notify_str, zone->name);

    if (notify->is_waiting) {
        ods_log_debug("[%s] already waiting, skipping notify for zone %s",
            notify_str, zone->name);
        ods_log_assert(notify->handler.fd == -1);
        return;
    }
    if (event_types & NETIO_EVENT_READ) {
        ods_log_debug("[%s] read notify ok for zone %s", notify_str,
            zone->name);
        ods_log_assert(notify->handler.fd != -1);
        if (notify_udp_read_packet(notify)) {
            if (notify_handle_reply(notify)) {
                notify_next(notify);
            }
        }
    } else if(event_types & NETIO_EVENT_TIMEOUT) {
        ods_log_debug("[%s] notify timeout for zone %s", notify_str,
            zone->name);
        /* timeout, try again */
    }
    /* see if notify is still enabled */
    if (notify->secondary) {
        ods_log_assert(notify->secondary->address);
        notify->retry++;
        if (notify->retry > NOTIFY_MAX_RETRY) {
            ods_log_verbose("[%s] notify max retry for zone %s, %s unreachable",
                notify_str, zone->name, notify->secondary->address);
            notify_next(notify);
        } else {
            notify_send(notify);
        }
    }
    return;
}
Пример #5
0
/**
 * Process DNSKEY.
 *
 */
static void
adapi_process_dnskey(zone_type* zone, ldns_rr* rr)
{
    uint32_t tmp = 0;
    ods_log_assert(rr);
    ods_log_assert(zone);
    ods_log_assert(zone->name);
    ods_log_assert(zone->signconf);
    tmp = (uint32_t) duration2time(zone->signconf->dnskey_ttl);
    ods_log_verbose("[%s] zone %s set dnskey ttl to %u",
        adapi_str, zone->name, tmp);
    ldns_rr_set_ttl(rr, tmp);
}
Пример #6
0
/**
 * Start engine.
 *
 */
engine_type *
engine_start(const char* cfgfile, int cmdline_verbosity, int daemonize,
    int info)
{
    engine_type* engine = NULL;
    int use_syslog = 0;
    ods_status status = ODS_STATUS_OK;

    ods_log_assert(cfgfile);
    ods_log_init(NULL, use_syslog, cmdline_verbosity);
    ods_log_verbose("[%s] starting enforcer", engine_str);

    /* initialize */
    xmlInitGlobals();
    xmlInitParser();
    xmlInitThreads();
    engine = engine_create();
    if (!engine) {
        ods_fatal_exit("[%s] create failed", engine_str);
        return NULL;
    }
    engine->daemonize = daemonize;

    /* config */
    engine->config = engine_config(engine->allocator, cfgfile,
        cmdline_verbosity);
    status = engine_config_check(engine->config);
    if (status != ODS_STATUS_OK) {
        ods_log_error("[%s] cfgfile %s has errors", engine_str, cfgfile);
        engine_stop(engine);
        return NULL;
    }
    if (info) {
        engine_config_print(stdout, engine->config); /* for debugging */
        engine_stop(engine);
        return NULL;
    }

    /* open log */
    ods_log_init(engine->config->log_filename, engine->config->use_syslog,
       engine->config->verbosity);

    /* setup */
    tzset(); /* for portability */

    /* initialize protobuf and protobuf-orm */
    ods_protobuf_initialize();
    ods_orm_initialize();
    
    return engine;
}
Пример #7
0
static int
run_flush(int sockfd, cmdhandler_ctx_type* context, const char *cmd)
{
        engine_type* engine = getglobalcontext(context);
	(void)cmd;
	ods_log_debug("[%s] flush tasks command", module_str);
	ods_log_assert(engine);
	ods_log_assert(engine->taskq);

	schedule_flush(engine->taskq);
        
	client_printf(sockfd, "All tasks scheduled immediately.\n");
	ods_log_verbose("[cmdhandler] all tasks scheduled immediately");
	return 0;
}
Пример #8
0
/**
 * Read a zonelist file.
 *
 */
static ods_status
zonelist_read(zonelist_type* zl, const char* zlfile)
{
    const char* rngfile = ODS_SE_RNGDIR "/zonelist.rng";
    ods_status status = ODS_STATUS_OK;
    ods_log_assert(zlfile);
    ods_log_verbose("[%s] read file %s", zl_str, zlfile);
    status = parse_file_check(zlfile, rngfile);
    if (status != ODS_STATUS_OK) {
        ods_log_error("[%s] unable to read file: parse error in %s", zl_str,
                      zlfile);
        return status;
    }
    return parse_zonelist_zones((struct zonelist_struct*) zl, zlfile);
}
Пример #9
0
/**
 * Load signer configuration for zone.
 *
 */
ods_status
zone_load_signconf(zone_type* zone, signconf_type** new_signconf)
{
    ods_status status = ODS_STATUS_OK;
    signconf_type* signconf = NULL;
    char* datestamp = NULL;

    if (!zone || !zone->name || !zone->signconf) {
        return ODS_STATUS_ASSERT_ERR;
    }
    if (!zone->signconf_filename) {
        ods_log_warning("[%s] zone %s has no signconf filename, treat as "
            "insecure?", zone_str, zone->name);
        return ODS_STATUS_INSECURE;
    }
    status = signconf_update(&signconf, zone->signconf_filename,
        zone->signconf->last_modified);
    if (status == ODS_STATUS_OK) {
        if (!signconf) {
            /* this is unexpected */
            ods_log_alert("[%s] unable to load signconf for zone %s: signconf "
                "status ok but no signconf stored", zone_str, zone->name);
            return ODS_STATUS_ASSERT_ERR;
        }
        (void)time_datestamp(signconf->last_modified, "%Y-%m-%d %T",
            &datestamp);
        ods_log_debug("[%s] zone %s signconf file %s is modified since %s",
            zone_str, zone->name, zone->signconf_filename,
            datestamp?datestamp:"Unknown");
        free((void*)datestamp);
        *new_signconf = signconf;
    } else if (status == ODS_STATUS_UNCHANGED) {
        (void)time_datestamp(zone->signconf->last_modified,
            "%Y-%m-%d %T", &datestamp);
        ods_log_verbose("[%s] zone %s signconf file %s is unchanged since "
            "%s", zone_str, zone->name, zone->signconf_filename,
            datestamp?datestamp:"Unknown");
        free((void*)datestamp);
    } else {
        ods_log_error("[%s] unable to load signconf for zone %s: signconf %s "
            "%s", zone_str, zone->name, zone->signconf_filename,
            ods_status2str(status));
    }
    return status;
}
Пример #10
0
/**
 * Send notify.
 *
 */
void
notify_send(notify_type* notify)
{
    xfrhandler_type* xfrhandler = NULL;
    zone_type* zone = NULL;
    ods_log_assert(notify);
    ods_log_assert(notify->secondary);
    ods_log_assert(notify->secondary->address);
    xfrhandler = (xfrhandler_type*) notify->xfrhandler;
    zone = (zone_type*) notify->zone;
    ods_log_assert(xfrhandler);
    ods_log_assert(zone);
    ods_log_assert(zone->name);
    if (notify->handler.fd != -1) {
        close(notify->handler.fd);
    }
    notify->handler.fd = -1;
    notify->timeout.tv_sec = notify_time(notify) + NOTIFY_RETRY_TIMEOUT;
    buffer_pkt_notify(xfrhandler->packet, zone->apex, LDNS_RR_CLASS_IN);
    notify->query_id = buffer_pkt_id(xfrhandler->packet);
    buffer_pkt_set_aa(xfrhandler->packet);
    /* add current SOA to answer section */
    if (notify->soa) {
        if (buffer_write_rr(xfrhandler->packet, notify->soa)) {
            buffer_pkt_set_ancount(xfrhandler->packet, 1);
        }
    }
    if (notify->secondary->tsig) {
        notify_tsig_sign(notify, xfrhandler->packet);
    }
    buffer_flip(xfrhandler->packet);
    notify->handler.fd = notify_send_udp(notify, xfrhandler->packet);
    if (notify->handler.fd == -1) {
        ods_log_error("[%s] unable to send notify retry %u for zone %s to "
            "%s: notify_send_udp() failed", notify_str, notify->retry,
            zone->name, notify->secondary->address);
        return;
    }
    ods_log_verbose("[%s] notify retry %u for zone %s sent to %s", notify_str,
        notify->retry, zone->name, notify->secondary->address);
    return;
}
Пример #11
0
/**
 * Initialize logging.
 *
 */
void
ods_log_init(const char *filename, int use_syslog, int verbosity)
{
#ifdef HAVE_SYSLOG_H
    int facility;
#endif /* HAVE_SYSLOG_H */
    ods_log_verbose("[%s] switching log to %s verbosity %i (log level %i)",
        log_str, use_syslog?"syslog":(filename&&filename[0]?filename:"stderr"),
        verbosity, verbosity+2);
    if (logfile && logfile != stderr) {
            ods_fclose(logfile);
	}
    log_level = verbosity + 2;

#ifdef HAVE_SYSLOG_H
    if(logging_to_syslog) {
        closelog();
        logging_to_syslog = 0;
    }
    if(use_syslog) {
       facility = ods_log_get_facility(filename);
       openlog(MY_PACKAGE_TARNAME, LOG_NDELAY, facility);
       logging_to_syslog = 1;
       return;
    }
#endif /* HAVE_SYSLOG_H */

    if(filename && filename[0]) {
        logfile = ods_fopen(filename, NULL, "a");
        if (logfile) {
            ods_log_debug("[%s] new logfile %s", log_str, filename);
            return;
        }
        logfile = stderr;
        ods_log_warning("[%s] cannot open %s for appending, logging to "
            "stderr", log_str, filename);
    } else {
        logfile = stderr;
    }
    return;
}
Пример #12
0
/**
 * Reschedule task for zone.
 *
 */
ods_status
zone_reschedule_task(zone_type* zone, schedule_type* taskq, task_id what)
{
     task_type* task = NULL;
     ods_status status = ODS_STATUS_OK;

     ods_log_assert(taskq);
     ods_log_assert(zone);
     ods_log_assert(zone->name);
     ods_log_assert(zone->task);
     ods_log_debug("[%s] reschedule task for zone %s", zone_str, zone->name);
     lock_basic_lock(&taskq->schedule_lock);
     task = unschedule_task(taskq, (task_type*) zone->task);
     if (task != NULL) {
         if (task->what != what) {
             task->halted = task->what;
             task->halted_when = task->when;
             task->interrupt = what;
         }
         /** Only reschedule if what to do is lower than what was scheduled. */
         if (task->what > what) {
             task->what = what;
         }
         task->when = time_now();
         status = schedule_task(taskq, task, 0);
     } else {
         /* task not queued, being worked on? */
         ods_log_verbose("[%s] unable to reschedule task for zone %s now: "
             "task is not queued (task will be rescheduled when it is put "
             "back on the queue)", zone_str, zone->name);
         task = (task_type*) zone->task;
         task->interrupt = what;
         /* task->halted(_when) set by worker */
     }
     lock_basic_unlock(&taskq->schedule_lock);
     zone->task = task;
     return status;
}
Пример #13
0
/**
 * 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;
}
Пример #14
0
/**
 * Read IXFR from file.
 *
 */
static ods_status
addns_read_file(FILE* fd, zone_type* zone)
{
    ldns_rr* rr = NULL;
    uint32_t new_serial = 0;
    uint32_t old_serial = 0;
    uint32_t tmp_serial = 0;
    ldns_rdf* prev = NULL;
    ldns_rdf* orig = NULL;
    ldns_rdf* dname = NULL;
    uint32_t ttl = 0;
    size_t rr_count = 0;
    ods_status result = ODS_STATUS_OK;
    ldns_status status = LDNS_STATUS_OK;
    char line[SE_ADFILE_MAXLINE];
    unsigned is_axfr = 0;
    unsigned del_mode = 0;
    unsigned soa_seen = 0;
    unsigned line_update_interval = 100000;
    unsigned line_update = line_update_interval;
    unsigned l = 0;

    ods_log_assert(fd);
    ods_log_assert(zone);

    /* $ORIGIN <zone name> */
    dname = adapi_get_origin(zone);
    if (!dname) {
        ods_log_error("[%s] error getting default value for $ORIGIN",
                      adapter_str);
        return ODS_STATUS_ERR;
    }
    orig = ldns_rdf_clone(dname);
    if (!orig) {
        ods_log_error("[%s] error setting default value for $ORIGIN",
                      adapter_str);
        return ODS_STATUS_ERR;
    }
    /* $TTL <default ttl> */
    ttl = adapi_get_ttl(zone);
    /* read RRs */
    while ((rr = addns_read_rr(fd, line, &orig, &prev, &ttl, &status, &l))
            != NULL) {
        /* check status */
        if (status != LDNS_STATUS_OK) {
            ods_log_error("[%s] error reading RR at line %i (%s): %s",
                          adapter_str, l, ldns_get_errorstr_by_id(status), line);
            result = ODS_STATUS_ERR;
            break;
        }
        /* debug update */
        if (l > line_update) {
            ods_log_debug("[%s] ...at line %i: %s", adapter_str, l, line);
            line_update += line_update_interval;
        }
        /* first RR: check if SOA and correct zone & serialno */
        if (rr_count == 0) {
            rr_count++;
            if (ldns_rr_get_type(rr) != LDNS_RR_TYPE_SOA) {
                ods_log_error("[%s] bad xfr, first rr is not soa",
                              adapter_str);
                ldns_rr_free(rr);
                rr = NULL;
                result = ODS_STATUS_ERR;
                break;
            }
            soa_seen++;
            if (ldns_dname_compare(ldns_rr_owner(rr), zone->apex)) {
                ods_log_error("[%s] bad xfr, soa dname not equal to zone "
                              "dname %s", adapter_str, zone->name);
                ldns_rr_free(rr);
                rr = NULL;
                result = ODS_STATUS_ERR;
                break;
            }
            tmp_serial =
                ldns_rdf2native_int32(ldns_rr_rdf(rr, SE_SOA_RDATA_SERIAL));
            old_serial = adapi_get_serial(zone);
            if (!util_serial_gt(tmp_serial, old_serial)) {
                ods_log_info("[%s] zone %s is already up to date, have "
                             "serial %u, got serial %u", adapter_str, zone->name,
                             old_serial, tmp_serial);
                new_serial = tmp_serial;
                ldns_rr_free(rr);
                rr = NULL;
                result = ODS_STATUS_UNCHANGED;
                break;
            }
            ldns_rr_free(rr);
            rr = NULL;
            result = ODS_STATUS_OK;
            continue;
        }
        /* second RR: if not soa, this is an AXFR */
        if (rr_count == 1) {
            if (ldns_rr_get_type(rr) != LDNS_RR_TYPE_SOA) {
                ods_log_verbose("[%s] detected axfr serial=%u for zone %s",
                                adapter_str, tmp_serial, zone->name);
                new_serial = tmp_serial;
                is_axfr = 1;
                del_mode = 0;
            } else {
                ods_log_verbose("[%s] detected ixfr serial=%u for zone %s",
                                adapter_str, tmp_serial, zone->name);
                new_serial = tmp_serial;
                tmp_serial =
                    ldns_rdf2native_int32(ldns_rr_rdf(rr, SE_SOA_RDATA_SERIAL));
                ldns_rr_free(rr);
                rr = NULL;
                rr_count++;
                if (tmp_serial < new_serial) {
                    del_mode = 1;
                    result = ODS_STATUS_OK;
                    continue;
                } else {
                    ods_log_error("[%s] bad xfr for zone %s, bad soa serial",
                                  adapter_str, zone->name);
                    result = ODS_STATUS_ERR;
                    break;
                }
            }
        }
        /* soa means swap */
        rr_count++;
        if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_SOA) {
            if (!is_axfr) {
                tmp_serial =
                    ldns_rdf2native_int32(ldns_rr_rdf(rr, SE_SOA_RDATA_SERIAL));
                if (tmp_serial <= new_serial) {
                    if (tmp_serial == new_serial) {
                        soa_seen++;
                    }
                    del_mode = !del_mode;
                    ldns_rr_free(rr);
                    rr = NULL;
                    result = ODS_STATUS_OK;
                    continue;
                } else {
                    ods_log_assert(tmp_serial > new_serial);
                    ods_log_error("[%s] bad xfr for zone %s, bad soa serial",
                                  adapter_str, zone->name);
                    ldns_rr_free(rr);
                    rr = NULL;
                    result = ODS_STATUS_ERR;
                    break;
                }
            } else {
                /* for axfr */
                soa_seen++;
            }
        }
        /* [add to/remove from] the zone */
        if (!is_axfr && del_mode) {
            ods_log_debug("[%s] delete RR #%i at line %i: %s",
                          adapter_str, rr_count, l, line);
            result = adapi_del_rr(zone, rr, 0);
            ldns_rr_free(rr);
            rr = NULL;
        } else {
            ods_log_debug("[%s] add RR #%i at line %i: %s",
                          adapter_str, rr_count, l, line);
            result = adapi_add_rr(zone, rr, 0);
        }
        if (result == ODS_STATUS_UNCHANGED) {
            ods_log_debug("[%s] skipping RR at line %i (%s): %s",
                          adapter_str, l, del_mode?"not found":"duplicate", line);
            ldns_rr_free(rr);
            rr = NULL;
            result = ODS_STATUS_OK;
            continue;
        } else if (result != ODS_STATUS_OK) {
            ods_log_error("[%s] error %s RR at line %i: %s",
                          adapter_str, del_mode?"deleting":"adding", l, line);
            ldns_rr_free(rr);
            rr = NULL;
            break;
        }
    }
    /* and done */
    if (orig) {
        ldns_rdf_deep_free(orig);
        orig = NULL;
    }
    if (prev) {
        ldns_rdf_deep_free(prev);
        prev = NULL;
    }
    if (result == ODS_STATUS_OK && status != LDNS_STATUS_OK) {
        ods_log_error("[%s] error reading RR at line %i (%s): %s",
                      adapter_str, l, ldns_get_errorstr_by_id(status), line);
        result = ODS_STATUS_ERR;
    }
    /* check the number of SOAs seen */
    if (result == ODS_STATUS_OK) {
        if ((is_axfr && soa_seen != 2) || (!is_axfr && soa_seen != 3)) {
            ods_log_error("[%s] bad %s, wrong number of SOAs (%u)",
                          adapter_str, is_axfr?"axfr":"ixfr", soa_seen);
            result = ODS_STATUS_ERR;
        }
    }
    /* input zone ok, set inbound serial and apply differences */
    if (result == ODS_STATUS_OK || result == ODS_STATUS_UNCHANGED) {
        adapi_set_serial(zone, new_serial);
        if (is_axfr) {
            adapi_trans_full(zone);
        } else {
            adapi_trans_diff(zone);
        }
        if (result == ODS_STATUS_UNCHANGED) {
            result = ODS_STATUS_OK;
        }
    }
    return result;
}
Пример #15
0
/**
 * Write zone to output adapter.
 *
 */
ods_status
tools_output(zone_type* zone, engine_type* engine)
{
    ods_status status = ODS_STATUS_OK;
    ods_log_assert(engine);
    ods_log_assert(engine->config);
    ods_log_assert(zone);
    ods_log_assert(zone->db);
    ods_log_assert(zone->name);
    ods_log_assert(zone->signconf);
    ods_log_assert(zone->adoutbound);
    /* prepare */
    if (zone->stats) {
        pthread_mutex_lock(&zone->stats->stats_lock);
        if (zone->stats->sort_done == 0 &&
            (zone->stats->sig_count <= zone->stats->sig_soa_count)) {
            ods_log_verbose("[%s] skip write zone %s serial %u (zone not "
                "changed)", tools_str, zone->name?zone->name:"(null)",
                zone->db->intserial);
            stats_clear(zone->stats);
            pthread_mutex_unlock(&zone->stats->stats_lock);
            zone->db->intserial =
                zone->db->outserial;
            return ODS_STATUS_OK;
        }
        pthread_mutex_unlock(&zone->stats->stats_lock);
    }
    /* Output Adapter */
    status = adapter_write((void*)zone);
    if (status != ODS_STATUS_OK) {
        ods_log_error("[%s] unable to write zone %s: adapter failed (%s)",
            tools_str, zone->name, ods_status2str(status));
        return status;
    }
    zone->db->outserial = zone->db->intserial;
    zone->db->is_initialized = 1;
    zone->db->have_serial = 1;
    pthread_mutex_lock(&zone->ixfr->ixfr_lock);
    ixfr_purge(zone->ixfr, zone->name);
    pthread_mutex_unlock(&zone->ixfr->ixfr_lock);
    /* kick the nameserver */
    if (zone->notify_ns) {
	int pid_status;
        pid_t pid, wpid;
        ods_log_verbose("[%s] notify nameserver: %s", tools_str,
            zone->notify_ns);
	/** fork */
        switch ((pid = fork())) {
            case -1: /* error */
                ods_log_error("[%s] notify nameserver failed: unable to fork "
                    "(%s)", tools_str, strerror(errno));
                return ODS_STATUS_FORK_ERR;
            case 0: /* child */
                /** close fds */
		ods_closeall(0);
                /** execv */
                execvp(zone->notify_ns, zone->notify_args);
                /** error */
                ods_log_error("[%s] notify nameserver failed: execv() failed "
                    "(%s)", tools_str, strerror(errno));
                exit(1);
                break;
            default: /* parent */
                ods_log_debug("[%s] notify nameserver process forked",
                    tools_str);
                /** wait for completion  */
                while((wpid = waitpid(pid, &pid_status, 0)) <= 0) {
                    if (errno != EINTR) {
                        break;
                    }
                }
                if (wpid == -1) {
                    ods_log_error("[%s] notify nameserver failed: waitpid() "
                        "failed (%s)", tools_str, strerror(errno));
                } else if (!WIFEXITED(pid_status)) {
                    ods_log_error("[%s] notify nameserver failed: notify "
                        "command did not terminate normally", tools_str);
                } else {
                    ods_log_verbose("[%s] notify nameserver ok", tools_str);
                }
                break;
        }
    }
    /* log stats */
    if (zone->stats) {
        pthread_mutex_lock(&zone->stats->stats_lock);
        zone->stats->end_time = time(NULL);
        ods_log_debug("[%s] log stats for zone %s serial %u", tools_str,
            zone->name?zone->name:"(null)", (unsigned) zone->db->outserial);
        stats_log(zone->stats, zone->name, zone->db->outserial,
            zone->signconf->nsec_type);
        stats_clear(zone->stats);
        pthread_mutex_unlock(&zone->stats->stats_lock);
    }
    if (engine->dnshandler) {
        ods_log_debug("[%s] forward a notify", tools_str);
        dnshandler_fwd_notify(engine->dnshandler, (uint8_t*) ODS_SE_NOTIFY_CMD,
            strlen(ODS_SE_NOTIFY_CMD));
    }
    return status;
}
Пример #16
0
/**
 * Start engine.
 *
 */
void
engine_start(const char* cfgfile, int cmdline_verbosity, int daemonize,
    int info, int single_run)
{
    engine_type* engine = NULL;
    int use_syslog = 0;
    ods_status zl_changed = ODS_STATUS_UNCHANGED;
    ods_status status = ODS_STATUS_OK;
    int close_hsm = 0;

    ods_log_assert(cfgfile);
    ods_log_init(NULL, use_syslog, cmdline_verbosity);
    ods_log_verbose("[%s] starting signer", engine_str);

    /* initialize */
    xmlInitGlobals();
    xmlInitParser();
    xmlInitThreads();
    engine = engine_create();
    if (!engine) {
        ods_fatal_exit("[%s] create failed", engine_str);
        return;
    }
    engine->daemonize = daemonize;

    /* config */
    engine->config = engine_config(engine->allocator, cfgfile,
        cmdline_verbosity);
    status = engine_config_check(engine->config);
    if (status != ODS_STATUS_OK) {
        ods_log_error("[%s] cfgfile %s has errors", engine_str, cfgfile);
        goto earlyexit;
    }
    if (info) {
        engine_config_print(stdout, engine->config); /* for debugging */
        goto earlyexit;
    }
    /* check pidfile */
    if (!util_check_pidfile(engine->config->pid_filename)) {
        exit(1);
    }
    /* open log */
    ods_log_init(engine->config->log_filename, engine->config->use_syslog,
       engine->config->verbosity);
    /* setup */
    tzset(); /* for portability */
    status = engine_setup(engine);
    if (status != ODS_STATUS_OK) {
        ods_log_error("[%s] setup failed: %s", engine_str,
            ods_status2str(status));
        engine->need_to_exit = 1;
        if (status != ODS_STATUS_WRITE_PIDFILE_ERR) {
            /* command handler had not yet been started */
            engine->cmdhandler_done = 1;
        }
    } else {
        /* setup ok, mark hsm open */
        close_hsm = 1;
    }

    /* run */
    while (engine->need_to_exit == 0) {
        /* update zone list */
        lock_basic_lock(&engine->zonelist->zl_lock);
        zl_changed = zonelist_update(engine->zonelist,
            engine->config->zonelist_filename);
        engine->zonelist->just_removed = 0;
        engine->zonelist->just_added = 0;
        engine->zonelist->just_updated = 0;
        lock_basic_unlock(&engine->zonelist->zl_lock);
        /* start/reload */
        if (engine->need_to_reload) {
            ods_log_info("[%s] signer reloading", engine_str);
            engine->need_to_reload = 0;
        } else {
            ods_log_info("[%s] signer started", engine_str);
            zl_changed = engine_recover(engine);
        }
        if (zl_changed == ODS_STATUS_OK ||
            zl_changed == ODS_STATUS_UNCHANGED) {
            engine_update_zones(engine, zl_changed);
        }
        engine_run(engine, single_run);
    }

    /* shutdown */
    ods_log_info("[%s] signer shutdown", engine_str);
    if (close_hsm) {
        ods_log_verbose("[%s] close hsm", engine_str);
        hsm_close();
    }
    if (!engine->cmdhandler_done) {
        engine_stop_xfrhandler(engine);
        engine_stop_dnshandler(engine);
        engine_stop_cmdhandler(engine);
    }

earlyexit:
    if (engine && engine->config) {
        if (engine->config->pid_filename) {
            (void)unlink(engine->config->pid_filename);
        }
        if (engine->config->clisock_filename) {
            (void)unlink(engine->config->clisock_filename);
        }
    }
    tsig_handler_cleanup();
    engine_cleanup(engine);
    engine = NULL;
    ods_log_close();
    xmlCleanupParser();
    xmlCleanupGlobals();
    xmlCleanupThreads();
    return;
}
Пример #17
0
/**
 * Set up engine.
 *
 */
static ods_status
engine_setup(engine_type* engine)
{
    ods_status status = ODS_STATUS_OK;
    struct sigaction action;
    int result = 0;
    int sockets[2] = {0,0};

    ods_log_debug("[%s] setup signer engine", engine_str);
    if (!engine || !engine->config) {
        return ODS_STATUS_ASSERT_ERR;
    }
    /* set edns */
    edns_init(&engine->edns, EDNS_MAX_MESSAGE_LEN);

    /* create command handler (before chowning socket file) */
    engine->cmdhandler = cmdhandler_create(engine->allocator,
        engine->config->clisock_filename);
    if (!engine->cmdhandler) {
        return ODS_STATUS_CMDHANDLER_ERR;
    }
    engine->dnshandler = dnshandler_create(engine->allocator,
        engine->config->interfaces);
    engine->xfrhandler = xfrhandler_create(engine->allocator);
    if (!engine->xfrhandler) {
        return ODS_STATUS_XFRHANDLER_ERR;
    }
    if (engine->dnshandler) {
        if (socketpair(AF_UNIX, SOCK_DGRAM, 0, sockets) == -1) {
            return ODS_STATUS_XFRHANDLER_ERR;
        }
        engine->xfrhandler->dnshandler.fd = sockets[0];
        engine->dnshandler->xfrhandler.fd = sockets[1];
        status = dnshandler_listen(engine->dnshandler);
        if (status != ODS_STATUS_OK) {
            ods_log_error("[%s] setup: unable to listen to sockets (%s)",
                engine_str, ods_status2str(status));
        }
    }
    /* privdrop */
    engine->uid = privuid(engine->config->username);
    engine->gid = privgid(engine->config->group);
    /* TODO: does piddir exists? */
    /* remove the chown stuff: piddir? */
    ods_chown(engine->config->pid_filename, engine->uid, engine->gid, 1);
    ods_chown(engine->config->clisock_filename, engine->uid, engine->gid, 0);
    ods_chown(engine->config->working_dir, engine->uid, engine->gid, 0);
    if (engine->config->log_filename && !engine->config->use_syslog) {
        ods_chown(engine->config->log_filename, engine->uid, engine->gid, 0);
    }
    if (engine->config->working_dir &&
        chdir(engine->config->working_dir) != 0) {
        ods_log_error("[%s] setup: unable to chdir to %s (%s)", engine_str,
            engine->config->working_dir, strerror(errno));
        return ODS_STATUS_CHDIR_ERR;
    }
    if (engine_privdrop(engine) != ODS_STATUS_OK) {
        return ODS_STATUS_PRIVDROP_ERR;
    }
    /* daemonize */
    if (engine->daemonize) {
        switch ((engine->pid = fork())) {
            case -1: /* error */
                ods_log_error("[%s] setup: unable to fork daemon (%s)",
                    engine_str, strerror(errno));
                return ODS_STATUS_FORK_ERR;
            case 0: /* child */
                break;
            default: /* parent */
                engine_cleanup(engine);
                engine = NULL;
                xmlCleanupParser();
                xmlCleanupGlobals();
                xmlCleanupThreads();
                exit(0);
        }
        if (setsid() == -1) {
            ods_log_error("[%s] setup: unable to setsid daemon (%s)",
                engine_str, strerror(errno));
            return ODS_STATUS_SETSID_ERR;
        }
    }
    engine->pid = getpid();
    ods_log_verbose("[%s] running as pid %lu", engine_str,
        (unsigned long) engine->pid);
    /* catch signals */
    signal_set_engine(engine);
    action.sa_handler = signal_handler;
    sigfillset(&action.sa_mask);
    action.sa_flags = 0;
    sigaction(SIGTERM, &action, NULL);
    sigaction(SIGHUP, &action, NULL);
    sigaction(SIGINT, &action, NULL);
    sigaction(SIGILL, &action, NULL);
    sigaction(SIGUSR1, &action, NULL);
    sigaction(SIGALRM, &action, NULL);
    sigaction(SIGCHLD, &action, NULL);
    action.sa_handler = SIG_IGN;
    sigaction(SIGPIPE, &action, NULL);
    /* set up hsm */ /* LEAK */
    result = lhsm_open(engine->config->cfg_filename);
    if (result != HSM_OK) {
        return ODS_STATUS_HSM_ERR;
    }
    /* create workers/drudgers */
    engine_create_workers(engine);
    engine_create_drudgers(engine);
    /* start cmd/dns/xfr handlers */
    engine_start_cmdhandler(engine);
    engine_start_dnshandler(engine);
    engine_start_xfrhandler(engine);
    tsig_handler_init(engine->allocator);
    /* write pidfile */
    if (util_write_pidfile(engine->config->pid_filename, engine->pid) == -1) {
        hsm_close();
        return ODS_STATUS_WRITE_PIDFILE_ERR;
    }
    /* setup done */
    return ODS_STATUS_OK;
}
Пример #18
0
/**
 * Configure engine.
 *
 */
engineconfig_type*
engine_config(allocator_type* allocator, const char* cfgfile,
    int cmdline_verbosity)
{
    engineconfig_type* ecfg;
    const char* rngfile = ODS_SE_RNGDIR "/conf.rng";
    FILE* cfgfd = NULL;

    if (!allocator) {
        ods_log_error("[%s] failed to read: no allocator available", conf_str);
        return NULL;
    }
    ods_log_assert(allocator);
    if (!cfgfile) {
        ods_log_error("[%s] failed to read: no filename given", conf_str);
        return NULL;
    }
    ods_log_assert(cfgfile);
    ods_log_verbose("[%s] read cfgfile: %s", conf_str, cfgfile);

    ecfg = (engineconfig_type*) allocator_alloc(allocator,
        sizeof(engineconfig_type));
    if (!ecfg) {
        ods_log_error("[%s] failed to read: allocator failed", conf_str);
        return NULL;
    }

    ecfg->allocator = allocator;

    /* check syntax (slows down parsing configuration file) */
    if (parse_file_check(cfgfile, rngfile) != ODS_STATUS_OK) {
        ods_log_error("[%s] failed to read: unable to parse file %s",
            conf_str, cfgfile);
        return NULL;
    }

    /* open cfgfile */
    cfgfd = ods_fopen(cfgfile, NULL, "r");
    if (cfgfd) {
        /* get values */
        ecfg->cfg_filename = allocator_strdup(allocator, cfgfile);
        ecfg->policy_filename = parse_conf_policy_filename(allocator,
            cfgfile);
        ecfg->zonelist_filename = parse_conf_zonelist_filename(allocator,
            cfgfile);
        ecfg->zonefetch_filename = parse_conf_zonefetch_filename(allocator,
            cfgfile);
        ecfg->log_filename = parse_conf_log_filename(allocator, cfgfile);
        ecfg->pid_filename = parse_conf_pid_filename(allocator, cfgfile);
        ecfg->delegation_signer_submit_command = 
            parse_conf_delegation_signer_submit_command(allocator, cfgfile);
        ecfg->delegation_signer_retract_command = 
            parse_conf_delegation_signer_retract_command(allocator, cfgfile);
        ecfg->clisock_filename = parse_conf_clisock_filename(allocator,
            cfgfile);
        ecfg->working_dir = parse_conf_working_dir(allocator, cfgfile);
        ecfg->username = parse_conf_username(allocator, cfgfile);
        ecfg->group = parse_conf_group(allocator, cfgfile);
        ecfg->chroot = parse_conf_chroot(allocator, cfgfile);
        ecfg->datastore = parse_conf_datastore(allocator, cfgfile);
		ecfg->db_host = parse_conf_db_host(allocator,cfgfile);
		ecfg->db_username = parse_conf_db_username(allocator,cfgfile);
		ecfg->db_password = parse_conf_db_password(allocator,cfgfile);
        ecfg->use_syslog = parse_conf_use_syslog(cfgfile);
        ecfg->num_worker_threads = parse_conf_worker_threads(cfgfile);
        ecfg->manual_keygen = parse_conf_manual_keygen(cfgfile);
        /* If any verbosity has been specified at cmd line we will use that */
        if (cmdline_verbosity > 0) {
        	ecfg->verbosity = cmdline_verbosity;
        }
        else {
        	ecfg->verbosity = parse_conf_verbosity(cfgfile);
        }
		ecfg->db_port = parse_conf_db_port(cfgfile);
		ecfg->automatic_keygen_duration =
			parse_conf_automatic_keygen_period(cfgfile);

        /* done */
        ods_fclose(cfgfd);
        return ecfg;
    }

    ods_log_error("[%s] failed to read: unable to open file %s", conf_str,
        cfgfile);
    return NULL;
}
Пример #19
0
/**
 * Process SOA.
 *
 */
static ods_status
adapi_process_soa(zone_type* zone, ldns_rr* rr, int add, int backup)
{
    uint32_t tmp = 0;
    ldns_rdf* soa_rdata = NULL;
    ods_status status = ODS_STATUS_OK;

    ods_log_assert(rr);
    ods_log_assert(zone);
    ods_log_assert(zone->name);
    ods_log_assert(zone->signconf);

    if (backup) {
        /* no need to do processing */
        return ODS_STATUS_OK;
    }
    if (zone->signconf->soa_ttl) {
        tmp = (uint32_t) duration2time(zone->signconf->soa_ttl);
        ods_log_verbose("[%s] zone %s set soa ttl to %u",
            adapi_str, zone->name, tmp);
        ldns_rr_set_ttl(rr, tmp);
    }
    if (zone->signconf->soa_min) {
        tmp = (uint32_t) duration2time(zone->signconf->soa_min);
        ods_log_verbose("[%s] zone %s set soa minimum to %u",
            adapi_str, zone->name, tmp);
        soa_rdata = ldns_rr_set_rdf(rr,
            ldns_native2rdf_int32(LDNS_RDF_TYPE_INT32, tmp),
            SE_SOA_RDATA_MINIMUM);
        if (soa_rdata) {
            ldns_rdf_deep_free(soa_rdata);
            soa_rdata = NULL;
        } else {
            ods_log_error("[%s] unable to %s soa to zone %s: failed to replace "
                "soa minimum rdata", adapi_str, add?"add":"delete",
                zone->name);
            return ODS_STATUS_ASSERT_ERR;
        }
    }
    if (!add) {
        /* we are done */
        return ODS_STATUS_OK;
    }
    tmp = ldns_rdf2native_int32(ldns_rr_rdf(rr, SE_SOA_RDATA_SERIAL));
    status = namedb_update_serial(zone->db, zone->name,
        zone->signconf->soa_serial, tmp);
    if (status != ODS_STATUS_OK) {
        ods_log_error("[%s] unable to add soa to zone %s: failed to replace "
            "soa serial rdata (%s)", adapi_str, zone->name,
            ods_status2str(status));
        if (status == ODS_STATUS_CONFLICT_ERR) {
            ods_log_error("[%s] If this is the result of a key rollover, "
                "please increment the serial in the unsigned zone %s",
                adapi_str, zone->name);
        }
        return status;
    }
    ods_log_verbose("[%s] zone %s set soa serial to %u", adapi_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 add soa to zone %s: failed to replace "
            "soa serial rdata", adapi_str, zone->name);
        return ODS_STATUS_ERR;
    }
    zone->db->serial_updated = 1;
    return ODS_STATUS_OK;
}
Пример #20
0
/**
 * Set up engine and return the setup status.
 *
 */
static ods_status
engine_setup_and_return_status(engine_type* engine)
{
    struct sigaction action;
    int result = 0;
    int fd;

    ods_log_debug("[%s] enforcer setup", engine_str);
    if (!engine || !engine->config) {
        return ODS_STATUS_ASSERT_ERR;
    }

    /* create command handler (before chowning socket file) */
    engine->cmdhandler = cmdhandler_create(engine->allocator,
        engine->config->clisock_filename);
    if (!engine->cmdhandler) {
        ods_log_error("[%s] create command handler to %s failed",
            engine_str, engine->config->clisock_filename);
        return ODS_STATUS_CMDHANDLER_ERR;
    }

    /* privdrop */
    engine->uid = privuid(engine->config->username);
    engine->gid = privgid(engine->config->group);
    /* TODO: does piddir exists? */
    /* remove the chown stuff: piddir? */
    ods_chown(engine->config->pid_filename, engine->uid, engine->gid, 1);
    ods_chown(engine->config->clisock_filename, engine->uid, engine->gid, 0);
    ods_chown(engine->config->working_dir, engine->uid, engine->gid, 0);
    if (engine->config->log_filename && !engine->config->use_syslog) {
        ods_chown(engine->config->log_filename, engine->uid, engine->gid, 0);
    }
    if (engine->config->working_dir &&
        chdir(engine->config->working_dir) != 0) {
        ods_log_error("[%s] chdir to %s failed: %s", engine_str,
            engine->config->working_dir, strerror(errno));
        return ODS_STATUS_CHDIR_ERR;
    }
    if (engine_privdrop(engine) != ODS_STATUS_OK) {
        ods_log_error("[%s] unable to drop privileges", engine_str);
        return ODS_STATUS_PRIVDROP_ERR;
    }

    /* daemonize */
    if (engine->daemonize) {
        switch ((engine->pid = fork())) {
            case -1: /* error */
                ods_log_error("[%s] unable to fork daemon: %s",
                    engine_str, strerror(errno));
                return ODS_STATUS_FORK_ERR;
            case 0: /* child */
                if ((fd = open("/dev/null", O_RDWR, 0)) != -1) {
                    (void)dup2(fd, STDIN_FILENO);
                    (void)dup2(fd, STDOUT_FILENO);
                    (void)dup2(fd, STDERR_FILENO);
                    if (fd > 2) (void)close(fd);
                }
                break;
            default: /* parent */
                engine_cleanup(engine);
                engine = NULL;
                xmlCleanupParser();
                xmlCleanupGlobals();
                xmlCleanupThreads();
                exit(0);
        }
        if (setsid() == -1) {
            ods_log_error("[%s] unable to setsid daemon (%s)",
                engine_str, strerror(errno));
            return ODS_STATUS_SETSID_ERR;
        }
    }
    engine->pid = getpid();
    ods_log_verbose("[%s] running as pid %lu", engine_str,
        (unsigned long) engine->pid);

    /* catch signals */
    signal_set_engine(engine);
    action.sa_handler = signal_handler;
    sigfillset(&action.sa_mask);
    action.sa_flags = 0;
    sigaction(SIGHUP, &action, NULL);
    sigaction(SIGTERM, &action, NULL);

    /* set up hsm */ /* LEAK */
    result = hsm_open(engine->config->cfg_filename, hsm_prompt_pin, NULL);
    if (result != HSM_OK) {
        ods_log_error("[%s] error initializing libhsm (errno %i)",
            engine_str, result);
        return ODS_STATUS_HSM_ERR;
    }

    /* create workers */
    engine_create_workers(engine);
    engine_create_drudgers(engine);

    /* start command handler */
    engine_start_cmdhandler(engine);

    /* write pidfile */
    if (util_write_pidfile(engine->config->pid_filename, engine->pid) == -1) {
        hsm_close();
        ods_log_error("[%s] unable to write pid file", engine_str);
        return ODS_STATUS_WRITE_PIDFILE_ERR;
    }

    return ODS_STATUS_OK;
}