diff --git a/opal/dss/dss_types.h b/opal/dss/dss_types.h index 4b61baa562..25048bd2d9 100644 --- a/opal/dss/dss_types.h +++ b/opal/dss/dss_types.h @@ -50,6 +50,9 @@ typedef struct { uint8_t *bytes; } opal_byte_object_t; +/* define an RTE-agnostic process identifier */ +typedef uint64_t opal_identifier_t; + /* Type defines for packing and unpacking */ #define OPAL_UNDEF (opal_data_type_t) 0 /**< type hasn't been defined yet */ #define OPAL_BYTE (opal_data_type_t) 1 /**< a byte of data */ diff --git a/opal/mca/db/db_types.h b/opal/mca/db/db_types.h index c9f2873298..7ef8e81a6a 100644 --- a/opal/mca/db/db_types.h +++ b/opal/mca/db/db_types.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2012-2013 Los Alamos National Security, Inc. All rights reserved. + * Copyright (c) 2014 Intel, Inc. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow @@ -18,11 +19,10 @@ #include "opal_config.h" #include "opal/types.h" +#include "opal/dss/dss_types.h" BEGIN_C_DECLS -typedef uint64_t opal_identifier_t; - /* some OPAL-appropriate key definitions */ #define OPAL_DB_LOCALITY "opal.locality" #define OPAL_DB_CPUSET "opal.cpuset" diff --git a/opal/mca/sec/Makefile.am b/opal/mca/sec/Makefile.am new file mode 100644 index 0000000000..e5ba5243d1 --- /dev/null +++ b/opal/mca/sec/Makefile.am @@ -0,0 +1,32 @@ +# +# Copyright (c) 2014 Intel, Inc. All rights reserved. +# $COPYRIGHT$ +# +# Additional copyrights may follow +# +# $HEADER$ +# + +AM_CPPFLAGS = $(LTDLINCL) + +# main library setup +noinst_LTLIBRARIES = libmca_sec.la +libmca_sec_la_SOURCES = + +# pkgdata setup +dist_ompidata_DATA = + +# local files +headers = sec.h +libmca_sec_la_SOURCES += $(headers) + +# Conditionally install the header files +if WANT_INSTALL_HEADERS +opaldir = $(ompiincludedir)/$(subdir) +nobase_opal_HEADERS = $(headers) +endif + +include base/Makefile.am + +distclean-local: + rm -f base/static-components.h diff --git a/opal/mca/sec/base/Makefile.am b/opal/mca/sec/base/Makefile.am new file mode 100644 index 0000000000..820fa23fd4 --- /dev/null +++ b/opal/mca/sec/base/Makefile.am @@ -0,0 +1,17 @@ +# +# Copyright (c) 2014 Intel, Inc. All rights reserved. +# $COPYRIGHT$ +# +# Additional copyrights may follow +# +# $HEADER$ +# + +dist_ompidata_DATA += base/help-sec-base.txt + +headers += \ + base/base.h + +libmca_sec_la_SOURCES += \ + base/sec_base_frame.c \ + base/sec_base_select.c diff --git a/opal/mca/sec/base/base.h b/opal/mca/sec/base/base.h new file mode 100644 index 0000000000..c1dc56dbba --- /dev/null +++ b/opal/mca/sec/base/base.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2014 Intel, Inc. All rights reserved. + * $COPYRIGHT$ + * + * Additional copyrights may follow + * + * $HEADER$ + */ +/** @file: + */ + +#ifndef MCA_SEC_BASE_H +#define MCA_SEC_BASE_H + +#include "opal_config.h" +#include "opal/types.h" + +#include "opal/mca/mca.h" +#include "opal/mca/base/mca_base_framework.h" +#include "opal/class/opal_list.h" +#include "opal/dss/dss.h" + +#include "opal/mca/sec/sec.h" + +BEGIN_C_DECLS + +OPAL_DECLSPEC extern mca_base_framework_t opal_sec_base_framework; + +/** + * Select a sec module + */ +OPAL_DECLSPEC int opal_sec_base_select(void); + +END_C_DECLS + +#endif diff --git a/opal/mca/sec/base/help-sec-base.txt b/opal/mca/sec/base/help-sec-base.txt new file mode 100644 index 0000000000..f603f2eaf3 --- /dev/null +++ b/opal/mca/sec/base/help-sec-base.txt @@ -0,0 +1,19 @@ + -*- text -*- +# +# Copyright (c) 2010 Cisco Systems, Inc. All rights reserved. +# +# $COPYRIGHT$ +# +# Additional copyrights may follow +# +# $HEADER$ +# +# This is the US/English general help file for OPAL Errmgr HNP module. +# +[errmgr-hnp:unknown-job-error] +An error has occurred in an unknown job. This generally should not happen +except due to an internal OPAL error. + +Job state: %s + +This information should probably be repopald to the OMPI developers. diff --git a/opal/mca/sec/base/sec_base_frame.c b/opal/mca/sec/base/sec_base_frame.c new file mode 100644 index 0000000000..e3a22335c3 --- /dev/null +++ b/opal/mca/sec/base/sec_base_frame.c @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2014 Intel, Inc. All rights reserved. + * $COPYRIGHT$ + * + * Additional copyrights may follow + * + * $HEADER$ + */ + + +#include "opal_config.h" +#include "opal/constants.h" + +#include "opal/mca/mca.h" +#include "opal/util/output.h" +#include "opal/mca/base/base.h" +#include "opal/dss/dss_types.h" + +#include "opal/mca/sec/base/base.h" + + +/* + * The following file was created by configure. It contains extern + * secments and the definition of an array of pointers to each + * module's public mca_base_module_t struct. + */ + +#include "opal/mca/sec/base/static-components.h" + +opal_sec_base_module_t opal_sec; + +static int opal_sec_base_close(void) +{ + /* let the selected module finalize */ + if (NULL != opal_sec.finalize) { + opal_sec.finalize(); + } + + return mca_base_framework_components_close(&opal_sec_base_framework, NULL); +} + +static int opal_sec_base_open(mca_base_open_flag_t flags) +{ + /* Open up all available components */ + return mca_base_framework_components_open(&opal_sec_base_framework, flags); +} + +MCA_BASE_FRAMEWORK_DECLARE(opal, sec, NULL, NULL, opal_sec_base_open, opal_sec_base_close, + mca_sec_base_static_components, 0); diff --git a/opal/mca/sec/base/sec_base_select.c b/opal/mca/sec/base/sec_base_select.c new file mode 100644 index 0000000000..eeb720ec79 --- /dev/null +++ b/opal/mca/sec/base/sec_base_select.c @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2014 Intel, Inc. All rights reserved. + * $COPYRIGHT$ + * + * Additional copyrights may follow + * + * $HEADER$ + */ + +#include "opal_config.h" +#include "opal/constants.h" + +#include + +#include "opal/mca/mca.h" +#include "opal/mca/base/base.h" + +#include "opal/mca/sec/base/base.h" + +static bool selected = false; + +/* + * Function for selecting one component from all those that are + * available. + */ +int opal_sec_base_select(void) +{ + mca_base_component_list_item_t *cli = NULL; + mca_base_component_t *component = NULL; + mca_base_module_t *module = NULL; + opal_sec_base_module_t *smodule, *nmodule = NULL; + int rc, priority, pri = -1; + + if (selected) { + /* ensure we don't do this twice */ + return OPAL_SUCCESS; + } + selected = true; + + /* Query all available components and ask if they have a module */ + OPAL_LIST_FOREACH(cli, &opal_sec_base_framework.framework_components, mca_base_component_list_item_t) { + component = (mca_base_component_t *) cli->cli_component; + + opal_output_verbose(5, opal_sec_base_framework.framework_output, + "mca:sec:select: checking available component %s", component->mca_component_name); + + /* If there's no query function, skip it */ + if (NULL == component->mca_query_component) { + opal_output_verbose(5, opal_sec_base_framework.framework_output, + "mca:sec:select: Skipping component [%s]. It does not implement a query function", + component->mca_component_name ); + continue; + } + + /* Query the component */ + opal_output_verbose(5, opal_sec_base_framework.framework_output, + "mca:sec:select: Querying component [%s]", + component->mca_component_name); + rc = component->mca_query_component(&module, &priority); + + /* If no module was returned, then skip component */ + if (OPAL_SUCCESS != rc || NULL == module) { + opal_output_verbose(5, opal_sec_base_framework.framework_output, + "mca:sec:select: Skipping component [%s]. Query failed to return a module", + component->mca_component_name ); + continue; + } + + smodule = (opal_sec_base_module_t*)module; + /* modules are required to have an init function */ + if (NULL == smodule->init) { + /* report the error */ + opal_output_verbose(5, opal_sec_base_framework.framework_output, + "mca:sec:select: Skipping component [%s]. It does not implement an init function", + component->mca_component_name); + continue; + } + + /* if we got a module, let it try to initialize */ + if (OPAL_SUCCESS != (rc = smodule->init())) { + /* couldn't init - ignore it */ + opal_output_verbose(5, opal_sec_base_framework.framework_output, + "mca:sec:select: Skipping component [%s]. Init returned %d", + component->mca_component_name, rc); + continue; + } + + /* see if this is the one to keep - only retain the highest priority */ + if (pri < priority) { + nmodule = smodule; + pri = priority; + } + } + + if (NULL == nmodule) { + /* no module available - error out */ + return OPAL_ERROR; + } + + opal_sec = *nmodule; + + return OPAL_SUCCESS;; +} diff --git a/opal/mca/sec/basic/Makefile.am b/opal/mca/sec/basic/Makefile.am new file mode 100644 index 0000000000..6fc55d0ca4 --- /dev/null +++ b/opal/mca/sec/basic/Makefile.am @@ -0,0 +1,35 @@ +# +# Copyright (c) 2014 Intel, Inc. All rights reserved. +# $COPYRIGHT$ +# +# Additional copyrights may follow +# +# $HEADER$ +# + +sources = \ + sec_basic.h \ + sec_basic_component.c \ + sec_basic.c + +# Make the output library in this directory, and name it either +# mca__.la (for DSO builds) or libmca__.la +# (for static builds). + +if MCA_BUILD_opal_sec_basic_DSO +component_noinst = +component_install = mca_sec_basic.la +else +component_noinst = libmca_sec_basic.la +component_install = +endif + +mcacomponentdir = $(ompilibdir) +mcacomponent_LTLIBRARIES = $(component_install) +mca_sec_basic_la_SOURCES = $(sources) +mca_sec_basic_la_LDFLAGS = -module -avoid-version +mca_sec_basic_la_LIBADD = $(sec_basic_LIBS) + +noinst_LTLIBRARIES = $(component_noinst) +libmca_sec_basic_la_SOURCES =$(sources) +libmca_sec_basic_la_LDFLAGS = -module -avoid-version diff --git a/opal/mca/sec/basic/sec_basic.c b/opal/mca/sec/basic/sec_basic.c new file mode 100644 index 0000000000..5d61cf3748 --- /dev/null +++ b/opal/mca/sec/basic/sec_basic.c @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2014 Intel, Inc. All rights reserved. + * $COPYRIGHT$ + * + * Additional copyrights may follow + * + * $HEADER$ + * + */ + +#include "opal_config.h" +#include "opal/constants.h" + +#ifdef HAVE_STRING_H +#include +#endif + +#include "opal_stdint.h" +#include "opal/dss/dss_types.h" +#include "opal/util/error.h" +#include "opal/util/output.h" +#include "opal/util/show_help.h" + +#include "opal/mca/sec/base/base.h" +#include "sec_basic.h" + +static int init(void); +static void finalize(void); +static int get_token(const opal_identifier_t *proc, + opal_sec_cred_t token, + size_t size); +static int authenticate(const opal_identifier_t *proc, + opal_sec_cred_t token, + size_t size); + +opal_sec_base_module_t opal_sec_basic_module = { + init, + finalize, + get_token, + authenticate +}; + +static int init(void) +{ + return OPAL_SUCCESS; +} + +static void finalize(void) +{ +} + +static int get_token(const opal_identifier_t *proc, + opal_sec_cred_t token, + size_t size) +{ + uint32_t ui32; + + opal_output_verbose(2, opal_sec_base_framework.framework_output, + "creating sec token for %"PRIu64"", *proc); + + ui32 = htonl(12345); + memcpy(token, &ui32, 4); + + opal_output_verbose(2, opal_sec_base_framework.framework_output, + "proc %"PRIu64" was assigned token %u", + *proc, 12345); + return OPAL_SUCCESS; +} + +static int authenticate(const opal_identifier_t *proc, + opal_sec_cred_t token, + size_t size) +{ + uint32_t ui32; + uint32_t chk; + + opal_output_verbose(2, opal_sec_base_framework.framework_output, + "authenticating %"PRIu64"", *proc); + + /* for now, just check the identifier against the proc id */ + memcpy(&ui32, token, 4); + + chk = ntohl(ui32); + + if (12345 != chk) { + opal_output_verbose(2, opal_sec_base_framework.framework_output, + "proc %"PRIu64" was not authenticated %u vs %u", + *proc, chk, 12345); + return OPAL_ERROR; + } + + opal_output_verbose(2, opal_sec_base_framework.framework_output, + "proc %"PRIu64" was authenticated", *proc); + return OPAL_SUCCESS; +} + diff --git a/opal/mca/sec/basic/sec_basic.h b/opal/mca/sec/basic/sec_basic.h new file mode 100644 index 0000000000..1257452cd4 --- /dev/null +++ b/opal/mca/sec/basic/sec_basic.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2014 Intel, Inc. All rights reserved. + * $COPYRIGHT$ + * + * Additional copyrights may follow + * + * $HEADER$ + */ + +#ifndef OPAL_SEC_BASIC_H +#define OPAL_SEC_BASIC_H + +#include "opal/mca/sec/sec.h" + +BEGIN_C_DECLS + + +OPAL_MODULE_DECLSPEC extern opal_sec_base_component_t mca_sec_basic_component; +OPAL_DECLSPEC extern opal_sec_base_module_t opal_sec_basic_module; + +END_C_DECLS + +#endif /* OPAL_SEC_BASIC_H */ diff --git a/opal/mca/sec/basic/sec_basic_component.c b/opal/mca/sec/basic/sec_basic_component.c new file mode 100644 index 0000000000..809800a48e --- /dev/null +++ b/opal/mca/sec/basic/sec_basic_component.c @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2014 Intel, Inc. All rights reserved. + * $COPYRIGHT$ + * + * Additional copyrights may follow + * + * $HEADER$ + */ + +#include "opal_config.h" +#include "opal/constants.h" + +#include "opal/mca/base/base.h" + +#include "opal/mca/sec/sec.h" +#include "opal/mca/sec/base/base.h" +#include "sec_basic.h" + +static int sec_basic_component_open(void); +static int sec_basic_component_query(mca_base_module_t **module, int *priority); +static int sec_basic_component_close(void); + +/* + * Instantiate the public struct with all of our public information + * and pointers to our public functions in it + */ +opal_sec_base_component_t mca_sec_basic_component = { + { + OPAL_SEC_BASE_VERSION_1_0_0, + + /* Component name and version */ + "basic", + OPAL_MAJOR_VERSION, + OPAL_MINOR_VERSION, + OPAL_RELEASE_VERSION, + + /* Component open and close functions */ + sec_basic_component_open, + sec_basic_component_close, + sec_basic_component_query, + NULL + }, + { + /* The component is checkpoint ready */ + MCA_BASE_METADATA_PARAM_CHECKPOINT + } +}; + +static int sec_basic_component_open(void) +{ + return OPAL_SUCCESS; +} + +static int sec_basic_component_query(mca_base_module_t **module, int *priority) +{ + /* we are the default, so set ourselves low in the priority */ + *priority = 0; + *module = (mca_base_module_t*)&opal_sec_basic_module; + return OPAL_SUCCESS; +} + + +static int sec_basic_component_close(void) +{ + return OPAL_SUCCESS; +} diff --git a/opal/mca/sec/keystone/Makefile.am b/opal/mca/sec/keystone/Makefile.am new file mode 100644 index 0000000000..4b14f1f6c0 --- /dev/null +++ b/opal/mca/sec/keystone/Makefile.am @@ -0,0 +1,34 @@ +# +# Copyright (c) 2014 Intel, Inc. All rights reserved. +# $COPYRIGHT$ +# +# Additional copyrights may follow +# +# $HEADER$ +# + +sources = \ + sec_keystone.h \ + sec_keystone_component.c \ + sec_keystone.c + +# Make the output library in this directory, and name it either +# mca__.la (for DSO builds) or libmca__.la +# (for static builds). + +if MCA_BUILD_opal_sec_keystone_DSO +component_noinst = +component_install = mca_sec_keystone.la +else +component_noinst = libmca_sec_keystone.la +component_install = +endif + +mcacomponentdir = $(ompilibdir) +mcacomponent_LTLIBRARIES = $(component_install) +mca_sec_keystone_la_SOURCES = $(sources) +mca_sec_keystone_la_LDFLAGS = -module -avoid-version + +noinst_LTLIBRARIES = $(component_noinst) +libmca_sec_keystone_la_SOURCES =$(sources) +libmca_sec_keystone_la_LDFLAGS = -module -avoid-version diff --git a/opal/mca/sec/keystone/configure.m4 b/opal/mca/sec/keystone/configure.m4 new file mode 100644 index 0000000000..51ef7a635e --- /dev/null +++ b/opal/mca/sec/keystone/configure.m4 @@ -0,0 +1,42 @@ +dnl -*- shell-script -*- +dnl +dnl Copyright (c) 2014 Intel, Inc. All rights reserved. +dnl $COPYRIGHT$ +dnl +dnl Additional copyrights may follow +dnl +dnl $HEADER$ +dnl + +# MCA_sec_keystone_CONFIG([action-if-found], [action-if-not-found]) +# ----------------------------------------------------------- +AC_DEFUN([MCA_opal_sec_keystone_CONFIG], [ + AC_CONFIG_FILES([opal/mca/sec/keystone/Makefile]) + + AC_ARG_WITH([keystone], + [AC_HELP_STRING([--with-keystone], + [Build keystone support (default: no)])], + [], with_keystone=no) + + # do not build if support not requested + AS_IF([test "$with_keystone" != "no"], + [AS_IF([test ! -z "$with_keystone" -a "$with_keystone" != "yes"], + [opal_check_keystone_dir="$with_keystone"]) + OMPI_CHECK_PACKAGE([sec_keystone], + [libkeystone.h], + [keystone], + [keystoneFN], + [], + [$opal_check_keystone_dir], + [], + [$1], + [AC_MSG_WARN([KEYSTONE SUPPORT REQUESTED]) + AC_MSG_WARN([BUT REQUIRED LIBRARY OR HEADER NOT FOUND]) + AC_MSG_ERROR([CANNOT CONTINUE]) + $2])], + [$2]) + + AC_SUBST(sec_keystone_CPPFLAGS) + AC_SUBST(sec_keystone_LDFLAGS) + AC_SUBST(sec_keystone_LIBS) +])dnl diff --git a/opal/mca/sec/keystone/sec_keystone.c b/opal/mca/sec/keystone/sec_keystone.c new file mode 100644 index 0000000000..19545427e5 --- /dev/null +++ b/opal/mca/sec/keystone/sec_keystone.c @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2014 Intel, Inc. All rights reserved. + * $COPYRIGHT$ + * + * Additional copyrights may follow + * + * $HEADER$ + * + */ + +#include "opal_config.h" +#include "opal/constants.h" + +#include "opal_stdint.h" +#include "opal/dss/dss_types.h" +#include "opal/util/error.h" +#include "opal/util/output.h" +#include "opal/util/show_help.h" + +#include "opal/mca/sec/base/base.h" +#include "sec_basic.h" + +static int init(void); +static void finalize(void); +static int get_token(const opal_identifier_t *proc, + opal_sec_cred_t *token, + size_t size); +static int authenticate(const opal_identifier_t *proc, + opal_sec_cred_t *token, + size_t size); + +opal_sec_base_module_t opal_sec_keystone_module = { + init, + finalize, + get_token, + authenticate +}; + +static int init(void) +{ + return OPAL_SUCCESS; +} + +static void finalize(void) +{ +} + +static int get_token(const opal_identifier_t *proc, + opal_sec_cred_t token, + size_t size) +{ + return OPAL_ERR_NOT_IMPLEMENTED; +} + +static int authenticate(const opal_identifier_t *proc, + opal_sec_cred_t token, + size_t size) +{ + return OPAL_ERR_NOT_IMPLEMENTED; +} + diff --git a/opal/mca/sec/keystone/sec_keystone.h b/opal/mca/sec/keystone/sec_keystone.h new file mode 100644 index 0000000000..01488a49ba --- /dev/null +++ b/opal/mca/sec/keystone/sec_keystone.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2014 Intel, Inc. All rights reserved. + * $COPYRIGHT$ + * + * Additional copyrights may follow + * + * $HEADER$ + */ + +#ifndef OPAL_SEC_KEYSTONE_H +#define OPAL_SEC_KEYSTONE_H + +#include "opal/mca/sec/sec.h" + +BEGIN_C_DECLS + + +OPAL_MODULE_DECLSPEC extern opal_sec_base_component_t mca_sec_keystone_component; +OPAL_DECLSPEC extern opal_sec_base_module_t opal_sec_keystone_module; + +END_C_DECLS + +#endif /* OPAL_SEC_KEYSTONE_H */ diff --git a/opal/mca/sec/keystone/sec_keystone_component.c b/opal/mca/sec/keystone/sec_keystone_component.c new file mode 100644 index 0000000000..474724cb3b --- /dev/null +++ b/opal/mca/sec/keystone/sec_keystone_component.c @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2014 Intel, Inc. All rights reserved. + * $COPYRIGHT$ + * + * Additional copyrights may follow + * + * $HEADER$ + */ + +#include "opal_config.h" +#include "opal/constants.h" + +#include "opal/mca/base/base.h" + +#include "opal/mca/sec/sec.h" +#include "opal/mca/sec/base/base.h" +#include "sec_keystone.h" + +static int sec_keystone_component_open(void); +static int sec_keystone_component_query(mca_base_module_t **module, int *priority); +static int sec_keystone_component_close(void); + +/* + * Instantiate the public struct with all of our public information + * and pointers to our public functions in it + */ +opal_sec_base_component_t mca_sec_keystone_component = { + { + OPAL_SEC_BASE_VERSION_1_0_0, + + /* Component name and version */ + "keystone", + OPAL_MAJOR_VERSION, + OPAL_MINOR_VERSION, + OPAL_RELEASE_VERSION, + + /* Component open and close functions */ + sec_keystone_component_open, + sec_keystone_component_close, + sec_keystone_component_query, + NULL + }, + { + /* The component is checkpoint ready */ + MCA_BASE_METADATA_PARAM_CHECKPOINT + } +}; + +static int sec_keystone_component_open(void) +{ + return OPAL_SUCCESS; +} + +static int sec_keystone_component_query(mca_base_module_t **module, int *priority) +{ + /* we are the default, so set ourselves low in the priority */ + *priority = 0; + *module = (mca_base_module_t*)&opal_sec_keystone_module; + return OPAL_SUCCESS; +} + + +static int sec_keystone_component_close(void) +{ + return OPAL_SUCCESS; +} diff --git a/opal/mca/sec/sec.h b/opal/mca/sec/sec.h new file mode 100644 index 0000000000..db3ae710a4 --- /dev/null +++ b/opal/mca/sec/sec.h @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2014 Intel, Inc. All rights reserved. + * $COPYRIGHT$ + * + * Additional copyrights may follow + * + * $HEADER$ + */ +/** @file: + * + * The Security Framework + * + */ + +#ifndef OPAL_SEC_H +#define OPAL_SEC_H + +#include "opal_config.h" +#include "opal/types.h" + +#include "opal/mca/mca.h" +#include "opal/dss/dss_types.h" + + +/* The security framework is a single-select one - i.e., + * only one plugin is active at any time, though multiple + * plugins may build. When init is called, each plugin that + * built should check to see if it can connect to its + * respective server - if it can, then it should return + * success to indicate it is ready to be used. + */ + +BEGIN_C_DECLS + +#define OPAL_SEC_CRED_MAX_SIZE 512 // max size of the OPAL security credential +typedef uint8_t* opal_sec_cred_t; + +/* + * Initialize the module + */ +typedef int (*opal_sec_base_module_init_fn_t)(void); + +/* + * Finalize the module + */ +typedef void (*opal_sec_base_module_finalize_fn_t)(void); + +/* + * Get a security credential - given my process identifier, return + * a "token" that I can use for authenticating myself to another process. + * The value must be returned in the provided location, subject to + * the specified size constraint, in a network-byte-ordered form suitable + * for sending across the network. + * + * Function returns OPAL_SUCCESS if a token was assigned, or an error + * code indicating why it failed + */ +typedef int (*opal_sec_base_module_get_token_fn_t)(const opal_identifier_t *proc, + opal_sec_cred_t token, + size_t size); + +/* + * Authenticate a security credential - given a process identifier and + * the security credential it provided, determine if the credential is + * valid. The credential is passed in a network-byte-ordered form as it + * came across the network. + * + * Function returns OPAL_SUCCESS if the token is authenticated, or an + * error code indicating why it failed + */ +typedef int (*opal_sec_base_module_auth_fn_t)(const opal_identifier_t *proc, + opal_sec_cred_t token, + size_t size); + +/* + * the standard module data structure + */ +struct opal_sec_base_module_1_0_0_t { + opal_sec_base_module_init_fn_t init; + opal_sec_base_module_finalize_fn_t finalize; + opal_sec_base_module_get_token_fn_t get_token; + opal_sec_base_module_auth_fn_t authenticate; +}; +typedef struct opal_sec_base_module_1_0_0_t opal_sec_base_module_1_0_0_t; +typedef struct opal_sec_base_module_1_0_0_t opal_sec_base_module_t; + +/* + * the standard component data structure + */ +struct opal_sec_base_component_1_0_0_t { + mca_base_component_t base_version; + mca_base_component_data_t base_data; +}; +typedef struct opal_sec_base_component_1_0_0_t opal_sec_base_component_1_0_0_t; +typedef struct opal_sec_base_component_1_0_0_t opal_sec_base_component_t; + +/* + * Macro for use in components that are of type sec + */ +#define OPAL_SEC_BASE_VERSION_1_0_0 \ + MCA_BASE_VERSION_2_0_0, \ + "sec", 1, 0, 0 + +/* Global structure for accessing SEC functions */ +OPAL_DECLSPEC extern opal_sec_base_module_t opal_sec; /* holds base function pointers */ + +END_C_DECLS + +#endif diff --git a/opal/runtime/opal_finalize.c b/opal/runtime/opal_finalize.c index 2e7d0e3e70..901493fdcb 100644 --- a/opal/runtime/opal_finalize.c +++ b/opal/runtime/opal_finalize.c @@ -12,7 +12,7 @@ * Copyright (c) 2008-2012 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2010-2013 Los Alamos National Security, LLC. * All rights reserved. - * Copyright (c) 2013 Intel, Inc. All rights reserved + * Copyright (c) 2013-2014 Intel, Inc. All rights reserved * $COPYRIGHT$ * * Additional copyrights may follow @@ -42,6 +42,7 @@ #include "opal/mca/memcpy/base/base.h" #include "opal/mca/memory/base/base.h" #include "opal/mca/backtrace/base/base.h" +#include "opal/mca/sec/base/base.h" #include "opal/mca/timer/base/base.h" #include "opal/mca/hwloc/base/base.h" #include "opal/mca/event/base/base.h" @@ -124,6 +125,9 @@ opal_finalize(void) /* close the checkpoint and restart service */ opal_cr_finalize(); + /* close the security framework */ + (void) mca_base_framework_close(&opal_sec_base_framework); + #if OPAL_ENABLE_FT_CR == 1 (void) mca_base_framework_close(&opal_compress_base_framework); #endif diff --git a/opal/runtime/opal_init.c b/opal/runtime/opal_init.c index 02c4f25738..e6d8a8de71 100644 --- a/opal/runtime/opal_init.c +++ b/opal/runtime/opal_init.c @@ -40,6 +40,7 @@ #include "opal/mca/memory/base/base.h" #include "opal/mca/memcpy/base/base.h" #include "opal/mca/hwloc/base/base.h" +#include "opal/mca/sec/base/base.h" #include "opal/mca/timer/base/base.h" #include "opal/mca/memchecker/base/base.h" #include "opal/dss/dss.h" @@ -488,6 +489,16 @@ opal_init(int* pargc, char*** pargv) goto return_error; } + /* initialize the security framework */ + if( OPAL_SUCCESS != (ret = mca_base_framework_open(&opal_sec_base_framework, 0)) ) { + error = "opal_sec_base_open"; + goto return_error; + } + if( OPAL_SUCCESS != (ret = opal_sec_base_select()) ) { + error = "opal_sec_base_select"; + goto return_error; + } + return OPAL_SUCCESS; return_error: diff --git a/orte/mca/oob/tcp/oob_tcp.c b/orte/mca/oob/tcp/oob_tcp.c index 8b21022dd0..54460e5b73 100644 --- a/orte/mca/oob/tcp/oob_tcp.c +++ b/orte/mca/oob/tcp/oob_tcp.c @@ -52,6 +52,7 @@ #include "opal/util/net.h" #include "opal/util/argv.h" #include "opal/class/opal_hash_table.h" +#include "opal/mca/sec/sec.h" #include "orte/mca/errmgr/errmgr.h" #include "orte/mca/ess/ess.h" @@ -598,25 +599,62 @@ static void recv_probe(int sd, mca_oob_tcp_hdr_t* hdr) * identifier. Used in both the threaded and event listen modes. */ static void recv_connect(mca_oob_tcp_module_t *mod, - int sd, mca_oob_tcp_hdr_t* hdr) + int sd, uint8_t *msg) { mca_oob_tcp_peer_t* peer; - int flags; - int cmpval; + int flags, cmpval; uint64_t *ui64; + mca_oob_tcp_hdr_t *hdr; + char *version; + int rc; opal_output_verbose(OOB_TCP_DEBUG_CONNECT, orte_oob_base_framework.framework_output, - "%s:tcp:recv:connect called", - ORTE_NAME_PRINT(ORTE_PROC_MY_NAME)); + "%s:tcp:recv:connect called with msg size %lu", + ORTE_NAME_PRINT(ORTE_PROC_MY_NAME), + (unsigned long)sizeof(msg)); /* check for invalid name - if this is true, then we have an error */ - cmpval = orte_util_compare_name_fields(ORTE_NS_CMP_ALL, &hdr->origin, ORTE_NAME_INVALID); - if (cmpval == OPAL_EQUAL) { + hdr = (mca_oob_tcp_hdr_t*)msg; // was already converted to host order + if (OPAL_EQUAL == orte_util_compare_name_fields(ORTE_NS_CMP_ALL, &hdr->origin, ORTE_NAME_INVALID)) { ORTE_ERROR_LOG(ORTE_ERR_VALUE_OUT_OF_BOUNDS); + CLOSE_THE_SOCKET(sd); return; } + opal_output_verbose(OOB_TCP_DEBUG_CONNECT, orte_oob_base_framework.framework_output, + "%s connect-ack header from %s is okay", + ORTE_NAME_PRINT(ORTE_PROC_MY_NAME), + ORTE_NAME_PRINT(&hdr->origin)); + + /* check that this is from a matching version */ + version = (char*)(msg + sizeof(mca_oob_tcp_hdr_t)); + if (0 != strcmp(version, orte_version_string)) { + opal_output(0, "%s recv_connect: " + "received different version from %s: %s instead of %s\n", + ORTE_NAME_PRINT(ORTE_PROC_MY_NAME), + ORTE_NAME_PRINT(&(hdr->origin)), + version, orte_version_string); + ORTE_ERROR_LOG(ORTE_ERR_VALUE_OUT_OF_BOUNDS); + CLOSE_THE_SOCKET(sd); + return; + } + + opal_output_verbose(OOB_TCP_DEBUG_CONNECT, orte_oob_base_framework.framework_output, + "%s connect-ack version from %s matches ours", + ORTE_NAME_PRINT(ORTE_PROC_MY_NAME), + ORTE_NAME_PRINT(&hdr->origin)); + + /* check security token */ + if (OPAL_SUCCESS != (rc = opal_sec.authenticate((opal_identifier_t*)(&hdr->origin), + (opal_sec_cred_t)(msg+sizeof(mca_oob_tcp_hdr_t)+strlen(orte_version_string)+1), + OPAL_SEC_CRED_MAX_SIZE))) { + opal_output(0, "%s SECURITY CONNECTION ERROR FROM %s", + ORTE_NAME_PRINT(ORTE_PROC_MY_NAME), + ORTE_NAME_PRINT(&hdr->origin)); + ORTE_ERROR_LOG(rc); + } + opal_output_verbose(OOB_TCP_DEBUG_CONNECT, orte_oob_base_framework.framework_output, "%s mca_oob_tcp_recv_connect: processing connection from %s for socket %d", ORTE_NAME_PRINT(ORTE_PROC_MY_NAME), @@ -635,6 +673,7 @@ static void recv_connect(mca_oob_tcp_module_t *mod, ui64 = (uint64_t*)(&peer->name); if (OPAL_SUCCESS != opal_hash_table_set_value_uint64(&mod->peers, (*ui64), peer)) { OBJ_RELEASE(peer); + CLOSE_THE_SOCKET(sd); return; } } else { @@ -721,21 +760,26 @@ static void recv_connect(mca_oob_tcp_module_t *mod, static void recv_handler(int sd, short flags, void *cbdata) { mca_oob_tcp_conn_op_t *op = (mca_oob_tcp_conn_op_t*)cbdata; - mca_oob_tcp_hdr_t hdr; + size_t cnt, rdsize; + uint8_t *msg; + mca_oob_tcp_hdr_t *hdr; int rc; - size_t cnt; opal_output_verbose(OOB_TCP_DEBUG_CONNECT, orte_oob_base_framework.framework_output, "%s:tcp:recv:handler called", ORTE_NAME_PRINT(ORTE_PROC_MY_NAME)); - /* ensure all is zero'd */ - memset(&hdr, 0, sizeof(hdr)); + /* malloc a fixed size */ + rdsize = OPAL_SEC_CRED_MAX_SIZE + sizeof(mca_oob_tcp_hdr_t) + strlen(orte_version_string) + 1; // need to include the NULL + msg = (uint8_t*)malloc(rdsize); - /* recv the process identifier */ + /* ensure all is zero'd */ + memset(msg, 0, rdsize); + + /* get the handshake */ cnt = 0; - while (cnt < sizeof(hdr)) { - rc = recv(sd, (char *)&hdr, sizeof(hdr), 0); + while (cnt < rdsize) { + rc = recv(sd, (char*)(msg+cnt), rdsize-cnt, 0); if (0 == rc) { if (OOB_TCP_DEBUG_CONNECT <= opal_output_get_verbosity(orte_oob_base_framework.framework_output)) { opal_output(0, "%s mca_oob_tcp_recv_handler: peer closed connection", @@ -756,19 +800,22 @@ static void recv_handler(int sd, short flags, void *cbdata) } cnt += rc; } - MCA_OOB_TCP_HDR_NTOH(&hdr); + /* check the header */ + hdr = (mca_oob_tcp_hdr_t*)msg; + MCA_OOB_TCP_HDR_NTOH(hdr); /* dispatch based on message type */ - switch (hdr.type) { + switch (hdr->type) { case MCA_OOB_TCP_PROBE: - recv_probe(sd, &hdr); + recv_probe(sd, hdr); break; case MCA_OOB_TCP_IDENT: - recv_connect(op->mod, sd, &hdr); + recv_connect(op->mod, sd, msg); break; default: - opal_output(0, "%s mca_oob_tcp_recv_handler: invalid message type: %d\n", - ORTE_NAME_PRINT(ORTE_PROC_MY_NAME), hdr.type); + opal_output(0, "%s recv_handler: invalid message type: %d from peer %s\n", + ORTE_NAME_PRINT(ORTE_PROC_MY_NAME), hdr->type, + ORTE_NAME_PRINT(&hdr->origin)); CLOSE_THE_SOCKET(sd); break; } diff --git a/orte/mca/oob/tcp/oob_tcp_component.c b/orte/mca/oob/tcp/oob_tcp_component.c index 5c8d27bc53..86d7655d26 100644 --- a/orte/mca/oob/tcp/oob_tcp_component.c +++ b/orte/mca/oob/tcp/oob_tcp_component.c @@ -132,8 +132,8 @@ static int tcp_component_open(void) if (ORTE_PROC_IS_HNP) { OBJ_CONSTRUCT(&mca_oob_tcp_component.listen_thread, opal_thread_t); mca_oob_tcp_component.listen_thread_active = false; - mca_oob_tcp_component.listen_thread_tv.tv_sec = 1; - mca_oob_tcp_component.listen_thread_tv.tv_usec = 0; + mca_oob_tcp_component.listen_thread_tv.tv_sec = 0; + mca_oob_tcp_component.listen_thread_tv.tv_usec = 300000; } mca_oob_tcp_component.addr_count = 0; OBJ_CONSTRUCT(&mca_oob_tcp_component.modules, opal_pointer_array_t); diff --git a/orte/mca/oob/tcp/oob_tcp_connection.c b/orte/mca/oob/tcp/oob_tcp_connection.c index 5d83de48f9..84b08e79ce 100644 --- a/orte/mca/oob/tcp/oob_tcp_connection.c +++ b/orte/mca/oob/tcp/oob_tcp_connection.c @@ -13,7 +13,7 @@ * All rights reserved. * Copyright (c) 2009 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2011 Oak Ridge National Labs. All rights reserved. - * Copyright (c) 2013 Intel, Inc. All rights reserved. + * Copyright (c) 2013-2014 Intel, Inc. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow @@ -51,6 +51,7 @@ #include "opal_stdint.h" #include "opal/mca/backtrace/backtrace.h" #include "opal/mca/base/mca_base_var.h" +#include "opal/mca/sec/sec.h" #include "opal/util/output.h" #include "opal/util/net.h" #include "opal/util/error.h" @@ -316,24 +317,46 @@ void mca_oob_tcp_peer_try_connect(int fd, short args, void *cbdata) OBJ_RELEASE(op); } +/* send a handshake that includes our process identifier, our + * version string, and a security token to ensure we are talking + * to another OMPI process + */ static int tcp_peer_send_connect_ack(mca_oob_tcp_module_t *mod, mca_oob_tcp_peer_t* peer) { - mca_oob_tcp_hdr_t hdr; + uint8_t *msg; + mca_oob_tcp_hdr_t *hdr; + int rc; + size_t sdsize; opal_output_verbose(OOB_TCP_DEBUG_CONNECT, orte_oob_base_framework.framework_output, "%s SEND CONNECT ACK", ORTE_NAME_PRINT(ORTE_PROC_MY_NAME)); - /* send a handshake that includes our process identifier - * to ensure we are talking to another OMPI process - */ - hdr.origin = *ORTE_PROC_MY_NAME; - hdr.dst = peer->name; - hdr.type = MCA_OOB_TCP_IDENT; - hdr.tag = 0; - hdr.nbytes = 0; - MCA_OOB_TCP_HDR_HTON(&hdr); - if (ORTE_SUCCESS != tcp_peer_send_blocking(mod, peer, &hdr, sizeof(hdr))) { + /* malloc a fixed size */ + sdsize = OPAL_SEC_CRED_MAX_SIZE + sizeof(mca_oob_tcp_hdr_t) + strlen(orte_version_string) + 1; // need to include the NULL + msg = (uint8_t*)malloc(sdsize); + memset(msg, 0, sdsize); + + /* load the header */ + hdr = (mca_oob_tcp_hdr_t*)msg; + hdr->origin = *ORTE_PROC_MY_NAME; + hdr->dst = peer->name; + hdr->type = MCA_OOB_TCP_IDENT; + hdr->tag = 0; + hdr->nbytes = 0; + MCA_OOB_TCP_HDR_HTON(hdr); + + /* load the version string */ + memcpy(msg+sizeof(mca_oob_tcp_hdr_t), orte_version_string, strlen(orte_version_string)); + + /* load our security credential, stepping over to leave the NULL at end of version string */ + if (OPAL_SUCCESS != (rc = opal_sec.get_token((opal_identifier_t*)ORTE_PROC_MY_NAME, + (opal_sec_cred_t)(msg+sizeof(mca_oob_tcp_hdr_t)+strlen(orte_version_string)+1), + OPAL_SEC_CRED_MAX_SIZE))) { + ORTE_ERROR_LOG(rc); + } + + if (ORTE_SUCCESS != tcp_peer_send_blocking(mod, peer, msg, sdsize)) { ORTE_ERROR_LOG(ORTE_ERR_UNREACH); return ORTE_ERR_UNREACH; } @@ -507,17 +530,25 @@ static int tcp_peer_send_blocking(mca_oob_tcp_module_t *mod, int mca_oob_tcp_peer_recv_connect_ack(mca_oob_tcp_module_t *mod, mca_oob_tcp_peer_t* peer) { - mca_oob_tcp_hdr_t hdr; + uint8_t *msg; + mca_oob_tcp_hdr_t *hdr; + char *version; + int rc; + size_t rsize; opal_output_verbose(OOB_TCP_DEBUG_CONNECT, orte_oob_base_framework.framework_output, "%s RECV CONNECT ACK FROM %s ON SOCKET %d", ORTE_NAME_PRINT(ORTE_PROC_MY_NAME), ORTE_NAME_PRINT(&peer->name), peer->sd); - /* ensure all is zero'd */ - memset(&hdr, 0, sizeof(hdr)); + /* malloc a fixed size */ + rsize = OPAL_SEC_CRED_MAX_SIZE + sizeof(mca_oob_tcp_hdr_t) + strlen(orte_version_string) + 1; // need to include the NULL + msg = (uint8_t*)malloc(rsize); - if (tcp_peer_recv_blocking(mod, peer, &hdr, sizeof(hdr))) { + /* ensure all is zero'd */ + memset(msg, 0, rsize); + + if (tcp_peer_recv_blocking(mod, peer, msg, rsize)) { /* If the peer state is CONNECT_ACK, then we were waiting for * the connection to be ack'd */ @@ -538,21 +569,28 @@ int mca_oob_tcp_peer_recv_connect_ack(mca_oob_tcp_module_t *mod, return ORTE_ERR_UNREACH; } - MCA_OOB_TCP_HDR_NTOH(&hdr); - if (hdr.type != MCA_OOB_TCP_IDENT) { + opal_output_verbose(OOB_TCP_DEBUG_CONNECT, orte_oob_base_framework.framework_output, + "%s connect-ack recvd from %s", + ORTE_NAME_PRINT(ORTE_PROC_MY_NAME), + ORTE_NAME_PRINT(&peer->name)); + + /* check the header */ + hdr = (mca_oob_tcp_hdr_t*)msg; + MCA_OOB_TCP_HDR_NTOH(hdr); + if (hdr->type != MCA_OOB_TCP_IDENT) { opal_output(0, "tcp_peer_recv_connect_ack: invalid header type: %d\n", - hdr.type); + hdr->type); peer->state = MCA_OOB_TCP_FAILED; mca_oob_tcp_peer_close(mod, peer); return ORTE_ERR_UNREACH; } /* compare the peers name to the expected value */ - if (OPAL_EQUAL != orte_util_compare_name_fields(ORTE_NS_CMP_ALL, &peer->name, &hdr.origin)) { + if (OPAL_EQUAL != orte_util_compare_name_fields(ORTE_NS_CMP_ALL, &peer->name, &hdr->origin)) { opal_output(0, "%s tcp_peer_recv_connect_ack: " "received unexpected process identifier %s from %s\n", ORTE_NAME_PRINT(ORTE_PROC_MY_NAME), - ORTE_NAME_PRINT(&(hdr.origin)), + ORTE_NAME_PRINT(&(hdr->origin)), ORTE_NAME_PRINT(&(peer->name))); peer->state = MCA_OOB_TCP_FAILED; mca_oob_tcp_peer_close(mod, peer); @@ -560,10 +598,35 @@ int mca_oob_tcp_peer_recv_connect_ack(mca_oob_tcp_module_t *mod, } opal_output_verbose(OOB_TCP_DEBUG_CONNECT, orte_oob_base_framework.framework_output, - "%s connect-ack recvd from %s", + "%s connect-ack header from %s is okay", ORTE_NAME_PRINT(ORTE_PROC_MY_NAME), ORTE_NAME_PRINT(&peer->name)); + /* check that this is from a matching version */ + version = (char*)(msg + sizeof(mca_oob_tcp_hdr_t)); + if (0 != strcmp(version, orte_version_string)) { + opal_output(0, "%s tcp_peer_recv_connect_ack: " + "received different version from %s: %s instead of %s\n", + ORTE_NAME_PRINT(ORTE_PROC_MY_NAME), + ORTE_NAME_PRINT(&(peer->name)), + version, orte_version_string); + peer->state = MCA_OOB_TCP_FAILED; + mca_oob_tcp_peer_close(mod, peer); + return ORTE_ERR_UNREACH; + } + + opal_output_verbose(OOB_TCP_DEBUG_CONNECT, orte_oob_base_framework.framework_output, + "%s connect-ack version from %s matches ours", + ORTE_NAME_PRINT(ORTE_PROC_MY_NAME), + ORTE_NAME_PRINT(&peer->name)); + + /* check security token */ + if (OPAL_SUCCESS != (rc = opal_sec.authenticate((opal_identifier_t*)(&hdr->origin), + (opal_sec_cred_t)(msg+sizeof(mca_oob_tcp_hdr_t)+strlen(orte_version_string)+1), + OPAL_SEC_CRED_MAX_SIZE))) { + ORTE_ERROR_LOG(rc); + } + /* set the peer into the component and OOB-level peer tables to indicate * that we know this peer and we will be handling him */