sdap_async.c revision 3319d964721396c07daba383ded6aaaf33ed6e3b
/*
SSSD
Async LDAP Helper routines
Copyright (C) Simo Sorce <ssorce@redhat.com> - 2009
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 <ctype.h>
#include "util/strtonum.h"
#include "providers/ldap/sdap_async_private.h"
#define REPLY_REALLOC_INCREMENT 10
/* ==LDAP-Memory-Handling================================================= */
static int lmsg_destructor(void *mem)
{
return 0;
}
{
void *h;
if (!h) return ENOMEM;
return EOK;
}
/* ==sdap-hanlde-utility-functions======================================== */
static int sdap_handle_destructor(void *mem);
{
struct sdap_handle *sh;
return sh;
}
static int sdap_handle_destructor(void *mem)
{
/* if the structure is currently locked, then mark it to be released
* and prevent talloc from freeing the memory */
if (sh->destructor_lock) {
sh->release_memory = true;
return -1;
}
return 0;
}
{
"Trace: sh[%p], connected[%d], ops[%p], ldap[%p], "
"destructor_lock[%d], release_memory[%d]\n",
if (sh->destructor_lock) return;
sh->destructor_lock = true;
/* make sure nobody tries to reuse this connection from now on */
/* calling the callback may result in freeing the op */
/* check if it is still the same or avoid freeing */
}
}
/* ok, we have done the job, unlock now */
sh->destructor_lock = false;
/* finally if a destructor was ever called, free sh before
* exiting */
if (sh->release_memory) {
/* neutralize the destructor as we already handled
* all was needed to be released */
}
}
/* ==Parse-Results-And-Handle-Disconnections============================== */
struct tevent_timer *te,
{
}
struct tevent_timer *te,
{
}
{
struct timeval no_timeout = {0, 0};
struct tevent_timer *te;
int ret;
"Trace: sh[%p], connected[%d], ops[%p], ldap[%p]\n",
return;
}
if (ret == 0) {
/* this almost always means we have reached the end of
* the list of received messages */
return;
}
if (ret == -1) {
return;
}
/* We don't know if this will be the last result.
*
* important: we must do this before actually processing the message
* because the message processing might even free the sdap_handler
* so it must be the last operation.
* FIXME: use tevent_immediate/tevent_queues, when avilable */
if (!te) {
"Failed to add critical timer to fetch next result!\n");
}
/* now process this message */
}
static const char *sdap_ldap_result_str(int msgtype)
{
switch (msgtype) {
case LDAP_RES_BIND:
return "LDAP_RES_BIND";
case LDAP_RES_SEARCH_ENTRY:
return "LDAP_RES_SEARCH_ENTRY";
return "LDAP_RES_SEARCH_REFERENCE";
case LDAP_RES_SEARCH_RESULT:
return "LDAP_RES_SEARCH_RESULT";
case LDAP_RES_MODIFY:
return "LDAP_RES_MODIFY";
case LDAP_RES_ADD:
return "LDAP_RES_ADD";
case LDAP_RES_DELETE:
return "LDAP_RES_DELETE";
case LDAP_RES_MODDN:
/* These are the same result
case LDAP_RES_MODRDN:
case LDAP_RES_RENAME:
*/
return "LDAP_RES_RENAME";
case LDAP_RES_COMPARE:
return "LDAP_RES_COMPARE";
case LDAP_RES_EXTENDED:
return "LDAP_RES_EXTENDED";
case LDAP_RES_INTERMEDIATE:
return "LDAP_RES_INTERMEDIATE";
case LDAP_RES_ANY:
return "LDAP_RES_ANY";
case LDAP_RES_UNSOLICITED:
return "LDAP_RES_UNSOLICITED";
default:
/* Unmatched, fall through */
break;
}
/* Unknown result type */
return "Unknown result type!";
}
/* process a messgae calling the right operation callback.
* msg is completely taken care of (including freeeing it)
* NOTE: this function may even end up freeing the sdap_handle
* so sdap_hanbdle must not be used after this function is called
*/
{
int msgid;
int msgtype;
int ret;
if (msgid == -1) {
return;
}
}
"Unmatched msgid, discarding message (type: %0x)\n",
msgtype);
return;
}
/* shouldn't happen */
return;
}
switch (msgtype) {
case LDAP_RES_SEARCH_ENTRY:
/* go and process entry */
break;
case LDAP_RES_BIND:
case LDAP_RES_SEARCH_RESULT:
case LDAP_RES_MODIFY:
case LDAP_RES_ADD:
case LDAP_RES_DELETE:
case LDAP_RES_MODDN:
case LDAP_RES_COMPARE:
case LDAP_RES_EXTENDED:
case LDAP_RES_INTERMEDIATE:
/* no more results expected with this msgid */
break;
default:
/* unkwon msg type ?? */
"Couldn't figure out the msg type! [%0x]\n", msgtype);
return;
}
if (!reply) {
} else {
}
}
/* list exist, queue it */
} else {
/* create list, then call callback */
/* must be the last operation as it may end up freeing all memory
* including all ops handlers */
}
}
{
struct tevent_timer *te;
struct sdap_msg *next_reply;
/* get rid of the previous reply, it has been processed already */
}
/* if there are still replies to parse, queue a new operation */
/* use a very small timeout, so that fd operations have a chance to be
* served while processing a long reply */
tv = tevent_timeval_current();
/* wait 5 microsecond */
if (!te) {
"Failed to add critical timer for next reply!\n");
}
}
}
struct tevent_timer *te,
{
}
/* ==LDAP-Operations-Helpers============================================== */
static int sdap_op_destructor(void *mem)
{
return 0;
}
/* we don't check the result here, if a message was really abandoned,
* hopefully the server will get an abandon.
* If the operation was already fully completed, this is going to be
* just a noop */
return 0;
}
{
/* should never happen, but just in case */
return;
}
/* signal the caller that we have a timeout */
}
{
/* check if we need to set a timeout */
if (timeout) {
struct tevent_req *req;
tv = tevent_timeval_current();
/* allocate on op, so when it get freed the timeout is removed */
if (!req) {
return ENOMEM;
}
}
return EOK;
}
/* ==Modify-Password====================================================== */
struct sdap_exop_modify_passwd_state {
struct sdap_handle *sh;
char *user_error_message;
};
struct tevent_context *ev,
struct sdap_handle *sh,
char *user_dn,
const char *password,
const char *new_password,
int timeout)
{
struct sdap_exop_modify_passwd_state *state;
int ret;
int msgid;
struct sdap_exop_modify_passwd_state);
return NULL;
}
if (ret == -1) {
return NULL;
}
if (ret == -1) {
return NULL;
}
"Password Policy control.\n");
ret = ERR_INTERNAL;
goto fail;
}
ber_bvfree(bv);
goto fail;
}
"ldap_extended_operation sent, msgid = %d\n", msgid);
if (ret) {
ret = ERR_INTERNAL;
goto fail;
}
return req;
fail:
return req;
}
{
struct sdap_exop_modify_passwd_state);
int ret;
int c;
int result;
if (error) {
return;
}
&response_controls, 0);
if (ret != LDAP_SUCCESS) {
ret = ERR_INTERNAL;
goto done;
}
if (response_controls == NULL) {
} else {
for (c = 0; response_controls[c] != NULL; c++) {
response_controls[c]->ldctl_oid);
LDAP_CONTROL_PASSWORDPOLICYRESPONSE) == 0) {
&pp_error);
if (ret != LDAP_SUCCESS) {
"ldap_parse_passwordpolicy_control failed.\n");
goto done;
}
"Password Policy Response: expire [%d] grace [%d] "
}
}
}
switch (result) {
case LDAP_SUCCESS:
break;
} else {
"Please make sure the password meets the "
"complexity constraints.");
}
goto done;
}
break;
default:
if (errmsg) {
goto done;
}
}
break;
}
done:
} else {
}
}
char **user_error_message)
{
struct sdap_exop_modify_passwd_state);
return EOK;
}
/* ==Update-passwordLastChanged-attribute====================== */
struct update_last_changed_state {
struct tevent_context *ev;
struct sdap_handle *sh;
const char *dn;
};
struct tevent_req *
struct tevent_context *ev,
struct sdap_handle *sh,
const char *dn,
char *lastchanged_name)
{
struct tevent_req *req;
struct update_last_changed_state *state;
char **values;
int msgid;
return NULL;
}
goto done;
}
goto done;
}
goto done;
}
/* The attribute contains number of days since the epoch */
goto done;
}
if (ret) {
goto done;
}
if (ret) {
goto done;
}
done:
}
return req;
}
{
struct update_last_changed_state *state;
char *errmsg;
int result;
int lret;
if (error) {
return;
}
NULL, 0);
if (lret != LDAP_SUCCESS) {
goto done;
}
done:
} else {
}
}
{
return EOK;
}
/* ==Fetch-RootDSE============================================= */
struct sdap_get_rootdse_state {
struct tevent_context *ev;
struct sdap_options *opts;
struct sdap_handle *sh;
struct sysdb_attrs *rootdse;
};
struct tevent_context *ev,
struct sdap_options *opts,
struct sdap_handle *sh)
{
struct sdap_get_rootdse_state *state;
const char *attrs[] = {
"*",
"altServer",
"supportedControl",
"supportedExtension",
"supportedFeatures",
"supportedLDAPVersion",
"supportedSASLMechanisms",
};
"", LDAP_SCOPE_BASE,
false);
if (!subreq) {
return NULL;
}
return req;
}
/* This is not a real attribute, it's just there to avoid
* actually pulling real data down, to save bandwidth
*/
#define SDAP_MATCHING_RULE_TEST_ATTR "sssmatchingruletest"
{
struct tevent_req);
struct sdap_get_rootdse_state);
struct sysdb_attrs **results;
int ret;
const char *filter;
if (ret) {
return;
}
if (num_results == 0 || !results) {
"Please check that anonymous access to RootDSE is allowed\n"
);
return;
}
if (num_results > 1) {
"Multiple replies when searching for RootDSE ??\n");
return;
}
/* Auto-detect the ldap matching rule if requested */
/* This feature is disabled for both groups
* and initgroups. Skip the auto-detection
* lookup.
*/
"Skipping auto-detection of match rule\n");
return;
}
"Auto-detecting support for match rule\n");
/* Create a filter using the matching rule. It need not point
* at any valid data. We're only going to be looking for the
* error code.
*/
/* Perform a trivial query with the matching rule in play.
* If it returns success, we know it is available. If it
* returns EIO, we know it isn't.
*/
false);
if (!subreq) {
return;
}
}
{
struct tevent_req);
struct sdap_get_rootdse_state);
struct sysdb_attrs **results;
/* The search succeeded */
/* The search failed. Disable support for
* matching rule lookups.
*/
} else {
"Unexpected error while testing for matching rule support\n");
return;
}
"LDAP server %s the matching rule extension\n",
? "supports"
: "does not support");
}
struct sysdb_attrs **rootdse)
{
struct sdap_get_rootdse_state);
return EOK;
}
/* ==Helpers for parsing replies============================== */
struct sdap_reply {
struct sysdb_attrs **reply;
};
struct sdap_reply *sreply,
struct sysdb_attrs *msg)
{
struct sysdb_attrs *,
return ENOMEM;
}
}
return EOK;
}
struct sdap_deref_reply {
struct sdap_deref_attrs **reply;
};
int num_maps,
struct sdap_deref_reply *dreply,
struct sdap_deref_attrs **res)
{
int i;
/* Nothing to add, probably ACIs prevented us from dereferencing
* the attribute */
return EOK;
}
for (i=0; i < num_maps; i++) {
struct sdap_deref_attrs *,
return ENOMEM;
}
}
}
return EOK;
}
{
int ret;
int fd;
struct sockaddr_storage ss;
char ip[NI_MAXHOST];
int port;
if (!DEBUG_IS_SET(SSSDBG_TRACE_INTERNAL)) {
return;
}
return;
}
if (ret == -1) {
return;
}
if (ret != 0) {
return;
}
case AF_INET:
break;
case AF_INET6:
break;
default:
}
}
/* ==Generic Search exposing all options======================= */
void *pvt);
struct sdap_get_generic_ext_state {
struct tevent_context *ev;
struct sdap_options *opts;
struct sdap_handle *sh;
const char *search_base;
int scope;
const char *filter;
const char **attrs;
int timeout;
int sizelimit;
int nserverctrls;
char **refs;
void *cb_data;
unsigned int flags;
};
enum {
/* Be silent about exceeded size limit */
SDAP_SRCH_FLG_SIZELIMIT_SILENT = 1 << 0,
/* Allow paging */
/* Only attribute descriptions are requested */
};
static struct tevent_req *
struct tevent_context *ev,
struct sdap_options *opts,
struct sdap_handle *sh,
const char *search_base,
int scope,
const char *filter,
const char **attrs,
int sizelimit,
int timeout,
void *cb_data,
unsigned int flags)
{
struct sdap_get_generic_ext_state *state;
struct tevent_req *req;
int i;
"Trying LDAP search while not connected.\n");
return req;
}
/* Be extra careful and never allow paging for BASE searches,
* even if requested.
*/
/* Disable paging */
"WARNING: Disabling paging because scope is set to base.\n");
}
* paging on for those requests
*/
/* X-DEREF */
NULL);
if (control) {
}
/* ASQ */
NULL);
if (control) {
}
for (state->nserverctrls=0;
state->nserverctrls++) ;
/* One extra space for NULL, one for page control */
if (!state->serverctrls) {
return req;
}
for (i=0; i < state->nserverctrls; i++) {
}
return req;
}
return req;
}
{
struct sdap_get_generic_ext_state *state =
char *errmsg;
int lret;
int optret;
int msgid;
bool disable_paging;
/* Make sure to free any previous operations so
* if we are handling a large number of pages we
* don't waste memory.
*/
"calling ldap_search_ext with [%s][%s].\n",
state->search_base);
if (DEBUG_IS_SET(SSSDBG_TRACE_LIBS)) {
int i;
}
}
}
if (!disable_paging
NULL,
false,
&page_control);
if (lret != LDAP_SUCCESS) {
goto done;
}
}
if (lret != LDAP_SUCCESS) {
if (lret == LDAP_SERVER_DOWN) {
&errmsg);
if (optret == LDAP_SUCCESS) {
}
else {
}
} else if (lret == LDAP_FILTER_ERROR) {
} else {
}
goto done;
}
goto done;
}
done:
return ret;
}
static errno_t
char **refs)
{
int i;
/* Rare, but it's possible that we might get a reference result with
* no references attached.
*/
return EOK;
}
for (i = 0; refs[i]; i++) {
}
/* Extend the size of the ref array */
"talloc_realloc failed extending ref_array.\n");
return ENOMEM;
}
/* Copy in all the references */
for (i = 0; refs[i]; i++) {
return ENOMEM;
}
}
return EOK;
}
{
struct sdap_get_generic_ext_state);
int result;
int ret;
int lret;
if (error) {
return;
}
if (ret != LDAP_SUCCESS) {
return;
}
"sdap_get_generic_ext_add_references failed: %s(%d)\n",
ldap_memvfree((void **)refs);
return;
}
/* Remove the original strings */
ldap_memvfree((void **)refs);
/* unlock the operation so that we can proceed with the next result */
break;
case LDAP_RES_SEARCH_ENTRY:
return;
}
break;
case LDAP_RES_SEARCH_RESULT:
&returned_controls, 0);
if (ret != LDAP_SUCCESS) {
return;
}
if (result == LDAP_SIZELIMIT_EXCEEDED
|| result == LDAP_ADMINLIMIT_EXCEEDED) {
/* Try to return what we've got */
"LDAP sizelimit was exceeded, "
"returning incomplete data\n");
}
} else if (result == LDAP_INAPPROPRIATE_MATCHING) {
/* This error should only occur when we're testing for
* specialized functionality like the ldap matching rule
* filter for Active Directory. Warn at a higher log
* level and return EIO.
*/
"LDAP_INAPPROPRIATE_MATCHING: %s\n",
return;
} else if (result == LDAP_UNAVAILABLE_CRITICAL_EXTENSION) {
return;
} else if (result == LDAP_REFERRAL) {
"sdap_get_generic_ext_add_references failed: %s(%d)\n",
}
/* For referrals, we need to fall through as if it was LDAP_SUCCESS */
"Unexpected result from ldap: %s(%d), %s\n",
return;
}
/* Determine if there are more pages to retrieve */
if (!page_control) {
/* No paging support. We are done */
return;
}
&total_count, &cookie);
if (lret != LDAP_SUCCESS) {
return;
}
/* Cookie contains data, which means there are more requests
* to be processed.
*/
return;
}
return;
}
return;
}
/* The cookie must be freed even if len == 0 */
/* This was the last page. We're done */
return;
default:
/* what is going on here !? */
return;
}
}
static int
char ***refs)
{
struct sdap_get_generic_ext_state *state =
if (ref_count) {
}
if (refs) {
}
return EOK;
}
/* This search handler can be used by most calls */
struct sdap_options *opts)
{
struct tevent_req);
int ret;
char **refs;
"sdap_get_generic_ext_recv failed [%d]: %s\n",
return;
}
if (ref_count > 0) {
/* We will ignore referrals in the generic handler */
"Request included referrals which were ignored.\n");
if (debug_level & SSSDBG_TRACE_ALL) {
for(i = 0; i < ref_count; i++) {
" Ref: %s\n", refs[i]);
}
}
}
}
/* ==Generic Search exposing all options======================= */
struct sdap_get_and_parse_generic_state {
struct sdap_attr_map *map;
int map_num_attrs;
struct sdap_reply sreply;
struct sdap_options *opts;
};
void *pvt);
struct tevent_context *ev,
struct sdap_options *opts,
struct sdap_handle *sh,
const char *search_base,
int scope,
const char *filter,
const char **attrs,
struct sdap_attr_map *map,
int map_num_attrs,
int attrsonly,
int sizelimit,
int timeout,
bool allow_paging)
{
unsigned int flags = 0;
struct sdap_get_and_parse_generic_state);
if (allow_paging) {
}
if (attrsonly) {
}
if (!subreq) {
return NULL;
}
return req;
}
void *pvt)
{
struct sysdb_attrs *attrs;
struct sdap_get_and_parse_generic_state *state =
return ret;
}
return ret;
}
/* add_to_reply steals attrs, no need to free them here */
return EOK;
}
{
struct tevent_req);
struct sdap_get_and_parse_generic_state *state =
}
struct sysdb_attrs ***reply)
{
struct sdap_get_and_parse_generic_state);
return EOK;
}
/* ==Simple generic search============================================== */
struct sdap_get_generic_state {
struct sysdb_attrs **reply;
};
struct tevent_context *ev,
struct sdap_options *opts,
struct sdap_handle *sh,
const char *search_base,
int scope,
const char *filter,
const char **attrs,
struct sdap_attr_map *map,
int map_num_attrs,
int timeout,
bool allow_paging)
{
return NULL;
}
return req;
}
{
struct tevent_req);
struct sdap_get_generic_state *state =
return;
}
}
struct sysdb_attrs ***reply)
{
struct sdap_get_generic_state *state =
return EOK;
}
/* ==OpenLDAP deref search============================================== */
const char *deref_attr,
const char **attrs,
LDAPControl **ctrl);
static int sdap_x_deref_search_ctrls_destructor(void *ptr);
void *pvt);
struct sdap_x_deref_search_state {
struct sdap_handle *sh;
struct sdap_attr_map_info *maps;
LDAPControl **ctrls;
struct sdap_options *opts;
struct sdap_deref_reply dreply;
int num_maps;
};
static struct tevent_req *
const char *deref_attr, const char **attrs,
int timeout)
{
struct sdap_x_deref_search_state *state;
int ret;
return NULL;
}
return NULL;
}
"Dereferencing entry [%s] using OpenLDAP deref\n", base_dn);
if (!subreq) {
return NULL;
}
return req;
}
const char *deref_attr,
const char **attrs,
LDAPControl **ctrl)
{
int ret;
if (ret != LDAP_SUCCESS) {
return ret;
}
return ret;
}
return EOK;
}
void *pvt)
{
struct sdap_deref_attrs **res;
struct sdap_x_deref_search_state);
&ctrls);
if (ret != LDAP_SUCCESS) {
goto done;
}
if (!ctrls) {
/* When we attempt to request attributes that are not present in
* the dereferenced links, some serves might not send the dereference
* control back at all. Be permissive and treat the search as if
* it didn't find anything.
*/
goto done;
}
if (!derefctrl) {
goto done;
}
&deref_res);
if (ret != LDAP_SUCCESS) {
"ldap_parse_derefresponse_control failed: %s\n",
goto done;
}
if (ret) {
goto done;
}
goto done;
}
}
"All deref results from a single control parsed\n");
done:
return ret;
}
{
struct tevent_req);
struct sdap_x_deref_search_state *state =
}
static int sdap_x_deref_search_ctrls_destructor(void *ptr)
{
ldap_control_free(ctrls[0]);
}
return 0;
}
static int
struct sdap_deref_attrs ***reply)
{
struct sdap_x_deref_search_state);
return EOK;
}
/* ==Security Descriptor (ACL) search=================================== */
struct sdap_sd_search_state {
LDAPControl **ctrls;
struct sdap_options *opts;
struct sysdb_attrs **reply;
struct sdap_reply sreply;
/* Referrals returned by the search */
char **refs;
};
int val,
LDAPControl **ctrl);
static int sdap_sd_search_ctrls_destructor(void *ptr);
void *pvt);
struct tevent_req *
{
struct sdap_sd_search_state *state;
int ret;
goto fail;
}
goto fail;
}
if (!subreq) {
goto fail;
}
return req;
fail:
return req;
}
int val,
LDAPControl **ctrl)
{
int ret;
return ENOMEM;
}
if (ret == -1) {
return EIO;
}
if (ret == -1) {
return EIO;
}
return ret;
}
return EOK;
}
void *pvt)
{
struct sysdb_attrs *attrs;
struct sdap_sd_search_state *state =
NULL, 0,
return ret;
}
return ret;
}
/* add_to_reply steals attrs, no need to free them here */
return EOK;
}
{
int ret;
struct tevent_req);
struct sdap_sd_search_state *state =
"sdap_get_generic_ext_recv failed [%d]: %s\n",
return;
}
}
static int sdap_sd_search_ctrls_destructor(void *ptr)
{
ldap_control_free(ctrls[0]);
}
return 0;
}
struct sysdb_attrs ***_reply,
char ***_refs)
{
struct sdap_sd_search_state);
if(_ref_count) {
}
if (_refs) {
}
return EOK;
}
/* ==Attribute scoped search============================================ */
struct sdap_asq_search_state {
struct sdap_attr_map_info *maps;
int num_maps;
LDAPControl **ctrls;
struct sdap_options *opts;
struct sdap_deref_reply dreply;
};
const char *attr,
LDAPControl **ctrl);
static int sdap_asq_search_ctrls_destructor(void *ptr);
void *pvt);
static struct tevent_req *
const char *base_dn, const char *deref_attr,
{
struct sdap_asq_search_state *state;
int ret;
return NULL;
}
return NULL;
}
if (!subreq) {
return NULL;
}
return req;
}
const char *attr,
LDAPControl **ctrl)
{
int ret;
return ENOMEM;
}
if (ret == -1) {
return EIO;
}
if (ret == -1) {
return EIO;
}
return ret;
}
return EOK;
}
void *pvt)
{
struct sdap_asq_search_state *state =
int i, mi;
struct sdap_attr_map *map;
int num_attrs;
struct sdap_deref_attrs **res;
char *tmp;
char *dn;
bool disable_range_rtrvl;
if (!res) {
goto done;
}
goto done;
}
}
if (!tmp) {
goto done;
}
if (!dn) {
goto done;
}
/* Find all suitable maps in the list */
if (!vals) {
"Unknown entry type, no objectClass found for DN [%s]!\n", dn);
goto done;
}
for (i = 0; vals[i]; i++) {
/* the objectclass is always the first name in the map */
/* it's an entry of the right type */
"Matched objectclass [%s] on DN [%s], will use associated map\n",
break;
}
}
if (!map) {
"DN [%s] did not match the objectClass [%s]\n",
continue;
}
goto done;
}
}
goto done;
}
done:
return ret;
}
{
struct tevent_req);
struct sdap_asq_search_state *state =
}
static int sdap_asq_search_ctrls_destructor(void *ptr)
{
ldap_control_free(ctrls[0]);
}
return 0;
}
struct sdap_deref_attrs ***reply)
{
struct sdap_asq_search_state);
return EOK;
}
/* ==Posix attribute presence test================================= */
void *pvt);
struct sdap_posix_check_state {
struct tevent_context *ev;
struct sdap_options *opts;
struct sdap_handle *sh;
struct sdap_search_base **search_bases;
int timeout;
const char **attrs;
const char *filter;
bool has_posix;
};
struct tevent_req *
struct sdap_search_base **search_bases,
int timeout)
{
struct sdap_posix_check_state *state;
return NULL;
}
goto fail;
}
"(|(&(%s=*)(objectclass=%s))(&(%s=*)(objectclass=%s)))",
goto fail;
}
goto fail;
}
return req;
fail:
return req;
}
{
struct sdap_posix_check_state *state =
"Searching for POSIX attributes with base [%s]\n",
return ENOMEM;
}
return EOK;
}
void *pvt)
{
struct sdap_posix_check_state *state =
char *dn;
char *endptr;
"Search did not find any entry with POSIX attributes\n");
goto done;
}
goto done;
}
}
goto done;
}
errno = 0;
}
done:
return EOK;
}
{
struct tevent_req);
struct sdap_posix_check_state *state =
"sdap_get_generic_ext_recv failed [%d]: %s\n",
return;
}
/* Positive hit is definitve, no need to search other bases */
return;
}
/* There are more search bases to try */
}
return;
}
/* All bases done! */
}
bool *_has_posix)
{
struct sdap_posix_check_state);
return EOK;
}
/* ==Generic Deref Search============================================ */
enum sdap_deref_type {
};
struct sdap_deref_search_state {
struct sdap_handle *sh;
const char *base_dn;
const char *deref_attr;
struct sdap_deref_attrs **reply;
enum sdap_deref_type deref_type;
unsigned flags;
};
struct tevent_req *
struct tevent_context *ev,
struct sdap_options *opts,
struct sdap_handle *sh,
const char *search_base,
const char *filter,
const char *deref_attr,
const char **attrs,
int num_maps,
struct sdap_attr_map_info *maps,
int timeout,
unsigned flags)
{
struct sdap_deref_search_state *state;
state->reply_count = 0;
if (!subreq) {
goto fail;
}
} else {
"Server does not support any known deref method!\n");
goto fail;
}
return req;
fail:
return NULL;
}
{
}
struct sdap_deref_attrs ***reply)
{
}
struct tevent_req *
struct tevent_context *ev,
struct sdap_options *opts,
struct sdap_handle *sh,
const char *base_dn,
const char *deref_attr,
const char **attrs,
int num_maps,
struct sdap_attr_map_info *maps,
int timeout)
{
struct sdap_deref_search_state *state;
state->reply_count = 0;
timeout);
if (!subreq) {
goto fail;
}
timeout);
if (!subreq) {
goto fail;
}
} else {
"Server does not support any known deref method!\n");
goto fail;
}
return req;
fail:
return NULL;
}
{
struct tevent_req);
struct sdap_deref_search_state);
int ret;
switch (state->deref_type) {
case SDAP_DEREF_OPENLDAP:
break;
case SDAP_DEREF_ASQ:
break;
default:
return;
}
}
"LDAP server claims to support deref, but deref search "
"failed. Disabling deref for further requests. You can "
"permanently disable deref by setting "
"ldap_deref_threshold to 0 in domain configuration.");
} else {
}
}
return;
}
}
struct sdap_deref_attrs ***reply)
{
struct sdap_deref_search_state);
return EOK;
}
{
{ LDAP_CONTROL_X_DEREF, "OpenLDAP" },
};
int i;
int deref_threshold;
if (sh->disable_deref) {
return false;
}
if (deref_threshold == 0) {
return false;
}
for (i=0; deref_oids[i][0]; i++) {
deref_oids[i][1]);
return true;
}
}
return false;
}