blob: b072db296f71b3ee2d08882a3b071c79ff4abc99 [file] [log] [blame]
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "authentication/cram_md5/auxprop.hpp"
#include <mutex>
#include <stout/strings.hpp>
#include "logging/logging.hpp"
// We need to disable the deprecation warnings as Apple has decided
// to deprecate all of CyrusSASL's functions with OS 10.11
// (see MESOS-3030). We are using GCC pragmas also for covering clang.
#ifdef __APPLE__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#endif
using std::list;
using std::string;
namespace mesos {
namespace internal {
namespace cram_md5 {
// Storage for the static members.
Multimap<string, Property> InMemoryAuxiliaryPropertyPlugin::properties;
sasl_auxprop_plug_t InMemoryAuxiliaryPropertyPlugin::plugin;
std::mutex InMemoryAuxiliaryPropertyPlugin::mutex;
int InMemoryAuxiliaryPropertyPlugin::initialize(
const sasl_utils_t* utils,
int api,
int* version,
sasl_auxprop_plug_t** plug,
const char* name)
{
if (version == nullptr || plug == nullptr) {
return SASL_BADPARAM;
}
// Check if SASL API is older than the one we were compiled against.
if (api < SASL_AUXPROP_PLUG_VERSION) {
return SASL_BADVERS;
}
*version = SASL_AUXPROP_PLUG_VERSION;
plugin.features = 0;
plugin.spare_int1 = 0;
plugin.glob_context = nullptr;
plugin.auxprop_free = nullptr;
plugin.auxprop_lookup = &InMemoryAuxiliaryPropertyPlugin::lookup;
plugin.name = const_cast<char*>(InMemoryAuxiliaryPropertyPlugin::name());
plugin.auxprop_store = nullptr;
*plug = &plugin;
VLOG(1) << "Initialized in-memory auxiliary property plugin";
return SASL_OK;
}
#if SASL_AUXPROP_PLUG_VERSION <= 4
void InMemoryAuxiliaryPropertyPlugin::lookup(
#else
int InMemoryAuxiliaryPropertyPlugin::lookup(
#endif
void* context,
sasl_server_params_t* sparams,
unsigned flags,
const char* user,
unsigned length)
{
// Pull out the utils.
const sasl_utils_t* utils = sparams->utils;
// We determine the properties we should be looking up by doing a
// 'prop_get' on the property context. Note that some of the
// properties we get might need to be skipped depending on the
// flags (see below).
const propval* properties = utils->prop_get(sparams->propctx);
CHECK(properties != nullptr)
<< "Invalid auxiliary properties requested for lookup";
// TODO(benh): Consider "parsing" 'user' if it has an '@' separating
// the actual user and a realm.
string realm = sparams->user_realm != nullptr
? sparams->user_realm
: sparams->serverFQDN;
VLOG(1)
<< "Request to lookup properties for "
<< "user: '" << user << "' "
<< "realm: '" << realm << "' "
<< "server FQDN: '" << sparams->serverFQDN << "' "
#ifdef SASL_AUXPROP_VERIFY_AGAINST_HASH
<< "SASL_AUXPROP_VERIFY_AGAINST_HASH: "
<< (flags & SASL_AUXPROP_VERIFY_AGAINST_HASH ? "true ": "false ")
#endif
<< "SASL_AUXPROP_OVERRIDE: "
<< (flags & SASL_AUXPROP_OVERRIDE ? "true ": "false ")
<< "SASL_AUXPROP_AUTHZID: "
<< (flags & SASL_AUXPROP_AUTHZID ? "true ": "false ");
// Now iterate through each property requested.
const propval* property = properties;
for (; property->name != nullptr; property++) {
const char* name = property->name;
// Skip properties that don't apply to this lookup given the flags.
if (flags & SASL_AUXPROP_AUTHZID) {
if (strings::startsWith(name, '*')) {
VLOG(1) << "Skipping auxiliary property '" << name
<< "' since SASL_AUXPROP_AUTHZID == true";
continue;
}
} else {
// Only consider properties that start with '*' if
// SASL_AUXPROP_AUTHZID is not set but don't include the '*'
// when looking up the property name.
if (!strings::startsWith(name, '*')) {
VLOG(1) << "Skipping auxiliary property '" << name
<< "' since SASL_AUXPROP_AUTHZID == false "
<< "but property name starts with '*'";
continue;
} else {
name = name + 1;
}
}
// Don't override already set values unless instructed otherwise.
if (property->values != nullptr && !(flags & SASL_AUXPROP_OVERRIDE)) {
#ifdef SASL_AUXPROP_VERIFY_AGAINST_HASH
// Regardless of SASL_AUXPROP_OVERRIDE we're expected to
// override property 'userPassword' when the
// SASL_AUXPROP_VERIFY_AGAINST_HASH flag is set, so we erase it
// here.
if (flags & SASL_AUXPROP_VERIFY_AGAINST_HASH &&
string(name) == string(SASL_AUX_PASSWORD_PROP)) {
VLOG(1) << "Erasing auxiliary property '" << name
<< "' even though SASL_AUXPROP_OVERRIDE == true "
<< "since SASL_AUXPROP_VERIFY_AGAINST_HASH == true";
utils->prop_erase(sparams->propctx, property->name);
} else {
VLOG(1) << "Skipping auxiliary property '" << name
<< "' since SASL_AUXPROP_OVERRIDE == false "
<< "and value(s) already set";
continue;
}
#else
VLOG(1) << "Skipping auxiliary property '" << name
<< "' since SASL_AUXPROP_OVERRIDE == false "
<< "and value(s) already set";
continue;
#endif
} else if (property->values != nullptr) {
CHECK(flags & SASL_AUXPROP_OVERRIDE);
VLOG(1) << "Erasing auxiliary property '" << name
<< "' since SASL_AUXPROP_OVERRIDE == true";
utils->prop_erase(sparams->propctx, property->name);
}
VLOG(1) << "Looking up auxiliary property '" << property->name << "'";
Option<list<string>> values = lookup(user, name);
if (values.isSome()) {
if (values->empty()) {
// Add the 'nullptr' value to indicate there were no values.
utils->prop_set(sparams->propctx, property->name, nullptr, 0);
} else {
// Add all the values. Note that passing nullptr as the property
// name for 'prop_set' will append values to the same name as
// the previous 'prop_set' calls which is the behavior we want
// after adding the first value.
bool append = false;
foreach (const string& value, values.get()) {
sparams->utils->prop_set(
sparams->propctx,
append ? nullptr : property->name,
value.c_str(),
-1); // Let 'prop_set' use strlen.
append = true;
}
}
}
}
#if SASL_AUXPROP_PLUG_VERSION > 4
return SASL_OK;
#endif
}
} // namespace cram_md5 {
} // namespace internal {
} // namespace mesos {
#ifdef __APPLE__
#pragma GCC diagnostic pop
#endif