Ejemplo n.º 1
0
static void fatal(
    int err,
    char *param)
{
    warn(err, param);
    config_unload();
    exit(err);
}
Ejemplo n.º 2
0
static void cleanup_control(control_t *control)
{
	assert(control != NULL);

	assert(control->reply);
	expbuf_clear(control->reply);
	expbuf_free(control->reply);
	free(control->reply);
	control->reply = NULL;

	if (control->entries) {
		config_unload(control);
	}

	assert(control->req == NULL);
	assert(control->rqsvc == NULL);
	assert(control->risp == NULL);
	assert(control->sigint_event == NULL);
	assert(control->sighup_event == NULL);
}
Ejemplo n.º 3
0
// print usage to stdout for the user
void printUsage(
    char **argv)
{
    fprintf(stderr, "Usage:\n");
    fprintf(stderr,
            "        %s OBJECT_TYPE arg1=value arg2=value arg3=value\n",
            argv[0]);
    fprintf(stderr, "\n");
    fprintf(stderr, "where OBJECT_TYPE is one of the following: \n");
    fprintf(stderr, "            (CERT, CRL, ROA or MANIFEST)\n");
    fprintf(stderr,
            "and argument/value pairs are based upon the object type\n");
    fprintf(stderr, "\n");
    fprintf(stderr, "options:\n");
    fprintf(stderr,
            "\t-f\tread config file for additional argument/value pairs (cmd line takes precedence)\n");
    fprintf(stderr,
            "\t-t\tuse specified file template rather than the default\n");
    fprintf(stderr, "\t-h\tprint this usage\n");

    config_unload();

    exit(0);
}
Ejemplo n.º 4
0
/*
 * create_object parse the object fields from the command line and call the
 * appropriate object creator with a table of fields filled in.
 */
int main(
    int argc,
    char **argv)
{

    int ret = 0;
    int parse_err = 0;
    int index = 1;
    int c;
    char *obj_type;
    char *configFile = NULL;
    extern char *optarg;
    struct object_field *table;


    OPEN_LOG("create_object", LOG_USER);

    if (!my_config_load())
    {
        LOG(LOG_ERR, "can't load configuration");
        return EXIT_FAILURE;
    }


    // parse options
    while ((c = getopt(argc, argv, "hf:t:")) != -1)
    {
        switch (c)
        {
        case 'h':
            printUsage(argv);
            break;

        case 'f':
            configFile = optarg;
            break;

        case 't':
            templateFile = optarg;
            break;

        case '?':
            printUsage(argv);
            break;

        default:
            fprintf(stderr, "Illegal Option\n");
            printUsage(argv);
            break;
        }
    }

    index = optind;             // remaining arguments
    if (configFile == NULL)
        fprintf(stdout, "No Config file\n");

    if (index >= argc)
        fatal(INPUT_ARG_ERR, "No Object Type");
    else
        obj_type = argv[index++];

    if (strncasecmp(obj_type, "CERT", strlen("CERT")) == 0)
    {
        table = get_cert_field_table();
        if (configFile != NULL)
            if (parse_config(configFile, table) != 0)
            {
                warn(INPUT_ARG_ERR, parse_errstr);
                parse_err = 1;
            }

        // parse and validate arguments, exit if either or both fail
        if (parse_args(argc, argv, index, table) != 0)
        {
            warn(INPUT_ARG_ERR, parse_errstr);
            parse_err = 1;
        }
        if (validate_table(table, validate_errstr, sizeof(validate_errstr)) !=
            0)
            fatal(MISSING_FIELDS, validate_errstr);

        // if no validation error but we did have a parse err - exit
        if (parse_err)
        {
            config_unload();
            exit(INPUT_ARG_ERR);
        }

        ret = create_cert(table);
        // fprintf(stdout,"return from creating certificate %d\n", ret);
    }
    else if (strncasecmp(obj_type, "CRL", strlen("CRL")) == 0)
    {
        table = get_crl_field_table();
        if (configFile != NULL)
            if (parse_config(configFile, table) != 0)
            {
                warn(INPUT_ARG_ERR, parse_errstr);
                parse_err = 1;
            }

        if (parse_args(argc, argv, index, table) != 0)
        {
            warn(INPUT_ARG_ERR, parse_errstr);
            parse_err = 1;
        }
        if (validate_table(table, validate_errstr, sizeof(validate_errstr)) !=
            0)
            fatal(MISSING_FIELDS, validate_errstr);

        // if no validation error but we did have a parse err - exit
        if (parse_err)
        {
            config_unload();
            exit(INPUT_ARG_ERR);
        }

        ret = create_crl(table);
    }
    else if (strncasecmp(obj_type, "ROA", strlen("ROA")) == 0)
    {
        table = get_roa_field_table();
        if (configFile != NULL)
            if (parse_config(configFile, table) != 0)
            {
                warn(INPUT_ARG_ERR, parse_errstr);
                parse_err = 1;
            }

        if (parse_args(argc, argv, index, table) != 0)
            fatal(INPUT_ARG_ERR, parse_errstr);

        if (validate_table(table, validate_errstr, sizeof(validate_errstr)) !=
            0)
            fatal(MISSING_FIELDS, validate_errstr);
        ret = create_roa(table);
    }
    else if (strncasecmp(obj_type, "MANIFEST", strlen("MANIFEST")) == 0)
    {
        table = get_man_field_table();
        if (configFile != NULL)
            if (parse_config(configFile, table) != 0)
            {
                warn(INPUT_ARG_ERR, parse_errstr);
                parse_err = 1;
            }

        // parse arguments and validate table
        if (parse_args(argc, argv, index, table) != 0)
            warn(INPUT_ARG_ERR, parse_errstr);

        if (validate_table(table, validate_errstr, sizeof(validate_errstr)) !=
            0)
            fatal(MISSING_FIELDS, validate_errstr);
        ret = create_manifest(table);
    }
    else
        fatal(INPUT_ARG_ERR, argv[1]);

    config_unload();

    exit(ret);
}
Ejemplo n.º 5
0
int main(
    int argc,
    char **argv)
{
    int ret = EXIT_SUCCESS;
    bool done_db_init = false;
    bool done_db_thread_init = false;
    dbconn * db = NULL;

    bool first_time;
    bool force_update = false;
    bool update_had_changes;
    serial_number_t previous_serial;
    serial_number_t current_serial;

    if (argc < 1 || argc > 2)
    {
        fprintf(stderr,
                "Usage: %s [<next serial number>]\n",
                argv[0]);
        fprintf(stderr, "\n");
        fprintf(stderr,
                "The next serial number should only be specified in test mode.\n");
        return EXIT_FAILURE;
    }

    OPEN_LOG("rtr-update", LOG_USER);

    if (!my_config_load())
    {
        LOG(LOG_ERR, "can't load configuration");
        return EXIT_FAILURE;
    }

    // initialize the database connection
    if (!db_init())
    {
        LOG(LOG_ERR, "Could not initialize database program.");
        ret = EXIT_FAILURE;
        goto done;
    }
    done_db_init = true;

    if (!db_thread_init())
    {
        LOG(LOG_ERR, "Could not initialize database thread.");
        ret = EXIT_FAILURE;
        goto done;
    }
    done_db_thread_init = true;

    db = db_connect_default(DB_CLIENT_RTR);
    if (db == NULL)
    {
        LOG(LOG_ERR,
            "Could not connect to the database, check your config "
            "file.");
        ret = EXIT_FAILURE;
        goto done;
    }


    if (!db_rtr_has_valid_session(db))
    {
        return EXIT_FAILURE;
    }

    // Get the previous serial number.
    switch (db_rtr_get_latest_sernum(db, &previous_serial))
    {
        case GET_SERNUM_SUCCESS:
            first_time = false;
            // previous_serial was set by db_rtr_get_latest_sernum
            break;

        case GET_SERNUM_NONE:
            first_time = true;
            // Set previous_serial to a pseudo-random number
            srandom((unsigned int)time(NULL));
            previous_serial = (serial_number_t)random();
            break;

        case GET_SERNUM_ERR:
        default:
            LOG(LOG_ERR, "Error finding latest serial number.");
            ret = EXIT_FAILURE;
            goto done;
    }

    if (!db_rtr_delete_incomplete_updates(db))
    {
        LOG(LOG_ERR, "Error deleting incomplete updates.");
        ret = EXIT_FAILURE;
        goto done;
    }

    // Get/compute the current serial number.
    if (argc > 1)
    {
        force_update = true;
        if (sscanf(argv[1], "%" SCNSERIAL, &current_serial) != 1)
        {
            fprintf(stderr,
                    "Error: next serial number must be a nonnegative integer\n");
            return EXIT_FAILURE;
        }
    }
    else
    {
        // NOTE: this relies on unsigned integer wrap-around to zero
        current_serial = previous_serial + 1;
    }

    // Make sure we're not about to overwrite current_serial, create a
    // loop, or start a diverging history, even though these should be
    // *really* unlikely.
    if (!first_time &&
        !db_rtr_good_serials(db, previous_serial, current_serial))
    {
        if (argc > 1)
        {
            LOG(LOG_ERR,
                "Error: rtr_update is full or in an unusual state, "
                "or the specified next serial number already "
                "exists.");
        }
        else
        {
            LOG(LOG_ERR,
                "Error: rtr_update table is either full or in an "
                "unusual state.");
        }

        ret = EXIT_FAILURE;
        goto done;
    }

    if (!db_rtr_insert_full(db, current_serial))
    {
        LOG(LOG_ERR, "Could not copy current RPKI state.");
        ret = EXIT_FAILURE;
        goto done;
    }

    if (!first_time &&
        !db_rtr_insert_incremental(db, previous_serial, current_serial))
    {
        LOG(LOG_ERR, "Could not compute incremental changes.");
        ret = EXIT_FAILURE;
        goto done;
    }

    if (first_time)
    {
        update_had_changes = true;
    }
    else
    {
        switch (db_rtr_has_incremental_changes(db, current_serial))
        {
            case 1:
                update_had_changes = true;
                break;

            case 0:
                update_had_changes = false;
                break;

            case -1:
            default:
                LOG(LOG_ERR,
                    "Error determining if there were any changes.");
                ret = EXIT_FAILURE;
                goto done;
        }
    }

    if (update_had_changes || force_update)
    {
        // Make the new serial number available for use.
        if (
            !db_rtr_insert_update(db, current_serial, previous_serial,
                first_time))
        {
            LOG(LOG_ERR, "Error making updates available.");
            ret = EXIT_FAILURE;
            goto done;
        }
    }
    else
    {
        LOG(LOG_INFO,
            "Data had no changes since the last update, so no update "
            "was made.");

        // The new data in rtr_full is useless, so delete it.
        if (!db_rtr_delete_full(db, current_serial))
        {
            LOG(LOG_ERR, "Error deleting duplicate data in rtr_full.");
            ret = EXIT_FAILURE;
            goto done;
        }

        // there's nothing to delete from rtr_incremental
    }

    // clean up all the data no longer needed
    // save last two full updates so that no problems at transition
    // (with client still receiving data from previous one)
    //
    // NOTE: The order of these updates and deletes is important.
    // All data must be marked as unusable according to rtr_update
    // before it is deleted from rtr_full or rtr_incremental.
    if (
        !db_rtr_ignore_old_full(
            db, current_serial, previous_serial) ||
        !db_rtr_delete_old_full(
            db, current_serial, previous_serial) ||
        !db_rtr_delete_old_update(
            db, current_serial, previous_serial) ||
        !db_rtr_ignore_old_incremental(db) ||
        !db_rtr_delete_old_incremental(db) ||
        false)
    {
        LOG(LOG_ERR, "Error cleaning up old data.");
        ret = EXIT_FAILURE;
        goto done;
    }


done:

    if (db != NULL)
    {
        db_disconnect(db);
    }

    if (done_db_thread_init)
    {
        db_thread_close();
    }

    if (done_db_init)
    {
        db_close();
    }

    config_unload();

    CLOSE_LOG();

    return ret;
}
Ejemplo n.º 6
0
int
main (int argc, char *argv[])
{
	struct pollfd *poll_fd;
	struct config etherpoke_conf;
	struct config_filter *filter_iter;
	struct session_data *pcap_session;
	struct option_data opt;
	char conf_errbuff[CONF_ERRBUF_SIZE];
	char pcap_errbuff[PCAP_ERRBUF_SIZE];
	struct pathname path_config;
	struct sigaction sa;
#ifdef DBG_AVG_LOOP_SPEED
	clock_t clock_start;
	double clock_avg;
#endif
	pid_t pid;
	int i, c, j, rval, syslog_flags, opt_index, filter_cnt, sock, poll_len;
	struct option opt_long[] = {
		{ "", no_argument, NULL, '4' },
		{ "", no_argument, NULL, '6' },
		{ "hostname", required_argument, NULL, 't' },
		{ "daemon", no_argument, NULL, 'd' },
		{ "accept-max", required_argument, NULL, 'm' },
		{ "verbose", no_argument, NULL, 'V' },
		{ "help", no_argument, NULL, 'h' },
		{ "version", no_argument, NULL, 'v' },
		{ NULL, 0, NULL, 0 }
	};

	sock = -1;
	poll_fd = NULL;
	pcap_session = NULL;
	exitno = EXIT_SUCCESS;
	syslog_flags = LOG_PID | LOG_PERROR;
#ifdef DBG_AVG_LOOP_SPEED
	clock_avg = 0;
#endif

	memset (&opt, 0, sizeof (struct option_data));

	opt.accept_max = ACCEPT_MAX;
	opt.ip_version = AF_UNSPEC;

	memset (&path_config, 0, sizeof (struct pathname));
	memset (&etherpoke_conf, 0, sizeof (struct config));

	while ( (c = getopt_long (argc, argv, "46t:dm:Vhv", opt_long, &opt_index)) != -1 ){
		switch ( c ){
			case 'd':
				opt.daemon = 1;
				break;

			case 't':
				rval = hostformat_parse (optarg, opt.hostname, opt.port);

				if ( rval == -1 || strlen (opt.hostname) == 0 || strlen (opt.port) == 0 ){
					fprintf (stderr, "%s: invalid hostname format (expects HOSTNAME:PORT)\n", argv[0]);
					exitno = EXIT_FAILURE;
					goto cleanup;
				}

				opt.tcp_event = 1;
				break;

			case '4':
				opt.ip_version = AF_INET;
				break;

			case '6':
				opt.ip_version = AF_INET6;
				break;

			case 'm':
				rval = sscanf (optarg, "%u", &(opt.accept_max));

				if ( rval < 1 || opt.accept_max == 0 ){
					fprintf (stderr, "%s: invalid number for maximum connections\n", argv[0]);
					exitno = EXIT_FAILURE;
					goto cleanup;
				}
				break;

			case 'V':
				opt.verbose = 1;
				break;

			case 'h':
				etherpoke_help (argv[0]);
				exitno = EXIT_SUCCESS;
				goto cleanup;

			case 'v':
				etherpoke_version (argv[0]);
				exitno = EXIT_SUCCESS;
				goto cleanup;

			default:
				etherpoke_help (argv[0]);
				exitno = EXIT_FAILURE;
				goto cleanup;
		}
	}

	// Check if there are some non-option arguments, these are treated as paths
	// to configuration files.
	if ( (argc - optind) == 0 ){
		fprintf (stderr, "%s: configuration file not specified. Use '--help' to see usage information.\n", argv[0]);
		exitno = EXIT_FAILURE;
		goto cleanup;
	}

	// Change working directory to match the dirname of the config file.
	rval = path_split (argv[optind], &path_config);

	if ( rval != 0 ){
		fprintf (stderr, "%s: cannot split path to configuration file.\n", argv[0]);
		exitno = EXIT_FAILURE;
		goto cleanup;
	}

	rval = chdir (path_config.dir);

	if ( rval == -1 ){
		fprintf (stderr, "%s: cannot set working directory to '%s': %s\n", argv[0], path_config.dir, strerror (errno));
		exitno = EXIT_FAILURE;
		goto cleanup;
	}

	//
	// Load configuration file
	//
	filter_cnt = config_load (&etherpoke_conf, path_config.base, conf_errbuff);

	if ( filter_cnt == -1 ){
		fprintf (stderr, "%s: cannot load configuration file '%s': %s\n", argv[0], argv[optind], conf_errbuff);
		exitno = EXIT_FAILURE;
		goto cleanup;
	} else	if ( filter_cnt == 0 ){
		fprintf (stderr, "%s: nothing to do, no filters defined.\n", argv[0]);
		exitno = EXIT_FAILURE;
		goto cleanup;
	}

	// Allocate enough memory for filters (+1 means that we are also allocating
	// space for listening socket).
	// NOTE: always allocate space for listening socket here, to move this
	// allocation inside the block below (where listening socket is actually
	// allocated) is not a good idea as more complex condition would have to be
	// used inside the main loop.
	poll_len = filter_cnt + 1;

	if ( opt.tcp_event ){
		struct addrinfo *host_addr, addr_hint;
		int opt_val;

		// Increase poll size to accommodate socket descriptors for clients.
		poll_len += opt.accept_max;
		host_addr = NULL;

		memset (&addr_hint, 0, sizeof (struct addrinfo));

		// Setup addrinfo hints
		addr_hint.ai_family = opt.ip_version;
		addr_hint.ai_socktype = SOCK_STREAM;
		addr_hint.ai_flags = AI_PASSIVE | AI_NUMERICSERV;

		rval = getaddrinfo (opt.hostname, opt.port, &addr_hint, &host_addr);

		if ( rval != 0 ){
			fprintf (stderr, "%s: hostname resolve failed: %s\n", argv[0], gai_strerror (rval));
			exitno = EXIT_FAILURE;
			goto cleanup;
		}

		sock = socket (host_addr->ai_family, host_addr->ai_socktype | SOCK_NONBLOCK, host_addr->ai_protocol);

		if ( sock == -1 ){
			freeaddrinfo (host_addr);
			fprintf (stderr, "%s: cannot create socket: %s\n", argv[0], strerror (errno));
			exitno = EXIT_FAILURE;
			goto cleanup;
		}

		opt_val = 1;

		if ( setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, &opt_val, sizeof (opt_val)) == -1 ){
			freeaddrinfo (host_addr);
			fprintf (stderr, "%s: cannot set socket options: %s\n", argv[0], strerror (errno));
			exitno = EXIT_FAILURE;
			goto cleanup;
		}

		rval = bind (sock, (struct sockaddr*) host_addr->ai_addr, host_addr->ai_addrlen);

		if ( rval == -1 ){
			freeaddrinfo (host_addr);
			fprintf (stderr, "%s: cannot bind to address: %s\n", argv[0], strerror (errno));
			exitno = EXIT_FAILURE;
			goto cleanup;
		}

		rval = listen (sock, LISTEN_QUEUE_LEN);

		if ( rval == -1 ){
			freeaddrinfo (host_addr);
			fprintf (stderr, "%s: %s\n", argv[0], strerror (errno));
			exitno = EXIT_FAILURE;
			goto cleanup;
		}

		freeaddrinfo (host_addr);
	}

	pcap_session = (struct session_data*) calloc (filter_cnt, sizeof (struct session_data));

	if ( pcap_session == NULL ){
		fprintf (stderr, "%s: cannot allocate memory: %s\n", argv[0], strerror (errno));
		exitno = EXIT_FAILURE;
		goto cleanup;
	}

	for ( i = 0, filter_iter = etherpoke_conf.head; filter_iter != NULL; i++, filter_iter = filter_iter->next ){
		int link_type;

		session_data_init (&(pcap_session[i]));

		pcap_session[i].timeout = filter_iter->session_timeout;
		pcap_session[i].evt_mask = filter_iter->notify;

		pcap_session[i].filter_name = strdup (filter_iter->name);

		if ( pcap_session[i].filter_name == NULL ){
			fprintf (stderr, "%s: cannot allocate memory: %s\n", argv[0], strerror (errno));
			exitno = EXIT_FAILURE;
			goto cleanup;
		}

		if ( filter_iter->notify & NOTIFY_EXEC ){

			if ( filter_iter->session_begin != NULL ){
				rval = wordexp (filter_iter->session_begin, &(pcap_session[i].evt_cmd_beg), WORDEXP_FLAGS);

				if ( rval != 0 )
					goto filter_error;
			}

			if ( filter_iter->session_error != NULL ){
				rval = wordexp (filter_iter->session_error, &(pcap_session[i].evt_cmd_err), WORDEXP_FLAGS);

				if ( rval != 0 )
					goto filter_error;
			}

			if ( filter_iter->session_end != NULL ){
				rval = wordexp (filter_iter->session_end, &(pcap_session[i].evt_cmd_end), WORDEXP_FLAGS);

				if ( rval != 0 )
					goto filter_error;
			}

filter_error:
			switch ( rval ){
				case WRDE_SYNTAX:
					fprintf (stderr, "%s: invalid event hook in '%s': syntax error\n", argv[0], filter_iter->name);
					exitno = EXIT_FAILURE;
					goto cleanup;

				case WRDE_BADCHAR:
					fprintf (stderr, "%s: invalid event hook in '%s': bad character\n", argv[0], filter_iter->name);
					exitno = EXIT_FAILURE;
					goto cleanup;

				case WRDE_BADVAL:
					fprintf (stderr, "%s: invalid event hook in '%s': referencing undefined variable\n", argv[0], filter_iter->name);
					exitno = EXIT_FAILURE;
					goto cleanup;

				case WRDE_NOSPACE:
					fprintf (stderr, "%s: cannot expand event hook string in '%s': out of memory\n", argv[0], filter_iter->name);
					exitno = EXIT_FAILURE;
					goto cleanup;
			}
		}

		pcap_session[i].handle = pcap_create (filter_iter->interface, pcap_errbuff);

		if ( pcap_session[i].handle == NULL ){
			fprintf (stderr, "%s: cannot start packet capture: %s\n", argv[0], pcap_errbuff);
			exitno = EXIT_FAILURE;
			goto cleanup;
		}

		rval = pcap_set_rfmon (pcap_session[i].handle, filter_iter->rfmon);

		if ( rval != 0 ){
			fprintf (stderr, "%s: cannot enable monitor mode on interface '%s': %s\n", argv[0], filter_iter->interface, pcap_geterr (pcap_session[i].handle));
			exitno = EXIT_FAILURE;
			goto cleanup;
		}

		rval = pcap_set_promisc (pcap_session[i].handle, !(filter_iter->rfmon));

		if ( rval != 0 ){
			fprintf (stderr, "%s: cannot enable promiscuous mode on interface '%s'\n", argv[0], filter_iter->interface);
			exitno = EXIT_FAILURE;
			goto cleanup;
		}

		rval = pcap_set_timeout (pcap_session[i].handle, SELECT_TIMEOUT_MS);

		if ( rval != 0 ){
			fprintf (stderr, "%s: cannot set read timeout on interface '%s': %s\n", argv[0], filter_iter->interface, pcap_geterr (pcap_session[i].handle));
			exitno = EXIT_FAILURE;
			goto cleanup;
		}

		rval = pcap_setnonblock (pcap_session[i].handle, 1, pcap_errbuff);

		if ( rval == -1 ){
			fprintf (stderr, "%s: cannot set nonblock mode on packet capture resource: %s\n", argv[0], pcap_errbuff);
			exitno = EXIT_FAILURE;
			goto cleanup;
		}

		rval = pcap_activate (pcap_session[i].handle);

		if ( rval != 0 ){
			fprintf (stderr, "%s: cannot activate packet capture on interface '%s': %s\n", argv[0], filter_iter->interface, pcap_geterr (pcap_session[i].handle));
			exitno = EXIT_FAILURE;
			goto cleanup;
		}

		// Set link-layer type from configuration file.
		if ( filter_iter->link_type != NULL ){
			link_type = pcap_datalink_name_to_val (filter_iter->link_type);

			if ( link_type == -1 ){
				fprintf (stderr, "%s: cannot convert link-layer type '%s': unknown link-layer type name\n", argv[0], filter_iter->link_type);
				exitno = EXIT_FAILURE;
				goto cleanup;
			}
		} else {
			// If no link-layer type is specified in the configuration file,
			// use default value. At this point I am sticking with DLTs used by
			// wireshark on hardware I have available. Different values may
			// apply to different hardware/driver, therefore more research time
			// should be put into finding 'best' values.
			// More information: http://www.tcpdump.org/linktypes.html
			if ( filter_iter->rfmon ){
				link_type = DLT_IEEE802_11_RADIO;
			} else {
				link_type = DLT_EN10MB;
			}
		}

		rval = pcap_set_datalink (pcap_session[i].handle, link_type);

		if ( rval == -1 ){
			fprintf (stderr, "%s: cannot set data-link type: %s\n", argv[0], pcap_geterr (pcap_session[i].handle));
			exitno = EXIT_FAILURE;
			goto cleanup;
		}

		if ( filter_iter->match != NULL ){
			struct bpf_program bpf_prog;

			rval = pcap_compile (pcap_session[i].handle, &bpf_prog, filter_iter->match, 0, PCAP_NETMASK_UNKNOWN);

			if ( rval == -1 ){
				fprintf (stderr, "%s: cannot compile the filter '%s' match rule: %s\n", argv[0], filter_iter->name, pcap_geterr (pcap_session[i].handle));
				exitno = EXIT_FAILURE;
				goto cleanup;
			}

			rval = pcap_setfilter (pcap_session[i].handle, &bpf_prog);

			if ( rval == -1 ){
				fprintf (stderr, "%s: cannot apply the filter '%s' on interface '%s': %s\n", argv[0], filter_iter->name, filter_iter->interface, pcap_geterr (pcap_session[i].handle));
				exitno = EXIT_FAILURE;
				goto cleanup;
			}

			pcap_freecode (&bpf_prog);
		}

		pcap_session[i].fd = pcap_get_selectable_fd (pcap_session[i].handle);

		if ( pcap_session[i].fd == -1 ){
			fprintf (stderr, "%s: cannot obtain file descriptor for packet capture interface '%s'\n", argv[0], filter_iter->interface);
			exitno = EXIT_FAILURE;
			goto cleanup;
		}
	}

	// We no longer need data stored in config structure. All neccessary data
	// were moved into session_data structure.
	config_unload (&etherpoke_conf);

	poll_fd = (struct pollfd*) malloc (sizeof (struct pollfd) * poll_len);

	if ( poll_fd == NULL ){
		fprintf (stderr, "%s: cannot allocate memory: %s\n", argv[0], strerror (errno));
		exitno = EXIT_FAILURE;
		goto cleanup;
	}

	// Populate poll structure...
	for ( i = 0; i < poll_len; i++ ){
		// ... with pcap file descriptors...
		if ( i < filter_cnt )
			poll_fd[i].fd = pcap_session[i].fd;
		// ... listening socket...
		else if ( i == filter_cnt )
			poll_fd[i].fd = sock;
		// ... invalid file descriptors (will be ignored by poll(2)), in space reserved for client sockets...
		else
			poll_fd[i].fd = -1;

		poll_fd[i].events = POLLIN | POLLERR;
		poll_fd[i].revents = 0;
	}

	//
	// Setup signal handler
	//
	sa.sa_handler = etherpoke_sigdie;
	sigemptyset (&(sa.sa_mask));
	sa.sa_flags = 0;

	rval = 0;
	rval &= sigaction (SIGINT, &sa, NULL);
	rval &= sigaction (SIGQUIT, &sa, NULL);
	rval &= sigaction (SIGTERM, &sa, NULL);

	sa.sa_handler = SIG_IGN;
	sigemptyset (&(sa.sa_mask));
	sa.sa_flags = 0;

	rval &= sigaction (SIGCHLD, &sa, NULL);

	if ( rval != 0 ){
		fprintf (stderr, "%s: cannot setup signal handler: %s\n", argv[0], strerror (errno));
		exitno = EXIT_FAILURE;
		goto cleanup;
	}

	//
	// Daemonize the process if the flag was set
	//
	if ( opt.daemon == 1 ){
		pid = fork ();

		if ( pid > 0 ){
			exitno = EXIT_SUCCESS;
			goto cleanup;
		} else if ( pid == -1 ){
			fprintf (stderr, "%s: cannot daemonize the process (fork failed).\n", argv[0]);
			exitno = EXIT_FAILURE;
			goto cleanup;
		}

		if ( setsid () == -1 ){
			fprintf (stderr, "%s: cannot daemonize the process (setsid failed).\n", argv[0]);
			exitno = EXIT_FAILURE;
			goto cleanup;
		}

		umask (0);

		freopen ("/dev/null", "r", stdin);
		freopen ("/dev/null", "w", stdout);
		freopen ("/dev/null", "w", stderr);
		syslog_flags = LOG_PID;
	}

	openlog ("etherpoke", syslog_flags, LOG_DAEMON);

	syslog (LOG_INFO, "Etherpoke started (loaded filters: %u)", filter_cnt);

	if ( opt.tcp_event )
		syslog (LOG_INFO, "Event notifications available via %s:%s (ACCEPT_MAX: %u)", opt.hostname, opt.port, opt.accept_max);

	//
	// Main loop
	//
	main_loop = 1;

	while ( main_loop ){
		const u_char *pkt_data;
		struct pcap_pkthdr *pkt_header;
		time_t current_time;

		errno = 0;
		rval = poll (poll_fd, poll_len, SELECT_TIMEOUT_MS);

		if ( rval == -1 ){
			if ( errno == EINTR )
				continue;

			syslog (LOG_ERR, "poll(2) failed: %s", strerror (errno));
			exitno = EXIT_FAILURE;
			goto cleanup;
		}

#ifdef DBG_AVG_LOOP_SPEED
		clock_start = clock ();
#endif

		// Accept incoming connection
		if ( poll_fd[filter_cnt].revents & POLLIN ){
			int sock_new;

			sock_new = accept (sock, NULL, NULL);

			if ( sock_new == -1 ){
				syslog (LOG_ERR, "cannot accept new connection: %s", strerror (errno));
				exitno = EXIT_FAILURE;
				goto cleanup;
			}

			// Find unused place in the poll array
			for ( j = (filter_cnt + 1); j < poll_len; j++ ){
				if ( poll_fd[j].fd == -1 ){
					poll_fd[j].fd = sock_new;
					sock_new = -1;
					break;
				}
			}

			if ( sock_new != -1 ){
				if ( opt.verbose )
					syslog (LOG_INFO, "Client refused: too many concurrent connections");
				close (sock_new);
			} else {
				if ( opt.verbose )
					syslog (LOG_INFO, "Client connected...");
			}
		}

		// Take care of incoming client data.  At this point only shutdown and
		// close is handled, no other input is expected from the clients.
		for ( i = (filter_cnt + 1); i < poll_len; i++ ){
			if ( poll_fd[i].revents & POLLIN ){
				char nok[128];

				errno = 0;
				rval = recv (poll_fd[i].fd, nok, sizeof (nok), MSG_DONTWAIT);

				if ( rval <= 0 && (errno != EAGAIN && errno != EWOULDBLOCK) ){
					if ( opt.verbose )
						syslog (LOG_INFO, "Client disconnected...");
					close (poll_fd[i].fd);
					poll_fd[i].fd = -1;
				}
			}
		}

		time (&current_time);

		// Handle changes on pcap file descriptors
		for ( i = 0; i < filter_cnt; i++ ){
			wordexp_t *cmd_exp;
			const char *evt_str;

			// Handle incoming packet
			if ( (poll_fd[i].revents & POLLIN) || (poll_fd[i].revents & POLLERR) ){
				rval = pcap_next_ex (pcap_session[i].handle, &pkt_header, &pkt_data);

				if ( rval == 1 ){
					if ( pcap_session[i].evt.ts == 0 )
						pcap_session[i].evt.type = SE_BEG;

					pcap_session[i].evt.ts = pkt_header->ts.tv_sec;
				} else if ( rval < 0 ){
					pcap_session[i].evt.type = SE_ERR;
				}
			}

			if ( (pcap_session[i].evt.ts > 0)
					&& (difftime (current_time, pcap_session[i].evt.ts) >= pcap_session[i].timeout) ){
				pcap_session[i].evt.type = SE_END;
			}

			switch ( pcap_session[i].evt.type ){
				case SE_NUL:
					// There was no change on this file descriptor, skip to
					// another one. 'continue' may seem a bit confusing here,
					// but it applies to a loop above. Not sure how other
					// compilers will behave (other than gcc).
					continue;

				case SE_BEG:
					evt_str = "BEG";
					cmd_exp = &(pcap_session[i].evt_cmd_beg);
					pcap_session[i].evt.type = SE_NUL;
					break;

				case SE_END:
					cmd_exp = &(pcap_session[i].evt_cmd_end);
					evt_str = "END";
					pcap_session[i].evt.type = SE_NUL;
					pcap_session[i].evt.ts = 0;
					break;

				case SE_ERR:
					evt_str = "ERR";
					cmd_exp = &(pcap_session[i].evt_cmd_err);
					pcap_session[i].evt.type = SE_NUL;
					pcap_session[i].evt.ts = 0;
					break;

				default:
					// Undefined state... What to do, other than die?
					syslog (LOG_ERR, "undefined event type");
					exitno = EXIT_FAILURE;
					goto cleanup;
			}

			if ( opt.verbose )
				syslog (LOG_INFO, "%s:%s", pcap_session[i].filter_name, evt_str);

			// Send socket notification
			if ( pcap_session[i].evt_mask & NOTIFY_SOCK ){
				char msg[CONF_FILTER_NAME_MAXLEN + 5];

				snprintf (msg, sizeof (msg), "%s:%s", pcap_session[i].filter_name, evt_str);

				for ( j = (filter_cnt + 1); j < poll_len; j++ ){
					if ( poll_fd[j].fd == -1 )
						continue;

					errno = 0;
					rval = send (poll_fd[j].fd, msg, strlen (msg) + 1, MSG_NOSIGNAL | MSG_DONTWAIT);

					if ( rval == -1 && (errno != EAGAIN && errno != EWOULDBLOCK) ){
						syslog (LOG_WARNING, "failed to send notification: %s", strerror (errno));
						close (poll_fd[j].fd);
						poll_fd[j].fd = -1;
					}
				}
			}

			// Execute an event hook
			if ( pcap_session[i].evt_mask & NOTIFY_EXEC ){

				// Expansion was not made...
				if ( cmd_exp->we_wordc == 0 )
					continue;

				pid = fork ();

				if ( pid == -1 ){
					syslog (LOG_ERR, "cannot fork the process: %s", strerror (errno));
					exitno = EXIT_FAILURE;
					goto cleanup;
				}

				// Parent process, carry on...
				if ( pid > 0 )
					continue;

				errno = 0;
				execv (cmd_exp->we_wordv[0], cmd_exp->we_wordv);

				// This code gets executed only if execv(3) fails. Wrapping
				// this code in a condition is unneccessary.
				syslog (LOG_WARNING, "cannot execute event hook in '%s': %s", pcap_session[i].filter_name, strerror (errno));

				exitno = EXIT_FAILURE;
				goto cleanup;
			}
		}

#ifdef DBG_AVG_LOOP_SPEED
		clock_avg = (clock_avg + (clock () - clock_start)) / 2;

		syslog (LOG_DEBUG, "Average loop speed: %lf", (double) (clock_avg / CLOCKS_PER_SEC));
#endif
	}

	syslog (LOG_INFO, "Etherpoke shutdown (signal %u)", exitno);

cleanup:
	closelog ();

	if ( pcap_session != NULL ){
		for ( i = 0; i < filter_cnt; i++ )
			session_data_free (&(pcap_session[i]));
		free (pcap_session);
	}

	if ( poll_fd != NULL )
		free (poll_fd);

	if ( sock != -1 )
		close (sock);

	config_unload (&etherpoke_conf);

	path_free (&path_config);

	return exitno;
}
Ejemplo n.º 7
0
//-----------------------------------------------------------------------------
// Main... process command line parameters, and then setup our listening 
// sockets and event loop.
int main(int argc, char **argv) 
{
	rq_service_t   *service;
	control_t      *control  = NULL;
	char *queue;

///============================================================================
/// Initialization.
///============================================================================

	// create the 'control' object that will be passed to all the handlers so
	// that they have access to the information that they require.
	control = (control_t *) malloc(sizeof(control_t));
	init_control(control);

	// create new service object.
	service = rq_svc_new();
	control->rqsvc = service;

	// add the command-line options that are specific to this service.
	rq_svc_setname(service, PACKAGE " " VERSION);
	rq_svc_setoption(service, 'f', "filename", "blacklist .csv file.");
	rq_svc_setoption(service, 'q', "queue",    "Queue to listen on for requests.");
	rq_svc_process_args(service, argc, argv);
	rq_svc_initdaemon(service);
	
	assert(control->evbase == NULL);
	control->evbase = event_base_new();
	assert(control->evbase);
	rq_svc_setevbase(service, control->evbase);


	// initialise the risp system for processing what we receive on the queue.
	assert(control);
	assert(control->risp == NULL);
	control->risp = risp_init(NULL);
	assert(control->risp != NULL);
	risp_add_command(control->risp, BL_CMD_NOP,      &cmdNop);
	risp_add_command(control->risp, BL_CMD_CLEAR, 	 &cmdClear);
	risp_add_command(control->risp, BL_CMD_CHECK,    &cmdCheck);
	risp_add_command(control->risp, BL_CMD_IP,       &cmdIP);
	
	// initialise signal handlers.
	assert(control);
	assert(control->evbase);
	assert(control->sigint_event == NULL);
	control->sigint_event = evsignal_new(control->evbase, SIGINT, sigint_handler, control);
	assert(control->sigint_event);
	event_add(control->sigint_event, NULL);
	assert(control->sighup_event == NULL);
	control->sighup_event = evsignal_new(control->evbase, SIGHUP, sighup_handler, control);
	assert(control->sighup_event);
	event_add(control->sighup_event, NULL);

	// load the config file that we assume is supplied.
	assert(control->configfile == NULL);
	control->configfile = rq_svc_getoption(service, 'f');
	if (control->configfile == NULL) {
		fprintf(stderr, "Configfile is required\n");
		exit(EXIT_FAILURE);
	}
	else {
		if (config_load(control) < 0) {
			fprintf(stderr, "Errors loading config file: %s\n", control->configfile);
			exit(EXIT_FAILURE);
		}
	}

	// Tell the rq subsystem to connect to the rq servers.  It gets its info
	// from the common paramaters that it expects.
	rq_svc_connect(service, NULL, NULL, NULL);
	
	// initialise the queue that we are consuming, provide callback handler.
	queue = rq_svc_getoption(service, 'q');
	assert(queue);
	assert(service->rq);
	rq_consume(service->rq, queue, 200, RQ_PRIORITY_NORMAL, 0, message_handler, NULL, NULL, control);

	// we also want to make sure that when we lose the connection to the
	// controller, we indicate that we lost connection to the queue, unless we
	// have already established another controller connection.

///============================================================================
/// Main Event Loop.
///============================================================================

	// enter the processing loop.  This function will not return until there is
	// nothing more to do and the service has shutdown.  Therefore everything
	// needs to be setup and running before this point.  Once inside the
	// rq_process function, everything is initiated by the RQ event system.
	assert(control != NULL);
	assert(control->evbase);
	event_base_loop(control->evbase, 0);

///============================================================================
/// Shutdown
///============================================================================

	assert(control);
	assert(control->evbase);
	event_base_free(control->evbase);
	control->evbase = NULL;

	// the rq service sub-system has no real way of knowing when the event-base
	// has been cleared, so we need to tell it.
	rq_svc_setevbase(service, NULL);
	control->rqsvc = NULL;


	// unload the config entries.
	assert(control);
	if (control->entries) {
		config_unload(control);
	}
	assert(control->entries == NULL);

	// make sure signal handlers have been cleared.
	assert(control);
	assert(control->sigint_event == NULL);
	assert(control->sighup_event == NULL);

	// cleanup risp library.
	assert(control);
	assert(control->risp);
	control->risp = risp_shutdown(control->risp);
	assert(control->risp == NULL);

	// we are done, cleanup what is left in the control structure.
	cleanup_control(control);
	free(control);

	rq_svc_cleanup(service);

	return 0;
}
Ejemplo n.º 8
0
int main(
    int argc,
    char **argv)
{
    char **skis;
    char inbuf[128];
    int numskis = 0;
    if (argc < 2)
        fatal("Usage: name of constraints file");
    FILE *str = fopen(argv[1], "r");
    if (!str)
        fatal("Can't open %s", argv[1]);
    FILE *tmpstr;
    char *f = "xproof.tmp";
    int i = 0;
    struct keyring keyring = { NULL, NULL, NULL };

    OPEN_LOG("proofreader", LOG_USER);

    if (!my_config_load())
    {
        LOG(LOG_ERR, "can't load configuration");
        exit(EXIT_FAILURE);
    }

    if (!(tmpstr = fopen(f, "w+")))
        fatal("Can't open %s", f);

    if (parse_SKI_blocks(&keyring, str, argv[1], inbuf, sizeof(inbuf), &i) < 0)
        fatal("Invalid line: %s", errbuf);
    fseek(str, (long)0, 0);
    *inbuf = 0;
    while (1)
    {
        if (!fgets(inbuf, sizeof(inbuf), str))
            abort();
        if (!strncmp(inbuf, "SKI ", 4))
            break;
        fputs(inbuf, tmpstr);
    }
    char *c;
    do                          // starting with first SKI line
    {
        for (c = &inbuf[4]; *c && ((*c >= '0' && *c <= '9') || *c == ':' ||
                                   (*c >= 'A' && *c <= 'F') || (*c >= 'a'
                                                                && *c <= 'f'));
             c++);
        if (c != &inbuf[63])
            fatal("Invalid line: %s", inbuf);
        while (*c == ' ' || *c == '\t')
            c++;
        if (*c != '\n')
            fatal("Invalid line: %s", inbuf);
        if (numskis)
        {
            int num;
            for (num = 0; num < numskis && strcmp(inbuf, skis[num]); num++);
            if (num < numskis)
                fatal("Duplicate SKI: %s ", &inbuf[4]);
        }
        if (!numskis)
            skis = (char **)calloc(2, sizeof(char *));
        else
            skis = (char **)realloc(skis, (sizeof(char *) * (numskis + 2)));
        skis[numskis] = calloc(1, strlen(inbuf) + 2);
        strcpy(skis[numskis], inbuf);
        numskis++;
        fputs(inbuf, tmpstr);
        // get IPv4 start
        if (!fgets(inbuf, sizeof(inbuf), str))
            fatal("Premature end of file");
        if (strcmp(inbuf, "IPv4\n"))
            fatal("Missing IPv4 line");
        fputs(inbuf, tmpstr);   // print v4 hdr
        // get first v4 line, if any
        if (!fgets(inbuf, sizeof(inbuf), str))
            fatal("Premature end of file");
        // process v4 entries, if any
        process_type(str, tmpstr, 4, inbuf, "IPv6\n");
        fputs(inbuf, tmpstr);   // print v6 hdr
        // get first v6 line, if any
        if (!fgets(inbuf, sizeof(inbuf), str))
            fatal("Premature end of file");
        process_type(str, tmpstr, 6, inbuf, "AS#\n");
        fputs(inbuf, tmpstr);   // print as# hdr
        // get first AS#, if any
        if (!(c = fgets(inbuf, sizeof(inbuf), str)))
            break;
        process_type(str, tmpstr, 8, inbuf, "SKI ");
    }
    while (*inbuf);
    if (warnings == 0)
    {
        LOG(LOG_INFO, "Finished %s OK", argv[1]);
    }
    else
    {
        LOG(LOG_ERR, "Had %d warnings. New file NOT created", warnings);
    }
    config_unload();
    CLOSE_LOG();
    return 0;
}
Ejemplo n.º 9
0
int main(
    int argc,
    char **argv)
{
    char *displays[MAX_VALS];
    char *clauses[MAX_CONDS];
    char *orderp = NULL;
    int i;
    err_code status;
    int numDisplays = 0;
    int numClauses = 0;

    OPEN_LOG("query", LOG_USER);
    if (!my_config_load())
    {
        LOG(LOG_ERR, "can't initialize configuration");
        exit(EXIT_FAILURE);
    }
    output = stdout;
    useLabels = 1;
    multiline = 0;
    validate = 1;
    if (argc == 1)
        return printUsage();
    if (strcasecmp(argv[1], "-l") == 0)
    {
        if (argc != 3)
            return printUsage();
        setObjectType(argv[2]);
        return listOptions();
    }
    for (i = 1; i < argc; i += 2)
    {
        if (strcasecmp(argv[i], "-i") == 0)
        {
            validate = 0;
            i--;
        }
        else if (strcasecmp(argv[i], "-n") == 0)
        {
            useLabels = 0;
            i--;
        }
        else if (strcasecmp(argv[i], "-m") == 0)
        {
            multiline = 1;
            i--;
        }
        else if (argc == (i + 1))
        {
            return printUsage();
        }
        else if (strcasecmp(argv[i], "-t") == 0)
        {
            setObjectType(argv[i + 1]);
        }
        else if (strcasecmp(argv[i], "-d") == 0)
        {
            displays[numDisplays++] = argv[i + 1];
        }
        else if (strcasecmp(argv[i], "-f") == 0)
        {
            clauses[numClauses++] = argv[i + 1];
        }
        else if (strcasecmp(argv[i], "-o") == 0)
        {
            output = fopen(argv[i + 1], "w");
        }
        else if (strcasecmp(argv[i], "-x") == 0)
        {
            orderp = argv[i + 1];
        }
        else
        {                       // unknown switch
            return printUsage();
        }
    }
    checkErr((!isROA) && (!isCRL) && (!isCert) &&
             (!isManifest) && (!isGBR), BAD_OBJECT_TYPE);
    checkErr(numDisplays == 0, "Need to display something\n");
    if (numDisplays == 1 && strcasecmp(displays[0], "all") == 0)
        numDisplays = addAllFields(displays, 0);
    displays[numDisplays++] = NULL;
    clauses[numClauses++] = NULL;
    status = doQuery(displays, clauses, orderp);
    if (status == ERR_SCM_NODATA)
    {
        LOG(LOG_DEBUG, "%s", err2string(status));
        status = 0;
    }
    else if (status < 0)
    {
        LOG(LOG_ERR, "%s", err2string(status));
    }
    config_unload();
    CLOSE_LOG();
    return status;
}
Ejemplo n.º 10
0
Archivo: rcli.c Proyecto: dseomn/rpstir
int main(
    int argc,
    char **argv)
{
    scmcon *testconp = NULL;
    scmcon *realconp = NULL;
    scm *scmp = NULL;
    FILE *sfile = NULL;
    char *thedelfile = NULL;
    char *topdir = NULL;
    char *thefile = NULL;
    char *outfile = NULL;
    char *outfull = NULL;
    char *outdir = NULL;
    char *tmpdsn = NULL;
    char *ne;
    char *porto = NULL;
    char errmsg[1024];
    char *skifile = NULL;
    int ians = 0;
    int do_create = 0;
    int do_delete = 0;
    int do_sockopts = 0;
    int do_fileopts = 0;
    int use_filelist = 0;
    int perpetual = 0;
    int really = 0;
    int trusted = 0;
    int force = 0;
    int allowex = 0;
    int sta = 0;
    int s;
    int c;

    (void)setbuf(stdout, NULL);
    if (argc <= 1)
    {
        usage();
        return (1);
    }
    while ((c = getopt(argc, argv, "t:xyhad:f:F:lLwz:pm:c:s")) != EOF)
    {
        switch (c)
        {
        case 'a':
            allowex = 1;
            break;
        case 't':
            do_create++;
            topdir = optarg;
            break;
        case 'x':
            do_delete++;
            break;
        case 'y':
            force++;
            break;
        case 'D':
            trusted++;
        case 'd':
            thedelfile = optarg;
            break;
        case 'F':
            trusted++;
        case 'f':
            thefile = optarg;
            break;
        case 'L':
            trusted++;
        case 'l':
            use_filelist++;
            break;
        case 'w':
            do_sockopts++;
            break;
        case 'z':
            do_fileopts++;
            porto = optarg;
            break;
        case 'p':
            perpetual++;
            break;
        case 'c':
            skifile = optarg;
            break;
        case 'h':
            usage();
            return (0);
        case 's':
            strict_profile_checks = 1;  // global from myssl.c
            strict_profile_checks_cms = 1;      // global from roa_validate.c
            break;
        default:
            (void)fprintf(stderr, "Invalid option '%c'\n", c);
            usage();
            return (1);
        }
    }
    // if there is anything left in argv, or no operation specified, warn user
    if (optind < argc)
    {
        (void)printf("Extra arguments at the end of the command line.\n");
        usage();
        return (1);
    }
    if ((do_create + do_delete + do_sockopts + do_fileopts) == 0 &&
            thefile == 0 && thedelfile == 0 && skifile == 0 && use_filelist == 0)
    {
        (void)printf("You need to specify at least one operation "
                     "(e.g. -f file).\n");
        usage();
        return (1);
    }
    OPEN_LOG("rcli", LOG_USER);
    if (!my_config_load())
    {
        LOG(LOG_ERR, "can't load configuration");
        exit(EXIT_FAILURE);
    }
    if (force == 0)
    {
        if (do_delete > 0)
        {
            ians = yorn("Do you REALLY want to delete all database tables");
            if (ians <= 0)
            {
                LOG(LOG_NOTICE, "Delete operation cancelled");
                return (1);
            }
            really++;
        }
        if ((do_create > 0) && (really == 0))
        {
            ians = yorn("Do you REALLY want to create all database tables");
            if (ians <= 0)
            {
                LOG(LOG_NOTICE, "Create operation cancelled");
                return (1);
            }
            really++;
        }
    }
    scmp = initscm();
    if (scmp == NULL)
    {
        LOG(LOG_ERR, "Internal error: cannot initialize database schema");
        return (-2);
    }
    /*
     * If a create or delete operation is being performed, then a test dsn
     * will be needed; create it now and defer the creation of the real dsn
     * until later. Otherwise, create the real dsn.
     *
     * A test dsn is needed for operations that operate on the overall
     * database state as opposed to the rpki tables, namely the create and
     * delete operations.
     */
    if ((do_create + do_delete) > 0)
    {
        /*
         * Note that in the following line, we do not intend to edit
         * the database named "information_schema".  We are simply
         * filling in the "database name" parameter with something
         * that is guaranteed to be valid for MySQL.
         */
        tmpdsn = makedsnscm(scmp->dsnpref, "information_schema",
                            CONFIG_DATABASE_USER_get(),
                            CONFIG_DATABASE_PASSWORD_get());
        if (tmpdsn == NULL)
        {
            membail();
            return (-1);
        }
        testconp = connectscm(tmpdsn, errmsg, 1024);
        memset(tmpdsn, 0, strlen(tmpdsn));
        free((void *)tmpdsn);
        if (testconp == NULL)
        {
            LOG(LOG_ERR, "Cannot connect to DSN: %s", errmsg);
            freescm(scmp);
            return (-1);
        }
    }
    else
    {
        realconp = connectscm(scmp->dsn, errmsg, 1024);
        if (realconp == NULL)
        {
            LOG(LOG_ERR, "Cannot connect to DSN %s: %s", scmp->dsn,
                errmsg);
            freescm(scmp);
            return (-1);
        }
    }
    /*
     * Process command line options in the following order: delete, create,
     * dofile, dodir, listener.
     */
    if (do_delete > 0)
        sta = deleteop(testconp, scmp);
    if ((do_create > 0) && (sta == 0))  /* first phase of create */
        sta = createop(testconp, scmp);
    /*
     * Don't need the test connection any more
     */
    if (testconp != NULL)
    {
        disconnectscm(testconp);
        testconp = NULL;
    }
    /*
     * If there has been an error or if we're done because the database was
     * just deleted and not re-created, bail out.
     */
    if (sta < 0 || (do_delete > 0 && do_create == 0))
    {
        if (realconp != NULL)
            disconnectscm(realconp);
        freescm(scmp);
        if (tdir != NULL)
            free((void *)tdir);
        return (sta);
    }
    /*
     * If a connection to the real DSN has not been opened yet, open it now.
     */
    if (realconp == NULL)
    {
        realconp = connectscm(scmp->dsn, errmsg, 1024);
        if (realconp == NULL)
        {
            LOG(LOG_ERR, "Cannot connect to DSN %s: %s",
                scmp->dsn, errmsg);
            freescm(scmp);
            if (tdir != NULL)
                free((void *)tdir);
            return (-1);
        }
    }
    /*
     * If a create operation was requested, complete it now.
     */
    if ((do_create > 0) && (sta == 0))
        sta = create2op(scmp, realconp, topdir);
    /*
     * If the top level repository directory is not set, then retrieve it from
     * the database.
     */
    if ((tdir == NULL) && (sta == 0))
    {
        tdir = retrieve_tdir(scmp, realconp, &sta);
        if (tdir == NULL)
            LOG(LOG_ERR,
                "Cannot retrieve top level repository info from DB");
    }
    if (sta == 0)
    {
        LOG(LOG_INFO, "Top level repository directory is %s", tdir);
        tdirlen = strlen(tdir);
    }
    /*
     * Setup for actual SSL operations
     */
    OpenSSL_add_all_algorithms();
    ERR_load_crypto_strings();
    LOG(LOG_NOTICE, "Rsync client session started");
    if (thefile != NULL && sta == 0)
    {
        // Check that the file is in the repository, ask if not and force is
        // off
        sta = splitdf(NULL, NULL, thefile, &outdir, &outfile, &outfull);
        if (sta == 0)
        {
            if (strncmp(tdir, outdir, tdirlen) != 0 && force == 0)
            {
                ians =
                    yorn("That file is not in the repository. Proceed anyway");
                if (ians <= 0)
                    sta = 1;
            }
            // if ( strstr(outdir, "TRUST") != NULL )
            // trusted++;
            // if the user has declared it to be trusted
            // ask for verification unless force is set
            if (trusted > 0 && force == 0 && sta == 0)
            {
                ians = yorn("Really declare this file as trusted");
                if (ians <= 0)
                    sta = 1;
            }
            if (sta == 1)
                LOG(LOG_NOTICE, "File operation cancelled");
            if (sta == 0)
            {
                LOG(LOG_INFO, "Attempting add: %s", outfile);
                setallowexpired(allowex);
                sta = add_object(scmp, realconp, outfile, outdir, outfull,
                                 trusted);
                if (sta < 0)
                {
                    LOG(LOG_ERR,
                        "Add failed: %s: error %s (%d)",
                        thefile, err2string(sta), sta);
                    if (sta == ERR_SCM_SQL)
                    {
                        ne = geterrorscm(realconp);
                        if (ne != NULL && ne != 0)
                            LOG(LOG_ERR, "\t%s", ne);
                    }
                }
                else
                    LOG(LOG_INFO, "Add succeeded: %s", outfile);
            }
            free((void *)outdir);
            free((void *)outfile);
            free((void *)outfull);
        }
        else
            LOG(LOG_ERR, "%s (%d)", err2string(sta), sta);
    }
    if (use_filelist > 0 && sta == 0)
    {
        char *line = NULL;
        size_t len = 0;
        ssize_t read;
        int status;

        setallowexpired(allowex);
        while ((read = getline(&line, &len, stdin)) != -1)
        {
            if (read == 0)
                continue;

            // Trim newline and skip line if empty
            if (line[read - 1] == '\n')
                line[read - 1] = '\0';
            if (strlen(line) == 0)
                continue;

            // Split directory and file components of path
            status = splitdf(NULL, NULL, line, &outdir, &outfile, &outfull);
            if (status != 0)
            {
                LOG(LOG_ERR, "%s (%d)", err2string(status), status);
                continue;
            }

            LOG(LOG_INFO, "Attempting add: %s", outfile);

            // Warn if file not within repository directory
            if (strncmp(tdir, outdir, tdirlen) != 0)
                LOG(LOG_WARNING, "%s is not in the repository", line);

            // Add
            status = add_object(scmp, realconp, outfile, outdir, outfull,
                                trusted);
            if (status == 0)
            {
                LOG(LOG_INFO, "Add succeeded: %s", outfile);
            }
            else
            {
                LOG(LOG_ERR, "Add failed: %s: error %s (%d)",
                    line, err2string(status), status);
                if (status == ERR_SCM_SQL)
                {
                    ne = geterrorscm(realconp);
                    if (ne != NULL && ne != 0)
                        LOG(LOG_ERR, "\t%s", ne);
                }
            }
            free((void *)outdir);
            free((void *)outfile);
            free((void *)outfull);
        }

        free(line);
    }
    if (thedelfile != NULL && sta == 0)
    {
        sta = splitdf(NULL, NULL, thedelfile, &outdir, &outfile, &outfull);
        if (sta == 0)
        {
            sta = delete_object(scmp, realconp, outfile, outdir, outfull, 0);
            if (sta < 0)
            {
                LOG(LOG_ERR,
                    "Could not delete file %s: error %s (%d)",
                    thedelfile, err2string(sta), sta);
                if (sta == ERR_SCM_SQL)
                {
                    ne = geterrorscm(realconp);
                    if (ne != NULL && ne != 0)
                        LOG(LOG_ERR, "\t%s", ne);
                }
            }
            else
                LOG(LOG_INFO, "Delete operation succeeded (%s removed)",
                    thedelfile);
            free((void *)outdir);
            free((void *)outfile);
            free((void *)outfull);
        }
        else
            LOG(LOG_ERR, "Error: %s (%d)", err2string(sta), sta);
    }
    if ((do_sockopts + do_fileopts) > 0 && sta == 0)
    {
        int protos = (-1);
        const int max_makesock_attempts = 10;
        int makesock_failures = 0;
        do
        {
            if (do_sockopts > 0)
            {
                uint16_t port = CONFIG_RPKI_PORT_get();
                s = makesock(port, &protos);
                if (s < 0)
                {
                    makesock_failures++;
                    LOG(LOG_ERR,
                        "Failed to listen on port %" PRIu16 " (failure #%d)", port,
                        makesock_failures);
                    sleep(1);
                    if (makesock_failures >= max_makesock_attempts)
                    {
                        LOG(LOG_ERR,
                            "%d failed attempts to create socket. Aborting.",
                            max_makesock_attempts);
                        sta = -1;
                        break;
                    }
                }
                else
                {
                    makesock_failures = 0;
                    FLUSH_LOG();
                    sta = sockline(scmp, realconp, s);
                    LOG(LOG_INFO, "Socket connection closed");
                    FLUSH_LOG();
                    (void)close(s);
                }
            }
            if (do_fileopts > 0 && porto != NULL)
            {
                if (!isatty(0))
                {
                    LOG(LOG_DEBUG, "Opening stdin");
                    sfile = stdin;
                    sta = fileline(scmp, realconp, sfile);
                }
                else
                {
                    LOG(LOG_DEBUG, "Opening a socket cmdfile %s", porto);
                    sfile = fopen(porto, "r");
                    if (sfile == NULL)
                        LOG(LOG_ERR, "Could not open cmdfile");
                    else
                    {
                        sta = fileline(scmp, realconp, sfile);
                        LOG(LOG_DEBUG, "Cmdfile closed");
                        (void)fclose(sfile);
                    }
                }
            }
            if (sta == 0 && skifile)
            {
                LOG(LOG_DEBUG, "Starting skifile %s", skifile);
                sta = read_SKI_blocks(scmp, realconp, skifile);
                if (sta > 0)
                    sta = 0;
                if (sta)
                    LOG(LOG_ERR, "Error with skifile: %s (%d)",
                        err2string(sta), sta);
            }
        } while (perpetual > 0);
        if (protos >= 0)
            (void)close(protos);
    }
    if (sta == 0 && skifile)
    {
        LOG(LOG_DEBUG, "Starting skifile %s", skifile);
        sta = read_SKI_blocks(scmp, realconp, skifile);
        if (sta > 0)
            sta = 0;
        if (sta)
            LOG(LOG_ERR, "Error with skifile: %s (%d)", err2string(sta),
                sta);
    }
    (void)ranlast(scmp, realconp, "RSYNC");
    sqcleanup();
    if (realconp != NULL)
        disconnectscm(realconp);
    freescm(scmp);
    if (tdir != NULL)
        free((void *)tdir);
    LOG(LOG_NOTICE, "Rsync client session ended");
    config_unload();
    CLOSE_LOG();
    return (sta);
}