├── hook ├── modules.json.in └── test_hook_module.cpp ├── authentication ├── kerberos │ ├── authenticatee_module.json.in │ ├── authenticator_module.json.in │ ├── NOTICE │ ├── authenticatee.hpp │ ├── authenticator.hpp │ ├── kerberos_auth_mod.cpp │ ├── README.md │ ├── authenticatee.cpp │ └── authenticator.cpp └── cram_md5 │ ├── modules.json.in │ ├── authenticatee.hpp │ ├── authenticator.hpp │ ├── test_authentication_modules.cpp │ ├── auxprop.hpp │ └── auxprop.cpp ├── isolator ├── modules.json.in ├── test_isolator_module.cpp └── test_isolator_module.hpp ├── bootstrap ├── Makefile.am ├── README.md ├── configure.ac ├── m4 ├── ax_compare_version.m4 └── ax_cxx_compile_stdcxx.m4 └── LICENSE /hook/modules.json.in: -------------------------------------------------------------------------------- 1 | { 2 | "libraries": [ 3 | { 4 | "file": "@abs_top_builddir@/.libs/libtesthook.@LIB_EXT@", 5 | "modules": [ 6 | { 7 | "name": "org_apache_mesos_TestHook" 8 | } 9 | ] 10 | } 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /authentication/kerberos/authenticatee_module.json.in: -------------------------------------------------------------------------------- 1 | { 2 | "libraries": 3 | [ 4 | { 5 | "file": "@abs_top_builddir@/.libs/libkerberosauth.@LIB_EXT@", 6 | "modules": 7 | [ 8 | { 9 | "name": "com_mesosphere_mesos_GSSAPIAuthenticatee" 10 | } 11 | ] 12 | } 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /authentication/kerberos/authenticator_module.json.in: -------------------------------------------------------------------------------- 1 | { 2 | "libraries": 3 | [ 4 | { 5 | "file": "@abs_top_builddir@/.libs/libkerberosauth.@LIB_EXT@", 6 | "modules": 7 | [ 8 | { 9 | "name": "com_mesosphere_mesos_GSSAPIAuthenticator" 10 | } 11 | ] 12 | } 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /isolator/modules.json.in: -------------------------------------------------------------------------------- 1 | { 2 | "libraries": [ 3 | { 4 | "file": "@abs_top_builddir@/.libs/libtestisolator.@LIB_EXT@", 5 | "modules": [ 6 | { 7 | "name": "org_apache_mesos_TestCpuIsolator" 8 | }, 9 | { 10 | "name": "org_apache_mesos_TestMemIsolator" 11 | } 12 | ] 13 | } 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /authentication/cram_md5/modules.json.in: -------------------------------------------------------------------------------- 1 | { 2 | "libraries": [ 3 | { 4 | "file": "@abs_top_builddir@/.libs/libtestauthentication.@LIB_EXT@", 5 | "modules": [ 6 | { 7 | "name": "org_apache_mesos_TestCRAMMD5Authenticator" 8 | }, 9 | { 10 | "name": "org_apache_mesos_TestCRAMMD5Authenticatee" 11 | } 12 | ] 13 | } 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /authentication/kerberos/NOTICE: -------------------------------------------------------------------------------- 1 | Copyright 2014-present Mesosphere Inc. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | -------------------------------------------------------------------------------- /bootstrap: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Make sure that we are in the right directory. 4 | if test ! -f configure.ac; then 5 | cat >&2 <<__EOF__ 6 | 7 | You must run bootstrap from the root of the distribution. 8 | 9 | __EOF__ 10 | exit 1 11 | fi 12 | 13 | if [ -n "$AUTOMAKE" ] || [ -n "$ACLOCAL" ] ; then 14 | if [ -z "$ACLOCAL" ] || [ -z "$AUTOMAKE" ] ; then 15 | _present="AUTOMAKE" 16 | _missing="ACLOCAL" 17 | 18 | [ -n "$ACLOCAL" ] && _present="ACLOCAL" && _missing="AUTOMAKE" 19 | 20 | cat >&2 <<__EOF__ 21 | 22 | [ERROR]: You are providing the path to ${_present} 23 | through your environment but no reference to ${_missing}. 24 | To fix this error please specify ${_missing} too. 25 | 26 | As an example, if you are using automake-1.12 and have 27 | available aclocal-1.12 you will want to do the following: 28 | 29 | AUTOMAKE="/usr/local/bin/automake-1.12" \\ 30 | ACLOCAL="/usr/local/bin/aclocal-1.12" \\ 31 | ./bootstrap 32 | 33 | Your current environment has: 34 | AUTOMAKE="$AUTOMAKE" 35 | ACLOCAL="$ACLOCAL" 36 | 37 | __EOF__ 38 | exit 1 39 | fi 40 | else 41 | AUTOMAKE="$(which automake)" 42 | fi 43 | 44 | 45 | # Note that we don't use '--no-recursive' because older versions of 46 | # autoconf/autoreconf bail with that option. Unfortunately this means 47 | # that we'll modify a lot of files in 3rdparty/libprocess, but that 48 | # may change in the future. 49 | 50 | autoreconf --install -Wall --verbose "${@}" 51 | -------------------------------------------------------------------------------- /authentication/kerberos/authenticatee.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2014-present Mesosphere Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | 18 | #ifndef __AUTHENTICATION_GSSAPI_AUTHENTICATEE_HPP__ 19 | #define __AUTHENTICATION_GSSAPI_AUTHENTICATEE_HPP__ 20 | 21 | #include 22 | 23 | #include 24 | 25 | #include 26 | #include 27 | #include 28 | 29 | namespace mesos { 30 | namespace internal { 31 | namespace gssapi { 32 | 33 | // Forward declaration. 34 | class GSSAPIAuthenticateeProcess; 35 | 36 | 37 | class GSSAPIAuthenticatee : public Authenticatee 38 | { 39 | public: 40 | GSSAPIAuthenticatee(); 41 | 42 | virtual ~GSSAPIAuthenticatee(); 43 | 44 | void prepare(const std::string& service, 45 | const std::string& serverPrefix); 46 | 47 | virtual process::Future authenticate( 48 | const process::UPID& pid, 49 | const process::UPID& clientPid, 50 | const mesos::Credential& credential); 51 | 52 | private: 53 | GSSAPIAuthenticateeProcess* process; 54 | 55 | std::string principal; 56 | std::string service; 57 | std::string serverPrefix; 58 | }; 59 | 60 | } // namespace gssapi { 61 | } // namespace internal { 62 | } // namespace mesos { 63 | 64 | #endif //__AUTHENTICATION_GSSAPI_AUTHENTICATEE_HPP__ 65 | -------------------------------------------------------------------------------- /authentication/cram_md5/authenticatee.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | #ifndef __AUTHENTICATION_CRAM_MD5_AUTHENTICATEE_HPP__ 20 | #define __AUTHENTICATION_CRAM_MD5_AUTHENTICATEE_HPP__ 21 | 22 | #include 23 | 24 | #include 25 | 26 | #include 27 | #include 28 | 29 | #include 30 | 31 | namespace mesos { 32 | namespace internal { 33 | namespace cram_md5 { 34 | 35 | // Forward declaration. 36 | class CRAMMD5AuthenticateeProcess; 37 | 38 | 39 | class CRAMMD5Authenticatee : public Authenticatee 40 | { 41 | public: 42 | // Factory to allow for typed tests. 43 | static Try create(); 44 | 45 | CRAMMD5Authenticatee(); 46 | 47 | virtual ~CRAMMD5Authenticatee(); 48 | 49 | process::Future authenticate( 50 | const process::UPID& pid, 51 | const process::UPID& client, 52 | const Credential& credential); 53 | 54 | private: 55 | CRAMMD5AuthenticateeProcess* process; 56 | }; 57 | 58 | } // namespace cram_md5 { 59 | } // namespace internal { 60 | } // namespace mesos { 61 | 62 | #endif //__AUTHENTICATION_CRAM_MD5_AUTHENTICATEE_HPP__ 63 | -------------------------------------------------------------------------------- /authentication/cram_md5/authenticator.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | #ifndef __AUTHENTICATION_CRAM_MD5_AUTHENTICATOR_HPP__ 20 | #define __AUTHENTICATION_CRAM_MD5_AUTHENTICATOR_HPP__ 21 | 22 | #include 23 | 24 | #include 25 | 26 | #include 27 | #include 28 | 29 | #include 30 | #include 31 | 32 | namespace mesos { 33 | namespace internal { 34 | namespace cram_md5 { 35 | 36 | // Forward declaration. 37 | class CRAMMD5AuthenticatorProcess; 38 | 39 | class CRAMMD5Authenticator : public Authenticator 40 | { 41 | public: 42 | // Factory to allow for typed tests. 43 | static Try create(); 44 | 45 | CRAMMD5Authenticator(); 46 | 47 | virtual ~CRAMMD5Authenticator(); 48 | 49 | virtual Try initialize(const Option& credentials); 50 | 51 | virtual process::Future> authenticate( 52 | const process::UPID& pid); 53 | 54 | private: 55 | CRAMMD5AuthenticatorProcess* process; 56 | }; 57 | 58 | } // namespace cram_md5 { 59 | } // namespace internal { 60 | } // namespace mesos { 61 | 62 | #endif //__AUTHENTICATION_CRAM_MD5_AUTHENTICATOR_HPP__ 63 | -------------------------------------------------------------------------------- /authentication/kerberos/authenticator.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2014-present Mesosphere Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | 18 | #ifndef __AUTHENTICATION_GSSAPI_AUTHENTICATOR_HPP__ 19 | #define __AUTHENTICATION_GSSAPI_AUTHENTICATOR_HPP__ 20 | 21 | #include 22 | 23 | #include 24 | 25 | #include 26 | 27 | #include 28 | #include 29 | #include 30 | 31 | #include 32 | #include 33 | 34 | namespace mesos { 35 | namespace internal { 36 | namespace gssapi { 37 | 38 | // Forward declarations. 39 | class GSSAPIAuthenticatorProcess; 40 | 41 | class GSSAPIAuthenticator : public Authenticator 42 | { 43 | public: 44 | GSSAPIAuthenticator(); 45 | 46 | virtual ~GSSAPIAuthenticator(); 47 | 48 | void prepare(const std::string& service_, 49 | const std::string& serverPrefix_, 50 | const std::string& realm_); 51 | 52 | virtual Try initialize(const Option& credentials); 53 | 54 | virtual process::Future> authenticate( 55 | const process::UPID& pid); 56 | 57 | private: 58 | GSSAPIAuthenticatorProcess* process; 59 | 60 | std::string service; 61 | std::string serverPrefix; 62 | std::string realm; 63 | }; 64 | 65 | } // namespace cram_md5 { 66 | } // namespace internal { 67 | } // namespace mesos { 68 | 69 | #endif // __AUTHENTICATION_GSSAPI_AUTHENTICATOR_HPP__ -------------------------------------------------------------------------------- /authentication/cram_md5/test_authentication_modules.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | #include 20 | #include 21 | 22 | #include 23 | #include 24 | 25 | #include 26 | #include 27 | 28 | #include "authentication/cram_md5/authenticatee.hpp" 29 | #include "authentication/cram_md5/authenticator.hpp" 30 | 31 | using namespace mesos; 32 | 33 | using mesos::Authenticatee; 34 | using mesos::Authenticator; 35 | 36 | static bool compatible() 37 | { 38 | return true; 39 | } 40 | 41 | 42 | static Authenticatee* createCRAMMD5Authenticatee(const Parameters& parameters) 43 | { 44 | return new mesos::internal::cram_md5::CRAMMD5Authenticatee(); 45 | } 46 | 47 | 48 | mesos::modules::Module org_apache_mesos_TestCRAMMD5Authenticatee( 49 | MESOS_MODULE_API_VERSION, 50 | MESOS_VERSION, 51 | "Apache Mesos", 52 | "modules@mesos.apache.org", 53 | "Test CRAM-MD5 SASL authenticatee module.", 54 | compatible, 55 | createCRAMMD5Authenticatee); 56 | 57 | 58 | static Authenticator* createCRAMMD5Authenticator(const Parameters& parameters) 59 | { 60 | return new mesos::internal::cram_md5::CRAMMD5Authenticator(); 61 | } 62 | 63 | 64 | mesos::modules::Module org_apache_mesos_TestCRAMMD5Authenticator( 65 | MESOS_MODULE_API_VERSION, 66 | MESOS_VERSION, 67 | "Apache Mesos", 68 | "modules@mesos.apache.org", 69 | "Test CRAM-MD5 SASL authenticator module.", 70 | compatible, 71 | createCRAMMD5Authenticator); 72 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | # Licensed to the Apache Software Foundation (ASF) under one 2 | # or more contributor license agreements. See the NOTICE file 3 | # distributed with this work for additional information 4 | # regarding copyright ownership. The ASF licenses this file 5 | # to you under the Apache License, Version 2.0 (the 6 | # "License"); you may not use this file except in compliance 7 | # with the License. You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License 16 | 17 | AUTOMAKE_OPTIONS = subdir-objects 18 | ACLOCAL_AMFLAGS = -I m4 19 | 20 | # We want to install modules in mesos directory. 21 | pkglibdir = $(libdir)/mesos 22 | 23 | # Initialize variables here so we can use += operator everywhere else. 24 | pkglib_LTLIBRARIES = 25 | 26 | # Add compiler and linker flags for pthreads. 27 | AM_CXXFLAGS = $(PTHREAD_CFLAGS) 28 | AM_LIBS = $(PTHREAD_LIBS) 29 | 30 | # Setup CPPFLAGS that are used for most source files. 31 | AM_CPPFLAGS = $(MESOS_CPPFLAGS) -Wall -Werror 32 | 33 | # Library containing the test CRAM-MD5 authentication modules. 34 | # TODO(tillt): Add cyrus-sasl2 dependency while removing it from libmesos. 35 | # TODO(tillt): Enable optional building of this module library. 36 | # TODO(tillt): Make this module library installable. See MESOS-1940. 37 | pkglib_LTLIBRARIES += libtestauthentication.la 38 | libtestauthentication_la_SOURCES = \ 39 | authentication/cram_md5/test_authentication_modules.cpp \ 40 | authentication/cram_md5/auxprop.cpp 41 | 42 | libtestauthentication_la_LDFLAGS = \ 43 | -release $(PACKAGE_VERSION) -shared $(MESOS_LDFLAGS) 44 | 45 | # Library containing the kerberos authentication modules. 46 | pkglib_LTLIBRARIES += libkerberosauth.la 47 | libkerberosauth_la_SOURCES = \ 48 | authentication/kerberos/authenticatee.cpp \ 49 | authentication/kerberos/authenticator.cpp \ 50 | authentication/kerberos/kerberos_auth_mod.cpp 51 | 52 | libkerberosauth_la_LDFLAGS = \ 53 | -release $(PACKAGE_VERSION) -shared $(MESOS_LDFLAGS) 54 | 55 | # Library containing test CPU and memory isolator modules. 56 | pkglib_LTLIBRARIES += libtestisolator.la 57 | libtestisolator_la_SOURCES = isolator/test_isolator_module.cpp 58 | libtestisolator_la_LDFLAGS = \ 59 | -release $(PACKAGE_VERSION) -shared $(MESOS_LDFLAGS) 60 | 61 | # Library containing test hook module. 62 | pkglib_LTLIBRARIES += libtesthook.la 63 | libtesthook_la_SOURCES = hook/test_hook_module.cpp 64 | libtesthook_la_LDFLAGS = -release $(PACKAGE_VERSION) -shared $(MESOS_LDFLAGS) 65 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Building the Modules 2 | 3 | Mesos modules provide a way to easily extend inner workings of Mesos by creating 4 | and using shared libraries that are loaded on demand. Modules can be used to 5 | customize Mesos without having to recompiling/relinking for each specific use 6 | case. Modules can isolate external dependencies into separate libraries, thus 7 | resulting into a smaller Mesos core. Modules also make it easy to experiment 8 | with new features. For example, imagine loadable allocators that contain a VM 9 | (Lua, Python, …) which makes it possible to try out new allocator algorithms 10 | written in scripting languages without forcing those dependencies into the 11 | project. Finally, modules provide an easy way for third parties to easily extend 12 | Mesos without having to know all the internal details. 13 | 14 | For more details, please see 15 | [Mesos Modules](http://mesos.apache.org/documentation/latest/modules/). 16 | 17 | 18 | ## Prerequisites 19 | 20 | Building Mesos modules requires system-wide installation of the following: 21 | 22 | 1. google-protobuf 23 | 2. glog 24 | 3. boost 25 | 4. picojson 26 | 27 | ## Build Mesos with some unbundled dependencies 28 | 29 | ### Preparing Mesos source code 30 | First we need to prepare Mesos source code. You can either download the Mesos 31 | standard release in the form of a tarball and extract it, or clone the git 32 | repository. 33 | 34 | Let us assume you did extract/clone 35 | the repository into `~/mesos`. Let us also assume that you build Mesos in a 36 | subdirectory 37 | called `build` (`~/mesos/build`). 38 | 39 | ### Building and Installing Mesos 40 | Next, we need to configure and build Mesos. 41 | Due to the fact that modules will need to have access to a couple of libprocess 42 | dependencies, Mesos itself should get built with unbundled dependencies to 43 | reduce chances of problems introduced by varying versions (libmesos vs. module 44 | library). 45 | 46 | We recommend using the following configure options: 47 | 48 | ``` 49 | cd 50 | mkdir build 51 | cd build 52 | ../configure --with-glog=/usr/local --with-protobuf=/usr/local --with-boost=/usr/local --prefix=$HOME/usr 53 | make 54 | make install 55 | ``` 56 | 57 | Note that the `--prefix=$HOME/usr` is required only if you don't want to do a system-wide Mesos installation. 58 | 59 | ## Build Mesos Modules 60 | 61 | Once that is done, extract/clone the mesos-modules package. For the sake of this 62 | example, that could be in `~/mesos-modules`. Note that you should not put 63 | `mesos-modules` into the `mesos` folder. 64 | 65 | You may now run start building the modules. 66 | 67 | The configuration phase needs to know some details about your Mesos installation 68 | location, hence the following are used: 69 | `--with-mesos=/path/to/mesos/installation` 70 | 71 | ## Example 72 | ``` 73 | ./bootstrap 74 | mkdir build && cd build 75 | ../configure --with-mesos=/path/to/mesos/installation 76 | make 77 | ``` 78 | 79 | At this point, the Module libraries are ready in `/build/.libs`. 80 | 81 | ## Using Mesos Modules 82 | See [Mesos Modules](http://mesos.apache.org/documentation/latest/modules/). 83 | -------------------------------------------------------------------------------- /authentication/cram_md5/auxprop.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | #ifndef __AUTHENTICATION_CRAM_MD5_AUXPROP_HPP__ 20 | #define __AUTHENTICATION_CRAM_MD5_AUXPROP_HPP__ 21 | 22 | #include 23 | #include 24 | 25 | #include 26 | #include 27 | 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | 34 | namespace mesos { 35 | namespace internal { 36 | namespace cram_md5 { 37 | 38 | struct Property 39 | { 40 | std::string name; 41 | std::list values; 42 | }; 43 | 44 | 45 | class InMemoryAuxiliaryPropertyPlugin 46 | { 47 | public: 48 | static const char* name() { return "in-memory-auxprop"; } 49 | 50 | static void load(const Multimap& _properties) 51 | { 52 | synchronized (mutex) { 53 | properties = _properties; 54 | } 55 | } 56 | 57 | static Option> lookup( 58 | const std::string& user, 59 | const std::string& name) 60 | { 61 | synchronized (mutex) { 62 | if (properties.contains(user)) { 63 | foreach (const Property& property, properties.get(user)) { 64 | if (property.name == name) { 65 | return property.values; 66 | } 67 | } 68 | } 69 | } 70 | 71 | return None(); 72 | } 73 | 74 | // SASL plugin initialize entry. 75 | static int initialize( 76 | const sasl_utils_t* utils, 77 | int api, 78 | int* version, 79 | sasl_auxprop_plug_t** plug, 80 | const char* name); 81 | 82 | private: 83 | #if SASL_AUXPROP_PLUG_VERSION <= 4 84 | static void lookup( 85 | #else 86 | static int lookup( 87 | #endif 88 | void* context, 89 | sasl_server_params_t* sparams, 90 | unsigned flags, 91 | const char* user, 92 | unsigned length); 93 | 94 | // TODO(tillt): For allowing multiple authenticators with differing 95 | // credentials, consider using a non-static credential properties. 96 | static Multimap properties; 97 | 98 | static sasl_auxprop_plug_t plugin; 99 | 100 | // Access to 'properties' has to be protected as multiple 101 | // authenticator instances may be active concurrently. 102 | static std::mutex mutex; 103 | }; 104 | 105 | } // namespace cram_md5 { 106 | } // namespace internal { 107 | } // namespace mesos { 108 | 109 | #endif // __AUTHENTICATION_CRAM_MD5_AUXPROP_HPP__ 110 | -------------------------------------------------------------------------------- /authentication/kerberos/kerberos_auth_mod.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2014-present Mesosphere Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include 18 | #include 19 | 20 | #include 21 | #include 22 | 23 | #include 24 | #include 25 | 26 | #include 27 | 28 | #include "authenticatee.hpp" 29 | #include "authenticator.hpp" 30 | 31 | using namespace mesos; 32 | 33 | using mesos::Authenticatee; 34 | using mesos::Authenticator; 35 | 36 | using std::string; 37 | 38 | static bool compatible() 39 | { 40 | return true; 41 | } 42 | 43 | 44 | std::string getEnvironment(const std::string& key) 45 | { 46 | const Option path = os::getenv(key); 47 | return path.isSome() ? path.get() : std::string(); 48 | } 49 | 50 | 51 | static Authenticatee* createGSSAPIAuthenticatee(const Parameters& parameters) 52 | { 53 | mesos::internal::gssapi::GSSAPIAuthenticatee* authenticatee( 54 | new mesos::internal::gssapi::GSSAPIAuthenticatee()); 55 | 56 | // Get user configuration overrides from the environment for 57 | // backwards compatibility. 58 | string service = getEnvironment("SASL_SERVICE_NAME"); 59 | string serverPrefix = getEnvironment("SASL_SERVER_PREFIX"); 60 | 61 | // Get user configuration overrides from the module parameters. 62 | foreach (const mesos::Parameter& parameter, parameters.parameter()) { 63 | if (parameter.has_key() && parameter.has_value()) { 64 | if (parameter.key() == "service_name") { 65 | service = parameter.value(); 66 | } else if (parameter.key() == "server_prefix") { 67 | serverPrefix = parameter.value(); 68 | } else { 69 | LOG(WARNING) << "com_mesosphere_mesos_GSSAPIAuthenticatee does not " 70 | << "support a parameter named '" << parameter.key() << "'"; 71 | } 72 | } 73 | } 74 | 75 | authenticatee->prepare(service, serverPrefix); 76 | 77 | return authenticatee; 78 | } 79 | 80 | 81 | mesos::modules::Module com_mesosphere_mesos_GSSAPIAuthenticatee( 82 | MESOS_MODULE_API_VERSION, 83 | MESOS_VERSION, 84 | "Mesosphere", 85 | "till@mesosphere.io", 86 | "Kerberos (GSSAPI) SASL authenticatee module.", 87 | compatible, 88 | createGSSAPIAuthenticatee); 89 | 90 | 91 | static Authenticator* createGSSAPIAuthenticator(const Parameters& parameters) 92 | { 93 | mesos::internal::gssapi::GSSAPIAuthenticator* authenticator( 94 | new mesos::internal::gssapi::GSSAPIAuthenticator()); 95 | 96 | // Get user configuration overrides from the environment for 97 | // backwards compatibility. 98 | string service = getEnvironment("SASL_SERVICE_NAME"); 99 | string serverPrefix = getEnvironment("SASL_SERVER_PREFIX"); 100 | string realm = getEnvironment("SASL_REALM"); 101 | 102 | // Get user configuration overrides from the module parameters. 103 | foreach (const mesos::Parameter& parameter, parameters.parameter()) { 104 | if (parameter.has_key() && parameter.has_value()) { 105 | if (parameter.key() == "service_name") { 106 | service = parameter.value(); 107 | } else if (parameter.key() == "server_prefix") { 108 | serverPrefix = parameter.value(); 109 | } else if (parameter.key() == "realm") { 110 | realm = parameter.value(); 111 | } else { 112 | LOG(WARNING) << "com_mesosphere_mesos_GSSAPIAuthenticator does not " 113 | << "support a parameter named '" << parameter.key() << "'"; 114 | } 115 | } 116 | } 117 | 118 | authenticator->prepare(service, serverPrefix, realm); 119 | 120 | return authenticator; 121 | } 122 | 123 | 124 | mesos::modules::Module com_mesosphere_mesos_GSSAPIAuthenticator( 125 | MESOS_MODULE_API_VERSION, 126 | MESOS_VERSION, 127 | "Mesosphere", 128 | "till@mesosphere.io", 129 | "Kerberos (GSSAPI) SASL authenticator module.", 130 | compatible, 131 | createGSSAPIAuthenticator); 132 | -------------------------------------------------------------------------------- /hook/test_hook_module.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | #include 20 | #include 21 | #include 22 | 23 | #include 24 | 25 | #include 26 | #include 27 | #include 28 | 29 | #include 30 | #include 31 | #include 32 | 33 | using namespace mesos; 34 | 35 | using process::Future; 36 | 37 | // Must be kept in sync with variables of the same name in 38 | // tests/hook_tests.cpp. 39 | const char* testLabelKey = "MESOS_Test_Label"; 40 | const char* testLabelValue = "ApacheMesos"; 41 | const char* testRemoveLabelKey = "MESOS_Test_Remove_Label"; 42 | 43 | class TestHook : public Hook 44 | { 45 | public: 46 | virtual Result masterLaunchTaskLabelDecorator( 47 | const TaskInfo& taskInfo, 48 | const FrameworkInfo& frameworkInfo, 49 | const SlaveInfo& slaveInfo) 50 | { 51 | LOG(INFO) << "Executing 'masterLaunchTaskLabelDecorator' hook"; 52 | 53 | Labels labels; 54 | 55 | // Set one known label. 56 | Label* newLabel = labels.add_labels(); 57 | newLabel->set_key(testLabelKey); 58 | newLabel->set_value(testLabelValue); 59 | 60 | // Remove the 'testRemoveLabelKey' label which was set by the test. 61 | foreach (const Label& oldLabel, taskInfo.labels().labels()) { 62 | if (oldLabel.key() != testRemoveLabelKey) { 63 | labels.add_labels()->CopyFrom(oldLabel); 64 | } 65 | } 66 | 67 | return labels; 68 | } 69 | 70 | virtual Result slaveRunTaskLabelDecorator( 71 | const TaskInfo& taskInfo, 72 | const ExecutorInfo& executorInfo, 73 | const FrameworkInfo& frameworkInfo, 74 | const SlaveInfo& slaveInfo) 75 | { 76 | LOG(INFO) << "Executing 'slaveRunTaskLabelDecorator' hook"; 77 | 78 | Labels labels; 79 | 80 | // Set one known label. 81 | Label* newLabel = labels.add_labels(); 82 | newLabel->set_key("baz"); 83 | newLabel->set_value("qux"); 84 | 85 | // Remove label which was set by test. 86 | foreach (const Label& oldLabel, taskInfo.labels().labels()) { 87 | if (oldLabel.key() != "foo") { 88 | labels.add_labels()->CopyFrom(oldLabel); 89 | } 90 | } 91 | 92 | return labels; 93 | } 94 | 95 | // In this hook, we create a new environment variable "FOO" and set 96 | // it's value to "bar". 97 | virtual Result slaveExecutorEnvironmentDecorator( 98 | const ExecutorInfo& executorInfo) 99 | { 100 | LOG(INFO) << "Executing 'slaveExecutorEnvironmentDecorator' hook"; 101 | 102 | Environment environment; 103 | 104 | if (executorInfo.command().has_environment()) { 105 | environment.CopyFrom(executorInfo.command().environment()); 106 | } 107 | 108 | Environment::Variable* variable = environment.add_variables(); 109 | variable->set_name("FOO"); 110 | variable->set_value("bar"); 111 | 112 | return environment; 113 | } 114 | 115 | // This hook is called when the executor is being removed. 116 | virtual Try slaveRemoveExecutorHook( 117 | const FrameworkInfo& frameworkInfo, 118 | const ExecutorInfo& executorInfo) 119 | { 120 | LOG(INFO) << "Executing 'slaveRemoveExecutorHook'"; 121 | 122 | return Nothing(); 123 | } 124 | 125 | 126 | virtual Result slaveTaskStatusLabelDecorator( 127 | const FrameworkID& frameworkId, 128 | const TaskStatus& status) 129 | { 130 | LOG(INFO) << "Executing 'slaveTaskStatusLabelDecorator' hook"; 131 | 132 | Labels labels; 133 | 134 | // Set one known label. 135 | Label* newLabel = labels.add_labels(); 136 | newLabel->set_key("bar"); 137 | newLabel->set_value("qux"); 138 | 139 | // Remove label which was set by test. 140 | foreach (const Label& oldLabel, status.labels().labels()) { 141 | if (oldLabel.key() != "foo") { 142 | labels.add_labels()->CopyFrom(oldLabel); 143 | } 144 | } 145 | 146 | return labels; 147 | } 148 | }; 149 | 150 | 151 | static Hook* createHook(const Parameters& parameters) 152 | { 153 | return new TestHook(); 154 | } 155 | 156 | 157 | // Declares a Hook module named 'org_apache_mesos_TestHook'. 158 | mesos::modules::Module org_apache_mesos_TestHook( 159 | MESOS_MODULE_API_VERSION, 160 | MESOS_VERSION, 161 | "Apache Mesos", 162 | "modules@mesos.apache.org", 163 | "Test Hook module.", 164 | NULL, 165 | createHook); 166 | -------------------------------------------------------------------------------- /isolator/test_isolator_module.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | #include 20 | 21 | #include 22 | 23 | #include 24 | 25 | #include 26 | #include 27 | #include 28 | 29 | #include 30 | #include 31 | 32 | #include "test_isolator_module.hpp" 33 | 34 | using namespace mesos; 35 | using namespace mesos::slave; 36 | 37 | // A basic Isolator that keeps track of the pid but doesn't do any resource 38 | // isolation. Subclasses must implement usage() for their appropriate 39 | // resource(s). 40 | 41 | Try TestIsolatorProcess::create( 42 | const Parameters& parameters) 43 | { 44 | return new TestIsolator(process::Owned( 45 | new TestIsolatorProcess(parameters))); 46 | } 47 | 48 | process::Future TestIsolatorProcess::recover( 49 | const std::vector& states, 50 | const hashset& orphans) 51 | { 52 | foreach (const ContainerState& run, states) { 53 | // This should (almost) never occur: see comment in 54 | // PosixLauncher::recover(). 55 | if (pids.contains(run.container_id())) { 56 | return process::Failure("Container already recovered"); 57 | } 58 | 59 | pids.put(run.container_id(), run.pid()); 60 | 61 | process::Owned> promise( 62 | new process::Promise()); 63 | promises.put(run.container_id(), promise); 64 | } 65 | 66 | return Nothing(); 67 | } 68 | 69 | process::Future> 70 | TestIsolatorProcess::prepare( 71 | const ContainerID& containerId, 72 | const mesos::slave::ContainerConfig& containerConfig) 73 | { 74 | if (promises.contains(containerId)) { 75 | return process::Failure("Container " + stringify(containerId) + 76 | " has already been prepared"); 77 | } 78 | 79 | process::Owned> promise( 80 | new process::Promise()); 81 | promises.put(containerId, promise); 82 | 83 | return None(); 84 | } 85 | 86 | process::Future TestIsolatorProcess::isolate( 87 | const ContainerID& containerId, 88 | pid_t pid) 89 | { 90 | if (!promises.contains(containerId)) { 91 | return process::Failure("Unknown container: " + stringify(containerId)); 92 | } 93 | 94 | pids.put(containerId, pid); 95 | 96 | return Nothing(); 97 | } 98 | 99 | process::Future TestIsolatorProcess::watch( 100 | const ContainerID& containerId) 101 | { 102 | if (!promises.contains(containerId)) { 103 | return process::Failure("Unknown container: " + stringify(containerId)); 104 | } 105 | 106 | return promises[containerId]->future(); 107 | } 108 | 109 | process::Future TestIsolatorProcess::update( 110 | const ContainerID& containerId, 111 | const Resources& resources) 112 | { 113 | if (!promises.contains(containerId)) { 114 | return process::Failure("Unknown container: " + stringify(containerId)); 115 | } 116 | 117 | // No resources are actually isolated so nothing to do. 118 | return Nothing(); 119 | } 120 | 121 | process::Future TestIsolatorProcess::usage( 122 | const ContainerID& containerId) 123 | { 124 | if (!pids.contains(containerId)) { 125 | LOG(WARNING) << "No resource usage for unknown container '" 126 | << containerId << "'"; 127 | } 128 | return ResourceStatistics(); 129 | } 130 | 131 | process::Future TestIsolatorProcess::cleanup( 132 | const ContainerID& containerId) 133 | { 134 | if (!promises.contains(containerId)) { 135 | return process::Failure("Unknown container: " + stringify(containerId)); 136 | } 137 | 138 | // TODO(idownes): We should discard the container's promise here to signal 139 | // to anyone that holds the future from watch(). 140 | promises.erase(containerId); 141 | 142 | pids.erase(containerId); 143 | 144 | return Nothing(); 145 | } 146 | 147 | 148 | // The sole purpose of this function is just to exercise the 149 | // compatibility logic. 150 | static bool compatible() 151 | { 152 | return true; 153 | } 154 | 155 | 156 | static Isolator* createTestIsolator(const Parameters& parameters) 157 | { 158 | Try result = TestIsolatorProcess::create(parameters); 159 | if (result.isError()) { 160 | return NULL; 161 | } 162 | return result.get(); 163 | } 164 | 165 | 166 | // Declares a CPU Isolator module named 'testCpuIsolator'. 167 | mesos::modules::Module org_apache_mesos_TestIsolator( 168 | MESOS_MODULE_API_VERSION, 169 | MESOS_VERSION, 170 | "Apache Mesos", 171 | "modules@mesos.apache.org", 172 | "Test Isolator module.", 173 | compatible, 174 | createTestIsolator); 175 | -------------------------------------------------------------------------------- /isolator/test_isolator_module.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | #ifndef __TEST_ISOLATOR_MODULE_HPP__ 20 | #define __TEST_ISOLATOR_MODULE_HPP__ 21 | 22 | #include 23 | 24 | #include 25 | 26 | #include 27 | #include 28 | #include 29 | 30 | #include 31 | #include 32 | 33 | namespace mesos { 34 | 35 | // A basic Isolator that keeps track of the pid but doesn't do any resource 36 | // isolation. Subclasses must implement usage() for their appropriate 37 | // resource(s). 38 | 39 | class TestIsolatorProcess : public process::Process 40 | { 41 | public: 42 | static Try create( 43 | const Parameters& parameters); 44 | 45 | ~TestIsolatorProcess() {} 46 | 47 | process::Future recover( 48 | const std::vector& states, 49 | const hashset& orphans); 50 | 51 | process::Future> prepare( 52 | const ContainerID& containerId, 53 | const mesos::slave::ContainerConfig& containerConfig); 54 | 55 | process::Future isolate( 56 | const ContainerID& containerId, 57 | pid_t pid); 58 | 59 | process::Future watch( 60 | const ContainerID& containerId); 61 | 62 | process::Future update( 63 | const ContainerID& containerId, 64 | const Resources& resources); 65 | 66 | process::Future usage( 67 | const ContainerID& containerId); 68 | 69 | process::Future status( 70 | const ContainerID& containerId); 71 | 72 | process::Future cleanup( 73 | const ContainerID& containerId); 74 | 75 | private: 76 | TestIsolatorProcess(const Parameters& parameters_) 77 | : parameters(parameters_) {} 78 | 79 | const Parameters parameters; 80 | hashmap pids; 81 | hashmap>> 83 | promises; 84 | }; 85 | 86 | 87 | class TestIsolator : public mesos::slave::Isolator 88 | { 89 | public: 90 | TestIsolator(process::Owned process_) 91 | : process(process_) 92 | { 93 | spawn(CHECK_NOTNULL(process.get())); 94 | } 95 | 96 | virtual ~TestIsolator() override 97 | { 98 | terminate(process.get()); 99 | wait(process.get()); 100 | } 101 | 102 | virtual bool supportsNesting() override 103 | { 104 | return false; 105 | } 106 | 107 | virtual bool supportsStandalone() override 108 | { 109 | return false; 110 | } 111 | 112 | 113 | virtual process::Future recover( 114 | const std::vector& states, 115 | const hashset& orphans) override 116 | { 117 | return dispatch(process.get(), 118 | &TestIsolatorProcess::recover, 119 | states, 120 | orphans); 121 | } 122 | 123 | virtual process::Future> prepare( 124 | const ContainerID& containerId, 125 | const mesos::slave::ContainerConfig& containerConfig) override 126 | { 127 | return dispatch(process.get(), 128 | &TestIsolatorProcess::prepare, 129 | containerId, 130 | containerConfig); 131 | } 132 | 133 | virtual process::Future isolate( 134 | const ContainerID& containerId, 135 | pid_t pid) override 136 | { 137 | return dispatch(process.get(), 138 | &TestIsolatorProcess::isolate, 139 | containerId, 140 | pid); 141 | } 142 | 143 | virtual process::Future watch( 144 | const ContainerID& containerId) override 145 | { 146 | return dispatch(process.get(), 147 | &TestIsolatorProcess::watch, 148 | containerId); 149 | } 150 | 151 | virtual process::Future update( 152 | const ContainerID& containerId, 153 | const Resources& resources) override 154 | { 155 | return dispatch(process.get(), 156 | &TestIsolatorProcess::update, 157 | containerId, 158 | resources); 159 | } 160 | 161 | virtual process::Future usage( 162 | const ContainerID& containerId) override 163 | { 164 | return dispatch(process.get(), 165 | &TestIsolatorProcess::usage, 166 | containerId); 167 | } 168 | 169 | virtual process::Future cleanup( 170 | const ContainerID& containerId) override 171 | { 172 | return dispatch(process.get(), 173 | &TestIsolatorProcess::cleanup, 174 | containerId); 175 | } 176 | 177 | private: 178 | process::Owned process; 179 | }; 180 | 181 | } 182 | 183 | #endif // #ifndef __TEST_ISOLATOR_MODULE_HPP__ 184 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | AC_INIT([example-modules],[0.1]) 2 | AC_PREREQ([2.69]) 3 | AC_CONFIG_FILES([Makefile]) 4 | AC_LANG([C++]) 5 | AC_PROG_CC 6 | AC_PROG_CXX 7 | AC_PROG_CC_C_O 8 | AC_CONFIG_MACRO_DIR([m4]) 9 | 10 | AM_INIT_AUTOMAKE([foreign]) 11 | 12 | AX_PYTHON_DEVEL([]) 13 | 14 | LT_PREREQ([2.2]) 15 | LT_INIT 16 | LT_LANG([C++]) 17 | LT_OUTPUT 18 | 19 | AC_ARG_WITH([mesos], 20 | [AS_HELP_STRING([--with-mesos=dir], 21 | [provide root dir for Mesos installation])], 22 | [mesos=$withval], 23 | [mesos=no]) 24 | 25 | AC_ARG_WITH([mesos_root], 26 | [AS_HELP_STRING([--with-mesos-root=dir], 27 | [provide root dir for Mesos sources])], 28 | [mesos_root=$withval], 29 | [mesos_root=no]) 30 | 31 | AC_ARG_WITH([mesos_build_dir], 32 | [AS_HELP_STRING([--with-mesos-build-dir=dir], 33 | [provide Mesos build dir])], 34 | [mesos_build_dir=$withval], 35 | [mesos_build_dir=no]) 36 | 37 | MESOS_CPPFLAGS="" 38 | MESOS_LDFLAGS="" 39 | 40 | if test -d "$mesos"; then 41 | MESOS_CPPFLAGS+=" -I${mesos}/include" 42 | if test -d "${mesos}/lib"; then 43 | MESOS_LDFLAGS+=" -L${mesos}/lib -lmesos -lglog -lprotobuf" 44 | else 45 | MESOS_LDFLAGS+=" -L${mesos}/lib64 -lmesos -lglog -lprotobuf" 46 | fi 47 | else 48 | 49 | if test -d "$mesos_root"; then 50 | MESOS_CPPFLAGS+=" -I${mesos_root}/include" 51 | 52 | # Add src to include path. 53 | MESOS_CPPFLAGS+=" -I${mesos_root}/src" 54 | 55 | # Add libprocess to include path. 56 | MESOS_CPPFLAGS+=" -I${mesos_root}/3rdparty/libprocess/include" 57 | 58 | # Add stout to include path. 59 | MESOS_CPPFLAGS+=" -I${mesos_root}/3rdparty/stout/include" 60 | else 61 | AC_MSG_ERROR([Invalid mesos path; use --with-mesos-root= 62 | is the top-level directory of the Mesos distribution.]) 63 | fi 64 | 65 | if test -d "$mesos_build_dir"; then 66 | MESOS_CPPFLAGS+=" -I${mesos_build_dir}/include" 67 | 68 | # Add src to include path - only needed for mock-tests. 69 | MESOS_CPPFLAGS+=" -I${mesos_build_dir}/src" 70 | else 71 | AC_MSG_ERROR([Invalid mesos build path; use --with-mesos-build-dir= 72 | is the Mesos build directory.]) 73 | fi 74 | fi 75 | 76 | AC_SUBST(MESOS_CPPFLAGS) 77 | AC_SUBST(MESOS_LDFLAGS) 78 | 79 | # Check if we are on OSX or Linux. 80 | case "$host_os" in 81 | linux*) 82 | LIB_EXT="so" 83 | ;; 84 | darwin*) 85 | LIB_EXT="dylib" 86 | ;; 87 | *) 88 | AC_MSG_ERROR("Mesosphere's Modules are currently unsupported on your platform.") 89 | esac 90 | AC_SUBST(LIB_EXT) 91 | 92 | # Check if we're using clang. 93 | AC_MSG_CHECKING([if compiling with clang]) 94 | 95 | AC_LANG_PUSH([C++]) 96 | AC_COMPILE_IFELSE( 97 | [AC_LANG_PROGRAM([], [[ 98 | #ifndef __clang__ 99 | not clang 100 | #endif 101 | ]])], 102 | [CLANG=yes], [CLANG=no]) 103 | AC_LANG_POP([C++]) 104 | 105 | AC_MSG_RESULT([$CLANG]) 106 | AC_SUBST([CLANG]) 107 | 108 | if test "x$CLANG" = "xno"; then 109 | # Check the version of gcc and add any flags as appropriate. Note 110 | # that '-dumpversion' works for clang as well but as of clang 3.3 it 111 | # reports version 4.2.1 (for gcc backwards compatibility). 112 | GCC_VERSION="`${CC} -dumpversion`" 113 | AC_MSG_NOTICE([GCC version: $GCC_VERSION]) 114 | test $? = 0 || AC_MSG_ERROR([failed to determine version of gcc]) 115 | 116 | # Check for GCC version 4.4. 117 | AX_COMPARE_VERSION([$GCC_VERSION], [eq2], [4.4], 118 | [is_gxx44=yes], [is_gxx44=no]) 119 | if test "x$is_gxx44" = "xyes"; then 120 | AC_MSG_NOTICE([Setting up CXXFLAGS for g++-4.4]) 121 | # We fail to build some protobuf generated code with gcc 4.4 122 | # without setting -fno-strict-aliasing. 123 | CFLAGS="$CFLAGS -fno-strict-aliasing" 124 | CXXFLAGS="$CXXFLAGS -fno-strict-aliasing" 125 | fi 126 | 127 | # Check for GCC version >= 4.8. 128 | AX_COMPARE_VERSION([$GCC_VERSION], [ge], [4.8], 129 | [is_ge_gxx48=yes], [is_ge_gxx48=no]) 130 | if test "x$is_ge_gxx48" = "xyes"; then 131 | AC_MSG_NOTICE([Setting up CXXFLAGS for g++ version >= 4.8]) 132 | # Boost 1.53.0 fails to compile with GCC 4.8 without 133 | # -Wno-unused-local-typedefs, and automake does not recognize the 134 | # flag. 135 | # TODO(brenden): Remove this when Boost has a resolution. 136 | CFLAGS="${CFLAGS} -Wno-unused-local-typedefs" 137 | CXXFLAGS="${CXXFLAGS} -Wno-unused-local-typedefs" 138 | fi 139 | 140 | # Check for GCC version == 4.7 and fail. Starting with 4.7 the '#if 141 | # __cplusplus >= 201103L' will evaluate to true which means the 142 | # C++11 code paths will be compiled but certain C++11 features that 143 | # we use are not supported by 4.7. Since we're requiring C++11 going 144 | # forward we can't support this compiler. 145 | AX_COMPARE_VERSION([$GCC_VERSION], [eq2], [4.7], 146 | [is_gxx47=yes], [is_gxx47=no]) 147 | if test "x$is_gxx47" = "xyes"; then 148 | AC_MSG_ERROR([Unable to build with g++-4.7 due to missing C++11 features]) 149 | fi 150 | fi 151 | 152 | # Ensure we can build the C++11 features we expect, and set the std 153 | # CXXFLAG as appropriate. 154 | AX_CXX_COMPILE_STDCXX([11], [noext], [mandatory]) 155 | 156 | # Check if headers and library were located. 157 | AC_CHECK_HEADER([glog/logging.h], 158 | [AC_LINK_IFELSE( 159 | [AC_LANG_PROGRAM([#include ], [])], 160 | [], 161 | [AC_MSG_ERROR([glog is not installed.])])], 162 | [AC_MSG_ERROR([cannot find glog header.])]) 163 | 164 | AC_CHECK_HEADER([google/protobuf/message.h], 165 | [AC_LINK_IFELSE( 166 | [AC_LANG_PROGRAM([#include ], [])], 167 | [], 168 | [AC_MSG_ERROR([google protobuf is not installed.])])], 169 | [AC_MSG_ERROR([google protobuf is not installed.])]) 170 | 171 | AC_CHECK_HEADER([picojson.h], 172 | [], 173 | [AC_MSG_ERROR([picojson is not installed.])]) 174 | 175 | AC_CHECK_HEADERS([boost/lexical_cast.hpp boost/functional/hash.hpp], 176 | [], 177 | [AC_MSG_ERROR([boost is not installed.])]) 178 | 179 | # Create Modules JSON blobs. 180 | AC_CONFIG_FILES([authentication/cram_md5/modules.json], []) 181 | AC_CONFIG_FILES([authentication/kerberos/authenticatee_module.json], []) 182 | AC_CONFIG_FILES([authentication/kerberos/authenticator_module.json], []) 183 | AC_CONFIG_FILES([hook/modules.json], []) 184 | AC_CONFIG_FILES([isolator/modules.json], []) 185 | 186 | AC_OUTPUT 187 | -------------------------------------------------------------------------------- /authentication/kerberos/README.md: -------------------------------------------------------------------------------- 1 | # Mesos Kerberos Authentication Modules 2 | 3 | Modules allowing the SASL based authentication of slaves and frameworks against a master using Kerberos, via GSSAPI. 4 | 5 | ## Build 6 | See [Building the Modules](https://github.com/mesosphere/proprietary-modules). 7 | 8 | ## Prerequisites 9 | 10 | ### Kerberos 11 | 12 | These modules rely upon a fully setup Kerberos KDC [Key Distribution Center]. 13 | - [Manually setting up a KDC on Amazon's AWS](https://github.com/mesosphere/documentation/wiki/Prepare-AWS-for-Kerberos) 14 | - [Setting up a dockerized KDC](https://github.com/tillt/docker-kdc) 15 | 16 | ## Setup 17 | 18 | Create a host specific JSON file (e.g. `master_gssapi.json` or `slave_gssapi.json`): 19 | 20 | #### Authenticator module JSON 21 | 22 | This module supports parameters. All of those parameters are optional. For backwards compatiblity, the parameters may also get supplied using environment variables. 23 | 24 | | key | default value | description | environment variable | 25 | |-----------------|---------------|------------------------------------------------|----------------------| 26 | | `service_name` | `mesos` | The registered name of the service using SASL. | `SASL_SERVICE_NAME` | 27 | | `server_prefix` | | Added in front of the hostname. | `SASL_SERVER_PREFIX` | 28 | | `realm` | | The domain of the user agent. | `SASL_REALM` | 29 | 30 | ``` 31 | { 32 | "libraries": [ 33 | { 34 | "file": "/path/to/libkerberosauth.so", 35 | "modules": [ 36 | { 37 | "name": "com_mesosphere_mesos_GSSAPIAuthenticator", 38 | "parameters": [ 39 | { 40 | "key": "service_name", 41 | "value": "registered name" 42 | }, 43 | { 44 | "key": "server_prefix", 45 | "value": "hostname prefix" 46 | }, 47 | { 48 | "key": "realm", 49 | "value": "kerberos realm" 50 | } 51 | ] 52 | } 53 | ] 54 | } 55 | ] 56 | } 57 | ``` 58 | 59 | 60 | #### Authenticatee module JSON 61 | 62 | This module supports parameters. All of those parameters are optional. For backwards compatiblity, the parameters may also get supplied using environment variables. 63 | 64 | | key | default value | description | environment variable | 65 | |-----------------|---------------|------------------------------------------------|----------------------| 66 | | `service_name` | `mesos` | The registered name of the service using SASL. | `SASL_SERVICE_NAME` | 67 | | `server_prefix` | | Added in front of the hostname. | `SASL_SERVER_PREFIX` | 68 | 69 | ``` 70 | { 71 | "libraries": [ 72 | { 73 | "file": "/path/to/libkerberosauth.so", 74 | "modules": [ 75 | { 76 | "name": "com_mesosphere_mesos_GSSAPIAuthenticatee", 77 | "parameters": [ 78 | { 79 | "key": "service_name", 80 | "value": "" 81 | }, 82 | { 83 | "key": "server_prefix", 84 | "value": "" 85 | } 86 | ] 87 | } 88 | ] 89 | } 90 | ] 91 | } 92 | ``` 93 | 94 | #### Authenticatee credential JSON 95 | 96 | For selecting the principal that should get authenticated, use the `--credential` flag of the slave (or framework). Note that no password is used / required. 97 | 98 | ``` 99 | { 100 | "principal": "kerberos principal" 101 | } 102 | ``` 103 | 104 | #### Kerberos specific environment variables 105 | 106 | The following environment variables are supported. 107 | 108 | | name | description | 109 | |---------------|------------------------------------------------------------------------------------------------------------------------------| 110 | | `KRB5_KTNAME` | Default keytab file name. | 111 | | `KBB5CCNAME` | Default name for the credentials cache file. | 112 | | `KRB5_TRACE` | File name for trace-logging output. For example, `export KRB5_TRACE=/dev/stderr` would send tracing information to `stderr`. __Note__: this is for debugging Kerberos specifics and does not affect the log-output of Mesos or the modules. | 113 | 114 | ## Use 115 | 116 | #### Running a master 117 | 118 | ##### Relevant flags 119 | 120 | | name | description 121 | |-----------------------|----------------------------------------------------------| 122 | | `authenticate` | Only authenticated frameworks are allowed to register. | 123 | | `authenticate_slaves` | Only authenticated slaves are allowed to register. | 124 | | `authenticators` | Authenticator implementation to use when authenticating. | 125 | | `modules` | List of modules to be loaded. | 126 | 127 | ##### Example 128 | 129 | Enforce Kerberos authenticated slaves: 130 | 131 | ``` 132 | ./bin/mesos-master.sh --authenticate_slaves \ 133 | --authenticators=com_mesosphere_mesos_GSSAPIAuthenticator \ 134 | --work_dir=/tmp/mesos \ 135 | --modules=file://path/to/authenticator_modules.json 136 | ``` 137 | 138 | #### Running a slave 139 | 140 | ##### Relevant flags 141 | 142 | | name | description | 143 | |------------------|----------------------------------------------------------| 144 | | `authenticatee` | Authenticatee implementation to use when authenticating. | 145 | | `credential` | Information used for selecting a principal. | 146 | | `modules` | List of modules to be loaded. | 147 | 148 | ##### Example 149 | 150 | Enable Kerberos authentication when registering: 151 | 152 | ``` 153 | ./bin/mesos-slave.sh --master=master_ip:port \ 154 | --authenticatee=com_mesosphere_mesos_GSSAPIAuthenticatee \ 155 | --credential=file://path/to/credential.json \ 156 | --modules=file://path/to/authenticatee_modules.json 157 | ``` 158 | 159 | #### Running the test-framework 160 | 161 | ##### Relevant environment variables 162 | 163 | | name | description | 164 | |-----------------------|----------------------------------------------------------| 165 | | `DEFAULT_PRINCIPAL` | Information used for selecting a principal. | 166 | | `MESOS_AUTHENTICATE` | Enables authentication. | 167 | | `MESOS_AUTHENTICATEE` | Authenticatee implementation to use when authenticating. | 168 | | `MESOS_MODULES` | List of modules to be loaded. | 169 | 170 | ##### Example 171 | 172 | Enable Kerberos authentication when registering: 173 | 174 | ``` 175 | MESOS_AUTHENTICATE=YES \ 176 | DEFAULT_PRINCIPAL="mesos/hostname.domain.name" \ 177 | MESOS_MODULES=file://path/to/authenticatee_modules.json \ 178 | MESOS_AUTHENTICATEE=com_mesosphere_mesos_GSSAPIAuthenticatee \ 179 | ./src/test-framework.sh --master=master_ip:port 180 | ``` 181 | -------------------------------------------------------------------------------- /m4/ax_compare_version.m4: -------------------------------------------------------------------------------- 1 | # =========================================================================== 2 | # http://www.gnu.org/software/autoconf-archive/ax_compare_version.html 3 | # =========================================================================== 4 | # 5 | # SYNOPSIS 6 | # 7 | # AX_COMPARE_VERSION(VERSION_A, OP, VERSION_B, [ACTION-IF-TRUE], [ACTION-IF-FALSE]) 8 | # 9 | # DESCRIPTION 10 | # 11 | # This macro compares two version strings. Due to the various number of 12 | # minor-version numbers that can exist, and the fact that string 13 | # comparisons are not compatible with numeric comparisons, this is not 14 | # necessarily trivial to do in a autoconf script. This macro makes doing 15 | # these comparisons easy. 16 | # 17 | # The six basic comparisons are available, as well as checking equality 18 | # limited to a certain number of minor-version levels. 19 | # 20 | # The operator OP determines what type of comparison to do, and can be one 21 | # of: 22 | # 23 | # eq - equal (test A == B) 24 | # ne - not equal (test A != B) 25 | # le - less than or equal (test A <= B) 26 | # ge - greater than or equal (test A >= B) 27 | # lt - less than (test A < B) 28 | # gt - greater than (test A > B) 29 | # 30 | # Additionally, the eq and ne operator can have a number after it to limit 31 | # the test to that number of minor versions. 32 | # 33 | # eq0 - equal up to the length of the shorter version 34 | # ne0 - not equal up to the length of the shorter version 35 | # eqN - equal up to N sub-version levels 36 | # neN - not equal up to N sub-version levels 37 | # 38 | # When the condition is true, shell commands ACTION-IF-TRUE are run, 39 | # otherwise shell commands ACTION-IF-FALSE are run. The environment 40 | # variable 'ax_compare_version' is always set to either 'true' or 'false' 41 | # as well. 42 | # 43 | # Examples: 44 | # 45 | # AX_COMPARE_VERSION([3.15.7],[lt],[3.15.8]) 46 | # AX_COMPARE_VERSION([3.15],[lt],[3.15.8]) 47 | # 48 | # would both be true. 49 | # 50 | # AX_COMPARE_VERSION([3.15.7],[eq],[3.15.8]) 51 | # AX_COMPARE_VERSION([3.15],[gt],[3.15.8]) 52 | # 53 | # would both be false. 54 | # 55 | # AX_COMPARE_VERSION([3.15.7],[eq2],[3.15.8]) 56 | # 57 | # would be true because it is only comparing two minor versions. 58 | # 59 | # AX_COMPARE_VERSION([3.15.7],[eq0],[3.15]) 60 | # 61 | # would be true because it is only comparing the lesser number of minor 62 | # versions of the two values. 63 | # 64 | # Note: The characters that separate the version numbers do not matter. An 65 | # empty string is the same as version 0. OP is evaluated by autoconf, not 66 | # configure, so must be a string, not a variable. 67 | # 68 | # The author would like to acknowledge Guido Draheim whose advice about 69 | # the m4_case and m4_ifvaln functions make this macro only include the 70 | # portions necessary to perform the specific comparison specified by the 71 | # OP argument in the final configure script. 72 | # 73 | # LICENSE 74 | # 75 | # Copyright (c) 2008 Tim Toolan ; 76 | # 77 | # Copying and distribution of this file, with or without modification, are 78 | # permitted in any medium without royalty provided the copyright notice 79 | # and this notice are preserved. This file is offered as-is, without any 80 | # warranty. 81 | 82 | #serial 11 83 | 84 | dnl ######################################################################### 85 | AC_DEFUN([AX_COMPARE_VERSION], [ 86 | AC_REQUIRE([AC_PROG_AWK]) 87 | 88 | # Used to indicate true or false condition 89 | ax_compare_version=false 90 | 91 | # Convert the two version strings to be compared into a format that 92 | # allows a simple string comparison. The end result is that a version 93 | # string of the form 1.12.5-r617 will be converted to the form 94 | # 0001001200050617. In other words, each number is zero padded to four 95 | # digits, and non digits are removed. 96 | AS_VAR_PUSHDEF([A],[ax_compare_version_A]) 97 | A=`echo "$1" | sed -e 's/\([[0-9]]*\)/Z\1Z/g' \ 98 | -e 's/Z\([[0-9]]\)Z/Z0\1Z/g' \ 99 | -e 's/Z\([[0-9]][[0-9]]\)Z/Z0\1Z/g' \ 100 | -e 's/Z\([[0-9]][[0-9]][[0-9]]\)Z/Z0\1Z/g' \ 101 | -e 's/[[^0-9]]//g'` 102 | 103 | AS_VAR_PUSHDEF([B],[ax_compare_version_B]) 104 | B=`echo "$3" | sed -e 's/\([[0-9]]*\)/Z\1Z/g' \ 105 | -e 's/Z\([[0-9]]\)Z/Z0\1Z/g' \ 106 | -e 's/Z\([[0-9]][[0-9]]\)Z/Z0\1Z/g' \ 107 | -e 's/Z\([[0-9]][[0-9]][[0-9]]\)Z/Z0\1Z/g' \ 108 | -e 's/[[^0-9]]//g'` 109 | 110 | dnl # In the case of le, ge, lt, and gt, the strings are sorted as necessary 111 | dnl # then the first line is used to determine if the condition is true. 112 | dnl # The sed right after the echo is to remove any indented white space. 113 | m4_case(m4_tolower($2), 114 | [lt],[ 115 | ax_compare_version=`echo "x$A 116 | x$B" | sed 's/^ *//' | sort -r | sed "s/x${A}/false/;s/x${B}/true/;1q"` 117 | ], 118 | [gt],[ 119 | ax_compare_version=`echo "x$A 120 | x$B" | sed 's/^ *//' | sort | sed "s/x${A}/false/;s/x${B}/true/;1q"` 121 | ], 122 | [le],[ 123 | ax_compare_version=`echo "x$A 124 | x$B" | sed 's/^ *//' | sort | sed "s/x${A}/true/;s/x${B}/false/;1q"` 125 | ], 126 | [ge],[ 127 | ax_compare_version=`echo "x$A 128 | x$B" | sed 's/^ *//' | sort -r | sed "s/x${A}/true/;s/x${B}/false/;1q"` 129 | ],[ 130 | dnl Split the operator from the subversion count if present. 131 | m4_bmatch(m4_substr($2,2), 132 | [0],[ 133 | # A count of zero means use the length of the shorter version. 134 | # Determine the number of characters in A and B. 135 | ax_compare_version_len_A=`echo "$A" | $AWK '{print(length)}'` 136 | ax_compare_version_len_B=`echo "$B" | $AWK '{print(length)}'` 137 | 138 | # Set A to no more than B's length and B to no more than A's length. 139 | A=`echo "$A" | sed "s/\(.\{$ax_compare_version_len_B\}\).*/\1/"` 140 | B=`echo "$B" | sed "s/\(.\{$ax_compare_version_len_A\}\).*/\1/"` 141 | ], 142 | [[0-9]+],[ 143 | # A count greater than zero means use only that many subversions 144 | A=`echo "$A" | sed "s/\(\([[0-9]]\{4\}\)\{m4_substr($2,2)\}\).*/\1/"` 145 | B=`echo "$B" | sed "s/\(\([[0-9]]\{4\}\)\{m4_substr($2,2)\}\).*/\1/"` 146 | ], 147 | [.+],[ 148 | AC_WARNING( 149 | [illegal OP numeric parameter: $2]) 150 | ],[]) 151 | 152 | # Pad zeros at end of numbers to make same length. 153 | ax_compare_version_tmp_A="$A`echo $B | sed 's/./0/g'`" 154 | B="$B`echo $A | sed 's/./0/g'`" 155 | A="$ax_compare_version_tmp_A" 156 | 157 | # Check for equality or inequality as necessary. 158 | m4_case(m4_tolower(m4_substr($2,0,2)), 159 | [eq],[ 160 | test "x$A" = "x$B" && ax_compare_version=true 161 | ], 162 | [ne],[ 163 | test "x$A" != "x$B" && ax_compare_version=true 164 | ],[ 165 | AC_WARNING([illegal OP parameter: $2]) 166 | ]) 167 | ]) 168 | 169 | AS_VAR_POPDEF([A])dnl 170 | AS_VAR_POPDEF([B])dnl 171 | 172 | dnl # Execute ACTION-IF-TRUE / ACTION-IF-FALSE. 173 | if test "$ax_compare_version" = "true" ; then 174 | m4_ifvaln([$4],[$4],[:])dnl 175 | m4_ifvaln([$5],[else $5])dnl 176 | fi 177 | ]) dnl AX_COMPARE_VERSION 178 | -------------------------------------------------------------------------------- /authentication/cram_md5/auxprop.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | #include "authentication/cram_md5/auxprop.hpp" 20 | 21 | #include 22 | 23 | using std::list; 24 | using std::string; 25 | 26 | namespace mesos { 27 | namespace internal { 28 | namespace cram_md5 { 29 | 30 | // Storage for the static members. 31 | Multimap InMemoryAuxiliaryPropertyPlugin::properties; 32 | sasl_auxprop_plug_t InMemoryAuxiliaryPropertyPlugin::plugin; 33 | std::mutex InMemoryAuxiliaryPropertyPlugin::mutex; 34 | 35 | 36 | int InMemoryAuxiliaryPropertyPlugin::initialize( 37 | const sasl_utils_t* utils, 38 | int api, 39 | int* version, 40 | sasl_auxprop_plug_t** plug, 41 | const char* name) 42 | { 43 | if (version == NULL || plug == NULL) { 44 | return SASL_BADPARAM; 45 | } 46 | 47 | // Check if SASL API is older than the one we were compiled against. 48 | if (api < SASL_AUXPROP_PLUG_VERSION) { 49 | return SASL_BADVERS; 50 | } 51 | 52 | *version = SASL_AUXPROP_PLUG_VERSION; 53 | 54 | plugin.features = 0; 55 | plugin.spare_int1 = 0; 56 | plugin.glob_context = NULL; 57 | plugin.auxprop_free = NULL; 58 | plugin.auxprop_lookup = &InMemoryAuxiliaryPropertyPlugin::lookup; 59 | plugin.name = const_cast(InMemoryAuxiliaryPropertyPlugin::name()); 60 | plugin.auxprop_store = NULL; 61 | 62 | *plug = &plugin; 63 | 64 | VLOG(1) << "Initialized in-memory auxiliary property plugin"; 65 | 66 | return SASL_OK; 67 | } 68 | 69 | 70 | #if SASL_AUXPROP_PLUG_VERSION <= 4 71 | void InMemoryAuxiliaryPropertyPlugin::lookup( 72 | #else 73 | int InMemoryAuxiliaryPropertyPlugin::lookup( 74 | #endif 75 | void* context, 76 | sasl_server_params_t* sparams, 77 | unsigned flags, 78 | const char* user, 79 | unsigned length) 80 | { 81 | // Pull out the utils. 82 | const sasl_utils_t* utils = sparams->utils; 83 | 84 | // We determine the properties we should be looking up by doing a 85 | // 'prop_get' on the property context. Note that some of the 86 | // properties we get might need to be skipped depending on the 87 | // flags (see below). 88 | const propval* properties = utils->prop_get(sparams->propctx); 89 | 90 | CHECK(properties != NULL) 91 | << "Invalid auxiliary properties requested for lookup"; 92 | 93 | // TODO(benh): Consider "parsing" 'user' if it has an '@' separating 94 | // the actual user and a realm. 95 | 96 | string realm = sparams->user_realm != NULL 97 | ? sparams->user_realm 98 | : sparams->serverFQDN; 99 | 100 | VLOG(1) 101 | << "Request to lookup properties for " 102 | << "user: '" << user << "' " 103 | << "realm: '" << realm << "' " 104 | << "server FQDN: '" << sparams->serverFQDN << "' " 105 | #ifdef SASL_AUXPROP_VERIFY_AGAINST_HASH 106 | << "SASL_AUXPROP_VERIFY_AGAINST_HASH: " 107 | << (flags & SASL_AUXPROP_VERIFY_AGAINST_HASH ? "true ": "false ") 108 | #endif 109 | << "SASL_AUXPROP_OVERRIDE: " 110 | << (flags & SASL_AUXPROP_OVERRIDE ? "true ": "false ") 111 | << "SASL_AUXPROP_AUTHZID: " 112 | << (flags & SASL_AUXPROP_AUTHZID ? "true ": "false "); 113 | 114 | // Now iterate through each property requested. 115 | const propval* property = properties; 116 | for (; property->name != NULL; property++) { 117 | const char* name = property->name; 118 | 119 | // Skip properties that don't apply to this lookup given the flags. 120 | if (flags & SASL_AUXPROP_AUTHZID) { 121 | if (name[0] == '*') { 122 | VLOG(1) << "Skipping auxiliary property '" << name 123 | << "' since SASL_AUXPROP_AUTHZID == true"; 124 | continue; 125 | } 126 | } else { 127 | // Only consider properties that start with '*' if 128 | // SASL_AUXPROP_AUTHZID is not set but don't include the '*' 129 | // when looking up the property name. 130 | if (name[0] != '*') { 131 | VLOG(1) << "Skipping auxiliary property '" << name 132 | << "' since SASL_AUXPROP_AUTHZID == false " 133 | << "but property name starts with '*'"; 134 | continue; 135 | } else { 136 | name = name + 1; 137 | } 138 | } 139 | 140 | // Don't override already set values unless instructed otherwise. 141 | if (property->values != NULL && !(flags & SASL_AUXPROP_OVERRIDE)) { 142 | #ifdef SASL_AUXPROP_VERIFY_AGAINST_HASH 143 | // Regardless of SASL_AUXPROP_OVERRIDE we're expected to 144 | // override property 'userPassword' when the 145 | // SASL_AUXPROP_VERIFY_AGAINST_HASH flag is set, so we erase it 146 | // here. 147 | if (flags & SASL_AUXPROP_VERIFY_AGAINST_HASH && 148 | string(name) == string(SASL_AUX_PASSWORD_PROP)) { 149 | VLOG(1) << "Erasing auxiliary property '" << name 150 | << "' even though SASL_AUXPROP_OVERRIDE == true " 151 | << "since SASL_AUXPROP_VERIFY_AGAINST_HASH == true"; 152 | utils->prop_erase(sparams->propctx, property->name); 153 | } else { 154 | VLOG(1) << "Skipping auxiliary property '" << name 155 | << "' since SASL_AUXPROP_OVERRIDE == false " 156 | << "and value(s) already set"; 157 | continue; 158 | } 159 | #else 160 | VLOG(1) << "Skipping auxiliary property '" << name 161 | << "' since SASL_AUXPROP_OVERRIDE == false " 162 | << "and value(s) already set"; 163 | continue; 164 | #endif 165 | } else if (property->values != NULL) { 166 | CHECK(flags & SASL_AUXPROP_OVERRIDE); 167 | VLOG(1) << "Erasing auxiliary property '" << name 168 | << "' since SASL_AUXPROP_OVERRIDE == true"; 169 | utils->prop_erase(sparams->propctx, property->name); 170 | } 171 | 172 | VLOG(1) << "Looking up auxiliary property '" << property->name << "'"; 173 | 174 | Option > values = lookup(user, name); 175 | 176 | if (values.isSome()) { 177 | if (values.get().empty()) { 178 | // Add the 'NULL' value to indicate there were no values. 179 | utils->prop_set(sparams->propctx, property->name, NULL, 0); 180 | } else { 181 | // Add all the values. Note that passing NULL as the property 182 | // name for 'prop_set' will append values to the same name as 183 | // the previous 'prop_set' calls which is the behavior we want 184 | // after adding the first value. 185 | bool append = false; 186 | foreach (const string& value, values.get()) { 187 | sparams->utils->prop_set( 188 | sparams->propctx, 189 | append ? NULL : property->name, 190 | value.c_str(), 191 | -1); // Let 'prop_set' use strlen. 192 | append = true; 193 | } 194 | } 195 | } 196 | } 197 | 198 | #if SASL_AUXPROP_PLUG_VERSION > 4 199 | return SASL_OK; 200 | #endif 201 | } 202 | 203 | } // namespace cram_md5 { 204 | } // namespace internal { 205 | } // namespace mesos { 206 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright 2015-present Mesosphere Inc. 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /authentication/kerberos/authenticatee.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2014-present Mesosphere Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | 18 | #include 19 | 20 | #include 21 | 22 | #include 23 | 24 | #include 25 | #include 26 | #include 27 | 28 | #include 29 | #include 30 | #include 31 | 32 | #include "authenticatee.hpp" 33 | 34 | // We need to disable the deprecation warnings as Apple has decided 35 | // to deprecate all of CyrusSASL's functions with OS 10.11 36 | // (see MESOS-3030). We are using GCC pragmas also for covering clang. 37 | #ifdef __APPLE__ 38 | #pragma GCC diagnostic push 39 | #pragma GCC diagnostic ignored "-Wdeprecated-declarations" 40 | #endif 41 | 42 | namespace mesos { 43 | namespace internal { 44 | namespace gssapi { 45 | 46 | using namespace process; 47 | 48 | using std::string; 49 | 50 | class GSSAPIAuthenticateeProcess 51 | : public ProtobufProcess 52 | { 53 | public: 54 | GSSAPIAuthenticateeProcess(const UPID& client_, 55 | const string& principal_, 56 | const string& service_, 57 | const string& serverPrefix_) 58 | : ProcessBase(ID::generate("authenticatee")), 59 | principal(principal_), 60 | service(service_), 61 | serverPrefix(serverPrefix_), 62 | client(client_), 63 | status(READY), 64 | connection(NULL) {} 65 | 66 | virtual ~GSSAPIAuthenticateeProcess() 67 | { 68 | if (connection != NULL) { 69 | sasl_dispose(&connection); 70 | } 71 | } 72 | 73 | virtual void finalize() 74 | { 75 | discarded(); // Fail the promise. 76 | } 77 | 78 | Future authenticate(const UPID& pid) 79 | { 80 | static Once* initialize = new Once(); 81 | static bool initialized = false; 82 | 83 | if (!initialize->once()) { 84 | LOG(INFO) << "Initializing client SASL"; 85 | int result = sasl_client_init(NULL); 86 | if (result != SASL_OK) { 87 | status = ERROR; 88 | string error(sasl_errstring(result, NULL, NULL)); 89 | promise.fail("Failed to initialize SASL: " + error); 90 | initialize->done(); 91 | return promise.future(); 92 | } 93 | 94 | initialized = true; 95 | 96 | initialize->done(); 97 | } 98 | 99 | if (!initialized) { 100 | promise.fail("Failed to initialize SASL"); 101 | return promise.future(); 102 | } 103 | 104 | if (status != READY) { 105 | return promise.future(); 106 | } 107 | 108 | LOG(INFO) << "Creating new client SASL connection"; 109 | 110 | callbacks[0].id = SASL_CB_GETREALM; 111 | callbacks[0].proc = NULL; 112 | callbacks[0].context = NULL; 113 | 114 | callbacks[1].id = SASL_CB_USER; 115 | callbacks[1].proc = (int(*)()) &user; 116 | callbacks[1].context = (void*) principal.c_str(); 117 | 118 | // NOTE: Some SASL mechanisms do not allow/enable "proxying", 119 | // i.e., authorization. Therefore, some mechanisms send _only_ the 120 | // authorization name rather than both the user (authentication 121 | // name) and authorization name. Thus, for now, we assume 122 | // authorization is handled out-of-band. Consider the 123 | // SASL_NEED_PROXY flag if we want to reconsider this in the 124 | // future. 125 | callbacks[2].id = SASL_CB_AUTHNAME; 126 | callbacks[2].proc = (int(*)()) &user; 127 | callbacks[2].context = (void*) principal.c_str(); 128 | 129 | callbacks[3].id = SASL_CB_PASS; 130 | callbacks[3].proc = (int(*)()) &pass; 131 | callbacks[3].context = (void*) NULL; 132 | 133 | callbacks[4].id = SASL_CB_LIST_END; 134 | callbacks[4].proc = NULL; 135 | callbacks[4].context = NULL; 136 | 137 | if (!service.empty()) { 138 | LOG(INFO) << "SASL service name: " << service; 139 | } 140 | const char* service_ = service.empty() ? "mesos" : service.c_str(); 141 | 142 | // Resolve server's hostname from pid ip. 143 | Try hostname = net::getHostname(pid.address.ip); 144 | if (hostname.isError()) { 145 | status = ERROR; 146 | promise.fail("Failed to resolve hostname: " + hostname.error()); 147 | return promise.future(); 148 | } 149 | string server = hostname.get(); 150 | 151 | if (!serverPrefix.empty()) { 152 | server = serverPrefix + server; 153 | } 154 | LOG(INFO) << "SASL connecting to server: " << server; 155 | const char* server_ = server.c_str(); 156 | 157 | int result = sasl_client_new( 158 | service_, // Registered name of service. 159 | server_, // Server's FQDN. 160 | NULL, NULL, // IP Address information strings. 161 | callbacks, // Callbacks supported only for this connection. 162 | 0, // Security flags (security layers are enabled 163 | // using security properties, separately). 164 | &connection); 165 | 166 | if (result != SASL_OK) { 167 | status = ERROR; 168 | string error(sasl_errstring(result, NULL, NULL)); 169 | promise.fail("Failed to create client SASL connection: " + error); 170 | return promise.future(); 171 | } 172 | 173 | AuthenticateMessage message; 174 | message.set_pid(client); 175 | send(pid, message); 176 | 177 | status = STARTING; 178 | 179 | // Stop authenticating if nobody cares. 180 | promise.future().onDiscard(defer(self(), &Self::discarded)); 181 | 182 | return promise.future(); 183 | } 184 | 185 | protected: 186 | virtual void initialize() 187 | { 188 | // Anticipate mechanisms and steps from the server. 189 | install( 190 | &GSSAPIAuthenticateeProcess::mechanisms, 191 | &AuthenticationMechanismsMessage::mechanisms); 192 | 193 | install( 194 | &GSSAPIAuthenticateeProcess::step, 195 | &AuthenticationStepMessage::data); 196 | 197 | install( 198 | &GSSAPIAuthenticateeProcess::completed); 199 | 200 | install( 201 | &GSSAPIAuthenticateeProcess::failed); 202 | 203 | install( 204 | &GSSAPIAuthenticateeProcess::error, 205 | &AuthenticationErrorMessage::error); 206 | } 207 | 208 | void mechanisms(const std::vector& mechanisms) 209 | { 210 | if (status != STARTING) { 211 | status = ERROR; 212 | promise.fail("Unexpected authentication 'mechanisms' received"); 213 | return; 214 | } 215 | 216 | // TODO(benh): Store 'from' in order to ensure we only communicate 217 | // with the same Authenticator. 218 | 219 | LOG(INFO) << "Received SASL authentication mechanisms: " 220 | << strings::join(",", mechanisms); 221 | 222 | sasl_interact_t* interact = NULL; 223 | const char* output = NULL; 224 | unsigned length = 0; 225 | const char* mechanism = NULL; 226 | 227 | int result = sasl_client_start( 228 | connection, 229 | strings::join(" ", mechanisms).c_str(), 230 | &interact, // Set if an interaction is needed. 231 | &output, // The output string (to send to server). 232 | &length, // The length of the output string. 233 | &mechanism); // The chosen mechanism. 234 | 235 | CHECK_NE(SASL_INTERACT, result) 236 | << "Not expecting an interaction (ID: " << interact->id << ")"; 237 | 238 | if (result != SASL_OK && result != SASL_CONTINUE) { 239 | string error(sasl_errdetail(connection)); 240 | status = ERROR; 241 | promise.fail("Failed to start the SASL client: " + error); 242 | return; 243 | } 244 | 245 | LOG(INFO) << "Attempting to authenticate with mechanism '" 246 | << mechanism << "'"; 247 | 248 | AuthenticationStartMessage message; 249 | message.set_mechanism(mechanism); 250 | message.set_data(output, length); 251 | 252 | reply(message); 253 | 254 | status = STEPPING; 255 | } 256 | 257 | void step(const string& data) 258 | { 259 | if (status != STEPPING) { 260 | status = ERROR; 261 | promise.fail("Unexpected authentication 'step' received"); 262 | return; 263 | } 264 | 265 | LOG(INFO) << "Received SASL authentication step"; 266 | 267 | sasl_interact_t* interact = NULL; 268 | const char* output = NULL; 269 | unsigned length = 0; 270 | 271 | int result = sasl_client_step( 272 | connection, 273 | data.length() == 0 ? NULL : data.data(), 274 | data.length(), 275 | &interact, 276 | &output, 277 | &length); 278 | 279 | CHECK_NE(SASL_INTERACT, result) 280 | << "Not expecting an interaction (ID: " << interact->id << ")"; 281 | 282 | if (result == SASL_OK || result == SASL_CONTINUE) { 283 | // We don't start the client with SASL_SUCCESS_DATA so we may 284 | // need to send one more "empty" message to the server. 285 | AuthenticationStepMessage message; 286 | if (output != NULL && length > 0) { 287 | message.set_data(output, length); 288 | } else { 289 | message.set_data(NULL, 0); 290 | } 291 | reply(message); 292 | } else { 293 | status = ERROR; 294 | string error(sasl_errdetail(connection)); 295 | promise.fail("Failed to perform authentication step: " + error); 296 | } 297 | } 298 | 299 | void completed() 300 | { 301 | if (status != STEPPING) { 302 | status = ERROR; 303 | promise.fail("Unexpected authentication 'completed' received"); 304 | return; 305 | } 306 | 307 | LOG(INFO) << "Authentication success"; 308 | 309 | status = COMPLETED; 310 | promise.set(true); 311 | } 312 | 313 | void failed() 314 | { 315 | status = FAILED; 316 | promise.set(false); 317 | } 318 | 319 | void error(const string& error) 320 | { 321 | status = ERROR; 322 | promise.fail("Authentication error: " + error); 323 | } 324 | 325 | void discarded() 326 | { 327 | status = DISCARDED; 328 | promise.fail("Authentication discarded"); 329 | } 330 | 331 | private: 332 | static int user( 333 | void* context, 334 | int id, 335 | const char** result, 336 | unsigned* length) 337 | { 338 | CHECK(SASL_CB_USER == id || SASL_CB_AUTHNAME == id); 339 | *result = static_cast(context); 340 | if (length != NULL) { 341 | *length = strlen(*result); 342 | } 343 | return SASL_OK; 344 | } 345 | 346 | static int pass( 347 | sasl_conn_t* connection, 348 | void* context, 349 | int id, 350 | sasl_secret_t** secret) 351 | { 352 | CHECK_EQ(SASL_CB_PASS, id); 353 | if (context == NULL) { 354 | return SASL_BADAUTH; 355 | } 356 | *secret = static_cast(context); 357 | return SASL_OK; 358 | } 359 | 360 | const string principal; 361 | const string service; 362 | const string serverPrefix; 363 | 364 | // PID of the client that needs to be authenticated. 365 | const UPID client; 366 | 367 | sasl_callback_t callbacks[5]; 368 | 369 | enum { 370 | READY, 371 | STARTING, 372 | STEPPING, 373 | COMPLETED, 374 | FAILED, 375 | ERROR, 376 | DISCARDED 377 | } status; 378 | 379 | sasl_conn_t* connection; 380 | 381 | Promise promise; 382 | }; 383 | 384 | 385 | GSSAPIAuthenticatee::GSSAPIAuthenticatee() : process(NULL) {} 386 | 387 | 388 | GSSAPIAuthenticatee::~GSSAPIAuthenticatee() 389 | { 390 | if (process != NULL) { 391 | terminate(process); 392 | wait(process); 393 | delete process; 394 | } 395 | } 396 | 397 | 398 | void GSSAPIAuthenticatee::prepare(const string& service_, 399 | const string& serverPrefix_) 400 | { 401 | service = service_; 402 | serverPrefix = serverPrefix_; 403 | } 404 | 405 | 406 | Future GSSAPIAuthenticatee::authenticate( 407 | const UPID& pid, 408 | const UPID& client, 409 | const mesos::Credential& credential) 410 | { 411 | CHECK(process == NULL); 412 | 413 | CHECK(credential.has_principal()); 414 | 415 | process = new GSSAPIAuthenticateeProcess( 416 | client, credential.principal(), service, serverPrefix); 417 | spawn(process); 418 | 419 | return dispatch( 420 | process, &GSSAPIAuthenticateeProcess::authenticate, pid); 421 | } 422 | 423 | } // namespace gssapi { 424 | } // namespace internal { 425 | } // namespace mesos { 426 | 427 | #ifdef __APPLE__ 428 | #pragma GCC diagnostic pop 429 | #endif 430 | -------------------------------------------------------------------------------- /authentication/kerberos/authenticator.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2014-present Mesosphere Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | 18 | #include // For size_t needed by sasl.h. 19 | 20 | #include 21 | #include 22 | 23 | #include 24 | #include 25 | 26 | #include 27 | 28 | #include 29 | 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | 37 | #include 38 | #include 39 | 40 | #include "authenticator.hpp" 41 | 42 | // We need to disable the deprecation warnings as Apple has decided 43 | // to deprecate all of CyrusSASL's functions with OS 10.11 44 | // (see MESOS-3030). We are using GCC pragmas also for covering clang. 45 | #ifdef __APPLE__ 46 | #pragma GCC diagnostic push 47 | #pragma GCC diagnostic ignored "-Wdeprecated-declarations" 48 | #endif 49 | 50 | namespace mesos { 51 | namespace internal { 52 | namespace gssapi { 53 | 54 | using namespace process; 55 | 56 | using std::string; 57 | 58 | class GSSAPIAuthenticatorSessionProcess 59 | : public ProtobufProcess 60 | { 61 | public: 62 | explicit GSSAPIAuthenticatorSessionProcess( 63 | const UPID& pid_, 64 | const string& service_, 65 | const string& serverPrefix_, 66 | const string& realm_) 67 | : ProcessBase(ID::generate("gssapi_authenticator_session")), 68 | status(READY), 69 | pid(pid_), 70 | service(service_), 71 | serverPrefix(serverPrefix_), 72 | realm(realm_), 73 | connection(NULL) {} 74 | 75 | virtual ~GSSAPIAuthenticatorSessionProcess() 76 | { 77 | if (connection != NULL) { 78 | sasl_dispose(&connection); 79 | } 80 | } 81 | 82 | virtual void finalize() 83 | { 84 | discarded(); // Fail the promise. 85 | } 86 | 87 | Future> authenticate() 88 | { 89 | if (status != READY) { 90 | return promise.future(); 91 | } 92 | 93 | // 'service', 'serverPrefix' as well as 'realm' may be supplied 94 | // as overrides. 95 | if (!service.empty()) { 96 | LOG(INFO) << "SASL service name: " << service; 97 | } 98 | const char* service_ = service.empty() ? "mesos" : service.c_str(); 99 | 100 | string server = ""; 101 | if (!serverPrefix.empty()) { 102 | Try hostname = net::hostname(); 103 | if (hostname.isError()) { 104 | status = ERROR; 105 | promise.fail("Failed to resolve hostname: " + hostname.error()); 106 | return promise.future(); 107 | } 108 | server = serverPrefix + hostname.get(); 109 | LOG(INFO) << "SASL connecting to server: " << server; 110 | } 111 | const char* server_ = server.empty() ? NULL : server.c_str(); 112 | 113 | LOG(INFO) << "SASL using realm: " << realm; 114 | const char* realm_ = realm.empty() ? NULL : realm.c_str(); 115 | 116 | LOG(INFO) << "Creating new server SASL connection"; 117 | 118 | int result = sasl_server_new( 119 | service_, // Registered name of service. 120 | server_, // Server's FQDN; NULL uses gethostname(). 121 | realm_, // The user realm used for password lookups; 122 | // NULL means default to FQDN. 123 | NULL, NULL, // IP address information strings. 124 | NULL, // Callbacks supported only for this connection. 125 | 0, // Security flags (security layers are enabled 126 | // using security properties, separately). 127 | &connection); 128 | 129 | if (result != SASL_OK) { 130 | string error = "Failed to create server SASL connection: "; 131 | error += sasl_errstring(result, NULL, NULL); 132 | LOG(ERROR) << error; 133 | AuthenticationErrorMessage message; 134 | message.set_error(error); 135 | send(pid, message); 136 | status = ERROR; 137 | promise.fail(error); 138 | return promise.future(); 139 | } 140 | 141 | // Get the list of mechanisms. 142 | const char* output = NULL; 143 | unsigned length = 0; 144 | int count = 0; 145 | 146 | result = sasl_listmech( 147 | connection, // The context for this connection. 148 | NULL, // Not supported. 149 | "", // What to prepend to the output string. 150 | ",", // What to separate mechanisms with. 151 | "", // What to append to the output string. 152 | &output, // The output string. 153 | &length, // The length of the output string. 154 | &count); // The count of the mechanisms in output. 155 | 156 | if (result != SASL_OK || output == NULL) { 157 | string error = "Failed to get list of mechanisms: "; 158 | LOG(WARNING) << error << sasl_errstring(result, NULL, NULL); 159 | AuthenticationErrorMessage message; 160 | error += sasl_errdetail(connection); 161 | message.set_error(error); 162 | send(pid, message); 163 | status = ERROR; 164 | promise.fail(error); 165 | return promise.future(); 166 | } 167 | 168 | std::vector mechanisms = strings::tokenize(output, ","); 169 | LOG(INFO) << "Available mechanisms: " << output; 170 | 171 | // Send authentication mechanisms. 172 | AuthenticationMechanismsMessage message; 173 | foreach (const string& mechanism, mechanisms) { 174 | message.add_mechanisms(mechanism); 175 | } 176 | 177 | send(pid, message); 178 | 179 | status = STARTING; 180 | 181 | // Stop authenticating if nobody cares. 182 | promise.future().onDiscard(defer(self(), &Self::discarded)); 183 | 184 | return promise.future(); 185 | } 186 | 187 | protected: 188 | virtual void initialize() 189 | { 190 | link(pid); // Don't bother waiting for a lost authenticatee. 191 | 192 | // Anticipate start and steps messages from the client. 193 | install( 194 | &GSSAPIAuthenticatorSessionProcess::start, 195 | &AuthenticationStartMessage::mechanism, 196 | &AuthenticationStartMessage::data); 197 | 198 | install( 199 | &GSSAPIAuthenticatorSessionProcess::step, 200 | &AuthenticationStepMessage::data); 201 | } 202 | 203 | virtual void exited(const UPID& _pid) 204 | { 205 | if (pid == _pid) { 206 | status = ERROR; 207 | promise.fail("Failed to communicate with authenticatee"); 208 | } 209 | } 210 | 211 | void start(const string& mechanism, const string& data) 212 | { 213 | if (status != STARTING) { 214 | AuthenticationErrorMessage message; 215 | message.set_error("Unexpected authentication 'start' received"); 216 | send(pid, message); 217 | status = ERROR; 218 | promise.fail(message.error()); 219 | return; 220 | } 221 | 222 | LOG(INFO) << "Received SASL authentication start with " 223 | << mechanism.c_str() << " mechanism"; 224 | 225 | // Start the server. 226 | const char* output = NULL; 227 | unsigned length = 0; 228 | 229 | int result = sasl_server_start( 230 | connection, 231 | mechanism.c_str(), 232 | data.length() == 0 ? NULL : data.data(), 233 | data.length(), 234 | &output, 235 | &length); 236 | 237 | handle(result, output, length); 238 | } 239 | 240 | void step(const string& data) 241 | { 242 | if (status != STEPPING) { 243 | AuthenticationErrorMessage message; 244 | message.set_error("Unexpected authentication 'step' received"); 245 | send(pid, message); 246 | status = ERROR; 247 | promise.fail(message.error()); 248 | return; 249 | } 250 | 251 | LOG(INFO) << "Received SASL authentication step"; 252 | 253 | const char* output = NULL; 254 | unsigned length = 0; 255 | 256 | int result = sasl_server_step( 257 | connection, 258 | data.length() == 0 ? NULL : data.data(), 259 | data.length(), 260 | &output, 261 | &length); 262 | 263 | handle(result, output, length); 264 | } 265 | 266 | void discarded() 267 | { 268 | status = DISCARDED; 269 | promise.fail("Authentication discarded"); 270 | } 271 | 272 | private: 273 | // Helper for handling result of server start and step. 274 | void handle(int result, const char* output, unsigned length) 275 | { 276 | if (result == SASL_OK) { 277 | char *name; 278 | 279 | result = sasl_getprop(connection, SASL_USERNAME, (const void **)&name); 280 | 281 | if (result != SASL_OK) { 282 | LOG(ERROR) << "Failed to retrieve principal after successful " 283 | << "authentication: " << sasl_errstring(result, NULL, NULL); 284 | AuthenticationErrorMessage message; 285 | std::string error(sasl_errdetail(connection)); 286 | message.set_error(error); 287 | send(pid, message); 288 | status = ERROR; 289 | promise.fail(error); 290 | return; 291 | } else { 292 | principal = name; 293 | } 294 | 295 | LOG(INFO) << "Authentication success"; 296 | // Note that we're not using SASL_SUCCESS_DATA which means that 297 | // we should not have any data to send when we get a SASL_OK. 298 | CHECK(output == NULL); 299 | send(pid, AuthenticationCompletedMessage()); 300 | status = COMPLETED; 301 | promise.set(principal); 302 | } else if (result == SASL_CONTINUE) { 303 | LOG(INFO) << "Authentication requires more steps"; 304 | AuthenticationStepMessage message; 305 | message.set_data(CHECK_NOTNULL(output), length); 306 | send(pid, message); 307 | status = STEPPING; 308 | } else if (result == SASL_NOUSER || result == SASL_BADAUTH) { 309 | LOG(WARNING) << "Authentication failure: " 310 | << sasl_errstring(result, NULL, NULL); 311 | send(pid, AuthenticationFailedMessage()); 312 | status = FAILED; 313 | promise.set(Option::none()); 314 | } else { 315 | LOG(ERROR) << "Authentication error: " 316 | << sasl_errstring(result, NULL, NULL); 317 | AuthenticationErrorMessage message; 318 | string error(sasl_errdetail(connection)); 319 | message.set_error(error); 320 | send(pid, message); 321 | status = ERROR; 322 | promise.fail(message.error()); 323 | } 324 | } 325 | 326 | enum { 327 | READY, 328 | STARTING, 329 | STEPPING, 330 | COMPLETED, 331 | FAILED, 332 | ERROR, 333 | DISCARDED 334 | } status; 335 | 336 | const UPID pid; 337 | 338 | const string service; 339 | const string serverPrefix; 340 | const string realm; 341 | 342 | sasl_conn_t* connection; 343 | 344 | Promise> promise; 345 | 346 | Option principal; 347 | }; 348 | 349 | 350 | class GSSAPIAuthenticatorSession 351 | { 352 | public: 353 | GSSAPIAuthenticatorSession(const UPID& pid, 354 | const string& service, 355 | const string& serverPrefix, 356 | const string& realm) 357 | { 358 | process = 359 | new GSSAPIAuthenticatorSessionProcess(pid, service, serverPrefix, realm); 360 | spawn(process); 361 | } 362 | 363 | virtual ~GSSAPIAuthenticatorSession() 364 | { 365 | // TODO(vinod): As a short term fix for the race condition #1 in 366 | // MESOS-1866, we inject the 'terminate' event at the end of the 367 | // CRAMMD5AuthenticatorProcess queue instead of at the front. 368 | // The long term fix for this is https://reviews.apache.org/r/25945/. 369 | terminate(process, false); 370 | wait(process); 371 | delete process; 372 | } 373 | 374 | virtual Future> authenticate() 375 | { 376 | return dispatch(process, &GSSAPIAuthenticatorSessionProcess::authenticate); 377 | } 378 | 379 | private: 380 | GSSAPIAuthenticatorSessionProcess* process; 381 | }; 382 | 383 | 384 | class GSSAPIAuthenticatorProcess : 385 | public Process 386 | { 387 | public: 388 | GSSAPIAuthenticatorProcess() : 389 | ProcessBase(ID::generate("gssapi_authenticator")) {} 390 | 391 | virtual ~GSSAPIAuthenticatorProcess() {} 392 | 393 | Future> authenticate(const UPID& pid, 394 | const string& service, 395 | const string& serverPrefix, 396 | const string& realm) 397 | { 398 | VLOG(1) << "Starting authentication session for " << pid; 399 | 400 | if (sessions.contains(pid)) { 401 | return Failure("Authentication session already active for " + 402 | string(pid)); 403 | } 404 | 405 | Owned session( 406 | new GSSAPIAuthenticatorSession(pid, service, serverPrefix, realm)); 407 | 408 | sessions.put(pid, session); 409 | 410 | return session->authenticate() 411 | .onAny(defer(self(), &Self::_authenticate, pid)); 412 | } 413 | 414 | virtual void _authenticate(const UPID& pid) 415 | { 416 | VLOG(1) << "Authentication session cleanup for " << pid; 417 | 418 | CHECK(sessions.contains(pid)); 419 | 420 | sessions.erase(pid); 421 | } 422 | 423 | private: 424 | hashmap > sessions; 425 | }; 426 | 427 | 428 | GSSAPIAuthenticator::GSSAPIAuthenticator() : process(NULL) {} 429 | 430 | 431 | GSSAPIAuthenticator::~GSSAPIAuthenticator() 432 | { 433 | if (process != NULL) { 434 | terminate(process); 435 | wait(process); 436 | delete process; 437 | } 438 | } 439 | 440 | 441 | Try GSSAPIAuthenticator::initialize( 442 | const Option& credentials) 443 | { 444 | static Once* initialize = new Once(); 445 | static Option* error = new Option(); 446 | 447 | if (process != NULL) { 448 | return Error("Authenticator initialized already"); 449 | } 450 | 451 | // Thechnically, this guard is not needed as sasl_server_init itself 452 | // makes sure it only gets initialized once. 453 | if (!initialize->once()) { 454 | LOG(INFO) << "Initializing server SASL"; 455 | 456 | int result = sasl_server_init(NULL, "mesos"); 457 | 458 | if (result != SASL_OK) { 459 | *error = Error( 460 | string("Failed to initialize SASL: ") + 461 | sasl_errstring(result, NULL, NULL)); 462 | } 463 | 464 | initialize->done(); 465 | } 466 | 467 | if (error->isSome()) { 468 | return error->get(); 469 | } 470 | 471 | process = new GSSAPIAuthenticatorProcess(); 472 | spawn(process); 473 | 474 | return Nothing(); 475 | } 476 | 477 | 478 | void GSSAPIAuthenticator::prepare(const string& service_, 479 | const string& serverPrefix_, 480 | const string& realm_) 481 | { 482 | service = service_; 483 | serverPrefix = serverPrefix_; 484 | realm = realm_; 485 | } 486 | 487 | 488 | Future> GSSAPIAuthenticator::authenticate( 489 | const UPID& pid) 490 | { 491 | if (process == NULL) { 492 | return Failure("Authenticator not initialized"); 493 | } 494 | return dispatch( 495 | process, 496 | &GSSAPIAuthenticatorProcess::authenticate, 497 | pid, 498 | service, 499 | serverPrefix, 500 | realm); 501 | } 502 | 503 | } // namespace gssapi { 504 | } // namespace internal { 505 | } // namespace mesos { 506 | 507 | #ifdef __APPLE__ 508 | #pragma GCC diagnostic pop 509 | #endif 510 | -------------------------------------------------------------------------------- /m4/ax_cxx_compile_stdcxx.m4: -------------------------------------------------------------------------------- 1 | # =========================================================================== 2 | # http://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx.html 3 | # =========================================================================== 4 | # 5 | # SYNOPSIS 6 | # 7 | # AX_CXX_COMPILE_STDCXX(VERSION, [ext|noext], [mandatory|optional]) 8 | # 9 | # DESCRIPTION 10 | # 11 | # Check for baseline language coverage in the compiler for the specified 12 | # version of the C++ standard. If necessary, add switches to CXX to 13 | # enable support. VERSION may be '11' (for the C++11 standard) or '14' 14 | # (for the C++14 standard). 15 | # 16 | # The second argument, if specified, indicates whether you insist on an 17 | # extended mode (e.g. -std=gnu++11) or a strict conformance mode (e.g. 18 | # -std=c++11). If neither is specified, you get whatever works, with 19 | # preference for an extended mode. 20 | # 21 | # The third argument, if specified 'mandatory' or if left unspecified, 22 | # indicates that baseline support for the specified C++ standard is 23 | # required and that the macro should error out if no mode with that 24 | # support is found. If specified 'optional', then configuration proceeds 25 | # regardless, after defining HAVE_CXX${VERSION} if and only if a 26 | # supporting mode is found. 27 | # 28 | # LICENSE 29 | # 30 | # Copyright (c) 2008 Benjamin Kosnik 31 | # Copyright (c) 2012 Zack Weinberg 32 | # Copyright (c) 2013 Roy Stogner 33 | # Copyright (c) 2014, 2015 Google Inc.; contributed by Alexey Sokolov 34 | # Copyright (c) 2015 Paul Norman 35 | # Copyright (c) 2015 Moritz Klammler 36 | # 37 | # Copying and distribution of this file, with or without modification, are 38 | # permitted in any medium without royalty provided the copyright notice 39 | # and this notice are preserved. This file is offered as-is, without any 40 | # warranty. 41 | 42 | #serial 3 43 | 44 | dnl This macro is based on the code from the AX_CXX_COMPILE_STDCXX_11 macro 45 | dnl (serial version number 13). 46 | 47 | AC_DEFUN([AX_CXX_COMPILE_STDCXX], [dnl 48 | m4_if([$1], [11], [], 49 | [$1], [14], [], 50 | [$1], [17], [m4_fatal([support for C++17 not yet implemented in AX_CXX_COMPILE_STDCXX])], 51 | [m4_fatal([invalid first argument `$1' to AX_CXX_COMPILE_STDCXX])])dnl 52 | m4_if([$2], [], [], 53 | [$2], [ext], [], 54 | [$2], [noext], [], 55 | [m4_fatal([invalid second argument `$2' to AX_CXX_COMPILE_STDCXX])])dnl 56 | m4_if([$3], [], [ax_cxx_compile_cxx$1_required=true], 57 | [$3], [mandatory], [ax_cxx_compile_cxx$1_required=true], 58 | [$3], [optional], [ax_cxx_compile_cxx$1_required=false], 59 | [m4_fatal([invalid third argument `$3' to AX_CXX_COMPILE_STDCXX])]) 60 | AC_LANG_PUSH([C++])dnl 61 | ac_success=no 62 | AC_CACHE_CHECK(whether $CXX supports C++$1 features by default, 63 | ax_cv_cxx_compile_cxx$1, 64 | [AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])], 65 | [ax_cv_cxx_compile_cxx$1=yes], 66 | [ax_cv_cxx_compile_cxx$1=no])]) 67 | if test x$ax_cv_cxx_compile_cxx$1 = xyes; then 68 | ac_success=yes 69 | fi 70 | 71 | m4_if([$2], [noext], [], [dnl 72 | if test x$ac_success = xno; then 73 | for switch in -std=gnu++$1 -std=gnu++0x; do 74 | cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch]) 75 | AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch, 76 | $cachevar, 77 | [ac_save_CXXFLAGS="$CXXFLAGS" 78 | CXXFLAGS="$CXXFLAGS $switch" 79 | AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])], 80 | [eval $cachevar=yes], 81 | [eval $cachevar=no]) 82 | CXXFLAGS="$ac_save_CXXFLAGS"]) 83 | if eval test x\$$cachevar = xyes; then 84 | CXXFLAGS="$CXXFLAGS $switch" 85 | ac_success=yes 86 | break 87 | fi 88 | done 89 | fi]) 90 | 91 | m4_if([$2], [ext], [], [dnl 92 | dnl Note that in "noext" mode, we still want to specify a "-std" flag 93 | dnl if the compiler accepts it (even if the compiler supports the 94 | dnl desired C++ dialect without any flags), because the default compiler 95 | dnl dialect might include support for extensions. 96 | dnl HP's aCC needs +std=c++11 according to: 97 | dnl http://h21007.www2.hp.com/portal/download/files/unprot/aCxx/PDF_Release_Notes/769149-001.pdf 98 | dnl Cray's crayCC needs "-h std=c++11" 99 | for switch in -std=c++$1 -std=c++0x +std=c++$1 "-h std=c++$1"; do 100 | cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch]) 101 | AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch, 102 | $cachevar, 103 | [ac_save_CXXFLAGS="$CXXFLAGS" 104 | CXXFLAGS="$CXXFLAGS $switch" 105 | AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])], 106 | [eval $cachevar=yes], 107 | [eval $cachevar=no]) 108 | CXXFLAGS="$ac_save_CXXFLAGS"]) 109 | if eval test x\$$cachevar = xyes; then 110 | CXXFLAGS="$CXXFLAGS $switch" 111 | ac_success=yes 112 | break 113 | fi 114 | done 115 | ]) 116 | 117 | AC_LANG_POP([C++]) 118 | if test x$ax_cxx_compile_cxx$1_required = xtrue; then 119 | if test x$ac_success = xno; then 120 | AC_MSG_ERROR([*** A compiler with support for C++$1 language features is required.]) 121 | fi 122 | fi 123 | if test x$ac_success = xno; then 124 | HAVE_CXX$1=0 125 | AC_MSG_NOTICE([No compiler with C++$1 support was found]) 126 | else 127 | HAVE_CXX$1=1 128 | AC_DEFINE(HAVE_CXX$1,1, 129 | [define if the compiler supports basic C++$1 syntax]) 130 | fi 131 | AC_SUBST(HAVE_CXX$1) 132 | ]) 133 | 134 | 135 | dnl Test body for checking C++11 support 136 | 137 | m4_define([_AX_CXX_COMPILE_STDCXX_testbody_11], 138 | _AX_CXX_COMPILE_STDCXX_testbody_new_in_11 139 | ) 140 | 141 | 142 | dnl Test body for checking C++14 support 143 | 144 | m4_define([_AX_CXX_COMPILE_STDCXX_testbody_14], 145 | _AX_CXX_COMPILE_STDCXX_testbody_new_in_11 146 | _AX_CXX_COMPILE_STDCXX_testbody_new_in_14 147 | ) 148 | 149 | 150 | dnl Tests for new features in C++11 151 | 152 | m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_11], [[ 153 | 154 | // If the compiler admits that it is not ready for C++11, why torture it? 155 | // Hopefully, this will speed up the test. 156 | 157 | #ifndef __cplusplus 158 | 159 | #error "This is not a C++ compiler" 160 | 161 | #elif __cplusplus < 201103L 162 | 163 | #error "This is not a C++11 compiler" 164 | 165 | #else 166 | 167 | namespace cxx11 168 | { 169 | 170 | namespace test_static_assert 171 | { 172 | 173 | template 174 | struct check 175 | { 176 | static_assert(sizeof(int) <= sizeof(T), "not big enough"); 177 | }; 178 | 179 | } 180 | 181 | namespace test_final_override 182 | { 183 | 184 | struct Base 185 | { 186 | virtual void f() {} 187 | }; 188 | 189 | struct Derived : public Base 190 | { 191 | virtual void f() override {} 192 | }; 193 | 194 | } 195 | 196 | namespace test_double_right_angle_brackets 197 | { 198 | 199 | template < typename T > 200 | struct check {}; 201 | 202 | typedef check single_type; 203 | typedef check> double_type; 204 | typedef check>> triple_type; 205 | typedef check>>> quadruple_type; 206 | 207 | } 208 | 209 | namespace test_decltype 210 | { 211 | 212 | int 213 | f() 214 | { 215 | int a = 1; 216 | decltype(a) b = 2; 217 | return a + b; 218 | } 219 | 220 | } 221 | 222 | namespace test_type_deduction 223 | { 224 | 225 | template < typename T1, typename T2 > 226 | struct is_same 227 | { 228 | static const bool value = false; 229 | }; 230 | 231 | template < typename T > 232 | struct is_same 233 | { 234 | static const bool value = true; 235 | }; 236 | 237 | template < typename T1, typename T2 > 238 | auto 239 | add(T1 a1, T2 a2) -> decltype(a1 + a2) 240 | { 241 | return a1 + a2; 242 | } 243 | 244 | int 245 | test(const int c, volatile int v) 246 | { 247 | static_assert(is_same::value == true, ""); 248 | static_assert(is_same::value == false, ""); 249 | static_assert(is_same::value == false, ""); 250 | auto ac = c; 251 | auto av = v; 252 | auto sumi = ac + av + 'x'; 253 | auto sumf = ac + av + 1.0; 254 | static_assert(is_same::value == true, ""); 255 | static_assert(is_same::value == true, ""); 256 | static_assert(is_same::value == true, ""); 257 | static_assert(is_same::value == false, ""); 258 | static_assert(is_same::value == true, ""); 259 | return (sumf > 0.0) ? sumi : add(c, v); 260 | } 261 | 262 | } 263 | 264 | namespace test_noexcept 265 | { 266 | 267 | int f() { return 0; } 268 | int g() noexcept { return 0; } 269 | 270 | static_assert(noexcept(f()) == false, ""); 271 | static_assert(noexcept(g()) == true, ""); 272 | 273 | } 274 | 275 | namespace test_constexpr 276 | { 277 | 278 | template < typename CharT > 279 | unsigned long constexpr 280 | strlen_c_r(const CharT *const s, const unsigned long acc) noexcept 281 | { 282 | return *s ? strlen_c_r(s + 1, acc + 1) : acc; 283 | } 284 | 285 | template < typename CharT > 286 | unsigned long constexpr 287 | strlen_c(const CharT *const s) noexcept 288 | { 289 | return strlen_c_r(s, 0UL); 290 | } 291 | 292 | static_assert(strlen_c("") == 0UL, ""); 293 | static_assert(strlen_c("1") == 1UL, ""); 294 | static_assert(strlen_c("example") == 7UL, ""); 295 | static_assert(strlen_c("another\0example") == 7UL, ""); 296 | 297 | } 298 | 299 | namespace test_rvalue_references 300 | { 301 | 302 | template < int N > 303 | struct answer 304 | { 305 | static constexpr int value = N; 306 | }; 307 | 308 | answer<1> f(int&) { return answer<1>(); } 309 | answer<2> f(const int&) { return answer<2>(); } 310 | answer<3> f(int&&) { return answer<3>(); } 311 | 312 | void 313 | test() 314 | { 315 | int i = 0; 316 | const int c = 0; 317 | static_assert(decltype(f(i))::value == 1, ""); 318 | static_assert(decltype(f(c))::value == 2, ""); 319 | static_assert(decltype(f(0))::value == 3, ""); 320 | } 321 | 322 | } 323 | 324 | namespace test_uniform_initialization 325 | { 326 | 327 | struct test 328 | { 329 | static const int zero {}; 330 | static const int one {1}; 331 | }; 332 | 333 | static_assert(test::zero == 0, ""); 334 | static_assert(test::one == 1, ""); 335 | 336 | } 337 | 338 | namespace test_lambdas 339 | { 340 | 341 | void 342 | test1() 343 | { 344 | auto lambda1 = [](){}; 345 | auto lambda2 = lambda1; 346 | lambda1(); 347 | lambda2(); 348 | } 349 | 350 | int 351 | test2() 352 | { 353 | auto a = [](int i, int j){ return i + j; }(1, 2); 354 | auto b = []() -> int { return '0'; }(); 355 | auto c = [=](){ return a + b; }(); 356 | auto d = [&](){ return c; }(); 357 | auto e = [a, &b](int x) mutable { 358 | const auto identity = [](int y){ return y; }; 359 | for (auto i = 0; i < a; ++i) 360 | a += b--; 361 | return x + identity(a + b); 362 | }(0); 363 | return a + b + c + d + e; 364 | } 365 | 366 | int 367 | test3() 368 | { 369 | const auto nullary = [](){ return 0; }; 370 | const auto unary = [](int x){ return x; }; 371 | using nullary_t = decltype(nullary); 372 | using unary_t = decltype(unary); 373 | const auto higher1st = [](nullary_t f){ return f(); }; 374 | const auto higher2nd = [unary](nullary_t f1){ 375 | return [unary, f1](unary_t f2){ return f2(unary(f1())); }; 376 | }; 377 | return higher1st(nullary) + higher2nd(nullary)(unary); 378 | } 379 | 380 | } 381 | 382 | namespace test_variadic_templates 383 | { 384 | 385 | template 386 | struct sum; 387 | 388 | template 389 | struct sum 390 | { 391 | static constexpr auto value = N0 + sum::value; 392 | }; 393 | 394 | template <> 395 | struct sum<> 396 | { 397 | static constexpr auto value = 0; 398 | }; 399 | 400 | static_assert(sum<>::value == 0, ""); 401 | static_assert(sum<1>::value == 1, ""); 402 | static_assert(sum<23>::value == 23, ""); 403 | static_assert(sum<1, 2>::value == 3, ""); 404 | static_assert(sum<5, 5, 11>::value == 21, ""); 405 | static_assert(sum<2, 3, 5, 7, 11, 13>::value == 41, ""); 406 | 407 | } 408 | 409 | // http://stackoverflow.com/questions/13728184/template-aliases-and-sfinae 410 | // Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function 411 | // because of this. 412 | namespace test_template_alias_sfinae 413 | { 414 | 415 | struct foo {}; 416 | 417 | template 418 | using member = typename T::member_type; 419 | 420 | template 421 | void func(...) {} 422 | 423 | template 424 | void func(member*) {} 425 | 426 | void test(); 427 | 428 | void test() { func(0); } 429 | 430 | } 431 | 432 | } // namespace cxx11 433 | 434 | #endif // __cplusplus >= 201103L 435 | 436 | ]]) 437 | 438 | 439 | dnl Tests for new features in C++14 440 | 441 | m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_14], [[ 442 | 443 | // If the compiler admits that it is not ready for C++14, why torture it? 444 | // Hopefully, this will speed up the test. 445 | 446 | #ifndef __cplusplus 447 | 448 | #error "This is not a C++ compiler" 449 | 450 | #elif __cplusplus < 201402L 451 | 452 | #error "This is not a C++14 compiler" 453 | 454 | #else 455 | 456 | namespace cxx14 457 | { 458 | 459 | namespace test_polymorphic_lambdas 460 | { 461 | 462 | int 463 | test() 464 | { 465 | const auto lambda = [](auto&&... args){ 466 | const auto istiny = [](auto x){ 467 | return (sizeof(x) == 1UL) ? 1 : 0; 468 | }; 469 | const int aretiny[] = { istiny(args)... }; 470 | return aretiny[0]; 471 | }; 472 | return lambda(1, 1L, 1.0f, '1'); 473 | } 474 | 475 | } 476 | 477 | namespace test_binary_literals 478 | { 479 | 480 | constexpr auto ivii = 0b0000000000101010; 481 | static_assert(ivii == 42, "wrong value"); 482 | 483 | } 484 | 485 | namespace test_generalized_constexpr 486 | { 487 | 488 | template < typename CharT > 489 | constexpr unsigned long 490 | strlen_c(const CharT *const s) noexcept 491 | { 492 | auto length = 0UL; 493 | for (auto p = s; *p; ++p) 494 | ++length; 495 | return length; 496 | } 497 | 498 | static_assert(strlen_c("") == 0UL, ""); 499 | static_assert(strlen_c("x") == 1UL, ""); 500 | static_assert(strlen_c("test") == 4UL, ""); 501 | static_assert(strlen_c("another\0test") == 7UL, ""); 502 | 503 | } 504 | 505 | namespace test_lambda_init_capture 506 | { 507 | 508 | int 509 | test() 510 | { 511 | auto x = 0; 512 | const auto lambda1 = [a = x](int b){ return a + b; }; 513 | const auto lambda2 = [a = lambda1(x)](){ return a; }; 514 | return lambda2(); 515 | } 516 | 517 | } 518 | 519 | namespace test_digit_seperators 520 | { 521 | 522 | constexpr auto ten_million = 100'000'000; 523 | static_assert(ten_million == 100000000, ""); 524 | 525 | } 526 | 527 | namespace test_return_type_deduction 528 | { 529 | 530 | auto f(int& x) { return x; } 531 | decltype(auto) g(int& x) { return x; } 532 | 533 | template < typename T1, typename T2 > 534 | struct is_same 535 | { 536 | static constexpr auto value = false; 537 | }; 538 | 539 | template < typename T > 540 | struct is_same 541 | { 542 | static constexpr auto value = true; 543 | }; 544 | 545 | int 546 | test() 547 | { 548 | auto x = 0; 549 | static_assert(is_same::value, ""); 550 | static_assert(is_same::value, ""); 551 | return x; 552 | } 553 | 554 | } 555 | 556 | } // namespace cxx14 557 | 558 | #endif // __cplusplus >= 201402L 559 | 560 | ]]) 561 | --------------------------------------------------------------------------------