From aa1c54de2e1755e1fc932b4335c5a6f2376dc310 Mon Sep 17 00:00:00 2001 From: David Lawrence Date: Tue, 14 Mar 2000 03:37:10 +0000 Subject: [PATCH] support for signed messages --- lib/omapi/auth.c | 344 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 344 insertions(+) create mode 100644 lib/omapi/auth.c diff --git a/lib/omapi/auth.c b/lib/omapi/auth.c new file mode 100644 index 0000000000..2883f0292c --- /dev/null +++ b/lib/omapi/auth.c @@ -0,0 +1,344 @@ +/* + * Copyright (C) 2000 Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE + * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +/* $Id: auth.c,v 1.1 2000/03/14 03:37:10 tale Exp $ */ + +/* Principal Author: DCL */ + +/* + * XXXDCL Todo: + * How do keys get specified by named.conf for the control channel? + * Could use the keys in the address_match_list (acl) specified in the + * "controls" statement. All of the keys would need to be at the beginning, + * so the match does not stop at an IP address. The server would register + * all of the keys. Currently, however, there is no way to limit a key + * to a particular listening interface on the server, as the configuration + * file would allow. + */ + +/* + * Subroutines for dealing with authorization. + */ +#include +#include /* NULL */ +#include /* memset */ + +#include +#include +#include + +#include + +typedef struct auth auth_t; + +#define AUTH_MAGIC 0x41555448U /* AUTH. */ +#define VALID_AUTH(a) ((a) != NULL && (a)->magic == AUTH_MAGIC) + +/* + * XXXDCL For reloading, Make refcounted, and use attach and detach? + */ +struct auth { + unsigned int magic; + char *name; + char *secret; + unsigned int algorithms; + + ISC_LINK(auth_t) link; +}; + +static ISC_LIST(auth_t) omapi_authlist; +static isc_mutex_t mutex; /* To lock the previous variable. */ +static isc_once_t once = ISC_ONCE_INIT; /* To initialize the mutex. */ + +static void +initialize_mutex(void) { + RUNTIME_CHECK(isc_mutex_init(&mutex) == ISC_R_SUCCESS); +} + +static isc_result_t +auth_find(const char *name, unsigned int algorithm, auth_t **ap) { + auth_t *a; + isc_result_t result; + + REQUIRE(name != NULL); + REQUIRE(ap != NULL && *ap == NULL); + + for (a = ISC_LIST_HEAD(omapi_authlist); a != NULL; + a = ISC_LIST_NEXT(a, link)) + if (strcmp(name, a->name) == 0) + break; + + if (a == NULL) + result = ISC_R_NOTFOUND; + + else if (algorithm != 0 && (algorithm & a->algorithms) != algorithm) + result = DST_R_UNSUPPORTEDALG; + + else { + ENSURE(VALID_AUTH(a)); + + *ap = a; + + result = ISC_R_SUCCESS; + } + + return (result); +} + + +isc_result_t +auth_makekey(const char *name, unsigned int algorithm, dst_key_t **key) { + isc_result_t result; + isc_buffer_t secret; + auth_t *auth = NULL; + unsigned int dst_algorithm; + unsigned int secret_len; + + REQUIRE(name != NULL && algorithm != 0); + REQUIRE(key != NULL && *key == NULL); + + RUNTIME_CHECK(isc_once_do(&once, initialize_mutex) == ISC_R_SUCCESS); + LOCK(&mutex); + result = auth_find(name, algorithm, &auth); + + if (result == ISC_R_SUCCESS) { + switch (algorithm) { + case OMAPI_AUTH_HMACMD5: + dst_algorithm = DST_ALG_HMACMD5; + break; + default: + UNEXPECTED_ERROR(__FILE__, __LINE__, + "unknown auth algorithm %d", + algorithm); + return (ISC_R_UNEXPECTED); + } + + secret_len = strlen(auth->secret); + + isc_buffer_init(&secret, auth->secret, secret_len, + ISC_BUFFERTYPE_GENERIC); + + isc_buffer_add(&secret, secret_len); + + result = dst_key_frombuffer(auth->name, dst_algorithm, NULL, + NULL, &secret, omapi_mctx, key); + } + + UNLOCK(&mutex); + + return (result); +} + +static void +auth_delete(auth_t *a) { + REQUIRE(VALID_AUTH(a)); + + ISC_LIST_UNLINK(omapi_authlist, a, link); + + a->magic = 0; + + isc_mem_free(omapi_mctx, a->secret); + isc_mem_free(omapi_mctx, a->name); + isc_mem_put(omapi_mctx, a, sizeof(*a)); +} + +isc_result_t +omapi_auth_register(const char *name, const char *secret, + unsigned int algorithms) +{ + auth_t *new = NULL; + isc_result_t result = ISC_R_SUCCESS; + + REQUIRE(name != NULL && secret != NULL); + REQUIRE(algorithms != 0); + + RUNTIME_CHECK(isc_once_do(&once, initialize_mutex) == ISC_R_SUCCESS); + LOCK(&mutex); + + if (auth_find(name, 0, &new) == ISC_R_SUCCESS) + result = ISC_R_EXISTS; + + if (result == ISC_R_SUCCESS) { + new = isc_mem_get(omapi_mctx, sizeof(*new)); + if (new != NULL) + memset(new, 0, sizeof(*new)); + else + result = ISC_R_NOMEMORY; + } + + if (result == ISC_R_SUCCESS) { + new->name = isc_mem_strdup(omapi_mctx, name); + if (new->name == NULL) + result = ISC_R_NOMEMORY; + + new->secret = isc_mem_strdup(omapi_mctx, secret); + if (new->secret == NULL) + result = ISC_R_NOMEMORY; + + new->algorithms = algorithms; + + ISC_LINK_INIT(new, link); + + new->magic = AUTH_MAGIC; + + ISC_LIST_APPEND(omapi_authlist, new, link); + } + + UNLOCK(&mutex); + + if (result != ISC_R_SUCCESS) { + if (new->secret != NULL) + isc_mem_free(omapi_mctx, new->secret); + if (new->name != NULL) + isc_mem_free(omapi_mctx, new->name); + if (new != NULL) + isc_mem_put(omapi_mctx, new, sizeof(*new)); + } + + return (result); +} + +/* + * Currently the way to effect a reload is to use omapi_auth_deregister(NULL) + * to remove all of the existing auth structs before building a new + * omapi_authlist via omapi_auth_register calls. This clearly leaves a + * window, however small, where there is no authentication possible. + */ +void +omapi_auth_deregister(const char *name) { + auth_t *a = NULL; + + RUNTIME_CHECK(isc_once_do(&once, initialize_mutex) == ISC_R_SUCCESS); + LOCK(&mutex); + + if (name == NULL) + while ((a = ISC_LIST_HEAD(omapi_authlist)) != NULL) + auth_delete(a); + + else + if (auth_find(name, 0, &a) == ISC_R_SUCCESS) + auth_delete(a); + + UNLOCK(&mutex); +} + +/* + * Send a message from the client to the server that says the key with the + * given name should be used to authenticate messages. + */ +isc_result_t +omapi_auth_use(omapi_object_t *manager, const char *name, + unsigned int algorithm) { + omapi_protocol_t *protocol; + omapi_connection_t *connection; + omapi_object_t *message = NULL; + omapi_object_t *generic = NULL; + isc_result_t result; + auth_t *auth = NULL; + + REQUIRE(manager != NULL); + REQUIRE(manager->type == omapi_type_protocol || + (manager->outer != NULL && + manager->outer->type == omapi_type_protocol)); + + if (manager->type == omapi_type_protocol) + protocol = (omapi_protocol_t *)manager; + else + protocol = (omapi_protocol_t *)manager->outer; + + REQUIRE(protocol->outer != NULL && + protocol->outer->type == omapi_type_connection); + + connection = (omapi_connection_t *)protocol->outer; + + INSIST(connection->is_client); + + RUNTIME_CHECK(isc_once_do(&once, initialize_mutex) == ISC_R_SUCCESS); + LOCK(&mutex); + + result = auth_find(name, algorithm, &auth); + + UNLOCK(&mutex); + + if (result == ISC_R_SUCCESS) + result = omapi_object_create(&generic, NULL, 0); + + if (result == ISC_R_SUCCESS) + result = omapi_message_create(&message); + + if (result == ISC_R_SUCCESS) + result = omapi_object_setinteger(message, "op", OMAPI_OP_OPEN); + + if (result == ISC_R_SUCCESS) + result = omapi_object_setboolean(message, "update", ISC_TRUE); + + if (result == ISC_R_SUCCESS) + result = omapi_object_setstring(message, "type", "protocol"); + + if (result == ISC_R_SUCCESS) + result = omapi_object_setobject(message, "object", generic); + + if (result == ISC_R_SUCCESS) + result = omapi_object_setstring(generic, "auth-name", name); + + if (result == ISC_R_SUCCESS) + result = omapi_object_setinteger(generic, "auth-algorithm", + algorithm); + + if (message != NULL) + omapi_message_register(message); + + if (result == ISC_R_SUCCESS) + result = omapi_message_send(message, manager); + + if (message != NULL) { + omapi_message_unregister(message); + omapi_object_dereference(&message); + } + + if (result == ISC_R_SUCCESS) + /* + * If the name was not found on the server, ISC_R_NOTFOUND + * will be returned. Unlike with a username/password pair, + * where it is undesirable to disclose whether it was the + * username or password that was at fault, only one item + * can be discerned here -- the name, since the secret is + * not exchanged. Therefore there is no point in having + * the server obfuscate the ISC_R_NOTFOUND error into some + * other error. + */ + result = generic->waitresult; + + if (result == ISC_R_SUCCESS) + /* + * This sets up the key in the protocol structure + * on this side of the connection. + */ + result = object_update((omapi_object_t *)protocol, generic, 0); + + if (generic != NULL) + omapi_object_dereference(&generic); + + return (result); +} + +void +auth_destroy(void) { + omapi_auth_deregister(NULL); + + RUNTIME_CHECK(isc_mutex_destroy(&mutex) == ISC_R_SUCCESS); +}