mirror of
https://salsa.debian.org/freeipa-team/freeipa.git
synced 2024-12-26 08:51:50 -06:00
9f13b330aa
Internally performs multiple seraches as needed based on the basedn strings passed in and whether the caller indicated that any result is ok or all results are needed. Signed-off-by: Simo Sorce <simo@redhat.com> Reviewed-By: Martin Babinsky <mbabinsk@redhat.com>
716 lines
18 KiB
C
716 lines
18 KiB
C
/*
|
|
* MIT Kerberos KDC database backend for FreeIPA
|
|
*
|
|
* Authors: Simo Sorce <ssorce@redhat.com>
|
|
*
|
|
* Copyright (C) 2011 Simo Sorce, Red Hat
|
|
* see file 'COPYING' for use and warranty information
|
|
*
|
|
* This program is free software you can redistribute it and/or modify
|
|
* 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 "ipa_kdb.h"
|
|
#include <unicase.h>
|
|
|
|
static struct timeval std_timeout = {300, 0};
|
|
|
|
char *ipadb_filter_escape(const char *input, bool star)
|
|
{
|
|
char *output;
|
|
size_t i = 0;
|
|
size_t j = 0;
|
|
|
|
if (!input) {
|
|
return NULL;
|
|
}
|
|
|
|
/* Assume the worst-case. */
|
|
output = malloc(strlen(input) * 3 + 1);
|
|
if (!output) {
|
|
return NULL;
|
|
}
|
|
|
|
while (input[i]) {
|
|
switch(input[i]) {
|
|
case '*':
|
|
if (star) {
|
|
output[j++] = '\\';
|
|
output[j++] = '2';
|
|
output[j++] = 'a';
|
|
} else {
|
|
output[j++] = '*';
|
|
}
|
|
break;
|
|
case '(':
|
|
output[j++] = '\\';
|
|
output[j++] = '2';
|
|
output[j++] = '8';
|
|
break;
|
|
case ')':
|
|
output[j++] = '\\';
|
|
output[j++] = '2';
|
|
output[j++] = '9';
|
|
break;
|
|
case '\\':
|
|
output[j++] = '\\';
|
|
output[j++] = '5';
|
|
output[j++] = 'c';
|
|
break;
|
|
default:
|
|
output[j++] = input[i];
|
|
}
|
|
|
|
i++;
|
|
}
|
|
output[j] = '\0';
|
|
|
|
return output;
|
|
}
|
|
|
|
static krb5_error_code ipadb_simple_ldap_to_kerr(int ldap_error)
|
|
{
|
|
switch (ldap_error) {
|
|
case LDAP_SUCCESS:
|
|
return 0;
|
|
|
|
case LDAP_NO_SUCH_OBJECT:
|
|
case LDAP_NO_SUCH_ATTRIBUTE:
|
|
return KRB5_KDB_NOENTRY;
|
|
|
|
case LDAP_ALIAS_PROBLEM:
|
|
case LDAP_INVALID_DN_SYNTAX:
|
|
case LDAP_ALIAS_DEREF_PROBLEM:
|
|
case LDAP_UNDEFINED_TYPE:
|
|
case LDAP_INAPPROPRIATE_MATCHING:
|
|
case LDAP_INVALID_SYNTAX:
|
|
case LDAP_NAMING_VIOLATION:
|
|
case LDAP_OBJECT_CLASS_VIOLATION:
|
|
case LDAP_NO_OBJECT_CLASS_MODS:
|
|
return KRB5_KDB_INTERNAL_ERROR;
|
|
|
|
case LDAP_ALREADY_EXISTS:
|
|
case LDAP_NOT_ALLOWED_ON_NONLEAF:
|
|
case LDAP_NOT_ALLOWED_ON_RDN:
|
|
case LDAP_TIMELIMIT_EXCEEDED:
|
|
case LDAP_SIZELIMIT_EXCEEDED:
|
|
case LDAP_ADMINLIMIT_EXCEEDED:
|
|
case LDAP_STRONG_AUTH_REQUIRED:
|
|
case LDAP_CONFIDENTIALITY_REQUIRED:
|
|
case LDAP_INAPPROPRIATE_AUTH:
|
|
case LDAP_INVALID_CREDENTIALS:
|
|
case LDAP_INSUFFICIENT_ACCESS:
|
|
case LDAP_BUSY:
|
|
case LDAP_UNAVAILABLE:
|
|
case LDAP_UNWILLING_TO_PERFORM:
|
|
case LDAP_CONSTRAINT_VIOLATION:
|
|
case LDAP_TYPE_OR_VALUE_EXISTS:
|
|
return KRB5_KDB_CONSTRAINT_VIOLATION;
|
|
}
|
|
|
|
return KRB5_KDB_SERVER_INTERNAL_ERR;
|
|
}
|
|
|
|
static bool ipadb_need_retry(struct ipadb_context *ipactx, int error)
|
|
{
|
|
switch(error) {
|
|
/* connection errors */
|
|
case LDAP_SERVER_DOWN:
|
|
case LDAP_LOCAL_ERROR:
|
|
case LDAP_ENCODING_ERROR:
|
|
case LDAP_DECODING_ERROR:
|
|
case LDAP_TIMEOUT:
|
|
case LDAP_USER_CANCELLED:
|
|
case LDAP_PARAM_ERROR:
|
|
case LDAP_NO_MEMORY:
|
|
case LDAP_CONNECT_ERROR:
|
|
case LDAP_NOT_SUPPORTED:
|
|
case LDAP_CLIENT_LOOP:
|
|
case LDAP_X_CONNECTING:
|
|
|
|
/* server returned errors */
|
|
case LDAP_PROTOCOL_ERROR:
|
|
case LDAP_BUSY:
|
|
case LDAP_UNAVAILABLE:
|
|
case LDAP_UNWILLING_TO_PERFORM:
|
|
case LDAP_LOOP_DETECT:
|
|
|
|
/* prob connection error, try to reconnect */
|
|
error = ipadb_get_connection(ipactx);
|
|
if (error == 0) {
|
|
return true;
|
|
}
|
|
/* fall through */
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
static int ipadb_check_connection(struct ipadb_context *ipactx)
|
|
{
|
|
if (ipactx->lcontext == NULL) {
|
|
return ipadb_get_connection(ipactx);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
krb5_error_code ipadb_simple_search(struct ipadb_context *ipactx,
|
|
char *basedn, int scope,
|
|
char *filter, char **attrs,
|
|
LDAPMessage **res)
|
|
{
|
|
int ret;
|
|
|
|
ret = ipadb_check_connection(ipactx);
|
|
if (ret != 0)
|
|
return ipadb_simple_ldap_to_kerr(ret);
|
|
|
|
ret = ldap_search_ext_s(ipactx->lcontext, basedn, scope,
|
|
filter, attrs, 0, NULL, NULL,
|
|
&std_timeout, LDAP_NO_LIMIT,
|
|
res);
|
|
|
|
/* first test if we need to retry to connect */
|
|
if (ret != 0 &&
|
|
ipadb_need_retry(ipactx, ret)) {
|
|
ldap_msgfree(*res);
|
|
ret = ldap_search_ext_s(ipactx->lcontext, basedn, scope,
|
|
filter, attrs, 0, NULL, NULL,
|
|
&std_timeout, LDAP_NO_LIMIT,
|
|
res);
|
|
}
|
|
|
|
return ipadb_simple_ldap_to_kerr(ret);
|
|
}
|
|
|
|
krb5_error_code ipadb_simple_delete(struct ipadb_context *ipactx, char *dn)
|
|
{
|
|
int ret;
|
|
|
|
ret = ipadb_check_connection(ipactx);
|
|
if (ret != 0)
|
|
return ipadb_simple_ldap_to_kerr(ret);
|
|
|
|
ret = ldap_delete_ext_s(ipactx->lcontext, dn, NULL, NULL);
|
|
|
|
/* first test if we need to retry to connect */
|
|
if (ret != 0 &&
|
|
ipadb_need_retry(ipactx, ret)) {
|
|
|
|
ret = ldap_delete_ext_s(ipactx->lcontext, dn, NULL, NULL);
|
|
}
|
|
|
|
return ipadb_simple_ldap_to_kerr(ret);
|
|
}
|
|
|
|
krb5_error_code ipadb_simple_add(struct ipadb_context *ipactx,
|
|
char *dn, LDAPMod **mods)
|
|
{
|
|
int ret;
|
|
|
|
ret = ipadb_check_connection(ipactx);
|
|
if (ret != 0)
|
|
return ipadb_simple_ldap_to_kerr(ret);
|
|
|
|
ret = ldap_add_ext_s(ipactx->lcontext, dn, mods, NULL, NULL);
|
|
|
|
/* first test if we need to retry to connect */
|
|
if (ret != 0 &&
|
|
ipadb_need_retry(ipactx, ret)) {
|
|
|
|
ret = ldap_add_ext_s(ipactx->lcontext, dn, mods, NULL, NULL);
|
|
}
|
|
|
|
return ipadb_simple_ldap_to_kerr(ret);
|
|
}
|
|
|
|
krb5_error_code ipadb_simple_modify(struct ipadb_context *ipactx,
|
|
char *dn, LDAPMod **mods)
|
|
{
|
|
int ret;
|
|
|
|
ret = ipadb_check_connection(ipactx);
|
|
if (ret != 0)
|
|
return ipadb_simple_ldap_to_kerr(ret);
|
|
|
|
ret = ldap_modify_ext_s(ipactx->lcontext, dn, mods, NULL, NULL);
|
|
|
|
/* first test if we need to retry to connect */
|
|
if (ret != 0 &&
|
|
ipadb_need_retry(ipactx, ret)) {
|
|
|
|
ret = ldap_modify_ext_s(ipactx->lcontext, dn, mods, NULL, NULL);
|
|
}
|
|
|
|
return ipadb_simple_ldap_to_kerr(ret);
|
|
}
|
|
|
|
krb5_error_code ipadb_simple_delete_val(struct ipadb_context *ipactx,
|
|
char *dn, char *attr, char *value)
|
|
{
|
|
krb5_error_code kerr;
|
|
LDAPMod *mods[2];
|
|
|
|
mods[0] = calloc(1, sizeof(LDAPMod));
|
|
if (!mods[0]) {
|
|
return ENOMEM;
|
|
}
|
|
mods[1] = NULL;
|
|
|
|
mods[0]->mod_op = LDAP_MOD_DELETE;
|
|
mods[0]->mod_type = strdup(attr);
|
|
if (!mods[0]->mod_type) {
|
|
kerr = ENOMEM;
|
|
goto done;
|
|
}
|
|
mods[0]->mod_values = calloc(2, sizeof(char *));
|
|
if (!mods[0]->mod_values) {
|
|
kerr = ENOMEM;
|
|
goto done;
|
|
}
|
|
mods[0]->mod_values[0] = strdup(value);
|
|
if (!mods[0]->mod_values[0]) {
|
|
kerr = ENOMEM;
|
|
goto done;
|
|
}
|
|
|
|
kerr = ipadb_simple_modify(ipactx, dn, mods);
|
|
|
|
done:
|
|
ldap_mods_free(mods, 0);
|
|
return kerr;
|
|
}
|
|
|
|
krb5_error_code ipadb_deref_search(struct ipadb_context *ipactx,
|
|
char *base_dn, int scope,
|
|
char *filter,
|
|
char **entry_attrs,
|
|
char **deref_attr_names,
|
|
char **deref_attrs,
|
|
LDAPMessage **res)
|
|
{
|
|
struct berval derefval = { 0, NULL };
|
|
LDAPControl *ctrl[2] = { NULL, NULL };
|
|
LDAPDerefSpec *ds;
|
|
krb5_error_code kerr;
|
|
int times;
|
|
int ret;
|
|
int c, i;
|
|
bool retry;
|
|
|
|
for (c = 0; deref_attr_names[c]; c++) {
|
|
/* count */ ;
|
|
}
|
|
|
|
ds = calloc(c+1, sizeof(LDAPDerefSpec));
|
|
if (!ds) {
|
|
return ENOMEM;
|
|
}
|
|
|
|
for (i = 0; deref_attr_names[i]; i++) {
|
|
ds[i].derefAttr = deref_attr_names[i];
|
|
ds[i].attributes = deref_attrs;
|
|
}
|
|
ds[c].derefAttr = NULL;
|
|
|
|
ret = ldap_create_deref_control_value(ipactx->lcontext, ds, &derefval);
|
|
if (ret != LDAP_SUCCESS) {
|
|
kerr = ENOMEM;
|
|
goto done;
|
|
}
|
|
|
|
ret = ldap_control_create(LDAP_CONTROL_X_DEREF,
|
|
1, &derefval, 1, &ctrl[0]);
|
|
if (ret != LDAP_SUCCESS) {
|
|
kerr = ENOMEM;
|
|
goto done;
|
|
}
|
|
|
|
/* retry once if connection errors (tot. max. 2 tries) */
|
|
times = 2;
|
|
ret = LDAP_SUCCESS;
|
|
retry = true;
|
|
while (retry) {
|
|
times--;
|
|
|
|
ret = ipadb_check_connection(ipactx);
|
|
if (ret != 0)
|
|
break;
|
|
|
|
ret = ldap_search_ext_s(ipactx->lcontext, base_dn,
|
|
scope, filter,
|
|
entry_attrs, 0,
|
|
ctrl, NULL,
|
|
&std_timeout, LDAP_NO_LIMIT,
|
|
res);
|
|
retry = ipadb_need_retry(ipactx, ret) && times > 0;
|
|
|
|
if (retry) {
|
|
/* Free result before next try */
|
|
ldap_msgfree(*res);
|
|
}
|
|
}
|
|
|
|
kerr = ipadb_simple_ldap_to_kerr(ret);
|
|
|
|
done:
|
|
ldap_control_free(ctrl[0]);
|
|
ldap_memfree(derefval.bv_val);
|
|
free(ds);
|
|
return kerr;
|
|
}
|
|
|
|
/* result extraction */
|
|
|
|
int ipadb_ldap_attr_to_int(LDAP *lcontext, LDAPMessage *le,
|
|
char *attrname, int *result)
|
|
{
|
|
struct berval **vals;
|
|
int ret = ENOENT;
|
|
|
|
vals = ldap_get_values_len(lcontext, le, attrname);
|
|
if (vals) {
|
|
*result = atoi(vals[0]->bv_val);
|
|
ret = 0;
|
|
ldap_value_free_len(vals);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int ipadb_ldap_attr_to_uint32(LDAP *lcontext, LDAPMessage *le,
|
|
char *attrname, uint32_t *result)
|
|
{
|
|
struct berval **vals;
|
|
long r;
|
|
int ret = ENOENT;
|
|
|
|
vals = ldap_get_values_len(lcontext, le, attrname);
|
|
if (vals) {
|
|
r = atol(vals[0]->bv_val);
|
|
if (r < 0 || r > (uint32_t)-1) {
|
|
ret = EINVAL;
|
|
} else {
|
|
*result = r;
|
|
ret = 0;
|
|
}
|
|
ldap_value_free_len(vals);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int ipadb_ldap_attr_to_str(LDAP *lcontext, LDAPMessage *le,
|
|
char *attrname, char **result)
|
|
{
|
|
struct berval **vals;
|
|
int ret = ENOENT;
|
|
|
|
vals = ldap_get_values_len(lcontext, le, attrname);
|
|
if (vals) {
|
|
*result = strndup(vals[0]->bv_val, vals[0]->bv_len);
|
|
if (!*result) {
|
|
ret = ENOMEM;
|
|
} else {
|
|
ret = 0;
|
|
}
|
|
ldap_value_free_len(vals);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int ipadb_ldap_attr_to_strlist(LDAP *lcontext, LDAPMessage *le,
|
|
char *attrname, char ***result)
|
|
{
|
|
struct berval **vals = NULL;
|
|
char **strlist = NULL;
|
|
int ret;
|
|
int i;
|
|
|
|
vals = ldap_get_values_len(lcontext, le, attrname);
|
|
if (!vals) {
|
|
return ENOENT;
|
|
}
|
|
|
|
for (i = 0; vals[i]; i++) /* count */ ;
|
|
|
|
strlist = calloc(i + 1, sizeof(char *));
|
|
if (!strlist) {
|
|
ret = ENOMEM;
|
|
goto fail;
|
|
}
|
|
|
|
for (i = 0; vals[i]; i++) {
|
|
strlist[i] = strndup(vals[i]->bv_val, vals[i]->bv_len);
|
|
if (!strlist[i]) {
|
|
ret = ENOMEM;
|
|
goto fail;
|
|
}
|
|
}
|
|
|
|
ldap_value_free_len(vals);
|
|
*result = strlist;
|
|
return 0;
|
|
|
|
fail:
|
|
ldap_value_free_len(vals);
|
|
for (i = 0; strlist && strlist[i]; i++) {
|
|
free(strlist[i]);
|
|
}
|
|
free(strlist);
|
|
return ret;
|
|
}
|
|
|
|
int ipadb_ldap_attr_to_bool(LDAP *lcontext, LDAPMessage *le,
|
|
char *attrname, bool *result)
|
|
{
|
|
struct berval **vals;
|
|
int ret = ENOENT;
|
|
|
|
vals = ldap_get_values_len(lcontext, le, attrname);
|
|
if (vals) {
|
|
if (strcasecmp("TRUE", vals[0]->bv_val) == 0) {
|
|
*result = true;
|
|
ret = 0;
|
|
} else if (strcasecmp("FALSE", vals[0]->bv_val) == 0) {
|
|
*result = false;
|
|
ret = 0;
|
|
} else {
|
|
ret = EINVAL;
|
|
}
|
|
ldap_value_free_len(vals);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int ipadb_ldap_attr_to_time_t(LDAP *lcontext, LDAPMessage *le,
|
|
char *attrname, time_t *result)
|
|
{
|
|
struct berval **vals;
|
|
char *p;
|
|
struct tm stm = { 0 };
|
|
int ret = ENOENT;
|
|
|
|
vals = ldap_get_values_len(lcontext, le, attrname);
|
|
if (vals) {
|
|
p = strptime(vals[0]->bv_val, "%Y%m%d%H%M%SZ", &stm);
|
|
if (p && *p == '\0') {
|
|
*result = timegm(&stm);
|
|
ret = 0;
|
|
} else {
|
|
ret = EINVAL;
|
|
}
|
|
ldap_value_free_len(vals);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int ipadb_ldap_attr_to_krb5_timestamp(LDAP *lcontext, LDAPMessage *le,
|
|
char *attrname, krb5_timestamp *result)
|
|
{
|
|
time_t res_time;
|
|
long long res_long;
|
|
|
|
int ret = ipadb_ldap_attr_to_time_t(lcontext, le,
|
|
attrname, &res_time);
|
|
if (ret) return ret;
|
|
|
|
/* this will cast correctly maintaing sign to a 64bit variable */
|
|
res_long = res_time;
|
|
|
|
/* For dates beyond IPAPWD_END_OF_TIME, rest_time might oveflow
|
|
* on 32-bit platforms. This does not apply for 64-bit platforms.
|
|
* However, since krb5 uses 32-bit time representation, we need
|
|
* to limit the result.*/
|
|
|
|
if (res_long < 0 || res_long > IPAPWD_END_OF_TIME) {
|
|
*result = IPAPWD_END_OF_TIME; // 1 Jan 2038, 00:00 GMT
|
|
} else {
|
|
*result = (krb5_timestamp)res_long;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int ipadb_ldap_attr_has_value(LDAP *lcontext, LDAPMessage *le,
|
|
char *attrname, const char *value)
|
|
{
|
|
struct berval **vals;
|
|
int ret = ENOENT;
|
|
int i, result;
|
|
|
|
vals = ldap_get_values_len(lcontext, le, attrname);
|
|
if (vals) {
|
|
for (i = 0; vals[i]; i++) {
|
|
if (ulc_casecmp(vals[i]->bv_val, vals[i]->bv_len,
|
|
value, strlen(value),
|
|
NULL, NULL, &result) != 0) {
|
|
ret = errno;
|
|
break;
|
|
}
|
|
|
|
if (result == 0) {
|
|
ret = 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
ldap_value_free_len(vals);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int ipadb_ldap_deref_results(LDAP *lcontext, LDAPMessage *le,
|
|
LDAPDerefRes **results)
|
|
{
|
|
LDAPControl **ctrls = NULL;
|
|
LDAPControl *derefctrl = NULL;
|
|
int ret;
|
|
|
|
ret = ldap_get_entry_controls(lcontext, le, &ctrls);
|
|
if (ret != LDAP_SUCCESS) {
|
|
return EINVAL;
|
|
}
|
|
|
|
if (!ctrls) {
|
|
return ENOENT;
|
|
}
|
|
|
|
derefctrl = ldap_control_find(LDAP_CONTROL_X_DEREF, ctrls, NULL);
|
|
if (!derefctrl) {
|
|
ret = ENOENT;
|
|
goto done;
|
|
}
|
|
|
|
ret = ldap_parse_derefresponse_control(lcontext, derefctrl, results);
|
|
if (ret) {
|
|
ret = EINVAL;
|
|
goto done;
|
|
}
|
|
|
|
ret = 0;
|
|
|
|
done:
|
|
ldap_controls_free(ctrls);
|
|
return ret;
|
|
}
|
|
|
|
struct ipadb_multires {
|
|
LDAP *lcontext;
|
|
LDAPMessage **res;
|
|
LDAPMessage *next;
|
|
ssize_t cursor;
|
|
ssize_t count;
|
|
};
|
|
|
|
krb5_error_code ipadb_multires_init(LDAP *lcontext, struct ipadb_multires **r)
|
|
{
|
|
*r = malloc(sizeof(struct ipadb_multires));
|
|
if (!*r) return ENOMEM;
|
|
(*r)->lcontext = lcontext;
|
|
(*r)->res = NULL;
|
|
(*r)->next = NULL;
|
|
(*r)->cursor = -1;
|
|
(*r)->count = 0;
|
|
|
|
return 0;
|
|
}
|
|
|
|
void ipadb_multires_free(struct ipadb_multires *r)
|
|
{
|
|
for (int i = 0; i < r->count; i++) {
|
|
ldap_msgfree(r->res[i]);
|
|
}
|
|
free(r);
|
|
}
|
|
|
|
LDAPMessage *ipadb_multires_next_entry(struct ipadb_multires *r)
|
|
{
|
|
if (r->count == 0) return NULL;
|
|
|
|
if (r->next) {
|
|
r->next = ldap_next_entry(r->lcontext, r->next);
|
|
}
|
|
if (r->next == NULL) {
|
|
if (r->cursor >= r->count - 1) {
|
|
return NULL;
|
|
}
|
|
r->cursor++;
|
|
r->next = ldap_first_entry(r->lcontext, r->res[r->cursor]);
|
|
}
|
|
|
|
return r->next;
|
|
}
|
|
|
|
krb5_error_code ipadb_multibase_search(struct ipadb_context *ipactx,
|
|
char **basedns, int scope,
|
|
char *filter, char **attrs,
|
|
struct ipadb_multires **res,
|
|
bool any)
|
|
{
|
|
int ret;
|
|
|
|
ret = ipadb_multires_init(ipactx->lcontext, res);
|
|
if (ret != 0) return ret;
|
|
|
|
ret = ipadb_check_connection(ipactx);
|
|
if (ret != 0)
|
|
return ipadb_simple_ldap_to_kerr(ret);
|
|
|
|
for (int b = 0; basedns[b]; b++) {
|
|
LDAPMessage *r;
|
|
ret = ldap_search_ext_s(ipactx->lcontext, basedns[b], scope,
|
|
filter, attrs, 0, NULL, NULL,
|
|
&std_timeout, LDAP_NO_LIMIT, &r);
|
|
|
|
/* first test if we need to retry to connect */
|
|
if (ret != 0 &&
|
|
ipadb_need_retry(ipactx, ret)) {
|
|
ldap_msgfree(r);
|
|
ret = ldap_search_ext_s(ipactx->lcontext, basedns[b], scope,
|
|
filter, attrs, 0, NULL, NULL,
|
|
&std_timeout, LDAP_NO_LIMIT, &r);
|
|
}
|
|
|
|
if (ret != 0) break;
|
|
|
|
if (ldap_count_entries(ipactx->lcontext, r) > 0) {
|
|
void *tmp = realloc((*res)->res, (((*res)->count + 1) *
|
|
sizeof(LDAPMessage *)));
|
|
if (tmp == NULL) {
|
|
ret = ENOMEM;
|
|
break;
|
|
}
|
|
(*res)->res = tmp;
|
|
(*res)->res[(*res)->count] = r;
|
|
(*res)->count++;
|
|
|
|
if (any) break;
|
|
}
|
|
}
|
|
|
|
if (ret != 0) {
|
|
ipadb_multires_free(*res);
|
|
*res = NULL;
|
|
}
|
|
|
|
return ipadb_simple_ldap_to_kerr(ret);
|
|
}
|
|
|