cache_req.c revision 1a89fc33d1b9b1070c7ab83fb0314e538ac46736
/*
Authors:
Pavel Březina <pbrezina@redhat.com>
Copyright (C) 2016 Red Hat
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <ldb.h>
#include <talloc.h>
#include <tevent.h>
#include <errno.h>
#include "responder/common/responder.h"
#include "responder/common/cache_req/cache_req_private.h"
#include "responder/common/cache_req/cache_req_plugin.h"
static const struct cache_req_plugin *
{
};
if (type >= CACHE_REQ_SENTINEL) {
return NULL;
}
}
enum cache_req_type type)
{
const struct cache_req_plugin *plugin;
return EINVAL;
}
return EOK;
}
static const char *
{
return "BUG: Invalid cache_req pointer\n";
}
switch (cr->req_dom_type) {
case CACHE_REQ_POSIX_DOM:
return "POSIX-only";
return "Application-only";
case CACHE_REQ_ANY_DOM:
return "Any";
}
return "Unknown";
}
static struct cache_req *
struct cache_req_data *data,
struct sss_nc_ctx *ncache,
int midpoint,
{
return NULL;
}
/* It is perfectly fine to just overflow here. */
return NULL;
}
return cr;
}
static errno_t
{
const char *dup_name;
return ENOMEM;
}
return EOK;
}
static bool
struct sss_domain_info *domain)
{
return true;
}
return false;
}
return true;
}
static bool
struct sss_domain_info *domain)
{
bool valid = false;
switch (cr->req_dom_type) {
case CACHE_REQ_POSIX_DOM:
break;
break;
case CACHE_REQ_ANY_DOM:
valid = true;
break;
}
"Request type %s for domain %s type %s is %svalid\n",
return valid;
}
static bool
struct sss_domain_info *domain)
{
bool ok;
if (ok == false) {
return false;
}
if (ok == false) {
return false;
}
return true;
}
static errno_t
struct cache_req_result **_result)
{
return ENOENT;
}
(*_result)->well_known_object = true;
"Unable to prepare data [%d]: %s\n",
}
return ret;
}
static errno_t
struct sss_domain_info *domain)
{
return EOK;
}
"Preparing input data for domain [%s] rules\n",
"Unable to prepare data [%d]: %s\n",
return ret;
}
return EOK;
}
static errno_t
struct sss_domain_info *domain)
{
"Bug: no create debug name function specified!\n");
return ERR_INTERNAL;
}
"Unable to create debug name!\n");
return ENOMEM;
}
return EOK;
}
static errno_t
struct sss_domain_info *domain)
{
return ret;
}
return ret;
}
return EOK;
}
{
"This request type does not support "
"global negative cache\n");
return;
}
"Cannot set negative cache for [%s] [%d]: %s\n",
/* not fatal */
}
return;
}
static bool
{
return false;
}
return false;
}
return false;
}
return true;
}
struct cache_req_search_domains_state {
/* input data */
struct tevent_context *ev;
/* work data */
struct cache_req_domain *cr_domain;
struct sss_domain_info *selected_domain;
struct cache_req_result **results;
bool check_next;
bool dp_success;
bool bypass_cache;
bool bypass_dp;
};
struct tevent_req *
struct tevent_context *ev,
struct cache_req_domain *cr_domain,
bool check_next,
bool bypass_cache,
bool bypass_dp)
{
struct tevent_req *req;
struct cache_req_search_domains_state);
return NULL;
}
state->dp_success = true;
return req;
}
} else {
}
return req;
}
{
struct cache_req_search_domains_state *state;
struct tevent_req *subreq;
struct sss_domain_info *domain;
bool is_domain_valid;
bool allow_no_fqn;
/* As the cr_domain list is a flatten version of the domains
* list, we have to ensure to only go through the subdomains in
* case it's specified in the plugin to do so.
*/
continue;
}
/* Check if this domain is valid for this request. */
if (!is_domain_valid) {
continue;
}
/* If not specified otherwise, we skip domains that require fully
* qualified names on domain less search. We do not descend into
* subdomains here since those are implicitly qualified.
*/
continue;
}
break;
}
return ret;
}
return ENOMEM;
}
/* we will continue with the following domain the next time */
if (state->check_next) {
}
return EAGAIN;
}
/* If we've got some result from previous searches we want to return
* EOK here so the whole cache request is successfully finished. */
if (state->num_results > 0) {
return EOK;
}
/* We have searched all available domains and no result was found.
*
* If the plug-in uses a negative cache which is shared among all domains
* (e.g. unique identifiers such as user or group id or sid), we add it
* here and return object not found error.
*
* However, we can only set the negative cache if all data provider
* requests succeeded because only then we can be sure that it does
* not exist-
*/
if (state->dp_success) {
}
return ENOENT;
}
{
struct cache_req_search_domains_state *state;
struct ldb_result *result;
struct tevent_req *req;
bool dp_success;
/* Remember if any DP request fails. */
switch (ret) {
case EOK:
/* We got some data from this search. Save it. */
&state->num_results);
/* We were unable to save data. */
goto done;
}
/* We are not interested in more results. */
goto done;
}
break;
case ENOENT:
if (state->check_next == false) {
/* Not found. */
goto done;
}
/* Continue with next domain. */
break;
default:
/* Some serious error has happened. Finish. */
goto done;
}
/* This is a domain less search, continue with the next domain. */
done:
/* We have at least one result. */
}
switch (ret) {
case EOK:
break;
case EAGAIN:
break;
default:
break;
}
return;
}
static errno_t
struct tevent_req *req,
struct cache_req_result ***_results)
{
struct cache_req_search_domains_state *state;
}
return EOK;
}
/**
* Return true if we should issue another search.
*/
const char *input_domain,
bool first_iteration,
bool *_bypass_cache,
bool *_bypass_dp)
{
bool bypass_cache;
bool bypass_dp;
if (cr->bypass_cache) {
/* The caller wants to contact Data Provider first
* or it is inferred by cache_req plug-in. */
bypass_cache = true;
bypass_dp = false;
if (!first_iteration) {
return false;
}
} else if (input_domain != NULL) {
/* We will search only one domain. */
bypass_cache = false;
bypass_dp = false;
if (!first_iteration) {
return false;
}
} else if (!cr->cache_first) {
/* We will search cache and on cache-miss
* contact domain provider sequentially. */
bypass_cache = false;
bypass_dp = false;
if (!first_iteration) {
return false;
}
} else {
/* We will first search the cache in all domains. If we don't get
* any match we will then contact Data Provider starting with the
* first domain again. */
bypass_cache = first_iteration ? false : true;
bypass_dp = first_iteration ? true : false;
}
*_bypass_dp = bypass_dp;
return true;
}
struct cache_req_state {
/* input data */
struct tevent_context *ev;
const char *domain_name;
/* work data */
struct cache_req_result **results;
bool first_iteration;
};
struct tevent_req *req,
const char *domain);
struct tevent_req *req,
const char *domain);
const char *domain_name);
static errno_t
struct cache_req_domain *oredered_domain,
bool check_next,
bool bypass_cache,
bool bypass_dp);
struct tevent_context *ev,
struct sss_nc_ctx *ncache,
int midpoint,
const char *domain,
struct cache_req_data *data)
{
struct cache_req_state *state;
struct cache_req_result *result;
struct tevent_req *req;
return NULL;
}
goto done;
}
state->first_iteration = true;
&state->num_results);
goto done;
goto done;
}
goto done;
}
done:
}
return req;
}
struct tevent_req *req,
const char *domain)
{
struct tevent_req *subreq;
const char *default_domain;
/* Call cache_req_update_domains() in order to get a up to date list
* of domains and subdomains, if needed. Otherwise just return EOK as
* the input was not a name, thus there's no need to process it
* further. */
}
/* Call cache_req_update_domains() in order to get a up to date list
* of domains and subdomains, if needed. Otherwise, just use the input
* name as it is. */
return ret;
}
}
}
/* Parse name since it may contain a domain name. */
return ENOMEM;
}
return EAGAIN;
}
struct tevent_req *req,
const char *domain)
{
struct tevent_req *subreq;
return EOK;
}
return ENOMEM;
}
return EAGAIN;
}
{
struct tevent_req *req;
struct cache_req_state *state;
goto done;
}
/* Input was not name, there is no need to process it further. */
goto immediately;
}
/* We do not want to parse the name. */
goto done;
}
}
done:
return;
}
}
{
struct tevent_req *req;
struct cache_req_state *state;
char *name;
char *domain;
bool maybe_upn;
switch (ret) {
case EOK:
return;
}
break;
case ERR_DOMAIN_NOT_FOUND:
if (!maybe_upn) {
return;
}
break;
default:
return;
}
return;
}
}
const char *domain_name)
{
struct cache_req_domain *cr_domain;
bool check_next;
bool bypass_cache;
bool bypass_dp;
bool search;
&bypass_cache, &bypass_dp);
if (!search) {
/* We're done here. */
return EOK;
}
if (domain_name != NULL) {
"Performing a single domain search\n");
return ERR_DOMAIN_NOT_FOUND;
}
check_next = false;
} else {
"Performing a multi-domain search\n");
check_next = true;
}
}
static errno_t
struct cache_req_domain *cr_domain,
bool check_next,
bool bypass_cache,
bool bypass_dp)
{
struct tevent_req *subreq;
"Search will %s the cache and %s the data provider\n",
return ENOMEM;
}
return EAGAIN;
}
{
struct cache_req_state *state;
struct tevent_req *req;
/* Try again different search schema. */
state->first_iteration = false;
/* We're done searching and we have found nothing. */
/* Lookup domain was specified as input. Since we haven't
* found anything yet we may want to try UPN search with
* some plug-ins. */
/* Try UPN now. */
state->first_iteration = true;
}
}
}
}
switch (ret) {
case EOK:
break;
case EAGAIN:
break;
case ENOENT:
break;
default:
break;
}
return;
}
struct tevent_req *req,
struct cache_req_result ***_results)
{
struct cache_req_state *state;
}
return EOK;
}
struct tevent_req *req,
struct cache_req_result **_result)
{
struct cache_req_state *state;
}
return EOK;
}
struct tevent_req *
struct tevent_context *ev,
struct sss_nc_ctx *ncache,
const char *domain,
struct cache_req_data *data)
{
struct tevent_req *req;
return NULL;
}
return req;
}