|
Packit |
6bd9ab |
/*
|
|
Packit |
6bd9ab |
myldap.c - simple interface to do LDAP requests
|
|
Packit |
6bd9ab |
Parts of this file were part of the nss_ldap library (as ldap-nss.c)
|
|
Packit |
6bd9ab |
which has been forked into the nss-pam-ldapd library.
|
|
Packit |
6bd9ab |
|
|
Packit |
6bd9ab |
Copyright (C) 1997-2006 Luke Howard
|
|
Packit |
6bd9ab |
Copyright (C) 2006-2007 West Consulting
|
|
Packit |
6bd9ab |
Copyright (C) 2006-2017 Arthur de Jong
|
|
Packit |
6bd9ab |
|
|
Packit |
6bd9ab |
This library is free software; you can redistribute it and/or
|
|
Packit |
6bd9ab |
modify it under the terms of the GNU Lesser General Public
|
|
Packit |
6bd9ab |
License as published by the Free Software Foundation; either
|
|
Packit |
6bd9ab |
version 2.1 of the License, or (at your option) any later version.
|
|
Packit |
6bd9ab |
|
|
Packit |
6bd9ab |
This library is distributed in the hope that it will be useful,
|
|
Packit |
6bd9ab |
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
6bd9ab |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit |
6bd9ab |
Lesser General Public License for more details.
|
|
Packit |
6bd9ab |
|
|
Packit |
6bd9ab |
You should have received a copy of the GNU Lesser General Public
|
|
Packit |
6bd9ab |
License along with this library; if not, write to the Free Software
|
|
Packit |
6bd9ab |
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
|
Packit |
6bd9ab |
02110-1301 USA
|
|
Packit |
6bd9ab |
*/
|
|
Packit |
6bd9ab |
|
|
Packit |
6bd9ab |
/*
|
|
Packit |
6bd9ab |
This library expects to use an LDAP library to provide the real
|
|
Packit |
6bd9ab |
functionality and only provides a convenient wrapper.
|
|
Packit |
6bd9ab |
Some pointers for more information on the LDAP API:
|
|
Packit |
6bd9ab |
http://tools.ietf.org/id/draft-ietf-ldapext-ldap-c-api-05.txt
|
|
Packit |
6bd9ab |
http://www.mozilla.org/directory/csdk-docs/function.htm
|
|
Packit |
6bd9ab |
http://publib.boulder.ibm.com/infocenter/iseries/v5r3/topic/apis/dirserv1.htm
|
|
Packit |
6bd9ab |
http://www.openldap.org/software/man.cgi?query=ldap
|
|
Packit |
6bd9ab |
*/
|
|
Packit |
6bd9ab |
|
|
Packit |
6bd9ab |
#include "config.h"
|
|
Packit |
6bd9ab |
|
|
Packit |
6bd9ab |
#include <stdio.h>
|
|
Packit |
6bd9ab |
#include <stdlib.h>
|
|
Packit |
6bd9ab |
#include <unistd.h>
|
|
Packit |
6bd9ab |
#include <string.h>
|
|
Packit |
6bd9ab |
#include <strings.h>
|
|
Packit |
6bd9ab |
#include <sys/time.h>
|
|
Packit |
6bd9ab |
#include <time.h>
|
|
Packit |
6bd9ab |
#include <sys/types.h>
|
|
Packit |
6bd9ab |
#include <sys/socket.h>
|
|
Packit |
6bd9ab |
#include <errno.h>
|
|
Packit |
6bd9ab |
#include <lber.h>
|
|
Packit |
6bd9ab |
#include <ldap.h>
|
|
Packit |
6bd9ab |
#ifdef HAVE_LDAP_SSL_H
|
|
Packit |
6bd9ab |
#include <ldap_ssl.h>
|
|
Packit |
6bd9ab |
#endif
|
|
Packit |
6bd9ab |
#ifdef HAVE_GSSLDAP_H
|
|
Packit |
6bd9ab |
#include <gssldap.h>
|
|
Packit |
6bd9ab |
#endif
|
|
Packit |
6bd9ab |
#ifdef HAVE_GSSSASL_H
|
|
Packit |
6bd9ab |
#include <gsssasl.h>
|
|
Packit |
6bd9ab |
#endif
|
|
Packit |
6bd9ab |
#ifdef HAVE_SASL_SASL_H
|
|
Packit |
6bd9ab |
#include <sasl/sasl.h>
|
|
Packit |
6bd9ab |
#endif
|
|
Packit |
6bd9ab |
#ifdef HAVE_SASL_H
|
|
Packit |
6bd9ab |
#include <sasl.h>
|
|
Packit |
6bd9ab |
#endif
|
|
Packit |
6bd9ab |
#include <ctype.h>
|
|
Packit |
6bd9ab |
#include <pthread.h>
|
|
Packit |
6bd9ab |
#include <stdarg.h>
|
|
Packit |
6bd9ab |
|
|
Packit |
6bd9ab |
#include "myldap.h"
|
|
Packit |
6bd9ab |
#include "common.h"
|
|
Packit |
6bd9ab |
#include "log.h"
|
|
Packit |
6bd9ab |
#include "cfg.h"
|
|
Packit |
6bd9ab |
#include "common/set.h"
|
|
Packit |
6bd9ab |
#include "compat/ldap_compat.h"
|
|
Packit |
6bd9ab |
#include "attmap.h"
|
|
Packit |
6bd9ab |
|
|
Packit |
6bd9ab |
/* the maximum number of searches per session */
|
|
Packit |
6bd9ab |
#define MAX_SEARCHES_IN_SESSION 4
|
|
Packit |
6bd9ab |
|
|
Packit |
6bd9ab |
/* the maximum number of dn's to log to the debug log for each search */
|
|
Packit |
6bd9ab |
#define MAX_DEBUG_LOG_DNS 10
|
|
Packit |
6bd9ab |
|
|
Packit |
6bd9ab |
/* a fake scope that is used to not perform an actual search but only
|
|
Packit |
6bd9ab |
simulate the handling of the search (used for authentication) */
|
|
Packit |
6bd9ab |
#define MYLDAP_SCOPE_BINDONLY 0x1972 /* magic number: should never be a real scope */
|
|
Packit |
6bd9ab |
|
|
Packit |
6bd9ab |
/* This refers to a current LDAP session that contains the connection
|
|
Packit |
6bd9ab |
information. */
|
|
Packit |
6bd9ab |
struct ldap_session {
|
|
Packit |
6bd9ab |
/* the connection */
|
|
Packit |
6bd9ab |
LDAP *ld;
|
|
Packit |
6bd9ab |
/* timestamp of last activity */
|
|
Packit |
6bd9ab |
time_t lastactivity;
|
|
Packit |
6bd9ab |
/* index into uris: currently connected LDAP uri */
|
|
Packit |
6bd9ab |
int current_uri;
|
|
Packit |
6bd9ab |
/* a list of searches registered with this session */
|
|
Packit |
6bd9ab |
struct myldap_search *searches[MAX_SEARCHES_IN_SESSION];
|
|
Packit |
6bd9ab |
/* the username to bind with */
|
|
Packit |
6bd9ab |
char binddn[BUFLEN_DN];
|
|
Packit |
6bd9ab |
/* the password to bind with if any */
|
|
Packit |
6bd9ab |
char bindpw[BUFLEN_PASSWORD];
|
|
Packit |
6bd9ab |
/* the authentication result (NSLCD_PAM_* code) */
|
|
Packit |
6bd9ab |
int policy_response;
|
|
Packit |
6bd9ab |
/* the authentication message */
|
|
Packit |
6bd9ab |
char policy_message[BUFLEN_MESSAGE];
|
|
Packit |
6bd9ab |
};
|
|
Packit |
6bd9ab |
|
|
Packit |
6bd9ab |
/* A search description set as returned by myldap_search(). */
|
|
Packit |
6bd9ab |
struct myldap_search {
|
|
Packit |
6bd9ab |
/* reference to the session */
|
|
Packit |
6bd9ab |
MYLDAP_SESSION *session;
|
|
Packit |
6bd9ab |
/* indicator that the search is still valid */
|
|
Packit |
6bd9ab |
int valid;
|
|
Packit |
6bd9ab |
/* the parameters descibing the search */
|
|
Packit |
6bd9ab |
const char *base;
|
|
Packit |
6bd9ab |
int scope;
|
|
Packit |
6bd9ab |
const char *filter;
|
|
Packit |
6bd9ab |
char **attrs;
|
|
Packit |
6bd9ab |
/* a pointer to the current result entry, used for
|
|
Packit |
6bd9ab |
freeing resource allocated with that entry */
|
|
Packit |
6bd9ab |
MYLDAP_ENTRY *entry;
|
|
Packit |
6bd9ab |
/* LDAP message id for the search, -1 indicates absense of an active search */
|
|
Packit |
6bd9ab |
int msgid;
|
|
Packit |
6bd9ab |
/* the last result that was returned by ldap_result() */
|
|
Packit |
6bd9ab |
LDAPMessage *msg;
|
|
Packit |
6bd9ab |
/* cookie for paged searches */
|
|
Packit |
6bd9ab |
struct berval *cookie;
|
|
Packit |
6bd9ab |
/* to indicate that we can retry the search from myldap_get_entry() */
|
|
Packit |
6bd9ab |
int may_retry_search;
|
|
Packit |
6bd9ab |
/* the number of resutls returned so far */
|
|
Packit |
6bd9ab |
int count;
|
|
Packit |
6bd9ab |
};
|
|
Packit |
6bd9ab |
|
|
Packit |
6bd9ab |
/* The maximum number of calls to myldap_get_values() that may be
|
|
Packit |
6bd9ab |
done per returned entry. */
|
|
Packit |
6bd9ab |
#define MAX_ATTRIBUTES_PER_ENTRY 16
|
|
Packit |
6bd9ab |
|
|
Packit |
6bd9ab |
/* The maximum number of buffers (used for ranged attribute values and
|
|
Packit |
6bd9ab |
values returned by bervalues_to_values()) that may be stored per entry. */
|
|
Packit |
6bd9ab |
#define MAX_BUFFERS_PER_ENTRY 8
|
|
Packit |
6bd9ab |
|
|
Packit |
6bd9ab |
/* A single entry from the LDAP database as returned by
|
|
Packit |
6bd9ab |
myldap_get_entry(). */
|
|
Packit |
6bd9ab |
struct myldap_entry {
|
|
Packit |
6bd9ab |
/* reference to the search to be used to get parameters
|
|
Packit |
6bd9ab |
(e.g. LDAP connection) for other calls */
|
|
Packit |
6bd9ab |
MYLDAP_SEARCH *search;
|
|
Packit |
6bd9ab |
/* the DN */
|
|
Packit |
6bd9ab |
const char *dn;
|
|
Packit |
6bd9ab |
/* a cached version of the exploded rdn */
|
|
Packit |
6bd9ab |
char **exploded_rdn;
|
|
Packit |
6bd9ab |
/* a cache of attribute to value list */
|
|
Packit |
6bd9ab |
char **attributevalues[MAX_ATTRIBUTES_PER_ENTRY];
|
|
Packit |
6bd9ab |
/* a reference to buffers so we can free() them later on */
|
|
Packit |
6bd9ab |
char **buffers[MAX_BUFFERS_PER_ENTRY];
|
|
Packit |
6bd9ab |
};
|
|
Packit |
6bd9ab |
|
|
Packit |
6bd9ab |
/* Flag to record first search operation */
|
|
Packit |
6bd9ab |
int first_search = 1;
|
|
Packit |
6bd9ab |
|
|
Packit |
6bd9ab |
static void myldap_err(int pri, LDAP *ld, int rc, const char *format, ...)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
char message[BUFLEN_MESSAGE];
|
|
Packit |
6bd9ab |
char *msg_ldap = NULL;
|
|
Packit |
6bd9ab |
char *msg_diag = NULL;
|
|
Packit |
6bd9ab |
char *msg_errno = NULL;
|
|
Packit |
6bd9ab |
va_list ap;
|
|
Packit |
6bd9ab |
/* make the message */
|
|
Packit |
6bd9ab |
va_start(ap, format);
|
|
Packit |
6bd9ab |
vsnprintf(message, sizeof(message), format, ap);
|
|
Packit |
6bd9ab |
message[sizeof(message) - 1] = '\0';
|
|
Packit |
6bd9ab |
va_end(ap);
|
|
Packit |
6bd9ab |
/* get the various error message */
|
|
Packit |
6bd9ab |
if (rc != LDAP_SUCCESS)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
msg_ldap = ldap_err2string(rc);
|
|
Packit |
6bd9ab |
/* get the diagnostic information */
|
|
Packit |
6bd9ab |
#ifdef LDAP_OPT_DIAGNOSTIC_MESSAGE
|
|
Packit |
6bd9ab |
if (ld != NULL)
|
|
Packit |
6bd9ab |
ldap_get_option(ld, LDAP_OPT_DIAGNOSTIC_MESSAGE, &msg_diag);
|
|
Packit |
6bd9ab |
#endif /* LDAP_OPT_DIAGNOSTIC_MESSAGE */
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
if (errno != 0)
|
|
Packit |
6bd9ab |
msg_errno = strerror(errno);
|
|
Packit |
6bd9ab |
/* log the message */
|
|
Packit |
6bd9ab |
log_log(pri, "%s%s%s%s%s%s%s", message,
|
|
Packit |
6bd9ab |
(msg_ldap == NULL) ? "" : ": ", (msg_ldap == NULL) ? "" : msg_ldap,
|
|
Packit |
6bd9ab |
(msg_diag == NULL) ? "" : ": ", (msg_diag == NULL) ? "" : msg_diag,
|
|
Packit |
6bd9ab |
(msg_errno == NULL) ? "" : ": ", (msg_errno == NULL) ? "" : msg_errno);
|
|
Packit |
6bd9ab |
/* free diagnostic message */
|
|
Packit |
6bd9ab |
if (msg_diag != NULL)
|
|
Packit |
6bd9ab |
ldap_memfree(msg_diag);
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
|
|
Packit |
6bd9ab |
static MYLDAP_ENTRY *myldap_entry_new(MYLDAP_SEARCH *search)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
MYLDAP_ENTRY *entry;
|
|
Packit |
6bd9ab |
int i;
|
|
Packit |
6bd9ab |
/* Note: as an alternative we could embed the myldap_entry into the
|
|
Packit |
6bd9ab |
myldap_search struct to save on malloc() and free() calls. */
|
|
Packit |
6bd9ab |
/* allocate new entry */
|
|
Packit |
6bd9ab |
entry = (MYLDAP_ENTRY *)malloc(sizeof(struct myldap_entry));
|
|
Packit |
6bd9ab |
if (entry == NULL)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
log_log(LOG_CRIT, "myldap_entry_new(): malloc() failed to allocate memory");
|
|
Packit |
6bd9ab |
exit(EXIT_FAILURE);
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
/* fill in fields */
|
|
Packit |
6bd9ab |
entry->search = search;
|
|
Packit |
6bd9ab |
entry->dn = NULL;
|
|
Packit |
6bd9ab |
entry->exploded_rdn = NULL;
|
|
Packit |
6bd9ab |
for (i = 0; i < MAX_ATTRIBUTES_PER_ENTRY; i++)
|
|
Packit |
6bd9ab |
entry->attributevalues[i] = NULL;
|
|
Packit |
6bd9ab |
for (i = 0; i < MAX_BUFFERS_PER_ENTRY; i++)
|
|
Packit |
6bd9ab |
entry->buffers[i] = NULL;
|
|
Packit |
6bd9ab |
/* return the fresh entry */
|
|
Packit |
6bd9ab |
return entry;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
|
|
Packit |
6bd9ab |
static void myldap_entry_free(MYLDAP_ENTRY *entry)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
int i;
|
|
Packit |
6bd9ab |
/* free the DN */
|
|
Packit |
6bd9ab |
if (entry->dn != NULL)
|
|
Packit |
6bd9ab |
ldap_memfree((char *)entry->dn);
|
|
Packit |
6bd9ab |
/* free the exploded RDN */
|
|
Packit |
6bd9ab |
if (entry->exploded_rdn != NULL)
|
|
Packit |
6bd9ab |
ldap_value_free(entry->exploded_rdn);
|
|
Packit |
6bd9ab |
/* free all attribute values */
|
|
Packit |
6bd9ab |
for (i = 0; i < MAX_ATTRIBUTES_PER_ENTRY; i++)
|
|
Packit |
6bd9ab |
if (entry->attributevalues[i] != NULL)
|
|
Packit |
6bd9ab |
ldap_value_free(entry->attributevalues[i]);
|
|
Packit |
6bd9ab |
/* free all buffers */
|
|
Packit |
6bd9ab |
for (i = 0; i < MAX_BUFFERS_PER_ENTRY; i++)
|
|
Packit |
6bd9ab |
if (entry->buffers[i] != NULL)
|
|
Packit |
6bd9ab |
free(entry->buffers[i]);
|
|
Packit |
6bd9ab |
/* we don't need the result anymore, ditch it. */
|
|
Packit |
6bd9ab |
ldap_msgfree(entry->search->msg);
|
|
Packit |
6bd9ab |
entry->search->msg = NULL;
|
|
Packit |
6bd9ab |
/* free the actual memory for the struct */
|
|
Packit |
6bd9ab |
free(entry);
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
|
|
Packit |
6bd9ab |
static MYLDAP_SEARCH *myldap_search_new(MYLDAP_SESSION *session,
|
|
Packit |
6bd9ab |
const char *base, int scope,
|
|
Packit |
6bd9ab |
const char *filter,
|
|
Packit |
6bd9ab |
const char **attrs)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
char *buffer;
|
|
Packit |
6bd9ab |
MYLDAP_SEARCH *search;
|
|
Packit |
6bd9ab |
int i;
|
|
Packit |
6bd9ab |
size_t sz;
|
|
Packit |
6bd9ab |
/* figure out size for new memory block to allocate
|
|
Packit |
6bd9ab |
this has the advantage that we can free the whole lot with one call */
|
|
Packit |
6bd9ab |
sz = sizeof(struct myldap_search);
|
|
Packit |
6bd9ab |
sz += strlen(base) + 1 + strlen(filter) + 1;
|
|
Packit |
6bd9ab |
for (i = 0; attrs[i] != NULL; i++)
|
|
Packit |
6bd9ab |
sz += strlen(attrs[i]) + 1;
|
|
Packit |
6bd9ab |
sz += (i + 1) * sizeof(char *);
|
|
Packit |
6bd9ab |
/* allocate new results memory region */
|
|
Packit |
6bd9ab |
buffer = (char *)malloc(sz);
|
|
Packit |
6bd9ab |
if (buffer == NULL)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
log_log(LOG_CRIT, "myldap_search_new(): malloc() failed to allocate memory");
|
|
Packit |
6bd9ab |
exit(EXIT_FAILURE);
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
/* initialize struct */
|
|
Packit |
6bd9ab |
search = (MYLDAP_SEARCH *)(void *)(buffer);
|
|
Packit |
6bd9ab |
buffer += sizeof(struct myldap_search);
|
|
Packit |
6bd9ab |
/* save pointer to session */
|
|
Packit |
6bd9ab |
search->session = session;
|
|
Packit |
6bd9ab |
/* flag as valid search */
|
|
Packit |
6bd9ab |
search->valid = 1;
|
|
Packit |
6bd9ab |
/* initialize array of attributes */
|
|
Packit |
6bd9ab |
search->attrs = (char **)(void *)buffer;
|
|
Packit |
6bd9ab |
buffer += (i + 1) * sizeof(char *);
|
|
Packit |
6bd9ab |
/* copy base */
|
|
Packit |
6bd9ab |
strcpy(buffer, base);
|
|
Packit |
6bd9ab |
search->base = buffer;
|
|
Packit |
6bd9ab |
buffer += strlen(base) + 1;
|
|
Packit |
6bd9ab |
/* just plainly store scope */
|
|
Packit |
6bd9ab |
search->scope = scope;
|
|
Packit |
6bd9ab |
/* copy filter */
|
|
Packit |
6bd9ab |
strcpy(buffer, filter);
|
|
Packit |
6bd9ab |
search->filter = buffer;
|
|
Packit |
6bd9ab |
buffer += strlen(filter) + 1;
|
|
Packit |
6bd9ab |
/* copy attributes themselves */
|
|
Packit |
6bd9ab |
for (i = 0; attrs[i] != NULL; i++)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
strcpy(buffer, attrs[i]);
|
|
Packit |
6bd9ab |
search->attrs[i] = buffer;
|
|
Packit |
6bd9ab |
buffer += strlen(attrs[i]) + 1;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
search->attrs[i] = NULL;
|
|
Packit |
6bd9ab |
/* initialize context */
|
|
Packit |
6bd9ab |
search->cookie = NULL;
|
|
Packit |
6bd9ab |
search->msg = NULL;
|
|
Packit |
6bd9ab |
search->msgid = -1;
|
|
Packit |
6bd9ab |
search->may_retry_search = 1;
|
|
Packit |
6bd9ab |
/* clear result entry */
|
|
Packit |
6bd9ab |
search->entry = NULL;
|
|
Packit |
6bd9ab |
search->count = 0;
|
|
Packit |
6bd9ab |
/* return the new search struct */
|
|
Packit |
6bd9ab |
return search;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
|
|
Packit |
6bd9ab |
static MYLDAP_SESSION *myldap_session_new(void)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
MYLDAP_SESSION *session;
|
|
Packit |
6bd9ab |
int i;
|
|
Packit |
6bd9ab |
/* allocate memory for the session storage */
|
|
Packit |
6bd9ab |
session = (struct ldap_session *)malloc(sizeof(struct ldap_session));
|
|
Packit |
6bd9ab |
if (session == NULL)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
log_log(LOG_CRIT, "myldap_session_new(): malloc() failed to allocate memory");
|
|
Packit |
6bd9ab |
exit(EXIT_FAILURE);
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
/* initialize the session */
|
|
Packit |
6bd9ab |
session->ld = NULL;
|
|
Packit |
6bd9ab |
session->lastactivity = 0;
|
|
Packit |
6bd9ab |
session->current_uri = 0;
|
|
Packit |
6bd9ab |
for (i = 0; i < MAX_SEARCHES_IN_SESSION; i++)
|
|
Packit |
6bd9ab |
session->searches[i] = NULL;
|
|
Packit |
6bd9ab |
session->binddn[0] = '\0';
|
|
Packit |
6bd9ab |
memset(session->bindpw, 0, sizeof(session->bindpw));
|
|
Packit |
6bd9ab |
session->bindpw[0] = '\0';
|
|
Packit |
6bd9ab |
session->policy_response = NSLCD_PAM_SUCCESS;
|
|
Packit |
6bd9ab |
session->policy_message[0] = '\0';
|
|
Packit |
6bd9ab |
/* return the new session */
|
|
Packit |
6bd9ab |
return session;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
|
|
Packit |
6bd9ab |
PURE static inline int is_valid_entry(MYLDAP_ENTRY *entry)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
return (entry != NULL) && (entry->search != NULL) &&
|
|
Packit |
6bd9ab |
(entry->search->session != NULL) && (entry->search->session->ld != NULL) &&
|
|
Packit |
6bd9ab |
(entry->search->msg != NULL);
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
|
|
Packit |
6bd9ab |
#ifdef HAVE_SASL_INTERACT_T
|
|
Packit |
6bd9ab |
/* this is registered with ldap_sasl_interactive_bind_s() in do_bind() */
|
|
Packit |
6bd9ab |
static int do_sasl_interact(LDAP UNUSED(*ld), unsigned UNUSED(flags),
|
|
Packit |
6bd9ab |
void *defaults, void *_interact)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
struct ldap_config *cfg = defaults;
|
|
Packit |
6bd9ab |
sasl_interact_t *interact = _interact;
|
|
Packit |
6bd9ab |
while (interact->id != SASL_CB_LIST_END)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
switch (interact->id)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
case SASL_CB_GETREALM:
|
|
Packit |
6bd9ab |
if (cfg->sasl_realm)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
log_log(LOG_DEBUG, "do_sasl_interact(): returning sasl_realm \"%s\"",
|
|
Packit |
6bd9ab |
cfg->sasl_realm);
|
|
Packit |
6bd9ab |
interact->result = cfg->sasl_realm;
|
|
Packit |
6bd9ab |
interact->len = strlen(cfg->sasl_realm);
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
else
|
|
Packit |
6bd9ab |
log_log(LOG_DEBUG, "do_sasl_interact(): were asked for sasl_realm but we don't have any");
|
|
Packit |
6bd9ab |
break;
|
|
Packit |
6bd9ab |
case SASL_CB_AUTHNAME:
|
|
Packit |
6bd9ab |
if (cfg->sasl_authcid)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
log_log(LOG_DEBUG, "do_sasl_interact(): returning sasl_authcid \"%s\"",
|
|
Packit |
6bd9ab |
cfg->sasl_authcid);
|
|
Packit |
6bd9ab |
interact->result = cfg->sasl_authcid;
|
|
Packit |
6bd9ab |
interact->len = strlen(cfg->sasl_authcid);
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
else
|
|
Packit |
6bd9ab |
log_log(LOG_DEBUG, "do_sasl_interact(): were asked for sasl_authcid but we don't have any");
|
|
Packit |
6bd9ab |
break;
|
|
Packit |
6bd9ab |
case SASL_CB_USER:
|
|
Packit |
6bd9ab |
if (cfg->sasl_authzid)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
log_log(LOG_DEBUG, "do_sasl_interact(): returning sasl_authzid \"%s\"",
|
|
Packit |
6bd9ab |
cfg->sasl_authzid);
|
|
Packit |
6bd9ab |
interact->result = cfg->sasl_authzid;
|
|
Packit |
6bd9ab |
interact->len = strlen(cfg->sasl_authzid);
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
else
|
|
Packit |
6bd9ab |
log_log(LOG_DEBUG, "do_sasl_interact(): were asked for sasl_authzid but we don't have any");
|
|
Packit |
6bd9ab |
break;
|
|
Packit |
6bd9ab |
case SASL_CB_PASS:
|
|
Packit |
6bd9ab |
if (cfg->bindpw)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
log_log(LOG_DEBUG, "do_sasl_interact(): returning bindpw \"***\"");
|
|
Packit |
6bd9ab |
interact->result = cfg->bindpw;
|
|
Packit |
6bd9ab |
interact->len = strlen(cfg->bindpw);
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
else
|
|
Packit |
6bd9ab |
log_log(LOG_DEBUG, "do_sasl_interact(): were asked for bindpw but we don't have any");
|
|
Packit |
6bd9ab |
break;
|
|
Packit |
6bd9ab |
default:
|
|
Packit |
6bd9ab |
/* just ignore */
|
|
Packit |
6bd9ab |
break;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
interact++;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
return LDAP_SUCCESS;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
#endif /* HAVE_SASL_INTERACT_T */
|
|
Packit |
6bd9ab |
|
|
Packit |
6bd9ab |
#define LDAP_SET_OPTION(ld, option, invalue) \
|
|
Packit |
6bd9ab |
rc = ldap_set_option(ld, option, invalue); \
|
|
Packit |
6bd9ab |
if (rc != LDAP_SUCCESS) \
|
|
Packit |
6bd9ab |
{ \
|
|
Packit |
6bd9ab |
myldap_err(LOG_ERR, ld, rc, "ldap_set_option(" #option ") failed"); \
|
|
Packit |
6bd9ab |
return rc; \
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
|
|
Packit |
6bd9ab |
#if defined(HAVE_LDAP_SASL_BIND) && defined(LDAP_SASL_SIMPLE)
|
|
Packit |
6bd9ab |
static void print_ppolicy_expiry(MYLDAP_SESSION *session, unsigned int sec)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
unsigned int days = 0;
|
|
Packit |
6bd9ab |
unsigned int hours = 0;
|
|
Packit |
6bd9ab |
unsigned int minutes = 0;
|
|
Packit |
6bd9ab |
/* return this warning so PAM can present it to the user */
|
|
Packit |
6bd9ab |
if (strlen(session->policy_message) != 0)
|
|
Packit |
6bd9ab |
return;
|
|
Packit |
6bd9ab |
if (sec > 24 * 3600)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
days = sec / (24 * 3600);
|
|
Packit |
6bd9ab |
sec -= days * 24 * 3600;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
if (sec > 3600)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
hours = sec / 3600;
|
|
Packit |
6bd9ab |
sec -= (hours * 3600);
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
if (sec > 60)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
minutes = sec / 60;
|
|
Packit |
6bd9ab |
sec -= minutes * 60;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
if (days > 1)
|
|
Packit |
6bd9ab |
mysnprintf(session->policy_message, sizeof(session->policy_message),
|
|
Packit |
6bd9ab |
"Password will expires in %u days", days);
|
|
Packit |
6bd9ab |
else if (days > 0)
|
|
Packit |
6bd9ab |
mysnprintf(session->policy_message, sizeof(session->policy_message),
|
|
Packit |
6bd9ab |
"Password will expires in %u hours", hours + 24);
|
|
Packit |
6bd9ab |
else if (hours > 1)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
if (minutes > 1)
|
|
Packit |
6bd9ab |
mysnprintf(session->policy_message, sizeof(session->policy_message),
|
|
Packit |
6bd9ab |
"Password will expires in %u hours and %u minutes",
|
|
Packit |
6bd9ab |
hours, minutes);
|
|
Packit |
6bd9ab |
else
|
|
Packit |
6bd9ab |
mysnprintf(session->policy_message, sizeof(session->policy_message),
|
|
Packit |
6bd9ab |
"Password will expires in %u hours", hours);
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
else if (hours > 0)
|
|
Packit |
6bd9ab |
mysnprintf(session->policy_message, sizeof(session->policy_message),
|
|
Packit |
6bd9ab |
"Password will expires in %u minutes", minutes + 60);
|
|
Packit |
6bd9ab |
else if (minutes > 1)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
if (sec > 1)
|
|
Packit |
6bd9ab |
mysnprintf(session->policy_message, sizeof(session->policy_message),
|
|
Packit |
6bd9ab |
"Password will expires in %u minutes and %u seconds",
|
|
Packit |
6bd9ab |
minutes, sec);
|
|
Packit |
6bd9ab |
else
|
|
Packit |
6bd9ab |
mysnprintf(session->policy_message, sizeof(session->policy_message),
|
|
Packit |
6bd9ab |
"Password will expires in %u minutes", minutes);
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
else
|
|
Packit |
6bd9ab |
mysnprintf(session->policy_message, sizeof(session->policy_message),
|
|
Packit |
6bd9ab |
"Password will expires in %u seconds", sec);
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
|
|
Packit |
6bd9ab |
static void handle_ppolicy_controls(MYLDAP_SESSION *session, LDAP *ld, LDAPControl **ctrls)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
int i;
|
|
Packit |
6bd9ab |
int rc;
|
|
Packit |
6bd9ab |
/* clear policy response information in session */
|
|
Packit |
6bd9ab |
session->policy_response = NSLCD_PAM_SUCCESS;
|
|
Packit |
6bd9ab |
strncpy(session->policy_message, "", sizeof(session->policy_message));
|
|
Packit |
6bd9ab |
for (i = 0; ctrls[i] != NULL; i++)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
if (strcmp(ctrls[i]->ldctl_oid, LDAP_CONTROL_PWEXPIRED) == 0)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
/* check for expired control: force the user to change their password */
|
|
Packit |
6bd9ab |
log_log(LOG_DEBUG, "got LDAP_CONTROL_PWEXPIRED (password expired, user should change)");
|
|
Packit |
6bd9ab |
if (session->policy_response == NSLCD_PAM_SUCCESS)
|
|
Packit |
6bd9ab |
session->policy_response = NSLCD_PAM_NEW_AUTHTOK_REQD;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
else if (strcmp(ctrls[i]->ldctl_oid, LDAP_CONTROL_PWEXPIRING) == 0)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
/* check for password expiration warning control: the password is about
|
|
Packit |
6bd9ab |
to expire (returns the number of seconds remaining until the password
|
|
Packit |
6bd9ab |
expires) */
|
|
Packit |
6bd9ab |
char seconds[32];
|
|
Packit |
6bd9ab |
long int sec;
|
|
Packit |
6bd9ab |
mysnprintf(seconds, sizeof(seconds), "%.*s", (int)ctrls[i]->ldctl_value.bv_len,
|
|
Packit |
6bd9ab |
ctrls[i]->ldctl_value.bv_val);
|
|
Packit |
6bd9ab |
sec = atol(seconds);
|
|
Packit |
6bd9ab |
log_log(LOG_DEBUG, "got LDAP_CONTROL_PWEXPIRING (password will expire in %ld seconds)",
|
|
Packit |
6bd9ab |
sec);
|
|
Packit |
6bd9ab |
print_ppolicy_expiry(session, (unsigned int)sec);
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
else if (strcmp(ctrls[i]->ldctl_oid, LDAP_CONTROL_PASSWORDPOLICYRESPONSE) == 0)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
/* check for password policy control */
|
|
Packit |
6bd9ab |
int expire = 0, grace = 0;
|
|
Packit |
6bd9ab |
LDAPPasswordPolicyError error = -1;
|
|
Packit |
6bd9ab |
rc = ldap_parse_passwordpolicy_control(ld, ctrls[i], &expire, &grace, &error);
|
|
Packit |
6bd9ab |
if (rc != LDAP_SUCCESS)
|
|
Packit |
6bd9ab |
myldap_err(LOG_WARNING, ld, rc, "ldap_parse_passwordpolicy_control() failed (ignored)");
|
|
Packit |
6bd9ab |
else
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
/* log returned control information */
|
|
Packit |
6bd9ab |
log_log(LOG_DEBUG, "got LDAP_CONTROL_PASSWORDPOLICYRESPONSE (%s)",
|
|
Packit |
6bd9ab |
ldap_passwordpolicy_err2txt(error));
|
|
Packit |
6bd9ab |
if (expire >= 0)
|
|
Packit |
6bd9ab |
log_log(LOG_DEBUG, "got LDAP_CONTROL_PASSWORDPOLICYRESPONSE (password will expire in %d seconds)",
|
|
Packit |
6bd9ab |
expire);
|
|
Packit |
6bd9ab |
if (grace >= 0)
|
|
Packit |
6bd9ab |
log_log(LOG_DEBUG, "got LDAP_CONTROL_PASSWORDPOLICYRESPONSE (%d grace logins left)",
|
|
Packit |
6bd9ab |
grace);
|
|
Packit |
6bd9ab |
/* return this information to PAM */
|
|
Packit |
6bd9ab |
if ((error == PP_passwordExpired) &&
|
|
Packit |
6bd9ab |
((session->policy_response == NSLCD_PAM_SUCCESS) ||
|
|
Packit |
6bd9ab |
(session->policy_response == NSLCD_PAM_NEW_AUTHTOK_REQD)))
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
/* this means that the password has expired and must be reset */
|
|
Packit |
6bd9ab |
session->policy_response = NSLCD_PAM_NEW_AUTHTOK_REQD;
|
|
Packit |
6bd9ab |
mysnprintf(session->policy_message, sizeof(session->policy_message),
|
|
Packit |
6bd9ab |
"%s", ldap_passwordpolicy_err2txt(error));
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
else if ((error == PP_accountLocked) &&
|
|
Packit |
6bd9ab |
((session->policy_response == NSLCD_PAM_SUCCESS) ||
|
|
Packit |
6bd9ab |
(session->policy_response == NSLCD_PAM_NEW_AUTHTOK_REQD)))
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
/* this means that the account is locked and the user cannot log
|
|
Packit |
6bd9ab |
in (the bind probably failed already) */
|
|
Packit |
6bd9ab |
session->policy_response = NSLCD_PAM_ACCT_EXPIRED;
|
|
Packit |
6bd9ab |
mysnprintf(session->policy_message, sizeof(session->policy_message),
|
|
Packit |
6bd9ab |
"%s", ldap_passwordpolicy_err2txt(error));
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
else if ((error == PP_changeAfterReset) &&
|
|
Packit |
6bd9ab |
(session->policy_response == NSLCD_PAM_SUCCESS))
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
/* this indicates that the password must be changed before the
|
|
Packit |
6bd9ab |
user is allowed to perform any other operation */
|
|
Packit |
6bd9ab |
session->policy_response = NSLCD_PAM_NEW_AUTHTOK_REQD;
|
|
Packit |
6bd9ab |
mysnprintf(session->policy_message, sizeof(session->policy_message),
|
|
Packit |
6bd9ab |
"%s", ldap_passwordpolicy_err2txt(error));
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
else if ((error != PP_noError) &&
|
|
Packit |
6bd9ab |
((session->policy_response == NSLCD_PAM_SUCCESS) ||
|
|
Packit |
6bd9ab |
(session->policy_response == NSLCD_PAM_NEW_AUTHTOK_REQD)))
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
/* any other error is assumed to mean that the operation failed */
|
|
Packit |
6bd9ab |
session->policy_response = NSLCD_PAM_PERM_DENIED;
|
|
Packit |
6bd9ab |
mysnprintf(session->policy_message, sizeof(session->policy_message),
|
|
Packit |
6bd9ab |
"%s", ldap_passwordpolicy_err2txt(error));
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
/* both expire and grace should just be warnings to the user */
|
|
Packit |
6bd9ab |
if ((expire >= 0) && (strlen(session->policy_message) == 0))
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
/* if no other error has happened, this indicates that the password
|
|
Packit |
6bd9ab |
will soon expire (number of seconds) */
|
|
Packit |
6bd9ab |
print_ppolicy_expiry(session, (unsigned int)expire);
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
else if ((grace >= 0) && (strlen(session->policy_message) == 0))
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
/* this indicates the number of grace logins that are left before
|
|
Packit |
6bd9ab |
no further login attempts will be allowed */
|
|
Packit |
6bd9ab |
mysnprintf(session->policy_message, sizeof(session->policy_message),
|
|
Packit |
6bd9ab |
"Password expired, %d grace logins left", grace);
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
/* ignore any other controls */
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
|
|
Packit |
6bd9ab |
static int do_ppolicy_bind(MYLDAP_SESSION *session, LDAP *ld, const char *uri)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
int rc, parserc;
|
|
Packit |
6bd9ab |
struct berval cred;
|
|
Packit |
6bd9ab |
LDAPControl passwd_policy_req;
|
|
Packit |
6bd9ab |
LDAPControl *requestctrls[2];
|
|
Packit |
6bd9ab |
LDAPControl **responsectrls;
|
|
Packit |
6bd9ab |
int msgid;
|
|
Packit |
6bd9ab |
struct timeval timeout;
|
|
Packit |
6bd9ab |
LDAPMessage *result;
|
|
Packit |
6bd9ab |
/* build policy request if pam_authc_ppolicy is set */
|
|
Packit |
6bd9ab |
if (nslcd_cfg->pam_authc_ppolicy)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
passwd_policy_req.ldctl_oid = LDAP_CONTROL_PASSWORDPOLICYREQUEST;
|
|
Packit |
6bd9ab |
passwd_policy_req.ldctl_value.bv_val = NULL; /* none */
|
|
Packit |
6bd9ab |
passwd_policy_req.ldctl_value.bv_len = 0;
|
|
Packit |
6bd9ab |
passwd_policy_req.ldctl_iscritical = 0; /* not critical */
|
|
Packit |
6bd9ab |
requestctrls[0] = &passwd_policy_req;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
else
|
|
Packit |
6bd9ab |
requestctrls[0] = NULL;
|
|
Packit |
6bd9ab |
requestctrls[1] = NULL;
|
|
Packit |
6bd9ab |
/* build password berval */
|
|
Packit |
6bd9ab |
cred.bv_val = (char *)session->bindpw;
|
|
Packit |
6bd9ab |
cred.bv_len = strlen(session->bindpw);
|
|
Packit |
6bd9ab |
/* do a SASL simple bind with the binddn and bindpw */
|
|
Packit |
6bd9ab |
log_log(LOG_DEBUG, "ldap_sasl_bind(\"%s\",%s) (uri=\"%s\") (ppolicy=%s)",
|
|
Packit |
6bd9ab |
session->binddn, (session->bindpw[0] != '\0') ? "\"***\"" : "\"\"",
|
|
Packit |
6bd9ab |
uri, (requestctrls[0] == NULL) ? "no" : "yes");
|
|
Packit |
6bd9ab |
rc = ldap_sasl_bind(ld, session->binddn, LDAP_SASL_SIMPLE, &cred, requestctrls, NULL, &msgid);
|
|
Packit |
6bd9ab |
if (rc != LDAP_SUCCESS)
|
|
Packit |
6bd9ab |
return rc;
|
|
Packit |
6bd9ab |
if (msgid == -1)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
myldap_err(LOG_WARNING, ld, rc,"ldap_sasl_bind() failed (msgid=-1, uri=%s)", uri);
|
|
Packit |
6bd9ab |
return LDAP_OPERATIONS_ERROR;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
/* get the result from the bind operation */
|
|
Packit |
6bd9ab |
timeout.tv_sec = nslcd_cfg->bind_timelimit;
|
|
Packit |
6bd9ab |
timeout.tv_usec = 0;
|
|
Packit |
6bd9ab |
result = NULL;
|
|
Packit |
6bd9ab |
rc = ldap_result(ld, msgid, LDAP_MSG_ALL, &timeout, &result);
|
|
Packit |
6bd9ab |
if (rc == -1) /* some error */
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
if (ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &rc) != LDAP_SUCCESS)
|
|
Packit |
6bd9ab |
rc = LDAP_UNAVAILABLE;
|
|
Packit |
6bd9ab |
myldap_err(LOG_ERR, ld, rc, "ldap_result() failed");
|
|
Packit |
6bd9ab |
if (result != NULL)
|
|
Packit |
6bd9ab |
ldap_msgfree(result);
|
|
Packit |
6bd9ab |
return LDAP_LOCAL_ERROR;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
if (rc == 0) /* the timeout expired */
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
log_log(LOG_ERR, "ldap_result() timed out");
|
|
Packit |
6bd9ab |
if (result != NULL)
|
|
Packit |
6bd9ab |
ldap_msgfree(result);
|
|
Packit |
6bd9ab |
return LDAP_TIMEOUT;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
responsectrls = NULL;
|
|
Packit |
6bd9ab |
/* ignore any response controls unless we're interested in ppolicy */
|
|
Packit |
6bd9ab |
if (nslcd_cfg->pam_authc_ppolicy)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
/* parse the result from the bind operation (frees result, gets controls) */
|
|
Packit |
6bd9ab |
parserc = ldap_parse_result(ld, result, &rc, NULL, NULL, NULL, &responsectrls, 1);
|
|
Packit |
6bd9ab |
if (parserc != LDAP_SUCCESS)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
myldap_err(LOG_ERR, ld, parserc, "ldap_parse_result() failed");
|
|
Packit |
6bd9ab |
if (responsectrls != NULL)
|
|
Packit |
6bd9ab |
ldap_controls_free(responsectrls);
|
|
Packit |
6bd9ab |
return parserc;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
/* handle any returned controls */
|
|
Packit |
6bd9ab |
if (responsectrls != NULL)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
handle_ppolicy_controls(session, ld, responsectrls);
|
|
Packit |
6bd9ab |
ldap_controls_free(responsectrls);
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
/* return the result of the BIND operation */
|
|
Packit |
6bd9ab |
if (rc != LDAP_SUCCESS)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
myldap_err(LOG_DEBUG, ld, rc, "ldap_parse_result() result");
|
|
Packit |
6bd9ab |
return rc;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
/* check the returned controls */
|
|
Packit |
6bd9ab |
return LDAP_SUCCESS;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
#endif /* no SASL, so no ppolicy */
|
|
Packit |
6bd9ab |
|
|
Packit |
6bd9ab |
/* This function performs the authentication phase of opening a connection.
|
|
Packit |
6bd9ab |
The binddn and bindpw parameters may be used to override the authentication
|
|
Packit |
6bd9ab |
mechanism defined in the configuration. This returns an LDAP result
|
|
Packit |
6bd9ab |
code. */
|
|
Packit |
6bd9ab |
static int do_bind(MYLDAP_SESSION *session, LDAP *ld, const char *uri)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
int rc;
|
|
Packit |
6bd9ab |
#ifdef HAVE_LDAP_SASL_INTERACTIVE_BIND_S
|
|
Packit |
6bd9ab |
#ifndef HAVE_SASL_INTERACT_T
|
|
Packit |
6bd9ab |
struct berval cred;
|
|
Packit |
6bd9ab |
#endif /* not HAVE_SASL_INTERACT_T */
|
|
Packit |
6bd9ab |
#endif /* HAVE_LDAP_SASL_INTERACTIVE_BIND_S */
|
|
Packit |
6bd9ab |
#ifdef LDAP_OPT_X_TLS
|
|
Packit |
6bd9ab |
/* check if StartTLS is requested */
|
|
Packit |
6bd9ab |
if (nslcd_cfg->ssl == SSL_START_TLS)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
log_log(LOG_DEBUG, "ldap_start_tls_s()");
|
|
Packit |
6bd9ab |
errno = 0;
|
|
Packit |
6bd9ab |
rc = ldap_start_tls_s(ld, NULL, NULL);
|
|
Packit |
6bd9ab |
if (rc != LDAP_SUCCESS)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
myldap_err(LOG_WARNING, ld, rc, "ldap_start_tls_s() failed (uri=%s)",
|
|
Packit |
6bd9ab |
uri);
|
|
Packit |
6bd9ab |
return rc;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
#endif /* LDAP_OPT_X_TLS */
|
|
Packit |
6bd9ab |
/* check if the binddn and bindpw are overwritten in the session */
|
|
Packit |
6bd9ab |
if (session->binddn[0] != '\0')
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
#if defined(HAVE_LDAP_SASL_BIND) && defined(LDAP_SASL_SIMPLE)
|
|
Packit |
6bd9ab |
return do_ppolicy_bind(session, ld, uri);
|
|
Packit |
6bd9ab |
#else /* no SASL, so no ppolicy */
|
|
Packit |
6bd9ab |
/* do a simple bind */
|
|
Packit |
6bd9ab |
log_log(LOG_DEBUG, "ldap_simple_bind_s(\"%s\",%s) (uri=\"%s\")",
|
|
Packit |
6bd9ab |
session->binddn,
|
|
Packit |
6bd9ab |
(session->bindpw[0] != '\0') ? "\"***\"" : "\"\"",
|
|
Packit |
6bd9ab |
uri);
|
|
Packit |
6bd9ab |
return ldap_simple_bind_s(ld, session->binddn, session->bindpw);
|
|
Packit |
6bd9ab |
#endif
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
/* perform SASL bind if requested and available on platform */
|
|
Packit |
6bd9ab |
#ifdef HAVE_LDAP_SASL_INTERACTIVE_BIND_S
|
|
Packit |
6bd9ab |
/* TODO: store this information in the session */
|
|
Packit |
6bd9ab |
if (nslcd_cfg->sasl_mech != NULL)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
/* do a SASL bind */
|
|
Packit |
6bd9ab |
if (nslcd_cfg->sasl_secprops != NULL)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
log_log(LOG_DEBUG, "ldap_set_option(LDAP_OPT_X_SASL_SECPROPS,\"%s\")",
|
|
Packit |
6bd9ab |
nslcd_cfg->sasl_secprops);
|
|
Packit |
6bd9ab |
LDAP_SET_OPTION(ld, LDAP_OPT_X_SASL_SECPROPS, (void *)nslcd_cfg->sasl_secprops);
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
#ifdef HAVE_SASL_INTERACT_T
|
|
Packit |
6bd9ab |
if (nslcd_cfg->binddn != NULL)
|
|
Packit |
6bd9ab |
log_log(LOG_DEBUG, "ldap_sasl_interactive_bind_s(\"%s\",\"%s\") (uri=\"%s\")",
|
|
Packit |
6bd9ab |
nslcd_cfg->binddn, nslcd_cfg->sasl_mech, uri);
|
|
Packit |
6bd9ab |
else
|
|
Packit |
6bd9ab |
log_log(LOG_DEBUG, "ldap_sasl_interactive_bind_s(NULL,\"%s\") (uri=\"%s\")",
|
|
Packit |
6bd9ab |
nslcd_cfg->sasl_mech, uri);
|
|
Packit |
6bd9ab |
return ldap_sasl_interactive_bind_s(ld, nslcd_cfg->binddn,
|
|
Packit |
6bd9ab |
nslcd_cfg->sasl_mech, NULL, NULL,
|
|
Packit |
6bd9ab |
LDAP_SASL_QUIET, do_sasl_interact,
|
|
Packit |
6bd9ab |
(void *)nslcd_cfg);
|
|
Packit |
6bd9ab |
#else /* HAVE_SASL_INTERACT_T */
|
|
Packit |
6bd9ab |
if (nslcd_cfg->bindpw != NULL)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
cred.bv_val = nslcd_cfg->bindpw;
|
|
Packit |
6bd9ab |
cred.bv_len = strlen(nslcd_cfg->bindpw);
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
else
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
cred.bv_val = "";
|
|
Packit |
6bd9ab |
cred.bv_len = 0;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
if (nslcd_cfg->binddn != NULL)
|
|
Packit |
6bd9ab |
log_log(LOG_DEBUG, "ldap_sasl_bind_s(\"%s\",\"%s\",%s) (uri=\"%s\")",
|
|
Packit |
6bd9ab |
nslcd_cfg->binddn, nslcd_cfg->sasl_mech,
|
|
Packit |
6bd9ab |
nslcd_cfg->bindpw ? "\"***\"" : "NULL", uri);
|
|
Packit |
6bd9ab |
else
|
|
Packit |
6bd9ab |
log_log(LOG_DEBUG, "ldap_sasl_bind_s(NULL,\"%s\",%s) (uri=\"%s\")",
|
|
Packit |
6bd9ab |
nslcd_cfg->sasl_mech,
|
|
Packit |
6bd9ab |
nslcd_cfg->bindpw ? "\"***\"" : "NULL", uri);
|
|
Packit |
6bd9ab |
return ldap_sasl_bind_s(ld, nslcd_cfg->binddn,
|
|
Packit |
6bd9ab |
nslcd_cfg->sasl_mech, &cred, NULL, NULL, NULL);
|
|
Packit |
6bd9ab |
#endif /* not HAVE_SASL_INTERACT_T */
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
#endif /* HAVE_LDAP_SASL_INTERACTIVE_BIND_S */
|
|
Packit |
6bd9ab |
/* do a simple bind */
|
|
Packit |
6bd9ab |
if (nslcd_cfg->binddn)
|
|
Packit |
6bd9ab |
log_log(LOG_DEBUG, "ldap_simple_bind_s(\"%s\",%s) (uri=\"%s\")",
|
|
Packit |
6bd9ab |
nslcd_cfg->binddn, nslcd_cfg->bindpw ? "\"***\"" : "NULL",
|
|
Packit |
6bd9ab |
uri);
|
|
Packit |
6bd9ab |
else
|
|
Packit |
6bd9ab |
log_log(LOG_DEBUG, "ldap_simple_bind_s(NULL,%s) (uri=\"%s\")",
|
|
Packit |
6bd9ab |
nslcd_cfg->bindpw ? "\"***\"" : "NULL", uri);
|
|
Packit |
6bd9ab |
return ldap_simple_bind_s(ld, nslcd_cfg->binddn, nslcd_cfg->bindpw);
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
|
|
Packit |
6bd9ab |
#ifdef HAVE_LDAP_SET_REBIND_PROC
|
|
Packit |
6bd9ab |
/* This function is called by the LDAP library when chasing referrals.
|
|
Packit |
6bd9ab |
It is configured with the ldap_set_rebind_proc() below. */
|
|
Packit |
6bd9ab |
#if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
|
|
Packit |
6bd9ab |
static int do_rebind(LDAP *ld, LDAP_CONST char *url,
|
|
Packit |
6bd9ab |
ber_tag_t UNUSED(request),
|
|
Packit |
6bd9ab |
ber_int_t UNUSED(msgid), void *arg)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
MYLDAP_SESSION *session = (MYLDAP_SESSION *)arg;
|
|
Packit |
6bd9ab |
log_log(LOG_DEBUG, "rebinding to %s", url);
|
|
Packit |
6bd9ab |
return do_bind(session, ld, url);
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
#else /* not recent OpenLDAP */
|
|
Packit |
6bd9ab |
static int do_rebind(LDAP *ld, char **dnp, char **passwdp, int *authmethodp,
|
|
Packit |
6bd9ab |
int freeit, void *arg)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
MYLDAP_SESSION *session = (MYLDAP_SESSION *)arg;
|
|
Packit |
6bd9ab |
if (freeit)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
free(*dnp);
|
|
Packit |
6bd9ab |
memset(*passwdp, 0, strlen(*passwdp));
|
|
Packit |
6bd9ab |
free(*passwdp);
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
else
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
log_log(LOG_DEBUG, "rebinding");
|
|
Packit |
6bd9ab |
*dnp = strdup(session->binddn);
|
|
Packit |
6bd9ab |
*passwdp = strdup(session->bindpw);
|
|
Packit |
6bd9ab |
*authmethodp = LDAP_AUTH_SIMPLE;
|
|
Packit |
6bd9ab |
if ((*dnp == NULL) || (*passwdp == NULL))
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
if (*dnp != NULL)
|
|
Packit |
6bd9ab |
free(*dnp);
|
|
Packit |
6bd9ab |
log_log(LOG_CRIT, "do_rebind(): strdup() failed to allocate memory");
|
|
Packit |
6bd9ab |
return LDAP_NO_MEMORY;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
return LDAP_SUCCESS;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
#endif /* not recent OpenLDAP */
|
|
Packit |
6bd9ab |
#endif /* HAVE_LDAP_SET_REBIND_PROC */
|
|
Packit |
6bd9ab |
|
|
Packit |
6bd9ab |
/* set a recieve and send timeout on a socket */
|
|
Packit |
6bd9ab |
static int set_socket_timeout(LDAP *ld, time_t sec, suseconds_t usec)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
struct timeval tv;
|
|
Packit |
6bd9ab |
int rc = LDAP_SUCCESS;
|
|
Packit |
6bd9ab |
int sd;
|
|
Packit |
6bd9ab |
log_log(LOG_DEBUG, "set_socket_timeout(%lu,%lu)",
|
|
Packit |
6bd9ab |
(unsigned long)sec, (unsigned long)usec);
|
|
Packit |
6bd9ab |
/* get the socket */
|
|
Packit |
6bd9ab |
if ((rc = ldap_get_option(ld, LDAP_OPT_DESC, &sd)) != LDAP_SUCCESS)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
myldap_err(LOG_ERR, ld, rc, "ldap_get_option(LDAP_OPT_DESC) failed");
|
|
Packit |
6bd9ab |
return rc;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
/* ignore invalid (probably closed) file descriptors */
|
|
Packit |
6bd9ab |
if (sd <= 0)
|
|
Packit |
6bd9ab |
return LDAP_SUCCESS;
|
|
Packit |
6bd9ab |
/* set timeouts */
|
|
Packit |
6bd9ab |
memset(&tv, 0, sizeof(tv));
|
|
Packit |
6bd9ab |
tv.tv_sec = sec;
|
|
Packit |
6bd9ab |
tv.tv_usec = usec;
|
|
Packit |
6bd9ab |
if (setsockopt(sd, SOL_SOCKET, SO_RCVTIMEO, (void *)&tv, sizeof(tv)))
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
log_log(LOG_ERR, "setsockopt(%d,SO_RCVTIMEO) failed: %s",
|
|
Packit |
6bd9ab |
sd, strerror(errno));
|
|
Packit |
6bd9ab |
rc = LDAP_LOCAL_ERROR;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
if (setsockopt(sd, SOL_SOCKET, SO_SNDTIMEO, (void *)&tv, sizeof(tv)))
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
log_log(LOG_ERR, "setsockopt(%d,SO_RCVTIMEO) failed: %s",
|
|
Packit |
6bd9ab |
sd, strerror(errno));
|
|
Packit |
6bd9ab |
rc = LDAP_LOCAL_ERROR;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
return rc;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
|
|
Packit |
6bd9ab |
#ifdef LDAP_OPT_CONNECT_CB
|
|
Packit |
6bd9ab |
/* This function is called by the LDAP library once a connection was made to the server. We
|
|
Packit |
6bd9ab |
set a timeout on the socket here, to catch network timeouts during the ssl
|
|
Packit |
6bd9ab |
handshake phase. It is configured with LDAP_OPT_CONNECT_CB. */
|
|
Packit |
6bd9ab |
static int connect_cb(LDAP *ld, Sockbuf UNUSED(*sb),
|
|
Packit |
6bd9ab |
LDAPURLDesc UNUSED(*srv), struct sockaddr UNUSED(*addr),
|
|
Packit |
6bd9ab |
struct ldap_conncb UNUSED(*ctx))
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
/* set timeout options on socket to avoid hang in some cases (a little
|
|
Packit |
6bd9ab |
more than the normal timeout so this should only be triggered in cases
|
|
Packit |
6bd9ab |
where the library behaves incorrectly) */
|
|
Packit |
6bd9ab |
if (nslcd_cfg->timelimit)
|
|
Packit |
6bd9ab |
set_socket_timeout(ld, nslcd_cfg->timelimit, 500000);
|
|
Packit |
6bd9ab |
return LDAP_SUCCESS;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
|
|
Packit |
6bd9ab |
/* We have an empty disconnect callback because LDAP_OPT_CONNECT_CB expects
|
|
Packit |
6bd9ab |
both functions to be available. */
|
|
Packit |
6bd9ab |
static void disconnect_cb(LDAP UNUSED(*ld), Sockbuf UNUSED(*sb),
|
|
Packit |
6bd9ab |
struct ldap_conncb UNUSED(*ctx))
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
#endif /* LDAP_OPT_CONNECT_CB */
|
|
Packit |
6bd9ab |
|
|
Packit |
6bd9ab |
/* This function sets a number of properties on the connection, based
|
|
Packit |
6bd9ab |
what is configured in the configfile. This function returns an
|
|
Packit |
6bd9ab |
LDAP status code. */
|
|
Packit |
6bd9ab |
static int do_set_options(MYLDAP_SESSION *session)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
int rc;
|
|
Packit |
6bd9ab |
struct timeval tv;
|
|
Packit |
6bd9ab |
#ifdef LDAP_OPT_CONNECT_CB
|
|
Packit |
6bd9ab |
/* make this static because OpenLDAP doesn't make its own copy */
|
|
Packit |
6bd9ab |
static struct ldap_conncb cb;
|
|
Packit |
6bd9ab |
#endif /* LDAP_OPT_CONNECT_CB */
|
|
Packit |
6bd9ab |
#ifdef LDAP_OPT_X_TLS
|
|
Packit |
6bd9ab |
int i;
|
|
Packit |
6bd9ab |
#endif /* LDAP_OPT_X_TLS */
|
|
Packit |
6bd9ab |
#ifdef HAVE_LDAP_SET_REBIND_PROC
|
|
Packit |
6bd9ab |
/* the rebind function that is called when chasing referrals, see
|
|
Packit |
6bd9ab |
http://publib.boulder.ibm.com/infocenter/iseries/v5r3/topic/apis/ldap_set_rebind_proc.htm
|
|
Packit |
6bd9ab |
http://www.openldap.org/software/man.cgi?query=ldap_set_rebind_proc&manpath=OpenLDAP+2.4-Release */
|
|
Packit |
6bd9ab |
/* TODO: probably only set this if we should chase referrals */
|
|
Packit |
6bd9ab |
log_log(LOG_DEBUG, "ldap_set_rebind_proc()");
|
|
Packit |
6bd9ab |
#ifndef LDAP_SET_REBIND_PROC_RETURNS_VOID /* it returns int */
|
|
Packit |
6bd9ab |
rc = ldap_set_rebind_proc(session->ld, do_rebind, session);
|
|
Packit |
6bd9ab |
if (rc != LDAP_SUCCESS)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
myldap_err(LOG_ERR, session->ld, rc, "ldap_set_rebind_proc() failed");
|
|
Packit |
6bd9ab |
return rc;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
#else /* ldap_set_rebind_proc() returns void */
|
|
Packit |
6bd9ab |
ldap_set_rebind_proc(session->ld, do_rebind, session);
|
|
Packit |
6bd9ab |
#endif
|
|
Packit |
6bd9ab |
#endif /* HAVE_LDAP_SET_REBIND_PROC */
|
|
Packit |
6bd9ab |
/* set the protocol version to use */
|
|
Packit |
6bd9ab |
log_log(LOG_DEBUG, "ldap_set_option(LDAP_OPT_PROTOCOL_VERSION,%d)",
|
|
Packit |
6bd9ab |
nslcd_cfg->ldap_version);
|
|
Packit |
6bd9ab |
LDAP_SET_OPTION(session->ld, LDAP_OPT_PROTOCOL_VERSION,
|
|
Packit |
6bd9ab |
&nslcd_cfg->ldap_version);
|
|
Packit |
6bd9ab |
/* set some other options */
|
|
Packit |
6bd9ab |
log_log(LOG_DEBUG, "ldap_set_option(LDAP_OPT_DEREF,%d)",
|
|
Packit |
6bd9ab |
nslcd_cfg->deref);
|
|
Packit |
6bd9ab |
LDAP_SET_OPTION(session->ld, LDAP_OPT_DEREF, &nslcd_cfg->deref);
|
|
Packit |
6bd9ab |
log_log(LOG_DEBUG, "ldap_set_option(LDAP_OPT_TIMELIMIT,%d)",
|
|
Packit |
6bd9ab |
nslcd_cfg->timelimit);
|
|
Packit |
6bd9ab |
LDAP_SET_OPTION(session->ld, LDAP_OPT_TIMELIMIT, &nslcd_cfg->timelimit);
|
|
Packit |
6bd9ab |
tv.tv_sec = nslcd_cfg->bind_timelimit;
|
|
Packit |
6bd9ab |
tv.tv_usec = 0;
|
|
Packit |
6bd9ab |
#ifdef LDAP_OPT_TIMEOUT
|
|
Packit |
6bd9ab |
log_log(LOG_DEBUG, "ldap_set_option(LDAP_OPT_TIMEOUT,%d)",
|
|
Packit |
6bd9ab |
nslcd_cfg->timelimit);
|
|
Packit |
6bd9ab |
LDAP_SET_OPTION(session->ld, LDAP_OPT_TIMEOUT, &tv;;
|
|
Packit |
6bd9ab |
#endif /* LDAP_OPT_TIMEOUT */
|
|
Packit |
6bd9ab |
#ifdef LDAP_OPT_NETWORK_TIMEOUT
|
|
Packit |
6bd9ab |
log_log(LOG_DEBUG, "ldap_set_option(LDAP_OPT_NETWORK_TIMEOUT,%d)",
|
|
Packit |
6bd9ab |
nslcd_cfg->timelimit);
|
|
Packit |
6bd9ab |
LDAP_SET_OPTION(session->ld, LDAP_OPT_NETWORK_TIMEOUT, &tv;;
|
|
Packit |
6bd9ab |
#endif /* LDAP_OPT_NETWORK_TIMEOUT */
|
|
Packit |
6bd9ab |
#ifdef LDAP_X_OPT_CONNECT_TIMEOUT
|
|
Packit |
6bd9ab |
log_log(LOG_DEBUG, "ldap_set_option(LDAP_X_OPT_CONNECT_TIMEOUT,%d)",
|
|
Packit |
6bd9ab |
nslcd_cfg->timelimit);
|
|
Packit |
6bd9ab |
LDAP_SET_OPTION(session->ld, LDAP_X_OPT_CONNECT_TIMEOUT, &tv;;
|
|
Packit |
6bd9ab |
#endif /* LDAP_X_OPT_CONNECT_TIMEOUT */
|
|
Packit |
6bd9ab |
log_log(LOG_DEBUG, "ldap_set_option(LDAP_OPT_REFERRALS,%s)",
|
|
Packit |
6bd9ab |
nslcd_cfg->referrals ? "LDAP_OPT_ON" : "LDAP_OPT_OFF");
|
|
Packit |
6bd9ab |
LDAP_SET_OPTION(session->ld, LDAP_OPT_REFERRALS,
|
|
Packit |
6bd9ab |
nslcd_cfg->referrals ? LDAP_OPT_ON : LDAP_OPT_OFF);
|
|
Packit |
6bd9ab |
log_log(LOG_DEBUG, "ldap_set_option(LDAP_OPT_RESTART,LDAP_OPT_ON)");
|
|
Packit |
6bd9ab |
LDAP_SET_OPTION(session->ld, LDAP_OPT_RESTART, LDAP_OPT_ON);
|
|
Packit |
6bd9ab |
#ifdef LDAP_OPT_CONNECT_CB
|
|
Packit |
6bd9ab |
/* register a connection callback */
|
|
Packit |
6bd9ab |
cb.lc_add = connect_cb;
|
|
Packit |
6bd9ab |
cb.lc_del = disconnect_cb;
|
|
Packit |
6bd9ab |
cb.lc_arg = NULL;
|
|
Packit |
6bd9ab |
LDAP_SET_OPTION(session->ld, LDAP_OPT_CONNECT_CB, (void *)&cb;;
|
|
Packit |
6bd9ab |
#endif /* LDAP_OPT_CONNECT_CB */
|
|
Packit |
6bd9ab |
#ifdef LDAP_OPT_X_TLS
|
|
Packit |
6bd9ab |
/* if SSL is desired, then enable it */
|
|
Packit |
6bd9ab |
if ((nslcd_cfg->ssl == SSL_LDAPS) ||
|
|
Packit |
6bd9ab |
(strncasecmp(nslcd_cfg->uris[session->current_uri].uri, "ldaps://", 8) == 0))
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
/* use tls */
|
|
Packit |
6bd9ab |
i = LDAP_OPT_X_TLS_HARD;
|
|
Packit |
6bd9ab |
log_log(LOG_DEBUG, "ldap_set_option(LDAP_OPT_X_TLS,LDAP_OPT_X_TLS_HARD)");
|
|
Packit |
6bd9ab |
LDAP_SET_OPTION(session->ld, LDAP_OPT_X_TLS, &i);
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
#endif /* LDAP_OPT_X_TLS */
|
|
Packit |
6bd9ab |
#ifdef LDAP_OPT_X_SASL_NOCANON
|
|
Packit |
6bd9ab |
if (nslcd_cfg->sasl_canonicalize >= 0)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
log_log(LOG_DEBUG, "ldap_set_option(LDAP_OPT_X_SASL_NOCANON,%s)",
|
|
Packit |
6bd9ab |
nslcd_cfg->sasl_canonicalize ? "LDAP_OPT_OFF" : "LDAP_OPT_ON");
|
|
Packit |
6bd9ab |
LDAP_SET_OPTION(session->ld, LDAP_OPT_X_SASL_NOCANON,
|
|
Packit |
6bd9ab |
nslcd_cfg->sasl_canonicalize ? LDAP_OPT_OFF : LDAP_OPT_ON);
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
#endif /* LDAP_OPT_X_SASL_NOCANON */
|
|
Packit |
6bd9ab |
/* if nothing above failed, everything should be fine */
|
|
Packit |
6bd9ab |
return LDAP_SUCCESS;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
|
|
Packit |
6bd9ab |
/* close the connection to the server and invalidate any running searches */
|
|
Packit |
6bd9ab |
static void do_close(MYLDAP_SESSION *session)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
int i;
|
|
Packit |
6bd9ab |
int rc;
|
|
Packit |
6bd9ab |
time_t sec;
|
|
Packit |
6bd9ab |
/* if we had reachability problems with the server close the connection */
|
|
Packit |
6bd9ab |
if (session->ld != NULL)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
/* set timeout options on socket to avoid hang in some cases
|
|
Packit |
6bd9ab |
(we set a short timeout because we don't care too much about properly
|
|
Packit |
6bd9ab |
shutting down the connection) */
|
|
Packit |
6bd9ab |
if (nslcd_cfg->timelimit)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
sec = nslcd_cfg->timelimit / 2;
|
|
Packit |
6bd9ab |
if (!sec)
|
|
Packit |
6bd9ab |
sec = 1;
|
|
Packit |
6bd9ab |
set_socket_timeout(session->ld, sec, 0);
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
/* go over the other searches and partially close them */
|
|
Packit |
6bd9ab |
for (i = 0; i < MAX_SEARCHES_IN_SESSION; i++)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
if (session->searches[i] != NULL)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
/* free any messages (because later ld is no longer valid) */
|
|
Packit |
6bd9ab |
if (session->searches[i]->msg != NULL)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
ldap_msgfree(session->searches[i]->msg);
|
|
Packit |
6bd9ab |
session->searches[i]->msg = NULL;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
/* abandon the search if there were more results to fetch */
|
|
Packit |
6bd9ab |
if (session->searches[i]->msgid != -1)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
log_log(LOG_DEBUG, "ldap_abandon()");
|
|
Packit |
6bd9ab |
if (ldap_abandon(session->searches[i]->session->ld, session->searches[i]->msgid))
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
if (ldap_get_option(session->ld, LDAP_OPT_ERROR_NUMBER, &rc) != LDAP_SUCCESS)
|
|
Packit |
6bd9ab |
rc = LDAP_OTHER;
|
|
Packit |
6bd9ab |
myldap_err(LOG_WARNING, session->ld, rc,
|
|
Packit |
6bd9ab |
"ldap_abandon() failed to abandon search");
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
session->searches[i]->msgid = -1;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
/* flag the search as invalid */
|
|
Packit |
6bd9ab |
session->searches[i]->valid = 0;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
/* close the connection to the server */
|
|
Packit |
6bd9ab |
log_log(LOG_DEBUG, "ldap_unbind()");
|
|
Packit |
6bd9ab |
rc = ldap_unbind(session->ld);
|
|
Packit |
6bd9ab |
session->ld = NULL;
|
|
Packit |
6bd9ab |
if (rc != LDAP_SUCCESS)
|
|
Packit |
6bd9ab |
myldap_err(LOG_WARNING, session->ld, rc, "ldap_unbind() failed");
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
|
|
Packit |
6bd9ab |
void myldap_session_check(MYLDAP_SESSION *session)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
int i;
|
|
Packit |
6bd9ab |
time_t current_time;
|
|
Packit |
6bd9ab |
int sd;
|
|
Packit |
6bd9ab |
int rc;
|
|
Packit |
6bd9ab |
struct sockaddr sa;
|
|
Packit |
6bd9ab |
socklen_t salen = sizeof(sa);
|
|
Packit |
6bd9ab |
/* check parameters */
|
|
Packit |
6bd9ab |
if (session == NULL)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
log_log(LOG_ERR, "myldap_session_check(): invalid parameter passed");
|
|
Packit |
6bd9ab |
errno = EINVAL;
|
|
Packit |
6bd9ab |
return;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
if (session->ld != NULL)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
rc = ldap_get_option(session->ld, LDAP_OPT_DESC, &sd);
|
|
Packit |
6bd9ab |
if (rc != LDAP_SUCCESS)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
myldap_err(LOG_WARNING, session->ld, rc,
|
|
Packit |
6bd9ab |
"ldap_get_option(LDAP_OPT_DESC) failed (ignored)");
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
else
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
/* check if the connection was closed by the peer */
|
|
Packit |
6bd9ab |
if (getpeername(sd, &sa, &salen) == -1)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
if (errno == ENOTCONN)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
log_log(LOG_DEBUG, "myldap_session_check(): connection reset by peer");
|
|
Packit |
6bd9ab |
do_close(session);
|
|
Packit |
6bd9ab |
return;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
/* check if we should time out the connection */
|
|
Packit |
6bd9ab |
if (nslcd_cfg->idle_timelimit > 0)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
/* if we have any running searches, don't time out */
|
|
Packit |
6bd9ab |
for (i = 0; i < MAX_SEARCHES_IN_SESSION; i++)
|
|
Packit |
6bd9ab |
if ((session->searches[i] != NULL) && (session->searches[i]->valid))
|
|
Packit |
6bd9ab |
return;
|
|
Packit |
6bd9ab |
/* consider timeout (there are no running searches) */
|
|
Packit |
6bd9ab |
time(¤t_time);
|
|
Packit |
6bd9ab |
if ((session->lastactivity + nslcd_cfg->idle_timelimit) < current_time)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
log_log(LOG_DEBUG, "myldap_session_check(): idle_timelimit reached");
|
|
Packit |
6bd9ab |
do_close(session);
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
|
|
Packit |
6bd9ab |
/* This opens connection to an LDAP server, sets all connection options
|
|
Packit |
6bd9ab |
and binds to the server. This returns an LDAP status code. */
|
|
Packit |
6bd9ab |
static int do_open(MYLDAP_SESSION *session)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
int rc;
|
|
Packit |
6bd9ab |
/* if the connection is still there (ie. ldap_unbind() wasn't
|
|
Packit |
6bd9ab |
called) then we can return the cached connection */
|
|
Packit |
6bd9ab |
if (session->ld != NULL)
|
|
Packit |
6bd9ab |
return LDAP_SUCCESS;
|
|
Packit |
6bd9ab |
/* we should build a new session now */
|
|
Packit |
6bd9ab |
session->ld = NULL;
|
|
Packit |
6bd9ab |
session->lastactivity = 0;
|
|
Packit |
6bd9ab |
/* open the connection */
|
|
Packit |
6bd9ab |
log_log(LOG_DEBUG, "ldap_initialize(%s)",
|
|
Packit |
6bd9ab |
nslcd_cfg->uris[session->current_uri].uri);
|
|
Packit |
6bd9ab |
errno = 0;
|
|
Packit |
6bd9ab |
rc = ldap_initialize(&(session->ld), nslcd_cfg->uris[session->current_uri].uri);
|
|
Packit |
6bd9ab |
if (rc != LDAP_SUCCESS)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
myldap_err(LOG_WARNING, session->ld, rc, "ldap_initialize(%s) failed",
|
|
Packit |
6bd9ab |
nslcd_cfg->uris[session->current_uri].uri);
|
|
Packit |
6bd9ab |
if (session->ld != NULL)
|
|
Packit |
6bd9ab |
do_close(session);
|
|
Packit |
6bd9ab |
return rc;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
else if (session->ld == NULL)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
log_log(LOG_WARNING, "ldap_initialize() returned NULL");
|
|
Packit |
6bd9ab |
return LDAP_LOCAL_ERROR;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
/* set the options for the connection */
|
|
Packit |
6bd9ab |
rc = do_set_options(session);
|
|
Packit |
6bd9ab |
if (rc != LDAP_SUCCESS)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
do_close(session);
|
|
Packit |
6bd9ab |
return rc;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
/* bind to the server */
|
|
Packit |
6bd9ab |
errno = 0;
|
|
Packit |
6bd9ab |
rc = do_bind(session, session->ld, nslcd_cfg->uris[session->current_uri].uri);
|
|
Packit |
6bd9ab |
if (rc != LDAP_SUCCESS)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
/* log actual LDAP error code */
|
|
Packit |
6bd9ab |
myldap_err((session->binddn[0] == '\0') ? LOG_WARNING : LOG_DEBUG,
|
|
Packit |
6bd9ab |
session->ld, rc, "failed to bind to LDAP server %s",
|
|
Packit |
6bd9ab |
nslcd_cfg->uris[session->current_uri].uri);
|
|
Packit |
6bd9ab |
do_close(session);
|
|
Packit |
6bd9ab |
return rc;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
/* update last activity and finish off state */
|
|
Packit |
6bd9ab |
time(&(session->lastactivity));
|
|
Packit |
6bd9ab |
return LDAP_SUCCESS;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
|
|
Packit |
6bd9ab |
/* Perform a simple bind operation and return the ppolicy results. */
|
|
Packit |
6bd9ab |
int myldap_bind(MYLDAP_SESSION *session, const char *dn, const char *password,
|
|
Packit |
6bd9ab |
int *response, const char **message)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
MYLDAP_SEARCH *search;
|
|
Packit |
6bd9ab |
static const char *attrs[2];
|
|
Packit |
6bd9ab |
int rc;
|
|
Packit |
6bd9ab |
/* error out when buffers are too small */
|
|
Packit |
6bd9ab |
if (strlen(dn) >= sizeof(session->binddn))
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
log_log(LOG_ERR, "myldap_bind(): binddn buffer too small (%lu required)",
|
|
Packit |
6bd9ab |
(unsigned long) strlen(dn));
|
|
Packit |
6bd9ab |
return LDAP_LOCAL_ERROR;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
if (strlen(password) >= sizeof(session->bindpw))
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
log_log(LOG_ERR, "myldap_bind(): bindpw buffer too small (%lu required)",
|
|
Packit |
6bd9ab |
(unsigned long) strlen(password));
|
|
Packit |
6bd9ab |
return LDAP_LOCAL_ERROR;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
/* copy dn and password into session */
|
|
Packit |
6bd9ab |
strncpy(session->binddn, dn, sizeof(session->binddn));
|
|
Packit |
6bd9ab |
session->binddn[sizeof(session->binddn) - 1] = '\0';
|
|
Packit |
6bd9ab |
strncpy(session->bindpw, password, sizeof(session->bindpw));
|
|
Packit |
6bd9ab |
session->bindpw[sizeof(session->bindpw) - 1] = '\0';
|
|
Packit |
6bd9ab |
/* construct a fake search to trigger the BIND operation */
|
|
Packit |
6bd9ab |
attrs[0] = "dn";
|
|
Packit |
6bd9ab |
attrs[1] = NULL;
|
|
Packit |
6bd9ab |
search = myldap_search(session, session->binddn, MYLDAP_SCOPE_BINDONLY,
|
|
Packit |
6bd9ab |
"(objectClass=*)", attrs, &rc);
|
|
Packit |
6bd9ab |
if (search != NULL)
|
|
Packit |
6bd9ab |
myldap_search_close(search);
|
|
Packit |
6bd9ab |
/* return ppolicy results */
|
|
Packit |
6bd9ab |
if (response != NULL)
|
|
Packit |
6bd9ab |
*response = session->policy_response;
|
|
Packit |
6bd9ab |
if (message != NULL)
|
|
Packit |
6bd9ab |
*message = session->policy_message;
|
|
Packit |
6bd9ab |
return rc;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
|
|
Packit |
6bd9ab |
/* perform a search operation, the connection is assumed to be open */
|
|
Packit |
6bd9ab |
static int do_try_search(MYLDAP_SEARCH *search)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
int ctrlidx = 0;
|
|
Packit |
6bd9ab |
int rc;
|
|
Packit |
6bd9ab |
LDAPControl *serverctrls[3];
|
|
Packit |
6bd9ab |
#ifdef HAVE_LDAP_CREATE_DEREF_CONTROL
|
|
Packit |
6bd9ab |
int i;
|
|
Packit |
6bd9ab |
struct LDAPDerefSpec ds[2];
|
|
Packit |
6bd9ab |
char *deref_attrs[2];
|
|
Packit |
6bd9ab |
#endif /* HAVE_LDAP_CREATE_DEREF_CONTROL */
|
|
Packit |
6bd9ab |
int msgid;
|
|
Packit |
6bd9ab |
/* if we're using paging, build a page control */
|
|
Packit |
6bd9ab |
if ((nslcd_cfg->pagesize > 0) && (search->scope != LDAP_SCOPE_BASE))
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
rc = ldap_create_page_control(search->session->ld, nslcd_cfg->pagesize,
|
|
Packit |
6bd9ab |
search->cookie, 0, &serverctrls[ctrlidx]);
|
|
Packit |
6bd9ab |
if (rc == LDAP_SUCCESS)
|
|
Packit |
6bd9ab |
ctrlidx++;
|
|
Packit |
6bd9ab |
else
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
myldap_err(LOG_WARNING, search->session->ld, rc,
|
|
Packit |
6bd9ab |
"ldap_create_page_control() failed");
|
|
Packit |
6bd9ab |
serverctrls[ctrlidx] = NULL;
|
|
Packit |
6bd9ab |
/* if we were paging, failure building the second control is fatal */
|
|
Packit |
6bd9ab |
if (search->cookie != NULL)
|
|
Packit |
6bd9ab |
return rc;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
#ifdef HAVE_LDAP_CREATE_DEREF_CONTROL
|
|
Packit |
6bd9ab |
/* if doing group searches, add deref control to search request
|
|
Packit |
6bd9ab |
(this is currently a bit of a hack and hard-coded for group searches
|
|
Packit |
6bd9ab |
which are detected by requesting the attmap_group_member member
|
|
Packit |
6bd9ab |
attribute) */
|
|
Packit |
6bd9ab |
for (i = 0; search->attrs[i] != NULL; i++)
|
|
Packit |
6bd9ab |
if (strcasecmp(search->attrs[i], attmap_group_member) == 0)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
/* attributes from dereff'd entries */
|
|
Packit |
6bd9ab |
deref_attrs[0] = (void *)attmap_passwd_uid;
|
|
Packit |
6bd9ab |
deref_attrs[1] = NULL;
|
|
Packit |
6bd9ab |
/* build deref control */
|
|
Packit |
6bd9ab |
ds[0].derefAttr = (void *)attmap_group_member;
|
|
Packit |
6bd9ab |
ds[0].attributes = deref_attrs;
|
|
Packit |
6bd9ab |
ds[1].derefAttr = NULL;
|
|
Packit |
6bd9ab |
ds[1].attributes = NULL;
|
|
Packit |
6bd9ab |
rc = ldap_create_deref_control(search->session->ld, ds, 0, &serverctrls[ctrlidx]);
|
|
Packit |
6bd9ab |
if (rc == LDAP_SUCCESS)
|
|
Packit |
6bd9ab |
ctrlidx++;
|
|
Packit |
6bd9ab |
else
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
myldap_err(LOG_WARNING, search->session->ld, rc,
|
|
Packit |
6bd9ab |
"ldap_create_deref_control() failed");
|
|
Packit |
6bd9ab |
serverctrls[ctrlidx] = NULL;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
#endif /* HAVE_LDAP_CREATE_DEREF_CONTROL */
|
|
Packit |
6bd9ab |
/* NULL terminate control list */
|
|
Packit |
6bd9ab |
serverctrls[ctrlidx] = NULL;
|
|
Packit |
6bd9ab |
/* clear error flag (perhaps control setting failed) */
|
|
Packit |
6bd9ab |
if (ctrlidx > 0)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
rc = LDAP_SUCCESS;
|
|
Packit |
6bd9ab |
if (ldap_set_option(search->session->ld, LDAP_OPT_ERROR_NUMBER, &rc) != LDAP_SUCCESS)
|
|
Packit |
6bd9ab |
log_log(LOG_WARNING, "failed to clear the error flag");
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
/* perform the search */
|
|
Packit |
6bd9ab |
rc = ldap_search_ext(search->session->ld, search->base, search->scope,
|
|
Packit |
6bd9ab |
search->filter, (char **)(search->attrs),
|
|
Packit |
6bd9ab |
0, serverctrls[0] == NULL ? NULL : serverctrls,
|
|
Packit |
6bd9ab |
NULL, NULL, LDAP_NO_LIMIT, &msgid);
|
|
Packit |
6bd9ab |
/* free the controls if we had them */
|
|
Packit |
6bd9ab |
for (ctrlidx = 0; serverctrls[ctrlidx] != NULL; ctrlidx++)
|
|
Packit |
6bd9ab |
ldap_control_free(serverctrls[ctrlidx]);
|
|
Packit |
6bd9ab |
/* handle errors */
|
|
Packit |
6bd9ab |
if (rc != LDAP_SUCCESS)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
myldap_err(LOG_WARNING, search->session->ld, rc, "ldap_search_ext() failed");
|
|
Packit |
6bd9ab |
return rc;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
/* update the last activity on the connection */
|
|
Packit |
6bd9ab |
time(&(search->session->lastactivity));
|
|
Packit |
6bd9ab |
/* save msgid */
|
|
Packit |
6bd9ab |
search->msgid = msgid;
|
|
Packit |
6bd9ab |
/* return the new search */
|
|
Packit |
6bd9ab |
return LDAP_SUCCESS;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
|
|
Packit |
6bd9ab |
MYLDAP_SESSION *myldap_create_session(void)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
return myldap_session_new();
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
|
|
Packit |
6bd9ab |
void myldap_session_cleanup(MYLDAP_SESSION *session)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
int i;
|
|
Packit |
6bd9ab |
/* check parameter */
|
|
Packit |
6bd9ab |
if (session == NULL)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
log_log(LOG_ERR, "myldap_session_cleanup(): invalid session passed");
|
|
Packit |
6bd9ab |
return;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
/* go over all searches in the session and close them */
|
|
Packit |
6bd9ab |
for (i = 0; i < MAX_SEARCHES_IN_SESSION; i++)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
if (session->searches[i] != NULL)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
myldap_search_close(session->searches[i]);
|
|
Packit |
6bd9ab |
session->searches[i] = NULL;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
|
|
Packit |
6bd9ab |
void myldap_session_close(MYLDAP_SESSION *session)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
/* check parameter */
|
|
Packit |
6bd9ab |
if (session == NULL)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
log_log(LOG_ERR, "myldap_session_cleanup(): invalid session passed");
|
|
Packit |
6bd9ab |
return;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
/* close pending searches */
|
|
Packit |
6bd9ab |
myldap_session_cleanup(session);
|
|
Packit |
6bd9ab |
/* close any open connections */
|
|
Packit |
6bd9ab |
do_close(session);
|
|
Packit |
6bd9ab |
/* free allocated memory */
|
|
Packit |
6bd9ab |
memset(session->bindpw, 0, sizeof(session->bindpw));
|
|
Packit |
6bd9ab |
free(session);
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
|
|
Packit |
6bd9ab |
/* mutex for updating the times in the uri */
|
|
Packit |
6bd9ab |
pthread_mutex_t uris_mutex = PTHREAD_MUTEX_INITIALIZER;
|
|
Packit |
6bd9ab |
|
|
Packit |
6bd9ab |
static int do_retry_search(MYLDAP_SEARCH *search)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
int sleeptime = 0;
|
|
Packit |
6bd9ab |
int start_uri;
|
|
Packit |
6bd9ab |
time_t endtime;
|
|
Packit |
6bd9ab |
time_t nexttry;
|
|
Packit |
6bd9ab |
time_t t;
|
|
Packit |
6bd9ab |
int rc = LDAP_UNAVAILABLE;
|
|
Packit |
6bd9ab |
struct myldap_uri *current_uri;
|
|
Packit |
6bd9ab |
int dotry[NSS_LDAP_CONFIG_MAX_URIS];
|
|
Packit |
6bd9ab |
int do_invalidate = 0;
|
|
Packit |
6bd9ab |
/* clear time stamps */
|
|
Packit |
6bd9ab |
for (start_uri = 0; start_uri < NSS_LDAP_CONFIG_MAX_URIS; start_uri++)
|
|
Packit |
6bd9ab |
dotry[start_uri] = 1;
|
|
Packit |
6bd9ab |
/* keep trying until we time out */
|
|
Packit |
6bd9ab |
endtime = time(NULL) + nslcd_cfg->reconnect_retrytime;
|
|
Packit |
6bd9ab |
while (1)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
nexttry = endtime;
|
|
Packit |
6bd9ab |
/* try each configured URL once */
|
|
Packit |
6bd9ab |
pthread_mutex_lock(&uris_mutex);
|
|
Packit |
6bd9ab |
start_uri = search->session->current_uri;
|
|
Packit |
6bd9ab |
do
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
current_uri = &(nslcd_cfg->uris[search->session->current_uri]);
|
|
Packit |
6bd9ab |
/* only try this URI if we should */
|
|
Packit |
6bd9ab |
if (!dotry[search->session->current_uri])
|
|
Packit |
6bd9ab |
{ /* skip this URI */ }
|
|
Packit |
6bd9ab |
else if ((current_uri->lastfail > (current_uri->firstfail + nslcd_cfg->reconnect_retrytime)) &&
|
|
Packit |
6bd9ab |
((t = time(NULL)) < (current_uri->lastfail + nslcd_cfg->reconnect_retrytime)))
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
/* we are in a hard fail state and have retried not long ago */
|
|
Packit |
6bd9ab |
log_log(LOG_DEBUG, "not retrying server %s which failed just %d second(s) ago and has been failing for %d seconds",
|
|
Packit |
6bd9ab |
current_uri->uri, (int)(t - current_uri->lastfail),
|
|
Packit |
6bd9ab |
(int)(t - current_uri->firstfail));
|
|
Packit |
6bd9ab |
dotry[search->session->current_uri] = 0;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
else
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
/* try to start the search */
|
|
Packit |
6bd9ab |
pthread_mutex_unlock(&uris_mutex);
|
|
Packit |
6bd9ab |
/* ensure that we have an open connection and start a search */
|
|
Packit |
6bd9ab |
rc = do_open(search->session);
|
|
Packit |
6bd9ab |
/* perform the actual search, unless we were only binding */
|
|
Packit |
6bd9ab |
if ((rc == LDAP_SUCCESS) && (search->scope != MYLDAP_SCOPE_BINDONLY))
|
|
Packit |
6bd9ab |
rc = do_try_search(search);
|
|
Packit |
6bd9ab |
/* if we are authenticating a user and get an error regarding failed
|
|
Packit |
6bd9ab |
password we should error out instead of trying all servers */
|
|
Packit |
6bd9ab |
if ((search->session->binddn[0] != '\0') && (rc == LDAP_INVALID_CREDENTIALS))
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
do_close(search->session);
|
|
Packit |
6bd9ab |
return rc;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
if (rc == LDAP_SUCCESS)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
pthread_mutex_lock(&uris_mutex);
|
|
Packit |
6bd9ab |
/* check if we are coming back from an error */
|
|
Packit |
6bd9ab |
if ((current_uri->lastfail > 0) || (search->session->current_uri != start_uri))
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
log_log(LOG_INFO, "connected to LDAP server %s", current_uri->uri);
|
|
Packit |
6bd9ab |
do_invalidate = 1;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
if (first_search)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
do_invalidate = 1;
|
|
Packit |
6bd9ab |
first_search = 0;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
/* update ok time */
|
|
Packit |
6bd9ab |
current_uri->firstfail = 0;
|
|
Packit |
6bd9ab |
current_uri->lastfail = 0;
|
|
Packit |
6bd9ab |
pthread_mutex_unlock(&uris_mutex);
|
|
Packit |
6bd9ab |
/* flag the search as valid */
|
|
Packit |
6bd9ab |
search->valid = 1;
|
|
Packit |
6bd9ab |
/* signal external invalidation of configured caches */
|
|
Packit |
6bd9ab |
if (do_invalidate)
|
|
Packit |
6bd9ab |
invalidator_do(LM_NONE);
|
|
Packit |
6bd9ab |
return LDAP_SUCCESS;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
/* close the current connection */
|
|
Packit |
6bd9ab |
do_close(search->session);
|
|
Packit |
6bd9ab |
/* update time of failure and figure out when we should retry */
|
|
Packit |
6bd9ab |
pthread_mutex_lock(&uris_mutex);
|
|
Packit |
6bd9ab |
t = time(NULL);
|
|
Packit |
6bd9ab |
/* update timestaps unless we are doing an authentication search */
|
|
Packit |
6bd9ab |
if (search->session->binddn[0] == '\0')
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
if (current_uri->firstfail == 0)
|
|
Packit |
6bd9ab |
current_uri->firstfail = t;
|
|
Packit |
6bd9ab |
current_uri->lastfail = t;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
/* if it is one of these, retrying this URI is not going to help */
|
|
Packit |
6bd9ab |
if ((rc == LDAP_INVALID_CREDENTIALS) || (rc == LDAP_INSUFFICIENT_ACCESS) ||
|
|
Packit |
6bd9ab |
(rc == LDAP_AUTH_METHOD_NOT_SUPPORTED))
|
|
Packit |
6bd9ab |
dotry[search->session->current_uri] = 0;
|
|
Packit |
6bd9ab |
/* check when we should try this URI again */
|
|
Packit |
6bd9ab |
else if (t <= (current_uri->firstfail + nslcd_cfg->reconnect_retrytime))
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
t += nslcd_cfg->reconnect_sleeptime;
|
|
Packit |
6bd9ab |
if (t < nexttry)
|
|
Packit |
6bd9ab |
nexttry = t;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
/* try the next URI (with wrap-around) */
|
|
Packit |
6bd9ab |
search->session->current_uri++;
|
|
Packit |
6bd9ab |
if (nslcd_cfg->uris[search->session->current_uri].uri == NULL)
|
|
Packit |
6bd9ab |
search->session->current_uri = 0;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
while (search->session->current_uri != start_uri);
|
|
Packit |
6bd9ab |
pthread_mutex_unlock(&uris_mutex);
|
|
Packit |
6bd9ab |
/* see if it is any use sleeping */
|
|
Packit |
6bd9ab |
if (nexttry >= endtime)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
if (search->session->binddn[0] == '\0')
|
|
Packit |
6bd9ab |
myldap_err(LOG_ERR, search->session->ld, rc, "no available LDAP server found");
|
|
Packit |
6bd9ab |
return rc;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
/* sleep between tries */
|
|
Packit |
6bd9ab |
sleeptime = nexttry - time(NULL);
|
|
Packit |
6bd9ab |
if (sleeptime > 0)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
log_log(LOG_WARNING, "no available LDAP server found, sleeping %d seconds",
|
|
Packit |
6bd9ab |
sleeptime);
|
|
Packit |
6bd9ab |
(void)sleep(sleeptime);
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
|
|
Packit |
6bd9ab |
/* force quick retries of all failing LDAP servers */
|
|
Packit |
6bd9ab |
void myldap_immediate_reconnect(void)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
int i;
|
|
Packit |
6bd9ab |
time_t t;
|
|
Packit |
6bd9ab |
t = time(NULL) - nslcd_cfg->reconnect_retrytime;
|
|
Packit |
6bd9ab |
pthread_mutex_lock(&uris_mutex);
|
|
Packit |
6bd9ab |
for (i = 0; i < (NSS_LDAP_CONFIG_MAX_URIS + 1); i++)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
/* only adjust failing connections that are in a hard fail state */
|
|
Packit |
6bd9ab |
if ((nslcd_cfg->uris[i].lastfail > t) &&
|
|
Packit |
6bd9ab |
(nslcd_cfg->uris[i].lastfail > (nslcd_cfg->uris[i].firstfail + nslcd_cfg->reconnect_retrytime)))
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
/* move lastfail back to ensure quick retry */
|
|
Packit |
6bd9ab |
log_log(LOG_DEBUG, "moving lastfail of %s %d second(s) back to force retry",
|
|
Packit |
6bd9ab |
nslcd_cfg->uris[i].uri, (int)(nslcd_cfg->uris[i].lastfail - t));
|
|
Packit |
6bd9ab |
nslcd_cfg->uris[i].lastfail = t;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
pthread_mutex_unlock(&uris_mutex);
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
|
|
Packit |
6bd9ab |
MYLDAP_SEARCH *myldap_search(MYLDAP_SESSION *session,
|
|
Packit |
6bd9ab |
const char *base, int scope, const char *filter,
|
|
Packit |
6bd9ab |
const char **attrs, int *rcp)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
MYLDAP_SEARCH *search;
|
|
Packit |
6bd9ab |
int i;
|
|
Packit |
6bd9ab |
int rc;
|
|
Packit |
6bd9ab |
/* check parameters */
|
|
Packit |
6bd9ab |
if ((session == NULL) || (base == NULL) || (filter == NULL) || (attrs == NULL))
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
log_log(LOG_ERR, "myldap_search(): invalid parameter passed");
|
|
Packit |
6bd9ab |
errno = EINVAL;
|
|
Packit |
6bd9ab |
if (rcp != NULL)
|
|
Packit |
6bd9ab |
*rcp = LDAP_OPERATIONS_ERROR;
|
|
Packit |
6bd9ab |
return NULL;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
/* log the call */
|
|
Packit |
6bd9ab |
log_log(LOG_DEBUG, "myldap_search(base=\"%s\", filter=\"%s\")",
|
|
Packit |
6bd9ab |
base, filter);
|
|
Packit |
6bd9ab |
/* check if the idle time for the connection has expired */
|
|
Packit |
6bd9ab |
myldap_session_check(session);
|
|
Packit |
6bd9ab |
/* allocate a new search entry */
|
|
Packit |
6bd9ab |
search = myldap_search_new(session, base, scope, filter, attrs);
|
|
Packit |
6bd9ab |
/* find a place in the session where we can register our search */
|
|
Packit |
6bd9ab |
for (i = 0; (i < MAX_SEARCHES_IN_SESSION) && (session->searches[i] != NULL); i++)
|
|
Packit |
6bd9ab |
/* nothing */ ;
|
|
Packit |
6bd9ab |
if (i >= MAX_SEARCHES_IN_SESSION)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
log_log(LOG_ERR, "myldap_search(): too many searches registered with session (max %d)",
|
|
Packit |
6bd9ab |
MAX_SEARCHES_IN_SESSION);
|
|
Packit |
6bd9ab |
myldap_search_close(search);
|
|
Packit |
6bd9ab |
if (rcp != NULL)
|
|
Packit |
6bd9ab |
*rcp = LDAP_OPERATIONS_ERROR;
|
|
Packit |
6bd9ab |
return NULL;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
/* register search with the session so we can free it later on */
|
|
Packit |
6bd9ab |
session->searches[i] = search;
|
|
Packit |
6bd9ab |
/* do the search with retries to all configured servers */
|
|
Packit |
6bd9ab |
rc = do_retry_search(search);
|
|
Packit |
6bd9ab |
if (rc != LDAP_SUCCESS)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
myldap_search_close(search);
|
|
Packit |
6bd9ab |
if (rcp != NULL)
|
|
Packit |
6bd9ab |
*rcp = rc;
|
|
Packit |
6bd9ab |
return NULL;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
if (rcp != NULL)
|
|
Packit |
6bd9ab |
*rcp = LDAP_SUCCESS;
|
|
Packit |
6bd9ab |
return search;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
|
|
Packit |
6bd9ab |
void myldap_search_close(MYLDAP_SEARCH *search)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
int i;
|
|
Packit |
6bd9ab |
if (search == NULL)
|
|
Packit |
6bd9ab |
return;
|
|
Packit |
6bd9ab |
/* free any messages */
|
|
Packit |
6bd9ab |
if (search->msg != NULL)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
ldap_msgfree(search->msg);
|
|
Packit |
6bd9ab |
search->msg = NULL;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
/* abandon the search if there were more results to fetch */
|
|
Packit |
6bd9ab |
if ((search->session->ld != NULL) && (search->msgid != -1))
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
ldap_abandon(search->session->ld, search->msgid);
|
|
Packit |
6bd9ab |
search->msgid = -1;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
/* find the reference to this search in the session */
|
|
Packit |
6bd9ab |
for (i = 0; i < MAX_SEARCHES_IN_SESSION; i++)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
if (search->session->searches[i] == search)
|
|
Packit |
6bd9ab |
search->session->searches[i] = NULL;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
/* free any search entries */
|
|
Packit |
6bd9ab |
if (search->entry != NULL)
|
|
Packit |
6bd9ab |
myldap_entry_free(search->entry);
|
|
Packit |
6bd9ab |
/* clean up cookie */
|
|
Packit |
6bd9ab |
if (search->cookie != NULL)
|
|
Packit |
6bd9ab |
ber_bvfree(search->cookie);
|
|
Packit |
6bd9ab |
/* free read messages */
|
|
Packit |
6bd9ab |
if (search->msg != NULL)
|
|
Packit |
6bd9ab |
ldap_msgfree(search->msg);
|
|
Packit |
6bd9ab |
/* free the storage we allocated */
|
|
Packit |
6bd9ab |
free(search);
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
|
|
Packit |
6bd9ab |
MYLDAP_ENTRY *myldap_get_entry(MYLDAP_SEARCH *search, int *rcp)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
int rc;
|
|
Packit |
6bd9ab |
int parserc;
|
|
Packit |
6bd9ab |
struct timeval tv, *tvp;
|
|
Packit |
6bd9ab |
LDAPControl **resultcontrols;
|
|
Packit |
6bd9ab |
ber_int_t count;
|
|
Packit |
6bd9ab |
/* check parameters */
|
|
Packit |
6bd9ab |
if ((search == NULL) || (search->session == NULL) || (search->session->ld == NULL))
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
log_log(LOG_ERR, "myldap_get_entry(): invalid search passed");
|
|
Packit |
6bd9ab |
errno = EINVAL;
|
|
Packit |
6bd9ab |
if (rcp != NULL)
|
|
Packit |
6bd9ab |
*rcp = LDAP_OPERATIONS_ERROR;
|
|
Packit |
6bd9ab |
return NULL;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
/* check if the connection wasn't closed in another search */
|
|
Packit |
6bd9ab |
if (!search->valid)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
log_log(LOG_WARNING, "myldap_get_entry(): connection was closed");
|
|
Packit |
6bd9ab |
/* retry the search */
|
|
Packit |
6bd9ab |
if (search->may_retry_search)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
log_log(LOG_DEBUG, "myldap_get_entry(): retry search");
|
|
Packit |
6bd9ab |
search->may_retry_search = 0;
|
|
Packit |
6bd9ab |
if (do_retry_search(search) == LDAP_SUCCESS)
|
|
Packit |
6bd9ab |
return myldap_get_entry(search, rcp);
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
myldap_search_close(search);
|
|
Packit |
6bd9ab |
if (rcp != NULL)
|
|
Packit |
6bd9ab |
*rcp = LDAP_SERVER_DOWN;
|
|
Packit |
6bd9ab |
return NULL;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
/* set up a timelimit value for operations */
|
|
Packit |
6bd9ab |
if (nslcd_cfg->timelimit == LDAP_NO_LIMIT)
|
|
Packit |
6bd9ab |
tvp = NULL;
|
|
Packit |
6bd9ab |
else
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
tv.tv_sec = nslcd_cfg->timelimit;
|
|
Packit |
6bd9ab |
tv.tv_usec = 0;
|
|
Packit |
6bd9ab |
tvp = &tv;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
/* if we have an existing result entry, free it */
|
|
Packit |
6bd9ab |
if (search->entry != NULL)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
myldap_entry_free(search->entry);
|
|
Packit |
6bd9ab |
search->entry = NULL;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
/* try to parse results until we have a final error or ok */
|
|
Packit |
6bd9ab |
while (1)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
/* free the previous message if there was any */
|
|
Packit |
6bd9ab |
if (search->msg != NULL)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
ldap_msgfree(search->msg);
|
|
Packit |
6bd9ab |
search->msg = NULL;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
/* get the next result */
|
|
Packit |
6bd9ab |
rc = ldap_result(search->session->ld, search->msgid, LDAP_MSG_ONE, tvp,
|
|
Packit |
6bd9ab |
&(search->msg));
|
|
Packit |
6bd9ab |
/* handle result */
|
|
Packit |
6bd9ab |
switch (rc)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
case LDAP_RES_SEARCH_ENTRY:
|
|
Packit |
6bd9ab |
/* we have a normal search entry, update timestamp and return result */
|
|
Packit |
6bd9ab |
time(&(search->session->lastactivity));
|
|
Packit |
6bd9ab |
search->entry = myldap_entry_new(search);
|
|
Packit |
6bd9ab |
if (rcp != NULL)
|
|
Packit |
6bd9ab |
*rcp = LDAP_SUCCESS;
|
|
Packit |
6bd9ab |
/* log the first couple of dns in the result (but not all, to
|
|
Packit |
6bd9ab |
prevent swamping the log) */
|
|
Packit |
6bd9ab |
if (search->count < MAX_DEBUG_LOG_DNS)
|
|
Packit |
6bd9ab |
log_log(LOG_DEBUG, "ldap_result(): %s", myldap_get_dn(search->entry));
|
|
Packit |
6bd9ab |
search->count++;
|
|
Packit |
6bd9ab |
search->may_retry_search = 0;
|
|
Packit |
6bd9ab |
return search->entry;
|
|
Packit |
6bd9ab |
case LDAP_RES_SEARCH_RESULT:
|
|
Packit |
6bd9ab |
/* we have a search result, parse it */
|
|
Packit |
6bd9ab |
resultcontrols = NULL;
|
|
Packit |
6bd9ab |
if (search->cookie != NULL)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
ber_bvfree(search->cookie);
|
|
Packit |
6bd9ab |
search->cookie = NULL;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
/* NB: this frees search->msg */
|
|
Packit |
6bd9ab |
parserc = ldap_parse_result(search->session->ld, search->msg, &rc,
|
|
Packit |
6bd9ab |
NULL, NULL, NULL, &resultcontrols, 1);
|
|
Packit |
6bd9ab |
search->msg = NULL;
|
|
Packit |
6bd9ab |
/* check for errors during parsing */
|
|
Packit |
6bd9ab |
if ((parserc != LDAP_SUCCESS) && (parserc != LDAP_MORE_RESULTS_TO_RETURN))
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
if (resultcontrols != NULL)
|
|
Packit |
6bd9ab |
ldap_controls_free(resultcontrols);
|
|
Packit |
6bd9ab |
myldap_err(LOG_ERR, search->session->ld, parserc, "ldap_parse_result() failed");
|
|
Packit |
6bd9ab |
myldap_search_close(search);
|
|
Packit |
6bd9ab |
if (rcp != NULL)
|
|
Packit |
6bd9ab |
*rcp = parserc;
|
|
Packit |
6bd9ab |
return NULL;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
/* check for errors in message */
|
|
Packit |
6bd9ab |
if ((rc != LDAP_SUCCESS) && (rc != LDAP_MORE_RESULTS_TO_RETURN))
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
if (resultcontrols != NULL)
|
|
Packit |
6bd9ab |
ldap_controls_free(resultcontrols);
|
|
Packit |
6bd9ab |
myldap_err(LOG_ERR, search->session->ld, rc, "ldap_result() failed");
|
|
Packit |
6bd9ab |
/* close connection on connection problems */
|
|
Packit |
6bd9ab |
if ((rc == LDAP_UNAVAILABLE) || (rc == LDAP_SERVER_DOWN))
|
|
Packit |
6bd9ab |
do_close(search->session);
|
|
Packit |
6bd9ab |
myldap_search_close(search);
|
|
Packit |
6bd9ab |
if (rcp != NULL)
|
|
Packit |
6bd9ab |
*rcp = rc;
|
|
Packit |
6bd9ab |
return NULL;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
/* handle result controls */
|
|
Packit |
6bd9ab |
if (resultcontrols != NULL)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
/* see if there are any more pages to come */
|
|
Packit |
6bd9ab |
rc = ldap_parse_page_control(search->session->ld, resultcontrols,
|
|
Packit |
6bd9ab |
&count, &(search->cookie));
|
|
Packit |
6bd9ab |
if (rc != LDAP_SUCCESS)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
if (rc != LDAP_CONTROL_NOT_FOUND)
|
|
Packit |
6bd9ab |
myldap_err(LOG_WARNING, search->session->ld, rc, "ldap_parse_page_control() failed");
|
|
Packit |
6bd9ab |
/* clear error flag */
|
|
Packit |
6bd9ab |
rc = LDAP_SUCCESS;
|
|
Packit |
6bd9ab |
if (ldap_set_option(search->session->ld, LDAP_OPT_ERROR_NUMBER,
|
|
Packit |
6bd9ab |
&rc) != LDAP_SUCCESS)
|
|
Packit |
6bd9ab |
log_log(LOG_WARNING, "failed to clear the error flag");
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
/* TODO: handle the above return code?? */
|
|
Packit |
6bd9ab |
ldap_controls_free(resultcontrols);
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
search->msgid = -1;
|
|
Packit |
6bd9ab |
/* check if there are more pages to come */
|
|
Packit |
6bd9ab |
if ((search->cookie == NULL) || (search->cookie->bv_len == 0))
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
if (search->count > MAX_DEBUG_LOG_DNS)
|
|
Packit |
6bd9ab |
log_log(LOG_DEBUG, "ldap_result(): ... %d more results",
|
|
Packit |
6bd9ab |
search->count - MAX_DEBUG_LOG_DNS);
|
|
Packit |
6bd9ab |
log_log(LOG_DEBUG, "ldap_result(): end of results (%d total)",
|
|
Packit |
6bd9ab |
search->count);
|
|
Packit |
6bd9ab |
/* we are at the end of the search, no more results */
|
|
Packit |
6bd9ab |
myldap_search_close(search);
|
|
Packit |
6bd9ab |
if (rcp != NULL)
|
|
Packit |
6bd9ab |
*rcp = LDAP_SUCCESS;
|
|
Packit |
6bd9ab |
return NULL;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
/* try the next page */
|
|
Packit |
6bd9ab |
rc = do_try_search(search);
|
|
Packit |
6bd9ab |
if (rc != LDAP_SUCCESS)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
/* close connection on connection problems */
|
|
Packit |
6bd9ab |
if ((rc == LDAP_UNAVAILABLE) || (rc == LDAP_SERVER_DOWN))
|
|
Packit |
6bd9ab |
do_close(search->session);
|
|
Packit |
6bd9ab |
myldap_search_close(search);
|
|
Packit |
6bd9ab |
if (rcp != NULL)
|
|
Packit |
6bd9ab |
*rcp = rc;
|
|
Packit |
6bd9ab |
return NULL;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
/* we continue with another pass */
|
|
Packit |
6bd9ab |
break;
|
|
Packit |
6bd9ab |
case LDAP_RES_SEARCH_REFERENCE:
|
|
Packit |
6bd9ab |
break; /* just ignore search references */
|
|
Packit |
6bd9ab |
default:
|
|
Packit |
6bd9ab |
/* we have some error condition, find out which */
|
|
Packit |
6bd9ab |
switch (rc)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
case -1:
|
|
Packit |
6bd9ab |
/* try to get error code */
|
|
Packit |
6bd9ab |
if (ldap_get_option(search->session->ld, LDAP_OPT_ERROR_NUMBER,
|
|
Packit |
6bd9ab |
&rc) != LDAP_SUCCESS)
|
|
Packit |
6bd9ab |
rc = LDAP_UNAVAILABLE;
|
|
Packit |
6bd9ab |
myldap_err(LOG_ERR, search->session->ld, rc, "ldap_result() failed");
|
|
Packit |
6bd9ab |
break;
|
|
Packit |
6bd9ab |
case 0:
|
|
Packit |
6bd9ab |
/* the timeout expired */
|
|
Packit |
6bd9ab |
log_log(LOG_ERR, "ldap_result() timed out");
|
|
Packit |
6bd9ab |
rc = LDAP_TIMELIMIT_EXCEEDED;
|
|
Packit |
6bd9ab |
break;
|
|
Packit |
6bd9ab |
default:
|
|
Packit |
6bd9ab |
/* unknown code */
|
|
Packit |
6bd9ab |
log_log(LOG_WARNING, "ldap_result() returned unexpected result type");
|
|
Packit |
6bd9ab |
rc = LDAP_PROTOCOL_ERROR;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
/* close connection on some connection problems */
|
|
Packit |
6bd9ab |
if ((rc == LDAP_UNAVAILABLE) || (rc == LDAP_SERVER_DOWN) ||
|
|
Packit |
6bd9ab |
(rc == LDAP_SUCCESS) || (rc == LDAP_TIMELIMIT_EXCEEDED) ||
|
|
Packit |
6bd9ab |
(rc == LDAP_OPERATIONS_ERROR) || (rc == LDAP_PROTOCOL_ERROR) ||
|
|
Packit |
6bd9ab |
(rc == LDAP_BUSY) || (rc == LDAP_UNWILLING_TO_PERFORM) ||
|
|
Packit |
6bd9ab |
(rc == LDAP_TIMEOUT) || (rc == LDAP_CONNECT_ERROR) ||
|
|
Packit |
6bd9ab |
(rc == LDAP_NOT_SUPPORTED))
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
do_close(search->session);
|
|
Packit |
6bd9ab |
/* retry once if no data has been received yet */
|
|
Packit |
6bd9ab |
if (search->may_retry_search)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
log_log(LOG_DEBUG, "myldap_get_entry(): retry search");
|
|
Packit |
6bd9ab |
search->may_retry_search = 0;
|
|
Packit |
6bd9ab |
if (do_retry_search(search) == LDAP_SUCCESS)
|
|
Packit |
6bd9ab |
return myldap_get_entry(search, rcp);
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
/* close search */
|
|
Packit |
6bd9ab |
myldap_search_close(search);
|
|
Packit |
6bd9ab |
if (rcp != NULL)
|
|
Packit |
6bd9ab |
*rcp = rc;
|
|
Packit |
6bd9ab |
return NULL;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
|
|
Packit |
6bd9ab |
/* Get the DN from the entry. This function only returns NULL (and sets
|
|
Packit |
6bd9ab |
errno) if an incorrect entry is passed. If the DN value cannot be
|
|
Packit |
6bd9ab |
retrieved "unknown" is returned instead. */
|
|
Packit |
6bd9ab |
const char *myldap_get_dn(MYLDAP_ENTRY *entry)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
int rc;
|
|
Packit |
6bd9ab |
/* check parameters */
|
|
Packit |
6bd9ab |
if (!is_valid_entry(entry))
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
log_log(LOG_ERR, "myldap_get_dn(): invalid result entry passed");
|
|
Packit |
6bd9ab |
errno = EINVAL;
|
|
Packit |
6bd9ab |
return "unknown";
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
/* if we don't have it yet, retreive it */
|
|
Packit |
6bd9ab |
if ((entry->dn == NULL) && (entry->search->valid))
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
entry->dn = ldap_get_dn(entry->search->session->ld, entry->search->msg);
|
|
Packit |
6bd9ab |
if (entry->dn == NULL)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
if (ldap_get_option(entry->search->session->ld, LDAP_OPT_ERROR_NUMBER,
|
|
Packit |
6bd9ab |
&rc) != LDAP_SUCCESS)
|
|
Packit |
6bd9ab |
rc = LDAP_UNAVAILABLE;
|
|
Packit |
6bd9ab |
myldap_err(LOG_WARNING, entry->search->session->ld, rc, "ldap_get_dn() returned NULL");
|
|
Packit |
6bd9ab |
/* close connection on connection problems */
|
|
Packit |
6bd9ab |
if ((rc == LDAP_UNAVAILABLE) || (rc == LDAP_SERVER_DOWN))
|
|
Packit |
6bd9ab |
do_close(entry->search->session);
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
/* if we still don't have it, return unknown */
|
|
Packit |
6bd9ab |
if (entry->dn == NULL)
|
|
Packit |
6bd9ab |
return "unknown";
|
|
Packit |
6bd9ab |
/* return it */
|
|
Packit |
6bd9ab |
return entry->dn;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
|
|
Packit |
6bd9ab |
char *myldap_cpy_dn(MYLDAP_ENTRY *entry, char *buf, size_t buflen)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
const char *dn;
|
|
Packit |
6bd9ab |
/* get the dn */
|
|
Packit |
6bd9ab |
dn = myldap_get_dn(entry);
|
|
Packit |
6bd9ab |
/* copy into buffer */
|
|
Packit |
6bd9ab |
if (strlen(dn) < buflen)
|
|
Packit |
6bd9ab |
strcpy(buf, dn);
|
|
Packit |
6bd9ab |
else
|
|
Packit |
6bd9ab |
buf = NULL;
|
|
Packit |
6bd9ab |
return buf;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
|
|
Packit |
6bd9ab |
/* Perform ranged retreival of attributes.
|
|
Packit |
6bd9ab |
http://msdn.microsoft.com/en-us/library/aa367017(vs.85).aspx
|
|
Packit |
6bd9ab |
http://www.tkk.fi/cc/docs/kerberos/draft-kashi-incremental-00.txt */
|
|
Packit |
6bd9ab |
static char **myldap_get_ranged_values(MYLDAP_ENTRY *entry, const char *attr)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
char **values;
|
|
Packit |
6bd9ab |
char *attn;
|
|
Packit |
6bd9ab |
const char *attrs[2];
|
|
Packit |
6bd9ab |
BerElement *ber;
|
|
Packit |
6bd9ab |
int i;
|
|
Packit |
6bd9ab |
int startat = 0, nxt = 0;
|
|
Packit |
6bd9ab |
char attbuf[80];
|
|
Packit |
6bd9ab |
const char *dn = myldap_get_dn(entry);
|
|
Packit |
6bd9ab |
MYLDAP_SESSION *session = entry->search->session;
|
|
Packit |
6bd9ab |
MYLDAP_SEARCH *search = NULL;
|
|
Packit |
6bd9ab |
SET *set = NULL;
|
|
Packit |
6bd9ab |
/* build the attribute name to find */
|
|
Packit |
6bd9ab |
if (mysnprintf(attbuf, sizeof(attbuf), "%s;range=0-*", attr))
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
log_log(LOG_ERR, "myldap_get_ranged_values(): attbuf buffer too small (%lu required)",
|
|
Packit |
6bd9ab |
(unsigned long) strlen(attr) + 10);
|
|
Packit |
6bd9ab |
return NULL;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
/* keep doing lookups untul we can't get any more results */
|
|
Packit |
6bd9ab |
while (1)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
/* go over all attributes to find the ranged attribute */
|
|
Packit |
6bd9ab |
ber = NULL;
|
|
Packit |
6bd9ab |
attn = ldap_first_attribute(entry->search->session->ld, entry->search->msg, &ber);
|
|
Packit |
6bd9ab |
values = NULL;
|
|
Packit |
6bd9ab |
while (attn != NULL)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
if (strncasecmp(attn, attbuf, strlen(attbuf) - 1) == 0)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
log_log(LOG_DEBUG, "found ranged results %s", attn);
|
|
Packit |
6bd9ab |
nxt = atoi(attn + strlen(attbuf) - 1) + 1;
|
|
Packit |
6bd9ab |
values = ldap_get_values(entry->search->session->ld, entry->search->msg, attn);
|
|
Packit |
6bd9ab |
ldap_memfree(attn);
|
|
Packit |
6bd9ab |
break;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
/* free old attribute name and get next one */
|
|
Packit |
6bd9ab |
ldap_memfree(attn);
|
|
Packit |
6bd9ab |
attn = ldap_next_attribute(entry->search->session->ld, entry->search->msg, ber);
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
ber_free(ber, 0);
|
|
Packit |
6bd9ab |
/* see if we found any values */
|
|
Packit |
6bd9ab |
if ((values == NULL) || (*values == NULL))
|
|
Packit |
6bd9ab |
break;
|
|
Packit |
6bd9ab |
/* allocate memory */
|
|
Packit |
6bd9ab |
if (set == NULL)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
set = set_new();
|
|
Packit |
6bd9ab |
if (set == NULL)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
ldap_value_free(values);
|
|
Packit |
6bd9ab |
log_log(LOG_CRIT, "myldap_get_ranged_values(): set_new() failed to allocate memory");
|
|
Packit |
6bd9ab |
return NULL;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
/* add to the set */
|
|
Packit |
6bd9ab |
for (i = 0; values[i] != NULL; i++)
|
|
Packit |
6bd9ab |
set_add(set, values[i]);
|
|
Packit |
6bd9ab |
/* free results */
|
|
Packit |
6bd9ab |
ldap_value_free(values);
|
|
Packit |
6bd9ab |
/* check if we should start a new search */
|
|
Packit |
6bd9ab |
if (nxt <= startat)
|
|
Packit |
6bd9ab |
break;
|
|
Packit |
6bd9ab |
startat = nxt;
|
|
Packit |
6bd9ab |
/* build attributes for a new search */
|
|
Packit |
6bd9ab |
if (mysnprintf(attbuf, sizeof(attbuf), "%s;range=%d-*", attr, startat))
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
log_log(LOG_ERR, "myldap_get_ranged_values(): attbuf buffer too small");
|
|
Packit |
6bd9ab |
break;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
attrs[0] = attbuf;
|
|
Packit |
6bd9ab |
attrs[1] = NULL;
|
|
Packit |
6bd9ab |
/* close the previous search, if any */
|
|
Packit |
6bd9ab |
if (search != NULL)
|
|
Packit |
6bd9ab |
myldap_search_close(search);
|
|
Packit |
6bd9ab |
/* start the new search */
|
|
Packit |
6bd9ab |
search = myldap_search(session, dn, LDAP_SCOPE_BASE, "(objectClass=*)", attrs, NULL);
|
|
Packit |
6bd9ab |
if (search == NULL)
|
|
Packit |
6bd9ab |
break;
|
|
Packit |
6bd9ab |
entry = myldap_get_entry(search, NULL);
|
|
Packit |
6bd9ab |
if (entry == NULL)
|
|
Packit |
6bd9ab |
break;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
/* close any started searches */
|
|
Packit |
6bd9ab |
if (search != NULL)
|
|
Packit |
6bd9ab |
myldap_search_close(search);
|
|
Packit |
6bd9ab |
/* return the contents of the set as a list */
|
|
Packit |
6bd9ab |
if (set == NULL)
|
|
Packit |
6bd9ab |
return NULL;
|
|
Packit |
6bd9ab |
values = (char **)set_tolist(set);
|
|
Packit |
6bd9ab |
set_free(set);
|
|
Packit |
6bd9ab |
if (values == NULL)
|
|
Packit |
6bd9ab |
log_log(LOG_CRIT, "myldap_get_ranged_values(): malloc() failed to allocate memory");
|
|
Packit |
6bd9ab |
return values;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
|
|
Packit |
6bd9ab |
/* Simple wrapper around ldap_get_values(). */
|
|
Packit |
6bd9ab |
const char **myldap_get_values(MYLDAP_ENTRY *entry, const char *attr)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
char **values;
|
|
Packit |
6bd9ab |
int rc;
|
|
Packit |
6bd9ab |
int i;
|
|
Packit |
6bd9ab |
/* check parameters */
|
|
Packit |
6bd9ab |
if (!is_valid_entry(entry))
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
log_log(LOG_ERR, "myldap_get_values(): invalid result entry passed");
|
|
Packit |
6bd9ab |
errno = EINVAL;
|
|
Packit |
6bd9ab |
return NULL;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
else if (attr == NULL)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
log_log(LOG_ERR, "myldap_get_values(): invalid attribute name passed");
|
|
Packit |
6bd9ab |
errno = EINVAL;
|
|
Packit |
6bd9ab |
return NULL;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
if (!entry->search->valid)
|
|
Packit |
6bd9ab |
return NULL; /* search has been stopped */
|
|
Packit |
6bd9ab |
/* get from LDAP */
|
|
Packit |
6bd9ab |
values = ldap_get_values(entry->search->session->ld, entry->search->msg, attr);
|
|
Packit |
6bd9ab |
if (values == NULL)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
if (ldap_get_option(entry->search->session->ld, LDAP_OPT_ERROR_NUMBER, &rc) != LDAP_SUCCESS)
|
|
Packit |
6bd9ab |
rc = LDAP_UNAVAILABLE;
|
|
Packit |
6bd9ab |
/* ignore decoding errors as they are just nonexisting attribute values */
|
|
Packit |
6bd9ab |
if (rc == LDAP_DECODING_ERROR)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
rc = LDAP_SUCCESS;
|
|
Packit |
6bd9ab |
if (ldap_set_option(entry->search->session->ld, LDAP_OPT_ERROR_NUMBER, &rc) != LDAP_SUCCESS)
|
|
Packit |
6bd9ab |
log_log(LOG_WARNING, "failed to clear the error flag");
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
else if (rc == LDAP_SUCCESS)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
/* we have a success code but no values, let's try to get ranged
|
|
Packit |
6bd9ab |
values */
|
|
Packit |
6bd9ab |
values = myldap_get_ranged_values(entry, attr);
|
|
Packit |
6bd9ab |
if (values == NULL)
|
|
Packit |
6bd9ab |
return NULL;
|
|
Packit |
6bd9ab |
/* store values entry so we can free it later on */
|
|
Packit |
6bd9ab |
for (i = 0; i < MAX_BUFFERS_PER_ENTRY; i++)
|
|
Packit |
6bd9ab |
if (entry->buffers[i] == NULL)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
entry->buffers[i] = values;
|
|
Packit |
6bd9ab |
return (const char **)entry->buffers[i];
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
/* we found no room to store the values */
|
|
Packit |
6bd9ab |
log_log(LOG_ERR, "ldap_get_values() couldn't store results, increase MAX_BUFFERS_PER_ENTRY");
|
|
Packit |
6bd9ab |
free(values);
|
|
Packit |
6bd9ab |
return NULL;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
else
|
|
Packit |
6bd9ab |
myldap_err(LOG_WARNING, entry->search->session->ld, rc,
|
|
Packit |
6bd9ab |
"ldap_get_values() of attribute \"%s\" on entry \"%s\" returned NULL",
|
|
Packit |
6bd9ab |
attr, myldap_get_dn(entry));
|
|
Packit |
6bd9ab |
return NULL;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
/* store values entry so we can free it later on */
|
|
Packit |
6bd9ab |
for (i = 0; i < MAX_ATTRIBUTES_PER_ENTRY; i++)
|
|
Packit |
6bd9ab |
if (entry->attributevalues[i] == NULL)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
entry->attributevalues[i] = values;
|
|
Packit |
6bd9ab |
return (const char **)values;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
/* we found no room to store the entry */
|
|
Packit |
6bd9ab |
log_log(LOG_ERR, "ldap_get_values() couldn't store results, increase MAX_ATTRIBUTES_PER_ENTRY");
|
|
Packit |
6bd9ab |
ldap_value_free(values);
|
|
Packit |
6bd9ab |
return NULL;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
|
|
Packit |
6bd9ab |
/* Convert the bervalues to a simple list of strings that can be freed
|
|
Packit |
6bd9ab |
with one call to free(). */
|
|
Packit |
6bd9ab |
static const char **bervalues_to_values(struct berval **bvalues)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
int num_values;
|
|
Packit |
6bd9ab |
int i;
|
|
Packit |
6bd9ab |
size_t sz;
|
|
Packit |
6bd9ab |
char *buf;
|
|
Packit |
6bd9ab |
char **values;
|
|
Packit |
6bd9ab |
/* figure out how much memory to allocate */
|
|
Packit |
6bd9ab |
num_values = ldap_count_values_len(bvalues);
|
|
Packit |
6bd9ab |
sz = (num_values + 1) * sizeof(char *);
|
|
Packit |
6bd9ab |
for (i = 0; i < num_values; i++)
|
|
Packit |
6bd9ab |
sz += bvalues[i]->bv_len + 1;
|
|
Packit |
6bd9ab |
/* allocate the needed memory */
|
|
Packit |
6bd9ab |
values = (char **)malloc(sz);
|
|
Packit |
6bd9ab |
if (values == NULL)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
log_log(LOG_CRIT, "bervalues_to_values(): malloc() failed to allocate memory");
|
|
Packit |
6bd9ab |
return NULL;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
buf = (char *)values;
|
|
Packit |
6bd9ab |
buf += (num_values + 1) * sizeof(char *);
|
|
Packit |
6bd9ab |
/* copy from bvalues */
|
|
Packit |
6bd9ab |
for (i = 0; i < num_values; i++)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
values[i] = buf;
|
|
Packit |
6bd9ab |
memcpy(values[i], bvalues[i]->bv_val, bvalues[i]->bv_len);
|
|
Packit |
6bd9ab |
values[i][bvalues[i]->bv_len] = '\0';
|
|
Packit |
6bd9ab |
buf += bvalues[i]->bv_len + 1;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
values[i] = NULL;
|
|
Packit |
6bd9ab |
return (const char **)values;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
|
|
Packit |
6bd9ab |
/* Simple wrapper around ldap_get_values(). */
|
|
Packit |
6bd9ab |
const char **myldap_get_values_len(MYLDAP_ENTRY *entry, const char *attr)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
const char **values;
|
|
Packit |
6bd9ab |
struct berval **bvalues;
|
|
Packit |
6bd9ab |
int rc;
|
|
Packit |
6bd9ab |
int i;
|
|
Packit |
6bd9ab |
/* check parameters */
|
|
Packit |
6bd9ab |
if (!is_valid_entry(entry))
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
log_log(LOG_ERR, "myldap_get_values_len(): invalid result entry passed");
|
|
Packit |
6bd9ab |
errno = EINVAL;
|
|
Packit |
6bd9ab |
return NULL;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
else if (attr == NULL)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
log_log(LOG_ERR, "myldap_get_values_len(): invalid attribute name passed");
|
|
Packit |
6bd9ab |
errno = EINVAL;
|
|
Packit |
6bd9ab |
return NULL;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
if (!entry->search->valid)
|
|
Packit |
6bd9ab |
return NULL; /* search has been stopped */
|
|
Packit |
6bd9ab |
/* get from LDAP */
|
|
Packit |
6bd9ab |
bvalues = ldap_get_values_len(entry->search->session->ld, entry->search->msg, attr);
|
|
Packit |
6bd9ab |
if (bvalues == NULL)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
if (ldap_get_option(entry->search->session->ld, LDAP_OPT_ERROR_NUMBER, &rc) != LDAP_SUCCESS)
|
|
Packit |
6bd9ab |
rc = LDAP_UNAVAILABLE;
|
|
Packit |
6bd9ab |
/* ignore decoding errors as they are just nonexisting attribute values */
|
|
Packit |
6bd9ab |
if (rc == LDAP_DECODING_ERROR)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
rc = LDAP_SUCCESS;
|
|
Packit |
6bd9ab |
if (ldap_set_option(entry->search->session->ld, LDAP_OPT_ERROR_NUMBER, &rc) != LDAP_SUCCESS)
|
|
Packit |
6bd9ab |
log_log(LOG_WARNING, "failed to clear the error flag");
|
|
Packit |
6bd9ab |
return NULL;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
else if (rc == LDAP_SUCCESS)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
/* we have a success code but no values, let's try to get ranged
|
|
Packit |
6bd9ab |
values */
|
|
Packit |
6bd9ab |
values = (const char **)myldap_get_ranged_values(entry, attr);
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
else
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
myldap_err(LOG_WARNING, entry->search->session->ld, rc,
|
|
Packit |
6bd9ab |
"myldap_get_values_len() of attribute \"%s\" on entry \"%s\" returned NULL",
|
|
Packit |
6bd9ab |
attr, myldap_get_dn(entry));
|
|
Packit |
6bd9ab |
return NULL;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
else
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
values = bervalues_to_values(bvalues);
|
|
Packit |
6bd9ab |
ldap_value_free_len(bvalues);
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
/* check if we got allocated memory */
|
|
Packit |
6bd9ab |
if (values == NULL)
|
|
Packit |
6bd9ab |
return NULL;
|
|
Packit |
6bd9ab |
/* store values entry so we can free it later on */
|
|
Packit |
6bd9ab |
for (i = 0; i < MAX_BUFFERS_PER_ENTRY; i++)
|
|
Packit |
6bd9ab |
if (entry->buffers[i] == NULL)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
entry->buffers[i] = (char **)values;
|
|
Packit |
6bd9ab |
return values;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
/* we found no room to store the values */
|
|
Packit |
6bd9ab |
log_log(LOG_ERR, "myldap_get_values_len() couldn't store results, increase MAX_BUFFERS_PER_ENTRY");
|
|
Packit |
6bd9ab |
free(values);
|
|
Packit |
6bd9ab |
return NULL;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
|
|
Packit |
6bd9ab |
/* Go over the entries in exploded_rdn and see if any start with
|
|
Packit |
6bd9ab |
the requested attribute. Return a reference to the value part of
|
|
Packit |
6bd9ab |
the DN (does not modify exploded_rdn). */
|
|
Packit |
6bd9ab |
static const char *find_rdn_value(char **exploded_rdn, const char *attr)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
int i, j;
|
|
Packit |
6bd9ab |
int l;
|
|
Packit |
6bd9ab |
if (exploded_rdn == NULL)
|
|
Packit |
6bd9ab |
return NULL;
|
|
Packit |
6bd9ab |
/* go over all RDNs */
|
|
Packit |
6bd9ab |
l = strlen(attr);
|
|
Packit |
6bd9ab |
for (i = 0; exploded_rdn[i] != NULL; i++)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
/* check that RDN starts with attr */
|
|
Packit |
6bd9ab |
if (strncasecmp(exploded_rdn[i], attr, l) != 0)
|
|
Packit |
6bd9ab |
continue;
|
|
Packit |
6bd9ab |
j = l;
|
|
Packit |
6bd9ab |
/* skip spaces */
|
|
Packit |
6bd9ab |
while (isspace(exploded_rdn[i][j]))
|
|
Packit |
6bd9ab |
j++;
|
|
Packit |
6bd9ab |
/* ensure that we found an equals sign now */
|
|
Packit |
6bd9ab |
if (exploded_rdn[i][j] != '=')
|
|
Packit |
6bd9ab |
continue;
|
|
Packit |
6bd9ab |
j++;
|
|
Packit |
6bd9ab |
/* skip more spaces */
|
|
Packit |
6bd9ab |
while (isspace(exploded_rdn[i][j]))
|
|
Packit |
6bd9ab |
j++;
|
|
Packit |
6bd9ab |
/* ensure that we're not at the end of the string */
|
|
Packit |
6bd9ab |
if (exploded_rdn[i][j] == '\0')
|
|
Packit |
6bd9ab |
continue;
|
|
Packit |
6bd9ab |
/* we found our value */
|
|
Packit |
6bd9ab |
return exploded_rdn[i] + j;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
/* fail */
|
|
Packit |
6bd9ab |
return NULL;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
|
|
Packit |
6bd9ab |
/* explode the first part of DN into parts
|
|
Packit |
6bd9ab |
(e.g. "cn=Test", "uid=test")
|
|
Packit |
6bd9ab |
The returned value should be freed with ldap_value_free(). */
|
|
Packit |
6bd9ab |
static char **get_exploded_rdn(const char *dn)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
char **exploded_dn;
|
|
Packit |
6bd9ab |
char **exploded_rdn;
|
|
Packit |
6bd9ab |
/* check if we have a DN */
|
|
Packit |
6bd9ab |
if ((dn == NULL) || (strcasecmp(dn, "unknown") == 0))
|
|
Packit |
6bd9ab |
return NULL;
|
|
Packit |
6bd9ab |
/* explode dn into { "uid=test", "ou=people", ..., NULL } */
|
|
Packit |
6bd9ab |
exploded_dn = ldap_explode_dn(dn, 0);
|
|
Packit |
6bd9ab |
if ((exploded_dn == NULL) || (exploded_dn[0] == NULL))
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
log_log(LOG_WARNING, "ldap_explode_dn(%s) returned NULL: %s",
|
|
Packit |
6bd9ab |
dn, strerror(errno));
|
|
Packit |
6bd9ab |
return NULL;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
/* explode rdn (first part of exploded_dn),
|
|
Packit |
6bd9ab |
e.g. "cn=Test User+uid=testusr" into
|
|
Packit |
6bd9ab |
{ "cn=Test User", "uid=testusr", NULL } */
|
|
Packit |
6bd9ab |
errno = 0;
|
|
Packit |
6bd9ab |
exploded_rdn = ldap_explode_rdn(exploded_dn[0], 0);
|
|
Packit |
6bd9ab |
if ((exploded_rdn == NULL) || (exploded_rdn[0] == NULL))
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
log_log(LOG_WARNING, "ldap_explode_rdn(%s) returned NULL: %s",
|
|
Packit |
6bd9ab |
exploded_dn[0], strerror(errno));
|
|
Packit |
6bd9ab |
if (exploded_rdn != NULL)
|
|
Packit |
6bd9ab |
ldap_value_free(exploded_rdn);
|
|
Packit |
6bd9ab |
ldap_value_free(exploded_dn);
|
|
Packit |
6bd9ab |
return NULL;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
ldap_value_free(exploded_dn);
|
|
Packit |
6bd9ab |
return exploded_rdn;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
|
|
Packit |
6bd9ab |
const char *myldap_get_rdn_value(MYLDAP_ENTRY *entry, const char *attr)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
/* check parameters */
|
|
Packit |
6bd9ab |
if (!is_valid_entry(entry))
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
log_log(LOG_ERR, "myldap_get_rdn_value(): invalid result entry passed");
|
|
Packit |
6bd9ab |
errno = EINVAL;
|
|
Packit |
6bd9ab |
return NULL;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
else if (attr == NULL)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
log_log(LOG_ERR, "myldap_get_rdn_value(): invalid attribute name passed");
|
|
Packit |
6bd9ab |
errno = EINVAL;
|
|
Packit |
6bd9ab |
return NULL;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
/* check if entry contains exploded_rdn */
|
|
Packit |
6bd9ab |
if (entry->exploded_rdn == NULL)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
entry->exploded_rdn = get_exploded_rdn(myldap_get_dn(entry));
|
|
Packit |
6bd9ab |
if (entry->exploded_rdn == NULL)
|
|
Packit |
6bd9ab |
return NULL;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
/* find rnd value */
|
|
Packit |
6bd9ab |
return find_rdn_value(entry->exploded_rdn, attr);
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
|
|
Packit |
6bd9ab |
const char *myldap_cpy_rdn_value(const char *dn, const char *attr,
|
|
Packit |
6bd9ab |
char *buf, size_t buflen)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
char **exploded_rdn;
|
|
Packit |
6bd9ab |
const char *value;
|
|
Packit |
6bd9ab |
/* explode dn into { "cn=Test", "uid=test", NULL } */
|
|
Packit |
6bd9ab |
exploded_rdn = get_exploded_rdn(dn);
|
|
Packit |
6bd9ab |
if (exploded_rdn == NULL)
|
|
Packit |
6bd9ab |
return NULL;
|
|
Packit |
6bd9ab |
/* see if we have a match */
|
|
Packit |
6bd9ab |
value = find_rdn_value(exploded_rdn, attr);
|
|
Packit |
6bd9ab |
/* if we have something store it in the buffer */
|
|
Packit |
6bd9ab |
if ((value != NULL) && (strlen(value) < buflen))
|
|
Packit |
6bd9ab |
strcpy(buf, value);
|
|
Packit |
6bd9ab |
else
|
|
Packit |
6bd9ab |
value = NULL;
|
|
Packit |
6bd9ab |
/* free allocated stuff */
|
|
Packit |
6bd9ab |
ldap_value_free(exploded_rdn);
|
|
Packit |
6bd9ab |
/* check if we have something to return */
|
|
Packit |
6bd9ab |
return (value != NULL) ? buf : NULL;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
|
|
Packit |
6bd9ab |
int myldap_has_objectclass(MYLDAP_ENTRY *entry, const char *objectclass)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
const char **values;
|
|
Packit |
6bd9ab |
int i;
|
|
Packit |
6bd9ab |
if ((!is_valid_entry(entry)) || (objectclass == NULL))
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
log_log(LOG_ERR, "myldap_has_objectclass(): invalid argument passed");
|
|
Packit |
6bd9ab |
errno = EINVAL;
|
|
Packit |
6bd9ab |
return 0;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
values = myldap_get_values(entry, "objectClass");
|
|
Packit |
6bd9ab |
if (values == NULL)
|
|
Packit |
6bd9ab |
return 0;
|
|
Packit |
6bd9ab |
for (i = 0; values[i] != NULL; i++)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
if (strcasecmp(values[i], objectclass) == 0)
|
|
Packit |
6bd9ab |
return -1;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
return 0;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
|
|
Packit |
6bd9ab |
#ifdef HAVE_LDAP_PARSE_DEREF_CONTROL
|
|
Packit |
6bd9ab |
const char ***myldap_get_deref_values(MYLDAP_ENTRY *entry,
|
|
Packit |
6bd9ab |
const char *derefattr, const char *getattr)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
LDAPControl **entryctrls;
|
|
Packit |
6bd9ab |
LDAPDerefRes *deref, *d;
|
|
Packit |
6bd9ab |
LDAPDerefVal *a;
|
|
Packit |
6bd9ab |
int i, pass;
|
|
Packit |
6bd9ab |
int rc;
|
|
Packit |
6bd9ab |
int found;
|
|
Packit |
6bd9ab |
int counts[2];
|
|
Packit |
6bd9ab |
size_t sizes[2], size;
|
|
Packit |
6bd9ab |
char *buffer = NULL;
|
|
Packit |
6bd9ab |
char ***results = NULL;
|
|
Packit |
6bd9ab |
rc = ldap_get_entry_controls(entry->search->session->ld, entry->search->msg,
|
|
Packit |
6bd9ab |
&entryctrls);
|
|
Packit |
6bd9ab |
if (rc != LDAP_SUCCESS)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
myldap_err(LOG_WARNING, entry->search->session->ld, rc,
|
|
Packit |
6bd9ab |
"ldap_get_entry_controls() failed");
|
|
Packit |
6bd9ab |
return NULL;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
if (entryctrls == NULL)
|
|
Packit |
6bd9ab |
return NULL;
|
|
Packit |
6bd9ab |
/* see if we can find a deref control */
|
|
Packit |
6bd9ab |
rc = ldap_parse_deref_control(entry->search->session->ld, entryctrls,
|
|
Packit |
6bd9ab |
&deref);
|
|
Packit |
6bd9ab |
if ((rc != LDAP_SUCCESS) || (deref == NULL))
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
if ((rc != LDAP_SUCCESS) && (rc != LDAP_CONTROL_NOT_FOUND))
|
|
Packit |
6bd9ab |
myldap_err(LOG_WARNING, entry->search->session->ld, rc,
|
|
Packit |
6bd9ab |
"ldap_parse_deref_control() failed");
|
|
Packit |
6bd9ab |
/* clear error flag */
|
|
Packit |
6bd9ab |
rc = LDAP_SUCCESS;
|
|
Packit |
6bd9ab |
if (ldap_set_option(entry->search->session->ld, LDAP_OPT_ERROR_NUMBER,
|
|
Packit |
6bd9ab |
&rc) != LDAP_SUCCESS)
|
|
Packit |
6bd9ab |
log_log(LOG_WARNING, "failed to clear the error flag");
|
|
Packit |
6bd9ab |
ldap_controls_free(entryctrls);
|
|
Packit |
6bd9ab |
return NULL;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
/* two passes: one to calculate size, one to store data */
|
|
Packit |
6bd9ab |
for (pass=0; pass < 2; pass++)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
/* reset counters and size */
|
|
Packit |
6bd9ab |
for (i = 0; i < 2; i++)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
counts[i] = 0;
|
|
Packit |
6bd9ab |
sizes[i] = 0;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
/* go over all deref'd attributes and find the one we're looking for */
|
|
Packit |
6bd9ab |
for (d = deref; d != NULL; d = d->next)
|
|
Packit |
6bd9ab |
if ((d->derefAttr != NULL) && (d->derefVal.bv_val != NULL) &&
|
|
Packit |
6bd9ab |
(strcasecmp(derefattr, d->derefAttr) == 0))
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
/* we should have one d per original attribute value */
|
|
Packit |
6bd9ab |
found = 0;
|
|
Packit |
6bd9ab |
/* go over deref'd attribute values to find the ones we're looking for */
|
|
Packit |
6bd9ab |
for (a = d->attrVals; a != NULL; a = a->next)
|
|
Packit |
6bd9ab |
if ((a->type != NULL) && (a->vals != NULL) &&
|
|
Packit |
6bd9ab |
(strcasecmp(getattr, a->type) == 0))
|
|
Packit |
6bd9ab |
for (i=0; a->vals[i].bv_val != NULL; i++)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
found = 1;
|
|
Packit |
6bd9ab |
if (results == NULL)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
log_log(LOG_DEBUG, "deref %s %s=%s -> %s=%s",
|
|
Packit |
6bd9ab |
myldap_get_dn(entry), d->derefAttr, d->derefVal.bv_val,
|
|
Packit |
6bd9ab |
a->type, a->vals[i].bv_val);
|
|
Packit |
6bd9ab |
counts[0]++;
|
|
Packit |
6bd9ab |
sizes[0] += strlen(a->vals[i].bv_val) + 1;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
else
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
strcpy(buffer, a->vals[i].bv_val);
|
|
Packit |
6bd9ab |
results[0][counts[0]++] = buffer;
|
|
Packit |
6bd9ab |
buffer += strlen(buffer) + 1;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
if (!found)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
if (results == NULL)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
log_log(LOG_DEBUG, "no %s deref %s %s=%s", getattr,
|
|
Packit |
6bd9ab |
myldap_get_dn(entry), d->derefAttr, d->derefVal.bv_val);
|
|
Packit |
6bd9ab |
counts[1]++;
|
|
Packit |
6bd9ab |
sizes[1] += strlen(d->derefVal.bv_val) + 1;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
else
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
strcpy(buffer, d->derefVal.bv_val);
|
|
Packit |
6bd9ab |
results[1][counts[1]++] = buffer;
|
|
Packit |
6bd9ab |
buffer += strlen(buffer) + 1;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
/* allocate memory after first pass */
|
|
Packit |
6bd9ab |
if (results == NULL)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
size = sizeof(char **) * 3;
|
|
Packit |
6bd9ab |
for (i = 0; i < 2; i++)
|
|
Packit |
6bd9ab |
size += sizeof(char *) * (counts[i] + 1);
|
|
Packit |
6bd9ab |
for (i = 0; i < 2; i++)
|
|
Packit |
6bd9ab |
size += sizeof(char) * sizes[i];
|
|
Packit |
6bd9ab |
buffer = (char *)malloc(size);
|
|
Packit |
6bd9ab |
if (buffer == NULL)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
log_log(LOG_CRIT, "myldap_get_deref_values(): malloc() failed to allocate memory");
|
|
Packit |
6bd9ab |
return NULL;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
/* allocate the list of lists */
|
|
Packit |
6bd9ab |
results = (void *)buffer;
|
|
Packit |
6bd9ab |
buffer += sizeof(char **) * 3;
|
|
Packit |
6bd9ab |
/* allocate the lists */
|
|
Packit |
6bd9ab |
for (i = 0; i < 2; i++)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
results[i] = (char **)buffer;
|
|
Packit |
6bd9ab |
buffer += sizeof(char *) * (counts[i] + 1);
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
results[i] = NULL;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
/* NULL terminate the lists */
|
|
Packit |
6bd9ab |
results[0][counts[0]] = NULL;
|
|
Packit |
6bd9ab |
results[1][counts[1]] = NULL;
|
|
Packit |
6bd9ab |
/* free control data */
|
|
Packit |
6bd9ab |
ldap_derefresponse_free(deref);
|
|
Packit |
6bd9ab |
ldap_controls_free(entryctrls);
|
|
Packit |
6bd9ab |
/* store results so we can free it later on */
|
|
Packit |
6bd9ab |
for (i = 0; i < MAX_BUFFERS_PER_ENTRY; i++)
|
|
Packit |
6bd9ab |
if (entry->buffers[i] == NULL)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
entry->buffers[i] = (void *)results;
|
|
Packit |
6bd9ab |
return (const char ***)results;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
/* we found no room to store the values */
|
|
Packit |
6bd9ab |
log_log(LOG_ERR, "myldap_get_deref_values() couldn't store results, "
|
|
Packit |
6bd9ab |
"increase MAX_BUFFERS_PER_ENTRY");
|
|
Packit |
6bd9ab |
free(results);
|
|
Packit |
6bd9ab |
return NULL;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
#else /* not HAVE_LDAP_PARSE_DEREF_CONTROL */
|
|
Packit |
6bd9ab |
const char ***myldap_get_deref_values(MYLDAP_ENTRY UNUSED(*entry),
|
|
Packit |
6bd9ab |
const char UNUSED(*derefattr), const char UNUSED(*getattr))
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
return NULL;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
#endif /* not HAVE_LDAP_PARSE_DEREF_CONTROL */
|
|
Packit |
6bd9ab |
|
|
Packit |
6bd9ab |
int myldap_escape(const char *src, char *buffer, size_t buflen)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
size_t pos = 0;
|
|
Packit |
6bd9ab |
/* go over all characters in source string */
|
|
Packit |
6bd9ab |
for (; *src != '\0'; src++)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
/* check if char will fit */
|
|
Packit |
6bd9ab |
if ((pos + 4) >= buflen)
|
|
Packit |
6bd9ab |
return -1;
|
|
Packit |
6bd9ab |
/* do escaping for some characters */
|
|
Packit |
6bd9ab |
switch (*src)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
case '*':
|
|
Packit |
6bd9ab |
strcpy(buffer + pos, "\\2a");
|
|
Packit |
6bd9ab |
pos += 3;
|
|
Packit |
6bd9ab |
break;
|
|
Packit |
6bd9ab |
case '(':
|
|
Packit |
6bd9ab |
strcpy(buffer + pos, "\\28");
|
|
Packit |
6bd9ab |
pos += 3;
|
|
Packit |
6bd9ab |
break;
|
|
Packit |
6bd9ab |
case ')':
|
|
Packit |
6bd9ab |
strcpy(buffer + pos, "\\29");
|
|
Packit |
6bd9ab |
pos += 3;
|
|
Packit |
6bd9ab |
break;
|
|
Packit |
6bd9ab |
case '\\':
|
|
Packit |
6bd9ab |
strcpy(buffer + pos, "\\5c");
|
|
Packit |
6bd9ab |
pos += 3;
|
|
Packit |
6bd9ab |
break;
|
|
Packit |
6bd9ab |
default:
|
|
Packit |
6bd9ab |
/* just copy character */
|
|
Packit |
6bd9ab |
buffer[pos++] = *src;
|
|
Packit |
6bd9ab |
break;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
/* terminate destination string */
|
|
Packit |
6bd9ab |
buffer[pos] = '\0';
|
|
Packit |
6bd9ab |
return 0;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
|
|
Packit |
6bd9ab |
int myldap_set_debuglevel(int level)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
int i;
|
|
Packit |
6bd9ab |
int rc;
|
|
Packit |
6bd9ab |
/* turn on debugging */
|
|
Packit |
6bd9ab |
if (level > 1)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
#ifdef LBER_OPT_LOG_PRINT_FILE
|
|
Packit |
6bd9ab |
log_log(LOG_DEBUG, "ber_set_option(LBER_OPT_LOG_PRINT_FILE)");
|
|
Packit |
6bd9ab |
rc = ber_set_option(NULL, LBER_OPT_LOG_PRINT_FILE, stderr);
|
|
Packit |
6bd9ab |
if (rc != LDAP_SUCCESS)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
myldap_err(LOG_ERR, NULL, rc, "ber_set_option(LBER_OPT_LOG_PRINT_FILE) failed");
|
|
Packit |
6bd9ab |
return rc;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
#endif /* LBER_OPT_LOG_PRINT_FILE */
|
|
Packit |
6bd9ab |
#ifdef LBER_OPT_DEBUG_LEVEL
|
|
Packit |
6bd9ab |
if (level > 2)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
i = -1;
|
|
Packit |
6bd9ab |
log_log(LOG_DEBUG, "ber_set_option(LBER_OPT_DEBUG_LEVEL,-1)");
|
|
Packit |
6bd9ab |
rc = ber_set_option(NULL, LBER_OPT_DEBUG_LEVEL, &i);
|
|
Packit |
6bd9ab |
if (rc != LDAP_SUCCESS)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
myldap_err(LOG_ERR, NULL, rc, "ber_set_option(LBER_OPT_DEBUG_LEVEL) failed");
|
|
Packit |
6bd9ab |
return rc;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
#endif /* LBER_OPT_DEBUG_LEVEL */
|
|
Packit |
6bd9ab |
#ifdef LDAP_OPT_DEBUG_LEVEL
|
|
Packit |
6bd9ab |
i = -1;
|
|
Packit |
6bd9ab |
log_log(LOG_DEBUG, "ldap_set_option(LDAP_OPT_DEBUG_LEVEL,-1)");
|
|
Packit |
6bd9ab |
rc = ldap_set_option(NULL, LDAP_OPT_DEBUG_LEVEL, &i);
|
|
Packit |
6bd9ab |
if (rc != LDAP_SUCCESS)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
myldap_err(LOG_ERR, NULL, rc, "ldap_set_option(LDAP_OPT_DEBUG_LEVEL) failed");
|
|
Packit |
6bd9ab |
return rc;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
#endif /* LDAP_OPT_DEBUG_LEVEL */
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
return LDAP_SUCCESS;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
|
|
Packit |
6bd9ab |
int myldap_passwd(MYLDAP_SESSION *session,
|
|
Packit |
6bd9ab |
const char *userdn, const char *oldpassword,
|
|
Packit |
6bd9ab |
const char *newpasswd)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
int rc;
|
|
Packit |
6bd9ab |
struct berval ber_userdn, ber_oldpassword, ber_newpassword, ber_retpassword;
|
|
Packit |
6bd9ab |
/* check parameters */
|
|
Packit |
6bd9ab |
if ((session == NULL) || (userdn == NULL) || (newpasswd == NULL))
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
log_log(LOG_ERR, "myldap_passwd(): invalid parameter passed");
|
|
Packit |
6bd9ab |
errno = EINVAL;
|
|
Packit |
6bd9ab |
return LDAP_OTHER;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
/* log the call */
|
|
Packit |
6bd9ab |
log_log(LOG_DEBUG, "myldap_passwd(userdn=\"%s\",oldpasswd=%s,newpasswd=\"***\")",
|
|
Packit |
6bd9ab |
userdn, oldpassword ? "\"***\"" : "NULL");
|
|
Packit |
6bd9ab |
/* translate to ber stuff */
|
|
Packit |
6bd9ab |
ber_userdn.bv_val = (char *)userdn;
|
|
Packit |
6bd9ab |
ber_userdn.bv_len = strlen(userdn);
|
|
Packit |
6bd9ab |
ber_newpassword.bv_val = (char *)newpasswd;
|
|
Packit |
6bd9ab |
ber_newpassword.bv_len = strlen(newpasswd);
|
|
Packit |
6bd9ab |
ber_retpassword.bv_val = NULL;
|
|
Packit |
6bd9ab |
ber_retpassword.bv_len = 0;
|
|
Packit |
6bd9ab |
/* perform request */
|
|
Packit |
6bd9ab |
log_log(LOG_DEBUG, "myldap_passwd(): try ldap_passwd_s() without old password");
|
|
Packit |
6bd9ab |
rc = ldap_passwd_s(session->ld, &ber_userdn, NULL, &ber_newpassword,
|
|
Packit |
6bd9ab |
&ber_retpassword, NULL, NULL);
|
|
Packit |
6bd9ab |
if (rc != LDAP_SUCCESS)
|
|
Packit |
6bd9ab |
myldap_err(LOG_ERR, session->ld, rc, "ldap_passwd_s() without old password failed");
|
|
Packit |
6bd9ab |
/* free returned data if needed */
|
|
Packit |
6bd9ab |
if (ber_retpassword.bv_val != NULL)
|
|
Packit |
6bd9ab |
ldap_memfree(ber_retpassword.bv_val);
|
|
Packit |
6bd9ab |
if ((rc != LDAP_SUCCESS) && (oldpassword != NULL))
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
/* retry with old password */
|
|
Packit |
6bd9ab |
log_log(LOG_DEBUG, "myldap_passwd(): try ldap_passwd_s() with old password");
|
|
Packit |
6bd9ab |
ber_oldpassword.bv_val = (char *)oldpassword;
|
|
Packit |
6bd9ab |
ber_oldpassword.bv_len = strlen(oldpassword);
|
|
Packit |
6bd9ab |
/* perform request */
|
|
Packit |
6bd9ab |
rc = ldap_passwd_s(session->ld, &ber_userdn, &ber_oldpassword,
|
|
Packit |
6bd9ab |
&ber_newpassword, &ber_retpassword, NULL, NULL);
|
|
Packit |
6bd9ab |
if (rc != LDAP_SUCCESS)
|
|
Packit |
6bd9ab |
myldap_err(LOG_ERR, session->ld, rc, "ldap_passwd_s() with old password failed");
|
|
Packit |
6bd9ab |
/* free returned data if needed */
|
|
Packit |
6bd9ab |
if (ber_retpassword.bv_val != NULL)
|
|
Packit |
6bd9ab |
ldap_memfree(ber_retpassword.bv_val);
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
return rc;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
|
|
Packit |
6bd9ab |
int myldap_modify(MYLDAP_SESSION *session, const char *dn, LDAPMod * mods[])
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
if ((session == NULL) || (dn == NULL))
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
log_log(LOG_ERR, "myldap_passwd(): invalid parameter passed");
|
|
Packit |
6bd9ab |
errno = EINVAL;
|
|
Packit |
6bd9ab |
return LDAP_OTHER;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
return ldap_modify_ext_s(session->ld, dn, mods, NULL, NULL);
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
|
|
Packit |
6bd9ab |
int myldap_error_message(MYLDAP_SESSION *session, int rc,
|
|
Packit |
6bd9ab |
char *buffer, size_t buflen)
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
char *msg_diag = NULL;
|
|
Packit |
6bd9ab |
if ((session == NULL) || (buffer == NULL) || (buflen <= 0))
|
|
Packit |
6bd9ab |
{
|
|
Packit |
6bd9ab |
log_log(LOG_ERR, "myldap_error_message(): invalid parameter passed");
|
|
Packit |
6bd9ab |
errno = EINVAL;
|
|
Packit |
6bd9ab |
return LDAP_OTHER;
|
|
Packit |
6bd9ab |
}
|
|
Packit |
6bd9ab |
/* clear buffer */
|
|
Packit |
6bd9ab |
buffer[0] = '\0';
|
|
Packit |
6bd9ab |
#ifdef LDAP_OPT_DIAGNOSTIC_MESSAGE
|
|
Packit |
6bd9ab |
if (session->ld != NULL)
|
|
Packit |
6bd9ab |
ldap_get_option(session->ld, LDAP_OPT_DIAGNOSTIC_MESSAGE, &msg_diag);
|
|
Packit |
6bd9ab |
#endif /* LDAP_OPT_DIAGNOSTIC_MESSAGE */
|
|
Packit |
6bd9ab |
/* return msg_diag or generic error message */
|
|
Packit |
6bd9ab |
mysnprintf(buffer, buflen - 1, "%s",
|
|
Packit |
6bd9ab |
((msg_diag != NULL) && (msg_diag[0]!='\0')) ?
|
|
Packit |
6bd9ab |
msg_diag : ldap_err2string(rc));
|
|
Packit |
6bd9ab |
/* free diagnostic message */
|
|
Packit |
6bd9ab |
if (msg_diag != NULL)
|
|
Packit |
6bd9ab |
ldap_memfree(msg_diag);
|
|
Packit |
6bd9ab |
return LDAP_SUCCESS;
|
|
Packit |
6bd9ab |
}
|