Beispiel #1
0
void 
engine_runloop(engine_type* engine, start_cb_t start, int single_run)
{
    /* run */
    while (engine->need_to_exit == 0) {
        
        if (engine->need_to_reload) {
            ods_log_info("[%s] enforcer reloading", engine_str);
            engine->need_to_reload = 0;
        } else {
            ods_log_info("[%s] enforcer started", engine_str);
            /* try to recover from backups */
            /* not for now:
             engine_recover_from_backups(engine);
             */
        }
        
        engine_run(engine, start, single_run);
    }
    
    /* shutdown */
    ods_log_info("[%s] enforcer shutdown", engine_str);
    hsm_close();
    if (engine->cmdhandler != NULL) {
        engine_stop_cmdhandler(engine);
    }
}
static int
run(int sockfd, cmdhandler_ctx_type* context, const char *cmd)
{
    db_connection_t* dbconn = getconnectioncontext(context);
    engine_type* engine = getglobalcontext(context);
    (void)cmd;

    if (!engine) {
        return 1;
    }
    if (!engine->config) {
        return 1;
    }
    if (!engine->config->zonelist_filename) {
        return 1;
    }
    if (!dbconn) {
        return 1;
    }

    ods_log_debug("[%s] %s command", module_str, zonelist_export_funcblock.cmdname);

    if (zonelist_export(sockfd, dbconn, engine->config->zonelist_filename, 1) != ZONELIST_EXPORT_OK) {
        ods_log_error("[%s] zonelist exported to %s failed", module_str, engine->config->zonelist_filename);
        client_printf_err(sockfd, "Exported zonelist to %s failed!\n", engine->config->zonelist_filename);
        return 1;
    }

    ods_log_info("[%s] zonelist exported to %s successfully", module_str, engine->config->zonelist_filename);
    client_printf(sockfd, "Exported zonelist to %s successfully\n", engine->config->zonelist_filename);
    return 0;
}
Beispiel #3
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;
	}
}
/**
 * Open HSM.
 *
 */
int
lhsm_open(const char* filename)
{
    int result = hsm_open(filename, hsm_check_pin);
    if (result != HSM_OK) {
        char* error =  hsm_get_error(NULL);
        if (error != NULL) {
            ods_log_error("[%s] %s", hsm_str, error);
            free(error);
        } else {
            ods_log_crit("[%s] error opening libhsm (errno %i)", hsm_str,
                         result);
        }
        /* exit? */
    } else {
        ods_log_info("[%s] libhsm connection opened succesfully", hsm_str);
    }
    return result;
}
Beispiel #5
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;
}
/**
 * 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;
}
Beispiel #7
0
static int
run(int sockfd, cmdhandler_ctx_type* context, const char *cmd)
{
    #define NARGV 6
    char* buf;
    const char* argv[NARGV];
    int argc = 0;
    const char *zone_name2 = NULL;
    int all = 0;
    int write_xml = 0;
    int long_index = 0, opt = 0;
    zone_list_db_t* zone_list;
    zone_db_t* zone;
    int ret = 0;
    char path[PATH_MAX];
    char *signconf_del = NULL;
    db_connection_t* dbconn = getconnectioncontext(context);;
    engine_type* engine = getglobalcontext(context);

    static struct option long_options[] = {
        {"zone", required_argument, 0, 'z'},
        {"all", no_argument, 0, 'a'},
        {"xml", no_argument, 0, 'u'},
        {0, 0, 0, 0}
    };

    ods_log_debug("[%s] %s command", module_str, zone_del_funcblock.cmdname);

    if (!(buf = strdup(cmd))) {
        client_printf_err(sockfd, "memory error\n");
        return -1;
    }

    argc = ods_str_explode(buf, NARGV, argv);
    if (argc == -1) {
        client_printf_err(sockfd, "too many arguments\n");
        ods_log_error("[%s] too many arguments for %s command",
                      module_str, zone_del_funcblock.cmdname);
        free(buf);
        return -1;
    }

    optind = 0;
    while ((opt = getopt_long(argc, (char* const*)argv, "z:au", long_options, &long_index)) != -1) {
        switch (opt) {
            case 'z':
                zone_name2 = optarg;
                break;
            case 'a':
                all = 1;
                break;
            case 'u':
                write_xml = 1;
                break;
           default:
               client_printf_err(sockfd, "unknown arguments\n");
               ods_log_error("[%s] unknown arguments for %s command",
                                module_str, zone_del_funcblock.cmdname);
               free(buf);
               return -1;
        }
    }

    if (zone_name2 && !all) {
        if (!(zone = zone_db_new_get_by_name(dbconn, zone_name2))) {
            client_printf_err(sockfd, "Unable to delete zone, zone %s not found!\n", zone_name2);
            free(buf);
            return 1;
        }

        if (!delete_key_data(zone, dbconn, sockfd)) {
            zone_db_free(zone);
            free(buf);
            return 1;
        }
        if (zone_db_delete(zone)) {
            client_printf_err(sockfd, "Unable to delete zone %s from database!\n", zone_name2);
            zone_db_free(zone);
            free(buf);
            return 1;
        }
        signconf_del = (char*) calloc(strlen(zone_db_signconf_path(zone)) +
            strlen(".ZONE_DELETED") + 1, sizeof(char));
        if (!signconf_del) {
            ods_log_error("[%s] malloc failed", module_str);
            zone_db_free(zone);
            free(buf);
            return 1;
        }
        strncpy(signconf_del, zone_db_signconf_path(zone), strlen(zone_db_signconf_path(zone)));
        strncat(signconf_del, ".ZONE_DELETED", strlen(".ZONE_DELETED"));
        rename(zone_db_signconf_path(zone), signconf_del);
        free(signconf_del);
        signconf_del = NULL;

        /* Delete all 'zone' related tasks */
        schedule_purge_owner(engine->taskq, TASK_CLASS_ENFORCER, zone_name2);

        ods_log_info("[%s] zone %s deleted", module_str, zone_name2);
        client_printf(sockfd, "Deleted zone %s successfully\n", zone_name2);
    } else if (!zone_name2 && all) {
        if (!(zone_list = zone_list_db_new_get(dbconn))) {
            client_printf_err(sockfd, "Unable to get list of zones from database!\n");
            free(buf);
            return 1;
        }
        for (zone = zone_list_db_get_next(zone_list); zone; zone_db_free(zone), zone = zone_list_db_get_next(zone_list)) {
            if (!delete_key_data(zone, dbconn, sockfd)) {
                continue;
            }
            if (zone_db_delete(zone)) {
                client_printf_err(sockfd, "Unable to delete zone %s from database!\n", zone_db_name(zone));
                continue;
            }

            signconf_del = (char*) calloc(strlen(zone_db_signconf_path(zone)) +
                strlen(".ZONE_DELETED") + 1, sizeof(char));
            if (!signconf_del) {
                ods_log_error("[%s] malloc failed", module_str);
                zone_db_free(zone);
                zone_list_db_free(zone_list);
                free(buf);
                return 1;
            }
            strncpy(signconf_del, zone_db_signconf_path(zone), strlen(zone_db_signconf_path(zone)));
            strncat(signconf_del, ".ZONE_DELETED", strlen(".ZONE_DELETED"));
            rename(zone_db_signconf_path(zone), signconf_del);
            free(signconf_del);
            signconf_del = NULL;

            /* Delete all 'zone' related tasks */
            schedule_purge_owner(engine->taskq, TASK_CLASS_ENFORCER, zone_db_name(zone));

            ods_log_info("[%s] zone %s deleted", module_str, zone_db_name(zone));
            client_printf(sockfd, "Deleted zone %s successfully\n", zone_db_name(zone));
        }
        zone_list_db_free(zone_list);
        zone = NULL;
        client_printf(sockfd, "All zones deleted successfully\n");
    } else {
        client_printf_err(sockfd, "expected either --zone <zone> or --all\n");
        free(buf);
        return -1;
    }
    free(buf);

    if (write_xml) {
        if (zone) {
            if (zonelist_update_delete(sockfd, engine->config->zonelist_filename, zone, 1) != ZONELIST_UPDATE_OK) {
                ods_log_error("[%s] zonelist %s updated failed", module_str, engine->config->zonelist_filename);
                client_printf_err(sockfd, "Zonelist %s update failed!\n", engine->config->zonelist_filename);
                ret = 1;
            } else {
                ods_log_info("[%s] zonelist %s updated successfully", module_str, engine->config->zonelist_filename);
                client_printf(sockfd, "Zonelist %s updated successfully\n", engine->config->zonelist_filename);
            }
        } else {
            if (zonelist_export(sockfd, dbconn, engine->config->zonelist_filename, 1) != ZONELIST_EXPORT_OK) {
                ods_log_error("[%s] zonelist exported to %s failed", module_str, engine->config->zonelist_filename);
                client_printf_err(sockfd, "Exported zonelist to %s failed!\n", engine->config->zonelist_filename);
                ret = 1;
            } else {
                ods_log_info("[%s] zonelist exported to %s successfully", module_str, engine->config->zonelist_filename);
                client_printf(sockfd, "Exported zonelist to %s successfully\n", engine->config->zonelist_filename);
            }
        }
    }

    if (zone) {
        if (snprintf(path, sizeof(path), "%s/%s", engine->config->working_dir, OPENDNSSEC_ENFORCER_ZONELIST) >= (int)sizeof(path)
            || zonelist_update_delete(sockfd, path, zone, 0) != ZONELIST_UPDATE_OK)
        {
            ods_log_error("[%s] internal zonelist update failed", module_str);
            client_printf_err(sockfd, "Unable to update the internal zonelist %s, updates will not reach the Signer!\n", path);
            ret = 1;
        } else {
            ods_log_info("[%s] internal zonelist updated successfully", module_str);
        }
    } else {
        if (snprintf(path, sizeof(path), "%s/%s", engine->config->working_dir, OPENDNSSEC_ENFORCER_ZONELIST) >= (int)sizeof(path)
            || zonelist_export(sockfd, dbconn, path, 0) != ZONELIST_EXPORT_OK)
        {
            ods_log_error("[%s] internal zonelist update failed", module_str);
            client_printf_err(sockfd, "Unable to update the internal zonelist %s, updates will not reach the Signer!\n", path);
            ret = 1;
        } else {
            ods_log_info("[%s] internal zonelist updated successfully", module_str);
        }
    }

    zone_db_free(zone);
    return ret;
}
/**
 * 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;
}
/**
 * NOTIFY.
 *
 */
static query_state
query_process_notify(query_type* q, ldns_rr_type qtype, void* engine)
{
    engine_type* e = (engine_type*) engine;
    dnsin_type* dnsin = NULL;
    uint16_t count = 0;
    uint16_t rrcount = 0;
    uint32_t serial = 0;
    size_t pos = 0;
    char address[128];
    if (!e || !q || !q->zone) {
        return QUERY_DISCARDED;
    }
    ods_log_assert(e->dnshandler);
    ods_log_assert(q->zone->name);
    ods_log_debug("[%s] incoming notify for zone %s", query_str,
        q->zone->name);
    if (buffer_pkt_rcode(q->buffer) != LDNS_RCODE_NOERROR ||
        buffer_pkt_qr(q->buffer) ||
        !buffer_pkt_aa(q->buffer) ||
        buffer_pkt_tc(q->buffer) ||
        buffer_pkt_rd(q->buffer) ||
        buffer_pkt_ra(q->buffer) ||
        buffer_pkt_ad(q->buffer) ||
        buffer_pkt_cd(q->buffer) ||
        buffer_pkt_qdcount(q->buffer) != 1 ||
        buffer_pkt_ancount(q->buffer) > 1 ||
        qtype != LDNS_RR_TYPE_SOA) {
        return query_formerr(q);
    }
    if (!q->zone->adinbound || q->zone->adinbound->type != ADAPTER_DNS) {
        ods_log_error("[%s] zone %s is not configured to have input dns "
            "adapter", query_str, q->zone->name);
        return query_notauth(q);
    }
    ods_log_assert(q->zone->adinbound->config);
    dnsin = (dnsin_type*) q->zone->adinbound->config;
    if (!acl_find(dnsin->allow_notify, &q->addr, q->tsig_rr)) {
        if (addr2ip(q->addr, address, sizeof(address))) {
            ods_log_info("[%s] unauthorized notify for zone %s from client %s: "
                "no acl matches", query_str, q->zone->name, address);
        } else {
            ods_log_info("[%s] unauthorized notify for zone %s from unknown "
                "client: no acl matches", query_str, q->zone->name);
        }
        return query_notauth(q);
    }
    ods_log_assert(q->zone->xfrd);
    /* skip header and question section */
    buffer_skip(q->buffer, BUFFER_PKT_HEADER_SIZE);
    count = buffer_pkt_qdcount(q->buffer);
    for (rrcount = 0; rrcount < count; rrcount++) {
        if (!buffer_skip_rr(q->buffer, 1)) {
            ods_log_error("[%s] dropped packet: zone %s received bad notify "
                "(bad question section)", query_str, q->zone->name);
            return QUERY_DISCARDED;
        }
    }
    pos = buffer_position(q->buffer);

    /* examine answer section */
    count = buffer_pkt_ancount(q->buffer);
    if (count) {
        if (!buffer_skip_dname(q->buffer) ||
            !query_parse_soa(q->buffer, &serial)) {
            ods_log_error("[%s] dropped packet: zone %s received bad notify "
                "(bad soa in answer section)", query_str, q->zone->name);
            return QUERY_DISCARDED;
        }
        lock_basic_lock(&q->zone->xfrd->serial_lock);
        q->zone->xfrd->serial_notify = serial;
        q->zone->xfrd->serial_notify_acquired = time_now();
        if (!util_serial_gt(q->zone->xfrd->serial_notify,
            q->zone->xfrd->serial_disk)) {
            ods_log_debug("[%s] ignore notify: already got zone %s serial "
                "%u on disk", query_str, q->zone->name,
                q->zone->xfrd->serial_notify);
            lock_basic_unlock(&q->zone->xfrd->serial_lock);
            goto send_notify_ok;
        }
        lock_basic_unlock(&q->zone->xfrd->serial_lock);
    } else {
        lock_basic_lock(&q->zone->xfrd->serial_lock);
        q->zone->xfrd->serial_notify = 0;
        q->zone->xfrd->serial_notify_acquired = 0;
        lock_basic_unlock(&q->zone->xfrd->serial_lock);
    }
    /* forward notify to xfrd */
    xfrd_set_timer_now(q->zone->xfrd);
    dnshandler_fwd_notify(e->dnshandler, buffer_begin(q->buffer),
        buffer_remaining(q->buffer));

send_notify_ok:
    /* send notify ok */
    buffer_pkt_set_qr(q->buffer);
    buffer_pkt_set_aa(q->buffer);
    buffer_pkt_set_ancount(q->buffer, 0);

    buffer_clear(q->buffer); /* lim = pos, pos = 0; */
    buffer_set_position(q->buffer, pos);
    buffer_set_limit(q->buffer, buffer_capacity(q->buffer));
    q->reserved_space = edns_rr_reserved_space(q->edns_rr);
    q->reserved_space += tsig_rr_reserved_space(q->tsig_rr);
    return QUERY_PROCESSED;
}
Beispiel #10
0
/**
 * Start engine.
 *
 */
int
engine_start(const char* cfgfile, int cmdline_verbosity, int daemonize,
    int info, int single_run)
{
    engine_type* engine = NULL;
    ods_status zl_changed = ODS_STATUS_UNCHANGED;
    ods_status status = ODS_STATUS_OK;

    engine = engine_create();
    if (!engine) {
        ods_fatal_exit("[%s] create failed", engine_str);
        return 1;
    }
    engine->daemonize = daemonize;

    /* config */
    engine->config = engine_config(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("ods-signerd", engine->config->use_syslog,
        engine->config->log_filename, engine->config->verbosity);
    /* setup */
    status = engine_setup(engine);
    if (status != ODS_STATUS_OK) {
        ods_log_error("[%s] setup failed: %s", engine_str,
            ods_status2str(status));
        if (status != ODS_STATUS_WRITE_PIDFILE_ERR) {
            /* command handler had not yet been started */
            engine->cmdhandler_done = 1;
        }
        goto earlyexit;
    }

    /* 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);
            fifoq_wipe(engine->signq);
            engine->need_to_reload = 0;
        } else {
            ods_log_info("[%s] signer started (version %s), pid %u",
                engine_str, PACKAGE_VERSION, engine->pid);
            if (hsm_open2(engine->config->repositories, hsm_check_pin) != HSM_OK) {
                char* error =  hsm_get_error(NULL);
                if (error != NULL) {
                    ods_log_error("[%s] %s", "hsm", error);
                    free(error);
                }
                ods_log_error("[%s] opening hsm failed (for engine recover)", engine_str);
                break;
            }
            zl_changed = engine_recover(engine);
            hsm_close();
        }
        if (zl_changed == ODS_STATUS_OK ||
            zl_changed == ODS_STATUS_UNCHANGED) {
            engine_update_zones(engine, zl_changed);
        }
        if (hsm_open2(engine->config->repositories, hsm_check_pin) != HSM_OK) {
            char* error =  hsm_get_error(NULL);
            if (error != NULL) {
                ods_log_error("[%s] %s", "hsm", error);
                free(error);
            }
            ods_log_error("[%s] opening hsm failed (for engine run)", engine_str);
            break;
        }
        engine_run(engine, single_run);
        hsm_close();
    }

    /* shutdown */
    ods_log_info("[%s] signer shutdown", engine_str);
    engine_stop_cmdhandler(engine);
    engine_stop_xfrhandler(engine);
    engine_stop_dnshandler(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;

    return 1;
}
Beispiel #11
0
/**
 * Read zone from input adapter.
 *
 */
ods_status
tools_input(zone_type* zone)
{
    ods_status status = ODS_STATUS_OK;
    time_t start = 0;
    time_t end = 0;

    ods_log_assert(zone);
    ods_log_assert(zone->name);
    ods_log_assert(zone->adinbound);
    ods_log_assert(zone->signconf);
    /* Key Rollover? */
    status = zone_publish_dnskeys(zone, 0);
    if (status != ODS_STATUS_OK) {
        ods_log_error("[%s] unable to read zone %s: failed to "
            "publish dnskeys (%s)", tools_str, zone->name,
            ods_status2str(status));
        zone_rollback_dnskeys(zone);
        zone_rollback_nsec3param(zone);
        namedb_rollback(zone->db, 0);
        return status;
    }
    /* Denial of Existence Rollover? */
    if (!zone->signconf->passthrough)
        status = zone_publish_nsec3param(zone);
    if (status != ODS_STATUS_OK) {
        ods_log_error("[%s] unable to read zone %s: failed to "
            "publish nsec3param (%s)", tools_str, zone->name,
            ods_status2str(status));
        zone_rollback_dnskeys(zone);
        zone_rollback_nsec3param(zone);
        namedb_rollback(zone->db, 0);
        return status;
    }

    if (zone->stats) {
        pthread_mutex_lock(&zone->stats->stats_lock);
        zone->stats->sort_done = 0;
        zone->stats->sort_count = 0;
        zone->stats->sort_time = 0;
        pthread_mutex_unlock(&zone->stats->stats_lock);
    }
    /* Input Adapter */
    start = time(NULL);
    status = adapter_read((void*)zone);
    if (status != ODS_STATUS_OK && status != ODS_STATUS_UNCHANGED) {
        if (status == ODS_STATUS_XFRINCOMPLETE) {
            ods_log_info("[%s] read zone %s: xfr in progress",
                tools_str, zone->name);
        } else {
            ods_log_error("[%s] unable to read zone %s: adapter failed (%s)",
                tools_str, zone->name, ods_status2str(status));
        }
        zone_rollback_dnskeys(zone);
        zone_rollback_nsec3param(zone);
        namedb_rollback(zone->db, 0);
    }
    end = time(NULL);
    if ((status == ODS_STATUS_OK || status == ODS_STATUS_UNCHANGED)
        && zone->stats) {
        pthread_mutex_lock(&zone->stats->stats_lock);
        zone->stats->start_time = start;
        zone->stats->sort_time = (end-start);
        zone->stats->sort_done = 1;
        pthread_mutex_unlock(&zone->stats->stats_lock);
    }
    return status;
}
Beispiel #12
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;
}