]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
v4: Updates to functions for establishing LDAP directory type (#4424)
authorNick Porter <nick@portercomputing.co.uk>
Mon, 21 Mar 2022 12:28:42 +0000 (12:28 +0000)
committerGitHub <noreply@github.com>
Mon, 21 Mar 2022 12:28:42 +0000 (08:28 -0400)
* 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

src/lib/ldap/base.h
src/lib/ldap/directory.c

index b8c6630872085f40bf073606a022f9dcdcd6b86e..c7c5fcf9c109d22ac1dd7eafe090c77a9716b133 100644 (file)
@@ -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;              //! <What kind of LDAP sync this directory supports.
 } fr_ldap_directory_t;
 
 /** Connection configuration
@@ -665,8 +679,21 @@ int                fr_ldap_control_add_session_tracking(fr_ldap_connection_t *conn, request_t
 /*
  *     directory.c - Get directory capabilities from the remote server
  */
+#define LDAP_DIRECTORY_ATTRS { "vendorname", \
+                              "vendorversion", \
+                              "isGlobalCatalogReady", \
+                              "objectClass", \
+                              "orcldirectoryversion", \
+                              "supportedControl", \
+                              NULL }
+
+int            fr_ldap_directory_result_parse(fr_ldap_directory_t *directory, LDAP *handle,
+                                              LDAPMessage *result, char const *name);
+
 int            fr_ldap_trunk_directory_alloc_async(TALLOC_CTX *ctx, fr_ldap_thread_trunk_t *ttrunk);
 
+int            fr_ldap_conn_directory_alloc_async(fr_ldap_connection_t *ldap_conn);
+
 /*
  *     edir.c - Edirectory integrations
  */
index d40f02b06bacbc18c202a7b1de842d0e91639e22..d31de1d58b1bbfd30809a909e87c07120dc76ec3 100644 (file)
@@ -48,8 +48,8 @@ static fr_table_num_sorted_t const fr_ldap_directory_type_table[] = {
 };
 static size_t fr_ldap_directory_type_table_len = NUM_ELEMENTS(fr_ldap_directory_type_table);
 
-static int ldap_directory_result_parse(fr_ldap_directory_t *directory, LDAP *handle,
-                                      LDAPMessage *result, char const *name)
+int fr_ldap_directory_result_parse(fr_ldap_directory_t *directory, LDAP *handle,
+                                  LDAPMessage *result, char const *name)
 {
        int                     entry_cnt, i, num, ldap_errno;
        LDAPMessage             *entry;
@@ -87,7 +87,7 @@ static int ldap_directory_result_parse(fr_ldap_directory_t *directory, LDAP *han
 
        if (directory->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;
+}