Esempio n. 1
0
/**
 *  Free the dynamic memory used to store fetch requests
 */
static void free_fetch_request(fetch_req_t *req)
{
    req->distributionPoints->destroy_function(req->distributionPoints, free);
    DESTROY_IF(req->issuer);
    free(req->authKeyID.ptr);
    free(req);
}
Esempio n. 2
0
/**
 * Create or replace a pool by name
 */
static u_int create_pool(char *name, chunk_t start, chunk_t end, int timeout)
{
	enumerator_t *e;
	int pool;

	e = db->query(db, "SELECT id FROM pools WHERE name = ?",
			DB_TEXT, name, DB_UINT);
	if (e && e->enumerate(e, &pool))
	{
		if (replace_pool == FALSE)
		{
			fprintf(stderr, "pool '%s' exists.\n", name);
			e->destroy(e);
			exit(EXIT_FAILURE);
		}
		del(name);
	}
	DESTROY_IF(e);
	if (db->execute(db, &pool,
			"INSERT INTO pools (name, start, end, timeout) VALUES (?, ?, ?, ?)",
			DB_TEXT, name, DB_BLOB, start, DB_BLOB, end,
			DB_INT, timeout*3600) != 1)
	{
		fprintf(stderr, "creating pool failed.\n");
		exit(EXIT_FAILURE);
	}

	return pool;
}
Esempio n. 3
0
/**
 *  Free myid module
 */
void free_myid(void)
{
	enum myid_state s;

	for (s = MYID_UNKNOWN; s <= MYID_SPECIFIED; s++)
	{
		DESTROY_IF(myids[s]);
	}
}
Esempio n. 4
0
/*
 * Described in header
 */
bool botan_get_fingerprint(botan_pubkey_t pubkey, void *cache,
						   cred_encoding_type_t type, chunk_t *fp)
{
	hasher_t *hasher;
	chunk_t key;

	if (cache &&
		lib->encoding->get_cache(lib->encoding, type, cache, fp))
	{
		return TRUE;
	}

	switch (type)
	{
		case KEYID_PUBKEY_SHA1:
			/* subjectPublicKey -> use botan_pubkey_fingerprint() */
			*fp = chunk_alloc(HASH_SIZE_SHA1);
			if (botan_pubkey_fingerprint(pubkey, "SHA-1", fp->ptr, &fp->len))
			{
				chunk_free(fp);
				return FALSE;
			}
			break;
		case KEYID_PUBKEY_INFO_SHA1:
			/* subjectPublicKeyInfo -> use botan_pubkey_export(), then hash */
			if (!botan_get_encoding(pubkey, PUBKEY_SPKI_ASN1_DER, &key))
			{
				return FALSE;
			}

			hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1);
			if (!hasher || !hasher->allocate_hash(hasher, key, fp))
			{
				DBG1(DBG_LIB, "SHA1 hash algorithm not supported, "
					 "fingerprinting failed");
				DESTROY_IF(hasher);
				chunk_free(&key);
				return FALSE;
			}
			hasher->destroy(hasher);
			chunk_free(&key);
			break;
		default:
			return FALSE;
	}

	if (cache)
	{
		lib->encoding->cache(lib->encoding, type, cache, *fp);
	}
	return TRUE;
}
Esempio n. 5
0
/**
 * see section 3.8.9 of TCG TNC IF-IMV Specification 1.3
 */
TNC_Result TNC_IMV_Terminate(TNC_IMVID imv_id)
{
	if (!imv_attestation)
	{
		DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name);
		return TNC_RESULT_NOT_INITIALIZED;
	}
	if (pts_creds)
	{
		pts_credmgr->remove_set(pts_credmgr, pts_creds->get_set(pts_creds));
		pts_creds->destroy(pts_creds);
	}
	DESTROY_IF(pts_db);
	DESTROY_IF(pts_credmgr);

	libpts_deinit();

	imv_attestation->destroy(imv_attestation);
	imv_attestation = NULL;

	return TNC_RESULT_SUCCESS;
}
Esempio n. 6
0
/**
 * Described in header.
 */
void libimcv_deinit(void)
{
	if (ref_put(&libimcv_ref))
	{
		imcv_pts_components->remove_vendor(imcv_pts_components, PEN_TCG);
		imcv_pts_components->remove_vendor(imcv_pts_components, PEN_ITA);
		imcv_pts_components->destroy(imcv_pts_components);

		imcv_pa_tnc_attributes->remove_vendor(imcv_pa_tnc_attributes, PEN_IETF);
		imcv_pa_tnc_attributes->remove_vendor(imcv_pa_tnc_attributes, PEN_ITA);
		imcv_pa_tnc_attributes->remove_vendor(imcv_pa_tnc_attributes, PEN_TCG);
		DESTROY_IF(imcv_pa_tnc_attributes);
		imcv_pa_tnc_attributes = NULL;
		DESTROY_IF(imcv_db);
		DESTROY_IF(imcv_sessions);
		DBG1(DBG_LIB, "libimcv terminated");
	}
	if (ref_put(&libstrongswan_ref))
	{
		library_deinit();
	}
}
Esempio n. 7
0
/**
 * atexit() cleanup handler
 */
static void cleanup()
{
	file_logger_t *logger;
	hook_t *hook;

	DESTROY_IF(conftest->test);
	lib->credmgr->remove_set(lib->credmgr, &conftest->creds->set);
	conftest->creds->destroy(conftest->creds);
	DESTROY_IF(conftest->actions);
	while (conftest->hooks->remove_last(conftest->hooks,
										(void**)&hook) == SUCCESS)
	{
		charon->bus->remove_listener(charon->bus, &hook->listener);
		hook->destroy(hook);
	}
	conftest->hooks->destroy(conftest->hooks);
	if (conftest->config)
	{
		if (charon->backends)
		{
			charon->backends->remove_backend(charon->backends,
											 &conftest->config->backend);
		}
		conftest->config->destroy(conftest->config);
	}
	while (conftest->loggers->remove_last(conftest->loggers,
										  (void**)&logger) == SUCCESS)
	{
		charon->bus->remove_logger(charon->bus, &logger->logger);
		logger->destroy(logger);
	}
	conftest->loggers->destroy(conftest->loggers);
	free(conftest->suite_dir);
	free(conftest);
	libcharon_deinit();
	libhydra_deinit();
	library_deinit();
}
Esempio n. 8
0
/**
 * see section 3.8.9 of TCG TNC IF-IMV Specification 1.3
 */
TNC_Result TNC_IMV_Terminate(TNC_IMVID imv_id)
{
	if (!imv_os)
	{
		DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name);
		return TNC_RESULT_NOT_INITIALIZED;
	}
	DESTROY_IF(os_db);

	imv_os->destroy(imv_os);
	imv_os = NULL;

	return TNC_RESULT_SUCCESS;
}
Esempio n. 9
0
/**
 * Described in header.
 */
void libimcv_deinit(void)
{
	if (ref_put(&libimcv_ref))
	{
		imcv_pa_tnc_attributes->remove_vendor(imcv_pa_tnc_attributes, PEN_IETF);
		imcv_pa_tnc_attributes->remove_vendor(imcv_pa_tnc_attributes, PEN_ITA);
		DESTROY_IF(imcv_pa_tnc_attributes);
		DBG1(DBG_LIB, "libimcv terminated");
	}
	if (ref_put(&libstrongswan_ref))
	{
		library_deinit();		
	}
}
Esempio n. 10
0
/**
 * Generates a unique fingerprint of the pkcs10 request
 * by computing an MD5 hash over it
 */
chunk_t scep_generate_pkcs10_fingerprint(chunk_t pkcs10)
{
	chunk_t digest = chunk_alloca(HASH_SIZE_MD5);
	hasher_t *hasher;

	hasher = lib->crypto->create_hasher(lib->crypto, HASH_MD5);
	if (!hasher || !hasher->get_hash(hasher, pkcs10, digest.ptr))
	{
		DESTROY_IF(hasher);
		return chunk_empty;
	}
	hasher->destroy(hasher);

	return chunk_to_hex(digest, NULL, FALSE);
}
Esempio n. 11
0
/**
 * Load certificate distribution points
 */
static void load_cdps(settings_t *settings)
{
	enumerator_t *enumerator;
	identification_t *id;
	char *ca, *uri, *section;
	certificate_type_t type;
	x509_t *x509;

	enumerator = settings->create_section_enumerator(settings, "cdps");
	while (enumerator->enumerate(enumerator, &section))
	{
		if (strncaseeq(section, "crl", strlen("crl")))
		{
			type = CERT_X509_CRL;
		}
		else if (strncaseeq(section, "ocsp", strlen("ocsp")))
		{
			type = CERT_X509_OCSP_RESPONSE;
		}
		else
		{
			fprintf(stderr, "unknown cdp type '%s', ignored\n", section);
			continue;
		}

		uri = settings->get_str(settings, "cdps.%s.uri", NULL, section);
		ca = settings->get_str(settings, "cdps.%s.ca", NULL, section);
		if (!ca || !uri)
		{
			fprintf(stderr, "cdp '%s' misses ca/uri, ignored\n", section);
			continue;
		}
		x509 = lib->creds->create(lib->creds, CRED_CERTIFICATE,
							CERT_X509, BUILD_FROM_FILE, ca, BUILD_END);
		if (!x509)
		{
			fprintf(stderr, "loading cdp '%s' ca failed, ignored\n", section);
			continue;
		}
		id = identification_create_from_encoding(ID_KEY_ID,
									x509->get_subjectKeyIdentifier(x509));
		conftest->creds->add_cdp(conftest->creds, type, id, uri);
		DESTROY_IF((certificate_t*)x509);
		id->destroy(id);
	}
	enumerator->destroy(enumerator);
}
Esempio n. 12
0
/**
 * Adds a senderNonce attribute to the given pkcs9 attribute list
 */
static bool add_senderNonce_attribute(pkcs9_t *pkcs9)
{
	const size_t nonce_len = 16;
	u_char nonce_buf[nonce_len];
	chunk_t senderNonce = { nonce_buf, nonce_len };
	rng_t *rng;

	rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
	if (!rng || !rng->get_bytes(rng, nonce_len, nonce_buf))
	{
		DESTROY_IF(rng);
		return FALSE;
	}
	rng->destroy(rng);

	pkcs9->set_attribute(pkcs9, OID_PKI_SENDER_NONCE, senderNonce);
	return TRUE;
}
Esempio n. 13
0
/**
 * @brief exit scepclient
 *
 * @param status 0 = OK, 1 = general discomfort
 */
static void exit_scepclient(err_t message, ...)
{
    int status = 0;

    if (creds)
    {
        lib->credmgr->remove_set(lib->credmgr, &creds->set);
        creds->destroy(creds);
    }

    DESTROY_IF(subject);
    DESTROY_IF(private_key);
    DESTROY_IF(public_key);
    DESTROY_IF(x509_signer);
    DESTROY_IF(x509_ca_enc);
    DESTROY_IF(x509_ca_sig);
    DESTROY_IF(pkcs10_req);
    subjectAltNames->destroy_offset(subjectAltNames,
                                    offsetof(identification_t, destroy));
    free(pkcs1.ptr);
    free(pkcs7.ptr);
    free(serialNumber.ptr);
    free(transID.ptr);
    free(fingerprint.ptr);
    free(encoding.ptr);
    free(pkcs10_encoding.ptr);
    free(issuerAndSubject.ptr);
    free(getCertInitial.ptr);
    free(scep_response.ptr);
    options->destroy(options);

    /* print any error message to stderr */
    if (message != NULL && *message != '\0')
    {
        va_list args;
        char m[8192];

        va_start(args, message);
        vsnprintf(m, sizeof(m), message, args);
        va_end(args);

        fprintf(stderr, "error: %s\n", m);
        status = -1;
    }
    library_deinit();
    exit(status);
}
Esempio n. 14
0
err_t scep_parse_response(chunk_t response, chunk_t transID, pkcs7_t **data,
						  scep_attributes_t *attrs, certificate_t *signer_cert)
{
	pkcs7_t *pkcs7;

	pkcs7 = pkcs7_create_from_chunk(response, 0);
	if (!pkcs7 || !pkcs7->parse_signedData(pkcs7, signer_cert))
	{
		DESTROY_IF(pkcs7);
		return "error parsing the scep response";
	}
	extract_attributes(pkcs7, attrs);
	if (!chunk_equals(transID, attrs->transID))
	{
		pkcs7->destroy(pkcs7);
		return "transaction ID of scep response does not match";
	}
	*data = pkcs7;
	return NULL;
}
Esempio n. 15
0
/**
 * Generate a transaction id as the MD5 hash of an public key
 * the transaction id is also used as a unique serial number
 */
void scep_generate_transaction_id(public_key_t *key, chunk_t *transID,
								  chunk_t *serialNumber)
{
	chunk_t digest = chunk_alloca(HASH_SIZE_MD5);
	chunk_t keyEncoding = chunk_empty, keyInfo;
	hasher_t *hasher;
	bool msb_set;
	u_char *pos;

	key->get_encoding(key, PUBKEY_ASN1_DER, &keyEncoding);

	keyInfo = asn1_wrap(ASN1_SEQUENCE, "mm",
						asn1_algorithmIdentifier(OID_RSA_ENCRYPTION),
						asn1_bitstring("m", keyEncoding));

	hasher = lib->crypto->create_hasher(lib->crypto, HASH_MD5);
	if (!hasher || !hasher->get_hash(hasher, keyInfo, digest.ptr))
	{
		memset(digest.ptr, 0, digest.len);
	}
	DESTROY_IF(hasher);
	free(keyInfo.ptr);

	/* is the most significant bit of the digest set? */
	msb_set = (*digest.ptr & 0x80) == 0x80;

	/* allocate space for the serialNumber */
	serialNumber->len = msb_set + digest.len;
	serialNumber->ptr = malloc(serialNumber->len);

	/* the serial number as the two's complement of the digest */
	pos = serialNumber->ptr;
	if (msb_set)
	{
		*pos++ = 0x00;
	}
	memcpy(pos, digest.ptr, digest.len);

	/* the transaction id is the serial number in hex format */
	*transID = chunk_to_hex(digest, NULL, TRUE);
}
Esempio n. 16
0
/**
 * Lookup/insert an identity
 */
u_int get_identity(identification_t *id)
{
	enumerator_t *e;
	u_int row;

	/* look for peer identity in the identities table */
	e = db->query(db, "SELECT id FROM identities WHERE type = ? AND data = ?",
			DB_INT, id->get_type(id), DB_BLOB, id->get_encoding(id), DB_UINT);
	if (e && e->enumerate(e, &row))
	{
		e->destroy(e);
		return row;
	}
	DESTROY_IF(e);
	/* not found, insert new one */
	if (db->execute(db, &row, "INSERT INTO identities (type,data) VALUES (?,?)",
				  DB_INT, id->get_type(id), DB_BLOB, id->get_encoding(id)) != 1)
	{
		fprintf(stderr, "creating id '%Y' failed.\n", id);
		return 0;
	}
	return row;
}
Esempio n. 17
0
/**
 * Lookup/insert an attribute pool by name
 */
static u_int get_attr_pool(char *name)
{
	enumerator_t *e;
	u_int row = 0;

	/* look for an existing attribute pool in the table */
	e = db->query(db, "SELECT id FROM attribute_pools WHERE name = ?",
				  DB_TEXT, name, DB_UINT);
	if (e && e->enumerate(e, &row))
	{
		e->destroy(e);
		return row;
	}
	DESTROY_IF(e);
	/* not found, insert new one */
	if (db->execute(db, &row, "INSERT INTO attribute_pools (name) VALUES (?)",
					DB_TEXT, name) != 1)
	{
		fprintf(stderr, "creating attribute pool '%s' failed.\n", name);
		return 0;
	}
	return row;
}
Esempio n. 18
0
/**
 * Load an encrypted private key from an ASN.1 encoded blob
 * Schemes per PKCS#5 (RFC 2898)
 */
static private_key_t *parse_encrypted_private_key(chunk_t blob)
{
	asn1_parser_t *parser;
	chunk_t object;
	int objectID;
	private_key_t *key = NULL;
	pkcs5_t *pkcs5 = NULL;

	parser = asn1_parser_create(encryptedPKIObjects, blob);

	while (parser->iterate(parser, &objectID, &object))
	{
		switch (objectID)
		{
			case EPKINFO_ENCRYPTION_ALGORITHM:
			{
				pkcs5 = pkcs5_from_algorithmIdentifier(object,
												parser->get_level(parser) + 1);
				if (!pkcs5)
				{
					goto end;
				}
				break;
			}
			case EPKINFO_ENCRYPTED_DATA:
			{
				key = decrypt_private_key(pkcs5, object);
				break;
			}
		}
	}

end:
	DESTROY_IF(pkcs5);
	parser->destroy(parser);
	return key;
}
Esempio n. 19
0
/**
 * atexit handler to close db on shutdown
 */
static void cleanup(void)
{
	db->destroy(db);
	DESTROY_IF(start);
	DESTROY_IF(end);
}
Esempio n. 20
0
int main(int argc, char *argv[])
{
    char *address = NULL;
    bool listen = FALSE;
    int port = 0, times = -1, res;
    identification_t *server, *client;
    tls_cache_t *cache;
    host_t *host;

    init();

    while (TRUE)
    {
        struct option long_opts[] = {
            {"help",		no_argument,			NULL,		'h' },
            {"connect",		required_argument,		NULL,		'c' },
            {"listen",		required_argument,		NULL,		'l' },
            {"port",		required_argument,		NULL,		'p' },
            {"cert",		required_argument,		NULL,		'x' },
            {"key",			required_argument,		NULL,		'k' },
            {"times",		required_argument,		NULL,		't' },
            {"debug",		required_argument,		NULL,		'd' },
            {0,0,0,0 }
        };
        switch (getopt_long(argc, argv, "", long_opts, NULL))
        {
        case EOF:
            break;
        case 'h':
            usage(stdout, argv[0]);
            return 0;
        case 'x':
            if (!load_certificate(optarg))
            {
                return 1;
            }
            continue;
        case 'k':
            if (!load_key(optarg))
            {
                return 1;
            }
            continue;
        case 'l':
            listen = TRUE;
        /* fall */
        case 'c':
            if (address)
            {
                usage(stderr, argv[0]);
                return 1;
            }
            address = optarg;
            continue;
        case 'p':
            port = atoi(optarg);
            continue;
        case 't':
            times = atoi(optarg);
            continue;
        case 'd':
            tls_level = atoi(optarg);
            continue;
        default:
            usage(stderr, argv[0]);
            return 1;
        }
        break;
    }
    if (!port || !address)
    {
        usage(stderr, argv[0]);
        return 1;
    }
    host = host_create_from_dns(address, 0, port);
    if (!host)
    {
        DBG1(DBG_TLS, "resolving hostname %s failed", address);
        return 1;
    }
    server = identification_create_from_string(address);
    cache = tls_cache_create(100, 30);
    if (listen)
    {
        res = serve(host, server, times, cache);
    }
    else
    {
        client = find_client_id();
        res = run_client(host, server, client, times, cache);
        DESTROY_IF(client);
    }
    cache->destroy(cache);
    host->destroy(host);
    server->destroy(server);
    return res;
}
Esempio n. 21
0
/**
 * @brief openac main program
 *
 * @param argc number of arguments
 * @param argv pointer to the argument values
 */
int main(int argc, char **argv)
{
	certificate_t *attr_cert   = NULL;
	certificate_t *userCert   = NULL;
	certificate_t *signerCert = NULL;
	private_key_t *signerKey  = NULL;

	time_t notBefore = UNDEFINED_TIME;
	time_t notAfter  = UNDEFINED_TIME;
	time_t validity = 0;

	char *keyfile = NULL;
	char *certfile = NULL;
	char *usercertfile = NULL;
	char *outfile = NULL;
	char *groups = "";
	char buf[BUF_LEN];

	chunk_t passphrase = { buf, 0 };
	chunk_t serial = chunk_empty;
	chunk_t attr_chunk = chunk_empty;

	int status = 1;

	/* enable openac debugging hook */
	dbg = openac_dbg;

	passphrase.ptr[0] = '\0';

	openlog("openac", 0, LOG_AUTHPRIV);

	/* initialize library */
	atexit(library_deinit);
	if (!library_init(NULL))
	{
		exit(SS_RC_LIBSTRONGSWAN_INTEGRITY);
	}
	if (lib->integrity &&
		!lib->integrity->check_file(lib->integrity, "openac", argv[0]))
	{
		fprintf(stderr, "integrity check of openac failed\n");
		exit(SS_RC_DAEMON_INTEGRITY);
	}
	if (!lib->plugins->load(lib->plugins,
			lib->settings->get_str(lib->settings, "openac.load", PLUGINS)))
	{
		exit(SS_RC_INITIALIZATION_FAILED);
	}

	/* initialize optionsfrom */
	options_t *options = options_create();

	/* handle arguments */
	for (;;)
	{
		static const struct option long_opts[] = {
			/* name, has_arg, flag, val */
			{ "help", no_argument, NULL, 'h' },
			{ "version", no_argument, NULL, 'v' },
			{ "optionsfrom", required_argument, NULL, '+' },
			{ "quiet", no_argument, NULL, 'q' },
			{ "cert", required_argument, NULL, 'c' },
			{ "key", required_argument, NULL, 'k' },
			{ "password", required_argument, NULL, 'p' },
			{ "usercert", required_argument, NULL, 'u' },
			{ "groups", required_argument, NULL, 'g' },
			{ "days", required_argument, NULL, 'D' },
			{ "hours", required_argument, NULL, 'H' },
			{ "startdate", required_argument, NULL, 'S' },
			{ "enddate", required_argument, NULL, 'E' },
			{ "out", required_argument, NULL, 'o' },
			{ "debug", required_argument, NULL, 'd' },
			{ 0,0,0,0 }
		};

		int c = getopt_long(argc, argv, "hv+:qc:k:p;u:g:D:H:S:E:o:d:", long_opts, NULL);

		/* Note: "breaking" from case terminates loop */
		switch (c)
		{
			case EOF:	/* end of flags */
				break;

			case 0: /* long option already handled */
				continue;

			case ':':	/* diagnostic already printed by getopt_long */
			case '?':	/* diagnostic already printed by getopt_long */
			case 'h':	/* --help */
				usage(NULL);
				status = 1;
				goto end;

			case 'v':	/* --version */
				printf("openac (strongSwan %s)\n", VERSION);
				status = 0;
				goto end;

			case '+':	/* --optionsfrom <filename> */
				{
					char path[BUF_LEN];

					if (*optarg == '/')	/* absolute pathname */
					{
						strncpy(path, optarg, BUF_LEN);
						path[BUF_LEN-1] = '\0';
					}
					else			/* relative pathname */
					{
						snprintf(path, BUF_LEN, "%s/%s", OPENAC_PATH, optarg);
					}
					if (!options->from(options, path, &argc, &argv, optind))
					{
						status = 1;
						goto end;
					}
				}
				continue;

			case 'q':	/* --quiet */
				stderr_quiet = TRUE;
				continue;

			case 'c':	/* --cert */
				certfile = optarg;
				continue;

			case 'k':	/* --key */
				keyfile = optarg;
				continue;

			case 'p':	/* --key */
				if (strlen(optarg) >= BUF_LEN)
				{
					usage("passphrase too long");
					goto end;
				}
				strncpy(passphrase.ptr, optarg, BUF_LEN);
				passphrase.len = min(strlen(optarg), BUF_LEN);
				continue;

			case 'u':	/* --usercert */
				usercertfile = optarg;
				continue;

			case 'g':	/* --groups */
				groups = optarg;
				continue;

			case 'D':	/* --days */
				if (optarg == NULL || !isdigit(optarg[0]))
				{
					usage("missing number of days");
					goto end;
				}
				else
				{
					char *endptr;
					long days = strtol(optarg, &endptr, 0);

					if (*endptr != '\0' || endptr == optarg || days <= 0)
					{
						usage("<days> must be a positive number");
						goto end;
					}
					validity += 24*3600*days;
				}
				continue;

			case 'H':	/* --hours */
				if (optarg == NULL || !isdigit(optarg[0]))
				{
					usage("missing number of hours");
					goto end;
				}
				else
				{
					char *endptr;
					long hours = strtol(optarg, &endptr, 0);

					if (*endptr != '\0' || endptr == optarg || hours <= 0)
					{
						usage("<hours> must be a positive number");
						goto end;
					}
					validity += 3600*hours;
				}
				continue;

			case 'S':	/* --startdate */
				if (optarg == NULL || strlen(optarg) != 15 || optarg[14] != 'Z')
				{
					usage("date format must be YYYYMMDDHHMMSSZ");
					goto end;
				}
				else
				{
					chunk_t date = { optarg, 15 };

					notBefore = asn1_to_time(&date, ASN1_GENERALIZEDTIME);
				}
				continue;

			case 'E':	/* --enddate */
				if (optarg == NULL || strlen(optarg) != 15 || optarg[14] != 'Z')
				{
					usage("date format must be YYYYMMDDHHMMSSZ");
					goto end;
				}
				else
				{
					chunk_t date = { optarg, 15 };
					notAfter = asn1_to_time(&date, ASN1_GENERALIZEDTIME);
				}
				continue;

			case 'o':	/* --out */
				outfile = optarg;
				continue;

			case 'd':	/* --debug */
				debug_level = atoi(optarg);
				continue;

			default:
				usage("");
				status = 0;
				goto end;
		}
		/* break from loop */
		break;
	}

	if (optind != argc)
	{
		usage("unexpected argument");
		goto end;
	}

	DBG1(DBG_LIB, "starting openac (strongSwan Version %s)", VERSION);

	/* load the signer's RSA private key */
	if (keyfile != NULL)
	{
		mem_cred_t *mem;
		shared_key_t *shared;

		mem = mem_cred_create();
		lib->credmgr->add_set(lib->credmgr, &mem->set);
		shared = shared_key_create(SHARED_PRIVATE_KEY_PASS,
								   chunk_clone(passphrase));
		mem->add_shared(mem, shared, NULL);
		signerKey = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_RSA,
									   BUILD_FROM_FILE, keyfile,
									   BUILD_END);
		lib->credmgr->remove_set(lib->credmgr, &mem->set);
		mem->destroy(mem);
		if (signerKey == NULL)
		{
			goto end;
		}
		DBG1(DBG_LIB, "  loaded private key file '%s'", keyfile);
	}

	/* load the signer's X.509 certificate */
	if (certfile != NULL)
	{
		signerCert = lib->creds->create(lib->creds,
										CRED_CERTIFICATE, CERT_X509,
										BUILD_FROM_FILE, certfile,
										BUILD_END);
		if (signerCert == NULL)
		{
			goto end;
		}
	}

	/* load the users's X.509 certificate */
	if (usercertfile != NULL)
	{
		userCert = lib->creds->create(lib->creds,
									  CRED_CERTIFICATE, CERT_X509,
									  BUILD_FROM_FILE, usercertfile,
									  BUILD_END);
		if (userCert == NULL)
		{
			goto end;
		}
	}

	/* compute validity interval */
	validity = (validity)? validity : DEFAULT_VALIDITY;
	notBefore = (notBefore == UNDEFINED_TIME) ? time(NULL) : notBefore;
	notAfter =  (notAfter  == UNDEFINED_TIME) ? time(NULL) + validity : notAfter;

	/* build and parse attribute certificate */
	if (userCert != NULL && signerCert != NULL && signerKey != NULL &&
		outfile != NULL)
	{
		/* read the serial number and increment it by one */
		serial = read_serial();

		attr_cert = lib->creds->create(lib->creds,
							CRED_CERTIFICATE, CERT_X509_AC,
							BUILD_CERT, userCert,
							BUILD_NOT_BEFORE_TIME, notBefore,
							BUILD_NOT_AFTER_TIME, notAfter,
							BUILD_SERIAL, serial,
							BUILD_IETF_GROUP_ATTR, groups,
							BUILD_SIGNING_CERT, signerCert,
							BUILD_SIGNING_KEY, signerKey,
							BUILD_END);
		if (!attr_cert)
		{
			goto end;
		}

		/* write the attribute certificate to file */
		if (attr_cert->get_encoding(attr_cert, CERT_ASN1_DER, &attr_chunk))
		{
			if (chunk_write(attr_chunk, outfile, 0022, TRUE))
			{
				DBG1(DBG_APP, "  written attribute cert file '%s' (%d bytes)",
						 outfile, attr_chunk.len);
				write_serial(serial);
				status = 0;
			}
			else
			{
				DBG1(DBG_APP, "  writing attribute cert file '%s' failed: %s",
					 outfile, strerror(errno));
			}
		}
	}
	else
	{
		usage("some of the mandatory parameters --usercert --cert --key --out "
			  "are missing");
	}

end:
	/* delete all dynamically allocated objects */
	DESTROY_IF(signerKey);
	DESTROY_IF(signerCert);
	DESTROY_IF(userCert);
	DESTROY_IF(attr_cert);
	free(attr_chunk.ptr);
	free(serial.ptr);
	closelog();
	dbg = dbg_default;
	options->destroy(options);
	exit(status);
}
Esempio n. 22
0
/**
 * Clean up credentials atexit()
 */
static void cleanup_creds()
{
	DESTROY_IF(creds);
}
Esempio n. 23
0
/**
 * ipsec pool --status - show pool overview
 */
static void status(void)
{
	enumerator_t *ns, *pool, *lease;
	host_t *server;
	chunk_t value;
	bool found = FALSE;

	/* enumerate IPv4 DNS servers */
	ns = db->query(db, "SELECT value FROM attributes WHERE type = ?",
				   DB_INT, INTERNAL_IP4_DNS, DB_BLOB);
	if (ns)
	{
		while (ns->enumerate(ns, &value))
		{
			if (!found)
			{
				printf("dns servers:");
				found = TRUE;
			}
			server = host_create_from_chunk(AF_INET, value, 0);
			if (server)
			{
				printf(" %H", server);
				server->destroy(server);
			}
		}
		ns->destroy(ns);
	}

	/* enumerate IPv6 DNS servers */
	ns = db->query(db, "SELECT value FROM attributes WHERE type = ?",
				   DB_INT, INTERNAL_IP6_DNS, DB_BLOB);
	if (ns)
	{
		while (ns->enumerate(ns, &value))
		{
			if (!found)
			{
				printf("dns servers:");
				found = TRUE;
			}
			server = host_create_from_chunk(AF_INET6, value, 0);
			if (server)
			{
				printf(" %H", server);
				server->destroy(server);
			}
		}
		ns->destroy(ns);
	}
	if (found)
	{
		printf("\n");
	}
	else
	{
		printf("no dns servers found.\n");
	}
	found = FALSE;

	/* enumerate IPv4 NBNS servers */
	ns = db->query(db, "SELECT value FROM attributes WHERE type = ?",
				   DB_INT, INTERNAL_IP4_NBNS, DB_BLOB);
	if (ns)
	{
		while (ns->enumerate(ns, &value))
		{
			if (!found)
			{
				printf("nbns servers:");
				found = TRUE;
			}
			server = host_create_from_chunk(AF_INET, value, 0);
			if (server)
			{
				printf(" %H", server);
				server->destroy(server);
			}
		}
		ns->destroy(ns);
	}

	/* enumerate IPv6 NBNS servers */
	ns = db->query(db, "SELECT value FROM attributes WHERE type = ?",
				   DB_INT, INTERNAL_IP6_NBNS, DB_BLOB);
	if (ns)
	{
		while (ns->enumerate(ns, &value))
		{
			if (!found)
			{
				printf("nbns servers:");
				found = TRUE;
			}
			server = host_create_from_chunk(AF_INET6, value, 0);
			if (server)
			{
				printf(" %H", server);
				server->destroy(server);
			}
		}
		ns->destroy(ns);
	}
	if (found)
	{
		printf("\n");
	}
	else
	{
		printf("no nbns servers found.\n");
	}
	found = FALSE;

	pool = db->query(db, "SELECT id, name, start, end, timeout FROM pools",
					 DB_INT, DB_TEXT, DB_BLOB, DB_BLOB, DB_UINT);
	if (pool)
	{
		char *name;
		chunk_t start_chunk, end_chunk;
		host_t *start, *end;
		u_int id, timeout, online = 0, used = 0, size = 0;

		while (pool->enumerate(pool, &id, &name,
							   &start_chunk, &end_chunk, &timeout))
		{
			if (!found)
			{
				printf("%8s %15s %15s %8s %6s %11s %11s\n", "name", "start",
					   "end", "timeout", "size", "online", "usage");
				found = TRUE;
			}

			start = host_create_from_chunk(AF_UNSPEC, start_chunk, 0);
			end = host_create_from_chunk(AF_UNSPEC, end_chunk, 0);
			if (start->is_anyaddr(start) && end->is_anyaddr(end))
			{
				printf("%8s %15s %15s ", name, "n/a", "n/a");
			}
			else
			{
				printf("%8s %15H %15H ", name, start, end);
			}
			if (timeout)
			{
				printf("%7dh ", timeout/3600);
			}
			else
			{
				printf("%8s ", "static");
			}
			/* get total number of hosts in the pool */
			lease = db->query(db, "SELECT COUNT(*) FROM addresses "
							  "WHERE pool = ?", DB_UINT, id, DB_INT);
			if (lease)
			{
				lease->enumerate(lease, &size);
				lease->destroy(lease);
			}
			if (!size)
			{	/* empty pool */
				printf("%6d %11s %11s ", 0, "n/a", "n/a");
				goto next_pool;
			}
			printf("%6d ", size);
			/* get number of online hosts */
			lease = db->query(db, "SELECT COUNT(*) FROM addresses "
							  "WHERE pool = ? AND released = 0",
							  DB_UINT, id, DB_INT);
			if (lease)
			{
				lease->enumerate(lease, &online);
				lease->destroy(lease);
			}
			printf("%5d (%2d%%) ", online, online*100/size);
			/* get number of online or valid leases */
			lease = db->query(db, "SELECT COUNT(*) FROM addresses "
							  "WHERE addresses.pool = ? "
							  "AND ((? AND acquired != 0) "
							  "     OR released = 0 OR released > ?) ",
							  DB_UINT, id, DB_UINT, !timeout,
							  DB_UINT, time(NULL) - timeout, DB_UINT);
			if (lease)
			{
				lease->enumerate(lease, &used);
				lease->destroy(lease);
			}
			printf("%5d (%2d%%) ", used, used*100/size);

next_pool:
			printf("\n");
			DESTROY_IF(start);
			DESTROY_IF(end);
		}
		pool->destroy(pool);
	}
	if (!found)
	{
		printf("no pools found.\n");
	}
}
Esempio n. 24
0
/**
 * Clean up connection definition atexit()
 */
static void cleanup_conn()
{
	DESTROY_IF(conn);
}
Esempio n. 25
0
/**
 * ipsec pool --resize - resize a pool
 */
static void resize(char *name, host_t *end)
{
	enumerator_t *query;
	chunk_t old_addr, new_addr, cur_addr;
	u_int id, count;
	host_t *old_end;

	new_addr = end->get_address(end);

	query = db->query(db, "SELECT id, end FROM pools WHERE name = ?",
					  DB_TEXT, name, DB_UINT, DB_BLOB);
	if (!query || !query->enumerate(query, &id, &old_addr))
	{
		DESTROY_IF(query);
		fprintf(stderr, "resizing pool failed.\n");
		exit(EXIT_FAILURE);
	}
	if (old_addr.len != new_addr.len ||
		memcmp(new_addr.ptr, old_addr.ptr, old_addr.len) < 0)
	{
		fprintf(stderr, "shrinking of pools not supported.\n");
		query->destroy(query);
		exit(EXIT_FAILURE);
	}
	cur_addr = chunk_clonea(old_addr);
	count = get_pool_size(old_addr, new_addr) - 1;
	query->destroy(query);

	/* Check whether pool is resizable */
	old_end = host_create_from_chunk(AF_UNSPEC, old_addr, 0);
	if (old_end && old_end->is_anyaddr(old_end))
	{
		fprintf(stderr, "pool is not resizable.\n");
		old_end->destroy(old_end);
		exit(EXIT_FAILURE);
	}
	DESTROY_IF(old_end);

	db->transaction(db, FALSE);
	if (db->execute(db, NULL,
			"UPDATE pools SET end = ? WHERE name = ?",
			DB_BLOB, new_addr, DB_TEXT, name) <= 0)
	{
		fprintf(stderr, "pool '%s' not found.\n", name);
		exit(EXIT_FAILURE);
	}

	printf("allocating %d new addresses... ", count);
	fflush(stdout);
	while (count-- > 0)
	{
		chunk_increment(cur_addr);
		db->execute(db, NULL,
			"INSERT INTO addresses (pool, address, identity, acquired, released) "
			"VALUES (?, ?, ?, ?, ?)",
			DB_UINT, id, DB_BLOB, cur_addr,	DB_UINT, 0, DB_UINT, 0, DB_UINT, 1);
	}
	db->commit(db);
	printf("done.\n");

}
Esempio n. 26
0
/**
 * ipsec pool --leases - show lease information of a pool
 */
static void leases(char *filter, bool utc)
{
	enumerator_t *query;
	array_t *to_free = NULL;
	chunk_t address_chunk, identity_chunk;
	int identity_type;
	char *name;
	u_int db_acquired, db_released, db_timeout;
	time_t acquired, released, timeout;
	host_t *address;
	identification_t *identity;
	bool found = FALSE;

	query = create_lease_query(filter, &to_free);
	if (!query)
	{
		fprintf(stderr, "querying leases failed.\n");
		exit(EXIT_FAILURE);
	}
	while (query->enumerate(query, &name, &address_chunk, &identity_type,
							&identity_chunk, &db_acquired, &db_released, &db_timeout))
	{
		if (!found)
		{
			int len = utc ? 25 : 21;

			found = TRUE;
			printf("%-8s %-15s %-7s  %-*s %-*s %s\n",
				   "name", "address", "status", len, "start", len, "end", "identity");
		}
		address = host_create_from_chunk(AF_UNSPEC, address_chunk, 0);
		identity = identification_create_from_encoding(identity_type, identity_chunk);

		/* u_int is not always equal to time_t */
		acquired = (time_t)db_acquired;
		released = (time_t)db_released;
		timeout  = (time_t)db_timeout;

		printf("%-8s %-15H ", name, address);
		if (released == 0)
		{
			printf("%-7s ", "online");
		}
		else if (timeout == 0)
		{
			printf("%-7s ", "static");
		}
		else if (released >= time(NULL) - timeout)
		{
			printf("%-7s ", "valid");
		}
		else
		{
			printf("%-7s ", "expired");
		}

		printf(" %T  ", &acquired, utc);
		if (released)
		{
			printf("%T  ", &released, utc);
		}
		else
		{
			printf("                      ");
			if (utc)
			{
				printf("    ");
			}
		}
		printf("%Y\n", identity);
		DESTROY_IF(address);
		identity->destroy(identity);
	}
	query->destroy(query);
	if (to_free)
	{
		array_destroy_function(to_free, (void*)free, NULL);
	}
	if (!found)
	{
		fprintf(stderr, "no matching leases found.\n");
		exit(EXIT_FAILURE);
	}
}
Esempio n. 27
0
/**
 * Determine the type of the attribute and its value
 */
static bool parse_attributes(char *name, char *value, value_type_t *value_type,
							 configuration_attribute_type_t *type,
							 configuration_attribute_type_t *type_ip6,
							 chunk_t *blob)
{
	host_t *addr = NULL, *mask = NULL;
	chunk_t addr_chunk, mask_chunk, blob_next;
	char *text = "", *pos_addr, *pos_mask, *pos_next, *endptr;
	int i;

	switch (*value_type)
	{
		case VALUE_STRING:
			*blob = chunk_create(value, strlen(value));
			*blob = chunk_clone(*blob);
			break;
		case VALUE_HEX:
			*blob = chunk_from_hex(chunk_create(value, strlen(value)), NULL);
			break;
		case VALUE_ADDR:
			addr = host_create_from_string(value, 0);
			if (addr == NULL)
			{
				fprintf(stderr, "invalid IP address: '%s'.\n", value);
				return FALSE;
			}
			addr_chunk = addr->get_address(addr);
			*blob = chunk_clone(addr_chunk);
			break;
		case VALUE_SUBNET:
			*blob = chunk_empty;
			pos_next = value;

			do
			{
				pos_addr = pos_next;
				pos_next = strchr(pos_next, ',');
				if (pos_next)
				{
					*pos_next = '\0';
					pos_next += 1;
				}
				pos_mask = strchr(pos_addr, '/');
				if (pos_mask == NULL)
				{
					fprintf(stderr, "invalid IPv4 subnet: '%s'.\n", pos_addr);
					free(blob->ptr);
					return FALSE;
				}
				*pos_mask = '\0';
				pos_mask += 1;
				addr = host_create_from_string(pos_addr, 0);
				mask = host_create_from_string(pos_mask, 0);
				if (addr == NULL || addr->get_family(addr) != AF_INET ||
					mask == NULL || mask->get_family(addr) != AF_INET)
				{
					fprintf(stderr, "invalid IPv4 subnet: '%s/%s'.\n",
									pos_addr, pos_mask);
					DESTROY_IF(addr);
					DESTROY_IF(mask);
					free(blob->ptr);
					return FALSE;
				}
				addr_chunk = addr->get_address(addr);
				mask_chunk = mask->get_address(mask);
				blob_next = chunk_alloc(blob->len + UNITY_NETWORK_LEN);
				memcpy(blob_next.ptr, blob->ptr, blob->len);
				pos_addr = blob_next.ptr + blob->len;
				memset(pos_addr, 0x00, UNITY_NETWORK_LEN);
				memcpy(pos_addr,     addr_chunk.ptr, 4);
				memcpy(pos_addr + 4, mask_chunk.ptr, 4);
				addr->destroy(addr);
				addr = NULL;
				mask->destroy(mask);
				chunk_free(blob);
				*blob = blob_next;
			}
			while (pos_next);
			break;
		case VALUE_NONE:
			*blob = chunk_empty;
			break;
	}

	/* init the attribute type */
	*type     = 0;
	*type_ip6 = 0;

	for (i = 0; i < countof(attr_info); i++)
	{
		if (strcaseeq(name, attr_info[i].keyword))
		{
			*type      = attr_info[i].type;
			*type_ip6  = attr_info[i].type_ip6;

			if (*value_type == VALUE_NONE)
			{
				*value_type = attr_info[i].value_type;
				return TRUE;
			}

			if (*value_type != attr_info[i].value_type &&
				*value_type != VALUE_HEX)
			{
				switch (attr_info[i].value_type)
				{
					case VALUE_STRING:
						text = "a string";
						break;
					case VALUE_HEX:
						text = "a hex";
						break;
					case VALUE_ADDR:
						text = "an IP address";
						break;
					case VALUE_SUBNET:
						text = "a subnet";
						break;
					case VALUE_NONE:
						text = "no";
						break;
				}
				fprintf(stderr, "the %s attribute requires %s value.\n",
								 name, text);
				DESTROY_IF(addr);
				free(blob->ptr);
				return FALSE;
			}

			if (*value_type == VALUE_ADDR)
			{
				*type = (addr->get_family(addr) == AF_INET) ?
							attr_info[i].type : attr_info[i].type_ip6;
				addr->destroy(addr);
			}
			else if (*value_type == VALUE_HEX)
			{
				*value_type = attr_info[i].value_type;

				if (*value_type == VALUE_ADDR)
				{
					if (blob->len == 16)
					{
						*type = attr_info[i].type_ip6;
					}
					else if (blob->len != 4)
					{
						fprintf(stderr, "the %s attribute requires "
										"a valid IP address.\n", name);
						free(blob->ptr);
						return FALSE;
					}
				}
			}
			return TRUE;
		}
	}

	/* clean up */
	DESTROY_IF(addr);

	/* is the attribute type numeric? */
	*type = strtol(name, &endptr, 10);

	if (*endptr != '\0')
	{
		fprintf(stderr, "the %s attribute is not recognized.\n", name);
		free(blob->ptr);
		return FALSE;
	}
	if (*type < 1 || *type > 32767)
	{
		fprintf(stderr, "the attribute type must lie in the range 1..32767.\n");
		free(blob->ptr);
		return FALSE;
	}
	if (*value_type == VALUE_NONE)
	{
		*value_type = VALUE_HEX;
	}
	return TRUE;
}
Esempio n. 28
0
static bool do_test_gcm(test_vector_t *test)
{
	encryption_algorithm_t alg;
	chunk_t key, iv;
	aead_t *aead;
	size_t saltlen, ivlen;

	switch (ctx.icvlen / 8)
	{
		case 8:
			alg = ENCR_AES_GCM_ICV8;
			break;
		case 12:
			alg = ENCR_AES_GCM_ICV12;
			break;
		case 16:
			alg = ENCR_AES_GCM_ICV16;
			break;
		default:
			DBG1(DBG_APP, "unsupported ICV length: %d", ctx.icvlen);
			return FALSE;
	}

	aead = lib->crypto->create_aead(lib->crypto, alg, test->key.len, 4);
	if (!aead)
	{
		DBG1(DBG_APP, "algorithm %N or key length (%d bits) not supported",
			 encryption_algorithm_names, alg, test->key.len * 8);
		return FALSE;
	}
	/* our API is quite RFC 4106 specific, that is, part of the IV is provided
	 * at the end of the key. */
	saltlen = aead->get_key_size(aead) - test->key.len;
	ivlen = aead->get_iv_size(aead);
	if (ctx.ivlen / 8 != saltlen + ivlen)
	{
		DBG1(DBG_APP, "unsupported IV length: %d", ctx.ivlen);
		aead->destroy(aead);
		return FALSE;
	}
	if (!test->external_iv)
	{
		rng_t *rng;

		/* the IV consists of saltlen random bytes (usually additional keymat)
		 * followed by a counter, zero here */
		test->iv = chunk_alloc(saltlen + ivlen);
		memset(test->iv.ptr, 0, test->iv.len);
		rng = lib->crypto->create_rng(lib->crypto, RNG_STRONG);
		if (!rng || !rng->get_bytes(rng, saltlen, test->iv.ptr))
		{
			DBG1(DBG_APP, "failed to generate IV");
			DESTROY_IF(rng);
			aead->destroy(aead);
			return FALSE;
		}
		rng->destroy(rng);
	}
	key = chunk_alloca(test->key.len + saltlen);
	memcpy(key.ptr, test->key.ptr, test->key.len);
	memcpy(key.ptr + test->key.len, test->iv.ptr, saltlen);
	iv = chunk_alloca(ivlen);
	memcpy(iv.ptr, test->iv.ptr + saltlen, iv.len);
	if (!aead->set_key(aead, key))
	{
		DBG1(DBG_APP, "failed to set key");
		aead->destroy(aead);
		return FALSE;
	}
	if (ctx.decrypt)
	{
		/* the ICV is expected to follow the cipher text */
		chunk_t cipher = chunk_cata("cc", test->cipher, test->icv);
		/* store if the verification of the ICV verification is successful */
		test->success = aead->decrypt(aead, cipher, test->aad, iv,
									  &test->plain);
	}
	else
	{
		if (!aead->encrypt(aead, test->plain, test->aad, iv, &test->cipher))
		{
			DBG1(DBG_APP, "encryption failed");
			aead->destroy(aead);
			return FALSE;
		}
		/* copy ICV from the end of the cipher text */
		test->icv = chunk_alloc(ctx.icvlen / 8);
		test->cipher.len -= test->icv.len;
		memcpy(test->icv.ptr, test->cipher.ptr + test->cipher.len,
			   test->icv.len);
	}
	aead->destroy(aead);
	return TRUE;
}
Esempio n. 29
0
/**
 * atexit() cleanup for dispatcher
 */
void dispatcher_cleanup()
{
	DESTROY_IF(dispatcher);
}
Esempio n. 30
0
static void do_args(int argc, char *argv[])
{
	char *name = "", *value = "", *filter = "";
	char *pool = NULL, *identity = NULL, *addresses = NULL;
	value_type_t value_type = VALUE_NONE;
	int timeout = 0;
	bool utc = FALSE, hexout = FALSE;

	enum {
		OP_UNDEF,
		OP_USAGE,
		OP_STATUS,
		OP_STATUS_ATTR,
		OP_ADD,
		OP_ADD_ATTR,
		OP_DEL,
		OP_DEL_ATTR,
		OP_SHOW_ATTR,
		OP_RESIZE,
		OP_LEASES,
		OP_PURGE,
		OP_BATCH
	} operation = OP_UNDEF;

	/* reinit getopt state */
	optind = 0;

	while (TRUE)
	{
		int c;

		struct option long_opts[] = {
			{ "help", no_argument, NULL, 'h' },

			{ "utc", no_argument, NULL, 'u' },
			{ "status", no_argument, NULL, 'w' },
			{ "add", required_argument, NULL, 'a' },
			{ "replace", required_argument, NULL, 'c' },
			{ "del", required_argument, NULL, 'd' },
			{ "resize", required_argument, NULL, 'r' },
			{ "leases", no_argument, NULL, 'l' },
			{ "purge", required_argument, NULL, 'p' },
			{ "statusattr", no_argument, NULL, '1' },
			{ "addattr", required_argument, NULL, '2' },
			{ "delattr", required_argument, NULL, '3' },
			{ "showattr", no_argument, NULL, '4' },
			{ "batch", required_argument, NULL, 'b' },

			{ "start", required_argument, NULL, 's' },
			{ "end", required_argument, NULL, 'e' },
			{ "addresses", required_argument, NULL, 'y' },
			{ "timeout", required_argument, NULL, 't' },
			{ "filter", required_argument, NULL, 'f' },
			{ "addr", required_argument, NULL, 'v' },
			{ "mask", required_argument, NULL, 'v' },
			{ "server", required_argument, NULL, 'v' },
			{ "subnet", required_argument, NULL, 'n' },
			{ "string", required_argument, NULL, 'g' },
			{ "hex", required_argument, NULL, 'x' },
			{ "hexout", no_argument, NULL, '5' },
			{ "pool", required_argument, NULL, '6' },
			{ "identity", required_argument, NULL, '7' },
			{ 0,0,0,0 }
		};

		c = getopt_long(argc, argv, "", long_opts, NULL);
		switch (c)
		{
			case EOF:
				break;
			case 'h':
				operation = OP_USAGE;
				break;
			case 'w':
				operation = OP_STATUS;
				break;
			case '1':
				operation = OP_STATUS_ATTR;
				break;
			case 'u':
				utc = TRUE;
				continue;
			case 'c':
				replace_pool = TRUE;
				/* fallthrough */
			case 'a':
				name = optarg;
				operation = is_attribute(name) ? OP_ADD_ATTR : OP_ADD;
				if (replace_pool && operation == OP_ADD_ATTR)
				{
					fprintf(stderr, "invalid pool name: "
									"reserved for '%s' attribute.\n", optarg);
					usage();
					exit(EXIT_FAILURE);
				}
				continue;
			case '2':
				name = optarg;
				operation = OP_ADD_ATTR;
				continue;
			case 'd':
				name = optarg;
				operation = is_attribute(name) ? OP_DEL_ATTR : OP_DEL;
				continue;
			case '3':
				name = optarg;
				operation = OP_DEL_ATTR;
				continue;
			case '4':
				operation = OP_SHOW_ATTR;
				continue;
			case 'r':
				name = optarg;
				operation = OP_RESIZE;
				continue;
			case 'l':
				operation = OP_LEASES;
				continue;
			case 'p':
				name = optarg;
				operation = OP_PURGE;
				continue;
			case 'b':
				name = optarg;
				if (operation == OP_BATCH)
				{
					fprintf(stderr, "--batch commands can not be nested\n");
					exit(EXIT_FAILURE);
				}
				operation = OP_BATCH;
				continue;
			case 's':
				DESTROY_IF(start);
				start = host_create_from_string(optarg, 0);
				if (start == NULL)
				{
					fprintf(stderr, "invalid start address: '%s'.\n", optarg);
					usage();
					exit(EXIT_FAILURE);
				}
				continue;
			case 'e':
				DESTROY_IF(end);
				end = host_create_from_string(optarg, 0);
				if (end == NULL)
				{
					fprintf(stderr, "invalid end address: '%s'.\n", optarg);
					usage();
					exit(EXIT_FAILURE);
				}
				continue;
			case 't':
				timeout = atoi(optarg);
				if (timeout == 0 && strcmp(optarg, "0") != 0)
				{
					fprintf(stderr, "invalid timeout '%s'.\n", optarg);
					usage();
					exit(EXIT_FAILURE);
				}
				continue;
			case 'f':
				filter = optarg;
				continue;
			case 'y':
				addresses = optarg;
				continue;
			case 'g':
				value_type = VALUE_STRING;
				value = optarg;
				continue;
			case 'n':
				value_type = VALUE_SUBNET;
				value = optarg;
				continue;
			case 'v':
				value_type = VALUE_ADDR;
				value = optarg;
				continue;
			case 'x':
				value_type = VALUE_HEX;
				value = optarg;
				continue;
			case '5':
				hexout = TRUE;
				continue;
			case '6':
				pool = optarg;
				continue;
			case '7':
				identity = optarg;
				continue;
			default:
				usage();
				exit(EXIT_FAILURE);
				break;
		}
		break;
	}

	switch (operation)
	{
		case OP_USAGE:
			usage();
			break;
		case OP_STATUS:
			status();
			break;
		case OP_STATUS_ATTR:
			status_attr(hexout);
			break;
		case OP_ADD:
			if (addresses != NULL)
			{
				add_addresses(name, addresses, timeout);
			}
			else if (start != NULL && end != NULL)
			{
				add(name, start, end, timeout);
			}
			else
			{
				fprintf(stderr, "missing arguments.\n");
				usage();
				exit(EXIT_FAILURE);
			}
			break;
		case OP_ADD_ATTR:
			if (value_type == VALUE_NONE)
			{
				fprintf(stderr, "missing arguments.\n");
				usage();
				exit(EXIT_FAILURE);
			}
			if (identity && !pool)
			{
				fprintf(stderr, "--identity option can't be used without --pool.\n");
				usage();
				exit(EXIT_FAILURE);
			}
			add_attr(name, pool, identity, value, value_type);
			break;
		case OP_DEL:
			del(name);
			break;
		case OP_DEL_ATTR:
			if (identity && !pool)
			{
				fprintf(stderr, "--identity option can't be used without --pool.\n");
				usage();
				exit(EXIT_FAILURE);
			}
			del_attr(name, pool, identity, value, value_type);
			break;
		case OP_SHOW_ATTR:
			show_attr();
			break;
		case OP_RESIZE:
			if (end == NULL)
			{
				fprintf(stderr, "missing arguments.\n");
				usage();
				exit(EXIT_FAILURE);
			}
			resize(name, end);
			break;
		case OP_LEASES:
			leases(filter, utc);
			break;
		case OP_PURGE:
			purge(name);
			break;
		case OP_BATCH:
			if (name == NULL)
			{
				fprintf(stderr, "missing arguments.\n");
				usage();
				exit(EXIT_FAILURE);
			}
			batch(argv[0], name);
			break;
		default:
			usage();
			exit(EXIT_FAILURE);
	}
}