27RCSID(
"$Id: 8cf014313e7680ae4f6b9b1a2721b899bda20b9a $")
31#define LOG_PREFIX name
33#include <freeradius-devel/ldap/base.h>
69 LDAPMessage *result,
char const *
name)
71 int entry_cnt, i, num, ldap_errno;
73 struct berval **values = NULL;
76 char const *
const *context_p;
84 entry_cnt = ldap_count_entries(handle, result);
86 WARN(
"Capability check failed: Ambiguous result for rootDSE, expected 1 entry, got %i", entry_cnt);
90 entry = ldap_first_entry(handle, result);
92 ldap_get_option(handle, LDAP_OPT_RESULT_CODE, &ldap_errno);
94 WARN(
"Capability check failed: Failed retrieving entry: %s", ldap_err2string(ldap_errno));
110 if (strcasestr(directory->
vendor_str,
"International Business Machines")) {
112 }
else if (strcasestr(directory->
vendor_str,
"Samba Team")) {
123 if (strcasestr(directory->
version_str,
"eDirectory")) {
128 }
else if (strcasestr(directory->
version_str,
"Oracle Unified Directory")) {
133 }
else if (strcasestr(directory->
version_str,
"UnboundID")) {
138 }
else if (strcasestr(directory->
version_str,
"Netscape-Directory")) {
143 }
else if (strcasestr(directory->
version_str,
"DirX Directory")) {
148 }
else if (strcasestr(directory->
version_str,
"Sun Java")) {
166 values = ldap_get_values_len(handle, entry,
"objectClass");
168 num = ldap_count_values_len(values);
169 for (i = 0; i < num; i++) {
170 if ((values[i]->bv_len ==
sizeof(
"OpenLDAProotDSE") - 1) &&
171 (memcmp(
"OpenLDAProotDSE", values[i]->bv_val, values[i]->bv_len) == 0)) {
175 ldap_value_free_len(values);
183 if (memmem(
value.bv_val,
value.bv_len,
"OID", 3)) {
185 }
else if (memmem(
value.bv_val,
value.bv_len,
"OVD", 3)) {
193 switch (directory->
type) {
200 directory->
dn_attr =
"distinguishedName";
216 values = ldap_get_values_len(handle, entry,
"supportedControl");
218 num = ldap_count_values_len(values);
219 for (i = 0; i < num; i++) {
220 if ((values[i]->bv_len == strlen(LDAP_CONTROL_SYNC)) &&
221 (memcmp(LDAP_CONTROL_SYNC, values[i]->bv_val, values[i]->bv_len) == 0)) {
222 INFO(
"Directory supports RFC 4533");
228 INFO(
"Directory supports LDAP_SERVER_NOTIFICATION_OID");
232 if ((values[i]->bv_len == strlen(LDAP_CONTROL_PERSIST_REQUEST)) &&
233 (memcmp(LDAP_CONTROL_PERSIST_REQUEST, values[i]->bv_val, values[i]->bv_len) == 0)) {
234 INFO(
"Directory supports persistent search");
239 ldap_value_free_len(values);
241 WARN(
"No supportedControl returned by LDAP server");
260 for (context_p = list->strings; context_p < list->p; context_p++) {
277 directory->
dn_attr =
"entryDN";
298 char const *common = NULL;
299 char const *
const *dn_p;
303 for (dn_p = dn_list; *dn_p; dn_p++) {
305 char const *p = *dn_p;
329 if (common !=
context)
return NULL;
376 LDAPMessage *result = NULL;
384 PWARN(
"Directory discovery failed, proceeding without directory capability data");
386 if (result) ldap_msgfree(result);
420 if ((ldap_get_option(c->
handle, LDAP_OPT_DESC, &fd) != LDAP_OPT_SUCCESS) || (fd < 0))
goto error;
426 discover_ctx) < 0)
goto error;
449 if (
fr_ldap_search_async(&msgid, NULL, ldap_conn,
"", LDAP_SCOPE_BASE,
"(objectclass=*)", attrs,
#define USES_APPLE_DEPRECATED_API
#define L(_str)
Helper for initialising arrays of string literals.
#define CMP(_a, _b)
Same as CMP_PREFER_SMALLER use when you don't really care about ordering, you just want an ordering.
char const * fr_ldap_directory_common_base_find(fr_ldap_directory_t const *directory, char const *const *dn_list)
Find the naming context which contains a set of DNs.
int fr_ldap_conn_directory_alloc_async(fr_ldap_connection_t *ldap_conn)
Asynchronously extract useful information from the rootDSE of the LDAP server.
int msgid
Of the outstanding rootDSE search.
fr_ldap_connection_t * c
Connection the rootDSE search was sent on.
static void _ldap_directory_discover_io_read(UNUSED fr_event_list_t *el, UNUSED int fd, UNUSED int flags, void *uctx)
Parse a rootDSE response from a server.
fr_ldap_directory_t * fr_ldap_directory_alloc(TALLOC_CTX *ctx)
Allocate a directory structure with defaults.
static void _ldap_directory_discover_io_error(UNUSED fr_event_list_t *el, UNUSED int fd, UNUSED int flags, UNUSED int fd_errno, void *uctx)
Error reading from or writing to the file descriptor.
static int8_t _naming_context_cmp(void const *one, void const *two)
Compare two naming contexts, case insensitively.
static fr_table_num_sorted_t const fr_ldap_directory_type_table[]
int fr_ldap_directory_discover_async(fr_ldap_connection_t *c)
Send a rootDSE search on a connection being established.
int fr_ldap_directory_result_parse(fr_ldap_directory_t *directory, LDAP *handle, LDAPMessage *result, char const *name)
static size_t fr_ldap_directory_type_table_len
static uint32_t _naming_context_hash(void const *data)
Hash a naming context, case insensitively.
State of an in progress rootDSE search on a connection being established.
#define fr_event_fd_insert(...)
void * fr_hash_table_find(fr_hash_table_t *ht, void const *data)
Find data in a hash table.
uint32_t fr_hash_case_string(char const *p)
Hash a C string, converting all chars to lowercase.
bool fr_hash_table_insert(fr_hash_table_t *ht, void const *data)
Insert data into a hash table.
#define fr_hash_table_alloc(_ctx, _hash_node, _cmp_node, _free_node)
#define LDAP_DIRECTORY_ATTRS
#define LDAP_SERVER_NOTIFICATION_OID
OID of Active Directory control for persistent search.
int fr_ldap_entry_value_find(struct berval *out, LDAP *handle, LDAPMessage *entry, char const *attr)
Find an attribute in an entry, returning its first value referenced in place.
@ FR_LDAP_DIRECTORY_ORACLE_UNIFIED_DIRECTORY
Directory server is Oracle Unified Directory.
@ FR_LDAP_DIRECTORY_UNKNOWN
We can't determine the directory server.
@ FR_LDAP_DIRECTORY_NETSCAPE
Directory server is Netscape.
@ FR_LDAP_DIRECTORY_EDIRECTORY
Directory server is eDir.
@ FR_LDAP_DIRECTORY_ORACLE_INTERNET_DIRECTORY
Directory server is Oracle Internet Directory.
@ FR_LDAP_DIRECTORY_UNBOUND_ID
Directory server is Unbound ID.
@ FR_LDAP_DIRECTORY_SIEMENS_AG
Directory server is Siemens AG.
@ FR_LDAP_DIRECTORY_ORACLE_VIRTUAL_DIRECTORY
Directory server is Oracle Virtual Directory.
@ FR_LDAP_DIRECTORY_ACTIVE_DIRECTORY
Directory server is Active Directory.
@ FR_LDAP_DIRECTORY_OPENLDAP
Directory server is OpenLDAP.
@ FR_LDAP_DIRECTORY_SUN_ONE_DIRECTORY
Directory server is Sun One Directory.
@ FR_LDAP_DIRECTORY_IBM
Directory server is IBM.
@ FR_LDAP_DIRECTORY_SAMBA
Directory server is Samba.
fr_ldap_sync_type_t sync_type
What kind of LDAP sync this directory supports.
LDAP * handle
libldap handle.
fr_ldap_directory_t * directory
The type of directory we're connected to.
void fr_ldap_state_error(fr_ldap_connection_t *c)
Signal that there's been an error on the connection.
char * fr_ldap_berval_to_string(TALLOC_CTX *ctx, struct berval const *in)
Convert a berval to a talloced string.
fr_ldap_config_t const * config
rlm_ldap connection configuration.
talloc_str_list_t * fr_ldap_str_list_afrom_result(TALLOC_CTX *ctx, LDAP *handle, LDAPMessage *result, char const *attr, size_t extra)
Copy an attribute's values from every entry of a result into a string list.
fr_ldap_state_t fr_ldap_state_next(fr_ldap_connection_t *c)
Move between LDAP connection states.
char const * vendor_str
As returned from the vendorName attribute in the rootDSE.
fr_hash_table_t * naming_contexts_ht
For resolving DNs to the naming context containing them.
bool cleartext_password
Whether the server will return the user's plaintext password.
char const * name
Name of the module that created this connection.
@ FR_LDAP_SYNC_ACTIVE_DIRECTORY
Directory supports AD style persistent search.
@ FR_LDAP_SYNC_PERSISTENT_SEARCH
Directory supports persistent search.
@ FR_LDAP_SYNC_RFC4533
Directory supports RFC 4533.
bool discovered
A rootDSE response has been parsed into these fields.
int fr_ldap_connection_timeout_reset(fr_ldap_connection_t const *conn)
char const * version_str
As returned from the vendorVersion attribute in the rootDSE.
connection_t * conn
Connection state handle.
char const * dn_attr
Attribute to match an entry's DN in a search filter.
char const ** naming_contexts
NULL terminated array of databases served by this directory.
fr_ldap_directory_type_t type
Canonical server implementation.
fr_ldap_rcode_t
Codes returned by fr_ldap internal functions.
@ LDAP_PROC_SUCCESS
Operation was successful.
Tracks the state of a libldap connection handle.
fr_ldap_rcode_t fr_ldap_search_async(int *msgid, request_t *request, fr_ldap_connection_t *pconn, char const *dn, int scope, char const *filter, char const *const *attrs, LDAPControl **serverctrls, LDAPControl **clientctrls)
Search for something in the LDAP directory.
fr_ldap_rcode_t fr_ldap_result(LDAPMessage **result, LDAPControl ***ctrls, fr_ldap_connection_t const *conn, int msgid, int all, char const *dn, fr_time_delta_t timeout)
Parse response from LDAP server dealing with any errors.
Stores all information relating to an event list.
int strcasecmp(char *s1, char *s2)
#define fr_table_str_by_value(_table, _number, _def)
Convert an integer to a string.
An element in a lexicographically sorted array of name to num mappings.
static size_t talloc_str_list_num(talloc_str_list_t const *list)
Return the number of strings in a string list.
A NULL terminated array of strings with an append cursor.
#define fr_time_delta_wrap(_time)
static fr_event_list_t * el
char const * fr_strerror(void)
Get the last library error.