Allow arbitrary attributes for LDAP clients
authorArran Cudbard-Bell <a.cudbardb@freeradius.org>
Mon, 13 Oct 2014 14:18:20 +0000 (10:18 -0400)
committerArran Cudbard-Bell <a.cudbardb@freeradius.org>
Mon, 13 Oct 2014 14:18:20 +0000 (10:18 -0400)
src/modules/rlm_ldap/clients.c
src/modules/rlm_ldap/ldap.h
src/modules/rlm_ldap/rlm_ldap.c

index a858f80..01ff2e1 100644 (file)
   * @param[in] inst rlm_ldap configuration.
   * @return -1 on error else 0.
   */
-int rlm_ldap_load_clients(ldap_instance_t const *inst)
+int rlm_ldap_load_clients(ldap_instance_t const *inst, CONF_SECTION *cs)
 {
-       int                     ret = 0;
-       ldap_rcode_t            status;
-       ldap_handle_t           *conn = NULL;
+       int             ret = 0;
+       ldap_rcode_t    status;
+       ldap_handle_t   *conn = NULL;
 
-       /* This needs to be updated if additional attributes need to be retrieved */
-       char const              *attrs[7];
-       char const              **attrs_p;
+       char const      **attrs = NULL;
+       char const      **attrs_p;
 
-       LDAPMessage             *result = NULL;
-       LDAPMessage             *entry;
+       CONF_ITEM       *ci;
+       CONF_PAIR       *cp;
+       int             count = 1;      /* +1 for NULL termination */
 
-       RADCLIENT               *c;
+       LDAPMessage     *result = NULL;
+       LDAPMessage     *entry;
+
+       RADCLIENT       *c;
 
        LDAP_DBG("Loading dynamic clients");
 
        rad_assert(inst->clientobj_base_dn);
 
-       /*
-        *      Basic sanity checks.
-        */
-       if (!inst->clientobj_identifier) {
-               LDAP_ERR("Told to load clients but 'client.identifier_attribute' not specified");
-
-               return -1;
-       }
-
-       if (!inst->clientobj_secret) {
-               LDAP_ERR("Told to load clients but 'client.secret_attribute' not specified");
-
-               return -1;
-       }
-
        if (!inst->clientobj_filter) {
                LDAP_ERR("Told to load clients but 'client.filter' not specified");
 
                return -1;
        }
 
-       /*
-        *      Construct the attribute array
-        */
-       attrs[0] = inst->clientobj_identifier;
-       attrs[1] = inst->clientobj_secret;
-       attrs_p  = attrs + 2;
+       for (ci = cf_item_find_next(cs, NULL);
+            ci != NULL;
+            ci = cf_item_find_next(cs, ci)) {
 
-       if (inst->clientobj_shortname) { /* 2 */
-               *attrs_p++ = inst->clientobj_shortname;
-       }
+               if (!cf_item_is_pair(ci)) {
+                       cf_log_err(ci, "Entry is not in \"attribute = value\" format");
+                       return -1;
+               }
 
-       if (inst->clientobj_type) { /* 3 */
-               *attrs_p++ = inst->clientobj_type;
+               count++;
        }
 
-       if (inst->clientobj_server) { /* 4 */
-               *attrs_p++ = inst->clientobj_server;
-       }
+       /*
+        *      Create an array of LDAP attributes to feed to rlm_ldap_search.
+        */
+       attrs_p = attrs = talloc_array(inst, char const *, count);
+       for (ci = cf_item_find_next(cs, NULL);
+            ci != NULL;
+            ci = cf_item_find_next(cs, ci)) {
+               char const *value;
+
+               cp = cf_itemtopair(ci);
+               value = cf_pair_value(cp);
+               if (!value) {
+                       cf_log_err(ci, "Failed getting LDAP attribute name");
+                       talloc_free(attrs);
+                       return -1;
+               }
 
-       if (inst->clientobj_require_ma) { /* 5 */
-               *attrs_p++ = inst->clientobj_require_ma;
+               *attrs_p++ = value;
        }
-
-       *attrs_p = NULL;        /* 6 - array needs to be NULL terminated */
+       *attrs_p = NULL;
 
        conn = rlm_ldap_get_socket(inst, NULL);
        if (!conn) return -1;
@@ -145,90 +141,70 @@ int rlm_ldap_load_clients(ldap_instance_t const *inst)
        }
 
        do {
-               char *dn;
-               char **identifier       = NULL;
-               char **shortname        = NULL;
-               char **secret           = NULL;
-               char **type             = NULL;
-               char **server           = NULL;
-               char **require_ma       = NULL;
+               CONF_SECTION *cc;
+               char *dn = NULL, *id;
 
-               dn = ldap_get_dn(conn->handle, entry);
+               char **value;
 
-               /*
-                *      Check for the required attributes first
-                */
-               identifier = ldap_get_values(conn->handle, entry, inst->clientobj_identifier);
-               if (!identifier) {
-                       LDAP_WARN("Client \"%s\" missing required attribute 'identifier', skipping...", dn);
-                       goto next;
+               id = dn = ldap_get_dn(conn->handle, entry);
+               cp = cf_pair_find(cs, "identifier");
+               if (cp) {
+                       value = ldap_get_values(conn->handle, entry, cf_pair_value(cp));
+                       if (value) id = value[0];
                }
 
-               secret = ldap_get_values(conn->handle, entry, inst->clientobj_secret);
-               if (!secret) {
-                       LDAP_WARN("Client \"%s\" missing required attribute 'secret', skipping...", dn);
-                       goto next;
-               }
+               cc = cf_section_alloc(NULL, "client", id);
 
-               if (inst->clientobj_shortname) {
-                       shortname = ldap_get_values(conn->handle, entry, inst->clientobj_shortname);
-                       if (!shortname) {
-                               LDAP_DBG3("Client \"%s\" missing optional attribute 'shortname'", dn);
-                       }
-               }
+               for (ci = cf_item_find_next(cs, NULL);
+                    ci != NULL;
+                    ci = cf_item_find_next(cs, ci)) {
+                       char const *attr;
 
-               if (inst->clientobj_type) {
-                       type = ldap_get_values(conn->handle, entry, inst->clientobj_type);
-                       if (!type) {
-                               LDAP_DBG3("Client \"%s\" missing optional attribute 'type'", dn);
-                       }
-               }
+                       cp = cf_itemtopair(ci);
+                       attr = cf_pair_attr(cp);
 
-               if (inst->clientobj_server) {
-                       server = ldap_get_values(conn->handle, entry, inst->clientobj_server);
-                       if (!server) {
-                               LDAP_DBG3("Client \"%s\" missing optional attribute 'server'", dn);
-                       }
-               }
+                       value = ldap_get_values(conn->handle, entry, cf_pair_value(cp));
+                       if (!value) continue;
 
-               if (inst->clientobj_require_ma) {
-                       require_ma = ldap_get_values(conn->handle, entry, inst->clientobj_require_ma);
-                       if (!require_ma) {
-                               LDAP_DBG3("Client \"%s\" missing optional attribute 'require_ma'", dn);
+                       cp = cf_pair_alloc(cc, attr, value[0], T_OP_SET, T_SINGLE_QUOTED_STRING);
+                       if (!cp) {
+                               LDAP_ERR("Failed allocing pair \"%s\" = \"%s\"", attr, value[0]);
+                               ret = -1;
+                               goto finish;
                        }
+                       cf_item_add(cc, cf_pairtoitem(cp));
                }
 
-               /* FIXME: We should really pass a proper ctx */
-               c = client_afrom_query(NULL,
-                                     identifier[0],
-                                     secret[0],
-                                     shortname ? shortname[0] : NULL,
-                                     type ? type[0] : NULL,
-                                     server ? server[0] : NULL,
-                                     require_ma ? strncmp(require_ma[0], "true", 4) == 0 : false);
+               /*
+                * @todo these should be parented from something
+                */
+               c = client_afrom_cs(NULL, cc, false);
                if (!c) {
-                       goto next;
+                       talloc_free(cc);
+                       ret = -1;
+                       goto finish;
                }
 
-               if (!client_add(NULL, c)) {
-                       WARN("Failed to add client, possible duplicate?");
+               /*
+                *      Client parents the CONF_SECTION which defined it
+                */
+               talloc_steal(c, cc);
 
+               if (!client_add(NULL, c)) {
+                       LDAP_ERR("Failed to add client \"%s\", possible duplicate?", dn);
+                       ret = -1;
                        client_free(c);
-                       goto next;
+                       goto finish;
                }
 
                LDAP_DBG("Client \"%s\" added", dn);
 
-               next:
                ldap_memfree(dn);
-               if (identifier) ldap_value_free(identifier);
-               if (shortname)  ldap_value_free(shortname);
-               if (secret)     ldap_value_free(secret);
-               if (type)       ldap_value_free(type);
-               if (server)     ldap_value_free(server);
        } while ((entry = ldap_next_entry(conn->handle, entry)));
 
 finish:
+       talloc_free(attrs);
+       if (dn) ldap_memfree(dn);
        if (result) ldap_msgfree(result);
 
        rlm_ldap_release_socket(inst, conn);
index c928023..bfb4c5f 100644 (file)
@@ -154,13 +154,6 @@ typedef struct ldap_instance {
        char const      *clientobj_scope_str;           //!< Scope (sub, one, base).
        int             clientobj_scope;                //!< Search scope.
 
-       char const      *clientobj_identifier;          //!< IP/FQDN/IP Prefix for the NAS.
-       char const      *clientobj_shortname;           //!< Short/Friendly name to assign.
-       char const      *clientobj_type;                //!< Type of NAS (not usually used).
-       char const      *clientobj_secret;              //!< RADIUS secret.
-       char const      *clientobj_server;              //!< Virtual server to associate the client with.
-       char const      *clientobj_require_ma;          //!< Require message-authenticator.
-
        bool            do_clients;                     //!< If true, attempt to load clients on instantiation.
 
        /*
@@ -387,7 +380,7 @@ rlm_rcode_t rlm_ldap_map_profile(ldap_instance_t const *inst, REQUEST *request,
 /*
  *     clients.c - Dynamic clients (bulk load).
  */
-int  rlm_ldap_load_clients(ldap_instance_t const *inst);
+int  rlm_ldap_load_clients(ldap_instance_t const *inst, CONF_SECTION *cs);
 
 /*
  *     edir.c - Magic extensions for Novell
index 2d0971b..d143a5d 100644 (file)
@@ -143,25 +143,10 @@ static CONF_PARSER group_config[] = {
        { NULL, -1, 0, NULL, NULL }
 };
 
-/*
- *     Client configuration
- */
-static CONF_PARSER client_attribute[] = {
-       { "identifier", FR_CONF_OFFSET(PW_TYPE_STRING, ldap_instance_t, clientobj_identifier), "host" },
-       { "shortname", FR_CONF_OFFSET(PW_TYPE_STRING, ldap_instance_t, clientobj_shortname), "cn" },
-       { "nas_type", FR_CONF_OFFSET(PW_TYPE_STRING, ldap_instance_t, clientobj_type), NULL },
-       { "secret", FR_CONF_OFFSET(PW_TYPE_STRING, ldap_instance_t, clientobj_secret), NULL },
-       { "virtual_server", FR_CONF_OFFSET(PW_TYPE_STRING, ldap_instance_t, clientobj_server), NULL },
-       { "require_message_authenticator", FR_CONF_OFFSET(PW_TYPE_STRING, ldap_instance_t, clientobj_require_ma), NULL },
-
-       { NULL, -1, 0, NULL, NULL }
-};
-
 static CONF_PARSER client_config[] = {
        { "filter", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT, ldap_instance_t, clientobj_filter), NULL },
        { "scope", FR_CONF_OFFSET(PW_TYPE_STRING, ldap_instance_t, clientobj_scope_str), "sub" },
        { "base_dn", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT, ldap_instance_t, clientobj_base_dn), "" },
-       { "attribute", FR_CONF_POINTER(PW_TYPE_SUBSECTION, NULL), (void const *) client_attribute },
 
        { NULL, -1, 0, NULL, NULL }
 };
@@ -764,7 +749,7 @@ static int mod_instantiate(CONF_SECTION *conf, void *instance)
                if (dict_addattr(inst->cache_attribute, -1, 0, PW_TYPE_STRING, flags) < 0) {
                        LDAP_ERR("Error creating cache attribute: %s", fr_strerror());
 
-                       return -1;
+                       goto error;
                }
                inst->cache_da = dict_attrbyname(inst->cache_attribute);
        } else {
@@ -775,13 +760,27 @@ static int mod_instantiate(CONF_SECTION *conf, void *instance)
         *      Initialize the socket pool.
         */
        inst->pool = fr_connection_pool_module_init(inst->cs, inst, mod_conn_create, NULL, NULL);
-       if (!inst->pool) return -1;
+       if (!inst->pool) goto error;
 
        /*
         *      Bulk load dynamic clients.
         */
        if (inst->do_clients) {
-               if (rlm_ldap_load_clients(inst) < 0) {
+               CONF_SECTION *cs;
+
+               cs = cf_section_sub_find(inst->cs, "client");
+               if (!cs) {
+                       LDAP_ERR("Told to load clients but no client section found");
+                       goto error;
+               }
+
+               cs = cf_section_sub_find(cs, "attribute");
+               if (!cs) {
+                       LDAP_ERR("Told to load clients but no attribute section found");
+                       goto error;
+               }
+
+               if (rlm_ldap_load_clients(inst, cs) < 0) {
                        LDAP_ERR("Error loading clients");
 
                        return -1;