From: Nick Porter Date: Mon, 21 Mar 2022 12:28:42 +0000 (+0000) Subject: v4: Updates to functions for establishing LDAP directory type (#4424) X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=c97e6ca1fc3f7933ff51bc44eaeccb1aa754b454;p=thirdparty%2Ffreeradius-server.git v4: Updates to functions for establishing LDAP directory type (#4424) * Make parsing of LDAP directory type results a library function. * Define fr_ldap_conn_directory_alloc_async() For querying the LDAP directory type on a single connection * Add a type to represent which sync protocol an LDAP directory supports * Correct identification of IBM LDAP directories * Define Active Directory specific OIDs * Use supportedControl to identify which sync method an LDAP directory supports --- diff --git a/src/lib/ldap/base.h b/src/lib/ldap/base.h index b8c66308720..c7c5fcf9c10 100644 --- a/src/lib/ldap/base.h +++ b/src/lib/ldap/base.h @@ -120,6 +120,11 @@ ldap_create_session_tracking_control LDAP_P(( #define LDAP_VIRTUAL_DN_ATTR "dn" //!< 'Virtual' attribute which maps to the DN of the object. +#define LDAP_SERVER_NOTIFICATION_OID "1.2.840.113556.1.4.528" //!< OID of Active Directory control for + //!< persistent search. +#define LDAP_SERVER_SHOW_DELETED_OID "1.2.840.113556.1.4.417" //!< OID of Active Directory control which + //!< enables searching for deleted objects. + typedef enum { LDAP_EXT_UNSUPPORTED, //!< Unsupported extension. LDAP_EXT_BINDNAME, //!< Specifies the user DN or name for an LDAP bind. @@ -154,6 +159,13 @@ typedef enum { FR_LDAP_DIRECTORY_UNBOUND_ID //!< Directory server is Unbound ID } fr_ldap_directory_type_t; +typedef enum { + FR_LDAP_SYNC_NONE = 0, //!< No support for LDAP sync + FR_LDAP_SYNC_RFC4533, //!< Directory supports RFC 4533 + FR_LDAP_SYNC_ACTIVE_DIRECTORY, //!< Directory supports AD style persistent search. + FR_LDAP_SYNC_PERSISTENT_SEARCH //!< Directory supports persistent search +} fr_ldap_sync_type_t; + /** LDAP connection handle states * */ @@ -198,6 +210,8 @@ typedef struct { bool cleartext_password; //!< Whether the server will return the user's plaintext ///< password. + + fr_ldap_sync_type_t sync_type; //! vendor_str) { if (strcasestr(directory->vendor_str, "International Business Machines")) { - directory->type = FR_LDAP_DIRECTORY_EDIRECTORY; + directory->type = FR_LDAP_DIRECTORY_IBM; } goto found; @@ -181,6 +181,34 @@ found: break; } + /* + * Evaluate what type of sync the directory supports + */ + values = ldap_get_values_len(handle, entry, "supportedControl"); + if (values) { + num = ldap_count_values_len(values); + for (i = 0; i < num; i++) { + if (strncmp(LDAP_CONTROL_SYNC, values[i]->bv_val, values[i]->bv_len) == 0) { + INFO("Directory supports RFC 4533"); + directory->sync_type = FR_LDAP_SYNC_RFC4533; + break; + } + if (strncmp(LDAP_SERVER_NOTIFICATION_OID, values[i]->bv_val, values[i]->bv_len) == 0) { + INFO("Directory supports LDAP_SERVER_NOTIFICATION_OID"); + directory->sync_type = FR_LDAP_SYNC_ACTIVE_DIRECTORY; + break; + } + if (strncmp(LDAP_CONTROL_PERSIST_REQUEST, values[i]->bv_val, values[i]->bv_len) == 0) { + INFO("Directory supports persistent search"); + directory->sync_type = FR_LDAP_SYNC_PERSISTENT_SEARCH; + break; + } + } + ldap_value_free_len(values); + } else { + WARN("No supportedControl returned by LDAP server"); + } + return 0; } @@ -194,7 +222,7 @@ static void ldap_trunk_directory_alloc_read(LDAP *handle, fr_ldap_query_t *query fr_ldap_config_t const *config = query->ldap_conn->config; fr_ldap_directory_t *directory = talloc_get_type_abort(rctx, fr_ldap_directory_t); - (void)ldap_directory_result_parse(directory, handle, result, config->name); + (void)fr_ldap_directory_result_parse(directory, handle, result, config->name); } /** Async extract useful information from the rootDSE of the LDAP server @@ -209,13 +237,8 @@ static void ldap_trunk_directory_alloc_read(LDAP *handle, fr_ldap_query_t *query */ int fr_ldap_trunk_directory_alloc_async(TALLOC_CTX *ctx, fr_ldap_thread_trunk_t *ttrunk) { - static char const *attrs[] = { "vendorname", - "vendorversion", - "isGlobalCatalogReady", - "objectClass", - "orcldirectoryversion", - NULL }; fr_ldap_query_t *query; + static char const *attrs[] = LDAP_DIRECTORY_ATTRS; ttrunk->directory = talloc_zero(ctx, fr_ldap_directory_t); if (!ttrunk->directory) return -1; @@ -229,3 +252,26 @@ int fr_ldap_trunk_directory_alloc_async(TALLOC_CTX *ctx, fr_ldap_thread_trunk_t return 0; } + +/** Async extract useful information from the rootDSE of the LDAP server + * + * This version is for a single connection rather than a connection trunk + * + * @param[in] ldap_conn connection to be queried + * @return + * - message ID on success + * < 0 on failure + */ +int fr_ldap_conn_directory_alloc_async(fr_ldap_connection_t *ldap_conn) +{ + int msgid; + static char const *attrs[] = LDAP_DIRECTORY_ATTRS; + + ldap_conn->directory = talloc_zero(ldap_conn, fr_ldap_directory_t); + if (!ldap_conn->directory) return -1; + + if (fr_ldap_search_async(&msgid, NULL, &ldap_conn, "", LDAP_SCOPE_BASE, "(objectclass=*)", attrs, + NULL, NULL) != LDAP_PROC_SUCCESS) return -1; + + return msgid; +}