Exemple #1
0
/**
 * (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);
    }
}
Exemple #2
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;
	}
}
/**
 * Convert a duration to a time.
 *
 */
time_t
duration2time(duration_type* duration)
{
    time_t period = 0;
    char* dstr = NULL;

    if (duration) {
        period += (duration->seconds);
        period += (duration->minutes)*60;
        period += (duration->hours)*3600;
        period += (duration->days)*86400;
        period += (duration->weeks)*86400*7;
        period += (duration->months)*86400*31;
        period += (duration->years)*86400*365;

        if (duration->months || duration->years) {
            /* [TODO] calculate correct number of days in this month/year */
            dstr = duration2string(duration);
            ods_log_warning("[%s] converting duration %s to approximate value",
                duration_str, dstr?dstr:"(null)");
            free((void*) dstr);
        }
    }
    return period;
}
Exemple #4
0
/**
 * Add zone.
 *
 */
zone_type*
zonelist_add_zone(zonelist_type* zlist, zone_type* zone)
{
    ldns_rbnode_t* new_node = NULL;
    if (!zone) {
        return NULL;
    }
    if (!zlist || !zlist->zones) {
        zone_cleanup(zone);
        return NULL;
    }
    /* look up */
    if (zonelist_lookup_zone(zlist, zone) != NULL) {
        ods_log_warning("[%s] unable to add zone %s: already present", zl_str,
                        zone->name);
        zone_cleanup(zone);
        return NULL;
    }
    /* add */
    new_node = zone2node(zone);
    if (ldns_rbtree_insert(zlist->zones, new_node) == NULL) {
        ods_log_error("[%s] unable to add zone %s: ldns_rbtree_insert() "
                      "failed", zl_str, zone->name);
        free((void*) new_node);
        zone_cleanup(zone);
        return NULL;
    }
    zone->zl_status = ZONE_ZL_ADDED;
    zlist->just_added++;
    return zone;
}
int handled_keystate_list_cmd(int sockfd, engine_type* engine, const char *cmd,
                              ssize_t n)
{
    char buf[ODS_SE_MAXLINE];
    const char *argv[8];
    const int NARGV = sizeof(argv)/sizeof(char*);
    int argc;
    const char *scmd = "key list";

    cmd = ods_check_command(cmd,n,scmd);
    if (!cmd)
        return 0; // not handled
    
    ods_log_debug("[%s] %s command", module_str, scmd);
    
    // Use buf as an intermediate buffer for the command.
    strncpy(buf,cmd,sizeof(buf));
    buf[sizeof(buf)-1] = '\0';
    
    // separate the arguments
    argc = ods_str_explode(buf,NARGV,argv);
    if (argc > NARGV) {
        ods_log_warning("[%s] too many arguments for %s command",
                        module_str,scmd);
        ods_printf(sockfd,"too many arguments\n");
		help_keystate_list_cmd(sockfd);
        return 1; // errors, but handled
    }
    
    bool bVerbose = ods_find_arg(&argc,argv,"verbose","v") != -1;
    bool bDebug = ods_find_arg(&argc,argv,"debug","d") != -1;
    if (argc) {
        ods_log_warning("[%s] unknown arguments for %s command",
                        module_str,scmd);
        ods_printf(sockfd,"unknown arguments\n");
		help_keystate_list_cmd(sockfd);
        return 1; // errors, but handled
    }
    
    time_t tstart = time(NULL);

    perform_keystate_list(sockfd, engine->config, bVerbose, bDebug);
	
	ods_printf(sockfd,"%s completed in %ld seconds.\n",scmd,time(NULL)-tstart);
    
    return 1;
}
/**
 * Reopen HSM.
 *
 */
int
lhsm_reopen(const char* filename)
{
    if (hsm_check_context(NULL) != HSM_OK) {
        ods_log_warning("[%s] idle libhsm connection, trying to reopen",
                        hsm_str);
        hsm_close();
        return lhsm_open(filename);
    }
    return HSM_OK;
}
/**
 * Enable notify.
 *
 */
void
notify_enable(notify_type* notify, ldns_rr* soa)
{
    xfrhandler_type* xfrhandler = NULL;
    zone_type* zone = NULL;
    dnsout_type* dnsout = NULL;
    if (!notify) {
        return;
    }
    xfrhandler = (xfrhandler_type*) notify->xfrhandler;
    ods_log_assert(xfrhandler);
    zone = (zone_type*) notify->zone;
    ods_log_assert(zone);
    ods_log_assert(zone->name);
    ods_log_assert(zone->adoutbound);
    ods_log_assert(zone->adoutbound->config);
    ods_log_assert(zone->adoutbound->type == ADAPTER_DNS);
    dnsout = (dnsout_type*) zone->adoutbound->config;
    if (!dnsout->do_notify) {
        ods_log_warning("[%s] zone %s has no notify acl", notify_str,
            zone->name);
        return; /* nothing to do */
    }
    notify_update_soa(notify, soa);
    if (notify->is_waiting) {
        ods_log_debug("[%s] zone %s already on waiting list", notify_str,
            zone->name);
       return;
    }
    if (xfrhandler->notify_udp_num < NOTIFY_MAX_UDP) {
        notify_setup(notify);
        xfrhandler->notify_udp_num++;
        ods_log_debug("[%s] zone %s notify enabled", notify_str,
            zone->name);
        return;
    }
    /* put it in waiting list */
    notify->secondary = dnsout->do_notify;
    notify->is_waiting = 1;
    notify->waiting_next = NULL;
    if (xfrhandler->notify_waiting_last) {
        xfrhandler->notify_waiting_last->waiting_next = notify;
    } else {
        xfrhandler->notify_waiting_first = notify;
    }
    xfrhandler->notify_waiting_last = notify;
    notify->handler.timeout = NULL;
    ods_log_debug("[%s] zone %s notify on waiting list", notify_str,
        zone->name);
    return;
}
/**
 * Delete RR.
 *
 */
ods_status
zone_del_rr(zone_type* zone, ldns_rr* rr, int do_stats)
{
    domain_type* domain = NULL;
    rrset_type* rrset = NULL;
    rr_type* record = NULL;
    ods_log_assert(rr);
    ods_log_assert(zone);
    ods_log_assert(zone->name);
    ods_log_assert(zone->db);
    ods_log_assert(zone->signconf);
    domain = namedb_lookup_domain(zone->db, ldns_rr_owner(rr));
    if (!domain) {
        ods_log_warning("[%s] unable to delete RR from zone %s: "
            "domain not found", zone_str, zone->name);
        return ODS_STATUS_UNCHANGED;
    }
    rrset = domain_lookup_rrset(domain, ldns_rr_get_type(rr));
    if (!rrset) {
        ods_log_warning("[%s] unable to delete RR from zone %s: "
            "RRset not found", zone_str, zone->name);
        return ODS_STATUS_UNCHANGED;
    }
    record = rrset_lookup_rr(rrset, rr);
    if (!record) {
        ods_log_error("[%s] unable to delete RR from zone %s: "
            "RR not found", zone_str, zone->name);
        return ODS_STATUS_UNCHANGED;
    }

    record->is_removed = 1;
    record->is_added = 0; /* unset is_added */
    /* update stats */
    if (do_stats && zone->stats) {
        zone->stats->sort_count -= 1;
    }
    return ODS_STATUS_OK;
}
/**
 * Run engine, run!.
 *
 */
static void
engine_run(engine_type* engine, int single_run)
{
    if (!engine) {
        return;
    }
    engine_start_workers(engine);
    engine_start_drudgers(engine);

    lock_basic_lock(&engine->signal_lock);
    engine->signal = SIGNAL_RUN;
    lock_basic_unlock(&engine->signal_lock);

    while (!engine->need_to_exit && !engine->need_to_reload) {
        lock_basic_lock(&engine->signal_lock);
        engine->signal = signal_capture(engine->signal);
        switch (engine->signal) {
            case SIGNAL_RUN:
                ods_log_assert(1);
                break;
            case SIGNAL_RELOAD:
                engine->need_to_reload = 1;
                break;
            case SIGNAL_SHUTDOWN:
                engine->need_to_exit = 1;
                break;
            default:
                ods_log_warning("[%s] invalid signal %d captured, "
                    "keep running", engine_str, signal);
                engine->signal = SIGNAL_RUN;
                break;
        }
        lock_basic_unlock(&engine->signal_lock);

        if (single_run) {
           engine->need_to_exit = engine_all_zones_processed(engine);
        }
        lock_basic_lock(&engine->signal_lock);
        if (engine->signal == SIGNAL_RUN && !single_run) {
           ods_log_debug("[%s] taking a break", engine_str);
           lock_basic_sleep(&engine->signal_cond, &engine->signal_lock, 3600);
        }
        lock_basic_unlock(&engine->signal_lock);
    }
    ods_log_debug("[%s] signer halted", engine_str);
    engine_stop_drudgers(engine);
    engine_stop_workers(engine);
    (void)lhsm_reopen(engine->config->cfg_filename);
    return;
}
Exemple #10
0
int
ods_log_get_facility(const char* facility)
{
    int length;

    if (!facility) {
        return LOG_DAEMON;
    }
    length = strlen(facility);

    if (length == 4 && strncasecmp(facility, "KERN", 4) == 0)
        return LOG_KERN;
    else if (length == 4 && strncasecmp(facility, "USER", 4) == 0)
        return LOG_USER;
    else if (length == 4 && strncasecmp(facility, "MAIL", 4) == 0)
        return LOG_MAIL;
    else if (length == 6 && strncasecmp(facility, "DAEMON", 6) == 0)
        return LOG_DAEMON;
    else if (length == 4 && strncasecmp(facility, "AUTH", 4) == 0)
        return LOG_AUTH;
    else if (length == 3 && strncasecmp(facility, "LPR", 3) == 0)
        return LOG_LPR;
    else if (length == 4 && strncasecmp(facility, "NEWS", 4) == 0)
        return LOG_NEWS;
    else if (length == 4 && strncasecmp(facility, "UUCP", 4) == 0)
        return LOG_UUCP;
    else if (length == 4 && strncasecmp(facility, "CRON", 4) == 0)
        return LOG_CRON;
    else if (length == 6 && strncasecmp(facility, "LOCAL0", 6) == 0)
        return LOG_LOCAL0;
    else if (length == 6 && strncasecmp(facility, "LOCAL1", 6) == 0)
        return LOG_LOCAL1;
    else if (length == 6 && strncasecmp(facility, "LOCAL2", 6) == 0)
        return LOG_LOCAL2;
    else if (length == 6 && strncasecmp(facility, "LOCAL3", 6) == 0)
        return LOG_LOCAL3;
    else if (length == 6 && strncasecmp(facility, "LOCAL4", 6) == 0)
        return LOG_LOCAL4;
    else if (length == 6 && strncasecmp(facility, "LOCAL5", 6) == 0)
        return LOG_LOCAL5;
    else if (length == 6 && strncasecmp(facility, "LOCAL6", 6) == 0)
        return LOG_LOCAL6;
    else if (length == 6 && strncasecmp(facility, "LOCAL7", 6) == 0)
        return LOG_LOCAL7;
    ods_log_warning("[%s] syslog facility %s not supported, logging to "
                   "log_daemon", log_str, facility);
    return LOG_DAEMON;

}
Exemple #11
0
static int
run(int sockfd, engine_type* engine, const char *cmd, ssize_t n,
	db_connection_t *dbconn)
{
	#define NARGV 8
	char buf[ODS_SE_MAXLINE];
	const char *argv[NARGV];
	int argc;
	const char *zone = NULL;
	(void)engine;
	
	ods_log_debug("[%s] %s command", module_str, rollover_list_funcblock()->cmdname);
	cmd = ods_check_command(cmd, n, rollover_list_funcblock()->cmdname);
	
	/* Use buf as an intermediate buffer for the command.*/
	strncpy(buf, cmd,sizeof(buf));
	buf[sizeof(buf)-1] = '\0';
	
	/* separate the arguments*/
	argc = ods_str_explode(buf, NARGV, argv);
	if (argc > NARGV) {
		ods_log_warning("[%s] too many arguments for %s command",
						module_str, rollover_list_funcblock()->cmdname);
		client_printf(sockfd,"too many arguments\n");
		return -1;
	}
	
	(void)ods_find_arg_and_param(&argc,argv,"zone","z",&zone);
	if (argc) {
		ods_log_warning("[%s] unknown arguments for %s command",
						module_str, rollover_list_funcblock()->cmdname);
		client_printf(sockfd,"unknown arguments\n");
		return -1;
	}
	return perform_rollover_list(sockfd, zone, dbconn);
}
/**
 * Check the HSM connection, reload engine if necessary.
 *
 */
void
lhsm_check_connection(void* engine)
{
    engine_type* e = (engine_type*) engine;
    if (hsm_check_context(NULL) != HSM_OK) {
        ods_log_warning("[%s] idle libhsm connection, trying to reopen",
                        hsm_str);
        engine_stop_drudgers(e);
        hsm_close();
        (void)lhsm_open(e->config->cfg_filename);
        engine_start_drudgers((engine_type*) engine);
    } else {
        ods_log_debug("[%s] libhsm connection ok", hsm_str);
    }
    return;
}
/**
 * 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;
}
Exemple #14
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;
}
Exemple #15
0
/**
 * Delete zone.
 *
 */
zone_type*
zonelist_del_zone(zonelist_type* zlist, zone_type* zone)
{
    ldns_rbnode_t* old_node = LDNS_RBTREE_NULL;
    if (!zone) {
        return NULL;
    }
    if (!zlist || !zlist->zones) {
        goto zone_not_present;
    }
    old_node = ldns_rbtree_delete(zlist->zones, zone);
    if (!old_node) {
        goto zone_not_present;
    }
    free((void*) old_node);
    return zone;

zone_not_present:
    ods_log_warning("[%s] unable to delete zone %s: not present", zl_str,
                    zone->name);
    return zone;
}
Exemple #16
0
/**
 * Convert a duration to a time.
 *
 */
time_t
duration2time(duration_type* duration)
{
    time_t period = 0;
    if (duration) {
        period += (duration->seconds);
        period += (duration->minutes)*60;
        period += (duration->hours)*3600;
        period += (duration->days)*86400;
        period += (duration->weeks)*86400*7;
        period += (duration->months)*86400*31;
        period += (duration->years)*86400*365;
        if (duration->months || duration->years) {
            /* [TODO] calculate correct number of days in this month/year */
            region_type* tmpregion = region_create();
            char* dstr = duration2str(tmpregion, duration);
            ods_log_warning("[%s] converting duration %s to approximate value",
                logstr, dstr?dstr:"(null)");
            region_cleanup(tmpregion);
        }
    }
    return period;
}
/**
 * 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;
}
/**
 * Process query.
 *
 */
query_state
query_process(query_type* q, void* engine)
{
    ldns_status status = LDNS_STATUS_OK;
    ldns_pkt* pkt = NULL;
    ldns_rr* rr = NULL;
    ldns_pkt_rcode rcode = LDNS_RCODE_NOERROR;
    ldns_pkt_opcode opcode = LDNS_PACKET_QUERY;
    ldns_rr_type qtype = LDNS_RR_TYPE_SOA;
    engine_type* e = (engine_type*) engine;
    ods_log_assert(e);
    ods_log_assert(q);
    ods_log_assert(q->buffer);
    if (!e || !q || !q->buffer) {
        ods_log_error("[%s] drop query: assertion error", query_str);
        return QUERY_DISCARDED; /* should not happen */
    }
    if (buffer_limit(q->buffer) < BUFFER_PKT_HEADER_SIZE) {
        ods_log_debug("[%s] drop query: packet too small", query_str);
        return QUERY_DISCARDED; /* too small */
    }
    if (buffer_pkt_qr(q->buffer)) {
        ods_log_debug("[%s] drop query: qr bit set", query_str);
        return QUERY_DISCARDED; /* not a query */
    }
    /* parse packet */
    status = ldns_wire2pkt(&pkt, buffer_current(q->buffer),
        buffer_remaining(q->buffer));
    if (status != LDNS_STATUS_OK) {
        ods_log_debug("[%s] got bad packet: %s", query_str,
            ldns_get_errorstr_by_id(status));
        return query_formerr(q);
    }
    rr = ldns_rr_list_rr(ldns_pkt_question(pkt), 0);
    lock_basic_lock(&e->zonelist->zl_lock);
    /* we can just lookup the zone, because we will only handle SOA queries,
       zone transfers, updates and notifies */
    q->zone = zonelist_lookup_zone_by_dname(e->zonelist, ldns_rr_owner(rr),
        ldns_rr_get_class(rr));
    /* don't answer for zones that are just added */
    if (q->zone && q->zone->zl_status == ZONE_ZL_ADDED) {
        ods_log_warning("[%s] zone %s just added, don't answer for now",
            query_str, q->zone->name);
        q->zone = NULL;
    }
    lock_basic_unlock(&e->zonelist->zl_lock);
    if (!q->zone) {
        ods_log_debug("[%s] zone not found", query_str);
        return query_servfail(q);
    }
    /* see if it is tsig signed */
    if (!query_find_tsig(q)) {
        return query_formerr(q);
    }
    /* else: valid tsig, or no tsig present */
    ods_log_debug("[%s] tsig %s", query_str, tsig_status2str(q->tsig_rr->status));
    rcode = query_process_tsig(q);
    if (rcode != LDNS_RCODE_NOERROR) {
        return query_error(q, rcode);
    }
    /* process edns */
    rcode = query_process_edns(q);
    if (rcode != LDNS_RCODE_NOERROR) {
        /* We should not return FORMERR, but BADVERS (=16).
         * BADVERS is created with Ext. RCODE, followed by RCODE.
         * Ext. RCODE is set to 1, RCODE must be 0 (getting 0x10 = 16).
         * Thus RCODE = NOERROR = NSD_RC_OK. */
        return query_error(q, LDNS_RCODE_NOERROR);
    }

    /* handle incoming request */
    opcode = ldns_pkt_get_opcode(pkt);
    qtype = ldns_rr_get_type(rr);
    ldns_pkt_free(pkt);

    switch (opcode) {
        case LDNS_PACKET_NOTIFY:
            return query_process_notify(q, qtype, engine);
        case LDNS_PACKET_QUERY:
            return query_process_query(q, qtype, engine);
        case LDNS_PACKET_UPDATE:
            return query_process_update(q);
        default:
            break;
    }
    return query_notimpl(q);
}
int handled_keystate_ds_seen_cmd(int sockfd, engine_type* engine,
                                 const char *cmd, ssize_t n)
{
    char buf[ODS_SE_MAXLINE];
    const char *argv[8];
    const int NARGV = sizeof(argv)/sizeof(char*);
    int argc;
    const char *scmd = "key ds-seen";
    
    cmd = ods_check_command(cmd,n,scmd);
    if (!cmd)
        return 0; // not handled

    ods_log_debug("[%s] %s command", module_str, scmd);

    // Use buf as an intermediate buffer for the command.
    strncpy(buf,cmd,sizeof(buf));
    buf[sizeof(buf)-1] = '\0';

    // separate the arguments
    argc = ods_str_explode(buf,NARGV,argv);
    if (argc > NARGV) {
        ods_log_warning("[%s] too many arguments for %s command",
                        module_str,scmd);
        ods_printf(sockfd,"too many arguments\n");
        return 1; // errors, but handled
    }
    
    const char *zone = NULL;
    const char *cka_id = NULL;
    const char *keytag = NULL;
    (void)ods_find_arg_and_param(&argc,argv,"zone","z",&zone);
    (void)ods_find_arg_and_param(&argc,argv,"cka_id","k",&cka_id);
    (void)ods_find_arg_and_param(&argc,argv,"keytag","x",&keytag);
    
    // Check for unknown parameters on the command line
    if (argc) {
        ods_log_warning("[%s] unknown arguments for %s command",
                        module_str,scmd);
        ods_printf(sockfd,"unknown arguments\n");
		help_keystate_ds_seen_cmd(sockfd);
        return 1; // errors, but handled
    }
    
    // Check for too many parameters on the command line
    if (argc > NARGV) {
        ods_log_warning("[%s] too many arguments for %s command",
                        module_str,scmd);
		ods_printf(sockfd,"too many arguments\n");
		help_keystate_ds_seen_cmd(sockfd);		
        return 1; // errors, but handled
    }
    
    // Either no option or combi of zone & cka_id or zone & keytag needs to be 
    // present. But not both cka_id and keytag
    uint16_t nkeytag = 0;
    if (zone || cka_id || keytag) {
        if (!zone) {
            ods_log_warning("[%s] expected option --zone <zone> for %s command",
                            module_str,scmd);
			ods_printf(sockfd,"expected --zone <zone> option\n");
			help_keystate_ds_seen_cmd(sockfd);
            return 1; // errors, but handled
        }
        if (!cka_id && !keytag) {
            ods_log_warning("[%s] expected option --cka_id <cka_id> or "
                            "--keytag <keytag> for %s command",
                            module_str,scmd);
            ods_printf(sockfd,"expected --cka_id <cka_id> or "
                           "--keytag <keytag> option\n");
			help_keystate_ds_seen_cmd(sockfd);
            return 1; // errors, but handled
        } else {
            if (cka_id && keytag) {
                ods_log_warning("[%s] both --cka_id <cka_id> and --keytag <keytag> given, "
                                "please only specify one for %s command",
                                module_str,scmd);
                ods_printf(sockfd,
                               "both --cka_id <cka_id> and --keytag <keytag> given, "
                               "please only specify one\n");
				help_keystate_ds_seen_cmd(sockfd);
                return 1; // errors, but handled
            }
        }
        if (keytag) {
            int kt = atoi(keytag);
            if (kt<=0 || kt>=65536) {
                ods_log_warning("[%s] value \"%s\" for --keytag is invalid",
                                module_str,keytag);
                ods_printf(sockfd,
                               "value \"%s\" for --keytag is invalid\n",
                               keytag);
                return 1; // errors, but handled
            }
            nkeytag = (uint16_t )kt;
        }
    }

    time_t tstart = time(NULL);
	
    perform_keystate_ds_seen(sockfd,engine->config,zone,cka_id,nkeytag);

    ods_printf(sockfd,"%s completed in %ld seconds.\n",scmd,time(NULL)-tstart);

    flush_enforce_task(engine);
    return 1;
}
/**
 * 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;
}
Exemple #22
0
/**
 * Parse keys from the signer configuration file.
 *
 */
keylist_type*
parse_sc_keys(void* sc, const char* cfgfile)
{
    xmlDocPtr doc = NULL;
    xmlXPathContextPtr xpathCtx = NULL;
    xmlXPathObjectPtr xpathObj = NULL;
    xmlNode* curNode = NULL;
    xmlChar* xexpr = NULL;
    key_type* new_key = NULL;
    keylist_type* kl = NULL;
    char* resourcerecord;
    char* locator;
    char* flags;
    char* algorithm;
    int configerr;
    int ksk, zsk, publish, i;

    if (!cfgfile || !sc) {
        return NULL;
    }
    /* Load XML document */
    doc = xmlParseFile(cfgfile);
    if (doc == NULL) {
        ods_log_error("[%s] unable to parse <Keys>: "
            "xmlParseFile() failed", parser_str);
        return NULL;
    }
    /* Create xpath evaluation context */
    xpathCtx = xmlXPathNewContext(doc);
    if(xpathCtx == NULL) {
        xmlFreeDoc(doc);
        ods_log_error("[%s] unable to parse <Keys>: "
            "xmlXPathNewContext() failed", parser_str);
        return NULL;
    }
    /* Evaluate xpath expression */
    xexpr = (xmlChar*) "//SignerConfiguration/Zone/Keys/Key";
    xpathObj = xmlXPathEvalExpression(xexpr, xpathCtx);
    if(xpathObj == NULL) {
        xmlXPathFreeContext(xpathCtx);
        xmlFreeDoc(doc);
        ods_log_error("[%s] unable to parse <Keys>: "
            "xmlXPathEvalExpression() failed", parser_str);
        return NULL;
    }
    /* Parse keys */
    kl = keylist_create(sc);
    ods_log_assert(kl);
    if (xpathObj->nodesetval && xpathObj->nodesetval->nodeNr > 0) {
        for (i = 0; i < xpathObj->nodesetval->nodeNr; i++) {
            resourcerecord = NULL;
            locator = NULL;
            flags = NULL;
            algorithm = NULL;
            ksk = 0;
            zsk = 0;
            publish = 0;
            configerr = 0;

            curNode = xpathObj->nodesetval->nodeTab[i]->xmlChildrenNode;
            while (curNode) {
                if (xmlStrEqual(curNode->name, (const xmlChar *)"Locator")) {
                    locator = (char *) xmlNodeGetContent(curNode);
                } else if (xmlStrEqual(curNode->name, (const xmlChar *)"Algorithm")) {
                    algorithm = (char *) xmlNodeGetContent(curNode);
                } else if (xmlStrEqual(curNode->name, (const xmlChar *)"Flags")) {
                    flags = (char *) xmlNodeGetContent(curNode);
                } else if (xmlStrEqual(curNode->name, (const xmlChar *)"KSK")) {
                    ksk = 1;
                } else if (xmlStrEqual(curNode->name, (const xmlChar *)"ZSK")) {
                    zsk = 1;
                } else if (xmlStrEqual(curNode->name, (const xmlChar *)"Publish")) {
                    publish = 1;
                } else if (xmlStrEqual(curNode->name, (const xmlChar *)"ResourceRecord")) {
                    resourcerecord = (char *) xmlNodeGetContent(curNode);
                }
                curNode = curNode->next;
            }
            if (!algorithm)
                configerr = 1;
            if (!flags)
                configerr = 1;
            if (!locator && !resourcerecord)
                configerr = 1;
            if (!configerr) {
                /* search for duplicates */
                new_key = keylist_lookup_by_locator(kl, locator);
                if (new_key &&
                    new_key->algorithm == (uint8_t) atoi(algorithm) &&
                    new_key->flags == (uint32_t) atoi(flags) &&
                    new_key->publish == publish &&
                    new_key->ksk == ksk &&
                    new_key->zsk == zsk) {
                    /* duplicate */
                    ods_log_warning("[%s] unable to push duplicate key %s "
                        "to keylist, skipping", parser_str, locator);
                } else {
                    (void) keylist_push(kl, locator, resourcerecord,
                        (uint8_t) atoi(algorithm), (uint32_t) atoi(flags),
                        publish, ksk, zsk);
                }
            } else {
                ods_log_error("[%s] unable to push key to keylist: <Key> "
                    "is missing required elements, skipping",
                    parser_str);
            }
            free((void*)algorithm);
            free((void*)flags);
        }
    }
    xmlXPathFreeObject(xpathObj);
    xmlXPathFreeContext(xpathCtx);
    if (doc) {
        xmlFreeDoc(doc);
    }
    return kl;
}
Exemple #23
0
/**
 * Interface.
 *
 */
static int
interface_run(FILE* fp, int sockfd, char* cmd)
{
    int maxfdp1 = 0;
    int stdineof = 0;
    int i = 0;
    int n = 0;
    int ret = 0;
    int cmd_written = 0;
    int cmd_response = 0;
    fd_set rset;
    char buf[ODS_SE_MAXLINE];
    int written;

    stdineof = 0;
    FD_ZERO(&rset);
    for(;;) {
        /* prepare */
        if (stdineof == 0) {
            FD_SET(fileno(fp), &rset);
        }
        FD_SET(sockfd, &rset);
        maxfdp1 = max(fileno(fp), sockfd) + 1;

        if (!cmd || cmd_written) {
            /* interactive mode */
            ret = select(maxfdp1, &rset, NULL, NULL, NULL);
            if (ret < 0) {
                if (errno != EINTR && errno != EWOULDBLOCK) {
                    ods_log_warning("[%s] interface select error: %s",
                        cli_str, strerror(errno));
                }
                continue;
            }
        } else if (cmd) {
            /* passive mode */
            ods_writen(sockfd, cmd, strlen(cmd));
            cmd_written = 1;
            stdineof = 1;
            /* Clear the interactive mode / stdin fd from the set */
            FD_CLR(fileno(fp), &rset);
            continue;
        }

        if (cmd && cmd_written && cmd_response) {
            /* normal termination */
            return 0;
        }

        if (FD_ISSET(sockfd, &rset)) {
            /* clear buffer */
            for (i=0; i < ODS_SE_MAXLINE; i++) {
                buf[i] = 0;
            }
            buf[ODS_SE_MAXLINE-1] = '\0';

            /* socket is readable */
            if ((n = read(sockfd, buf, ODS_SE_MAXLINE)) <= 0) {
                if (n < 0) {
                    /* error occurred */
                    fprintf(stderr, "error: %s\n", strerror(errno));
                    return 1;
                } else {
                    /* n==0 */
                    if (stdineof == 1) {
                        /* normal termination */
                        return 0;
                    } else {
                        /* weird termination */
                        fprintf(stderr, "enforcer engine terminated "
                                "prematurely\n");
                        return 1;
                    }
                }
            }

            if (cmd) {
                if (n < SE_CLI_CMDLEN) {
                    /* not enough data received */
                    fprintf(stderr, "not enough response data received "
                            "from daemon.\n");
                    return 1;
                }
                
                /* n >= SE_CLI_CMDLEN : and so it is safe to do buffer 
                    manipulations below. */
                if (strncmp(buf+n-SE_CLI_CMDLEN,"\ncmd> ",SE_CLI_CMDLEN) == 0) {
                
                    /* we have the full response */
                    n -= SE_CLI_CMDLEN;
                    buf[n] = '\0';
                    cmd_response = 1;
                }
            }

            /* n > 0 : when we get to this line... */
            for (written=0; written < n; written += ret) {
                /* write what we got to stdout */
                ret = (int) write(fileno(stdout), &buf[written], n-written);
                /* error and shutdown handling */
                if (ret == 0) {
                    fprintf(stderr, "no write\n");
                    break;
                }
                if (ret < 0) {
                    if (errno == EINTR || errno == EWOULDBLOCK) {
                        ret = 0;
                        continue; /* try again... */
                    }
                    fprintf(stderr, "\n\nwrite error: %s\n", strerror(errno));
                    break;
                }
                /* ret > 0 : when we get here... */
                if (written+ret > n) {
                    fprintf(stderr, "\n\nwrite error: more bytes (%d) written than required (%d)\n", written+ret, n);
                    break;
                }
                /* written+ret < n : means partial write, requires us to loop... */
            }
            if (ods_strcmp(buf, ODS_SE_STOP_RESPONSE) == 0 ) {
                /* we do no further reading, flush */
                write(fileno(stdout), "\n", 1);
                return 0;
            } else if (cmd_response) return 0;
        }

        if (FD_ISSET(fileno(fp), &rset)) {
            /* input is readable */

            if (cmd && cmd_written) {
                /* passive mode */
                stdineof = 1;
                ret = shutdown(sockfd, SHUT_WR);
                if (ret != 0) {
                    fprintf(stderr, "shutdown failed: %s\n",
                        strerror(errno));
                    return 1;
                }
                FD_CLR(fileno(fp), &rset);
                continue;
            }

            /* clear buffer */
            for (i=0; i< ODS_SE_MAXLINE; i++) {
                buf[i] = 0;
            }

            /* interactive mode */
            if ((n = read(fileno(fp), buf, ODS_SE_MAXLINE)) == 0) {
                stdineof = 1;
                ret = shutdown(sockfd, SHUT_WR);
                if (ret != 0) {
                    fprintf(stderr, "shutdown failed: %s\n",
                        strerror(errno));
                    return 1;
                }
                FD_CLR(fileno(fp), &rset);
                continue;
            }
            if (strncmp(buf, "exit", 4) == 0 ||
                strncmp(buf, "quit", 4) == 0) {
                return 0;
            }
            ods_str_trim(buf);
            n = strlen(buf);
            ods_writen(sockfd, buf, n);
        }
    }
}
/**
 * Recover zone from backup.
 *
 */
ods_status
zone_recover2(zone_type* zone)
{
    char* filename = NULL;
    FILE* fd = NULL;
    const char* token = NULL;
    time_t when = 0;
    task_type* task = NULL;
    ods_status status = ODS_STATUS_OK;
    /* zone part */
    int klass = 0;
    uint32_t inbound = 0, internal = 0, outbound = 0;
    /* signconf part */
    time_t lastmod = 0;
    /* nsec3params part */
    const char* salt = NULL;

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

    filename = ods_build_path(zone->name, ".backup2", 0, 1);
    if (!filename) {
        return ODS_STATUS_MALLOC_ERR;
    }
    fd = ods_fopen(filename, NULL, "r");
    if (fd) {
        /* start recovery */
        if (!backup_read_check_str(fd, ODS_SE_FILE_MAGIC_V3)) {
            ods_log_error("[%s] corrupted backup file zone %s: read magic "
                "error", zone_str, zone->name);
            goto recover_error2;
        }
        if (!backup_read_check_str(fd, ";;Time:") |
            !backup_read_time_t(fd, &when)) {
            ods_log_error("[%s] corrupted backup file zone %s: read time "
                "error", zone_str, zone->name);
            goto recover_error2;
        }
        /* zone stuff */
        if (!backup_read_check_str(fd, ";;Zone:") |
            !backup_read_check_str(fd, "name") |
            !backup_read_check_str(fd, zone->name)) {
            ods_log_error("[%s] corrupted backup file zone %s: read name "
                "error", zone_str, zone->name);
            goto recover_error2;
        }
        if (!backup_read_check_str(fd, "class") |
            !backup_read_int(fd, &klass)) {
            ods_log_error("[%s] corrupted backup file zone %s: read class "
                "error", zone_str, zone->name);
            goto recover_error2;
        }
        if (!backup_read_check_str(fd, "inbound") |
            !backup_read_uint32_t(fd, &inbound) |
            !backup_read_check_str(fd, "internal") |
            !backup_read_uint32_t(fd, &internal) |
            !backup_read_check_str(fd, "outbound") |
            !backup_read_uint32_t(fd, &outbound)) {
            ods_log_error("[%s] corrupted backup file zone %s: read serial "
                "error", zone_str, zone->name);
            goto recover_error2;
        }
        zone->klass = (ldns_rr_class) klass;
        zone->db->inbserial = inbound;
        zone->db->intserial = internal;
        zone->db->outserial = outbound;
        /* signconf part */
        if (!backup_read_check_str(fd, ";;Signconf:") |
            !backup_read_check_str(fd, "lastmod") |
            !backup_read_time_t(fd, &lastmod) |
            !backup_read_check_str(fd, "maxzonettl") |
            !backup_read_check_str(fd, "0") |
            !backup_read_check_str(fd, "resign") |
            !backup_read_duration(fd, &zone->signconf->sig_resign_interval) |
            !backup_read_check_str(fd, "refresh") |
            !backup_read_duration(fd, &zone->signconf->sig_refresh_interval) |
            !backup_read_check_str(fd, "valid") |
            !backup_read_duration(fd, &zone->signconf->sig_validity_default) |
            !backup_read_check_str(fd, "denial") |
            !backup_read_duration(fd,&zone->signconf->sig_validity_denial) |
            !backup_read_check_str(fd, "jitter") |
            !backup_read_duration(fd, &zone->signconf->sig_jitter) |
            !backup_read_check_str(fd, "offset") |
            !backup_read_duration(fd, &zone->signconf->sig_inception_offset) |
            !backup_read_check_str(fd, "nsec") |
            !backup_read_rr_type(fd, &zone->signconf->nsec_type) |
            !backup_read_check_str(fd, "dnskeyttl") |
            !backup_read_duration(fd, &zone->signconf->dnskey_ttl) |
            !backup_read_check_str(fd, "soattl") |
            !backup_read_duration(fd, &zone->signconf->soa_ttl) |
            !backup_read_check_str(fd, "soamin") |
            !backup_read_duration(fd, &zone->signconf->soa_min) |
            !backup_read_check_str(fd, "serial") |
            !backup_read_str(fd, &zone->signconf->soa_serial)) {
            ods_log_error("[%s] corrupted backup file zone %s: read signconf "
                "error", zone_str, zone->name);
            goto recover_error2;
        }
        /* nsec3params part */
        if (zone->signconf->nsec_type == LDNS_RR_TYPE_NSEC3) {
            if (!backup_read_check_str(fd, ";;Nsec3parameters:") |
                !backup_read_check_str(fd, "salt") |
                !backup_read_str(fd, &salt) |
                !backup_read_check_str(fd, "algorithm") |
                !backup_read_uint32_t(fd, &zone->signconf->nsec3_algo) |
                !backup_read_check_str(fd, "optout") |
                !backup_read_int(fd, &zone->signconf->nsec3_optout) |
                !backup_read_check_str(fd, "iterations") |
                !backup_read_uint32_t(fd, &zone->signconf->nsec3_iterations)) {
                ods_log_error("[%s] corrupted backup file zone %s: read "
                    "nsec3parameters error", zone_str, zone->name);
                goto recover_error2;
            }
            zone->signconf->nsec3_salt = allocator_strdup(
                zone->signconf->allocator, salt);
            free((void*) salt);
            salt = NULL;
            zone->signconf->nsec3params = nsec3params_create(
                (void*) zone->signconf,
                (uint8_t) zone->signconf->nsec3_algo,
                (uint8_t) zone->signconf->nsec3_optout,
                (uint16_t) zone->signconf->nsec3_iterations,
                zone->signconf->nsec3_salt);
            if (!zone->signconf->nsec3params) {
                ods_log_error("[%s] corrupted backup file zone %s: unable to "
                    "create nsec3param", zone_str, zone->name);
                goto recover_error2;
            }
        }
        zone->signconf->last_modified = lastmod;
        zone->default_ttl = (uint32_t) duration2time(zone->signconf->soa_min);
        /* keys part */
        zone->signconf->keys = keylist_create((void*) zone->signconf);
        while (backup_read_str(fd, &token)) {
            if (ods_strcmp(token, ";;Key:") == 0) {
                if (!key_recover2(fd, zone->signconf->keys)) {
                    ods_log_error("[%s] corrupted backup file zone %s: read "
                        "key error", zone_str, zone->name);
                    goto recover_error2;
                }
            } else if (ods_strcmp(token, ";;") == 0) {
                /* keylist done */
                free((void*) token);
                token = NULL;
                break;
            } else {
                /* keylist corrupted */
                goto recover_error2;
            }
            free((void*) token);
            token = NULL;
        }
        /* publish dnskeys */
        status = zone_publish_dnskeys(zone);
        if (status != ODS_STATUS_OK) {
            ods_log_error("[%s] corrupted backup file zone %s: unable to "
                "publish dnskeys (%s)", zone_str, zone->name,
                ods_status2str(status));
            goto recover_error2;
        }
        /* publish nsec3param */
        status = zone_publish_nsec3param(zone);
        if (status != ODS_STATUS_OK) {
            ods_log_error("[%s] corrupted backup file zone %s: unable to "
                "publish nsec3param (%s)", zone_str, zone->name,
                ods_status2str(status));
            goto recover_error2;
        }
        /* publish other records */
        status = backup_read_namedb(fd, zone);
        if (status != ODS_STATUS_OK) {
            ods_log_error("[%s] corrupted backup file zone %s: unable to "
                "read resource records (%s)", zone_str, zone->name,
                ods_status2str(status));
            goto recover_error2;
        }
        /* task */
        task = task_create(TASK_SIGN, when, (void*) zone);
        if (!task) {
            ods_log_error("[%s] failed to restore zone %s: unable to "
                "create task", zone_str, zone->name);
            goto recover_error2;
        }
        zone->task = (void*) task;
        free((void*)filename);
        ods_fclose(fd);
        /* journal */
        zone->db->is_initialized = 1;

        filename = ods_build_path(zone->name, ".ixfr", 0, 1);
        if (filename) {
            fd = ods_fopen(filename, NULL, "r");
        }
        if (fd) {
            status = backup_read_ixfr(fd, zone);
            if (status != ODS_STATUS_OK) {
                ods_log_warning("[%s] corrupted journal file zone %s, "
                    "skipping (%s)", zone_str, zone->name,
                    ods_status2str(status));
                ixfr_cleanup(zone->ixfr);
                zone->ixfr = ixfr_create((void*)zone);
            }
        }
        lock_basic_lock(&zone->ixfr->ixfr_lock);
        ixfr_purge(zone->ixfr);
        lock_basic_unlock(&zone->ixfr->ixfr_lock);

        /* all ok */
        free((void*)filename);
        ods_fclose(fd);
        if (zone->stats) {
            lock_basic_lock(&zone->stats->stats_lock);
            stats_clear(zone->stats);
            lock_basic_unlock(&zone->stats->stats_lock);
        }
        return ODS_STATUS_OK;
    }
    return ODS_STATUS_UNCHANGED;

recover_error2:
    free((void*)filename);
    ods_fclose(fd);
    /* signconf cleanup */
    free((void*)salt);
    salt = NULL;
    signconf_cleanup(zone->signconf);
    zone->signconf = signconf_create();
    ods_log_assert(zone->signconf);
    /* namedb cleanup */
    namedb_cleanup(zone->db);
    zone->db = namedb_create((void*)zone);
    ods_log_assert(zone->db);
    /* stats reset */
    if (zone->stats) {
       lock_basic_lock(&zone->stats->stats_lock);
       stats_clear(zone->stats);
       lock_basic_unlock(&zone->stats->stats_lock);
    }
    return ODS_STATUS_ERR;
}
Exemple #25
0
static time_t
perform_enforce(int sockfd, engine_type *engine, int bForceUpdate,
	task_type* task, db_connection_t *dbconn)
{
	zone_list_t *zonelist = NULL;
	zone_t *zone, *firstzone = NULL;
	policy_t *policy;
	key_data_list_t *keylist;
	const key_data_t *key;
	time_t t_next, t_now = time_now(), t_reschedule = -1;
	/* Flags that indicate tasks to be scheduled after zones have been
	 * enforced. */
	int bSignerConfNeedsWriting = 0;
	int bSubmitToParent = 0;
	int bRetractFromParent = 0;
	int zone_updated;

	if (!(zonelist = zone_list_new(dbconn))
		/*|| zone_list_associated_fetch(zonelist)*/
		|| zone_list_get(zonelist))
	{
		zone_list_free(zonelist);
		zonelist = NULL;
	}
	if (!zonelist) {
		/* TODO: log error */
		ods_log_error("[%s] zonelist NULL", module_str);
		/* TODO: backoff? */
		return t_reschedule;
	}

	for (zone = zone_list_get_next(zonelist); zone;
		zone_free(zone), zone = zone_list_get_next(zonelist))
	{
		if (engine->need_to_reload || engine->need_to_exit) break;

		if (!bForceUpdate && (zone_next_change(zone) == -1)) {
			continue;
		} else if (zone_next_change(zone) > t_now && !bForceUpdate) {
			/* This zone needs no update, however it might be the first
			 * for future updates */
			if (zone_next_change(zone) < t_reschedule || !firstzone)
			{
				t_reschedule = zone_next_change(zone);
				if (firstzone) {
					zone_free(firstzone);
				}
				firstzone = zone;
				zone = NULL; /* keeps firstzone from being freed. */
			}
			continue;
		}
		if (!(policy = zone_get_policy(zone))) {
			client_printf(sockfd,
				"Next update for zone %s NOT scheduled "
				"because policy is missing !\n", zone_name(zone));
			if (zone_next_change(zone) != -1
				&& (zone_set_next_change(zone, -1)
					|| zone_update(zone)))
			{
				/* TODO: Log error */
			}
			continue;
		}

		if (policy_passthrough(policy)) {
			ods_log_info("Passing through zone %s.\n", zone_name(zone));
			zone_set_signconf_needs_writing(zone, 1);
			zone_update(zone);
			bSignerConfNeedsWriting = 1;
			policy_free(policy);
			continue;
		}

		zone_updated = 0;
		t_next = update(engine, dbconn, zone, policy, t_now, &zone_updated);
		policy_free(policy);
		bSignerConfNeedsWriting |= zone_signconf_needs_writing(zone);

		keylist = zone_get_keys(zone);
		while ((key = key_data_list_next(keylist))) {
			if (key_data_ds_at_parent(key) == KEY_DATA_DS_AT_PARENT_SUBMIT) {
				ods_log_warning("[%s] please submit DS "
					"with keytag %d for zone %s",
					module_str, key_data_keytag(key)&0xFFFF, zone_name(zone));
				bSubmitToParent = 1;
			} else if (key_data_ds_at_parent(key) == KEY_DATA_DS_AT_PARENT_RETRACT) {
				ods_log_warning("[%s] please retract DS "
					"with keytag %d for zone %s",
					module_str, key_data_keytag(key)&0xFFFF, zone_name(zone));
				bRetractFromParent = 1;
			}
		}
		key_data_list_free(keylist);

		if (t_next == -1) {
			client_printf(sockfd,
				"Next update for zone %s NOT scheduled "
				"by enforcer !\n", zone_name(zone));
			ods_log_debug("Next update for zone %s NOT scheduled "
				"by enforcer !\n", zone_name(zone));
		} else {
			/* Invalid schedule time then skip the zone.*/
			char tbuf[32] = "date/time invalid\n"; /* at least 26 bytes */
			ctime_r(&t_next, tbuf); /* note that ctime_r inserts \n */
			client_printf(sockfd,
				"Next update for zone %s scheduled at %s",
				zone_name(zone), tbuf);
			ods_log_debug("Next update for zone %s scheduled at %s",
				zone_name(zone), tbuf);
		}
		if (zone_next_change(zone) != t_next) {
			zone_set_next_change(zone, t_next);
			zone_updated = 1;
		}

		/*
		 * Commit the changes to the zone if there where any.
		 */
		if (zone_updated) {
			if (zone_update(zone)) {
				ods_log_debug("[%s] error zone_update(%s)", module_str, zone_name(zone));
			}
		}

		/*
		 * Find out when to schedule the next change.
		 */
		if (zone_next_change(zone) != -1
			&& (zone_next_change(zone) < t_reschedule
				|| !firstzone))
		{
			t_reschedule = zone_next_change(zone);
			if (firstzone) {
				zone_free(firstzone);
			}
			firstzone = zone;
			zone = NULL;
		}
	}
	zone_list_free(zonelist);

	/*
	 * Schedule the next change if needed.
	 */
	if (firstzone) {
		reschedule_enforce(task, t_reschedule, zone_name(firstzone));
		zone_free(firstzone);
	}

	/* Launch signer configuration writer task when one of the
	 * zones indicated that it needs to be written.
	 * TODO: unschedule it first!
	 */
	if (bSignerConfNeedsWriting) {
		task_type *signconf =
			signconf_task(dbconn, "signconf", "signer configurations");
		enf_schedule_task(sockfd,engine,signconf,"signconf");
	} else {
		ods_log_info("[%s] No changes to any signconf file required", module_str);
	}

	/* Launch ds-submit task when one of the updated key states has the
	 * DS_SUBMIT flag set. */
	if (bSubmitToParent) {
		task_type *submit =
			keystate_ds_submit_task(engine);
		enf_schedule_task(sockfd, engine, submit, "ds-submit");
	}


	/* Launch ds-retract task when one of the updated key states has the
	 * DS_RETRACT flag set. */
	if (bRetractFromParent) {
		task_type *retract =
			keystate_ds_retract_task(engine);
		enf_schedule_task(sockfd, engine, retract, "ds-retract");
	}


	return t_reschedule;
}
Exemple #26
0
/**
 * Process RR.
 *
 */
static ods_status
adapi_process_rr(zone_type* zone, ldns_rr* rr, int add, int backup)
{
    ods_status status = ODS_STATUS_OK;
    uint32_t tmp = 0;
    ods_log_assert(rr);
    ods_log_assert(zone);
    ods_log_assert(zone->name);
    ods_log_assert(zone->db);
    ods_log_assert(zone->signconf);
    /* We only support IN class */
    if (ldns_rr_get_class(rr) != LDNS_RR_CLASS_IN) {
        ods_log_warning("[%s] only class in is supported, changing class "
            "to in", adapi_str);
        ldns_rr_set_class(rr, LDNS_RR_CLASS_IN);
    }
    /* RR processing */
    if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_SOA) {
        if (ldns_dname_compare(ldns_rr_owner(rr), zone->apex)) {
            ods_log_error("[%s] unable to %s rr to zone: soa record has "
                "invalid owner name", adapi_str, add?"add":"delete");
            return ODS_STATUS_ERR;
        }
        status = adapi_process_soa(zone, rr, add, backup);
        if (status != ODS_STATUS_OK) {
            ods_log_error("[%s] unable to %s rr: failed to process soa "
                "record", adapi_str, add?"add":"delete");
            return status;
        }
    } else {
        if (ldns_dname_compare(ldns_rr_owner(rr), zone->apex) &&
            !ldns_dname_is_subdomain(ldns_rr_owner(rr), zone->apex)) {
            ods_log_warning("[%s] zone %s contains out-of-zone data, "
                "skipping", adapi_str, zone->name);
            return ODS_STATUS_UNCHANGED;
        } else if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_DNSKEY) {
            adapi_process_dnskey(zone, rr);
        } else if (util_is_dnssec_rr(rr) && !backup) {
            ods_log_warning("[%s] zone %s contains dnssec data (type=%u), "
                "skipping", adapi_str, zone->name,
                (unsigned) ldns_rr_get_type(rr));
            return ODS_STATUS_UNCHANGED;
        } else if (zone->signconf->max_zone_ttl) {
            /* Convert MaxZoneTTL */
            tmp = (uint32_t) duration2time(zone->signconf->max_zone_ttl);
        }
    }
    /* //MaxZoneTTL. Only set for RRtype != SOA && RRtype != DNSKEY */
    if (tmp && tmp < ldns_rr_ttl(rr)) {
        char* str = ldns_rdf2str(ldns_rr_owner(rr));
        if (str) {
            size_t i = 0;
            str[(strlen(str))-1] = '\0';
            /* replace tabs with white space */
            for (i=0; i < strlen(str); i++) {
                if (str[i] == '\t') {
                    str[i] = ' ';
                }
            }
            ods_log_debug("[%s] capping ttl %u to MaxZoneTTL %u for rrset "
                "<%s,%s>", adapi_str, ldns_rr_ttl(rr), tmp, str,
                rrset_type2str(ldns_rr_get_type(rr)));
        }
        ldns_rr_set_ttl(rr, tmp);
    }

    /* TODO: DNAME and CNAME checks */
    /* TODO: NS and DS checks */

    if (add) {
        return zone_add_rr(zone, rr, 1);
    } else {
        return zone_del_rr(zone, rr, 1);
    }
    /* not reached */
    return ODS_STATUS_ERR;
}
Exemple #27
0
/**
 * Run engine, run!.
 *
 */
static void
engine_run(engine_type* engine, start_cb_t start, int single_run)
{
    if (!engine) {
        return;
    }
    ods_log_assert(engine);

    engine_start_workers(engine);
    engine_start_drudgers(engine);

    lock_basic_lock(&engine->signal_lock);
    /* [LOCK] signal */
    engine->signal = SIGNAL_RUN;
    /* [UNLOCK] signal */
    lock_basic_unlock(&engine->signal_lock);

    /* call the external start callback function */
    start(engine);
    
    while (!engine->need_to_exit && !engine->need_to_reload) {
        lock_basic_lock(&engine->signal_lock);
        /* [LOCK] signal */
        engine->signal = signal_capture(engine->signal);
        switch (engine->signal) {
            case SIGNAL_RUN:
                ods_log_assert(1);
                break;
            case SIGNAL_RELOAD:
                engine->need_to_reload = 1;
                break;
            case SIGNAL_SHUTDOWN:
                engine->need_to_exit = 1;
                break;
            default:
                ods_log_warning("[%s] invalid signal captured: %d, "
                    "keep running", engine_str, signal);
                engine->signal = SIGNAL_RUN;
                break;
        }
        /* [UNLOCK] signal */
        lock_basic_unlock(&engine->signal_lock);

        if (single_run) {
            engine->need_to_exit = 1;
            /* FIXME: all tasks need to terminate, then set need_to_exit to 1 */
        }

        lock_basic_lock(&engine->signal_lock);
        /* [LOCK] signal */
        if (engine->signal == SIGNAL_RUN && !single_run) {
           ods_log_debug("[%s] taking a break", engine_str);
           lock_basic_sleep(&engine->signal_cond, &engine->signal_lock, 3600);
        }
        /* [UNLOCK] signal */
        lock_basic_unlock(&engine->signal_lock);
    }
    ods_log_debug("[%s] enforcer halted", engine_str);
    engine_stop_drudgers(engine);
    engine_stop_workers(engine);
    return;
}
Exemple #28
0
static int
run(int sockfd, engine_type* engine, const char *cmd, ssize_t n,
	db_connection_t *dbconn) {
    char buf[ODS_SE_MAXLINE];
#define NARGV 12
    const char *argv[NARGV];
    int success, argIndex;
    int argc, bVerbose, bDebug, bParsable, bAll;
    char* keytypeParam;
    char* keystateParam;
    const char* filterZone; /* NULL if no filtering on zone, otherwise zone to match */
    char** filterKeytype; /* NULL if no filtering on key type, NULL terminated list of key types to filter */
    char** filterKeystate; /* NULL if no filtering on key state, NULL terminated list of key states to filter */
    (void) engine;

    ods_log_debug("[%s] %s command", module_str, key_list_funcblock()->cmdname);

    cmd = ods_check_command(cmd, n, key_list_funcblock()->cmdname);
    /* Use buf as an intermediate buffer for the command. */
    strncpy(buf, cmd, sizeof (buf));
    buf[sizeof (buf) - 1] = '\0';

    /* separate the arguments */
    argc = ods_str_explode(buf, NARGV, argv);
    if (argc > NARGV) {
        ods_log_warning("[%s] too many arguments for %s command",
                module_str, key_list_funcblock()->cmdname);
        client_printf(sockfd, "too many arguments\n");
        return -1;
    }

    bVerbose = ods_find_arg(&argc, argv, "verbose", "v") != -1;
    bDebug = ods_find_arg(&argc, argv, "debug", "d") != -1;
    bParsable = ods_find_arg(&argc, argv, "parsable", "p") != -1;
    if ((argIndex = ods_find_arg_and_param(&argc, argv, "zone", "z", &filterZone)) == -1) {
        filterZone = NULL;
    }
    if (ods_find_arg_and_param(&argc, argv, "keytype", "k", (const char **)&keytypeParam) == -1) {
        keytypeParam = NULL;
    }
    if (ods_find_arg_and_param(&argc, argv, "keystate", "e", (const char **)&keystateParam) == -1) {
        keystateParam = NULL;
    }

    bAll = (ods_find_arg(&argc, argv, "all", "a") != -1);

    if (keystateParam != NULL && bAll) {
        client_printf(sockfd, "Error: --keystate and --all option cannot be given together\n");
        return -1;
    }

    if (argc) {
        ods_log_warning("[%s] unknown arguments for %s command", module_str, key_list_funcblock()->cmdname);
        client_printf(sockfd, "unknown arguments\n");
        return -1;
    }

    if (keytypeParam)
        filterKeytype = tokenizeparam(keytypeParam);
    else
        filterKeytype = NULL;
    if (keystateParam) {
        filterKeystate = tokenizeparam(keystateParam);
    } else
        filterKeystate = NULL;
    if (bAll) {
        if (filterKeystate != NULL) {
            free(filterKeystate);
        }
        filterKeystate = NULL;
    } else if(filterKeystate == NULL) {
        if ((filterKeystate = malloc(sizeof (char*) * 6))) {
            filterKeystate[0] = (char *)"publish";
            filterKeystate[1] = (char *)"ready";
            filterKeystate[2] = (char *)"active";
            filterKeystate[3] = (char *)"retire";
            filterKeystate[4] = (char *)"mixed";
            filterKeystate[5] = NULL;
        } /* else emit error */
    }

    if (bDebug) {
        if (bParsable) {
            success = perform_keystate_list(sockfd, dbconn, filterZone, filterKeytype, filterKeystate, NULL, &printdebugparsablekey);
        } else {
            success = perform_keystate_list(sockfd, dbconn, filterZone, filterKeytype, filterKeystate, &printdebugheader, &printdebugkey);
        }
    } else if (bVerbose) {
        if (bParsable) {
            success = perform_keystate_list(sockfd, dbconn, filterZone, filterKeytype, filterKeystate, NULL, &printverboseparsablekey);
        } else {
            success = perform_keystate_list(sockfd, dbconn, filterZone, filterKeytype, filterKeystate, &printverboseheader, &printverbosekey);
        }
    } else {
        success = perform_keystate_list(sockfd, dbconn, filterZone, filterKeytype, filterKeystate, &printcompatheader, &printcompatkey);
    }

    if (filterKeytype)
        free(filterKeytype);
    if (filterKeystate)
        free(filterKeystate);
    return success;
}