Use the default that the log output claims will be used for the basedn
[asterisk/asterisk.git] / res / res_config_ldap.c
index ab71d8b..52855fd 100644 (file)
@@ -58,15 +58,16 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "asterisk/linkedlists.h"
 
 #define RES_CONFIG_LDAP_CONF "res_ldap.conf"
+#define RES_CONFIG_LDAP_DEFAULT_BASEDN "asterisk"
 
 AST_MUTEX_DEFINE_STATIC(ldap_lock);
 
 static LDAP *ldapConn;
-static char host[512];
+static char url[512];
 static char user[512];
 static char pass[50];
 static char basedn[512];
-static int port = 389;
+static int version = 3;
 static time_t connect_time;
 
 static int parse_config(void);
@@ -326,7 +327,7 @@ static struct ast_variable *realtime_ldap_entry_to_var(struct ldap_table_config
                                }
                                v++;
                        }
-                       ber_bvecfree(values);
+                       ldap_value_free_len(values);
                }
                ldap_attribute_name = ldap_next_attribute(ldapConn, ldap_entry, ber);
        }
@@ -492,7 +493,7 @@ static struct ast_variable **realtime_ldap_result_to_vars(struct ldap_table_conf
                                                }
                                                v++;
                                        } /*!< while(*v) */
-                                       ber_bvecfree(values);
+                                       ldap_value_free_len(values);
                                }/*!< if (values) */
                                ldap_attribute_name = ldap_next_attribute(ldapConn, ldap_entry, ber);
                        } /*!< while (ldap_attribute_name) */
@@ -552,7 +553,7 @@ static struct ast_variable *ldap_loadentry(struct ldap_table_config *table_confi
                do {
                        result = ldap_search_ext_s(ldapConn, dn, LDAP_SCOPE_BASE,
                                           "(objectclass=*)", NULL, 0, NULL, NULL, NULL, LDAP_NO_LIMIT, &ldap_result);
-                       if (result < 0 && is_ldap_connect_error(result)) {
+                       if (result != LDAP_SUCCESS && is_ldap_connect_error(result)) {
                                ast_log(LOG_WARNING,
                                        "Failed to query database. Try %d/3\n",
                                        tries + 1);
@@ -567,9 +568,9 @@ static struct ast_variable *ldap_loadentry(struct ldap_table_config *table_confi
                                                break;
                                }
                        }
-               } while (result < 0 && tries < 3 && is_ldap_connect_error(result));
+               } while (result != LDAP_SUCCESS && tries < 3 && is_ldap_connect_error(result));
 
-               if (result < 0) {
+               if (result != LDAP_SUCCESS) {
                        ast_log(LOG_WARNING,
                                        "Failed to query database. Check debug for more info.\n");
                        ast_debug(2, "dn=%s\n", dn);
@@ -687,7 +688,9 @@ static void append_var_and_value_to_filter(struct ast_str **filter,
        ast_debug(2, "name='%s' value='%s'\n", name, value);
 
        if (like_pos) {
-               name = new_name = ast_strdupa(like_pos + strlen(" LIKE"));
+               int len = like_pos - name;
+               name = new_name = ast_strdupa(name);
+               new_name[len] = '\0';
                value = new_value = ast_strdupa(value);
                replace_string_in_string(new_value, "\\_", "_");
                replace_string_in_string(new_value, "%", "*");
@@ -725,9 +728,10 @@ static struct ast_variable **realtime_ldap_base_ap(unsigned int *entries_count_p
                return NULL;
        } 
 
-       if (!(filter = ast_str_create(80)))
+       if (!(filter = ast_str_create(80))) {
                ast_free(clean_basedn);
                return NULL;
+       }
 
        /* Get the first parameter and first value in our list of passed paramater/value pairs  */
        newparam = va_arg(ap, const char *);
@@ -763,10 +767,10 @@ static struct ast_variable **realtime_ldap_base_ap(unsigned int *entries_count_p
        ast_str_append(&filter, 0, "(&");
 
        if (table_config && table_config->additional_filter)
-               ast_str_append(&filter, 0, table_config->additional_filter);
+               ast_str_append(&filter, 0, "%s", table_config->additional_filter);
        if (table_config != base_table_config && base_table_config && 
                base_table_config->additional_filter) {
-               ast_str_append(&filter, 0, base_table_config->additional_filter);
+               ast_str_append(&filter, 0, "%s", base_table_config->additional_filter);
        }
 
        /* Create the first part of the query using the first parameter/value pairs we just extracted */
@@ -784,7 +788,7 @@ static struct ast_variable **realtime_ldap_base_ap(unsigned int *entries_count_p
                result = ldap_search_ext_s(ldapConn, clean_basedn,
                                  LDAP_SCOPE_SUBTREE, filter->str, NULL, 0, NULL, NULL, NULL, LDAP_NO_LIMIT,
                                  &ldap_result);
-               if (result < 0 && is_ldap_connect_error(result)) {
+               if (result != LDAP_SUCCESS && is_ldap_connect_error(result)) {
                        ast_log(LOG_DEBUG, "Failed to query database. Try %d/10\n",
                                tries + 1);
                        if (++tries < 10) {
@@ -797,9 +801,9 @@ static struct ast_variable **realtime_ldap_base_ap(unsigned int *entries_count_p
                                        break;
                        }
                }
-       } while (result < 0 && tries < 10 && is_ldap_connect_error(result));
+       } while (result != LDAP_SUCCESS && tries < 10 && is_ldap_connect_error(result));
 
-       if (result < 0) {
+       if (result != LDAP_SUCCESS) {
                ast_log(LOG_WARNING, "Failed to query database. Check debug for more info.\n");
                ast_log(LOG_WARNING, "Query: %s\n", filter->str);
                ast_log(LOG_WARNING, "Query Failed because: %s\n", ldap_err2string(result));
@@ -1003,7 +1007,7 @@ static int compare_categories(const void *a, const void *b)
 *      called on a reload
 */
 static struct ast_config *config_ldap(const char *basedn, const char *table_name,
-       const char *file, struct ast_config *cfg, struct ast_flags config_flags, const char *sugg_incl)
+       const char *file, struct ast_config *cfg, struct ast_flags config_flags, const char *sugg_incl, const char *who_asked)
 {
        unsigned int vars_count = 0;
        struct ast_variable **vars;
@@ -1085,7 +1089,7 @@ static struct ast_config *config_ldap(const char *basedn, const char *table_name
        for (i = 0; i < vars_count; i++) {
                if (!strcmp(categories[i].variable_name, "#include")) {
                        struct ast_flags config_flags = { 0 };
-                       if (!ast_config_internal_load(categories[i].variable_value, cfg, config_flags, ""))
+                       if (!ast_config_internal_load(categories[i].variable_value, cfg, config_flags, "", who_asked))
                                break;
                        continue;
                }
@@ -1168,11 +1172,11 @@ static int update_ldap(const char *basedn, const char *table_name, const char *a
        /* Create the filter with the table additional filter and the parameter/value pairs we were given */
        ast_str_append(&filter, 0, "(&");
        if (table_config && table_config->additional_filter) {
-               ast_str_append(&filter, 0, table_config->additional_filter);
+               ast_str_append(&filter, 0, "%s", table_config->additional_filter);
        }
        if (table_config != base_table_config && base_table_config
                && base_table_config->additional_filter) {
-               ast_str_append(&filter, 0, base_table_config->additional_filter);
+               ast_str_append(&filter, 0, "%s", base_table_config->additional_filter);
        }
        append_var_and_value_to_filter(&filter, table_config, attribute, lookup);
        ast_str_append(&filter, 0, ")");
@@ -1241,7 +1245,7 @@ static int update_ldap(const char *basedn, const char *table_name, const char *a
                result = ldap_search_ext_s(ldapConn, clean_basedn,
                                  LDAP_SCOPE_SUBTREE, filter->str, NULL, 0, NULL, NULL, NULL, LDAP_NO_LIMIT,
                                  &ldap_result);
-               if (result < 0 && is_ldap_connect_error(result)) {
+               if (result != LDAP_SUCCESS && is_ldap_connect_error(result)) {
                        ast_log(LOG_WARNING, "Failed to query database. Try %d/3\n",
                                tries + 1);
                        tries++;
@@ -1255,9 +1259,9 @@ static int update_ldap(const char *basedn, const char *table_name, const char *a
                                        break;
                        }
                }
-       } while (result < 0 && tries < 3 && is_ldap_connect_error(result));
+       } while (result != LDAP_SUCCESS && tries < 3 && is_ldap_connect_error(result));
 
-       if (result < 0) {
+       if (result != LDAP_SUCCESS) {
                ast_log(LOG_WARNING, "Failed to query directory. Check debug for more info.\n");
                ast_log(LOG_WARNING, "Query: %s\n", filter->str);
                ast_log(LOG_WARNING, "Query Failed because: %s\n",
@@ -1282,7 +1286,7 @@ static int update_ldap(const char *basedn, const char *table_name, const char *a
 
                for (i = 0; ldap_entry; i++) { 
                        dn = ldap_get_dn(ldapConn, ldap_entry);
-                       if (!(error = ldap_modify_ext_s(ldapConn, dn, ldap_mods, NULL, NULL))) 
+                       if ((error = ldap_modify_ext_s(ldapConn, dn, ldap_mods, NULL, NULL)) != LDAP_SUCCESS) 
                                ast_log(LOG_ERROR, "Couldn't modify dn:%s because %s", dn, ldap_err2string(error));
 
                        ldap_entry = ldap_next_entry(ldapConn, ldap_entry);
@@ -1361,6 +1365,7 @@ static int reload(void)
 
        if (parse_config() < 0) {
                ast_log(LOG_NOTICE, "Cannot reload LDAP RealTime driver.\n");
+               ast_mutex_unlock(&ldap_lock);
                return 0;
        }               
 
@@ -1379,7 +1384,8 @@ int parse_config(void)
 {
        struct ast_config *config;
        struct ast_flags config_flags = {0};
-       const char *s;
+       const char *s, *host;
+       int port;
        char *category_name = NULL;
 
        config = ast_config_load(RES_CONFIG_LDAP_CONF, config_flags);
@@ -1401,28 +1407,34 @@ int parse_config(void)
        } else
                ast_copy_string(pass, s, sizeof(pass));
 
-       if (!(s = ast_variable_retrieve(config, "_general", "host"))) {
-               ast_log(LOG_ERROR, "No directory host found.\n");
-               host[0] = '\0';
+       /* URL is preferred, use host and port if not found */
+       if ((s = ast_variable_retrieve(config, "_general", "url"))) {
+               ast_copy_string(url, s, sizeof(url));
+       } else if ((host = ast_variable_retrieve(config, "_general", "host"))) {
+               if (!(s = ast_variable_retrieve(config, "_general", "port")) || sscanf(s, "%d", &port) != 1) {
+                       ast_log(LOG_NOTICE, "No directory port found, using 389 as default.\n");
+                       port = 389;
+               }
+
+               snprintf(url, sizeof(url), "ldap://%s:%d", host, port);
        } else {
-               ast_copy_string(host, "ldap://", 8 );
-               ast_copy_string(host + 7, s, sizeof(host));
+               ast_log(LOG_ERROR, "No directory URL or host found.\n");
+               ast_config_destroy(config);
+               return -1;
        }
 
        if (!(s = ast_variable_retrieve(config, "_general", "basedn"))) {
-               ast_log(LOG_ERROR, "No LDAP base dn found, using 'asterisk' as default.\n");
-               basedn[0] = '\0';
+               ast_log(LOG_ERROR, "No LDAP base dn found, using '%s' as default.\n", RES_CONFIG_LDAP_DEFAULT_BASEDN);
+               ast_copy_string(basedn, RES_CONFIG_LDAP_DEFAULT_BASEDN, sizeof(basedn));
        } else 
                ast_copy_string(basedn, s, sizeof(basedn));
 
-       if (!(s = ast_variable_retrieve(config, "_general", "port"))) {
-               ast_log(LOG_WARNING, "No directory port found, using 389 as default.\n");
-               port = 389;
-               ast_copy_string(host + strlen(host), ":389", sizeof(host));
-       } else { 
-               ast_copy_string(host + 1, ":", sizeof(s));
-               ast_copy_string(host + strlen(host), s, sizeof(s));
-               port = atoi(s);
+       if (!(s = ast_variable_retrieve(config, "_general", "version")) || !(s = ast_variable_retrieve(config, "_general", "protocol"))) {
+               ast_log(LOG_NOTICE, "No explicit LDAP version found, using 3 as default.\n");
+               version = 3;
+       } else if (sscanf(s, "%d", &version) != 1 || version < 1 || version > 6) {
+               ast_log(LOG_WARNING, "Invalid LDAP version '%s', using 3 as default.\n", s);
+               version = 3;
        }
 
        table_configs_free();
@@ -1468,23 +1480,27 @@ static int ldap_reconnect(void)
                return 1;
        }
 
-       if (ast_strlen_zero(host)) {
+       if (ast_strlen_zero(url)) {
                ast_log(LOG_ERROR, "Not enough parameters to connect to ldap database\n");
                return 0;
        }
 
-       if (LDAP_SUCCESS != ldap_initialize(&ldapConn, host)) {
-               ast_log(LOG_ERROR, "Failed to init ldap connection to %s. Check debug for more info.\n", host);
+       if (LDAP_SUCCESS != ldap_initialize(&ldapConn, url)) {
+               ast_log(LOG_ERROR, "Failed to init ldap connection to '%s'. Check debug for more info.\n", url);
                return 0;
-       } 
+       }
+
+       if (LDAP_OPT_SUCCESS != ldap_set_option(ldapConn, LDAP_OPT_PROTOCOL_VERSION, &version)) {
+               ast_log(LOG_WARNING, "Unable to set LDAP protocol version to %d, falling back to default.\n", version);
+       }
 
        if (!ast_strlen_zero(user)) {
-               ast_debug(2, "bind to %s as %s\n", host, user);
+               ast_debug(2, "bind to '%s' as user '%s'\n", url, user);
                cred.bv_val = (char *) pass;
                cred.bv_len = strlen(pass);
                bind_result = ldap_sasl_bind_s(ldapConn, user, LDAP_SASL_SIMPLE, &cred, NULL, NULL, NULL);
        } else {
-               ast_debug(2, "bind anonymously %s anonymously\n", host);
+               ast_debug(2, "bind %s anonymously\n", url);
                bind_result = ldap_sasl_bind_s(ldapConn, NULL, LDAP_SASL_SIMPLE, NULL, NULL, NULL, NULL);
        }
        if (bind_result == LDAP_SUCCESS) {
@@ -1518,8 +1534,8 @@ static char *realtime_ldap_status(struct ast_cli_entry *e, int cmd, struct ast_c
        if (!ldapConn)
                return CLI_FAILURE;
 
-       if (!ast_strlen_zero(host)) 
-               snprintf(status, sizeof(status), "Connected to %s, port %d baseDN %s", host, port, basedn);
+       if (!ast_strlen_zero(url)) 
+               snprintf(status, sizeof(status), "Connected to '%s', baseDN %s", url, basedn);
 
        if (!ast_strlen_zero(user))
                snprintf(status2, sizeof(status2), " with username %s", user);